summaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2006-10-13 22:51:49 +0200
committerFelix Fietkau <nbd@openwrt.org>2016-03-20 17:29:15 +0100
commit60c1f0f64d23003a19a07d6b9638542130f6641d (patch)
tree8fb2787f4c49baded97cd55e0c371fe1cffce2b6 /target
parentd58a09110ccfa95f06c983fe796806f2e035c9d2 (diff)
parentb3ce218b51746d3a576221ea542facf3a1703ab2 (diff)
downloadmtk-20170518-60c1f0f64d23003a19a07d6b9638542130f6641d.zip
mtk-20170518-60c1f0f64d23003a19a07d6b9638542130f6641d.tar.gz
mtk-20170518-60c1f0f64d23003a19a07d6b9638542130f6641d.tar.bz2
finally move buildroot-ng to trunk
Diffstat (limited to 'target')
-rw-r--r--target/Config.in272
-rw-r--r--target/Makefile49
-rw-r--r--target/image/ar7/Makefile102
-rw-r--r--target/image/ar7/sercomm/adam2.binbin0 -> 131072 bytes
-rw-r--r--target/image/ar7/sercomm/dg834bin0 -> 80 bytes
-rw-r--r--target/image/ar7/sercomm/jdr454wbbin0 -> 80 bytes
-rw-r--r--target/image/ar7/src/LzmaDecode.c663
-rw-r--r--target/image/ar7/src/LzmaDecode.h100
-rw-r--r--target/image/ar7/src/gzip.h51
-rw-r--r--target/image/ar7/src/ld.script.in34
-rw-r--r--target/image/ar7/src/loader.c140
-rw-r--r--target/image/ar7/src/srec2bin.c523
-rw-r--r--target/image/ar7/src/zimage.script.in11
-rw-r--r--target/image/aruba/Makefile43
-rwxr-xr-xtarget/image/aruba/addVersionbin0 -> 34464 bytes
-rw-r--r--target/image/aruba/version1
-rw-r--r--target/image/au1000/Makefile22
-rw-r--r--target/image/brcm/Makefile69
-rw-r--r--target/image/brcm/lzma-loader/Makefile34
-rw-r--r--target/image/brcm/lzma-loader/src/LzmaDecode.c663
-rw-r--r--target/image/brcm/lzma-loader/src/LzmaDecode.h100
-rw-r--r--target/image/brcm/lzma-loader/src/Makefile77
-rw-r--r--target/image/brcm/lzma-loader/src/README55
-rw-r--r--target/image/brcm/lzma-loader/src/decompress.c175
-rw-r--r--target/image/brcm/lzma-loader/src/decompress.lds.in20
-rw-r--r--target/image/brcm/lzma-loader/src/head.S155
-rw-r--r--target/image/brcm/lzma-loader/src/loader.lds.in17
-rw-r--r--target/image/brcm63xx/Makefile33
-rw-r--r--target/image/generic/Makefile12
-rw-r--r--target/image/generic/lzma-loader/Makefile43
-rw-r--r--target/image/generic/lzma-loader/src/LzmaDecode.c590
-rw-r--r--target/image/generic/lzma-loader/src/LzmaDecode.h131
-rw-r--r--target/image/generic/lzma-loader/src/Makefile63
-rw-r--r--target/image/generic/lzma-loader/src/decompress.c154
-rw-r--r--target/image/generic/lzma-loader/src/lzma-copy.lds.in20
-rw-r--r--target/image/generic/lzma-loader/src/lzma.lds.in24
-rw-r--r--target/image/generic/lzma-loader/src/print.c324
-rw-r--r--target/image/generic/lzma-loader/src/print.h36
-rw-r--r--target/image/generic/lzma-loader/src/printf.c35
-rw-r--r--target/image/generic/lzma-loader/src/printf.h18
-rw-r--r--target/image/generic/lzma-loader/src/start.S160
-rw-r--r--target/image/generic/lzma-loader/src/uart16550.c86
-rw-r--r--target/image/generic/lzma-loader/src/uart16550.h47
-rw-r--r--target/image/magicbox/Makefile38
-rw-r--r--target/image/rb532/Makefile57
-rwxr-xr-xtarget/image/uml/Makefile15
-rw-r--r--target/image/x86/Config.in20
-rw-r--r--target/image/x86/Makefile54
-rwxr-xr-xtarget/image/x86/gen_image.sh60
-rw-r--r--target/image/x86/grub/Makefile58
-rw-r--r--target/image/x86/grub/menu.lst11
-rw-r--r--target/image/xscale/Makefile32
-rw-r--r--target/linux/Config.in492
-rw-r--r--target/linux/Makefile24
-rw-r--r--target/linux/ar531x-2.4/Makefile22
-rw-r--r--target/linux/ar531x-2.4/config1164
-rw-r--r--target/linux/ar531x-2.4/patches/000-atheros-support.patch11411
-rw-r--r--target/linux/ar7-2.4/Config.in29
-rw-r--r--target/linux/ar7-2.4/Makefile72
-rw-r--r--target/linux/ar7-2.4/config1080
-rw-r--r--target/linux/ar7-2.4/patches/000-ar7_support.patch9549
-rw-r--r--target/linux/ar7-2.4/patches/001-flash_map.patch307
-rw-r--r--target/linux/ar7-2.4/patches/002-led_driver.patch1915
-rw-r--r--target/linux/ar7-2.4/patches/003-net_driver_cpmac.patch13341
-rw-r--r--target/linux/ar7-2.4/patches/004-atm_driver.patch27232
-rw-r--r--target/linux/ar7-2.4/patches/005-wdt_driver.patch392
-rw-r--r--target/linux/ar7-2.4/patches/006-sched_use_tsc.patch84
-rw-r--r--target/linux/aruba-2.6/Makefile22
-rw-r--r--target/linux/aruba-2.6/config1539
-rw-r--r--target/linux/aruba-2.6/patches/000-aruba.patch10521
-rw-r--r--target/linux/aruba-2.6/patches/001-flash.patch159
-rw-r--r--target/linux/aruba-2.6/patches/002-irq.patch286
-rw-r--r--target/linux/aruba-2.6/patches/003-pci.patch618
-rw-r--r--target/linux/aruba-2.6/patches/004-wdt.patch126
-rw-r--r--target/linux/aruba-2.6/patches/010-ar2313_enet.patch2175
-rw-r--r--target/linux/aruba-2.6/patches/011-ap6x_serial_fix.patch31
-rw-r--r--target/linux/aruba-2.6/patches/012-ehci_softirq.patch70
-rw-r--r--target/linux/au1000-2.6/Makefile27
-rw-r--r--target/linux/au1000-2.6/config1595
-rw-r--r--target/linux/au1000-2.6/patches/001-redefinitions_fixes.patch26
-rw-r--r--target/linux/au1000-2.6/patches/002-mtx1_flash_map.patch16
-rw-r--r--target/linux/au1000-2.6/patches/003-zImage.patch1364
-rw-r--r--target/linux/au1000-2.6/patches/004-mtx1_watchdog.patch279
-rw-r--r--target/linux/au1000-2.6/patches/005-au1000_eth_link_beat.patch24
-rw-r--r--target/linux/au1000-2.6/patches/006-mtx1_system_button.patch241
-rw-r--r--target/linux/au1000-2.6/patches/007-mtx1_sio2.patch13
-rw-r--r--target/linux/au1000-2.6/patches/008-isdel_cardbus.patch63
-rw-r--r--target/linux/brcm-2.4/Makefile22
-rw-r--r--target/linux/brcm-2.4/config1385
-rw-r--r--target/linux/brcm-2.4/patches/001-bcm47xx.patch16794
-rw-r--r--target/linux/brcm-2.4/patches/002-wl_fix.patch348
-rw-r--r--target/linux/brcm-2.4/patches/003-bcm47xx_cache_fixes.patch498
-rw-r--r--target/linux/brcm-2.4/patches/004-flash.patch916
-rw-r--r--target/linux/brcm-2.4/patches/005-bluetooth_sco_buffer_align.patch12
-rw-r--r--target/linux/brcm-2.4/patches/006-ide_workaround.patch18
-rw-r--r--target/linux/brcm-2.4/patches/007-sched_use_tsc.patch84
-rw-r--r--target/linux/brcm-2.4/patches/008-b44_bcm47xx_support.patch585
-rw-r--r--target/linux/brcm-2.4/patches/009-wrt54g3g_pcmcia.patch119
-rw-r--r--target/linux/brcm-2.4/patches/010-bcm47xx-cam_absent.patch42
-rw-r--r--target/linux/brcm-2.6/Makefile23
-rw-r--r--target/linux/brcm-2.6/config1740
-rw-r--r--target/linux/brcm-2.6/patches/001-bcm947xx.patch11862
-rw-r--r--target/linux/brcm-2.6/patches/002-flash-map.patch483
-rw-r--r--target/linux/brcm-2.6/patches/003-bcm4710_cache_fixes.patch354
-rw-r--r--target/linux/brcm-2.6/patches/004-b44_bcm47xx_support.patch699
-rw-r--r--target/linux/brcm-2.6/patches/010-bcm47xx-cam_absent.patch42
-rw-r--r--target/linux/brcm63xx-2.6/Makefile23
-rw-r--r--target/linux/brcm63xx-2.6/config1629
-rw-r--r--target/linux/brcm63xx-2.6/patches/001-bcm963xx.patch9656
-rw-r--r--target/linux/brcm63xx-2.6/patches/040-bcm963xx_flashmap.patch213
-rw-r--r--target/linux/brcm63xx-2.6/patches/100-binary_hacks.patch267
-rw-r--r--target/linux/control/kernel.control4
-rw-r--r--target/linux/control/kmod-atm.control4
-rw-r--r--target/linux/control/kmod-ax25.control4
-rw-r--r--target/linux/control/kmod-bluetooth.control4
-rw-r--r--target/linux/control/kmod-brcm-et.control4
-rw-r--r--target/linux/control/kmod-brcm-wl.control4
-rw-r--r--target/linux/control/kmod-brcm-wl2.control5
-rw-r--r--target/linux/control/kmod-cpmac.control4
-rw-r--r--target/linux/control/kmod-fs-cifs.control4
-rw-r--r--target/linux/control/kmod-fs-ext2.control4
-rw-r--r--target/linux/control/kmod-fs-ext3.control4
-rw-r--r--target/linux/control/kmod-fs-hfsplus.control4
-rw-r--r--target/linux/control/kmod-fs-minix.control4
-rw-r--r--target/linux/control/kmod-fs-nfs.control4
-rw-r--r--target/linux/control/kmod-fs-vfat.control4
-rw-r--r--target/linux/control/kmod-fs-xfs.control4
-rw-r--r--target/linux/control/kmod-imq.control4
-rw-r--r--target/linux/control/kmod-iptables-extra.control4
-rw-r--r--target/linux/control/kmod-iptables.control4
-rw-r--r--target/linux/control/kmod-loop.control4
-rw-r--r--target/linux/control/kmod-lp.control4
-rw-r--r--target/linux/control/kmod-nbd.control4
-rw-r--r--target/linux/control/kmod-net-airo.control4
-rw-r--r--target/linux/control/kmod-net-hermes-pci.control4
-rw-r--r--target/linux/control/kmod-net-hermes-plx.control4
-rw-r--r--target/linux/control/kmod-net-hermes.control4
-rw-r--r--target/linux/control/kmod-net-prism54.control4
-rw-r--r--target/linux/control/kmod-nls-base.control4
-rw-r--r--target/linux/control/kmod-nls-cp437.control4
-rw-r--r--target/linux/control/kmod-nls-cp850.control4
-rw-r--r--target/linux/control/kmod-nls-iso8859-1.control4
-rw-r--r--target/linux/control/kmod-nls-iso8859-15.control4
-rw-r--r--target/linux/control/kmod-nls-utf8.control4
-rw-r--r--target/linux/control/kmod-pcmcia-core.control4
-rw-r--r--target/linux/control/kmod-pcmcia-serial.control4
-rw-r--r--target/linux/control/kmod-pwc.control4
-rw-r--r--target/linux/control/kmod-sangam-atm-annex-a.control4
-rw-r--r--target/linux/control/kmod-sangam-atm-annex-b.control4
-rw-r--r--target/linux/control/kmod-softdog.control4
-rw-r--r--target/linux/control/kmod-soundcore.control4
-rw-r--r--target/linux/control/kmod-usb-acm.control4
-rw-r--r--target/linux/control/kmod-usb-atm-speedtouch.control4
-rw-r--r--target/linux/control/kmod-usb-atm.control5
-rw-r--r--target/linux/control/kmod-usb-audio.control5
-rw-r--r--target/linux/control/kmod-usb-core.control4
-rw-r--r--target/linux/control/kmod-usb-ohci.control4
-rw-r--r--target/linux/control/kmod-usb-printer.control4
-rw-r--r--target/linux/control/kmod-usb-serial-belkin.control4
-rw-r--r--target/linux/control/kmod-usb-serial-ftdi.control4
-rw-r--r--target/linux/control/kmod-usb-serial-mct-u232.control4
-rw-r--r--target/linux/control/kmod-usb-serial-pl2303.control4
-rw-r--r--target/linux/control/kmod-usb-serial-visor.control4
-rw-r--r--target/linux/control/kmod-usb-serial.control4
-rw-r--r--target/linux/control/kmod-usb-storage.control4
-rw-r--r--target/linux/control/kmod-usb-uhci.control4
-rw-r--r--target/linux/control/kmod-usb2.control4
-rw-r--r--target/linux/control/kmod-videodev.control4
-rw-r--r--target/linux/control/kmod-wd1100.control4
-rw-r--r--target/linux/generic-2.4/README98
-rw-r--r--target/linux/generic-2.4/patches/000-linux_mips.patch27959
-rw-r--r--target/linux/generic-2.4/patches/001-squashfs.patch4070
-rw-r--r--target/linux/generic-2.4/patches/002-squashfs_lzma.patch883
-rw-r--r--target/linux/generic-2.4/patches/003-jffs2_compression.patch9119
-rw-r--r--target/linux/generic-2.4/patches/004-exec_pagesize.patch11
-rw-r--r--target/linux/generic-2.4/patches/005-mtd_flashtypes.patch925
-rw-r--r--target/linux/generic-2.4/patches/006-gcc4_fixes.patch522
-rw-r--r--target/linux/generic-2.4/patches/007-more_gcc4_fixes.patch1339
-rw-r--r--target/linux/generic-2.4/patches/008-intel_flashchip_fix.patch101
-rw-r--r--target/linux/generic-2.4/patches/009-calibrate_section.patch11
-rw-r--r--target/linux/generic-2.4/patches/010-disable_old_squashfs_compatibility.patch25
-rw-r--r--target/linux/generic-2.4/patches/050-build_flags.patch83
-rw-r--r--target/linux/generic-2.4/patches/051-remove_pcmcia_modinst_compat.patch21
-rw-r--r--target/linux/generic-2.4/patches/100-wireless-extension.patch1121
-rw-r--r--target/linux/generic-2.4/patches/106-mppe_mppc.patch1649
-rw-r--r--target/linux/generic-2.4/patches/107-cifs.patch22022
-rw-r--r--target/linux/generic-2.4/patches/108-optional_aout_support.patch688
-rw-r--r--target/linux/generic-2.4/patches/109-ipsec_nat_traversal.patch140
-rw-r--r--target/linux/generic-2.4/patches/110-netdev_random_core.patch296
-rw-r--r--target/linux/generic-2.4/patches/112-bridging_performance.patch22
-rw-r--r--target/linux/generic-2.4/patches/113-even_more_gcc4_stuff.patch367
-rw-r--r--target/linux/generic-2.4/patches/200-i4l.patch20247
-rw-r--r--target/linux/generic-2.4/patches/201-hfc_usb_backport.patch2663
-rw-r--r--target/linux/generic-2.4/patches/202-pl2303_backport.patch40
-rw-r--r--target/linux/generic-2.4/patches/203-hfsplus_fix.patch23
-rw-r--r--target/linux/generic-2.4/patches/206-gcc_3.4_fixes.patch225
-rw-r--r--target/linux/generic-2.4/patches/208-usb2_fix.patch15
-rw-r--r--target/linux/generic-2.4/patches/209-build_fixes.patch48
-rw-r--r--target/linux/generic-2.4/patches/210-fix-irq-serial.patch21
-rw-r--r--target/linux/generic-2.4/patches/212-htb_time_fix.patch75
-rw-r--r--target/linux/generic-2.4/patches/213-htb_disable_hysteresis.patch11
-rw-r--r--target/linux/generic-2.4/patches/222-sound.patch27
-rw-r--r--target/linux/generic-2.4/patches/224-atm_hotplug.patch98
-rw-r--r--target/linux/generic-2.4/patches/225-string_lib_useful_exports.patch170
-rw-r--r--target/linux/generic-2.4/patches/226-atm_br2684.patch578
-rw-r--r--target/linux/generic-2.4/patches/227-jffs2_eofdetect.patch97
-rw-r--r--target/linux/generic-2.4/patches/228-more_usb_fixes.patch861
-rw-r--r--target/linux/generic-2.4/patches/229-pppoe_mtu_fix.patch12
-rw-r--r--target/linux/generic-2.4/patches/601-netfilter_ipp2p_0.8.1rc1.patch929
-rw-r--r--target/linux/generic-2.4/patches/602-netfilter_layer7_2.1nbd.patch2083
-rw-r--r--target/linux/generic-2.4/patches/603-netfilter_nat_pptp.patch2412
-rw-r--r--target/linux/generic-2.4/patches/604-netfilter_maxconn.patch20
-rw-r--r--target/linux/generic-2.4/patches/605-netfilter_TTL.patch180
-rw-r--r--target/linux/generic-2.4/patches/606-netfilter_NETMAP.patch159
-rw-r--r--target/linux/generic-2.4/patches/607-netfilter_connmark.patch351
-rw-r--r--target/linux/generic-2.4/patches/608-netfilter_ipset.patch5725
-rw-r--r--target/linux/generic-2.4/patches/609-netfilter_string.patch348
-rw-r--r--target/linux/generic-2.4/patches/610-netfilter_connbytes.patch439
-rw-r--r--target/linux/generic-2.4/patches/611-netfilter_condition.patch625
-rw-r--r--target/linux/generic-2.4/patches/612-netfilter_quota.patch147
-rw-r--r--target/linux/generic-2.4/patches/613-netfilter_nat_h323.patch821
-rw-r--r--target/linux/generic-2.4/patches/614-netfilter_nat_rtsp.patch1523
-rw-r--r--target/linux/generic-2.4/patches/615-netfilter_nat_mms.patch739
-rw-r--r--target/linux/generic-2.4/patches/616-netfilter_imq.patch748
-rw-r--r--target/linux/generic-2.4/patches/617-netfilter_time.patch238
-rw-r--r--target/linux/generic-2.4/patches/618-netfilter_multiport_backport.patch231
-rw-r--r--target/linux/generic-2.4/patches/700-multiple_default_gateways.patch1299
-rwxr-xr-xtarget/linux/generic-2.6/files/init82
-rw-r--r--target/linux/generic-2.6/patches/000-reenable_devfs.patch718
-rw-r--r--target/linux/generic-2.6/patches/001-squashfs.patch4173
-rw-r--r--target/linux/generic-2.6/patches/002-squashfs_lzma.patch886
-rw-r--r--target/linux/generic-2.6/patches/004-extra_optimization.patch12
-rw-r--r--target/linux/generic-2.6/patches/005-gcc4_fix.patch221
-rw-r--r--target/linux/generic-2.6/patches/006-gcc4_inline_fix.patch11
-rw-r--r--target/linux/generic-2.6/patches/010-disable_old_squashfs_compatibility.patch22
-rw-r--r--target/linux/generic-2.6/patches/011-mips_boot.patch15
-rw-r--r--target/linux/generic-2.6/patches/100-netfilter_layer7_2.1nbd.patch2071
-rw-r--r--target/linux/generic-2.6/patches/101-ipp2p_0.8.1rc1.patch935
-rw-r--r--target/linux/generic-2.6/patches/102-openswan-2.4.0.kernel-2.6-natt.patch171
-rw-r--r--target/linux/generic-2.6/patches/103-netfilter-ipset.patch5739
-rw-r--r--target/linux/generic-2.6/patches/105-netfilter_time.patch241
-rw-r--r--target/linux/generic-2.6/patches/106-netfilter_imq.patch885
-rw-r--r--target/linux/generic-2.6/patches/107-netfilter_nat_sip.patch830
-rw-r--r--target/linux/generic-2.6/patches/108-netfilter_route.patch914
-rw-r--r--target/linux/generic-2.6/patches/200-sched_esfq.patch730
-rw-r--r--target/linux/generic-2.6/patches/201-multiple_default_gateways.patch1238
-rw-r--r--target/linux/generic-2.6/patches/202-mips-freestanding.patch12
-rw-r--r--target/linux/generic-2.6/patches/203-fix_initrd_duplication.patch13
-rw-r--r--target/linux/generic-2.6/patches/204-jffs2_eofdetect.patch58
-rw-r--r--target/linux/generic-2.6/patches/205-block2mtd_fix.patch235
-rw-r--r--target/linux/generic-2.6/patches/206-pppoe_mtu_fix.patch12
-rw-r--r--target/linux/magicbox-2.6/Makefile22
-rw-r--r--target/linux/magicbox-2.6/config1161
-rw-r--r--target/linux/magicbox-2.6/patches/001-magicbox_support.patch372
-rw-r--r--target/linux/magicbox-2.6/patches/002-flash_map.patch147
-rw-r--r--target/linux/package/Config.in1
-rw-r--r--target/linux/package/Makefile54
-rw-r--r--target/linux/rb532-2.6/Makefile22
-rw-r--r--target/linux/rb532-2.6/config1335
-rw-r--r--target/linux/rb532-2.6/patches/100-rb5xx_support.patch5606
-rw-r--r--target/linux/rb532-2.6/patches/110-korina_ethernet.patch1375
-rw-r--r--target/linux/rb532-2.6/patches/120-cf.patch990
-rw-r--r--target/linux/rb532-2.6/patches/130-custom_partitions.patch311
-rw-r--r--target/linux/rb532-2.6/patches/200-bridge_resource_hack.patch13
-rw-r--r--target/linux/rb532-2.6/patches/210-pci_fixes.patch46
-rw-r--r--target/linux/rb532-2.6/patches/220-serial_fix.patch18
-rw-r--r--target/linux/rb532-2.6/patches/230-dma_limit.patch13
-rw-r--r--target/linux/rb532-2.6/patches/240-via_rhine_performance.patch461
-rw-r--r--target/linux/sibyte-2.6/Makefile22
-rw-r--r--target/linux/sibyte-2.6/config1313
-rw-r--r--target/linux/sibyte-2.6/patches/000-DUART.patch957
-rw-r--r--target/linux/sibyte-2.6/patches/001-bcm112x_ax.patch17
-rw-r--r--target/linux/uml-2.6/Makefile21
-rw-r--r--target/linux/uml-2.6/README45
-rw-r--r--target/linux/uml-2.6/config904
-rw-r--r--target/linux/x86-2.6/Makefile21
-rw-r--r--target/linux/x86-2.6/config2077
-rw-r--r--target/linux/x86-2.6/patches/100-scx200_hr_timer.patch320
-rw-r--r--target/linux/xscale-2.6/Makefile21
-rw-r--r--target/linux/xscale-2.6/config1384
-rw-r--r--target/linux/xscale-2.6/patches/001-gateway_7001.patch163
-rw-r--r--target/sdk/Config.in9
-rw-r--r--target/sdk/Makefile47
-rw-r--r--target/sdk/files/Makefile69
-rw-r--r--target/sdk/files/README.SDK7
-rw-r--r--target/sdk/files/package/depend.mk6
-rw-r--r--target/sdk/files/package/rules.mk89
-rw-r--r--target/utils/Makefile32
-rw-r--r--target/utils/src/addpattern.c235
-rw-r--r--target/utils/src/dgfirmware.c376
-rw-r--r--target/utils/src/motorola-bin.c146
-rw-r--r--target/utils/src/trx.c366
292 files changed, 296373 insertions, 0 deletions
diff --git a/target/Config.in b/target/Config.in
new file mode 100644
index 0000000..effd9d7
--- /dev/null
+++ b/target/Config.in
@@ -0,0 +1,272 @@
+choice
+ prompt "Target System"
+ default LINUX_2_4_BRCM
+
+config LINUX_2_6_AU1000
+ bool "AMD Alchemy AUxx [2.6]"
+ select mipsel
+ select LINUX_2_6
+ select PCI_SUPPORT
+ select USB_SUPPORT
+ select USES_JFFS2
+ help
+ Build firmware for AMD Alchemy 1500 boards
+ (e.g. 4G-Systems Mesh/Access Cube ...)
+
+config LINUX_2_6_ARUBA
+ bool "Aruba [2.6]"
+ select mips
+ select LINUX_2_6
+ select PCI_SUPPORT
+ select USB_SUPPORT
+ select USES_JFFS2
+ help
+ Build firmware images for Aruba boards
+
+config LINUX_2_4_AR531X
+ bool "Atheros AR531x [2.4]"
+ depends BROKEN
+ select mips
+ select LINUX_2_4
+ select USES_JFFS2
+ help
+ Build firmware images for Atheros AR531x based boards
+ (e.g. Netgear WGT624, Linksys WRT55AG)
+
+config LINUX_2_4_BRCM
+ bool "Broadcom BCM47xx/53xx [2.4]"
+ select mipsel
+ select PCI_SUPPORT
+ select USB_SUPPORT
+ select PCMCIA_SUPPORT
+ select USES_SQUASHFS
+ select USES_JFFS2
+ help
+ Build firmware images for Broadcom based routers
+ (e.g. Linksys WRT54G(S), Asus WL-500g, Motorola WR850G)
+
+ This one builds the generic .trx images, activate one of the
+ options below for creating device specific files for use
+ with TFTP client too.
+
+config LINUX_2_6_BRCM
+ bool "Broadcom BCM47xx/53xx [2.6]"
+ select mipsel
+ select LINUX_2_6
+ select PCI_SUPPORT
+ select USB_SUPPORT
+ #select PCMCIA_SUPPORT
+ select USES_SQUASHFS
+ select USES_JFFS2
+ help
+ Build firmware images for Broadcom based routers
+ (e.g. Netgear WGT634u)
+
+config LINUX_2_6_BRCM63XX
+ bool "Broadcom BCM63xx [2.6]"
+ depends BROKEN
+ select mips
+ select LINUX_2_6
+ select PCI_SUPPORT
+ select USB_SUPPORT
+ select PCMCIA_SUPPORT
+ select USES_SQUASHFS
+ select USES_JFFS2
+ help
+ Build firmware images for Broadcom based xDSL/routers
+ (e.g. Inventel Livebox, Siemens SE515)
+
+config LINUX_2_6_XSCALE
+ bool "Intel XScale [2.6]"
+ select armeb
+ select LINUX_2_6
+ select PCI_SUPPORT
+ select USB_SUPPORT
+ select USES_JFFS2
+
+config LINUX_2_6_MAGICBOX
+ bool "Magicbox [2.6]"
+ select powerpc
+ select LINUX_2_6
+ select PCI_SUPPORT
+ select USES_JFFS2
+
+config LINUX_2_6_RB532
+ bool "Mikrotik RB532 [2.6]"
+ select mipsel
+ select LINUX_2_6
+ select PCI_SUPPORT
+ select USES_JFFS2
+
+config LINUX_2_4_AR7
+ bool "TI AR7 [2.4]"
+ select mipsel
+ select USES_SQUASHFS
+ select USES_JFFS2
+ help
+ Build firmware images for TI AR7 based routers (w.g. Linksys WAG54G v2)
+
+config LINUX_2_6_X86
+ bool "x86 [2.6]"
+ select i386
+ select LINUX_2_6
+ select PCI_SUPPORT
+ select USB_SUPPORT
+ select PCMCIA_SUPPORT
+ select USES_JFFS2
+ help
+ Build firmware images for x86 based boards
+ (e.g. Soekris net4521 and net4801, PC Engines WRAP...)
+
+config LINUX_2_6_UML
+ bool "x86 [uml]"
+ select i386
+ select LINUX_2_6
+ help
+ Build uml targetted images
+
+if DEVEL
+
+config LINUX_2_6_ARM
+ bool "UNSUPPORTED little-endian arm platform"
+ depends BROKEN
+ select LINUX_2_6
+ select arm
+
+config LINUX_2_6_CRIS
+ bool "UNSUPPORTED cris platform"
+ depends BROKEN
+ select LINUX_2_6
+ select cris
+
+config LINUX_2_6_M68K
+ bool "UNSUPPORTED m68k platform"
+ depends BROKEN
+ select LINUX_2_6
+ select m68k
+
+config LINUX_2_6_SH3
+ bool "UNSUPPORTED little-endian sh3 platform"
+ depends BROKEN
+ select LINUX_2_6
+ select sh3
+
+config LINUX_2_6_SH3EB
+ bool "UNSUPPORTED big-endian sh3 platform"
+ depends BROKEN
+ select LINUX_2_6
+ select sh3eb
+
+config LINUX_2_6_SH4
+ bool "UNSUPPORTED little-endian sh4 platform"
+ depends BROKEN
+ select LINUX_2_6
+ select sh4
+
+config LINUX_2_6_SH4EB
+ bool "UNSUPPORTED big-endian sh4 platform"
+ depends BROKEN
+ select LINUX_2_6
+ select sh4eb
+
+config LINUX_2_6_SPARC
+ bool "UNSUPPORTED sparc platform"
+ depends BROKEN
+ select LINUX_2_6
+ select sparc
+
+endif
+
+endchoice
+
+
+# Kernel/Hardware features
+
+config LINUX_2_4
+ bool
+
+config LINUX_2_6
+ bool
+
+config PCI_SUPPORT
+ bool
+
+config PCMCIA_SUPPORT
+ bool
+
+config USB_SUPPORT
+ bool
+
+config BIG_ENDIAN
+ bool
+
+config USES_SQUASHFS
+ bool
+
+config USES_JFFS2
+ bool
+
+# Architecture selection
+
+config i386
+ bool
+
+config mips
+ select BIG_ENDIAN
+ bool
+
+config mipsel
+ bool
+
+config arm
+ bool
+
+config armeb
+ select BIG_ENDIAN
+ bool
+
+config cris
+ bool
+
+config m68k
+ bool
+
+config powerpc
+ select BIG_ENDIAN
+ bool
+
+config sh3
+ bool
+
+config sh3eb
+ select BIG_ENDIAN
+ bool
+
+config sh4
+ bool
+
+config sh4eb
+ select BIG_ENDIAN
+ bool
+
+config sparc
+ select BIG_ENDIAN
+ bool
+
+config ARCH
+ string
+ default "arm" if arm
+ default "armeb" if armeb
+ default "cris" if cris
+ default "i386" if i386
+ default "m68k" if m68k
+ default "mips" if mips
+ default "mipsel" if mipsel
+ default "powerpc" if powerpc
+ default "sh3" if sh3
+ default "sh3eb" if sh3eb
+ default "sh4" if sh4
+ default "sh4eb" if sh4eb
+ default "sparc" if sparc
+ default "mipsel" if !DEVEL
+
diff --git a/target/Makefile b/target/Makefile
new file mode 100644
index 0000000..195878e
--- /dev/null
+++ b/target/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/target.mk
+
+all: install
+
+$(BIN_DIR):
+ mkdir -p $(BIN_DIR)
+
+TARGETS-y := linux utils
+TARGETS-$(CONFIG_SDK) += sdk
+
+linux-compile: utils-install
+linux-install: $(BIN_DIR)
+sdk-compile: linux-install
+image_install: linux-install
+
+download: $(patsubst %,%-download,$(TARGETS-y))
+prepare: linux-prepare
+compile: linux-compile image_compile
+install: image_clean $(patsubst %,%-install,$(TARGETS-y)) image_install
+clean: $(patsubst %,%-clean,$(TARGETS-y)) image_clean
+
+image_clean: FORCE
+ $(MAKE) -C image/$(BOARD) clean
+ rm -f $(BIN_DIR)/openwrt-*
+
+image_compile: FORCE
+ $(MAKE) -C image/$(BOARD) compile
+
+image_install: image_compile
+ $(MAKE) -C image/$(BOARD) install
+
+%-clean: FORCE
+ $(MAKE) -C $(patsubst %-clean,%,$@) clean
+%-download: FORCE
+ $(MAKE) -C $(patsubst %-download,%,$@) download
+%-prepare: FORCE
+ $(MAKE) -C $(patsubst %-prepare,%,$@) prepare
+%-compile: %-prepare
+ $(MAKE) -C $(patsubst %-compile,%,$@) compile
+%-install: %-compile
+ $(MAKE) -C $(patsubst %-install,%,$@) install
+
diff --git a/target/image/ar7/Makefile b/target/image/ar7/Makefile
new file mode 100644
index 0000000..d2af2d9
--- /dev/null
+++ b/target/image/ar7/Makefile
@@ -0,0 +1,102 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/ar7loader
+
+LOADADDR := 0x94020000
+OUTPUT_FORMAT := elf32-tradlittlemips
+
+CFLAGS := -D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -Os \
+ -fno-strict-aliasing -fno-common -fomit-frame-pointer -G 0 -mno-abicalls -fno-pic \
+ -pipe -mlong-calls -fno-common \
+ -mabi=32 -march=mips32 -Wa,-32 -Wa,-march=mips32 -Wa,-mips32 -Wa,--trap \
+ -DLOADADDR=$(LOADADDR)
+
+$(PKG_BUILD_DIR)/cksum.o: $(PKG_BUILD_DIR)/cksum.c
+ $(HOSTCC) -o $@ $<
+
+$(PKG_BUILD_DIR)/ckmain.o: $(PKG_BUILD_DIR)/ckmain.c
+ $(HOSTCC) -o $@ $<
+
+$(PKG_BUILD_DIR)/tichksum: $(PKG_BUILD_DIR)/ckmain.o $(PKG_BUILD_DIR)/cksum.o
+ $(HOSTCC) -o $@ $<
+
+$(PKG_BUILD_DIR)/LzmaDecode.o: src/LzmaDecode.c
+ $(TARGET_CC) $(CFLAGS) -c -o $@ $<
+
+$(PKG_BUILD_DIR)/loader.o: src/loader.c
+ $(TARGET_CC) $(CFLAGS) -c -o $@ $<
+
+$(STAGING_DIR)/bin/srec2bin: src/srec2bin.c
+ $(HOSTCC) -o $@ $<
+
+
+define Build/Compile
+ mkdir -p $(PKG_BUILD_DIR)
+ sed -e 's/@@OUTPUT_FORMAT@@/$(OUTPUT_FORMAT)/' \
+ -e 's/@@LOADADDR@@/$(LOADADDR)/' \
+ < src/zimage.script.in \
+ > $(PKG_BUILD_DIR)/zimage.script
+ sed -e 's/@@OUTPUT_FORMAT@@/$(OUTPUT_FORMAT)/' \
+ -e 's/@@LOADADDR@@/$(LOADADDR)/' \
+ < src/ld.script.in \
+ > $(PKG_BUILD_DIR)/ld.script
+ $(MAKE) $(PKG_BUILD_DIR)/loader.o $(PKG_BUILD_DIR)/LzmaDecode.o $(STAGING_DIR)/bin/srec2bin
+endef
+
+define Build/Clean
+ rm -rf $(PKG_BUILD_DIR)
+endef
+
+define Image/Prepare
+ cat $(KDIR)/vmlinux | $(STAGING_DIR)/bin/lzma e -si -so -eos -lc1 -lp2 -pb2 > $(KDIR)/vmlinux.lzma
+ $(TARGET_CROSS)ld -T $(PKG_BUILD_DIR)/zimage.script -r -b binary $(KDIR)/vmlinux.lzma -o $(KDIR)/zimage.o
+ $(TARGET_CROSS)ld -static -G 0 --defsym kernel_entry=0x$${shell nm $(KDIR)/linux-*/vmlinux | grep kernel_entry | cut -d' ' -f1} -T $(PKG_BUILD_DIR)/ld.script \
+ $(PKG_BUILD_DIR)/loader.o \
+ $(PKG_BUILD_DIR)/LzmaDecode.o \
+ $(KDIR)/zimage.o \
+ -o $(KDIR)/loader
+ $(TARGET_CROSS)objcopy -O srec $(KDIR)/loader $(KDIR)/ram_zimage.sre
+ $(STAGING_DIR)/bin/srec2bin $(KDIR)/ram_zimage.sre $(KDIR)/vmlinux.bin
+endef
+
+define align/jffs2-64k
+bs=65536 conv=sync
+endef
+
+define align/jffs2-128k
+bs=131072 conv=sync
+endef
+
+define Image/Build/CyberTAN
+ (dd if=/dev/zero bs=16 count=1; cat $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).bin) | \
+ $(STAGING_DIR)/bin/addpattern -p $(3) -o $(BIN_DIR)/openwrt-$(2)-$(KERNEL)-$(4).bin
+endef
+
+define Image/Build/sErCoMm
+ cat sercomm/adam2.bin "$(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).bin" > "$(BIN_DIR)/openwrt-$(2)-$(KERNEL)-$(3).img"
+ dd if=sercomm/$(2) of="$(KDIR)/dgfw.tmp" bs=$$$$((0x3e0000 - 80)) seek=1 conv=notrunc
+ $(STAGING_DIR)/bin/dgfirmware -f -w "$(BIN_DIR)/openwrt-$(2)-$(KERNEL)-$(3).img" "$(KDIR)/dgfw.tmp"
+ rm -f "$(KDIR)/dgfw.tmp"
+endef
+
+define Image/Build
+ dd if=$(KDIR)/vmlinux.bin $(call align/$(1)) > $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).bin
+ cat $(BUILD_DIR)/linux-$(KERNEL)-$(BOARD)/root.$(1) >> $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).bin
+ $(call Image/Build/CyberTAN,$(1),AG1B,AG1B,$(1))
+ $(call Image/Build/CyberTAN,$(1),WA21,WA21,$(1))
+ $(call Image/Build/CyberTAN,$(1),WA22,WA22,$(1))
+ $(call Image/Build/CyberTAN,$(1),WAG2,WAG2,$(1))
+ $(call Image/Build/CyberTAN,$(1),WA31,WA31 -b,$(1))
+ $(call Image/Build/CyberTAN,$(1),WA32,WA32 -b,$(1))
+ $(call Image/Build/sErCoMm,$(1),dg834,$(1))
+ $(call Image/Build/sErCoMm,$(1),jdr454wb,$(1))
+endef
+
+$(eval $(call BuildImage))
diff --git a/target/image/ar7/sercomm/adam2.bin b/target/image/ar7/sercomm/adam2.bin
new file mode 100644
index 0000000..d4aa0cd
--- /dev/null
+++ b/target/image/ar7/sercomm/adam2.bin
Binary files differ
diff --git a/target/image/ar7/sercomm/dg834 b/target/image/ar7/sercomm/dg834
new file mode 100644
index 0000000..61fe336
--- /dev/null
+++ b/target/image/ar7/sercomm/dg834
Binary files differ
diff --git a/target/image/ar7/sercomm/jdr454wb b/target/image/ar7/sercomm/jdr454wb
new file mode 100644
index 0000000..821ff1c
--- /dev/null
+++ b/target/image/ar7/sercomm/jdr454wb
Binary files differ
diff --git a/target/image/ar7/src/LzmaDecode.c b/target/image/ar7/src/LzmaDecode.c
new file mode 100644
index 0000000..951700b
--- /dev/null
+++ b/target/image/ar7/src/LzmaDecode.c
@@ -0,0 +1,663 @@
+/*
+ LzmaDecode.c
+ LZMA Decoder
+
+ LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#ifndef Byte
+#define Byte unsigned char
+#endif
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+typedef struct _CRangeDecoder
+{
+ Byte *Buffer;
+ Byte *BufferLim;
+ UInt32 Range;
+ UInt32 Code;
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *InCallback;
+ int Result;
+ #endif
+ int ExtraBytes;
+} CRangeDecoder;
+
+Byte RangeDecoderReadByte(CRangeDecoder *rd)
+{
+ if (rd->Buffer == rd->BufferLim)
+ {
+ #ifdef _LZMA_IN_CB
+ UInt32 size;
+ rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size);
+ rd->BufferLim = rd->Buffer + size;
+ if (size == 0)
+ #endif
+ {
+ rd->ExtraBytes = 1;
+ return 0xFF;
+ }
+ }
+ return (*rd->Buffer++);
+}
+
+/* #define ReadByte (*rd->Buffer++) */
+#define ReadByte (RangeDecoderReadByte(rd))
+
+void RangeDecoderInit(CRangeDecoder *rd,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback
+ #else
+ Byte *stream, UInt32 bufferSize
+ #endif
+ )
+{
+ int i;
+ #ifdef _LZMA_IN_CB
+ rd->InCallback = inCallback;
+ rd->Buffer = rd->BufferLim = 0;
+ #else
+ rd->Buffer = stream;
+ rd->BufferLim = stream + bufferSize;
+ #endif
+ rd->ExtraBytes = 0;
+ rd->Code = 0;
+ rd->Range = (0xFFFFFFFF);
+ for(i = 0; i < 5; i++)
+ rd->Code = (rd->Code << 8) | ReadByte;
+}
+
+#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code;
+#define RC_FLUSH_VAR rd->Range = range; rd->Code = code;
+#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; }
+
+UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits)
+{
+ RC_INIT_VAR
+ UInt32 result = 0;
+ int i;
+ for (i = numTotalBits; i > 0; i--)
+ {
+ /* UInt32 t; */
+ range >>= 1;
+
+ result <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ result |= 1;
+ }
+ /*
+ t = (code - range) >> 31;
+ t &= 1;
+ code -= range & (t - 1);
+ result = (result + result) | (1 - t);
+ */
+ RC_NORMALIZE
+ }
+ RC_FLUSH_VAR
+ return result;
+}
+
+int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd)
+{
+ UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob;
+ if (rd->Code < bound)
+ {
+ rd->Range = bound;
+ *prob += (kBitModelTotal - *prob) >> kNumMoveBits;
+ if (rd->Range < kTopValue)
+ {
+ rd->Code = (rd->Code << 8) | ReadByte;
+ rd->Range <<= 8;
+ }
+ return 0;
+ }
+ else
+ {
+ rd->Range -= bound;
+ rd->Code -= bound;
+ *prob -= (*prob) >> kNumMoveBits;
+ if (rd->Range < kTopValue)
+ {
+ rd->Code = (rd->Code << 8) | ReadByte;
+ rd->Range <<= 8;
+ }
+ return 1;
+ }
+}
+
+#define RC_GET_BIT2(prob, mi, A0, A1) \
+ UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \
+ if (code < bound) \
+ { A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \
+ else \
+ { A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \
+ RC_NORMALIZE
+
+#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;)
+
+int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
+{
+ int mi = 1;
+ int i;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ for(i = numLevels; i > 0; i--)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + mi;
+ RC_GET_BIT(prob, mi)
+ #else
+ mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd);
+ #endif
+ }
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return mi - (1 << numLevels);
+}
+
+int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
+{
+ int mi = 1;
+ int i;
+ int symbol = 0;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ for(i = 0; i < numLevels; i++)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + mi;
+ RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i))
+ #else
+ int bit = RangeDecoderBitDecode(probs + mi, rd);
+ mi = mi + mi + bit;
+ symbol |= (bit << i);
+ #endif
+ }
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd)
+{
+ int symbol = 1;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ do
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + symbol;
+ RC_GET_BIT(prob, symbol)
+ #else
+ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
+ #endif
+ }
+ while (symbol < 0x100);
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte)
+{
+ int symbol = 1;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ do
+ {
+ int bit;
+ int matchBit = (matchByte >> 7) & 1;
+ matchByte <<= 1;
+ #ifdef _LZMA_LOC_OPT
+ {
+ CProb *prob = probs + ((1 + matchBit) << 8) + symbol;
+ RC_GET_BIT2(prob, symbol, bit = 0, bit = 1)
+ }
+ #else
+ bit = RangeDecoderBitDecode(probs + ((1 + matchBit) << 8) + symbol, rd);
+ symbol = (symbol << 1) | bit;
+ #endif
+ if (matchBit != bit)
+ {
+ while (symbol < 0x100)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + symbol;
+ RC_GET_BIT(prob, symbol)
+ #else
+ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
+ #endif
+ }
+ break;
+ }
+ }
+ while (symbol < 0x100);
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState)
+{
+ if(RangeDecoderBitDecode(p + LenChoice, rd) == 0)
+ return RangeDecoderBitTreeDecode(p + LenLow +
+ (posState << kLenNumLowBits), kLenNumLowBits, rd);
+ if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0)
+ return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid +
+ (posState << kLenNumMidBits), kLenNumMidBits, rd);
+ return kLenNumLowSymbols + kLenNumMidSymbols +
+ RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd);
+}
+
+#define kNumStates 12
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+#ifdef _LZMA_OUT_READ
+
+typedef struct _LzmaVarState
+{
+ CRangeDecoder RangeDecoder;
+ Byte *Dictionary;
+ UInt32 DictionarySize;
+ UInt32 DictionaryPos;
+ UInt32 GlobalPos;
+ UInt32 Reps[4];
+ int lc;
+ int lp;
+ int pb;
+ int State;
+ int PreviousIsMatch;
+ int RemainLen;
+} LzmaVarState;
+
+int LzmaDecoderInit(
+ unsigned char *buffer, UInt32 bufferSize,
+ int lc, int lp, int pb,
+ unsigned char *dictionary, UInt32 dictionarySize,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback
+ #else
+ unsigned char *inStream, UInt32 inSize
+ #endif
+ )
+{
+ LzmaVarState *vs = (LzmaVarState *)buffer;
+ CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
+ UInt32 i;
+ if (bufferSize < numProbs * sizeof(CProb) + sizeof(LzmaVarState))
+ return LZMA_RESULT_NOT_ENOUGH_MEM;
+ vs->Dictionary = dictionary;
+ vs->DictionarySize = dictionarySize;
+ vs->DictionaryPos = 0;
+ vs->GlobalPos = 0;
+ vs->Reps[0] = vs->Reps[1] = vs->Reps[2] = vs->Reps[3] = 1;
+ vs->lc = lc;
+ vs->lp = lp;
+ vs->pb = pb;
+ vs->State = 0;
+ vs->PreviousIsMatch = 0;
+ vs->RemainLen = 0;
+ dictionary[dictionarySize - 1] = 0;
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ RangeDecoderInit(&vs->RangeDecoder,
+ #ifdef _LZMA_IN_CB
+ inCallback
+ #else
+ inStream, inSize
+ #endif
+ );
+ return LZMA_RESULT_OK;
+}
+
+int LzmaDecode(unsigned char *buffer,
+ unsigned char *outStream, UInt32 outSize,
+ UInt32 *outSizeProcessed)
+{
+ LzmaVarState *vs = (LzmaVarState *)buffer;
+ CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
+ CRangeDecoder rd = vs->RangeDecoder;
+ int state = vs->State;
+ int previousIsMatch = vs->PreviousIsMatch;
+ Byte previousByte;
+ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+ UInt32 nowPos = 0;
+ UInt32 posStateMask = (1 << (vs->pb)) - 1;
+ UInt32 literalPosMask = (1 << (vs->lp)) - 1;
+ int lc = vs->lc;
+ int len = vs->RemainLen;
+ UInt32 globalPos = vs->GlobalPos;
+
+ Byte *dictionary = vs->Dictionary;
+ UInt32 dictionarySize = vs->DictionarySize;
+ UInt32 dictionaryPos = vs->DictionaryPos;
+
+ if (len == -1)
+ {
+ *outSizeProcessed = 0;
+ return LZMA_RESULT_OK;
+ }
+
+ while(len > 0 && nowPos < outSize)
+ {
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ len--;
+ }
+ if (dictionaryPos == 0)
+ previousByte = dictionary[dictionarySize - 1];
+ else
+ previousByte = dictionary[dictionaryPos - 1];
+#else
+
+int LzmaDecode(
+ Byte *buffer, UInt32 bufferSize,
+ int lc, int lp, int pb,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback,
+ #else
+ unsigned char *inStream, UInt32 inSize,
+ #endif
+ unsigned char *outStream, UInt32 outSize,
+ UInt32 *outSizeProcessed)
+{
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
+ CProb *p = (CProb *)buffer;
+ CRangeDecoder rd;
+ UInt32 i;
+ int state = 0;
+ int previousIsMatch = 0;
+ Byte previousByte = 0;
+ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+ UInt32 nowPos = 0;
+ UInt32 posStateMask = (1 << pb) - 1;
+ UInt32 literalPosMask = (1 << lp) - 1;
+ int len = 0;
+ if (bufferSize < numProbs * sizeof(CProb))
+ return LZMA_RESULT_NOT_ENOUGH_MEM;
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ RangeDecoderInit(&rd,
+ #ifdef _LZMA_IN_CB
+ inCallback
+ #else
+ inStream, inSize
+ #endif
+ );
+#endif
+
+ *outSizeProcessed = 0;
+ while(nowPos < outSize)
+ {
+ int posState = (int)(
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & posStateMask);
+ #ifdef _LZMA_IN_CB
+ if (rd.Result != LZMA_RESULT_OK)
+ return rd.Result;
+ #endif
+ if (rd.ExtraBytes != 0)
+ return LZMA_RESULT_DATA_ERROR;
+ if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0)
+ {
+ CProb *probs = p + Literal + (LZMA_LIT_SIZE *
+ (((
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+ if (state < 4) state = 0;
+ else if (state < 10) state -= 3;
+ else state -= 6;
+ if (previousIsMatch)
+ {
+ Byte matchByte;
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ matchByte = dictionary[pos];
+ #else
+ matchByte = outStream[nowPos - rep0];
+ #endif
+ previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte);
+ previousIsMatch = 0;
+ }
+ else
+ previousByte = LzmaLiteralDecode(probs, &rd);
+ outStream[nowPos++] = previousByte;
+ #ifdef _LZMA_OUT_READ
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #endif
+ }
+ else
+ {
+ previousIsMatch = 1;
+ if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1)
+ {
+ if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0)
+ {
+ if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0)
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos;
+ #endif
+ if (
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ == 0)
+ return LZMA_RESULT_DATA_ERROR;
+ state = state < 7 ? 9 : 11;
+ #ifdef _LZMA_OUT_READ
+ pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ outStream[nowPos++] = previousByte;
+ continue;
+ }
+ }
+ else
+ {
+ UInt32 distance;
+ if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0)
+ distance = rep1;
+ else
+ {
+ if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0)
+ distance = rep2;
+ else
+ {
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ len = LzmaLenDecode(p + RepLenCoder, &rd, posState);
+ state = state < 7 ? 8 : 11;
+ }
+ else
+ {
+ int posSlot;
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ state = state < 7 ? 7 : 10;
+ len = LzmaLenDecode(p + LenCoder, &rd, posState);
+ posSlot = RangeDecoderBitTreeDecode(p + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits), kNumPosSlotBits, &rd);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+ rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits);
+ if (posSlot < kEndPosModelIndex)
+ {
+ rep0 += RangeDecoderReverseBitTreeDecode(
+ p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd);
+ }
+ else
+ {
+ rep0 += RangeDecoderDecodeDirectBits(&rd,
+ numDirectBits - kNumAlignBits) << kNumAlignBits;
+ rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd);
+ }
+ }
+ else
+ rep0 = posSlot;
+ rep0++;
+ }
+ if (rep0 == (UInt32)(0))
+ {
+ /* it's for stream version */
+ len = -1;
+ break;
+ }
+ if (rep0 > nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ {
+ return LZMA_RESULT_DATA_ERROR;
+ }
+ len += kMatchMinLen;
+ do
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ outStream[nowPos++] = previousByte;
+ len--;
+ }
+ while(len > 0 && nowPos < outSize);
+ }
+ }
+
+ #ifdef _LZMA_OUT_READ
+ vs->RangeDecoder = rd;
+ vs->DictionaryPos = dictionaryPos;
+ vs->GlobalPos = globalPos + nowPos;
+ vs->Reps[0] = rep0;
+ vs->Reps[1] = rep1;
+ vs->Reps[2] = rep2;
+ vs->Reps[3] = rep3;
+ vs->State = state;
+ vs->PreviousIsMatch = previousIsMatch;
+ vs->RemainLen = len;
+ #endif
+
+ *outSizeProcessed = nowPos;
+ return LZMA_RESULT_OK;
+}
diff --git a/target/image/ar7/src/LzmaDecode.h b/target/image/ar7/src/LzmaDecode.h
new file mode 100644
index 0000000..f58944e
--- /dev/null
+++ b/target/image/ar7/src/LzmaDecode.h
@@ -0,0 +1,100 @@
+/*
+ LzmaDecode.h
+ LZMA Decoder interface
+
+ LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs,
+ but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+#ifndef UInt32
+#ifdef _LZMA_UINT32_IS_ULONG
+#define UInt32 unsigned long
+#else
+#define UInt32 unsigned int
+#endif
+#endif
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb unsigned short
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+#define LZMA_RESULT_NOT_ENOUGH_MEM 2
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+ int (*Read)(void *object, unsigned char **buffer, UInt32 *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+/*
+bufferSize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb)
+bufferSize += 100 in case of _LZMA_OUT_READ
+by default CProb is unsigned short,
+but if specify _LZMA_PROB_32, CProb will be UInt32(unsigned int)
+*/
+
+#ifdef _LZMA_OUT_READ
+int LzmaDecoderInit(
+ unsigned char *buffer, UInt32 bufferSize,
+ int lc, int lp, int pb,
+ unsigned char *dictionary, UInt32 dictionarySize,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback
+ #else
+ unsigned char *inStream, UInt32 inSize
+ #endif
+);
+#endif
+
+int LzmaDecode(
+ unsigned char *buffer,
+ #ifndef _LZMA_OUT_READ
+ UInt32 bufferSize,
+ int lc, int lp, int pb,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback,
+ #else
+ unsigned char *inStream, UInt32 inSize,
+ #endif
+ #endif
+ unsigned char *outStream, UInt32 outSize,
+ UInt32 *outSizeProcessed);
+
+#endif
diff --git a/target/image/ar7/src/gzip.h b/target/image/ar7/src/gzip.h
new file mode 100644
index 0000000..917e666
--- /dev/null
+++ b/target/image/ar7/src/gzip.h
@@ -0,0 +1,51 @@
+//bvb#include "timemmap.h"
+
+#define OF(args) args
+#define STATIC static
+
+#define WSIZE 0x8000 /* Slideing window size (defined as var
+ * "window" below) must be at least 32k,
+ * and a power of two. This is the
+ * data work window used for input buffer
+ * by the input routine */
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+
+static char *output_data;
+static ulg output_ptr;
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#define NOMEMCPY /* Does routine memcpy exist? */
+
+//bvb static uch *inbuf; /* input buffer */
+static uch *window;
+
+//bvb static uch outwin[WSIZE];
+
+//bvb static unsigned insize; /* valid bytes in inbuf */
+static unsigned inptr; /* index of next byte to process in inbuf */
+
+static unsigned outcnt; /* 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 */
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16 /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+static char *input_data;
+
+static void *freememstart;
diff --git a/target/image/ar7/src/ld.script.in b/target/image/ar7/src/ld.script.in
new file mode 100644
index 0000000..40389e6
--- /dev/null
+++ b/target/image/ar7/src/ld.script.in
@@ -0,0 +1,34 @@
+ OUTPUT_FORMAT("@@OUTPUT_FORMAT@@")
+ OUTPUT_ARCH(mips)
+ENTRY(tikernelunzip)
+ SECTIONS
+{
+
+ /* Allocate memory space on top of kernel bss space */
+ . = 0x94200000;
+ .text :
+ {
+ *(.text)
+ *(.rodata)
+ *(.rodata1)
+ *(.gnu.warning)
+ *(.text.init)
+ *(.data.init)
+ }
+
+ .data :
+ {
+ *(*)
+ }
+
+ .bss :
+ {
+ *(.dynbss)
+ *(COMMON)
+ *(.bss)
+ *(.sbss)
+ *(.scommon)
+ . = ALIGN (0x8000);
+ workspace = .;
+ }
+}
diff --git a/target/image/ar7/src/loader.c b/target/image/ar7/src/loader.c
new file mode 100644
index 0000000..22b909d
--- /dev/null
+++ b/target/image/ar7/src/loader.c
@@ -0,0 +1,140 @@
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+ version c10p1, 10 January 1993 */
+
+/*
+ * Adapted for booting Linux by Hannu Savolainen 1993
+ * based on gzip-1.0.3
+ *
+ * Nicolas Pitre <nico@visuaide.com>, 1999/04/14 :
+ * Little mods for all variable to reside either into rodata or bss segments
+ * by marking constant variables with 'const' and initializing all the others
+ * at run-time only. This allows for the kernel uncompressor to run
+ * directly from Flash or ROM memory on embeded systems.
+ */
+
+#include <linux/config.h>
+#include "gzip.h"
+#include "LzmaDecode.h"
+
+/* Function prototypes */
+unsigned char get_byte(void);
+int tikernelunzip(int,char *[], char *[]);
+static int tidecompress(uch *, uch *);
+
+void kernel_entry(int, char *[], char *[]);
+void (*ke)(int, char *[], char *[]); /* Gen reference to kernel function */
+void (*prnt)(unsigned int, char *); /* Gen reference to Yamon print function */
+void printf(char *ptr); /* Generate our own printf */
+
+int tikernelunzip(int argc, char *argv[], char *arge[])
+{
+ extern unsigned int _ftext;
+ extern uch kernelimage[];
+ uch *in, *out;
+ int status;
+
+ printf("Launching kernel decompressor.\n");
+
+ out = (unsigned char *) LOADADDR;
+ in = &(kernelimage[0]);
+
+ status = tidecompress(in, out);
+
+ if (status == 0) {
+ printf("Kernel decompressor was successful ... launching kernel.\n");
+
+ ke = ( void(*)(int, char *[],char*[]))kernel_entry;
+ (*ke)(argc,argv,arge);
+
+ return (0);
+ } else {
+ printf("Error in decompression.\n");
+ return(1);
+ }
+}
+
+#if 0
+char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+void print_i(int i)
+{
+ int j;
+ char buf[11];
+
+ buf[0] = '0';
+ buf[1] = 'x';
+ buf[10] = 0;
+
+ for (j = 0; j < 8; j++)
+ {
+ buf[2 + 7 - j] = hex[i & 0xf];
+ i = i >> 4;
+ }
+
+ printf(buf);
+}
+#endif
+
+int tidecompress(uch *indata, uch *outdata)
+{
+ extern unsigned int workspace;
+ extern unsigned char kernelimage[], kernelimage_end[];
+ unsigned int i; /* temp value */
+ unsigned int lc; /* literal context bits */
+ unsigned int lp; /* literal pos state bits */
+ unsigned int pb; /* pos state bits */
+ unsigned int osize; /* uncompressed size */
+ unsigned int wsize; /* window size */
+ unsigned int insize = kernelimage_end - kernelimage;
+ int status;
+
+ output_ptr = 0;
+ output_data = outdata;
+ input_data = indata;
+
+ /* lzma args */
+ i = get_byte();
+ lc = i % 9, i = i / 9;
+ lp = i % 5, pb = i / 5;
+
+ /* skip rest of the LZMA coder property */
+ for (i = 0; i < 4; i++)
+ get_byte();
+
+ /* read the lower half of uncompressed size in the header */
+ osize = ((unsigned int)get_byte()) +
+ ((unsigned int)get_byte() << 8) +
+ ((unsigned int)get_byte() << 16) +
+ ((unsigned int)get_byte() << 24);
+
+ /* skip rest of the header (upper half of uncompressed size) */
+ for (i = 0; i < 4; i++)
+ get_byte();
+
+ i = 0;
+ wsize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp))) * sizeof(CProb);
+
+ if ((status = LzmaDecode((unsigned char *) &workspace, wsize, lc, lp, pb,
+ indata + 13, insize - 13, (unsigned char *) output_data, osize, &i)) == LZMA_RESULT_OK)
+ return 0;
+
+ return status;
+}
+
+
+void printf(char *ptr)
+{
+ unsigned int *tempptr = (unsigned int *)0x90000534;
+ prnt = ( void (*)(unsigned int, char *)) *tempptr;
+ (*prnt)(0,ptr);
+}
+
+unsigned char get_byte()
+{
+ unsigned char c;
+
+ c = *input_data;
+ input_data++;
+
+ return c;
+}
+
diff --git a/target/image/ar7/src/srec2bin.c b/target/image/ar7/src/srec2bin.c
new file mode 100644
index 0000000..0eb8b20
--- /dev/null
+++ b/target/image/ar7/src/srec2bin.c
@@ -0,0 +1,523 @@
+#include <stdio.h>
+#include <ctype.h>
+
+//Rev 0.1 Original
+// 8 Jan 2001 MJH Added code to write data to Binary file
+// note: outputfile is name.bin, where name is first part
+// of input file. ie tmp.rec -> tmp.bin
+//
+// srec2bin <input SREC file> <Output Binary File> <If Present, Big Endian>
+//
+// TAG
+// bit32u TAG_BIG = 0xDEADBE42;
+// bit32u TAG_LITTLE = 0xFEEDFA42;
+//
+// File Structure
+//
+// TAG : 32 Bits
+// [DATA RECORDS]
+//
+// Data Records Structure
+//
+// LENGTH : 32 Bits <- Length of DATA, excludes ADDRESS and CHECKSUM
+// ADDRESS : 32 Bits
+// DATA : 8 Bits * LENGTH
+// CHECKSUM: 32 Bits <- 0 - (Sum of Length --> End of Data)
+//
+// Note : If Length == 0, Address will be Program Start
+//
+//
+//
+//
+//
+
+#define MajRevNum 0
+#define MinRevNum 2
+
+
+#define EndianSwitch(x) ((x >> 24) | (x << 24) | ((x << 8) & (0x00FF0000)) | ((x >> 8) & (0x0000FF00)) )
+
+typedef unsigned char bit8u;
+typedef unsigned int bit32u;
+typedef int bit32;
+
+#define FALSE 0
+#define TRUE (!FALSE)
+
+
+bit32u CheckSum;
+int RecStart;
+int debug;
+int verbose;
+
+FILE *OpenOutputFile( char *Name );
+FILE *fOut;
+bit32u RecLength=0;
+
+bit32u AddressCurrent;
+
+bit32u gh(char *cp,int nibs);
+
+int BigEndian;
+
+int inputline;
+
+// char buf[16*1024];
+
+char buffer[2048];
+char *cur_ptr;
+int cur_line=0;
+int cur_len=0;
+
+int s1s2s3_total=0;
+
+bit32u PBVal;
+int PBValid;
+bit32u PBAdr;
+
+
+void dumpfTell(char *s, bit32u Value)
+{
+ int Length;
+ Length = (int) RecLength;
+ if (debug)
+ printf("[%s ] ftell()[0x%08lX] Length[0x%4X] Length[%4d] Value[0x%08x]\n",
+ s, ftell(fOut), Length, Length, Value);
+}
+
+void DispHex(bit32u Hex)
+{
+// printf("%X", Hex);
+}
+
+void WaitDisplay(void)
+{
+ static int Count=0;
+ static int Index=0;
+ char iline[]={"-\\|/"};
+
+ Count++;
+ if ((Count % 32)==0)
+ {
+ if (verbose)
+ printf("%c%c",iline[Index++],8);
+ Index &= 3;
+ }
+}
+
+
+void binOut32 ( bit32u Data )
+{
+// On UNIX machine all 32bit writes need ENDIAN switched
+// Data = EndianSwitch(Data);
+// fwrite( &Data, sizeof(bit32u), 1, fOut);
+
+ char sdat[4];
+ int i;
+
+ for(i=0;i<4;i++)
+ sdat[i]=(char)(Data>>(i*8));
+ fwrite( sdat, 1, 4, fOut);
+ dumpfTell("Out32" , Data);
+}
+
+// Only update RecLength on Byte Writes
+// All 32 bit writes will be for Length etc
+
+void binOut8 ( bit8u Data )
+{
+ int n;
+ dumpfTell("B4Data" , (bit32u) (Data & 0xFF) );
+ n = fwrite( &Data, sizeof(bit8u), 1, fOut);
+ if (n != 1)
+ printf("Error in writing %X for Address 0x%8X\n", Data, AddressCurrent);
+ RecLength += 1;
+}
+
+// Currently ONLY used for outputting Program Start
+
+void binRecStart(bit32u Address)
+{
+ RecLength = 0;
+ CheckSum = Address;
+ RecStart = TRUE;
+
+ if (debug)
+ printf("[RecStart] CheckSum[0x%08X] Length[%4d] Address[0x%08X]\n",
+ CheckSum, RecLength, Address);
+
+
+ dumpfTell("RecLength", RecLength);
+ binOut32( RecLength );
+ dumpfTell("Address", Address);
+ binOut32( Address );
+}
+
+void binRecEnd(void)
+{
+ long RecEnd;
+
+ if (!RecStart) // if no record started, do not end it
+ {
+ return;
+ }
+
+ RecStart = FALSE;
+
+
+ RecEnd = ftell(fOut); // Save Current position
+
+ if (debug)
+ printf("[RecEnd ] CheckSum[0x%08X] Length[%4d] Length[0x%X] RecEnd[0x%08lX]\n",
+ CheckSum, RecLength, RecLength, RecEnd);
+
+ fseek( fOut, -((long) RecLength), SEEK_CUR); // move back Start Of Data
+
+ dumpfTell("Data ", -1);
+
+ fseek( fOut, -4, SEEK_CUR); // move back Start Of Address
+
+ dumpfTell("Address ", -1);
+
+ fseek( fOut, -4, SEEK_CUR); // move back Start Of Length
+
+ dumpfTell("Length ", -1);
+
+ binOut32( RecLength );
+
+ fseek( fOut, RecEnd, SEEK_SET); // move to end of Record
+
+ CheckSum += RecLength;
+
+ CheckSum = ~CheckSum + 1; // Two's complement
+
+ binOut32( CheckSum );
+
+ if (verbose)
+ printf("[Created Record of %d Bytes with CheckSum [0x%8X]\n", RecLength, CheckSum);
+}
+
+void binRecOutProgramStart(bit32u Address)
+{
+ if (Address != (AddressCurrent+1))
+ {
+ binRecEnd();
+ binRecStart(Address);
+ }
+ AddressCurrent = Address;
+}
+void binRecOutByte(bit32u Address, bit8u Data)
+{
+ // If Address is one after Current Address, output Byte
+ // If not, close out last record, update Length, write checksum
+ // Then Start New Record, updating Current Address
+
+ if (Address != (AddressCurrent+1))
+ {
+ binRecEnd();
+ binRecStart(Address);
+ }
+ AddressCurrent = Address;
+ CheckSum += Data;
+ binOut8( Data );
+}
+
+//=============================================================================
+// SUPPORT FUNCTIONS
+//=============================================================================
+int readline(FILE *fil,char *buf,int len)
+{
+ int rlen;
+
+ rlen=0;
+ if (len==0) return(0);
+ while(1)
+ {
+ if (cur_len==0)
+ {
+ cur_len=fread(buffer, 1, sizeof(buffer), fil);
+ if (cur_len==0)
+ {
+ if (rlen)
+ {
+ *buf=0;
+ return(rlen);
+ }
+ return(-1);
+ }
+ cur_ptr=buffer;
+ }
+ if (cur_len)
+ {
+ if (*cur_ptr=='\n')
+ {
+ *buf=0;
+ cur_ptr++;
+ cur_len--;
+ return(rlen);
+ }
+ else
+ {
+ if ((len>1)&&(*cur_ptr!='\r'))
+ {
+ *buf++=*cur_ptr++;
+ len--;
+ }
+ else
+ cur_ptr++;
+
+ rlen++;
+ cur_len--;
+ }
+ }
+ else
+ {
+ *buf=0;
+ cur_ptr++;
+ cur_len--;
+ return(rlen);
+ }
+ }
+}
+
+
+int SRLerrorout(char *c1,char *c2)
+{
+ printf("\nERROR: %s - '%s'.",c1,c2);
+ return(FALSE);
+}
+
+
+int checksum(char *cp,int count)
+{
+ char *scp;
+ int cksum;
+ int dum;
+
+ scp=cp;
+ while(*scp)
+ {
+ if (!isxdigit(*scp++))
+ return(SRLerrorout("Invalid hex digits",cp));
+ }
+ scp=cp;
+
+ cksum=count;
+
+ while(count)
+ {
+ cksum += gh(scp,2);
+ if (count == 2)
+ dum = ~cksum;
+ scp += 2;
+ count--;
+ }
+ cksum&=0x0ff;
+ // printf("\nCk:%02x",cksum);
+ return(cksum==0x0ff);
+}
+
+bit32u gh(char *cp,int nibs)
+{
+ int i;
+ bit32u j;
+
+ j=0;
+
+ for(i=0;i<nibs;i++)
+ {
+ j<<=4;
+ if ((*cp>='a')&&(*cp<='z')) *cp &= 0x5f;
+ if ((*cp>='0')&&(*cp<='9'))
+ j += (*cp-0x30);
+ else
+ if ((*cp>='A')&&(*cp<='F'))
+ j += (*cp-0x37);
+ else
+ SRLerrorout("Bad Hex char", cp);
+ cp++;
+ }
+ return(j);
+}
+
+
+//=============================================================================
+// PROCESS SREC LINE
+//=============================================================================
+
+int srecLine(char *pSrecLine)
+{
+ char *scp,ch;
+ int itmp,count,dat;
+ bit32u adr;
+ static bit32u RecordCounter=0;
+
+ cur_line++;
+ scp=pSrecLine;
+
+ if (*pSrecLine!='S')
+ return(SRLerrorout("Not an Srecord file",scp));
+ pSrecLine++;
+ if (strlen(pSrecLine)<4)
+ return(SRLerrorout("Srecord too short",scp));
+
+ ch=*pSrecLine++;
+
+ count=gh(pSrecLine,2);
+
+ pSrecLine += 2;
+
+ // if(debug)
+ // printf("count %d, strlen(pSrecLine) = %d, pSrecLine =[%s]\n", count, strlen(pSrecLine), pSrecLine);
+ RecordCounter++;
+ DispHex(RecordCounter);
+
+ if ((count*2) != strlen(pSrecLine)) return(SRLerrorout("Count field larger than record",scp));
+
+ if (!checksum(pSrecLine, count)) return(SRLerrorout("Bad Checksum",scp));
+
+ switch(ch)
+ {
+ case '0': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
+ itmp=gh(pSrecLine,4); pSrecLine+=4; count-=2;
+ if (itmp) return(SRLerrorout("Srecord 1 address not zero",scp));
+ break;
+ case '1': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
+ return(SRLerrorout("Srecord Not valid for MIPS",scp));
+ break;
+ case '2': if (count<4) return(SRLerrorout("Invalid Srecord count field",scp));
+ return(SRLerrorout("Srecord Not valid for MIPS",scp));
+ break;
+ case '3': if (count<5) return(SRLerrorout("Invalid Srecord count field",scp));
+ adr=gh(pSrecLine,8); pSrecLine+=8; count-=4;
+ count--;
+ while(count)
+ {
+ dat=gh(pSrecLine,2); pSrecLine+=2; count--;
+ binRecOutByte(adr, (char) (dat & 0xFF));
+ adr++;
+ }
+ s1s2s3_total++;
+ break;
+ case '4': return(SRLerrorout("Invalid Srecord type",scp));
+ break;
+ case '5': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
+ itmp=gh(pSrecLine,4); pSrecLine+=4; count-=2;
+ if (itmp|=s1s2s3_total) return(SRLerrorout("Incorrect number of S3 Record processed",scp));
+ break;
+ case '6': return(SRLerrorout("Invalid Srecord type",scp));
+ break;
+ case '7': // PROGRAM START
+ if (count<5) return(SRLerrorout("Invalid Srecord count field",scp));
+ adr=gh(pSrecLine,8); pSrecLine+=8; count-=4;
+ if (count!=1) return(SRLerrorout("Invalid Srecord count field",scp));
+ binRecOutProgramStart(adr);
+ break;
+ case '8': if (count<4) return(SRLerrorout("Invalid Srecord count field",scp));
+ return(SRLerrorout("Srecord Not valid for MIPS",scp));
+ break;
+ case '9': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
+ return(SRLerrorout("Srecord Not valid for MIPS",scp));
+ break;
+ default:
+ break;
+ }
+ return(TRUE);
+}
+
+
+//=============================================================================
+// MAIN LOGIC, READS IN LINE AND OUTPUTS BINARY
+//=============================================================================
+
+int srec2bin(int argc,char *argv[],int verbose)
+{
+ int i,rlen,sts;
+ FILE *fp;
+ char ac;
+ char buff[256];
+ bit32u TAG_BIG = 0xDEADBE42;
+ bit32u TAG_LITTLE = 0xFEEDFA42;
+
+ bit32u Tag;
+
+
+ if(argc < 3)
+ {
+ printf("\nError: <srec2bin <srec input file> <bin output file>\n\n");
+ return(0);
+ }
+
+ if (argc > 3) BigEndian=TRUE; else BigEndian=FALSE;
+
+ if (BigEndian)
+ Tag = TAG_BIG;
+ else
+ Tag = TAG_LITTLE;
+
+ if (verbose)
+ printf("\nEndian: %s, Tag is 0x%8X\n",(BigEndian)?"BIG":"LITTLE", Tag);
+
+ fp = fopen(argv[1],"rt");
+
+ if (fp==NULL)
+ {
+ printf("\nError: Opening input file, %s.", argv[1]);
+ return(0);
+ }
+
+ fOut = fopen( argv[2], "wb");
+
+ if (fOut==NULL)
+ {
+ printf("\nError: Opening Output file, %s.", argv[2]);
+ if(fp) fclose(fp);
+ return(0);
+ }
+
+ RecStart = FALSE;
+
+ AddressCurrent = 0xFFFFFFFFL;
+
+ // Setup Tag
+
+ dumpfTell("Tag", Tag);
+
+ binOut32(Tag);
+
+
+ inputline=0;
+ sts=TRUE;
+
+ rlen = readline(fp,buff,sizeof buff);
+
+ while( (sts) && (rlen != -1))
+ {
+ if (strlen(buff))
+ {
+ sts &= srecLine(buff);
+ WaitDisplay();
+ }
+ rlen = readline(fp,buff,sizeof buff);
+ }
+
+
+ // printf("PC: 0x%08X, Length 0x%08X, Tag 0x%08X\n", ProgramStart, RecLength, TAG_LITTLE);
+
+ binRecEnd();
+
+ if(fp) fclose(fp);
+ if(fOut) fclose(fOut);
+
+ return(1);
+}
+
+main(int argc, char *argv[])
+{
+ debug = TRUE;
+ debug = FALSE;
+ verbose = FALSE;
+ srec2bin(argc,argv,verbose);
+ return 0;
+}
+
diff --git a/target/image/ar7/src/zimage.script.in b/target/image/ar7/src/zimage.script.in
new file mode 100644
index 0000000..1a0865b
--- /dev/null
+++ b/target/image/ar7/src/zimage.script.in
@@ -0,0 +1,11 @@
+ OUTPUT_FORMAT("@@OUTPUT_FORMAT@@")
+OUTPUT_ARCH(mips)
+ SECTIONS
+{
+ .data :
+ {
+ kernelimage = .;
+ *(.data)
+ kernelimage_end = .;
+ }
+}
diff --git a/target/image/aruba/Makefile b/target/image/aruba/Makefile
new file mode 100644
index 0000000..09aa8ea
--- /dev/null
+++ b/target/image/aruba/Makefile
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+LOADADDR = 0x81000000 # RAM start + 16M
+KERNEL_ENTRY = 0x80100000
+RAMSIZE = 0x00100000 # 1MB
+
+LOADER_MAKEOPTS= \
+ KDIR=$(KDIR) \
+ LOADADDR=$(LOADADDR) \
+ KERNEL_ENTRY=$(KERNEL_ENTRY) \
+ RAMSIZE=$(RAMSIZE)
+
+define Build/Clean
+ $(MAKE) -C ../generic/lzma-loader $(LOADER_MAKEOPTS) clean
+endef
+
+define Image/Prepare
+ cat $(KDIR)/vmlinux | $(STAGING_DIR)/bin/lzma e -si -so -eos -lc1 -lp2 -pb2 > $(KDIR)/vmlinux.lzma
+ $(MAKE) -C ../generic/lzma-loader $(LOADER_MAKEOPTS) clean compile
+endef
+
+define Image/BuildKernel
+ ./addVersion -n ArubaOS $(KDIR)/loader.elf $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL).ari version
+endef
+
+define Image/Build/jffs2-64k
+ @dd if=$(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL).ari of=$(KDIR)/image.tmp bs=655360 conv=sync
+ @cat $(KDIR)/root.$(1) >> $(KDIR)/image.tmp
+ mv $(KDIR)/image.tmp $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(patsubst jffs2-%,jffs2,$(1)).bin
+endef
+
+define Image/Build
+ $(call Image/Build/$(1),$(1))
+endef
+
+$(eval $(call BuildImage))
diff --git a/target/image/aruba/addVersion b/target/image/aruba/addVersion
new file mode 100755
index 0000000..796f73a
--- /dev/null
+++ b/target/image/aruba/addVersion
Binary files differ
diff --git a/target/image/aruba/version b/target/image/aruba/version
new file mode 100644
index 0000000..fff5589
--- /dev/null
+++ b/target/image/aruba/version
@@ -0,0 +1 @@
+3.0.0.0
diff --git a/target/image/au1000/Makefile b/target/image/au1000/Makefile
new file mode 100644
index 0000000..0fb3cb2
--- /dev/null
+++ b/target/image/au1000/Makefile
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+define Build/Clean
+endef
+
+define Image/Prepare
+endef
+
+define Image/Build
+ $(TARGET_CROSS)objcopy -O srec -I binary --adjust-vma 0xbe000000 $(KDIR)/root.$(1) $(KDIR)/root.$(1).srec
+ grep -v S7 $(KDIR)/root.$(1).srec > $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).img
+ grep -v S0 $(LINUX_DIR)/arch/mips/boot/compressed/images/zImage.flash.srec >> $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).img
+endef
+
+$(eval $(call BuildImage))
diff --git a/target/image/brcm/Makefile b/target/image/brcm/Makefile
new file mode 100644
index 0000000..2dc599d
--- /dev/null
+++ b/target/image/brcm/Makefile
@@ -0,0 +1,69 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+define Build/Compile
+ rm -f $(KDIR)/loader.gz
+ $(MAKE) -C lzma-loader \
+ BUILD_DIR="$(KDIR)" \
+ TARGET="$(KDIR)" \
+ install
+ echo -ne "\\x00" >> $(KDIR)/loader.gz
+endef
+
+define Build/Clean
+ $(MAKE) -C lzma-loader clean
+endef
+
+define Image/Prepare
+ cat $(KDIR)/vmlinux | $(STAGING_DIR)/bin/lzma e -si -so -eos -lc1 -lp2 -pb2 > $(KDIR)/vmlinux.lzma
+endef
+
+define Image/Build/wgt634u
+ dd if=$(KDIR)/loader.elf of=$(BIN_DIR)/openwrt-wgt634u-$(KERNEL)-$(2).bin bs=131072 conv=sync
+ cat $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).trx >> $(BIN_DIR)/openwrt-wgt634u-$(KERNEL)-$(2).bin
+endef
+
+define Image/Build/CyberTAN
+ $(STAGING_DIR)/bin/addpattern -4 -p $(3) -v v$(4) -i $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).trx -o $(BIN_DIR)/openwrt-$(2)-$(KERNEL)-$(5).bin
+endef
+
+define Image/Build/Motorola
+ $(STAGING_DIR)/bin/motorola-bin -$(3) $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).trx $(BIN_DIR)/openwrt-$(2)-$(4).bin
+endef
+
+define trxalign/jffs2-128k
+-a 0x20000
+endef
+define trxalign/jffs2-64k
+-a 0x10000
+endef
+define trxalign/squashfs
+-a 1024
+endef
+
+define Image/Build
+ $(STAGING_DIR)/bin/trx -o $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).trx -f $(KDIR)/loader.gz -f $(KDIR)/vmlinux.lzma $(call trxalign/$(1)) -f $(KDIR)/root.$(1)
+ifneq ($(1),jffs2-128k)
+ $(call Image/Build/CyberTAN,$(1),wrt54g3g,W54F,1.99.5,$(patsubst jffs2-%,jffs2,$(1)))
+ $(call Image/Build/CyberTAN,$(1),wrt54g,W54G,4.40.1,$(patsubst jffs2-%,jffs2,$(1)))
+ $(call Image/Build/CyberTAN,$(1),wrt54gs_v4,W54s,1.09.1,$(patsubst jffs2-%,jffs2,$(1)))
+ $(call Image/Build/Motorola,$(1),wa840g,2,$(patsubst jffs2-%,jffs2,$(1)))
+ $(call Image/Build/Motorola,$(1),we800g,3,$(patsubst jffs2-%,jffs2,$(1)))
+endif
+ifneq ($(1),jffs2-64k)
+ $(call Image/Build/CyberTAN,$(1),wrt54gs,W54S,4.80.1,$(patsubst jffs2-%,jffs2,$(1)))
+ $(call Image/Build/CyberTAN,$(1),wrtsl54gs,W54U,2.00.5,$(patsubst jffs2-%,jffs2,$(1)))
+ifeq ($(KERNEL),2.6)
+ $(call Image/Build/wgt634u,$(1),$(patsubst jffs2-%,jffs2,$(1)))
+endif
+endif
+ $(call Image/Build/Motorola,$(1),wr850g,1,$(1))
+endef
+
+$(eval $(call BuildImage))
diff --git a/target/image/brcm/lzma-loader/Makefile b/target/image/brcm/lzma-loader/Makefile
new file mode 100644
index 0000000..b56cbaa
--- /dev/null
+++ b/target/image/brcm/lzma-loader/Makefile
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+# $Id$
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME := lzma-loader
+PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
+
+$(PKG_BUILD_DIR)/.prepared:
+ mkdir $(PKG_BUILD_DIR)
+ $(CP) ./src/* $(PKG_BUILD_DIR)/
+ touch $@
+
+$(PKG_BUILD_DIR)/loader.gz: $(PKG_BUILD_DIR)/.prepared
+ $(MAKE) -C $(PKG_BUILD_DIR) CC="$(TARGET_CC)" \
+ LD="$(TARGET_CROSS)ld" CROSS_COMPILE="$(TARGET_CROSS)"
+
+download:
+prepare: $(PKG_BUILD_DIR)/.prepared
+compile: $(PKG_BUILD_DIR)/loader.gz
+install:
+
+ifneq ($(TARGET),)
+install: compile
+ $(CP) $(PKG_BUILD_DIR)/loader.gz $(PKG_BUILD_DIR)/loader.elf $(TARGET)/
+endif
+
+clean:
+ rm -rf $(PKG_BUILD_DIR)
diff --git a/target/image/brcm/lzma-loader/src/LzmaDecode.c b/target/image/brcm/lzma-loader/src/LzmaDecode.c
new file mode 100644
index 0000000..951700b
--- /dev/null
+++ b/target/image/brcm/lzma-loader/src/LzmaDecode.c
@@ -0,0 +1,663 @@
+/*
+ LzmaDecode.c
+ LZMA Decoder
+
+ LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#ifndef Byte
+#define Byte unsigned char
+#endif
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+typedef struct _CRangeDecoder
+{
+ Byte *Buffer;
+ Byte *BufferLim;
+ UInt32 Range;
+ UInt32 Code;
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *InCallback;
+ int Result;
+ #endif
+ int ExtraBytes;
+} CRangeDecoder;
+
+Byte RangeDecoderReadByte(CRangeDecoder *rd)
+{
+ if (rd->Buffer == rd->BufferLim)
+ {
+ #ifdef _LZMA_IN_CB
+ UInt32 size;
+ rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size);
+ rd->BufferLim = rd->Buffer + size;
+ if (size == 0)
+ #endif
+ {
+ rd->ExtraBytes = 1;
+ return 0xFF;
+ }
+ }
+ return (*rd->Buffer++);
+}
+
+/* #define ReadByte (*rd->Buffer++) */
+#define ReadByte (RangeDecoderReadByte(rd))
+
+void RangeDecoderInit(CRangeDecoder *rd,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback
+ #else
+ Byte *stream, UInt32 bufferSize
+ #endif
+ )
+{
+ int i;
+ #ifdef _LZMA_IN_CB
+ rd->InCallback = inCallback;
+ rd->Buffer = rd->BufferLim = 0;
+ #else
+ rd->Buffer = stream;
+ rd->BufferLim = stream + bufferSize;
+ #endif
+ rd->ExtraBytes = 0;
+ rd->Code = 0;
+ rd->Range = (0xFFFFFFFF);
+ for(i = 0; i < 5; i++)
+ rd->Code = (rd->Code << 8) | ReadByte;
+}
+
+#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code;
+#define RC_FLUSH_VAR rd->Range = range; rd->Code = code;
+#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; }
+
+UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits)
+{
+ RC_INIT_VAR
+ UInt32 result = 0;
+ int i;
+ for (i = numTotalBits; i > 0; i--)
+ {
+ /* UInt32 t; */
+ range >>= 1;
+
+ result <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ result |= 1;
+ }
+ /*
+ t = (code - range) >> 31;
+ t &= 1;
+ code -= range & (t - 1);
+ result = (result + result) | (1 - t);
+ */
+ RC_NORMALIZE
+ }
+ RC_FLUSH_VAR
+ return result;
+}
+
+int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd)
+{
+ UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob;
+ if (rd->Code < bound)
+ {
+ rd->Range = bound;
+ *prob += (kBitModelTotal - *prob) >> kNumMoveBits;
+ if (rd->Range < kTopValue)
+ {
+ rd->Code = (rd->Code << 8) | ReadByte;
+ rd->Range <<= 8;
+ }
+ return 0;
+ }
+ else
+ {
+ rd->Range -= bound;
+ rd->Code -= bound;
+ *prob -= (*prob) >> kNumMoveBits;
+ if (rd->Range < kTopValue)
+ {
+ rd->Code = (rd->Code << 8) | ReadByte;
+ rd->Range <<= 8;
+ }
+ return 1;
+ }
+}
+
+#define RC_GET_BIT2(prob, mi, A0, A1) \
+ UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \
+ if (code < bound) \
+ { A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \
+ else \
+ { A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \
+ RC_NORMALIZE
+
+#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;)
+
+int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
+{
+ int mi = 1;
+ int i;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ for(i = numLevels; i > 0; i--)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + mi;
+ RC_GET_BIT(prob, mi)
+ #else
+ mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd);
+ #endif
+ }
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return mi - (1 << numLevels);
+}
+
+int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
+{
+ int mi = 1;
+ int i;
+ int symbol = 0;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ for(i = 0; i < numLevels; i++)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + mi;
+ RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i))
+ #else
+ int bit = RangeDecoderBitDecode(probs + mi, rd);
+ mi = mi + mi + bit;
+ symbol |= (bit << i);
+ #endif
+ }
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd)
+{
+ int symbol = 1;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ do
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + symbol;
+ RC_GET_BIT(prob, symbol)
+ #else
+ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
+ #endif
+ }
+ while (symbol < 0x100);
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte)
+{
+ int symbol = 1;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ do
+ {
+ int bit;
+ int matchBit = (matchByte >> 7) & 1;
+ matchByte <<= 1;
+ #ifdef _LZMA_LOC_OPT
+ {
+ CProb *prob = probs + ((1 + matchBit) << 8) + symbol;
+ RC_GET_BIT2(prob, symbol, bit = 0, bit = 1)
+ }
+ #else
+ bit = RangeDecoderBitDecode(probs + ((1 + matchBit) << 8) + symbol, rd);
+ symbol = (symbol << 1) | bit;
+ #endif
+ if (matchBit != bit)
+ {
+ while (symbol < 0x100)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + symbol;
+ RC_GET_BIT(prob, symbol)
+ #else
+ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
+ #endif
+ }
+ break;
+ }
+ }
+ while (symbol < 0x100);
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState)
+{
+ if(RangeDecoderBitDecode(p + LenChoice, rd) == 0)
+ return RangeDecoderBitTreeDecode(p + LenLow +
+ (posState << kLenNumLowBits), kLenNumLowBits, rd);
+ if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0)
+ return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid +
+ (posState << kLenNumMidBits), kLenNumMidBits, rd);
+ return kLenNumLowSymbols + kLenNumMidSymbols +
+ RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd);
+}
+
+#define kNumStates 12
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+#ifdef _LZMA_OUT_READ
+
+typedef struct _LzmaVarState
+{
+ CRangeDecoder RangeDecoder;
+ Byte *Dictionary;
+ UInt32 DictionarySize;
+ UInt32 DictionaryPos;
+ UInt32 GlobalPos;
+ UInt32 Reps[4];
+ int lc;
+ int lp;
+ int pb;
+ int State;
+ int PreviousIsMatch;
+ int RemainLen;
+} LzmaVarState;
+
+int LzmaDecoderInit(
+ unsigned char *buffer, UInt32 bufferSize,
+ int lc, int lp, int pb,
+ unsigned char *dictionary, UInt32 dictionarySize,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback
+ #else
+ unsigned char *inStream, UInt32 inSize
+ #endif
+ )
+{
+ LzmaVarState *vs = (LzmaVarState *)buffer;
+ CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
+ UInt32 i;
+ if (bufferSize < numProbs * sizeof(CProb) + sizeof(LzmaVarState))
+ return LZMA_RESULT_NOT_ENOUGH_MEM;
+ vs->Dictionary = dictionary;
+ vs->DictionarySize = dictionarySize;
+ vs->DictionaryPos = 0;
+ vs->GlobalPos = 0;
+ vs->Reps[0] = vs->Reps[1] = vs->Reps[2] = vs->Reps[3] = 1;
+ vs->lc = lc;
+ vs->lp = lp;
+ vs->pb = pb;
+ vs->State = 0;
+ vs->PreviousIsMatch = 0;
+ vs->RemainLen = 0;
+ dictionary[dictionarySize - 1] = 0;
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ RangeDecoderInit(&vs->RangeDecoder,
+ #ifdef _LZMA_IN_CB
+ inCallback
+ #else
+ inStream, inSize
+ #endif
+ );
+ return LZMA_RESULT_OK;
+}
+
+int LzmaDecode(unsigned char *buffer,
+ unsigned char *outStream, UInt32 outSize,
+ UInt32 *outSizeProcessed)
+{
+ LzmaVarState *vs = (LzmaVarState *)buffer;
+ CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
+ CRangeDecoder rd = vs->RangeDecoder;
+ int state = vs->State;
+ int previousIsMatch = vs->PreviousIsMatch;
+ Byte previousByte;
+ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+ UInt32 nowPos = 0;
+ UInt32 posStateMask = (1 << (vs->pb)) - 1;
+ UInt32 literalPosMask = (1 << (vs->lp)) - 1;
+ int lc = vs->lc;
+ int len = vs->RemainLen;
+ UInt32 globalPos = vs->GlobalPos;
+
+ Byte *dictionary = vs->Dictionary;
+ UInt32 dictionarySize = vs->DictionarySize;
+ UInt32 dictionaryPos = vs->DictionaryPos;
+
+ if (len == -1)
+ {
+ *outSizeProcessed = 0;
+ return LZMA_RESULT_OK;
+ }
+
+ while(len > 0 && nowPos < outSize)
+ {
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ len--;
+ }
+ if (dictionaryPos == 0)
+ previousByte = dictionary[dictionarySize - 1];
+ else
+ previousByte = dictionary[dictionaryPos - 1];
+#else
+
+int LzmaDecode(
+ Byte *buffer, UInt32 bufferSize,
+ int lc, int lp, int pb,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback,
+ #else
+ unsigned char *inStream, UInt32 inSize,
+ #endif
+ unsigned char *outStream, UInt32 outSize,
+ UInt32 *outSizeProcessed)
+{
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
+ CProb *p = (CProb *)buffer;
+ CRangeDecoder rd;
+ UInt32 i;
+ int state = 0;
+ int previousIsMatch = 0;
+ Byte previousByte = 0;
+ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+ UInt32 nowPos = 0;
+ UInt32 posStateMask = (1 << pb) - 1;
+ UInt32 literalPosMask = (1 << lp) - 1;
+ int len = 0;
+ if (bufferSize < numProbs * sizeof(CProb))
+ return LZMA_RESULT_NOT_ENOUGH_MEM;
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ RangeDecoderInit(&rd,
+ #ifdef _LZMA_IN_CB
+ inCallback
+ #else
+ inStream, inSize
+ #endif
+ );
+#endif
+
+ *outSizeProcessed = 0;
+ while(nowPos < outSize)
+ {
+ int posState = (int)(
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & posStateMask);
+ #ifdef _LZMA_IN_CB
+ if (rd.Result != LZMA_RESULT_OK)
+ return rd.Result;
+ #endif
+ if (rd.ExtraBytes != 0)
+ return LZMA_RESULT_DATA_ERROR;
+ if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0)
+ {
+ CProb *probs = p + Literal + (LZMA_LIT_SIZE *
+ (((
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+ if (state < 4) state = 0;
+ else if (state < 10) state -= 3;
+ else state -= 6;
+ if (previousIsMatch)
+ {
+ Byte matchByte;
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ matchByte = dictionary[pos];
+ #else
+ matchByte = outStream[nowPos - rep0];
+ #endif
+ previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte);
+ previousIsMatch = 0;
+ }
+ else
+ previousByte = LzmaLiteralDecode(probs, &rd);
+ outStream[nowPos++] = previousByte;
+ #ifdef _LZMA_OUT_READ
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #endif
+ }
+ else
+ {
+ previousIsMatch = 1;
+ if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1)
+ {
+ if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0)
+ {
+ if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0)
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos;
+ #endif
+ if (
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ == 0)
+ return LZMA_RESULT_DATA_ERROR;
+ state = state < 7 ? 9 : 11;
+ #ifdef _LZMA_OUT_READ
+ pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ outStream[nowPos++] = previousByte;
+ continue;
+ }
+ }
+ else
+ {
+ UInt32 distance;
+ if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0)
+ distance = rep1;
+ else
+ {
+ if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0)
+ distance = rep2;
+ else
+ {
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ len = LzmaLenDecode(p + RepLenCoder, &rd, posState);
+ state = state < 7 ? 8 : 11;
+ }
+ else
+ {
+ int posSlot;
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ state = state < 7 ? 7 : 10;
+ len = LzmaLenDecode(p + LenCoder, &rd, posState);
+ posSlot = RangeDecoderBitTreeDecode(p + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits), kNumPosSlotBits, &rd);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+ rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits);
+ if (posSlot < kEndPosModelIndex)
+ {
+ rep0 += RangeDecoderReverseBitTreeDecode(
+ p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd);
+ }
+ else
+ {
+ rep0 += RangeDecoderDecodeDirectBits(&rd,
+ numDirectBits - kNumAlignBits) << kNumAlignBits;
+ rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd);
+ }
+ }
+ else
+ rep0 = posSlot;
+ rep0++;
+ }
+ if (rep0 == (UInt32)(0))
+ {
+ /* it's for stream version */
+ len = -1;
+ break;
+ }
+ if (rep0 > nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ {
+ return LZMA_RESULT_DATA_ERROR;
+ }
+ len += kMatchMinLen;
+ do
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ outStream[nowPos++] = previousByte;
+ len--;
+ }
+ while(len > 0 && nowPos < outSize);
+ }
+ }
+
+ #ifdef _LZMA_OUT_READ
+ vs->RangeDecoder = rd;
+ vs->DictionaryPos = dictionaryPos;
+ vs->GlobalPos = globalPos + nowPos;
+ vs->Reps[0] = rep0;
+ vs->Reps[1] = rep1;
+ vs->Reps[2] = rep2;
+ vs->Reps[3] = rep3;
+ vs->State = state;
+ vs->PreviousIsMatch = previousIsMatch;
+ vs->RemainLen = len;
+ #endif
+
+ *outSizeProcessed = nowPos;
+ return LZMA_RESULT_OK;
+}
diff --git a/target/image/brcm/lzma-loader/src/LzmaDecode.h b/target/image/brcm/lzma-loader/src/LzmaDecode.h
new file mode 100644
index 0000000..f58944e
--- /dev/null
+++ b/target/image/brcm/lzma-loader/src/LzmaDecode.h
@@ -0,0 +1,100 @@
+/*
+ LzmaDecode.h
+ LZMA Decoder interface
+
+ LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs,
+ but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+#ifndef UInt32
+#ifdef _LZMA_UINT32_IS_ULONG
+#define UInt32 unsigned long
+#else
+#define UInt32 unsigned int
+#endif
+#endif
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb unsigned short
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+#define LZMA_RESULT_NOT_ENOUGH_MEM 2
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+ int (*Read)(void *object, unsigned char **buffer, UInt32 *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+/*
+bufferSize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb)
+bufferSize += 100 in case of _LZMA_OUT_READ
+by default CProb is unsigned short,
+but if specify _LZMA_PROB_32, CProb will be UInt32(unsigned int)
+*/
+
+#ifdef _LZMA_OUT_READ
+int LzmaDecoderInit(
+ unsigned char *buffer, UInt32 bufferSize,
+ int lc, int lp, int pb,
+ unsigned char *dictionary, UInt32 dictionarySize,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback
+ #else
+ unsigned char *inStream, UInt32 inSize
+ #endif
+);
+#endif
+
+int LzmaDecode(
+ unsigned char *buffer,
+ #ifndef _LZMA_OUT_READ
+ UInt32 bufferSize,
+ int lc, int lp, int pb,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback,
+ #else
+ unsigned char *inStream, UInt32 inSize,
+ #endif
+ #endif
+ unsigned char *outStream, UInt32 outSize,
+ UInt32 *outSizeProcessed);
+
+#endif
diff --git a/target/image/brcm/lzma-loader/src/Makefile b/target/image/brcm/lzma-loader/src/Makefile
new file mode 100644
index 0000000..85a8646
--- /dev/null
+++ b/target/image/brcm/lzma-loader/src/Makefile
@@ -0,0 +1,77 @@
+#
+# Makefile for Broadcom BCM947XX boards
+#
+# Copyright 2001-2003, Broadcom Corporation
+# All Rights Reserved.
+#
+# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+#
+# Copyright 2004 Manuel Novoa III <mjn3@codepoet.org>
+# Modified to support bzip'd kernels.
+# Of course, it would be better to integrate bunzip capability into CFE.
+#
+# Copyright 2005 Oleg I. Vdovikin <oleg@cs.msu.su>
+# Cleaned up, modified for lzma support, removed from kernel
+#
+
+TEXT_START := 0x80001000
+BZ_TEXT_START := 0x80300000
+
+OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .reginfo -R .note -R .comment -R .mdebug -S
+
+CFLAGS = -D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -Os \
+ -fno-strict-aliasing -fno-common -fomit-frame-pointer -G 0 -mno-abicalls -fno-pic \
+ -ffunction-sections -pipe -mlong-calls -fno-common \
+ -mabi=32 -march=mips32 -Wa,-32 -Wa,-march=mips32 -Wa,-mips32 -Wa,--trap
+CFLAGS += -DLOADADDR=$(TEXT_START) -D_LZMA_IN_CB
+
+ASFLAGS = $(CFLAGS) -D__ASSEMBLY__ -DBZ_TEXT_START=$(BZ_TEXT_START)
+
+SEDFLAGS := s/BZ_TEXT_START/$(BZ_TEXT_START)/;s/TEXT_START/$(TEXT_START)/
+
+OBJECTS := head.o data.o
+
+all: loader.gz loader.elf
+
+# Don't build dependencies, this may die if $(CC) isn't gcc
+dep:
+
+install:
+
+loader.gz: loader
+ gzip -nc9 $< > $@
+
+loader.elf: loader.o
+ cp $< $@
+
+loader: loader.o
+ $(OBJCOPY) $< $@
+
+loader.o: loader.lds $(OBJECTS)
+ $(LD) -static --gc-sections -no-warn-mismatch -T loader.lds -o $@ $(OBJECTS)
+
+loader.lds: loader.lds.in Makefile
+ @sed "$(SEDFLAGS)" < $< > $@
+
+data.o: data.lds decompress.image
+ $(LD) -no-warn-mismatch -T data.lds -r -o $@ -b binary decompress.image -b elf32-tradlittlemips
+
+data.lds:
+ @echo "SECTIONS { .data : { code_start = .; *(.data) code_stop = .; }}" > $@
+
+decompress.image: decompress
+ $(OBJCOPY) $< $@
+
+decompress: decompress.lds decompress.o LzmaDecode.o
+ $(LD) -static --gc-sections -no-warn-mismatch -T decompress.lds -o $@ decompress.o LzmaDecode.o
+
+decompress.lds: decompress.lds.in Makefile
+ @sed "$(SEDFLAGS)" < $< > $@
+
+mrproper: clean
+
+clean:
+ rm -f loader.gz loader decompress *.lds *.o *.image
diff --git a/target/image/brcm/lzma-loader/src/README b/target/image/brcm/lzma-loader/src/README
new file mode 100644
index 0000000..16649e9
--- /dev/null
+++ b/target/image/brcm/lzma-loader/src/README
@@ -0,0 +1,55 @@
+/*
+ * LZMA compressed kernel decompressor for bcm947xx boards
+ *
+ * Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
+ *
+ * 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
+ *
+ */
+
+The code is intended to decompress kernel, being compressed using lzma utility
+build using 7zip LZMA SDK. This utility is located in the LZMA_Alone directory
+
+decompressor code expects that your .trx file consist of three partitions:
+
+1) decompressor itself (this is gziped code which pmon/cfe will extract and run
+on boot-up instead of real kernel)
+2) LZMA compressed kernel (both streamed and regular modes are supported now)
+3) Root filesystem
+
+Please be sure to apply the following patch for use this new trx layout (it will
+allow using both new and old trx files for root filesystem lookup code)
+
+--- linuz/arch/mips/brcm-boards/bcm947xx/setup.c 2005-01-23 19:24:27.503322896 +0300
++++ linux/arch/mips/brcm-boards/bcm947xx/setup.c 2005-01-23 19:29:05.237100944 +0300
+@@ -221,7 +221,9 @@
+ /* Try looking at TRX header for rootfs offset */
+ if (le32_to_cpu(trx->magic) == TRX_MAGIC) {
+ bcm947xx_parts[1].offset = off;
+- if (le32_to_cpu(trx->offsets[1]) > off)
++ if (le32_to_cpu(trx->offsets[2]) > off)
++ off = le32_to_cpu(trx->offsets[2]);
++ else if (le32_to_cpu(trx->offsets[1]) > off)
+ off = le32_to_cpu(trx->offsets[1]);
+ continue;
+ }
+
+
+Revision history:
+ 0.02 Initial release
+ 0.03 Added Mineharu Takahara <mtakahar@yahoo.com> patch to pass actual
+ output size to decoder (stream mode compressed input is not
+ a requirement anymore)
+ 0.04 Reordered functions using lds script
diff --git a/target/image/brcm/lzma-loader/src/decompress.c b/target/image/brcm/lzma-loader/src/decompress.c
new file mode 100644
index 0000000..ec510e2
--- /dev/null
+++ b/target/image/brcm/lzma-loader/src/decompress.c
@@ -0,0 +1,175 @@
+/*
+ * LZMA compressed kernel decompressor for bcm947xx boards
+ *
+ * Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
+ *
+ * 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
+ *
+ *
+ * Please note, this was code based on the bunzip2 decompressor code
+ * by Manuel Novoa III (mjn3@codepoet.org), although the only thing left
+ * is an idea and part of original vendor code
+ *
+ *
+ * 12-Mar-2005 Mineharu Takahara <mtakahar@yahoo.com>
+ * pass actual output size to decoder (stream mode
+ * compressed input is not a requirement anymore)
+ *
+ * 24-Apr-2005 Oleg I. Vdovikin
+ * reordered functions using lds script, removed forward decl
+ *
+ */
+
+#include "LzmaDecode.h"
+
+#define BCM4710_FLASH 0x1fc00000 /* Flash */
+
+#define KSEG0 0x80000000
+#define KSEG1 0xa0000000
+
+#define KSEG1ADDR(a) ((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
+
+#define Index_Invalidate_I 0x00
+#define Index_Writeback_Inv_D 0x01
+
+#define cache_unroll(base,op) \
+ __asm__ __volatile__( \
+ ".set noreorder;\n" \
+ ".set mips3;\n" \
+ "cache %1, (%0);\n" \
+ ".set mips0;\n" \
+ ".set reorder\n" \
+ : \
+ : "r" (base), \
+ "i" (op));
+
+static __inline__ void blast_icache(unsigned long size, unsigned long lsize)
+{
+ unsigned long start = KSEG0;
+ unsigned long end = (start + size);
+
+ while(start < end) {
+ cache_unroll(start,Index_Invalidate_I);
+ start += lsize;
+ }
+}
+
+static __inline__ void blast_dcache(unsigned long size, unsigned long lsize)
+{
+ unsigned long start = KSEG0;
+ unsigned long end = (start + size);
+
+ while(start < end) {
+ cache_unroll(start,Index_Writeback_Inv_D);
+ start += lsize;
+ }
+}
+
+#define TRX_MAGIC 0x30524448 /* "HDR0" */
+
+struct trx_header {
+ unsigned int magic; /* "HDR0" */
+ unsigned int len; /* Length of file including header */
+ unsigned int crc32; /* 32-bit CRC from flag_version to end of file */
+ unsigned int flag_version; /* 0:15 flags, 16:31 version */
+ unsigned int offsets[3]; /* Offsets of partitions from start of header */
+};
+
+/* beyound the image end, size not known in advance */
+extern unsigned char workspace[];
+
+unsigned int offset;
+unsigned char *data;
+
+/* flash access should be aligned, so wrapper is used */
+/* read byte from the flash, all accesses are 32-bit aligned */
+static int read_byte(void *object, unsigned char **buffer, UInt32 *bufferSize)
+{
+ static unsigned int val;
+
+ if (((unsigned int)offset % 4) == 0) {
+ val = *(unsigned int *)data;
+ data += 4;
+ }
+
+ *bufferSize = 1;
+ *buffer = ((unsigned char *)&val) + (offset++ & 3);
+
+ return LZMA_RESULT_OK;
+}
+
+static __inline__ unsigned char get_byte(void)
+{
+ unsigned char *buffer;
+ UInt32 fake;
+
+ return read_byte(0, &buffer, &fake), *buffer;
+}
+
+/* should be the first function */
+void entry(unsigned long icache_size, unsigned long icache_lsize,
+ unsigned long dcache_size, unsigned long dcache_lsize)
+{
+ unsigned int i; /* temp value */
+ unsigned int lc; /* literal context bits */
+ unsigned int lp; /* literal pos state bits */
+ unsigned int pb; /* pos state bits */
+ unsigned int osize; /* uncompressed size */
+
+ ILzmaInCallback callback;
+ callback.Read = read_byte;
+
+ /* look for trx header, 32-bit data access */
+ for (data = ((unsigned char *) KSEG1ADDR(BCM4710_FLASH));
+ ((struct trx_header *)data)->magic != TRX_MAGIC; data += 65536);
+
+ /* compressed kernel is in the partition 0 or 1 */
+ if (((struct trx_header *)data)->offsets[1] > 65536)
+ data += ((struct trx_header *)data)->offsets[0];
+ else
+ data += ((struct trx_header *)data)->offsets[1];
+
+ offset = 0;
+
+ /* lzma args */
+ i = get_byte();
+ lc = i % 9, i = i / 9;
+ lp = i % 5, pb = i / 5;
+
+ /* skip rest of the LZMA coder property */
+ for (i = 0; i < 4; i++)
+ get_byte();
+
+ /* read the lower half of uncompressed size in the header */
+ osize = ((unsigned int)get_byte()) +
+ ((unsigned int)get_byte() << 8) +
+ ((unsigned int)get_byte() << 16) +
+ ((unsigned int)get_byte() << 24);
+
+ /* skip rest of the header (upper half of uncompressed size) */
+ for (i = 0; i < 4; i++)
+ get_byte();
+
+ /* decompress kernel */
+ if (LzmaDecode(workspace, ~0, lc, lp, pb, &callback,
+ (unsigned char*)LOADADDR, osize, &i) == LZMA_RESULT_OK)
+ {
+ blast_dcache(dcache_size, dcache_lsize);
+ blast_icache(icache_size, icache_lsize);
+
+ /* Jump to load address */
+ ((void (*)(void)) LOADADDR)();
+ }
+}
diff --git a/target/image/brcm/lzma-loader/src/decompress.lds.in b/target/image/brcm/lzma-loader/src/decompress.lds.in
new file mode 100644
index 0000000..33f56f8
--- /dev/null
+++ b/target/image/brcm/lzma-loader/src/decompress.lds.in
@@ -0,0 +1,20 @@
+OUTPUT_ARCH(mips)
+ENTRY(entry)
+SECTIONS {
+ . = BZ_TEXT_START;
+ .text : {
+ *(.text.entry)
+ *(.text)
+ *(.rodata)
+ }
+
+ .data : {
+ *(.data)
+ }
+
+ .bss : {
+ *(.bss)
+ }
+
+ workspace = .;
+}
diff --git a/target/image/brcm/lzma-loader/src/head.S b/target/image/brcm/lzma-loader/src/head.S
new file mode 100644
index 0000000..9bfbd53
--- /dev/null
+++ b/target/image/brcm/lzma-loader/src/head.S
@@ -0,0 +1,155 @@
+/* Copyright 2005 Oleg I. Vdovikin (oleg@cs.msu.su) */
+/* cache manipulation adapted from Broadcom code */
+/* idea taken from original bunzip2 decompressor code */
+/* Copyright 2004 Manuel Novoa III (mjn3@codepoet.org) */
+/* Licensed under the linux kernel's version of the GPL.*/
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+#define KSEG0 0x80000000
+
+#define C0_CONFIG $16
+#define C0_TAGLO $28
+#define C0_TAGHI $29
+
+#define CONF1_DA_SHIFT 7 /* D$ associativity */
+#define CONF1_DA_MASK 0x00000380
+#define CONF1_DA_BASE 1
+#define CONF1_DL_SHIFT 10 /* D$ line size */
+#define CONF1_DL_MASK 0x00001c00
+#define CONF1_DL_BASE 2
+#define CONF1_DS_SHIFT 13 /* D$ sets/way */
+#define CONF1_DS_MASK 0x0000e000
+#define CONF1_DS_BASE 64
+#define CONF1_IA_SHIFT 16 /* I$ associativity */
+#define CONF1_IA_MASK 0x00070000
+#define CONF1_IA_BASE 1
+#define CONF1_IL_SHIFT 19 /* I$ line size */
+#define CONF1_IL_MASK 0x00380000
+#define CONF1_IL_BASE 2
+#define CONF1_IS_SHIFT 22 /* Instruction cache sets/way */
+#define CONF1_IS_MASK 0x01c00000
+#define CONF1_IS_BASE 64
+
+#define Index_Invalidate_I 0x00
+#define Index_Writeback_Inv_D 0x01
+
+ .text
+ LEAF(startup)
+ .set noreorder
+
+ /* Copy decompressor code to the right place */
+ li t2, BZ_TEXT_START
+ add a0, t2, 0
+ la a1, code_start
+ la a2, code_stop
+$L1:
+ lw t0, 0(a1)
+ sw t0, 0(a0)
+ add a1, 4
+ add a0, 4
+ blt a1, a2, $L1
+ nop
+
+ /* At this point we need to invalidate dcache and */
+ /* icache before jumping to new code */
+
+1: /* Get cache sizes */
+ .set mips32
+ mfc0 s0,C0_CONFIG,1
+ .set mips0
+
+ li s1,CONF1_DL_MASK
+ and s1,s0
+ beq s1,zero,nodc
+ nop
+
+ srl s1,CONF1_DL_SHIFT
+ li t0,CONF1_DL_BASE
+ sll s1,t0,s1 /* s1 has D$ cache line size */
+
+ li s2,CONF1_DA_MASK
+ and s2,s0
+ srl s2,CONF1_DA_SHIFT
+ addiu s2,CONF1_DA_BASE /* s2 now has D$ associativity */
+
+ li t0,CONF1_DS_MASK
+ and t0,s0
+ srl t0,CONF1_DS_SHIFT
+ li s3,CONF1_DS_BASE
+ sll s3,s3,t0 /* s3 has D$ sets per way */
+
+ multu s2,s3 /* sets/way * associativity */
+ mflo t0 /* total cache lines */
+
+ multu s1,t0 /* D$ linesize * lines */
+ mflo s2 /* s2 is now D$ size in bytes */
+
+ /* Initilize the D$: */
+ mtc0 zero,C0_TAGLO
+ mtc0 zero,C0_TAGHI
+
+ li t0,KSEG0 /* Just an address for the first $ line */
+ addu t1,t0,s2 /* + size of cache == end */
+
+ .set mips3
+1: cache Index_Writeback_Inv_D,0(t0)
+ .set mips0
+ bne t0,t1,1b
+ addu t0,s1
+
+nodc:
+ /* Now we get to do it all again for the I$ */
+
+ move s3,zero /* just in case there is no icache */
+ move s4,zero
+
+ li t0,CONF1_IL_MASK
+ and t0,s0
+ beq t0,zero,noic
+ nop
+
+ srl t0,CONF1_IL_SHIFT
+ li s3,CONF1_IL_BASE
+ sll s3,t0 /* s3 has I$ cache line size */
+
+ li t0,CONF1_IA_MASK
+ and t0,s0
+ srl t0,CONF1_IA_SHIFT
+ addiu s4,t0,CONF1_IA_BASE /* s4 now has I$ associativity */
+
+ li t0,CONF1_IS_MASK
+ and t0,s0
+ srl t0,CONF1_IS_SHIFT
+ li s5,CONF1_IS_BASE
+ sll s5,t0 /* s5 has I$ sets per way */
+
+ multu s4,s5 /* sets/way * associativity */
+ mflo t0 /* s4 is now total cache lines */
+
+ multu s3,t0 /* I$ linesize * lines */
+ mflo s4 /* s4 is cache size in bytes */
+
+ /* Initilize the I$: */
+ mtc0 zero,C0_TAGLO
+ mtc0 zero,C0_TAGHI
+
+ li t0,KSEG0 /* Just an address for the first $ line */
+ addu t1,t0,s4 /* + size of cache == end */
+
+ .set mips3
+1: cache Index_Invalidate_I,0(t0)
+ .set mips0
+ bne t0,t1,1b
+ addu t0,s3
+
+noic:
+ move a0,s3 /* icache line size */
+ move a1,s4 /* icache size */
+ move a2,s1 /* dcache line size */
+ jal t2
+ move a3,s2 /* dcache size */
+
+ .set reorder
+ END(startup)
diff --git a/target/image/brcm/lzma-loader/src/loader.lds.in b/target/image/brcm/lzma-loader/src/loader.lds.in
new file mode 100644
index 0000000..20f2ea9
--- /dev/null
+++ b/target/image/brcm/lzma-loader/src/loader.lds.in
@@ -0,0 +1,17 @@
+OUTPUT_ARCH(mips)
+ENTRY(startup)
+SECTIONS {
+ . = TEXT_START;
+ .text : {
+ *(.text)
+ *(.rodata)
+ }
+
+ .data : {
+ *(.data)
+ }
+
+ .bss : {
+ *(.bss)
+ }
+}
diff --git a/target/image/brcm63xx/Makefile b/target/image/brcm63xx/Makefile
new file mode 100644
index 0000000..6aa72c2
--- /dev/null
+++ b/target/image/brcm63xx/Makefile
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+LOADADDR = 0x8108c8f4 # RAM start + 16M
+KERNEL_ENTRY = 0x80100000 # Default kernel entry in arch/mips/Makefile
+RAMSIZE = 0x01000000 # 64MB
+
+LOADER_MAKEOPTS= \
+ KDIR=$(KDIR) \
+ LOADADDR=$(LOADADDR) \
+ KERNEL_ENTRY=$(KERNEL_ENTRY) \
+ RAMSIZE=$(RAMSIZE)
+
+define Build/Clean
+ $(MAKE) -C ../generic/lzma-loader $(LOADER_MAKEOPTS) clean
+endef
+
+define Image/Prepare
+ cat $(KDIR)/vmlinux | $(STAGING_DIR)/bin/lzma e -si -so -eos -lc1 -lp2 -pb2 > $(KDIR)/vmlinux.lzma
+ $(MAKE) -C ../generic/lzma-loader $(LOADER_MAKEOPTS) compile
+endef
+
+define Image/Build
+ cp $(KDIR)/vmlinux $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).img
+endef
+
+$(eval $(call BuildImage))
diff --git a/target/image/generic/Makefile b/target/image/generic/Makefile
new file mode 100644
index 0000000..64b294d
--- /dev/null
+++ b/target/image/generic/Makefile
@@ -0,0 +1,12 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+# use default targets for everything
+
+$(eval $(call BuildImage))
diff --git a/target/image/generic/lzma-loader/Makefile b/target/image/generic/lzma-loader/Makefile
new file mode 100644
index 0000000..5bd01ee
--- /dev/null
+++ b/target/image/generic/lzma-loader/Makefile
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+# $Id: Makefile 1823 2005-09-01 20:07:42Z nbd $
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME := loader
+PKG_VERSION := 0.05
+
+PKG_BUILD_DIR := $(KDIR)/$(PKG_NAME)-$(PKG_VERSION)
+
+$(PKG_BUILD_DIR)/.prepared:
+ mkdir $(PKG_BUILD_DIR)
+ $(CP) ./src/* $(PKG_BUILD_DIR)/
+ touch $@
+
+$(PKG_BUILD_DIR)/lzma.elf: $(PKG_BUILD_DIR)/.prepared $(PKG_BUILD_DIR)/vmlinux.lzma
+ PATH="$(TARGET_PATH)" $(MAKE) -C $(PKG_BUILD_DIR) \
+ CC="$(TARGET_CC)" CROSS_COMPILE="$(TARGET_CROSS)" \
+ RAMSIZE=$(RAMSIZE) \
+ LOADADDR=$(LOADADDR) \
+ KERNEL_ENTRY=$(KERNEL_ENTRY) \
+ IMAGE_COPY=$(IMAGE_COPY)
+
+
+$(PKG_BUILD_DIR)/vmlinux.lzma: $(KDIR)/vmlinux.lzma
+ $(CP) $< $@
+
+$(KDIR)/loader.elf: $(PKG_BUILD_DIR)/lzma.elf
+ $(CP) $< $@
+
+download:
+prepare: $(PKG_BUILD_DIR)/.prepared
+compile: $(KDIR)/loader.elf
+install:
+
+clean:
+ rm -rf $(PKG_BUILD_DIR)
+ rm -f $(KDIR)/loader.elf
diff --git a/target/image/generic/lzma-loader/src/LzmaDecode.c b/target/image/generic/lzma-loader/src/LzmaDecode.c
new file mode 100644
index 0000000..c90a0d3
--- /dev/null
+++ b/target/image/generic/lzma-loader/src/LzmaDecode.c
@@ -0,0 +1,590 @@
+/*
+ LzmaDecode.c
+ LZMA Decoder (optimized for Speed version)
+
+ LZMA SDK 4.22 Copyright (c) 1999-2005 Igor Pavlov (2005-06-10)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this Code, expressly permits you to
+ statically or dynamically link your Code (or bind by name) to the
+ interfaces of this file without subjecting your linked Code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#ifndef Byte
+#define Byte unsigned char
+#endif
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+ { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+#ifdef _LZMA_IN_CB
+
+#define RC_TEST { if (Buffer == BufferLim) \
+ { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \
+ BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }}
+
+#define RC_INIT Buffer = BufferLim = 0; RC_INIT2
+
+#else
+
+#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+
+#endif
+
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+ { UpdateBit0(p); mi <<= 1; A0; } else \
+ { UpdateBit1(p); mi = (mi + mi) + 1; A1; }
+
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+ { int i = numLevels; res = 1; \
+ do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
+ res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+#if 0
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+ unsigned char prop0;
+ if (size < LZMA_PROPERTIES_SIZE)
+ return LZMA_RESULT_DATA_ERROR;
+ prop0 = propsData[0];
+ if (prop0 >= (9 * 5 * 5))
+ return LZMA_RESULT_DATA_ERROR;
+ {
+ for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+ for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+ propsRes->lc = prop0;
+ /*
+ unsigned char remainder = (unsigned char)(prop0 / 9);
+ propsRes->lc = prop0 % 9;
+ propsRes->pb = remainder / 5;
+ propsRes->lp = remainder % 5;
+ */
+ }
+
+ #ifdef _LZMA_OUT_READ
+ {
+ int i;
+ propsRes->DictionarySize = 0;
+ for (i = 0; i < 4; i++)
+ propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+ if (propsRes->DictionarySize == 0)
+ propsRes->DictionarySize = 1;
+ }
+ #endif
+ return LZMA_RESULT_OK;
+}
+#endif
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *InCallback,
+ #else
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ #endif
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+ CProb *p = vs->Probs;
+ SizeT nowPos = 0;
+ Byte previousByte = 0;
+ UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+ UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+ int lc = vs->Properties.lc;
+
+ #ifdef _LZMA_OUT_READ
+
+ UInt32 Range = vs->Range;
+ UInt32 Code = vs->Code;
+ #ifdef _LZMA_IN_CB
+ const Byte *Buffer = vs->Buffer;
+ const Byte *BufferLim = vs->BufferLim;
+ #else
+ const Byte *Buffer = inStream;
+ const Byte *BufferLim = inStream + inSize;
+ #endif
+ int state = vs->State;
+ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+ int len = vs->RemainLen;
+ UInt32 globalPos = vs->GlobalPos;
+ UInt32 distanceLimit = vs->DistanceLimit;
+
+ Byte *dictionary = vs->Dictionary;
+ UInt32 dictionarySize = vs->Properties.DictionarySize;
+ UInt32 dictionaryPos = vs->DictionaryPos;
+
+ Byte tempDictionary[4];
+
+ #ifndef _LZMA_IN_CB
+ *inSizeProcessed = 0;
+ #endif
+ *outSizeProcessed = 0;
+ if (len == kLzmaStreamWasFinishedId)
+ return LZMA_RESULT_OK;
+
+ if (dictionarySize == 0)
+ {
+ dictionary = tempDictionary;
+ dictionarySize = 1;
+ tempDictionary[0] = vs->TempDictionary[0];
+ }
+
+ if (len == kLzmaNeedInitId)
+ {
+ {
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+ UInt32 i;
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ rep0 = rep1 = rep2 = rep3 = 1;
+ state = 0;
+ globalPos = 0;
+ distanceLimit = 0;
+ dictionaryPos = 0;
+ dictionary[dictionarySize - 1] = 0;
+ #ifdef _LZMA_IN_CB
+ RC_INIT;
+ #else
+ RC_INIT(inStream, inSize);
+ #endif
+ }
+ len = 0;
+ }
+ while(len != 0 && nowPos < outSize)
+ {
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ len--;
+ }
+ if (dictionaryPos == 0)
+ previousByte = dictionary[dictionarySize - 1];
+ else
+ previousByte = dictionary[dictionaryPos - 1];
+
+ #else /* if !_LZMA_OUT_READ */
+
+ int state = 0;
+ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+ int len = 0;
+ const Byte *Buffer;
+ const Byte *BufferLim;
+ UInt32 Range;
+ UInt32 Code;
+
+ #ifndef _LZMA_IN_CB
+ *inSizeProcessed = 0;
+ #endif
+ *outSizeProcessed = 0;
+
+ {
+ UInt32 i;
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ }
+
+ #ifdef _LZMA_IN_CB
+ RC_INIT;
+ #else
+ RC_INIT(inStream, inSize);
+ #endif
+
+ #endif /* _LZMA_OUT_READ */
+
+ while(nowPos < outSize)
+ {
+ CProb *prob;
+ UInt32 bound;
+ int posState = (int)(
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & posStateMask);
+
+ prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+ IfBit0(prob)
+ {
+ int symbol = 1;
+ UpdateBit0(prob)
+ prob = p + Literal + (LZMA_LIT_SIZE *
+ (((
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+ if (state >= kNumLitStates)
+ {
+ int matchByte;
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ matchByte = dictionary[pos];
+ #else
+ matchByte = outStream[nowPos - rep0];
+ #endif
+ do
+ {
+ int bit;
+ CProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & 0x100);
+ probLit = prob + 0x100 + bit + symbol;
+ RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+ }
+ while (symbol < 0x100);
+ }
+ while (symbol < 0x100)
+ {
+ CProb *probLit = prob + symbol;
+ RC_GET_BIT(probLit, symbol)
+ }
+ previousByte = (Byte)symbol;
+
+ outStream[nowPos++] = previousByte;
+ #ifdef _LZMA_OUT_READ
+ if (distanceLimit < dictionarySize)
+ distanceLimit++;
+
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #endif
+ if (state < 4) state = 0;
+ else if (state < 10) state -= 3;
+ else state -= 6;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRep + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ state = state < kNumLitStates ? 0 : 3;
+ prob = p + LenCoder;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRepG0 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IfBit0(prob)
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos;
+ #endif
+ UpdateBit0(prob);
+
+ #ifdef _LZMA_OUT_READ
+ if (distanceLimit == 0)
+ #else
+ if (nowPos == 0)
+ #endif
+ return LZMA_RESULT_DATA_ERROR;
+
+ state = state < kNumLitStates ? 9 : 11;
+ #ifdef _LZMA_OUT_READ
+ pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ outStream[nowPos++] = previousByte;
+ #ifdef _LZMA_OUT_READ
+ if (distanceLimit < dictionarySize)
+ distanceLimit++;
+ #endif
+
+ continue;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ }
+ }
+ else
+ {
+ UInt32 distance;
+ UpdateBit1(prob);
+ prob = p + IsRepG1 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRepG2 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = p + RepLenCoder;
+ }
+ {
+ int numBits, offset;
+ CProb *probLen = prob + LenChoice;
+ IfBit0(probLen)
+ {
+ UpdateBit0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ numBits = kLenNumLowBits;
+ }
+ else
+ {
+ UpdateBit1(probLen);
+ probLen = prob + LenChoice2;
+ IfBit0(probLen)
+ {
+ UpdateBit0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ numBits = kLenNumMidBits;
+ }
+ else
+ {
+ UpdateBit1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ numBits = kLenNumHighBits;
+ }
+ }
+ RangeDecoderBitTreeDecode(probLen, numBits, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ int posSlot;
+ state += kNumLitStates;
+ prob = p + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+ rep0 = (2 | ((UInt32)posSlot & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ rep0 <<= numDirectBits;
+ prob = p + SpecPos + rep0 - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ RC_NORMALIZE
+ Range >>= 1;
+ rep0 <<= 1;
+ if (Code >= Range)
+ {
+ Code -= Range;
+ rep0 |= 1;
+ }
+ }
+ while (--numDirectBits != 0);
+ prob = p + Align;
+ rep0 <<= kNumAlignBits;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ int i = 1;
+ int mi = 1;
+ do
+ {
+ CProb *prob3 = prob + mi;
+ RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+ i <<= 1;
+ }
+ while(--numDirectBits != 0);
+ }
+ }
+ else
+ rep0 = posSlot;
+ if (++rep0 == (UInt32)(0))
+ {
+ /* it's for stream version */
+ len = kLzmaStreamWasFinishedId;
+ break;
+ }
+ }
+
+ len += kMatchMinLen;
+ #ifdef _LZMA_OUT_READ
+ if (rep0 > distanceLimit)
+ #else
+ if (rep0 > nowPos)
+ #endif
+ return LZMA_RESULT_DATA_ERROR;
+
+ #ifdef _LZMA_OUT_READ
+ if (dictionarySize - distanceLimit > (UInt32)len)
+ distanceLimit += len;
+ else
+ distanceLimit = dictionarySize;
+ #endif
+
+ do
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ len--;
+ outStream[nowPos++] = previousByte;
+ }
+ while(len != 0 && nowPos < outSize);
+ }
+ }
+ RC_NORMALIZE;
+
+ #ifdef _LZMA_OUT_READ
+ vs->Range = Range;
+ vs->Code = Code;
+ vs->DictionaryPos = dictionaryPos;
+ vs->GlobalPos = globalPos + (UInt32)nowPos;
+ vs->DistanceLimit = distanceLimit;
+ vs->Reps[0] = rep0;
+ vs->Reps[1] = rep1;
+ vs->Reps[2] = rep2;
+ vs->Reps[3] = rep3;
+ vs->State = state;
+ vs->RemainLen = len;
+ vs->TempDictionary[0] = tempDictionary[0];
+ #endif
+
+ #ifdef _LZMA_IN_CB
+ vs->Buffer = Buffer;
+ vs->BufferLim = BufferLim;
+ #else
+ *inSizeProcessed = (SizeT)(Buffer - inStream);
+ #endif
+ *outSizeProcessed = nowPos;
+ return LZMA_RESULT_OK;
+}
diff --git a/target/image/generic/lzma-loader/src/LzmaDecode.h b/target/image/generic/lzma-loader/src/LzmaDecode.h
new file mode 100644
index 0000000..213062a
--- /dev/null
+++ b/target/image/generic/lzma-loader/src/LzmaDecode.h
@@ -0,0 +1,131 @@
+/*
+ LzmaDecode.h
+ LZMA Decoder interface
+
+ LZMA SDK 4.21 Copyright (c) 1999-2005 Igor Pavlov (2005-06-08)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs,
+ but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+/* #define _LZMA_SYSTEM_SIZE_T */
+/* Use system's size_t. You can use it to enable 64-bit sizes supporting*/
+
+#ifndef UInt32
+#ifdef _LZMA_UINT32_IS_ULONG
+#define UInt32 unsigned long
+#else
+#define UInt32 unsigned int
+#endif
+#endif
+
+#ifndef SizeT
+#ifdef _LZMA_SYSTEM_SIZE_T
+#include <stddef.h>
+#define SizeT size_t
+#else
+#define SizeT UInt32
+#endif
+#endif
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb unsigned short
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+ int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+ int lc;
+ int lp;
+ int pb;
+ #ifdef _LZMA_OUT_READ
+ UInt32 DictionarySize;
+ #endif
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+ CLzmaProperties Properties;
+ CProb *Probs;
+
+ #ifdef _LZMA_IN_CB
+ const unsigned char *Buffer;
+ const unsigned char *BufferLim;
+ #endif
+
+ #ifdef _LZMA_OUT_READ
+ unsigned char *Dictionary;
+ UInt32 Range;
+ UInt32 Code;
+ UInt32 DictionaryPos;
+ UInt32 GlobalPos;
+ UInt32 DistanceLimit;
+ UInt32 Reps[4];
+ int State;
+ int RemainLen;
+ unsigned char TempDictionary[4];
+ #endif
+} CLzmaDecoderState;
+
+#ifdef _LZMA_OUT_READ
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; }
+#endif
+
+int LzmaDecode(CLzmaDecoderState *vs,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback,
+ #else
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ #endif
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif
diff --git a/target/image/generic/lzma-loader/src/Makefile b/target/image/generic/lzma-loader/src/Makefile
new file mode 100644
index 0000000..d4a100d
--- /dev/null
+++ b/target/image/generic/lzma-loader/src/Makefile
@@ -0,0 +1,63 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+LOADADDR = 0x80400000 # RAM start + 4M
+KERNEL_ENTRY = 0x80001000
+RAMSIZE = 0x00100000 # 1MB
+IMAGE_COPY:=0
+
+CROSS_COMPILE = mips-linux-
+
+OBJCOPY:= $(CROSS_COMPILE)objcopy -O binary -R .reginfo -R .note -R .comment -R .mdebug -S
+CFLAGS := -fno-builtin -Os -G 0 -ffunction-sections -mno-abicalls -fno-pic -mabi=32 -march=mips32 -Wa,-32 -Wa,-march=mips32 -Wa,-mips32 -Wa,--trap -Wall -DRAMSIZE=${RAMSIZE} -DKERNEL_ENTRY=${KERNEL_ENTRY} -D_LZMA_IN_CB
+ifeq ($(IMAGE_COPY),1)
+CFLAGS += -DLOADADDR=${LOADADDR} -DIMAGE_COPY=1
+endif
+
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+.c.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+CC = $(CROSS_COMPILE)gcc
+LD = $(CROSS_COMPILE)ld
+OBJDUMP = $(CROSS_COMPILE)objdump
+
+O_FORMAT = $(shell $(OBJDUMP) -i | head -2 | grep elf32)
+
+# Drop some uninteresting sections in the kernel.
+# This is only relevant for ELF kernels but doesn't hurt a.out
+drop-sections = .reginfo .mdebug .comment
+strip-flags = $(addprefix --remove-section=,$(drop-sections))
+
+all : lzma.elf
+
+lzma.lds: lzma.lds.in
+ sed -e 's,@LOADADDR@,$(LOADADDR),g' -e 's,@ENTRY@,_start,g' $< >$@
+
+kernel.o: vmlinux.lzma lzma.lds
+ $(LD) -r -b binary --oformat $(O_FORMAT) -o $@ $<
+
+ifeq ($(IMAGE_COPY),1)
+lzma.o: decompress.o LzmaDecode.o kernel.o
+ sed -e 's,@LOADADDR@,$(LOADADDR),g' -e 's,@ENTRY@,entry,g' lzma.lds.in >lzma-stage2.lds
+ $(LD) -static --no-warn-mismatch -e entry -Tlzma-stage2.lds -o temp-$@ $^
+ $(OBJCOPY) temp-$@ lzma.tmp
+ @echo "SECTIONS { .data : { code_start = .; *(.data) code_stop = .; }}" > lzma-data.lds
+ $(LD) -no-warn-mismatch -T lzma-data.lds -r -o $@ -b binary lzma.tmp --oformat $(O_FORMAT)
+
+lzma.elf: start.o lzma.o
+ sed -e 's,@LOADADDR@,$(KERNEL_ENTRY),g' lzma-copy.lds.in >lzma-copy.lds
+ $(LD) -s -Tlzma-copy.lds -o $@ $^
+else
+lzma.elf: start.o decompress.o LzmaDecode.o kernel.o
+ $(LD) -s -Tlzma.lds -o $@ $^
+endif
+
+clean:
+ rm -f *.o lzma.elf *.tmp *.lds
diff --git a/target/image/generic/lzma-loader/src/decompress.c b/target/image/generic/lzma-loader/src/decompress.c
new file mode 100644
index 0000000..4ed432d
--- /dev/null
+++ b/target/image/generic/lzma-loader/src/decompress.c
@@ -0,0 +1,154 @@
+/*
+ * LZMA compressed kernel decompressor for bcm947xx boards
+ *
+ * Copyright (C) 2005 by Oleg I. Vdovikin <oleg@cs.msu.su>
+ *
+ * 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
+ *
+ *
+ * Please note, this was code based on the bunzip2 decompressor code
+ * by Manuel Novoa III (mjn3@codepoet.org), although the only thing left
+ * is an idea and part of original vendor code
+ *
+ *
+ * 12-Mar-2005 Mineharu Takahara <mtakahar@yahoo.com>
+ * pass actual output size to decoder (stream mode
+ * compressed input is not a requirement anymore)
+ *
+ * 24-Apr-2005 Oleg I. Vdovikin
+ * reordered functions using lds script, removed forward decl
+ *
+ * ??-Nov-2005 Mike Baker
+ * reorder the script as an lzma wrapper; do not depend on flash access
+ */
+
+#include "LzmaDecode.h"
+
+#define KSEG0 0x80000000
+#define KSEG1 0xa0000000
+
+#define KSEG1ADDR(a) ((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
+
+#define Index_Invalidate_I 0x00
+#define Index_Writeback_Inv_D 0x01
+
+#define cache_unroll(base,op) \
+ __asm__ __volatile__( \
+ ".set noreorder;\n" \
+ ".set mips3;\n" \
+ "cache %1, (%0);\n" \
+ ".set mips0;\n" \
+ ".set reorder\n" \
+ : \
+ : "r" (base), \
+ "i" (op));
+
+
+static __inline__ void blast_icache(unsigned long size, unsigned long lsize)
+{
+ unsigned long start = KSEG0;
+ unsigned long end = (start + size);
+
+ while(start < end) {
+ cache_unroll(start,Index_Invalidate_I);
+ start += lsize;
+ }
+}
+
+static __inline__ void blast_dcache(unsigned long size, unsigned long lsize)
+{
+ unsigned long start = KSEG0;
+ unsigned long end = (start + size);
+
+ while(start < end) {
+ cache_unroll(start,Index_Writeback_Inv_D);
+ start += lsize;
+ }
+}
+
+unsigned char *data;
+
+static int read_byte(void *object, unsigned char **buffer, UInt32 *bufferSize)
+{
+ *bufferSize = 1;
+ *buffer = data;
+ ++data;
+ return LZMA_RESULT_OK;
+}
+
+static __inline__ unsigned char get_byte(void)
+{
+ unsigned char *buffer;
+ UInt32 fake;
+
+ return read_byte(0, &buffer, &fake), *buffer;
+}
+
+static char *buffer = (char *)0x80C00000;
+extern char lzma_start[];
+extern char lzma_end[];
+
+/* should be the first function */
+void entry(unsigned long icache_size, unsigned long icache_lsize,
+ unsigned long dcache_size, unsigned long dcache_lsize)
+{
+ unsigned int i; /* temp value */
+ unsigned int osize; /* uncompressed size */
+ volatile unsigned int arg0, arg1, arg2, arg3;
+
+ /* restore argument registers */
+ __asm__ __volatile__ ("ori %0, $12, 0":"=r"(arg0));
+ __asm__ __volatile__ ("ori %0, $13, 0":"=r"(arg1));
+ __asm__ __volatile__ ("ori %0, $14, 0":"=r"(arg2));
+ __asm__ __volatile__ ("ori %0, $15, 0":"=r"(arg3));
+
+ ILzmaInCallback callback;
+ CLzmaDecoderState vs;
+ callback.Read = read_byte;
+
+ data = lzma_start;
+
+ /* lzma args */
+ i = get_byte();
+ vs.Properties.lc = i % 9, i = i / 9;
+ vs.Properties.lp = i % 5, vs.Properties.pb = i / 5;
+
+ vs.Probs = (CProb *)buffer;
+
+ /* skip rest of the LZMA coder property */
+ for (i = 0; i < 4; i++)
+ get_byte();
+
+ /* read the lower half of uncompressed size in the header */
+ osize = ((unsigned int)get_byte()) +
+ ((unsigned int)get_byte() << 8) +
+ ((unsigned int)get_byte() << 16) +
+ ((unsigned int)get_byte() << 24);
+
+ /* skip rest of the header (upper half of uncompressed size) */
+ for (i = 0; i < 4; i++)
+ get_byte();
+
+ /* decompress kernel */
+ if ((i = LzmaDecode(&vs, &callback,
+ (unsigned char*)KERNEL_ENTRY, osize, &osize)) == LZMA_RESULT_OK)
+ {
+ blast_dcache(dcache_size, dcache_lsize);
+ blast_icache(icache_size, icache_lsize);
+
+ /* Jump to load address */
+ ((void (*)(int a0, int a1, int a2, int a3)) KERNEL_ENTRY)(arg0, arg1, arg2, arg3);
+ }
+}
diff --git a/target/image/generic/lzma-loader/src/lzma-copy.lds.in b/target/image/generic/lzma-loader/src/lzma-copy.lds.in
new file mode 100644
index 0000000..fbc87ab
--- /dev/null
+++ b/target/image/generic/lzma-loader/src/lzma-copy.lds.in
@@ -0,0 +1,20 @@
+OUTPUT_ARCH(mips)
+ENTRY(_start)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = @LOADADDR@;
+ .text :
+ {
+ _ftext = . ;
+ *(.text)
+ *(.rodata)
+ } =0
+
+ .reginfo : { *(.reginfo) }
+
+ .bss :
+ {
+ *(.bss)
+ }
+}
diff --git a/target/image/generic/lzma-loader/src/lzma.lds.in b/target/image/generic/lzma-loader/src/lzma.lds.in
new file mode 100644
index 0000000..6021cec
--- /dev/null
+++ b/target/image/generic/lzma-loader/src/lzma.lds.in
@@ -0,0 +1,24 @@
+OUTPUT_ARCH(mips)
+ENTRY(@ENTRY@)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = @LOADADDR@;
+ .text :
+ {
+ _ftext = . ;
+ *(.text.entry)
+ *(.text)
+ *(.rodata)
+ lzma_start = .;
+ kernel.o
+ lzma_end = .;
+ } =0
+
+ .reginfo : { *(.reginfo) }
+
+ .bss :
+ {
+ *(.bss)
+ }
+}
diff --git a/target/image/generic/lzma-loader/src/print.c b/target/image/generic/lzma-loader/src/print.c
new file mode 100644
index 0000000..950687b
--- /dev/null
+++ b/target/image/generic/lzma-loader/src/print.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include "print.h"
+
+/* macros */
+#define IsDigit(x) ( ((x) >= '0') && ((x) <= '9') )
+#define Ctod(x) ( (x) - '0')
+
+/* forward declaration */
+extern int PrintChar(char *, char, int, int);
+extern int PrintString(char *, char *, int, int);
+extern int PrintNum(char *, unsigned long, int, int, int, int, char, int);
+
+/* private variable */
+static const char theFatalMsg[] = "fatal error in lp_Print!";
+
+/* -*-
+ * A low level printf() function.
+ */
+void
+lp_Print(void (*output)(void *, char *, int),
+ void * arg,
+ char *fmt,
+ va_list ap)
+{
+
+#define OUTPUT(arg, s, l) \
+ { if (((l) < 0) || ((l) > LP_MAX_BUF)) { \
+ (*output)(arg, (char*)theFatalMsg, sizeof(theFatalMsg)-1); for(;;); \
+ } else { \
+ (*output)(arg, s, l); \
+ } \
+ }
+
+ char buf[LP_MAX_BUF];
+
+ char c;
+ char *s;
+ long int num;
+
+ int longFlag;
+ int negFlag;
+ int width;
+ int prec;
+ int ladjust;
+ char padc;
+
+ int length;
+
+ for(;;) {
+ {
+ /* scan for the next '%' */
+ char *fmtStart = fmt;
+ while ( (*fmt != '\0') && (*fmt != '%')) {
+ fmt ++;
+ }
+
+ /* flush the string found so far */
+ OUTPUT(arg, fmtStart, fmt-fmtStart);
+
+ /* are we hitting the end? */
+ if (*fmt == '\0') break;
+ }
+
+ /* we found a '%' */
+ fmt ++;
+
+ /* check for long */
+ if (*fmt == 'l') {
+ longFlag = 1;
+ fmt ++;
+ } else {
+ longFlag = 0;
+ }
+
+ /* check for other prefixes */
+ width = 0;
+ prec = -1;
+ ladjust = 0;
+ padc = ' ';
+
+ if (*fmt == '-') {
+ ladjust = 1;
+ fmt ++;
+ }
+
+ if (*fmt == '0') {
+ padc = '0';
+ fmt++;
+ }
+
+ if (IsDigit(*fmt)) {
+ while (IsDigit(*fmt)) {
+ width = 10 * width + Ctod(*fmt++);
+ }
+ }
+
+ if (*fmt == '.') {
+ fmt ++;
+ if (IsDigit(*fmt)) {
+ prec = 0;
+ while (IsDigit(*fmt)) {
+ prec = prec*10 + Ctod(*fmt++);
+ }
+ }
+ }
+
+
+ /* check format flag */
+ negFlag = 0;
+ switch (*fmt) {
+ case 'b':
+ if (longFlag) {
+ num = va_arg(ap, long int);
+ } else {
+ num = va_arg(ap, int);
+ }
+ length = PrintNum(buf, num, 2, 0, width, ladjust, padc, 0);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case 'd':
+ case 'D':
+ if (longFlag) {
+ num = va_arg(ap, long int);
+ } else {
+ num = va_arg(ap, int);
+ }
+ if (num < 0) {
+ num = - num;
+ negFlag = 1;
+ }
+ length = PrintNum(buf, num, 10, negFlag, width, ladjust, padc, 0);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case 'o':
+ case 'O':
+ if (longFlag) {
+ num = va_arg(ap, long int);
+ } else {
+ num = va_arg(ap, int);
+ }
+ length = PrintNum(buf, num, 8, 0, width, ladjust, padc, 0);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case 'u':
+ case 'U':
+ if (longFlag) {
+ num = va_arg(ap, long int);
+ } else {
+ num = va_arg(ap, int);
+ }
+ length = PrintNum(buf, num, 10, 0, width, ladjust, padc, 0);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case 'x':
+ if (longFlag) {
+ num = va_arg(ap, long int);
+ } else {
+ num = va_arg(ap, int);
+ }
+ length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 0);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case 'X':
+ if (longFlag) {
+ num = va_arg(ap, long int);
+ } else {
+ num = va_arg(ap, int);
+ }
+ length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 1);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case 'c':
+ c = (char)va_arg(ap, int);
+ length = PrintChar(buf, c, width, ladjust);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case 's':
+ s = (char*)va_arg(ap, char *);
+ length = PrintString(buf, s, width, ladjust);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case '\0':
+ fmt --;
+ break;
+
+ default:
+ /* output this char as it is */
+ OUTPUT(arg, fmt, 1);
+ } /* switch (*fmt) */
+
+ fmt ++;
+ } /* for(;;) */
+
+ /* special termination call */
+ OUTPUT(arg, "\0", 1);
+}
+
+
+/* --------------- local help functions --------------------- */
+int
+PrintChar(char * buf, char c, int length, int ladjust)
+{
+ int i;
+
+ if (length < 1) length = 1;
+ if (ladjust) {
+ *buf = c;
+ for (i=1; i< length; i++) buf[i] = ' ';
+ } else {
+ for (i=0; i< length-1; i++) buf[i] = ' ';
+ buf[length - 1] = c;
+ }
+ return length;
+}
+
+int
+PrintString(char * buf, char* s, int length, int ladjust)
+{
+ int i;
+ int len=0;
+ char* s1 = s;
+ while (*s1++) len++;
+ if (length < len) length = len;
+
+ if (ladjust) {
+ for (i=0; i< len; i++) buf[i] = s[i];
+ for (i=len; i< length; i++) buf[i] = ' ';
+ } else {
+ for (i=0; i< length-len; i++) buf[i] = ' ';
+ for (i=length-len; i < length; i++) buf[i] = s[i-length+len];
+ }
+ return length;
+}
+
+int
+PrintNum(char * buf, unsigned long u, int base, int negFlag,
+ int length, int ladjust, char padc, int upcase)
+{
+ /* algorithm :
+ * 1. prints the number from left to right in reverse form.
+ * 2. fill the remaining spaces with padc if length is longer than
+ * the actual length
+ * TRICKY : if left adjusted, no "0" padding.
+ * if negtive, insert "0" padding between "0" and number.
+ * 3. if (!ladjust) we reverse the whole string including paddings
+ * 4. otherwise we only reverse the actual string representing the num.
+ */
+
+ int actualLength =0;
+ char *p = buf;
+ int i;
+
+ do {
+ int tmp = u %base;
+ if (tmp <= 9) {
+ *p++ = '0' + tmp;
+ } else if (upcase) {
+ *p++ = 'A' + tmp - 10;
+ } else {
+ *p++ = 'a' + tmp - 10;
+ }
+ u /= base;
+ } while (u != 0);
+
+ if (negFlag) {
+ *p++ = '-';
+ }
+
+ /* figure out actual length and adjust the maximum length */
+ actualLength = p - buf;
+ if (length < actualLength) length = actualLength;
+
+ /* add padding */
+ if (ladjust) {
+ padc = ' ';
+ }
+ if (negFlag && !ladjust && (padc == '0')) {
+ for (i = actualLength-1; i< length-1; i++) buf[i] = padc;
+ buf[length -1] = '-';
+ } else {
+ for (i = actualLength; i< length; i++) buf[i] = padc;
+ }
+
+
+ /* prepare to reverse the string */
+ {
+ int begin = 0;
+ int end;
+ if (ladjust) {
+ end = actualLength - 1;
+ } else {
+ end = length -1;
+ }
+
+ while (end > begin) {
+ char tmp = buf[begin];
+ buf[begin] = buf[end];
+ buf[end] = tmp;
+ begin ++;
+ end --;
+ }
+ }
+
+ /* adjust the string pointer */
+ return length;
+}
diff --git a/target/image/generic/lzma-loader/src/print.h b/target/image/generic/lzma-loader/src/print.h
new file mode 100644
index 0000000..b051463
--- /dev/null
+++ b/target/image/generic/lzma-loader/src/print.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef _print_h_
+#define _print_h_
+
+#include <stdarg.h>
+
+/* this is the maximum width for a variable */
+#define LP_MAX_BUF 80
+
+/* -*-
+ * output function takes an void pointer which is passed in as the
+ * second argument in lp_Print(). This black-box argument gives output
+ * function a way to track state.
+ *
+ * The second argument in output function is a pointer to char buffer.
+ * The third argument specifies the number of chars to outputed.
+ *
+ * output function cannot assume the buffer is null-terminated after
+ * l number of chars.
+ */
+void lp_Print(void (*output)(void *, char *, int),
+ void * arg,
+ char *fmt,
+ va_list ap);
+
+#endif
diff --git a/target/image/generic/lzma-loader/src/printf.c b/target/image/generic/lzma-loader/src/printf.c
new file mode 100644
index 0000000..49bd50d
--- /dev/null
+++ b/target/image/generic/lzma-loader/src/printf.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include "printf.h"
+#include "print.h"
+#include "uart16550.h"
+
+static void myoutput(void *arg, char *s, int l)
+{
+ int i;
+
+ // special termination call
+ if ((l==1) && (s[0] == '\0')) return;
+
+ for (i=0; i< l; i++) {
+ Uart16550Put(s[i]);
+ if (s[i] == '\n') Uart16550Put('\r');
+ }
+}
+
+void printf(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ lp_Print(myoutput, 0, fmt, ap);
+ va_end(ap);
+}
diff --git a/target/image/generic/lzma-loader/src/printf.h b/target/image/generic/lzma-loader/src/printf.h
new file mode 100644
index 0000000..9b1c1df
--- /dev/null
+++ b/target/image/generic/lzma-loader/src/printf.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef _printf_h_
+#define _printf_h_
+
+#include <stdarg.h>
+void printf(char *fmt, ...);
+
+#endif /* _printf_h_ */
diff --git a/target/image/generic/lzma-loader/src/start.S b/target/image/generic/lzma-loader/src/start.S
new file mode 100644
index 0000000..9a85c4c
--- /dev/null
+++ b/target/image/generic/lzma-loader/src/start.S
@@ -0,0 +1,160 @@
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+#define KSEG0 0x80000000
+
+#define C0_CONFIG $16
+#define C0_TAGLO $28
+#define C0_TAGHI $29
+
+#define CONF1_DA_SHIFT 7 /* D$ associativity */
+#define CONF1_DA_MASK 0x00000380
+#define CONF1_DA_BASE 1
+#define CONF1_DL_SHIFT 10 /* D$ line size */
+#define CONF1_DL_MASK 0x00001c00
+#define CONF1_DL_BASE 2
+#define CONF1_DS_SHIFT 13 /* D$ sets/way */
+#define CONF1_DS_MASK 0x0000e000
+#define CONF1_DS_BASE 64
+#define CONF1_IA_SHIFT 16 /* I$ associativity */
+#define CONF1_IA_MASK 0x00070000
+#define CONF1_IA_BASE 1
+#define CONF1_IL_SHIFT 19 /* I$ line size */
+#define CONF1_IL_MASK 0x00380000
+#define CONF1_IL_BASE 2
+#define CONF1_IS_SHIFT 22 /* Instruction cache sets/way */
+#define CONF1_IS_MASK 0x01c00000
+#define CONF1_IS_BASE 64
+
+#define Index_Invalidate_I 0x00
+#define Index_Writeback_Inv_D 0x01
+
+LEAF(_start)
+
+ .set mips32
+ .set noreorder
+
+ /* save argument registers */
+ move t4, a0
+ move t5, a1
+ move t6, a2
+ move t7, a3
+
+ /* set up stack */
+ li sp, 0xa0000000 + RAMSIZE - 16
+
+#ifdef IMAGE_COPY
+ /* Copy decompressor code to the right place */
+ li t2, LOADADDR
+ add a0, t2, 0
+ la a1, code_start
+ la a2, code_stop
+$L1:
+ lw t0, 0(a1)
+ sw t0, 0(a0)
+ add a1, 4
+ add a0, 4
+ blt a1, a2, $L1
+ nop
+#endif
+
+ /* At this point we need to invalidate dcache and */
+ /* icache before jumping to new code */
+
+1: /* Get cache sizes */
+ mfc0 s0,C0_CONFIG,1
+
+ li s1,CONF1_DL_MASK
+ and s1,s0
+ beq s1,zero,nodc
+ nop
+
+ srl s1,CONF1_DL_SHIFT
+ li t0,CONF1_DL_BASE
+ sll s1,t0,s1 /* s1 has D$ cache line size */
+
+ li s2,CONF1_DA_MASK
+ and s2,s0
+ srl s2,CONF1_DA_SHIFT
+ addiu s2,CONF1_DA_BASE /* s2 now has D$ associativity */
+
+ li t0,CONF1_DS_MASK
+ and t0,s0
+ srl t0,CONF1_DS_SHIFT
+ li s3,CONF1_DS_BASE
+ sll s3,s3,t0 /* s3 has D$ sets per way */
+
+ multu s2,s3 /* sets/way * associativity */
+ mflo t0 /* total cache lines */
+
+ multu s1,t0 /* D$ linesize * lines */
+ mflo s2 /* s2 is now D$ size in bytes */
+
+ /* Initilize the D$: */
+ mtc0 zero,C0_TAGLO
+ mtc0 zero,C0_TAGHI
+
+ li t0,KSEG0 /* Just an address for the first $ line */
+ addu t1,t0,s2 /* + size of cache == end */
+
+1: cache Index_Writeback_Inv_D,0(t0)
+ bne t0,t1,1b
+ addu t0,s1
+
+nodc:
+ /* Now we get to do it all again for the I$ */
+
+ move s3,zero /* just in case there is no icache */
+ move s4,zero
+
+ li t0,CONF1_IL_MASK
+ and t0,s0
+ beq t0,zero,noic
+ nop
+
+ srl t0,CONF1_IL_SHIFT
+ li s3,CONF1_IL_BASE
+ sll s3,t0 /* s3 has I$ cache line size */
+
+ li t0,CONF1_IA_MASK
+ and t0,s0
+ srl t0,CONF1_IA_SHIFT
+ addiu s4,t0,CONF1_IA_BASE /* s4 now has I$ associativity */
+
+ li t0,CONF1_IS_MASK
+ and t0,s0
+ srl t0,CONF1_IS_SHIFT
+ li s5,CONF1_IS_BASE
+ sll s5,t0 /* s5 has I$ sets per way */
+
+ multu s4,s5 /* sets/way * associativity */
+ mflo t0 /* s4 is now total cache lines */
+
+ multu s3,t0 /* I$ linesize * lines */
+ mflo s4 /* s4 is cache size in bytes */
+
+ /* Initilize the I$: */
+ mtc0 zero,C0_TAGLO
+ mtc0 zero,C0_TAGHI
+
+ li t0,KSEG0 /* Just an address for the first $ line */
+ addu t1,t0,s4 /* + size of cache == end */
+
+1: cache Index_Invalidate_I,0(t0)
+ bne t0,t1,1b
+ addu t0,s3
+noic:
+ /* jump to main */
+ move a0,s3 /* icache line size */
+ move a1,s4 /* icache size */
+ move a2,s1 /* dcache line size */
+#ifdef IMAGE_COPY
+ jal t2
+#else
+ jal entry
+#endif
+ move a3,s2 /* dcache size */
+
+ .set reorder
+END(_start)
+
diff --git a/target/image/generic/lzma-loader/src/uart16550.c b/target/image/generic/lzma-loader/src/uart16550.c
new file mode 100644
index 0000000..7df5727
--- /dev/null
+++ b/target/image/generic/lzma-loader/src/uart16550.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+
+#include "uart16550.h"
+
+/* === CONFIG === */
+
+#define BASE 0xb8058000
+#define MAX_BAUD 1152000
+#define REG_OFFSET 4
+
+/* === END OF CONFIG === */
+
+/* register offset */
+#define OFS_RCV_BUFFER (0*REG_OFFSET)
+#define OFS_TRANS_HOLD (0*REG_OFFSET)
+#define OFS_SEND_BUFFER (0*REG_OFFSET)
+#define OFS_INTR_ENABLE (1*REG_OFFSET)
+#define OFS_INTR_ID (2*REG_OFFSET)
+#define OFS_DATA_FORMAT (3*REG_OFFSET)
+#define OFS_LINE_CONTROL (3*REG_OFFSET)
+#define OFS_MODEM_CONTROL (4*REG_OFFSET)
+#define OFS_RS232_OUTPUT (4*REG_OFFSET)
+#define OFS_LINE_STATUS (5*REG_OFFSET)
+#define OFS_MODEM_STATUS (6*REG_OFFSET)
+#define OFS_RS232_INPUT (6*REG_OFFSET)
+#define OFS_SCRATCH_PAD (7*REG_OFFSET)
+
+#define OFS_DIVISOR_LSB (0*REG_OFFSET)
+#define OFS_DIVISOR_MSB (1*REG_OFFSET)
+
+
+/* memory-mapped read/write of the port */
+#define UART16550_READ(y) (*((volatile uint32*)(BASE + y)))
+#define UART16550_WRITE(y, z) ((*((volatile uint32*)(BASE + y))) = z)
+
+#define DEBUG_LED (*(unsigned short*)0xb7ffffc0)
+#define OutputLED(x) (DEBUG_LED = x)
+
+void Uart16550Init(uint32 baud, uint8 data, uint8 parity, uint8 stop)
+{
+ /* disable interrupts */
+ UART16550_WRITE(OFS_INTR_ENABLE, 0);
+
+ /* set up buad rate */
+ {
+ uint32 divisor;
+
+ /* set DIAB bit */
+ UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
+
+ /* set divisor */
+ divisor = MAX_BAUD / baud;
+ UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
+ UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00)>>8);
+
+ /* clear DIAB bit */
+ UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
+ }
+
+ /* set data format */
+ UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
+}
+
+uint8 Uart16550GetPoll()
+{
+ while((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
+ return UART16550_READ(OFS_RCV_BUFFER);
+}
+
+
+void Uart16550Put(uint8 byte)
+{
+ while ((UART16550_READ(OFS_LINE_STATUS) &0x20) == 0);
+ UART16550_WRITE(OFS_SEND_BUFFER, byte);
+}
+
diff --git a/target/image/generic/lzma-loader/src/uart16550.h b/target/image/generic/lzma-loader/src/uart16550.h
new file mode 100644
index 0000000..b3fd6fd
--- /dev/null
+++ b/target/image/generic/lzma-loader/src/uart16550.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef _uart16550_h_
+#define _uart16550_h_
+
+typedef unsigned char uint8;
+typedef unsigned int uint32;
+
+#define UART16550_BAUD_2400 2400
+#define UART16550_BAUD_4800 4800
+#define UART16550_BAUD_9600 9600
+#define UART16550_BAUD_19200 19200
+#define UART16550_BAUD_38400 38400
+#define UART16550_BAUD_57600 57600
+#define UART16550_BAUD_115200 115200
+
+#define UART16550_PARITY_NONE 0
+#define UART16550_PARITY_ODD 0x08
+#define UART16550_PARITY_EVEN 0x18
+#define UART16550_PARITY_MARK 0x28
+#define UART16550_PARITY_SPACE 0x38
+
+#define UART16550_DATA_5BIT 0x0
+#define UART16550_DATA_6BIT 0x1
+#define UART16550_DATA_7BIT 0x2
+#define UART16550_DATA_8BIT 0x3
+
+#define UART16550_STOP_1BIT 0x0
+#define UART16550_STOP_2BIT 0x4
+
+void Uart16550Init(uint32 baud, uint8 data, uint8 parity, uint8 stop);
+
+/* blocking call */
+uint8 Uart16550GetPoll();
+
+void Uart16550Put(uint8 byte);
+
+#endif
diff --git a/target/image/magicbox/Makefile b/target/image/magicbox/Makefile
new file mode 100644
index 0000000..10f71df
--- /dev/null
+++ b/target/image/magicbox/Makefile
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+define Build/Clean
+endef
+
+define Image/Prepare
+endef
+
+define Image/BuildKernel
+ cp $(LINUX_DIR)/arch/ppc/boot/images/uImage $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-uImage
+endef
+
+define Image/Build
+ $(call Image/Build/$(1),$(1))
+endef
+
+define Image/Build/jffs2-64k
+ ( \
+ dd if=$(LINUX_DIR)/arch/ppc/boot/images/uImage bs=65536 conv=sync; \
+ dd if=$(KDIR)/root.$(1) bs=65536 conv=sync; \
+ ) > $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).img
+endef
+
+#define Image/Build/jffs2-128k
+# ( \
+# dd if=$(LINUX_DIR)/arch/ppc/boot/images/uImage bs=131072 conv=sync; \
+# dd if=$(KDIR)/root.$(1) bs=131072 conv=sync; \
+# ) > $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).img
+#endef
+
+$(eval $(call BuildImage))
diff --git a/target/image/rb532/Makefile b/target/image/rb532/Makefile
new file mode 100644
index 0000000..2a61a48
--- /dev/null
+++ b/target/image/rb532/Makefile
@@ -0,0 +1,57 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+LOADADDR = 0x81000000 # RAM start + 16M
+KERNEL_ENTRY = 0x80101000
+RAMSIZE = 0x00100000 # 1MB
+IMAGE_COPY = 1
+
+LOADER_MAKEOPTS= \
+ KDIR=$(KDIR) \
+ LOADADDR=$(LOADADDR) \
+ KERNEL_ENTRY=$(KERNEL_ENTRY) \
+ RAMSIZE=$(RAMSIZE) \
+ IMAGE_COPY=$(IMAGE_COPY)
+
+define Build/Clean
+ $(MAKE) -C ../generic/lzma-loader $(LOADER_MAKEOPTS) clean
+endef
+
+define Image/Prepare
+ cat $(KDIR)/vmlinux | $(STAGING_DIR)/bin/lzma e -si -so -eos -lc1 -lp2 -pb2 > $(KDIR)/vmlinux.lzma
+ $(MAKE) -C ../generic/lzma-loader $(LOADER_MAKEOPTS) clean compile
+endef
+
+define Image/BuildKernel
+ $(CP) $(KDIR)/loader.elf $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-vmlinux
+endef
+
+PARTITION1=\x80\x01\x01\x00\x27\x01\x20\x7b\x20\x00\x00\x00\xe0\x1e\x00\x00# 4 MB (kernel part)
+PARTITION2=\x00\x00\x01\x7c\x83\x01\xa0\x64\x00\x1f\x00\x00\x40\x7a\x00\x00# 16 MB (rootfs part)
+
+define Image/Build/jffs2-128k
+ ( \
+ echo -ne OWRT | dd bs=$$$$((0x1be)) conv=sync; \
+ ( \
+ echo -ne '$(strip $(PARTITION1))'; \
+ echo -ne '$(strip $(PARTITION2))'; \
+ ) | dd bs=$$$$((0x40)) conv=sync; \
+ echo -ne '\x55\xaa'; \
+ dd if=/dev/zero bs=$$$$((0x3e00)) conv=sync count=1; \
+ dd if=$(KDIR)/loader.elf bs=$$$$((0x3dc000)) conv=sync; \
+ cat $(KDIR)/root.$(1); \
+ echo -ne '\xde\xad\xc0\xde'; \
+ ) > $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).bin
+endef
+
+define Image/Build
+ $(call Image/Build/$(1),$(1))
+endef
+
+$(eval $(call BuildImage))
diff --git a/target/image/uml/Makefile b/target/image/uml/Makefile
new file mode 100755
index 0000000..6af4b8b
--- /dev/null
+++ b/target/image/uml/Makefile
@@ -0,0 +1,15 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+define Image/Build
+ cp $(KDIR)/root.$(1) $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).img
+ cp $(LINUX_DIR)/linux $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-vmlinux
+endef
+
+$(eval $(call BuildImage))
diff --git a/target/image/x86/Config.in b/target/image/x86/Config.in
new file mode 100644
index 0000000..fa61468
--- /dev/null
+++ b/target/image/x86/Config.in
@@ -0,0 +1,20 @@
+config X86_GRUB_IMAGES
+ bool "Build GRUB images (Linux x86 or x86_64 host only)"
+ depends LINUX_2_6_X86
+ depends TARGET_ROOTFS_EXT2FS || TARGET_ROOTFS_JFFS2
+ default y
+
+config X86_GRUB_BAUDRATE
+ int "Serial port baud rate"
+ depends X86_GRUB_IMAGES
+ default 38400
+
+config X86_GRUB_KERNELPART
+ int "Kernel partition size (in MB)"
+ depends X86_GRUB_IMAGES
+ default 4
+
+config X86_GRUB_FSPART
+ int "Filesystem partition size (in MB)"
+ depends X86_GRUB_IMAGES
+ default 16
diff --git a/target/image/x86/Makefile b/target/image/x86/Makefile
new file mode 100644
index 0000000..b836f3a
--- /dev/null
+++ b/target/image/x86/Makefile
@@ -0,0 +1,54 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+ifeq ($(CONFIG_X86_GRUB_IMAGES),y)
+ define Build/Compile
+ $(MAKE) -C grub compile
+ endef
+
+ define Build/Clean
+ $(MAKE) -C grub clean
+ endef
+
+ define Image/cmdline/jffs2-64k
+ block2mtd.block2mtd=/dev/hda2,65536 root=/dev/mtdblock0 rootfstype=jffs2
+ endef
+
+ define Image/cmdline/jffs2-128k
+ block2mtd.block2mtd=/dev/hda2,131072 root=/dev/mtdblock0 rootfstype=jffs2
+ endef
+
+ define Image/cmdline/ext2
+ root=/dev/hda2 rootfstype=ext2
+ endef
+
+ define Image/Build/grub
+ mkdir -p $(KDIR)/root.grub/boot/grub
+ $(CP) \
+ $(STAGING_DIR)/usr/lib/grub/i386-pc/stage1 \
+ $(STAGING_DIR)/usr/lib/grub/i386-pc/stage2 \
+ $(STAGING_DIR)/usr/lib/grub/i386-pc/e2fs_stage1_5 \
+ $(KDIR)/root.grub/boot/grub/
+ $(CP) $(LINUX_DIR)/arch/i386/boot/bzImage $(KDIR)/root.grub/boot/vmlinuz
+ sed \
+ -e 's#@CMDLINE@#$(strip $(call Image/cmdline/$(1)))#g' \
+ -e 's#@BAUDRATE@#$(CONFIG_X86_GRUB_BAUDRATE)#g' \
+ ./grub/menu.lst > $(KDIR)/root.grub/boot/grub/menu.lst
+ PATH="$(STAGING_DIR)/usr/sbin:$(STAGING_DIR)/bin:$(PATH)" ./gen_image.sh $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).image $(CONFIG_X86_GRUB_KERNELPART) $(KDIR)/root.grub $(CONFIG_X86_GRUB_FSPART) $(KDIR)/root.$(1)
+ endef
+endif
+
+define Image/Build
+ $(call Image/Build/grub,$(1))
+ cp $(KDIR)/root.$(1) $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).fs
+ cp $(LINUX_DIR)/arch/i386/boot/bzImage $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-vmlinuz
+endef
+
+
+$(eval $(call BuildImage))
diff --git a/target/image/x86/gen_image.sh b/target/image/x86/gen_image.sh
new file mode 100755
index 0000000..95be6cc
--- /dev/null
+++ b/target/image/x86/gen_image.sh
@@ -0,0 +1,60 @@
+#!/usr/bin/env bash
+# Copyright (C) 2006 OpenWrt.org
+
+[ $# == 5 ] || {
+ echo "SYNTAX: $0 <file> <kernel size> <kernel directory> <rootfs size> <rootfs image>"
+ exit 1
+}
+
+file="$1"
+part1s="$2"
+part1d="$3"
+part2s="$4"
+part2f="$5"
+
+head=16
+sect=63
+cyl=$(( ($part1s + $part2s) * 1024 * 1024 / ($head * $sect * 512)))
+
+dd if=/dev/zero of="$file" bs=1M count=$(($part1s + $part2s)) 2>/dev/null || exit
+fdisk -u -C $cyl -H $head -S $sect "$file" > /dev/null 2>/dev/null <<EOF
+n
+p
+1
+
++${part1s}M
+n
+p
+2
+
++${part2s}M
+w
+q
+EOF
+
+block() {
+ echo -e 'p\nq' | fdisk -u -C $cyl -H $head -S $sect "$file" | awk -v file="$file$1" -v n="$(($2 + 2))" '
+$1 == file {
+ print $n * 512
+}'
+}
+
+start="$(block 1 0)"
+end="$(block 1 1)"
+blocks="$(( ($end - $start) / 1024 ))"
+
+genext2fs -d "$part1d" -b "$blocks" "$file.kernel"
+dd if="$file.kernel" of="$file" bs=512 seek="$(($start / 512))" conv=notrunc
+rm -f "$file.kernel"
+
+start="$(block 2 0)"
+dd if="$part2f" of="$file" bs=512 seek="$(($start / 512))" conv=notrunc
+
+which chpax >/dev/null && chpax -zp $(which grub)
+grub --device-map=/dev/null <<EOF
+device (hd0) $file
+geometry (hd0) $cyl $head $sect
+root (hd0,0)
+setup (hd0)
+EOF
+
diff --git a/target/image/x86/grub/Makefile b/target/image/x86/grub/Makefile
new file mode 100644
index 0000000..86a9001
--- /dev/null
+++ b/target/image/x86/grub/Makefile
@@ -0,0 +1,58 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+# $Id: Makefile 4855 2006-09-24 20:49:31Z nico $
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=grub
+PKG_VERSION:=0.97
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=ftp://alpha.gnu.org/gnu/grub
+PKG_MD5SUM:=cd3f3eb54446be6003156158d51f4884
+PKG_CAT:=zcat
+
+PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/grub-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Build/Configure
+ (cd $(PKG_BUILD_DIR); \
+ LDFLAGS="-static" \
+ ./configure \
+ --target=$(GNU_TARGET_NAME) \
+ --host=$(GNU_TARGET_NAME) \
+ --build=$(GNU_HOST_NAME) \
+ --program-prefix="" \
+ --program-suffix="" \
+ --prefix=/usr \
+ --exec-prefix=/usr \
+ --bindir=/usr/bin \
+ --sbindir=/usr/sbin \
+ --libexecdir=/usr/lib \
+ --sysconfdir=/etc \
+ --datadir=/usr/share \
+ --localstatedir=/var \
+ --mandir=/usr/man \
+ --infodir=/usr/info \
+ $(DISABLE_NLS) \
+ )
+endef
+
+define Build/Compile
+ $(MAKE) -C $(PKG_BUILD_DIR)
+endef
+
+define Build/InstallDev
+ $(MAKE) -C $(PKG_BUILD_DIR) \
+ DESTDIR="$(STAGING_DIR)" \
+ install
+endef
+
+$(eval $(call Build/DefaultTargets))
diff --git a/target/image/x86/grub/menu.lst b/target/image/x86/grub/menu.lst
new file mode 100644
index 0000000..590a7d5
--- /dev/null
+++ b/target/image/x86/grub/menu.lst
@@ -0,0 +1,11 @@
+serial --unit=0 --speed=@BAUDRATE@ --word=8 --parity=no --stop=1
+terminal --timeout=10 serial
+
+default 0
+timeout 5
+
+title OpenWrt
+root (hd0,0)
+kernel /boot/vmlinuz @CMDLINE@ noinitrd console=ttyS0,@BAUDRATE@n8 reboot=bios
+boot
+
diff --git a/target/image/xscale/Makefile b/target/image/xscale/Makefile
new file mode 100644
index 0000000..23a0644
--- /dev/null
+++ b/target/image/xscale/Makefile
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+define Build/Clean
+endef
+
+define Image/Prepare
+endef
+
+define Image/BuildKernel
+ cp $(LINUX_DIR)/arch/arm/boot/zImage $(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-zImage
+endef
+
+define Image/Build
+ $(call Image/Build/$(1),$(1))
+endef
+
+define Image/Build/jffs2-64k
+ dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).img bs=65536 conv=sync
+endef
+
+define Image/Build/jffs2-128k
+ dd if=$(KDIR)/root.$(1) of=$(BIN_DIR)/openwrt-$(BOARD)-$(KERNEL)-$(1).img bs=131072 conv=sync
+endef
+
+$(eval $(call BuildImage))
diff --git a/target/linux/Config.in b/target/linux/Config.in
new file mode 100644
index 0000000..20099fe
--- /dev/null
+++ b/target/linux/Config.in
@@ -0,0 +1,492 @@
+menu "Kernel Configuration / Device Support"
+
+comment "Device specific configuration"
+
+source "target/linux/*-2.[46]/Config.in"
+
+comment "Kernel modules"
+
+menu "Networking modules"
+
+config PACKAGE_KMOD_ATM
+ prompt "kmod-atm.......................... ATM support"
+ tristate
+ default y if LINUX_2_4_AR7
+ default m
+ help
+ ATM support
+
+config PACKAGE_KMOD_IPIP
+ prompt "kmod-ipip......................... IP in IP encapsulation support"
+ tristate
+ default m
+ help
+ Kernel module for IP in IP encapsulation
+
+config PACKAGE_KMOD_RING
+ prompt "kmod-ring......................... PF Ring"
+ tristate
+ default m
+ help
+ PF Ring
+
+config PACKAGE_KMOD_TUN
+ prompt "kmod-tun.......................... Universal TUN/TAP driver"
+ tristate
+ default m
+ help
+ Kernel support for the TUN/TAP tunneling device
+
+endmenu
+
+menu "Block devices support"
+
+config PACKAGE_kmod-ide-core
+ prompt "kmod-ide-core..................... IDE support"
+ tristate
+ default m
+ depends LINUX_2_4_X86 || LINUX_2_6_X86 || LINUX_2_4_BRCM || LINUX_2_6_BRCM
+ help
+ Kernel modules for IDE support
+ useful for usb mass storage devices (e.g. on WL-HDD)
+
+ Includes:
+ - ide-core
+ - ide-detect
+ - ide-disk
+
+config PACKAGE_kmod-ide-pdc202xx
+ prompt "kmod-ide-pdc202xx................. PDC202xx driver"
+ tristate
+ default m
+ depends PACKAGE_kmod-ide-core
+ depends LINUX_2_4_X86 || LINUX_2_6_X86 || LINUX_2_4_BRCM || LINUX_2_6_BRCM
+ help
+ Kernel modules for IDE support
+ useful for usb mass storage devices (e.g. on WL-HDD)
+
+ Includes:
+ - ide-core
+ - ide-detect
+ - ide-disk
+
+config PACKAGE_KMOD_LOOP
+ prompt "kmod-loop......................... Loop mount support"
+ tristate
+ default m
+ help
+ Kernel module for loop mount support
+
+config PACKAGE_KMOD_NBD
+ prompt "kmod-nbd.......................... Network Block Device"
+ tristate
+ default m
+ help
+ Kernel module for network block device
+
+endmenu
+
+menu "Filesystems support"
+
+config PACKAGE_KMOD_FS_CIFS
+ prompt "kmod-fs-cifs...................... CIFS support"
+ tristate
+ default m
+ help
+ Kernel modules for CIFS support
+
+config PACKAGE_KMOD_FS_EXT2
+ prompt "kmod-fs-ext2...................... EXT2 filesystem support"
+ tristate
+ default m
+ help
+ Kernel modules for EXT2 filesystem support
+
+config PACKAGE_KMOD_FS_EXT3
+ prompt "kmod-fs-ext3...................... EXT3 filesystem support"
+ tristate
+ default m
+ help
+ Kernel modules for EXT3 filesystem support
+
+config PACKAGE_KMOD_FS_HFSPLUS
+ prompt "kmod-fs-hfsplus................... HFS+ filesystem support"
+ tristate
+ default m
+ help
+ Kernel modules for HFS+ filesystem support
+
+config PACKAGE_KMOD_FS_NFS
+ prompt "kmod-fs-nfs....................... NFS support"
+ tristate
+ default m
+ help
+ Kernel modules for NFS support
+ Includes lockd, nfs and sunrpc
+
+config PACKAGE_KMOD_FS_VFAT
+ prompt "kmod-fs-vfat...................... VFAT filesystem support"
+ tristate
+ default m
+ help
+ Kernel modules for VFAT filesystem support
+ useful for usb mass storage devices
+
+config PACKAGE_KMOD_FS_XFS
+ prompt "kmod-fs-xfs....................... XFS filesystem support"
+ tristate
+ default m
+ help
+ Kernel modules for XFS filesystem support
+
+endmenu
+
+menu "Multimedia devices support"
+
+config PACKAGE_KMOD_PWC
+ prompt "kmod-pwc.......................... Kernel driver for USB Philips Cameras"
+ tristate
+ depends PACKAGE_KMOD_USB
+ default m
+
+config PACKAGE_KMOD_SOUNDCORE
+ prompt "kmod-soundcore.................... Soundcard support"
+ tristate
+ default n
+ help
+ Base support for soundcards
+ Requires either USB soundcard support (OSS) or ALSA package to be useful
+
+config PACKAGE_KMOD_VIDEODEV
+ prompt "kmod-videodev..................... Video (For Linux) kernel support"
+ tristate
+ default m
+
+endmenu
+
+menu "Native Language support"
+
+config PACKAGE_KMOD_NLS_BASE
+ prompt "kmod-nls-base..................... Native Language support"
+ tristate
+ default m
+ help
+ Kernel native language support
+
+config PACKAGE_KMOD_NLS_CP437
+ prompt "kmod-nls-cp437.................. Codepage 437 (United States, Canada)"
+ tristate
+ default m
+ depends PACKAGE_KMOD_NLS_BASE
+ help
+ Kernel native language support
+
+config PACKAGE_KMOD_NLS_CP850
+ prompt "kmod-nls-cp850.................. Codepage 850 (Europe)"
+ tristate
+ default m
+ depends PACKAGE_KMOD_NLS_BASE
+ help
+ Kernel native language support
+
+config PACKAGE_KMOD_NLS_ISO8859_1
+ prompt "kmod-nls-iso8859-1.............. NLS ISO 8859-1 (Latin 1; Western European Languages)"
+ tristate
+ default m
+ depends PACKAGE_KMOD_NLS_BASE
+ help
+ Kernel native language support
+
+config PACKAGE_KMOD_NLS_ISO8859_15
+ prompt "kmod-nls-iso8859-15............. NLS ISO 8859-15 (Latin 15; Western European Languages with Euro)"
+ tristate
+ default m
+ depends PACKAGE_KMOD_NLS_BASE
+ help
+ Kernel native language support
+
+config PACKAGE_KMOD_NLS_UTF8
+ prompt "kmod-nls-utf8................... NLS UTF8"
+ tristate
+ default m
+ depends PACKAGE_KMOD_NLS_BASE
+ help
+ Kernel native language support
+
+endmenu
+
+menu "Network devices support"
+ depends LINUX_2_4_X86 || LINUX_2_6_X86
+
+
+config PACKAGE_KMOD_NET_AIRO
+ prompt "kmod-net-airo..................... Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards kernel support"
+ tristate
+ depends LINUX_2_4_X86 || LINUX_2_6_X86
+ default m
+ help
+ This is the standard Linux driver to support Cisco/Aironet ISA and
+ PCI 802.11 wireless cards.
+ It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X
+ - with or without encryption) as well as card before the Cisco
+ acquisition (Aironet 4500, Aironet 4800, Aironet 4800B).
+
+ This driver support both the standard Linux Wireless Extensions
+ and Cisco proprietary API, so both the Linux Wireless Tools and the
+ Cisco Linux utilities can be used to configure the card.
+
+
+config PACKAGE_KMOD_NET_HERMES
+ prompt "kmod-net-hermes................... Hermes chipset 802.11b support (Orinoco/Prism2/Symbol) kernel support"
+ tristate
+ depends LINUX_2_4_X86 || LINUX_2_6_X86
+ default m
+ help
+ A driver for 802.11b wireless cards based based on the "Hermes" or
+ Intersil HFA384x (Prism 2) MAC controller. This includes the vast
+ majority of the PCMCIA 802.11b cards (which are nearly all rebadges)
+ - except for the Cisco/Aironet cards. Cards supported include the
+ Apple Airport (not a PCMCIA card), WavelanIEEE/Orinoco,
+ Cabletron/EnteraSys Roamabout, ELSA AirLancer, MELCO Buffalo, Avaya,
+ IBM High Rate Wireless, Farralon Syyline, Samsung MagicLAN, Netgear
+ MA401, LinkSys WPC-11, D-Link DWL-650, 3Com AirConnect, Intel
+ PRO/Wireless, and Symbol Spectrum24 High Rate amongst others.
+
+config PACKAGE_KMOD_NET_HERMES_PCI
+ prompt "kmod-net-hermes-pci............. Intersil Prism 2.5 PCI 802.11b adaptor support"
+ tristate
+ default m
+ depends PACKAGE_KMOD_NET_HERMES
+ help
+ Enable support for PCI and mini-PCI 802.11b wireless NICs based on
+ the Prism 2.5 chipset. These are true PCI cards, not the 802.11b
+ PCMCIA cards bundled with PCI<->PCMCIA adaptors which are also
+ common. Some of the built-in wireless adaptors in laptops are of
+ this variety.
+
+config PACKAGE_KMOD_NET_HERMES_PLX
+ prompt "kmod-net-hermes-plx............. Hermes in PLX9052 based PCI adaptor (Netgear MA301, etc.) kernel support"
+ tristate
+ default m
+ depends PACKAGE_KMOD_NET_HERMES
+ help
+ Enable support for PCMCIA cards supported by the "Hermes" (aka
+ orinoco_cs) driver when used in PLX9052 based PCI adaptors. These
+ adaptors are not a full PCMCIA controller but act as a more limited
+ PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
+ 802.11b PCMCIA cards can be used in desktop machines. The Netgear
+ MA301 is such an adaptor.
+
+
+
+config PACKAGE_KMOD_NET_PRISM54
+ prompt "kmod-net-prism54.................. Intersil Prism GT/Duette/Indigo PCI/PCMCIA cards kernel support"
+ tristate
+ depends LINUX_2_4_X86 || LINUX_2_6_X86 || LINUX_2_4_BRCM || LINUX_2_6_BRCM
+ default m
+ help
+ Enable PCI and Cardbus support for the following chipset based cards:
+
+ * ISL3880 - Prism GT 802.11 b/g
+ * ISL3877 - Prism Indigo 802.11 a
+ * ISL3890 - Prism Duette 802.11 a/b/g
+
+ For a complete list of supported cards visit <http://prism54.org>.
+ Here is the latest confirmed list of supported cards:
+
+ * 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72
+ * Allnet ALL0271 PCI Card
+ * Compex WL54G Cardbus Card
+ * Corega CG-WLCB54GT Cardbus Card
+ * D-Link Air Plus Xtreme G A1 Cardbus Card aka DWL-g650
+ * I-O Data WN-G54/CB Cardbus Card
+ * Kobishi XG-300 aka Z-Com Cardbus Card
+ * Netgear WG511 Cardbus Card
+ * Ovislink WL-5400PCI PCI Card
+ * Peabird WLG-PCI PCI Card
+ * Sitecom WL-100i Cardbus Card
+ * Sitecom WL-110i PCI Card
+ * SMC2802W - EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card
+ * SMC2835W - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card
+ * Z-Com XG-900 PCI Card
+ * Zyxel G-100 Cardbus Card
+
+ If you enable this, you require a firmware file as well.
+ You will need to copy this to /usr/lib/hotplug/firmware/isl3890.
+ You can get this non-GPL'd firmware file from the Prism54 project page:
+ <http://prism54.org>.
+
+ Note: You need a motherboard with DMA support to use any of these cards.
+
+endmenu
+
+menu "PCMCIA/CardBus support"
+ depends PCMCIA_SUPPORT
+
+config PACKAGE_KMOD_PCMCIA_CORE
+ prompt "kmod-pcmcia-core.................. PCMCIA/CardBus support"
+ tristate
+ default m
+
+config PACKAGE_KMOD_PCMCIA_SERIAL
+ prompt "kmod-pcmcia-serial.............. PCMCIA/CardBus serial device support"
+ tristate
+ default m
+ depends PACKAGE_KMOD_PCMCIA_CORE
+
+endmenu
+
+menu "USB support"
+ depends USB_SUPPORT
+
+config PACKAGE_KMOD_USB
+ prompt "kmod-usb-core..................... USB support"
+ tristate
+ default m
+
+config PACKAGE_KMOD_USB_UHCI
+ prompt "kmod-usb-uhci................... Support for UHCI controllers"
+ tristate
+ default n if LINUX_2_6_AU1000
+ depends PACKAGE_KMOD_USB
+ select PACKAGE_KMOD_USB_CONTROLLER
+
+config PACKAGE_KMOD_USB_OHCI
+ prompt "kmod-usb-ohci................... Support for OHCI controllers"
+ tristate
+ default m
+ depends PACKAGE_KMOD_USB
+ select PACKAGE_KMOD_USB_CONTROLLER
+
+config PACKAGE_KMOD_USB2
+ prompt "kmod-usb2....................... Support for USB 2.0 controllers"
+ tristate
+ default n if LINUX_2_6_AU1000
+ depends PACKAGE_KMOD_USB
+ select PACKAGE_KMOD_USB_CONTROLLER
+
+config PACKAGE_KMOD_USB_CONTROLLER
+ tristate
+ depends on PACKAGE_KMOD_USB_UHCI || PACKAGE_KMOD_USB_OHCI || PACKAGE_KMOD_USB2
+ default n
+
+config PACKAGE_KMOD_USB_ACM
+ prompt "kmod-usb-acm...................... Support for USB modems/isdn controllers"
+ tristate
+ default m
+ depends PACKAGE_KMOD_USB_CONTROLLER
+
+config PACKAGE_KMOD_USB_AUDIO
+ prompt "kmod-usb-audio.................... Support for USB soundcards"
+ tristate
+ default m
+ depends PACKAGE_KMOD_USB_CONTROLLER
+ select PACKAGE_KMOD_SOUNDCORE
+
+config PACKAGE_KMOD_USB_PRINTER
+ prompt "kmod-usb-printer.................. Support for USB printers"
+ tristate
+ default m
+ depends PACKAGE_KMOD_USB_CONTROLLER
+
+config PACKAGE_KMOD_USB_SERIAL
+ prompt "kmod-usb-serial................... Support for USB-to-serial converters"
+ tristate
+ default m
+ depends PACKAGE_KMOD_USB_CONTROLLER
+
+config PACKAGE_KMOD_USB_SERIAL_BELKIN
+ prompt "kmod-usb-serial-belkin.......... Support for Belkin USB-to-serial converters"
+ tristate
+ default m
+ depends PACKAGE_KMOD_USB_SERIAL
+
+config PACKAGE_KMOD_USB_SERIAL_FTDI
+ prompt "kmod-usb-serial-ftdi............ Support for FTDI USB-to-serial converterr"
+ tristate
+ default m
+ depends PACKAGE_KMOD_USB_SERIAL
+
+config PACKAGE_KMOD_USB_SERIAL_MCT_U232
+ prompt "kmod-usb-serial-mct-u232........ Support for Magic Control Technology USB-to-Serial converters"
+ tristate
+ default m
+ depends PACKAGE_KMOD_USB_SERIAL
+
+config PACKAGE_KMOD_USB_SERIAL_PL2303
+ prompt "kmod-usb-serial-pl2303.......... Support for Prolific PL2303 USB-to-Serial converters"
+ tristate
+ default m
+ depends PACKAGE_KMOD_USB_SERIAL
+
+config PACKAGE_KMOD_USB_SERIAL_VISOR
+ prompt "kmod-usb-serial-visor........... Support for Handspring Visor / Palm m50x / Sony Clie Driver"
+ tristate
+ default m
+ depends PACKAGE_KMOD_USB_SERIAL
+
+config PACKAGE_KMOD_USB_STORAGE
+ prompt "kmod-usb-storage.................. Support for USB storage devices"
+ tristate
+ default m
+ depends PACKAGE_KMOD_USB_CONTROLLER
+
+config PACKAGE_KMOD_USB_ATM
+ prompt "kmod-usb-atm...................... Support for USB ATM devices"
+ tristate
+ default m
+ depends PACKAGE_KMOD_USB_CONTROLLER
+
+config PACKAGE_KMOD_USB_ATM_SPEEDTOUCH
+ prompt "kmod-usb-atm-speedtouch......... Support for USB Speedtouch ADSL modem"
+ tristate
+ default m
+ depends PACKAGE_KMOD_USB_ATM
+
+endmenu
+
+menu "Misc. devices support"
+
+config PACKAGE_KMOD_AX25
+ prompt "kmod-ax25......................... AX25 support"
+ tristate
+ default m
+ help
+ Kernel modules for AX25 protocol family
+
+ This package contains both the AX25 layer 2 support (ax25) and AX25 KISS driver (mkiss)
+
+config PACKAGE_KMOD_BLUETOOTH
+ prompt "kmod-bluetooth.................... Bluetooth drivers and network stack"
+ tristate
+ depends PCI_SUPPORT || USB_SUPPORT
+ default m
+ help
+ Bluetooth drivers and network stack
+
+config PACKAGE_KMOD_LP
+ prompt "kmod-lp........................... Parallel port and lp support"
+ tristate
+ default m
+ help
+ Kernel modules for line printer and parallel port support
+
+config PACKAGE_KMOD_SOFTDOG
+ prompt "kmod-softdog...................... Software watchdog"
+ tristate
+ default m
+ help
+ Kernel modules for software watchdog driver
+
+config PACKAGE_KMOD_WD1100
+ prompt "kmod-wd1100....................... Soekris net4801 watchdog"
+ tristate
+ default y
+ depends LINUX_2_4_X86
+ help
+ Driver for the NatSemi SC1x00 series Watchdog
+ found on Soekris net4801 boards
+
+endmenu
+
+endmenu
diff --git a/target/linux/Makefile b/target/linux/Makefile
new file mode 100644
index 0000000..8682fc2
--- /dev/null
+++ b/target/linux/Makefile
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/target.mk
+
+download:
+ $(MAKE) -C $(BOARD)-$(KERNEL) download
+
+prepare:
+ rm -f $(TOPDIR)/.kernel.mk
+ $(MAKE) -C $(BOARD)-$(KERNEL) prepare
+
+compile:
+ $(MAKE) -C $(BOARD)-$(KERNEL) compile
+
+install:
+ $(MAKE) -C $(BOARD)-$(KERNEL) install
+
+clean:
+ $(MAKE) -C $(BOARD)-$(KERNEL) clean
diff --git a/target/linux/ar531x-2.4/Makefile b/target/linux/ar531x-2.4/Makefile
new file mode 100644
index 0000000..33cb47c
--- /dev/null
+++ b/target/linux/ar531x-2.4/Makefile
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+LINUX_VERSION:=2.4.32
+LINUX_RELEASE:=1
+LINUX_KERNEL_MD5SUM:=38f4d0830e95a20f4bfed17622d5557c
+
+include ./config
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/kernel-build.mk
+
+$(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked
+ [ -d ../generic-$(KERNEL)/patches ] && $(PATCH) $(LINUX_DIR) ../generic-$(KERNEL)/patches
+ [ -d ./patches ] && $(PATCH) $(LINUX_DIR) ./patches
+ @$(CP) config $(LINUX_DIR)/.config
+ touch $@
+
diff --git a/target/linux/ar531x-2.4/config b/target/linux/ar531x-2.4/config
new file mode 100644
index 0000000..782d1de
--- /dev/null
+++ b/target/linux/ar531x-2.4/config
@@ -0,0 +1,1164 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MIPS=y
+CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_FICMMP is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_HYDROGEN3 is not set
+CONFIG_AR531X=y
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_COGENT_CSB250 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_CASIO_E55 is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_IBM_WORKPAD is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_PMC_BIG_SUR is not set
+# CONFIG_PMC_STRETCH is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TANBAC_TB0226 is not set
+# CONFIG_TANBAC_TB0229 is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_VICTOR_MPC30X is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_IRQ_CPU=y
+CONFIG_CPU_R4X00=y
+CONFIG_SERIAL=y
+CONFIG_NEW_IRQ=y
+CONFIG_NEW_TIME_C=y
+CONFIG_NONCOHERENT_IO=y
+CONFIG_EARLY_PRINTK_HACK=y
+# CONFIG_SCSI is not set
+
+#
+# Board selection
+#
+# CONFIG_APUNKNOWN is not set
+CONFIG_AP30=y
+# CONFIG_AP31 is not set
+# CONFIG_AP33 is not set
+# CONFIG_AP38 is not set
+# CONFIG_AP43 is not set
+# CONFIG_AP48 is not set
+# CONFIG_AP51 is not set
+# CONFIG_AP30ASK is not set
+CONFIG_MTD_PHYSMAP_BUSWIDTH=2
+
+#
+# Flash Selection
+#
+CONFIG_FLASH_2MB=y
+# CONFIG_FLASH_4MB is not set
+# CONFIG_MIPS_AU1000 is not set
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32 is not set
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+CONFIG_CPU_R4X00=y
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+CONFIG_CPU_ADVANCED=y
+# CONFIG_CPU_HAS_LLSC is not set
+# CONFIG_CPU_HAS_LLDSCD is not set
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
+
+#
+# General setup
+#
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+# CONFIG_BUILD_ELF64 is not set
+# CONFIG_BINFMT_IRIX is not set
+CONFIG_NET=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_NEW is not set
+CONFIG_PCI_AUTO=y
+# CONFIG_ISA is not set
+# CONFIG_TC is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+# CONFIG_HOTPLUG_PCI is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_ELF_AOUT is not set
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_MIPS32_O32 is not set
+# CONFIG_MIPS32_N32 is not set
+# CONFIG_BINFMT_ELF32 is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_REDBOOT_PARTS=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_SSTSTD=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+CONFIG_MTD_OBSOLETE_CHIPS=y
+CONFIG_MTD_AMDSTD=y
+# CONFIG_MTD_SHARP is not set
+CONFIG_MTD_JEDEC=y
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0xbe000000
+CONFIG_MTD_PHYSMAP_LEN=200000
+CONFIG_MTD_PHYSMAP_BUSWIDTH=2
+# CONFIG_MTD_PB1000 is not set
+# CONFIG_MTD_PB1500 is not set
+# CONFIG_MTD_PB1100 is not set
+# CONFIG_MTD_BOSPORUS is not set
+# CONFIG_MTD_XXS1500 is not set
+# CONFIG_MTD_MTX1 is not set
+# CONFIG_MTD_DB1X00 is not set
+# CONFIG_MTD_PB1550 is not set
+# CONFIG_MTD_HYDROGEN3 is not set
+# CONFIG_MTD_MIRAGE is not set
+# CONFIG_MTD_CSTM_MIPS_IXX is not set
+# CONFIG_MTD_OCELOT is not set
+# CONFIG_MTD_LASAT is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+# CONFIG_PARPORT_PC is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_IP22 is not set
+# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_1284 is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_CISS_MONITOR_THREAD is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=3072
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS is not set
+
+#
+# MIPS initrd options
+#
+# CONFIG_EMBEDDED_RAMDISK is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK_DEV=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_NAT=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_TOS=y
+# CONFIG_IP_ROUTE_VERBOSE is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+CONFIG_IP_NF_FTP=y
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_IRC=y
+CONFIG_IP_NF_CT_ACCT=m
+CONFIG_IP_NF_MATCH_CONNBYTES=m
+CONFIG_IP_NF_CT_PROTO_GRE=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+CONFIG_IP_NF_RTSP=m
+CONFIG_IP_NF_MMS=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_QUOTA=m
+CONFIG_IP_NF_SET=m
+CONFIG_IP_NF_SET_MAX=256
+CONFIG_IP_NF_SET_HASHSIZE=1024
+CONFIG_IP_NF_MATCH_SET=m
+CONFIG_IP_NF_TARGET_SET=m
+CONFIG_IP_NF_SET_IPMAP=m
+CONFIG_IP_NF_SET_PORTMAP=m
+CONFIG_IP_NF_SET_MACIPMAP=m
+CONFIG_IP_NF_SET_IPHASH=m
+CONFIG_IP_NF_SET_NETHASH=m
+CONFIG_IP_NF_SET_IPTREE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=y
+CONFIG_IP_NF_MATCH_MULTIPORT=y
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_TIME=m
+CONFIG_IP_NF_MATCH_CONDITION=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_IPP2P=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=y
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_UNCLEAN=m
+CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_MIRROR=m
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_PROTO_GRE=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_NAT_RTSP=m
+CONFIG_IP_NF_NAT_MMS=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=y
+CONFIG_IP_NF_NAT_FTP=y
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=y
+CONFIG_IP_NF_TARGET_IMQ=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IPV6=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_CONDITION=m
+CONFIG_IP6_NF_MATCH_MAC=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_AHESP is not set
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_TARGET_IMQ=m
+# CONFIG_KHTTPD is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+CONFIG_VLAN_8021Q=y
+
+#
+#
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+CONFIG_BRIDGE=y
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+CONFIG_WAN_ROUTER=m
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_CSZ=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_POLICE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_IPSEC_NAT_TRAVERSAL=y
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=m
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_IDEDISK_STROKE=y
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_DELKIN is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_BOOT is not set
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_IMQ=m
+CONFIG_TUN=m
+CONFIG_NET_RANDOM=y
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_VENETDEV is not set
+# CONFIG_NET_ATHEROS_ETHER is not set
+CONFIG_MARVELL_ENET_PHY=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE_MPPC=m
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_HERMES is not set
+
+#
+# Prism54 PCI/PCMCIA GT/Duette Driver - 802.11(a/b/g)
+#
+# CONFIG_PRISM54 is not set
+# CONFIG_NET_WIRELESS is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+CONFIG_SHAPER=m
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+CONFIG_HAMRADIO=y
+
+#
+# Packet Radio protocols
+#
+CONFIG_AX25=m
+# CONFIG_AX25_DAMA_SLAVE is not set
+# CONFIG_NETROM is not set
+# CONFIG_ROSE is not set
+
+#
+# AX.25 network device drivers
+#
+
+#
+# AX.25 network device drivers
+#
+CONFIG_MKISS=m
+# CONFIG_6PACK is not set
+# CONFIG_BPQETHER is not set
+# CONFIG_SCC_DELAY is not set
+# CONFIG_SCC_TRXECHO is not set
+# CONFIG_BAYCOM_SER_FDX is not set
+# CONFIG_BAYCOM_SER_HDX is not set
+# CONFIG_BAYCOM_PAR is not set
+# CONFIG_BAYCOM_EPP is not set
+# CONFIG_SOUNDMODEM is not set
+# CONFIG_YAM is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=128
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+CONFIG_PPDEV=m
+# CONFIG_TIPAR is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SCx200_WDT is not set
+CONFIG_SOFT_WATCHDOG=m
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_SCx200 is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+
+#
+# Direct Rendering Manager (XFree86 DRI support)
+#
+# CONFIG_DRM is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_QFMT_V2 is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=m
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_BBC_ARMLIB is not set
+# CONFIG_JFFS2_BBC_LZO is not set
+CONFIG_JFFS2_BBC_LZARI=y
+# CONFIG_JFFS2_BBC_LZHD is not set
+# CONFIG_JFFS2_BBC_LZSS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_MINIX_FS=m
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=m
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_POSIX=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+# CONFIG_SOUND_AD1980 is not set
+# CONFIG_SOUND_WM97XX is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+CONFIG_BLUEZ=m
+CONFIG_BLUEZ_L2CAP=m
+CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_RFCOMM=m
+CONFIG_BLUEZ_RFCOMM_TTY=y
+CONFIG_BLUEZ_BNEP=m
+CONFIG_BLUEZ_BNEP_MC_FILTER=y
+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BLUEZ_HCIUSB is not set
+CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIUART_H4=y
+CONFIG_BLUEZ_HCIUART_BCSP=y
+CONFIG_BLUEZ_HCIUART_BCSP_TXCRC=y
+# CONFIG_BLUEZ_HCIBFUSB is not set
+# CONFIG_BLUEZ_HCIDTL1 is not set
+# CONFIG_BLUEZ_HCIBT3C is not set
+# CONFIG_BLUEZ_HCIBLUECARD is not set
+# CONFIG_BLUEZ_HCIBTUART is not set
+# CONFIG_BLUEZ_HCIVHCI is not set
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_RUNTIME_DEBUG is not set
+# CONFIG_KGDB is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_MIPS_UNCACHED is not set
+CONFIG_LOG_BUF_SHIFT=0
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/target/linux/ar531x-2.4/patches/000-atheros-support.patch b/target/linux/ar531x-2.4/patches/000-atheros-support.patch
new file mode 100644
index 0000000..de7115b
--- /dev/null
+++ b/target/linux/ar531x-2.4/patches/000-atheros-support.patch
@@ -0,0 +1,11411 @@
+diff -urN linux-mips/arch/mips/ar531x/ar531xdbg_io.c mips-linux-2.4.25/arch/mips/ar531x/ar531xdbg_io.c
+--- linux-mips/arch/mips/ar531x/ar531xdbg_io.c 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/arch/mips/ar531x/ar531xdbg_io.c 2005-12-30 17:26:30.606883840 +0000
+@@ -0,0 +1,234 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright MontaVista Software Inc
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * Basic support for polled character input/output
++ * using the AR531X's serial port.
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/serial.h>
++#include <linux/types.h>
++#include <linux/string.h>
++
++#include <asm/reboot.h>
++#include <asm/io.h>
++#include <asm/time.h>
++#include <asm/pgtable.h>
++#include <asm/processor.h>
++#include <asm/reboot.h>
++#include <asm/system.h>
++#include <asm/serial.h>
++#include <asm/gdb-stub.h>
++
++#include "ar531xlnx.h"
++
++#if CONFIG_EARLY_PRINTK_HACK || CONFIG_KGDB
++/* base addr of uart and clock timing */
++#if CONFIG_AR5315
++#define BASE AR5315_UART0
++#else
++#define BASE AR531X_UART0
++#endif
++
++/* distance in bytes between two serial registers */
++#define REG_OFFSET 4
++
++/*
++ * 0 - we need to do serial init
++ * 1 - skip serial init
++ */
++static int serialPortInitialized = 0;
++
++/*
++ * * the default baud rate *if* we do serial init
++ * */
++#define BAUD_DEFAULT UART16550_BAUD_9600
++
++/* === END OF CONFIG === */
++
++#define UART16550_BAUD_2400 2400
++#define UART16550_BAUD_4800 4800
++#define UART16550_BAUD_9600 9600
++#define UART16550_BAUD_19200 19200
++#define UART16550_BAUD_38400 38400
++#define UART16550_BAUD_57600 57600
++#define UART16550_BAUD_115200 115200
++
++#define UART16550_PARITY_NONE 0
++#define UART16550_PARITY_ODD 0x08
++#define UART16550_PARITY_EVEN 0x18
++#define UART16550_PARITY_MARK 0x28
++#define UART16550_PARITY_SPACE 0x38
++
++#define UART16550_DATA_5BIT 0x0
++#define UART16550_DATA_6BIT 0x1
++#define UART16550_DATA_7BIT 0x2
++#define UART16550_DATA_8BIT 0x3
++
++#define UART16550_STOP_1BIT 0x0
++#define UART16550_STOP_2BIT 0x4
++
++/* register offset */
++#define OFS_RCV_BUFFER (0*REG_OFFSET)
++#define OFS_TRANS_HOLD (0*REG_OFFSET)
++#define OFS_SEND_BUFFER (0*REG_OFFSET)
++#define OFS_INTR_ENABLE (1*REG_OFFSET)
++#define OFS_INTR_ID (2*REG_OFFSET)
++#define OFS_DATA_FORMAT (3*REG_OFFSET)
++#define OFS_LINE_CONTROL (3*REG_OFFSET)
++#define OFS_MODEM_CONTROL (4*REG_OFFSET)
++#define OFS_RS232_OUTPUT (4*REG_OFFSET)
++#define OFS_LINE_STATUS (5*REG_OFFSET)
++#define OFS_MODEM_STATUS (6*REG_OFFSET)
++#define OFS_RS232_INPUT (6*REG_OFFSET)
++#define OFS_SCRATCH_PAD (7*REG_OFFSET)
++
++#define OFS_DIVISOR_LSB (0*REG_OFFSET)
++#define OFS_DIVISOR_MSB (1*REG_OFFSET)
++
++
++/* memory-mapped read/write of the port */
++#define UART16550_READ(y) (*((volatile u8*)(BASE + y)))
++#define UART16550_WRITE(y, z) ((*((volatile u8*)(BASE + y))) = z)
++
++void
++debugPortInit(u32 baud, u8 data, u8 parity, u8 stop)
++{
++ /* Pull UART out of reset */
++#if CONFIG_AR5315
++ sysRegWrite(AR5315_RESET,
++ sysRegRead(AR5315_RESET) & ~(RESET_UART0));
++#else
++ sysRegWrite(AR531X_RESET,
++ sysRegRead(AR531X_RESET) & ~(AR531X_RESET_UART0));
++#endif
++
++ /* disable interrupts */
++ UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
++ UART16550_WRITE(OFS_INTR_ENABLE, 0);
++
++ /* set up buad rate */
++ {
++ u32 divisor;
++#if CONFIG_AR5315
++ u32 uart_clock_rate = ar531x_apb_frequency();
++#else
++ u32 uart_clock_rate = ar531x_cpu_frequency() / 4;
++#endif
++ u32 base_baud = uart_clock_rate / 16;
++
++ /* set DIAB bit */
++ UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
++
++ /* set divisor */
++ divisor = base_baud / baud;
++ UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
++ UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00)>>8);
++
++ /* clear DIAB bit */
++ UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
++ }
++
++ /* set data format */
++ UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
++}
++
++u8
++getDebugChar(void)
++{
++ if (!serialPortInitialized) {
++ serialPortInitialized = 1;
++ debugPortInit(BAUD_DEFAULT,
++ UART16550_DATA_8BIT,
++ UART16550_PARITY_NONE, UART16550_STOP_1BIT);
++ }
++
++ while((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
++ return UART16550_READ(OFS_RCV_BUFFER);
++}
++
++#if CONFIG_KGDB
++/*
++ * Peek at the most recently received character.
++ * Don't wait for a new character to be received.
++ */
++u8
++peekDebugChar(void)
++{
++ return UART16550_READ(OFS_RCV_BUFFER);
++}
++
++static int kgdbInitialized = 0;
++
++void
++kgdbInit(void)
++{
++#if CONFIG_AR5315
++ sysRegWrite(AR5315_WDC, WDC_IGNORE_EXPIRATION);
++#else
++ sysRegWrite(AR531X_WD_CTRL, AR531X_WD_CTRL_IGNORE_EXPIRATION);
++#endif
++
++ if (!kgdbInitialized) {
++ printk("Setting debug traps - please connect the remote debugger.\n");
++ set_debug_traps();
++ kgdbInitialized = 1;
++ }
++ breakpoint();
++}
++
++int
++kgdbEnabled(void)
++{
++ return kgdbInitialized;
++}
++
++#define DEBUG_CHAR '\001';
++
++int
++kgdbInterrupt(void)
++{
++ if (!kgdbInitialized) {
++ return 0;
++ }
++
++ /*
++ * Try to avoid swallowing too much input: Only consume
++ * a character if nothing new has arrived. Yes, there's
++ * still a small hole here, and we may lose an input
++ * character now and then.
++ */
++ if (UART16550_READ(OFS_LINE_STATUS) & 1) {
++ return 0;
++ } else {
++ return UART16550_READ(OFS_RCV_BUFFER) == DEBUG_CHAR;
++ }
++}
++#endif
++
++
++void
++putDebugChar(char byte)
++{
++ if (!serialPortInitialized) {
++ serialPortInitialized = 1;
++ debugPortInit(BAUD_DEFAULT,
++ UART16550_DATA_8BIT,
++ UART16550_PARITY_NONE, UART16550_STOP_1BIT);
++ }
++
++ while ((UART16550_READ(OFS_LINE_STATUS) &0x20) == 0);
++ UART16550_WRITE(OFS_SEND_BUFFER, byte);
++ }
++#endif /* CONFIG_EARLY_PRINTK_HACK || CONFIG_KGDB */
+diff -urN linux-mips/arch/mips/ar531x/ar531xgpio.c mips-linux-2.4.25/arch/mips/ar531x/ar531xgpio.c
+--- linux-mips/arch/mips/ar531x/ar531xgpio.c 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/arch/mips/ar531x/ar531xgpio.c 2005-12-30 17:26:30.606883840 +0000
+@@ -0,0 +1,147 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * Support for GPIO -- General Purpose Input/Output Pins
++ */
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/signal.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++
++#include "ar531xlnx.h"
++
++/* GPIO Interrupt Support */
++
++/* Turn on the specified AR531X_GPIO_IRQ interrupt */
++static unsigned int
++ar531x_gpio_intr_startup(unsigned int irq)
++{
++ ar531x_gpio_intr_enable(irq);
++ return 0;
++}
++
++/* Turn off the specified AR531X_GPIO_IRQ interrupt */
++static void
++ar531x_gpio_intr_shutdown(unsigned int irq)
++{
++ ar531x_gpio_intr_disable(irq);
++}
++
++u32 gpioIntMask = 0;
++
++/* Enable the specified AR531X_GPIO_IRQ interrupt */
++void
++ar531x_gpio_intr_enable(unsigned int irq)
++{
++ u32 reg;
++ int gpio;
++
++#ifndef CONFIG_AR5315
++ gpio = irq - AR531X_GPIO_IRQ_BASE;
++ gpioIntMask |= gpio;
++
++ reg = sysRegRead(AR531X_GPIO_CR);
++ reg &= ~(GPIO_CR_M(gpio) | GPIO_CR_UART(gpio) | GPIO_CR_INT(gpio));
++ reg |= GPIO_CR_I(gpio);
++ reg |= GPIO_CR_INT(gpio);
++
++ sysRegWrite(AR531X_GPIO_CR, reg);
++ (void)sysRegRead(AR531X_GPIO_CR); /* flush to hardware */
++#endif
++}
++
++/* Disable the specified AR531X_GPIO_IRQ interrupt */
++void
++ar531x_gpio_intr_disable(unsigned int irq)
++{
++ u32 reg;
++ int gpio;
++
++#ifndef CONFIG_AR5315
++ gpio = irq - AR531X_GPIO_IRQ_BASE;
++ reg = sysRegRead(AR531X_GPIO_CR);
++ reg &= ~(GPIO_CR_M(gpio) | GPIO_CR_UART(gpio) | GPIO_CR_INT(gpio));
++ reg |= GPIO_CR_I(gpio);
++ /* No GPIO_CR_INT bit */
++
++ sysRegWrite(AR531X_GPIO_CR, reg);
++ (void)sysRegRead(AR531X_GPIO_CR); /* flush to hardware */
++
++ gpioIntMask &= ~gpio;
++#endif
++}
++
++static void
++ar531x_gpio_intr_ack(unsigned int irq)
++{
++ ar531x_gpio_intr_disable(irq);
++}
++
++static void
++ar531x_gpio_intr_end(unsigned int irq)
++{
++ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
++ ar531x_gpio_intr_enable(irq);
++}
++
++static void
++ar531x_gpio_intr_set_affinity(unsigned int irq, unsigned long mask)
++{
++ /* Only 1 CPU; ignore affinity request */
++}
++
++int ar531x_gpio_irq_base;
++
++struct hw_interrupt_type ar531x_gpio_intr_controller = {
++ "AR531X GPIO",
++ ar531x_gpio_intr_startup,
++ ar531x_gpio_intr_shutdown,
++ ar531x_gpio_intr_enable,
++ ar531x_gpio_intr_disable,
++ ar531x_gpio_intr_ack,
++ ar531x_gpio_intr_end,
++ ar531x_gpio_intr_set_affinity,
++};
++
++void
++ar531x_gpio_intr_init(int irq_base)
++{
++ int i;
++
++ for (i = irq_base; i < irq_base + AR531X_GPIO_IRQ_COUNT; i++) {
++ irq_desc[i].status = IRQ_DISABLED;
++ irq_desc[i].action = NULL;
++ irq_desc[i].depth = 1;
++ irq_desc[i].handler = &ar531x_gpio_intr_controller;
++ }
++
++ ar531x_gpio_irq_base = irq_base;
++}
++
++/* ARGSUSED */
++void
++spurious_gpio_handler(int cpl, void *dev_id, struct pt_regs *regs)
++{
++ u32 gpioDataIn;
++#if CONFIG_AR5315
++ gpioDataIn = sysRegRead(AR5315_GPIO_DI) & gpioIntMask;
++#else
++ gpioDataIn = sysRegRead(AR531X_GPIO_DI) & gpioIntMask;
++#endif
++
++ printk("spurious_gpio_handler: 0x%x di=0x%8.8x gpioIntMask=0x%8.8x\n",
++ cpl, gpioDataIn, gpioIntMask);
++}
++
++struct irqaction spurious_gpio =
++ {spurious_gpio_handler, SA_INTERRUPT, 0, "spurious_gpio",
++ NULL, NULL};
++
+diff -urN linux-mips/arch/mips/ar531x/ar531x.h mips-linux-2.4.25/arch/mips/ar531x/ar531x.h
+--- linux-mips/arch/mips/ar531x/ar531x.h 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/arch/mips/ar531x/ar531x.h 2005-12-30 17:26:30.605883992 +0000
+@@ -0,0 +1,1018 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++#ifndef AR531X_H
++#define AR531X_H 1
++
++#ifndef CONFIG_AR5315
++
++#include <asm/addrspace.h>
++
++/* Address Map */
++#define AR531X_WLAN0 0x18000000
++#define AR531X_WLAN1 0x18500000
++#define AR531X_ENET0 0x18100000
++#define AR531X_ENET1 0x18200000
++#define AR531X_SDRAMCTL 0x18300000
++#define AR531X_FLASHCTL 0x18400000
++#define AR531X_APBBASE 0x1c000000
++#define AR531X_FLASH 0x1e000000
++#define AR531X_UART0 0xbc000003 /* UART MMR */
++
++/*
++ * AR531X_NUM_ENET_MAC defines the number of ethernet MACs that
++ * should be considered available. The AR5312 supports 2 enet MACS,
++ * even though many reference boards only actually use 1 of them
++ * (i.e. Only MAC 0 is actually connected to an enet PHY or PHY switch.
++ * The AR2312 supports 1 enet MAC.
++ */
++#define AR531X_NUM_ENET_MAC 2
++
++/*
++ * Need these defines to determine true number of ethernet MACs
++ */
++#define AR5212_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */
++#define AR5212_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */
++#define AR5212_AR2313_REV8 0x0058 /* AR2313 WMAC (AP43-030) */
++#define AR531X_RADIO_MASK_OFF 0xc8
++#define AR531X_RADIO0_MASK 0x0003
++#define AR531X_RADIO1_MASK 0x000c
++#define AR531X_RADIO1_S 2
++
++/*
++ * AR531X_NUM_WMAC defines the number of Wireless MACs that\
++ * should be considered available.
++ */
++#define AR531X_NUM_WMAC 2
++
++/* Reset/Timer Block Address Map */
++#define AR531X_RESETTMR (AR531X_APBBASE + 0x3000)
++#define AR531X_TIMER (AR531X_RESETTMR + 0x0000) /* countdown timer */
++#define AR531X_WD_CTRL (AR531X_RESETTMR + 0x0008) /* watchdog cntrl */
++#define AR531X_WD_TIMER (AR531X_RESETTMR + 0x000c) /* watchdog timer */
++#define AR531X_ISR (AR531X_RESETTMR + 0x0010) /* Intr Status Reg */
++#define AR531X_IMR (AR531X_RESETTMR + 0x0014) /* Intr Mask Reg */
++#define AR531X_RESET (AR531X_RESETTMR + 0x0020)
++#define AR5312_CLOCKCTL1 (AR531X_RESETTMR + 0x0064)
++#define AR5312_SCRATCH (AR531X_RESETTMR + 0x006c)
++#define AR531X_PROCADDR (AR531X_RESETTMR + 0x0070)
++#define AR531X_PROC1 (AR531X_RESETTMR + 0x0074)
++#define AR531X_DMAADDR (AR531X_RESETTMR + 0x0078)
++#define AR531X_DMA1 (AR531X_RESETTMR + 0x007c)
++#define AR531X_ENABLE (AR531X_RESETTMR + 0x0080) /* interface enb */
++#define AR531X_REV (AR531X_RESETTMR + 0x0090) /* revision */
++
++/* AR531X_WD_CTRL register bit field definitions */
++#define AR531X_WD_CTRL_IGNORE_EXPIRATION 0x0000
++#define AR531X_WD_CTRL_NMI 0x0001
++#define AR531X_WD_CTRL_RESET 0x0002
++
++/* AR531X_ISR register bit field definitions */
++#define AR531X_ISR_NONE 0x0000
++#define AR531X_ISR_TIMER 0x0001
++#define AR531X_ISR_AHBPROC 0x0002
++#define AR531X_ISR_AHBDMA 0x0004
++#define AR531X_ISR_GPIO 0x0008
++#define AR531X_ISR_UART0 0x0010
++#define AR531X_ISR_UART0DMA 0x0020
++#define AR531X_ISR_WD 0x0040
++#define AR531X_ISR_LOCAL 0x0080
++
++/* AR531X_RESET register bit field definitions */
++#define AR531X_RESET_SYSTEM 0x00000001 /* cold reset full system */
++#define AR531X_RESET_PROC 0x00000002 /* cold reset MIPS core */
++#define AR531X_RESET_WLAN0 0x00000004 /* cold reset WLAN MAC and BB */
++#define AR531X_RESET_EPHY0 0x00000008 /* cold reset ENET0 phy */
++#define AR531X_RESET_EPHY1 0x00000010 /* cold reset ENET1 phy */
++#define AR531X_RESET_ENET0 0x00000020 /* cold reset ENET0 mac */
++#define AR531X_RESET_ENET1 0x00000040 /* cold reset ENET1 mac */
++#define AR531X_RESET_UART0 0x00000100 /* cold reset UART0 (high speed) */
++#define AR531X_RESET_WLAN1 0x00000200 /* cold reset WLAN MAC/BB */
++#define AR531X_RESET_APB 0x00000400 /* cold reset APB (ar5312) */
++#define AR531X_RESET_WARM_PROC 0x00001000 /* warm reset MIPS core */
++#define AR531X_RESET_WARM_WLAN0_MAC 0x00002000 /* warm reset WLAN0 MAC */
++#define AR531X_RESET_WARM_WLAN0_BB 0x00004000 /* warm reset WLAN0 BaseBand */
++#define AR531X_RESET_NMI 0x00010000 /* send an NMI to the processor */
++#define AR531X_RESET_WARM_WLAN1_MAC 0x00020000 /* warm reset WLAN1 mac */
++#define AR531X_RESET_WARM_WLAN1_BB 0x00040000 /* warm reset WLAN1 baseband */
++#define AR531X_RESET_LOCAL_BUS 0x00080000 /* reset local bus */
++#define AR531X_RESET_WDOG 0x00100000 /* last reset was a watchdog */
++
++#define AR531X_RESET_WMAC0_BITS \
++ AR531X_RESET_WLAN0 |\
++ AR531X_RESET_WARM_WLAN0_MAC |\
++ AR531X_RESET_WARM_WLAN0_BB
++
++#define AR531X_RESERT_WMAC1_BITS \
++ AR531X_RESET_WLAN1 |\
++ AR531X_RESET_WARM_WLAN1_MAC |\
++ AR531X_RESET_WARM_WLAN1_BB
++
++/* AR5312_CLOCKCTL1 register bit field definitions */
++#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030
++#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4
++#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00
++#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8
++#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000
++
++/* Valid for AR5312 and AR2312 */
++#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030
++#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4
++#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00
++#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8
++#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000
++
++/* Valid for AR2313 */
++#define AR2313_CLOCKCTL1_PREDIVIDE_MASK 0x00003000
++#define AR2313_CLOCKCTL1_PREDIVIDE_SHIFT 12
++#define AR2313_CLOCKCTL1_MULTIPLIER_MASK 0x001f0000
++#define AR2313_CLOCKCTL1_MULTIPLIER_SHIFT 16
++#define AR2313_CLOCKCTL1_DOUBLER_MASK 0x00000000
++
++
++/* AR531X_ENABLE register bit field definitions */
++#define AR531X_ENABLE_WLAN0 0x0001
++#define AR531X_ENABLE_ENET0 0x0002
++#define AR531X_ENABLE_ENET1 0x0004
++#define AR531X_ENABLE_UART_AND_WLAN1_PIO 0x0008 /* UART, and WLAN1 PIOs */
++#define AR531X_ENABLE_WLAN1_DMA 0x0010 /* WLAN1 DMAs */
++#define AR531X_ENABLE_WLAN1 \
++ (AR531X_ENABLE_UART_AND_WLAN1_PIO | AR531X_ENABLE_WLAN1_DMA)
++
++/* AR531X_REV register bit field definitions */
++#define AR531X_REV_WMAC_MAJ 0xf000
++#define AR531X_REV_WMAC_MAJ_S 12
++#define AR531X_REV_WMAC_MIN 0x0f00
++#define AR531X_REV_WMAC_MIN_S 8
++#define AR531X_REV_MAJ 0x00f0
++#define AR531X_REV_MAJ_S 4
++#define AR531X_REV_MIN 0x000f
++#define AR531X_REV_MIN_S 0
++#define AR531X_REV_CHIP (REV_MAJ|REV_MIN)
++
++/* Major revision numbers, bits 7..4 of Revision ID register */
++#define AR531X_REV_MAJ_AR5312 0x4
++#define AR531X_REV_MAJ_AR2313 0x5
++
++/* Minor revision numbers, bits 3..0 of Revision ID register */
++#define AR5312_REV_MIN_DUAL 0x0 /* Dual WLAN version */
++#define AR5312_REV_MIN_SINGLE 0x1 /* Single WLAN version */
++
++/* AR531X_FLASHCTL register bit field definitions */
++#define FLASHCTL_IDCY 0x0000000f /* Idle cycle turn around time */
++#define FLASHCTL_IDCY_S 0
++#define FLASHCTL_WST1 0x000003e0 /* Wait state 1 */
++#define FLASHCTL_WST1_S 5
++#define FLASHCTL_RBLE 0x00000400 /* Read byte lane enable */
++#define FLASHCTL_WST2 0x0000f800 /* Wait state 2 */
++#define FLASHCTL_WST2_S 11
++#define FLASHCTL_AC 0x00070000 /* Flash address check (added) */
++#define FLASHCTL_AC_S 16
++#define FLASHCTL_AC_128K 0x00000000
++#define FLASHCTL_AC_256K 0x00010000
++#define FLASHCTL_AC_512K 0x00020000
++#define FLASHCTL_AC_1M 0x00030000
++#define FLASHCTL_AC_2M 0x00040000
++#define FLASHCTL_AC_4M 0x00050000
++#define FLASHCTL_AC_8M 0x00060000
++#define FLASHCTL_AC_RES 0x00070000 /* 16MB is not supported */
++#define FLASHCTL_E 0x00080000 /* Flash bank enable (added) */
++#define FLASHCTL_BUSERR 0x01000000 /* Bus transfer error status flag */
++#define FLASHCTL_WPERR 0x02000000 /* Write protect error status flag */
++#define FLASHCTL_WP 0x04000000 /* Write protect */
++#define FLASHCTL_BM 0x08000000 /* Burst mode */
++#define FLASHCTL_MW 0x30000000 /* Memory width */
++#define FLASHCTL_MWx8 0x00000000 /* Memory width x8 */
++#define FLASHCTL_MWx16 0x10000000 /* Memory width x16 */
++#define FLASHCTL_MWx32 0x20000000 /* Memory width x32 (not supported) */
++#define FLASHCTL_ATNR 0x00000000 /* Access type == no retry */
++#define FLASHCTL_ATR 0x80000000 /* Access type == retry every */
++#define FLASHCTL_ATR4 0xc0000000 /* Access type == retry every 4 */
++
++/* ARM Flash Controller -- 3 flash banks with either x8 or x16 devices. */
++#define AR531X_FLASHCTL0 (AR531X_FLASHCTL + 0x00)
++#define AR531X_FLASHCTL1 (AR531X_FLASHCTL + 0x04)
++#define AR531X_FLASHCTL2 (AR531X_FLASHCTL + 0x08)
++
++/* ARM SDRAM Controller -- just enough to determine memory size */
++#define AR531X_MEM_CFG1 (AR531X_SDRAMCTL + 0x04)
++#define MEM_CFG1_AC0 0x00000700 /* bank 0: SDRAM addr check (added) */
++#define MEM_CFG1_AC0_S 8
++#define MEM_CFG1_AC1 0x00007000 /* bank 1: SDRAM addr check (added) */
++#define MEM_CFG1_AC1_S 12
++
++/* GPIO Address Map */
++#define AR531X_GPIO (AR531X_APBBASE + 0x2000)
++#define AR531X_GPIO_DO (AR531X_GPIO + 0x00) /* output register */
++#define AR531X_GPIO_DI (AR531X_GPIO + 0x04) /* intput register */
++#define AR531X_GPIO_CR (AR531X_GPIO + 0x08) /* control register */
++
++/* GPIO Control Register bit field definitions */
++#define GPIO_CR_M(x) (1 << (x)) /* mask for i/o */
++#define GPIO_CR_O(x) (0 << (x)) /* mask for output */
++#define GPIO_CR_I(x) (1 << (x)) /* mask for input */
++#define GPIO_CR_INT(x) (1 << ((x)+8)) /* mask for interrupt */
++#define GPIO_CR_UART(x) (1 << ((x)+16)) /* uart multiplex */
++
++
++typedef unsigned int AR531X_REG;
++
++#define sysRegRead(phys) \
++ (*(volatile AR531X_REG *)PHYS_TO_K1(phys))
++
++#define sysRegWrite(phys, val) \
++ ((*(volatile AR531X_REG *)PHYS_TO_K1(phys)) = (val))
++
++
++/*
++ * This is board-specific data that is stored in a "fixed" location in flash.
++ * It is shared across operating systems, so it should not be changed lightly.
++ * The main reason we need it is in order to extract the ethernet MAC
++ * address(es).
++ */
++struct ar531x_boarddata {
++ u32 magic; /* board data is valid */
++#define AR531X_BD_MAGIC 0x35333131 /* "5311", for all 531x platforms */
++ u16 cksum; /* checksum (starting with BD_REV 2) */
++ u16 rev; /* revision of this struct */
++#define BD_REV 4
++ char boardName[64]; /* Name of board */
++ u16 major; /* Board major number */
++ u16 minor; /* Board minor number */
++ u32 config; /* Board configuration */
++#define BD_ENET0 0x00000001 /* ENET0 is stuffed */
++#define BD_ENET1 0x00000002 /* ENET1 is stuffed */
++#define BD_UART1 0x00000004 /* UART1 is stuffed */
++#define BD_UART0 0x00000008 /* UART0 is stuffed (dma) */
++#define BD_RSTFACTORY 0x00000010 /* Reset factory defaults stuffed */
++#define BD_SYSLED 0x00000020 /* System LED stuffed */
++#define BD_EXTUARTCLK 0x00000040 /* External UART clock */
++#define BD_CPUFREQ 0x00000080 /* cpu freq is valid in nvram */
++#define BD_SYSFREQ 0x00000100 /* sys freq is set in nvram */
++#define BD_WLAN0 0x00000200 /* Enable WLAN0 */
++#define BD_MEMCAP 0x00000400 /* CAP SDRAM @ memCap for testing */
++#define BD_DISWATCHDOG 0x00000800 /* disable system watchdog */
++#define BD_WLAN1 0x00001000 /* Enable WLAN1 (ar5212) */
++#define BD_ISCASPER 0x00002000 /* FLAG for AR2312 */
++#define BD_WLAN0_2G_EN 0x00004000 /* FLAG for radio0_2G */
++#define BD_WLAN0_5G_EN 0x00008000 /* FLAG for radio0_2G */
++#define BD_WLAN1_2G_EN 0x00020000 /* FLAG for radio0_2G */
++#define BD_WLAN1_5G_EN 0x00040000 /* FLAG for radio0_2G */
++ u16 resetConfigGpio; /* Reset factory GPIO pin */
++ u16 sysLedGpio; /* System LED GPIO pin */
++
++ u32 cpuFreq; /* CPU core frequency in Hz */
++ u32 sysFreq; /* System frequency in Hz */
++ u32 cntFreq; /* Calculated C0_COUNT frequency */
++
++ u8 wlan0Mac[6];
++ u8 enet0Mac[6];
++ u8 enet1Mac[6];
++
++ u16 pciId; /* Pseudo PCIID for common code */
++ u16 memCap; /* cap bank1 in MB */
++
++ /* version 3 */
++ u8 wlan1Mac[6]; /* (ar5212) */
++};
++
++#else
++
++/*
++ * Address map
++ */
++#define AR5315_SDRAM0 0x00000000 /* DRAM */
++#define AR5315_SPI_READ 0x08000000 /* SPI FLASH */
++#define AR5315_WLAN0 0xB0000000 /* Wireless MMR */
++#define AR5315_PCI 0xB0100000 /* PCI MMR */
++#define AR5315_SDRAMCTL 0xB0300000 /* SDRAM MMR */
++#define AR5315_LOCAL 0xB0400000 /* LOCAL BUS MMR */
++#define AR5315_ENET0 0xB0500000 /* ETHERNET MMR */
++#define AR5315_DSLBASE 0xB1000000 /* RESET CONTROL MMR */
++#define AR5315_UART0 0xB1100003 /* UART MMR */
++#define AR5315_SPI 0xB1300000 /* SPI FLASH MMR */
++#define AR5315_FLASHBT 0xBfc00000 /* ro boot alias to FLASH */
++#define AR5315_RAM1 0x40000000 /* ram alias */
++#define AR5315_PCIEXT 0x80000000 /* pci external */
++#define AR5315_RAM2 0xc0000000 /* ram alias */
++#define AR5315_RAM3 0xe0000000 /* ram alias */
++
++/*
++ * Reset Register
++ */
++#define AR5315_COLD_RESET (AR5315_DSLBASE + 0x0000)
++
++/* Cold Reset */
++#define RESET_COLD_AHB 0x00000001
++#define RESET_COLD_APB 0x00000002
++#define RESET_COLD_CPU 0x00000004
++#define RESET_COLD_CPUWARM 0x00000008
++#define RESET_SYSTEM (RESET_COLD_CPU | RESET_COLD_APB | RESET_COLD_AHB) /* full system */
++
++/* Warm Reset */
++
++#define AR5315_RESET (AR5315_DSLBASE + 0x0004)
++
++#define RESET_WARM_WLAN0_MAC 0x00000001 /* warm reset WLAN0 MAC */
++#define RESET_WARM_WLAN0_BB 0x00000002 /* warm reset WLAN0 BaseBand */
++#define RESET_MPEGTS_RSVD 0x00000004 /* warm reset MPEG-TS */
++#define RESET_PCIDMA 0x00000008 /* warm reset PCI ahb/dma */
++#define RESET_MEMCTL 0x00000010 /* warm reset memory controller */
++#define RESET_LOCAL 0x00000020 /* warm reset local bus */
++#define RESET_I2C_RSVD 0x00000040 /* warm reset I2C bus */
++#define RESET_SPI 0x00000080 /* warm reset SPI interface */
++#define RESET_UART0 0x00000100 /* warm reset UART0 */
++#define RESET_IR_RSVD 0x00000200 /* warm reset IR interface */
++#define RESET_EPHY0 0x00000400 /* cold reset ENET0 phy */
++#define RESET_ENET0 0x00000800 /* cold reset ENET0 mac */
++
++/*
++ * AHB master arbitration control
++ */
++#define AR5315_AHB_ARB_CTL (AR5315_DSLBASE + 0x0008)
++
++#define ARB_CPU 0x00000001 /* CPU, default */
++#define ARB_WLAN 0x00000002 /* WLAN */
++#define ARB_MPEGTS_RSVD 0x00000004 /* MPEG-TS */
++#define ARB_LOCAL 0x00000008 /* LOCAL */
++#define ARB_PCI 0x00000010 /* PCI */
++#define ARB_ETHERNET 0x00000020 /* Ethernet */
++#define ARB_RETRY 0x00000100 /* retry policy, debug only */
++
++/*
++ * Config Register
++ */
++#define AR5315_ENDIAN_CTL (AR5315_DSLBASE + 0x000c)
++
++#define CONFIG_AHB 0x00000001 /* EC - AHB bridge endianess */
++#define CONFIG_WLAN 0x00000002 /* WLAN byteswap */
++#define CONFIG_MPEGTS_RSVD 0x00000004 /* MPEG-TS byteswap */
++#define CONFIG_PCI 0x00000008 /* PCI byteswap */
++#define CONFIG_MEMCTL 0x00000010 /* Memory controller endianess */
++#define CONFIG_LOCAL 0x00000020 /* Local bus byteswap */
++#define CONFIG_ETHERNET 0x00000040 /* Ethernet byteswap */
++
++#define CONFIG_MERGE 0x00000200 /* CPU write buffer merge */
++#define CONFIG_CPU 0x00000400 /* CPU big endian */
++#define CONFIG_PCIAHB 0x00000800
++#define CONFIG_PCIAHB_BRIDGE 0x00001000
++#define CONFIG_SPI 0x00008000 /* SPI byteswap */
++#define CONFIG_CPU_DRAM 0x00010000
++#define CONFIG_CPU_PCI 0x00020000
++#define CONFIG_CPU_MMR 0x00040000
++#define CONFIG_BIG 0x00000400
++
++
++/*
++ * NMI control
++ */
++#define AR5315_NMI_CTL (AR5315_DSLBASE + 0x0010)
++
++#define NMI_EN 1
++
++/*
++ * Revision Register - Initial value is 0x3010 (WMAC 3.0, AR531X 1.0).
++ */
++#define AR5315_SREV (AR5315_DSLBASE + 0x0014)
++
++#define REV_MAJ 0x00f0
++#define REV_MAJ_S 4
++#define REV_MIN 0x000f
++#define REV_MIN_S 0
++#define REV_CHIP (REV_MAJ|REV_MIN)
++
++/*
++ * Interface Enable
++ */
++#define AR5315_IF_CTL (AR5315_DSLBASE + 0x0018)
++
++#define IF_MASK 0x00000007
++#define IF_DISABLED 0
++#define IF_PCI 1
++#define IF_TS_LOCAL 2
++#define IF_ALL 3 /* only for emulation with separate pins */
++#define IF_LOCAL_HOST 0x00000008
++#define IF_PCI_HOST 0x00000010
++#define IF_PCI_INTR 0x00000020
++#define IF_PCI_CLK_MASK 0x00030000
++#define IF_PCI_CLK_INPUT 0
++#define IF_PCI_CLK_OUTPUT_LOW 1
++#define IF_PCI_CLK_OUTPUT_CLK 2
++#define IF_PCI_CLK_OUTPUT_HIGH 3
++#define IF_PCI_CLK_SHIFT 16
++
++
++/* Major revision numbers, bits 7..4 of Revision ID register */
++#define REV_MAJ_AR5311 0x01
++#define REV_MAJ_AR5312 0x04
++#define REV_MAJ_AR5315 0x0B
++
++/*
++ * APB Interrupt control
++ */
++
++#define AR5315_ISR (AR5315_DSLBASE + 0x0020)
++#define AR5315_IMR (AR5315_DSLBASE + 0x0024)
++#define AR5315_GISR (AR5315_DSLBASE + 0x0028)
++
++#define ISR_UART0 0x0001 /* high speed UART */
++#define ISR_I2C_RSVD 0x0002 /* I2C bus */
++#define ISR_SPI 0x0004 /* SPI bus */
++#define ISR_AHB 0x0008 /* AHB error */
++#define ISR_APB 0x0010 /* APB error */
++#define ISR_TIMER 0x0020 /* timer */
++#define ISR_GPIO 0x0040 /* GPIO */
++#define ISR_WD 0x0080 /* watchdog */
++#define ISR_IR_RSVD 0x0100 /* IR */
++
++#define IMR_UART0 ISR_UART0
++#define IMR_I2C_RSVD ISR_I2C_RSVD
++#define IMR_SPI ISR_SPI
++#define IMR_AHB ISR_AHB
++#define IMR_APB ISR_APB
++#define IMR_TIMER ISR_TIMER
++#define IMR_GPIO ISR_GPIO
++#define IMR_WD ISR_WD
++#define IMR_IR_RSVD ISR_IR_RSVD
++
++#define GISR_MISC 0x0001
++#define GISR_WLAN0 0x0002
++#define GISR_MPEGTS_RSVD 0x0004
++#define GISR_LOCALPCI 0x0008
++#define GISR_WMACPOLL 0x0010
++#define GISR_TIMER 0x0020
++#define GISR_ETHERNET 0x0040
++
++/*
++ * Interrupt routing from IO to the processor IP bits
++ * Define our inter mask and level
++ */
++#define AR5315_INTR_MISCIO SR_IBIT3
++#define AR5315_INTR_WLAN0 SR_IBIT4
++#define AR5315_INTR_ENET0 SR_IBIT5
++#define AR5315_INTR_LOCALPCI SR_IBIT6
++#define AR5315_INTR_WMACPOLL SR_IBIT7
++#define AR5315_INTR_COMPARE SR_IBIT8
++
++/*
++ * Timers
++ */
++#define AR5315_TIMER (AR5315_DSLBASE + 0x0030)
++#define AR5315_RELOAD (AR5315_DSLBASE + 0x0034)
++#define AR5315_WD (AR5315_DSLBASE + 0x0038)
++#define AR5315_WDC (AR5315_DSLBASE + 0x003c)
++
++#define WDC_RESET 0x00000002 /* reset on watchdog */
++#define WDC_NMI 0x00000001 /* NMI on watchdog */
++#define WDC_IGNORE_EXPIRATION 0x00000000
++
++/*
++ * Interface Debug
++ */
++#define AR531X_FLASHDBG (AR531X_RESETTMR + 0x0040)
++#define AR531X_MIIDBG (AR531X_RESETTMR + 0x0044)
++
++
++/*
++ * CPU Performance Counters
++ */
++#define AR5315_PERFCNT0 (AR5315_DSLBASE + 0x0048)
++#define AR5315_PERFCNT1 (AR5315_DSLBASE + 0x004c)
++
++#define PERF_DATAHIT 0x0001 /* Count Data Cache Hits */
++#define PERF_DATAMISS 0x0002 /* Count Data Cache Misses */
++#define PERF_INSTHIT 0x0004 /* Count Instruction Cache Hits */
++#define PERF_INSTMISS 0x0008 /* Count Instruction Cache Misses */
++#define PERF_ACTIVE 0x0010 /* Count Active Processor Cycles */
++#define PERF_WBHIT 0x0020 /* Count CPU Write Buffer Hits */
++#define PERF_WBMISS 0x0040 /* Count CPU Write Buffer Misses */
++
++#define PERF_EB_ARDY 0x0001 /* Count EB_ARdy signal */
++#define PERF_EB_AVALID 0x0002 /* Count EB_AValid signal */
++#define PERF_EB_WDRDY 0x0004 /* Count EB_WDRdy signal */
++#define PERF_EB_RDVAL 0x0008 /* Count EB_RdVal signal */
++#define PERF_VRADDR 0x0010 /* Count valid read address cycles */
++#define PERF_VWADDR 0x0020 /* Count valid write address cycles */
++#define PERF_VWDATA 0x0040 /* Count valid write data cycles */
++
++/*
++ * AHB Error Reporting.
++ */
++#define AR5315_AHB_ERR0 (AR5315_DSLBASE + 0x0050) /* error */
++#define AR5315_AHB_ERR1 (AR5315_DSLBASE + 0x0054) /* haddr */
++#define AR5315_AHB_ERR2 (AR5315_DSLBASE + 0x0058) /* hwdata */
++#define AR5315_AHB_ERR3 (AR5315_DSLBASE + 0x005c) /* hrdata */
++#define AR5315_AHB_ERR4 (AR5315_DSLBASE + 0x0060) /* status */
++
++#define AHB_ERROR_DET 1 /* AHB Error has been detected, */
++ /* write 1 to clear all bits in ERR0 */
++#define AHB_ERROR_OVR 2 /* AHB Error overflow has been detected */
++#define AHB_ERROR_WDT 4 /* AHB Error due to wdt instead of hresp */
++
++#define PROCERR_HMAST 0x0000000f
++#define PROCERR_HMAST_DFLT 0
++#define PROCERR_HMAST_WMAC 1
++#define PROCERR_HMAST_ENET 2
++#define PROCERR_HMAST_PCIENDPT 3
++#define PROCERR_HMAST_LOCAL 4
++#define PROCERR_HMAST_CPU 5
++#define PROCERR_HMAST_PCITGT 6
++
++#define PROCERR_HMAST_S 0
++#define PROCERR_HWRITE 0x00000010
++#define PROCERR_HSIZE 0x00000060
++#define PROCERR_HSIZE_S 5
++#define PROCERR_HTRANS 0x00000180
++#define PROCERR_HTRANS_S 7
++#define PROCERR_HBURST 0x00000e00
++#define PROCERR_HBURST_S 9
++
++
++
++/*
++ * Clock Control
++ */
++#define AR5315_PLLC_CTL (AR5315_DSLBASE + 0x0064)
++#define AR5315_PLLV_CTL (AR5315_DSLBASE + 0x0068)
++#define AR5315_CPUCLK (AR5315_DSLBASE + 0x006c)
++#define AR5315_AMBACLK (AR5315_DSLBASE + 0x0070)
++#define AR5315_SYNCCLK (AR5315_DSLBASE + 0x0074)
++#define AR5315_DSL_SLEEP_CTL (AR5315_DSLBASE + 0x0080)
++#define AR5315_DSL_SLEEP_DUR (AR5315_DSLBASE + 0x0084)
++
++/* PLLc Control fields */
++#define PLLC_REF_DIV_M 0x00000003
++#define PLLC_REF_DIV_S 0
++#define PLLC_FDBACK_DIV_M 0x0000007C
++#define PLLC_FDBACK_DIV_S 2
++#define PLLC_ADD_FDBACK_DIV_M 0x00000080
++#define PLLC_ADD_FDBACK_DIV_S 7
++#define PLLC_CLKC_DIV_M 0x0001c000
++#define PLLC_CLKC_DIV_S 14
++#define PLLC_CLKM_DIV_M 0x00700000
++#define PLLC_CLKM_DIV_S 20
++
++/* CPU CLK Control fields */
++#define CPUCLK_CLK_SEL_M 0x00000003
++#define CPUCLK_CLK_SEL_S 0
++#define CPUCLK_CLK_DIV_M 0x0000000c
++#define CPUCLK_CLK_DIV_S 2
++
++/* AMBA CLK Control fields */
++#define AMBACLK_CLK_SEL_M 0x00000003
++#define AMBACLK_CLK_SEL_S 0
++#define AMBACLK_CLK_DIV_M 0x0000000c
++#define AMBACLK_CLK_DIV_S 2
++
++#if defined(COBRA_EMUL)
++#define AR5315_AMBA_CLOCK_RATE 20000000
++#define AR5315_CPU_CLOCK_RATE 40000000
++#else
++#if defined(DEFAULT_PLL)
++#define AR5315_AMBA_CLOCK_RATE 40000000
++#define AR5315_CPU_CLOCK_RATE 40000000
++#else
++#define AR5315_AMBA_CLOCK_RATE 92000000
++#define AR5315_CPU_CLOCK_RATE 184000000
++#endif /* ! DEFAULT_PLL */
++#endif /* ! COBRA_EMUL */
++
++#define AR5315_UART_CLOCK_RATE AR5315_AMBA_CLOCK_RATE
++#define AR5315_SDRAM_CLOCK_RATE AR5315_AMBA_CLOCK_RATE
++
++/*
++ * The UART computes baud rate as:
++ * baud = clock / (16 * divisor)
++ * where divisor is specified as a High Byte (DLM) and a Low Byte (DLL).
++ */
++#define DESIRED_BAUD_RATE 38400
++
++/*
++ * The WATCHDOG value is computed as
++ * 10 seconds * AR531X_WATCHDOG_CLOCK_RATE
++ */
++#define DESIRED_WATCHDOG_SECONDS 10
++#define AR531X_WATCHDOG_TIME \
++ (DESIRED_WATCHDOG_SECONDS * AR531X_WATCHDOG_CLOCK_RATE)
++
++
++#define CLOCKCTL_UART0 0x0010 /* enable UART0 external clock */
++
++
++ /*
++ * Applicable "PCICFG" bits for WLAN(s). Assoc status and LED mode.
++ */
++#define AR531X_PCICFG (AR531X_RESETTMR + 0x00b0)
++#define ASSOC_STATUS_M 0x00000003
++#define ASSOC_STATUS_NONE 0
++#define ASSOC_STATUS_PENDING 1
++#define ASSOC_STATUS_ASSOCIATED 2
++#define LED_MODE_M 0x0000001c
++#define LED_BLINK_THRESHOLD_M 0x000000e0
++#define LED_SLOW_BLINK_MODE 0x00000100
++
++/*
++ * GPIO
++ */
++
++#define AR5315_GPIO_DI (AR5315_DSLBASE + 0x0088)
++#define AR5315_GPIO_DO (AR5315_DSLBASE + 0x0090)
++#define AR5315_GPIO_CR (AR5315_DSLBASE + 0x0098)
++#define AR5315_GPIO_INT (AR5315_DSLBASE + 0x00a0)
++
++#define GPIO_CR_M(x) (1 << (x)) /* mask for i/o */
++#define GPIO_CR_O(x) (1 << (x)) /* output */
++#define GPIO_CR_I(x) (0 << (x)) /* input */
++
++#define GPIO_INT(x,Y) ((x) << (8 * (Y))) /* interrupt enable */
++#define GPIO_INT_M(Y) ((0x3F) << (8 * (Y))) /* mask for int */
++#define GPIO_INT_LVL(x,Y) ((x) << (8 * (Y) + 6)) /* interrupt level */
++#define GPIO_INT_LVL_M(Y) ((0x3) << (8 * (Y) + 6)) /* mask for int level */
++
++#define AR5315_RESET_GPIO 5
++#define AR5315_NUM_GPIO 22
++
++
++/*
++ * PCI Clock Control
++ */
++
++#define AR5315_PCICLK (AR5315_DSLBASE + 0x00a4)
++
++#define PCICLK_INPUT_M 0x3
++#define PCICLK_INPUT_S 0
++
++#define PCICLK_PLLC_CLKM 0
++#define PCICLK_PLLC_CLKM1 1
++#define PCICLK_PLLC_CLKC 2
++#define PCICLK_REF_CLK 3
++
++#define PCICLK_DIV_M 0xc
++#define PCICLK_DIV_S 2
++
++#define PCICLK_IN_FREQ 0
++#define PCICLK_IN_FREQ_DIV_6 1
++#define PCICLK_IN_FREQ_DIV_8 2
++#define PCICLK_IN_FREQ_DIV_10 3
++
++/*
++ * Observation Control Register
++ */
++#define AR5315_OCR (AR5315_DSLBASE + 0x00b0)
++#define OCR_GPIO0_IRIN 0x0040
++#define OCR_GPIO1_IROUT 0x0080
++#define OCR_GPIO3_RXCLR 0x0200
++
++/*
++ * General Clock Control
++ */
++
++#define AR5315_MISCCLK (AR5315_DSLBASE + 0x00b4)
++#define MISCCLK_PLLBYPASS_EN 0x00000001
++#define MISCCLK_PROCREFCLK 0x00000002
++
++/*
++ * SDRAM Controller
++ * - No read or write buffers are included.
++ */
++#define AR5315_MEM_CFG (AR5315_SDRAMCTL + 0x00)
++#define AR5315_MEM_CTRL (AR5315_SDRAMCTL + 0x0c)
++#define AR5315_MEM_REF (AR5315_SDRAMCTL + 0x10)
++
++#define SDRAM_DATA_WIDTH_M 0x00006000
++#define SDRAM_DATA_WIDTH_S 13
++
++#define SDRAM_COL_WIDTH_M 0x00001E00
++#define SDRAM_COL_WIDTH_S 9
++
++#define SDRAM_ROW_WIDTH_M 0x000001E0
++#define SDRAM_ROW_WIDTH_S 5
++
++#define SDRAM_BANKADDR_BITS_M 0x00000018
++#define SDRAM_BANKADDR_BITS_S 3
++
++
++/*
++ * SDRAM Memory Refresh (MEM_REF) value is computed as:
++ * MEMCTL_SREFR = (Tr * hclk_freq) / R
++ * where Tr is max. time of refresh of any single row
++ * R is number of rows in the DRAM
++ * For most 133MHz SDRAM parts, Tr=64ms, R=4096 or 8192
++ */
++#if defined(COBRA_EMUL)
++#define AR5315_SDRAM_MEMORY_REFRESH_VALUE 0x96
++#else
++#if defined(DEFAULT_PLL)
++#define AR5315_SDRAM_MEMORY_REFRESH_VALUE 0x200
++#else
++#define AR5315_SDRAM_MEMORY_REFRESH_VALUE 0x61a
++#endif /* ! DEFAULT_PLL */
++#endif
++
++#if defined(AR5315)
++
++#define AR5315_SDRAM_DDR_SDRAM 0 /* Not DDR SDRAM */
++#define AR5315_SDRAM_DATA_WIDTH 16 /* bits */
++#define AR5315_SDRAM_COL_WIDTH 8
++#define AR5315_SDRAM_ROW_WIDTH 12
++
++#else
++
++#define AR5315_SDRAM_DDR_SDRAM 0 /* Not DDR SDRAM */
++#define AR5315_SDRAM_DATA_WIDTH 16
++#define AR5315_SDRAM_COL_WIDTH 8
++#define AR5315_SDRAM_ROW_WIDTH 12
++
++#endif /* ! AR5315 */
++
++/*
++ * SPI Flash Interface Registers
++ */
++
++#define AR5315_SPI_CTL (AR5315_SPI + 0x00)
++#define AR5315_SPI_OPCODE (AR5315_SPI + 0x04)
++#define AR5315_SPI_DATA (AR5315_SPI + 0x08)
++
++#define SPI_CTL_START 0x00000100
++#define SPI_CTL_BUSY 0x00010000
++#define SPI_CTL_TXCNT_MASK 0x0000000f
++#define SPI_CTL_RXCNT_MASK 0x000000f0
++#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff
++#define SPI_CTL_SIZE_MASK 0x00060000
++
++#define SPI_CTL_CLK_SEL_MASK 0x03000000
++#define SPI_OPCODE_MASK 0x000000ff
++
++/*
++ * PCI-MAC Configuration registers
++ */
++#define PCI_MAC_RC (AR5315_PCI + 0x4000)
++#define PCI_MAC_SCR (AR5315_PCI + 0x4004)
++#define PCI_MAC_INTPEND (AR5315_PCI + 0x4008)
++#define PCI_MAC_SFR (AR5315_PCI + 0x400C)
++#define PCI_MAC_PCICFG (AR5315_PCI + 0x4010)
++#define PCI_MAC_SREV (AR5315_PCI + 0x4020)
++
++#define PCI_MAC_RC_MAC 0x00000001
++#define PCI_MAC_RC_BB 0x00000002
++
++#define PCI_MAC_SCR_SLMODE_M 0x00030000
++#define PCI_MAC_SCR_SLMODE_S 16
++#define PCI_MAC_SCR_SLM_FWAKE 0
++#define PCI_MAC_SCR_SLM_FSLEEP 1
++#define PCI_MAC_SCR_SLM_NORMAL 2
++
++#define PCI_MAC_SFR_SLEEP 0x00000001
++
++#define PCI_MAC_PCICFG_SPWR_DN 0x00010000
++
++
++
++
++/*
++ * PCI Bus Interface Registers
++ */
++#define AR5315_PCI_1MS_REG (AR5315_PCI + 0x0008)
++#define AR5315_PCI_1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */
++
++#define AR5315_PCI_MISC_CONFIG (AR5315_PCI + 0x000c)
++#define AR5315_PCIMISC_TXD_EN 0x00000001 /* Enable TXD for fragments */
++#define AR5315_PCIMISC_CFG_SEL 0x00000002 /* mem or config cycles */
++#define AR5315_PCIMISC_GIG_MASK 0x0000000C /* bits 31-30 for pci req */
++#define AR5315_PCIMISC_RST_MODE 0x00000030
++#define AR5315_PCIRST_INPUT 0x00000000 /* 4:5=0 rst is input */
++#define AR5315_PCIRST_LOW 0x00000010 /* 4:5=1 rst to GND */
++#define AR5315_PCIRST_HIGH 0x00000020 /* 4:5=2 rst to VDD */
++#define AR5315_PCIGRANT_EN 0x00000000 /* 6:7=0 early grant en */
++#define AR5315_PCIGRANT_FRAME 0x00000040 /* 6:7=1 grant waits 4 frame */
++#define AR5315_PCIGRANT_IDLE 0x00000080 /* 6:7=2 grant waits 4 idle */
++#define AR5315_PCIGRANT_GAP 0x00000000 /* 6:7=2 grant waits 4 idle */
++#define AR5315_PCICACHE_DIS 0x00001000 /* PCI external access cache disable */
++
++#define AR5315_PCI_OUT_TSTAMP (AR5315_PCI + 0x0010)
++
++#define AR5315_PCI_UNCACHE_CFG (AR5315_PCI + 0x0014)
++
++#define AR5315_PCI_IN_EN (AR5315_PCI + 0x0100)
++#define AR5315_PCI_IN_EN0 0x01 /* Enable chain 0 */
++#define AR5315_PCI_IN_EN1 0x02 /* Enable chain 1 */
++#define AR5315_PCI_IN_EN2 0x04 /* Enable chain 2 */
++#define AR5315_PCI_IN_EN3 0x08 /* Enable chain 3 */
++
++#define AR5315_PCI_IN_DIS (AR5315_PCI + 0x0104)
++#define AR5315_PCI_IN_DIS0 0x01 /* Disable chain 0 */
++#define AR5315_PCI_IN_DIS1 0x02 /* Disable chain 1 */
++#define AR5315_PCI_IN_DIS2 0x04 /* Disable chain 2 */
++#define AR5315_PCI_IN_DIS3 0x08 /* Disable chain 3 */
++
++#define AR5315_PCI_IN_PTR (AR5315_PCI + 0x0200)
++
++#define AR5315_PCI_OUT_EN (AR5315_PCI + 0x0400)
++#define AR5315_PCI_OUT_EN0 0x01 /* Enable chain 0 */
++
++#define AR5315_PCI_OUT_DIS (AR5315_PCI + 0x0404)
++#define AR5315_PCI_OUT_DIS0 0x01 /* Disable chain 0 */
++
++#define AR5315_PCI_OUT_PTR (AR5315_PCI + 0x0408)
++
++#define AR5315_PCI_INT_STATUS (AR5315_PCI + 0x0500) /* write one to clr */
++#define AR5315_PCI_TXINT 0x00000001 /* Desc In Completed */
++#define AR5315_PCI_TXOK 0x00000002 /* Desc In OK */
++#define AR5315_PCI_TXERR 0x00000004 /* Desc In ERR */
++#define AR5315_PCI_TXEOL 0x00000008 /* Desc In End-of-List */
++#define AR5315_PCI_RXINT 0x00000010 /* Desc Out Completed */
++#define AR5315_PCI_RXOK 0x00000020 /* Desc Out OK */
++#define AR5315_PCI_RXERR 0x00000040 /* Desc Out ERR */
++#define AR5315_PCI_RXEOL 0x00000080 /* Desc Out EOL */
++#define AR5315_PCI_TXOOD 0x00000200 /* Desc In Out-of-Desc */
++#define AR5315_PCI_MASK 0x0000FFFF /* Desc Mask */
++#define AR5315_PCI_EXT_INT 0x02000000
++#define AR5315_PCI_ABORT_INT 0x04000000
++
++#define AR5315_PCI_INT_MASK (AR5315_PCI + 0x0504) /* same as INT_STATUS */
++
++#define AR5315_PCI_INTEN_REG (AR5315_PCI + 0x0508)
++#define AR5315_PCI_INT_DISABLE 0x00 /* disable pci interrupts */
++#define AR5315_PCI_INT_ENABLE 0x01 /* enable pci interrupts */
++
++#define AR5315_PCI_HOST_IN_EN (AR5315_PCI + 0x0800)
++#define AR5315_PCI_HOST_IN_DIS (AR5315_PCI + 0x0804)
++#define AR5315_PCI_HOST_IN_PTR (AR5315_PCI + 0x0810)
++#define AR5315_PCI_HOST_OUT_EN (AR5315_PCI + 0x0900)
++#define AR5315_PCI_HOST_OUT_DIS (AR5315_PCI + 0x0904)
++#define AR5315_PCI_HOST_OUT_PTR (AR5315_PCI + 0x0908)
++
++
++/*
++ * Local Bus Interface Registers
++ */
++#define AR5315_LB_CONFIG (AR5315_LOCAL + 0x0000)
++#define AR5315_LBCONF_OE 0x00000001 /* =1 OE is low-true */
++#define AR5315_LBCONF_CS0 0x00000002 /* =1 first CS is low-true */
++#define AR5315_LBCONF_CS1 0x00000004 /* =1 2nd CS is low-true */
++#define AR5315_LBCONF_RDY 0x00000008 /* =1 RDY is low-true */
++#define AR5315_LBCONF_WE 0x00000010 /* =1 Write En is low-true */
++#define AR5315_LBCONF_WAIT 0x00000020 /* =1 WAIT is low-true */
++#define AR5315_LBCONF_ADS 0x00000040 /* =1 Adr Strobe is low-true */
++#define AR5315_LBCONF_MOT 0x00000080 /* =0 Intel, =1 Motorola */
++#define AR5315_LBCONF_8CS 0x00000100 /* =1 8 bits CS, 0= 16bits */
++#define AR5315_LBCONF_8DS 0x00000200 /* =1 8 bits Data S, 0=16bits */
++#define AR5315_LBCONF_ADS_EN 0x00000400 /* =1 Enable ADS */
++#define AR5315_LBCONF_ADR_OE 0x00000800 /* =1 Adr cap on OE, WE or DS */
++#define AR5315_LBCONF_ADDT_MUX 0x00001000 /* =1 Adr and Data share bus */
++#define AR5315_LBCONF_DATA_OE 0x00002000 /* =1 Data cap on OE, WE, DS */
++#define AR5315_LBCONF_16DATA 0x00004000 /* =1 Data is 16 bits wide */
++#define AR5315_LBCONF_SWAPDT 0x00008000 /* =1 Byte swap data */
++#define AR5315_LBCONF_SYNC 0x00010000 /* =1 Bus synchronous to clk */
++#define AR5315_LBCONF_INT 0x00020000 /* =1 Intr is low true */
++#define AR5315_LBCONF_INT_CTR0 0x00000000 /* GND high-Z, Vdd is high-Z */
++#define AR5315_LBCONF_INT_CTR1 0x00040000 /* GND drive, Vdd is high-Z */
++#define AR5315_LBCONF_INT_CTR2 0x00080000 /* GND high-Z, Vdd drive */
++#define AR5315_LBCONF_INT_CTR3 0x000C0000 /* GND drive, Vdd drive */
++#define AR5315_LBCONF_RDY_WAIT 0x00100000 /* =1 RDY is negative of WAIT */
++#define AR5315_LBCONF_INT_PULSE 0x00200000 /* =1 Interrupt is a pulse */
++#define AR5315_LBCONF_ENABLE 0x00400000 /* =1 Falcon respond to LB */
++
++#define AR5315_LB_CLKSEL (AR5315_LOCAL + 0x0004)
++#define AR5315_LBCLK_EXT 0x0001 /* use external clk for lb */
++
++#define AR5315_LB_1MS (AR5315_LOCAL + 0x0008)
++#define AR5315_LB1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */
++
++#define AR5315_LB_MISCCFG (AR5315_LOCAL + 0x000C)
++#define AR5315_LBM_TXD_EN 0x00000001 /* Enable TXD for fragments */
++#define AR5315_LBM_RX_INTEN 0x00000002 /* Enable LB ints on RX ready */
++#define AR5315_LBM_MBOXWR_INTEN 0x00000004 /* Enable LB ints on mbox wr */
++#define AR5315_LBM_MBOXRD_INTEN 0x00000008 /* Enable LB ints on mbox rd */
++#define AR5315_LMB_DESCSWAP_EN 0x00000010 /* Byte swap desc enable */
++#define AR5315_LBM_TIMEOUT_MASK 0x00FFFF80
++#define AR5315_LBM_TIMEOUT_SHFT 7
++#define AR5315_LBM_PORTMUX 0x07000000
++
++
++#define AR5315_LB_RXTSOFF (AR5315_LOCAL + 0x0010)
++
++#define AR5315_LB_TX_CHAIN_EN (AR5315_LOCAL + 0x0100)
++#define AR5315_LB_TXEN_0 0x01
++#define AR5315_LB_TXEN_1 0x02
++#define AR5315_LB_TXEN_2 0x04
++#define AR5315_LB_TXEN_3 0x08
++
++#define AR5315_LB_TX_CHAIN_DIS (AR5315_LOCAL + 0x0104)
++#define AR5315_LB_TX_DESC_PTR (AR5315_LOCAL + 0x0200)
++
++#define AR5315_LB_RX_CHAIN_EN (AR5315_LOCAL + 0x0400)
++#define AR5315_LB_RXEN 0x01
++
++#define AR5315_LB_RX_CHAIN_DIS (AR5315_LOCAL + 0x0404)
++#define AR5315_LB_RX_DESC_PTR (AR5315_LOCAL + 0x0408)
++
++#define AR5315_LB_INT_STATUS (AR5315_LOCAL + 0x0500)
++#define AR5315_INT_TX_DESC 0x0001
++#define AR5315_INT_TX_OK 0x0002
++#define AR5315_INT_TX_ERR 0x0004
++#define AR5315_INT_TX_EOF 0x0008
++#define AR5315_INT_RX_DESC 0x0010
++#define AR5315_INT_RX_OK 0x0020
++#define AR5315_INT_RX_ERR 0x0040
++#define AR5315_INT_RX_EOF 0x0080
++#define AR5315_INT_TX_TRUNC 0x0100
++#define AR5315_INT_TX_STARVE 0x0200
++#define AR5315_INT_LB_TIMEOUT 0x0400
++#define AR5315_INT_LB_ERR 0x0800
++#define AR5315_INT_MBOX_WR 0x1000
++#define AR5315_INT_MBOX_RD 0x2000
++
++/* Bit definitions for INT MASK are the same as INT_STATUS */
++#define AR5315_LB_INT_MASK (AR5315_LOCAL + 0x0504)
++
++#define AR5315_LB_INT_EN (AR5315_LOCAL + 0x0508)
++#define AR5315_LB_MBOX (AR5315_LOCAL + 0x0600)
++
++
++
++/*
++ * IR Interface Registers
++ */
++#define AR5315_IR_PKTDATA (AR5315_IR + 0x0000)
++
++#define AR5315_IR_PKTLEN (AR5315_IR + 0x07fc) /* 0 - 63 */
++
++#define AR5315_IR_CONTROL (AR5315_IR + 0x0800)
++#define AR5315_IRCTL_TX 0x00000000 /* use as tranmitter */
++#define AR5315_IRCTL_RX 0x00000001 /* use as receiver */
++#define AR5315_IRCTL_SAMPLECLK_MASK 0x00003ffe /* Sample clk divisor mask */
++#define AR5315_IRCTL_SAMPLECLK_SHFT 1
++#define AR5315_IRCTL_OUTPUTCLK_MASK 0x03ffc000 /* Output clk divisor mask */
++#define AR5315_IRCTL_OUTPUTCLK_SHFT 14
++
++#define AR5315_IR_STATUS (AR5315_IR + 0x0804)
++#define AR5315_IRSTS_RX 0x00000001 /* receive in progress */
++#define AR5315_IRSTS_TX 0x00000002 /* transmit in progress */
++
++#define AR5315_IR_CONFIG (AR5315_IR + 0x0808)
++#define AR5315_IRCFG_INVIN 0x00000001 /* invert input polarity */
++#define AR5315_IRCFG_INVOUT 0x00000002 /* invert output polarity */
++#define AR5315_IRCFG_SEQ_START_WIN_SEL 0x00000004 /* 1 => 28, 0 => 7 */
++#define AR5315_IRCFG_SEQ_START_THRESH 0x000000f0 /* */
++#define AR5315_IRCFG_SEQ_END_UNIT_SEL 0x00000100 /* */
++#define AR5315_IRCFG_SEQ_END_UNIT_THRESH 0x00007e00 /* */
++#define AR5315_IRCFG_SEQ_END_WIN_SEL 0x00008000 /* */
++#define AR5315_IRCFG_SEQ_END_WIN_THRESH 0x001f0000 /* */
++#define AR5315_IRCFG_NUM_BACKOFF_WORDS 0x01e00000 /* */
++
++/*
++ * PCI memory constants: Memory area 1 and 2 are the same size -
++ * (twice the PCI_TLB_PAGE_SIZE). The definition of
++ * CPU_TO_PCI_MEM_SIZE is coupled with the TLB setup routine
++ * sysLib.c/sysTlbInit(), in that it assumes that 2 pages of size
++ * PCI_TLB_PAGE_SIZE are set up in the TLB for each PCI memory space.
++ */
++
++#define CPU_TO_PCI_MEM_BASE1 0xE0000000
++#define CPU_TO_PCI_MEM_SIZE1 (2*PCI_TLB_PAGE_SIZE)
++
++
++/* TLB attributes for PCI transactions */
++
++#define PCI_MMU_PAGEMASK 0x00003FFF
++#define MMU_PAGE_UNCACHED 0x00000010
++#define MMU_PAGE_DIRTY 0x00000004
++#define MMU_PAGE_VALID 0x00000002
++#define MMU_PAGE_GLOBAL 0x00000001
++#define PCI_MMU_PAGEATTRIB (MMU_PAGE_UNCACHED|MMU_PAGE_DIRTY|\
++ MMU_PAGE_VALID|MMU_PAGE_GLOBAL)
++#define PCI_MEMORY_SPACE1_VIRT 0xE0000000 /* Used for non-prefet mem */
++#define PCI_MEMORY_SPACE1_PHYS 0x80000000
++#define PCI_TLB_PAGE_SIZE 0x01000000
++#define TLB_HI_MASK 0xFFFFE000
++#define TLB_LO_MASK 0x3FFFFFFF
++#define PAGEMASK_SHIFT 11
++#define TLB_LO_SHIFT 6
++
++#define PCI_MAX_LATENCY 0xFFF /* Max PCI latency */
++
++#define HOST_PCI_DEV_ID 3
++#define HOST_PCI_MBAR0 0x10000000
++#define HOST_PCI_MBAR1 0x20000000
++#define HOST_PCI_MBAR2 0x30000000
++
++#define HOST_PCI_SDRAM_BASEADDR HOST_PCI_MBAR1
++#define PCI_DEVICE_MEM_SPACE 0x800000
++
++
++typedef unsigned int AR531X_REG;
++
++#define sysRegRead(phys) \
++ (*(volatile AR531X_REG *)PHYS_TO_K1(phys))
++
++#define sysRegWrite(phys, val) \
++ ((*(volatile AR531X_REG *)PHYS_TO_K1(phys)) = (val))
++#endif
++
++#endif
+diff -urN linux-mips/arch/mips/ar531x/ar531xintr.S mips-linux-2.4.25/arch/mips/ar531x/ar531xintr.S
+--- linux-mips/arch/mips/ar531x/ar531xintr.S 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/arch/mips/ar531x/ar531xintr.S 2005-12-30 17:26:31.000823952 +0000
+@@ -0,0 +1,30 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++#include <asm/asm.h>
++#include <asm/mipsregs.h>
++#include <asm/regdef.h>
++#include <asm/stackframe.h>
++
++/*
++ * Glue code to save registers and get us to the interrupt dispatcher
++ */
++ .text
++ .set noat
++ .align 5
++NESTED(ar531x_interrupt_receive, PT_SIZE, sp)
++ SAVE_ALL
++ CLI
++ .set at
++
++ move a0, sp
++ jal ar531x_irq_dispatch
++
++ j ret_from_irq
++
++ END(ar531x_interrupt_receive)
+diff -urN linux-mips/arch/mips/ar531x/ar531xirq.c mips-linux-2.4.25/arch/mips/ar531x/ar531xirq.c
+--- linux-mips/arch/mips/ar531x/ar531xirq.c 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/arch/mips/ar531x/ar531xirq.c 2005-12-30 17:26:31.000823952 +0000
+@@ -0,0 +1,442 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * Interrupt support for AR531X WiSOC.
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/kernel_stat.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/random.h>
++#include <linux/pm.h>
++#include <linux/delay.h>
++#include <linux/reboot.h>
++
++#include <asm/irq.h>
++#include <asm/mipsregs.h>
++#include <asm/gdb-stub.h>
++
++#include "ar531xlnx.h"
++#include <asm/irq_cpu.h>
++
++extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
++
++static void ar531x_misc_intr_enable(unsigned int irq);
++static void ar531x_misc_intr_disable(unsigned int irq);
++
++/* Turn on the specified AR531X_MISC_IRQ interrupt */
++static unsigned int
++ar531x_misc_intr_startup(unsigned int irq)
++{
++ ar531x_misc_intr_enable(irq);
++ return 0;
++}
++
++/* Turn off the specified AR531X_MISC_IRQ interrupt */
++static void
++ar531x_misc_intr_shutdown(unsigned int irq)
++{
++ ar531x_misc_intr_disable(irq);
++}
++
++/* Enable the specified AR531X_MISC_IRQ interrupt */
++static void
++ar531x_misc_intr_enable(unsigned int irq)
++{
++ unsigned int imr;
++
++#if CONFIG_AR5315
++ imr = sysRegRead(AR5315_IMR);
++ switch(irq)
++ {
++ case AR531X_MISC_IRQ_TIMER:
++ imr |= IMR_TIMER;
++ break;
++
++ case AR531X_MISC_IRQ_AHB_PROC:
++ imr |= IMR_AHB;
++ break;
++
++ case AR531X_MISC_IRQ_AHB_DMA:
++ imr |= 0/* ?? */;
++ break;
++ /*
++ case AR531X_ISR_GPIO:
++ imr |= IMR_GPIO;
++ break;
++ */
++
++ case AR531X_MISC_IRQ_UART0:
++ imr |= IMR_UART0;
++ break;
++
++
++ case AR531X_MISC_IRQ_WATCHDOG:
++ imr |= IMR_WD;
++ break;
++
++ case AR531X_MISC_IRQ_LOCAL:
++ imr |= 0/* ?? */;
++ break;
++
++ }
++ sysRegWrite(AR5315_IMR, imr);
++ imr=sysRegRead(AR5315_IMR); /* flush write buffer */
++ //printk("enable Interrupt irq 0x%x imr 0x%x \n",irq,imr);
++
++#else
++ imr = sysRegRead(AR531X_IMR);
++ imr |= (1 << (irq - AR531X_MISC_IRQ_BASE - 1));
++ sysRegWrite(AR531X_IMR, imr);
++ sysRegRead(AR531X_IMR); /* flush write buffer */
++#endif
++}
++
++/* Disable the specified AR531X_MISC_IRQ interrupt */
++static void
++ar531x_misc_intr_disable(unsigned int irq)
++{
++ unsigned int imr;
++
++#if CONFIG_AR5315
++ imr = sysRegRead(AR5315_IMR);
++ switch(irq)
++ {
++ case AR531X_MISC_IRQ_TIMER:
++ imr &= (~IMR_TIMER);
++ break;
++
++ case AR531X_MISC_IRQ_AHB_PROC:
++ imr &= (~IMR_AHB);
++ break;
++
++ case AR531X_MISC_IRQ_AHB_DMA:
++ imr &= 0/* ?? */;
++ break;
++ /*
++ case AR531X_ISR_GPIO:
++ imr &= ~IMR_GPIO;
++ break;
++ */
++
++ case AR531X_MISC_IRQ_UART0:
++ imr &= (~IMR_UART0);
++ break;
++
++ case AR531X_MISC_IRQ_WATCHDOG:
++ imr &= (~IMR_WD);
++ break;
++
++ case AR531X_MISC_IRQ_LOCAL:
++ imr &= ~0/* ?? */;
++ break;
++
++ }
++ sysRegWrite(AR5315_IMR, imr);
++ sysRegRead(AR5315_IMR); /* flush write buffer */
++#else
++ imr = sysRegRead(AR531X_IMR);
++ imr &= ~(1 << (irq - AR531X_MISC_IRQ_BASE - 1));
++ sysRegWrite(AR531X_IMR, imr);
++ sysRegRead(AR531X_IMR); /* flush write buffer */
++#endif
++}
++
++static void
++ar531x_misc_intr_ack(unsigned int irq)
++{
++ ar531x_misc_intr_disable(irq);
++}
++
++static void
++ar531x_misc_intr_end(unsigned int irq)
++{
++ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
++ ar531x_misc_intr_enable(irq);
++}
++
++static void
++ar531x_misc_intr_set_affinity(unsigned int irq, unsigned long mask)
++{
++ /* Only 1 CPU; ignore affinity request */
++}
++
++struct hw_interrupt_type ar531x_misc_intr_controller = {
++ "AR531X MISC",
++ ar531x_misc_intr_startup,
++ ar531x_misc_intr_shutdown,
++ ar531x_misc_intr_enable,
++ ar531x_misc_intr_disable,
++ ar531x_misc_intr_ack,
++ ar531x_misc_intr_end,
++ ar531x_misc_intr_set_affinity,
++};
++
++int ar531x_misc_irq_base;
++
++/*
++ * Determine interrupt source among interrupts that use IP6
++ */
++void
++ar531x_misc_intr_init(int irq_base)
++{
++ int i;
++
++ for (i = irq_base; i < irq_base + AR531X_MISC_IRQ_COUNT; i++) {
++ irq_desc[i].status = IRQ_DISABLED;
++ irq_desc[i].action = NULL;
++ irq_desc[i].depth = 1;
++ irq_desc[i].handler = &ar531x_misc_intr_controller;
++ }
++
++ ar531x_misc_irq_base = irq_base;
++}
++
++/* ARGSUSED */
++void
++spurious_irq_handler(int cpl, void *dev_id, struct pt_regs *regs)
++{
++ /*
++ printk("spurious_irq_handler: %d cause=0x%8.8x status=0x%8.8x\n",
++ cpl, cause_intrs, status_intrs);
++ */
++}
++
++/* ARGSUSED */
++void
++spurious_misc_handler(int cpl, void *dev_id, struct pt_regs *regs)
++{
++ /*
++ printk("spurious_misc_handler: 0x%x isr=0x%8.8x imr=0x%8.8x\n",
++ cpl, ar531x_isr, ar531x_imr);
++ */
++}
++
++void
++ar531x_timer_handler(int cpl, void *dev_id, struct pt_regs *regs)
++{
++#if CONFIG_AR5315
++ (void)sysRegRead(AR5315_TIMER); /* clear interrupt */
++#else
++ (void)sysRegRead(AR531X_TIMER); /* clear interrupt */
++#endif
++}
++
++void
++ar531x_ahb_proc_handler(int cpl, void *dev_id, struct pt_regs *regs)
++{
++ u32 procAddr;
++ u32 proc1;
++ u32 dmaAddr;
++ u32 dma1;
++#if CONFIG_AR5315
++ sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET);
++ sysRegRead(AR5315_AHB_ERR1);
++#else
++ proc1 = sysRegRead(AR531X_PROC1);
++ procAddr = sysRegRead(AR531X_PROCADDR); /* clears error state */
++ dma1 = sysRegRead(AR531X_DMA1);
++ dmaAddr = sysRegRead(AR531X_DMAADDR); /* clears error state */
++#endif
++
++ printk("AHB interrupt: PROCADDR=0x%8.8x PROC1=0x%8.8x DMAADDR=0x%8.8x DMA1=0x%8.8x\n",
++ procAddr, proc1, dmaAddr, dma1);
++
++ machine_restart("AHB error"); /* Catastrophic failure */
++}
++
++static struct irqaction cascade =
++ {no_action, SA_INTERRUPT, 0, "cascade",
++ NULL, NULL};
++
++static struct irqaction spurious_irq =
++ {spurious_irq_handler, SA_INTERRUPT, 0, "spurious_irq",
++ NULL, NULL};
++
++static struct irqaction spurious_misc =
++ {spurious_misc_handler, SA_INTERRUPT, 0, "spurious_misc",
++ NULL, NULL};
++
++static struct irqaction ar531x_timer_interrupt =
++ {ar531x_timer_handler, SA_INTERRUPT, 0, "ar531x_timer_interrupt",
++ NULL, NULL};
++
++static struct irqaction ar531x_ahb_proc_interrupt =
++ {ar531x_ahb_proc_handler, SA_INTERRUPT, 0, "ar531x_ahb_proc_interrupt",
++ NULL, NULL};
++
++extern asmlinkage void ar531x_interrupt_receive(void);
++
++/*
++ * Called when an interrupt is received, this function
++ * determines exactly which interrupt it was, and it
++ * invokes the appropriate handler.
++ *
++ * Implicitly, we also define interrupt priority by
++ * choosing which to dispatch first.
++ */
++extern void dump_uart(void *);
++
++#if CONFIG_AR5315
++
++void
++ar531x_irq_dispatch(struct pt_regs *regs)
++{
++ int cause_intrs = regs->cp0_cause;
++ int status_intrs = regs->cp0_status;
++ int pending = cause_intrs & status_intrs;
++
++ if (pending & CAUSEF_IP3) {
++ do_IRQ(AR531X_IRQ_WLAN0_INTRS, regs);
++ }
++ else if (pending & CAUSEF_IP4) {
++ do_IRQ(AR531X_IRQ_ENET0_INTRS, regs);
++ }
++ else if (pending & CAUSEF_IP2) {
++ AR531X_REG ar531x_isr = sysRegRead(AR5315_ISR);
++ AR531X_REG ar531x_imr = sysRegRead(AR5315_IMR);
++ unsigned int ar531x_misc_intrs = ar531x_isr & ar531x_imr;
++
++ if (ar531x_misc_intrs & ISR_TIMER)
++ do_IRQ(AR531X_MISC_IRQ_TIMER, regs);
++ else if (ar531x_misc_intrs & ISR_AHB)
++ do_IRQ(AR531X_MISC_IRQ_AHB_PROC, regs);
++ else if (ar531x_misc_intrs & ISR_GPIO)
++ {
++ int i;
++ u32 gpioIntPending;
++
++ gpioIntPending = sysRegRead(AR5315_GPIO_DI) & gpioIntMask;
++ for (i=0; i<AR531X_GPIO_IRQ_COUNT; i++) {
++ if (gpioIntPending & (1 << i))
++ do_IRQ(AR531X_GPIO_IRQ(i), regs);
++ }
++ }
++ else if (ar531x_misc_intrs & ISR_UART0) {
++ do_IRQ(AR531X_MISC_IRQ_UART0, regs);
++#if CONFIG_KGDB
++ if (kgdbInterrupt()) {
++ if (!user_mode(regs))
++ set_async_breakpoint((unsigned long *)&regs->cp0_epc);
++ }
++#endif /* CONFIG_KGDB */
++ }
++ else if (ar531x_misc_intrs & ISR_WD)
++ do_IRQ(AR531X_MISC_IRQ_WATCHDOG, regs);
++ else
++ do_IRQ(AR531X_MISC_IRQ_NONE, regs);
++ } else if (pending & CAUSEF_IP7) {
++ do_IRQ(AR531X_IRQ_CPU_CLOCK, regs);
++ }
++ else {
++ do_IRQ(AR531X_IRQ_NONE, regs);
++ }
++}
++
++#else
++
++void
++ar531x_irq_dispatch(struct pt_regs *regs)
++{
++ int cause_intrs = regs->cp0_cause;
++ int status_intrs = regs->cp0_status;
++ int pending = cause_intrs & status_intrs;
++
++ if (pending & CAUSEF_IP2) {
++ do_IRQ(AR531X_IRQ_WLAN0_INTRS, regs);
++ }
++ else if (pending & CAUSEF_IP3) {
++ do_IRQ(AR531X_IRQ_ENET0_INTRS, regs);
++ }
++ else if (pending & CAUSEF_IP4) {
++ do_IRQ(AR531X_IRQ_ENET1_INTRS, regs);
++ }
++ else if (pending & CAUSEF_IP5) {
++ do_IRQ(AR531X_IRQ_WLAN1_INTRS, regs);
++ }
++ else if (pending & CAUSEF_IP6) {
++ AR531X_REG ar531x_isr = sysRegRead(AR531X_ISR);
++ AR531X_REG ar531x_imr = sysRegRead(AR531X_IMR);
++ unsigned int ar531x_misc_intrs = ar531x_isr & ar531x_imr;
++
++ if (ar531x_misc_intrs & AR531X_ISR_TIMER)
++ do_IRQ(AR531X_MISC_IRQ_TIMER, regs);
++ else if (ar531x_misc_intrs & AR531X_ISR_AHBPROC)
++ do_IRQ(AR531X_MISC_IRQ_AHB_PROC, regs);
++ else if (ar531x_misc_intrs & AR531X_ISR_AHBDMA)
++ do_IRQ(AR531X_MISC_IRQ_AHB_DMA, regs);
++ else if (ar531x_misc_intrs & AR531X_ISR_GPIO)
++ {
++ int i;
++ u32 gpioIntPending;
++
++ gpioIntPending = sysRegRead(AR531X_GPIO_DI) & gpioIntMask;
++ for (i=0; i<AR531X_GPIO_IRQ_COUNT; i++) {
++ if (gpioIntPending & (1 << i))
++ do_IRQ(AR531X_GPIO_IRQ(i), regs);
++ }
++ }
++ else if ((ar531x_misc_intrs & AR531X_ISR_UART0) ||
++ (ar531x_misc_intrs & AR531X_ISR_UART0DMA)) {
++ do_IRQ(AR531X_MISC_IRQ_UART0, regs);
++#if CONFIG_KGDB
++ if (kgdbInterrupt()) {
++ if (!user_mode(regs))
++ set_async_breakpoint((unsigned long *)&regs->cp0_epc);
++ }
++#endif /* CONFIG_KGDB */
++ }
++ else if (ar531x_misc_intrs & AR531X_ISR_WD)
++ do_IRQ(AR531X_MISC_IRQ_WATCHDOG, regs);
++ else if (ar531x_misc_intrs & AR531X_ISR_LOCAL)
++ do_IRQ(AR531X_MISC_IRQ_LOCAL, regs);
++ else
++ do_IRQ(AR531X_MISC_IRQ_NONE, regs);
++ } else if (pending & CAUSEF_IP7) {
++ do_IRQ(AR531X_IRQ_CPU_CLOCK, regs);
++ } else
++ do_IRQ(AR531X_IRQ_NONE, regs);
++}
++
++#endif
++
++void __init init_IRQ(void)
++{
++ init_generic_irq();
++ set_except_vector(0, ar531x_interrupt_receive);
++
++ /* Initialize interrupt controllers */
++ mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
++ ar531x_misc_intr_init(AR531X_MISC_IRQ_BASE);
++ ar531x_gpio_intr_init(AR531X_GPIO_IRQ_BASE);
++ setup_irq(AR531X_IRQ_MISC_INTRS, &cascade);
++ /*
++ * AR531X_IRQ_CPU_CLOCK is setup by ar531x_timer_setup.
++ */
++
++ /* Default "spurious interrupt" handlers */
++ setup_irq(AR531X_IRQ_NONE, &spurious_irq);
++ setup_irq(AR531X_MISC_IRQ_NONE, &spurious_misc);
++ setup_irq(AR531X_GPIO_IRQ_NONE, &spurious_gpio);
++#ifndef CONFIG_AR5315
++ setup_irq(AR531X_MISC_IRQ_TIMER, &ar531x_timer_interrupt);
++#endif
++ setup_irq(AR531X_MISC_IRQ_AHB_PROC, &ar531x_ahb_proc_interrupt);
++ setup_irq(AR531X_MISC_IRQ_GPIO, &cascade);
++
++#ifdef CONFIG_KGDB
++#if CONFIG_EARLY_STOP
++ kgdbInit();
++#endif
++#endif
++}
+diff -urN linux-mips/arch/mips/ar531x/ar531xksyms.c mips-linux-2.4.25/arch/mips/ar531x/ar531xksyms.c
+--- linux-mips/arch/mips/ar531x/ar531xksyms.c 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/arch/mips/ar531x/ar531xksyms.c 2005-12-30 17:26:31.001823800 +0000
+@@ -0,0 +1,17 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++#include <linux/module.h>
++#include "asm/atheros/ar531xbsp.h"
++
++#ifdef CONFIG_KGDB
++EXPORT_SYMBOL(kgdbInit);
++EXPORT_SYMBOL(kgdbEnabled);
++#endif
++EXPORT_SYMBOL(ar531x_sys_frequency);
++EXPORT_SYMBOL(get_system_type);
+diff -urN linux-mips/arch/mips/ar531x/ar531xlnx.h mips-linux-2.4.25/arch/mips/ar531x/ar531xlnx.h
+--- linux-mips/arch/mips/ar531x/ar531xlnx.h 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/arch/mips/ar531x/ar531xlnx.h 2005-12-30 17:26:31.001823800 +0000
+@@ -0,0 +1,135 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * This file contains definitions needed in order to compile
++ * AR531X products for linux. Definitions that are largely
++ * AR531X-specific and independent of operating system belong
++ * in ar531x.h rather than this file.
++ */
++#include "ar531x.h"
++
++#define MIPS_CPU_IRQ_BASE 0x00
++#define AR531X_HIGH_PRIO 0x10
++#define AR531X_MISC_IRQ_BASE 0x20
++#define AR531X_GPIO_IRQ_BASE 0x30
++
++/* Software's idea of interrupts handled by "CPU Interrupt Controller" */
++#if CONFIG_AR5315
++#define AR531X_IRQ_NONE MIPS_CPU_IRQ_BASE+0
++#define AR531X_IRQ_MISC_INTRS MIPS_CPU_IRQ_BASE+2 /* C0_CAUSE: 0x0400 */
++#define AR531X_IRQ_WLAN0_INTRS MIPS_CPU_IRQ_BASE+3 /* C0_CAUSE: 0x0800 */
++#define AR531X_IRQ_ENET0_INTRS MIPS_CPU_IRQ_BASE+4 /* C0_CAUSE: 0x1000 */
++#define AR531X_IRQ_LCBUS_PCI MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */
++#define AR531X_IRQ_WLAN0_POLL MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */
++#define AR531X_IRQ_CPU_CLOCK MIPS_CPU_IRQ_BASE+7 /* C0_CAUSE: 0x8000 */
++#else
++#define AR531X_IRQ_NONE MIPS_CPU_IRQ_BASE+0
++#define AR531X_IRQ_WLAN0_INTRS MIPS_CPU_IRQ_BASE+2 /* C0_CAUSE: 0x0400 */
++#define AR531X_IRQ_ENET0_INTRS MIPS_CPU_IRQ_BASE+3 /* C0_CAUSE: 0x0800 */
++#define AR531X_IRQ_ENET1_INTRS MIPS_CPU_IRQ_BASE+4 /* C0_CAUSE: 0x1000 */
++#define AR531X_IRQ_WLAN1_INTRS MIPS_CPU_IRQ_BASE+5 /* C0_CAUSE: 0x2000 */
++#define AR531X_IRQ_MISC_INTRS MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */
++#define AR531X_IRQ_CPU_CLOCK MIPS_CPU_IRQ_BASE+7 /* C0_CAUSE: 0x8000 */
++#endif
++/* Miscellaneous interrupts, which share IP6 */
++#define AR531X_MISC_IRQ_NONE AR531X_MISC_IRQ_BASE+0
++#define AR531X_MISC_IRQ_TIMER AR531X_MISC_IRQ_BASE+1
++#define AR531X_MISC_IRQ_AHB_PROC AR531X_MISC_IRQ_BASE+2
++#define AR531X_MISC_IRQ_AHB_DMA AR531X_MISC_IRQ_BASE+3
++#define AR531X_MISC_IRQ_GPIO AR531X_MISC_IRQ_BASE+4
++#define AR531X_MISC_IRQ_UART0 AR531X_MISC_IRQ_BASE+5
++#define AR531X_MISC_IRQ_UART0_DMA AR531X_MISC_IRQ_BASE+6
++#define AR531X_MISC_IRQ_WATCHDOG AR531X_MISC_IRQ_BASE+7
++#define AR531X_MISC_IRQ_LOCAL AR531X_MISC_IRQ_BASE+8
++#define AR531X_MISC_IRQ_COUNT 9
++
++/* GPIO Interrupts [0..7], share AR531X_MISC_IRQ_GPIO */
++#define AR531X_GPIO_IRQ_NONE AR531X_MISC_IRQ_BASE+0
++#define AR531X_GPIO_IRQ(n) AR531X_MISC_IRQ_BASE+(n)+1
++#ifdef CONFIG_AR5315
++#define AR531X_GPIO_IRQ_COUNT 2
++#else
++#define AR531X_GPIO_IRQ_COUNT 9
++#endif
++
++#define PHYS_TO_K1(physaddr) KSEG1ADDR(physaddr)
++#define PHYS_TO_K0(physaddr) KSEG0ADDR(physaddr)
++#define UNMAPPED_TO_PHYS(vaddr) PHYSADDR(vaddr)
++#define IS_UNMAPPED_VADDR(vaddr) \
++ ((KSEGX(vaddr) == KSEG0) || (KSEGX(vaddr) == KSEG1))
++
++/* IOCTL commands for /proc/ar531x */
++#define AR531X_CTRL_DO_BREAKPOINT 1
++#define AR531X_CTRL_DO_MADWIFI 2
++
++/*
++ * Definitions for operating system portability.
++ * These are vxWorks-->Linux translations.
++ */
++#define LOCAL static
++#define BOOL int
++#define TRUE 1
++#define FALSE 0
++#define UINT8 u8
++#define UINT16 u16
++#define UINT32 u32
++#define PRINTF printk
++#if /* DEBUG */ 1
++#define DEBUG_PRINTF printk
++#define INLINE
++#else
++DEBUG_PRINTF while (0) printk
++#define INLINE inline
++#endif
++#define sysUDelay(usecs) udelay(usecs)
++#define sysMsDelay(msecs) mdelay(msecs)
++typedef volatile UINT8 *VIRT_ADDR;
++#define MALLOC(sz) kmalloc(sz, GFP_KERNEL)
++#define MALLOC_NOSLEEP(sz) kmalloc(sz, GFP_ATOMIC)
++#define FREE(ptr) kfree((void *)ptr)
++#define BSP_BUG() do { printk("kernel BSP BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0)
++#define BSP_BUG_ON(condition) do { if (unlikely((condition)!=0)) BSP_BUG(); } while(0)
++#define ASSERT(x) BSP_BUG_ON(!(x))
++
++extern struct ar531x_boarddata *ar531x_board_configuration;
++extern char *ar531x_radio_configuration;
++extern char *enet_mac_address_get(int MACUnit);
++
++extern void kgdbInit(void);
++extern int kgdbEnabled(void);
++extern void breakpoint(void);
++extern int kgdbInterrupt(void);
++extern unsigned int ar531x_cpu_frequency(void);
++extern unsigned int ar531x_sys_frequency(void);
++
++/* GPIO support */
++extern struct irqaction spurious_gpio;
++extern unsigned int gpioIntMask;
++extern void ar531x_gpio_intr_init(int irq_base);
++extern void ar531x_gpio_ctrl_output(int gpio);
++extern void ar531x_gpio_ctrl_input(int gpio);
++extern void ar531x_gpio_set(int gpio, int val);
++extern int ar531x_gpio_get(int gpio);
++extern void ar531x_gpio_intr_enable(unsigned int irq);
++extern void ar531x_gpio_intr_disable(unsigned int irq);
++
++/* Watchdog Timer support */
++extern int watchdog_start(unsigned int milliseconds);
++extern int watchdog_stop(void);
++extern int watchdog_is_enabled(void);
++extern unsigned int watchdog_min_timer_reached(void);
++extern void watchdog_notify_alive(void);
++
++#define A_DATA_CACHE_INVAL(start, length) \
++ dma_cache_inv((UINT32)(start),(length))
++
++#define sysWbFlush() mb()
++
++#define intDisable(x) cli()
++#define intEnable(x) sti()
+diff -urN linux-mips/arch/mips/ar531x/ar531xprom.c mips-linux-2.4.25/arch/mips/ar531x/ar531xprom.c
+--- linux-mips/arch/mips/ar531x/ar531xprom.c 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/arch/mips/ar531x/ar531xprom.c 2005-12-30 17:26:31.001823800 +0000
+@@ -0,0 +1,88 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright MontaVista Software Inc
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * Prom setup file for ar531x
++ */
++
++#include <linux/init.h>
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/bootmem.h>
++
++#include <asm/bootinfo.h>
++#include <asm/addrspace.h>
++
++#include "ar531xlnx.h"
++
++#define COMMAND_LINE_SIZE 512
++
++char arcs_cmdline[COMMAND_LINE_SIZE];
++
++void __init prom_init(int argc, char *argv[])
++{
++ int i;
++ unsigned int memcfg1;
++ int bank0AC, bank1AC;
++ int memsz_in_mb;
++ strcpy(arcs_cmdline, "console=ttyS0,9600");
++ for (i=0; i<argc; i++) {
++ strcat(arcs_cmdline, " ");
++ strcat(arcs_cmdline, argv[i]);
++ }
++
++ mips_machgroup = MACH_GROUP_AR531X;
++#ifdef CONFIG_APUNUSED
++ mips_machtype = MACH_ATHEROS_UNUSED;
++#endif
++#ifdef CONFIG_AP30
++ mips_machtype = MACH_ATHEROS_AP30;
++#endif
++#ifdef CONFIG_AP33
++ mips_machtype = MACH_ATHEROS_AP33;
++#endif
++#ifdef CONFIG_AP38
++ mips_machtype = MACH_ATHEROS_AP38;
++#endif
++#ifdef CONFIG_AP43
++ mips_machtype = MACH_ATHEROS_AP43;
++#endif
++#ifdef CONFIG_AP48
++ mips_machtype = MACH_ATHEROS_AP48;
++#endif
++#ifdef CONFIG_PB32
++ mips_machtype = MACH_ATHEROS_PB32;
++#endif
++
++
++ /* Determine SDRAM size based on Address Checks done at startup */
++#if CONFIG_AR5315
++ /* TO-DO : compute the SDRAM size */
++ memsz_in_mb=8;
++#else
++ memcfg1 = sysRegRead(AR531X_MEM_CFG1);
++ bank0AC = (memcfg1 & MEM_CFG1_AC0) >> MEM_CFG1_AC0_S;
++ bank1AC = (memcfg1 & MEM_CFG1_AC1) >> MEM_CFG1_AC1_S;
++ memsz_in_mb = (bank0AC ? (1 << (bank0AC+1)) : 0)
++ + (bank1AC ? (1 << (bank1AC+1)) : 0);
++#endif
++
++ /*
++ * By default, use all available memory. You can override this
++ * to use, say, 8MB by specifying "mem=8M" as an argument on the
++ * linux bootup command line.
++ */
++ add_memory_region(0, memsz_in_mb << 20, BOOT_MEM_RAM);
++}
++
++void __init prom_free_prom_memory(void)
++{
++}
+diff -urN linux-mips/arch/mips/ar531x/ar531xsetup.c mips-linux-2.4.25/arch/mips/ar531x/ar531xsetup.c
+--- linux-mips/arch/mips/ar531x/ar531xsetup.c 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/arch/mips/ar531x/ar531xsetup.c 2005-12-30 17:26:31.002823648 +0000
+@@ -0,0 +1,406 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * Initialization for ar531x SOC.
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/serial.h>
++#include <linux/types.h>
++#include <linux/string.h>
++
++#include <asm/reboot.h>
++#include <asm/io.h>
++#include <asm/time.h>
++#include <asm/pgtable.h>
++#include <asm/processor.h>
++#include <asm/reboot.h>
++#include <asm/system.h>
++#include <asm/serial.h>
++
++#include "ar531xlnx.h"
++
++void
++ar531x_restart(char *command)
++{
++ for(;;) {
++#if CONFIG_AR5315
++ /*
++ ** Cold reset does not work,work around is to use the GPIO reset bit.
++ */
++ unsigned int reg;
++ reg = sysRegRead(AR5315_GPIO_DO);
++ reg &= ~(1 << AR5315_RESET_GPIO);
++ sysRegWrite(AR5315_GPIO_DO, reg);
++ (void)sysRegRead(AR5315_GPIO_DO); /* flush write to hardware */
++
++#else
++ sysRegWrite(AR531X_RESET, AR531X_RESET_SYSTEM);
++#endif
++ }
++}
++
++void
++ar531x_halt(void)
++{
++ printk(KERN_NOTICE "\n** You can safely turn off the power\n");
++ while (1);
++}
++
++void
++ar531x_power_off(void)
++{
++ ar531x_halt();
++}
++
++const char *
++get_system_type(void)
++{
++#if CONFIG_AR5315
++ return "Atheros AR5315";
++#else
++ return "Atheros AR531X";
++#endif
++}
++
++/*
++ * This table is indexed by bits 5..4 of the CLOCKCTL1 register
++ * to determine the predevisor value.
++ */
++static int CLOCKCTL1_PREDIVIDE_TABLE[4] = {
++ 1,
++ 2,
++ 4,
++ 5
++};
++
++#if CONFIG_AR5315
++static int PLLC_DIVIDE_TABLE[5] = {
++ 2,
++ 3,
++ 4,
++ 6,
++ 3
++};
++
++unsigned int
++ar531x_cpu_frequency(void)
++{
++ static unsigned int ar531x_calculated_cpu_freq=0;
++ unsigned int clockCtl,pllcCtrl,cpuDiv;
++ unsigned int pllcOut,refdiv,fdiv,divby2;
++
++ if(ar531x_calculated_cpu_freq)
++ return ar531x_calculated_cpu_freq;
++
++
++ pllcCtrl = sysRegRead(AR5315_PLLC_CTL);
++ refdiv = (pllcCtrl & PLLC_REF_DIV_M) >> PLLC_REF_DIV_S;
++ refdiv = CLOCKCTL1_PREDIVIDE_TABLE[refdiv];
++ fdiv = (pllcCtrl & PLLC_FDBACK_DIV_M) >> PLLC_FDBACK_DIV_S;
++ divby2 = (pllcCtrl & PLLC_ADD_FDBACK_DIV_M) >> PLLC_ADD_FDBACK_DIV_S;
++ divby2 += 1;
++ pllcOut = (40000000/refdiv)*(2*divby2)*fdiv;
++
++ clockCtl = sysRegRead(AR5315_CPUCLK);
++
++ /* clkm input selected */
++ if((clockCtl & CPUCLK_CLK_SEL_M) == 0 || (clockCtl & CPUCLK_CLK_SEL_M) == 1 ) {
++ unsigned int clkMdiv;
++ clkMdiv = (pllcCtrl & PLLC_CLKM_DIV_M) >> PLLC_CLKM_DIV_S;
++ clkMdiv = PLLC_DIVIDE_TABLE[clkMdiv];
++
++ cpuDiv = (clockCtl & CPUCLK_CLK_DIV_M) >> CPUCLK_CLK_DIV_S;
++ if(cpuDiv) cpuDiv *= 2;
++ else cpuDiv=1;
++
++ ar531x_calculated_cpu_freq= (pllcOut/(clkMdiv * cpuDiv)) ;
++
++ return ar531x_calculated_cpu_freq;
++ }
++
++ /* clkc input selected */
++ if((clockCtl & CPUCLK_CLK_SEL_M) == 2 ) {
++ unsigned int clkCdiv;
++ clkCdiv = (pllcCtrl & PLLC_CLKC_DIV_M) >> PLLC_CLKC_DIV_S;
++ clkCdiv = PLLC_DIVIDE_TABLE[clkCdiv];
++
++ cpuDiv = (clockCtl & CPUCLK_CLK_DIV_M) >> CPUCLK_CLK_DIV_S;
++ if(cpuDiv) cpuDiv *= 2;
++ else cpuDiv=1;
++
++ ar531x_calculated_cpu_freq= (pllcOut/(clkCdiv * cpuDiv)) ;
++
++ return ar531x_calculated_cpu_freq;
++ } else { /* ref_clk selected */
++
++ cpuDiv = (clockCtl & CPUCLK_CLK_DIV_M) >> CPUCLK_CLK_DIV_S;
++ if(cpuDiv) cpuDiv *= 2;
++ else cpuDiv=1;
++
++ ar531x_calculated_cpu_freq= (40000000/(cpuDiv)) ;
++ return ar531x_calculated_cpu_freq;
++ }
++}
++
++unsigned int
++ar531x_apb_frequency(void)
++{
++ static unsigned int ar531x_calculated_cpu_freq=0;
++ unsigned int clockCtl,pllcCtrl,cpuDiv;
++ unsigned int pllcOut,refdiv,fdiv,divby2;
++
++ if(ar531x_calculated_cpu_freq)
++ return ar531x_calculated_cpu_freq;
++
++
++ pllcCtrl = sysRegRead(AR5315_PLLC_CTL);
++ refdiv = (pllcCtrl & PLLC_REF_DIV_M) >> PLLC_REF_DIV_S;
++ refdiv = CLOCKCTL1_PREDIVIDE_TABLE[refdiv];
++ fdiv = (pllcCtrl & PLLC_FDBACK_DIV_M) >> PLLC_FDBACK_DIV_S;
++ divby2 = (pllcCtrl & PLLC_ADD_FDBACK_DIV_M) >> PLLC_ADD_FDBACK_DIV_S;
++ divby2 += 1;
++ pllcOut = (40000000/refdiv)*(2*divby2)*fdiv;
++
++ clockCtl = sysRegRead(AR5315_AMBACLK);
++
++ /* clkm input selected */
++ if((clockCtl & CPUCLK_CLK_SEL_M) == 0 || (clockCtl & CPUCLK_CLK_SEL_M) == 1 ) {
++ unsigned int clkMdiv;
++ clkMdiv = (pllcCtrl & PLLC_CLKM_DIV_M) >> PLLC_CLKM_DIV_S;
++ clkMdiv = PLLC_DIVIDE_TABLE[clkMdiv];
++
++ cpuDiv = (clockCtl & CPUCLK_CLK_DIV_M) >> CPUCLK_CLK_DIV_S;
++ if(cpuDiv) cpuDiv *= 2;
++ else cpuDiv=1;
++
++ ar531x_calculated_cpu_freq= (pllcOut/(clkMdiv * cpuDiv)) ;
++
++ return ar531x_calculated_cpu_freq;
++ }
++
++ /* clkc input selected */
++ if((clockCtl & CPUCLK_CLK_SEL_M) == 2 ) {
++ unsigned int clkCdiv;
++ clkCdiv = (pllcCtrl & PLLC_CLKC_DIV_M) >> PLLC_CLKC_DIV_S;
++ clkCdiv = PLLC_DIVIDE_TABLE[clkCdiv];
++
++ cpuDiv = (clockCtl & CPUCLK_CLK_DIV_M) >> CPUCLK_CLK_DIV_S;
++ if(cpuDiv) cpuDiv *= 2;
++ else cpuDiv=1;
++
++ ar531x_calculated_cpu_freq= (pllcOut/(clkCdiv * cpuDiv)) ;
++
++ return ar531x_calculated_cpu_freq;
++ } else { /* ref_clk selected */
++
++ cpuDiv = (clockCtl & CPUCLK_CLK_DIV_M) >> CPUCLK_CLK_DIV_S;
++ if(cpuDiv) cpuDiv *= 2;
++ else cpuDiv=1;
++
++ ar531x_calculated_cpu_freq= (40000000/(cpuDiv)) ;
++ return ar531x_calculated_cpu_freq;
++ }
++}
++
++#else
++unsigned int
++ar531x_cpu_frequency(void)
++{
++ static unsigned int ar531x_calculated_cpu_freq;
++ unsigned int clockctl1_predivide_mask;
++ unsigned int clockctl1_predivide_shift;
++ unsigned int clockctl1_multiplier_mask;
++ unsigned int clockctl1_multiplier_shift;
++ unsigned int clockctl1_doubler_mask;
++ int wisoc_revision;
++
++ /*
++ * Trust the bootrom's idea of cpu frequency.
++ */
++ ar531x_calculated_cpu_freq = sysRegRead(AR5312_SCRATCH);
++ if (ar531x_calculated_cpu_freq)
++ return ar531x_calculated_cpu_freq;
++
++ wisoc_revision = (sysRegRead(AR531X_REV) & AR531X_REV_MAJ) >> AR531X_REV_MAJ_S;
++
++ if (wisoc_revision == AR531X_REV_MAJ_AR2313) {
++ clockctl1_predivide_mask = AR2313_CLOCKCTL1_PREDIVIDE_MASK;
++ clockctl1_predivide_shift = AR2313_CLOCKCTL1_PREDIVIDE_SHIFT;
++ clockctl1_multiplier_mask = AR2313_CLOCKCTL1_MULTIPLIER_MASK;
++ clockctl1_multiplier_shift = AR2313_CLOCKCTL1_MULTIPLIER_SHIFT;
++ clockctl1_doubler_mask = AR2313_CLOCKCTL1_DOUBLER_MASK;
++ } else { /* AR5312 and AR2312 */
++ clockctl1_predivide_mask = AR5312_CLOCKCTL1_PREDIVIDE_MASK;
++ clockctl1_predivide_shift = AR5312_CLOCKCTL1_PREDIVIDE_SHIFT;
++ clockctl1_multiplier_mask = AR5312_CLOCKCTL1_MULTIPLIER_MASK;
++ clockctl1_multiplier_shift = AR5312_CLOCKCTL1_MULTIPLIER_SHIFT;
++ clockctl1_doubler_mask = AR5312_CLOCKCTL1_DOUBLER_MASK;
++ }
++
++ /*
++ * Clocking is derived from a fixed 40MHz input clock.
++ * cpuFreq = InputClock * MULT (where MULT is PLL multiplier)
++ *
++ * sysFreq = cpuFreq / 4 (used for APB clock, serial,
++ * flash, Timer, Watchdog Timer)
++ *
++ * cntFreq = cpuFreq / 2 (use for CPU count/compare)
++ *
++ * So, for example, with a PLL multiplier of 5, we have
++ * cpuFrez = 200MHz
++ * sysFreq = 50MHz
++ * cntFreq = 100MHz
++ *
++ * We compute the CPU frequency, based on PLL settings.
++ */
++ if (ar531x_calculated_cpu_freq == 0) {
++ unsigned int clockCtl1 = sysRegRead(AR5312_CLOCKCTL1);
++
++ int preDivideSelect = (clockCtl1 & clockctl1_predivide_mask) >>
++ clockctl1_predivide_shift;
++
++ int preDivisor = CLOCKCTL1_PREDIVIDE_TABLE[preDivideSelect];
++
++ int multiplier = (clockCtl1 & clockctl1_multiplier_mask) >>
++ clockctl1_multiplier_shift;
++
++ if (clockCtl1 & clockctl1_doubler_mask) {
++ multiplier = multiplier << 1;
++ }
++
++ ar531x_calculated_cpu_freq = (40000000 / preDivisor) * multiplier;
++ }
++
++ return ar531x_calculated_cpu_freq;
++}
++#endif
++
++unsigned int
++ar531x_sys_frequency(void)
++{
++ static unsigned int ar531x_calculated_sys_freq = 0;
++
++ if (ar531x_calculated_sys_freq == 0) {
++ ar531x_calculated_sys_freq = ar531x_cpu_frequency() / 4;
++ }
++
++ return ar531x_calculated_sys_freq;
++}
++
++static void __init
++flash_setup(void)
++{
++ UINT32 flash_ctl;
++#ifndef CONFIG_AR5315
++ /* Configure flash bank 0 */
++ flash_ctl = FLASHCTL_E |
++ FLASHCTL_AC_8M |
++ FLASHCTL_RBLE |
++ (0x01 << FLASHCTL_IDCY_S) |
++ (0x07 << FLASHCTL_WST1_S) |
++ (0x07 << FLASHCTL_WST2_S) |
++ (sysRegRead(AR531X_FLASHCTL0) & FLASHCTL_MW);
++
++ sysRegWrite(AR531X_FLASHCTL0, flash_ctl);
++
++ /* Disable other flash banks */
++ sysRegWrite(AR531X_FLASHCTL1,
++ sysRegRead(AR531X_FLASHCTL1) & ~(FLASHCTL_E | FLASHCTL_AC));
++
++ sysRegWrite(AR531X_FLASHCTL2,
++ sysRegRead(AR531X_FLASHCTL2) & ~(FLASHCTL_E | FLASHCTL_AC));
++#endif
++}
++
++
++
++void __init
++serial_setup(void)
++{
++ struct serial_struct s;
++
++ memset(&s, 0, sizeof(s));
++
++ s.flags = STD_COM_FLAGS;
++ s.io_type = SERIAL_IO_MEM;
++#if CONFIG_AR5315
++ s.baud_base = ar531x_apb_frequency()/16;
++#else
++ s.baud_base = ar531x_sys_frequency()/16;
++#endif
++ s.irq = AR531X_MISC_IRQ_UART0;
++ s.iomem_reg_shift = 2;
++#if CONFIG_AR5315
++ s.iomem_base = (u8 *)AR5315_UART0;
++#else
++ s.iomem_base = (u8 *)AR531X_UART0;
++#endif
++
++ if (early_serial_setup(&s) != 0)
++ printk(KERN_ERR "early_serial_setup failed\n");
++}
++
++extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
++static void __init
++ar531x_timer_setup(struct irqaction *irq)
++{
++ unsigned int count;
++
++ /* Usually irq is timer_irqaction (timer_interrupt) */
++ setup_irq(AR531X_IRQ_CPU_CLOCK, irq);
++
++ /* to generate the first CPU timer interrupt */
++ count = read_c0_count();
++ write_c0_compare(count + 1000);
++}
++
++extern void (*board_time_init)(void);
++
++static void __init
++ar531x_time_init(void)
++{
++ mips_hpt_frequency = ar531x_cpu_frequency() / 2;
++}
++
++void __init
++ar531x_setup(void)
++{
++ /* Clear any lingering AHB errors */
++#if CONFIG_AR5315
++ unsigned int config = read_c0_config();
++ write_c0_config(config & ~0x3);
++ sysRegWrite(AR5315_AHB_ERR0,AHB_ERROR_DET);
++ sysRegRead(AR5315_AHB_ERR1);
++ sysRegWrite(AR5315_WDC, WDC_IGNORE_EXPIRATION);
++#else
++ sysRegRead(AR531X_PROCADDR);
++ sysRegRead(AR531X_DMAADDR);
++
++ sysRegWrite(AR531X_WD_CTRL, AR531X_WD_CTRL_IGNORE_EXPIRATION);
++
++#endif
++
++ /* Disable data watchpoints */
++ write_c0_watchlo0(0);
++
++ board_time_init = ar531x_time_init;
++ board_timer_setup = ar531x_timer_setup;
++
++ _machine_restart = ar531x_restart;
++ _machine_halt = ar531x_halt;
++ _machine_power_off = ar531x_power_off;
++
++ flash_setup();
++ serial_setup();
++}
+diff -urN linux-mips/arch/mips/ar531x/Makefile mips-linux-2.4.25/arch/mips/ar531x/Makefile
+--- linux-mips/arch/mips/ar531x/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/arch/mips/ar531x/Makefile 2005-12-30 17:26:29.912989328 +0000
+@@ -0,0 +1,33 @@
++#
++# This file is subject to the terms and conditions of the GNU General Public
++# License. See the file "COPYING" in the main directory of this archive
++# for more details.
++#
++# Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++#
++
++# Makefile for Atheros ar531x boards
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++
++.S.s:
++ $(CPP) $(CFLAGS) $< -o $*.s
++.S.o:
++ $(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $*.o
++
++O_TARGET:= ar531x.o
++
++export-objs = ar531xksyms.o
++
++obj-y := ar531xdbg_io.o \
++ ar531xsetup.o \
++ ar531xprom.o \
++ ar531xirq.o \
++ ar531xintr.o \
++ ar531xgpio.o \
++ ar531xksyms.o
++
++include $(TOPDIR)/Rules.make
+diff -urN linux-mips/arch/mips/ar531x/README mips-linux-2.4.25/arch/mips/ar531x/README
+--- linux-mips/arch/mips/ar531x/README 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/arch/mips/ar531x/README 2005-12-30 17:26:30.478903296 +0000
+@@ -0,0 +1,68 @@
++Basic information for the AR531X Board Support Package
++
++This directory contains the "LBSP" -- Linux Board Support Package --
++for Linux on the Atheros AR531X Wireless System-On-a-Chip. It is intended
++primarily as a building block for wireless products. At this time, the
++AR531X Linux BSP is experimental code, and is actively UNDER CONSTRUCTION.
++
++Some components that are supported by this LBSP along with a standard 2.4
++Linux MIPS kernel include
++ R4Kc CPU
++ instruction and data caches
++ SDRAM
++ flash (Macronix, AMD, STS, etc.)
++ 16550 serial port
++ ethernet MACs
++ ethernet PHY or PHY Switch (RealTek, Kendin, Marvell)
++ General-Purpose I/O pins
++ kernel debugging with kgdb
++
++This LBSP code does NOT include drivers for the wireless components of the
++chip/boards! Drivers for those components may be distributed separately.
++In particular, the MADWiFi project under SourceForge supports (not yet!)
++wireless functions on the AR531X chipset. See
++ http://www.sourceforge.net/projects/madwifi
++
++Files included in this BSP:
++ae531xlnx.c - Linux-specific portions of the ethernet driver
++ae531xmac.c - OS-independent AR531X ethernet MAC code
++ae531xmac.h - OS-independent AR531X ethernet MAC software definitions
++ae531xreg.h - OS-independent AR531X ethernet MAC hardware definitions
++ar531x.h - OS-independent AR531X system hardware definitions
++ar531xlnx.h - Linux-specific AR531X system definitions and externs
++defconfig-ar531x - Default Linux configuration file
++intr_recv.S - Linux interrupt "glue" code
++ar531xirq.c - Linux Interrupt Request management
++Makefile - Linux makefile
++mvPhy.c - OS-independent ethernet PHY code for Marvell Switch
++mvPhy.h - OS-independent ethernet PHY definitions for Marvell Switch
++ar531xprom.c - Linux prom "glue" code
++ar531xsetup.c - Linux startup code
++ar531xdbg_io.c - Support for kgdb-based debugging and for EARLY_PRINTK_HACK
++ar531xproc.c - Pseudo-device driver for /proc/ar531x device
++ar531xgpio.c - Support for General Purpose I/O pins
++ar531xwmacsl.c - Wireless MAC Support Layer
++
++Additional files, distributed with the BSP:
++README - This file
++README.BUILD - Instructions for building a linux kernel from source
++README.EXECUTE - Instructions for testing your linux kernel
++README.RAMDISK - Instructions for building a root ramdisk image
++
++ramdisk.gz - A binary ramdisk image, suitable for use with AR531X.
++DIFFS - Directory that contains "patch" files (See README.BUILD)
++
++
++There are several ways to boot a vmlinux image on an AR531X board:
++ -You can boot in over ethernet from the vxWorks bootrom, which is preloaded
++ on all Atheros boards
++ -You can use an ICE (e.g. VisionICE) to load the vmlinux image. You will
++ need appropriate register initialization (e.g. AP30.ini file)
++ -You can use the eCos RedBoot bootrom loader. This is a full-featured
++ bootrom which as been ported to AR531x. It can boot vmlinux over ethernet
++ or from flash. Source code is available from Atheros.
++
++Please send comments, corrections, complaints, criticisms, suggestions,
++enhancements, requests, or any other reasonable communications regarding
++this effort, to "linux@atheros.com". Your email will be received by a
++couple of engineers, and redirected as appropriate.
+diff -urN linux-mips/arch/mips/ar531x/README.BUILD mips-linux-2.4.25/arch/mips/ar531x/README.BUILD
+--- linux-mips/arch/mips/ar531x/README.BUILD 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/arch/mips/ar531x/README.BUILD 2005-12-30 17:26:30.478903296 +0000
+@@ -0,0 +1,47 @@
++ How to BUILD a linux kernel for an AR531X system
++
++It is expected that you will build Linux on an existing Linux system, which
++has all of the standard Linux tools.
++
++01) Obtain a MIPS BigEndian ELF gcc-compatible toolchain. For example,
++ if you're cross-compiling on a x86 Linux system, you could use:
++ ftp://ftp.mips.com/pub/tools/software/sde-for-linux/sdelinux-5.01-4eb.i386.rpm
++
++02) Obtain the latest working MIPS Linux kernel
++ cvs -d :pserver:cvs@ftp.linux-mips.org:/home/cvs login (password "cvs")
++ cvs -d :pserver:cvs@ftp.linux-mips.org:/home/cvs co -r linux_2_4 linux
++
++ Now "cd linux". The remainder of these instructions assume
++ that you are in the linux directory.
++
++03) Place the contents of this directory at arch/mips/ar531x.
++
++04) Use the patch command to patch generic linux files according
++ to the DIFFS directory
++ for i in arch/mips/ar531x/DIFFS/*.diff
++ do
++ patch -p1 < $i
++ done
++ NOTE: This version of the AR531X Linux BSP was tested with
++ MIPS Linux 2.4.22 as of 11/14/03. If you use a different
++ (e.g. more recent) version of Linux source, you may need to
++ resolve some minor patch and compilation issues.
++
++05) Set up a RAMDISK image.
++ See the instructions in README.RAMDISK.
++
++06) Set up a linux configuration using ar531x/defconfig-ar531x.
++ cp arch/mips/ar531x/defconfig-ar531x .config
++ make oldconfig (answer all questions that are asked)
++ NOTE: For development/debug purposes, you may want to
++ enable CONFIG_RUNTIME_DEBUG and CONFIG_KGDB.
++
++07) Make dependencies.
++ make dep
++
++08) Build the linux kernel
++ make
++
++09) The linux image you just built is in vmlinux.
++ See instructions in README.EXECUTE to run your vmlinux
++ image on an AP531X-based board.
+diff -urN linux-mips/arch/mips/ar531x/README.EXECUTE mips-linux-2.4.25/arch/mips/ar531x/README.EXECUTE
+--- linux-mips/arch/mips/ar531x/README.EXECUTE 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/arch/mips/ar531x/README.EXECUTE 2005-12-30 17:26:30.479903144 +0000
+@@ -0,0 +1,23 @@
++ How to EXECUTE a linux image on an AR531X system
++
++There are currently three ways to run you vmlinux image:
++ 1) Load it using the vxWorks bootrom that is supplied with the board.
++ You can load it over ethernet or from the TFFS file system, if you
++ have sufficient flash to store the image.
++ 2) Load it using an ICE (e.g. VisionICE).
++ 3) Use a bootrom loader, such as eCos RedBoot.
++
++After you have booted linux:
++ By default, the root filesystem on ramdisk is read-only.
++ To make it writable, use "mount -o remount w /".
++
++ The user-level commands are slightly non-standard, as they
++ are based on "busybox".
++
++ The "wget" command is included. You can use wget to fetch
++ files from any ftp server. So, for instance, you can fetch
++ a kernel module and then "insmod" it.
++
++Note that the standard source-level kernel debugger, kgdb, works well
++over the serial line with this port. We use kgdb and the kgdb_demux perl
++script -- available over the www -- for debugging.
+diff -urN linux-mips/arch/mips/ar531x/README.VERSION mips-linux-2.4.25/arch/mips/ar531x/README.VERSION
+--- linux-mips/arch/mips/ar531x/README.VERSION 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/arch/mips/ar531x/README.VERSION 2005-12-30 17:26:30.479903144 +0000
+@@ -0,0 +1 @@
++Source release last modified: 12/16/03
+diff -urN linux-mips/arch/mips/config-shared.in mips-linux-2.4.25/arch/mips/config-shared.in
+--- linux-mips/arch/mips/config-shared.in 2005-12-24 15:11:15.963885864 +0000
++++ mips-linux-2.4.25/arch/mips/config-shared.in 2005-12-30 17:26:31.611731080 +0000
+@@ -34,6 +34,7 @@
+ dep_bool 'Support for Alchemy PB1550 board' CONFIG_MIPS_PB1550 $CONFIG_MIPS32
+ dep_bool 'Support for Alchemy PB1200 board' CONFIG_MIPS_PB1200 $CONFIG_MIPS32
+ dep_bool 'Support for Alchemy Hydrogen3 board' CONFIG_MIPS_HYDROGEN3 $CONFIG_MIPS32
++dep_bool 'Support for Atheros AR5312/AR2312 WiSoC (EXPERIMENTAL)' CONFIG_AR531X $CONFIG_AR531X $CONFIG_EXPERIMENTAL
+ dep_bool 'Support for MyCable XXS1500 board' CONFIG_MIPS_XXS1500 $CONFIG_MIPS32
+ dep_bool 'Support for 4G Systems MTX-1 board' CONFIG_MIPS_MTX1 $CONFIG_MIPS32
+ dep_bool 'Support for Cogent CSB250 board' CONFIG_COGENT_CSB250 $CONFIG_MIPS32
+@@ -238,6 +239,63 @@
+ define_bool CONFIG_PC_KEYB y
+ define_bool CONFIG_OLD_TIME_C y
+ fi
++if [ "$CONFIG_AR531X" = "y" ]; then
++ define_bool CONFIG_IRQ_CPU y
++ define_bool CONFIG_CPU_R4X00 y
++ define_bool CONFIG_SERIAL y
++ define_bool CONFIG_NEW_IRQ y
++ define_bool CONFIG_NEW_TIME_C y
++ define_bool CONFIG_AR5312
++ define_bool CONFIG_NONCOHERENT_IO y
++ bool 'Enable early printk hack' CONFIG_EARLY_PRINTK_HACK
++ define_bool CONFIG_SCSI n
++ mainmenu_option next_comment
++ comment 'Board selection'
++ choice 'Board type' \
++ "UNKNOWN CONFIG_APUNKNOWN \
++ AP30 CONFIG_AP30 \
++ AP31 CONFIG_AP31 \
++ AP33 CONFIG_AP33 \
++ AP38 CONFIG_AP38 \
++ AP43 CONFIG_AP43 \
++ AP48 CONFIG_AP48 \
++ AP51 CONFIG_AP51 \
++ AP30-ASK CONFIG_AP30ASK" AP30
++ if [ "$CONFIG_AP30" = "y" -o "$CONFIG_AP30ASK" = "y" ]; then
++ define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 2
++ fi
++ if [ "$CONFIG_AP33" = "y" ]; then
++ define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 1
++ fi
++ if [ "$CONFIG_AP38" = "y" ]; then
++ define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 1
++ fi
++ if [ "$CONFIG_AP43" = "y" ]; then
++ define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 1
++ fi
++ if [ "$CONFIG_AP48" = "y" ]; then
++ define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 1
++ fi
++ if [ "$CONFIG_AP51" = "y" ]; then
++ define_int CONFIG_MTD_PHYSMAP_BUSWIDTH 1
++ define_bool CONFIG_MTD_REDBOOT_PARTS y
++ define_bool CONFIG_AR5315 y
++ define_bool CONFIG_MTD_SPIFLASH y
++ define_bool CONFIG_MTD_CFI n
++ define_bool CONFIG_MTD_JEDECPROBE n
++ define_bool CONFIG_MTD_CFI_INTELEXT n
++ define_bool CONFIG_MTD_CFI_AMDSTD n
++ define_bool CONFIG_MTD_OBSOLETE_CHIPS n
++ define_bool CONFIG_MTD_AMDSTD n
++ define_bool CONFIG_MTD_JEDEC n
++ define_bool CONFIG_MTD_PHYSMAP n
++ fi
++ mainmenu_option next_comment
++ comment 'Flash Selection'
++ choice 'Flash Size' \
++ "2MB CONFIG_FLASH_2MB \
++ 4MB CONFIG_FLASH_4MB" 2MB
++fi
+ if [ "$CONFIG_CASIO_E55" = "y" ]; then
+ define_bool CONFIG_IRQ_CPU y
+ define_bool CONFIG_NEW_TIME_C y
+
+diff -urN linux-mips/arch/mips/kernel/setup.c mips-linux-2.4.25/arch/mips/kernel/setup.c
+--- linux-mips/arch/mips/kernel/setup.c 2005-12-24 15:11:16.188851664 +0000
++++ mips-linux-2.4.25/arch/mips/kernel/setup.c 2005-12-30 17:26:33.536438480 +0000
+@@ -496,6 +496,7 @@
+ void hp_setup(void);
+ void au1x00_setup(void);
+ void frame_info_init(void);
++ void ar531x_setup(void);
+
+ frame_info_init();
+ #if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE)
+@@ -693,6 +694,12 @@
+ pmc_yosemite_setup();
+ break;
+ #endif
++
++#ifdef CONFIG_AR531X
++ case MACH_GROUP_AR531X:
++ ar531x_setup();
++ break;
++#endif
+ default:
+ panic("Unsupported architecture");
+ }
+diff -urN linux-mips/arch/mips/Makefile mips-linux-2.4.25/arch/mips/Makefile
+--- linux-mips/arch/mips/Makefile 2005-12-24 15:11:15.903894984 +0000
++++ mips-linux-2.4.25/arch/mips/Makefile 2005-12-30 17:26:29.911989480 +0000
+@@ -701,6 +701,17 @@
+ LOADADDR += 0x80020000
+ endif
+
++ifdef CONFIG_AR531X
++SUBDIRS += arch/mips/ar531x
++LIBS += arch/mips/ar531x/ar531x.o
++ifdef CONFIG_AP51
++LOADADDR += 0x80041000
++else
++LOADADDR += 0x80002000
++endif
++
++endif
++
+ #
+ # Choosing incompatible machines durings configuration will result in
+ # error messages during linking. Select a default linkscript if
+diff -urN linux-mips/ath_version.mk mips-linux-2.4.25/ath_version.mk
+--- linux-mips/ath_version.mk 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/ath_version.mk 2005-12-30 17:27:00.579327336 +0000
+@@ -0,0 +1 @@
++EXTRAVERSION=-LSDK-5.0.0-RC5
+diff -urN linux-mips/drivers/char/serial.c mips-linux-2.4.25/drivers/char/serial.c
+--- linux-mips/drivers/char/serial.c 2005-12-24 15:11:21.796999096 +0000
++++ mips-linux-2.4.25/drivers/char/serial.c 2005-12-30 17:27:10.815771160 +0000
+@@ -3441,7 +3441,7 @@
+
+ static _INLINE_ void show_serial_version(void)
+ {
+- printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name,
++ printk(KERN_INFO "%s version %s%s (%s) with%s\n", serial_name,
+ serial_version, LOCAL_VERSTRING, serial_revdate,
+ serial_options);
+ }
+@@ -5567,7 +5567,7 @@
+ printk(KERN_INFO"ttyS%02d%s at 0x%p (irq = %d) is a %s\n",
+ state->line + SERIAL_DEV_OFFSET,
+ (state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
+- state->iomem_base, state->irq,
++ (void *)state->iomem_base, state->irq,
+ uart_config[state->type].name);
+ }
+ else {
+diff -urN linux-mips/drivers/mtd/chips/cfi_cmdset_0002.c mips-linux-2.4.25/drivers/mtd/chips/cfi_cmdset_0002.c
+--- linux-mips/drivers/mtd/chips/cfi_cmdset_0002.c 2005-12-24 15:11:25.102496584 +0000
++++ mips-linux-2.4.25/drivers/mtd/chips/cfi_cmdset_0002.c 2005-12-30 17:27:21.333172272 +0000
+@@ -511,7 +511,7 @@
+ or tells us why it failed. */
+ dq6 = CMD(1<<6);
+ dq5 = CMD(1<<5);
+- timeo = jiffies + (HZ/1000); /* setting timeout to 1ms for now */
++ timeo = jiffies + (HZ/1000) + 1; /* setting timeout to 1ms for now */
+
+ oldstatus = cfi_read(map, adr);
+ status = cfi_read(map, adr);
+@@ -536,16 +536,18 @@
+ if( (status & dq5) == dq5 ) {
+ /* When DQ5 raises, we must check once again
+ if DQ6 is toggling. If not, the erase has been
+- completed OK. If not, reset chip. */
++ completed OK. But if so, reset chip. */
+ oldstatus = cfi_read(map, adr);
+ status = cfi_read(map, adr);
+
+ if ( (oldstatus & 0x00FF) == (status & 0x00FF) ) {
++#if 0
+ printk(KERN_WARNING "Warning: DQ5 raised while program operation was in progress, however operation completed OK\n" );
++#endif
+ } else {
+ /* DQ5 is active so we can do a reset and stop the erase */
+ cfi_write(map, CMD(0xF0), chip->start);
+- printk(KERN_WARNING "Internal flash device timeout occurred or write operation was performed while flash was programming.\n" );
++ printk(KERN_WARNING "Internal flash device timeout pt A occurred or write operation was performed while flash was programming. timeout=%d\n",chip->word_write_time );
+ }
+ } else {
+ printk(KERN_WARNING "Waiting for write to complete timed out in do_write_oneword.");
+@@ -959,7 +961,7 @@
+ {
+ /* DQ5 is active so we can do a reset and stop the erase */
+ cfi_write(map, CMD(0xF0), chip->start);
+- printk( KERN_WARNING "Internal flash device timeout occured or write operation was performed while flash was erasing\n" );
++ printk( KERN_WARNING "Internal flash device timeout pt B occured or write operation was performed while flash was erasing\n" );
+ }
+ }
+ else
+diff -urN linux-mips/drivers/mtd/chips/cfi_probe.c mips-linux-2.4.25/drivers/mtd/chips/cfi_probe.c
+--- linux-mips/drivers/mtd/chips/cfi_probe.c 2005-12-24 15:11:25.103496432 +0000
++++ mips-linux-2.4.25/drivers/mtd/chips/cfi_probe.c 2005-12-30 17:27:21.507145824 +0000
+@@ -51,7 +51,7 @@
+ struct flchip *chips, struct cfi_private *cfi)
+ {
+ int i;
+-
++
+ if ((base + 0) >= map->size) {
+ printk(KERN_NOTICE
+ "Probe at base[0x00](0x%08lx) past the end of the map(0x%08lx)\n",
+@@ -221,12 +221,10 @@
+
+ static void print_cfi_ident(struct cfi_ident *cfip)
+ {
+-#if 0
+ if (cfip->qry[0] != 'Q' || cfip->qry[1] != 'R' || cfip->qry[2] != 'Y') {
+ printk("Invalid CFI ident structure.\n");
+ return;
+ }
+-#endif
+ printk("Primary Vendor Command Set: %4.4X (%s)\n", cfip->P_ID, vendorname(cfip->P_ID));
+ if (cfip->P_ADR)
+ printk("Primary Algorithm Table at %4.4X\n", cfip->P_ADR);
+diff -urN linux-mips/drivers/mtd/chips/jedec_probe.c mips-linux-2.4.25/drivers/mtd/chips/jedec_probe.c
+--- linux-mips/drivers/mtd/chips/jedec_probe.c 2005-12-24 15:11:25.126492936 +0000
++++ mips-linux-2.4.25/drivers/mtd/chips/jedec_probe.c 2005-12-30 17:27:21.532142024 +0000
+@@ -104,6 +104,7 @@
+ #define SST29LE512 0x003d
+ #define SST39LF800 0x2781
+ #define SST39LF160 0x2782
++#define SST39LF1601 0x234b
+ #define SST39LF512 0x00D4
+ #define SST39LF010 0x00D5
+ #define SST39LF020 0x00D6
+@@ -113,6 +114,8 @@
+ #define SST49LF030A 0x001C
+ #define SST49LF040A 0x0051
+ #define SST49LF080A 0x005B
++#define SST39VF3201 0x235B
++#define SST39VF3202 0x235A
+
+ /* Toshiba */
+ #define TC58FVT160 0x00C2
+@@ -900,7 +903,43 @@
+ NumEraseRegions: 1,
+ regions: {ERASEINFO(0x01000,256),
+ }
+- }
++ }, {
++ mfr_id: MANUFACTURER_SST,
++ dev_id: SST39LF160,
++ name: "SST 39LF160",
++ DevSize: SIZE_2MiB,
++ CmdSet: P_ID_AMD_STD,
++ NumEraseRegions: 1,
++ regions: {ERASEINFO(0x01000,512),
++ }
++ }, {
++ mfr_id: MANUFACTURER_SST,
++ dev_id: SST39LF1601,
++ name: "SST 39LF1601",
++ DevSize: SIZE_2MiB,
++ CmdSet: P_ID_AMD_STD,
++ NumEraseRegions: 1,
++ regions: {ERASEINFO(0x01000,512),
++ }
++ }, {
++ mfr_id: MANUFACTURER_SST,
++ dev_id: SST39VF3201,
++ name: "SST 39VF3201",
++ DevSize: SIZE_4MiB,
++ CmdSet: P_ID_AMD_STD,
++ NumEraseRegions: 1,
++ regions: {ERASEINFO(0x01000,1024),
++ }
++ }, {
++ mfr_id: MANUFACTURER_SST,
++ dev_id: SST39VF3202,
++ name: "SST 39VF3202",
++ DevSize: SIZE_4MiB,
++ CmdSet: P_ID_AMD_STD,
++ NumEraseRegions: 1,
++ regions: {ERASEINFO(0x01000,1024),
++ }
++ }
+ };
+
+
+@@ -967,6 +1006,35 @@
+ p_cfi->cfiq->DevSize = jedec_table[index].DevSize;
+ p_cfi->cfi_mode = CFI_MODE_JEDEC;
+
++ /*
++ * Add the following code to set the flash timing parameters.
++ * Maybe this is done in a table somwehere else? I can't find it.
++ */
++
++
++ switch(jedec_table[index].dev_id) {
++ case SST39VF3201:
++ case SST39VF3202:
++ p_cfi->cfiq->WordWriteTimeoutTyp = 3; /* 8 us */
++ p_cfi->cfiq->WordWriteTimeoutMax = 4; /* 16 us */
++ p_cfi->cfiq->BlockEraseTimeoutTyp = 15; /* Actually 18ms, max 25 */
++ p_cfi->cfiq->BlockEraseTimeoutMax = 15; /* Actually 25ms */
++ p_cfi->cfiq->ChipEraseTimeoutTyp = 16; /* Max is 50ms, typical is 40ms */
++ p_cfi->cfiq->ChipEraseTimeoutMax = 16;
++ break;
++ case SST39LF160:
++ case SST39LF1601:
++ p_cfi->cfiq->WordWriteTimeoutTyp = 4; /* 14 us */
++ p_cfi->cfiq->WordWriteTimeoutMax = 5; /* 20 us */
++ p_cfi->cfiq->BlockEraseTimeoutTyp = 15; /* Actually 18ms, max 25 */
++ p_cfi->cfiq->BlockEraseTimeoutMax = 15; /* Actually 25ms */
++ p_cfi->cfiq->ChipEraseTimeoutTyp = 17; /* Max is 70ms, typical is 40ms */
++ p_cfi->cfiq->ChipEraseTimeoutMax = 17;
++ break;
++ }
++
++
++
+ for (i=0; i<num_erase_regions; i++){
+ p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i];
+ }
+diff -urN linux-mips/drivers/mtd/Config.in mips-linux-2.4.25/drivers/mtd/Config.in
+--- linux-mips/drivers/mtd/Config.in 2005-12-24 15:11:25.091498256 +0000
++++ mips-linux-2.4.25/drivers/mtd/Config.in 2005-12-30 17:27:21.182195224 +0000
+@@ -14,6 +14,9 @@
+ dep_tristate ' MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD
+ dep_tristate ' MTD concatenating support' CONFIG_MTD_CONCAT $CONFIG_MTD
+ dep_tristate ' RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS
++ if [ "$CONFIG_MTD_END_RESERVED" != "" ]; then
++ define_int CONFIG_MTD_END_RESERVED $CONFIG_MTD_END_RESERVED
++ fi
+ dep_tristate ' Command line partition table parsing' CONFIG_MTD_CMDLINE_PARTS $CONFIG_MTD_PARTITIONS
+ if [ "$CONFIG_ARM" = "y" ]; then
+ dep_tristate ' ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS
+diff -urN linux-mips/drivers/mtd/devices/Makefile mips-linux-2.4.25/drivers/mtd/devices/Makefile
+--- linux-mips/drivers/mtd/devices/Makefile 2005-12-24 15:11:25.128492632 +0000
++++ mips-linux-2.4.25/drivers/mtd/devices/Makefile 2005-12-30 17:27:21.561137616 +0000
+@@ -22,5 +22,6 @@
+ obj-$(CONFIG_MTD_MTDRAM) += mtdram.o
+ obj-$(CONFIG_MTD_LART) += lart.o
+ obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o
++obj-$(CONFIG_MTD_SPIFLASH) += spiflash.o
+
+ include $(TOPDIR)/Rules.make
+diff -urN linux-mips/drivers/mtd/devices/spiflash.c mips-linux-2.4.25/drivers/mtd/devices/spiflash.c
+--- linux-mips/drivers/mtd/devices/spiflash.c 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/drivers/mtd/devices/spiflash.c 2005-12-30 17:27:21.652123784 +0000
+@@ -0,0 +1,506 @@
++
++/*
++ * MTD driver for the SPI Flash Memory support.
++ *
++ * $Id: //depot/sw/releases/linuxsrc/src/kernels/mips-linux-2.4.25/drivers/mtd/devices/spiflash.c#3 $
++ *
++ *
++ * Copyright (c) 2005-2006 Atheros Communications Inc.
++ *
++ * This code is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++/*===========================================================================
++** !!!! VERY IMPORTANT NOTICE !!!! FLASH DATA STORED IN LITTLE ENDIAN FORMAT
++**
++** This module contains the Serial Flash access routines for the Atheros SOC.
++** The Atheros SOC integrates a SPI flash controller that is used to access
++** serial flash parts. The SPI flash controller executes in "Little Endian"
++** mode. THEREFORE, all WRITES and READS from the MIPS CPU must be
++** BYTESWAPPED! The SPI Flash controller hardware by default performs READ
++** ONLY byteswapping when accessed via the SPI Flash Alias memory region
++** (Physical Address 0x0800_0000 - 0x0fff_ffff). The data stored in the
++** flash sectors is stored in "Little Endian" format.
++**
++** The spiflash_write() routine performs byteswapping on all write
++** operations.
++**===========================================================================*/
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/version.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <asm/delay.h>
++#include <asm/io.h>
++#include "spiflash.h"
++
++/* debugging */
++/* #define SPIFLASH_DEBUG */
++
++#ifndef __BIG_ENDIAN
++#error This driver currently only works with big endian CPU.
++#endif
++
++static char module_name[] = "spiflash";
++
++#define MIN(a,b) ((a) < (b) ? (a) : (b))
++#define FALSE 0
++#define TRUE 1
++
++#define ROOTFS_NAME "rootfs"
++
++static __u32 spiflash_regread32(int reg);
++static void spiflash_regwrite32(int reg, __u32 data);
++static __u32 spiflash_sendcmd (int op);
++
++int __init spiflash_init (void);
++void __exit spiflash_exit (void);
++static int spiflash_probe (void);
++static int spiflash_erase (struct mtd_info *mtd,struct erase_info *instr);
++static int spiflash_read (struct mtd_info *mtd, loff_t from,size_t len,size_t *retlen,u_char *buf);
++static int spiflash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf);
++
++/* Flash configuration table */
++struct flashconfig {
++ __u32 byte_cnt;
++ __u32 sector_cnt;
++ __u32 sector_size;
++ __u32 cs_addrmask;
++} flashconfig_tbl[MAX_FLASH] =
++ {
++ { 0, 0, 0, 0},
++ { STM_1MB_BYTE_COUNT, STM_1MB_SECTOR_COUNT, STM_1MB_SECTOR_SIZE, 0x0},
++ { STM_2MB_BYTE_COUNT, STM_2MB_SECTOR_COUNT, STM_2MB_SECTOR_SIZE, 0x0},
++ { STM_4MB_BYTE_COUNT, STM_4MB_SECTOR_COUNT, STM_4MB_SECTOR_SIZE, 0x0}
++ };
++
++/* Mapping of generic opcodes to STM serial flash opcodes */
++struct opcodes {
++ __u16 code;
++ __s8 tx_cnt;
++ __s8 rx_cnt;
++} stm_opcodes[] = {
++ {STM_OP_WR_ENABLE, 1, 0},
++ {STM_OP_WR_DISABLE, 1, 0},
++ {STM_OP_RD_STATUS, 1, 1},
++ {STM_OP_WR_STATUS, 1, 0},
++ {STM_OP_RD_DATA, 4, 4},
++ {STM_OP_FAST_RD_DATA, 1, 0},
++ {STM_OP_PAGE_PGRM, 8, 0},
++ {STM_OP_SECTOR_ERASE, 4, 0},
++ {STM_OP_BULK_ERASE, 1, 0},
++ {STM_OP_DEEP_PWRDOWN, 1, 0},
++ {STM_OP_RD_SIG, 4, 1}
++};
++
++/* Driver private data structure */
++struct spiflash_data {
++ struct mtd_info *mtd;
++ struct mtd_partition *parsed_parts; /* parsed partitions */
++ void *spiflash_readaddr; /* memory mapped data for read */
++ void *spiflash_mmraddr; /* memory mapped register space */
++};
++
++static struct spiflash_data *spidata;
++
++extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
++
++/***************************************************************************************************/
++
++static __u32
++spiflash_regread32(int reg)
++{
++ volatile __u32 *data = (__u32 *)(spidata->spiflash_mmraddr + reg);
++
++ return (*data);
++}
++
++static void
++spiflash_regwrite32(int reg, __u32 data)
++{
++ volatile __u32 *addr = (__u32 *)(spidata->spiflash_mmraddr + reg);
++
++ *addr = data;
++ return;
++}
++
++static __u32
++spiflash_sendcmd (int op)
++{
++ __u32 reg;
++ __u32 mask;
++ struct opcodes *ptr_opcode;
++
++ ptr_opcode = &stm_opcodes[op];
++
++ do {
++ reg = spiflash_regread32(SPI_FLASH_CTL);
++ } while (reg & SPI_CTL_BUSY);
++
++ spiflash_regwrite32(SPI_FLASH_OPCODE, ptr_opcode->code);
++
++ reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | ptr_opcode->tx_cnt |
++ (ptr_opcode->rx_cnt << 4) | SPI_CTL_START;
++
++ spiflash_regwrite32(SPI_FLASH_CTL, reg);
++
++ if (ptr_opcode->rx_cnt > 0) {
++ do {
++ reg = spiflash_regread32(SPI_FLASH_CTL);
++ } while (reg & SPI_CTL_BUSY);
++
++ reg = (__u32) spiflash_regread32(SPI_FLASH_DATA);
++
++ switch (ptr_opcode->rx_cnt) {
++ case 1:
++ mask = 0x000000ff;
++ break;
++ case 2:
++ mask = 0x0000ffff;
++ break;
++ case 3:
++ mask = 0x00ffffff;
++ break;
++ default:
++ mask = 0xffffffff;
++ break;
++ }
++
++ reg &= mask;
++ }
++ else {
++ reg = 0;
++ }
++
++ return reg;
++}
++
++/* Probe SPI flash device
++ * Function returns 0 for failure.
++ * and flashconfig_tbl array index for success.
++ */
++static int
++spiflash_probe (void)
++{
++ __u32 sig;
++ int flash_size;
++
++ /* Read the signature on the flash device */
++ sig = spiflash_sendcmd(SPI_RD_SIG);
++
++ switch (sig) {
++ case STM_8MBIT_SIGNATURE:
++ flash_size = FLASH_1MB;
++ break;
++ case STM_16MBIT_SIGNATURE:
++ flash_size = FLASH_2MB;
++ break;
++ case STM_32MBIT_SIGNATURE:
++ flash_size = FLASH_4MB;
++ break;
++ default:
++ printk (KERN_WARNING "%s: Read of flash device signature failed!\n", module_name);
++ return (0);
++ }
++
++ return (flash_size);
++}
++
++
++static int
++spiflash_erase (struct mtd_info *mtd,struct erase_info *instr)
++{
++ struct opcodes *ptr_opcode;
++ __u32 temp, reg;
++ int finished = FALSE;
++
++#ifdef SPIFLASH_DEBUG
++ printk (KERN_DEBUG "%s(addr = 0x%.8x, len = %d)\n",__FUNCTION__,instr->addr,instr->len);
++#endif
++
++ /* sanity checks */
++ if (instr->addr + instr->len > mtd->size) return (-EINVAL);
++
++ ptr_opcode = &stm_opcodes[SPI_SECTOR_ERASE];
++
++ temp = ((__u32)instr->addr << 8) | (__u32)(ptr_opcode->code);
++ spiflash_sendcmd(SPI_WRITE_ENABLE);
++ do {
++ reg = spiflash_regread32(SPI_FLASH_CTL);
++ } while (reg & SPI_CTL_BUSY);
++
++ spiflash_regwrite32(SPI_FLASH_OPCODE, temp);
++
++ reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | ptr_opcode->tx_cnt | SPI_CTL_START;
++ spiflash_regwrite32(SPI_FLASH_CTL, reg);
++
++ do {
++ reg = spiflash_sendcmd(SPI_RD_STATUS);
++ if (!(reg & SPI_STATUS_WIP)) {
++ finished = TRUE;
++ }
++ } while (!finished);
++
++ instr->state = MTD_ERASE_DONE;
++ if (instr->callback) instr->callback (instr);
++
++#ifdef SPIFLASH_DEBUG
++ printk (KERN_DEBUG "%s return\n",__FUNCTION__);
++#endif
++ return (0);
++}
++
++static int
++spiflash_read (struct mtd_info *mtd, loff_t from,size_t len,size_t *retlen,u_char *buf)
++{
++ u_char *read_addr;
++
++#ifdef SPIFLASH_DEBUG
++ printk (KERN_DEBUG "%s(from = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) from,(int)len);
++#endif
++
++ /* sanity checks */
++ if (!len) return (0);
++ if (from + len > mtd->size) return (-EINVAL);
++
++
++ /* we always read len bytes */
++ *retlen = len;
++
++ read_addr = (u_char *)(spidata->spiflash_readaddr + from);
++ memcpy(buf, read_addr, len);
++
++ return (0);
++}
++
++static int
++spiflash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf)
++{
++ int done = FALSE, page_offset, bytes_left, finished;
++ __u32 xact_len, spi_data = 0, opcode, reg;
++
++#ifdef SPIFLASH_DEBUG
++ printk (KERN_DEBUG "%s(to = 0x%.8x, len = %d)\n",__FUNCTION__,(__u32) to,len);
++#endif
++
++ *retlen = 0;
++
++ /* sanity checks */
++ if (!len) return (0);
++ if (to + len > mtd->size) return (-EINVAL);
++
++ opcode = stm_opcodes[SPI_PAGE_PROGRAM].code;
++ bytes_left = len;
++
++ while (done == FALSE) {
++ xact_len = MIN(bytes_left, sizeof(__u32));
++
++ /* 32-bit writes cannot span across a page boundary
++ * (256 bytes). This types of writes require two page
++ * program operations to handle it correctly. The STM part
++ * will write the overflow data to the beginning of the
++ * current page as opposed to the subsequent page.
++ */
++ page_offset = (to & (STM_PAGE_SIZE - 1)) + xact_len;
++
++ if (page_offset > STM_PAGE_SIZE) {
++ xact_len -= (page_offset - STM_PAGE_SIZE);
++ }
++
++ spiflash_sendcmd(SPI_WRITE_ENABLE);
++
++ do {
++ reg = spiflash_regread32(SPI_FLASH_CTL);
++ } while (reg & SPI_CTL_BUSY);
++
++ switch (xact_len) {
++ case 1:
++ (__u8)spi_data = *buf;
++ break;
++ case 2:
++ spi_data = (buf[1] << 8) | buf[0];
++ break;
++ case 3:
++ spi_data = (buf[2] << 16) | (buf[1] << 8) | buf[0];
++ break;
++ case 4:
++ spi_data = (buf[3] << 24) | (buf[2] << 16) |
++ (buf[1] << 8) | buf[0];
++ break;
++ default:
++ printk("spiflash_write: default case\n");
++ break;
++ }
++
++ spiflash_regwrite32(SPI_FLASH_DATA, spi_data);
++ opcode = (opcode & SPI_OPCODE_MASK) | ((__u32)to << 8);
++ spiflash_regwrite32(SPI_FLASH_OPCODE, opcode);
++
++ reg = (reg & ~SPI_CTL_TX_RX_CNT_MASK) | (xact_len + 4) | SPI_CTL_START;
++ spiflash_regwrite32(SPI_FLASH_CTL, reg);
++ finished = FALSE;
++
++ do {
++ udelay(1);
++ reg = spiflash_sendcmd(SPI_RD_STATUS);
++ if (!(reg & SPI_STATUS_WIP)) {
++ finished = TRUE;
++ }
++ } while (!finished);
++
++ bytes_left -= xact_len;
++ to += xact_len;
++ buf += xact_len;
++
++ *retlen += xact_len;
++
++ if (bytes_left == 0) {
++ done = TRUE;
++ }
++ }
++
++ return (0);
++}
++
++
++int __init
++spiflash_init (void)
++{
++ int result, i;
++ int index, num_parts;
++ struct mtd_info *mtd;
++ struct mtd_partition *mtd_parts;
++
++ spidata = kmalloc(sizeof(struct spiflash_data), GFP_KERNEL);
++ if (!spidata)
++ return (-ENXIO);
++
++ spidata->spiflash_mmraddr = ioremap_nocache(SPI_FLASH_MMR, SPI_FLASH_MMR_SIZE);
++ if (!spidata->spiflash_mmraddr) {
++ printk (KERN_WARNING "%s: Failed to map flash device\n", module_name);
++ kfree(spidata);
++ return (-ENXIO);
++ }
++
++ mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
++ if (!mtd) {
++ kfree(spidata);
++ return (-ENXIO);
++ }
++
++ memset (mtd,0,sizeof (*mtd));
++
++ printk ("MTD driver for SPI flash.\n");
++ printk ("%s: Probing for Serial flash ...\n", module_name);
++ if (!(index = spiflash_probe ())) {
++ printk (KERN_WARNING "%s: Found no serial flash device\n", module_name);
++ kfree(mtd);
++ kfree(spidata);
++ return (-ENXIO);
++ }
++ printk ("%s: Found SPI serial Flash.\n", module_name);
++ printk ("%d: size\n", flashconfig_tbl[index].byte_cnt);
++
++ spidata->spiflash_readaddr = ioremap_nocache(SPI_FLASH_READ, flashconfig_tbl[index].byte_cnt);
++ if (!spidata->spiflash_readaddr) {
++ printk (KERN_WARNING "%s: Failed to map flash device\n", module_name);
++ kfree(mtd);
++ kfree(spidata);
++ return (-ENXIO);
++ }
++
++ mtd->name = module_name;
++ mtd->type = MTD_NORFLASH;
++ mtd->flags = (MTD_CAP_NORFLASH|MTD_WRITEABLE);
++ mtd->size = flashconfig_tbl[index].byte_cnt;
++ mtd->erasesize = flashconfig_tbl[index].sector_size;
++ mtd->numeraseregions = 0;
++ mtd->eraseregions = NULL;
++ mtd->module = THIS_MODULE;
++ mtd->erase = spiflash_erase;
++ mtd->read = spiflash_read;
++ mtd->write = spiflash_write;
++
++#ifdef SPIFLASH_DEBUG
++ printk (KERN_DEBUG
++ "mtd->name = %s\n"
++ "mtd->size = 0x%.8x (%uM)\n"
++ "mtd->erasesize = 0x%.8x (%uK)\n"
++ "mtd->numeraseregions = %d\n",
++ mtd->name,
++ mtd->size, mtd->size / (1024*1024),
++ mtd->erasesize, mtd->erasesize / 1024,
++ mtd->numeraseregions);
++
++ if (mtd->numeraseregions) {
++ for (result = 0; result < mtd->numeraseregions; result++) {
++ printk (KERN_DEBUG
++ "\n\n"
++ "mtd->eraseregions[%d].offset = 0x%.8x\n"
++ "mtd->eraseregions[%d].erasesize = 0x%.8x (%uK)\n"
++ "mtd->eraseregions[%d].numblocks = %d\n",
++ result,mtd->eraseregions[result].offset,
++ result,mtd->eraseregions[result].erasesize,mtd->eraseregions[result].erasesize / 1024,
++ result,mtd->eraseregions[result].numblocks);
++ }
++ }
++#endif
++
++#ifndef CONFIG_BLK_DEV_INITRD
++ /* parse redboot partitions */
++ num_parts = parse_redboot_partitions(mtd, &spidata->parsed_parts);
++
++#ifdef SPIFLASH_DEBUG
++ printk (KERN_DEBUG "Found %d redboot partitions\n", num_parts);
++#endif
++
++ if (num_parts) {
++ result = add_mtd_partitions(mtd, spidata->parsed_parts, num_parts);
++ /* Find root partition */
++ mtd_parts = spidata->parsed_parts;
++ for (i=0; i < num_parts; i++) {
++ if (!strcmp(mtd_parts[i].name, ROOTFS_NAME)) {
++ /* Create root device */
++ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, i);
++ break;
++ }
++ }
++ } else {
++#ifdef SPIFLASH_DEBUG
++ printk (KERN_DEBUG "Did not find any redboot partitions\n");
++#endif
++ kfree(mtd);
++ kfree(spidata);
++ return (-ENXIO);
++ }
++#endif
++
++ spidata->mtd = mtd;
++
++ return (result);
++}
++
++void __exit
++spiflash_exit (void)
++{
++ if (spidata && spidata->parsed_parts) {
++ del_mtd_partitions (spidata->mtd);
++ kfree(spidata->mtd);
++ kfree(spidata);
++ }
++}
++
++module_init (spiflash_init);
++module_exit (spiflash_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Atheros Communications Inc");
++MODULE_DESCRIPTION("MTD driver for SPI Flash on Atheros SOC");
++
+diff -urN linux-mips/drivers/mtd/devices/spiflash.h mips-linux-2.4.25/drivers/mtd/devices/spiflash.h
+--- linux-mips/drivers/mtd/devices/spiflash.h 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/drivers/mtd/devices/spiflash.h 2005-12-30 17:27:21.652123784 +0000
+@@ -0,0 +1,113 @@
++/*
++ * SPI Flash Memory support header file.
++ *
++ * $Id: //depot/sw/releases/linuxsrc/src/kernels/mips-linux-2.4.25/drivers/mtd/devices/spiflash.h#3 $
++ *
++ *
++ * Copyright (c) 2005, Atheros Communications Inc.
++ *
++ * This code is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++#define FLASH_1MB 1
++#define FLASH_2MB 2
++#define FLASH_4MB 3
++#define MAX_FLASH 4
++
++#define STM_PAGE_SIZE 256
++
++#define STM_8MBIT_SIGNATURE 0x13
++#define STM_M25P80_BYTE_COUNT 1048576
++#define STM_M25P80_SECTOR_COUNT 16
++#define STM_M25P80_SECTOR_SIZE 0x10000
++
++#define STM_16MBIT_SIGNATURE 0x14
++#define STM_M25P16_BYTE_COUNT 2097152
++#define STM_M25P16_SECTOR_COUNT 32
++#define STM_M25P16_SECTOR_SIZE 0x10000
++
++#define STM_32MBIT_SIGNATURE 0x15
++#define STM_M25P32_BYTE_COUNT 4194304
++#define STM_M25P32_SECTOR_COUNT 64
++#define STM_M25P32_SECTOR_SIZE 0x10000
++
++#define STM_1MB_BYTE_COUNT STM_M25P80_BYTE_COUNT
++#define STM_1MB_SECTOR_COUNT STM_M25P80_SECTOR_COUNT
++#define STM_1MB_SECTOR_SIZE STM_M25P80_SECTOR_SIZE
++#define STM_2MB_BYTE_COUNT STM_M25P16_BYTE_COUNT
++#define STM_2MB_SECTOR_COUNT STM_M25P16_SECTOR_COUNT
++#define STM_2MB_SECTOR_SIZE STM_M25P16_SECTOR_SIZE
++#define STM_4MB_BYTE_COUNT STM_M25P32_BYTE_COUNT
++#define STM_4MB_SECTOR_COUNT STM_M25P32_SECTOR_COUNT
++#define STM_4MB_SECTOR_SIZE STM_M25P32_SECTOR_SIZE
++
++#define SPI_WRITE_ENABLE 0
++#define SPI_WRITE_DISABLE 1
++#define SPI_RD_STATUS 2
++#define SPI_WR_STATUS 3
++#define SPI_RD_DATA 4
++#define SPI_FAST_RD_DATA 5
++#define SPI_PAGE_PROGRAM 6
++#define SPI_SECTOR_ERASE 7
++#define SPI_BULK_ERASE 8
++#define SPI_DEEP_PWRDOWN 9
++#define SPI_RD_SIG 10
++#define SPI_MAX_OPCODES 11
++
++#define SFI_WRITE_BUFFER_SIZE 4
++#define SFI_FLASH_ADDR_MASK 0x00ffffff
++
++/*
++ * ST Microelectronics Opcodes for Serial Flash
++ */
++
++#define STM_OP_WR_ENABLE 0x06 /* Write Enable */
++#define STM_OP_WR_DISABLE 0x04 /* Write Disable */
++#define STM_OP_RD_STATUS 0x05 /* Read Status */
++#define STM_OP_WR_STATUS 0x01 /* Write Status */
++#define STM_OP_RD_DATA 0x03 /* Read Data */
++#define STM_OP_FAST_RD_DATA 0x0b /* Fast Read Data */
++#define STM_OP_PAGE_PGRM 0x02 /* Page Program */
++#define STM_OP_SECTOR_ERASE 0xd8 /* Sector Erase */
++#define STM_OP_BULK_ERASE 0xc7 /* Bulk Erase */
++#define STM_OP_DEEP_PWRDOWN 0xb9 /* Deep Power-Down Mode */
++#define STM_OP_RD_SIG 0xab /* Read Electronic Signature */
++
++#define STM_STATUS_WIP 0x01 /* Write-In-Progress */
++#define STM_STATUS_WEL 0x02 /* Write Enable Latch */
++#define STM_STATUS_BP0 0x04 /* Block Protect 0 */
++#define STM_STATUS_BP1 0x08 /* Block Protect 1 */
++#define STM_STATUS_BP2 0x10 /* Block Protect 2 */
++#define STM_STATUS_SRWD 0x80 /* Status Register Write Disable */
++
++/*
++ * SPI Flash Interface Registers
++ */
++#define AR531XPLUS_SPI_READ 0x1fc00000
++#define AR531XPLUS_SPI_MMR 0x11300000
++#define AR531XPLUS_SPI_MMR_SIZE 12
++
++#define AR531XPLUS_SPI_CTL 0x00
++#define AR531XPLUS_SPI_OPCODE 0x04
++#define AR531XPLUS_SPI_DATA 0x08
++
++#define SPI_FLASH_READ AR531XPLUS_SPI_READ
++#define SPI_FLASH_MMR AR531XPLUS_SPI_MMR
++#define SPI_FLASH_MMR_SIZE AR531XPLUS_SPI_MMR_SIZE
++#define SPI_FLASH_CTL AR531XPLUS_SPI_CTL
++#define SPI_FLASH_OPCODE AR531XPLUS_SPI_OPCODE
++#define SPI_FLASH_DATA AR531XPLUS_SPI_DATA
++
++#define SPI_CTL_START 0x00000100
++#define SPI_CTL_BUSY 0x00010000
++#define SPI_CTL_TXCNT_MASK 0x0000000f
++#define SPI_CTL_RXCNT_MASK 0x000000f0
++#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff
++#define SPI_CTL_SIZE_MASK 0x00060000
++
++#define SPI_CTL_CLK_SEL_MASK 0x03000000
++#define SPI_OPCODE_MASK 0x000000ff
++
++#define SPI_STATUS_WIP STM_STATUS_WIP
+diff -urN linux-mips/drivers/mtd/maps/Config.in mips-linux-2.4.25/drivers/mtd/maps/Config.in
+--- linux-mips/drivers/mtd/maps/Config.in 2005-12-24 15:11:25.158488072 +0000
++++ mips-linux-2.4.25/drivers/mtd/maps/Config.in 2005-12-30 17:27:21.660122568 +0000
+@@ -9,7 +9,14 @@
+ dep_tristate ' CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_GEN_PROBE
+ if [ "$CONFIG_MTD_PHYSMAP" = "y" -o "$CONFIG_MTD_PHYSMAP" = "m" ]; then
+ hex ' Physical start address of flash mapping' CONFIG_MTD_PHYSMAP_START 0x8000000
+- hex ' Physical length of flash mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000
++ if [ "$CONFIG_FLASH_2MB" = "y" ]; then
++ define_hex CONFIG_MTD_PHYSMAP_LEN 200000
++ fi
++ if [ "$CONFIG_FLASH_4MB" = "y" ]; then
++ define_hex CONFIG_MTD_PHYSMAP_LEN 400000
++ fi
++
++# hex ' Physical length of flash mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000
+ int ' Bus width in octets' CONFIG_MTD_PHYSMAP_BUSWIDTH 2
+ fi
+
+diff -urN linux-mips/drivers/mtd/maps/physmap.c mips-linux-2.4.25/drivers/mtd/maps/physmap.c
+--- linux-mips/drivers/mtd/maps/physmap.c 2005-12-24 15:11:25.217479104 +0000
++++ mips-linux-2.4.25/drivers/mtd/maps/physmap.c 2005-12-30 17:27:22.044064200 +0000
+@@ -80,12 +80,25 @@
+ };
+
+ #ifdef CONFIG_MTD_PARTITIONS
+-#ifdef CONFIG_MTD_CMDLINE_PARTS
++#if defined(CONFIG_MTD_CMDLINE_PARTS) || defined(CONFIG_MTD_REDBOOT_PARTS)
+ static struct mtd_partition *mtd_parts = 0;
+ static int mtd_parts_nb = 0;
+ #else
+ static struct mtd_partition physmap_partitions[] = {
+ /* Put your own partition definitions here */
++ {
++ name: "rootfs",
++#ifdef CONFIG_FLASH_2MB
++ size: 0x000e0000,
++ offset: 0x000f0000,
++#endif
++#ifdef CONFIG_FLASH_4MB
++ size: 0x002dd000,
++ offset: 0x00100000,
++#endif
++
++ /* Allow file system to be mounted for writing */
++ }
+ #if 0
+ {
+ name: "bootROM",
+@@ -138,6 +151,22 @@
+
+ add_mtd_device(mymtd);
+ #ifdef CONFIG_MTD_PARTITIONS
++#ifdef CONFIG_MTD_REDBOOT_PARTS
++ {
++ extern int parse_redboot_partitions(struct mtd_info *master,
++ struct mtd_partition **pparts);
++
++ struct mtd_partition *rb_parts = 0;
++ int rb_parts_nb = 0;
++
++ rb_parts_nb = parse_redboot_partitions(mymtd, &rb_parts);
++ if (rb_parts_nb > 0) {
++ printk(KERN_NOTICE
++ "Using redboot flash partitioning");
++ add_mtd_partitions (mymtd, rb_parts, rb_parts_nb);
++ }
++ }
++#endif
+ #ifdef CONFIG_MTD_CMDLINE_PARTS
+ mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts,
+ "phys");
+@@ -147,7 +176,8 @@
+ "Using command line partition definition\n");
+ add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb);
+ }
+-#else
++#endif
++#if !defined(CONFIG_MTD_CMDLINE_PARTS) && !defined(CONFIG_MTD_REDBOOT_PARTS)
+ if (NUM_PARTITIONS != 0)
+ {
+ printk(KERN_NOTICE
+diff -urN linux-mips/drivers/mtd/redboot.c mips-linux-2.4.25/drivers/mtd/redboot.c
+--- linux-mips/drivers/mtd/redboot.c 2005-12-24 15:11:25.249474240 +0000
++++ mips-linux-2.4.25/drivers/mtd/redboot.c 2005-12-30 17:27:22.517992152 +0000
+@@ -51,8 +51,14 @@
+ return -ENOMEM;
+
+ /* Read the start of the last erase block */
+- ret = master->read(master, master->size - master->erasesize,
++ {
++ u_int32_t part_table_start = master->size - master->erasesize;
++#if defined(CONFIG_MTD_END_RESERVED)
++ part_table_start -= CONFIG_MTD_END_RESERVED;
++#endif
++ ret = master->read(master, part_table_start,
+ PAGE_SIZE, &retlen, (void *)buf);
++ }
+
+ if (ret)
+ goto out;
+diff -urN linux-mips/drivers/net/Config.in mips-linux-2.4.25/drivers/net/Config.in
+--- linux-mips/drivers/net/Config.in 2005-12-24 15:11:25.725401888 +0000
++++ mips-linux-2.4.25/drivers/net/Config.in 2005-12-30 17:27:22.684966768 +0000
+@@ -24,6 +24,18 @@
+ comment 'Ethernet (10 or 100Mbit)'
+ bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
+ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
++ define_bool CONFIG_VENETDEV n
++ tristate ' BUILT-IN ATHEROS ENET DRIVER' CONFIG_NET_ATHEROS_ETHER
++ if [ "$CONFIG_AP38" = "y" -o "$CONFIG_AP48" = "y" ]; then
++ define_bool CONFIG_KENDIN_ENET_PHY y
++ elif [ "$CONFIG_AP30ASK" = "y" ]; then
++ define_bool CONFIG_KENDIN_KS8995XA_ENET_PHY y
++ bool 'Multiple Ethernet address hack ' CONFIG_ASK_MULT_MAC_HACK
++ elif [ "$CONFIG_AP51" = "y" ]; then
++ define_bool CONFIG_ICPLUS_ENET_PHY y
++ else
++ define_bool CONFIG_MARVELL_ENET_PHY y
++ fi
+ if [ "$CONFIG_ARM" = "y" ]; then
+ dep_bool ' ARM EBSA110 AM79C961A support' CONFIG_ARM_AM79C961A $CONFIG_ARCH_EBSA110
+ tristate ' Cirrus Logic CS8900A support' CONFIG_ARM_CIRRUS
+diff -urN linux-mips/drivers/net/Makefile mips-linux-2.4.25/drivers/net/Makefile
+--- linux-mips/drivers/net/Makefile 2005-12-24 15:11:25.726401736 +0000
++++ mips-linux-2.4.25/drivers/net/Makefile 2005-12-30 17:27:22.709962968 +0000
+@@ -31,6 +31,10 @@
+ obj-y += e1000/e1000.o
+ endif
+
++ifeq ($(CONFIG_NET_ATHEROS_ETHER),y)
++ obj-y += ath/ae531x.o
++endif
++
+ ifeq ($(CONFIG_BONDING),y)
+ obj-y += bonding/bonding.o
+ endif
+@@ -53,8 +57,13 @@
+ subdir-$(CONFIG_SKFP) += skfp
+ subdir-$(CONFIG_E100) += e100
+ subdir-$(CONFIG_E1000) += e1000
++subdir-$(CONFIG_NET_ATHEROS_ETHER) += ath
+ subdir-$(CONFIG_BONDING) += bonding
+
++ifeq ($(CONFIG_ATHAP33),y)
++subdir-$(CONFIG_ATHAP33) += athap33
++endif
++
+ #
+ # link order important here
+ #
+@@ -242,6 +251,10 @@
+ obj-$(CONFIG_R8169) += r8169.o
+ obj-$(CONFIG_AMD8111_ETH) += amd8111e.o mii.o
+
++ifeq ($(CONFIG_ATHAP33),y)
++obj-$(CONFIG_ATHAP33) += athap33/ath_ap_mips.o
++endif
++
+ # non-drivers/net drivers who want mii lib
+ obj-$(CONFIG_PCMCIA_SMC91C92) += mii.o
+ obj-$(CONFIG_USB_USBNET) += mii.o
+diff -urN linux-mips/fs/jffs2/nodelist.h mips-linux-2.4.25/fs/jffs2/nodelist.h
+--- linux-mips/fs/jffs2/nodelist.h 2005-12-24 15:11:50.407649616 +0000
++++ mips-linux-2.4.25/fs/jffs2/nodelist.h 2005-12-30 17:27:51.289618200 +0000
+@@ -31,7 +31,7 @@
+ * provisions above, a recipient may use your version of this file
+ * under either the RHEPL or the GPL.
+ *
+- * $Id: nodelist.h,v 1.46.2.5 2003/11/02 13:54:20 dwmw2 Exp $
++ * $Id: //depot/sw/releases/linuxsrc/src/kernels/mips-linux-2.4.25/fs/jffs2/nodelist.h#3 $
+ *
+ */
+
+@@ -222,8 +222,8 @@
+ #define ALLOC_DELETION 1 /* Deletion node. Best to allow it */
+ #define ALLOC_GC 2 /* Space requested for GC. Give it or die */
+
+-#define JFFS2_RESERVED_BLOCKS_BASE 3 /* Number of free blocks there must be before we... */
+-#define JFFS2_RESERVED_BLOCKS_WRITE (JFFS2_RESERVED_BLOCKS_BASE + 2) /* ... allow a normal filesystem write */
++#define JFFS2_RESERVED_BLOCKS_BASE 2 /* Number of free blocks there must be before we... */
++#define JFFS2_RESERVED_BLOCKS_WRITE (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... allow a normal filesystem write */
+ #define JFFS2_RESERVED_BLOCKS_DELETION (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... allow a normal filesystem deletion */
+ #define JFFS2_RESERVED_BLOCKS_GCTRIGGER (JFFS2_RESERVED_BLOCKS_BASE + 3) /* ... wake up the GC thread */
+ #define JFFS2_RESERVED_BLOCKS_GCBAD (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... pick a block from the bad_list to GC */
+diff -urN linux-mips/fs/partitions/Config.in mips-linux-2.4.25/fs/partitions/Config.in
+--- linux-mips/fs/partitions/Config.in 2005-12-24 15:11:52.366351848 +0000
++++ mips-linux-2.4.25/fs/partitions/Config.in 2005-12-30 17:27:52.279467720 +0000
+@@ -39,7 +39,7 @@
+ fi
+ if [ "$CONFIG_AMIGA" != "y" -a "$CONFIG_ATARI" != "y" -a \
+ "$CONFIG_MAC" != "y" -a "$CONFIG_SGI_IP22" != "y" -a \
+- "$CONFIG_SGI_IP27" != "y" ]; then
++ "$CONFIG_SGI_IP27" != "y" -a "$CONFIG_AR531X" != "y" ]; then
+ define_bool CONFIG_MSDOS_PARTITION y
+ fi
+ if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_AFFS_FS" = "y" ]; then
+diff -urN linux-mips/include/asm-mips/atheros/ar531xbsp.h mips-linux-2.4.25/include/asm-mips/atheros/ar531xbsp.h
+--- linux-mips/include/asm-mips/atheros/ar531xbsp.h 1970-01-01 01:00:00.000000000 +0100
++++ mips-linux-2.4.25/include/asm-mips/atheros/ar531xbsp.h 2005-12-30 17:28:01.523062480 +0000
+@@ -0,0 +1,17 @@
++#ifndef __ASM_ATHEROS_BSP_SUPPORT_H
++#define __ASM_ATHEROS_BSP_SUPPORT_H
++/*
++ * These are definitions and functions provided by the bsp to support the
++ * AR5312 WiSoC running LSDK. For different BSP implementations, different
++ * BSP functions will be needed.
++ */
++
++extern unsigned int ar531x_sys_frequency(void);
++extern const char* get_system_type(void);
++
++#ifdef CONFIG_KGDB
++extern void kgdbInit(void);
++extern int kgdbEnabled(void);
++#endif
++
++#endif /* __ASM_ATHEROS_BSP_SUPPORT_H */
+diff -urN linux-mips/include/asm-mips/bootinfo.h mips-linux-2.4.25/include/asm-mips/bootinfo.h
+--- linux-mips/include/asm-mips/bootinfo.h 2005-12-24 15:12:00.645093288 +0000
++++ mips-linux-2.4.25/include/asm-mips/bootinfo.h 2005-12-30 17:28:01.534060808 +0000
+@@ -37,6 +37,7 @@
+ #define MACH_GROUP_HP_LJ 20 /* Hewlett Packard LaserJet */
+ #define MACH_GROUP_LASAT 21
+ #define MACH_GROUP_TITAN 22 /* PMC-Sierra Titan */
++#define MACH_GROUP_AR531X 23 /* Atheros AR531X */
+
+ /*
+ * Valid machtype values for group unknown (low order halfword of mips_machtype)
+@@ -198,6 +199,17 @@
+ */
+ #define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */
+
++/*
++ * Valid machtype for group MACH_GROUP_AR5312
++ */
++#define MACH_ATHEROS_UNUSED 0
++#define MACH_ATHEROS_AP30 1 /* AP30 */
++#define MACH_ATHEROS_AP33 2 /* AP33 */
++#define MACH_ATHEROS_AP38 3 /* AP38 */
++#define MACH_ATHEROS_AP43 4 /* AP43 */
++#define MACH_ATHEROS_AP48 5 /* AP48 */
++#define MACH_ATHEROS_PB32 6 /* PB32 */
++
+ #define CL_SIZE (256)
+
+ const char *get_system_type(void);
+diff -urN linux-mips/include/asm-mips/page.h mips-linux-2.4.25/include/asm-mips/page.h
+--- linux-mips/include/asm-mips/page.h 2005-12-24 15:12:01.097024584 +0000
++++ mips-linux-2.4.25/include/asm-mips/page.h 2005-12-30 17:28:01.898005480 +0000
+@@ -13,7 +13,6 @@
+ #include <linux/config.h>
+ #include <asm/break.h>
+
+-#ifdef __KERNEL__
+
+ /*
+ * PAGE_SHIFT determines the page size
+@@ -30,6 +29,7 @@
+ #define PAGE_SIZE (1L << PAGE_SHIFT)
+ #define PAGE_MASK (~(PAGE_SIZE-1))
+
++#ifdef __KERNEL__
+ #ifndef __ASSEMBLY__
+
+ #include <asm/cacheflush.h>
+diff -urN linux-mips/include/asm-mips/serial.h mips-linux-2.4.25/include/asm-mips/serial.h
+--- linux-mips/include/asm-mips/serial.h 2005-12-24 15:12:01.130019568 +0000
++++ mips-linux-2.4.25/include/asm-mips/serial.h 2005-12-30 17:28:02.143968088 +0000
+@@ -410,6 +410,11 @@
+ #define DDB5477_SERIAL_PORT_DEFNS
+ #endif
+
++#if defined(CONFIG_AR531X)
++#undef RS_TABLE_SIZE
++#define RS_TABLE_SIZE 1
++#endif
++
+ #define SERIAL_PORT_DFNS \
+ ATLAS_SERIAL_PORT_DEFNS \
+ AU1000_SERIAL_PORT_DEFNS \
+diff -urN linux-mips/kernel/printk.c mips-linux-2.4.25/kernel/printk.c
+--- linux-mips/kernel/printk.c 2005-12-24 15:12:09.361768152 +0000
++++ mips-linux-2.4.25/kernel/printk.c 2005-12-30 17:28:11.943478336 +0000
+@@ -383,6 +383,18 @@
+ _call_console_drivers(start_print, end, msg_level);
+ }
+
++#if CONFIG_EARLY_PRINTK_HACK
++void putDebugChar(char byte);
++static void emit_log_char(char c)
++{
++ if (c == '\n') {
++ putDebugChar('\r');
++ putDebugChar('\n');
++ } else {
++ putDebugChar(c);
++ }
++}
++#else
+ static void emit_log_char(char c)
+ {
+ LOG_BUF(log_end) = c;
+@@ -394,6 +406,7 @@
+ if (logged_chars < LOG_BUF_LEN)
+ logged_chars++;
+ }
++#endif
+
+ /*
+ * This is printk. It can be called from any context. We want it to work.
+@@ -696,3 +709,4 @@
+ tty->driver.write(tty, 0, msg, strlen(msg));
+ return;
+ }
++
+diff -urN linux-mips-orig/drivers/net/ath/ae531x.h linux-mips-new/drivers/net/ath/ae531x.h
+--- linux-mips-orig/drivers/net/ath/ae531x.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/ae531x.h 2005-12-31 12:33:57.672538976 +0000
+@@ -0,0 +1,43 @@
++#ifndef __AE531X_H
++#define __AE531X_H
++
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <asm/io.h>
++
++#include "ar531xlnx.h"
++#include "ae531xreg.h"
++#include "ae531xmac.h"
++
++extern void *ae531x_rxbuf_alloc(ae531x_MAC_t *MACInfo, char **rxBuffp,
++ int *rxBuffSizep);
++extern void ae531x_swptr_free(VIRT_ADDR desc);
++extern BOOL ae531x_twisted_enet(void);
++extern void ae531x_MiiWrite(UINT32 phyBase, UINT32 phyAddr, UINT8 reg,
++ UINT16 data);
++extern UINT16 ae531x_MiiRead(UINT32 phyBase, UINT32 phyAddr, UINT8 reg);
++extern void ae531x_unitLinkGained(int ethUnit);
++extern void ae531x_unitLinkLost(int ethUnit);
++extern void ae531x_WriteDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data);
++extern void ae531x_MACReset(ae531x_MAC_t *MACInfo);
++extern void ae531x_DisableComm(ae531x_MAC_t *MACInfo);
++extern void ae531x_FreeQueues(ae531x_MAC_t *MACInfo);
++extern void ae531x_reset(ae531x_MAC_t *MACInfo);
++extern int ae531x_AllocateQueues(ae531x_MAC_t *MACInfo);
++extern void ae531x_EnableComm(ae531x_MAC_t *MACInfo);
++extern void ae531x_DmaIntEnable(ae531x_MAC_t *MACInfo);
++extern void ae531x_DmaIntDisable(ae531x_MAC_t *MACInfo);
++extern void ae531x_DmaReset(ae531x_MAC_t *MACInfo);
++extern void ae531x_BeginResetMode(ae531x_MAC_t *MACInfo);
++extern void ae531x_AckIntr(ae531x_MAC_t *MACInfo, UINT32 data);
++extern void ae531x_SetDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val);
++extern BOOL ae531x_IsInResetMode(ae531x_MAC_t *MACInfo);
++extern UINT32 ae531x_ReadDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg);
++extern void ae531x_ClearDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val);
++
++#endif /* __AE531X_H */
+diff -urN linux-mips-orig/drivers/net/ath/ae531xlnx.c linux-mips-new/drivers/net/ath/ae531xlnx.c
+--- linux-mips-orig/drivers/net/ath/ae531xlnx.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/ae531xlnx.c 2005-12-31 12:33:57.673538824 +0000
+@@ -0,0 +1,1303 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * Ethernet driver for Atheros' ae531x ethernet MAC.
++ * This is a fairly generic driver, but it's intended
++ * for use in typical Atheros products.
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <asm/io.h>
++
++#include "ar531xlnx.h"
++#include "ae531xreg.h"
++#include "ae531xmac.h"
++#include "ae531x.h"
++
++#ifndef EXPORT_SYMTAB
++#define EXPORT_SYMTAB
++#endif
++
++#ifdef DEBUG
++void my_mvPhyShow(int ethUnit);
++#endif
++
++static struct ar531x_boarddata *ar531x_boardConfig=NULL;
++
++static char *radioConfig=NULL;
++
++#define AE531X_LAN_PORT 0
++#define AE531X_DEV_PER_MAC 1
++
++/*
++ * ae531x_MAC_state contains driver-specific linux-specific per-MAC information.
++ * The OSinfo member of ae531x_MAC_t points to one of these.
++ */
++typedef struct ae531x_MAC_state {
++ int irq;
++ struct tq_struct restart_task;
++ struct net_device_stats stats;
++ struct ae531x_dev_sw_state *dev_sw_state[AE531X_DEV_PER_MAC];
++ int primary_dev;
++ ae531x_MAC_t MACInfo; /* hardware state */
++} ae531x_MAC_state_t;
++
++/*
++ * ae531x_dev_sw_state contains driver-specific linux-specific per-device
++ * information. The net_device priv member points to one of these, and
++ * this structure contains a pointer to the associated MAC information.
++ */
++
++typedef struct ae531x_dev_sw_state {
++ int enetUnit; /* system unit number "eth%d" */
++ int unit_on_MAC; /* MAC-relative unit number */
++ struct net_device *dev;
++ ae531x_MAC_state_t *MAC_state; /* underlying MAC hw/sw state */
++} ae531x_dev_sw_state_t;
++
++/*
++ * Driver-independent linux-specific per-ethernet device software information.
++ */
++static struct net_device *ae531x_MAC_dev[AR531X_NUM_ENET_MAC * AE531X_DEV_PER_MAC];
++
++/* Driver-dependent per-MAC information */
++static ae531x_MAC_state_t per_MAC_info[AR531X_NUM_ENET_MAC];
++
++/*
++ * Receive buffers need enough room to hold the following:
++ * 1) a max MTU-sized packet.
++ * 2) space for an ethernet header
++ * 3) room at the beginning of the receive buffer in order
++ * to facilitate cooperating drivers that need to PREpend
++ * data.
++ * 4) Depending on configuration, we may need some additional
++ * room at the END of the rx buffer for phy-supplied
++ * trailers (if any). (c.f. CONFIG_VENETDEV)
++ *
++ * The DMA engine insists on 32-bit aligned RX buffers.
++ * TBDXXX: With current code, the IP stack ends up looking
++ * at misaligned headers with word operations. The misaligned
++ * reads are software-emulated via handle_adel_int. We'd
++ * rather align the buffers on a 16-bit boundary, but the
++ * DMA engine doesn't permit it???
++ */
++#define ETH_MAX_MTU 1518
++#define AE531X_RX_BUF_SIZE \
++ (((RXBUFF_RESERVE + ETH_HLEN + ETH_MAX_MTU + PHY_TRAILER_SIZE) + 3) & ~3)
++
++/* Forward references to local functions */
++static void ae531x_TxReap(ae531x_MAC_state_t *MAC_state);
++static int ae531x_phy_poll(void *data);
++static int ae531x_MAC_stop(struct net_device *dev);
++static int ae531x_MAC_open(struct net_device *dev);
++
++/*******************************************************************************
++* ae531x_MAC_poll checks for received packets, and sends data
++* up the stack.
++*/
++int
++ae531x_MAC_poll(struct net_device *dev, int *budget)
++{
++ struct sk_buff *skb;
++ struct sk_buff *newskb;
++ char *rxBufp;
++ int unused_length;
++ VIRT_ADDR rxDesc;
++ int length;
++ ae531x_dev_sw_state_t *dev_sw_state;
++ ae531x_MAC_state_t *MAC_state;
++ ae531x_MAC_t *MACInfo;
++ u32 cmdsts;
++ int rx_limit;
++ int rx_received;
++ int rxDescCount;
++ struct net_device *rxdev;
++ int early_stop;
++ int retval;
++#ifdef DEBUG
++ static int rxDescCountMax = 0;
++#endif
++
++ ARRIVE();
++
++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;
++ MAC_state = dev_sw_state->MAC_state;
++ MACInfo = &MAC_state->MACInfo;
++ rx_limit = MAC_state->dev_sw_state[MAC_state->primary_dev]->dev->quota;
++ rx_received = 0;
++
++ rxDescCount = 0;
++
++ early_stop = 0;
++ do {
++ ae531x_AckIntr(MACInfo, DmaIntRxCompleted);
++
++ for(;!early_stop;) {
++ rxDesc = MACInfo->rxQueue.curDescAddr;
++ cmdsts = AE531X_DESC_STATUS_GET(KSEG1ADDR(rxDesc));
++
++ AE531X_PRINT(AE531X_DEBUG_RX,
++ ("examine rxDesc %p with cmdsts=0x%x\n",
++ (void *)rxDesc, cmdsts));
++
++ if (cmdsts & DescOwnByDma) {
++ /* There's nothing left to process in the RX ring */
++ goto rx_all_done;
++ }
++
++ rxDescCount++;
++
++ AE531X_CONSUME_DESC((&MACInfo->rxQueue));
++
++ A_DATA_CACHE_INVAL(rxDesc, AE531X_DESC_SIZE);
++
++ /* Process a packet */
++ length = AE531X_DESC_STATUS_RX_SIZE(cmdsts) - ETH_CRC_LEN;
++ if ( (cmdsts & (DescRxFirst |DescRxLast | DescRxErrors)) ==
++ (DescRxFirst | DescRxLast) ) {
++ /* Descriptor status indicates "NO errors" */
++ skb = AE531X_DESC_SWPTR_GET(rxDesc);
++
++ /*
++ * Allocate a replacement skb.
++ * We want to get another buffer ready for Rx ASAP.
++ */
++ newskb = (struct sk_buff *)ae531x_rxbuf_alloc(MACInfo, &rxBufp, &unused_length);
++ if(newskb == NULL ) {
++ /*
++ * Give this descriptor back to the DMA engine,
++ * and drop the received packet.
++ */
++ MAC_state->stats.rx_dropped++;
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("Can't allocate new skb\n"));
++ } else {
++ AE531X_DESC_BUFPTR_SET(rxDesc, virt_to_bus(rxBufp));
++ AE531X_DESC_SWPTR_SET(rxDesc, newskb);
++ }
++
++ AE531X_DESC_STATUS_SET(rxDesc, DescOwnByDma);
++ rxDesc = NULL; /* sanity -- cannot use rxDesc now */
++ sysWbFlush();
++
++ if (newskb == NULL) {
++ retval = 1;
++ goto rx_no_skbs;
++ } else {
++ /* Sync data cache w.r.t. DMA */
++ A_DATA_CACHE_INVAL(skb->data, length);
++
++ rxdev = dev_sw_state->dev;
++
++ if (rxdev == NULL) {
++ /*
++ * We received a packet for a virtual enet device
++ * that is no longer up. Ignore it.
++ */
++ kfree_skb(skb);
++ continue;
++ }
++
++ /* Advance data pointer to show that there's data here */
++ skb_put(skb, length);
++ skb->protocol = eth_type_trans(skb, rxdev);
++ skb->dev = rxdev;
++ rxdev->last_rx = jiffies;
++ rxdev->quota--;
++
++ if (rx_limit-- < 0) {
++ early_stop=1;
++ /* We've done enough for now -- more later */
++ AE531X_PRINT(AE531X_DEBUG_RX_STOP,
++ ("Enet%d RX early stop. Quota=%d rxDescCount=%d budget=%d\n",
++ MACInfo->unit, dev->quota, rxDescCount, *budget));
++ }
++ rx_received++;
++
++ /* Send the data up the stack */
++ AE531X_PRINT(AE531X_DEBUG_RX,
++ ("Send data up stack: skb=%p data=%p length=%d\n",
++ (void *)skb, (void *)skb->data, length));
++
++ netif_receive_skb(skb);
++
++ MAC_state->stats.rx_packets++;
++ MAC_state->stats.rx_bytes += length;
++ }
++ } else {
++ /* Descriptor status indicates ERRORS */
++ MAC_state->stats.rx_errors++;
++
++ if (cmdsts & (DescRxRunt | DescRxLateColl)) {
++ MAC_state->stats.collisions++;
++ }
++
++ if (cmdsts & DescRxLengthError) {
++ MAC_state->stats.rx_length_errors++;
++ }
++
++ if (cmdsts & DescRxCrc) {
++ MAC_state->stats.rx_crc_errors++;
++ }
++
++ if (cmdsts & DescRxDribbling) {
++ MAC_state->stats.rx_frame_errors++;
++ }
++
++ AE531X_DESC_STATUS_SET(rxDesc, DescOwnByDma);
++
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("Bad receive. rxDesc=%p cmdsts=0x%8.8x\n",
++ (void *)rxDesc, cmdsts));
++ }
++ }
++ } while ((!early_stop) &&
++ ae531x_ReadDmaReg(MACInfo, DmaStatus) & DmaIntRxCompleted);
++
++rx_all_done:
++ AE531X_PRINT(AE531X_DEBUG_RX,
++ ("rx done (%d)\n", rxDescCount));
++ *budget -= rxDescCount;
++
++ if (!early_stop) {
++ netif_rx_complete(dev);
++
++ ae531x_SetDmaReg(MACInfo, DmaIntrEnb,
++ DmaIeRxCompleted | DmaIeRxNoBuffer);
++ ae531x_WriteDmaReg(MACInfo, DmaRxPollDemand, 0);
++ }
++
++ retval = early_stop;
++
++rx_no_skbs:
++
++ LEAVE();
++
++#ifdef DEBUG
++ if (rxDescCount > rxDescCountMax) {
++ printk("max rx %d\n", rxDescCount);
++ rxDescCountMax = rxDescCount;
++ }
++#endif
++
++ return retval;
++}
++
++/*******************************************************************************
++* ae531x_restart stops all ethernet devices associated with a physical MAC,
++* then shuts down the MAC. Then it re-opens all devices that were in use.
++* TBDXXX: needs testing!
++*/
++static void
++ae531x_restart(void *data)
++{
++ ae531x_MAC_t *MACInfo = (ae531x_MAC_t *)data;
++ ae531x_MAC_state_t *MAC_state = (ae531x_MAC_state_t *)MACInfo->OSinfo;
++ struct net_device *saved_dev[AE531X_DEV_PER_MAC];
++ int i;
++
++ for (i=0; i<AE531X_DEV_PER_MAC; i++) {
++ if ((saved_dev[i] = MAC_state->dev_sw_state[i]->dev) != NULL) {
++ ae531x_MAC_stop(saved_dev[i]);
++ }
++ }
++
++ for (i=0; i<AE531X_DEV_PER_MAC; i++) {
++ if (saved_dev[i])
++ ae531x_MAC_open(saved_dev[i]);
++ }
++}
++
++/*******************************************************************************
++* ae531x_MAC_intr handle interrupts from an ethernet MAC.
++* It checks MAC status registers, and dispatches as appropriate.
++*/
++void
++ae531x_MAC_intr(int cpl, void *dev_id, struct pt_regs *regs)
++{
++ ae531x_MAC_state_t *MAC_state;
++ ae531x_MAC_t *MACInfo;
++ u32 regIsr;
++ u32 regImr;
++ u32 pendIntrs;
++
++ ARRIVE();
++ MACInfo = (ae531x_MAC_t *)dev_id;
++ MAC_state = (ae531x_MAC_state_t *)MACInfo->OSinfo;
++ for(;;) {
++ /* Clear any unhandled intr causes. */
++ ae531x_WriteDmaReg(MACInfo, DmaStatus, UnhandledIntrMask);
++
++ regIsr = ae531x_ReadDmaReg(MACInfo, DmaStatus);
++ regImr = ae531x_ReadDmaReg(MACInfo, DmaIntrEnb);
++ pendIntrs = regIsr & regImr;
++
++ AE531X_PRINT(AE531X_DEBUG_INT,
++ ("ethmac%d: intIsr=0x%8.8x intImr=0x%8.8x pendIntrs=0x%8.8x\n",
++ MACInfo->unit, regIsr, regImr, pendIntrs ));
++
++ if ((pendIntrs & DmaAllIntCauseMask) == 0)
++ break;
++
++ if ((pendIntrs & DmaIntRxCompleted) ||
++ (pendIntrs & DmaIntRxNoBuffer)) {
++ if (netif_rx_schedule_prep(MAC_state->dev_sw_state[MAC_state->primary_dev]->dev)) {
++ ae531x_ClearDmaReg(MACInfo,
++ DmaIntrEnb,
++ DmaIeRxCompleted | DmaIeRxNoBuffer);
++ ae531x_AckIntr(MACInfo,
++ DmaIntRxCompleted | DmaIntRxNoBuffer);
++ (void)ae531x_ReadDmaReg(MACInfo, DmaIntrEnb);
++ __netif_rx_schedule(MAC_state->dev_sw_state[MAC_state->primary_dev]->dev);
++ } else {
++#if 0
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("%s: Interrupt (0x%8.8x/0x%8.8x) while in poll. regs@%p, pc=%p, ra=%p\n",
++ __FILE__,
++ regIsr,
++ ae531x_ReadDmaReg(MACInfo, DmaIntrEnb),
++ (void *)regs,
++ (void *)regs->cp0_epc,
++ (void *)regs->regs[31]));
++#endif
++ ae531x_AckIntr(MACInfo,
++ DmaIntRxCompleted | DmaIntRxNoBuffer);
++ }
++ }
++
++ if (pendIntrs &
++ (DmaIntTxStopped | DmaIntTxJabber | DmaIntTxUnderflow)) {
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("ethmac%d: TX Error Intr (0x%x)\n",
++ MACInfo->unit, pendIntrs));
++ ae531x_AckIntr(MACInfo,
++ (DmaIntTxStopped | DmaIntTxJabber | DmaIntTxUnderflow));
++ }
++
++ if (pendIntrs & DmaIntBusError) {
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("ethmac%d: DMA Bus Error Intr (0x%x)\n",
++ MACInfo->unit, pendIntrs));
++ ae531x_AckIntr(MACInfo, DmaIntBusError);
++ /* Reset the chip, if it's not already being done */
++ if (ae531x_IsInResetMode(MACInfo)) {
++ goto intr_done;
++ }
++ ae531x_BeginResetMode(MACInfo);
++ schedule_task(&MAC_state->restart_task);
++ }
++
++ if (pendIntrs & DmaIntRxStopped) {
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("ethmac%d: RX Stopped Intr (0x%x)\n",
++ MACInfo->unit, pendIntrs));
++ ae531x_AckIntr(MACInfo, DmaIntRxStopped);
++ }
++ }
++
++ intr_done:
++ LEAVE();
++}
++
++/*******************************************************************************
++* ae531x_MAC_get_stats returns statistics for a specified device
++*/
++static struct net_device_stats*
++ae531x_MAC_get_stats(struct net_device *dev)
++{
++ ae531x_dev_sw_state_t *dev_sw_state;
++ ae531x_MAC_state_t *MAC_state;
++
++ ARRIVE();
++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;
++ MAC_state = dev_sw_state->MAC_state;
++
++ LEAVE();
++ return &MAC_state->stats;
++}
++
++#define AE531X_PHY_POLL_SECONDS 2
++
++#if CONFIG_AR5315
++
++/*******************************************************************************
++* ae531x_getMACInfo returns the MACInfo of the interface given by unit
++*/
++ae531x_MAC_t *ae531x_getMAcInfo(int ethUnit)
++{
++ int i,j;
++ for(i=0;i<AR531X_NUM_ENET_MAC;++i) {
++ if(per_MAC_info[i].dev_sw_state) {
++ for(j=0;j<AE531X_DEV_PER_MAC;++j) {
++ if(per_MAC_info[i].dev_sw_state[j]
++ && per_MAC_info[i].dev_sw_state[j]->enetUnit == ethUnit)
++ return (&(per_MAC_info[i].MACInfo));
++ }
++ }
++ }
++ return NULL;
++}
++
++
++#endif
++
++/*******************************************************************************
++* ae531x_phy_poll periodically checks for changes in phy status
++* (e.g. dropped link).
++*/
++static int
++ae531x_phy_poll(void *data)
++{
++ ae531x_dev_sw_state_t *dev_sw_state = (ae531x_dev_sw_state_t *)data;
++ ae531x_MAC_t *MACInfo = &dev_sw_state->MAC_state->MACInfo;
++ int unit = dev_sw_state->enetUnit;
++
++ while(dev_sw_state->dev!=NULL) {
++ if (MACInfo->port_is_up) {
++ phyCheckStatusChange(unit);
++ }
++
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ schedule_timeout(AE531X_PHY_POLL_SECONDS * HZ);
++ }
++
++ return 0;
++}
++
++
++static char invalid_enet_MAC_addr[] = {0, 0, 0, 0, 0, 0};
++
++/*
++ * Fetch a pointer to an ethernet's MAC address
++ * in the Board Configuration data (in flash).
++ */
++char *
++ae531x_enet_mac_address_get(int MACUnit)
++{
++ /* XXX: Hack for poorly configured boards.
++ * Cannot setup bridging properly (brctl) when both enet
++ * interfaces share the same MAC address.
++ *
++ */
++
++#ifdef CONFIG_ASK_MULT_MAC_HACK
++ static u8 enet0Mac[6] = {0x00, 0x0d, 0x0b, 0x13, 0x6b, 0x16};
++ static u8 enet1Mac[6] = {0x00, 0x0d, 0x0b, 0x13, 0x6b, 0x17};
++#endif
++
++ if (!ar531x_boardConfig)
++ return invalid_enet_MAC_addr;
++ if (MACUnit == 0) {
++#ifndef CONFIG_ASK_MULT_MAC_HACK
++ return ar531x_boardConfig->enet0Mac;
++#else
++ return enet0Mac;
++#endif
++ }
++ if (MACUnit == 1) {
++#ifndef CONFIG_ASK_MULT_MAC_HACK
++ return ar531x_boardConfig->enet1Mac;
++#else
++ return enet1Mac;
++#endif
++ }
++ printk("Invalid ethernet MAC unit number (%d)!\n", MACUnit);
++ return invalid_enet_MAC_addr;
++}
++
++
++
++/*******************************************************************************
++* ae531x_MAC_open is the standard Linux open function. It puts
++* hardware into a known good state, allocates queues, starts
++* the phy polling task, and arranges for interrupts to be handled.
++*/
++static int
++ae531x_MAC_open(struct net_device *dev)
++{
++ ae531x_dev_sw_state_t *dev_sw_state;
++ ae531x_MAC_state_t *MAC_state;
++ ae531x_MAC_t *MACInfo;
++ u8 *MACAddr;
++ int rv;
++ struct tq_struct *restart_task;
++ pid_t phy_poll_pid;
++ ARRIVE();
++
++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;
++ dev_sw_state->dev = dev;
++ MAC_state = dev_sw_state->MAC_state;
++ MACInfo = &MAC_state->MACInfo;
++
++ restart_task = &MAC_state->restart_task;
++ restart_task->routine = ae531x_restart;
++ restart_task->data = (void *)MACInfo;
++
++ AE531X_PRINT(AE531X_DEBUG_RESET,
++ ("ae531x_MAC_open eth%d ethmac%d macBase=0x%x dmaBase=0x%x irq=0x%x\n",
++ dev_sw_state->enetUnit,
++ MACInfo->unit,
++ MACInfo->macBase,
++ MACInfo->dmaBase,
++ MAC_state->irq));
++
++ /* Default MAC address */
++ MACAddr = ae531x_enet_mac_address_get(MACInfo->unit);
++ memcpy(dev->dev_addr, MACAddr, dev->addr_len );
++
++ if (!MACInfo->port_is_up) {
++ /* Bring MAC and PHY out of reset */
++ ae531x_reset(MACInfo);
++
++ /* Attach interrupt handler */
++ rv = request_irq(MAC_state->irq, ae531x_MAC_intr, SA_INTERRUPT,
++ "ae531x_MAC_intr", (void *)MACInfo);
++ if (rv < 0) {
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("request_irq(0x%x) failed (%d)\n",
++ MAC_state->irq, rv));
++ goto open_failure;
++ }
++
++ /* Initialize PHY */
++ AE531X_PRINT(AE531X_DEBUG_RESET, ("\n --- phyBase: %08x\n", MACInfo->phyBase));
++ phySetup(MACInfo->unit, MACInfo->phyBase);
++
++ /* Start thread to poll for phy link status changes */
++ phy_poll_pid = kernel_thread(ae531x_phy_poll, dev_sw_state, 0);
++ if (phy_poll_pid < 0) {
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("ethmac%d unable to start Phy Poll thread\n",
++ MACInfo->unit));
++ }
++
++ /* Allocate RX/TX Queues */
++ if (ae531x_AllocateQueues(MACInfo) < 0) {
++ AE531X_PRINT(AE531X_DEBUG_RESET, ("Queue allocation failed"));
++ free_irq(MAC_state->irq, (void *)MACInfo);
++ goto open_failure;
++ }
++
++ /* Initialize DMA and descriptors */
++ ae531x_DmaReset(MACInfo);
++
++ /* Initialize MAC */
++ ae531x_MACReset(MACInfo);
++
++ /* Enable Receive/Transmit */
++ ae531x_EnableComm(MACInfo);
++
++ MAC_state->primary_dev = dev_sw_state->unit_on_MAC;
++ MACInfo->port_is_up = TRUE;
++ }
++
++ dev->trans_start = jiffies;
++ SET_MODULE_OWNER(dev);
++
++ LEAVE();
++ return 0;
++
++open_failure:
++ LEAVE();
++ return -1;
++}
++
++/*
++ * Shut down MAC hardware.
++ */
++static void
++ae531x_MAC_shutdown(ae531x_MAC_state_t *MAC_state)
++{
++ ae531x_MAC_t *MACInfo;
++
++ MACInfo = &MAC_state->MACInfo;
++ MACInfo->port_is_up = FALSE;
++
++ /* Disable Receive/Transmit */
++ ae531x_DisableComm(MACInfo);
++
++ /* Disable Interrupts */
++ ae531x_DmaIntDisable(MACInfo);
++ sysWbFlush();
++ free_irq(MAC_state->irq, (void *)MACInfo);
++
++ /* Free Transmit & Receive skb's/descriptors */
++ ae531x_TxReap(MAC_state); /* one last time */
++ ae531x_FreeQueues(MACInfo);
++}
++
++/*******************************************************************************
++* ae531x_MAC_stop is the standard Linux stop function. It undoes
++* everything set up by ae531x_MAC_open.
++*/
++static int
++ae531x_MAC_stop(struct net_device *dev)
++{
++ ae531x_dev_sw_state_t *dev_sw_state;
++ ae531x_MAC_state_t *MAC_state;
++ ae531x_MAC_t *MACInfo;
++ int i;
++
++ ARRIVE();
++
++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;
++ MAC_state = dev_sw_state->MAC_state;
++ MACInfo = &MAC_state->MACInfo;
++
++ for (i=0; i<AE531X_DEV_PER_MAC; i++) {
++ if ((MAC_state->dev_sw_state[i]->dev) &&
++ (MAC_state->dev_sw_state[i]->dev != dev_sw_state->dev)) {
++ break;
++ }
++ }
++
++ if (i < AE531X_DEV_PER_MAC) {
++ /* Physical MAC is still in use */
++ if (MAC_state->primary_dev == dev_sw_state->unit_on_MAC) {
++ /*
++ * If the primary_dev is being stopped
++ * then we need to assign a new one.
++ */
++ MAC_state->primary_dev = i;
++ }
++ } else {
++ /* Physical MAC is no longer in use */
++ ae531x_MAC_shutdown(MAC_state);
++ }
++
++ dev_sw_state->dev = NULL;
++ LEAVE();
++ return 0;
++}
++
++/*******************************************************************************
++* ae531x_rxbuf_alloc - Allocate an skb to be associated with an RX descriptor.
++*
++* RETURNS: A pointer to the skb. Also returns a pointer to the underlying
++* buffer and the size of that buffer.
++*/
++void *
++ae531x_rxbuf_alloc(ae531x_MAC_t *MACInfo, char **rxBuffp, int *rxBuffSizep)
++{
++ int buf_size;
++ struct sk_buff *skb;
++ char *rxBuff;
++ int rxBuffSize;
++
++ buf_size = AE531X_RX_BUF_SIZE;
++
++ skb = dev_alloc_skb(buf_size);
++ if (skb) {
++ /* skb->dev = dev; */
++ skb_reserve(skb, RXBUFF_RESERVE);
++
++ rxBuffSize = skb_tailroom(skb);
++ rxBuff = skb->tail;
++
++ *rxBuffp = rxBuff;
++ *rxBuffSizep = rxBuffSize;
++ }
++
++ return skb;
++}
++
++/*******************************************************************************
++* ae531x_swptr_free - Free the skb, if any, associated with a descriptor.
++*/
++void
++ae531x_swptr_free(VIRT_ADDR desc)
++{
++ struct sk_buff *skb;
++
++ skb = (struct sk_buff *)AE531X_DESC_SWPTR_GET(desc);
++ if (skb) {
++ AE531X_DESC_SWPTR_SET(desc, NULL);
++ kfree_skb(skb);
++ }
++}
++
++/*******************************************************************************
++*
++* ae531x_TxReap - the driver Tx completion routine.
++*
++* This routine reaps sk_buffs which have already been transmitted.
++*
++*/
++static void
++ae531x_TxReap(ae531x_MAC_state_t *MAC_state)
++{
++ AE531X_QUEUE *txq;
++ VIRT_ADDR txDesc;
++ UINT32 cmdsts;
++ struct sk_buff *skb;
++ int reaped;
++ ae531x_MAC_t *MACInfo;
++ static int aeUselessReap = 0;
++#ifdef DEBUG
++ static int aeMaxReap = 0;
++#endif
++ ARRIVE();
++
++ MACInfo = &MAC_state->MACInfo;
++ txq = &MACInfo->txQueue;
++ reaped = 0;
++
++ while (1) {
++
++ txDesc = AE531X_QUEUE_ELE_NEXT_GET(txq, txq->reapDescAddr);
++ if (txDesc == txq->curDescAddr) {
++ break;
++ }
++
++ cmdsts = AE531X_DESC_STATUS_GET(KSEG1ADDR(txDesc));
++ if (cmdsts & DescOwnByDma) {
++ break;
++ }
++
++ /* Release sk_buff associated with completed transmit */
++ skb = (struct sk_buff *)AE531X_DESC_SWPTR_GET(txDesc);
++ if (skb) {
++ kfree_skb(skb);
++ AE531X_DESC_SWPTR_SET(txDesc, NULL);
++ }
++
++ /* Update statistics according to completed transmit desc */
++ if (cmdsts & DescTxErrors) {
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("enetmac%d Tx prior error: 0x%8.8x <0x%8.8x> 0x%8.8x\n",
++ MACInfo->unit,
++ cmdsts,
++ DescTxErrors,
++ (int)txDesc));
++#ifdef DEBUG
++ //my_mvPhyShow(MACInfo->unit);
++ printk ("ae531xMacControl: 0x%08x\tMacFlowControl: 0x%08x\n",
++ ae531x_ReadMacReg(MACInfo, MacControl),
++ ae531x_ReadMacReg(MACInfo, MacFlowControl));
++#endif
++ MAC_state->stats.tx_errors++;
++ if (cmdsts & (DescTxLateCollision | DescTxExcCollisions)) {
++ MAC_state->stats.tx_aborted_errors++;
++ }
++ if (cmdsts & (DescTxLostCarrier | DescTxNoCarrier)) {
++ MAC_state->stats.tx_carrier_errors++;
++ }
++ } else {
++ MAC_state->stats.tx_bytes += AE531X_DESC_STATUS_RX_SIZE(cmdsts);
++ MAC_state->stats.tx_packets++;
++ }
++
++ MAC_state->stats.collisions +=
++ ((cmdsts & DescTxCollMask) >> DescTxCollShift);
++
++ txq->reapDescAddr = txDesc;
++ reaped++;
++ }
++
++ if (reaped > 0) {
++ int i;
++
++#ifdef DEBUG
++ if (reaped > aeMaxReap) {
++ aeMaxReap = reaped;
++ printk("max reaped = %d\n", reaped);
++ }
++#endif
++ AE531X_PRINT(AE531X_DEBUG_TX_REAP,
++ ("reaped %d\n", reaped));
++
++ /*
++ * Re-start transmit queues for all ethernet devices
++ * associated with this MAC.
++ */
++ for (i=0; i<AE531X_DEV_PER_MAC; i++) {
++ if (MAC_state->dev_sw_state[i]->dev)
++ netif_start_queue(MAC_state->dev_sw_state[i]->dev);
++ }
++ } else {
++ aeUselessReap++;
++ }
++
++ LEAVE();
++}
++
++
++/*******************************************************************************
++* ae531x_MAC_start_xmit sends a packet.
++*/
++static int
++ae531x_MAC_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ ae531x_dev_sw_state_t *dev_sw_state;
++ ae531x_MAC_state_t *MAC_state;
++ ae531x_MAC_t *MACInfo;
++ u32 buf;
++ u32 ctrlen;
++ u32 length;
++ int mtu;
++ int max_buf_size;
++ VIRT_ADDR txDesc;
++
++ ARRIVE();
++
++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;
++ MAC_state = dev_sw_state->MAC_state;
++ MACInfo = &MAC_state->MACInfo;
++
++ length = skb->len;
++
++ /* Check if this port is up, else toss packet */
++ if (!MACInfo->port_is_up) {
++ buf = virt_to_bus(skb->data);
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("eth%d Tx Down, dropping buf=0x%8.8x, length=0x%8.8x, skb=%p\n",
++ dev_sw_state->enetUnit, buf, length, (void *)skb));
++
++ MAC_state->stats.tx_dropped++;
++ MAC_state->stats.tx_carrier_errors++;
++ goto dropFrame;
++ }
++
++ if (ae531x_IsInResetMode(MACInfo)) {
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("eth%d Tx: In Chip reset - drop frame\n",
++ dev_sw_state->enetUnit));
++
++ MAC_state->stats.tx_dropped++;
++ MAC_state->stats.tx_aborted_errors++;
++ goto dropFrame;
++ }
++
++ /* Check if we can transport this packet */
++ length = max((u32)60, length); /* total length */
++ mtu = dev->mtu;
++ max_buf_size = mtu + ETH_HLEN;
++ if (length > max_buf_size) {
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("eth%d Tx: length %d too long. mtu=%d, trailer=%d\n",
++ dev_sw_state->enetUnit, length, mtu, PHY_TRAILER_SIZE));
++
++ MAC_state->stats.tx_errors++;
++ MAC_state->stats.tx_aborted_errors++;
++
++ goto dropFrame;
++ }
++
++ /* Reap any old, completed Tx descriptors */
++ ae531x_TxReap(MAC_state);
++
++ txDesc = MACInfo->txQueue.curDescAddr;
++ if (txDesc == MACInfo->txQueue.reapDescAddr) {
++ int i;
++
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("eth%d Tx: cannot get txDesc\n",
++ dev_sw_state->enetUnit));
++
++ MAC_state->stats.tx_dropped++;
++ MAC_state->stats.tx_fifo_errors++;
++
++ /*
++ * Stop transmit queues for any ethernet devices
++ * associated with this MAC.
++ */
++#if 0 /* XXX: no way to recover from queue stop until ae531x_MAC_tx_timeout()
++ * is rewritten to avoid calls to shedule().
++ */
++ for (i=0; i<AE531X_DEV_PER_MAC; i++) {
++ if (MAC_state->dev_sw_state[i]->dev)
++ netif_stop_queue(MAC_state->dev_sw_state[i]->dev);
++ }
++#endif
++ goto dropFrame;
++ }
++
++ /* We won't fail now; so consume this descriptor */
++ AE531X_CONSUME_DESC((&MACInfo->txQueue));
++
++ /* Update the descriptor */
++ buf = virt_to_bus(skb->data);
++ AE531X_DESC_BUFPTR_SET(txDesc, buf);
++ AE531X_DESC_SWPTR_SET(txDesc, skb);
++ ctrlen = AE531X_DESC_CTRLEN_GET(txDesc);
++ ctrlen = (ctrlen & (DescEndOfRing)) |
++ DescTxFirst |
++ DescTxLast |
++ DescTxIntEnable;
++
++ ctrlen |= ((length << DescSize1Shift) & DescSize1Mask);
++
++ AE531X_DESC_CTRLEN_SET(txDesc, ctrlen);
++ AE531X_DESC_STATUS_SET(txDesc, DescOwnByDma);
++
++ /* Alert DMA engine to resume Tx */
++ ae531x_WriteDmaReg(MACInfo, DmaTxPollDemand, 0);
++ sysWbFlush();
++
++ AE531X_PRINT(AE531X_DEBUG_TX,
++ ("eth%d Tx: Desc=0x%8.8x, L=0x%8.8x, D=0x%8.8x, d=0x%8.8x, length=0x%8.8x\n",
++ dev_sw_state->enetUnit,
++ (UINT32)txDesc,
++ AE531X_DESC_CTRLEN_GET(txDesc),
++ buf,
++ AE531X_DESC_LNKBUF_GET(txDesc),
++ length));
++
++ /* Tell upper layers to keep it coming */
++ dev->trans_start = jiffies;
++
++ LEAVE();
++
++ return 0;
++
++dropFrame:
++ kfree_skb(skb);
++ LEAVE();
++ return 0;
++}
++
++
++/*******************************************************************************
++* ae531x_MAC_tx_timeout handles transmit timeouts
++*/
++static void
++ae531x_MAC_tx_timeout(struct net_device *dev)
++{
++ ae531x_dev_sw_state_t *dev_sw_state;
++ ae531x_MAC_state_t *MAC_state;
++ ae531x_MAC_t *MACInfo;
++
++ ARRIVE();
++
++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;
++ MAC_state = dev_sw_state->MAC_state;
++ MACInfo = &MAC_state->MACInfo;
++
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("enet%d: Tx timeout\n", dev_sw_state->enetUnit));
++
++ ae531x_restart(MACInfo);
++
++ LEAVE();
++}
++
++
++/*******************************************************************************
++* ae531x_MAC_do_ioctl is a placeholder for future ioctls.
++*/
++static int
++ae531x_MAC_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++ int rv;
++ ae531x_MAC_t *MACInfo;
++ struct ioctl_data {
++ u32 unit;
++ u32 addr;
++ u32 data;
++ } *req;
++ ae531x_dev_sw_state_t *dev_sw_state;
++ ae531x_MAC_state_t *MAC_state;
++
++ ARRIVE();
++
++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;
++ MAC_state = dev_sw_state->MAC_state;
++ MACInfo = &MAC_state->MACInfo;
++
++ req = (struct ioctl_data *)ifr->ifr_data;
++
++ switch( cmd ) {
++ default:
++ AE531X_PRINT(AE531X_DEBUG_ERROR,
++ ("Unsupported ioctl: 0x%x\n", cmd));
++ rv = -EOPNOTSUPP;
++ }
++
++ LEAVE();
++ return rv;
++}
++
++static void
++ae531x_MAC_setup_fntable(struct net_device *dev)
++{
++ ARRIVE();
++
++ dev->get_stats = ae531x_MAC_get_stats;
++ dev->open = ae531x_MAC_open;
++ dev->stop = ae531x_MAC_stop;
++ dev->hard_start_xmit = ae531x_MAC_start_xmit;
++ dev->do_ioctl = ae531x_MAC_do_ioctl;
++ dev->poll = ae531x_MAC_poll;
++ dev->weight = 16;
++#if 0 /* XXX: currently, ae531x_MAC_tx_timeout() will call functions
++ * that in turn call schedule(). this is BAD, since the
++ * timeout call runs at interrupt time. until ae531x_MAC_tx_timeout
++ * is rewritten to avoid schedule() calls, we do not use it.
++ */
++ dev->tx_timeout = ae531x_MAC_tx_timeout;
++#else
++ dev->tx_timeout = NULL;
++#endif
++ dev->features = NETIF_F_HW_CSUM |\
++ NETIF_F_HIGHDMA;
++
++ LEAVE();
++}
++
++static void
++ar5312EepromRead(char *EepromAddr, u_int16_t id, unsigned int off,
++ unsigned int nbytes, char *data)
++{
++ int i;
++
++ for (i=0; i<nbytes; i++, off++) {
++ data[i] = EepromAddr[off];
++ }
++}
++
++int
++ae531x_get_numMACs(void)
++{
++ int devid;
++ u16 radioMask;
++
++ /* Probe to find out the silicon revision and enable the
++ correct number of macs */
++ devid = ((u_int16_t) ((sysRegRead(AR531X_REV) >>8) &
++ (AR531X_REV_MAJ | AR531X_REV_MIN)));
++ switch (devid) {
++ case AR5212_AR5312_REV2:
++ case AR5212_AR5312_REV7:
++ /* Need to determine if we have a 5312 or a 2312 since they
++ have the same Silicon Rev ID*/
++ ar5312EepromRead(radioConfig,0,2*AR531X_RADIO_MASK_OFF,2,
++ (char *) &radioMask);
++ if ((radioMask & AR531X_RADIO0_MASK) != 0) {
++ return 2;
++ }
++ return 1;
++ case AR5212_AR2313_REV8:
++ return 1;
++ }
++
++ /* default to 1 */
++ return 1;
++}
++
++BOOL
++ae531x_twisted_enet(void)
++{
++ int wisoc_revision;
++
++ wisoc_revision = (sysRegRead(AR531X_REV) & AR531X_REV_MAJ) >> AR531X_REV_MAJ_S;
++ if ( (wisoc_revision == AR531X_REV_MAJ_AR2313) ||
++ /* next clause is used to determine AR2312, based on number of MACs.
++ * must do this since revision is same for 5312 and 2312.
++ */
++ (wisoc_revision == AR531X_REV_MAJ_AR5312 && ae531x_get_numMACs() == 1) ) {
++ return TRUE;
++ } else {
++ return FALSE;
++ }
++}
++
++int
++ae531x_get_board_config(void)
++{
++ int dataFound;
++ char *bd_config;
++
++ /*
++ * Find start of Board Configuration data, using heuristics:
++ * Search back from the (aliased) end of flash by 0x1000 bytes
++ * at a time until we find the string "5311", which marks the
++ * start of Board Configuration. Give up if we've searched
++ * more than 500KB.
++ */
++ dataFound = 0;
++ for (bd_config = (char *)0xbffff000;
++ bd_config > (char *)0xbff80000;
++ bd_config -= 0x1000)
++ {
++ if ( *(int *)bd_config == AR531X_BD_MAGIC) {
++ dataFound = 1;
++ break;
++ }
++ }
++
++ if (!dataFound) {
++ printk("Could not find Board Configuration Data\n");
++ bd_config = NULL;
++ }
++
++ ar531x_boardConfig = (struct ar531x_boarddata *) bd_config;
++
++ return(dataFound);
++}
++
++int
++ae531x_get_radio_config(void)
++{
++ int dataFound;
++ char *radio_config;
++
++ /*
++ * Now find the start of Radio Configuration data, using heuristics:
++ * Search forward from Board Configuration data by 0x1000 bytes
++ * at a time until we find non-0xffffffff.
++ */
++ dataFound = 0;
++ for (radio_config = ((char *) ar531x_boardConfig) + 0x1000;
++ radio_config < (char *)0xbffff000;
++ radio_config += 0x1000)
++ {
++ if (*(int *)radio_config != 0xffffffff) {
++ dataFound = 1;
++ break;
++ }
++ }
++
++ if (!dataFound) { /* AR2316 relocates radio config to new location */
++ dataFound = 0;
++ for (radio_config = ((char *) ar531x_boardConfig) + 0xf8;
++ radio_config < (char *)0xbffff0f8;
++ radio_config += 0x1000)
++ {
++ if (*(int *)radio_config != 0xffffffff) {
++ dataFound = 1;
++ break;
++ }
++ }
++ }
++
++ if (!dataFound) {
++ printk("Could not find Radio Configuration data\n");
++ radio_config = NULL;
++ }
++ radioConfig = radio_config;
++ return(dataFound);
++}
++
++static int __init
++ae531x_MAC_setup(void)
++{
++ int next_dev, i;
++ struct net_device *dev;
++ ae531x_dev_sw_state_t *dev_sw_state;
++ ae531x_MAC_state_t *MAC_state;
++ ae531x_MAC_t *MACInfo;
++ char *addr;
++
++ ARRIVE();
++
++ MOD_INC_USE_COUNT;
++ for (i=0;i<AR531X_NUM_ENET_MAC * AE531X_DEV_PER_MAC; i++) {
++ ae531x_MAC_dev[i] = NULL;
++ }
++
++ if (!ae531x_get_board_config()) {
++ LEAVE();
++ return -1;
++ }
++ if (!ae531x_get_radio_config()) {
++ LEAVE();
++ return(-1);
++ }
++ for(i=0, next_dev = AR531X_NUM_ENET_MAC-1;
++ i<ae531x_get_numMACs() && next_dev>=0;
++ i++, next_dev--){
++
++ /* if MAC is bogus in config data, skip */
++ addr = ae531x_enet_mac_address_get(next_dev);
++ if((*(u32 *)addr == 0xffffffff) && (*(u16 *)(addr+4)==0xffff)){
++ /* bogus MAC config data */
++ continue;
++ }
++
++ dev = ae531x_MAC_dev[next_dev] =
++ init_etherdev(NULL, sizeof(ae531x_dev_sw_state_t));
++
++ if (dev == NULL) {
++ LEAVE();
++ return -1;
++ }
++
++ ae531x_MAC_setup_fntable(dev);
++
++ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;
++ dev_sw_state->enetUnit = next_dev;
++ dev_sw_state->unit_on_MAC = 0;
++ MAC_state = &per_MAC_info[next_dev];
++ dev_sw_state->MAC_state = MAC_state;
++ MAC_state->dev_sw_state[AE531X_LAN_PORT] = dev_sw_state;
++ MAC_state->primary_dev = -1;
++
++ /* Initialize per-MAC information */
++ MACInfo = &MAC_state->MACInfo;
++
++ MACInfo->unit = next_dev;
++
++ if (MACInfo->unit == 0) {
++ MACInfo->macBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_MAC_OFFSET);
++ MACInfo->dmaBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_DMA_OFFSET);
++ MACInfo->phyBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET);
++ MAC_state->irq = AR531X_IRQ_ENET0_INTRS;
++ } else {
++#ifndef CONFIG_AR5315
++ MACInfo->macBase = (u32) (PHYS_TO_K1(AR531X_ENET1)+AE531X_MAC_OFFSET);
++ MACInfo->dmaBase = (u32) (PHYS_TO_K1(AR531X_ENET1)+AE531X_DMA_OFFSET);
++ if (ae531x_twisted_enet()) {
++ MACInfo->phyBase = (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET);
++ } else {
++ MACInfo->phyBase = (u32)(PHYS_TO_K1(AR531X_ENET1)+AE531X_PHY_OFFSET);
++ }
++ MAC_state->irq = AR531X_IRQ_ENET1_INTRS;
++#endif
++ }
++
++ MACInfo->OSinfo = (void *)MAC_state;
++
++ }
++
++ LEAVE();
++ return 0;
++}
++module_init(ae531x_MAC_setup);
++
++/*******************************************************************************
++* ae531x_MAC_unload is the module unload function
++*/
++static void __exit
++ae531x_MAC_unload(void)
++{
++ int i;
++
++ for (i=0;i<AR531X_NUM_ENET_MAC * AE531X_DEV_PER_MAC; i++) {
++ if (ae531x_MAC_dev[i] != NULL) {
++ if( (((ae531x_dev_sw_state_t *)ae531x_MAC_dev[i]->priv)->dev) != NULL)
++ ae531x_MAC_stop(ae531x_MAC_dev[i]);
++ ae531x_MAC_dev[i] = NULL;
++ }
++ }
++ MOD_DEC_USE_COUNT;
++}
++
++MODULE_AUTHOR("Atheros Communications, Inc.");
++MODULE_DESCRIPTION("Support for Atheros WiSoC Ethernet device");
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("Atheros");
++#endif
++module_exit(ae531x_MAC_unload);
+diff -urN linux-mips-orig/drivers/net/ath/ae531xmac.c linux-mips-new/drivers/net/ath/ae531xmac.c
+--- linux-mips-orig/drivers/net/ath/ae531xmac.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/ae531xmac.c 2005-12-31 12:33:57.673538824 +0000
+@@ -0,0 +1,951 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++
++/*
++ * Ethernet driver for Atheros' ae531x ethernet MAC.
++ */
++
++#if linux
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/init.h>
++#include <asm/io.h>
++
++#include "ar531xlnx.h"
++#endif /* linux */
++
++#include "ae531xreg.h"
++#include "ae531xmac.h"
++
++#ifdef DEBUG
++int ae531x_MAC_debug = AE531X_DEBUG_ERROR;
++#else
++int ae531x_MAC_debug = 0;
++#endif
++
++extern char *ae531x_enet_mac_address_get(int);
++
++/* Forward references to local functions */
++static void ae531x_QueueDestroy(AE531X_QUEUE *q);
++
++
++/******************************************************************************
++*
++* ae531x_ReadMacReg - read AE MAC register
++*
++* RETURNS: register value
++*/
++UINT32
++ae531x_ReadMacReg(ae531x_MAC_t *MACInfo, UINT32 reg)
++{
++ UINT32 addr = MACInfo->macBase+reg;
++ UINT32 data;
++
++ data = RegRead(addr);
++ return data;
++}
++
++
++/******************************************************************************
++*
++* ae531x_WriteMacReg - write AE MAC register
++*
++* RETURNS: N/A
++*/
++void
++ae531x_WriteMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data)
++{
++ UINT32 addr = MACInfo->macBase+reg;
++
++ RegWrite(data, addr);
++}
++
++
++/******************************************************************************
++*
++* ae531x_SetMacReg - set bits in AE MAC register
++*
++* RETURNS: N/A
++*/
++void
++ae531x_SetMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val)
++{
++ UINT32 addr = MACInfo->macBase+reg;
++ UINT32 data = RegRead(addr);
++
++ data |= val;
++ RegWrite(data, addr);
++}
++
++
++/******************************************************************************
++*
++* ae531x_ClearMacReg - clear bits in AE MAC register
++*
++* RETURNS: N/A
++*/
++void
++ae531x_ClearMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val)
++{
++ UINT32 addr = MACInfo->macBase+reg;
++ UINT32 data = RegRead(addr);
++
++ data &= ~val;
++ RegWrite(data, addr);
++}
++
++
++/******************************************************************************
++*
++* ae531x_ReadDmaReg - read AE DMA register
++*
++* RETURNS: register value
++*/
++UINT32
++ae531x_ReadDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg)
++{
++ UINT32 addr = MACInfo->dmaBase+reg;
++ UINT32 data = RegRead(addr);
++
++ return data;
++}
++
++
++/******************************************************************************
++*
++* ae531x_WriteDmaReg - write AE DMA register
++*
++* RETURNS: N/A
++*/
++void
++ae531x_WriteDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data)
++{
++ UINT32 addr = MACInfo->dmaBase+reg;
++
++ RegWrite(data, addr);
++}
++
++
++/******************************************************************************
++ *
++ * ae531x_AckIntr - clear interrupt bits in the status register.
++ * Note: Interrupt bits are *cleared* by writing a 1.
++ */
++void
++ae531x_AckIntr(ae531x_MAC_t *MACInfo, UINT32 data)
++{
++ ae531x_WriteDmaReg(MACInfo, DmaStatus, data);
++}
++
++
++/******************************************************************************
++*
++* ae531x_SetDmaReg - set bits in an AE DMA register
++*
++* RETURNS: N/A
++*/
++void
++ae531x_SetDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val)
++{
++ UINT32 addr = MACInfo->dmaBase+reg;
++ UINT32 data = RegRead(addr);
++
++ data |= val;
++ RegWrite(data, addr);
++}
++
++
++/******************************************************************************
++*
++* ae531x_ClearDmaReg - clear bits in an AE DMA register
++*
++* RETURNS: N/A
++*/
++void
++ae531x_ClearDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val)
++{
++ UINT32 addr = MACInfo->dmaBase+reg;
++ UINT32 data = RegRead(addr);
++
++ data &= ~val;
++ RegWrite(data, addr);
++}
++
++
++/******************************************************************************
++*
++* ae531x_ReadMiiReg - read PHY registers via AE MAC Mii addr/data registers
++*
++* RETURNS: register value
++*/
++UINT32
++ae531x_ReadMiiReg(UINT32 phyBase, UINT32 reg)
++{
++ UINT32 data;
++ UINT32 addr = phyBase+reg;
++
++ data = RegRead(addr);
++ return data;
++}
++
++
++/******************************************************************************
++*
++* ae531x_WriteMiiReg - write PHY registers via AE MAC Mii addr/data registers
++*
++* RETURNS: N/A
++*/
++void
++ae531x_WriteMiiReg(UINT32 phyBase, UINT32 reg, UINT32 data)
++{
++ UINT32 addr = phyBase+reg;
++
++ RegWrite(data, addr);
++}
++
++
++/******************************************************************************
++*
++* ae531x_MiiRead - read AE Mii register
++*
++* RETURNS: register value
++*/
++UINT16
++ae531x_MiiRead(UINT32 phyBase, UINT32 phyAddr, UINT8 reg)
++{
++ UINT32 addr;
++ UINT16 data;
++
++ addr = ((phyAddr << MiiDevShift) & MiiDevMask) | ((reg << MiiRegShift) & MiiRegMask);
++
++ ae531x_WriteMiiReg(phyBase, MacMiiAddr, addr );
++ do {
++ /* nop */
++ } while ((ae531x_ReadMiiReg(phyBase, MacMiiAddr ) & MiiBusy) == MiiBusy);
++
++ data = ae531x_ReadMiiReg(phyBase, MacMiiData) & 0xFFFF;
++
++ return data;
++}
++
++
++/******************************************************************************
++*
++* ae531x_MiiWrite - write AE Mii register
++*
++* RETURNS: N/A
++*/
++void
++ae531x_MiiWrite(UINT32 phyBase, UINT32 phyAddr, UINT8 reg, UINT16 data)
++{
++ UINT32 addr;
++
++ ae531x_WriteMiiReg(phyBase, MacMiiData, data );
++
++ addr = ((phyAddr << MiiDevShift) & MiiDevMask) |
++ ((reg << MiiRegShift) & MiiRegMask) | MiiWrite;
++ ae531x_WriteMiiReg(phyBase, MacMiiAddr, addr );
++
++ do {
++ /* nop */
++ } while ((ae531x_ReadMiiReg(phyBase, MacMiiAddr ) & MiiBusy) == MiiBusy);
++}
++
++
++/*******************************************************************************
++* ae531x_BeginResetMode - enter a special "reset mode" in which
++* -no interrupts are expected from the device
++* -the device will not transmit nor receive
++* -attempts to send or receive will return with an error and
++* -the device will be reset at the next convenient opportunity.
++*/
++void
++ae531x_BeginResetMode(ae531x_MAC_t *MACInfo)
++{
++ /* Set the reset flag */
++ MACInfo->aeProcessRst = 1;
++}
++
++
++/*******************************************************************************
++* ae531x_EndResetMode - exit the special "reset mode" entered
++* earlier via a call to ae531x_BeginResetMode.
++*/
++void
++ae531x_EndResetMode(ae531x_MAC_t *MACInfo)
++{
++ MACInfo->aeProcessRst = 0;
++}
++
++
++/*******************************************************************************
++* ae531x_IsInResetMode - determine whether or not the device is
++* currently in "reset mode" (i.e. that a device reset is pending)
++*/
++BOOL
++ae531x_IsInResetMode(ae531x_MAC_t *MACInfo)
++{
++ return MACInfo->aeProcessRst;
++}
++
++
++/******************************************************************************
++*
++* ae531x_DmaRxStart - Start Rx
++*
++* RETURNS: N/A
++*/
++static void
++ae531x_DmaRxStart(ae531x_MAC_t *MACInfo)
++{
++ ae531x_SetDmaReg(MACInfo, DmaControl, DmaRxStart);
++ sysWbFlush();
++}
++
++
++/******************************************************************************
++*
++* ae531x_DmaRxStop - Stop Rx
++*
++* RETURNS: N/A
++*/
++void
++ae531x_DmaRxStop(ae531x_MAC_t *MACInfo)
++{
++ ae531x_ClearDmaReg(MACInfo, DmaControl, DmaRxStart);
++ sysWbFlush();
++}
++
++
++/******************************************************************************
++*
++* ae531x_DmaTxStart - Start Tx
++*
++* RETURNS: N/A
++*/
++void
++ae531x_DmaTxStart(ae531x_MAC_t *MACInfo)
++{
++ ae531x_SetDmaReg(MACInfo, DmaControl, DmaTxStart);
++ sysWbFlush();
++}
++
++
++/******************************************************************************
++*
++* ae531x_DmaTxStop - Stop Tx
++*
++* RETURNS: N/A
++*/
++void
++ae531x_DmaTxStop(ae531x_MAC_t *MACInfo)
++{
++ ae531x_ClearDmaReg(MACInfo, DmaControl, DmaTxStart);
++ sysWbFlush();
++}
++
++
++/******************************************************************************
++*
++* ae531x_DmaIntEnable - Enable DMA interrupts
++*
++* RETURNS: N/A
++*/
++void
++ae531x_DmaIntEnable(ae531x_MAC_t *MACInfo)
++{
++ ae531x_WriteDmaReg(MACInfo, DmaIntrEnb, DmaIntEnable);
++}
++
++
++/******************************************************************************
++*
++* ae531x_DmaIntDisable - Disable DMA interrupts
++*
++* RETURNS: N/A
++*/
++void
++ae531x_DmaIntDisable(ae531x_MAC_t *MACInfo)
++{
++ ae531x_WriteDmaReg(MACInfo, DmaIntrEnb, DmaIntDisable);
++}
++
++
++/******************************************************************************
++*
++* ae531x_DmaIntClear - Clear DMA interrupts
++*
++* RETURNS: N/A
++*/
++static void
++ae531x_DmaIntClear(ae531x_MAC_t *MACInfo)
++{
++ /* clear all interrupt requests */
++ ae531x_WriteDmaReg(MACInfo, DmaStatus,
++ ae531x_ReadDmaReg(MACInfo, DmaStatus));
++}
++
++
++/******************************************************************************
++* Initialize generic queue data
++*/
++void
++ae531x_QueueInit(AE531X_QUEUE *q, char *pMem, int count)
++{
++ ARRIVE();
++ q->firstDescAddr = pMem;
++ q->lastDescAddr = (VIRT_ADDR)((UINT32)q->firstDescAddr +
++ (count - 1) * AE531X_QUEUE_ELE_SIZE);
++ q->curDescAddr = q->firstDescAddr;
++ q->count = count;
++ LEAVE();
++}
++
++
++/******************************************************************************
++* ae531x_TxQueueCreate - create a circular queue of descriptors for Transmit
++*/
++static int
++ae531x_TxQueueCreate(ae531x_MAC_t *MACInfo,
++ AE531X_QUEUE *q,
++ char *pMem,
++ int count)
++{
++ int i;
++ VIRT_ADDR descAddr;
++
++ ARRIVE();
++
++ ae531x_QueueInit(q, pMem, count);
++ q->reapDescAddr = q->lastDescAddr;
++
++ /* Initialize Tx buffer descriptors. */
++ for (i=0, descAddr=q->firstDescAddr;
++ i<count;
++ i++, descAddr=(VIRT_ADDR)((UINT32)descAddr + AE531X_QUEUE_ELE_SIZE))
++ {
++ /* Update the size, BUFPTR, and SWPTR fields */
++
++ AE531X_DESC_STATUS_SET(descAddr, 0);
++ AE531X_DESC_CTRLEN_SET(descAddr, 0);
++
++ AE531X_DESC_BUFPTR_SET(descAddr, (UINT32)0);
++ AE531X_DESC_LNKBUF_SET(descAddr, (UINT32)0);
++ AE531X_DESC_SWPTR_SET(descAddr, (void *)0);
++ } /* for each desc */
++
++ /* Make the queue circular */
++ AE531X_DESC_CTRLEN_SET(q->lastDescAddr,
++ DescEndOfRing|AE531X_DESC_CTRLEN_GET(q->lastDescAddr));
++
++ AE531X_PRINT(AE531X_DEBUG_RESET,
++ ("ethmac%d Txbuf begin = %x, end = %x\n",
++ MACInfo->unit,
++ (UINT32)q->firstDescAddr,
++ (UINT32)q->lastDescAddr));
++
++ LEAVE();
++ return 0;
++}
++
++
++/******************************************************************************
++* ae531x_RxQueueCreate - create a circular queue of Rx descriptors
++*/
++int
++ae531x_RxQueueCreate(ae531x_MAC_t *MACInfo,
++ AE531X_QUEUE *q,
++ char *pMem,
++ int count)
++{
++ int i;
++ VIRT_ADDR descAddr;
++
++ ARRIVE();
++
++ ae531x_QueueInit(q, pMem, count);
++ q->reapDescAddr = NULL;
++
++
++ /* Initialize Rx buffer descriptors */
++ for (i=0, descAddr=q->firstDescAddr;
++ i<count;
++ i++, descAddr=(VIRT_ADDR)((UINT32)descAddr + AE531X_QUEUE_ELE_SIZE))
++ {
++ void *swptr;
++ char *rxBuffer;
++ int rxBufferSize;
++
++ swptr = ae531x_rxbuf_alloc(MACInfo, &rxBuffer, &rxBufferSize);
++ if (swptr == NULL) {
++ AE531X_PRINT(AE531X_DEBUG_RESET,
++ ("ethmac%d RX queue: ae531x_rxbuf_alloc failed\n",
++ MACInfo->unit));
++ ae531x_QueueDestroy(q);
++ return -1;
++ }
++ AE531X_DESC_SWPTR_SET(descAddr, swptr);
++
++ AE531X_DESC_STATUS_SET(descAddr, DescOwnByDma);
++ AE531X_DESC_CTRLEN_SET(descAddr, rxBufferSize);
++ AE531X_DESC_BUFPTR_SET(descAddr, virt_to_bus(rxBuffer));
++ AE531X_DESC_LNKBUF_SET(descAddr, (UINT32)0);
++ } /* for each desc */
++
++ /* Make the queue circular */
++ AE531X_DESC_CTRLEN_SET(q->lastDescAddr,
++ DescEndOfRing|AE531X_DESC_CTRLEN_GET(q->lastDescAddr));
++
++ AE531X_PRINT(AE531X_DEBUG_RESET,
++ ("ethmac%d Rxbuf begin = %x, end = %x\n",
++ MACInfo->unit,
++ (UINT32)q->firstDescAddr,
++ (UINT32)q->lastDescAddr));
++
++ LEAVE();
++ return 0;
++}
++
++
++/******************************************************************************
++* ae531x_QueueDestroy -- Free all buffers and descriptors associated
++* with a queue.
++*/
++static void
++ae531x_QueueDestroy(AE531X_QUEUE *q)
++{
++ int i;
++ int count;
++ VIRT_ADDR descAddr;
++
++ ARRIVE();
++
++ count = q->count;
++
++ for (i=0, descAddr=q->firstDescAddr;
++ i<count;
++ i++, descAddr=(VIRT_ADDR)((UINT32)descAddr + AE531X_QUEUE_ELE_SIZE)) {
++
++ AE531X_DESC_STATUS_SET(descAddr, 0);
++ AE531X_DESC_CTRLEN_SET(descAddr, 0);
++ AE531X_DESC_BUFPTR_SET(descAddr, (UINT32)0);
++ AE531X_DESC_LNKBUF_SET(descAddr, (UINT32)0);
++
++ ae531x_swptr_free(descAddr); /* Free OS-specific software pointer */
++ }
++
++ LEAVE();
++}
++
++static void
++ae531x_TxQueueDestroy(ae531x_MAC_t *MACInfo)
++{
++ ae531x_QueueDestroy(&MACInfo->txQueue);
++}
++
++static void
++ae531x_RxQueueDestroy(ae531x_MAC_t *MACInfo)
++{
++ ae531x_QueueDestroy(&MACInfo->rxQueue);
++}
++
++
++/******************************************************************************
++* ae531x_AllocateQueues - Allocate receive and transmit queues
++*/
++int
++ae531x_AllocateQueues(ae531x_MAC_t *MACInfo)
++{
++ size_t QMemSize;
++ char *pTxBuf = NULL;
++ char *pRxBuf = NULL;
++
++ ARRIVE();
++
++ MACInfo->txDescCount = AE531X_TX_DESC_COUNT_DEFAULT;
++ QMemSize = AE531X_QUEUE_ELE_SIZE * MACInfo->txDescCount;
++ pTxBuf = MALLOC(QMemSize);
++ if (pTxBuf == NULL) {
++ AE531X_PRINT(AE531X_DEBUG_RESET,
++ ("ethmac%d Failed to allocate TX queue\n", MACInfo->unit));
++ goto AllocQFail;
++ }
++
++ if (ae531x_TxQueueCreate(MACInfo, &MACInfo->txQueue, pTxBuf,
++ MACInfo->txDescCount) < 0)
++ {
++ AE531X_PRINT(AE531X_DEBUG_RESET,
++ ("ethmac%d Failed to create TX queue\n", MACInfo->unit));
++ goto AllocQFail;
++ }
++
++ MACInfo->rxDescCount = AE531X_RX_DESC_COUNT_DEFAULT;
++ QMemSize = AE531X_QUEUE_ELE_SIZE * MACInfo->rxDescCount;
++ pRxBuf = MALLOC(QMemSize);
++ if (pRxBuf == NULL) {
++ AE531X_PRINT(AE531X_DEBUG_RESET,
++ ("ethmac%d Failed to allocate RX queue\n", MACInfo->unit));
++ goto AllocQFail;
++ }
++
++ if (ae531x_RxQueueCreate(MACInfo, &MACInfo->rxQueue, pRxBuf,
++ MACInfo->rxDescCount) < 0)
++ {
++ AE531X_PRINT(AE531X_DEBUG_RESET,
++ ("ethmac%d Failed to create RX queue\n", MACInfo->unit));
++ goto AllocQFail;
++ }
++
++ AE531X_PRINT(AE531X_DEBUG_RESET,
++ ("ethmac%d Memory setup complete.\n", MACInfo->unit));
++
++ LEAVE();
++ return 0;
++
++AllocQFail:
++ MACInfo->txDescCount = 0; /* sanity */
++ MACInfo->rxDescCount = 0; /* sanity */
++
++ if (pTxBuf) {
++ FREE(pTxBuf);
++ }
++ if (pRxBuf) {
++ FREE(pRxBuf);
++ }
++
++ LEAVE();
++ return -1;
++}
++
++
++/******************************************************************************
++*
++* ae531x_FreeQueues - Free Transmit & Receive queues
++*/
++void
++ae531x_FreeQueues(ae531x_MAC_t *MACInfo)
++{
++ ae531x_TxQueueDestroy(MACInfo);
++ FREE(MACInfo->txQueue.firstDescAddr);
++
++ ae531x_RxQueueDestroy(MACInfo);
++ FREE(MACInfo->rxQueue.firstDescAddr);
++}
++
++/******************************************************************************
++*
++* ae531x_DmaReset - Reset DMA and TLI controllers
++*
++* RETURNS: N/A
++*/
++void
++ae531x_DmaReset(ae531x_MAC_t *MACInfo)
++{
++ int i;
++ UINT32 descAddr;
++
++ ARRIVE();
++
++ /* Disable device interrupts prior to any errors during stop */
++ intDisable(MACInfo->ilevel);
++
++ /* Disable MAC rx and tx */
++ ae531x_ClearMacReg(MACInfo, MacControl, (MacRxEnable | MacTxEnable));
++
++ udelay(1);
++
++ /* Reset dma controller */
++
++ ae531x_WriteDmaReg(MACInfo, DmaBusMode, DmaResetOn);
++
++ /* Delay 2 usec */
++ sysUDelay(2);
++
++ /* Flush the rx queue */
++ descAddr = (UINT32)MACInfo->rxQueue.firstDescAddr;
++ MACInfo->rxQueue.curDescAddr = MACInfo->rxQueue.firstDescAddr;
++ for (i=0;
++ i<(MACInfo->rxDescCount);
++ i++, descAddr += AE531X_QUEUE_ELE_SIZE) {
++ AE531X_DESC_STATUS_SET(descAddr, DescOwnByDma);
++ }
++
++ /* Flush the tx queue */
++ descAddr = (UINT32)MACInfo->txQueue.firstDescAddr;
++ MACInfo->txQueue.curDescAddr = MACInfo->txQueue.firstDescAddr;
++ MACInfo->txQueue.reapDescAddr = MACInfo->txQueue.lastDescAddr;
++ for (i=0;
++ i<(MACInfo->txDescCount);
++ i++, descAddr += AE531X_QUEUE_ELE_SIZE) {
++ AE531X_DESC_STATUS_SET (descAddr, 0);
++ }
++
++ /* Set init register values */
++ ae531x_WriteDmaReg(MACInfo, DmaBusMode, DmaBusModeInit);
++
++ /* Install the first Tx and Rx queues on the device */
++ ae531x_WriteDmaReg(MACInfo, DmaRxBaseAddr,
++ virt_to_bus(MACInfo->rxQueue.firstDescAddr));
++ ae531x_WriteDmaReg(MACInfo, DmaTxBaseAddr,
++ virt_to_bus(MACInfo->txQueue.firstDescAddr));
++
++
++ ae531x_WriteDmaReg(MACInfo, DmaControl, DmaStoreAndForward);
++
++ ae531x_WriteDmaReg(MACInfo, DmaIntrEnb, DmaIntDisable);
++
++ AE531X_PRINT(AE531X_DEBUG_RESET,
++ ("ethmac%d: DMA RESET!\n", MACInfo->unit));
++
++ /* Turn on device interrupts -- enable most errors */
++ ae531x_DmaIntClear(MACInfo); /* clear interrupt requests */
++ ae531x_DmaIntEnable(MACInfo); /* enable interrupts */
++
++ ae531x_EndResetMode(MACInfo);
++
++ intEnable(MACInfo->ilevel);
++
++ LEAVE();
++}
++
++
++/******************************************************************************
++*
++* ae531x_MACAddressSet - Set the ethernet address
++*
++* Sets the ethernet address according to settings in flash.
++*
++* RETURNS: void
++*/
++static void
++ae531x_MACAddressSet(ae531x_MAC_t *MACInfo)
++{
++ unsigned int data;
++ UINT8 *macAddr;
++
++ ARRIVE();
++
++ macAddr = ae531x_enet_mac_address_get(MACInfo->unit);
++
++ /* set our MAC address */
++ data = (macAddr[5]<<8) | macAddr[4];
++ ae531x_WriteMacReg(MACInfo, MacAddrHigh, data );
++
++ data = (macAddr[3]<<24) | (macAddr[2]<<16) | (macAddr[1]<<8) | macAddr[0];
++ ae531x_WriteMacReg(MACInfo, MacAddrLow, data );
++
++ AE531X_PRINT(AE531X_DEBUG_RESET,
++ ("ethmac%d Verify MAC address %8.8X %8.8X \n",
++ MACInfo->unit,
++ ae531x_ReadMacReg(MACInfo, MacAddrLow),
++ ae531x_ReadMacReg(MACInfo, MacAddrHigh)));
++
++ AE531X_PRINT(AE531X_DEBUG_RESET,
++ (" sb = %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
++ 0xff&macAddr[0],
++ 0xff&macAddr[1],
++ 0xff&macAddr[2],
++ 0xff&macAddr[3],
++ 0xff&macAddr[4],
++ 0xff&macAddr[5]));
++ LEAVE();
++}
++
++
++/******************************************************************************
++*
++* ae_SetMACFromPhy - read Phy settings and update Mac
++* with current duplex and speed.
++*
++* RETURNS:
++*/
++static void
++ae531x_SetMACFromPhy(ae531x_MAC_t *MACInfo)
++{
++ UINT32 macCtl;
++ BOOL fullDuplex;
++ UINT32 timeout;
++
++ ARRIVE();
++
++ timeout = jiffies+(HZ/1000)*AE531X_NEGOT_TIMEOUT;
++
++ /* Get duplex mode from Phy */
++ while (((fullDuplex = phyIsFullDuplex(MACInfo->unit)) == -1) &&
++ (jiffies <= timeout));
++
++ /* Flag is set for full duplex mode, else cleared */
++ macCtl = ae531x_ReadMacReg(MACInfo, MacControl);
++
++ if (fullDuplex) {
++ /* set values of control registers */
++ macCtl &= ~MacDisableRxOwn;
++ macCtl |= MacFullDuplex;
++ ae531x_WriteMacReg(MACInfo, MacControl, macCtl);
++ ae531x_WriteMacReg(MACInfo, MacFlowControl, MacFlowControlInitFdx);
++ } else {
++ /* set values of control registers */
++ ae531x_WriteMacReg(MACInfo, MacFlowControl, MacFlowControlInitHdx);
++ macCtl |= MacDisableRxOwn;
++ macCtl &= ~MacFullDuplex;
++ ae531x_WriteMacReg(MACInfo, MacControl, macCtl);
++ }
++
++ LEAVE();
++}
++
++
++/******************************************************************************
++* ae531x_MACReset -- sets MAC address and duplex.
++*/
++void
++ae531x_MACReset(ae531x_MAC_t *MACInfo)
++{
++ ae531x_MACAddressSet(MACInfo);
++#ifndef CONFIG_AR5315
++ ae531x_SetMACFromPhy(MACInfo);
++#endif
++}
++
++
++/******************************************************************************
++* ae531x_EnableComm -- enable Transmit and Receive
++*/
++void
++ae531x_EnableComm(ae531x_MAC_t *MACInfo)
++{
++ ae531x_SetMacReg(MACInfo, MacControl, (MacRxEnable | MacTxEnable));
++ ae531x_DmaRxStart(MACInfo); /* start receiver */
++ ae531x_DmaTxStart(MACInfo); /* start transmitter */
++}
++
++
++/******************************************************************************
++* ae531x_DisableComm -- disable Transmit and Receive
++*/
++void
++ae531x_DisableComm(ae531x_MAC_t *MACInfo)
++{
++ ae531x_ClearMacReg(MACInfo, MacControl, (MacRxEnable | MacTxEnable));
++}
++
++
++/******************************************************************************
++* ae531x_reset -- Cold reset ethernet interface
++*/
++void
++ae531x_reset(ae531x_MAC_t *MACInfo)
++{
++ UINT32 mask = 0;
++ UINT32 regtmp;
++#ifndef CONFIG_AR5315
++
++ if (MACInfo->unit == 0) {
++ mask = AR531X_RESET_ENET0 | AR531X_RESET_EPHY0;
++ } else {
++ mask = AR531X_RESET_ENET1 | AR531X_RESET_EPHY1;
++ }
++
++ /* Put into reset */
++ regtmp = sysRegRead(AR531X_RESET);
++ sysRegWrite(AR531X_RESET, regtmp | mask);
++ sysMsDelay(15);
++
++ /* Pull out of reset */
++ regtmp = sysRegRead(AR531X_RESET);
++ sysRegWrite(AR531X_RESET, regtmp & ~mask);
++ sysUDelay(25);
++
++ /* Enable */
++ if (MACInfo->unit == 0) {
++ mask = AR531X_ENABLE_ENET0;
++ } else {
++ mask = AR531X_ENABLE_ENET1;
++ }
++ regtmp = sysRegRead(AR531X_ENABLE);
++ sysRegWrite(AR531X_ENABLE, regtmp | mask);
++#else
++ if (MACInfo->unit == 0) {
++ mask = AR531X_RESET_ENET0 | AR531X_RESET_EPHY0;
++ }
++ /* Enable Arbitration for Ethernet bus */
++ regtmp = sysRegRead(AR531XPLUS_AHB_ARB_CTL);
++ regtmp |= ARB_ETHERNET;
++ sysRegWrite(AR531XPLUS_AHB_ARB_CTL, regtmp);
++
++ /* Put into reset */
++ regtmp = sysRegRead(AR531X_RESET);
++ sysRegWrite(AR531X_RESET, regtmp | mask);
++ sysMsDelay(10);
++
++ /* Pull out of reset */
++ regtmp = sysRegRead(AR531X_RESET);
++ sysRegWrite(AR531X_RESET, regtmp & ~mask);
++ sysMsDelay(10);
++
++ regtmp = sysRegRead(AR531XPLUS_IF_CTL);
++ regtmp |= IF_TS_LOCAL;
++ sysRegWrite(AR531XPLUS_IF_CTL, regtmp);
++#endif
++}
++
++
++/******************************************************************************
++* ae531x_unitLinkLost -- Called from PHY layer to notify the MAC layer
++* that there are no longer any live links associated with a MAC.
++*/
++void
++ae531x_unitLinkLost(int ethUnit)
++{
++ AE531X_PRINT(AE531X_DEBUG_LINK_CHANGE,
++ ("enetmac%d link down\n", ethUnit));
++}
++
++
++/******************************************************************************
++* ae531x_unitLinkGained -- Called from PHY layer to notify the MAC layer
++* that there are 1 or more live links associated with a MAC.
++*/
++void
++ae531x_unitLinkGained(int ethUnit)
++{
++#if CONFIG_AR5315
++#define AE531X_POLL_MILLI_SECONDS 200
++ ae531x_MAC_t *MACInfo = ae531x_getMAcInfo(ethUnit);
++ while(!MACInfo || !MACInfo->port_is_up)
++ {
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ schedule_timeout((AE531X_POLL_MILLI_SECONDS * HZ)/1000);
++ MACInfo = ae531x_getMAcInfo(ethUnit);
++ }
++ ae531x_SetMACFromPhy(MACInfo);
++#endif
++ AE531X_PRINT(AE531X_DEBUG_LINK_CHANGE,
++ ("enet%d link up\n", ethUnit));
++}
++
++/******************************************************************************
++* ae531x_ethMacDefault -- Called from PHY layer to determine the default
++* ethernet MAC. On some "twisted" platforms, the only usable MAC is 1,
++* while on others the usable MAC is 0. Future boards may allow both MACs
++* to be used; in this case, return -1 to indicate that there IS NO default
++* MAC.
++*/
++int
++ae531x_ethMacDefault(void)
++{
++ if (ae531x_twisted_enet())
++ return 1;
++
++ return 0;
++
++}
+diff -urN linux-mips-orig/drivers/net/ath/ae531xmac.h linux-mips-new/drivers/net/ath/ae531xmac.h
+--- linux-mips-orig/drivers/net/ath/ae531xmac.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/ae531xmac.h 2005-12-31 12:33:57.674538672 +0000
+@@ -0,0 +1,229 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * See README to understand the decomposition of the ethernet driver.
++ *
++ * This file contains OS-independent pure software definitions for
++ * ethernet support on the AR531X platform.
++ */
++
++#ifndef _AE531XMAC_H_
++#define _AE531XMAC_H_
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++/*
++ * DEBUG switches to control verbosity.
++ * Just modify the value of ae531x_MAC_debug.
++ */
++#define AE531X_DEBUG_ALL 0xffffffff
++#define AE531X_DEBUG_ERROR 0x00000001 /* Unusual conditions and Errors */
++#define AE531X_DEBUG_ARRIVE 0x00000002 /* Arrive into a function */
++#define AE531X_DEBUG_LEAVE 0x00000004 /* Leave a function */
++#define AE531X_DEBUG_RESET 0x00000008 /* Reset */
++#define AE531X_DEBUG_TX 0x00000010 /* Transmit */
++#define AE531X_DEBUG_TX_REAP 0x00000020 /* Transmit Descriptor Reaping */
++#define AE531X_DEBUG_RX 0x00000040 /* Receive */
++#define AE531X_DEBUG_RX_STOP 0x00000080 /* Receive Early Stop */
++#define AE531X_DEBUG_INT 0x00000100 /* Interrupts */
++#define AE531X_DEBUG_LINK_CHANGE 0x00000200 /* PHY Link status changed */
++
++#define AE531X_NEGOT_TIMEOUT 500 /* ms to wait for autonegotiation */
++
++extern int ae531x_MAC_debug;
++
++#define AE531X_PRINT(FLG, X) \
++{ \
++ if (ae531x_MAC_debug & (FLG)) { \
++ DEBUG_PRINTF("%s#%d:%s ", \
++ __FILE__, \
++ __LINE__, \
++ __FUNCTION__); \
++ DEBUG_PRINTF X; \
++ } \
++}
++
++#define ARRIVE() AE531X_PRINT(AE531X_DEBUG_ARRIVE, ("Arrive{\n"))
++#define LEAVE() AE531X_PRINT(AE531X_DEBUG_LEAVE, ("}Leave\n"))
++
++#define RegRead(addr) \
++ (*(volatile unsigned int *)(addr))
++
++#define RegWrite(val,addr) \
++ ((*(volatile unsigned int *)(addr)) = (val))
++
++/*****************************************************************
++ * Phy code is broken out into a separate layer, so that different
++ * PHY hardware can easily be supported.
++ *
++ * These functions are provided by the PHY layer for use by the MAC layer.
++ * phySetup -- Set phy hardware appropriately for a MAC unit
++ *
++ * phyCheckStatusChange -- Look for dropped/initiated links on any
++ * phy port associated with a MAC unit
++ *
++ * phyIsSpeed100 -- Determines whether or not a PHY is up and
++ * running at 100Mbit
++ *
++ * phyIsFullDuplex -- Determines whether or not a PHY is up and
++ * running in Full Duplex mode
++ *
++ */
++#if CONFIG_MARVELL_ENET_PHY
++/*
++ * Mapping of generic phy APIs to Marvell Ethernet Switch phy functions.
++ */
++#include "mvPhy.h"
++#define phySetup(ethUnit, phyBase) mv_phySetup((ethUnit), (phyBase))
++#define phyCheckStatusChange(ethUnit) mv_phyCheckStatusChange(ethUnit)
++#define phyIsSpeed100(ethUnit) mv_phyIsSpeed100(ethUnit)
++#define phyIsFullDuplex(ethUnit) mv_phyIsFullDuplex(ethUnit)
++
++#if CONFIG_VENETDEV
++#define PHY_TRAILER_SIZE MV_PHY_TRAILER_SIZE
++extern void mv_phyDetermineSource(char *data, int len, int *pFromLAN);
++extern void mv_phySetDestinationPort(char *data, int len, int fromLAN);
++#define phyDetermineSource(data, len, pFromLAN) mv_phyDetermineSource((data), (len), (pFromLAN))
++#define phySetDestinationPort(data, len, fromLAN) mv_phySetDestinationPort((data), (len), (fromLAN))
++#else
++#define PHY_TRAILER_SIZE 0
++#endif
++#endif /* CONFIG_MARVELL_ENET_PHY */
++
++#if CONFIG_KENDIN_ENET_PHY || CONFIG_REALTEK_ENET_PHY || CONFIG_KENDIN_KS8995XA_ENET_PHY
++/*
++ * Mapping of generic phy APIs to Kendin KS8721B and RealTek RTL8201BL phys.
++ */
++#include "rtPhy.h"
++#define phySetup(ethUnit, phyBase) rt_phySetup((ethUnit), (phyBase))
++#define phyCheckStatusChange(ethUnit) rt_phyCheckStatusChange(ethUnit)
++#define phyIsSpeed100(ethUnit) rt_phyIsSpeed100(ethUnit)
++#define phyIsFullDuplex(ethUnit) rt_phyIsFullDuplex(ethUnit)
++#endif
++
++#if CONFIG_ICPLUS_ENET_PHY
++/*
++ * Mapping of generic phy APIs to Icplus phys.
++ */
++#include "ipPhy.h"
++#define phySetup(ethUnit, phyBase) ip_phySetup((ethUnit), (phyBase))
++#define phyCheckStatusChange(ethUnit) ip_phyCheckStatusChange(ethUnit)
++#define phyIsSpeed100(ethUnit) ip_phyIsSpeed100(ethUnit)
++#define phyIsFullDuplex(ethUnit) ip_phyIsFullDuplex(ethUnit)
++#endif
++
++#if !defined(PHY_TRAILER_SIZE)
++#define PHY_TRAILER_SIZE 0
++#endif
++
++/*****************************************************************
++ * MAC-independent interface to be used by PHY code
++ *
++ * These functions are provided by the MAC layer for use by the PHY layer.
++ */
++#define phyRegRead ae531x_MiiRead
++#define phyRegWrite ae531x_MiiWrite
++#define phyLinkLost(ethUnit) ae531x_unitLinkLost(ethUnit)
++#define phyLinkGained(ethUnit) ae531x_unitLinkGained(ethUnit)
++#define phyEthMacDefault() ae531x_ethMacDefault()
++
++void ae531x_unitLinkLost(int unit);
++void ae531x_unitLinkGained(int unit);
++int ae531x_ethMacDefault(void);
++
++
++/*
++ * RXBUFF_RESERVE enables building header on WLAN-side in place
++ * NB: Divisible by 2 but NOT 4. Otherwise handle_adel_int() will
++ * be used by the ip layer for misaligned word accesses and
++ * performance will suffer - a lot.
++ */
++#define ETH_CRC_LEN 4
++#define RXBUFF_RESERVE 98
++// #define RXBUFF_RESERVE 98
++
++/*****************************************************************
++ * Descriptor queue
++ */
++typedef struct ae531x_queue {
++ VIRT_ADDR firstDescAddr; /* descriptor array address */
++ VIRT_ADDR lastDescAddr; /* last descriptor address */
++ VIRT_ADDR curDescAddr; /* current descriptor address */
++ VIRT_ADDR reapDescAddr; /* current tail of tx descriptors reaped */
++ UINT16 count; /* number of elements */
++} AE531X_QUEUE;
++
++/* Given a descriptor, return the next one in a circular list */
++#define AE531X_QUEUE_ELE_NEXT_GET(q, descAddr) \
++ ((descAddr) == (q)->lastDescAddr) ? (q)->firstDescAddr : \
++ (VIRT_ADDR)((UINT32)(descAddr) + AE531X_QUEUE_ELE_SIZE)
++
++/* Move the "current descriptor" forward to the next one */
++#define AE531X_CONSUME_DESC(q) \
++ q->curDescAddr = AE531X_QUEUE_ELE_NEXT_GET(q, q->curDescAddr)
++
++/*****************************************************************
++ * Per-ethernet-MAC OS-independent information
++ */
++typedef struct ae531x_MAC_s {
++ u32 unit; /* MAC unit ID */
++ u32 macBase; /* MAC base address */
++ u32 dmaBase; /* DMA base address */
++ u32 phyBase; /* PHY base address */
++ AE531X_QUEUE txQueue; /* Transmit descriptor queue */
++ AE531X_QUEUE rxQueue; /* Receive descriptor queue */
++ UINT16 txDescCount; /* Transmit descriptor count */
++ UINT16 rxDescCount; /* Receive descriptor count */
++ BOOL aeProcessRst; /* flag to indicate reset in progress */
++ BOOL port_is_up; /* flag to indicate port is up */
++ void *OSinfo; /* OS-dependent data */
++} ae531x_MAC_t;
++
++#define AE531X_TX_DESC_COUNT_DEFAULT 128 /* Transmit descriptors */
++#define AE531X_RX_DESC_COUNT_DEFAULT 128 /* Receive descriptors */
++
++
++/*****************************************************************
++ * Interfaces exported by the OS-independent MAC layer
++ */
++void ae531x_BeginResetMode(ae531x_MAC_t *MACInfo);
++void ae531x_EndResetMode(ae531x_MAC_t *MACInfo);
++BOOL ae531x_IsInResetMode(ae531x_MAC_t *MACInfo);
++int ae531x_RxQueueCreate(ae531x_MAC_t *MACInfo, AE531X_QUEUE *q,
++ char *pMem, int count);
++int ae531x_QueueDelete(struct ae531x_queue *q);
++void ae531x_DmaReset(ae531x_MAC_t *MACInfo);
++void ae531x_MACReset(ae531x_MAC_t *MACInfo);
++void ae531x_EnableComm(ae531x_MAC_t *MACInfo);
++void ae531x_DisableComm(ae531x_MAC_t *MACInfo);
++void ae531x_reset(ae531x_MAC_t *MACInfo);
++int ae531x_AllocateQueues(ae531x_MAC_t *MACInfo);
++void ae531x_FreeQueues(ae531x_MAC_t *MACInfo);
++void ae531x_QueueInit(AE531X_QUEUE *q, char *pMem, int count);
++UINT32 ae531x_ReadMacReg(ae531x_MAC_t *MACInfo, UINT32 reg);
++void ae531x_WriteMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data);
++void ae531x_SetMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val);
++void ae531x_ClearMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val);
++void ae531x_SetDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val);
++void ae531x_ClearDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val);
++UINT32 ae531x_ReadDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg);
++void ae531x_WriteDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data);
++UINT32 ae531x_ReadMiiReg(UINT32 phyBase, UINT32 reg);
++void ae531x_WriteMiiReg(UINT32 phyBase, UINT32 reg, UINT32 data);
++UINT16 ae531x_MiiRead(UINT32 phyBase, UINT32 phyAddr, UINT8 reg);
++void ae531x_MiiWrite(UINT32 phyBase, UINT32 phyAddr, UINT8 reg, UINT16 data);
++void ae531x_DmaIntEnable(ae531x_MAC_t *MACInfo);
++void ae531x_DmaIntDisable(ae531x_MAC_t *MACInfo);
++void ae531x_AckIntr(ae531x_MAC_t *MACInfo, UINT32 val);
++void *ae531x_rxbuf_alloc(ae531x_MAC_t *MACInfo, char **rxBptr, int *rxBSize);
++void ae531x_swptr_free(VIRT_ADDR txDesc);
++BOOL ae531x_twisted_enet(void);
++
++#endif /* _AE531XMAC_H_ */
+diff -urN linux-mips-orig/drivers/net/ath/ae531xreg.h linux-mips-new/drivers/net/ath/ae531xreg.h
+--- linux-mips-orig/drivers/net/ath/ae531xreg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/ae531xreg.h 2005-12-31 12:33:57.675538520 +0000
+@@ -0,0 +1,439 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * See README to understand the decomposition of the ethernet driver.
++ *
++ * Register definitions for Atheros AR531X Ethernet MAC.
++ */
++
++#ifndef _AE531XREG_H_
++#define _AE531XREG_H_
++
++#define AE531X_MAC_OFFSET 0x0000
++#define AE531X_PHY_OFFSET 0x0000 /* Same as MAC offset */
++#define AE531X_DMA_OFFSET 0x1000
++
++/***********************************************************/
++/* MAC110 registers, base address is BAR+AE531X_MAC_OFFSET */
++/***********************************************************/
++#define MacControl 0x00 /* control */
++#define MacAddrHigh 0x04 /* address high */
++#define MacAddrLow 0x08 /* address low */
++#define MacMultiHashHigh 0x0C /* multicast hash table high */
++#define MacMultiHashLow 0x10 /* multicast hash table low */
++#define MacMiiAddr 0x14 /* MII address */
++#define MacMiiData 0x18 /* MII data */
++#define MacFlowControl 0x1C /* Flow control */
++#define MacVlan1Tag 0x4C /* VLAN1 tag */
++#define MacVlan2Tag 0x50 /* VLAN2 tag */
++
++
++/***************************************************************/
++/* DMA engine registers, base address is BAR+AE531X_DMA_OFFSET */
++/***************************************************************/
++#define DmaBusMode 0x00 /* CSR0 - Bus Mode */
++#define DmaTxPollDemand 0x04 /* CSR1 - Transmit Poll Demand */
++#define DmaRxPollDemand 0x08 /* CSR2 - Receive Poll Demand */
++#define DmaRxBaseAddr 0x0C /* CSR3 - Receive list base address */
++#define DmaTxBaseAddr 0x10 /* CSR4 - Transmit list base address */
++#define DmaStatus 0x14 /* CSR5 - Dma status */
++#define DmaControl 0x18 /* CSR6 - Dma control */
++#define DmaIntrEnb 0x1C /* CSR7 - Interrupt enable */
++#define DmaOverflowCnt 0x20 /* CSR8 - Missed Frame and Buff Overflow counter */
++#define DmaTxCurrAddr 0x50 /* CSR20 - Current host transmit buffer address */
++#define DmaRxCurrAddr 0x54 /* CSR21 - Current host receive buffer address */
++
++/**********************************************************/
++/* MAC Control register layout */
++/**********************************************************/
++#define MacFilterOff 0x80000000 /* Receive all incoming packets RW */
++#define MacFilterOn 0 /* Receive filtered packets only 0 */
++#define MacBigEndian 0x40000000 /* Big endian mode RW */
++#define MacLittleEndian 0 /* Little endian 0 */
++#define MacHeartBeatOff 0x10000000 /* Heartbeat signal qual disable RW*/
++#define MacHeartBeatOn 0 /* Heartbeat signal qual enable 0 */
++#define MacSelectSrl 0x08000000 /* Select SRL port RW */
++#define MacSelectMii 0 /* Select MII port 0 */
++#define MacDisableRxOwn 0x00800000 /* Disable receive own packets RW */
++#define MacEnableRxOwn 0 /* Enable receive own packets 0 */
++#define MacLoopbackExt 0x00400000 /* External loopback RW */
++#define MacLoopbackInt 0x00200000 /* Internal loopback */
++#define MacLoopbackOff 0 /* Normal mode 00 */
++#define MacFullDuplex 0x00100000 /* Full duplex mode RW */
++#define MacHalfDuplex 0 /* Half duplex mode 0 */
++#define MacMulticastFilterOff 0x00080000 /* Pass all multicast packets RW */
++#define MacMulticastFilterOn 0 /* Pass filtered mcast packets 0 */
++#define MacPromiscuousModeOn 0x00040000 /* Receive all valid packets RW 1 */
++#define MacPromiscuousModeOff 0 /* Receive filtered packets only */
++#define MacFilterInverse 0x00020000 /* Inverse filtering RW */
++#define MacFilterNormal 0 /* Normal filtering 0 */
++#define MacBadFramesEnable 0x00010000 /* Pass bad frames RW */
++#define MacBadFramesDisable 0 /* Do not pass bad frames 0 */
++#define MacPerfectFilterOff 0x00008000 /* Hash filtering only RW */
++#define MacPerfectFilterOn 0 /* Both perfect and hash filtering 0 */
++#define MacHashFilterOn 0x00002000 /* perform hash filtering RW */
++#define MacHashFilterOff 0 /* perfect filtering only 0 */
++#define MacLateCollisionOn 0x00001000 /* Enable late collision control RW */
++#define MacLateCollisionOff 0 /* Disable late collision control 0 */
++#define MacBroadcastDisable 0x00000800 /* Disable reception of bcast frames RW */
++#define MacBroadcastEnable 0 /* Enable broadcast frames 0 */
++#define MacRetryDisable 0x00000400 /* Disable retransmission RW */
++#define MacRetryEnable 0 /* Enable retransmission 0 */
++#define MacPadStripEnable 0x00000100 /* Pad stripping enable RW */
++#define MacPadStripDisable 0 /* Pad stripping disable 0 */
++#define MacBackoff 0 /* Backoff Limit RW 00 */
++#define MacDeferralCheckEnable 0x00000020 /* Deferral check enable RW */
++#define MacDeferralCheckDisable 0 /* Deferral check disable 0 */
++#define MacTxEnable 0x00000008 /* Transmitter enable RW */
++#define MacTxDisable 0 /* Transmitter disable 0 */
++#define MacRxEnable 0x00000004 /* Receiver enable RW */
++#define MacRxDisable 0 /* Receiver disable 0 */
++
++
++/**********************************************************/
++/* MII address register layout */
++/**********************************************************/
++#define MiiDevMask 0x0000F800 /* MII device address */
++#define MiiDevShift 11
++#define MiiRegMask 0x000007C0 /* MII register */
++#define MiiRegShift 6
++#define MiiWrite 0x00000002 /* Write to register */
++#define MiiRead 0 /* Read from register */
++#define MiiBusy 0x00000001 /* MII interface is busy */
++
++/**********************************************************/
++/* MII Data register layout */
++/**********************************************************/
++#define MiiDataMask 0x0000FFFF /* MII Data */
++
++/**********************************************************/
++/* MAC flow control register layout */
++/**********************************************************/
++#define MacPauseTimeMask 0xFFFF0000 /* PAUSE TIME field in ctrl frame */
++#define MacPauseTimeShift 15
++#define MacControlFrameEnable 0x00000004 /* Enable pass ctrl frames to host */
++#define MacControlFrameDisable 0 /* Do not pass ctrl frames to host */
++#define MacFlowControlEnable 0x00000002 /* Enable flow control */
++#define MacFlowControlDisable 0 /* Disable flow control */
++#define MacSendPauseFrame 0x00000001 /* send pause frame */
++
++/**********************************************************/
++/* DMA bus mode register layout */
++/**********************************************************/
++#define DmaRxAlign16 0x01000000 /* Force all rx buffers to align on odd hw bndry */
++#define DmaBigEndianDes 0x00100000 /* Big endian data buffer descriptors RW */
++#define DmaLittleEndianDesc 0 /* Little endian data descriptors */
++#define DmaBurstLength32 0x00002000 /* Dma burst length 32 RW */
++#define DmaBurstLength16 0x00001000 /* Dma burst length 16 */
++#define DmaBurstLength8 0x00000800 /* Dma burst length 8 */
++#define DmaBurstLength4 0x00000400 /* Dma burst length 4 */
++#define DmaBurstLength2 0x00000200 /* Dma burst length 2 */
++#define DmaBurstLength1 0x00000100 /* Dma burst length 1 */
++#define DmaBurstLength0 0x00000000 /* Dma burst length 0 */
++#define DmaBigEndianData 0x00000080 /* Big endian data buffers RW */
++#define DmaLittleEndianData 0 /* Little endian data buffers 0 */
++#define DmaDescriptorSkip16 0x00000040 /* number of dwords to skip RW */
++#define DmaDescriptorSkip8 0x00000020 /* between two unchained descriptors */
++#define DmaDescriptorSkip4 0x00000010
++#define DmaDescriptorSkip2 0x00000008
++#define DmaDescriptorSkip1 0x00000004
++#define DmaDescriptorSkip0 0
++#define DmaReceivePriorityOff 0x00000002 /* equal rx and tx priorities RW */
++#define DmaReceivePriorityOn 0 /* Rx has prioryty over Tx 0 */
++#define DmaResetOn 0x00000001 /* Reset DMA engine RW */
++#define DmaResetOff 0
++
++/**********************************************************/
++/* DMA Status register layout */
++/**********************************************************/
++#define DmaRxAbort 0x01000000 /* receiver bus abort R 0 */
++#define DmaTxAbort 0x00800000 /* transmitter bus abort R 0 */
++#define DmaTxState 0x00700000 /* Transmit process state R 000 */
++#define DmaTxStopped 0x00000000 /* Stopped */
++#define DmaTxFetching 0x00100000 /* Running - fetching the descriptor */
++#define DmaTxWaiting 0x00200000 /* Running - waiting for end of transmission */
++#define DmaTxReading 0x00300000 /* Running - reading the data from memory */
++#define DmaTxSuspended 0x00600000 /* Suspended */
++#define DmaTxClosing 0x00700000 /* Running - closing descriptor */
++#define DmaRxState 0x000E0000 /* Receive process state 000 */
++#define DmaRxStopped 0x00000000 /* Stopped */
++#define DmaRxFetching 0x00020000 /* Running - fetching the descriptor */
++#define DmaRxChecking 0x00040000 /* Running - checking for end of packet */
++#define DmaRxWaiting 0x00060000 /* Running - waiting for packet */
++#define DmaRxSuspended 0x00080000 /* Suspended */
++#define DmaRxClosing 0x000A0000 /* Running - closing descriptor */
++#define DmaRxFlushing 0x000C0000 /* Running - flushing the current frame */
++#define DmaRxQueuing 0x000E0000 /* Running - queuing the recieve frame into host memory */
++#define DmaIntNormal 0x00010000 /* Normal interrupt summary RW 0 */
++#define DmaIntAbnormal 0x00008000 /* Abnormal interrupt summary RW 0 */
++#define DmaIntEarlyRx 0x00004000 /* Early receive interrupt (Normal) RW 0 */
++#define DmaIntBusError 0x00002000 /* Fatal bus error (Abnormal) RW 0 */
++#define DmaIntEarlyTx 0x00000400 /* Early transmit interrupt RW 0 */
++#define DmaIntRxStopped 0x00000100 /* Receive process stopped (Abnormal) RW 0 */
++#define DmaIntRxNoBuffer 0x00000080 /* Receive buffer unavailable (Abnormal) RW 0*/
++#define DmaIntRxCompleted 0x00000040 /* Completion of frame reception(Normal) RW 0*/
++#define DmaIntTxUnderflow 0x00000020 /* Transmit underflow (Abnormal) RW 0 */
++#define DmaIntTxJabber 0x00000008 /* Transmit Jabber Timeout (Abnormal) RW 0 */
++#define DmaIntTxNoBuffer 0x00000004 /* Transmit buffer unavailable (Normal) RW 0*/
++#define DmaIntTxStopped 0x00000002 /* Transmit process stopped (Abnormal) RW 0 */
++#define DmaIntTxCompleted 0x00000001 /* Transmit completed (Normal) RW 0 */
++
++/**********************************************************/
++/* DMA control register layout */
++/**********************************************************/
++#define DmaStoreAndForward 0x00000000 /* Store and forward RW 0 */
++#define DmaTxThreshCtl256 0x0000c000 /* Non-SF threshold is 256 words */
++#define DmaTxThreshCtl128 0x00008000 /* Non-SF threshold is 128 words */
++#define DmaTxThreshCtl064 0x00004000 /* Non-SF threshold is 64 words */
++#define DmaTxThreshCtl032 0x00000000 /* Non-SF threshold is 32 words */
++#define DmaTxStart 0x00002000 /* Start/Stop transmission RW 0 */
++#define DmaTxSecondFrame 0x00000004 /* Operate on second frame RW 0 */
++#define DmaRxStart 0x00000002 /* Start/Stop reception RW 0 */
++
++/**********************************************************/
++/* DMA interrupt enable register layout */
++/**********************************************************/
++#define DmaIeNormal DmaIntNormal /* Normal interrupt enable RW 0 */
++#define DmaIeAbnormal DmaIntAbnormal /* Abnormal interrupt enable RW 0 */
++#define DmaIeEarlyRx DmaIntEarlyRx /* Early receive interrupt enable RW 0 */
++#define DmaIeBusError DmaIntBusError /* Fatal bus error enable RW 0 */
++#define DmaIeEarlyTx DmaIntEarlyTx /* Early transmit interrupt enable RW 0 */
++#define DmaIeRxStopped DmaIntRxStopped /* Receive process stopped enable RW 0 */
++#define DmaIeRxNoBuffer DmaIntRxNoBuffer /* Receive buffer unavailable enable RW 0 */
++#define DmaIeRxCompleted DmaIntRxCompleted /* Completion of frame reception enable RW 0 */
++#define DmaIeTxUnderflow DmaIntTxUnderflow /* Transmit underflow enable RW 0 */
++#define DmaIeTxJabber DmaIntTxJabber /* Transmit jabber timeout RW 0 */
++#define DmaIeTxNoBuffer DmaIntTxNoBuffer /* Transmit buffer unavailable enable RW 0 */
++#define DmaIeTxStopped DmaIntTxStopped /* Transmit process stopped enable RW 0 */
++#define DmaIeTxCompleted DmaIntTxCompleted /* Transmit completed enable RW 0 */
++
++/****************************************************************/
++/* DMA Missed Frame and Buffer Overflow Counter register layout */
++/****************************************************************/
++#define DmaRxBufferMissedFrame 0xffff0000 /* cleared on read */
++#define DmaMissedFrameShift 16
++#define DmaRxBufferOverflowCnt 0x0000ffff /* cleared on read */
++#define DmaMissedFrameCountMask 0x0000ffff
++
++/**********************************************************/
++/* DMA Engine descriptor layout */
++/**********************************************************/
++/* status word of DMA descriptor */
++#define DescOwnByDma 0x80000000 /* Descriptor is owned by DMA engine */
++#define DescFrameLengthMask 0x3FFF0000 /* Receive descriptor frame length */
++#define DescFrameLengthShift 16
++#define DescError 0x00008000 /* Error summary bit OR of following bits */
++#define DescRxTruncated 0x00004000 /* Rx - no more descs for receive frame */
++#define DescRxLengthError 0x00001000 /* Rx - frame size not matching with length field */
++#define DescRxRunt 0x00000800 /* Rx - runt frame, damaged by a
++ collision or term before 64 bytes */
++#define DescRxMulticast 0x00000400 /* Rx - received frame is multicast */
++#define DescRxFirst 0x00000200 /* Rx - first descriptor of the frame */
++#define DescRxLast 0x00000100 /* Rx - last descriptor of the frame */
++#define DescRxLongFrame 0x00000080 /* Rx - frame is longer than 1518 bytes */
++#define DescRxLateColl 0x00000040 /* Rx - frame was damaged by a late collision */
++#define DescRxFrameEther 0x00000020 /* Rx - Frame type Ethernet 802.3*/
++#define DescRxMiiError 0x00000008 /* Rx - error reported by MII interface */
++#define DescRxDribbling 0x00000004 /* Rx - frame contains noninteger multiple of 8 bits */
++#define DescRxCrc 0x00000002 /* Rx - CRC error */
++#define DescTxTimeout 0x00004000 /* Tx - Transmit jabber timeout */
++#define DescTxLostCarrier 0x00000800 /* Tx - carrier lost during tramsmission */
++#define DescTxNoCarrier 0x00000400 /* Tx - no carrier signal from tranceiver */
++#define DescTxLateCollision 0x00000200 /* Tx - transmission aborted due to collision */
++#define DescTxExcCollisions 0x00000100 /* Tx - transmission aborted after 16 collisions */
++#define DescTxHeartbeatFail 0x00000080 /* Tx - heartbeat collision check failure */
++#define DescTxCollMask 0x00000078 /* Tx - Collision count */
++#define DescTxCollShift 3
++#define DescTxExcDeferral 0x00000004 /* Tx - excessive deferral */
++#define DescTxUnderflow 0x00000002 /* Tx - late data arrival from memory */
++#define DescTxDeferred 0x00000001 /* Tx - frame transmision deferred */
++
++/* length word of DMA descriptor */
++#define DescTxIntEnable 0x80000000 /* Tx - interrupt on completion */
++#define DescTxLast 0x40000000 /* Tx - Last segment of the frame */
++#define DescTxFirst 0x20000000 /* Tx - First segment of the frame */
++#define DescTxDisableCrc 0x04000000 /* Tx - Add CRC disabled (first segment only) */
++#define DescEndOfRing 0x02000000 /* End of descriptors ring */
++#define DescChain 0x01000000 /* Second buffer address is chain address */
++#define DescTxDisablePadd 0x00800000 /* disable padding */
++#define DescSize2Mask 0x003FF800 /* Buffer 2 size */
++#define DescSize2Shift 11
++#define DescSize1Mask 0x000007FF /* Buffer 1 size */
++#define DescSize1Shift 0
++
++/**********************************************************/
++/* Initial register values */
++/**********************************************************/
++/* Full-duplex mode with perfect filter on */
++#define MacControlInitFdx \
++ ( MacFilterOn \
++ | MacLittleEndian \
++ | MacHeartBeatOn \
++ | MacSelectMii \
++ | MacEnableRxOwn \
++ | MacLoopbackOff \
++ | MacFullDuplex \
++ | MacMulticastFilterOn \
++ | MacPromiscuousModeOff \
++ | MacFilterNormal \
++ | MacBadFramesDisable \
++ | MacPerfectFilterOn \
++ | MacHashFilterOff \
++ | MacLateCollisionOff \
++ | MacBroadcastEnable \
++ | MacRetryEnable \
++ | MacPadStripDisable \
++ | MacDeferralCheckDisable \
++ | MacTxEnable \
++ | MacRxEnable)
++
++/* Full-duplex mode */
++#define MacFlowControlInitFdx \
++ ( MacControlFrameDisable \
++ | MacFlowControlEnable)
++
++/* Half-duplex mode with perfect filter on */
++#define MacControlInitHdx \
++ ( MacFilterOn \
++ | MacLittleEndian \
++ | MacHeartBeatOn \
++ | MacSelectMii \
++ | MacDisableRxOwn \
++ | MacLoopbackOff \
++ | MacHalfDuplex \
++ | MacMulticastFilterOn \
++ | MacPromiscuousModeOff \
++ | MacFilterNormal \
++ | MacBadFramesDisable \
++ | MacPerfectFilterOn \
++ | MacHashFilterOff \
++ | MacLateCollisionOff \
++ | MacBroadcastEnable \
++ | MacRetryEnable \
++ | MacPadStripDisable \
++ | MacDeferralCheckDisable \
++ | MacTxEnable \
++ | MacRxEnable)
++
++/* Half-duplex mode */
++#define MacFlowControlInitHdx \
++ ( MacControlFrameDisable \
++ | MacFlowControlDisable)
++
++/* Bus Mode Rx odd half word align */
++#define DmaBusModeInit \
++ ( DmaLittleEndianDesc \
++ | DmaRxAlign16 \
++ | DmaBurstLength32 \
++ | DmaBigEndianData \
++ | DmaDescriptorSkip1 \
++ | DmaReceivePriorityOn \
++ | DmaResetOff)
++
++#define DmaControlInit (DmaStoreAndForward)
++
++/* Interrupt groups */
++#define DmaIntEnable \
++ ( DmaIeNormal \
++ | DmaIeAbnormal \
++ | DmaIntBusError \
++ | DmaIntRxStopped \
++ | DmaIntRxNoBuffer \
++ | DmaIntRxCompleted \
++ | DmaIntTxUnderflow \
++ | DmaIntTxStopped)
++
++#define DmaIntDisable 0
++
++#define DmaAllIntCauseMask \
++ ( DmaIeNormal \
++ | DmaIeAbnormal \
++ | DmaIntEarlyRx \
++ | DmaIntBusError \
++ | DmaIntEarlyTx \
++ | DmaIntRxStopped \
++ | DmaIntRxNoBuffer \
++ | DmaIntRxCompleted \
++ | DmaIntTxUnderflow \
++ | DmaIntTxJabber \
++ | DmaIntTxNoBuffer \
++ | DmaIntTxStopped \
++ | DmaIntTxCompleted)
++
++#define UnhandledIntrMask \
++ (DmaAllIntCauseMask \
++ & ~(DmaIntRxNoBuffer \
++ | DmaIntTxStopped \
++ | DmaIntTxJabber \
++ | DmaIntTxUnderflow \
++ | DmaIntBusError \
++ | DmaIntRxCompleted ))
++
++#define DescRxErrors \
++ (DescRxTruncated \
++ | DescRxRunt \
++ | DescRxLateColl \
++ | DescRxMiiError \
++ | DescRxCrc)
++
++#define DescTxErrors \
++ ( DescTxTimeout \
++ | DescTxLateCollision \
++ | DescTxExcCollisions \
++ | DescTxExcDeferral \
++ | DescTxUnderflow)
++
++/**********************************************************/
++/* Descriptor Layout */
++/**********************************************************/
++#define AE531X_DESC_STATUS 0x00 /* Status offset */
++#define AE531X_DESC_CTRLEN 0x04 /* Control and Length offset */
++#define AE531X_DESC_BUFPTR 0x08 /* Buffer pointer offset */
++#define AE531X_DESC_LNKBUF 0x0c /* Link field offset, or ptr to 2nd buf */
++#define AE531X_DESC_SWPTR 0x10 /* OS-Dependent software pointer */
++
++#define AE531X_DESC_SIZE 0x10 /* 4 words, 16 bytes */
++#define AE531X_QUEUE_ELE_SIZE 0x14 /* with software pointer extension */
++
++/* Accessors to the dma descriptor fields */
++#define AE531X_DESC_STATUS_GET(ptr) \
++ *(volatile UINT32 *)((UINT32)(ptr) + AE531X_DESC_STATUS)
++
++#define AE531X_DESC_STATUS_SET(ptr, val) \
++ AE531X_DESC_STATUS_GET(ptr) = (val)
++
++#define AE531X_DESC_CTRLEN_GET(ptr) \
++ *(volatile UINT32 *)((UINT32)ptr + AE531X_DESC_CTRLEN)
++
++#define AE531X_DESC_CTRLEN_SET(ptr, val) \
++ AE531X_DESC_CTRLEN_GET(ptr) = (val)
++
++#define AE531X_DESC_BUFPTR_GET(ptr) \
++ *(volatile UINT32 *)((UINT32)ptr + AE531X_DESC_BUFPTR)
++
++#define AE531X_DESC_BUFPTR_SET(ptr,val) \
++ AE531X_DESC_BUFPTR_GET(ptr) = (UINT32)(val)
++
++#define AE531X_DESC_LNKBUF_GET(ptr) \
++ *(volatile UINT32 *)((UINT32)ptr + AE531X_DESC_LNKBUF)
++
++#define AE531X_DESC_LNKBUF_SET(ptr, val) \
++ AE531X_DESC_LNKBUF_GET(ptr) = (val)
++
++#define AE531X_DESC_SWPTR_GET(ptr) \
++ (void *)(*(volatile UINT32 *) ((UINT32)ptr + AE531X_DESC_SWPTR))
++
++#define AE531X_DESC_SWPTR_SET(ptr,val) \
++ AE531X_DESC_SWPTR_GET(ptr) = (void *)(val)
++
++/* Get size of Rx data from desc, in bytes */
++#define AE531X_DESC_STATUS_RX_SIZE(x) \
++ (((x) & DescFrameLengthMask) >> DescFrameLengthShift)
++
++#endif /* _AE531XREG_H_ */
+diff -urN linux-mips-orig/drivers/net/ath/ar531x.h linux-mips-new/drivers/net/ath/ar531x.h
+--- linux-mips-orig/drivers/net/ath/ar531x.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/ar531x.h 2005-12-31 12:33:57.676538368 +0000
+@@ -0,0 +1,1124 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++#ifndef AR531X_H
++#define AR531X_H 1
++
++
++#ifndef CONFIG_AR5315
++
++#include <asm/addrspace.h>
++
++/* Address Map */
++#define AR531X_WLAN0 0x18000000
++#define AR531X_WLAN1 0x18500000
++#define AR531X_ENET0 0x18100000
++#define AR531X_ENET1 0x18200000
++#define AR531X_SDRAMCTL 0x18300000
++#define AR531X_FLASHCTL 0x18400000
++#define AR531X_APBBASE 0x1c000000
++#define AR531X_FLASH 0x1e000000
++
++/*
++ * AR531X_NUM_ENET_MAC defines the number of ethernet MACs that
++ * should be considered available. The AR5312 supports 2 enet MACS,
++ * even though many reference boards only actually use 1 of them
++ * (i.e. Only MAC 0 is actually connected to an enet PHY or PHY switch.
++ * The AR2312 supports 1 enet MAC.
++ */
++#define AR531X_NUM_ENET_MAC 2
++
++/*
++ * Need these defines to determine true number of ethernet MACs
++ */
++#define AR5212_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */
++#define AR5212_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */
++#define AR5212_AR2313_REV8 0x0058 /* AR2313 WMAC (AP43-030) */
++#define AR531X_RADIO_MASK_OFF 0xc8
++#define AR531X_RADIO0_MASK 0x0003
++#define AR531X_RADIO1_MASK 0x000c
++#define AR531X_RADIO1_S 2
++
++/*
++ * AR531X_NUM_WMAC defines the number of Wireless MACs that\
++ * should be considered available.
++ */
++#define AR531X_NUM_WMAC 2
++
++/* Reset/Timer Block Address Map */
++#define AR531X_RESETTMR (AR531X_APBBASE + 0x3000)
++#define AR531X_TIMER (AR531X_RESETTMR + 0x0000) /* countdown timer */
++#define AR531X_WD_CTRL (AR531X_RESETTMR + 0x0008) /* watchdog cntrl */
++#define AR531X_WD_TIMER (AR531X_RESETTMR + 0x000c) /* watchdog timer */
++#define AR531X_ISR (AR531X_RESETTMR + 0x0010) /* Intr Status Reg */
++#define AR531X_IMR (AR531X_RESETTMR + 0x0014) /* Intr Mask Reg */
++#define AR531X_RESET (AR531X_RESETTMR + 0x0020)
++#define AR5312_CLOCKCTL1 (AR531X_RESETTMR + 0x0064)
++#define AR5312_SCRATCH (AR531X_RESETTMR + 0x006c)
++#define AR531X_PROCADDR (AR531X_RESETTMR + 0x0070)
++#define AR531X_PROC1 (AR531X_RESETTMR + 0x0074)
++#define AR531X_DMAADDR (AR531X_RESETTMR + 0x0078)
++#define AR531X_DMA1 (AR531X_RESETTMR + 0x007c)
++#define AR531X_ENABLE (AR531X_RESETTMR + 0x0080) /* interface enb */
++#define AR531X_REV (AR531X_RESETTMR + 0x0090) /* revision */
++
++/* AR531X_WD_CTRL register bit field definitions */
++#define AR531X_WD_CTRL_IGNORE_EXPIRATION 0x0000
++#define AR531X_WD_CTRL_NMI 0x0001
++#define AR531X_WD_CTRL_RESET 0x0002
++
++/* AR531X_ISR register bit field definitions */
++#define AR531X_ISR_NONE 0x0000
++#define AR531X_ISR_TIMER 0x0001
++#define AR531X_ISR_AHBPROC 0x0002
++#define AR531X_ISR_AHBDMA 0x0004
++#define AR531X_ISR_GPIO 0x0008
++#define AR531X_ISR_UART0 0x0010
++#define AR531X_ISR_UART0DMA 0x0020
++#define AR531X_ISR_WD 0x0040
++#define AR531X_ISR_LOCAL 0x0080
++
++/* AR531X_RESET register bit field definitions */
++#define AR531X_RESET_SYSTEM 0x00000001 /* cold reset full system */
++#define AR531X_RESET_PROC 0x00000002 /* cold reset MIPS core */
++#define AR531X_RESET_WLAN0 0x00000004 /* cold reset WLAN MAC and BB */
++#define AR531X_RESET_EPHY0 0x00000008 /* cold reset ENET0 phy */
++#define AR531X_RESET_EPHY1 0x00000010 /* cold reset ENET1 phy */
++#define AR531X_RESET_ENET0 0x00000020 /* cold reset ENET0 mac */
++#define AR531X_RESET_ENET1 0x00000040 /* cold reset ENET1 mac */
++#define AR531X_RESET_UART0 0x00000100 /* cold reset UART0 (high speed) */
++#define AR531X_RESET_WLAN1 0x00000200 /* cold reset WLAN MAC/BB */
++#define AR531X_RESET_APB 0x00000400 /* cold reset APB (ar5312) */
++#define AR531X_RESET_WARM_PROC 0x00001000 /* warm reset MIPS core */
++#define AR531X_RESET_WARM_WLAN0_MAC 0x00002000 /* warm reset WLAN0 MAC */
++#define AR531X_RESET_WARM_WLAN0_BB 0x00004000 /* warm reset WLAN0 BaseBand */
++#define AR531X_RESET_NMI 0x00010000 /* send an NMI to the processor */
++#define AR531X_RESET_WARM_WLAN1_MAC 0x00020000 /* warm reset WLAN1 mac */
++#define AR531X_RESET_WARM_WLAN1_BB 0x00040000 /* warm reset WLAN1 baseband */
++#define AR531X_RESET_LOCAL_BUS 0x00080000 /* reset local bus */
++#define AR531X_RESET_WDOG 0x00100000 /* last reset was a watchdog */
++
++#define AR531X_RESET_WMAC0_BITS \
++ AR531X_RESET_WLAN0 |\
++ AR531X_RESET_WARM_WLAN0_MAC |\
++ AR531X_RESET_WARM_WLAN0_BB
++
++#define AR531X_RESERT_WMAC1_BITS \
++ AR531X_RESET_WLAN1 |\
++ AR531X_RESET_WARM_WLAN1_MAC |\
++ AR531X_RESET_WARM_WLAN1_BB
++
++/* AR5312_CLOCKCTL1 register bit field definitions */
++#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030
++#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4
++#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00
++#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8
++#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000
++
++/* Valid for AR5312 and AR2312 */
++#define AR5312_CLOCKCTL1_PREDIVIDE_MASK 0x00000030
++#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT 4
++#define AR5312_CLOCKCTL1_MULTIPLIER_MASK 0x00001f00
++#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT 8
++#define AR5312_CLOCKCTL1_DOUBLER_MASK 0x00010000
++
++/* Valid for AR2313 */
++#define AR2313_CLOCKCTL1_PREDIVIDE_MASK 0x00003000
++#define AR2313_CLOCKCTL1_PREDIVIDE_SHIFT 12
++#define AR2313_CLOCKCTL1_MULTIPLIER_MASK 0x001f0000
++#define AR2313_CLOCKCTL1_MULTIPLIER_SHIFT 16
++#define AR2313_CLOCKCTL1_DOUBLER_MASK 0x00000000
++
++
++/* AR531X_ENABLE register bit field definitions */
++#define AR531X_ENABLE_WLAN0 0x0001
++#define AR531X_ENABLE_ENET0 0x0002
++#define AR531X_ENABLE_ENET1 0x0004
++#define AR531X_ENABLE_UART_AND_WLAN1_PIO 0x0008 /* UART, and WLAN1 PIOs */
++#define AR531X_ENABLE_WLAN1_DMA 0x0010 /* WLAN1 DMAs */
++#define AR531X_ENABLE_WLAN1 \
++ (AR531X_ENABLE_UART_AND_WLAN1_PIO | AR531X_ENABLE_WLAN1_DMA)
++
++/* AR531X_REV register bit field definitions */
++#define AR531X_REV_WMAC_MAJ 0xf000
++#define AR531X_REV_WMAC_MAJ_S 12
++#define AR531X_REV_WMAC_MIN 0x0f00
++#define AR531X_REV_WMAC_MIN_S 8
++#define AR531X_REV_MAJ 0x00f0
++#define AR531X_REV_MAJ_S 4
++#define AR531X_REV_MIN 0x000f
++#define AR531X_REV_MIN_S 0
++#define AR531X_REV_CHIP (REV_MAJ|REV_MIN)
++
++/* Major revision numbers, bits 7..4 of Revision ID register */
++#define AR531X_REV_MAJ_AR5312 0x4
++#define AR531X_REV_MAJ_AR2313 0x5
++
++/* Minor revision numbers, bits 3..0 of Revision ID register */
++#define AR5312_REV_MIN_DUAL 0x0 /* Dual WLAN version */
++#define AR5312_REV_MIN_SINGLE 0x1 /* Single WLAN version */
++
++/* AR531X_FLASHCTL register bit field definitions */
++#define FLASHCTL_IDCY 0x0000000f /* Idle cycle turn around time */
++#define FLASHCTL_IDCY_S 0
++#define FLASHCTL_WST1 0x000003e0 /* Wait state 1 */
++#define FLASHCTL_WST1_S 5
++#define FLASHCTL_RBLE 0x00000400 /* Read byte lane enable */
++#define FLASHCTL_WST2 0x0000f800 /* Wait state 2 */
++#define FLASHCTL_WST2_S 11
++#define FLASHCTL_AC 0x00070000 /* Flash address check (added) */
++#define FLASHCTL_AC_S 16
++#define FLASHCTL_AC_128K 0x00000000
++#define FLASHCTL_AC_256K 0x00010000
++#define FLASHCTL_AC_512K 0x00020000
++#define FLASHCTL_AC_1M 0x00030000
++#define FLASHCTL_AC_2M 0x00040000
++#define FLASHCTL_AC_4M 0x00050000
++#define FLASHCTL_AC_8M 0x00060000
++#define FLASHCTL_AC_RES 0x00070000 /* 16MB is not supported */
++#define FLASHCTL_E 0x00080000 /* Flash bank enable (added) */
++#define FLASHCTL_BUSERR 0x01000000 /* Bus transfer error status flag */
++#define FLASHCTL_WPERR 0x02000000 /* Write protect error status flag */
++#define FLASHCTL_WP 0x04000000 /* Write protect */
++#define FLASHCTL_BM 0x08000000 /* Burst mode */
++#define FLASHCTL_MW 0x30000000 /* Memory width */
++#define FLASHCTL_MWx8 0x00000000 /* Memory width x8 */
++#define FLASHCTL_MWx16 0x10000000 /* Memory width x16 */
++#define FLASHCTL_MWx32 0x20000000 /* Memory width x32 (not supported) */
++#define FLASHCTL_ATNR 0x00000000 /* Access type == no retry */
++#define FLASHCTL_ATR 0x80000000 /* Access type == retry every */
++#define FLASHCTL_ATR4 0xc0000000 /* Access type == retry every 4 */
++
++/* ARM Flash Controller -- 3 flash banks with either x8 or x16 devices. */
++#define AR531X_FLASHCTL0 (AR531X_FLASHCTL + 0x00)
++#define AR531X_FLASHCTL1 (AR531X_FLASHCTL + 0x04)
++#define AR531X_FLASHCTL2 (AR531X_FLASHCTL + 0x08)
++
++/* ARM SDRAM Controller -- just enough to determine memory size */
++#define AR531X_MEM_CFG1 (AR531X_SDRAMCTL + 0x04)
++#define MEM_CFG1_AC0 0x00000700 /* bank 0: SDRAM addr check (added) */
++#define MEM_CFG1_AC0_S 8
++#define MEM_CFG1_AC1 0x00007000 /* bank 1: SDRAM addr check (added) */
++#define MEM_CFG1_AC1_S 12
++
++/* GPIO Address Map */
++#define AR531X_GPIO (AR531X_APBBASE + 0x2000)
++#define AR531X_GPIO_DO (AR531X_GPIO + 0x00) /* output register */
++#define AR531X_GPIO_DI (AR531X_GPIO + 0x04) /* intput register */
++#define AR531X_GPIO_CR (AR531X_GPIO + 0x08) /* control register */
++
++/* GPIO Control Register bit field definitions */
++#define GPIO_CR_M(x) (1 << (x)) /* mask for i/o */
++#define GPIO_CR_O(x) (0 << (x)) /* mask for output */
++#define GPIO_CR_I(x) (1 << (x)) /* mask for input */
++#define GPIO_CR_INT(x) (1 << ((x)+8)) /* mask for interrupt */
++#define GPIO_CR_UART(x) (1 << ((x)+16)) /* uart multiplex */
++
++
++typedef unsigned int AR531X_REG;
++
++#define sysRegRead(phys) \
++ (*(volatile AR531X_REG *)PHYS_TO_K1(phys))
++
++#define sysRegWrite(phys, val) \
++ ((*(volatile AR531X_REG *)PHYS_TO_K1(phys)) = (val))
++
++
++/*
++ * This is board-specific data that is stored in a "fixed" location in flash.
++ * It is shared across operating systems, so it should not be changed lightly.
++ * The main reason we need it is in order to extract the ethernet MAC
++ * address(es).
++ */
++struct ar531x_boarddata {
++ u32 magic; /* board data is valid */
++#define AR531X_BD_MAGIC 0x35333131 /* "5311", for all 531x platforms */
++ u16 cksum; /* checksum (starting with BD_REV 2) */
++ u16 rev; /* revision of this struct */
++#define BD_REV 4
++ char boardName[64]; /* Name of board */
++ u16 major; /* Board major number */
++ u16 minor; /* Board minor number */
++ u32 config; /* Board configuration */
++#define BD_ENET0 0x00000001 /* ENET0 is stuffed */
++#define BD_ENET1 0x00000002 /* ENET1 is stuffed */
++#define BD_UART1 0x00000004 /* UART1 is stuffed */
++#define BD_UART0 0x00000008 /* UART0 is stuffed (dma) */
++#define BD_RSTFACTORY 0x00000010 /* Reset factory defaults stuffed */
++#define BD_SYSLED 0x00000020 /* System LED stuffed */
++#define BD_EXTUARTCLK 0x00000040 /* External UART clock */
++#define BD_CPUFREQ 0x00000080 /* cpu freq is valid in nvram */
++#define BD_SYSFREQ 0x00000100 /* sys freq is set in nvram */
++#define BD_WLAN0 0x00000200 /* Enable WLAN0 */
++#define BD_MEMCAP 0x00000400 /* CAP SDRAM @ memCap for testing */
++#define BD_DISWATCHDOG 0x00000800 /* disable system watchdog */
++#define BD_WLAN1 0x00001000 /* Enable WLAN1 (ar5212) */
++#define BD_ISCASPER 0x00002000 /* FLAG for AR2312 */
++#define BD_WLAN0_2G_EN 0x00004000 /* FLAG for radio0_2G */
++#define BD_WLAN0_5G_EN 0x00008000 /* FLAG for radio0_2G */
++#define BD_WLAN1_2G_EN 0x00020000 /* FLAG for radio0_2G */
++#define BD_WLAN1_5G_EN 0x00040000 /* FLAG for radio0_2G */
++ u16 resetConfigGpio; /* Reset factory GPIO pin */
++ u16 sysLedGpio; /* System LED GPIO pin */
++
++ u32 cpuFreq; /* CPU core frequency in Hz */
++ u32 sysFreq; /* System frequency in Hz */
++ u32 cntFreq; /* Calculated C0_COUNT frequency */
++
++ u8 wlan0Mac[6];
++ u8 enet0Mac[6];
++ u8 enet1Mac[6];
++
++ u16 pciId; /* Pseudo PCIID for common code */
++ u16 memCap; /* cap bank1 in MB */
++
++ /* version 3 */
++ u8 wlan1Mac[6]; /* (ar5212) */
++};
++
++#else
++
++/*
++ * Add support for Cobra
++ *
++ * AR531XPLUSreg.h Register definitions for Atheros AR5311 and AR5312 chipsets.
++ * - WLAN registers are listed in
++ * hal/ar5211/ar5211Reg.h
++ * hal/ar5212/ar5212Reg.h
++ * - Ethernet registers are listed in ar531xenet.h
++ * - Standard UART is 16550 compatible.
++ */
++
++
++/*
++ * Address map
++ */
++#define AR531XPLUS_SDRAM0 0x00000000 /* DRAM */
++#define AR531XPLUS_SPI_READ 0x08000000 /* SPI FLASH */
++#define AR531XPLUS_WLAN0 0xB0000000 /* Wireless MMR */
++#define AR531XPLUS_PCI 0xB0100000 /* PCI MMR */
++#define AR531XPLUS_SDRAMCTL 0xB0300000 /* SDRAM MMR */
++#define AR531XPLUS_LOCAL 0xB0400000 /* LOCAL BUS MMR */
++#define AR531XPLUS_ENET0 0xB0500000 /* ETHERNET MMR */
++#define AR531XPLUS_DSLBASE 0xB1000000 /* RESET CONTROL MMR */
++#define AR531XPLUS_UART0 0xB1100003 /* UART MMR */
++#define AR531XPLUS_SPI 0xB1300000 /* SPI FLASH MMR */
++#define AR531XPLUS_FLASHBT 0xBfc00000 /* ro boot alias to FLASH */
++#define AR531XPLUS_RAM1 0x40000000 /* ram alias */
++#define AR531XPLUS_PCIEXT 0x80000000 /* pci external */
++#define AR531XPLUS_RAM2 0xc0000000 /* ram alias */
++#define AR531XPLUS_RAM3 0xe0000000 /* ram alias */
++
++#define AR531X_ENET0 AR531XPLUS_ENET0
++#define AR531X_ENET1 0
++/*
++ * Reset Register
++ */
++#define AR531XPLUS_COLD_RESET (AR531XPLUS_DSLBASE + 0x0000)
++
++/* Cold Reset */
++#define RESET_COLD_AHB 0x00000001
++#define RESET_COLD_APB 0x00000002
++#define RESET_COLD_CPU 0x00000004
++#define RESET_COLD_CPUWARM 0x00000008
++#define RESET_SYSTEM (RESET_COLD_CPU | RESET_COLD_APB | RESET_COLD_AHB) /* full system */
++
++/* Warm Reset */
++
++#define AR531XPLUS_RESET (AR531XPLUS_DSLBASE + 0x0004)
++#define AR531X_RESET AR531XPLUS_RESET
++
++#define RESET_WARM_WLAN0_MAC 0x00000001 /* warm reset WLAN0 MAC */
++#define RESET_WARM_WLAN0_BB 0x00000002 /* warm reset WLAN0 BaseBand */
++#define RESET_MPEGTS_RSVD 0x00000004 /* warm reset MPEG-TS */
++#define RESET_PCIDMA 0x00000008 /* warm reset PCI ahb/dma */
++#define RESET_MEMCTL 0x00000010 /* warm reset memory controller */
++#define RESET_LOCAL 0x00000020 /* warm reset local bus */
++#define RESET_I2C_RSVD 0x00000040 /* warm reset I2C bus */
++#define RESET_SPI 0x00000080 /* warm reset SPI interface */
++#define RESET_UART0 0x00000100 /* warm reset UART0 */
++#define RESET_IR_RSVD 0x00000200 /* warm reset IR interface */
++#define RESET_EPHY0 0x00000400 /* cold reset ENET0 phy */
++#define RESET_ENET0 0x00000800 /* cold reset ENET0 mac */
++
++#define AR531X_RESET_ENET0 RESET_ENET0
++#define AR531X_RESET_EPHY0 RESET_EPHY0
++#define AR531X_RESET_ENET1 0
++#define AR531X_RESET_EPHY1 0
++
++/*
++ * AHB master arbitration control
++ */
++#define AR531XPLUS_AHB_ARB_CTL (AR531XPLUS_DSLBASE + 0x0008)
++
++#define ARB_CPU 0x00000001 /* CPU, default */
++#define ARB_WLAN 0x00000002 /* WLAN */
++#define ARB_MPEGTS_RSVD 0x00000004 /* MPEG-TS */
++#define ARB_LOCAL 0x00000008 /* LOCAL */
++#define ARB_PCI 0x00000010 /* PCI */
++#define ARB_ETHERNET 0x00000020 /* Ethernet */
++#define ARB_RETRY 0x00000100 /* retry policy, debug only */
++
++/*
++ * Config Register
++ */
++#define AR531XPLUS_ENDIAN_CTL (AR531XPLUS_DSLBASE + 0x000c)
++
++#define CONFIG_AHB 0x00000001 /* EC - AHB bridge endianess */
++#define CONFIG_WLAN 0x00000002 /* WLAN byteswap */
++#define CONFIG_MPEGTS_RSVD 0x00000004 /* MPEG-TS byteswap */
++#define CONFIG_PCI 0x00000008 /* PCI byteswap */
++#define CONFIG_MEMCTL 0x00000010 /* Memory controller endianess */
++#define CONFIG_LOCAL 0x00000020 /* Local bus byteswap */
++#define CONFIG_ETHERNET 0x00000040 /* Ethernet byteswap */
++
++#define CONFIG_MERGE 0x00000200 /* CPU write buffer merge */
++#define CONFIG_CPU 0x00000400 /* CPU big endian */
++#define CONFIG_PCIAHB 0x00000800
++#define CONFIG_PCIAHB_BRIDGE 0x00001000
++#define CONFIG_SPI 0x00008000 /* SPI byteswap */
++#define CONFIG_CPU_DRAM 0x00010000
++#define CONFIG_CPU_PCI 0x00020000
++#define CONFIG_CPU_MMR 0x00040000
++#define CONFIG_BIG 0x00000400
++
++
++/*
++ * NMI control
++ */
++#define AR531XPLUS_NMI_CTL (AR531XPLUS_DSLBASE + 0x0010)
++
++#define NMI_EN 1
++
++/*
++ * Revision Register - Initial value is 0x3010 (WMAC 3.0, AR531X 1.0).
++ */
++#define AR531XPLUS_SREV (AR531XPLUS_DSLBASE + 0x0014)
++
++#define AR531X_REV AR531XPLUS_SREV
++
++#define REV_MAJ 0x00f0
++#define REV_MAJ_S 4
++#define REV_MIN 0x000f
++#define REV_MIN_S 0
++#define REV_CHIP (REV_MAJ|REV_MIN)
++
++#define AR531X_REV_MAJ REV_MAJ
++#define AR531X_REV_MAJ_S REV_MAJ_S
++#define AR531X_REV_MIN REV_MIN
++#define AR531X_REV_MIN_S REV_MIN_S
++#define REV_CHIP (REV_MAJ|REV_MIN)
++/*
++ * Need these defines to determine true number of ethernet MACs
++ */
++#define AR5212_AR5312_REV2 0x0052 /* AR5312 WMAC (AP31) */
++#define AR5212_AR5312_REV7 0x0057 /* AR5312 WMAC (AP30-040) */
++#define AR5212_AR2313_REV8 0x0058 /* AR2313 WMAC (AP43-030) */
++#define AR531X_RADIO_MASK_OFF 0xc8
++#define AR531X_RADIO0_MASK 0x0003
++#define AR531X_RADIO1_MASK 0x000c
++#define AR531X_RADIO1_S 2
++
++/* Major revision numbers, bits 7..4 of Revision ID register */
++#define AR531X_REV_MAJ_AR5312 0x4
++#define AR531X_REV_MAJ_AR2313 0x5
++
++/*
++ * AR531X_NUM_ENET_MAC defines the number of ethernet MACs that
++ * should be considered available. The AR5312 supports 2 enet MACS,
++ * even though many reference boards only actually use 1 of them
++ * (i.e. Only MAC 0 is actually connected to an enet PHY or PHY switch.
++ * The AR2312 supports 1 enet MAC.
++ */
++#define AR531X_NUM_ENET_MAC 1
++
++/*
++ * Interface Enable
++ */
++#define AR531XPLUS_IF_CTL (AR531XPLUS_DSLBASE + 0x0018)
++
++#define IF_MASK 0x00000007
++#define IF_DISABLED 0
++#define IF_PCI 1
++#define IF_TS_LOCAL 2
++#define IF_ALL 3 /* only for emulation with separate pins */
++#define IF_LOCAL_HOST 0x00000008
++#define IF_PCI_HOST 0x00000010
++#define IF_PCI_INTR 0x00000020
++#define IF_PCI_CLK_MASK 0x00030000
++#define IF_PCI_CLK_INPUT 0
++#define IF_PCI_CLK_OUTPUT_LOW 1
++#define IF_PCI_CLK_OUTPUT_CLK 2
++#define IF_PCI_CLK_OUTPUT_HIGH 3
++#define IF_PCI_CLK_SHIFT 16
++
++
++/* Major revision numbers, bits 7..4 of Revision ID register */
++#define REV_MAJ_AR5311 0x01
++#define REV_MAJ_AR5312 0x04
++#define REV_MAJ_AR5315 0x0B
++
++/*
++ * APB Interrupt control
++ */
++
++#define AR531XPLUS_ISR (AR531XPLUS_DSLBASE + 0x0020)
++#define AR531XPLUS_IMR (AR531XPLUS_DSLBASE + 0x0024)
++#define AR531XPLUS_GISR (AR531XPLUS_DSLBASE + 0x0028)
++
++#define ISR_UART0 0x0001 /* high speed UART */
++#define ISR_I2C_RSVD 0x0002 /* I2C bus */
++#define ISR_SPI 0x0004 /* SPI bus */
++#define ISR_AHB 0x0008 /* AHB error */
++#define ISR_APB 0x0010 /* APB error */
++#define ISR_TIMER 0x0020 /* timer */
++#define ISR_GPIO 0x0040 /* GPIO */
++#define ISR_WD 0x0080 /* watchdog */
++#define ISR_IR_RSVD 0x0100 /* IR */
++
++#define IMR_UART0 ISR_UART0
++#define IMR_I2C_RSVD ISR_I2C_RSVD
++#define IMR_SPI ISR_SPI
++#define IMR_AHB ISR_AHB
++#define IMR_APB ISR_APB
++#define IMR_TIMER ISR_TIMER
++#define IMR_GPIO ISR_GPIO
++#define IMR_WD ISR_WD
++#define IMR_IR_RSVD ISR_IR_RSVD
++
++#define GISR_MISC 0x0001
++#define GISR_WLAN0 0x0002
++#define GISR_MPEGTS_RSVD 0x0004
++#define GISR_LOCALPCI 0x0008
++#define GISR_WMACPOLL 0x0010
++#define GISR_TIMER 0x0020
++#define GISR_ETHERNET 0x0040
++
++/*
++ * Interrupt routing from IO to the processor IP bits
++ * Define our inter mask and level
++ */
++#define AR531XPLUS_INTR_MISCIO SR_IBIT3
++#define AR531XPLUS_INTR_WLAN0 SR_IBIT4
++#define AR531XPLUS_INTR_ENET0 SR_IBIT5
++#define AR531XPLUS_INTR_LOCALPCI SR_IBIT6
++#define AR531XPLUS_INTR_WMACPOLL SR_IBIT7
++#define AR531XPLUS_INTR_COMPARE SR_IBIT8
++
++/*
++ * Timers
++ */
++#define AR531XPLUS_TIMER (AR531XPLUS_DSLBASE + 0x0030)
++#define AR531XPLUS_RELOAD (AR531XPLUS_DSLBASE + 0x0034)
++#define AR531XPLUS_WD (AR531XPLUS_DSLBASE + 0x0038)
++#define AR531XPLUS_WDC (AR531XPLUS_DSLBASE + 0x003c)
++
++#define WDC_RESET 0x00000002 /* reset on watchdog */
++#define WDC_NMI 0x00000001 /* NMI on watchdog */
++#define WDC_IGNORE_EXPIRATION 0x00000000
++
++/*
++ * Interface Debug
++ */
++#define AR531X_FLASHDBG (AR531X_RESETTMR + 0x0040)
++#define AR531X_MIIDBG (AR531X_RESETTMR + 0x0044)
++
++
++/*
++ * CPU Performance Counters
++ */
++#define AR531XPLUS_PERFCNT0 (AR531XPLUS_DSLBASE + 0x0048)
++#define AR531XPLUS_PERFCNT1 (AR531XPLUS_DSLBASE + 0x004c)
++
++#define PERF_DATAHIT 0x0001 /* Count Data Cache Hits */
++#define PERF_DATAMISS 0x0002 /* Count Data Cache Misses */
++#define PERF_INSTHIT 0x0004 /* Count Instruction Cache Hits */
++#define PERF_INSTMISS 0x0008 /* Count Instruction Cache Misses */
++#define PERF_ACTIVE 0x0010 /* Count Active Processor Cycles */
++#define PERF_WBHIT 0x0020 /* Count CPU Write Buffer Hits */
++#define PERF_WBMISS 0x0040 /* Count CPU Write Buffer Misses */
++
++#define PERF_EB_ARDY 0x0001 /* Count EB_ARdy signal */
++#define PERF_EB_AVALID 0x0002 /* Count EB_AValid signal */
++#define PERF_EB_WDRDY 0x0004 /* Count EB_WDRdy signal */
++#define PERF_EB_RDVAL 0x0008 /* Count EB_RdVal signal */
++#define PERF_VRADDR 0x0010 /* Count valid read address cycles */
++#define PERF_VWADDR 0x0020 /* Count valid write address cycles */
++#define PERF_VWDATA 0x0040 /* Count valid write data cycles */
++
++/*
++ * AHB Error Reporting.
++ */
++#define AR531XPLUS_AHB_ERR0 (AR531XPLUS_DSLBASE + 0x0050) /* error */
++#define AR531XPLUS_AHB_ERR1 (AR531XPLUS_DSLBASE + 0x0054) /* haddr */
++#define AR531XPLUS_AHB_ERR2 (AR531XPLUS_DSLBASE + 0x0058) /* hwdata */
++#define AR531XPLUS_AHB_ERR3 (AR531XPLUS_DSLBASE + 0x005c) /* hrdata */
++#define AR531XPLUS_AHB_ERR4 (AR531XPLUS_DSLBASE + 0x0060) /* status */
++
++#define AHB_ERROR_DET 1 /* AHB Error has been detected, */
++ /* write 1 to clear all bits in ERR0 */
++#define AHB_ERROR_OVR 2 /* AHB Error overflow has been detected */
++#define AHB_ERROR_WDT 4 /* AHB Error due to wdt instead of hresp */
++
++#define PROCERR_HMAST 0x0000000f
++#define PROCERR_HMAST_DFLT 0
++#define PROCERR_HMAST_WMAC 1
++#define PROCERR_HMAST_ENET 2
++#define PROCERR_HMAST_PCIENDPT 3
++#define PROCERR_HMAST_LOCAL 4
++#define PROCERR_HMAST_CPU 5
++#define PROCERR_HMAST_PCITGT 6
++
++#define PROCERR_HMAST_S 0
++#define PROCERR_HWRITE 0x00000010
++#define PROCERR_HSIZE 0x00000060
++#define PROCERR_HSIZE_S 5
++#define PROCERR_HTRANS 0x00000180
++#define PROCERR_HTRANS_S 7
++#define PROCERR_HBURST 0x00000e00
++#define PROCERR_HBURST_S 9
++
++
++
++/*
++ * Clock Control
++ */
++#define AR531XPLUS_PLLC_CTL (AR531XPLUS_DSLBASE + 0x0064)
++#define AR531XPLUS_PLLV_CTL (AR531XPLUS_DSLBASE + 0x0068)
++#define AR531XPLUS_CPUCLK (AR531XPLUS_DSLBASE + 0x006c)
++#define AR531XPLUS_AMBACLK (AR531XPLUS_DSLBASE + 0x0070)
++#define AR531XPLUS_SYNCCLK (AR531XPLUS_DSLBASE + 0x0074)
++#define AR531XPLUS_DSL_SLEEP_CTL (AR531XPLUS_DSLBASE + 0x0080)
++#define AR531XPLUS_DSL_SLEEP_DUR (AR531XPLUS_DSLBASE + 0x0084)
++
++/* PLLc Control fields */
++#define PLLC_REF_DIV_M 0x00000003
++#define PLLC_REF_DIV_S 0
++#define PLLC_FDBACK_DIV_M 0x0000007C
++#define PLLC_FDBACK_DIV_S 2
++#define PLLC_ADD_FDBACK_DIV_M 0x00000080
++#define PLLC_ADD_FDBACK_DIV_S 7
++#define PLLC_CLKC_DIV_M 0x0001c000
++#define PLLC_CLKC_DIV_S 14
++#define PLLC_CLKM_DIV_M 0x00700000
++#define PLLC_CLKM_DIV_S 20
++
++/* CPU CLK Control fields */
++#define CPUCLK_CLK_SEL_M 0x00000003
++#define CPUCLK_CLK_SEL_S 0
++#define CPUCLK_CLK_DIV_M 0x0000000c
++#define CPUCLK_CLK_DIV_S 2
++
++/* AMBA CLK Control fields */
++#define AMBACLK_CLK_SEL_M 0x00000003
++#define AMBACLK_CLK_SEL_S 0
++#define AMBACLK_CLK_DIV_M 0x0000000c
++#define AMBACLK_CLK_DIV_S 2
++
++#if defined(COBRA_EMUL)
++#define AR531XPLUS_AMBA_CLOCK_RATE 20000000
++#define AR531XPLUS_CPU_CLOCK_RATE 40000000
++#else
++#if defined(DEFAULT_PLL)
++#define AR531XPLUS_AMBA_CLOCK_RATE 40000000
++#define AR531XPLUS_CPU_CLOCK_RATE 40000000
++#else
++#define AR531XPLUS_AMBA_CLOCK_RATE 92000000
++#define AR531XPLUS_CPU_CLOCK_RATE 184000000
++#endif /* ! DEFAULT_PLL */
++#endif /* ! COBRA_EMUL */
++
++#define AR531XPLUS_UART_CLOCK_RATE AR531XPLUS_AMBA_CLOCK_RATE
++#define AR531XPLUS_SDRAM_CLOCK_RATE AR531XPLUS_AMBA_CLOCK_RATE
++
++/*
++ * The UART computes baud rate as:
++ * baud = clock / (16 * divisor)
++ * where divisor is specified as a High Byte (DLM) and a Low Byte (DLL).
++ */
++#define DESIRED_BAUD_RATE 38400
++
++/*
++ * The WATCHDOG value is computed as
++ * 10 seconds * AR531X_WATCHDOG_CLOCK_RATE
++ */
++#define DESIRED_WATCHDOG_SECONDS 10
++#define AR531X_WATCHDOG_TIME \
++ (DESIRED_WATCHDOG_SECONDS * AR531X_WATCHDOG_CLOCK_RATE)
++
++
++#define CLOCKCTL_UART0 0x0010 /* enable UART0 external clock */
++
++
++ /*
++ * Applicable "PCICFG" bits for WLAN(s). Assoc status and LED mode.
++ */
++#define AR531X_PCICFG (AR531X_RESETTMR + 0x00b0)
++#define ASSOC_STATUS_M 0x00000003
++#define ASSOC_STATUS_NONE 0
++#define ASSOC_STATUS_PENDING 1
++#define ASSOC_STATUS_ASSOCIATED 2
++#define LED_MODE_M 0x0000001c
++#define LED_BLINK_THRESHOLD_M 0x000000e0
++#define LED_SLOW_BLINK_MODE 0x00000100
++
++/*
++ * GPIO
++ */
++
++#define AR531XPLUS_GPIO_DI (AR531XPLUS_DSLBASE + 0x0088)
++#define AR531XPLUS_GPIO_DO (AR531XPLUS_DSLBASE + 0x0090)
++#define AR531XPLUS_GPIO_CR (AR531XPLUS_DSLBASE + 0x0098)
++#define AR531XPLUS_GPIO_INT (AR531XPLUS_DSLBASE + 0x00a0)
++
++#define GPIO_CR_M(x) (1 << (x)) /* mask for i/o */
++#define GPIO_CR_O(x) (1 << (x)) /* output */
++#define GPIO_CR_I(x) (0 << (x)) /* input */
++
++#define GPIO_INT(x,Y) ((x) << (8 * (Y))) /* interrupt enable */
++#define GPIO_INT_M(Y) ((0x3F) << (8 * (Y))) /* mask for int */
++#define GPIO_INT_LVL(x,Y) ((x) << (8 * (Y) + 6)) /* interrupt level */
++#define GPIO_INT_LVL_M(Y) ((0x3) << (8 * (Y) + 6)) /* mask for int level */
++
++#define AR531XPLUS_RESET_GPIO 5
++#define AR531XPLUS_NUM_GPIO 22
++
++
++/*
++ * PCI Clock Control
++ */
++
++#define AR531XPLUS_PCICLK (AR531XPLUS_DSLBASE + 0x00a4)
++
++#define PCICLK_INPUT_M 0x3
++#define PCICLK_INPUT_S 0
++
++#define PCICLK_PLLC_CLKM 0
++#define PCICLK_PLLC_CLKM1 1
++#define PCICLK_PLLC_CLKC 2
++#define PCICLK_REF_CLK 3
++
++#define PCICLK_DIV_M 0xc
++#define PCICLK_DIV_S 2
++
++#define PCICLK_IN_FREQ 0
++#define PCICLK_IN_FREQ_DIV_6 1
++#define PCICLK_IN_FREQ_DIV_8 2
++#define PCICLK_IN_FREQ_DIV_10 3
++
++/*
++ * Observation Control Register
++ */
++#define AR531XPLUS_OCR (AR531XPLUS_DSLBASE + 0x00b0)
++#define OCR_GPIO0_IRIN 0x0040
++#define OCR_GPIO1_IROUT 0x0080
++#define OCR_GPIO3_RXCLR 0x0200
++
++/*
++ * General Clock Control
++ */
++
++#define AR531XPLUS_MISCCLK (AR531XPLUS_DSLBASE + 0x00b4)
++#define MISCCLK_PLLBYPASS_EN 0x00000001
++#define MISCCLK_PROCREFCLK 0x00000002
++
++/*
++ * SDRAM Controller
++ * - No read or write buffers are included.
++ */
++#define AR531XPLUS_MEM_CFG (AR531XPLUS_SDRAMCTL + 0x00)
++#define AR531XPLUS_MEM_CTRL (AR531XPLUS_SDRAMCTL + 0x0c)
++#define AR531XPLUS_MEM_REF (AR531XPLUS_SDRAMCTL + 0x10)
++
++#define SDRAM_DATA_WIDTH_M 0x00006000
++#define SDRAM_DATA_WIDTH_S 13
++
++#define SDRAM_COL_WIDTH_M 0x00001E00
++#define SDRAM_COL_WIDTH_S 9
++
++#define SDRAM_ROW_WIDTH_M 0x000001E0
++#define SDRAM_ROW_WIDTH_S 5
++
++#define SDRAM_BANKADDR_BITS_M 0x00000018
++#define SDRAM_BANKADDR_BITS_S 3
++
++
++/*
++ * SDRAM Memory Refresh (MEM_REF) value is computed as:
++ * MEMCTL_SREFR = (Tr * hclk_freq) / R
++ * where Tr is max. time of refresh of any single row
++ * R is number of rows in the DRAM
++ * For most 133MHz SDRAM parts, Tr=64ms, R=4096 or 8192
++ */
++#if defined(COBRA_EMUL)
++#define AR531XPLUS_SDRAM_MEMORY_REFRESH_VALUE 0x96
++#else
++#if defined(DEFAULT_PLL)
++#define AR531XPLUS_SDRAM_MEMORY_REFRESH_VALUE 0x200
++#else
++#define AR531XPLUS_SDRAM_MEMORY_REFRESH_VALUE 0x61a
++#endif /* ! DEFAULT_PLL */
++#endif
++
++#if defined(AR531XPLUS)
++
++#define AR531XPLUS_SDRAM_DDR_SDRAM 0 /* Not DDR SDRAM */
++#define AR531XPLUS_SDRAM_DATA_WIDTH 16 /* bits */
++#define AR531XPLUS_SDRAM_COL_WIDTH 8
++#define AR531XPLUS_SDRAM_ROW_WIDTH 12
++
++#else
++
++#define AR531XPLUS_SDRAM_DDR_SDRAM 0 /* Not DDR SDRAM */
++#define AR531XPLUS_SDRAM_DATA_WIDTH 16
++#define AR531XPLUS_SDRAM_COL_WIDTH 8
++#define AR531XPLUS_SDRAM_ROW_WIDTH 12
++
++#endif /* ! AR531XPLUS */
++
++/*
++ * SPI Flash Interface Registers
++ */
++
++#define AR531XPLUS_SPI_CTL (AR531XPLUS_SPI + 0x00)
++#define AR531XPLUS_SPI_OPCODE (AR531XPLUS_SPI + 0x04)
++#define AR531XPLUS_SPI_DATA (AR531XPLUS_SPI + 0x08)
++
++#define SPI_CTL_START 0x00000100
++#define SPI_CTL_BUSY 0x00010000
++#define SPI_CTL_TXCNT_MASK 0x0000000f
++#define SPI_CTL_RXCNT_MASK 0x000000f0
++#define SPI_CTL_TX_RX_CNT_MASK 0x000000ff
++#define SPI_CTL_SIZE_MASK 0x00060000
++
++#define SPI_CTL_CLK_SEL_MASK 0x03000000
++#define SPI_OPCODE_MASK 0x000000ff
++
++/*
++ * PCI-MAC Configuration registers
++ */
++#define PCI_MAC_RC (AR531XPLUS_PCI + 0x4000)
++#define PCI_MAC_SCR (AR531XPLUS_PCI + 0x4004)
++#define PCI_MAC_INTPEND (AR531XPLUS_PCI + 0x4008)
++#define PCI_MAC_SFR (AR531XPLUS_PCI + 0x400C)
++#define PCI_MAC_PCICFG (AR531XPLUS_PCI + 0x4010)
++#define PCI_MAC_SREV (AR531XPLUS_PCI + 0x4020)
++
++#define PCI_MAC_RC_MAC 0x00000001
++#define PCI_MAC_RC_BB 0x00000002
++
++#define PCI_MAC_SCR_SLMODE_M 0x00030000
++#define PCI_MAC_SCR_SLMODE_S 16
++#define PCI_MAC_SCR_SLM_FWAKE 0
++#define PCI_MAC_SCR_SLM_FSLEEP 1
++#define PCI_MAC_SCR_SLM_NORMAL 2
++
++#define PCI_MAC_SFR_SLEEP 0x00000001
++
++#define PCI_MAC_PCICFG_SPWR_DN 0x00010000
++
++
++
++
++/*
++ * PCI Bus Interface Registers
++ */
++#define AR531XPLUS_PCI_1MS_REG (AR531XPLUS_PCI + 0x0008)
++#define AR531XPLUS_PCI_1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */
++
++#define AR531XPLUS_PCI_MISC_CONFIG (AR531XPLUS_PCI + 0x000c)
++#define AR531XPLUS_PCIMISC_TXD_EN 0x00000001 /* Enable TXD for fragments */
++#define AR531XPLUS_PCIMISC_CFG_SEL 0x00000002 /* mem or config cycles */
++#define AR531XPLUS_PCIMISC_GIG_MASK 0x0000000C /* bits 31-30 for pci req */
++#define AR531XPLUS_PCIMISC_RST_MODE 0x00000030
++#define AR531XPLUS_PCIRST_INPUT 0x00000000 /* 4:5=0 rst is input */
++#define AR531XPLUS_PCIRST_LOW 0x00000010 /* 4:5=1 rst to GND */
++#define AR531XPLUS_PCIRST_HIGH 0x00000020 /* 4:5=2 rst to VDD */
++#define AR531XPLUS_PCIGRANT_EN 0x00000000 /* 6:7=0 early grant en */
++#define AR531XPLUS_PCIGRANT_FRAME 0x00000040 /* 6:7=1 grant waits 4 frame */
++#define AR531XPLUS_PCIGRANT_IDLE 0x00000080 /* 6:7=2 grant waits 4 idle */
++#define AR531XPLUS_PCIGRANT_GAP 0x00000000 /* 6:7=2 grant waits 4 idle */
++#define AR531XPLUS_PCICACHE_DIS 0x00001000 /* PCI external access cache disable */
++
++#define AR531XPLUS_PCI_OUT_TSTAMP (AR531XPLUS_PCI + 0x0010)
++
++#define AR531XPLUS_PCI_UNCACHE_CFG (AR531XPLUS_PCI + 0x0014)
++
++#define AR531XPLUS_PCI_IN_EN (AR531XPLUS_PCI + 0x0100)
++#define AR531XPLUS_PCI_IN_EN0 0x01 /* Enable chain 0 */
++#define AR531XPLUS_PCI_IN_EN1 0x02 /* Enable chain 1 */
++#define AR531XPLUS_PCI_IN_EN2 0x04 /* Enable chain 2 */
++#define AR531XPLUS_PCI_IN_EN3 0x08 /* Enable chain 3 */
++
++#define AR531XPLUS_PCI_IN_DIS (AR531XPLUS_PCI + 0x0104)
++#define AR531XPLUS_PCI_IN_DIS0 0x01 /* Disable chain 0 */
++#define AR531XPLUS_PCI_IN_DIS1 0x02 /* Disable chain 1 */
++#define AR531XPLUS_PCI_IN_DIS2 0x04 /* Disable chain 2 */
++#define AR531XPLUS_PCI_IN_DIS3 0x08 /* Disable chain 3 */
++
++#define AR531XPLUS_PCI_IN_PTR (AR531XPLUS_PCI + 0x0200)
++
++#define AR531XPLUS_PCI_OUT_EN (AR531XPLUS_PCI + 0x0400)
++#define AR531XPLUS_PCI_OUT_EN0 0x01 /* Enable chain 0 */
++
++#define AR531XPLUS_PCI_OUT_DIS (AR531XPLUS_PCI + 0x0404)
++#define AR531XPLUS_PCI_OUT_DIS0 0x01 /* Disable chain 0 */
++
++#define AR531XPLUS_PCI_OUT_PTR (AR531XPLUS_PCI + 0x0408)
++
++#define AR531XPLUS_PCI_INT_STATUS (AR531XPLUS_PCI + 0x0500) /* write one to clr */
++#define AR531XPLUS_PCI_TXINT 0x00000001 /* Desc In Completed */
++#define AR531XPLUS_PCI_TXOK 0x00000002 /* Desc In OK */
++#define AR531XPLUS_PCI_TXERR 0x00000004 /* Desc In ERR */
++#define AR531XPLUS_PCI_TXEOL 0x00000008 /* Desc In End-of-List */
++#define AR531XPLUS_PCI_RXINT 0x00000010 /* Desc Out Completed */
++#define AR531XPLUS_PCI_RXOK 0x00000020 /* Desc Out OK */
++#define AR531XPLUS_PCI_RXERR 0x00000040 /* Desc Out ERR */
++#define AR531XPLUS_PCI_RXEOL 0x00000080 /* Desc Out EOL */
++#define AR531XPLUS_PCI_TXOOD 0x00000200 /* Desc In Out-of-Desc */
++#define AR531XPLUS_PCI_MASK 0x0000FFFF /* Desc Mask */
++#define AR531XPLUS_PCI_EXT_INT 0x02000000
++#define AR531XPLUS_PCI_ABORT_INT 0x04000000
++
++#define AR531XPLUS_PCI_INT_MASK (AR531XPLUS_PCI + 0x0504) /* same as INT_STATUS */
++
++#define AR531XPLUS_PCI_INTEN_REG (AR531XPLUS_PCI + 0x0508)
++#define AR531XPLUS_PCI_INT_DISABLE 0x00 /* disable pci interrupts */
++#define AR531XPLUS_PCI_INT_ENABLE 0x01 /* enable pci interrupts */
++
++#define AR531XPLUS_PCI_HOST_IN_EN (AR531XPLUS_PCI + 0x0800)
++#define AR531XPLUS_PCI_HOST_IN_DIS (AR531XPLUS_PCI + 0x0804)
++#define AR531XPLUS_PCI_HOST_IN_PTR (AR531XPLUS_PCI + 0x0810)
++#define AR531XPLUS_PCI_HOST_OUT_EN (AR531XPLUS_PCI + 0x0900)
++#define AR531XPLUS_PCI_HOST_OUT_DIS (AR531XPLUS_PCI + 0x0904)
++#define AR531XPLUS_PCI_HOST_OUT_PTR (AR531XPLUS_PCI + 0x0908)
++
++
++/*
++ * Local Bus Interface Registers
++ */
++#define AR531XPLUS_LB_CONFIG (AR531XPLUS_LOCAL + 0x0000)
++#define AR531XPLUS_LBCONF_OE 0x00000001 /* =1 OE is low-true */
++#define AR531XPLUS_LBCONF_CS0 0x00000002 /* =1 first CS is low-true */
++#define AR531XPLUS_LBCONF_CS1 0x00000004 /* =1 2nd CS is low-true */
++#define AR531XPLUS_LBCONF_RDY 0x00000008 /* =1 RDY is low-true */
++#define AR531XPLUS_LBCONF_WE 0x00000010 /* =1 Write En is low-true */
++#define AR531XPLUS_LBCONF_WAIT 0x00000020 /* =1 WAIT is low-true */
++#define AR531XPLUS_LBCONF_ADS 0x00000040 /* =1 Adr Strobe is low-true */
++#define AR531XPLUS_LBCONF_MOT 0x00000080 /* =0 Intel, =1 Motorola */
++#define AR531XPLUS_LBCONF_8CS 0x00000100 /* =1 8 bits CS, 0= 16bits */
++#define AR531XPLUS_LBCONF_8DS 0x00000200 /* =1 8 bits Data S, 0=16bits */
++#define AR531XPLUS_LBCONF_ADS_EN 0x00000400 /* =1 Enable ADS */
++#define AR531XPLUS_LBCONF_ADR_OE 0x00000800 /* =1 Adr cap on OE, WE or DS */
++#define AR531XPLUS_LBCONF_ADDT_MUX 0x00001000 /* =1 Adr and Data share bus */
++#define AR531XPLUS_LBCONF_DATA_OE 0x00002000 /* =1 Data cap on OE, WE, DS */
++#define AR531XPLUS_LBCONF_16DATA 0x00004000 /* =1 Data is 16 bits wide */
++#define AR531XPLUS_LBCONF_SWAPDT 0x00008000 /* =1 Byte swap data */
++#define AR531XPLUS_LBCONF_SYNC 0x00010000 /* =1 Bus synchronous to clk */
++#define AR531XPLUS_LBCONF_INT 0x00020000 /* =1 Intr is low true */
++#define AR531XPLUS_LBCONF_INT_CTR0 0x00000000 /* GND high-Z, Vdd is high-Z */
++#define AR531XPLUS_LBCONF_INT_CTR1 0x00040000 /* GND drive, Vdd is high-Z */
++#define AR531XPLUS_LBCONF_INT_CTR2 0x00080000 /* GND high-Z, Vdd drive */
++#define AR531XPLUS_LBCONF_INT_CTR3 0x000C0000 /* GND drive, Vdd drive */
++#define AR531XPLUS_LBCONF_RDY_WAIT 0x00100000 /* =1 RDY is negative of WAIT */
++#define AR531XPLUS_LBCONF_INT_PULSE 0x00200000 /* =1 Interrupt is a pulse */
++#define AR531XPLUS_LBCONF_ENABLE 0x00400000 /* =1 Falcon respond to LB */
++
++#define AR531XPLUS_LB_CLKSEL (AR531XPLUS_LOCAL + 0x0004)
++#define AR531XPLUS_LBCLK_EXT 0x0001 /* use external clk for lb */
++
++#define AR531XPLUS_LB_1MS (AR531XPLUS_LOCAL + 0x0008)
++#define AR531XPLUS_LB1MS_MASK 0x3FFFF /* # of AHB clk cycles in 1ms */
++
++#define AR531XPLUS_LB_MISCCFG (AR531XPLUS_LOCAL + 0x000C)
++#define AR531XPLUS_LBM_TXD_EN 0x00000001 /* Enable TXD for fragments */
++#define AR531XPLUS_LBM_RX_INTEN 0x00000002 /* Enable LB ints on RX ready */
++#define AR531XPLUS_LBM_MBOXWR_INTEN 0x00000004 /* Enable LB ints on mbox wr */
++#define AR531XPLUS_LBM_MBOXRD_INTEN 0x00000008 /* Enable LB ints on mbox rd */
++#define AR531XPLUS_LMB_DESCSWAP_EN 0x00000010 /* Byte swap desc enable */
++#define AR531XPLUS_LBM_TIMEOUT_MASK 0x00FFFF80
++#define AR531XPLUS_LBM_TIMEOUT_SHFT 7
++#define AR531XPLUS_LBM_PORTMUX 0x07000000
++
++
++#define AR531XPLUS_LB_RXTSOFF (AR531XPLUS_LOCAL + 0x0010)
++
++#define AR531XPLUS_LB_TX_CHAIN_EN (AR531XPLUS_LOCAL + 0x0100)
++#define AR531XPLUS_LB_TXEN_0 0x01
++#define AR531XPLUS_LB_TXEN_1 0x02
++#define AR531XPLUS_LB_TXEN_2 0x04
++#define AR531XPLUS_LB_TXEN_3 0x08
++
++#define AR531XPLUS_LB_TX_CHAIN_DIS (AR531XPLUS_LOCAL + 0x0104)
++#define AR531XPLUS_LB_TX_DESC_PTR (AR531XPLUS_LOCAL + 0x0200)
++
++#define AR531XPLUS_LB_RX_CHAIN_EN (AR531XPLUS_LOCAL + 0x0400)
++#define AR531XPLUS_LB_RXEN 0x01
++
++#define AR531XPLUS_LB_RX_CHAIN_DIS (AR531XPLUS_LOCAL + 0x0404)
++#define AR531XPLUS_LB_RX_DESC_PTR (AR531XPLUS_LOCAL + 0x0408)
++
++#define AR531XPLUS_LB_INT_STATUS (AR531XPLUS_LOCAL + 0x0500)
++#define AR531XPLUS_INT_TX_DESC 0x0001
++#define AR531XPLUS_INT_TX_OK 0x0002
++#define AR531XPLUS_INT_TX_ERR 0x0004
++#define AR531XPLUS_INT_TX_EOF 0x0008
++#define AR531XPLUS_INT_RX_DESC 0x0010
++#define AR531XPLUS_INT_RX_OK 0x0020
++#define AR531XPLUS_INT_RX_ERR 0x0040
++#define AR531XPLUS_INT_RX_EOF 0x0080
++#define AR531XPLUS_INT_TX_TRUNC 0x0100
++#define AR531XPLUS_INT_TX_STARVE 0x0200
++#define AR531XPLUS_INT_LB_TIMEOUT 0x0400
++#define AR531XPLUS_INT_LB_ERR 0x0800
++#define AR531XPLUS_INT_MBOX_WR 0x1000
++#define AR531XPLUS_INT_MBOX_RD 0x2000
++
++/* Bit definitions for INT MASK are the same as INT_STATUS */
++#define AR531XPLUS_LB_INT_MASK (AR531XPLUS_LOCAL + 0x0504)
++
++#define AR531XPLUS_LB_INT_EN (AR531XPLUS_LOCAL + 0x0508)
++#define AR531XPLUS_LB_MBOX (AR531XPLUS_LOCAL + 0x0600)
++
++
++
++/*
++ * IR Interface Registers
++ */
++#define AR531XPLUS_IR_PKTDATA (AR531XPLUS_IR + 0x0000)
++
++#define AR531XPLUS_IR_PKTLEN (AR531XPLUS_IR + 0x07fc) /* 0 - 63 */
++
++#define AR531XPLUS_IR_CONTROL (AR531XPLUS_IR + 0x0800)
++#define AR531XPLUS_IRCTL_TX 0x00000000 /* use as tranmitter */
++#define AR531XPLUS_IRCTL_RX 0x00000001 /* use as receiver */
++#define AR531XPLUS_IRCTL_SAMPLECLK_MASK 0x00003ffe /* Sample clk divisor mask */
++#define AR531XPLUS_IRCTL_SAMPLECLK_SHFT 1
++#define AR531XPLUS_IRCTL_OUTPUTCLK_MASK 0x03ffc000 /* Output clk divisor mask */
++#define AR531XPLUS_IRCTL_OUTPUTCLK_SHFT 14
++
++#define AR531XPLUS_IR_STATUS (AR531XPLUS_IR + 0x0804)
++#define AR531XPLUS_IRSTS_RX 0x00000001 /* receive in progress */
++#define AR531XPLUS_IRSTS_TX 0x00000002 /* transmit in progress */
++
++#define AR531XPLUS_IR_CONFIG (AR531XPLUS_IR + 0x0808)
++#define AR531XPLUS_IRCFG_INVIN 0x00000001 /* invert input polarity */
++#define AR531XPLUS_IRCFG_INVOUT 0x00000002 /* invert output polarity */
++#define AR531XPLUS_IRCFG_SEQ_START_WIN_SEL 0x00000004 /* 1 => 28, 0 => 7 */
++#define AR531XPLUS_IRCFG_SEQ_START_THRESH 0x000000f0 /* */
++#define AR531XPLUS_IRCFG_SEQ_END_UNIT_SEL 0x00000100 /* */
++#define AR531XPLUS_IRCFG_SEQ_END_UNIT_THRESH 0x00007e00 /* */
++#define AR531XPLUS_IRCFG_SEQ_END_WIN_SEL 0x00008000 /* */
++#define AR531XPLUS_IRCFG_SEQ_END_WIN_THRESH 0x001f0000 /* */
++#define AR531XPLUS_IRCFG_NUM_BACKOFF_WORDS 0x01e00000 /* */
++
++/*
++ * PCI memory constants: Memory area 1 and 2 are the same size -
++ * (twice the PCI_TLB_PAGE_SIZE). The definition of
++ * CPU_TO_PCI_MEM_SIZE is coupled with the TLB setup routine
++ * sysLib.c/sysTlbInit(), in that it assumes that 2 pages of size
++ * PCI_TLB_PAGE_SIZE are set up in the TLB for each PCI memory space.
++ */
++
++#define CPU_TO_PCI_MEM_BASE1 0xE0000000
++#define CPU_TO_PCI_MEM_SIZE1 (2*PCI_TLB_PAGE_SIZE)
++
++
++/* TLB attributes for PCI transactions */
++
++#define PCI_MMU_PAGEMASK 0x00003FFF
++#define MMU_PAGE_UNCACHED 0x00000010
++#define MMU_PAGE_DIRTY 0x00000004
++#define MMU_PAGE_VALID 0x00000002
++#define MMU_PAGE_GLOBAL 0x00000001
++#define PCI_MMU_PAGEATTRIB (MMU_PAGE_UNCACHED|MMU_PAGE_DIRTY|\
++ MMU_PAGE_VALID|MMU_PAGE_GLOBAL)
++#define PCI_MEMORY_SPACE1_VIRT 0xE0000000 /* Used for non-prefet mem */
++#define PCI_MEMORY_SPACE1_PHYS 0x80000000
++#define PCI_TLB_PAGE_SIZE 0x01000000
++#define TLB_HI_MASK 0xFFFFE000
++#define TLB_LO_MASK 0x3FFFFFFF
++#define PAGEMASK_SHIFT 11
++#define TLB_LO_SHIFT 6
++
++#define PCI_MAX_LATENCY 0xFFF /* Max PCI latency */
++
++#define HOST_PCI_DEV_ID 3
++#define HOST_PCI_MBAR0 0x10000000
++#define HOST_PCI_MBAR1 0x20000000
++#define HOST_PCI_MBAR2 0x30000000
++
++#define HOST_PCI_SDRAM_BASEADDR HOST_PCI_MBAR1
++#define PCI_DEVICE_MEM_SPACE 0x800000
++
++
++typedef unsigned int AR531X_REG;
++
++#define sysRegRead(phys) \
++ (*(volatile AR531X_REG *)PHYS_TO_K1(phys))
++
++#define sysRegWrite(phys, val) \
++ ((*(volatile AR531X_REG *)PHYS_TO_K1(phys)) = (val))
++
++
++
++/*
++ * This is board-specific data that is stored in a "fixed" location in flash.
++ * It is shared across operating systems, so it should not be changed lightly.
++ * The main reason we need it is in order to extract the ethernet MAC
++ * address(es).
++ */
++struct ar531x_boarddata {
++ u32 magic; /* board data is valid */
++#define AR531X_BD_MAGIC 0x35333131 /* "5311", for all 531x platforms */
++ u16 cksum; /* checksum (starting with BD_REV 2) */
++ u16 rev; /* revision of this struct */
++#define BD_REV 4
++ char boardName[64]; /* Name of board */
++ u16 major; /* Board major number */
++ u16 minor; /* Board minor number */
++ u32 config; /* Board configuration */
++#define BD_ENET0 0x00000001 /* ENET0 is stuffed */
++#define BD_ENET1 0x00000002 /* ENET1 is stuffed */
++#define BD_UART1 0x00000004 /* UART1 is stuffed */
++#define BD_UART0 0x00000008 /* UART0 is stuffed (dma) */
++#define BD_RSTFACTORY 0x00000010 /* Reset factory defaults stuffed */
++#define BD_SYSLED 0x00000020 /* System LED stuffed */
++#define BD_EXTUARTCLK 0x00000040 /* External UART clock */
++#define BD_CPUFREQ 0x00000080 /* cpu freq is valid in nvram */
++#define BD_SYSFREQ 0x00000100 /* sys freq is set in nvram */
++#define BD_WLAN0 0x00000200 /* Enable WLAN0 */
++#define BD_MEMCAP 0x00000400 /* CAP SDRAM @ memCap for testing */
++#define BD_DISWATCHDOG 0x00000800 /* disable system watchdog */
++#define BD_WLAN1 0x00001000 /* Enable WLAN1 (ar5212) */
++#define BD_ISCASPER 0x00002000 /* FLAG for AR2312 */
++#define BD_WLAN0_2G_EN 0x00004000 /* FLAG for radio0_2G */
++#define BD_WLAN0_5G_EN 0x00008000 /* FLAG for radio0_2G */
++#define BD_WLAN1_2G_EN 0x00020000 /* FLAG for radio0_2G */
++#define BD_WLAN1_5G_EN 0x00040000 /* FLAG for radio0_2G */
++ u16 resetConfigGpio; /* Reset factory GPIO pin */
++ u16 sysLedGpio; /* System LED GPIO pin */
++
++ u32 cpuFreq; /* CPU core frequency in Hz */
++ u32 sysFreq; /* System frequency in Hz */
++ u32 cntFreq; /* Calculated C0_COUNT frequency */
++
++ u8 wlan0Mac[6];
++ u8 enet0Mac[6];
++ u8 enet1Mac[6];
++
++ u16 pciId; /* Pseudo PCIID for common code */
++ u16 memCap; /* cap bank1 in MB */
++
++ /* version 3 */
++ u8 wlan1Mac[6]; /* (ar5212) */
++};
++
++#endif
++
++#endif /* AR531X_H */
+diff -urN linux-mips-orig/drivers/net/ath/ar531xlnx.h linux-mips-new/drivers/net/ath/ar531xlnx.h
+--- linux-mips-orig/drivers/net/ath/ar531xlnx.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/ar531xlnx.h 2005-12-31 12:33:57.676538368 +0000
+@@ -0,0 +1,137 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * This file contains definitions needed in order to compile
++ * AR531X products for linux. Definitions that are largely
++ * AR531X-specific and independent of operating system belong
++ * in ar531x.h rather than this file.
++ */
++#ifndef __AR531XLNX_H
++#define __AR531XLNX_H
++#include "ar531x.h"
++
++#define MIPS_CPU_IRQ_BASE 0x00
++#define AR531X_HIGH_PRIO 0x10
++#define AR531X_MISC_IRQ_BASE 0x20
++#define AR531X_GPIO_IRQ_BASE 0x30
++
++/* Software's idea of interrupts handled by "CPU Interrupt Controller" */
++#if CONFIG_AR5315
++#define AR531X_IRQ_NONE MIPS_CPU_IRQ_BASE+0
++#define AR531X_IRQ_MISC_INTRS MIPS_CPU_IRQ_BASE+2 /* C0_CAUSE: 0x0400 */
++#define AR531X_IRQ_WLAN0_INTRS MIPS_CPU_IRQ_BASE+3 /* C0_CAUSE: 0x0800 */
++#define AR531X_IRQ_ENET0_INTRS MIPS_CPU_IRQ_BASE+4 /* C0_CAUSE: 0x1000 */
++#define AR531X_IRQ_LCBUS_PCI MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */
++#define AR531X_IRQ_WLAN0_POLL MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */
++#define AR531X_IRQ_CPU_CLOCK MIPS_CPU_IRQ_BASE+7 /* C0_CAUSE: 0x8000 */
++#else
++#define AR531X_IRQ_NONE MIPS_CPU_IRQ_BASE+0
++#define AR531X_IRQ_WLAN0_INTRS MIPS_CPU_IRQ_BASE+2 /* C0_CAUSE: 0x0400 */
++#define AR531X_IRQ_ENET0_INTRS MIPS_CPU_IRQ_BASE+3 /* C0_CAUSE: 0x0800 */
++#define AR531X_IRQ_ENET1_INTRS MIPS_CPU_IRQ_BASE+4 /* C0_CAUSE: 0x1000 */
++#define AR531X_IRQ_WLAN1_INTRS MIPS_CPU_IRQ_BASE+5 /* C0_CAUSE: 0x2000 */
++#define AR531X_IRQ_MISC_INTRS MIPS_CPU_IRQ_BASE+6 /* C0_CAUSE: 0x4000 */
++#define AR531X_IRQ_CPU_CLOCK MIPS_CPU_IRQ_BASE+7 /* C0_CAUSE: 0x8000 */
++#endif
++
++/* Miscellaneous interrupts, which share IP6 or IP2 */
++#define AR531X_MISC_IRQ_NONE AR531X_MISC_IRQ_BASE+0
++#define AR531X_MISC_IRQ_TIMER AR531X_MISC_IRQ_BASE+1
++#define AR531X_MISC_IRQ_AHB_PROC AR531X_MISC_IRQ_BASE+2
++#define AR531X_MISC_IRQ_AHB_DMA AR531X_MISC_IRQ_BASE+3
++#define AR531X_MISC_IRQ_GPIO AR531X_MISC_IRQ_BASE+4
++#define AR531X_MISC_IRQ_UART0 AR531X_MISC_IRQ_BASE+5
++#define AR531X_MISC_IRQ_UART0_DMA AR531X_MISC_IRQ_BASE+6
++#define AR531X_MISC_IRQ_WATCHDOG AR531X_MISC_IRQ_BASE+7
++#define AR531X_MISC_IRQ_LOCAL AR531X_MISC_IRQ_BASE+8
++#define AR531X_MISC_IRQ_COUNT 9
++
++/* GPIO Interrupts [0..7], share AR531X_MISC_IRQ_GPIO */
++#define AR531X_GPIO_IRQ_NONE AR531X_MISC_IRQ_BASE+0
++#define AR531X_GPIO_IRQ(n) AR531X_MISC_IRQ_BASE+(n)+1
++#define AR531X_GPIO_IRQ_COUNT 9
++
++#define PHYS_TO_K1(physaddr) KSEG1ADDR(physaddr)
++#define PHYS_TO_K0(physaddr) KSEG0ADDR(physaddr)
++#define UNMAPPED_TO_PHYS(vaddr) PHYSADDR(vaddr)
++#define IS_UNMAPPED_VADDR(vaddr) \
++ ((KSEGX(vaddr) == KSEG0) || (KSEGX(vaddr) == KSEG1))
++
++/* IOCTL commands for /proc/ar531x */
++#define AR531X_CTRL_DO_BREAKPOINT 1
++#define AR531X_CTRL_DO_MADWIFI 2
++
++/*
++ * Definitions for operating system portability.
++ * These are vxWorks-->Linux translations.
++ */
++#define LOCAL static
++#define BOOL int
++#define TRUE 1
++#define FALSE 0
++#define UINT8 u8
++#define UINT16 u16
++#define UINT32 u32
++#define PRINTF printk
++#if /* DEBUG */ 1
++#define DEBUG_PRINTF printk
++#define printf printk
++#define INLINE
++#else
++DEBUG_PRINTF while (0) printk
++#define INLINE inline
++#endif
++#define sysUDelay(usecs) udelay(usecs)
++#define sysMsDelay(msecs) mdelay(msecs)
++typedef volatile UINT8 *VIRT_ADDR;
++#define MALLOC(sz) kmalloc(sz, GFP_KERNEL)
++#define MALLOC_NOSLEEP(sz) kmalloc(sz, GFP_ATOMIC)
++#define FREE(ptr) kfree((void *)ptr)
++#define BSP_BUG() do { printk("kernel BSP BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0)
++#define BSP_BUG_ON(condition) do { if (unlikely((condition)!=0)) BSP_BUG(); } while(0)
++#define ASSERT(x) BSP_BUG_ON(!(x))
++
++extern struct ar531x_boarddata *ar531x_board_configuration;
++extern char *ar531x_radio_configuration;
++extern char *enet_mac_address_get(int MACUnit);
++
++extern void kgdbInit(void);
++extern int kgdbEnabled(void);
++extern void breakpoint(void);
++extern int kgdbInterrupt(void);
++extern unsigned int ar531x_cpu_frequency(void);
++extern unsigned int ar531x_sys_frequency(void);
++
++/* GPIO support */
++extern struct irqaction spurious_gpio;
++extern unsigned int gpioIntMask;
++extern void ar531x_gpio_intr_init(int irq_base);
++extern void ar531x_gpio_ctrl_output(int gpio);
++extern void ar531x_gpio_ctrl_input(int gpio);
++extern void ar531x_gpio_set(int gpio, int val);
++extern int ar531x_gpio_get(int gpio);
++extern void ar531x_gpio_intr_enable(unsigned int irq);
++extern void ar531x_gpio_intr_disable(unsigned int irq);
++
++/* Watchdog Timer support */
++extern int watchdog_start(unsigned int milliseconds);
++extern int watchdog_stop(void);
++extern int watchdog_is_enabled(void);
++extern unsigned int watchdog_min_timer_reached(void);
++extern void watchdog_notify_alive(void);
++
++#define A_DATA_CACHE_INVAL(start, length) \
++ dma_cache_inv((UINT32)(start),(length))
++
++#define sysWbFlush() mb()
++
++#define intDisable(x) cli()
++#define intEnable(x) sti()
++
++#endif /* __AR531XLNX_H */
+diff -urN linux-mips-orig/drivers/net/ath/ipPhy.c linux-mips-new/drivers/net/ath/ipPhy.c
+--- linux-mips-orig/drivers/net/ath/ipPhy.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/ipPhy.c 2005-12-31 12:33:57.677538216 +0000
+@@ -0,0 +1,833 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * Manage the ICPLUS ethernet PHY.
++ *
++ * All definitions in this file are operating system independent!
++ */
++
++#if defined(linux)
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/delay.h>
++
++#include "ar531xlnx.h"
++#endif
++
++#include "ae531xmac.h"
++#include "ae531xreg.h"
++#include "ipPhy.h"
++
++/* PHY selections and access functions */
++
++typedef enum {
++ PHY_SRCPORT_INFO,
++ PHY_PORTINFO_SIZE,
++} PHY_CAP_TYPE;
++
++typedef enum {
++ PHY_SRCPORT_NONE,
++ PHY_SRCPORT_VLANTAG,
++ PHY_SRCPORT_TRAILER,
++} PHY_SRCPORT_TYPE;
++
++#ifdef DEBUG
++#define DRV_DEBUG 1
++#endif
++#define DRV_DEBUG 1
++
++#if DRV_DEBUG
++#define DRV_DEBUG_PHYERROR 0x00000001
++#define DRV_DEBUG_PHYCHANGE 0x00000002
++#define DRV_DEBUG_PHYSETUP 0x00000004
++
++int ipPhyDebug = DRV_DEBUG_PHYERROR;
++
++#define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) \
++{ \
++ if (ipPhyDebug & (FLG)) { \
++ logMsg(X0, X1, X2, X3, X4, X5, X6); \
++ } \
++}
++
++#define DRV_MSG(x,a,b,c,d,e,f) \
++ logMsg(x,a,b,c,d,e,f)
++
++#define DRV_PRINT(FLG, X) \
++{ \
++ if (ipPhyDebug & (FLG)) { \
++ printf X; \
++ } \
++}
++
++#else /* !DRV_DEBUG */
++#define DRV_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6)
++#define DRV_MSG(x,a,b,c,d,e,f)
++#define DRV_PRINT(DBG_SW,X)
++#endif
++
++#define IP_LAN_PORT_VLAN 1
++#define IP_WAN_PORT_VLAN 2
++
++#define ENET_UNIT_DEFAULT 0
++
++/*
++ * Track per-PHY port information.
++ */
++typedef struct {
++ BOOL isEnetPort; /* normal enet port */
++ BOOL isPhyAlive; /* last known state of link */
++ int ethUnit; /* MAC associated with this phy port */
++ UINT32 phyBase;
++ UINT32 phyAddr; /* PHY registers associated with this phy port */
++ UINT32 VLANTableSetting; /* Value to be written to VLAN table */
++} ipPhyInfo_t;
++
++/*
++ * Per-PHY information, indexed by PHY unit number.
++ */
++ipPhyInfo_t ipPhyInfo[] = {
++ /*
++ * On AP30/AR5312, all PHYs are associated with MAC0.
++ * AP30/AR5312's MAC1 isn't used for anything.
++ * CONFIG_VENETDEV==1 (router) configuration:
++ * Ports 0,1,2, and 3 are "LAN ports"
++ * Port 4 is a WAN port
++ * Port 5 connects to MAC0 in the AR5312
++ * CONFIG_VENETDEV==0 (bridge) configuration:
++ * Ports 0,1,2,3,4 are "LAN ports"
++ * Port 5 connects to the MAC0 in the AR5312
++ */
++ {TRUE, /* phy port 0 -- LAN port 0 */
++ FALSE,
++ ENET_UNIT_DEFAULT,
++ (UINT32) (PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET),
++ IP_PHY0_ADDR,
++ IP_LAN_PORT_VLAN
++ },
++
++ {TRUE, /* phy port 1 -- LAN port 1 */
++ FALSE,
++ ENET_UNIT_DEFAULT,
++ (UINT32) (PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET),
++ IP_PHY1_ADDR,
++ IP_LAN_PORT_VLAN
++ },
++
++ {TRUE, /* phy port 2 -- LAN port 2 */
++ FALSE,
++ ENET_UNIT_DEFAULT,
++ (UINT32) (PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET),
++ IP_PHY2_ADDR,
++ IP_LAN_PORT_VLAN
++ },
++
++ {TRUE, /* phy port 3 -- LAN port 3 */
++ FALSE,
++ ENET_UNIT_DEFAULT,
++ (UINT32) (PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET),
++ IP_PHY3_ADDR,
++ IP_LAN_PORT_VLAN
++ },
++
++ {TRUE, /* phy port 4 -- WAN port or LAN port 4 */
++ FALSE,
++ ENET_UNIT_DEFAULT,
++ (UINT32) (PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET),
++ IP_PHY4_ADDR,
++ IP_LAN_PORT_VLAN /* Send to all ports */
++ },
++
++ {FALSE, /* phy port 5 -- CPU port (no RJ45 connector) */
++ TRUE,
++ ENET_UNIT_DEFAULT,
++ (UINT32) (PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET),
++ 0x00,
++ IP_LAN_PORT_VLAN /* Send to all ports */
++ },
++};
++
++#define IP_GLOBALREGBASE ((UINT32) (PHYS_TO_K1(AR531X_ENET0)))
++
++#define IP_PHY_MAX (sizeof(ipPhyInfo) / sizeof(ipPhyInfo[0]))
++
++/* Range of valid PHY IDs is [MIN..MAX] */
++#define IP_ID_MIN 0
++#define IP_ID_MAX (IP_PHY_MAX-1)
++
++/* Convenience macros to access myPhyInfo */
++#define IP_IS_ENET_PORT(phyUnit) (ipPhyInfo[phyUnit].isEnetPort)
++#define IP_IS_PHY_ALIVE(phyUnit) (ipPhyInfo[phyUnit].isPhyAlive)
++#define IP_ETHUNIT(phyUnit) (ipPhyInfo[phyUnit].ethUnit)
++#define IP_PHYBASE(phyUnit) (ipPhyInfo[phyUnit].phyBase)
++#define IP_PHYADDR(phyUnit) (ipPhyInfo[phyUnit].phyAddr)
++#define IP_VLAN_TABLE_SETTING(phyUnit) (ipPhyInfo[phyUnit].VLANTableSetting)
++
++
++#define IP_IS_ETHUNIT(phyUnit, ethUnit) \
++ (IP_IS_ENET_PORT(phyUnit) && \
++ IP_ETHUNIT(phyUnit) == (ethUnit))
++
++/* Forward references */
++BOOL ip_phyIsLinkAlive(int phyUnit);
++LOCAL void ip_VLANInit(int ethUnit);
++LOCAL void ip_verifyReady(int ethUnit);
++#if DEBUG
++void ip_phyShow(int phyUnit);
++void ip_phySet(int phyUnit, UINT32 regnum, UINT32 value);
++void ip_globalSet(UINT32 phyAddr, UINT32 regnum, UINT32 value);
++#endif
++
++/******************************************************************************
++*
++* ip_phyIsLinkAlive - test to see if the specified link is alive
++*
++* RETURNS:
++* TRUE --> link is alive
++* FALSE --> link is down
++*/
++BOOL
++ip_phyIsLinkAlive(int phyUnit)
++{
++ UINT16 phyHwStatus;
++ UINT32 phyBase;
++ UINT32 phyAddr;
++
++ phyBase = IP_PHYBASE(phyUnit);
++ phyAddr = IP_PHYADDR(phyUnit);
++
++ phyHwStatus = phyRegRead(phyBase, phyAddr, IP_PHY_STATUS);
++
++ if (phyHwStatus & IP_STATUS_LINK_PASS) {
++ return TRUE;
++ } else {
++ return FALSE;
++ }
++}
++
++/******************************************************************************
++*
++* ip_VLANInit - initialize "port-based VLANs" for the specified enet unit.
++*/
++LOCAL void
++ip_VLANInit(int ethUnit)
++{
++ int phyUnit;
++ UINT32 phyBase;
++ UINT32 phyReg;
++
++ phyBase = IP_GLOBALREGBASE;
++
++ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) {
++ if (IP_ETHUNIT(phyUnit) != ethUnit) {
++ continue;
++ }
++ phyRegWrite(phyBase, IP_GLOBAL_PHY29_ADDR,
++ IP_GLOBAL_PHY29_24_REG + ((phyUnit == 5) ? (phyUnit + 1) : phyUnit),
++ IP_VLAN_TABLE_SETTING(phyUnit));
++
++ /* Send all packets to all ports */
++ phyReg = phyRegRead(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_1_REG);
++ phyReg = phyReg | ((1 << phyUnit) << IP_VLAN1_OUTPUT_PORT_MASK_S);
++ phyRegWrite(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_1_REG, phyReg);
++ }
++ phyReg = phyRegRead(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_9_REG);
++ phyReg = phyReg | TAG_VLAN_ENABLE;
++ phyReg = phyReg & ~VID_INDX_SEL_M;
++ phyRegWrite(phyBase, IP_GLOBAL_PHY30_ADDR, IP_GLOBAL_PHY30_9_REG, phyReg);
++
++}
++
++
++LOCAL void
++ip_verifyReady(int ethUnit)
++{
++ int phyUnit;
++ UINT32 phyBase = 0;
++ UINT32 phyAddr;
++ UINT16 phyID1;
++ UINT16 phyID2;
++
++ /*
++ * The first read to the Phy port registers always fails and
++ * returns 0. So get things started with a bogus read.
++ */
++ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) {
++ if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++
++ phyBase = IP_PHYBASE(phyUnit);
++ phyAddr = IP_PHYADDR(phyUnit);
++
++ phyID1 = phyRegRead(phyBase, phyAddr, IP_PHY_ID1); /* returns 0 */
++ break;
++ }
++
++ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) {
++ if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++
++ /*******************/
++ /* Verify phy port */
++ /*******************/
++ phyBase = IP_PHYBASE(phyUnit);
++ phyAddr = IP_PHYADDR(phyUnit);
++
++ phyID1 = phyRegRead(phyBase, phyAddr, IP_PHY_ID1);
++ if (phyID1 != IP_PHY_ID1_EXPECTATION) {
++ DRV_PRINT(DRV_DEBUG_PHYERROR,
++ ("Invalid PHY ID1 for enet%d port%d. Expected 0x%04x, read 0x%04x\n",
++ ethUnit,
++ phyUnit,
++ IP_PHY_ID1_EXPECTATION,
++ phyID1));
++ return;
++ }
++
++ phyID2 = phyRegRead(phyBase, phyAddr, IP_PHY_ID2);
++ if ((phyID2 & IP_OUI_LSB_MASK) != IP_OUI_LSB_EXPECTATION) {
++ DRV_PRINT(DRV_DEBUG_PHYERROR,
++ ("Invalid PHY ID2 for enet%d port %d. Expected 0x%04x, read 0x%04x\n",
++ ethUnit,
++ phyUnit,
++ IP_OUI_LSB_EXPECTATION,
++ phyID2));
++ return;
++ }
++
++ DRV_PRINT(DRV_DEBUG_PHYSETUP,
++ ("Found PHY enet%d port%d: model 0x%x revision 0x%x\n",
++ ethUnit,
++ phyUnit,
++ (phyID2 & IP_MODEL_NUM_MASK) >> IP_MODEL_NUM_SHIFT,
++ (phyID2 & IP_REV_NUM_MASK) >> IP_REV_NUM_SHIFT));
++
++ }
++}
++
++
++/******************************************************************************
++*
++* ip_phySetup - reset and setup the PHY associated with
++* the specified MAC unit number.
++*
++* Resets the associated PHY port.
++*
++* RETURNS:
++* TRUE --> associated PHY is alive
++* FALSE --> no LINKs on this ethernet unit
++*/
++
++BOOL
++ip_phySetup(int ethUnit, UINT32 _phyBase)
++{
++ int phyUnit;
++ UINT16 phyHwStatus;
++ UINT16 timeout;
++ int liveLinks = 0;
++ UINT32 phyBase = 0;
++ BOOL foundPhy = FALSE;
++ UINT32 phyAddr;
++
++ /* Reset PHYs*/
++ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) {
++ if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++
++ phyBase = IP_PHYBASE(phyUnit);
++ phyAddr = IP_PHYADDR(phyUnit);
++
++ phyRegWrite(phyBase, phyAddr, IP_PHY_CONTROL,
++ IP_CTRL_SOFTWARE_RESET);
++ }
++ /*
++ * After the phy is reset, it takes a little while before
++ * it can respond properly.
++ */
++ sysMsDelay(300);
++ /* Verify that the switch is what we think it is, and that it's ready */
++ ip_verifyReady(ethUnit);
++
++ /* See if there's any configuration data for this enet */
++ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) {
++ if (IP_ETHUNIT(phyUnit) != ethUnit) {
++ continue;
++ }
++
++ phyBase = IP_PHYBASE(phyUnit);
++ foundPhy = TRUE;
++ break;
++ }
++
++ if (!foundPhy) {
++ return FALSE; /* No PHY's configured for this ethUnit */
++ }
++
++#ifdef COBRA_TODO
++ /* Initialize global switch settings */
++
++ /* Initialize the aging time */
++
++ /* Set the learning properties */
++#endif
++
++ /* start auto negogiation on each phy */
++ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) {
++ if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++
++ phyBase = IP_PHYBASE(phyUnit);
++ phyAddr = IP_PHYADDR(phyUnit);
++
++ phyRegWrite(phyBase, phyAddr, IP_AUTONEG_ADVERT,
++ IP_ADVERTISE_ALL);
++ phyRegWrite(phyBase, phyAddr, IP_PHY_CONTROL,
++ IP_CTRL_AUTONEGOTIATION_ENABLE | IP_CTRL_START_AUTONEGOTIATION);
++ }
++
++ /*
++ * Wait up to .75 seconds for ALL associated PHYs to finish
++ * autonegotiation. The only way we get out of here sooner is
++ * if ALL PHYs are connected AND finish autonegotiation.
++ */
++ timeout=5;
++ for (phyUnit=0; (phyUnit < IP_PHY_MAX) /*&& (timeout > 0) */; phyUnit++) {
++ if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++ for (;;) {
++ phyBase = IP_PHYBASE(phyUnit);
++ phyAddr = IP_PHYADDR(phyUnit);
++
++ phyHwStatus = phyRegRead(phyBase, phyAddr, IP_PHY_STATUS);
++
++ if (IP_AUTONEG_DONE(phyHwStatus)) {
++ DRV_PRINT(DRV_DEBUG_PHYSETUP,
++ ("Port %d, Neg Success\n", phyUnit));
++ break;
++ }
++ if (timeout == 0) {
++ DRV_PRINT(DRV_DEBUG_PHYSETUP,
++ ("Port %d, Negogiation timeout\n", phyUnit));
++ break;
++ }
++ if (--timeout == 0) {
++ DRV_PRINT(DRV_DEBUG_PHYSETUP,
++ ("Port %d, Negogiation timeout\n", phyUnit));
++ break;
++ }
++
++ sysMsDelay(150);
++ }
++ }
++
++ /*
++ * All PHYs have had adequate time to autonegotiate.
++ * Now initialize software status.
++ *
++ * It's possible that some ports may take a bit longer
++ * to autonegotiate; but we can't wait forever. They'll
++ * get noticed by mv_phyCheckStatusChange during regular
++ * polling activities.
++ */
++ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) {
++ if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++
++ if (ip_phyIsLinkAlive(phyUnit)) {
++ liveLinks++;
++ IP_IS_PHY_ALIVE(phyUnit) = TRUE;
++ } else {
++ IP_IS_PHY_ALIVE(phyUnit) = FALSE;
++ }
++
++ DRV_PRINT(DRV_DEBUG_PHYSETUP,
++ ("eth%d: Phy Status=%4.4x\n",
++ ethUnit,
++ phyRegRead(IP_PHYBASE(phyUnit),
++ IP_PHYADDR(phyUnit),
++ IP_PHY_STATUS)));
++ }
++#if 0
++ /* XXX Divy. Disable WAN/LAN seggregation. See bug 17866 */
++ ip_VLANInit(ethUnit);
++#endif
++ return (liveLinks > 0);
++}
++
++/******************************************************************************
++*
++* ip_phyIsDuplexFull - Determines whether the phy ports associated with the
++* specified device are FULL or HALF duplex.
++*
++* RETURNS:
++* 1 --> FULL
++* 0 --> HALF
++*/
++int
++ip_phyIsFullDuplex(int ethUnit)
++{
++ int phyUnit;
++ UINT32 phyBase;
++ UINT32 phyAddr;
++ UINT16 phyHwStatus;
++
++ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) {
++ if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++
++ if (ip_phyIsLinkAlive(phyUnit)) {
++
++ phyBase = IP_PHYBASE(phyUnit);
++ phyAddr = IP_PHYADDR(phyUnit);
++
++ phyHwStatus = phyRegRead(phyBase, phyAddr, IP_LINK_PARTNER_ABILITY);
++ printk("ipPhy.c: phyHwStatus 0x%x\n",phyHwStatus);
++ if ((phyHwStatus & IP_LINK_100BASETX_FULL_DUPLEX) ||
++ (phyHwStatus & IP_LINK_10BASETX_FULL_DUPLEX)) {
++ return TRUE;
++ }
++ }
++ return -1;
++ }
++
++ return FALSE;
++
++}
++
++
++/******************************************************************************
++*
++* ip_phyIsSpeed100 - Determines the speed of phy ports associated with the
++* specified device.
++*
++* RETURNS:
++* TRUE --> 100Mbit
++* FALSE --> 10Mbit
++*/
++
++BOOL
++ip_phyIsSpeed100(int ethUnit)
++{
++ int phyUnit;
++ UINT16 phyHwStatus;
++ UINT32 phyBase;
++ UINT32 phyAddr;
++
++ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) {
++ if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++
++ if (ip_phyIsLinkAlive(phyUnit)) {
++
++ phyBase = IP_PHYBASE(phyUnit);
++ phyAddr = IP_PHYADDR(phyUnit);
++
++ phyHwStatus = phyRegRead(phyBase, phyAddr, IP_LINK_PARTNER_ABILITY);
++
++ if (phyHwStatus & IP_LINK_100BASETX) {
++ return TRUE;
++ }
++ }
++ }
++
++ return FALSE;
++}
++
++/*****************************************************************************
++*
++* ip_phyCheckStatusChange -- checks for significant changes in PHY state.
++*
++* A "significant change" is:
++* dropped link (e.g. ethernet cable unplugged) OR
++* autonegotiation completed + link (e.g. ethernet cable plugged in)
++*
++* When a PHY is plugged in, phyLinkGained is called.
++* When a PHY is unplugged, phyLinkLost is called.
++*/
++
++void
++ip_phyCheckStatusChange(int ethUnit)
++{
++
++ int phyUnit;
++ UINT16 phyHwStatus;
++ ipPhyInfo_t *lastStatus;
++ int linkCount = 0;
++ int lostLinks = 0;
++ int gainedLinks = 0;
++ UINT32 phyBase;
++ UINT32 phyAddr;
++
++ for (phyUnit=0; phyUnit < IP_PHY_MAX; phyUnit++) {
++ if (!IP_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++
++ phyBase = IP_PHYBASE(phyUnit);
++ phyAddr = IP_PHYADDR(phyUnit);
++
++ lastStatus = &ipPhyInfo[phyUnit];
++ phyHwStatus = phyRegRead(phyBase, phyAddr, IP_PHY_STATUS);
++
++ if (lastStatus->isPhyAlive) { /* last known link status was ALIVE */
++ /* See if we've lost link */
++ if (phyHwStatus & IP_STATUS_LINK_PASS) {
++ linkCount++;
++ } else {
++ lostLinks++;
++#ifdef COBRA_TODO
++ mv_flushATUDB(phyUnit);
++#endif
++ DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d down\n",
++ ethUnit, phyUnit));
++ lastStatus->isPhyAlive = FALSE;
++ }
++ } else { /* last known link status was DEAD */
++ /* Check for AutoNegotiation complete */
++ if (IP_AUTONEG_DONE(phyHwStatus)) {
++ gainedLinks++;
++ linkCount++;
++ DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d up\n",
++ ethUnit, phyUnit));
++ lastStatus->isPhyAlive = TRUE;
++ }
++ }
++ }
++
++ if (linkCount == 0) {
++ if (lostLinks) {
++ /* We just lost the last link for this MAC */
++ phyLinkLost(ethUnit);
++ }
++ } else {
++ if (gainedLinks == linkCount) {
++ /* We just gained our first link(s) for this MAC */
++ phyLinkGained(ethUnit);
++ }
++ }
++
++}
++
++#if DEBUG
++
++/* Define the registers of interest for a phyShow command */
++typedef struct ipRegisterTableEntry_s {
++ UINT32 regNum;
++ char *regIdString;
++} ipRegisterTableEntry_t;
++
++ipRegisterTableEntry_t ipPhyRegisterTable[] = {
++ {IP_PHY_CONTROL, "PHY Control "},
++ {IP_PHY_STATUS, "PHY Status "},
++ {IP_PHY_ID1, "PHY Identifier 1 "},
++ {IP_PHY_ID2, "PHY Identifier 2 "},
++ {IP_AUTONEG_ADVERT, "Auto-Negotiation Advertisement "},
++ {IP_LINK_PARTNER_ABILITY, "Link Partner Ability "},
++ {IP_AUTONEG_EXPANSION, "Auto-Negotiation Expansion "},
++};
++int ipPhyNumRegs = sizeof(ipPhyRegisterTable) / sizeof(ipPhyRegisterTable[0]);
++
++
++ipRegisterTableEntry_t ipPhy29GlobalRegisterTable[] = {
++ {IP_GLOBAL_PHY29_18_REG, "29_18_REG "},
++ {IP_GLOBAL_PHY29_19_REG, "29_19_REG "},
++ {IP_GLOBAL_PHY29_20_REG, "29_20_REG "},
++ {IP_GLOBAL_PHY29_21_REG, "29_21_REG "},
++ {IP_GLOBAL_PHY29_22_REG, "29_22_REG "},
++ {IP_GLOBAL_PHY29_23_REG, "29_23_REG "},
++ {IP_GLOBAL_PHY29_24_REG, "29_24_REG "},
++ {IP_GLOBAL_PHY29_25_REG, "29_25_REG "},
++ {IP_GLOBAL_PHY29_26_REG, "29_26_REG "},
++ {IP_GLOBAL_PHY29_27_REG, "29_27_REG "},
++ {IP_GLOBAL_PHY29_28_REG, "29_28_REG "},
++ {IP_GLOBAL_PHY29_29_REG, "29_29_REG "},
++ {IP_GLOBAL_PHY29_30_REG, "29_30_REG "},
++ {IP_GLOBAL_PHY29_31_REG, "29_31_REG "},
++};
++int ipPhy29GlobalNumRegs =
++ sizeof(ipPhy29GlobalRegisterTable) / sizeof(ipPhy29GlobalRegisterTable[0]);
++
++
++ipRegisterTableEntry_t ipPhy30GlobalRegisterTable[] = {
++ {IP_GLOBAL_PHY30_0_REG, "30_0_REG "},
++ {IP_GLOBAL_PHY30_1_REG, "30_1_REG "},
++ {IP_GLOBAL_PHY30_2_REG, "30_2_REG "},
++ {IP_GLOBAL_PHY30_3_REG, "30_3_REG "},
++ {IP_GLOBAL_PHY30_4_REG, "30_4_REG "},
++ {IP_GLOBAL_PHY30_5_REG, "30_5_REG "},
++ {IP_GLOBAL_PHY30_6_REG, "30_6_REG "},
++ {IP_GLOBAL_PHY30_7_REG, "30_7_REG "},
++ {IP_GLOBAL_PHY30_8_REG, "30_8_REG "},
++ {IP_GLOBAL_PHY30_9_REG, "30_9_REG "},
++ {IP_GLOBAL_PHY30_10_REG, "30_10_REG "},
++ {IP_GLOBAL_PHY30_11_REG, "30_11_REG "},
++ {IP_GLOBAL_PHY30_12_REG, "30_12_REG "},
++ {IP_GLOBAL_PHY30_13_REG, "30_13_REG "},
++ {IP_GLOBAL_PHY30_16_REG, "30_16_REG "},
++ {IP_GLOBAL_PHY30_17_REG, "30_17_REG "},
++ {IP_GLOBAL_PHY30_18_REG, "30_18_REG "},
++ {IP_GLOBAL_PHY30_20_REG, "30_20_REG "},
++ {IP_GLOBAL_PHY30_21_REG, "30_21_REG "},
++ {IP_GLOBAL_PHY30_22_REG, "30_22_REG "},
++ {IP_GLOBAL_PHY30_23_REG, "30_23_REG "},
++ {IP_GLOBAL_PHY30_24_REG, "30_24_REG "},
++ {IP_GLOBAL_PHY30_25_REG, "30_25_REG "},
++ {IP_GLOBAL_PHY30_26_REG, "30_26_REG "},
++ {IP_GLOBAL_PHY30_27_REG, "30_27_REG "},
++ {IP_GLOBAL_PHY30_28_REG, "30_28_REG "},
++ {IP_GLOBAL_PHY30_29_REG, "30_29_REG "},
++ {IP_GLOBAL_PHY30_30_REG, "30_30_REG "},
++ {IP_GLOBAL_PHY30_31_REG, "30_31_REG "},
++};
++int ipPhy30GlobalNumRegs =
++ sizeof(ipPhy30GlobalRegisterTable) / sizeof(ipPhy30GlobalRegisterTable[0]);
++
++ipRegisterTableEntry_t ipPhy31GlobalRegisterTable[] = {
++ {IP_GLOBAL_PHY31_0_REG, "31_0_REG "},
++ {IP_GLOBAL_PHY31_1_REG, "31_1_REG "},
++ {IP_GLOBAL_PHY31_2_REG, "31_2_REG "},
++ {IP_GLOBAL_PHY31_3_REG, "31_3_REG "},
++ {IP_GLOBAL_PHY31_4_REG, "31_4_REG "},
++ {IP_GLOBAL_PHY31_5_REG, "31_5_REG "},
++ {IP_GLOBAL_PHY31_6_REG, "31_6_REG "},
++};
++
++int ipPhy31GlobalNumRegs =
++ sizeof(ipPhy31GlobalRegisterTable) / sizeof(ipPhy31GlobalRegisterTable[0]);
++
++
++/*****************************************************************************
++*
++* ip_phyShow - Dump the state of a PHY.
++* There are two sets of registers for each phy port:
++* "phy registers" and
++* "switch port registers"
++* We dump 'em all, plus the switch global registers.
++*/
++void
++ip_phyShow(int phyUnit)
++{
++ int i;
++ UINT16 value;
++ UINT32 phyBase;
++ UINT32 phyAddr;
++
++ if (!ip_validPhyId(phyUnit)) {
++ return;
++ }
++
++ phyBase = IP_PHYBASE(phyUnit);
++ phyAddr = IP_PHYADDR(phyUnit);
++
++ printf("PHY state for PHY%d (enet%d, phyBase 0x%8x, phyAddr 0x%x)\n",
++ phyUnit,
++ IP_ETHUNIT(phyUnit),
++ IP_PHYBASE(phyUnit),
++ IP_PHYADDR(phyUnit));
++
++ printf("PHY Registers:\n");
++ for (i=0; i < ipPhyNumRegs; i++) {
++
++ value = phyRegRead(phyBase, phyAddr, ipPhyRegisterTable[i].regNum);
++
++ printf("Reg %02d (0x%02x) %s = 0x%08x\n",
++ ipPhyRegisterTable[i].regNum,
++ ipPhyRegisterTable[i].regNum,
++ ipPhyRegisterTable[i].regIdString,
++ value);
++ }
++
++ phyBase = IP_GLOBALREGBASE;
++
++ printf("Switch Global Registers:\n");
++ printf("Phy29 Registers:\n");
++ for (i=0; i < ipPhy29GlobalNumRegs; i++) {
++
++ value = phyRegRead(phyBase, IP_GLOBAL_PHY29_ADDR,
++ ipPhy29GlobalRegisterTable[i].regNum);
++
++ printf("Reg %02d (0x%02x) %s = 0x%08x\n",
++ ipPhy29GlobalRegisterTable[i].regNum,
++ ipPhy29GlobalRegisterTable[i].regNum,
++ ipPhy29GlobalRegisterTable[i].regIdString,
++ value);
++ }
++
++ printf("Phy30 Registers:\n");
++ for (i=0; i < ipPhy30GlobalNumRegs; i++) {
++
++ value = phyRegRead(phyBase, IP_GLOBAL_PHY30_ADDR,
++ ipPhy30GlobalRegisterTable[i].regNum);
++
++ printf("Reg %02d (0x%02x) %s = 0x%08x\n",
++ ipPhy30GlobalRegisterTable[i].regNum,
++ ipPhy30GlobalRegisterTable[i].regNum,
++ ipPhy30GlobalRegisterTable[i].regIdString,
++ value);
++ }
++ printf("Phy31 Registers:\n");
++ for (i=0; i < ipPhy31GlobalNumRegs; i++) {
++
++ value = phyRegRead(phyBase, IP_GLOBAL_PHY31_ADDR,
++ ipPhy31GlobalRegisterTable[i].regNum);
++
++ printf("Reg %02d (0x%02x) %s = 0x%08x\n",
++ ipPhy31GlobalRegisterTable[i].regNum,
++ ipPhy31GlobalRegisterTable[i].regNum,
++ ipPhy31GlobalRegisterTable[i].regIdString,
++ value);
++ }
++}
++
++/*****************************************************************************
++*
++* ip_phySet - Modify the value of a PHY register (debug only).
++*/
++void
++ip_phySet(int phyUnit, UINT32 regnum, UINT32 value)
++{
++ UINT32 phyBase;
++ UINT32 phyAddr;
++
++ if (ip_validPhyId(phyUnit)) {
++
++ phyBase = IP_PHYBASE(phyUnit);
++ phyAddr = IP_PHYADDR(phyUnit);
++
++ phyRegWrite(phyBase, phyAddr, regnum, value);
++ }
++}
++
++/*****************************************************************************
++*
++* ip_globalSet - Modify the value of a global register
++* (debug only).
++*/
++void
++ip_globalSet(UINT32 phyAddr, UINT32 regnum, UINT32 value)
++{
++ UINT32 phyBase;
++
++ phyBase = IP_GLOBALREGBASE;
++
++ phyRegWrite(phyBase, phyAddr, regnum, value);
++}
++
++
++#endif
+diff -urN linux-mips-orig/drivers/net/ath/ipPhy.h linux-mips-new/drivers/net/ath/ipPhy.h
+--- linux-mips-orig/drivers/net/ath/ipPhy.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/ipPhy.h 2005-12-31 12:33:57.678538064 +0000
+@@ -0,0 +1,172 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * icPhy.h - definitions for the ethernet PHY.
++ * This code supports a simple 1-port ethernet phy, ICPLUS,
++ * All definitions in this file are operating system independent!
++ */
++
++#ifndef IPPHY_H
++#define IPPHY_H
++
++/*****************/
++/* PHY Registers */
++/*****************/
++#define IP_PHY_CONTROL 0
++#define IP_PHY_STATUS 1
++#define IP_PHY_ID1 2
++#define IP_PHY_ID2 3
++#define IP_AUTONEG_ADVERT 4
++#define IP_LINK_PARTNER_ABILITY 5
++#define IP_AUTONEG_EXPANSION 6
++
++
++/* IP_PHY_CONTROL fields */
++#define IP_CTRL_SOFTWARE_RESET 0x8000
++#define IP_CTRL_SPEED_100 0x2000
++#define IP_CTRL_AUTONEGOTIATION_ENABLE 0x1000
++#define IP_CTRL_START_AUTONEGOTIATION 0x0200
++#define IP_CTRL_SPEED_FULL_DUPLEX 0x0100
++
++/* Phy status fields */
++#define IP_STATUS_AUTO_NEG_DONE 0x0020
++#define IP_STATUS_LINK_PASS 0x0004
++
++#define IP_AUTONEG_DONE(ip_phy_status) \
++ (((ip_phy_status) & \
++ (IP_STATUS_AUTO_NEG_DONE)) == \
++ (IP_STATUS_AUTO_NEG_DONE))
++
++/* ICPLUS_PHY_ID1 fields */
++#define IP_PHY_ID1_EXPECTATION 0x0243 /* OUI >> 6 */
++
++/* ICPLUS_PHY_ID2 fields */
++#define IP_OUI_LSB_MASK 0xfc00
++#define IP_OUI_LSB_EXPECTATION 0x0c00
++#define IP_OUI_LSB_SHIFT 10
++#define IP_MODEL_NUM_MASK 0x03f0
++#define IP_MODEL_NUM_SHIFT 4
++#define IP_REV_NUM_MASK 0x000f
++#define IP_REV_NUM_SHIFT 0
++
++/* Link Partner ability */
++#define IP_LINK_100BASETX_FULL_DUPLEX 0x0100
++#define IP_LINK_100BASETX 0x0080
++#define IP_LINK_10BASETX_FULL_DUPLEX 0x0040
++#define IP_LINK_10BASETX 0x0020
++
++/* Advertisement register. */
++#define IP_ADVERTISE_100FULL 0x0100
++#define IP_ADVERTISE_100HALF 0x0080
++#define IP_ADVERTISE_10FULL 0x0040
++#define IP_ADVERTISE_10HALF 0x0020
++
++#define IP_ADVERTISE_ALL (IP_ADVERTISE_10HALF | IP_ADVERTISE_10FULL | \
++ IP_ADVERTISE_100HALF | IP_ADVERTISE_100FULL)
++
++
++#define IP_VLAN_TAG_VALID 0x81
++#define IP_VLAN_TAG_SIZE 4
++#define IP_VLAN_TAG_OFFSET 12 /* After DA & SA */
++#define IP_SPECIAL_TAG_VALID 0x81
++
++/****************************/
++/* Global Control Registers */
++/****************************/
++/* IP Global register doesn't have names based on functionality
++ * hence has to live with this names for now */
++#define IP_GLOBAL_PHY29_18_REG 18
++#define IP_GLOBAL_PHY29_19_REG 19
++#define IP_GLOBAL_PHY29_20_REG 20
++#define IP_GLOBAL_PHY29_21_REG 21
++#define IP_GLOBAL_PHY29_22_REG 22
++#define IP_GLOBAL_PHY29_23_REG 23
++#define IP_GLOBAL_PHY29_24_REG 24
++#define IP_GLOBAL_PHY29_25_REG 25
++#define IP_GLOBAL_PHY29_26_REG 26
++#define IP_GLOBAL_PHY29_27_REG 27
++#define IP_GLOBAL_PHY29_28_REG 28
++#define IP_GLOBAL_PHY29_29_REG 29
++#define IP_GLOBAL_PHY29_30_REG 30
++#define IP_GLOBAL_PHY29_31_REG 31
++
++
++#define IP_GLOBAL_PHY30_0_REG 0
++#define IP_GLOBAL_PHY30_1_REG 1
++#define IP_GLOBAL_PHY30_2_REG 2
++#define IP_GLOBAL_PHY30_3_REG 3
++#define IP_GLOBAL_PHY30_4_REG 4
++#define IP_GLOBAL_PHY30_5_REG 5
++#define IP_GLOBAL_PHY30_6_REG 6
++#define IP_GLOBAL_PHY30_7_REG 7
++#define IP_GLOBAL_PHY30_8_REG 8
++#define IP_GLOBAL_PHY30_9_REG 9
++#define IP_GLOBAL_PHY30_10_REG 10
++#define IP_GLOBAL_PHY30_11_REG 11
++#define IP_GLOBAL_PHY30_12_REG 12
++#define IP_GLOBAL_PHY30_13_REG 13
++#define IP_GLOBAL_PHY30_16_REG 16
++#define IP_GLOBAL_PHY30_17_REG 17
++#define IP_GLOBAL_PHY30_18_REG 18
++#define IP_GLOBAL_PHY30_20_REG 20
++#define IP_GLOBAL_PHY30_21_REG 21
++#define IP_GLOBAL_PHY30_22_REG 22
++#define IP_GLOBAL_PHY30_23_REG 23
++#define IP_GLOBAL_PHY30_24_REG 24
++#define IP_GLOBAL_PHY30_25_REG 25
++#define IP_GLOBAL_PHY30_26_REG 26
++#define IP_GLOBAL_PHY30_27_REG 27
++#define IP_GLOBAL_PHY30_28_REG 28
++#define IP_GLOBAL_PHY30_29_REG 29
++#define IP_GLOBAL_PHY30_30_REG 30
++#define IP_GLOBAL_PHY30_31_REG 31
++
++#define IP_GLOBAL_PHY31_0_REG 0
++#define IP_GLOBAL_PHY31_1_REG 1
++#define IP_GLOBAL_PHY31_2_REG 2
++#define IP_GLOBAL_PHY31_3_REG 3
++#define IP_GLOBAL_PHY31_4_REG 4
++#define IP_GLOBAL_PHY31_5_REG 5
++#define IP_GLOBAL_PHY31_6_REG 6
++
++#define IP_GLOBAL_PHY29_31_REG 31
++
++
++#define IP_VLAN0_OUTPUT_PORT_MASK_S 0
++#define IP_VLAN1_OUTPUT_PORT_MASK_S 8
++#define IP_VLAN2_OUTPUT_PORT_MASK_S 0
++#define IP_VLAN3_OUTPUT_PORT_MASK_S 8
++
++/* Masks and shifts for 29.23 register */
++#define IP_PORTX_ADD_TAG_S 11
++#define IP_PORTX_REMOVE_TAG_S 6
++#define IP_PORT5_ADD_TAG_S 1
++#define IP_PORT5_REMOVE_TAG_S 0
++
++/*
++ * 30.9 Definitions
++ */
++#define TAG_VLAN_ENABLE 0x0080
++#define VID_INDX_SEL_M 0x0070
++#define VID_INDX_SEL_S 4
++
++
++/* PHY Addresses */
++#define IP_PHY0_ADDR 0
++#define IP_PHY1_ADDR 1
++#define IP_PHY2_ADDR 2
++#define IP_PHY3_ADDR 3
++#define IP_PHY4_ADDR 4
++
++#define IP_GLOBAL_PHY29_ADDR 29
++#define IP_GLOBAL_PHY30_ADDR 30
++#define IP_GLOBAL_PHY31_ADDR 31
++
++
++#endif
+diff -urN linux-mips-orig/drivers/net/ath/kendSwitchPhy.c linux-mips-new/drivers/net/ath/kendSwitchPhy.c
+--- linux-mips-orig/drivers/net/ath/kendSwitchPhy.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/kendSwitchPhy.c 2005-12-31 12:33:57.678538064 +0000
+@@ -0,0 +1,286 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * Manage the ethernet PHY.
++ * This code supports a simple 1-port ethernet phy, Realtek RTL8201BL,
++ * and compatible PHYs, such as the Kendin KS8721B.
++ * All definitions in this file are operating system independent!
++ */
++
++#if defined(linux)
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/delay.h>
++
++#include "ar531xlnx.h"
++#endif
++
++#if defined(__ECOS)
++#include "ae531xecos.h"
++#endif
++
++
++#include "ae531xmac.h"
++#include "ae531xreg.h"
++#include "rtPhy.h"
++
++#define RT_MAX_PORTS 5 /* max addressable ports per MIIM */
++
++#if /* DEBUG */ 1
++#define RT_DEBUG_ERROR 0x00000001
++#define RT_DEBUG_PHYSETUP 0x00000002
++#define RT_DEBUG_PHYCHANGE 0x00000004
++
++/* XXX: must hardcode this since same MIIM for all ethUnits */
++const UINT32 phyBase = 0xb8100000;
++
++int rtPhyDebug = RT_DEBUG_ERROR;
++
++#define RT_PRINT(FLG, X) \
++{ \
++ if (rtPhyDebug & (FLG)) { \
++ DEBUG_PRINTF X; \
++ } \
++}
++#else
++#define RT_PRINT(FLG, X)
++#endif
++
++/*
++ * Track per-PHY state.
++ */
++static BOOL rtPhyAlive[RT_MAX_PORTS];
++
++
++/******************************************************************************
++*
++* rt_phySetup - reset and setup the PHY associated with
++* the specified MAC unit number.
++*
++* Resets the associated PHY port.
++*
++* RETURNS:
++* TRUE --> associated PHY is alive
++* FALSE --> no LINKs on this ethernet unit
++*/
++
++BOOL
++rt_phySetup(int ethUnit, UINT32 phyBaseIgnored)
++{
++ BOOL linkAlive = FALSE;
++
++ /* Reset phy */
++ if (ethUnit == 0) {
++ int i;
++ for (i=1; i<5; i++) {
++ phyRegWrite(phyBase, i, GEN_ctl, AUTONEGENA);
++ sysMsDelay(200);
++ if (phyRegRead(phyBase, i, GEN_sts) & (AUTOCMPLT | LINK)) {
++ rtPhyAlive[i] = TRUE;
++ }
++ else {
++ rtPhyAlive[i] = FALSE;
++ }
++ }
++ }
++ else {
++ phyRegWrite(phyBase, 5, GEN_ctl, AUTONEGENA);
++ sysMsDelay(200);
++ if (phyRegRead(phyBase, 5, GEN_sts) & (AUTOCMPLT | LINK)) {
++ rtPhyAlive[5] = TRUE;
++ }
++ else {
++ rtPhyAlive[5] = FALSE;
++ }
++ }
++
++ return linkAlive;
++}
++
++/******************************************************************************
++*
++* rt_phyIsDuplexFull - Determines whether the phy ports associated with the
++* specified device are FULL or HALF duplex.
++*
++* RETURNS:
++* 1 --> FULL
++* 0 --> HALF
++*/
++int
++rt_phyIsFullDuplex(int ethUnit)
++{
++ UINT16 phyLpa = 0;
++
++ if (ethUnit == 0) {
++ int i;
++ /* 4 ports connected. If any are half-duplex report half. */
++ for (i=1; i<5; i++) {
++ phyLpa = phyRegRead(phyBase, i, AN_lpa);
++ if ( (!(phyLpa & (LPA_TXFD | LPA_10FD))) &&
++ (phyLpa & (LPA_TX | LPA_10)) ) {
++ return 0;
++ }
++ }
++ return 1;
++ }
++ else {
++ phyLpa = phyRegRead(phyBase, 5, AN_lpa);
++ if (phyLpa & (LPA_TXFD | LPA_10FD) ) {
++ return 1;
++ }
++ else {
++ return 0;
++ }
++ }
++}
++
++/******************************************************************************
++*
++* rt_phyIsSpeed100 - Determines the speed of phy ports associated with the
++* specified device.
++*
++* RETURNS:
++* TRUE --> 100Mbit
++* FALSE --> 10Mbit
++*/
++BOOL
++rt_phyIsSpeed100(int ethUnit)
++{
++ UINT16 phyLpa;
++
++ if (ethUnit == 0) {
++ int i;
++ /* 4 ports connected. If any are not 100 report 10. */
++ for (i=1; i<5; i++) {
++ phyLpa = phyRegRead(phyBase, i, AN_lpa);
++ if ( (!(phyLpa & (LPA_TXFD | LPA_TX))) &&
++ (phyLpa & (LPA_10FD | LPA_10)) ) {
++ printk("10\n");
++ return FALSE;
++ }
++ }
++ printk("100\n");
++ return TRUE;
++ }
++ else {
++ phyLpa = phyRegRead(phyBase, 5, AN_lpa);
++ if (phyLpa & (LPA_TXFD | LPA_TX) ) {
++ printk("100\n");
++ return TRUE;
++ }
++ else {
++ printk("10\n");
++ return FALSE;
++ }
++ }
++}
++
++/*****************************************************************************
++*
++* rt_phyCheckStatusChange -- checks for significant changes in PHY state.
++*
++* A "significant change" is:
++* dropped link (e.g. ethernet cable unplugged) OR
++* autonegotiation completed + link (e.g. ethernet cable plugged in)
++*
++* When a PHY is plugged in, phyLinkGained is called.
++* When a PHY is unplugged, phyLinkLost is called.
++*/
++void
++rt_phyCheckStatusChange(int ethUnit)
++{
++ UINT16 phyHwStatus;
++ int i, loopLower, loopUpper;
++
++ if (ethUnit == 0) {
++ loopLower = 1;
++ loopUpper = 4;
++ }
++ else {
++ loopLower = 5;
++ loopUpper = 5;
++ }
++
++ for (i=loopLower; i<=loopUpper; i++) {
++ phyHwStatus = phyRegRead(phyBase, i, GEN_sts);
++
++ if (rtPhyAlive[i]) { /* last known status was ALIVE */
++ /* See if we've lost link */
++ if (!(phyHwStatus & LINK)) {
++ RT_PRINT(RT_DEBUG_PHYCHANGE,("\nethmac%d link down\n", ethUnit));
++ rtPhyAlive[i] = FALSE;
++ phyLinkLost(ethUnit);
++ }
++ } else { /* last known status was DEAD */
++ /* Check for AN complete */
++ if ((phyHwStatus & (AUTOCMPLT | LINK)) == (AUTOCMPLT | LINK)) {
++ RT_PRINT(RT_DEBUG_PHYCHANGE,("\nethmac%d link up\n", ethUnit));
++ rtPhyAlive[i] = TRUE;
++ phyLinkGained(ethUnit);
++ }
++ }
++ }
++}
++
++#if DEBUG
++
++/* Define the PHY registers of interest for a phyShow command */
++struct rtRegisterTable_s {
++ UINT32 regNum;
++ char *regIdString;
++} rtRegisterTable[] =
++{
++ {GEN_ctl, "Basic Mode Control (GEN_ctl) "},
++ {GEN_sts, "Basic Mode Status (GEN_sts) "},
++ {GEN_id_hi, "PHY Identifier 1 (GET_id_hi) "},
++ {GEN_id_lo, "PHY Identifier 2 (GET_id_lo) "},
++ {AN_adv, "Auto-Neg Advertisement (AN_adv) "},
++ {AN_lpa, "Auto-Neg Link Partner Ability "},
++ {AN_exp, "Auto-Neg Expansion "},
++};
++
++int rtNumRegs = sizeof(rtRegisterTable) / sizeof(rtRegisterTable[0]);
++
++/*
++ * Dump the state of a PHY.
++ */
++void
++rt_phyShow(int phyUnit)
++{
++ int i;
++ UINT16 value;
++ int j, loopLower, loopUpper;
++
++ printf("PHY state for ethphy%d\n", phyUnit);
++
++ if (phyUnit == 0) {
++ loopLower = 1;
++ loopUpper = 4;
++ }
++ else {
++ loopLower = 5;
++ loopUpper = 5;
++ }
++
++ for (j=loopLower; j<=loopUpper; j++) {
++ printk("PHY port %d:\n", j);
++ for (i=0; i<rtNumRegs; i++) {
++
++ value = phyRegRead(phyBase, j, rtRegisterTable[i].regNum);
++
++ printf("Reg %02d (0x%02x) %s = 0x%08x\n",
++ rtRegisterTable[i].regNum, rtRegisterTable[i].regNum,
++ rtRegisterTable[i].regIdString, value);
++ }
++ }
++}
++
++#endif
+diff -urN linux-mips-orig/drivers/net/ath/Makefile linux-mips-new/drivers/net/ath/Makefile
+--- linux-mips-orig/drivers/net/ath/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/Makefile 2005-12-31 12:33:57.678538064 +0000
+@@ -0,0 +1,78 @@
++################################################################################
++#
++# This file is subject to the terms and conditions of the GNU General Public
++# License. See the file "COPYING" in the main directory of this archive
++# for more details.
++#
++# Copyright © 2004 Atheros Communications, Inc., All Rights Reserved.
++#
++# Makefile for Atheros ar531x ethernet driver
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++################################################################################
++
++#
++# Makefile for the Atheros ar531x ethernet driver
++#
++
++obj= .
++
++obj-m += ae531x.o
++ae531x-objs := ae531xlnx.o ae531xmac.o
++export-objs := ae531xlnx.o
++list-multi := ae531x.o
++
++ifeq ($(CONFIG_KENDIN_ENET_PHY),y)
++ ae531x-objs += rtPhy.o
++endif
++ifeq ($(CONFIG_KENDIN_KS8995XA_ENET_PHY),y)
++ ae531x-objs += kendSwitchPhy.o
++endif
++ifeq ($(CONFIG_MARVELL_ENET_PHY),y)
++ ae531x-objs += mvPhy.o
++endif
++ifeq ($(CONFIG_ICPLUS_ENET_PHY),y)
++ ae531x-objs += ipPhy.o
++endif
++
++#
++# If building directly into kernel
++#
++ifneq ($(MAKING_MODULES),1)
++obj-$(CONFIG_NET_ATHEROS_ETHER) := ae531x.o $(ae531x-objs)
++O_TARGET := ae531x.o
++endif
++
++INCS += -I.
++
++EXTRA_CFLAGS+=$(INCS) ${COPTS} -g
++ifeq ($(DEBUG_BUILD),1)
++EXTRA_CFLAGS+=-DDEBUG
++endif
++
++# release tag versioning
++-include $(KERNELPATH)/ath_version.mk
++
++-include $(TOPDIR)/Rules.make
++STRIP= ${TOOLPREFIX}strip
++
++ifndef MODPATH
++MODPATH = ${KERNELPATH}/arch/mips/ar531x/ROOTDISK/rootdir/lib/modules/${KERNELRELEASE}/
++endif
++
++all:
++ $(MAKE) -C ${KERNELPATH} SUBDIRS=$(shell pwd) modules
++
++install: all
++ $(STRIP) -S ae531x.o
++ cp ae531x.o ${KERNELPATH}/arch/mips/ar531x/ROOTDISK/rootdir/lib/modules/$(strip $(shell head -n 1 $(KERNELPATH)/Makefile | cut -f 2 -d'=')).$(strip $(shell head -n 2 $(KERNELPATH)/Makefile | tail -1 | cut -f 2 -d'=')).$(strip $(shell head -n 3 $(KERNELPATH)/Makefile | tail -1 | cut -f 2 -d'='))${EXTRAVERSION}/net/.
++
++clean:
++ -rm -f *~ *.o *.ko *.mod.c
++ -rm -f .version .*.o.flags .*.o.d .*.o.cmd .*.ko.cmd
++
++ae531x.o : $(ae531x-objs)
++ $(LD) -o ae531x.o -r $(ae531x-objs)
+diff -urN linux-mips-orig/drivers/net/ath/mvPhy.c linux-mips-new/drivers/net/ath/mvPhy.c
+--- linux-mips-orig/drivers/net/ath/mvPhy.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/mvPhy.c 2005-12-31 12:33:57.726530768 +0000
+@@ -0,0 +1,1230 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++* Manage the ethernet PHY switch, Marvell 88E6060.
++*
++* This module is intended to be largely OS and platform-independent.
++*/
++
++#if defined(linux)
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/delay.h>
++
++#include "ar531xlnx.h"
++#endif
++
++#if defined(__ECOS)
++#include "ae531xecos.h"
++#endif
++
++
++#include "ae531xmac.h"
++#include "ae531xreg.h"
++#include "mvPhy.h"
++
++#if /* DEBUG */ 1
++#define MV_DEBUG_ERROR 0x00000001
++#define MV_DEBUG_PHYSETUP 0x00000002
++#define MV_DEBUG_PHYCHANGE 0x00000004
++
++int mvPhyDebug = MV_DEBUG_ERROR;
++
++#define MV_PRINT(FLG, X) \
++{ \
++ if (mvPhyDebug & (FLG)) { \
++ DEBUG_PRINTF X; \
++ } \
++}
++#else
++#define MV_PRINT(FLG, X)
++#endif
++
++#if CONFIG_VENETDEV
++/*
++ * On AR5312 with CONFIG_VENETDEV==1,
++ * ports 0..3 are LAN ports (accessed through ae0)
++ * port 4 is the WAN port. (accessed through ae1)
++ *
++ * The phy switch settings in the mvPhyInfo table are set accordingly.
++ */
++#define MV_WAN_PORT 4
++#define MV_IS_LAN_PORT(port) ((port) < MV_WAN_PORT)
++#define MV_IS_WAN_PORT(port) ((port) == MV_WAN_PORT)
++#endif
++
++/*
++ * Track per-PHY port information.
++ */
++typedef struct {
++ BOOL isEnetPort; /* normal enet port */
++ BOOL isPhyAlive; /* last known state of link */
++ int ethUnit; /* MAC associated with this phy port */
++ UINT32 phyBase;
++ UINT32 phyAddr; /* PHY registers associated with this phy port */
++ UINT32 switchPortAddr; /* switch port regs assoc'ed with this phy port */
++ UINT32 VLANTableSetting; /* Value to be written to VLAN table */
++} mvPhyInfo_t;
++
++/******************************************************************************
++ * Per-PHY information, indexed by PHY unit number.
++ *
++ * This table is board-dependent. It includes information
++ * about which enet MAC controls which PHY port.
++ */
++mvPhyInfo_t mvPhyInfo[] = {
++ /*
++ * On AP30/AR5312, all PHYs are associated with MAC0.
++ * AP30/AR5312's MAC1 isn't used for anything.
++ * CONFIG_VENETDEV==1 (router) configuration:
++ * Ports 0,1,2, and 3 are "LAN ports"
++ * Port 4 is a WAN port
++ * Port 5 connects to MAC0 in the AR5312
++ * CONFIG_VENETDEV==0 (bridge) configuration:
++ * Ports 0,1,2,3,4 are "LAN ports"
++ * Port 5 connects to the MAC0 in the AR5312
++ */
++ {isEnetPort: TRUE, /* phy port 0 -- LAN port 0 */
++ isPhyAlive: FALSE,
++ ethUnit: 0,
++ phyBase: 0,
++ phyAddr: 0x10,
++ switchPortAddr: 0x18,
++#if CONFIG_VENETDEV
++ VLANTableSetting: 0x2e
++#else
++ VLANTableSetting: 0x3e
++#endif
++ },
++
++ {isEnetPort: TRUE, /* phy port 1 -- LAN port 1 */
++ isPhyAlive: FALSE,
++ ethUnit: 0,
++ phyBase: 0,
++ phyAddr: 0x11,
++ switchPortAddr: 0x19,
++#if CONFIG_VENETDEV
++ VLANTableSetting: 0x2d
++#else
++ VLANTableSetting: 0x3d
++#endif
++ },
++
++ {isEnetPort: TRUE, /* phy port 2 -- LAN port 2 */
++ isPhyAlive: FALSE,
++ ethUnit: 0,
++ phyBase: 0,
++ phyAddr: 0x12,
++ switchPortAddr: 0x1a,
++#if CONFIG_VENETDEV
++ VLANTableSetting: 0x2b
++#else
++ VLANTableSetting: 0x3b
++#endif
++ },
++
++ {isEnetPort: TRUE, /* phy port 3 -- LAN port 3 */
++ isPhyAlive: FALSE,
++ ethUnit: 0,
++ phyBase: 0,
++ phyAddr: 0x13,
++ switchPortAddr: 0x1b,
++#if CONFIG_VENETDEV
++ VLANTableSetting: 0x27
++#else
++ VLANTableSetting: 0x37
++#endif
++ },
++
++ {isEnetPort: TRUE, /* phy port 4 -- WAN port or LAN port 4 */
++ isPhyAlive: FALSE,
++ ethUnit: 0,
++ phyBase: 0,
++ phyAddr: 0x14,
++ switchPortAddr: 0x1c,
++#if CONFIG_VENETDEV
++ VLANTableSetting: 0x1020 /* WAN port */
++#else
++ VLANTableSetting: 0x2f /* LAN port 4 */
++#endif
++ },
++
++ {isEnetPort: FALSE, /* phy port 5 -- CPU port (no RJ45 connector) */
++ isPhyAlive: TRUE,
++ ethUnit: 0,
++ phyBase: 0,
++ phyAddr: 0x15,
++ switchPortAddr: 0x1d,
++#if CONFIG_VENETDEV
++ VLANTableSetting: 0x0f /* Send only to LAN ports */
++#else
++ VLANTableSetting: 0x1f /* Send to all ports */
++#endif
++ },
++};
++
++#define MV_PHY_MAX (sizeof(mvPhyInfo) / sizeof(mvPhyInfo[0]))
++
++/* Range of valid PHY IDs is [MIN..MAX] */
++#define MV_ID_MIN 0
++#define MV_ID_MAX (MV_PHY_MAX-1)
++
++/* Convenience macros to access myPhyInfo */
++#define MV_IS_ENET_PORT(phyUnit) (mvPhyInfo[phyUnit].isEnetPort)
++#define MV_IS_PHY_ALIVE(phyUnit) (mvPhyInfo[phyUnit].isPhyAlive)
++#define MV_ETHUNIT(phyUnit) (mvPhyInfo[phyUnit].ethUnit)
++#define MV_PHYBASE(phyUnit) (mvPhyInfo[phyUnit].phyBase)
++#define MV_PHYADDR(phyUnit) (mvPhyInfo[phyUnit].phyAddr)
++#define MV_SWITCH_PORT_ADDR(phyUnit) (mvPhyInfo[phyUnit].switchPortAddr)
++#define MV_VLAN_TABLE_SETTING(phyUnit) (mvPhyInfo[phyUnit].VLANTableSetting)
++
++#define MV_IS_ETHUNIT(phyUnit, ethUnit) \
++ (MV_IS_ENET_PORT(phyUnit) && \
++ MV_ETHUNIT(phyUnit) == (ethUnit))
++
++
++/* Forward references */
++BOOL mv_phyIsLinkAlive(int phyUnit);
++LOCAL void mv_VLANInit(int ethUnit);
++LOCAL void mv_enableConfiguredPorts(int ethUnit);
++LOCAL void mv_verifyReady(int ethUnit);
++BOOL mv_phySetup(int ethUnit, UINT32 phyBase);
++int mv_phyIsFullDuplex(int ethUnit);
++BOOL mv_phyIsSpeed100(int phyUnit);
++LOCAL BOOL mv_validPhyId(int phyUnit);
++void mv_flushATUDB(int phyUnit);
++void mv_phyCheckStatusChange(int ethUnit);
++#if DEBUG
++void mv_phyShow(int phyUnit);
++void mv_phySet(int phyUnit, UINT32 regnum, UINT32 value);
++void mv_switchPortSet(int phyUnit, UINT32 regnum, UINT32 value);
++void mv_switchGlobalSet(int phyUnit, UINT32 regnum, UINT32 value);
++void mv_showATUDB(int phyUnit);
++void mv_countGoodFrames(int phyUnit);
++void mv_countBadFrames(int phyUnit);
++void mv_showFrameCounts(int phyUnit);
++#endif
++
++
++/******************************************************************************
++*
++* mv_phyIsLinkAlive - test to see if the specified link is alive
++*
++* RETURNS:
++* TRUE --> link is alive
++* FALSE --> link is down
++*/
++BOOL
++mv_phyIsLinkAlive(int phyUnit)
++{
++ UINT16 phyHwStatus;
++ UINT32 phyBase;
++ UINT32 phyAddr;
++
++ phyBase = MV_PHYBASE(phyUnit);
++ phyAddr = MV_PHYADDR(phyUnit);
++
++ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS);
++
++ if (phyHwStatus & MV_STATUS_REAL_TIME_LINK_UP) {
++ return TRUE;
++ } else {
++ return FALSE;
++ }
++}
++
++/******************************************************************************
++*
++* mv_VLANInit - initialize "port-based VLANs" for the specified enet unit.
++*/
++LOCAL void
++mv_VLANInit(int ethUnit)
++{
++ int phyUnit;
++ UINT32 phyBase;
++ UINT32 switchPortAddr;
++
++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
++ if (MV_ETHUNIT(phyUnit) != ethUnit) {
++ continue;
++ }
++
++ phyBase = MV_PHYBASE(phyUnit);
++ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit);
++
++ phyRegWrite(phyBase, switchPortAddr, MV_PORT_BASED_VLAN_MAP,
++ MV_VLAN_TABLE_SETTING(phyUnit));
++ }
++}
++
++#define phyPortConfigured(phyUnit) TRUE /* TBDFREEDOM2 */
++
++/******************************************************************************
++*
++* mv_enableConfiguredPorts - enable whichever PHY ports are supposed
++* to be enabled according to administrative configuration.
++*/
++LOCAL void
++mv_enableConfiguredPorts(int ethUnit)
++{
++ int phyUnit;
++ UINT32 phyBase;
++ UINT32 switchPortAddr;
++ UINT16 portControl;
++ UINT16 portAssociationVector;
++
++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
++ if (MV_ETHUNIT(phyUnit) != ethUnit) {
++ continue;
++ }
++
++ phyBase = MV_PHYBASE(phyUnit);
++ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit);
++
++ if (phyPortConfigured(phyUnit)) {
++
++ portControl = MV_PORT_CONTROL_PORT_STATE_FORWARDING;
++#if CONFIG_VENETDEV
++ if (!MV_IS_ENET_PORT(phyUnit)) { /* CPU port */
++ portControl |= MV_PORT_CONTROL_INGRESS_TRAILER
++ | MV_PORT_CONTROL_EGRESS_MODE;
++ }
++#endif
++ phyRegWrite(phyBase, switchPortAddr, MV_PORT_CONTROL, portControl);
++
++ portAssociationVector = 1 << phyUnit;
++
++ phyRegWrite(phyBase, switchPortAddr,
++ MV_PORT_ASSOCIATION_VECTOR, portAssociationVector);
++ }
++ }
++}
++
++/******************************************************************************
++*
++* mv_verifyReady - validates that we're dealing with the device
++* we think we're dealing with, and that it's ready.
++*/
++LOCAL void
++mv_verifyReady(int ethUnit)
++{
++ int phyUnit;
++ UINT16 globalStatus;
++ UINT32 phyBase = 0;
++ UINT32 phyAddr;
++ UINT32 switchPortAddr;
++ UINT16 phyID1;
++ UINT16 phyID2;
++ UINT16 switchID;
++
++ /*
++ * The first read to the Phy port registers always fails and
++ * returns 0. So get things started with a bogus read.
++ */
++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
++ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++ phyBase = MV_PHYBASE(phyUnit);
++ phyAddr = MV_PHYADDR(phyUnit);
++
++ (void)phyRegRead(phyBase, phyAddr, MV_PHY_ID1); /* returns 0 */
++ break;
++ }
++
++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
++ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++
++ /*******************/
++ /* Verify phy port */
++ /*******************/
++ phyBase = MV_PHYBASE(phyUnit);
++ phyAddr = MV_PHYADDR(phyUnit);
++
++ phyID1 = phyRegRead(phyBase, phyAddr, MV_PHY_ID1);
++ if (phyID1 != MV_PHY_ID1_EXPECTATION) {
++ MV_PRINT(MV_DEBUG_PHYSETUP,
++ ("Invalid PHY ID1 for ethmac%d port%d. Expected 0x%04x, read 0x%04x\n",
++ ethUnit,
++ phyUnit,
++ MV_PHY_ID1_EXPECTATION,
++ phyID1));
++ return;
++ }
++
++ phyID2 = phyRegRead(phyBase, phyAddr, MV_PHY_ID2);
++ if ((phyID2 & MV_OUI_LSB_MASK) != MV_OUI_LSB_EXPECTATION) {
++ MV_PRINT(MV_DEBUG_PHYSETUP,
++ ("Invalid PHY ID2 for ethmac%d port %d. Expected 0x%04x, read 0x%04x\n",
++ ethUnit,
++ phyUnit,
++ MV_OUI_LSB_EXPECTATION,
++ phyID2));
++ return;
++ }
++
++ MV_PRINT(MV_DEBUG_PHYSETUP,
++ ("Found PHY ethmac%d port%d: model 0x%x revision 0x%x\n",
++ ethUnit,
++ phyUnit,
++ (phyID2 & MV_MODEL_NUM_MASK) >> MV_MODEL_NUM_SHIFT,
++ (phyID2 & MV_REV_NUM_MASK) >> MV_REV_NUM_SHIFT));
++
++
++ /**********************/
++ /* Verify switch port */
++ /**********************/
++ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit);
++
++ switchID = phyRegRead(phyBase, switchPortAddr, MV_SWITCH_ID);
++ if ((switchID & MV_SWITCH_ID_DEV_MASK) !=
++ MV_SWITCH_ID_DEV_EXPECTATION) {
++
++ MV_PRINT(MV_DEBUG_PHYSETUP,
++ ("Invalid switch ID for ethmac%d port %d. Expected 0x%04x, read 0x%04x\n",
++ ethUnit,
++ phyUnit,
++ MV_SWITCH_ID_DEV_EXPECTATION,
++ switchID));
++ return;
++ }
++
++ MV_PRINT(MV_DEBUG_PHYSETUP,
++ ("Found PHY switch for enet %d port %d deviceID 0x%x revision 0x%x\n",
++ ethUnit,
++ phyUnit,
++ (switchID & MV_SWITCH_ID_DEV_MASK) >> MV_SWITCH_ID_DEV_SHIFT,
++ (switchID & MV_SWITCH_ID_REV_MASK) >> MV_SWITCH_ID_REV_SHIFT))
++ }
++
++ /*******************************/
++ /* Verify that switch is ready */
++ /*******************************/
++ if (phyBase) {
++ globalStatus = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR,
++ MV_SWITCH_GLOBAL_STATUS);
++
++ if (!(globalStatus & MV_SWITCH_STATUS_READY_MASK)) {
++ MV_PRINT(MV_DEBUG_PHYSETUP,
++ ("PHY switch for ethmac%d NOT ready!\n",
++ ethUnit));
++ }
++ } else {
++ MV_PRINT(MV_DEBUG_PHYSETUP,
++ ("No ports configured for ethmac%d\n", ethUnit));
++ }
++}
++
++/******************************************************************************
++*
++* mv_phySetup - reset and setup the PHY switch.
++*
++* Resets each PHY port.
++*
++* RETURNS:
++* TRUE --> at least 1 PHY with LINK
++* FALSE --> no LINKs on this ethernet unit
++*/
++BOOL
++mv_phySetup(int ethUnit, UINT32 phyBase)
++{
++ int phyUnit;
++ int liveLinks = 0;
++ BOOL foundPhy = FALSE;
++ UINT32 phyAddr;
++ UINT16 atuControl;
++
++ /*
++ * Allow platform-specific code to determine the default Ethernet MAC
++ * at run-time. If phyEthMacDefault returns a negative value, use the
++ * static mvPhyInfo table "as is". But if phyEthMacDefault returns a
++ * non-negative value, use it as the default ethernet unit.
++ */
++ {
++ int ethMacDefault = phyEthMacDefault();
++
++ if (ethMacDefault >= 0) {
++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
++ MV_ETHUNIT(phyUnit)=ethMacDefault;
++ }
++ }
++ }
++
++ /*
++ * See if there's any configuration data for this enet,
++ * and set up phyBase in table.
++ */
++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
++ if (MV_ETHUNIT(phyUnit) != ethUnit) {
++ continue;
++ }
++
++ MV_PHYBASE(phyUnit) = phyBase;
++ foundPhy = TRUE;
++ }
++
++ if (!foundPhy) {
++ return FALSE; /* No PHY's configured for this ethUnit */
++ }
++
++ /* Verify that the switch is what we think it is, and that it's ready */
++ mv_verifyReady(ethUnit);
++
++ /* Initialize global switch settings */
++ atuControl = MV_ATUCTRL_AGE_TIME_DEFAULT << MV_ATUCTRL_AGE_TIME_SHIFT;
++ atuControl |= MV_ATUCTRL_ATU_SIZE_DEFAULT << MV_ATUCTRL_ATU_SIZE_SHIFT;
++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_CONTROL, atuControl);
++
++ /* Reset PHYs and start autonegoation on each. */
++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
++ if (MV_ETHUNIT(phyUnit) != ethUnit) {
++ continue;
++ }
++
++ phyBase = MV_PHYBASE(phyUnit);
++ phyAddr = MV_PHYADDR(phyUnit);
++
++ phyRegWrite(phyBase, phyAddr, MV_PHY_CONTROL,
++ MV_CTRL_SOFTWARE_RESET | MV_CTRL_AUTONEGOTIATION_ENABLE);
++ }
++
++#if 0 /* Don't wait -- we'll detect shortly after the link comes up */
++{
++ int timeout;
++ UINT16 phyHwStatus;
++
++ /*
++ * Wait 5 seconds for ALL associated PHYs to finish autonegotiation.
++ */
++ timeout=50;
++ for (phyUnit=0; (phyUnit < MV_PHY_MAX) && (timeout > 0); phyUnit++) {
++ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++ for (;;) {
++ phyBase = MV_PHYBASE(phyUnit);
++ phyAddr = MV_PHYADDR(phyUnit);
++
++ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS);
++
++ if (MV_AUTONEG_DONE(phyHwStatus)) {
++ break;
++ }
++
++ if (--timeout == 0) {
++ break;
++ }
++
++ sysMsDelay(100);
++ }
++ }
++}
++#endif
++
++ /*
++ * All PHYs have had adequate time to autonegotiate.
++ * Now initialize software status.
++ *
++ * It's possible that some ports may take a bit longer
++ * to autonegotiate; but we can't wait forever. They'll
++ * get noticed by mv_phyCheckStatusChange during regular
++ * polling activities.
++ */
++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
++ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++
++ if (mv_phyIsLinkAlive(phyUnit)) {
++ liveLinks++;
++ MV_IS_PHY_ALIVE(phyUnit) = TRUE;
++ } else {
++ MV_IS_PHY_ALIVE(phyUnit) = FALSE;
++ }
++
++ MV_PRINT(MV_DEBUG_PHYSETUP,
++ ("ethmac%d: Phy Status=%4.4x\n",
++ ethUnit,
++ phyRegRead(MV_PHYBASE(phyUnit),
++ MV_PHYADDR(phyUnit),
++ MV_PHY_SPECIFIC_STATUS)));
++ }
++
++ mv_VLANInit(ethUnit);
++
++ mv_enableConfiguredPorts(ethUnit);
++
++ return (liveLinks > 0);
++}
++
++
++/******************************************************************************
++*
++* mv_phyIsDuplexFull - Determines whether the phy ports associated with the
++* specified device are FULL or HALF duplex.
++*
++* RETURNS:
++* 1 --> at least one associated PHY in FULL DUPLEX
++* 0 --> all half duplex
++* -1 --> No links
++*/
++int
++mv_phyIsFullDuplex(int ethUnit)
++{
++ int phyUnit;
++ UINT32 phyBase;
++ UINT32 phyAddr;
++ UINT16 phyHwStatus;
++ int oneIsReady=0;
++
++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
++ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++
++ if (mv_phyIsLinkAlive(phyUnit)) {
++ oneIsReady = 1;
++
++ phyBase = MV_PHYBASE(phyUnit);
++ phyAddr = MV_PHYADDR(phyUnit);
++
++ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS);
++
++ if (phyHwStatus & MV_STATUS_RESOLVED_DUPLEX_FULL) {
++ return 1;
++ }
++ }
++ }
++ if (oneIsReady)
++ return 0;
++ else
++ return -1;
++}
++
++/******************************************************************************
++*
++* mv_phyIsSpeed100 - Determines the speed of a phy port
++*
++* RETURNS:
++* TRUE --> PHY operating at 100 Mbit
++* FALSE --> link down, or not operating at 100 Mbit
++*/
++BOOL
++mv_phyIsSpeed100(int phyUnit)
++{
++ UINT16 phyHwStatus;
++ UINT32 phyBase;
++ UINT32 phyAddr;
++
++ if (MV_IS_ENET_PORT(phyUnit)) {
++ if (mv_phyIsLinkAlive(phyUnit)) {
++
++ phyBase = MV_PHYBASE(phyUnit);
++ phyAddr = MV_PHYADDR(phyUnit);
++
++ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS);
++
++ if (phyHwStatus & MV_STATUS_RESOLVED_SPEED_100) {
++ return TRUE;
++ }
++ }
++ }
++
++ return FALSE;
++}
++
++#if CONFIG_VENETDEV
++/******************************************************************************
++*
++* mv_phyDetermineSource - Examine a received frame's Egress Trailer
++* to determine whether it came from a LAN or WAN port.
++*
++* RETURNS:
++* Sets *pFromLAN: 1-->LAN, 0-->WAN
++* Modifies *pLen to remove PHY trailer from frame
++*/
++void
++mv_phyDetermineSource(char *data, int len, int *pFromLAN)
++{
++ unsigned char *phyTrailer;
++ unsigned char incomingPort;
++
++ phyTrailer = &data[len - MV_PHY_TRAILER_SIZE];
++ ASSERT(phyTrailer[0] == MV_EGRESS_TRAILER_VALID);
++
++ incomingPort = phyTrailer[1];
++ if (MV_IS_LAN_PORT(incomingPort)) {
++ *pFromLAN = 1;
++ } else {
++ ASSERT(MV_IS_WAN_PORT(incomingPort));
++ *pFromLAN = 0;
++ }
++}
++
++
++/******************************************************************************
++*
++* mv_phySetDestinationPort - Set the Ingress Trailer to force the
++* frame to be sent to LAN or WAN, as specified.
++*
++*/
++void
++mv_phySetDestinationPort(char *data, int len, int fromLAN)
++{
++ char *phyTrailer;
++
++ phyTrailer = &data[len];
++ if (fromLAN) {
++ /* LAN ports: Use default settings, as per mvPhyInfo */
++ phyTrailer[0] = 0x00;
++ phyTrailer[1] = 0x00;
++ } else {
++ /* WAN port: Direct to WAN port */
++ phyTrailer[0] = MV_INGRESS_TRAILER_OVERRIDE;
++ phyTrailer[1] = 1 << MV_WAN_PORT;
++ }
++ phyTrailer[2] = 0x00;
++ phyTrailer[3] = 0x00;
++}
++#endif
++
++
++/*****************************************************************************
++*
++* Validate that the specified PHY unit number is a valid PHY ID.
++* Print a message if it is invalid.
++* RETURNS
++* TRUE --> valid
++* FALSE --> invalid
++*/
++LOCAL BOOL
++mv_validPhyId(int phyUnit)
++{
++ if ((phyUnit >= MV_ID_MIN) && (phyUnit <= MV_ID_MAX)) {
++ return TRUE;
++ } else {
++ PRINTF("PHY unit number must be in the range [%d..%d]\n",
++ MV_ID_MIN, MV_ID_MAX);
++ return FALSE;
++ }
++}
++
++
++/*****************************************************************************
++*
++* mv_waitWhileATUBusy - spins until the ATU completes
++* its previous operation.
++*/
++LOCAL void
++mv_waitWhileATUBusy(UINT32 phyBase)
++{
++ BOOL isBusy;
++ UINT16 ATUOperation;
++
++ do {
++
++ ATUOperation = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR,
++ MV_ATU_OPERATION);
++
++ isBusy = (ATUOperation & MV_ATU_BUSY_MASK) == MV_ATU_IS_BUSY;
++
++ } while(isBusy);
++}
++
++/*****************************************************************************
++*
++* mv_flushATUDB - flushes ALL entries in the Address Translation Unit
++* DataBase associated with phyUnit. [Since we use a single DB for
++* all PHYs, this flushes the entire shared DataBase.]
++*
++* The current implementation flushes even more than absolutely needed --
++* it flushes all entries for all phyUnits on the same ethernet as the
++* specified phyUnit.
++*
++* It is called only when a link failure is detected on a port that was
++* previously working. In other words, when the cable is unplugged.
++*/
++void
++mv_flushATUDB(int phyUnit)
++{
++ UINT32 phyBase;
++
++ if (!mv_validPhyId(phyUnit)) {
++ PRINTF("Invalid port number: %d\n", phyUnit);
++ return;
++ }
++
++ phyBase = MV_PHYBASE(phyUnit);
++
++ /* Wait for previous operation (if any) to complete */
++ mv_waitWhileATUBusy(phyBase);
++
++ /* Tell hardware to flush all entries */
++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_OPERATION,
++ MV_ATU_OP_FLUSH_ALL | MV_ATU_IS_BUSY);
++
++ mv_waitWhileATUBusy(phyBase);
++}
++
++/*****************************************************************************
++*
++* mv_phyCheckStatusChange -- checks for significant changes in PHY state.
++*
++* A "significant change" is:
++* dropped link (e.g. ethernet cable unplugged) OR
++* autonegotiation completed + link (e.g. ethernet cable plugged in)
++*/
++void
++mv_phyCheckStatusChange(int ethUnit)
++{
++ int phyUnit;
++ UINT16 phyHwStatus;
++ mvPhyInfo_t *lastStatus;
++ int linkCount = 0;
++ int lostLinks = 0;
++ int gainedLinks = 0;
++ UINT32 phyBase;
++ UINT32 phyAddr;
++
++ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
++ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++
++ phyBase = MV_PHYBASE(phyUnit);
++ phyAddr = MV_PHYADDR(phyUnit);
++
++ lastStatus = &mvPhyInfo[phyUnit];
++ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS);
++
++ if (lastStatus->isPhyAlive) { /* last known link status was ALIVE */
++ /* See if we've lost link */
++ if (phyHwStatus & MV_STATUS_REAL_TIME_LINK_UP) {
++ linkCount++;
++ } else {
++ lostLinks++;
++ mv_flushATUDB(phyUnit);
++ MV_PRINT(MV_DEBUG_PHYCHANGE,("\nethmac%d port%d down\n",
++ ethUnit, phyUnit));
++ lastStatus->isPhyAlive = FALSE;
++ }
++ } else { /* last known link status was DEAD */
++ /* Check for AutoNegotiation complete */
++ if (MV_AUTONEG_DONE(phyHwStatus)) {
++ gainedLinks++;
++ linkCount++;
++ MV_PRINT(MV_DEBUG_PHYCHANGE,("\nethmac%d port%d up\n",
++ ethUnit, phyUnit));
++ lastStatus->isPhyAlive = TRUE;
++ }
++ }
++ }
++
++ if (linkCount == 0) {
++ if (lostLinks) {
++ /* We just lost the last link for this MAC */
++ phyLinkLost(ethUnit);
++ }
++ } else {
++ if (gainedLinks == linkCount) {
++ /* We just gained our first link(s) for this MAC */
++ phyLinkGained(ethUnit);
++ }
++ }
++}
++
++#if DEBUG
++
++/* Define the registers of interest for a phyShow command */
++typedef struct mvRegisterTableEntry_s {
++ UINT32 regNum;
++ char *regIdString;
++} mvRegisterTableEntry_t;
++
++mvRegisterTableEntry_t mvPhyRegisterTable[] = {
++ {MV_PHY_CONTROL, "PHY Control "},
++ {MV_PHY_STATUS, "PHY Status "},
++ {MV_PHY_ID1, "PHY Identifier 1 "},
++ {MV_PHY_ID2, "PHY Identifier 2 "},
++ {MV_AUTONEG_ADVERT, "Auto-Negotiation Advertisement "},
++ {MV_LINK_PARTNER_ABILITY, "Link Partner Ability "},
++ {MV_AUTONEG_EXPANSION, "Auto-Negotiation Expansion "},
++ {MV_NEXT_PAGE_TRANSMIT, "Next Page Transmit "},
++ {MV_LINK_PARTNER_NEXT_PAGE, "Link Partner Next Page "},
++ {MV_PHY_SPECIFIC_CONTROL_1, "PHY-Specific Control Register 1 "},
++ {MV_PHY_SPECIFIC_STATUS, "PHY-Specific Status "},
++ {MV_PHY_INTERRUPT_ENABLE, "PHY Interrupt Enable "},
++ {MV_PHY_INTERRUPT_STATUS, "PHY Interrupt Status "},
++ {MV_PHY_INTERRUPT_PORT_SUMMARY, "PHY Interrupt Port Summary "},
++ {MV_RECEIVE_ERROR_COUNTER, "Receive Error Counter "},
++ {MV_LED_PARALLEL_SELECT, "LED Parallel Select "},
++ {MV_LED_STREAM_SELECT_LEDS, "LED Stream Select "},
++ {MV_PHY_LED_CONTROL, "PHY LED Control "},
++ {MV_PHY_MANUAL_LED_OVERRIDE, "PHY Manual LED Override "},
++ {MV_VCT_CONTROL, "VCT Control "},
++ {MV_VCT_STATUS, "VCT Status "},
++ {MV_PHY_SPECIFIC_CONTROL_2, "PHY-Specific Control Register 2 "},
++};
++int mvPhyNumRegs = sizeof(mvPhyRegisterTable) / sizeof(mvPhyRegisterTable[0]);
++
++
++mvRegisterTableEntry_t mvSwitchPortRegisterTable[] = {
++ {MV_PORT_STATUS, "Port Status "},
++ {MV_SWITCH_ID, "Switch ID "},
++ {MV_PORT_CONTROL, "Port Control "},
++ {MV_PORT_BASED_VLAN_MAP, "Port-Based VLAN Map "},
++ {MV_PORT_ASSOCIATION_VECTOR, "Port Association Vector "},
++ {MV_RX_COUNTER, "RX Counter "},
++ {MV_TX_COUNTER, "TX Counter "},
++};
++int mvSwitchPortNumRegs =
++ sizeof(mvSwitchPortRegisterTable) / sizeof(mvSwitchPortRegisterTable[0]);
++
++
++mvRegisterTableEntry_t mvSwitchGlobalRegisterTable[] = {
++ {MV_SWITCH_GLOBAL_STATUS, "Switch Global Status "},
++ {MV_SWITCH_MAC_ADDR0, "Switch MAC Addr 0 & 1 "},
++ {MV_SWITCH_MAC_ADDR2, "Switch MAC Addr 2 & 3 "},
++ {MV_SWITCH_MAC_ADDR4, "Switch MAC Addr 4 & 5 "},
++ {MV_SWITCH_GLOBAL_CONTROL, "Switch Global Control "},
++ {MV_ATU_CONTROL, "ATU Control "},
++ {MV_ATU_OPERATION, "ATU Operation "},
++ {MV_ATU_DATA, "ATU Data "},
++ {MV_ATU_MAC_ADDR0, "ATU MAC Addr 0 & 1 "},
++ {MV_ATU_MAC_ADDR2, "ATU MAC Addr 2 & 3 "},
++ {MV_ATU_MAC_ADDR4, "ATU MAC Addr 4 & 5 "},
++};
++int mvSwitchGlobalNumRegs =
++ sizeof(mvSwitchGlobalRegisterTable) / sizeof(mvSwitchGlobalRegisterTable[0]);
++
++void my_mvPhyShow(int ethUnit)
++{
++ int phyUnit;
++ for (phyUnit=0; (phyUnit < MV_PHY_MAX); phyUnit++) {
++ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) {
++ continue;
++ }
++ mv_phyShow(phyUnit);
++ }
++}
++
++/*****************************************************************************
++*
++* mv_phyShow - Dump the state of a PHY.
++* There are two sets of registers for each phy port:
++* "phy registers" and
++* "switch port registers"
++* We dump 'em all, plus the switch global registers.
++*/
++void
++mv_phyShow(int phyUnit)
++{
++ int i;
++ UINT16 value;
++ UINT32 phyBase;
++ UINT32 phyAddr;
++ UINT32 switchPortAddr;
++
++ if (!mv_validPhyId(phyUnit)) {
++ return;
++ }
++
++ phyBase = MV_PHYBASE(phyUnit);
++ phyAddr = MV_PHYADDR(phyUnit);
++ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit);
++
++ printk("PHY state for PHY%d (ethmac%d, phyBase 0x%8x, phyAddr 0x%x, switchAddr 0x%x)\n",
++ phyUnit,
++ MV_ETHUNIT(phyUnit),
++ MV_PHYBASE(phyUnit),
++ MV_PHYADDR(phyUnit),
++ MV_SWITCH_PORT_ADDR(phyUnit));
++
++ printk("PHY Registers:\n");
++ for (i=0; i < mvPhyNumRegs; i++) {
++
++ value = phyRegRead(phyBase, phyAddr, mvPhyRegisterTable[i].regNum);
++
++ printk("Reg %02d (0x%02x) %s = 0x%08x\n",
++ mvPhyRegisterTable[i].regNum,
++ mvPhyRegisterTable[i].regNum,
++ mvPhyRegisterTable[i].regIdString,
++ value);
++ }
++
++ printk("Switch Port Registers:\n");
++ for (i=0; i < mvSwitchPortNumRegs; i++) {
++
++ value = phyRegRead(phyBase, switchPortAddr,
++ mvSwitchPortRegisterTable[i].regNum);
++
++ printk("Reg %02d (0x%02x) %s = 0x%08x\n",
++ mvSwitchPortRegisterTable[i].regNum,
++ mvSwitchPortRegisterTable[i].regNum,
++ mvSwitchPortRegisterTable[i].regIdString,
++ value);
++ }
++
++ printk("Switch Global Registers:\n");
++ for (i=0; i < mvSwitchGlobalNumRegs; i++) {
++
++ value = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR,
++ mvSwitchGlobalRegisterTable[i].regNum);
++
++ printk("Reg %02d (0x%02x) %s = 0x%08x\n",
++ mvSwitchGlobalRegisterTable[i].regNum,
++ mvSwitchGlobalRegisterTable[i].regNum,
++ mvSwitchGlobalRegisterTable[i].regIdString,
++ value);
++ }
++}
++
++/*****************************************************************************
++*
++* mv_phySet - Modify the value of a PHY register (debug only).
++*/
++void
++mv_phySet(int phyUnit, UINT32 regnum, UINT32 value)
++{
++ UINT32 phyBase;
++ UINT32 phyAddr;
++
++ if (mv_validPhyId(phyUnit)) {
++
++ phyBase = MV_PHYBASE(phyUnit);
++ phyAddr = MV_PHYADDR(phyUnit);
++
++ phyRegWrite(phyBase, phyAddr, regnum, value);
++ }
++}
++
++
++/*****************************************************************************
++*
++* mv_switchPortSet - Modify the value of a switch port register (debug only).
++*/
++void
++mv_switchPortSet(int phyUnit, UINT32 regnum, UINT32 value)
++{
++ UINT32 phyBase;
++ UINT32 switchPortAddr;
++
++ if (mv_validPhyId(phyUnit)) {
++
++ phyBase = MV_PHYBASE(phyUnit);
++ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit);
++
++ phyRegWrite(phyBase, switchPortAddr, regnum, value);
++ }
++}
++
++/*****************************************************************************
++*
++* mv_switchGlobalSet - Modify the value of a switch global register
++* (debug only).
++*/
++void
++mv_switchGlobalSet(int phyUnit, UINT32 regnum, UINT32 value)
++{
++ UINT32 phyBase;
++
++ if (mv_validPhyId(phyUnit)) {
++
++ phyBase = MV_PHYBASE(phyUnit);
++
++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, regnum, value);
++ }
++}
++
++/*****************************************************************************
++*
++* mv_showATUDB - Dump the contents of the Address Translation Unit DataBase
++* for the PHY switch associated with the specified phy.
++*/
++void
++mv_showATUDB(int phyUnit)
++{
++ UINT32 phyBase;
++ UINT16 ATUData;
++ UINT16 ATUMac0;
++ UINT16 ATUMac2;
++ UINT16 ATUMac4;
++ int portVec;
++ int entryState;
++
++ if (!mv_validPhyId(phyUnit)) {
++ printk("Invalid port number: %d\n", phyUnit);
++ return;
++ }
++
++ phyBase = MV_PHYBASE(phyUnit);
++
++ /* Wait for previous operation (if any) to complete */
++ mv_waitWhileATUBusy(phyBase);
++
++ /* Initialize ATU MAC to all 1's */
++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR0, 0xffff);
++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR2, 0xffff);
++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR4, 0xffff);
++
++ printk(" MAC ADDRESS EntryState PortVector\n");
++
++ for(;;) {
++ /* Tell hardware to get next MAC info */
++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_OPERATION,
++ MV_ATU_OP_GET_NEXT | MV_ATU_IS_BUSY);
++
++ mv_waitWhileATUBusy(phyBase);
++
++ ATUData = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_DATA);
++ entryState = (ATUData & MV_ENTRYSTATE_MASK) >> MV_ENTRYSTATE_SHIFT;
++
++ if (entryState == 0) {
++ /* We've hit the end of the list */
++ break;
++ }
++
++ ATUMac0 = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR0);
++ ATUMac2 = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR2);
++ ATUMac4 = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR4);
++
++ portVec = (ATUData & MV_PORTVEC_MASK) >> MV_PORTVEC_SHIFT;
++
++ printk("%02x:%02x:%02x:%02x:%02x:%02x 0x%02x 0x%02x\n",
++ ATUMac0 >> 8, /* MAC byte 0 */
++ ATUMac0 & 0xff, /* MAC byte 1 */
++ ATUMac2 >> 8, /* MAC byte 2 */
++ ATUMac2 & 0xff, /* MAC byte 3 */
++ ATUMac4 >> 8, /* MAC byte 4 */
++ ATUMac4 & 0xff, /* MAC byte 5 */
++ entryState,
++ portVec);
++ }
++}
++
++LOCAL BOOL countingGoodFrames;
++
++/*****************************************************************************
++*
++* mv_countGoodFrames - starts counting GOOD RX/TX frames per port
++*/
++void
++mv_countGoodFrames(int phyUnit)
++{
++ UINT32 phyBase;
++ UINT16 globalControl;
++
++ if (mv_validPhyId(phyUnit)) {
++ /*
++ * Guarantee that counters are cleared by
++ * forcing CtrMode to toggle and end on GOODFRAMES.
++ */
++
++ phyBase = MV_PHYBASE(phyUnit);
++
++ /* Read current Switch Global Control Register */
++ globalControl = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR,
++ MV_SWITCH_GLOBAL_CONTROL);
++
++ /* Set CtrMode to count BAD frames */
++ globalControl = ((globalControl & ~MV_CTRMODE_MASK) |
++ MV_CTRMODE_BADFRAMES);
++
++ /* Push new value out to hardware */
++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR,
++ MV_SWITCH_GLOBAL_CONTROL, globalControl);
++
++ /* Now toggle CtrMode to count GOOD frames */
++ globalControl = ((globalControl & ~MV_CTRMODE_MASK) |
++ MV_CTRMODE_GOODFRAMES);
++
++ /* Push new value out to hardware */
++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR,
++ MV_SWITCH_GLOBAL_CONTROL, globalControl);
++
++ countingGoodFrames = TRUE;
++ }
++}
++
++/*****************************************************************************
++*
++* mv_countBadFrames - starts counting BAD RX/TX frames per port
++*/
++void
++mv_countBadFrames(int phyUnit)
++{
++ UINT32 phyBase;
++ UINT16 globalControl;
++
++ if (mv_validPhyId(phyUnit)) {
++ /*
++ * Guarantee that counters are cleared by
++ * forcing CtrMode to toggle and end on BADFRAMES.
++ */
++
++ phyBase = MV_PHYBASE(phyUnit);
++
++ /* Read current Switch Global Control Register */
++ globalControl = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR,
++ MV_SWITCH_GLOBAL_CONTROL);
++
++ /* Set CtrMode to count GOOD frames */
++ globalControl = ((globalControl & ~MV_CTRMODE_MASK) |
++ MV_CTRMODE_GOODFRAMES);
++
++ /* Push new value out to hardware */
++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR,
++ MV_SWITCH_GLOBAL_CONTROL, globalControl);
++
++ /* Now toggle CtrMode to count BAD frames */
++ globalControl = ((globalControl & ~MV_CTRMODE_MASK) |
++ MV_CTRMODE_BADFRAMES);
++
++ /* Push new value out to hardware */
++ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR,
++ MV_SWITCH_GLOBAL_CONTROL, globalControl);
++
++ countingGoodFrames = FALSE;
++ }
++}
++
++/*****************************************************************************
++*
++* mv_showFrameCounts - shows current GOOD/BAD Frame counts
++*/
++void
++mv_showFrameCounts(int phyUnit)
++{
++ UINT16 rxCounter;
++ UINT16 txCounter;
++ UINT32 phyBase;
++ UINT32 switchPortAddr;
++
++ if (!mv_validPhyId(phyUnit)) {
++ return;
++ }
++
++ phyBase = MV_PHYBASE(phyUnit);
++ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit);
++
++ rxCounter = phyRegRead(phyBase, switchPortAddr, MV_RX_COUNTER);
++
++ txCounter = phyRegRead(phyBase, switchPortAddr, MV_TX_COUNTER);
++
++ printk("port%d %s frames: receive: %05d transmit: %05d\n",
++ phyUnit,
++ (countingGoodFrames ? "good" : "error"),
++ rxCounter,
++ txCounter);
++}
++#endif
+diff -urN linux-mips-orig/drivers/net/ath/mvPhy.h linux-mips-new/drivers/net/ath/mvPhy.h
+--- linux-mips-orig/drivers/net/ath/mvPhy.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/mvPhy.h 2005-12-31 12:33:57.727530616 +0000
+@@ -0,0 +1,162 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * mvPhy.h - definitions for the ethernet PHY -- Marvell 88E6060
++ * All definitions in this file are operating system independent!
++ */
++
++#ifndef MVPHY_H
++#define MVPHY_H
++
++/*****************/
++/* PHY Registers */
++/*****************/
++#define MV_PHY_CONTROL 0
++#define MV_PHY_STATUS 1
++#define MV_PHY_ID1 2
++#define MV_PHY_ID2 3
++#define MV_AUTONEG_ADVERT 4
++#define MV_LINK_PARTNER_ABILITY 5
++#define MV_AUTONEG_EXPANSION 6
++#define MV_NEXT_PAGE_TRANSMIT 7
++#define MV_LINK_PARTNER_NEXT_PAGE 8
++#define MV_PHY_SPECIFIC_CONTROL_1 16
++#define MV_PHY_SPECIFIC_STATUS 17
++#define MV_PHY_INTERRUPT_ENABLE 18
++#define MV_PHY_INTERRUPT_STATUS 19
++#define MV_PHY_INTERRUPT_PORT_SUMMARY 20
++#define MV_RECEIVE_ERROR_COUNTER 21
++#define MV_LED_PARALLEL_SELECT 22
++#define MV_LED_STREAM_SELECT_LEDS 23
++#define MV_PHY_LED_CONTROL 24
++#define MV_PHY_MANUAL_LED_OVERRIDE 25
++
++#define MV_VCT_CONTROL 26
++#define MV_VCT_STATUS 27
++#define MV_PHY_SPECIFIC_CONTROL_2 28
++
++/* MV_PHY_CONTROL fields */
++#define MV_CTRL_SOFTWARE_RESET 0x8000
++#define MV_CTRL_AUTONEGOTIATION_ENABLE 0x1000
++#define MV_CTRL_FULL_DUPLEX 0x0100
++#define MV_CTRL_100_MBPS 0x2000
++
++/* MV_PHY_ID1 fields */
++#define MV_PHY_ID1_EXPECTATION 0x0141 /* OUI >> 6 */
++
++/* MV_PHY_ID2 fields */
++#define MV_OUI_LSB_MASK 0xfc00
++#define MV_OUI_LSB_EXPECTATION 0x0c00
++#define MV_OUI_LSB_SHIFT 10
++#define MV_MODEL_NUM_MASK 0x03f0
++#define MV_MODEL_NUM_SHIFT 4
++#define MV_REV_NUM_MASK 0x000f
++#define MV_REV_NUM_SHIFT 0
++
++/* MV_PHY_SPECIFIC_STATUS fields */
++#define MV_STATUS_RESOLVED_SPEED_100 0x4000
++#define MV_STATUS_RESOLVED_DUPLEX_FULL 0x2000
++#define MV_STATUS_RESOLVED 0x0800
++#define MV_STATUS_REAL_TIME_LINK_UP 0x0400
++
++/* Check if autonegotiation is complete and link is up */
++#define MV_AUTONEG_DONE(mv_phy_specific_status) \
++ (((mv_phy_specific_status) & \
++ (MV_STATUS_RESOLVED | MV_STATUS_REAL_TIME_LINK_UP)) == \
++ (MV_STATUS_RESOLVED | MV_STATUS_REAL_TIME_LINK_UP))
++
++
++/*************************/
++/* Switch Port Registers */
++/*************************/
++#define MV_PORT_STATUS 0
++#define MV_SWITCH_ID 3
++#define MV_PORT_CONTROL 4
++#define MV_PORT_BASED_VLAN_MAP 6
++#define MV_PORT_ASSOCIATION_VECTOR 11
++#define MV_RX_COUNTER 16
++#define MV_TX_COUNTER 17
++
++/* MV_SWITCH_ID fields */
++#define MV_SWITCH_ID_DEV_MASK 0xfff0
++#define MV_SWITCH_ID_DEV_EXPECTATION 0x0600
++#define MV_SWITCH_ID_DEV_SHIFT 4
++#define MV_SWITCH_ID_REV_MASK 0x000f
++#define MV_SWITCH_ID_REV_SHIFT 0
++
++/* MV_PORT_CONTROL fields */
++#define MV_PORT_CONTROL_PORT_STATE_MASK 0x0003
++#define MV_PORT_CONTROL_PORT_STATE_DISABLED 0x0000
++#define MV_PORT_CONTROL_PORT_STATE_FORWARDING 0x0003
++
++#define MV_PORT_CONTROL_EGRESS_MODE 0x0100 /* Receive */
++#define MV_PORT_CONTROL_INGRESS_TRAILER 0x4000 /* Transmit */
++
++#define MV_EGRESS_TRAILER_VALID 0x80
++#define MV_INGRESS_TRAILER_OVERRIDE 0x80
++
++#define MV_PHY_TRAILER_SIZE 4
++
++
++/***************************/
++/* Switch Global Registers */
++/***************************/
++#define MV_SWITCH_GLOBAL_STATUS 0
++#define MV_SWITCH_MAC_ADDR0 1
++#define MV_SWITCH_MAC_ADDR2 2
++#define MV_SWITCH_MAC_ADDR4 3
++#define MV_SWITCH_GLOBAL_CONTROL 4
++#define MV_ATU_CONTROL 10
++#define MV_ATU_OPERATION 11
++#define MV_ATU_DATA 12
++#define MV_ATU_MAC_ADDR0 13
++#define MV_ATU_MAC_ADDR2 14
++#define MV_ATU_MAC_ADDR4 15
++
++/* MV_SWITCH_GLOBAL_STATUS fields */
++#define MV_SWITCH_STATUS_READY_MASK 0x0800
++
++/* MV_SWITCH_GLOBAL_CONTROL fields */
++#define MV_CTRMODE_MASK 0x0100
++#define MV_CTRMODE_GOODFRAMES 0x0000
++#define MV_CTRMODE_BADFRAMES 0x0100
++
++/* MV_ATU_CONTROL fields */
++#define MV_ATUCTRL_ATU_SIZE_MASK 0x3000
++#define MV_ATUCTRL_ATU_SIZE_SHIFT 12
++#define MV_ATUCTRL_ATU_SIZE_DEFAULT 2 /* 1024 entry database */
++#define MV_ATUCTRL_AGE_TIME_MASK 0x0ff0
++#define MV_ATUCTRL_AGE_TIME_SHIFT 4
++#define MV_ATUCTRL_AGE_TIME_DEFAULT 19 /* 19 * 16 = 304 seconds */
++
++/* MV_ATU_OPERATION fields */
++#define MV_ATU_BUSY_MASK 0x8000
++#define MV_ATU_IS_BUSY 0x8000
++#define MV_ATU_IS_FREE 0x0000
++#define MV_ATU_OP_MASK 0x7000
++#define MV_ATU_OP_FLUSH_ALL 0x1000
++#define MV_ATU_OP_GET_NEXT 0x4000
++
++/* MV_ATU_DATA fields */
++#define MV_ENTRYPRI_MASK 0xc000
++#define MV_ENTRYPRI_SHIFT 14
++#define MV_PORTVEC_MASK 0x03f0
++#define MV_PORTVEC_SHIFT 4
++#define MV_ENTRYSTATE_MASK 0x000f
++#define MV_ENTRYSTATE_SHIFT 0
++
++/* PHY Address for the switch itself */
++#define MV_SWITCH_GLOBAL_ADDR 0x1f
++
++BOOL mv_phySetup(int ethUnit, UINT32 phyBase);
++void mv_phyCheckStatusChange(int ethUnit);
++BOOL mv_phyIsSpeed100(int ethUnit);
++int mv_phyIsFullDuplex(int ethUnit);
++
++#endif /* MVPHY_H */
+diff -urN linux-mips-orig/drivers/net/ath/rtPhy.c linux-mips-new/drivers/net/ath/rtPhy.c
+--- linux-mips-orig/drivers/net/ath/rtPhy.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/rtPhy.c 2005-12-31 12:33:57.727530616 +0000
+@@ -0,0 +1,272 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * Manage the ethernet PHY.
++ * This code supports a simple 1-port ethernet phy, Realtek RTL8201BL,
++ * and compatible PHYs, such as the Kendin KS8721B.
++ * All definitions in this file are operating system independent!
++ */
++
++#if defined(linux)
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/delay.h>
++
++#include "ar531xlnx.h"
++#endif
++
++#if defined(__ECOS)
++#include "ae531xecos.h"
++#endif
++
++
++#include "ae531xmac.h"
++#include "ae531xreg.h"
++#include "rtPhy.h"
++
++#if /* DEBUG */ 1
++#define RT_DEBUG_ERROR 0x00000001
++#define RT_DEBUG_PHYSETUP 0x00000002
++#define RT_DEBUG_PHYCHANGE 0x00000004
++
++int rtPhyDebug = RT_DEBUG_ERROR;
++
++#define RT_PRINT(FLG, X) \
++{ \
++ if (rtPhyDebug & (FLG)) { \
++ DEBUG_PRINTF X; \
++ } \
++}
++#else
++#define RT_PRINT(FLG, X)
++#endif
++
++/*
++ * Track per-PHY port information.
++ */
++typedef struct {
++ BOOL phyAlive; /* last known state of link */
++ UINT32 phyBase;
++ UINT32 phyAddr;
++} rtPhyInfo_t;
++
++#define ETH_PHY_ADDR 1
++
++/*
++ * This table defines the mapping from phy units to
++ * per-PHY information.
++ *
++ * This table is somewhat board-dependent.
++ */
++rtPhyInfo_t rtPhyInfo[] = {
++ {phyAlive: FALSE, /* PHY 0 */
++ phyBase: 0, /* filled in by rt_phySetup */
++ phyAddr: ETH_PHY_ADDR},
++
++ {phyAlive: FALSE, /* PHY 1 */
++ phyBase: 0, /* filled in by rt_phySetup */
++ phyAddr: ETH_PHY_ADDR}
++};
++
++/* Convert from phy unit# to (phyBase, phyAddr) pair */
++#define RT_PHYBASE(phyUnit) (rtPhyInfo[phyUnit].phyBase)
++#define RT_PHYADDR(phyUnit) (rtPhyInfo[phyUnit].phyAddr)
++
++
++/******************************************************************************
++*
++* rt_phySetup - reset and setup the PHY associated with
++* the specified MAC unit number.
++*
++* Resets the associated PHY port.
++*
++* RETURNS:
++* TRUE --> associated PHY is alive
++* FALSE --> no LINKs on this ethernet unit
++*/
++
++BOOL
++rt_phySetup(int ethUnit, UINT32 phyBase)
++{
++ BOOL linkAlive = FALSE;
++ UINT32 phyAddr;
++
++ RT_PHYBASE(ethUnit) = phyBase;
++
++ phyAddr = RT_PHYADDR(ethUnit);
++
++ /* Reset phy */
++ phyRegWrite(phyBase, phyAddr, GEN_ctl, PHY_SW_RST | AUTONEGENA);
++
++ sysMsDelay(1500);
++
++ return linkAlive;
++}
++
++/******************************************************************************
++*
++* rt_phyIsDuplexFull - Determines whether the phy ports associated with the
++* specified device are FULL or HALF duplex.
++*
++* RETURNS:
++* 1 --> FULL
++* 0 --> HALF
++*/
++int
++rt_phyIsFullDuplex(int ethUnit)
++{
++ UINT16 phyCtl;
++ UINT32 phyBase;
++ UINT32 phyAddr;
++
++ phyBase = RT_PHYBASE(ethUnit);
++ phyAddr = RT_PHYADDR(ethUnit);
++
++ phyCtl = phyRegRead(phyBase, phyAddr, GEN_ctl);
++
++ if (phyCtl & DUPLEX) {
++ return 1;
++ } else {
++ return 0;
++ }
++}
++
++/******************************************************************************
++*
++* rt_phyIsSpeed100 - Determines the speed of phy ports associated with the
++* specified device.
++*
++* RETURNS:
++* TRUE --> 100Mbit
++* FALSE --> 10Mbit
++*/
++BOOL
++rt_phyIsSpeed100(int phyUnit)
++{
++ UINT16 phyLpa;
++ UINT32 phyBase;
++ UINT32 phyAddr;
++
++ phyBase = RT_PHYBASE(phyUnit);
++ phyAddr = RT_PHYADDR(phyUnit);
++
++ phyLpa = phyRegRead(phyBase, phyAddr, AN_lpa);
++
++ if (phyLpa & (LPA_TXFD | LPA_TX)) {
++ return TRUE;
++ } else {
++ return FALSE;
++ }
++}
++
++/*****************************************************************************
++*
++* rt_phyCheckStatusChange -- checks for significant changes in PHY state.
++*
++* A "significant change" is:
++* dropped link (e.g. ethernet cable unplugged) OR
++* autonegotiation completed + link (e.g. ethernet cable plugged in)
++*
++* On AR5311, there is a 1-to-1 mapping of ethernet units to PHYs.
++* When a PHY is plugged in, phyLinkGained is called.
++* When a PHY is unplugged, phyLinkLost is called.
++*/
++void
++rt_phyCheckStatusChange(int ethUnit)
++{
++ UINT16 phyHwStatus;
++ rtPhyInfo_t *lastStatus = &rtPhyInfo[ethUnit];
++ UINT32 phyBase;
++ UINT32 phyAddr;
++
++ phyBase = RT_PHYBASE(ethUnit);
++ phyAddr = RT_PHYADDR(ethUnit);
++
++ phyHwStatus = phyRegRead(phyBase, phyAddr, GEN_sts);
++
++ if (lastStatus->phyAlive) { /* last known status was ALIVE */
++ /* See if we've lost link */
++ if (!(phyHwStatus & LINK)) {
++ RT_PRINT(RT_DEBUG_PHYCHANGE,("\nethmac%d link down\n", ethUnit));
++ lastStatus->phyAlive = FALSE;
++ phyLinkLost(ethUnit);
++ }
++ } else { /* last known status was DEAD */
++ /* Check for AN complete */
++ if ((phyHwStatus & (AUTOCMPLT | LINK)) == (AUTOCMPLT | LINK)) {
++ RT_PRINT(RT_DEBUG_PHYCHANGE,("\nethmac%d link up\n", ethUnit));
++ lastStatus->phyAlive = TRUE;
++ phyLinkGained(ethUnit);
++ }
++ }
++}
++
++#if DEBUG
++
++/* Define the PHY registers of interest for a phyShow command */
++struct rtRegisterTable_s {
++ UINT32 regNum;
++ char *regIdString;
++} rtRegisterTable[] =
++{
++ {GEN_ctl, "Basic Mode Control (GEN_ctl) "},
++ {GEN_sts, "Basic Mode Status (GEN_sts) "},
++ {GEN_id_hi, "PHY Identifier 1 (GET_id_hi) "},
++ {GEN_id_lo, "PHY Identifier 2 (GET_id_lo) "},
++ {AN_adv, "Auto-Neg Advertisement (AN_adv) "},
++ {AN_lpa, "Auto-Neg Link Partner Ability "},
++ {AN_exp, "Auto-Neg Expansion "},
++};
++
++int rtNumRegs = sizeof(rtRegisterTable) / sizeof(rtRegisterTable[0]);
++
++/*
++ * Dump the state of a PHY.
++ */
++void
++rt_phyShow(int phyUnit)
++{
++ int i;
++ UINT16 value;
++ UINT32 phyBase;
++ UINT32 phyAddr;
++
++ phyBase = RT_PHYBASE(phyUnit);
++ phyAddr = RT_PHYADDR(phyUnit);
++
++ printf("PHY state for ethphy%d\n", phyUnit);
++
++ for (i=0; i<rtNumRegs; i++) {
++
++ value = phyRegRead(phyBase, phyAddr, rtRegisterTable[i].regNum);
++
++ printf("Reg %02d (0x%02x) %s = 0x%08x\n",
++ rtRegisterTable[i].regNum, rtRegisterTable[i].regNum,
++ rtRegisterTable[i].regIdString, value);
++ }
++}
++
++/*
++ * Modify the value of a PHY register.
++ * This makes it a bit easier to modify PHY values during debug.
++ */
++void
++rt_phySet(int phyUnit, UINT32 regnum, UINT32 value)
++{
++ UINT32 phyBase;
++ UINT32 phyAddr;
++
++ phyBase = RT_PHYBASE(phyUnit);
++ phyAddr = RT_PHYADDR(phyUnit);
++
++ phyRegWrite(phyBase, phyAddr, regnum, value);
++}
++#endif
+diff -urN linux-mips-orig/drivers/net/ath/rtPhy.h linux-mips-new/drivers/net/ath/rtPhy.h
+--- linux-mips-orig/drivers/net/ath/rtPhy.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips-new/drivers/net/ath/rtPhy.h 2005-12-31 12:33:57.727530616 +0000
+@@ -0,0 +1,50 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
++ */
++
++/*
++ * rtPhy.h - definitions for the ethernet PHY.
++ * This code supports a simple 1-port ethernet phy, Realtek RTL8201BL,
++ * and compatible PHYs, such as the Kendin KS8721B.
++ * All definitions in this file are operating system independent!
++ */
++
++#ifndef RTPHY_H
++#define RTPHY_H
++
++/* MII Registers */
++
++#define GEN_ctl 00
++#define GEN_sts 01
++#define GEN_id_hi 02
++#define GEN_id_lo 03
++#define AN_adv 04
++#define AN_lpa 05
++#define AN_exp 06
++
++/* GEN_ctl */
++#define PHY_SW_RST 0x8000
++#define LOOPBACK 0x4000
++#define SPEED 0x2000 /* 100 Mbit/s */
++#define AUTONEGENA 0x1000
++#define DUPLEX 0x0100 /* Duplex mode */
++
++
++/* GEN_sts */
++#define AUTOCMPLT 0x0020 /* Autonegotiation completed */
++#define LINK 0x0004 /* Link status */
++
++/* GEN_ids */
++#define RT_PHY_ID1_EXPECTATION 0x22
++
++/* AN_lpa */
++#define LPA_TXFD 0x0100 /* Link partner supports 100 TX Full Duplex */
++#define LPA_TX 0x0080 /* Link partner supports 100 TX Half Duplex */
++#define LPA_10FD 0x0040 /* Link partner supports 10 BT Full Duplex */
++#define LPA_10 0x0020 /* Link partner supports 10 BT Half Duplex */
++
++#endif /* RTPHY_H */
+diff -urN linux-mips/include/linux/raid/md_p.h mips-linux-2.4.25/include/linux/raid/md_p.h
+--- linux-mips/include/linux/raid/md_p.h 2005-12-24 15:12:07.189098448 +0000
++++ mips-linux-2.4.25/include/linux/raid/md_p.h 2005-12-30 17:28:10.345721232 +0000
+@@ -151,10 +151,12 @@
+ */
+ mdp_disk_t disks[MD_SB_DISKS];
+
++#if MD_SB_RESERVED_WORDS
+ /*
+ * Reserved
+ */
+ __u32 reserved[MD_SB_RESERVED_WORDS];
++#endif
+
+ /*
+ * Active descriptor
diff --git a/target/linux/ar7-2.4/Config.in b/target/linux/ar7-2.4/Config.in
new file mode 100644
index 0000000..57d06c0
--- /dev/null
+++ b/target/linux/ar7-2.4/Config.in
@@ -0,0 +1,29 @@
+config PACKAGE_KMOD_CPMAC
+ prompt "kmod-cpmac........................ AR7 CPMAC Network Driver"
+ tristate
+ default y
+ depends LINUX_2_4_AR7
+ help
+ Driver for the AR7 CPMAC network chip
+
+config PACKAGE_KMOD_SANGAM_ATM_A
+ prompt "kmod-sangam-atm-annex-a........... AR7 Sangam ADSL Driver (Annex A)"
+ tristate
+ default m
+ depends LINUX_2_4_AR7
+ select PACKAGE_KMOD_ATM
+ help
+ ATM driver for the Sangam ADSL chip on AR7
+ Annex A version
+
+config PACKAGE_KMOD_SANGAM_ATM_B
+ prompt "kmod-sangam-atm-annex-b........... AR7 Sangam ADSL Driver (Annex B)"
+ tristate
+ default y
+ depends LINUX_2_4_AR7
+ select PACKAGE_KMOD_ATM
+ help
+ ATM driver for the Sangam ADSL chip on AR7
+ Annex B version
+
+
diff --git a/target/linux/ar7-2.4/Makefile b/target/linux/ar7-2.4/Makefile
new file mode 100644
index 0000000..d385722
--- /dev/null
+++ b/target/linux/ar7-2.4/Makefile
@@ -0,0 +1,72 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+LINUX_VERSION:=2.4.32
+LINUX_RELEASE:=1
+LINUX_KERNEL_MD5SUM:=38f4d0830e95a20f4bfed17622d5557c
+
+include ./config
+include $(INCLUDE_DIR)/kernel.mk
+
+ATM_FIRMWARE_VERSION:=0.4
+ATM_FIRMWARE_DIR=sangam-atm-firmware-$(ATM_FIRMWARE_VERSION)
+
+$(eval $(call KMOD_template,SANGAM_ATM_A,sangam-atm-annex-a,\
+ $(MODULES_DIR)/kernel/drivers/atm/tiatm.o \
+,CONFIG_MIPS_SANGAM_ATM,kmod-atm,60,tiatm, \
+ $(CP) $(BUILD_DIR)/$(ATM_FIRMWARE_DIR)/ar0700xx_a.bin $$(I_SANGAM_ATM_A)/lib/modules/ar0700xx.bin \
+))
+
+$(eval $(call KMOD_template,SANGAM_ATM_B,sangam-atm-annex-b,\
+ $(MODULES_DIR)/kernel/drivers/atm/tiatm.o \
+,CONFIG_MIPS_SANGAM_ATM,kmod-atm,60,tiatm, \
+ $(CP) $(BUILD_DIR)/$(ATM_FIRMWARE_DIR)/ar0700xx_b.bin $$(I_SANGAM_ATM_B)/lib/modules/ar0700xx.bin \
+))
+
+$(eval $(call KMOD_template,CPMAC,cpmac,\
+ $(MODULES_DIR)/kernel/drivers/net/avalanche_cpmac/avalanche_cpmac.o \
+,CONFIG_MIPS_AVALANCHE_CPMAC,,10,avalanche_cpmac))
+
+include $(INCLUDE_DIR)/kernel-build.mk
+
+
+$(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked
+ [ -d ../generic-$(KERNEL)/patches ] && $(PATCH) $(LINUX_DIR) ../generic-$(KERNEL)/patches
+ [ -d ./patches ] && $(PATCH) $(LINUX_DIR) ./patches
+ @$(CP) config $(LINUX_DIR)/.config
+ touch $@
+
+
+###############################################
+# ATM firmware for the DSL modem
+###############################################
+
+DOWNLOAD_SITE=http://openwrt.org/downloads/downloads
+# extracted from netgear DG834B V1.0.5 GPL release
+ATM_FIRMWARE_FILE=$(ATM_FIRMWARE_DIR).tar.gz
+ATM_FIRMWARE_MD5SUM=8bfcb31109796502d66b11baaeb2fba6
+
+$(DL_DIR)/$(ATM_FIRMWARE_FILE):
+ $(SCRIPT_DIR)/download.pl $(DL_DIR) $(ATM_FIRMWARE_FILE) $(ATM_FIRMWARE_MD5SUM) $(DOWNLOAD_SITE)
+
+download: $(DL_DIR)/$(ATM_FIRMWARE_FILE)
+$(LINUX_DIR)/.unpacked: $(DL_DIR)/$(ATM_FIRMWARE_FILE)
+$(LINUX_DIR)/.depend_done: $(LINUX_DIR)/.drivers-unpacked
+$(LINUX_DIR)/.modules_done: $(LINUX_DIR)/.drivers-unpacked
+
+$(LINUX_DIR)/.drivers-unpacked: $(LINUX_DIR)/.unpacked
+ -mkdir -p $(BUILD_DIR)
+ zcat $(DL_DIR)/$(ATM_FIRMWARE_FILE) | tar -C $(BUILD_DIR) $(TAR_OPTIONS) -
+ touch $@
+
+linux-dirclean: drivers-clean
+
+drivers-clean: FORCE
+ rm -rf $(BUILD_DIR)/$(ATM_FIRMWARE_DIR)
+
+
diff --git a/target/linux/ar7-2.4/config b/target/linux/ar7-2.4/config
new file mode 100644
index 0000000..5f7a151
--- /dev/null
+++ b/target/linux/ar7-2.4/config
@@ -0,0 +1,1080 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MIPS=y
+CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+CONFIG_AR7=y
+# CONFIG_AR7DB is not set
+# CONFIG_AR7RD is not set
+CONFIG_AR7WRD=y
+CONFIG_AR7_CPU=150
+CONFIG_AR7_SYS=125
+CONFIG_AR7_MEMORY=0x14000000
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_FICMMP is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_HYDROGEN3 is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_COGENT_CSB250 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_CASIO_E55 is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_IBM_WORKPAD is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_PMC_BIG_SUR is not set
+# CONFIG_PMC_STRETCH is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TANBAC_TB0226 is not set
+# CONFIG_TANBAC_TB0229 is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_VICTOR_MPC30X is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_IRQ_CPU=y
+CONFIG_NONCOHERENT_IO=y
+CONFIG_SWAP_IO_SPACE=y
+# CONFIG_MIPS_AU1000 is not set
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_VTAG_ICACHE is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+# CONFIG_CPU_HAS_LLDSCD is not set
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
+
+#
+# General setup
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_BUILD_ELF64 is not set
+CONFIG_NET=y
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+# CONFIG_TC is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+# CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE is not set
+# CONFIG_HOTPLUG_PCI_PCIE is not set
+# CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_ELF_AOUT is not set
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_MIPS32_O32 is not set
+# CONFIG_MIPS32_N32 is not set
+# CONFIG_BINFMT_ELF32 is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=squashfs,jffs2 init=/etc/preinit noinitrd"
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_CFI_SSTSTD is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_AR7=y
+CONFIG_MTD_AR7_DEFAULTS=y
+CONFIG_MTD_AR7_START=0x10000000
+CONFIG_MTD_AR7_LEN=0x400000
+CONFIG_MTD_AR7_BUSWIDTH=2
+# CONFIG_MTD_PB1000 is not set
+# CONFIG_MTD_PB1500 is not set
+# CONFIG_MTD_PB1100 is not set
+# CONFIG_MTD_BOSPORUS is not set
+# CONFIG_MTD_XXS1500 is not set
+# CONFIG_MTD_MTX1 is not set
+# CONFIG_MTD_DB1X00 is not set
+# CONFIG_MTD_PB1550 is not set
+# CONFIG_MTD_HYDROGEN3 is not set
+# CONFIG_MTD_MIRAGE is not set
+# CONFIG_MTD_CSTM_MIPS_IXX is not set
+# CONFIG_MTD_OCELOT is not set
+# CONFIG_MTD_LASAT is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_CISS_MONITOR_THREAD is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK_DEV=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_NAT=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_TOS=y
+# CONFIG_IP_ROUTE_VERBOSE is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+CONFIG_IP_NF_FTP=y
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_IRC=y
+CONFIG_IP_NF_CT_ACCT=m
+CONFIG_IP_NF_MATCH_CONNBYTES=m
+CONFIG_IP_NF_CT_PROTO_GRE=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+CONFIG_IP_NF_MMS=m
+CONFIG_IP_NF_RTSP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_QUOTA=m
+CONFIG_IP_NF_SET=m
+CONFIG_IP_NF_SET_MAX=256
+CONFIG_IP_NF_SET_HASHSIZE=1024
+CONFIG_IP_NF_MATCH_SET=m
+CONFIG_IP_NF_TARGET_SET=m
+CONFIG_IP_NF_SET_IPMAP=m
+CONFIG_IP_NF_SET_PORTMAP=m
+CONFIG_IP_NF_SET_MACIPMAP=m
+CONFIG_IP_NF_SET_IPHASH=m
+CONFIG_IP_NF_SET_NETHASH=m
+CONFIG_IP_NF_SET_IPTREE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=y
+CONFIG_IP_NF_MATCH_MULTIPORT=y
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_TIME=m
+CONFIG_IP_NF_MATCH_CONDITION=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_IPP2P=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=y
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_UNCLEAN=m
+CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN=2048
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_MIRROR=m
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_PROTO_GRE=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_NAT_MMS=m
+CONFIG_IP_NF_NAT_RTSP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=y
+CONFIG_IP_NF_NAT_FTP=y
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=y
+CONFIG_IP_NF_TARGET_IMQ=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_CONDITION=m
+CONFIG_IP6_NF_MATCH_MAC=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_AHESP is not set
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_TARGET_IMQ=m
+# CONFIG_KHTTPD is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+CONFIG_ATM=m
+# CONFIG_ATM_CLIP is not set
+# CONFIG_ATM_LANE is not set
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_VLAN_8021Q=y
+
+#
+#
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+CONFIG_BRIDGE=y
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+CONFIG_WAN_ROUTER=m
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_CSZ=m
+CONFIG_NET_SCH_HFSC=m
+# CONFIG_NET_SCH_ATM is not set
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_POLICE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_IPSEC_NAT_TRAVERSAL=y
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=m
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_SD_EXTRA_DEVS=5
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_MEGARAID2 is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_SATA_AHCI is not set
+# CONFIG_SCSI_SATA_SVW is not set
+# CONFIG_SCSI_ATA_PIIX is not set
+# CONFIG_SCSI_SATA_NV is not set
+# CONFIG_SCSI_SATA_QSTOR is not set
+# CONFIG_SCSI_SATA_PROMISE is not set
+# CONFIG_SCSI_SATA_SX4 is not set
+# CONFIG_SCSI_SATA_SIL is not set
+# CONFIG_SCSI_SATA_SIS is not set
+# CONFIG_SCSI_SATA_ULI is not set
+# CONFIG_SCSI_SATA_VIA is not set
+# CONFIG_SCSI_SATA_VITESSE is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_BOOT is not set
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_IMQ=m
+CONFIG_TUN=m
+CONFIG_NET_RANDOM=y
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MIPS_AVALANCHE_CPMAC=m
+CONFIG_MIPS_CPMAC_INIT_BUF_MALLOC=y
+CONFIG_MIPS_CPMAC_PORTS=1
+CONFIG_AVALANCHE_CPMAC_AUTO=y
+# CONFIG_AVALANCHE_LOW_CPMAC is not set
+# CONFIG_AVALANCHE_HIGH_CPMAC is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE_MPPC=m
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_HERMES is not set
+
+#
+# Prism54 PCI/PCMCIA GT/Duette Driver - 802.11(a/b/g)
+#
+# CONFIG_PRISM54 is not set
+# CONFIG_NET_WIRELESS is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+CONFIG_SHAPER=m
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ATM drivers
+#
+# CONFIG_ATM_TCP is not set
+CONFIG_MIPS_SANGAM_ATM=m
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_AR7_LED=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=128
+CONFIG_AR7_VLYNQ=y
+CONFIG_VLYNQ_CLK_LOCAL=y
+CONFIG_AR7_VLYNQ_PORTS=2
+CONFIG_AR7_ADAM2=y
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
+
+#
+# Input core support is needed for joysticks
+#
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+CONFIG_AR7_WDT=y
+CONFIG_SOFT_WATCHDOG=m
+# CONFIG_SCx200 is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+
+#
+# Direct Rendering Manager (XFree86 DRI support)
+#
+# CONFIG_DRM is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_QFMT_V2 is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=m
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_BBC_ARMLIB is not set
+# CONFIG_JFFS2_BBC_LZO is not set
+CONFIG_JFFS2_BBC_LZARI=y
+# CONFIG_JFFS2_BBC_LZHD is not set
+# CONFIG_JFFS2_BBC_LZSS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=m
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_POSIX=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+CONFIG_BLUEZ=m
+CONFIG_BLUEZ_L2CAP=m
+CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_RFCOMM=m
+CONFIG_BLUEZ_RFCOMM_TTY=y
+CONFIG_BLUEZ_BNEP=m
+CONFIG_BLUEZ_BNEP_MC_FILTER=y
+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BLUEZ_HCIUSB is not set
+CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIUART_H4=y
+CONFIG_BLUEZ_HCIUART_BCSP=y
+CONFIG_BLUEZ_HCIUART_BCSP_TXCRC=y
+# CONFIG_BLUEZ_HCIBFUSB is not set
+# CONFIG_BLUEZ_HCIDTL1 is not set
+# CONFIG_BLUEZ_HCIBT3C is not set
+# CONFIG_BLUEZ_HCIBLUECARD is not set
+# CONFIG_BLUEZ_HCIBTUART is not set
+# CONFIG_BLUEZ_HCIVHCI is not set
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_RUNTIME_DEBUG is not set
+# CONFIG_KGDB is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_MIPS_UNCACHED is not set
+CONFIG_LOG_BUF_SHIFT=0
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_FW_LOADER is not set
diff --git a/target/linux/ar7-2.4/patches/000-ar7_support.patch b/target/linux/ar7-2.4/patches/000-ar7_support.patch
new file mode 100644
index 0000000..0c9c0d3
--- /dev/null
+++ b/target/linux/ar7-2.4/patches/000-ar7_support.patch
@@ -0,0 +1,9549 @@
+diff -urN linux.old/arch/mips/Makefile linux.dev/arch/mips/Makefile
+--- linux.old/arch/mips/Makefile 2005-10-21 16:43:16.316951500 +0200
++++ linux.dev/arch/mips/Makefile 2005-11-10 01:10:45.775570250 +0100
+@@ -369,6 +369,16 @@
+ endif
+
+ #
++# Texas Instruments AR7
++#
++
++ifdef CONFIG_AR7
++LIBS += arch/mips/ar7/ar7.o
++SUBDIRS += arch/mips/ar7
++LOADADDR += 0x94020000
++endif
++
++#
+ # DECstation family
+ #
+ ifdef CONFIG_DECSTATION
+diff -urN linux.old/arch/mips/ar7/Makefile linux.dev/arch/mips/ar7/Makefile
+--- linux.old/arch/mips/ar7/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/ar7/Makefile 2005-11-10 01:13:51.443173750 +0100
+@@ -0,0 +1,14 @@
++.S.s:
++ $(CPP) $(AFLAGS) $< -o $*.s
++
++.S.o:
++ $(CC) $(AFLAGS) -c $< -o $*.o
++
++EXTRA_CFLAGS := -I$(TOPDIR)/include/asm/ar7 -DLITTLE_ENDIAN -D_LINK_KSEG0_
++O_TARGET := ar7.o
++
++obj-y := tnetd73xx_misc.o misc.o
++export-objs := misc.o irq.o init.o
++obj-y += setup.o irq.o int-handler.o reset.o init.o psp_env.o memory.o promlib.o cmdline.o
++
++include $(TOPDIR)/Rules.make
+diff -urN linux.old/arch/mips/ar7/cmdline.c linux.dev/arch/mips/ar7/cmdline.c
+--- linux.old/arch/mips/ar7/cmdline.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/ar7/cmdline.c 2005-11-10 01:14:16.372731750 +0100
+@@ -0,0 +1,88 @@
++/*
++ * Carsten Langgaard, carstenl@mips.com
++ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
++ *
++ * This program is free software; you can distribute it and/or modify it
++ * under the terms of the GNU General Public License (Version 2) as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope 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.
++ *
++ * Kernel command line creation using the prom monitor (YAMON) argc/argv.
++ */
++#include <linux/init.h>
++#include <linux/string.h>
++
++#include <asm/bootinfo.h>
++
++extern int prom_argc;
++extern int *_prom_argv;
++
++/*
++ * YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer.
++ * This macro take care of sign extension.
++ */
++#define prom_argv(index) ((char *)(((int *)(int)_prom_argv)[(index)]))
++
++char arcs_cmdline[CL_SIZE];
++#ifdef CONFIG_CMDLINE_BOOL
++char __initdata cfg_cmdline[] = CONFIG_CMDLINE;
++#endif
++
++char * __init prom_getcmdline(void)
++{
++ return &(arcs_cmdline[0]);
++}
++
++
++void __init prom_init_cmdline(void)
++{
++ char *cp, *end;
++ int actr;
++ char *env_cmdline = prom_getenv("kernel_args");
++ size_t len;
++
++ actr = 1; /* Always ignore argv[0] */
++
++ cp = end = &(arcs_cmdline[0]);
++ end += sizeof(arcs_cmdline);
++
++ if (env_cmdline) {
++ len = strlen(env_cmdline);
++ if (len > end - cp - 1)
++ len = end - cp - 1;
++ strncpy(cp, env_cmdline, len);
++ cp += len;
++ *cp++ = ' ';
++ }
++#ifdef CONFIG_CMDLINE_BOOL
++ else {
++ len = strlen(cfg_cmdline);
++ if (len > end - cp - 1)
++ len = end - cp - 1;
++ strncpy(cp, cfg_cmdline, len);
++ cp += len;
++ *cp++ = ' ';
++ }
++#endif
++
++ while(actr < prom_argc) {
++ len = strlen(prom_argv(actr));
++ if (len > end - cp - 1)
++ break;
++ strncpy(cp, prom_argv(actr), len);
++ cp += len;
++ *cp++ = ' ';
++ actr++;
++ }
++ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
++ --cp;
++ *cp = '\0';
++}
+diff -urN linux.old/arch/mips/ar7/init.c linux.dev/arch/mips/ar7/init.c
+--- linux.old/arch/mips/ar7/init.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/ar7/init.c 2005-11-10 01:10:45.795571500 +0100
+@@ -0,0 +1,199 @@
++/*
++ * Carsten Langgaard, carstenl@mips.com
++ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
++ *
++ * This program is free software; you can distribute it and/or modify it
++ * under the terms of the GNU General Public License (Version 2) as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope 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.
++ *
++ * PROM library initialisation code.
++ */
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include <asm/io.h>
++#include <asm/mips-boards/prom.h>
++#include <asm/mips-boards/generic.h>
++
++#include <asm/ar7/adam2_env.h>
++
++int prom_argc;
++int *_prom_argv, *_prom_envp;
++
++/* max # of Adam2 environment variables */
++#define MAX_ENV_ENTRY 80
++
++static t_env_var local_envp[MAX_ENV_ENTRY];
++static int env_type = 0;
++int init_debug = 0;
++
++unsigned int max_env_entry;
++
++extern char *prom_psp_getenv(char *envname);
++
++static inline char *prom_adam2_getenv(char *envname)
++{
++ /*
++ * Return a pointer to the given environment variable.
++ * In 64-bit mode: we're using 64-bit pointers, but all pointers
++ * in the PROM structures are only 32-bit, so we need some
++ * workarounds, if we are running in 64-bit mode.
++ */
++ int i;
++ t_env_var *env = (t_env_var *) local_envp;
++
++ if (strcmp("bootloader", envname) == 0)
++ return "Adam2";
++
++ i = strlen(envname);
++ while (env->name) {
++ if(strncmp(envname, env->name, i) == 0) {
++ return(env->val);
++ }
++ env++;
++ }
++
++ return NULL;
++}
++
++/* XXX "bootloader" won't be returned.
++ * Better make it an element of local_envp */
++static inline t_env_var *
++prom_adam2_iterenv(t_env_var *env) {
++ if (!env)
++ env = local_envp;
++ else
++ env++;
++ if (env - local_envp > MAX_ENV_ENTRY || !env->name)
++ return 0;
++ return env;
++}
++
++char *prom_getenv(char *envname)
++{
++ if (env_type == 1)
++ return prom_psp_getenv(envname);
++ else
++ return prom_adam2_getenv(envname);
++}
++
++t_env_var *
++prom_iterenv(t_env_var *last)
++{
++ if (env_type == 1)
++ return 0; /* not yet implemented */
++ return prom_adam2_iterenv(last);
++}
++
++static inline unsigned char str2hexnum(unsigned char c)
++{
++ if (c >= '0' && c <= '9')
++ return c - '0';
++ if (c >= 'a' && c <= 'f')
++ return c - 'a' + 10;
++ return 0; /* foo */
++}
++
++static inline void str2eaddr(unsigned char *ea, unsigned char *str)
++{
++ int i;
++
++ for (i = 0; i < 6; i++) {
++ unsigned char num;
++
++ if((*str == '.') || (*str == ':'))
++ str++;
++ num = str2hexnum(*str++) << 4;
++ num |= (str2hexnum(*str++));
++ ea[i] = num;
++ }
++}
++
++int get_ethernet_addr(char *ethernet_addr)
++{
++ char *ethaddr_str;
++
++ ethaddr_str = prom_getenv("ethaddr");
++ if (!ethaddr_str) {
++ printk("ethaddr not set in boot prom\n");
++ return -1;
++ }
++ str2eaddr(ethernet_addr, ethaddr_str);
++
++ if (init_debug > 1) {
++ int i;
++ printk("get_ethernet_addr: ");
++ for (i=0; i<5; i++)
++ printk("%02x:", (unsigned char)*(ethernet_addr+i));
++ printk("%02x\n", *(ethernet_addr+i));
++ }
++
++ return 0;
++}
++
++struct psbl_rec {
++ unsigned int psbl_size;
++ unsigned int env_base;
++ unsigned int env_size;
++ unsigned int ffs_base;
++ unsigned int ffs_size;
++};
++
++static const char psp_env_version[] = "TIENV0.8";
++
++int __init prom_init(int argc, char **argv, char **envp)
++{
++ int i;
++
++ t_env_var *env = (t_env_var *) envp;
++ struct psbl_rec *psbl = (struct psbl_rec *)(KSEG1ADDR(0x94000300));
++ void *psp_env = (void *)KSEG1ADDR(psbl->env_base);
++
++ prom_argc = argc;
++ _prom_argv = (int *)argv;
++ _prom_envp = (int *)envp;
++
++ if(strcmp(psp_env, psp_env_version) == 0) {
++ /* PSPBOOT */
++
++ env_type = 1;
++ _prom_envp = psp_env;
++ max_env_entry = (psbl->env_size / 16) - 1;
++ } else {
++ /* Copy what we need locally so we are not dependent on
++ * bootloader RAM. In Adam2, the environment parameters
++ * are in flash but the table that references them is in
++ * RAM
++ */
++
++ for(i=0; i < MAX_ENV_ENTRY; i++, env++) {
++ if (env->name) {
++ local_envp[i].name = env->name;
++ local_envp[i].val = env->val;
++ } else {
++ local_envp[i].name = NULL;
++ local_envp[i].val = NULL;
++ }
++ }
++ }
++
++ set_io_port_base(0);
++
++ prom_printf("\nLINUX started...\n");
++ prom_init_cmdline();
++ prom_meminit();
++
++ return 0;
++}
+diff -urN linux.old/arch/mips/ar7/int-handler.S linux.dev/arch/mips/ar7/int-handler.S
+--- linux.old/arch/mips/ar7/int-handler.S 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/ar7/int-handler.S 2005-11-10 01:12:43.938955000 +0100
+@@ -0,0 +1,63 @@
++/*
++ * Copyright 2004 PMC-Sierra Inc.
++ * Author: Manish Lachwani (lachwani@pmc-sierra.com)
++ * Adaption for AR7: Enrik Berkhan <enrik@akk.org>
++ *
++ * First-level interrupt dispatcher for the TI AR7
++ *
++ * 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.
++ */
++#define __ASSEMBLY__
++#include <linux/config.h>
++#include <asm/asm.h>
++#include <asm/mipsregs.h>
++#include <asm/addrspace.h>
++#include <asm/regdef.h>
++#include <asm/stackframe.h>
++
++/*
++ * First level interrupt dispatcher for TI AR7 based boards
++ */
++
++ .align 5
++ NESTED(ar7IRQ, PT_SIZE, sp)
++ SAVE_ALL
++ CLI
++ .set at
++
++ mfc0 t0, CP0_CAUSE
++ mfc0 t2, CP0_STATUS
++
++ and t0, t2
++
++ andi t1, t0, STATUSF_IP2 /* hw0 hardware interrupt */
++ bnez t1, ll_hw0_irq
++
++ andi t1, t0, STATUSF_IP7 /* R4k CPU timer */
++ bnez t1, ll_timer_irq
++
++ .set reorder
++
++ /* wrong alarm or masked ... */
++ j spurious_interrupt
++ nop
++ END(ar7IRQ)
++
++ .align 5
++
++ll_hw0_irq:
++ li a0, 2
++ move a1, sp
++ jal do_IRQ
++ j ret_from_irq
++
++ll_timer_irq:
++ li a0, 7
++ move a1, sp
++ jal do_IRQ
++ j ret_from_irq
++
++
+diff -urN linux.old/arch/mips/ar7/irq.c linux.dev/arch/mips/ar7/irq.c
+--- linux.old/arch/mips/ar7/irq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/ar7/irq.c 2005-11-10 01:12:43.938955000 +0100
+@@ -0,0 +1,427 @@
++/*
++ * Nitin Dhingra, iamnd@ti.com
++ * Copyright (C) 2002 Texas Instruments, Inc. All rights reserved.
++ *
++ * ########################################################################
++ *
++ * This program is free software; you can distribute it and/or modify it
++ * under the terms of the GNU General Public License (Version 2) as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope 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.
++ *
++ * ########################################################################
++ *
++ * Routines for generic manipulation of the interrupts found on the Texas
++ * Instruments avalanche board
++ *
++ */
++
++#include <linux/init.h>
++#include <linux/interrupt.h>
++
++#include <asm/irq.h>
++#include <asm/mipsregs.h>
++#include <asm/ar7/ar7.h>
++#include <asm/ar7/avalanche_intc.h>
++
++#define shutdown_avalanche_irq disable_avalanche_irq
++#define mask_and_ack_avalanche_irq disable_avalanche_irq
++
++static unsigned int startup_avalanche_irq(unsigned int irq);
++static void end_avalanche_irq(unsigned int irq);
++void enable_avalanche_irq(unsigned int irq_nr);
++void disable_avalanche_irq(unsigned int irq_nr);
++void ar7_hw0_interrupt(int interrupt, void *dev, struct pt_regs *regs);
++
++static struct hw_interrupt_type avalanche_irq_type = {
++ "AR7",
++ startup_avalanche_irq,
++ shutdown_avalanche_irq,
++ enable_avalanche_irq,
++ disable_avalanche_irq,
++ mask_and_ack_avalanche_irq,
++ end_avalanche_irq,
++ NULL
++};
++
++static int ar7_irq_base;
++
++static struct irqaction ar7_hw0_action = {
++ ar7_hw0_interrupt, 0, 0, "AR7 on hw0", NULL, NULL
++};
++
++struct avalanche_ictrl_regs *avalanche_hw0_icregs; /* Interrupt control regs (primary) */
++struct avalanche_exctrl_regs *avalanche_hw0_ecregs; /* Exception control regs (secondary) */
++struct avalanche_ipace_regs *avalanche_hw0_ipaceregs;
++struct avalanche_channel_int_number *avalanche_hw0_chregs; /* Channel control registers */
++
++/*
++ This remaps interrupts to exist on other channels than the default
++ channels. essentially we can use the line # as the index for this
++ array
++ */
++
++static unsigned long line_to_channel[AVINTNUM(AVALANCHE_INT_END_PRIMARY)];
++unsigned long uni_secondary_interrupt = 0;
++
++static void end_avalanche_irq(unsigned int irq)
++{
++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
++ enable_avalanche_irq(irq);
++}
++
++void disable_avalanche_irq(unsigned int irq_nr)
++{
++ unsigned long flags;
++ unsigned long chan_nr=0;
++
++ save_and_cli(flags);
++
++ /* irq_nr represents the line number for the interrupt. We must
++ * disable the channel number associated with that line number.
++ */
++
++ if(irq_nr > AVALANCHE_INT_END_PRIMARY_REG2)
++ chan_nr = AVINTNUM(irq_nr); /*CHECK THIS ALSO*/
++ else
++ chan_nr = line_to_channel[AVINTNUM(irq_nr)];/* WE NEED A LINE TO CHANNEL MAPPING FUNCTION HERE*/
++
++ /* disable the interrupt channel bit */
++
++ /* primary interrupt #'s 0-31 */
++
++ if(chan_nr <= AVINTNUM(AVALANCHE_INT_END_PRIMARY_REG1))
++ avalanche_hw0_icregs->intecr1 = (1 << chan_nr);
++
++ /* primary interrupt #'s 32-39 */
++
++ else if ((chan_nr <= AVINTNUM(AVALANCHE_INT_END_PRIMARY_REG2)) &&
++ (chan_nr > AVINTNUM(AVALANCHE_INT_END_PRIMARY_REG1)))
++ avalanche_hw0_icregs->intecr2 = (1 << (chan_nr - AVINTNUM(AVALANCHE_INT_END_SECONDARY)));
++
++ else /* secondary interrupt #'s 0-31 */
++ avalanche_hw0_ecregs->exiecr = (1 << (chan_nr - AVINTNUM(AVALANCHE_INT_END_PRIMARY)));
++
++ restore_flags(flags);
++}
++
++void enable_avalanche_irq(unsigned int irq_nr)
++{
++ unsigned long flags;
++ unsigned long chan_nr=0;
++
++ save_and_cli(flags);
++
++ /* irq_nr represents the line number for the interrupt. We must
++ * disable the channel number associated with that line number.
++ */
++
++ if(irq_nr > AVALANCHE_INT_END_PRIMARY_REG2)
++ chan_nr = AVINTNUM(irq_nr);
++ else
++ chan_nr = line_to_channel[AVINTNUM(irq_nr)];
++
++ /* enable the interrupt channel bit */
++
++ /* primary interrupt #'s 0-31 */
++ if(chan_nr <= AVINTNUM(AVALANCHE_INT_END_PRIMARY_REG1))
++ avalanche_hw0_icregs->intesr1 = (1 << chan_nr);
++
++ /* primary interrupt #'s 32 throuth 39 */
++ else if ((chan_nr <= AVINTNUM(AVALANCHE_INT_END_PRIMARY_REG2)) &&
++ (chan_nr > AVINTNUM(AVALANCHE_INT_END_PRIMARY_REG1)))
++ avalanche_hw0_icregs->intesr2 = (1 << (chan_nr - AVINTNUM(AVALANCHE_INT_END_SECONDARY)));
++
++ else /* secondary interrupt #'s 0-31 */
++ avalanche_hw0_ecregs->exiesr = (1 << (chan_nr - AVINTNUM(AVALANCHE_INT_END_PRIMARY)));
++
++ restore_flags(flags);
++}
++
++static unsigned int startup_avalanche_irq(unsigned int irq)
++{
++ enable_avalanche_irq(irq);
++ return 0; /* never anything pending */
++}
++
++void __init ar7_irq_init(int base)
++{
++ int i;
++
++ avalanche_hw0_icregs = (struct avalanche_ictrl_regs *)AVALANCHE_ICTRL_REGS_BASE;
++ avalanche_hw0_ecregs = (struct avalanche_exctrl_regs *)AVALANCHE_ECTRL_REGS_BASE;
++ avalanche_hw0_ipaceregs = (struct avalanche_ipace_regs *)AVALANCHE_IPACE_REGS_BASE;
++ avalanche_hw0_chregs = (struct avalanche_channel_int_number *)AVALANCHE_CHCTRL_REGS_BASE;
++
++ /* Disable interrupts and clear pending
++ */
++
++ avalanche_hw0_icregs->intecr1 = 0xffffffff; /* disable interrupts 0:31 */
++ avalanche_hw0_icregs->intcr1 = 0xffffffff; /* clear interrupts 0:31 */
++ avalanche_hw0_icregs->intecr2 = 0xff; /* disable interrupts 32:39 */
++ avalanche_hw0_icregs->intcr2 = 0xff; /* clear interrupts 32:39 */
++ avalanche_hw0_ecregs->exiecr = 0xffffffff; /* disable secondary interrupts 0:31 */
++ avalanche_hw0_ecregs->excr = 0xffffffff; /* clear secondary interrupts 0:31 */
++
++
++ // avalanche_hw0_ipaceregs->ipacep = (2*get_avalanche_vbus_freq()/1000000)*4;
++ /* hack for speeding up the pacing. */
++ printk("the pacing pre-scalar has been set as 600.\n");
++ avalanche_hw0_ipaceregs->ipacep = 600;
++ /* Channel to line mapping, Line to Channel mapping */
++
++ for(i = 0; i < 40; i++)
++ avalanche_int_set(i,i);
++
++ ar7_irq_base = base;
++ for (i = base; i <= base+40; i++)
++ {
++ irq_desc[i].status = IRQ_DISABLED;
++ irq_desc[i].action = 0;
++ irq_desc[i].depth = 1;
++ irq_desc[i].handler = &avalanche_irq_type;
++ }
++
++ setup_irq(2, &ar7_hw0_action);
++ set_c0_status(IE_IRQ0);
++
++ return;
++}
++
++void ar7_hw0_interrupt(int interrupt, void *dev, struct pt_regs *regs)
++{
++ int irq;
++ unsigned long int_line_number, status;
++ int i, chan_nr = 0;
++
++ int_line_number = ((avalanche_hw0_icregs->pintir >> 16) & 0x3F);
++ chan_nr = ((avalanche_hw0_icregs->pintir) & 0x3F);
++
++ if(chan_nr < 32) /* primary 0-31 */
++ {
++ if( chan_nr != uni_secondary_interrupt)
++ avalanche_hw0_icregs->intcr1 = (1<<chan_nr);
++
++ }
++
++ if((chan_nr < 40) && (chan_nr > 31)) /* primary 32-39 */
++ {
++ avalanche_hw0_icregs->intcr2 = (1<<(chan_nr-32));
++ }
++
++
++ /* If the Priority Interrupt Index Register returns 40 then no
++ * interrupts are pending
++ */
++
++ if(chan_nr == 40)
++ return;
++
++ if(chan_nr == uni_secondary_interrupt) /* secondary 0-31 */
++ {
++ status = avalanche_hw0_ecregs->exsr;
++ for(i=0; i < 32; i++)
++ {
++ if (status & 1<<i)
++ {
++ /* clear secondary interrupt */
++ avalanche_hw0_ecregs->excr = 1 << i;
++ break;
++ }
++ }
++ irq = i+40;
++
++ /* clear the universal secondary interrupt */
++ avalanche_hw0_icregs->intcr1 = 1 << uni_secondary_interrupt;
++
++ }
++ else
++ irq = chan_nr;
++
++ do_IRQ(irq + ar7_irq_base, regs);
++ return;
++}
++
++void avalanche_int_set(int channel, int line)
++{
++ switch(channel)
++ {
++ case(0):
++ avalanche_hw0_chregs->cintnr0 = line;
++ break;
++ case(1):
++ avalanche_hw0_chregs->cintnr1 = line;
++ break;
++ case(2):
++ avalanche_hw0_chregs->cintnr2 = line;
++ break;
++ case(3):
++ avalanche_hw0_chregs->cintnr3 = line;
++ break;
++ case(4):
++ avalanche_hw0_chregs->cintnr4 = line;
++ break;
++ case(5):
++ avalanche_hw0_chregs->cintnr5 = line;
++ break;
++ case(6):
++ avalanche_hw0_chregs->cintnr6 = line;
++ break;
++ case(7):
++ avalanche_hw0_chregs->cintnr7 = line;
++ break;
++ case(8):
++ avalanche_hw0_chregs->cintnr8 = line;
++ break;
++ case(9):
++ avalanche_hw0_chregs->cintnr9 = line;
++ break;
++ case(10):
++ avalanche_hw0_chregs->cintnr10 = line;
++ break;
++ case(11):
++ avalanche_hw0_chregs->cintnr11 = line;
++ break;
++ case(12):
++ avalanche_hw0_chregs->cintnr12 = line;
++ break;
++ case(13):
++ avalanche_hw0_chregs->cintnr13 = line;
++ break;
++ case(14):
++ avalanche_hw0_chregs->cintnr14 = line;
++ break;
++ case(15):
++ avalanche_hw0_chregs->cintnr15 = line;
++ break;
++ case(16):
++ avalanche_hw0_chregs->cintnr16 = line;
++ break;
++ case(17):
++ avalanche_hw0_chregs->cintnr17 = line;
++ break;
++ case(18):
++ avalanche_hw0_chregs->cintnr18 = line;
++ break;
++ case(19):
++ avalanche_hw0_chregs->cintnr19 = line;
++ break;
++ case(20):
++ avalanche_hw0_chregs->cintnr20 = line;
++ break;
++ case(21):
++ avalanche_hw0_chregs->cintnr21 = line;
++ break;
++ case(22):
++ avalanche_hw0_chregs->cintnr22 = line;
++ break;
++ case(23):
++ avalanche_hw0_chregs->cintnr23 = line;
++ break;
++ case(24):
++ avalanche_hw0_chregs->cintnr24 = line;
++ break;
++ case(25):
++ avalanche_hw0_chregs->cintnr25 = line;
++ break;
++ case(26):
++ avalanche_hw0_chregs->cintnr26 = line;
++ break;
++ case(27):
++ avalanche_hw0_chregs->cintnr27 = line;
++ break;
++ case(28):
++ avalanche_hw0_chregs->cintnr28 = line;
++ break;
++ case(29):
++ avalanche_hw0_chregs->cintnr29 = line;
++ break;
++ case(30):
++ avalanche_hw0_chregs->cintnr30 = line;
++ break;
++ case(31):
++ avalanche_hw0_chregs->cintnr31 = line;
++ break;
++ case(32):
++ avalanche_hw0_chregs->cintnr32 = line;
++ break;
++ case(33):
++ avalanche_hw0_chregs->cintnr33 = line;
++ break;
++ case(34):
++ avalanche_hw0_chregs->cintnr34 = line;
++ break;
++ case(35):
++ avalanche_hw0_chregs->cintnr35 = line;
++ break;
++ case(36):
++ avalanche_hw0_chregs->cintnr36 = line;
++ break;
++ case(37):
++ avalanche_hw0_chregs->cintnr37 = line;
++ break;
++ case(38):
++ avalanche_hw0_chregs->cintnr38 = line;
++ break;
++ case(39):
++ avalanche_hw0_chregs->cintnr39 = line;
++ break;
++ default:
++ printk("Error: Unknown Avalanche interrupt channel\n");
++ }
++
++ line_to_channel[line] = channel; /* Suraj check */
++
++ if (channel == UNIFIED_SECONDARY_INTERRUPT)
++ uni_secondary_interrupt = line;
++
++}
++
++
++#define AVALANCHE_MAX_PACING_BLK 3
++#define AVALANCHE_PACING_LOW_VAL 2
++#define AVALANCHE_PACING_HIGH_VAL 63
++
++int avalanche_request_pacing(int irq_nr, unsigned int blk_num,
++ unsigned int pace_value)
++{
++ unsigned int blk_offset;
++ unsigned long flags;
++
++ if(irq_nr < MIPS_EXCEPTION_OFFSET &&
++ irq_nr >= AVALANCHE_INT_END_PRIMARY)
++ return (0);
++
++ if(blk_num > AVALANCHE_MAX_PACING_BLK)
++ return(-1);
++
++ if(pace_value > AVALANCHE_PACING_HIGH_VAL &&
++ pace_value < AVALANCHE_PACING_LOW_VAL)
++ return(-1);
++
++ blk_offset = blk_num*8;
++
++ save_and_cli(flags);
++
++ /* disable the interrupt pacing, if enabled previously */
++ avalanche_hw0_ipaceregs->ipacemax &= ~(0xff << blk_offset);
++
++ /* clear the pacing map */
++ avalanche_hw0_ipaceregs->ipacemap &= ~(0xff << blk_offset);
++
++ /* setup the new values */
++ avalanche_hw0_ipaceregs->ipacemap |= ((AVINTNUM(irq_nr)) << blk_offset);
++ avalanche_hw0_ipaceregs->ipacemax |= ((0x80 | pace_value) << blk_offset);
++
++ restore_flags(flags);
++
++ return(0);
++}
+diff -urN linux.old/arch/mips/ar7/memory.c linux.dev/arch/mips/ar7/memory.c
+--- linux.old/arch/mips/ar7/memory.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/ar7/memory.c 2005-11-10 01:14:16.372731750 +0100
+@@ -0,0 +1,103 @@
++/*
++ * Carsten Langgaard, carstenl@mips.com
++ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
++ *
++ * ########################################################################
++ *
++ * This program is free software; you can distribute it and/or modify it
++ * under the terms of the GNU General Public License (Version 2) as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * ########################################################################
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/bootmem.h>
++
++#include <asm/bootinfo.h>
++#include <asm/page.h>
++#include <asm/mips-boards/prom.h>
++
++extern char _ftext;
++extern int preserve_adam2;
++
++void __init prom_meminit(void)
++{
++ char *memsize_str;
++ unsigned long memsize, adam2size;
++
++ /* assume block before kernel is used by bootloader */
++ adam2size = __pa(&_ftext) - PHYS_OFFSET;
++
++ memsize_str = prom_getenv("memsize");
++ if (!memsize_str) {
++ memsize = 0x02000000;
++ } else {
++ memsize = simple_strtol(memsize_str, NULL, 0);
++ }
++
++#if 0
++ add_memory_region(0x00000000, PHYS_OFFSET, BOOT_MEM_RESERVED);
++#endif
++ add_memory_region(PHYS_OFFSET, adam2size, BOOT_MEM_ROM_DATA);
++ add_memory_region(PHYS_OFFSET+adam2size, memsize-adam2size,
++ BOOT_MEM_RAM);
++}
++
++unsigned long __init prom_free_prom_memory (void)
++{
++ int i;
++ unsigned long freed = 0;
++ unsigned long addr;
++
++ if (preserve_adam2) {
++ char *firstfree_str = prom_getenv("firstfreeaddress");
++ unsigned long firstfree = 0;
++
++ if (firstfree_str)
++ firstfree = simple_strtol(firstfree_str, NULL, 0);
++
++ if (firstfree && firstfree < (unsigned long)&_ftext) {
++ printk("Preserving ADAM2 memory.\n");
++ } else if (firstfree) {
++ printk("Can't preserve ADAM2 memory, "
++ "firstfreeaddress = %08lx.\n", firstfree);
++ preserve_adam2 = 0;
++ } else {
++ printk("Can't preserve ADAM2 memory, "
++ "firstfreeaddress unknown!\n");
++ preserve_adam2 = 0;
++ }
++ }
++
++ if (!preserve_adam2) {
++ for (i = 0; i < boot_mem_map.nr_map; i++) {
++ if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
++ continue;
++
++ addr = boot_mem_map.map[i].addr;
++ while (addr < boot_mem_map.map[i].addr
++ + boot_mem_map.map[i].size) {
++ ClearPageReserved(virt_to_page(__va(addr)));
++ set_page_count(virt_to_page(__va(addr)), 1);
++ free_page((unsigned long)__va(addr));
++ addr += PAGE_SIZE;
++ freed += PAGE_SIZE;
++ }
++ }
++ printk("Freeing prom memory: %ldkb freed\n", freed >> 10);
++ }
++ return freed >> PAGE_SHIFT;
++}
+diff -urN linux.old/arch/mips/ar7/misc.c linux.dev/arch/mips/ar7/misc.c
+--- linux.old/arch/mips/ar7/misc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/ar7/misc.c 2005-11-10 01:12:43.946955500 +0100
+@@ -0,0 +1,322 @@
++#include <asm/ar7/sangam.h>
++#include <asm/ar7/avalanche_misc.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++
++#define TRUE 1
++
++static unsigned int avalanche_vbus_freq;
++
++REMOTE_VLYNQ_DEV_RESET_CTRL_FN p_remote_vlynq_dev_reset_ctrl = NULL;
++
++/*****************************************************************************
++ * Reset Control Module.
++ *****************************************************************************/
++void avalanche_reset_ctrl(unsigned int module_reset_bit,
++ AVALANCHE_RESET_CTRL_T reset_ctrl)
++{
++ volatile unsigned int *reset_reg = (unsigned int*) AVALANCHE_RST_CTRL_PRCR;
++
++ if(module_reset_bit >= 32 && module_reset_bit < 64)
++ return;
++
++ if(module_reset_bit >= 64)
++ {
++ if(p_remote_vlynq_dev_reset_ctrl) {
++ p_remote_vlynq_dev_reset_ctrl(module_reset_bit - 64, reset_ctrl);
++ return;
++ }
++ else
++ return;
++ }
++
++ if(reset_ctrl == OUT_OF_RESET)
++ *reset_reg |= 1 << module_reset_bit;
++ else
++ *reset_reg &= ~(1 << module_reset_bit);
++ return;
++}
++
++AVALANCHE_RESET_CTRL_T avalanche_get_reset_status(unsigned int module_reset_bit)
++{
++ volatile unsigned int *reset_reg = (unsigned int*) AVALANCHE_RST_CTRL_PRCR;
++
++ return (((*reset_reg) & (1 << module_reset_bit)) ? OUT_OF_RESET : IN_RESET );
++}
++
++void avalanche_sys_reset(AVALANCHE_SYS_RST_MODE_T mode)
++{
++ volatile unsigned int *sw_reset_reg = (unsigned int*) AVALANCHE_RST_CTRL_SWRCR;
++ *sw_reset_reg = mode;
++}
++
++#define AVALANCHE_RST_CTRL_RSR_MASK 0x3
++
++AVALANCHE_SYS_RESET_STATUS_T avalanche_get_sys_last_reset_status()
++{
++ volatile unsigned int *sys_reset_status = (unsigned int*) AVALANCHE_RST_CTRL_RSR;
++
++ return ( (AVALANCHE_SYS_RESET_STATUS_T) (*sys_reset_status & AVALANCHE_RST_CTRL_RSR_MASK) );
++}
++
++
++/*****************************************************************************
++ * Power Control Module
++ *****************************************************************************/
++#define AVALANCHE_GLOBAL_POWER_DOWN_MASK 0x3FFFFFFF /* bit 31, 30 masked */
++#define AVALANCHE_GLOBAL_POWER_DOWN_BIT 30 /* shift to bit 30, 31 */
++
++
++void avalanche_power_ctrl(unsigned int module_power_bit, AVALANCHE_POWER_CTRL_T power_ctrl)
++{
++ volatile unsigned int *power_reg = (unsigned int*)AVALANCHE_POWER_CTRL_PDCR;
++
++ if (power_ctrl == POWER_CTRL_POWER_DOWN)
++ /* power down the module */
++ *power_reg |= (1 << module_power_bit);
++ else
++ /* power on the module */
++ *power_reg &= (~(1 << module_power_bit));
++}
++
++AVALANCHE_POWER_CTRL_T avalanche_get_power_status(unsigned int module_power_bit)
++{
++ volatile unsigned int *power_status_reg = (unsigned int*)AVALANCHE_POWER_CTRL_PDCR;
++
++ return (((*power_status_reg) & (1 << module_power_bit)) ? POWER_CTRL_POWER_DOWN : POWER_CTRL_POWER_UP);
++}
++
++void avalanche_set_global_power_mode(AVALANCHE_SYS_POWER_MODE_T power_mode)
++{
++ volatile unsigned int *power_status_reg = (unsigned int*)AVALANCHE_POWER_CTRL_PDCR;
++
++ *power_status_reg &= AVALANCHE_GLOBAL_POWER_DOWN_MASK;
++ *power_status_reg |= ( power_mode << AVALANCHE_GLOBAL_POWER_DOWN_BIT);
++}
++
++AVALANCHE_SYS_POWER_MODE_T avalanche_get_global_power_mode(void)
++{
++ volatile unsigned int *power_status_reg = (unsigned int*)AVALANCHE_POWER_CTRL_PDCR;
++
++ return((AVALANCHE_SYS_POWER_MODE_T) (((*power_status_reg) & (~AVALANCHE_GLOBAL_POWER_DOWN_MASK))
++ >> AVALANCHE_GLOBAL_POWER_DOWN_BIT));
++}
++
++/*****************************************************************************
++ * GPIO Control
++ *****************************************************************************/
++
++/****************************************************************************
++ * FUNCTION: avalanche_gpio_init
++ ***************************************************************************/
++void avalanche_gpio_init(void)
++{
++ spinlock_t closeLock;
++ unsigned int closeFlag;
++ volatile unsigned int *reset_reg = (unsigned int*) AVALANCHE_RST_CTRL_PRCR;
++ spin_lock_irqsave(&closeLock, closeFlag);
++ *reset_reg |= (1 << AVALANCHE_GPIO_RESET_BIT);
++ spin_unlock_irqrestore(&closeLock, closeFlag);
++}
++
++/****************************************************************************
++ * FUNCTION: avalanche_gpio_ctrl
++ ***************************************************************************/
++int avalanche_gpio_ctrl(unsigned int gpio_pin,
++ AVALANCHE_GPIO_PIN_MODE_T pin_mode,
++ AVALANCHE_GPIO_PIN_DIRECTION_T pin_direction)
++{
++ spinlock_t closeLock;
++ unsigned int closeFlag;
++ volatile unsigned int *gpio_ctrl = (unsigned int*)AVALANCHE_GPIO_ENBL;
++
++ if(gpio_pin >= 32)
++ return(-1);
++
++ spin_lock_irqsave(&closeLock, closeFlag);
++
++ if(pin_mode == GPIO_PIN)
++ {
++ *gpio_ctrl |= (1 << gpio_pin);
++
++ gpio_ctrl = (unsigned int*)AVALANCHE_GPIO_DIR;
++
++ if(pin_direction == GPIO_INPUT_PIN)
++ *gpio_ctrl |= (1 << gpio_pin);
++ else
++ *gpio_ctrl &= ~(1 << gpio_pin);
++ }
++ else /* FUNCTIONAL PIN */
++ {
++ *gpio_ctrl &= ~(1 << gpio_pin);
++ }
++
++ spin_unlock_irqrestore(&closeLock, closeFlag);
++
++ return (0);
++}
++
++/****************************************************************************
++ * FUNCTION: avalanche_gpio_out
++ ***************************************************************************/
++int avalanche_gpio_out_bit(unsigned int gpio_pin, int value)
++{
++ spinlock_t closeLock;
++ unsigned int closeFlag;
++ volatile unsigned int *gpio_out = (unsigned int*) AVALANCHE_GPIO_DATA_OUT;
++
++ if(gpio_pin >= 32)
++ return(-1);
++
++ spin_lock_irqsave(&closeLock, closeFlag);
++ if(value == TRUE)
++ *gpio_out |= 1 << gpio_pin;
++ else
++ *gpio_out &= ~(1 << gpio_pin);
++ spin_unlock_irqrestore(&closeLock, closeFlag);
++
++ return(0);
++}
++
++/****************************************************************************
++ * FUNCTION: avalanche_gpio_in
++ ***************************************************************************/
++int avalanche_gpio_in_bit(unsigned int gpio_pin)
++{
++ spinlock_t closeLock;
++ unsigned int closeFlag;
++ volatile unsigned int *gpio_in = (unsigned int*) AVALANCHE_GPIO_DATA_IN;
++ int ret_val = 0;
++
++ if(gpio_pin >= 32)
++ return(-1);
++
++ spin_lock_irqsave(&closeLock, closeFlag);
++ ret_val = ((*gpio_in) & (1 << gpio_pin));
++ spin_unlock_irqrestore(&closeLock, closeFlag);
++
++ return (ret_val);
++}
++
++/****************************************************************************
++ * FUNCTION: avalanche_gpio_out_val
++ ***************************************************************************/
++int avalanche_gpio_out_value(unsigned int out_val, unsigned int out_mask,
++ unsigned int reg_index)
++{
++ spinlock_t closeLock;
++ unsigned int closeFlag;
++ volatile unsigned int *gpio_out = (unsigned int*) AVALANCHE_GPIO_DATA_OUT;
++
++ if(reg_index > 0)
++ return(-1);
++
++ spin_lock_irqsave(&closeLock, closeFlag);
++ *gpio_out &= ~out_mask;
++ *gpio_out |= out_val;
++ spin_unlock_irqrestore(&closeLock, closeFlag);
++
++ return(0);
++}
++
++/****************************************************************************
++ * FUNCTION: avalanche_gpio_in_value
++ ***************************************************************************/
++int avalanche_gpio_in_value(unsigned int* in_val, unsigned int reg_index)
++{
++ spinlock_t closeLock;
++ unsigned int closeFlag;
++ volatile unsigned int *gpio_in = (unsigned int*) AVALANCHE_GPIO_DATA_IN;
++
++ if(reg_index > 0)
++ return(-1);
++
++ spin_lock_irqsave(&closeLock, closeFlag);
++ *in_val = *gpio_in;
++ spin_unlock_irqrestore(&closeLock, closeFlag);
++
++ return (0);
++}
++
++/***********************************************************************
++ *
++ * Wakeup Control Module for TNETV1050 Communication Processor
++ *
++ ***********************************************************************/
++
++#define AVALANCHE_WAKEUP_POLARITY_BIT 16
++
++void avalanche_wakeup_ctrl(AVALANCHE_WAKEUP_INTERRUPT_T wakeup_int,
++ AVALANCHE_WAKEUP_CTRL_T wakeup_ctrl,
++ AVALANCHE_WAKEUP_POLARITY_T wakeup_polarity)
++{
++ volatile unsigned int *wakeup_status_reg = (unsigned int*) AVALANCHE_WAKEUP_CTRL_WKCR;
++
++ /* enable/disable */
++ if (wakeup_ctrl == WAKEUP_ENABLED)
++ /* enable wakeup */
++ *wakeup_status_reg |= wakeup_int;
++ else
++ /* disable wakeup */
++ *wakeup_status_reg &= (~wakeup_int);
++
++ /* set polarity */
++ if (wakeup_polarity == WAKEUP_ACTIVE_LOW)
++ *wakeup_status_reg |= (wakeup_int << AVALANCHE_WAKEUP_POLARITY_BIT);
++ else
++ *wakeup_status_reg &= ~(wakeup_int << AVALANCHE_WAKEUP_POLARITY_BIT);
++}
++
++void avalanche_set_vbus_freq(unsigned int new_vbus_freq)
++{
++ avalanche_vbus_freq = new_vbus_freq;
++}
++
++unsigned int avalanche_get_vbus_freq()
++{
++ return(avalanche_vbus_freq);
++}
++
++unsigned int avalanche_get_chip_version_info()
++{
++ return(*(volatile unsigned int*)AVALANCHE_CVR);
++}
++
++SET_MDIX_ON_CHIP_FN_T p_set_mdix_on_chip_fn = NULL;
++
++int avalanche_set_mdix_on_chip(unsigned int base_addr, unsigned int operation)
++{
++ if(p_set_mdix_on_chip_fn)
++ return (p_set_mdix_on_chip_fn(base_addr, operation));
++ else
++ return(-1);
++}
++
++unsigned int avalanche_is_mdix_on_chip(void)
++{
++ return(p_set_mdix_on_chip_fn ? 1:0);
++}
++
++EXPORT_SYMBOL(avalanche_reset_ctrl);
++EXPORT_SYMBOL(avalanche_get_reset_status);
++EXPORT_SYMBOL(avalanche_sys_reset);
++EXPORT_SYMBOL(avalanche_get_sys_last_reset_status);
++EXPORT_SYMBOL(avalanche_power_ctrl);
++EXPORT_SYMBOL(avalanche_get_power_status);
++EXPORT_SYMBOL(avalanche_set_global_power_mode);
++EXPORT_SYMBOL(avalanche_get_global_power_mode);
++EXPORT_SYMBOL(avalanche_set_mdix_on_chip);
++EXPORT_SYMBOL(avalanche_is_mdix_on_chip);
++
++EXPORT_SYMBOL(avalanche_gpio_init);
++EXPORT_SYMBOL(avalanche_gpio_ctrl);
++EXPORT_SYMBOL(avalanche_gpio_out_bit);
++EXPORT_SYMBOL(avalanche_gpio_in_bit);
++EXPORT_SYMBOL(avalanche_gpio_out_value);
++EXPORT_SYMBOL(avalanche_gpio_in_value);
++
++EXPORT_SYMBOL(avalanche_set_vbus_freq);
++EXPORT_SYMBOL(avalanche_get_vbus_freq);
++
++EXPORT_SYMBOL(avalanche_get_chip_version_info);
++
+diff -urN linux.old/arch/mips/ar7/platform.h linux.dev/arch/mips/ar7/platform.h
+--- linux.old/arch/mips/ar7/platform.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/ar7/platform.h 2005-11-10 01:10:45.799571750 +0100
+@@ -0,0 +1,65 @@
++#ifndef _PLATFORM_H_
++#define _PLATFORM_H_
++
++#include <linux/config.h>
++
++
++/* Important: The definition of ENV_SPACE_SIZE should match with that in
++ * PSPBoot. (/psp_boot/inc/psbl/env.h)
++ */
++#ifdef CONFIG_MIPS_AVALANCHE_TICFG
++#define ENV_SPACE_SIZE (10 * 1024)
++#endif
++
++#ifdef CONFIG_MIPS_TNETV1050SDB
++#define TNETV1050SDB
++#define DUAL_FLASH
++#endif
++
++#ifdef CONFIG_MIPS_AR7DB
++#define TNETD73XX_BOARD
++#define AR7DB
++#endif
++
++#ifdef CONFIG_MIPS_AR7RD
++#define TNETD73XX_BOARD
++#define AR7RD
++#endif
++
++#ifdef CONFIG_AR7WRD
++#define TNETD73XX_BOARD
++#define AR7WRD
++#endif
++
++#ifdef CONFIG_MIPS_AR7VWI
++#define TNETD73XX_BOARD
++#define AR7VWi
++#endif
++
++/* Merging from the DEV_DSL-PSPL4.3.2.7_Patch release. */
++#ifdef CONFIG_MIPS_AR7VW
++#define TNETD73XX_BOARD
++#define AR7WRD
++#endif
++
++#ifdef CONFIG_MIPS_AR7WI
++#define TNETD73XX_BOARD
++#define AR7Wi
++#endif
++
++#ifdef CONFIG_MIPS_AR7V
++#define TNETD73XX_BOARD
++#define AR7V
++#endif
++
++#ifdef CONFIG_MIPS_AR7V
++#define TNETD73XX_BOARD
++#define AR7V
++#endif
++
++#ifdef CONFIG_MIPS_WA1130
++#define AVALANCHE
++#define WLAN
++#endif
++
++#endif
+diff -urN linux.old/arch/mips/ar7/promlib.c linux.dev/arch/mips/ar7/promlib.c
+--- linux.old/arch/mips/ar7/promlib.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/ar7/promlib.c 2005-11-10 01:14:16.372731750 +0100
+@@ -0,0 +1,48 @@
++/*
++ * Carsten Langgaard, carstenl@mips.com
++ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
++ *
++ * This program is free software; you can distribute it and/or modify it
++ * under the terms of the GNU General Public License (Version 2) as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope 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.
++ *
++ * Putting things on the screen/serial line using Adam2 facilities.
++ */
++
++#include <linux/types.h>
++#include <asm/addrspace.h>
++
++#define AVALANCHE_YAMON_FUNCTION_BASE (KSEG1ADDR(0x10000500))
++#define AVALANCHE_YAMON_PROM_PRINT_COUNT_ADDR \
++ (AVALANCHE_YAMON_FUNCTION_BASE + 1 * 0x4)
++#define AVALANCHE_YAMON_PROM_EXIT \
++ (AVALANCHE_YAMON_FUNCTION_BASE + 8 * 0x4)
++
++void prom_putchar(char c)
++{
++ static char buf[1];
++ void (*prom_print_str)(unsigned int dummy, char *s, int len) =
++ (void *)(*(uint32_t *)AVALANCHE_YAMON_PROM_PRINT_COUNT_ADDR);
++
++ buf[0] = c;
++ prom_print_str(1, buf, 1);
++ return;
++}
++
++void adam2_exit(int retval)
++{
++ void (*yamon_exit)(int retval) =
++ (void *)(*(uint32_t *)AVALANCHE_YAMON_PROM_EXIT);
++
++ yamon_exit(retval);
++ return;
++}
+diff -urN linux.old/arch/mips/ar7/psp_env.c linux.dev/arch/mips/ar7/psp_env.c
+--- linux.old/arch/mips/ar7/psp_env.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/ar7/psp_env.c 2005-11-10 01:10:45.799571750 +0100
+@@ -0,0 +1,350 @@
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <asm/io.h>
++
++#include "platform.h"
++
++#define ENV_CELL_SIZE 16
++
++/* control field decode */
++#define ENV_GARBAGE_BIT 0x01 /* Env is garbage if this bit is off */
++#define ENV_DYNAMIC_BIT 0x02 /* Env is dynamic if this bit is off */
++
++#define ENV_CTRL_MASK 0x03
++#define ENV_PREFINED (ENV_GARBAGE_BIT | ENV_DYNAMIC_BIT)
++#define ENV_DYNAMIC (ENV_GARBAGE_BIT)
++
++struct env_variable {
++ unsigned char varNum;
++ unsigned char ctrl;
++ unsigned short chksum;
++ unsigned char numCells;
++ unsigned char data[ENV_CELL_SIZE - 5]; /* The data section starts
++ * here, continues for
++ * numCells.
++ */
++};
++
++extern unsigned int max_env_entry;
++
++/* Internal macros */
++#define get_next_block(var) ((struct env_variable *)( (char*)(var) + (var)->numCells * ENV_CELL_SIZE))
++
++typedef enum ENV_VARS {
++ env_vars_start = 0,
++ CPUFREQ,
++ MEMSZ,
++ FLASHSZ,
++ MODETTY0,
++ MODETTY1,
++ PROMPT,
++ BOOTCFG,
++ HWA_0,
++#if !defined (AVALANCHE) || defined(TNETC401B)
++ HWA_1,
++#endif
++#if !defined(TNETV1020_BOARD)
++ HWA_RNDIS,
++#endif
++#if defined (TNETD73XX_BOARD)
++ HWA_3,
++#endif
++ IPA,
++ IPA_SVR,
++ BLINE_MAC0,
++#if !defined (AVALANCHE) || defined(TNETC401B)
++ BLINE_MAC1,
++#endif
++#if !defined(TNETV1020_BOARD)
++ BLINE_RNDIS,
++#endif
++#if defined (TNETD73XX_BOARD)
++ BLINE_ATM,
++#endif
++#if !defined(TNETV1020_BOARD)
++ USB_PID,
++ USB_VID,
++ USB_EPPOLLI,
++#endif
++ IPA_GATEWAY,
++ SUBNET_MASK,
++#if defined (TNETV1050_BOARD)
++ BLINE_ESWITCH,
++#endif
++#if !defined(TNETV1020_BOARD)
++ USB_SERIAL,
++ HWA_HRNDIS, /* Host (PC) side RNDIS address */
++#endif
++ REMOTE_USER,
++ REMOTE_PASS,
++ REMOTE_DIR,
++ SYSFREQ,
++ LINK_TIMEOUT,
++#ifndef AVALANCHE /* Avalanche boards use only one mac port */
++ MAC_PORT,
++#endif
++ PATH,
++ HOSTNAME,
++#ifdef WLAN
++ HW_REV_MAJOR,
++ HW_REV_MINOR,
++ HW_PATCH,
++ SW_PATCH,
++ SERIAL_NUMBER,
++#endif
++ TFTPCFG,
++#if defined (TNETV1050_BOARD)
++ HWA_ESWITCH,
++#endif
++ /*
++ * Add new env variables here.
++ * NOTE: New environment variables should always be placed at the end, ie
++ * just before env_vars_end.
++ */
++
++ env_vars_end
++} ENV_VARS;
++
++
++struct env_description {
++ ENV_VARS idx;
++ char *nm;
++ char *alias;
++};
++
++#define ENVSTR(x) #x
++#define _ENV_ENTRY(x) {.idx = x, .nm = ENVSTR(x), .alias = NULL}
++
++struct env_description env_ns[] = {
++ _ENV_ENTRY(env_vars_start), /* start. */
++ _ENV_ENTRY(CPUFREQ),
++ _ENV_ENTRY(MEMSZ),
++ _ENV_ENTRY(FLASHSZ),
++ _ENV_ENTRY(MODETTY0),
++ _ENV_ENTRY(MODETTY1),
++ _ENV_ENTRY(PROMPT),
++ _ENV_ENTRY(BOOTCFG),
++ _ENV_ENTRY(HWA_0),
++#if !defined (AVALANCHE) || defined(TNETC401B)
++ _ENV_ENTRY(HWA_1),
++#endif
++#if !defined(TNETV1020_BOARD)
++ _ENV_ENTRY(HWA_RNDIS),
++#endif
++#if defined (TNETD73XX_BOARD)
++ _ENV_ENTRY(HWA_3),
++#endif
++ _ENV_ENTRY(IPA),
++ _ENV_ENTRY(IPA_SVR),
++ _ENV_ENTRY(IPA_GATEWAY),
++ _ENV_ENTRY(SUBNET_MASK),
++ _ENV_ENTRY(BLINE_MAC0),
++#if !defined (AVALANCHE) || defined(TNETC401B)
++ _ENV_ENTRY(BLINE_MAC1),
++#endif
++#if !defined(TNETV1020_BOARD)
++ _ENV_ENTRY(BLINE_RNDIS),
++#endif
++#if defined (TNETD73XX_BOARD)
++ _ENV_ENTRY(BLINE_ATM),
++#endif
++#if !defined(TNETV1020_BOARD)
++ _ENV_ENTRY(USB_PID),
++ _ENV_ENTRY(USB_VID),
++ _ENV_ENTRY(USB_EPPOLLI),
++#endif
++#if defined (TNETV1050_BOARD)
++ _ENV_ENTRY(BLINE_ESWITCH),
++#endif
++#if !defined(TNETV1020_BOARD)
++ _ENV_ENTRY(USB_SERIAL),
++ _ENV_ENTRY(HWA_HRNDIS),
++#endif
++ _ENV_ENTRY(REMOTE_USER),
++ _ENV_ENTRY(REMOTE_PASS),
++ _ENV_ENTRY(REMOTE_DIR),
++ _ENV_ENTRY(SYSFREQ),
++ _ENV_ENTRY(LINK_TIMEOUT),
++#ifndef AVALANCHE /* Avalanche boards use only one mac port */
++ _ENV_ENTRY(MAC_PORT),
++#endif
++ _ENV_ENTRY(PATH),
++ _ENV_ENTRY(HOSTNAME),
++#ifdef WLAN
++ _ENV_ENTRY(HW_REV_MAJOR),
++ _ENV_ENTRY(HW_REV_MINOR),
++ _ENV_ENTRY(HW_PATCH),
++ _ENV_ENTRY(SW_PATCH),
++ _ENV_ENTRY(SERIAL_NUMBER),
++#endif
++ _ENV_ENTRY(TFTPCFG),
++#if defined (TNETV1050_BOARD)
++ _ENV_ENTRY(HWA_ESWITCH),
++#endif
++ /*
++ * Add new entries below this.
++ */
++ /* Adam2 environment name alias. */
++ { .idx = IPA, .nm = "my_ipaddress" },
++ { .idx = CPUFREQ, .nm = "cpufrequency" },
++ { .idx = SYSFREQ, .nm = "sysfrequency" },
++ { .idx = HWA_0, .nm = "maca" },
++#ifndef AVALANCHE
++ { .idx = HWA_1, .nm = "macb" },
++#endif
++ { .idx = MODETTY0, .nm = "modetty0" },
++ { .idx = MODETTY1, .nm = "modetty1" },
++ { .idx = MEMSZ, .nm = "memsize" },
++
++ _ENV_ENTRY(env_vars_end) /* delimiter. */
++};
++
++static inline int var_to_idx(const char* var)
++{
++ int ii;
++
++ /* go over the list of pre-defined environment variables */
++ for (ii = env_vars_start; env_ns[ii].idx != env_vars_end; ii++){
++ /* check if the env variable is listed */
++ if (strcmp(env_ns[ii].nm, var) == 0) {
++ return env_ns[ii].idx;
++ }
++
++ /* if an alias is present, check if the alias matches
++ * the description
++ */
++ if (env_ns[ii].alias != NULL) {
++ if (strcmp(env_ns[ii].alias, var) == 0) {
++ return env_ns[ii].idx;
++ }
++ }
++ }
++ return 0;
++}
++
++extern int *_prom_envp;
++
++/* FIXME: reading from the flash is extremly unstable. Sometime a read returns garbage,
++ * the next read some seconds later is ok. It looks like something is hidding or
++ * overlay the flash address at 0xb0000000. Is this possible?
++ *
++ * The readb() and while() usage below is a attempt of a workarround - with limited success.
++ */
++
++static inline struct env_variable* get_var_by_number(int index)
++{
++ struct env_variable *env_var = (struct env_variable *)_prom_envp;
++ volatile unsigned char nr;
++ int i;
++
++ env_var++; /* skip signature */
++
++ i = 0;
++ nr = readb(&(env_var->varNum));
++
++ while (i < max_env_entry && nr != 0xFF) {
++ if ((env_var->ctrl & ENV_CTRL_MASK) == ENV_PREFINED) {
++ if (nr == index) {
++ return env_var;
++ }
++ }
++ i++;
++ env_var = get_next_block(env_var);
++ nr = readb(&(env_var->varNum));
++ }
++
++ return NULL;
++}
++
++static inline struct env_variable* get_var_by_name(char *var)
++{
++ struct env_variable *env_var = (struct env_variable *)_prom_envp;
++ volatile unsigned char nr;
++ int i;
++
++ env_var++; /* skip signature */
++
++ nr = readb(&(env_var->varNum));
++ i = 0;
++
++ while (i < max_env_entry && nr != 0xFF) {
++ if ((env_var->ctrl & ENV_CTRL_MASK) == ENV_DYNAMIC) {
++ if (strcmp(var, env_var->data) == 0)
++ return env_var;
++ }
++ i++;
++ env_var = get_next_block(env_var);
++ nr = readb(&(env_var->varNum));
++ }
++ return NULL;
++}
++
++static inline struct env_variable* get_var(char *var)
++{
++ int index = var_to_idx(var);
++
++ if (index)
++ return get_var_by_number(index);
++ else
++ return get_var_by_name(var);
++
++ return NULL;
++}
++
++static inline char *get_value(struct env_variable* env_var)
++{
++ unsigned char *name;
++ unsigned char *value;
++ unsigned short chksum;
++ int i;
++
++ chksum = env_var->varNum + env_var->ctrl + env_var->numCells;
++
++ if ((env_var->ctrl & ENV_CTRL_MASK) == ENV_DYNAMIC) {
++ name = env_var->data;
++ value = env_var->data + strlen(name) + 1;
++
++ for(i = 0; i < strlen(name); i++)
++ chksum += name[i];
++ } else
++ value = env_var->data;
++
++ for (i = 0; i < strlen(value); i++)
++ chksum += value[i];
++
++ chksum += env_var->chksum;
++ chksum = ~(chksum);
++
++ if(chksum != 0) {
++ return NULL;
++ }
++
++ return value;
++}
++
++struct psbl_rec {
++ unsigned int psbl_size;
++ unsigned int env_base;
++ unsigned int env_size;
++ unsigned int ffs_base;
++ unsigned int ffs_size;
++};
++
++char *prom_psp_getenv(char *envname)
++{
++ struct env_variable* env_var;
++ char *value;
++
++ if (strcmp("bootloader", envname) == 0)
++ return "PSPBoot";
++
++ if (!(env_var = get_var(envname)))
++ return NULL;
++
++ value = get_value(env_var);
++
++ return value;
++}
+diff -urN linux.old/arch/mips/ar7/reset.c linux.dev/arch/mips/ar7/reset.c
+--- linux.old/arch/mips/ar7/reset.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/ar7/reset.c 2005-11-10 01:14:16.372731750 +0100
+@@ -0,0 +1,98 @@
++/*
++ * Carsten Langgaard, carstenl@mips.com
++ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
++ *
++ * ########################################################################
++ *
++ * This program is free software; you can distribute it and/or modify it
++ * under the terms of the GNU General Public License (Version 2) as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope 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.
++ *
++ * ########################################################################
++ *
++ * Reset the AR7 boards.
++ *
++ */
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/types.h>
++
++#include <asm/mipsregs.h>
++#include <asm/reboot.h>
++#include <asm/addrspace.h>
++
++int preserve_adam2 = 1;
++
++extern void adam2_exit(int retval);
++
++static void ar7_machine_restart(char *command);
++static void ar7_machine_halt(void);
++static void ar7_machine_power_off(void);
++
++static void ar7_machine_restart(char *command)
++{
++ volatile uint32_t *softres_reg = (void *)(KSEG1ADDR(0x08611600 + 0x4));
++
++ *softres_reg = 1;
++}
++
++static void ar7_machine_halt(void)
++{
++
++ if (preserve_adam2) {
++ set_c0_status(ST0_BEV);
++ adam2_exit(0);
++ } else {
++ /* I'd like to have Alt-SysRq-b work in this state.
++ * What's missing here? The timer interrupt is still running.
++ * Why doesn't the UART work anymore? */
++ while(1) {
++ __asm__(".set\tmips3\n\t"
++ "wait\n\t"
++ ".set\tmips0");
++ }
++ }
++}
++
++static void ar7_machine_power_off(void)
++{
++ volatile uint32_t *power_reg = (void *)(KSEG1ADDR(0x08610A00));
++ uint32_t power_state = *power_reg;
++
++ /* add something to turn LEDs off? */
++
++ power_state &= ~(3 << 30);
++ power_state |= (3 << 30); /* power down */
++ *power_reg = power_state;
++
++ printk("after power down?\n");
++}
++
++void ar7_reboot_setup(void)
++{
++ _machine_restart = ar7_machine_restart;
++ _machine_halt = ar7_machine_halt;
++ _machine_power_off = ar7_machine_power_off;
++}
++
++static int __init ar7_do_preserve_adam2(char *s)
++{
++ if (!strcmp(s, "no") || !strcmp(s, "0"))
++ preserve_adam2 = 0;
++ else
++ preserve_adam2 = 1;
++ return 1;
++}
++
++__setup("adam2=", ar7_do_preserve_adam2);
+diff -urN linux.old/arch/mips/ar7/setup.c linux.dev/arch/mips/ar7/setup.c
+--- linux.old/arch/mips/ar7/setup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/ar7/setup.c 2005-11-10 01:12:43.946955500 +0100
+@@ -0,0 +1,143 @@
++/*
++ * Carsten Langgaard, carstenl@mips.com
++ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
++ *
++ * This program is free software; you can distribute it and/or modify it
++ * under the terms of the GNU General Public License (Version 2) as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/string.h>
++#include <linux/irq.h>
++
++#include <asm/processor.h>
++#include <asm/irq.h>
++#include <asm/irq_cpu.h>
++#include <asm/time.h>
++#include <asm/mipsregs.h>
++#include <asm/mips-boards/prom.h>
++
++#ifdef CONFIG_KGDB
++extern void rs_kgdb_hook(int);
++extern void breakpoint(void);
++int remote_debug = 0;
++#endif
++
++extern void ar7_reboot_setup(void);
++extern void ar7_irq_init(int);
++extern asmlinkage void ar7IRQ(void);
++
++void ar7_time_init(void)
++{
++ /* XXX runtime */
++ mips_hpt_frequency = CONFIG_AR7_CPU * 500000;
++}
++
++void ar7_timer_setup(struct irqaction *irq)
++{
++ setup_irq(7, irq);
++ set_c0_status(IE_IRQ5);
++}
++
++void __init init_IRQ(void)
++{
++ init_generic_irq();
++ mips_cpu_irq_init(0);
++ ar7_irq_init(8);
++
++ /* Now safe to set the exception vector. */
++ set_except_vector(0, ar7IRQ);
++
++#ifdef CONFIG_KGDB
++ if (remote_debug)
++ {
++ set_debug_traps();
++ breakpoint();
++ }
++#endif
++}
++
++const char *get_system_type(void)
++{
++ return "Texas Instruments AR7";
++}
++
++void __init ar7_setup(void)
++{
++#ifdef CONFIG_KGDB
++ int rs_putDebugChar(char);
++ char rs_getDebugChar(void);
++ extern int (*generic_putDebugChar)(char);
++ extern char (*generic_getDebugChar)(void);
++#endif
++ char *argptr;
++#ifdef CONFIG_SERIAL_CONSOLE
++ argptr = prom_getcmdline();
++ if ((argptr = strstr(argptr, "console=")) == NULL) {
++ char console[20];
++ char *s;
++ int i = 0;
++
++ s = prom_getenv("modetty0");
++ strcpy(console, "38400");
++
++ if (s != NULL) {
++ while (s[i] >= '0' && s[i] <= '9')
++ i++;
++
++ if (i > 0) {
++ strncpy(console, s, i);
++ console[i] = 0;
++ }
++ }
++
++ argptr = prom_getcmdline();
++ strcat(argptr, " console=ttyS0,");
++ strcat(argptr, console);
++ }
++#endif
++
++#ifdef CONFIG_KGDB
++ argptr = prom_getcmdline();
++ if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) {
++ int line;
++ argptr += strlen("kgdb=ttyS");
++ if (*argptr != '0' && *argptr != '1')
++ printk("KGDB: Uknown serial line /dev/ttyS%c, "
++ "falling back to /dev/ttyS1\n", *argptr);
++ line = *argptr == '0' ? 0 : 1;
++ printk("KGDB: Using serial line /dev/ttyS%d for session\n",
++ line ? 1 : 0);
++
++ rs_kgdb_hook(line);
++ generic_putDebugChar = rs_putDebugChar;
++ generic_getDebugChar = rs_getDebugChar;
++
++ prom_printf("KGDB: Using serial line /dev/ttyS%d for session, "
++ "please connect your debugger\n", line ? 1 : 0);
++
++ remote_debug = 1;
++ /* Breakpoints are in init_IRQ() */
++ }
++#endif
++
++ argptr = prom_getcmdline();
++ if ((argptr = strstr(argptr, "nofpu")) != NULL)
++ cpu_data[0].options &= ~MIPS_CPU_FPU;
++
++ ar7_reboot_setup();
++
++ board_time_init = ar7_time_init;
++ board_timer_setup = ar7_timer_setup;
++}
+diff -urN linux.old/arch/mips/ar7/tnetd73xx_misc.c linux.dev/arch/mips/ar7/tnetd73xx_misc.c
+--- linux.old/arch/mips/ar7/tnetd73xx_misc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/ar7/tnetd73xx_misc.c 2005-11-10 01:12:43.946955500 +0100
+@@ -0,0 +1,921 @@
++/******************************************************************************
++ * FILE PURPOSE: TNETD73xx Misc modules API Source
++ ******************************************************************************
++ * FILE NAME: tnetd73xx_misc.c
++ *
++ * DESCRIPTION: Clock Control, Reset Control, Power Management, GPIO
++ * FSER Modules API
++ * As per TNETD73xx specifications
++ *
++ * REVISION HISTORY:
++ * 27 Nov 02 - Sharath Kumar PSP TII
++ * 14 Feb 03 - Anant Gole PSP TII
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++#include <linux/types.h>
++#include <asm/ar7/tnetd73xx.h>
++#include <asm/ar7/tnetd73xx_misc.h>
++
++/* TNETD73XX Revision */
++u32 tnetd73xx_get_revision(void)
++{
++ /* Read Chip revision register - This register is from GPIO module */
++ return ( (u32) REG32_DATA(TNETD73XX_CVR));
++}
++
++/*****************************************************************************
++ * Reset Control Module
++ *****************************************************************************/
++
++
++void tnetd73xx_reset_ctrl(TNETD73XX_RESET_MODULE_T reset_module, TNETD73XX_RESET_CTRL_T reset_ctrl)
++{
++ u32 reset_status;
++
++ /* read current reset register */
++ REG32_READ(TNETD73XX_RST_CTRL_PRCR, reset_status);
++
++ if (reset_ctrl == OUT_OF_RESET)
++ {
++ /* bring module out of reset */
++ reset_status |= (1 << reset_module);
++ }
++ else
++ {
++ /* put module in reset */
++ reset_status &= (~(1 << reset_module));
++ }
++
++ /* write to the reset register */
++ REG32_WRITE(TNETD73XX_RST_CTRL_PRCR, reset_status);
++}
++
++
++TNETD73XX_RESET_CTRL_T tnetd73xx_get_reset_status (TNETD73XX_RESET_MODULE_T reset_module)
++{
++ u32 reset_status;
++
++ REG32_READ(TNETD73XX_RST_CTRL_PRCR, reset_status);
++ return ( (reset_status & (1 << reset_module)) ? OUT_OF_RESET : IN_RESET );
++}
++
++void tnetd73xx_sys_reset(TNETD73XX_SYS_RST_MODE_T mode)
++{
++ REG32_WRITE(TNETD73XX_RST_CTRL_SWRCR, mode);
++}
++
++#define TNETD73XX_RST_CTRL_RSR_MASK 0x3
++
++TNETD73XX_SYS_RESET_STATUS_T tnetd73xx_get_sys_last_reset_status()
++{
++ u32 sys_reset_status;
++
++ REG32_READ(TNETD73XX_RST_CTRL_RSR, sys_reset_status);
++
++ return ( (TNETD73XX_SYS_RESET_STATUS_T) (sys_reset_status & TNETD73XX_RST_CTRL_RSR_MASK) );
++}
++
++
++/*****************************************************************************
++ * Power Control Module
++ *****************************************************************************/
++#define TNETD73XX_GLOBAL_POWER_DOWN_MASK 0x3FFFFFFF /* bit 31, 30 masked */
++#define TNETD73XX_GLOBAL_POWER_DOWN_BIT 30 /* shift to bit 30, 31 */
++
++
++void tnetd73xx_power_ctrl(TNETD73XX_POWER_MODULE_T power_module, TNETD73XX_POWER_CTRL_T power_ctrl)
++{
++ u32 power_status;
++
++ /* read current power down control register */
++ REG32_READ(TNETD73XX_POWER_CTRL_PDCR, power_status);
++
++ if (power_ctrl == POWER_CTRL_POWER_DOWN)
++ {
++ /* power down the module */
++ power_status |= (1 << power_module);
++ }
++ else
++ {
++ /* power on the module */
++ power_status &= (~(1 << power_module));
++ }
++
++ /* write to the reset register */
++ REG32_WRITE(TNETD73XX_POWER_CTRL_PDCR, power_status);
++}
++
++TNETD73XX_POWER_CTRL_T tnetd73xx_get_pwr_status(TNETD73XX_POWER_MODULE_T power_module)
++{
++ u32 power_status;
++
++ /* read current power down control register */
++ REG32_READ(TNETD73XX_POWER_CTRL_PDCR, power_status);
++
++ return ( (power_status & (1 << power_module)) ? POWER_CTRL_POWER_DOWN : POWER_CTRL_POWER_UP );
++}
++
++void tnetd73xx_set_global_pwr_mode(TNETD73XX_SYS_POWER_MODE_T power_mode)
++{
++ u32 power_status;
++
++ /* read current power down control register */
++ REG32_READ(TNETD73XX_POWER_CTRL_PDCR, power_status);
++
++ power_status &= TNETD73XX_GLOBAL_POWER_DOWN_MASK;
++ power_status |= ( power_mode << TNETD73XX_GLOBAL_POWER_DOWN_BIT);
++
++ /* write to power down control register */
++ REG32_WRITE(TNETD73XX_POWER_CTRL_PDCR, power_status);
++}
++
++TNETD73XX_SYS_POWER_MODE_T tnetd73xx_get_global_pwr_mode()
++{
++ u32 power_status;
++
++ /* read current power down control register */
++ REG32_READ(TNETD73XX_POWER_CTRL_PDCR, power_status);
++
++ power_status &= (~TNETD73XX_GLOBAL_POWER_DOWN_MASK);
++ power_status = ( power_status >> TNETD73XX_GLOBAL_POWER_DOWN_BIT);
++
++ return ( (TNETD73XX_SYS_POWER_MODE_T) power_status );
++}
++
++
++/*****************************************************************************
++ * Wakeup Control
++ *****************************************************************************/
++
++#define TNETD73XX_WAKEUP_POLARITY_BIT 16
++
++void tnetd73xx_wakeup_ctrl(TNETD73XX_WAKEUP_INTERRUPT_T wakeup_int,
++ TNETD73XX_WAKEUP_CTRL_T wakeup_ctrl,
++ TNETD73XX_WAKEUP_POLARITY_T wakeup_polarity)
++{
++ u32 wakeup_status;
++
++ /* read the wakeup control register */
++ REG32_READ(TNETD73XX_POWER_CTRL_WKCR, wakeup_status);
++
++ /* enable/disable */
++ if (wakeup_ctrl == WAKEUP_ENABLED)
++ {
++ /* enable wakeup */
++ wakeup_status |= wakeup_int;
++ }
++ else
++ {
++ /* disable wakeup */
++ wakeup_status &= (~wakeup_int);
++ }
++
++ /* set polarity */
++ if (wakeup_polarity == WAKEUP_ACTIVE_LOW)
++ {
++ wakeup_status |= (wakeup_int << TNETD73XX_WAKEUP_POLARITY_BIT);
++ }
++ else
++ {
++ wakeup_status &= ~(wakeup_int << TNETD73XX_WAKEUP_POLARITY_BIT);
++ }
++
++ /* write the wakeup control register */
++ REG32_WRITE(TNETD73XX_POWER_CTRL_WKCR, wakeup_status);
++}
++
++
++/*****************************************************************************
++ * FSER Control
++ *****************************************************************************/
++
++void tnetd73xx_fser_ctrl(TNETD73XX_FSER_MODE_T fser_mode)
++{
++ REG32_WRITE(TNETD73XX_FSER_BASE, fser_mode);
++}
++
++/*****************************************************************************
++ * Clock Control
++ *****************************************************************************/
++
++#define MIN(x,y) ( ((x) < (y)) ? (x) : (y) )
++#define MAX(x,y) ( ((x) > (y)) ? (x) : (y) )
++#define ABS(x) ( ((signed)(x) > 0) ? (x) : (-(x)) )
++#define CEIL(x,y) ( ((x) + (y) / 2) / (y) )
++
++#define CLKC_CLKCR(x) (TNETD73XX_CLOCK_CTRL_BASE + 0x20 + (0x20 * (x)))
++#define CLKC_CLKPLLCR(x) (TNETD73XX_CLOCK_CTRL_BASE + 0x30 + (0x20 * (x)))
++
++#define CLKC_PRE_DIVIDER 0x0000001F
++#define CLKC_POST_DIVIDER 0x001F0000
++
++#define CLKC_PLL_STATUS 0x1
++#define CLKC_PLL_FACTOR 0x0000F000
++
++#define BOOTCR_PLL_BYPASS (1 << 5)
++#define BOOTCR_MIPS_ASYNC_MODE (1 << 25)
++
++#define MIPS_PLL_SELECT 0x00030000
++#define SYSTEM_PLL_SELECT 0x0000C000
++#define USB_PLL_SELECT 0x000C0000
++#define ADSLSS_PLL_SELECT 0x00C00000
++
++#define MIPS_AFECLKI_SELECT 0x00000000
++#define MIPS_REFCLKI_SELECT 0x00010000
++#define MIPS_XTAL3IN_SELECT 0x00020000
++
++#define SYSTEM_AFECLKI_SELECT 0x00000000
++#define SYSTEM_REFCLKI_SELECT 0x00004000
++#define SYSTEM_XTAL3IN_SELECT 0x00008000
++#define SYSTEM_MIPSPLL_SELECT 0x0000C000
++
++#define USB_SYSPLL_SELECT 0x00000000
++#define USB_REFCLKI_SELECT 0x00040000
++#define USB_XTAL3IN_SELECT 0x00080000
++#define USB_MIPSPLL_SELECT 0x000C0000
++
++#define ADSLSS_AFECLKI_SELECT 0x00000000
++#define ADSLSS_REFCLKI_SELECT 0x00400000
++#define ADSLSS_XTAL3IN_SELECT 0x00800000
++#define ADSLSS_MIPSPLL_SELECT 0x00C00000
++
++#define SYS_MAX CLK_MHZ(150)
++#define SYS_MIN CLK_MHZ(1)
++
++#define MIPS_SYNC_MAX SYS_MAX
++#define MIPS_ASYNC_MAX CLK_MHZ(160)
++#define MIPS_MIN CLK_MHZ(1)
++
++#define USB_MAX CLK_MHZ(100)
++#define USB_MIN CLK_MHZ(1)
++
++#define ADSL_MAX CLK_MHZ(180)
++#define ADSL_MIN CLK_MHZ(1)
++
++#define PLL_MUL_MAXFACTOR 15
++#define MAX_DIV_VALUE 32
++#define MIN_DIV_VALUE 1
++
++#define MIN_PLL_INP_FREQ CLK_MHZ(8)
++#define MAX_PLL_INP_FREQ CLK_MHZ(100)
++
++#define DIVIDER_LOCK_TIME 10100
++#define PLL_LOCK_TIME 10100 * 75
++
++
++
++ /****************************************************************************
++ * DATA PURPOSE: PRIVATE Variables
++ **************************************************************************/
++ static u32 *clk_src[4];
++ static u32 mips_pll_out;
++ static u32 sys_pll_out;
++ static u32 afeclk_inp;
++ static u32 refclk_inp;
++ static u32 xtal_inp;
++ static u32 present_min;
++ static u32 present_max;
++
++ /* Forward References */
++ static u32 find_gcd(u32 min, u32 max);
++ static u32 compute_prediv( u32 divider, u32 min, u32 max);
++ static void get_val(u32 base_freq, u32 output_freq,u32 *multiplier, u32 *divider);
++ static u32 get_base_frequency(TNETD73XX_CLKC_ID_T clk_id);
++ static void find_approx(u32 *,u32 *,u32);
++
++ /****************************************************************************
++ * FUNCTION: tnetd73xx_clkc_init
++ ****************************************************************************
++ * Description: The routine initializes the internal variables depending on
++ * on the sources selected for different clocks.
++ ***************************************************************************/
++void tnetd73xx_clkc_init(u32 afeclk, u32 refclk, u32 xtal3in)
++{
++
++ u32 choice;
++
++ afeclk_inp = afeclk;
++ refclk_inp = refclk;
++ xtal_inp = xtal3in;
++
++ choice = REG32_DATA(TNETD73XX_DCL_BOOTCR) & MIPS_PLL_SELECT;
++ switch(choice)
++ {
++ case MIPS_AFECLKI_SELECT:
++ clk_src[CLKC_MIPS] = &afeclk_inp;
++ break;
++
++ case MIPS_REFCLKI_SELECT:
++ clk_src[CLKC_MIPS] = &refclk_inp;
++ break;
++
++ case MIPS_XTAL3IN_SELECT:
++ clk_src[CLKC_MIPS] = &xtal_inp;
++ break;
++
++ default :
++ clk_src[CLKC_MIPS] = 0;
++
++ }
++
++ choice = REG32_DATA(TNETD73XX_DCL_BOOTCR) & SYSTEM_PLL_SELECT;
++ switch(choice)
++ {
++ case SYSTEM_AFECLKI_SELECT:
++ clk_src[CLKC_SYS] = &afeclk_inp;
++ break;
++
++ case SYSTEM_REFCLKI_SELECT:
++ clk_src[CLKC_SYS] = &refclk_inp;
++ break;
++
++ case SYSTEM_XTAL3IN_SELECT:
++ clk_src[CLKC_SYS] = &xtal_inp;
++ break;
++
++ case SYSTEM_MIPSPLL_SELECT:
++ clk_src[CLKC_SYS] = &mips_pll_out;
++ break;
++
++ default :
++ clk_src[CLKC_SYS] = 0;
++
++ }
++
++
++ choice = REG32_DATA(TNETD73XX_DCL_BOOTCR) & ADSLSS_PLL_SELECT;
++ switch(choice)
++ {
++ case ADSLSS_AFECLKI_SELECT:
++ clk_src[CLKC_ADSLSS] = &afeclk_inp;
++ break;
++
++ case ADSLSS_REFCLKI_SELECT:
++ clk_src[CLKC_ADSLSS] = &refclk_inp;
++ break;
++
++ case ADSLSS_XTAL3IN_SELECT:
++ clk_src[CLKC_ADSLSS] = &xtal_inp;
++ break;
++
++ case ADSLSS_MIPSPLL_SELECT:
++ clk_src[CLKC_ADSLSS] = &mips_pll_out;
++ break;
++
++ default :
++ clk_src[CLKC_ADSLSS] = 0;
++
++ }
++
++
++ choice = REG32_DATA(TNETD73XX_DCL_BOOTCR) & USB_PLL_SELECT;
++ switch(choice)
++ {
++ case USB_SYSPLL_SELECT:
++ clk_src[CLKC_USB] = &sys_pll_out ;
++ break;
++
++ case USB_REFCLKI_SELECT:
++ clk_src[CLKC_USB] = &refclk_inp;
++ break;
++
++ case USB_XTAL3IN_SELECT:
++ clk_src[CLKC_USB] = &xtal_inp;
++ break;
++
++ case USB_MIPSPLL_SELECT:
++ clk_src[CLKC_USB] = &mips_pll_out;
++ break;
++
++ default :
++ clk_src[CLKC_USB] = 0;
++
++ }
++}
++
++
++
++/****************************************************************************
++ * FUNCTION: tnetd73xx_clkc_set_freq
++ ****************************************************************************
++ * Description: The above routine is called to set the output_frequency of the
++ * selected clock(using clk_id) to the required value given
++ * by the variable output_freq.
++ ***************************************************************************/
++TNETD73XX_ERR tnetd73xx_clkc_set_freq
++(
++ TNETD73XX_CLKC_ID_T clk_id,
++ u32 output_freq
++ )
++{
++ u32 base_freq;
++ u32 multiplier;
++ u32 divider;
++ u32 min_prediv;
++ u32 max_prediv;
++ u32 prediv;
++ u32 postdiv;
++ u32 temp;
++
++ /* check if PLLs are bypassed*/
++ if(REG32_DATA(TNETD73XX_DCL_BOOTCR) & BOOTCR_PLL_BYPASS)
++ {
++ return TNETD73XX_ERR_ERROR;
++ }
++
++ /*check if the requested output_frequency is in valid range*/
++ switch( clk_id )
++ {
++ case CLKC_SYS:
++ if( output_freq < SYS_MIN || output_freq > SYS_MAX)
++ {
++ return TNETD73XX_ERR_ERROR;
++ }
++ present_min = SYS_MIN;
++ present_max = SYS_MAX;
++ break;
++
++ case CLKC_MIPS:
++ if((output_freq < MIPS_MIN) ||
++ (output_freq > ((REG32_DATA(TNETD73XX_DCL_BOOTCR) & BOOTCR_MIPS_ASYNC_MODE) ? MIPS_ASYNC_MAX: MIPS_SYNC_MAX)))
++ {
++ return TNETD73XX_ERR_ERROR;
++ }
++ present_min = MIPS_MIN;
++ present_max = (REG32_DATA(TNETD73XX_DCL_BOOTCR) & BOOTCR_MIPS_ASYNC_MODE) ? MIPS_ASYNC_MAX: MIPS_SYNC_MAX;
++ break;
++
++ case CLKC_USB:
++ if( output_freq < USB_MIN || output_freq > USB_MAX)
++ {
++ return TNETD73XX_ERR_ERROR;
++ }
++ present_min = USB_MIN;
++ present_max = USB_MAX;
++ break;
++
++ case CLKC_ADSLSS:
++ if( output_freq < ADSL_MIN || output_freq > ADSL_MAX)
++ {
++ return TNETD73XX_ERR_ERROR;
++ }
++ present_min = ADSL_MIN;
++ present_max = ADSL_MAX;
++ break;
++ }
++
++
++ base_freq = get_base_frequency(clk_id);
++
++
++ /* check for minimum base frequency value */
++ if( base_freq < MIN_PLL_INP_FREQ)
++ {
++ return TNETD73XX_ERR_ERROR;
++ }
++
++ get_val(output_freq, base_freq, &multiplier, &divider);
++
++ /* check multiplier range */
++ if( (multiplier > PLL_MUL_MAXFACTOR) || (multiplier <= 0) )
++ {
++ return TNETD73XX_ERR_ERROR;
++ }
++
++ /* check divider value */
++ if( divider == 0 )
++ {
++ return TNETD73XX_ERR_ERROR;
++ }
++
++ /*compute minimum and maximum predivider values */
++ min_prediv = MAX(base_freq / MAX_PLL_INP_FREQ + 1, divider / MAX_DIV_VALUE + 1);
++ max_prediv = MIN(base_freq / MIN_PLL_INP_FREQ, MAX_DIV_VALUE);
++
++ /*adjust the value of divider so that it not less than minimum predivider value*/
++ if (divider < min_prediv)
++ {
++ temp = CEIL(min_prediv, divider);
++ if ((temp * multiplier) > PLL_MUL_MAXFACTOR)
++ {
++ return TNETD73XX_ERR_ERROR ;
++ }
++ else
++ {
++ multiplier = temp * multiplier;
++ divider = min_prediv;
++ }
++
++ }
++
++ /* compute predivider and postdivider values */
++ prediv = compute_prediv (divider, min_prediv, max_prediv);
++ postdiv = CEIL(divider,prediv);
++
++ /*return fail if postdivider value falls out of range */
++ if(postdiv > MAX_DIV_VALUE)
++ {
++ return TNETD73XX_ERR_ERROR;
++ }
++
++
++ /*write predivider and postdivider values*/
++ /* pre-Divider and post-divider are 5 bit N+1 dividers */
++ REG32_WRITE(CLKC_CLKCR(clk_id), ((postdiv -1) & 0x1F) << 16 | ((prediv -1) & 0x1F) );
++
++ /*wait for divider output to stabilise*/
++ for(temp =0; temp < DIVIDER_LOCK_TIME; temp++);
++
++ /*write to PLL clock register*/
++
++ if(clk_id == CLKC_SYS)
++ {
++ /* but before writing put DRAM to hold mode */
++ REG32_DATA(TNETD73XX_EMIF_SDRAM_CFG) |= 0x80000000;
++ }
++ /*Bring PLL into div mode */
++ REG32_WRITE(CLKC_CLKPLLCR(clk_id), 0x4);
++
++ /*compute the word to be written to PLLCR
++ *corresponding to multiplier value
++ */
++ multiplier = (((multiplier - 1) & 0xf) << 12)| ((255 <<3) | 0x0e);
++
++ /* wait till PLL enters div mode */
++ while(REG32_DATA(CLKC_CLKPLLCR(clk_id)) & CLKC_PLL_STATUS)
++ /*nothing*/;
++
++ REG32_WRITE(CLKC_CLKPLLCR(clk_id), multiplier);
++
++ while(!REG32_DATA(CLKC_CLKPLLCR(clk_id)) & CLKC_PLL_STATUS)
++ /*nothing*/;
++
++
++ /*wait for External pll to lock*/
++ for(temp =0; temp < PLL_LOCK_TIME; temp++);
++
++ if(clk_id == CLKC_SYS)
++ {
++ /* Bring DRAM out of hold */
++ REG32_DATA(TNETD73XX_EMIF_SDRAM_CFG) &= ~0x80000000;
++ }
++
++ return TNETD73XX_ERR_OK ;
++}
++
++/****************************************************************************
++ * FUNCTION: tnetd73xx_clkc_get_freq
++ ****************************************************************************
++ * Description: The above routine is called to get the output_frequency of the
++ * selected clock( clk_id)
++ ***************************************************************************/
++u32 tnetd73xx_clkc_get_freq
++(
++ TNETD73XX_CLKC_ID_T clk_id
++ )
++{
++
++ u32 clk_ctrl_register;
++ u32 clk_pll_setting;
++ u32 clk_predivider;
++ u32 clk_postdivider;
++ u16 pll_factor;
++ u32 base_freq;
++ u32 divider;
++
++ base_freq = get_base_frequency(clk_id);
++
++ clk_ctrl_register = REG32_DATA(CLKC_CLKCR(clk_id));
++
++ /* pre-Divider and post-divider are 5 bit N+1 dividers */
++ clk_predivider = (CLKC_PRE_DIVIDER & clk_ctrl_register) + 1;
++ clk_postdivider = ((CLKC_POST_DIVIDER & clk_ctrl_register) >> 16) + 1;
++
++ divider = clk_predivider * clk_postdivider;
++
++
++ if( (REG32_DATA(TNETD73XX_DCL_BOOTCR) & BOOTCR_PLL_BYPASS))
++ {
++ return (CEIL(base_freq, divider)); /* PLLs bypassed.*/
++ }
++
++
++ else
++ {
++ /* return the current clock speed based upon the PLL setting */
++ clk_pll_setting = REG32_DATA(CLKC_CLKPLLCR(clk_id));
++
++ /* Get the PLL multiplication factor */
++ pll_factor = ((clk_pll_setting & CLKC_PLL_FACTOR) >> 12) + 1;
++
++ /* Check if we're in divide mode or multiply mode */
++ if((clk_pll_setting & 0x1) == 0)
++ {
++ /* We're in divide mode */
++ if(pll_factor < 0x10)
++ return (CEIL(base_freq >> 1, divider));
++ else
++ return (CEIL(base_freq >> 2, divider));
++ }
++
++ else /* We're in PLL mode */
++ {
++ /* See if PLLNDIV & PLLDIV are set */
++ if((clk_pll_setting & 0x0800) && (clk_pll_setting & 0x2))
++ {
++ if(clk_pll_setting & 0x1000)
++ {
++ /* clk = base_freq * k/2 */
++ return(CEIL((base_freq * pll_factor) >> 1, divider));
++ }
++ else
++ {
++ /* clk = base_freq * (k-1) / 4)*/
++ return(CEIL((base_freq * (pll_factor - 1)) >>2, divider));
++ }
++ }
++ else
++ {
++ if(pll_factor < 0x10)
++ {
++ /* clk = base_freq * k */
++ return(CEIL(base_freq * pll_factor, divider));
++ }
++
++ else
++ {
++ /* clk = base_freq */
++ return(CEIL(base_freq, divider));
++ }
++ }
++ }
++ return(0); /* Should never reach here */
++
++ }
++
++}
++
++
++/* local helper functions */
++
++/****************************************************************************
++ * FUNCTION: get_base_frequency
++ ****************************************************************************
++ * Description: The above routine is called to get base frequency of the clocks.
++ ***************************************************************************/
++
++static u32 get_base_frequency(TNETD73XX_CLKC_ID_T clk_id)
++{
++ /* update the current MIPs PLL output value, if the required
++ * source is MIPS PLL
++ */
++ if ( clk_src[clk_id] == &mips_pll_out)
++ {
++ *clk_src[clk_id] = tnetd73xx_clkc_get_freq(CLKC_MIPS);
++ }
++
++
++ /* update the current System PLL output value, if the required
++ * source is system PLL
++ */
++ if ( clk_src[clk_id] == &sys_pll_out)
++ {
++ *clk_src[clk_id] = tnetd73xx_clkc_get_freq(CLKC_SYS);
++ }
++
++ return (*clk_src[clk_id]);
++
++}
++
++
++
++/****************************************************************************
++ * FUNCTION: find_gcd
++ ****************************************************************************
++ * Description: The above routine is called to find gcd of 2 numbers.
++ ***************************************************************************/
++static u32 find_gcd
++(
++ u32 min,
++ u32 max
++ )
++{
++ if (max % min == 0)
++ {
++ return min;
++ }
++ else
++ {
++ return find_gcd(max % min, min);
++ }
++}
++
++/****************************************************************************
++ * FUNCTION: compute_prediv
++ ****************************************************************************
++ * Description: The above routine is called to compute predivider value
++ ***************************************************************************/
++static u32 compute_prediv(u32 divider, u32 min, u32 max)
++{
++ u16 prediv;
++
++ /* return the divider itself it it falls within the range of predivider*/
++ if (min <= divider && divider <= max)
++ {
++ return divider;
++ }
++
++ /* find a value for prediv such that it is a factor of divider */
++ for (prediv = max; prediv >= min ; prediv--)
++ {
++ if ( (divider % prediv) == 0 )
++ {
++ return prediv;
++ }
++ }
++
++ /* No such factor exists, return min as prediv */
++ return min;
++}
++
++/****************************************************************************
++ * FUNCTION: get_val
++ ****************************************************************************
++ * Description: This routine is called to get values of divider and multiplier.
++ ***************************************************************************/
++
++static void get_val(u32 output_freq, u32 base_freq,u32 *multiplier, u32 *divider)
++{
++ u32 temp_mul;
++ u32 temp_div;
++ u32 gcd;
++ u32 min_freq;
++ u32 max_freq;
++
++ /* find gcd of base_freq, output_freq */
++ min_freq = (base_freq < output_freq) ? base_freq : output_freq;
++ max_freq = (base_freq > output_freq) ? base_freq : output_freq;
++ gcd = find_gcd(min_freq , max_freq);
++
++ if(gcd == 0)
++ return; /* ERROR */
++
++ /* compute values of multiplier and divider */
++ temp_mul = output_freq / gcd;
++ temp_div = base_freq / gcd;
++
++
++ /* set multiplier such that 1 <= multiplier <= PLL_MUL_MAXFACTOR */
++ if( temp_mul > PLL_MUL_MAXFACTOR )
++ {
++ if((temp_mul / temp_div) > PLL_MUL_MAXFACTOR)
++ return;
++
++ find_approx(&temp_mul,&temp_div,base_freq);
++ }
++
++ *multiplier = temp_mul;
++ *divider = temp_div;
++}
++
++/****************************************************************************
++ * FUNCTION: find_approx
++ ****************************************************************************
++ * Description: This function gets the approx value of num/denom.
++ ***************************************************************************/
++
++static void find_approx(u32 *num,u32 *denom,u32 base_freq)
++{
++ u32 num1;
++ u32 denom1;
++ u32 num2;
++ u32 denom2;
++ int32_t closest;
++ int32_t prev_closest;
++ u32 temp_num;
++ u32 temp_denom;
++ u32 normalize;
++ u32 gcd;
++ u32 output_freq;
++
++ num1 = *num;
++ denom1 = *denom;
++
++ prev_closest = 0x7fffffff; /* maximum possible value */
++ num2 = num1;
++ denom2 = denom1;
++
++ /* start with max */
++ for(temp_num = 15; temp_num >=1; temp_num--)
++ {
++
++ temp_denom = CEIL(temp_num * denom1, num1);
++ output_freq = (temp_num * base_freq) / temp_denom;
++
++ if(temp_denom < 1)
++ {
++ break;
++ }
++ else
++ {
++ normalize = CEIL(num1,temp_num);
++ closest = (ABS((num1 * (temp_denom) ) - (temp_num * denom1))) * normalize;
++ if(closest < prev_closest && output_freq > present_min && output_freq <present_max)
++ {
++ prev_closest = closest;
++ num2 = temp_num;
++ denom2 = temp_denom;
++ }
++
++ }
++
++ }
++
++ gcd = find_gcd(num2,denom2);
++ num2 = num2 / gcd;
++ denom2 = denom2 /gcd;
++
++ *num = num2;
++ *denom = denom2;
++}
++
++
++/*****************************************************************************
++ * GPIO Control
++ *****************************************************************************/
++
++/****************************************************************************
++ * FUNCTION: tnetd73xx_gpio_init
++ ***************************************************************************/
++void tnetd73xx_gpio_init()
++{
++ /* Bring module out of reset */
++ tnetd73xx_reset_ctrl(RESET_MODULE_GPIO, OUT_OF_RESET);
++ REG32_WRITE(TNETD73XX_GPIOENR, 0xFFFFFFFF);
++}
++
++/****************************************************************************
++ * FUNCTION: tnetd73xx_gpio_ctrl
++ ***************************************************************************/
++void tnetd73xx_gpio_ctrl(TNETD73XX_GPIO_PIN_T gpio_pin,
++ TNETD73XX_GPIO_PIN_MODE_T pin_mode,
++ TNETD73XX_GPIO_PIN_DIRECTION_T pin_direction)
++{
++ u32 pin_status;
++ REG32_READ(TNETD73XX_GPIOENR, pin_status);
++ if (pin_mode == GPIO_PIN)
++ {
++ pin_status |= (1 << gpio_pin);
++ REG32_WRITE(TNETD73XX_GPIOENR, pin_status);
++
++ /* Set pin direction */
++ REG32_READ(TNETD73XX_GPIOPDIRR, pin_status);
++ if (pin_direction == GPIO_INPUT_PIN)
++ {
++ pin_status |= (1 << gpio_pin);
++ }
++ else /* GPIO_OUTPUT_PIN */
++ {
++ pin_status &= (~(1 << gpio_pin));
++ }
++ REG32_WRITE(TNETD73XX_GPIOPDIRR, pin_status);
++ }
++ else /* FUNCTIONAL PIN */
++ {
++ pin_status &= (~(1 << gpio_pin));
++ REG32_WRITE(TNETD73XX_GPIOENR, pin_status);
++ }
++
++}
++
++/****************************************************************************
++ * FUNCTION: tnetd73xx_gpio_out
++ ***************************************************************************/
++void tnetd73xx_gpio_out(TNETD73XX_GPIO_PIN_T gpio_pin, int value)
++{
++ u32 pin_value;
++
++ REG32_READ(TNETD73XX_GPIODOUTR, pin_value);
++ if (value == 1)
++ {
++ pin_value |= (1 << gpio_pin);
++ }
++ else
++ {
++ pin_value &= (~(1 << gpio_pin));
++ }
++ REG32_WRITE(TNETD73XX_GPIODOUTR, pin_value);
++}
++
++/****************************************************************************
++ * FUNCTION: tnetd73xx_gpio_in
++ ***************************************************************************/
++int tnetd73xx_gpio_in(TNETD73XX_GPIO_PIN_T gpio_pin)
++{
++ u32 pin_value;
++ REG32_READ(TNETD73XX_GPIODINR, pin_value);
++ return ( (pin_value & (1 << gpio_pin)) ? 1 : 0 );
++}
++
+diff -urN linux.old/arch/mips/config-shared.in linux.dev/arch/mips/config-shared.in
+--- linux.old/arch/mips/config-shared.in 2005-10-21 16:43:18.917114000 +0200
++++ linux.dev/arch/mips/config-shared.in 2005-11-10 01:12:43.950955750 +0100
+@@ -20,6 +20,16 @@
+ mainmenu_option next_comment
+ comment 'Machine selection'
+ dep_bool 'Support for Acer PICA 1 chipset (EXPERIMENTAL)' CONFIG_ACER_PICA_61 $CONFIG_EXPERIMENTAL
++dep_bool 'Support for Texas Instruments AR7 (EXPERIMENTAL)' CONFIG_AR7 $CONFIG_MIPS32 $CONFIG_EXPERIMENTAL
++if [ "$CONFIG_AR7" = "y" ]; then
++ choice 'Texas Instruments Reference Platform' \
++ "AR7DB CONFIG_AR7DB \
++ AR7RD CONFIG_AR7RD \
++ AR7WRD CONFIG_AR7WRD" AR7DB
++ int 'Texas Instruments AR7 CPU Frequency' CONFIG_AR7_CPU 150
++ int 'Texas Instruments AR7 System Frequency' CONFIG_AR7_SYS 125
++ hex 'Texas Instruments AR7 SDRAM Start' CONFIG_AR7_MEMORY 0x14000000
++fi
+ dep_bool 'Support for Alchemy Bosporus board' CONFIG_MIPS_BOSPORUS $CONFIG_MIPS32
+ dep_bool 'Support for FIC Multimedia Player board' CONFIG_MIPS_FICMMP $CONFIG_MIPS32
+ dep_bool 'Support for Alchemy Mirage board' CONFIG_MIPS_MIRAGE $CONFIG_MIPS32
+@@ -239,6 +249,11 @@
+ define_bool CONFIG_NONCOHERENT_IO y
+ define_bool CONFIG_PC_KEYB y
+ fi
++if [ "$CONFIG_AR7" = "y" ]; then
++ define_bool CONFIG_IRQ_CPU y
++ define_bool CONFIG_NONCOHERENT_IO y
++ define_bool CONFIG_SWAP_IO_SPACE y
++fi
+ if [ "$CONFIG_CASIO_E55" = "y" ]; then
+ define_bool CONFIG_IRQ_CPU y
+ define_bool CONFIG_NONCOHERENT_IO y
+@@ -736,6 +751,7 @@
+ mainmenu_option next_comment
+ comment 'General setup'
+ if [ "$CONFIG_ACER_PICA_61" = "y" -o \
++ "$CONFIG_AR7" = "y" -o \
+ "$CONFIG_CASIO_E55" = "y" -o \
+ "$CONFIG_DDB5074" = "y" -o \
+ "$CONFIG_DDB5476" = "y" -o \
+@@ -797,6 +813,7 @@
+ bool 'Networking support' CONFIG_NET
+
+ if [ "$CONFIG_ACER_PICA_61" = "y" -o \
++ "$CONFIG_AR7" = "y" -o \
+ "$CONFIG_CASIO_E55" = "y" -o \
+ "$CONFIG_DECSTATION" = "y" -o \
+ "$CONFIG_IBM_WORKPAD" = "y" -o \
+diff -urN linux.old/arch/mips/kernel/head.S linux.dev/arch/mips/kernel/head.S
+--- linux.old/arch/mips/kernel/head.S 2005-10-21 16:43:16.396956500 +0200
++++ linux.dev/arch/mips/kernel/head.S 2005-11-10 01:10:45.807572250 +0100
+@@ -75,11 +75,11 @@
+ * size!
+ */
+ NESTED(except_vec4, 0, sp)
+- .set push
+- .set noreorder
+-1: j 1b /* Dummy, will be replaced */
+- nop
+- .set pop
++ .set mips2
++ lui k0, 0x9400
++ ori k0, 0x200
++ jr k0
++ nop
+ END(except_vec4)
+
+ /*
+diff -urN linux.old/arch/mips/kernel/mips_ksyms.c linux.dev/arch/mips/kernel/mips_ksyms.c
+--- linux.old/arch/mips/kernel/mips_ksyms.c 2004-02-18 14:36:30.000000000 +0100
++++ linux.dev/arch/mips/kernel/mips_ksyms.c 2005-11-10 01:10:45.811572500 +0100
+@@ -40,6 +40,12 @@
+ extern long __strnlen_user_nocheck_asm(const char *s);
+ extern long __strnlen_user_asm(const char *s);
+
++#ifdef CONFIG_AR7
++#include <asm/ar7/adam2_env.h>
++int avalanche_request_pacing(int irq_nr, unsigned int blk_num, unsigned int pace_value);
++#endif
++
++
+ EXPORT_SYMBOL(mips_machtype);
+ #ifdef CONFIG_EISA
+ EXPORT_SYMBOL(EISA_bus);
+@@ -103,3 +109,10 @@
+ #endif
+
+ EXPORT_SYMBOL(get_wchan);
++
++#ifdef CONFIG_AR7
++EXPORT_SYMBOL_NOVERS(avalanche_request_pacing);
++EXPORT_SYMBOL_NOVERS(prom_getenv);
++EXPORT_SYMBOL_NOVERS(prom_iterenv);
++#endif
++
+diff -urN linux.old/arch/mips/kernel/setup.c linux.dev/arch/mips/kernel/setup.c
+--- linux.old/arch/mips/kernel/setup.c 2005-10-21 16:43:16.396956500 +0200
++++ linux.dev/arch/mips/kernel/setup.c 2005-11-10 01:14:16.376732000 +0100
+@@ -38,6 +38,7 @@
+ #include <asm/io.h>
+ #include <asm/ptrace.h>
+ #include <asm/system.h>
++#include <asm/addrspace.h>
+
+ struct cpuinfo_mips cpu_data[NR_CPUS];
+ EXPORT_SYMBOL(cpu_data);
+@@ -88,7 +89,7 @@
+ struct boot_mem_map boot_mem_map;
+
+ unsigned char aux_device_present;
+-extern char _ftext, _etext, _fdata, _edata, _end;
++extern char _ftext, _etext, _fdata, _edata, _fbss, _end;
+
+ static char command_line[CL_SIZE];
+ char saved_command_line[CL_SIZE];
+@@ -116,6 +117,7 @@
+
+ static struct resource code_resource = { "Kernel code" };
+ static struct resource data_resource = { "Kernel data" };
++static struct resource bss_resource = { "Kernel bss" };
+
+ asmlinkage void __init
+ init_arch(int argc, char **argv, char **envp, int *prom_vec)
+@@ -272,7 +274,7 @@
+ for (i = 0; i < boot_mem_map.nr_map; i++) {
+ unsigned long start, end;
+
+- if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
++ if (boot_mem_map.map[i].type == BOOT_MEM_RESERVED)
+ continue;
+
+ start = PFN_UP(boot_mem_map.map[i].addr);
+@@ -320,7 +322,8 @@
+ #endif
+
+ /* Initialize the boot-time allocator with low memory only. */
+- bootmap_size = init_bootmem(first_usable_pfn, max_low_pfn);
++ bootmap_size = init_bootmem_node(NODE_DATA(0), first_usable_pfn,
++ PFN_UP(PHYS_OFFSET), max_low_pfn);
+
+ /*
+ * Register fully available low RAM pages with the bootmem allocator.
+@@ -371,11 +374,12 @@
+ continue;
+
+ /* Register lowmem ranges */
+- free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size));
++ free_bootmem_node(NODE_DATA(0), PFN_PHYS(curr_pfn),
++ size<<PAGE_SHIFT);
+ }
+
+ /* Reserve the bootmap memory. */
+- reserve_bootmem(PFN_PHYS(first_usable_pfn), bootmap_size);
++ reserve_bootmem_node(NODE_DATA(0), PFN_PHYS(first_usable_pfn), bootmap_size);
+
+ #ifdef CONFIG_BLK_DEV_INITRD
+ /* Board specific code should have set up initrd_start and initrd_end */
+@@ -409,6 +413,8 @@
+ code_resource.end = virt_to_bus(&_etext) - 1;
+ data_resource.start = virt_to_bus(&_fdata);
+ data_resource.end = virt_to_bus(&_edata) - 1;
++ bss_resource.start = virt_to_bus(&_fbss);
++ bss_resource.end = virt_to_bus(&_end) - 1;
+
+ /*
+ * Request address space for all standard RAM.
+@@ -448,6 +454,7 @@
+ */
+ request_resource(res, &code_resource);
+ request_resource(res, &data_resource);
++ request_resource(res, &bss_resource);
+ }
+ }
+
+@@ -494,6 +501,7 @@
+ void hp_setup(void);
+ void au1x00_setup(void);
+ void frame_info_init(void);
++ void ar7_setup(void);
+
+ frame_info_init();
+ #if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE)
+@@ -691,6 +699,11 @@
+ pmc_yosemite_setup();
+ break;
+ #endif
++#ifdef CONFIG_AR7
++ case MACH_GROUP_UNKNOWN:
++ ar7_setup();
++ break;
++#endif
+ default:
+ panic("Unsupported architecture");
+ }
+diff -urN linux.old/arch/mips/kernel/time.c linux.dev/arch/mips/kernel/time.c
+--- linux.old/arch/mips/kernel/time.c 2005-01-19 15:09:29.000000000 +0100
++++ linux.dev/arch/mips/kernel/time.c 2005-11-10 01:12:43.950955750 +0100
+@@ -143,7 +143,6 @@
+ expirelo = (count / cycles_per_jiffy + 1) * cycles_per_jiffy;
+ write_c0_count(expirelo - cycles_per_jiffy);
+ write_c0_compare(expirelo);
+- write_c0_count(count);
+ }
+
+ int (*mips_timer_state)(void);
+diff -urN linux.old/arch/mips/kernel/traps.c linux.dev/arch/mips/kernel/traps.c
+--- linux.old/arch/mips/kernel/traps.c 2005-10-21 16:43:16.400956750 +0200
++++ linux.dev/arch/mips/kernel/traps.c 2005-11-10 01:13:28.301727500 +0100
+@@ -869,9 +869,24 @@
+
+ exception_handlers[n] = handler;
+ if (n == 0 && cpu_has_divec) {
++ printk(KERN_DEBUG "%s: using long jump via k0 to reach %08x\n",
++ __FUNCTION__, handler);
++ /* where does the 8 byte limit mentioned in head.S come from??? */
++ if (handler > 0x0fffffff) { /* maximum for single J instruction */
++ /* lui k0, 0x0000 */
++ *(volatile u32 *)(KSEG0+0x200) = 0x3c1a0000 | (handler >> 16);
++ /* ori k0, 0x0000 */
++ *(volatile u32 *)(KSEG0+0x204) = 0x375a0000 | (handler & 0xffff);
++ /* jr k0 */
++ *(volatile u32 *)(KSEG0+0x208) = 0x03400008;
++ /* nop */
++ *(volatile u32 *)(KSEG0+0x20C) = 0x00000000;
++ flush_icache_range(KSEG0+0x200, KSEG0+0x210);
++ } else {
+ *(volatile u32 *)(KSEG0+0x200) = 0x08000000 |
+ (0x03ffffff & (handler >> 2));
+- flush_icache_range(KSEG0+0x200, KSEG0 + 0x204);
++ flush_icache_range(KSEG0+0x200, KSEG0+0x204);
++ }
+ }
+ return (void *)old_handler;
+ }
+diff -urN linux.old/arch/mips/mm/init.c linux.dev/arch/mips/mm/init.c
+--- linux.old/arch/mips/mm/init.c 2004-02-18 14:36:30.000000000 +0100
++++ linux.dev/arch/mips/mm/init.c 2005-11-10 01:14:16.376732000 +0100
+@@ -235,10 +235,13 @@
+ #endif
+ }
+
++#define START_PFN (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT)
++#define MAX_LOW_PFN (NODE_DATA(0)->bdata->node_low_pfn)
++
+ void __init paging_init(void)
+ {
+ unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0};
+- unsigned long max_dma, high, low;
++ unsigned long max_dma, high, low, start;
+
+ pagetable_init();
+
+@@ -247,7 +250,8 @@
+ #endif
+
+ max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+- low = max_low_pfn;
++ start = START_PFN;
++ low = MAX_LOW_PFN - start;
+ high = highend_pfn;
+
+ #ifdef CONFIG_ISA
+@@ -270,7 +274,8 @@
+ zones_size[ZONE_HIGHMEM] = high - low;
+ #endif
+
+- free_area_init(zones_size);
++ free_area_init_node(0, NODE_DATA(0), 0, zones_size,
++ start << PAGE_SHIFT, 0);
+ }
+
+ #define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT)
+@@ -283,7 +288,7 @@
+ for (i = 0; i < boot_mem_map.nr_map; i++) {
+ unsigned long addr, end;
+
+- if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
++ if (boot_mem_map.map[i].type == BOOT_MEM_RESERVED)
+ /* not usable memory */
+ continue;
+
+@@ -313,16 +318,17 @@
+ max_mapnr = num_physpages = highend_pfn;
+ num_mappedpages = max_low_pfn;
+ #else
+- max_mapnr = num_mappedpages = num_physpages = max_low_pfn;
++ max_mapnr = num_mappedpages = num_physpages = MAX_LOW_PFN - START_PFN;
+ #endif
+- high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
+-
+- totalram_pages += free_all_bootmem();
++
++ high_memory = (void *) __va(MAX_LOW_PFN * PAGE_SIZE);
++
++ totalram_pages += free_all_bootmem_node(NODE_DATA(0));
+ totalram_pages -= setup_zero_pages(); /* Setup zeroed pages. */
+
+ reservedpages = ram = 0;
+- for (tmp = 0; tmp < max_low_pfn; tmp++)
+- if (page_is_ram(tmp)) {
++ for (tmp = 0; tmp < max_mapnr; tmp++)
++ if (page_is_ram(START_PFN + tmp)) {
+ ram++;
+ if (PageReserved(mem_map+tmp))
+ reservedpages++;
+@@ -377,13 +383,13 @@
+ #endif
+
+ extern char __init_begin, __init_end;
+-extern void prom_free_prom_memory(void) __init;
++extern unsigned long prom_free_prom_memory(void) __init;
+
+ void free_initmem(void)
+ {
+ unsigned long addr;
+
+- prom_free_prom_memory ();
++ totalram_pages += prom_free_prom_memory ();
+
+ addr = (unsigned long) &__init_begin;
+ while (addr < (unsigned long) &__init_end) {
+diff -urN linux.old/drivers/char/Config.in linux.dev/drivers/char/Config.in
+--- linux.old/drivers/char/Config.in 2005-10-21 16:43:16.440959250 +0200
++++ linux.dev/drivers/char/Config.in 2005-11-10 01:10:45.843574500 +0100
+@@ -188,6 +188,14 @@
+ tristate 'Total Impact briQ front panel driver' CONFIG_BRIQ_PANEL
+ fi
+
++if [ "$CONFIG_AR7" = "y" ]; then
++ bool 'VLYNQ support for the TI SOC' CONFIG_AR7_VLYNQ
++ dep_bool 'VLYNQ clock source Internal' CONFIG_VLYNQ_CLK_LOCAL $CONFIG_AR7_VLYNQ
++
++ define_int CONFIG_AR7_VLYNQ_PORTS 2
++ tristate 'ADAM2 environment support (read-only)' CONFIG_AR7_ADAM2
++fi
++
+ source drivers/i2c/Config.in
+
+ mainmenu_option next_comment
+diff -urN linux.old/drivers/char/Config.in.orig linux.dev/drivers/char/Config.in.orig
+--- linux.old/drivers/char/Config.in.orig 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/char/Config.in.orig 2005-11-10 01:10:45.863575750 +0100
+@@ -0,0 +1,414 @@
++#
++# Character device configuration
++#
++mainmenu_option next_comment
++comment 'Character devices'
++
++bool 'Virtual terminal' CONFIG_VT
++if [ "$CONFIG_VT" = "y" ]; then
++ bool ' Support for console on virtual terminal' CONFIG_VT_CONSOLE
++ if [ "$CONFIG_GSC_LASI" = "y" ]; then
++ bool ' Support for Lasi/Dino PS2 port' CONFIG_GSC_PS2
++ fi
++fi
++tristate 'Standard/generic (8250/16550 and compatible UARTs) serial support' CONFIG_SERIAL
++if [ "$CONFIG_SERIAL" = "y" ]; then
++ bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE
++ if [ "$CONFIG_GSC_LASI" = "y" ]; then
++ bool ' serial port on GSC support' CONFIG_SERIAL_GSC
++ fi
++ if [ "$CONFIG_IA64" = "y" ]; then
++ bool ' Support for serial port described by EFI HCDP table' CONFIG_SERIAL_HCDP
++ fi
++ if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
++ tristate ' Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL
++ tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL
++ fi
++fi
++dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL
++if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
++ bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
++ bool ' Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
++ bool ' Autodetect IRQ on standard ports (unsafe)' CONFIG_SERIAL_DETECT_IRQ
++ bool ' Support special multiport boards' CONFIG_SERIAL_MULTIPORT
++ bool ' Support the Bell Technologies HUB6 card' CONFIG_HUB6
++fi
++bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD
++if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then
++ tristate ' Computone IntelliPort Plus serial support' CONFIG_COMPUTONE
++ tristate ' Comtrol Rocketport support' CONFIG_ROCKETPORT
++ tristate ' Cyclades async mux support' CONFIG_CYCLADES
++ if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_CYCLADES" != "n" ]; then
++ bool ' Cyclades-Z interrupt mode operation (EXPERIMENTAL)' CONFIG_CYZ_INTR
++ fi
++ if [ "$CONFIG_X86_64" != "y" ]; then
++ tristate ' Digiboard Intelligent Async Support' CONFIG_DIGIEPCA
++ if [ "$CONFIG_DIGIEPCA" = "n" ]; then
++ tristate ' Digiboard PC/Xx Support' CONFIG_DIGI
++ fi
++ fi
++ dep_tristate ' Hayes ESP serial port support' CONFIG_ESPSERIAL $CONFIG_ISA
++ tristate ' Moxa Intellio support' CONFIG_MOXA_INTELLIO
++ tristate ' Moxa SmartIO support' CONFIG_MOXA_SMARTIO
++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
++ dep_tristate ' Multi-Tech multiport card support (EXPERIMENTAL)' CONFIG_ISI m
++ fi
++ tristate ' Microgate SyncLink card support' CONFIG_SYNCLINK
++ tristate ' SyncLink Multiport support' CONFIG_SYNCLINKMP
++ tristate ' HDLC line discipline support' CONFIG_N_HDLC
++ tristate ' SDL RISCom/8 card support' CONFIG_RISCOM8
++ if [ "$CONFIG_X86_64" != "y" ]; then
++ tristate ' Specialix IO8+ card support' CONFIG_SPECIALIX
++ if [ "$CONFIG_SPECIALIX" != "n" ]; then
++ bool ' Specialix DTR/RTS pin is RTS' CONFIG_SPECIALIX_RTSCTS
++ fi
++ tristate ' Specialix SX (and SI) card support' CONFIG_SX
++ tristate ' Specialix RIO system support' CONFIG_RIO
++ if [ "$CONFIG_RIO" != "n" ]; then
++ bool ' Support really old RIO/PCI cards' CONFIG_RIO_OLDPCI
++ fi
++ fi
++ bool ' Stallion multiport serial support' CONFIG_STALDRV
++ if [ "$CONFIG_STALDRV" = "y" ]; then
++ tristate ' Stallion EasyIO or EC8/32 support' CONFIG_STALLION
++ tristate ' Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
++ fi
++ if [ "$CONFIG_PARISC" = "y" ]; then
++ if [ "$CONFIG_PDC_CONSOLE" != "y" ]; then
++ bool ' Serial MUX support' CONFIG_SERIAL_MUX CONFIG_SERIAL_NONSTANDARD
++ fi
++ if [ "$CONFIG_SERIAL_MUX" != "y" ]; then
++ bool ' PDC software console support' CONFIG_PDC_CONSOLE CONFIG_SERIAL_NONSTANDARD
++ fi
++ fi
++ if [ "$CONFIG_MIPS" = "y" ]; then
++ bool ' TX3912/PR31700 serial port support' CONFIG_SERIAL_TX3912
++ dep_bool ' Console on TX3912/PR31700 serial port' CONFIG_SERIAL_TX3912_CONSOLE $CONFIG_SERIAL_TX3912
++ bool ' TMPTX39XX/49XX serial port support' CONFIG_SERIAL_TXX9
++ dep_bool ' Console on TMPTX39XX/49XX serial port' CONFIG_SERIAL_TXX9_CONSOLE $CONFIG_SERIAL_TXX9
++ if [ "$CONFIG_SOC_AU1X00" = "y" ]; then
++ bool ' Enable Au1x00 UART Support' CONFIG_AU1X00_UART
++ if [ "$CONFIG_AU1X00_UART" = "y" ]; then
++ bool ' Enable Au1x00 serial console' CONFIG_AU1X00_SERIAL_CONSOLE
++ fi
++ dep_tristate ' Au1x00 USB TTY Device support' CONFIG_AU1X00_USB_TTY $CONFIG_SOC_AU1X00
++ if [ "$CONFIG_AU1000_USB_TTY" != "y" ]; then
++ dep_tristate ' Au1x00 USB Raw Device support' CONFIG_AU1X00_USB_RAW $CONFIG_SOC_AU1X00
++ fi
++ if [ "$CONFIG_AU1X00_USB_TTY" != "n" -o \
++ "$CONFIG_AU1X00_USB_RAW" != "n" ]; then
++ define_bool CONFIG_AU1X00_USB_DEVICE y
++ fi
++ fi
++ bool ' TXx927 SIO support' CONFIG_TXX927_SERIAL
++ if [ "$CONFIG_TXX927_SERIAL" = "y" ]; then
++ bool ' TXx927 SIO Console support' CONFIG_TXX927_SERIAL_CONSOLE
++ fi
++ if [ "$CONFIG_SIBYTE_SB1xxx_SOC" = "y" ]; then
++ bool ' Support for BCM1xxx onchip DUART' CONFIG_SIBYTE_SB1250_DUART
++ if [ "$CONFIG_SIBYTE_SB1250_DUART" = "y" ]; then
++ bool ' Console on BCM1xxx DUART' CONFIG_SIBYTE_SB1250_DUART_CONSOLE
++ if [ "$CONFIG_SIBYTE_SB1250_DUART_CONSOLE" = "y" ]; then
++ define_bool CONFIG_SERIAL_CONSOLE y
++ fi
++ fi
++ fi
++ fi
++ if [ "$CONFIG_DECSTATION" = "y" ]; then
++ bool ' DECstation serial support' CONFIG_SERIAL_DEC
++ dep_bool ' Support for console on a DECstation serial port' CONFIG_SERIAL_DEC_CONSOLE $CONFIG_SERIAL_DEC
++ dep_bool ' DZ11 serial support' CONFIG_DZ $CONFIG_SERIAL_DEC $CONFIG_MIPS32
++ dep_bool ' Z85C30 serial support' CONFIG_ZS $CONFIG_SERIAL_DEC $CONFIG_TC
++ fi
++ if [ "$CONFIG_SGI_IP22" = "y" ]; then
++ bool ' SGI Zilog85C30 serial support' CONFIG_IP22_SERIAL
++ fi
++ if [ "$CONFIG_IA64" = "y" ]; then
++ bool ' SGI SN2 l1 serial port support' CONFIG_SGI_L1_SERIAL
++ if [ "$CONFIG_SGI_L1_SERIAL" = "y" ]; then
++ bool ' SGI SN2 l1 Console support' CONFIG_SGI_L1_SERIAL_CONSOLE
++ fi
++ if [ "$CONFIG_IA64_GENERIC" = "y" -o "$CONFIG_IA64_SGI_SN2" = "y" ]; then
++ bool ' SGI SN2 IOC4 serial port support' CONFIG_SGI_IOC4_SERIAL
++ fi
++ fi
++fi
++if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then
++ tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232
++fi
++if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
++ bool 'DC21285 serial port support' CONFIG_SERIAL_21285
++ if [ "$CONFIG_SERIAL_21285" = "y" ]; then
++ if [ "$CONFIG_OBSOLETE" = "y" ]; then
++ bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD
++ fi
++ bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE
++ fi
++ if [ "$CONFIG_PARISC" = "y" ]; then
++ bool ' PDC software console support' CONFIG_PDC_CONSOLE
++ fi
++fi
++if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then
++ bool 'Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD
++ if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then
++ define_bool CONFIG_IT8172_CIR y
++ else
++ bool ' Enable PS2 Keyboard Support' CONFIG_PC_KEYB
++ fi
++ bool 'Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0
++ bool 'Enable Smart Card Reader 1 Support ' CONFIG_IT8172_SCR1
++fi
++if [ "$CONFIG_MIPS_IVR" = "y" ]; then
++ bool 'Enable Qtronix 990P Keyboard Support' CONFIG_QTRONIX_KEYBOARD
++ if [ "$CONFIG_QTRONIX_KEYBOARD" = "y" ]; then
++ define_bool CONFIG_IT8172_CIR y
++ fi
++ bool 'Enable Smart Card Reader 0 Support ' CONFIG_IT8172_SCR0
++fi
++if [ "$CONFIG_CPU_VR41XX" = "y" ]; then
++ bool 'NEC VR4100 series Keyboard Interface Unit Support ' CONFIG_VR41XX_KIU
++fi
++bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
++if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
++ int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
++fi
++if [ "$CONFIG_PARPORT" != "n" ]; then
++ dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
++ if [ "$CONFIG_PRINTER" != "n" ]; then
++ bool ' Support for console on line printer' CONFIG_LP_CONSOLE
++ fi
++ dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT
++ dep_tristate 'Texas Instruments parallel link cable support' CONFIG_TIPAR $CONFIG_PARPORT
++fi
++
++if [ "$CONFIG_PPC64" = "y" ] ; then
++ bool 'pSeries Hypervisor Virtual Console support' CONFIG_HVC_CONSOLE
++fi
++if [ "$CONFIG_ALL_PPC" = "y" ]; then
++ tristate 'Total Impact briQ front panel driver' CONFIG_BRIQ_PANEL
++fi
++
++if [ "$CONFIG_AR7" = "y" ]; then
++ bool 'VLYNQ support for the TI SOC' CONFIG_AR7_VLYNQ
++ dep_bool 'VLYNQ clock source Internal' CONFIG_VLYNQ_CLK_LOCAL $CONFIG_AR7_VLYNQ
++
++ define_int CONFIG_AR7_VLYNQ_PORTS 2
++fi
++
++source drivers/i2c/Config.in
++
++mainmenu_option next_comment
++comment 'Mice'
++tristate 'Bus Mouse Support' CONFIG_BUSMOUSE
++if [ "$CONFIG_BUSMOUSE" != "n" ]; then
++ dep_tristate ' ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE
++ dep_tristate ' Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE
++ dep_tristate ' Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE
++ if [ "$CONFIG_ADB" = "y" -a "$CONFIG_ADB_KEYBOARD" = "y" ]; then
++ dep_tristate ' Apple Desktop Bus mouse support (old driver)' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
++ fi
++# if [ "$CONFIG_DECSTATION" = "y" ]; then
++# dep_bool ' MAXINE Access.Bus mouse (VSXXX-BB/GB) support' CONFIG_DTOP_MOUSE $CONFIG_ACCESSBUS
++# fi
++fi
++
++tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE
++if [ "$CONFIG_MOUSE" != "n" ]; then
++ bool ' PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
++ tristate ' C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
++ tristate ' PC110 digitizer pad support' CONFIG_PC110_PAD
++ tristate ' MK712 touch screen support' CONFIG_MK712_MOUSE
++fi
++endmenu
++
++source drivers/char/joystick/Config.in
++
++tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE
++if [ "$CONFIG_QIC02_TAPE" != "n" ]; then
++ bool ' Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF
++ if [ "$CONFIG_QIC02_DYNCONF" != "y" ]; then
++ comment ' Edit configuration parameters in ./include/linux/tpqic02.h!'
++ else
++ comment ' Setting runtime QIC-02 configuration is done with qic02conf'
++ comment ' from the tpqic02-support package. It is available at'
++ comment ' metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/'
++ fi
++fi
++
++tristate 'IPMI top-level message handler' CONFIG_IPMI_HANDLER
++dep_mbool ' Generate a panic event to all BMCs on a panic' CONFIG_IPMI_PANIC_EVENT $CONFIG_IPMI_HANDLER
++dep_tristate ' Device interface for IPMI' CONFIG_IPMI_DEVICE_INTERFACE $CONFIG_IPMI_HANDLER
++dep_tristate ' IPMI KCS handler' CONFIG_IPMI_KCS $CONFIG_IPMI_HANDLER
++dep_tristate ' IPMI Watchdog Timer' CONFIG_IPMI_WATCHDOG $CONFIG_IPMI_HANDLER
++
++mainmenu_option next_comment
++comment 'Watchdog Cards'
++bool 'Watchdog Timer Support' CONFIG_WATCHDOG
++if [ "$CONFIG_WATCHDOG" != "n" ]; then
++ bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
++ tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
++ tristate ' Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT
++ tristate ' ALi M7101 PMU on ALi 1535D+ Watchdog Timer' CONFIG_ALIM1535_WDT
++ tristate ' ALi M7101 PMU Watchdog Timer' CONFIG_ALIM7101_WDT
++ tristate ' AMD "Elan" SC520 Watchdog Timer' CONFIG_SC520_WDT
++ tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
++ if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
++ tristate ' DC21285 watchdog' CONFIG_21285_WATCHDOG
++ if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then
++ tristate ' NetWinder WB83C977 watchdog' CONFIG_977_WATCHDOG
++ fi
++ fi
++ tristate ' Eurotech CPU-1220/1410 Watchdog Timer' CONFIG_EUROTECH_WDT
++ tristate ' IB700 SBC Watchdog Timer' CONFIG_IB700_WDT
++ tristate ' ICP ELectronics Wafer 5823 Watchdog' CONFIG_WAFER_WDT
++ tristate ' Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO
++ tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD
++ tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
++ dep_tristate ' SC1200 Watchdog Timer (EXPERIMENTAL)' CONFIG_SC1200_WDT $CONFIG_EXPERIMENTAL
++ tristate ' NatSemi SCx200 Watchdog' CONFIG_SCx200_WDT
++ tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG
++ tristate ' W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT
++ tristate ' WDT Watchdog timer' CONFIG_WDT
++ tristate ' WDT PCI Watchdog timer' CONFIG_WDTPCI
++ if [ "$CONFIG_WDT" != "n" ]; then
++ bool ' WDT501 features' CONFIG_WDT_501
++ if [ "$CONFIG_WDT_501" = "y" ]; then
++ bool ' Fan Tachometer' CONFIG_WDT_501_FAN
++ fi
++ fi
++ tristate ' ZF MachZ Watchdog' CONFIG_MACHZ_WDT
++ if [ "$CONFIG_SGI_IP22" = "y" ]; then
++ dep_tristate ' Indy/I2 Hardware Watchdog' CONFIG_INDYDOG $CONFIG_SGI_IP22
++ fi
++ if [ "$CONFIG_8xx" = "y" ]; then
++ tristate ' MPC8xx Watchdog Timer' CONFIG_8xx_WDT
++ fi
++fi
++endmenu
++
++if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then
++ tristate 'NetWinder thermometer support' CONFIG_DS1620
++ tristate 'NetWinder Button' CONFIG_NWBUTTON
++ if [ "$CONFIG_NWBUTTON" != "n" ]; then
++ bool ' Reboot Using Button' CONFIG_NWBUTTON_REBOOT
++ fi
++ tristate 'NetWinder flash support' CONFIG_NWFLASH
++fi
++tristate 'NatSemi SCx200 Support' CONFIG_SCx200
++dep_tristate ' NatSemi SCx200 GPIO Support' CONFIG_SCx200_GPIO $CONFIG_SCx200
++
++if [ "$CONFIG_IA64_GENERIC" = "y" -o "$CONFIG_IA64_SGI_SN2" = "y" ] ; then
++ bool 'SGI SN2 fetchop support' CONFIG_FETCHOP
++fi
++
++if [ "$CONFIG_X86" = "y" -o "$CONFIG_X86_64" = "y" ]; then
++ dep_tristate 'AMD 768/8111 Random Number Generator support' CONFIG_AMD_RNG $CONFIG_PCI
++fi
++if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then
++ dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI
++fi
++if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" -o \
++ "$CONFIG_X86_64" = "y" ]; then
++ dep_tristate 'Intel/AMD/VIA HW Random Number Generator support' CONFIG_HW_RANDOM $CONFIG_PCI
++fi
++dep_tristate 'AMD 76x native power management (Experimental)' CONFIG_AMD_PM768 $CONFIG_PCI
++tristate '/dev/nvram support' CONFIG_NVRAM
++tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
++if [ "$CONFIG_IA64" = "y" ]; then
++ bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC
++fi
++if [ "$CONFIG_OBSOLETE" = "y" -a "$CONFIG_ALPHA_BOOK1" = "y" ]; then
++ bool 'Tadpole ANA H8 Support (OBSOLETE)' CONFIG_H8
++fi
++if [ "$CONFIG_SGI_IP22" = "y" ]; then
++ tristate 'Dallas DS1286 RTC support' CONFIG_DS1286
++fi
++if [ "$CONFIG_SGI_IP27" = "y" ]; then
++ tristate 'SGI M48T35 RTC support' CONFIG_SGI_IP27_RTC
++fi
++if [ "$CONFIG_TOSHIBA_RBTX4927" = "y" -o "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then
++ tristate 'Dallas DS1742 RTC support' CONFIG_DS1742
++fi
++
++tristate 'Double Talk PC internal speech card support' CONFIG_DTLK
++tristate 'Siemens R3964 line discipline' CONFIG_R3964
++tristate 'Applicom intelligent fieldbus card support' CONFIG_APPLICOM
++if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_X86" = "y" -a "$CONFIG_X86_64" != "y" ]; then
++ dep_tristate 'Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)' CONFIG_SONYPI $CONFIG_PCI
++fi
++
++mainmenu_option next_comment
++comment 'Ftape, the floppy tape device driver'
++tristate 'Ftape (QIC-80/Travan) support' CONFIG_FTAPE
++if [ "$CONFIG_FTAPE" != "n" ]; then
++ source drivers/char/ftape/Config.in
++fi
++
++endmenu
++
++if [ "$CONFIG_GART_IOMMU" = "y" ]; then
++ bool '/dev/agpgart (AGP Support)' CONFIG_AGP
++ define_bool CONFIG_AGP_AMD_K8 y
++else
++ tristate '/dev/agpgart (AGP Support)' CONFIG_AGP
++fi
++if [ "$CONFIG_AGP" != "n" ]; then
++ bool ' Intel 440LX/BX/GX and I815/I820/I830M/I830MP/I840/I845/I850/I860 support' CONFIG_AGP_INTEL
++ bool ' Intel I810/I815/I830M (on-board) support' CONFIG_AGP_I810
++ bool ' VIA chipset support' CONFIG_AGP_VIA
++ bool ' AMD Irongate, 761, and 762 support' CONFIG_AGP_AMD
++ if [ "$CONFIG_GART_IOMMU" != "y" ]; then
++ bool ' AMD Opteron/Athlon64 on-CPU GART support' CONFIG_AGP_AMD_K8
++ fi
++ bool ' Generic SiS support' CONFIG_AGP_SIS
++ bool ' ALI chipset support' CONFIG_AGP_ALI
++ bool ' Serverworks LE/HE support' CONFIG_AGP_SWORKS
++ if [ "$CONFIG_X86" = "y" ]; then
++ bool ' NVIDIA chipset support' CONFIG_AGP_NVIDIA
++ fi
++ if [ "$CONFIG_IA64" = "y" ]; then
++ bool ' Intel 460GX support' CONFIG_AGP_I460
++ bool ' HP ZX1 AGP support' CONFIG_AGP_HP_ZX1
++ fi
++ bool ' ATI IGP chipset support' CONFIG_AGP_ATI
++fi
++
++mainmenu_option next_comment
++comment 'Direct Rendering Manager (XFree86 DRI support)'
++bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
++if [ "$CONFIG_DRM" = "y" ]; then
++ bool ' Build drivers for old (XFree 4.0) DRM' CONFIG_DRM_OLD
++ if [ "$CONFIG_DRM_OLD" = "y" ]; then
++ comment 'DRM 4.0 drivers'
++ source drivers/char/drm-4.0/Config.in
++ else
++ comment 'DRM 4.1 drivers'
++ define_bool CONFIG_DRM_NEW y
++ source drivers/char/drm/Config.in
++ fi
++fi
++
++if [ "$CONFIG_X86" = "y" ]; then
++ tristate 'ACP Modem (Mwave) support' CONFIG_MWAVE
++fi
++
++endmenu
++
++if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
++ source drivers/char/pcmcia/Config.in
++fi
++if [ "$CONFIG_SOC_AU1X00" = "y" ]; then
++ tristate ' Alchemy Au1x00 GPIO device support' CONFIG_AU1X00_GPIO
++ tristate ' Au1000/ADS7846 touchscreen support' CONFIG_TS_AU1X00_ADS7846
++ #tristate ' Alchemy Au1550 PSC SPI support' CONFIG_AU1550_PSC_SPI
++fi
++if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then
++ tristate ' ITE GPIO' CONFIG_ITE_GPIO
++fi
++
++if [ "$CONFIG_X86" = "y" ]; then
++ tristate 'ACP Modem (Mwave) support' CONFIG_MWAVE
++ dep_tristate 'HP OB600 C/CT Pop-up mouse support' CONFIG_OBMOUSE $CONFIG_INPUT_MOUSEDEV
++fi
++
++endmenu
+diff -urN linux.old/drivers/char/Makefile linux.dev/drivers/char/Makefile
+--- linux.old/drivers/char/Makefile 2005-10-21 16:43:16.460960500 +0200
++++ linux.dev/drivers/char/Makefile 2005-11-10 01:10:45.871576250 +0100
+@@ -240,6 +240,13 @@
+ obj-y += joystick/js.o
+ endif
+
++#
++# Texas Intruments VLYNQ driver
++#
++
++subdir-$(CONFIG_AR7_VLYNQ) += avalanche_vlynq
++obj-$(CONFIG_AR7_VLYNQ) += avalanche_vlynq/avalanche_vlynq.o
++
+ obj-$(CONFIG_FETCHOP) += fetchop.o
+ obj-$(CONFIG_BUSMOUSE) += busmouse.o
+ obj-$(CONFIG_DTLK) += dtlk.o
+@@ -340,6 +347,11 @@
+ obj-y += ipmi/ipmi.o
+ endif
+
++subdir-$(CONFIG_AR7_ADAM2) += ticfg
++ifeq ($(CONFIG_AR7_ADAM2),y)
++ obj-y += ticfg/ticfg.o
++endif
++
+ include $(TOPDIR)/Rules.make
+
+ fastdep:
+diff -urN linux.old/drivers/char/Makefile.orig linux.dev/drivers/char/Makefile.orig
+--- linux.old/drivers/char/Makefile.orig 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/char/Makefile.orig 2005-11-10 01:10:45.871576250 +0100
+@@ -0,0 +1,374 @@
++#
++# Makefile for the kernel character device drivers.
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definitions are now inherited from the
++# parent makes..
++#
++
++#
++# This file contains the font map for the default (hardware) font
++#
++FONTMAPFILE = cp437.uni
++
++O_TARGET := char.o
++
++obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o raw.o pty.o misc.o random.o
++
++# All of the (potential) objects that export symbols.
++# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
++
++export-objs := busmouse.o console.o keyboard.o sysrq.o \
++ misc.o pty.o random.o selection.o serial.o \
++ sonypi.o tty_io.o tty_ioctl.o generic_serial.o \
++ au1000_gpio.o vac-serial.o hp_psaux.o nvram.o \
++ scx200.o fetchop.o
++
++mod-subdirs := joystick ftape drm drm-4.0 pcmcia
++
++list-multi :=
++
++KEYMAP =defkeymap.o
++KEYBD =pc_keyb.o
++CONSOLE =console.o
++SERIAL =serial.o
++
++ifeq ($(ARCH),s390)
++ KEYMAP =
++ KEYBD =
++ CONSOLE =
++ SERIAL =
++endif
++
++ifeq ($(ARCH),mips)
++ ifneq ($(CONFIG_PC_KEYB),y)
++ KEYBD =
++ endif
++ ifeq ($(CONFIG_VR41XX_KIU),y)
++ ifeq ($(CONFIG_IBM_WORKPAD),y)
++ KEYMAP = ibm_workpad_keymap.o
++ endif
++ ifeq ($(CONFIG_VICTOR_MPC30X),y)
++ KEYMAP = victor_mpc30x_keymap.o
++ endif
++ KEYBD = vr41xx_keyb.o
++ endif
++endif
++
++ifeq ($(ARCH),s390x)
++ KEYMAP =
++ KEYBD =
++ CONSOLE =
++ SERIAL =
++endif
++
++ifeq ($(ARCH),m68k)
++ ifdef CONFIG_AMIGA
++ KEYBD = amikeyb.o
++ else
++ ifndef CONFIG_MAC
++ KEYBD =
++ endif
++ endif
++ SERIAL =
++endif
++
++ifeq ($(ARCH),parisc)
++ ifdef CONFIG_GSC_PS2
++ KEYBD = hp_psaux.o hp_keyb.o
++ else
++ KEYBD =
++ endif
++ ifdef CONFIG_SERIAL_MUX
++ CONSOLE += mux.o
++ endif
++ ifdef CONFIG_PDC_CONSOLE
++ CONSOLE += pdc_console.o
++ endif
++endif
++
++ifdef CONFIG_Q40
++ KEYBD += q40_keyb.o
++ SERIAL = serial.o
++endif
++
++ifdef CONFIG_APOLLO
++ KEYBD += dn_keyb.o
++endif
++
++ifeq ($(ARCH),parisc)
++ ifdef CONFIG_GSC_PS2
++ KEYBD = hp_psaux.o hp_keyb.o
++ else
++ KEYBD =
++ endif
++ ifdef CONFIG_PDC_CONSOLE
++ CONSOLE += pdc_console.o
++ endif
++endif
++
++ifeq ($(ARCH),arm)
++ ifneq ($(CONFIG_PC_KEYMAP),y)
++ KEYMAP =
++ endif
++ ifneq ($(CONFIG_PC_KEYB),y)
++ KEYBD =
++ endif
++endif
++
++ifeq ($(ARCH),sh)
++ KEYMAP =
++ KEYBD =
++ CONSOLE =
++ ifeq ($(CONFIG_SH_HP600),y)
++ KEYMAP = defkeymap.o
++ KEYBD = scan_keyb.o hp600_keyb.o
++ CONSOLE = console.o
++ endif
++ ifeq ($(CONFIG_SH_DMIDA),y)
++ # DMIDA does not connect the HD64465 PS/2 keyboard port
++ # but we allow for USB keyboards to be plugged in.
++ KEYMAP = defkeymap.o
++ KEYBD = # hd64465_keyb.o pc_keyb.o
++ CONSOLE = console.o
++ endif
++ ifeq ($(CONFIG_SH_EC3104),y)
++ KEYMAP = defkeymap.o
++ KEYBD = ec3104_keyb.o
++ CONSOLE = console.o
++ endif
++ ifeq ($(CONFIG_SH_DREAMCAST),y)
++ KEYMAP = defkeymap.o
++ KEYBD =
++ CONSOLE = console.o
++ endif
++endif
++
++ifeq ($(CONFIG_DECSTATION),y)
++ KEYMAP =
++ KEYBD =
++endif
++
++ifeq ($(CONFIG_BAGET_MIPS),y)
++ KEYBD =
++ SERIAL = vac-serial.o
++endif
++
++ifeq ($(CONFIG_NINO),y)
++ SERIAL =
++endif
++
++ifneq ($(CONFIG_SUN_SERIAL),)
++ SERIAL =
++endif
++
++ifeq ($(CONFIG_QTRONIX_KEYBOARD),y)
++ KEYBD = qtronix.o
++ KEYMAP = qtronixmap.o
++endif
++
++ifeq ($(CONFIG_DUMMY_KEYB),y)
++ KEYBD = dummy_keyb.o
++endif
++
++obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o
++obj-$(CONFIG_SERIAL) += $(SERIAL)
++obj-$(CONFIG_PARPORT_SERIAL) += parport_serial.o
++obj-$(CONFIG_SERIAL_HCDP) += hcdp_serial.o
++obj-$(CONFIG_SERIAL_21285) += serial_21285.o
++obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o
++obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o
++obj-$(CONFIG_TS_AU1X00_ADS7846) += au1000_ts.o
++obj-$(CONFIG_SERIAL_DEC) += decserial.o
++
++ifndef CONFIG_SUN_KEYBOARD
++ obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD)
++else
++ obj-$(CONFIG_PCI) += keyboard.o $(KEYMAP)
++endif
++
++obj-$(CONFIG_HIL) += hp_keyb.o
++obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
++obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
++obj-$(CONFIG_ROCKETPORT) += rocket.o
++obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
++obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
++obj-$(CONFIG_DIGI) += pcxx.o
++obj-$(CONFIG_DIGIEPCA) += epca.o
++obj-$(CONFIG_CYCLADES) += cyclades.o
++obj-$(CONFIG_STALLION) += stallion.o
++obj-$(CONFIG_ISTALLION) += istallion.o
++obj-$(CONFIG_SIBYTE_SB1250_DUART) += sb1250_duart.o
++obj-$(CONFIG_COMPUTONE) += ip2.o ip2main.o
++obj-$(CONFIG_RISCOM8) += riscom8.o
++obj-$(CONFIG_ISI) += isicom.o
++obj-$(CONFIG_ESPSERIAL) += esp.o
++obj-$(CONFIG_SYNCLINK) += synclink.o
++obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o
++obj-$(CONFIG_N_HDLC) += n_hdlc.o
++obj-$(CONFIG_SPECIALIX) += specialix.o
++obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
++obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o
++obj-$(CONFIG_SX) += sx.o generic_serial.o
++obj-$(CONFIG_RIO) += rio/rio.o generic_serial.o
++obj-$(CONFIG_SH_SCI) += sh-sci.o generic_serial.o
++obj-$(CONFIG_SERIAL167) += serial167.o
++obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o
++obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o
++obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o
++obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o
++obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o
++obj-$(CONFIG_TXX927_SERIAL) += serial_txx927.o
++obj-$(CONFIG_SERIAL_TXX9) += generic_serial.o serial_txx9.o
++obj-$(CONFIG_IP22_SERIAL) += sgiserial.o
++obj-$(CONFIG_AU1X00_UART) += au1x00-serial.o
++obj-$(CONFIG_SGI_L1_SERIAL) += sn_serial.o
++
++subdir-$(CONFIG_RIO) += rio
++subdir-$(CONFIG_INPUT) += joystick
++
++obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o
++obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o
++obj-$(CONFIG_PRINTER) += lp.o
++obj-$(CONFIG_TIPAR) += tipar.o
++obj-$(CONFIG_OBMOUSE) += obmouse.o
++
++ifeq ($(CONFIG_INPUT),y)
++obj-y += joystick/js.o
++endif
++
++#
++# Texas Intruments VLYNQ driver
++#
++
++subdir-$(CONFIG_AR7_VLYNQ) += avalanche_vlynq
++obj-$(CONFIG_AR7_VLYNQ) += avalanche_vlynq/avalanche_vlynq.o
++
++obj-$(CONFIG_FETCHOP) += fetchop.o
++obj-$(CONFIG_BUSMOUSE) += busmouse.o
++obj-$(CONFIG_DTLK) += dtlk.o
++obj-$(CONFIG_R3964) += n_r3964.o
++obj-$(CONFIG_APPLICOM) += applicom.o
++obj-$(CONFIG_SONYPI) += sonypi.o
++obj-$(CONFIG_MS_BUSMOUSE) += msbusmouse.o
++obj-$(CONFIG_82C710_MOUSE) += qpmouse.o
++obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o
++obj-$(CONFIG_ATARIMOUSE) += atarimouse.o
++obj-$(CONFIG_ADBMOUSE) += adbmouse.o
++obj-$(CONFIG_PC110_PAD) += pc110pad.o
++obj-$(CONFIG_MK712_MOUSE) += mk712.o
++obj-$(CONFIG_RTC) += rtc.o
++obj-$(CONFIG_GEN_RTC) += genrtc.o
++obj-$(CONFIG_EFI_RTC) += efirtc.o
++obj-$(CONFIG_MIPS_RTC) += mips_rtc.o
++obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
++ifeq ($(CONFIG_PPC),)
++ obj-$(CONFIG_NVRAM) += nvram.o
++endif
++obj-$(CONFIG_TOSHIBA) += toshiba.o
++obj-$(CONFIG_I8K) += i8k.o
++obj-$(CONFIG_DS1286) += ds1286.o
++obj-$(CONFIG_DS1620) += ds1620.o
++obj-$(CONFIG_DS1742) += ds1742.o
++obj-$(CONFIG_INTEL_RNG) += i810_rng.o
++obj-$(CONFIG_AMD_RNG) += amd768_rng.o
++obj-$(CONFIG_HW_RANDOM) += hw_random.o
++obj-$(CONFIG_AMD_PM768) += amd76x_pm.o
++obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
++
++obj-$(CONFIG_ITE_GPIO) += ite_gpio.o
++obj-$(CONFIG_AU1X00_GPIO) += au1000_gpio.o
++obj-$(CONFIG_AU1550_PSC_SPI) += au1550_psc_spi.o
++obj-$(CONFIG_AU1X00_USB_TTY) += au1000_usbtty.o
++obj-$(CONFIG_AU1X00_USB_RAW) += au1000_usbraw.o
++obj-$(CONFIG_COBALT_LCD) += lcd.o
++
++obj-$(CONFIG_QIC02_TAPE) += tpqic02.o
++
++subdir-$(CONFIG_FTAPE) += ftape
++subdir-$(CONFIG_DRM_OLD) += drm-4.0
++subdir-$(CONFIG_DRM_NEW) += drm
++subdir-$(CONFIG_PCMCIA) += pcmcia
++subdir-$(CONFIG_AGP) += agp
++
++ifeq ($(CONFIG_FTAPE),y)
++obj-y += ftape/ftape.o
++endif
++
++obj-$(CONFIG_H8) += h8.o
++obj-$(CONFIG_PPDEV) += ppdev.o
++obj-$(CONFIG_DZ) += dz.o
++obj-$(CONFIG_NWBUTTON) += nwbutton.o
++obj-$(CONFIG_NWFLASH) += nwflash.o
++obj-$(CONFIG_SCx200) += scx200.o
++obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o
++
++# Only one watchdog can succeed. We probe the hardware watchdog
++# drivers first, then the softdog driver. This means if your hardware
++# watchdog dies or is 'borrowed' for some reason the software watchdog
++# still gives you some cover.
++
++obj-$(CONFIG_PCWATCHDOG) += pcwd.o
++obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
++obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
++obj-$(CONFIG_IB700_WDT) += ib700wdt.o
++obj-$(CONFIG_MIXCOMWD) += mixcomwd.o
++obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
++obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
++obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
++obj-$(CONFIG_WDT) += wdt.o
++obj-$(CONFIG_WDTPCI) += wdt_pci.o
++obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
++obj-$(CONFIG_977_WATCHDOG) += wdt977.o
++obj-$(CONFIG_I810_TCO) += i810-tco.o
++obj-$(CONFIG_MACHZ_WDT) += machzwd.o
++obj-$(CONFIG_SH_WDT) += shwdt.o
++obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
++obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
++obj-$(CONFIG_ALIM1535_WDT) += alim1535d_wdt.o
++obj-$(CONFIG_INDYDOG) += indydog.o
++obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
++obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
++obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
++obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
++obj-$(CONFIG_INDYDOG) += indydog.o
++obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
++
++subdir-$(CONFIG_MWAVE) += mwave
++ifeq ($(CONFIG_MWAVE),y)
++ obj-y += mwave/mwave.o
++endif
++
++subdir-$(CONFIG_IPMI_HANDLER) += ipmi
++ifeq ($(CONFIG_IPMI_HANDLER),y)
++ obj-y += ipmi/ipmi.o
++endif
++
++include $(TOPDIR)/Rules.make
++
++fastdep:
++
++conmakehash: conmakehash.c
++ $(HOSTCC) $(HOSTCFLAGS) -o conmakehash conmakehash.c
++
++consolemap_deftbl.c: $(FONTMAPFILE) conmakehash
++ ./conmakehash $(FONTMAPFILE) > consolemap_deftbl.c
++
++consolemap_deftbl.o: consolemap_deftbl.c $(TOPDIR)/include/linux/types.h
++
++.DELETE_ON_ERROR:
++
++defkeymap.c: defkeymap.map
++ set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
++
++qtronixmap.c: qtronixmap.map
++ set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
++
++ibm_workpad_keymap.c: ibm_workpad_keymap.map
++ set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
++
++victor_mpc30x_keymap.c: victor_mpc30x_keymap.map
++ set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+diff -urN linux.old/drivers/char/avalanche_vlynq/Makefile linux.dev/drivers/char/avalanche_vlynq/Makefile
+--- linux.old/drivers/char/avalanche_vlynq/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/char/avalanche_vlynq/Makefile 2005-11-10 01:10:45.871576250 +0100
+@@ -0,0 +1,16 @@
++#
++# Makefile for the linux kernel.
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definitions are now in the main makefile...
++
++O_TARGET := avalanche_vlynq.o
++
++export-objs := vlynq_board.o
++
++obj-y += vlynq_drv.o vlynq_hal.o vlynq_board.o
++
++include $(TOPDIR)/Rules.make
+diff -urN linux.old/drivers/char/avalanche_vlynq/vlynq_board.c linux.dev/drivers/char/avalanche_vlynq/vlynq_board.c
+--- linux.old/drivers/char/avalanche_vlynq/vlynq_board.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/char/avalanche_vlynq/vlynq_board.c 2005-11-10 01:10:45.871576250 +0100
+@@ -0,0 +1,184 @@
++/*
++ * Jeff Harrell, jharrell@ti.com
++ * Copyright (C) 2001 Texas Instruments, Inc. All rights reserved.
++ *
++ * This program is free software; you can distribute it and/or modify it
++ * under the terms of the GNU General Public License (Version 2) as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope 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.
++ *
++ * Texas Instruments Sangam specific setup.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <asm/ar7/sangam.h>
++#include <asm/ar7/avalanche_misc.h>
++#include <asm/ar7/vlynq.h>
++
++#define SYS_VLYNQ_LOCAL_INTERRUPT_VECTOR 30 /* MSB - 1 bit */
++#define SYS_VLYNQ_REMOTE_INTERRUPT_VECTOR 31 /* MSB bit */
++#define SYS_VLYNQ_OPTIONS 0x7F; /* all options*/
++
++/* These defines are board specific */
++
++
++#define VLYNQ0_REMOTE_WINDOW1_OFFSET (0x0C000000)
++#define VLYNQ0_REMOTE_WINDOW1_SIZE (0x500)
++
++
++#define VLYNQ1_REMOTE_WINDOW1_OFFSET (0x0C000000)
++#define VLYNQ1_REMOTE_WINDOW1_SIZE (0x500)
++
++
++extern VLYNQ_DEV vlynqDevice0, vlynqDevice1;
++int vlynq_init_status[2] = {0, 0};
++EXPORT_SYMBOL(vlynq_init_status);
++static int reset_hack = 1;
++
++void vlynq_ar7wrd_dev_init()
++{
++ *(unsigned long*) AVALANCHE_GPIO_ENBL |= (1<<18);
++ vlynq_delay(20000);
++ *(unsigned long*) AVALANCHE_GPIO_DIR &= ~(1<<18);
++ vlynq_delay(20000);
++ *(unsigned long*) AVALANCHE_GPIO_DATA_OUT&= ~(1<<18);
++ vlynq_delay(50000);
++ *(unsigned long*) AVALANCHE_GPIO_DATA_OUT|= (1<<18);
++ vlynq_delay(50000);
++
++ /* Initialize the MIPS host vlynq driver for a given vlynq interface */
++ vlynqDevice0.dev_idx = 0; /* first vlynq module - this parameter is for reference only */
++ vlynqDevice0.module_base = AVALANCHE_LOW_VLYNQ_CONTROL_BASE; /* vlynq0 module base address */
++
++#if defined(CONFIG_VLYNQ_CLK_LOCAL)
++ vlynqDevice0.clk_source = VLYNQ_CLK_SOURCE_LOCAL;
++#else
++ vlynqDevice0.clk_source = VLYNQ_CLK_SOURCE_REMOTE;
++#endif
++ vlynqDevice0.clk_div = 0x01; /* board/hardware specific */
++ vlynqDevice0.state = VLYNQ_DRV_STATE_UNINIT; /* uninitialized module */
++
++ /* Populate vlynqDevice0.local_mem & Vlynq0.remote_mem based on system configuration */
++ /*Local memory configuration */
++
++ /* Demiurg : not good !*/
++#if 0
++ vlynqDevice0.local_mem.Txmap= AVALANCHE_LOW_VLYNQ_MEM_MAP_BASE & ~(0xc0000000) ; /* physical address */
++ vlynqDevice0.remote_mem.RxOffset[0]= VLYNQ0_REMOTE_WINDOW1_OFFSET; /* This is specific to the board on the other end */
++ vlynqDevice0.remote_mem.RxSize[0]=VLYNQ0_REMOTE_WINDOW1_SIZE;
++#endif
++
++ /* Demiurg : This is how it should be ! */
++ vlynqDevice0.local_mem.Txmap = PHYSADDR(AVALANCHE_LOW_VLYNQ_MEM_MAP_BASE);
++#define VLYNQ_ACX111_MEM_OFFSET 0xC0000000 /* Physical address of ACX111 memory */
++#define VLYNQ_ACX111_MEM_SIZE 0x00040000 /* Total size of the ACX111 memory */
++#define VLYNQ_ACX111_REG_OFFSET 0xF0000000 /* PHYS_ADDR of ACX111 control registers */
++#define VLYNQ_ACX111_REG_SIZE 0x00022000 /* Size of ACX111 registers area, MAC+PHY */
++#define ACX111_VL1_REMOTE_SIZE 0x1000000
++ vlynqDevice0.remote_mem.RxOffset[0] = VLYNQ_ACX111_MEM_OFFSET;
++ vlynqDevice0.remote_mem.RxSize[0] = VLYNQ_ACX111_MEM_SIZE ;
++ vlynqDevice0.remote_mem.RxOffset[1] = VLYNQ_ACX111_REG_OFFSET;
++ vlynqDevice0.remote_mem.RxSize[1] = VLYNQ_ACX111_REG_SIZE ;
++ vlynqDevice0.remote_mem.Txmap = 0;
++ vlynqDevice0.local_mem.RxOffset[0] = AVALANCHE_SDRAM_BASE;
++ vlynqDevice0.local_mem.RxSize[0] = ACX111_VL1_REMOTE_SIZE;
++
++
++ /* Local interrupt configuration */
++ vlynqDevice0.local_irq.intLocal = VLYNQ_INT_LOCAL; /* Host handles vlynq interrupts*/
++ vlynqDevice0.local_irq.intRemote = VLYNQ_INT_ROOT_ISR; /* vlynq root isr used */
++ vlynqDevice0.local_irq.map_vector = SYS_VLYNQ_LOCAL_INTERRUPT_VECTOR;
++ vlynqDevice0.local_irq.intr_ptr = 0; /* Since remote interrupts part of vlynq root isr this is unused */
++
++ /* Remote interrupt configuration */
++ vlynqDevice0.remote_irq.intLocal = VLYNQ_INT_REMOTE; /* MIPS handles interrupts */
++ vlynqDevice0.remote_irq.intRemote = VLYNQ_INT_ROOT_ISR; /* Not significant since MIPS handles interrupts */
++ vlynqDevice0.remote_irq.map_vector = SYS_VLYNQ_REMOTE_INTERRUPT_VECTOR;
++ vlynqDevice0. remote_irq.intr_ptr = AVALANCHE_INTC_BASE; /* Not significant since MIPS handles interrupts */
++
++ if(reset_hack != 1)
++ printk("About to re-init the VLYNQ.\n");
++
++ if(vlynq_init(&vlynqDevice0,VLYNQ_INIT_PERFORM_ALL)== 0)
++ {
++ /* Suraj added the following to keep the 1130 going. */
++ vlynq_interrupt_vector_set(&vlynqDevice0, 0 /* intr vector line running into 1130 vlynq */,
++ 0 /* intr mapped onto the interrupt register on remote vlynq and this vlynq */,
++ VLYNQ_REMOTE_DVC, 0 /* polarity active high */, 0 /* interrupt Level triggered */);
++
++ /* System wide interrupt is 80 for 1130, please note. */
++ vlynq_init_status[0] = 1;
++ reset_hack = 2;
++ }
++ else
++ {
++ if(reset_hack == 1)
++ printk("VLYNQ INIT FAILED: Please try cold reboot. \n");
++ else
++ printk("Failed to initialize the VLYNQ interface at insmod.\n");
++
++ }
++}
++
++void vlynq_dev_init(void)
++{
++ volatile unsigned int *reset_base = (unsigned int *) AVALANCHE_RESET_CONTROL_BASE;
++
++ *reset_base &= ~((1 << AVALANCHE_LOW_VLYNQ_RESET_BIT)); /* | (1 << AVALANCHE_HIGH_VLYNQ_RESET_BIT)); */
++
++ vlynq_delay(20000);
++
++ /* Bring vlynq out of reset if not already done */
++ *reset_base |= (1 << AVALANCHE_LOW_VLYNQ_RESET_BIT); /* | (1 << AVALANCHE_HIGH_VLYNQ_RESET_BIT); */
++ vlynq_delay(20000); /* Allowing sufficient time to VLYNQ to settle down.*/
++
++ vlynq_ar7wrd_dev_init( );
++
++}
++
++/* This function is board specific and should be ported for each board. */
++void remote_vlynq_dev_reset_ctrl(unsigned int module_reset_bit,
++ AVALANCHE_RESET_CTRL_T reset_ctrl)
++{
++ if(module_reset_bit >= 32)
++ return;
++
++ switch(module_reset_bit)
++ {
++ case 0:
++ if(OUT_OF_RESET == reset_ctrl)
++ {
++ if(reset_hack) return;
++
++ vlynq_delay(20000);
++ printk("Un-resetting the remote device.\n");
++ vlynq_dev_init();
++ printk("Re-initialized the VLYNQ.\n");
++ reset_hack = 2;
++ }
++ else if(IN_RESET == reset_ctrl)
++ {
++ *(unsigned long*) AVALANCHE_GPIO_DATA_OUT &= ~(1<<18);
++
++ vlynq_delay(20000);
++ printk("Resetting the remote device.\n");
++ reset_hack = 0;
++ }
++ else
++ ;
++ break;
++
++ default:
++ break;
++
++ }
++}
++
+diff -urN linux.old/drivers/char/avalanche_vlynq/vlynq_drv.c linux.dev/drivers/char/avalanche_vlynq/vlynq_drv.c
+--- linux.old/drivers/char/avalanche_vlynq/vlynq_drv.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/char/avalanche_vlynq/vlynq_drv.c 2005-11-10 01:10:45.891577500 +0100
+@@ -0,0 +1,243 @@
++/******************************************************************************
++ * FILE PURPOSE: Vlynq Linux Device Driver Source
++ ******************************************************************************
++ * FILE NAME: vlynq_drv.c
++ *
++ * DESCRIPTION: Vlynq Linux Device Driver Source
++ *
++ * REVISION HISTORY:
++ *
++ * Date Description Author
++ *-----------------------------------------------------------------------------
++ * 17 July 2003 Initial Creation Anant Gole
++ * 17 Dec 2003 Updates Sharath Kumar
++ *
++ * (C) Copyright 2003, Texas Instruments, Inc
++ *******************************************************************************/
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/miscdevice.h>
++#include <linux/smp_lock.h>
++#include <linux/delay.h>
++#include <linux/proc_fs.h>
++#include <linux/capability.h>
++#include <asm/ar7/avalanche_intc.h>
++#include <asm/ar7/sangam.h>
++#include <asm/ar7/vlynq.h>
++
++
++#define TI_VLYNQ_VERSION "0.2"
++
++/* debug on ? */
++#define VLYNQ_DEBUG
++
++/* Macro for debug and error printf's */
++#ifdef VLYNQ_DEBUG
++#define DBGPRINT printk
++#else
++#define DBGPRINT(x)
++#endif
++
++#define ERRPRINT printk
++
++/* Define the max vlynq ports this driver will support.
++ Device name strings are statically added here */
++#define MAX_VLYNQ_PORTS 2
++
++
++/* Type define for VLYNQ private structure */
++typedef struct vlynqPriv{
++ int irq;
++ VLYNQ_DEV *vlynqDevice;
++}VLYNQ_PRIV;
++
++extern int vlynq_init_status[2];
++
++/* Extern Global variable for vlynq devices used in initialization of the vlynq device
++ * These variables need to be populated/initialized by the system as part of initialization
++ * process. The vlynq enumerator can run at initialization and populate these globals
++ */
++
++VLYNQ_DEV vlynqDevice0;
++VLYNQ_DEV vlynqDevice1;
++
++/* Defining dummy macro AVALANCHE_HIGH_VLYNQ_INT to take
++ * care of compilation in case of single vlynq device
++ */
++
++#ifndef AVALANCHE_HIGH_VLYNQ_INT
++#define AVALANCHE_HIGH_VLYNQ_INT 0
++#endif
++
++
++
++/* vlynq private object */
++VLYNQ_PRIV vlynq_priv[CONFIG_AR7_VLYNQ_PORTS] = {
++ { LNXINTNUM(AVALANCHE_LOW_VLYNQ_INT),&vlynqDevice0},
++ { LNXINTNUM(AVALANCHE_HIGH_VLYNQ_INT),&vlynqDevice1},
++};
++
++extern void vlynq_dev_init(void);
++
++
++/* =================================== all the operations */
++
++static int
++vlynq_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++ return 0;
++}
++
++static struct file_operations vlynq_fops = {
++ owner: THIS_MODULE,
++ ioctl: vlynq_ioctl,
++};
++
++/* Vlynq device object */
++static struct miscdevice vlynq_dev [MAX_VLYNQ_PORTS] = {
++ { MISC_DYNAMIC_MINOR , "vlynq0", &vlynq_fops },
++ { MISC_DYNAMIC_MINOR , "vlynq1", &vlynq_fops },
++};
++
++
++/* Proc read function */
++static int
++vlynq_read_link_proc(char *buf, char **start, off_t offset, int count, int *eof, void *unused)
++{
++ int instance;
++ int len = 0;
++
++ len += sprintf(buf +len,"VLYNQ Devices : %d\n",CONFIG_AR7_VLYNQ_PORTS);
++
++ for(instance =0;instance < CONFIG_AR7_VLYNQ_PORTS;instance++)
++ {
++ int link_state;
++ char *link_msg[] = {" DOWN "," UP "};
++
++ if(vlynq_init_status[instance] == 0)
++ link_state = 0;
++
++ else if (vlynq_link_check(vlynq_priv[instance].vlynqDevice))
++ link_state = 1;
++
++ else
++ link_state = 0;
++
++ len += sprintf(buf + len, "VLYNQ %d: Link state: %s\n",instance,link_msg[link_state]);
++
++ }
++ /* Print info about vlynq device 1 */
++
++ return len;
++}
++
++
++/* Proc function to display driver version */
++static int
++vlynq_read_ver_proc(char *buf, char **start, off_t offset, int count, int *eof, void *data)
++{
++ int instance;
++ int len=0;
++
++ len += sprintf(buf +len,"\nTI Linux VLYNQ Driver Version %s\n",TI_VLYNQ_VERSION);
++ return len;
++}
++
++
++
++
++/* Wrapper for vlynq ISR */
++static void lnx_vlynq_root_isr(int irq, void * arg, struct pt_regs *regs)
++{
++ vlynq_root_isr(arg);
++}
++
++/* =================================== init and cleanup */
++
++int vlynq_init_module(void)
++{
++ int ret;
++ int unit = 0;
++ int instance_count = CONFIG_AR7_VLYNQ_PORTS;
++ volatile int *ptr;
++
++ vlynq_dev_init();
++
++ DBGPRINT("Vlynq CONFIG_AR7_VLYNQ_PORTS=%d\n", CONFIG_AR7_VLYNQ_PORTS);
++ /* If num of configured vlynq ports > supported by driver return error */
++ if (instance_count > MAX_VLYNQ_PORTS)
++ {
++ ERRPRINT("ERROR: vlynq_init_module(): Max %d supported\n", MAX_VLYNQ_PORTS);
++ return (-1);
++ }
++
++ /* register the misc device */
++ for (unit = 0; unit < CONFIG_AR7_VLYNQ_PORTS; unit++)
++ {
++ ret = misc_register(&vlynq_dev[unit]);
++
++ if(ret < 0)
++ {
++ ERRPRINT("ERROR:Could not register vlynq device:%d\n",unit);
++ continue;
++ }
++ else
++ DBGPRINT("Vlynq Device %s registered with minor no %d as misc device. Result=%d\n",
++ vlynq_dev[unit].name, vlynq_dev[unit].minor, ret);
++#if 0
++
++ DBGPRINT("Calling vlynq init\n");
++
++ /* Read the global variable for VLYNQ device structure and initialize vlynq driver */
++ ret = vlynq_init(vlynq_priv[unit].vlynqDevice,VLYNQ_INIT_PERFORM_ALL );
++#endif
++
++ if(vlynq_init_status[unit] == 0)
++ {
++ printk("VLYNQ %d : init failed\n",unit);
++ continue;
++ }
++
++ /* Check link before proceeding */
++ if (!vlynq_link_check(vlynq_priv[unit].vlynqDevice))
++ {
++ DBGPRINT("\nError: Vlynq link not available.trying once before Exiting");
++ }
++ else
++ {
++ DBGPRINT("Vlynq instance:%d Link UP\n",unit);
++
++ /* Install the vlynq local root ISR */
++ request_irq(vlynq_priv[unit].irq,lnx_vlynq_root_isr,0,vlynq_dev[unit].name,vlynq_priv[unit].vlynqDevice);
++ }
++ }
++
++ proc_mkdir("avalanche", NULL);
++ /* Creating proc entry for the devices */
++ create_proc_read_entry("avalanche/vlynq_link", 0, NULL, vlynq_read_link_proc, NULL);
++ create_proc_read_entry("avalanche/vlynq_ver", 0, NULL, vlynq_read_ver_proc, NULL);
++
++ return 0;
++}
++
++void vlynq_cleanup_module(void)
++{
++ int unit = 0;
++
++ for (unit = 0; unit < CONFIG_AR7_VLYNQ_PORTS; unit++)
++ {
++ DBGPRINT("vlynq_cleanup_module(): Unregistring misc device %s\n",vlynq_dev[unit].name);
++ misc_deregister(&vlynq_dev[unit]);
++ }
++
++ remove_proc_entry("avalanche/vlynq_link", NULL);
++ remove_proc_entry("avalanche/vlynq_ver", NULL);
++}
++
++
++module_init(vlynq_init_module);
++module_exit(vlynq_cleanup_module);
++
+diff -urN linux.old/drivers/char/avalanche_vlynq/vlynq_hal.c linux.dev/drivers/char/avalanche_vlynq/vlynq_hal.c
+--- linux.old/drivers/char/avalanche_vlynq/vlynq_hal.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/char/avalanche_vlynq/vlynq_hal.c 2005-11-10 01:10:45.975582750 +0100
+@@ -0,0 +1,1214 @@
++/***************************************************************************
++**+----------------------------------------------------------------------+**
++**| **** |**
++**| **** |**
++**| ******o*** |**
++**| ********_///_**** |**
++**| ***** /_//_/ **** |**
++**| ** ** (__/ **** |**
++**| ********* |**
++**| **** |**
++**| *** |**
++**| |**
++**| Copyright (c) 2003 Texas Instruments Incorporated |**
++**| ALL RIGHTS RESERVED |**
++**| |**
++**| Permission is hereby granted to licensees of Texas Instruments |**
++**| Incorporated (TI) products to use this computer program for the sole |**
++**| purpose of implementing a licensee product based on TI products. |**
++**| No other rights to reproduce, use, or disseminate this computer |**
++**| program, whether in part or in whole, are granted. |**
++**| |**
++**| TI makes no representation or warranties with respect to the |**
++**| performance of this computer program, and specifically disclaims |**
++**| any responsibility for any damages, special or consequential, |**
++**| connected with the use of this program. |**
++**| |**
++**+----------------------------------------------------------------------+**
++***************************************************************************/
++
++/***************************************************************************
++ * ------------------------------------------------------------------------------
++ * Module : vlynq_hal.c
++ * Description : This file implements VLYNQ HAL API.
++ * ------------------------------------------------------------------------------
++ ***************************************************************************/
++
++#include <linux/stddef.h>
++#include <linux/types.h>
++#include <asm/ar7/vlynq.h>
++
++/**** Local Function prototypes *******/
++static int vlynqInterruptInit(VLYNQ_DEV *pdev);
++static void vlynq_configClock(VLYNQ_DEV *pdev);
++
++/*** Second argument must be explicitly type casted to
++ * (VLYNQ_DEV*) inside the following functions */
++static void vlynq_local_module_isr(void *arg1, void *arg2, void *arg3);
++static void vlynq_remote_module_isr(void *arg1, void *arg2, void *arg3);
++
++
++volatile int vlynq_delay_value = 0;
++
++/* Code adopted from original vlynq driver */
++void vlynq_delay(unsigned int clktime)
++{
++ int i = 0;
++ volatile int *ptr = &vlynq_delay_value;
++ *ptr = 0;
++
++ /* We are assuming that the each cycle takes about
++ * 23 assembly instructions. */
++ for(i = 0; i < (clktime + 23)/23; i++)
++ {
++ *ptr = *ptr + 1;
++ }
++}
++
++
++/* ----------------------------------------------------------------------------
++ * Function : vlynq_configClock()
++ * Description: Configures clock settings based on input parameters
++ * Adapted from original vlyna driver from Cable
++ */
++static void vlynq_configClock(VLYNQ_DEV * pdev)
++{
++ unsigned int tmp;
++
++ switch( pdev->clk_source)
++ {
++ case VLYNQ_CLK_SOURCE_LOCAL: /* we output the clock, clk_div in range [1..8]. */
++ tmp = ((pdev->clk_div - 1) << 16) | VLYNQ_CTL_CLKDIR_MASK ;
++ VLYNQ_CTRL_REG = tmp;
++ VLYNQ_R_CTRL_REG = 0ul;
++ break;
++ case VLYNQ_CLK_SOURCE_REMOTE: /* we need to set the clock pin as input */
++ VLYNQ_CTRL_REG = 0ul;
++ tmp = ((pdev->clk_div - 1) << 16) | VLYNQ_CTL_CLKDIR_MASK ;
++ VLYNQ_R_CTRL_REG = tmp;
++ break;
++ default: /* do nothing about the clock, but clear other bits. */
++ tmp = ~(VLYNQ_CTL_CLKDIR_MASK | VLYNQ_CTL_CLKDIV_MASK);
++ VLYNQ_CTRL_REG &= tmp;
++ break;
++ }
++}
++
++ /* ----------------------------------------------------------------------------
++ * Function : vlynq_link_check()
++ * Description: This function checks the current VLYNQ for a link.
++ * An arbitrary amount of time is allowed for the link to come up .
++ * Returns 0 for "no link / failure " and 1 for "link available".
++ * -----------------------------------------------------------------------------
++ */
++unsigned int vlynq_link_check( VLYNQ_DEV * pdev)
++{
++ /*sleep for 64 cycles, allow link to come up*/
++ vlynq_delay(64);
++
++ /* check status register return OK if link is found. */
++ if (VLYNQ_STATUS_REG & VLYNQ_STS_LINK_MASK)
++ {
++ return 1; /* Link Available */
++ }
++ else
++ {
++ return 0; /* Link Failure */
++ }
++}
++
++/* ----------------------------------------------------------------------------
++ * Function : vlynq_init()
++ * Description: Initialization function accepting paramaters for VLYNQ module
++ * initialization. The Options bitmap decides what operations are performed
++ * as a part of initialization. The Input parameters are obtained through the
++ * sub fields of VLYNQ_DEV structure.
++ */
++
++int vlynq_init(VLYNQ_DEV *pdev, VLYNQ_INIT_OPTIONS options)
++{
++ unsigned int map;
++ unsigned int val=0,cnt,tmp;
++ unsigned int counter=0;
++ VLYNQ_INTERRUPT_CNTRL *intSetting=NULL;
++
++ /* validate arguments */
++ if( VLYNQ_OUTRANGE(pdev->clk_source, VLYNQ_CLK_SOURCE_REMOTE, VLYNQ_CLK_SOURCE_NONE) ||
++ VLYNQ_OUTRANGE(pdev->clk_div, 8, 1) )
++ {
++ return VLYNQ_INVALID_ARG;
++ }
++
++ /** perform all sanity checks first **/
++ if(pdev->state != VLYNQ_DRV_STATE_UNINIT)
++ return VLYNQ_INVALID_DRV_STATE;
++
++ /** Initialize local and remote register set addresses- additional
++ * provision to access the registers directly if need be */
++ pdev->local = (VLYNQ_REG_SET*)pdev->module_base;
++ pdev->remote = (VLYNQ_REG_SET*) (pdev->module_base + VLYNQ_REMOTE_REGS_OFFSET);
++
++ /* Detect faulty int configuration that might induce int pkt looping */
++ if ( (options & VLYNQ_INIT_LOCAL_INTERRUPTS) && (options & VLYNQ_INIT_REMOTE_INTERRUPTS) )
++ {
++ /* case when both local and remote are configured */
++ if((pdev->local_irq.intLocal== VLYNQ_INT_REMOTE ) /* interrupts transfered to remote from local */
++ && (pdev->remote_irq.intLocal== VLYNQ_INT_REMOTE) /* interrupts transfered from remote to local */
++ && ((pdev->local_irq.intRemote == VLYNQ_INT_ROOT_ISR) || (pdev->remote_irq.intRemote == VLYNQ_INT_ROOT_ISR)) )
++ {
++ return (VLYNQ_INT_CONFIG_ERR);
++ }
++ }
++
++ pdev->state = VLYNQ_DRV_STATE_ININIT;
++ pdev->intCount = 0;
++ pdev->isrCount = 0;
++
++ /*** Its assumed that the vlynq module has been brought out of reset
++ * before invocation of vlynq_init. Since, this operation is board specific
++ * it must be handled outside this generic driver */
++
++ /* Assert reset the remote device, call reset_cb,
++ * reset CB holds Reset according to the device needs. */
++ VLYNQ_RESETCB(VLYNQ_RESET_ASSERT);
++
++ /* Handle VLYNQ clock, HW default (Sense On Reset) is
++ * usually input for all the devices. */
++ if (options & VLYNQ_INIT_CONFIG_CLOCK)
++ {
++ vlynq_configClock(pdev);
++ }
++
++ /* Call reset_cb again. It will release the remote device
++ * from reset, and wait for a while. */
++ VLYNQ_RESETCB(VLYNQ_RESET_DEASSERT);
++
++ if(options & VLYNQ_INIT_CHECK_LINK )
++ {
++ /* Check for link up during initialization*/
++ while( counter < 25 )
++ {
++ /* loop around giving a chance for link status to settle down */
++ counter++;
++ if(vlynq_link_check(pdev))
++ {
++ /* Link is up exit loop*/
++ break;
++ }
++
++ vlynq_delay(4000);
++ }/*end of while counter loop */
++
++ if(!vlynq_link_check(pdev))
++ {
++ /* Handle this case as abort */
++ pdev->state = VLYNQ_DRV_STATE_ERROR;
++ VLYNQ_RESETCB( VLYNQ_RESET_INITFAIL);
++ return VLYNQ_LINK_DOWN;
++ }/* end of if not vlynq_link_check conditional block */
++
++ }/*end of if options & VLYNQ_INIT_CHECK_LINK conditional block */
++
++
++ if (options & VLYNQ_INIT_LOCAL_MEM_REGIONS)
++ {
++ /* Initialise local memory regions . This initialization lets
++ * the local host access remote device memory regions*/
++ int i;
++
++ /* configure the VLYNQ portal window to a PHYSICAL
++ * address of the local CPU */
++ VLYNQ_ALIGN4(pdev->local_mem.Txmap);
++ VLYNQ_TXMAP_REG = (pdev->local_mem.Txmap);
++
++ /*This code assumes input parameter is itself a physical address */
++ for(i=0; i < VLYNQ_MAX_MEMORY_REGIONS ; i++)
++ {
++ /* Physical address on the remote */
++ map = i+1;
++ VLYNQ_R_RXMAP_SIZE_REG(map) = 0;
++ if( pdev->remote_mem.RxSize[i])
++ {
++ VLYNQ_ALIGN4(pdev->remote_mem.RxOffset[i]);
++ VLYNQ_ALIGN4(pdev->remote_mem.RxSize[i]);
++ VLYNQ_R_RXMAP_OFFSET_REG(map) = pdev->remote_mem.RxOffset[i];
++ VLYNQ_R_RXMAP_SIZE_REG(map) = pdev->remote_mem.RxSize[i];
++ }
++ }
++ }
++
++ if(options & VLYNQ_INIT_REMOTE_MEM_REGIONS )
++ {
++ int i;
++
++ /* Initialise remote memory regions. This initialization lets remote
++ * device access local host memory regions. It configures the VLYNQ portal
++ * window to a PHYSICAL address of the remote */
++ VLYNQ_ALIGN4(pdev->remote_mem.Txmap);
++ VLYNQ_R_TXMAP_REG = pdev->remote_mem.Txmap;
++
++ for( i=0; i<VLYNQ_MAX_MEMORY_REGIONS; i++)
++ {
++ /* Physical address on the local */
++ map = i+1;
++ VLYNQ_RXMAP_SIZE_REG(map) = 0;
++ if( pdev->local_mem.RxSize[i])
++ {
++ VLYNQ_ALIGN4(pdev->local_mem.RxOffset[i]);
++ VLYNQ_ALIGN4(pdev->local_mem.RxSize[i]);
++ VLYNQ_RXMAP_OFFSET_REG(map) = (pdev->local_mem.RxOffset[i]);
++ VLYNQ_RXMAP_SIZE_REG(map) = (pdev->local_mem.RxSize[i]);
++ }
++ }
++ }
++
++ /* Adapted from original vlynq driver from cable - Calculate VLYNQ bus width */
++ pdev->width = 3 + VLYNQ_STATUS_FLD_WIDTH(VLYNQ_STATUS_REG)
++ + VLYNQ_STATUS_FLD_WIDTH(VLYNQ_R_STATUS_REG);
++
++ /* chance to initialize the device, e.g. to boost VLYNQ
++ * clock by modifying pdev->clk_div or and verify the width. */
++ VLYNQ_RESETCB(VLYNQ_RESET_LINKESTABLISH);
++
++ /* Handle VLYNQ clock, HW default (Sense On Reset) is
++ * usually input for all the devices. */
++ if(options & VLYNQ_INIT_CONFIG_CLOCK )
++ {
++ vlynq_configClock(pdev);
++ }
++
++ /* last check for link*/
++ if(options & VLYNQ_INIT_CHECK_LINK )
++ {
++ /* Final Check for link during initialization*/
++ while( counter < 25 )
++ {
++ /* loop around giving a chance for link status to settle down */
++ counter++;
++ if(vlynq_link_check(pdev))
++ {
++ /* Link is up exit loop*/
++ break;
++ }
++
++ vlynq_delay(4000);
++ }/*end of while counter loop */
++
++ if(!vlynq_link_check(pdev))
++ {
++ /* Handle this case as abort */
++ pdev->state = VLYNQ_DRV_STATE_ERROR;
++ VLYNQ_RESETCB( VLYNQ_RESET_INITFAIL);
++ return VLYNQ_LINK_DOWN;
++ }/* end of if not vlynq_link_check conditional block */
++
++ } /* end of if options & VLYNQ_INIT_CHECK_LINK */
++
++ if(options & VLYNQ_INIT_LOCAL_INTERRUPTS )
++ {
++ /* Configure local interrupt settings */
++ intSetting = &(pdev->local_irq);
++
++ /* Map local module status interrupts to interrupt vector*/
++ val = intSetting->map_vector << VLYNQ_CTL_INTVEC_SHIFT ;
++
++ /* enable local module status interrupts */
++ val |= 0x01 << VLYNQ_CTL_INTEN_SHIFT;
++
++ if ( intSetting->intLocal == VLYNQ_INT_LOCAL )
++ {
++ /*set the intLocal bit*/
++ val |= 0x01 << VLYNQ_CTL_INTLOCAL_SHIFT;
++ }
++
++ /* Irrespective of whether interrupts are handled locally, program
++ * int2Cfg. Error checking for accidental loop(when intLocal=0 and int2Cfg=1
++ * i.e remote packets are set intPending register->which will result in
++ * same packet being sent out) has been done already
++ */
++
++ if (intSetting->intRemote == VLYNQ_INT_ROOT_ISR)
++ {
++ /* Set the int2Cfg register, so that remote interrupt
++ * packets are written to intPending register */
++ val |= 0x01 << VLYNQ_CTL_INT2CFG_SHIFT;
++
++ /* Set intPtr register to point to intPending register */
++ VLYNQ_INT_PTR_REG = VLYNQ_INT_PENDING_REG_PTR ;
++ }
++ else
++ {
++ /*set the interrupt pointer register*/
++ VLYNQ_INT_PTR_REG = intSetting->intr_ptr;
++ /* Dont bother to modify int2Cfg as it would be zero */
++ }
++
++ /** Clear bits related to INT settings in control register **/
++ VLYNQ_CTRL_REG = VLYNQ_CTRL_REG & (~VLYNQ_CTL_INTFIELDS_CLEAR_MASK);
++
++ /** Or the bits to be set with Control register **/
++ VLYNQ_CTRL_REG = VLYNQ_CTRL_REG | val;
++
++ /* initialise local ICB */
++ if(vlynqInterruptInit(pdev)==VLYNQ_MEMALLOC_FAIL)
++ return VLYNQ_MEMALLOC_FAIL;
++
++ /* Install handler for local module status interrupts. By default when
++ * local interrupt setting is initialised, the local module status are
++ * enabled and handler hooked up */
++ if(vlynq_install_isr(pdev, intSetting->map_vector, vlynq_local_module_isr,
++ pdev, NULL, NULL) == VLYNQ_INVALID_ARG)
++ return VLYNQ_INVALID_ARG;
++ } /* end of init local interrupts */
++
++ if(options & VLYNQ_INIT_REMOTE_INTERRUPTS )
++ {
++ /* Configure remote interrupt settings from configuration */
++ intSetting = &(pdev->remote_irq);
++
++ /* Map remote module status interrupts to remote interrupt vector*/
++ val = intSetting->map_vector << VLYNQ_CTL_INTVEC_SHIFT ;
++ /* enable remote module status interrupts */
++ val |= 0x01 << VLYNQ_CTL_INTEN_SHIFT;
++
++ if ( intSetting->intLocal == VLYNQ_INT_LOCAL )
++ {
++ /*set the intLocal bit*/
++ val |= 0x01 << VLYNQ_CTL_INTLOCAL_SHIFT;
++ }
++
++ /* Irrespective of whether interrupts are handled locally, program
++ * int2Cfg. Error checking for accidental loop(when intLocal=0 and int2Cfg=1
++ * i.e remote packets are set intPending register->which will result in
++ * same packet being sent out) has been done already
++ */
++
++ if (intSetting->intRemote == VLYNQ_INT_ROOT_ISR)
++ {
++ /* Set the int2Cfg register, so that remote interrupt
++ * packets are written to intPending register */
++ val |= 0x01 << VLYNQ_CTL_INT2CFG_SHIFT;
++ /* Set intPtr register to point to intPending register */
++ VLYNQ_R_INT_PTR_REG = VLYNQ_R_INT_PENDING_REG_PTR ;
++ }
++ else
++ {
++ /*set the interrupt pointer register*/
++ VLYNQ_R_INT_PTR_REG = intSetting->intr_ptr;
++ /* Dont bother to modify int2Cfg as it would be zero */
++ }
++
++ if( (intSetting->intLocal == VLYNQ_INT_REMOTE) &&
++ (options & VLYNQ_INIT_LOCAL_INTERRUPTS) &&
++ (pdev->local_irq.intRemote == VLYNQ_INT_ROOT_ISR) )
++ {
++ /* Install handler for remote module status interrupts. By default when
++ * remote interrupts are forwarded to local root_isr then remote_module_isr is
++ * enabled and handler hooked up */
++ if(vlynq_install_isr(pdev,intSetting->map_vector,vlynq_remote_module_isr,
++ pdev, NULL, NULL) == VLYNQ_INVALID_ARG)
++ return VLYNQ_INVALID_ARG;
++ }
++
++
++ /** Clear bits related to INT settings in control register **/
++ VLYNQ_R_CTRL_REG = VLYNQ_R_CTRL_REG & (~VLYNQ_CTL_INTFIELDS_CLEAR_MASK);
++
++ /** Or the bits to be set with the remote Control register **/
++ VLYNQ_R_CTRL_REG = VLYNQ_R_CTRL_REG | val;
++
++ } /* init remote interrupt settings*/
++
++ if(options & VLYNQ_INIT_CLEAR_ERRORS )
++ {
++ /* Clear errors during initialization */
++ tmp = VLYNQ_STATUS_REG & (VLYNQ_STS_RERROR_MASK | VLYNQ_STS_LERROR_MASK);
++ VLYNQ_STATUS_REG = tmp;
++ tmp = VLYNQ_R_STATUS_REG & (VLYNQ_STS_RERROR_MASK | VLYNQ_STS_LERROR_MASK);
++ VLYNQ_R_STATUS_REG = tmp;
++ }
++
++ /* clear int status */
++ val = VLYNQ_INT_STAT_REG;
++ VLYNQ_INT_STAT_REG = val;
++
++ /* finish initialization */
++ pdev->state = VLYNQ_DRV_STATE_RUN;
++ VLYNQ_RESETCB( VLYNQ_RESET_INITOK);
++ return VLYNQ_SUCCESS;
++
++}
++
++
++/* ----------------------------------------------------------------------------
++ * Function : vlynqInterruptInit()
++ * Description: This local function is used to set up the ICB table for the
++ * VLYNQ_STATUS_REG vlynq module. The input parameter "pdev" points the vlynq
++ * device instance whose ICB is allocated.
++ * Return : returns VLYNQ_SUCCESS or vlynq error for failure
++ * -----------------------------------------------------------------------------
++ */
++static int vlynqInterruptInit(VLYNQ_DEV *pdev)
++{
++ int i, numslots;
++
++ /* Memory allocated statically.
++ * Initialise ICB,free list.Indicate primary slot empty.
++ * Intialise intVector <==> map_vector translation table*/
++ for(i=0; i < VLYNQ_NUM_INT_BITS; i++)
++ {
++ pdev->pIntrCB[i].isr = NULL;
++ pdev->pIntrCB[i].next = NULL; /*nothing chained */
++ pdev->vector_map[i] = -1; /* indicates unmapped */
++ }
++
++ /* In the ICB slots, [VLYNQ_NUM_INT_BITS i.e 32 to ICB array size) are expansion slots
++ * required only when interrupt chaining/sharing is supported. In case
++ * of chained interrupts the list starts from primary slot and the
++ * additional slots are obtained from the common free area */
++
++ /* Initialise freelist */
++
++ numslots = VLYNQ_NUM_INT_BITS + VLYNQ_IVR_CHAIN_SLOTS;
++
++ if (numslots > VLYNQ_NUM_INT_BITS)
++ {
++ pdev->freelist = &(pdev->pIntrCB[VLYNQ_NUM_INT_BITS]);
++
++ for(i = VLYNQ_NUM_INT_BITS; i < (numslots-1) ; i++)
++ {
++ pdev->pIntrCB[i].next = &(pdev->pIntrCB[i+1]);
++ pdev->pIntrCB[i].isr = NULL;
++ }
++ pdev->pIntrCB[i].next=NULL; /* Indicate end of freelist*/
++ pdev->pIntrCB[i].isr=NULL;
++ }
++ else
++ {
++ pdev->freelist = NULL;
++ }
++
++ /** Reset mapping for IV 0-7 **/
++ VLYNQ_IVR_03TO00_REG = 0;
++ VLYNQ_IVR_07TO04_REG = 0;
++
++ return VLYNQ_SUCCESS;
++}
++
++/** remember that hooking up of root ISR handler with the interrupt controller
++ * is not done as a part of this driver. Typically, it must be done after
++ * invoking vlynq_init*/
++
++
++ /* ----------------------------------------------------------------------------
++ * ISR with the SOC interrupt controller. This ISR typically scans
++ * the Int PENDING/SET register in the VLYNQ module and calls the
++ * appropriate ISR associated with the correponding vector number.
++ * -----------------------------------------------------------------------------
++ */
++void vlynq_root_isr(void *arg)
++{
++ int source; /* Bit position of pending interrupt, start from 0 */
++ unsigned int interrupts, clrInterrupts;
++ VLYNQ_DEV * pdev;
++ VLYNQ_INTR_CNTRL_ICB *entry;
++
++ pdev=(VLYNQ_DEV*)(arg); /*obtain the vlynq device pointer*/
++
++ interrupts = VLYNQ_INT_STAT_REG; /* Get the list of pending interrupts */
++ VLYNQ_INT_STAT_REG = interrupts; /* clear the int CR register */
++ clrInterrupts = interrupts; /* save them for further analysis */
++
++ debugPrint("vlynq_root_isr: dev %u. INTCR = 0x%08lx\n", pdev->dev_idx, clrInterrupts,0,0,0,0);
++
++ /* Scan interrupt bits */
++ source =0;
++ while( clrInterrupts != 0)
++ {
++ /* test if bit is set? */
++ if( 0x1ul & clrInterrupts)
++ {
++ entry = &(pdev->pIntrCB[source]); /* Get the ISR entry */
++ pdev->intCount++; /* update interrupt count */
++ if(entry->isr != NULL)
++ {
++ do
++ {
++ pdev->isrCount++; /* update isr invocation count */
++ /* Call the user ISR and update the count for ISR */
++ entry->isrCount++;
++ entry->isr(entry->arg1, entry->arg2, entry->arg3);
++ if (entry->next == NULL) break;
++ entry = entry->next;
++
++ } while (entry->isr != NULL);
++ }
++ else
++ {
++ debugPrint(" ISR not installed for vlynq vector:%d\n",source,0,0,0,0,0);
++ }
++ }
++ clrInterrupts >>= 1; /* Next source bit */
++ ++source;
++ } /* endWhile clrInterrupts != 0 */
++}
++
++
++ /* ----------------------------------------------------------------------------
++ * Function : vlynq_local__module_isr()
++ * Description: This ISR is attached to the local VLYNQ interrupt vector
++ * by the Vlynq Driver when local interrupts are being handled. i.e.
++ * intLocal=1. This ISR handles local Vlynq module status interrupts only
++ * AS a part of this ISR, user callback in VLYNQ_DEV structure
++ * is invoked.
++ * VLYNQ_DEV is passed as arg1. arg2 and arg3 are unused.
++ * -----------------------------------------------------------------------------
++ */
++static void vlynq_local_module_isr(void *arg1,void *arg2, void *arg3)
++{
++ VLYNQ_REPORT_CB func;
++ unsigned int dwStatRegVal;
++ VLYNQ_DEV * pdev;
++
++ pdev = (VLYNQ_DEV*) arg1;
++ /* Callback function is read from the device pointer that is passed as an argument */
++ func = pdev->report_cb;
++
++ /* read local status register */
++ dwStatRegVal = VLYNQ_STATUS_REG;
++
++ /* clear pending events */
++ VLYNQ_STATUS_REG = dwStatRegVal;
++
++ /* invoke user callback */
++ if( func != NULL)
++ func( pdev, VLYNQ_LOCAL_DVC, dwStatRegVal);
++
++}
++
++ /* ----------------------------------------------------------------------------
++ * Function : vlynq_remote_module_isr()
++ * Description: This ISR is attached to the remote VLYNQ interrupt vector
++ * by the Vlynq Driver when remote interrupts are being handled locally. i.e.
++ * intLocal=1. This ISR handles local Vlynq module status interrupts only
++ * AS a part of this ISR, user callback in VLYNQ_DEV structure
++ * is invoked.
++ * The parameters irq,regs ar unused.
++ * -----------------------------------------------------------------------------
++ */
++static void vlynq_remote_module_isr(void *arg1,void *arg2, void *arg3)
++{
++ VLYNQ_REPORT_CB func;
++ unsigned int dwStatRegVal;
++ VLYNQ_DEV * pdev;
++
++
++ pdev = (VLYNQ_DEV*) arg1;
++
++ /* Callback function is read from the device pointer that is passed as an argument */
++ func = pdev->report_cb;
++
++ /* read local status register */
++ dwStatRegVal = VLYNQ_R_STATUS_REG;
++
++ /* clear pending events */
++ VLYNQ_R_STATUS_REG = dwStatRegVal;
++
++ /* invoke user callback */
++ if( func != NULL)
++ func( pdev, VLYNQ_REMOTE_DVC, dwStatRegVal);
++
++}
++
++/* ----------------------------------------------------------------------------
++ * Function : vlynq_interrupt_get_count()
++ * Description: This function returns the number of times a particular intr
++ * has been invoked.
++ *
++ * It returns 0, if erroneous map_vector is specified or if the corres isr
++ * has not been registered with VLYNQ.
++ */
++unsigned int vlynq_interrupt_get_count(VLYNQ_DEV *pdev,
++ unsigned int map_vector)
++{
++ VLYNQ_INTR_CNTRL_ICB *entry;
++ unsigned int count = 0;
++
++ if (map_vector > (VLYNQ_NUM_INT_BITS-1))
++ return count;
++
++ entry = &(pdev->pIntrCB[map_vector]);
++
++ if (entry)
++ count = entry->isrCount;
++
++ return (count);
++}
++
++
++/* ----------------------------------------------------------------------------
++ * Function : vlynq_install_isr()
++ * Description: This function installs ISR for Vlynq interrupt vector
++ * bits(in IntPending register). This function should be used only when
++ * Vlynq interrupts are being handled locally(remote may be programmed to send
++ * interrupt packets).Also, the int2cfg should be 1 and the least significant
++ * 8 bits of the Interrupt Pointer Register must point to Interrupt
++ * Pending/Set Register).
++ * If host int2cfg=0 and the Interrupt Pointer register contains
++ * the address of the interrupt set register in the interrupt controller
++ * module of the local device , then the ISR for the remote interrupt must be
++ * directly registered with the Interrupt controller and must not use this API
++ * Note: this function simply installs the ISR in ICB It doesnt modify
++ * any register settings
++ */
++int
++vlynq_install_isr(VLYNQ_DEV *pdev,
++ unsigned int map_vector,
++ VLYNQ_INTR_CNTRL_ISR isr,
++ void *arg1, void *arg2, void *arg3)
++{
++ VLYNQ_INTR_CNTRL_ICB *entry;
++
++ if ( (map_vector > (VLYNQ_NUM_INT_BITS-1)) || (isr == NULL) )
++ return VLYNQ_INVALID_ARG;
++
++ entry = &(pdev->pIntrCB[map_vector]);
++
++ if(entry->isr == NULL)
++ {
++ entry->isr = isr;
++ entry->arg1 = arg1;
++ entry->arg2 = arg2;
++ entry->arg3 = arg3;
++ entry->next = NULL;
++ }
++ else
++ {
++ /** No more empty slots,return error */
++ if(pdev->freelist == NULL)
++ return VLYNQ_MEMALLOC_FAIL;
++
++ while(entry->next != NULL)
++ {
++ entry = entry->next;
++ }
++
++ /* Append new node to the chain */
++ entry->next = pdev->freelist;
++ /* Remove the appended node from freelist */
++ pdev->freelist = pdev->freelist->next;
++ entry= entry->next;
++
++ /*** Set the ICB fields ***/
++ entry->isr = isr;
++ entry->arg1 = arg1;
++ entry->arg2 = arg2;
++ entry->arg3 = arg3;
++ entry->next = NULL;
++ }
++
++ return VLYNQ_SUCCESS;
++}
++
++
++
++/* ----------------------------------------------------------------------------
++ * Function : vlynq_uninstall_isr
++ * Description: This function is used to uninstall a previously
++ * registered ISR. In case of shared/chained interrupts, the
++ * void * arg parameter must uniquely identify the ISR to be
++ * uninstalled.
++ * Note: this function simply uninstalls the ISR in ICB
++ * It doesnt modify any register settings
++ */
++int
++vlynq_uninstall_isr(VLYNQ_DEV *pdev,
++ unsigned int map_vector,
++ void *arg1, void *arg2, void *arg3)
++{
++ VLYNQ_INTR_CNTRL_ICB *entry,*temp;
++
++ if (map_vector > (VLYNQ_NUM_INT_BITS-1))
++ return VLYNQ_INVALID_ARG;
++
++ entry = &(pdev->pIntrCB[map_vector]);
++
++ if(entry->isr == NULL )
++ return VLYNQ_ISR_NON_EXISTENT;
++
++ if ( (entry->arg1 == arg1) && (entry->arg2 == arg2) && (entry->arg3 == arg3) )
++ {
++ if(entry->next == NULL)
++ {
++ entry->isr=NULL;
++ return VLYNQ_SUCCESS;
++ }
++ else
++ {
++ temp = entry->next;
++ /* Copy next node in the chain to prim.slot */
++ entry->isr = temp->isr;
++ entry->arg1 = temp->arg1;
++ entry->arg2 = temp->arg2;
++ entry->arg3 = temp->arg3;
++ entry->next = temp->next;
++ /* Free the just copied node */
++ temp->isr = NULL;
++ temp->arg1 = NULL;
++ temp->arg2 = NULL;
++ temp->arg3 = NULL;
++ temp->next = pdev->freelist;
++ pdev->freelist = temp;
++ return VLYNQ_SUCCESS;
++ }
++ }
++ else
++ {
++ temp = entry;
++ while ( (entry = temp->next) != NULL)
++ {
++ if ( (entry->arg1 == arg1) && (entry->arg2 == arg2) && (entry->arg3 == arg3) )
++ {
++ /* remove node from chain */
++ temp->next = entry->next;
++ /* Add the removed node to freelist */
++ entry->isr = NULL;
++ entry->arg1 = NULL;
++ entry->arg2 = NULL;
++ entry->arg3 = NULL;
++ entry->next = pdev->freelist;
++ entry->isrCount = 0;
++ pdev->freelist = entry;
++ return VLYNQ_SUCCESS;
++ }
++ temp = entry;
++ }
++
++ return VLYNQ_ISR_NON_EXISTENT;
++ }
++}
++
++
++
++
++/* ----------------------------------------------------------------------------
++ * function : vlynq_interrupt_vector_set()
++ * description:configures interrupt vector mapping,interrupt type
++ * polarity -all in one go.
++ */
++int
++vlynq_interrupt_vector_set(VLYNQ_DEV *pdev, /* vlynq device */
++ unsigned int int_vector, /* int vector on vlynq device */
++ unsigned int map_vector, /* bit for this interrupt */
++ VLYNQ_DEV_TYPE dev_type, /* local or remote device */
++ VLYNQ_INTR_POLARITY pol, /* polarity of interrupt */
++ VLYNQ_INTR_TYPE type) /* pulsed/level interrupt */
++{
++ volatile unsigned int * vecreg;
++ unsigned int val=0;
++ unsigned int bytemask=0XFF;
++
++ /* use the lower 8 bits of val to set the value , shift it to
++ * appropriate byte position in the ivr and write it to the
++ * corresponding register */
++
++ /* validate the number of interrupts supported */
++ if (int_vector >= VLYNQ_IVR_MAXIVR)
++ return VLYNQ_INVALID_ARG;
++
++ if(map_vector > (VLYNQ_NUM_INT_BITS - 1) )
++ return VLYNQ_INVALID_ARG;
++
++ if (dev_type == VLYNQ_LOCAL_DVC)
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
++ }
++ else
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
++ }
++
++ /* Update the intVector<==> bit position translation table */
++ pdev->vector_map[map_vector] = int_vector;
++
++ /* val has been initialised to zero. we only have to turn on appropriate bits*/
++ if(type == VLYNQ_INTR_PULSED)
++ val |= VLYNQ_IVR_INTTYPE_MASK;
++
++ if(pol == VLYNQ_INTR_ACTIVE_LOW)
++ val |= VLYNQ_IVR_INTPOL_MASK;
++
++ val |= map_vector;
++
++ /** clear the correct byte position and then or val **/
++ *vecreg = (*vecreg) & ( ~(bytemask << ( (int_vector %4)*8) ) );
++
++ /** write to correct byte position in vecreg*/
++ *vecreg = (*vecreg) | (val << ( (int_vector % 4)*8) ) ;
++
++ /* Setting a interrupt vector, leaves the interrupt disabled
++ * which must be enabled subsequently */
++
++ return VLYNQ_SUCCESS;
++}
++
++
++/* ----------------------------------------------------------------------------
++ * Function : vlynq_interrupt_vector_cntl()
++ * Description:enables/disable interrupt
++ */
++int vlynq_interrupt_vector_cntl( VLYNQ_DEV *pdev,
++ unsigned int int_vector,
++ VLYNQ_DEV_TYPE dev_type,
++ unsigned int enable)
++{
++ volatile unsigned int *vecReg;
++ unsigned int val=0;
++ unsigned int intenMask=0x80;
++
++ /* validate the number of interrupts supported */
++ if (int_vector >= VLYNQ_IVR_MAXIVR)
++ return VLYNQ_INVALID_ARG;
++
++ if (dev_type == VLYNQ_LOCAL_DVC)
++ {
++ vecReg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
++ }
++ else
++ {
++ vecReg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
++ }
++
++ /** Clear the correct byte position and then or val **/
++ *vecReg = (*vecReg) & ( ~(intenMask << ( (int_vector %4)*8) ) );
++
++ if(enable)
++ {
++ val |= VLYNQ_IVR_INTEN_MASK;
++ /** Write to correct byte position in vecReg*/
++ *vecReg = (*vecReg) | (val << ( (int_vector % 4)*8) ) ;
++ }
++
++ return VLYNQ_SUCCESS;
++
++}/* end of function vlynq_interrupt_vector_cntl */
++
++
++
++/* ----------------------------------------------------------------------------
++ * Function : vlynq_interrupt_vector_map()
++ * Description:Configures interrupt vector mapping alone
++ */
++int
++vlynq_interrupt_vector_map( VLYNQ_DEV *pdev,
++ VLYNQ_DEV_TYPE dev_type,
++ unsigned int int_vector,
++ unsigned int map_vector)
++{
++ volatile unsigned int * vecreg;
++ unsigned int val=0;
++ unsigned int bytemask=0x1f; /* mask to turn off bits corresponding to int vector */
++
++ /* use the lower 8 bits of val to set the value , shift it to
++ * appropriate byte position in the ivr and write it to the
++ * corresponding register */
++
++ /* validate the number of interrupts supported */
++ if (int_vector >= VLYNQ_IVR_MAXIVR)
++ return VLYNQ_INVALID_ARG;
++
++ if(map_vector > (VLYNQ_NUM_INT_BITS - 1) )
++ return VLYNQ_INVALID_ARG;
++
++ if (dev_type == VLYNQ_LOCAL_DVC)
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
++ }
++ else
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
++ }
++
++ /* Update the intVector<==> bit position translation table */
++ pdev->vector_map[map_vector] = int_vector;
++
++ /** val has been initialised to zero. we only have to turn on
++ * appropriate bits*/
++ val |= map_vector;
++
++ /** clear the correct byte position and then or val **/
++ *vecreg = (*vecreg) & ( ~(bytemask << ( (int_vector %4)*8) ) );
++
++ /** write to correct byte position in vecreg*/
++ *vecreg = (*vecreg) | (val << ( (int_vector % 4)*8) ) ;
++
++ return VLYNQ_SUCCESS;
++}
++
++
++/* ----------------------------------------------------------------------------
++ * function : vlynq_interrupt_set_polarity()
++ * description:configures interrupt polarity .
++ */
++int
++vlynq_interrupt_set_polarity( VLYNQ_DEV *pdev ,
++ VLYNQ_DEV_TYPE dev_type,
++ unsigned int map_vector,
++ VLYNQ_INTR_POLARITY pol)
++{
++ volatile unsigned int * vecreg;
++ int int_vector;
++ unsigned int val=0;
++ unsigned int bytemask=0x20; /** mask to turn off bits corresponding to int polarity */
++
++ /* get the int_vector from map_vector */
++ int_vector = pdev->vector_map[map_vector];
++
++ if(int_vector == -1)
++ return VLYNQ_INTVEC_MAP_NOT_FOUND;
++
++ /* use the lower 8 bits of val to set the value , shift it to
++ * appropriate byte position in the ivr and write it to the
++ * corresponding register */
++
++ if (dev_type == VLYNQ_LOCAL_DVC)
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
++ }
++ else
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
++ }
++
++ /* val has been initialised to zero. we only have to turn on
++ * appropriate bits, if need be*/
++
++ /** clear the correct byte position and then or val **/
++ *vecreg = (*vecreg) & ( ~(bytemask << ( (int_vector %4)*8) ) );
++
++ if( pol == VLYNQ_INTR_ACTIVE_LOW)
++ {
++ val |= VLYNQ_IVR_INTPOL_MASK;
++ /** write to correct byte position in vecreg*/
++ *vecreg = (*vecreg) | (val << ( (int_vector % 4)*8) ) ;
++ }
++
++ return VLYNQ_SUCCESS;
++}
++
++int vlynq_interrupt_get_polarity( VLYNQ_DEV *pdev ,
++ VLYNQ_DEV_TYPE dev_type,
++ unsigned int map_vector)
++{
++ volatile unsigned int * vecreg;
++ int int_vector;
++ unsigned int val=0;
++
++ /* get the int_vector from map_vector */
++ int_vector = pdev->vector_map[map_vector];
++
++ if (map_vector > (VLYNQ_NUM_INT_BITS-1))
++ return(-1);
++
++ if(int_vector == -1)
++ return VLYNQ_INTVEC_MAP_NOT_FOUND;
++
++ /* use the lower 8 bits of val to set the value , shift it to
++ * appropriate byte position in the ivr and write it to the
++ * corresponding register */
++
++ if (dev_type == VLYNQ_LOCAL_DVC)
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
++ }
++ else
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
++ }
++
++ /** read the information into val **/
++ val = (*vecreg) & ((VLYNQ_IVR_INTPOL_MASK << ( (int_vector %4)*8) ) );
++
++ return (val ? (VLYNQ_INTR_ACTIVE_LOW) : (VLYNQ_INTR_ACTIVE_HIGH));
++}
++
++
++/* ----------------------------------------------------------------------------
++ * function : vlynq_interrupt_set_type()
++ * description:configures interrupt type .
++ */
++int vlynq_interrupt_set_type( VLYNQ_DEV *pdev,
++ VLYNQ_DEV_TYPE dev_type,
++ unsigned int map_vector,
++ VLYNQ_INTR_TYPE type)
++{
++ volatile unsigned int * vecreg;
++ unsigned int val=0;
++ int int_vector;
++
++ /** mask to turn off bits corresponding to interrupt type */
++ unsigned int bytemask=0x40;
++
++ /* get the int_vector from map_vector */
++ int_vector = pdev->vector_map[map_vector];
++ if(int_vector == -1)
++ return VLYNQ_INTVEC_MAP_NOT_FOUND;
++
++ /* use the lower 8 bits of val to set the value , shift it to
++ * appropriate byte position in the ivr and write it to the
++ * corresponding register */
++ if (dev_type == VLYNQ_LOCAL_DVC)
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
++ }
++ else
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
++ }
++
++ /** val has been initialised to zero. we only have to turn on
++ * appropriate bits if need be*/
++
++ /** clear the correct byte position and then or val **/
++ *vecreg = (*vecreg) & ( ~(bytemask << ( (int_vector %4)*8) ) );
++
++ if( type == VLYNQ_INTR_PULSED)
++ {
++ val |= VLYNQ_IVR_INTTYPE_MASK;
++ /** write to correct byte position in vecreg*/
++ *vecreg = (*vecreg) | (val << ( (int_vector % 4)*8) ) ;
++ }
++
++ return VLYNQ_SUCCESS;
++}
++
++/* ----------------------------------------------------------------------------
++ * function : vlynq_interrupt_get_type()
++ * description:returns interrupt type .
++ */
++int vlynq_interrupt_get_type( VLYNQ_DEV *pdev, VLYNQ_DEV_TYPE dev_type,
++ unsigned int map_vector)
++{
++ volatile unsigned int * vecreg;
++ unsigned int val=0;
++ int int_vector;
++
++ if (map_vector > (VLYNQ_NUM_INT_BITS-1))
++ return(-1);
++
++ /* get the int_vector from map_vector */
++ int_vector = pdev->vector_map[map_vector];
++ if(int_vector == -1)
++ return VLYNQ_INTVEC_MAP_NOT_FOUND;
++
++ /* use the lower 8 bits of val to set the value , shift it to
++ * appropriate byte position in the ivr and write it to the
++ * corresponding register */
++ if (dev_type == VLYNQ_LOCAL_DVC)
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
++ }
++ else
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
++ }
++
++ /** Read the correct bit position into val **/
++ val = (*vecreg) & ((VLYNQ_IVR_INTTYPE_MASK << ( (int_vector %4)*8) ) );
++
++ return (val ? (VLYNQ_INTR_PULSED) : (VLYNQ_INTR_LEVEL));
++}
++
++/* ----------------------------------------------------------------------------
++ * function : vlynq_interrupt_enable()
++ * description:Enable interrupt by writing to IVR register.
++ */
++int vlynq_interrupt_enable( VLYNQ_DEV *pdev,
++ VLYNQ_DEV_TYPE dev_type,
++ unsigned int map_vector)
++{
++ volatile unsigned int * vecreg;
++ unsigned int val=0;
++ int int_vector;
++
++ /** mask to turn off bits corresponding to interrupt enable */
++ unsigned int bytemask=0x80;
++
++ /* get the int_vector from map_vector */
++ int_vector = pdev->vector_map[map_vector];
++ if(int_vector == -1)
++ return VLYNQ_INTVEC_MAP_NOT_FOUND;
++
++ /* use the lower 8 bits of val to set the value , shift it to
++ * appropriate byte position in the ivr and write it to the
++ * corresponding register */
++
++ if (dev_type == VLYNQ_LOCAL_DVC)
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
++ }
++ else
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
++ }
++
++ /** val has been initialised to zero. we only have to turn on
++ * bit corresponding to interrupt enable*/
++ val |= VLYNQ_IVR_INTEN_MASK;
++
++ /** clear the correct byte position and then or val **/
++ *vecreg = (*vecreg) & ( ~(bytemask << ( (int_vector %4)*8) ) );
++
++ /** write to correct byte position in vecreg*/
++ *vecreg = (*vecreg) | (val << ( (int_vector % 4)*8) ) ;
++
++ return VLYNQ_SUCCESS;
++}
++
++
++/* ----------------------------------------------------------------------------
++ * function : vlynq_interrupt_disable()
++ * description:Disable interrupt by writing to IVR register.
++ */
++int
++vlynq_interrupt_disable( VLYNQ_DEV *pdev,
++ VLYNQ_DEV_TYPE dev_type,
++ unsigned int map_vector)
++{
++ volatile unsigned int * vecreg;
++ int int_vector;
++
++ /** mask to turn off bits corresponding to interrupt enable */
++ unsigned int bytemask=0x80;
++
++ /* get the int_vector from map_vector */
++ int_vector = pdev->vector_map[map_vector];
++ if(int_vector == -1)
++ return VLYNQ_INTVEC_MAP_NOT_FOUND;
++
++ /* use the lower 8 bits of val to set the value , shift it to
++ * appropriate byte position in the ivr and write it to the
++ * corresponding register */
++ if (dev_type == VLYNQ_LOCAL_DVC)
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_IVR_OFFSET(int_vector));
++ }
++ else
++ {
++ vecreg = (volatile unsigned int *) (VLYNQ_R_IVR_OFFSET(int_vector));
++ }
++
++ /* We disable the interrupt by simply turning off the bit
++ * corresponding to Interrupt enable.
++ * Clear the interrupt enable bit in the correct byte position **/
++ *vecreg = (*vecreg) & ( ~(bytemask << ( (int_vector %4)*8) ) );
++
++ /* Dont have to set any bit positions */
++
++ return VLYNQ_SUCCESS;
++
++}
++
++
++
++
+diff -urN linux.old/drivers/char/serial.c linux.dev/drivers/char/serial.c
+--- linux.old/drivers/char/serial.c 2005-10-21 16:43:20.709226000 +0200
++++ linux.dev/drivers/char/serial.c 2005-11-10 01:10:46.015585250 +0100
+@@ -419,7 +419,40 @@
+ return 0;
+ }
+
+-#if defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_SEAD)
++#if defined(CONFIG_AR7)
++
++static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
++{
++ return (inb(info->port + (offset * 4)) & 0xff);
++}
++
++
++static _INLINE_ unsigned int serial_inp(struct async_struct *info, int offset)
++{
++#ifdef CONFIG_SERIAL_NOPAUSE_IO
++ return (inb(info->port + (offset * 4)) & 0xff);
++#else
++ return (inb_p(info->port + (offset * 4)) & 0xff);
++#endif
++}
++
++static _INLINE_ void serial_out(struct async_struct *info, int offset, int value)
++{
++ outb(value, info->port + (offset * 4));
++}
++
++
++static _INLINE_ void serial_outp(struct async_struct *info, int offset,
++ int value)
++{
++#ifdef CONFIG_SERIAL_NOPAUSE_IO
++ outb(value, info->port + (offset * 4));
++#else
++ outb_p(value, info->port + (offset * 4));
++#endif
++}
++
++#elif defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_SEAD)
+
+ #include <asm/mips-boards/atlas.h>
+
+@@ -478,8 +511,10 @@
+ * needed for certain old 386 machines, I've left these #define's
+ * in....
+ */
++#ifndef CONFIG_AR7
+ #define serial_inp(info, offset) serial_in(info, offset)
+ #define serial_outp(info, offset, value) serial_out(info, offset, value)
++#endif
+
+
+ /*
+@@ -1728,7 +1763,15 @@
+ /* Special case since 134 is really 134.5 */
+ quot = (2*baud_base / 269);
+ else if (baud)
++#ifdef CONFIG_AR7
++ quot = (CONFIG_AR7_SYS*500000) / baud;
++
++ if ((quot%16)>7)
++ quot += 8;
++ quot /=16;
++#else
+ quot = baud_base / baud;
++#endif
+ }
+ /* If the quotient is zero refuse the change */
+ if (!quot && old_termios) {
+@@ -5540,8 +5583,10 @@
+ state->irq = irq_cannonicalize(state->irq);
+ if (state->hub6)
+ state->io_type = SERIAL_IO_HUB6;
++#ifndef CONFIG_AR7
+ if (state->port && check_region(state->port,8))
+ continue;
++#endif
+ #ifdef CONFIG_MCA
+ if ((state->flags & ASYNC_BOOT_ONLYMCA) && !MCA_bus)
+ continue;
+@@ -5997,7 +6042,15 @@
+ info->io_type = state->io_type;
+ info->iomem_base = state->iomem_base;
+ info->iomem_reg_shift = state->iomem_reg_shift;
++#ifdef CONFIG_AR7
++ quot = (CONFIG_AR7_SYS*500000) / baud;
++
++ if ((quot%16)>7)
++ quot += 8;
++ quot /=16;
++#else
+ quot = state->baud_base / baud;
++#endif
+ cval = cflag & (CSIZE | CSTOPB);
+ #if defined(__powerpc__) || defined(__alpha__)
+ cval >>= 8;
+diff -urN linux.old/drivers/char/ticfg/Makefile linux.dev/drivers/char/ticfg/Makefile
+--- linux.old/drivers/char/ticfg/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/char/ticfg/Makefile 2005-11-10 01:10:46.051587500 +0100
+@@ -0,0 +1,6 @@
++
++O_TARGET := ticfg.o
++
++obj-$(CONFIG_AR7_ADAM2) := adam2_env.o
++
++include $(TOPDIR)/Rules.make
+diff -urN linux.old/drivers/char/ticfg/adam2_env.c linux.dev/drivers/char/ticfg/adam2_env.c
+--- linux.old/drivers/char/ticfg/adam2_env.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/char/ticfg/adam2_env.c 2005-11-10 01:10:46.051587500 +0100
+@@ -0,0 +1,85 @@
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/proc_fs.h>
++#include <linux/fcntl.h>
++#include <linux/init.h>
++
++#include <asm/ar7/adam2_env.h>
++
++#undef ADAM2_ENV_DEBUG
++
++#ifdef ADAM2_ENV_DEBUG
++#define DPRINTK(args...) do { printk(args); } while(0);
++#else
++#define DPRINTK(args...) do { } while(0);
++#endif
++
++#define ADAM2_ENV_DIR "ticfg"
++#define ADAM2_ENV_NAME "env"
++
++static struct proc_dir_entry *adam2_env_proc_dir;
++static struct proc_dir_entry *adam2_env_proc_ent;
++
++static int
++adam2_proc_read_env(char *page, char **start, off_t pos, int count,
++ int *eof, void *data)
++{
++ int len;
++ t_env_var *env;
++
++ if (pos > 0)
++ return 0;
++
++ len=0;
++ for (env = prom_iterenv(0); env; env = prom_iterenv(env)) {
++ if (env->val) {
++ /* XXX check for page len */
++ len += sprintf(page + len, "%s\t%s\n",
++ env->name, env->val);
++ }
++ }
++
++ *eof=1;
++ return len;
++}
++
++static int __init
++adam2_env_init(void)
++{
++
++ DPRINTK("%s\n", __FUNCTION__);
++
++ adam2_env_proc_dir = proc_mkdir(ADAM2_ENV_DIR, NULL);
++ if (!adam2_env_proc_dir) {
++ printk(KERN_ERR "%s: Unable to create /proc/%s entry\n",
++ __FUNCTION__, ADAM2_ENV_DIR);
++ return -ENOMEM;
++ }
++
++ adam2_env_proc_ent =
++ create_proc_entry(ADAM2_ENV_NAME, 0444, adam2_env_proc_dir);
++ if (!adam2_env_proc_ent) {
++ printk(KERN_ERR "%s: Unable to create /proc/%s/%s entry\n",
++ __FUNCTION__, ADAM2_ENV_DIR, ADAM2_ENV_NAME);
++ remove_proc_entry(ADAM2_ENV_DIR, NULL);
++ return -ENOMEM;
++ }
++ adam2_env_proc_ent->read_proc = adam2_proc_read_env;
++
++ return 0;
++}
++
++static
++void __exit
++adam2_env_cleanup(void)
++{
++ remove_proc_entry(ADAM2_ENV_NAME, adam2_env_proc_dir);
++ remove_proc_entry(ADAM2_ENV_DIR, NULL);
++}
++
++module_init(adam2_env_init);
++module_exit(adam2_env_cleanup);
++
++MODULE_LICENSE("GPL");
+diff -urN linux.old/include/asm-mips/addrspace.h linux.dev/include/asm-mips/addrspace.h
+--- linux.old/include/asm-mips/addrspace.h 2002-11-29 00:53:15.000000000 +0100
++++ linux.dev/include/asm-mips/addrspace.h 2005-11-10 01:14:16.400733500 +0100
+@@ -11,6 +11,8 @@
+ #ifndef __ASM_MIPS_ADDRSPACE_H
+ #define __ASM_MIPS_ADDRSPACE_H
+
++#include <linux/config.h>
++
+ /*
+ * Configure language
+ */
+@@ -102,4 +104,11 @@
+ #define XKPHYS_TO_PHYS(p) ((p) & TO_PHYS_MASK)
+ #define PHYS_TO_XKPHYS(cm,a) (0x8000000000000000 | ((cm)<<59) | (a))
+
++#ifdef CONFIG_AR7_MEMORY
++#define PHYS_OFFSET ((unsigned long)(CONFIG_AR7_MEMORY))
++#else
++#define PHYS_OFFSET (0)
++#endif
++#define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT)
++
+ #endif /* __ASM_MIPS_ADDRSPACE_H */
+diff -urN linux.old/include/asm-mips/ar7/adam2_env.h linux.dev/include/asm-mips/ar7/adam2_env.h
+--- linux.old/include/asm-mips/ar7/adam2_env.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/adam2_env.h 2005-11-10 01:10:46.067588500 +0100
+@@ -0,0 +1,13 @@
++#ifndef _INCLUDE_ASM_AR7_ADAM2_ENV_H_
++#define _INCLUDE_ASM_AR7_ADAM2_ENV_H_
++
++/* Environment variable */
++typedef struct {
++ char *name;
++ char *val;
++} t_env_var;
++
++char *prom_getenv(char *);
++t_env_var *prom_iterenv(t_env_var *);
++
++#endif /* _INCLUDE_ASM_AR7_ADAM2_ENV_H_ */
+diff -urN linux.old/include/asm-mips/ar7/ar7.h linux.dev/include/asm-mips/ar7/ar7.h
+--- linux.old/include/asm-mips/ar7/ar7.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/ar7.h 2005-11-10 01:10:46.067588500 +0100
+@@ -0,0 +1,33 @@
++/*
++ * $Id$
++ * Copyright (C) $Date$ $Author$
++ *
++ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ */
++
++#ifndef _AR7_H
++#define _AR7_H
++
++#include <asm/addrspace.h>
++#include <linux/config.h>
++
++#define AVALANCHE_VECS_KSEG0 (KSEG0ADDR(CONFIG_AR7_MEMORY))
++
++#define AR7_UART0_REGS_BASE (KSEG1ADDR(0x08610E00))
++#define AR7_UART1_REGS_BASE (KSEG1ADDR(0x08610F00))
++#define AR7_BASE_BAUD ( 3686400 / 16 )
++
++#endif
+diff -urN linux.old/include/asm-mips/ar7/avalanche_intc.h linux.dev/include/asm-mips/ar7/avalanche_intc.h
+--- linux.old/include/asm-mips/ar7/avalanche_intc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/avalanche_intc.h 2005-11-10 01:10:46.067588500 +0100
+@@ -0,0 +1,292 @@
++ /*
++ * Nitin Dhingra, iamnd@ti.com
++ * Copyright (C) 2000 Texas Instruments Inc.
++ *
++ *
++ * ########################################################################
++ *
++ * This program is free software; you can distribute it and/or modify it
++ * under the terms of the GNU General Public License (Version 2) as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope 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.
++ *
++ * ########################################################################
++ *
++ * Defines of the Sead board specific address-MAP, registers, etc.
++ *
++ */
++#ifndef _AVALANCHE_INTC_H
++#define _AVALANCHE_INTC_H
++
++#include <linux/config.h>
++
++/* ----- */
++
++#define KSEG1_BASE 0xA0000000
++#define KSEG_INV_MASK 0x1FFFFFFF /* Inverted mask for kseg address */
++#define PHYS_ADDR(addr) ((addr) & KSEG_INV_MASK)
++#define PHYS_TO_K1(addr) (PHYS_ADDR(addr)|KSEG1_BASE)
++#define AVALANCHE_INTC_BASE PHYS_TO_K1(0x08612400)
++
++/* ----- */
++
++#define MIPS_EXCEPTION_OFFSET 8
++
++/******************************************************************************
++ Avalanche Interrupt number
++******************************************************************************/
++#define AVINTNUM(x) ((x) - MIPS_EXCEPTION_OFFSET)
++
++/*******************************************************************************
++*Linux Interrupt number
++*******************************************************************************/
++#define LNXINTNUM(x)((x) + MIPS_EXCEPTION_OFFSET)
++
++
++
++#define AVALANCHE_INT_END_PRIMARY (40 + MIPS_EXCEPTION_OFFSET)
++#define AVALANCHE_INT_END_SECONDARY (32 + MIPS_EXCEPTION_OFFSET)
++
++#define AVALANCHE_INT_END_PRIMARY_REG1 (31 + MIPS_EXCEPTION_OFFSET)
++#define AVALANCHE_INT_END_PRIMARY_REG2 (39 + MIPS_EXCEPTION_OFFSET)
++
++#define AVALANCHE_INTC_END (AVINTNUM(AVALANCHE_INT_END_PRIMARY) + \
++ AVINTNUM(AVALANCHE_INT_END_SECONDARY) + \
++ MIPS_EXCEPTION_OFFSET)
++
++#if defined(CONFIG_AR7_VLYNQ)
++#define AVALANCHE_INT_END_LOW_VLYNQ (AVALANCHE_INTC_END + 32)
++#define AVALANCHE_INT_END_VLYNQ (AVALANCHE_INTC_END + 32 * CONFIG_AR7_VLYNQ_PORTS)
++#define AVALANCHE_INT_END AVALANCHE_INT_END_VLYNQ
++#else
++#define AVALANCHE_INT_END AVALANCHE_INTC_END
++#endif
++
++
++/*
++ * Avalanche interrupt controller register base (primary)
++ */
++#define AVALANCHE_ICTRL_REGS_BASE AVALANCHE_INTC_BASE
++
++/******************************************************************************
++ * Avalanche exception controller register base (secondary)
++ ******************************************************************************/
++#define AVALANCHE_ECTRL_REGS_BASE (AVALANCHE_ICTRL_REGS_BASE + 0x80)
++
++
++/******************************************************************************
++ * Avalanche Interrupt pacing register base (secondary)
++ ******************************************************************************/
++#define AVALANCHE_IPACE_REGS_BASE (AVALANCHE_ICTRL_REGS_BASE + 0xA0)
++
++
++
++/******************************************************************************
++ * Avalanche Interrupt Channel Control register base
++ *****************************************************************************/
++#define AVALANCHE_CHCTRL_REGS_BASE (AVALANCHE_ICTRL_REGS_BASE + 0x200)
++
++
++struct avalanche_ictrl_regs /* Avalanche Interrupt control registers */
++{
++ volatile unsigned long intsr1; /* Interrupt Status/Set Register 1 0x00 */
++ volatile unsigned long intsr2; /* Interrupt Status/Set Register 2 0x04 */
++ volatile unsigned long unused1; /*0x08 */
++ volatile unsigned long unused2; /*0x0C */
++ volatile unsigned long intcr1; /* Interrupt Clear Register 1 0x10 */
++ volatile unsigned long intcr2; /* Interrupt Clear Register 2 0x14 */
++ volatile unsigned long unused3; /*0x18 */
++ volatile unsigned long unused4; /*0x1C */
++ volatile unsigned long intesr1; /* Interrupt Enable (Set) Register 1 0x20 */
++ volatile unsigned long intesr2; /* Interrupt Enable (Set) Register 2 0x24 */
++ volatile unsigned long unused5; /*0x28 */
++ volatile unsigned long unused6; /*0x2C */
++ volatile unsigned long intecr1; /* Interrupt Enable Clear Register 1 0x30 */
++ volatile unsigned long intecr2; /* Interrupt Enable Clear Register 2 0x34 */
++ volatile unsigned long unused7; /* 0x38 */
++ volatile unsigned long unused8; /* 0x3c */
++ volatile unsigned long pintir; /* Priority Interrupt Index Register 0x40 */
++ volatile unsigned long intmsr; /* Priority Interrupt Mask Index Reg 0x44 */
++ volatile unsigned long unused9; /* 0x48 */
++ volatile unsigned long unused10; /* 0x4C */
++ volatile unsigned long intpolr1; /* Interrupt Polarity Mask register 10x50 */
++ volatile unsigned long intpolr2; /* Interrupt Polarity Mask register 20x54 */
++ volatile unsigned long unused11; /* 0x58 */
++ volatile unsigned long unused12; /*0x5C */
++ volatile unsigned long inttypr1; /* Interrupt Type Mask register 10x60 */
++ volatile unsigned long inttypr2; /* Interrupt Type Mask register 20x64 */
++};
++
++struct avalanche_exctrl_regs /* Avalanche Exception control registers */
++{
++ volatile unsigned long exsr; /* Exceptions Status/Set register 0x80 */
++ volatile unsigned long reserved; /*0x84 */
++ volatile unsigned long excr; /* Exceptions Clear Register 0x88 */
++ volatile unsigned long reserved1; /*0x8c */
++ volatile unsigned long exiesr; /* Exceptions Interrupt Enable (set) 0x90 */
++ volatile unsigned long reserved2; /*0x94 */
++ volatile unsigned long exiecr; /* Exceptions Interrupt Enable(clear)0x98 */
++};
++struct avalanche_ipace_regs
++{
++
++ volatile unsigned long ipacep; /* Interrupt pacing register 0xa0 */
++ volatile unsigned long ipacemap; /*Interrupt Pacing Map Register 0xa4 */
++ volatile unsigned long ipacemax; /*Interrupt Pacing Max Register 0xa8 */
++};
++struct avalanche_channel_int_number
++{
++ volatile unsigned long cintnr0; /* Channel Interrupt Number Register0x200 */
++ volatile unsigned long cintnr1; /* Channel Interrupt Number Register0x204 */
++ volatile unsigned long cintnr2; /* Channel Interrupt Number Register0x208 */
++ volatile unsigned long cintnr3; /* Channel Interrupt Number Register0x20C */
++ volatile unsigned long cintnr4; /* Channel Interrupt Number Register0x210 */
++ volatile unsigned long cintnr5; /* Channel Interrupt Number Register0x214 */
++ volatile unsigned long cintnr6; /* Channel Interrupt Number Register0x218 */
++ volatile unsigned long cintnr7; /* Channel Interrupt Number Register0x21C */
++ volatile unsigned long cintnr8; /* Channel Interrupt Number Register0x220 */
++ volatile unsigned long cintnr9; /* Channel Interrupt Number Register0x224 */
++ volatile unsigned long cintnr10; /* Channel Interrupt Number Register0x228 */
++ volatile unsigned long cintnr11; /* Channel Interrupt Number Register0x22C */
++ volatile unsigned long cintnr12; /* Channel Interrupt Number Register0x230 */
++ volatile unsigned long cintnr13; /* Channel Interrupt Number Register0x234 */
++ volatile unsigned long cintnr14; /* Channel Interrupt Number Register0x238 */
++ volatile unsigned long cintnr15; /* Channel Interrupt Number Register0x23C */
++ volatile unsigned long cintnr16; /* Channel Interrupt Number Register0x240 */
++ volatile unsigned long cintnr17; /* Channel Interrupt Number Register0x244 */
++ volatile unsigned long cintnr18; /* Channel Interrupt Number Register0x248 */
++ volatile unsigned long cintnr19; /* Channel Interrupt Number Register0x24C */
++ volatile unsigned long cintnr20; /* Channel Interrupt Number Register0x250 */
++ volatile unsigned long cintnr21; /* Channel Interrupt Number Register0x254 */
++ volatile unsigned long cintnr22; /* Channel Interrupt Number Register0x358 */
++ volatile unsigned long cintnr23; /* Channel Interrupt Number Register0x35C */
++ volatile unsigned long cintnr24; /* Channel Interrupt Number Register0x260 */
++ volatile unsigned long cintnr25; /* Channel Interrupt Number Register0x264 */
++ volatile unsigned long cintnr26; /* Channel Interrupt Number Register0x268 */
++ volatile unsigned long cintnr27; /* Channel Interrupt Number Register0x26C */
++ volatile unsigned long cintnr28; /* Channel Interrupt Number Register0x270 */
++ volatile unsigned long cintnr29; /* Channel Interrupt Number Register0x274 */
++ volatile unsigned long cintnr30; /* Channel Interrupt Number Register0x278 */
++ volatile unsigned long cintnr31; /* Channel Interrupt Number Register0x27C */
++ volatile unsigned long cintnr32; /* Channel Interrupt Number Register0x280 */
++ volatile unsigned long cintnr33; /* Channel Interrupt Number Register0x284 */
++ volatile unsigned long cintnr34; /* Channel Interrupt Number Register0x288 */
++ volatile unsigned long cintnr35; /* Channel Interrupt Number Register0x28C */
++ volatile unsigned long cintnr36; /* Channel Interrupt Number Register0x290 */
++ volatile unsigned long cintnr37; /* Channel Interrupt Number Register0x294 */
++ volatile unsigned long cintnr38; /* Channel Interrupt Number Register0x298 */
++ volatile unsigned long cintnr39; /* Channel Interrupt Number Register0x29C */
++};
++
++struct avalanche_interrupt_line_to_channel
++{
++ unsigned long int_line0; /* Start of primary interrupts */
++ unsigned long int_line1;
++ unsigned long int_line2;
++ unsigned long int_line3;
++ unsigned long int_line4;
++ unsigned long int_line5;
++ unsigned long int_line6;
++ unsigned long int_line7;
++ unsigned long int_line8;
++ unsigned long int_line9;
++ unsigned long int_line10;
++ unsigned long int_line11;
++ unsigned long int_line12;
++ unsigned long int_line13;
++ unsigned long int_line14;
++ unsigned long int_line15;
++ unsigned long int_line16;
++ unsigned long int_line17;
++ unsigned long int_line18;
++ unsigned long int_line19;
++ unsigned long int_line20;
++ unsigned long int_line21;
++ unsigned long int_line22;
++ unsigned long int_line23;
++ unsigned long int_line24;
++ unsigned long int_line25;
++ unsigned long int_line26;
++ unsigned long int_line27;
++ unsigned long int_line28;
++ unsigned long int_line29;
++ unsigned long int_line30;
++ unsigned long int_line31;
++ unsigned long int_line32;
++ unsigned long int_line33;
++ unsigned long int_line34;
++ unsigned long int_line35;
++ unsigned long int_line36;
++ unsigned long int_line37;
++ unsigned long int_line38;
++ unsigned long int_line39;
++};
++
++
++/* Interrupt Line #'s (Sangam peripherals) */
++
++/*------------------------------*/
++/* Sangam primary interrupts */
++/*------------------------------*/
++
++#define UNIFIED_SECONDARY_INTERRUPT 0
++#define AVALANCHE_EXT_INT_0 1
++#define AVALANCHE_EXT_INT_1 2
++/* Line #3 Reserved */
++/* Line #4 Reserved */
++#define AVALANCHE_TIMER_0_INT 5
++#define AVALANCHE_TIMER_1_INT 6
++#define AVALANCHE_UART0_INT 7
++#define AVALANCHE_UART1_INT 8
++#define AVALANCHE_PDMA_INT0 9
++#define AVALANCHE_PDMA_INT1 10
++/* Line #11 Reserved */
++/* Line #12 Reserved */
++/* Line #13 Reserved */
++/* Line #14 Reserved */
++#define AVALANCHE_ATM_SAR_INT 15
++/* Line #16 Reserved */
++/* Line #17 Reserved */
++/* Line #18 Reserved */
++#define AVALANCHE_MAC0_INT 19
++/* Line #20 Reserved */
++#define AVALANCHE_VLYNQ0_INT 21
++#define AVALANCHE_CODEC_WAKE_INT 22
++/* Line #23 Reserved */
++#define AVALANCHE_USB_INT 24
++#define AVALANCHE_VLYNQ1_INT 25
++/* Line #26 Reserved */
++/* Line #27 Reserved */
++#define AVALANCHE_MAC1_INT 28
++#define AVALANCHE_I2CM_INT 29
++#define AVALANCHE_PDMA_INT2 30
++#define AVALANCHE_PDMA_INT3 31
++/* Line #32 Reserved */
++/* Line #33 Reserved */
++/* Line #34 Reserved */
++/* Line #35 Reserved */
++/* Line #36 Reserved */
++#define AVALANCHE_VDMA_VT_RX_INT 37
++#define AVALANCHE_VDMA_VT_TX_INT 38
++#define AVALANCHE_ADSLSS_INT 39
++
++/*-----------------------------------*/
++/* Sangam Secondary Interrupts */
++/*-----------------------------------*/
++#define PRIMARY_INTS 40
++
++#define EMIF_INT (7 + PRIMARY_INTS)
++
++
++extern void avalanche_int_set(int channel, int line);
++
++
++#endif /* _AVALANCHE_INTC_H */
+diff -urN linux.old/include/asm-mips/ar7/avalanche_misc.h linux.dev/include/asm-mips/ar7/avalanche_misc.h
+--- linux.old/include/asm-mips/ar7/avalanche_misc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/avalanche_misc.h 2005-11-10 01:10:46.067588500 +0100
+@@ -0,0 +1,174 @@
++#ifndef _AVALANCHE_MISC_H_
++#define _AVALANCHE_MISC_H_
++
++typedef enum AVALANCHE_ERR_t
++{
++ AVALANCHE_ERR_OK = 0, /* OK or SUCCESS */
++ AVALANCHE_ERR_ERROR = -1, /* Unspecified/Generic ERROR */
++
++ /* Pointers and args */
++ AVALANCHE_ERR_INVARG = -2, /* Invaild argument to the call */
++ AVALANCHE_ERR_NULLPTR = -3, /* NULL pointer */
++ AVALANCHE_ERR_BADPTR = -4, /* Bad (out of mem) pointer */
++
++ /* Memory issues */
++ AVALANCHE_ERR_ALLOC_FAIL = -10, /* allocation failed */
++ AVALANCHE_ERR_FREE_FAIL = -11, /* free failed */
++ AVALANCHE_ERR_MEM_CORRUPT = -12, /* corrupted memory */
++ AVALANCHE_ERR_BUF_LINK = -13, /* buffer linking failed */
++
++ /* Device issues */
++ AVALANCHE_ERR_DEVICE_TIMEOUT = -20, /* device timeout on read/write */
++ AVALANCHE_ERR_DEVICE_MALFUNC = -21, /* device malfunction */
++
++ AVALANCHE_ERR_INVID = -30 /* Invalid ID */
++
++} AVALANCHE_ERR;
++
++/*****************************************************************************
++ * Reset Control Module
++ *****************************************************************************/
++
++typedef enum AVALANCHE_RESET_MODULE_tag
++{
++ RESET_MODULE_UART0 = 0,
++ RESET_MODULE_UART1 = 1,
++ RESET_MODULE_I2C = 2,
++ RESET_MODULE_TIMER0 = 3,
++ RESET_MODULE_TIMER1 = 4,
++ RESET_MODULE_GPIO = 6,
++ RESET_MODULE_ADSLSS = 7,
++ RESET_MODULE_USBS = 8,
++ RESET_MODULE_SAR = 9,
++ RESET_MODULE_VDMA_VT = 11,
++ RESET_MODULE_FSER = 12,
++ RESET_MODULE_VLYNQ1 = 16,
++ RESET_MODULE_EMAC0 = 17,
++ RESET_MODULE_DMA = 18,
++ RESET_MODULE_BIST = 19,
++ RESET_MODULE_VLYNQ0 = 20,
++ RESET_MODULE_EMAC1 = 21,
++ RESET_MODULE_MDIO = 22,
++ RESET_MODULE_ADSLSS_DSP = 23,
++ RESET_MODULE_EPHY = 26
++} AVALANCHE_RESET_MODULE_T;
++
++typedef enum AVALANCHE_RESET_CTRL_tag
++{
++ IN_RESET = 0,
++ OUT_OF_RESET
++} AVALANCHE_RESET_CTRL_T;
++
++typedef enum AVALANCHE_SYS_RST_MODE_tag
++{
++ RESET_SOC_WITH_MEMCTRL = 1, /* SW0 bit in SWRCR register */
++ RESET_SOC_WITHOUT_MEMCTRL = 2 /* SW1 bit in SWRCR register */
++} AVALANCHE_SYS_RST_MODE_T;
++
++typedef enum AVALANCHE_SYS_RESET_STATUS_tag
++{
++ HARDWARE_RESET = 0,
++ SOFTWARE_RESET0, /* Caused by writing 1 to SW0 bit in SWRCR register */
++ WATCHDOG_RESET,
++ SOFTWARE_RESET1 /* Caused by writing 1 to SW1 bit in SWRCR register */
++} AVALANCHE_SYS_RESET_STATUS_T;
++
++AVALANCHE_RESET_CTRL_T avalanche_get_reset_status(AVALANCHE_RESET_MODULE_T reset_module);
++void avalanche_sys_reset(AVALANCHE_SYS_RST_MODE_T mode);
++AVALANCHE_SYS_RESET_STATUS_T avalanche_get_sys_last_reset_status(void);
++
++typedef int (*REMOTE_VLYNQ_DEV_RESET_CTRL_FN)(unsigned int reset_module, AVALANCHE_RESET_CTRL_T reset_ctrl);
++
++/*****************************************************************************
++ * Power Control Module
++ *****************************************************************************/
++
++typedef enum AVALANCHE_POWER_CTRL_tag
++{
++ POWER_CTRL_POWER_UP = 0,
++ POWER_CTRL_POWER_DOWN
++} AVALANCHE_POWER_CTRL_T;
++
++typedef enum AVALANCHE_SYS_POWER_MODE_tag
++{
++ GLOBAL_POWER_MODE_RUN = 0, /* All system is up */
++ GLOBAL_POWER_MODE_IDLE, /* MIPS is power down, all peripherals working */
++ GLOBAL_POWER_MODE_STANDBY, /* Chip in power down, but clock to ADSKL subsystem is running */
++ GLOBAL_POWER_MODE_POWER_DOWN /* Total chip is powered down */
++} AVALANCHE_SYS_POWER_MODE_T;
++
++void avalanche_power_ctrl(unsigned int power_module, AVALANCHE_POWER_CTRL_T power_ctrl);
++AVALANCHE_POWER_CTRL_T avalanche_get_power_status(unsigned int power_module);
++void avalanche_set_global_power_mode(AVALANCHE_SYS_POWER_MODE_T power_mode);
++AVALANCHE_SYS_POWER_MODE_T avalanche_get_global_power_mode(void);
++
++/*****************************************************************************
++ * Wakeup Control
++ *****************************************************************************/
++
++typedef enum AVALANCHE_WAKEUP_INTERRUPT_tag
++{
++ WAKEUP_INT0 = 1,
++ WAKEUP_INT1 = 2,
++ WAKEUP_INT2 = 4,
++ WAKEUP_INT3 = 8
++} AVALANCHE_WAKEUP_INTERRUPT_T;
++
++typedef enum TNETV1050_WAKEUP_CTRL_tag
++{
++ WAKEUP_DISABLED = 0,
++ WAKEUP_ENABLED
++} AVALANCHE_WAKEUP_CTRL_T;
++
++typedef enum TNETV1050_WAKEUP_POLARITY_tag
++{
++ WAKEUP_ACTIVE_HIGH = 0,
++ WAKEUP_ACTIVE_LOW
++} AVALANCHE_WAKEUP_POLARITY_T;
++
++void avalanche_wakeup_ctrl(AVALANCHE_WAKEUP_INTERRUPT_T wakeup_int,
++ AVALANCHE_WAKEUP_CTRL_T wakeup_ctrl,
++ AVALANCHE_WAKEUP_POLARITY_T wakeup_polarity);
++
++/*****************************************************************************
++ * GPIO Control
++ *****************************************************************************/
++
++typedef enum AVALANCHE_GPIO_PIN_MODE_tag
++{
++ FUNCTIONAL_PIN = 0,
++ GPIO_PIN = 1
++} AVALANCHE_GPIO_PIN_MODE_T;
++
++typedef enum AVALANCHE_GPIO_PIN_DIRECTION_tag
++{
++ GPIO_OUTPUT_PIN = 0,
++ GPIO_INPUT_PIN = 1
++} AVALANCHE_GPIO_PIN_DIRECTION_T;
++
++typedef enum { GPIO_FALSE, GPIO_TRUE } AVALANCHE_GPIO_BOOL_T;
++
++void avalanche_gpio_init(void);
++int avalanche_gpio_ctrl(unsigned int gpio_pin,
++ AVALANCHE_GPIO_PIN_MODE_T pin_mode,
++ AVALANCHE_GPIO_PIN_DIRECTION_T pin_direction);
++int avalanche_gpio_ctrl_with_link_count(unsigned int gpio_pin,
++ AVALANCHE_GPIO_PIN_MODE_T pin_mode,
++ AVALANCHE_GPIO_PIN_DIRECTION_T pin_direction);
++int avalanche_gpio_out_bit(unsigned int gpio_pin, int value);
++int avalanche_gpio_in_bit(unsigned int gpio_pin);
++int avalanche_gpio_out_value(unsigned int out_val, unsigned int set_mask, unsigned int reg_index);
++int avalanche_gpio_out_value_with_link_count(unsigned int out_val, unsigned int set_mask, unsigned int reg_index);
++int avalanche_gpio_in_value(unsigned int *in_val, unsigned int reg_index);
++
++unsigned int avalanche_get_chip_version_info(void);
++
++unsigned int avalanche_get_vbus_freq(void);
++void avalanche_set_vbus_freq(unsigned int);
++
++
++typedef int (*SET_MDIX_ON_CHIP_FN_T)(unsigned int base_addr, unsigned int operation);
++int avalanche_set_mdix_on_chip(unsigned int base_addr, unsigned int operation);
++unsigned int avalanche_is_mdix_on_chip(void);
++
++#endif
+diff -urN linux.old/include/asm-mips/ar7/avalanche_regs.h linux.dev/include/asm-mips/ar7/avalanche_regs.h
+--- linux.old/include/asm-mips/ar7/avalanche_regs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/avalanche_regs.h 2005-11-10 01:10:46.071588750 +0100
+@@ -0,0 +1,567 @@
++/*
++ * $Id$
++ * Avalanche Register Descriptions
++ *
++ * Jeff Harrell, jharrell@ti.com
++ * 2000 (c) Texas Instruments Inc.
++ */
++
++#ifndef __AVALANCHE_REGS_H
++#define __AVALANCHE_REGS_H
++
++#include <asm/addrspace.h>
++#include <linux/config.h>
++
++/*----------------------------------------*/
++/* Base offsets within the Avalanche ASIC */
++/*----------------------------------------*/
++
++#define BBIF_SPACE0 (KSEG1ADDR(0x01000000))
++#define BBIF_SPACE1 (KSEG1ADDR(0x01800000))
++#define BBIF_CONTROL (KSEG1ADDR(0x02000000))
++#define ATM_SAR_BASE (KSEG1ADDR(0x03000000))
++#define USB_MCU_BASE (KSEG1ADDR(0x03400000))
++#define DES_BASE (KSEG1ADDR(0x08600000))
++#define ETH_MACA_BASE (KSEG1ADDR(0x08610000))
++#define ETH_MACB_BASE (KSEG1ADDR(0x08612800))
++#define MEM_CTRLR_BASE (KSEG1ADDR(0x08610800))
++#define GPIO_BASE (KSEG1ADDR(0x08610900))
++#define CLK_CTRL_BASE (KSEG1ADDR(0x08610A00))
++#define WATCH_DOG_BASE (KSEG1ADDR(0x08610B00))
++#define TMR1_BASE (KSEG1ADDR(0x08610C00))
++#define TRM2_BASE (KSEG1ADDR(0x08610D00))
++#define UARTA_BASE (KSEG1ADDR(0x08610E00))
++#define UARTB_BASE (KSEG1ADDR(0x08610F00))
++#define I2C_BASE (KSEG1ADDR(0x08611000))
++#define DEV_ID_BASE (KSEG1ADDR(0x08611100))
++#define USB_BASE (KSEG1ADDR(0x08611200))
++#define PCI_CONFIG_BASE (KSEG1ADDR(0x08611300))
++#define DMA_BASE (KSEG1ADDR(0x08611400))
++#define RESET_CTRL_BASE (KSEG1ADDR(0x08611600))
++#define DSL_IF_BASE (KSEG1ADDR(0x08611B00))
++#define INT_CTL_BASE (KSEG1ADDR(0x08612400))
++#define PHY_BASE (KSEG1ADDR(0x1E000000))
++
++/*---------------------------------*/
++/* Device ID, chip version number */
++/*---------------------------------*/
++
++#define AVALANCHE_CHVN (*(volatile unsigned int *)(DEV_ID_BASE+0x14))
++#define AVALANCHE_DEVID1 (*(volatile unsigned int *)(DEV_ID_BASE+0x18))
++#define AVALANCHE_DEVID2 (*(volatile unsigned int *)(DEV_ID_BASE+0x1C))
++
++/*----------------------------------*/
++/* Reset Control VW changed to ptrs */
++/*----------------------------------*/
++
++#define AVALANCHE_PRCR (*(volatile unsigned int *)(RESET_CTRL_BASE + 0x0)) /* Peripheral reset control */
++#define AVALANCHE_SWRCR (*(volatile unsigned int *)(RESET_CTRL_BASE + 0x4)) /* Software reset control */
++#define AVALANCHE_RSR (*(volatile unsigned int *)(RESET_CTRL_BASE + 0x8)) /* Reset status register */
++
++/* reset control bits */
++
++#define AV_RST_UART0 (1<<0) /* Brings UART0 out of reset */
++#define AV_RST_UART1 (1<<1) /* Brings UART1 out of reset */
++#define AV_RST_IICM (1<<2) /* Brings the I2CM out of reset */
++#define AV_RST_TIMER0 (1<<3) /* Brings Timer 0 out of reset */
++#define AV_RST_TIMER1 (1<<4) /* Brings Timer 1 out of reset */
++#define AV_RST_DES (1<<5) /* Brings the DES module out of reset */
++#define AV_RST_GPIO (1<<6) /* Brings the GPIO module out of reset (see note below) */
++/*
++ JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE
++ If you reset the GPIO interface all of the directions (i/o) of the UART B
++ interface pins are inputs and must be reconfigured so as not to lose the
++ serial console interface
++ JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE
++*/
++#define AV_RST_BBIF (1<<7) /* Brings the Broadband interface out of reset */
++#define AV_RST_USB (1<<8) /* Brings the USB module out of reset */
++#define AV_RST_SAR (1<<9) /* Brings the SAR out of reset */
++#define AV_RST_HDLC (1<<10) /* Brings the HDLC module out of reset */
++#define AV_RST_PCI (1<<16) /* Brings the PCI module out of reset */
++#define AV_RST_ETH_MAC0 (1<<17) /* Brings the Ethernet MAC0 out of reset */
++#define AV_RST_PICO_DMA (1<<18) /* Brings the PICO DMA module out of reset */
++#define AV_RST_BIST (1<<19) /* Brings the BIST module out of reset */
++#define AV_RST_DSP (1<<20) /* Brings the DSP sub system out of reset */
++#define AV_RST_ETH_MAC1 (1<<21) /* Brings the Ethernet MAC1 out of reset */
++
++/*----------------------*/
++/* Physical interfaces */
++/*----------------------*/
++
++/* Phy loopback */
++#define PHY_LOOPBACK 1
++
++
++/* Phy 0 */
++#define PHY0BASE (PHY_BASE)
++#define PHY0RST (*(volatile unsigned char *) (PHY0BASE)) /* reset */
++#define PHY0CTRL (*(volatile unsigned char *) (PHY0BASE+0x5)) /* control */
++#define PHY0RACPCTRL (*(volatile unsigned char *) (PHY0BASE+0x50)) /* RACP control/status */
++#define PHY0TACPCTRL (*(volatile unsigned char *) (PHY0BASE+0x60)) /* TACP idle/unassigned cell hdr */
++#define PHY0RACPINT (*(volatile unsigned char *) (PHY0BASE+0x51)) /* RACP interrupt enable/Status */
++
++
++/* Phy 1 */
++
++#define PHY1BASE (PHY_BASE + 0x100000)
++#define PHY1RST (*(volatile unsigned char *) (PHY1BASE)) /* reset */
++#define PHY1CTRL (*(volatile unsigned char *) (PHY1BASE+0x5)) /* control */
++#define PHY1RACPCTRL (*(volatile unsigned char *) (PHY1BASE+0x50))
++#define PHY1TACPCTRL (*(volatile unsigned char *) (PHY1BASE+0x60))
++#define PHY1RACPINT (*(volatile unsigned char *) (PHY1BASE+0x51))
++
++/* Phy 2 */
++
++#define PHY2BASE (PHY_BASE + 0x200000)
++#define PHY2RST (*(volatile unsigned char *) (PHY2BASE)) /* reset */
++#define PHY2CTRL (*(volatile unsigned char *) (PHY2BASE+0x5)) /* control */
++#define PHY2RACPCTRL (*(volatile unsigned char *) (PHY2BASE+0x50))
++#define PHY2TACPCTRL (*(volatile unsigned char *) (PHY2BASE+0x60))
++#define PHY2RACPINT (*(volatile unsigned char *) (PHY2BASE+0x51))
++
++/*-------------------*/
++/* Avalanche ATM SAR */
++/*-------------------*/
++
++#define AVSAR_SYSCONFIG (*(volatile unsigned int*)(ATM_SAR_BASE+0x00000000)) /* SAR system config register */
++#define AVSAR_SYSSTATUS (*(volatile unsigned int*)(ATM_SAR_BASE+0x00000004)) /* SAR system status register */
++#define AVSAR_INT_ENABLE (*(volatile unsigned int*)(ATM_SAR_BASE+0x00000008)) /* SAR interrupt enable register */
++#define AVSAR_CONN_VPI_VCI (*(volatile unsigned int*)(ATM_SAR_BASE+0x0000000c)) /* VPI/VCI connection config */
++#define AVSAR_CONN_CONFIG (*(volatile unsigned int*)(ATM_SAR_BASE+0x00000010)) /* Connection config register */
++#define AVSAR_OAM_CONFIG (*(volatile unsigned int*)(ATM_SAR_BASE+0x00000018)) /* OAM configuration register */
++
++/* Transmit completion ring registers */
++
++#define AVSAR_TCRAPTR (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000100))
++#define AVSAR_TCRASIZE (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000104))
++#define AVSAR_TCRAINTTHRESH (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000108))
++#define AVSAR_TCRATOTENT (*(volatile unsigned int *)(ATM_SAR_BASE+0x0000010c))
++#define AVSAR_TCRAFREEENT (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000110))
++#define AVSAR_TCRAPENDENT (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000114))
++#define AVSAR_TCRAENTINC (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000118))
++#define AVSAR_TCRBPTR (*(volatile unsigned int *)(ATM_SAR_BASE+0x0000011c))
++#define AVSAR_TCRBSIZE (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000120))
++#define AVSAR_TCRBINTTHRESH (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000124))
++#define AVSAR_TCRBTOTENT (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000128))
++#define AVSAR_TCRBFREEENT (*(volatile unsigned int *)(ATM_SAR_BASE+0x0000012c))
++#define AVSAR_TCRBPENDENT (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000130))
++#define AVSAR_TCRBENTINC (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000134))
++
++/* Transmit Queue Packet registers */
++#define AVSAR_TXQUEUE_PKT0 (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000140))
++#define AVSAR_TXQUEUE_PKT1 (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000144))
++#define AVSAR_TXQUEUE_PKT2 (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000148))
++#define AVSAR_TX_FLUSH (*(volatile unsigned int *)(ATM_SAR_BASE+0x0000014C))
++/* Receive completion ring registers */
++
++#define AVSAR_RCRAPTR (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000200))
++#define AVSAR_RCRASIZE (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000204))
++#define AVSAR_RCRAINTTHRESH (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000208))
++#define AVSAR_RCRATOTENT (*(volatile unsigned int *)(ATM_SAR_BASE+0x0000020c))
++#define AVSAR_RCRAFREEENT (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000210))
++#define AVSAR_RCRAPENDENT (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000214))
++#define AVSAR_RCRAENTINC (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000218))
++#define AVSAR_RCRBPTR (*(volatile unsigned int *)(ATM_SAR_BASE+0x0000021c))
++#define AVSAR_RCRBSIZE (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000220))
++#define AVSAR_RCRBINTTHRESH (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000224))
++#define AVSAR_RCRBTOTENT (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000228))
++#define AVSAR_RCRBFREEENT (*(volatile unsigned int *)(ATM_SAR_BASE+0x0000022c))
++#define AVSAR_RCRBPENDENT (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000230))
++#define AVSAR_RCRBENTINC (*(volatile unsigned int *)(ATM_SAR_BASE+0x00000234))
++
++#define AVSAR_RXFBL_ADD0 (*(volatile unsigned int*)(ATM_SAR_BASE+0x00000240)) /* Rx Free buffer list add 0 */
++#define AVSAR_RXFBL_ADD1 (*(volatile unsigned int*)(ATM_SAR_BASE+0x00000244)) /* Rx Free buffer list add 1 */
++#define AVSAR_RXFBL_ADD2 (*(volatile unsigned int*)(ATM_SAR_BASE+0x00000248)) /* Rx Free buffer list add 2 */
++#define AVSAR_RXFBLSIZE_0 (*(volatile unsigned int*)(ATM_SAR_BASE+0x0000028c)) /* Rx Free buffer list size 0 */
++#define AVSAR_RXFBLSIZE_1 (*(volatile unsigned int*)(ATM_SAR_BASE+0x0000029c)) /* Rx Free buffer list size 1 */
++#define AVSAR_RXFBLSIZE_2 (*(volatile unsigned int*)(ATM_SAR_BASE+0x000002ac)) /* Rx Free buffer list size 2 */
++#define AVSAR_RXFBLSIZE_3 (*(volatile unsigned int*)(ATM_SAR_BASE+0x000002bc)) /* Rx Free buffer list size 3 */
++
++
++#if defined(CONFIG_MIPS_EVM3D) || defined(CONFIG_MIPS_AR5D01) || defined(CONFIG_MIPS_AR5W01)
++
++#define AVSAR_SAR_FREQUENCY (*(volatile unsigned int*)(ATM_SAR_BASE+0x00010480))
++#define AVSAR_OAM_CC_SINK (*(volatile unsigned int*)(ATM_SAR_BASE+0x00010484))
++#define AVSAR_OAM_AIS_RDI_RX (*(volatile unsigned int*)(ATM_SAR_BASE+0x00010488))
++#define AVSAR_OAM_CPID0 (*(volatile unsigned int*)(ATM_SAR_BASE+0x000104E0))
++#define AVSAR_OAM_LLID0 (*(volatile unsigned int*)(ATM_SAR_BASE+0x000104F0))
++#define AVSAR_OAM_CPID1 (*(volatile unsigned int*)(ATM_SAR_BASE+0x000104E4))
++#define AVSAR_OAM_LLID1 (*(volatile unsigned int*)(ATM_SAR_BASE+0x000104F4))
++#define AVSAR_OAM_CPID2 (*(volatile unsigned int*)(ATM_SAR_BASE+0x000104E8))
++#define AVSAR_OAM_LLID2 (*(volatile unsigned int*)(ATM_SAR_BASE+0x000104F8))
++#define AVSAR_OAM_CPID3 (*(volatile unsigned int*)(ATM_SAR_BASE+0x000104EC))
++#define AVSAR_OAM_LLID3 (*(volatile unsigned int*)(ATM_SAR_BASE+0x000104FC))
++#define AVSAR_OAM_CORR_TAG (*(volatile unsigned int*)(ATM_SAR_BASE+0x00010500))
++#define AVSAR_OAM_FAR_COUNT (*(volatile unsigned int*)(ATM_SAR_BASE+0x00010520))
++#define AVSAR_OAM_NEAR_COUNT (*(volatile unsigned int*)(ATM_SAR_BASE+0x00010540))
++#define AVSAR_OAM_CONFIG_REG (*(volatile unsigned int*)(ATM_SAR_BASE+0x00000018))
++#define AVSAR_FAIRNESS_REG (*(volatile unsigned int*)(ATM_SAR_BASE+0x000104B8))
++#define AVSAR_UBR_PCR_REG (*(volatile unsigned int*)(ATM_SAR_BASE+0x00010490))
++
++
++/*
++
++#define OAM_CPID_ADD 0xa30104e0
++
++#define OAM_LLID_ADD 0xa30104f0
++
++#define OAM_LLID_VAL 0xffffffff
++
++#define OAM_CORR_TAG 0xa3010500
++
++#define OAM_FAR_COUNT_ADD 0xa3010520
++
++#define OAM_NEAR_COUNT_ADD 0xa3010540
++
++#define OAM_CONFIG_REG_ADD 0xa3000018
++*/
++
++
++#else /* CONFIG_MIPS_EVM3 || CONFIG_MIPS_ACPEP */
++
++#define AVSAR_SAR_FREQUENCY (*(volatile unsigned int*)(ATM_SAR_BASE+0x00012000))
++#define AVSAR_OAM_CC_SINK (*(volatile unsigned int*)(ATM_SAR_BASE+0x00012004))
++#define AVSAR_OAM_AIS_RDI_RX (*(volatile unsigned int*)(ATM_SAR_BASE+0x00012008))
++#define AVSAR_OAM_CPID (*(volatile unsigned int*)(ATM_SAR_BASE+0x00012300))
++
++#endif /* CONFIG_MIPS_EVM3D || CONFIG_MIPS_AR5D01 || CONFIG_MIPS_AR5W01 */
++
++
++#define AVSAR_STATE_RAM (ATM_SAR_BASE + 0x010000) /* SAR state RAM */
++#define AVSAR_PDSP_BASE (ATM_SAR_BASE + 0x020000) /* SAR PDSP base address */
++#define AVSAR_TXDMA_BASE (ATM_SAR_BASE + 0x030000) /* Transmit DMA state base */
++#define AVSAR_TDMASTATE6 0x18 /* Transmit DMA state word 6 */
++#define AVSAR_RXDMA_BASE (ATM_SAR_BASE + 0x040000) /* Receive DMA state base */
++#define AVSAR_RDMASTATE0 0x0 /* Receive DMA state word 0 */
++
++/*------------------------------------------*/
++/* DSL Interface */
++/*------------------------------------------*/
++
++#define AVDSL_TX_EN (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000000))
++#define AVDSL_RX_EN (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000004))
++#define AVDSL_POLL (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000008))
++
++/* Fast */
++
++#define AVDSL_TX_FIFO_ADDR0 (*(volatile unsigned int *)(DSL_IF_BASE + 0x0000000C))
++#define AVDSL_TX_FIFO_BASE0 (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000010))
++#define AVDSL_TX_FIFO_LEN0 (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000014))
++#define AVDSL_TX_FIFO_PR0 (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000018))
++#define AVDSL_RX_FIFO_ADDR0 (*(volatile unsigned int *)(DSL_IF_BASE + 0x0000001C))
++#define AVDSL_RX_FIFO_BASE0 (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000020))
++#define AVDSL_RX_FIFO_LEN0 (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000024))
++#define AVDSL_RX_FIFO_PR0 (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000028))
++
++/* Interleaved */
++
++#define AVDSL_TX_FIFO_ADDR1 (*(volatile unsigned int *)(DSL_IF_BASE + 0x0000002C))
++#define AVDSL_TX_FIFO_BASE1 (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000030))
++#define AVDSL_TX_FIFO_LEN1 (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000034))
++#define AVDSL_TX_FIFO_PR1 (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000038))
++#define AVDSL_RX_FIFO_ADDR1 (*(volatile unsigned int *)(DSL_IF_BASE + 0x0000003C))
++#define AVDSL_RX_FIFO_BASE1 (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000040))
++#define AVDSL_RX_FIFO_LEN1 (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000044))
++#define AVDSL_RX_FIFO_PR1 (*(volatile unsigned int *)(DSL_IF_BASE + 0x00000048))
++
++/*------------------------------------------*/
++/* Broadband I/F */
++/*------------------------------------------*/
++
++#define AVBBIF_BBIF_CNTRL (*(volatile unsigned int *)(BBIF_CONTROL + 0x00000000))
++#define AVBBIF_ADDR_TRANS_0 (*(volatile unsigned int *)(BBIF_CONTROL + 0x00000004))
++#define AVBBIF_ADDR_TRANS_1 (*(volatile unsigned int *)(BBIF_CONTROL + 0x00000008))
++#define AVBBIF_ADDR_XB_MX_BL (*(volatile unsigned int *)(BBIF_CONTROL + 0x0000000C))
++#define AVBBIF_INFIFO_LVL (*(volatile unsigned int *)(BBIF_CONTROL + 0x00000010))
++#define AVBBIF_OUTFIFO_LVL (*(volatile unsigned int *)(BBIF_CONTROL + 0x00000014))
++
++#define AVBBIF_DISABLED 0x0
++#define AVBBIF_LBT4040_INT 0x1
++#define AVBBIF_XBUS 0x2
++#define AVBBIF_LBT4040_EXT 0x4
++
++#define AVBBIF_ADDR_MASK0 0xff000000 /* handles upper bits of BBIF 0 address */
++#define AVBBIF_ADDR_MASK1 0xff800000 /* handles upper bits of BBIF 1 address */
++#define AVBBIF_TRANS_MASK 0xff000000
++/*------------------------------------------*/
++/* GPIO I/F */
++/*------------------------------------------*/
++
++#define GPIO_DATA_INPUT (*(volatile unsigned int *)(GPIO_BASE + 0x00000000))
++#define GPIO_DATA_OUTPUT (*(volatile unsigned int *)(GPIO_BASE + 0x00000004))
++#define GPIO_DATA_DIR (*(volatile unsigned int *)(GPIO_BASE + 0x00000008)) /* 0=output 1=input */
++#define GPIO_DATA_ENABLE (*(volatile unsigned int *)(GPIO_BASE + 0x0000000C)) /* 0=GPIO Mux 1=GPIO */
++
++#define GPIO_0 (1<<21)
++#define GPIO_1 (1<<22)
++#define GPIO_2 (1<<23)
++#define GPIO_3 (1<<24)
++#define EINT_1 (1<<18)
++
++/*
++ JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE
++ If you reset the GPIO interface all of the directions (i/o) of the UART B
++ interface pins are inputs and must be reconfigured so as not to lose the
++ serial console interface
++ JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE JAH NOTE
++*/
++
++/*------------------------------------------*/
++/* CLK_CTRL */
++/*------------------------------------------*/
++#define PERIPH_CLK_CTL (*(volatile unsigned int *)(CLK_CTRL_BASE + 0x00000004))
++
++#define PCLK_0_HALF_VBUS (0<<16)
++#define PCLK_EQ_INPUT (1<<16)
++#define BBIF_CLK_HALF_VBUS (0<<17)
++#define BBIF_CLK_EQ_VBUS (1<<17)
++#define BBIF_CLK_EQ_BBCLK (3<<17)
++#define DSP_MODCLK_DSPCLKI (0<<20)
++#define DSP_MODCLK_REFCLKI (1<<20)
++#define USB_CLK_EQ_USBCLKI (0<<21)
++#define USB_CLK_EQ_REFCLKI (1<<21)
++
++/*------------------------------------------*/
++/* PCI Control Registers */
++/*------------------------------------------*/
++#define PCIC_CONTROL (*(volatile unsigned int *)(PCI_CONFIG_BASE))
++#define PCIC_CONTROL_CFG_DONE (1<<0)
++#define PCIC_CONTROL_DIS_SLAVE_TO (1<<1)
++#define PCIC_CONTROL_FORCE_DELAY_READ (1<<2)
++#define PCIC_CONTROL_FORCE_DELAY_READ_LINE (1<<3)
++#define PCIC_CONTROL_FORCE_DELAY_READ_MULT (1<<4)
++#define PCIC_CONTROL_MEM_SPACE_EN (1<<5)
++#define PCIC_CONTROL_MEM_MASK (1<<6)
++#define PCIC_CONTROL_IO_SPACE_EN (1<<7)
++#define PCIC_CONTROL_IO_MASK (1<<8)
++/* PCIC_CONTROL_RESERVED (1<<9) */
++#define PCIC_CONTROL_BASE0_EN (1<<10)
++#define PCIC_CONTROL_BASE1_EN (1<<11)
++#define PCIC_CONTROL_BASE2_EN (1<<12)
++#define PCIC_CONTROL_HOLD_MASTER_WRITE (1<<13)
++#define PCIC_CONTROL_ARBITER_EN (1<<14)
++#define PCIC_INT_SOURCE (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000004))
++#define PCIC_INT_SOURCE_PWR_MGMT (1<<0)
++#define PCIC_INT_SOURCE_PCI_TARGET (1<<1)
++#define PCIC_INT_SOURCE_PCI_MASTER (1<<2)
++#define PCIC_INT_SOURCE_POWER_WAKEUP (1<<3)
++#define PCIC_INT_SOURCE_PMEIN (1<<4)
++/* PCIC_INT_SOURCE_RESERVED (1<<5) */
++/* PCIC_INT_SOURCE_RESERVED (1<<6) */
++#define PCIC_INT_SOURCE_PIC_INTA (1<<7)
++#define PCIC_INT_SOURCE_PIC_INTB (1<<8)
++#define PCIC_INT_SOURCE_PIC_INTC (1<<9)
++#define PCIC_INT_SOURCE_PIC_INTD (1<<10)
++#define PCIC_INT_SOURCE_SOFT_INT0 (1<<11)
++#define PCIC_INT_SOURCE_SOFT_INT1 (1<<12)
++#define PCIC_INT_SOURCE_SOFT_INT2 (1<<13)
++#define PCIC_INT_SOURCE_SOFT_INT3 (1<<14)
++#define PCIC_INT_CLEAR (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000008))
++#define PCIC_INT_CLEAR_PM (1<<0)
++#define PCIC_INT_CLEAR_PCI_TARGET (1<<1)
++#define PCIC_INT_CLEAR_PCI_MASTER (1<<2)
++/* PCIC_INT_CLEAR_RESERVED (1<<3) */
++#define PCIC_INT_CLEAR_PMEIN (1<<4)
++/* PCIC_INT_CLEAR_RESERVED (1<<5) */
++/* PCIC_INT_CLEAR_RESERVED (1<<6) */
++#define PCIC_INT_CLEAR_PCI_INTA (1<<7)
++#define PCIC_INT_CLEAR_PCI_INTB (1<<8)
++#define PCIC_INT_CLEAR_PCI_INTC (1<<9)
++#define PCIC_INT_CLEAR_PCI_INTD (1<<10)
++#define PCIC_INT_CLEAR_SOFT_INT0 (1<<11)
++#define PCIC_INT_CLEAR_SOFT_INT1 (1<<12)
++#define PCIC_INT_CLEAR_SOFT_INT2 (1<<13)
++#define PCIC_INT_CLEAR_SOFT_INT3 (1<<14)
++#define PCIC_INT_EN_AVAL (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x0000000c))
++#define PCIC_INT_EN_AVAL_PM (1<<0)
++#define PCIC_INT_EN_AVAL_PCI_TARGET (1<<1)
++#define PCIC_INT_EN_AVAL_PCI_MASTER (1<<2)
++/* PCIC_INT_EN_AVAL_RESERVED (1<<3) */
++#define PCIC_INT_EN_AVAL_PMEIN (1<<4)
++/* PCIC_INT_EN_AVAL_RESERVED (1<<5) */
++/* PCIC_INT_EN_AVAL_RESERVED (1<<6) */
++#define PCIC_INT_EN_AVAL_PCI_INTA (1<<7)
++#define PCIC_INT_EN_AVAL_PCI_INTB (1<<8)
++#define PCIC_INT_EN_AVAL_PCI_INTC (1<<9)
++#define PCIC_INT_EN_AVAL_PCI_INTD (1<<10)
++#define PCIC_INT_EN_AVAL_SOFT_INT0 (1<<11)
++#define PCIC_INT_EN_AVAL_SOFT_INT1 (1<<12)
++#define PCIC_INT_EN_AVAL_SOFT_INT2 (1<<13)
++#define PCIC_INT_EN_AVAL_SOFT_INT3 (1<<14)
++#define PCIC_INT_EN_PCI (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000010))
++#define PCIC_INT_EN_PCI_PM (1<<0)
++#define PCIC_INT_EN_PCI_PCI_TARGET (1<<1)
++#define PCIC_INT_EN_PCI_PCI_MASTER (1<<2)
++/* PCIC_INT_EN_PCI_RESERVED (1<<3) */
++#define PCIC_INT_EN_PCI_PMEIN (1<<4)
++/* PCIC_INT_EN_PCI_RESERVED (1<<5) */
++/* PCIC_INT_EN_PCI_RESERVED (1<<6) */
++#define PCIC_INT_EN_PCI_PCI_INTA (1<<7)
++#define PCIC_INT_EN_PCI_PCI_INTB (1<<8)
++#define PCIC_INT_EN_PCI_PCI_INTC (1<<9)
++#define PCIC_INT_EN_PCI_PCI_INTD (1<<10)
++#define PCIC_INT_EN_PCI_SOFT_INT0 (1<<11)
++#define PCIC_INT_EN_PCI_SOFT_INT1 (1<<12)
++#define PCIC_INT_EN_PCI_SOFT_INT2 (1<<13)
++#define PCIC_INT_EN_PCI_SOFT_INT3 (1<<14)
++#define PCIC_INT_SWSET (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000014))
++#define PCIC_INT_SWSET_SOFT_INT0 (1<<0)
++#define PCIC_INT_SWSET_SOFT_INT1 (1<<1)
++#define PCIC_INT_SWSET_SOFT_INT2 (1<<2)
++#define PCIC_INT_SWSET_SOFT_INT3 (1<<3)
++#define PCIC_PM_CTL (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000018))
++#define PCIC_PM_CTL_PWR_STATE_MASK (0x02)
++/* PCIC_PM_CTL_RESERVED (1<<2) */
++/* PCIC_PM_CTL_RESERVED (1<<3) */
++/* PCIC_PM_CTL_RESERVED (1<<4) */
++/* PCIC_PM_CTL_RESERVED (1<<5) */
++/* PCIC_PM_CTL_RESERVED (1<<6) */
++/* PCIC_PM_CTL_RESERVED (1<<7) */
++/* PCIC_PM_CTL_RESERVED (1<<8) */
++/* PCIC_PM_CTL_RESERVED (1<<9) */
++#define PCIC_PM_CTL_PWR_SUPPORT (1<<10)
++#define PCIC_PM_CTL_PMEIN (1<<11)
++#define PCIC_PM_CTL_CAP_MASK (*(volatile unsigned short int *)(PCI_CONFIG_BASE + 0x0000001a))
++#define PCIC_PM_CONSUME (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x0000001c))
++#define PCIC_PM_CONSUME_D0 (*(volatile unsigned char *)(PCI_CONFIG_BASE + 0x0000001c))
++#define PCIC_PM_CONSUME_D1 (*(volatile unsigned char *)(PCI_CONFIG_BASE + 0x0000001d))
++#define PCIC_PM_CONSUME_D2 (*(volatile unsigned char *)(PCI_CONFIG_BASE + 0x0000001e))
++#define PCIC_PM_CONSUME_D3 (*(volatile unsigned char *)(PCI_CONFIG_BASE + 0x0000001f))
++#define PCIC_PM_DISSAPATED (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000020))
++#define PCIC_PM_DISSAPATED_D0 (*(volatile unsigned char *)(PCI_CONFIG_BASE + 0x00000020))
++#define PCIC_PM_DISSAPATED_D1 (*(volatile unsigned char *)(PCI_CONFIG_BASE + 0x00000021))
++#define PCIC_PM_DISSAPATED_D2 (*(volatile unsigned char *)(PCI_CONFIG_BASE + 0x00000022))
++#define PCIC_PM_DISSAPATED_D3 (*(volatile unsigned char *)(PCI_CONFIG_BASE + 0x00000023))
++#define PCIC_PM_DATA_SCALE (*(volatile unsigned short int *)(PCI_CONFIG_BASE + 0x00000024))
++#define PCIC_VEND_DEV_ID (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000028))
++#define PCIC_SUB_VEND_DEV_ID (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x0000002c))
++#define PCIC_CLASS_REV_ID (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000030))
++#define PCIC_MAX_MIN (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000034))
++#define PCIC_MAST_MEM_AT0 (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x0000003c))
++#define PCIC_MAST_MEM_AT1 (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000040))
++#define PCIC_MAST_MEM_AT2 (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000044))
++#define PCIC_SLAVE_MASK0 (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x0000004c))
++#define PCIC_SLAVE_MASK1 (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000050))
++#define PCIC_SLAVE_MASK2 (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000054))
++#define PCIC_SLAVE_BASE_AT0 (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000058))
++#define PCIC_SLAVE_BASE_AT1 (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x0000005c))
++#define PCIC_SLAVE_BASE_AT2 (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000060))
++#define PCIC_CONF_COMMAND (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000090))
++#define PCIC_CONF_ADDR (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000094))
++#define PCIC_CONF_DATA (*(volatile unsigned int *)(PCI_CONFIG_BASE + 0x00000098))
++
++/*------------------------------------------*/
++/* IIC_INTERFACE */
++/*------------------------------------------*/
++#define I2C_DATA_HI (*(volatile unsigned int *)(I2C_BASE + 0x0))
++#define I2C_DATA_LOW (*(volatile unsigned int *)(I2C_BASE + 0x4))
++#define I2C_CONFIG (*(volatile unsigned int *)(I2C_BASE + 0x8))
++#define I2C_DATA_READ (*(volatile unsigned int *)(I2C_BASE + 0xC))
++#define I2C_CLOCK_DIV (*(volatile unsigned int *)(I2C_BASE + 0x10))
++
++#define I2CWRITE 0x200
++#define I2CREAD 0x300
++#define I2C_END_BURST 0x400
++
++/* read bits */
++#define I2C_READ_ERROR 0x8000
++#define I2C_READ_COMPLETE 0x4000
++#define I2C_READ_BUSY 0x2000
++
++/* device types */
++#define I2C_IO_EXPANDER 0x2
++#define I2C_RTC 0xd
++
++/* device Addresses on I2C bus (EVM3) */
++#define SEVEN_SEGMENT_DISP 0x23 /* Device type = 0x2, Addr = 3 */
++#define EVM3_RTC 0xd0 /* Device type = 0xd, Addr = 0 */
++#define EVM3_RTC_I2C_ADDR 0x0
++
++/*------------------------------------------*/
++/* Ethernet MAC register offset definitions */
++/*------------------------------------------*/
++#define VMAC_DMACONFIG(X) (*(volatile unsigned int *)(X + 0x00000000))
++#define VMAC_INTSTS(X) (*(volatile unsigned int *)(X + 0x00000004))
++#define VMAC_INTMASK(X) (*(volatile unsigned int *)(X + 0x00000008))
++
++#define VMAC_WRAPCLK(X) (*(volatile unsigned int *)(X + 0x00000340))
++#define VMAC_STATSBASE(X) (*(volatile unsigned int *)(X + 0x00000400))
++
++#define VMAC_TCRPTR(X) (*(volatile unsigned int *)(X + 0x00000100))
++#define VMAC_TCRSIZE(X) (*(volatile unsigned int *)(X + 0x00000104))
++#define VMAC_TCRINTTHRESH(X) (*(volatile unsigned int *)(X + 0x00000108))
++#define VMAC_TCRTOTENT(X) (*(volatile unsigned int *)(X + 0x0000010C))
++#define VMAC_TCRFREEENT(X) (*(volatile unsigned int *)(X + 0x00000110))
++#define VMAC_TCRPENDENT(X) (*(volatile unsigned int *)(X + 0x00000114))
++#define VMAC_TCRENTINC(X) (*(volatile unsigned int *)(X + 0x00000118))
++#define VMAC_TXISRPACE(X) (*(volatile unsigned int *)(X + 0x0000011c))
++
++
++#define VMAC_TDMASTATE0(X) (*(volatile unsigned int *)(X + 0x00000120))
++#define VMAC_TDMASTATE1(X) (*(volatile unsigned int *)(X + 0x00000124))
++#define VMAC_TDMASTATE2(X) (*(volatile unsigned int *)(X + 0x00000128))
++#define VMAC_TDMASTATE3(X) (*(volatile unsigned int *)(X + 0x0000012C))
++#define VMAC_TDMASTATE4(X) (*(volatile unsigned int *)(X + 0x00000130))
++#define VMAC_TDMASTATE5(X) (*(volatile unsigned int *)(X + 0x00000134))
++#define VMAC_TDMASTATE6(X) (*(volatile unsigned int *)(X + 0x00000138))
++#define VMAC_TDMASTATE7(X) (*(volatile unsigned int *)(X + 0x0000013C))
++#define VMAC_TXPADDCNT(X) (*(volatile unsigned int *)(X + 0x00000140))
++#define VMAC_TXPADDSTART(X) (*(volatile unsigned int *)(X + 0x00000144))
++#define VMAC_TXPADDEND(X) (*(volatile unsigned int *)(X + 0x00000148))
++#define VMAC_TXQFLUSH(X) (*(volatile unsigned int *)(X + 0x0000014C))
++
++#define VMAC_RCRPTR(X) (*(volatile unsigned int *)(X + 0x00000200))
++#define VMAC_RCRSIZE(X) (*(volatile unsigned int *)(X + 0x00000204))
++#define VMAC_RCRINTTHRESH(X) (*(volatile unsigned int *)(X + 0x00000208))
++#define VMAC_RCRTOTENT(X) (*(volatile unsigned int *)(X + 0x0000020C))
++#define VMAC_RCRFREEENT(X) (*(volatile unsigned int *)(X + 0x00000210))
++#define VMAC_RCRPENDENT(X) (*(volatile unsigned int *)(X + 0x00000214))
++#define VMAC_RCRENTINC(X) (*(volatile unsigned int *)(X + 0x00000218))
++#define VMAC_RXISRPACE(X) (*(volatile unsigned int *)(X + 0x0000021c))
++
++#define VMAC_RDMASTATE0(X) (*(volatile unsigned int *)(X + 0x00000220))
++#define VMAC_RDMASTATE1(X) (*(volatile unsigned int *)(X + 0x00000224))
++#define VMAC_RDMASTATE2(X) (*(volatile unsigned int *)(X + 0x00000228))
++#define VMAC_RDMASTATE3(X) (*(volatile unsigned int *)(X + 0x0000022C))
++#define VMAC_RDMASTATE4(X) (*(volatile unsigned int *)(X + 0x00000230))
++#define VMAC_RDMASTATE5(X) (*(volatile unsigned int *)(X + 0x00000234))
++#define VMAC_RDMASTATE6(X) (*(volatile unsigned int *)(X + 0x00000238))
++#define VMAC_RDMASTATE7(X) (*(volatile unsigned int *)(X + 0x0000023C))
++#define VMAC_FBLADDCNT(X) (*(volatile unsigned int *)(X + 0x00000240))
++#define VMAC_FBLADDSTART(X) (*(volatile unsigned int *)(X + 0x00000244))
++#define VMAC_FBLADDEND(X) (*(volatile unsigned int *)(X + 0x00000248))
++#define VMAC_RXONOFF(X) (*(volatile unsigned int *)(X + 0x0000024C))
++
++#define VMAC_FBL0NEXTD(X) (*(volatile unsigned int *)(X + 0x00000280))
++#define VMAC_FBL0LASTD(X) (*(volatile unsigned int *)(X + 0x00000284))
++#define VMAC_FBL0COUNTD(X) (*(volatile unsigned int *)(X + 0x00000288))
++#define VMAC_FBL0BUFSIZE(X) (*(volatile unsigned int *)(X + 0x0000028C))
++
++#define VMAC_MACCONTROL(X) (*(volatile unsigned int *)(X + 0x00000300))
++#define VMAC_MACSTATUS(X) (*(volatile unsigned int *)(X + 0x00000304))
++#define VMAC_MACADDRHI(X) (*(volatile unsigned int *)(X + 0x00000308))
++#define VMAC_MACADDRLO(X) (*(volatile unsigned int *)(X + 0x0000030C))
++#define VMAC_MACHASH1(X) (*(volatile unsigned int *)(X + 0x00000310))
++#define VMAC_MACHASH2(X) (*(volatile unsigned int *)(X + 0x00000314))
++
++#define VMAC_WRAPCLK(X) (*(volatile unsigned int *)(X + 0x00000340))
++#define VMAC_BOFTEST(X) (*(volatile unsigned int *)(X + 0x00000344))
++#define VMAC_PACTEST(X) (*(volatile unsigned int *)(X + 0x00000348))
++#define VMAC_PAUSEOP(X) (*(volatile unsigned int *)(X + 0x0000034C))
++
++#define VMAC_MDIOCONTROL(X) (*(volatile unsigned int *)(X + 0x00000380))
++#define VMAC_MDIOUSERACCESS(X) (*(volatile unsigned int *)(X +0x00000384))
++#define VMAC_MDIOACK(X) (*(volatile unsigned int *)(X + 0x00000388))
++#define VMAC_MDIOLINK(X) (*(volatile unsigned int *)(X + 0x0000038C))
++#define VMAC_MDIOMACPHY(X) (*(volatile unsigned int *)(X + 0x00000390))
++
++#define VMAC_STATS_BASE(X) (X + 0x00000400)
++
++#endif __AVALANCHE_REGS_H
++
++
++
++
++
++
+diff -urN linux.old/include/asm-mips/ar7/avalanche_types.h linux.dev/include/asm-mips/ar7/avalanche_types.h
+--- linux.old/include/asm-mips/ar7/avalanche_types.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/avalanche_types.h 2005-11-10 01:10:46.071588750 +0100
+@@ -0,0 +1,126 @@
++/*------------------------------------------------------------------------------------------*\
++\*------------------------------------------------------------------------------------------*/
++#ifndef _avalanche_types_h_
++#define _avalanche_types_h_
++
++/*--- #include <asm/avalanche/generic/hal_modules/haltypes.h> ---*/
++#ifndef TRUE
++#define TRUE 1
++#endif
++#ifndef FALSE
++#define FALSE 0
++#endif
++#ifndef NULL
++#define NULL (void *)0
++#endif
++
++/*------------------------------------------------------------------------------------------*\
++ * Typen für Texas GPL Module
++\*------------------------------------------------------------------------------------------*/
++#ifndef __UINT8_T__
++typedef unsigned char UINT8;
++#define __UINT8_T__
++#endif
++
++#ifndef __UCHAR_T__
++typedef unsigned char UCHAR;
++#define __UCHAR_T__
++#endif
++
++#ifndef __INT8_T__
++typedef signed char INT8;
++#define __INT8_T__
++#endif
++
++#ifndef __UINT16_T__
++typedef unsigned short UINT16;
++#define __UINT16_T__
++#endif
++
++#ifndef __USHORT_T__
++typedef unsigned short USHORT;
++#define __USHORT_T__
++#endif
++
++#ifndef __INT16_T__
++typedef signed short INT16;
++#define __INT16_T__
++#endif
++
++#ifndef __UINT32_T__
++typedef unsigned int UINT32;
++#define __UINT32_T__
++#endif
++
++#ifndef __UINT_T__
++typedef unsigned int UINT;
++#define __UINT_T__
++#endif
++
++#ifndef __INT32_T__
++typedef signed int INT32;
++#define __INT32_T__
++#endif
++
++#ifndef __ULONG_T__
++typedef unsigned long ULONG;
++#define __ULONG_T__
++#endif
++
++#ifndef __BOOL_T__
++typedef int BOOL;
++#define __BOOL_T__
++#endif
++
++#ifndef __STATUS_T__
++typedef int STATUS;
++#define __STATUS_T__
++#endif
++
++/*------------------------------------------------------------------------------------------*\
++\*------------------------------------------------------------------------------------------*/
++typedef void (*p_vlynq_intr_cntrl_isr_t)(void *,void *,void *);
++typedef INT32 (*p_vlynq_interrupt_vector_set_t)(void *, UINT32, UINT32, INT32, INT32, INT32);
++typedef INT32 (*p_vlynq_interrupt_vector_cntl_t)(void *, UINT32, INT32, UINT32);
++typedef UINT32 (*p_vlynq_interrupt_get_count_t)(void *, UINT32);
++typedef INT32 (*p_vlynq_install_isr_t)(void *, UINT32, p_vlynq_intr_cntrl_isr_t, void *, void *, void *);
++typedef INT32 (*p_vlynq_uninstall_isr_t)(void *, UINT32, void *, void *, void *);
++typedef void (*p_vlynq_root_isr_t)(void *);
++typedef void (*p_vlynq_delay_t)(UINT32);
++typedef INT32 (*p_vlynq_interrupt_vector_map_t)(void *, INT32, UINT32, UINT32);
++typedef INT32 (*p_vlynq_interrupt_set_polarity_t)(void *, INT32, UINT32, INT32);
++typedef INT32 (*p_vlynq_interrupt_get_polarity_t)(void *, INT32, UINT32);
++typedef INT32 (*p_vlynq_interrupt_set_type_t)(void *, INT32, UINT32, INT32);
++typedef INT32 (*p_vlynq_interrupt_get_type_t)(void *, INT32, UINT32);
++typedef INT32 (*p_vlynq_interrupt_enable_t)(void *, INT32, UINT32);
++typedef INT32 (*p_vlynq_interrupt_disable_t)(void *, INT32, UINT32);
++
++/*------------------------------------------------------------------------------------------*\
++\*------------------------------------------------------------------------------------------*/
++extern p_vlynq_interrupt_vector_set_t p_vlynq_interrupt_vector_set;
++extern p_vlynq_interrupt_vector_cntl_t p_vlynq_interrupt_vector_cntl;
++extern p_vlynq_interrupt_get_count_t p_vlynq_interrupt_get_count;
++extern p_vlynq_install_isr_t p_vlynq_install_isr;
++extern p_vlynq_uninstall_isr_t p_vlynq_uninstall_isr;
++extern p_vlynq_root_isr_t p_vlynq_root_isr;
++extern p_vlynq_delay_t p_vlynq_delay;
++extern p_vlynq_interrupt_vector_map_t p_vlynq_interrupt_vector_map;
++extern p_vlynq_interrupt_set_polarity_t p_vlynq_interrupt_set_polarity;
++extern p_vlynq_interrupt_get_polarity_t p_vlynq_interrupt_get_polarity;
++extern p_vlynq_interrupt_set_type_t p_vlynq_interrupt_set_type;
++extern p_vlynq_interrupt_get_type_t p_vlynq_interrupt_get_type;
++extern p_vlynq_interrupt_enable_t p_vlynq_interrupt_enable;
++extern p_vlynq_interrupt_disable_t p_vlynq_interrupt_disable;
++extern void *p_vlynqDevice0;
++extern void *p_vlynqDevice1;
++
++/*------------------------------------------------------------------------------------------*\
++\*------------------------------------------------------------------------------------------*/
++enum _avalanche_need_ {
++ avalanche_need_vlynq,
++ avalanche_need_auto_mdix
++};
++
++int avalanche_need(enum _avalanche_need_);
++
++#endif /*--- #ifndef _avalanche_types_h_ ---*/
+diff -urN linux.old/include/asm-mips/ar7/if_port.h linux.dev/include/asm-mips/ar7/if_port.h
+--- linux.old/include/asm-mips/ar7/if_port.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/if_port.h 2005-11-10 01:10:46.071588750 +0100
+@@ -0,0 +1,26 @@
++/*******************************************************************************
++ * FILE PURPOSE: Interface port id Header file
++ *******************************************************************************
++ * FILE NAME: if_port.h
++ *
++ * DESCRIPTION: Header file carrying information about port ids of interfaces
++ *
++ *
++ * (C) Copyright 2003, Texas Instruments, Inc
++ ******************************************************************************/
++#ifndef _IF_PORT_H_
++#define _IF_PORT_H_
++
++#define AVALANCHE_CPMAC_LOW_PORT_ID 0
++#define AVALANCHE_CPMAC_HIGH_PORT_ID 1
++#define AVALANCHE_USB_PORT_ID 2
++#define AVALANCHE_WLAN_PORT_ID 3
++
++
++#define AVALANCHE_MARVELL_BASE_PORT_ID 4
++
++/* The marvell ports occupy port ids from 4 to 8 */
++/* so the next port id number should start at 9 */
++
++
++#endif /* _IF_PORT_H_ */
+diff -urN linux.old/include/asm-mips/ar7/sangam.h linux.dev/include/asm-mips/ar7/sangam.h
+--- linux.old/include/asm-mips/ar7/sangam.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/sangam.h 2005-11-10 01:10:46.071588750 +0100
+@@ -0,0 +1,180 @@
++#ifndef _SANGAM_H_
++#define _SANGAM_H_
++
++#include <linux/config.h>
++#include <asm/addrspace.h>
++
++/*----------------------------------------------------
++ * Sangam's Module Base Addresses
++ *--------------------------------------------------*/
++#define AVALANCHE_ADSL_SUB_SYS_MEM_BASE (KSEG1ADDR(0x01000000)) /* AVALANCHE ADSL Mem Base */
++#define AVALANCHE_BROADBAND_INTERFACE__BASE (KSEG1ADDR(0x02000000)) /* AVALANCHE BBIF */
++#define AVALANCHE_ATM_SAR_BASE (KSEG1ADDR(0x03000000)) /* AVALANCHE ATM SAR */
++#define AVALANCHE_USB_SLAVE_BASE (KSEG1ADDR(0x03400000)) /* AVALANCHE USB SLAVE */
++#define AVALANCHE_LOW_VLYNQ_MEM_MAP_BASE (KSEG1ADDR(0x04000000)) /* AVALANCHE VLYNQ 0 Mem map */
++#define AVALANCHE_LOW_CPMAC_BASE (KSEG1ADDR(0x08610000)) /* AVALANCHE CPMAC 0 */
++#define AVALANCHE_EMIF_CONTROL_BASE (KSEG1ADDR(0x08610800)) /* AVALANCHE EMIF */
++#define AVALANCHE_GPIO_BASE (KSEG1ADDR(0x08610900)) /* AVALANCHE GPIO */
++#define AVALANCHE_CLOCK_CONTROL_BASE (KSEG1ADDR(0x08610A00)) /* AVALANCHE Clock Control */
++#define AVALANCHE_WATCHDOG_TIMER_BASE (KSEG1ADDR(0x08610B00)) /* AVALANCHE Watch Dog Timer */
++#define AVALANCHE_TIMER0_BASE (KSEG1ADDR(0x08610C00)) /* AVALANCHE Timer 1 */
++#define AVALANCHE_TIMER1_BASE (KSEG1ADDR(0x08610D00)) /* AVALANCHE Timer 2 */
++#define AVALANCHE_UART0_REGS_BASE (KSEG1ADDR(0x08610E00)) /* AVALANCHE UART 0 */
++#define AVALANCHE_UART1_REGS_BASE (KSEG1ADDR(0x08610F00)) /* AVALANCHE UART 0 */
++#define AVALANCHE_I2C_BASE (KSEG1ADDR(0x08611000)) /* AVALANCHE I2C */
++#define AVALANCHE_USB_SLAVE_CONTROL_BASE (KSEG1ADDR(0x08611200)) /* AVALANCHE USB DMA */
++#define AVALANCHE_MCDMA0_CTRL_BASE (KSEG1ADDR(0x08611400)) /* AVALANCHE MC DMA 0 (channels 0-3) */
++#define AVALANCHE_RESET_CONTROL_BASE (KSEG1ADDR(0x08611600)) /* AVALANCHE Reset Control */
++#define AVALANCHE_BIST_CONTROL_BASE (KSEG1ADDR(0x08611700)) /* AVALANCHE BIST Control */
++#define AVALANCHE_LOW_VLYNQ_CONTROL_BASE (KSEG1ADDR(0x08611800)) /* AVALANCHE VLYNQ0 Control */
++#define AVALANCHE_DEVICE_CONFIG_LATCH_BASE (KSEG1ADDR(0x08611A00)) /* AVALANCHE Device Config Latch */
++#define AVALANCHE_HIGH_VLYNQ_CONTROL_BASE (KSEG1ADDR(0x08611C00)) /* AVALANCHE VLYNQ1 Control */
++#define AVALANCHE_MDIO_BASE (KSEG1ADDR(0x08611E00)) /* AVALANCHE MDIO */
++#define AVALANCHE_FSER_BASE (KSEG1ADDR(0x08612000)) /* AVALANCHE FSER base */
++#define AVALANCHE_INTC_BASE (KSEG1ADDR(0x08612400)) /* AVALANCHE INTC */
++#define AVALANCHE_HIGH_CPMAC_BASE (KSEG1ADDR(0x08612800)) /* AVALANCHE CPMAC 1 */
++#define AVALANCHE_HIGH_VLYNQ_MEM_MAP_BASE (KSEG1ADDR(0x0C000000)) /* AVALANCHE VLYNQ 1 Mem map */
++
++#define AVALANCHE_SDRAM_BASE 0x14000000UL
++
++
++/*----------------------------------------------------
++ * Sangam Interrupt Map (Primary Interrupts)
++ *--------------------------------------------------*/
++
++#define AVALANCHE_UNIFIED_SECONDARY_INT 0
++#define AVALANCHE_EXT_INT_0 1
++#define AVALANCHE_EXT_INT_1 2
++/* Line# 3 to 4 are reserved */
++#define AVALANCHE_TIMER_0_INT 5
++#define AVALANCHE_TIMER_1_INT 6
++#define AVALANCHE_UART0_INT 7
++#define AVALANCHE_UART1_INT 8
++#define AVALANCHE_DMA_INT0 9
++#define AVALANCHE_DMA_INT1 10
++/* Line# 11 to 14 are reserved */
++#define AVALANCHE_ATM_SAR_INT 15
++/* Line# 16 to 18 are reserved */
++#define AVALANCHE_LOW_CPMAC_INT 19
++/* Line# 20 is reserved */
++#define AVALANCHE_LOW_VLYNQ_INT 21
++#define AVALANCHE_CODEC_WAKEUP_INT 22
++/* Line# 23 is reserved */
++#define AVALANCHE_USB_SLAVE_INT 24
++#define AVALANCHE_HIGH_VLYNQ_INT 25
++/* Line# 26 to 27 are reserved */
++#define AVALANCHE_UNIFIED_PHY_INT 28
++#define AVALANCHE_I2C_INT 29
++#define AVALANCHE_DMA_INT2 30
++#define AVALANCHE_DMA_INT3 31
++/* Line# 32 is reserved */
++#define AVALANCHE_HIGH_CPMAC_INT 33
++/* Line# 34 to 36 is reserved */
++#define AVALANCHE_VDMA_VT_RX_INT 37
++#define AVALANCHE_VDMA_VT_TX_INT 38
++#define AVALANCHE_ADSL_SUB_SYSTEM_INT 39
++
++
++#define AVALANCHE_EMIF_INT 47
++
++
++
++/*-----------------------------------------------------------
++ * Sangam's Reset Bits
++ *---------------------------------------------------------*/
++
++#define AVALANCHE_UART0_RESET_BIT 0
++#define AVALANCHE_UART1_RESET_BIT 1
++#define AVALANCHE_I2C_RESET_BIT 2
++#define AVALANCHE_TIMER0_RESET_BIT 3
++#define AVALANCHE_TIMER1_RESET_BIT 4
++/* Reset bit 5 is reserved. */
++#define AVALANCHE_GPIO_RESET_BIT 6
++#define AVALANCHE_ADSL_SUB_SYS_RESET_BIT 7
++#define AVALANCHE_USB_SLAVE_RESET_BIT 8
++#define AVALANCHE_ATM_SAR_RESET_BIT 9
++/* Reset bit 10 is reserved. */
++#define AVALANCHE_VDMA_VT_RESET_BIT 11
++#define AVALANCHE_FSER_RESET_BIT 12
++/* Reset bit 13 to 15 are reserved */
++#define AVALANCHE_HIGH_VLYNQ_RESET_BIT 16
++#define AVALANCHE_LOW_CPMAC_RESET_BIT 17
++#define AVALANCHE_MCDMA_RESET_BIT 18
++#define AVALANCHE_BIST_RESET_BIT 19
++#define AVALANCHE_LOW_VLYNQ_RESET_BIT 20
++#define AVALANCHE_HIGH_CPMAC_RESET_BIT 21
++#define AVALANCHE_MDIO_RESET_BIT 22
++#define AVALANCHE_ADSL_SUB_SYS_DSP_RESET_BIT 23
++/* Reset bit 24 to 25 are reserved */
++#define AVALANCHE_LOW_EPHY_RESET_BIT 26
++/* Reset bit 27 to 31 are reserved */
++
++
++#define AVALANCHE_POWER_MODULE_USBSP 0
++#define AVALANCHE_POWER_MODULE_WDTP 1
++#define AVALANCHE_POWER_MODULE_UT0P 2
++#define AVALANCHE_POWER_MODULE_UT1P 3
++#define AVALANCHE_POWER_MODULE_IICP 4
++#define AVALANCHE_POWER_MODULE_VDMAP 5
++#define AVALANCHE_POWER_MODULE_GPIOP 6
++#define AVALANCHE_POWER_MODULE_VLYNQ1P 7
++#define AVALANCHE_POWER_MODULE_SARP 8
++#define AVALANCHE_POWER_MODULE_ADSLP 9
++#define AVALANCHE_POWER_MODULE_EMIFP 10
++#define AVALANCHE_POWER_MODULE_ADSPP 12
++#define AVALANCHE_POWER_MODULE_RAMP 13
++#define AVALANCHE_POWER_MODULE_ROMP 14
++#define AVALANCHE_POWER_MODULE_DMAP 15
++#define AVALANCHE_POWER_MODULE_BISTP 16
++#define AVALANCHE_POWER_MODULE_TIMER0P 18
++#define AVALANCHE_POWER_MODULE_TIMER1P 19
++#define AVALANCHE_POWER_MODULE_EMAC0P 20
++#define AVALANCHE_POWER_MODULE_EMAC1P 22
++#define AVALANCHE_POWER_MODULE_EPHYP 24
++#define AVALANCHE_POWER_MODULE_VLYNQ0P 27
++
++
++
++
++
++/*
++ * Sangam board vectors
++ */
++
++#define AVALANCHE_VECS (KSEG1ADDR(AVALANCHE_SDRAM_BASE))
++#define AVALANCHE_VECS_KSEG0 (KSEG0ADDR(AVALANCHE_SDRAM_BASE))
++
++/*-----------------------------------------------------------------------------
++ * Sangam's system register.
++ *
++ *---------------------------------------------------------------------------*/
++#define AVALANCHE_DCL_BOOTCR (KSEG1ADDR(0x08611A00))
++#define AVALANCHE_EMIF_SDRAM_CFG (AVALANCHE_EMIF_CONTROL_BASE + 0x8)
++#define AVALANCHE_RST_CTRL_PRCR (KSEG1ADDR(0x08611600))
++#define AVALANCHE_RST_CTRL_SWRCR (KSEG1ADDR(0x08611604))
++#define AVALANCHE_RST_CTRL_RSR (KSEG1ADDR(0x08611600))
++
++#define AVALANCHE_POWER_CTRL_PDCR (KSEG1ADDR(0x08610A00))
++#define AVALANCHE_WAKEUP_CTRL_WKCR (KSEG1ADDR(0x08610A0C))
++
++#define AVALANCHE_GPIO_DATA_IN (AVALANCHE_GPIO_BASE + 0x0)
++#define AVALANCHE_GPIO_DATA_OUT (AVALANCHE_GPIO_BASE + 0x4)
++#define AVALANCHE_GPIO_DIR (AVALANCHE_GPIO_BASE + 0x8)
++#define AVALANCHE_GPIO_ENBL (AVALANCHE_GPIO_BASE + 0xC)
++#define AVALANCHE_CVR (AVALANCHE_GPIO_BASE + 0x14)
++
++/*
++ * Yamon Prom print address.
++ */
++#define AVALANCHE_YAMON_FUNCTION_BASE (KSEG1ADDR(0x10000500))
++#define AVALANCHE_YAMON_PROM_PRINT_COUNT_ADDR (AVALANCHE_YAMON_FUNCTION_BASE + 0x4) /* print_count function */
++#define AVALANCHE_YAMON_PROM_PRINT_ADDR (AVALANCHE_YAMON_FUNCTION_BASE + 0x34)
++
++#define AVALANCHE_BASE_BAUD ( 3686400 / 16 )
++
++#define AVALANCHE_GPIO_PIN_COUNT 32
++#define AVALANCHE_GPIO_OFF_MAP {0xF34FFFC0}
++
++#include "sangam_boards.h"
++
++#endif /*_SANGAM_H_ */
+diff -urN linux.old/include/asm-mips/ar7/sangam_boards.h linux.dev/include/asm-mips/ar7/sangam_boards.h
+--- linux.old/include/asm-mips/ar7/sangam_boards.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/sangam_boards.h 2005-11-10 01:10:46.071588750 +0100
+@@ -0,0 +1,77 @@
++#ifndef _SANGAM_BOARDS_H
++#define _SANGAM_BOARDS_H
++
++// Let us define board specific information here.
++
++
++#if defined(CONFIG_AR7DB)
++
++#define AFECLK_FREQ 35328000
++#define REFCLK_FREQ 25000000
++#define OSC3_FREQ 24000000
++#define AVALANCHE_LOW_CPMAC_PHY_MASK 0x80000000
++#define AVALANCHE_HIGH_CPMAC_PHY_MASK 0x55555555
++#define AVALANCHE_LOW_CPMAC_MDIX_MASK 0x80000000
++
++#endif
++
++
++#if defined(CONFIG_AR7RD)
++#define AFECLK_FREQ 35328000
++#define REFCLK_FREQ 25000000
++#define OSC3_FREQ 24000000
++#define AVALANCHE_LOW_CPMAC_PHY_MASK 0x80000000
++#define AVALANCHE_HIGH_CPMAC_PHY_MASK 0x2
++#define AVALANCHE_LOW_CPMAC_MDIX_MASK 0x80000000
++#endif
++
++
++#if defined(CONFIG_AR7WI)
++#define AFECLK_FREQ 35328000
++#define REFCLK_FREQ 25000000
++#define OSC3_FREQ 24000000
++#define AVALANCHE_LOW_CPMAC_PHY_MASK 0x80000000
++#define AVALANCHE_HIGH_CPMAC_PHY_MASK 0x2
++#define AVALANCHE_LOW_CPMAC_MDIX_MASK 0x80000000
++#endif
++
++
++#if defined(CONFIG_AR7V)
++#define AFECLK_FREQ 35328000
++#define REFCLK_FREQ 25000000
++#define OSC3_FREQ 24000000
++#define AVALANCHE_LOW_CPMAC_PHY_MASK 0x80000000
++#define AVALANCHE_HIGH_CPMAC_PHY_MASK 0x2
++#define AVALANCHE_LOW_CPMAC_MDIX_MASK 0x80000000
++#endif
++
++
++#if defined(CONFIG_AR7WRD)
++#define AFECLK_FREQ 35328000
++#define REFCLK_FREQ 25000000
++#define OSC3_FREQ 24000000
++#define AVALANCHE_LOW_CPMAC_PHY_MASK 0x80000000
++#define AVALANCHE_HIGH_CPMAC_PHY_MASK 0x00010000
++#define AVALANCHE_LOW_CPMAC_MDIX_MASK 0x80000000
++#endif
++
++
++#if defined(CONFIG_AR7VWI)
++#define AFECLK_FREQ 35328000
++#define REFCLK_FREQ 25000000
++#define OSC3_FREQ 24000000
++#define AVALANCHE_LOW_CPMAC_PHY_MASK 0x80000000
++#define AVALANCHE_HIGH_CPMAC_PHY_MASK 0x00010000
++#define AVALANCHE_LOW_CPMAC_MDIX_MASK 0x80000000
++#endif
++
++
++#if defined CONFIG_SEAD2
++#define AVALANCHE_LOW_CPMAC_PHY_MASK 0xAAAAAAAA
++#define AVALANCHE_HIGH_CPMAC_PHY_MASK 0x55555555
++#define AVALANCHE_LOW_CPMAC_MDIX_MASK 0
++#include <asm/mips-boards/sead.h>
++#endif
++
++
++#endif
+diff -urN linux.old/include/asm-mips/ar7/tnetd73xx.h linux.dev/include/asm-mips/ar7/tnetd73xx.h
+--- linux.old/include/asm-mips/ar7/tnetd73xx.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/tnetd73xx.h 2005-11-10 01:10:46.075589000 +0100
+@@ -0,0 +1,338 @@
++/******************************************************************************
++ * FILE PURPOSE: TNETD73xx Common Header File
++ ******************************************************************************
++ * FILE NAME: tnetd73xx.h
++ *
++ * DESCRIPTION: shared typedef's, constants and API for TNETD73xx
++ *
++ * REVISION HISTORY:
++ * 27 Nov 02 - PSP TII
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++/*
++ *
++ *
++ * These are const, typedef, and api definitions for tnetd73xx.
++ *
++ * NOTES:
++ * 1. This file may be included into both C and Assembly files.
++ * - for .s files, please do #define _ASMLANGUAGE in your ASM file to
++ * avoid C data types (typedefs) below;
++ * - for .c files, you don't have to do anything special.
++ *
++ * 2. This file has a number of sections for each SOC subsystem. When adding
++ * a new constant, find the subsystem you are working on and follow the
++ * name pattern. If you are adding another typedef for your interface, please,
++ * place it with other typedefs and function prototypes.
++ *
++ * 3. Please, DO NOT add any macros or types that are local to a subsystem to avoid
++ * cluttering. Include such items directly into the module's .c file or have a
++ * local .h file to pass data between smaller modules. This file defines only
++ * shared items.
++ */
++
++#ifndef __TNETD73XX_H__
++#define __TNETD73XX_H__
++
++#ifndef _ASMLANGUAGE /* This part not for assembly language */
++
++extern unsigned int tnetd73xx_mips_freq;
++extern unsigned int tnetd73xx_vbus_freq;
++
++#include "tnetd73xx_err.h"
++
++#endif /* _ASMLANGUAGE */
++
++
++/*******************************************************************************************
++* Emerald core specific
++******************************************************************************************** */
++
++#ifdef BIG_ENDIAN
++#elif defined(LITTLE_ENDIAN)
++#else
++#error Need to define endianism
++#endif
++
++#ifndef KSEG_MSK
++#define KSEG_MSK 0xE0000000 /* Most significant 3 bits denote kseg choice */
++#endif
++
++#ifndef KSEG_INV_MASK
++#define KSEG_INV_MASK 0x1FFFFFFF /* Inverted mask for kseg address */
++#endif
++
++#ifndef KSEG0_BASE
++#define KSEG0_BASE 0x80000000
++#endif
++
++#ifndef KSEG1_BASE
++#define KSEG1_BASE 0xA0000000
++#endif
++
++#ifndef KSEG0
++#define KSEG0(addr) (((__u32)(addr) & ~KSEG_MSK) | KSEG0_BASE)
++#endif
++
++#ifndef KSEG1
++#define KSEG1(addr) (((__u32)(addr) & ~KSEG_MSK) | KSEG1_BASE)
++#endif
++
++#ifndef KUSEG
++#define KUSEG(addr) ((__u32)(addr) & ~KSEG_MSK)
++#endif
++
++#ifndef PHYS_ADDR
++#define PHYS_ADDR(addr) ((addr) & KSEG_INV_MASK)
++#endif
++
++#ifndef PHYS_TO_K0
++#define PHYS_TO_K0(addr) (PHYS_ADDR(addr)|KSEG0_BASE)
++#endif
++
++#ifndef PHYS_TO_K1
++#define PHYS_TO_K1(addr) (PHYS_ADDR(addr)|KSEG1_BASE)
++#endif
++
++#ifndef REG8_ADDR
++#define REG8_ADDR(addr) (volatile __u8 *)(PHYS_TO_K1(addr))
++#define REG8_DATA(addr) (*(volatile __u8 *)(PHYS_TO_K1(addr)))
++#define REG8_WRITE(addr, data) REG8_DATA(addr) = data;
++#define REG8_READ(addr, data) data = (__u8) REG8_DATA(addr);
++#endif
++
++#ifndef REG16_ADDR
++#define REG16_ADDR(addr) (volatile __u16 *)(PHYS_TO_K1(addr))
++#define REG16_DATA(addr) (*(volatile __u16 *)(PHYS_TO_K1(addr)))
++#define REG16_WRITE(addr, data) REG16_DATA(addr) = data;
++#define REG16_READ(addr, data) data = (__u16) REG16_DATA(addr);
++#endif
++
++#ifndef REG32_ADDR
++#define REG32_ADDR(addr) (volatile __u32 *)(PHYS_TO_K1(addr))
++#define REG32_DATA(addr) (*(volatile __u32 *)(PHYS_TO_K1(addr)))
++#define REG32_WRITE(addr, data) REG32_DATA(addr) = data;
++#define REG32_READ(addr, data) data = (__u32) REG32_DATA(addr);
++#endif
++
++#ifdef _LINK_KSEG0_ /* Application is linked into KSEG0 space */
++#define VIRT_ADDR(addr) PHYS_TO_K0(PHYS_ADDR(addr))
++#endif
++
++#ifdef _LINK_KSEG1_ /* Application is linked into KSEG1 space */
++#define VIRT_ADDR(addr) PHYS_TO_K1(PHYS_ADDR(addr))
++#endif
++
++#if !defined(_LINK_KSEG0_) && !defined(_LINK_KSEG1_)
++#error You must define _LINK_KSEG0_ or _LINK_KSEG1_ to compile the code.
++#endif
++
++/* TNETD73XX chip definations */
++
++#define FREQ_1MHZ 1000000
++#define TNETD73XX_MIPS_FREQ tnetd73xx_mips_freq /* CPU clock frequency */
++#define TNETD73XX_VBUS_FREQ tnetd73xx_vbus_freq /* originally (TNETD73XX_MIPS_FREQ/2) */
++
++#ifdef AR7SEAD2
++#define TNETD73XX_MIPS_FREQ_DEFAULT 25000000 /* 25 Mhz for sead2 board crystal */
++#else
++#define TNETD73XX_MIPS_FREQ_DEFAULT 125000000 /* 125 Mhz */
++#endif
++#define TNETD73XX_VBUS_FREQ_DEFAULT (TNETD73XX_MIPS_FREQ_DEFAULT / 2) /* Sync mode */
++
++
++
++/* Module base addresses */
++#define TNETD73XX_ADSLSS_BASE PHYS_TO_K1(0x01000000) /* ADSLSS Module */
++#define TNETD73XX_BBIF_CTRL_BASE PHYS_TO_K1(0x02000000) /* BBIF Control */
++#define TNETD73XX_ATMSAR_BASE PHYS_TO_K1(0x03000000) /* ATM SAR */
++#define TNETD73XX_USB_BASE PHYS_TO_K1(0x03400000) /* USB Module */
++#define TNETD73XX_VLYNQ0_BASE PHYS_TO_K1(0x04000000) /* VLYNQ0 Module */
++#define TNETD73xx_EMAC0_BASE PHYS_TO_K1(0x08610000) /* EMAC0 Module*/
++#define TNETD73XX_EMIF_BASE PHYS_TO_K1(0x08610800) /* EMIF Module */
++#define TNETD73XX_GPIO_BASE PHYS_TO_K1(0x08610900) /* GPIO control */
++#define TNETD73XX_CLOCK_CTRL_BASE PHYS_TO_K1(0x08610A00) /* Clock Control */
++#define TNETD73XX_WDTIMER_BASE PHYS_TO_K1(0x08610B00) /* WDTIMER Module */
++#define TNETD73XX_TIMER0_BASE PHYS_TO_K1(0x08610C00) /* TIMER0 Module */
++#define TNETD73XX_TIMER1_BASE PHYS_TO_K1(0x08610D00) /* TIMER1 Module */
++#define TNETD73XX_UARTA_BASE PHYS_TO_K1(0x08610E00) /* UART A */
++#define TNETD73XX_UARTB_BASE PHYS_TO_K1(0x08610F00) /* UART B */
++#define TNETD73XX_I2C_BASE PHYS_TO_K1(0x08611000) /* I2C Module */
++#define TNETD73XX_USB_DMA_BASE PHYS_TO_K1(0x08611200) /* USB Module */
++#define TNETD73XX_MCDMA_BASE PHYS_TO_K1(0x08611400) /* MC-DMA */
++#define TNETD73xx_VDMAVT_BASE PHYS_TO_K1(0x08611500) /* VDMAVT Control */
++#define TNETD73XX_RST_CTRL_BASE PHYS_TO_K1(0x08611600) /* Reset Control */
++#define TNETD73xx_BIST_CTRL_BASE PHYS_TO_K1(0x08611700) /* BIST Control */
++#define TNETD73xx_VLYNQ0_CTRL_BASE PHYS_TO_K1(0x08611800) /* VLYNQ0 Control */
++#define TNETD73XX_DCL_BASE PHYS_TO_K1(0x08611A00) /* Device Configuration Latch */
++#define TNETD73xx_VLYNQ1_CTRL_BASE PHYS_TO_K1(0x08611C00) /* VLYNQ1 Control */
++#define TNETD73xx_MDIO_BASE PHYS_TO_K1(0x08611E00) /* MDIO Control */
++#define TNETD73XX_FSER_BASE PHYS_TO_K1(0x08612000) /* FSER Control */
++#define TNETD73XX_INTC_BASE PHYS_TO_K1(0x08612400) /* Interrupt Controller */
++#define TNETD73xx_EMAC1_BASE PHYS_TO_K1(0x08612800) /* EMAC1 Module*/
++#define TNETD73XX_VLYNQ1_BASE PHYS_TO_K1(0x0C000000) /* VLYNQ1 Module */
++
++/* BBIF Registers */
++#define TNETD73XX_BBIF_ADSLADR (TNETD73XX_BBIF_CTRL_BASE + 0x0)
++
++/* Device Configuration Latch Registers */
++#define TNETD73XX_DCL_BOOTCR (TNETD73XX_DCL_BASE + 0x0)
++#define TNETD73XX_DCL_DPLLSELR (TNETD73XX_DCL_BASE + 0x10)
++#define TNETD73XX_DCL_SPEEDCTLR (TNETD73XX_DCL_BASE + 0x14)
++#define TNETD73XX_DCL_SPEEDPWDR (TNETD73XX_DCL_BASE + 0x18)
++#define TNETD73XX_DCL_SPEEDCAPR (TNETD73XX_DCL_BASE + 0x1C)
++
++/* GPIO Control */
++#define TNETD73XX_GPIODINR (TNETD73XX_GPIO_BASE + 0x0)
++#define TNETD73XX_GPIODOUTR (TNETD73XX_GPIO_BASE + 0x4)
++#define TNETD73XX_GPIOPDIRR (TNETD73XX_GPIO_BASE + 0x8)
++#define TNETD73XX_GPIOENR (TNETD73XX_GPIO_BASE + 0xC)
++#define TNETD73XX_CVR (TNETD73XX_GPIO_BASE + 0x14)
++#define TNETD73XX_DIDR1 (TNETD73XX_GPIO_BASE + 0x18)
++#define TNETD73XX_DIDR2 (TNETD73XX_GPIO_BASE + 0x1C)
++
++/* Reset Control */
++#define TNETD73XX_RST_CTRL_PRCR (TNETD73XX_RST_CTRL_BASE + 0x0)
++#define TNETD73XX_RST_CTRL_SWRCR (TNETD73XX_RST_CTRL_BASE + 0x4)
++#define TNETD73XX_RST_CTRL_RSR (TNETD73XX_RST_CTRL_BASE + 0x8)
++
++/* Power Control */
++#define TNETD73XX_POWER_CTRL_PDCR (TNETD73XX_CLOCK_CTRL_BASE + 0x0)
++#define TNETD73XX_POWER_CTRL_PCLKCR (TNETD73XX_CLOCK_CTRL_BASE + 0x4)
++#define TNETD73XX_POWER_CTRL_PDUCR (TNETD73XX_CLOCK_CTRL_BASE + 0x8)
++#define TNETD73XX_POWER_CTRL_WKCR (TNETD73XX_CLOCK_CTRL_BASE + 0xC)
++
++/* Clock Control */
++#define TNETD73XX_CLK_CTRL_SCLKCR (TNETD73XX_CLOCK_CTRL_BASE + 0x20)
++#define TNETD73XX_CLK_CTRL_SCLKPLLCR (TNETD73XX_CLOCK_CTRL_BASE + 0x30)
++#define TNETD73XX_CLK_CTRL_MCLKCR (TNETD73XX_CLOCK_CTRL_BASE + 0x40)
++#define TNETD73XX_CLK_CTRL_MCLKPLLCR (TNETD73XX_CLOCK_CTRL_BASE + 0x50)
++#define TNETD73XX_CLK_CTRL_UCLKCR (TNETD73XX_CLOCK_CTRL_BASE + 0x60)
++#define TNETD73XX_CLK_CTRL_UCLKPLLCR (TNETD73XX_CLOCK_CTRL_BASE + 0x70)
++#define TNETD73XX_CLK_CTRL_ACLKCR0 (TNETD73XX_CLOCK_CTRL_BASE + 0x80)
++#define TNETD73XX_CLK_CTRL_ACLKPLLCR0 (TNETD73XX_CLOCK_CTRL_BASE + 0x90)
++#define TNETD73XX_CLK_CTRL_ACLKCR1 (TNETD73XX_CLOCK_CTRL_BASE + 0xA0)
++#define TNETD73XX_CLK_CTRL_ACLKPLLCR1 (TNETD73XX_CLOCK_CTRL_BASE + 0xB0)
++
++/* EMIF control */
++#define TNETD73XX_EMIF_SDRAM_CFG ( TNETD73XX_EMIF_BASE + 0x08 )
++
++/* UART */
++#ifdef AR7SEAD2
++#define TNETD73XX_UART_FREQ 3686400
++#else
++#define TNETD73XX_UART_FREQ TNETD73XX_VBUS_FREQ
++#endif
++
++/* Interrupt Controller */
++
++/* Primary interrupts */
++#define TNETD73XX_INTC_UNIFIED_SECONDARY 0 /* Unified secondary interrupt */
++#define TNETD73XX_INTC_EXTERNAL0 1 /* External Interrupt Line 0 */
++#define TNETD73XX_INTC_EXTERNAL1 2 /* External Interrupt Line 1 */
++#define TNETD73XX_INTC_RESERVED3 3 /* Reserved */
++#define TNETD73XX_INTC_RESERVED4 4 /* Reserved */
++#define TNETD73XX_INTC_TIMER0 5 /* TIMER 0 int */
++#define TNETD73XX_INTC_TIMER1 6 /* TIMER 1 int */
++#define TNETD73XX_INTC_UART0 7 /* UART 0 int */
++#define TNETD73XX_INTC_UART1 8 /* UART 1 int */
++#define TNETD73XX_INTC_MCDMA0 9 /* MCDMA 0 int */
++#define TNETD73XX_INTC_MCDMA1 10 /* MCDMA 1 int */
++#define TNETD73XX_INTC_RESERVED11 11 /* Reserved */
++#define TNETD73XX_INTC_RESERVED12 12 /* Reserved */
++#define TNETD73XX_INTC_RESERVED13 13 /* Reserved */
++#define TNETD73XX_INTC_RESERVED14 14 /* Reserved */
++#define TNETD73XX_INTC_ATMSAR 15 /* ATM SAR int */
++#define TNETD73XX_INTC_RESERVED16 16 /* Reserved */
++#define TNETD73XX_INTC_RESERVED17 17 /* Reserved */
++#define TNETD73XX_INTC_RESERVED18 18 /* Reserved */
++#define TNETD73XX_INTC_EMAC0 19 /* EMAC 0 int */
++#define TNETD73XX_INTC_RESERVED20 20 /* Reserved */
++#define TNETD73XX_INTC_VLYNQ0 21 /* VLYNQ 0 int */
++#define TNETD73XX_INTC_CODEC 22 /* CODEC int */
++#define TNETD73XX_INTC_RESERVED23 23 /* Reserved */
++#define TNETD73XX_INTC_USBSLAVE 24 /* USB Slave int */
++#define TNETD73XX_INTC_VLYNQ1 25 /* VLYNQ 1 int */
++#define TNETD73XX_INTC_RESERVED26 26 /* Reserved */
++#define TNETD73XX_INTC_RESERVED27 27 /* Reserved */
++#define TNETD73XX_INTC_ETH_PHY 28 /* Ethernet PHY */
++#define TNETD73XX_INTC_I2C 29 /* I2C int */
++#define TNETD73XX_INTC_MCDMA2 30 /* MCDMA 2 int */
++#define TNETD73XX_INTC_MCDMA3 31 /* MCDMA 3 int */
++#define TNETD73XX_INTC_RESERVED32 32 /* Reserved */
++#define TNETD73XX_INTC_EMAC1 33 /* EMAC 1 int */
++#define TNETD73XX_INTC_RESERVED34 34 /* Reserved */
++#define TNETD73XX_INTC_RESERVED35 35 /* Reserved */
++#define TNETD73XX_INTC_RESERVED36 36 /* Reserved */
++#define TNETD73XX_INTC_VDMAVTRX 37 /* VDMAVTRX */
++#define TNETD73XX_INTC_VDMAVTTX 38 /* VDMAVTTX */
++#define TNETD73XX_INTC_ADSLSS 39 /* ADSLSS */
++
++/* Secondary interrupts */
++#define TNETD73XX_INTC_SEC0 40 /* Secondary */
++#define TNETD73XX_INTC_SEC1 41 /* Secondary */
++#define TNETD73XX_INTC_SEC2 42 /* Secondary */
++#define TNETD73XX_INTC_SEC3 43 /* Secondary */
++#define TNETD73XX_INTC_SEC4 44 /* Secondary */
++#define TNETD73XX_INTC_SEC5 45 /* Secondary */
++#define TNETD73XX_INTC_SEC6 46 /* Secondary */
++#define TNETD73XX_INTC_EMIF 47 /* EMIF */
++#define TNETD73XX_INTC_SEC8 48 /* Secondary */
++#define TNETD73XX_INTC_SEC9 49 /* Secondary */
++#define TNETD73XX_INTC_SEC10 50 /* Secondary */
++#define TNETD73XX_INTC_SEC11 51 /* Secondary */
++#define TNETD73XX_INTC_SEC12 52 /* Secondary */
++#define TNETD73XX_INTC_SEC13 53 /* Secondary */
++#define TNETD73XX_INTC_SEC14 54 /* Secondary */
++#define TNETD73XX_INTC_SEC15 55 /* Secondary */
++#define TNETD73XX_INTC_SEC16 56 /* Secondary */
++#define TNETD73XX_INTC_SEC17 57 /* Secondary */
++#define TNETD73XX_INTC_SEC18 58 /* Secondary */
++#define TNETD73XX_INTC_SEC19 59 /* Secondary */
++#define TNETD73XX_INTC_SEC20 60 /* Secondary */
++#define TNETD73XX_INTC_SEC21 61 /* Secondary */
++#define TNETD73XX_INTC_SEC22 62 /* Secondary */
++#define TNETD73XX_INTC_SEC23 63 /* Secondary */
++#define TNETD73XX_INTC_SEC24 64 /* Secondary */
++#define TNETD73XX_INTC_SEC25 65 /* Secondary */
++#define TNETD73XX_INTC_SEC26 66 /* Secondary */
++#define TNETD73XX_INTC_SEC27 67 /* Secondary */
++#define TNETD73XX_INTC_SEC28 68 /* Secondary */
++#define TNETD73XX_INTC_SEC29 69 /* Secondary */
++#define TNETD73XX_INTC_SEC30 70 /* Secondary */
++#define TNETD73XX_INTC_SEC31 71 /* Secondary */
++
++/* These ugly macros are to access the -1 registers, like config1 */
++#define MFC0_SEL1_OPCODE(dst, src)\
++ .word (0x40000000 | ((dst)<<16) | ((src)<<11) | 1);\
++ nop; \
++ nop; \
++ nop
++
++#define MTC0_SEL1_OPCODE(dst, src)\
++ .word (0x40800000 | ((dst)<<16) | ((src)<<11) | 1);\
++ nop; \
++ nop; \
++ nop
++
++
++/* Below are Jade core specific */
++#define CFG0_4K_IL_MASK 0x00380000
++#define CFG0_4K_IL_SHIFT 19
++#define CFG0_4K_IA_MASK 0x00070000
++#define CFG0_4K_IA_SHIFT 16
++#define CFG0_4K_IS_MASK 0x01c00000
++#define CFG0_4K_IS_SHIFT 22
++
++#define CFG0_4K_DL_MASK 0x00001c00
++#define CFG0_4K_DL_SHIFT 10
++#define CFG0_4K_DA_MASK 0x00000380
++#define CFG0_4K_DA_SHIFT 7
++#define CFG0_4K_DS_MASK 0x0000E000
++#define CFG0_4K_DS_SHIFT 13
++
++
++
++#endif /* __TNETD73XX_H_ */
+diff -urN linux.old/include/asm-mips/ar7/tnetd73xx_err.h linux.dev/include/asm-mips/ar7/tnetd73xx_err.h
+--- linux.old/include/asm-mips/ar7/tnetd73xx_err.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/tnetd73xx_err.h 2005-11-10 01:10:46.075589000 +0100
+@@ -0,0 +1,42 @@
++/******************************************************************************
++ * FILE PURPOSE: TNETD73xx Error Definations Header File
++ ******************************************************************************
++ * FILE NAME: tnetd73xx_err.h
++ *
++ * DESCRIPTION: Error definations for TNETD73XX
++ *
++ * REVISION HISTORY:
++ * 27 Nov 02 - PSP TII
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++
++#ifndef __TNETD73XX_ERR_H__
++#define __TNETD73XX_ERR_H__
++
++typedef enum TNETD73XX_ERR_t
++{
++ TNETD73XX_ERR_OK = 0, /* OK or SUCCESS */
++ TNETD73XX_ERR_ERROR = -1, /* Unspecified/Generic ERROR */
++
++ /* Pointers and args */
++ TNETD73XX_ERR_INVARG = -2, /* Invaild argument to the call */
++ TNETD73XX_ERR_NULLPTR = -3, /* NULL pointer */
++ TNETD73XX_ERR_BADPTR = -4, /* Bad (out of mem) pointer */
++
++ /* Memory issues */
++ TNETD73XX_ERR_ALLOC_FAIL = -10, /* allocation failed */
++ TNETD73XX_ERR_FREE_FAIL = -11, /* free failed */
++ TNETD73XX_ERR_MEM_CORRUPT = -12, /* corrupted memory */
++ TNETD73XX_ERR_BUF_LINK = -13, /* buffer linking failed */
++
++ /* Device issues */
++ TNETD73XX_ERR_DEVICE_TIMEOUT = -20, /* device timeout on read/write */
++ TNETD73XX_ERR_DEVICE_MALFUNC = -21, /* device malfunction */
++
++ TNETD73XX_ERR_INVID = -30 /* Invalid ID */
++
++} TNETD73XX_ERR;
++
++#endif /* __TNETD73XX_ERR_H__ */
+diff -urN linux.old/include/asm-mips/ar7/tnetd73xx_misc.h linux.dev/include/asm-mips/ar7/tnetd73xx_misc.h
+--- linux.old/include/asm-mips/ar7/tnetd73xx_misc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/tnetd73xx_misc.h 2005-11-10 01:10:46.075589000 +0100
+@@ -0,0 +1,239 @@
++/******************************************************************************
++ * FILE PURPOSE: TNETD73xx Misc modules API Header
++ ******************************************************************************
++ * FILE NAME: tnetd73xx_misc.h
++ *
++ * DESCRIPTION: Clock Control, Reset Control, Power Management, GPIO
++ * FSER Modules API
++ * As per TNETD73xx specifications
++ *
++ * REVISION HISTORY:
++ * 27 Nov 02 - Sharath Kumar PSP TII
++ * 14 Feb 03 - Anant Gole PSP TII
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++#ifndef __TNETD73XX_MISC_H__
++#define __TNETD73XX_MISC_H__
++
++/*****************************************************************************
++ * Reset Control Module
++ *****************************************************************************/
++
++typedef enum TNETD73XX_RESET_MODULE_tag
++{
++ RESET_MODULE_UART0 = 0,
++ RESET_MODULE_UART1 = 1,
++ RESET_MODULE_I2C = 2,
++ RESET_MODULE_TIMER0 = 3,
++ RESET_MODULE_TIMER1 = 4,
++ RESET_MODULE_GPIO = 6,
++ RESET_MODULE_ADSLSS = 7,
++ RESET_MODULE_USBS = 8,
++ RESET_MODULE_SAR = 9,
++ RESET_MODULE_VDMA_VT = 11,
++ RESET_MODULE_FSER = 12,
++ RESET_MODULE_VLYNQ1 = 16,
++ RESET_MODULE_EMAC0 = 17,
++ RESET_MODULE_DMA = 18,
++ RESET_MODULE_BIST = 19,
++ RESET_MODULE_VLYNQ0 = 20,
++ RESET_MODULE_EMAC1 = 21,
++ RESET_MODULE_MDIO = 22,
++ RESET_MODULE_ADSLSS_DSP = 23,
++ RESET_MODULE_EPHY = 26
++} TNETD73XX_RESET_MODULE_T;
++
++typedef enum TNETD73XX_RESET_CTRL_tag
++{
++ IN_RESET = 0,
++ OUT_OF_RESET
++} TNETD73XX_RESET_CTRL_T;
++
++typedef enum TNETD73XX_SYS_RST_MODE_tag
++{
++ RESET_SOC_WITH_MEMCTRL = 1, /* SW0 bit in SWRCR register */
++ RESET_SOC_WITHOUT_MEMCTRL = 2 /* SW1 bit in SWRCR register */
++} TNETD73XX_SYS_RST_MODE_T;
++
++typedef enum TNETD73XX_SYS_RESET_STATUS_tag
++{
++ HARDWARE_RESET = 0,
++ SOFTWARE_RESET0, /* Caused by writing 1 to SW0 bit in SWRCR register */
++ WATCHDOG_RESET,
++ SOFTWARE_RESET1 /* Caused by writing 1 to SW1 bit in SWRCR register */
++} TNETD73XX_SYS_RESET_STATUS_T;
++
++void tnetd73xx_reset_ctrl(TNETD73XX_RESET_MODULE_T reset_module,
++ TNETD73XX_RESET_CTRL_T reset_ctrl);
++TNETD73XX_RESET_CTRL_T tnetd73xx_get_reset_status(TNETD73XX_RESET_MODULE_T reset_module);
++void tnetd73xx_sys_reset(TNETD73XX_SYS_RST_MODE_T mode);
++TNETD73XX_SYS_RESET_STATUS_T tnetd73xx_get_sys_last_reset_status(void);
++
++/*****************************************************************************
++ * Power Control Module
++ *****************************************************************************/
++
++typedef enum TNETD73XX_POWER_MODULE_tag
++{
++ POWER_MODULE_USBSP = 0,
++ POWER_MODULE_WDTP = 1,
++ POWER_MODULE_UT0P = 2,
++ POWER_MODULE_UT1P = 3,
++ POWER_MODULE_IICP = 4,
++ POWER_MODULE_VDMAP = 5,
++ POWER_MODULE_GPIOP = 6,
++ POWER_MODULE_VLYNQ1P = 7,
++ POWER_MODULE_SARP = 8,
++ POWER_MODULE_ADSLP = 9,
++ POWER_MODULE_EMIFP = 10,
++ POWER_MODULE_ADSPP = 12,
++ POWER_MODULE_RAMP = 13,
++ POWER_MODULE_ROMP = 14,
++ POWER_MODULE_DMAP = 15,
++ POWER_MODULE_BISTP = 16,
++ POWER_MODULE_TIMER0P = 18,
++ POWER_MODULE_TIMER1P = 19,
++ POWER_MODULE_EMAC0P = 20,
++ POWER_MODULE_EMAC1P = 22,
++ POWER_MODULE_EPHYP = 24,
++ POWER_MODULE_VLYNQ0P = 27,
++} TNETD73XX_POWER_MODULE_T;
++
++typedef enum TNETD73XX_POWER_CTRL_tag
++{
++ POWER_CTRL_POWER_UP = 0,
++ POWER_CTRL_POWER_DOWN
++} TNETD73XX_POWER_CTRL_T;
++
++typedef enum TNETD73XX_SYS_POWER_MODE_tag
++{
++ GLOBAL_POWER_MODE_RUN = 0, /* All system is up */
++ GLOBAL_POWER_MODE_IDLE, /* MIPS is power down, all peripherals working */
++ GLOBAL_POWER_MODE_STANDBY, /* Chip in power down, but clock to ADSKL subsystem is running */
++ GLOBAL_POWER_MODE_POWER_DOWN /* Total chip is powered down */
++} TNETD73XX_SYS_POWER_MODE_T;
++
++void tnetd73xx_power_ctrl(TNETD73XX_POWER_MODULE_T power_module, TNETD73XX_POWER_CTRL_T power_ctrl);
++TNETD73XX_POWER_CTRL_T tnetd73xx_get_pwr_status(TNETD73XX_POWER_MODULE_T power_module);
++void tnetd73xx_set_global_pwr_mode(TNETD73XX_SYS_POWER_MODE_T power_mode);
++TNETD73XX_SYS_POWER_MODE_T tnetd73xx_get_global_pwr_mode(void);
++
++/*****************************************************************************
++ * Wakeup Control
++ *****************************************************************************/
++
++typedef enum TNETD73XX_WAKEUP_INTERRUPT_tag
++{
++ WAKEUP_INT0 = 1,
++ WAKEUP_INT1 = 2,
++ WAKEUP_INT2 = 4,
++ WAKEUP_INT3 = 8
++} TNETD73XX_WAKEUP_INTERRUPT_T;
++
++typedef enum TNETD73XX_WAKEUP_CTRL_tag
++{
++ WAKEUP_DISABLED = 0,
++ WAKEUP_ENABLED
++} TNETD73XX_WAKEUP_CTRL_T;
++
++typedef enum TNETD73XX_WAKEUP_POLARITY_tag
++{
++ WAKEUP_ACTIVE_HIGH = 0,
++ WAKEUP_ACTIVE_LOW
++} TNETD73XX_WAKEUP_POLARITY_T;
++
++void tnetd73xx_wakeup_ctrl(TNETD73XX_WAKEUP_INTERRUPT_T wakeup_int,
++ TNETD73XX_WAKEUP_CTRL_T wakeup_ctrl,
++ TNETD73XX_WAKEUP_POLARITY_T wakeup_polarity);
++
++/*****************************************************************************
++ * FSER Control
++ *****************************************************************************/
++
++typedef enum TNETD73XX_FSER_MODE_tag
++{
++ FSER_I2C = 0,
++ FSER_UART = 1
++} TNETD73XX_FSER_MODE_T;
++
++void tnetd73xx_fser_ctrl(TNETD73XX_FSER_MODE_T fser_mode);
++
++/*****************************************************************************
++ * Clock Control
++ *****************************************************************************/
++
++#define CLK_MHZ(x) ( (x) * 1000000 )
++
++typedef enum TNETD73XX_CLKC_ID_tag
++{
++ CLKC_SYS = 0,
++ CLKC_MIPS,
++ CLKC_USB,
++ CLKC_ADSLSS
++} TNETD73XX_CLKC_ID_T;
++
++void tnetd73xx_clkc_init(__u32 afeclk, __u32 refclk, __u32 xtal3in);
++TNETD73XX_ERR tnetd73xx_clkc_set_freq(TNETD73XX_CLKC_ID_T clk_id, __u32 output_freq);
++__u32 tnetd73xx_clkc_get_freq(TNETD73XX_CLKC_ID_T clk_id);
++
++/*****************************************************************************
++ * GPIO Control
++ *****************************************************************************/
++
++typedef enum TNETD73XX_GPIO_PIN_tag
++{
++ GPIO_UART0_RD = 0,
++ GPIO_UART0_TD = 1,
++ GPIO_UART0_RTS = 2,
++ GPIO_UART0_CTS = 3,
++ GPIO_FSER_CLK = 4,
++ GPIO_FSER_D = 5,
++ GPIO_EXT_AFE_SCLK = 6,
++ GPIO_EXT_AFE_TX_FS = 7,
++ GPIO_EXT_AFE_TXD = 8,
++ GPIO_EXT_AFE_RS_FS = 9,
++ GPIO_EXT_AFE_RXD1 = 10,
++ GPIO_EXT_AFE_RXD0 = 11,
++ GPIO_EXT_AFE_CDIN = 12,
++ GPIO_EXT_AFE_CDOUT = 13,
++ GPIO_EPHY_SPEED100 = 14,
++ GPIO_EPHY_LINKON = 15,
++ GPIO_EPHY_ACTIVITY = 16,
++ GPIO_EPHY_FDUPLEX = 17,
++ GPIO_EINT0 = 18,
++ GPIO_EINT1 = 19,
++ GPIO_MBSP0_TCLK = 20,
++ GPIO_MBSP0_RCLK = 21,
++ GPIO_MBSP0_RD = 22,
++ GPIO_MBSP0_TD = 23,
++ GPIO_MBSP0_RFS = 24,
++ GPIO_MBSP0_TFS = 25,
++ GPIO_MII_DIO = 26,
++ GPIO_MII_DCLK = 27,
++} TNETD73XX_GPIO_PIN_T;
++
++typedef enum TNETD73XX_GPIO_PIN_MODE_tag
++{
++ FUNCTIONAL_PIN = 0,
++ GPIO_PIN = 1
++} TNETD73XX_GPIO_PIN_MODE_T;
++
++typedef enum TNETD73XX_GPIO_PIN_DIRECTION_tag
++{
++ GPIO_OUTPUT_PIN = 0,
++ GPIO_INPUT_PIN = 1
++} TNETD73XX_GPIO_PIN_DIRECTION_T;
++
++void tnetd73xx_gpio_init(void);
++void tnetd73xx_gpio_ctrl(TNETD73XX_GPIO_PIN_T gpio_pin,
++ TNETD73XX_GPIO_PIN_MODE_T pin_mode,
++ TNETD73XX_GPIO_PIN_DIRECTION_T pin_direction);
++void tnetd73xx_gpio_out(TNETD73XX_GPIO_PIN_T gpio_pin, int value);
++int tnetd73xx_gpio_in(TNETD73XX_GPIO_PIN_T gpio_pin);
++
++/* TNETD73XX Revision */
++__u32 tnetd73xx_get_revision(void);
++
++#endif /* __TNETD73XX_MISC_H__ */
+diff -urN linux.old/include/asm-mips/ar7/vlynq.h linux.dev/include/asm-mips/ar7/vlynq.h
+--- linux.old/include/asm-mips/ar7/vlynq.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/vlynq.h 2005-11-10 01:10:46.095590250 +0100
+@@ -0,0 +1,610 @@
++/***************************************************************************
++**+----------------------------------------------------------------------+**
++**| **** |**
++**| **** |**
++**| ******o*** |**
++**| ********_///_**** |**
++**| ***** /_//_/ **** |**
++**| ** ** (__/ **** |**
++**| ********* |**
++**| **** |**
++**| *** |**
++**| |**
++**| Copyright (c) 2003 Texas Instruments Incorporated |**
++**| ALL RIGHTS RESERVED |**
++**| |**
++**| Permission is hereby granted to licensees of Texas Instruments |**
++**| Incorporated (TI) products to use this computer program for the sole |**
++**| purpose of implementing a licensee product based on TI products. |**
++**| No other rights to reproduce, use, or disseminate this computer |**
++**| program, whether in part or in whole, are granted. |**
++**| |**
++**| TI makes no representation or warranties with respect to the |**
++**| performance of this computer program, and specifically disclaims |**
++**| any responsibility for any damages, special or consequential, |**
++**| connected with the use of this program. |**
++**| |**
++**+----------------------------------------------------------------------+**
++***************************************************************************/
++
++/*********************************************************************************
++ * ------------------------------------------------------------------------------
++ * Module : vlynq_hal.h
++ * Description :
++ * This header file provides the set of functions exported by the
++ * VLYNQ HAL. This file is included from the SOC specific VLYNQ driver wrapper.
++ * ------------------------------------------------------------------------------
++ *********************************************************************************/
++
++#ifndef _VLYNQ_HAL_H_
++#define _VLYNQ_HAL_H_
++
++/* Enable/Disable debug feature */
++#undef VLYNQ_DEBUG
++
++#ifdef VLYNQ_DEBUG /* This needs to be OS abstracted - for testing use vxworks/linux calls */
++#define debugPrint(format,args...)
++#else
++#define debugPrint(format,args...)
++#endif
++
++ /* number of VLYNQ memory regions supported */
++#define VLYNQ_MAX_MEMORY_REGIONS 0x04
++
++ /* Max.number of external interrupt inputs supported by VLYNQ module */
++#define VLYNQ_IVR_MAXIVR 0x08
++
++#define VLYNQ_CLK_DIV_MAX 0x08
++#define VLYNQ_CLK_DIV_MIN 0x01
++
++
++/*** the total number of entries allocated for ICB would be
++ * 32(for 32 bits in IntPending register) + VLYNQ_IVR_CHAIN_SLOTS*/
++#define VLYNQ_IVR_CHAIN_SLOTS 10
++
++
++/* Error defines */
++#define VLYNQ_SUCCESS 0
++
++#define VLYNQ_ERRCODE_BASE 0 /* Chosen by system */
++#define VLYNQ_INVALID_ARG -(VLYNQ_ERRCODE_BASE+1)
++#define VLYNQ_INVALID_DRV_STATE -(VLYNQ_ERRCODE_BASE+2)
++#define VLYNQ_INT_CONFIG_ERR -(VLYNQ_ERRCODE_BASE+3)
++#define VLYNQ_LINK_DOWN -(VLYNQ_ERRCODE_BASE+4)
++#define VLYNQ_MEMALLOC_FAIL -(VLYNQ_ERRCODE_BASE+5)
++#define VLYNQ_ISR_NON_EXISTENT -(VLYNQ_ERRCODE_BASE+6)
++#define VLYNQ_INTVEC_MAP_NOT_FOUND -(VLYNQ_ERRCODE_BASE+7)
++
++/* Vlynq Defines and Macros */
++
++#define VLYNQ_NUM_INT_BITS 32 /* 32 bit interrupt staus register */
++
++/* Base address of module */
++#define VLYNQ_BASE (pdev->module_base)
++
++#define VLYNQ_REMOTE_REGS_OFFSET 0x0080
++
++#define VLYNQ_REV_OFFSET 0x0000
++#define VLYNQ_CTRL_OFFSET 0x0004
++#define VLYNQ_STATUS_OFFSET 0x0008
++#define VLYNQ_INT_STAT_OFFSET 0x0010
++#define VLYNQ_INT_PEND_OFFSET 0x0014
++#define VLYNQ_INT_PTR_OFFSET 0x0018
++#define VLYNQ_TXMAP_OFFSET 0x001c
++
++#define VLYNQ_RX0MAP_SIZE_REG_OFFSET 0x0020
++#define VLYNQ_RX0MAP_OFFSET_REG_OFFSET 0x0024
++
++#define VLYNQ_CHIP_VER_OFFSET 0x0040
++#define VLYNQ_IVR_REGS_OFFSET 0x0060
++
++#define VLYNQ_INT_PENDING_REG_PTR 0x14
++#define VLYNQ_R_INT_PENDING_REG_PTR VLYNQ_REMOTE_REGS_OFFSET + 0x14
++
++#define VLYNQ_REV_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_REV_OFFSET))
++#define VLYNQ_CTRL_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_CTRL_OFFSET))
++#define VLYNQ_STATUS_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_STATUS_OFFSET))
++#define VLYNQ_INT_STAT_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_INT_STAT_OFFSET))
++#define VLYNQ_INT_PEND_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_INT_PEND_OFFSET))
++#define VLYNQ_INT_PTR_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_INT_PTR_OFFSET))
++#define VLYNQ_TXMAP_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_TXMAP_OFFSET))
++
++/** map takes on values between 1 to VLYNQ_MAX_MEMORY_REGIONS **/
++#define VLYNQ_RXMAP_SIZE_REG(map) \
++ *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_RX0MAP_SIZE_REG_OFFSET+( (map-1)<<3)))
++
++/** map takes on values between 1 to VLYNQ_MAX_MEMORY_REGIONS **/
++#define VLYNQ_RXMAP_OFFSET_REG(map) \
++ *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_RX0MAP_OFFSET_REG_OFFSET+( (map-1)<<3)))
++
++#define VLYNQ_CHIP_VER_REG *((volatile unsigned int *)(VLYNQ_BASE+VLYNQ_CHIP_VER_OFFSET))
++
++/* 0 =< ivr <= 31; currently ivr < VLYNQ_IVR_MAXIVR=8) */
++#define VLYNQ_IVR_OFFSET(ivr) \
++ (VLYNQ_BASE + VLYNQ_IVR_REGS_OFFSET +((((unsigned)(ivr)) & 31) & ~3) )
++
++#define VLYNQ_IVR_03TO00_REG *((volatile unsigned int*) (VLYNQ_IVR_OFFSET(0)) )
++#define VLYNQ_IVR_07TO04_REG *((volatile unsigned int*) (VLYNQ_IVR_OFFSET(4)) )
++/*** Can be extended for 11TO08...31TO28 when all 31 are supported**/
++
++#define VLYNQ_IVR_INTEN(ivr) (((unsigned int)(0x80)) << ((((unsigned)(ivr)) % 4) * 8))
++#define VLYNQ_IVR_INTTYPE(ivr) (((unsigned int)(0x40)) << ((((unsigned)(ivr)) % 4) * 8))
++#define VLYNQ_IVR_INTPOL(ivr) (((unsigned int)(0x20)) << ((((unsigned)(ivr)) % 4) * 8))
++#define VLYNQ_IVR_INTVEC(ivr) (((unsigned int)(0x1F)) << ((((unsigned)(ivr)) % 4) * 8))
++#define VLYNQ_IVR_INTALL(ivr) (((unsigned int)(0xFF)) << ((((unsigned)(ivr)) % 4) * 8))
++
++
++
++/*********************************
++ * Remote VLYNQ register set *
++ *********************************/
++
++#define VLYNQ_R_REV_OFFSET 0x0080
++#define VLYNQ_R_CTRL_OFFSET 0x0084
++#define VLYNQ_R_STATUS_OFFSET 0x0088
++#define VLYNQ_R_INT_STAT_OFFSET 0x0090
++#define VLYNQ_R_INT_PEND_OFFSET 0x0094
++#define VLYNQ_R_INT_PTR_OFFSET 0x0098
++#define VLYNQ_R_TXMAP_OFFSET 0x009c
++
++#define VLYNQ_R_RX0MAP_SIZE_REG_OFFSET 0x00A0
++#define VLYNQ_R_RX0MAP_OFFSET_REG_OFFSET 0x00A4
++
++#define VLYNQ_R_CHIP_VER_OFFSET 0x00C0
++#define VLYNQ_R_IVR_REGS_OFFSET 0x00E0
++
++#define VLYNQ_R_REV_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_REV_OFFSET))
++#define VLYNQ_R_CTRL_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_CTRL_OFFSET))
++#define VLYNQ_R_STATUS_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_STATUS_OFFSET))
++#define VLYNQ_R_INT_STAT_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_INT_STAT_OFFSET))
++#define VLYNQ_R_INT_PEND_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_INT_PEND_OFFSET))
++#define VLYNQ_R_INT_PTR_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_INT_PTR_OFFSET))
++#define VLYNQ_R_TXMAP_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_TXMAP_OFFSET))
++
++/** map takes on values between 1 to VLYNQ_MAX_MEMORY_REGIONS **/
++#define VLYNQ_R_RXMAP_SIZE_REG(map) \
++ *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_RX0MAP_SIZE_REG_OFFSET + ((map-1)<<3)))
++
++/** map takes on values between 1 to VLYNQ_MAX_MEMORY_REGIONS **/
++#define VLYNQ_R_RXMAP_OFFSET_REG(map) \
++ *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_RX0MAP_OFFSET_REG_OFFSET + ((map-1)<<3)))
++
++#define VLYNQ_R_CHIP_VER_REG *((volatile unsigned int *)(VLYNQ_BASE + VLYNQ_R_CHIP_VER_OFFSET)
++
++#define VLYNQ_R_IVR_OFFSET(ivr) \
++ (VLYNQ_BASE + VLYNQ_R_IVR_REGS_OFFSET +((((unsigned)(ivr)) & 31) & ~3))
++
++
++/*** Can be extended for 11TO08...31TO28 when all 31 are supported**/
++#define VLYNQ_R_IVR_03TO00_REG *((volatile unsigned int*) (VLYNQ_R_IVR_OFFSET(0)) )
++#define VLYNQ_R_IVR_07TO04_REG *((volatile unsigned int*) (VLYNQ_R_IVR_OFFSET(4)) )
++
++
++/****End of remote register set definition******/
++
++
++/*** Masks for individual register fields ***/
++
++#define VLYNQ_MODULE_ID_MASK 0xffff0000
++#define VLYNQ_MAJOR_REV_MASK 0x0000ff00
++#define VLYNQ_MINOR_REV_MASK 0x000000ff
++
++
++#define VLYNQ_CTL_ILOOP_MASK 0x00000002
++#define VLYNQ_CTL_INT2CFG_MASK 0x00000080
++#define VLYNQ_CTL_INTVEC_MASK 0x00001f00
++#define VLYNQ_CTL_INTEN_MASK 0x00002000
++#define VLYNQ_CTL_INTLOCAL_MASK 0x00004000
++#define VLYNQ_CTL_CLKDIR_MASK 0x00008000
++#define VLYNQ_CTL_CLKDIV_MASK 0x00070000
++#define VLYNQ_CTL_MODE_MASK 0x00e00000
++
++
++#define VLYNQ_STS_LINK_MASK 0x00000001 /* Link is active */
++#define VLYNQ_STS_MPEND_MASK 0x00000002 /* Pending master requests */
++#define VLYNQ_STS_SPEND_MASK 0x00000004 /* Pending slave requests */
++#define VLYNQ_STS_NFEMPTY0_MASK 0x00000008 /* Master data FIFO not empty */
++#define VLYNQ_STS_NFEMPTY1_MASK 0x00000010 /* Master command FIFO not empty */
++#define VLYNQ_STS_NFEMPTY2_MASK 0x00000020 /* Slave data FIFO not empty */
++#define VLYNQ_STS_NFEMPTY3_MASK 0x00000040 /* Slave command FIFO not empty */
++#define VLYNQ_STS_LERROR_MASK 0x00000080 /* Local error, w/c */
++#define VLYNQ_STS_RERROR_MASK 0x00000100 /* remote error w/c */
++#define VLYNQ_STS_OFLOW_MASK 0x00000200
++#define VLYNQ_STS_IFLOW_MASK 0x00000400
++#define VLYNQ_STS_MODESUP_MASK 0x00E00000 /* Highest mode supported */
++#define VLYNQ_STS_SWIDTH_MASK 0x07000000 /* Used for reading the width of VLYNQ bus */
++#define VLYNQ_STS_DEBUG_MASK 0xE0000000
++
++#define VLYNQ_CTL_INTVEC_SHIFT 0x08
++#define VLYNQ_CTL_INTEN_SHIFT 0x0D
++#define VLYNQ_CTL_INT2CFG_SHIFT 0x07
++#define VLYNQ_CTL_INTLOCAL_SHIFT 0x0E
++
++#define VLYNQ_CTL_INTFIELDS_CLEAR_MASK 0x7F80
++
++#define VLYNQ_CHIPVER_DEVREV_MASK 0xffff0000
++#define VLYNQ_CHIPVER_DEVID_MASK 0x0000ffff
++
++#define VLYNQ_IVR_INTEN_MASK 0x80
++#define VLYNQ_IVR_INTTYPE_MASK 0x40
++#define VLYNQ_IVR_INTPOL_MASK 0x20
++
++
++/**** Helper macros ****/
++
++#define VLYNQ_RESETCB(arg) \
++ if( pdev->reset_cb != NULL) \
++ { \
++ (pdev->reset_cb)(pdev, (arg)); \
++ }
++
++#define VLYNQ_STATUS_FLD_WIDTH(sts) (((sts) & VLYNQ_STS_SWIDTH_MASK) >> 24 )
++#define VLYNQ_CTL_INTVEC(x) (((x) & 31) << 8 )
++
++#define VLYNQ_INRANGE(x,hi,lo) (((x) <= (hi)) && ((x) >= (lo)))
++#define VLYNQ_OUTRANGE(x,hi,lo) (((x) > (hi)) || ((x) < (lo)))
++
++#define VLYNQ_ALIGN4(x) (x)=(x)&(~3)
++
++
++/*************************************
++ * Enums *
++ *************************************/
++
++/* Initialization options define what operations are
++ * undertaken during vlynq module initialization */
++typedef enum
++{
++ /* Init host local memory regions.This allows
++ * local host access remote memory regions */
++ VLYNQ_INIT_LOCAL_MEM_REGIONS = 0x01,
++ /* Init host remote memory regions.This allows
++ * remote device access local memory regions */
++ VLYNQ_INIT_REMOTE_MEM_REGIONS =0x02,
++ /* Init local interrupt config*/
++ VLYNQ_INIT_LOCAL_INTERRUPTS =0x04,
++ /* Init remote interrupt config*/
++ VLYNQ_INIT_REMOTE_INTERRUPTS =0x08,
++ /* Check link during initialization*/
++ VLYNQ_INIT_CHECK_LINK =0x10,
++ /* configure clock during init */
++ VLYNQ_INIT_CONFIG_CLOCK =0x20,
++ /* Clear errors during init */
++ VLYNQ_INIT_CLEAR_ERRORS =0x40,
++ /* All options */
++ VLYNQ_INIT_PERFORM_ALL =0x7F
++}VLYNQ_INIT_OPTIONS;
++
++
++/* VLYNQ_DEV_TYPE identifies local or remote device */
++typedef enum
++{
++ VLYNQ_LOCAL_DVC = 0, /* vlynq local device (SOC's vlynq module) */
++ VLYNQ_REMOTE_DVC = 1 /* vlynq remote device (remote vlynq module) */
++}VLYNQ_DEV_TYPE;
++
++
++/* VLYNQ_CLK_SOURCE identifies the vlynq module clock source */
++typedef enum
++{
++ VLYNQ_CLK_SOURCE_NONE = 0, /* do not initialize clock generator*/
++ VLYNQ_CLK_SOURCE_LOCAL = 1, /* clock is generated by local machine */
++ VLYNQ_CLK_SOURCE_REMOTE = 2 /* clock is generated by remote machine */
++}VLYNQ_CLK_SOURCE;
++
++
++/* VLYNQ_DRV_STATE indicates the current driver state */
++typedef enum
++{
++ VLYNQ_DRV_STATE_UNINIT = 0, /* driver is uninitialized */
++ VLYNQ_DRV_STATE_ININIT = 1, /* VLYNQ is being initialized */
++ VLYNQ_DRV_STATE_RUN = 2, /* VLYNQ is running properly */
++ VLYNQ_DRV_STATE_HOLD = 3, /* driver stopped temporarily */
++ VLYNQ_DRV_STATE_ERROR = 4 /* driver stopped on unrecoverable error */
++}VLYNQ_DRV_STATE;
++
++
++/* VLYNQ_BUS_WIDTH identifies the vlynq module bus width */
++typedef enum
++{
++ VLYNQ_BUS_WIDTH_3 = 3,
++ VLYNQ_BUS_WIDTH_5 = 5,
++ VLYNQ_BUS_WIDTH_7 = 7,
++ VLYNQ_BUS_WIDTH_9 = 9
++}VLYNQ_BUS_WIDTH;
++
++
++/* VLYNQ_LOCAL_INT_CONFIG indicates whether the local vlynq
++ * interrupts are processed by the host or passed on to the
++ * remote device.
++ */
++typedef enum
++{
++ VLYNQ_INT_REMOTE = 0, /* Interrupt packets sent to remote, intlocal=0 */
++ VLYNQ_INT_LOCAL = 1 /* Interrupts are handled locally, intlocal=1 */
++}VLYNQ_LOCAL_INT_CONFIG;
++
++
++/* VLYNQ_REMOTE_INT_CONFIG indicates whether the remote
++ * interrupts are to be handled by the SOC system ISR
++ * or via the vlynq root ISR
++ */
++typedef enum
++{
++ VLYNQ_INT_ROOT_ISR = 0, /* remote ints handled via vlynq root ISR */
++ VLYNQ_INT_SYSTEM_ISR = 1 /* remote ints handled via system ISR */
++}VLYNQ_REMOTE_INT_CONFIG;
++
++
++/* VLYNQ_INTR_POLARITY - vlynq interrupt polarity setting */
++typedef enum
++{
++ VLYNQ_INTR_ACTIVE_HIGH = 0,
++ VLYNQ_INTR_ACTIVE_LOW = 1
++}VLYNQ_INTR_POLARITY;
++
++
++/* VLYNQ_INTR_TYPE - vlynq interrupt type */
++typedef enum
++{
++ VLYNQ_INTR_LEVEL = 0,
++ VLYNQ_INTR_PULSED = 1
++}VLYNQ_INTR_TYPE;
++
++
++/* VLYNQ_RESET_MODE - vlynq reset mode */
++typedef enum
++{
++ VLYNQ_RESET_ASSERT, /* hold device in reset state */
++ VLYNQ_RESET_DEASSERT, /* release device from reset state */
++ VLYNQ_RESET_INITFAIL, /* handle the device in case driver initialization fails */
++ VLYNQ_RESET_LINKESTABLISH, /* handle the device in case driver established link */
++ VLYNQ_RESET_INITFAIL2, /* Driver initialization failed but VLYNQ link exist. */
++ VLYNQ_RESET_INITOK /* Driver initialization finished OK. */
++}VLYNQ_RESET_MODE;
++
++
++
++/*************************************
++ * Typedefs *
++ *************************************/
++
++struct VLYNQ_DEV_t; /*forward declaration*/
++
++/*--------Function Pointers defintions -----------*/
++
++/* prototype for interrupt handler definition */
++typedef void (*VLYNQ_INTR_CNTRL_ISR)(void *arg1,void *arg2,void *arg3);
++
++typedef void
++(*VLYNQ_RESET_REMOTE)(struct VLYNQ_DEV_t *pDev, VLYNQ_RESET_MODE mode);
++
++typedef void
++(*VLYNQ_REPORT_CB)( struct VLYNQ_DEV_t *pDev, /* This VLYNQ */
++ VLYNQ_DEV_TYPE aSrcDvc, /* Event Cause -local/remote? */
++ unsigned int dwStatRegVal); /* Value of the relevant status register */
++
++
++/*-------Structure Definitions------------*/
++
++typedef struct VLYNQ_MEMORY_MAP_t
++{
++ unsigned int Txmap;
++ unsigned int RxOffset[VLYNQ_MAX_MEMORY_REGIONS];
++ unsigned int RxSize[VLYNQ_MAX_MEMORY_REGIONS];
++}VLYNQ_MEMORY_MAP;
++
++
++/**VLYNQ_INTERRUPT_CNTRL - defines the vlynq module interrupt
++ * settings in vlynq Control register */
++typedef struct VLYNQ_INTERRUPT_CNTRL_t
++{
++ /* vlynq interrupts handled by host or remote - maps to
++ * intLocal bit in vlynq control register */
++ VLYNQ_LOCAL_INT_CONFIG intLocal;
++
++ /* remote interrupts handled by vlynq isr or host system
++ * interrupt controller - maps to the int2Cfg in vlynq
++ * control register */
++ VLYNQ_REMOTE_INT_CONFIG intRemote;
++
++ /* bit in pending/set register used for module interrupts*/
++ unsigned int map_vector;
++
++ /* used only if remote interrupts are to be handled by system ISR*/
++ unsigned int intr_ptr;
++
++}VLYNQ_INTERRUPT_CNTRL;
++
++
++/* VLYNQ_INTR_CNTRL_ICB - defines the Interrupt control block which hold
++ * the interrupt dispatch table. The vlynq_root_isr() indexes into this
++ * table to identify the ISR to be invoked
++ */
++typedef struct VLYNQ_INTR_CNTRL_ICB_t
++{
++ VLYNQ_INTR_CNTRL_ISR isr; /* Clear errors during initialization */
++ void *arg1 ; /* Arg 1 for the ISR */
++ void *arg2 ; /* Arg 2 for the ISR */
++ void *arg3 ; /* Arg 3 for the ISR */
++ unsigned int isrCount; /* number of ISR invocations so far */
++ struct VLYNQ_INTR_CNTRL_ICB_t *next;
++}VLYNQ_INTR_CNTRL_ICB;
++
++/* overlay of vlynq register set */
++typedef struct VLYNQ_REG_SET_t
++{
++ unsigned int revision; /*offset : 0x00 */
++ unsigned int control; /* 0x04*/
++ unsigned int status; /* 0x08*/
++ unsigned int pad1; /* 0x0c*/
++ unsigned int intStatus; /*0x10*/
++ unsigned int intPending; /*0x14*/
++ unsigned int intPtr; /*0x18*/
++ unsigned int txMap; /*0x1C*/
++ unsigned int rxSize1; /*0x20*/
++ unsigned int rxOffset1; /*0x24*/
++ unsigned int rxSize2; /*0x28*/
++ unsigned int rxOffset2; /*0x2C*/
++ unsigned int rxSize3; /*0x30*/
++ unsigned int rxOffset3; /*0x34*/
++ unsigned int rxSize4; /*0x38*/
++ unsigned int rxOffset4; /*0x3C*/
++ unsigned int chipVersion; /*0x40*/
++ unsigned int pad2[8];
++ unsigned int ivr30; /*0x60*/
++ unsigned int ivr74; /*0x64*/
++ unsigned int pad3[7];
++}VLYNQ_REG_SET;
++
++
++typedef struct VLYNQ_DEV_t
++{
++ /** module index:1,2,3... used for debugging purposes */
++ unsigned int dev_idx;
++
++ /*VLYNQ module base address */
++ unsigned int module_base;
++
++ /* clock source selection */
++ VLYNQ_CLK_SOURCE clk_source;
++
++ /* Clock Divider.Val=1 to 8. VLYNQ_clk = VBUSCLK/clk_div */
++ unsigned int clk_div;
++
++ /* State of the VLYNQ driver, set to VLYNQ_DRV_STATE_UNINIT, when initializing */
++ VLYNQ_DRV_STATE state;
++
++ /* Valid VLYNQ bus width, filled by driver */
++ VLYNQ_BUS_WIDTH width;
++
++ /* local memory mapping */
++ VLYNQ_MEMORY_MAP local_mem;
++
++ /* remote memory mapping */
++ VLYNQ_MEMORY_MAP remote_mem;
++
++ /* Local module interrupt params */
++ VLYNQ_INTERRUPT_CNTRL local_irq;
++
++ /* remote module interrupt params */
++ VLYNQ_INTERRUPT_CNTRL remote_irq;
++
++ /*** ICB related fields **/
++
++ /* Sizeof of ICB = VLYNQ_NUM_INT_BITS(for 32 bits in IntPending) +
++ * expansion slots for shared interrupts*/
++ VLYNQ_INTR_CNTRL_ICB pIntrCB[VLYNQ_NUM_INT_BITS + VLYNQ_IVR_CHAIN_SLOTS];
++ VLYNQ_INTR_CNTRL_ICB *freelist;
++
++ /* table holding mapping between intVector and the bit position the interrupt
++ * is mapped to(mapVector)*/
++ char vector_map[32];
++
++ /* user callback for vlynq events, NULL if unused */
++ VLYNQ_REPORT_CB report_cb;
++
++ /* user callback for resetting/realeasing remote device */
++ VLYNQ_RESET_REMOTE reset_cb;
++
++ /*** Handles provided for direct access to register set if need be
++ * Must be intialized to point to appropriate address during
++ * vlynq_init */
++ volatile VLYNQ_REG_SET * local;
++ volatile VLYNQ_REG_SET * remote;
++
++ unsigned int intCount; /* number of interrupts generated so far */
++ unsigned int isrCount; /* number of ISR invocations so far */
++}VLYNQ_DEV;
++
++
++typedef struct VLYNQ_ISR_ARGS_t
++{
++ int irq;
++ void * arg;
++ void * regset;
++}VLYNQ_ISR_ARGS;
++
++
++/****************************************
++ * Function Prototypes *
++ * API exported by generic vlynq driver *
++ ****************************************/
++/* Initialization function */
++int vlynq_init( VLYNQ_DEV *pdev, VLYNQ_INIT_OPTIONS options);
++
++/* Check vlynq link */
++unsigned int vlynq_link_check( VLYNQ_DEV * pdev);
++
++/* Set interrupt vector in local or remote device */
++int vlynq_interrupt_vector_set( VLYNQ_DEV *pdev,
++ unsigned int int_vector,
++ unsigned int map_vector,
++ VLYNQ_DEV_TYPE dev,
++ VLYNQ_INTR_POLARITY pol,
++ VLYNQ_INTR_TYPE type);
++
++
++int vlynq_interrupt_vector_cntl( VLYNQ_DEV *pdev,
++ unsigned int int_vector,
++ VLYNQ_DEV_TYPE dev,
++ unsigned int enable);
++
++unsigned int vlynq_interrupt_get_count( VLYNQ_DEV *pdev,
++ unsigned int map_vector);
++
++int vlynq_install_isr( VLYNQ_DEV *pdev,
++ unsigned int map_vector,
++ VLYNQ_INTR_CNTRL_ISR isr,
++ void *arg1, void *arg2, void *arg3);
++
++int vlynq_uninstall_isr( VLYNQ_DEV *pdev,
++ unsigned int map_vector,
++ void *arg1, void *arg2, void *arg3);
++
++
++void vlynq_root_isr(void *arg);
++
++void vlynq_delay(unsigned int clktime);
++
++/* The following functions, provide better granularity in setting
++ * interrupt parameters. (for better support of linux INT Controller)
++ * Note: The interrupt source is identified by "map_vector"- the bit
++ * position in interrupt status register*/
++
++int vlynq_interrupt_vector_map(VLYNQ_DEV * pdev,
++ VLYNQ_DEV_TYPE dev,
++ unsigned int int_vector,
++ unsigned int map_vector);
++
++int vlynq_interrupt_set_polarity(VLYNQ_DEV * pdev,
++ VLYNQ_DEV_TYPE dev,
++ unsigned int map_vector,
++ VLYNQ_INTR_POLARITY pol);
++
++int vlynq_interrupt_get_polarity( VLYNQ_DEV *pdev ,
++ VLYNQ_DEV_TYPE dev_type,
++ unsigned int map_vector);
++
++int vlynq_interrupt_set_type(VLYNQ_DEV * pdev,
++ VLYNQ_DEV_TYPE dev,
++ unsigned int map_vector,
++ VLYNQ_INTR_TYPE type);
++
++int vlynq_interrupt_get_type( VLYNQ_DEV *pdev,
++ VLYNQ_DEV_TYPE dev_type,
++ unsigned int map_vector);
++
++int vlynq_interrupt_enable(VLYNQ_DEV* pdev,
++ VLYNQ_DEV_TYPE dev,
++ unsigned int map_vector);
++
++int vlynq_interrupt_disable(VLYNQ_DEV * pdev,
++ VLYNQ_DEV_TYPE dev,
++ unsigned int map_vector);
++
++
++
++
++
++#endif /* _VLYNQ_HAL_H_ */
+diff -urN linux.old/include/asm-mips/ar7/vlynq_hal.h linux.dev/include/asm-mips/ar7/vlynq_hal.h
+--- linux.old/include/asm-mips/ar7/vlynq_hal.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/vlynq_hal.h 2005-11-10 01:10:46.095590250 +0100
+@@ -0,0 +1,606 @@
++/***************************************************************************
++**+----------------------------------------------------------------------+**
++**| **** |**
++**| **** |**
++**| ******o*** |**
++**| ********_///_**** |**
++**| ***** /_//_/ **** |**
++**| ** ** (__/ **** |**
++**| ********* |**
++**| **** |**
++**| *** |**
++**| |**
++**| Copyright (c) 2003 Texas Instruments Incorporated |**
++**| ALL RIGHTS RESERVED |**
++**| |**
++**| Permission is hereby granted to licensees of Texas Instruments |**
++**| Incorporated (TI) products to use this computer program for the sole |**
++**| purpose of implementing a licensee product based on TI products. |**
++**| No other rights to reproduce, use, or disseminate this computer |**
++**| program, whether in part or in whole, are granted. |**
++**| |**
++**| TI makes no representation or warranties with respect to the |**
++**| performance of this computer program, and specifically disclaims |**
++**| any responsibility for any damages, special or consequential, |**
++**| connected with the use of this program. |**
++**| |**
++**+----------------------------------------------------------------------+**
++***************************************************************************/
++
++/*********************************************************************************
++ * ------------------------------------------------------------------------------
++ * Module : vlynq_hal.h
++ * Description :
++ * This header file provides the set of functions exported by the
++ * VLYNQ HAL. This file is included from the SOC specific VLYNQ driver wrapper.
++ * ------------------------------------------------------------------------------
++ *********************************************************************************/
++
++#ifndef _VLYNQ_HAL_H_
++#define _VLYNQ_HAL_H_
++
++#include <asm/ar7/avalanche_types.h>
++#include <asm/ar7/vlynq_hal_params.h>
++
++#ifndef PRIVATE
++#define PRIVATE static
++#endif
++
++#ifndef GLOBAL
++#define GLOBAL
++#endif
++
++/* Enable/Disable debug feature */
++#undef VLYNQ_DEBUG
++
++#ifdef VLYNQ_DEBUG /* This needs to be OS abstracted - for testing use vxworks/linux calls */
++#define debugPrint(format,args...)
++#else
++#define debugPrint(format,args...)
++#endif
++
++/* Error defines */
++#define VLYNQ_SUCCESS 0
++
++#define VLYNQ_ERRCODE_BASE 0 /* Chosen by system */
++#define VLYNQ_INVALID_ARG -(VLYNQ_ERRCODE_BASE+1)
++#define VLYNQ_INVALID_DRV_STATE -(VLYNQ_ERRCODE_BASE+2)
++#define VLYNQ_INT_CONFIG_ERR -(VLYNQ_ERRCODE_BASE+3)
++#define VLYNQ_LINK_DOWN -(VLYNQ_ERRCODE_BASE+4)
++#define VLYNQ_MEMALLOC_FAIL -(VLYNQ_ERRCODE_BASE+5)
++#define VLYNQ_ISR_NON_EXISTENT -(VLYNQ_ERRCODE_BASE+6)
++#define VLYNQ_INTVEC_MAP_NOT_FOUND -(VLYNQ_ERRCODE_BASE+7)
++
++/* Vlynq Defines and Macros */
++
++#define VLYNQ_NUM_INT_BITS 32 /* 32 bit interrupt staus register */
++
++/* Base address of module */
++#define VLYNQ_BASE (pdev->module_base)
++
++#define VLYNQ_REMOTE_REGS_OFFSET 0x0080
++
++#define VLYNQ_REV_OFFSET 0x0000
++#define VLYNQ_CTRL_OFFSET 0x0004
++#define VLYNQ_STATUS_OFFSET 0x0008
++#define VLYNQ_INT_STAT_OFFSET 0x0010
++#define VLYNQ_INT_PEND_OFFSET 0x0014
++#define VLYNQ_INT_PTR_OFFSET 0x0018
++#define VLYNQ_TXMAP_OFFSET 0x001c
++
++#define VLYNQ_RX0MAP_SIZE_REG_OFFSET 0x0020
++#define VLYNQ_RX0MAP_OFFSET_REG_OFFSET 0x0024
++
++#define VLYNQ_CHIP_VER_OFFSET 0x0040
++#define VLYNQ_IVR_REGS_OFFSET 0x0060
++
++#define VLYNQ_INT_PENDING_REG_PTR 0x14
++#define VLYNQ_R_INT_PENDING_REG_PTR VLYNQ_REMOTE_REGS_OFFSET + 0x14
++
++#define VLYNQ_REV_REG *((volatile UINT32 *)(VLYNQ_BASE+VLYNQ_REV_OFFSET))
++#define VLYNQ_CTRL_REG *((volatile UINT32 *)(VLYNQ_BASE+VLYNQ_CTRL_OFFSET))
++#define VLYNQ_STATUS_REG *((volatile UINT32 *)(VLYNQ_BASE+VLYNQ_STATUS_OFFSET))
++#define VLYNQ_INT_STAT_REG *((volatile UINT32 *)(VLYNQ_BASE+VLYNQ_INT_STAT_OFFSET))
++#define VLYNQ_INT_PEND_REG *((volatile UINT32 *)(VLYNQ_BASE+VLYNQ_INT_PEND_OFFSET))
++#define VLYNQ_INT_PTR_REG *((volatile UINT32 *)(VLYNQ_BASE+VLYNQ_INT_PTR_OFFSET))
++#define VLYNQ_TXMAP_REG *((volatile UINT32 *)(VLYNQ_BASE+VLYNQ_TXMAP_OFFSET))
++
++/** map takes on values between 1 to VLYNQ_MAX_MEMORY_REGIONS **/
++#define VLYNQ_RXMAP_SIZE_REG(map) \
++ *((volatile UINT32 *)(VLYNQ_BASE+VLYNQ_RX0MAP_SIZE_REG_OFFSET+( (map-1)<<3)))
++
++/** map takes on values between 1 to VLYNQ_MAX_MEMORY_REGIONS **/
++#define VLYNQ_RXMAP_OFFSET_REG(map) \
++ *((volatile UINT32 *)(VLYNQ_BASE+VLYNQ_RX0MAP_OFFSET_REG_OFFSET+( (map-1)<<3)))
++
++#define VLYNQ_CHIP_VER_REG *((volatile UINT32 *)(VLYNQ_BASE+VLYNQ_CHIP_VER_OFFSET))
++
++/* 0 =< ivr <= 31; currently ivr < VLYNQ_IVR_MAXIVR=8) */
++#define VLYNQ_IVR_OFFSET(ivr) \
++ (VLYNQ_BASE + VLYNQ_IVR_REGS_OFFSET +((((unsigned)(ivr)) & 31) & ~3) )
++
++#define VLYNQ_IVR_03TO00_REG *((volatile UINT32*) (VLYNQ_IVR_OFFSET(0)) )
++#define VLYNQ_IVR_07TO04_REG *((volatile UINT32*) (VLYNQ_IVR_OFFSET(4)) )
++/*** Can be extended for 11TO08...31TO28 when all 31 are supported**/
++
++#define VLYNQ_IVR_INTEN(ivr) (((UINT32)(0x80)) << ((((unsigned)(ivr)) % 4) * 8))
++#define VLYNQ_IVR_INTTYPE(ivr) (((UINT32)(0x40)) << ((((unsigned)(ivr)) % 4) * 8))
++#define VLYNQ_IVR_INTPOL(ivr) (((UINT32)(0x20)) << ((((unsigned)(ivr)) % 4) * 8))
++#define VLYNQ_IVR_INTVEC(ivr) (((UINT32)(0x1F)) << ((((unsigned)(ivr)) % 4) * 8))
++#define VLYNQ_IVR_INTALL(ivr) (((UINT32)(0xFF)) << ((((unsigned)(ivr)) % 4) * 8))
++
++
++
++/*********************************
++ * Remote VLYNQ register set *
++ *********************************/
++
++#define VLYNQ_R_REV_OFFSET 0x0080
++#define VLYNQ_R_CTRL_OFFSET 0x0084
++#define VLYNQ_R_STATUS_OFFSET 0x0088
++#define VLYNQ_R_INT_STAT_OFFSET 0x0090
++#define VLYNQ_R_INT_PEND_OFFSET 0x0094
++#define VLYNQ_R_INT_PTR_OFFSET 0x0098
++#define VLYNQ_R_TXMAP_OFFSET 0x009c
++
++#define VLYNQ_R_RX0MAP_SIZE_REG_OFFSET 0x00A0
++#define VLYNQ_R_RX0MAP_OFFSET_REG_OFFSET 0x00A4
++
++#define VLYNQ_R_CHIP_VER_OFFSET 0x00C0
++#define VLYNQ_R_IVR_REGS_OFFSET 0x00E0
++
++#define VLYNQ_R_REV_REG *((volatile UINT32 *)(VLYNQ_BASE + VLYNQ_R_REV_OFFSET))
++#define VLYNQ_R_CTRL_REG *((volatile UINT32 *)(VLYNQ_BASE + VLYNQ_R_CTRL_OFFSET))
++#define VLYNQ_R_STATUS_REG *((volatile UINT32 *)(VLYNQ_BASE + VLYNQ_R_STATUS_OFFSET))
++#define VLYNQ_R_INT_STAT_REG *((volatile UINT32 *)(VLYNQ_BASE + VLYNQ_R_INT_STAT_OFFSET))
++#define VLYNQ_R_INT_PEND_REG *((volatile UINT32 *)(VLYNQ_BASE + VLYNQ_R_INT_PEND_OFFSET))
++#define VLYNQ_R_INT_PTR_REG *((volatile UINT32 *)(VLYNQ_BASE + VLYNQ_R_INT_PTR_OFFSET))
++#define VLYNQ_R_TXMAP_REG *((volatile UINT32 *)(VLYNQ_BASE + VLYNQ_R_TXMAP_OFFSET))
++
++/** map takes on values between 1 to VLYNQ_MAX_MEMORY_REGIONS **/
++#define VLYNQ_R_RXMAP_SIZE_REG(map) \
++ *((volatile UINT32 *)(VLYNQ_BASE + VLYNQ_R_RX0MAP_SIZE_REG_OFFSET + ((map-1)<<3)))
++
++/** map takes on values between 1 to VLYNQ_MAX_MEMORY_REGIONS **/
++#define VLYNQ_R_RXMAP_OFFSET_REG(map) \
++ *((volatile UINT32 *)(VLYNQ_BASE + VLYNQ_R_RX0MAP_OFFSET_REG_OFFSET + ((map-1)<<3)))
++
++#define VLYNQ_R_CHIP_VER_REG *((volatile UINT32 *)(VLYNQ_BASE + VLYNQ_R_CHIP_VER_OFFSET)
++
++#define VLYNQ_R_IVR_OFFSET(ivr) \
++ (VLYNQ_BASE + VLYNQ_R_IVR_REGS_OFFSET +((((unsigned)(ivr)) & 31) & ~3))
++
++
++/*** Can be extended for 11TO08...31TO28 when all 31 are supported**/
++#define VLYNQ_R_IVR_03TO00_REG *((volatile UINT32*) (VLYNQ_R_IVR_OFFSET(0)) )
++#define VLYNQ_R_IVR_07TO04_REG *((volatile UINT32*) (VLYNQ_R_IVR_OFFSET(4)) )
++
++
++/****End of remote register set definition******/
++
++
++/*** Masks for individual register fields ***/
++
++#define VLYNQ_MODULE_ID_MASK 0xffff0000
++#define VLYNQ_MAJOR_REV_MASK 0x0000ff00
++#define VLYNQ_MINOR_REV_MASK 0x000000ff
++
++
++#define VLYNQ_CTL_ILOOP_MASK 0x00000002
++#define VLYNQ_CTL_INT2CFG_MASK 0x00000080
++#define VLYNQ_CTL_INTVEC_MASK 0x00001f00
++#define VLYNQ_CTL_INTEN_MASK 0x00002000
++#define VLYNQ_CTL_INTLOCAL_MASK 0x00004000
++#define VLYNQ_CTL_CLKDIR_MASK 0x00008000
++#define VLYNQ_CTL_CLKDIV_MASK 0x00070000
++#define VLYNQ_CTL_MODE_MASK 0x00e00000
++
++
++#define VLYNQ_STS_LINK_MASK 0x00000001 /* Link is active */
++#define VLYNQ_STS_MPEND_MASK 0x00000002 /* Pending master requests */
++#define VLYNQ_STS_SPEND_MASK 0x00000004 /* Pending slave requests */
++#define VLYNQ_STS_NFEMPTY0_MASK 0x00000008 /* Master data FIFO not empty */
++#define VLYNQ_STS_NFEMPTY1_MASK 0x00000010 /* Master command FIFO not empty */
++#define VLYNQ_STS_NFEMPTY2_MASK 0x00000020 /* Slave data FIFO not empty */
++#define VLYNQ_STS_NFEMPTY3_MASK 0x00000040 /* Slave command FIFO not empty */
++#define VLYNQ_STS_LERROR_MASK 0x00000080 /* Local error, w/c */
++#define VLYNQ_STS_RERROR_MASK 0x00000100 /* remote error w/c */
++#define VLYNQ_STS_OFLOW_MASK 0x00000200
++#define VLYNQ_STS_IFLOW_MASK 0x00000400
++#define VLYNQ_STS_MODESUP_MASK 0x00E00000 /* Highest mode supported */
++#define VLYNQ_STS_SWIDTH_MASK 0x07000000 /* Used for reading the width of VLYNQ bus */
++#define VLYNQ_STS_DEBUG_MASK 0xE0000000
++
++#define VLYNQ_CTL_INTVEC_SHIFT 0x08
++#define VLYNQ_CTL_INTEN_SHIFT 0x0D
++#define VLYNQ_CTL_INT2CFG_SHIFT 0x07
++#define VLYNQ_CTL_INTLOCAL_SHIFT 0x0E
++
++#define VLYNQ_CTL_INTFIELDS_CLEAR_MASK 0x7F80
++
++#define VLYNQ_CHIPVER_DEVREV_MASK 0xffff0000
++#define VLYNQ_CHIPVER_DEVID_MASK 0x0000ffff
++
++#define VLYNQ_IVR_INTEN_MASK 0x80
++#define VLYNQ_IVR_INTTYPE_MASK 0x40
++#define VLYNQ_IVR_INTPOL_MASK 0x20
++
++
++/**** Helper macros ****/
++
++#define VLYNQ_RESETCB(arg) \
++ if( pdev->reset_cb != NULL) \
++ { \
++ (pdev->reset_cb)(pdev, (arg)); \
++ }
++
++#define VLYNQ_STATUS_FLD_WIDTH(sts) (((sts) & VLYNQ_STS_SWIDTH_MASK) >> 24 )
++#define VLYNQ_CTL_INTVEC(x) (((x) & 31) << 8 )
++
++#define VLYNQ_INRANGE(x,hi,lo) (((x) <= (hi)) && ((x) >= (lo)))
++#define VLYNQ_OUTRANGE(x,hi,lo) (((x) > (hi)) || ((x) < (lo)))
++
++#define VLYNQ_ALIGN4(x) (x)=(x)&(~3)
++
++
++/*************************************
++ * Enums *
++ *************************************/
++
++/* Initialization options define what operations are
++ * undertaken during vlynq module initialization */
++typedef enum
++{
++ /* Init host local memory regions.This allows
++ * local host access remote memory regions */
++ VLYNQ_INIT_LOCAL_MEM_REGIONS = 0x01,
++ /* Init host remote memory regions.This allows
++ * remote device access local memory regions */
++ VLYNQ_INIT_REMOTE_MEM_REGIONS =0x02,
++ /* Init local interrupt config*/
++ VLYNQ_INIT_LOCAL_INTERRUPTS =0x04,
++ /* Init remote interrupt config*/
++ VLYNQ_INIT_REMOTE_INTERRUPTS =0x08,
++ /* Check link during initialization*/
++ VLYNQ_INIT_CHECK_LINK =0x10,
++ /* configure clock during init */
++ VLYNQ_INIT_CONFIG_CLOCK =0x20,
++ /* Clear errors during init */
++ VLYNQ_INIT_CLEAR_ERRORS =0x40,
++ /* All options */
++ VLYNQ_INIT_PERFORM_ALL =0x7F
++}VLYNQ_INIT_OPTIONS;
++
++
++/* VLYNQ_DEV_TYPE identifies local or remote device */
++typedef enum
++{
++ VLYNQ_LOCAL_DVC = 0, /* vlynq local device (SOC's vlynq module) */
++ VLYNQ_REMOTE_DVC = 1 /* vlynq remote device (remote vlynq module) */
++}VLYNQ_DEV_TYPE;
++
++
++/* VLYNQ_CLK_SOURCE identifies the vlynq module clock source */
++typedef enum
++{
++ VLYNQ_CLK_SOURCE_NONE = 0, /* do not initialize clock generator*/
++ VLYNQ_CLK_SOURCE_LOCAL = 1, /* clock is generated by local machine */
++ VLYNQ_CLK_SOURCE_REMOTE = 2 /* clock is generated by remote machine */
++}VLYNQ_CLK_SOURCE;
++
++
++/* VLYNQ_DRV_STATE indicates the current driver state */
++typedef enum
++{
++ VLYNQ_DRV_STATE_UNINIT = 0, /* driver is uninitialized */
++ VLYNQ_DRV_STATE_ININIT = 1, /* VLYNQ is being initialized */
++ VLYNQ_DRV_STATE_RUN = 2, /* VLYNQ is running properly */
++ VLYNQ_DRV_STATE_HOLD = 3, /* driver stopped temporarily */
++ VLYNQ_DRV_STATE_ERROR = 4 /* driver stopped on unrecoverable error */
++}VLYNQ_DRV_STATE;
++
++
++/* VLYNQ_BUS_WIDTH identifies the vlynq module bus width */
++typedef enum
++{
++ VLYNQ_BUS_WIDTH_3 = 3,
++ VLYNQ_BUS_WIDTH_5 = 5,
++ VLYNQ_BUS_WIDTH_7 = 7,
++ VLYNQ_BUS_WIDTH_9 = 9
++}VLYNQ_BUS_WIDTH;
++
++
++/* VLYNQ_LOCAL_INT_CONFIG indicates whether the local vlynq
++ * interrupts are processed by the host or passed on to the
++ * remote device.
++ */
++typedef enum
++{
++ VLYNQ_INT_REMOTE = 0, /* Interrupt packets sent to remote, intlocal=0 */
++ VLYNQ_INT_LOCAL = 1 /* Interrupts are handled locally, intlocal=1 */
++}VLYNQ_LOCAL_INT_CONFIG;
++
++
++/* VLYNQ_REMOTE_INT_CONFIG indicates whether the remote
++ * interrupts are to be handled by the SOC system ISR
++ * or via the vlynq root ISR
++ */
++typedef enum
++{
++ VLYNQ_INT_ROOT_ISR = 0, /* remote ints handled via vlynq root ISR */
++ VLYNQ_INT_SYSTEM_ISR = 1 /* remote ints handled via system ISR */
++}VLYNQ_REMOTE_INT_CONFIG;
++
++
++/* VLYNQ_INTR_POLARITY - vlynq interrupt polarity setting */
++typedef enum
++{
++ VLYNQ_INTR_ACTIVE_HIGH = 0,
++ VLYNQ_INTR_ACTIVE_LOW = 1
++}VLYNQ_INTR_POLARITY;
++
++
++/* VLYNQ_INTR_TYPE - vlynq interrupt type */
++typedef enum
++{
++ VLYNQ_INTR_LEVEL = 0,
++ VLYNQ_INTR_PULSED = 1
++}VLYNQ_INTR_TYPE;
++
++
++/* VLYNQ_RESET_MODE - vlynq reset mode */
++typedef enum
++{
++ VLYNQ_RESET_ASSERT, /* hold device in reset state */
++ VLYNQ_RESET_DEASSERT, /* release device from reset state */
++ VLYNQ_RESET_INITFAIL, /* handle the device in case driver initialization fails */
++ VLYNQ_RESET_LINKESTABLISH, /* handle the device in case driver established link */
++ VLYNQ_RESET_INITFAIL2, /* Driver initialization failed but VLYNQ link exist. */
++ VLYNQ_RESET_INITOK /* Driver initialization finished OK. */
++}VLYNQ_RESET_MODE;
++
++
++
++/*************************************
++ * Typedefs *
++ *************************************/
++
++struct VLYNQ_DEV_t; /*forward declaration*/
++
++/*--------Function Pointers defintions -----------*/
++
++/* prototype for interrupt handler definition */
++typedef void (*VLYNQ_INTR_CNTRL_ISR)(void *arg1,void *arg2,void *arg3);
++
++typedef void
++(*VLYNQ_RESET_REMOTE)(struct VLYNQ_DEV_t *pDev, VLYNQ_RESET_MODE mode);
++
++typedef void
++(*VLYNQ_REPORT_CB)( struct VLYNQ_DEV_t *pDev, /* This VLYNQ */
++ VLYNQ_DEV_TYPE aSrcDvc, /* Event Cause -local/remote? */
++ UINT32 dwStatRegVal); /* Value of the relevant status register */
++
++
++/*-------Structure Definitions------------*/
++
++typedef struct VLYNQ_MEMORY_MAP_t
++{
++ UINT32 Txmap;
++ UINT32 RxOffset[VLYNQ_MAX_MEMORY_REGIONS];
++ UINT32 RxSize[VLYNQ_MAX_MEMORY_REGIONS];
++}VLYNQ_MEMORY_MAP;
++
++
++/**VLYNQ_INTERRUPT_CNTRL - defines the vlynq module interrupt
++ * settings in vlynq Control register */
++typedef struct VLYNQ_INTERRUPT_CNTRL_t
++{
++ /* vlynq interrupts handled by host or remote - maps to
++ * intLocal bit in vlynq control register */
++ VLYNQ_LOCAL_INT_CONFIG intLocal;
++
++ /* remote interrupts handled by vlynq isr or host system
++ * interrupt controller - maps to the int2Cfg in vlynq
++ * control register */
++ VLYNQ_REMOTE_INT_CONFIG intRemote;
++
++ /* bit in pending/set register used for module interrupts*/
++ UINT32 map_vector;
++
++ /* used only if remote interrupts are to be handled by system ISR*/
++ UINT32 intr_ptr;
++
++}VLYNQ_INTERRUPT_CNTRL;
++
++
++/* VLYNQ_INTR_CNTRL_ICB - defines the Interrupt control block which hold
++ * the interrupt dispatch table. The vlynq_root_isr() indexes into this
++ * table to identify the ISR to be invoked
++ */
++typedef struct VLYNQ_INTR_CNTRL_ICB_t
++{
++ VLYNQ_INTR_CNTRL_ISR isr; /* Clear errors during initialization */
++ void *arg1 ; /* Arg 1 for the ISR */
++ void *arg2 ; /* Arg 2 for the ISR */
++ void *arg3 ; /* Arg 3 for the ISR */
++ UINT32 isrCount; /* number of ISR invocations so far */
++ struct VLYNQ_INTR_CNTRL_ICB_t *next;
++}VLYNQ_INTR_CNTRL_ICB;
++
++/* overlay of vlynq register set */
++typedef struct VLYNQ_REG_SET_t
++{
++ UINT32 revision; /*offset : 0x00 */
++ UINT32 control; /* 0x04*/
++ UINT32 status; /* 0x08*/
++ UINT32 pad1; /* 0x0c*/
++ UINT32 intStatus; /*0x10*/
++ UINT32 intPending; /*0x14*/
++ UINT32 intPtr; /*0x18*/
++ UINT32 txMap; /*0x1C*/
++ UINT32 rxSize1; /*0x20*/
++ UINT32 rxOffset1; /*0x24*/
++ UINT32 rxSize2; /*0x28*/
++ UINT32 rxOffset2; /*0x2C*/
++ UINT32 rxSize3; /*0x30*/
++ UINT32 rxOffset3; /*0x34*/
++ UINT32 rxSize4; /*0x38*/
++ UINT32 rxOffset4; /*0x3C*/
++ UINT32 chipVersion; /*0x40*/
++ UINT32 pad2[8];
++ UINT32 ivr30; /*0x60*/
++ UINT32 ivr74; /*0x64*/
++ UINT32 pad3[7];
++}VLYNQ_REG_SET;
++
++
++typedef struct VLYNQ_DEV_t
++{
++ /** module index:1,2,3... used for debugging purposes */
++ UINT32 dev_idx;
++
++ /*VLYNQ module base address */
++ UINT32 module_base;
++
++ /* clock source selection */
++ VLYNQ_CLK_SOURCE clk_source;
++
++ /* Clock Divider.Val=1 to 8. VLYNQ_clk = VBUSCLK/clk_div */
++ UINT32 clk_div;
++
++ /* State of the VLYNQ driver, set to VLYNQ_DRV_STATE_UNINIT, when initializing */
++ VLYNQ_DRV_STATE state;
++
++ /* Valid VLYNQ bus width, filled by driver */
++ VLYNQ_BUS_WIDTH width;
++
++ /* local memory mapping */
++ VLYNQ_MEMORY_MAP local_mem;
++
++ /* remote memory mapping */
++ VLYNQ_MEMORY_MAP remote_mem;
++
++ /* Local module interrupt params */
++ VLYNQ_INTERRUPT_CNTRL local_irq;
++
++ /* remote module interrupt params */
++ VLYNQ_INTERRUPT_CNTRL remote_irq;
++
++ /*** ICB related fields **/
++
++ /* Sizeof of ICB = VLYNQ_NUM_INT_BITS(for 32 bits in IntPending) +
++ * expansion slots for shared interrupts*/
++ VLYNQ_INTR_CNTRL_ICB pIntrCB[VLYNQ_NUM_INT_BITS + VLYNQ_IVR_CHAIN_SLOTS];
++ VLYNQ_INTR_CNTRL_ICB *freelist;
++
++ /* table holding mapping between intVector and the bit position the interrupt
++ * is mapped to(mapVector)*/
++ INT8 vector_map[32];
++
++ /* user callback for vlynq events, NULL if unused */
++ VLYNQ_REPORT_CB report_cb;
++
++ /* user callback for resetting/realeasing remote device */
++ VLYNQ_RESET_REMOTE reset_cb;
++
++ /*** Handles provided for direct access to register set if need be
++ * Must be intialized to point to appropriate address during
++ * vlynq_init */
++ volatile VLYNQ_REG_SET * local;
++ volatile VLYNQ_REG_SET * remote;
++
++ UINT32 intCount; /* number of interrupts generated so far */
++ UINT32 isrCount; /* number of ISR invocations so far */
++}VLYNQ_DEV;
++
++
++typedef struct VLYNQ_ISR_ARGS_t
++{
++ int irq;
++ void * arg;
++ void * regset;
++}VLYNQ_ISR_ARGS;
++
++
++/****************************************
++ * Function Prototypes *
++ * API exported by generic vlynq driver *
++ ****************************************/
++/* Initialization function */
++GLOBAL INT32 vlynq_init( VLYNQ_DEV *pdev, VLYNQ_INIT_OPTIONS options);
++
++/* Check vlynq link */
++GLOBAL UINT32 vlynq_link_check( VLYNQ_DEV * pdev);
++
++/* Set interrupt vector in local or remote device */
++GLOBAL INT32 vlynq_interrupt_vector_set( VLYNQ_DEV *pdev,
++ UINT32 int_vector,
++ UINT32 map_vector,
++ VLYNQ_DEV_TYPE dev,
++ VLYNQ_INTR_POLARITY pol,
++ VLYNQ_INTR_TYPE type);
++
++
++GLOBAL INT32 vlynq_interrupt_vector_cntl( VLYNQ_DEV *pdev,
++ UINT32 int_vector,
++ VLYNQ_DEV_TYPE dev,
++ UINT32 enable);
++
++GLOBAL UINT32 vlynq_interrupt_get_count( VLYNQ_DEV *pdev,
++ UINT32 map_vector);
++
++GLOBAL INT32 vlynq_install_isr( VLYNQ_DEV *pdev,
++ UINT32 map_vector,
++ VLYNQ_INTR_CNTRL_ISR isr,
++ void *arg1, void *arg2, void *arg3);
++
++GLOBAL INT32 vlynq_uninstall_isr( VLYNQ_DEV *pdev,
++ UINT32 map_vector,
++ void *arg1, void *arg2, void *arg3);
++
++
++GLOBAL void vlynq_root_isr(void *arg);
++
++GLOBAL void vlynq_delay(UINT32 clktime);
++
++/* The following functions, provide better granularity in setting
++ * interrupt parameters. (for better support of linux INT Controller)
++ * Note: The interrupt source is identified by "map_vector"- the bit
++ * position in interrupt status register*/
++
++GLOBAL INT32 vlynq_interrupt_vector_map(VLYNQ_DEV * pdev,
++ VLYNQ_DEV_TYPE dev,
++ UINT32 int_vector,
++ UINT32 map_vector);
++
++GLOBAL INT32 vlynq_interrupt_set_polarity(VLYNQ_DEV * pdev,
++ VLYNQ_DEV_TYPE dev,
++ UINT32 map_vector,
++ VLYNQ_INTR_POLARITY pol);
++
++GLOBAL INT32 vlynq_interrupt_get_polarity( VLYNQ_DEV *pdev ,
++ VLYNQ_DEV_TYPE dev_type,
++ UINT32 map_vector);
++
++GLOBAL INT32 vlynq_interrupt_set_type(VLYNQ_DEV * pdev,
++ VLYNQ_DEV_TYPE dev,
++ UINT32 map_vector,
++ VLYNQ_INTR_TYPE type);
++
++GLOBAL INT32 vlynq_interrupt_get_type( VLYNQ_DEV *pdev,
++ VLYNQ_DEV_TYPE dev_type,
++ UINT32 map_vector);
++
++GLOBAL INT32 vlynq_interrupt_enable(VLYNQ_DEV* pdev,
++ VLYNQ_DEV_TYPE dev,
++ UINT32 map_vector);
++
++GLOBAL INT32 vlynq_interrupt_disable(VLYNQ_DEV * pdev,
++ VLYNQ_DEV_TYPE dev,
++ UINT32 map_vector);
++
++
++
++
++
++#endif /* _VLYNQ_HAL_H_ */
+diff -urN linux.old/include/asm-mips/ar7/vlynq_hal_params.h linux.dev/include/asm-mips/ar7/vlynq_hal_params.h
+--- linux.old/include/asm-mips/ar7/vlynq_hal_params.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/ar7/vlynq_hal_params.h 2005-11-10 01:10:46.095590250 +0100
+@@ -0,0 +1,50 @@
++/***************************************************************************
++**+----------------------------------------------------------------------+**
++**| **** |**
++**| **** |**
++**| ******o*** |**
++**| ********_///_**** |**
++**| ***** /_//_/ **** |**
++**| ** ** (__/ **** |**
++**| ********* |**
++**| **** |**
++**| *** |**
++**| |**
++**| Copyright (c) 2003 Texas Instruments Incorporated |**
++**| ALL RIGHTS RESERVED |**
++**| |**
++**| Permission is hereby granted to licensees of Texas Instruments |**
++**| Incorporated (TI) products to use this computer program for the sole |**
++**| purpose of implementing a licensee product based on TI products. |**
++**| No other rights to reproduce, use, or disseminate this computer |**
++**| program, whether in part or in whole, are granted. |**
++**| |**
++**| TI makes no representation or warranties with respect to the |**
++**| performance of this computer program, and specifically disclaims |**
++**| any responsibility for any damages, special or consequential, |**
++**| connected with the use of this program. |**
++**| |**
++**+----------------------------------------------------------------------+**
++***************************************************************************/
++
++/* This file defines Vlynq module parameters*/
++
++#ifndef _VLYNQ_HAL_PARAMS_H
++#define _VLYNQ_HAL_PARAMS_H
++
++ /* number of VLYNQ memory regions supported */
++#define VLYNQ_MAX_MEMORY_REGIONS 0x04
++
++ /* Max.number of external interrupt inputs supported by VLYNQ module */
++#define VLYNQ_IVR_MAXIVR 0x08
++
++#define VLYNQ_CLK_DIV_MAX 0x08
++#define VLYNQ_CLK_DIV_MIN 0x01
++
++
++/*** the total number of entries allocated for ICB would be
++ * 32(for 32 bits in IntPending register) + VLYNQ_IVR_CHAIN_SLOTS*/
++#define VLYNQ_IVR_CHAIN_SLOTS 10
++
++
++#endif /* _VLYNQ_HAL_PARAMS_H */
+diff -urN linux.old/include/asm-mips/io.h linux.dev/include/asm-mips/io.h
+--- linux.old/include/asm-mips/io.h 2003-08-25 13:44:43.000000000 +0200
++++ linux.dev/include/asm-mips/io.h 2005-11-10 01:14:16.400733500 +0100
+@@ -61,9 +61,9 @@
+ * Change "struct page" to physical address.
+ */
+ #ifdef CONFIG_64BIT_PHYS_ADDR
+-#define page_to_phys(page) ((u64)(page - mem_map) << PAGE_SHIFT)
++#define page_to_phys(page) (((u64)(page - mem_map) << PAGE_SHIFT) + PHYS_OFFSET)
+ #else
+-#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT)
++#define page_to_phys(page) (((page - mem_map) << PAGE_SHIFT) + PHYS_OFFSET)
+ #endif
+
+ #define IO_SPACE_LIMIT 0xffff
+diff -urN linux.old/include/asm-mips/irq.h linux.dev/include/asm-mips/irq.h
+--- linux.old/include/asm-mips/irq.h 2003-08-25 13:44:43.000000000 +0200
++++ linux.dev/include/asm-mips/irq.h 2005-11-10 01:12:43.950955750 +0100
+@@ -14,7 +14,20 @@
+ #include <linux/config.h>
+ #include <linux/linkage.h>
+
++#ifdef CONFIG_AR7
++/* MIPS has 8 irqs
++ * AR7 has 40 primary and 32 secondary irqs
++ * vlynq0 has 32 irqs
++ * vlynq1 has 32 irqs
++ */
++#ifdef CONFIG_AR7_VLYNQ
++#define NR_IRQS (80 + 32 * CONFIG_AR7_VLYNQ_PORTS)
++#else
++#define NR_IRQS 80
++#endif
++#else
+ #define NR_IRQS 128 /* Largest number of ints of all machines. */
++#endif
+
+ #ifdef CONFIG_I8259
+ static inline int irq_cannonicalize(int irq)
+diff -urN linux.old/include/asm-mips/mips-boards/prom.h linux.dev/include/asm-mips/mips-boards/prom.h
+--- linux.old/include/asm-mips/mips-boards/prom.h 2001-09-09 19:43:02.000000000 +0200
++++ linux.dev/include/asm-mips/mips-boards/prom.h 2005-11-10 01:14:16.436735750 +0100
+@@ -33,7 +33,7 @@
+ extern void prom_init_cmdline(void);
+ extern void prom_meminit(void);
+ extern void prom_fixup_mem_map(unsigned long start_mem, unsigned long end_mem);
+-extern void prom_free_prom_memory (void);
++extern unsigned long prom_free_prom_memory (void);
+ extern void mips_display_message(const char *str);
+ extern void mips_display_word(unsigned int num);
+ extern int get_ethernet_addr(char *ethernet_addr);
+diff -urN linux.old/include/asm-mips/page.h linux.dev/include/asm-mips/page.h
+--- linux.old/include/asm-mips/page.h 2004-02-18 14:36:32.000000000 +0100
++++ linux.dev/include/asm-mips/page.h 2005-11-10 01:14:16.436735750 +0100
+@@ -12,6 +12,7 @@
+
+ #include <linux/config.h>
+ #include <asm/break.h>
++#include <asm/addrspace.h>
+
+ #ifdef __KERNEL__
+
+@@ -129,7 +130,7 @@
+
+ #define __pa(x) ((unsigned long) (x) - PAGE_OFFSET)
+ #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET))
+-#define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT))
++#define virt_to_page(kaddr) (mem_map + ((__pa(kaddr)-PHYS_OFFSET) >> PAGE_SHIFT))
+ #define VALID_PAGE(page) ((page - mem_map) < max_mapnr)
+
+ #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
+diff -urN linux.old/include/asm-mips/pgtable-32.h linux.dev/include/asm-mips/pgtable-32.h
+--- linux.old/include/asm-mips/pgtable-32.h 2004-02-18 14:36:32.000000000 +0100
++++ linux.dev/include/asm-mips/pgtable-32.h 2005-11-10 01:14:16.436735750 +0100
+@@ -108,7 +108,7 @@
+ * and a page entry and page directory to the page they refer to.
+ */
+
+-#ifdef CONFIG_CPU_VR41XX
++#if defined(CONFIG_CPU_VR41XX)
+ #define mk_pte(page, pgprot) \
+ ({ \
+ pte_t __pte; \
+@@ -123,13 +123,14 @@
+ ({ \
+ pte_t __pte; \
+ \
+- pte_val(__pte) = ((phys_t)(page - mem_map) << PAGE_SHIFT) | \
+- pgprot_val(pgprot); \
++ pte_val(__pte) = (((phys_t)(page - mem_map) << PAGE_SHIFT) + \
++ PHYS_OFFSET) | pgprot_val(pgprot); \
+ \
+ __pte; \
+ })
+ #endif
+
++
+ static inline pte_t mk_pte_phys(phys_t physpage, pgprot_t pgprot)
+ {
+ #ifdef CONFIG_CPU_VR41XX
+@@ -175,12 +176,12 @@
+ set_pte(ptep, __pte(0));
+ }
+
+-#ifdef CONFIG_CPU_VR41XX
++#if defined(CONFIG_CPU_VR41XX)
+ #define pte_page(x) (mem_map+((unsigned long)(((x).pte_low >> (PAGE_SHIFT+2)))))
+ #define __mk_pte(page_nr,pgprot) __pte(((page_nr) << (PAGE_SHIFT+2)) | pgprot_val(pgprot))
+ #else
+-#define pte_page(x) (mem_map+((unsigned long)(((x).pte_low >> PAGE_SHIFT))))
+-#define __mk_pte(page_nr,pgprot) __pte(((page_nr) << PAGE_SHIFT) | pgprot_val(pgprot))
++#define pte_page(x) (mem_map+((unsigned long)((((x).pte_low-PHYS_OFFSET) >> PAGE_SHIFT))))
++#define __mk_pte(page_nr,pgprot) __pte((((page_nr) << PAGE_SHIFT)+PHYS_OFFSET)|pgprot_val(pgprot))
+ #endif
+
+ #endif
+diff -urN linux.old/include/asm-mips/serial.h linux.dev/include/asm-mips/serial.h
+--- linux.old/include/asm-mips/serial.h 2005-01-19 15:10:12.000000000 +0100
++++ linux.dev/include/asm-mips/serial.h 2005-11-10 01:14:16.436735750 +0100
+@@ -65,6 +65,16 @@
+
+ #define C_P(card,port) (((card)<<6|(port)<<3) + 1)
+
++#ifdef CONFIG_AR7
++#include <asm/ar7/ar7.h>
++#include <asm/ar7/avalanche_intc.h>
++#define AR7_SERIAL_PORT_DEFNS \
++ { 0, AR7_BASE_BAUD, AR7_UART0_REGS_BASE, LNXINTNUM(AVALANCHE_UART0_INT), STD_COM_FLAGS }, \
++ { 0, AR7_BASE_BAUD, AR7_UART1_REGS_BASE, LNXINTNUM(AVALANCHE_UART1_INT), STD_COM_FLAGS },
++#else
++#define AR7_SERIAL_PORT_DEFNS
++#endif
++
+ #ifdef CONFIG_MIPS_JAZZ
+ #define _JAZZ_SERIAL_INIT(int, base) \
+ { .baud_base = JAZZ_BASE_BAUD, .irq = int, .flags = STD_COM_FLAGS, \
+@@ -468,6 +478,7 @@
+ #endif
+
+ #define SERIAL_PORT_DFNS \
++ AR7_SERIAL_PORT_DEFNS \
+ ATLAS_SERIAL_PORT_DEFNS \
+ AU1000_SERIAL_PORT_DEFNS \
+ COBALT_SERIAL_PORT_DEFNS \
diff --git a/target/linux/ar7-2.4/patches/001-flash_map.patch b/target/linux/ar7-2.4/patches/001-flash_map.patch
new file mode 100644
index 0000000..0b58439
--- /dev/null
+++ b/target/linux/ar7-2.4/patches/001-flash_map.patch
@@ -0,0 +1,307 @@
+diff -urN linux.old/drivers/mtd/maps/ar7-flash.c linux.dev/drivers/mtd/maps/ar7-flash.c
+--- linux.old/drivers/mtd/maps/ar7-flash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/mtd/maps/ar7-flash.c 2005-07-22 04:35:26.624453992 +0200
+@@ -0,0 +1,267 @@
++/*
++ * $Id$
++ *
++ * Normal mappings of chips in physical memory
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <asm/io.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/config.h>
++#include <linux/mtd/partitions.h>
++#include <linux/squashfs_fs.h>
++
++#define WINDOW_ADDR CONFIG_MTD_AR7_START
++#define WINDOW_SIZE CONFIG_MTD_AR7_LEN
++#define BUSWIDTH CONFIG_MTD_AR7_BUSWIDTH
++
++#include <asm/mips-boards/prom.h>
++extern char *prom_getenv(char *name);
++
++static int create_mtd_partitions(void);
++static void __exit ar7_mtd_cleanup(void);
++
++#define MAX_NUM_PARTITIONS 5
++static struct mtd_partition ar7_partinfo[MAX_NUM_PARTITIONS];
++
++static struct mtd_info *ar7_mtd_info;
++
++__u8 ar7_read8(struct map_info *map, unsigned long ofs)
++{
++ return __raw_readb(map->map_priv_1 + ofs);
++}
++
++__u16 ar7_read16(struct map_info *map, unsigned long ofs)
++{
++ return __raw_readw(map->map_priv_1 + ofs);
++}
++
++__u32 ar7_read32(struct map_info *map, unsigned long ofs)
++{
++ return __raw_readl(map->map_priv_1 + ofs);
++}
++
++void ar7_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++ memcpy_fromio(to, map->map_priv_1 + from, len);
++}
++
++void ar7_write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++ __raw_writeb(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void ar7_write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++ __raw_writew(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void ar7_write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++ __raw_writel(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void ar7_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
++{
++ memcpy_toio(map->map_priv_1 + to, from, len);
++}
++
++struct map_info ar7_map = {
++ name: "Physically mapped flash",
++ size: WINDOW_SIZE,
++ buswidth: BUSWIDTH,
++ read8: ar7_read8,
++ read16: ar7_read16,
++ read32: ar7_read32,
++ copy_from: ar7_copy_from,
++ write8: ar7_write8,
++ write16: ar7_write16,
++ write32: ar7_write32,
++ copy_to: ar7_copy_to
++};
++
++int __init ar7_mtd_init(void)
++{
++ int partitions;
++
++ printk(KERN_NOTICE "ar7 flash device: 0x%lx at 0x%lx.\n", (unsigned long)WINDOW_SIZE, (unsigned long)WINDOW_ADDR);
++ ar7_map.map_priv_1 = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE);
++
++ if (!ar7_map.map_priv_1) {
++ printk("Failed to ioremap\n");
++ return -EIO;
++ }
++
++ ar7_mtd_info = do_map_probe("cfi_probe", &ar7_map);
++ if (!ar7_mtd_info)
++ {
++ ar7_mtd_cleanup();
++ return -ENXIO;
++ }
++
++ ar7_mtd_info->module = THIS_MODULE;
++
++ if (!(partitions = create_mtd_partitions()))
++ add_mtd_device(ar7_mtd_info);
++ else
++ add_mtd_partitions(ar7_mtd_info, ar7_partinfo, partitions);
++
++ return 0;
++}
++
++static char *strdup(char *str)
++{
++ int n = strlen(str)+1;
++ char *s = kmalloc(n, GFP_KERNEL);
++ if (!s) return NULL;
++ return strcpy(s, str);
++}
++
++
++static int create_mtd_partitions(void)
++{
++ unsigned int offset;
++ unsigned int size;
++ unsigned int found = 0;
++ unsigned int p = 0;
++ unsigned char *flash_base;
++ unsigned char *flash_end;
++ char *env_ptr;
++ char *base_ptr;
++ char *end_ptr;
++ unsigned int adam2_size = 0x20000;
++ unsigned int config_offset = WINDOW_SIZE;
++ unsigned int rootfs_start = 0xe0000;
++
++ printk("Parsing ADAM2 partition map...\n");
++
++ do {
++ char env_name[20];
++
++ /* get base and end addresses of flash file system from environment */
++ sprintf(env_name, "mtd%1u", p);
++ printk("Looking for mtd device :%s:\n", env_name);
++
++ env_ptr = prom_getenv(env_name);
++ if(env_ptr == NULL) {
++ /* No more partitions to find */
++ break;
++ }
++
++ /* Extract the start and stop addresses of the partition */
++ base_ptr = strtok(env_ptr, ",");
++ end_ptr = strtok(NULL, ",");
++ if ((base_ptr == NULL) || (end_ptr == NULL)) {
++ printk("ADAM2 partition error: Invalid %s start,end.\n", env_name);
++ break;
++ }
++
++ flash_base = (unsigned char*) simple_strtol(base_ptr, NULL, 0);
++ flash_end = (unsigned char*) simple_strtol(end_ptr, NULL, 0);
++ if((!flash_base) || (!flash_end)) {
++ printk("ADAM2 partition error: Invalid %s start,end.\n", env_name);
++ break;
++ }
++
++ offset = virt_to_bus(flash_base) - WINDOW_ADDR;
++ size = flash_end - flash_base;
++ printk("Found a %s image (0x%x), with size (0x%x).\n",env_name, offset, size);
++
++
++ if (offset == 0) {
++ printk("Assuming adam2 size of 0x%x\n", size);
++ adam2_size = size; // boot loader
++ } else if (offset > 0x120000) {
++ if (config_offset > offset)
++ config_offset = offset; // reserved at the end of the flash chip
++ } else if (offset > 0x30000) {
++ printk("Assuming default rootfs offset of 0x%x\n", offset);
++ rootfs_start = offset; // probably root fs
++ }
++
++ p++;
++ } while (p < MAX_NUM_PARTITIONS);
++
++ p = 0;
++
++ ar7_partinfo[p].name = strdup("adam2");
++ ar7_partinfo[p].offset = 0;
++ ar7_partinfo[p].size = adam2_size;
++ ar7_partinfo[p++].mask_flags = 0;
++
++ ar7_partinfo[p].name = strdup("linux");
++ ar7_partinfo[p].offset = adam2_size;
++ ar7_partinfo[p].size = config_offset - adam2_size;
++ ar7_partinfo[p++].mask_flags = 0;
++
++ if (ar7_read32(&ar7_map, adam2_size) == 0xfeedfa42) {
++ rootfs_start = ar7_read32(&ar7_map, adam2_size + 4) + adam2_size + 28;
++ printk("Setting new rootfs offset to %08x\n", rootfs_start);
++ }
++
++ ar7_partinfo[p].name = strdup("rootfs");
++ ar7_partinfo[p].offset = rootfs_start;
++ ar7_partinfo[p].size = config_offset - rootfs_start;
++
++ ar7_partinfo[p++].mask_flags = 0;
++
++ ar7_partinfo[p].name = strdup("config");
++ ar7_partinfo[p].offset = config_offset;
++ ar7_partinfo[p].size = WINDOW_SIZE - config_offset;
++ ar7_partinfo[p++].mask_flags = 0;
++
++ if (ar7_read32(&ar7_map, rootfs_start) == SQUASHFS_MAGIC) {
++ int newsize, newoffset;
++ struct squashfs_super_block sb;
++
++ ar7_copy_from(&ar7_map, &sb, rootfs_start, sizeof(sb));
++ printk("Squashfs detected (size = 0x%08x)\n", sb.bytes_used);
++
++ newoffset = rootfs_start + sb.bytes_used;
++
++ if ((newoffset % ar7_mtd_info->erasesize) > 0)
++ newoffset += ar7_mtd_info->erasesize - (newoffset % ar7_mtd_info->erasesize);
++
++ ar7_partinfo[p - 2].size = newoffset - rootfs_start;
++
++ ar7_partinfo[p].name = strdup("OpenWrt");
++ ar7_partinfo[p].offset = newoffset;
++ ar7_partinfo[p].size = config_offset - newoffset;
++ ar7_partinfo[p++].mask_flags = 0;
++ } else {
++ printk("Unknown filesystem. Moving rootfs partition to next erase block");
++ if ((rootfs_start % ar7_mtd_info->erasesize) > 0) {
++ ar7_partinfo[p - 2].offset += ar7_mtd_info->erasesize - (rootfs_start % ar7_mtd_info->erasesize);
++ ar7_partinfo[p - 2].size -= ar7_mtd_info->erasesize - (rootfs_start % ar7_mtd_info->erasesize);
++ }
++ }
++
++ return p;
++}
++
++static void __exit ar7_mtd_cleanup(void)
++{
++ if (ar7_mtd_info) {
++ del_mtd_partitions(ar7_mtd_info);
++ del_mtd_device(ar7_mtd_info);
++ map_destroy(ar7_mtd_info);
++ }
++
++ if (ar7_map.map_priv_1) {
++ iounmap((void *)ar7_map.map_priv_1);
++ ar7_map.map_priv_1 = 0;
++ }
++}
++
++module_init(ar7_mtd_init);
++module_exit(ar7_mtd_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Felix Fietkau");
++MODULE_DESCRIPTION("AR7 CFI map driver");
+diff -urN linux.old/drivers/mtd/maps/Config.in linux.dev/drivers/mtd/maps/Config.in
+--- linux.old/drivers/mtd/maps/Config.in 2005-07-21 05:36:32.414242296 +0200
++++ linux.dev/drivers/mtd/maps/Config.in 2005-07-21 06:29:04.067118232 +0200
+@@ -48,6 +48,21 @@
+ fi
+
+ if [ "$CONFIG_MIPS" = "y" ]; then
++ if [ "$CONFIG_AR7" = "y" ]; then
++ dep_tristate ' Flash chip mapping on Texas Instruments AR7' CONFIG_MTD_AR7 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS
++ dep_bool ' Use defaults for Texas Instruments AR7' CONFIG_MTD_AR7_DEFAULTS $CONFIG_MTD_AR7
++ if [ "$CONFIG_MTD_AR7" = "y" -o "$CONFIG_MTD_AR7" = "m" ]; then
++ if [ "$CONFIG_MTD_AR7_DEFAULTS" = "y" ]; then
++ define_hex CONFIG_MTD_AR7_START 0x10000000
++ define_hex CONFIG_MTD_AR7_LEN 0x400000
++ define_int CONFIG_MTD_AR7_BUSWIDTH 2
++ else
++ hex ' Physical start address of flash mapping' CONFIG_MTD_AR7_START 0x10000000
++ hex ' Physical length of flash mapping' CONFIG_MTD_AR7_LEN 0x400000
++ int ' Bus width in octets' CONFIG_MTD_AR7_BUSWIDTH 2
++ fi
++ fi
++ fi
+ dep_tristate ' Pb1000 MTD support' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000
+ dep_tristate ' Pb1500 MTD support' CONFIG_MTD_PB1500 $CONFIG_MIPS_PB1500
+ dep_tristate ' Pb1100 MTD support' CONFIG_MTD_PB1100 $CONFIG_MIPS_PB1100
+diff -urN linux.old/drivers/mtd/maps/Makefile linux.dev/drivers/mtd/maps/Makefile
+--- linux.old/drivers/mtd/maps/Makefile 2005-07-21 05:36:32.414242296 +0200
++++ linux.dev/drivers/mtd/maps/Makefile 2005-07-21 06:56:33.265401984 +0200
+@@ -10,6 +10,7 @@
+ endif
+
+ # Chip mappings
++obj-$(CONFIG_MTD_AR7) += ar7-flash.o
+ obj-$(CONFIG_MTD_CDB89712) += cdb89712.o
+ obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
+ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
diff --git a/target/linux/ar7-2.4/patches/002-led_driver.patch b/target/linux/ar7-2.4/patches/002-led_driver.patch
new file mode 100644
index 0000000..81fe153
--- /dev/null
+++ b/target/linux/ar7-2.4/patches/002-led_driver.patch
@@ -0,0 +1,1915 @@
+diff -urN linux.dev/drivers/char/Config.in linux.dev2/drivers/char/Config.in
+--- linux.dev/drivers/char/Config.in 2005-10-21 17:02:20.199991500 +0200
++++ linux.dev2/drivers/char/Config.in 2005-10-21 18:03:44.541778750 +0200
+@@ -133,6 +133,10 @@
+ fi
+ fi
+ fi
++if [ "$CONFIG_AR7" = "y" ]; then
++ bool 'Enable LED support' CONFIG_AR7_LED
++fi
++
+ if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then
+ tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232
+ fi
+diff -urN linux.dev/drivers/char/Makefile linux.dev2/drivers/char/Makefile
+--- linux.dev/drivers/char/Makefile 2005-10-21 17:02:20.199991500 +0200
++++ linux.dev2/drivers/char/Makefile 2005-10-21 18:03:44.541778750 +0200
+@@ -190,6 +190,12 @@
+ obj-$(CONFIG_PCI) += keyboard.o $(KEYMAP)
+ endif
+
++#
++# Texas Intruments LED driver
++#
++obj-$(CONFIG_AR7_LED) += avalanche_led/avalanche_led.o
++subdir-$(CONFIG_AR7_LED) += avalanche_led
++
+ obj-$(CONFIG_HIL) += hp_keyb.o
+ obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
+ obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
+diff -urN linux.dev/drivers/char/avalanche_led/Makefile linux.dev2/drivers/char/avalanche_led/Makefile
+--- linux.dev/drivers/char/avalanche_led/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev2/drivers/char/avalanche_led/Makefile 2005-10-21 18:03:44.513777000 +0200
+@@ -0,0 +1,23 @@
++# File: drivers/char/avalanche_led/Makefile
++#
++# Makefile for the Linux LED device driver.
++#
++
++
++O_TARGET := avalanche_led.o
++obj-m := avalanche_led.o
++list-multi := avalanche_led.o
++
++EXTRA_CFLAGS := -I$(TOPDIR)/include/asm/ar7
++
++export-objs := ledmod.o leds.o
++
++avalanche_led-objs := ledmod.o gpio.o uartled.o leds.o
++
++include $(TOPDIR)/Rules.make
++
++avalanche_led.o: $(avalanche_led-objs)
++ $(LD) -r -o $@ $(avalanche_led-objs)
++
++clean:
++ rm -f core *.o *.a *.s
+diff -urN linux.dev/drivers/char/avalanche_led/gpio.c linux.dev2/drivers/char/avalanche_led/gpio.c
+--- linux.dev/drivers/char/avalanche_led/gpio.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev2/drivers/char/avalanche_led/gpio.c 2005-10-21 18:03:44.513777000 +0200
+@@ -0,0 +1,382 @@
++#include <linux/kernel.h>
++#include <asm/uaccess.h>
++#include <linux/spinlock.h>
++#include <linux/proc_fs.h>
++#include <linux/fs.h>
++#include <linux/timer.h>
++#include <linux/module.h>
++
++#include <asm/ar7/tnetd73xx_err.h>
++#include <asm/ar7/tnetd73xx_misc.h>
++#include <asm/ar7/ledapp.h>
++
++#define TRUE 1
++#define FALSE 0
++
++#if defined CONFIG_AR7WRD || defined CONFIG_AR7RD
++
++#define AR7_RESET_FILE "led_mod/ar7reset"
++#define AR7_VERSION_FILE "led_mod/hardware_version"
++#define AR7_RESET_GPIO 11
++#define RESET_POLL_TIME 1
++#define RESET_HOLD_TIME 4
++#define NO_OF_LEDS
++
++static struct proc_dir_entry *reset_file;
++static int res_state = 0;
++static int count;
++static struct timer_list *pTimer = NULL;
++static ssize_t proc_read_reset_fops(struct file *filp,
++ char *buf,size_t count , loff_t *offp);
++
++static ssize_t proc_read_hwversion_fops(struct file *filp,
++ char *buf,size_t count , loff_t *offp);
++
++struct file_operations reset_fops = {
++ read: proc_read_reset_fops
++ };
++struct file_operations hardware_version_fops = {
++ read: proc_read_hwversion_fops
++ };
++#endif
++
++static spinlock_t device_lock;
++led_reg_t temp[15];
++
++static void gpio_led_on( unsigned long param )
++{
++ unsigned int flags;
++
++ spin_lock_irqsave(&device_lock, flags);
++
++ tnetd73xx_gpio_out(param,FALSE);
++ spin_unlock_irqrestore(&device_lock, flags);
++}
++
++static void gpio_led_off ( unsigned long param )
++{
++ unsigned int flags = 0x00;
++
++ spin_lock_irqsave(&device_lock, flags);
++
++ tnetd73xx_gpio_out(param,TRUE);
++ spin_unlock_irqrestore(&device_lock, flags);
++}
++
++static void gpio_led_init( unsigned long param)
++{
++ tnetd73xx_gpio_ctrl(param,GPIO_PIN,GPIO_OUTPUT_PIN);
++}
++
++static void board_gpio_reset(void)
++{
++ /* Initialize the link mask */
++ device_lock = SPIN_LOCK_UNLOCKED;
++ return;
++}
++
++#if defined CONFIG_AR7WRD || defined CONFIG_AR7RD
++
++static ssize_t proc_read_hwversion_fops(struct file *filp, char *buf,
++ size_t count, loff_t *offp)
++{
++ char line[8];
++ int len = 0;
++ if( *offp != 0 )
++ return 0;
++
++ len = sprintf(line, "%d%d.%d%d%d%d\n", tnetd73xx_gpio_in(20),
++ tnetd73xx_gpio_in(21), tnetd73xx_gpio_in(22),
++ tnetd73xx_gpio_in(23), tnetd73xx_gpio_in(24),
++ tnetd73xx_gpio_in(25));
++
++ copy_to_user(buf, line, len);
++ *offp = len;
++ return len;
++}
++
++static ssize_t proc_read_reset_fops(struct file *filp,
++ char *buf,size_t count , loff_t *offp)
++{
++ char * pdata = NULL;
++ char line[3];
++ int len = 0;
++ if( *offp != 0 )
++ return 0;
++
++ pdata = buf;
++ len = sprintf(line,"%d\n", res_state );
++//wwzh
++// res_state = 0;
++ copy_to_user(buf,line,len );
++ *offp = len;
++ return len;
++}
++
++static void reset_timer_func(unsigned long data)
++{
++//wwzh
++#if 0
++ count = (tnetd73xx_gpio_in(AR7_RESET_GPIO) == 0) ? count + 1: 0;
++ if( count >= RESET_HOLD_TIME/RESET_POLL_TIME )
++#endif
++ if (tnetd73xx_gpio_in(AR7_RESET_GPIO) == 0)
++ res_state = 1;
++ else
++ res_state = 0;
++ pTimer->expires = jiffies + HZ*RESET_POLL_TIME;
++ add_timer (pTimer);
++ return;
++}
++
++static void hardware_version_init(void)
++{
++ static struct proc_dir_entry *hardware_version_file;
++ hardware_version_file = create_proc_entry(AR7_VERSION_FILE, 0777, NULL);
++ if(hardware_version_file == NULL)
++ return;
++
++ hardware_version_file->owner = THIS_MODULE;
++ hardware_version_file->proc_fops = &hardware_version_fops;
++
++ tnetd73xx_gpio_ctrl(20,GPIO_PIN,GPIO_INPUT_PIN);
++ tnetd73xx_gpio_ctrl(21,GPIO_PIN,GPIO_INPUT_PIN);
++ tnetd73xx_gpio_ctrl(22,GPIO_PIN,GPIO_INPUT_PIN);
++ tnetd73xx_gpio_ctrl(23,GPIO_PIN,GPIO_INPUT_PIN);
++ tnetd73xx_gpio_ctrl(24,GPIO_PIN,GPIO_INPUT_PIN);
++ tnetd73xx_gpio_ctrl(25,GPIO_PIN,GPIO_INPUT_PIN);
++
++ return;
++}
++
++static void reset_init(void)
++{
++ /* Create board reset proc file */
++ reset_file = create_proc_entry( AR7_RESET_FILE, 0777, NULL);
++ if( reset_file == NULL)
++ goto reset_file;
++ reset_file->owner = THIS_MODULE;
++ reset_file->proc_fops = &reset_fops;
++
++ /* Initialise GPIO 11 for input */
++ tnetd73xx_gpio_ctrl(AR7_RESET_GPIO,GPIO_PIN,GPIO_INPUT_PIN);
++
++ /* Create a timer which fires every seconds */
++ pTimer = kmalloc(sizeof(struct timer_list),GFP_KERNEL);
++ init_timer( pTimer );
++ pTimer->function = reset_timer_func;
++ pTimer->data = 0;
++ /* Start the timer */
++ reset_timer_func(0);
++ return ;
++
++ reset_file:
++ remove_proc_entry("AR7_RESET_FILE",NULL);
++ return;
++}
++#endif
++/*************wwzh****************/
++#if 1
++extern unsigned int sys_mod_state;
++extern unsigned int wan_mod_state;
++extern unsigned int wlan_mod_state;
++void sys_led_init(void)
++{
++ tnetd73xx_gpio_ctrl(4, GPIO_PIN, GPIO_OUTPUT_PIN);
++ tnetd73xx_gpio_ctrl(5, GPIO_PIN, GPIO_OUTPUT_PIN);
++ tnetd73xx_gpio_ctrl(8, GPIO_PIN, GPIO_OUTPUT_PIN);
++
++ tnetd73xx_gpio_out(4, FALSE);
++ tnetd73xx_gpio_out(5, TRUE);
++ tnetd73xx_gpio_out(8, TRUE);
++
++
++ sys_mod_state = 2;
++
++}
++void wan_led_init(void)
++{
++
++ tnetd73xx_gpio_ctrl(2, GPIO_PIN, GPIO_OUTPUT_PIN);
++ tnetd73xx_gpio_ctrl(3, GPIO_PIN, GPIO_OUTPUT_PIN);
++
++ tnetd73xx_gpio_out(2, FALSE);
++ tnetd73xx_gpio_out(3, FALSE);
++
++ wan_mod_state = 1;
++}
++//wwzh wireless
++#if 0
++void wlan_led_init(void)
++{
++ //unsigned long i = 0;
++ tnetd73xx_gpio_ctrl(12, GPIO_PIN, GPIO_OUTPUT_PIN);
++ tnetd73xx_gpio_ctrl(13, GPIO_PIN, GPIO_OUTPUT_PIN);
++
++ tnetd73xx_gpio_out(12, FALSE);
++ tnetd73xx_gpio_out(13, TRUE);
++ //for (i = 0; i < 0x20000000; i++);
++ wlan_mod_state = 1;
++}
++#endif
++
++#endif
++/*************end ****************/
++
++void board_gpio_init(void)
++{
++
++ board_gpio_reset();
++/**************wwzh*************/
++ sys_led_init();
++ wan_led_init();
++
++ //junzhao 2004.3.15
++ hardware_version_init();
++
++ //wlan_led_init();
++
++ /* Register Device MAX_LED_ID + 1 for reset to factory default */
++ temp[0].param = 0;
++ temp[0].init = reset_init;
++ temp[0].onfunc = 0;
++ temp[0].offfunc = 0;
++ register_led_drv( MAX_LED_ID + 1 , &temp[0]);
++//wwzh for wireless led
++#if 1
++ /* Register led 12 WiFi 6 */
++ temp[1].param = 6;
++ temp[1].init = gpio_led_init;
++ temp[1].onfunc = gpio_led_on;
++ temp[1].offfunc = gpio_led_off;
++ register_led_drv( 12 , &temp[1]);
++
++#endif
++
++#if 0
++/**************end ************/
++#if defined(CONFIG_AR5D01)
++ /* Register led 1 GPIO0 */
++ temp[0].param = GPIO_0;
++ temp[0].init = gpio_led_init;
++ temp[0].onfunc = gpio_led_on;
++ temp[0].offfunc = gpio_led_off;
++ register_led_drv( 1 , &temp[0]);
++
++ /* Register led 2 EINT1 */
++ temp[1].param = EINT_1;
++ temp[1].init = gpio_led_init;
++ temp[1].onfunc = gpio_led_on;
++ temp[1].offfunc = gpio_led_off;
++ register_led_drv( 2 , &temp[1]);
++
++ /* Register led 5 EINT1 */
++ temp[2].param = GPIO_1;
++ temp[2].init = gpio_led_init;
++ temp[2].onfunc = gpio_led_on;
++ temp[2].offfunc = gpio_led_off;
++ register_led_drv( 5 , &temp[2]);
++#endif
++
++#if defined(CONFIG_AR5W01)
++ /* Register led 5 GPIO_1 */
++ temp[0].param = GPIO_1;
++ temp[0].init = gpio_led_init;
++ temp[0].onfunc = gpio_led_on;
++ temp[0].offfunc = gpio_led_off;
++ register_led_drv( 5 , &temp[0]);
++
++ /* Register led 7 GPIO_0 */
++ temp[1].param = GPIO_0;
++ temp[1].init = gpio_led_init;
++ temp[1].onfunc = gpio_led_on;
++ temp[1].offfunc = gpio_led_off;
++ register_led_drv( 7 , &temp[1]);
++#endif
++
++//wwzh #if defined(CONFIG_AR7RD)
++#if defined CONFIG_AR7WRD || defined CONFIG_AR7RD
++ /* Register led 5 Green PPPOE GPIO 13 */
++ temp[0].param = 13;
++ temp[0].init = gpio_led_init;
++ temp[0].onfunc = gpio_led_on;
++ temp[0].offfunc = gpio_led_off;
++ register_led_drv( 5 , &temp[0]);
++
++ /* Register led 7 Green USB GPIO 12 */
++ temp[1].param = 12;
++ temp[1].init = gpio_led_init;
++ temp[1].onfunc = gpio_led_on;
++ temp[1].offfunc = gpio_led_off;
++ register_led_drv( 7 , &temp[1]);
++
++ /* Register Device MAX_LED_ID + 1 for reset to factory default */
++ temp[2].param = 0;
++ temp[2].init = reset_init;
++ temp[2].onfunc = 0;
++ temp[2].offfunc = 0;
++ register_led_drv( MAX_LED_ID + 1 , &temp[2]);
++
++ /* Register led 8 RED DSL GPIO 10 */
++ temp[3].param = 10;
++ temp[3].init = gpio_led_init;
++ temp[3].onfunc = gpio_led_on;
++ temp[3].offfunc = gpio_led_off;
++ register_led_drv( 8 , &temp[3]);
++
++ /* Register led 9 RED PPPoE down GPIO 9 */
++ temp[4].param = 9;
++ temp[4].init = gpio_led_init;
++ temp[4].onfunc = gpio_led_on;
++ temp[4].offfunc = gpio_led_off;
++ register_led_drv( 9 , &temp[4]);
++
++ /* Register led 10 DSL down GPIO 8 */
++ temp[5].param = 8;
++ temp[5].init = gpio_led_init;
++ temp[5].onfunc = gpio_led_on;
++ temp[5].offfunc = gpio_led_off;
++ register_led_drv( 10 , &temp[5]);
++
++ /* Register led 11 Power GPIO 7 */
++ temp[6].param = 7;
++ temp[6].init = gpio_led_init;
++ temp[6].onfunc = gpio_led_on;
++ temp[6].offfunc = gpio_led_off;
++ register_led_drv( 11 , &temp[6]);
++
++ /* Register led 12 WiFi 6 */
++ temp[7].param = 6;
++ temp[7].init = gpio_led_init;
++ temp[7].onfunc = gpio_led_on;
++ temp[7].offfunc = gpio_led_off;
++ register_led_drv( 12 , &temp[7]);
++
++ /* Register led 13 ELINK(AA1313) GPIO 15 */
++ temp[8].param = 15;
++ temp[8].init = gpio_led_init;
++ temp[8].onfunc = gpio_led_on;
++ temp[8].offfunc = gpio_led_off;
++ register_led_drv( 13 , &temp[8]);
++
++ /* Register led 14 EACT(Y13) GPIO 16 */
++ temp[9].param = 16;
++ temp[9].init = gpio_led_init;
++ temp[9].onfunc = gpio_led_on;
++ temp[9].offfunc = gpio_led_off;
++ register_led_drv( 14 , &temp[9]);
++
++#endif
++/**************wwzh**************/
++#endif
++/**************end **************/
++ return;
++}
++
++
++
++
++
++
++
++
+diff -urN linux.dev/drivers/char/avalanche_led/ledmod.c linux.dev2/drivers/char/avalanche_led/ledmod.c
+--- linux.dev/drivers/char/avalanche_led/ledmod.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev2/drivers/char/avalanche_led/ledmod.c 2005-10-21 18:03:44.513777000 +0200
+@@ -0,0 +1,1116 @@
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/proc_fs.h>
++#include <asm/uaccess.h>
++#include <linux/fs.h>
++#include <linux/timer.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <asm/ar7/avalanche_regs.h>
++#include <asm/ar7/ledapp.h>
++#include <linux/module.h>
++
++#define LED_ON 1
++#define LED_OFF 2
++#define LED_BLINK 3
++#define LED_FLASH 4
++
++#define LED_BLINK_UP 5
++#define LED_BLINK_DOWN 6
++
++extern void avalanche_leds_init(void);
++
++/***********wwzh**************/
++unsigned int sys_mod_state;
++unsigned int wan_mod_state;
++unsigned int wlan_mod_state;
++
++struct timer_list *pWanTimer = NULL;
++struct timer_list *pWlanTimer = NULL;
++/***********end **************/
++
++typedef struct state_entry{
++ unsigned char mode;
++ unsigned char led;
++ void (*handler)(struct state_entry *pState);
++ unsigned long param;
++}state_entry_t;
++
++typedef struct mod_entry{
++ state_entry_t *states[MAX_STATE_ID];
++}mod_entry_t;
++
++static mod_entry_t *modArr[MAX_MOD_ID];
++static struct proc_dir_entry *led_proc_dir,*led_file;
++
++/* index of the array is the led number HARDWARE SPECIFIC*/
++typedef struct led_data{
++ led_reg_t *led;
++ int state;
++ struct timer_list *pTimer;
++ unsigned char timer_running;
++ unsigned long param;
++}led_data_t;
++
++led_data_t led_arr[MAX_LED_ID + 1];
++/*!!! The last device is actually being used for ar7 reset to factory default */
++
++
++static spinlock_t config_lock;
++
++static void board_led_link_up( state_entry_t *pState );
++static void board_led_link_down( state_entry_t *pState );
++static void board_led_activity_on( state_entry_t *pState );
++static void board_led_activity_off( state_entry_t *pState );
++static void led_timer_func(unsigned long data);
++
++extern void board_gpio_init(void);
++extern void uart_led_init(void);
++
++static ssize_t proc_read_led_fops(struct file *filp,
++ char *buf,size_t count , loff_t *offp);
++static ssize_t proc_write_led_fops(struct file *filp,const char *buffer,
++ size_t count , loff_t *offp);
++static int config_led( unsigned long y);
++
++struct file_operations led_fops = {
++ read: proc_read_led_fops,
++ write: proc_write_led_fops,
++ };
++
++static int led_atoi( char *name)
++{
++ int val = 0;
++ for(;;name++)
++ {
++ switch(*name)
++ {
++ case '0'...'9':
++ val = val*10+(*name - '0');
++ break;
++ default:
++ return val;
++ }
++ }
++}
++
++static int free_memory(void)
++{
++ int i, j;
++
++ for( i = 0; i < MAX_MOD_ID ; i++)
++ {
++ if( modArr[i] != NULL )
++ {
++ for( j = 0; j < MAX_STATE_ID ; j++ )
++ {
++ if( modArr[i]->states[j] != NULL )
++ kfree( modArr[i]->states[j]);
++ }
++ kfree(modArr[i]);
++ modArr[i] = NULL;
++ }
++ }
++ return 0;
++}
++
++static int led_on( state_entry_t *pState )
++{
++ if( led_arr[pState->led].led == NULL)
++ return -1;
++ led_arr[pState->led].led->onfunc( led_arr[pState->led].led->param);
++ return 0;
++}
++
++static int led_off( state_entry_t *pState )
++{
++ if( led_arr[pState->led].led == NULL)
++ return -1;
++ led_arr[pState->led].led->offfunc( led_arr[pState->led].led->param);
++ return 0;
++}
++
++static void board_led_link_up( state_entry_t *pState )
++{
++ led_arr[pState->led].state = LED_ON;
++ if( led_arr[pState->led].timer_running == 0 )
++ led_on(pState);
++ return;
++}
++
++static void board_led_link_down( state_entry_t *pState )
++{
++ led_arr[pState->led].state = LED_OFF;
++ if( led_arr[pState->led].timer_running == 0 )
++ led_off(pState);
++ return;
++}
++
++static void add_led_timer(state_entry_t *pState)
++{
++ led_arr[pState->led].pTimer->expires = jiffies + HZ*(pState->param)/1000;
++ led_arr[pState->led].param = pState->param;
++ led_arr[pState->led].pTimer->data = pState;
++ add_timer (led_arr[pState->led].pTimer);
++}
++
++static void board_led_activity_on(state_entry_t *pState)
++{
++ if(led_arr[pState->led].timer_running == 0)
++ {
++ led_on(pState);
++ add_led_timer(pState);
++ led_arr[pState->led].timer_running = 1;
++ led_arr[pState->led].state = LED_BLINK_UP;
++ }
++ else if( led_arr[pState->led].timer_running > 0xF0)
++ {
++ led_arr[pState->led].state = LED_BLINK_UP;
++ led_arr[pState->led].pTimer->expires = jiffies + HZ*(pState->param)/1000;
++ led_arr[pState->led].param = pState->param;
++ led_arr[pState->led].pTimer->data = pState;
++ }
++ return;
++}
++
++static void board_led_activity_off(state_entry_t *pState)
++{
++ if(led_arr[pState->led].timer_running == 0)
++ {
++ led_off(pState);
++ add_led_timer(pState);
++ led_arr[pState->led].timer_running = 1;
++ led_arr[pState->led].state = LED_BLINK_UP;
++ }
++ else if( led_arr[pState->led].timer_running > 0xF0)
++ {
++ led_arr[pState->led].state = LED_BLINK_UP;
++ led_arr[pState->led].pTimer->expires = jiffies + HZ*(pState->param)/1000;
++ led_arr[pState->led].param = pState->param;
++ led_arr[pState->led].pTimer->data = pState;
++ }
++ return;
++}
++
++static void board_led_link_flash(state_entry_t *pState)
++{
++ if(led_on(pState))
++ return;
++ if(led_arr[pState->led].timer_running == 0)
++ add_led_timer(pState);
++ else
++ led_arr[pState->led].param = pState->param;
++ led_arr[pState->led].timer_running = 0xFF;
++ led_arr[pState->led].state = LED_FLASH;
++ return;
++}
++
++static void led_timer_func(unsigned long data)
++{
++ state_entry_t *pState = NULL;
++ mod_entry_t *pMod = NULL;
++ unsigned int flags;
++
++ spin_lock_irqsave(&config_lock, flags);
++
++ pState = (state_entry_t *)data;
++
++ if( led_arr[pState->led].state == LED_BLINK_DOWN )
++ {
++ led_arr[pState->led].timer_running = 0;
++ if( pState->mode == 2 )
++ led_arr[pState->led].state = LED_OFF;
++ else
++ led_arr[pState->led].state = LED_ON;
++ }
++ else if( led_arr[pState->led].state == LED_BLINK_UP )
++ {
++ led_arr[pState->led].pTimer->expires = jiffies + HZ*(led_arr[pState->led].param)/1000;
++ led_arr[pState->led].pTimer->data = pState;
++ add_timer (led_arr[pState->led].pTimer);
++ if( pState->mode == 2 )
++ {
++ led_off(pState);
++ led_arr[pState->led].state = LED_BLINK_DOWN;
++ }
++ else
++ {
++ led_on(pState);
++ led_arr[pState->led].state = LED_BLINK_DOWN;
++ }
++ led_arr[pState->led].timer_running = 1;
++ }
++ else if( led_arr[pState->led].state == LED_FLASH )
++ {
++ led_arr[pState->led].pTimer->expires = jiffies + HZ*(led_arr[pState->led].param)/1000;
++ led_arr[pState->led].pTimer->data = pState;
++ add_timer (led_arr[pState->led].pTimer);
++
++ if( led_arr[pState->led].timer_running == 0xFF )
++ {
++ led_off(pState);
++ led_arr[pState->led].timer_running--;
++ }
++ else
++ {
++ led_on(pState);
++ led_arr[pState->led].timer_running++;
++ }
++ spin_unlock_irqrestore(&config_lock, flags);
++ return;
++ }
++ else if(led_arr[pState->led].state == LED_OFF)
++ {
++ led_off(pState);
++ led_arr[pState->led].timer_running = 0;
++ }
++ else if( led_arr[pState->led].state == LED_ON )
++ {
++ led_on(pState);
++ led_arr[pState->led].timer_running = 0;
++ }
++ spin_unlock_irqrestore(&config_lock, flags);
++ return;
++}
++/************wwzh*****************/
++#if 0
++/************end *****************/
++static ssize_t proc_read_led_fops(struct file *filp,
++ char *buf,size_t count , loff_t *offp)
++{
++ char * pdata = NULL;
++ int i = 0, j = 0, len = 0, totallen = 0;
++ char line[255];
++
++ if( *offp != 0 )
++ return 0;
++
++ pdata = buf;
++ len += sprintf(line,"LEDS Registered for use are:");
++ for( i = 0; i< MAX_LED_ID; i++)
++ if( led_arr[i].led != NULL )
++ len += sprintf(&line[len]," %d ", i );
++ line[len++] = '\n';
++
++ copy_to_user(pdata, line,len );
++ pdata += len;
++ totallen += len;
++ len = 0;
++ len = sprintf(line,"USER MODULE INFORMATION:\n");
++ copy_to_user(pdata, line,len );
++ pdata += len;
++ totallen += len;
++ len = 0;
++ for( i = 0; i< MAX_MOD_ID; i++)
++ {
++ if( modArr[i] != NULL )
++ {
++ len = sprintf(line," Module ID = %d \n" , i);
++ copy_to_user(pdata, line,len );
++ pdata += len;
++ totallen += len;
++ len = 0;
++ for( j = 0; j < MAX_STATE_ID; j++)
++ {
++ if( modArr[i]->states[j] != NULL)
++ {
++ len = sprintf(line ,
++ " State = %d , Led = %d," , j , modArr[i]->states[j]->led);
++ copy_to_user(pdata, line,len );
++ pdata += len;
++ totallen += len;
++
++ len = 0;
++ switch( modArr[i]->states[j]->mode )
++ {
++ case 1:
++ len = sprintf(line ," Mode = OFF\n");
++ break;
++ case 2:
++ len = sprintf(line ," Mode = BLINK_ON , On Time(ms) = %d\n" ,
++ (unsigned int)modArr[i]->states[j]->param);
++ break;
++ case 3:
++ len = sprintf(line ," Mode = BLINK_OFF , Off Time(ms) = %d\n" ,
++ (unsigned int)modArr[i]->states[j]->param);
++ break;
++ case 4:
++ len = sprintf(line ," Mode = ON \n");
++ break;
++ case 5:
++ len = sprintf(line ," Mode = FLASH , Time Period(ms) = %d\n" ,
++ (unsigned int)modArr[i]->states[j]->param);
++ break;
++ default:
++ break;
++
++ }
++ copy_to_user(pdata, line,len );
++ pdata += len;
++ totallen += len;
++
++ len = 0;
++ }
++ }
++ }
++ }
++ /* Return with configuration information for LEDs */
++ *offp = totallen;
++ return totallen;
++}
++static ssize_t proc_write_led_fops(struct file *filp,const char *buffer,
++ size_t count , loff_t *offp)
++{
++ char *pdata = NULL, *ptemp = NULL;
++ char line[10],temp[10];
++ int i = 0;
++ int mod = 0xFFFF , state = 0xFFFF;
++ int flag = 0;
++
++ /* Check if this write is for configuring stuff */
++ if( *(int *)(buffer) == 0xFFEEDDCC )
++ {
++ printk("<1>proc write:Calling Configuration\n");
++ config_led((unsigned long)(buffer + sizeof(int)) );
++ return count;
++ }
++
++ if( count >= 10)
++ {
++ printk("<1>proc write:Input too long,max length = %d\n",10);
++ return count;
++ }
++ memset( temp, 0x00 , 10);
++ memset( line, 0x00 , 10);
++ copy_from_user(line,buffer,count);
++ line[count] = 0x00;
++ pdata = line;
++ ptemp = temp;
++ while( flag == 0)
++ {
++ if( i > 10 )
++ break;
++ if( ((*pdata) >= '0' ) && ((*pdata) <= '9') )
++ {
++ *ptemp = *pdata ;
++ ptemp++;
++ }
++ else if( (*pdata) == ',' )
++ {
++ *ptemp = 0x00;
++ flag = 1;
++ }
++ pdata++;
++ i++;
++ };
++ if( flag == 1)
++ mod = led_atoi( temp);
++ else
++ return count;
++
++ ptemp = temp;
++ *ptemp = 0x00;
++ flag = 0;
++ while( flag == 0)
++ {
++ if( i > 10 )
++ break;
++ if( ((*pdata) >= '0' ) && ((*pdata) <= '9') )
++ {
++ *ptemp = *pdata ;
++ ptemp++;
++ }
++ else if( (*pdata) == 0x00 )
++ {
++ *ptemp = 0x00;
++ flag = 1;
++ }
++ pdata++;
++ i++;
++ };
++ if( flag == 1)
++ state = led_atoi( temp);
++ else
++ return count;
++ if( (mod == 0xFFFF) || (state == 0xFFFF))
++ return count;
++ else
++ led_operation( mod , state );
++ return count;
++}
++
++/************wwzh*******************/
++#else
++
++#define TRUE 1
++#define FALSE 0
++#define FLICK_TIME (HZ*100/1000)
++static unsigned int wan_txrx_state = 0;
++static unsigned int wlan_txrx_state = 0;
++
++void led_operation( int mod , int state)
++{
++
++ unsigned int flags;
++
++ spin_lock_irqsave(&config_lock, flags);
++
++ if( (mod >= MAX_MOD_ID) || ( state >= MAX_STATE_ID) )
++ {
++ spin_unlock_irqrestore(&config_lock, flags);
++ return;
++ }
++ if ( modArr[mod] == NULL )
++ {
++ spin_unlock_irqrestore(&config_lock, flags);
++ return;
++ }
++ if( modArr[mod]->states[state] == NULL )
++ {
++ spin_unlock_irqrestore(&config_lock, flags);
++ return;
++ }
++ /* Call the function handler */
++ modArr[mod]->states[state]->handler(modArr[mod]->states[state]);
++
++ spin_unlock_irqrestore(&config_lock, flags);
++}
++
++static void wan_led_func(unsigned long data)
++{
++ if (wan_txrx_state == 0)
++ {
++ tnetd73xx_gpio_out(2, TRUE);
++ tnetd73xx_gpio_out(3, FALSE);
++ wan_txrx_state = 1;
++ }
++ else
++ {
++ tnetd73xx_gpio_out(2, FALSE);
++ tnetd73xx_gpio_out(3, FALSE);
++ wan_txrx_state = 0;
++ }
++ pWanTimer->expires = jiffies + FLICK_TIME;
++ add_timer(pWanTimer);
++}
++//wwzh for wireless
++#if 0
++static void wlan_led_func(unsigned long data)
++{
++ if (wlan_txrx_state == 0)
++ {
++ tnetd73xx_gpio_out(12, TRUE);
++ tnetd73xx_gpio_out(13, FALSE);
++ wlan_txrx_state = 1;
++ }
++ else
++ {
++ tnetd73xx_gpio_out(12, FALSE);
++ tnetd73xx_gpio_out(13, FALSE);
++ wlan_txrx_state = 0;
++
++ }
++ pWlanTimer->expires = jiffies + FLICK_TIME;
++ add_timer(pWlanTimer);
++}
++#endif
++
++void led_active(int mod, int state)
++{
++ unsigned int flags = 0;
++
++//printk("mod = %d state = %d\n", mod, state);
++ spin_lock_irqsave(&config_lock, flags);
++ if ((mod >= 5) || (state >= 5))
++ {
++ spin_unlock_irqrestore(&config_lock, flags);
++ return;
++ }
++
++ switch (mod)
++ {
++ case 2: /*system led */
++ sys_mod_state = state;
++ switch (state)
++ {
++ case 1:
++ break;
++ case 2: /*sys led flashing green */
++ tnetd73xx_gpio_out(4, FALSE);
++ tnetd73xx_gpio_out(5, TRUE);
++ tnetd73xx_gpio_out(8, TRUE);
++ break;
++ case 3: /*sys led solid green */
++ tnetd73xx_gpio_out(4, TRUE);
++ tnetd73xx_gpio_out(5, TRUE);
++ tnetd73xx_gpio_out(8, TRUE);
++
++ break;
++ case 4: /*sys fail red */
++ tnetd73xx_gpio_out(4, TRUE);
++ tnetd73xx_gpio_out(5, FALSE);
++ tnetd73xx_gpio_out(8, FALSE);
++ break;
++ default:
++ break;
++ }
++ break;
++ case 3: /*wan led */
++ wan_mod_state = state;
++ switch (state)
++ {
++ case 1: /*no wan interface*/
++ if (pWanTimer)
++ {
++ del_timer(pWanTimer);
++ kfree(pWanTimer);
++ pWanTimer = NULL;
++ }
++ tnetd73xx_gpio_out(2, FALSE);
++ tnetd73xx_gpio_out(3, FALSE);
++ break;
++ case 2: /*wan connected */
++ if (pWanTimer)
++ {
++ del_timer(pWanTimer);
++ kfree(pWanTimer);
++ pWanTimer = NULL;
++ }
++ tnetd73xx_gpio_out(2, TRUE);
++ tnetd73xx_gpio_out(3, FALSE);
++ break;
++ case 3: /*rx/tx activity */
++ if (pWanTimer != NULL)
++ break;
++
++ pWanTimer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
++ init_timer(pWanTimer);
++
++ pWanTimer->function = wan_led_func;
++ pWanTimer->data = 0;
++ pWanTimer->expires = jiffies + FLICK_TIME;
++ tnetd73xx_gpio_out(2, FALSE);
++ tnetd73xx_gpio_out(3, FALSE);
++ wan_txrx_state = 0;
++ add_timer(pWanTimer);
++
++ break;
++ case 4: /*no ipaddress */
++ if (pWanTimer)
++ {
++ del_timer(pWanTimer);
++ kfree(pWanTimer);
++ pWanTimer = NULL;
++ }
++ tnetd73xx_gpio_out(2, FALSE);
++ tnetd73xx_gpio_out(3, TRUE);
++ break;
++ default:
++ if (pWanTimer)
++ {
++ del_timer(pWanTimer);
++ kfree(pWanTimer);
++ pWanTimer = NULL;
++ }
++ break;
++ }
++ break;
++ //wwzh for wireless
++ #if 0
++ case 4: /*wlan led */
++ wlan_mod_state = state;
++ switch (state)
++ {
++ case 1: /* wlan off */
++ if (pWlanTimer)
++ {
++ del_timer(pWlanTimer);
++ kfree(pWlanTimer);
++ pWlanTimer = NULL;
++ }
++ tnetd73xx_gpio_out(12, FALSE);
++ tnetd73xx_gpio_out(13, FALSE);
++ break;
++ case 2: /* wlan ready */
++ if (pWlanTimer)
++ {
++ del_timer(pWlanTimer);
++ kfree(pWlanTimer);
++ pWlanTimer = NULL;
++ }
++ tnetd73xx_gpio_out(12, TRUE);
++ tnetd73xx_gpio_out(13, FALSE);
++ break;
++ case 3: /* wlan rx/tx activity */
++ if (pWlanTimer != NULL)
++ break;
++
++ pWlanTimer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
++ init_timer(pWlanTimer);
++
++ pWlanTimer->function = wlan_led_func;
++ pWlanTimer->data = 0;
++ pWlanTimer->expires = jiffies + FLICK_TIME;
++ tnetd73xx_gpio_out(12, FALSE);
++ tnetd73xx_gpio_out(13, FALSE);
++ wlan_txrx_state = 0;
++ add_timer(pWlanTimer);
++
++ break;
++ default:
++ if (pWlanTimer)
++ {
++ del_timer(pWlanTimer);
++ kfree(pWlanTimer);
++ pWlanTimer = NULL;
++ }
++
++ break;
++ }
++ break;
++ #endif //for wireless
++ default:
++ break;
++ }
++ spin_unlock_irqrestore(&config_lock, flags);
++}
++static ssize_t proc_read_led_fops(struct file *filp,
++ char *buf,size_t count , loff_t *offp)
++{
++ char *pdata = NULL;
++ int i = 0, j = 0, len = 0, totallen = 0;
++ char line[255];
++
++ if (*offp != 0)
++ return 0;
++ pdata = buf;
++ len = sprintf(line, "USER MODULE INFORMATION:\n");
++ copy_to_user(pdata, line, len);
++ pdata += len;
++ totallen += len;
++ len = 0;
++
++ //*******add Module 1 , this Module is ADSL ********/
++ for (i = 0; i < MAX_MOD_ID; i++)
++ {
++ if (modArr[i] != NULL)
++ {
++ len = sprintf(line, " Module ID = %d\n", i);
++ copy_to_user(pdata, line, len);
++ pdata += len;
++ totallen += len;
++ len = 0;
++ for(j = 0; j < MAX_STATE_ID; j++)
++ {
++ if (modArr[i]->states[j] != NULL)
++ {
++ len = sprintf(line, "State =%d, Led = %d,", j, modArr[i]->states[j]->led);
++ copy_to_user(pdata, line, len);
++ pdata += len;
++ totallen += len;
++ len = 0;
++ switch(modArr[i]->states[j]->mode)
++ {
++ case 1:
++ len = sprintf(line, "Mode = OFF\n");
++ break;
++ case 2:
++ len = sprintf(line, "Mode = BLINK_ON, On Time(ms) = %d\n", (unsigned int)modArr[i]->states[j]->param);
++ break;
++ case 3:
++ len = sprintf(line, "Mode = BLINK_OFF, Off Time(ms) = %d\n", (unsigned int)modArr[i]->states[j]->param);
++ break;
++ case 4:
++ len = sprintf(line, "Mode = On\n");
++ break;
++ case 5:
++ len = sprintf(line, "Mode = FLASH, Time Period(ms) = %d\n", (unsigned int)modArr[i]->states[j]->param);
++ break;
++ default:
++ break;
++ }
++ copy_to_user(pdata, line, len);
++ pdata += len;
++ totallen += len;
++ len = 0;
++ }
++ }
++ }
++
++ }
++
++ len = sprintf(line, "Module ID = 2(system led)\n");
++ copy_to_user(pdata, line, len);
++ pdata += len;
++ totallen += len;
++ len = 0;
++ switch(sys_mod_state)
++ {
++ case 1:
++ len = sprintf(line, "State = OFF\n");
++ break;
++ case 2:
++ len = sprintf(line, "State = Booting\n");
++ break;
++ case 3:
++ len = sprintf(line, "State = System Ready\n");
++ break;
++ case 4:
++ len = sprintf(line, "State = System Failure\n");
++ break;
++ default:
++ break;
++ }
++ copy_to_user(pdata, line, len);
++ pdata += len;
++ totallen += len;
++ len = 0;
++
++ len = sprintf(line, "Module ID = 3(WAN led)\n");
++ copy_to_user(pdata, line, len);
++ pdata += len;
++ totallen += len;
++ len = 0;
++ switch(wan_mod_state)
++ {
++ case 1:
++ len = sprintf(line, "State = OFF\n");
++ break;
++ case 2:
++ len = sprintf(line, "State = Wan Connected\n");
++ break;
++ case 3:
++ len = sprintf(line, "State = Wan Tx/Rx Activity\n");
++ break;
++ case 4:
++ len = sprintf(line, "State = Wan Connect Failure\n");
++ break;
++ default:
++ break;
++ }
++ copy_to_user(pdata, line, len);
++ pdata += len;
++ totallen += len;
++ len = 0;
++
++//wwzh for wireless
++#if 0
++ len = sprintf(line, "Module ID = 4(WLAN led)\n");
++ copy_to_user(pdata, line, len);
++ pdata += len;
++ totallen += len;
++ len = 0;
++ switch(wlan_mod_state)
++ {
++ case 1:
++ len = sprintf(line, "State = OFF\n");
++ break;
++ case 2:
++ len = sprintf(line, "State = wlan Ready\n");
++ break;
++ case 3:
++ len = sprintf(line, "State = wlan rx/tx activity\n");
++ break;
++ default:
++ break;
++ }
++ copy_to_user(pdata, line, len);
++ pdata += len;
++ totallen += len;
++ len = 0;
++#endif //for wireless
++
++ *offp = totallen;
++ return totallen;
++}
++static ssize_t proc_write_led_fops(struct file *filp,const char *buffer,
++ size_t count , loff_t *offp)
++{
++ char *pdata = NULL, *ptemp = NULL;
++ char line[10], temp[10];
++ int i = 0;
++ int mod = 0xffff, state = 0xffff;
++ int flag = 0;
++
++ /* Check if this write is for configuring ADSL */
++ if( *(int *)(buffer) == 0xFFEEDDCC )
++ {
++ printk("<1>proc write:Calling Configuration\n");
++ config_led((unsigned long)(buffer + sizeof(int)) );
++ return count;
++ }
++
++ if (count > 10)
++ {
++ printk("<1> proc write: Input too long, max length = 10\n");
++ return count;
++ }
++ memset(temp, 0x00, 10);
++ memset(line, 0x00, 10);
++ copy_from_user(line, buffer, count);
++ line[count] = 0x00;
++ pdata = line;
++ ptemp = temp;
++
++ while (flag == 0)
++ {
++ if (i > 10)
++ break;
++ if (((*pdata) >= '0') && ((*pdata) <= '9'))
++ {
++ *ptemp = *pdata;
++ ptemp++;
++ }
++ else if ((*pdata) == ',')
++ {
++ *ptemp = 0x00;
++ flag = 1;
++ }
++ pdata++;
++ i++;
++ }
++ if (flag == 1)
++ mod = led_atoi(temp);
++ else
++ return count;
++
++ ptemp = temp;
++ *ptemp = 0x00;
++ flag = 0;
++
++ while(flag == 0)
++ {
++ if (i > 10)
++ break;
++ if (((*pdata) >= '0') && ((*pdata) <= '9'))
++ {
++ *ptemp = *pdata;
++ ptemp++;
++ }
++ else if ((*pdata) == 0x00)
++ {
++ *ptemp = 0x00;
++ flag = 1;
++ }
++ pdata++;
++ i++;
++ }
++ if (flag == 1)
++ state = led_atoi(temp);
++ else
++ return count;
++ if ((mod == 0xFFFF) || (state == 0xFFFF))
++ return count;
++ else
++ {
++ if (mod != 4)
++ led_active(mod, state);
++ else
++ led_operation(mod, state);
++ }
++ return 1;
++}
++#endif
++/************end *******************/
++static int config_led(unsigned long y)
++{
++ config_elem_t *pcfg = NULL;
++ char *pdata = NULL;
++ int i;
++ int length = 0 , number = 0;
++ unsigned int flags;
++
++ spin_lock_irqsave(&config_lock, flags);
++
++ /* ioctl to configure */
++ length = *((int*)y);
++ pdata = (char *)y + sizeof(int);
++ number = (length - sizeof(int))/sizeof(config_elem_t);
++ pcfg = (config_elem_t *)(pdata);
++
++ /* Check if an earlier configuration exists IF yes free it up */
++ free_memory();
++
++ for ( i = 0 ; i < number ; i++ )
++ {
++ /* If no structure has been allocated for the module do so */
++ if ( modArr[pcfg->name] == NULL )
++ {
++ printk("<1>module = %d\n",pcfg->name);
++ if( pcfg->name >= MAX_MOD_ID)
++ {
++ printk("<1>Exiting Configuration: Module ID too large %d\n",pcfg->name);
++ free_memory();
++ spin_unlock_irqrestore(&config_lock, flags);
++ return -1;
++ }
++ modArr[pcfg->name] = kmalloc(sizeof(mod_entry_t),GFP_KERNEL);
++ if(modArr[pcfg->name] == NULL)
++ {
++ printk("<1>Exiting Configuration: Error in allocating memory\n");
++ free_memory();
++ spin_unlock_irqrestore(&config_lock, flags);
++ return -1;
++ }
++ memset( modArr[pcfg->name], 0x00, sizeof(mod_entry_t));
++ }
++
++ /* if no structure is allocated previously for this state
++ allocate a structure, if it's already there fill it up */
++ if( modArr[pcfg->name]->states[pcfg->state] == NULL)
++ {
++ printk("<1>STATE = %d\n",pcfg->state);
++ if( pcfg->state >= MAX_STATE_ID)
++ {
++ printk("<1>Exiting Configuration: State ID too large\n");
++ free_memory();
++ spin_unlock_irqrestore(&config_lock, flags);
++ return -1;
++ }
++ modArr[pcfg->name]->states[pcfg->state] =
++ kmalloc(sizeof(state_entry_t),GFP_KERNEL);
++ if( modArr[pcfg->name]->states[pcfg->state] == NULL)
++ {
++ free_memory();
++ spin_unlock_irqrestore(&config_lock, flags);
++ return -1;
++ }
++ memset( modArr[pcfg->name]->states[pcfg->state], 0x00, sizeof(state_entry_t));
++ }
++ /* Fill up the fields of the state */
++ if( pcfg->led >= MAX_LED_ID)
++ {
++ printk("<1>led = %d\n",pcfg->led);
++ free_memory();
++ spin_unlock_irqrestore(&config_lock, flags);
++ return -1;
++ }
++ modArr[pcfg->name]->states[pcfg->state]->led = pcfg->led;
++ modArr[pcfg->name]->states[pcfg->state]->mode = pcfg->mode;
++ modArr[pcfg->name]->states[pcfg->state]->param = pcfg->param;
++ switch(pcfg->mode)
++ {
++ case 1:
++ modArr[pcfg->name]->states[pcfg->state]->handler = board_led_link_down;
++ break;
++ case 2:
++ case 3:
++ case 5:
++ if( pcfg->mode == 2 )
++ modArr[pcfg->name]->states[pcfg->state]->handler = board_led_activity_on;
++ else if( pcfg->mode == 3)
++ modArr[pcfg->name]->states[pcfg->state]->handler = board_led_activity_off;
++ else
++ modArr[pcfg->name]->states[pcfg->state]->handler = board_led_link_flash;
++ break;
++ case 4:
++ modArr[pcfg->name]->states[pcfg->state]->handler = board_led_link_up;
++ break;
++ default:
++ printk("<1>Exiting Configuration: Unknown LED Mode\n");
++ free_memory();
++ spin_unlock_irqrestore(&config_lock, flags);
++ return -1;
++ }
++ pcfg++;
++ }
++ spin_unlock_irqrestore(&config_lock, flags);
++ return 0;
++}
++
++
++int __init led_init(void)
++{
++
++ /* Clear our memory */
++ memset(modArr,0x00,sizeof(mod_entry_t *)*MAX_MOD_ID);
++ memset(led_arr,0x00,sizeof(led_data_t *)*MAX_LED_ID);
++
++ /* Create spin lock for config data structure */
++ config_lock=SPIN_LOCK_UNLOCKED;
++
++ /* Create directory */
++ led_proc_dir = proc_mkdir("led", NULL);
++ if( led_proc_dir == NULL )
++ goto out;
++
++ /* Create adsl file */
++ led_file = create_proc_entry("led", 0777, led_proc_dir);
++ if( led_file == NULL)
++ goto led_file;
++ led_file->owner = THIS_MODULE;
++ led_file->proc_fops = &led_fops;
++
++ memset( modArr , 0x00 , sizeof(mod_entry_t *) * MAX_MOD_ID);
++ /* Reset the GPIO pins */
++ board_gpio_init();
++
++ /* Register the UART controlled LEDS */
++ uart_led_init();
++ /* Create the usb proc file */
++ avalanche_leds_init();
++ return 0;
++
++ led_file:
++ remove_proc_entry("led",led_proc_dir);
++ out:
++ return 0;
++
++}
++
++void led_exit()
++{
++ remove_proc_entry("led", led_proc_dir);
++}
++
++module_init(led_init);
++module_exit(led_exit);
++
++void register_led_drv( int device , led_reg_t *pInfo)
++{
++ unsigned int flags;
++ struct timer_list *pTimer = NULL;
++
++ spin_lock_irqsave(&config_lock, flags);
++
++ led_arr[device].led = pInfo;
++ if( led_arr[device].led->init != 0x00)
++ led_arr[device].led->init(led_arr[device].led->param);
++ if( led_arr[device].led->offfunc != 0x00)
++ led_arr[device].led->offfunc(led_arr[device].led->param);
++
++ /* Create a timer for blinking */
++ pTimer = kmalloc(sizeof(struct timer_list),GFP_KERNEL);
++ init_timer( pTimer );
++ pTimer->function = led_timer_func;
++ pTimer->data = 0;
++ led_arr[device].pTimer = pTimer;
++ led_arr[device].timer_running = 0;
++
++ spin_unlock_irqrestore(&config_lock, flags);
++
++ return;
++}
++
++void deregister_led_drv( int device)
++{
++ unsigned int flags;
++
++ spin_lock_irqsave(&config_lock, flags);
++ led_arr[device].led = NULL;
++
++ if( led_arr[device].pTimer != NULL)
++ {
++ del_timer(led_arr[device].pTimer);
++ kfree(led_arr[device].pTimer);
++ }
++ spin_unlock_irqrestore(&config_lock, flags);
++
++ return;
++}
++
++EXPORT_SYMBOL_NOVERS(led_operation);
++EXPORT_SYMBOL_NOVERS(register_led_drv);
++EXPORT_SYMBOL_NOVERS(deregister_led_drv);
++
+diff -urN linux.dev/drivers/char/avalanche_led/leds.c linux.dev2/drivers/char/avalanche_led/leds.c
+--- linux.dev/drivers/char/avalanche_led/leds.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev2/drivers/char/avalanche_led/leds.c 2005-10-21 18:03:44.513777000 +0200
+@@ -0,0 +1,133 @@
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <asm/ar7/avalanche_regs.h>
++#include <linux/spinlock.h>
++#include <linux/timer.h>
++#include <linux/sched.h>
++#include <linux/module.h>
++#include <linux/proc_fs.h>
++#include <asm/uaccess.h>
++#include <linux/fs.h>
++
++#include <asm/ar7/ledapp.h>
++
++#if defined(CONFIG_AR5D01) || defined(CONFIG_AR5W01) || defined(CONFIG_AR7)
++
++#define ETH_MASK 0x01
++#define USB_MASK 0x02
++
++static struct proc_dir_entry *usb_file;
++static ssize_t proc_read_usb_fops(struct file *filp,
++ char *buf,size_t count , loff_t *offp);
++struct file_operations usb_fops = {read: proc_read_usb_fops};
++
++typedef struct mod_states{
++ int module;
++ int activity;
++ int linkup;
++ int idle;
++}mod_states_t;
++
++mod_states_t state_arr[] = {
++ { MOD_ETH,DEF_ETH_ACTIVITY,DEF_ETH_LINK_UP,DEF_ETH_IDLE },
++ { MOD_USB,DEF_USB_ACTIVITY,DEF_USB_LINK_UP,DEF_USB_IDLE },
++ { MOD_LAN,DEF_LAN_ACTIVITY,DEF_LAN_LINK_UP,DEF_LAN_IDLE }
++ };
++
++unsigned char device_links = 0; /* Bitmask with the devices that are up */
++
++
++void avalanche_led_activity_pulse(unsigned long device)
++{
++ /* If device link is not up return */
++ if( !(device_links & (unsigned char)(1 << device)))
++ return;
++#ifdef MULTIPLEX_LED
++ led_operation( state_arr[2].module, state_arr[2].activity);
++#else
++ led_operation( state_arr[device].module, state_arr[device].activity);
++#endif
++}
++
++void avalanche_led_link_up( unsigned long device )
++{
++
++ /* If already UP ignore */
++ if( device_links & (unsigned char)(1 << device))
++ return;
++ /* Turn on the bit for the device */
++ device_links |= (unsigned char)(1 << device);
++#ifdef MULTIPLEX_LED
++ led_operation( state_arr[2].module, state_arr[2].linkup);
++#else
++ led_operation( state_arr[device].module, state_arr[device].linkup);
++#endif
++}
++
++void avalanche_led_link_down ( unsigned long device )
++{
++
++ /* If already DOWN ignore */
++ if( !(device_links & (unsigned char)(1 << device)))
++ return;
++
++ /* Turn off the bit for the device */
++ device_links &= ~(unsigned char)(1 << device);
++#ifdef MULTIPLEX_LED
++ /* If no links, then shut the LED off */
++ if(!device_links)
++ led_operation( state_arr[2].module, state_arr[2].idle);
++#else
++ led_operation( state_arr[device].module, state_arr[device].idle);
++#endif
++}
++
++static ssize_t proc_read_usb_fops(struct file *filp,
++ char *buf,size_t count , loff_t *offp)
++{
++ char * pdata = NULL;
++ char line[3];
++ if( *offp != 0 )
++ return 0;
++ pdata = buf;
++ if( device_links & USB_MASK)
++ sprintf(line,"%s\n","1");
++ else
++ sprintf(line,"%s\n","0");
++ copy_to_user(pdata,line,2);
++ *offp = 2;
++ return 2;
++}
++
++
++void avalanche_leds_init(void)
++{
++ /* Create usb link proc file */
++ usb_file = create_proc_entry("avalanche/usb_link", 0444, NULL);
++ if( usb_file == NULL)
++ return;
++ usb_file->owner = THIS_MODULE;
++ usb_file->proc_fops = &usb_fops;
++ return;
++}
++
++EXPORT_SYMBOL(avalanche_led_activity_pulse);
++EXPORT_SYMBOL(avalanche_led_link_up);
++EXPORT_SYMBOL(avalanche_led_link_down);
++
++#else
++/* We make a dummy init routine for the platforms that do not support this led
++ API
++*/
++
++void avalanche_leds_init(void)
++{
++}
++
++#endif
++
++
++
++
++
+diff -urN linux.dev/drivers/char/avalanche_led/uartled.c linux.dev2/drivers/char/avalanche_led/uartled.c
+--- linux.dev/drivers/char/avalanche_led/uartled.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev2/drivers/char/avalanche_led/uartled.c 2005-10-21 18:03:44.529778000 +0200
+@@ -0,0 +1,55 @@
++#include <linux/kernel.h>
++#include <asm/uaccess.h>
++#include <linux/spinlock.h>
++#include <asm/ar7/avalanche_regs.h>
++#include <asm/ar7/ledapp.h>
++
++#define UART_LED_REG (*(volatile unsigned int *)(UARTA_BASE + 0x10))
++
++static spinlock_t device_lock;
++led_reg_t temp1[2];
++
++static void uart_led_on(unsigned long param)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&device_lock,flags);
++ UART_LED_REG &= 0xFFFD;
++ spin_unlock_irqrestore(&device_lock, flags);
++}
++
++static void uart_led_off ( unsigned long param )
++{
++ unsigned int flags = 0x00;
++ spin_lock_irqsave(&device_lock, flags);
++ UART_LED_REG |= 0x02;
++ spin_unlock_irqrestore(&device_lock, flags);
++}
++
++void uart_led_init(void)
++{
++
++#if defined(CONFIG_AR5D01)
++ /* Register led 6 UART Pin 1 */
++ temp1[0].param = 0;
++ temp1[0].init = NULL;
++ temp1[0].onfunc = uart_led_on;
++ temp1[0].offfunc = uart_led_off;
++ register_led_drv( 6 , &temp1[0]);
++#endif
++
++#if defined(CONFIG_AR5W01)
++ /* Register led 8 UART Pin 1 */
++ temp1[0].param = 0;
++ temp1[0].init = NULL;
++ temp1[0].onfunc = uart_led_on;
++ temp1[0].offfunc = uart_led_off;
++ register_led_drv( 8 , &temp1[0]);
++#endif
++
++ /* Initialize the link mask */
++ device_lock = SPIN_LOCK_UNLOCKED;
++
++ return;
++}
++
+diff -urN linux.dev/include/asm-mips/ar7/led_config.h linux.dev2/include/asm-mips/ar7/led_config.h
+--- linux.dev/include/asm-mips/ar7/led_config.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev2/include/asm-mips/ar7/led_config.h 2005-10-21 17:02:25.568327000 +0200
+@@ -0,0 +1,55 @@
++/******************************************************************************
++ * FILE PURPOSE: - LED config Header
++ ******************************************************************************
++ * FILE NAME: led_config.h
++ *
++ * DESCRIPTION: Header file for LED configuration parameters
++ * and data structures
++ *
++ * REVISION HISTORY:
++ * 11 Oct 03 - PSP TII
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++
++#ifndef __LED_CONFIG__
++#define __LED_CONFIG__
++
++/* LED config parameters */
++#define MAX_GPIO_PIN_NUM 64
++#define MAX_GPIOS_PER_STATE 5
++#define MAX_MODULE_ENTRIES 25
++#define MAX_MODULE_INSTANCES 4
++#define MAX_STATE_ENTRIES 25
++#define MAX_LED_ENTRIES 25
++
++
++/* LED modes */
++#define LED_OFF 0
++#define LED_ON 1
++#define LED_ONESHOT_OFF 2
++#define LED_ONESHOT_ON 3
++#define LED_FLASH 4
++#define LED_BLINK_CODE0 5 /*--- param1: on time, param2: blink nr , (param2 > 100 blink off) ---*/
++#define LED_BLINK_CODE1 6
++#define LED_BLINK_CODE2 7
++
++#define NUM_LED_MODES 8
++
++
++
++/* Data structure for LED configuration */
++typedef struct led_config{
++ unsigned char name[80];
++ unsigned int instance;
++ unsigned int state;
++ unsigned int gpio[MAX_GPIOS_PER_STATE];
++ unsigned int mode[MAX_GPIOS_PER_STATE];
++ unsigned int gpio_num;
++ unsigned int param1;
++ unsigned int param2;
++}LED_CONFIG_T;
++
++
++#endif /* __LED_CONFIG__ */
+diff -urN linux.dev/include/asm-mips/ar7/led_hal.h linux.dev2/include/asm-mips/ar7/led_hal.h
+--- linux.dev/include/asm-mips/ar7/led_hal.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev2/include/asm-mips/ar7/led_hal.h 2005-10-21 17:02:25.568327000 +0200
+@@ -0,0 +1,30 @@
++/******************************************************************************
++ * FILE PURPOSE: - LED HAL module Header
++ ******************************************************************************
++ * FILE NAME: led_hal.h
++ *
++ * DESCRIPTION: LED HAL API's.
++ *
++ * REVISION HISTORY:
++ * 11 Oct 03 - PSP TII
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++#ifndef __LED_HAL__
++#define __LED_HAL__
++
++/* Interface prototypes */
++#include "led_config.h"
++
++int avalanche_led_hal_init (int *gpio_off_value, int num_gpio_pins);
++int avalanche_led_config_set (LED_CONFIG_T * led_cfg);
++int avalanche_led_config_get (LED_CONFIG_T *led_cfg,int module_id,int instance, int state);
++void *avalanche_led_register (const char *module_name, int instance_num);
++void avalanche_led_action (void *handle, int state_id);
++void avalanche_led_late_actions(void);
++int avalanche_led_unregister (void *handle);
++void avalanche_led_free_all(void);
++void avalanche_led_hal_exit (void);
++
++#endif /*__LED_HAL__ */
+diff -urN linux.dev/include/asm-mips/ar7/ledapp.h linux.dev2/include/asm-mips/ar7/ledapp.h
+--- linux.dev/include/asm-mips/ar7/ledapp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev2/include/asm-mips/ar7/ledapp.h 2005-10-21 18:03:44.573780750 +0200
+@@ -0,0 +1,59 @@
++#ifndef __LED_APP__
++#define __LED_APP__
++
++#define CONF_FILE "/etc/led.conf"
++#define LED_PROC_FILE "/proc/led_mod/led"
++
++#define CONFIG_LED_MODULE
++
++#define MAX_MOD_ID 25
++#define MAX_STATE_ID 25
++#define MAX_LED_ID 25
++
++#define MOD_ADSL 1
++#define DEF_ADSL_IDLE 1
++#define DEF_ADSL_TRAINING 2
++#define DEF_ADSL_SYNC 3
++#define DEF_ADSL_ACTIVITY 4
++
++#define MOD_WAN 2
++#define DEF_WAN_IDLE 1
++#define DEF_WAN_NEGOTIATE 2
++#define DEF_WAN_SESSION 3
++
++#define MOD_LAN 3
++#define DEF_LAN_IDLE 1
++#define DEF_LAN_LINK_UP 2
++#define DEF_LAN_ACTIVITY 3
++
++#define MOD_WLAN 4
++#define DEF_WLAN_IDLE 1
++#define DEF_WLAN_LINK_UP 2
++#define DEF_WLAN_ACTIVITY 3
++
++#define MOD_USB 5
++#define DEF_USB_IDLE 1
++#define DEF_USB_LINK_UP 2
++#define DEF_USB_ACTIVITY 3
++
++#define MOD_ETH 6
++#define DEF_ETH_IDLE 1
++#define DEF_ETH_LINK_UP 2
++#define DEF_ETH_ACTIVITY 3
++
++typedef struct config_elem{
++ unsigned char name;
++ unsigned char state;
++ unsigned char mode;
++ unsigned char led;
++ int param;
++}config_elem_t;
++
++typedef struct led_reg{
++ unsigned int param;
++ void (*init)(unsigned long param);
++ void (*onfunc)(unsigned long param);
++ void (*offfunc)(unsigned long param);
++}led_reg_t;
++
++#endif
diff --git a/target/linux/ar7-2.4/patches/003-net_driver_cpmac.patch b/target/linux/ar7-2.4/patches/003-net_driver_cpmac.patch
new file mode 100644
index 0000000..06df07d
--- /dev/null
+++ b/target/linux/ar7-2.4/patches/003-net_driver_cpmac.patch
@@ -0,0 +1,13341 @@
+diff -urN linux.old/drivers/net/avalanche_cpmac/cpcommon_cpmac.c linux.dev/drivers/net/avalanche_cpmac/cpcommon_cpmac.c
+--- linux.old/drivers/net/avalanche_cpmac/cpcommon_cpmac.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/cpcommon_cpmac.c 2005-07-12 02:48:41.996601000 +0200
+@@ -0,0 +1,728 @@
++#ifndef _INC_CPCOMMON_C
++#define _INC_CPCOMMON_C
++
++#ifdef _CPHAL_CPMAC
++#include "cpremap_cpmac.c"
++#endif
++
++#ifdef _CPHAL_AAL5
++#include "cpremap_cpaal5.c"
++#endif
++
++#ifdef _CPHAL_CPSAR
++#include "cpremap_cpsar.c"
++#endif
++
++#ifdef _CPHAL_AAL2
++#include "cpremap_cpaal2.c"
++#endif
++
++/**
++@defgroup Common_Config_Params Common Configuration Parameters
++
++This section documents the configuration parameters that are valid across
++all CPHAL devices.
++@{
++*/
++/** This is the debug level. The field is bit defined, such that the user
++should set to 1 all the bits corresponding to desired debug outputs. The following
++are the meanings for each debug bit:
++- bit0 (LSB): CPHAL Function Trace
++- b1 : OS Function call trace
++- b2 : Critical section entry/exit
++- b3 : Memory allocation/destruction
++- b4 : Detailed information in Rx path
++- b5 : Detailed information in Tx path
++- b6 : Extended error information
++- b7 : General info
++*/
++static const char pszDebug[] = "debug";
++/** CPU Frequency. */
++/*static const char pszCpuFreq[] = "CpuFreq";*/ /*MJH-030403*/
++/** Base address for the module. */
++static const char pszBase[] = "base";
++/** Reset bit for the module. */
++static const char pszResetBit[] = "reset_bit";
++/** Reset base address for the module. */
++static const char pszResetBase[] = "ResetBase";
++/** Interrupt line for the module. */
++static const char pszIntLine[] = "int_line";
++/** VLYNQ offset for the module. Disregard if not using VLYNQ. */
++static const char pszOffset[] = "offset";
++/** The OS may "Get" this parameter, which is a pointer
++ to a character string that indicates the version of CPHAL. */
++static const char pszVer[] = "Version";
++/*@}*/
++
++/**
++@defgroup Common_Control_Params Common Keys for [os]Control()
++
++This section documents the keys used with the OS @c Control() interface that
++are required by CPHAL devices.
++
++@{
++*/
++/** Used to wait for an integer number of clock ticks, given as an integer
++ pointer in the @p Value parameter. No actions are defined. */
++static const char pszSleep[] = "Sleep";
++/** Requests the OS to flush it's IO buffers. No actions are defined. */
++static const char pszSioFlush[] = "SioFlush";
++/*@}*/
++
++static const char pszStateChange[] = "StateChange";
++static const char pszStatus[] = "Status";
++
++static const char pszGET[] = "Get";
++static const char pszSET[] = "Set";
++static const char pszCLEAR[] = "Clear";
++static const char pszNULL[] = "";
++static const char pszLocator[] = "Locator";
++static const char pszOff[] = "Off";
++static const char pszOn[] = "On";
++static const char hcMaxFrags[] = "MaxFrags";
++
++#ifdef _CPHAL_CPMAC
++
++/* New method for string constants */
++const char hcClear[] = "Clear";
++const char hcGet[] = "Get";
++const char hcSet[] = "Set";
++
++const char hcTick[] = "Tick";
++
++static const CONTROL_KEY KeyCommon[] =
++ {
++ {"" , enCommonStart},
++ {pszStatus , enStatus},
++ {pszOff , enOff},
++ {pszOn , enOn},
++ {pszDebug , enDebug},
++ {hcCpuFrequency , enCpuFreq}, /*MJH~030403*/
++ {"" , enCommonEnd}
++ };
++#endif
++
++/**
++@defgroup Common_Statistics Statistics
++
++A broad array of module statistics is available. Statistics values are accessed
++through the @c Control() interface of the CPHAL. There are 5 different levels
++of statistics, each of which correspond to a unique set of data. Furthermore,
++certain statistics data is indexed by using a channel number and Tx queue number.
++The following is a brief description of each statistics level, along with the
++indexes used for the level:
++
++- Level 0: Hardware Statistics (index with channel)
++- Level 1: CPHAL Software Statistics (channel, queue)
++- Level 2: CPHAL Flags (channel, queue)
++- Level 3: CPHAL Channel Configuration (channel)
++- Level 4: CPHAL General Configuration (no index)
++
++The caller requests statistics information by providing a Key string to the
++@c Control() API in the following format: "Stats;[Level #];[Ch #];[Queue #]".
++The only valid Action parameter for statistics usage is "Get".
++
++Code Examples:
++@code
++unsigned int *StatsData;
++
++# Get Level 0 stats for Channel 1
++HalFunc->Control(OsDev->HalDev, "Stats;0;1", "Get", &StatsData);
++
++# Get Level 2 stats for Channel 0, Queue 0
++HalFunc->Control(OsDev->HalDev, "Stats;2;0;0", "Get", &StatsData);
++
++# Get Level 4 stats
++HalFunc->Control(OsDev->HalDev, "Stats;4", "Get", &StatsData);
++@endcode
++
++The information returned in the Value parameter of @c Control() is an
++array of pointers to strings. The pointers are arranged in pairs.
++The first pointer is a pointer to a name string for a particular statistic.
++The next pointer is a pointer to a string containing the representation of
++the integer statistic value corresponding to the first pointer. This is followed
++by another pair of pointers, and so on, until a NULL pointer is encountered. The
++following is example code for processing the statistics data. Note that the OS
++is responsible for freeing the memory passed back through the Value parameter of
++@c Control().
++
++@code
++unsigned int *StatsData;
++
++# Get Level 0 stats for Channel 1
++HalFunc->Control(OsDev->HalDev, "Stats;0;1", "Get", &StatsData);
++
++# output Statistics data
++PrintStats(StatsData);
++
++# the upper layer is responsible for freeing stats info
++free(&StatsPtr);
++
++...
++
++void PrintStats(unsigned int *StatsPtr)
++ {
++ while(*StatsPtr)
++ {
++ printf("%20s:", (char *)*StatsPtr);
++ StatsPtr++;
++ printf("%11s\n", (char *)*StatsPtr);
++ StatsPtr++;
++ }
++ MySioFlush();
++ }
++@endcode
++
++Within each statistics level, there are several statistics defined. The statistics that
++are common to every CPPI module are listed below. In addition, each module may define
++extra statistics in each level, which will be documented within the module-specific
++documentation appendices.
++
++- Level 0 Statistics
++ - All level 0 statistics are module-specific.
++- Level 1 Statistics (CPHAL Software Statistics)
++ - DmaLenErrors: Incremented when the port DMA's more data than expected (per channel). (AAL5 Only)
++ - TxMisQCnt: Incremented when host queues a packet for transmission as the port finishes
++transmitting the previous last packet in the queue (per channel and queue).
++ - RxMisQCnt: Incremented when host queues adds buffers to a queue as the port finished the
++reception of the previous last packet in the queue (per channel).
++ - TxEOQCnt: Number of times the port has reached the end of the transmit queue (per channel and queue).
++ - RxEOQCnt: Number of times the port has reached the end of the receive queue (per channel).
++ - RxPacketsServiced: Number of received packets (per channel).
++ - TxPacketsServiced: Number of transmitted packets (per channel and queue).
++ - RxMaxServiced: Maximum number of packets that the CPHAL receive interrupt has serviced at a time (per channel).
++ - TxMaxServiced: Maximum number of packets that the CPHAL transmit interrupt has serviced at a time (per channel and queue).
++ - RxTotal: Total number of received packets, all channels.
++ - TxTotal: Total number of transmitted packets, all channels and queues.
++- Level 2 Statistics (CPHAL Flags)
++ - RcbPool: Pointer to receive descriptor pool (per channel).
++ - RxActQueueCount: Number of buffers currently available for receive (per channel).
++ - RxActQueueHead: Pointer to first buffer in receive queue (per channel).
++ - RxActQueueTail: Pointer to last buffer in receive queue (per channel).
++ - RxActive: 0 if inactive (no buffers available), or 1 if active (buffers available).
++ - RcbStart: Pointer to block of receive descriptors.
++ - RxTeardownPending: 1 if Rx teardown is pending but incomplete, 0 otherwise.
++ - TcbPool: Pointer to transmit descriptor pool (per channel and queue).
++ - TxActQueueCount: Number of buffers currently queued to be transmitted (per channel and queue).
++ - TxActQueueHead: Pointer to first buffer in transmit queue (per channel and queue).
++ - TxActQueueTail: Pointer to last buffer in transmit queue (per channel and queue).
++ - TxActive: 0 if inactive (no buffers to send), or 1 if active (buffers queued to send).
++ - TcbStart: Pointer to block of transmit descriptors.
++ - TxTeardownPending: 1 if Tx teardown is pending but incomplete, 0 otherwise.
++- Level 3 Statistics (CPHAL Channel Configuration)
++ - RxBufSize: Rx buffer size.
++ - RxBufferOffset: Rx buffer offset.
++ - RxNumBuffers: Number of Rx buffers.
++ - RxServiceMax: Maximum number of receive packets to service at a time.
++ - TxNumBuffers: Number of Tx buffer descriptors.
++ - TxNumQueues: Number of Tx queues to use.
++ - TxServiceMax: Maximum number of transmit packets to service at a time.
++- Level 4 Statistics (CPHAL General Configuration)
++ - Base Address: Base address of the module.
++ - Offset (VLYNQ): VLYNQ relative module offset.
++ - Interrupt Line: Interrupt number.
++ - Debug: Debug flag, 1 to enable debug.
++ - Inst: Instance number.
++*/
++
++/*
++ Data Type 0 = int display
++ Data Type 1 = hex display
++ Data Type 2 = channel structure, int display
++ Data Type 3 = queue index and int display
++ Data Type 4 = queue index and hex display
++*/
++#if (defined(_CPHAL_AAL5) || defined(_CPHAL_CPMAC)) /* +GSG 030307 */
++static STATS_TABLE StatsTable0[] =
++ {
++#ifdef _CPHAL_AAL5
++ /* Name , Data Ptr, Data Type */
++ {"Crc Errors", 0, 0},
++ {"Len Errors", 0, 0},
++ {"Abort Errors", 0, 0},
++ {"Starv Errors", 0, 0}
++#endif
++#ifdef _CPHAL_CPMAC
++ {"Rx Good Frames", 0, 0}
++#endif
++ };
++
++static STATS_TABLE StatsTable1[] =
++ {
++ /* Name , Data Ptr, Data Type */
++ {"DmaLenErrors", 0, 0},
++ {"TxMisQCnt", 0, 3},
++ {"RxMisQCnt", 0, 0},
++ {"TxEOQCnt", 0, 3},
++ {"RxEOQCnt", 0, 0},
++ {"RxPacketsServiced", 0, 0},
++ {"TxPacketsServiced", 0, 3},
++ {"RxMaxServiced", 0, 0},
++ {"TxMaxServiced", 0, 3},
++ {"RxTotal", 0, 0},
++ {"TxTotal", 0, 0},
++ };
++
++static STATS_TABLE StatsTable2[] =
++ {
++ /* Name , Data Ptr, Data Type */
++ {"RcbPool", 0, 1},
++ {"RxActQueueCount", 0, 0},
++ {"RxActQueueHead", 0, 1},
++ {"RxActQueueTail", 0, 1},
++ {"RxActive", 0, 0},
++ {"RcbStart", 0, 1},
++ {"RxTeardownPending", 0, 0},
++ {"TcbPool", 0, 4},
++ {"TxActQueueCount", 0, 3},
++ {"TxActQueueHead", 0, 4},
++ {"TxActQueueTail", 0, 4},
++ {"TxActive", 0, 3},
++ {"TcbStart", 0, 4},
++ {"TxTeardownPending", 0, 0}
++ };
++
++static STATS_TABLE StatsTable3[] =
++ {
++ /* Name , Data Ptr, Data Type */
++ {"RxBufSize", 0, 2},
++ {"RxBufferOffset", 0, 2},
++ {"RxNumBuffers", 0, 2},
++ {"RxServiceMax", 0, 2},
++ {"TxNumBuffers", 0, 2},
++ {"TxNumQueues", 0, 2},
++ {"TxServiceMax", 0, 2},
++#ifdef _CPHAL_AAL5
++ {"CpcsUU", 0, 2},
++ {"Gfc", 0, 2},
++ {"Clp", 0, 2},
++ {"Pti", 0, 2},
++ {"DaMask", 0, 2},
++ {"Priority", 0, 2},
++ {"PktType", 0, 2},
++ {"Vci", 0, 2},
++ {"Vpi", 0, 2},
++ {"CellRate", 0, 2},
++ {"QosType", 0, 2},
++ {"Mbs", 0, 2},
++ {"Pcr", 0, 2}
++#endif
++ };
++
++static STATS_TABLE StatsTable4[] =
++ {
++ {"Base Address", 0, 1},
++ {"Offset (VLYNQ)", 0, 0},
++ {"Interrupt Line", 0, 0},
++ {"Debug", 0, 0},
++ {"Instance", 0, 0},
++#ifdef _CPHAL_AAL5
++ {"UniNni", 0, 0}
++#endif
++ };
++
++static STATS_DB StatsDb[] =
++ {
++ {(sizeof(StatsTable0)/sizeof(STATS_TABLE)), StatsTable0},
++ {(sizeof(StatsTable1)/sizeof(STATS_TABLE)), StatsTable1},
++ {(sizeof(StatsTable2)/sizeof(STATS_TABLE)), StatsTable2},
++ {(sizeof(StatsTable3)/sizeof(STATS_TABLE)), StatsTable3},
++ {(sizeof(StatsTable4)/sizeof(STATS_TABLE)), StatsTable4}
++ };
++#endif /* +GSG 030307 */
++
++#ifdef _CPHAL_CPMAC /* +RC 3.02 */
++static void resetWait(HAL_DEVICE *HalDev)
++ { /*+RC3.02*/
++ const int TickReset=64;
++ osfuncSleep((int*)&TickReset);
++ } /*+RC3.02*/
++#endif /* +RC 3.02 */
++
++/* I only define the reset base function for the modules
++ that can perform a reset. The AAL5 and AAL2 modules
++ do not perform a reset, that is done by the shared module
++ CPSAR */
++#if defined(_CPHAL_CPSAR) || defined(_CPHAL_CPMAC) || defined(_CPHAL_VDMAVT)
++/*
++ * Determines the reset register address to be used for a particular device.
++ * It will search the current device entry for Locator information. If the
++ * device is a root device, there will be no Locator information, and the
++ * function will find and return the root reset register. If a Locator value
++ * is found, the function will search each VLYNQ device entry in the system
++ * looking for a matching Locator. Once it finds a VLYNQ device entry with
++ * a matching Locator, it will extract the "ResetBase" parameter from that
++ * VLYNQ device entry (thus every VLYNQ entry must have the ResetBase parameter).
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param ResetBase Pointer to integer address of reset register.
++ *
++ * @return 0 OK, Non-zero not OK
++ */
++static int ResetBaseGet(HAL_DEVICE *HalDev, bit32u *ResetBase)
++ {
++ char *DeviceInfo = HalDev->DeviceInfo;
++ char *MyLocator, *NextLocator;
++ int Inst=1;
++ bit32u error_code;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpcommon]ResetBaseGet(HalDev:%08x, ResetBase:%08x)\n", (bit32u)HalDev, ResetBase);
++ osfuncSioFlush();
++ }
++#endif
++
++ error_code = HalDev->OsFunc->DeviceFindParmValue(DeviceInfo, "Locator", &MyLocator);
++ if (error_code)
++ {
++ /* if no Locator value, device is on the root, so get the "reset" device */
++ error_code = HalDev->OsFunc->DeviceFindInfo(0, "reset", &DeviceInfo);
++ if (error_code)
++ {
++ return(EC_VAL_DEVICE_NOT_FOUND);
++ }
++
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, "base", ResetBase);
++ if (error_code)
++ {
++ return(EC_VAL_BASE_ADDR_NOT_FOUND);
++ }
++
++ *ResetBase = ((bit32u)PhysToVirtNoCache(*ResetBase));
++
++ /* found base address for root device, so we're done */
++ return (EC_NO_ERRORS);
++ }
++ else
++ {
++ /* we have a Locator value, so the device is remote */
++
++ /* Find a vlynq device with a matching locator value */
++ while ((HalDev->OsFunc->DeviceFindInfo(Inst, "vlynq", &DeviceInfo)) == EC_NO_ERRORS)
++ {
++ error_code = HalDev->OsFunc->DeviceFindParmValue(DeviceInfo, "Locator", &NextLocator);
++ if (error_code)
++ {
++ /* no Locator value for this VLYNQ, so move on */
++ continue;
++ }
++ if (HalDev->OsFunc->Strcmpi(MyLocator, NextLocator)==0)
++ {
++ /* we have found a VLYNQ with a matching Locator, so extract the ResetBase */
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, "ResetBase", ResetBase);
++ if (error_code)
++ {
++ return(EC_VAL_BASE_ADDR_NOT_FOUND);
++ }
++ *ResetBase = ((bit32u)PhysToVirtNoCache(*ResetBase));
++
++ /* found base address for root device, so we're done */
++ return (EC_NO_ERRORS);
++ }
++ Inst++;
++ } /* while */
++ } /* else */
++
++ return (EC_NO_ERRORS);
++ }
++#endif
++
++#ifndef _CPHAL_AAL2 /* + RC 3.02 */
++static bit32u ConfigGetCommon(HAL_DEVICE *HalDev)
++ {
++ bit32u ParmValue;
++ bit32 error_code;
++ char *DeviceInfo = HalDev->DeviceInfo;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpcommon]ConfigGetCommon(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszBase, &ParmValue);
++ if (error_code)
++ {
++ return(EC_FUNC_HAL_INIT|EC_VAL_BASE_ADDR_NOT_FOUND);
++ }
++ HalDev->dev_base = ((bit32u)PhysToVirtNoCache(ParmValue));
++
++#ifndef _CPHAL_AAL5
++#ifndef _CPHAL_AAL2
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszResetBit, &ParmValue);
++ if(error_code)
++ {
++ return(EC_FUNC_HAL_INIT|EC_VAL_RESET_BIT_NOT_FOUND);
++ }
++ HalDev->ResetBit = ParmValue;
++
++ /* Get reset base address */
++ error_code = ResetBaseGet(HalDev, &ParmValue);
++ if (error_code)
++ return(EC_FUNC_HAL_INIT|EC_VAL_RESET_BASE_NOT_FOUND);
++ HalDev->ResetBase = ParmValue;
++#endif
++#endif
++
++#ifndef _CPHAL_CPSAR
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszIntLine,&ParmValue);
++ if (error_code)
++ {
++ return(EC_FUNC_HAL_INIT|EC_VAL_INTERRUPT_NOT_FOUND);
++ }
++ HalDev->interrupt = ParmValue;
++#endif
++
++ /* only look for the offset if there is a Locator field, which indicates that
++ the module is a VLYNQ module */
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszLocator,&ParmValue);
++ if (!error_code)
++ {
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszOffset,&ParmValue);
++ if (error_code)
++ {
++ return(EC_FUNC_HAL_INIT|EC_VAL_OFFSET_NOT_FOUND);
++ }
++ HalDev->offset = ParmValue;
++ }
++ else
++ HalDev->offset = 0;
++
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszDebug, &ParmValue);
++ if (!error_code) HalDev->debug = ParmValue;
++
++ return (EC_NO_ERRORS);
++ }
++#endif /* +RC 3.02 */
++
++#ifdef _CPHAL_CPMAC /* +RC 3.02 */
++static void StatsInit(HAL_DEVICE *HalDev) /* +() RC3.02 */
++ {
++ /* even though these statistics may be for multiple channels and
++ queues, i need only configure the pointer to the beginning
++ of the array, and I can index from there if necessary */
++
++#ifdef _CPHAL_AAL5
++ StatsTable0[0].StatPtr = &HalDev->Stats.CrcErrors[0];
++ StatsTable0[1].StatPtr = &HalDev->Stats.LenErrors[0];
++ StatsTable0[2].StatPtr = &HalDev->Stats.AbortErrors[0];
++ StatsTable0[3].StatPtr = &HalDev->Stats.StarvErrors[0];
++
++ StatsTable1[0].StatPtr = &HalDev->Stats.DmaLenErrors[0];
++ StatsTable1[1].StatPtr = &HalDev->Stats.TxMisQCnt[0][0];
++ StatsTable1[2].StatPtr = &HalDev->Stats.RxMisQCnt[0];
++ StatsTable1[3].StatPtr = &HalDev->Stats.TxEOQCnt[0][0];
++ StatsTable1[4].StatPtr = &HalDev->Stats.RxEOQCnt[0];
++ StatsTable1[5].StatPtr = &HalDev->Stats.RxPacketsServiced[0];
++ StatsTable1[6].StatPtr = &HalDev->Stats.TxPacketsServiced[0][0];
++ StatsTable1[7].StatPtr = &HalDev->Stats.RxMaxServiced;
++ StatsTable1[8].StatPtr = &HalDev->Stats.TxMaxServiced[0][0];
++ StatsTable1[9].StatPtr = &HalDev->Stats.RxTotal;
++ StatsTable1[10].StatPtr = &HalDev->Stats.TxTotal;
++#endif
++
++#if (defined(_CPHAL_AAL5) || defined(_CPHAL_CPMAC))
++ StatsTable2[0].StatPtr = (bit32u *)&HalDev->RcbPool[0];
++ StatsTable2[1].StatPtr = &HalDev->RxActQueueCount[0];
++ StatsTable2[2].StatPtr = (bit32u *)&HalDev->RxActQueueHead[0];
++ StatsTable2[3].StatPtr = (bit32u *)&HalDev->RxActQueueTail[0];
++ StatsTable2[4].StatPtr = &HalDev->RxActive[0];
++ StatsTable2[5].StatPtr = (bit32u *)&HalDev->RcbStart[0];
++ StatsTable2[6].StatPtr = &HalDev->RxTeardownPending[0];
++ StatsTable2[7].StatPtr = (bit32u *)&HalDev->TcbPool[0][0];
++ StatsTable2[8].StatPtr = &HalDev->TxActQueueCount[0][0];
++ StatsTable2[9].StatPtr = (bit32u *)&HalDev->TxActQueueHead[0][0];
++ StatsTable2[10].StatPtr = (bit32u *)&HalDev->TxActQueueTail[0][0];
++ StatsTable2[11].StatPtr = &HalDev->TxActive[0][0];
++ StatsTable2[12].StatPtr = (bit32u *)&HalDev->TcbStart[0][0];
++ StatsTable2[13].StatPtr = &HalDev->TxTeardownPending[0];
++
++ StatsTable3[0].StatPtr = &HalDev->ChData[0].RxBufSize;
++ StatsTable3[1].StatPtr = &HalDev->ChData[0].RxBufferOffset;
++ StatsTable3[2].StatPtr = &HalDev->ChData[0].RxNumBuffers;
++ StatsTable3[3].StatPtr = &HalDev->ChData[0].RxServiceMax;
++ StatsTable3[4].StatPtr = &HalDev->ChData[0].TxNumBuffers;
++ StatsTable3[5].StatPtr = &HalDev->ChData[0].TxNumQueues;
++ StatsTable3[6].StatPtr = &HalDev->ChData[0].TxServiceMax;
++#ifdef _CPHAL_AAL5
++ StatsTable3[7].StatPtr = &HalDev->ChData[0].CpcsUU;
++ StatsTable3[8].StatPtr = &HalDev->ChData[0].Gfc;
++ StatsTable3[9].StatPtr = &HalDev->ChData[0].Clp;
++ StatsTable3[10].StatPtr = &HalDev->ChData[0].Pti;
++ StatsTable3[11].StatPtr = &HalDev->ChData[0].DaMask;
++ StatsTable3[12].StatPtr = &HalDev->ChData[0].Priority;
++ StatsTable3[13].StatPtr = &HalDev->ChData[0].PktType;
++ StatsTable3[14].StatPtr = &HalDev->ChData[0].Vci;
++ StatsTable3[15].StatPtr = &HalDev->ChData[0].Vpi;
++ StatsTable3[16].StatPtr = &HalDev->ChData[0].TxVc_CellRate;
++ StatsTable3[17].StatPtr = &HalDev->ChData[0].TxVc_QosType;
++ StatsTable3[18].StatPtr = &HalDev->ChData[0].TxVc_Mbs;
++ StatsTable3[19].StatPtr = &HalDev->ChData[0].TxVc_Pcr;
++#endif
++#endif
++
++ StatsTable4[0].StatPtr = &HalDev->dev_base;
++ StatsTable4[1].StatPtr = &HalDev->offset;
++ StatsTable4[2].StatPtr = &HalDev->interrupt;
++ StatsTable4[3].StatPtr = &HalDev->debug;
++ StatsTable4[4].StatPtr = &HalDev->Inst;
++ }
++#endif /* +RC 3.02 */
++
++#ifndef _CPHAL_CPSAR /* +RC 3.02 */
++#ifndef _CPHAL_AAL2 /* +RC 3.02 */
++/*
++ * Returns statistics information.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ *
++ * @return 0
++ */
++static int StatsGet(HAL_DEVICE *HalDev, void **StatPtr, int Index, int Ch, int Queue)
++ {
++ int Size;
++ bit32u *AddrPtr;
++ char *DataPtr;
++ STATS_TABLE *StatsTable;
++ int i, NumberOfStats;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpcommon]StatsGet(HalDev:%08x, StatPtr:%08x)\n",
++ (bit32u)HalDev, (bit32u)StatPtr);
++ osfuncSioFlush();
++ }
++#endif
++
++ StatsTable = StatsDb[Index].StatTable;
++ NumberOfStats = StatsDb[Index].NumberOfStats;
++
++ Size = sizeof(bit32u)*((NumberOfStats*2)+1);
++ Size += (NumberOfStats*11);
++ *StatPtr = (bit32u *)HalDev->OsFunc->Malloc(Size);
++
++ AddrPtr = (bit32u *) *StatPtr;
++ DataPtr = (char *)AddrPtr;
++ DataPtr += sizeof(bit32u)*((NumberOfStats*2)+1);
++
++ for (i=0; i<NumberOfStats; i++)
++ {
++ *AddrPtr++ = (bit32u)StatsTable[i].StatName;
++ *AddrPtr++ = (bit32u)DataPtr;
++ if (&StatsTable[i].StatPtr[Ch] != 0)
++ {
++ switch(StatsTable[i].DataType)
++ {
++ case 0:
++ HalDev->OsFunc->Sprintf(DataPtr, "%d", (bit32u *)StatsTable[i].StatPtr[Ch]);
++ break;
++ case 1:
++ HalDev->OsFunc->Sprintf(DataPtr, "0x%x", (bit32u *)StatsTable[i].StatPtr[Ch]);
++ break;
++ case 2:
++ HalDev->OsFunc->Sprintf(DataPtr, "%d", *((bit32u *)StatsTable[i].StatPtr + (Ch * (sizeof(CHANNEL_INFO)/4))));
++ break;
++ case 3:
++ HalDev->OsFunc->Sprintf(DataPtr, "%d", *((bit32u *)StatsTable[i].StatPtr + (Ch*MAX_QUEUE)+Queue));
++ break;
++ case 4:
++ HalDev->OsFunc->Sprintf(DataPtr, "0x%x", *((bit32u *)StatsTable[i].StatPtr + (Ch*MAX_QUEUE)+Queue));
++ break;
++ default:
++ /* invalid data type, due to CPHAL programming error */
++ break;
++ }
++ }
++ else
++ {
++ /* invalid statistics pointer, probably was not initialized */
++ }
++ DataPtr += HalDev->OsFunc->Strlen(DataPtr) + 1;
++ }
++
++ *AddrPtr = (bit32u) 0;
++
++ return (EC_NO_ERRORS);
++ }
++#endif /* +RC 3.02 */
++#endif /* +RC 3.02 */
++
++#ifdef _CPHAL_CPMAC
++static void gpioFunctional(int base, int bit)
++ { /*+RC3.02*/
++ bit32u GpioEnr = base + 0xC;
++ /* To make functional, set to zero */
++ *(volatile bit32u *)(GpioEnr) &= ~(1 << bit); /*+RC3.02*/
++ } /*+RC3.02*/
++
++
++/*+RC3.02*/
++/* Common function, Checks to see if GPIO should be in functional mode */
++static void gpioCheck(HAL_DEVICE *HalDev, void *moduleDeviceInfo)
++ { /*+RC3.02*/
++ int rc;
++ void *DeviceInfo;
++ char *pszMuxBits;
++ char pszMuxBit[20];
++ char *pszTmp;
++ char szMuxBit[20];
++ char *ptr;
++ int base;
++ int reset_bit;
++ int bit;
++ OS_FUNCTIONS *OsFunc = HalDev->OsFunc;
++
++ rc = OsFunc->DeviceFindParmValue(moduleDeviceInfo, "gpio_mux",&pszTmp);
++ if(rc) return;
++ /* gpio entry found, get GPIO register info and make functional */
++
++ /* temp copy until FinParmValue fixed */
++ ptr = &szMuxBit[0];
++ while ((*ptr++ = *pszTmp++));
++
++ pszMuxBits = &szMuxBit[0];
++
++ rc = OsFunc->DeviceFindInfo(0,"gpio",&DeviceInfo);
++ if(rc) return;
++
++ rc = OsFunc->DeviceFindParmUint(DeviceInfo, "base",&base);
++ if(rc) return;
++
++ rc = OsFunc->DeviceFindParmUint(DeviceInfo, "reset_bit",&reset_bit);
++ if(rc) return;
++
++ /* If GPIO still in reset, then exit */
++ if((VOLATILE32(HalDev->ResetBase) & (1 << reset_bit)) == 0)
++ return;
++ /* format for gpio_mux is gpio_mux = <int>;<int>;<int>...*/
++ while (*pszMuxBits)
++ {
++ pszTmp = &pszMuxBit[0];
++ if(*pszMuxBits == ';') pszMuxBits++;
++ while ((*pszMuxBits != ';') && (*pszMuxBits != '\0'))
++ {
++ osfuncSioFlush();
++ /*If value not a number, skip */
++ if((*pszMuxBits < '0') || (*pszMuxBits > '9'))
++ pszMuxBits++;
++ else
++ *pszTmp++ = *pszMuxBits++;
++ }
++ *pszTmp = '\0';
++ bit = OsFunc->Strtoul(pszMuxBit, &pszTmp, 10);
++ gpioFunctional(base, bit);
++ resetWait(HalDev); /* not sure if this is needed */
++ }
++ } /*+RC3.02*/
++#endif /* CPMAC */
++
++#ifdef _CPHAL_AAL5
++const char hcSarFrequency[] = "SarFreq";
++#endif
++
++#endif /* _INC */
+diff -urN linux.old/drivers/net/avalanche_cpmac/cpcommon_cpmac.h linux.dev/drivers/net/avalanche_cpmac/cpcommon_cpmac.h
+--- linux.old/drivers/net/avalanche_cpmac/cpcommon_cpmac.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/cpcommon_cpmac.h 2005-07-12 02:48:41.996601000 +0200
+@@ -0,0 +1,79 @@
++#ifndef _INC_CPCOMMON_H
++#define _INC_CPCOMMON_H
++
++#define VOLATILE32(addr) (*(volatile bit32u *)(addr))
++#ifndef dbgPrintf
++#define dbgPrintf HalDev->OsFunc->Printf
++#endif
++
++#define ChannelUpdate(Field) if(HalChn->Field != 0xFFFFFFFF) HalDev->ChData[Ch].Field = HalChn->Field
++
++#define DBG(level) (HalDev->debug & (1<<(level)))
++/*
++#define DBG0() DBG(0)
++#define DBG1() DBG(1)
++#define DBG2() DBG(2)
++#define DBG3() DBG(3)
++#define DBG4() DBG(4)
++#define DBG5() DBG(5)
++#define DBG6() DBG(6)
++#define DBG7() DBG(7)
++*/
++
++/*
++ * List of defined actions for use with Control().
++ */
++typedef enum
++ {
++ enGET=0, /**< Get the value associated with a key */
++ enSET, /**< Set the value associates with a key */
++ enCLEAR, /**<Clear the value */
++ enNULL /**< No data action, used to initiate a service or send a message */
++ }ACTION;
++
++/*
++ * Enumerated hardware states.
++ */
++typedef enum
++ {
++ enConnected=1, enDevFound, enInitialized, enOpened
++ }DEVICE_STATE;
++
++typedef enum
++ {
++ enCommonStart=0,
++ /* General */
++ enOff, enOn, enDebug,
++ /* Module General */
++ enCpuFreq,
++ enStatus,
++ enCommonEnd
++ }COMMON_KEY;
++
++typedef struct
++ {
++ const char *strKey;
++ int enKey;
++ }CONTROL_KEY;
++
++typedef struct
++ {
++ char *StatName;
++ unsigned int *StatPtr;
++ int DataType; /* 0: int, 1: hex int, 2:channel data */
++ }STATS_TABLE;
++
++typedef struct
++ {
++ int NumberOfStats;
++ STATS_TABLE *StatTable;
++ }STATS_DB;
++
++#define osfuncSioFlush() HalDev->OsFunc->Control(HalDev->OsDev,"SioFlush",pszNULL,0)
++#define osfuncSleep(Ticks) HalDev->OsFunc->Control(HalDev->OsDev,pszSleep,pszNULL,Ticks)
++#define osfuncStateChange() HalDev->OsFunc->Control(HalDev->OsDev,pszStateChange,pszNULL,0)
++
++#define CHANNEL_NAMES {"Ch0","Ch1","Ch2","Ch3","Ch4","Ch5","Ch6","Ch7","Ch8","Ch9","Ch10","Ch11","Ch12","Ch13","Ch14","Ch15"}
++
++#endif
++
+diff -urN linux.old/drivers/net/avalanche_cpmac/cpmac.c linux.dev/drivers/net/avalanche_cpmac/cpmac.c
+--- linux.old/drivers/net/avalanche_cpmac/cpmac.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/cpmac.c 2005-07-22 01:03:12.609318544 +0200
+@@ -0,0 +1,2504 @@
++/******************************************************************************
++ * FILE PURPOSE: CPMAC Linux Network Device Driver Source
++ ******************************************************************************
++ * FILE NAME: cpmac.c
++ *
++ * DESCRIPTION: CPMAC Network Device Driver Source
++ *
++ * REVISION HISTORY:
++ *
++ * Date Description Author
++ *-----------------------------------------------------------------------------
++ * 27 Nov 2002 Initial Creation Suraj S Iyer
++ * 09 Jun 2003 Updates for GA Suraj S Iyer
++ * 30 Sep 2003 Updates for LED, Reset stats Suraj S Iyer
++ *
++ * (C) Copyright 2003, Texas Instruments, Inc
++ *******************************************************************************/
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/proc_fs.h>
++#include <linux/ioport.h>
++#include <asm/io.h>
++
++#include <linux/skbuff.h>
++
++#include <asm/mips-boards/prom.h>
++#include <linux/string.h>
++#include <asm/uaccess.h>
++#include <linux/config.h>
++#include <asm/ar7/if_port.h>
++
++extern void build_psp_config(void);
++extern void psp_config_cleanup(void);
++
++#include "cpmacHalLx.h"
++#include "cpmac.h"
++
++static struct net_device *last_cpmac_device = NULL;
++static int cpmac_devices_installed = 0;
++
++void xdump( u_char* cp, int length, char* prefix );
++
++unsigned int cpmac_cpu_freq = 0;
++
++char cpmac_version[] = "1.5";
++
++char l3_align_array[] = {0x02, 0x01, 0x00, 0x03};
++#define L3_ALIGN(i) l3_align_array[i]
++
++char add_for_4byte_align[] = {0x04, 0x03, 0x02, 0x05};
++#define ADD_FOR_4BYTE_ALIGN(i) add_for_4byte_align[i]
++
++
++#define TPID 0x8100
++#define IS_802_1Q_FRAME(byte_ptr) (*(unsigned short*)byte_ptr == TPID)
++#define TPID_START_OFFSET 12
++#define TCI_START_OFFSET 14
++#define TCI_LENGTH 2
++#define TPID_LENGTH 2
++#define TPID_END_OFFSET (TPID_START_OFFSET + TPID_LENGTH)
++#define TCI_END_OFFSET (TCI_START_OFFSET + TCI_LENGTH)
++#define IS_VALID_VLAN_ID(byte_ptr) ((*(unsigned short*)byte_ptr) && 0xfff != 0)
++#define MAX_CLASSES 8
++#define MAX_USER_PRIORITY 8
++#define CONTROL_802_1Q_SIZE (TCI_LENGTH + TPID_LENGTH)
++
++unsigned char user_priority_to_traffic_class_map[MAX_CLASSES][MAX_USER_PRIORITY] =
++{
++ {0, 0, 0, 1, 1, 1, 1, 2},
++ {0, 0, 0, 0, 0, 0, 0, 0},
++ {0, 0, 0, 0, 0, 0, 0, 1},
++ {0, 0, 0, 1, 1, 2, 2, 3},
++ {0, 1, 1, 2, 2, 3, 3, 4},
++ {0, 1, 1, 2, 3, 4, 4, 5},
++ {0, 1, 2, 3, 4, 5, 5, 6},
++ {0, 1, 2, 3, 4, 5, 6, 7}
++};
++
++#define GET_802_1P_CHAN(x,y) user_priority_to_traffic_class_map[x][(y & 0xe0)]
++
++#if defined(CONFIG_MIPS_SEAD2)
++unsigned long temp_base_address[2] = {0xa8610000, 0xa8612800};
++unsigned long temp_reset_value[2] = { 1<< 17,1<<21};
++#define RESET_REG_PRCR (*(volatile unsigned int *)((0xa8611600 + 0x0)))
++#define VERSION(base) (*(volatile unsigned int *)(((base)|0xa0000000) + 0x0))
++#endif
++
++MODULE_AUTHOR("Maintainer: Suraj S Iyer <ssiyer@ti.com>");
++MODULE_DESCRIPTION("Driver for TI CPMAC");
++
++static int cfg_link_speed = 0;
++MODULE_PARM(cfg_link_speed, "i");
++MODULE_PARM_DESC(cfg_link_speed, "Fixed speed of the Link: <100/10>");
++
++static char *cfg_link_mode = NULL;
++MODULE_PARM(cfg_link_mode, "1-3s");
++MODULE_PARM_DESC(cfg_link_mode, "Fixed mode of the Link: <fd/hd>");
++
++int cpmac_debug_mode = 0;
++MODULE_PARM(debug_mode, "i");
++MODULE_PARM_DESC(debug_mode, "Turn on the debug info: <0/1>. Default is 0 (off)");
++
++#define dbgPrint if (cpmac_debug_mode) printk
++#define errPrint printk
++
++static int g_cfg_start_link_params = CFG_START_LINK_SPEED;
++static int g_init_enable_flag = 0;
++static int cfg_start_link_speed;
++static int cpmac_max_frame_size;
++
++static struct net_device *g_dev_array[2];
++static struct proc_dir_entry *gp_stats_file = NULL;
++
++//-----------------------------------------------------------------------------
++// Statistics related private functions.
++//-----------------------------------------------------------------------------
++static int cpmac_p_update_statistics(struct net_device *p_dev, char *buf, int limit, int *len);
++static int cpmac_p_read_rfc2665_stats(char *buf, char **start, off_t offset, int count, int *eof, void *data);
++static int cpmac_p_read_link(char *buf, char **start, off_t offset, int count, int *eof, void *data);
++static int cpmac_p_read_stats(char* buf, char **start, off_t offset, int count, int *eof, void *data);
++static int cpmac_p_write_stats (struct file *fp, const char * buf, unsigned long count, void * data);
++static int cpmac_p_reset_statistics (struct net_device *p_dev);
++static int cpmac_p_get_version(char *buf, char **start, off_t offset, int count, int *eof, void *data);
++
++static int cpmac_p_detect_manual_cfg(int, char*, int);
++static int cpmac_p_process_status_ind(CPMAC_PRIVATE_INFO_T *p_cpmac_priv);
++
++//-----------------------------------------------------------------------------
++// Timer related private functions.
++//-----------------------------------------------------------------------------
++static int cpmac_p_timer_init(CPMAC_PRIVATE_INFO_T *p_cpmac_priv);
++// static int cpmac_timer_cleanup(CPMAC_PRIVATE_INFO_T *p_cpmac_priv);
++static void cpmac_p_tick_timer_expiry(unsigned long p_cb_param);
++inline static int cpmac_p_start_timer(struct timer_list *p_timer, unsigned int delay_ticks);
++static int cpmac_p_stop_timer(struct timer_list *p_timer);
++
++//------------------------------------------------------------------------------
++// Device configuration and setup related private functions.
++//------------------------------------------------------------------------------
++static int cpmac_p_probe_and_setup_device(CPMAC_PRIVATE_INFO_T *p_cpmac_priv, unsigned long *p_dev_flags);
++static int cpmac_p_setup_driver_params(CPMAC_PRIVATE_INFO_T *p_cpmac_priv);
++inline static int cpmac_p_rx_buf_setup(CPMAC_RX_CHAN_INFO_T *p_rx_chan);
++
++//-----------------------------------------------------------------------------
++// Net device related private functions.
++//-----------------------------------------------------------------------------
++static int cpmac_dev_init(struct net_device *p_dev);
++static int cpmac_dev_open( struct net_device *dev );
++static int cpmac_dev_close(struct net_device *p_dev);
++static void cpmac_dev_mcast_set(struct net_device *p_dev);
++static int cpmac_dev_set_mac_addr(struct net_device *p_dev,void * addr);
++static int cpmac_dev_tx( struct sk_buff *skb, struct net_device *p_dev);
++static struct net_device_stats *cpmac_dev_get_net_stats (struct net_device *dev);
++
++static int cpmac_p_dev_enable( struct net_device *p_dev);
++
++
++
++/* Max. Reserved headroom in front of each packet so that the headers can be added to
++ * a packet. Worst case scenario would be PPPoE + 2684 LLC Encapsulation + Ethernet
++ * header. */
++#define MAX_RESERVED_HEADROOM 20
++
++/* This is the MAX size of the static buffer for pure data. */
++#define MAX_SIZE_STATIC_BUFFER 1600
++
++typedef struct DRIVER_BUFFER
++{
++ /* Pointer to the allocated data buffer. This is the static data buffer
++ * allocated for the TI-Cache. 60 bytes out of the below buffer are required
++ * by the SKB shared info. We always reserve at least MAX_RESERVED_HEADROOM bytes
++ * so that the packets always have sufficient headroom. */
++ char ptr_buffer[MAX_SIZE_STATIC_BUFFER + MAX_RESERVED_HEADROOM + 60];
++
++ /* List of the driver buffers. */
++ struct DRIVER_BUFFER* ptr_next;
++}DRIVER_BUFFER;
++
++typedef struct DRIVER_BUFFER_MCB
++{
++ /* List of the driver buffers. */
++ DRIVER_BUFFER* ptr_available_driver_buffers;
++
++ /* The number of available buffers. */
++ int num_available_buffers;
++}DRIVER_BUFFER_MCB;
++
++DRIVER_BUFFER_MCB driver_mcb;
++int hybrid_mode = 0;
++
++static union {
++ struct sk_buff_head list;
++ char pad[SMP_CACHE_BYTES];
++} skb_head_pool[NR_CPUS];
++
++/**************************************************************************
++ * FUNCTION NAME : ti_release_skb
++ **************************************************************************
++ * DESCRIPTION :
++ * This function is called from the ti_alloc_skb when there were no more
++ * data buffers available. The allocated SKB had to released back to the
++ * data pool. The reason why this function was moved from the fast path
++ * below was because '__skb_queue_head' is an inline function which adds
++ * a large code chunk on the fast path.
++ *
++ * NOTES :
++ * This function is called with interrupts disabled.
++ **************************************************************************/
++static void ti_release_skb (struct sk_buff_head* list, struct sk_buff* skb)
++{
++ __skb_queue_head(list, skb);
++ return;
++}
++
++/**************************************************************************
++ * FUNCTION NAME : ti_alloc_skb
++ **************************************************************************
++ * DESCRIPTION :
++ * The function is called to allocate memory from the static allocated
++ * TI-Cached memory pool.
++ *
++ * RETURNS :
++ * Allocated static memory buffer - Success
++ * NULL - Error.
++ **************************************************************************/
++struct sk_buff *ti_alloc_skb(unsigned int size,int gfp_mask)
++{
++ register struct sk_buff* skb;
++ unsigned long flags;
++ struct sk_buff_head* list;
++ DRIVER_BUFFER* ptr_node = NULL;
++
++ /* Critical Section Begin: Lock out interrupts. */
++ local_irq_save(flags);
++
++ /* Get the SKB Pool list associated with the processor and dequeue the head. */
++ list = &skb_head_pool[smp_processor_id()].list;
++ skb = __skb_dequeue(list);
++
++ /* Align the data size. */
++ size = SKB_DATA_ALIGN(size);
++
++ /* Did we get one. */
++ if (skb != NULL)
++ {
++ /* YES. Now get a data block from the head of statically allocated block. */
++ ptr_node = driver_mcb.ptr_available_driver_buffers;
++ if (ptr_node != NULL)
++ {
++ /* YES. Got a data block. Advance the free list pointer to the next available buffer. */
++ driver_mcb.ptr_available_driver_buffers = ptr_node->ptr_next;
++ ptr_node->ptr_next = NULL;
++
++ /* Decrement the number of available data buffers. */
++ driver_mcb.num_available_buffers = driver_mcb.num_available_buffers - 1;
++ }
++ else
++ {
++ /* NO. Was unable to get a data block. So put the SKB back on the free list.
++ * This is slow path. */
++#ifdef DEBUG_SKB
++ printk ("DEBUG: No Buffer memory available: Number of free buffer:%d.\n",
++ driver_mcb.num_available_buffers);
++#endif
++ ti_release_skb (list, skb);
++ }
++ }
++
++ /* Critical Section End: Unlock interrupts. */
++ local_irq_restore(flags);
++
++ /* Did we get an SKB and data buffer. Proceed only if we were succesful in getting both else drop */
++ if (skb != NULL && ptr_node != NULL)
++ {
++ /* XXX: does not include slab overhead */
++ skb->truesize = size + sizeof(struct sk_buff);
++
++ /* Load the data pointers. */
++ skb->head = ptr_node->ptr_buffer;
++ skb->data = ptr_node->ptr_buffer + MAX_RESERVED_HEADROOM;
++ skb->tail = ptr_node->ptr_buffer + MAX_RESERVED_HEADROOM;
++ skb->end = ptr_node->ptr_buffer + size + MAX_RESERVED_HEADROOM;
++
++ /* Set up other state */
++ skb->len = 0;
++ skb->cloned = 0;
++ skb->data_len = 0;
++
++ /* Mark the SKB indicating that the SKB is from the TI cache. */
++ skb->cb[45] = 1;
++
++ atomic_set(&skb->users, 1);
++ atomic_set(&(skb_shinfo(skb)->dataref), 1);
++ skb_shinfo(skb)->nr_frags = 0;
++ skb_shinfo(skb)->frag_list = NULL;
++ return skb;
++ }
++ else
++ {
++ /* Control comes here only when there is no statically allocated data buffers
++ * available. This case is handled using the mode selected
++ *
++ * 1. Hybrid Mode.
++ * In that case lets jump to the old allocation code. This way we
++ * can allocate a small number of data buffers upfront and the rest will hit
++ * this portion of the code, which is slow path. Note the number of hits here
++ * should be kept as low as possible to satisfy performance requirements.
++ *
++ * 2. Pure Static Mode.
++ * Return NULL the user should have tuned the number of static buffers for
++ * worst case scenario. So return NULL and let the drivers handle the error. */
++ if (hybrid_mode == 1)
++ {
++ /* Hybrid Mode: Old allocation. */
++ return dev_alloc_skb(size);
++ }
++ else
++ {
++ /* Pure Static Mode: No buffers available. */
++ return NULL;
++ }
++ }
++}
++
++/**************************************************************************
++ * FUNCTION NAME : ti_skb_release_fragment
++ **************************************************************************
++ * DESCRIPTION :
++ * This function is called to release fragmented packets. This is NOT in
++ * the fast path and this function requires some work.
++ **************************************************************************/
++static void ti_skb_release_fragment(struct sk_buff *skb)
++{
++ if (skb_shinfo(skb)->nr_frags)
++ {
++ /* PANKAJ TODO: This portion has not been tested. */
++ int i;
++#ifdef DEBUG_SKB
++ printk ("DEBUG: Releasing fragments in TI-Cached code.\n");
++#endif
++ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
++ printk ("DEBUG: Fragmented Page = 0x%p.\n", skb_shinfo(skb)->frags[i].page);
++ }
++
++ /* Check if there were any fragments present and if so clean all the SKB's.
++ * This is required to recursivly clean the SKB's. */
++ if (skb_shinfo(skb)->frag_list)
++ skb_drop_fraglist(skb);
++
++ return;
++}
++
++/**************************************************************************
++ * FUNCTION NAME : ti_skb_release_data
++ **************************************************************************
++ * DESCRIPTION :
++ * The function is called to release the SKB back into the TI-Cached static
++ * memory pool.
++ **************************************************************************/
++static void ti_skb_release_data(struct sk_buff *skb)
++{
++ DRIVER_BUFFER* ptr_node;
++ unsigned long flags;
++
++ /* The SKB data can be cleaned only if the packet has not been cloned and we
++ * are the only one holding a reference to the data. */
++ if (!skb->cloned || atomic_dec_and_test(&(skb_shinfo(skb)->dataref)))
++ {
++ /* Are there any fragments associated with the SKB ?*/
++ if ((skb_shinfo(skb)->nr_frags != 0) || (skb_shinfo(skb)->frag_list != NULL))
++ {
++ /* Slow Path: Try and clean up the fragments. */
++ ti_skb_release_fragment (skb);
++ }
++
++ /* Cleanup the SKB data memory. This is fast path. */
++ ptr_node = (DRIVER_BUFFER *)skb->head;
++
++ /* Critical Section: Lock out interrupts. */
++ local_irq_save(flags);
++
++ /* Add the data buffer to the list of available buffers. */
++ ptr_node->ptr_next = driver_mcb.ptr_available_driver_buffers;
++ driver_mcb.ptr_available_driver_buffers = ptr_node;
++
++ /* Increment the number of available data buffers. */
++ driver_mcb.num_available_buffers = driver_mcb.num_available_buffers + 1;
++
++ /* Criticial Section: Unlock interrupts. */
++ local_irq_restore(flags);
++ }
++ return;
++}
++
++
++
++
++static unsigned char str2hexnum(unsigned char c)
++{
++ if(c >= '0' && c <= '9')
++ return c - '0';
++ if(c >= 'a' && c <= 'f')
++ return c - 'a' + 10;
++ if(c >= 'A' && c <= 'F')
++ return c - 'A' + 10;
++ return 0;
++}
++
++static void str2eaddr(unsigned char *ea, unsigned char *str)
++{
++ int i;
++ unsigned char num;
++ for(i = 0; i < 6; i++) {
++ if((*str == '.') || (*str == ':'))
++ str++;
++ num = str2hexnum(*str++) << 4;
++ num |= (str2hexnum(*str++));
++ ea[i] = num;
++ }
++}
++
++//-----------------------------------------------------------------------------
++// Statistics related private functions.
++//-----------------------------------------------------------------------------
++static int cpmac_p_update_statistics(struct net_device *p_dev, char *buf, int limit, int *p_len)
++{
++ int ret_val = -1;
++ unsigned long rx_hal_errors = 0;
++ unsigned long rx_hal_discards = 0;
++ unsigned long tx_hal_errors = 0;
++ unsigned long ifOutDiscards = 0;
++ unsigned long ifInDiscards = 0;
++ unsigned long ifOutErrors = 0;
++ unsigned long ifInErrors = 0;
++
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cpmac_priv->drv_hal;
++ CPMAC_DEVICE_MIB_T *p_device_mib = p_cpmac_priv->device_mib;
++ CPMAC_DRV_STATS_T *p_stats = p_cpmac_priv->stats;
++ CPMAC_DEVICE_MIB_T local_mib;
++ CPMAC_DEVICE_MIB_T *p_local_mib = &local_mib;
++
++ struct net_device_stats *p_net_dev_stats = &p_cpmac_priv->net_dev_stats;
++
++ int len = 0;
++ int dev_mib_elem_count = 0;
++
++ /* do not access the hardware if it is in the reset state. */
++ if(!test_bit(0, &p_cpmac_priv->set_to_close))
++ {
++ if(p_drv_hal->hal_funcs->Control(p_drv_hal->hal_dev, "StatsDump", "Get",
++ p_local_mib) != 0)
++ {
++ errPrint("The stats dump for %s is failing.\n", p_dev->name);
++ return(ret_val);
++ }
++
++ p_drv_hal->hal_funcs->Control(p_drv_hal->hal_dev, "StatsClear", "Set", NULL);
++
++ dev_mib_elem_count = sizeof(CPMAC_DEVICE_MIB_T)/sizeof(unsigned long);
++
++ /* Update the history of the stats. This takes care of any reset of the
++ * device and stats that might have taken place during the life time of
++ * the driver.
++ */
++ while(dev_mib_elem_count--)
++ {
++ *((unsigned long*) p_device_mib + dev_mib_elem_count) +=
++ *((unsigned long*) p_local_mib + dev_mib_elem_count);
++ }
++ }
++
++ /* RFC2665, section 3.2.7, page 9 */
++ rx_hal_errors = p_device_mib->ifInFragments +
++ p_device_mib->ifInCRCErrors +
++ p_device_mib->ifInAlignCodeErrors +
++ p_device_mib->ifInJabberFrames;
++
++ /* RFC2233 */
++ rx_hal_discards = p_device_mib->ifRxDMAOverruns;
++
++ /* RFC2665, section 3.2.7, page 9 */
++ tx_hal_errors = p_device_mib->ifExcessiveCollisionFrames +
++ p_device_mib->ifLateCollisions +
++ p_device_mib->ifCarrierSenseErrors +
++ p_device_mib->ifOutUnderrun;
++
++ /* if not set, the short frames (< 64 bytes) are considered as errors */
++ if(!p_cpmac_priv->flags & IFF_PRIV_SHORT_FRAMES)
++ rx_hal_errors += p_device_mib->ifInUndersizedFrames;
++
++ /* if not set, the long frames ( > 1518) are considered as errors
++ * RFC2665, section 3.2.7, page 9. */
++ if(!p_cpmac_priv->flags & IFF_PRIV_JUMBO_FRAMES)
++ rx_hal_errors += p_device_mib->ifInOversizedFrames;
++
++ /* if not in promiscous, then non addr matching frames are discarded */
++ /* CPMAC 2.0 Manual Section 2.8.1.14 */
++ if(!p_dev->flags & IFF_PROMISC)
++ {
++ ifInDiscards += p_device_mib->ifInFilteredFrames;
++ }
++
++ /* total rx discards = hal discards + driver discards. */
++ ifInDiscards = rx_hal_discards + p_net_dev_stats->rx_dropped;
++ ifInErrors = rx_hal_errors;
++
++ ifOutErrors = tx_hal_errors;
++ ifOutDiscards = p_net_dev_stats->tx_dropped;
++
++ /* Let us update the net device stats struct. To be updated in the later releases.*/
++ p_cpmac_priv->net_dev_stats.rx_errors = ifInErrors;
++ p_cpmac_priv->net_dev_stats.collisions = p_device_mib->ifCollisionFrames;
++
++ if(buf == NULL || limit == 0)
++ {
++ return(0);
++ }
++
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %ld\n", "ifSpeed", (long)p_cpmac_priv->link_speed);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "dot3StatsDuplexStatus", (long)p_cpmac_priv->link_mode);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifAdminStatus", (long)(p_dev->flags & IFF_UP ? 1:2));
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifOperStatus", (long)(((p_dev->flags & IFF_UP) && netif_carrier_ok(p_dev)) ? 1:2));
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifLastChange", p_stats->start_tick);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInDiscards", ifInDiscards);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInErrors", ifInErrors);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifOutDiscards", ifOutDiscards);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifOutErrors", ifOutErrors);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInGoodFrames", p_device_mib->ifInGoodFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInBroadcasts", p_device_mib->ifInBroadcasts);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInMulticasts", p_device_mib->ifInMulticasts);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInPauseFrames", p_device_mib->ifInPauseFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInCRCErrors", p_device_mib->ifInCRCErrors);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInAlignCodeErrors", p_device_mib->ifInAlignCodeErrors);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInOversizedFrames", p_device_mib->ifInOversizedFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInJabberFrames", p_device_mib->ifInJabberFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInUndersizedFrames", p_device_mib->ifInUndersizedFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInFragments", p_device_mib->ifInFragments);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInFilteredFrames", p_device_mib->ifInFilteredFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInQosFilteredFrames", p_device_mib->ifInQosFilteredFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifInOctets", p_device_mib->ifInOctets);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifOutGoodFrames", p_device_mib->ifOutGoodFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifOutBroadcasts", p_device_mib->ifOutBroadcasts);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifOutMulticasts", p_device_mib->ifOutMulticasts);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifOutPauseFrames", p_device_mib->ifOutPauseFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifDeferredTransmissions", p_device_mib->ifDeferredTransmissions);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifCollisionFrames", p_device_mib->ifCollisionFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifSingleCollisionFrames", p_device_mib->ifSingleCollisionFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifMultipleCollisionFrames", p_device_mib->ifMultipleCollisionFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifExcessiveCollisionFrames", p_device_mib->ifExcessiveCollisionFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifLateCollisions", p_device_mib->ifLateCollisions);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifOutUnderrun", p_device_mib->ifOutUnderrun);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifCarrierSenseErrors", p_device_mib->ifCarrierSenseErrors);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifOutOctets", p_device_mib->ifOutOctets);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "if64OctetFrames", p_device_mib->if64OctetFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "if65To127POctetFrames", p_device_mib->if65To127OctetFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "if128To255OctetFrames", p_device_mib->if128To255OctetFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "if256To511OctetFrames", p_device_mib->if256To511OctetFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "if512To1023OctetFrames", p_device_mib->if512To1023OctetFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "if1024ToUpOctetFrames", p_device_mib->if1024ToUPOctetFrames);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifNetOctets", p_device_mib->ifNetOctets);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifRxSofOverruns", p_device_mib->ifRxSofOverruns);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifRxMofOverruns", p_device_mib->ifRxMofOverruns);
++ if(len <= limit)
++ len+= sprintf(buf + len, "%-35s: %lu\n", "ifRxDMAOverruns", p_device_mib->ifRxDMAOverruns);
++
++ *p_len = len;
++
++ return(0);
++}
++
++
++static int cpmac_p_read_rfc2665_stats(char* buf, char **start, off_t offset,
++ int count, int *eof, void *data)
++{
++ int limit = count - 80;
++ int len = 0;
++ struct net_device *p_dev = (struct net_device*)data;
++
++ cpmac_p_update_statistics(p_dev, buf, limit, &len);
++
++ *eof = 1;
++
++ return len;
++}
++
++static int cpmac_p_read_link(char *buf, char **start, off_t offset, int count,
++ int *eof, void *data)
++{
++ int len = 0;
++
++ struct net_device *p_dev;
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv;
++ struct net_device *cpmac_dev_list[cpmac_devices_installed];
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal;
++
++ int i;
++ int phy; /* what phy are we using? */
++
++ len += sprintf(buf+len, "CPMAC devices = %d\n",cpmac_devices_installed);
++
++ p_dev = last_cpmac_device;
++
++ /* Reverse the the device link list to list eth0,eth1...in correct order */
++ for(i=0; i< cpmac_devices_installed; i++)
++ {
++ cpmac_dev_list[cpmac_devices_installed -(i+1)] = p_dev;
++ p_cpmac_priv = p_dev->priv;
++ p_dev = p_cpmac_priv->next_device;
++ }
++
++ for(i=0; i< cpmac_devices_installed; i++)
++ {
++ p_dev = cpmac_dev_list[i];
++ p_cpmac_priv = p_dev->priv;
++ p_drv_hal = p_cpmac_priv->drv_hal;
++
++ /* This prints them out from high to low because of how the devices are linked */
++ if(netif_carrier_ok(p_dev))
++ {
++ p_drv_hal->hal_funcs->Control(p_drv_hal->hal_dev, "PhyNum", "Get", &phy);
++
++
++ len += sprintf(buf+len,"eth%d: Link State: %s Phy:0x%x, Speed = %s, Duplex = %s\n",
++ p_cpmac_priv->instance_num, "UP", phy,
++ (p_cpmac_priv->link_speed == 100000000) ? "100":"10",
++ (p_cpmac_priv->link_mode == 2) ? "Half":"Full");
++
++ }
++ else
++ len += sprintf(buf+len,"eth%d: Link State: DOWN\n",p_cpmac_priv->instance_num);
++
++ p_dev = p_cpmac_priv->next_device;
++ }
++
++ return len;
++
++}
++
++static int cpmac_p_read_stats(char* buf, char **start, off_t offset, int count,
++ int *eof, void *data)
++{
++ struct net_device *p_dev = last_cpmac_device;
++ int len = 0;
++ int limit = count - 80;
++ int i;
++ struct net_device *cpmac_dev_list[cpmac_devices_installed];
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv;
++ CPMAC_DEVICE_MIB_T *p_device_mib;
++
++ /* Reverse the the device link list to list eth0,eth1...in correct order */
++ for(i=0; i< cpmac_devices_installed; i++)
++ {
++ cpmac_dev_list[cpmac_devices_installed - (i+1)] = p_dev;
++ p_cpmac_priv = p_dev->priv;
++ p_dev = p_cpmac_priv->next_device;
++ }
++
++ for(i=0; i< cpmac_devices_installed; i++)
++ {
++ p_dev = cpmac_dev_list[i];
++
++ if(!p_dev)
++ goto proc_error;
++
++ /* Get Stats */
++ cpmac_p_update_statistics(p_dev, NULL, 0, NULL);
++
++ p_cpmac_priv = p_dev->priv;
++ p_device_mib = p_cpmac_priv->device_mib;
++
++ /* Transmit stats */
++ if(len<=limit)
++ len+= sprintf(buf+len, "\nCpmac %d, Address %lx\n",i+1, p_dev->base_addr);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Transmit Stats\n");
++ if(len<=limit)
++ len+= sprintf(buf+len, " Tx Valid Bytes Sent :%lu\n",p_device_mib->ifOutOctets);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Good Tx Frames (Hardware) :%lu\n",p_device_mib->ifOutGoodFrames);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Good Tx Frames (Software) :%lu\n",p_cpmac_priv->net_dev_stats.tx_packets);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Good Tx Broadcast Frames :%lu\n",p_device_mib->ifOutBroadcasts);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Good Tx Multicast Frames :%lu\n",p_device_mib->ifOutMulticasts);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Pause Frames Sent :%lu\n",p_device_mib->ifOutPauseFrames);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Collisions :%lu\n",p_device_mib->ifCollisionFrames);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Tx Error Frames :%lu\n",p_cpmac_priv->net_dev_stats.tx_errors);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Carrier Sense Errors :%lu\n",p_device_mib->ifCarrierSenseErrors);
++ if(len<=limit)
++ len+= sprintf(buf+len, "\n");
++
++
++ /* Receive Stats */
++ if(len<=limit)
++ len+= sprintf(buf+len, "\nCpmac %d, Address %lx\n",i+1,p_dev->base_addr);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Receive Stats\n");
++ if(len<=limit)
++ len+= sprintf(buf+len, " Rx Valid Bytes Received :%lu\n",p_device_mib->ifInOctets);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Good Rx Frames (Hardware) :%lu\n",p_device_mib->ifInGoodFrames);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Good Rx Frames (Software) :%lu\n",p_cpmac_priv->net_dev_stats.rx_packets);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Good Rx Broadcast Frames :%lu\n",p_device_mib->ifInBroadcasts);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Good Rx Multicast Frames :%lu\n",p_device_mib->ifInMulticasts);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Pause Frames Received :%lu\n",p_device_mib->ifInPauseFrames);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Rx CRC Errors :%lu\n",p_device_mib->ifInCRCErrors);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Rx Align/Code Errors :%lu\n",p_device_mib->ifInAlignCodeErrors);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Rx Jabbers :%lu\n",p_device_mib->ifInOversizedFrames);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Rx Filtered Frames :%lu\n",p_device_mib->ifInFilteredFrames);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Rx Fragments :%lu\n",p_device_mib->ifInFragments);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Rx Undersized Frames :%lu\n",p_device_mib->ifInUndersizedFrames);
++ if(len<=limit)
++ len+= sprintf(buf+len, " Rx Overruns :%lu\n",p_device_mib->ifRxDMAOverruns);
++ }
++
++
++ return len;
++
++ proc_error:
++ *eof=1;
++ return len;
++}
++
++static int cpmac_p_write_stats (struct file *fp, const char * buf, unsigned long count, void * data)
++{
++ char local_buf[31];
++ int ret_val = 0;
++
++ if(count > 30)
++ {
++ printk("Error : Buffer Overflow\n");
++ printk("Use \"echo 0 > cpmac_stat\" to reset the statistics\n");
++ return -EFAULT;
++ }
++
++ copy_from_user(local_buf,buf,count);
++ local_buf[count-1]='\0'; /* Ignoring last \n char */
++ ret_val = count;
++
++ if(strcmp("0",local_buf)==0)
++ {
++ struct net_device *p_dev = last_cpmac_device;
++ int i;
++ struct net_device *cpmac_dev_list[cpmac_devices_installed];
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv;
++
++ /* Valid command */
++ printk("Resetting statistics for CPMAC interface.\n");
++
++ /* Reverse the the device link list to list eth0,eth1...in correct order */
++ for(i=0; i< cpmac_devices_installed; i++)
++ {
++ cpmac_dev_list[cpmac_devices_installed - (i+1)] = p_dev;
++ p_cpmac_priv = p_dev->priv;
++ p_dev = p_cpmac_priv->next_device;
++ }
++
++ for(i=0; i< cpmac_devices_installed; i++)
++ {
++ p_dev = cpmac_dev_list[i];
++ if(!p_dev)
++ {
++ ret_val = -EFAULT;
++ break;
++ }
++
++ cpmac_p_reset_statistics(p_dev);
++ }
++ }
++ else
++ {
++ printk("Error: Unknown operation on cpmac statistics\n");
++ printk("Use \"echo 0 > cpmac_stats\" to reset the statistics\n");
++ return -EFAULT;
++ }
++
++ return ret_val;
++}
++
++static int cpmac_p_reset_statistics(struct net_device *p_dev)
++{
++ int ret_val = 0;
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cpmac_priv->drv_hal;
++
++ memset(p_cpmac_priv->device_mib, 0, sizeof(CPMAC_DEVICE_MIB_T));
++ memset(p_cpmac_priv->stats, 0, sizeof(CPMAC_DRV_STATS_T));
++ memset(&p_cpmac_priv->net_dev_stats, 0, sizeof(struct net_device_stats));
++
++ p_drv_hal->hal_funcs->Control(p_drv_hal->hal_dev, "StatsClear", "Set", NULL);
++
++ return(ret_val);
++}
++
++static int cpmac_p_get_version(char* buf, char **start, off_t offset, int count,int *eof, void *data)
++{
++ int len = 0;
++ int limit = count - 80;
++ char *hal_version = NULL;
++ struct net_device *p_dev = last_cpmac_device;
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cpmac_priv->drv_hal;
++
++ p_drv_hal->hal_funcs->Control(p_drv_hal->hal_dev, "Version", "Get", &hal_version);
++
++ len += sprintf(buf+len, "Texas Instruments CPMAC driver version: %s\n", cpmac_version);
++
++ if(len <= limit && hal_version)
++ len += sprintf(buf+len, "Texas Instruments CPMAC HAL version: %s\n", hal_version);
++
++ return len;
++}
++
++static struct net_device_stats *cpmac_dev_get_net_stats (struct net_device *p_dev)
++{
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = (CPMAC_PRIVATE_INFO_T *) p_dev->priv;
++
++ cpmac_p_update_statistics(p_dev, NULL, 0, NULL);
++
++ return &p_cpmac_priv->net_dev_stats;
++}
++
++static int cpmac_p_detect_manual_cfg(int link_speed, char* link_mode, int debug)
++{
++ char *pSpeed = NULL;
++
++ if(debug == 1)
++ {
++ cpmac_debug_mode = 1;
++ dbgPrint("Enabled the debug print.\n");
++ }
++
++ if(!link_speed && !link_mode)
++ {
++ dbgPrint("No manual link params, defaulting to auto negotiation.\n");
++ return (0);
++ }
++
++ if(!link_speed || (link_speed != 10 && link_speed != 100))
++ {
++ dbgPrint("Invalid or No value of link speed specified, defaulting to auto speed.\n");
++ pSpeed = "auto";
++ }
++ else if(link_speed == 10)
++ {
++ g_cfg_start_link_params &= ~(_CPMDIO_100);
++ pSpeed = "10 Mbps";
++ }
++ else
++ {
++ g_cfg_start_link_params &= ~(_CPMDIO_10);
++ pSpeed = "100 Mbps";
++ }
++
++ if(!link_mode || (!strcmp(link_mode, "fd") && !strcmp(link_mode, "hd")))
++ {
++ dbgPrint("Invalid or No value of link mode specified, defaulting to auto mode.\n");
++ }
++ else if(!strcmp(link_mode, "hd"))
++ {
++ g_cfg_start_link_params &= ~(_CPMDIO_FD);
++ }
++ else
++ {
++ g_cfg_start_link_params &= ~(_CPMDIO_HD);
++ }
++
++ dbgPrint("Link is manually set to the speed of %s speed and %s mode.\n",
++ pSpeed, link_mode ? link_mode : "auto");
++
++ return(0);
++}
++
++//------------------------------------------------------------------------------
++// Call back from the HAL.
++//------------------------------------------------------------------------------
++static int cpmac_p_process_status_ind(CPMAC_PRIVATE_INFO_T *p_cpmac_priv)
++{
++ struct net_device *p_dev = p_cpmac_priv->owner;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cpmac_priv->drv_hal;
++ int status;
++
++ p_drv_hal->hal_funcs->Control(p_drv_hal->hal_dev, "Status", "Get", &status);
++
++ /* We do not reflect the real link status if in loopback.
++ * After all, we want the packets to reach the hardware so
++ * that Send() should work. */
++ if(p_dev->flags & IFF_LOOPBACK)
++ {
++ dbgPrint("Maintaining the link up loopback for %s.\n", p_dev->name);
++ netif_carrier_on(p_dev);
++
++//#if defined (CONFIG_MIPS_AVALANCHE_LED)
++// avalanche_led_action(p_cpmac_priv->led_handle, CPMAC_LINK_ON);
++//#endif
++
++ return(0);
++ }
++
++ if(status & CPMAC_STATUS_ADAPTER_CHECK) /* ???? */
++ {
++ ; /* what to do ? */
++ }
++ else if(status)
++ {
++ if(!netif_carrier_ok(p_dev))
++ {
++ netif_carrier_on(p_cpmac_priv->owner);
++
++//#if defined (CONFIG_MIPS_AVALANCHE_LED)
++// avalanche_led_action(p_cpmac_priv->led_handle, CPMAC_LINK_ON);
++//#endif
++ dbgPrint("Found the Link for the CPMAC instance %s.\n", p_dev->name);
++ }
++
++ if(netif_running(p_dev) & netif_queue_stopped(p_dev))
++ {
++ netif_wake_queue(p_dev);
++ }
++
++ p_cpmac_priv->link_speed = status & CPMAC_STATUS_LINK_SPEED ? 100000000:10000000;
++ p_cpmac_priv->link_mode = status & CPMAC_STATUS_LINK_DUPLEX? 3:2;
++
++ }
++ else
++ {
++ if(netif_carrier_ok(p_dev))
++ {
++ /* do we need to register synchronization issues with stats here. */
++ p_cpmac_priv->link_speed = 100000000;
++ p_cpmac_priv->link_mode = 1;
++
++ netif_carrier_off(p_dev);
++
++//#if defined (CONFIG_MIPS_AVALANCHE_LED)
++// avalanche_led_action(p_cpmac_priv->led_handle, CPMAC_LINK_OFF);
++//#endif
++
++ dbgPrint("Lost the Link for the CPMAC for %s.\n", p_dev->name);
++ }
++
++ if(!netif_queue_stopped(p_dev))
++ {
++ netif_stop_queue(p_dev); /* So that kernel does not keep on xmiting pkts. */
++ }
++ }
++
++ return(0);
++}
++
++//-----------------------------------------------------------------------------
++// Timer related private functions.
++//-----------------------------------------------------------------------------
++static int cpmac_p_timer_init(CPMAC_PRIVATE_INFO_T *p_cpmac_priv)
++{
++ struct timer_list *p_timer = p_cpmac_priv->timer;
++
++ init_timer(p_timer);
++
++ p_timer = p_cpmac_priv->timer + TICK_TIMER;
++ p_timer->expires = 0;
++ p_timer->data = (unsigned long)p_cpmac_priv;
++ p_timer->function = cpmac_p_tick_timer_expiry;
++
++ return(0);
++}
++
++#if 0
++static int cpmac_timer_cleanup(CPMAC_PRIVATE_INFO_T *p_cpmac_priv)
++{
++ struct timer_list *p_timer;
++
++ p_timer = p_cpmac_priv->timer + TICK_TIMER;
++
++ /* use spin lock to establish synchronization with the dispatch */
++ if(p_timer->function) del_timer_sync(p_timer);
++ p_timer->function = NULL;
++
++ return (0);
++}
++#endif
++
++static int cpmac_p_start_timer(struct timer_list *p_timer, unsigned int delay_ticks)
++{
++ p_timer->expires = jiffies + delay_ticks;
++
++ if(p_timer->function)
++ {
++ add_timer(p_timer);
++ }
++
++ return(0);
++}
++
++static void cpmac_p_tick_timer_expiry(unsigned long p_cb_param)
++{
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = (CPMAC_PRIVATE_INFO_T*) p_cb_param;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cpmac_priv->drv_hal;
++ struct timer_list *p_timer = p_cpmac_priv->timer + TICK_TIMER;
++
++ if(test_bit(0, &p_cpmac_priv->set_to_close))
++ {
++ return;
++ }
++
++ p_drv_hal->hal_funcs->Tick(p_drv_hal->hal_dev);
++
++ cpmac_p_start_timer(p_timer, p_cpmac_priv->delay_ticks);
++}
++
++static int cpmac_p_stop_timer(struct timer_list *p_timer)
++{
++ /* Ideally we need to a set flag indicating not to start the timer again
++ before del_timer_sync() is called up. But here we assume that the
++ caller has set the p_cpmac_priv->set_to_close (ok for now). */
++ del_timer_sync(p_timer);
++
++ return(0);
++}
++
++//------------------------------------------------------------------------------
++// Device configuration and setup related private functions.
++//------------------------------------------------------------------------------
++static int cpmac_p_probe_and_setup_device(CPMAC_PRIVATE_INFO_T *p_cpmac_priv,
++ unsigned long *p_dev_flags)
++{
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cpmac_priv->drv_hal;
++ HAL_FUNCTIONS *p_hal_funcs = p_drv_hal->hal_funcs;
++ HAL_DEVICE *p_hal_dev = p_drv_hal->hal_dev;
++ CPMAC_ABILITY_INFO_T *p_capability= p_cpmac_priv->ability_info;
++ unsigned int val = 0;
++ int channel = 0;
++
++ p_cpmac_priv->flags = 0;
++
++ p_capability->promiscous = CFG_PROMISCOUS;
++ p_capability->broadcast = CFG_BROADCAST;
++ p_capability->multicast = CFG_MULTICAST;
++ p_capability->all_multi = CFG_ALL_MULTI;
++ p_capability->jumbo_frames = CFG_JUMBO_FRAMES;
++ p_capability->short_frames = CFG_SHORT_FRAMES;
++ p_capability->auto_negotiation = CFG_AUTO_NEGOTIATION;
++ p_capability->link_speed = cfg_start_link_speed;
++ p_capability->loop_back = CFG_LOOP_BACK;
++ p_capability->tx_flow_control = CFG_TX_FLOW_CNTL;
++ p_capability->rx_flow_control = CFG_RX_FLOW_CNTL;
++ p_capability->tx_pacing = CFG_TX_PACING;
++ p_capability->rx_pass_crc = CFG_RX_PASS_CRC;
++ p_capability->qos_802_1q = CFG_QOS_802_1Q;
++ p_capability->tx_num_chan = CFG_TX_NUM_CHAN;
++
++ /* Lets probe the device for the configured capabilities (netdev specific).*/
++
++ /* Following are set in the set_multi_list, when indicated by the kernel
++ * Promiscous and all multi.
++ */
++
++ if(p_capability->broadcast)
++ {
++ channel = 0;
++ val = 1;
++ if((p_hal_funcs->Control(p_hal_dev, pszRX_BROAD_EN, pszSet, &val) == 0) &&
++ (p_hal_funcs->Control(p_hal_dev, pszRX_BROAD_CH, pszSet, &channel) == 0))
++ *p_dev_flags |= IFF_BROADCAST;
++ else
++ p_capability->broadcast = 0; /* no broadcast capabilities */
++ }
++
++ if(p_capability->multicast)
++ {
++ val = 1;
++ channel = 0;
++ if((p_hal_funcs->Control(p_hal_dev, pszRX_MULT_EN, pszSet, &val) == 0) &&
++ (p_hal_funcs->Control(p_hal_dev, pszRX_MULT_CH, pszSet, &channel) == 0))
++ *p_dev_flags |= IFF_MULTICAST;
++ else
++ {
++ p_capability->multicast = 0;
++ p_capability->all_multi = 0; /* no multicast, no all-multi. */
++ }
++ }
++
++ if(p_capability->loop_back)
++ {
++ ; /* We do not put the device in loopback, if required use ioctl */
++ }
++
++ /* Lets probe the device for the configured capabilities (Non net device specific).*/
++
++ if(p_capability->jumbo_frames)
++ {
++ val = 0;
++ if(p_hal_funcs->Control(p_hal_dev, pszRX_NO_CHAIN, pszSet, &val) == 0)
++ p_cpmac_priv->flags |= IFF_PRIV_JUMBO_FRAMES;
++ else
++ p_capability->jumbo_frames = 0;
++ }
++
++ if(p_capability->short_frames)
++ {
++ val = 1;
++ if(p_hal_funcs->Control(p_hal_dev, pszRX_CSF_EN, pszSet, &val) == 0)
++ p_cpmac_priv->flags |= IFF_PRIV_SHORT_FRAMES;
++ else
++ p_capability->short_frames = 0;
++ }
++
++ val = g_cfg_start_link_params;
++
++#ifdef CONFIG_AR7_MDIX
++ if( avalanche_is_mdix_on_chip() )
++ {
++ val |= _CPMDIO_AUTOMDIX;
++ }
++#endif
++
++ if(p_hal_funcs->Control(p_hal_dev,pszMdioConnect,pszSet, &val) !=0)
++ {
++ p_capability->link_speed = 0;
++ }
++ else
++ {
++ if(g_cfg_start_link_params & (_CPMDIO_100 | _CPMDIO_HD | _CPMDIO_FD | _CPMDIO_10))
++ p_cpmac_priv->flags |= IFF_PRIV_AUTOSPEED;
++ else if(g_cfg_start_link_params & (_CPMDIO_100 | _CPMDIO_HD))
++ p_cpmac_priv->flags |= IFF_PRIV_LINK100_HD;
++ else if(g_cfg_start_link_params & (_CPMDIO_100 | _CPMDIO_FD))
++ p_cpmac_priv->flags |= IFF_PRIV_LINK100_FD;
++ else if(g_cfg_start_link_params & (_CPMDIO_10 | _CPMDIO_HD))
++ p_cpmac_priv->flags |= IFF_PRIV_LINK10_HD;
++ else if(g_cfg_start_link_params & (_CPMDIO_10 | _CPMDIO_FD))
++ p_cpmac_priv->flags |= IFF_PRIV_LINK10_FD;
++ else
++ ;
++ }
++
++ if(p_capability->tx_flow_control)
++ {
++ val = 1;
++ if(p_hal_funcs->Control(p_hal_dev,pszTX_FLOW_EN, pszSet, &val) ==0)
++ p_cpmac_priv->flags |= IFF_PRIV_TX_FLOW_CNTL;
++ else
++ p_capability->tx_flow_control = 0;
++ }
++
++ if(p_capability->rx_flow_control)
++ {
++ val = 1;
++ if(p_hal_funcs->Control(p_hal_dev, pszRX_FLOW_EN, pszSet, &val) ==0)
++ p_cpmac_priv->flags |= IFF_PRIV_RX_FLOW_CNTL;
++ else
++ p_capability->rx_flow_control = 0;
++ }
++
++ if(p_capability->tx_pacing)
++ {
++ val = 1;
++ if(p_hal_funcs->Control(p_hal_dev, pszTX_PACE, pszSet, &val) ==0)
++ p_cpmac_priv->flags |= IFF_PRIV_TX_PACING;
++ else
++ p_capability->tx_pacing = 0;
++ }
++
++ if(p_capability->rx_pass_crc)
++ {
++ val = 1;
++ if(p_hal_funcs->Control(p_hal_dev, pszRX_PASS_CRC, pszSet, &val) == 0)
++ p_cpmac_priv->flags |= IFF_PRIV_RX_PASS_CRC;
++ else
++ p_capability->rx_pass_crc = 0;
++ }
++
++ if(p_capability->qos_802_1q)
++ {
++ val = 1;
++ if(p_hal_funcs->Control(p_hal_dev, pszRX_QOS_EN, pszSet, &val) == 0)
++ p_cpmac_priv->flags |= IFF_PRIV_8021Q_EN;
++ else
++ {
++ p_capability->qos_802_1q = 0;
++ p_capability->tx_num_chan= 1;
++ }
++ }
++
++ if(p_capability->tx_num_chan > 1)
++ {
++ int cfg_tx_num_chan = p_capability->tx_num_chan;
++ val = 0;
++#ifdef TEST
++ if(p_hal_funcs->Control(p_hal_dev, pszTX_NUM_CH, pszGet, &val) == 0)
++ cfg_tx_num_chan = cfg_tx_num_chan > val ? val : cfg_tx_num_chan;
++ else
++ cfg_tx_num_chan = 1;
++#endif
++ p_capability->tx_num_chan = cfg_tx_num_chan;
++ }
++
++ return(0);
++}
++
++static int cpmac_p_setup_driver_params(CPMAC_PRIVATE_INFO_T *p_cpmac_priv)
++{
++ int i=0;
++ int threshold = CFG_TX_NUM_BUF_SERVICE;
++
++ char *tx_threshold_ptr = prom_getenv("threshold");
++
++ CPMAC_TX_CHAN_INFO_T *p_tx_chan_info = p_cpmac_priv->tx_chan_info;
++ CPMAC_RX_CHAN_INFO_T *p_rx_chan_info = p_cpmac_priv->rx_chan_info;
++ CPMAC_ABILITY_INFO_T *p_capability = p_cpmac_priv->ability_info;
++
++ /* Timer stuff */
++ p_cpmac_priv->timer_count = 1; /* should be < or = the MAX TIMER */
++ p_cpmac_priv->timer_created = 0;
++ p_cpmac_priv->timer_access_hal = 1;
++
++ for(i=0; i < MAX_TIMER; i++)
++ p_cpmac_priv->timer[i].function = NULL;
++
++ p_cpmac_priv->enable_802_1q = p_capability->qos_802_1q;
++
++ /* Tx channel related.*/
++ p_tx_chan_info->cfg_chan = p_capability->tx_num_chan;
++ p_tx_chan_info->opened_chan = 0;
++
++ if(tx_threshold_ptr)
++ threshold = simple_strtol(tx_threshold_ptr, (char **)NULL, 10);
++
++ if((threshold <= 0) && tx_threshold_ptr) /* If threshold set to 0 then Enable the TX interrupt */
++ {
++ threshold = CFG_TX_NUM_BUF_SERVICE;
++ p_tx_chan_info->tx_int_disable = 0;
++
++ }
++ else
++ {
++ p_tx_chan_info->tx_int_disable = CFG_TX_INT_DISABLE;
++ }
++
++ for(i=0; i < MAX_TX_CHAN; i++)
++ {
++
++
++
++ p_tx_chan_info->chan[i].state = CHAN_CLOSE;
++ p_tx_chan_info->chan[i].num_BD = CFG_TX_NUM_BUF_DESC;
++ p_tx_chan_info->chan[i].buffer_size = cpmac_max_frame_size;
++ p_tx_chan_info->chan[i].buffer_offset = CFG_TX_BUF_OFFSET;
++
++
++
++ p_tx_chan_info->chan[i].service_max = threshold;
++ }
++
++ if (p_tx_chan_info->tx_int_disable)
++ printk("Cpmac driver Disable TX complete interrupt setting threshold to %d.\n",threshold);
++ else
++ printk("Cpmac driver Enable TX complete interrupt\n");
++
++
++ /* Assuming just one rx channel for now */
++ p_rx_chan_info->cfg_chan = 1;
++ p_rx_chan_info->opened_chan = 0;
++ p_rx_chan_info->chan->state = CHAN_CLOSE;
++ p_rx_chan_info->chan->num_BD = CFG_RX_NUM_BUF_DESC;
++ p_rx_chan_info->chan->buffer_size = cpmac_max_frame_size;
++ p_rx_chan_info->chan->buffer_offset = CFG_RX_BUF_OFFSET;
++ p_rx_chan_info->chan->service_max = CFG_RX_NUM_BUF_SERVICE;
++
++ /* Set as per RFC 2665 */
++ p_cpmac_priv->link_speed = 100000000;
++ p_cpmac_priv->link_mode = 1;
++
++ p_cpmac_priv->loop_back = 0;
++
++ return(0);
++}
++
++inline static int cpmac_p_rx_buf_setup(CPMAC_RX_CHAN_INFO_T *p_rx_chan)
++{
++ /* Number of ethernet packets & max pkt length */
++ p_rx_chan->chan->tot_buf_size = p_rx_chan->chan->buffer_size +
++ 2*(CONTROL_802_1Q_SIZE) +
++ p_rx_chan->chan->buffer_offset +
++ ADD_FOR_4BYTE_ALIGN(p_rx_chan->chan->buffer_offset & 0x3);
++
++ p_rx_chan->chan->tot_reserve_bytes = CONTROL_802_1Q_SIZE +
++ p_rx_chan->chan->buffer_offset +
++ L3_ALIGN(p_rx_chan->chan->buffer_offset & 0x3);
++
++ return(0);
++}
++
++//-----------------------------------------------------------------------------
++// Net device related private functions.
++//-----------------------------------------------------------------------------
++
++/***************************************************************
++ * cpmac_dev_init
++ *
++ * Returns:
++ * 0 on success, error code otherwise.
++ * Parms:
++ * dev The structure of the device to be
++ * init'ed.
++ *
++ * This function completes the initialization of the
++ * device structure and driver. It reserves the IO
++ * addresses and assignes the device's methods.
++ *
++ *
++ **************************************************************/
++
++static int cpmac_dev_init(struct net_device *p_dev)
++{
++ int retVal = -1;
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ int instance_num = p_cpmac_priv->instance_num;
++ unsigned long net_flags = 0;
++ char *mac_name = NULL;
++ char *mac_string = NULL;
++
++ CPMAC_TX_CHAN_INFO_T *p_tx_chan_info;
++ CPMAC_RX_CHAN_INFO_T *p_rx_chan_info;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal;
++ int i;
++
++ int mem_size = sizeof(CPMAC_DRV_HAL_INFO_T)
++ + sizeof(CPMAC_TX_CHAN_INFO_T)
++ + sizeof(CPMAC_RX_CHAN_INFO_T)
++ + sizeof(CPMAC_ABILITY_INFO_T)
++ + sizeof(CPMAC_DEVICE_MIB_T)
++ + sizeof(CPMAC_DRV_STATS_T);
++
++
++#if defined(CONFIG_MIPS_SEAD2)
++ int prev_reset_val = RESET_REG_PRCR;
++ /* Bring the module out of reset */
++ RESET_REG_PRCR |= temp_reset_value[p_cpmac_priv->instance_num];
++
++ /* Read the version id of the device to check if the device really exists */
++ if( VERSION(temp_base_address[p_cpmac_priv->instance_num]) == 0)
++ {
++ printk(" CPMAC:Device not found\n");
++ RESET_REG_PRCR = prev_reset_val;
++ return -ENODEV;
++ }
++
++ RESET_REG_PRCR = prev_reset_val;
++#endif
++
++
++ if((p_drv_hal = kmalloc(mem_size, GFP_KERNEL)) == NULL)
++ {
++ errPrint("Failed to allocate memory; rewinding.\n");
++ return(-1);
++ }
++
++ memset(p_drv_hal, 0, mem_size);
++
++ /* build the cpmac private object */
++ p_cpmac_priv->drv_hal = p_drv_hal;
++ p_cpmac_priv->tx_chan_info = p_tx_chan_info
++ = (CPMAC_TX_CHAN_INFO_T*)((char*)p_drv_hal
++ + sizeof(CPMAC_DRV_HAL_INFO_T));
++ p_cpmac_priv->rx_chan_info = p_rx_chan_info
++ = (CPMAC_RX_CHAN_INFO_T*)((char *)p_tx_chan_info
++ + sizeof(CPMAC_TX_CHAN_INFO_T));
++ p_cpmac_priv->ability_info = (CPMAC_ABILITY_INFO_T *)((char *)p_rx_chan_info
++ + sizeof(CPMAC_RX_CHAN_INFO_T));
++ p_cpmac_priv->device_mib = (CPMAC_DEVICE_MIB_T *)((char *)p_cpmac_priv->ability_info
++ + sizeof(CPMAC_ABILITY_INFO_T));
++ p_cpmac_priv->stats = (CPMAC_DRV_STATS_T *)((char *)p_cpmac_priv->device_mib
++ + sizeof(CPMAC_DEVICE_MIB_T));
++
++ p_drv_hal->owner = p_cpmac_priv;
++
++
++ switch(instance_num)
++ {
++
++ case 0:
++ mac_name="maca";
++
++ /* Also setting port information */
++ p_dev->if_port = AVALANCHE_CPMAC_LOW_PORT_ID;
++
++ break;
++
++ case 1:
++ mac_name="macb";
++
++ /* Also setting port information */
++ p_dev->if_port = AVALANCHE_CPMAC_HIGH_PORT_ID;
++
++ break;
++ }
++
++ if(mac_name)
++ mac_string=prom_getenv(mac_name);
++
++ if(!mac_string)
++ {
++ mac_string="08.00.28.32.06.02";
++ printk("Error getting mac from Boot enviroment for %s\n",p_dev->name);
++ printk("Using default mac address: %s\n",mac_string);
++ if(mac_name)
++ {
++ printk("Use Bootloader command:\n");
++ printk(" setenv %s xx.xx.xx.xx.xx.xx\n","<env_name>");
++ printk("to set mac address\n");
++ }
++ }
++
++ str2eaddr(p_cpmac_priv->mac_addr,mac_string);
++
++ for (i=0; i <= ETH_ALEN; i++)
++ {
++ /* This sets the hardware address */
++ p_dev->dev_addr[i] = p_cpmac_priv->mac_addr[i];
++ }
++
++ p_cpmac_priv->set_to_close = 1;
++ p_cpmac_priv->non_data_irq_expected = 0;
++
++//#if defined (CONFIG_MIPS_AVALANCHE_LED)
++// if((p_cpmac_priv->led_handle = avalanche_led_register("cpmac", instance_num)) == NULL)
++// {
++// errPrint("Could not allocate handle for CPMAC[%d] LED.\n", instance_num);
++// goto cpmac_init_mod_error;
++// }
++//#endif
++
++ if(cpmac_drv_init_module(p_drv_hal, p_dev, instance_num) != 0)
++ {
++ errPrint("Could not initialize the HAL for %s.\n", p_dev->name);
++ goto cpmac_init_mod_error;
++ }
++
++ /* initialize the CPMAC device */
++ if (cpmac_drv_init(p_drv_hal) == -1)
++ {
++ errPrint("HAL init failed for %s.\n", p_dev->name);
++ goto cpmac_init_device_error;
++ }
++
++ if(cpmac_p_probe_and_setup_device(p_cpmac_priv, &net_flags) == -1)
++ {
++ errPrint("Failed to configure up %s.\n", p_dev->name);
++ goto cpmac_init_device_error;
++ }
++
++ if(cpmac_p_setup_driver_params(p_cpmac_priv) == -1)
++ {
++ errPrint("Failed to set driver parameters for %s.\n", p_dev->name);
++ goto cpmac_init_device_error;
++ }
++
++ cpmac_p_rx_buf_setup(p_rx_chan_info);
++
++ /* initialize the timers for the net device */
++ if(cpmac_p_timer_init(p_cpmac_priv) == -1)
++ {
++ errPrint("Failed to set timer(s) for %s.\n", p_dev->name);
++ goto cpmac_timer_init_error;
++ }
++
++ p_dev->addr_len = 6;
++
++ p_dev->open = &cpmac_dev_open; /* i.e. Start Device */
++ p_dev->hard_start_xmit = &cpmac_dev_tx;
++ p_dev->stop = &cpmac_dev_close;
++ p_dev->get_stats = &cpmac_dev_get_net_stats;
++
++ p_dev->set_multicast_list = &cpmac_dev_mcast_set;
++ p_dev->set_mac_address = cpmac_dev_set_mac_addr;
++ /* Knocking off the default broadcast and multicast flags. Allowing the
++ device configuration to control the flags. */
++ p_dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
++ p_dev->flags |= net_flags;
++
++ netif_carrier_off(p_dev);
++
++//#if defined (CONFIG_MIPS_AVALANCHE_LED)
++// avalanche_led_action(p_cpmac_priv->led_handle, CPMAC_LINK_OFF);
++//#endif
++
++ /* Tasklet is initialized at the isr registeration time. */
++ p_drv_hal->hal_funcs->Control(p_drv_hal->hal_dev, "CpmacBase", "Get", &p_dev->base_addr);
++ p_drv_hal->hal_funcs->Control(p_drv_hal->hal_dev, "CpmacSize", "Get", &p_cpmac_priv->dev_size);
++
++ request_mem_region(p_dev->base_addr, p_cpmac_priv->dev_size, p_dev->name);
++
++ retVal = 0;
++
++ if(g_init_enable_flag)
++ cpmac_p_dev_enable(p_dev);
++
++ return(retVal);
++
++cpmac_timer_init_error:
++cpmac_init_device_error :
++ cpmac_drv_cleanup(p_drv_hal);
++
++cpmac_init_mod_error:
++ kfree(p_drv_hal);
++
++ return (retVal);
++
++} /* cpmac_dev_init */
++
++
++/***************************************************************
++ * cpmac_p_dev_enable
++ *
++ * Returns:
++ * 0 on success, error code otherwise.
++ * Parms:
++ * dev Structure of device to be opened.
++ *
++ * This routine puts the driver and CPMAC adapter in a
++ * state where it is ready to send and receive packets.
++ *
++ *
++ **************************************************************/
++int cpmac_p_dev_enable( struct net_device *p_dev)
++{
++ int ret_val = 0;
++ int channel = 0;
++
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cpmac_priv->drv_hal;
++ CPMAC_RX_CHAN_INFO_T *p_rx_chan_info = p_cpmac_priv->rx_chan_info;
++ int max_length = p_rx_chan_info->chan->tot_buf_size;
++
++ p_cpmac_priv->set_to_close = 0;
++
++ if((ret_val = cpmac_drv_start(p_drv_hal, p_cpmac_priv->tx_chan_info,
++ p_cpmac_priv->rx_chan_info, CHAN_SETUP))==-1)
++ {
++ errPrint("%s error: failed to start the device.\n", p_dev->name);
++ ret_val = -1;
++ }
++ else if(p_drv_hal->hal_funcs->Control(p_drv_hal->hal_dev,"RX_UNICAST_SET",
++ "Set", &channel)!=0)
++ {
++ errPrint("%s error: device chan 0 could not be enabled.\n", p_dev->name);
++ ret_val = -1;
++ }
++ else if(p_drv_hal->hal_funcs->Control(p_drv_hal->hal_dev, pszRX_MAXLEN, pszSet, &max_length) != 0)
++ {
++ errPrint(" CPMAC registers can't be written \n");
++ ret_val = -1;
++ }
++ else if(p_drv_hal->hal_funcs->Control(p_drv_hal->hal_dev, "TxIntDisable", "Set",
++ &p_cpmac_priv->tx_chan_info->tx_int_disable) != 0)
++ {
++ errPrint(" CPMAC registers can't be written \n");
++ ret_val = -1;
++ }
++ else
++ {
++ ; // Every thing went OK.
++ }
++
++ return(ret_val);
++} /* cpmac_dev_enable */
++
++
++static int cpmac_dev_open(struct net_device *p_dev)
++{
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ CPMAC_ISR_INFO_T *p_isr_cb_param = &p_cpmac_priv->cpmac_isr;
++
++ if(!g_init_enable_flag)
++ cpmac_p_dev_enable(p_dev);
++
++ if(request_irq(p_isr_cb_param->intr, cpmac_hal_isr, SA_INTERRUPT,
++ "Cpmac Driver", p_isr_cb_param))
++ {
++ errPrint("Failed to register the irq %d for Cpmac %s.\n",
++ p_isr_cb_param->intr, p_dev->name);
++ return (-1);
++ }
++
++ netif_start_queue(p_dev);
++
++ MOD_INC_USE_COUNT;
++ p_cpmac_priv->stats->start_tick = jiffies;
++ dbgPrint("Started the network queue for %s.\n", p_dev->name);
++ return(0);
++}
++
++/***************************************************************
++ * cpmac_p_dev_disable
++ *
++ * Returns:
++ * An error code.
++ * Parms:
++ * dev The device structure of the device to
++ * close.
++ *
++ * This function shuts down the adapter.
++ *
++ **************************************************************/
++int cpmac_p_dev_disable(struct net_device *p_dev)
++{
++ int ret_val = 0;
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cpmac_priv->drv_hal;
++
++ set_bit(0, &p_cpmac_priv->set_to_close);
++ set_bit(0, &p_cpmac_priv->non_data_irq_expected);
++
++ /* The driver does not re-schedule the tasklet after kill is called. So, this
++ should take care of the bug in the kernel. */
++ tasklet_kill(&p_cpmac_priv->cpmac_isr.tasklet);
++
++ if(cpmac_drv_stop(p_drv_hal, p_cpmac_priv->tx_chan_info,
++ p_cpmac_priv->rx_chan_info,
++ CHAN_TEARDOWN | FREE_BUFFER | BLOCKING | COMPLETE) == -1)
++ {
++ ret_val = -1;
++ }
++ else
++ {
++ /* hope that the HAL closes down the tick timer.*/
++
++ dbgPrint("Device %s Closed.\n", p_dev->name);
++ p_cpmac_priv->stats->start_tick = jiffies;
++
++ p_cpmac_priv->link_speed = 100000000;
++ p_cpmac_priv->link_mode = 1;
++ netif_carrier_off(p_dev);
++
++//#if defined (CONFIG_MIPS_AVALANCHE_LED)
++// avalanche_led_action(p_cpmac_priv->led_handle, CPMAC_LINK_OFF);
++//#endif
++
++ clear_bit(0, &p_cpmac_priv->non_data_irq_expected);
++
++ }
++
++ return (ret_val);
++
++} /* cpmac_dev_close */
++
++
++/***************************************************************
++ * cpmac_dev_close
++ *
++ * Returns:
++ * An error code.
++ * Parms:
++ * dev The device structure of the device to
++ * close.
++ *
++ * This function shuts down the adapter.
++ *
++ **************************************************************/
++static int cpmac_dev_close(struct net_device *p_dev)
++{
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ CPMAC_ISR_INFO_T *p_isr_cb_param = &p_cpmac_priv->cpmac_isr;
++
++ /* inform the upper layers. */
++ netif_stop_queue(p_dev);
++
++ if(!g_init_enable_flag)
++ cpmac_p_dev_disable(p_dev);
++ else
++ free_irq(p_isr_cb_param->intr, p_isr_cb_param);
++
++ MOD_DEC_USE_COUNT;
++
++ return(0);
++}
++
++static void cpmac_dev_mcast_set(struct net_device *p_dev)
++{
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cpmac_priv->drv_hal;
++ CPMAC_ABILITY_INFO_T *p_capability = p_cpmac_priv->ability_info;
++ HAL_FUNCTIONS *p_hal_funcs = p_drv_hal->hal_funcs;
++ HAL_DEVICE *p_hal_dev = p_drv_hal->hal_dev;
++ int val = 1;
++ int channel = 0;
++
++//#if defined (CONFIG_MIPS_AVALANCHE_LED)
++// if(netif_carrier_ok(p_dev))
++// avalanche_led_action(p_cpmac_priv->led_handle, CPMAC_LINK_ON);
++//#endif
++
++ if(p_dev->flags & IFF_PROMISC)
++ {
++ if(p_capability->promiscous)
++ {
++ /* multi mode in the HAL, check this */
++ val = 0;
++ p_hal_funcs->Control(p_hal_dev, pszRX_MULTI_ALL, "Clear", &val);
++
++ val = 1;
++ /* set the promiscous mode in the HAL */
++ p_hal_funcs->Control(p_hal_dev, pszRX_CAF_EN, pszSet, &val);
++ p_hal_funcs->Control(p_hal_dev, pszRX_PROM_CH, pszSet, &channel);
++
++ dbgPrint("%s set in the Promisc mode.\n", p_dev->name);
++ }
++ else
++ {
++ errPrint("%s not configured for Promisc mode.\n", p_dev->name);
++ }
++ }
++ else if(p_dev->flags & IFF_ALLMULTI)
++ {
++ if(p_capability->all_multi)
++ {
++ val = 0;
++ /* disable the promiscous mode in the HAL */
++ p_hal_funcs->Control(p_hal_dev, pszRX_CAF_EN, "Clear", &val);
++
++ val = 1;
++ /* set the all multi mode in the HAL */
++ p_hal_funcs->Control(p_hal_dev, pszRX_MULTI_ALL, pszSet, &val);
++ p_hal_funcs->Control(p_hal_dev, pszRX_MULT_CH, pszSet, &channel);
++
++ dbgPrint("%s has been set to the ALL_MULTI mode.\n", p_dev->name);
++ }
++ else
++ {
++ errPrint("%s not configured for ALL MULTI mode.\n", p_dev->name);
++ }
++ }
++ else if(p_dev->mc_count)
++ {
++ if(p_capability->multicast)
++ {
++ struct dev_mc_list *p_dmi = p_dev->mc_list;
++ int count;
++
++ val = 0;
++ /* clear all the previous data, we are going to populate new ones.*/
++ p_hal_funcs->Control(p_hal_dev, pszRX_MULTI_ALL, "Clear", &val);
++ /* disable the promiscous mode in the HAL */
++ p_hal_funcs->Control(p_hal_dev, pszRX_CAF_EN, pszSet, &val);
++
++ for(count = 0; count < p_dev->mc_count; count++, p_dmi = p_dmi->next)
++ {
++ p_hal_funcs->Control(p_hal_dev, "RX_MULTI_SINGLE", "Set", p_dmi->dmi_addr);
++ }
++
++ dbgPrint("%s configured for %d multicast addresses.\n", p_dev->name, p_dev->mc_count);
++ }
++ else
++ {
++ errPrint("%s has not been configuted for multicast handling.\n", p_dev->name);
++ }
++ }
++ else
++ {
++ val = 0;
++ /* clear all the previous data, we are going to populate new ones.*/
++ p_hal_funcs->Control(p_hal_dev, pszRX_MULTI_ALL, "Clear", &val);
++ /* disable the promiscous mode in the HAL */
++ p_hal_funcs->Control(p_hal_dev, pszRX_CAF_EN, pszSet, &val);
++ dbgPrint("Dev set to Unicast mode.\n");
++ }
++}
++
++static int cpmac_dev_set_mac_addr(struct net_device *p_dev,void * addr)
++{
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cpmac_priv->drv_hal;
++ HAL_FUNCTIONS *p_hal_funcs = p_drv_hal->hal_funcs;
++ HAL_DEVICE *p_hal_dev = p_drv_hal->hal_dev;
++ struct sockaddr *sa = addr;
++
++ memcpy(p_cpmac_priv->mac_addr,sa->sa_data,p_dev->addr_len);
++ memcpy(p_dev->dev_addr,sa->sa_data,p_dev->addr_len);
++ p_hal_funcs->Control(p_hal_dev, pszMacAddr, pszSet, p_cpmac_priv->mac_addr);
++
++ return 0;
++
++}
++
++/* VLAN is handled by vlan/vconfig support. Here, we just check for the
++ * 802.1q configuration of the device and en-queue the packet accordingly.
++ * We do not do any 802.1q processing here.
++ */
++static int cpmac_dev_tx( struct sk_buff *skb, struct net_device *p_dev)
++{
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cpmac_priv->drv_hal;
++ int channel = 0;
++ int ret_val = 0;
++ FRAGLIST send_frag_list[1];
++
++#ifdef CPMAC_8021Q_SUPPORT
++ if(skb->len < TCI_END_OFFSET)
++ {
++ /* Whee, frame shorter than 14 bytes !! We need to copy
++ * fragments to understand the frame. Too much work.
++ * Hmm, dump it. */
++
++ /* Free the buffer */
++ goto cpmac_dev_tx_drop_pkt;
++ }
++
++ /* 802.1p/q stuff */
++ if(IS_802_1Q_FRAME(skb->data + TPID_START_OFFSET))
++ {
++ /* IEEE 802.1q, section 8.8 and section 8.11.9 */
++ if(!p_cpmac_priv->enable_802_1q)
++ {
++ /* free the buffer */
++ goto cpmac_dev_tx_drop_pkt;
++ }
++
++ channel = GET_802_1P_CHAN(p_cpmac_priv->tx_chan_info->opened_chan,
++ skb->data[TCI_START_OFFSET]);
++
++ }
++ /* sending a non 802.1q frame, when configured for 802.1q: dump it.*/
++ else if(p_cpmac_priv->enable_802_1q)
++ {
++ /* free the buffer */
++ goto cpmac_dev_tx_drop_pkt;
++ }
++ else
++ {
++ ;/* it is the good old non 802.1q */
++ }
++#endif
++
++ send_frag_list->len = skb->len;
++ send_frag_list->data = skb->data;
++
++#ifdef CPMAC_TEST
++ xdump(skb->data, skb->len, "send");
++#endif
++
++ dma_cache_wback_inv((unsigned long)skb->data, skb->len);
++
++ if(p_drv_hal->hal_funcs->Send(p_drv_hal->hal_dev, send_frag_list, 1,
++ skb->len, skb, channel) != 0)
++ {
++ /* code here to stop the queue, when allowing tx timeout, perhaps next release.*/
++ p_cpmac_priv->net_dev_stats.tx_errors++;
++#ifndef TI_SLOW_PATH
++ /* Free the skb in case of Send return error */
++ dev_kfree_skb_any(skb);
++ p_cpmac_priv->net_dev_stats.tx_dropped++;
++ return 0;
++#endif
++ goto cpmac_dev_tx_drop_pkt;
++ }
++
++//#if defined (CONFIG_MIPS_AVALANCHE_LED)
++// avalanche_led_action(p_cpmac_priv->led_handle, CPMAC_TX_ACTIVITY);
++//#endif
++
++ return(ret_val);
++
++cpmac_dev_tx_drop_pkt:
++
++ p_cpmac_priv->net_dev_stats.tx_dropped++;
++ ret_val = -1;
++ return (ret_val);
++
++} /*cpmac_dev_tx */
++
++
++//------------------------------------------------------------------------------
++// Public functions : Called by outsiders to this file.
++//------------------------------------------------------------------------------
++
++
++void *cpmac_hal_malloc_buffer(unsigned int size, void* mem_base, unsigned int mem_range,
++ OS_SETUP *p_os_setup, HAL_RECEIVEINFO *HalReceiveInfo,
++ OS_RECEIVEINFO **osReceiveInfo, OS_DEVICE *p_dev)
++{
++ CPMAC_RX_CHAN_INFO_T *p_rx_chan_info = (CPMAC_RX_CHAN_INFO_T *)p_os_setup;
++ int tot_buf_size = p_rx_chan_info->chan->tot_buf_size;
++ int tot_reserve_bytes = p_rx_chan_info->chan->tot_reserve_bytes;
++ struct sk_buff *p_skb;
++ void *ret_ptr;
++
++ /* use TI SKB private pool */
++ p_skb = dev_alloc_skb(tot_buf_size);
++
++ if(p_skb == NULL)
++ {
++ errPrint("Failed to allocate skb for %s.\n", ((struct net_device*)p_dev)->name);
++ return (NULL);
++ }
++
++ p_skb->dev = p_dev;
++ skb_reserve(p_skb, tot_reserve_bytes);
++
++ *osReceiveInfo = p_skb;
++
++ ret_ptr = skb_put(p_skb, p_rx_chan_info->chan->buffer_size);
++
++ return(ret_ptr);
++}
++
++void cpmac_hal_isr(int irq, void *p_param, struct pt_regs *regs)
++{
++ CPMAC_ISR_INFO_T *p_cb_param = (CPMAC_ISR_INFO_T*) p_param;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cb_param->owner;
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_drv_hal->owner;
++ int pkts_to_handle = 0;
++
++ if(p_cpmac_priv->non_data_irq_expected)
++ {
++ p_cb_param->hal_isr(p_drv_hal->hal_dev, &pkts_to_handle);
++ p_drv_hal->hal_funcs->PacketProcessEnd(p_drv_hal->hal_dev);
++ }
++ else if(!p_cpmac_priv->set_to_close)
++ tasklet_schedule(&((CPMAC_ISR_INFO_T*) p_param)->tasklet);
++ else
++ ; // back off from doing anything more. We are closing down.
++}
++
++void cpmac_handle_tasklet(unsigned long data)
++{
++ CPMAC_ISR_INFO_T *p_cb_param = (CPMAC_ISR_INFO_T*) data;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cb_param->owner;
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_drv_hal->owner;
++ int pkts_to_handle;
++
++ p_cb_param->hal_isr(p_drv_hal->hal_dev, &pkts_to_handle);
++
++ if(test_bit(0, &p_cpmac_priv->non_data_irq_expected) || !pkts_to_handle)
++ p_drv_hal->hal_funcs->PacketProcessEnd(p_drv_hal->hal_dev);
++ else if(!test_bit(0, &p_cpmac_priv->set_to_close))
++ tasklet_schedule(&p_cb_param->tasklet);
++ else
++ ; // Back off from processing packets we are closing down.
++}
++
++int cpmac_hal_control(OS_DEVICE *p_dev, const char *key,
++ const char *action, void *value)
++{
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ int ret_val = -1;
++
++ if(key == NULL)
++ {
++ dbgPrint("Encountered NULL key.\n");
++ return (-1);
++ }
++
++ if(cpmac_ci_strcmp(key, "Sleep") == 0 && value != NULL)
++ {
++ unsigned int clocks_per_tick = cpmac_cpu_freq/HZ;
++ unsigned int requested_clocks = *(unsigned int*)value;
++ unsigned int requested_ticks = (requested_clocks + clocks_per_tick - 1)/clocks_per_tick;
++ mdelay(requested_ticks);
++ ret_val = 0;
++ }
++ else if(cpmac_ci_strcmp(key, "StateChange") == 0)
++ {
++ ret_val = cpmac_p_process_status_ind(p_cpmac_priv);
++ }
++ else if(cpmac_ci_strcmp(key, "Tick") == 0 && action != NULL)
++ {
++ if(cpmac_ci_strcmp(action, "Set") == 0 && value != NULL)
++ {
++ if(*(unsigned int*)value == 0)
++ {
++ cpmac_p_stop_timer(p_cpmac_priv->timer + TICK_TIMER);
++ ret_val = 0;
++ }
++ else
++ {
++ unsigned int clocks_per_tick = cpmac_cpu_freq/HZ;
++ unsigned int requested_clocks = *(unsigned int*)value;
++ unsigned int requested_ticks = (requested_clocks + clocks_per_tick - 1)/clocks_per_tick;
++
++ p_cpmac_priv->delay_ticks = requested_ticks; /* save it for re-triggering */
++ ret_val = cpmac_p_start_timer(p_cpmac_priv->timer + TICK_TIMER,
++ p_cpmac_priv->delay_ticks);
++ }
++ }
++ else if(cpmac_ci_strcmp(action, "Clear") == 0)
++ {
++ ret_val = cpmac_p_stop_timer(p_cpmac_priv->timer + TICK_TIMER);
++ }
++ else
++ ;
++ }
++ else if(cpmac_ci_strcmp(key, "MacAddr") == 0 && action != NULL)
++ {
++ if(cpmac_ci_strcmp(action, "Get") == 0 && value != NULL)
++ {
++ *(char **)value = p_cpmac_priv->mac_addr;
++ ret_val = 0;
++ }
++ }
++ else if(cpmac_ci_strcmp(key, "CpuFreq") == 0)
++ {
++ if(cpmac_ci_strcmp(action, "Get") == 0 && value != NULL)
++ {
++ *(unsigned int *)value = cpmac_cpu_freq;
++ dbgPrint("Cpu frequency for cpmacs is %u\n",cpmac_cpu_freq);
++ ret_val = 0;
++ }
++ }
++ else if(cpmac_ci_strcmp(key, "SioFlush") == 0)
++ {
++ ret_val = 0;
++ dbgPrint("\n");
++ }
++ else if(cpmac_ci_strcmp(key, "CpmacFrequency") == 0)
++ {
++ /* For Sangam cpmac clock is off the PBUS */
++ /* OS Needs to supply CORRECT frequency */
++ if(cpmac_ci_strcmp(action, "Get") == 0 && value != NULL)
++ {
++ *(unsigned int *)value = CONFIG_AR7_SYS * 1000 * 1000;
++ ret_val = 0;
++ }
++ }
++ /* For now, providing back the default values. */
++ else if(cpmac_ci_strcmp(key, "MdioClockFrequency") == 0)
++ {
++ if(cpmac_ci_strcmp(action, "Get") == 0 && value != NULL)
++ {
++ *(unsigned int *)value = 2200000; /*DEFAULT */
++ ret_val = 0;
++ }
++ }
++ /* For now, providing back the default values. */
++ else if(cpmac_ci_strcmp(key, "MdioBusFrequency") == 0)
++ {
++ /* For Sangam MdioBusFreq is off the PBUS */
++ if(cpmac_ci_strcmp(action, "Get") == 0 && value != NULL)
++ {
++ *(unsigned int *)value = CONFIG_AR7_SYS * 1000 * 1000;
++ ret_val = 0;
++ }
++ }
++
++#if 0
++#if defined(CONFIG_AVALANCHE_AUTO_MDIX)
++ /* supporting Mdio Mdix switching */
++ else if(cpmac_ci_strcmp(key, hcMdioMdixSwitch) == 0)
++ {
++ /* For Sangam Mdio-switching action should be always "set"*/
++ if(cpmac_ci_strcmp(action, hcSet) == 0 && value != NULL )
++ {
++ unsigned int mdix = *((unsigned int *) value) ;
++
++ if(mdix)
++ avalanche_set_phy_into_mdix_mode();
++
++ else
++ avalanche_set_phy_into_mdi_mode();
++
++ ret_val = 0;
++ }
++
++ }
++#endif
++#endif
++ else if(cpmac_ci_strcmp(key, hcMdioMdixSwitch) == 0)
++ {
++ /* For Sangam Mdio-switching action should be always "set"*/
++ if(cpmac_ci_strcmp(action, hcSet) == 0 && value != NULL )
++ {
++ unsigned int mdix = *((unsigned int *) value) ;
++
++#ifdef CONFIG_AR7_MDIX
++ avalanche_set_mdix_on_chip(0xa8610000 , mdix ? 1: 0);
++#endif
++
++ ret_val = 0;
++ }
++
++ }
++
++ return(ret_val);
++}
++
++
++int cpmac_hal_receive(OS_DEVICE *p_dev, FRAGLIST *fragList,
++ unsigned int fragCount,
++ unsigned int packet_size,
++ HAL_RECEIVEINFO *hal_receive_info,
++ unsigned int mode)
++{
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cpmac_priv->drv_hal;
++ struct sk_buff *p_skb = fragList[0].OsInfo;
++ p_skb->len = fragList[0].len;
++
++ /* invalidate the cache. */
++ dma_cache_inv((unsigned long)p_skb->data, fragList[0].len);
++#ifdef CPMAC_TEST
++ xdump(p_skb->data, p_skb->len, "recv");
++#endif
++#ifdef CPMAC_8021Q_SUPPORT
++ /* 802.1q stuff, just does the basic checking here. */
++ if(!p_cpmac_priv->enable_802_1q &&
++ p_skb->len > TCI_END_OFFSET &&
++ IS_802_1Q_FRAME(p_skb->data + TPID_START_OFFSET))
++ {
++ goto cpmac_hal_recv_frame_mismatch;
++ }
++#endif
++ if(fragCount > 1)
++ {
++ int len;
++ struct sk_buff *p_temp_skb;
++ CPMAC_RX_CHAN_INFO_T *p_rx_chan_info = p_cpmac_priv->rx_chan_info;
++ int count;
++
++ dbgPrint("Recv: It is multifragment for %s.\n", p_dev->name);
++
++ p_skb = dev_alloc_skb(packet_size +
++ p_rx_chan_info->chan->tot_reserve_bytes);
++ if(p_skb == NULL)
++ {
++ p_cpmac_priv->net_dev_stats.rx_errors++;
++ goto cpmac_hal_recv_alloc_failed;
++ }
++
++ p_skb->dev = p_dev;
++ skb_reserve(p_skb, p_rx_chan_info->chan->tot_reserve_bytes);
++
++ for(count = 0; count < fragCount; count++)
++ {
++ p_temp_skb = fragList[count].OsInfo;
++ len = fragList[count].len;
++
++ dma_cache_inv((unsigned long)p_temp_skb->data, len);
++
++ memcpy(skb_put(p_skb, len), p_temp_skb->data, len);
++ dev_kfree_skb_any(p_temp_skb);
++ }
++ }
++
++
++#if defined(CONFIG_MIPS_AVALANCHE_MARVELL)
++ /* Fetch the receiving port information from EGRESS TRAILOR Bytes*/
++ p_dev->if_port = (unsigned char)p_skb->data[packet_size -(EGRESS_TRAILOR_LEN-1)] + AVALANCHE_MARVELL_BASE_PORT_ID;
++ skb_trim(p_skb, packet_size - EGRESS_TRAILOR_LEN);
++#else
++ /* set length & tail */
++ skb_trim(p_skb, packet_size);
++#endif
++
++ p_skb->protocol = eth_type_trans(p_skb, p_dev);
++
++ netif_rx(p_skb);
++
++//#if defined (CONFIG_MIPS_AVALANCHE_LED)
++// avalanche_led_action(p_cpmac_priv->led_handle, CPMAC_RX_ACTIVITY);
++//#endif
++
++ p_cpmac_priv->net_dev_stats.rx_packets++;
++ p_cpmac_priv->net_dev_stats.rx_bytes += packet_size;
++
++ p_drv_hal->hal_funcs->RxReturn(hal_receive_info,1);
++
++ return(0);
++
++cpmac_hal_recv_alloc_failed:
++
++#ifdef CPMAC_8021Q_SUPPORT
++cpmac_hal_recv_frame_mismatch:
++#endif
++
++ fragCount--;
++
++ do
++ {
++ dev_kfree_skb_any(fragList[fragCount].OsInfo);
++ }
++ while(fragCount--);
++
++ p_cpmac_priv->net_dev_stats.rx_dropped++;
++
++ return(-1);
++} /*cpmac_receive*/
++
++
++void cpmac_hal_tear_down_complete(OS_DEVICE*a, int b, int ch)
++{
++ dbgPrint("what to do with this.\n");
++}
++
++
++int cpmac_hal_send_complete(OS_SENDINFO *p_skb)
++{
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_skb->dev->priv;
++
++ p_cpmac_priv->net_dev_stats.tx_packets++;
++ p_cpmac_priv->net_dev_stats.tx_bytes += p_skb->len;
++
++ dev_kfree_skb_any(p_skb);
++
++ return(0);
++}
++
++
++int cpmac_reset(CPMAC_PRIVATE_INFO_T *p_cpmac_priv)
++{
++ // code here to reset the device/hal. Not now.
++
++ netif_wake_queue(p_cpmac_priv->owner);
++ return(0);
++}
++
++#ifdef CPMAC_TEST
++
++#define isprint(a) ((a >=' ')&&(a<= '~'))
++void xdump( u_char* cp, int length, char* prefix )
++{
++ int col, count;
++ u_char prntBuf[120];
++ u_char* pBuf = prntBuf;
++ count = 0;
++ while(count < length){
++ pBuf += sprintf( pBuf, "%s", prefix );
++ for(col = 0;count + col < length && col < 16; col++){
++ if (col != 0 && (col % 4) == 0)
++ pBuf += sprintf( pBuf, " " );
++ pBuf += sprintf( pBuf, "%02X ", cp[count + col] );
++ }
++ while(col++ < 16){ /* pad end of buffer with blanks */
++ if ((col % 4) == 0)
++ sprintf( pBuf, " " );
++ pBuf += sprintf( pBuf, " " );
++ }
++ pBuf += sprintf( pBuf, " " );
++ for(col = 0;count + col < length && col < 16; col++){
++ if (isprint((int)cp[count + col]))
++ pBuf += sprintf( pBuf, "%c", cp[count + col] );
++ else
++ pBuf += sprintf( pBuf, "." );
++ }
++ sprintf( pBuf, "\n" );
++ // SPrint(prntBuf);
++ printk(prntBuf);
++ count += col;
++ pBuf = prntBuf;
++ }
++
++} /* close xdump(... */
++#endif
++
++
++static int __init cpmac_dev_probe(void)
++{
++ int retVal = 0;
++ int unit;
++ int instance_count = CONFIG_MIPS_CPMAC_PORTS;
++
++ //cpmac_cpu_freq = avalanche_clkc_get_freq(CLKC_MIPS);
++ cpmac_cpu_freq = CONFIG_AR7_CPU * 1000 * 1000;
++
++ build_psp_config();
++
++ for(unit = 0; unit < instance_count; unit++)
++ {
++ struct net_device *p_dev;
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv;
++ size_t dev_size;
++ int failed;
++
++ dev_size = sizeof(struct net_device)
++ + sizeof(CPMAC_PRIVATE_INFO_T);
++
++
++ if((p_dev = (struct net_device *) kmalloc(dev_size, GFP_KERNEL)) == NULL)
++ {
++ dbgPrint( "Could not allocate memory for device.\n" );
++ retVal = -ENOMEM;
++ break;
++ }
++
++ memset(p_dev, 0, dev_size );
++
++ p_dev->priv = p_cpmac_priv
++ = (CPMAC_PRIVATE_INFO_T*)(((char *) p_dev) + sizeof(struct net_device));
++ p_cpmac_priv->owner = p_dev;
++
++ ether_setup(p_dev);
++
++ p_cpmac_priv->instance_num = unit;
++ p_dev->init = cpmac_dev_init;
++
++ g_dev_array[p_cpmac_priv->instance_num] = p_dev;
++
++#if defined CONFIG_MIPS_CPMAC_INIT_BUF_MALLOC
++ g_init_enable_flag = 1;
++ printk("Cpmac driver is allocating buffer memory at init time.\n");
++#endif
++
++ /* This section gives a default value by the number of PHY in order to
++ * replace the default MACRO. */
++ {
++ char *mac_port = prom_getenv("MAC_PORT"); /* Internal: 0, External: 1 */
++ if(0 == strcmp(mac_port, "1")) {
++ printk("Using the MAC with external PHY\n");
++ cfg_start_link_speed = _CPMDIO_NOPHY;
++ cpmac_max_frame_size = CPMAC_MAX_FRAME_SIZE + 4;
++ }
++ else {
++ printk("Using the MAC with internal PHY\n");
++ cfg_start_link_speed = CFG_START_LINK_SPEED;
++ cpmac_max_frame_size = CPMAC_MAX_FRAME_SIZE;
++ }
++ g_cfg_start_link_params = cfg_start_link_speed;
++ }
++
++ cpmac_p_detect_manual_cfg(cfg_link_speed, cfg_link_mode, cpmac_debug_mode);
++
++ failed = register_netdev(p_dev);
++ if (failed)
++ {
++ dbgPrint("Could not register device for inst %d because of reason \
++ code %d.\n", unit, failed);
++ retVal = -1;
++ kfree(p_dev);
++ break;
++ }
++ else
++ {
++
++ char proc_name[100];
++ int proc_category_name_len = 0;
++
++ p_cpmac_priv->next_device = last_cpmac_device;
++ last_cpmac_device = p_dev;
++
++ dbgPrint(" %s irq=%2d io=%04x\n",p_dev->name, (int) p_dev->irq,
++ (int) p_dev->base_addr);
++
++ strcpy(proc_name, "avalanche/");
++ strcat(proc_name, p_dev->name);
++ proc_category_name_len = strlen(proc_name);
++
++ strcpy(proc_name + proc_category_name_len, "_rfc2665_stats");
++ create_proc_read_entry(proc_name,0,NULL,cpmac_p_read_rfc2665_stats, p_dev);
++
++ }
++ }
++
++ if(retVal == 0)
++ {
++ /* To maintain backward compatibility with NSP. */
++ gp_stats_file = create_proc_entry("avalanche/cpmac_stats", 0644, NULL);
++ if(gp_stats_file)
++ {
++ gp_stats_file->read_proc = cpmac_p_read_stats;
++ gp_stats_file->write_proc = cpmac_p_write_stats;
++ }
++ create_proc_read_entry("avalanche/cpmac_link", 0, NULL, cpmac_p_read_link, NULL);
++ create_proc_read_entry("avalanche/cpmac_ver", 0, NULL, cpmac_p_get_version, NULL);
++
++ }
++
++ cpmac_devices_installed = unit;
++ dbgPrint("Installed %d cpmac instances.\n", unit);
++ return ( (unit >= 0 ) ? 0 : -ENODEV );
++
++} /* init_module */
++
++
++/***************************************************************
++ * cleanup_module
++ *
++ * Returns:
++ * Nothing
++ * Parms:
++ * None
++ *
++ * Goes through the CpmacDevices list and frees the device
++ * structs and memory associated with each device (lists
++ * and buffers). It also ureserves the IO port regions
++ * associated with this device.
++ *
++ **************************************************************/
++
++void cpmac_exit(void)
++{
++ struct net_device *p_dev;
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv;
++
++ while (cpmac_devices_installed)
++ {
++ char proc_name[100];
++ int proc_category_name_len = 0;
++
++ p_dev = last_cpmac_device;
++ p_cpmac_priv = (CPMAC_PRIVATE_INFO_T *) p_dev->priv;
++
++ dbgPrint("Unloading %s irq=%2d io=%04x\n",p_dev->name, (int) p_dev->irq, (int) p_dev->base_addr);
++
++ if(g_init_enable_flag)
++ cpmac_p_dev_disable(p_dev);
++
++ cpmac_drv_cleanup(p_cpmac_priv->drv_hal);
++
++//#if defined (CONFIG_MIPS_AVALANCHE_LED)
++// avalanche_led_unregister(p_cpmac_priv->led_handle);
++//#endif
++ strcpy(proc_name, "avalanche/");
++ strcat(proc_name, p_dev->name);
++ proc_category_name_len = strlen(proc_name);
++
++ strcpy(proc_name + proc_category_name_len, "_rfc2665_stats");
++ remove_proc_entry(proc_name, NULL);
++
++ release_mem_region(p_dev->base_addr, p_cpmac_priv->dev_size);
++ unregister_netdev(p_dev);
++ last_cpmac_device = p_cpmac_priv->next_device;
++
++ kfree(p_cpmac_priv->drv_hal);
++ kfree(p_dev);
++
++ cpmac_devices_installed--;
++ }
++
++ if(gp_stats_file)
++ remove_proc_entry("avalanche/cpmac_stats", NULL);
++
++ remove_proc_entry("avalanche/cpmac_link", NULL);
++ remove_proc_entry("avalanche/cpmac_ver", NULL);
++
++ psp_config_cleanup();
++}
++
++
++module_init(cpmac_dev_probe);
++module_exit(cpmac_exit);
+diff -urN linux.old/drivers/net/avalanche_cpmac/cpmac.h linux.dev/drivers/net/avalanche_cpmac/cpmac.h
+--- linux.old/drivers/net/avalanche_cpmac/cpmac.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/cpmac.h 2005-07-12 02:48:42.043594000 +0200
+@@ -0,0 +1,379 @@
++/******************************************************************************
++ * FILE PURPOSE: CPMAC Linux Network Device Driver Header
++ ******************************************************************************
++ * FILE NAME: cpmac.h
++ *
++ * DESCRIPTION: CPMAC Network Device Driver Header
++ *
++ * REVISION HISTORY:
++ * Date Name Details
++ *-----------------------------------------------------------------------------
++ * 27 Nov 2002 Suraj S Iyer Initial Create.
++ * 09 Jun 2003 Suraj S Iyer Preparing for GA.
++ *
++ * (C) Copyright 2003, Texas Instruments, Inc
++ *******************************************************************************/
++
++#ifndef CPMAC_H
++#define CPMAC_H
++
++#include <linux/timer.h>
++#include <linux/netdevice.h>
++#include <asm/semaphore.h>
++#include <linux/ctype.h>
++#include <linux/interrupt.h>
++
++#include "cpmacHalLx.h"
++/*-----------------------------------------------------------------------------
++ * Config macros. Use these to config the driver.
++ *---------------------------------------------------------------------------*/
++#define CPMAC_MAX_FRAME_SIZE 1518
++
++#if defined(CONFIG_AR7WRD) || defined(CONFIG_AR7WI) || defined(CONFIG_AR7VWI)|| defined(CONFIG_AR7VW)
++#define CFG_RX_NUM_BUF_DESC 64
++#define CFG_RX_NUM_BUF_SERVICE 32
++#else
++#define CFG_RX_NUM_BUF_DESC 16
++#define CFG_RX_NUM_BUF_SERVICE 8
++#endif
++
++#define CFG_RX_BUF_OFFSET 0
++
++#define CFG_TX_NUM_BUF_DESC 128
++#define CFG_TX_NUM_BUF_SERVICE 20
++#define CFG_TX_BUF_OFFSET 0 /* Lets not change this. */
++#define CFG_TX_TIMEOUT 2000 /* ticks*/
++#define CFG_TX_INT_DISABLE 1 /* Disable the Tx Complete interrupt */
++
++#define CFG_JUMBO_FRAMES 1
++#define CFG_SHORT_FRAMES 1
++#define CFG_PROMISCOUS 1
++#define CFG_BROADCAST 1
++#define CFG_MULTICAST 1
++#define CFG_ALL_MULTI (1*(CFG_MULTICAST))
++#define CFG_AUTO_NEGOTIATION 1
++
++#if defined (CONFIG_MIPS_AVALANCHE_MARVELL)
++#define EGRESS_TRAILOR_LEN 4
++#define CFG_START_LINK_SPEED (_CPMDIO_NOPHY)
++#undef CPMAC_MAX_FRAME_SIZE
++#define CPMAC_MAX_FRAME_SIZE (1518 + EGRESS_TRAILOR_LEN)
++#else
++#define CFG_START_LINK_SPEED (_CPMDIO_10 | _CPMDIO_100 | _CPMDIO_HD | _CPMDIO_FD) /* auto nego */
++#endif
++
++#define CFG_LOOP_BACK 1
++#define CFG_TX_FLOW_CNTL 0
++#define CFG_RX_FLOW_CNTL 0
++#define CFG_TX_PACING 0
++#define CFG_RX_PASS_CRC 0
++#define CFG_QOS_802_1Q 0
++#define CFG_TX_NUM_CHAN 1
++
++
++/*-----------------------------------------------------------------------------
++ * Private macros.
++ *---------------------------------------------------------------------------*/
++#define MAX_TIMER 2
++#define TX_TIMER 0
++#define TICK_TIMER 0
++#define MAX_TX_CHAN 8
++
++#define CPMAC_LINK_OFF 0
++#define CPMAC_LINK_ON 1
++/*#define CPMAC_SPEED_100 2
++#define CPMAC_SPEED_10 3
++#define CPMAC_FULL_DPLX 4
++#define CPMAC_HALF_DPLX 5*/
++#define CPMAC_RX_ACTIVITY 2
++#define CPMAC_TX_ACTIVITY 3
++
++struct cpmac_timer_info;
++
++typedef int (*CPMAC_HAL_ISR_FUNC_T)(HAL_DEVICE*, int*);
++typedef int (*CPMAC_TIMEOUT_CB_T)(struct cpmac_timer_info*);
++
++typedef struct cpmac_ability_info
++{
++ int promiscous;
++ int broadcast;
++ int multicast;
++ int all_multi;
++ int loop_back;
++ int jumbo_frames;
++ int short_frames;
++ int auto_negotiation;
++ int tx_flow_control;
++ int rx_flow_control;
++ int tx_pacing;
++ int link_speed;
++ int rx_pass_crc;
++ int qos_802_1q;
++ int tx_num_chan;
++}
++CPMAC_ABILITY_INFO_T;
++
++#ifdef DEBUG
++typedef struct cpmac_timer_info
++{
++ void *owner;
++ UINT32 delay_ticks;
++ WDOG_ID timer_id;
++ UINT32 is_running;
++ UINT32 timer_set_at;
++ CPMAC_TIMEOUT_CB_T timeout_CB;
++} CPMAC_TIMER_INFO_T;
++
++typedef struct
++{
++ void *owner;
++ unsigned int num_cl_desc;
++ CL_DESC *cl_desc_tbl;
++ M_CL_CONFIG *m_cl_blk_config;
++ NET_POOL *net_pool;
++ CL_POOL_ID clPoolId;
++
++} CPMAC_NET_MEM_INFO_T;
++
++#endif
++
++typedef struct
++{
++ void *owner;
++ CPMAC_HAL_ISR_FUNC_T hal_isr;
++ struct tasklet_struct tasklet;
++ int intr;
++
++} CPMAC_ISR_INFO_T;
++
++typedef struct cpmac_chan
++{
++ int num_BD;
++ int buffer_size;
++ int buffer_offset;
++ int service_max;
++ int state;
++ int tot_buf_size;
++ int tot_reserve_bytes;
++
++} CPMAC_CHAN_T;
++
++#define CHAN_CLOSE 0
++#define CHAN_OPENED 1
++
++typedef struct
++{
++ int cfg_chan;
++ int dev_chan;
++ int opened_chan;
++ CPMAC_CHAN_T chan[1];
++ int enable_802_1q;
++
++} CPMAC_RX_CHAN_INFO_T;
++
++typedef struct
++{
++ int cfg_chan;
++ int dev_chan;
++ int opened_chan;
++ int tx_int_disable;
++ CPMAC_CHAN_T chan[MAX_TX_CHAN];
++
++} CPMAC_TX_CHAN_INFO_T;
++
++
++
++typedef struct
++{
++ void *owner;
++ HAL_FUNCTIONS *hal_funcs;
++ HAL_DEVICE *hal_dev;
++ OS_FUNCTIONS *os_funcs;
++// SEM_ID chan_teardown_sem;
++ int non_data_irq_expected;
++} CPMAC_DRV_HAL_INFO_T;
++
++
++typedef struct
++{
++ unsigned long tx_discards;
++ unsigned long rx_discards;
++ unsigned long start_tick;
++
++} CPMAC_DRV_STATS_T;
++
++typedef struct
++{
++ unsigned long ifInGoodFrames;
++ unsigned long ifInBroadcasts;
++ unsigned long ifInMulticasts;
++ unsigned long ifInPauseFrames;
++ unsigned long ifInCRCErrors;
++ unsigned long ifInAlignCodeErrors;
++ unsigned long ifInOversizedFrames;
++ unsigned long ifInJabberFrames;
++ unsigned long ifInUndersizedFrames;
++ unsigned long ifInFragments;
++ unsigned long ifInFilteredFrames;
++ unsigned long ifInQosFilteredFrames;
++ unsigned long ifInOctets;
++ unsigned long ifOutGoodFrames;
++ unsigned long ifOutBroadcasts;
++ unsigned long ifOutMulticasts;
++ unsigned long ifOutPauseFrames;
++ unsigned long ifDeferredTransmissions;
++ unsigned long ifCollisionFrames;
++ unsigned long ifSingleCollisionFrames;
++ unsigned long ifMultipleCollisionFrames;
++ unsigned long ifExcessiveCollisionFrames;
++ unsigned long ifLateCollisions;
++ unsigned long ifOutUnderrun;
++ unsigned long ifCarrierSenseErrors;
++ unsigned long ifOutOctets;
++ unsigned long if64OctetFrames;
++ unsigned long if65To127OctetFrames;
++ unsigned long if128To255OctetFrames;
++ unsigned long if256To511OctetFrames;
++ unsigned long if512To1023OctetFrames;
++ unsigned long if1024ToUPOctetFrames;
++ unsigned long ifNetOctets;
++ unsigned long ifRxSofOverruns;
++ unsigned long ifRxMofOverruns;
++ unsigned long ifRxDMAOverruns;
++
++} CPMAC_DEVICE_MIB_T;
++
++
++typedef struct
++{
++ void *owner;
++ int timer_count;
++ int timer_created;
++ struct timer_list timer[1];
++ CPMAC_DRV_HAL_INFO_T *drv_hal;
++ unsigned int num_of_intr;
++ CPMAC_ISR_INFO_T cpmac_isr;
++ unsigned int link_speed;
++ unsigned int link_mode;
++ unsigned int enable_802_1q;
++ unsigned int timer_access_hal;
++ unsigned int loop_back;
++ CPMAC_RX_CHAN_INFO_T *rx_chan_info;
++ CPMAC_TX_CHAN_INFO_T *tx_chan_info;
++ CPMAC_ABILITY_INFO_T *ability_info;
++ CPMAC_DEVICE_MIB_T *device_mib;
++ CPMAC_DRV_STATS_T *stats;
++ unsigned int flags;
++ unsigned int delay_ticks;
++ char mac_addr[6];
++ struct net_device_stats net_dev_stats;
++// rwlock_t rw_lock;
++ int set_to_close;
++ struct net_device *next_device;
++ unsigned int instance_num;
++ unsigned int non_data_irq_expected;
++ unsigned long dev_size;
++ void* led_handle;
++} CPMAC_PRIVATE_INFO_T;
++
++
++/* Private flags */
++
++/* bit 0 to 31, bit 32 is used to indicate set or reset */
++
++#define IFF_PRIV_SHORT_FRAMES 0x00010000
++#define IFF_PRIV_JUMBO_FRAMES 0x00020000
++#define IFF_PRIV_AUTOSPEED 0x00080000
++#define IFF_PRIV_LINK10_HD 0x00100000
++#define IFF_PRIV_LINK10_FD 0x00200000
++#define IFF_PRIV_LINK100_HD 0x00400000
++#define IFF_PRIV_LINK100_FD 0x00800000
++#define IFF_PRIV_8021Q_EN 0x01000000
++#define IFF_PRIV_NUM_TX_CHAN 0x02000000
++#define IFF_PRIV_TX_FLOW_CNTL 0x04000000
++#define IFF_PRIV_RX_FLOW_CNTL 0x08000000
++#define IFF_PRIV_TX_PACING 0x10000000
++#define IFF_PRIV_RX_PASS_CRC 0x20000000
++
++#define PRIVCSFLAGS 0x200
++#define PRIVCGFLAGS 0x201
++
++
++#define BLOCKING 1
++#define CHAN_TEARDOWN 2
++#define CHAN_SETUP 4
++#define COMPLETE 8
++#define FREE_BUFFER 16
++
++
++static const char pszStats0[] = "Stats0";
++static const char pszStats1[] = "Stats1";
++static const char pszStats2[] = "Stats2";
++static const char pszStats3[] = "Stats3";
++static const char pszStats4[] = "Stats4";
++static const char pszStatsDump[] = "StatsDump";
++static const char pszStatsClear[] = "StatsClear";
++static const char pszRX_PASS_CRC[] = "RX_PASS_CRC";
++static const char pszRX_QOS_EN[] = "RX_QOS_EN";
++static const char pszRX_NO_CHAIN[] = "RX_NO_CHAIN";
++static const char pszRX_CMF_EN[] = "RX_CMF_EN";
++static const char pszRX_CSF_EN[] = "RX_CSF_EN";
++static const char pszRX_CEF_EN[] = "RX_CEF_EN";
++static const char pszRX_CAF_EN[] = "RX_CAF_EN";
++static const char pszRX_PROM_CH[] = "RX_PROM_CH";
++static const char pszRX_BROAD_EN[] = "RX_BROAD_EN";
++static const char pszRX_BROAD_CH[] = "RX_BROAD_CH";
++static const char pszRX_MULT_EN[] = "RX_MULT_EN";
++static const char pszRX_MULT_CH[] = "RX_MULT_CH";
++static const char pszTX_PTYPE[] = "TX_PTYPE";
++static const char pszTX_PACE[] = "TX_PACE";
++static const char pszMII_EN[] = "MII_EN";
++static const char pszTX_FLOW_EN[] = "TX_FLOW_EN";
++static const char pszRX_FLOW_EN[] = "RX_FLOW_EN";
++static const char pszRX_MAXLEN[] = "RX_MAXLEN";
++static const char pszRX_FILTERLOWTHRESH[] = "RX_FILTERLOWTHRESH";
++static const char pszRX0_FLOWTHRESH[] = "RX0_FLOWTHRESH";
++static const char pszRX_UNICAST_SET[] = "RX_UNICAST_SET";
++static const char pszRX_UNICAST_CLEAR[] = "RX_UNICAST_CLEAR";
++static const char pszMdioConnect[] = "MdioConnect";
++static const char pszMacAddr[] = "MacAddr";
++static const char pszTick[] = "Tick";
++static const char pszRX_MULTICAST[] = "RX_MULTICAST";
++static const char pszRX_MULTI_ALL[] = "RX_MULTI_ALL";
++static const char pszRX_MULTI_SINGLE[] = "RX_MULTI_SINGLE";
++
++static const char pszSet[] = "Set";
++static const char pszGet[] = "Get";
++static const char pszClear[] = "Clear";
++
++
++void *cpmac_hal_malloc_buffer(unsigned int size, void *MemBase, unsigned int MemRange,
++ HAL_DEVICE *HalDev, HAL_RECEIVEINFO *HalReceiveInfo,
++ OS_RECEIVEINFO **OsReceiveInfo, OS_DEVICE *OsDev);
++
++void cpmac_hal_tear_down_complete(OS_DEVICE*, int, int);
++int cpmac_hal_control(OS_DEVICE *p_END_obj, const char *key,
++ const char *action, void *value);
++int cpmac_hal_receive(OS_DEVICE *p_END_obj, FRAGLIST *fragList,
++ unsigned int FragCount, unsigned int pkt_len,
++ HAL_RECEIVEINFO *halReceiveInfo,
++ unsigned int mode);
++int cpmac_hal_send_complete(OS_SENDINFO*);
++
++void cpmac_hal_isr(int irq, void *p_param, struct pt_regs *p_cb_param);
++void cpmac_handle_tasklet(unsigned long data);
++
++inline static int cpmac_ci_strcmp(const char *s1, const char *s2)
++{
++ while(*s1 && *s2)
++ {
++ if(tolower(*s1) != tolower(*s2))
++ break;
++ s1++;
++ s2++;
++ }
++
++ return(tolower(*s1) - tolower(*s2));
++}
++
++#endif
+diff -urN linux.old/drivers/net/avalanche_cpmac/cpmacHalLx.c linux.dev/drivers/net/avalanche_cpmac/cpmacHalLx.c
+--- linux.old/drivers/net/avalanche_cpmac/cpmacHalLx.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/cpmacHalLx.c 2005-07-12 02:48:42.044593000 +0200
+@@ -0,0 +1,492 @@
++/******************************************************************************
++ * FILE PURPOSE: CPMAC Net Driver HAL support Source
++ ******************************************************************************
++ * FILE NAME: cpmacHalLx.c
++ *
++ * DESCRIPTION: CPMAC Network Device Driver Source
++ *
++ * REVISION HISTORY:
++ *
++ * Date Description Author
++ *-----------------------------------------------------------------------------
++ * 27 Nov 2002 Initial Creation Suraj S Iyer
++ * 09 Jun 2003 Updates for GA Suraj S Iyer
++ * 18 Dec 2003 Updated for 5.7 Suraj S Iyer
++ *
++ * (C) Copyright 2003, Texas Instruments, Inc
++ *******************************************************************************/
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/proc_fs.h>
++#include <asm/io.h>
++#include <linux/string.h>
++
++#include <asm/ar7/avalanche_intc.h>
++
++#include "cpmacHalLx.h"
++#include "cpmac.h"
++
++/* PSP config headers */
++#include "psp_config_parse.h"
++#include "psp_config_mgr.h"
++
++/* debug */
++extern int cpmac_debug_mode;
++#define dbgPrint if (cpmac_debug_mode) printk
++#define errPrint printk
++
++char CpmacSignature[] = "Cpmac driver";
++static unsigned long irq_flags = 0;
++OS_SETUP *p_os_setup = NULL;
++
++extern int avalanche_request_intr_pacing(int, unsigned int, unsigned int);
++extern int avalanche_free_intr_pacing(unsigned int blk_num);
++
++/*----------------------------------------------------------------------------
++ * Parameter extracting functionalities.
++ *--------------------------------------------------------------------------*/
++static int os_find_parm_u_int(void *info_ptr, const char *param, unsigned int *val)
++{
++ int ret_val = 0;
++
++ if((ret_val = psp_config_get_param_uint(info_ptr, param, val)) == -1)
++ {
++ dbgPrint("Error: could not locate the requested \"%s\" param.\n",param);
++ ret_val = -1;
++ }
++
++ return(ret_val);
++}
++
++static int os_find_parm_val(void *info_ptr, const char *param, void *val)
++{
++ int ret_val = 0;
++
++ if(psp_config_get_param_string(info_ptr, param, val) == -1)
++ {
++ dbgPrint("Error: could not locate the requested \"%s\" param.\n",param);
++ ret_val = -1;
++ }
++
++ return(ret_val);
++}
++
++static int os_find_device(int unit, const char *find_name, void *device_info)
++{
++ int ret_val = 0;
++
++ if(psp_config_get((char *)find_name, unit, device_info) == -1)
++ {
++ dbgPrint("Error: could not locate the requested \"%s\" param.\n", find_name);
++ ret_val = -1;
++ }
++
++ return(ret_val);
++}
++
++/*---------------------------------------------------------------------------
++ * Memory related OS abstraction.
++ *--------------------------------------------------------------------------*/
++void os_free(void *mem_ptr)
++{
++ kfree(mem_ptr);
++}
++
++void os_free_buffer(OS_RECEIVEINFO *osReceiveInfo, void *mem_ptr)
++{
++ dev_kfree_skb_any(osReceiveInfo);
++}
++
++void os_free_dev(void *mem_ptr)
++{
++ kfree(mem_ptr);
++}
++
++void os_free_dma_xfer(void *mem_ptr)
++{
++ kfree(mem_ptr);
++}
++
++static void *os_malloc(unsigned int size)
++{
++ return(kmalloc(size, GFP_KERNEL));
++}
++
++static void *os_malloc_dma_xfer(unsigned int size,
++ void *mem_base,
++ unsigned int mem_range)
++{
++ return(kmalloc(size, GFP_KERNEL));
++}
++
++static void *os_malloc_dev(unsigned int size)
++{
++ return(kmalloc(size, GFP_KERNEL));
++}
++
++
++/*----------------------------------------------------------------------------
++ * CRITICAL SECTION ENABLING/DISABLING.
++ *--------------------------------------------------------------------------*/
++static void os_critical_on(void)
++{
++ save_and_cli(irq_flags);
++}
++
++static void os_critical_off(void)
++{
++ restore_flags(irq_flags);
++}
++
++/*----------------------------------------------------------------------------
++ * Cache related abstraction
++ *--------------------------------------------------------------------------*/
++static void os_cache_invalidate(void *mem_ptr, int size)
++{
++ dma_cache_inv((unsigned long)mem_ptr, size);
++}
++
++static void os_cache_writeback(void *mem_ptr, int size)
++{
++ dma_cache_wback_inv((unsigned long)mem_ptr, size);
++}
++
++/*-----------------------------------------------------------------------------
++ * Support functions.
++ *---------------------------------------------------------------------------*/
++
++static void hal_drv_unregister_isr(OS_DEVICE *p_dev, int intr)
++{
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ CPMAC_ISR_INFO_T *p_isr_cb_param = &p_cpmac_priv->cpmac_isr;
++ intr = LNXINTNUM(intr);
++
++ free_irq(p_isr_cb_param->intr, p_isr_cb_param);
++
++ dbgPrint("cpmac_hal_unregister called for the intr %d for unit %x and isr_cb_param %x.\n",
++ intr, p_cpmac_priv->instance_num, (unsigned int )&p_cpmac_priv->cpmac_isr);
++}
++
++
++static void hal_drv_register_isr(OS_DEVICE *p_dev,
++ CPMAC_HAL_ISR_FUNC_T hal_isr, int intr)
++{
++ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
++ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cpmac_priv->drv_hal;
++ CPMAC_ISR_INFO_T *p_isr_cb_param = &p_cpmac_priv->cpmac_isr;
++ intr = LNXINTNUM(intr);
++
++ dbgPrint("osRegister called for the intr %d for device %x and p_isr_cb_param %x.\n",
++ intr, (bit32u)p_dev, (bit32u)p_isr_cb_param);
++
++ p_isr_cb_param->owner = p_drv_hal;
++ p_isr_cb_param->hal_isr = hal_isr;
++ p_isr_cb_param->intr = intr;
++
++ tasklet_init(&p_isr_cb_param->tasklet, cpmac_handle_tasklet, (unsigned long)p_isr_cb_param);
++ dbgPrint("Success in registering irq %d for Cpmac unit# %d.\n", intr, p_cpmac_priv->instance_num);
++}
++
++/*---------------------------------------------------------------------------
++ * FUNCTIONS called by the CPMAC Net Device.
++ *-------------------------------------------------------------------------*/
++static int load_os_funcs(OS_FUNCTIONS *os_func)
++{
++ dbgPrint("os_init_module: Start\n");
++ if( os_func == 0 )
++ {
++ return(sizeof(OS_FUNCTIONS));
++ }
++
++ os_func->Control = cpmac_hal_control;
++ os_func->CriticalOn = os_critical_on;
++ os_func->CriticalOff = os_critical_off;
++ os_func->DataCacheHitInvalidate = os_cache_invalidate;
++ os_func->DataCacheHitWriteback = os_cache_writeback;
++ os_func->DeviceFindInfo = os_find_device;
++ os_func->DeviceFindParmUint = os_find_parm_u_int;
++ os_func->DeviceFindParmValue= os_find_parm_val;
++ os_func->Free = os_free;
++ os_func->FreeRxBuffer = os_free_buffer;
++ os_func->FreeDev = os_free_dev;
++ os_func->FreeDmaXfer = os_free_dma_xfer;
++ os_func->IsrRegister = hal_drv_register_isr;
++ os_func->IsrUnRegister = hal_drv_unregister_isr;
++ os_func->Malloc = os_malloc;
++ os_func->MallocDev = os_malloc_dev;
++ os_func->MallocDmaXfer = os_malloc_dma_xfer;
++ os_func->MallocRxBuffer = cpmac_hal_malloc_buffer;
++ os_func->Memset = memset;
++ os_func->Printf = printk;
++ os_func->Receive = cpmac_hal_receive;
++ os_func->SendComplete = cpmac_hal_send_complete;
++ os_func->Strcmpi = cpmac_ci_strcmp;
++ os_func->TeardownComplete = cpmac_hal_tear_down_complete;
++ os_func->Strstr = strstr;
++ os_func->Strtoul = simple_strtol;
++ os_func->Sprintf = sprintf;
++ os_func->Strlen = strlen;
++
++ dbgPrint("os_init_module: Leave\n");
++
++ return(0);
++}
++
++
++int cpmac_drv_init(CPMAC_DRV_HAL_INFO_T *p_drv_hal)
++{
++ HAL_DEVICE *p_hal_dev = p_drv_hal->hal_dev;
++ HAL_FUNCTIONS *p_hal_funcs = p_drv_hal->hal_funcs;
++
++ return(p_hal_funcs->Init(p_hal_dev));
++}
++
++int cpmac_drv_cleanup(CPMAC_DRV_HAL_INFO_T *p_drv_hal)
++{
++ HAL_DEVICE *p_hal_dev = p_drv_hal->hal_dev;
++ HAL_FUNCTIONS *p_hal_funcs = p_drv_hal->hal_funcs;
++
++ int ret_val = p_hal_funcs->Shutdown(p_hal_dev);
++
++#if 0
++ if(ret_val == 0)
++ kfree(p_hal_funcs);
++ else
++ ret_val = -1;
++#endif
++
++ kfree(p_drv_hal->os_funcs);
++
++ return (ret_val);
++}
++
++int cpmac_drv_tx_setup(HAL_FUNCTIONS *p_hal_funcs,
++ HAL_DEVICE *p_hal_dev,
++ CPMAC_TX_CHAN_INFO_T *p_tx_chan_info)
++{
++ int ret_val = 0;
++ int count = 0;
++ CHANNEL_INFO chan_info;
++
++ /* Let's setup the TX Channels. */
++ for(count=0; count < p_tx_chan_info->cfg_chan; count++)
++ {
++ chan_info.Channel = count;
++ chan_info.Direction = DIRECTION_TX;
++ chan_info.TxNumBuffers = p_tx_chan_info->chan[count].num_BD;
++ chan_info.TxServiceMax = p_tx_chan_info->chan[count].service_max;
++ chan_info.TxNumQueues = 0;
++
++ if((ret_val = p_hal_funcs->ChannelSetup(p_hal_dev, &chan_info,
++ NULL)) != 0)
++ {
++ errPrint("Error in opening channel %d for TX.\n", count);
++ ret_val = -1;
++ break;
++ }
++
++ p_tx_chan_info->opened_chan++;
++ }
++
++ return(ret_val);
++}
++
++int cpmac_drv_rx_setup(HAL_FUNCTIONS *p_hal_funcs,
++ HAL_DEVICE *p_hal_dev,
++ CPMAC_RX_CHAN_INFO_T *p_rx_chan_info)
++{
++ int ret_val = 0;
++ CHANNEL_INFO chan_info;
++
++ chan_info.Channel = 0;
++ chan_info.Direction = DIRECTION_RX;
++ chan_info.RxBufSize = p_rx_chan_info->chan[0].buffer_size;
++ chan_info.RxBufferOffset= p_rx_chan_info->chan[0].buffer_offset;
++ chan_info.RxNumBuffers = p_rx_chan_info->chan[0].num_BD;
++ chan_info.RxServiceMax = p_rx_chan_info->chan[0].service_max;
++
++ if(p_hal_funcs->ChannelSetup(p_hal_dev, &chan_info, p_rx_chan_info) != 0)
++ {
++ errPrint("Error in opening channel %d for RX.\n", 0);
++ ret_val = -1;
++ }
++
++ return(ret_val);
++}
++
++int cpmac_drv_start(CPMAC_DRV_HAL_INFO_T *p_drv_hal,
++ CPMAC_TX_CHAN_INFO_T *p_tx_chan_info,
++ CPMAC_RX_CHAN_INFO_T *p_rx_chan_info,
++ unsigned int flags)
++{
++ int ret_val = 0;
++ HAL_FUNCTIONS *p_hal_funcs = p_drv_hal->hal_funcs;
++ HAL_DEVICE *p_hal_dev = p_drv_hal->hal_dev;
++
++ dbgPrint("It is in cpmac_drv_start for %x.\n", (unsigned int)p_drv_hal);
++
++ if(flags & CHAN_SETUP)
++ {
++ if(cpmac_drv_tx_setup(p_hal_funcs, p_hal_dev,
++ p_tx_chan_info)!=0)
++ {
++ errPrint("Failed to set up tx channel(s).\n");
++ ret_val = -1;
++ }
++ else if(cpmac_drv_rx_setup(p_hal_funcs, p_hal_dev,
++ p_rx_chan_info)!=0)
++ {
++ errPrint("Failed to set up rx channel.\n");
++ ret_val = -1;
++ }
++ else
++ {
++ ret_val = 0;
++ }
++ }
++
++ /* Error in setting up the Channels, quit. */
++ if((ret_val == 0) && (ret_val = p_hal_funcs->Open(p_hal_dev)) != 0)
++ {
++ errPrint("failed to open the HAL!!!.\n");
++ ret_val = -1;
++ }
++
++ return (ret_val);
++} /* cpmac_drv_start */
++
++
++
++int cpmac_drv_tx_teardown(HAL_FUNCTIONS *p_hal_funcs,
++ HAL_DEVICE *p_hal_dev,
++ CPMAC_TX_CHAN_INFO_T *p_tx_chan_info,
++ unsigned int flags)
++{
++ int ret_val = 0;
++ int count = 0;
++
++ /* Let's setup the TX Channels. */
++ for(; p_tx_chan_info->opened_chan > 0;
++ p_tx_chan_info->opened_chan--, count++)
++ {
++ if(p_hal_funcs->ChannelTeardown(p_hal_dev, count, flags) != 0)
++ {
++ errPrint("Error in tearing down channel %d for TX.\n", count);
++ ret_val = -1;
++ break;
++ }
++ }
++
++ return(ret_val);
++}
++
++
++int cpmac_drv_rx_teardown(HAL_FUNCTIONS *p_hal_funcs,
++ HAL_DEVICE *p_hal_dev,
++ unsigned int flags)
++{
++ int ret_val = 0;
++
++ if(p_hal_funcs->ChannelTeardown(p_hal_dev, 0, flags) != 0)
++ {
++ errPrint("Error in tearing down channel %d for RX.\n", 0);
++ ret_val = -1;
++ }
++
++ return(ret_val);
++}
++
++int cpmac_drv_stop(CPMAC_DRV_HAL_INFO_T *p_drv_hal,
++ CPMAC_TX_CHAN_INFO_T *p_tx_chan_info,
++ CPMAC_RX_CHAN_INFO_T *p_rx_chan_info,
++ unsigned int flags)
++{
++ HAL_DEVICE *p_hal_dev = p_drv_hal->hal_dev;
++ HAL_FUNCTIONS *p_hal_funcs = p_drv_hal->hal_funcs;
++ int ret_val = 0;
++
++ if(flags & CHAN_TEARDOWN)
++ {
++ unsigned int chan_flags = 0;
++
++ if(flags & FREE_BUFFER) chan_flags |= 0x4; /* full tear down */
++ if(flags & BLOCKING) chan_flags |= 0x8; /* blocking call */
++
++ dbgPrint("The teardown flags are %d.\n", flags);
++ dbgPrint("The teardown chan flags are %d.\n", chan_flags);
++
++ if(cpmac_drv_tx_teardown(p_hal_funcs, p_hal_dev,
++ p_tx_chan_info, chan_flags | 0x1) != 0)
++ {
++ ret_val = -1;
++ errPrint("The tx channel teardown failed.\n");
++ }
++ else if(cpmac_drv_rx_teardown(p_hal_funcs, p_hal_dev, chan_flags | 0x2) != 0)
++ {
++ ret_val = -1;
++ errPrint("The rx channel teardown failed.\n");
++ }
++ else
++ {
++ ;
++ }
++ }
++
++ if(ret_val == 0)
++ {
++ int close_flags = 1;
++
++ if(flags & FREE_BUFFER) close_flags = 2;
++// if(flags & COMPLETE) close_flags = 3;
++
++ if(p_hal_funcs->Close(p_hal_dev, close_flags) != 0)
++ {
++ ret_val = -1;
++ }
++ }
++
++ return(ret_val);
++}
++
++int cpmac_drv_init_module(CPMAC_DRV_HAL_INFO_T *p_drv_hal, OS_DEVICE *p_os_dev, int inst)
++{
++ int ret_val = -1;
++ int hal_func_size;
++
++ dbgPrint("Entering the CpmacInitModule for the inst %d \n", inst);
++
++ if((p_drv_hal->os_funcs = kmalloc(sizeof(OS_FUNCTIONS), GFP_KERNEL)) == NULL)
++ {
++ errPrint("Failed to allocate memory for OS_FUNCTIONS.\n");
++ }
++ else if(load_os_funcs(p_drv_hal->os_funcs) != 0)
++ {
++ errPrint("Failed to load OS funcs.\n");
++ os_free(p_drv_hal->os_funcs);
++ }
++ else if(halCpmacInitModule(&p_drv_hal->hal_dev, p_os_dev,
++ &p_drv_hal->hal_funcs, p_drv_hal->os_funcs,
++ sizeof(*p_drv_hal->os_funcs),
++ &hal_func_size, inst) != 0)
++ {
++ errPrint("halCpmacInitModule failed for inst %d \n", inst);
++ os_free(p_drv_hal->os_funcs);
++ }
++ else if(p_drv_hal->hal_funcs->Probe(p_drv_hal->hal_dev) != 0)
++ {
++ errPrint("halCpmacProbe failed for inst %d \n", inst);
++ os_free(p_drv_hal->os_funcs);
++ }
++ else
++ {
++ /* every thing went well. */
++ ret_val = 0;
++ }
++
++ return (ret_val);
++}
+diff -urN linux.old/drivers/net/avalanche_cpmac/cpmacHalLx.h linux.dev/drivers/net/avalanche_cpmac/cpmacHalLx.h
+--- linux.old/drivers/net/avalanche_cpmac/cpmacHalLx.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/cpmacHalLx.h 2005-07-12 02:48:42.044593000 +0200
+@@ -0,0 +1,51 @@
++/******************************************************************************
++ * FILE PURPOSE: CPMAC Linux Device Driver HAL support Header
++ ******************************************************************************
++ * FILE NAME: cpmacHalVx.h
++ *
++ * DESCRIPTION: CPMAC Linux Device Driver Header
++ *
++ * REVISION HISTORY:
++ *
++ * Date Description Author
++ *-----------------------------------------------------------------------------
++ * 27 Nov 2002 Initial Creation Suraj S Iyer
++ * 09 Jun 2003 Updates for GA Suraj S Iyer
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++#ifndef __CPMAC_HAL_LX_H
++#define __CPMAC_HAL_LX_H
++
++
++typedef struct net_device OS_DEVICE;
++typedef struct sk_buff OS_RECEIVEINFO;
++typedef struct sk_buff OS_SENDINFO;
++
++#ifdef DEBUG
++typedef void HAL_RECEIVEINFO;
++typedef void HAL_DEVICE;
++typedef void OS_SETUP;
++#endif
++
++#define OS_SETUP void
++#define HAL_DEVICE void
++#define HAL_RECEIVEINFO void
++
++#define _CPHAL_CPMAC
++
++#include "cpswhal_cpmac.h"
++#include "cpmac.h"
++
++int cpmac_drv_start(CPMAC_DRV_HAL_INFO_T *, CPMAC_TX_CHAN_INFO_T*,
++ CPMAC_RX_CHAN_INFO_T *, unsigned int);
++int cpmac_drv_cleanup(CPMAC_DRV_HAL_INFO_T *);
++int cpmac_drv_init(CPMAC_DRV_HAL_INFO_T*);
++int cpmac_drv_close(CPMAC_DRV_HAL_INFO_T*);
++int cpmac_drv_open(CPMAC_DRV_HAL_INFO_T*);
++int cpmac_drv_init_module(CPMAC_DRV_HAL_INFO_T*, OS_DEVICE*, int);
++int cpmac_drv_stop(CPMAC_DRV_HAL_INFO_T *p_drv_hal,CPMAC_TX_CHAN_INFO_T *p_tx_chan_info,
++ CPMAC_RX_CHAN_INFO_T *p_rx_chan_info,unsigned int flags);
++
++#endif
+diff -urN linux.old/drivers/net/avalanche_cpmac/cpmac_reg.h linux.dev/drivers/net/avalanche_cpmac/cpmac_reg.h
+--- linux.old/drivers/net/avalanche_cpmac/cpmac_reg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/cpmac_reg.h 2005-07-12 02:48:42.045593000 +0200
+@@ -0,0 +1,406 @@
++/****************************************************************************
++ TNETD73xx Software Support
++ Copyright(c) 2000, Texas Instruments Incorporated. All Rights Reserved.
++
++ FILE: cpmac_reg.h Register definitions for the CPMAC module
++
++ DESCRIPTION:
++ This include file contains register definitions for the
++ CPMAC module.
++
++ HISTORY:
++ 15Nov00 BEGR Original version written
++ 30May02 MICK Added bits for Int Vector
++ 19Sep02 MICK Added INT_ACK per Channel
++ 08Nov02 GDUN Updated to use base
++ 12Nov02 MICK Incorporated into CPHAL
++*****************************************************************************/
++#ifndef _INC_CPMAC_REG
++#define _INC_CPMAC_REG
++
++#ifndef MEM_PTR
++#define MEM_PTR volatile bit32u *
++#endif
++
++/***************************************************************************
++ *
++ * C P M A C M E M O R Y M A P
++ *
++ **************************************************************************/
++
++#define pCPMAC_TX_IDVER(base) ((MEM_PTR)(base+0x000))
++#define CPMAC_TX_IDVER(base) (*pCPMAC_TX_IDVER(base))
++#define pCPMAC_TX_CONTROL(base) ((MEM_PTR)(base+0x004))
++#define CPMAC_TX_CONTROL(base) (*pCPMAC_TX_CONTROL(base))
++#define pCPMAC_TX_TEARDOWN(base) ((MEM_PTR)(base+0x008))
++#define CPMAC_TX_TEARDOWN(base) (*pCPMAC_TX_TEARDOWN(base))
++#define pCPMAC_RX_IDVER(base) ((MEM_PTR)(base+0x010))
++#define CPMAC_RX_IDVER(base) (*pCPMAC_RX_IDVER(base))
++#define pCPMAC_RX_CONTROL(base) ((MEM_PTR)(base+0x014))
++#define CPMAC_RX_CONTROL(base) (*pCPMAC_RX_CONTROL(base))
++#define pCPMAC_RX_TEARDOWN(base) ((MEM_PTR)(base+0x018))
++#define CPMAC_RX_TEARDOWN(base) (*pCPMAC_RX_TEARDOWN(base))
++#define pCPMAC_RX_MBP_ENABLE(base) ((MEM_PTR)(base+0x100))
++#define CPMAC_RX_MBP_ENABLE(base) (*pCPMAC_RX_MBP_ENABLE(base))
++#define pCPMAC_RX_UNICAST_SET(base) ((MEM_PTR)(base+0x104))
++#define CPMAC_RX_UNICAST_SET(base) (*pCPMAC_RX_UNICAST_SET(base))
++#define pCPMAC_RX_UNICAST_CLEAR(base) ((MEM_PTR)(base+0x108))
++#define CPMAC_RX_UNICAST_CLEAR(base) (*pCPMAC_RX_UNICAST_CLEAR(base))
++#define pCPMAC_RX_MAXLEN(base) ((MEM_PTR)(base+0x10C))
++#define CPMAC_RX_MAXLEN(base) (*pCPMAC_RX_MAXLEN(base))
++#define pCPMAC_RX_BUFFER_OFFSET(base) ((MEM_PTR)(base+0x110))
++#define CPMAC_RX_BUFFER_OFFSET(base) (*pCPMAC_RX_BUFFER_OFFSET(base))
++#define pCPMAC_RX_FILTERLOWTHRESH(base) ((MEM_PTR)(base+0x114))
++#define CPMAC_RX_FILTERLOWTHRESH(base) (*pCPMAC_RX_FILTERLOWTHRESH(base))
++#define pCPMAC_RX0_FLOWTHRESH(base) ((MEM_PTR)(base+0x120))
++#define CPMAC_RX0_FLOWTHRESH(base) (*pCPMAC_RX0_FLOWTHRESH(base))
++#define pCPMAC_RX1_FLOWTHRESH(base) ((MEM_PTR)(base+0x124))
++#define CPMAC_RX1_FLOWTHRESH(base) (*pCPMAC_RX1_FLOWTHRESH(base))
++#define pCPMAC_RX2_FLOWTHRESH(base) ((MEM_PTR)(base+0x128))
++#define CPMAC_RX2_FLOWTHRESH(base) (*pCPMAC_RX2_FLOWTHRESH(base))
++#define pCPMAC_RX3_FLOWTHRESH(base) ((MEM_PTR)(base+0x12C))
++#define CPMAC_RX3_FLOWTHRESH(base) (*pCPMAC_RX3_FLOWTHRESH(base))
++#define pCPMAC_RX4_FLOWTHRESH(base) ((MEM_PTR)(base+0x130))
++#define CPMAC_RX4_FLOWTHRESH(base) (*pCPMAC_RX4_FLOWTHRESH(base))
++#define pCPMAC_RX5_FLOWTHRESH(base) ((MEM_PTR)(base+0x134))
++#define CPMAC_RX5_FLOWTHRESH(base) (*pCPMAC_RX5_FLOWTHRESH(base))
++#define pCPMAC_RX6_FLOWTHRESH(base) ((MEM_PTR)(base+0x138))
++#define CPMAC_RX6_FLOWTHRESH(base) (*pCPMAC_RX6_FLOWTHRESH(base))
++#define pCPMAC_RX7_FLOWTHRESH(base) ((MEM_PTR)(base+0x13C))
++#define CPMAC_RX7_FLOWTHRESH(base) (*pCPMAC_RX7_FLOWTHRESH(base))
++#define pCPMAC_RX0_FREEBUFFER(base) ((MEM_PTR)(base+0x140))
++#define CPMAC_RX0_FREEBUFFER(base) (*pCPMAC_RX0_FREEBUFFER(base))
++#define pCPMAC_RX1_FREEBUFFER(base) ((MEM_PTR)(base+0x144))
++#define CPMAC_RX1_FREEBUFFER(base) (*pCPMAC_RX1_FREEBUFFER(base))
++#define pCPMAC_RX2_FREEBUFFER(base) ((MEM_PTR)(base+0x148))
++#define CPMAC_RX2_FREEBUFFER(base) (*pCPMAC_RX2_FREEBUFFER(base))
++#define pCPMAC_RX3_FREEBUFFER(base) ((MEM_PTR)(base+0x14C))
++#define CPMAC_RX3_FREEBUFFER(base) (*pCPMAC_RX3_FREEBUFFER(base))
++#define pCPMAC_RX4_FREEBUFFER(base) ((MEM_PTR)(base+0x150))
++#define CPMAC_RX4_FREEBUFFER(base) (*pCPMAC_RX4_FREEBUFFER(base))
++#define pCPMAC_RX5_FREEBUFFER(base) ((MEM_PTR)(base+0x154))
++#define CPMAC_RX5_FREEBUFFER(base) (*pCPMAC_RX5_FREEBUFFER(base))
++#define pCPMAC_RX6_FREEBUFFER(base) ((MEM_PTR)(base+0x158))
++#define CPMAC_RX6_FREEBUFFER(base) (*pCPMAC_RX6_FREEBUFFER(base))
++#define pCPMAC_RX7_FREEBUFFER(base) ((MEM_PTR)(base+0x15C))
++#define CPMAC_RX7_FREEBUFFER(base) (*pCPMAC_RX7_FREEBUFFER(base))
++#define pCPMAC_MACCONTROL(base) ((MEM_PTR)(base+0x160))
++#define CPMAC_MACCONTROL(base) (*pCPMAC_MACCONTROL(base))
++#define pCPMAC_MACSTATUS(base) ((MEM_PTR)(base+0x164))
++#define CPMAC_MACSTATUS(base) (*pCPMAC_MACSTATUS(base))
++#define pCPMAC_EMCONTROL(base) ((MEM_PTR)(base+0x168))
++#define CPMAC_EMCONTROL(base) (*pCPMAC_EMCONTROL(base))
++#define pCPMAC_TX_INTSTAT_RAW(base) ((MEM_PTR)(base+0x170))
++#define CPMAC_TX_INTSTAT_RAW(base) (*pCPMAC_TX_INTSTAT_RAW(base))
++#define pCPMAC_TX_INTSTAT_MASKED(base) ((MEM_PTR)(base+0x174))
++#define CPMAC_TX_INTSTAT_MASKED(base) (*pCPMAC_TX_INTSTAT_MASKED(base))
++#define pCPMAC_TX_INTMASK_SET(base) ((MEM_PTR)(base+0x178))
++#define CPMAC_TX_INTMASK_SET(base) (*pCPMAC_TX_INTMASK_SET(base))
++#define pCPMAC_TX_INTMASK_CLEAR(base) ((MEM_PTR)(base+0x17C))
++#define CPMAC_TX_INTMASK_CLEAR(base) (*pCPMAC_TX_INTMASK_CLEAR(base))
++#define pCPMAC_MAC_IN_VECTOR(base) ((MEM_PTR)(base+0x180))
++#define CPMAC_MAC_IN_VECTOR(base) (*pCPMAC_MAC_IN_VECTOR(base))
++#define pCPMAC_MAC_EOI_VECTOR(base) ((MEM_PTR)(base+0x184))
++#define CPMAC_MAC_EOI_VECTOR(base) (*pCPMAC_MAC_EOI_VECTOR(base))
++#define pCPMAC_RX_INTSTAT_RAW(base) ((MEM_PTR)(base+0x190))
++#define CPMAC_RX_INTSTAT_RAW(base) (*pCPMAC_RX_INTSTAT_RAW(base))
++#define pCPMAC_RX_INTSTAT_MASKED(base) ((MEM_PTR)(base+0x194))
++#define CPMAC_RX_INTSTAT_MASKED(base) (*pCPMAC_RX_INTSTAT_MASKED(base))
++#define pCPMAC_RX_INTMASK_SET(base) ((MEM_PTR)(base+0x198))
++#define CPMAC_RX_INTMASK_SET(base) (*pCPMAC_RX_INTMASK_SET(base))
++#define pCPMAC_RX_INTMASK_CLEAR(base) ((MEM_PTR)(base+0x19C))
++#define CPMAC_RX_INTMASK_CLEAR(base) (*pCPMAC_RX_INTMASK_CLEAR(base))
++#define pCPMAC_MAC_INTSTAT_RAW(base) ((MEM_PTR)(base+0x1A0))
++#define CPMAC_MAC_INTSTAT_RAW(base) (*pCPMAC_MAC_INTSTAT_RAW(base))
++#define pCPMAC_MAC_INTSTAT_MASKED(base) ((MEM_PTR)(base+0x1A4))
++#define CPMAC_MAC_INTSTAT_MASKED(base) (*pCPMAC_MAC_INTSTAT_MASKED(base))
++#define pCPMAC_MAC_INTMASK_SET(base) ((MEM_PTR)(base+0x1A8))
++#define CPMAC_MAC_INTMASK_SET(base) (*pCPMAC_MAC_INTMASK_SET(base))
++#define pCPMAC_MAC_INTMASK_CLEAR(base) ((MEM_PTR)(base+0x1AC))
++#define CPMAC_MAC_INTMASK_CLEAR(base) (*pCPMAC_MAC_INTMASK_CLEAR(base))
++#define pCPMAC_MACADDRLO_0(base) ((MEM_PTR)(base+0x1B0))
++#define CPMAC_MACADDRLO_0(base) (*pCPMAC_MACADDRLO_0(base))
++#define pCPMAC_MACADDRLO_1(base) ((MEM_PTR)(base+0x1B4))
++#define CPMAC_MACADDRLO_1(base) (*pCPMAC_MACADDRLO_1(base))
++#define pCPMAC_MACADDRLO_2(base) ((MEM_PTR)(base+0x1B8))
++#define CPMAC_MACADDRLO_2(base) (*pCPMAC_MACADDRLO_2(base))
++#define pCPMAC_MACADDRLO_3(base) ((MEM_PTR)(base+0x1BC))
++#define CPMAC_MACADDRLO_3(base) (*pCPMAC_MACADDRLO_3(base))
++#define pCPMAC_MACADDRLO_4(base) ((MEM_PTR)(base+0x1C0))
++#define CPMAC_MACADDRLO_4(base) (*pCPMAC_MACADDRLO_4(base))
++#define pCPMAC_MACADDRLO_5(base) ((MEM_PTR)(base+0x1C4))
++#define CPMAC_MACADDRLO_5(base) (*pCPMAC_MACADDRLO_5(base))
++#define pCPMAC_MACADDRLO_6(base) ((MEM_PTR)(base+0x1C8))
++#define CPMAC_MACADDRLO_6(base) (*pCPMAC_MACADDRLO_6(base))
++#define pCPMAC_MACADDRLO_7(base) ((MEM_PTR)(base+0x1CC))
++#define CPMAC_MACADDRLO_7(base) (*pCPMAC_MACADDRLO_7(base))
++#define pCPMAC_MACADDRMID(base) ((MEM_PTR)(base+0x1D0))
++#define CPMAC_MACADDRMID(base) (*pCPMAC_MACADDRMID(base))
++#define pCPMAC_MACADDRHI(base) ((MEM_PTR)(base+0x1D4))
++#define CPMAC_MACADDRHI(base) (*pCPMAC_MACADDRHI(base))
++#define pCPMAC_MACHASH1(base) ((MEM_PTR)(base+0x1D8))
++#define CPMAC_MACHASH1(base) (*pCPMAC_MACHASH1(base))
++#define pCPMAC_MACHASH2(base) ((MEM_PTR)(base+0x1DC))
++#define CPMAC_MACHASH2(base) (*pCPMAC_MACHASH2(base))
++#define pCPMAC_BOFFTEST(base) ((MEM_PTR)(base+0x1E0))
++#define CPMAC_BOFFTEST(base) (*pCPMAC_BOFFTEST(base))
++#define pCPMAC_PACTEST(base) ((MEM_PTR)(base+0x1E4))
++#define CPMAC_PACTEST(base) (*pCPMAC_PACTEST(base))
++#define pCPMAC_RXPAUSE(base) ((MEM_PTR)(base+0x1E8))
++#define CPMAC_RXPAUSE(base) (*pCPMAC_RXPAUSE(base))
++#define pCPMAC_TXPAUSE(base) ((MEM_PTR)(base+0x1EC))
++#define CPMAC_TXPAUSE(base) (*pCPMAC_TXPAUSE(base))
++/* STATISTICS */
++#define pCPMAC_RXGOODFRAMES(base) ((MEM_PTR)(base+0x200))
++#define CPMAC_RXGOODFRAMES(base) (*pCPMAC_RXGOODFRAMES(base))
++#define pCPMAC_RXBROADCASTFRAMES(base) ((MEM_PTR)(base+0x204))
++#define CPMAC_RXBROADCASTFRAMES(base) (*pCPMAC_RXBROADCASTFRAMES(base))
++#define pCPMAC_RXMULTICASTFRAMES(base) ((MEM_PTR)(base+0x208))
++#define CPMAC_RXMULTICASTFRAMES(base) (*pCPMAC_RXMULTICASTFRAMES(base))
++#define pCPMAC_RXPAUSEFRAMES(base) ((MEM_PTR)(base+0x20C))
++#define CPMAC_RXPAUSEFRAMES(base) (*pCPMAC_RXPAUSEFRAMES(base))
++#define pCPMAC_RXCRCERRORS(base) ((MEM_PTR)(base+0x210))
++#define CPMAC_RXCRCERRORS(base) (*pCPMAC_RXCRCERRORS(base))
++#define pCPMAC_RXALIGNCODEERRORS(base) ((MEM_PTR)(base+0x214))
++#define CPMAC_RXALIGNCODEERRORS(base) (*pCPMAC_RXALIGNCODEERRORS(base))
++#define pCPMAC_RXOVERSIZEDFRAMES(base) ((MEM_PTR)(base+0x218))
++#define CPMAC_RXOVERSIZEDFRAMES(base) (*pCPMAC_RXOVERSIZEDFRAMES(base))
++#define pCPMAC_RXJABBERFRAMES(base) ((MEM_PTR)(base+0x21C))
++#define CPMAC_RXJABBERFRAMES(base) (*pCPMAC_RXJABBERFRAMES(base))
++#define pCPMAC_RXUNDERSIZEDFRAMES(base) ((MEM_PTR)(base+0x220))
++#define CPMAC_RXUNDERSIZEDFRAMES(base) (*pCPMAC_RXUNDERSIZEDFRAMES(base))
++#define pCPMAC_RXFRAGMENTS(base) ((MEM_PTR)(base+0x224))
++#define CPMAC_RXFRAGMENTS(base) (*pCPMAC_RXFRAGMENTS(base))
++#define pCPMAC_RXFILTEREDFRAMES(base) ((MEM_PTR)(base+0x228))
++#define CPMAC_RXFILTEREDFRAMES(base) (*pCPMAC_RXFILTEREDFRAMES(base))
++#define pCPMAC_RXQOSFILTEREDFRAMES(base) ((MEM_PTR)(base+0x22C))
++#define CPMAC_RXQOSFILTEREDFRAMES(base) (*pCPMAC_RXQOSFILTEREDFRAMES(base))
++#define pCPMAC_RXOCTETS(base) ((MEM_PTR)(base+0x230))
++#define CPMAC_RXOCTETS(base) (*pCPMAC_RXOCTETS(base))
++#define pCPMAC_TXGOODFRAMES(base) ((MEM_PTR)(base+0x234))
++#define CPMAC_TXGOODFRAMES(base) (*pCPMAC_TXGOODFRAMES(base))
++#define pCPMAC_TXBROADCASTFRAMES(base) ((MEM_PTR)(base+0x238))
++#define CPMAC_TXBROADCASTFRAMES(base) (*pCPMAC_TXBROADCASTFRAMES(base))
++#define pCPMAC_TXMULTICASTFRAMES(base) ((MEM_PTR)(base+0x23C))
++#define CPMAC_TXMULTICASTFRAMES(base) (*pCPMAC_TXMULTICASTFRAMES(base))
++#define pCPMAC_TXPAUSEFRAMES(base) ((MEM_PTR)(base+0x240))
++#define CPMAC_TXPAUSEFRAMES(base) (*pCPMAC_TXPAUSEFRAMES(base))
++#define pCPMAC_TXDEFERREDFRAMES(base) ((MEM_PTR)(base+0x244))
++#define CPMAC_TXDEFERREDFRAMES(base) (*pCPMAC_TXDEFERREDFRAMES(base))
++#define pCPMAC_TXCOLLISIONFRAMES(base) ((MEM_PTR)(base+0x248))
++#define CPMAC_TXCOLLISIONFRAMES(base) (*pCPMAC_TXCOLLISIONFRAMES(base))
++#define pCPMAC_TXSINGLECOLLFRAMES(base) ((MEM_PTR)(base+0x24C))
++#define CPMAC_TXSINGLECOLLFRAMES(base) (*pCPMAC_TXSINGLECOLLFRAMES(base))
++#define pCPMAC_TXMULTCOLLFRAMES(base) ((MEM_PTR)(base+0x250))
++#define CPMAC_TXMULTCOLLFRAMES(base) (*pCPMAC_TXMULTCOLLFRAMES(base))
++#define pCPMAC_TXEXCESSIVECOLLISIONS(base) ((MEM_PTR)(base+0x254))
++#define CPMAC_TXEXCESSIVECOLLISIONS(base) (*pCPMAC_TXEXCESSIVECOLLISIONS(base))
++#define pCPMAC_TXLATECOLLISIONS(base) ((MEM_PTR)(base+0x258))
++#define CPMAC_TXLATECOLLISIONS(base) (*pCPMAC_TXLATECOLLISIONS(base))
++#define pCPMAC_TXUNDERRUN(base) ((MEM_PTR)(base+0x25C))
++#define CPMAC_TXUNDERRUN(base) (*pCPMAC_TXUNDERRUN(base))
++#define pCPMAC_TXCARRIERSENSEERRORS(base) ((MEM_PTR)(base+0x260))
++#define CPMAC_TXCARRIERSENSEERRORS(base) (*pCPMAC_TXCARRIERSENSEERRORS(base))
++#define pCPMAC_TXOCTETS(base) ((MEM_PTR)(base+0x264))
++#define CPMAC_TXOCTETS(base) (*pCPMAC_TXOCTETS(base))
++#define pCPMAC_64OCTETFRAMES(base) ((MEM_PTR)(base+0x268))
++#define CPMAC_64OCTETFRAMES(base) (*pCPMAC_64OCTETFRAMES(base))
++#define pCPMAC_65T127OCTETFRAMES(base) ((MEM_PTR)(base+0x26C))
++#define CPMAC_65T127OCTETFRAMES(base) (*pCPMAC_65T127OCTETFRAMES(base))
++#define pCPMAC_128T255OCTETFRAMES(base) ((MEM_PTR)(base+0x270))
++#define CPMAC_128T255OCTETFRAMES(base) (*pCPMAC_128T255OCTETFRAMES(base))
++#define pCPMAC_256T511OCTETFRAMES(base) ((MEM_PTR)(base+0x274))
++#define CPMAC_256T511OCTETFRAMES(base) (*pCPMAC_256T511OCTETFRAMES(base))
++#define pCPMAC_512T1023OCTETFRAMES(base) ((MEM_PTR)(base+0x278))
++#define CPMAC_512T1023OCTETFRAMES(base) (*pCPMAC_512T1023OCTETFRAMES(base))
++#define pCPMAC_1024TUPOCTETFRAMES(base) ((MEM_PTR)(base+0x27C))
++#define CPMAC_1024TUPOCTETFRAMES(base) (*pCPMAC_1024TUPOCTETFRAMES(base))
++#define pCPMAC_NETOCTETS(base) ((MEM_PTR)(base+0x280))
++#define CPMAC_NETOCTETS(base) (*pCPMAC_NETOCTETS(base))
++#define pCPMAC_RXSOFOVERRUNS(base) ((MEM_PTR)(base+0x284))
++#define CPMAC_RXSOFOVERRUNS(base) (*pCPMAC_RXSOFOVERRUNS(base))
++#define pCPMAC_RXMOFOVERRUNS(base) ((MEM_PTR)(base+0x288))
++#define CPMAC_RXMOFOVERRUNS(base) (*pCPMAC_RXMOFOVERRUNS(base))
++#define pCPMAC_RXDMAOVERRUNS(base) ((MEM_PTR)(base+0x28C))
++#define CPMAC_RXDMAOVERRUNS(base) (*pCPMAC_RXDMAOVERRUNS(base))
++
++#define CPMAC_TX_HDP(base,ch) (*(MEM_PTR)(base+0x600+(4*ch)))
++#define pCPMAC_TX0_HDP(base) ((MEM_PTR)(base+0x600))
++#define CPMAC_TX0_HDP(base) (*pCPMAC_TX0_HDP(base))
++#define pCPMAC_TX1_HDP(base) ((MEM_PTR)(base+0x604))
++#define CPMAC_TX1_HDP(base) (*pCPMAC_TX1_HDP(base))
++#define pCPMAC_TX2_HDP(base) ((MEM_PTR)(base+0x608))
++#define CPMAC_TX2_HDP(base) (*pCPMAC_TX2_HDP(base))
++#define pCPMAC_TX3_HDP(base) ((MEM_PTR)(base+0x60C))
++#define CPMAC_TX3_HDP(base) (*pCPMAC_TX3_HDP(base))
++#define pCPMAC_TX4_HDP(base) ((MEM_PTR)(base+0x610))
++#define CPMAC_TX4_HDP(base) (*pCPMAC_TX4_HDP(base))
++#define pCPMAC_TX5_HDP(base) ((MEM_PTR)(base+0x614))
++#define CPMAC_TX5_HDP(base) (*pCPMAC_TX5_HDP(base))
++#define pCPMAC_TX6_HDP(base) ((MEM_PTR)(base+0x618))
++#define CPMAC_TX6_HDP(base) (*pCPMAC_TX6_HDP(base))
++#define pCPMAC_TX7_HDP(base) ((MEM_PTR)(base+0x61C))
++#define CPMAC_TX7_HDP(base) (*pCPMAC_TX7_HDP(base))
++#define CPMAC_RX_HDP(base,ch) (*(MEM_PTR)(base+0x620+(4*ch)))
++#define pCPMAC_RX0_HDP(base) ((MEM_PTR)(base+0x620))
++#define CPMAC_RX0_HDP(base) (*pCPMAC_RX0_HDP(base))
++#define pCPMAC_RX1_HDP(base) ((MEM_PTR)(base+0x624))
++#define CPMAC_RX1_HDP(base) (*pCPMAC_RX1_HDP(base))
++#define pCPMAC_RX2_HDP(base) ((MEM_PTR)(base+0x628))
++#define CPMAC_RX2_HDP(base) (*pCPMAC_RX2_HDP(base))
++#define pCPMAC_RX3_HDP(base) ((MEM_PTR)(base+0x62C))
++#define CPMAC_RX3_HDP(base) (*pCPMAC_RX3_HDP(base))
++#define pCPMAC_RX4_HDP(base) ((MEM_PTR)(base+0x630))
++#define CPMAC_RX4_HDP(base) (*pCPMAC_RX4_HDP(base))
++#define pCPMAC_RX5_HDP(base) ((MEM_PTR)(base+0x634))
++#define CPMAC_RX5_HDP(base) (*pCPMAC_RX5_HDP(base))
++#define pCPMAC_RX6_HDP(base) ((MEM_PTR)(base+0x638))
++#define CPMAC_RX6_HDP(base) (*pCPMAC_RX6_HDP(base))
++#define pCPMAC_RX7_HDP(base) ((MEM_PTR)(base+0x63C))
++#define CPMAC_RX7_HDP(base) (*pCPMAC_RX7_HDP(base))
++
++
++#define CPMAC_TX_INT_ACK(base,ch) (*(MEM_PTR)(base+0x640+(4*ch)))
++
++#define pCPMAC_TX0_INT_ACK(base) ((MEM_PTR)(base+0x640))
++#define CPMAC_TX0_INT_ACK(base) (*pCPMAC_TX0_INT_ACK(base))
++#define pCPMAC_TX1_INT_ACK(base) ((MEM_PTR)(base+0x644))
++#define CPMAC_TX1_INT_ACK(base) (*pCPMAC_TX1_INT_ACK(base))
++#define pCPMAC_TX2_INT_ACK(base) ((MEM_PTR)(base+0x648))
++#define CPMAC_TX2_INT_ACK(base) (*pCPMAC_TX2_INT_ACK(base))
++#define pCPMAC_TX3_INT_ACK(base) ((MEM_PTR)(base+0x64C))
++#define CPMAC_TX3_INT_ACK(base) (*pCPMAC_TX3_INT_ACK(base))
++#define pCPMAC_TX4_INT_ACK(base) ((MEM_PTR)(base+0x650))
++#define CPMAC_TX4_INT_ACK(base) (*pCPMAC_TX4_INT_ACK(base))
++#define pCPMAC_TX5_INT_ACK(base) ((MEM_PTR)(base+0x654))
++#define CPMAC_TX5_INT_ACK(base) (*pCPMAC_TX5_INT_ACK(base))
++#define pCPMAC_TX6_INT_ACK(base) ((MEM_PTR)(base+0x658))
++#define CPMAC_TX6_INT_ACK(base) (*pCPMAC_TX6_INT_ACK(base))
++#define pCPMAC_TX7_INT_ACK(base) ((MEM_PTR)(base+0x65C))
++#define CPMAC_TX7_INT_ACK(base) (*pCPMAC_TX7_INT_ACK(base))
++#define CPMAC_RX_INT_ACK(base,ch) (*(MEM_PTR)(base+0x660+(4*ch)))
++
++#define pCPMAC_RX0_INT_ACK(base) ((MEM_PTR)(base+0x660))
++#define CPMAC_RX0_INT_ACK(base) (*pCPMAC_RX0_INT_ACK(base))
++#define pCPMAC_RX1_INT_ACK(base) ((MEM_PTR)(base+0x664))
++#define CPMAC_RX1_INT_ACK(base) (*pCPMAC_RX1_INT_ACK(base))
++#define pCPMAC_RX2_INT_ACK(base) ((MEM_PTR)(base+0x668))
++#define CPMAC_RX2_INT_ACK(base) (*pCPMAC_RX2_INT_ACK(base))
++#define pCPMAC_RX3_INT_ACK(base) ((MEM_PTR)(base+0x66C))
++#define CPMAC_RX3_INT_ACK(base) (*pCPMAC_RX3_INT_ACK(base))
++#define pCPMAC_RX4_INT_ACK(base) ((MEM_PTR)(base+0x670))
++#define CPMAC_RX4_INT_ACK(base) (*pCPMAC_RX4_INT_ACK(base))
++#define pCPMAC_RX5_INT_ACK(base) ((MEM_PTR)(base+0x674))
++#define CPMAC_RX5_INT_ACK(base) (*pCPMAC_RX5_INT_ACK(base))
++#define pCPMAC_RX6_INT_ACK(base) ((MEM_PTR)(base+0x678))
++#define CPMAC_RX6_INT_ACK(base) (*pCPMAC_RX6_INT_ACK(base))
++#define pCPMAC_RX7_INT_ACK(base) ((MEM_PTR)(base+0x67C))
++#define CPMAC_RX7_INT_ACK(base) (*pCPMAC_RX7_INT_ACK(base))
++
++/****************************************************************************/
++/* */
++/* R E G I S T E R B I T D E F I N I T I O N S */
++/* */
++/****************************************************************************/
++
++/* TX_CONTROL */
++
++#define TX_EN (1 << 0)
++
++/* RX_CONTROL */
++
++#define RX_EN (1 << 0)
++
++/* RX_MBP_ENABLE */
++
++#define RX_PASS_CRC (1 << 30)
++#define RX_QOS_EN (1 << 29)
++#define RX_NO_CHAIN (1 << 28)
++
++#define RX_CMF_EN (1 << 24)
++#define RX_CSF_EN (1 << 23)
++#define RX_CEF_EN (1 << 22)
++#define RX_CAF_EN (1 << 21)
++
++#define RX_PROM_CH(n) (n << 16)
++#define RX_PROM_CH_MASK RX_PROM_CH(7)
++#define RX_PROM_CH_7 RX_PROM_CH(7)
++#define RX_PROM_CH_6 RX_PROM_CH(6)
++#define RX_PROM_CH_5 RX_PROM_CH(5)
++#define RX_PROM_CH_4 RX_PROM_CH(4)
++#define RX_PROM_CH_3 RX_PROM_CH(3)
++#define RX_PROM_CH_2 RX_PROM_CH(2)
++#define RX_PROM_CH_1 RX_PROM_CH(1)
++#define RX_PROM_CH_0 RX_PROM_CH(0)
++
++#define RX_BROAD_EN (1 << 13)
++
++#define RX_BROAD_CH(n) (n << 8)
++#define RX_BROAD_CH_MASK RX_BROAD_CH(7)
++#define RX_BROAD_CH_7 RX_BROAD_CH(7)
++#define RX_BROAD_CH_6 RX_BROAD_CH(6)
++#define RX_BROAD_CH_5 RX_BROAD_CH(5)
++#define RX_BROAD_CH_4 RX_BROAD_CH(4)
++#define RX_BROAD_CH_3 RX_BROAD_CH(3)
++#define RX_BROAD_CH_2 RX_BROAD_CH(2)
++#define RX_BROAD_CH_1 RX_BROAD_CH(1)
++#define RX_BROAD_CH_0 RX_BROAD_CH(0)
++
++#define RX_MULT_EN (1 << 5)
++
++#define RX_MULT_CH(n) (n << 0)
++#define RX_MULT_CH_MASK RX_MULT_CH(7)
++#define RX_MULT_CH_7 RX_MULT_CH(7)
++#define RX_MULT_CH_6 RX_MULT_CH(6)
++#define RX_MULT_CH_5 RX_MULT_CH(5)
++#define RX_MULT_CH_4 RX_MULT_CH(4)
++#define RX_MULT_CH_3 RX_MULT_CH(3)
++#define RX_MULT_CH_2 RX_MULT_CH(2)
++#define RX_MULT_CH_1 RX_MULT_CH(1)
++#define RX_MULT_CH_0 RX_MULT_CH(0)
++
++
++
++/* RX_UNICAST_SET */
++
++#define RX_CH7_EN (1 << 7)
++#define RX_CH6_EN (1 << 6)
++#define RX_CH5_EN (1 << 5)
++#define RX_CH4_EN (1 << 4)
++#define RX_CH3_EN (1 << 3)
++#define RX_CH2_EN (1 << 2)
++#define RX_CH1_EN (1 << 1)
++#define RX_CH0_EN (1 << 0)
++
++
++
++/* MAC control */
++#define TX_PTYPE (1 << 9)
++#define TX_PACE (1 << 6)
++#define MII_EN (1 << 5)
++#define TX_FLOW_EN (1 << 4)
++#define RX_FLOW_EN (1 << 3)
++#define MTEST (1 << 2)
++#define CTRL_LOOPBACK (1 << 1)
++#define FULLDUPLEX (1 << 0)
++
++
++/* IntVec definitions */
++#define MAC_IN_VECTOR_STATUS_INT (1 << 19)
++#define MAC_IN_VECTOR_HOST_INT (1 << 18)
++#define MAC_IN_VECTOR_RX_INT_OR (1 << 17)
++#define MAC_IN_VECTOR_TX_INT_OR (1 << 16)
++#define MAC_IN_VECTOR_RX_INT_VEC (7 << 8)
++#define MAC_IN_VECTOR_TX_INT_VEC (7)
++
++
++/* MacStatus */
++
++#define TX_HOST_ERR_CODE (0xF << 20)
++#define TX_ERR_CH (0x7 << 16)
++#define RX_HOST_ERR_CODE (0xF << 12)
++#define RX_ERR_CH (0x7 << 8)
++#define RX_QOS_ACT (1 << 2)
++#define RX_FLOW_ACT (1 << 1)
++#define TX_FLOW_ACT (1 << 0)
++#endif _INC_CPMAC_REG
+diff -urN linux.old/drivers/net/avalanche_cpmac/cpmdio.c linux.dev/drivers/net/avalanche_cpmac/cpmdio.c
+--- linux.old/drivers/net/avalanche_cpmac/cpmdio.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/cpmdio.c 2005-07-12 02:48:42.046593000 +0200
+@@ -0,0 +1,960 @@
++/***************************************************************************
++** TNETD53xx Software Support
++** Copyright(c) 2002, Texas Instruments Incorporated. All Rights Reserved.
++**
++** FILE: cpmdio.c
++**
++** DESCRIPTION:
++** MDIO Polling State Machine API. Functions will enable mii-Phy
++** negotiation.
++**
++** HISTORY:
++** 01Jan01 Denis, Bill Original
++** 27Mar02 Michael Hanrahan (modified from emacmdio.c)
++** 07May02 Michael Hanrahan replaced clockwait for code delay
++** 10Jul02 Michael Hanrahan more debug, if fallback link is selected
++*****************************************************************************/
++#define __CPHAL_CPMDIO
++
++#include "mdio_reg.h"
++
++#ifdef _CPHAL_CPMAC
++#define mdioPrintf PhyDev->HalDev->OsFunc->Printf
++#else
++#define mdioPrintf printf
++#endif
++
++typedef struct _phy_device
++{
++ bit32u miibase;
++ bit32u inst;
++ bit32u PhyState;
++ bit32u MdixMask;
++ bit32u PhyMask;
++ bit32u MLinkMask;
++ bit32u PhyMode;
++#ifdef _CPHAL_CPMAC
++ HAL_DEVICE *HalDev;
++#endif
++} _PHY_DEVICE;
++
++static void _mdioDelayEmulate(PHY_DEVICE *PhyDev, int ClockWait);
++static void _mdioWaitForAccessComplete(PHY_DEVICE *PhyDev);
++static void _mdioUserAccess(PHY_DEVICE *PhyDev, bit32u method, bit32u regadr, bit32u phyadr, bit32u data);
++static bit32u _mdioUserAccessRead(PHY_DEVICE *PhyDev, bit32u regadr, bit32u phyadr);
++static void _mdioUserAccessWrite(PHY_DEVICE *PhyDev, bit32u regadr, bit32u phyadr, bit32u data);
++
++static void _mdioDisablePhy(PHY_DEVICE *PhyDev,bit32u PhyNum);
++static void _mdioPhyTimeOut(PHY_DEVICE *PhyDev);
++static void _mdioResetPhy(PHY_DEVICE *PhyDev,bit32u PhyNum);
++
++static void _mdioDumpPhy(PHY_DEVICE *PhyDev, bit32u p);
++static void _mdioDumpState(PHY_DEVICE *PhyDev);
++
++/* Auto Mdix */
++static void _mdioMdixDelay(PHY_DEVICE *PhyDev);
++static int _mdioMdixSupported(PHY_DEVICE *PhyDev);
++
++static void _MdioDefaultState (PHY_DEVICE *PhyDev);
++static void _MdioFindingState (PHY_DEVICE *PhyDev);
++static void _MdioFoundState (PHY_DEVICE *PhyDev);
++static void _MdioInitState (PHY_DEVICE *PhyDev);
++static void _MdioLinkedState (PHY_DEVICE *PhyDev);
++static void _MdioLinkWaitState (PHY_DEVICE *PhyDev);
++static void _MdioLoopbackState (PHY_DEVICE *PhyDev);
++static void _MdioNwayStartState(PHY_DEVICE *PhyDev);
++static void _MdioNwayWaitState (PHY_DEVICE *PhyDev);
++
++
++
++#ifndef TRUE
++#define TRUE (1==1)
++#endif
++
++#ifndef FALSE
++#define FALSE (1==2)
++#endif
++
++#define PHY_NOT_FOUND 0xFFFF /* Used in Phy Detection */
++
++/*PhyState breakout */
++
++#define PHY_DEV_OFFSET (0)
++#define PHY_DEV_SIZE (5) /* 5 Bits used */
++#define PHY_DEV_MASK (0x1f<<PHY_DEV_OFFSET)
++
++#define PHY_STATE_OFFSET (PHY_DEV_SIZE+PHY_DEV_OFFSET)
++#define PHY_STATE_SIZE (5) /* 10 Bits used */
++#define PHY_STATE_MASK (0x1f<<PHY_STATE_OFFSET)
++ #define INIT (1<<PHY_STATE_OFFSET)
++ #define FINDING (2<<PHY_STATE_OFFSET)
++ #define FOUND (3<<PHY_STATE_OFFSET)
++ #define NWAY_START (4<<PHY_STATE_OFFSET)
++ #define NWAY_WAIT (5<<PHY_STATE_OFFSET)
++ #define LINK_WAIT (6<<PHY_STATE_OFFSET)
++ #define LINKED (7<<PHY_STATE_OFFSET)
++ #define LOOPBACK (8<<PHY_STATE_OFFSET)
++
++#define PHY_SPEED_OFFSET (PHY_STATE_OFFSET+PHY_STATE_SIZE)
++#define PHY_SPEED_SIZE (1) /* 11 Bits used */
++#define PHY_SPEED_MASK (1<<PHY_SPEED_OFFSET)
++
++#define PHY_DUPLEX_OFFSET (PHY_SPEED_OFFSET+PHY_SPEED_SIZE)
++#define PHY_DUPLEX_SIZE (1) /* 12 Bits used */
++#define PHY_DUPLEX_MASK (1<<PHY_DUPLEX_OFFSET)
++
++#define PHY_TIM_OFFSET (PHY_DUPLEX_OFFSET+PHY_DUPLEX_SIZE)
++#define PHY_TIM_SIZE (10) /* 22 Bits used */
++#define PHY_TIM_MASK (0x3ff<<PHY_TIM_OFFSET)
++ #define PHY_FIND_TO ( 2<<PHY_TIM_OFFSET)
++ #define PHY_RECK_TO (200<<PHY_TIM_OFFSET)
++ #define PHY_LINK_TO (500<<PHY_TIM_OFFSET)
++ #define PHY_NWST_TO (500<<PHY_TIM_OFFSET)
++ #define PHY_NWDN_TO (800<<PHY_TIM_OFFSET)
++ #define PHY_MDIX_TO (274<<PHY_TIM_OFFSET) /* 2.74 Seconds <--Spec and empirical */
++
++#define PHY_SMODE_OFFSET (PHY_TIM_OFFSET+PHY_TIM_SIZE)
++#define PHY_SMODE_SIZE (5) /* 27 Bits used */
++#define PHY_SMODE_MASK (0x1f<<PHY_SMODE_OFFSET)
++ #define SMODE_AUTO (0x10<<PHY_SMODE_OFFSET)
++ #define SMODE_FD100 (0x08<<PHY_SMODE_OFFSET)
++ #define SMODE_HD100 (0x04<<PHY_SMODE_OFFSET)
++ #define SMODE_FD10 (0x02<<PHY_SMODE_OFFSET)
++ #define SMODE_HD10 (0x01<<PHY_SMODE_OFFSET)
++ #define SMODE_ALL (0x1f<<PHY_SMODE_OFFSET)
++
++#define PHY_CHNG_OFFSET (PHY_SMODE_OFFSET+PHY_SMODE_SIZE)
++#define PHY_CHNG_SIZE (1) /* 28 Bits used */
++#define PHY_CHNG_MASK (1<<PHY_CHNG_OFFSET)
++ #define PHY_CHANGE (1<<PHY_CHNG_OFFSET)
++
++#define PHY_TIMEDOUT_OFFSET (PHY_CHNG_OFFSET+PHY_CHNG_SIZE)
++#define PHY_TIMEDOUT_SIZE (1) /* 29 Bits used */
++#define PHY_TIMEDOUT_MASK (1<<PHY_TIMEDOUT_OFFSET)
++ #define PHY_MDIX_SWITCH (1<<PHY_TIMEDOUT_OFFSET)
++
++#define PHY_MDIX_OFFSET (PHY_TIMEDOUT_OFFSET+PHY_TIMEDOUT_SIZE)
++#define PHY_MDIX_SIZE (1) /* 30 Bits used */
++#define PHY_MDIX_MASK (1<<PHY_MDIX_OFFSET)
++ #define PHY_MDIX (1<<PHY_MDIX_OFFSET)
++
++static char *lstate[]={"NULL","INIT","FINDING","FOUND","NWAY_START","NWAY_WAIT","LINK_WAIT","LINKED", "LOOPBACK"};
++static int cpMacDebug;
++
++/* Local MDIO Register Macros */
++
++#define myMDIO_ALIVE MDIO_ALIVE (PhyDev->miibase)
++#define myMDIO_CONTROL MDIO_CONTROL (PhyDev->miibase)
++#define myMDIO_LINK MDIO_LINK (PhyDev->miibase)
++#define myMDIO_LINKINT MDIO_LINKINT (PhyDev->miibase)
++#define myMDIO_USERACCESS MDIO_USERACCESS(PhyDev->miibase, PhyDev->inst)
++#define myMDIO_USERPHYSEL MDIO_USERPHYSEL(PhyDev->miibase, PhyDev->inst)
++#define myMDIO_VER MDIO_VER (PhyDev->miibase)
++
++#ifndef VOLATILE32
++#define VOLATILE32(addr) (*((volatile bit32u *)(addr)))
++#endif
++
++/************************************
++***
++*** Delays at least ClockWait cylces
++*** before returning
++***
++**************************************/
++void _mdioDelayEmulate(PHY_DEVICE *PhyDev, int ClockWait)
++ {
++#ifdef _CPHAL_CPMAC /*+RC3.02*/
++ HAL_DEVICE *HalDev = PhyDev->HalDev; /*+RC3.02*/
++ osfuncSleep((int*)&ClockWait); /*+RC3.02*/
++#else /*+RC3.02*/
++ volatile bit32u i=0;
++ while(ClockWait--)
++ {
++ i |= myMDIO_LINK; /* MDIO register access to burn cycles */
++ }
++#endif
++ }
++
++void _mdioWaitForAccessComplete(PHY_DEVICE *PhyDev)
++ {
++ while((myMDIO_USERACCESS & MDIO_USERACCESS_GO)!=0)
++ {
++ }
++ }
++
++void _mdioUserAccess(PHY_DEVICE *PhyDev, bit32u method, bit32u regadr, bit32u phyadr, bit32u data)
++ {
++ bit32u control;
++
++ control = MDIO_USERACCESS_GO |
++ (method) |
++ (((regadr) << 21) & MDIO_USERACCESS_REGADR) |
++ (((phyadr) << 16) & MDIO_USERACCESS_PHYADR) |
++ ((data) & MDIO_USERACCESS_DATA);
++
++ myMDIO_USERACCESS = control;
++ }
++
++
++
++/************************************
++***
++*** Waits for MDIO_USERACCESS to be ready and reads data
++*** If 'WaitForData' set, waits for read to complete and returns Data,
++*** otherwise returns 0
++*** Note: 'data' is 16 bits but we use 32 bits
++*** to be consistent with rest of the code.
++***
++**************************************/
++bit32u _mdioUserAccessRead(PHY_DEVICE *PhyDev, bit32u regadr, bit32u phyadr)
++ {
++
++ _mdioWaitForAccessComplete(PhyDev); /* Wait until UserAccess ready */
++ _mdioUserAccess(PhyDev, MDIO_USERACCESS_READ, regadr, phyadr, 0);
++ _mdioWaitForAccessComplete(PhyDev); /* Wait for Read to complete */
++
++ return(myMDIO_USERACCESS & MDIO_USERACCESS_DATA);
++ }
++
++
++/************************************
++***
++*** Waits for MDIO_USERACCESS to be ready and writes data
++***
++**************************************/
++void _mdioUserAccessWrite(PHY_DEVICE *PhyDev, bit32u regadr, bit32u phyadr, bit32u data)
++ {
++ _mdioWaitForAccessComplete(PhyDev); /* Wait until UserAccess ready */
++ _mdioUserAccess(PhyDev, MDIO_USERACCESS_WRITE, regadr, phyadr, data);
++ }
++
++void _mdioDumpPhyDetailed(PHY_DEVICE *PhyDev)
++{
++ bit32u *PhyState = &PhyDev->PhyState;
++ bit32u PhyNum;
++ int RegData;
++
++ PhyNum=(*PhyState&PHY_DEV_MASK)>>PHY_DEV_OFFSET;
++
++ RegData = _mdioUserAccessRead(PhyDev, 0, PhyNum);
++ mdioPrintf("PhyControl: %04X, Lookback=%s, Speed=%s, Duplex=%s\n",
++ RegData,
++ RegData&PHY_LOOP?"On":"Off",
++ RegData&PHY_100?"100":"10",
++ RegData&PHY_FD?"Full":"Half");
++ RegData = _mdioUserAccessRead(PhyDev, 1, PhyNum);
++ mdioPrintf("PhyStatus: %04X, AutoNeg=%s, Link=%s\n",
++ RegData,
++ RegData&NWAY_COMPLETE?"Complete":"NotComplete",
++ RegData&PHY_LINKED?"Up":"Down");
++ RegData = _mdioUserAccessRead(PhyDev, 4, PhyNum);
++ mdioPrintf("PhyMyCapability: %04X, 100FD=%s, 100HD=%s, 10FD=%s, 10HD=%s\n",
++ RegData,
++ RegData&NWAY_FD100?"Yes":"No",
++ RegData&NWAY_HD100?"Yes":"No",
++ RegData&NWAY_FD10?"Yes":"No",
++ RegData&NWAY_HD10?"Yes":"No");
++
++ RegData = _mdioUserAccessRead(PhyDev, 5, PhyNum);
++ mdioPrintf("PhyPartnerCapability: %04X, 100FD=%s, 100HD=%s, 10FD=%s, 10HD=%s\n",
++ RegData,
++ RegData&NWAY_FD100?"Yes":"No",
++ RegData&NWAY_HD100?"Yes":"No",
++ RegData&NWAY_FD10?"Yes":"No",
++ RegData&NWAY_HD10?"Yes":"No");
++}
++void _mdioDumpPhy(PHY_DEVICE *PhyDev, bit32u p)
++ {
++ bit32u j,n,PhyAcks;
++ bit32u PhyRegAddr;
++ bit32u phy_num;
++ bit32u PhyMask = PhyDev->PhyMask;
++
++ PhyAcks=myMDIO_ALIVE;
++ PhyAcks&=PhyMask; /* Only interested in 'our' Phys */
++
++ for(phy_num=0,j=1;phy_num<32;phy_num++,j<<=1)
++ {
++ if (PhyAcks&j)
++ {
++ mdioPrintf("%2d%s:",phy_num,(phy_num==p)?">":" ");
++ for(PhyRegAddr=0;PhyRegAddr<6;PhyRegAddr++)
++ {
++ n = _mdioUserAccessRead(PhyDev, PhyRegAddr, phy_num);
++ mdioPrintf(" %04x",n&0x0ffff);
++ }
++ mdioPrintf("\n");
++ }
++ }
++ _mdioDumpPhyDetailed(PhyDev);
++ }
++
++void _mdioDumpState(PHY_DEVICE *PhyDev)
++ {
++ bit32u state = PhyDev->PhyState;
++
++ if (!cpMacDebug) return;
++
++ mdioPrintf("Phy: %d, ",(state&PHY_DEV_MASK)>>PHY_DEV_OFFSET);
++ mdioPrintf("State: %d/%s, ",(state&PHY_STATE_MASK)>>PHY_STATE_OFFSET,lstate[(state&PHY_STATE_MASK)>>PHY_STATE_OFFSET]);
++ mdioPrintf("Speed: %d, ",(state&PHY_SPEED_MASK)>>PHY_SPEED_OFFSET);
++ mdioPrintf("Dup: %d, ",(state&PHY_DUPLEX_MASK)>>PHY_DUPLEX_OFFSET);
++ mdioPrintf("Tim: %d, ",(state&PHY_TIM_MASK)>>PHY_TIM_OFFSET);
++ mdioPrintf("SMode: %d, ",(state&PHY_SMODE_MASK)>>PHY_SMODE_OFFSET);
++ mdioPrintf("Chng: %d",(state&PHY_CHNG_MASK)>>PHY_CHNG_OFFSET);
++ mdioPrintf("\n");
++
++ if (((state&PHY_STATE_MASK)!=FINDING)&&((state&PHY_STATE_MASK)!=INIT))
++ _mdioDumpPhy(PhyDev, (state&PHY_DEV_MASK)>>PHY_DEV_OFFSET);
++ }
++
++
++void _mdioResetPhy(PHY_DEVICE *PhyDev,bit32u PhyNum)
++ {
++ bit16u PhyControlReg;
++
++ _mdioUserAccessWrite(PhyDev, PHY_CONTROL_REG, PhyNum, PHY_RESET);
++ if (cpMacDebug)
++ mdioPrintf("cpMacMdioPhYReset(%d)\n",PhyNum);
++
++ /* Read control register until Phy Reset is complete */
++ do
++ {
++ PhyControlReg = _mdioUserAccessRead(PhyDev, PHY_CONTROL_REG, PhyNum);
++ }
++ while (PhyControlReg & PHY_RESET); /* Wait for Reset to clear */
++ }
++
++void _mdioDisablePhy(PHY_DEVICE *PhyDev,bit32u PhyNum)
++ {
++ _mdioUserAccessWrite(PhyDev, PHY_CONTROL_REG, PhyNum, PHY_ISOLATE|PHY_PDOWN);
++
++ if (cpMacDebug)
++ mdioPrintf("cpMacMdioDisablePhy(%d)\n",PhyNum);
++
++ }
++
++void _MdioInitState(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ bit32u CurrentState;
++
++ CurrentState=*PhyState;
++ CurrentState=(CurrentState&~PHY_TIM_MASK)|(PHY_FIND_TO);
++ CurrentState=(CurrentState&~PHY_STATE_MASK)|(FINDING);
++ CurrentState=(CurrentState&~PHY_SPEED_MASK);
++ CurrentState=(CurrentState&~PHY_DUPLEX_MASK);
++ CurrentState|=PHY_CHANGE;
++
++ *PhyState=CurrentState;
++
++ }
++
++void _MdioFindingState(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ bit32u PhyMask = PhyDev->PhyMask;
++ bit32u PhyNum,i,j,PhyAcks;
++
++
++ PhyNum=PHY_NOT_FOUND;
++
++ if (*PhyState&PHY_TIM_MASK)
++ {
++ *PhyState=(*PhyState&~PHY_TIM_MASK)|((*PhyState&PHY_TIM_MASK)-(1<<PHY_TIM_OFFSET));
++ }
++ else
++ {
++ PhyAcks=myMDIO_ALIVE;
++ PhyAcks&=PhyMask; /* Only interested in 'our' Phys */
++
++ for(i=0,j=1;(i<32)&&((j&PhyAcks)==0);i++,j<<=1);
++
++ if ((PhyAcks)&&(i<32)) PhyNum=i;
++ if (PhyNum!=PHY_NOT_FOUND)
++ {
++ /* Phy Found! */
++ *PhyState=(*PhyState&~PHY_DEV_MASK)|((PhyNum&PHY_DEV_MASK)<<PHY_DEV_OFFSET);
++ *PhyState=(*PhyState&~PHY_STATE_MASK)|(FOUND);
++ *PhyState|=PHY_CHANGE;
++ if (cpMacDebug)
++ mdioPrintf("cpMacMdioFindingState: PhyNum: %d\n",PhyNum);
++ }
++ else
++ {
++ if (cpMacDebug)
++ mdioPrintf("cpMacMdioFindingState: Timed Out looking for a Phy!\n");
++ *PhyState|=PHY_RECK_TO; /* This state currently has no support?*/
++ }
++ }
++ }
++
++void _MdioFoundState(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ bit32u PhyMask = PhyDev->PhyMask;
++ bit32u MLinkMask = PhyDev->MLinkMask;
++ bit32u PhyNum,PhyStatus,NWAYadvertise,m,phynum,i,j,PhyAcks;
++ bit32u PhySel;
++
++ if ((*PhyState&PHY_SMODE_MASK)==0) return;
++
++ PhyNum=(*PhyState&PHY_DEV_MASK)>>PHY_DEV_OFFSET;
++
++ PhyAcks=myMDIO_ALIVE;
++ PhyAcks&=PhyMask; /* Only interested in 'our' Phys */
++
++ /* Will now isolate all our Phys, except the one we have decided to use */
++ for(phynum=0,j=1;phynum<32;phynum++,j<<=1)
++ {
++ if (PhyAcks&j)
++ {
++ if (phynum!=PhyNum) /* Do not disabled Found Phy */
++ _mdioDisablePhy(PhyDev,phynum);
++ }
++ }
++
++ /* Reset the Phy and proceed with auto-negotiation */
++ _mdioResetPhy(PhyDev,PhyNum);
++
++ /* Now setup the MDIOUserPhySel register */
++
++ PhySel=PhyNum; /* Set the phy address */
++
++ /* Set the way Link will be Monitored */
++ /* Check the Link Selection Method */
++ if ((1 << PhyNum) & MLinkMask)
++ PhySel |= MDIO_USERPHYSEL_LINKSEL;
++
++ myMDIO_USERPHYSEL = PhySel; /* update PHYSEL */
++
++ /* Get the Phy Status */
++ PhyStatus = _mdioUserAccessRead(PhyDev, PHY_STATUS_REG, PhyNum);
++
++
++#ifdef _CPHAL_CPMAC
++ /* For Phy Internal loopback test, need to wait until Phy
++ found, then set Loopback */
++ if (PhyDev->HalDev->MdioConnect & _CPMDIO_LOOPBK)
++ {
++ /* Set Phy in Loopback */
++ _mdioUserAccessWrite(PhyDev, PHY_CONTROL_REG, PhyNum, PHY_LOOP|PHY_FD);
++ /* Do a read to ensure PHY_LOOP has completed */
++ _mdioUserAccessRead(PhyDev, PHY_STATUS_REG, PhyNum);
++ *PhyState=(*PhyState&~PHY_STATE_MASK)|(LOOPBACK);
++ *PhyState|=PHY_CHANGE;
++ return;
++ }
++#endif
++
++
++ if (cpMacDebug)
++ mdioPrintf("Enable Phy to negotiate external connection\n");
++
++ NWAYadvertise=NWAY_SEL;
++ if (*PhyState&SMODE_FD100) NWAYadvertise|=NWAY_FD100;
++ if (*PhyState&SMODE_HD100) NWAYadvertise|=NWAY_HD100;
++ if (*PhyState&SMODE_FD10) NWAYadvertise|=NWAY_FD10;
++ if (*PhyState&SMODE_HD10) NWAYadvertise|=NWAY_HD10;
++
++ *PhyState&=~(PHY_TIM_MASK|PHY_STATE_MASK);
++ if ((PhyStatus&NWAY_CAPABLE)&&(*PhyState&SMODE_AUTO)) /*NWAY Phy Detected*/
++ {
++ /*For NWAY compliant Phys */
++
++ _mdioUserAccessWrite(PhyDev, NWAY_ADVERTIZE_REG, PhyNum, NWAYadvertise);
++
++ if (cpMacDebug)
++ {
++ mdioPrintf("NWAY Advertising: ");
++ if (NWAYadvertise&NWAY_FD100) mdioPrintf("FullDuplex-100 ");
++ if (NWAYadvertise&NWAY_HD100) mdioPrintf("HalfDuplex-100 ");
++ if (NWAYadvertise&NWAY_FD10) mdioPrintf("FullDuplex-10 ");
++ if (NWAYadvertise&NWAY_HD10) mdioPrintf("HalfDuplex-10 ");
++ mdioPrintf("\n");
++ }
++
++ _mdioUserAccessWrite(PhyDev, PHY_CONTROL_REG, PhyNum, AUTO_NEGOTIATE_EN);
++
++ _mdioUserAccessWrite(PhyDev, PHY_CONTROL_REG, PhyNum, AUTO_NEGOTIATE_EN|RENEGOTIATE);
++
++ *PhyState|=PHY_CHANGE|PHY_NWST_TO|NWAY_START;
++ }
++ else
++ {
++ *PhyState&=~SMODE_AUTO; /*The Phy is not capable of auto negotiation! */
++ m=NWAYadvertise;
++ for(j=0x8000,i=0;(i<16)&&((j&m)==0);i++,j>>=1);
++ m=j;
++ j=0;
++ if (m&(NWAY_FD100|NWAY_HD100))
++ {
++ j=PHY_100;
++ m&=(NWAY_FD100|NWAY_HD100);
++ }
++ if (m&(NWAY_FD100|NWAY_FD10))
++ j |= PHY_FD;
++ if (cpMacDebug)
++ mdioPrintf("Requested PHY mode %s Duplex %s Mbps\n",(j&PHY_FD)?"Full":"Half",(j&PHY_100)?"100":"10");
++ _mdioUserAccessWrite(PhyDev, PHY_CONTROL_REG, PhyNum, j);
++ *PhyState&=~PHY_SPEED_MASK;
++ if (j&PHY_100)
++ *PhyState|=(1<<PHY_SPEED_OFFSET);
++ *PhyState&=~PHY_DUPLEX_MASK;
++ if (j&PHY_FD)
++ *PhyState|=(1<<PHY_DUPLEX_OFFSET);
++ *PhyState|=PHY_CHANGE|PHY_LINK_TO|LINK_WAIT;
++ }
++ _mdioMdixDelay(PhyDev); /* If AutoMdix add delay */
++ }
++
++void _MdioNwayStartState(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ bit32u PhyNum,PhyMode;
++
++ PhyNum=(*PhyState&PHY_DEV_MASK)>>PHY_DEV_OFFSET;
++
++ /*Wait for Negotiation to start */
++
++ PhyMode=_mdioUserAccessRead(PhyDev, PHY_CONTROL_REG, PhyNum);
++
++ if((PhyMode&RENEGOTIATE)==0)
++ {
++ _mdioUserAccessRead(PhyDev, PHY_STATUS_REG, PhyNum); /*Flush pending latch bits*/
++ *PhyState&=~(PHY_STATE_MASK|PHY_TIM_MASK);
++ *PhyState|=PHY_CHANGE|NWAY_WAIT|PHY_NWDN_TO;
++ _mdioMdixDelay(PhyDev); /* If AutoMdix add delay */
++ }
++ else
++ {
++ if (*PhyState&PHY_TIM_MASK)
++ *PhyState=(*PhyState&~PHY_TIM_MASK)|((*PhyState&PHY_TIM_MASK)-(1<<PHY_TIM_OFFSET));
++ else
++ _mdioPhyTimeOut(PhyDev);
++ }
++ }
++
++void _MdioNwayWaitState(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ bit32u PhyNum,PhyStatus,NWAYadvertise,NWAYREadvertise,NegMode,i,j;
++
++ PhyNum=(*PhyState&PHY_DEV_MASK)>>PHY_DEV_OFFSET;
++
++ PhyStatus=_mdioUserAccessRead(PhyDev, PHY_STATUS_REG, PhyNum);
++
++ if (PhyStatus&NWAY_COMPLETE)
++ {
++ *PhyState|=PHY_CHANGE;
++ *PhyState&=~PHY_SPEED_MASK;
++ *PhyState&=~PHY_DUPLEX_MASK;
++
++ NWAYadvertise =_mdioUserAccessRead(PhyDev, NWAY_ADVERTIZE_REG, PhyNum);
++ NWAYREadvertise =_mdioUserAccessRead(PhyDev, NWAY_REMADVERTISE_REG, PhyNum);
++
++ /* Negotiated mode is we and the remote have in common */
++ NegMode = NWAYadvertise & NWAYREadvertise;
++
++ if (cpMacDebug)
++ {
++ mdioPrintf("Phy: %d, ",(*PhyState&PHY_DEV_MASK)>>PHY_DEV_OFFSET);
++ mdioPrintf("NegMode %04X, NWAYadvertise %04X, NWAYREadvertise %04X\n",
++ NegMode, NWAYadvertise, NWAYREadvertise);
++ }
++
++ /* Limit negotiation to fields below */
++ NegMode &= (NWAY_FD100|NWAY_HD100|NWAY_FD10|NWAY_HD10);
++
++ if (NegMode==0)
++ {
++ NegMode=(NWAY_HD100|NWAY_HD10)&NWAYadvertise; /*or 10 ?? who knows, Phy is not MII compliant*/
++ if(cpMacDebug)
++ {
++ mdioPrintf("Mdio:WARNING: Negotiation complete but NO agreement, default is HD\n");
++ _mdioDumpPhyDetailed(PhyDev);
++ }
++ }
++ for(j=0x8000,i=0;(i<16)&&((j&NegMode)==0);i++,j>>=1);
++
++
++ NegMode=j;
++ if (cpMacDebug)
++ {
++ mdioPrintf("Negotiated connection: ");
++ if (NegMode&NWAY_FD100) mdioPrintf("FullDuplex 100 Mbs\n");
++ if (NegMode&NWAY_HD100) mdioPrintf("HalfDuplex 100 Mbs\n");
++ if (NegMode&NWAY_FD10) mdioPrintf("FullDuplex 10 Mbs\n");
++ if (NegMode&NWAY_HD10) mdioPrintf("HalfDuplex 10 Mbs\n");
++ }
++ if (NegMode!=0)
++ {
++ if (PhyStatus&PHY_LINKED)
++ *PhyState=(*PhyState&~PHY_STATE_MASK)|LINKED;
++ else
++ *PhyState=(*PhyState&~PHY_STATE_MASK)|LINK_WAIT;
++ if (NegMode&(NWAY_FD100|NWAY_HD100))
++ *PhyState=(*PhyState&~PHY_SPEED_MASK)|(1<<PHY_SPEED_OFFSET);
++ if (NegMode&(NWAY_FD100|NWAY_FD10))
++ *PhyState=(*PhyState&~PHY_DUPLEX_MASK)|(1<<PHY_DUPLEX_OFFSET);
++ }
++ }
++ else
++ {
++ if (*PhyState&PHY_TIM_MASK)
++ *PhyState=(*PhyState&~PHY_TIM_MASK)|((*PhyState&PHY_TIM_MASK)-(1<<PHY_TIM_OFFSET));
++ else
++ _mdioPhyTimeOut(PhyDev);
++ }
++ }
++
++void _MdioLinkWaitState(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ bit32u PhyStatus;
++ bit32u PhyNum;
++
++ PhyNum=(*PhyState&PHY_DEV_MASK)>>PHY_DEV_OFFSET;
++
++ PhyStatus=_mdioUserAccessRead(PhyDev, PHY_STATUS_REG, PhyNum);
++
++ if (PhyStatus&PHY_LINKED)
++ {
++ *PhyState=(*PhyState&~PHY_STATE_MASK)|LINKED;
++ *PhyState|=PHY_CHANGE;
++ }
++ else
++ {
++ if (*PhyState&PHY_TIM_MASK)
++ *PhyState=(*PhyState&~PHY_TIM_MASK)|((*PhyState&PHY_TIM_MASK)-(1<<PHY_TIM_OFFSET));
++ else
++ _mdioPhyTimeOut(PhyDev);
++ }
++ }
++
++void _mdioPhyTimeOut(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState;
++
++ if(_mdioMdixSupported(PhyDev) == 0)
++ return; /* AutoMdix not supported */
++
++ PhyState = &PhyDev->PhyState;
++
++ /* Indicate MDI/MDIX mode switch is needed */
++ *PhyState|=PHY_MDIX_SWITCH;
++
++ /* Toggle the MDIX mode indicatir */
++ if(*PhyState & PHY_MDIX)
++ *PhyState &= ~PHY_MDIX_MASK; /* Current State is MDIX, set to MDI */
++ else
++ *PhyState |= PHY_MDIX_MASK; /* Current State is MDI, set to MDIX */
++
++ /* Reset state machine to FOUND */
++ *PhyState=(*PhyState&~PHY_STATE_MASK)|(FOUND);
++ }
++
++void _MdioLoopbackState(PHY_DEVICE *PhyDev)
++ {
++ return;
++ }
++
++void _MdioLinkedState(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ bit32u PhyNum = (*PhyState&PHY_DEV_MASK)>>PHY_DEV_OFFSET;
++
++ if (myMDIO_LINK&(1<<PhyNum)) return; /* if still Linked, exit*/
++
++ /* Not Linked */
++ *PhyState&=~(PHY_STATE_MASK|PHY_TIM_MASK);
++ if (*PhyState&SMODE_AUTO)
++ *PhyState|=PHY_CHANGE|NWAY_WAIT|PHY_NWDN_TO;
++ else
++ *PhyState|=PHY_CHANGE|PHY_LINK_TO|LINK_WAIT;
++
++ _mdioMdixDelay(PhyDev); /* If AutoMdix add delay */
++ }
++
++void _MdioDefaultState(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ /*Awaiting a cpMacMdioInit call */
++ *PhyState|=PHY_CHANGE;
++ }
++
++
++/*User Calls********************************************************* */
++
++void cpMacMdioClose(PHY_DEVICE *PhyDev, int Full)
++ {
++ }
++
++
++int cpMacMdioInit(PHY_DEVICE *PhyDev, bit32u miibase, bit32u inst, bit32u PhyMask, bit32u MLinkMask, bit32u MdixMask, bit32u ResetReg, bit32u ResetBit, bit32u MdioBusFreq, bit32u MdioClockFreq, int verbose, void *Info)
++ {
++ bit32u HighestChannel;
++ bit32u ControlState;
++ bit32u *PhyState = &PhyDev->PhyState;
++ bit32u clkdiv; /*MJH+030328*/
++
++ cpMacDebug=verbose;
++
++ PhyDev->miibase = miibase;
++ PhyDev->inst = inst;
++ PhyDev->PhyMask = PhyMask;
++ PhyDev->MLinkMask = MLinkMask;
++ PhyDev->MdixMask = MdixMask;
++#ifdef _CPHAL_CPMAC
++ PhyDev->HalDev = (HAL_DEVICE*) Info;
++#endif
++
++ *PhyState &= ~PHY_MDIX_MASK; /* Set initial State to MDI */
++
++ /* Check that the channel supplied is within range */
++ HighestChannel = (myMDIO_CONTROL & MDIO_CONTROL_HIGHEST_USER_CHANNEL) > 8;
++ if(inst > HighestChannel)
++ return(HighestChannel);
++
++ /*Setup MII MDIO access regs */
++
++ /* Calculate the correct value for the mclkdiv */
++ /* See PITS #14 */
++ if (MdioClockFreq) /*MJH+030402*/
++ clkdiv = (MdioBusFreq / MdioClockFreq) - 1; /*MJH+030402*/
++ else /*MJH+030402*/
++ clkdiv = 0xFF; /*MJH+030402*/
++
++ ControlState = MDIO_CONTROL_ENABLE;
++ ControlState |= (clkdiv & MDIO_CONTROL_CLKDIV); /*MJH+030328*/
++
++ /*
++ If mii is not out of reset or if the Control Register is not set correctly
++ then initalize
++ */
++ if( !(VOLATILE32(ResetReg) & (1 << ResetBit)) ||
++ ((myMDIO_CONTROL & (MDIO_CONTROL_CLKDIV | MDIO_CONTROL_ENABLE)) != ControlState) )/*GSG~030404*/
++ {
++ /* MII not setup, Setup initial condition */
++ VOLATILE32(ResetReg) &= ~(1 << ResetBit);
++ _mdioDelayEmulate(PhyDev, 64);
++ VOLATILE32(ResetReg) |= (1 << ResetBit); /* take mii out of reset */
++ _mdioDelayEmulate(PhyDev, 64);
++ myMDIO_CONTROL = ControlState; /* Enable MDIO */
++ }
++
++ *PhyState=INIT;
++
++ if (cpMacDebug)
++ mdioPrintf("cpMacMdioInit\n");
++ _mdioDumpState(PhyDev);
++ return(0);
++ }
++
++void cpMacMdioSetPhyMode(PHY_DEVICE *PhyDev,bit32u PhyMode)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ bit32u CurrentState;
++
++ PhyDev->PhyMode = PhyMode; /* used for AUTOMIDX, planned to replace PhyState fields */
++
++ *PhyState&=~PHY_SMODE_MASK;
++
++ if (PhyMode&NWAY_AUTO) *PhyState|=SMODE_AUTO;
++ if (PhyMode&NWAY_FD100) *PhyState|=SMODE_FD100;
++ if (PhyMode&NWAY_HD100) *PhyState|=SMODE_HD100;
++ if (PhyMode&NWAY_FD10) *PhyState|=SMODE_FD10;
++ if (PhyMode&NWAY_HD10) *PhyState|=SMODE_HD10;
++
++ CurrentState=*PhyState&PHY_STATE_MASK;
++ if ((CurrentState==NWAY_START)||
++ (CurrentState==NWAY_WAIT) ||
++ (CurrentState==LINK_WAIT) ||
++ (CurrentState==LINKED) )
++ *PhyState=(*PhyState&~PHY_STATE_MASK)|FOUND|PHY_CHANGE;
++ if (cpMacDebug)
++ mdioPrintf("cpMacMdioSetPhyMode:%08X Auto:%d, FD10:%d, HD10:%d, FD100:%d, HD100:%d\n", PhyMode,
++ PhyMode&NWAY_AUTO, PhyMode&NWAY_FD10, PhyMode&NWAY_HD10, PhyMode&NWAY_FD100,
++ PhyMode&NWAY_HD100);
++ _mdioDumpState(PhyDev);
++ }
++
++/* cpMacMdioTic is called every 10 mili seconds to process Phy states */
++
++int cpMacMdioTic(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ bit32u CurrentState;
++
++ /*Act on current state of the Phy */
++
++ CurrentState=*PhyState;
++ switch(CurrentState&PHY_STATE_MASK)
++ {
++ case INIT: _MdioInitState(PhyDev); break;
++ case FINDING: _MdioFindingState(PhyDev); break;
++ case FOUND: _MdioFoundState(PhyDev); break;
++ case NWAY_START: _MdioNwayStartState(PhyDev); break;
++ case NWAY_WAIT: _MdioNwayWaitState(PhyDev); break;
++ case LINK_WAIT: _MdioLinkWaitState(PhyDev); break;
++ case LINKED: _MdioLinkedState(PhyDev); break;
++ case LOOPBACK: _MdioLoopbackState(PhyDev); break;
++ default: _MdioDefaultState(PhyDev); break;
++ }
++
++ /*Dump state info if a change has been detected */
++
++ if ((CurrentState&~PHY_TIM_MASK)!=(*PhyState&~PHY_TIM_MASK))
++ _mdioDumpState(PhyDev);
++
++ /* Check is MDI/MDIX mode switch is needed */
++ if(*PhyState & PHY_MDIX_SWITCH)
++ {
++ bit32u Mdix;
++
++ *PhyState &= ~PHY_MDIX_SWITCH; /* Clear Mdix Flip indicator */
++
++ if(*PhyState & PHY_MDIX)
++ Mdix = 1;
++ else
++ Mdix = 0;
++ return(_MIIMDIO_MDIXFLIP|Mdix);
++ }
++
++ /*Return state change to user */
++
++ if (*PhyState&PHY_CHNG_MASK)
++ {
++ *PhyState&=~PHY_CHNG_MASK;
++ return(1);
++ }
++ else
++ return(0);
++ }
++
++/* cpMacMdioGetDuplex is called to retrieve the Duplex info */
++
++int cpMacMdioGetDuplex(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ return((*PhyState&PHY_DUPLEX_MASK)?1:0); /* return 0 or a 1 */
++ }
++
++/* cpMacMdioGetSpeed is called to retreive the Speed info */
++
++int cpMacMdioGetSpeed(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ return(*PhyState&PHY_SPEED_MASK);
++ }
++
++/* cpMacMdioGetPhyNum is called to retreive the Phy Device Adr info */
++
++int cpMacMdioGetPhyNum(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ return((*PhyState&PHY_DEV_MASK)>>PHY_DEV_OFFSET);
++ }
++
++/* cpMacMdioGetLoopback is called to Determine if the LOOPBACK state has been reached*/
++
++int cpMacMdioGetLoopback(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ return((*PhyState&PHY_STATE_MASK)==LOOPBACK);
++ }
++/* cpMacMdioGetLinked is called to Determine if the LINKED state has been reached*/
++
++int cpMacMdioGetLinked(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ return((*PhyState&PHY_STATE_MASK)==LINKED);
++ }
++
++void cpMacMdioLinkChange(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ bit32u PhyNum,PhyStatus;
++
++ PhyNum=(*PhyState&PHY_DEV_MASK)>>PHY_DEV_OFFSET;
++
++ if (cpMacMdioGetLinked(PhyDev))
++ {
++ PhyStatus=_mdioUserAccessRead(PhyDev, PHY_STATUS_REG, PhyNum);
++
++ if ((PhyStatus&PHY_LINKED)==0)
++ {
++ *PhyState&=~(PHY_TIM_MASK|PHY_STATE_MASK);
++ if (*PhyState&SMODE_AUTO)
++ {
++ _mdioUserAccessWrite(PhyDev, PHY_CONTROL_REG, PhyNum, AUTO_NEGOTIATE_EN|RENEGOTIATE);
++ *PhyState|=PHY_CHANGE|PHY_NWST_TO|NWAY_START;
++ }
++ else
++ {
++ *PhyState|=PHY_CHANGE|PHY_LINK_TO|LINK_WAIT;
++ }
++ }
++ }
++ }
++
++void cpMacMdioGetVer(bit32u miibase, bit32u *ModID, bit32u *RevMaj, bit32u *RevMin)
++ {
++ bit32u Ver;
++
++ Ver = MDIO_VER(miibase);
++
++ *ModID = (Ver & MDIO_VER_MODID) >> 16;
++ *RevMaj = (Ver & MDIO_VER_REVMAJ) >> 8;
++ *RevMin = (Ver & MDIO_VER_REVMIN);
++ }
++
++int cpMacMdioGetPhyDevSize(void)
++ {
++ return(sizeof(PHY_DEVICE));
++ }
++
++ /* returns 0 if current Phy has AutoMdix support, otherwise 0 */
++int _mdioMdixSupported(PHY_DEVICE *PhyDev)
++ {
++ bit32u *PhyState = &PhyDev->PhyState;
++ bit32u PhyNum;
++
++ if((PhyDev->PhyMode & NWAY_AUTOMDIX) == 0)
++ return(0); /* AutoMdix not turned on */
++
++ PhyNum=(*PhyState&PHY_DEV_MASK)>>PHY_DEV_OFFSET;
++ if( ((1<<PhyNum) & PhyDev->MdixMask) == 0)
++ return(0); /* Phy does not support AutoMdix*/
++
++ return(1);
++ }
++
++/* If current Phy has AutoMdix support add Mdix Delay to the Timer State Value */
++void _mdioMdixDelay(PHY_DEVICE *PhyDev)
++ {
++ int Delay;
++ bit32u *PhyState = &PhyDev->PhyState;
++#ifdef _CPHAL_CPMAC
++ HAL_DEVICE *HalDev = PhyDev->HalDev;
++#endif
++
++ if(_mdioMdixSupported(PhyDev) == 0)
++ return; /* AutoMdix not supported */
++/* Currently only supported when used with the CPMAC */
++#ifdef _CPHAL_CPMAC
++ /* Get the Delay value in milli-seconds and convert to ten-milli second value */
++ Delay = cpmacRandomRange(HalDev, _AUTOMDIX_DELAY_MIN, _AUTOMDIX_DELAY_MAX);
++ Delay /= 10;
++
++ /* Add AutoMidx Random Switch Delay to AutoMdix Link Delay */
++
++ Delay += (PHY_MDIX_TO>>PHY_TIM_OFFSET);
++
++ /* Change Timeout value to AutoMdix standard */
++ *PhyState &= ~(PHY_TIM_MASK); /* Clear current Time out value */
++ *PhyState |= (Delay<<PHY_TIM_OFFSET); /* Set new value */
++#endif
++ }
++
++
+diff -urN linux.old/drivers/net/avalanche_cpmac/cpmdio.h linux.dev/drivers/net/avalanche_cpmac/cpmdio.h
+--- linux.old/drivers/net/avalanche_cpmac/cpmdio.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/cpmdio.h 2005-07-12 02:48:42.047593000 +0200
+@@ -0,0 +1,73 @@
++/*****************************************************************************
++** TNETD53xx Software Support
++** Copyright(c) 2002, Texas Instruments Incorporated. All Rights Reserved.
++**
++** FILE: cpmdio.h User Include for MDIO API Access
++**
++** DESCRIPTION:
++** This include file contains definitions for the the MDIO API
++**
++** HISTORY:
++** 27Mar02 Michael Hanrahan Original (modified from emacmdio.h)
++** 04Apr02 Michael Hanrahan Added Interrupt Support
++*****************************************************************************/
++#ifndef _INC_CPMDIO
++#define _INC_CPMDIO
++
++
++#ifndef __CPHAL_CPMDIO
++typedef void PHY_DEVICE;
++#endif
++
++
++/*Version Information */
++
++void cpMacMdioGetVer(bit32u miiBase, bit32u *ModID, bit32u *RevMaj, bit32u *RevMin);
++
++/*Called once at the begining of time */
++
++int cpMacMdioInit(PHY_DEVICE *PhyDev, bit32u miibase, bit32u inst, bit32u PhyMask, bit32u MLinkMask, bit32u MdixMask, bit32u ResetBase, bit32u ResetBit, bit32u MdioBusFreq, bit32u MdioClockFreq, int verbose, void *Info);
++int cpMacMdioGetPhyDevSize(void);
++
++
++/*Called every 10 mili Seconds, returns TRUE if there has been a mode change */
++
++int cpMacMdioTic(PHY_DEVICE *PhyDev);
++
++/*Called to set Phy mode */
++
++void cpMacMdioSetPhyMode(PHY_DEVICE *PhyDev,bit32u PhyMode);
++
++/*Calls to retreive info after a mode change! */
++
++int cpMacMdioGetDuplex(PHY_DEVICE *PhyDev);
++int cpMacMdioGetSpeed(PHY_DEVICE *PhyDev);
++int cpMacMdioGetPhyNum(PHY_DEVICE *PhyDev);
++int cpMacMdioGetLinked(PHY_DEVICE *PhyDev);
++void cpMacMdioLinkChange(PHY_DEVICE *PhyDev);
++
++/* Shot Down */
++
++void cpMacMdioClose(PHY_DEVICE *PhyDev, int Full);
++
++
++/* Phy Mode Values */
++#define NWAY_AUTOMDIX (1<<16)
++#define NWAY_FD100 (1<<8)
++#define NWAY_HD100 (1<<7)
++#define NWAY_FD10 (1<<6)
++#define NWAY_HD10 (1<<5)
++#define NWAY_AUTO (1<<0)
++
++/*
++ *
++ * Tic() return values
++ *
++ */
++
++#define _MIIMDIO_MDIXFLIP (1<<28)
++
++#define _AUTOMDIX_DELAY_MIN 80 /* milli-seconds*/
++#define _AUTOMDIX_DELAY_MAX 200 /* milli-seconds*/
++
++#endif /* _INC_CPMDIO */
+diff -urN linux.old/drivers/net/avalanche_cpmac/cppi_cpmac.c linux.dev/drivers/net/avalanche_cpmac/cppi_cpmac.c
+--- linux.old/drivers/net/avalanche_cpmac/cppi_cpmac.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/cppi_cpmac.c 2005-07-12 02:48:42.048593000 +0200
+@@ -0,0 +1,1345 @@
++/*************************************************************************
++ * TNETDxxxx Software Support
++ * Copyright (c) 2002,2003 Texas Instruments Incorporated. All Rights Reserved.
++ *
++ * FILE: cppi.c
++ *
++ * DESCRIPTION:
++ * This file contains shared code for all CPPI modules.
++ *
++ * HISTORY:
++ * 7Aug02 Greg RC1.00 Original Version created.
++ * 27Sep02 Mick RC1.01 Merged for use by CPMAC/CPSAR
++ * 16Oct02 Mick RC1.02 Performance Tweaks (see cppihist.txt)
++ * 12Nov02 Mick RC1.02 Updated to use cpmac_reg.h
++ * 09Jan03 Mick RC3.01 Removed modification to RxBuffer ptr
++ * 28Mar03 Mick 1.03 RxReturn now returns error if Malloc Fails
++ * 10Apr03 Mick 1.03.02 Added Needs Buffer Support
++ * 11Jun03 Mick 1.06.02 halSend() errors corrected
++ * 23Aug04 Mick 1.07.08 cpmac only - Send: bypass threshold check if TxInts re-enabled
++ *
++ * @author Greg Guyotte
++ * @version 1.00
++ * @date 7-Aug-2002
++ *****************************************************************************/
++/* each CPPI module must modify this file, the rest of the
++ code in cppi.c should be totally shared *//* Each CPPI module MUST properly define all constants shown below */
++
++/* CPPI registers */
++
++/* the following defines are not CPPI specific */
++
++static int TxInt(HAL_DEVICE *HalDev, int Ch, int Queue, int *MoreWork);
++
++static void FreeRx(HAL_DEVICE *HalDev, int Ch)
++ {
++ HAL_RCB *rcb_ptr; /*+GSG 030303*/
++ int rcbSize = (sizeof(HAL_RCB)+0xf)&~0xf; /*+GSG 030303*/
++ int Num = HalDev->ChData[Ch].RxNumBuffers, i; /*+GSG 030303*/
++
++ /* Free Rx data buffers attached to descriptors, if necessary */
++ if (HalDev->RcbStart[Ch] != 0) /*+GSG 030303*/
++ { /*+GSG 030303*/
++ for(i=0;i<Num;i++) /*+GSG 030303*/
++ { /*+GSG 030303*/
++ rcb_ptr = (HAL_RCB *)(HalDev->RcbStart[Ch] + (i*rcbSize)); /*+GSG 030303*/
++
++ /* free the data buffer */
++ if (rcb_ptr->DatPtr != 0)
++ {
++
++ HalDev->OsFunc->FreeRxBuffer((void *)rcb_ptr->OsInfo, (void *)rcb_ptr->DatPtr);
++ rcb_ptr->OsInfo=0; /*MJH+030522*/
++ rcb_ptr->DatPtr=0; /*MJH+030522*/
++ }
++ } /*+GSG 030303*/
++ } /*+GSG 030303*/
++
++ /* free up all desciptors at once */
++ HalDev->OsFunc->FreeDmaXfer(HalDev->RcbStart[Ch]);
++
++ /* mark buffers as freed */
++ HalDev->RcbStart[Ch] = 0;
++ }
++
++static void FreeTx(HAL_DEVICE *HalDev, int Ch, int Queue)
++ {
++
++/*+GSG 030303*/
++
++ /* free all descriptors at once */
++ HalDev->OsFunc->FreeDmaXfer(HalDev->TcbStart[Ch][Queue]);
++
++ HalDev->TcbStart[Ch][Queue] = 0;
++ }
++
++/* return of 0 means that this code executed, -1 means the interrupt was not
++ a teardown interrupt */
++static int RxTeardownInt(HAL_DEVICE *HalDev, int Ch)
++ {
++ bit32u base = HalDev->dev_base;
++
++ /* check to see if the interrupt is a teardown interrupt */
++ if (((CPMAC_RX_INT_ACK( base , Ch )) & TEARDOWN_VAL) == TEARDOWN_VAL)
++ {
++ /* finish channel teardown */
++
++ /* Free channel resources on a FULL teardown */
++ if (HalDev->RxTeardownPending[Ch] & FULL_TEARDOWN)
++ {
++ FreeRx(HalDev, Ch);
++ }
++
++ /* bug fix - clear Rx channel pointers on teardown */
++ HalDev->RcbPool[Ch] = 0;
++ HalDev->RxActQueueHead[Ch] = 0;
++ HalDev->RxActQueueCount[Ch] = 0;
++ HalDev->RxActive[Ch] = FALSE;
++
++ /* write completion pointer */
++ (CPMAC_RX_INT_ACK( base , Ch )) = TEARDOWN_VAL;
++
++ /* use direction bit as a teardown pending bit! May be able to
++ use only one teardown pending integer in HalDev */
++
++ HalDev->RxTeardownPending[Ch] &= ~RX_TEARDOWN;
++
++ HalDev->ChIsOpen[Ch][DIRECTION_RX] = 0;
++
++ HalDev->ChIsOpen[Ch][DIRECTION_RX] = 0;
++ CPMAC_RX_INTMASK_CLEAR(HalDev->dev_base) = (1<<Ch);
++ if ((HalDev->RxTeardownPending[Ch] & BLOCKING_TEARDOWN) == 0)
++ {
++
++ HalDev->OsFunc->TeardownComplete(HalDev->OsDev, Ch, DIRECTION_RX);
++ }
++ HalDev->RxTeardownPending[Ch] = 0;
++
++ return (EC_NO_ERRORS);
++ }
++ return (-1);
++ }
++
++/* return of 0 means that this code executed, -1 means the interrupt was not
++ a teardown interrupt. Note: this code is always called with Queue == 0 (hi priority). */
++static int TxTeardownInt(HAL_DEVICE *HalDev, int Ch, int Queue)
++ {
++ bit32u base = HalDev->dev_base;
++ HAL_TCB *Last, *Curr, *First; /*+GSG 030303*/
++ int i;
++
++ if (((CPMAC_TX_INT_ACK( base , Ch )) & TEARDOWN_VAL) == TEARDOWN_VAL)
++ {
++ /* perform all actions for both queues (+GSG 040212) */
++ for (i=0; i<HalDev->ChData[Ch].TxNumQueues; i++)
++ {
++ /* return outstanding buffers to OS +RC3.02*/
++ Curr = HalDev->TxActQueueHead[Ch][i]; /*+GSG 030303*/
++ First = Curr; /*+GSG 030303*/
++ while (Curr) /*+GSG 030303*/
++ { /*+GSG 030303*/
++ /* Pop TCB(s) for packet from the stack */ /*+GSG 030303*/
++ Last = Curr->Eop; /*+GSG 030303*/
++ HalDev->TxActQueueHead[Ch][i] = Last->Next; /*+GSG 030303*/
++ /*+GSG 030303*/
++ /* return to OS */ /*+GSG 030303*/
++ HalDev->OsFunc->SendComplete(Curr->OsInfo); /*+GSG 030303*/
++ /*+GSG 030303*/
++ /* Push Tcb(s) back onto the stack */ /*+GSG 030303*/
++ Curr = Last->Next; /*+GSG 030303*/
++ Last->Next = HalDev->TcbPool[Ch][i]; /*+GSG 030303*/
++ HalDev->TcbPool[Ch][i] = First; /*+GSG 030303*/
++ /*+GSG 030303*/
++ /* set the first(SOP) pointer for the next packet */ /*+GSG 030303*/
++ First = Curr; /*+GSG 030303*/
++ } /*+GSG 030303*/
++ }
++
++ /* finish channel teardown */
++
++ if (HalDev->TxTeardownPending[Ch] & FULL_TEARDOWN)
++ {
++ FreeTx(HalDev, Ch, 0);
++
++ if (HalDev->ChData[Ch].TxNumQueues == 2)
++ FreeTx(HalDev, Ch, 1);
++ } /* if FULL teardown */
++
++ /* perform all actions for both queues (+GSG 040212) */
++ for (i=0; i<HalDev->ChData[Ch].TxNumQueues; i++)
++ {
++ /* bug fix - clear Tx channel pointers on teardown */
++ HalDev->TcbPool[Ch][i] = 0;
++ HalDev->TxActQueueHead[Ch][i] = 0;
++ HalDev->TxActQueueCount[Ch][i] = 0;
++ HalDev->TxActive[Ch][i] = FALSE;
++ }
++
++ /* write completion pointer, only needed for the high priority queue */
++ (CPMAC_TX_INT_ACK( base , Ch )) = TEARDOWN_VAL;
++
++ /* no longer pending teardown */
++ HalDev->TxTeardownPending[Ch] &= ~TX_TEARDOWN;
++
++ HalDev->ChIsOpen[Ch][DIRECTION_TX] = 0;
++
++ HalDev->ChIsOpen[Ch][DIRECTION_TX] = 0;
++ CPMAC_TX_INTMASK_CLEAR(HalDev->dev_base) = (1<<Ch);
++ if ((HalDev->TxTeardownPending[Ch] & BLOCKING_TEARDOWN) == 0)
++ {
++
++ HalDev->OsFunc->TeardownComplete(HalDev->OsDev, Ch, DIRECTION_TX);
++ }
++ HalDev->TxTeardownPending[Ch] = 0;
++
++ return (EC_NO_ERRORS);
++ }
++ return (-1);
++ }
++
++/* +GSG 030421 */
++static void AddToRxQueue(HAL_DEVICE *HalDev, HAL_RCB *FirstRcb, HAL_RCB *LastRcb, int FragCount, int Ch)
++ {
++ if (HalDev->RxActQueueHead[Ch]==0)
++ {
++
++ HalDev->RxActQueueHead[Ch]=FirstRcb;
++ HalDev->RxActQueueTail[Ch]=LastRcb;
++ if (!HalDev->RxActive[Ch])
++ {
++ /* write Rx Queue Head Descriptor Pointer */
++ ((CPMAC_RX_HDP( HalDev->dev_base , Ch )) ) = VirtToPhys(FirstRcb) - HalDev->offset;
++ HalDev->RxActive[Ch]=TRUE;
++ }
++ }
++ else
++ {
++ register HAL_RCB *OldTailRcb;
++ register bit32u rmode;
++
++ HalDev->OsFunc->CriticalOn();
++ OldTailRcb=HalDev->RxActQueueTail[Ch];
++ OldTailRcb->Next=(void *)FirstRcb;
++ OldTailRcb=VirtToVirtNoCache(OldTailRcb);
++ OldTailRcb->HNext=VirtToPhys(FirstRcb) - HalDev->offset;
++ HalDev->RxActQueueTail[Ch]=LastRcb;
++ rmode=OldTailRcb->mode;
++ if (rmode&CB_EOQ_BIT)
++ {
++ rmode&=~CB_EOQ_BIT;
++ ((CPMAC_RX_HDP( HalDev->dev_base , Ch )) ) = VirtToPhys(FirstRcb) - HalDev->offset;
++ OldTailRcb->mode=rmode;
++ }
++ HalDev->OsFunc->CriticalOff();
++ }
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * This function is called to indicate to the CPHAL that the upper layer
++ * software has finished processing the receive data (given to it by
++ * osReceive()). The CPHAL will then return the appropriate receive buffers
++ * and buffer descriptors to the available pool.
++ *
++ * @param HalReceiveInfo Start of receive buffer descriptor chain returned to
++ * CPHAL.
++ * @param StripFlag Flag indicating whether the upper layer software has
++ * retained ownership of the receive data buffers.
++ *<BR>
++ * 'FALSE' means that the CPHAL can reuse the receive data buffers.
++ *<BR>
++ * 'TRUE' : indicates the data buffers were retained by the OS
++ *<BR>
++ * NOTE: If StripFlag is TRUE, it is the responsibility of the upper layer software to free the buffers when they are no longer needed.
++ *
++ * @return EC_NO_ERRORS (ok). <BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_INVALID_STATE "EC_VAL_INVALID_STATE"<BR>
++ * @ref EC_VAL_RCB_NEEDS_BUFFER "EC_VAL_RCB_NEEDS_BUFFER"<BR>
++ * @ref EC_VAL_RCB_DROPPED "EC_VAL_RCB_DROPPED"<BR>
++ */
++static int halRxReturn(HAL_RECEIVEINFO *HalReceiveInfo,
++ int StripFlag)
++ {
++ int Ch, i;
++ HAL_RCB *LastRcb;
++ HAL_DEVICE *HalDev;
++ int RcbSize;
++ int FragCount;
++
++ Ch = HalReceiveInfo->mode&0x0ff;
++ HalDev = (HAL_DEVICE *)HalReceiveInfo->Off_BLen;
++ FragCount = HalReceiveInfo->mode>>8;
++
++ if (HalDev->State != enOpened)
++ return(EC_CPMAC |EC_FUNC_RXRETURN|EC_VAL_INVALID_STATE);
++
++ LastRcb=(HAL_RCB *)HalReceiveInfo->Eop;
++ LastRcb->HNext=0;
++ LastRcb->Next=0;
++ RcbSize = HalDev->ChData[Ch].RxBufSize;
++
++ if (FragCount>1)
++ {
++ LastRcb->Off_BLen=RcbSize;
++ LastRcb->mode=CB_OWNERSHIP_BIT;
++ }
++
++ HalReceiveInfo->Off_BLen=RcbSize;
++ HalReceiveInfo->mode=CB_OWNERSHIP_BIT;
++
++ /* If OS has kept the buffers for this packet, attempt to alloc new buffers */
++ if (StripFlag)
++ {
++ int rc=0; /*MJH+030417*/
++ int GoodCount=0; /*GSG+030421*/
++ HAL_RCB *TempRcb;
++ char *pBuf;
++ HAL_RCB *CurrHeadRcb = HalReceiveInfo, *LastGoodRcb=0; /* +GSG 030421 */
++
++ TempRcb = HalReceiveInfo;
++ for (i=0; i<FragCount; i++)
++ {
++ if (TempRcb == 0)
++ {
++ dbgPrintf("Rx Return error while allocating new buffers\n");
++ dbgPrintf("Rcb = %08x, Rcb->Eop = %08x, FragCount = %d:%d\n",
++ (bit32u)HalReceiveInfo, (bit32u)HalReceiveInfo->Eop, FragCount,i);
++ osfuncSioFlush();
++
++ return(EC_CPPI|EC_FUNC_RXRETURN|EC_VAL_CORRUPT_RCB_CHAIN);
++ }
++
++ pBuf= (char *) HalDev->OsFunc->MallocRxBuffer(RcbSize,0,
++ 0xF,HalDev->ChData[Ch].OsSetup,
++ (void *)TempRcb,
++ (void *)&TempRcb->OsInfo,
++ (void *) HalDev->OsDev);
++ if (!pBuf)
++ {
++ /* malloc failed, add this RCB to Needs Buffer List */
++ (HAL_RCB *)TempRcb->Eop = TempRcb; /* GSG +030430 */
++ TempRcb->mode=1<<8|Ch;
++ TempRcb->Off_BLen=(bit32u)HalDev;
++
++ if(HalDev->NeedsCount < MAX_NEEDS) /* +MJH 030410 */
++ { /* +MJH 030410 */
++ HalDev->Needs[HalDev->NeedsCount] = (HAL_RECEIVEINFO *) TempRcb; /* +MJH 030410 */
++ HalDev->NeedsCount++; /* +MJH 030410 */
++ rc = (EC_CPPI|EC_FUNC_RXRETURN|EC_VAL_RCB_NEEDS_BUFFER); /* ~MJH 030417 */
++ } /* +MJH 030410 */
++ else /* +MJH 030410 */
++ rc = (EC_CPPI|EC_FUNC_RXRETURN|EC_VAL_RCB_DROPPED); /* ~MJH 030417 */
++
++ /* requeue any previous RCB's that were ready to go before this one */
++ if (GoodCount > 0) /* +GSG 030421 */
++ { /* +GSG 030421 */
++ LastGoodRcb->HNext=0; /* +GSG 030430 */
++ LastGoodRcb->Next=0; /* +GSG 030430 */
++ osfuncDataCacheHitWritebackAndInvalidate((void *)LastGoodRcb, 16); /* +GSG 030430 */
++
++ AddToRxQueue(HalDev, CurrHeadRcb, LastGoodRcb, GoodCount, Ch); /* +GSG 030421 */
++ GoodCount = 0; /* +GSG 030421 */
++ } /* +GSG 030421 */
++
++ CurrHeadRcb = TempRcb->Next; /* +GSG 030421 */
++ }
++ else /* +GSG 030421 */
++ { /* +GSG 030421 */
++ /* malloc succeeded, requeue the RCB to the hardware */
++ TempRcb->BufPtr=VirtToPhys(pBuf) - HalDev->offset;
++ TempRcb->DatPtr=pBuf;
++ /* Emerald fix 10/29 */
++ osfuncDataCacheHitWritebackAndInvalidate((void *)TempRcb, 16);
++
++ /* i store the last good RCB in case the malloc fails for the
++ next fragment. This ensures that I can go ahead and return
++ a partial chain of RCB's to the hardware */
++ LastGoodRcb = TempRcb; /* +GSG 030421 */
++ GoodCount++; /* +GSG 030421 */
++ } /* +GSG 030421 */
++ TempRcb = TempRcb->Next;
++ } /* end of Frag loop */
++ /* if there any good RCB's to requeue, do so here */
++ if (GoodCount > 0) /* +GSG 030421 */
++ {
++ AddToRxQueue(HalDev, CurrHeadRcb, LastGoodRcb, GoodCount, Ch); /* +GSG 030421 */
++ }
++ return(rc); /* ~GSG 030421 */
++ }
++ else
++ {
++ /* Not Stripping */
++ /* Emerald */
++ /* Write Back SOP and last RCB */
++ osfuncDataCacheHitWritebackAndInvalidate((void *)HalReceiveInfo, 16);
++
++ if (FragCount > 1)
++ {
++ osfuncDataCacheHitWritebackAndInvalidate((void *)LastRcb, 16);
++ }
++ /* if not stripping buffers, always add to queue */
++ AddToRxQueue(HalDev, HalReceiveInfo, LastRcb, FragCount, Ch); /*MJH~030520*/
++ }
++
++ return(EC_NO_ERRORS);
++ }
++
++/* +MJH 030410
++ Trys to liberate an RCB until liberation fails.
++ Note: If liberation fails then RxReturn will re-add the RCB to the
++ Needs list.
++*/
++static void NeedsCheck(HAL_DEVICE *HalDev)
++{
++ HAL_RECEIVEINFO* HalRcb;
++ int rc;
++ HalDev->OsFunc->CriticalOn();
++ while(HalDev->NeedsCount)
++ {
++ HalDev->NeedsCount--;
++ HalRcb = HalDev->Needs[HalDev->NeedsCount];
++ rc = halRxReturn(HalRcb, 1);
++ /* short circuit if RxReturn starts to fail */
++ if (rc != 0)
++ break;
++ }
++ HalDev->OsFunc->CriticalOff();
++}
++
++/*
++ * This function allocates transmit buffer descriptors (internal CPHAL function).
++ * It creates a high priority transmit queue by default for a single Tx
++ * channel. If QoS is enabled for the given CPHAL device, this function
++ * will also allocate a low priority transmit queue.
++ *
++ * @param HalDev CPHAL module instance. (set by cphalInitModule())
++ * @param Ch Channel number.
++ *
++ * @return 0 OK, Non-Zero Not OK
++ */
++static int InitTcb(HAL_DEVICE *HalDev, int Ch)
++ {
++ int i, Num = HalDev->ChData[Ch].TxNumBuffers;
++ HAL_TCB *pTcb=0;
++ char *AllTcb;
++ int tcbSize, Queue;
++ int SizeMalloc;
++
++ tcbSize = (sizeof(HAL_TCB)+0xf)&~0xf;
++ SizeMalloc = (tcbSize*Num)+0xf;
++
++ for (Queue=0; Queue < HalDev->ChData[Ch].TxNumQueues; Queue++)
++ {
++ if (HalDev->TcbStart[Ch][Queue] == 0)
++ {
++
++ /* malloc all TCBs at once */
++ AllTcb = (char *)HalDev->OsFunc->MallocDmaXfer(SizeMalloc,0,0xffffffff);
++ if (!AllTcb)
++ {
++ return(EC_CPPI|EC_FUNC_HAL_INIT|EC_VAL_TCB_MALLOC_FAILED);
++ }
++
++ HalDev->OsFunc->Memset(AllTcb, 0, SizeMalloc);
++
++ /* keep this address for freeing later */
++ HalDev->TcbStart[Ch][Queue] = AllTcb;
++ }
++ else
++ {
++ /* if the memory has already been allocated, simply reuse it! */
++ AllTcb = HalDev->TcbStart[Ch][Queue];
++ }
++
++ /* align to cache line */
++ AllTcb = (char *)(((bit32u)AllTcb + 0xf) &~ 0xf); /*PITS #143 MJH~030522*/
++
++ /* default High priority transmit queue */
++ HalDev->TcbPool[Ch][Queue]=0;
++ for(i=0;i<Num;i++)
++ {
++ /*pTcb=(HAL_TCB *) OsFunc->MallocDmaXfer(sizeof(HAL_TCB),0,0xffffffff); */
++ pTcb= (HAL_TCB *)(AllTcb + (i*tcbSize));
++ pTcb->mode=0;
++ pTcb->BufPtr=0;
++ pTcb->Next=HalDev->TcbPool[Ch][Queue];
++ pTcb->Off_BLen=0;
++ HalDev->TcbPool[Ch][Queue]=pTcb;
++ }
++ /*HalDev->TcbEnd = pTcb;*/
++ }
++
++ return(EC_NO_ERRORS);
++ }
++
++/*
++ * This function allocates receive buffer descriptors (internal CPHAL function).
++ * After allocation, the function 'queues' (gives to the hardware) the newly
++ * created receive buffers to enable packet reception.
++ *
++ * @param HalDev CPHAL module instance. (set by cphalInitModule())
++ * @param Ch Channel number.
++ *
++ * @return 0 OK, Non-Zero Not OK
++ */
++static int InitRcb(HAL_DEVICE *HalDev, int Ch)
++ {
++ int i, Num = HalDev->ChData[Ch].RxNumBuffers;
++ int Size = HalDev->ChData[Ch].RxBufSize;
++ HAL_RCB *pRcb;
++ char *pBuf;
++ char *AllRcb;
++ int rcbSize;
++ int DoMalloc = 0;
++ int SizeMalloc;
++ int MallocSize;
++
++ rcbSize = (sizeof(HAL_RCB)+0xf)&~0xf;
++ SizeMalloc = (rcbSize*Num)+0xf;
++
++ if (HalDev->RcbStart[Ch] == 0)
++ {
++ DoMalloc = 1;
++
++ /* malloc all RCBs at once */
++ AllRcb= (char *)HalDev->OsFunc->MallocDmaXfer(SizeMalloc,0,0xffffffff);
++ if (!AllRcb)
++ {
++ return(EC_CPPI|EC_FUNC_HAL_INIT|EC_VAL_RCB_MALLOC_FAILED);
++ }
++
++ HalDev->OsFunc->Memset(AllRcb, 0, SizeMalloc);
++
++ /* keep this address for freeing later */
++ HalDev->RcbStart[Ch] = AllRcb;
++ }
++ else
++ {
++ /* if the memory has already been allocated, simply reuse it! */
++ AllRcb = HalDev->RcbStart[Ch];
++ }
++
++ /* align to cache line */
++ AllRcb = (char *)(((bit32u)AllRcb + 0xf)&~0xf); /*PITS #143 MJH~030522*/
++
++ HalDev->RcbPool[Ch]=0;
++ for(i=0;i<Num;i++)
++ {
++ pRcb = (HAL_RCB *)(AllRcb + (i*rcbSize));
++
++ if (DoMalloc == 1)
++ {
++
++ MallocSize = Size; /*~3.01 */
++ pBuf= (char *) HalDev->OsFunc->MallocRxBuffer(MallocSize,0,0xF,HalDev->ChData[Ch].OsSetup, (void *)pRcb, (void *)&pRcb->OsInfo, (void *) HalDev->OsDev);
++ if(!pBuf)
++ {
++ return(EC_CPPI|EC_FUNC_HAL_INIT|EC_VAL_RX_BUFFER_MALLOC_FAILED);
++ }
++ /* -RC3.01 pBuf = (char *)(((bit32u)pBuf+0xF) & ~0xF); */
++ pRcb->BufPtr=VirtToPhys(pBuf) - HalDev->offset;
++ pRcb->DatPtr=pBuf;
++ }
++ pRcb->mode=(1<<8)|Ch; /* One Frag for Ch */
++ pRcb->Next=(void *)HalDev->RcbPool[Ch];
++ pRcb->Off_BLen=(bit32u)HalDev;
++ HalDev->RcbPool[Ch]=pRcb;
++ }
++
++ /* Give all of the Rx buffers to hardware */
++
++ while(HalDev->RcbPool[Ch])
++ {
++ pRcb=HalDev->RcbPool[Ch];
++ HalDev->RcbPool[Ch]=pRcb->Next;
++ pRcb->Eop=(void*)pRcb;
++ pRcb->mode=(1<<8)|Ch;
++ halRxReturn((HAL_RECEIVEINFO *)pRcb, 0);
++ }
++
++ return(EC_NO_ERRORS);
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * This function transmits the data in FragList using available transmit
++ * buffer descriptors. More information on the use of the Mode parameter
++ * is available in the module-specific appendices. Note: The OS should
++ * not call Send() for a channel that has been requested to be torndown.
++ *
++ * @param HalDev CPHAL module instance. (set by cphalInitModule())
++ * @param FragList Fragment List structure.
++ * @param FragCount Number of fragments in FragList.
++ * @param PacketSize Number of bytes to transmit.
++ * @param OsSendInfo OS Send Information structure. <BR>
++ * @param Mode 32-bit value with the following bit fields: <BR>
++ * 31-16: Mode (used for module specific data). <BR>
++ * 15-08: Queue (transmit queue to send on). <BR>
++ * 07-00: Channel (channel number to send on).
++ *
++ * @return EC_NO_ERRORS (ok). <BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_INVALID_STATE "EC_VAL_INVALID_STATE"<BR>
++ * @ref EC_VAL_NOT_LINKED "EC_VAL_NOT_LINKED"<BR>
++ * @ref EC_VAL_INVALID_CH "EC_VAL_INVALID_CH"<BR>
++ * @ref EC_VAL_OUT_OF_TCBS "EC_VAL_OUT_OF_TCBS"<BR>
++ * @ref EC_VAL_NO_TCBS "EC_VAL_NO_TCBS"<BR>
++ */
++static int halSend(HAL_DEVICE *HalDev,FRAGLIST *FragList,
++ int FragCount,int PacketSize, OS_SENDINFO *OsSendInfo,
++ bit32u Mode)
++ {
++ HAL_TCB *tcb_ptr, *head;
++ int i;
++ int rc = EC_NO_ERRORS;
++ int Ch = Mode & 0xFF;
++ int Queue = (Mode>>8)&0xFF;
++ /*int DoThresholdCheck=1; */ /* Used when TxIntDisable is set and TxInts are re-enabled */
++
++ if (HalDev->State != enOpened)
++ return(EC_CPPI|EC_FUNC_SEND|EC_VAL_INVALID_STATE);
++
++ if (!HalDev->Linked)
++ {
++ rc = EC_CPPI|EC_FUNC_SEND|EC_VAL_NOT_LINKED;
++ return(rc);
++ }
++
++ if (HalDev->ChIsOpen[Ch][DIRECTION_TX] == 0) /*MJH~030611*/ /*PITS 148*/
++ return(EC_CPMAC |EC_FUNC_SEND|EC_VAL_INVALID_CH); /*+GSG 030303*/
++
++ HalDev->OsFunc->CriticalOn();
++
++ /* Setup Tx mode and size */
++ if (PacketSize<60)
++ {
++ FragList[FragCount-1].len += (60 - PacketSize); /*MJH~030506*//*PITS 132*/
++ PacketSize = 60; /*MJH~030506*/
++ }
++ Mode &= CB_PASSCRC_BIT;
++
++ tcb_ptr = head = HalDev->TcbPool[Ch][Queue];
++
++ if (tcb_ptr)
++ {
++
++ Mode|=PacketSize|CB_SOF_BIT|CB_OWNERSHIP_BIT;
++
++ for (i=0; i<FragCount; i++)
++
++ {
++ /* Setup Tx mode and size */
++ tcb_ptr->Off_BLen = FragList[i].len;
++
++ tcb_ptr->mode = Mode;
++ tcb_ptr->BufPtr = VirtToPhys((bit32 *)FragList[i].data) - HalDev->offset;
++ tcb_ptr->OsInfo = OsSendInfo;
++
++ if (i == (FragCount - 1))
++ {
++ /* last fragment */
++ tcb_ptr->mode |= CB_EOF_BIT;
++
++ /* since this is the last fragment, set the TcbPool pointer before
++ nulling out the Next pointers */
++
++ HalDev->TcbPool[Ch][Queue] = tcb_ptr->Next;
++
++ tcb_ptr->Next = 0;
++ tcb_ptr->HNext = 0;
++
++ /* In the Tx Interrupt handler, we will need to know which TCB is EOP,
++ so we can save that information in the SOP */
++ head->Eop = tcb_ptr;
++
++ /* Emerald fix 10/29 */
++ osfuncDataCacheHitWritebackAndInvalidate((void *)tcb_ptr, 16);
++
++ }
++ else
++ {
++ Mode=CB_OWNERSHIP_BIT;
++ tcb_ptr->HNext = VirtToPhys((bit32 *)tcb_ptr->Next) - HalDev->offset;
++
++ /* Emerald fix 10/29 */
++ osfuncDataCacheHitWritebackAndInvalidate((void *)tcb_ptr, 16);
++
++ tcb_ptr = tcb_ptr->Next; /* what about the end of TCB list?? */
++
++ if (tcb_ptr == 0)
++ {
++ rc = EC_CPPI|EC_FUNC_SEND|EC_VAL_OUT_OF_TCBS;
++ goto ExitSend;
++ }
++ }
++ } /* for */
++
++ /* put it on the high priority queue */
++ if (HalDev->TxActQueueHead[Ch][Queue] == 0)
++ {
++ HalDev->TxActQueueHead[Ch][Queue]=head;
++ HalDev->TxActQueueTail[Ch][Queue]=tcb_ptr;
++/*+GSG 030303*//*+GSG 030303*/
++ if (!HalDev->TxActive[Ch][Queue])
++ {
++
++ bit32u base = HalDev->dev_base;
++
++ /* write CPPI TX HDP */
++ (CPMAC_TX_HDP( base , Ch )) = VirtToPhys(head) - HalDev->offset;
++ HalDev->TxActive[Ch][Queue]=TRUE;
++
++ }
++ }
++ else
++ {
++ register volatile HAL_TCB *pTailTcb;
++ register bit32u tmode;
++ register bit32u pCurrentTcb;
++
++ HalDev->TxActQueueTail[Ch][Queue]->Next=head;
++ /* Emerald fix 10/29 */
++
++ pTailTcb=(HAL_TCB *)VirtToVirtNoCache(&HalDev->TxActQueueTail[Ch][Queue]->HNext);
++ pCurrentTcb=VirtToPhys(head) - HalDev->offset;
++ pTailTcb->HNext=pCurrentTcb;
++ HalDev->TxActQueueTail[Ch][Queue]=tcb_ptr;
++/*+GSG 030303*/
++ tmode=pTailTcb->mode;
++ if (tmode&CB_EOQ_BIT)
++ {
++ bit32u base = HalDev->dev_base;
++
++ tmode&=~CB_EOQ_BIT;
++ pTailTcb->mode=tmode;
++ ((CPMAC_TX_HDP( base , Ch )) ) = pCurrentTcb;
++ }
++
++ else
++ {
++ if(HalDev->TxIntDisable)
++ {
++ /* Enable Interrupts, to ensure packet goes out on wire */
++ CPMAC_TX_INTMASK_SET(HalDev->dev_base) = (1<<Ch);
++ halPacketProcessEnd(HalDev); /* Allow Interrupt to be seen at the OS */
++ /*DoThresholdCheck = 0; */ /* Disable Threshold Check */
++
++ }
++ }
++
++ }
++ rc = EC_NO_ERRORS;
++ goto ExitSend;
++ } /* if (tcb_ptr) */
++ else
++ {
++ rc = EC_CPPI|EC_FUNC_SEND|EC_VAL_NO_TCBS;
++ goto ExitSend;
++ }
++ExitSend:
++
++/* 15 June 2004 - NSP Performance Update : If Tx Ints are disabled then process them here */
++/* 29 June 2004 - NSP Performance Update : Moved to end at request of BCIL */
++/* 23 Aug 2004 - NSP Performance Update : If Tx Ints are re-enabled do not do Threshold check */
++
++ if(HalDev->TxIntDisable /*&& DoThresholdCheck*/)
++ {
++ if(--HalDev->TxIntThreshold[Ch] <= 0)
++ {
++ int MoreWork;
++ TxInt(HalDev, Ch, 0, &MoreWork);
++ HalDev->TxIntThreshold[Ch] = HalDev->TxIntThresholdMaster[Ch];
++ }
++ }
++ HalDev->OsFunc->CriticalOff();
++
++ return(rc);
++ }
++
++/*
++ * This function processes receive interrupts. It traverses the receive
++ * buffer queue, extracting the data and passing it to the upper layer software via
++ * osReceive(). It handles all error conditions and fragments without valid data by
++ * immediately returning the RCB's to the RCB pool.
++ *
++ * @param HalDev CPHAL module instance. (set by cphalInitModule())
++ * @param Ch Channel Number.
++ * @param MoreWork Flag that indicates that there is more work to do when set to 1.
++ *
++ * @return 0 if OK, non-zero otherwise.
++ */
++static int RxInt(HAL_DEVICE *HalDev, int Ch, int *MoreWork)
++ {
++ HAL_RCB *CurrentRcb, *SopRcb, *EofRcb, *EopRcb;
++ bit32u RxBufStatus,PacketsServiced, RxPktLen = 0, RxSopStatus,
++ FrmFrags, TotalFrags, FrmLen;
++ int base = HalDev->dev_base, Ret;
++ OS_FUNCTIONS *OsFunc = HalDev->OsFunc;
++ int RxServiceMax = HalDev->ChData[Ch].RxServiceMax;
++ int FragIndex; /* +GSG 030508 */
++
++ if(HalDev->NeedsCount) /* +MJH 030410 */
++ NeedsCheck(HalDev); /* +MJH 030410 */
++
++ /* Handle case of teardown interrupt */
++ if (HalDev->RxTeardownPending[Ch] != 0)
++ {
++ Ret = RxTeardownInt(HalDev, Ch);
++ if (Ret == 0)
++ { /*+GSG 030303*/
++ *MoreWork = 0;
++ return (EC_NO_ERRORS);
++ } /*+GSG 030303*/
++ }
++
++ /* Examine first RCB on the software active queue */
++ CurrentRcb=HalDev->RxActQueueHead[Ch];
++ osfuncDataCacheHitInvalidate((void*)CurrentRcb, 16);
++ RxBufStatus=CurrentRcb->mode;
++ PacketsServiced=0;
++
++ /* Process received packets until we find hardware owned descriptors
++ or until we hit RxServiceMax */
++ while((CurrentRcb)&&((RxBufStatus&CB_OWNERSHIP_BIT)==0)&&
++ (PacketsServiced<RxServiceMax)) /* ~GSG 030307 */
++ {
++
++ PacketsServiced++; /* ~GSG 030307 */
++ SopRcb=CurrentRcb;
++ RxSopStatus=RxBufStatus;
++ RxPktLen = RxSopStatus&CB_SIZE_MASK;
++
++ FrmFrags=0;
++ TotalFrags=0;
++ FragIndex=0;
++ FrmLen=0;
++ EofRcb=0;
++
++/* +GSG 030508 *//* +GSG 030508 */
++
++ /* Loop through all fragments that comprise current packet. Build
++ fraglist and exit when the end of the packet is reached, or the
++ end of the descriptor list is reached. */
++ do
++ {
++ bit32u DmaLen;
++
++
++ DmaLen=CurrentRcb->Off_BLen;
++
++ FrmLen+=DmaLen;
++ TotalFrags++;
++ if (!EofRcb)
++ {
++ HalDev->fraglist[FragIndex].data=((char *)CurrentRcb->DatPtr); /* ~GSG 030508 */
++
++ HalDev->fraglist[FragIndex].len=DmaLen; /* ~GSG 030508 */
++
++ /* GSG 12/9 */
++ HalDev->fraglist[FragIndex].OsInfo = CurrentRcb->OsInfo; /* ~GSG 030508 */
++
++ /* Upper layer must do the data invalidate */
++
++ FrmFrags++;
++ FragIndex++; /* ~GSG 030508 */
++ if (FrmLen>=RxPktLen)
++ EofRcb=CurrentRcb;
++ }
++ EopRcb=CurrentRcb;
++ CurrentRcb=EopRcb->Next;
++ if (CurrentRcb)
++ {
++ osfuncDataCacheHitInvalidate((void*)CurrentRcb,16);
++ }
++ }while(((EopRcb->mode&CB_EOF_BIT)==0)&&(CurrentRcb));
++
++ /* Write the completion pointer for interrupt acknowledgement*/
++ (CPMAC_RX_INT_ACK( base , Ch )) = VirtToPhys(EopRcb) - HalDev->offset;
++
++ EopRcb->Next=0;
++
++ if (CurrentRcb == 0)
++ {
++ /* If we are out of RCB's we must not send this packet
++ to the OS. */
++ int RcbSize = HalDev->ChData[Ch].RxBufSize;
++
++ if (TotalFrags>1)
++ {
++ EopRcb->Off_BLen=RcbSize;
++ EopRcb->mode=CB_OWNERSHIP_BIT;
++ osfuncDataCacheHitWritebackAndInvalidate((void *)EopRcb, 16);
++ }
++
++ SopRcb->Off_BLen=RcbSize;
++ SopRcb->mode=CB_OWNERSHIP_BIT;
++ osfuncDataCacheHitWritebackAndInvalidate((void *)SopRcb, 16);
++
++ ((CPMAC_RX_HDP( base , Ch )) ) = VirtToPhys(SopRcb);
++ }
++ else
++ {
++ /* Dequeue packet and send to OS */
++ int mode;
++
++ /* setup SopRcb for the packet */
++ SopRcb->Eop=(void*)EopRcb;
++
++ /* dequeue packet */
++ HalDev->RxActQueueHead[Ch]=CurrentRcb;
++
++ if (EopRcb->mode&CB_EOQ_BIT)
++ {
++ /* Next pointer is non-null and EOQ bit is set, which
++ indicates misqueue packet in CPPI protocol. */
++
++ ((CPMAC_RX_HDP( base , Ch )) ) = EopRcb->HNext;
++ }
++
++ mode = (SopRcb->mode & 0xFFFF0000) | Ch;
++
++ SopRcb->mode=(FrmFrags<<8)|Ch;
++ SopRcb->Off_BLen=(bit32u)HalDev;
++
++ /* send packet up the higher layer driver */
++ OsFunc->Receive(HalDev->OsDev,HalDev->fraglist,FragIndex,RxPktLen, /* ~GSG 030508 */
++ (HAL_RECEIVEINFO *)SopRcb,mode);
++
++ RxBufStatus=CurrentRcb->mode;
++ }
++ } /* while loop */
++
++ if ((CurrentRcb)&&((RxBufStatus&CB_OWNERSHIP_BIT)==0)) /*~GSG 030307*/
++ {
++ *MoreWork = 1;
++ }
++ else
++ {
++ *MoreWork = 0;
++ }
++
++ return (EC_NO_ERRORS);
++}
++
++/*
++ * This function processes transmit interrupts. It traverses the
++ * transmit buffer queue, detecting sent data buffers and notifying the upper
++ * layer software via osSendComplete(). (for SAR, i originally had this split
++ * into two functions, one for each queue, but joined them on 8/8/02)
++ *
++ * @param HalDev CPHAL module instance. (set by cphalInitModule())
++ * @param Queue Queue number to service (always 0 for MAC, Choose 1 for SAR to service low priority queue)
++ * @param MoreWork Flag that indicates that there is more work to do when set to 1.
++ *
++ * @return 0 if OK, non-zero otherwise.
++ */
++int TxInt(HAL_DEVICE *HalDev, int Ch, int Queue, int *MoreWork)
++ {
++ HAL_TCB *CurrentTcb,*LastTcbProcessed,*FirstTcbProcessed;
++ int PacketsServiced;
++ bit32u TxFrameStatus;
++ int base;
++ int TxServiceMax = HalDev->ChData[Ch].TxServiceMax;
++ OS_FUNCTIONS *OsFunc = HalDev->OsFunc;
++
++/*+GSG 030303*//*+GSG 030303*/
++
++ /* load the module base address */
++ base = HalDev->dev_base;
++
++ /* Handle case of teardown interrupt. This must be checked at
++ the top of the function rather than the bottom, because
++ the normal data processing can wipe out the completion
++ pointer which is used to determine teardown complete. */
++ if (HalDev->TxTeardownPending[Ch] != 0)
++ {
++ int Ret;
++
++ Ret = TxTeardownInt(HalDev, Ch, Queue);
++ if (Ret == 0)
++ { /*+GSG 030303*/
++ *MoreWork = 0; /* bug fix 1/6 */ /*+GSG 030303*/
++ return (EC_NO_ERRORS);
++ } /*+GSG 030303*/
++ }
++
++ OsFunc->CriticalOn(); /* 240904 */
++
++ CurrentTcb = HalDev->TxActQueueHead[Ch][Queue];
++ FirstTcbProcessed=CurrentTcb;
++
++ if (CurrentTcb==0)
++ {
++ /* I saw this error a couple of times when multi-channels were added */
++ dbgPrintf("[cppi TxInt()]TxH int with no TCB in queue!\n");
++ dbgPrintf(" Ch=%d, CurrentTcb = 0x%08x\n", Ch, (bit32u)CurrentTcb);
++ dbgPrintf(" HalDev = 0x%08x\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ OsFunc->CriticalOff();
++ return(EC_CPPI|EC_FUNC_TXINT|EC_VAL_NULL_TCB);
++ }
++
++ osfuncDataCacheHitInvalidate((void *)CurrentTcb, 16);
++ TxFrameStatus=CurrentTcb->mode;
++ PacketsServiced=0;
++
++ /* should the ownership bit check be inside of the loop?? could make it a
++ while-do loop and take this check away */
++ if ((TxFrameStatus&CB_OWNERSHIP_BIT)==0)
++ {
++ do
++ {
++ /* Pop TCB(s) for packet from the stack */
++ LastTcbProcessed=CurrentTcb->Eop;
++
++ /* new location for acknowledge */
++ /* Write the completion pointer */
++ (CPMAC_TX_INT_ACK( base , Ch )) = VirtToPhys(LastTcbProcessed) - HalDev->offset;
++
++ HalDev->TxActQueueHead[Ch][Queue] = LastTcbProcessed->Next;
++
++/*+GSG 030303*//*+GSG 030303*/
++
++ osfuncDataCacheHitInvalidate((void *)LastTcbProcessed, 16);
++
++ if (LastTcbProcessed->mode&CB_EOQ_BIT)
++ {
++ if (LastTcbProcessed->Next)
++ {
++ /* Misqueued packet */
++
++ (CPMAC_TX_HDP( base , Ch )) = LastTcbProcessed->HNext;
++
++ }
++ else
++ {
++ /* Tx End of Queue */
++
++ HalDev->TxActive[Ch][Queue]=FALSE;
++ }
++ }
++
++ OsFunc->SendComplete(CurrentTcb->OsInfo);
++
++ /* Push Tcb(s) back onto the stack */
++ CurrentTcb = LastTcbProcessed->Next;
++
++ LastTcbProcessed->Next=HalDev->TcbPool[Ch][Queue];
++
++ HalDev->TcbPool[Ch][Queue]=FirstTcbProcessed;
++
++ PacketsServiced++;
++
++ TxFrameStatus=CB_OWNERSHIP_BIT;
++ /* set the first(SOP) pointer for the next packet */
++ FirstTcbProcessed = CurrentTcb;
++ if (CurrentTcb)
++ {
++ osfuncDataCacheHitInvalidate((void *)CurrentTcb, 16);
++ TxFrameStatus=CurrentTcb->mode;
++ }
++
++ }while(((TxFrameStatus&CB_OWNERSHIP_BIT)==0)
++ &&(PacketsServiced<TxServiceMax));
++
++ if (((TxFrameStatus&CB_OWNERSHIP_BIT)==0)
++ &&(PacketsServiced==TxServiceMax))
++ {
++ *MoreWork = 1;
++ }
++ else
++ {
++ *MoreWork = 0;
++ }
++ }
++ OsFunc->CriticalOff();
++
++ return(EC_NO_ERRORS);
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * This function performs a teardown for the given channel. The value of the
++ * Mode parameter controls the operation of the function, as documented below.
++ *
++ * Note: If bit 3 of Mode is set, this call is blocking, and will not return
++ * until the teardown interrupt has occurred and been processed. While waiting
++ * for a blocking teardown to complete, ChannelTeardown() will signal the OS
++ * (via Control(.."Sleep"..)) to allow the OS to perform other tasks if
++ * necessary. If and only if bit 3 of Mode is clear, the CPHAL will call the
++ * OS TeardownComplete() function to indicate that the teardown has completed.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param Ch Channel number.
++ * @param Mode Bit 0 (LSB): Perform Tx teardown (if set).<BR>
++ * Bit 1: Perform Rx teardown (if set). <BR>
++ * Bit 2: If set, perform full teardown (free buffers/descriptors).
++ * If clear, perform partial teardown (keep buffers). <BR>
++ * Bit 3 (MSB): If set, call is blocking.
++ * If clear, call is non-blocking.
++ *
++ * @return EC_NO_ERRORS (ok). <BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_INVALID_STATE "EC_VAL_INVALID_STATE"<BR>
++ * @ref EC_VAL_INVALID_CH "EC_VAL_INVALID_CH"<BR>
++ * @ref EC_VAL_TX_TEARDOWN_ALREADY_PEND "EC_VAL_TX_TEARDOWN_ALREADY_PEND"<BR>
++ * @ref EC_VAL_RX_TEARDOWN_ALREADY_PEND "EC_VAL_RX_TEARDOWN_ALREADY_PEND"<BR>
++ * @ref EC_VAL_TX_CH_ALREADY_TORNDOWN "EC_VAL_TX_CH_ALREADY_TORNDOWN"<BR>
++ * @ref EC_VAL_RX_CH_ALREADY_TORNDOWN "EC_VAL_RX_CH_ALREADY_TORNDOWN"<BR>
++ * @ref EC_VAL_TX_TEARDOWN_TIMEOUT "EC_VAL_TX_TEARDOWN_TIMEOUT"<BR>
++ * @ref EC_VAL_RX_TEARDOWN_TIMEOUT "EC_VAL_RX_TEARDOWN_TIMEOUT"<BR>
++ * @ref EC_VAL_LUT_NOT_READY "EC_VAL_LUT_NOT_READY"<BR>
++ */
++static int halChannelTeardown(HAL_DEVICE *HalDev, int Ch, bit32 Mode)
++ {
++ int DoTx, DoRx, Sleep=2048, timeout=0; /*MJH~030306*/
++ bit32u base = HalDev->dev_base;
++
++/* Set the module, used for error returns */
++
++ DoTx = (Mode & TX_TEARDOWN);
++ DoRx = (Mode & RX_TEARDOWN);
++
++ if (HalDev->State < enInitialized)
++ return(EC_CPMAC |EC_FUNC_CHTEARDOWN|EC_VAL_INVALID_STATE);
++
++ if ((Ch < 0) || (Ch > (MAX_CHAN-1) ))
++ {
++ return(EC_CPMAC |EC_FUNC_CHTEARDOWN|EC_VAL_INVALID_CH);
++ }
++
++ /* set teardown pending bits before performing the teardown, because they
++ will be used in the int handler (this is done for AAL5) */
++ if (DoTx)
++ {
++ if (HalDev->TxTeardownPending[Ch] != 0)
++ return(EC_CPMAC |EC_FUNC_CHTEARDOWN|EC_VAL_TX_TEARDOWN_ALREADY_PEND);
++
++ /* If a full teardown, this also means that the user must
++ setup all channels again to use them */
++ if (Mode & FULL_TEARDOWN)
++ HalDev->ChIsSetup[Ch][DIRECTION_TX] = 0;
++
++ if (HalDev->State < enOpened)
++ {
++ /* if the hardware has never been opened, the channel has never actually
++ been setup in the hardware, so I just need to reset the software flag
++ and leave */
++ HalDev->ChIsSetup[Ch][DIRECTION_TX] = 0;
++ return (EC_NO_ERRORS);
++ }
++ else
++ {
++ if (HalDev->ChIsOpen[Ch][DIRECTION_TX] == 0)
++ {
++ return(EC_CPMAC |EC_FUNC_CHTEARDOWN|EC_VAL_TX_CH_ALREADY_TORNDOWN);
++ }
++
++ /* set teardown flag */
++ HalDev->TxTeardownPending[Ch] = Mode;
++ }
++ }
++
++ if (DoRx)
++ {
++ if (HalDev->RxTeardownPending[Ch] != 0)
++ return(EC_CPMAC |EC_FUNC_CHTEARDOWN|EC_VAL_RX_TEARDOWN_ALREADY_PEND);
++
++ if (Mode & FULL_TEARDOWN)
++ HalDev->ChIsSetup[Ch][DIRECTION_RX] = 0;
++
++ if (HalDev->State < enOpened)
++ {
++ HalDev->ChIsSetup[Ch][DIRECTION_RX] = 0;
++ return (EC_NO_ERRORS);
++ }
++ else
++ {
++ if (HalDev->ChIsOpen[Ch][DIRECTION_RX] == 0)
++ return(EC_CPMAC |EC_FUNC_CHTEARDOWN|EC_VAL_RX_CH_ALREADY_TORNDOWN);
++
++ HalDev->RxTeardownPending[Ch] = Mode;
++ }
++ }
++
++ /* Perform Tx Teardown Duties */
++ if ((DoTx) && (HalDev->State == enOpened))
++ {
++ /* Request TX channel teardown */
++ (CPMAC_TX_TEARDOWN( base )) = Ch;
++
++ /* wait until teardown has completed */
++ if (Mode & BLOCKING_TEARDOWN)
++ {
++ timeout = 0;
++ while (HalDev->ChIsOpen[Ch][DIRECTION_TX] == TRUE)
++ {
++ osfuncSleep(&Sleep);
++
++ timeout++;
++ if (timeout > 100000)
++ {
++ return(EC_CPMAC |EC_FUNC_CHTEARDOWN|EC_VAL_TX_TEARDOWN_TIMEOUT);
++ }
++ }
++ }
++ } /* if DoTx */
++
++ /* Perform Rx Teardown Duties */
++ if ((DoRx) && (HalDev->State == enOpened))
++ {
++
++ /* perform CPMAC specific RX channel teardown */
++ CPMAC_RX_TEARDOWN(base) = Ch;
++
++ if (Mode & BLOCKING_TEARDOWN)
++ {
++ timeout = 0;
++ while (HalDev->ChIsOpen[Ch][DIRECTION_RX] == TRUE)
++ {
++ osfuncSleep(&Sleep);
++
++ timeout++;
++ if (timeout > 100000)
++ {
++ return(EC_CPMAC |EC_FUNC_CHTEARDOWN|EC_VAL_RX_TEARDOWN_TIMEOUT);
++ }
++ }
++ }
++ } /* if DoRx */
++
++ return (EC_NO_ERRORS);
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * This function closes the CPHAL module. The module will be reset.
++ * The Mode parameter should be used to determine the actions taken by
++ * Close().
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param Mode Indicates actions to take on close. The following integer
++ * values are valid: <BR>
++ * 1: Does not free buffer resources, init parameters remain
++ * intact. User can then call Open() without calling Init()
++ * to attempt to reset the device and bring it back to the
++ * last known state.<BR>
++ * 2: Frees the buffer resources, but keeps init parameters. This
++ * option is a more aggressive means of attempting a device reset.
++ * 3: Frees the buffer resources, and clears all init parameters. <BR>
++ * At this point, the caller would have to call to completely
++ * reinitialize the device (Init()) before being able to call
++ * Open(). Use this mode if you are shutting down the module
++ * and do not plan to restart.
++ *
++ * @return EC_NO_ERRORS (ok).<BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_INVALID_STATE "EC_VAL_INVALID_STATE"<BR>
++ * Any error code from halChannelTeardown().<BR>
++ */
++static int halClose(HAL_DEVICE *HalDev, bit32 Mode)
++ {
++ int Ch, Inst, Ret;
++ OS_DEVICE *TmpOsDev;
++ OS_FUNCTIONS *TmpOsFunc;
++ HAL_FUNCTIONS *TmpHalFunc;
++ char *TmpDeviceInfo;
++
++ int Ticks; /*MJH~030306*/
++
++ /* Verify proper device state */
++ if (HalDev->State != enOpened)
++ return (EC_CPMAC | EC_FUNC_CLOSE|EC_VAL_INVALID_STATE);
++
++ /* Teardown all open channels */
++ for (Ch = 0; Ch <= (MAX_CHAN-1) ; Ch++)
++ {
++ if (HalDev->ChIsOpen[Ch][DIRECTION_TX] == TRUE)
++ {
++ if (Mode == 1)
++ {
++ Ret = halChannelTeardown(HalDev, Ch, TX_TEARDOWN | PARTIAL_TEARDOWN | BLOCKING_TEARDOWN);
++ if (Ret) return (Ret);
++ }
++ else
++ {
++ Ret = halChannelTeardown(HalDev, Ch, TX_TEARDOWN | FULL_TEARDOWN | BLOCKING_TEARDOWN);
++ if (Ret) return (Ret);
++ }
++ }
++
++ if (HalDev->ChIsOpen[Ch][DIRECTION_RX] == TRUE)
++ {
++ if (Mode == 1)
++ {
++ Ret = halChannelTeardown(HalDev, Ch, RX_TEARDOWN | PARTIAL_TEARDOWN | BLOCKING_TEARDOWN);
++ if (Ret) return (Ret);
++ }
++ else
++ {
++ Ret = halChannelTeardown(HalDev, Ch, RX_TEARDOWN | FULL_TEARDOWN | BLOCKING_TEARDOWN);
++ if (Ret) return (Ret);
++ }
++ }
++ }
++
++ /* free fraglist in HalDev */
++ HalDev->OsFunc->Free(HalDev->fraglist);
++ HalDev->fraglist = 0;
++
++ /* unregister the interrupt */
++ HalDev->OsFunc->IsrUnRegister(HalDev->OsDev, HalDev->interrupt);
++
++ Ticks = 0; /* Disable Tick Timer */ /*MJH+030306*/
++ HalDev->OsFunc->Control(HalDev->OsDev, hcTick, hcClear, &Ticks); /*MJH+030306*/
++
++ /* Free the Phy Information Structure */
++ if(HalDev->PhyDev)
++ {
++ HalDev->OsFunc->Free(HalDev->PhyDev); /*MJH+030513*/
++ HalDev->PhyDev = 0; /*MJH+030522*/
++ }
++
++ /* Perform CPMAC specific closing functions */
++ CPMAC_MACCONTROL(HalDev->dev_base) &= ~MII_EN;
++ CPMAC_TX_CONTROL(HalDev->dev_base) &= ~TX_EN;
++ CPMAC_RX_CONTROL(HalDev->dev_base) &= ~RX_EN;
++
++ /* put device back into reset */
++ (*(volatile bit32u *)(HalDev->ResetBase)) &=~ (1<<HalDev->ResetBit);
++ Ticks = 64; /*MJH~030306*/
++ osfuncSleep(&Ticks);
++
++ /* If mode is 3, than clear the HalDev and set next state to DevFound*/
++ if (Mode == 3)
++ {
++ /* I need to keep the HalDev parameters that were setup in InitModule */
++ TmpOsDev = HalDev->OsDev;
++ TmpOsFunc = HalDev->OsFunc;
++ TmpDeviceInfo = HalDev->DeviceInfo;
++
++ TmpHalFunc = HalDev->HalFuncPtr;
++ Inst = HalDev->Inst;
++
++ /* Clear HalDev */
++
++ HalDev->OsFunc->Memset(HalDev, 0, sizeof(HAL_DEVICE));
++
++ /* Restore key parameters */
++ HalDev->OsDev = TmpOsDev;
++ HalDev->OsFunc = TmpOsFunc;
++ HalDev->DeviceInfo = TmpDeviceInfo;
++
++ HalDev->HalFuncPtr = TmpHalFunc;
++ HalDev->Inst = Inst;
++
++ HalDev->State = enDevFound;
++ }
++ else
++ {
++ HalDev->State = enInitialized;
++ }
++
++ return(EC_NO_ERRORS);
++ }
+diff -urN linux.old/drivers/net/avalanche_cpmac/cpremap_cpmac.c linux.dev/drivers/net/avalanche_cpmac/cpremap_cpmac.c
+--- linux.old/drivers/net/avalanche_cpmac/cpremap_cpmac.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/cpremap_cpmac.c 2005-07-12 02:48:42.049593000 +0200
+@@ -0,0 +1,28 @@
++#ifndef _INC_CPREMAP_C
++#define _INC_CPREMAP_C
++
++#ifdef __ADAM2
++static inline void osfuncDataCacheHitInvalidate(void *ptr, int Size)
++ {
++ asm(" cache 17, (%0)" : : "r" (ptr));
++ }
++
++static inline void osfuncDataCacheHitWriteback(void *ptr, int Size)
++ {
++ asm(" cache 25, (%0)" : : "r" (ptr));
++ }
++
++static inline void osfuncDataCacheHitWritebackAndInvalidate(void *ptr, int Size)
++ {
++ asm(" cache 21, (%0)" : : "r" (ptr));
++ }
++
++#else
++
++#define osfuncDataCacheHitInvalidate(MemPtr, Size) __asm__(" .set mips3; cache 17, (%0); .set mips0" : : "r" (MemPtr))
++#define osfuncDataCacheHitWritebackAndInvalidate(MemPtr, Size) __asm__(" .set mips3; cache 21, (%0); .set mips0" : : "r" (MemPtr))
++#define osfuncDataCacheHitWriteback(MemPtr, Size) __asm__(" .set mips3; cache 25, (%0); .set mips0" : : "r" (MemPtr))
++
++#endif
++
++#endif
+diff -urN linux.old/drivers/net/avalanche_cpmac/cpswhal_cpmac.h linux.dev/drivers/net/avalanche_cpmac/cpswhal_cpmac.h
+--- linux.old/drivers/net/avalanche_cpmac/cpswhal_cpmac.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/cpswhal_cpmac.h 2005-07-12 02:48:42.050593000 +0200
+@@ -0,0 +1,632 @@
++/************************************************************************
++ * TNETDxxxx Software Support
++ * Copyright (c) 2002 Texas Instruments Incorporated. All Rights Reserved.
++ *
++ * FILE: cphal.h
++ *
++ * DESCRIPTION:
++ * User include file, contains data definitions shared between the CPHAL
++ * and the upper-layer software.
++ *
++ * HISTORY:
++ * Date Modifier Ver Notes
++ * 28Feb02 Greg 1.00 Original
++ * 06Mar02 Greg 1.01 Documentation enhanced
++ * 18Jul02 Greg 1.02 Many updates (OAM additions, general reorg)
++ * 22Nov02 Mick RC2 Additions from Denis' input on Control
++ *
++ * author Greg Guyotte
++ * version 1.02
++ * date 18-Jul-2002
++ *****************************************************************************/
++#ifndef _INC_CPHAL_H
++#define _INC_CPHAL_H
++
++#ifdef _CPHAL_CPMAC
++#include "ec_errors_cpmac.h"
++#endif
++
++#ifdef _CPHAL_AAL5
++#include "ec_errors_cpaal5.h"
++#endif
++
++#ifdef _CPHAL_CPSAR
++#include "ec_errors_cpsar.h"
++#endif
++
++#ifdef _CPHAL_AAL2
++#include "ec_errors_cpaal2.h"
++#endif
++
++#ifndef __ADAM2
++typedef char bit8;
++typedef short bit16;
++typedef int bit32;
++
++typedef unsigned char bit8u;
++typedef unsigned short bit16u;
++typedef unsigned int bit32u;
++
++/*
++typedef char INT8;
++typedef short INT16;
++typedef int INT32;
++typedef unsigned char UINT8;
++typedef unsigned short UINT16;
++typedef unsigned int UINT32;
++*/
++/*typedef unsigned int size_t;*/
++#endif
++
++#ifdef _CPHAL
++
++#ifndef TRUE
++#define TRUE (1==1)
++#endif
++
++#ifndef FALSE
++#define FALSE (1==2)
++#endif
++
++#ifndef NULL
++#define NULL 0
++#endif
++
++#endif
++
++#define VirtToPhys(a) (((int)a)&~0xe0000000)
++#define VirtToVirtNoCache(a) ((void*)((VirtToPhys(a))|0xa0000000))
++#define VirtToVirtCache(a) ((void*)((VirtToPhys(a))|0x80000000))
++#define PhysToVirtNoCache(a) ((void*)(((int)a)|0xa0000000))
++#define PhysToVirtCache(a) ((void*)(((int)a)|0x80000000))
++/*
++#define DataCacheHitInvalidate(a) {__asm__(" cache 17, (%0)" : : "r" (a));}
++#define DataCacheHitWriteback(a) {__asm__(" cache 25, (%0)" : : "r" (a));}
++*/
++
++#define PARTIAL 1 /**< Used in @c Close() and @c ChannelTeardown() */
++#define FULL 2 /**< Used in @c Close() and @c ChannelTeardown() */
++
++/* Channel Teardown Defines */
++#define RX_TEARDOWN 2
++#define TX_TEARDOWN 1
++#define BLOCKING_TEARDOWN 8
++#define FULL_TEARDOWN 4
++#define PARTIAL_TEARDOWN 0
++
++#define MAX_DIR 2
++#define DIRECTION_TX 0
++#define DIRECTION_RX 1
++#define TX_CH 0
++#define RX_CH 1
++#define HAL_ERROR_DEVICE_NOT_FOUND 1
++#define HAL_ERROR_FAILED_MALLOC 2
++#define HAL_ERROR_OSFUNC_SIZE 3
++#define HAL_DEFAULT 0xFFFFFFFF
++#define VALID(val) (val!=HAL_DEFAULT)
++
++/*
++ERROR REPORTING
++
++HAL Module Codes. Each HAL module reporting an error code
++should OR the error code with the respective Module error code
++from the list below.
++*/
++#define EC_AAL5 EC_HAL|EC_DEV_AAL5
++#define EC_AAL2 EC_HAL|EC_DEV_AAL2
++#define EC_CPSAR EC_HAL|EC_DEV_CPSAR
++#define EC_CPMAC EC_HAL|EC_DEV_CPMAC
++#define EC_VDMA EC_HAL|EC_DEV_VDMA
++#define EC_VLYNQ EC_HAL|EC_DEV_VLYNQ
++#define EC_CPPI EC_HAL|EC_DEV_CPPI
++
++/*
++HAL Function Codes. Each HAL module reporting an error code
++should OR the error code with one of the function codes from
++the list below.
++*/
++#define EC_FUNC_HAL_INIT EC_FUNC(1)
++#define EC_FUNC_CHSETUP EC_FUNC(2)
++#define EC_FUNC_CHTEARDOWN EC_FUNC(3)
++#define EC_FUNC_RXRETURN EC_FUNC(4)
++#define EC_FUNC_SEND EC_FUNC(5)
++#define EC_FUNC_RXINT EC_FUNC(6)
++#define EC_FUNC_TXINT EC_FUNC(7)
++#define EC_FUNC_AAL2_VDMA EC_FUNC(8)
++#define EC_FUNC_OPTIONS EC_FUNC(9)
++#define EC_FUNC_PROBE EC_FUNC(10)
++#define EC_FUNC_OPEN EC_FUNC(11)
++#define EC_FUNC_CONTROL EC_FUNC(12)
++#define EC_FUNC_DEVICE_INT EC_FUNC(13)
++#define EC_FUNC_STATUS EC_FUNC(14)
++#define EC_FUNC_TICK EC_FUNC(15)
++#define EC_FUNC_CLOSE EC_FUNC(16)
++#define EC_FUNC_SHUTDOWN EC_FUNC(17)
++#define EC_FUNC_DEVICE_INT_ALT EC_FUNC(18) /* +GSG 030306 */
++
++/*
++HAL Error Codes. The list below defines every type of error
++used in all HAL modules. DO NOT CHANGE THESE VALUES! Add new
++values in integer order to the bottom of the list.
++*/
++#define EC_VAL_PDSP_LOAD_FAIL EC_ERR(0x01)|EC_CRITICAL
++#define EC_VAL_FIRMWARE_TOO_LARGE EC_ERR(0x02)|EC_CRITICAL
++#define EC_VAL_DEVICE_NOT_FOUND EC_ERR(0x03)|EC_CRITICAL
++#define EC_VAL_BASE_ADDR_NOT_FOUND EC_ERR(0x04)|EC_CRITICAL
++#define EC_VAL_RESET_BIT_NOT_FOUND EC_ERR(0x05)|EC_CRITICAL
++#define EC_VAL_CH_INFO_NOT_FOUND EC_ERR(0x06)
++#define EC_VAL_RX_STATE_RAM_NOT_CLEARED EC_ERR(0x07)|EC_CRITICAL
++#define EC_VAL_TX_STATE_RAM_NOT_CLEARED EC_ERR(0x08)|EC_CRITICAL
++#define EC_VAL_MALLOC_DEV_FAILED EC_ERR(0x09)
++#define EC_VAL_OS_VERSION_NOT_SUPPORTED EC_ERR(0x0A)|EC_CRITICAL
++#define EC_VAL_CPSAR_VERSION_NOT_SUPPORTED EC_ERR(0x0B)|EC_CRITICAL
++#define EC_VAL_NULL_CPSAR_DEV EC_ERR(0x0C)|EC_CRITICAL
++
++#define EC_VAL_LUT_NOT_READY EC_ERR(0x0D)
++#define EC_VAL_INVALID_CH EC_ERR(0x0E)
++#define EC_VAL_NULL_CH_STRUCT EC_ERR(0x0F)
++#define EC_VAL_RX_TEARDOWN_ALREADY_PEND EC_ERR(0x10)
++#define EC_VAL_TX_TEARDOWN_ALREADY_PEND EC_ERR(0x11)
++#define EC_VAL_RX_CH_ALREADY_TORNDOWN EC_ERR(0x12)
++#define EC_VAL_TX_CH_ALREADY_TORNDOWN EC_ERR(0x13)
++#define EC_VAL_TX_TEARDOWN_TIMEOUT EC_ERR(0x14)
++#define EC_VAL_RX_TEARDOWN_TIMEOUT EC_ERR(0x15)
++#define EC_VAL_CH_ALREADY_TORNDOWN EC_ERR(0x16)
++#define EC_VAL_VC_SETUP_NOT_READY EC_ERR(0x17)
++#define EC_VAL_VC_TEARDOWN_NOT_READY EC_ERR(0x18)
++#define EC_VAL_INVALID_VC EC_ERR(0x19)
++#define EC_VAL_INVALID_LC EC_ERR(0x20)
++#define EC_VAL_INVALID_VDMA_CH EC_ERR(0x21)
++#define EC_VAL_INVALID_CID EC_ERR(0x22)
++#define EC_VAL_INVALID_UUI EC_ERR(0x23)
++#define EC_VAL_INVALID_UUI_DISCARD EC_ERR(0x24)
++#define EC_VAL_CH_ALREADY_OPEN EC_ERR(0x25)
++
++#define EC_VAL_RCB_MALLOC_FAILED EC_ERR(0x26)
++#define EC_VAL_RX_BUFFER_MALLOC_FAILED EC_ERR(0x27)
++#define EC_VAL_OUT_OF_TCBS EC_ERR(0x28)
++#define EC_VAL_NO_TCBS EC_ERR(0x29)
++#define EC_VAL_NULL_RCB EC_ERR(0x30)|EC_CRITICAL
++#define EC_VAL_SOP_ERROR EC_ERR(0x31)|EC_CRITICAL
++#define EC_VAL_EOP_ERROR EC_ERR(0x32)|EC_CRITICAL
++#define EC_VAL_NULL_TCB EC_ERR(0x33)|EC_CRITICAL
++#define EC_VAL_CORRUPT_RCB_CHAIN EC_ERR(0x34)|EC_CRITICAL
++#define EC_VAL_TCB_MALLOC_FAILED EC_ERR(0x35)
++
++#define EC_VAL_DISABLE_POLLING_FAILED EC_ERR(0x36)
++#define EC_VAL_KEY_NOT_FOUND EC_ERR(0x37)
++#define EC_VAL_MALLOC_FAILED EC_ERR(0x38)
++#define EC_VAL_RESET_BASE_NOT_FOUND EC_ERR(0x39)|EC_CRITICAL
++#define EC_VAL_INVALID_STATE EC_ERR(0x40)
++#define EC_VAL_NO_TXH_WORK_TO_DO EC_ERR(0x41)
++#define EC_VAL_NO_TXL_WORK_TO_DO EC_ERR(0x42)
++#define EC_VAL_NO_RX_WORK_TO_DO EC_ERR(0x43)
++#define EC_VAL_NOT_LINKED EC_ERR(0x44)
++#define EC_VAL_INTERRUPT_NOT_FOUND EC_ERR(0x45)
++#define EC_VAL_OFFSET_NOT_FOUND EC_ERR(0x46)
++#define EC_VAL_MODULE_ALREADY_CLOSED EC_ERR(0x47)
++#define EC_VAL_MODULE_ALREADY_SHUTDOWN EC_ERR(0x48)
++#define EC_VAL_ACTION_NOT_FOUND EC_ERR(0x49)
++#define EC_VAL_RX_CH_ALREADY_SETUP EC_ERR(0x50)
++#define EC_VAL_TX_CH_ALREADY_SETUP EC_ERR(0x51)
++#define EC_VAL_RX_CH_ALREADY_OPEN EC_ERR(0x52)
++#define EC_VAL_TX_CH_ALREADY_OPEN EC_ERR(0x53)
++#define EC_VAL_CH_ALREADY_SETUP EC_ERR(0x54)
++#define EC_VAL_RCB_NEEDS_BUFFER EC_ERR(0x55) /* +GSG 030410 */
++#define EC_VAL_RCB_DROPPED EC_ERR(0x56) /* +GSG 030410 */
++#define EC_VAL_INVALID_VALUE EC_ERR(0x57)
++
++/**
++@defgroup shared_data Shared Data Structures
++
++The data structures documented here are shared by all modules.
++*/
++
++/**
++ * @ingroup shared_data
++ * This is the fragment list structure. Each fragment list entry contains a
++ * length and a data buffer.
++ */
++typedef struct
++ {
++ bit32u len; /**< Length of the fragment in bytes (lower 16 bits are valid). For SOP, upper 16 bits is the buffer offset. */
++ void *data; /**< Pointer to fragment data. */
++ void *OsInfo; /**< Pointer to OS defined data. */
++ }FRAGLIST;
++
++#if defined (_CPHAL_CPMAC)
++#define CB_PASSCRC_BIT (1<<26)
++
++/* CPMAC CPHAL STATUS */
++#define CPMAC_STATUS_LINK (1 << 0)
++#define CPMAC_STATUS_LINK_DUPLEX (1 << 1) /* 0 - HD, 1 - FD */
++#define CPMAC_STATUS_LINK_SPEED (1 << 2) /* 0 - 10, 1 - 100 */
++
++/* ADAPTER CHECK Codes */
++
++#define CPMAC_STATUS_ADAPTER_CHECK (1 << 7)
++#define CPMAC_STATUS_HOST_ERR_DIRECTION (1 << 8)
++#define CPMAC_STATUS_HOST_ERR_CODE (0xF << 9)
++#define CPMAC_STATUS_HOST_ERR_CH (0x7 << 13)
++
++#define _CPMDIO_DISABLE (1 << 0)
++#define _CPMDIO_HD (1 << 1)
++#define _CPMDIO_FD (1 << 2)
++#define _CPMDIO_10 (1 << 3)
++#define _CPMDIO_100 (1 << 4)
++#define _CPMDIO_NEG_OFF (1 << 5)
++#define _CPMDIO_LOOPBK (1 << 16)
++#define _CPMDIO_AUTOMDIX (1 << 17) /* Bit 16 and above not used by MII register */
++#define _CPMDIO_NOPHY (1 << 20)
++#endif
++
++/**
++ * @ingroup shared_data
++ * Channel specific configuration information. This structure should be
++ * populated by upper-layer software prior to calling @c ChannelSetup(). Any
++ * configuration item that can be changed on a per channel basis should
++ * be represented here. Each module may define this structure with additional
++ * module-specific members.
++ */
++typedef struct
++ {
++ int Channel; /**< Channel number. */
++ int Direction; /**< DIRECTION_RX(1) or DIRECTION_TX(0). */
++ OS_SETUP *OsSetup; /**< OS defined information associated with this channel. */
++
++#if defined(_CPHAL_AAL5) || defined (_CPHAL_CPSAR) || defined (_CPHAL_CPMAC)
++ int RxBufSize; /**< Size (in bytes) for each Rx buffer.*/
++ int RxBufferOffset; /**< Number of bytes to offset rx data from start of buffer (must be less than buffer size). */
++ int RxNumBuffers; /**< The number of Rx buffer descriptors to allocate for Ch. */
++ int RxServiceMax; /**< Maximum number of packets to service at one time. */
++
++ int TxNumBuffers; /**< The number of Tx buffer descriptors to allocate for Ch. */
++ int TxNumQueues; /**< Number of Tx queues for this channel (1-2). Choosing 2 enables a low priority SAR queue. */
++ int TxServiceMax; /**< Maximum number of packets to service at one time. */
++#endif
++
++#if defined(_CPHAL_AAL5) || defined(_CPHAL_CPSAR)
++ int CpcsUU; /**< The 2-byte CPCS UU and CPI information. */
++ int Gfc; /**< Generic Flow Control. */
++ int Clp; /**< Cell Loss Priority. */
++ int Pti; /**< Payload Type Indication. */
++#endif
++
++#if defined(_CPHAL_AAL2) || defined(_CPHAL_AAL5) || defined(_CPHAL_CPSAR)
++ int DaMask; /**< Specifies whether credit issuance is paused when Tx data not available. */
++ int Priority; /**< Priority bin this channel will be scheduled within. */
++ int PktType; /**< 0=AAL5,1=Null AAL,2=OAM,3=Transparent,4=AAL2. */
++ int Vci; /**< Virtual Channel Identifier. */
++ int Vpi; /**< Virtual Path Identifier. */
++ int FwdUnkVc; /**< Enables forwarding of unknown VCI/VPI cells to host. 1=enable, 0=disable. */
++
++ /* Tx VC State */
++ int TxVc_CellRate; /**< Tx rate, set as clock ticks between transmissions (SCR for VBR, CBR for CBR). */
++ int TxVc_QosType; /**< 0=CBR,1=VBR,2=UBR,3=UBRmcr. */
++ int TxVc_Mbs; /**< Min Burst Size in cells.*/
++ int TxVc_Pcr; /**< Peak Cell Rate for VBR in clock ticks between transmissions. */
++
++ bit32 TxVc_AtmHeader; /**< ATM Header placed on firmware gen'd OAM cells for this Tx Ch (must be big endian with 0 PTI). */
++ int TxVc_OamTc; /**< TC Path to transmit OAM cells for TX connection (0,1). */
++ int TxVc_VpOffset; /**< Offset to the OAM VP state table. */
++ /* Rx VC State */
++ int RxVc_OamCh; /**< Ch to terminate rx'd OAM cells to be forwarded to the host. */
++ int RxVc_OamToHost; /**< 0=do not pass, 1=pass. */
++ bit32 RxVc_AtmHeader; /**< ATM Header placed on firmware gen'd OAM cells for this Rx conn (must be big endian with 0 PTI). */
++ int RxVc_OamTc; /**< TC Path to transmit OAM cells for RX connection (0,1). */
++ int RxVc_VpOffset; /**< Offset to the OAM VP state table. */
++ /* Tx VP State */
++ int TxVp_OamTc; /**< TC Path to transmit OAM cells for TX VP connection (0,1). */
++ bit32 TxVp_AtmHeader; /**< ATM Header placed on firmware gen'd VP OAM cells for this Tx VP conn (must be big endian with 0 VCI). */
++ /* Rx VP State */
++ int RxVp_OamCh; /**< Ch to terminate rx'd OAM cells to be forwarded to the host. */
++ int RxVp_OamToHost; /**< 0=do not pass, 1=pass. */
++ bit32 RxVp_AtmHeader; /**< ATM Header placed on firmware gen'd OAM cells for this Rx VP conn (must be big endian with 0 VCI). */
++ int RxVp_OamTc; /**< TC Path to transmit OAM cells for RX VP connection (0,1). */
++ int RxVp_OamVcList; /**< Indicates all VC channels associated with this VP channel (one-hot encoded). */
++#endif
++
++
++#ifdef _CPHAL_VDMAVT
++ bit32u RemFifoAddr; /* Mirror mode only. */
++ bit32u FifoAddr;
++ bit32 PollInt;
++ bit32 FifoSize;
++ int Ready;
++#endif
++
++ }CHANNEL_INFO;
++
++/*
++ * This structure contains each statistic value gathered by the CPHAL.
++ * Applications may access statistics data by using the @c StatsGet() routine.
++ */
++/* STATS */
++#if defined(_CPHAL_AAL2) || defined(_CPHAL_AAL5) || defined(_CPHAL_CPSAR)
++typedef struct
++ {
++ bit32u CrcErrors[16];
++ bit32u LenErrors[16];
++ bit32u DmaLenErrors[16];
++ bit32u AbortErrors[16];
++ bit32u StarvErrors[16];
++ bit32u TxMisQCnt[16][2];
++ bit32u RxMisQCnt[16];
++ bit32u RxEOQCnt[16];
++ bit32u TxEOQCnt[16][2];
++ bit32u RxPacketsServiced[16];
++ bit32u TxPacketsServiced[16][2];
++ bit32u RxMaxServiced;
++ bit32u TxMaxServiced[16][2];
++ bit32u RxTotal;
++ bit32u TxTotal;
++ } STAT_INFO;
++#endif
++
++/*
++ * VDMA Channel specific configuration information
++ */
++#ifdef _CPHAL_AAL2
++typedef struct
++ {
++ int Ch; /**< Channel Number */
++ int RemoteEndian; /**< Endianness of remote VDMA-VT device */
++ int CpsSwap; /**< When 0, octet 0 in CPS pkt located in LS byte of 16-bit word sent to rem VDMA device. When 1, in MS byte. */
++ }VdmaChInfo;
++#endif
++
++#ifndef _CPHAL
++ typedef void HAL_DEVICE;
++ typedef void HAL_PRIVATE;
++ typedef void HAL_RCB;
++ typedef void HAL_RECEIVEINFO;
++#endif
++
++/**
++ * @ingroup shared_data
++ * The HAL_FUNCTIONS struct defines the function pointers used by upper layer
++ * software. The upper layer software receives these pointers through the
++ * call to xxxInitModule().
++ */
++typedef struct
++ {
++ int (*ChannelSetup) (HAL_DEVICE *HalDev, CHANNEL_INFO *Channel, OS_SETUP *OsSetup);
++ int (*ChannelTeardown) (HAL_DEVICE *HalDev, int Channel, int Mode);
++ int (*Close) (HAL_DEVICE *HalDev, int Mode);
++ int (*Control) (HAL_DEVICE *HalDev, const char *Key, const char *Action, void *Value);
++ int (*Init) (HAL_DEVICE *HalDev);
++ int (*Open) (HAL_DEVICE *HalDev);
++ int (*PacketProcessEnd) (HAL_DEVICE *HalDev);
++ int (*Probe) (HAL_DEVICE *HalDev);
++ int (*RxReturn) (HAL_RECEIVEINFO *HalReceiveInfo, int StripFlag);
++ int (*Send) (HAL_DEVICE *HalDev, FRAGLIST *FragList, int FragCount, int PacketSize, OS_SENDINFO *OsSendInfo, bit32u Mode);
++ int (*Shutdown) (HAL_DEVICE *HalDev);
++ int (*Tick) (HAL_DEVICE *HalDev);
++
++#ifdef _CPHAL_AAL5
++ int (*Kick) (HAL_DEVICE *HalDev, int Queue);
++ void (*OamFuncConfig) (HAL_DEVICE *HalDev, unsigned int OamConfig);
++ void (*OamLoopbackConfig) (HAL_DEVICE *HalDev, unsigned int OamConfig, unsigned int *LLID, unsigned int CorrelationTag);
++ volatile bit32u* (*RegAccess)(HAL_DEVICE *HalDev, bit32u RegOffset);
++ STAT_INFO* (*StatsGetOld)(HAL_DEVICE *HalDev);
++#endif
++ } HAL_FUNCTIONS;
++
++/**
++ * @ingroup shared_data
++ * The OS_FUNCTIONS struct defines the function pointers for all upper layer
++ * functions accessible to the CPHAL. The upper layer software is responsible
++ * for providing the correct OS-specific implementations for the following
++ * functions. It is populated by calling InitModule() (done by the CPHAL in
++ * xxxInitModule().
++ */
++typedef struct
++ {
++ int (*Control)(OS_DEVICE *OsDev, const char *Key, const char *Action, void *Value);
++ void (*CriticalOn)(void);
++ void (*CriticalOff)(void);
++ void (*DataCacheHitInvalidate)(void *MemPtr, int Size);
++ void (*DataCacheHitWriteback)(void *MemPtr, int Size);
++ int (*DeviceFindInfo)(int Inst, const char *DeviceName, void *DeviceInfo);
++ int (*DeviceFindParmUint)(void *DeviceInfo, const char *Parm, bit32u *Value);
++ int (*DeviceFindParmValue)(void *DeviceInfo, const char *Parm, void *Value);
++ void (*Free)(void *MemPtr);
++ void (*FreeRxBuffer)(OS_RECEIVEINFO *OsReceiveInfo, void *MemPtr);
++ void (*FreeDev)(void *MemPtr);
++ void (*FreeDmaXfer)(void *MemPtr);
++ void (*IsrRegister)(OS_DEVICE *OsDev, int (*halISR)(HAL_DEVICE*, int*), int InterruptBit);
++ void (*IsrUnRegister)(OS_DEVICE *OsDev, int InterruptBit);
++ void* (*Malloc)(bit32u size);
++ void* (*MallocDev)(bit32u Size);
++ void* (*MallocDmaXfer)(bit32u size, void *MemBase, bit32u MemRange);
++ void* (*MallocRxBuffer)(bit32u size, void *MemBase, bit32u MemRange,
++ OS_SETUP *OsSetup, HAL_RECEIVEINFO *HalReceiveInfo,
++ OS_RECEIVEINFO **OsReceiveInfo, OS_DEVICE *OsDev);
++ void* (*Memset)(void *Dest, int C, bit32u N);
++ int (*Printf)(const char *Format, ...);
++ int (*Receive)(OS_DEVICE *OsDev,FRAGLIST *FragList,bit32u FragCount,
++ bit32u PacketSize,HAL_RECEIVEINFO *HalReceiveInfo, bit32u Mode);
++ int (*SendComplete)(OS_SENDINFO *OsSendInfo);
++ int (*Sprintf)(char *S, const char *Format, ...);
++ int (*Strcmpi)(const char *Str1, const char *Str2);
++ unsigned int (*Strlen)(const char *S);
++ char* (*Strstr)(const char *S1, const char *S2);
++ unsigned long (*Strtoul)(const char *Str, char **Endptr, int Base);
++ void (*TeardownComplete)(OS_DEVICE *OsDev, int Ch, int Direction);
++ } OS_FUNCTIONS;
++
++/************** MODULE SPECIFIC STUFF BELOW **************/
++
++#ifdef _CPHAL_CPMAC
++
++/*
++int halCpmacInitModule(HAL_DEVICE **HalDev, OS_DEVICE *OsDev, HAL_FUNCTIONS *HalFunc, int (*osBridgeInitModule)(OS_FUNCTIONS *), void* (*osMallocDev) (bit32u), int *Size, int inst);
++*/
++
++int halCpmacInitModule(HAL_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ HAL_FUNCTIONS **HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++#endif
++
++#ifdef _CPHAL_AAL5
++/*
++ * @ingroup shared_data
++ * The AAL5_FUNCTIONS struct defines the AAL5 function pointers used by upper layer
++ * software. The upper layer software receives these pointers through the
++ * call to cphalInitModule().
++ */
++/*
++typedef struct
++ {
++ int (*ChannelSetup)(HAL_DEVICE *HalDev, CHANNEL_INFO *HalCh, OS_SETUP *OsSetup);
++ int (*ChannelTeardown)(HAL_DEVICE *HalDev, int Ch, int Mode);
++ int (*Close)(HAL_DEVICE *HalDev, int Mode);
++ int (*Init)(HAL_DEVICE *HalDev);
++ int (*ModeChange)(HAL_DEVICE *HalDev, char *DeviceParms);
++ int (*Open)(HAL_DEVICE *HalDev);
++ int (*InfoGet)(HAL_DEVICE *HalDev, int Key, void *Value);
++ int (*Probe)(HAL_DEVICE *HalDev);
++ int (*RxReturn)(HAL_RECEIVEINFO *HalReceiveInfo, int StripFlag);
++ int (*Send)(HAL_DEVICE *HalDev,FRAGLIST *FragList,int FragCount,
++ int PacketSize,OS_SENDINFO *OsSendInfo,int Ch, int Queue,
++ bit32u Mode);
++ int (*StatsClear)(HAL_DEVICE *HalDev);
++ STAT_INFO* (*StatsGet)(HAL_DEVICE *HalDev);
++ int (*Status)(HAL_DEVICE *HalDev);
++ void (*Tick)(HAL_DEVICE *HalDev);
++ int (*Kick)(HAL_DEVICE *HalDev, int Queue);
++ volatile bit32u* (*RegAccess)(HAL_DEVICE *HalDev, bit32u RegOffset);
++ } AAL5_FUNCTIONS;
++*/
++
++int cpaal5InitModule(HAL_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ HAL_FUNCTIONS **HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++#endif
++
++#ifdef _CPHAL_AAL2
++/**
++ * @ingroup shared_data
++ * The AAL2_FUNCTIONS struct defines the AAL2 function pointers used by upper layer
++ * software. The upper layer software receives these pointers through the
++ * call to cphalInitModule().
++ */
++typedef struct
++ {
++ int (*ChannelSetup)(HAL_DEVICE *HalDev, CHANNEL_INFO *HalCh, OS_SETUP *OsSetup);
++ int (*ChannelTeardown)(HAL_DEVICE *HalDev, int Ch, int Mode);
++ int (*Close)(HAL_DEVICE *HalDev, int Mode);
++ int (*Init)(HAL_DEVICE *HalDev);
++ int (*ModeChange)(HAL_DEVICE *HalDev, char *DeviceParms);
++ int (*Open)(HAL_DEVICE *HalDev);
++ int (*OptionsGet)(HAL_DEVICE *HalDev, char *Key, bit32u *Value);
++ int (*Probe)(HAL_DEVICE *HalDev);
++
++ int (*StatsClear)(HAL_DEVICE *HalDev);
++ STAT_INFO* (*StatsGet)(HAL_DEVICE *HalDev);
++ int (*Status)(HAL_DEVICE *HalDev);
++ void (*Tick)(HAL_DEVICE *HalDev);
++ int (*Aal2UuiMappingSetup)(HAL_DEVICE *HalDev, int VC, int UUI,
++ int VdmaCh, int UUIDiscard);
++ int (*Aal2RxMappingSetup)(HAL_DEVICE *HalDev, int VC, int CID,
++ int LC);
++ int (*Aal2TxMappingSetup)(HAL_DEVICE *HalDev, int VC, int LC, int VdmaCh);
++ int (*Aal2VdmaChSetup)(HAL_DEVICE *HalDev, bit32u RemVdmaVtAddr,
++ VdmaChInfo *VdmaCh);
++ volatile bit32u* (*RegAccess)(HAL_DEVICE *HalDev, bit32u RegOffset);
++ int (*Aal2ModeChange)(HAL_DEVICE *HalDev, int Vc, int RxCrossMode,
++ int RxMultiMode, int TxMultiMode, int SchedMode,
++ int TcCh);
++ void (*Aal2VdmaEnable)(HAL_DEVICE *HalDev, int Ch);
++ int (*Aal2VdmaDisable)(HAL_DEVICE *HalDev, int Ch);
++ } AAL2_FUNCTIONS;
++
++int cpaal2InitModule(HAL_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ AAL2_FUNCTIONS **HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++#endif
++
++#ifdef _CPHAL_VDMAVT
++/**
++ * @ingroup shared_data
++ * The VDMA_FUNCTIONS struct defines the HAL function pointers used by upper layer
++ * software. The upper layer software receives these pointers through the
++ * call to InitModule().
++ *
++ * Note that this list is still under definition.
++ */
++typedef struct
++ {
++ bit32 (*Init)( HAL_DEVICE *VdmaVtDev);
++ /* bit32 (*SetupTxFifo)(HAL_DEVICE *VdmaVtDev, bit32u LclRem,
++ bit32u Addr, bit32u Size, bit32u PollInt);
++ bit32 (*SetupRxFifo)(HAL_DEVICE *VdmaVtDev, bit32u LclRem,
++ bit32u Addr, bit32u Size, bit32u PollInt); */
++ bit32 (*Tx)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*Rx)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*SetRemoteChannel)(HAL_DEVICE *VdmaVtDev, bit32u RemAddr,
++ bit32u RemDevID);
++ bit32 (*ClearRxInt)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*ClearTxInt)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*Open)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*Close)(HAL_DEVICE *VdmaVtDev);
++ int (*Control) (HAL_DEVICE *HalDev, const char *Key, const char *Action, void *Value);
++ int (*ChannelSetup)(HAL_DEVICE *VdmaVtDev, CHANNEL_INFO *HalCh, OS_SETUP *OsSetup);
++ int (*ChannelTeardown)(HAL_DEVICE *VdmaVtDev, int Ch, int Mode);
++ int (*Send)(HAL_DEVICE *VdmaVtDev,FRAGLIST *FragList,int FragCount,
++ int PacketSize,OS_SENDINFO *OsSendInfo,bit32u Mode);
++ } VDMA_FUNCTIONS;
++
++int VdmaInitModule(HAL_DEVICE **VdmaVt,
++ OS_DEVICE *OsDev,
++ VDMA_FUNCTIONS **VdmaVtFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++#endif
++
++/*
++extern int cphalInitModule(MODULE_TYPE ModuleType, HAL_DEVICE **HalDev, OS_DEVICE *OsDev, HAL_FUNCTIONS *HalFunc,
++ int (*osInitModule)(OS_FUNCTIONS *), void* (*osMallocDev)(bit32u),
++ int *Size, int Inst);
++*/
++
++
++#ifdef _CPHAL_AAL5
++extern const char hcSarFrequency[];
++#endif
++
++#ifdef _CPHAL_CPMAC
++/* following will be common, once 'utl' added */
++extern const char hcClear[];
++extern const char hcGet[];
++extern const char hcSet[];
++extern const char hcTick[];
++
++extern const char hcCpuFrequency[];
++extern const char hcCpmacFrequency[];
++extern const char hcMdioBusFrequency[];
++extern const char hcMdioClockFrequency[];
++extern const char hcCpmacBase[];
++extern const char hcPhyNum[];
++extern const char hcSize[];
++extern const char hcCpmacSize[];
++extern const char hcPhyAccess[];
++extern const char hcMdixMask[];
++extern const char hcMdioMdixSwitch[];
++#endif
++
++#endif /* end of _INC_ */
+diff -urN linux.old/drivers/net/avalanche_cpmac/dox_cpmac.h linux.dev/drivers/net/avalanche_cpmac/dox_cpmac.h
+--- linux.old/drivers/net/avalanche_cpmac/dox_cpmac.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/dox_cpmac.h 2005-07-12 02:48:42.050593000 +0200
+@@ -0,0 +1,842 @@
++/*****************************************************************************
++ * TNETDxxxx Software Support
++ * Copyright (c) 2002,2003 Texas Instruments Incorporated. All Rights Reserved.
++ *
++ * FILE:
++ *
++ * DESCRIPTION:
++ * This file contains documentation for the CPMAC
++ *
++ * HISTORY:
++ * @author Michael Hanrahan/Greg Guyotte
++ * @version 1.00
++ * @date 03-Dec-2002
++ *****************************************************************************/
++#ifndef _DOX_CPMAC_H
++#define _DOX_CPMAC_H
++/**
++@page CPMAC_Implementation_Details Version
++
++@copydoc CPMAC_Version
++*/
++
++/**
++@page cpmac_intro Introduction
++
++The CPMAC implementation will support 8 channels for transmit and 8 channel for
++receive. Each of the 8 transmit channels has 1 queue associated with it. It is
++recommended that only 1 channel is used for @c Receive() per processor.
++*/
++
++/**
++@page cpmac_details API Implementation Details
++@par osReceive
++@p Mode parameter
++- The Upper 16 bits of Mode match Word 3 of the Rx Buffer Descriptor
++
++@par halSend
++@p Mode parameter
++- Bits 0-7 contain the Channel Number
++- Bits 8-25 are reserved
++- Bit 26 - if 0, the CRC will be calculated, if 1 the CRC will be Passed
++- Bits 27-31 : reserved
++@section cpmac_keys Control Keys
++
++@par StateChange
++CPHAL calls the OS when a state change is detected.
++OS should check the CPMAC Status. See the Control Key 'Status' for more details.
++
++@par Status
++OS calls the CPHAL to obtain Status information. The Returned status is as follows
++
++@par MaxFrags
++The OS may "Set" or "Get" this value. This defines the maximum
++number of fragments that can be received by the CPMAC Rx port. The default
++value for CPMAC is 2. This provides enough space to receive a maximum
++length packet (1,518 bytes) with the default buffer size of 1518 and any
++amount of RxBufferOffset. If the buffer size is configured to be smaller,
++the OS *MUST* modify this parameter according to the following formula:
++((System Max packet length)/(RxBufSize)) + 1. (The extra 1 fragment is to
++allow for RxBufferOffset)
++
++@code
++// Following defined in "cpswhal_cpmac.h"
++// CPMAC CPHAL STATUS
++#define CPMAC_STATUS_LINK (1 << 0)
++#define CPMAC_STATUS_LINK_DUPLEX (1 << 1) // 0 - HD, 1 - FD
++#define CPMAC_STATUS_LINK_SPEED (1 << 2) // 0 - 10, 1 - 100
++
++// ADAPTER CHECK Codes
++#define CPMAC_STATUS_ADAPTER_CHECK (1 << 7)
++#define CPMAC_STATUS_HOST_ERR_DIRECTION (1 << 8) // 0 - Tx, 1 - Rx
++#define CPMAC_STATUS_HOST_ERR_CODE (0xF << 9) See CPMAC Guide
++#define CPMAC_STATUS_HOST_ERR_CH (0x7 << 13) See CPMAC Guide
++@endcode
++
++@code
++void osStateChange(OS_DEVICE *OsDev)
++ {
++ int status;
++ OsDev->HalFunc->Control(OsDev->HalDev, "Status", hcGet, &status);
++ if(status & CPMAC_STATUS_ADAPTER_CHECK)
++ {
++ printf("[osStateChange[%d]] HAL notified OS of AdapterCheck (Link Status 0x%08X)\n", OsDev->port, status);
++ adaptercheck(OsDev->port);
++ }
++ else
++ {
++ printf("[osStateChange[%d]] HAL notified OS of State Change (Link Status %s)\n", OsDev->port, (status & CPMAC_STATUS_LINK) ? "Up" : "Down");
++ if(status & CPMAC_STATUS_LINK)
++ {
++ printf("Speed %s, Duplex %s\n",
++ status & CPMAC_STATUS_LINK_SPEED ? "100" : "10",
++ status & CPMAC_STATUS_LINK_DUPLEX ? "FD" : "HD");
++ }
++ }
++@endcode
++
++@par Tick
++ The CPHAL calls the OS to set the interval for calling halTick()<BR>
++ Note: Predefined value hcTick now recommended for use.
++@code
++*** Example Code ***
++
++*** CPHAL code ***
++int Ticks;
++HalDev->OsFunc->Control(HalDev->OsDev, hcTick, hcSet, &Ticks);
++
++*** OS code ***
++ ..
++ if(osStrcmpi(pszKey, hcTick) == 0)
++ {
++ if(osStrcmpi(pszAction, hcSet) == 0)
++ {
++ // Enable the Tick Interval
++ if(*(unsigned int *) ParmValue)
++ printf("osTickSet: Interval = %d ticks\n", Interval);
++ }
++ else
++ if(osStrcmpi(pszAction, hcClear) == 0)
++ {
++ // Request disabling of the Tick Timer, ParmValue is ignored
++ }
++ }
++@endcode
++
++@par The following information can be obtained by the OS via 'Get'
++
++- StatsDump : OS supplies pointer to an 36 element unsigned int array
++CPHAL will populate the array with the current Statistics values.<BR>
++Note: all hcXXXX values are predefined and should be used by the OS.
++
++- hcPhyNum : Returns the PHY number.
++- hcCpmacBase : Returns the base-address of the CPMAC device
++- hcCpmacSize : Returns size of the CPMAC memory map
++
++
++@par Phy Register Communication
++
++halControl() is used to read and write the Phy Registers via the key hcPhyAccess
++
++Both reading and writing the Phy registers involve setting the Value parameter of halControl()
++<BR>
++Value is a 32-bit value with bits partioned as follows
++<BR>
++
++ 0 - 4 Phy Number <BR>
++ 5 - 9 Phy Register <BR>
++ 10 - 15 reserved <BR>
++ 16 - 31 Data (write only)
++<BR>
++
++
++<B>Reading the Phy register</B>
++
++@code
++ bit32u Value;
++ bit32u RegAddr;
++ bit32u PhyNum;
++ bit32u PhyRegisterData;
++
++ // Read Phy 31, register 20
++
++ PhyNum = 31;
++ RegAddr = 20;
++
++ Value = (RegAddr << 5);
++ Value |= (PhyNum & 0x1F);
++
++ rc = HalFunc->Control(HalDev, hcPhyAccess, hcGet, (bit32u *) &Value)
++ If(rc == 0)
++ {
++ // Value is overwriten with the value in Register 20 of Phy number 31.
++ PhyRegisterData = Value;
++ }
++@endcode
++
++<B>Writing the Phy register</B>
++@code
++ bit32u Value;
++ bit32u RegAddr;
++ bit32u PhyNum;
++ bit32u PhyRegisterData;
++
++ // Reset Phy 23
++
++ PhyNum = 23;
++ RegAddr = 0;
++ PhyRegisterData = 0x8000; // Reset bit set
++
++ Value = (RegAddr << 5);
++ Value |= (PhyNum & 0x1F);
++ Value |= (PhyRegisterData << 16);
++
++ rc = HalFunc->Control(HalDev, hcPhyAccess, hcSet, (bit32u *) &Value)
++
++ // Check is reset if done
++
++ PhyNum = 23;
++ RegAddr = 0;
++
++ Value = (RegAddr << 5);
++ Value |= (PhyNum & 0x1F);
++
++ rc = HalFunc->Control(HalDev, hcPhyAccess, hcGet, (bit32u *) &Value)
++
++ If(rc == 0)
++ {
++ // Value is overwriten with the value in Register 0 of Phy number 23.
++ PhyRegisterData = Value;
++ if((PhyRegisterData & 0x8000) == 0)
++ ResetIsComplete;
++ }
++
++@endcode
++<B>
++*** Example Showing turning values off/on ***
++<BR>
++</B>
++
++@code
++
++int On=1;
++int Off=0;
++ # Turn On loopback
++ OsDev->HalFunc->Control(OsDev->HalDev, "CTRL_LOOPBACK", hcSet, (int*) &On);
++
++ # Turn off RX Flow
++ OsDev->HalFunc->Control(OsDev->HalDev, "RX_FLOW_EN", hcSet, (int*) &Off);
++@endcode
++
++@par CPMAC Configurable Parameters
++
++- RX_PASS_CRC : See MBP_Enable description
++- RX_QOS_EN : See MBP_Enable description
++- RX_NO_CHAIN : See MBP_Enable description
++- RX_CMF_EN : See MBP_Enable description
++- RX_CSF_EN : See MBP_Enable description
++- RX_CEF_EN : See MBP_Enable description
++- RX_CAF_EN : See MBP_Enable description
++- RX_PROM_CH : See MBP_Enable description
++- RX_BROAD_EN : See MBP_Enable description
++- RX_BROAD_CH : See MBP_Enable description
++- RX_MULT_EN : See MBP_Enable description
++- RX_MULT_CH : See MBP_Enable description
++
++- TX_PTYPE : See MacControl description
++- TX_PACE : See MacControl description
++- TX_FLOW_EN : See MacControl description
++- RX_FLOW_EN : See MacControl description
++- CTRL_LOOPBACK : See MacControl description
++
++- RX_MAXLEN : See CPMAC Guide
++- RX_FILTERLOWTHRESH : See CPMAC Guide
++- RX0_FLOWTHRESH : See CPMAC Guide
++- RX_UNICAST_SET : See CPMAC Guide
++- RX_UNICAST_CLEAR : See CPMAC Guide
++
++@par Multicast Support
++- RX_MULTI_ALL : When used with hcSet, sets all the Hash Bits. When used
++with hcClear clears all the Hash Bits.
++- RX_MULTI_SINGLE : When used with hcSet, adds the Hashed Mac Address. When used
++with hcClear deletes the Hashed Mac Address.
++Note: Support will be added to keep track of Single additions and deletions.
++
++@code
++*** Example Code ***
++
++*** OS code ***
++ bit8u MacAddress[6];
++ MacAddress[0] = 0x80;
++ MacAddress[1] = 0x12;
++ MacAddress[2] = 0x34;
++ MacAddress[3] = 0x56;
++ MacAddress[4] = 0x78;
++ MacAddress[5] = 0x78;
++ OsDev->HalFunc->Control(OsDev->HalDev, "RX_MULTI_SINGLE", hcSet, (bit8u*) &MacAddress);
++ OsDev->HalFunc->Control(OsDev->HalDev, "RX_MULTI_SINGLE", hcClear, (bit8u*) &MacAddress);
++ OsDev->HalFunc->Control(OsDev->HalDev, "RX_MULTI_ALL", hcSet, NULL);
++ OsDev->HalFunc->Control(OsDev->HalDev, "RX_MULTI_ALL", hcClear, NULL);
++@endcode
++@par MdioConnect Fields
++<BR>
++- "MdioConnect" : The OS can set the Phy connection using this key. The default connection is Auto-Negotiation ON, All modes possible.
++
++
++- _CPMDIO_HD <----- Allow Half Duplex, default is 1 (On)
++- _CPMDIO_FD <----- Allow Full Duplex, default is 1 (On)
++- _CPMDIO_10 <----- Allow 10 Mbs, default is 1 (On)
++- _CPMDIO_100 <----- Allow 100 Mbs, default is 1 (On)
++- _CPMDIO_NEG_OFF <----- Turn off Auto Negotiation, default is 0 (Auto Neg is on)
++- _CPMDIO_NOPHY <----- Set for use with Marvel-type switch, default is 0 (Phy present)
++- _CPMDIO_AUTOMDIX <---- Enables Auto Mdix (in conjunction with MdixMask), default is 1 (On)
++
++Note: When _CPMDIO_NOPHY is set, CPMAC will report being linked at 100/FD. Reported PhyNum will be 0xFFFFFFFF
++
++@par Setting CPMAC for use with a Marvel-type Switch
++@code
++ bit32u MdioConnect;
++
++ MdioConnect = _CPMDIO_NOPHY;
++ OsDev->HalFunc->Control(OsDev->HalDev, "MdioConnect", hcSet, (bit32u*) &MdioConnect);
++@endcode
++
++@par OS Support for MDIO
++@p The OS will need to supply the following values which the CPHAL will request via halControl()
++<BR>
++- MdioBusFrequency : The frequency of the BUS that MDIO is on (requested via hcMdioBusFrequency)
++<BR>
++- MdioClockFrequency : The desired Clock Frequency that MDIO qill operate at (requested via hcMdioClockFrequency)
++*/
++
++/**
++@page cpmac_conf DeviceFindxxx() Parameters
++
++These are some of the parameters that the CPMAC will request via the DeviceFindxxx() functions -
++<BR>
++- "Mlink" : bit mask indicating what link status method Phy is using. Default is MDIO state machine (0x0)
++- "PhyMask" : bit mask indicating PhyNums used by this CPMAC (e.g 0x8000000, PhyNum is 31)
++- "MdixMask" : bit mask indicating which Phys support AutoMdix. Default is 0x0 (None)
++<BR>
++@par Example cpmac definition from the options.conf for the Sangam VDB
++<BR>
++- cpmac( id=eth0, base=0xA8610000, size=0x800, reset_bit=17, int_line=19, PhyMask=0x80000000, MLink=0, MdixMask=0 )
++*/
++
++/**
++@page auto_mdix Auto Mdix Support
++
++Auto Mdix selection is controlled by two elements in the CPMAC. First the OS can turn Auto Midx On or Off by the use of the
++MdioConnect field, _CPMDIO_AUTOMDIX. This is defaulted ON. For actual Auto Mdix operation the Phy must also be Auto Mdix capable.
++This is specified by the DeviceFindxxx() field, "MdixMask" (supplied as the variable hcMdixMask).
++If both these fields are set then the CPMDIO state machine will be enabled for Auto Mdix checking.
++If a switch to MDI or MDIX mode is needed, the CPMAC will signal this to the OS via Control() using
++the hcMdioMdixSwitch key.
++
++@par OS example for responding to a Mdix Switch Request
++<BR>
++@code
++if(osStrcmpi(pszKey, hcMdioMdixSwitch) == 0) // See if key is Mdix Switch Request
++ {
++ if(osStrcmpi(pszAction, hcSet) == 0) // Only respond to Set requests
++ {
++
++ bit32u Mdix;
++
++ Mdix = *(bit32u *) ParmValue; // Extract requested Mode
++ // 0 : MDI
++ // 1 : MDIX
++ if(Mdix)
++ osSetPhyIntoMdixMode(); // Device specific logic
++ else
++ osSetPhyIntoMdiMode(); // Device specific logic
++ rc = 0; // Set return code as Successfull
++ }
++@endcode
++*/
++
++/**
++@page cpmac_stats CPMAC Specific Statistics
++
++Statistics level '0' contains all CPMAC specific statistics.
++
++
++*/
++
++/**
++@page Example_Driver_Code
++
++@section example_intro Introduction
++This section provides an in-depth code example for driver implementations. The code
++below illustrates the use of the CPMAC HAL, but is equally applicable to any CPHAL
++implementation. Note: the CPHAl constants hcGet, hcSet etc., are currently available for use with teh CPMAC module.
++Other modules should continue to use pszGET, etc. until these are made generally available.
++
++@par Pull Model Example
++
++@code
++
++#define _CPHAL_CPMAC
++
++typedef struct _os_device_s OS_DEVICE;
++typedef struct _os_receive_s OS_RECEIVEINFO;
++typedef struct _os_send_s OS_SENDINFO;
++typedef struct _os_setup_s OS_SETUP;
++
++#include "cpswhal_cpmac.h"
++
++#define dbgPrintf printf
++
++typedef struct _os_device_s
++{
++ HAL_DEVICE *HalDev;
++ HAL_FUNCTIONS *HalFunc;
++ OS_FUNCTIONS *OsFunc;
++ OS_SETUP *OsSetup;
++ bit32u Interrupt;
++ int (*halIsr)(HAL_DEVICE *HalDev, int*);
++ int ModulePort;
++ int Protocol;
++ int LinkStatus; // 0-> down, otherwise up
++}os_device_s;
++
++typedef struct _os_receive_s
++{
++ HAL_RECEIVEINFO *HalReceiveInfo;
++ char *ReceiveBuffer;
++ OS_DEVICE *OsDev;
++}os_receive_s;
++
++typedef struct _os_send_s
++{
++ OS_DEVICE *OsDev;
++}os_send_s;
++
++typedef struct _os_setup_s
++{
++ OS_DEVICE *OsDev;
++}os_setup_s;
++
++
++
++void FlowForCphal(OS_DEVICE *OsDev)
++{
++ CHANNEL_INFO ChannelInfo;
++ int nChannels = 200;
++ int halFuncSize;
++ int rc;
++
++ // Populate OsFunc structure
++ rc = osInitModule(OsDev);
++
++ if(rc)
++ {
++ sprintf(bufTmp, "%s: return code from osInitModule:'0x%08X'", __FUNCTION__, rc);
++ errorout(bufTmp);
++ }
++
++
++ // OS-Cphal handshake
++ rc = halCpmacInitModule(&OsDev->HalDev, OsDev, &OsDev->HalFunc, OsDev->OsFunc,
++ sizeof(OS_FUNCTIONS), &halFuncSize, OsDev->ModulePort);
++
++ if(rc)
++ {
++ sprintf(bufTmp, "%s: return code from halCpmacInitModule:'0x%08X'", __FUNCTION__, rc);
++ errorout(bufTmp);
++ }
++
++ // See if hardware module exists
++ rc = OsDev->HalFunc->Probe(OsDev->HalDev);
++
++ if(rc)
++ {
++ sprintf(bufTmp, "%s: return code from Probe:'0x%08X'", __FUNCTION__, rc);
++ errorout(bufTmp);
++ }
++
++ // Initialize hardware module
++ rc = OsDev->HalFunc->Init(OsDev->HalDev);
++
++ if(rc)
++ {
++ sprintf(bufTmp, "%s: return code from Init:'0x%08X'", __FUNCTION__, rc);
++ errorout(bufTmp);
++ }
++
++ // Setup Channel Information (Tranmsit, channel 0)
++ ChannelInfo.Channel = 0;
++ ChannelInfo.Direction = DIRECTION_TX;
++ ChannelInfo.TxNumBuffers = nChannels;
++ ChannelInfo.TxNumQueues = 1;
++ ChannelInfo.TxServiceMax = nChannels/3;
++
++ rc = OsDev->HalFunc->ChannelSetup(OsDev->HalDev, &ChannelInfo, OsDev->OsSetup);
++
++ // Setup Channel Information (Receive, channel 0)
++ ChannelInfo.Channel = 0;
++ ChannelInfo.Direction = DIRECTION_RX;
++ ChannelInfo.RxBufSize = 1518;
++ ChannelInfo.RxBufferOffset = 0;
++ ChannelInfo.RxNumBuffers = 2*nChannels;
++ ChannelInfo.RxServiceMax = nChannels/3;
++
++ rc = OsDev->HalFunc->ChannelSetup(OsDev->HalDev, &ChannelInfo, OsDev->OsSetup);
++
++ // Open the hardware module
++ rc = OsDev->HalFunc->Open(OsDev->HalDev);
++
++ // Module now ready to Send/Receive data
++}
++
++
++int osInitModule(OS_FUNCTIONS **pOsFunc)
++ {
++ OS_FUNCTIONS *OsFunc;
++
++ OsFunc = (OS_FUNCTIONS *) malloc(sizeof(OS_FUNCTIONS));
++ if (!OsFunc)
++ return (-1);
++
++ *pOsFunc = OsFunc;
++
++ OsFunc->CriticalOff = osCriticalOff;
++ OsFunc->CriticalOn = osCriticalOn;
++ OsFunc->DataCacheHitInvalidate = osDataCacheHitInvalidate;
++ OsFunc->DataCacheHitWriteback = osDataCacheHitWriteback;
++ OsFunc->DeviceFindInfo = osDeviceFindInfo;
++ OsFunc->DeviceFindParmUint = osDeviceFindParmUint;
++ OsFunc->DeviceFindParmValue = osDeviceFindParmValue;
++ OsFunc->Free = osFree;
++ OsFunc->FreeDev = osFreeDev;
++ OsFunc->FreeDmaXfer = osFreeDmaXfer;
++ OsFunc->FreeRxBuffer = osFreeRxBuffer;
++ OsFunc->IsrRegister = osIsrRegister;
++ OsFunc->IsrUnRegister = osIsrUnRegister;
++ OsFunc->Malloc = osMalloc;
++ OsFunc->MallocDev = osMallocDev;
++ OsFunc->MallocDmaXfer = osMallocDmaXfer;
++ OsFunc->MallocRxBuffer = osMallocRxBuffer;
++
++
++ OsFunc->Memset = memset;
++ OsFunc->Printf = printf;
++ OsFunc->Sprintf = sprintf;
++ OsFunc->Strcmpi = osStrcmpi;
++ OsFunc->Strlen = strlen;
++ OsFunc->Strstr = strstr;
++ OsFunc->Strtoul = strtoul;
++
++ OsFunc->Control = osControl;
++ OsFunc->Receive = osReceive;
++ OsFunc->SendComplete = osSendComplete;
++ OsFunc->TeardownComplete = osTearDownComplete;
++
++ return(0);
++ }
++
++
++int osReceive(OS_DEVICE *OsDev,FRAGLIST *Fraglist,bit32u FragCount,bit32u PacketSize,HAL_RECEIVEINFO *halInfo, bit32u mode)
++ {
++ OS_RECEIVEINFO *skb = (OS_RECEIVEINFO *)Fraglist[0].OsInfo;
++ dcache_i((char *)Fraglist->data, Fraglist->len);
++ OsDev->HalFunc->RxReturn(halInfo,0);
++ return(0);
++ }
++
++int osSendComplete(OS_SENDINFO *skb)
++ {
++ return(0);
++ }
++
++
++static void *osMallocRxBuffer(bit32u Size,void *MemBase, bit32u MemRange,
++ OS_SETUP *OsSetup, HAL_RECEIVEINFO *HalReceiveInfo,
++ OS_RECEIVEINFO **OsReceiveInfo, OS_DEVICE *OsDev )
++ {
++ void *HalBuffer;
++ OS_RECEIVEINFO *OsPriv;
++
++ HalBuffer=malloc(Size);
++ if (!HalBuffer)
++ {
++ return(0);
++ }
++
++ // Malloc the OS block
++ *OsReceiveInfo = malloc(sizeof(OS_RECEIVEINFO));
++ if (!*OsReceiveInfo)
++ {
++ free(HalBuffer);
++ return(0);
++ }
++
++ // Initialize the new buffer descriptor
++ OsPriv = *OsReceiveInfo;
++ OsPriv->OsDev = OsDev;
++ OsPriv->ReceiveBuffer = HalBuffer;
++ OsPriv->HalReceiveInfo = HalReceiveInfo;
++
++ return(HalBuffer);
++ }
++
++
++void SendBuffer(OS_DEVICE *OsDev, char *Buffer, int Size)
++{
++ FRAGLIST Fraglist;
++ bit32u FragCount;
++
++ tcb_pending++;
++ Fraglist.len = Size;
++ Fraglist.data = (unsigned *) Buffer;
++ FragCount = 1;
++ mode = 0; // Channel 0
++
++ dcache_wb(Fraglist.data, Fraglist.len);
++ OsDev->HalFunc->Send(OsDev->HalDev, &Fraglist, FragCount, Size, (OS_SENDINFO *) Buffer, mode);
++}
++
++
++void osStateChange(OS_DEVICE *OsDev)
++ {
++ int status;
++ int LinkStatus;
++ OsDev->HalFunc->Control(OsDev->HalDev, "Status", hcGet, &status);
++ if(status & CPMAC_STATUS_ADAPTER_CHECK)
++ {
++ // Adapter Check, take appropiate action
++ }
++ else
++ {
++ LinkStatus = status & CPMAC_STATUS_LINK;
++ if(LinkStatus != OsDev->LinkStatus)
++ {
++ dbgPrintf("\n%s:Link %s for inst %d Speed %s, Duplex %s\n",
++ __FUNCTION__,
++ LinkStatus ? "up" : "down",
++ OsDev->ModulePort,
++ status & CPMAC_STATUS_LINK_SPEED ? "100" : "10",
++ status & CPMAC_STATUS_LINK_DUPLEX ? "FD" : "HD");
++ OsDev->LinkStatus = LinkStatus;
++ }
++ }
++ }
++
++
++int osControl(OS_DEVICE *OsDev, const char *pszKey, const char* pszAction, void *ParmValue)
++ {
++ int rc=-1;
++
++ if (osStrcmpi(pszKey, hcCpuFrequency) == 0)
++ {
++ if(osStrcmpi(pszAction, hcGet) == 0)
++ {
++ *(bit32u*) ParmValue = cpufreq;
++ rc = 0;
++ }
++ }
++ if (osStrcmpi(pszKey, hcMdioBusFrequency) == 0)
++ {
++ if(osStrcmpi(pszAction, hcGet) == 0)
++ {
++ *(bit32u *)ParmValue = MdioBusFrequency;
++ rc = 0;
++ }
++ }
++if (osStrcmpi(pszKey, hcMdioClockFrequency) == 0)
++ {
++ if(osStrcmpi(pszAction, hcGet) == 0)
++ {
++ *(bit32u *)ParmValue = MdioClockFrequency;
++ rc = 0;
++ }
++ }
++
++ if (osStrcmpi(pszKey, hcTick) == 0)
++ {
++ if(osStrcmpi(pszAction, hcSet) == 0)
++ {
++ osTickSetInterval(OsDev, *(unsigned int *) ParmValue);
++ rc = 0;
++ }
++ else
++ if(osStrcmpi(pszAction, hcClear) == 0)
++ {
++ osTickDisable(OsDev);
++ rc = 0;
++ }
++ }
++
++ if (osStrcmpi(pszKey, "SioFlush") == 0)
++ {
++ MySioFlush();
++ rc = 0;
++ }
++
++ if (osStrcmpi(pszKey, "StateChange") == 0)
++ {
++ osStateChange(OsDev);
++ rc = 0;
++ }
++
++ if (osStrcmpi(pszKey, "Sleep") == 0)
++ {
++ osSleep(*(int *)ParmValue);
++ rc = 0;
++ }
++ return(rc);
++ }
++
++@endcode
++
++
++@par Push Model Example (Currently Eswitch ONLY)
++
++@code
++
++typedef struct _os_device_s OS_DEVICE;
++typedef struct _os_receive_s OS_RECEIVEINFO;
++typedef struct _os_send_s OS_SENDINFO;
++typedef struct _os_setup_s OS_SETUP;
++
++#include "cpswhal.h" //Get glogal HAL stuff
++#include "cpswhaleswitch.h" //Get device specific hal stuff
++
++
++typedef struct _os_device_s
++{
++ HAL_DEVICE *HalDev;
++ HAL_FUNCTIONS *HalFunc;
++ OS_FUNCTIONS *OsFunc;
++ OS_SETUP *OsSetup;
++ bit32u Interrupt;
++ int (*halIsr)(HAL_DEVICE *HalDev, int*);
++ int ModulePort;
++ int Protocol;
++ int LinkStatus; // 0-> down, otherwise up
++}os_device_s;
++
++typedef struct _os_receive_s
++{
++ HAL_RECEIVEINFO *HalReceiveInfo;
++ char *ReceiveBuffer;
++ OS_DEVICE *OsDev;
++}os_receive_s;
++
++typedef struct _os_send_s
++{
++ OS_DEVICE *OsDev;
++}os_send_s;
++
++typedef struct _os_setup_s
++{
++ OS_DEVICE *OsDev;
++}os_setup_s;
++
++
++
++void FlowForCphal(OS_DEVICE *OsDev)
++{
++CHANNEL_INFO ChannelInfo;
++ int nChannels = 200;
++ int halFuncSize;
++ int rc;
++
++ // Populate OsFunc structure
++ rc = osInitModule(OsDev);
++
++ if(rc)
++ {
++ sprintf(bufTmp, "%s: return code from osInitModule:'0x%08X'", __FUNCTION__, rc);
++ errorout(bufTmp);
++ }
++
++
++ // OS-Cphal handshake
++ rc = cpswHalEswitchInitModule(&OsDev->HalDev, OsDev, &OsDev->HalFunc, OsDev->OsFunc,
++ sizeof(OS_FUNCTIONS), &halFuncSize, OsDev->ModulePort);
++
++ if(rc)
++ {
++ sprintf(bufTmp, "%s: return code from cpswHalEswitchInitModule:'0x%08X'", __FUNCTION__, rc);
++ errorout(bufTmp);
++ }
++
++
++ ChannelInfo.Channel = 7;
++ ChannelInfo.Direction = DIRECTION_RX;
++ ChanInfo.Receive = osReceiveSS; // Specify function to receive data for this channel
++
++ rc = OsDev->HalFunc->ChannelSetup(OsDev->HalDev, &ChannelInfo, OsDev->OsSetup);
++
++ MyConfig.debug=0;
++ MyConfig.CpuFrequency = CpuFreq;
++ MyConfig.EswitchFrequency = EswitchFreq;
++ MyConfig.ResetBase = 0xa8611600;
++ MyConfig.MacAddress = MacAddr;
++
++ MyConfig.EswitchResetBit= 27;
++ MyConfig.Cpmac0ResetBit = 17;
++ MyConfig.Cpmac1ResetBit = 21;
++ MyConfig.MdioResetBit = 22;
++ MyConfig.Phy0ResetBit = 26;
++ MyConfig.Phy1ResetBit = 28;
++ MyConfig.HdmaResetBit = 13;
++ MyConfig.Cpmac0IntBit = 19;
++ MyConfig.Cpmac1IntBit = 33;
++ MyConfig.EswitchIntBit = 27;
++ MyConfig.EswitchBase = 0xa8640000;
++ MyConfig.EswitchBufferSize = 64;
++ MyConfig.EswitchHostBufCount = 0;
++ MyConfig.EswitchDefaultCamSize = 64;
++ MyConfig.EswitchOverFlowCount = 200;
++ MyConfig.EswitchOverFlowSize = 256;
++
++
++
++
++ rc=EswitchConfig(HalDev,HalFunc,&MyConfig);
++
++
++ // Open the hardware module
++ rc = OsDev->HalFunc->Open(OsDev->HalDev);
++
++ // Module now ready to Send/Receive data
++}
++
++
++int EswitchConfig(HAL_DEVICE *HalDev, HAL_FUNCTIONS *HalFunc, ESWITCH_CONFIG *Config)
++{
++ bit32u sts;
++ sts = 0;
++
++ sts |= cpswhalPushBin(hcdebug, Config->debug);
++ sts |= cpswhalPushBin(hcCpuFrequency , Config->CpuFrequency );
++ sts |= cpswhalPushBin(hcEswitchFrequency , Config->EswitchFrequency );
++ sts |= cpswhalPushBin(hcResetBase , Config->ResetBase );
++ sts |= cpswhalPushBin(hcMacAddress , Config->MacAddress );
++ sts |= cpswhalPushBin(hcEswitchResetBit, Config->EswitchResetBit);
++ sts |= cpswhalPushBin(hcCpmac0ResetBit , Config->Cpmac0ResetBit );
++ sts |= cpswhalPushBin(hcCpmac1ResetBit , Config->Cpmac1ResetBit );
++ sts |= cpswhalPushBin(hcMdioResetBit , Config->MdioResetBit );
++ sts |= cpswhalPushBin(hcPhy0ResetBit , Config->Phy0ResetBit );
++ sts |= cpswhalPushBin(hcPhy1ResetBit , Config->Phy1ResetBit );
++ sts |= cpswhalPushBin(hcHdmaResetBit , Config->HdmaResetBit );
++ sts |= cpswhalPushBin(hcCpmac0IntBit , Config->Cpmac0IntBit );
++ sts |= cpswhalPushBin(hcCpmac1IntBit , Config->Cpmac1IntBit );
++ sts |= cpswhalPushBin(hcEswitchIntBit , Config->EswitchIntBit );
++ sts |= cpswhalPushBin(hcEswitchBase , Config->EswitchBase );
++ sts |= cpswhalPushBin(hcEswitchBufferSize , Config->EswitchBufferSize );
++ sts |= cpswhalPushBin(hcEswitchHostBufCount , Config->EswitchHostBufCount );
++ sts |= cpswhalPushBin(hcEswitchDefaultCamSize , Config->EswitchDefaultCamSize );
++ sts |= cpswhalPushBin(hcEswitchOverFlowCount , Config->EswitchOverFlowCount );
++ sts |= cpswhalPushBin(hcEswitchOverFlowSize , Config->EswitchOverFlowSize );
++ return(sts);
++}
++
++
++
++@endcode
++*/
++
++#endif
+diff -urN linux.old/drivers/net/avalanche_cpmac/ec_errors_cpmac.h linux.dev/drivers/net/avalanche_cpmac/ec_errors_cpmac.h
+--- linux.old/drivers/net/avalanche_cpmac/ec_errors_cpmac.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/ec_errors_cpmac.h 2005-07-12 02:48:42.051592000 +0200
+@@ -0,0 +1,118 @@
++/***************************************************************************
++ Copyright(c) 2001, Texas Instruments Incorporated. All Rights Reserved.
++
++ FILE: ec_errors.h
++
++ DESCRIPTION:
++ This file contains definitions and function declarations for
++ error code support.
++
++ HISTORY:
++ 14Dec00 MJH Added masking to EC_CLASS etc macros
++ 17Sep02 GSG Added HAL support (new class&devices)
++ 03Oct02 GSG Removed C++ style comments
++***************************************************************************/
++#ifndef _INC_EC_ERRORS
++#define _INC_EC_ERRORS
++
++/*
++ 31 - CRITICAL
++ 30-28 - CLASS (ie. DIAG, KERNEL, FLASH, etc)
++ 27-24 - INSTANCE (ie. 1, 2, 3, etc )
++ 23-16 - DEVICE (ie. EMAC, IIC, etc)
++ 15-08 - FUNCTION (ie. RX, TX, INIT, etc)
++ 07-00 - ERROR CODE (ie. NO_BASE, FILE_NOT_FOUND, etc )
++*/
++
++/*---------------------------------------------------------------------------
++ Useful defines for accessing fields within error code
++---------------------------------------------------------------------------*/
++#define CRITICAL_SHIFT 31
++#define CLASS_SHIFT 28
++#define INST_SHIFT 24
++#define DEVICE_SHIFT 16
++#define FUNCTION_SHIFT 8
++#define ERROR_CODE_SHIFT 0
++
++#define CRITICAL_MASK 1
++#define CLASS_MASK 0x07
++#define DEVICE_MASK 0xFF
++#define INST_MASK 0x0F
++#define FUNCTION_MASK 0xFF
++#define ERROR_CODE_MASK 0xFF
++
++#define EC_CLASS(val) ((val&CLASS_MASK) << CLASS_SHIFT)
++#define EC_DEVICE(val) ((val&DEVICE_MASK) << DEVICE_SHIFT)
++#define EC_INST(val) ((val&INST_MASK) << INST_SHIFT)
++#define EC_FUNC(val) ((val&FUNCTION_MASK) << FUNCTION_SHIFT)
++#define EC_ERR(val) ((val&ERROR_CODE_MASK) << ERROR_CODE_SHIFT)
++
++/*---------------------------------------------------------------------------
++ Operation classes
++---------------------------------------------------------------------------*/
++#define EC_HAL EC_CLASS(0)
++#define EC_DIAG EC_CLASS(8)
++
++/*---------------------------------------------------------------------------
++ Device types
++---------------------------------------------------------------------------*/
++#define EC_DEV_EMAC EC_DEVICE(1)
++#define EC_DEV_IIC EC_DEVICE(2)
++#define EC_DEV_RESET EC_DEVICE(3)
++#define EC_DEV_ATMSAR EC_DEVICE(4)
++#define EC_DEV_MEM EC_DEVICE(5)
++#define EC_DEV_DES EC_DEVICE(6)
++#define EC_DEV_DMA EC_DEVICE(7)
++#define EC_DEV_DSP EC_DEVICE(8)
++#define EC_DEV_TMR EC_DEVICE(9)
++#define EC_DEV_WDT EC_DEVICE(10)
++#define EC_DEV_DCL EC_DEVICE(11)
++#define EC_DEV_BBIF EC_DEVICE(12)
++#define EC_DEV_PCI EC_DEVICE(13)
++#define EC_DEV_XBUS EC_DEVICE(14)
++#define EC_DEV_DSLIF EC_DEVICE(15)
++#define EC_DEV_USB EC_DEVICE(16)
++#define EC_DEV_CLKC EC_DEVICE(17)
++#define EC_DEV_RAPTOR EC_DEVICE(18)
++#define EC_DEV_DSPC EC_DEVICE(19)
++#define EC_DEV_INTC EC_DEVICE(20)
++#define EC_DEV_GPIO EC_DEVICE(21)
++#define EC_DEV_BIST EC_DEVICE(22)
++#define EC_DEV_HDLC EC_DEVICE(23)
++#define EC_DEV_UART EC_DEVICE(24)
++#define EC_DEV_VOIC EC_DEVICE(25)
++/* 9.17.02 (new HAL modules) */
++#define EC_DEV_CPSAR EC_DEVICE(0x1A)
++#define EC_DEV_AAL5 EC_DEVICE(0x1B)
++#define EC_DEV_AAL2 EC_DEVICE(0x1C)
++#define EC_DEV_CPMAC EC_DEVICE(0x1D)
++#define EC_DEV_VDMA EC_DEVICE(0x1E)
++#define EC_DEV_VLYNQ EC_DEVICE(0x1F)
++#define EC_DEV_CPPI EC_DEVICE(0x20)
++#define EC_DEV_CPMDIO EC_DEVICE(0x21)
++
++/*---------------------------------------------------------------------------
++ Function types
++---------------------------------------------------------------------------*/
++#define EC_FUNC_READ_CONF EC_FUNC(1)
++#define EC_FUNC_INIT EC_FUNC(2)
++
++/*---------------------------------------------------------------------------
++ Error codes
++---------------------------------------------------------------------------*/
++#define EC_CRITICAL (1<<CRITICAL_SHIFT)
++#define EC_NO_ERRORS 0
++#define EC_VAL_NO_BASE EC_ERR(1)
++#define EC_VAL_NO_RESET_BIT EC_ERR(2)
++#define EC_VAL_NO_RESET EC_ERR(3)
++#define EC_VAL_BAD_BASE EC_ERR(4)
++#define EC_VAL_MALLOCFAILED EC_ERR(5)
++#define EC_VAL_NO_RESETBASE EC_ERR(6)
++#define EC_DEVICE_NOT_FOUND EC_ERR(7)
++
++/*---------------------------------------------------------------------------
++ Function declarations
++---------------------------------------------------------------------------*/
++extern void ec_log_error( unsigned int );
++
++#endif /* _INC_EC_ERRORS */
+diff -urN linux.old/drivers/net/avalanche_cpmac/hcpmac.c linux.dev/drivers/net/avalanche_cpmac/hcpmac.c
+--- linux.old/drivers/net/avalanche_cpmac/hcpmac.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/hcpmac.c 2005-07-12 02:48:42.174574000 +0200
+@@ -0,0 +1,1878 @@
++/******************************************************************************
++ * TNETDxxxx Software Support
++ * Copyright (c) 2002-2004 Texas Instruments Incorporated. All Rights Reserved.
++ *
++ * FILE:
++ *
++ * DESCRIPTION:
++ * This file contains the code for the HAL EMAC Bridge Test
++ *
++ * HISTORY:
++ * xxXxx01 Denis RC1.00 Original Version created.
++ * 22Jan02 Denis/Mick RC1.01 Modified for HAL EMAC API
++ * 24Jan02 Denis/Mick RC1.02 Speed Improvements
++ * 28Jan02 Denis/Mick RC1.16 Made function calls pointers
++ * 28Jan02 Mick RC1.18 Split into separate modules
++ * 29Jan02 Mick RC1.19 Hal include file cleaned up
++ * 15Jul02 Michael Hanrahan RC1.20 Synch'd with Linux Version
++ * 23Sep02 Michael Hanrahan RC1.21 Added CPPI.C
++ * 16Oct02 Michael Hanrahan RC1.22 Added CAF etc to Options.Conf
++ * 09Jan03 Michael Hanrahan RC3.01 Fixed incorrect MDIO check
++ * 01Feb03 Michael Hanrahan RC3.02 Updated for GPIO/PBUSFREQ
++ * 29Mar03 Michael Hanrahan 1.03 Corrected ChannelConfigGet
++ * 29Mar03 Michael Hanrahan 1.03 Removed user setting of TxNumQueues
++ * 23Aug04 Michael Hanrahan 1.7.8 Support for Setting Mac Address
++ * @author Michael Hanrahan
++ * @version 1.02
++ * @date 24-Jan-2002
++ *****************************************************************************/
++#define _HAL_CPMAC
++#define _CPHAL_CPMAC
++#define _CPHAL
++#define __CPHAL_CPMDIO
++
++#include "dox_cpmac.h" /* Documentation information */
++
++/* OS Data Structure definitions */
++
++typedef void OS_PRIVATE;
++typedef void OS_DEVICE;
++typedef void OS_SENDINFO;
++typedef void OS_RECEIVEINFO;
++typedef void OS_SETUP;
++
++/* HAL Data Structure definitions */
++
++typedef struct _phy_device PHY_DEVICE;
++typedef struct hal_device HAL_DEVICE;
++typedef struct hal_private HAL_PRIVATE;
++typedef struct hal_private HAL_RECEIVEINFO;
++
++#include "cpcommon_cpmac.h"
++#include "cpswhal_cpmac.h"
++#include "cpmdio.h"
++#include "hcpmac.h"
++#include "cpmac_reg.h"
++
++
++#define EC_MODULE
++
++/* MDIO Clock Frequency Default Value */
++
++/* Rcb/Tcb Constants */
++
++#define CB_SOF_BIT (1<<31)
++#define CB_EOF_BIT (1<<30)
++#define CB_SOF_AND_EOF_BIT (CB_SOF_BIT|CB_EOF_BIT)
++#define CB_OWNERSHIP_BIT (1<<29)
++#define CB_EOQ_BIT (1<<28)
++#define CB_SIZE_MASK 0x0000ffff
++#define RCB_ERRORS_MASK 0x03fe0000
++
++static char *channel_names[] = CHANNEL_NAMES; /* GSG 11/22 (may change this implementation) */
++
++#define scFound(Module) if (HalDev->State != enDevFound) return (Module|EC_FUNC_CHSETUP|EC_VAL_INVALID_STATE)
++#define scInit(Module) if (HalDev->State < enInitialized) return (Module|EC_FUNC_CHSETUP|EC_VAL_INVALID_STATE)
++#define scOpen(Module) if (HalDev->State < enOpened) return (Module|EC_FUNC_CHSETUP|EC_VAL_INVALID_STATE)
++
++
++
++/********************************************************************
++**
++** L O C A L F U N C T I O N S
++**
++********************************************************************/
++static int halIsr(HAL_DEVICE *HalDev, int *MorePackets);
++static int cpmacRandom(HAL_DEVICE *HalDev);
++static int cpmacRandomRange(HAL_DEVICE *HalDev, int min, int max);
++static int halPacketProcessEnd(HAL_DEVICE *HalDev);
++
++#include "cpcommon_cpmac.c" /*~RC3.02*/
++#include "cppi_cpmac.c"
++#include "cpmdio.c" /*~RC3.02*/
++
++static int MacAddressSave(HAL_DEVICE *HalDev, unsigned char *MacAddr)
++ {
++ int i;
++ int inst = HalDev->inst;
++
++ HalDev->MacAddr = MacAddr;
++
++ if(HalDev->debug)
++ {
++ dbgPrintf("MacAddrSave[%d]: ", inst);
++ for (i=0;i<6;i++)
++ dbgPrintf("%X", HalDev->MacAddr[i]);
++ dbgPrintf("\n");
++ osfuncSioFlush();
++ }
++ return(EC_NO_ERRORS);
++ }
++static int MacAddressSet(HAL_DEVICE *HalDev)
++ {
++ unsigned char *macadr = &HalDev->MacAddr[0];
++ int base = HalDev->dev_base;
++
++ scOpen(EC_CPMAC);
++ CPMAC_MACADDRLO_0(base) = macadr[5];
++ CPMAC_MACADDRMID(base) = macadr[4];
++ CPMAC_MACADDRHI(base) = (macadr[0])|(macadr[1]<<8)|(macadr[2]<<16)|(macadr[3]<<24);
++ if(HalDev->debug)
++ {
++ dbgPrintf("MacAddrSet: MacAddr(%d) %X %X %X\n", HalDev->inst, CPMAC_MACADDRLO_0(base),
++ CPMAC_MACADDRMID(base),
++ CPMAC_MACADDRHI(base));
++
++ dbgPrintf("Start MAC: %d\n",HalDev->dev_base);
++ osfuncSioFlush();
++ }
++ return(EC_NO_ERRORS);
++ }
++
++
++/*
++ Updates the MacHash registers
++*/
++static void MacHashSet(HAL_DEVICE *HalDev)
++ {
++ if(HalDev->State < enOpened)
++ return;
++
++ CPMAC_MACHASH1(HalDev->dev_base) = HalDev->MacHash1;
++ CPMAC_MACHASH2(HalDev->dev_base) = HalDev->MacHash2;
++ if (DBG(11))
++ dbgPrintf("CPMAC[%X]: MacHash1 0x%08X, MacHash2 0x%08X\n", HalDev->dev_base, CPMAC_MACHASH1(HalDev->dev_base), CPMAC_MACHASH2(HalDev->dev_base));
++ }
++
++/*
++ Reads the MacControl register and updates
++ the changable bits. (See MACCONTROL_MASK)
++*/
++static void RxMBP_EnableSet(HAL_DEVICE *HalDev)
++ {
++ bit32u RxMbpEnable;
++ if(HalDev->State < enOpened)
++ return;
++ RxMbpEnable = CPMAC_RX_MBP_ENABLE(HalDev->dev_base);
++ RxMbpEnable &= ~RX_MBP_ENABLE_MASK; /* Clear out updatable bits */
++ RxMbpEnable |= HalDev->RxMbpEnable;
++ CPMAC_RX_MBP_ENABLE(HalDev->dev_base) = RxMbpEnable;
++ }
++/*
++ Reads the MacControl register and updates
++ the changable bits. (See MACCONTROL_MASK)
++*/
++static void MacControlSet(HAL_DEVICE *HalDev)
++ {
++ bit32u MacControl;
++ if(HalDev->State < enOpened)
++ return;
++ MacControl = CPMAC_MACCONTROL(HalDev->dev_base);
++ MacControl &= ~MACCONTROL_MASK; /* Clear out updatable bits */
++ MacControl |= HalDev->MacControl;
++ if(!(MacControl & MII_EN)) /* If Enable is not set just update register */
++ CPMAC_MACCONTROL(HalDev->dev_base) = MacControl;
++ else
++ {
++ if(MacControl & CTRL_LOOPBACK) /* Loopback Set */
++ {
++ /* mii_en is set and loopback is needed,
++ clear mii_en, set loopback, then set mii_en
++ */
++ MacControl &= ~MII_EN; /* Clear MII_EN */
++ CPMAC_MACCONTROL(HalDev->dev_base) = MacControl;
++ CPMAC_MACCONTROL(HalDev->dev_base) |= MII_EN; /* Set MII_EN */
++ HalDev->Linked = 1; /* if in loopback the logically linked */
++ }
++ else /* If Loopback not set just update */
++ {
++ CPMAC_MACCONTROL(HalDev->dev_base) = MacControl;
++ }
++ }
++ if(DBG(0))
++ dbgPrintf("[halMacControlSet]MacControl:%08X\n", CPMAC_MACCONTROL(HalDev->dev_base));
++ }
++static int UnicastSet(HAL_DEVICE *HalDev)
++ {
++ CPMAC_RX_UNICAST_SET(HalDev->dev_base) = HalDev->RxUnicastSet;
++ CPMAC_RX_UNICAST_CLEAR(HalDev->dev_base) = HalDev->RxUnicastClear;
++ return(EC_NO_ERRORS);
++ }
++
++
++static bit32u HashGet(bit8u *Address)
++ {
++ bit32u hash;
++ bit8u tmpval;
++ int i;
++
++ hash = 0;
++ for( i=0; i<2; i++ )
++ {
++ tmpval = *Address++;
++ hash ^= (tmpval>>2)^(tmpval<<4);
++ tmpval = *Address++;
++ hash ^= (tmpval>>4)^(tmpval<<2);
++ tmpval = *Address++;
++ hash ^= (tmpval>>6)^(tmpval);
++ }
++
++ return( hash & 0x3F );
++ }
++
++static void HashAdd(HAL_DEVICE *HalDev, bit8u *MacAddress)
++{
++ bit32u HashValue;
++ bit32u HashBit;
++
++ HashValue = HashGet(MacAddress);
++
++ if(HashValue < 32)
++ {
++ HashBit = (1 << HashValue);
++ HalDev->MacHash1 |= HashBit;
++ }
++ else
++ {
++ HashBit = (1 << (HashValue-32));
++ HalDev->MacHash2 |= HashBit;
++ }
++}
++
++static void HashDel(HAL_DEVICE *HalDev, bit8u *MacAddress)
++{
++ bit32u HashValue;
++ bit32u HashBit;
++
++ HashValue = HashGet(MacAddress);
++
++ if(HashValue < 32)
++ {
++ HashBit = (1 << HashValue);
++ HalDev->MacHash1 &= ~HashBit;
++ }
++ else
++ {
++ HashBit = (1 << (HashValue-32));
++ HalDev->MacHash2 &= ~HashBit;
++ }
++}
++
++/* Replace with an array based on key, with a ptr to the code to do */
++/* e.g. [enRX_PASS_CRC] = {Set, MBP_UPDATE() } */
++static void DuplexUpdate(HAL_DEVICE *HalDev)
++{
++ int base = HalDev->dev_base;
++ PHY_DEVICE *PhyDev = HalDev->PhyDev;
++
++ if(HalDev->State < enOpened)
++ return;
++
++ /* No Phy Condition */
++ if(HalDev->MdioConnect & _CPMDIO_NOPHY) /*MJH+030805*/
++ {
++ /* No Phy condition, always linked */
++ HalDev->Linked = 1;
++ HalDev->EmacSpeed = 1;
++ HalDev->EmacDuplex = 1;
++ HalDev->PhyNum = 0xFFFFFFFF; /* No Phy Num */
++ CPMAC_MACCONTROL(base) |= FULLDUPLEX; /*MJH+030909*/
++ osfuncStateChange();
++ return;
++ }
++
++ if(HalDev->MacControl & CTRL_LOOPBACK) /* Loopback Set */
++ {
++ HalDev->Linked = 1;
++ return;
++ }
++
++ if (HalDev->MdioConnect & _CPMDIO_LOOPBK)
++ {
++ HalDev->Linked = cpMacMdioGetLoopback(HalDev->PhyDev);
++ }
++ else
++ {
++ HalDev->Linked = cpMacMdioGetLinked(HalDev->PhyDev);
++ }
++ if (HalDev->Linked)
++ {
++ /* Retreive Duplex and Speed and the Phy Number */
++ if(HalDev->MdioConnect & _CPMDIO_LOOPBK)
++ HalDev->EmacDuplex = 1;
++ else
++ HalDev->EmacDuplex = cpMacMdioGetDuplex(PhyDev);
++ HalDev->EmacSpeed = cpMacMdioGetSpeed(PhyDev);
++ HalDev->PhyNum = cpMacMdioGetPhyNum(PhyDev);
++
++ if(HalDev->EmacDuplex)
++ CPMAC_MACCONTROL(base) |= FULLDUPLEX;
++ else
++ CPMAC_MACCONTROL(base) &= ~FULLDUPLEX;
++ if(HalDev->debug)
++ dbgPrintf("%d: Phy= %d, Speed=%s, Duplex=%s\n",HalDev->inst,HalDev->PhyNum,(HalDev->EmacSpeed)?"100":"10",(HalDev->EmacDuplex)?"Full":"Half");
++ }
++ if(HalDev->debug)
++ dbgPrintf("DuplexUpdate[%d]: MACCONTROL 0x%08X, %s\n", HalDev->inst, CPMAC_MACCONTROL(base),(HalDev->Linked)?"Linked":"Not Linked");
++}
++static void MdioSetPhyMode(HAL_DEVICE *HalDev)
++ {
++ unsigned int PhyMode;
++ /* Verify proper device state */
++ if (HalDev->State < enOpened)
++ return;
++
++ PhyMode = NWAY_AUTO|NWAY_FD100|NWAY_HD100|NWAY_FD10|NWAY_HD10;
++ if(DBG(0))
++ {
++ dbgPrintf("halSetPhyMode1: MdioConnect:%08X ,", HalDev->MdioConnect);
++ dbgPrintf("PhyMode:%08X Auto:%d, FD10:%d, HD10:%d, FD100:%d, HD100:%d\n", PhyMode,
++ PhyMode&NWAY_AUTO, PhyMode&NWAY_FD10, PhyMode&NWAY_HD10, PhyMode&NWAY_FD100,
++ PhyMode&NWAY_HD100);
++ }
++
++
++ if ( HalDev->MdioConnect & _CPMDIO_NEG_OFF) /* ~RC3.01 */
++ PhyMode &= ~(NWAY_AUTO); /* Disable Auto Neg */
++ if (!(HalDev->MdioConnect & _CPMDIO_HD))
++ PhyMode &= ~(NWAY_HD100|NWAY_HD10); /* Cannot support HD */
++ if (!(HalDev->MdioConnect & _CPMDIO_FD))
++ PhyMode &= ~(NWAY_FD100|NWAY_FD10); /* Cannot support FD */
++ if (!(HalDev->MdioConnect & _CPMDIO_10))
++ PhyMode &= ~(NWAY_HD10|NWAY_FD10); /* Cannot support 10 Mbs */
++ if (!(HalDev->MdioConnect & _CPMDIO_100))
++ PhyMode &= ~(NWAY_HD100|NWAY_FD100); /* Cannot support 100 Mbs */
++
++ if(HalDev->MdioConnect & _CPMDIO_AUTOMDIX) PhyMode |= NWAY_AUTOMDIX; /* Set AutoMdix */
++
++ if (HalDev->CpmacFrequency <= 50000000)
++ PhyMode &= ~(NWAY_FD100|NWAY_HD100); /* Cannot support 100 MBS */
++ if(DBG(7))
++ dbgPrintf("halNeg: PhyMode[0x%08X] %d\n", HalDev->dev_base, PhyMode);
++
++ if(DBG(0))
++ {
++ dbgPrintf("halSetPhyMode2: MdioConnect:%08X ,", HalDev->MdioConnect);
++ dbgPrintf("PhyMode:%08X Auto:%d, FD10:%d, HD10:%d, FD100:%d, HD100:%d\n", PhyMode,
++ PhyMode&NWAY_AUTO, PhyMode&NWAY_FD10, PhyMode&NWAY_HD10, PhyMode&NWAY_FD100,
++ PhyMode&NWAY_HD100);
++ }
++
++
++ cpMacMdioSetPhyMode(HalDev->PhyDev,PhyMode);
++ DuplexUpdate(HalDev);
++ }
++static int StatsClear(HAL_DEVICE *HalDev)
++{
++ int i;
++ MEM_PTR pStats;
++
++ scOpen(EC_CPMAC);
++
++ pStats = pCPMAC_RXGOODFRAMES(HalDev->dev_base);
++ for (i=0;i<STATS_MAX;i++)
++ {
++ *(MEM_PTR)(pStats) = 0xFFFFFFFF;
++ pStats++;
++ }
++
++ return(EC_NO_ERRORS);
++}
++static void StatsDump(HAL_DEVICE *HalDev, void *Value)
++ {
++ MEM_PTR ptrStats;
++ MEM_PTR ptrValue;
++ int i;
++ ptrStats = pCPMAC_RXGOODFRAMES(HalDev->dev_base);
++ ptrValue = (bit32u*) Value;
++ for (i=0; i<STATS_MAX; i++)
++ {
++ *ptrValue = *ptrStats;
++ if(DBG(4))
++ {
++ dbgPrintf("halStatsDump: Stat[%d:0x%08X] %d 0x%08X %d\n", i, ptrStats, *ptrStats, ptrValue, *ptrValue);
++ osfuncSioFlush();
++ }
++ ptrStats++;
++ ptrValue++;
++ }
++ }
++static void ConfigApply(HAL_DEVICE *HalDev)
++ {
++ CPMAC_RX_MAXLEN(HalDev->dev_base) = HalDev->RxMaxLen;
++ CPMAC_RX_FILTERLOWTHRESH(HalDev->dev_base) = HalDev->RxFilterLowThresh;
++ CPMAC_RX0_FLOWTHRESH(HalDev->dev_base) = HalDev->Rx0FlowThresh;
++ UnicastSet(HalDev);
++ MacAddressSet(HalDev);
++ RxMBP_EnableSet(HalDev);
++ MacHashSet(HalDev);
++ MacControlSet(HalDev);
++ if(DBG(0))
++ dbgPrintf("ValuesUpdate[%d]: MBP_ENABLE 0x%08X\n", HalDev->inst, CPMAC_RX_MBP_ENABLE(HalDev->dev_base));
++ }
++static int halStatus(HAL_DEVICE *HalDev)
++{
++ int status;
++
++ if(HalDev->State < enOpened)
++ return (EC_CPMAC|EC_FUNC_STATUS|EC_VAL_INVALID_STATE); /*MJH+030805*/
++
++ /* No Phy Condition */
++ if(HalDev->MdioConnect & _CPMDIO_NOPHY) /*MJH+030805*/
++ {
++ /* No Phy condition, always linked */
++ status = HalDev->Linked;
++ status |= CPMAC_STATUS_LINK_DUPLEX;
++ status |= CPMAC_STATUS_LINK_SPEED;
++ return(status);
++ }
++
++
++ if (HalDev->HostErr) /* Adapter Check */
++ {
++ bit32u tmp;
++ status = CPMAC_STATUS_ADAPTER_CHECK;
++ if(HalDev->MacStatus & RX_HOST_ERR_CODE)
++ {
++ status |= CPMAC_STATUS_HOST_ERR_DIRECTION;
++ tmp = (HalDev->MacStatus & RX_HOST_ERR_CODE) >> 12; /* Code */
++ status |= (tmp << 9); /* Code */
++ tmp = (HalDev->MacStatus & RX_ERR_CH) >> 8; /* Channel */
++ status |= (tmp << 13);
++ }
++ else
++ if(HalDev->MacStatus & TX_HOST_ERR_CODE)
++ {
++ status |= CPMAC_STATUS_HOST_ERR_DIRECTION;
++ tmp = (HalDev->MacStatus & TX_HOST_ERR_CODE) >> 20; /* Code */
++ status |= (tmp << 9); /* Code */
++ tmp = (HalDev->MacStatus & TX_ERR_CH) >> 16; /* Channel */
++ status |= (tmp << 13);
++ }
++ }
++ else
++ {
++ status = HalDev->Linked;
++ if(status)
++ {
++ status = CPMAC_STATUS_LINK;
++ if(cpMacMdioGetDuplex(HalDev->PhyDev))
++ status |= CPMAC_STATUS_LINK_DUPLEX;
++ if(cpMacMdioGetSpeed(HalDev->PhyDev))
++ status |= CPMAC_STATUS_LINK_SPEED;
++ }
++ }
++ if(HalDev->debug)
++ dbgPrintf("[halStatus] Link Status is %d for 0x%X\n", status, HalDev->dev_base);
++ return(status);
++}
++static int InfoAccess(HAL_DEVICE *HalDev, int Key, int Action, void *ParmValue)
++ {
++ int rc = 0;
++ int Update=0;
++
++ switch (Key)
++ {
++ /********************************************************************/
++ /* */
++ /* GENERAL */
++ /* */
++ /********************************************************************/
++
++ case enVersion :
++ if(Action==enGET)
++ {
++ *(const char **)ParmValue = pszVersion_CPMAC;
++ }
++ break;
++ case enDebug :
++ if(Action==enSET)
++ {
++ HalDev->debug = *(unsigned int *)ParmValue;
++ }
++ break;
++
++ case enStatus :
++ if(Action==enGET)
++ {
++ int status;
++ status = halStatus(HalDev);
++ *(int *)ParmValue = status;
++ }
++ break;
++ /********************************************************************/
++ /* */
++ /* RX_MBP_ENABLE */
++ /* */
++ /********************************************************************/
++
++ case enRX_PASS_CRC :
++ if(Action==enSET)
++ {
++ UPDATE_RX_PASS_CRC(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enRX_QOS_EN :
++ if(Action==enSET)
++ {
++ UPDATE_RX_QOS_EN(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enRX_NO_CHAIN :
++ if(Action==enSET)
++ {
++ UPDATE_RX_NO_CHAIN(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enRX_CMF_EN :
++ if(Action==enSET)
++ {
++ UPDATE_RX_CMF_EN(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enRX_CSF_EN :
++ if(Action==enSET)
++ {
++ UPDATE_RX_CSF_EN(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enRX_CEF_EN :
++ if(Action==enSET)
++ {
++ UPDATE_RX_CEF_EN(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enRX_CAF_EN :
++ if(Action==enSET)
++ {
++ UPDATE_RX_CAF_EN(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enRX_PROM_CH :
++ if(Action==enSET)
++ {
++ UPDATE_RX_PROM_CH(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enRX_BROAD_EN :
++ if(Action==enSET)
++ {
++ UPDATE_RX_BROAD_EN(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enRX_BROAD_CH :
++ if(Action==enSET)
++ {
++ UPDATE_RX_BROAD_CH(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enRX_MULT_EN :
++ if(Action==enSET)
++ {
++ UPDATE_RX_MULT_EN(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enRX_MULT_CH :
++ if(Action==enSET)
++ {
++ UPDATE_RX_MULT_CH(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++
++ /********************************************************************/
++ /* */
++ /* MAC_CONTROL */
++ /* */
++ /********************************************************************/
++
++ case enTX_PTYPE :
++ if(Action==enSET)
++ {
++ UPDATE_TX_PTYPE(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enTX_PACE :
++ if(Action==enSET)
++ {
++ UPDATE_TX_PACE(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enTX_FLOW_EN :
++ if(Action==enSET)
++ {
++ UPDATE_TX_FLOW_EN(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enRX_FLOW_EN :
++ if(Action==enSET)
++ {
++ UPDATE_RX_FLOW_EN(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++
++ case enCTRL_LOOPBACK :
++ if(Action==enSET)
++ {
++ UPDATE_CTRL_LOOPBACK(*(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ /********************************************************************/
++ /* */
++ /* RX_UNICAST_SET */
++ /* */
++ /********************************************************************/
++
++ case enRX_UNICAST_SET :
++ if(Action==enSET)
++ {
++ HalDev->RxUnicastSet |= (1 << *(unsigned int *)ParmValue);
++ HalDev->RxUnicastClear &= ~(1 << *(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++ case enRX_UNICAST_CLEAR :
++ if(Action==enSET)
++ {
++ HalDev->RxUnicastClear |= (1 << *(unsigned int *)ParmValue);
++ HalDev->RxUnicastSet &= ~(1 << *(unsigned int *)ParmValue);
++ Update=1;
++ }
++ break;
++
++ case enRX_MAXLEN :
++ if(Action==enSET)
++ {
++ HalDev->RxMaxLen = *(unsigned int *)ParmValue;
++ Update=1;
++ }
++ break;
++
++ case enRX_FILTERLOWTHRESH :
++ if(Action==enSET)
++ {
++ HalDev->RxFilterLowThresh = *(unsigned int *)ParmValue;
++ Update=1;
++ }
++ break;
++ case enRX0_FLOWTHRESH :
++ if(Action==enSET)
++ {
++ HalDev->Rx0FlowThresh = *(unsigned int *)ParmValue;
++ Update=1;
++ }
++ break;
++ /********************************************************************/
++ /* */
++ /* RX_MULTICAST */
++ /* */
++ /********************************************************************/
++
++ case enRX_MULTICAST :
++ break;
++ case enRX_MULTI_SINGLE :
++ if(DBG(11))
++ {
++ int tmpi;
++ bit8u *MacAddress;
++ MacAddress = (bit8u *) ParmValue;
++ dbgPrintf("CPMAC[%X]: MacAddress '", HalDev->dev_base);
++ for (tmpi=0; tmpi<6; tmpi++)
++ dbgPrintf("%02X:", MacAddress[tmpi]);
++ dbgPrintf("\n");
++ }
++ if(Action==enCLEAR)
++ {
++ HashDel(HalDev, ParmValue);
++ Update=1;
++ }
++ else
++ if(Action==enSET)
++ {
++ HashAdd(HalDev, ParmValue);
++ Update=1;
++ }
++ break;
++ case enRX_MULTI_ALL :
++ if(Action==enCLEAR)
++ {
++ HalDev->MacHash1 = 0;
++ HalDev->MacHash2 = 0;
++ Update=1;
++ }
++ else
++ if(Action==enSET)
++ {
++ HalDev->MacHash1 = 0xFFFFFFFF;
++ HalDev->MacHash2 = 0xFFFFFFFF;
++ Update=1;
++ }
++ break;
++
++ /********************************************************************/
++ /* */
++ /* MDIO */
++ /* */
++ /********************************************************************/
++
++ case enMdioConnect :
++ if(Action==enSET)
++ {
++ HalDev->MdioConnect = *(unsigned int *)ParmValue;
++ MdioSetPhyMode(HalDev);
++ }
++ if(Action==enGET)
++ {
++ *(unsigned int *)ParmValue = HalDev->MdioConnect;
++ }
++ break;
++
++
++ /********************************************************************/
++ /* */
++ /* STATISTICS */
++ /* */
++ /********************************************************************/
++ case enStatsClear :
++ StatsClear(HalDev);
++ break;
++ case enStatsDump :
++ if(Action==enGET)
++ {
++ StatsDump(HalDev, ParmValue);
++ }
++ break;
++
++/* Not implemented
++ case enStats1 :
++ if(Action==enGET)
++ {
++ StatsGet(HalDev, ParmValue, 1);
++ }
++ break;
++
++ case enStats2 :
++ if(Action==enGET)
++ {
++ StatsGet(HalDev, ParmValue, 2);
++ }
++ break;
++ case enStats3 :
++ if(Action==enGET)
++ {
++ StatsGet(HalDev, ParmValue, 3);
++ }
++ break;
++ case enStats4 :
++ if(Action==enGET)
++ {
++ StatsGet(HalDev, ParmValue, 4);
++ }
++ break;
++
++*/
++
++ default:
++ rc = EC_CPMAC|EC_FUNC_OPTIONS|EC_VAL_KEY_NOT_FOUND;
++ break;
++ }
++
++ /* Verify proper device state */
++ if (HalDev->State == enOpened)
++ switch (Update)
++ {
++ case 1 :
++ ConfigApply(HalDev);
++ break;
++ default:
++ break;
++ }
++
++ return (rc);
++ }
++static const char pszStats[] = "Stats;";
++
++static int halControl(HAL_DEVICE *HalDev, const char *pszKey, const char *pszAction, void *Value)
++ {
++ int i;
++ int rc=0;
++ int Action;
++ int ActionFound;
++ int KeyFound;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(1))
++ {
++ dbgPrintf("\nhalControl-HalDev:%08X,Action:%s,Key:%s\n", (bit32u)HalDev, pszAction, pszKey);
++ }
++#endif
++
++ /* 23Aug04 - BCIL needs to set Mac Address */
++ if(HalDev->OsFunc->Strcmpi(pszKey, pszMacAddr) == 0)
++ {
++ KeyFound=1;
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcSet) == 0)
++ {
++ unsigned char *MacAddr;
++ MacAddr = (unsigned char *) Value;
++ MacAddressSave(HalDev, MacAddr);
++ MacAddressSet(HalDev);
++ return(0);
++ }
++ else
++ {
++ return(-1);
++ }
++ }
++
++ if(HalDev->OsFunc->Strcmpi(pszKey, hcLinked) == 0)
++ {
++ KeyFound=1;
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcSet) == 0)
++ {
++ HalDev->Linked = *(int *)Value;
++ return(0);
++ }
++ else
++ {
++ return(-1);
++ }
++ }
++
++ if(HalDev->OsFunc->Strcmpi(pszKey, "TxIntDisable") == 0)
++ {
++ KeyFound=1;
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcSet) == 0)
++ {
++ HalDev->TxIntDisable = *(int *)Value;
++ if(HalDev->TxIntDisable && (HalDev->State == enOpened))
++ {
++ /* if Opened and need TxIntDisabled, clear Ints for Channel 0 */
++ CPMAC_TX_INTMASK_CLEAR(HalDev->dev_base) = 1;
++ }
++ return(0);
++ }
++ else
++ {
++ return(-1);
++ }
++ }
++
++ if(HalDev->OsFunc->Strcmpi(pszKey, hcPhyAccess) == 0)
++ {
++ bit32u RegAddr;
++ bit32u PhyNum;
++ bit32u Data;
++ bit32u ValueIn;
++
++ ValueIn = *(bit32u*) Value;
++
++ KeyFound=1;
++ /* Cannot access MII if not opended */
++
++ if(HalDev->State < enOpened)
++ return(-1);
++
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcGet) == 0)
++ {
++
++ PhyNum = (ValueIn & 0x1F); /* Phynum 0-32 */
++ RegAddr = (ValueIn >> 5) & 0xFF; /* RegAddr in upper 11 bits */
++
++ *(bit32u*)Value = _mdioUserAccessRead(HalDev->PhyDev, RegAddr, PhyNum);
++
++ return(0);
++ } /* end of hcGet */
++
++
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcSet) == 0)
++ {
++ PhyNum = (ValueIn & 0x1F); /* Phynum 0-32 */
++ RegAddr = (ValueIn >> 5) & 0xFF; /* RegAddr in upper 11 bits of lower 16 */
++
++ Data = ValueIn >> 16; /* Data store in upper 16 bits */
++
++ _mdioUserAccessWrite(HalDev->PhyDev, RegAddr, PhyNum, Data);
++ return(0);
++ }
++ } /* End of hcPhyAccess */
++
++ if(HalDev->OsFunc->Strcmpi(pszKey, hcPhyNum) == 0)
++ {
++ KeyFound=1;
++ if(!HalDev->Linked)
++ return(-1); /* if not linked the no Phy Connected */
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcGet) == 0)
++ {
++ *(int *)Value = HalDev->PhyNum;
++ return(0);
++ }
++ }
++
++ if(HalDev->OsFunc->Strcmpi(pszKey, hcCpmacSize) == 0)
++ {
++ KeyFound=1;
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcGet) == 0)
++ {
++ *(bit32u *)Value = HalDev->CpmacSize;
++ return(0);
++ }
++ }
++
++ if(HalDev->OsFunc->Strcmpi(pszKey, hcCpmacBase) == 0)
++ {
++ KeyFound=1;
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcGet) == 0)
++ {
++ *(int *)Value = HalDev->dev_base;
++ return(0);
++ }
++ }
++
++ if(HalDev->OsFunc->Strcmpi(pszKey, hcFullDuplex) == 0)
++ {
++ KeyFound=1;
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcSet) == 0)
++ {
++ UPDATE_FULLDUPLEX(*(unsigned int *)Value);
++ if(HalDev->State == enOpened)
++ ConfigApply(HalDev);
++ return(0);
++ }
++ else
++ return(-1);
++ }
++
++ if(HalDev->OsFunc->Strcmpi(pszKey, pszDebug) == 0)
++ {
++ KeyFound=1;
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcSet) == 0)
++ {
++ ActionFound=1;
++ HalDev->debug = *(int *)Value;
++ }
++ }
++
++ if(HalDev->OsFunc->Strcmpi(pszKey, hcMaxFrags) == 0)
++ {
++ KeyFound=1;
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcSet) == 0)
++ {
++ ActionFound=1;
++
++ if ((*(int *)Value) > 0)
++ HalDev->MaxFrags = *(int *)Value;
++ else
++ rc = (EC_AAL5|EC_FUNC_CONTROL|EC_VAL_INVALID_VALUE);
++ }
++
++ if (HalDev->OsFunc->Strcmpi(pszAction, hcGet) == 0)
++ {
++ ActionFound=1;
++
++ *(int *)Value = HalDev->MaxFrags;
++ }
++ }
++
++ if(HalDev->OsFunc->Strstr(pszKey, pszStats) != 0)
++ {
++ KeyFound=1;
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcGet) == 0)
++ {
++ int Level;
++ int Ch;
++ char *TmpKey = (char *)pszKey;
++ ActionFound=1;
++ TmpKey += HalDev->OsFunc->Strlen(pszStats);
++ Level = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++ TmpKey++;
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++ TmpKey++;
++ osfuncSioFlush();
++#ifdef __CPHAL_DEBUG
++ if (DBG(1))
++ {
++ dbgPrintf("\nhalControl-HalDev:%08X, Level:%d, Ch:%d\n", (bit32u)HalDev, Level, Ch);
++ }
++#endif
++ StatsGet(HalDev, (void **)Value, Level, Ch, 0);
++ osfuncSioFlush();
++ }
++ }
++
++
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcSet) == 0)
++ Action = enSET;
++ else
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcClear) == 0)
++ Action = enCLEAR;
++ else
++ if(HalDev->OsFunc->Strcmpi(pszAction, hcGet) == 0)
++ Action = enGET;
++ else
++ Action = enNULL;
++
++
++
++ for(i=enCommonStart+1;i<enCommonEnd;i++)
++ {
++ if(HalDev->OsFunc->Strcmpi(KeyCommon[i].strKey, pszKey)==0)
++ {
++ rc = InfoAccess(HalDev, KeyCommon[i].enKey, Action, Value);
++ }
++ }
++ for(i=enCpmacStart+1;i<enCpmacEnd;i++)
++ {
++ if(HalDev->OsFunc->Strcmpi(KeyCpmac[i].strKey, pszKey)==0)
++ {
++ rc = InfoAccess(HalDev, KeyCpmac[i].enKey, Action, Value);
++ }
++ }
++/*
++ if (KeyFound == 0)
++ rc = (EC_MODULE|EC_FUNC_CONTROL|EC_VAL_KEY_NOT_FOUND);
++
++ if (ActionFound == 0)
++ rc = (EC_MODULE|EC_FUNC_CONTROL|EC_VAL_ACTION_NOT_FOUND);
++*/
++
++ return(rc);
++ }
++static bit32u ConfigGet(HAL_DEVICE *HalDev)
++ {
++ OS_FUNCTIONS *OsFunc = HalDev->OsFunc;
++ char *DeviceInfo = HalDev->DeviceInfo;
++ int i = HalDev->inst;
++ bit32u Value;
++ int Error;
++
++ /* get the configuration parameters common to all modules */
++ Error = ConfigGetCommon(HalDev);
++ if (Error) return (EC_CPMAC|Error);
++
++ if (HalDev->debug)
++ {
++ dbgPrintf("ConfigGet: haldev:0x%08X inst:%d base:0x%08X reset:%d\n", (bit32u) &HalDev, HalDev->inst, HalDev->dev_base, HalDev->ResetBit);
++ osfuncSioFlush();
++ }
++
++ Error = OsFunc->DeviceFindParmUint(DeviceInfo, pszMdioConnect,&Value); /*MJH+030805*/
++ if(!Error) HalDev->MdioConnect = Value;
++
++ Error = OsFunc->DeviceFindParmUint(DeviceInfo, "PhyMask",&Value);
++ if(!Error) HalDev->PhyMask = Value;
++
++ Error = OsFunc->DeviceFindParmUint(DeviceInfo, "MLink",&Value);
++ if(!Error) HalDev->MLinkMask = Value;
++
++ Error = OsFunc->DeviceFindParmUint(DeviceInfo, hcMdixMask, &Value);
++ if(!Error)
++ HalDev->MdixMask = Value;
++ else
++ HalDev->MdixMask = 0;
++
++ Error = OsFunc->DeviceFindParmUint(DeviceInfo, hcSize, &Value); /*MJH+030425*/
++ if(!Error) HalDev->CpmacSize = Value;
++
++ for(i=enCommonStart+1;i<enCommonEnd;i++)
++ {
++ Error = OsFunc->DeviceFindParmUint(DeviceInfo, KeyCommon[i].strKey, (bit32u*)&Value);
++ if(!Error)
++ {
++ InfoAccess(HalDev, KeyCommon[i].enKey, enSET, (bit32u*)&Value);
++ }
++ }
++ for(i=enCpmacStart+1;i<enCpmacEnd;i++)
++ {
++ Error = OsFunc->DeviceFindParmUint(DeviceInfo, KeyCpmac[i].strKey, (bit32u*)&Value);
++ if(!Error)
++ {
++ InfoAccess(HalDev, KeyCpmac[i].enKey, enSET, (bit32u*)&Value);
++ }
++ }
++ return (EC_NO_ERRORS);
++ }
++
++
++static void ConfigInit(HAL_DEVICE *HalDev)
++ {
++ if(HalDev->inst == 0)
++ {
++ HalDev->dev_base = 0xA8610000;
++ HalDev->ResetBit = 17;
++ HalDev->interrupt = 19;
++ HalDev->MLinkMask = 0;
++ HalDev->PhyMask = 0xAAAAAAAA;
++ }
++ else
++ {
++ HalDev->dev_base = 0xA8612800;
++ HalDev->ResetBit = 21;
++ HalDev->interrupt = 33; /*~RC3.02*/
++ HalDev->MLinkMask = 0;
++ HalDev->PhyMask = 0x55555555;
++ }
++ HalDev->RxMaxLen = 1518;
++ HalDev->MaxFrags = 2;
++ HalDev->MdioConnect = _CPMDIO_HD|_CPMDIO_FD|_CPMDIO_10|_CPMDIO_100|_CPMDIO_AUTOMDIX;
++ HalDev->debug=0xFFFFFFFF;
++ HalDev->debug=0;
++ }
++/* Shuts down the EMAC device
++ *
++ *@param HalDev EMAC instance. This was returned by halOpen()
++ *@param mode Indicates actions to tak on close.
++ <br>
++ *PARTIAL - Disable EMAC
++ <br>
++ *FULL - Disable EMAC and call OS to free all allocated memory
++ *
++ *@retval
++ * 0 OK
++ <br>
++ * Non-Zero Not OK
++ *
++ */
++static int halInit( HAL_DEVICE *HalDev)
++ {
++ int rc;
++
++ /* Verify proper device state */
++ if (HalDev->State != enDevFound)
++ return(EC_CPMAC|EC_FUNC_HAL_INIT|EC_VAL_INVALID_STATE);
++
++ /* Configure HAL defaults */
++ ConfigInit(HalDev);
++
++ /* Retrieve HAL configuration parameters from data store */
++ rc = ConfigGet(HalDev);
++ if (rc) return (rc);
++
++ /* Updated 030403*/
++ rc = HalDev->OsFunc->Control(HalDev->OsDev, hcCpuFrequency, hcGet, &HalDev->CpuFrequency); /*MJH+030403*/
++ if(rc)
++ HalDev->CpuFrequency = 20000000; /*20 Mhz default */ /*MJH+030403*/
++
++ rc = HalDev->OsFunc->Control(HalDev->OsDev, hcCpmacFrequency, hcGet, &HalDev->CpmacFrequency); /*MJH+030331*/
++ if(rc)
++ HalDev->CpmacFrequency = HalDev->CpuFrequency/2; /*MJH~030404*/
++
++ rc = HalDev->OsFunc->Control(HalDev->OsDev, hcMdioBusFrequency, hcGet, &HalDev->MdioBusFrequency); /*MJH+030402*/
++ if(rc)
++ HalDev->MdioBusFrequency = HalDev->CpmacFrequency;
++
++ rc = HalDev->OsFunc->Control(HalDev->OsDev, hcMdioClockFrequency, hcGet, &HalDev->MdioClockFrequency); /*MJH+030402*/
++ if(rc)
++ HalDev->MdioClockFrequency = 2200000; /* 2.2 Mhz PITS #14 */
++
++
++ /* update device state */
++ HalDev->State = enInitialized;
++
++ /* initialize statistics */
++ StatsInit(HalDev); /* +RC3.02 */
++
++ /* -RC3.02
++ StatsTable3[0].StatPtr = &HalDev->ChData[0].RxBufSize;
++ StatsTable3[1].StatPtr = &HalDev->ChData[0].RxBufferOffset;
++ StatsTable3[2].StatPtr = &HalDev->ChData[0].RxNumBuffers;
++ StatsTable3[3].StatPtr = &HalDev->ChData[0].RxServiceMax;
++ StatsTable3[4].StatPtr = &HalDev->ChData[0].TxNumBuffers;
++ StatsTable3[5].StatPtr = &HalDev->ChData[0].TxNumQueues;
++ StatsTable3[6].StatPtr = &HalDev->ChData[0].TxServiceMax;
++ */
++
++ return(EC_NO_ERRORS);
++ }
++static int halProbe(HAL_DEVICE *HalDev)
++ {
++ int inst = HalDev->inst;
++ OS_FUNCTIONS *OsFunc = HalDev->OsFunc;
++ int error_code;
++
++ if (HalDev->State != enConnected)
++ return (EC_CPMAC|EC_FUNC_PROBE|EC_VAL_INVALID_STATE);
++
++ if(HalDev->debug) dbgPrintf("halProbe: %d ",inst);
++
++ error_code = OsFunc->DeviceFindInfo(inst,"cpmac",&HalDev->DeviceInfo);
++
++ if(error_code)
++ return (EC_CPMAC|EC_FUNC_PROBE|EC_VAL_DEVICE_NOT_FOUND );
++
++ /* Set device state to DevFound */
++ HalDev->State = enDevFound;
++ return(EC_NO_ERRORS);
++ }
++static void ChannelConfigInit(HAL_DEVICE *HalDev, CHANNEL_INFO *HalChn)
++ {
++ int Ch = HalChn->Channel;
++ int Direction = HalChn->Direction;
++ int nTxBuffers = 256;
++
++ if (Direction == DIRECTION_TX)
++ {
++ HalDev->ChData[Ch].TxNumBuffers = nTxBuffers;
++ HalDev->ChData[Ch].TxNumQueues = 1;
++ HalDev->ChData[Ch].TxServiceMax = nTxBuffers/3;
++ HalDev->TxIntThreshold[Ch] = HalDev->ChData[Ch].TxServiceMax;
++ HalDev->TxIntThresholdMaster[Ch] = HalDev->TxIntThreshold[Ch];
++ }
++
++ if (Direction == DIRECTION_RX)
++ {
++ HalDev->ChData[Ch].RxNumBuffers = nTxBuffers*2;
++ HalDev->ChData[Ch].RxBufferOffset = 0;
++ HalDev->ChData[Ch].RxBufSize = 1518;
++ HalDev->ChData[Ch].RxServiceMax = nTxBuffers/3; /*Not a typo*/
++ }
++ }
++static int ChannelConfigApply(HAL_DEVICE *HalDev, CHANNEL_INFO *HalChn)
++ {
++ int Ch = HalChn->Channel;
++ int Direction = HalChn->Direction;
++
++ if (DBG(11))
++ {
++ dbgPrintf("halChannelConfigApply[%d:%d] haldev:0x%08X inst:%d base:0x%08X reset:%d\n", Ch, Direction, (bit32u) &HalDev, HalDev->inst, HalDev->dev_base, HalDev->ResetBit);
++ osfuncSioFlush();
++ }
++
++ if (Direction == DIRECTION_TX)
++ {
++ if (HalDev->ChIsOpen[Ch][Direction] == TRUE)
++ {
++ return(EC_CPMAC|EC_FUNC_CHSETUP|EC_VAL_TX_CH_ALREADY_OPEN);
++ }
++
++ /* Initialize Queue Data */
++ HalDev->TxActQueueHead[Ch][0] = 0;
++ HalDev->TxActQueueCount[Ch][0] = 0;
++ HalDev->TxActive[Ch][0] = FALSE;
++
++ /* Need to use a macro that takes channel as input */
++ CPMAC_TX0_HDP(HalDev->dev_base)=0;
++
++ /* Initialize buffer memory for the channel */
++ InitTcb(HalDev, Ch);
++
++ if(!HalDev->TxIntDisable)
++ CPMAC_TX_INTMASK_SET(HalDev->dev_base) = (1<<Ch); /* GSG 11/22 */
++ }
++ else
++ {
++ if (HalDev->ChIsOpen[Ch][Direction] == TRUE)
++ {
++ return(EC_CPMAC|EC_FUNC_CHSETUP|EC_VAL_RX_CH_ALREADY_OPEN);
++ }
++
++ /* Initialize Queue Data */
++ HalDev->RxActQueueHead[Ch] = 0;
++ HalDev->RxActQueueCount[Ch] = 0;
++
++ HalDev->RxActive[Ch] = FALSE;
++
++ /* Need to use a macro that takes channel as input */
++ CPMAC_RX0_HDP(HalDev->dev_base)=0;
++
++ /* Initialize buffer memory for the channel */
++ InitRcb(HalDev, Ch);
++
++ CPMAC_RX_INTMASK_SET(HalDev->dev_base) = (1<<Ch); /* GSG 11/22 */
++ }
++
++ HalDev->ChIsOpen[Ch][Direction] = TRUE; /* channel is open */
++
++ return (EC_NO_ERRORS);
++ }
++
++/* GSG 11/22
++ * Retrieves channel parameters from configuration file. Any parameters
++ * which are not found are ignored, and the HAL default value will apply,
++ * unless a new value is given through the channel structure in the call
++ * to ChannelSetup.
++ */
++static int ChannelConfigGet(HAL_DEVICE *HalDev, CHANNEL_INFO *HalChn)
++ {
++ int Ch = HalChn->Channel;
++ int Direction = HalChn->Direction;
++ OS_FUNCTIONS *OsFunc = HalDev->OsFunc;
++ unsigned int rc, Value;
++ void *ChInfo;
++
++ rc=OsFunc->DeviceFindParmValue(HalDev->DeviceInfo, channel_names[Ch], &ChInfo);
++ /* Do not fail if Channel Info not available for RC2 */
++ if (rc) return(0);
++/* if (rc) return(EC_CPMAC|EC_FUNC_CHSETUP|EC_VAL_CH_INFO_NOT_FOUND);*/
++
++ /* i don't care if a value is not found because they are optional */
++ if(Direction == DIRECTION_TX)
++ {
++ rc=OsFunc->DeviceFindParmUint(ChInfo, "TxNumBuffers", &Value);
++ if (!rc) HalDev->ChData[Ch].TxNumBuffers = Value;
++
++ /*rc=OsFunc->DeviceFindParmUint(ChInfo, "TxNumQueues", &Value);*/ /*MJH-030329*/
++ /*if (!rc) HalDev->ChData[Ch].TxNumQueues = Value;*/ /*MJH-030329*/
++
++ rc=OsFunc->DeviceFindParmUint(ChInfo, "TxServiceMax", &Value);
++ if (!rc)
++ {
++ HalDev->ChData[Ch].TxServiceMax = Value;
++ HalDev->TxIntThreshold[Ch] = HalDev->ChData[Ch].TxServiceMax;
++ HalDev->TxIntThresholdMaster[Ch] = HalDev->TxIntThreshold[Ch];
++ }
++ }
++ if(Direction == DIRECTION_RX)
++ {
++ rc=OsFunc->DeviceFindParmUint(ChInfo, "RxNumBuffers", &Value);
++ if (!rc) HalDev->ChData[Ch].RxNumBuffers = Value;
++
++ rc=OsFunc->DeviceFindParmUint(ChInfo, "RxBufferOffset", &Value);
++ if (!rc) HalDev->ChData[Ch].RxBufferOffset = Value;
++
++ rc=OsFunc->DeviceFindParmUint(ChInfo, "RxBufSize", &Value);
++ if (!rc) HalDev->ChData[Ch].RxBufSize = Value;
++
++ rc=OsFunc->DeviceFindParmUint(ChInfo, "RxServiceMax", &Value);
++ if (!rc) HalDev->ChData[Ch].RxServiceMax = Value;
++ }
++ return (EC_NO_ERRORS);
++ }
++#define ChannelUpdate(Field) if(HalChn->Field != 0xFFFFFFFF) HalDev->ChData[Ch].Field = HalChn->Field
++
++static void ChannelConfigUpdate(HAL_DEVICE *HalDev, CHANNEL_INFO *HalChn)
++ {
++ int Ch = HalChn->Channel;
++ int Direction = HalChn->Direction;
++#ifdef __CPHAL_DEBUG
++ if (DBG(1))
++ {
++ dbgPrintf("\nChnUpd-HalDev:%08X,Chn:%d:%d\n", (bit32u)HalDev, Ch, Direction); osfuncSioFlush();
++ }
++#endif
++ if (Direction == DIRECTION_TX)
++ {
++ ChannelUpdate(TxNumBuffers);
++ /*ChannelUpdate(TxNumQueues);*/ /*MJH~030329*/
++ ChannelUpdate(TxServiceMax);
++ HalDev->TxIntThreshold[Ch] = HalDev->ChData[Ch].TxServiceMax;
++ HalDev->TxIntThresholdMaster[Ch] = HalDev->TxIntThreshold[Ch];
++ }
++ else
++ if (Direction == DIRECTION_RX)
++ {
++ ChannelUpdate(RxBufferOffset);
++ ChannelUpdate(RxBufSize);
++ ChannelUpdate(RxNumBuffers);
++ ChannelUpdate(RxServiceMax);
++#ifdef __CPHAL_DEBUG
++ if (DBG(1))
++ {
++ dbgPrintf("\nRxNumBuffers %d\n",HalChn->RxNumBuffers); osfuncSioFlush();
++ }
++#endif
++ }
++ }
++static int halChannelSetup(HAL_DEVICE *HalDev, CHANNEL_INFO *HalChn, OS_SETUP *OsSetup)
++ {
++ int Direction;
++ int Ch;
++ int rc;
++
++ /* Verify proper device state */
++ if (HalDev->State < enInitialized)
++ return (EC_CPMAC|EC_FUNC_CHSETUP|EC_VAL_INVALID_STATE);
++
++ /* We require the channel structure to be passed, even if it only contains
++ the channel number */
++ if (HalChn == NULL)
++ {
++ return(EC_CPMAC|EC_FUNC_CHSETUP|EC_VAL_NULL_CH_STRUCT);
++ }
++
++ Ch = HalChn->Channel;
++ Direction = HalChn->Direction;
++
++ /* This should check on Maximum Channels for RX or TX,
++ they might be different Mick 021124 */
++ if ((Ch < 0) || (Ch > (MAX_CHAN-1)))
++ {
++ return(EC_CPMAC|EC_FUNC_CHSETUP|EC_VAL_INVALID_CH);
++ }
++
++ /* if channel is already open, this call is invalid */
++ if (HalDev->ChIsOpen[Ch][Direction] == TRUE)
++ {
++ return(EC_CPMAC|EC_FUNC_CHSETUP|EC_VAL_CH_ALREADY_OPEN);
++ }
++
++ /* channel is closed, but might be setup. If so, reopen the hardware channel. */
++ if (HalDev->ChIsSetup[Ch][Direction] == FALSE)
++ {
++ /* Setup channel configuration */
++ HalDev->ChData[Ch].Channel = Ch;
++
++ /* Store OS_SETUP */
++ HalDev->ChData[Ch].OsSetup = OsSetup;
++
++ /* Framework :
++ Set Default Values
++ Update with options.conf
++ Apply driver updates
++ */
++ ChannelConfigInit(HalDev, HalChn);
++ ChannelConfigGet(HalDev, HalChn);
++ ChannelConfigUpdate(HalDev, HalChn);
++
++ /* cppi.c needs to use Rx/TxServiceMax */
++ HalDev->BuffersServicedMax = 169; /* TEMP */
++
++ HalDev->ChIsSetup[Ch][Direction] = TRUE;
++ }
++
++ rc = EC_NO_ERRORS;
++
++ /* If the hardware has been opened (is out of reset), then configure the channel
++ in the hardware. NOTE: ChannelConfigApply calls the CPSAR ChannelSetup()! */
++ if (HalDev->State == enOpened)
++ {
++ rc = ChannelConfigApply(HalDev, HalChn);
++ }
++
++ return (rc);
++ }
++
++
++static int miiInfoGet(HAL_DEVICE *HalDev, bit32u *miiBaseAddress, bit32u *miiResetBit)
++ {
++ int rc;
++ void *DeviceInfo;
++ OS_FUNCTIONS *OsFunc = HalDev->OsFunc;
++
++ /* Only one instance of cpmdio */
++ rc = OsFunc->DeviceFindInfo(0,"cpmdio",&DeviceInfo); /*~RC3.02*/
++
++ if(rc)
++ return (EC_DEV_CPMDIO|EC_FUNC_OPEN|EC_VAL_DEVICE_NOT_FOUND );
++
++ rc = OsFunc->DeviceFindParmUint(DeviceInfo, "base",miiBaseAddress);
++ if(rc)
++ rc=EC_DEV_CPMDIO|EC_FUNC_OPEN|EC_VAL_NO_BASE;
++
++ rc = OsFunc->DeviceFindParmUint(DeviceInfo, "reset_bit",miiResetBit);
++ if(rc)
++ rc=EC_DEV_CPMDIO|EC_FUNC_OPEN|EC_VAL_NO_BASE;
++
++
++ /* See if need to make mdio functional in GPIO */
++ gpioCheck(HalDev, DeviceInfo);
++
++ if(DBG(0))
++ dbgPrintf("miiBase: 0x%08X %u\n", *miiBaseAddress, *miiResetBit);
++ return(rc);
++ }
++static void ephyCheck(HAL_DEVICE *HalDev)
++ { /*+RC3.02*/
++ int rc;
++ void *DeviceInfo;
++ int mii_phy;
++ int reset_bit;
++ OS_FUNCTIONS *OsFunc = HalDev->OsFunc;
++
++ rc = OsFunc->DeviceFindInfo(0,"ephy",&DeviceInfo);
++ if(rc) return;
++
++ rc = OsFunc->DeviceFindParmUint(DeviceInfo, "mii_phy",&mii_phy);
++ if(rc) return;
++
++ rc = OsFunc->DeviceFindParmUint(DeviceInfo, "reset_bit",&reset_bit);
++ if(rc) return;
++
++ if (HalDev->PhyMask & (1 << mii_phy))
++ {
++ *(volatile bit32u *)(HalDev->ResetBase) |= (1 << reset_bit); /*+RC3.02*/
++ resetWait(HalDev);
++ }
++ } /*+RC3.02*/
++static void AutoNegotiate(HAL_DEVICE *HalDev)
++ {
++ int size;
++ bit32u ModID, RevMaj, RevMin;
++ PHY_DEVICE *PhyDev;
++ bit32u miiBaseAddress;
++ bit32u miiResetBit;
++
++ /* Verify proper device state */
++ if (HalDev->State < enOpened)
++ return;
++
++ miiInfoGet(HalDev, &miiBaseAddress, &miiResetBit);
++
++ cpMacMdioGetVer(miiBaseAddress, &ModID, &RevMaj, &RevMin);
++ if(HalDev->debug)
++ dbgPrintf("Mdio Module Id %d, Version %d.%d\n", ModID, RevMaj, RevMin);
++
++ size = cpMacMdioGetPhyDevSize();
++ PhyDev = (PHY_DEVICE *) HalDev->OsFunc->Malloc( size );
++
++ HalDev->PhyDev = PhyDev;
++
++ ephyCheck(HalDev);
++
++ cpMacMdioInit( PhyDev, miiBaseAddress, HalDev->inst, HalDev->PhyMask, HalDev->MLinkMask, HalDev->MdixMask, HalDev->ResetBase, miiResetBit, HalDev->MdioBusFrequency, HalDev->MdioClockFrequency, HalDev->debug, HalDev); /*MJH~030402*/
++ MdioSetPhyMode(HalDev);
++
++ return;
++ }
++static int halOpen(HAL_DEVICE *HalDev)
++ {
++ unsigned char *MacAddr;
++ int i;
++ int j;
++ int rc, Ticks;
++
++ if (HalDev->debug)
++ {
++ dbgPrintf("halOpen: haldev:0x%08X inst:%d base:0x%08X reset:%d\n", (bit32u) &HalDev, HalDev->inst, HalDev->dev_base, HalDev->ResetBit);
++ osfuncSioFlush();
++ }
++
++ /* Verify proper device state */
++ if (HalDev->State < enInitialized)
++ return (EC_CPMAC|EC_FUNC_OPEN|EC_VAL_INVALID_STATE);
++
++
++ /* take CPMAC out of reset - GSG 11/20*/
++ if ((VOLATILE32(HalDev->ResetBase) & (1 << HalDev->ResetBit)) != 0)
++ {
++ /* perform normal close duties */
++ CPMAC_MACCONTROL(HalDev->dev_base) &= ~MII_EN;
++ CPMAC_TX_CONTROL(HalDev->dev_base) &= ~TX_EN;
++ CPMAC_RX_CONTROL(HalDev->dev_base) &= ~RX_EN;
++
++ /* disable interrupt masks */
++ CPMAC_TX_INTMASK_CLEAR(HalDev->dev_base) = 0xFF;
++ CPMAC_RX_INTMASK_CLEAR(HalDev->dev_base) = 0xFF;
++ }
++
++ /* take CPMAC out of reset */
++ *(volatile bit32u *)(HalDev->ResetBase) &= ~(1 << HalDev->ResetBit);
++ resetWait(HalDev);
++ *(volatile bit32u *)(HalDev->ResetBase) |= (1 << HalDev->ResetBit);
++ resetWait(HalDev);
++
++ /* After Reset clear the Transmit and Receive DMA Head Descriptor Pointers */
++
++ CPMAC_TX0_HDP(HalDev->dev_base)=0;
++ CPMAC_TX1_HDP(HalDev->dev_base)=0;
++ CPMAC_TX2_HDP(HalDev->dev_base)=0;
++ CPMAC_TX3_HDP(HalDev->dev_base)=0;
++ CPMAC_TX4_HDP(HalDev->dev_base)=0;
++ CPMAC_TX5_HDP(HalDev->dev_base)=0;
++ CPMAC_TX6_HDP(HalDev->dev_base)=0;
++ CPMAC_TX7_HDP(HalDev->dev_base)=0;
++
++ /* Rx Init */
++
++ CPMAC_RX0_HDP(HalDev->dev_base) = 0;
++ CPMAC_RX1_HDP(HalDev->dev_base) = 0;
++ CPMAC_RX2_HDP(HalDev->dev_base) = 0;
++ CPMAC_RX3_HDP(HalDev->dev_base) = 0;
++ CPMAC_RX4_HDP(HalDev->dev_base) = 0;
++ CPMAC_RX5_HDP(HalDev->dev_base) = 0;
++ CPMAC_RX6_HDP(HalDev->dev_base) = 0;
++ CPMAC_RX7_HDP(HalDev->dev_base) = 0;
++
++ CPMAC_RX_BUFFER_OFFSET(HalDev->dev_base) = 0;
++
++ /* Init Tx and Rx DMA */
++
++ CPMAC_TX_CONTROL(HalDev->dev_base) |= TX_EN;
++ CPMAC_RX_CONTROL(HalDev->dev_base) |= RX_EN;
++
++ CPMAC_MAC_INTMASK_SET(HalDev->dev_base) |=2; /* Enable Adaptercheck Ints */
++ HalDev->OsFunc->Control(HalDev->OsDev, pszMacAddr, hcGet, &MacAddr); /* GSG 11/22 */
++ MacAddressSave(HalDev, MacAddr);
++
++ HalDev->HostErr = 0; /* Clear Adapter Check indicator */
++ HalDev->State = enOpened; /* Change device state */
++
++ /* Start MDIO Negotiation */
++ AutoNegotiate(HalDev);
++
++ /* Enable the Os Timer */
++ Ticks = HalDev->CpuFrequency / 100; /* 10 milli-secs */ /*MJH~030402*/
++ HalDev->OsFunc->Control(HalDev->OsDev, pszTick, hcSet, &Ticks); /* GSG 11/22 */
++ HalDev->OsFunc->IsrRegister(HalDev->OsDev, halIsr, HalDev->interrupt);
++
++ /* GSG +030523 Malloc space for the Rx fraglist */
++ HalDev->fraglist = HalDev->OsFunc->Malloc(HalDev->MaxFrags * sizeof(FRAGLIST));
++
++ /* Any pre-open configuration */
++
++ /* For any channels that have been pre-initialized, set them up now */
++ /* Note : This loop should not use MAX_CHN, it should only
++ loop through Channels Setup, memory should not be reserved
++ until Channel is Setup
++ */
++ for(i=0; i<MAX_CHAN; i++) /* i loops through Channels */
++ for(j=0; j<2; j++) /* j loops through DIRECTION values, 0 and 1 */
++ {
++ if(HalDev->ChIsSetup[i][j]==TRUE) /* If the Channel and Direction have been Setup */
++ if(HalDev->ChIsOpen[i][j]==FALSE) /* but not opened, then Apply Values now */
++ {
++ CHANNEL_INFO HalChn;
++ HalChn.Channel = i;
++ HalChn.Direction = j;
++ rc = ChannelConfigApply(HalDev, &HalChn);
++ if(rc != EC_NO_ERRORS)
++ return(rc);
++ }
++ } /* End of looping through Channel/Direction */
++
++ ConfigApply(HalDev); /* Apply Configuration Values to Device */
++ CPMAC_MACCONTROL(HalDev->dev_base) |= MII_EN; /* MAC_EN */
++ if(DBG(0))
++ dbgPrintf("[halOpen]MacControl:%08X\n", CPMAC_MACCONTROL(HalDev->dev_base));
++ return(EC_NO_ERRORS);
++ }
++
++#define INT_PENDING (MAC_IN_VECTOR_TX_INT_OR | MAC_IN_VECTOR_RX_INT_OR | MAC_IN_VECTOR_HOST_INT)
++static int halShutdown(HAL_DEVICE *HalDev)
++ {
++ int Ch, Queue; /*GSG+030514*/
++
++ /* Verify proper device state */
++ if (HalDev->State == enOpened)
++ halClose(HalDev, 3); /* GSG ~030429 */
++
++ /* Buffer/descriptor resources may still need to be freed if a Close
++ Mode 1 was performed prior to Shutdown - clean up here */ /*GSG+030514*/
++ for (Ch=0; Ch<MAX_CHAN; Ch++)
++ {
++ if (HalDev->RcbStart[Ch] != 0)
++ FreeRx(HalDev,Ch);
++
++ for(Queue=0; Queue<MAX_QUEUE; Queue++)
++ {
++ if (HalDev->TcbStart[Ch][Queue] != 0)
++ FreeTx(HalDev,Ch,Queue);
++ }
++ }
++
++ /* free the HalFunc */
++ HalDev->OsFunc->Free(HalDev->HalFuncPtr);
++
++ /* free the HAL device */
++ HalDev->OsFunc->Free(HalDev);
++
++ return(EC_NO_ERRORS);
++ }
++int halIsr(HAL_DEVICE *HalDev, int *MorePackets)
++{
++ bit32u IntVec;
++ int Serviced;
++ int PacketsServiced=0;
++ int Channel;
++ int TxMorePackets=0;
++ int RxMorePackets=0;
++
++ /* Verify proper device state - important because a call prior to Open would
++ result in a lockup */
++ if (HalDev->State != enOpened)
++ return(EC_CPMAC|EC_FUNC_DEVICE_INT|EC_VAL_INVALID_STATE);
++
++ IntVec = CPMAC_MAC_IN_VECTOR(HalDev->dev_base);
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("\nhalIsr: inst %d, IntVec 0x%X\n", HalDev->inst, IntVec); osfuncSioFlush();/* GSG 11/22 */
++ }
++#endif
++
++ HalDev->IntVec = IntVec;
++ if (IntVec & MAC_IN_VECTOR_TX_INT_OR)
++ {
++ int TxServiceMax=0; /* Compiler complains if not initialized */
++
++ Channel = (IntVec & 0x7);
++
++ if(HalDev->TxIntDisable)
++ {
++ CPMAC_TX_INTMASK_CLEAR(HalDev->dev_base) = (1<<Channel); /* Disable Interrupt for Channel */
++ TxServiceMax = HalDev->ChData[Channel].TxServiceMax;
++ HalDev->ChData[Channel].TxServiceMax = 10000; /* Need to service all packets in the Queue */
++ }
++
++ PacketsServiced |= TxInt(HalDev, Channel, 0, &TxMorePackets);
++
++ if(HalDev->TxIntDisable)
++ HalDev->ChData[Channel].TxServiceMax = TxServiceMax;
++ }
++
++ if (IntVec & MAC_IN_VECTOR_RX_INT_OR)
++ {
++ Channel = (IntVec >> 8) & 0x7;
++ Serviced = RxInt(HalDev, Channel, &RxMorePackets);
++ PacketsServiced |= (Serviced<<16);
++ }
++
++ if (IntVec & MAC_IN_VECTOR_HOST_INT)
++ {
++ /* Adaptercheck */
++ HalDev->HostErr = 1;
++ HalDev->MacStatus = CPMAC_MACSTATUS(HalDev->dev_base);
++ osfuncStateChange(); /*MJH+030328*/
++ if(DBG(0))
++ {
++ dbgPrintf("Adaptercheck: %08x for base:%X\n",HalDev->MacStatus, (bit32u)HalDev->dev_base);
++ osfuncSioFlush();
++ }
++ }
++ *MorePackets = (TxMorePackets | RxMorePackets);
++ return (PacketsServiced);
++}
++
++int halPacketProcessEnd(HAL_DEVICE *HalDev)
++{
++ int base = HalDev->dev_base;
++ CPMAC_MAC_EOI_VECTOR(base) = 0;
++ return(0);
++}
++
++
++
++static int PhyCheck(HAL_DEVICE *HalDev)
++ {
++ return(cpMacMdioTic(HalDev->PhyDev));
++ }
++static int halTick(HAL_DEVICE *HalDev)
++{
++ int TickChange;
++
++ if(HalDev->State < enOpened)
++ return (EC_CPMAC|EC_FUNC_TICK|EC_VAL_INVALID_STATE);
++
++ /* if NO Phy no need to check Link */
++ if(HalDev->MdioConnect & _CPMDIO_NOPHY)
++ return(EC_NO_ERRORS); /* No change in Phy State detected */
++
++ TickChange = PhyCheck(HalDev);
++ /* Phy State Change Detected */
++ if(TickChange == 1)
++ {
++ /* MDIO indicated a change */
++ DuplexUpdate(HalDev);
++ osfuncStateChange();
++ return(EC_NO_ERRORS);
++ }
++
++ /* if in AutoMdix mode, and Flip request received, inform OS */
++ if( (HalDev->MdioConnect & _CPMDIO_AUTOMDIX) &&
++ (TickChange & _MIIMDIO_MDIXFLIP))
++ {
++ bit32u Mdix;
++ Mdix = TickChange & 0x1; /* Mdix mode stored in bit 0 */
++ HalDev->OsFunc->Control(HalDev->OsDev, hcMdioMdixSwitch, hcSet, &Mdix);
++ return(EC_NO_ERRORS);
++ }
++
++ return(EC_NO_ERRORS);
++}
++
++int halCpmacInitModule(HAL_DEVICE **pHalDev, OS_DEVICE *OsDev, HAL_FUNCTIONS **pHalFunc,
++ OS_FUNCTIONS *OsFunc, int OsFuncSize, int *HalFuncSize, int Inst)
++ {
++ HAL_DEVICE *HalDev;
++ HAL_FUNCTIONS *HalFunc;
++
++ if (OsFuncSize < sizeof(OS_FUNCTIONS))
++ return (EC_CPMAC|EC_FUNC_HAL_INIT|EC_VAL_OS_VERSION_NOT_SUPPORTED);
++
++ HalDev = (HAL_DEVICE *) OsFunc->MallocDev(sizeof(HAL_DEVICE));
++ if (!HalDev)
++ return (EC_CPMAC|EC_FUNC_HAL_INIT|EC_VAL_MALLOC_DEV_FAILED);
++
++ /* clear the HalDev area */
++ OsFunc->Memset(HalDev, 0, sizeof(HAL_DEVICE));
++
++ /* Initialize the size of hal functions */
++ *HalFuncSize = sizeof (HAL_FUNCTIONS);
++
++ HalFunc = (HAL_FUNCTIONS *) OsFunc->Malloc(sizeof(HAL_FUNCTIONS));
++ if (!HalFunc)
++ return (EC_CPMAC|EC_FUNC_HAL_INIT|EC_VAL_MALLOC_FAILED);
++
++ /* clear the function pointers */
++ OsFunc->Memset(HalFunc, 0, sizeof(HAL_FUNCTIONS));
++
++ HalDev->OsDev = OsDev;
++ HalDev->OsOpen = OsDev;
++ HalDev->inst = Inst;
++ HalDev->OsFunc = OsFunc;
++ HalDev->HalFunc = HalFunc;
++ /* Remove the following from cppi, replace with HalFunc */
++ HalDev->HalFuncPtr = HalFunc; /* GSG 11/20 changed name to match cppi */
++
++ /****************************************************************/
++ /* POPULATE HALFUNC */
++ /****************************************************************/
++ HalFunc->ChannelSetup = halChannelSetup;
++ HalFunc->ChannelTeardown = halChannelTeardown; /* GSG 11/20 */
++ HalFunc->Close = halClose; /* GSG 11/20 */
++ HalFunc->Control = halControl; /* GSG 11/22 */
++ HalFunc->Init = halInit;
++ HalFunc->Open = halOpen;
++ HalFunc->PacketProcessEnd = halPacketProcessEnd;
++ HalFunc->Probe = halProbe;
++ HalFunc->RxReturn = halRxReturn;
++ HalFunc->Send = halSend;
++ HalFunc->Shutdown = halShutdown;
++ HalFunc->Tick = halTick;
++
++ /* HalFunc->Status = halStatus;*/ /* GSG 11/22 */
++ /* pass the HalDev and HalFunc back to the caller */
++
++ *pHalDev = HalDev;
++ *pHalFunc = HalFunc;
++
++ HalDev->State = enConnected; /* Initialize the hardware state */
++
++ if (HalDev->debug) HalDev->OsFunc->Printf("halCpmacInitModule: Leave\n");
++ return(0);
++ }
++
++int cpmacRandomRange(HAL_DEVICE *HalDev, int min, int max)
++{
++ int iTmp;
++ iTmp = cpmacRandom(HalDev);
++ iTmp %= ((max-min)+1);
++ iTmp += min;
++ return(iTmp);
++}
++
++int cpmacRandom(HAL_DEVICE *HalDev)
++{
++ int iTmp;
++ iTmp = CPMAC_BOFFTEST(HalDev->dev_base);
++ iTmp >>= 16; /* get rndnum field */
++ iTmp &= (0x3FF); /* field is 10 bits wide */
++ return(iTmp);
++}
+diff -urN linux.old/drivers/net/avalanche_cpmac/hcpmac.h linux.dev/drivers/net/avalanche_cpmac/hcpmac.h
+--- linux.old/drivers/net/avalanche_cpmac/hcpmac.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/hcpmac.h 2005-07-12 02:48:42.175574000 +0200
+@@ -0,0 +1,383 @@
++/** @file***********************************************************************
++ * TNETDxxxx Software Support
++ * Copyright (c) 2002 Texas Instruments Incorporated. All Rights Reserved.
++ *
++ * FILE:
++ *
++ * DESCRIPTION:
++ * This file contains definitions for the HAL EMAC API
++ *
++ * HISTORY:
++ * xxXxx01 Denis 1.00 Original Version created.
++ * 22Jan02 Denis/Mick 1.01 Modified for HAL EMAC API
++ * 24Jan02 Denis/Mick 1.02 Speed Improvements
++ * 28Jan02 Denis/Mick 1.16 Made function calls pointers
++ * 28Jan02 Mick 1.18 Split into separate modules
++ * @author Michael Hanrahan
++ * @version 1.02
++ * @date 24-Jan-2002
++ *****************************************************************************/
++#ifndef _INC_HCPMAC
++#define _INC_HCPMAC
++
++/** \namespace CPMAC_Version
++This documents version 01.07.04 of the CPMAC CPHAL.
++*/
++const char *pszVersion_CPMAC="CPMAC 01.07.08 "__DATE__" "__TIME__;
++
++/* CHECK THESE LOCATIONS */
++#define TEARDOWN_VAL 0xfffffffc
++#define CB_OFFSET_MASK 0xFFFF0000
++
++
++#define MAX_CHAN 8
++#define MAX_QUEUE 1
++
++typedef struct
++ {
++ bit32 HNext; /*< Hardware's pointer to next buffer descriptor */
++ bit32 BufPtr; /*< Pointer to the data buffer */
++ bit32 Off_BLen; /*< Contains buffer offset and buffer length */
++ bit32 mode; /*< SOP, EOP, Ownership, EOQ, Teardown, Q Starv, Length */
++ void *Next;
++ void *OsInfo;
++ void *Eop;
++#ifdef __CPHAL_DEBUG
++ bit32 DbgSop;
++ bit32 DbgData;
++ bit32 DbgFraglist;
++#endif
++ }HAL_TCB;
++
++typedef volatile struct hal_private
++ {
++ bit32 HNext; /*< Hardware's pointer to next buffer descriptor */
++ bit32 BufPtr; /*< Pointer to the data buffer */
++ bit32 Off_BLen; /*< Contains buffer offset and buffer length */
++ bit32 mode; /*< SOP, EOP, Ownership, EOQ, Teardown Complete bits */
++ void *DatPtr;
++ void *Next;
++ void *OsInfo;
++ void *Eop;
++ }HAL_RCB;
++
++#define MAX_NEEDS 512 /*MJH+030409*/
++/* HAL */
++
++typedef struct hal_device
++ {
++ OS_DEVICE *OsDev;
++ OS_FUNCTIONS *OsFunc;
++ /*OS_SETUP *OsSetup;*/ /* -GSG 030508 */
++ int inst;
++ bit32u rxbufseq;
++
++
++ bit32 dev_base;
++ bit32 offset;
++
++ bit32u ResetBase; /* GSG 10/20 */
++ int ResetBit;
++ void *OsOpen;
++ bit32u IntVec;
++ PHY_DEVICE *PhyDev;
++ bit32u EmacDuplex;
++ bit32u EmacSpeed;
++ bit32u PhyNum;
++ bit32u MLinkMask;
++ bit32u PhyMask;
++ bit32u MdixMask;
++
++ bit32u Linked;
++ DEVICE_STATE State;
++ unsigned char *MacAddr;
++ HAL_FUNCTIONS *HalFuncPtr; /* GSG 11/20 changed name to match cppi */
++ HAL_FUNCTIONS *HalFunc;
++/* unsigned int CpuFreq;*/ /*MJH-030402*/
++ unsigned int MdioConnect;
++ unsigned int HostErr;
++
++/************************************************************************/
++/* */
++/* R E G I S T E R S */
++/* */
++/************************************************************************/
++
++ bit32u RxMbpEnable;
++ bit32u RxUnicastSet;
++ bit32u RxUnicastClear;
++ bit32u RxMaxLen;
++ bit32u RxFilterLowThresh;
++ bit32u Rx0FlowThresh;
++ bit32u MacControl;
++ bit32u MacStatus;
++ bit32u MacHash1;
++ bit32u MacHash2;
++
++/************************************************************************/
++/* */
++/* O P T I O N S */
++/* */
++/************************************************************************/
++
++ char *DeviceInfo;
++ bit32u interrupt;
++
++
++ bit32u RxPassCrc;
++ bit32u RxCaf;
++ bit32u RxCef;
++ bit32u RxBcast;
++ bit32u RxBcastCh;
++ HAL_RCB *RcbPool[MAX_CHAN];
++ bit32 RxActQueueCount[MAX_CHAN];
++ HAL_RCB *RxActQueueHead[MAX_CHAN];
++ HAL_RCB *RxActQueueTail[MAX_CHAN];
++ bit32 RxActive[MAX_CHAN];
++ HAL_TCB *TcbPool[MAX_CHAN][MAX_QUEUE];
++ bit32 TxActQueueCount[MAX_CHAN][MAX_QUEUE];
++ HAL_TCB *TxActQueueHead[MAX_CHAN][MAX_QUEUE];
++ HAL_TCB *TxActQueueTail[MAX_CHAN][MAX_QUEUE];
++ bit32 TxActive[MAX_CHAN][MAX_QUEUE];
++ bit32 TxTeardownPending[MAX_CHAN];
++ bit32 RxTeardownPending[MAX_CHAN];
++ bit32 ChIsOpen[MAX_CHAN][2];
++ bit32 ChIsSetup[MAX_CHAN][2];
++ FRAGLIST *fraglist;
++ char *TcbStart[MAX_CHAN][MAX_QUEUE];
++ char *RcbStart[MAX_CHAN];
++ bit32 RcbSize[MAX_CHAN];
++/* STAT_INFO Stats; */
++ bit32 Inst;
++ bit32u BuffersServicedMax;
++ CHANNEL_INFO ChData[MAX_CHAN];
++ bit32u MdioClockFrequency; /*MJH+030402*/
++ bit32u MdioBusFrequency; /*MJH+030402*/
++ bit32u CpuFrequency; /*MJH+030402*/
++ bit32u CpmacFrequency; /*MJH+030403*/
++ bit32u CpmacSize; /*MJH+030425*/
++ int debug;
++ bit32u NeedsCount; /*MJH+030409*/
++ HAL_RECEIVEINFO *Needs[MAX_NEEDS]; /*MJH+030409*/
++ int MaxFrags;
++ int TxIntThreshold[MAX_CHAN]; /* MJH 040621 NSP Performance Update */
++ int TxIntThresholdMaster[MAX_CHAN]; /* MJH 040827 NSP Performance Update */
++ int TxIntDisable; /* MJH 040621 NSP Performance Update */
++ }HALDEVICE;
++
++#define STATS_MAX 36
++
++#define MACCONTROL_MASK (TX_PTYPE|TX_PACE|TX_FLOW_EN|RX_FLOW_EN|CTRL_LOOPBACK)
++#define RX_MBP_ENABLE_MASK \
++ (RX_PASS_CRC|RX_QOS_EN|RX_NO_CHAIN| \
++ RX_CMF_EN|RX_CSF_EN|RX_CEF_EN|RX_CAF_EN|RX_PROM_CH_MASK| \
++ RX_BROAD_EN|RX_BROAD_CH_MASK|RX_MULT_EN|RX_MULT_CH_MASK)
++
++
++#define MBP_UPDATE(Mask, On) \
++ if(On) HalDev->RxMbpEnable |= Mask; \
++ else HalDev->RxMbpEnable &= ~Mask
++
++#define CONTROL_UPDATE(Mask, On) \
++ if(On) HalDev->MacControl |= Mask; \
++ else HalDev->MacControl &= ~Mask
++
++
++#define UPDATE_TX_PTYPE(Value) CONTROL_UPDATE(TX_PTYPE,Value)
++#define UPDATE_TX_PACE(Value) CONTROL_UPDATE(TX_PACE,Value)
++#define UPDATE_MII_EN(Value) CONTROL_UPDATE(MII_EN,Value)
++#define UPDATE_TX_FLOW_EN(Value) CONTROL_UPDATE(TX_FLOW_EN,Value)
++#define UPDATE_RX_FLOW_EN(Value) CONTROL_UPDATE(RX_FLOW_EN,Value)
++#define UPDATE_CTRL_LOOPBACK(Value) CONTROL_UPDATE(CTRL_LOOPBACK,Value)
++#define UPDATE_FULLDUPLEX(Value) CONTROL_UPDATE(FULLDUPLEX,(Value))
++
++#define UPDATE_RX_PASS_CRC(Value) MBP_UPDATE(RX_PASS_CRC, Value)
++#define UPDATE_RX_QOS_EN(Value) MBP_UPDATE(RX_QOS_EN, Value)
++#define UPDATE_RX_NO_CHAIN(Value) MBP_UPDATE(RX_NO_CHAIN, Value)
++#define UPDATE_RX_CMF_EN(Value) MBP_UPDATE(RX_CMF_EN, Value)
++#define UPDATE_RX_CSF_EN(Value) MBP_UPDATE(RX_CSF_EN, Value)
++#define UPDATE_RX_CEF_EN(Value) MBP_UPDATE(RX_CEF_EN, Value)
++#define UPDATE_RX_CAF_EN(Value) MBP_UPDATE(RX_CAF_EN, Value)
++#define UPDATE_RX_BROAD_EN(Value) MBP_UPDATE(RX_BROAD_EN, Value)
++#define UPDATE_RX_MULT_EN(Value) MBP_UPDATE(RX_MULT_EN, Value)
++
++#define UPDATE_RX_PROM_CH(Value) \
++ HalDev->RxMbpEnable &= ~RX_PROM_CH_MASK; \
++ HalDev->RxMbpEnable |= RX_PROM_CH(Value)
++
++#define UPDATE_RX_BROAD_CH(Value) \
++ HalDev->RxMbpEnable &= ~RX_BROAD_CH_MASK; \
++ HalDev->RxMbpEnable |= RX_BROAD_CH(Value)
++
++#define UPDATE_RX_MULT_CH(Value) \
++ HalDev->RxMbpEnable &= ~RX_MULT_CH_MASK; \
++ HalDev->RxMbpEnable |= RX_MULT_CH(Value)
++
++
++
++typedef enum
++ {
++ /* CPMAC */
++ enCpmacStart=0,
++ enStats0,
++ enStats1,
++ enStats2,
++ enStats3,
++ enStats4,
++ enStatsDump,
++ enStatsClear,
++ enRX_PASS_CRC,
++ enRX_QOS_EN,
++ enRX_NO_CHAIN,
++ enRX_CMF_EN,
++ enRX_CSF_EN,
++ enRX_CEF_EN,
++ enRX_CAF_EN,
++ enRX_PROM_CH,
++ enRX_BROAD_EN,
++ enRX_BROAD_CH,
++ enRX_MULT_EN,
++ enRX_MULT_CH,
++
++ enTX_PTYPE,
++ enTX_PACE,
++ enMII_EN,
++ enTX_FLOW_EN,
++ enRX_FLOW_EN,
++ enCTRL_LOOPBACK,
++
++ enRX_MAXLEN,
++ enRX_FILTERLOWTHRESH,
++ enRX0_FLOWTHRESH,
++ enRX_UNICAST_SET,
++ enRX_UNICAST_CLEAR,
++ enMdioConnect,
++ enMAC_ADDR_GET,
++ enTick,
++ enRX_MULTICAST,
++ enRX_MULTI_ALL,
++ enRX_MULTI_SINGLE,
++ enVersion,
++ enCpmacEnd /* Last entry */
++ }INFO_KEY_CPMAC;
++
++static const char pszVersion[] = "Version";
++static const char pszStats0[] = "Stats0";
++static const char pszStats1[] = "Stats1";
++static const char pszStats2[] = "Stats2";
++static const char pszStats3[] = "Stats3";
++static const char pszStats4[] = "Stats4";
++static const char pszStatsDump[] = "StatsDump";
++static const char pszStatsClear[] = "StatsClear";
++
++/********************************************************************
++**
++** RX MBP ENABLE
++**
++********************************************************************/
++static const char pszRX_PASS_CRC[] = "RX_PASS_CRC";
++static const char pszRX_QOS_EN[] = "RX_QOS_EN";
++static const char pszRX_NO_CHAIN[] = "RX_NO_CHAIN";
++static const char pszRX_CMF_EN[] = "RX_CMF_EN";
++static const char pszRX_CSF_EN[] = "RX_CSF_EN";
++static const char pszRX_CEF_EN[] = "RX_CEF_EN";
++static const char pszRX_CAF_EN[] = "RX_CAF_EN";
++static const char pszRX_PROM_CH[] = "RX_PROM_CH";
++static const char pszRX_BROAD_EN[] = "RX_BROAD_EN";
++static const char pszRX_BROAD_CH[] = "RX_BROAD_CH";
++static const char pszRX_MULT_EN[] = "RX_MULT_EN";
++static const char pszRX_MULT_CH[] = "RX_MULT_CH";
++
++
++/********************************************************************
++**
++** MAC CONTROL
++**
++********************************************************************/
++static const char pszTX_PTYPE[] = "TX_PTYPE";
++static const char pszTX_PACE[] = "TX_PACE";
++static const char pszMII_EN[] = "MII_EN";
++static const char pszTX_FLOW_EN[] = "TX_FLOW_EN";
++static const char pszRX_FLOW_EN[] = "RX_FLOW_EN";
++static const char pszCTRL_LOOPBACK[] = "CTRL_LOOPBACK";
++
++static const char pszRX_MAXLEN[] = "RX_MAXLEN";
++static const char pszRX_FILTERLOWTHRESH[] = "RX_FILTERLOWTHRESH";
++static const char pszRX0_FLOWTHRESH[] = "RX0_FLOWTHRESH";
++static const char pszRX_UNICAST_SET[] = "RX_UNICAST_SET";
++static const char pszRX_UNICAST_CLEAR[] = "RX_UNICAST_CLEAR";
++static const char pszMdioConnect[] = "MdioConnect";
++static const char pszMacAddr[] = "MacAddr";
++static const char pszTick[] = "Tick";
++
++/********************************************************************
++**
++** MULTICAST
++**
++********************************************************************/
++
++static const char pszRX_MULTICAST[] = "RX_MULTICAST";
++static const char pszRX_MULTI_ALL[] = "RX_MULTI_ALL";
++static const char pszRX_MULTI_SINGLE[] = "RX_MULTI_SINGLE";
++
++/*
++static const char* pszGFHN = "GFHN";
++*/
++
++static const CONTROL_KEY KeyCpmac[] =
++ {
++ {"" , enCpmacStart},
++ {pszStats0 , enStats0},
++ {pszStats1 , enStats1},
++ {pszStats2 , enStats2},
++ {pszStats3 , enStats3},
++ {pszStats4 , enStats4},
++ {pszStatsClear , enStatsClear},
++ {pszStatsDump , enStatsDump},
++ {pszRX_PASS_CRC , enRX_PASS_CRC},
++ {pszRX_QOS_EN , enRX_QOS_EN},
++ {pszRX_NO_CHAIN , enRX_NO_CHAIN},
++ {pszRX_CMF_EN , enRX_CMF_EN},
++ {pszRX_CSF_EN , enRX_CSF_EN},
++ {pszRX_CEF_EN , enRX_CEF_EN},
++ {pszRX_CAF_EN , enRX_CAF_EN},
++ {pszRX_PROM_CH , enRX_PROM_CH},
++ {pszRX_BROAD_EN , enRX_BROAD_EN},
++ {pszRX_BROAD_CH , enRX_BROAD_CH},
++ {pszRX_MULT_EN , enRX_MULT_EN},
++ {pszRX_MULT_CH , enRX_MULT_CH},
++
++ {pszTX_PTYPE , enTX_PTYPE},
++ {pszTX_PACE , enTX_PACE},
++ {pszMII_EN , enMII_EN},
++ {pszTX_FLOW_EN , enTX_FLOW_EN},
++ {pszRX_FLOW_EN , enRX_FLOW_EN},
++ {pszCTRL_LOOPBACK , enCTRL_LOOPBACK},
++ {pszRX_MAXLEN , enRX_MAXLEN},
++ {pszRX_FILTERLOWTHRESH , enRX_FILTERLOWTHRESH},
++ {pszRX0_FLOWTHRESH , enRX0_FLOWTHRESH},
++ {pszRX_UNICAST_SET , enRX_UNICAST_SET},
++ {pszRX_UNICAST_CLEAR , enRX_UNICAST_CLEAR},
++ {pszMdioConnect , enMdioConnect},
++ {pszRX_MULTICAST , enRX_MULTICAST},
++ {pszRX_MULTI_ALL , enRX_MULTI_ALL},
++ {pszRX_MULTI_SINGLE , enRX_MULTI_SINGLE},
++ {pszTick , enTick},
++ {pszVersion , enVersion},
++ {"" , enCpmacEnd}
++ };
++
++const char hcCpuFrequency[] = "CpuFreq";
++const char hcCpmacFrequency[] = "CpmacFrequency";
++const char hcMdioBusFrequency[] = "MdioBusFrequency";
++const char hcMdioClockFrequency[] = "MdioClockFrequency";
++const char hcCpmacBase[] = "CpmacBase";
++const char hcPhyNum[] = "PhyNum";
++const char hcSize[] = "size";
++const char hcCpmacSize[] = "CpmacSize";
++const char hcPhyAccess[] = "PhyAccess";
++const char hcLinked[] = "Linked";
++const char hcFullDuplex[] = "FullDuplex";
++const char hcMdixMask[] = "MdixMask";
++const char hcMdioMdixSwitch[] = "MdixSet";
++#endif
+diff -urN linux.old/drivers/net/avalanche_cpmac/Makefile linux.dev/drivers/net/avalanche_cpmac/Makefile
+--- linux.old/drivers/net/avalanche_cpmac/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/Makefile 2005-07-12 02:48:42.175574000 +0200
+@@ -0,0 +1,26 @@
++# File: drivers/net/avalanche_cpmac/Makefile
++#
++# Makefile for the Linux network (CPMAC) device drivers.
++#
++
++O_TARGET := avalanche_cpmac.o
++
++
++list-multi := avalanche_cpmac.o
++obj-$(CONFIG_MIPS_AVALANCHE_CPMAC) := avalanche_cpmac.o
++
++avalanche_cpmac-objs += cpmac.o cpmacHalLx.o hcpmac.o \
++ psp_config_build.o psp_config_mgr.o \
++ psp_config_parse.o psp_config_util.o
++
++
++include $(TOPDIR)/Rules.make
++
++
++avalanche_cpmac.o: $(avalanche_cpmac-objs)
++ $(LD) -r -o $@ $(avalanche_cpmac-objs)
++
++
++
++clean:
++ rm -f core *.o *.a *.s
+diff -urN linux.old/drivers/net/avalanche_cpmac/mdio_reg.h linux.dev/drivers/net/avalanche_cpmac/mdio_reg.h
+--- linux.old/drivers/net/avalanche_cpmac/mdio_reg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/mdio_reg.h 2005-07-12 02:48:42.176573000 +0200
+@@ -0,0 +1,121 @@
++/****************************************************************************
++** TNETD53xx Software Support
++** Copyright(c) 2002, Texas Instruments Incorporated. All Rights Reserved.
++**
++** FILE: mdio_reg.h Register definitions for the VBUS MII module
++**
++** DESCRIPTION:
++** This include file contains register definitions for the
++** VBUS MII module.
++**
++** HISTORY:
++** 27Mar02 Michael Hanrahan Original (modified from emacmdio.h)
++** 01Apr02 Michael Hanrahan Modified to include all regs. in spec
++** 03Apr02 Michael Hanrahan Updated to Version 0.6 of spec
++** 05Apr02 Michael Hanrahan Moved Phy Mode values into here
++** 30Apr02 Michael Hanrahan Updated to Version 0.8 of spec
++** 30Apr02 Michael Hanrahan Updated to recommended format
++** 10May02 Michael Hanrahan Updated to Version 0.9 of spec
++*****************************************************************************/
++#ifndef _INC_MDIO_REG
++#define _INC_MDIO_REG
++
++/***************************************************************************
++**
++** M D I O M E M O R Y M A P
++**
++***************************************************************************/
++
++
++#define pMDIO_VER(base) ((volatile bit32u *)(base+0x00))
++#define pMDIO_CONTROL(base) ((volatile bit32u *)(base+0x04))
++#define pMDIO_ALIVE(base) ((volatile bit32u *)(base+0x08))
++#define pMDIO_LINK(base) ((volatile bit32u *)(base+0x0C))
++#define pMDIO_LINKINTRAW(base) ((volatile bit32u *)(base+0x10))
++#define pMDIO_LINKINTMASKED(base) ((volatile bit32u *)(base+0x14))
++#define pMDIO_USERINTRAW(base) ((volatile bit32u *)(base+0x20))
++#define pMDIO_USERINTMASKED(base) ((volatile bit32u *)(base+0x24))
++#define pMDIO_USERINTMASKED_SET(base) ((volatile bit32u *)(base+0x28))
++#define pMDIO_USERINTMASKED_CLR(base) ((volatile bit32u *)(base+0x2C))
++#define pMDIO_USERACCESS(base, channel) ((volatile bit32u *)(base+(0x80+(channel*8))))
++#define pMDIO_USERPHYSEL(base, channel) ((volatile bit32u *)(base+(0x84+(channel*8))))
++
++
++/***************************************************************************
++**
++** M D I O R E G I S T E R A C C E S S M A C R O S
++**
++***************************************************************************/
++
++
++#define MDIO_ALIVE(base) (*(pMDIO_ALIVE(base)))
++#define MDIO_CONTROL(base) (*(pMDIO_CONTROL(base)))
++#define MDIO_CONTROL_IDLE (1 << 31)
++#define MDIO_CONTROL_ENABLE (1 << 30)
++#define MDIO_CONTROL_PREAMBLE (1 << 20)
++#define MDIO_CONTROL_FAULT (1 << 19)
++#define MDIO_CONTROL_FAULT_DETECT_ENABLE (1 << 18)
++#define MDIO_CONTROL_INT_TEST_ENABLE (1 << 17)
++#define MDIO_CONTROL_HIGHEST_USER_CHANNEL (0x1F << 8)
++#define MDIO_CONTROL_CLKDIV (0xFF)
++#define MDIO_LINK(base) (*(pMDIO_LINK(base)))
++#define MDIO_LINKINTRAW(base) (*(pMDIO_LINKINTRAW(base)))
++#define MDIO_LINKINTMASKED(base) (*(pMDIO_LINKINTMASKED(base)))
++#define MDIO_USERINTRAW(base) (*(pMDIO_USERINTRAW(base)))
++#define MDIO_USERINTMASKED(base) (*(pMDIO_USERINTMASKED(base)))
++#define MDIO_USERINTMASKED_CLR(base) (*(pMDIO_USERINTMASKED_CLR(base)))
++#define MDIO_USERINTMASKED_SET(base) (*(pMDIO_USERINTMASKED_SET(base)))
++#define MDIO_USERINTRAW(base) (*(pMDIO_USERINTRAW(base)))
++#define MDIO_USERACCESS(base, channel) (*(pMDIO_USERACCESS(base, channel)))
++#define MDIO_USERACCESS_GO (1 << 31)
++#define MDIO_USERACCESS_WRITE (1 << 30)
++#define MDIO_USERACCESS_READ (0 << 30)
++#define MDIO_USERACCESS_ACK (1 << 29)
++#define MDIO_USERACCESS_REGADR (0x1F << 21)
++#define MDIO_USERACCESS_PHYADR (0x1F << 16)
++#define MDIO_USERACCESS_DATA (0xFFFF)
++#define MDIO_USERPHYSEL(base, channel) (*(pMDIO_USERPHYSEL(base, channel)))
++#define MDIO_USERPHYSEL_LINKSEL (1 << 7)
++#define MDIO_USERPHYSEL_LINKINT_ENABLE (1 << 6)
++#define MDIO_USERPHYSEL_PHYADR_MON (0x1F)
++#define MDIO_VER(base) (*(pMDIO_VER(base)))
++#define MDIO_VER_MODID (0xFFFF << 16)
++#define MDIO_VER_REVMAJ (0xFF << 8)
++#define MDIO_VER_REVMIN (0xFF)
++
++
++
++
++/****************************************************************************/
++/* */
++/* P H Y R E G I S T E R D E F I N I T I O N S */
++/* */
++/****************************************************************************/
++
++
++#define PHY_CONTROL_REG 0
++ #define PHY_RESET (1<<15)
++ #define PHY_LOOP (1<<14)
++ #define PHY_100 (1<<13)
++ #define AUTO_NEGOTIATE_EN (1<<12)
++ #define PHY_PDOWN (1<<11)
++ #define PHY_ISOLATE (1<<10)
++ #define RENEGOTIATE (1<<9)
++ #define PHY_FD (1<<8)
++
++#define PHY_STATUS_REG 1
++ #define NWAY_COMPLETE (1<<5)
++ #define NWAY_CAPABLE (1<<3)
++ #define PHY_LINKED (1<<2)
++
++#define NWAY_ADVERTIZE_REG 4
++#define NWAY_REMADVERTISE_REG 5
++ #define NWAY_FD100 (1<<8)
++ #define NWAY_HD100 (1<<7)
++ #define NWAY_FD10 (1<<6)
++ #define NWAY_HD10 (1<<5)
++ #define NWAY_SEL (1<<0)
++ #define NWAY_AUTO (1<<0)
++
++
++#endif _INC_MDIO_REG
+diff -urN linux.old/drivers/net/avalanche_cpmac/psp_config_build.c linux.dev/drivers/net/avalanche_cpmac/psp_config_build.c
+--- linux.old/drivers/net/avalanche_cpmac/psp_config_build.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/psp_config_build.c 2005-07-12 02:48:42.176573000 +0200
+@@ -0,0 +1,335 @@
++/******************************************************************************
++ * FILE PURPOSE: PSP Config Manager - Configuration Build Source
++ ******************************************************************************
++ * FILE NAME: psp_config_build.c
++ *
++ * DESCRIPTION: Configuration Build API Implementation
++ *
++ * REVISION HISTORY:
++ * 27 Nov 02 - PSP TII
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++#ifdef INCLUDE_FFS
++#include "ffs.h"
++#endif /* INCLUDE_FFS */
++
++#include "psp_config_mgr.h"
++#include "psp_config_build.h"
++#include "psp_config_util.h"
++
++#define MAX_DEVICE_NAME_LEN 16
++#define MAX_DEVICE_STR_LEN 512
++
++#ifndef NULL
++#define NULL (char *)0
++#endif
++
++#include <asm/ar7/sangam.h>
++#include <linux/slab.h>
++#include <linux/config.h>
++
++
++#define os_malloc(size) kmalloc(size, GFP_KERNEL)
++
++int psp_run_enumerator(void)
++{
++ return(0);
++}
++
++#if defined (CONFIG_AVALANCHE_CPMAC_AUTO)
++
++static int auto_detect_cpmac_phy(void)
++{
++
++#define SELECT_INT_PHY_MAC 0
++#define SELECT_EXT_PHY_MAC 1
++
++ volatile unsigned long *reset_cntl = AVALANCHE_RESET_CONTROL_BASE, *mdio_cntl = ((int)AVALANCHE_MDIO_BASE + 0x4);
++ unsigned int j= 0, detected_phy_map = 0, auto_select = SELECT_INT_PHY_MAC;
++
++ *reset_cntl |= (1 << AVALANCHE_MDIO_RESET_BIT) | (1 << AVALANCHE_LOW_CPMAC_RESET_BIT) | (1 << AVALANCHE_HIGH_CPMAC_RESET_BIT) | (1 << AVALANCHE_LOW_EPHY_RESET_BIT);
++ *mdio_cntl = (1 << 30) | ((CONFIG_AR7_SYS * 1000)/2200);
++
++ for(j=0;j < 300000; j++)
++ {
++ if(j%100000) continue;
++
++ detected_phy_map = *(mdio_cntl + 1);
++ if(detected_phy_map)
++ {
++ detected_phy_map &= ~AVALANCHE_LOW_CPMAC_PHY_MASK;
++
++ if(detected_phy_map && !(detected_phy_map & (detected_phy_map - 1)))
++ {
++ auto_select = SELECT_EXT_PHY_MAC;
++ break;
++ }
++ }
++ }
++
++ return(auto_select);
++
++}
++
++#endif
++
++
++#ifndef AVALANCHE_LOW_CPMAC_MDIX_MASK
++#define AVALANCHE_LOW_CPMAC_MDIX_MASK 0
++#endif
++
++void psp_load_default_static_cfg(void)
++{
++ char s2[100], s3[100];
++ char s4[2000], s6[2000];
++ int threshold = 20;
++ char *tx_threshold_ptr = prom_getenv("threshold");
++
++ if(tx_threshold_ptr)
++ threshold = simple_strtol(tx_threshold_ptr, (char **)NULL, 10);
++
++ /* Static configuration if options.conf not present */
++ sprintf(s3,"cpmdio(id=mii, base=%u, reset_bit=%d)", AVALANCHE_MDIO_BASE, 22);
++ sprintf(s2, "reset( id=[ResetRegister], base=%u)", AVALANCHE_RESET_CONTROL_BASE);
++
++ sprintf(s4, "cpmac(id=[cpmac], unit=0, base=%u, size=0x800, reset_bit=%d, PhyMask=%u, MdixMask=%u, MLink=0, int_line=%d, memory_offset=0, RX_CAF=1, RX_PASSCRC=0, RX_CEF=1, RX_BCAST=0, RX_BCASTCH=0, Ch0=[TxNumBuffers=256, TxNumQueues=1, TxServiceMax=%d, RxNumBuffers=256, RxBufferOffset=0, RxBufSize=1000, RxServiceMax=128], Ch1=[TxNumBuffers=256, TxNumQueues=1, TxServiceMax=%d, RxNumBuffers=256, RxBufferOffset=0, RxBufSize=1000, RxServiceMax=128], Ch2=[TxNumBuffers=256, TxNumQueues=1, TxServiceMax=%d, RxNumBuffers=256, RxBufferOffset=0, RxBufSize=1000, RxServiceMax=128])", AVALANCHE_LOW_CPMAC_BASE, AVALANCHE_LOW_CPMAC_RESET_BIT, AVALANCHE_LOW_CPMAC_PHY_MASK, AVALANCHE_LOW_CPMAC_MDIX_MASK, AVALANCHE_LOW_CPMAC_INT,threshold,threshold,threshold);
++
++ sprintf(s6, "cpmac(id=[cpmac], unit=1, base=%u, size=0x800, reset_bit=%d, PhyMask=%u, MLink=0, int_line=%d, memory_offset=0, RX_CAF=1, RX_PASSCRC=0, RX_CEF=1, RX_BCAST=0, RX_BCASTCH=0, Ch0=[TxNumBuffers=256, TxNumQueues=1, TxServiceMax=%d, RxNumBuffers=256, RxBufferOffset=0, RxBufSize=1000, RxServiceMax=128], Ch1=[TxNumBuffers=256, TxNumQueues=1, TxServiceMax=%d, RxNumBuffers=256, RxBufferOffset=0, RxBufSize=1000, RxServiceMax=128], Ch2=[TxNumBuffers=256, TxNumQueues=1, TxServiceMax=%d, RxNumBuffers=256, RxBufferOffset=0, RxBufSize=1000, RxServiceMax=128])", AVALANCHE_HIGH_CPMAC_BASE, AVALANCHE_HIGH_CPMAC_RESET_BIT, AVALANCHE_HIGH_CPMAC_PHY_MASK, AVALANCHE_HIGH_CPMAC_INT,threshold,threshold,threshold);
++
++ psp_config_add("reset", s2, psp_config_strlen(s2), en_compile);
++
++
++#if defined (CONFIG_AVALANCHE_LOW_CPMAC)
++
++ psp_config_add("cpmdio", s3, psp_config_strlen(s3), en_compile);
++ psp_config_add("cpmac", s4, psp_config_strlen(s4), en_compile);
++
++#endif
++
++
++#if defined (CONFIG_AVALANCHE_HIGH_CPMAC)
++
++ psp_config_add("cpmdio", s3, psp_config_strlen(s3), en_compile);
++ psp_config_add("cpmac", s6, psp_config_strlen(s6), en_compile);
++
++#endif
++
++#if defined (CONFIG_AVALANCHE_CPMAC_AUTO)
++ {
++ char *phy_sel_ptr = prom_getenv("mac_phy_sel");
++ int phy_sel = SELECT_EXT_PHY_MAC;
++ char *mac_port = prom_getenv("MAC_PORT"); /* Internal: 0, External: 1 */
++
++ if(phy_sel_ptr && (0 == strcmp(phy_sel_ptr, "int")))
++ {
++ phy_sel = SELECT_INT_PHY_MAC;
++ }
++
++ //if(phy_sel == auto_detect_cpmac_phy())
++ if(0 == strcmp(mac_port, "1"))
++ {
++ printk("Using the MAC with external PHY\n");
++ psp_config_add("cpmdio", s3, psp_config_strlen(s3), en_compile);
++ psp_config_add("cpmac", s6, psp_config_strlen(s6), en_compile);
++ }
++ else
++ {
++ printk("Using the MAC with internal PHY\n");
++ psp_config_add("cpmdio", s3, psp_config_strlen(s3), en_compile);
++ psp_config_add("cpmac", s4, psp_config_strlen(s4), en_compile);
++ }
++ }
++
++#endif
++
++}
++
++char* psp_conf_read_file(char *p_file_name)
++{
++#ifdef INCLUDE_FFS
++
++ char *p_file_data = NULL;
++ unsigned int file_size;
++ FFS_FILE *p_file = NULL;
++
++ if(p_file_name == NULL)
++ {
++ return (NULL);
++ }
++
++ if(!(p_file = ffs_fopen(p_file_name, "r")))
++ {
++ return(NULL);
++ }
++
++ file_size = p_file->_AvailableBytes;
++
++ p_file_data = os_malloc(file_size + 1);
++
++ if(ffs_fread(p_file_data, file_size, 1, p_file) == 0)
++ {
++ kfree(p_file_data);
++ return(NULL);
++ }
++
++ ffs_fclose(p_file);
++
++ p_file_data[file_size] = '\0';
++
++ return(p_file_data);
++
++#else /* NO FFS */
++ return(NULL);
++#endif /* INCLUDE_FFS */
++}
++
++int psp_conf_get_line(char *p_in_data, char **next_line)
++{
++ char *p = p_in_data;
++
++ while(*p && *p++ != '\n')
++ {
++
++ }
++
++ *next_line = p;
++
++ return(p - 1 - p_in_data);
++}
++
++
++int psp_conf_is_data_line(char *line)
++{
++ int ret_val = 1;
++
++ if(*line == '\0' || *line == '\n' || *line == '#')
++ ret_val = 0;
++
++ return(ret_val);
++}
++
++int psp_conf_get_key_size(char *data)
++{
++ char *p = data;
++
++ while(*p && *p != '\n' && *p != '(' && *p != ' ')
++ p++;
++
++ return(p - data);
++}
++
++char* psp_conf_eat_white_spaces(char *p)
++{
++ while(*p && *p != '\n' && *p == ' ')
++ p++;
++
++ return (p);
++}
++
++int psp_build_from_opt_conf(void)
++{
++ char *data = NULL;
++ char *data_hold = NULL;
++ char *next_line = NULL;
++ int line_size = 0;
++
++ if((data = psp_conf_read_file("/etc/options.conf")) == NULL)
++ return(-1);
++
++ data_hold = data;
++
++ while((line_size=psp_conf_get_line(data, &next_line)) != -1)
++ {
++
++ char *name = NULL;
++ int name_size;
++
++ data = psp_conf_eat_white_spaces(data);
++
++ if(psp_conf_is_data_line(data))
++ {
++ data[line_size] = '\0';
++
++ name_size = psp_conf_get_key_size(data);
++
++ if(name_size > 0)
++ {
++ name = (char *) os_malloc(name_size + 1);
++ if(name == NULL) break;
++
++ psp_config_memcpy(name, data, name_size);
++ name[name_size] = '\0';
++
++ psp_config_add(name, data, line_size, en_opt_conf);
++
++ kfree(name);
++ }
++
++ data[line_size] = '\n';
++ }
++
++ data = next_line;
++ }
++
++ kfree(data_hold);
++ return (0);
++}
++
++
++int psp_write_conf_file(char *p_write_file, char * dev_cfg_string)
++{
++#ifdef INCLUDE_FFS
++ int bytes_written=0;
++ FFS_FILE *file_ptr=NULL;
++
++ /*
++ * NOTE: In current implementation of FFS in ADAM2 if the file exists beforehand, it
++ * can't be opened for write.
++ */
++ if(!(file_ptr=ffs_fopen(p_write_file, "w"))) {
++ return(-1);
++ }
++
++ /* Write into the file "output.con" the character string */
++ /* write a \n before a writing a line */
++ if(!(bytes_written = ffs_fwrite("\n", 1, sizeof(char), file_ptr))) {
++ return (-1);
++ }
++
++ if(!(bytes_written = ffs_fwrite(dev_cfg_string, psp_config_strlen(dev_cfg_string), sizeof(char), file_ptr))) {
++ return (-1);
++ }
++ ffs_fclose(file_ptr);
++ return (bytes_written+1);
++#else /* NO FFS */
++ return(-1);
++#endif /* INCLUDE_FFS */
++}
++
++void build_psp_config(void)
++{
++
++ /* initialize the repository. */
++ psp_config_init();
++
++#ifdef INCLUDE_FFS
++ ffs_init();
++#endif /* INCLUDE_FFS */
++
++ /* read the configuration from the options.conf to override default ones */
++ psp_build_from_opt_conf();
++
++ /* read the configuration which were not over ridden in options.conf */
++ psp_load_default_static_cfg();
++
++ /* let the vlynq be enumerated. Enumerator will add cfg info
++ of the discovered device instances to the repository.*/
++ psp_run_enumerator();
++
++ /* dump the repository*/
++ dump_device_cfg_pool();
++
++}
++
+diff -urN linux.old/drivers/net/avalanche_cpmac/psp_config_build.h linux.dev/drivers/net/avalanche_cpmac/psp_config_build.h
+--- linux.old/drivers/net/avalanche_cpmac/psp_config_build.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/psp_config_build.h 2005-07-12 02:48:42.176573000 +0200
+@@ -0,0 +1,138 @@
++/******************************************************************************
++ * FILE PURPOSE: PSP Config Manager - Configuration Build Header
++ ******************************************************************************
++ * FILE NAME: psp_config_build.h
++ *
++ * DESCRIPTION: Configuration Build API's.
++ *
++ * REVISION HISTORY:
++ * 27 Nov 02 - PSP TII
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++#ifndef __PSP_CONF_BUILD_H__
++#define __PSP_CONF_BUILD_H__
++
++/*------------------------------------------------------------------------------
++ * Name: psp_conf_read_file
++ *
++ * Parameters:
++ * in: p_file_name - the name of the file to read from.
++ *
++ * Description:
++ * Reads the entire file in one shot. This function opens the
++ * file, determines the size of the data to be read, allocates
++ * the required memory, NULL terminates the data and closes the
++ * file.
++ *
++ * It is responsibily of the callee to free the memory after it is
++ * done with that data.
++ *
++ *
++ * Returns:
++ * A NULL pointer, if failed to read the data otherwise, a valid
++ * pointer referring to the data read from the file.
++ *
++ * Example:
++ *
++ * psp_conf_read_file("/etc/options.conf");
++ *---------------------------------------------------------------------------*/
++ char *psp_conf_read_file(char *p_file_name);
++
++ /*----------------------------------------------------------------------------
++ * Function : psp_conf_write_file
++ *
++ * Parameters:
++ * in: p_file_name - the file to which data is to be written.
++ * in: data - the NULL terminated data string.
++ *
++ * Description:
++ * Write the indicated data into the file. This function opens the file,
++ * appends the data to end of the file, closes the file.
++ *
++ * Returns:
++ *
++ * The number of bytes on success.
++ * 0 on failure.
++ *
++ * Example:
++ *
++ * psp_conf_write_file("/etc/outcon.conf", data);
++ *--------------------------------------------------------------------------*/
++ int psp_conf_write_file(char *p_file_name, char *data);
++
++ /*----------------------------------------------------------------------------
++ * Function: psp_conf_get_line
++ *
++ * Parameters:
++ * in: data - the data from which the line is to identified.
++ * out: next_line - the pointer to start of the next line.
++ *
++ * Description:
++ * Expects the data to be '\n' separated segments and data is NULL
++ * terminated. Parses the given data for '\n' or '\0'. Provides a pointer
++ * to the start of next line in the next_line.
++ *
++ * Returns:
++ * -1 on error.
++ * 0 or more to indicate the number of bytes in the line starting at
++ * data.
++ *--------------------------------------------------------------------------*/
++ int psp_get_conf_line(char *p_in_data, char **next_line);
++
++ /*----------------------------------------------------------------------------
++ * Function: psp_conf_is_data_line
++ *
++ * Parameters:
++ * in: line - the array of bytes.
++ *
++ * Description:
++ * Tests the first byte in the array for '\0' or '\n' or '#'. Lines
++ * starting with these characters are not considered data.
++ *
++ * Returns:
++ * 1 if the line has data.
++ * 0 otherwise.
++ *
++ *--------------------------------------------------------------------------*/
++ int psp_conf_is_data_line(char *line);
++
++ /*----------------------------------------------------------------------------
++ * Function: psp_conf_eat_white_spaces
++ *
++ * Parameters:
++ * in: line - the array of bytes.
++ *
++ * Description:
++ * Eats white spaces at the begining of the line while looking out for
++ * '\0' or '\n' or ' '.
++ *
++ * Returns:
++ * Pointer to the begining of the non white space character.
++ * NULL if '\0' or '\n' is found.
++ *
++ *--------------------------------------------------------------------------*/
++ char *psp_conf_eat_white_spaces(char *line);
++
++ /*---------------------------------------------------------------------------
++ * Function: psp_conf_get_key_size
++ *
++ * Parameters:
++ * in: line - the array of bytes.
++ *
++ * Description:
++ * Identifies the size of the 'key' in array formatted as
++ * key(id=[key1]....). This function also checks out for '\0' and '\n'.
++ *
++ * Returns:
++ * On success, The number of bytes that forms the key.
++ * 0 otherwise.
++ *
++ *-------------------------------------------------------------------------*/
++ int psp_conf_get_key_size(char *line);
++
++
++
++#endif /* __PSP_CONF_BUILD_H__ */
++
+diff -urN linux.old/drivers/net/avalanche_cpmac/psp_config_mgr.c linux.dev/drivers/net/avalanche_cpmac/psp_config_mgr.c
+--- linux.old/drivers/net/avalanche_cpmac/psp_config_mgr.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/psp_config_mgr.c 2005-07-12 02:48:42.177573000 +0200
+@@ -0,0 +1,464 @@
++/******************************************************************************
++ * FILE PURPOSE: PSP Config Manager Source
++ ******************************************************************************
++ * FILE NAME: psp_config_mgr.c
++ *
++ * DESCRIPTION:
++ *
++ * Manages configuration information. The repository is managed on the basis of
++ * <key, info> pair. It is possible to have multiple occurrence of the same key.
++ * Multiple occurences of the same keys are referred to as 'instances'.
++ * 'instances' are assigned in the order of configuration arrival. The first
++ * config for a 'key' added to the repository would be treated as instance 0 and
++ * next config to arrive for the same key would be treated as instance '1' and
++ * so on.
++ *
++ * Info is retrieved from the repository based on the 'key' and 'instance' value.
++ *
++ * No assumption is made about the format of the information that is put in the
++ * repository. The only requirement is that 'key' should be NULL terminated
++ * string.
++ *
++ * REVISION HISTORY:
++ * 27 Nov 02 - PSP TII
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++//#include <stdio.h>
++//#include <stdlib.h>
++#include "psp_config_mgr.h"
++#include "psp_config_util.h"
++
++#include <linux/slab.h>
++
++/*-----------------------------------------------------------
++ Implemented elsewhere
++ -----------------------------------------------------------*/
++extern int sys_read_options_conf(void);
++extern int sys_write_options_conf(char *cfg_info);
++extern int sys_load_default_static_cfg(void);
++extern int sys_run_enumerator(void);
++
++#define os_malloc(size) kmalloc(size, GFP_KERNEL)
++
++/*---------------------------------------------------------
++ * Data structures.
++ *--------------------------------------------------------*/
++struct device_cfg_data;
++
++typedef struct device_instance_cfg_data
++{
++ struct device_instance_cfg_data *next;
++ char locale[100];
++ unsigned int data_size;
++ char *data;
++
++} DEV_INSTANCE_CFG_DATA_T;
++
++struct device_cfg_collection;
++
++typedef struct device_cfg_collection
++{
++ struct device_cfg_collection *next;
++ char *device_name;
++ CFG_TYPE_T cfg_type;
++ int count;
++ DEV_INSTANCE_CFG_DATA_T *dev_inst_list_begin;
++ DEV_INSTANCE_CFG_DATA_T *dev_inst_list_end;
++} DEVICE_CFG_T;
++
++
++typedef struct device_cfg_list
++{
++ DEVICE_CFG_T *device_cfg_begin;
++ int count;
++} DEVICE_CFG_LIST_T;
++
++/*-----------------------------------------------------------------------------
++ * Functions used locally with in the file.
++ *---------------------------------------------------------------------------*/
++static void p_init_device_cfg_list(void);
++static int p_add_instance_cfg_data(DEVICE_CFG_T *p_dev_cfg,
++ DEV_INSTANCE_CFG_DATA_T *p_dev_inst_data);
++static DEVICE_CFG_T* p_create_dev_cfg(char *device_name);
++static DEVICE_CFG_T* p_get_dev_cfg(char *device_name);
++static int p_set_device_cfg_type(DEVICE_CFG_T *p_dev_cfg,
++ CFG_TYPE_T cfg_type);
++
++/* PSP Config manager debug */
++#define PSP_CFG_MGR_DEBUG 0
++
++#define dbgPrint if (PSP_CFG_MGR_DEBUG) printk
++
++/*-----------------------------------------------------------------------------
++ * The repository.
++ *---------------------------------------------------------------------------*/
++static DEVICE_CFG_LIST_T g_device_cfg_list;
++
++/*---------------------------------------------
++ * Initialize the device collection pool.
++ *--------------------------------------------*/
++void p_init_device_cfg_list(void)
++{
++ g_device_cfg_list.count = 0;
++ g_device_cfg_list.device_cfg_begin = NULL;
++}
++
++/*----------------------------------------------------------------------
++ * Add the device cfg into the device linked list.
++ *---------------------------------------------------------------------*/
++int p_add_dev_cfg_to_list(DEVICE_CFG_LIST_T *p_dev_list,
++ DEVICE_CFG_T *p_dev_cfg)
++{
++ if(p_dev_list->count != 0)
++ p_dev_cfg->next = p_dev_list->device_cfg_begin;
++
++ p_dev_list->device_cfg_begin = p_dev_cfg;
++
++ p_dev_list->count++;
++
++ return (0);
++}
++
++/*------------------------------------------------------------------
++ * Add the cfg data into the cfg data linked list of the collection.
++ *------------------------------------------------------------------*/
++int p_add_instance_cfg_data(DEVICE_CFG_T *p_dev_cfg,
++ DEV_INSTANCE_CFG_DATA_T *p_dev_inst_data)
++{
++ if(p_dev_cfg->count == 0)
++ p_dev_cfg->dev_inst_list_begin = p_dev_inst_data;
++ else
++ p_dev_cfg->dev_inst_list_end->next = p_dev_inst_data;
++
++ p_dev_cfg->dev_inst_list_end = p_dev_inst_data;
++
++ p_dev_cfg->count++;
++
++ return (0);
++}
++
++/*-----------------------------------------------------------------------------
++ * Create the device cfg.
++ *---------------------------------------------------------------------------*/
++DEVICE_CFG_T *p_create_dev_cfg(char *device_name)
++{
++ DEVICE_CFG_T *p_dev_cfg = NULL;
++
++ if((p_dev_cfg = os_malloc(sizeof(DEVICE_CFG_T))) == NULL)
++ {
++ dbgPrint("Failed to allocate memory for DEVICE_CFG_T.\n");
++ }
++ else if((p_dev_cfg->device_name = os_malloc(psp_config_strlen(device_name) + 1))==NULL)
++ {
++ dbgPrint("Failed to allocate memory for device name.\n");
++ }
++ else
++ {
++ psp_config_strcpy(p_dev_cfg->device_name, device_name);
++ p_dev_cfg->cfg_type = en_raw;
++ p_dev_cfg->count = 0;
++ p_dev_cfg->dev_inst_list_begin = NULL;
++ p_dev_cfg->dev_inst_list_end = NULL;
++ p_dev_cfg->next = NULL;
++ }
++
++ return(p_dev_cfg);
++}
++
++/*------------------------------------------------------------------------------
++ * Get the device cfg collection.
++ *-----------------------------------------------------------------------------*/
++DEVICE_CFG_T *p_get_dev_cfg(char *device_name)
++{
++ int count = 0;
++ DEVICE_CFG_T *p_dev_cfg = g_device_cfg_list.device_cfg_begin;
++
++ for(count=0; count < g_device_cfg_list.count; count++)
++ {
++ if(psp_config_strcmp(device_name, p_dev_cfg->device_name) == 0)
++ {
++ break;
++ }
++
++ p_dev_cfg = p_dev_cfg->next;
++ }
++
++ return(p_dev_cfg);
++}
++
++/*-------------------------------------------------------------------------
++ * Gets the name for the static cfg type. Utility function. Debug purposes.
++ *-------------------------------------------------------------------------*/
++char *p_get_cfg_type_name_for_en(CFG_TYPE_T cfg_type)
++{
++ static char raw_str [] = "still raw";
++ static char compile_str [] = "configured at compile time";
++ static char optconf_str [] = "configured by options.conf";
++ static char vlynq_str [] = "configured by VLYNQ";
++ static char no_static_str[] = "no static configuration";
++
++ if(cfg_type == en_raw)
++ return (raw_str);
++ else if(cfg_type == en_compile)
++ return (compile_str);
++ else if(cfg_type == en_opt_conf)
++ return (optconf_str);
++ else if(cfg_type == en_vlynq)
++ return (vlynq_str);
++ else
++ return (no_static_str);
++
++}
++
++/*-----------------------------------------------------------------------------
++ * Sets the static cfg status of the device collection.
++ *
++ * If the collection is en_virgin then, the collection is assigned to cfg_type.
++ * If the cfg_type is en_vlynq then, the old cfg_type is retained.
++ * en_compile and en_opt_conf are mutually exclusive. One of these can be
++ * accomodated.
++ *
++ *---------------------------------------------------------------------------*/
++int p_set_device_cfg_type(DEVICE_CFG_T *p_dev_cfg,
++ CFG_TYPE_T cfg_type)
++{
++ int ret_val = 0;
++
++ if(p_dev_cfg->cfg_type == en_raw)
++ p_dev_cfg->cfg_type = cfg_type;
++ else if((cfg_type == en_vlynq) || (p_dev_cfg->cfg_type == cfg_type))
++ ;
++ else
++ {
++ dbgPrint("Device %s has been %s which overrides %s.\n",
++ p_dev_cfg->device_name,
++ p_get_cfg_type_name_for_en(p_dev_cfg->cfg_type),
++ p_get_cfg_type_name_for_en(cfg_type));
++ ret_val = -1;
++ }
++
++ return(ret_val);
++}
++
++/*------------------------------------------------------------------------
++ * Add the config str into the repository. The cfg type indicates
++ * whether the device has been configured statically, from options.conf or
++ * by vlynq enumeration.
++ *------------------------------------------------------------------------*/
++int psp_config_add(char *key, void *p_cfg_str, unsigned int cfg_len,
++ CFG_TYPE_T cfg_type)
++{
++ int ret_val = -1;
++ DEVICE_CFG_T *p_dev_cfg = NULL;
++ DEV_INSTANCE_CFG_DATA_T *p_dev_inst_data = NULL;
++
++ if(p_cfg_str == NULL || key == NULL)
++ {
++ dbgPrint("Null input pointer(s).\n");
++ }
++ /* check if there exist a dev_cfg for the given key, if not,
++ then create one and add it to the device list. */
++ else if(((p_dev_cfg = p_get_dev_cfg(key)) == NULL) &&
++ (((p_dev_cfg = p_create_dev_cfg(key)) == NULL) ||
++ p_add_dev_cfg_to_list(&g_device_cfg_list, p_dev_cfg) != 0))
++ {
++ dbgPrint("Failed to allocate mem or add dev cfg for %s.\n", key);
++ }
++ /* make sure that we can add this cfg type to the repository */
++ else if(p_set_device_cfg_type(p_dev_cfg, cfg_type) == -1)
++ {
++ dbgPrint("Ignoring \"%s\" for device \"%s\".\n",
++ p_get_cfg_type_name_for_en(cfg_type),
++ p_dev_cfg->device_name);
++ }
++ else if((p_dev_inst_data = os_malloc(sizeof(DEV_INSTANCE_CFG_DATA_T)))== NULL)
++ {
++ dbgPrint("Failed to allocate memory for DEV_INSTANCE_CFG_DATA_T.\n");
++ }
++ else if((p_dev_inst_data->data = os_malloc(cfg_len) + 1) == NULL)
++ {
++ dbgPrint("Failed to allocate memory for the config data.\n");
++ }
++ else
++ {
++ p_dev_inst_data->next = NULL;
++
++ if(cfg_type == en_opt_conf || cfg_type == en_compile)
++ psp_config_strcpy(p_dev_inst_data->locale, "dev on chip ");
++ else if(cfg_type == en_vlynq)
++ psp_config_strcpy(p_dev_inst_data->locale, "dev on vlynq");
++ else
++ psp_config_strcpy(p_dev_inst_data->locale, "dev locale ?");
++
++ psp_config_memcpy(p_dev_inst_data->data, p_cfg_str, cfg_len);
++ p_dev_inst_data->data_size = cfg_len;
++ *(p_dev_inst_data->data + cfg_len) = '\0';
++
++ ret_val = p_add_instance_cfg_data(p_dev_cfg, p_dev_inst_data);
++ }
++
++ return(ret_val);
++}
++
++/*-------------------------------------------------------------
++ * Get the total number of device instances in the repository
++ *------------------------------------------------------------*/
++int psp_config_get_num_keys(void)
++{
++ return(g_device_cfg_list.count);
++}
++
++
++/*--------------------------------------------------------------------
++ * Get the device configuration info from the repository.
++ *-------------------------------------------------------------------*/
++int psp_config_get(char *key, int instance, char **cfg_data_out)
++{
++ int ret_val = -1;
++ DEVICE_CFG_T *p_dev_cfg = NULL;
++ *cfg_data_out = NULL;
++
++ if(key == NULL && cfg_data_out == NULL)
++ {
++ dbgPrint("Key has a NULL value.\n");
++ }
++ else if((p_dev_cfg = p_get_dev_cfg(key)) == NULL)
++ {
++ dbgPrint("cfg information for %s could not be found.\n", key);
++ }
++ else if(p_dev_cfg->count)
++ {
++ DEV_INSTANCE_CFG_DATA_T *p_dev_inst_data =
++ p_dev_cfg->dev_inst_list_begin;
++ int index = 0;
++ for(index = 0;
++ index != instance && index < p_dev_cfg->count;
++ index++)
++ {
++ p_dev_inst_data = p_dev_inst_data->next;
++ }
++
++ if(p_dev_inst_data != NULL && p_dev_inst_data->data != NULL)
++ {
++ *cfg_data_out = p_dev_inst_data->data;
++ ret_val = p_dev_inst_data->data_size;
++ }
++ }
++
++ return (ret_val);
++}
++
++/*----------------------------------------------------------------
++ * Returns the number of instances found in the repository for the
++ * specified key.
++ *---------------------------------------------------------------*/
++int psp_config_get_num_instances(char *key)
++{
++ int ret_val = 0;
++ DEVICE_CFG_T *p_dev_cfg = NULL;
++
++ if(key == NULL)
++ {
++ dbgPrint("Key has a NULL value.\n");
++ }
++ else if((p_dev_cfg = p_get_dev_cfg(key)) == NULL)
++ {
++ dbgPrint("cfg information for %s could not be found.\n", key);
++ }
++ else
++ {
++ ret_val = p_dev_cfg->count;
++ }
++
++ return (ret_val);
++}
++
++/*------------------------------------------------------------------
++ * Dump the configuration repository.
++ * Caution: DO NOT USE THIS FOR ANY NON NBU specified config format.
++ *-----------------------------------------------------------------*/
++void psp_config_print(char *key)
++{
++ DEVICE_CFG_T *p_dev_cfg = NULL;
++
++ if(key == NULL)
++ {
++ dbgPrint("Key has a NULL value.\n");
++ }
++ else if((p_dev_cfg = p_get_dev_cfg(key)) == NULL)
++ {
++ dbgPrint("cfg information for %s could not be found.\n", key);
++ }
++ else if(p_dev_cfg && p_dev_cfg->count)
++ {
++ DEV_INSTANCE_CFG_DATA_T *p_dev_inst_data;
++
++ p_dev_inst_data = p_dev_cfg->dev_inst_list_begin;
++
++ do
++ {
++ dbgPrint("%s : %s\n", p_dev_inst_data->locale,
++ p_dev_inst_data->data);
++ p_dev_inst_data = p_dev_inst_data->next;
++
++ } while(p_dev_inst_data);
++ }
++ else
++ {
++ dbgPrint("Nothing was found for %s.\n", key);
++ }
++}
++
++void dump_device_cfg_pool(void)
++{
++ DEVICE_CFG_T *p_dev_cfg = g_device_cfg_list.device_cfg_begin;
++
++ if(p_dev_cfg != NULL && g_device_cfg_list.count)
++ {
++ int index=0;
++
++ for(index=0; index < g_device_cfg_list.count; index++)
++ {
++ psp_config_print(p_dev_cfg->device_name);
++ p_dev_cfg = p_dev_cfg->next;
++ }
++ }
++ else
++ {
++ dbgPrint("repository is empty.\n");
++ }
++}
++
++void psp_config_init(void)
++{
++ p_init_device_cfg_list();
++}
++
++void psp_config_cleanup()
++{
++ int dev_count = 0;
++ int inst_count = 0;
++ DEVICE_CFG_T *p = g_device_cfg_list.device_cfg_begin;
++ DEV_INSTANCE_CFG_DATA_T *q = NULL;
++
++ for(dev_count = 0; dev_count < g_device_cfg_list.count; dev_count++)
++ {
++ DEVICE_CFG_T *p_temp = NULL;
++ if(p) q = p->dev_inst_list_begin;
++
++ for(inst_count = 0; inst_count < p->count && q != NULL; inst_count++)
++ {
++ DEV_INSTANCE_CFG_DATA_T *q_temp = q;
++ q_temp = q->next;
++ kfree(q->data);
++ kfree(q);
++ q = q_temp;
++ }
++
++ p_temp = p->next;
++ kfree(p);
++ p = p_temp;
++ }
++}
+diff -urN linux.old/drivers/net/avalanche_cpmac/psp_config_mgr.h linux.dev/drivers/net/avalanche_cpmac/psp_config_mgr.h
+--- linux.old/drivers/net/avalanche_cpmac/psp_config_mgr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/psp_config_mgr.h 2005-07-12 02:48:42.177573000 +0200
+@@ -0,0 +1,110 @@
++/******************************************************************************
++ * FILE PURPOSE: PSP Config Manager Header
++ ******************************************************************************
++ * FILE NAME: psp_config_mgr.h
++ *
++ * DESCRIPTION: Storing and retrieving the configuration based on key
++ * A set of APIs to be used by one and sundry (including drivers and enumerator) to build
++ * and read cfg information of the devices for an avalanche SOC.
++ *
++ * This set of APIs isolates the configuration management from the world and provides simple
++ * access convinience.
++ *
++ * Device in this set refers to the peripherals that can be found on the SOC or on VLYNQ.
++ * The configuration is stored in the form of string and drivers can use these APIs to get
++ * a particular parameter value.
++ *
++ * The memory allocation for the pass back parameters is done by the caller.
++ *
++ * 0 is returned for SUCCESS or TRUE.
++ * -1 is returned for FAILURE or FALSE.
++ *
++ * REVISION HISTORY:
++ * 27 Nov 02 - PSP TII
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++#ifndef __PSP_CONFIG_MGR_H__
++#define __PSP_CONFIG_MGR_H__
++
++typedef enum cfg_type
++{
++ en_raw = 0,
++ en_compile,
++ en_opt_conf,
++ en_vlynq
++} CFG_TYPE_T;
++
++/* Build psp configuration */
++void build_psp_config(void);
++
++/********************************************************
++ * Access Operations.
++ ********************************************************/
++
++/*-------------------------------------------------------------------------
++ initializes the configuration repository.
++ -------------------------------------------------------------------------*/
++void psp_config_init(void);
++
++/*--------------------------------------------------------------------------
++ Adds the configuration information into the repository. 'key' is required
++ to be NULL terminated string. 'cfg_ptr' points to the configuration data.
++ 'cfg_len' is the length of the data pointed to by 'cfg_ptr' in bytes.
++ 'cfg_type' indicates the type of config information.
++
++ psp_config_mgr copies the 'cfg_len' bytes of data pointed to by 'cfg_ptr'
++ into its internal repository.
++
++ Returns: 0 on success, -1 on failure.
++ -------------------------------------------------------------------------*/
++int psp_config_add(char *key, void *cfg_ptr,
++ unsigned int cfg_len, CFG_TYPE_T cfg_type);
++
++
++/* --------------------------------------------------------------------------
++ Passes back, in "*cfg_out_val" a pointer to the config data in the repository
++ for the specified 'key' and 'instance'. It returns the size of the config
++ info
++
++ psp_config_mgr passes back a pointer in '*cfg_out_val' which refers to
++ some location in its internal repository. It is strongly recommended that
++ if the user intends to modify the contents of the config info for reasons
++ whatsoever, then, user should allocate memory of size returned by this
++ routine and copy the contents from '*cfg_out_val'.
++
++ Any, modification carried out on the repository would lead to un-expected
++ results.
++
++ Returns: 0 or more for the size of config info, -1 on error.
++ --------------------------------------------------------------------------*/
++int psp_config_get(char *key, int instance, char **cfg_out_val);
++
++
++/*--------------------------------------------------------------------------
++ Get the number of keys that have been added in the repository so far.
++
++ Returns: 0 or more for the num of keys, -1 on error.
++ -------------------------------------------------------------------------*/
++int psp_config_get_num_keys(void);
++
++
++/*--------------------------------------------------------------------------
++ Get the number of instances that are present in the repository for the
++ given 'key'.
++
++ Returns: 0 or more for the num of instances, -1 on error.
++ -------------------------------------------------------------------------*/
++int psp_config_get_num_instances(char *key);
++
++
++/*--------------------------------------------------------------------------
++ Prints the config data for all instances associated with the specified
++ 'key'.
++ -------------------------------------------------------------------------*/
++void psp_config_print(char *key);
++
++void dump_device_cfg_pool(void);
++
++#endif /* __PSP_CONFIG_MGR_H__ */
+diff -urN linux.old/drivers/net/avalanche_cpmac/psp_config_parse.c linux.dev/drivers/net/avalanche_cpmac/psp_config_parse.c
+--- linux.old/drivers/net/avalanche_cpmac/psp_config_parse.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/psp_config_parse.c 2005-07-12 02:48:42.178573000 +0200
+@@ -0,0 +1,362 @@
++/******************************************************************************
++ * FILE PURPOSE: PSP Config Manager - Parse API Source
++ ******************************************************************************
++ * FILE NAME: psp_config_parse.c
++ *
++ * DESCRIPTION: These APIs should be used only for scanvenging parameters which
++ * are stored in the following format.
++ *
++ * str[] = "module(id=[module], k1=v1, k2=[k3=v3, k4=v4], k5=v5)"
++ *
++ * REVISION HISTORY:
++ * 27 Nov 02 - PSP TII
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++//#include <stdio.h>
++#include <linux/stddef.h>
++
++/*--------------------------------------------------
++ * MACROS.
++ *-------------------------------------------------*/
++#define my_isdigit(c) (c >= '0' && c <= '9')
++#define my_isoct(c) (c >= '0' && c <= '7')
++#define my_xtod(c) ((c) <= '9' ? (c) - '0' : (c) - 'a' + 10)
++#define my_ifupper(c) (c >= 'A' && c <= 'F')
++#define XTOD(c) ((c) - 'A' + 10)
++#define my_ishex(c) ((c >= 'a' && c <='f') || (c >= 'A' && c<='F') || my_isdigit(c) )
++
++/*---------------------------------------------------
++ * Local Functions.
++ *--------------------------------------------------*/
++static int p_get_substr_from_str(char *p_in_str, char begin_delimiter,
++ char end_delimiter, int pair_flag,
++ char **p_out_str);
++static int p_get_u_int_from_str(char *p_in_str, char begin_delimiter,
++ char end_delimiter, unsigned long *out_val);
++
++/*---------------------------------------------------
++ * Return pointer to first instance of the char.
++ *--------------------------------------------------*/
++static char* psp_config_strchr(char *str, char chr)
++{
++ while(*str)
++ {
++ if(*str == chr)
++ break;
++ str++;
++ }
++
++ return((*str) ? str : NULL);
++}
++
++/*------------------------------------------------------------------------
++ * Convert the string upto delimiter to unsigned long.
++ *-----------------------------------------------------------------------*/
++unsigned long my_atoul(char *p, char end_delimiter, unsigned long *out_val)
++{
++ unsigned long n;
++ int c;
++
++ /* check the for null input */
++ if (!p)
++ return -1;
++
++ c = *p;
++
++ /* pass through the leading spaces */
++ if (!my_isdigit(c))
++ {
++ while ( c == ' ')
++ c = *++p;
++
++ }
++
++ if (c == '0')
++ {
++ if(*(p + 1) == 'x' || *(p+1) == 'X' )
++ {
++ /* string is in hex format */
++
++ p += 2;
++ c = *p;
++
++ if(my_ishex(c))
++ {
++ if(my_ifupper(c))
++ n = XTOD(c);
++ else
++ n = my_xtod(c);
++ }
++ else
++ return -1; /* invalid hex string format */
++
++ while ((c = *++p) && my_ishex(c))
++ {
++ n *= 16;
++ if(my_ifupper(c))
++ n += XTOD(c);
++ else
++ n += my_xtod(c);
++ }
++ }
++ else
++ {
++ /* string is in octal format */
++
++ if( my_isoct(c) )
++ n = c - '0';
++ else
++ return -1; /* invalid octal string format */
++
++ while ((c = *++p) && my_isoct(c))
++ {
++ n *= 8;
++ n += c - '0';
++ }
++ }
++
++ }
++ else
++ {
++ /* string is in decimal format */
++
++ if( my_isdigit(c) )
++ n = c - '0';
++ else
++ return -1; /* invalid decimal string format */
++
++ while ((c = *++p) && my_isdigit(c))
++ {
++ n *= 10;
++ n += c - '0';
++ }
++ }
++
++ /* move through the trailing spaces */
++ while(*p == ' ')
++ p++;
++
++ if(*p == end_delimiter)
++ {
++ *out_val = n;
++ return 0;
++ }
++
++ else
++ return -1; /* invalid string format */
++}
++
++/*---------------------------------------------------------------------------------
++ * Gets the substring de-limited by the 'begin_delimiter' and 'end_delimiter'.
++ * and returns the size of the substring.
++ *
++ * Parses the NULL terminated p_in_str for a character array delimited by
++ * begin_delimiter and end_delimiter, passes back the pointer to the character
++ * array in ' *p_out_str '. The passed pointer ' *p_out_str ' should point to
++ * the location next (byte) to the begin_delimiter. The function routine returns
++ * the number of characters excluding the begin_delimiter and end_delimiter,
++ * found in the array delimited by the said delimiters.
++ *
++ * If the pair_flag is set to 1, then, number of begin_delimiter and end_delimiter
++ * found in the parsing should match (equal) and this routine passes back the
++ * pointer to the character array, starting at a location next (byte) to the
++ * first begin_delimiter, inclusive of all intermediate matching delimiter
++ * characters found between outer delimiters. If the pair flag is set and if
++ * begin_delimiter and end_delimiter happens to be same, then error (-1) is
++ * returned.
++ *
++ * Return: 0 or more to indicate the size of the substring, -1 on error.
++ *-------------------------------------------------------------------------------*/
++int p_get_substr_from_str(char *p_in_str, char begin_delimiter,
++ char end_delimiter, int pair_flag,
++ char **p_out_str)
++{
++ int cnt,pos;
++
++ if(pair_flag && begin_delimiter == end_delimiter)
++ return -1;
++
++ if((p_in_str = psp_config_strchr(p_in_str, begin_delimiter)) == 0)
++ return -1; /* no start delimiter found */
++
++ p_in_str++;
++ *p_out_str = p_in_str;
++
++ for(pos = 0,cnt =1; cnt && p_in_str[pos] ; pos++)
++ {
++ if(p_in_str[pos] == end_delimiter)
++ {
++ if(pair_flag == 0)
++ return pos;
++
++ cnt--;
++ }
++ else if(p_in_str[pos] == begin_delimiter)
++ cnt++;
++ else
++ ; /* We do nothing */
++
++ }
++
++ if( cnt == 0)
++ return pos - 1;
++ else
++ return -1; /* no corresponding end delimiter found */
++}
++
++/*--------------------------------------------------------------------------
++ * Parses the NULL terminated p_in_str for unsigned long value delimited by
++ * begin_delimiter and end_delimiter, passes back the found in ' *out_val '.
++ * The function routine returns 0 on success and returns -1 on failure.
++ * The first instance of the de-limiter should be accounted for the parsing.
++ *
++ * The base for unsigned value would 10, octal and hex. The value passed back
++ * would be of the base 10. Spaces at the begining of the byte array are valid
++ * and should be ingnored in the calculation of the value. Space character in
++ * the middle of the byte array or any character other than the valid ones
++ * (based on base type) should return error. The octal value begins with '0',
++ * the hex value begins with "0x" or "0X", the base value can begin with
++ * '1' to '9'.
++ *
++ * Returns: 0 on success, -1 on failure.
++ *-------------------------------------------------------------------------*/
++int p_get_u_int_from_str(char *p_in_str, char begin_delimiter,
++ char end_delimiter, unsigned long *out_val)
++{
++ char *start;
++ unsigned long num;
++
++ num = p_get_substr_from_str(p_in_str, begin_delimiter, end_delimiter,
++ 0, &start);
++
++ if(num == (unsigned long)-1)
++ return -1;
++
++ return my_atoul(start,end_delimiter,out_val);
++}
++
++/*--------------------------------------------------------------------------
++ * Finds the first occurrence of the substring p_find_str in the string
++ * p_in_str.
++ *-------------------------------------------------------------------------*/
++char *my_strstr(char *p_in_str, const char *p_find_str)
++{
++ char *p = (char *)p_find_str;
++ char *ret = NULL;
++
++ while(*p_in_str)
++ {
++ if(!(*p))
++ return (ret);
++ else if(*p_in_str == *p)
++ {
++ if(!ret) ret = p_in_str;
++ p++;
++ p_in_str++;
++ }
++ else if(ret)
++ {
++ p = (char *)p_find_str;
++ p_in_str = ret + 1;
++ ret = NULL;
++ }
++ else
++ p_in_str++;
++ }
++
++ if(*p_in_str != *p) ret = NULL;
++
++ return (ret);
++
++}
++
++/*------------------------------------------------------------------------------
++ * Gets the value of the config param in the unsigned int format. The value is
++ * stored in the following format in the string.
++ * str[] = "module(id=[module], k1=v1, k2=[k3=v3, k4=v4], k5=v5)"
++ *-----------------------------------------------------------------------------*/
++int psp_config_get_param_uint(char *p_in_str, const char *param, unsigned int *out_val)
++{
++ int ret_val = -1;
++ char *p_strstr;
++
++ if(!p_in_str || !param || !out_val)
++ {
++ ;
++ }
++ else if((p_strstr = my_strstr(p_in_str, param)) == NULL)
++ {
++ ;
++ }
++ else if(p_get_u_int_from_str(p_strstr, '=', ',', (unsigned long *)out_val) == 0)
++ {
++ ret_val = 0;
++ }
++ else if(p_get_u_int_from_str(p_strstr, '=', ']', (unsigned long*)out_val) == 0)
++ {
++ ret_val = 0;
++ }
++ else if(p_get_u_int_from_str(p_strstr, '=', ')', (unsigned long*)out_val) == 0)
++ {
++ ret_val = 0;
++ }
++ else
++ {
++ /* we failed */
++ }
++
++ return (ret_val);
++}
++
++/*------------------------------------------------------------------------------
++ * Gets the value of the config param in the Non NULL terminated format. The value
++ * is stored in the following format in the string.
++ * str[] = "module(id=[module], k1=v1, k2=[k3=v3, k4=v4], k5=v5)"
++ *-----------------------------------------------------------------------------*/
++int psp_config_get_param_string(char *p_in_str, const char *param, char **out_val)
++{
++ int ret_val = -1;
++ char *p_strstr;
++
++ if(!p_in_str || !param || !(out_val))
++ ;
++ else if((p_strstr = my_strstr(p_in_str, param)) == NULL)
++ {
++ ;
++ }
++ else if((ret_val = p_get_substr_from_str(p_strstr, '[', ']', 1, out_val)) == -1)
++ {
++ ;
++ }
++ else
++ {
++ ; /* we got the value */
++ }
++
++ return (ret_val);
++}
++
++#ifdef PSP_CONFIG_MGR_DEBUG_TEST
++main()
++{
++ unsigned long num =999;
++ int ret = 0;
++ char *val1 = NULL;
++ char val[30];
++ char str1[] = "cpmac(id=[cpmac], k0=[a1=[a2=[test], a3=2], k1=100, k2=[k3=300, k4=200], k7=722)";
++
++ psp_config_get_param_uint(str1, "k7", &num);
++ printf("%u.\n", num);
++ ret = psp_config_get_param_string(str1, "a1", &val1);
++ if(ret >= 0) { printf("%d.\n", ret); strncpy(val, val1, ret); val[ret] = '\0';}
++
++ printf("val = \"%s\", and size = %d \n", val, ret);
++
++ if(val[ret]) ; else printf("jeee.\n");
++}
++#endif /* PSP_CONFIG_MGR_DEBUG_TEST */
++
++
++
+diff -urN linux.old/drivers/net/avalanche_cpmac/psp_config_parse.h linux.dev/drivers/net/avalanche_cpmac/psp_config_parse.h
+--- linux.old/drivers/net/avalanche_cpmac/psp_config_parse.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/psp_config_parse.h 2005-07-12 02:48:42.178573000 +0200
+@@ -0,0 +1,32 @@
++/******************************************************************************
++ * FILE PURPOSE: PSP Config Manager - Parse API Header
++ ******************************************************************************
++ * FILE NAME: psp_config_parse.h
++ *
++ * DESCRIPTION: Parsing for params from string available in the NBU format.
++ * These APIs should be used only for scanvenging parameters which
++ * are stored in the following format.
++ *
++ * str[] = "module(id=[module], k1=v1, k2=[k3=v3, k4=v4], k5=v5)"
++ *
++ * REVISION HISTORY:
++ * 27 Nov 02 - PSP TII
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++#ifndef __PSP_CONFIG_PARSER_H__
++#define __PSP_CONFIG_PARSER_H__
++
++/*------------------------------------------------------------------
++ * These APIs should be used only for scanvenging parameters which
++ * are stored in the following format.
++ *
++ * str[] = "module(id=[module], k1=v1, k2=[k3=v3, k4=v4], k5=v5)"
++ *-----------------------------------------------------------------*/
++int psp_config_get_param_uint(char *p_in_str, const char *param,
++ unsigned int *out_val);
++int psp_config_get_param_string(char *p_in_str, const char *param,
++ char **out_val);
++
++#endif /* __PSP_CONFIG_PARSER_H__ */
+diff -urN linux.old/drivers/net/avalanche_cpmac/psp_config_util.c linux.dev/drivers/net/avalanche_cpmac/psp_config_util.c
+--- linux.old/drivers/net/avalanche_cpmac/psp_config_util.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/psp_config_util.c 2005-07-12 02:48:42.178573000 +0200
+@@ -0,0 +1,106 @@
++/******************************************************************************
++ * FILE PURPOSE: PSP Config Manager - Utilities API Source
++ ******************************************************************************
++ * FILE NAME: psp_config_util.c
++ *
++ * DESCRIPTION: These APIs provide the standard "C" string interfaces.
++ * Provided here to reduce dependencies on the standard libraries
++ * and for cases where psp_config would required to run before
++ * the whole system is loaded or outside the scope of the OS.
++ *
++ * REVISION HISTORY:
++ * 27 Nov 02 - PSP TII
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++//#include <stdio.h>
++#include "psp_config_util.h"
++#include <linux/stddef.h>
++
++/*---------------------------------------------
++ * strlen.
++ *-------------------------------------------*/
++int psp_config_strlen(char *p)
++{
++ char *p_orig = p;
++ while(*p)
++ p++;
++ return(p - p_orig);
++}
++
++/*--------------------------------------------
++ * strcmp.
++ *-------------------------------------------*/
++int psp_config_strcmp(char *s1, char *s2)
++{
++ while(*s1 && *s2)
++ {
++ if(*s1 != *s2)
++ break;
++ s1++;
++ s2++;
++ }
++
++ return(*s1 - *s2);
++}
++
++/*--------------------------------------------
++ * strcpy.
++ *------------------------------------------*/
++char* psp_config_strcpy(char *dest, char *src)
++{
++ char *dest_orig = dest;
++
++ while(*src)
++ {
++ *dest++ = *src++;
++ }
++
++ *dest = '\0';
++
++ return(dest_orig);
++}
++
++/*----------------------------------------------
++ * psp_config_memcpy.
++ *--------------------------------------------*/
++void* psp_config_memcpy(void* dest, void* src, unsigned int n)
++{
++ void *dest_orig = dest;
++
++ while(n)
++ {
++ *(char *)dest++ = *(char *)src++;
++ n--;
++ }
++
++ return (dest_orig);
++}
++
++/*---------------------------------------------------
++ * Return pointer to first instance of the char.
++ *--------------------------------------------------*/
++char* psp_config_strchr(char *str, char chr)
++{
++ while(*str)
++ {
++ if(*str == chr)
++ break;
++ str++;
++ }
++
++ return((*str) ? str : NULL);
++}
++
++#ifdef PSP_CONFIG_MGR_DEBUG_TEST
++
++int main( )
++{
++ char s[] = "hello ";
++ printf("%d.\n", psp_config_strlen("hello\n"));
++ printf("%d.\n", psp_config_strcmp("hells", "hellq"));
++ printf("%s %s.\n", psp_config_strcpy(s + 6, "test1"), s);
++}
++
++#endif /* PSP_CONFIG_MGR_DEBUG_TEST */
+diff -urN linux.old/drivers/net/avalanche_cpmac/psp_config_util.h linux.dev/drivers/net/avalanche_cpmac/psp_config_util.h
+--- linux.old/drivers/net/avalanche_cpmac/psp_config_util.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/psp_config_util.h 2005-07-12 02:48:42.179573000 +0200
+@@ -0,0 +1,26 @@
++/******************************************************************************
++ * FILE PURPOSE: PSP Config Manager - Utilities API Header
++ ******************************************************************************
++ * FILE NAME: psp_config_util.h
++ *
++ * DESCRIPTION: These APIs provide the standard "C" string interfaces.
++ * Provided here to reduce dependencies on the standard libraries
++ * and for cases where psp_config would required to run before
++ * the whole system is loaded or outside the scope of the OS.
++ *
++ * REVISION HISTORY:
++ * 27 Nov 02 - PSP TII
++ *
++ * (C) Copyright 2002, Texas Instruments, Inc
++ *******************************************************************************/
++
++#ifndef __PSP_CONFIG_UTIL_H__
++#define __PSP_CONFIG_UTIL_H__
++
++extern int psp_config_strlen(char*);
++extern int psp_config_strcmp(char*, char*);
++extern char* psp_config_strcpy(char*, char*);
++extern void* psp_config_memcpy(void*, void*, unsigned int n);
++extern char* psp_config_strchr(char*, char);
++
++#endif /* __PSP_CONFIG_UTIL_H__ */
+diff -urN linux.old/drivers/net/avalanche_cpmac/readme.txt linux.dev/drivers/net/avalanche_cpmac/readme.txt
+--- linux.old/drivers/net/avalanche_cpmac/readme.txt 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/avalanche_cpmac/readme.txt 2005-07-12 02:48:42.179573000 +0200
+@@ -0,0 +1,545 @@
++23 August 2004 CPMAC 1.7.8 (NSP Performance Team Release)
++
++CC Labels: REL_20040823_HALdallas_cpmac_01.07.08
++
++New features: Key "MacAddr" can now be used to set the Mac Address after Open.
++
++ unsigned char MacAddr[6];
++
++ // Set Mac Address to "00.B0.D0.10.80.C1"
++ MacAddr[0] = 0x00;
++ MacAddr[1] = 0xB0;
++ MacAddr[2] = 0xD0;
++ MacAddr[3] = 0x10;
++ MacAddr[4] = 0x80;
++ MacAddr[5] = 0xC1;
++
++ HalFunc->Control(HalDev, "MacAddr", hcSet, &MacAddr);
++
++Bug fixes: in Send(), Threshold is not checked if Tx Ints are re-enabled.
++
++Modules affected: hcpmac.c, hcpmac.h, cppi_cpmac.c
++
++22 June 2004 CPMAC 1.7.6 (NSP Performance Team Release)
++
++CC Labels: REL_20040622_HALdallas_cpmac_01.07.06
++
++New features: Key "TxIntDisable" used to disable Tx Interrupts. If it is set, then Tx Interrupts will be processed on Send() controlled by Tx ServiceMax Setting.
++
++ int On = 1;
++ HalFunc->Control(HalDev, "TxIntDisable", "Set", &On);
++
++Bug fixes: NTR
++
++10 June 2004 CPMAC 1.7.5 (external release)
++
++CC Labels: REL_20040610_HALdallas_cpmac_01.07.05
++
++New features: NTR
++
++Bug fixes: Fixed an issue with calculation for the multicast hash.
++
++27 May 2004 CPSAR 1.7.4, CPMAC 1.7.4 (external release)
++
++CC Labels: REL_20040527_HALdallas_cpsar_01.07.04
++ REL_20040527_HALdallas_cpmac_01.07.04
++
++New features: NTR
++
++Bug fixes: A flaw was fixed in the critical sectioning of the CPPI file, affecting both
++ the MAC and the SAR releases. This flaw was detected on Titan PSP 4.7 BFT2.
++
++05 May 2004 CPSAR 1.7.3, CPMAC 1.7.3 (external release)
++
++CC Labels: REL_20040505_HALdallas_cpsar_01.07.03
++ REL_20040505_HALdallas_cpmac_01.07.03
++
++New features: NTR
++
++Bug fixes: 1) Firmware has been updated to fix a problem with Host OAM mode operation.
++ 2) Cache macros have been fixed.
++
++Notes: This release contains all performance enhancements currently available for CPHAL 1.x.
++
++19 April 2004 CPSAR 1.7.2, CPMAC 1.7.2 (external release)
++
++CC Labels: REL_20040419_HALdallas_cpsar_01.07.02
++ REL_20040419_HALdallas_cpmac_01.07.02
++
++New features: NTR
++
++Bug fixes: Fixes merge problem in 1.7.1.
++
++Notes: This is a branch release which contains only a subset of the performance improvements.
++ The remaining performance improvements are stiill being qualified at this time.
++
++1 April 2004 CPSAR 1.7.1, CPMAC 1.7.1 (external release)
++
++NOTICE: DO NOT USE 1.7.1. It has a known problem (see 1.7.2 notes)
++
++CC Labels: REL_20040401_HALdallas_cpsar_01.07.01
++ REL_20040401_HALdallas_cpmac_01.07.01
++
++New features: Performance improvement in CPPI layer, affecting both CPSAR and CPMAC.
++
++Bug fixes: NTR
++
++17 Februrary 2004 CPSAR 1.7.0 (external release)
++
++CC Labels: REL_20040217_HALdallas_cpsar_01.07.00
++
++New features: Added support for "TxFlush" feature. This allows the upper
++ layer to flush all or part of a given Tx queue for a given
++ channel. This is to be used during call setup for a voice
++ connection.
++
++30 January 2004 CPMAC 1.7.0 (external release)
++
++CC Labels: REL_20040130_HALdallas_cpmac_01.07.00
++
++Bug fixes: CPMDIO - When in manual negotiate mode and linked, dropping link would move into NWAY state rather than manual state.
++ CPMDIO - Extraneous debug message corrected
++New features: CPMDIO - Support for AutoMdix usage added.
++
++25 September 2003 CPSAR 1.6.6 (external release)
++
++CC Labels: REL_20030925_HALdallas_cpsar_01.06.06
++
++Bug fixes: PDSP firmware has been updated to fix the OAM padding problem. It previously
++ wrote pad bytes into a reserved field of the OAM cell. There is a small
++ change to the CPSAR configuration code which corresponds to the PDSP spec
++ change.
++
++New features: NTR
++
++09 September 2003 CPMAC 1.6.6 (external release)
++
++CC Labels: REL_20030909_HALdallas_cpmac_01.06.06
++
++Bug fixes: CPMAC : When _CPMDIO_NOPHY is set, Cpmac COntrol is set to Full Duplex
++ Bridge loopback test does not show a problem using 1.6.5 if packet rate is
++ below 50,000 pbs. Now testing with a 100% send from Ixia.
++
++New features: NTR
++
++05 August 2003 CPHAL 1.6.5 (external release)
++
++CC Labels: REL_20030805_HALdallas_cpmac_01.06.05
++
++Bug fixes: NTR
++
++New features: CPMAC : Added support for CPMAC modules that do not have a Phy connected.
++ The CPMAC is informed of this by the MdioConnect option
++ _CPMDIO_NOPHY. This is the only driver change needed to
++ receive and transmit packets through the Marvel switch.
++ Note In this mode Link status will reported linked at 100/FD to
++ PhyNum 0xFFFFFFFF.
++
++ ALL: Cleaned up some Vlynq support logic.
++
++16 July 2003 CPSAR 1.6.3 (external release), no CPMAC release
++
++CC Labels: REL_20030716_HALdallas_cpsar_01.06.03
++
++Bug fixes: 1) Changed default value of CPCS_UU from 0x5aa5 to 0. The old default value caused
++ problems with Cisco routers.
++
++New features: NTR
++
++Known issues not addressed in this release: NTR.
++
++01 July 2003 CPHAL 1.6.2 (external release)
++
++CC Labels: REL_20030701_HALdallas_cpmac_01.06.02
++ REL_20030701_HALdallas_cpsar_01.06.02
++
++Bug fixes: 1) A previous firmware upgrade caused firmware OAM loopback cells to only work on every other
++ command. This has been fixed in the new firmware version (0.47).
++ 2) Problem with PTI values changing on transparent mode packets has been resolved.
++ 3) Previously, successful firmware OAM loopback cells waited 5 seconds before notifying the
++ OS of success, rather that notifying immediately. This has been resolved in firmware.
++ 4) PITS #148 (MAC and SAR), #149 (MAC) have been fixed.
++
++New features: 1) AAL5 HAL now capable of receiving unknown VCI/VPI cells on a single transparent channel.
++ See updated HAL document (AAL5 appendix) for implementation details.
++ 2) AAL5 HAL now allows OS to modify the OAM loopback timeout window. Previously, failed
++ OAM loopback attempts timed out after a nominal 5 seconds (based on the SAR frequency
++ provided by the OS). Now, the default is 5 seconds, but the OS may change the
++ value via halControl() to any integer number of milliseconds. See updated HAL document
++ (AAL5 appendix) for implementation details.
++ 3) MAC (cpmdio): added loopback to Istate. Used for debug.
++
++Known issues not addressed in this release: NTR.
++
++09 June 2003 CPSAR 1.6.1 (external release), CPMAC 1.6.1 (internal release - no functional change)
++
++Note: This is the same set of fixes being applied to 1.6.0 that were applied to 1.5.3. The only difference
++ between 1.6.1 and 1.5.4 is that 1.6.1 has the TurboDSL fix.
++
++CC Labels: REL_20030609_HALdallas_cpmac_01.06.01
++ REL_20030609_HALdallas_cpsar_01.06.01
++
++Bug fixes: 1) Bug in OamLoopbackConfig fixed.
++ 2) New firmware version (.43) to fix Westell issue of dropped downstream packets in
++ presence of OAM traffic when operating at or near line rate.
++
++New features: NTR.
++
++09 June 2003 CPSAR 1.5.4 (external release), CPMAC 1.5.4 (internal release - no functional change)
++
++Note: This is a branch release from 1.5.3. This does not contain anything from 1.6.0. The CPMAC is
++only being labeled to keep the release flow consistent.
++
++CC Labels: REL_20030609_HALdallas_cpmac_01.05.04
++ REL_20030609_HALdallas_cpsar_01.05.04
++
++Bug fixes: 1) Bug in OamLoopbackConfig fixed.
++ 2) New firmware version (.43) to fix Westell issue of dropped downstream packets in
++ presence of OAM traffic when operating at or near line rate.
++
++New features: NTR.
++
++30 May 2003 CPSAR 1.6.0 (external release), CPMAC 1.6.0 (internal release - no functional change)
++
++CC Labels: REL_20030530_HALdallas_cpmac_01.06.00
++ REL_20030530_HALdallas_cpsar_01.06.00
++
++Bug fixes: 1) TurboDSL issue has been fixed with a software workaround in TxInt. This workaround
++ has been verified under Adam2 ONLY at this point. Testing remains to be done on
++ Linux and VxWorks.
++
++New features: NTR.
++
++Known issues not addressed in this release: NTR.
++
++30 May 2003 CPSAR 1.5.3 (external release), CPMAC 1.5.3 (internal release - no functional change)
++
++CC Labels: REL_20030530_HALdallas_cpmac_01.05.03
++ REL_20030530_HALdallas_cpsar_01.05.03
++
++Bug fixes: NTR.
++
++New features: 1) AAL5 Send() has been modified to accept an ATM Header either in the first
++ fragment by itself, or in the first fragment directly in front of payload data.
++ The API() does not change.
++ 2) Documentation updates throughout, reflected in latest version of CPHAL user's
++ guide.
++ 3) AAL5 MaxFrags default value is now 46. This is based upon the default AAL5
++ RxBufSize of 1518 (MaxFrags = (65568/1518) + 2). IF THE OS CHOOSES A SMALLER
++ RxBufSize, IT MUST INCREASE THE VALUE OF MaxFrags ACCORDINGLY. This is done
++ via halControl(), prior to Open().
++
++Known issues not addressed in this release:
++ 1) The Linux SAR driver is seeing an issue in which it cannot
++ reliably send traffic simultaneously on both the high and
++ low priority queues of a single AAL5 channel. (TurboDSL)
++
++23 May 2003 CPHAL 1.5.2 (external release)
++
++CC Labels: REL_20030523_HALdallas_cpmac_01.05.02
++ REL_20030523_HALdallas_cpsar_01.05.02
++
++Bug fixes: 1) PITS #138: CPMAC flooding issue resolved.
++ 2) PITS #142: OS may now set "MaxFrags" via Control(). This controls the
++ maximum number of fragments expected by the CPHAL. The default value is 2 for
++ CPMAC and 1028 for AAL5. If the OS chooses a RxBufSize that will cause more
++ fragments than the defaults, the OS must set "MaxFrags" to a correct value
++ ((maximum packet length / RxBufSize) + 2).
++ 3) PITS #143: Fixed.
++ 4) Firmware OAM bug fixed. (new firmware release in this version)
++
++New features: NTR.
++
++Known issues not addressed in this release:
++ 1) The Linux SAR driver is seeing an issue in which it cannot
++ reliably send traffic simultaneously on both the high and
++ low priority queues of a single AAL5 channel. (TurboDSL)
++
++14 May 2003 CPHAL 1.5.1 (external release)
++
++CC Labels: REL_20030514_HALdallas_cpmac_01.05.01
++ REL_20030514_HALdallas_cpsar_01.05.01
++
++Bug fixes: 1) PITS 132 - (CPMAC) Frames < 60 bytes and split into
++ multi-fragments.
++ 2) BCIL MR PSP00000353 - (CPMAC) PhyDev not free'd on halClose()
++ 3) PITS 113 - OsSetup bug in ChannelSetup fixed.
++ 4) Fixed AAL5 to check return values of InitTcb/InitRcb.
++ 5) Fixed Shutdown to properly free resources in the case of a Close
++ mode 1 followed by Shutdown. Previously, buffer and descriptor
++ resources were left unfreed in this case.
++
++New features: 1) AAL5 Send() modified to be capable of accepting ATM header as first four
++ bytes of first fragment. This allows the OS to "override" the
++ default ATM header which is constructed from preconfigured channel
++ parameters.
++ 2) AAL5 Receive() modified to be capable of passing the received ATM header (4 bytes, no HEC)
++ in the first fragment (by itself). It also passes up the OS an indication
++ of what the received packet type was. For Host OAM and transparent mode
++ packets, the ATM header is passed in this manner, and for other types of packets
++ (AAL5, NULL AAL) no ATM header is passed currently.
++
++Known issues not addressed in this release:
++ 1) The Linux SAR driver is seeing an issue in which it cannot
++ reliably send traffic simultaneously on both the high and
++ low priority queues of a single AAL5 channel.
++
++30 April 2003 CPHAL 1.5.0 (external release)
++
++CC Labels: REL_20030430_HALdallas_cpmac_01.05.00
++ REL_20030430_HALdallas_cpsar_01.05.00
++
++Bug fixes: 1) Fixed AAL5 bug that rendered the low priority queue
++ unusable.
++ 2) Fixed a bug in AAL5's Oam Rate calculations.
++ 3) Fixed use of "DeviceCPID" key in AAL5's halControl().
++ 4) Fixed RxReturn logic in HAL. The HAL now can handle
++ failing MallocRxBuffer calls when multiple fragments
++ are being used.
++
++New features: 1) AAL5 Stats now available on a per queue basis.
++ 2) AAL5 adds two new keys to halControl() for "Set" actions:
++ RxVc_OamCh and RxVp_OamCh.
++ 3) Shutdown() has been modified for both AAL5 and CPMAC to
++ call Close() if the module is still in the Open state.
++ 4) CPMAC adds the following access keys to halControl():
++ hcPhyAccess,hcPhyNum,hcCpmacBase,hcSize,and hcCpmacSize.
++ 5) CPHAL no longer requests an extra 15 bytes on data buffer
++ mallocs.
++
++Known issues not addressed in this release:
++ 1) The Linux SAR driver is seeing an issue in which it cannot
++ reliably send traffic simultaneously on both the high and
++ low priority queues of a single AAL5 channel.
++
++21 April 2003 CPHAL 1.4.1 (external release)
++
++CC Labels: REL_20030421_HALdallas_cpmac_01.04.01
++ REL_20030421_HALdallas_cpsar_01.04.01
++
++Bug fixes: 1) Fixed OAM logic in SAR portion of CPHAL.
++
++New features: 1) OAM loopback counters exposed through halControl.
++ 2) Host OAM Send() can now use a single channel to send
++ OAM cells on unlimited number of VP's/VC's.
++ 3) CPHAL now requests "SarFreq" through osControl.
++ 4) CPHAL now calculates all OAM function rates based on
++ "SarFreq"; function OamRateConfig removed for API.
++ 5) New OAM function OamLoopbackConfig, used for configuring
++ loopback functions in firmware OAM mode.
++
++Known issues not addressed in this release: Bug fix 1) in release 1.4
++ (see below) does not work properly for multiple fragments.
++
++10 April 2003 CPHAL 1.4 (external release)
++
++CC Labels: REL_20030410_HALdallas_cpmac_01.04.00
++ REL_20030410_HALdallas_cpsar_01.04.00
++
++This release is for SAR and MAC.
++
++ Bug fixes: 1) Implemented logic in HAL to re-request buffer mallocs
++ in the case of MallocRxBuffer failing. The HAL now maintains
++ a NeedsBuffer queue of all RCB's that are without buffers.
++ On interrupts, or on Send(), the HAL checks to see if any
++ RCB's are on the queue, and if so, calls MallocRxBuffer
++ to attempt to get a new buffer and return the RCB to
++ circulation.
++ 2) SAR now properly returns all error codes from halOpen and
++ halChannelSetup.
++
++ New features: NTR
++
++ Known issues not addressed in this release: NTR
++
++08 April 2003 CPHAL 1.3.1 (internal release - SAR only)
++
++ CC Labels: REL_20030408_HALdallas_cpsar_01.03.01
++
++ This is a SAR only release. The current CPMAC release is still 1.3.
++
++ Bug fixes: 1) PDSP State RAM / Scratchpad RAM is now completely cleared after reset.
++ This resolves a stability issue.
++
++ New features: 1) OamMode is now a parameter in halControl(). Both "Set" and "Get"
++ actions are available. The value may be "0" (Host OAM), or "1"
++ (Firmware OAM).
++
++ Known issues not addressed in this release:
++ 1) Appropriate action for HAL in the case of MallocRxBuffer failing. We
++ are investigating whether the HAL should implement a needs buffer
++ queue.
++
++04 April 2003 CPHAL 1.3 (external release)
++
++ CC Labels: REL_20030404_HALdallas_cpmac_01.03.00
++ REL_20030404_HALdallas_cpsar_01.03.00
++ REL_20030404_HALdallas_cpaal5_01.03.00
++ REL_20030404_HALdallas_cpaal2_01.03.00
++
++ This release requires no changes for the ethernet end driver. The changes necessary
++ for the sar driver (firmware file name changes) have already been implemented.
++
++ Bug fixes: 1) RxReturn now returns an error if MallocRxBuffer fails. On RxReturn error, the driver should
++ call RxReturn again at a later time (when the malloc may succeed) in order for the CPHAL
++ to maintain a full complement of Rx buffers. We recommend holding off making this driver
++ change until we verify that this condition occurs.
++
++ New features: 1) Removed benign compiler warnings.
++ 2) PITS 122: http://www.nbu.sc.ti.com/cgi-bin/pits/redisplay_archive?product=cphal_dev&report=122
++ 3) Cpsar label (above) now is applied to everything
++ beneath /cpsar.
++ 4) PITS 14: http://www.nbu.sc.ti.com/cgi-bin/pits/redisplay_archive?product=cphal_dev&report=14
++ Transferred to MR PSP 00000089.
++ 5) PITS 120: http://www.nbu.sc.ti.com/cgi-bin/pits/redisplay_archive?product=cphal_dev&report=120
++
++ Known issues not addressed in this release:
++ 1) PITS 102 (as relating to OamMode configuration):
++ http://www.nbu.sc.ti.com/cgi-bin/pits/redisplay_archive?product=cphal_dev&report=102
++ Future release will make OamMode configurable
++ through halControl(), not on per channel basis.
++
++20 March 2003 CPHAL 1.2.1 (internal release)
++
++ CC Labels: REL_20030320_HALdallas_cpmac_01.02.01
++ REL_20030320_HALdallas_cpsar_01.02.01
++ REL_20030320_HALdallas_cpaal5_01.02.01
++ REL_20030320_HALdallas_cpaal2_01.02.01
++
++ Bug fixes: 1. Fixed modification of buffer pointer following
++ MallocRxBuffer in cppi.c.
++ 2. Removed extra firmware files from /cpsar.
++
++ New features: NTR.
++
++ Known issues not addressed in this release: NTR.
++
++07 March 2003 CPHAL 1.2 (external release)
++
++ CPMAC/CPSAR feature complete release. SAR added
++ several features including full OAM support and various
++ other features and bug fixes to address PITS 99-106, and
++ 114. CPMAC cleaned up details raised by India PSP
++ team.
++
++29 January 2003 CPHAL RC 3.01a (external release)
++
++ Corrects non-static functions to be static in cppi.c.
++
++09 Janurary 2003 CPHAL RC 3.01 (external release)
++
++ PITS 88: Fixed MDIO re-connection problem (hcpmac.c)
++ PITS 90: Corrected Rx Buffer Pointer modification (cppi.c)
++
++ Corrected error in cpremap.c
++
++20 December 2002 CPHAL RC 3 (external release)
++
++ Statistics support via halControl(). See Appendix A of guide.
++ Fixed errors in ChannelTeardown/ChannelSetup CPHAL logic.
++ Added multicast support as requested.
++ Several new OS string functions added to OS_FUNCTIONS.
++ "DebugLevel" configuration parameter changed to "Debug".
++ "Stats0" changed to "StatsDump" for CPMAC.
++
++13 December 2002 CPHAL RC 2.03 (internal release)
++
++ Performance improvements.
++ More debug statements implemented (esp AAL5).
++ Updated makefile with "make debug" option.
++ Hbridge performance: [debug library] 15774 tps (53% line rate)
++ [non-debug library] 13700 tps (46%)
++
++10 December 2002 CPHAL Release Candidate 2.02 (internal release)
++
++ Much of the configuration code internal to CPMAC and AAL5 has been made common.
++ [os]Receive API had been modified to remove OsReceiveInfo. This information is now
++ available as third member of the FRAGLIST structure, on a per buffer basis.
++ Successfully tested multi-fragment support on CPMAC, using 32 byte buffers.
++ Code is now Emerald compliant - all buffer descriptors now aligned to cache-line
++ boundaries.
++
++2 December 2002 CPHAL Release Candidate 2.01
++
++ Updates to comments in hcpmac.c, cpmdio.c, hcpmac.h
++ Nested comment in hcpmac.c in RC2 can cause compile errors.
++
++25 November 2002 CPHAL Release Candidate 2
++
++Project Items not completed for RC2
++#6 Ship as Library - Once under CC. Moved to RC3
++#8 Under Clearcase - Moved to RC3
++#25 Emerald compliant - Moved to RC3
++#26 Statistics support - Moved to RC3 (some support in RC2)
++#36 Debug scheme implemented - Moved to RC3 (some support in RC2)
++
++8 November 2002 CPHAL Release Candidate 1
++
++Notes:
++
++Project Items not completed for RC1
++
++#8 Under Clearcase - Clearcase server failure this week. Moved to RC2
++#6 Ship as Library - Once under CC. Moved to RC2
++#13 Verify Datatypes. Moved to RC2
++#14 Review APIs. Moved to RC2
++
++APIs under review for RC2
++
++halIsr()
++hslRxReturn()
++halSend()
++osSendComplete()
++osReceive()
++
++
++CPMAC Build Instructions
++
++Compile the file 'hcpmac.c'.
++
++
++AAL5 Build Instructions
++
++The AAL5 build is composed of the source files aal5sar.c and cpsar.c.
++Refer to the provided makefile for an example of compiling these files
++into a library.
++
++Example CPHAL Code
++
++CPMAC:
++
++Example CPMAC code is provided in the file hbridge.c.
++This program is provided simply as an example of using the CPHAL API.
++It is not intended to be compiled and executed in your environment.
++
++AAL5:
++
++Example AAL5 code is provided in the file loopback.c. This program
++is provided simply as an example of using the CPHAL API. It is not
++intended to be compiled and executed in your environment.
++
++
++Performance Baseline
++
++
++Cpmac
++
++RC1: hbridge.bin, running with IXIA cpahl_1.cfg.
++ This sends 64-byte packets from each Ixia port, with mac destination the other Ixia port.
++ MIPS core 4Kc.
++
++RC2: hbridge.bin, running with IXIA cpahl_1.cfg.
++ This sends 64-byte packets from each Ixia port, with mac destination the other Ixia port.
++ MIPS core 4Ke.
++ CPHAL now includes Emerald support, but this has been disabled by using 'cache -wt' to emulate 4Kc.
++
++RC3: hbridge.bin, running with IXIA cpahl_1.cfg.
++ This sends 64-byte packets from each Ixia port, with mac destination the other Ixia port.
++ MIPS core 4Ke.
++ Running as Emerald processor.
++
++Release Total Receive Rate Throughput Setting
++
++RC1 11300 38%
++RC2 9524 32%
++RC3 15190 51%
+diff -urN linux.old/drivers/net/Config.in linux.dev/drivers/net/Config.in
+--- linux.old/drivers/net/Config.in 2005-07-12 03:20:45.726149872 +0200
++++ linux.dev/drivers/net/Config.in 2005-07-12 02:48:42.180573000 +0200
+@@ -25,6 +25,24 @@
+ comment 'Ethernet (10 or 100Mbit)'
+ bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
+ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
++ if [ "$CONFIG_MIPS_TITAN" = "y" -o "$CONFIG_AR7" = "y" ]; then
++ tristate ' Texas Instruments Avalanche CPMAC support' CONFIG_MIPS_AVALANCHE_CPMAC
++ fi
++ if [ "$CONFIG_MIPS_AVALANCHE_CPMAC" != "n" ]; then
++ if [ "$CONFIG_AR7WRD" = "y" -o "$CONFIG_AR7VWI" = "y" -o "$CONFIG_AR7VW" = "y" ]; then
++ define_bool CONFIG_MIPS_CPMAC_INIT_BUF_MALLOC y
++ define_int CONFIG_MIPS_CPMAC_PORTS 1
++ if [ "$CONFIG_MIPS_AVALANCHE_MARVELL" = "y" ]; then
++ define_bool CONFIG_AVALANCHE_LOW_CPMAC n
++ define_bool CONFIG_AVALANCHE_HIGH_CPMAC y
++ else
++ define_bool CONFIG_AVALANCHE_CPMAC_AUTO y
++ define_bool CONFIG_AVALANCHE_LOW_CPMAC n
++ define_bool CONFIG_AVALANCHE_HIGH_CPMAC n
++ fi
++ fi
++ fi
++
+ if [ "$CONFIG_ARM" = "y" ]; then
+ dep_bool ' ARM EBSA110 AM79C961A support' CONFIG_ARM_AM79C961A $CONFIG_ARCH_EBSA110
+ tristate ' Cirrus Logic CS8900A support' CONFIG_ARM_CIRRUS
+diff -urN linux.old/drivers/net/Makefile linux.dev/drivers/net/Makefile
+--- linux.old/drivers/net/Makefile 2005-07-12 03:20:45.726149872 +0200
++++ linux.dev/drivers/net/Makefile 2005-07-12 02:48:42.181573000 +0200
+@@ -56,6 +56,16 @@
+ subdir-$(CONFIG_BONDING) += bonding
+
+ #
++# Texas Instruments AVALANCHE CPMAC driver
++#
++
++subdir-$(CONFIG_MIPS_AVALANCHE_CPMAC) += avalanche_cpmac
++#obj-$(CONFIG_MIPS_AVALANCHE_CPMAC) += avalanche_cpmac/avalanche_cpmac.o
++ifeq ($(CONFIG_MIPS_AVALANCHE_CPMAC),y)
++ obj-y += avalanche_cpmac/avalanche_cpmac.o
++endif
++
++#
+ # link order important here
+ #
+ obj-$(CONFIG_PLIP) += plip.o
+--- linux.old/drivers/net/avalanche_cpmac/cpmac.c 2005-08-25 10:56:33.702931008 +0200
++++ linux.dev/drivers/net/avalanche_cpmac/cpmac.c 2005-08-25 11:08:45.027451520 +0200
+@@ -2158,17 +2158,16 @@
+ CPMAC_PRIVATE_INFO_T *p_cpmac_priv = p_dev->priv;
+ CPMAC_DRV_HAL_INFO_T *p_drv_hal = p_cpmac_priv->drv_hal;
+ struct sk_buff *p_skb = fragList[0].OsInfo;
+- p_skb->len = fragList[0].len;
+
+ /* invalidate the cache. */
+ dma_cache_inv((unsigned long)p_skb->data, fragList[0].len);
+ #ifdef CPMAC_TEST
+- xdump(p_skb->data, p_skb->len, "recv");
++ xdump(p_skb->data, fragList[0].len, "recv");
+ #endif
+ #ifdef CPMAC_8021Q_SUPPORT
+ /* 802.1q stuff, just does the basic checking here. */
+ if(!p_cpmac_priv->enable_802_1q &&
+- p_skb->len > TCI_END_OFFSET &&
++ fragList[0].len > TCI_END_OFFSET &&
+ IS_802_1Q_FRAME(p_skb->data + TPID_START_OFFSET))
+ {
+ goto cpmac_hal_recv_frame_mismatch;
diff --git a/target/linux/ar7-2.4/patches/004-atm_driver.patch b/target/linux/ar7-2.4/patches/004-atm_driver.patch
new file mode 100644
index 0000000..f6a9208
--- /dev/null
+++ b/target/linux/ar7-2.4/patches/004-atm_driver.patch
@@ -0,0 +1,27232 @@
+diff -urN linux.old/drivers/atm/Config.in linux.dev/drivers/atm/Config.in
+--- linux.old/drivers/atm/Config.in 2005-08-22 23:18:37.773532032 +0200
++++ linux.dev/drivers/atm/Config.in 2005-08-23 04:46:50.076846888 +0200
+@@ -99,4 +99,10 @@
+ bool 'Use S/UNI PHY driver' CONFIG_ATM_HE_USE_SUNI
+ fi
+ fi
++#
++# Texas Instruments SANGAM ADSL/ATM support
++#
++if [ "$CONFIG_AR7" = "y" ]; then
++ tristate 'Texas Instruments SANGAM ATM/ADSL support' CONFIG_MIPS_SANGAM_ATM
++fi
+ endmenu
+diff -urN linux.old/drivers/atm/Makefile linux.dev/drivers/atm/Makefile
+--- linux.old/drivers/atm/Makefile 2005-08-22 23:18:37.773532032 +0200
++++ linux.dev/drivers/atm/Makefile 2005-08-23 04:46:50.077846736 +0200
+@@ -14,6 +14,32 @@
+ obj-$(CONFIG_ATM_NICSTAR) += nicstar.o
+ obj-$(CONFIG_ATM_IDT77252) += idt77252.o
+
++ifeq ($(CONFIG_AR7),y)
++
++subdir-$(CONFIG_MIPS_SANGAM_ATM) += sangam_atm
++
++EXTRA_CFLAGS += -DEL -I$(TOPDIR)/drivers/atm/sangam_atm -DPOST_SILICON -DCOMMON_NSP -DCONFIG_LED_MODULE -DDEREGISTER_LED -DNO_ACT
++#EXTRA_CFLAGS += -DEL -I$(TOPDIR)/drivers/atm/sangam_atm -DPOST_SILICON -DCOMMON_NSP
++
++ifeq ($(ANNEX),B)
++EXTRA_CFLAGS += -DANNEX_B -DB
++else
++ifeq ($(ANNEX),C)
++EXTRA_CFLAGS += -DANNEX_C -DC
++else
++EXTRA_CFLAGS += -DANNEX_A -DP
++endif
++endif
++
++list-multi := tiatm.o
++tiatm-objs := sangam_atm/tn7atm.o sangam_atm/tn7dsl.o sangam_atm/tn7sar.o \
++ sangam_atm/dsl_hal_api.o sangam_atm/dsl_hal_support.o sangam_atm/cpsar.o \
++ sangam_atm/aal5sar.o
++
++obj-$(CONFIG_MIPS_SANGAM_ATM) += sangam_atm/tiatm.o
++
++endif
++
+ ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y)
+ obj-$(CONFIG_ATM_NICSTAR) += suni.o
+ endif
+diff -urN linux.old/drivers/atm/sangam_atm/aal5sar.c linux.dev/drivers/atm/sangam_atm/aal5sar.c
+--- linux.old/drivers/atm/sangam_atm/aal5sar.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/aal5sar.c 2005-08-23 04:46:50.080846280 +0200
+@@ -0,0 +1,2962 @@
++
++/**
++ *
++ * aal5sar.c
++ *
++ * TNETDxxxx Software Support\n
++ * Copyright (c) 2002 Texas Instruments Incorporated. All Rights Reserved.
++ *
++ * version
++ * 28Feb02 Greg 1.00 Original Version created.\n
++ * 06Mar02 Greg 1.01 Documentation (Doxygen-style) enhanced
++ * 06May02 Greg 1.02 AAL2 added
++ * 06Jun02 Greg 1.03 Multiple API and bug fixes from emulation
++ * 12Jul02 Greg 1.04 API Update
++ */
++
++/**
++@defgroup CPHAL_Functions CPHAL Functions
++
++These are the CPHAL Functions.
++*/
++
++/**
++@page CPHAL_Implementation_Details
++
++@section cphal_intro Introduction
++
++The CPHAL API described above is generally applicable to all modules. Any
++implementation differences will be described in the following module-specific
++appendix sections.
++
++Included for your reference is a diagram showing the internal architecture
++of the CPHAL:
++
++@image html SangamSoftware.jpg "HAL Architecture"
++@image latex SangamSoftware.jpg "HAL Architecture" height=2.8in
++
++*/
++
++/**
++@defgroup AAL5_Functions Additional Functions for AAL5 Implementation
++
++These functions are used only by the AAL5 module.
++*/
++
++/*
++@defgroup CPMAC_Functions Additional Functions for CPMAC Implementation
++
++No additional functions currently defined.
++*/
++
++/**
++@page VDMA_Implementation_Details
++
++@section vdma_intro Introduction
++
++The VDMA-VT module facilitates efficient transfer of data (especially voice)
++between two devices, as shown in the figure below.
++
++@image html vdma.jpg "VDMA System Block Diagram"
++@image latex vdma.jpg "VDMA System Block Diagram" height=1in
++
++The VDMA-VT module supports two modes of operation: mirror mode and credit mode.
++Mirror mode is intended for systems in which the remote device does not have a
++VDMA-based module. Credit mode is intended for highest performance when VDMA-based
++modules exist on both ends of an interface.
++
++For more detailed information on the operation of the VDMA module, please
++reference the VDMA Module Guide.
++
++@section vdma_channels VDMA Channels
++
++The VDMA-VT module is a single channel, single transmit queue device. Therefore,
++when using the CHANNEL_INFO structure, the correct value for @c Ch is always 0.
++Correspondingly, the correct value for the @c Ch parameter in @c ChannelTeardown() is
++always 0. Further, when calling @c Send(), the driver should always supply the value
++of 0 for both the @c Ch and @c Queue parameters.
++
++For the VDMA-VT, configuring the channel requires the configuration of either 2 FIFO
++elements (in credit mode) or 4 FIFO elements (in mirror mode). For credit mode, the
++driver must configure just the local Tx and Rx FIFOs. For mirror mode, the driver must
++configure the Tx and Rx FIFOs for both the remote and local ends of the interface.
++
++This channel configuration is accomplished through multiple calls to @c ChannelSetup().
++Each call configures a single FIFO, according to the parameters in the CHANNEL_INFO
++structure. The members of VDMA-VT's CHANNEL_INFO structure are defined below.
++
++
++- int RemFifoAddr; Address of remote FIFO (mirror mode only). Set to 0 for credit mode.
++- int FifoAddr; Address of the local FIFO. If 0, the CPHAL will allocate the FIFO.
++- int FifoSize; Size of the FIFO.
++- int PollInt; Polling interval for the FIFO.
++- int Endianness; Endianness of the FIFO. If 1, big endian. If 0, little endian.
++- int RemAddr; Used only in credit mode. This is the base address of the remote
++ remote VDMA-based device (VDMA-VT or AAL2)
++- int RemDevID; Used only in credit mode. Identifies the type of remote VDMA-based device.
++ 0=VDMAVT, 1=AAL2 Ch0, 2=AAL2 Ch1, 3=AAL2 Ch2, 4= AAL2 Ch3.
++
++For the VDMA-VT module, the driver must make all calls to @c ChannelSetup() prior to calling
++@c Open(). This is because several of the channel specific parameters may not be changed
++while the VDMA-VT module is operational.
++
++@section vdma_params VDMA Parameters
++
++Defined here are the set of parameters for the VDMA-VT module. Default settings for
++each parameter should be represented in the device configuration file (options.conf).
++During @c Init(), the CPHAL will reference the device configuration file and load all
++default settings. The @c Control() interface gives the driver an opportunity to
++modify any default settings before the module becomes operational during the @c Open()
++call.
++
++@param NoTxIndication If 1, the CPHAL will not call @c SendComplete(). 0 is default.
++@param NoRxIndication If 1, the CPHAL will not call @c Receive(). 0 is default.
++@param RemoteCPU If 1, the CPHAL will not directly manipulate data in FIFO's, leaving
++ that task for a remote CPU. 0 is default.
++@param RxIntEn If 1, enables Rx interrupts. 0 is default.
++@param TxIntEn If 1, enables Tx interrupts. 0 is default.
++@param Mirror If 1, enables mirror mode. 0 selects credit mode (default).
++@param RxIntCtl Valid only in mirror mode. If 1, interrupts will occur when the Rx FIFO
++ RdIndex is updated. If 0, interrupts occur when the Rx FIFO WrIndex
++ is updated.
++@param TxIntCtl Valid only in mirror mode. If 1, interrupts will occur when the Rx FIFO
++ RdIndex is updated. If 0, interrupts occur when the Rx FIFO WrIndex
++ is updated.
++@param RBigEn Remote big endian mode. If 1, remote is big endian.
++@param LBigEn Local big endian mode. If 1, local is big endian.
++
++@section vdma_polling Using VDMA-VT without interrupts
++
++If your system configuration does not utilize VDMA interrupts, the ability to process the
++Tx and Rx FIFOs is supported. To process the Tx FIFO, call @c CheckTx(). If the CPHAL is
++able to process any complete data transmissions, it will call @c SendComplete() as usual.
++To process the Rx FIFO, call @c CheckRx(). If the CPHAL has received any data, it will
++call @c Receive() to pass the driver the data. Please reference @ref VDMA_Functions for more
++information on these interfaces.
++
++@section vdma_details VDMA Implementation Details
++
++The following functions are not defined for use with VDMA: @c Status(), @c Tick(), @c StatsGet(),
++and @c StatsClear().
++
++*/
++
++/**
++@page AAL5_Implementation_Details
++
++@section aal5_ver Version
++
++@copydoc AAL5_Version
++
++@section aal5_intro Introduction
++
++The AAL5 implementation will support 16 channels for transmit and 16 channels for
++receive. Each of the transmit channels may have up to two transmit queues
++associated with it. If two queues are used, Queue 0 is the high priority queue,
++and Queue 1 is the low priority queue.
++
++@section aal5_params AAL5 Configuration Parameters
++
++AAL5 requires two device entries to be available in the configuration repository, named
++@p "aal5" and @p "sar". The @p aal5 device entry must contain @p base (base address)
++and @p int_line (interrupt number). The @p sar device entry must have both @p base
++(base address) and @p reset_bit (reset bit).
++
++@par Device Level Configuration Parameters
++
++The following parameters are device-level parameters, which apply across all
++channels. The value for these parameters may be modified by changing the value in the
++configuration repository.
++
++- "UniNni":
++AAL5 network setting. 0 = UNI (default), 1 = NNI.
++
++@par Channel Configuration Parameters
++
++All AAL5 channel parameters may also be configured through the @c ChannelSetup() interface.
++Following is the list of @p CHANNEL_INFO members that may be modified by the driver when
++calling @c ChannelSetup(). The driver may provide a value of 0xFFFFFFFF for any channel
++parameter to select a default value for the parameter. The driver should at a minimum
++configure @p Vci and @p Vpi. The usage of all parameters beginning with TxVc_,
++TxVp_, RxVc_, RxVp_ is described in greater detail in the SAR Firmware Spec.
++These parameters are mainly associated with QoS and OAM functionality.
++
++- "RxNumBuffers":
++The number of Rx buffer descriptors to allocate for Ch.
++- "RxBufSize":
++Size (in bytes) for each Rx buffer.
++- "RxBufferOffset":
++Number of bytes to offset rx data from start of buffer (must be less than buffer size).
++- "RxServiceMax":
++Maximum number of packets to service at one time.
++- "TxNumBuffers":
++The number of Tx buffer descriptors to allocate for Ch.
++- "TxNumQueues":
++Number of Tx queues for this channel (1-2). Choosing 2 enables a low priority SAR queue.
++- "TxServiceMax":
++Maximum number of packets to service at one time.
++- "CpcsUU":
++The 2-byte CPCS UU and CPI information.
++- "Gfc":
++Generic Flow Control. Used in ATM header of Tx packets.
++- "Clp":
++Cell Loss Priority. Used in ATM header of Tx packets.
++- "Pti":
++Payload Type Indication. Used in ATM header of Tx packets.
++- "DaMask":
++Specifies whether credit issuance is paused when Tx data not available.
++- "Priority":
++Priority bin this channel will be scheduled within.
++- "PktType":
++0=AAL5,1=Null AAL,2=OAM,3=Transparent,4=AAL2.
++- "Vci":
++Virtual Channel Identifier.
++- "Vpi":
++Virtual Path Identifier.
++- "TxVc_AtmHeader":
++In firmware OAM mode, this
++is the ATM header to be appended to front of firmware generated VC OAM cells for
++this channel. Note: To generate host OAM cells, call @c Send() with
++the appropriate mode.
++- "TxVc_CellRate":
++Tx rate, set as clock ticks between transmissions (SCR for VBR, CBR for CBR).
++- "TxVc_QosType":
++0=CBR,1=VBR,2=UBR,3=UBRmcr.
++- "TxVc_Mbs":
++Min Burst Size in cells.
++- "TxVc_Pcr":
++Peak Cell Rate for VBR in clock ticks between transmissions.
++- "TxVc_OamTc":
++TC Path to transmit OAM cells for TX connections (0,1).
++- "TxVc_VpOffset":
++Offset to the OAM VP state table for TX connections. Channels with the same
++VPI must have the same VpOffset value. Channels with different VPIs
++must have unique VpOffset values.
++- "RxVc_OamCh":
++Channel to which to terminate received OAM cells to be forwarded to the Host
++for either Host OAM mode, or when RxVc_OamToHost is enabled during Firmware
++OAM mode.
++- "RxVc_OamToHost":
++Indicates whether to pass received unmatched OAM loopback cells to the host;
++0=do not pass, 1=pass.
++- "RxVc_AtmHeader":
++ATM Header placed on firmware gen'd OAM cells for this channel on a Rx
++connection (must be big endian with 0 PTI).
++- "RxVc_OamTc":
++TC Path to transmit OAM cells for RX connections (0,1).
++- "RxVc_VpOffset":
++Offset to the OAM VP state table for RX connections. Channels with the same
++VPI must have the same VpOffset value. Channels with different VPIs
++must have unique VpOffset values.
++- "TxVp_OamTc":
++TC Path to transmit OAM cells for TX VP connections (0,1).
++- "TxVp_AtmHeader":
++ATM Header placed on firmware gen'd VP OAM cells for this channel on a Tx VP
++connection (must be big endian with 0 VCI).
++- "RxVp_OamCh":
++Channel to which to terminate received OAM cells to be forwarded to the Host
++for either Host OAM mode, or when RxVc_OamToHost is enabled during Firmware
++OAM mode.
++- "RxVp_OamToHost":
++Indicates whether to pass received unmatched OAM loopback cells to the host;
++0=do not pass, 1=pass.
++- "RxVp_AtmHeader":
++In firmware OAM mode, this
++is the ATM header to be appended to front of firmware generated VP OAM cells for
++this channel. Note: To generate host OAM cells, call @c Send() with
++the appropriate mode.
++- "RxVp_OamTc":
++TC Path to transmit OAM cells for RX VP connections (0,1).
++- "RxVp_OamVcList":
++This 32-bit field is one-hot encoded to indicate all the VC channels that are
++associated with this VP channel. A value of 21 will indicate that VC
++channels 0, 2, and 4 are associated with this VP channel.
++- "FwdUnkVc":
++Indicates whether or not to forward unknown VCI/VPI cells to the host. This
++parameter only takes effect if the channel's PktType is Transparent(3).
++1=forwarding enabled, 0=forwarding disabled.
++
++@section aal5_details API Implementation Details
++
++ATTENTION: Documentation given here supplements the documentation given in the general
++CPHAL API section. The following details are crucial to correct usage of the
++AAL5 CPHAL.
++
++@par Receive()
++The least significant byte of @p Mode contains the channel number. Bit 31
++indicates whether or not the ATM header is present in the first fragment of
++the packet. If bit 31 is set, the 4 byte ATM header (minus HEC) will be provided
++in the first fragment, with the payload beginning in the second fragment. Currently,
++this is the default behavior for host OAM and transparent mode packets.
++Bits 17-16 indicate the packet type that is being received.
++Mode Parameter Breakdown: <BR>
++- 31 ATM Header In First Fragment (1=true, 0=false) <BR>
++- 30-18 Unused. <BR>
++- 17-16 Pkt Type. <BR>
++ - 0=AAL5 <BR>
++ - 1=PTI Based Null AAL <BR>
++ - 2=OAM <BR>
++ - 3=Transparent <BR>
++- 15-08 Unused. <BR>
++- 07-00 Channel Number.
++
++@par Send()
++The most significant 16 bits of the first fragment 'len' is used as the Offset
++to be added to the packet. @c Send() will reserve this many bytes at the
++beginning of the transmit buffer prior to the first byte of valid data.
++For the @p Mode parameter, Bit 31 must be set if the user has sent a packet with
++the ATM Header (minus HEC) embedded in the first 4 bytes of the first fragment data buffer.
++The OS has the option of using a 4 byte first fragment containing only ATM header,
++or concatenating the ATM Header in front of the data payload.
++If Bit 31 is set, the ATM Header in the buffer is preserved and sent with
++each cell of the packet. Otherwise, Send() will build the ATM header based on the
++values of the Pti, Gfc, Clp, Vpi, and Vci parameters for the given channel.
++Bits 17-16 are defined as the packet type. Bits 15-08 may be used to specify the
++transmit queue to send the packet on. Only values 0 (high priority) and 1 (low
++priority) are accepted. Bits 07-00 should be used to indicate the channel number
++for the @c Send() operation. Valid channel numbers are 0-15.
++Mode Parameter Breakdown: <BR>
++- 31 ATM Header In Packet (1=true, 0=false) <BR>
++- 30-18 Unused. <BR>
++- 17-16 Pkt Type. <BR>
++ - 0=AAL5 <BR>
++ - 1=PTI Based Null AAL <BR>
++ - 2=OAM <BR>
++ - 3=Transparent <BR>
++- 15-08 Transmit Queue. <BR>
++- 07-00 Channel Number.
++
++@par ChannelSetup()
++The AAL5 @c ChannelSetup() always configures both the Tx and Rx side of the channel
++connection in the same call.
++
++@par ChannelTeardown()
++Regardless of the channel teardown direction selected, the AAL5 CPHAL will always
++teardown both the Tx and Rx side of the channel connection.
++
++@par TeardownComplete()
++The value for the @p Direction parameter should be ignored for the AAL5 implementation,
++since both directions (Tx and Rx) are always torndown in response to a @c ChannelTeardown()
++command.
++
++@par Control() (HAL version)
++Defined keys and actions. Unless otherwise stated, the data type
++for Value is pointer to unsigned integer. The list is broken into
++three groups, one group which can be used anytime, one group that should
++be used before halOpen(), and one group which can only be used after
++halOpen() (but before halClose()). For channelized parameters, replace
++'Ch' with the integer number of a channel (ex. "Gfc.4" can be used to set
++Gfc for channel 4).
++
++MAY USE ANYTIME AFTER INIT (after halInit() is called):
++
++- "Gfc.Ch". The OS may "Set" this value. Changing this value causes
++the Gfc in each Tx ATM header for this channel to take on the new Gfc value.
++
++- "Clp.Ch". The OS may "Set" this value. Changing this value causes
++the Clp in each Tx ATM header for this channel to take on the new Clp value.
++
++- "Pti.Ch". The OS may "Set" this value. Changing this value causes
++the Pti in each Tx ATM header for this channel to take on the new Pti value.
++
++- "CpcsUU.Ch". The OS may "Set" this value. Changing this value causes
++the CpcsUU in each Tx ATM header for this channel to take on the new CpcsUU value.
++
++- "OamMode". Specifies if host or firmware is performing OAM functions; 0 = Host OAM,
++1 = Firmware OAM. When set, all SAR channels will be configured for
++the selection, including AAL2 channels.
++
++- "OamLbTimeout". Specifies the firmware OAM loopback timeout, in milliseconds.
++
++- "DeviceCPID". The OS may "Set" this value. This is the OAM connection
++point identifier. The OS should provide a pointer to an array of 4 32-bit
++integers. Each word must be configured in big endian format.
++
++- "FwdUnkVc.Ch". Indicates whether or not to forward unknown VCI/VPI cells to the host.
++This parameter only takes effect if the channel's PktType is Transparent(3).
++1=forwarding enabled, 0=forwarding disabled.
++
++MAY USE ONLY BEFORE HAL IS OPEN (before halOpen() call):
++- "StrictPriority". The OS may "Set" this value. Setting to 1 causes
++a different interrupt processing routine to be used, which gives strict
++priority to channels with lower numbers (channel 0 has highest priority).
++The default handler gives equal priority to all channels.
++
++- "MaxFrags". The OS may "Set" or "Get" this value. This defines the maximum
++number of fragments that can be received by the AAL5 Rx port. The default
++value for AAL5 is 46. This provides enough space to receive a maximum
++length AAL5 packet (65,568 bytes) with the default buffer size of 1518 bytes, and
++any amount of RxBufferOffset. If the buffer size is configured to be smaller,
++the OS *MUST* modify this parameter according to the following formula:
++((System Max AAL5 packet length)/(RxBufSize)) + 2. (The extra two fragments in
++the formula allow for RxBufferOffset and one fragment for the ATM Header, used
++when receiving host OAM or transparent mode packets)
++
++MAY USE ONLY AFTER HAL IS 'OPEN' (after halOpen() call):
++- "Stats;Level;Ch;Queue". The OS may "Get" Stats groups with this key, where
++'Level' is an integer from 0-4, Ch is an integer from 0-15, and Queue is
++an integer from 0-1. Note that Ch is not required for Level 4 stats, and Queue
++is not required for Level 0, 3, and 4. The statistics functionality and return
++value is described in the appendix entitled "Configuration and Control".
++
++- "TxVc_CellRate.Ch". The OS may "Set" this value. Can be used to modify
++CellRate for a channel on the fly.
++
++- "TxVc_Mbs.Ch". The OS may "Set" this value. Can be used to modify
++Mbs for a channel on the fly.
++
++- "TxVc_Pcr.Ch". The OS may "Set" this value. Can be used to modify
++Pcr for a channel on the fly.
++
++- "PdspEnable". The OS may "Set" this value. Value 0 disables the PDSP.
++Value 1 enables to PDSP.
++
++- "DeviceCPID". The OS may "Set" this value. The Value should be an array
++of 4 32-bit integers that comprise the CPID.
++
++- "RxVc_RDICount.Ch". The OS may "Get" or "Set" this value. Get returns
++the current RDI count for the VC channel. Set clears the counter, and the Value
++is ignored.
++
++- "RxVp_RDICount.Ch". The OS may "Get" or "Set" this value. Get returns
++the current RDI count for the VP channel. Set clears the counter, and the Value
++is ignored.
++
++- "RxVc_AISseg.Ch". The OS may "Get" this value. This is an indication of
++AIS segment error for the VC channel.
++
++- "RxVp_AISseg.Ch". The OS may "Get" this value. This is an indication of
++AIS segment error for the VP channel.
++
++- "RxVc_AISetoe.Ch". The OS may "Get" this value. This is an indication of
++AIS end-to-end error for the VC channel.
++
++- "RxVp_AISetoe.Ch". The OS may "Get" this value. This is an indication of
++AIS end-to-end error for the VP channel.
++
++- "RxVc_OamCh.Ch". The OS may "Set" this value. Channel to which to terminate
++received OAM cells to be forwarded to the Host for either Host OAM mode, or when
++RxVc_OamToHost is enabled during Firmware OAM mode.
++
++- "RxVp_OamCh.Ch". The OS may "Set" this value. Channel to which to terminate
++received OAM cells to be forwarded to the Host for either Host OAM mode, or when
++RxVp_OamToHost is enabled during Firmware OAM mode.
++
++- "F4_LB_Counter". The OS may "Get" this value. This is a count of the number
++ of near-end F4 loopbacks performed by the PDSP in firmware OAM mode.
++
++- "F5_LB_Counter". The OS may "Get" this value. This is a count of the number
++ of near-end F5 loopbacks performed by the PDSP in firmware OAM mode.
++
++- "TxVc_AtmHeader.Ch". The OS may "Set" this value. In firmware OAM mode, this
++is the ATM header to be appended to front of firmware generated VC OAM cells for
++this channel. In host OAM mode, this is used as the ATM header to be appended
++to front of host generated VC OAM cells for this channel. It must be configured
++as big endian with PTI=0. Note: To generate host OAM cells, call @c Send() with
++the appropriate mode.
++
++- "TxVp_AtmHeader.Ch". The OS may "Set" this value. In firmware OAM mode, this
++is the ATM header to be appended to front of firmware generated VP OAM cells for
++this channel. In host OAM mode, this is used as the ATM header to be appended
++to front of host generated VP OAM cells for this channel. It must be configured
++as big endian with VCI=0. Note: To generate host OAM cells, call @c Send() with
++the appropriate mode.
++
++- "PdspEnable". The OS may "Set" this value. Controls whether or not the PDSP is
++allowed to fetch new instructions. The PDSP is enabled by the CPHAL during Open(),
++and disabled during Close(). 0 = disabled, 1 = enabled.
++
++@par Control() (OS version)
++Defined keys and actions:
++
++- "Firmware". The CPHAL will perform a "Get" action for the key "Firmware". A pointer
++to a pointer is passed in @p Value. The OS must modify the referenced pointer to point
++to the firmware.
++
++- "FirmwareSize". The CPHAL will perform a "Get" action for the key "FirmwareSize".
++The OS must place the firmware size in the memory pointed at by @p Value.
++
++- "OamLbResult". When a channel that is in firmware OAM mode is commanded to perform
++a loopback function, the result of the loopback generates an interrupt that is handled
++by the OS like any other interrupt. The CPHAL, upon servicing the interrupt, will call
++osControl with this key, and an action of "Set". The @p Value parameter will be a
++pointer to the integer result. 1 = pass, 0 = fail.
++
++- "SarFreq". The CPHAL will perform a "Get" action for this key. The OS should place
++the SAR frequency (in Hz) in the memory pointed at by @p Value.
++
++@section aal5_stats AAL5 Specific Statistics
++
++Statistics level '0' contains all AAL5 specific statistics. The following values will
++be obtained when requesting stats level 0:
++
++- "Crc Errors". Number of CRC errors reported by SAR hardware. Incremented for received
++packets that contain CRC errors.
++
++- "Len Errors". Number of length errors reported by SAR hardware. Incremented for received
++packets that are in excess of 1366 cells.
++
++- "Abort Errors". Number of abort errors reported by SAR hardware.
++
++- "Starv Errors". Number of buffer starvation errors reported by SAR hardware. Incremented
++when a part or all of a buffer cannot be received due to lack of RX buffer resources. The SAR
++drops all cells associated with the packet for each buffer starvation error that occurs.
++
++*/
++
++/* register files */
++#include "cp_sar_reg.h"
++
++#define _CPHAL_AAL5
++#define _CPHAL
++#define _CPPI_TEST /** @todo remove for release */
++#define __CPHAL_CPPI_OFFSET /* support use of offset */
++
++/* OS Data Structure definitions */
++
++typedef void OS_PRIVATE;
++typedef void OS_DEVICE;
++typedef void OS_SENDINFO;
++typedef void OS_RECEIVEINFO;
++typedef void OS_SETUP;
++
++/* CPHAL Data Structure definitions */
++
++typedef struct hal_device HAL_DEVICE;
++typedef struct hal_private HAL_PRIVATE;
++typedef struct hal_private HAL_RECEIVEINFO;
++
++/* include CPHAL header files here */
++#include "cpcommon_cpaal5.h"
++#include "cpswhal_cpaal5.h"
++#include "aal5sar.h"
++#include "cpcommon_cpaal5.c"
++
++#define CR_SERVICE (170-1)
++#define UTOPIA_PAUSE_REG (*(volatile bit32u *)0xa4000000)
++
++/*
++these masks are for the mode parameter used in halSend/OsReceive
++(may move these elsewhere)
++*/
++#define CH_MASK 0xff
++#define PRI_MASK 0x10000
++
++/* Rcb/Tcb Constants */
++#define CB_SOF_BIT (1<<31)
++#define CB_EOF_BIT (1<<30)
++#define CB_SOF_AND_EOF_BIT (CB_SOF_BIT|CB_EOF_BIT)
++#define CB_OWNERSHIP_BIT (1<<29)
++#define CB_EOQ_BIT (1<<28)
++#define CB_SIZE_MASK 0x0000ffff
++#define CB_OFFSET_MASK 0xffff0000
++#define RCB_ERRORS_MASK 0x03fe0000
++#define RX_ERROR_MASK 0x000f0000
++#define CRC_ERROR_MASK 0x00010000
++#define LENGTH_ERROR_MASK 0x00020000
++#define ABORT_ERROR_MASK 0x00040000
++#define STARV_ERROR_MASK 0x00080000
++#define TEARDOWN_VAL 0xfffffffc
++
++/* interrupt vector masks */
++#define TXH_PEND 0x01000000
++#define TXL_PEND 0x02000000
++#define RX_PEND 0x04000000
++#define STS_PEND 0x08000000
++#define AAL2_PEND 0x10000000
++#define INT_PENDING (TXH_PEND | TXL_PEND | RX_PEND | STS_PEND | AAL2_PEND)
++#define STS_PEND_INVEC 0x0001F000
++#define RX_PEND_INVEC 0x00000F00
++#define TXL_PEND_INVEC 0x000000F0
++#define TXH_PEND_INVEC 0x0000000F
++#define AIS_SEG_MASK 0x1 /* +01.02.00 */
++#define AIS_SEG_SHIFT 0 /* +01.02.00 */
++#define AIS_ETOE_MASK 0x20000 /* +01.02.00 */
++#define AIS_ETOE_SHIFT 17 /* +01.02.00 */
++#define RDI_CNT_MASK 0xffff0000 /* +01.02.00 */
++#define RDI_CNT_SHIFT 16 /* +01.02.00 */
++
++/*
++ * This function takes a vpi/vci pair and computes the 4 byte atm header
++ * (minus the HEC).
++ *
++ * @param vpi Virtual Path Identifier.
++ * @param vci Virtual Channel Identifier.
++ *
++ * @return A properly formatted ATM header, without the HEC.
++ */
++static int atmheader(int gfc, int vpi, int vci, int pti, int clp)
++ {
++ int itmp;
++
++ itmp=0;
++
++ /* UNI Mode uses the GFC field */
++ itmp |= ((gfc & 0xF) << 28);
++ itmp |= ((vpi & 0xFF) << 20);
++
++ /* if NNI Mode, no gfc and larger VPI */
++ /*itmp |= ((vpi & 0xFFF) << 20);*/
++
++ itmp|=((vci & 0xFFFF) << 4);
++ itmp|=((pti & 0x7) << 1);
++ itmp|=(clp & 0x1);
++ return(itmp);
++ }
++
++#include "cppi_cpaal5.c"
++
++/*
++ * Re-entrancy Issues
++ * In order to ensure successful re-entrancy certain sections of the
++ * CPHAL code will be bracketed as Critical.
++ * The OS will provide the function Os.CriticalSection(BOOL), which
++ * will be passed a TRUE to enter the Critical Section and FALSE to exit.
++ */
++
++/*
++ * @ingroup CPHAL_Functions
++ * Clears the statistics information.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ *
++ * @return 0 OK, Non-zero not OK
++ */
++static int StatsClear(HAL_DEVICE *HalDev)
++ {
++ int i;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]StatsClear(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* clear stats */
++ for (i=0; i<NUM_AAL5_CHAN; i++)
++ {
++ HalDev->Stats.CrcErrors[i]=0;
++ HalDev->Stats.LenErrors[i]=0;
++ HalDev->Stats.DmaLenErrors[i]=0;
++ HalDev->Stats.AbortErrors[i]=0;
++ HalDev->Stats.StarvErrors[i]=0;
++ HalDev->Stats.TxMisQCnt[i][0]=0;
++ HalDev->Stats.TxMisQCnt[i][1]=0;
++ HalDev->Stats.RxMisQCnt[i]=0;
++ HalDev->Stats.RxEOQCnt[i]=0;
++ HalDev->Stats.TxEOQCnt[i][0]=0;
++ HalDev->Stats.TxEOQCnt[i][1]=0;
++ HalDev->Stats.RxPacketsServiced[i]=0;
++ HalDev->Stats.TxPacketsServiced[i][0]=0;
++ HalDev->Stats.TxPacketsServiced[i][1]=0;
++ HalDev->Stats.TxMaxServiced[i][0]=0;
++ HalDev->Stats.TxMaxServiced[i][1]=0;
++ }
++ HalDev->Stats.RxTotal=0;
++ HalDev->Stats.TxTotal=0;
++ HalDev->Stats.RxMaxServiced=0;
++ return (EC_NO_ERRORS);
++ }
++
++/*
++ * Returns statistics information.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ *
++ * @return 0
++ */
++/*
++static STAT_INFO* StatsGet(HAL_DEVICE *HalDev)
++ {
++ STAT_INFO* MyStats = &HalDev->Stats;
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]StatsGet(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ dbgPrintf("HAL Stats:\n");
++ DispStat(HalDev, "Rx Total",MyStats->RxTotal);
++ DispStat(HalDev, "Tx Total",MyStats->TxTotal);
++ DispStat(HalDev, "Rx Peak",MyStats->RxMaxServiced);
++ DispStat(HalDev, "TxH Peak",MyStats->TxMaxServiced[0][0]);
++ DispStat(HalDev, "TxL Peak",MyStats->TxMaxServiced[0][1]);
++ DispChStat(HalDev, "CrcErr",&MyStats->CrcErrors[0],1);
++ DispChStat(HalDev, "LenErr",&MyStats->LenErrors[0],1);
++ DispChStat(HalDev, "DmaLenErr",&MyStats->DmaLenErrors[0],1);
++ DispChStat(HalDev, "AbortErr",&MyStats->AbortErrors[0],1);
++ DispChStat(HalDev, "StarvErr",&MyStats->StarvErrors[0],1);
++ DispChStat(HalDev, "TxH MisQ Cnt",&MyStats->TxMisQCnt[0][0],2);
++ DispChStat(HalDev, "TxL MisQ Cnt",&MyStats->TxMisQCnt[0][1],2);
++ DispChStat(HalDev, "Rx MisQ Cnt",&MyStats->RxMisQCnt[0],1);
++ DispChStat(HalDev, "Rx EOQ Cnt",&MyStats->RxEOQCnt[0],1);
++ DispChStat(HalDev, "TxH EOQ Cnt",&MyStats->TxEOQCnt[0][0],2);
++ DispChStat(HalDev, "TxL EOQ Cnt",&MyStats->TxEOQCnt[0][1],2);
++ DispChStat(HalDev, "Rx Pkts",&MyStats->RxPacketsServiced[0],1);
++ DispChStat(HalDev, "TxH Pkts",&MyStats->TxPacketsServiced[0][0],2);
++ DispChStat(HalDev, "TxL Pkts",&MyStats->TxPacketsServiced[0][1],2);
++
++ return (&HalDev->Stats);
++ }
++*/
++
++#ifdef __CPHAL_DEBUG
++void dbgChannelConfigDump(HAL_DEVICE *HalDev, int Ch)
++ {
++ CHANNEL_INFO *HalCh = &HalDev->ChData[Ch];
++ dbgPrintf(" [aal5 Inst %d, Ch %d] Config Dump:\n", HalDev->Inst, Ch);
++ dbgPrintf(" TxNumBuffers :%08d, TxNumQueues :%08d\n",
++ HalCh->TxNumBuffers, HalCh->TxNumQueues);
++ dbgPrintf(" RxNumBuffers :%08d, RxBufSize :%08d\n",
++ HalCh->RxNumBuffers, HalCh->RxBufSize);
++ dbgPrintf(" TxServiceMax :%08d, RxServiceMax:%08d\n",
++ HalCh->TxServiceMax, HalCh->RxServiceMax);
++ dbgPrintf(" RxBufferOffset:%08d, DaMask :%08d\n",
++ HalCh->RxBufferOffset, HalCh->DaMask);
++ dbgPrintf(" CpcsUU :%08d, Gfc :%08d\n",
++ HalCh->CpcsUU, HalCh->Gfc);
++ dbgPrintf(" Clp :%08d, Pti :%08d\n",
++ HalCh->Clp, HalCh->Pti);
++ dbgPrintf(" Priority :%08d, PktType :%08d\n",
++ HalCh->Priority, HalCh->PktType);
++ dbgPrintf(" Vci :%08d, Vpi :%08d\n",
++ HalCh->Vci, HalCh->Vpi);
++ dbgPrintf(" TxVc_CellRate :%08d, TxVc_QosType:%08d\n",
++ HalCh->TxVc_CellRate, HalCh->TxVc_QosType);
++ dbgPrintf(" TxVc_Mbs :%08d, TxVc_Pcr :%08d\n",
++ HalCh->TxVc_Mbs, HalCh->TxVc_Pcr);
++ dbgPrintf(" TxVc_AtmHeader:%08d\n",
++ HalCh->TxVc_AtmHeader);
++ osfuncSioFlush();
++ }
++#endif
++
++/*
++ * Retrieves channel parameters from configuration file. Any parameters
++ * which are not found are ignored, and the HAL default value will apply,
++ * unless a new value is given through the channel structure in the call
++ * to ChannelSetup.
++ */
++static int ChannelConfigGet(HAL_DEVICE *HalDev, CHANNEL_INFO *HalChn)
++ {
++ unsigned int Ret, Value, Ch = HalChn->Channel;
++ OS_FUNCTIONS *OsFunc = HalDev->OsFunc;
++ void *ChInfo;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]ChannelConfigGet(HalDev:%08x, HalChn:%08x)\n", (bit32u)HalDev,
++ (bit32u)HalChn);
++ osfuncSioFlush();
++ }
++#endif
++
++ Ret=OsFunc->DeviceFindParmValue(HalDev->DeviceInfo, channel_names[Ch], &ChInfo);
++ if (Ret) return (EC_AAL5|EC_FUNC_CHSETUP|EC_VAL_CH_INFO_NOT_FOUND);
++
++ /* i don't care if a value is not found because they are optional */
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "TxNumBuffers", &Value);
++ if (!Ret) HalDev->ChData[Ch].TxNumBuffers = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "TxNumQueues", &Value);
++ if (!Ret) HalDev->ChData[Ch].TxNumQueues = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "TxServiceMax", &Value);
++ if (!Ret) HalDev->ChData[Ch].TxServiceMax = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "RxNumBuffers", &Value);
++ if (!Ret) HalDev->ChData[Ch].RxNumBuffers = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "RxBufferOffset", &Value);
++ if (!Ret) HalDev->ChData[Ch].RxBufferOffset = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "RxBufSize", &Value);
++ if (!Ret) HalDev->ChData[Ch].RxBufSize = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "RxServiceMax", &Value);
++ if (!Ret) HalDev->ChData[Ch].RxServiceMax = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "CpcsUU", &Value);
++ if (!Ret) HalDev->ChData[Ch].CpcsUU = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "Gfc", &Value);
++ if (!Ret) HalDev->ChData[Ch].Gfc = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "Clp", &Value);
++ if (!Ret) HalDev->ChData[Ch].Clp = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "Pti", &Value);
++ if (!Ret) HalDev->ChData[Ch].Pti = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "DaMask", &Value);
++ if (!Ret) HalDev->ChData[Ch].DaMask = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "Priority", &Value);
++ if (!Ret) HalDev->ChData[Ch].Priority = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "PktType", &Value);
++ if (!Ret) HalDev->ChData[Ch].PktType = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "Vci", &Value);
++ if (!Ret) HalDev->ChData[Ch].Vci = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "Vpi", &Value);
++ if (!Ret) HalDev->ChData[Ch].Vpi = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "TxVc_CellRate", &Value);
++ if (!Ret) HalDev->ChData[Ch].TxVc_CellRate = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "TxVc_QosType", &Value);
++ if (!Ret) HalDev->ChData[Ch].TxVc_QosType = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "TxVc_Mbs", &Value);
++ if (!Ret) HalDev->ChData[Ch].TxVc_Mbs = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "TxVc_Pcr", &Value);
++ if (!Ret) HalDev->ChData[Ch].TxVc_Pcr = Value;
++
++ Ret=OsFunc->DeviceFindParmUint(ChInfo, "TxVc_AtmHeader", &Value);
++ if (!Ret) HalDev->ChData[Ch].TxVc_AtmHeader = Value;
++
++ return (EC_NO_ERRORS);
++ }
++
++/*
++ * Sets up channel parameters in the hardware, and initializes the CPPI
++ * TX and RX buffer descriptors and buffers.
++ */
++static int ChannelConfigApply(HAL_DEVICE *HalDev, CHANNEL_INFO *HalChn)
++ {
++ int j, Ch = HalChn->Channel;
++ volatile bit32u *pTmp;
++ int Ret; /* +GSG 030410 */
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]ChannelConfigApply(HalDev:%08x, HalChn:%08x)\n", (bit32u)HalDev,
++ (bit32u)HalChn);
++ osfuncSioFlush();
++ }
++#endif
++
++ if ((HalDev->ChIsOpen[Ch][DIRECTION_TX] == TRUE) || (HalDev->ChIsOpen[Ch][DIRECTION_RX] == TRUE))
++ {
++ return(EC_AAL5|EC_FUNC_CHSETUP|EC_VAL_CH_ALREADY_OPEN);
++ }
++
++ HalDev->InRxInt[Ch]=FALSE;
++
++ /* Initialize Queue Data */
++ HalDev->RxActQueueHead[Ch]=0;
++ HalDev->RxActQueueCount[Ch]=0;
++ HalDev->TxActQueueHead[Ch][0]=0;
++ HalDev->TxActQueueHead[Ch][1]=0;
++ HalDev->TxActQueueCount[Ch][0]=0;
++ HalDev->TxActQueueCount[Ch][1]=0;
++ HalDev->RxActive[Ch] = FALSE;
++ HalDev->TxActive[Ch][0] = FALSE;
++ HalDev->TxActive[Ch][1] = FALSE;
++
++ /* Clear Rx State RAM */
++ pTmp = pRX_DMA_STATE_WORD_0(HalDev->dev_base) + (Ch*64);
++ for (j=0; j<NUM_RX_STATE_WORDS; j++)
++ *pTmp++ = 0;
++
++ /* Check that Rx DMA State RAM was cleared */
++ pTmp -= NUM_RX_STATE_WORDS;
++ for (j=0; j<NUM_RX_STATE_WORDS; j++)
++ {
++ if (*pTmp++ != 0)
++ {
++ return(EC_AAL5|EC_FUNC_CHSETUP|EC_VAL_RX_STATE_RAM_NOT_CLEARED);
++ }
++ }
++
++ /* Clear Tx State RAM */
++ pTmp = pTX_DMA_STATE_WORD_0(HalDev->dev_base) + (Ch*64);
++ for (j=0; j<NUM_TX_STATE_WORDS; j++)
++ *pTmp++ = 0;
++
++ /* Check that Tx DMA State RAM was cleared */
++ pTmp -= NUM_TX_STATE_WORDS;
++ for (j=0; j<NUM_TX_STATE_WORDS; j++)
++ {
++ if (*pTmp++ != 0)
++ {
++ return(EC_AAL5|EC_FUNC_CHSETUP|EC_VAL_TX_STATE_RAM_NOT_CLEARED);
++ }
++ }
++
++ /* Initialize Tx State RAM (Nothing to do) */
++
++ /* Initialize Rx State RAM */
++ /* Configure the Rx buffer offset */
++ pTmp=(pRX_DMA_STATE_WORD_0(HalDev->dev_base) + (Ch*64));
++ *pTmp |= (HalDev->ChData[Ch].RxBufferOffset & 0xFF);
++
++ /* Initialize buffer memory for the channel */
++ Ret = InitTcb(HalDev, Ch);
++ if (Ret) return (Ret);
++
++ Ret = InitRcb(HalDev, Ch);
++ if (Ret) return (Ret);
++
++ /* setup interrupt mask/enable for the channel */
++ SAR_TX_MASK_SET(HalDev->dev_base) = (1<<Ch);
++
++ /* if using the low priority queue, set up mask for it */
++ if (HalDev->ChData[Ch].TxNumQueues == 2) /* +GSG 030421 */
++ SAR_TX_MASK_SET(HalDev->dev_base) = (1<<Ch)<<16; /* +GSG 030421 */
++
++ SAR_RX_MASK_SET(HalDev->dev_base) = (1<<Ch);
++
++ /* call SAR layer to complete the channel setup - hardware configuration of ch */
++ Ret = HalDev->SarFunc->ChannelSetup(HalDev->SarDev, &HalDev->ChData[Ch]); /* ~GSG 030410 */
++ if (Ret) /* +GSG 030410 */
++ return (Ret); /* +GSG 030410 */
++
++ /* channel officially open for business */
++ HalDev->ChIsOpen[Ch][DIRECTION_TX] = TRUE;
++ HalDev->ChIsOpen[Ch][DIRECTION_RX] = TRUE;
++
++ return (EC_NO_ERRORS);
++ }
++
++/*
++ * Sets up HAL default channel configuration parameter values.
++ */
++static void ChannelConfigInit(HAL_DEVICE *HalDev, CHANNEL_INFO *HalChn)
++ {
++ int Ch = HalChn->Channel;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]ChannelConfigInit(HalDev:%08x, HalChn:%08x)\n", (bit32u)HalDev,
++ (bit32u)HalChn);
++ osfuncSioFlush();
++ }
++#endif
++
++ HalDev->ChData[Ch].Channel = Ch;
++ HalDev->ChData[Ch].TxNumBuffers = cfg_tx_num_bufs[Ch];
++ HalDev->ChData[Ch].RxNumBuffers = cfg_rx_num_bufs[Ch];
++ HalDev->ChData[Ch].RxBufSize = cfg_rx_buf_size[Ch];
++ HalDev->ChData[Ch].RxBufferOffset = cfg_rx_buf_offset[Ch];
++ HalDev->ChData[Ch].TxNumQueues = cfg_tx_num_queues[Ch];
++ HalDev->ChData[Ch].CpcsUU = cfg_cpcs_uu[Ch];
++ HalDev->ChData[Ch].DaMask = cfg_da_mask[Ch];
++ HalDev->ChData[Ch].Priority = cfg_priority[Ch];
++ HalDev->ChData[Ch].PktType = cfg_pkt_type[Ch];
++ HalDev->ChData[Ch].Vci = cfg_vci[Ch];
++ HalDev->ChData[Ch].Vpi = cfg_vpi[Ch];
++ HalDev->ChData[Ch].TxVc_CellRate = cfg_cell_rate[Ch];
++ HalDev->ChData[Ch].TxVc_QosType = cfg_qos_type[Ch];
++ HalDev->ChData[Ch].TxVc_Mbs = cfg_mbs[Ch];
++ HalDev->ChData[Ch].TxVc_Pcr = cfg_pcr[Ch];
++ HalDev->ChData[Ch].Gfc = cfg_gfc[Ch];
++ HalDev->ChData[Ch].Clp = cfg_clp[Ch];
++ HalDev->ChData[Ch].Pti = cfg_pti[Ch];
++ HalDev->ChData[Ch].RxServiceMax = cfg_rx_max_service[Ch];
++ HalDev->ChData[Ch].TxServiceMax = cfg_tx_max_service[Ch];
++ }
++
++/*
++ * Update per channel data in the HalDev based channel structure.
++ * If a certain channel parameter has been passed with the HAL_DEFAULT
++ * value (0xFFFFFFFF), then do not copy it.
++ */
++static void ChannelConfigUpdate(HAL_DEVICE *HalDev, CHANNEL_INFO *HalChn)
++ {
++ int Ch = HalChn->Channel;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]ChannelConfigUpdate(HalDev:%08x, HalChn:%08x)\n", (bit32u)HalDev,
++ (bit32u)HalChn);
++ osfuncSioFlush();
++ }
++#endif
++
++ HalDev->ChData[Ch].Channel = Ch;
++
++ /* ChannelUpdate is a macro defined in cpcommon.h. It requires
++ the presence of the variables named 'Ch' and 'HalChn'.*/
++ ChannelUpdate(DaMask);
++ ChannelUpdate(Priority);
++ ChannelUpdate(PktType);
++ ChannelUpdate(Vci);
++ ChannelUpdate(Vpi);
++ ChannelUpdate(CpcsUU);
++ ChannelUpdate(Gfc);
++ ChannelUpdate(Clp);
++ ChannelUpdate(Pti);
++ /* AAL5 Stuff */
++ ChannelUpdate(TxNumBuffers);
++ ChannelUpdate(RxNumBuffers);
++ ChannelUpdate(RxBufSize);
++ ChannelUpdate(RxBufferOffset);
++ ChannelUpdate(TxNumQueues);
++ ChannelUpdate(TxServiceMax);
++ ChannelUpdate(RxServiceMax);
++ /* PDSP STATE RAM */
++ ChannelUpdate(TxVc_CellRate);
++ ChannelUpdate(TxVc_QosType);
++ ChannelUpdate(TxVc_Mbs);
++ ChannelUpdate(TxVc_Pcr);
++ /* OAM */
++ ChannelUpdate(TxVc_AtmHeader);
++ ChannelUpdate(TxVc_OamTc);
++ ChannelUpdate(TxVc_VpOffset);
++ ChannelUpdate(RxVc_OamCh);
++ ChannelUpdate(RxVc_OamToHost);
++ ChannelUpdate(RxVc_AtmHeader);
++ ChannelUpdate(RxVc_VpOffset);
++ ChannelUpdate(RxVc_OamTc);
++ ChannelUpdate(TxVp_AtmHeader);
++ ChannelUpdate(TxVp_OamTc);
++ ChannelUpdate(RxVp_AtmHeader);
++ ChannelUpdate(RxVp_OamCh);
++ ChannelUpdate(RxVp_OamTc);
++ ChannelUpdate(RxVp_OamToHost);
++ ChannelUpdate(RxVp_OamVcList);
++ ChannelUpdate(FwdUnkVc);
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * This function opens the specified channel. The caller must populate
++ * the @p HalCh structure. CPHAL default values may be requested for any or all
++ * members of the @p HalCh structure by supplying a value of 0xFFFFFFFF for the
++ * given member. The @p OsSetup parameter is a pointer to an OS defined
++ * data structure. If the CPHAL later calls @c MallocRxBuffer(), this pointer
++ * is returned in that call.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param HalCh Per channel information structure. Implementation specific.
++ * @param OsSetup Pointer to an OS-defined data structure.
++ *
++ * @return EC_NO_ERRORS (ok). <BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_INVALID_STATE "EC_VAL_INVALID_STATE"<BR>
++ * @ref EC_VAL_NULL_CH_STRUCT "EC_VAL_NULL_CH_STRUCT"<BR>
++ * @ref EC_VAL_INVALID_CH "EC_VAL_INVALID_CH"<BR>
++ * @ref EC_VAL_CH_ALREADY_OPEN "EC_VAL_CH_ALREADY_OPEN"<BR>
++ * @ref EC_VAL_RX_STATE_RAM_NOT_CLEARED "EC_VAL_RX_STATE_RAM_NOT_CLEARED"<BR>
++ * @ref EC_VAL_TX_STATE_RAM_NOT_CLEARED "EC_VAL_TX_STATE_RAM_NOT_CLEARED"<BR>
++ * @ref EC_VAL_TCB_MALLOC_FAILED "EC_VAL_TCB_MALLOC_FAILED"<BR>
++ * @ref EC_VAL_RCB_MALLOC_FAILED "EC_VAL_RCB_MALLOC_FAILED"<BR>
++ * @ref EC_VAL_RX_BUFFER_MALLOC_FAILED "EC_VAL_RX_BUFFER_MALLOC_FAILED"<BR>
++ * @ref EC_VAL_LUT_NOT_READY "EC_VAL_LUT_NOT_READY"<BR>
++ */
++static int halChannelSetup(HAL_DEVICE *HalDev, CHANNEL_INFO *HalCh, OS_SETUP *OsSetup)
++ {
++ int Ch, Ret;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]halChannelSetup(HalDev:%08x, HalCh:%08x, OsSetup:%08x)\n", (bit32u)HalDev,
++ (bit32u)HalCh, (bit32u)OsSetup);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Verify proper device state */
++ if (HalDev->State < enInitialized)
++ return (EC_AAL5|EC_FUNC_CHSETUP|EC_VAL_INVALID_STATE);
++
++ /* We require the channel structure to be passed, even if it only contains
++ the channel number */
++ if (HalCh == NULL)
++ {
++ return(EC_AAL5|EC_FUNC_CHSETUP|EC_VAL_NULL_CH_STRUCT);
++ }
++
++ Ch = HalCh->Channel;
++
++ if ((Ch < 0) || (Ch > MAX_AAL5_CHAN))
++ {
++ return(EC_AAL5|EC_FUNC_CHSETUP|EC_VAL_INVALID_CH);
++ }
++
++ /* if channel is already open, this call is invalid */
++ if ((HalDev->ChIsOpen[Ch][DIRECTION_TX] == TRUE) || (HalDev->ChIsOpen[Ch][DIRECTION_RX] == TRUE))
++ {
++ return(EC_AAL5|EC_FUNC_CHSETUP|EC_VAL_CH_ALREADY_OPEN);
++ }
++
++ /* channel is closed, but might be setup. If so, reopen the hardware channel. */
++ if ((HalDev->ChIsSetup[Ch][DIRECTION_TX] == FALSE) && (HalDev->ChIsSetup[Ch][DIRECTION_RX] == FALSE))
++ {
++ /* Setup channel configuration */
++ /* Store OS_SETUP */
++ HalDev->ChData[Ch].OsSetup = OsSetup; /* ~GSG 030508 */
++
++ /* setup HAL default values for this channel first */
++ ChannelConfigInit(HalDev, HalCh);
++
++ /* retrieve options.conf channel parameters */
++ /* currently ignoring return value, making the choice that it's okay if
++ the user does not supply channel configuration in the data store */
++ ChannelConfigGet(HalDev, HalCh);
++
++ /* update HalDev with data given in HalCh */
++ ChannelConfigUpdate(HalDev, HalCh);
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(8))
++ {
++ dbgChannelConfigDump(HalDev, Ch);
++ }
++#endif
++
++ /* HalDev->ChIsSetup[Ch][0] = TRUE; */
++ HalDev->ChIsSetup[Ch][DIRECTION_TX] = TRUE;
++ HalDev->ChIsSetup[Ch][DIRECTION_RX] = TRUE;
++
++ /* I don't initialize RcbStart or TcbStart here because their values may be
++ reused across several Setup/Teardown calls */
++ }
++
++ /* If the hardware has been opened (is out of reset), then configure the channel
++ in the hardware. NOTE: ChannelConfigApply calls the CPSAR ChannelSetup()! */
++ if (HalDev->State == enOpened)
++ {
++ Ret = ChannelConfigApply(HalDev, HalCh);
++ if (Ret) return (Ret);
++ }
++
++ return (EC_NO_ERRORS);
++ }
++
++/*
++ * This function configures the rate at which the OAM timer scheduler
++ * channels will be scheduled. The value of OamRate is the number of
++ * clock ticks between cell transmissions (if OAM function is sourcing
++ * cells), or the number of clock ticks between events or absence of events
++ * (if OAM function is sinking cells). The value of i indicates
++ * which OAM function to apply the rate to. A list is given below.
++ *
++ * @par Oam Function Values
++ * - 0 : Loopback source
++ * - 1 : F4 CC source
++ * - 2 : F5 CC source
++ * - 3 : F4 CC sink
++ * - 4 : F5 CC sink
++ * - 5 : F4 TX AIS source
++ * - 6 : F5 TX AIS source
++ * - 7 : F4 RX RDI source
++ * - 8 : F5 RX RDI source
++ * - 9 : F4 AIS monitor
++ * - 10 : F5 AIS monitor
++ *
++ * The following is information on how to calculate the OAM rate. There
++ * is only one OAM timer that is shared among all channels. Therefore, if
++ * you wanted an OAM source function (ex. F4 CC source) to generate 1 cell/sec
++ * across 8 channels, you would need to configure the OAM timer to schedule 8
++ * cells/sec. In addition, the credits are shared between segment and end-to-end
++ * type OAM cells, so if you were sending both types of cells, you would
++ * need to configure the OAM timer for 16 cells/sec. However, the clock
++ * rate must be specified in clock ticks between events. Using an example
++ * clock rate of 125 MHz, the rate in clock ticks can be calculated by
++ * dividing 125 Mhz by 16 cells/sec. The results is 7812500 ticks. Thus,
++ * every 7812500 clock cycles, an OAM cell will be generated for the F4 CC
++ * Source function.
++ */
++static void OamRateConfig(HAL_DEVICE *HalDev)
++ {
++ int i;
++ bit32u OamRate, Freq = HalDev->SarFrequency;
++
++ /* Configure OAM Timer State Block */
++ for (i=0; i<NUM_OAM_RATES; i++)
++ {
++ switch(i)
++ {
++ case 0: OamRate = ((Freq/1000)*HalDev->OamLbTimeout);
++ break;
++ case 1:
++ case 2:
++ case 5:
++ case 6:
++ case 7:
++ case 8: OamRate = (Freq/38);
++ break;
++ case 3:
++ case 4: OamRate = ((Freq*3) + (Freq/2))/38;
++ break;
++ case 9:
++ case 10: OamRate = ((Freq*2) + (Freq/2))/38;
++ break;
++ default: OamRate = (Freq*5);
++ break;
++ }
++
++ *(pOAM_TIMER_STATE_WORD_0(HalDev->dev_base) + (i*64) + 1) = OamRate;
++ }
++ }
++
++/**
++ * @ingroup AAL5_Functions
++ * This function is used to enable OAM functions (other than loopback) for a
++ * particular channel. The channel (embedded within OamConfig - see below) must
++ * have been configured for firmware OAM (not host OAM) for these configurations
++ * to take effect. More than one function may be enabled at one time.
++ * If more than one function is enabled, they must all be of the same level, all
++ * F4(VP) or all F5(VC).
++ *
++ * The usage of the OamConfig parameter is described through the table below. To
++ * initiate firmware OAM, set one or more bits in OamConfig corresponding to the
++ * various OAM functions. To disable firmware OAM functions, set bit 30 along
++ * with any other combination of bits to shutdown various OAM functions at once.
++ *
++ * Acronyms:
++ * e2e - end to end, seg - segment, CC - continuity check,
++ * AIS - Alarm Indication Signal
++ *
++ * @par Bit: Function: Description
++ * - 31: Reserved:
++ * - 30: Setup/Teardown: 0 - enable, 1 - disable (Note 1)
++ * - 29: F4 CC Source seg: 0 - no action, 1 - configure
++ * - 28: F4 CC Source e2e: 0 - no action, 1 - configure
++ * - 27: F4 AIS Source seg: 0 - no action, 1 - configure
++ * - 26: F4 AIS Source e2e: 0 - no action, 1 - configure
++ * - 25: F5 CC Source seg: 0 - no action, 1 - configure
++ * - 24: F5 CC Source e2e: 0 - no action, 1 - configure
++ * - 23: F5 AIS Source seg: 0 - no action, 1 - configure
++ * - 22: F5 AIS Source e2e: 0 - no action, 1 - configure
++ * - 21: F4 CC Sink seg: 0 - no action, 1 - configure
++ * - 20: F4 CC Sink e2e: 0 - no action, 1 - configure
++ * - 19: F5 CC Sink seg: 0 - no action, 1 - configure
++ * - 18: F5 CC Sink e2e: 0 - no action, 1 - configure
++ * - 17:8: Reserved:
++ * - 7:0: Channel: AAL5/AAL2 VC/VP channel (Note 2)
++ *
++ *
++ * Note 1: This bit must be clear to enable the specified OAM function.
++ * Note 2: This must specify the VC channel for F5 functions, and the VP
++ * channel for F4 functions.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param OamConfig A 32-bit integer field defined as follows:
++ */
++static void halOamFuncConfig(HAL_DEVICE *HalDev, unsigned int OamConfig)
++ {
++ /* GPR 0 */
++ SAR_PDSP_HOST_OAM_CONFIG_REG(HalDev->dev_base) = OamConfig;
++ }
++
++/**
++ * @ingroup AAL5_Functions
++ * This function is used to enable OAM loopback functions for a particular
++ * channel. The channel (embedded within OamConfig - see below) must have been
++ * configured for firmware OAM (not host OAM) for these configurations to take
++ * effect. Only one loopback function can be enabled at a time.
++ *
++ * The LLID is inserted into to the OAM cell's LLID field, and it specifies the
++ * LLID of the connection point in the network where the generated loopback cell
++ * should be turned around. The LLID is composed of 4 32-bit words, and this
++ * function expects the caller to pass an array of 4 words in the LLID field.
++ * The CorrelationTag is a 32-bit word that the PDSP uses to correlate loopback
++ * commands with loopback responses. It should simply be changed for each
++ * call, and there is no restriction on the value used for CorrelationTag.
++ *
++ * The usage of the OamConfig parameter is described through the table below. To
++ * initiate firmware OAM, set one of the bits corresponding to the
++ * various loopback OAM functions. Note that only one loopback source may be
++ * commanded at a time.
++ *
++ * Acronyms:
++ * e2e - end to end, seg - segment, LB - loopback
++ *
++ * @par Bit: Function: Description
++ * - 31:16: Reserved:
++ * - 15: F4 LB Source seg: 0 - no action, 1 - configure (Note 1)
++ * - 14: F4 LB Source seg: 0 - no action, 1 - configure (Note 1)
++ * - 13: F4 LB Source e2e: 0 - no action, 1 - configure (Note 1)
++ * - 12: F4 LB Source e2e: 0 - no action, 1 - configure (Note 1)
++ * - 11:8: Reserved:
++ * - 7:0: Channel: AAL5/AAL2 VC/VP channel (Note 2)
++ *
++ *
++ * Note 1: Only one LB function may be enabled at one time. Once enabled,
++ * the PDSP will time out after 5 seconds. The host must wait until it
++ * has received the result of the current LB request before initiating
++ * a new request. <BR>
++ * Note 2: This must specify the VC channel for F5 functions, and the VP
++ * channel for F4 functions.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param OamConfig A 32-bit integer field defined as follows:
++ * @param LLID Loopback Location Identifier (passed as 4 word array).
++ * Must be configured in big endian format.
++ * @param CorrelationTag 32-bit tag correlates loopback commands with loopback
++ * responses. Must be configured in big endian format.
++ *
++ */
++static void halOamLoopbackConfig(HAL_DEVICE *HalDev, unsigned int OamConfig, unsigned int *LLID, unsigned int CorrelationTag)
++ {
++ volatile bit32u *tmp;
++
++ /* test to see if this is a loopback command */
++ if (OamConfig & 0xf000)
++ {
++ /* write the OAM correlation tag (GPR 1) */
++ SAR_PDSP_OAM_CORR_REG(HalDev->dev_base) = CorrelationTag;
++
++ /* write the LLID */
++ tmp = pOAM_CONFIG_BLOCK_WORD_0(HalDev->dev_base);
++
++ /* advance past the CPID */
++ tmp += 4;
++
++ *tmp++ = LLID[0];
++ *tmp++ = LLID[1];
++ *tmp++ = LLID[2];
++ *tmp = LLID[3];
++
++ /* GPR 0 */
++ SAR_PDSP_HOST_OAM_CONFIG_REG(HalDev->dev_base) = OamConfig;
++ }
++ }
++
++/*
++ * This function allows the host software to access any register directly.
++ * Primarily used for debug.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param RegOffset Hexadecimal offset to desired register (from device base addr)
++ *
++ * @return Volatile pointer to desired register.
++ */
++static volatile bit32u* halRegAccess(HAL_DEVICE *HalDev, bit32u RegOffset)
++ {
++ /* compute the register address */
++ return ((volatile bit32u *)(HalDev->dev_base + RegOffset));
++ }
++
++#ifdef __CPHAL_DEBUG
++static void dbgConfigDump(HAL_DEVICE *HalDev)
++ {
++ dbgPrintf(" AAL5 Inst %d Config Dump:\n", HalDev->Inst);
++ dbgPrintf(" Base :%08x, offset:%08d\n",
++ HalDev->dev_base, HalDev->offset);
++ dbgPrintf(" Interrupt:%08d, debug :%08d\n",
++ HalDev->interrupt, HalDev->debug);
++ osfuncSioFlush();
++ }
++#endif
++
++/**
++ * @ingroup CPHAL_Functions
++ * Performs a variety of control functions on the CPHAL module. It is used to
++ * modify/read configuration parameters and to initiate internal functions.
++ * The @p Key indicates the function to perform or the parameter to access (note
++ * that these Keys are identical to those used in accessing the configuration data
++ * store). @p Action is applicable to parameters only, and indicates what the
++ * CPHAL should do with the parameter (i.e. "Set", "Get", etc..). The actions
++ * for each parameter are defined in the module specific documentation.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param Key Key specifying the parameter to change or internal function to initiate. See module specific documentation for available keys.
++ * @param Action Specifies the action to take. See module specific documentation for available actions.
++ * @param Value Pointer to new value for given @p Key parameter ("Set"), or returned value of Key ("Get").
++ *
++ * @return EC_NO_ERRORS (ok).<BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_INVALID_STATE "EC_VAL_INVALID_STATE"<BR>
++ * @ref EC_VAL_KEY_NOT_FOUND "EC_VAL_KEY_NOT_FOUND"<BR>
++ * @ref EC_VAL_ACTION_NOT_FOUND "EC_VAL_ACTION_NOT_FOUND"<BR>
++ */
++static int halControl(HAL_DEVICE *HalDev, const char *Key, const char *Action, void *Value)
++ {
++ int Level, Ch, KeyFound=0, ActionFound=0, rc=EC_NO_ERRORS, Queue;
++ char *TmpKey = (char *)Key;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]halControl(HalDev:%08x, Key:%s, Action:%s, Value:%08x)\n", (bit32u)HalDev,
++ Key, Action, (bit32u)Value);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Verify proper device state */
++ if (HalDev->State < enInitialized)
++ return (EC_AAL5|EC_FUNC_CONTROL|EC_VAL_INVALID_STATE);
++
++ if (HalDev->OsFunc->Strcmpi(Key, "Debug") == 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++ HalDev->debug = *(int *)Value;
++ /* also setup debug variable in CPSAR module */
++ rc = HalDev->SarFunc->Control(HalDev->SarDev, "Debug", "Set", Value);
++ }
++ }
++
++ if (HalDev->OsFunc->Strstr(Key, "FwdUnkVc.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("FwdUnkVc.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ HalDev->ChData[Ch].FwdUnkVc = *(int *)Value;
++
++ if ((HalDev->State == enOpened) && (HalDev->ChData[Ch].PktType == 3))
++ rc = HalDev->SarFunc->Control(HalDev->SarDev, Key, Action, Value);
++ }
++ }
++
++ /* +GSG 030407 */
++ if (HalDev->OsFunc->Strcmpi(Key, "OamMode") == 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++ rc = HalDev->SarFunc->Control(HalDev->SarDev, Key, Action, Value);
++ }
++
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ {
++ ActionFound=1;
++ rc = HalDev->SarFunc->Control(HalDev->SarDev, Key, Action, Value);
++ }
++ }
++
++ /* +GSG 030307 */
++ if (HalDev->OsFunc->Strcmpi(Key, "Version") == 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ {
++ ActionFound=1;
++ *(const char **)Value = pszVersion_CPAAL5;
++ }
++ }
++
++ /* +GSG 030529 */
++ if (HalDev->OsFunc->Strcmpi(Key, "TurboDslErrors") == 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ {
++ ActionFound=1;
++ *(int *)Value = HalDev->TurboDslErrors;
++ }
++ }
++
++ /* +GSG 030416 */
++ if (HalDev->OsFunc->Strcmpi(Key, "F4_LB_Counter") == 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ {
++ ActionFound=1;
++ *(int *)Value = SAR_PDSP_OAM_F4_LB_COUNT_REG(HalDev->dev_base);
++ }
++ }
++
++ /* +GSG 030416 */
++ if (HalDev->OsFunc->Strcmpi(Key, "F5_LB_Counter") == 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ {
++ ActionFound=1;
++ *(int *)Value = SAR_PDSP_OAM_F5_LB_COUNT_REG(HalDev->dev_base);
++ }
++ }
++
++ if (HalDev->OsFunc->Strstr(Key, "Stats;") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ {
++ ActionFound=1;
++ TmpKey += HalDev->OsFunc->Strlen("Stats;");
++ Level = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++ TmpKey++;
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++ TmpKey++;
++ Queue = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++ TmpKey++;
++ StatsGet(HalDev, (void **)Value, Level, Ch, Queue);
++ }
++ }
++
++ /* +GSG 030306 */
++ /* Fixes PITS #100 */
++ if (HalDev->OsFunc->Strstr(Key, "Gfc.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("Gfc.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* first, store new value in our channel structure */
++ HalDev->ChData[Ch].Gfc = *(int *)Value;
++ }
++ }
++
++ /* +GSG 030306 */
++ /* Fixes PITS #100 */
++ if (HalDev->OsFunc->Strstr(Key, "Clp.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("Clp.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* first, store new value in our channel structure */
++ HalDev->ChData[Ch].Clp = *(int *)Value;
++ }
++ }
++
++ /* +GSG 030306 */
++ /* Fixes PITS #100 */
++ if (HalDev->OsFunc->Strstr(Key, "Pti.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("Pti.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* first, store new value in our channel structure */
++ HalDev->ChData[Ch].Pti = *(int *)Value;
++ }
++ }
++
++ /* +GSG 030306 */
++ /* Fixes PITS #100 */
++ if (HalDev->OsFunc->Strstr(Key, "CpcsUU.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("CpcsUU.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* first, store new value in our channel structure */
++ HalDev->ChData[Ch].CpcsUU = *(int *)Value;
++ }
++ }
++
++ /* +GSG 030306 */
++ /* Fixes PITS #100 */
++ if (HalDev->OsFunc->Strstr(Key, "TxVc_CellRate.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("TxVc_CellRate.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* first, store new value in our channel structure */
++ HalDev->ChData[Ch].TxVc_CellRate = *(int *)Value;
++
++ /* now, apply to PDSP state RAM */
++ if (HalDev->State == enOpened)
++ *(pPDSP_AAL5_TX_STATE_WORD_0(HalDev->dev_base)+(Ch*64))= HalDev->ChData[Ch].TxVc_CellRate;
++ }
++ }
++
++ /* +GSG 030306 */
++ /* Fixes PITS #100 */
++ if (HalDev->OsFunc->Strstr(Key, "TxVc_Mbs.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("TxVc_Mbs.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* first, store new value in our channel structure */
++ HalDev->ChData[Ch].TxVc_Mbs = *(int *)Value;
++
++ /* now, apply to PDSP state RAM */
++ if (HalDev->State == enOpened)
++ *(pPDSP_AAL5_TX_STATE_WORD_0(HalDev->dev_base)+(Ch*64)+2)= HalDev->ChData[Ch].TxVc_Mbs;
++ }
++ }
++
++ if (HalDev->OsFunc->Strstr(Key, "TxVc_AtmHeader.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("TxVc_AtmHeader.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* first, store new value in our channel structure */
++ HalDev->ChData[Ch].TxVc_AtmHeader = *(int *)Value;
++
++ /* now, apply to PDSP state RAM */
++ if (HalDev->State == enOpened)
++ *(pPDSP_AAL5_TX_STATE_WORD_0(HalDev->dev_base)+(Ch*64)+6)= HalDev->ChData[Ch].TxVc_AtmHeader;
++ }
++ }
++
++ if (HalDev->OsFunc->Strstr(Key, "TxVp_AtmHeader.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("TxVp_AtmHeader.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* first, store new value in our channel structure */
++ HalDev->ChData[Ch].TxVp_AtmHeader = *(int *)Value;
++
++ /* now, apply to PDSP state RAM */
++ if (HalDev->State == enOpened)
++ *(pPDSP_AAL5_TX_VP_STATE_WORD_0(HalDev->dev_base)+(Ch*64))= HalDev->ChData[Ch].TxVp_AtmHeader;
++ }
++ }
++
++ /* +GSG 030306 */
++ /* Fixes PITS #100 */
++ if (HalDev->OsFunc->Strstr(Key, "TxVc_Pcr.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("TxVc_Pcr.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* first, store new value in our channel structure */
++ HalDev->ChData[Ch].TxVc_Pcr = *(int *)Value;
++
++ /* now, apply to PDSP state RAM */
++ if (HalDev->State == enOpened)
++ *(pPDSP_AAL5_TX_STATE_WORD_0(HalDev->dev_base)+(Ch*64)+4)= HalDev->ChData[Ch].TxVc_Pcr;
++ }
++ }
++
++ /* +GSG 030428 */
++ if (HalDev->OsFunc->Strstr(Key, "RxVc_OamCh.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("RxVc_OamCh.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* first, store new value in our channel structure */
++ HalDev->ChData[Ch].RxVc_OamCh = (*(int *)Value) & 0xff;
++
++ /* now, apply to PDSP state RAM */
++ if (HalDev->State == enOpened)
++ *(pPDSP_AAL5_RX_STATE_WORD_0(HalDev->dev_base)+(Ch*64)) |= HalDev->ChData[Ch].RxVc_OamCh;
++ }
++ }
++
++ /* +GSG 030428 */
++ if (HalDev->OsFunc->Strstr(Key, "RxVp_OamCh.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("RxVp_OamCh.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* first, store new value in our channel structure */
++ HalDev->ChData[Ch].RxVp_OamCh = (*(int *)Value) & 0xff;
++
++ /* now, apply to PDSP state RAM */
++ if (HalDev->State == enOpened)
++ *(pPDSP_AAL5_RX_VP_STATE_WORD_0(HalDev->dev_base)+(Ch*64)+1) |= HalDev->ChData[Ch].RxVp_OamCh;
++ }
++ }
++
++ /* +GSG 030304 */
++ /* Fixes PITS #98 */
++ if (HalDev->OsFunc->Strstr(Key, "PdspEnable") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++
++ /* this variable is controlled by the CPSAR module */
++ if (HalDev->State == enOpened)
++ {
++ rc=HalDev->SarFunc->Control(HalDev->SarDev, "PdspEnable", "Set", Value);
++ }
++ }
++ }
++
++ if (HalDev->OsFunc->Strstr(Key, "OamLbTimeout") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++
++ HalDev->OamLbTimeout = *(int *)Value;
++ /* this variable is controlled by the CPSAR module */
++ if (HalDev->State == enOpened)
++ {
++ *(pOAM_TIMER_STATE_WORD_0(HalDev->dev_base) + 1) =
++ ((HalDev->SarFrequency/1000) * HalDev->OamLbTimeout);
++ }
++ }
++ }
++
++ /* +GSG 030306 (PITS #114) */
++ if (HalDev->OsFunc->Strstr(Key, "DeviceCPID") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ unsigned int* local = (unsigned int *)Value;
++ ActionFound=1;
++ /* first, store new value in our hal structure */
++ HalDev->DeviceCPID[0] = local[0];
++ HalDev->DeviceCPID[1] = local[1];
++ HalDev->DeviceCPID[2] = local[2];
++ HalDev->DeviceCPID[3] = local[3];
++
++ /* now, apply to PDSP state RAM */
++ if (HalDev->State == enOpened)
++ {
++ *(bit32u *)(pOAM_CONFIG_BLOCK_WORD_0(HalDev->dev_base) + 0) = HalDev->DeviceCPID[0];
++ *(bit32u *)(pOAM_CONFIG_BLOCK_WORD_0(HalDev->dev_base) + 1) = HalDev->DeviceCPID[1];
++ *(bit32u *)(pOAM_CONFIG_BLOCK_WORD_0(HalDev->dev_base) + 2) = HalDev->DeviceCPID[2];
++ *(bit32u *)(pOAM_CONFIG_BLOCK_WORD_0(HalDev->dev_base) + 3) = HalDev->DeviceCPID[3];
++ }
++ }
++ }
++
++ /* +GSG 030304 */
++ /* Fixes PITS #99 */
++ if (HalDev->OsFunc->Strstr(Key, "StrictPriority") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++
++ /* used in halOpen to decide which interrupt handler to use */
++ HalDev->StrictPriority = *(int *)Value;
++ }
++ }
++
++ if (HalDev->OsFunc->Strstr(Key, hcMaxFrags) != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++
++ if ((*(int *)Value) > 0)
++ HalDev->MaxFrags = *(int *)Value;
++ else
++ rc = (EC_AAL5|EC_FUNC_CONTROL|EC_VAL_INVALID_VALUE);
++ }
++
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ {
++ ActionFound=1;
++
++ *(int *)Value = HalDev->MaxFrags;
++ }
++ }
++
++ /* +GSG 030306 */
++ /* Fixes PITS #103 */
++ if (HalDev->OsFunc->Strstr(Key, "RxVc_RDICount.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ {
++ ActionFound=1;
++
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("RxVc_RDICount.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* PDSP's Rx VC State word 3 contains the value */
++ if (HalDev->State == enOpened)
++ {
++ *(int *)Value = (((*(pPDSP_AAL5_RX_STATE_WORD_0(HalDev->dev_base)+(Ch*64))) & RDI_CNT_MASK)>>RDI_CNT_SHIFT);
++ }
++ }
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("RxVc_RDICount.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* All sets write 0, this action is a clear only */
++ if (HalDev->State == enOpened)
++ {
++ (*(pPDSP_AAL5_RX_STATE_WORD_0(HalDev->dev_base)+(Ch*64))) &=~ RDI_CNT_MASK;
++ }
++ }
++ }
++
++ /* +GSG 030306 */
++ /* Fixes PITS #103 */
++ if (HalDev->OsFunc->Strstr(Key, "RxVc_AISseg.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ {
++ ActionFound=1;
++
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("RxVc_AISseg.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* PDSP's Rx VC State word 3 contains the value */
++ if (HalDev->State == enOpened)
++ {
++ *(int *)Value = (((*(pPDSP_AAL5_RX_STATE_WORD_0(HalDev->dev_base)+(Ch*64)+3)) & AIS_SEG_MASK)>>AIS_SEG_SHIFT);
++ }
++ }
++ }
++
++ /* +GSG 030306 */
++ /* Fixes PITS #103 */
++ if (HalDev->OsFunc->Strstr(Key, "RxVc_AISetoe.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ {
++ ActionFound=1;
++
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("RxVc_AISetoe.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* PDSP's Rx VC State word 3 contains the value */
++ if (HalDev->State == enOpened)
++ {
++ *(int *)Value = (((*(pPDSP_AAL5_RX_STATE_WORD_0(HalDev->dev_base)+(Ch*64)+3)) & AIS_ETOE_MASK)>>AIS_ETOE_SHIFT);
++ }
++ }
++ }
++
++ /* +GSG 030306 */
++ /* Fixes PITS #103 */
++ if (HalDev->OsFunc->Strstr(Key, "RxVp_RDICount.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ {
++ ActionFound=1;
++
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("RxVp_RDICount.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* PDSP's Rx VC State word 3 contains the value */
++ if (HalDev->State == enOpened)
++ {
++ *(int *)Value = (((*(pPDSP_AAL5_RX_VP_STATE_WORD_0(HalDev->dev_base)+(Ch*64)+1)) & RDI_CNT_MASK)>>RDI_CNT_SHIFT);
++ }
++ }
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("RxVp_RDICount.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* All sets write 0, this action is a clear only */
++ if (HalDev->State == enOpened)
++ {
++ (*(pPDSP_AAL5_RX_VP_STATE_WORD_0(HalDev->dev_base)+(Ch*64)+1)) &=~ RDI_CNT_MASK;
++ }
++ }
++ }
++
++ /* +GSG 030306 */
++ /* Fixes PITS #103 */
++ if (HalDev->OsFunc->Strstr(Key, "RxVp_AISseg.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ {
++ ActionFound=1;
++
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("RxVp_AISseg.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* PDSP's Rx VC State word 3 contains the value */
++ if (HalDev->State == enOpened)
++ {
++ *(int *)Value = (((*(pPDSP_AAL5_RX_VP_STATE_WORD_0(HalDev->dev_base)+(Ch*64)+2)) & AIS_SEG_MASK)>>AIS_SEG_SHIFT);
++ }
++ }
++ }
++
++ /* +GSG 030306 */
++ /* Fixes PITS #103 */
++ if (HalDev->OsFunc->Strstr(Key, "RxVp_AISetoe.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ {
++ ActionFound=1;
++
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("RxVp_AISetoe.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* PDSP's Rx VC State word 3 contains the value */
++ if (HalDev->State == enOpened)
++ {
++ *(int *)Value = (((*(pPDSP_AAL5_RX_VP_STATE_WORD_0(HalDev->dev_base)+(Ch*64)+2)) & AIS_ETOE_MASK)>>AIS_ETOE_SHIFT);
++ }
++ }
++ }
++
++ if (KeyFound == 0)
++ rc = (EC_AAL5|EC_FUNC_CONTROL|EC_VAL_KEY_NOT_FOUND);
++
++ if (ActionFound == 0)
++ rc = (EC_AAL5|EC_FUNC_CONTROL|EC_VAL_ACTION_NOT_FOUND);
++
++ return(rc);
++ }
++
++/*
++ * Sets up HAL default configuration parameter values.
++ */
++static void ConfigInit(HAL_DEVICE *HalDev)
++ {
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]ConfigInit(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* configure some defaults with tnetx7300 values */
++ HalDev->dev_base = 0xa3000000;
++ HalDev->offset = 0;
++ HalDev->interrupt = 15;
++ HalDev->debug = 0;
++ HalDev->MaxFrags = 46;
++ HalDev->OamLbTimeout = 5000;
++ }
++
++/*
++ * Retrieve HAL configuration parameter values.
++ */
++static bit32u ConfigGet(HAL_DEVICE *HalDev)
++ {
++ bit32u Ret;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]ConfigGet(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* get the configuration parameters common to all modules */
++ Ret = ConfigGetCommon(HalDev);
++ if (Ret) return (EC_AAL5|Ret);
++
++ /* get AAL5 specific configuration parameters here */
++ Ret = HalDev->OsFunc->Control(HalDev->OsDev, hcSarFrequency, pszGET, &HalDev->SarFrequency); /* GSG +030416*/
++ if (Ret) /* GSG +030416*/
++ HalDev->SarFrequency = 200000000; /* 200 Mhz default */ /* GSG +030416*/
++
++ return (EC_NO_ERRORS);
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * This function initializes the CPHAL module. It gathers all
++ * necessary global configuration info from the configuration file, and
++ * performs initialization and configuration of the device. Note that
++ * the device operation is not started until the OS calls @c Open().
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ *
++ * @return EC_NO_ERRORS (ok). <BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_INVALID_STATE "EC_VAL_INVALID_STATE"<BR>
++ * @ref EC_VAL_BASE_ADDR_NOT_FOUND "EC_VAL_BASE_ADDR_NOT_FOUND"<BR>
++ * @ref EC_VAL_RESET_BIT_NOT_FOUND "EC_VAL_RESET_BIT_NOT_FOUND"<BR>
++ * @ref EC_VAL_INTERRUPT_NOT_FOUND "EC_VAL_INTERRUPT_NOT_FOUND"<BR>
++ * @ref EC_VAL_OFFSET_NOT_FOUND "EC_VAL_OFFSET_NOT_FOUND"<BR>
++ */
++static int halInit(HAL_DEVICE *HalDev)
++ {
++ int i;
++ bit32u error_code;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]halInit(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Verify proper device state */
++ if (HalDev->State != enDevFound)
++ return(EC_AAL5|EC_FUNC_HAL_INIT|EC_VAL_INVALID_STATE);
++
++ /* Configure HAL defaults */
++ ConfigInit(HalDev);
++
++ /* Retrieve HAL configuration parameters from data store */
++ error_code = ConfigGet(HalDev);
++ if (error_code) return (error_code);
++
++ /* Other items (OAM related) that need to be passed in somehow */
++ HalDev->DeviceCPID[0] = 0xffffffff;
++ HalDev->DeviceCPID[1] = 0xffffffff;
++ HalDev->DeviceCPID[2] = 0xffffffff;
++ HalDev->DeviceCPID[3] = 0xffffffff;
++ HalDev->LBSourceLLID[0] = 0xffffffff;
++ HalDev->LBSourceLLID[1] = 0xffffffff;
++ HalDev->LBSourceLLID[2] = 0xffffffff;
++ HalDev->LBSourceLLID[3] = 0xffffffff;
++
++ /* Initialize SAR layer*/
++ error_code = HalDev->SarFunc->Init(HalDev->SarDev);
++ if (error_code) return (error_code);
++
++ /* Initialize various HalDev members. This is probably overkill, since these
++ are initialized in ChannelSetup() and HalDev is cleared in InitModule(). */
++ for (i=0; i<NUM_AAL5_CHAN; i++)
++ {
++ HalDev->InRxInt[i]=FALSE;
++ HalDev->ChIsOpen[i][DIRECTION_TX] = FALSE;
++ HalDev->ChIsOpen[i][DIRECTION_RX] = FALSE;
++ HalDev->TcbStart[i][0] = 0;
++ HalDev->TcbStart[i][1] = 0;
++ HalDev->RcbStart[i] = 0;
++ }
++
++ /* initialize SAR stats */
++ StatsClear(HalDev);
++
++ /* init Stat pointers */
++
++ /* even though these statistics may be for multiple channels/queues, i need
++ only configure the pointer to the beginning of the array, and I can index
++ from there if necessary */
++ StatsTable0[0].StatPtr = &HalDev->Stats.CrcErrors[0];
++ StatsTable0[1].StatPtr = &HalDev->Stats.LenErrors[0];
++ StatsTable0[2].StatPtr = &HalDev->Stats.AbortErrors[0];
++ StatsTable0[3].StatPtr = &HalDev->Stats.StarvErrors[0];
++
++ StatsTable1[0].StatPtr = &HalDev->Stats.DmaLenErrors[0];
++ StatsTable1[1].StatPtr = &HalDev->Stats.TxMisQCnt[0][0];
++ StatsTable1[2].StatPtr = &HalDev->Stats.RxMisQCnt[0];
++ StatsTable1[3].StatPtr = &HalDev->Stats.TxEOQCnt[0][0];
++ StatsTable1[4].StatPtr = &HalDev->Stats.RxEOQCnt[0];
++ StatsTable1[5].StatPtr = &HalDev->Stats.RxPacketsServiced[0];
++ StatsTable1[6].StatPtr = &HalDev->Stats.TxPacketsServiced[0][0];
++ StatsTable1[7].StatPtr = &HalDev->Stats.RxMaxServiced;
++ StatsTable1[8].StatPtr = &HalDev->Stats.TxMaxServiced[0][0];
++ StatsTable1[9].StatPtr = &HalDev->Stats.RxTotal;
++ StatsTable1[10].StatPtr = &HalDev->Stats.TxTotal;
++
++ StatsTable2[0].StatPtr = (bit32u *)&HalDev->RcbPool[0];
++ StatsTable2[1].StatPtr = &HalDev->RxActQueueCount[0];
++ StatsTable2[2].StatPtr = (bit32u *)&HalDev->RxActQueueHead[0];
++ StatsTable2[3].StatPtr = (bit32u *)&HalDev->RxActQueueTail[0];
++ StatsTable2[4].StatPtr = &HalDev->RxActive[0];
++ StatsTable2[5].StatPtr = (bit32u *)&HalDev->RcbStart[0];
++ StatsTable2[6].StatPtr = &HalDev->RxTeardownPending[0];
++ StatsTable2[7].StatPtr = (bit32u *)&HalDev->TcbPool[0][0];
++ StatsTable2[8].StatPtr = &HalDev->TxActQueueCount[0][0];
++ StatsTable2[9].StatPtr = (bit32u *)&HalDev->TxActQueueHead[0][0];
++ StatsTable2[10].StatPtr = (bit32u *)&HalDev->TxActQueueTail[0][0];
++ StatsTable2[11].StatPtr = &HalDev->TxActive[0][0];
++ StatsTable2[12].StatPtr = (bit32u *)&HalDev->TcbStart[0][0];
++ StatsTable2[13].StatPtr = &HalDev->TxTeardownPending[0];
++
++ StatsTable4[0].StatPtr = &HalDev->dev_base;
++ StatsTable4[1].StatPtr = &HalDev->offset;
++ StatsTable4[2].StatPtr = &HalDev->interrupt;
++ StatsTable4[3].StatPtr = &HalDev->debug;
++ StatsTable4[4].StatPtr = &HalDev->Inst;
++
++ StatsTable3[0].StatPtr = &HalDev->ChData[0].RxBufSize;
++ StatsTable3[1].StatPtr = &HalDev->ChData[0].RxBufferOffset;
++ StatsTable3[2].StatPtr = &HalDev->ChData[0].RxNumBuffers;
++ StatsTable3[3].StatPtr = &HalDev->ChData[0].RxServiceMax;
++ StatsTable3[4].StatPtr = &HalDev->ChData[0].TxNumBuffers;
++ StatsTable3[5].StatPtr = &HalDev->ChData[0].TxNumQueues;
++ StatsTable3[6].StatPtr = &HalDev->ChData[0].TxServiceMax;
++ StatsTable3[7].StatPtr = &HalDev->ChData[0].CpcsUU;
++ StatsTable3[8].StatPtr = &HalDev->ChData[0].Gfc;
++ StatsTable3[9].StatPtr = &HalDev->ChData[0].Clp;
++ StatsTable3[10].StatPtr = &HalDev->ChData[0].Pti;
++ StatsTable3[11].StatPtr = &HalDev->ChData[0].DaMask;
++ StatsTable3[12].StatPtr = &HalDev->ChData[0].Priority;
++ StatsTable3[13].StatPtr = &HalDev->ChData[0].PktType;
++ StatsTable3[14].StatPtr = &HalDev->ChData[0].Vci;
++ StatsTable3[15].StatPtr = &HalDev->ChData[0].Vpi;
++ StatsTable3[16].StatPtr = &HalDev->ChData[0].TxVc_CellRate;
++ StatsTable3[17].StatPtr = &HalDev->ChData[0].TxVc_QosType;
++ StatsTable3[18].StatPtr = &HalDev->ChData[0].TxVc_Mbs;
++ StatsTable3[19].StatPtr = &HalDev->ChData[0].TxVc_Pcr;
++
++ /* update device state */
++ HalDev->State = enInitialized;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(9))
++ dbgConfigDump(HalDev);
++#endif
++
++ return(EC_NO_ERRORS);
++ }
++
++/*
++ * Use this function to actually send after queuing multiple packets using
++ * Send(). This is a debug only function that should be removed - it was
++ * necessary to properly implement my loopback tests.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param Queue Queue number to kick.
++ *
++ * @return 0 OK, Non-Zero Not OK
++ */
++static int halKick(HAL_DEVICE *HalDev, int Queue)
++ {
++ int Ch;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]halKick(HalDev:%08x. Queue:%d)\n", (bit32u)HalDev, Queue);
++ osfuncSioFlush();
++ }
++#endif
++
++ for (Ch = 0; Ch < 16; Ch ++)
++ {
++ if ((!HalDev->TxActive[Ch][Queue]) && (HalDev->TxActQueueHead[Ch][Queue] != 0))
++ {
++ *(pTX_DMA_STATE_WORD_0(HalDev->dev_base)+(Ch*64)+Queue)=
++ VirtToPhys(HalDev->TxActQueueHead[Ch][Queue]);
++ HalDev->TxActive[Ch][Queue]=TRUE;
++ }
++ }
++
++ return (EC_NO_ERRORS);
++ }
++
++/* +GSG 030305 For PITS #99
++ * Alternate interrupt handler that uses the INT_VECTOR in order to
++ * provide strict priority handling among channels, beginning with Ch 0.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param MoreWork (Output) When set to 1, indicates that there is more work to do.
++ * Caller should ensure that the value pointed at is set to 0
++ * prior to the call.
++ * @return 0 OK, non-zero error.
++ */
++static int DeviceIntAlt(HAL_DEVICE *HalDev, int *MoreWork)
++ {
++ int tmp, Ch, WorkFlag;
++ bit32u rc;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]DeviceIntAlt(HalDev:%08x, MoreWork:%08x)\n", (bit32u)HalDev, (bit32u)MoreWork);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Verify proper device state - important because a call prior to Open would
++ result in a lockup */
++ if (HalDev->State != enOpened)
++ return(EC_AAL5|EC_FUNC_DEVICE_INT_ALT|EC_VAL_INVALID_STATE);
++
++ if ((tmp=SAR_INTR_VECTOR(HalDev->dev_base))&INT_PENDING)
++ {
++ /*printf("\015 %d RxQ",HalDev->RxActQueueCount[0]);
++ HalDev->OsFunc->Control(HalDev->OsDev, enSIO_FLUSH, enNULL, 0); */
++
++ if (tmp&TXH_PEND)
++ {
++ /* decide which channel to service */
++ Ch = (SAR_INTR_VECTOR(HalDev->dev_base) & TXH_PEND_INVEC);
++
++ rc = TxInt(HalDev,Ch,0,&WorkFlag);
++ if (rc) return (rc);
++
++ if (WorkFlag == 1)
++ *MoreWork = 1;
++ }
++
++ if (tmp&TXL_PEND)
++ {
++ /* decide which channel to service */
++ Ch = ((SAR_INTR_VECTOR(HalDev->dev_base) & TXL_PEND_INVEC) >> 4);
++
++ rc = TxInt(HalDev,Ch,1,&WorkFlag);
++ if (rc) return (rc);
++
++ if (WorkFlag == 1)
++ *MoreWork = 1;
++ }
++
++ if (tmp&RX_PEND)
++ {
++ /* decide which channel to service */
++ Ch = ((SAR_INTR_VECTOR(HalDev->dev_base) & RX_PEND_INVEC) >> 8);
++
++ rc = RxInt(HalDev,Ch,&WorkFlag);
++ if (rc) return (rc);
++
++ if (WorkFlag == 1)
++ *MoreWork = 1;
++ }
++
++ if (tmp&STS_PEND)
++ {
++ /* GPR 2 code added for PITS 103 */
++ /* determine interrupt source */
++ Ch = ((SAR_INTR_VECTOR(HalDev->dev_base) & STS_PEND_INVEC) >> 12);
++
++ /* only if this is GPR 2 interrupt do we take action */
++ if (Ch == 26)
++ {
++ /* pass loopback result back to OS */
++ HalDev->OsFunc->Control(HalDev->OsDev, "OamLbResult", "Set",
++ (bit32u *)pSAR_PDSP_OAM_LB_RESULT_REG(HalDev->dev_base));
++ }
++
++ /* clear the interrupt */
++ SAR_STATUS_CLR_REG(HalDev->dev_base) |= 0x04000000;
++ }
++
++ if (tmp&AAL2_PEND)
++ {
++ /* no action defined */
++ }
++
++ SAR_INTR_VECTOR(HalDev->dev_base) = 0;
++ }
++
++ return (EC_NO_ERRORS);
++ }
++
++/*
++ * Called to service a module interrupt. This function determines
++ * what type of interrupt occurred and dispatches the correct handler.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param MoreWork (Output) When set to 1, indicates that there is more work to do.
++ * Caller should ensure that the value pointed at is set to 0
++ * prior to the call.
++ * @return 0 OK, non-zero error.
++ */
++static int DeviceInt(HAL_DEVICE *HalDev, int *MoreWork)
++ {
++ /*static int NextRxCh=0;
++ static int NextTxCh[2]={0,0};*/
++
++ int tmp, Ch, FirstCh, WorkFlag;
++ int NextTxLCh, NextTxHCh, NextRxCh;
++ bit32u rc;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]DeviceInt(HalDev:%08x, MoreWork:%08x)\n", (bit32u)HalDev, (bit32u)MoreWork);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Verify proper device state - important because a call prior to Open would
++ result in a lockup */
++ if (HalDev->State != enOpened)
++ return(EC_AAL5|EC_FUNC_DEVICE_INT|EC_VAL_INVALID_STATE);
++
++ NextTxHCh = HalDev->NextTxCh[0];
++ NextTxLCh = HalDev->NextTxCh[1];
++ NextRxCh = HalDev->NextRxCh;
++
++ /* service interrupts while there is more work to do */
++ /*while (((tmp=SAR_INTR_VECTOR(HalDev->dev_base))&INT_PENDING) && (TotalPkts < 500))*/
++ if ((tmp=SAR_INTR_VECTOR(HalDev->dev_base))&INT_PENDING)
++ {
++ /*printf("\015 %d RxQ",HalDev->RxActQueueCount[0]);
++ HalDev->OsFunc->Control(HalDev->OsDev, enSIO_FLUSH, enNULL, 0); */
++
++ if (tmp&TXH_PEND)
++ {
++ /* decide which channel to service */
++ FirstCh = NextTxHCh;
++ while (1)
++ {
++ Ch = NextTxHCh++;
++ if (NextTxHCh == 16)
++ NextTxHCh = 0;
++ if (SAR_TX_MASKED_STATUS(HalDev->dev_base) & (1<<Ch))
++ break;
++ if (FirstCh == NextTxHCh)
++ {
++ /* we checked every channel and still haven't found anything to do */
++ return (EC_AAL5|EC_FUNC_DEVICE_INT|EC_VAL_NO_TXH_WORK_TO_DO);
++ }
++ }
++
++ rc = TxInt(HalDev,Ch,0,&WorkFlag);
++ if (rc) return (rc);
++
++ if (WorkFlag == 1)
++ *MoreWork = 1;
++ }
++
++ if (tmp&TXL_PEND)
++ {
++ /* decide which channel to service */
++ FirstCh = NextTxLCh;
++ while (1)
++ {
++ Ch = NextTxLCh++;
++ if (NextTxLCh == 16)
++ NextTxLCh = 0;
++ if (SAR_TX_MASKED_STATUS(HalDev->dev_base) & (1<<(Ch+16)))
++ break;
++ if (FirstCh == NextTxLCh)
++ {
++ /* we checked every channel and still haven't found anything to do */
++ return (EC_AAL5|EC_FUNC_DEVICE_INT|EC_VAL_NO_TXL_WORK_TO_DO);
++ }
++ }
++
++ rc = TxInt(HalDev,Ch,1,&WorkFlag);
++ if (rc) return (rc);
++
++ if (WorkFlag == 1)
++ *MoreWork = 1;
++ }
++
++ if (tmp&RX_PEND)
++ {
++ FirstCh = NextRxCh;
++ while (1)
++ {
++ Ch = NextRxCh++;
++ if (NextRxCh == 16)
++ NextRxCh = 0;
++ if (SAR_RX_MASKED_STATUS(HalDev->dev_base) & (1 << Ch))
++ break; /* found a channel to service */
++ if (FirstCh == NextRxCh)
++ {
++ /* we checked every channel and still haven't found anything to do */
++ return (EC_AAL5|EC_FUNC_DEVICE_INT|EC_VAL_NO_RX_WORK_TO_DO);
++ }
++ }
++
++ rc = RxInt(HalDev,Ch, &WorkFlag);
++ if (rc) return (rc);
++
++ if (WorkFlag == 1)
++ *MoreWork = 1;
++ }
++
++ if (tmp&STS_PEND)
++ {
++ /* +GSG 030305 */
++ /* GPR 2 code added for PITS 103 */
++ /* determine interrupt source */
++ Ch = ((SAR_INTR_VECTOR(HalDev->dev_base) & STS_PEND_INVEC) >> 12);
++
++ /* only if this is GPR 2 interrupt do we take action */
++ if (Ch == 26)
++ {
++ /* pass loopback result back to OS */
++ HalDev->OsFunc->Control(HalDev->OsDev, "OamLbResult", "Set",
++ (bit32u *)pSAR_PDSP_OAM_LB_RESULT_REG(HalDev->dev_base));
++ }
++
++ /* clear the interrupt */
++ SAR_STATUS_CLR_REG(HalDev->dev_base) |= 0x04000000;
++ }
++
++ if (tmp&AAL2_PEND)
++ {
++ /* no action defined */
++ }
++
++ SAR_INTR_VECTOR(HalDev->dev_base) = 0;
++ }
++
++ HalDev->NextTxCh[0] = NextTxHCh;
++ HalDev->NextTxCh[1] = NextTxLCh;
++ HalDev->NextRxCh = NextRxCh;
++
++ /* This must be done by the upper layer */
++ /* SAR_EOI(HalDev->dev_base) = 0; */
++
++ return (EC_NO_ERRORS);
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * This function starts the operation of the CPHAL device. It takes the device
++ * out of reset, and calls @c IsrRegister(). This function should be called after
++ * calling the @c Init() function.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ *
++ * @return EC_NO_ERRORS (ok).<BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_INVALID_STATE "EC_VAL_INVALID_STATE"<BR>
++ * @ref EC_VAL_KEY_NOT_FOUND "EC_VAL_KEY_NOT_FOUND"<BR>
++ * @ref EC_VAL_FIRMWARE_TOO_LARGE "EC_VAL_FIRMWARE_TOO_LARGE"<BR>
++ * @ref EC_VAL_PDSP_LOAD_FAIL "EC_VAL_PDSP_LOAD_FAIL"<BR>
++ * @ref EC_VAL_RX_STATE_RAM_NOT_CLEARED "EC_VAL_RX_STATE_RAM_NOT_CLEARED"<BR>
++ * @ref EC_VAL_TX_STATE_RAM_NOT_CLEARED "EC_VAL_TX_STATE_RAM_NOT_CLEARED"<BR>
++ * @ref EC_VAL_TCB_MALLOC_FAILED "EC_VAL_TCB_MALLOC_FAILED"<BR>
++ * @ref EC_VAL_RCB_MALLOC_FAILED "EC_VAL_RCB_MALLOC_FAILED"<BR>
++ * @ref EC_VAL_RX_BUFFER_MALLOC_FAILED "EC_VAL_RX_BUFFER_MALLOC_FAILED"<BR>
++ * @ref EC_VAL_LUT_NOT_READY "EC_VAL_LUT_NOT_READY"<BR>
++ */
++static int halOpen(HAL_DEVICE *HalDev)
++ {
++ int i,Ret;
++ bit32 SarBase = HalDev->dev_base;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]halOpen(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Verify proper device state */
++ if (HalDev->State < enInitialized)
++ return (EC_AAL5|EC_FUNC_OPEN|EC_VAL_INVALID_STATE);
++
++ /* Open the SAR (this brings the whole device out of reset */
++ Ret = HalDev->SarFunc->Open(HalDev->SarDev); /* ~GSG 030410 */
++ if (Ret) /* +GSG 030410 */
++ return (Ret); /* +GSG 030410 */
++
++ /* Change device state */
++ HalDev->State = enOpened;
++
++
++#ifdef __CPHAL_DEBUG
++ /* print out the version information */
++ if (DBG(7))
++ {
++ dbgPrintf("[aal5 halOpen()]Module ID(AAL5-CPSAR):%d, Version:%2d.%02d\n",
++ (SAR_ID_REG(SarBase)&0xffff0000)>>16,
++ (SAR_ID_REG(SarBase)&0xff00)>>8,
++ SAR_ID_REG(SarBase)&0xff);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* GREG 11/1/02: The State RAM clearing code was previously in cpsar.c,
++ directly after device reset. I moved it here because I believe it is
++ AAL5 specific code. Also the MAX_CHAN was set to 19 in cpsar.c, which
++ would have caused this code to clear too much memory! */
++
++ /* NOTE: State RAM must be cleared prior to initializing the PDSP!! */
++
++ /* GSG 030416: Removed all of this. All PDSP State RAM is cleared
++ in CPSAR Open(). On Close(), all channels are torndown, thus all
++ AAL5 channel state RAM is cleared. */
++
++ /* Clear Rx State RAM */
++ /*for (i=0; i<NUM_AAL5_CHAN; i++)
++ for (j=0; j<NUM_RX_STATE_WORDS; j++)
++ *(pRX_DMA_STATE_WORD_0(SarBase) + (i*64) + j) = 0; */
++
++ /* Check that Rx DMA State RAM was cleared */
++ /*for (i=0; i<NUM_AAL5_CHAN; i++)
++ for (j=0; j<NUM_RX_STATE_WORDS; j++)
++ {
++ if (*(pRX_DMA_STATE_WORD_0(SarBase) + (i*64) + j) != 0)
++ {
++ return(EC_AAL5|EC_FUNC_HAL_INIT|EC_VAL_RX_STATE_RAM_NOT_CLEARED);
++ }
++ }*/
++
++ /* Clear Tx State RAM */
++ /*for (i=0; i<NUM_AAL5_CHAN; i++)
++ for (j=0; j<NUM_TX_STATE_WORDS; j++)
++ {
++ *(pTX_DMA_STATE_WORD_0(SarBase) + (i*64) + j) = 0;
++ }*/
++
++ /* Check that Tx DMA State RAM was cleared */
++ /*for (i=0; i<NUM_AAL5_CHAN; i++)
++ for (j=0; j<NUM_TX_STATE_WORDS; j++)
++ {
++ if (*(pTX_DMA_STATE_WORD_0(SarBase) + (i*64) + j) != 0)
++ {
++ return(EC_AAL5|EC_FUNC_HAL_INIT|EC_VAL_TX_STATE_RAM_NOT_CLEARED);
++ }
++ }*/
++
++ /* GSG +030523 Malloc space for the Rx fraglist */
++ HalDev->fraglist = HalDev->OsFunc->Malloc(HalDev->MaxFrags * sizeof(FRAGLIST));
++
++ /* For any channels that have been pre-initialized, set them up now */
++ for (i=0; i<NUM_AAL5_CHAN; i++)
++ {
++ if ((HalDev->ChIsSetup[i][0]==TRUE) && (HalDev->ChIsOpen[i][0]==FALSE))
++ {
++ CHANNEL_INFO HalChn;
++ HalChn.Channel = i;
++ Ret = ChannelConfigApply(HalDev, &HalChn);
++ if (Ret) return (Ret);
++ }
++ }
++
++ /* OAM code would be a candidate to go into ConfigApply */
++
++ /* Configure OAM Timer State Block */
++ OamRateConfig(HalDev); /* +GSG 030416 */
++
++ /* Setup OAM Configuration Block */
++ for (i=0; i<8; i++) /* ~GSG 030603 4->8 */
++ {
++ if (i < 4)
++ *(pOAM_CONFIG_BLOCK_WORD_0(SarBase) + i) = HalDev->DeviceCPID[i];
++ else
++ *(pOAM_CONFIG_BLOCK_WORD_0(SarBase) + i) = HalDev->LBSourceLLID[i-4];
++ }
++
++ /* Setup OAM Padding Block */
++ for (i=0; i<12; i++)
++ {
++ *(pOAM_PADDING_BLOCK_WORD_0(SarBase) + i) = ((i==11)?0x6a6a0000:0x6a6a6a6a);
++ }
++
++ /* Enable Tx CPPI DMA */
++ TX_CPPI_CTL_REG(HalDev->dev_base) = 1;
++
++ /* Enable Rx CPPI DMA */
++ RX_CPPI_CTL_REG(HalDev->dev_base) = 1;
++
++ /* +GSG 030306 */
++ /* Fix for PITS 103 */
++ /* Enable Host Interrupt for GPR 2 (OAM LB result register) */
++ SAR_HOST_INT_EN_SET_REG(HalDev->dev_base) |= 0x04000000;
++
++ /* +GSG 030304 to fix PITS 99 (if block is new)*/
++ if (HalDev->StrictPriority == 1)
++ {
++#ifdef __CPHAL_DEBUG
++ if (DBG(1))
++ {
++ dbgPrintf("[aal5->os]IsrRegister(OsDev:%08x, halIsr:%08x, Interrupt:%d)\n",
++ (bit32u)HalDev->OsDev, (bit32u)DeviceIntAlt, HalDev->interrupt);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* "register" the interrupt handler */
++ HalDev->OsFunc->IsrRegister(HalDev->OsDev, DeviceIntAlt, HalDev->interrupt);
++ }
++ else /* +GSG 030306 */
++ { /* +GSG 030306 */
++#ifdef __CPHAL_DEBUG
++ if (DBG(1))
++ {
++ dbgPrintf("[aal5->os]IsrRegister(OsDev:%08x, halIsr:%08x, Interrupt:%d)\n",
++ (bit32u)HalDev->OsDev, (bit32u)DeviceInt, HalDev->interrupt);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* "register" the interrupt handler */
++ HalDev->OsFunc->IsrRegister(HalDev->OsDev, DeviceInt, HalDev->interrupt);
++ } /* +GSG 030306 */
++
++ return(EC_NO_ERRORS);
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * Called to retrigger the interrupt mechanism after packets have been
++ * processed. Call this function when the HalISR function indicates that
++ * there is no more work to do. Proper use of this function will guarantee
++ * that interrupts are never missed.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ *
++ * @return EC_NO_ERRORS (ok). <BR>
++ */
++static int halPacketProcessEnd(HAL_DEVICE *HalDev)
++ {
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]halPacketProcessEnd(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ SAR_EOI(HalDev->dev_base) = 0;
++ return (EC_NO_ERRORS);
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * This function probes for the instance of the CPHAL module. It will call
++ * the OS function @c DeviceFindInfo() to get the information required.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ *
++ * @return EC_NO_ERRORS (ok). <BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_INVALID_STATE "EC_VAL_INVALID_STATE"<BR>
++ * @ref EC_VAL_DEVICE_NOT_FOUND "EC_VAL_DEVICE_NOT_FOUND"<BR>
++ */
++static int halProbe(HAL_DEVICE *HalDev)
++ {
++ int Ret;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]halProbe(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Verify hardware state is "enConnected */
++ if (HalDev->State != enConnected)
++ return (EC_AAL5|EC_FUNC_PROBE|EC_VAL_INVALID_STATE);
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(1))
++ {
++ dbgPrintf("[aal5->os]DeviceFindInfo(Inst:%d, DeviceName:%s, DeviceInfo:%08x)\n",
++ HalDev->Inst, "aal5", (bit32u)&HalDev->DeviceInfo);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Attempt to find the device information */
++ Ret = HalDev->OsFunc->DeviceFindInfo(HalDev->Inst, "aal5", &HalDev->DeviceInfo);
++ if (Ret)
++ return(EC_AAL5|EC_FUNC_PROBE|EC_VAL_DEVICE_NOT_FOUND);
++
++ /* Call Probe for supporting CPSAR layer */
++ Ret = HalDev->SarFunc->Probe(HalDev->SarDev);
++ if (Ret)
++ return(Ret);
++
++ /* Set device state to DevFound */
++ HalDev->State = enDevFound;
++
++ return(EC_NO_ERRORS);
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * This function shuts down the CPHAL module completely. The caller must call
++ * Close() to put the device in reset prior shutting down. This call will free
++ * the HalDev and the HAL function pointer structure, effectively ending
++ * communications between the driver and the CPHAL. Further use of the module
++ * must be initiated by a call to xxxInitModule(), which starts the entire process
++ * over again.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ *
++ * @return EC_NO_ERRORS (ok). <BR>
++ * Possible Error Codes:<BR>
++ * Any error code from halClose().<BR>
++ */
++static int halShutdown(HAL_DEVICE *HalDev)
++ {
++ int Ch, Queue; /*GSG+030514*/
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]halShutdown(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Verify proper device state */
++ if (HalDev->State == enOpened)
++ halClose(HalDev, 3); /*GSG+030429*/
++
++ /* Buffer/descriptor resources may still need to be freed if a Close
++ Mode 1 was performed prior to Shutdown - clean up here */ /*GSG+030514*/
++ for (Ch=0; Ch<NUM_AAL5_CHAN; Ch++)
++ {
++ if (HalDev->RcbStart[Ch] != 0)
++ FreeRx(HalDev,Ch);
++
++ for(Queue=0; Queue<MAX_QUEUE; Queue++)
++ {
++ if (HalDev->TcbStart[Ch][Queue] != 0)
++ FreeTx(HalDev,Ch,Queue);
++ }
++ }
++
++ /* shutdown the CPSAR layer */
++ HalDev->SarFunc->Shutdown(HalDev->SarDev);
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(6))
++ {
++ dbgPrintf(" [aal5 halShutdown()]Free AAL5 function pointers\n");
++ osfuncSioFlush();
++ }
++ if (DBG(1)||DBG(3))
++ {
++ dbgPrintf("[aal5->os]Free(MemPtr:%08x)\n", (bit32u)HalDev->HalFuncPtr);
++ osfuncSioFlush();
++ }
++#endif
++ /* free the HalFunc */
++ HalDev->OsFunc->Free(HalDev->HalFuncPtr);
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(6))
++ {
++ dbgPrintf(" [aal5 halShutdown]Free HalDev\n");
++ osfuncSioFlush();
++ }
++ if (DBG(1)||DBG(3))
++ {
++ dbgPrintf("[aal5->os]Free(MemPtr:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++ /* free the HAL device */
++ HalDev->OsFunc->FreeDev(HalDev);
++
++ return(EC_NO_ERRORS);
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * Used to perform regular checks on the device. This function should be
++ * called at a regular interval specified by the @c Tick parameter.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ *
++ * @return EC_NO_ERRORS (ok).<BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_INVALID_STATE "EC_VAL_INVALID_STATE"<BR>
++ */
++static int halTick(HAL_DEVICE *HalDev)
++ {
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[aal5]halTick(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ if (HalDev->State != enOpened)
++ return(EC_AAL5|EC_FUNC_TICK|EC_VAL_INVALID_STATE);
++
++ return(EC_NO_ERRORS);
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ *
++ * This function will:
++ * -# allocate a HalDev that will be used by the OS for future communications with the device
++ * -# save OsDev for use when calling OS functions
++ * -# allocate and populate HalFunc with the addresses of CPHAL functions.
++ * -# check OsFuncSize to see if it meets the minimum requirement.
++ * -# return the size of the HAL_FUNCTIONS structure through the HalFuncSize pointer. The OS
++ * should check this value to ensure that the HAL meets its minimum requirement.
++ *
++ * Version checking between the OS and the CPHAL is done using the OsFuncSize and
++ * HalFuncSize. Future versions of the CPHAL may add new functions to either
++ * HAL_FUNCTIONS or OS_FUNCTIONS, but will never remove functionality. This enables
++ * both the HAL and OS to check the size of the function structure to ensure that
++ * the current OS and CPHAL are compatible.
++ *
++ * Note: This is the only function exported by a CPHAL module.
++ *
++ * Please refer to the section "@ref hal_init" for example code.
++ *
++ * @param HalDev Pointer to pointer to CPHAL module information. This will
++ * be used by the OS when communicating to this module via
++ * CPHAL. Allocated during the call.
++ * @param OsDev Pointer to OS device information. This will be saved by
++ * the CPHAL and returned to the OS when required.
++ * @param HalFunc Pointer to pointer to structure containing function pointers for all CPHAL
++ * interfaces. Allocated during the call.
++ * @param OsFunc Pointer to structure containing function pointers for all OS
++ * provided interfaces. Must be allocated by OS prior to call.
++ * @param OsFuncSize Size of OS_FUNCTIONS structure.
++ * @param HalFuncSize Pointer to the size of the HAL_FUNCTIONS structure.
++ * @param Inst The instance number of the module to initialize. (start at
++ * 0).
++ *
++ * @return EC_NO_ERRORS (ok). <BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_OS_VERSION_NOT_SUPPORTED "EC_VAL_OS_VERSION_NOT_SUPPORTED"<BR>
++ * @ref EC_VAL_MALLOC_DEV_FAILED "EC_VAL_MALLOC_DEV_FAILED"<BR>
++ * @ref EC_VAL_MALLOC_FAILED "EC_VAL_MALLOC_FAILED"<BR>
++ */
++int xxxInitModule(HAL_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ HAL_FUNCTIONS **HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++
++int cpaal5InitModule(HAL_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ HAL_FUNCTIONS **HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst)
++ {
++ int rc, SarFuncSize;
++ HAL_DEVICE *HalPtr;
++ HAL_FUNCTIONS *HalFuncPtr;
++
++ /* NEW CODE */
++ if (OsFuncSize < sizeof(OS_FUNCTIONS))
++ return (EC_AAL5|EC_FUNC_HAL_INIT|EC_VAL_OS_VERSION_NOT_SUPPORTED);
++
++ HalPtr = (HAL_DEVICE *) OsFunc->MallocDev(sizeof(HAL_DEVICE));
++ if (!HalPtr)
++ return (EC_AAL5|EC_FUNC_HAL_INIT|EC_VAL_MALLOC_DEV_FAILED);
++
++ HalFuncPtr = (HAL_FUNCTIONS *) OsFunc->Malloc(sizeof(HAL_FUNCTIONS));
++ if (!HalFuncPtr)
++ return (EC_AAL5|EC_FUNC_HAL_INIT|EC_VAL_MALLOC_FAILED);
++
++ /* Initialize the size of hal functions */
++ *HalFuncSize = sizeof (HAL_FUNCTIONS);
++
++ /* clear the device structure */
++ OsFunc->Memset(HalPtr, 0, sizeof(HAL_DEVICE));
++
++ /* clear the function pointers */
++ OsFunc->Memset(HalFuncPtr, 0, sizeof(HAL_FUNCTIONS));
++
++ /* initialize the HAL_DEVICE structure */
++ HalPtr->OsDev = OsDev;
++ /*HalPtr->OsOpen = OsDev;*/
++ HalPtr->Inst = Inst;
++ HalPtr->OsFunc = OsFunc;
++
++ /* Supply pointers for the CPHAL API functions */
++ HalFuncPtr->RxReturn = halRxReturn;
++ HalFuncPtr->Init = halInit;
++ HalFuncPtr->Close = halClose;
++ HalFuncPtr->Send = halSend;
++ HalFuncPtr->ChannelSetup = halChannelSetup;
++ HalFuncPtr->ChannelTeardown = halChannelTeardown;
++ HalFuncPtr->Open = halOpen;
++ HalFuncPtr->Kick = halKick;
++ HalFuncPtr->RegAccess = halRegAccess;
++ HalFuncPtr->Probe = halProbe;
++ HalFuncPtr->Control = halControl;
++ HalFuncPtr->Tick = halTick;
++ HalFuncPtr->Shutdown = halShutdown;
++ HalFuncPtr->OamFuncConfig = halOamFuncConfig; /* +GSG 030306 */
++ HalFuncPtr->OamLoopbackConfig = halOamLoopbackConfig; /* ~GSG 030416 */
++
++ /* Temporary */
++ /*HalFuncPtr->StatsGetOld = StatsGet;*/
++ HalFuncPtr->PacketProcessEnd = halPacketProcessEnd;
++
++ /* Now, AAL5 must connect to the CPSAR layer */
++
++ /* Attach to SAR HAL Functions */
++ /*
++ cpsarInitModule(NULL, NULL, 0, NULL, &SarFuncSize, Inst);
++
++ if (SarFuncSize!=sizeof(CPSAR_FUNCTIONS))
++ return(EC_AAL5|EC_FUNC_HAL_INIT|EC_VAL_CPSAR_VERSION_NOT_SUPPORTED);
++
++ HalPtr->SarFunc = (CPSAR_FUNCTIONS *) OsFunc->Malloc(SarFuncSize);
++ */
++
++ rc = cpsarInitModule(&HalPtr->SarDev, OsDev, &HalPtr->SarFunc, OsFunc, sizeof(OS_FUNCTIONS), &SarFuncSize, Inst);
++
++ /* pass back the error value from the CPSAR layer if necessary */
++ if (rc)
++ return(rc);
++
++ /*
++ if (!HalPtr->SarDev)
++ return(EC_AAL5|EC_FUNC_HAL_INIT|EC_VAL_NULL_CPSAR_DEV);
++ */
++
++ /* Initialize the hardware state */
++ HalPtr->State = enConnected;
++
++ /* keep a reference to HalFuncPtr so I can free it later */
++ HalPtr->HalFuncPtr = HalFuncPtr;
++
++ /* pass the HalPtr back to the caller */
++ *HalDev = HalPtr;
++ *HalFunc = HalFuncPtr;
++
++ return(EC_NO_ERRORS);
++ }
+diff -urN linux.old/drivers/atm/sangam_atm/aal5sar.h linux.dev/drivers/atm/sangam_atm/aal5sar.h
+--- linux.old/drivers/atm/sangam_atm/aal5sar.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/aal5sar.h 2005-08-23 04:46:50.080846280 +0200
+@@ -0,0 +1,198 @@
++/**@file************************************************************************
++ * TNETDxxxx Software Support
++ * Copyright (c) 2002 Texas Instruments Incorporated. All Rights Reserved.
++ *
++ * FILE: aal5sar.h
++ *
++ * DESCRIPTION:
++ * This file contains data structure definitions for the AAL5 HAL SAR.
++ *
++ * HISTORY:
++ * 28Feb02 Greg 1.00 Original Version created.
++ * 06Mar02 Greg 1.01 Documented structures.
++ * 18Jul02 Greg 1.02 Major reorganization
++ *
++ *****************************************************************************/
++#ifndef _INC_AAL5SAR
++#define _INC_AAL5SAR
++
++/** \namespace AAL5_Version
++This documents version 01.06.06 of the AAL5 CPHAL.
++*/
++const char *pszVersion_CPAAL5="CPAAL5 01.06.06 "__DATE__" "__TIME__;
++
++#include "cpsar_cpaal5.h"
++
++#define NUM_AAL5_CHAN 16
++#define MAX_AAL5_CHAN 15
++#define MAX_QUEUE 2
++#define MAX_DIRECTION 2
++
++#define PKT_TYPE_AAL5 0 /* +GSG 030508 */
++#define PKT_TYPE_NULL 1 /* +GSG 030508 */
++#define PKT_TYPE_OAM 2 /* +GSG 030508 */
++#define PKT_TYPE_TRANS 3 /* +GSG 030508 */
++#define ATM_HEADER_SIZE 4 /* +GSG 030508 */
++
++/*
++ * HAL Default Parameter Values
++ */
++#define CFG_TX_NUM_BUFS {256,256,256,256,256,256,256,256, 256,256,256,256,256,256,256,256}
++#define CFG_RX_NUM_BUFS {256,256,256,256,256,256,256,256, 256,256,256,256,256,256,256,256}
++#define CFG_RX_BUF_SIZE {1518,1518,1518,1518,1518,1518,1518,1518, 1518,1518,1518,1518,1518,1518,1518,1518}
++#define CFG_RX_BUF_OFFSET {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}
++#define CFG_TX_NUM_QUEUES {1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1}
++#define CFG_CPCS_UU {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}
++#define CFG_DA_MASK {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}
++#define CFG_PRIORITY {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}
++#define CFG_PKT_TYPE {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}
++#define CFG_VCI {100,101,102,103,104,105,106,107, 108,109,110,111,112,113,114,115}
++#define CFG_VPI {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}
++#define CFG_CELL_RATE {0x30d4,0x30d4,0x30d4,0x30d4,0x30d4,0x30d4,0x30d4,0x30d4, 0x30d4,0x30d4,0x30d4,0x30d4,0x30d4,0x30d4,0x30d4,0x30d4}
++#define CFG_QOS_TYPE {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}
++#define CFG_MBS {8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8}
++#define CFG_PCR {1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1}
++#define CFG_GFC {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}
++#define CFG_CLP {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}
++#define CFG_PTI {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}
++#define CFG_RX_MAX_SERVICE {170,170,170,170,170,170,170,170, 170,170,170,170,170,170,170,170}
++#define CFG_TX_MAX_SERVICE {170,170,170,170,170,170,170,170, 170,170,170,170,170,170,170,170}
++
++static int cfg_tx_num_bufs[NUM_AAL5_CHAN] = CFG_TX_NUM_BUFS;
++static int cfg_rx_num_bufs[NUM_AAL5_CHAN] = CFG_RX_NUM_BUFS;
++static int cfg_rx_buf_size[NUM_AAL5_CHAN] = CFG_RX_BUF_SIZE;
++static int cfg_rx_buf_offset[NUM_AAL5_CHAN] = CFG_RX_BUF_OFFSET;
++static int cfg_tx_num_queues[NUM_AAL5_CHAN] = CFG_TX_NUM_QUEUES;
++static bit32u cfg_cpcs_uu[NUM_AAL5_CHAN] = CFG_CPCS_UU;
++static int cfg_da_mask[NUM_AAL5_CHAN] = CFG_DA_MASK;
++static int cfg_priority[NUM_AAL5_CHAN] = CFG_PRIORITY;
++static int cfg_pkt_type[NUM_AAL5_CHAN] = CFG_PKT_TYPE;
++static int cfg_vci[NUM_AAL5_CHAN] = CFG_VCI;
++static int cfg_vpi[NUM_AAL5_CHAN] = CFG_VPI;
++static bit32u cfg_cell_rate[NUM_AAL5_CHAN] = CFG_CELL_RATE;
++static int cfg_qos_type[NUM_AAL5_CHAN] = CFG_QOS_TYPE;
++static int cfg_mbs[NUM_AAL5_CHAN] = CFG_MBS;
++static int cfg_pcr[NUM_AAL5_CHAN] = CFG_PCR;
++static int cfg_gfc[NUM_AAL5_CHAN] = CFG_GFC;
++static int cfg_clp[NUM_AAL5_CHAN] = CFG_CLP;
++static int cfg_pti[NUM_AAL5_CHAN] = CFG_PTI;
++static int cfg_rx_max_service[NUM_AAL5_CHAN]= CFG_RX_MAX_SERVICE;
++static int cfg_tx_max_service[NUM_AAL5_CHAN]= CFG_TX_MAX_SERVICE;
++static char *channel_names[] = CHANNEL_NAMES;
++
++/*
++ * The HAL_FUNCTIONS struct defines the function pointers for all HAL functions
++ * accessible to upper layer software. It is populated by calling
++ * halInitModules().
++ *
++ * Note that this list is still under definition.
++ */
++
++/*
++ * This is the data structure for a transmit buffer descriptor. The first
++ * four 32-bit words of the BD represent the CPPI 3.0 defined buffer descriptor
++ * words. The other words are SAR/HAL implementation specific.
++ */
++typedef struct
++ {
++ bit32 HNext; /**< Hardware's pointer to next buffer descriptor */
++ bit32 BufPtr; /**< Pointer to the data buffer */
++ bit32 Off_BLen; /**< Contains buffer offset and buffer length */
++ bit32 mode; /**< SOP, EOP, Ownership, EOQ, Teardown Complete bits */
++ bit32 AtmHeader; /**< Atm Header to be used for each fragment */
++ bit32 Word5; /**< General control information for the packet */
++ bit32 Res6;
++ bit32 Res7;
++ void *Next;
++ void *OsInfo;
++#ifdef __CPHAL_DEBUG
++ bit32 DbgSop;
++ bit32 DbgData;
++ bit32 DbgFraglist;
++#endif
++ void *Eop;
++ }HAL_TCB;
++
++/*
++ * This is the data structure for a receive buffer descriptor. The first
++ * six 32-bit words of the BD represent the CPPI 3.0 defined buffer descriptor
++ * words. The other words are HAL implementation specific.
++ */
++typedef volatile struct hal_private
++ {
++ bit32 HNext; /**< Hardware's pointer to next buffer descriptor */
++ bit32 BufPtr; /**< Pointer to the data buffer */
++ bit32 Off_BLen; /**< Contains buffer offset and buffer length */
++ bit32 mode; /**< SOP, EOP, Ownership, EOQ, Teardown, Q Starv, Length */
++ bit32 AtmHeader;
++ bit32 UuCpi;
++ bit32 Res6;
++ bit32 Res7;
++ void *DatPtr;
++ void *Next;
++ void *OsInfo;
++ void *Eop;
++ bit32 FragCount;
++ bit32 Ch;
++ HAL_DEVICE *HalDev;
++ }HAL_RCB;
++
++
++#define MAX_NEEDS 512 /*MJH+030409*/
++/*
++ * This is the data structure for a generic HAL device. It contains all device
++ * specific data for a single instance of that device. This includes Rx/Tx
++ * buffer queues, device base address, reset bit, and other information.
++ */
++typedef struct hal_device
++ {
++ HAL_RCB *RcbPool[NUM_AAL5_CHAN];
++ bit32u rxbufseq;
++ bit32 RxActQueueCount[NUM_AAL5_CHAN];
++ HAL_RCB *RxActQueueHead[NUM_AAL5_CHAN];
++ HAL_RCB *RxActQueueTail[NUM_AAL5_CHAN];
++ bit32 RxActive[NUM_AAL5_CHAN];
++ bit32 dev_base;
++ HAL_TCB *TcbPool[NUM_AAL5_CHAN][MAX_QUEUE];
++ bit32 offset;
++ bit32 TxActQueueCount[NUM_AAL5_CHAN][MAX_QUEUE];
++ HAL_TCB *TxActQueueHead[NUM_AAL5_CHAN][MAX_QUEUE];
++ HAL_TCB *TxActQueueTail[NUM_AAL5_CHAN][MAX_QUEUE];
++ bit32 TxActive[NUM_AAL5_CHAN][MAX_QUEUE];
++ bit32 TxTeardownPending[NUM_AAL5_CHAN];
++ bit32 RxTeardownPending[NUM_AAL5_CHAN];
++ bit32 ChIsOpen[NUM_AAL5_CHAN][MAX_DIRECTION];
++ bit32 ChIsSetup[NUM_AAL5_CHAN][MAX_DIRECTION];
++ bit32 interrupt;
++ bit32 debug;
++ OS_DEVICE *OsDev;
++ OS_FUNCTIONS *OsFunc;
++ CPSAR_FUNCTIONS *SarFunc;
++ CPSAR_DEVICE *SarDev;
++ /*void *OsOpen;*/
++ /*FRAGLIST fraglist[MAX_FRAG];*/
++ FRAGLIST *fraglist;
++ char *TcbStart[NUM_AAL5_CHAN][MAX_QUEUE];
++ char *RcbStart[NUM_AAL5_CHAN];
++ /*bit32 RcbSize[NUM_AAL5_CHAN];*/
++ bit32 InRxInt[NUM_AAL5_CHAN];
++ STAT_INFO Stats;
++ bit32 Inst;
++ bit32u DeviceCPID[4];
++ bit32u LBSourceLLID[4];
++ CHANNEL_INFO ChData[NUM_AAL5_CHAN];
++ DEVICE_STATE State;
++ char *DeviceInfo;
++ HAL_FUNCTIONS *HalFuncPtr;
++ int NextRxCh;
++ int NextTxCh[2];
++ int StrictPriority; /* +GSG 030304 */
++ bit32u NeedsCount; /*MJH+030409*/
++ HAL_RECEIVEINFO *Needs[MAX_NEEDS]; /*MJH+030409*/
++ bit32u SarFrequency; /* +GSG 030416 */
++ int MaxFrags;
++ bit32u TurboDslErrors;
++ bit32u OamLbTimeout;
++ }HALDEVICE;
++
++#endif
+diff -urN linux.old/drivers/atm/sangam_atm/cpcommon_cpaal5.c linux.dev/drivers/atm/sangam_atm/cpcommon_cpaal5.c
+--- linux.old/drivers/atm/sangam_atm/cpcommon_cpaal5.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/cpcommon_cpaal5.c 2005-08-23 04:46:50.081846128 +0200
+@@ -0,0 +1,728 @@
++#ifndef _INC_CPCOMMON_C
++#define _INC_CPCOMMON_C
++
++#ifdef _CPHAL_CPMAC
++#include "cpremap_cpmac.c"
++#endif
++
++#ifdef _CPHAL_AAL5
++#include "cpremap_cpaal5.c"
++#endif
++
++#ifdef _CPHAL_CPSAR
++#include "cpremap_cpsar.c"
++#endif
++
++#ifdef _CPHAL_AAL2
++#include "cpremap_cpaal2.c"
++#endif
++
++/**
++@defgroup Common_Config_Params Common Configuration Parameters
++
++This section documents the configuration parameters that are valid across
++all CPHAL devices.
++@{
++*/
++/** This is the debug level. The field is bit defined, such that the user
++should set to 1 all the bits corresponding to desired debug outputs. The following
++are the meanings for each debug bit:
++- bit0 (LSB): CPHAL Function Trace
++- b1 : OS Function call trace
++- b2 : Critical section entry/exit
++- b3 : Memory allocation/destruction
++- b4 : Detailed information in Rx path
++- b5 : Detailed information in Tx path
++- b6 : Extended error information
++- b7 : General info
++*/
++static const char pszDebug[] = "debug";
++/** CPU Frequency. */
++/*static const char pszCpuFreq[] = "CpuFreq";*/ /*MJH-030403*/
++/** Base address for the module. */
++static const char pszBase[] = "base";
++/** Reset bit for the module. */
++static const char pszResetBit[] = "reset_bit";
++/** Reset base address for the module. */
++static const char pszResetBase[] = "ResetBase";
++/** Interrupt line for the module. */
++static const char pszIntLine[] = "int_line";
++/** VLYNQ offset for the module. Disregard if not using VLYNQ. */
++static const char pszOffset[] = "offset";
++/** The OS may "Get" this parameter, which is a pointer
++ to a character string that indicates the version of CPHAL. */
++static const char pszVer[] = "Version";
++/*@}*/
++
++/**
++@defgroup Common_Control_Params Common Keys for [os]Control()
++
++This section documents the keys used with the OS @c Control() interface that
++are required by CPHAL devices.
++
++@{
++*/
++/** Used to wait for an integer number of clock ticks, given as an integer
++ pointer in the @p Value parameter. No actions are defined. */
++static const char pszSleep[] = "Sleep";
++/** Requests the OS to flush it's IO buffers. No actions are defined. */
++static const char pszSioFlush[] = "SioFlush";
++/*@}*/
++
++static const char pszStateChange[] = "StateChange";
++static const char pszStatus[] = "Status";
++
++static const char pszGET[] = "Get";
++static const char pszSET[] = "Set";
++static const char pszCLEAR[] = "Clear";
++static const char pszNULL[] = "";
++static const char pszLocator[] = "Locator";
++static const char pszOff[] = "Off";
++static const char pszOn[] = "On";
++static const char hcMaxFrags[] = "MaxFrags";
++
++#ifdef _CPHAL_CPMAC
++
++/* New method for string constants */
++const char hcClear[] = "Clear";
++const char hcGet[] = "Get";
++const char hcSet[] = "Set";
++
++const char hcTick[] = "Tick";
++
++static const CONTROL_KEY KeyCommon[] =
++ {
++ {"" , enCommonStart},
++ {pszStatus , enStatus},
++ {pszOff , enOff},
++ {pszOn , enOn},
++ {pszDebug , enDebug},
++ {hcCpuFrequency , enCpuFreq}, /*MJH~030403*/
++ {"" , enCommonEnd}
++ };
++#endif
++
++/**
++@defgroup Common_Statistics Statistics
++
++A broad array of module statistics is available. Statistics values are accessed
++through the @c Control() interface of the CPHAL. There are 5 different levels
++of statistics, each of which correspond to a unique set of data. Furthermore,
++certain statistics data is indexed by using a channel number and Tx queue number.
++The following is a brief description of each statistics level, along with the
++indexes used for the level:
++
++- Level 0: Hardware Statistics (index with channel)
++- Level 1: CPHAL Software Statistics (channel, queue)
++- Level 2: CPHAL Flags (channel, queue)
++- Level 3: CPHAL Channel Configuration (channel)
++- Level 4: CPHAL General Configuration (no index)
++
++The caller requests statistics information by providing a Key string to the
++@c Control() API in the following format: "Stats;[Level #];[Ch #];[Queue #]".
++The only valid Action parameter for statistics usage is "Get".
++
++Code Examples:
++@code
++unsigned int *StatsData;
++
++# Get Level 0 stats for Channel 1
++HalFunc->Control(OsDev->HalDev, "Stats;0;1", "Get", &StatsData);
++
++# Get Level 2 stats for Channel 0, Queue 0
++HalFunc->Control(OsDev->HalDev, "Stats;2;0;0", "Get", &StatsData);
++
++# Get Level 4 stats
++HalFunc->Control(OsDev->HalDev, "Stats;4", "Get", &StatsData);
++@endcode
++
++The information returned in the Value parameter of @c Control() is an
++array of pointers to strings. The pointers are arranged in pairs.
++The first pointer is a pointer to a name string for a particular statistic.
++The next pointer is a pointer to a string containing the representation of
++the integer statistic value corresponding to the first pointer. This is followed
++by another pair of pointers, and so on, until a NULL pointer is encountered. The
++following is example code for processing the statistics data. Note that the OS
++is responsible for freeing the memory passed back through the Value parameter of
++@c Control().
++
++@code
++unsigned int *StatsData;
++
++# Get Level 0 stats for Channel 1
++HalFunc->Control(OsDev->HalDev, "Stats;0;1", "Get", &StatsData);
++
++# output Statistics data
++PrintStats(StatsData);
++
++# the upper layer is responsible for freeing stats info
++free(&StatsPtr);
++
++...
++
++void PrintStats(unsigned int *StatsPtr)
++ {
++ while(*StatsPtr)
++ {
++ printf("%20s:", (char *)*StatsPtr);
++ StatsPtr++;
++ printf("%11s\n", (char *)*StatsPtr);
++ StatsPtr++;
++ }
++ MySioFlush();
++ }
++@endcode
++
++Within each statistics level, there are several statistics defined. The statistics that
++are common to every CPPI module are listed below. In addition, each module may define
++extra statistics in each level, which will be documented within the module-specific
++documentation appendices.
++
++- Level 0 Statistics
++ - All level 0 statistics are module-specific.
++- Level 1 Statistics (CPHAL Software Statistics)
++ - DmaLenErrors: Incremented when the port DMA's more data than expected (per channel). (AAL5 Only)
++ - TxMisQCnt: Incremented when host queues a packet for transmission as the port finishes
++transmitting the previous last packet in the queue (per channel and queue).
++ - RxMisQCnt: Incremented when host queues adds buffers to a queue as the port finished the
++reception of the previous last packet in the queue (per channel).
++ - TxEOQCnt: Number of times the port has reached the end of the transmit queue (per channel and queue).
++ - RxEOQCnt: Number of times the port has reached the end of the receive queue (per channel).
++ - RxPacketsServiced: Number of received packets (per channel).
++ - TxPacketsServiced: Number of transmitted packets (per channel and queue).
++ - RxMaxServiced: Maximum number of packets that the CPHAL receive interrupt has serviced at a time (per channel).
++ - TxMaxServiced: Maximum number of packets that the CPHAL transmit interrupt has serviced at a time (per channel and queue).
++ - RxTotal: Total number of received packets, all channels.
++ - TxTotal: Total number of transmitted packets, all channels and queues.
++- Level 2 Statistics (CPHAL Flags)
++ - RcbPool: Pointer to receive descriptor pool (per channel).
++ - RxActQueueCount: Number of buffers currently available for receive (per channel).
++ - RxActQueueHead: Pointer to first buffer in receive queue (per channel).
++ - RxActQueueTail: Pointer to last buffer in receive queue (per channel).
++ - RxActive: 0 if inactive (no buffers available), or 1 if active (buffers available).
++ - RcbStart: Pointer to block of receive descriptors.
++ - RxTeardownPending: 1 if Rx teardown is pending but incomplete, 0 otherwise.
++ - TcbPool: Pointer to transmit descriptor pool (per channel and queue).
++ - TxActQueueCount: Number of buffers currently queued to be transmitted (per channel and queue).
++ - TxActQueueHead: Pointer to first buffer in transmit queue (per channel and queue).
++ - TxActQueueTail: Pointer to last buffer in transmit queue (per channel and queue).
++ - TxActive: 0 if inactive (no buffers to send), or 1 if active (buffers queued to send).
++ - TcbStart: Pointer to block of transmit descriptors.
++ - TxTeardownPending: 1 if Tx teardown is pending but incomplete, 0 otherwise.
++- Level 3 Statistics (CPHAL Channel Configuration)
++ - RxBufSize: Rx buffer size.
++ - RxBufferOffset: Rx buffer offset.
++ - RxNumBuffers: Number of Rx buffers.
++ - RxServiceMax: Maximum number of receive packets to service at a time.
++ - TxNumBuffers: Number of Tx buffer descriptors.
++ - TxNumQueues: Number of Tx queues to use.
++ - TxServiceMax: Maximum number of transmit packets to service at a time.
++- Level 4 Statistics (CPHAL General Configuration)
++ - Base Address: Base address of the module.
++ - Offset (VLYNQ): VLYNQ relative module offset.
++ - Interrupt Line: Interrupt number.
++ - Debug: Debug flag, 1 to enable debug.
++ - Inst: Instance number.
++*/
++
++/*
++ Data Type 0 = int display
++ Data Type 1 = hex display
++ Data Type 2 = channel structure, int display
++ Data Type 3 = queue index and int display
++ Data Type 4 = queue index and hex display
++*/
++#if (defined(_CPHAL_AAL5) || defined(_CPHAL_CPMAC)) /* +GSG 030307 */
++static STATS_TABLE StatsTable0[] =
++ {
++#ifdef _CPHAL_AAL5
++ /* Name , Data Ptr, Data Type */
++ {"Crc Errors", 0, 0},
++ {"Len Errors", 0, 0},
++ {"Abort Errors", 0, 0},
++ {"Starv Errors", 0, 0}
++#endif
++#ifdef _CPHAL_CPMAC
++ {"Rx Good Frames", 0, 0}
++#endif
++ };
++
++static STATS_TABLE StatsTable1[] =
++ {
++ /* Name , Data Ptr, Data Type */
++ {"DmaLenErrors", 0, 0},
++ {"TxMisQCnt", 0, 3},
++ {"RxMisQCnt", 0, 0},
++ {"TxEOQCnt", 0, 3},
++ {"RxEOQCnt", 0, 0},
++ {"RxPacketsServiced", 0, 0},
++ {"TxPacketsServiced", 0, 3},
++ {"RxMaxServiced", 0, 0},
++ {"TxMaxServiced", 0, 3},
++ {"RxTotal", 0, 0},
++ {"TxTotal", 0, 0},
++ };
++
++static STATS_TABLE StatsTable2[] =
++ {
++ /* Name , Data Ptr, Data Type */
++ {"RcbPool", 0, 1},
++ {"RxActQueueCount", 0, 0},
++ {"RxActQueueHead", 0, 1},
++ {"RxActQueueTail", 0, 1},
++ {"RxActive", 0, 0},
++ {"RcbStart", 0, 1},
++ {"RxTeardownPending", 0, 0},
++ {"TcbPool", 0, 4},
++ {"TxActQueueCount", 0, 3},
++ {"TxActQueueHead", 0, 4},
++ {"TxActQueueTail", 0, 4},
++ {"TxActive", 0, 3},
++ {"TcbStart", 0, 4},
++ {"TxTeardownPending", 0, 0}
++ };
++
++static STATS_TABLE StatsTable3[] =
++ {
++ /* Name , Data Ptr, Data Type */
++ {"RxBufSize", 0, 2},
++ {"RxBufferOffset", 0, 2},
++ {"RxNumBuffers", 0, 2},
++ {"RxServiceMax", 0, 2},
++ {"TxNumBuffers", 0, 2},
++ {"TxNumQueues", 0, 2},
++ {"TxServiceMax", 0, 2},
++#ifdef _CPHAL_AAL5
++ {"CpcsUU", 0, 2},
++ {"Gfc", 0, 2},
++ {"Clp", 0, 2},
++ {"Pti", 0, 2},
++ {"DaMask", 0, 2},
++ {"Priority", 0, 2},
++ {"PktType", 0, 2},
++ {"Vci", 0, 2},
++ {"Vpi", 0, 2},
++ {"CellRate", 0, 2},
++ {"QosType", 0, 2},
++ {"Mbs", 0, 2},
++ {"Pcr", 0, 2}
++#endif
++ };
++
++static STATS_TABLE StatsTable4[] =
++ {
++ {"Base Address", 0, 1},
++ {"Offset (VLYNQ)", 0, 0},
++ {"Interrupt Line", 0, 0},
++ {"Debug", 0, 0},
++ {"Instance", 0, 0},
++#ifdef _CPHAL_AAL5
++ {"UniNni", 0, 0}
++#endif
++ };
++
++static STATS_DB StatsDb[] =
++ {
++ {(sizeof(StatsTable0)/sizeof(STATS_TABLE)), StatsTable0},
++ {(sizeof(StatsTable1)/sizeof(STATS_TABLE)), StatsTable1},
++ {(sizeof(StatsTable2)/sizeof(STATS_TABLE)), StatsTable2},
++ {(sizeof(StatsTable3)/sizeof(STATS_TABLE)), StatsTable3},
++ {(sizeof(StatsTable4)/sizeof(STATS_TABLE)), StatsTable4}
++ };
++#endif /* +GSG 030307 */
++
++#ifdef _CPHAL_CPMAC /* +RC 3.02 */
++static void resetWait(HAL_DEVICE *HalDev)
++ { /*+RC3.02*/
++ const int TickReset=64;
++ osfuncSleep((int*)&TickReset);
++ } /*+RC3.02*/
++#endif /* +RC 3.02 */
++
++/* I only define the reset base function for the modules
++ that can perform a reset. The AAL5 and AAL2 modules
++ do not perform a reset, that is done by the shared module
++ CPSAR */
++#if defined(_CPHAL_CPSAR) || defined(_CPHAL_CPMAC) || defined(_CPHAL_VDMAVT)
++/*
++ * Determines the reset register address to be used for a particular device.
++ * It will search the current device entry for Locator information. If the
++ * device is a root device, there will be no Locator information, and the
++ * function will find and return the root reset register. If a Locator value
++ * is found, the function will search each VLYNQ device entry in the system
++ * looking for a matching Locator. Once it finds a VLYNQ device entry with
++ * a matching Locator, it will extract the "ResetBase" parameter from that
++ * VLYNQ device entry (thus every VLYNQ entry must have the ResetBase parameter).
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param ResetBase Pointer to integer address of reset register.
++ *
++ * @return 0 OK, Non-zero not OK
++ */
++static int ResetBaseGet(HAL_DEVICE *HalDev, bit32u *ResetBase)
++ {
++ char *DeviceInfo = HalDev->DeviceInfo;
++ char *MyLocator, *NextLocator;
++ int Inst=1;
++ bit32u error_code;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpcommon]ResetBaseGet(HalDev:%08x, ResetBase:%08x)\n", (bit32u)HalDev, ResetBase);
++ osfuncSioFlush();
++ }
++#endif
++
++ error_code = HalDev->OsFunc->DeviceFindParmValue(DeviceInfo, "Locator", &MyLocator);
++ if (error_code)
++ {
++ /* if no Locator value, device is on the root, so get the "reset" device */
++ error_code = HalDev->OsFunc->DeviceFindInfo(0, "reset", &DeviceInfo);
++ if (error_code)
++ {
++ return(EC_VAL_DEVICE_NOT_FOUND);
++ }
++
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, "base", ResetBase);
++ if (error_code)
++ {
++ return(EC_VAL_BASE_ADDR_NOT_FOUND);
++ }
++
++ *ResetBase = ((bit32u)PhysToVirtNoCache(*ResetBase));
++
++ /* found base address for root device, so we're done */
++ return (EC_NO_ERRORS);
++ }
++ else
++ {
++ /* we have a Locator value, so the device is remote */
++
++ /* Find a vlynq device with a matching locator value */
++ while ((HalDev->OsFunc->DeviceFindInfo(Inst, "vlynq", &DeviceInfo)) == EC_NO_ERRORS)
++ {
++ error_code = HalDev->OsFunc->DeviceFindParmValue(DeviceInfo, "Locator", &NextLocator);
++ if (error_code)
++ {
++ /* no Locator value for this VLYNQ, so move on */
++ continue;
++ }
++ if (HalDev->OsFunc->Strcmpi(MyLocator, NextLocator)==0)
++ {
++ /* we have found a VLYNQ with a matching Locator, so extract the ResetBase */
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, "ResetBase", ResetBase);
++ if (error_code)
++ {
++ return(EC_VAL_BASE_ADDR_NOT_FOUND);
++ }
++ *ResetBase = ((bit32u)PhysToVirtNoCache(*ResetBase));
++
++ /* found base address for root device, so we're done */
++ return (EC_NO_ERRORS);
++ }
++ Inst++;
++ } /* while */
++ } /* else */
++
++ return (EC_NO_ERRORS);
++ }
++#endif
++
++#ifndef _CPHAL_AAL2 /* + RC 3.02 */
++static bit32u ConfigGetCommon(HAL_DEVICE *HalDev)
++ {
++ bit32u ParmValue;
++ bit32 error_code;
++ char *DeviceInfo = HalDev->DeviceInfo;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpcommon]ConfigGetCommon(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszBase, &ParmValue);
++ if (error_code)
++ {
++ return(EC_FUNC_HAL_INIT|EC_VAL_BASE_ADDR_NOT_FOUND);
++ }
++ HalDev->dev_base = ((bit32u)PhysToVirtNoCache(ParmValue));
++
++#ifndef _CPHAL_AAL5
++#ifndef _CPHAL_AAL2
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszResetBit, &ParmValue);
++ if(error_code)
++ {
++ return(EC_FUNC_HAL_INIT|EC_VAL_RESET_BIT_NOT_FOUND);
++ }
++ HalDev->ResetBit = ParmValue;
++
++ /* Get reset base address */
++ error_code = ResetBaseGet(HalDev, &ParmValue);
++ if (error_code)
++ return(EC_FUNC_HAL_INIT|EC_VAL_RESET_BASE_NOT_FOUND);
++ HalDev->ResetBase = ParmValue;
++#endif
++#endif
++
++#ifndef _CPHAL_CPSAR
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszIntLine,&ParmValue);
++ if (error_code)
++ {
++ return(EC_FUNC_HAL_INIT|EC_VAL_INTERRUPT_NOT_FOUND);
++ }
++ HalDev->interrupt = ParmValue;
++#endif
++
++ /* only look for the offset if there is a Locator field, which indicates that
++ the module is a VLYNQ module */
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszLocator,&ParmValue);
++ if (!error_code)
++ {
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszOffset,&ParmValue);
++ if (error_code)
++ {
++ return(EC_FUNC_HAL_INIT|EC_VAL_OFFSET_NOT_FOUND);
++ }
++ HalDev->offset = ParmValue;
++ }
++ else
++ HalDev->offset = 0;
++
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszDebug, &ParmValue);
++ if (!error_code) HalDev->debug = ParmValue;
++
++ return (EC_NO_ERRORS);
++ }
++#endif /* +RC 3.02 */
++
++#ifdef _CPHAL_CPMAC /* +RC 3.02 */
++static void StatsInit(HAL_DEVICE *HalDev) /* +() RC3.02 */
++ {
++ /* even though these statistics may be for multiple channels and
++ queues, i need only configure the pointer to the beginning
++ of the array, and I can index from there if necessary */
++
++#ifdef _CPHAL_AAL5
++ StatsTable0[0].StatPtr = &HalDev->Stats.CrcErrors[0];
++ StatsTable0[1].StatPtr = &HalDev->Stats.LenErrors[0];
++ StatsTable0[2].StatPtr = &HalDev->Stats.AbortErrors[0];
++ StatsTable0[3].StatPtr = &HalDev->Stats.StarvErrors[0];
++
++ StatsTable1[0].StatPtr = &HalDev->Stats.DmaLenErrors[0];
++ StatsTable1[1].StatPtr = &HalDev->Stats.TxMisQCnt[0][0];
++ StatsTable1[2].StatPtr = &HalDev->Stats.RxMisQCnt[0];
++ StatsTable1[3].StatPtr = &HalDev->Stats.TxEOQCnt[0][0];
++ StatsTable1[4].StatPtr = &HalDev->Stats.RxEOQCnt[0];
++ StatsTable1[5].StatPtr = &HalDev->Stats.RxPacketsServiced[0];
++ StatsTable1[6].StatPtr = &HalDev->Stats.TxPacketsServiced[0][0];
++ StatsTable1[7].StatPtr = &HalDev->Stats.RxMaxServiced;
++ StatsTable1[8].StatPtr = &HalDev->Stats.TxMaxServiced[0][0];
++ StatsTable1[9].StatPtr = &HalDev->Stats.RxTotal;
++ StatsTable1[10].StatPtr = &HalDev->Stats.TxTotal;
++#endif
++
++#if (defined(_CPHAL_AAL5) || defined(_CPHAL_CPMAC))
++ StatsTable2[0].StatPtr = (bit32u *)&HalDev->RcbPool[0];
++ StatsTable2[1].StatPtr = &HalDev->RxActQueueCount[0];
++ StatsTable2[2].StatPtr = (bit32u *)&HalDev->RxActQueueHead[0];
++ StatsTable2[3].StatPtr = (bit32u *)&HalDev->RxActQueueTail[0];
++ StatsTable2[4].StatPtr = &HalDev->RxActive[0];
++ StatsTable2[5].StatPtr = (bit32u *)&HalDev->RcbStart[0];
++ StatsTable2[6].StatPtr = &HalDev->RxTeardownPending[0];
++ StatsTable2[7].StatPtr = (bit32u *)&HalDev->TcbPool[0][0];
++ StatsTable2[8].StatPtr = &HalDev->TxActQueueCount[0][0];
++ StatsTable2[9].StatPtr = (bit32u *)&HalDev->TxActQueueHead[0][0];
++ StatsTable2[10].StatPtr = (bit32u *)&HalDev->TxActQueueTail[0][0];
++ StatsTable2[11].StatPtr = &HalDev->TxActive[0][0];
++ StatsTable2[12].StatPtr = (bit32u *)&HalDev->TcbStart[0][0];
++ StatsTable2[13].StatPtr = &HalDev->TxTeardownPending[0];
++
++ StatsTable3[0].StatPtr = &HalDev->ChData[0].RxBufSize;
++ StatsTable3[1].StatPtr = &HalDev->ChData[0].RxBufferOffset;
++ StatsTable3[2].StatPtr = &HalDev->ChData[0].RxNumBuffers;
++ StatsTable3[3].StatPtr = &HalDev->ChData[0].RxServiceMax;
++ StatsTable3[4].StatPtr = &HalDev->ChData[0].TxNumBuffers;
++ StatsTable3[5].StatPtr = &HalDev->ChData[0].TxNumQueues;
++ StatsTable3[6].StatPtr = &HalDev->ChData[0].TxServiceMax;
++#ifdef _CPHAL_AAL5
++ StatsTable3[7].StatPtr = &HalDev->ChData[0].CpcsUU;
++ StatsTable3[8].StatPtr = &HalDev->ChData[0].Gfc;
++ StatsTable3[9].StatPtr = &HalDev->ChData[0].Clp;
++ StatsTable3[10].StatPtr = &HalDev->ChData[0].Pti;
++ StatsTable3[11].StatPtr = &HalDev->ChData[0].DaMask;
++ StatsTable3[12].StatPtr = &HalDev->ChData[0].Priority;
++ StatsTable3[13].StatPtr = &HalDev->ChData[0].PktType;
++ StatsTable3[14].StatPtr = &HalDev->ChData[0].Vci;
++ StatsTable3[15].StatPtr = &HalDev->ChData[0].Vpi;
++ StatsTable3[16].StatPtr = &HalDev->ChData[0].TxVc_CellRate;
++ StatsTable3[17].StatPtr = &HalDev->ChData[0].TxVc_QosType;
++ StatsTable3[18].StatPtr = &HalDev->ChData[0].TxVc_Mbs;
++ StatsTable3[19].StatPtr = &HalDev->ChData[0].TxVc_Pcr;
++#endif
++#endif
++
++ StatsTable4[0].StatPtr = &HalDev->dev_base;
++ StatsTable4[1].StatPtr = &HalDev->offset;
++ StatsTable4[2].StatPtr = &HalDev->interrupt;
++ StatsTable4[3].StatPtr = &HalDev->debug;
++ StatsTable4[4].StatPtr = &HalDev->Inst;
++ }
++#endif /* +RC 3.02 */
++
++#ifndef _CPHAL_CPSAR /* +RC 3.02 */
++#ifndef _CPHAL_AAL2 /* +RC 3.02 */
++/*
++ * Returns statistics information.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ *
++ * @return 0
++ */
++static int StatsGet(HAL_DEVICE *HalDev, void **StatPtr, int Index, int Ch, int Queue)
++ {
++ int Size;
++ bit32u *AddrPtr;
++ char *DataPtr;
++ STATS_TABLE *StatsTable;
++ int i, NumberOfStats;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpcommon]StatsGet(HalDev:%08x, StatPtr:%08x)\n",
++ (bit32u)HalDev, (bit32u)StatPtr);
++ osfuncSioFlush();
++ }
++#endif
++
++ StatsTable = StatsDb[Index].StatTable;
++ NumberOfStats = StatsDb[Index].NumberOfStats;
++
++ Size = sizeof(bit32u)*((NumberOfStats*2)+1);
++ Size += (NumberOfStats*11);
++ *StatPtr = (bit32u *)HalDev->OsFunc->Malloc(Size);
++
++ AddrPtr = (bit32u *) *StatPtr;
++ DataPtr = (char *)AddrPtr;
++ DataPtr += sizeof(bit32u)*((NumberOfStats*2)+1);
++
++ for (i=0; i<NumberOfStats; i++)
++ {
++ *AddrPtr++ = (bit32u)StatsTable[i].StatName;
++ *AddrPtr++ = (bit32u)DataPtr;
++ if (&StatsTable[i].StatPtr[Ch] != 0)
++ {
++ switch(StatsTable[i].DataType)
++ {
++ case 0:
++ HalDev->OsFunc->Sprintf(DataPtr, "%d", (bit32u *)StatsTable[i].StatPtr[Ch]);
++ break;
++ case 1:
++ HalDev->OsFunc->Sprintf(DataPtr, "0x%x", (bit32u *)StatsTable[i].StatPtr[Ch]);
++ break;
++ case 2:
++ HalDev->OsFunc->Sprintf(DataPtr, "%d", *((bit32u *)StatsTable[i].StatPtr + (Ch * (sizeof(CHANNEL_INFO)/4))));
++ break;
++ case 3:
++ HalDev->OsFunc->Sprintf(DataPtr, "%d", *((bit32u *)StatsTable[i].StatPtr + (Ch*MAX_QUEUE)+Queue));
++ break;
++ case 4:
++ HalDev->OsFunc->Sprintf(DataPtr, "0x%x", *((bit32u *)StatsTable[i].StatPtr + (Ch*MAX_QUEUE)+Queue));
++ break;
++ default:
++ /* invalid data type, due to CPHAL programming error */
++ break;
++ }
++ }
++ else
++ {
++ /* invalid statistics pointer, probably was not initialized */
++ }
++ DataPtr += HalDev->OsFunc->Strlen(DataPtr) + 1;
++ }
++
++ *AddrPtr = (bit32u) 0;
++
++ return (EC_NO_ERRORS);
++ }
++#endif /* +RC 3.02 */
++#endif /* +RC 3.02 */
++
++#ifdef _CPHAL_CPMAC
++static void gpioFunctional(int base, int bit)
++ { /*+RC3.02*/
++ bit32u GpioEnr = base + 0xC;
++ /* To make functional, set to zero */
++ *(volatile bit32u *)(GpioEnr) &= ~(1 << bit); /*+RC3.02*/
++ } /*+RC3.02*/
++
++
++/*+RC3.02*/
++/* Common function, Checks to see if GPIO should be in functional mode */
++static void gpioCheck(HAL_DEVICE *HalDev, void *moduleDeviceInfo)
++ { /*+RC3.02*/
++ int rc;
++ void *DeviceInfo;
++ char *pszMuxBits;
++ char pszMuxBit[20];
++ char *pszTmp;
++ char szMuxBit[20];
++ char *ptr;
++ int base;
++ int reset_bit;
++ int bit;
++ OS_FUNCTIONS *OsFunc = HalDev->OsFunc;
++
++ rc = OsFunc->DeviceFindParmValue(moduleDeviceInfo, "gpio_mux",&pszTmp);
++ if(rc) return;
++ /* gpio entry found, get GPIO register info and make functional */
++
++ /* temp copy until FinParmValue fixed */
++ ptr = &szMuxBit[0];
++ while ((*ptr++ = *pszTmp++));
++
++ pszMuxBits = &szMuxBit[0];
++
++ rc = OsFunc->DeviceFindInfo(0,"gpio",&DeviceInfo);
++ if(rc) return;
++
++ rc = OsFunc->DeviceFindParmUint(DeviceInfo, "base",&base);
++ if(rc) return;
++
++ rc = OsFunc->DeviceFindParmUint(DeviceInfo, "reset_bit",&reset_bit);
++ if(rc) return;
++
++ /* If GPIO still in reset, then exit */
++ if((VOLATILE32(HalDev->ResetBase) & (1 << reset_bit)) == 0)
++ return;
++ /* format for gpio_mux is gpio_mux = <int>;<int>;<int>...*/
++ while (*pszMuxBits)
++ {
++ pszTmp = &pszMuxBit[0];
++ if(*pszMuxBits == ';') pszMuxBits++;
++ while ((*pszMuxBits != ';') && (*pszMuxBits != '\0'))
++ {
++ osfuncSioFlush();
++ /*If value not a number, skip */
++ if((*pszMuxBits < '0') || (*pszMuxBits > '9'))
++ pszMuxBits++;
++ else
++ *pszTmp++ = *pszMuxBits++;
++ }
++ *pszTmp = '\0';
++ bit = OsFunc->Strtoul(pszMuxBit, &pszTmp, 10);
++ gpioFunctional(base, bit);
++ resetWait(HalDev); /* not sure if this is needed */
++ }
++ } /*+RC3.02*/
++#endif /* CPMAC */
++
++#ifdef _CPHAL_AAL5
++const char hcSarFrequency[] = "SarFreq";
++#endif
++
++#endif /* _INC */
+diff -urN linux.old/drivers/atm/sangam_atm/cpcommon_cpaal5.h linux.dev/drivers/atm/sangam_atm/cpcommon_cpaal5.h
+--- linux.old/drivers/atm/sangam_atm/cpcommon_cpaal5.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/cpcommon_cpaal5.h 2005-08-23 04:46:50.082845976 +0200
+@@ -0,0 +1,79 @@
++#ifndef _INC_CPCOMMON_H
++#define _INC_CPCOMMON_H
++
++#define VOLATILE32(addr) (*(volatile bit32u *)(addr))
++#ifndef dbgPrintf
++#define dbgPrintf HalDev->OsFunc->Printf
++#endif
++
++#define ChannelUpdate(Field) if(HalChn->Field != 0xFFFFFFFF) HalDev->ChData[Ch].Field = HalChn->Field
++
++#define DBG(level) (HalDev->debug & (1<<(level)))
++/*
++#define DBG0() DBG(0)
++#define DBG1() DBG(1)
++#define DBG2() DBG(2)
++#define DBG3() DBG(3)
++#define DBG4() DBG(4)
++#define DBG5() DBG(5)
++#define DBG6() DBG(6)
++#define DBG7() DBG(7)
++*/
++
++/*
++ * List of defined actions for use with Control().
++ */
++typedef enum
++ {
++ enGET=0, /**< Get the value associated with a key */
++ enSET, /**< Set the value associates with a key */
++ enCLEAR, /**<Clear the value */
++ enNULL /**< No data action, used to initiate a service or send a message */
++ }ACTION;
++
++/*
++ * Enumerated hardware states.
++ */
++typedef enum
++ {
++ enConnected=1, enDevFound, enInitialized, enOpened
++ }DEVICE_STATE;
++
++typedef enum
++ {
++ enCommonStart=0,
++ /* General */
++ enOff, enOn, enDebug,
++ /* Module General */
++ enCpuFreq,
++ enStatus,
++ enCommonEnd
++ }COMMON_KEY;
++
++typedef struct
++ {
++ const char *strKey;
++ int enKey;
++ }CONTROL_KEY;
++
++typedef struct
++ {
++ char *StatName;
++ unsigned int *StatPtr;
++ int DataType; /* 0: int, 1: hex int, 2:channel data */
++ }STATS_TABLE;
++
++typedef struct
++ {
++ int NumberOfStats;
++ STATS_TABLE *StatTable;
++ }STATS_DB;
++
++#define osfuncSioFlush() HalDev->OsFunc->Control(HalDev->OsDev,"SioFlush",pszNULL,0)
++#define osfuncSleep(Ticks) HalDev->OsFunc->Control(HalDev->OsDev,pszSleep,pszNULL,Ticks)
++#define osfuncStateChange() HalDev->OsFunc->Control(HalDev->OsDev,pszStateChange,pszNULL,0)
++
++#define CHANNEL_NAMES {"Ch0","Ch1","Ch2","Ch3","Ch4","Ch5","Ch6","Ch7","Ch8","Ch9","Ch10","Ch11","Ch12","Ch13","Ch14","Ch15"}
++
++#endif
++
+diff -urN linux.old/drivers/atm/sangam_atm/cpcommon_cpsar.c linux.dev/drivers/atm/sangam_atm/cpcommon_cpsar.c
+--- linux.old/drivers/atm/sangam_atm/cpcommon_cpsar.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/cpcommon_cpsar.c 2005-08-23 04:46:50.082845976 +0200
+@@ -0,0 +1,728 @@
++#ifndef _INC_CPCOMMON_C
++#define _INC_CPCOMMON_C
++
++#ifdef _CPHAL_CPMAC
++#include "cpremap_cpmac.c"
++#endif
++
++#ifdef _CPHAL_AAL5
++#include "cpremap_cpaal5.c"
++#endif
++
++#ifdef _CPHAL_CPSAR
++#include "cpremap_cpsar.c"
++#endif
++
++#ifdef _CPHAL_AAL2
++#include "cpremap_cpaal2.c"
++#endif
++
++/**
++@defgroup Common_Config_Params Common Configuration Parameters
++
++This section documents the configuration parameters that are valid across
++all CPHAL devices.
++@{
++*/
++/** This is the debug level. The field is bit defined, such that the user
++should set to 1 all the bits corresponding to desired debug outputs. The following
++are the meanings for each debug bit:
++- bit0 (LSB): CPHAL Function Trace
++- b1 : OS Function call trace
++- b2 : Critical section entry/exit
++- b3 : Memory allocation/destruction
++- b4 : Detailed information in Rx path
++- b5 : Detailed information in Tx path
++- b6 : Extended error information
++- b7 : General info
++*/
++static const char pszDebug[] = "debug";
++/** CPU Frequency. */
++/*static const char pszCpuFreq[] = "CpuFreq";*/ /*MJH-030403*/
++/** Base address for the module. */
++static const char pszBase[] = "base";
++/** Reset bit for the module. */
++static const char pszResetBit[] = "reset_bit";
++/** Reset base address for the module. */
++static const char pszResetBase[] = "ResetBase";
++/** Interrupt line for the module. */
++static const char pszIntLine[] = "int_line";
++/** VLYNQ offset for the module. Disregard if not using VLYNQ. */
++static const char pszOffset[] = "offset";
++/** The OS may "Get" this parameter, which is a pointer
++ to a character string that indicates the version of CPHAL. */
++static const char pszVer[] = "Version";
++/*@}*/
++
++/**
++@defgroup Common_Control_Params Common Keys for [os]Control()
++
++This section documents the keys used with the OS @c Control() interface that
++are required by CPHAL devices.
++
++@{
++*/
++/** Used to wait for an integer number of clock ticks, given as an integer
++ pointer in the @p Value parameter. No actions are defined. */
++static const char pszSleep[] = "Sleep";
++/** Requests the OS to flush it's IO buffers. No actions are defined. */
++static const char pszSioFlush[] = "SioFlush";
++/*@}*/
++
++static const char pszStateChange[] = "StateChange";
++static const char pszStatus[] = "Status";
++
++static const char pszGET[] = "Get";
++static const char pszSET[] = "Set";
++static const char pszCLEAR[] = "Clear";
++static const char pszNULL[] = "";
++static const char pszLocator[] = "Locator";
++static const char pszOff[] = "Off";
++static const char pszOn[] = "On";
++static const char hcMaxFrags[] = "MaxFrags";
++
++#ifdef _CPHAL_CPMAC
++
++/* New method for string constants */
++const char hcClear[] = "Clear";
++const char hcGet[] = "Get";
++const char hcSet[] = "Set";
++
++const char hcTick[] = "Tick";
++
++static const CONTROL_KEY KeyCommon[] =
++ {
++ {"" , enCommonStart},
++ {pszStatus , enStatus},
++ {pszOff , enOff},
++ {pszOn , enOn},
++ {pszDebug , enDebug},
++ {hcCpuFrequency , enCpuFreq}, /*MJH~030403*/
++ {"" , enCommonEnd}
++ };
++#endif
++
++/**
++@defgroup Common_Statistics Statistics
++
++A broad array of module statistics is available. Statistics values are accessed
++through the @c Control() interface of the CPHAL. There are 5 different levels
++of statistics, each of which correspond to a unique set of data. Furthermore,
++certain statistics data is indexed by using a channel number and Tx queue number.
++The following is a brief description of each statistics level, along with the
++indexes used for the level:
++
++- Level 0: Hardware Statistics (index with channel)
++- Level 1: CPHAL Software Statistics (channel, queue)
++- Level 2: CPHAL Flags (channel, queue)
++- Level 3: CPHAL Channel Configuration (channel)
++- Level 4: CPHAL General Configuration (no index)
++
++The caller requests statistics information by providing a Key string to the
++@c Control() API in the following format: "Stats;[Level #];[Ch #];[Queue #]".
++The only valid Action parameter for statistics usage is "Get".
++
++Code Examples:
++@code
++unsigned int *StatsData;
++
++# Get Level 0 stats for Channel 1
++HalFunc->Control(OsDev->HalDev, "Stats;0;1", "Get", &StatsData);
++
++# Get Level 2 stats for Channel 0, Queue 0
++HalFunc->Control(OsDev->HalDev, "Stats;2;0;0", "Get", &StatsData);
++
++# Get Level 4 stats
++HalFunc->Control(OsDev->HalDev, "Stats;4", "Get", &StatsData);
++@endcode
++
++The information returned in the Value parameter of @c Control() is an
++array of pointers to strings. The pointers are arranged in pairs.
++The first pointer is a pointer to a name string for a particular statistic.
++The next pointer is a pointer to a string containing the representation of
++the integer statistic value corresponding to the first pointer. This is followed
++by another pair of pointers, and so on, until a NULL pointer is encountered. The
++following is example code for processing the statistics data. Note that the OS
++is responsible for freeing the memory passed back through the Value parameter of
++@c Control().
++
++@code
++unsigned int *StatsData;
++
++# Get Level 0 stats for Channel 1
++HalFunc->Control(OsDev->HalDev, "Stats;0;1", "Get", &StatsData);
++
++# output Statistics data
++PrintStats(StatsData);
++
++# the upper layer is responsible for freeing stats info
++free(&StatsPtr);
++
++...
++
++void PrintStats(unsigned int *StatsPtr)
++ {
++ while(*StatsPtr)
++ {
++ printf("%20s:", (char *)*StatsPtr);
++ StatsPtr++;
++ printf("%11s\n", (char *)*StatsPtr);
++ StatsPtr++;
++ }
++ MySioFlush();
++ }
++@endcode
++
++Within each statistics level, there are several statistics defined. The statistics that
++are common to every CPPI module are listed below. In addition, each module may define
++extra statistics in each level, which will be documented within the module-specific
++documentation appendices.
++
++- Level 0 Statistics
++ - All level 0 statistics are module-specific.
++- Level 1 Statistics (CPHAL Software Statistics)
++ - DmaLenErrors: Incremented when the port DMA's more data than expected (per channel). (AAL5 Only)
++ - TxMisQCnt: Incremented when host queues a packet for transmission as the port finishes
++transmitting the previous last packet in the queue (per channel and queue).
++ - RxMisQCnt: Incremented when host queues adds buffers to a queue as the port finished the
++reception of the previous last packet in the queue (per channel).
++ - TxEOQCnt: Number of times the port has reached the end of the transmit queue (per channel and queue).
++ - RxEOQCnt: Number of times the port has reached the end of the receive queue (per channel).
++ - RxPacketsServiced: Number of received packets (per channel).
++ - TxPacketsServiced: Number of transmitted packets (per channel and queue).
++ - RxMaxServiced: Maximum number of packets that the CPHAL receive interrupt has serviced at a time (per channel).
++ - TxMaxServiced: Maximum number of packets that the CPHAL transmit interrupt has serviced at a time (per channel and queue).
++ - RxTotal: Total number of received packets, all channels.
++ - TxTotal: Total number of transmitted packets, all channels and queues.
++- Level 2 Statistics (CPHAL Flags)
++ - RcbPool: Pointer to receive descriptor pool (per channel).
++ - RxActQueueCount: Number of buffers currently available for receive (per channel).
++ - RxActQueueHead: Pointer to first buffer in receive queue (per channel).
++ - RxActQueueTail: Pointer to last buffer in receive queue (per channel).
++ - RxActive: 0 if inactive (no buffers available), or 1 if active (buffers available).
++ - RcbStart: Pointer to block of receive descriptors.
++ - RxTeardownPending: 1 if Rx teardown is pending but incomplete, 0 otherwise.
++ - TcbPool: Pointer to transmit descriptor pool (per channel and queue).
++ - TxActQueueCount: Number of buffers currently queued to be transmitted (per channel and queue).
++ - TxActQueueHead: Pointer to first buffer in transmit queue (per channel and queue).
++ - TxActQueueTail: Pointer to last buffer in transmit queue (per channel and queue).
++ - TxActive: 0 if inactive (no buffers to send), or 1 if active (buffers queued to send).
++ - TcbStart: Pointer to block of transmit descriptors.
++ - TxTeardownPending: 1 if Tx teardown is pending but incomplete, 0 otherwise.
++- Level 3 Statistics (CPHAL Channel Configuration)
++ - RxBufSize: Rx buffer size.
++ - RxBufferOffset: Rx buffer offset.
++ - RxNumBuffers: Number of Rx buffers.
++ - RxServiceMax: Maximum number of receive packets to service at a time.
++ - TxNumBuffers: Number of Tx buffer descriptors.
++ - TxNumQueues: Number of Tx queues to use.
++ - TxServiceMax: Maximum number of transmit packets to service at a time.
++- Level 4 Statistics (CPHAL General Configuration)
++ - Base Address: Base address of the module.
++ - Offset (VLYNQ): VLYNQ relative module offset.
++ - Interrupt Line: Interrupt number.
++ - Debug: Debug flag, 1 to enable debug.
++ - Inst: Instance number.
++*/
++
++/*
++ Data Type 0 = int display
++ Data Type 1 = hex display
++ Data Type 2 = channel structure, int display
++ Data Type 3 = queue index and int display
++ Data Type 4 = queue index and hex display
++*/
++#if (defined(_CPHAL_AAL5) || defined(_CPHAL_CPMAC)) /* +GSG 030307 */
++static STATS_TABLE StatsTable0[] =
++ {
++#ifdef _CPHAL_AAL5
++ /* Name , Data Ptr, Data Type */
++ {"Crc Errors", 0, 0},
++ {"Len Errors", 0, 0},
++ {"Abort Errors", 0, 0},
++ {"Starv Errors", 0, 0}
++#endif
++#ifdef _CPHAL_CPMAC
++ {"Rx Good Frames", 0, 0}
++#endif
++ };
++
++static STATS_TABLE StatsTable1[] =
++ {
++ /* Name , Data Ptr, Data Type */
++ {"DmaLenErrors", 0, 0},
++ {"TxMisQCnt", 0, 3},
++ {"RxMisQCnt", 0, 0},
++ {"TxEOQCnt", 0, 3},
++ {"RxEOQCnt", 0, 0},
++ {"RxPacketsServiced", 0, 0},
++ {"TxPacketsServiced", 0, 3},
++ {"RxMaxServiced", 0, 0},
++ {"TxMaxServiced", 0, 3},
++ {"RxTotal", 0, 0},
++ {"TxTotal", 0, 0},
++ };
++
++static STATS_TABLE StatsTable2[] =
++ {
++ /* Name , Data Ptr, Data Type */
++ {"RcbPool", 0, 1},
++ {"RxActQueueCount", 0, 0},
++ {"RxActQueueHead", 0, 1},
++ {"RxActQueueTail", 0, 1},
++ {"RxActive", 0, 0},
++ {"RcbStart", 0, 1},
++ {"RxTeardownPending", 0, 0},
++ {"TcbPool", 0, 4},
++ {"TxActQueueCount", 0, 3},
++ {"TxActQueueHead", 0, 4},
++ {"TxActQueueTail", 0, 4},
++ {"TxActive", 0, 3},
++ {"TcbStart", 0, 4},
++ {"TxTeardownPending", 0, 0}
++ };
++
++static STATS_TABLE StatsTable3[] =
++ {
++ /* Name , Data Ptr, Data Type */
++ {"RxBufSize", 0, 2},
++ {"RxBufferOffset", 0, 2},
++ {"RxNumBuffers", 0, 2},
++ {"RxServiceMax", 0, 2},
++ {"TxNumBuffers", 0, 2},
++ {"TxNumQueues", 0, 2},
++ {"TxServiceMax", 0, 2},
++#ifdef _CPHAL_AAL5
++ {"CpcsUU", 0, 2},
++ {"Gfc", 0, 2},
++ {"Clp", 0, 2},
++ {"Pti", 0, 2},
++ {"DaMask", 0, 2},
++ {"Priority", 0, 2},
++ {"PktType", 0, 2},
++ {"Vci", 0, 2},
++ {"Vpi", 0, 2},
++ {"CellRate", 0, 2},
++ {"QosType", 0, 2},
++ {"Mbs", 0, 2},
++ {"Pcr", 0, 2}
++#endif
++ };
++
++static STATS_TABLE StatsTable4[] =
++ {
++ {"Base Address", 0, 1},
++ {"Offset (VLYNQ)", 0, 0},
++ {"Interrupt Line", 0, 0},
++ {"Debug", 0, 0},
++ {"Instance", 0, 0},
++#ifdef _CPHAL_AAL5
++ {"UniNni", 0, 0}
++#endif
++ };
++
++static STATS_DB StatsDb[] =
++ {
++ {(sizeof(StatsTable0)/sizeof(STATS_TABLE)), StatsTable0},
++ {(sizeof(StatsTable1)/sizeof(STATS_TABLE)), StatsTable1},
++ {(sizeof(StatsTable2)/sizeof(STATS_TABLE)), StatsTable2},
++ {(sizeof(StatsTable3)/sizeof(STATS_TABLE)), StatsTable3},
++ {(sizeof(StatsTable4)/sizeof(STATS_TABLE)), StatsTable4}
++ };
++#endif /* +GSG 030307 */
++
++#ifdef _CPHAL_CPMAC /* +RC 3.02 */
++static void resetWait(HAL_DEVICE *HalDev)
++ { /*+RC3.02*/
++ const int TickReset=64;
++ osfuncSleep((int*)&TickReset);
++ } /*+RC3.02*/
++#endif /* +RC 3.02 */
++
++/* I only define the reset base function for the modules
++ that can perform a reset. The AAL5 and AAL2 modules
++ do not perform a reset, that is done by the shared module
++ CPSAR */
++#if defined(_CPHAL_CPSAR) || defined(_CPHAL_CPMAC) || defined(_CPHAL_VDMAVT)
++/*
++ * Determines the reset register address to be used for a particular device.
++ * It will search the current device entry for Locator information. If the
++ * device is a root device, there will be no Locator information, and the
++ * function will find and return the root reset register. If a Locator value
++ * is found, the function will search each VLYNQ device entry in the system
++ * looking for a matching Locator. Once it finds a VLYNQ device entry with
++ * a matching Locator, it will extract the "ResetBase" parameter from that
++ * VLYNQ device entry (thus every VLYNQ entry must have the ResetBase parameter).
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param ResetBase Pointer to integer address of reset register.
++ *
++ * @return 0 OK, Non-zero not OK
++ */
++static int ResetBaseGet(HAL_DEVICE *HalDev, bit32u *ResetBase)
++ {
++ char *DeviceInfo = HalDev->DeviceInfo;
++ char *MyLocator, *NextLocator;
++ int Inst=1;
++ bit32u error_code;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpcommon]ResetBaseGet(HalDev:%08x, ResetBase:%08x)\n", (bit32u)HalDev, ResetBase);
++ osfuncSioFlush();
++ }
++#endif
++
++ error_code = HalDev->OsFunc->DeviceFindParmValue(DeviceInfo, "Locator", &MyLocator);
++ if (error_code)
++ {
++ /* if no Locator value, device is on the root, so get the "reset" device */
++ error_code = HalDev->OsFunc->DeviceFindInfo(0, "reset", &DeviceInfo);
++ if (error_code)
++ {
++ return(EC_VAL_DEVICE_NOT_FOUND);
++ }
++
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, "base", ResetBase);
++ if (error_code)
++ {
++ return(EC_VAL_BASE_ADDR_NOT_FOUND);
++ }
++
++ *ResetBase = ((bit32u)PhysToVirtNoCache(*ResetBase));
++
++ /* found base address for root device, so we're done */
++ return (EC_NO_ERRORS);
++ }
++ else
++ {
++ /* we have a Locator value, so the device is remote */
++
++ /* Find a vlynq device with a matching locator value */
++ while ((HalDev->OsFunc->DeviceFindInfo(Inst, "vlynq", &DeviceInfo)) == EC_NO_ERRORS)
++ {
++ error_code = HalDev->OsFunc->DeviceFindParmValue(DeviceInfo, "Locator", &NextLocator);
++ if (error_code)
++ {
++ /* no Locator value for this VLYNQ, so move on */
++ continue;
++ }
++ if (HalDev->OsFunc->Strcmpi(MyLocator, NextLocator)==0)
++ {
++ /* we have found a VLYNQ with a matching Locator, so extract the ResetBase */
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, "ResetBase", ResetBase);
++ if (error_code)
++ {
++ return(EC_VAL_BASE_ADDR_NOT_FOUND);
++ }
++ *ResetBase = ((bit32u)PhysToVirtNoCache(*ResetBase));
++
++ /* found base address for root device, so we're done */
++ return (EC_NO_ERRORS);
++ }
++ Inst++;
++ } /* while */
++ } /* else */
++
++ return (EC_NO_ERRORS);
++ }
++#endif
++
++#ifndef _CPHAL_AAL2 /* + RC 3.02 */
++static bit32u ConfigGetCommon(HAL_DEVICE *HalDev)
++ {
++ bit32u ParmValue;
++ bit32 error_code;
++ char *DeviceInfo = HalDev->DeviceInfo;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpcommon]ConfigGetCommon(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszBase, &ParmValue);
++ if (error_code)
++ {
++ return(EC_FUNC_HAL_INIT|EC_VAL_BASE_ADDR_NOT_FOUND);
++ }
++ HalDev->dev_base = ((bit32u)PhysToVirtNoCache(ParmValue));
++
++#ifndef _CPHAL_AAL5
++#ifndef _CPHAL_AAL2
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszResetBit, &ParmValue);
++ if(error_code)
++ {
++ return(EC_FUNC_HAL_INIT|EC_VAL_RESET_BIT_NOT_FOUND);
++ }
++ HalDev->ResetBit = ParmValue;
++
++ /* Get reset base address */
++ error_code = ResetBaseGet(HalDev, &ParmValue);
++ if (error_code)
++ return(EC_FUNC_HAL_INIT|EC_VAL_RESET_BASE_NOT_FOUND);
++ HalDev->ResetBase = ParmValue;
++#endif
++#endif
++
++#ifndef _CPHAL_CPSAR
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszIntLine,&ParmValue);
++ if (error_code)
++ {
++ return(EC_FUNC_HAL_INIT|EC_VAL_INTERRUPT_NOT_FOUND);
++ }
++ HalDev->interrupt = ParmValue;
++#endif
++
++ /* only look for the offset if there is a Locator field, which indicates that
++ the module is a VLYNQ module */
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszLocator,&ParmValue);
++ if (!error_code)
++ {
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszOffset,&ParmValue);
++ if (error_code)
++ {
++ return(EC_FUNC_HAL_INIT|EC_VAL_OFFSET_NOT_FOUND);
++ }
++ HalDev->offset = ParmValue;
++ }
++ else
++ HalDev->offset = 0;
++
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo, pszDebug, &ParmValue);
++ if (!error_code) HalDev->debug = ParmValue;
++
++ return (EC_NO_ERRORS);
++ }
++#endif /* +RC 3.02 */
++
++#ifdef _CPHAL_CPMAC /* +RC 3.02 */
++static void StatsInit(HAL_DEVICE *HalDev) /* +() RC3.02 */
++ {
++ /* even though these statistics may be for multiple channels and
++ queues, i need only configure the pointer to the beginning
++ of the array, and I can index from there if necessary */
++
++#ifdef _CPHAL_AAL5
++ StatsTable0[0].StatPtr = &HalDev->Stats.CrcErrors[0];
++ StatsTable0[1].StatPtr = &HalDev->Stats.LenErrors[0];
++ StatsTable0[2].StatPtr = &HalDev->Stats.AbortErrors[0];
++ StatsTable0[3].StatPtr = &HalDev->Stats.StarvErrors[0];
++
++ StatsTable1[0].StatPtr = &HalDev->Stats.DmaLenErrors[0];
++ StatsTable1[1].StatPtr = &HalDev->Stats.TxMisQCnt[0][0];
++ StatsTable1[2].StatPtr = &HalDev->Stats.RxMisQCnt[0];
++ StatsTable1[3].StatPtr = &HalDev->Stats.TxEOQCnt[0][0];
++ StatsTable1[4].StatPtr = &HalDev->Stats.RxEOQCnt[0];
++ StatsTable1[5].StatPtr = &HalDev->Stats.RxPacketsServiced[0];
++ StatsTable1[6].StatPtr = &HalDev->Stats.TxPacketsServiced[0][0];
++ StatsTable1[7].StatPtr = &HalDev->Stats.RxMaxServiced;
++ StatsTable1[8].StatPtr = &HalDev->Stats.TxMaxServiced[0][0];
++ StatsTable1[9].StatPtr = &HalDev->Stats.RxTotal;
++ StatsTable1[10].StatPtr = &HalDev->Stats.TxTotal;
++#endif
++
++#if (defined(_CPHAL_AAL5) || defined(_CPHAL_CPMAC))
++ StatsTable2[0].StatPtr = (bit32u *)&HalDev->RcbPool[0];
++ StatsTable2[1].StatPtr = &HalDev->RxActQueueCount[0];
++ StatsTable2[2].StatPtr = (bit32u *)&HalDev->RxActQueueHead[0];
++ StatsTable2[3].StatPtr = (bit32u *)&HalDev->RxActQueueTail[0];
++ StatsTable2[4].StatPtr = &HalDev->RxActive[0];
++ StatsTable2[5].StatPtr = (bit32u *)&HalDev->RcbStart[0];
++ StatsTable2[6].StatPtr = &HalDev->RxTeardownPending[0];
++ StatsTable2[7].StatPtr = (bit32u *)&HalDev->TcbPool[0][0];
++ StatsTable2[8].StatPtr = &HalDev->TxActQueueCount[0][0];
++ StatsTable2[9].StatPtr = (bit32u *)&HalDev->TxActQueueHead[0][0];
++ StatsTable2[10].StatPtr = (bit32u *)&HalDev->TxActQueueTail[0][0];
++ StatsTable2[11].StatPtr = &HalDev->TxActive[0][0];
++ StatsTable2[12].StatPtr = (bit32u *)&HalDev->TcbStart[0][0];
++ StatsTable2[13].StatPtr = &HalDev->TxTeardownPending[0];
++
++ StatsTable3[0].StatPtr = &HalDev->ChData[0].RxBufSize;
++ StatsTable3[1].StatPtr = &HalDev->ChData[0].RxBufferOffset;
++ StatsTable3[2].StatPtr = &HalDev->ChData[0].RxNumBuffers;
++ StatsTable3[3].StatPtr = &HalDev->ChData[0].RxServiceMax;
++ StatsTable3[4].StatPtr = &HalDev->ChData[0].TxNumBuffers;
++ StatsTable3[5].StatPtr = &HalDev->ChData[0].TxNumQueues;
++ StatsTable3[6].StatPtr = &HalDev->ChData[0].TxServiceMax;
++#ifdef _CPHAL_AAL5
++ StatsTable3[7].StatPtr = &HalDev->ChData[0].CpcsUU;
++ StatsTable3[8].StatPtr = &HalDev->ChData[0].Gfc;
++ StatsTable3[9].StatPtr = &HalDev->ChData[0].Clp;
++ StatsTable3[10].StatPtr = &HalDev->ChData[0].Pti;
++ StatsTable3[11].StatPtr = &HalDev->ChData[0].DaMask;
++ StatsTable3[12].StatPtr = &HalDev->ChData[0].Priority;
++ StatsTable3[13].StatPtr = &HalDev->ChData[0].PktType;
++ StatsTable3[14].StatPtr = &HalDev->ChData[0].Vci;
++ StatsTable3[15].StatPtr = &HalDev->ChData[0].Vpi;
++ StatsTable3[16].StatPtr = &HalDev->ChData[0].TxVc_CellRate;
++ StatsTable3[17].StatPtr = &HalDev->ChData[0].TxVc_QosType;
++ StatsTable3[18].StatPtr = &HalDev->ChData[0].TxVc_Mbs;
++ StatsTable3[19].StatPtr = &HalDev->ChData[0].TxVc_Pcr;
++#endif
++#endif
++
++ StatsTable4[0].StatPtr = &HalDev->dev_base;
++ StatsTable4[1].StatPtr = &HalDev->offset;
++ StatsTable4[2].StatPtr = &HalDev->interrupt;
++ StatsTable4[3].StatPtr = &HalDev->debug;
++ StatsTable4[4].StatPtr = &HalDev->Inst;
++ }
++#endif /* +RC 3.02 */
++
++#ifndef _CPHAL_CPSAR /* +RC 3.02 */
++#ifndef _CPHAL_AAL2 /* +RC 3.02 */
++/*
++ * Returns statistics information.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ *
++ * @return 0
++ */
++static int StatsGet(HAL_DEVICE *HalDev, void **StatPtr, int Index, int Ch, int Queue)
++ {
++ int Size;
++ bit32u *AddrPtr;
++ char *DataPtr;
++ STATS_TABLE *StatsTable;
++ int i, NumberOfStats;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpcommon]StatsGet(HalDev:%08x, StatPtr:%08x)\n",
++ (bit32u)HalDev, (bit32u)StatPtr);
++ osfuncSioFlush();
++ }
++#endif
++
++ StatsTable = StatsDb[Index].StatTable;
++ NumberOfStats = StatsDb[Index].NumberOfStats;
++
++ Size = sizeof(bit32u)*((NumberOfStats*2)+1);
++ Size += (NumberOfStats*11);
++ *StatPtr = (bit32u *)HalDev->OsFunc->Malloc(Size);
++
++ AddrPtr = (bit32u *) *StatPtr;
++ DataPtr = (char *)AddrPtr;
++ DataPtr += sizeof(bit32u)*((NumberOfStats*2)+1);
++
++ for (i=0; i<NumberOfStats; i++)
++ {
++ *AddrPtr++ = (bit32u)StatsTable[i].StatName;
++ *AddrPtr++ = (bit32u)DataPtr;
++ if (&StatsTable[i].StatPtr[Ch] != 0)
++ {
++ switch(StatsTable[i].DataType)
++ {
++ case 0:
++ HalDev->OsFunc->Sprintf(DataPtr, "%d", (bit32u *)StatsTable[i].StatPtr[Ch]);
++ break;
++ case 1:
++ HalDev->OsFunc->Sprintf(DataPtr, "0x%x", (bit32u *)StatsTable[i].StatPtr[Ch]);
++ break;
++ case 2:
++ HalDev->OsFunc->Sprintf(DataPtr, "%d", *((bit32u *)StatsTable[i].StatPtr + (Ch * (sizeof(CHANNEL_INFO)/4))));
++ break;
++ case 3:
++ HalDev->OsFunc->Sprintf(DataPtr, "%d", *((bit32u *)StatsTable[i].StatPtr + (Ch*MAX_QUEUE)+Queue));
++ break;
++ case 4:
++ HalDev->OsFunc->Sprintf(DataPtr, "0x%x", *((bit32u *)StatsTable[i].StatPtr + (Ch*MAX_QUEUE)+Queue));
++ break;
++ default:
++ /* invalid data type, due to CPHAL programming error */
++ break;
++ }
++ }
++ else
++ {
++ /* invalid statistics pointer, probably was not initialized */
++ }
++ DataPtr += HalDev->OsFunc->Strlen(DataPtr) + 1;
++ }
++
++ *AddrPtr = (bit32u) 0;
++
++ return (EC_NO_ERRORS);
++ }
++#endif /* +RC 3.02 */
++#endif /* +RC 3.02 */
++
++#ifdef _CPHAL_CPMAC
++static void gpioFunctional(int base, int bit)
++ { /*+RC3.02*/
++ bit32u GpioEnr = base + 0xC;
++ /* To make functional, set to zero */
++ *(volatile bit32u *)(GpioEnr) &= ~(1 << bit); /*+RC3.02*/
++ } /*+RC3.02*/
++
++
++/*+RC3.02*/
++/* Common function, Checks to see if GPIO should be in functional mode */
++static void gpioCheck(HAL_DEVICE *HalDev, void *moduleDeviceInfo)
++ { /*+RC3.02*/
++ int rc;
++ void *DeviceInfo;
++ char *pszMuxBits;
++ char pszMuxBit[20];
++ char *pszTmp;
++ char szMuxBit[20];
++ char *ptr;
++ int base;
++ int reset_bit;
++ int bit;
++ OS_FUNCTIONS *OsFunc = HalDev->OsFunc;
++
++ rc = OsFunc->DeviceFindParmValue(moduleDeviceInfo, "gpio_mux",&pszTmp);
++ if(rc) return;
++ /* gpio entry found, get GPIO register info and make functional */
++
++ /* temp copy until FinParmValue fixed */
++ ptr = &szMuxBit[0];
++ while ((*ptr++ = *pszTmp++));
++
++ pszMuxBits = &szMuxBit[0];
++
++ rc = OsFunc->DeviceFindInfo(0,"gpio",&DeviceInfo);
++ if(rc) return;
++
++ rc = OsFunc->DeviceFindParmUint(DeviceInfo, "base",&base);
++ if(rc) return;
++
++ rc = OsFunc->DeviceFindParmUint(DeviceInfo, "reset_bit",&reset_bit);
++ if(rc) return;
++
++ /* If GPIO still in reset, then exit */
++ if((VOLATILE32(HalDev->ResetBase) & (1 << reset_bit)) == 0)
++ return;
++ /* format for gpio_mux is gpio_mux = <int>;<int>;<int>...*/
++ while (*pszMuxBits)
++ {
++ pszTmp = &pszMuxBit[0];
++ if(*pszMuxBits == ';') pszMuxBits++;
++ while ((*pszMuxBits != ';') && (*pszMuxBits != '\0'))
++ {
++ osfuncSioFlush();
++ /*If value not a number, skip */
++ if((*pszMuxBits < '0') || (*pszMuxBits > '9'))
++ pszMuxBits++;
++ else
++ *pszTmp++ = *pszMuxBits++;
++ }
++ *pszTmp = '\0';
++ bit = OsFunc->Strtoul(pszMuxBit, &pszTmp, 10);
++ gpioFunctional(base, bit);
++ resetWait(HalDev); /* not sure if this is needed */
++ }
++ } /*+RC3.02*/
++#endif /* CPMAC */
++
++#ifdef _CPHAL_AAL5
++const char hcSarFrequency[] = "SarFreq";
++#endif
++
++#endif /* _INC */
+diff -urN linux.old/drivers/atm/sangam_atm/cpcommon_cpsar.h linux.dev/drivers/atm/sangam_atm/cpcommon_cpsar.h
+--- linux.old/drivers/atm/sangam_atm/cpcommon_cpsar.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/cpcommon_cpsar.h 2005-08-23 04:46:50.083845824 +0200
+@@ -0,0 +1,79 @@
++#ifndef _INC_CPCOMMON_H
++#define _INC_CPCOMMON_H
++
++#define VOLATILE32(addr) (*(volatile bit32u *)(addr))
++#ifndef dbgPrintf
++#define dbgPrintf HalDev->OsFunc->Printf
++#endif
++
++#define ChannelUpdate(Field) if(HalChn->Field != 0xFFFFFFFF) HalDev->ChData[Ch].Field = HalChn->Field
++
++#define DBG(level) (HalDev->debug & (1<<(level)))
++/*
++#define DBG0() DBG(0)
++#define DBG1() DBG(1)
++#define DBG2() DBG(2)
++#define DBG3() DBG(3)
++#define DBG4() DBG(4)
++#define DBG5() DBG(5)
++#define DBG6() DBG(6)
++#define DBG7() DBG(7)
++*/
++
++/*
++ * List of defined actions for use with Control().
++ */
++typedef enum
++ {
++ enGET=0, /**< Get the value associated with a key */
++ enSET, /**< Set the value associates with a key */
++ enCLEAR, /**<Clear the value */
++ enNULL /**< No data action, used to initiate a service or send a message */
++ }ACTION;
++
++/*
++ * Enumerated hardware states.
++ */
++typedef enum
++ {
++ enConnected=1, enDevFound, enInitialized, enOpened
++ }DEVICE_STATE;
++
++typedef enum
++ {
++ enCommonStart=0,
++ /* General */
++ enOff, enOn, enDebug,
++ /* Module General */
++ enCpuFreq,
++ enStatus,
++ enCommonEnd
++ }COMMON_KEY;
++
++typedef struct
++ {
++ const char *strKey;
++ int enKey;
++ }CONTROL_KEY;
++
++typedef struct
++ {
++ char *StatName;
++ unsigned int *StatPtr;
++ int DataType; /* 0: int, 1: hex int, 2:channel data */
++ }STATS_TABLE;
++
++typedef struct
++ {
++ int NumberOfStats;
++ STATS_TABLE *StatTable;
++ }STATS_DB;
++
++#define osfuncSioFlush() HalDev->OsFunc->Control(HalDev->OsDev,"SioFlush",pszNULL,0)
++#define osfuncSleep(Ticks) HalDev->OsFunc->Control(HalDev->OsDev,pszSleep,pszNULL,Ticks)
++#define osfuncStateChange() HalDev->OsFunc->Control(HalDev->OsDev,pszStateChange,pszNULL,0)
++
++#define CHANNEL_NAMES {"Ch0","Ch1","Ch2","Ch3","Ch4","Ch5","Ch6","Ch7","Ch8","Ch9","Ch10","Ch11","Ch12","Ch13","Ch14","Ch15"}
++
++#endif
++
+diff -urN linux.old/drivers/atm/sangam_atm/cppi_cpaal5.c linux.dev/drivers/atm/sangam_atm/cppi_cpaal5.c
+--- linux.old/drivers/atm/sangam_atm/cppi_cpaal5.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/cppi_cpaal5.c 2005-08-23 04:46:50.084845672 +0200
+@@ -0,0 +1,1483 @@
++/*************************************************************************
++ * TNETDxxxx Software Support
++ * Copyright (c) 2002,2003 Texas Instruments Incorporated. All Rights Reserved.
++ *
++ * FILE: cppi.c
++ *
++ * DESCRIPTION:
++ * This file contains shared code for all CPPI modules.
++ *
++ * HISTORY:
++ * 7Aug02 Greg RC1.00 Original Version created.
++ * 27Sep02 Mick RC1.01 Merged for use by CPMAC/CPSAR
++ * 16Oct02 Mick RC1.02 Performance Tweaks (see cppihist.txt)
++ * 12Nov02 Mick RC1.02 Updated to use cpmac_reg.h
++ * 09Jan03 Mick RC3.01 Removed modification to RxBuffer ptr
++ * 28Mar03 Mick 1.03 RxReturn now returns error if Malloc Fails
++ * 10Apr03 Mick 1.03.02 Added Needs Buffer Support
++ * 11Jun03 Mick 1.06.02 halSend() errors corrected
++ *
++ * @author Greg Guyotte
++ * @version 1.00
++ * @date 7-Aug-2002
++ *****************************************************************************/
++/* each CPPI module must modify this file, the rest of the
++ code in cppi.c should be totally shared *//* Each CPPI module MUST properly define all constants shown below */
++
++/* CPPI registers */
++
++/* the following defines are not CPPI specific, but still used by cppi.c */
++
++static void FreeRx(HAL_DEVICE *HalDev, int Ch)
++ {
++ HAL_RCB *rcb_ptr; /*+GSG 030303*/
++ int rcbSize = (sizeof(HAL_RCB)+0xf)&~0xf; /*+GSG 030303*/
++ int Num = HalDev->ChData[Ch].RxNumBuffers, i; /*+GSG 030303*/
++
++ /* Free Rx data buffers attached to descriptors, if necessary */
++ if (HalDev->RcbStart[Ch] != 0) /*+GSG 030303*/
++ { /*+GSG 030303*/
++ for(i=0;i<Num;i++) /*+GSG 030303*/
++ { /*+GSG 030303*/
++ rcb_ptr = (HAL_RCB *)(HalDev->RcbStart[Ch] + (i*rcbSize)); /*+GSG 030303*/
++
++ /* free the data buffer */
++ if (rcb_ptr->DatPtr != 0)
++ {
++
++ HalDev->OsFunc->FreeRxBuffer((void *)rcb_ptr->OsInfo, (void *)rcb_ptr->DatPtr);
++ rcb_ptr->OsInfo=0; /*MJH+030522*/
++ rcb_ptr->DatPtr=0; /*MJH+030522*/
++ }
++ } /*+GSG 030303*/
++ } /*+GSG 030303*/
++
++ /* free up all desciptors at once */
++ HalDev->OsFunc->FreeDmaXfer(HalDev->RcbStart[Ch]);
++
++ /* mark buffers as freed */
++ HalDev->RcbStart[Ch] = 0;
++ }
++
++static void FreeTx(HAL_DEVICE *HalDev, int Ch, int Queue)
++ {
++
++/*+GSG 030303*/
++
++ /* free all descriptors at once */
++ HalDev->OsFunc->FreeDmaXfer(HalDev->TcbStart[Ch][Queue]);
++
++ HalDev->TcbStart[Ch][Queue] = 0;
++ }
++
++/* return of 0 means that this code executed, -1 means the interrupt was not
++ a teardown interrupt */
++static int RxTeardownInt(HAL_DEVICE *HalDev, int Ch)
++ {
++ bit32u base = HalDev->dev_base;
++
++ int i;
++ volatile bit32u *pTmp;
++
++ /* check to see if the interrupt is a teardown interrupt */
++ if (((*(pRX_CPPI_COMP_PTR( base )+( Ch *64))) & TEARDOWN_VAL) == TEARDOWN_VAL)
++ {
++ /* finish channel teardown */
++
++ /* Free channel resources on a FULL teardown */
++ if (HalDev->RxTeardownPending[Ch] & FULL_TEARDOWN)
++ {
++ FreeRx(HalDev, Ch);
++ }
++
++ /* bug fix - clear Rx channel pointers on teardown */
++ HalDev->RcbPool[Ch] = 0;
++ HalDev->RxActQueueHead[Ch] = 0;
++ HalDev->RxActQueueCount[Ch] = 0;
++ HalDev->RxActive[Ch] = FALSE;
++
++ /* write completion pointer */
++ (*(pRX_CPPI_COMP_PTR( base )+( Ch *64))) = TEARDOWN_VAL;
++
++ /* use direction bit as a teardown pending bit! May be able to
++ use only one teardown pending integer in HalDev */
++
++ HalDev->RxTeardownPending[Ch] &= ~RX_TEARDOWN;
++
++ HalDev->ChIsOpen[Ch][DIRECTION_RX] = 0;
++
++ /* call OS Teardown Complete (if TX is also done) */
++ if ((HalDev->TxTeardownPending[Ch] & TX_TEARDOWN) == 0)
++ {
++ /* mark channel as closed */
++ HalDev->ChIsOpen[Ch][DIRECTION_TX] = 0;
++
++ /* disable channel interrupt */
++ SAR_TX_MASK_CLR(HalDev->dev_base) = (1<<Ch);
++ SAR_TX_MASK_CLR(HalDev->dev_base) = (1<<(Ch+16)); /* +GSG 030307 */
++ SAR_RX_MASK_CLR(HalDev->dev_base) = (1<<Ch);
++
++ /* Clear PDSP Channel State RAM */
++ pTmp = (pPDSP_BLOCK_0(HalDev->dev_base)+(Ch*64));
++ for (i=0; i<NUM_PDSP_AAL5_STATE_WORDS; i++)
++ *pTmp++ = 0;
++
++ if ((HalDev->RxTeardownPending[Ch] & BLOCKING_TEARDOWN) == 0)
++ {
++
++ HalDev->OsFunc->TeardownComplete(HalDev->OsDev, Ch, DIRECTION_TX|DIRECTION_RX);
++ }
++ /* clear all teardown pending information for this channel */
++ HalDev->RxTeardownPending[Ch] = 0;
++ HalDev->TxTeardownPending[Ch] = 0;
++ }
++
++ return (EC_NO_ERRORS);
++ }
++ return (-1);
++ }
++
++/* return of 0 means that this code executed, -1 means the interrupt was not
++ a teardown interrupt */
++static int TxTeardownInt(HAL_DEVICE *HalDev, int Ch, int Queue)
++ {
++ bit32u base = HalDev->dev_base;
++ HAL_TCB *Last, *Curr, *First; /*+GSG 030303*/
++
++ int i;
++ volatile bit32u *pTmp;
++
++ if (((*(pTXH_CPPI_COMP_PTR( base )+( Ch *64)+( Queue ))) & TEARDOWN_VAL) == TEARDOWN_VAL)
++ {
++ /* return outstanding buffers to OS +RC3.02*/
++ Curr = HalDev->TxActQueueHead[Ch][Queue]; /*+GSG 030303*/
++ First = Curr; /*+GSG 030303*/
++ while (Curr) /*+GSG 030303*/
++ { /*+GSG 030303*/
++ /* Pop TCB(s) for packet from the stack */ /*+GSG 030303*/
++ Last = Curr->Eop; /*+GSG 030303*/
++ HalDev->TxActQueueHead[Ch][Queue] = Last->Next; /*+GSG 030303*/
++ /*+GSG 030303*/
++ /* return to OS */ /*+GSG 030303*/
++ HalDev->OsFunc->SendComplete(Curr->OsInfo); /*+GSG 030303*/
++ /*+GSG 030303*/
++ /* Push Tcb(s) back onto the stack */ /*+GSG 030303*/
++ Curr = Last->Next; /*+GSG 030303*/
++ Last->Next = HalDev->TcbPool[Ch][Queue]; /*+GSG 030303*/
++ HalDev->TcbPool[Ch][Queue] = First; /*+GSG 030303*/
++ /*+GSG 030303*/
++ /* set the first(SOP) pointer for the next packet */ /*+GSG 030303*/
++ First = Curr; /*+GSG 030303*/
++ } /*+GSG 030303*/
++
++ /* finish channel teardown */
++
++ /* save the OsInfo to pass to upper layer
++ THIS WAS CRASHING - because it's possible that I get the teardown
++ notification and the TcbHPool is null. In this case, the buffers
++ to free can be found in the TxHActiveQueue. If I need to get OsInfo
++ in the future, I can get it from one of those buffers.
++ OsInfo = HalDev->TcbHPool[Ch]->OsInfo; */
++
++ if (HalDev->TxTeardownPending[Ch] & FULL_TEARDOWN)
++ {
++ FreeTx(HalDev, Ch, Queue);
++ } /* if FULL teardown */
++
++ /* bug fix - clear Tx channel pointers on teardown */
++ HalDev->TcbPool[Ch][Queue] = 0;
++ HalDev->TxActQueueHead[Ch][Queue] = 0;
++ HalDev->TxActQueueCount[Ch][Queue] = 0;
++ HalDev->TxActive[Ch][Queue] = FALSE;
++
++ /* write completion pointer */
++ (*(pTXH_CPPI_COMP_PTR( base )+( Ch *64)+( Queue ))) = TEARDOWN_VAL;
++
++ /* no longer pending teardown */
++ HalDev->TxTeardownPending[Ch] &= ~TX_TEARDOWN;
++
++ HalDev->ChIsOpen[Ch][DIRECTION_TX] = 0;
++
++ /* call OS Teardown Complete (if Rx is also done) */
++ if ((HalDev->RxTeardownPending[Ch] & RX_TEARDOWN) == 0)
++ {
++ /* mark channel as closed */
++ HalDev->ChIsOpen[Ch][DIRECTION_RX] = 0;
++
++ /* disable channel interrupt */
++ SAR_TX_MASK_CLR(HalDev->dev_base) = (1<<Ch);
++ SAR_TX_MASK_CLR(HalDev->dev_base) = (1<<(Ch+16)); /* +GSG 030307 */
++ SAR_RX_MASK_CLR(HalDev->dev_base) = (1<<Ch);
++
++ /* Clear PDSP Channel State RAM */
++ pTmp = (pPDSP_BLOCK_0(HalDev->dev_base)+(Ch*64));
++ for (i=0; i<NUM_PDSP_AAL5_STATE_WORDS; i++)
++ *pTmp++ = 0;
++
++ if ((HalDev->TxTeardownPending[Ch] & BLOCKING_TEARDOWN) == 0)
++ {
++
++ HalDev->OsFunc->TeardownComplete(HalDev->OsDev, Ch, DIRECTION_TX|DIRECTION_RX);
++ }
++
++ /* clear all teardown pending information for this channel */
++ HalDev->RxTeardownPending[Ch] = 0;
++ HalDev->TxTeardownPending[Ch] = 0;
++ }
++
++ return (EC_NO_ERRORS);
++ }
++ return (-1);
++ }
++
++/* +GSG 030421 */
++static void AddToRxQueue(HAL_DEVICE *HalDev, HAL_RCB *FirstRcb, HAL_RCB *LastRcb, int FragCount, int Ch)
++ {
++ HAL_RCB *OldTailRcb;
++
++ if (HalDev->RxActQueueCount[Ch]==0)
++ {
++
++ HalDev->RxActQueueHead[Ch]=FirstRcb;
++ HalDev->RxActQueueTail[Ch]=LastRcb;
++ HalDev->RxActQueueCount[Ch]=FragCount;
++ if ((!HalDev->InRxInt[Ch])&&(!HalDev->RxActive[Ch]))
++ {
++ /* write Rx Queue Head Descriptor Pointer */
++ (*(pRX_DMA_STATE_WORD_1( HalDev->dev_base )+( Ch *64))) = VirtToPhys(FirstRcb) - HalDev->offset;
++ HalDev->RxActive[Ch]=TRUE;
++ }
++ }
++ else
++ {
++
++ OldTailRcb=HalDev->RxActQueueTail[Ch];
++ OldTailRcb->Next=(void *)FirstRcb;
++
++ /* Emerald fix 10/29 (Denis) */
++ *((bit32u *) VirtToVirtNoCache(&OldTailRcb->HNext))=VirtToPhys(FirstRcb) - HalDev->offset;
++
++ HalDev->RxActQueueTail[Ch]=LastRcb;
++ HalDev->RxActQueueCount[Ch]+=FragCount;
++ }
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * This function is called to indicate to the CPHAL that the upper layer
++ * software has finished processing the receive data (given to it by
++ * osReceive()). The CPHAL will then return the appropriate receive buffers
++ * and buffer descriptors to the available pool.
++ *
++ * @param HalReceiveInfo Start of receive buffer descriptor chain returned to
++ * CPHAL.
++ * @param StripFlag Flag indicating whether the upper layer software has
++ * retained ownership of the receive data buffers.
++ *<BR>
++ * 'FALSE' means that the CPHAL can reuse the receive data buffers.
++ *<BR>
++ * 'TRUE' : indicates the data buffers were retained by the OS
++ *<BR>
++ * NOTE: If StripFlag is TRUE, it is the responsibility of the upper layer software to free the buffers when they are no longer needed.
++ *
++ * @return EC_NO_ERRORS (ok). <BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_INVALID_STATE "EC_VAL_INVALID_STATE"<BR>
++ * @ref EC_VAL_RCB_NEEDS_BUFFER "EC_VAL_RCB_NEEDS_BUFFER"<BR>
++ * @ref EC_VAL_RCB_DROPPED "EC_VAL_RCB_DROPPED"<BR>
++ */
++static int halRxReturn(HAL_RECEIVEINFO *HalReceiveInfo,
++ int StripFlag)
++ {
++ int Ch = HalReceiveInfo->Ch, i;
++ HAL_RCB *LastRcb, *TempRcb;
++ char *pBuf;
++ HAL_RCB *CurrHeadRcb = HalReceiveInfo, *LastGoodRcb=0; /* +GSG 030421 */
++ HAL_DEVICE *HalDev = HalReceiveInfo->HalDev;
++ int RcbSize = HalDev->ChData[Ch].RxBufSize;
++ int FragCount = HalReceiveInfo->FragCount;
++ int rc=0; /*MJH+030417*/
++ int GoodCount=0; /*GSG+030421*/
++
++ if (HalDev->State != enOpened)
++ return(EC_AAL5 |EC_FUNC_RXRETURN|EC_VAL_INVALID_STATE);
++
++ LastRcb=(HAL_RCB *)HalReceiveInfo->Eop;
++ LastRcb->HNext=0;
++ LastRcb->Next=0;
++
++ if (FragCount>1)
++ {
++ LastRcb->Off_BLen=RcbSize;
++ LastRcb->mode=CB_OWNERSHIP_BIT;
++ }
++
++ HalReceiveInfo->Off_BLen=RcbSize;
++ HalReceiveInfo->mode=CB_OWNERSHIP_BIT;
++
++ /* If OS has kept the buffers for this packet, attempt to alloc new buffers */
++ if (StripFlag)
++ {
++ TempRcb = HalReceiveInfo;
++ for (i=0; i<FragCount; i++)
++ {
++ if (TempRcb == 0)
++ {
++ dbgPrintf("Rx Return error while allocating new buffers\n");
++ dbgPrintf("Rcb = %08x, Rcb->Eop = %08x, FragCount = %d:%d\n",
++ (bit32u)HalReceiveInfo, (bit32u)HalReceiveInfo->Eop, FragCount,i);
++ osfuncSioFlush();
++
++ return(EC_CPPI|EC_FUNC_RXRETURN|EC_VAL_CORRUPT_RCB_CHAIN);
++ }
++
++ /* size = ((RcbSize+15) & ~15) + 15;*/ /*-3.01b*/
++ /*size = RcbSize + 15;*/ /* -GSG 030421 */
++ pBuf= (char *) HalDev->OsFunc->MallocRxBuffer(RcbSize,0,
++ 0xF,HalDev->ChData[Ch].OsSetup,
++ (void *)TempRcb,
++ (void *)&TempRcb->OsInfo,
++ (void *) HalDev->OsDev);
++ if (!pBuf)
++ {
++ /* malloc failed, add this RCB to Needs Buffer List */
++ TempRcb->FragCount = 1; /*MJH+030417*/
++ (HAL_RCB *)TempRcb->Eop = TempRcb; /* GSG +030430 */
++
++ if(HalDev->NeedsCount < MAX_NEEDS) /* +MJH 030410 */
++ { /* +MJH 030410 */
++ HalDev->Needs[HalDev->NeedsCount] = (HAL_RECEIVEINFO *) TempRcb; /* +MJH 030410 */
++ HalDev->NeedsCount++; /* +MJH 030410 */
++ rc = (EC_CPPI|EC_FUNC_RXRETURN|EC_VAL_RCB_NEEDS_BUFFER); /* ~MJH 030417 */
++ } /* +MJH 030410 */
++ else /* +MJH 030410 */
++ rc = (EC_CPPI|EC_FUNC_RXRETURN|EC_VAL_RCB_DROPPED); /* ~MJH 030417 */
++
++ /* requeue any previous RCB's that were ready to go before this one */
++ if (GoodCount > 0) /* +GSG 030421 */
++ { /* +GSG 030421 */
++ LastGoodRcb->HNext=0; /* +GSG 030430 */
++ LastGoodRcb->Next=0; /* +GSG 030430 */
++ osfuncDataCacheHitWriteback((void *)LastGoodRcb, 16); /* +GSG 030430 */
++
++ AddToRxQueue(HalDev, CurrHeadRcb, LastGoodRcb, GoodCount, Ch); /* +GSG 030421 */
++ GoodCount = 0; /* +GSG 030421 */
++ } /* +GSG 030421 */
++
++ CurrHeadRcb = TempRcb->Next; /* +GSG 030421 */
++ }
++ else /* +GSG 030421 */
++ { /* +GSG 030421 */
++ /* malloc succeeded, requeue the RCB to the hardware */
++ TempRcb->BufPtr=VirtToPhys(pBuf) - HalDev->offset;
++ TempRcb->DatPtr=pBuf;
++ /* Emerald fix 10/29 */
++ osfuncDataCacheHitWriteback((void *)TempRcb, 16);
++
++ /* i store the last good RCB in case the malloc fails for the
++ next fragment. This ensures that I can go ahead and return
++ a partial chain of RCB's to the hardware */
++ LastGoodRcb = TempRcb; /* +GSG 030421 */
++ GoodCount++; /* +GSG 030421 */
++ } /* +GSG 030421 */
++ TempRcb = TempRcb->Next;
++ } /* end of Frag loop */
++ /* if there any good RCB's to requeue, do so here */
++ if (GoodCount > 0) /* +GSG 030421 */
++ {
++ AddToRxQueue(HalDev, CurrHeadRcb, LastGoodRcb, GoodCount, Ch); /* +GSG 030421 */
++ }
++ return(rc); /* ~GSG 030421 */
++ }
++ else
++ {
++ /* Not Stripping */
++ /* Emerald */
++ /* Write Back SOP and last RCB */
++ osfuncDataCacheHitWriteback((void *)HalReceiveInfo, 16);
++
++ if (FragCount > 1)
++ {
++ osfuncDataCacheHitWriteback((void *)LastRcb, 16);
++ }
++ /* if not stripping buffers, always add to queue */
++ AddToRxQueue(HalDev, HalReceiveInfo, LastRcb, FragCount, Ch); /*MJH~030520*/
++ }
++
++ return(EC_NO_ERRORS);
++ }
++
++/* +MJH 030410
++ Trys to liberate an RCB until liberation fails.
++ Note: If liberation fails then RxReturn will re-add the RCB to the
++ Needs list.
++*/
++static void NeedsCheck(HAL_DEVICE *HalDev)
++{
++ HAL_RECEIVEINFO* HalRcb;
++ int rc;
++ HalDev->OsFunc->CriticalOn();
++ while(HalDev->NeedsCount)
++ {
++ HalDev->NeedsCount--;
++ HalRcb = HalDev->Needs[HalDev->NeedsCount];
++ rc = halRxReturn(HalRcb, 1);
++ /* short circuit if RxReturn starts to fail */
++ if (rc != 0)
++ break;
++ }
++ HalDev->OsFunc->CriticalOff();
++}
++
++/*
++ * This function allocates transmit buffer descriptors (internal CPHAL function).
++ * It creates a high priority transmit queue by default for a single Tx
++ * channel. If QoS is enabled for the given CPHAL device, this function
++ * will also allocate a low priority transmit queue.
++ *
++ * @param HalDev CPHAL module instance. (set by cphalInitModule())
++ * @param Ch Channel number.
++ *
++ * @return 0 OK, Non-Zero Not OK
++ */
++static int InitTcb(HAL_DEVICE *HalDev, int Ch)
++ {
++ int i, Num = HalDev->ChData[Ch].TxNumBuffers;
++ HAL_TCB *pTcb=0;
++ char *AllTcb;
++ int tcbSize, Queue;
++ int SizeMalloc;
++
++ tcbSize = (sizeof(HAL_TCB)+0xf)&~0xf;
++ SizeMalloc = (tcbSize*Num)+0xf;
++
++ for (Queue=0; Queue < HalDev->ChData[Ch].TxNumQueues; Queue++)
++ {
++ if (HalDev->TcbStart[Ch][Queue] == 0)
++ {
++
++ /* malloc all TCBs at once */
++ AllTcb = (char *)HalDev->OsFunc->MallocDmaXfer(SizeMalloc,0,0xffffffff);
++ if (!AllTcb)
++ {
++ return(EC_CPPI|EC_FUNC_HAL_INIT|EC_VAL_TCB_MALLOC_FAILED);
++ }
++
++ HalDev->OsFunc->Memset(AllTcb, 0, SizeMalloc);
++
++ /* keep this address for freeing later */
++ HalDev->TcbStart[Ch][Queue] = AllTcb;
++ }
++ else
++ {
++ /* if the memory has already been allocated, simply reuse it! */
++ AllTcb = HalDev->TcbStart[Ch][Queue];
++ }
++
++ /* align to cache line */
++ AllTcb = (char *)(((bit32u)AllTcb + 0xf) &~ 0xf); /*PITS #143 MJH~030522*/
++
++ /* default High priority transmit queue */
++ HalDev->TcbPool[Ch][Queue]=0;
++ for(i=0;i<Num;i++)
++ {
++ /*pTcb=(HAL_TCB *) OsFunc->MallocDmaXfer(sizeof(HAL_TCB),0,0xffffffff); */
++ pTcb= (HAL_TCB *)(AllTcb + (i*tcbSize));
++ pTcb->mode=0;
++ pTcb->BufPtr=0;
++ pTcb->Next=HalDev->TcbPool[Ch][Queue];
++ pTcb->Off_BLen=0;
++ HalDev->TcbPool[Ch][Queue]=pTcb;
++ }
++ /*HalDev->TcbEnd = pTcb;*/
++ }
++
++ return(EC_NO_ERRORS);
++ }
++
++/*
++ * This function allocates receive buffer descriptors (internal CPHAL function).
++ * After allocation, the function 'queues' (gives to the hardware) the newly
++ * created receive buffers to enable packet reception.
++ *
++ * @param HalDev CPHAL module instance. (set by cphalInitModule())
++ * @param Ch Channel number.
++ *
++ * @return 0 OK, Non-Zero Not OK
++ */
++static int InitRcb(HAL_DEVICE *HalDev, int Ch)
++ {
++ int i, Num = HalDev->ChData[Ch].RxNumBuffers;
++ int Size = HalDev->ChData[Ch].RxBufSize;
++ HAL_RCB *pRcb;
++ char *pBuf;
++ char *AllRcb;
++ int rcbSize;
++ int DoMalloc = 0;
++ int SizeMalloc;
++ int MallocSize;
++
++ rcbSize = (sizeof(HAL_RCB)+0xf)&~0xf;
++ SizeMalloc = (rcbSize*Num)+0xf;
++
++ if (HalDev->RcbStart[Ch] == 0)
++ {
++ DoMalloc = 1;
++
++ /* malloc all RCBs at once */
++ AllRcb= (char *)HalDev->OsFunc->MallocDmaXfer(SizeMalloc,0,0xffffffff);
++ if (!AllRcb)
++ {
++ return(EC_CPPI|EC_FUNC_HAL_INIT|EC_VAL_RCB_MALLOC_FAILED);
++ }
++
++ HalDev->OsFunc->Memset(AllRcb, 0, SizeMalloc);
++
++ /* keep this address for freeing later */
++ HalDev->RcbStart[Ch] = AllRcb;
++ }
++ else
++ {
++ /* if the memory has already been allocated, simply reuse it! */
++ AllRcb = HalDev->RcbStart[Ch];
++ }
++
++ /* align to cache line */
++ AllRcb = (char *)(((bit32u)AllRcb + 0xf)&~0xf); /*PITS #143 MJH~030522*/
++
++ HalDev->RcbPool[Ch]=0;
++ for(i=0;i<Num;i++)
++ {
++ pRcb = (HAL_RCB *)(AllRcb + (i*rcbSize));
++
++ if (DoMalloc == 1)
++ {
++
++ MallocSize = Size; /*~3.01 */
++ pBuf= (char *) HalDev->OsFunc->MallocRxBuffer(MallocSize,0,0xF,HalDev->ChData[Ch].OsSetup, (void *)pRcb, (void *)&pRcb->OsInfo, (void *) HalDev->OsDev);
++ if(!pBuf)
++ {
++ return(EC_CPPI|EC_FUNC_HAL_INIT|EC_VAL_RX_BUFFER_MALLOC_FAILED);
++ }
++ /* -RC3.01 pBuf = (char *)(((bit32u)pBuf+0xF) & ~0xF); */
++ pRcb->BufPtr=VirtToPhys(pBuf) - HalDev->offset;
++ pRcb->DatPtr=pBuf;
++ /*pRcb->BufSize=Size;*/
++ }
++ pRcb->mode=0;
++ pRcb->Ch=Ch;
++ pRcb->Next=(void *)HalDev->RcbPool[Ch];
++ pRcb->Off_BLen=0;
++ pRcb->HalDev = HalDev;
++ HalDev->RcbPool[Ch]=pRcb;
++ }
++
++ /* Give all of the Rx buffers to hardware */
++
++ while(HalDev->RcbPool[Ch])
++ {
++ pRcb=HalDev->RcbPool[Ch];
++ HalDev->RcbPool[Ch]=pRcb->Next;
++ pRcb->Eop=(void*)pRcb;
++ pRcb->FragCount=1;
++ halRxReturn((HAL_RECEIVEINFO *)pRcb, 0);
++ }
++
++ return(EC_NO_ERRORS);
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * This function transmits the data in FragList using available transmit
++ * buffer descriptors. More information on the use of the Mode parameter
++ * is available in the module-specific appendices. Note: The OS should
++ * not call Send() for a channel that has been requested to be torndown.
++ *
++ * @param HalDev CPHAL module instance. (set by cphalInitModule())
++ * @param FragList Fragment List structure.
++ * @param FragCount Number of fragments in FragList.
++ * @param PacketSize Number of bytes to transmit.
++ * @param OsSendInfo OS Send Information structure. <BR>
++ * @param Mode 32-bit value with the following bit fields: <BR>
++ * 31-16: Mode (used for module specific data). <BR>
++ * 15-08: Queue (transmit queue to send on). <BR>
++ * 07-00: Channel (channel number to send on).
++ *
++ * @return EC_NO_ERRORS (ok). <BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_INVALID_STATE "EC_VAL_INVALID_STATE"<BR>
++ * @ref EC_VAL_NOT_LINKED "EC_VAL_NOT_LINKED"<BR>
++ * @ref EC_VAL_INVALID_CH "EC_VAL_INVALID_CH"<BR>
++ * @ref EC_VAL_OUT_OF_TCBS "EC_VAL_OUT_OF_TCBS"<BR>
++ * @ref EC_VAL_NO_TCBS "EC_VAL_NO_TCBS"<BR>
++ */
++static int halSend(HAL_DEVICE *HalDev,FRAGLIST *FragList,
++ int FragCount,int PacketSize, OS_SENDINFO *OsSendInfo,
++ bit32u Mode)
++ {
++ HAL_TCB *tcb_ptr, *head;
++ int i;
++ bit32u base = HalDev->dev_base;
++ int rc = EC_NO_ERRORS;
++ int Ch = Mode & 0xFF;
++ int Queue = (Mode>>8)&0xFF;
++
++ int WaitFlag = (Mode>>30)&1; /* This is for AAL5 testing only */ /* ~GSG 030508 */
++ int Offset = (FragList[0].len >> 16);
++ int PktType = (Mode>>16)&3; /* 0=AAL5, 1=Null AAL, 2=OAM, 3=Transparent */ /* +GSG 030508 */
++ int AtmHeaderInData = (Mode>>31)&1; /* +GSG 030508 */
++ int FragIndex = 0;
++
++ if (HalDev->State != enOpened)
++ return(EC_CPPI|EC_FUNC_SEND|EC_VAL_INVALID_STATE);
++
++ if (HalDev->ChIsOpen[Ch][DIRECTION_TX] == 0) /*MJH~030611*/ /*PITS 148*/
++ return(EC_AAL5 |EC_FUNC_SEND|EC_VAL_INVALID_CH); /*+GSG 030303*/
++
++ HalDev->OsFunc->CriticalOn();
++
++ tcb_ptr = head = HalDev->TcbPool[Ch][Queue];
++
++ if (tcb_ptr)
++ {
++
++ /* these two TCB words are only valid on SOP */
++ if (AtmHeaderInData == 1)
++ {
++ tcb_ptr->AtmHeader = 0; /* bug fix for transparent mode PTI problem */
++ /* Expect AtmHeader in the data */
++ tcb_ptr->AtmHeader |= *((bit8u *)FragList[FragIndex].data++) << 24;
++ tcb_ptr->AtmHeader |= *((bit8u *)FragList[FragIndex].data++) << 16;
++ tcb_ptr->AtmHeader |= *((bit8u *)FragList[FragIndex].data++) << 8;
++ tcb_ptr->AtmHeader |= *((bit8u *)FragList[FragIndex].data++);
++
++ /* decrement data buffer length accordingly */
++ FragList[FragIndex].len -= ATM_HEADER_SIZE;
++
++ /* if the first fragment was ATM Header only, go to next fragment for loop */
++ if (FragList[FragIndex].len == 0)
++ FragIndex++;
++
++ /* No CPCS_UU/CPI if not AAL5 */
++ tcb_ptr->Word5 = ((PktType & 0x3)<<16);
++ }
++ else
++ {
++ /* calculate AtmHeader from fields */
++ tcb_ptr->AtmHeader = atmheader(HalDev->ChData[Ch].Gfc, /* ~GSG 030306 */
++ HalDev->ChData[Ch].Vpi, HalDev->ChData[Ch].Vci,
++ HalDev->ChData[Ch].Pti, HalDev->ChData[Ch].Clp);
++
++ tcb_ptr->Word5 = HalDev->ChData[Ch].CpcsUU | ((HalDev->ChData[Ch].PktType &0x3)<<16);
++ }
++
++ for (i=FragIndex; i<FragCount; i++)
++
++ {
++ /* Setup Tx mode and size */
++ tcb_ptr->HNext = VirtToPhys((bit32 *)tcb_ptr->Next) - HalDev->offset;
++ tcb_ptr->Off_BLen = FragList[i].len;
++
++ if (i==0)
++ tcb_ptr->Off_BLen |= (Offset << 16);
++
++ tcb_ptr->mode = 0; /* MUST clear this for each frag !!! */
++ tcb_ptr->BufPtr = VirtToPhys((bit32 *)FragList[i].data) -
++ HalDev->offset;
++
++ /* first fragment */
++ if (i == 0)
++ {
++ tcb_ptr->mode |= CB_SOF_BIT;
++
++ }
++
++ tcb_ptr->mode |= (PacketSize | CB_OWNERSHIP_BIT);
++ tcb_ptr->OsInfo = OsSendInfo;
++
++ if (i == (FragCount - 1))
++ {
++ /* last fragment */
++ tcb_ptr->mode |= CB_EOF_BIT;
++
++ /* since this is the last fragment, set the TcbPool pointer before
++ nulling out the Next pointers */
++
++ HalDev->TcbPool[Ch][Queue] = tcb_ptr->Next;
++
++ tcb_ptr->Next = 0;
++ tcb_ptr->HNext = 0;
++
++ /* In the Tx Interrupt handler, we will need to know which TCB is EOP,
++ so we can save that information in the SOP */
++ head->Eop = tcb_ptr;
++
++ /* Emerald fix 10/29 */
++ osfuncDataCacheHitWriteback((void *)tcb_ptr, 16);
++
++ osfuncDataCacheHitWriteback((void *)((bit32u)tcb_ptr + 16), 16);
++
++ }
++ else
++ {
++ /* Emerald fix 10/29 */
++ osfuncDataCacheHitWriteback((void *)tcb_ptr, 16);
++
++ osfuncDataCacheHitWriteback((void *)((bit32u)tcb_ptr + 16), 16);
++
++ tcb_ptr = tcb_ptr->Next; /* what about the end of TCB list?? */
++
++ if (tcb_ptr == 0)
++ {
++ rc = EC_CPPI|EC_FUNC_SEND|EC_VAL_OUT_OF_TCBS;
++ goto ExitSend;
++ }
++ }
++ } /* for */
++
++ /* put it on the high priority queue */
++ if (HalDev->TxActQueueHead[Ch][Queue] == 0)
++ {
++ HalDev->TxActQueueHead[Ch][Queue]=head;
++ HalDev->TxActQueueTail[Ch][Queue]=tcb_ptr;
++/*+GSG 030303*//*+GSG 030303*/
++ if (!HalDev->TxActive[Ch][Queue])
++ {
++
++ if (!WaitFlag)
++ {
++
++ /* write CPPI TX HDP */
++ (*(pTX_DMA_STATE_WORD_0( base )+( Ch *64)+( Queue ))) = VirtToPhys(head) - HalDev->offset;
++ HalDev->TxActive[Ch][Queue]=TRUE;
++
++ }
++
++ }
++ }
++ else
++ {
++ HalDev->TxActQueueTail[Ch][Queue]->Next=head;
++ /* Emerald fix 10/29 */
++ *((bit32u *) VirtToVirtNoCache(&HalDev->TxActQueueTail[Ch][Queue]->HNext))=VirtToPhys(head) - HalDev->offset;
++ HalDev->TxActQueueTail[Ch][Queue]=tcb_ptr;
++/*+GSG 030303*//*+GSG 030303*/
++ }
++ rc = EC_NO_ERRORS;
++ goto ExitSend;
++ } /* if (tcb_ptr) */
++ else
++ {
++ rc = EC_CPPI|EC_FUNC_SEND|EC_VAL_NO_TCBS;
++ goto ExitSend;
++ }
++ExitSend:
++
++ HalDev->OsFunc->CriticalOff();
++ return(rc);
++ }
++
++/*
++ * This function processes receive interrupts. It traverses the receive
++ * buffer queue, extracting the data and passing it to the upper layer software via
++ * osReceive(). It handles all error conditions and fragments without valid data by
++ * immediately returning the RCB's to the RCB pool.
++ *
++ * @param HalDev CPHAL module instance. (set by cphalInitModule())
++ * @param Ch Channel Number.
++ * @param MoreWork Flag that indicates that there is more work to do when set to 1.
++ *
++ * @return 0 if OK, non-zero otherwise.
++ */
++static int RxInt(HAL_DEVICE *HalDev, int Ch, int *MoreWork)
++ {
++ HAL_RCB *CurrentRcb, *LastRcb=0, *SopRcb, *EofRcb, *EopRcb;
++ bit32u RxBufStatus,PacketsServiced, RxPktLen = 0, RxSopStatus,
++ FrmFrags, TotalFrags, CurrDmaLen, DmaLen, FrmLen;
++ int base = HalDev->dev_base, Ret;
++ OS_FUNCTIONS *OsFunc = HalDev->OsFunc;
++ int RxServiceMax = HalDev->ChData[Ch].RxServiceMax;
++ int FragIndex; /* +GSG 030508 */
++ int EarlyReturn = 0; /* +GSG 030521 */
++
++ bit32u PktType, ExpDmaSize, Cells;
++ int PassHeader=0;
++
++ int mode;
++
++ bit32u SopOffset;
++
++ if(HalDev->NeedsCount) /* +MJH 030410 */
++ NeedsCheck(HalDev); /* +MJH 030410 */
++
++ /* Handle case of teardown interrupt */
++ if (HalDev->RxTeardownPending[Ch] != 0)
++ {
++ Ret = RxTeardownInt(HalDev, Ch);
++ if (Ret == 0)
++ { /*+GSG 030303*/
++ *MoreWork = 0; /* bug fix 1/6 */ /*+GSG 030303*/
++ return (EC_NO_ERRORS);
++ } /*+GSG 030303*/
++ }
++
++ CurrentRcb=HalDev->RxActQueueHead[Ch];
++
++ osfuncDataCacheHitInvalidate((void*)CurrentRcb, 16);
++
++ RxBufStatus=CurrentRcb->mode;
++
++ /* I think I need to do this to ensure that i read UuCpi properly,
++ which is on the second cache line of the Rcb */
++ osfuncDataCacheHitInvalidate((void*)((bit32u)CurrentRcb+16), 16);
++
++ PacketsServiced=0;
++ HalDev->InRxInt[Ch]=TRUE;
++
++ while((CurrentRcb)&&((RxBufStatus&CB_OWNERSHIP_BIT)==0)&&
++ (PacketsServiced<RxServiceMax)) /* ~GSG 030307 */
++ {
++
++ PacketsServiced++; /* ~GSG 030307 */
++ SopRcb=CurrentRcb;
++ RxSopStatus=RxBufStatus;
++
++ RxPktLen = RxSopStatus&CB_SIZE_MASK;
++ /* Not sure what MAC needs to do for next block */
++
++ PktType=((SopRcb->UuCpi & 0x00030000) >> 16); /* GSG ~030508 */
++ /* Calculate the expected DMA length */
++ if (RxPktLen != 0)
++ {
++ Cells=RxPktLen/48;
++ if ((RxPktLen%48) > 40)
++ Cells++;
++ if (PktType == PKT_TYPE_AAL5) /* ~GSG 030508 */
++ Cells++;
++ ExpDmaSize=Cells*48;
++ }
++ else
++ {
++ ExpDmaSize=0;
++ }
++
++ SopOffset=(SopRcb->Off_BLen&CB_OFFSET_MASK)>>16;
++
++ CurrDmaLen=0;
++ FrmFrags=0;
++ TotalFrags=0;
++ FragIndex=0;
++ FrmLen=0;
++ EofRcb=0;
++
++/* +GSG 030508 */
++ if ((PktType == PKT_TYPE_OAM) || (PktType == PKT_TYPE_TRANS)) /* +GSG 030508 */
++ { /* +GSG 030508 */
++ /* first frag is ATM Header */ /* +GSG 030508 */
++ PassHeader = 1; /* +GSG 030508 */
++ HalDev->fraglist[FragIndex].data = (void *)&SopRcb->AtmHeader; /* +GSG 030508 */
++ HalDev->fraglist[FragIndex].len = 4; /* +GSG 030508 */
++ HalDev->fraglist[FragIndex].OsInfo = SopRcb->OsInfo; /* +GSG 030701 */
++ FragIndex++; /* +GSG 030508 */
++ } /* +GSG 030508 */
++/* +GSG 030508 */
++
++ do
++ {
++
++ DmaLen=CurrentRcb->Off_BLen&CB_SIZE_MASK;
++
++ CurrDmaLen+=DmaLen;
++ FrmLen+=DmaLen;
++ TotalFrags++;
++ if (!EofRcb)
++ {
++ HalDev->fraglist[FragIndex].data=((char *)CurrentRcb->DatPtr); /* ~GSG 030508 */
++
++ HalDev->fraglist[FragIndex].data+=((FrmFrags==0)?SopOffset:0); /* ~GSG 030508 */
++
++ HalDev->fraglist[FragIndex].len=DmaLen; /* ~GSG 030508 */
++
++ /* GSG 12/9 */
++ HalDev->fraglist[FragIndex].OsInfo = CurrentRcb->OsInfo; /* ~GSG 030508 */
++
++ /* Upper layer must do the data invalidate */
++
++ FrmFrags++;
++ FragIndex++; /* ~GSG 030508 */
++ if (FrmLen>=RxPktLen)
++ EofRcb=CurrentRcb;
++ }
++ LastRcb=CurrentRcb;
++ CurrentRcb=LastRcb->Next;
++ if (CurrentRcb)
++ {
++ osfuncDataCacheHitInvalidate((void*)CurrentRcb,16);
++ /* RxBufStatus=CurrentRcb->mode; */ /*DRB~030522*/
++ }
++ }while(((LastRcb->mode&CB_EOF_BIT)==0)&&(CurrentRcb));
++
++ /* New location for interrupt acknowledge */
++ /* Write the completion pointer */
++ (*(pRX_CPPI_COMP_PTR( base )+( Ch *64))) = VirtToPhys(LastRcb) - HalDev->offset;
++
++ EopRcb=LastRcb;
++ HalDev->RxActQueueHead[Ch]=CurrentRcb;
++ HalDev->RxActQueueCount[Ch]-=TotalFrags;
++
++ if (LastRcb->mode&CB_EOQ_BIT)
++ {
++ if (CurrentRcb)
++ {
++
++ HalDev->Stats.RxMisQCnt[Ch]++;
++
++ (*(pRX_DMA_STATE_WORD_1( base )+( Ch *64))) = LastRcb->HNext;
++ }
++ else
++ {
++
++ /* Rx EOQ */
++ HalDev->Stats.RxMisQCnt[Ch]++;
++
++ HalDev->RxActive[Ch]=FALSE;
++ }
++ }
++
++ EopRcb->Next=0;
++
++ /* setup SopRcb for the packet */
++ SopRcb->Eop=(void*)EopRcb;
++ SopRcb->FragCount=TotalFrags;
++
++ if ((ExpDmaSize!=CurrDmaLen)||(RxSopStatus&RX_ERROR_MASK))
++ {
++ /* check for Rx errors (only valid on SOP) */
++ if (RxSopStatus & RX_ERROR_MASK)
++ {
++ if (RxSopStatus & CRC_ERROR_MASK)
++ HalDev->Stats.CrcErrors[Ch]++;
++
++ if (RxSopStatus & LENGTH_ERROR_MASK)
++ HalDev->Stats.LenErrors[Ch]++;
++
++ if (RxSopStatus & ABORT_ERROR_MASK)
++ HalDev->Stats.AbortErrors[Ch]++;
++
++ if (RxSopStatus & STARV_ERROR_MASK)
++ HalDev->Stats.StarvErrors[Ch]++;
++ }
++ else
++ {
++ HalDev->Stats.DmaLenErrors[Ch]++; /* different type of length error */
++ }
++
++ EarlyReturn = 1;
++ }
++
++ /* do not pass up the packet if we're out of RCB's (or have an errored packet)*/
++ if ((CurrentRcb == 0) || (EarlyReturn == 1))
++ {
++ halRxReturn((HAL_RECEIVEINFO *)SopRcb,0);
++ }
++ else
++ {
++
++ if (EopRcb!=EofRcb)
++ {
++ HAL_RCB *FirstEmptyRcb;
++
++ FirstEmptyRcb = EofRcb->Next;
++ FirstEmptyRcb->Eop = (void*)EopRcb;
++ FirstEmptyRcb->FragCount = TotalFrags-FrmFrags;
++
++ halRxReturn((HAL_RECEIVEINFO *)FirstEmptyRcb,0);
++ SopRcb->Eop=(void*)EofRcb;
++ SopRcb->FragCount=FrmFrags;
++ EofRcb->Next=0; /* Optional */
++ }
++
++ mode = Ch | (PktType << 16) | (PassHeader << 31); /* ~GSG 030508 */
++
++ OsFunc->Receive(HalDev->OsDev,HalDev->fraglist,FragIndex,RxPktLen, /* ~GSG 030508 */
++ (HAL_RECEIVEINFO *)SopRcb,mode);
++ } /* else */
++
++ if (CurrentRcb) /*MJH+030522*/
++ {
++ RxBufStatus=CurrentRcb->mode;
++ }
++ } /* while */
++
++ if ((CurrentRcb)&&((RxBufStatus&CB_OWNERSHIP_BIT)==0)) /*~GSG 030307*/
++ {
++ *MoreWork = 1;
++ }
++ else
++ {
++ *MoreWork = 0;
++ }
++
++ if (PacketsServiced != 0)
++ {
++ /* REMOVED when removing InRxInt */
++ if ((!HalDev->RxActive[Ch]) && (HalDev->RxActQueueCount[Ch]))
++ {
++ (*(pRX_DMA_STATE_WORD_1( base )+( Ch *64))) = VirtToPhys(HalDev->RxActQueueHead[Ch]);
++ HalDev->RxActive[Ch]=TRUE;
++ }
++ }
++
++ HalDev->InRxInt[Ch]=FALSE;
++
++ /* update stats */
++ HalDev->Stats.RxPacketsServiced[Ch] += PacketsServiced;
++ HalDev->Stats.RxTotal += PacketsServiced;
++ if (HalDev->Stats.RxMaxServiced < PacketsServiced)
++ HalDev->Stats.RxMaxServiced = PacketsServiced;
++
++ return (EC_NO_ERRORS);
++ }
++
++/*
++ * This function processes transmit interrupts. It traverses the
++ * transmit buffer queue, detecting sent data buffers and notifying the upper
++ * layer software via osSendComplete(). (for SAR, i originally had this split
++ * into two functions, one for each queue, but joined them on 8/8/02)
++ *
++ * @param HalDev CPHAL module instance. (set by cphalInitModule())
++ * @param Queue Queue number to service (always 0 for MAC, Choose 1 for SAR to service low priority queue)
++ * @param MoreWork Flag that indicates that there is more work to do when set to 1.
++ *
++ * @return 0 if OK, non-zero otherwise.
++ */
++static int TxInt(HAL_DEVICE *HalDev, int Ch, int Queue, int *MoreWork)
++ {
++ HAL_TCB *CurrentTcb,*LastTcbProcessed,*FirstTcbProcessed;
++ int PacketsServiced;
++ bit32u TxFrameStatus;
++ int base = HalDev->dev_base, Ret;
++ int TxServiceMax = HalDev->ChData[Ch].TxServiceMax;
++ OS_FUNCTIONS *OsFunc = HalDev->OsFunc;
++
++ int OtherQueue = Queue^1;
++
++/*+GSG 030303*//*+GSG 030303*/
++
++ /* Handle case of teardown interrupt. This must be checked at
++ the top of the function rather than the bottom, because
++ the normal data processing can wipe out the completion
++ pointer which is used to determine teardown complete. */
++ if (HalDev->TxTeardownPending[Ch] != 0)
++ {
++ Ret = TxTeardownInt(HalDev, Ch, Queue);
++ if (Ret == 0)
++ { /*+GSG 030303*/
++ *MoreWork = 0; /* bug fix 1/6 */ /*+GSG 030303*/
++ return (EC_NO_ERRORS);
++ } /*+GSG 030303*/
++ }
++
++ CurrentTcb = HalDev->TxActQueueHead[Ch][Queue];
++ FirstTcbProcessed=CurrentTcb;
++
++ if (CurrentTcb==0)
++ {
++ /* I saw this error a couple of times when multi-channels were added */
++ dbgPrintf("[cppi TxInt()]TxH int with no TCB in queue!\n");
++ dbgPrintf(" Ch=%d, CurrentTcb = 0x%08x\n", Ch, (bit32u)CurrentTcb);
++ dbgPrintf(" HalDev = 0x%08x\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ return(EC_CPPI|EC_FUNC_TXINT|EC_VAL_NULL_TCB);
++ }
++
++ osfuncDataCacheHitInvalidate((void *)CurrentTcb, 16);
++ TxFrameStatus=CurrentTcb->mode;
++ PacketsServiced=0;
++
++ /* should the ownership bit check be inside of the loop?? could make it a
++ while-do loop and take this check away */
++ if ((TxFrameStatus&CB_OWNERSHIP_BIT)==0)
++ {
++ OsFunc->CriticalOn(); /* +GSG 030307 */
++ do
++ {
++ /* Pop TCB(s) for packet from the stack */
++ LastTcbProcessed=CurrentTcb->Eop;
++
++ /* new location for acknowledge */
++ /* Write the completion pointer */
++ (*(pTXH_CPPI_COMP_PTR( base )+( Ch *64)+( Queue ))) = VirtToPhys(LastTcbProcessed);
++
++ HalDev->TxActQueueHead[Ch][Queue] = LastTcbProcessed->Next;
++
++/*+GSG 030303*//*+GSG 030303*/
++
++ osfuncDataCacheHitInvalidate((void *)LastTcbProcessed, 16);
++
++ if (LastTcbProcessed->mode&CB_EOQ_BIT)
++ {
++ if (LastTcbProcessed->Next)
++ {
++ /* Misqueued packet */
++
++ HalDev->Stats.TxMisQCnt[Ch][Queue]++;
++
++ (*(pTX_DMA_STATE_WORD_0( base )+( Ch *64)+( Queue ))) = LastTcbProcessed->HNext;
++ }
++ else
++ {
++ /* Tx End of Queue */
++
++ HalDev->Stats.TxEOQCnt[Ch][Queue]++;
++
++ HalDev->TxActive[Ch][Queue]=FALSE;
++ }
++ }
++
++ OsFunc->SendComplete(CurrentTcb->OsInfo);
++
++ /* Push Tcb(s) back onto the stack */
++ CurrentTcb = LastTcbProcessed->Next;
++
++ LastTcbProcessed->Next=HalDev->TcbPool[Ch][Queue];
++
++ HalDev->TcbPool[Ch][Queue]=FirstTcbProcessed;
++
++ PacketsServiced++;
++
++ TxFrameStatus=CB_OWNERSHIP_BIT;
++ /* set the first(SOP) pointer for the next packet */
++ FirstTcbProcessed = CurrentTcb;
++ if (CurrentTcb)
++ {
++ osfuncDataCacheHitInvalidate((void *)CurrentTcb, 16);
++ TxFrameStatus=CurrentTcb->mode;
++ }
++
++ }while(((TxFrameStatus&CB_OWNERSHIP_BIT)==0)
++ &&(PacketsServiced<TxServiceMax));
++
++ /* this fixes the SAR TurboDSL hardware bug (multiple queue failure) */
++ if (HalDev->TxActive[Ch][OtherQueue])
++ if (HalDev->TxActQueueHead[Ch][OtherQueue])
++ if ((*(pTX_DMA_STATE_WORD_0( base )+( Ch *64)+( OtherQueue ))) == 0)
++ {
++ osfuncDataCacheHitInvalidate(HalDev->TxActQueueHead[Ch][OtherQueue],16);
++ if ((HalDev->TxActQueueHead[Ch][OtherQueue]->mode) & CB_OWNERSHIP_BIT)
++ {
++ HalDev->TurboDslErrors++;
++ (*(pTX_DMA_STATE_WORD_0( base )+( Ch *64)+( OtherQueue ))) =
++ VirtToPhys(HalDev->TxActQueueHead[Ch][OtherQueue]);
++ }
++ }
++
++ OsFunc->CriticalOff(); /* +GSG 030307 */
++ if (((TxFrameStatus&CB_OWNERSHIP_BIT)==0)
++ &&(PacketsServiced==TxServiceMax))
++ {
++ *MoreWork = 1;
++ }
++ else
++ {
++ *MoreWork = 0;
++ }
++ }
++
++ /* update stats */
++ HalDev->Stats.TxPacketsServiced[Ch][Queue] += PacketsServiced;
++ HalDev->Stats.TxTotal += PacketsServiced;
++ if (HalDev->Stats.TxMaxServiced[Ch][Queue] < PacketsServiced)
++ HalDev->Stats.TxMaxServiced[Ch][Queue] = PacketsServiced;
++
++ return(EC_NO_ERRORS);
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * This function performs a teardown for the given channel. The value of the
++ * Mode parameter controls the operation of the function, as documented below.
++ *
++ * Note: If bit 3 of Mode is set, this call is blocking, and will not return
++ * until the teardown interrupt has occurred and been processed. While waiting
++ * for a blocking teardown to complete, ChannelTeardown() will signal the OS
++ * (via Control(.."Sleep"..)) to allow the OS to perform other tasks if
++ * necessary. If and only if bit 3 of Mode is clear, the CPHAL will call the
++ * OS TeardownComplete() function to indicate that the teardown has completed.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param Ch Channel number.
++ * @param Mode Bit 0 (LSB): Perform Tx teardown (if set).<BR>
++ * Bit 1: Perform Rx teardown (if set). <BR>
++ * Bit 2: If set, perform full teardown (free buffers/descriptors).
++ * If clear, perform partial teardown (keep buffers). <BR>
++ * Bit 3 (MSB): If set, call is blocking.
++ * If clear, call is non-blocking.
++ *
++ * @return EC_NO_ERRORS (ok). <BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_INVALID_STATE "EC_VAL_INVALID_STATE"<BR>
++ * @ref EC_VAL_INVALID_CH "EC_VAL_INVALID_CH"<BR>
++ * @ref EC_VAL_TX_TEARDOWN_ALREADY_PEND "EC_VAL_TX_TEARDOWN_ALREADY_PEND"<BR>
++ * @ref EC_VAL_RX_TEARDOWN_ALREADY_PEND "EC_VAL_RX_TEARDOWN_ALREADY_PEND"<BR>
++ * @ref EC_VAL_TX_CH_ALREADY_TORNDOWN "EC_VAL_TX_CH_ALREADY_TORNDOWN"<BR>
++ * @ref EC_VAL_RX_CH_ALREADY_TORNDOWN "EC_VAL_RX_CH_ALREADY_TORNDOWN"<BR>
++ * @ref EC_VAL_TX_TEARDOWN_TIMEOUT "EC_VAL_TX_TEARDOWN_TIMEOUT"<BR>
++ * @ref EC_VAL_RX_TEARDOWN_TIMEOUT "EC_VAL_RX_TEARDOWN_TIMEOUT"<BR>
++ * @ref EC_VAL_LUT_NOT_READY "EC_VAL_LUT_NOT_READY"<BR>
++ */
++static int halChannelTeardown(HAL_DEVICE *HalDev, int Ch, bit32 Mode)
++ {
++ int DoTx, DoRx, Sleep=2048, timeout=0; /*MJH~030306*/
++ bit32u base = HalDev->dev_base;
++
++/* Set the module, used for error returns */
++
++ int Ret;
++
++ /* AAL5 only supports tearing down both sides at once (currently)*/
++ Mode = (Mode | TX_TEARDOWN | RX_TEARDOWN);
++
++ DoTx = (Mode & TX_TEARDOWN);
++ DoRx = (Mode & RX_TEARDOWN);
++
++ if (HalDev->State < enInitialized)
++ return(EC_AAL5 |EC_FUNC_CHTEARDOWN|EC_VAL_INVALID_STATE);
++
++ if ((Ch < 0) || (Ch > MAX_AAL5_CHAN ))
++ {
++ return(EC_AAL5 |EC_FUNC_CHTEARDOWN|EC_VAL_INVALID_CH);
++ }
++
++ /* set teardown pending bits before performing the teardown, because they
++ will be used in the int handler (this is done for AAL5) */
++ if (DoTx)
++ {
++ if (HalDev->TxTeardownPending[Ch] != 0)
++ return(EC_AAL5 |EC_FUNC_CHTEARDOWN|EC_VAL_TX_TEARDOWN_ALREADY_PEND);
++
++ /* If a full teardown, this also means that the user must
++ setup all channels again to use them */
++ if (Mode & FULL_TEARDOWN)
++ HalDev->ChIsSetup[Ch][DIRECTION_TX] = 0;
++
++ if (HalDev->State < enOpened)
++ {
++ /* if the hardware has never been opened, the channel has never actually
++ been setup in the hardware, so I just need to reset the software flag
++ and leave */
++ HalDev->ChIsSetup[Ch][DIRECTION_TX] = 0;
++ return (EC_NO_ERRORS);
++ }
++ else
++ {
++ if (HalDev->ChIsOpen[Ch][DIRECTION_TX] == 0)
++ {
++ return(EC_AAL5 |EC_FUNC_CHTEARDOWN|EC_VAL_TX_CH_ALREADY_TORNDOWN);
++ }
++
++ /* set teardown flag */
++ HalDev->TxTeardownPending[Ch] = Mode;
++ }
++ }
++
++ if (DoRx)
++ {
++ if (HalDev->RxTeardownPending[Ch] != 0)
++ return(EC_AAL5 |EC_FUNC_CHTEARDOWN|EC_VAL_RX_TEARDOWN_ALREADY_PEND);
++
++ if (Mode & FULL_TEARDOWN)
++ HalDev->ChIsSetup[Ch][DIRECTION_RX] = 0;
++
++ if (HalDev->State < enOpened)
++ {
++ HalDev->ChIsSetup[Ch][DIRECTION_RX] = 0;
++ return (EC_NO_ERRORS);
++ }
++ else
++ {
++ if (HalDev->ChIsOpen[Ch][DIRECTION_RX] == 0)
++ return(EC_AAL5 |EC_FUNC_CHTEARDOWN|EC_VAL_RX_CH_ALREADY_TORNDOWN);
++
++ HalDev->RxTeardownPending[Ch] = Mode;
++ }
++ }
++
++ /* Perform Tx Teardown Duties */
++ if ((DoTx) && (HalDev->State == enOpened))
++ {
++ /* Request TX channel teardown */
++ (TX_CPPI_TEARDOWN_REG( base )) = Ch;
++
++ /* wait until teardown has completed */
++ if (Mode & BLOCKING_TEARDOWN)
++ {
++ timeout = 0;
++ while (HalDev->ChIsOpen[Ch][DIRECTION_TX] == TRUE)
++ {
++ osfuncSleep(&Sleep);
++
++ timeout++;
++ if (timeout > 100000)
++ {
++ return(EC_AAL5 |EC_FUNC_CHTEARDOWN|EC_VAL_TX_TEARDOWN_TIMEOUT);
++ }
++ }
++ }
++ } /* if DoTx */
++
++ /* Perform Rx Teardown Duties */
++ if ((DoRx) && (HalDev->State == enOpened))
++ {
++
++ /* call main teardown routine for Rx */
++ Ret = HalDev->SarFunc->ChannelTeardown(HalDev->SarDev, Ch, Mode);
++ if (Ret) return (Ret);
++
++ if (Mode & BLOCKING_TEARDOWN)
++ {
++ timeout = 0;
++ while (HalDev->ChIsOpen[Ch][DIRECTION_RX] == TRUE)
++ {
++ osfuncSleep(&Sleep);
++
++ timeout++;
++ if (timeout > 100000)
++ {
++ return(EC_AAL5 |EC_FUNC_CHTEARDOWN|EC_VAL_RX_TEARDOWN_TIMEOUT);
++ }
++ }
++ }
++ } /* if DoRx */
++
++ return (EC_NO_ERRORS);
++ }
++
++/**
++ * @ingroup CPHAL_Functions
++ * This function closes the CPHAL module. The module will be reset.
++ * The Mode parameter should be used to determine the actions taken by
++ * Close().
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ * @param Mode Indicates actions to take on close. The following integer
++ * values are valid: <BR>
++ * 1: Does not free buffer resources, init parameters remain
++ * intact. User can then call Open() without calling Init()
++ * to attempt to reset the device and bring it back to the
++ * last known state.<BR>
++ * 2: Frees the buffer resources, but keeps init parameters. This
++ * option is a more aggressive means of attempting a device reset.
++ * 3: Frees the buffer resources, and clears all init parameters. <BR>
++ * At this point, the caller would have to call to completely
++ * reinitialize the device (Init()) before being able to call
++ * Open(). Use this mode if you are shutting down the module
++ * and do not plan to restart.
++ *
++ * @return EC_NO_ERRORS (ok).<BR>
++ * Possible Error Codes:<BR>
++ * @ref EC_VAL_INVALID_STATE "EC_VAL_INVALID_STATE"<BR>
++ * Any error code from halChannelTeardown().<BR>
++ */
++static int halClose(HAL_DEVICE *HalDev, bit32 Mode)
++ {
++ int Ch, Inst, Ret;
++ OS_DEVICE *TmpOsDev;
++ OS_FUNCTIONS *TmpOsFunc;
++ HAL_FUNCTIONS *TmpHalFunc;
++ char *TmpDeviceInfo;
++
++ CPSAR_FUNCTIONS *TmpSarFunc;
++ CPSAR_DEVICE *TmpSarDev;
++
++ /* Verify proper device state */
++ if (HalDev->State != enOpened)
++ return (EC_AAL5 | EC_FUNC_CLOSE|EC_VAL_INVALID_STATE);
++
++ /* Teardown all open channels */
++ for (Ch = 0; Ch <= MAX_AAL5_CHAN ; Ch++)
++ {
++ if (HalDev->ChIsOpen[Ch][DIRECTION_TX] == TRUE)
++ {
++ if (Mode == 1)
++ {
++ Ret = halChannelTeardown(HalDev, Ch, TX_TEARDOWN | PARTIAL_TEARDOWN | BLOCKING_TEARDOWN);
++ if (Ret) return (Ret);
++ }
++ else
++ {
++ Ret = halChannelTeardown(HalDev, Ch, TX_TEARDOWN | FULL_TEARDOWN | BLOCKING_TEARDOWN);
++ if (Ret) return (Ret);
++ }
++ }
++
++ if (HalDev->ChIsOpen[Ch][DIRECTION_RX] == TRUE)
++ {
++ if (Mode == 1)
++ {
++ Ret = halChannelTeardown(HalDev, Ch, RX_TEARDOWN | PARTIAL_TEARDOWN | BLOCKING_TEARDOWN);
++ if (Ret) return (Ret);
++ }
++ else
++ {
++ Ret = halChannelTeardown(HalDev, Ch, RX_TEARDOWN | FULL_TEARDOWN | BLOCKING_TEARDOWN);
++ if (Ret) return (Ret);
++ }
++ }
++ }
++
++ /* free fraglist in HalDev */
++ HalDev->OsFunc->Free(HalDev->fraglist);
++ HalDev->fraglist = 0;
++
++ /* unregister the interrupt */
++ HalDev->OsFunc->IsrUnRegister(HalDev->OsDev, HalDev->interrupt);
++
++ /* Disable the Tx CPPI DMA */
++ TX_CPPI_CTL_REG(HalDev->dev_base) = 0;
++
++ /* Disable the Rx CPPI DMA */
++ RX_CPPI_CTL_REG(HalDev->dev_base) = 0;
++
++ /* Close the SAR hardware - puts the device in reset if this module is the
++ "last one out" */
++ HalDev->SarFunc->Close(HalDev->SarDev, Mode);
++
++ /* If mode is 3, than clear the HalDev and set next state to DevFound*/
++ if (Mode == 3)
++ {
++ /* I need to keep the HalDev parameters that were setup in InitModule */
++ TmpOsDev = HalDev->OsDev;
++ TmpOsFunc = HalDev->OsFunc;
++ TmpDeviceInfo = HalDev->DeviceInfo;
++
++ TmpSarFunc = HalDev->SarFunc;
++ TmpSarDev = HalDev->SarDev;
++
++ TmpHalFunc = HalDev->HalFuncPtr;
++ Inst = HalDev->Inst;
++
++ /* Clear HalDev */
++
++ HalDev->OsFunc->Memset(HalDev, 0, sizeof(HAL_DEVICE));
++
++ /* Restore key parameters */
++ HalDev->OsDev = TmpOsDev;
++ HalDev->OsFunc = TmpOsFunc;
++ HalDev->DeviceInfo = TmpDeviceInfo;
++
++ HalDev->SarFunc = TmpSarFunc;
++ HalDev->SarDev = TmpSarDev;
++
++ HalDev->HalFuncPtr = TmpHalFunc;
++ HalDev->Inst = Inst;
++
++ HalDev->State = enDevFound;
++ }
++ else
++ {
++ HalDev->State = enInitialized;
++ }
++
++ return(EC_NO_ERRORS);
++ }
+diff -urN linux.old/drivers/atm/sangam_atm/cpremap_cpaal5.c linux.dev/drivers/atm/sangam_atm/cpremap_cpaal5.c
+--- linux.old/drivers/atm/sangam_atm/cpremap_cpaal5.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/cpremap_cpaal5.c 2005-08-23 04:46:50.084845672 +0200
+@@ -0,0 +1,27 @@
++#ifndef _INC_CPREMAP_C
++#define _INC_CPREMAP_C
++
++#ifdef __ADAM2
++static inline void osfuncDataCacheHitInvalidate(void *ptr, int Size)
++ {
++ asm(" cache 17, (%0)" : : "r" (ptr));
++ }
++
++static inline void osfuncDataCacheHitWriteback(void *ptr, int Size)
++ {
++ asm(" cache 25, (%0)" : : "r" (ptr));
++ }
++
++#else
++ #define osfuncDataCacheHitInvalidate(MemPtr, Size) HalDev->OsFunc->DataCacheHitInvalidate(MemPtr, Size)
++ #define osfuncDataCacheHitWriteback(MemPtr, Size) HalDev->OsFunc->DataCacheHitWriteback(MemPtr, Size)
++#endif
++
++/*
++#define osfuncDataCacheHitInvalidate(ptr, Size) asm(" cache 17, (%0)" : : "r" (ptr))
++#define osfuncDataCacheHitWriteback(ptr, Size) asm(" cache 25, (%0)" : : "r" (ptr))
++*/
++
++
++
++#endif
+diff -urN linux.old/drivers/atm/sangam_atm/cpremap_cpsar.c linux.dev/drivers/atm/sangam_atm/cpremap_cpsar.c
+--- linux.old/drivers/atm/sangam_atm/cpremap_cpsar.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/cpremap_cpsar.c 2005-08-23 04:46:50.084845672 +0200
+@@ -0,0 +1,27 @@
++#ifndef _INC_CPREMAP_C
++#define _INC_CPREMAP_C
++
++#ifdef __ADAM2
++static inline void osfuncDataCacheHitInvalidate(void *ptr, int Size)
++ {
++ asm(" cache 17, (%0)" : : "r" (ptr));
++ }
++
++static inline void osfuncDataCacheHitWriteback(void *ptr, int Size)
++ {
++ asm(" cache 25, (%0)" : : "r" (ptr));
++ }
++
++#else
++ #define osfuncDataCacheHitInvalidate(MemPtr, Size) HalDev->OsFunc->DataCacheHitInvalidate(MemPtr, Size)
++ #define osfuncDataCacheHitWriteback(MemPtr, Size) HalDev->OsFunc->DataCacheHitWriteback(MemPtr, Size)
++#endif
++
++/*
++#define osfuncDataCacheHitInvalidate(ptr, Size) asm(" cache 17, (%0)" : : "r" (ptr))
++#define osfuncDataCacheHitWriteback(ptr, Size) asm(" cache 25, (%0)" : : "r" (ptr))
++*/
++
++
++
++#endif
+diff -urN linux.old/drivers/atm/sangam_atm/cpsar.c linux.dev/drivers/atm/sangam_atm/cpsar.c
+--- linux.old/drivers/atm/sangam_atm/cpsar.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/cpsar.c 2005-08-23 04:46:50.086845368 +0200
+@@ -0,0 +1,881 @@
++/**
++ * cpsar.c
++ *
++ * TNETDxxxx Software Support\n
++ * Copyright (c) 2002 Texas Instruments Incorporated. All Rights Reserved.
++ *
++ * This file contains the HAL for the CPSAR module. In the software
++ * architecture, the CPSAR module is used exclusively by the AAL5 and AAL2
++ * CPHAL modules. AAL5 and AAL2 may utilize the same CPSAR instance
++ * simulataneously.
++ *
++ * version
++ * 5Sep02 Greg 1.00 Original Version created.
++ */
++
++/* register files */
++#include "cp_sar_reg.h"
++
++#define _CPHAL_CPSAR
++#define _CPHAL
++
++#define WAIT_THRESH 200000
++#define IRAM_SIZE 1536
++#define MAX_INST 2
++
++/* OS Data Structure definition */
++
++typedef void OS_PRIVATE;
++typedef void OS_DEVICE;
++typedef void OS_SENDINFO;
++typedef void OS_RECEIVEINFO;
++typedef void OS_SETUP;
++
++/* CPHAL Data Structure definitions */
++
++typedef struct cpsar_device CPSAR_DEVICE;
++typedef struct cpsar_device HAL_DEVICE;
++typedef void HAL_RECEIVEINFO;
++
++#define MAX_QUEUE 2
++#define MAX_CHAN 19
++
++#include "cpcommon_cpsar.h"
++#include "cpswhal_cpsar.h"
++#include "cpsar.h"
++#include "cpcommon_cpsar.c"
++
++static CPSAR_DEVICE *CpsarDev[MAX_INST]= {0,0};
++
++/*
++ * Returns statistics information.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ *
++ * @return 0
++ */
++static int StatsGet3(CPSAR_DEVICE *HalDev)
++ {
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpsar]StatsGet3(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++ /*
++ dbgPrintf("CPSAR General Stats:\n");
++ DispHexStat(HalDev, "Base Address",HalDev->dev_base);
++ DispStat(HalDev, "Offset (VLYNQ)",HalDev->offset);
++ DispStat(HalDev, "Debug Level",HalDev->debug);
++ DispStat(HalDev, "Instance",HalDev->Inst);
++ DispHexStat(HalDev, "Reset Address",HalDev->ResetBase);
++ DispStat(HalDev, "Reset Bit",HalDev->ResetBit);
++ */
++ return (EC_NO_ERRORS);
++ }
++
++/* +GSG 030407 */
++static void SetOamMode(HAL_DEVICE *HalDev)
++ {
++ int Ch;
++ volatile bit32u *pTmp;
++ int OamMode = (1<<8);
++
++ /* any configuration of OamMode affects all VC's, including AAL2 */
++ for (Ch = 0; Ch < MAX_CHAN; Ch++)
++ {
++ if (Ch < 16)
++ pTmp = (pPDSP_AAL5_RX_STATE_WORD_0(HalDev->dev_base) + (Ch*64));
++ else
++ pTmp = (pPDSP_AAL2_RX_STATE_WORD_0(HalDev->dev_base) + ((Ch-16)*64));
++
++ if (HalDev->OamMode == 0)
++ {
++ *pTmp &=~ OamMode;
++ }
++ else
++ {
++ *pTmp |= OamMode;
++ }
++ }
++ }
++
++static int halControl(CPSAR_DEVICE *HalDev, const char *Key, const char *Action, void *Value)
++ {
++ int KeyFound=0, ActionFound=0, rc=EC_NO_ERRORS, Ch; /* +RC3.02*/
++ char *TmpKey = (char *)Key;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpsar]halControl(HalDev:%08x, Key:%s, Action:%s, Value:%08x)\n", (bit32u)HalDev,
++ Key, Action, (bit32u)Value);
++ osfuncSioFlush();
++ }
++#endif
++
++ if (HalDev->OsFunc->Strcmpi(Key, "Debug") == 0)
++ {
++ KeyFound=1; /* +RC3.02*/
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1; /* +RC3.02*/
++ HalDev->debug = *(int *)Value;
++ }
++ }
++
++ /* +GSG 030407 */
++ if (HalDev->OsFunc->Strcmpi(Key, "OamMode") == 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++ HalDev->OamMode = *(int *)Value;
++
++ /* only do this if we're open */
++ if (HalDev->OpenCount > 0)
++ SetOamMode(HalDev);
++ }
++
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ {
++ ActionFound=1;
++ *(int *)Value = HalDev->OamMode;
++ }
++ }
++
++ if (HalDev->OsFunc->Strcmpi(Key, "Stats3") == 0)
++ {
++ if (HalDev->OsFunc->Strcmpi(Action, "Get") == 0)
++ StatsGet3(HalDev);
++ }
++
++ /* +RC3.02 (if statement) */
++ /* Fixes PITS #98 */
++ if (HalDev->OsFunc->Strstr(Key, "PdspEnable") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++
++ /* Configure PDSP enable bit based on Value*/
++ if (*(int *)Value & 1)
++ {
++ /* enable PDSP */
++ PDSP_CTRL_REG(HalDev->dev_base) |= 0x2;
++ }
++ else
++ {
++ /* disable PDSP */
++ PDSP_CTRL_REG(HalDev->dev_base) &=~ 0x2;
++ }
++ }
++ }
++
++ if (HalDev->OsFunc->Strstr(Key, "FwdUnkVc.") != 0)
++ {
++ KeyFound=1;
++ if (HalDev->OsFunc->Strcmpi(Action, "Set") == 0)
++ {
++ ActionFound=1;
++
++ /* extract channel number */
++ TmpKey += HalDev->OsFunc->Strlen("FwdUnkVc.");
++ Ch = HalDev->OsFunc->Strtoul(TmpKey, &TmpKey, 10);
++
++ /* Configure forwarding of unknown VCI/VPI cells */
++ SAR_PDSP_FWD_UNK_VC_REG(HalDev->dev_base) = (((*(int*)Value)<<31) | Ch);
++ }
++ }
++
++ if (KeyFound == 0) /* +RC3.02 */
++ rc = (EC_CPSAR|EC_FUNC_CONTROL|EC_VAL_KEY_NOT_FOUND); /* +RC3.02 */
++
++ if (ActionFound == 0) /* +RC3.02 */
++ rc = (EC_CPSAR|EC_FUNC_CONTROL|EC_VAL_ACTION_NOT_FOUND); /* +RC3.02 */
++
++ return(rc); /* ~RC3.02 */
++ }
++
++/*
++ * This function opens the specified channel.
++ *
++ * @param HalDev CPHAL module instance. (set by cphalInitModule())
++ * @param Ch Channel number.
++ *
++ * @return 0 OK, Non-zero Not OK
++ */
++static int halChannelSetup(CPSAR_DEVICE *HalDev, CHANNEL_INFO *HalCh)
++ {
++ int i;
++ int Ch = HalCh->Channel;
++ int PdspChBlock = Ch;
++ int PdspBlockOffset = 0;
++ volatile bit32u *pTmp;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpsar]halChannelSetup(HalDev:%08x, HalCh:%08x)\n", (bit32u)HalDev,
++ (bit32u)HalCh);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Figure out the correct offset from the start of the PDSP
++ Scratchpad RAM (starting at 0x8050 in the SAR) */
++ if (Ch > 15)
++ {
++ /* this is an AAL2 channel, which are channels 16-18 */
++ PdspChBlock = Ch - 16;
++ /* Get the offset to the AAL2 portion of the block (in words) */
++ PdspBlockOffset = NUM_PDSP_AAL5_STATE_WORDS + (PdspChBlock*64);
++ /* Clear PDSP State RAM */
++ /*pTmp = (pPDSP_BLOCK_0(HalDev->dev_base)+PdspBlockOffset);
++ for (i=0; i<NUM_PDSP_AAL2_STATE_WORDS; i++)
++ *pTmp++ = 0;*/
++ }
++ else
++ {
++ /* Get the offset to the AAL5 portion of the block (in words) */
++ PdspBlockOffset = (PdspChBlock*64);
++ /* Clear PDSP State RAM */
++ /*pTmp = (pPDSP_BLOCK_0(HalDev->dev_base)+PdspBlockOffset);
++ for (i=0; i<NUM_PDSP_AAL5_STATE_WORDS; i++)
++ *pTmp++ = 0;*/
++ }
++
++ /* Configure PDSP State RAM */
++
++ /* Setup TX PDSP State RAM */
++ pTmp = (pPDSP_BLOCK_0(HalDev->dev_base)+PdspBlockOffset);
++ *pTmp++ = HalCh->TxVc_CellRate; /* Set the cell rate in cells/sec */
++ *pTmp++ = HalCh->TxVc_QosType; /* Configure the QoS Type */
++ *pTmp++ = HalCh->TxVc_Mbs; /* Set minimum burst size */
++ *pTmp++ = 0; /* (skip a register) */
++ *pTmp++ = HalCh->TxVc_Pcr; /* set the peak cell rate */
++ *pTmp++ = 0; /* new addition 4.9.02 */
++ *pTmp++ = HalCh->TxVc_AtmHeader; /* give the ATM header */
++ *pTmp++ = (HalCh->TxVc_OamTc << 8)
++ |(HalCh->TxVc_VpOffset); /* Set the OAM TC Path and VP Offset */
++
++ /* Setup RX PDSP State RAM */
++ *pTmp++ = (HalCh->RxVc_OamCh)|
++ (HalDev->OamMode << 8) |
++ (HalCh->RxVc_OamToHost<<9); /* Set OAM Channel, Mode, and ToHost options */
++ *pTmp++ = HalCh->RxVc_AtmHeader; /* ATM hdr put on firmware generated OAM */
++ *pTmp++ = (HalCh->RxVc_VpOffset)| /* Set Rx OAM TC Path and VP Offset */
++ (HalCh->RxVc_OamTc<<8);
++
++ /* Setup TX VP PDSP State RAM */
++ pTmp = (pPDSP_BLOCK_0(HalDev->dev_base)+PdspBlockOffset+16); /*GSG~030703 12->16 */
++ *pTmp++ = HalCh->TxVp_AtmHeader;
++ *pTmp++ = (HalCh->TxVp_OamTc << 8);
++
++ /* Setup RX VP PDSP State RAM */
++ pTmp = (pPDSP_BLOCK_0(HalDev->dev_base)+PdspBlockOffset+20); /*GSG~030703 16->20 */
++ *pTmp++ = HalCh->RxVp_AtmHeader;
++ *pTmp++ = (HalCh->RxVp_OamCh)|
++ (HalCh->RxVp_OamTc<<8)|
++ (HalCh->RxVp_OamToHost<<9); /* Set OAM Channel, Mode, and ToHost options */
++ *pTmp++ = 0;
++ *pTmp++ = HalCh->RxVp_OamVcList;
++
++ /* Configure forwarding of unknown VCI/VPI cells */
++ if (HalCh->PktType == 3)
++ SAR_PDSP_FWD_UNK_VC_REG(HalDev->dev_base) = ((HalCh->FwdUnkVc<<31)|Ch);
++
++ /* Configure Tx Channel Mapping Register (turn channel "ON") */
++ TX_CH_MAPPING_REG(HalDev->dev_base) = 0x80000000 |
++ (HalCh->DaMask << 30)
++ | (HalCh->Priority << 24) | Ch;
++
++ /* Setup Rx Channel in the LUT */
++ i=0;
++ while (!(RX_LUT_CH_SETUP_REQ_REG(HalDev->dev_base) & 0x80000000))
++ {
++ if (i > WAIT_THRESH)
++ {
++ return(EC_CPSAR|EC_FUNC_CHSETUP|EC_VAL_LUT_NOT_READY);
++ }
++ else
++ i++;
++ }
++
++ /* RX LUT is ready */
++ RX_LUT_CH_SETUP_REQ_REG(HalDev->dev_base) = (HalCh->PktType << 24) | Ch;
++ RX_LUT_CH_SETUP_REQ_VC_REG(HalDev->dev_base) = ((HalCh->Vpi << 20) |
++ (HalCh->Vci << 4));
++
++ return (EC_NO_ERRORS);
++ }
++
++static int halChannelTeardown(CPSAR_DEVICE *HalDev, int Ch, bit32 Mode)
++ {
++ int waitcnt = 0;
++ int PdspBlockOffset = 0, i;
++ volatile bit32u *pTmp;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpsar]halChannelTeardown(HalDev:%08x, Ch:%d, Mode:%d\n",
++ (bit32u)HalDev, Ch, Mode);
++ osfuncSioFlush();
++ }
++#endif
++
++ if ((Ch < 0) || (Ch > MAX_CHAN))
++ return(EC_CPSAR|EC_FUNC_CHTEARDOWN|EC_VAL_INVALID_CH);
++
++ /* Request RX channel teardown through LUT */
++ while ((RX_LUT_CH_TEARDOWN_REQ_REG(HalDev->dev_base) & 0x80000000) == 0)
++ {
++ waitcnt++;
++ if (waitcnt == WAIT_THRESH)
++ {
++ return(EC_CPSAR|EC_FUNC_CHTEARDOWN|EC_VAL_LUT_NOT_READY);
++ }
++ }
++
++ RX_LUT_CH_TEARDOWN_REQ_REG(HalDev->dev_base) = (Ch & 0xffff);
++
++ /* for AAL2, clear channel PDSP RAM here. AAL5 does it when the teardown
++ has completed (which is asynchronous)*/
++ if (Ch > 15)
++ {
++ /* Get the offset to the AAL2 portion of the block (in words) */
++ PdspBlockOffset = NUM_PDSP_AAL5_STATE_WORDS + ((Ch-16)*64);
++ /* Clear PDSP State RAM */
++ pTmp = (pPDSP_BLOCK_0(HalDev->dev_base)+PdspBlockOffset);
++ for (i=0; i<NUM_PDSP_AAL2_STATE_WORDS; i++)
++ *pTmp++ = 0;
++ }
++
++ return (EC_NO_ERRORS);
++ }
++
++int InitPdsp(CPSAR_DEVICE *HalDev)
++ {
++ bit32u NumOfEntries,i,IRamAddress,iTmp;
++ int *SarPdspFirmware; /* ~GSG 030403 */
++ int FirmwareSize, rc; /* ~GSG 030403 */
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpsar]InitPdsp(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Get firmware */
++ rc = HalDev->OsFunc->Control(HalDev->OsDev, "Firmware", "Get", &SarPdspFirmware); /* ~GSG 030403 */
++ if (rc) /* +GSG 030403 */
++ return (EC_CPSAR|EC_FUNC_OPEN|EC_VAL_KEY_NOT_FOUND); /* +GSG 030403 */
++
++ /* Get firmware size */
++ rc = HalDev->OsFunc->Control(HalDev->OsDev, "FirmwareSize", "Get", &FirmwareSize); /* ~GSG 030403 */
++ if (rc) /* +GSG 030403 */
++ return (EC_CPSAR|EC_FUNC_OPEN|EC_VAL_KEY_NOT_FOUND); /* +GSG 030403 */
++
++ IRamAddress = (bit32u) pPDSP_CTRL_REG(HalDev->dev_base);
++
++ NumOfEntries = (FirmwareSize)/4; /* ~GSG 030403 */
++ if (NumOfEntries > IRAM_SIZE)
++ {
++ /* Note: On Avalanche, they truncated the PDSP firmware and warned */
++ /* NumOfEntries = IRAM_SIZE; */
++ return(EC_CPSAR|EC_FUNC_INIT|EC_VAL_FIRMWARE_TOO_LARGE);
++ }
++ for(i=8;i<NumOfEntries;i++)
++ (*((bit32 *) (IRamAddress+(i*4))))=SarPdspFirmware[i]; /* ~GSG 030403 */
++
++ /* Check code */
++ for(i=8;i<NumOfEntries;i++)
++ {
++ iTmp=(*((bit32 *) (IRamAddress+(i*4))));
++ if (iTmp != SarPdspFirmware[i]) /* ~GSG 030403 */
++ {
++ return(EC_CPSAR|EC_FUNC_OPEN|EC_VAL_PDSP_LOAD_FAIL);
++ }
++ }
++
++ return(EC_NO_ERRORS);
++ }
++
++/*
++ * This function probes for the instance of the CPHAL module. It will call
++ * the OS function @c DeviceFindInfo() to get the information required.
++ *
++ * @param HalDev CPHAL module instance. (set by xxxInitModule())
++ *
++ * @return 0 OK, Otherwise error.
++ */
++static int halProbe(CPSAR_DEVICE *HalDev)
++ {
++ int Ret;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpsar]halProbe(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(1))
++ {
++ dbgPrintf("[os]DeviceFindInfo(Inst:%d, DeviceName:%s, DeviceInfo:%08x)\n",
++ HalDev->Inst, "sar", (bit32u)&HalDev->DeviceInfo);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Attempt to find the device information */
++ Ret = HalDev->OsFunc->DeviceFindInfo(HalDev->Inst, "sar", &HalDev->DeviceInfo);
++ if (Ret)
++ return(EC_CPSAR|EC_FUNC_PROBE|EC_VAL_DEVICE_NOT_FOUND);
++
++ return(EC_NO_ERRORS);
++ }
++
++#ifdef __CPHAL_DEBUG
++static void dbgConfigDump(HAL_DEVICE *HalDev)
++ {
++ dbgPrintf(" [cpsar Inst %d] Config Dump:\n", HalDev->Inst);
++ dbgPrintf(" Base :%08x, offset :%08d\n",
++ HalDev->dev_base, HalDev->offset);
++ dbgPrintf(" ResetBit:%08d, ResetBase:%08x\n",
++ HalDev->ResetBit, HalDev->ResetBase);
++ dbgPrintf(" UniNni :%08d, debug :%08d\n",
++ HalDev->ResetBit, HalDev->debug);
++ osfuncSioFlush();
++ }
++#endif
++
++/*
++ * Sets up HAL default configuration parameter values.
++ */
++static void ConfigInit(CPSAR_DEVICE *HalDev)
++ {
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpsar]ConfigInit(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++ /* configure some defaults with tnetd7300 values */
++ HalDev->dev_base = 0xa3000000;
++ HalDev->offset = 0;
++ HalDev->UniNni = CFG_UNI_NNI;
++ HalDev->ResetBit = 9;
++ HalDev->debug = 0;
++ HalDev->ResetBase = 0xa8611600;
++ }
++
++/*
++ * Retrieve HAL configuration parameter values.
++ */
++static bit32u ConfigGet(HAL_DEVICE *HalDev)
++ {
++ bit32u ParmValue, error_code;
++ char *DeviceInfo = HalDev->DeviceInfo;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpsar]ConfigGet(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* get the configuration parameters common to all modules */
++ error_code = ConfigGetCommon(HalDev);
++ if (error_code) return (EC_CPSAR|error_code);
++
++ /* get SAR specific configuration parameters */
++ error_code = HalDev->OsFunc->DeviceFindParmUint(DeviceInfo,"UniNni",&ParmValue);
++ if (!error_code) HalDev->UniNni = ParmValue;
++
++ return (EC_NO_ERRORS);
++ }
++
++static int halInit(CPSAR_DEVICE *HalDev)
++ {
++ bit32u Ret;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpsar]halInit(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(7))
++ {
++ dbgPrintf("[cpsar halInit()]InitCount = %d\n", HalDev->InitCount);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Only run the init code for the first calling module per instance */
++ if (HalDev->InitCount > 1)
++ {
++ return (EC_NO_ERRORS);
++ }
++
++ /* Configure HAL defaults */
++ ConfigInit(HalDev);
++
++ /* Retrieve HAL configuration parameters from data store */
++ Ret = ConfigGet(HalDev);
++ if (Ret) return (Ret);
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(9))
++ dbgConfigDump(HalDev);
++#endif
++
++ return(EC_NO_ERRORS);
++ }
++
++static int halOpen(CPSAR_DEVICE *HalDev)
++ {
++ int Ret, Ticks=64;
++ int i; /*+GSG 030407*/
++ volatile int *pTmp; /*+GSG 030407*/
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpsar]halOpen(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(7))
++ {
++ dbgPrintf("[cpsar halOpen()]OpenCount = %d\n", HalDev->OpenCount);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Only run the open code for the first calling module per instance */
++ if (HalDev->OpenCount++ > 0)
++ {
++ return (EC_NO_ERRORS);
++ }
++
++ /* Take SAR out of reset */
++ if (((*(volatile bit32u *)(HalDev->ResetBase)) & (1<<HalDev->ResetBit)) != 0)
++ {
++ /** @todo Should I somehow call AAL5/AAL2 Close() here? All I've done
++ here is copy the Close code from each and paste it here. */
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(7))
++ {
++ dbgPrintf("[cpsar halOpen()]Module was already out of reset.\n");
++ dbgPrintf(" Closing module and resetting.\n");
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Disable the Tx CPPI DMA */
++ TX_CPPI_CTL_REG(HalDev->dev_base) = 0;
++
++ /* Disable the Rx CPPI DMA */
++ RX_CPPI_CTL_REG(HalDev->dev_base) = 0;
++
++ /* Disable the PDSP */
++ PDSP_CTRL_REG(HalDev->dev_base) &=~ 0x00000002;
++
++ /* disable interrupt masks */
++ SAR_TX_MASK_CLR(HalDev->dev_base) = 0xffffffff;
++ SAR_RX_MASK_CLR(HalDev->dev_base) = 0xffffffff;
++
++#ifndef NO_RESET /* GSG+ 030428 */
++ /* clear reset bit */
++ (*(volatile bit32u *)(HalDev->ResetBase)) &=~ (1<<HalDev->ResetBit); /* ~GSG 030307 */
++ HalDev->OsFunc->Control(HalDev->OsDev, "Sleep", "", &Ticks);
++
++ /* set reset bit */
++ (*(volatile bit32u *)(HalDev->ResetBase)) |= (1<<HalDev->ResetBit); /* ~GSG 030307 */
++ HalDev->OsFunc->Control(HalDev->OsDev, "Sleep", "", &Ticks);
++#endif /* GSG+ 030428 */
++ }
++ else
++ {
++ (*(volatile bit32u *)(HalDev->ResetBase)) |= (1<<HalDev->ResetBit); /* ~GSG 030307 */
++ HalDev->OsFunc->Control(HalDev->OsDev, "Sleep", "", &Ticks);
++ }
++
++ /* Configure UNI/NNI */
++ RX_LUT_GLOBAL_CFG_REG(HalDev->dev_base) |= (HalDev->UniNni & 0x1);
++
++ /* Clear entire PDSP state RAM */ /*+GSG 030407*/
++ pTmp = (pTX_DMA_STATE_WORD_0(HalDev->dev_base)); /*+GSG 030407*/
++ for (i=0; i<PDSP_STATE_RAM_SIZE; i++) /*+GSG 030407*/
++ *pTmp++ = 0; /*+GSG 030407*/
++
++ /* Configure Oam Mode */ /*+GSG 030407*/
++ SetOamMode(HalDev); /*+GSG 030407*/
++
++ /* Initialize PDSP */
++ Ret=InitPdsp(HalDev);
++ if(Ret)
++ return(Ret);
++
++ /* Reset and Enable the PDSP */
++ PDSP_CTRL_REG(HalDev->dev_base) = 0x00080003;
++
++ return(EC_NO_ERRORS);
++ }
++
++static int halClose(CPSAR_DEVICE *HalDev, int Mode)
++ {
++ int Ticks = 64;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpsar]halClose(HalDev:%08x, Mode:%d)\n", (bit32u)HalDev, Mode);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* handle the error case if there is nothing open */
++ if (HalDev->OpenCount == 0)
++ {
++ return(EC_CPSAR|EC_FUNC_CLOSE|EC_VAL_MODULE_ALREADY_CLOSED);
++ }
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(7))
++ {
++ dbgPrintf("[cpsar halClose()]OpenCount = %d\n", HalDev->OpenCount);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Only run the close code for the last calling module per instance */
++ if (HalDev->OpenCount-- > 1)
++ {
++ return (EC_NO_ERRORS);
++ }
++
++ /* Disable the PDSP */
++ PDSP_CTRL_REG(HalDev->dev_base) &=~ 0x00000002;
++
++#ifndef NO_RESET /* GSG +030428 */
++ /* put device back into reset */
++ (*(volatile bit32u *)(HalDev->ResetBase)) &=~ (1<<HalDev->ResetBit); /* ~GSG 030307 */
++ HalDev->OsFunc->Control(HalDev->OsDev, "Sleep", "", &Ticks);
++#endif /* GSG +030428 */
++
++ return(EC_NO_ERRORS);
++ }
++
++static int halShutdown(CPSAR_DEVICE *HalDev)
++ {
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpsar]halShutdown(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* handle the error case */
++ if (HalDev->InitCount == 0)
++ {
++ return(EC_CPSAR|EC_FUNC_CLOSE|EC_VAL_MODULE_ALREADY_SHUTDOWN);
++ }
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(7))
++ {
++ dbgPrintf("[cpsar halShutdown()]InitCount = %d\n", HalDev->InitCount);
++ osfuncSioFlush();
++ }
++#endif
++
++ /* Only run the shutdown code for the last calling module per instance */
++ if (HalDev->InitCount-- > 1)
++ {
++ return (EC_NO_ERRORS);
++ }
++
++ /* free the SAR functions */
++#ifdef __CPHAL_DEBUG
++ if (DBG(6))
++ {
++ dbgPrintf(" [cpsar halShutdown()]: Free CPSAR function pointers\n");
++ osfuncSioFlush();
++ }
++ if (DBG(1)||DBG(3))
++ {
++ dbgPrintf("[os]Free(MemPtr:%08x)\n", (bit32u)HalDev->HalFuncPtr);
++ osfuncSioFlush();
++ }
++#endif
++ /* free the HalFunc */
++ HalDev->OsFunc->Free(HalDev->HalFuncPtr);
++
++ /* we have a static global, so I should clear it's value as well */
++ CpsarDev[HalDev->Inst] = 0;
++
++#ifdef __CPHAL_DEBUG
++ if (DBG(6))
++ {
++ dbgPrintf(" [cpsar halShutdown()]Free HalDev\n");
++ osfuncSioFlush();
++ }
++ if (DBG(1)||DBG(3))
++ {
++ dbgPrintf("[os]Free(MemPtr:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++ /* free the CPSAR device */
++ HalDev->OsFunc->Free(HalDev);
++
++ return(EC_NO_ERRORS);
++ }
++
++static int halTick(CPSAR_DEVICE *HalDev)
++ {
++#ifdef __CPHAL_DEBUG
++ if (DBG(0))
++ {
++ dbgPrintf("[cpsar]halTick(HalDev:%08x)\n", (bit32u)HalDev);
++ osfuncSioFlush();
++ }
++#endif
++
++ return(EC_NO_ERRORS);
++ }
++
++/*
++ * The CPSAR version of InitModule() should be passed the OS_FUNCTIONS pointer,
++ * and will return the HalDev pointer.
++ *
++ * @param HalDev Pointer to CPSAR module information. This will
++ * be used by the OS when communicating to this module via
++ * CPSAR.
++ * @param OsDev Pointer to OS device information. This will be saved by
++ * the CPSAR and returned to the OS when required.
++ * @param HalFunc HAL_FUNCTIONS pointer.
++ * @param Size Pointer to the size of the HAL_FUNCTIONS structure. (If
++ * HalFunc is 0, the value will be set by CPSAR, otherwise
++ * ignored)
++ * @param Inst The instance number of the module to initialize. (start at
++ * 0).
++ *
++ * @return 0 OK, Nonzero - error.
++ */
++/*
++int cpsarInitModule(CPSAR_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ CPSAR_FUNCTIONS *HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int *Size,
++ int Inst)
++*/
++int cpsarInitModule(CPSAR_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ CPSAR_FUNCTIONS **HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst)
++ {
++ CPSAR_DEVICE *HalPtr;
++ CPSAR_FUNCTIONS *HalFuncPtr;
++
++ /*
++ if ( HalFunc == 0 )
++ {
++ *Size = sizeof(CPSAR_FUNCTIONS);
++ return(EC_NO_ERRORS);
++ }
++ */
++
++ if (CpsarDev[Inst] != 0)
++ {
++ /* this SAR module has been connected to before, so do not
++ allocate another CPSAR_DEVICE */
++ HalPtr = CpsarDev[Inst];
++
++ /* increase count of attached modules */
++ HalPtr->InitCount++;
++ }
++ else
++ {
++ /* allocate the CPSAR_DEVICE structure */
++ HalPtr = (CPSAR_DEVICE *) OsFunc->MallocDev(sizeof(CPSAR_DEVICE));
++ if(!HalPtr)
++ return(EC_CPSAR|EC_FUNC_HAL_INIT|EC_VAL_MALLOC_DEV_FAILED);
++
++ HalFuncPtr = (CPSAR_FUNCTIONS *) OsFunc->Malloc(sizeof(CPSAR_FUNCTIONS));
++ if (!HalFuncPtr)
++ return (EC_CPSAR|EC_FUNC_HAL_INIT|EC_VAL_MALLOC_FAILED);
++
++ /* Initialize the size of hal functions */
++ *HalFuncSize = sizeof (CPSAR_FUNCTIONS);
++
++ /* ensure the device structure is cleared */
++ OsFunc->Memset(HalPtr, 0, sizeof(CPSAR_DEVICE));
++
++ /* clear the function pointers */
++ OsFunc->Memset(HalFuncPtr, 0, sizeof(CPSAR_FUNCTIONS));
++
++ /* Supply pointers for the CPSAR API functions */
++ HalFuncPtr->ChannelSetup = halChannelSetup;
++ HalFuncPtr->ChannelTeardown = halChannelTeardown;
++ HalFuncPtr->Close = halClose;
++ HalFuncPtr->Control = halControl;
++ HalFuncPtr->Init = halInit;
++ HalFuncPtr->Open = halOpen;
++ HalFuncPtr->Probe = halProbe;
++ HalFuncPtr->Shutdown = halShutdown;
++ HalFuncPtr->Tick = halTick;
++
++ /* keep a reference to HalFuncPtr so I can free it later */
++ HalPtr->HalFuncPtr = HalFuncPtr;
++
++ /* store the CPSAR_DEVICE, so the CPSAR module will know whether
++ it is in use for the given instance */
++ CpsarDev[Inst] = HalPtr;
++
++ /* increase count of attached modules */
++ HalPtr->InitCount++;
++ }
++
++ /* @todo Does this need modification to deal with multiple callers/
++ drivers? If different callers will use different OsDev/OsFunc,
++ then the current code will not work.
++ */
++
++ /* initialize the CPSAR_DEVICE structure */
++ HalPtr->OsDev = OsDev;
++ /*HalPtr->OsOpen = OsDev;*/
++ HalPtr->Inst = Inst;
++ HalPtr->OsFunc = OsFunc;
++
++ /* pass the HalPtr back to the caller */
++ *HalDev = HalPtr;
++ *HalFunc = HalPtr->HalFuncPtr;
++
++ return (EC_NO_ERRORS);
++ }
+diff -urN linux.old/drivers/atm/sangam_atm/cpsar_cpaal5.h linux.dev/drivers/atm/sangam_atm/cpsar_cpaal5.h
+--- linux.old/drivers/atm/sangam_atm/cpsar_cpaal5.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/cpsar_cpaal5.h 2005-08-23 04:46:50.087845216 +0200
+@@ -0,0 +1,103 @@
++/*******************************************************************************
++ * TNETDxxxx Software Support
++ * Copyright (c) 2002 Texas Instruments Incorporated. All Rights Reserved.
++ *
++ * FILE: cpsar.h
++ *
++ * DESCRIPTION:
++ * This file contains data structure definitions for the CPSAR HAL.
++ *
++ * HISTORY:
++ * 6Sep02 Greg 1.00 Original Version created.
++ *
++ *****************************************************************************/
++#ifndef _INC_CPSAR
++#define _INC_CPSAR
++
++#define NUM_RX_STATE_WORDS 7
++#define NUM_TX_STATE_WORDS 9
++#define MAX_CHAN 19
++
++
++#ifndef _CPHAL_CPSAR
++typedef void CPSAR_DEVICE;
++#endif
++
++/*
++ * HAL Default Parameter Values
++ */
++#define CFG_UNI_NNI 0
++
++/**
++ * @ingroup shared_data
++ *
++ * List of defined keys for use with Control().
++ */
++typedef enum
++ {
++ /* SAR */
++ enGET_FIRMWARE, /**< Used by the SAR to request a pointer to firmware */
++ enGET_FIRMWARE_SIZE, /**< Used by the SAR to request the size of the firmware */
++ enEND=9999 /* Last entry */
++ }INFO_KEY;
++
++/*
++ * The CPHAL_FUNCTIONS struct defines the CPHAL function pointers used by upper layer
++ * software. The upper layer software receives these pointers through the
++ * call to cphalInitModule().
++ */
++typedef struct
++ {
++ int (*ChannelSetup)(CPSAR_DEVICE *HalDev, CHANNEL_INFO *HalCh);
++ int (*ChannelTeardown)(CPSAR_DEVICE *HalDev, int Ch, int Mode);
++ int (*Close)(CPSAR_DEVICE *HalDev, int Mode);
++ int (*Control)(CPSAR_DEVICE *HalDev, const char *Key, const char *Action, void *Value);
++ int (*Init)(CPSAR_DEVICE *HalDev);
++ int (*ModeChange)(CPSAR_DEVICE *HalDev, char *DeviceParms);
++ int (*Open)(CPSAR_DEVICE *HalDev);
++ int (*Probe)(CPSAR_DEVICE *HalDev);
++ int (*Shutdown)(CPSAR_DEVICE *HalDev);
++ int (*Tick)(CPSAR_DEVICE *HalDev);
++ } CPSAR_FUNCTIONS;
++
++/*
++ * This is the data structure for a generic HAL device. It contains all device
++ * specific data for a single instance of that device. This includes Rx/Tx
++ * buffer queues, device base address, reset bit, and other information.
++ */
++typedef struct cpsar_device
++ {
++ bit32 dev_base;
++ bit32 offset;
++ bit32 TxTeardownPending[MAX_CHAN];
++ bit32 RxTeardownPending[MAX_CHAN];
++ bit32 ChIsOpen[MAX_CHAN];
++ bit32 ResetBit;
++ bit32 debug;
++ OS_DEVICE *OsDev;
++ OS_FUNCTIONS *OsFunc;
++ /*void *OsOpen;*/
++ bit32 UniNni;
++ bit32 Inst;
++ bit32u DeviceCPID[4];
++ bit32u LBSourceLLID[4];
++ bit32u OamRate[11];
++ CHANNEL_INFO ChData[MAX_CHAN];
++ int InitCount;
++ int OpenCount;
++ char *DeviceInfo;
++ bit32u ResetBase;
++ DEVICE_STATE State;
++ CPSAR_FUNCTIONS *HalFuncPtr;
++ int OamMode; /* +GSG 030407 */
++ }CPSARDEVICE;
++
++extern int cpsarInitModule(CPSAR_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ CPSAR_FUNCTIONS **HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++
++#endif
+diff -urN linux.old/drivers/atm/sangam_atm/cpsar.h linux.dev/drivers/atm/sangam_atm/cpsar.h
+--- linux.old/drivers/atm/sangam_atm/cpsar.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/cpsar.h 2005-08-23 04:46:50.087845216 +0200
+@@ -0,0 +1,103 @@
++/*******************************************************************************
++ * TNETDxxxx Software Support
++ * Copyright (c) 2002 Texas Instruments Incorporated. All Rights Reserved.
++ *
++ * FILE: cpsar.h
++ *
++ * DESCRIPTION:
++ * This file contains data structure definitions for the CPSAR HAL.
++ *
++ * HISTORY:
++ * 6Sep02 Greg 1.00 Original Version created.
++ *
++ *****************************************************************************/
++#ifndef _INC_CPSAR
++#define _INC_CPSAR
++
++#define NUM_RX_STATE_WORDS 7
++#define NUM_TX_STATE_WORDS 9
++#define MAX_CHAN 19
++
++
++#ifndef _CPHAL_CPSAR
++typedef void CPSAR_DEVICE;
++#endif
++
++/*
++ * HAL Default Parameter Values
++ */
++#define CFG_UNI_NNI 0
++
++/**
++ * @ingroup shared_data
++ *
++ * List of defined keys for use with Control().
++ */
++typedef enum
++ {
++ /* SAR */
++ enGET_FIRMWARE, /**< Used by the SAR to request a pointer to firmware */
++ enGET_FIRMWARE_SIZE, /**< Used by the SAR to request the size of the firmware */
++ enEND=9999 /* Last entry */
++ }INFO_KEY;
++
++/*
++ * The CPHAL_FUNCTIONS struct defines the CPHAL function pointers used by upper layer
++ * software. The upper layer software receives these pointers through the
++ * call to cphalInitModule().
++ */
++typedef struct
++ {
++ int (*ChannelSetup)(CPSAR_DEVICE *HalDev, CHANNEL_INFO *HalCh);
++ int (*ChannelTeardown)(CPSAR_DEVICE *HalDev, int Ch, int Mode);
++ int (*Close)(CPSAR_DEVICE *HalDev, int Mode);
++ int (*Control)(CPSAR_DEVICE *HalDev, const char *Key, const char *Action, void *Value);
++ int (*Init)(CPSAR_DEVICE *HalDev);
++ int (*ModeChange)(CPSAR_DEVICE *HalDev, char *DeviceParms);
++ int (*Open)(CPSAR_DEVICE *HalDev);
++ int (*Probe)(CPSAR_DEVICE *HalDev);
++ int (*Shutdown)(CPSAR_DEVICE *HalDev);
++ int (*Tick)(CPSAR_DEVICE *HalDev);
++ } CPSAR_FUNCTIONS;
++
++/*
++ * This is the data structure for a generic HAL device. It contains all device
++ * specific data for a single instance of that device. This includes Rx/Tx
++ * buffer queues, device base address, reset bit, and other information.
++ */
++typedef struct cpsar_device
++ {
++ bit32 dev_base;
++ bit32 offset;
++ bit32 TxTeardownPending[MAX_CHAN];
++ bit32 RxTeardownPending[MAX_CHAN];
++ bit32 ChIsOpen[MAX_CHAN];
++ bit32 ResetBit;
++ bit32 debug;
++ OS_DEVICE *OsDev;
++ OS_FUNCTIONS *OsFunc;
++ /*void *OsOpen;*/
++ bit32 UniNni;
++ bit32 Inst;
++ bit32u DeviceCPID[4];
++ bit32u LBSourceLLID[4];
++ bit32u OamRate[11];
++ CHANNEL_INFO ChData[MAX_CHAN];
++ int InitCount;
++ int OpenCount;
++ char *DeviceInfo;
++ bit32u ResetBase;
++ DEVICE_STATE State;
++ CPSAR_FUNCTIONS *HalFuncPtr;
++ int OamMode; /* +GSG 030407 */
++ }CPSARDEVICE;
++
++extern int cpsarInitModule(CPSAR_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ CPSAR_FUNCTIONS **HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++
++#endif
+diff -urN linux.old/drivers/atm/sangam_atm/cp_sar_reg.h linux.dev/drivers/atm/sangam_atm/cp_sar_reg.h
+--- linux.old/drivers/atm/sangam_atm/cp_sar_reg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/cp_sar_reg.h 2005-08-23 04:46:50.087845216 +0200
+@@ -0,0 +1,217 @@
++/***************************************************************************
++ TNETD73xx Software Support
++ Copyright(c) 2000, Texas Instruments Incorporated. All Rights Reserved.
++
++ FILE: cp_sar_reg.h Register definitions for the SAR module
++
++ DESCRIPTION:
++ This include file contains register definitions for the
++ SAR module.
++
++ HISTORY:
++ 15 Jan 02 G. Guyotte Original version written
++ 03 Oct 02 G. Guyotte C++ style comments removed
++****************************************************************************/
++#ifndef _INC_SAR_REG
++#define _INC_SAR_REG
++
++/* Global Registers */
++#define pSAR_ID_REG(base) ((volatile bit32u *)(base+0x0000))
++#define SAR_ID_REG(base) (*pSAR_ID_REG(base))
++#define pSAR_STATUS_SET_REG(base) ((volatile bit32u *)(base+0x0008))
++#define SAR_STATUS_SET_REG(base) (*pSAR_STATUS_SET_REG(base))
++#define pSAR_STATUS_CLR_REG(base) ((volatile bit32u *)(base+0x000C))
++#define SAR_STATUS_CLR_REG(base) (*pSAR_STATUS_CLR_REG(base))
++#define pSAR_HOST_INT_EN_SET_REG(base) ((volatile bit32u *)(base+0x0010))
++#define SAR_HOST_INT_EN_SET_REG(base) (*pSAR_HOST_INT_EN_SET_REG(base))
++#define pSAR_HOST_INT_EN_CLR_REG(base) ((volatile bit32u *)(base+0x0014))
++#define SAR_HOST_INT_EN_CLR_REG(base) (*pSAR_HOST_INT_EN_CLR_REG(base))
++#define pSAR_PDSP_INT_EN_SET_REG(base) ((volatile bit32u *)(base+0x0018))
++#define SAR_PDSP_INT_EN_SET_REG(base) (*pSAR_PDSP_INT_EN_SET_REG(base))
++#define pSAR_PDSP_INT_EN_CLR_REG(base) ((volatile bit32u *)(base+0x001C))
++#define SAR_PDSP_INT_EN_CLR_REG(base) (*pSAR_PDSP_INT_EN_CLR_REG(base))
++
++/* PDSP OAM General Purpose Registers */
++#define pSAR_PDSP_HOST_OAM_CONFIG_REG(base) ((volatile bit32u *)(base+0x0020))
++#define SAR_PDSP_HOST_OAM_CONFIG_REG(base) (*pSAR_PDSP_HOST_OAM_CONFIG_REG(base))
++#define pSAR_PDSP_OAM_CORR_REG(base) ((volatile bit32u *)(base+0x0024))
++#define SAR_PDSP_OAM_CORR_REG(base) (*pSAR_PDSP_OAM_CORR_REG(base))
++#define pSAR_PDSP_OAM_LB_RESULT_REG(base) ((volatile bit32u *)(base+0x0028))
++#define SAR_PDSP_OAM_LB_RESULT_REG(base) (*pSAR_PDSP_OAM_LB_RESULT_REG(base))
++#define pSAR_PDSP_OAM_F5_LB_COUNT_REG(base) ((volatile bit32u *)(base+0x002c)) /* +GSG 030416 */
++#define SAR_PDSP_OAM_F5_LB_COUNT_REG(base) (*pSAR_PDSP_OAM_F5_LB_COUNT_REG(base)) /* +GSG 030416 */
++#define pSAR_PDSP_OAM_F4_LB_COUNT_REG(base) ((volatile bit32u *)(base+0x0030)) /* +GSG 030416 */
++#define SAR_PDSP_OAM_F4_LB_COUNT_REG(base) (*pSAR_PDSP_OAM_F4_LB_COUNT_REG(base)) /* +GSG 030416 */
++#define pSAR_PDSP_FWD_UNK_VC_REG(base) ((volatile bit32u *)(base+0x0034)) /* +GSG 030701 */
++#define SAR_PDSP_FWD_UNK_VC_REG(base) (*pSAR_PDSP_FWD_UNK_VC_REG(base)) /* +GSG 030701 */
++
++
++/* Rx Lookup Table Registers */
++#define pRX_LUT_GLOBAL_CFG_REG(base) ((volatile bit32u *)(base+0x0080))
++#define RX_LUT_GLOBAL_CFG_REG(base) (*pRX_LUT_GLOBAL_CFG_REG(base))
++#define pRX_LUT_CH_SETUP_REQ_REG(base) ((volatile bit32u *)(base+0x0090))
++#define RX_LUT_CH_SETUP_REQ_REG(base) (*pRX_LUT_CH_SETUP_REQ_REG(base))
++#define pRX_LUT_CH_SETUP_REQ_VC_REG(base) ((volatile bit32u *)(base+0x0094))
++#define RX_LUT_CH_SETUP_REQ_VC_REG(base) (*pRX_LUT_CH_SETUP_REQ_VC_REG(base))
++#define pRX_LUT_CH_TEARDOWN_REQ_REG(base) ((volatile bit32u *)(base+0x009C))
++#define RX_LUT_CH_TEARDOWN_REQ_REG(base) (*pRX_LUT_CH_TEARDOWN_REQ_REG(base))
++
++/* Tx Scheduler Registers */
++#define pTX_CH_MAPPING_REG(base) ((volatile bit32u *)(base+0x0170))
++#define TX_CH_MAPPING_REG(base) (*pTX_CH_MAPPING_REG(base))
++
++/* Tx CPPI DMA Controller Registers */
++#define pTX_CPPI_CTL_REG(base) ((volatile bit32u *)(base+0x0700))
++#define TX_CPPI_CTL_REG(base) (*pTX_CPPI_CTL_REG(base))
++#define pTX_CPPI_TEARDOWN_REG(base) ((volatile bit32u *)(base+0x0704))
++#define TX_CPPI_TEARDOWN_REG(base) (*pTX_CPPI_TEARDOWN_REG(base))
++
++/* EOI Interrupt Additions */
++#define pSAR_EOI(base) ((volatile bit32u *)(base+0x0708))
++#define SAR_EOI(base) (*pSAR_EOI(base))
++#define pSAR_INTR_VECTOR(base) ((volatile bit32u *)(base+0x070c))
++#define SAR_INTR_VECTOR(base) (*pSAR_INTR_VECTOR(base))
++#define pSAR_TX_MASKED_STATUS(base) ((volatile bit32u *)(base+0x0710))
++#define SAR_TX_MASKED_STATUS(base) (*pSAR_TX_MASKED_STATUS(base))
++#define pSAR_TX_RAW_STATUS(base) ((volatile bit32u *)(base+0x0714))
++#define SAR_TX_RAW_STATUS(base) (*pSAR_TX_RAW_STATUS(base))
++#define pSAR_TX_MASK_SET(base) ((volatile bit32u *)(base+0x0718))
++#define SAR_TX_MASK_SET(base) (*pSAR_TX_MASK_SET(base))
++#define pSAR_TX_MASK_CLR(base) ((volatile bit32u *)(base+0x071c))
++#define SAR_TX_MASK_CLR(base) (*pSAR_TX_MASK_CLR(base))
++
++/* Rx CPPI DMA Controller Registers */
++#define pRX_CPPI_CTL_REG(base) ((volatile bit32u *)(base+0x0780))
++#define RX_CPPI_CTL_REG(base) (*pRX_CPPI_CTL_REG(base))
++#define pSAR_RX_MASKED_STATUS(base) ((volatile bit32u *)(base+0x0790))
++#define SAR_RX_MASKED_STATUS(base) (*pSAR_RX_MASKED_STATUS(base))
++#define pSAR_RX_RAW_STATUS(base) ((volatile bit32u *)(base+0x0794))
++#define SAR_RX_RAW_STATUS(base) (*pSAR_RX_RAW_STATUS(base))
++#define pSAR_RX_MASK_SET(base) ((volatile bit32u *)(base+0x0798))
++#define SAR_RX_MASK_SET(base) (*pSAR_RX_MASK_SET(base))
++#define pSAR_RX_MASK_CLR(base) ((volatile bit32u *)(base+0x079c))
++#define SAR_RX_MASK_CLR(base) (*pSAR_RX_MASK_CLR(base))
++
++/* PDSP Control/Status Registers */
++#define pPDSP_CTRL_REG(base) ((volatile bit32u *)(base+0x4000))
++#define PDSP_CTRL_REG(base) (*pPDSP_CTRL_REG(base))
++
++/* PDSP Instruction RAM */
++#define pPDSP_IRAM(base) ((volatile bit32u *)(base+0x4020))
++#define PDSP_IRAM(base) (*pPDSP_IRAM(base))
++
++/*
++ * Channel 0 State/Scratchpad RAM Block
++ *
++ * The following registers (Tx DMA State, Rx DMA State, CPPI Completion PTR,
++ * and PDSP Data) have been given the correct address for channel 0. To
++ * reach the registers for channel X, add (X * 0x100) to the pointer address.
++ *
++ */
++
++#define PDSP_STATE_RAM_SIZE 1024
++
++/* Tx DMA State RAM */
++#define pTX_DMA_STATE_WORD_0(base) ((volatile bit32u *)(base+0x8000))
++#define TX_DMA_STATE_WORD_0(base) (*pTX_DMA_STATE_WORD_0(base))
++#define pTX_DMA_STATE_WORD_1(base) ((volatile bit32u *)(base+0x8004))
++#define TX_DMA_STATE_WORD_1(base) (*pTX_DMA_STATE_WORD_1(base))
++#define pTX_DMA_STATE_WORD_2(base) ((volatile bit32u *)(base+0x8008))
++#define TX_DMA_STATE_WORD_2(base) (*pTX_DMA_STATE_WORD_2(base))
++#define pTX_DMA_STATE_WORD_3(base) ((volatile bit32u *)(base+0x800C))
++#define TX_DMA_STATE_WORD_3(base) (*pTX_DMA_STATE_WORD_3(base))
++#define pTX_DMA_STATE_WORD_4(base) ((volatile bit32u *)(base+0x8010))
++#define TX_DMA_STATE_WORD_4(base) (*pTX_DMA_STATE_WORD_4(base))
++#define pTX_DMA_STATE_WORD_5(base) ((volatile bit32u *)(base+0x8014))
++#define TX_DMA_STATE_WORD_5(base) (*pTX_DMA_STATE_WORD_5(base))
++#define pTX_DMA_STATE_WORD_6(base) ((volatile bit32u *)(base+0x8018))
++#define TX_DMA_STATE_WORD_6(base) (*pTX_DMA_STATE_WORD_6(base))
++#define pTX_DMA_STATE_WORD_7(base) ((volatile bit32u *)(base+0x801C))
++#define TX_DMA_STATE_WORD_7(base) (*pTX_DMA_STATE_WORD_7(base))
++#define pTX_DMA_STATE_WORD_8(base) ((volatile bit32u *)(base+0x8020))
++#define TX_DMA_STATE_WORD_8(base) (*pTX_DMA_STATE_WORD_8(base))
++
++/* Rx DMA State RAM */
++#define pRX_DMA_STATE_WORD_0(base) ((volatile bit32u *)(base+0x8024))
++#define RX_DMA_STATE_WORD_0(base) (*pRX_DMA_STATE_WORD_0(base))
++#define pRX_DMA_STATE_WORD_1(base) ((volatile bit32u *)(base+0x8028))
++#define RX_DMA_STATE_WORD_1(base) (*pRX_DMA_STATE_WORD_1(base))
++#define pRX_DMA_STATE_WORD_2(base) ((volatile bit32u *)(base+0x802C))
++#define RX_DMA_STATE_WORD_2(base) (*pRX_DMA_STATE_WORD_2(base))
++#define pRX_DMA_STATE_WORD_3(base) ((volatile bit32u *)(base+0x8030))
++#define RX_DMA_STATE_WORD_3(base) (*pRX_DMA_STATE_WORD_3(base))
++#define pRX_DMA_STATE_WORD_4(base) ((volatile bit32u *)(base+0x8034))
++#define RX_DMA_STATE_WORD_4(base) (*pRX_DMA_STATE_WORD_4(base))
++#define pRX_DMA_STATE_WORD_5(base) ((volatile bit32u *)(base+0x8038))
++#define RX_DMA_STATE_WORD_5(base) (*pRX_DMA_STATE_WORD_5(base))
++#define pRX_DMA_STATE_WORD_6(base) ((volatile bit32u *)(base+0x803C))
++#define RX_DMA_STATE_WORD_6(base) (*pRX_DMA_STATE_WORD_6(base))
++
++/* Tx CPPI Completion Pointers */
++#define pTXH_CPPI_COMP_PTR(base) ((volatile bit32u *)(base+0x8040))
++#define TXH_CPPI_COMP_PTR(base) (*pTXH_CPPI_COMP_PTR(base))
++#define pTXL_CPPI_COMP_PTR(base) ((volatile bit32u *)(base+0x8044))
++#define TXL_CPPI_COMP_PTR(base) (*pTXL_CPPI_COMP_PTR(base))
++
++/* Rx CPPI Completion Pointer */
++#define pRX_CPPI_COMP_PTR(base) ((volatile bit32u *)(base+0x8048))
++#define RX_CPPI_COMP_PTR(base) (*pRX_CPPI_COMP_PTR(base))
++
++/* Tx PDSP Defines */
++#define NUM_PDSP_AAL5_STATE_WORDS 24
++#define NUM_PDSP_AAL2_STATE_WORDS 20
++
++/* PDSP State RAM Block 0 */
++#define pPDSP_BLOCK_0(base) ((volatile bit32u *)(base+0x8050))
++#define PDSP_BLOCK_0(base) (*pPDSP_BLOCK_0(base))
++
++/* AAL5 Tx PDSP State RAM */
++#define pPDSP_AAL5_TX_STATE_WORD_0(base) ((volatile bit32u *)(base+0x8050))
++#define PDSP_AAL5_TX_STATE_WORD_0(base) (*pPDSP_AAL5_TX_STATE_WORD_0(base))
++
++/* AAL5 Rx PDSP State RAM */
++#define pPDSP_AAL5_RX_STATE_WORD_0(base) ((volatile bit32u *)(base+0x8070))
++#define PDSP_AAL5_RX_STATE_WORD_0(base) (*pPDSP_AAL5_RX_STATE_WORD_0(base))
++
++/* AAL5 Tx VP PDSP State RAM */
++#define pPDSP_AAL5_TX_VP_STATE_WORD_0(base) ((volatile bit32u *)(base+0x8090))
++#define PDSP_AAL5_TX_VP_STATE_WORD_0(base) (*pPDSP_AAL5_TX_VP_STATE_WORD_0(base))
++
++/* AAL5 Rx VP PDSP State RAM */
++#define pPDSP_AAL5_RX_VP_STATE_WORD_0(base) ((volatile bit32u *)(base+0x80A0))
++#define PDSP_AAL5_RX_VP_STATE_WORD_0(base) (*pPDSP_AAL5_RX_VP_STATE_WORD_0(base))
++
++/* AAL2 Tx PDSP State RAM */
++#define pPDSP_AAL2_TX_STATE_WORD_0(base) ((volatile bit32u *)(base+0x80B0))
++#define PDSP_AAL2_TX_STATE_WORD_0(base) (*pPDSP_AAL2_TX_STATE_WORD_0(base))
++
++/* AAL2 Rx PDSP State RAM */
++#define pPDSP_AAL2_RX_STATE_WORD_0(base) ((volatile bit32u *)(base+0x80D0))
++#define PDSP_AAL2_RX_STATE_WORD_0(base) (*pPDSP_AAL2_RX_STATE_WORD_0(base))
++
++/* AAL2 Tx VP PDSP State RAM */
++#define pPDSP_AAL2_TX_VP_STATE_WORD_0(base) ((volatile bit32u *)(base+0x80E0))
++#define PDSP_AAL2_TX_VP_STATE_WORD_0(base) (*pPDSP_AAL2_TX_VP_STATE_WORD_0(base))
++
++/* AAL2 Rx VP PDSP State RAM */
++#define pPDSP_AAL2_RX_VP_STATE_WORD_0(base) ((volatile bit32u *)(base+0x80F0))
++#define PDSP_AAL2_RX_VP_STATE_WORD_0(base) (*pPDSP_AAL2_RX_VP_STATE_WORD_0(base))
++
++/* PDSP OAM Configuration Block */
++#define pOAM_CONFIG_BLOCK_WORD_0(base) ((volatile bit32u *)(base+0x83C0))
++#define OAM_CONFIG_BLOCK_WORD_0(base) (*pOAM_CONFIG_BLOCK_WORD_0(base))
++
++/* PDSP OAM Padding Block */
++#define pOAM_PADDING_BLOCK_WORD_0(base) ((volatile bit32u *)(base+0x84C0))
++#define OAM_PADDING_BLOCK_WORD_0(base) (*pOAM_PADDING_BLOCK_WORD_0(base))
++
++#define NUM_OAM_RATES 11
++
++/* PDSP OAM Timer State RAM */
++#define pOAM_TIMER_STATE_WORD_0(base) ((volatile bit32u *)(base+0x85B0))
++#define OAM_TIMER_STATE_WORD_0(base) (*pOAM_TIMER_STATE_WORD_0(base))
++
++
++/* END OF FILE */
++
++#endif _INC_SAR_REG
+diff -urN linux.old/drivers/atm/sangam_atm/cpswhal_cpaal5.h linux.dev/drivers/atm/sangam_atm/cpswhal_cpaal5.h
+--- linux.old/drivers/atm/sangam_atm/cpswhal_cpaal5.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/cpswhal_cpaal5.h 2005-08-23 04:46:50.088845064 +0200
+@@ -0,0 +1,629 @@
++/************************************************************************
++ * TNETDxxxx Software Support
++ * Copyright (c) 2002 Texas Instruments Incorporated. All Rights Reserved.
++ *
++ * FILE: cphal.h
++ *
++ * DESCRIPTION:
++ * User include file, contains data definitions shared between the CPHAL
++ * and the upper-layer software.
++ *
++ * HISTORY:
++ * Date Modifier Ver Notes
++ * 28Feb02 Greg 1.00 Original
++ * 06Mar02 Greg 1.01 Documentation enhanced
++ * 18Jul02 Greg 1.02 Many updates (OAM additions, general reorg)
++ * 22Nov02 Mick RC2 Additions from Denis' input on Control
++ *
++ * author Greg Guyotte
++ * version 1.02
++ * date 18-Jul-2002
++ *****************************************************************************/
++#ifndef _INC_CPHAL_H
++#define _INC_CPHAL_H
++
++#ifdef _CPHAL_CPMAC
++#include "ec_errors_cpmac.h"
++#endif
++
++#ifdef _CPHAL_AAL5
++#include "ec_errors_cpaal5.h"
++#endif
++
++#ifdef _CPHAL_CPSAR
++#include "ec_errors_cpsar.h"
++#endif
++
++#ifdef _CPHAL_AAL2
++#include "ec_errors_cpaal2.h"
++#endif
++
++#ifndef __ADAM2
++typedef char bit8;
++typedef short bit16;
++typedef int bit32;
++
++typedef unsigned char bit8u;
++typedef unsigned short bit16u;
++typedef unsigned int bit32u;
++
++/*
++typedef char INT8;
++typedef short INT16;
++typedef int INT32;
++typedef unsigned char UINT8;
++typedef unsigned short UINT16;
++typedef unsigned int UINT32;
++*/
++/*typedef unsigned int size_t;*/
++#endif
++
++#ifdef _CPHAL
++
++#ifndef TRUE
++#define TRUE (1==1)
++#endif
++
++#ifndef FALSE
++#define FALSE (1==2)
++#endif
++
++#ifndef NULL
++#define NULL 0
++#endif
++
++#endif
++
++#define VirtToPhys(a) (((int)a)&~0xe0000000)
++#define VirtToVirtNoCache(a) ((void*)((VirtToPhys(a))|0xa0000000))
++#define VirtToVirtCache(a) ((void*)((VirtToPhys(a))|0x80000000))
++#define PhysToVirtNoCache(a) ((void*)(((int)a)|0xa0000000))
++#define PhysToVirtCache(a) ((void*)(((int)a)|0x80000000))
++/*
++#define DataCacheHitInvalidate(a) {__asm__(" cache 17, (%0)" : : "r" (a));}
++#define DataCacheHitWriteback(a) {__asm__(" cache 25, (%0)" : : "r" (a));}
++*/
++
++#define PARTIAL 1 /**< Used in @c Close() and @c ChannelTeardown() */
++#define FULL 2 /**< Used in @c Close() and @c ChannelTeardown() */
++
++/* Channel Teardown Defines */
++#define RX_TEARDOWN 2
++#define TX_TEARDOWN 1
++#define BLOCKING_TEARDOWN 8
++#define FULL_TEARDOWN 4
++#define PARTIAL_TEARDOWN 0
++
++#define MAX_DIR 2
++#define DIRECTION_TX 0
++#define DIRECTION_RX 1
++#define TX_CH 0
++#define RX_CH 1
++#define HAL_ERROR_DEVICE_NOT_FOUND 1
++#define HAL_ERROR_FAILED_MALLOC 2
++#define HAL_ERROR_OSFUNC_SIZE 3
++#define HAL_DEFAULT 0xFFFFFFFF
++#define VALID(val) (val!=HAL_DEFAULT)
++
++/*
++ERROR REPORTING
++
++HAL Module Codes. Each HAL module reporting an error code
++should OR the error code with the respective Module error code
++from the list below.
++*/
++#define EC_AAL5 EC_HAL|EC_DEV_AAL5
++#define EC_AAL2 EC_HAL|EC_DEV_AAL2
++#define EC_CPSAR EC_HAL|EC_DEV_CPSAR
++#define EC_CPMAC EC_HAL|EC_DEV_CPMAC
++#define EC_VDMA EC_HAL|EC_DEV_VDMA
++#define EC_VLYNQ EC_HAL|EC_DEV_VLYNQ
++#define EC_CPPI EC_HAL|EC_DEV_CPPI
++
++/*
++HAL Function Codes. Each HAL module reporting an error code
++should OR the error code with one of the function codes from
++the list below.
++*/
++#define EC_FUNC_HAL_INIT EC_FUNC(1)
++#define EC_FUNC_CHSETUP EC_FUNC(2)
++#define EC_FUNC_CHTEARDOWN EC_FUNC(3)
++#define EC_FUNC_RXRETURN EC_FUNC(4)
++#define EC_FUNC_SEND EC_FUNC(5)
++#define EC_FUNC_RXINT EC_FUNC(6)
++#define EC_FUNC_TXINT EC_FUNC(7)
++#define EC_FUNC_AAL2_VDMA EC_FUNC(8)
++#define EC_FUNC_OPTIONS EC_FUNC(9)
++#define EC_FUNC_PROBE EC_FUNC(10)
++#define EC_FUNC_OPEN EC_FUNC(11)
++#define EC_FUNC_CONTROL EC_FUNC(12)
++#define EC_FUNC_DEVICE_INT EC_FUNC(13)
++#define EC_FUNC_STATUS EC_FUNC(14)
++#define EC_FUNC_TICK EC_FUNC(15)
++#define EC_FUNC_CLOSE EC_FUNC(16)
++#define EC_FUNC_SHUTDOWN EC_FUNC(17)
++#define EC_FUNC_DEVICE_INT_ALT EC_FUNC(18) /* +GSG 030306 */
++
++/*
++HAL Error Codes. The list below defines every type of error
++used in all HAL modules. DO NOT CHANGE THESE VALUES! Add new
++values in integer order to the bottom of the list.
++*/
++#define EC_VAL_PDSP_LOAD_FAIL EC_ERR(0x01)|EC_CRITICAL
++#define EC_VAL_FIRMWARE_TOO_LARGE EC_ERR(0x02)|EC_CRITICAL
++#define EC_VAL_DEVICE_NOT_FOUND EC_ERR(0x03)|EC_CRITICAL
++#define EC_VAL_BASE_ADDR_NOT_FOUND EC_ERR(0x04)|EC_CRITICAL
++#define EC_VAL_RESET_BIT_NOT_FOUND EC_ERR(0x05)|EC_CRITICAL
++#define EC_VAL_CH_INFO_NOT_FOUND EC_ERR(0x06)
++#define EC_VAL_RX_STATE_RAM_NOT_CLEARED EC_ERR(0x07)|EC_CRITICAL
++#define EC_VAL_TX_STATE_RAM_NOT_CLEARED EC_ERR(0x08)|EC_CRITICAL
++#define EC_VAL_MALLOC_DEV_FAILED EC_ERR(0x09)
++#define EC_VAL_OS_VERSION_NOT_SUPPORTED EC_ERR(0x0A)|EC_CRITICAL
++#define EC_VAL_CPSAR_VERSION_NOT_SUPPORTED EC_ERR(0x0B)|EC_CRITICAL
++#define EC_VAL_NULL_CPSAR_DEV EC_ERR(0x0C)|EC_CRITICAL
++
++#define EC_VAL_LUT_NOT_READY EC_ERR(0x0D)
++#define EC_VAL_INVALID_CH EC_ERR(0x0E)
++#define EC_VAL_NULL_CH_STRUCT EC_ERR(0x0F)
++#define EC_VAL_RX_TEARDOWN_ALREADY_PEND EC_ERR(0x10)
++#define EC_VAL_TX_TEARDOWN_ALREADY_PEND EC_ERR(0x11)
++#define EC_VAL_RX_CH_ALREADY_TORNDOWN EC_ERR(0x12)
++#define EC_VAL_TX_CH_ALREADY_TORNDOWN EC_ERR(0x13)
++#define EC_VAL_TX_TEARDOWN_TIMEOUT EC_ERR(0x14)
++#define EC_VAL_RX_TEARDOWN_TIMEOUT EC_ERR(0x15)
++#define EC_VAL_CH_ALREADY_TORNDOWN EC_ERR(0x16)
++#define EC_VAL_VC_SETUP_NOT_READY EC_ERR(0x17)
++#define EC_VAL_VC_TEARDOWN_NOT_READY EC_ERR(0x18)
++#define EC_VAL_INVALID_VC EC_ERR(0x19)
++#define EC_VAL_INVALID_LC EC_ERR(0x20)
++#define EC_VAL_INVALID_VDMA_CH EC_ERR(0x21)
++#define EC_VAL_INVALID_CID EC_ERR(0x22)
++#define EC_VAL_INVALID_UUI EC_ERR(0x23)
++#define EC_VAL_INVALID_UUI_DISCARD EC_ERR(0x24)
++#define EC_VAL_CH_ALREADY_OPEN EC_ERR(0x25)
++
++#define EC_VAL_RCB_MALLOC_FAILED EC_ERR(0x26)
++#define EC_VAL_RX_BUFFER_MALLOC_FAILED EC_ERR(0x27)
++#define EC_VAL_OUT_OF_TCBS EC_ERR(0x28)
++#define EC_VAL_NO_TCBS EC_ERR(0x29)
++#define EC_VAL_NULL_RCB EC_ERR(0x30)|EC_CRITICAL
++#define EC_VAL_SOP_ERROR EC_ERR(0x31)|EC_CRITICAL
++#define EC_VAL_EOP_ERROR EC_ERR(0x32)|EC_CRITICAL
++#define EC_VAL_NULL_TCB EC_ERR(0x33)|EC_CRITICAL
++#define EC_VAL_CORRUPT_RCB_CHAIN EC_ERR(0x34)|EC_CRITICAL
++#define EC_VAL_TCB_MALLOC_FAILED EC_ERR(0x35)
++
++#define EC_VAL_DISABLE_POLLING_FAILED EC_ERR(0x36)
++#define EC_VAL_KEY_NOT_FOUND EC_ERR(0x37)
++#define EC_VAL_MALLOC_FAILED EC_ERR(0x38)
++#define EC_VAL_RESET_BASE_NOT_FOUND EC_ERR(0x39)|EC_CRITICAL
++#define EC_VAL_INVALID_STATE EC_ERR(0x40)
++#define EC_VAL_NO_TXH_WORK_TO_DO EC_ERR(0x41)
++#define EC_VAL_NO_TXL_WORK_TO_DO EC_ERR(0x42)
++#define EC_VAL_NO_RX_WORK_TO_DO EC_ERR(0x43)
++#define EC_VAL_NOT_LINKED EC_ERR(0x44)
++#define EC_VAL_INTERRUPT_NOT_FOUND EC_ERR(0x45)
++#define EC_VAL_OFFSET_NOT_FOUND EC_ERR(0x46)
++#define EC_VAL_MODULE_ALREADY_CLOSED EC_ERR(0x47)
++#define EC_VAL_MODULE_ALREADY_SHUTDOWN EC_ERR(0x48)
++#define EC_VAL_ACTION_NOT_FOUND EC_ERR(0x49)
++#define EC_VAL_RX_CH_ALREADY_SETUP EC_ERR(0x50)
++#define EC_VAL_TX_CH_ALREADY_SETUP EC_ERR(0x51)
++#define EC_VAL_RX_CH_ALREADY_OPEN EC_ERR(0x52)
++#define EC_VAL_TX_CH_ALREADY_OPEN EC_ERR(0x53)
++#define EC_VAL_CH_ALREADY_SETUP EC_ERR(0x54)
++#define EC_VAL_RCB_NEEDS_BUFFER EC_ERR(0x55) /* +GSG 030410 */
++#define EC_VAL_RCB_DROPPED EC_ERR(0x56) /* +GSG 030410 */
++#define EC_VAL_INVALID_VALUE EC_ERR(0x57)
++
++/**
++@defgroup shared_data Shared Data Structures
++
++The data structures documented here are shared by all modules.
++*/
++
++/**
++ * @ingroup shared_data
++ * This is the fragment list structure. Each fragment list entry contains a
++ * length and a data buffer.
++ */
++typedef struct
++ {
++ bit32u len; /**< Length of the fragment in bytes (lower 16 bits are valid). For SOP, upper 16 bits is the buffer offset. */
++ void *data; /**< Pointer to fragment data. */
++ void *OsInfo; /**< Pointer to OS defined data. */
++ }FRAGLIST;
++
++#if defined (_CPHAL_CPMAC)
++#define CB_PASSCRC_BIT (1<<26)
++
++/* CPMAC CPHAL STATUS */
++#define CPMAC_STATUS_LINK (1 << 0)
++#define CPMAC_STATUS_LINK_DUPLEX (1 << 1) /* 0 - HD, 1 - FD */
++#define CPMAC_STATUS_LINK_SPEED (1 << 2) /* 0 - 10, 1 - 100 */
++
++/* ADAPTER CHECK Codes */
++
++#define CPMAC_STATUS_ADAPTER_CHECK (1 << 7)
++#define CPMAC_STATUS_HOST_ERR_DIRECTION (1 << 8)
++#define CPMAC_STATUS_HOST_ERR_CODE (0xF << 9)
++#define CPMAC_STATUS_HOST_ERR_CH (0x7 << 13)
++
++#define _CPMDIO_DISABLE (1 << 0)
++#define _CPMDIO_HD (1 << 1)
++#define _CPMDIO_FD (1 << 2)
++#define _CPMDIO_10 (1 << 3)
++#define _CPMDIO_100 (1 << 4)
++#define _CPMDIO_NEG_OFF (1 << 5)
++#define _CPMDIO_LOOPBK (1 << 16)
++#define _CPMDIO_NOPHY (1 << 20)
++#endif
++
++/**
++ * @ingroup shared_data
++ * Channel specific configuration information. This structure should be
++ * populated by upper-layer software prior to calling @c ChannelSetup(). Any
++ * configuration item that can be changed on a per channel basis should
++ * be represented here. Each module may define this structure with additional
++ * module-specific members.
++ */
++typedef struct
++ {
++ int Channel; /**< Channel number. */
++ int Direction; /**< DIRECTION_RX(1) or DIRECTION_TX(0). */
++ OS_SETUP *OsSetup; /**< OS defined information associated with this channel. */
++
++#if defined(_CPHAL_AAL5) || defined (_CPHAL_CPSAR) || defined (_CPHAL_CPMAC)
++ int RxBufSize; /**< Size (in bytes) for each Rx buffer.*/
++ int RxBufferOffset; /**< Number of bytes to offset rx data from start of buffer (must be less than buffer size). */
++ int RxNumBuffers; /**< The number of Rx buffer descriptors to allocate for Ch. */
++ int RxServiceMax; /**< Maximum number of packets to service at one time. */
++
++ int TxNumBuffers; /**< The number of Tx buffer descriptors to allocate for Ch. */
++ int TxNumQueues; /**< Number of Tx queues for this channel (1-2). Choosing 2 enables a low priority SAR queue. */
++ int TxServiceMax; /**< Maximum number of packets to service at one time. */
++#endif
++
++#if defined(_CPHAL_AAL5) || defined(_CPHAL_CPSAR)
++ int CpcsUU; /**< The 2-byte CPCS UU and CPI information. */
++ int Gfc; /**< Generic Flow Control. */
++ int Clp; /**< Cell Loss Priority. */
++ int Pti; /**< Payload Type Indication. */
++#endif
++
++#if defined(_CPHAL_AAL2) || defined(_CPHAL_AAL5) || defined(_CPHAL_CPSAR)
++ int DaMask; /**< Specifies whether credit issuance is paused when Tx data not available. */
++ int Priority; /**< Priority bin this channel will be scheduled within. */
++ int PktType; /**< 0=AAL5,1=Null AAL,2=OAM,3=Transparent,4=AAL2. */
++ int Vci; /**< Virtual Channel Identifier. */
++ int Vpi; /**< Virtual Path Identifier. */
++ int FwdUnkVc; /**< Enables forwarding of unknown VCI/VPI cells to host. 1=enable, 0=disable. */
++
++ /* Tx VC State */
++ int TxVc_CellRate; /**< Tx rate, set as clock ticks between transmissions (SCR for VBR, CBR for CBR). */
++ int TxVc_QosType; /**< 0=CBR,1=VBR,2=UBR,3=UBRmcr. */
++ int TxVc_Mbs; /**< Min Burst Size in cells.*/
++ int TxVc_Pcr; /**< Peak Cell Rate for VBR in clock ticks between transmissions. */
++
++ bit32 TxVc_AtmHeader; /**< ATM Header placed on firmware gen'd OAM cells for this Tx Ch (must be big endian with 0 PTI). */
++ int TxVc_OamTc; /**< TC Path to transmit OAM cells for TX connection (0,1). */
++ int TxVc_VpOffset; /**< Offset to the OAM VP state table. */
++ /* Rx VC State */
++ int RxVc_OamCh; /**< Ch to terminate rx'd OAM cells to be forwarded to the host. */
++ int RxVc_OamToHost; /**< 0=do not pass, 1=pass. */
++ bit32 RxVc_AtmHeader; /**< ATM Header placed on firmware gen'd OAM cells for this Rx conn (must be big endian with 0 PTI). */
++ int RxVc_OamTc; /**< TC Path to transmit OAM cells for RX connection (0,1). */
++ int RxVc_VpOffset; /**< Offset to the OAM VP state table. */
++ /* Tx VP State */
++ int TxVp_OamTc; /**< TC Path to transmit OAM cells for TX VP connection (0,1). */
++ bit32 TxVp_AtmHeader; /**< ATM Header placed on firmware gen'd VP OAM cells for this Tx VP conn (must be big endian with 0 VCI). */
++ /* Rx VP State */
++ int RxVp_OamCh; /**< Ch to terminate rx'd OAM cells to be forwarded to the host. */
++ int RxVp_OamToHost; /**< 0=do not pass, 1=pass. */
++ bit32 RxVp_AtmHeader; /**< ATM Header placed on firmware gen'd OAM cells for this Rx VP conn (must be big endian with 0 VCI). */
++ int RxVp_OamTc; /**< TC Path to transmit OAM cells for RX VP connection (0,1). */
++ int RxVp_OamVcList; /**< Indicates all VC channels associated with this VP channel (one-hot encoded). */
++#endif
++
++
++#ifdef _CPHAL_VDMAVT
++ bit32u RemFifoAddr; /* Mirror mode only. */
++ bit32u FifoAddr;
++ bit32 PollInt;
++ bit32 FifoSize;
++ int Ready;
++#endif
++
++ }CHANNEL_INFO;
++
++/*
++ * This structure contains each statistic value gathered by the CPHAL.
++ * Applications may access statistics data by using the @c StatsGet() routine.
++ */
++/* STATS */
++#if defined(_CPHAL_AAL2) || defined(_CPHAL_AAL5) || defined(_CPHAL_CPSAR)
++typedef struct
++ {
++ bit32u CrcErrors[16];
++ bit32u LenErrors[16];
++ bit32u DmaLenErrors[16];
++ bit32u AbortErrors[16];
++ bit32u StarvErrors[16];
++ bit32u TxMisQCnt[16][2];
++ bit32u RxMisQCnt[16];
++ bit32u RxEOQCnt[16];
++ bit32u TxEOQCnt[16][2];
++ bit32u RxPacketsServiced[16];
++ bit32u TxPacketsServiced[16][2];
++ bit32u RxMaxServiced;
++ bit32u TxMaxServiced[16][2];
++ bit32u RxTotal;
++ bit32u TxTotal;
++ } STAT_INFO;
++#endif
++
++/*
++ * VDMA Channel specific configuration information
++ */
++#ifdef _CPHAL_AAL2
++typedef struct
++ {
++ int Ch; /**< Channel Number */
++ int RemoteEndian; /**< Endianness of remote VDMA-VT device */
++ int CpsSwap; /**< When 0, octet 0 in CPS pkt located in LS byte of 16-bit word sent to rem VDMA device. When 1, in MS byte. */
++ }VdmaChInfo;
++#endif
++
++#ifndef _CPHAL
++ typedef void HAL_DEVICE;
++ typedef void HAL_PRIVATE;
++ typedef void HAL_RCB;
++ typedef void HAL_RECEIVEINFO;
++#endif
++
++/**
++ * @ingroup shared_data
++ * The HAL_FUNCTIONS struct defines the function pointers used by upper layer
++ * software. The upper layer software receives these pointers through the
++ * call to xxxInitModule().
++ */
++typedef struct
++ {
++ int (*ChannelSetup) (HAL_DEVICE *HalDev, CHANNEL_INFO *Channel, OS_SETUP *OsSetup);
++ int (*ChannelTeardown) (HAL_DEVICE *HalDev, int Channel, int Mode);
++ int (*Close) (HAL_DEVICE *HalDev, int Mode);
++ int (*Control) (HAL_DEVICE *HalDev, const char *Key, const char *Action, void *Value);
++ int (*Init) (HAL_DEVICE *HalDev);
++ int (*Open) (HAL_DEVICE *HalDev);
++ int (*PacketProcessEnd) (HAL_DEVICE *HalDev);
++ int (*Probe) (HAL_DEVICE *HalDev);
++ int (*RxReturn) (HAL_RECEIVEINFO *HalReceiveInfo, int StripFlag);
++ int (*Send) (HAL_DEVICE *HalDev, FRAGLIST *FragList, int FragCount, int PacketSize, OS_SENDINFO *OsSendInfo, bit32u Mode);
++ int (*Shutdown) (HAL_DEVICE *HalDev);
++ int (*Tick) (HAL_DEVICE *HalDev);
++
++#ifdef _CPHAL_AAL5
++ int (*Kick) (HAL_DEVICE *HalDev, int Queue);
++ void (*OamFuncConfig) (HAL_DEVICE *HalDev, unsigned int OamConfig);
++ void (*OamLoopbackConfig) (HAL_DEVICE *HalDev, unsigned int OamConfig, unsigned int *LLID, unsigned int CorrelationTag);
++ volatile bit32u* (*RegAccess)(HAL_DEVICE *HalDev, bit32u RegOffset);
++ STAT_INFO* (*StatsGetOld)(HAL_DEVICE *HalDev);
++#endif
++ } HAL_FUNCTIONS;
++
++/**
++ * @ingroup shared_data
++ * The OS_FUNCTIONS struct defines the function pointers for all upper layer
++ * functions accessible to the CPHAL. The upper layer software is responsible
++ * for providing the correct OS-specific implementations for the following
++ * functions. It is populated by calling InitModule() (done by the CPHAL in
++ * xxxInitModule().
++ */
++typedef struct
++ {
++ int (*Control)(OS_DEVICE *OsDev, const char *Key, const char *Action, void *Value);
++ void (*CriticalOn)(void);
++ void (*CriticalOff)(void);
++ void (*DataCacheHitInvalidate)(void *MemPtr, int Size);
++ void (*DataCacheHitWriteback)(void *MemPtr, int Size);
++ int (*DeviceFindInfo)(int Inst, const char *DeviceName, void *DeviceInfo);
++ int (*DeviceFindParmUint)(void *DeviceInfo, const char *Parm, bit32u *Value);
++ int (*DeviceFindParmValue)(void *DeviceInfo, const char *Parm, void *Value);
++ void (*Free)(void *MemPtr);
++ void (*FreeRxBuffer)(OS_RECEIVEINFO *OsReceiveInfo, void *MemPtr);
++ void (*FreeDev)(void *MemPtr);
++ void (*FreeDmaXfer)(void *MemPtr);
++ void (*IsrRegister)(OS_DEVICE *OsDev, int (*halISR)(HAL_DEVICE*, int*), int InterruptBit);
++ void (*IsrUnRegister)(OS_DEVICE *OsDev, int InterruptBit);
++ void* (*Malloc)(bit32u size);
++ void* (*MallocDev)(bit32u Size);
++ void* (*MallocDmaXfer)(bit32u size, void *MemBase, bit32u MemRange);
++ void* (*MallocRxBuffer)(bit32u size, void *MemBase, bit32u MemRange,
++ OS_SETUP *OsSetup, HAL_RECEIVEINFO *HalReceiveInfo,
++ OS_RECEIVEINFO **OsReceiveInfo, OS_DEVICE *OsDev);
++ void* (*Memset)(void *Dest, int C, bit32u N);
++ int (*Printf)(const char *Format, ...);
++ int (*Receive)(OS_DEVICE *OsDev,FRAGLIST *FragList,bit32u FragCount,
++ bit32u PacketSize,HAL_RECEIVEINFO *HalReceiveInfo, bit32u Mode);
++ int (*SendComplete)(OS_SENDINFO *OsSendInfo);
++ int (*Sprintf)(char *S, const char *Format, ...);
++ int (*Strcmpi)(const char *Str1, const char *Str2);
++ unsigned int (*Strlen)(const char *S);
++ char* (*Strstr)(const char *S1, const char *S2);
++ unsigned long (*Strtoul)(const char *Str, char **Endptr, int Base);
++ void (*TeardownComplete)(OS_DEVICE *OsDev, int Ch, int Direction);
++ } OS_FUNCTIONS;
++
++/************** MODULE SPECIFIC STUFF BELOW **************/
++
++#ifdef _CPHAL_CPMAC
++
++/*
++int halCpmacInitModule(HAL_DEVICE **HalDev, OS_DEVICE *OsDev, HAL_FUNCTIONS *HalFunc, int (*osBridgeInitModule)(OS_FUNCTIONS *), void* (*osMallocDev) (bit32u), int *Size, int inst);
++*/
++
++int halCpmacInitModule(HAL_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ HAL_FUNCTIONS **HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++#endif
++
++#ifdef _CPHAL_AAL5
++/*
++ * @ingroup shared_data
++ * The AAL5_FUNCTIONS struct defines the AAL5 function pointers used by upper layer
++ * software. The upper layer software receives these pointers through the
++ * call to cphalInitModule().
++ */
++/*
++typedef struct
++ {
++ int (*ChannelSetup)(HAL_DEVICE *HalDev, CHANNEL_INFO *HalCh, OS_SETUP *OsSetup);
++ int (*ChannelTeardown)(HAL_DEVICE *HalDev, int Ch, int Mode);
++ int (*Close)(HAL_DEVICE *HalDev, int Mode);
++ int (*Init)(HAL_DEVICE *HalDev);
++ int (*ModeChange)(HAL_DEVICE *HalDev, char *DeviceParms);
++ int (*Open)(HAL_DEVICE *HalDev);
++ int (*InfoGet)(HAL_DEVICE *HalDev, int Key, void *Value);
++ int (*Probe)(HAL_DEVICE *HalDev);
++ int (*RxReturn)(HAL_RECEIVEINFO *HalReceiveInfo, int StripFlag);
++ int (*Send)(HAL_DEVICE *HalDev,FRAGLIST *FragList,int FragCount,
++ int PacketSize,OS_SENDINFO *OsSendInfo,int Ch, int Queue,
++ bit32u Mode);
++ int (*StatsClear)(HAL_DEVICE *HalDev);
++ STAT_INFO* (*StatsGet)(HAL_DEVICE *HalDev);
++ int (*Status)(HAL_DEVICE *HalDev);
++ void (*Tick)(HAL_DEVICE *HalDev);
++ int (*Kick)(HAL_DEVICE *HalDev, int Queue);
++ volatile bit32u* (*RegAccess)(HAL_DEVICE *HalDev, bit32u RegOffset);
++ } AAL5_FUNCTIONS;
++*/
++
++int cpaal5InitModule(HAL_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ HAL_FUNCTIONS **HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++#endif
++
++#ifdef _CPHAL_AAL2
++/**
++ * @ingroup shared_data
++ * The AAL2_FUNCTIONS struct defines the AAL2 function pointers used by upper layer
++ * software. The upper layer software receives these pointers through the
++ * call to cphalInitModule().
++ */
++typedef struct
++ {
++ int (*ChannelSetup)(HAL_DEVICE *HalDev, CHANNEL_INFO *HalCh, OS_SETUP *OsSetup);
++ int (*ChannelTeardown)(HAL_DEVICE *HalDev, int Ch, int Mode);
++ int (*Close)(HAL_DEVICE *HalDev, int Mode);
++ int (*Init)(HAL_DEVICE *HalDev);
++ int (*ModeChange)(HAL_DEVICE *HalDev, char *DeviceParms);
++ int (*Open)(HAL_DEVICE *HalDev);
++ int (*OptionsGet)(HAL_DEVICE *HalDev, char *Key, bit32u *Value);
++ int (*Probe)(HAL_DEVICE *HalDev);
++
++ int (*StatsClear)(HAL_DEVICE *HalDev);
++ STAT_INFO* (*StatsGet)(HAL_DEVICE *HalDev);
++ int (*Status)(HAL_DEVICE *HalDev);
++ void (*Tick)(HAL_DEVICE *HalDev);
++ int (*Aal2UuiMappingSetup)(HAL_DEVICE *HalDev, int VC, int UUI,
++ int VdmaCh, int UUIDiscard);
++ int (*Aal2RxMappingSetup)(HAL_DEVICE *HalDev, int VC, int CID,
++ int LC);
++ int (*Aal2TxMappingSetup)(HAL_DEVICE *HalDev, int VC, int LC, int VdmaCh);
++ int (*Aal2VdmaChSetup)(HAL_DEVICE *HalDev, bit32u RemVdmaVtAddr,
++ VdmaChInfo *VdmaCh);
++ volatile bit32u* (*RegAccess)(HAL_DEVICE *HalDev, bit32u RegOffset);
++ int (*Aal2ModeChange)(HAL_DEVICE *HalDev, int Vc, int RxCrossMode,
++ int RxMultiMode, int TxMultiMode, int SchedMode,
++ int TcCh);
++ void (*Aal2VdmaEnable)(HAL_DEVICE *HalDev, int Ch);
++ int (*Aal2VdmaDisable)(HAL_DEVICE *HalDev, int Ch);
++ } AAL2_FUNCTIONS;
++
++int cpaal2InitModule(HAL_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ AAL2_FUNCTIONS **HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++#endif
++
++#ifdef _CPHAL_VDMAVT
++/**
++ * @ingroup shared_data
++ * The VDMA_FUNCTIONS struct defines the HAL function pointers used by upper layer
++ * software. The upper layer software receives these pointers through the
++ * call to InitModule().
++ *
++ * Note that this list is still under definition.
++ */
++typedef struct
++ {
++ bit32 (*Init)( HAL_DEVICE *VdmaVtDev);
++ /* bit32 (*SetupTxFifo)(HAL_DEVICE *VdmaVtDev, bit32u LclRem,
++ bit32u Addr, bit32u Size, bit32u PollInt);
++ bit32 (*SetupRxFifo)(HAL_DEVICE *VdmaVtDev, bit32u LclRem,
++ bit32u Addr, bit32u Size, bit32u PollInt); */
++ bit32 (*Tx)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*Rx)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*SetRemoteChannel)(HAL_DEVICE *VdmaVtDev, bit32u RemAddr,
++ bit32u RemDevID);
++ bit32 (*ClearRxInt)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*ClearTxInt)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*Open)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*Close)(HAL_DEVICE *VdmaVtDev);
++ int (*Control) (HAL_DEVICE *HalDev, const char *Key, const char *Action, void *Value);
++ int (*ChannelSetup)(HAL_DEVICE *VdmaVtDev, CHANNEL_INFO *HalCh, OS_SETUP *OsSetup);
++ int (*ChannelTeardown)(HAL_DEVICE *VdmaVtDev, int Ch, int Mode);
++ int (*Send)(HAL_DEVICE *VdmaVtDev,FRAGLIST *FragList,int FragCount,
++ int PacketSize,OS_SENDINFO *OsSendInfo,bit32u Mode);
++ } VDMA_FUNCTIONS;
++
++int VdmaInitModule(HAL_DEVICE **VdmaVt,
++ OS_DEVICE *OsDev,
++ VDMA_FUNCTIONS **VdmaVtFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++#endif
++
++/*
++extern int cphalInitModule(MODULE_TYPE ModuleType, HAL_DEVICE **HalDev, OS_DEVICE *OsDev, HAL_FUNCTIONS *HalFunc,
++ int (*osInitModule)(OS_FUNCTIONS *), void* (*osMallocDev)(bit32u),
++ int *Size, int Inst);
++*/
++
++
++#ifdef _CPHAL_AAL5
++extern const char hcSarFrequency[];
++#endif
++
++#ifdef _CPHAL_CPMAC
++/* following will be common, once 'utl' added */
++extern const char hcClear[];
++extern const char hcGet[];
++extern const char hcSet[];
++extern const char hcTick[];
++
++extern const char hcCpuFrequency[];
++extern const char hcCpmacFrequency[];
++extern const char hcMdioBusFrequency[];
++extern const char hcMdioClockFrequency[];
++extern const char hcCpmacBase[];
++extern const char hcPhyNum[];
++extern const char hcSize[];
++extern const char hcCpmacSize[];
++extern const char hcPhyAccess[];
++#endif
++
++#endif /* end of _INC_ */
+diff -urN linux.old/drivers/atm/sangam_atm/cpswhal_cpsar.h linux.dev/drivers/atm/sangam_atm/cpswhal_cpsar.h
+--- linux.old/drivers/atm/sangam_atm/cpswhal_cpsar.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/cpswhal_cpsar.h 2005-08-23 04:46:50.089844912 +0200
+@@ -0,0 +1,629 @@
++/************************************************************************
++ * TNETDxxxx Software Support
++ * Copyright (c) 2002 Texas Instruments Incorporated. All Rights Reserved.
++ *
++ * FILE: cphal.h
++ *
++ * DESCRIPTION:
++ * User include file, contains data definitions shared between the CPHAL
++ * and the upper-layer software.
++ *
++ * HISTORY:
++ * Date Modifier Ver Notes
++ * 28Feb02 Greg 1.00 Original
++ * 06Mar02 Greg 1.01 Documentation enhanced
++ * 18Jul02 Greg 1.02 Many updates (OAM additions, general reorg)
++ * 22Nov02 Mick RC2 Additions from Denis' input on Control
++ *
++ * author Greg Guyotte
++ * version 1.02
++ * date 18-Jul-2002
++ *****************************************************************************/
++#ifndef _INC_CPHAL_H
++#define _INC_CPHAL_H
++
++#ifdef _CPHAL_CPMAC
++#include "ec_errors_cpmac.h"
++#endif
++
++#ifdef _CPHAL_AAL5
++#include "ec_errors_cpaal5.h"
++#endif
++
++#ifdef _CPHAL_CPSAR
++#include "ec_errors_cpsar.h"
++#endif
++
++#ifdef _CPHAL_AAL2
++#include "ec_errors_cpaal2.h"
++#endif
++
++#ifndef __ADAM2
++typedef char bit8;
++typedef short bit16;
++typedef int bit32;
++
++typedef unsigned char bit8u;
++typedef unsigned short bit16u;
++typedef unsigned int bit32u;
++
++/*
++typedef char INT8;
++typedef short INT16;
++typedef int INT32;
++typedef unsigned char UINT8;
++typedef unsigned short UINT16;
++typedef unsigned int UINT32;
++*/
++/*typedef unsigned int size_t;*/
++#endif
++
++#ifdef _CPHAL
++
++#ifndef TRUE
++#define TRUE (1==1)
++#endif
++
++#ifndef FALSE
++#define FALSE (1==2)
++#endif
++
++#ifndef NULL
++#define NULL 0
++#endif
++
++#endif
++
++#define VirtToPhys(a) (((int)a)&~0xe0000000)
++#define VirtToVirtNoCache(a) ((void*)((VirtToPhys(a))|0xa0000000))
++#define VirtToVirtCache(a) ((void*)((VirtToPhys(a))|0x80000000))
++#define PhysToVirtNoCache(a) ((void*)(((int)a)|0xa0000000))
++#define PhysToVirtCache(a) ((void*)(((int)a)|0x80000000))
++/*
++#define DataCacheHitInvalidate(a) {__asm__(" cache 17, (%0)" : : "r" (a));}
++#define DataCacheHitWriteback(a) {__asm__(" cache 25, (%0)" : : "r" (a));}
++*/
++
++#define PARTIAL 1 /**< Used in @c Close() and @c ChannelTeardown() */
++#define FULL 2 /**< Used in @c Close() and @c ChannelTeardown() */
++
++/* Channel Teardown Defines */
++#define RX_TEARDOWN 2
++#define TX_TEARDOWN 1
++#define BLOCKING_TEARDOWN 8
++#define FULL_TEARDOWN 4
++#define PARTIAL_TEARDOWN 0
++
++#define MAX_DIR 2
++#define DIRECTION_TX 0
++#define DIRECTION_RX 1
++#define TX_CH 0
++#define RX_CH 1
++#define HAL_ERROR_DEVICE_NOT_FOUND 1
++#define HAL_ERROR_FAILED_MALLOC 2
++#define HAL_ERROR_OSFUNC_SIZE 3
++#define HAL_DEFAULT 0xFFFFFFFF
++#define VALID(val) (val!=HAL_DEFAULT)
++
++/*
++ERROR REPORTING
++
++HAL Module Codes. Each HAL module reporting an error code
++should OR the error code with the respective Module error code
++from the list below.
++*/
++#define EC_AAL5 EC_HAL|EC_DEV_AAL5
++#define EC_AAL2 EC_HAL|EC_DEV_AAL2
++#define EC_CPSAR EC_HAL|EC_DEV_CPSAR
++#define EC_CPMAC EC_HAL|EC_DEV_CPMAC
++#define EC_VDMA EC_HAL|EC_DEV_VDMA
++#define EC_VLYNQ EC_HAL|EC_DEV_VLYNQ
++#define EC_CPPI EC_HAL|EC_DEV_CPPI
++
++/*
++HAL Function Codes. Each HAL module reporting an error code
++should OR the error code with one of the function codes from
++the list below.
++*/
++#define EC_FUNC_HAL_INIT EC_FUNC(1)
++#define EC_FUNC_CHSETUP EC_FUNC(2)
++#define EC_FUNC_CHTEARDOWN EC_FUNC(3)
++#define EC_FUNC_RXRETURN EC_FUNC(4)
++#define EC_FUNC_SEND EC_FUNC(5)
++#define EC_FUNC_RXINT EC_FUNC(6)
++#define EC_FUNC_TXINT EC_FUNC(7)
++#define EC_FUNC_AAL2_VDMA EC_FUNC(8)
++#define EC_FUNC_OPTIONS EC_FUNC(9)
++#define EC_FUNC_PROBE EC_FUNC(10)
++#define EC_FUNC_OPEN EC_FUNC(11)
++#define EC_FUNC_CONTROL EC_FUNC(12)
++#define EC_FUNC_DEVICE_INT EC_FUNC(13)
++#define EC_FUNC_STATUS EC_FUNC(14)
++#define EC_FUNC_TICK EC_FUNC(15)
++#define EC_FUNC_CLOSE EC_FUNC(16)
++#define EC_FUNC_SHUTDOWN EC_FUNC(17)
++#define EC_FUNC_DEVICE_INT_ALT EC_FUNC(18) /* +GSG 030306 */
++
++/*
++HAL Error Codes. The list below defines every type of error
++used in all HAL modules. DO NOT CHANGE THESE VALUES! Add new
++values in integer order to the bottom of the list.
++*/
++#define EC_VAL_PDSP_LOAD_FAIL EC_ERR(0x01)|EC_CRITICAL
++#define EC_VAL_FIRMWARE_TOO_LARGE EC_ERR(0x02)|EC_CRITICAL
++#define EC_VAL_DEVICE_NOT_FOUND EC_ERR(0x03)|EC_CRITICAL
++#define EC_VAL_BASE_ADDR_NOT_FOUND EC_ERR(0x04)|EC_CRITICAL
++#define EC_VAL_RESET_BIT_NOT_FOUND EC_ERR(0x05)|EC_CRITICAL
++#define EC_VAL_CH_INFO_NOT_FOUND EC_ERR(0x06)
++#define EC_VAL_RX_STATE_RAM_NOT_CLEARED EC_ERR(0x07)|EC_CRITICAL
++#define EC_VAL_TX_STATE_RAM_NOT_CLEARED EC_ERR(0x08)|EC_CRITICAL
++#define EC_VAL_MALLOC_DEV_FAILED EC_ERR(0x09)
++#define EC_VAL_OS_VERSION_NOT_SUPPORTED EC_ERR(0x0A)|EC_CRITICAL
++#define EC_VAL_CPSAR_VERSION_NOT_SUPPORTED EC_ERR(0x0B)|EC_CRITICAL
++#define EC_VAL_NULL_CPSAR_DEV EC_ERR(0x0C)|EC_CRITICAL
++
++#define EC_VAL_LUT_NOT_READY EC_ERR(0x0D)
++#define EC_VAL_INVALID_CH EC_ERR(0x0E)
++#define EC_VAL_NULL_CH_STRUCT EC_ERR(0x0F)
++#define EC_VAL_RX_TEARDOWN_ALREADY_PEND EC_ERR(0x10)
++#define EC_VAL_TX_TEARDOWN_ALREADY_PEND EC_ERR(0x11)
++#define EC_VAL_RX_CH_ALREADY_TORNDOWN EC_ERR(0x12)
++#define EC_VAL_TX_CH_ALREADY_TORNDOWN EC_ERR(0x13)
++#define EC_VAL_TX_TEARDOWN_TIMEOUT EC_ERR(0x14)
++#define EC_VAL_RX_TEARDOWN_TIMEOUT EC_ERR(0x15)
++#define EC_VAL_CH_ALREADY_TORNDOWN EC_ERR(0x16)
++#define EC_VAL_VC_SETUP_NOT_READY EC_ERR(0x17)
++#define EC_VAL_VC_TEARDOWN_NOT_READY EC_ERR(0x18)
++#define EC_VAL_INVALID_VC EC_ERR(0x19)
++#define EC_VAL_INVALID_LC EC_ERR(0x20)
++#define EC_VAL_INVALID_VDMA_CH EC_ERR(0x21)
++#define EC_VAL_INVALID_CID EC_ERR(0x22)
++#define EC_VAL_INVALID_UUI EC_ERR(0x23)
++#define EC_VAL_INVALID_UUI_DISCARD EC_ERR(0x24)
++#define EC_VAL_CH_ALREADY_OPEN EC_ERR(0x25)
++
++#define EC_VAL_RCB_MALLOC_FAILED EC_ERR(0x26)
++#define EC_VAL_RX_BUFFER_MALLOC_FAILED EC_ERR(0x27)
++#define EC_VAL_OUT_OF_TCBS EC_ERR(0x28)
++#define EC_VAL_NO_TCBS EC_ERR(0x29)
++#define EC_VAL_NULL_RCB EC_ERR(0x30)|EC_CRITICAL
++#define EC_VAL_SOP_ERROR EC_ERR(0x31)|EC_CRITICAL
++#define EC_VAL_EOP_ERROR EC_ERR(0x32)|EC_CRITICAL
++#define EC_VAL_NULL_TCB EC_ERR(0x33)|EC_CRITICAL
++#define EC_VAL_CORRUPT_RCB_CHAIN EC_ERR(0x34)|EC_CRITICAL
++#define EC_VAL_TCB_MALLOC_FAILED EC_ERR(0x35)
++
++#define EC_VAL_DISABLE_POLLING_FAILED EC_ERR(0x36)
++#define EC_VAL_KEY_NOT_FOUND EC_ERR(0x37)
++#define EC_VAL_MALLOC_FAILED EC_ERR(0x38)
++#define EC_VAL_RESET_BASE_NOT_FOUND EC_ERR(0x39)|EC_CRITICAL
++#define EC_VAL_INVALID_STATE EC_ERR(0x40)
++#define EC_VAL_NO_TXH_WORK_TO_DO EC_ERR(0x41)
++#define EC_VAL_NO_TXL_WORK_TO_DO EC_ERR(0x42)
++#define EC_VAL_NO_RX_WORK_TO_DO EC_ERR(0x43)
++#define EC_VAL_NOT_LINKED EC_ERR(0x44)
++#define EC_VAL_INTERRUPT_NOT_FOUND EC_ERR(0x45)
++#define EC_VAL_OFFSET_NOT_FOUND EC_ERR(0x46)
++#define EC_VAL_MODULE_ALREADY_CLOSED EC_ERR(0x47)
++#define EC_VAL_MODULE_ALREADY_SHUTDOWN EC_ERR(0x48)
++#define EC_VAL_ACTION_NOT_FOUND EC_ERR(0x49)
++#define EC_VAL_RX_CH_ALREADY_SETUP EC_ERR(0x50)
++#define EC_VAL_TX_CH_ALREADY_SETUP EC_ERR(0x51)
++#define EC_VAL_RX_CH_ALREADY_OPEN EC_ERR(0x52)
++#define EC_VAL_TX_CH_ALREADY_OPEN EC_ERR(0x53)
++#define EC_VAL_CH_ALREADY_SETUP EC_ERR(0x54)
++#define EC_VAL_RCB_NEEDS_BUFFER EC_ERR(0x55) /* +GSG 030410 */
++#define EC_VAL_RCB_DROPPED EC_ERR(0x56) /* +GSG 030410 */
++#define EC_VAL_INVALID_VALUE EC_ERR(0x57)
++
++/**
++@defgroup shared_data Shared Data Structures
++
++The data structures documented here are shared by all modules.
++*/
++
++/**
++ * @ingroup shared_data
++ * This is the fragment list structure. Each fragment list entry contains a
++ * length and a data buffer.
++ */
++typedef struct
++ {
++ bit32u len; /**< Length of the fragment in bytes (lower 16 bits are valid). For SOP, upper 16 bits is the buffer offset. */
++ void *data; /**< Pointer to fragment data. */
++ void *OsInfo; /**< Pointer to OS defined data. */
++ }FRAGLIST;
++
++#if defined (_CPHAL_CPMAC)
++#define CB_PASSCRC_BIT (1<<26)
++
++/* CPMAC CPHAL STATUS */
++#define CPMAC_STATUS_LINK (1 << 0)
++#define CPMAC_STATUS_LINK_DUPLEX (1 << 1) /* 0 - HD, 1 - FD */
++#define CPMAC_STATUS_LINK_SPEED (1 << 2) /* 0 - 10, 1 - 100 */
++
++/* ADAPTER CHECK Codes */
++
++#define CPMAC_STATUS_ADAPTER_CHECK (1 << 7)
++#define CPMAC_STATUS_HOST_ERR_DIRECTION (1 << 8)
++#define CPMAC_STATUS_HOST_ERR_CODE (0xF << 9)
++#define CPMAC_STATUS_HOST_ERR_CH (0x7 << 13)
++
++#define _CPMDIO_DISABLE (1 << 0)
++#define _CPMDIO_HD (1 << 1)
++#define _CPMDIO_FD (1 << 2)
++#define _CPMDIO_10 (1 << 3)
++#define _CPMDIO_100 (1 << 4)
++#define _CPMDIO_NEG_OFF (1 << 5)
++#define _CPMDIO_LOOPBK (1 << 16)
++#define _CPMDIO_NOPHY (1 << 20)
++#endif
++
++/**
++ * @ingroup shared_data
++ * Channel specific configuration information. This structure should be
++ * populated by upper-layer software prior to calling @c ChannelSetup(). Any
++ * configuration item that can be changed on a per channel basis should
++ * be represented here. Each module may define this structure with additional
++ * module-specific members.
++ */
++typedef struct
++ {
++ int Channel; /**< Channel number. */
++ int Direction; /**< DIRECTION_RX(1) or DIRECTION_TX(0). */
++ OS_SETUP *OsSetup; /**< OS defined information associated with this channel. */
++
++#if defined(_CPHAL_AAL5) || defined (_CPHAL_CPSAR) || defined (_CPHAL_CPMAC)
++ int RxBufSize; /**< Size (in bytes) for each Rx buffer.*/
++ int RxBufferOffset; /**< Number of bytes to offset rx data from start of buffer (must be less than buffer size). */
++ int RxNumBuffers; /**< The number of Rx buffer descriptors to allocate for Ch. */
++ int RxServiceMax; /**< Maximum number of packets to service at one time. */
++
++ int TxNumBuffers; /**< The number of Tx buffer descriptors to allocate for Ch. */
++ int TxNumQueues; /**< Number of Tx queues for this channel (1-2). Choosing 2 enables a low priority SAR queue. */
++ int TxServiceMax; /**< Maximum number of packets to service at one time. */
++#endif
++
++#if defined(_CPHAL_AAL5) || defined(_CPHAL_CPSAR)
++ int CpcsUU; /**< The 2-byte CPCS UU and CPI information. */
++ int Gfc; /**< Generic Flow Control. */
++ int Clp; /**< Cell Loss Priority. */
++ int Pti; /**< Payload Type Indication. */
++#endif
++
++#if defined(_CPHAL_AAL2) || defined(_CPHAL_AAL5) || defined(_CPHAL_CPSAR)
++ int DaMask; /**< Specifies whether credit issuance is paused when Tx data not available. */
++ int Priority; /**< Priority bin this channel will be scheduled within. */
++ int PktType; /**< 0=AAL5,1=Null AAL,2=OAM,3=Transparent,4=AAL2. */
++ int Vci; /**< Virtual Channel Identifier. */
++ int Vpi; /**< Virtual Path Identifier. */
++ int FwdUnkVc; /**< Enables forwarding of unknown VCI/VPI cells to host. 1=enable, 0=disable. */
++
++ /* Tx VC State */
++ int TxVc_CellRate; /**< Tx rate, set as clock ticks between transmissions (SCR for VBR, CBR for CBR). */
++ int TxVc_QosType; /**< 0=CBR,1=VBR,2=UBR,3=UBRmcr. */
++ int TxVc_Mbs; /**< Min Burst Size in cells.*/
++ int TxVc_Pcr; /**< Peak Cell Rate for VBR in clock ticks between transmissions. */
++
++ bit32 TxVc_AtmHeader; /**< ATM Header placed on firmware gen'd OAM cells for this Tx Ch (must be big endian with 0 PTI). */
++ int TxVc_OamTc; /**< TC Path to transmit OAM cells for TX connection (0,1). */
++ int TxVc_VpOffset; /**< Offset to the OAM VP state table. */
++ /* Rx VC State */
++ int RxVc_OamCh; /**< Ch to terminate rx'd OAM cells to be forwarded to the host. */
++ int RxVc_OamToHost; /**< 0=do not pass, 1=pass. */
++ bit32 RxVc_AtmHeader; /**< ATM Header placed on firmware gen'd OAM cells for this Rx conn (must be big endian with 0 PTI). */
++ int RxVc_OamTc; /**< TC Path to transmit OAM cells for RX connection (0,1). */
++ int RxVc_VpOffset; /**< Offset to the OAM VP state table. */
++ /* Tx VP State */
++ int TxVp_OamTc; /**< TC Path to transmit OAM cells for TX VP connection (0,1). */
++ bit32 TxVp_AtmHeader; /**< ATM Header placed on firmware gen'd VP OAM cells for this Tx VP conn (must be big endian with 0 VCI). */
++ /* Rx VP State */
++ int RxVp_OamCh; /**< Ch to terminate rx'd OAM cells to be forwarded to the host. */
++ int RxVp_OamToHost; /**< 0=do not pass, 1=pass. */
++ bit32 RxVp_AtmHeader; /**< ATM Header placed on firmware gen'd OAM cells for this Rx VP conn (must be big endian with 0 VCI). */
++ int RxVp_OamTc; /**< TC Path to transmit OAM cells for RX VP connection (0,1). */
++ int RxVp_OamVcList; /**< Indicates all VC channels associated with this VP channel (one-hot encoded). */
++#endif
++
++
++#ifdef _CPHAL_VDMAVT
++ bit32u RemFifoAddr; /* Mirror mode only. */
++ bit32u FifoAddr;
++ bit32 PollInt;
++ bit32 FifoSize;
++ int Ready;
++#endif
++
++ }CHANNEL_INFO;
++
++/*
++ * This structure contains each statistic value gathered by the CPHAL.
++ * Applications may access statistics data by using the @c StatsGet() routine.
++ */
++/* STATS */
++#if defined(_CPHAL_AAL2) || defined(_CPHAL_AAL5) || defined(_CPHAL_CPSAR)
++typedef struct
++ {
++ bit32u CrcErrors[16];
++ bit32u LenErrors[16];
++ bit32u DmaLenErrors[16];
++ bit32u AbortErrors[16];
++ bit32u StarvErrors[16];
++ bit32u TxMisQCnt[16][2];
++ bit32u RxMisQCnt[16];
++ bit32u RxEOQCnt[16];
++ bit32u TxEOQCnt[16][2];
++ bit32u RxPacketsServiced[16];
++ bit32u TxPacketsServiced[16][2];
++ bit32u RxMaxServiced;
++ bit32u TxMaxServiced[16][2];
++ bit32u RxTotal;
++ bit32u TxTotal;
++ } STAT_INFO;
++#endif
++
++/*
++ * VDMA Channel specific configuration information
++ */
++#ifdef _CPHAL_AAL2
++typedef struct
++ {
++ int Ch; /**< Channel Number */
++ int RemoteEndian; /**< Endianness of remote VDMA-VT device */
++ int CpsSwap; /**< When 0, octet 0 in CPS pkt located in LS byte of 16-bit word sent to rem VDMA device. When 1, in MS byte. */
++ }VdmaChInfo;
++#endif
++
++#ifndef _CPHAL
++ typedef void HAL_DEVICE;
++ typedef void HAL_PRIVATE;
++ typedef void HAL_RCB;
++ typedef void HAL_RECEIVEINFO;
++#endif
++
++/**
++ * @ingroup shared_data
++ * The HAL_FUNCTIONS struct defines the function pointers used by upper layer
++ * software. The upper layer software receives these pointers through the
++ * call to xxxInitModule().
++ */
++typedef struct
++ {
++ int (*ChannelSetup) (HAL_DEVICE *HalDev, CHANNEL_INFO *Channel, OS_SETUP *OsSetup);
++ int (*ChannelTeardown) (HAL_DEVICE *HalDev, int Channel, int Mode);
++ int (*Close) (HAL_DEVICE *HalDev, int Mode);
++ int (*Control) (HAL_DEVICE *HalDev, const char *Key, const char *Action, void *Value);
++ int (*Init) (HAL_DEVICE *HalDev);
++ int (*Open) (HAL_DEVICE *HalDev);
++ int (*PacketProcessEnd) (HAL_DEVICE *HalDev);
++ int (*Probe) (HAL_DEVICE *HalDev);
++ int (*RxReturn) (HAL_RECEIVEINFO *HalReceiveInfo, int StripFlag);
++ int (*Send) (HAL_DEVICE *HalDev, FRAGLIST *FragList, int FragCount, int PacketSize, OS_SENDINFO *OsSendInfo, bit32u Mode);
++ int (*Shutdown) (HAL_DEVICE *HalDev);
++ int (*Tick) (HAL_DEVICE *HalDev);
++
++#ifdef _CPHAL_AAL5
++ int (*Kick) (HAL_DEVICE *HalDev, int Queue);
++ void (*OamFuncConfig) (HAL_DEVICE *HalDev, unsigned int OamConfig);
++ void (*OamLoopbackConfig) (HAL_DEVICE *HalDev, unsigned int OamConfig, unsigned int *LLID, unsigned int CorrelationTag);
++ volatile bit32u* (*RegAccess)(HAL_DEVICE *HalDev, bit32u RegOffset);
++ STAT_INFO* (*StatsGetOld)(HAL_DEVICE *HalDev);
++#endif
++ } HAL_FUNCTIONS;
++
++/**
++ * @ingroup shared_data
++ * The OS_FUNCTIONS struct defines the function pointers for all upper layer
++ * functions accessible to the CPHAL. The upper layer software is responsible
++ * for providing the correct OS-specific implementations for the following
++ * functions. It is populated by calling InitModule() (done by the CPHAL in
++ * xxxInitModule().
++ */
++typedef struct
++ {
++ int (*Control)(OS_DEVICE *OsDev, const char *Key, const char *Action, void *Value);
++ void (*CriticalOn)(void);
++ void (*CriticalOff)(void);
++ void (*DataCacheHitInvalidate)(void *MemPtr, int Size);
++ void (*DataCacheHitWriteback)(void *MemPtr, int Size);
++ int (*DeviceFindInfo)(int Inst, const char *DeviceName, void *DeviceInfo);
++ int (*DeviceFindParmUint)(void *DeviceInfo, const char *Parm, bit32u *Value);
++ int (*DeviceFindParmValue)(void *DeviceInfo, const char *Parm, void *Value);
++ void (*Free)(void *MemPtr);
++ void (*FreeRxBuffer)(OS_RECEIVEINFO *OsReceiveInfo, void *MemPtr);
++ void (*FreeDev)(void *MemPtr);
++ void (*FreeDmaXfer)(void *MemPtr);
++ void (*IsrRegister)(OS_DEVICE *OsDev, int (*halISR)(HAL_DEVICE*, int*), int InterruptBit);
++ void (*IsrUnRegister)(OS_DEVICE *OsDev, int InterruptBit);
++ void* (*Malloc)(bit32u size);
++ void* (*MallocDev)(bit32u Size);
++ void* (*MallocDmaXfer)(bit32u size, void *MemBase, bit32u MemRange);
++ void* (*MallocRxBuffer)(bit32u size, void *MemBase, bit32u MemRange,
++ OS_SETUP *OsSetup, HAL_RECEIVEINFO *HalReceiveInfo,
++ OS_RECEIVEINFO **OsReceiveInfo, OS_DEVICE *OsDev);
++ void* (*Memset)(void *Dest, int C, bit32u N);
++ int (*Printf)(const char *Format, ...);
++ int (*Receive)(OS_DEVICE *OsDev,FRAGLIST *FragList,bit32u FragCount,
++ bit32u PacketSize,HAL_RECEIVEINFO *HalReceiveInfo, bit32u Mode);
++ int (*SendComplete)(OS_SENDINFO *OsSendInfo);
++ int (*Sprintf)(char *S, const char *Format, ...);
++ int (*Strcmpi)(const char *Str1, const char *Str2);
++ unsigned int (*Strlen)(const char *S);
++ char* (*Strstr)(const char *S1, const char *S2);
++ unsigned long (*Strtoul)(const char *Str, char **Endptr, int Base);
++ void (*TeardownComplete)(OS_DEVICE *OsDev, int Ch, int Direction);
++ } OS_FUNCTIONS;
++
++/************** MODULE SPECIFIC STUFF BELOW **************/
++
++#ifdef _CPHAL_CPMAC
++
++/*
++int halCpmacInitModule(HAL_DEVICE **HalDev, OS_DEVICE *OsDev, HAL_FUNCTIONS *HalFunc, int (*osBridgeInitModule)(OS_FUNCTIONS *), void* (*osMallocDev) (bit32u), int *Size, int inst);
++*/
++
++int halCpmacInitModule(HAL_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ HAL_FUNCTIONS **HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++#endif
++
++#ifdef _CPHAL_AAL5
++/*
++ * @ingroup shared_data
++ * The AAL5_FUNCTIONS struct defines the AAL5 function pointers used by upper layer
++ * software. The upper layer software receives these pointers through the
++ * call to cphalInitModule().
++ */
++/*
++typedef struct
++ {
++ int (*ChannelSetup)(HAL_DEVICE *HalDev, CHANNEL_INFO *HalCh, OS_SETUP *OsSetup);
++ int (*ChannelTeardown)(HAL_DEVICE *HalDev, int Ch, int Mode);
++ int (*Close)(HAL_DEVICE *HalDev, int Mode);
++ int (*Init)(HAL_DEVICE *HalDev);
++ int (*ModeChange)(HAL_DEVICE *HalDev, char *DeviceParms);
++ int (*Open)(HAL_DEVICE *HalDev);
++ int (*InfoGet)(HAL_DEVICE *HalDev, int Key, void *Value);
++ int (*Probe)(HAL_DEVICE *HalDev);
++ int (*RxReturn)(HAL_RECEIVEINFO *HalReceiveInfo, int StripFlag);
++ int (*Send)(HAL_DEVICE *HalDev,FRAGLIST *FragList,int FragCount,
++ int PacketSize,OS_SENDINFO *OsSendInfo,int Ch, int Queue,
++ bit32u Mode);
++ int (*StatsClear)(HAL_DEVICE *HalDev);
++ STAT_INFO* (*StatsGet)(HAL_DEVICE *HalDev);
++ int (*Status)(HAL_DEVICE *HalDev);
++ void (*Tick)(HAL_DEVICE *HalDev);
++ int (*Kick)(HAL_DEVICE *HalDev, int Queue);
++ volatile bit32u* (*RegAccess)(HAL_DEVICE *HalDev, bit32u RegOffset);
++ } AAL5_FUNCTIONS;
++*/
++
++int cpaal5InitModule(HAL_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ HAL_FUNCTIONS **HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++#endif
++
++#ifdef _CPHAL_AAL2
++/**
++ * @ingroup shared_data
++ * The AAL2_FUNCTIONS struct defines the AAL2 function pointers used by upper layer
++ * software. The upper layer software receives these pointers through the
++ * call to cphalInitModule().
++ */
++typedef struct
++ {
++ int (*ChannelSetup)(HAL_DEVICE *HalDev, CHANNEL_INFO *HalCh, OS_SETUP *OsSetup);
++ int (*ChannelTeardown)(HAL_DEVICE *HalDev, int Ch, int Mode);
++ int (*Close)(HAL_DEVICE *HalDev, int Mode);
++ int (*Init)(HAL_DEVICE *HalDev);
++ int (*ModeChange)(HAL_DEVICE *HalDev, char *DeviceParms);
++ int (*Open)(HAL_DEVICE *HalDev);
++ int (*OptionsGet)(HAL_DEVICE *HalDev, char *Key, bit32u *Value);
++ int (*Probe)(HAL_DEVICE *HalDev);
++
++ int (*StatsClear)(HAL_DEVICE *HalDev);
++ STAT_INFO* (*StatsGet)(HAL_DEVICE *HalDev);
++ int (*Status)(HAL_DEVICE *HalDev);
++ void (*Tick)(HAL_DEVICE *HalDev);
++ int (*Aal2UuiMappingSetup)(HAL_DEVICE *HalDev, int VC, int UUI,
++ int VdmaCh, int UUIDiscard);
++ int (*Aal2RxMappingSetup)(HAL_DEVICE *HalDev, int VC, int CID,
++ int LC);
++ int (*Aal2TxMappingSetup)(HAL_DEVICE *HalDev, int VC, int LC, int VdmaCh);
++ int (*Aal2VdmaChSetup)(HAL_DEVICE *HalDev, bit32u RemVdmaVtAddr,
++ VdmaChInfo *VdmaCh);
++ volatile bit32u* (*RegAccess)(HAL_DEVICE *HalDev, bit32u RegOffset);
++ int (*Aal2ModeChange)(HAL_DEVICE *HalDev, int Vc, int RxCrossMode,
++ int RxMultiMode, int TxMultiMode, int SchedMode,
++ int TcCh);
++ void (*Aal2VdmaEnable)(HAL_DEVICE *HalDev, int Ch);
++ int (*Aal2VdmaDisable)(HAL_DEVICE *HalDev, int Ch);
++ } AAL2_FUNCTIONS;
++
++int cpaal2InitModule(HAL_DEVICE **HalDev,
++ OS_DEVICE *OsDev,
++ AAL2_FUNCTIONS **HalFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++#endif
++
++#ifdef _CPHAL_VDMAVT
++/**
++ * @ingroup shared_data
++ * The VDMA_FUNCTIONS struct defines the HAL function pointers used by upper layer
++ * software. The upper layer software receives these pointers through the
++ * call to InitModule().
++ *
++ * Note that this list is still under definition.
++ */
++typedef struct
++ {
++ bit32 (*Init)( HAL_DEVICE *VdmaVtDev);
++ /* bit32 (*SetupTxFifo)(HAL_DEVICE *VdmaVtDev, bit32u LclRem,
++ bit32u Addr, bit32u Size, bit32u PollInt);
++ bit32 (*SetupRxFifo)(HAL_DEVICE *VdmaVtDev, bit32u LclRem,
++ bit32u Addr, bit32u Size, bit32u PollInt); */
++ bit32 (*Tx)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*Rx)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*SetRemoteChannel)(HAL_DEVICE *VdmaVtDev, bit32u RemAddr,
++ bit32u RemDevID);
++ bit32 (*ClearRxInt)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*ClearTxInt)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*Open)(HAL_DEVICE *VdmaVtDev);
++ bit32 (*Close)(HAL_DEVICE *VdmaVtDev);
++ int (*Control) (HAL_DEVICE *HalDev, const char *Key, const char *Action, void *Value);
++ int (*ChannelSetup)(HAL_DEVICE *VdmaVtDev, CHANNEL_INFO *HalCh, OS_SETUP *OsSetup);
++ int (*ChannelTeardown)(HAL_DEVICE *VdmaVtDev, int Ch, int Mode);
++ int (*Send)(HAL_DEVICE *VdmaVtDev,FRAGLIST *FragList,int FragCount,
++ int PacketSize,OS_SENDINFO *OsSendInfo,bit32u Mode);
++ } VDMA_FUNCTIONS;
++
++int VdmaInitModule(HAL_DEVICE **VdmaVt,
++ OS_DEVICE *OsDev,
++ VDMA_FUNCTIONS **VdmaVtFunc,
++ OS_FUNCTIONS *OsFunc,
++ int OsFuncSize,
++ int *HalFuncSize,
++ int Inst);
++#endif
++
++/*
++extern int cphalInitModule(MODULE_TYPE ModuleType, HAL_DEVICE **HalDev, OS_DEVICE *OsDev, HAL_FUNCTIONS *HalFunc,
++ int (*osInitModule)(OS_FUNCTIONS *), void* (*osMallocDev)(bit32u),
++ int *Size, int Inst);
++*/
++
++
++#ifdef _CPHAL_AAL5
++extern const char hcSarFrequency[];
++#endif
++
++#ifdef _CPHAL_CPMAC
++/* following will be common, once 'utl' added */
++extern const char hcClear[];
++extern const char hcGet[];
++extern const char hcSet[];
++extern const char hcTick[];
++
++extern const char hcCpuFrequency[];
++extern const char hcCpmacFrequency[];
++extern const char hcMdioBusFrequency[];
++extern const char hcMdioClockFrequency[];
++extern const char hcCpmacBase[];
++extern const char hcPhyNum[];
++extern const char hcSize[];
++extern const char hcCpmacSize[];
++extern const char hcPhyAccess[];
++#endif
++
++#endif /* end of _INC_ */
+diff -urN linux.old/drivers/atm/sangam_atm/dev_host_interface.h linux.dev/drivers/atm/sangam_atm/dev_host_interface.h
+--- linux.old/drivers/atm/sangam_atm/dev_host_interface.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/dev_host_interface.h 2005-08-23 04:46:50.091844608 +0200
+@@ -0,0 +1,1162 @@
++#ifndef __DEV_HOST_INTERFACE_H__
++#define __DEV_HOST_INTERFACE_H__ 1
++
++/*******************************************************************************
++* FILE PURPOSE: Public header file for the Host-to-DSP interface
++********************************************************************************
++*
++* TEXAS INSTRUMENTS PROPRIETARTY INFORMATION
++*
++* (C) Copyright Texas Instruments Inc. 2002. All rights reserved.
++*
++* Property of Texas Instruments Incorporated
++*
++* Restricted Rights - Use, duplication, or disclosure is subject to
++* restrictions set forth in TI's program license agreement and
++* associated documentation
++*
++*
++* FILE NAME: dev_host_interface.h
++*
++* DESCRIPTION:
++* This header file defines the variables and parameters used between the
++* host processor and the DSP. This file is included in both the DSP
++* software and the host software.
++*
++* RULES FOR MODIFICATION AND USE OF THIS FILE:
++*
++* --The main pointer to the struct of pointers will always be at the same fixed
++* location (0x80000000).
++*
++* --Each pointer element in the struct of pointers (indicated by the main pointer)
++* will always point to a struct only.
++*
++* --Any new structures added to the host interface in subsequent versions must
++* each have a corresponding new pointer element added to the END of the struct
++* of pointers. Other than this, there will never be any moving or rearranging
++* of the pointer elements in the struct of pointers.
++*
++* --Any new elements added to existing structures will be added at the END of the
++* structure. Other than this, there will never be any moving or rearranging
++* of structure elements.
++*
++* --A new structure will never be added as a new element in an old structure.
++* New structures must be added separately with a new entry in the struct of
++* pointers, as noted above.
++*
++* --Also, the sizes of existing arrays within old structures will never be changed.
++*
++* --The modem code in the DSP will never reference the struct of pointers in order
++* to avoid aliasing issues in the DSP code. The modem code will only use the
++* specific structures directly.
++*
++* --The host processor never accesses the DSP side of the ATM-TC hardware directly.
++* The DSP interfaces directly to the ATM-TC hardware and relays information to
++* the host processor through the host interface.
++*
++* --The host processor can track the modem's transition through important states
++* by accessing the Modem State Bit Field in the host interface. Each bit in
++* the bit field represents an important state to track in the modem. As the
++* modem transitions through each important state, the corresponding bit will
++* change from a zero to a one. Each bit in the bit field will only be reset to
++* zero if the modem retrains. If new states need to be tracked and are added
++* in subsequent versions of the host interface, a corresponding bit will be
++* added at the END of the bit field to ensure backwards compatibility. The
++* Modem State Bit Field is reset if the modem retrains or falls out of Showtime.
++*
++* --An interrupt will be sent to the host processor when a change occurs in the
++* Modem State Bit Field. There is an interrupt masking register which can mask
++* specific interrupts corresponding to the bits of the Modem State Bit Field.
++* This allows the host to keep an interrupt from being generated for those
++* states that are masked.
++*
++* HISTORY:
++*
++* 11/20/02 J. Bergsagel Written from the previous host interface file
++* 11/27/02 J. Bergsagel Added comments for mailbox control struct and
++* fixed a couple items for overlay page stuff.
++* Also, added temporary elements for SWTC code.
++* 12/04/02 J. Bergsagel Added extra dummy byte to DEV_HOST_eocVarDef_t
++* for proper word alignment.
++* 12/12/02 J. Bergsagel Changed initial states in the modem state bit field
++* and added more instructions for adding more states.
++* 12/16/02 J. Bergsagel Changed name "hostVersion_p" to "hostIntfcVersion_p".
++* Removed dspAturState from DEV_HOST_modemStateBitField_t.
++* Reorganized several struct elements to clean up the
++* host interface.
++* 12/27/02 Sameer V Added missing channel 0 statistics for TC. Added
++* ocd error information.
++* 12/27/02 Sameer V Added overlayState to OlayDP_Parms to indicate whether
++* overlays are being executed in current state.
++* 01/06/03 J. Bergsagel Added maxAllowedMargin and minRequiredMargin to
++* DEV_HOST_msg_t.
++* Renamed TC chan 1 items to be chan 0 items to start out.
++* 01/17/03 Sameer V Moved delineationState to atmStats structure.
++* 01/21/03 Barnett Implemented Ax7 UNIT-MODULE modular software framework.
++* 01/22/03 J. Bergsagel Added warning comments for certain struct typedefs.
++* 01/23/03 C. Perez-N. Removed old AX5-only diags. command/response entries in the
++* HOST and DSP ennumerations, and added the AX7 new ones
++* Added pointer entries in the DEV_HOST_dspOamSharedInterface_t
++* structure pointing to the analog diags. input/output/options
++* structures.
++* 01/29/03 Sameer V Removed TC_IDLE in enum for delineation state. Hardware
++* only reports TC_HUNT, TC_PRESYNC and TC_SYNC.
++* 03/07/03 Sameer/Jonathan Put SWTC token around structs and elements only used by SWTC
++* 03/12/03 Mannering Add CO profile data structures
++* 03/18/03 J. Bergsagel Removed the obsolete DSP_CHECK_TC response message.
++* 03/24/03 J. Bergsagel Added DEV_HOST_hostInterruptMask_t for masking DSP interrupt sources
++* 03/28/03 C. Perez-N Changed the C-style comments and made them C++ sytle instead.
++* Replaced the occurrences of "SINT32 *" pointer declarations with
++* "PSINT32"
++* 03/28/03 Mannering Update CO profile data structures
++* 04/04/03 S. Yim Add host I/F hooks for switchable hybrid and RJ11
++* inner/outer pair selection
++* 04/11/03 J. Bergsagel Changed modem state bit field struct types to enums instead and used
++* a single integer variable for each "bitfield".
++* Changed bit field for host interrupt masks to an integer value also.
++* 04/14/03 J. Bergsagel Changed name of table pointer "meanSquareTblDstrm_p" to "marginTblDstrm_p".
++* 04/03/03 Umesh Iyer CMsg1 and RMsg1 use the same storage as CMSGPCB and RMSGPCB.
++* The string lengths for these have been adjusted to hold the longest
++* message in each case. The PCB messages from ADSL2 are longer.
++* 04/21/03 Sameeer V Added new host mailbox message for shutting down the DSLSS peripherals.
++* 04/23/03 J. Bergsagel Fixed comments for overlay mailbox messages and for losErrors.
++* 04/28/03 Mannering Added skip phase op flag to CO profile data structure
++* 05/05/03 Mannering Review Comments - Removed "#if CO_PROFILE" from around structure
++* definitions and define the number of profiles (DEV_HOST_LIST_ENTRIES)
++* 05/13/03 J. Bergsagel Added new elements to DEV_HOST_phyPerf_t for host control of hybrid.
++* 05/15/03 J. Bergsagel Added "farEndLosErrors" and "farEndRdiErrors" to DEV_HOST_modemStatsDef_t.
++* 05/16/03 Mannering Updated CO profile structure to support updated bit allocation and
++* interopability.
++* 05/20/03 Sameer V Added DSP message to inicate DYING GASP.
++* 05/22/03 J. Bergsagel Added a new struct typedef "DEV_HOST_hostInterruptSource_t".
++* Added "atucGhsRevisionNum" to "DEV_HOST_dspWrNegoParaDef_t".
++* Moved the following struct typedef's here to the public host interface:
++* DEV_HOST_dspBitSwapDef_t
++* DEV_HOST_atmDsBert_t
++* 05/28/03 A. Redfern Changed pointer type and location for margin reporting.
++* 05/28/03 Mannering Moved CO profile defines to dev_host_interface_pvt.h
++* 05/28/03 J. Bergsagel Moved subStateIndex and STM BERT controls into new struct "DEV_HOST_modemEnvPublic_t"
++* 05/29/03 J. Bergsagel Added elements to "DEV_HOST_modemEnvPublic_t" for host control of DSLSS LED's.
++* 06/10/03 Umesh Iyer Modified trainMode check to be compliant with the new host i/f mods.
++* 06/05/03 J. Bergsagel Added enum that will eventually replace the bitfield: DEV_HOST_diagAnlgOptionsVar_t.
++* Added new element "currentHybridNumUsed" in the DEV_HOST_phyPerf_t typedef
++* Added new host control flags for LPR signal detection on GPIO[0].
++* 06/06/03 A. Redfern Removed fine gain scale from the CO profile and added max downstream power cutback.
++* Changed "test1" in CO profile struct to "phyEcDelayAdjustment".
++* 06/26/03 J. Bergsagel Added genericStructure typedef and two pointer elements of this type in the big table.
++* 07/03/03 Jack Huang Renamed test2 to bSwapThresholdUpdate
++* 07/07/03 Mallesh Changed phySigTxPowerCutback_f flag to a variable phySigTxGainReductionAt0kft which indicates the
++* amount of gain reduction in linear scale.
++* 07/15/03 Sameer V Changed DEV_HOST_diagAnlgOptionsVar_t to be an enum instead of a bit field. Host code
++* does not support setting bit fields.
++* 07/22/03 Jack Huang Added bitswap control flag in host i/f for API calls
++* 08/06/03 Sameer V Added missingToneDs_p to the DEV_HOST_oamWrNegoParaDef_t to enable host to switch off
++* DS tones on specified bins
++* 08/21/03 Jack Huang Added pcbEnabled flag in the DEV_HOST_modemEnvPublic_t structure
++* Added g.hs buffer definitions to DEV_HOST_dspOamSharedInterface_t
++* Added DEV_HOST_consBufDef_t to the DEV_HOST_dspOamSharedInterface_t structure
++* 08/26/03 J. Bergsagel Fixed name of "missingToneDs_p" to be "missingToneDsAddr" instead (since it is
++* not really used as a pointer).
++* 09/11/03 Mallesh Added a flag "usPilotInT1413ModeInMedley" to determine the need to send Upstream Pilot
++* in medley in T1.413 mode.
++* 09/12/03 J. Bergsagel Changed "test3" to "phyBitaFastPathExcessFineGainBump" in CO profile struct.
++* Changed "test4" to "phyBitaSkipGapAdjustment" in CO profile struct.
++* 09/23/03 J. Bergsagel Changed "T1413vendorRevisionNumber" to "vendorRevisionNumber" in DEV_HOST_msg_t.
++* Added ADSL2 and ADSL2 diag. states to the modem state bit field.
++* 10/01/03 J. Bergsagel Changed define of "MULTI_MODE" to be 255 to indicate that all possible bits
++* in the 8-bit bit field are turned on for any current and future training modes.
++* 10/09/03 M. Turkboylari Added DSP_TRAINING_MSGS and adsl2DeltMsgs_p, which is a pointer to a pointer,
++* in order to pass the ADSL2 training and DELT messages to the host side. This is for ACT.
++* 10/20/03 Mallesh Added a GHS state enumerator for cleardown
++* 10/20/03 Xiaohui Li Add definition for READSL2_MODE and READSL2_DELT
++* 11/07/03 J. Bergsagel Removed all code for when SWTC==1, which therefore allows removal of include of
++* "env_def_defines.h". We shouldn't have any compile tokens used in this file.
++* (the SWTC token is always off in any Ax7 code).
++* 11/14/03 J. Bergsagel Also removed READSL2_ENABLE token (no more compile tokens to be used in this .h file).
++* 12/12/03 Sameer/Ram Added DEV_HOST_EOCAOC_INTERRUPT_MASK to enable host to disable response code for AOC/EOC
++* mailbox messages
++* 12/09/03 Jack Huang Changed G.hs txbuf size from 60 to 64 to fit the max segment size
++* 12/15/03 Mallesh Changed vendor ID type defenition from SINT16 to UINT16
++* 12/23/03 Sameer V Added ability to turn off constellation display reporting to host using oamFeature bit field.
++* 12/24/03 Sameer V Changed comment for Constellation Display Current Address to Host Write instead of DSP Write.
++* 12/26/03 Sameer/Ram Added DEV_HOST_GHSMSG_INTERRUPT_MASK to enable host to disable response code for GHS Messages
++* (C) Copyright Texas Instruments Inc. 2002. All rights reserved.
++*******************************************************************************/
++
++#include "dev_host_verdef.h"
++
++// ---------------------------------------------------------------------------------
++// Address of the pointer to the DEV_HOST_dspOamSharedInterface_s struct of pointers
++// This is where it all starts.
++// ---------------------------------------------------------------------------------
++#define DEV_HOST_DSP_OAM_POINTER_LOCATION 0x80000000
++
++// The define "MAX_NUM_UPBINS" is used in "DEV_HOST_diagAnlgInputVar_t" below.
++// This value can never be changed (for host intf. backwards compatibility)
++#define MAX_NUM_UPBINS 64
++
++// -----------------------------------------------
++// Begin common enumerations between DSP and host.
++// -----------------------------------------------
++
++// These Host-to-DSP commands are organized into two groups:
++// immediate state change commands and status affecting commands.
++// Do not add or remove commands except at the bottom since the DSP assumes this sequence.
++
++enum
++{
++ HOST_ACTREQ, // Send R-ACKREQ and monitor for C-ACKx
++ HOST_QUIET, // Sit quietly doing nothing for about 60 seconds, DEFAULT STATE; R_IDLE
++ HOST_XMITBITSWAP, // Perform upstream bitswap - FOR INTERNAL USE ONLY
++ HOST_RCVBITSWAP, // Perform downstream bitswap - FOR INTERNAL USE ONLY
++ HOST_RTDLPKT, // Send a remote download packet - FOR INTERNAL USE ONLY
++ HOST_CHANGELED, // Read the LED settings and change accordingly
++ HOST_IDLE, // Sit quiet
++ HOST_REVERBTEST, // Generate REVERB for manufacturing test
++ HOST_CAGCTEST, // Set coarse receive gain for manufacturing test
++ HOST_DGASP, // send Dying Gasp messages through EOC channel
++ HOST_GHSREQ, // G.hs - FOR INTERNAL USE ONLY
++ HOST_GHSMSG, // G.hs - FOR INTERNAL USE ONLY
++ HOST_GHS_SENDGALF, // G.hs - FOR INTERNAL USE ONLY
++ HOST_GHSEXIT, // G.hs - FOR INTERNAL USE ONLY
++ HOST_GHSMSG1, // G.hs - FOR INTERNAL USE ONLY
++ HOST_HYBRID, // Enable/Disable automatic hybrid switch
++ HOST_RJ11SELECT, // RJ11 inner/outer pair select
++ HOST_DIGITAL_MEM, // Digital Diags: run external memory tests
++ HOST_TXREVERB, // AFE Diags: TX path Reverb
++ HOST_TXMEDLEY, // AFE Diags: TX path Medley
++ HOST_RXNOISEPOWER, // AFE Diags: RX noise power
++ HOST_ECPOWER, // AFE Diags: RX eco power
++ HOST_ALL_ADIAG, // AFE Diags: all major analog diagnostic modes. Host is responsible to initiate each diagnostic sessions
++ HOST_USER_ADIAG, // AFE Diags: Host fills in analog diagnostic input data structure as specified and requests DSP to perform measurements as specified
++ HOST_QUIT_ADIAG, // AFE Diags: Host requests DSP to quit current diagnostic session. This is used for stopping the transmit REVERB/MEDLEY
++ HOST_NO_CMD, // All others - G.hs - FOR INTERNAL USE ONLY
++ HOST_DSLSS_SHUTDOWN, // Host initiated DSLSS shutdown message
++ HOST_SET_GENERIC, // Set generic CO profile
++ HOST_UNDO_GENERIC, // Set profile previous to Generic
++ HOST_GHS_CLEARDOWN // G.hs - FOR INTERNAL USE ONLY to start cleardown
++};
++
++// These DSP-to-Host responses are organized into two groups:
++// responses to commands and requests for OAM services.
++
++enum
++{
++ DSP_IDLE, // R_IDLE state entered
++ DSP_ACTMON, // R_ACTMON state entered
++ DSP_TRAIN, // R_TRAIN state entered
++ DSP_ACTIVE, // R_ACTIVE state entered
++ DSP_XMITBITSWAP, // Upstream bitswap complete - FOR INTERNAL USE ONLY
++ DSP_RCVBITSWAP, // Downstream bitswap complete - FOR INTERNAL USE ONLY
++ DSP_RTDL, // R_RTDL state entered - FOR INTERNAL USE ONLY
++ DSP_RRTDLPKT, // RTDL packet received - FOR INTERNAL USE ONLY
++ DSP_XRTDLPKT, // RTDL packet transmitted - FOR INTERNAL USE ONLY
++ DSP_ERROR, // Command rejected, wrong state for this command
++ DSP_REVERBTEST, // Manufacturing REVERB test mode entered
++ DSP_CAGCTEST, // Manufacturing receive gain test done
++ DSP_OVERLAY_START, // Notify host that page overlay has started - overlay number indicated by "tag"
++ DSP_OVERLAY_END, // Notify host that page overlay has ended - overlay number indicated by "tag"
++ DSP_CRATES1, // CRATES1 message is valid and should be copied to host memory now
++ DSP_SNR, // SNR calculations are ready and should be copied to host memory now
++ DSP_GHSMSG, // G.hs - FOR INTERNAL USE ONLY
++ DSP_RCVBITSWAP_TIMEOUT, // Acknowledge Message was not received within ~500 msec (26 Superframes).
++ DSP_ATM_TC_SYNC, // Indicates true TC sync on both the upstream and downstream. Phy layer ready for data xfer.
++ DSP_ATM_NO_TC_SYNC, // Indicates loss of sync on phy layer on either US or DS.
++ DSP_HYBRID, // DSP completed hybrid switch
++ DSP_RJ11SELECT, // DSP completed RJ11 inner/outer pair select
++ DSP_INVALID_CMD, // Manufacturing (Digital and AFE) diags: CMD received not recognized
++ DSP_TEST_PASSED, // Manufacturing diags: test passed
++ DSP_TEST_FAILED, // Manufacturing diags: test failed
++ DSP_TXREVERB, // Manufacturing AFE diags: Response to HOST_TXREVERB
++ DSP_TXMEDLEY, // Manufacturing AFE diags: Response to HOST_TXMEDLEY
++ DSP_RXNOISEPOWER, // Manufacturing AFE diags: Response to HOST_RXNOISEPOWER
++ DSP_ECPOWER, // Manufacturing AFE diags: Response to HOST_ECPOWER
++ DSP_ALL_ADIAG, // Manufacturing AFE diags: Response to HOST_ALL_ADIAG
++ DSP_USER_ADIAG, // Manufacturing AFE diags: Response to HOST_USER_ADIAG
++ DSP_QUIT_ADIAG, // Manufacturing AFE diags: Response to HOST_QUIT_ADIAG
++ DSP_DGASP, // DSP Message to indicate dying gasp
++ DSP_EOC, // DSP Message to indicate that DSP sent an EOC message to CO
++ DSP_TRAINING_MSGS // DSP Message to indicate that host has to copy the training message specified in the tag field.
++};
++
++// Define different ADSL training modes.
++//Defintions as per new host interface.
++#define NO_MODE 0
++#define GDMT_MODE 2
++#define GLITE_MODE 4
++#define ADSL2_MODE 8
++#define ADSL2_DELT (ADSL2_MODE+1)
++#define ADSL2PLUS_MODE 16
++#define ADSL2PLUS_DELT (ADSL2PLUS_MODE+1)
++#define READSL2_MODE 32
++#define READSL2_DELT (READSL2_MODE+1)
++#define T1413_MODE 128
++#define MULTI_MODE 255 // all possible bits are set in the bit field
++
++// Define the reason for dropping the connection
++
++enum
++{
++ REASON_LOS = 0x01,
++ REASON_DYING_GASP = 0x02,
++ REASON_USCRCERR = 0x04,
++ REASON_MARGIN_DROP = 0x08
++};
++
++
++// ----------------------------------------------------
++// Begin modem state bit field definitions - DSP write.
++// ----------------------------------------------------
++
++// BitField1 for initial states and G.hs states.
++// If more values need to be added, they will be added at the end (up to 32 total entries). However, if this causes
++// the state transitions to tick off out of normal bit order, then the C code will have to be re-written
++// that causes the proper values to be entered into the modem state bit fields.
++typedef enum
++{
++ ZERO_STATE1 = 0,
++ RTEST = 0x1,
++ RIDLE = 0x2,
++ RINIT = 0x4,
++ RRESET = 0x8,
++ GNSFLR = 0x10,
++ GTONE = 0x20,
++ GSILENT = 0x40,
++ GNEGO = 0x80,
++ GFAIL = 0x100,
++ GACKX = 0x200,
++ GQUIET2 = 0x400
++} DEV_HOST_stateBitField1_t; // this enum should only have 32 bit entries in it. Add another enum if you need more.
++
++// BitField2 for T1.413 states and for the rest of the modem states (so far)
++// If more values need to be added, they will be added at the end (up to 32 total entries). However, if this causes
++// the state transitions to tick off out of normal bit order, then the C code will have to be re-written
++// that causes the proper values to be entered into the modem state bit fields.
++typedef enum
++{
++ ZERO_STATE2 = 0,
++ TNSFLR = 0x1,
++ TACTREQ = 0x2,
++ TACTMON = 0x4,
++ TFAIL = 0x8,
++ TACKX = 0x10,
++ TQUIET2 = 0x20,
++ RQUIET2 = 0x40,
++ RREVERB1 = 0x80,
++ RQUIET3 = 0x100,
++ RECT = 0x200,
++ RREVERB2 = 0x400,
++ RSEGUE1 = 0x800,
++ RREVERB3 = 0x1000,
++ RSEGUE2 = 0x2000,
++ RRATES1 = 0x4000,
++ RMSGS1 = 0x8000,
++ RMEDLEY = 0x10000,
++ RREVERB4 = 0x20000,
++ RSEGUE3 = 0x40000,
++ RMSGSRA = 0x80000,
++ RRATESRA = 0x100000,
++ RREVERBRA = 0x200000,
++ RSEGUERA = 0x400000,
++ RMSGS2 = 0x800000,
++ RRATES2 = 0x1000000,
++ RREVERB5 = 0x2000000,
++ RSEGUE4 = 0x4000000,
++ RBNG = 0x8000000,
++ RREVERB6 = 0x10000000,
++ RSHOWTIME = 0x20000000
++} DEV_HOST_stateBitField2_t; // this enum should only have 32 bit entries in it. Add another enum if you need more.
++
++// BitField3 for ADSL2 states
++// If more values need to be added, they will be added at the end (up to 32 total entries). However, if this causes
++// the state transitions to tick off out of normal bit order, then the C code will have to be re-written
++// that causes the proper values to be entered into the modem state bit fields.
++typedef enum
++{
++ ZERO_STATE3 = 0,
++ G2QUIET1 = 0x1,
++ G2COMB1 = 0x2,
++ G2QUIET2 = 0x4,
++ G2COMB2 = 0x8,
++ G2ICOMB1 = 0x10,
++ G2LINEPROBE = 0x20,
++ G2QUIET3 = 0x40,
++ G2COMB3 = 0x80,
++ G2ICOMB2 = 0x100,
++ G2RMSGFMT = 0x200,
++ G2RMSGPCB = 0x400,
++ G2REVERB1 = 0x800,
++ G2QUIET4 = 0x1000,
++ G2REVERB2 = 0x2000,
++ G2QUIET5 = 0x4000,
++ G2REVERB3 = 0x8000,
++ G2ECT = 0x10000,
++ G2REVERB4 = 0x20000,
++ G2SEGUE1 = 0x40000,
++ G2REVERB5 = 0x80000,
++ G2SEGUE2 = 0x100000,
++ G2RMSG1 = 0x200000,
++ G2MEDLEY = 0x400000,
++ G2EXCHANGE = 0x800000,
++ G2RMSG2 = 0x1000000,
++ G2REVERB6 = 0x2000000,
++ G2SEGUE3 = 0x4000000,
++ G2RPARAMS = 0x8000000,
++ G2REVERB7 = 0x10000000,
++ G2SEGUE4 = 0x20000000
++} DEV_HOST_stateBitField3_t; // this enum should only have 32 bit entries in it. Add another enum if you need more.
++
++// BitField4 for ADSL2 diag. states
++// If more values need to be added, they will be added at the end (up to 32 total entries). However, if this causes
++// the state transitions to tick off out of normal bit order, then the C code will have to be re-written
++// that causes the proper values to be entered into the modem state bit fields.
++typedef enum
++{
++ ZERO_STATE4 = 0,
++ GDSEGUE1 = 0x1,
++ GDREVERB5 = 0x2,
++ GDSEGUE2 = 0x4,
++ GDEXCHANGE = 0x8,
++ GDSEGUELD = 0x10,
++ GDRMSGLD = 0x20,
++ GDQUIET1LD = 0x40,
++ GDQUIET2LD = 0x80,
++ GDRACK1 = 0x100,
++ GDRNACK1 = 0x200,
++ GDQUIETLAST = 0x400
++} DEV_HOST_stateBitField4_t; // this enum should only have 32 bit entries in it. Add another enum if you need more.
++
++// This struct collects all of the bitfield types listed above for the modem state bit field(s)
++typedef struct
++{
++ DEV_HOST_stateBitField1_t bitField1; // this is the first modem state bit field (mostly init. and G.hs)
++ DEV_HOST_stateBitField2_t bitField2; // this is the second modem state bit field (T1.413 and G.dmt)
++ DEV_HOST_stateBitField3_t bitField3; // this is the third modem state bit field (ADSL2)
++ DEV_HOST_stateBitField4_t bitField4; // this is the fourth modem state bit field (ADSL2 diag.)
++} DEV_HOST_modemStateBitField_t;
++
++
++// -----------------------------------------------
++// Begin NegoPara message definitions - DSP write.
++// -----------------------------------------------
++
++typedef struct
++{
++ UINT8 trainMode; // Train mode selected. See training modes defined above.
++ UINT8 bDummy1; // dummy byte for explicit 32-bit alignment
++ UINT16 lineLength; // Contains loop length estimate. Accuracy w/i 500 ft. LSbit = 1 for straight loop, = 0 for bridge tap
++ UINT32 atucVendorId; // Pass the vendor id of the CO to the host
++ UINT8 cMsgs1[8]; // CMsgs1 and CMSGPCB
++ UINT16 adsl2DSRate; //
++ UINT8 cRates2; //
++ UINT8 rRates2; //
++ UINT8 rRates1[4][11]; //
++ UINT8 cMsgs2[4]; //
++ UINT8 cRates1[4][30]; //
++ UINT8 rMsgs2[4]; //
++ UINT16 adsl2USRate; //
++ UINT8 atucGhsRevisionNum; // Pass the G.hs Revision number of the CO to the host
++ UINT8 reserved1; //
++ PUINT8 *adsl2DeltMsgs_p; // This pointer to a pointer passes the address of the globalvar.pString, which is also
++ // a pointer list of pointers. It will be used to pass all the new ADSL2 DELT messages to
++ // host side. This is for ACT.
++} DEV_HOST_dspWrNegoParaDef_t;
++
++
++// ----------------------------------------------------
++// Begin OAM NegoPara message definitions - Host write.
++// ----------------------------------------------------
++
++// OAM Feature bit fields.
++//
++// Bit 0 - Enable auto retrain of modem
++// Bit 1 - Detect and report TC sync to host
++// Bit 2-31 - Reserved
++
++#define DEV_HOST_AUTORETRAIN_ON 0x00000001
++#define DEV_HOST_TC_SYNC_DETECT_ON 0x00000002
++
++#define DEV_HOST_AUTORETRAIN_MASK 0x00000001
++#define DEV_HOST_TC_SYNC_DETECT_MASK 0x00000002
++#define DEV_HOST_EOCAOC_INTERRUPT_MASK 0x00000004
++#define DEV_HOST_CONS_DISP_DISABLE_MASK 0x00000008
++#define DEV_HOST_GHSMSG_INTERRUPT_MASK 0x00000010
++
++typedef struct
++{
++ UINT8 stdMode; // Desired train mode. See training modes defined above.
++ UINT8 ghsSequence; // Selected G.hs session as shown in Appendix 1
++ UINT8 usPilotFlag; // Value of 1 indicates transmit an upstream pilot on bin 16
++ UINT8 bDummy1; // dummy byte for 32-bit alignment
++ UINT8 rMsgs1[38]; // RMSG-1(6) and RMSG_PCB (38)
++ UINT8 bDummy2[2]; // dummy bytes for 32-bit alignment
++ UINT32 oamFeature; // 32 bit wide bit field to set OAM-specific features.
++ SINT8 marginThreshold; // Threshold for margin reporting
++ UINT8 hostFixAgc; // flag to force datapump to bypass AGC training and use the following values
++ UINT8 hostFixEqualizer; // forced analog equalizer value used during AGC training when hostfix_agc is on
++ UINT8 hostFixPga1; // forced pga1 value used during AGC training when hostFixAgc is on
++ UINT8 hostFixPga2; // forced pga2 value used during AGC training when hostFixAgc is on
++ UINT8 hostFixPga3; // forced pga3 value used during AGC training when hostFixAgc is on
++ UINT8 marginMonitorShwtme; // margin monitoring flag (during showtime)
++ UINT8 marginMonitorTrning; // margin monitoring flag (during training)
++ UINT8 disableLosAlarm; // flag to disable training based on los
++ UINT8 usCrcRetrain; // flag to disable retrain due to excessive USCRC
++ UINT8 t1413VendorId[2]; // Vendor ID used for T1.413 trainings
++ UINT8 gdmtVendorId[8]; // Vendor ID used for G.dmt trainings (ITU VendorID)
++ UINT8 missingTones[64]; // 64 element array to define missing tones for TX_MEDLEY and TX REVERB tests
++ UINT32 missingToneDsAddr; // Address given to DSP for tones to be switched off in DS direction
++ UINT8 dsToneTurnoff_f; // This flag controls the DS tone turn off logic
++ UINT8 reserved1; // Dummy bytes
++ UINT8 reserved2; // Dummy bytes
++ UINT8 reserved3; // Dummy bytes
++} DEV_HOST_oamWrNegoParaDef_t;
++
++
++// ----------------------------------------
++// Begin Rate-adaptive message definitions.
++// ----------------------------------------
++
++// The four values below can never be changed (for host intf. backwards compatibility)
++#define DEV_HOST_RMSGSRA_LENGTH 10
++#define DEV_HOST_RRATESRA_LENGTH 1
++#define DEV_HOST_CRATESRA_LENGTH 120
++#define DEV_HOST_CMSGSRA_LENGTH 6
++
++typedef struct
++{
++ UINT8 rRatesRaString[DEV_HOST_RRATESRA_LENGTH+3];
++ UINT8 rMsgsRaString[DEV_HOST_RMSGSRA_LENGTH+2];
++ UINT8 cMsgsRaString[DEV_HOST_CMSGSRA_LENGTH+2];
++} DEV_HOST_raMsgsDef_t;
++
++
++// ----------------------------------------------
++// Begin superframe cnts definitions - DSP write.
++// ----------------------------------------------
++
++#define DEV_HOST_FRAMES_PER_SUPER 68
++#define DEV_HOST_SUPERFRAMECNTDSTRM 0
++#define DEV_HOST_SUPERFRAMECNTUSTRM 4
++
++// Although only the least significant 8 bits should be used as an
++// unsigned char for computing the bitswap superframe number, a
++// full 32 bit counter is provided here in order to have an
++// accurate indicator of the length of time that the modem has
++// been connected. This counter will overflow after 2.35 years
++// of connect time.
++
++typedef struct
++{
++ UINT32 wSuperFrameCntDstrm;
++ UINT32 wSuperFrameCntUstrm;
++} DEV_HOST_dspWrSuperFrameCntDef_t;
++
++
++// --------------------------------
++// Begin ATUR/ATUC msg definitions.
++// --------------------------------
++
++// Grouping used by the DSP to simplify parameter passing.
++// All of these are written by the DSP.
++
++typedef struct
++{
++ UINT16 vendorId; // TI's vendor ID = 0x0004; Amati's vendor ID = 0x0006
++ UINT8 versionNum; // T1.413 issue number
++ UINT8 rateAdapt; // 0 = fix rate (Default); 1= adaptive rate
++ UINT8 trellis; // 0 = disable trellis(default); 1 = enable trellis
++ UINT8 echoCancelling; // 0 = disable echo cancelling; 1 = enable echo cancelling(default)
++ UINT8 maxBits; // value range: 0-15; default = 15
++ UINT8 maxPsd; //
++ UINT8 actualPsd; //
++ UINT8 maxIntlvDepth; // 0, 1, 2, or 3 for 64, 128, 256, or 512 max depth
++ UINT8 framingMode; // 0 for asynchronous, 1 for synchronous full overhead
++ // 2 for reduced overhead, 3 for merged reduced overhead DSP write.
++ UINT8 maxFrameMode; // maximum framing mode desired. Nor 0 or 3.
++ SINT16 targetMargin; //
++ SINT16 maxAllowedMargin; //
++ SINT16 minRequiredMargin; //
++ SINT16 maxTotBits; //
++ UINT8 grossGain; //
++ UINT8 ntr; // Enable/disable NTR support
++ SINT16 loopAttn; // Loop Attenuation
++ UINT8 vendorRevisionNumber; // Reported Vendor Revision Number
++ UINT8 reserved1; // for 32-bit alignment
++ UINT8 reserved2; // for 32-bit alignment
++ UINT8 reserved3; // for 32-bit alignment
++} DEV_HOST_msg_t;
++
++
++// --------------------------------------
++// Begin bits and gains table definitions
++// --------------------------------------
++
++typedef struct
++{
++ PUINT8 aturBng_p; // pointer to ATU-R bits and gains table
++ PUINT8 atucBng_p; // pointer to ATU-C bits and gains table
++ PUINT8 bitAllocTblDstrm_p; // pointer to Downstream Bit Allocation table
++ PUINT8 bitAllocTblUstrm_p; // pointer to Upstream Bit Allocation table
++ PSINT8 marginTblDstrm_p; // pointer to Downstream Margin table
++} DEV_HOST_dspWrSharedTables_t;
++
++
++// ----------------------------------------
++// Begin datapump code overlay definitions.
++// ----------------------------------------
++
++#define DEV_HOST_PAGE_NUM 4 // number of overlay pages
++
++// Never access a struct of this typedef directly. Always go through the DEV_HOST_olayDpDef_t struct
++typedef struct
++{
++ UINT32 overlayHostAddr; // source address in host memory
++ UINT32 overlayXferCount; // number of 32bit words to be transfered
++ UINT32 overlayDspAddr; // destination address in DSP's PMEM
++} DEV_HOST_olayDpPageDef_t;
++
++
++typedef struct
++{
++ UINT32 overlayStatus; // Status of current overlay to DSP PMEM
++ UINT32 overlayNumber; // DSP PMEM overlay page number
++ UINT32 overlayState; // Indicates whether current state is an overlay state
++ DEV_HOST_olayDpPageDef_t *olayDpPage_p[DEV_HOST_PAGE_NUM]; // Def's for the Pages
++} DEV_HOST_olayDpDef_t;
++
++
++// -------------------------
++// Begin ATM-TC definitions.
++// -------------------------
++
++// TC cell states.
++typedef enum
++{
++ TC_HUNT,
++ TC_PRESYNC,
++ TC_SYNC
++} DEV_HOST_cellDelinState_t;
++
++
++// --------------------------------------------
++// Begin datapump error/statistics definitions.
++// --------------------------------------------
++
++// Never access a struct of this typedef directly. Always go through the DEV_HOST_modemStatsDef_t struct.
++typedef struct
++{
++ UINT32 crcErrors; // Num of CRC errored ADSL frames
++ UINT32 fecErrors; // Num of FEC errored (corrected) ADSL frames
++ UINT32 ocdErrors; // Out of Cell Delineation
++ UINT32 ncdError; // No Cell Delineation
++ UINT32 lcdErrors; // Loss of Cell Delineation (within the same connection)
++ UINT32 hecErrors; // Num of HEC errored ADSL frames
++} DEV_HOST_errorStats_t;
++
++
++typedef struct
++{
++ DEV_HOST_errorStats_t *usErrorStatsIntlv_p; // us error stats - interleave path
++ DEV_HOST_errorStats_t *dsErrorStatsIntlv_p; // ds error stats - interleave path
++ DEV_HOST_errorStats_t *usErrorStatsFast_p; // us error stats - fast path
++ DEV_HOST_errorStats_t *dsErrorStatsFast_p; // ds error stats - fast path
++ UINT32 losErrors; // Num of ADSL frames where loss-of-signal
++ UINT32 sefErrors; // Num of severly errored ADSL frames - LOS > MAXBADSYNC ADSL frames
++ UINT32 farEndLosErrors; // Number of reported LOS defects by the CO.
++ UINT32 farEndRdiErrors; // Number of reported RDI defects by the CO.
++} DEV_HOST_modemStatsDef_t;
++
++// Never access a struct of this typedef directly. Always go through the DEV_HOST_atmStats_t struct.
++typedef struct
++{
++ UINT32 goodCount; // Upstream Good Cell Count
++ UINT32 idleCount; // Upstream Idle Cell Count
++} DEV_HOST_usAtmStats_t;
++
++// Never access a struct of this typedef directly. Always go through the DEV_HOST_atmStats_t struct.
++typedef struct
++{
++ UINT32 goodCount; // Downstream Good Cell Count
++ UINT32 idleCount; // Downstream Idle Cell Count
++ UINT32 badHecCount; // Downstream Bad Hec Cell Count
++ UINT32 ovflwDropCount; // Downstream Overflow Dropped Cell Count
++ DEV_HOST_cellDelinState_t delineationState; // Indicates current delineation state
++} DEV_HOST_dsAtmStats_t;
++
++
++typedef struct
++{
++ DEV_HOST_usAtmStats_t *us0_p; // US ATM stats for TC channel 0
++ DEV_HOST_dsAtmStats_t *ds0_p; // DS ATM stats for TC channel 0
++ DEV_HOST_usAtmStats_t *us1_p; // US ATM stats for TC channel 1
++ DEV_HOST_dsAtmStats_t *ds1_p; // DS ATM stats for TC channel 1
++} DEV_HOST_atmStats_t;
++
++
++// ----------------------
++// Begin EOC definitions.
++// ----------------------
++
++// The two values below can never change (for backwards compatibility of host intf.)
++#define DEV_HOST_EOCREG4LENGTH 32
++#define DEV_HOST_EOCREG5LENGTH 32
++
++typedef struct
++{
++ UINT8 eocReg4[DEV_HOST_EOCREG4LENGTH]; // Host/Dsp Write, vendor specific EOC Register 4
++ UINT8 eocReg5[DEV_HOST_EOCREG5LENGTH]; // Host/Dsp Write, vendor specific EOC Register 5
++ UINT8 vendorId[8]; // Host write
++ UINT8 revNumber[4]; // Host, ATU-R Revision Number
++ UINT8 serialNumber[32]; // Host write
++ UINT8 eocReg4Length; // Host Write, valid length for EOC register 4
++ UINT8 eocReg5Length; // Host Write, valid length for EOC register 5
++ UINT8 dummy[2]; // dummy bytes for 32-bit alignment
++ UINT32 eocModemStatusReg; // Dsp Write, status bits to host
++ UINT8 lineAtten; // Dsp Write, line attenuation in 0.5 db step
++ SINT8 dsMargin; // DSP Write, measured DS margin
++ UINT8 aturConfig[30]; // Dsp Write, also used by EOC for ATUR Configuration
++} DEV_HOST_eocVarDef_t;
++
++typedef struct
++{
++ UINT16 endEocThresh; // Host Write, end of Clear EOC stream threshold
++ UINT16 dummy; // dummy value to fill gap
++ UINT32 dropEocCount; // Dsp Write, counter of dropped Clear EOC bytes
++ UINT16 eocRxLength; // Host/DSP write, number of valid Rx Clear EOC bytes
++ UINT16 eocTxLength; // Host/DSP write, number of valid Tx Clear EOC bytes
++ UINT8 eocRxBuf[64]; // Dsp Write, Buffer for receiving Rx Clear EOC bytes
++ UINT8 eocTxBuf[64]; // Host Write, Buffer for writing Tx Clear EOC bytes
++} DEV_HOST_clearEocVarDef_t;
++
++
++// -----------------------------------
++// Begin CO profile Definitions.
++// -----------------------------------
++
++/* struct size must be a word size */
++typedef struct
++{
++
++ SINT16 devCodecRxdf4Coeff[12] ; // (BOTH) IIR Coefficients
++ SINT16 devCodecTxdf2aCoeff[64] ; // (BOTH) FIR filter coefficients
++ SINT16 devCodecTxdf2bCoeff[64] ; // (BOTH) FIR filter coefficients
++ SINT16 devCodecTxdf1Coeff[12] ; // (BOTH) IIR filter coefficients
++ UINT16 devCodecTxDf2aDen; // (BOTH) denominator for IIR filter
++ UINT16 devCodecTxDf2bDen; // (BOTH) denominator for IIR filter
++ SINT16 ctrlMsmSpecGain[32]; // (BOTH)
++
++ SINT16 phyBitaRateNegIntNoTrellis ; // (BOTH) value to set
++ SINT16 phyBitaRateNegIntTrellis ; // (BOTH) value to set
++ SINT16 phyBitaRateNegFastNoTrellis ; // (BOTH) value to set
++ SINT16 phyBitaRateNegFastTrellis ; // (BOTH) value to set
++ SINT16 phyBitaRsFlag ; // (BOTH)
++ SINT16 phyBitaFirstSubChannel ; // (BOTH)
++ SINT16 phyBitaMaxFineGainBump; // max fine gain bump
++ SINT16 phyBitaFineGainReduction; // fine gain reduction
++ SINT16 phyBitaMaxDownstreamPowerCutback; // max downstream power cutback
++
++ SINT16 phySigTxGainReductionAt0kft; // upstream power reduction at 0 kft.
++
++ SINT16 phyAgcPgaTarget ; // (BOTH) compare value
++
++ UINT16 imsg413TxRate ; // (BOTH) Tx rate
++ SINT16 imsg413RsBytesAdjust ; // (BOTH) subtract value
++ UINT16 imsg413PstringMask ; // (POTS) Or'ed into pString[RMSGS1_INDEX][1]
++ SINT16 imsg413UsPilot ; // (BOTH)??
++ UINT16 imsg413SkipPhaseOp ; // (POTS)
++
++ UINT16 ctrlMsmSensitivity1 ; // (BOTH) value to set
++ UINT16 ctrlMsmTxPsdShape_f; // (BOTH) upstream spectral shaping flag
++
++ UINT16 ovhdAocUsBswapReq_f ; // (BOTH)value to set
++ UINT16 ovhdAocScanMse_f ; // (BOTH)value to set
++
++ SINT16 phyRevFullFirstBin ; //
++ SINT16 phyRevFullLastBin ; //
++ SINT16 phyRevFirstBin ; //
++ SINT16 phyRevLastBin ; //
++ SINT16 phyMedFirstBin ; //
++ SINT16 phyMedLastBin ; //
++ SINT16 phyMedOptionalLastBin; // Medley last bin - optional
++
++ SINT16 phyEcDelayAdjustment; // Echo delay adjustment
++ SINT16 bSwapThresholdUpdate; // bSwapThresholdUpdate
++ SINT16 phyBitaFastPathExcessFineGainBump; // Used in phy_bita.c
++ SINT16 phyBitaSkipGapAdjustment; // Used in phy_bita.c
++ SINT16 usPilotInT1413ModeInMedley; // To send Upstream Pilot in medley in T1.413 mode.
++
++ UINT32 profileVendorId ; // vendor id
++
++} DEV_HOST_coData_t ;
++
++typedef struct
++{
++ DEV_HOST_coData_t * hostProfileBase_p; // base address of profile list
++} DEV_HOST_profileBase_t ;
++
++
++
++// -----------------------------------
++// Begin DSP/Host Mailbox Definitions.
++// -----------------------------------
++
++// The 3 values below can never be decreased, only increased.
++// If you increase one of the values, you must add more to the
++// initializers in "dev_host_interface.c".
++#define DEV_HOST_HOSTQUEUE_LENGTH 8
++#define DEV_HOST_DSPQUEUE_LENGTH 8
++#define DEV_HOST_TEXTQUEUE_LENGTH 8
++
++// Never access a struct of this typedef directly. Always go through the DEV_HOST_mailboxControl_t struct.
++typedef struct
++{
++ UINT8 cmd;
++ UINT8 tag;
++ UINT8 param1;
++ UINT8 param2;
++} DEV_HOST_dspHostMsg_t;
++
++// Never access a struct of this typedef directly. Always go through the DEV_HOST_mailboxControl_t struct.
++typedef struct
++{
++ UINT32 msgPart1;
++ UINT32 msgPart2;
++} DEV_HOST_textMsg_t;
++
++// The structure below has been ordered so that the Host need only write to
++// even byte locations to update the indices.
++
++// The Buffer pointers in the struct below each point to a different
++// struct array that has an array size of one of the matching Queue Length
++// values defined above (DEV_HOST_HOSTQUEUE_LENGTH, DEV_HOST_DSPQUEUE_LENGTH,
++// and DEV_HOST_TEXTQUEUE_LENGTH).
++
++typedef struct
++{
++ UINT8 hostInInx; // Host write, DSP must never write except for init
++ UINT8 bDummy0[3]; // dummy bytes for explicit 32-bit alignment
++ UINT8 hostOutInx; // DSP write, Host must never write
++ UINT8 bDummy1[3]; // dummy bytes for explicit 32-bit alignment
++ UINT8 dspOutInx; // Host write, DSP must never write except for init
++ UINT8 bDummy2[3]; // dummy bytes for explicit 32-bit alignment
++ UINT8 dspInInx; // DSP write, Host must never write
++ UINT8 bDummy3[3]; // dummy bytes for explicit 32-bit alignment
++ UINT8 textInInx; // DSP write, Host must never write
++ UINT8 bDummy4[3]; // dummy bytes for explicit 32-bit alignment
++ UINT8 textOutInx; // Host write, DSP must never write except for init
++ UINT8 bDummy5[3]; // dummy bytes for explicit 32-bit alignment
++ DEV_HOST_dspHostMsg_t *hostMsgBuf_p; // pointer to Host Mailbox Buffer (Host writes the buffer)
++ DEV_HOST_dspHostMsg_t *dspMsgBuf_p; // pointer to DSP Mailbox Buffer (DSP writes the buffer)
++ DEV_HOST_textMsg_t *textMsgBuf_p; // pointer to Text Mailbox Buffer (DSP writes the buffer)
++} DEV_HOST_mailboxControl_t;
++
++
++//-----------------------------------------
++// Physical layer performance parameter
++//-----------------------------------------
++typedef struct
++{
++ SINT32 hybridCost[5]; // Cost functions for hybrids (0: none, 1-4 hybrid options)
++ SINT32 usAvgGain; // upstream average gain in 20log10 (Q8)
++ SINT32 dsAvgGain; // downstream average gain in 20log10 (Q8)
++ UINT8 disableDspHybridSelect_f; // Allows host to disable the automatic hybrid selection by the DSP
++ UINT8 hostSelectHybridNum; // DSP will use this hybrid number only if DSP Select is disabled (values: 1-4)
++ UINT8 currentHybridNumUsed; // DSP indicates to the host the current hybrid number in use
++ UINT8 reserved1; // reserved for future use
++} DEV_HOST_phyPerf_t;
++
++
++/***********************************************************
++ * The 3 structures below are used only for analog
++ * diagnostic functions originally defined in diag.h
++ * Moved here by Carlos A. Perez under J. Bergsagel request
++ ***********************************************************/
++
++/****************************************************************************/
++/* Options for the Analog Diagnostic user input data structure */
++/* (MUST be word aligned) */
++/****************************************************************************/
++typedef enum
++{
++ ZERO_DIAG_OPT = 0, // dummy value for zero place-holder
++ NOISE_ONLY = 0x1, // diagnostic in noise only mode (on=1, off=0), disregard diagMode 0-4
++ EXTERNAL_CO = 0x2, // operates against external CO (external=1, internal=0)
++ DIAG_AGC = 0x4, // agc selects gains control (agc=1, manual=0)
++ CROSSTALK_TEQ = 0x8, // crosstalk selects teq (crosstalk=1, manual=0)
++ LEAKY_TEQ = 0x10, // use leaky teq (on=1, off=0)
++ AUX_AMPS = 0x20, // auxamps (on=1, off=0)
++ BW_SELECT = 0x40, // change rxhpf/txlpf fc (modify=1, default=0)
++ DIAG_HYB_SELECT = 0x80, // change hybrid (modify=1, default=0)
++ POWER_DOWN_CDC = 0x100, // power down codec (power down=1, no power down=0)
++ ISDN_OP_MODE = 0x200, // operation mode (pots=0, isdn=1)
++ BYPASS_RXAF2 = 0x400, // Bypass except RXAF2 (on=1, off = 0)
++ TX_TEST_CONT = 0x800, // Continuous tx test (on=1, off=0)
++ TX_SCALE_MTT = 0x1000 // Scale tx signal for Mtt test (on=1, off=0)
++} DEV_HOST_diagAnlgOptionsVar_t;
++
++/****************************************************************************/
++/* Analog Diagnostic user input data structure (MUST be word align) */
++/****************************************************************************/
++
++typedef struct
++{
++ DEV_HOST_diagAnlgOptionsVar_t diagOption; // Other diagnostic optional settings
++
++ UINT8 diagMode; // Performance diagnostic mode
++ UINT8 txMode; // transmit mode
++ UINT8 rxMode; // receive mode
++ UINT8 teqSp; // Select teq starting pt
++ UINT8 txDf1; // see dev_codec_filters.c and
++ UINT8 txDf2a; // dev_codec.h for filter coefficients
++ UINT8 txDf2b;
++ UINT8 rxDf4;
++
++ UINT16 codingGain256Log2; // 256*Log2(coding gain)
++ UINT16 noiseMargin256Log2; // 256*Log2(noise margin)
++
++ UINT16 rxPga1; // PGA1
++ UINT16 rxPga2; // PGA2
++ UINT16 rxPga3; // PGA3
++ UINT16 anlgEq; // AEQ settings (dB/MHz)
++
++ SINT8 pilotBin; // Select pilot subchannel
++ SINT8 txSwGain; // manual set for bridge tap loop
++ SINT8 tdw1Len; // TDW1 length - 0,2,4,8,16
++ SINT8 tdw2Len; // TDW2 length - 0,2,4,8,16
++
++ UINT8 teqEcMode; // TEQ/EC mode
++ UINT8 hybrid;
++ UINT8 txAttn; // Codec Tx attenuation
++ UINT8 txGain; // Codec Tx gain (Sangam only)
++
++ SINT16 txPda; //Codec Tx Digital gain/attn
++ UINT8 txTone[MAX_NUM_UPBINS]; // Turning tones on/off
++ // Still govern by lastbin
++ UINT16 rsvd; //for 32 bits alignment
++}DEV_HOST_diagAnlgInputVar_t;
++
++/****************************************************************************/
++/* Analog diagnostic output data structure */
++/****************************************************************************/
++typedef struct
++{
++ PSINT32 rxSnr_p[2]; // Pointer to estimated snr
++ PSINT32 rxSubChannelCapacity_p[2]; // Pointer to estimated subchan capacity
++ PSINT32 rxSignalPower_p[2]; // Pointer to estimated signal power
++ PSINT32 rxNoisePower_p[2]; // Pointer to estimated noise power
++ PSINT32 rxAvg_p; // Pointer to average of rcvd signal
++ SINT32 chanCapacity[2] ; // Channel total capacity
++ SINT32 dataRate[2]; // Modem data rate (SNR)
++ SINT32 avgNoiseFloor; // Average noise floor
++ SINT16 snrGap256Log2; // 256*Log2(snr gap)
++ SINT16 rxPga1; // PGA1
++ SINT16 rxPga2; // PGA2
++ SINT16 rxPga3; // PGA3
++ SINT16 anlgEq; // AEQ settings (dB/MHz)
++ SINT16 rsvd;
++}DEV_HOST_diagAnlgOutputVar_t;
++
++
++// Bit field structure that allows the host to mask off interrupt sources for possible DSP-to-Host interrupts.
++// Each bit represents a possible source of interrupts in the DSP code that might cause a DSP-to-Host
++// interrupt to occur.
++// This mask structure is not intended to show how interrupt sources in the DSP code correspond to the actual
++// DSP-to-Host interrupts. There could be multiple ways to cause an interrupt in the DSP code, but they all
++// eventually tie into one of the three possible DSP-to-Host interrupts.
++// The host should write a "1" to an individual bit when it wants to mask possible interrupts from that source.
++
++// enum that represents individual bits in maskBitField1
++typedef enum
++{
++ ZERO_MASK1 = 0, // dummy value for zero place-holder
++ DSP_MSG_BUF = 0x1, // mask interrupts due to DSP-to-Host message mailbox updates
++ STATE_BIT_FIELD = 0x2, // mask interrupts due to changes in the modem state bit fields
++ DSP_HEARTBEAT = 0x4 // mask interrupts for the DSP hearbeat
++} DEV_HOST_intMask1_t; // this enum should only have 32 values in it (maximum).
++
++// Add more "mask bit fields" at the end of this struct if you need more mask values
++typedef struct
++{
++ DEV_HOST_intMask1_t maskBitField1;
++} DEV_HOST_hostInterruptMask_t; // this struct should only have 32 bits in it.
++
++// Bit field structure that allows the host to determine the source(s) of DSP-to-Host interrupts in case
++// several of the interrupt sources get combined onto a single DSP-to-Host interrupt.
++// DSP will set each bit to a "1"as an interrupt occurs.
++// Host has the reponsibility to clear each bit to a "0" after it has determined the source(s) of interrupts.
++// Each source bit field in this struct will use the same enum typedef that matches the corresponding mask
++// bit field in "DEV_HOST_hostInterruptMask_t"
++typedef struct
++{
++ DEV_HOST_intMask1_t sourceBitField1;
++} DEV_HOST_hostInterruptSource_t;
++
++
++// --------------------------
++// Begin bitswap definitions.
++// --------------------------
++
++// bitSwapSCnt contains the superframe to perform bit swap
++// The entries must be ordered so that the first group only contains bit change commands
++// The other entries may contain power adjustment instructions and must be
++// written with something. NOP (0) is an available instruction.
++typedef struct
++{
++ PUINT8 fineGains_p; // pointer to bng string, needed to check fine gains for powerswap
++ UINT8 bitSwapNewIndices[6]; // Bin before bitSwapBin to process
++ UINT8 bitSwapCmd[6]; // Bitswap command for bitSwapBin
++ UINT8 bitSwapBin[6]; // bin to modify
++ UINT8 bitSwapSCnt; // Superframe count on which to perform bitswap
++ UINT8 bitSwapEnabled; // bitSwapEnabled
++} DEV_HOST_dspBitSwapDef_t;
++
++
++// ---------------------------
++// Begin ATM BERT definitions.
++// ---------------------------
++
++// Structure used for ATM Idle Cells based bit error rate computation.
++typedef struct
++{
++ UINT8 atmBertFlag; // Feature enable/disable flag (Host write)
++ UINT8 dummy1;
++ UINT8 dummy[2]; // Dummy bytes for 32-bit alignment
++ UINT32 bitCountLow; // Low part of 64-bit BERT bit count (DSP write)
++ UINT32 bitCountHigh; // High part of 64-bit BERT bit count (DSP write)
++ UINT32 bitErrorCountLow; // Low part of 64-bit BERT bit count (DSP write)
++ UINT32 bitErrorCountHigh;// High part of 64-bit BERT bit count (DSP write)
++} DEV_HOST_atmDsBert_t;
++
++
++// ------------------------------------
++// Misc. modem environment definitions.
++// ------------------------------------
++
++
++typedef struct
++{
++ SINT16 subStateIndex; // Index that signifies datapump substate. (DSP write)
++ UINT8 externalBert; // Turn on/off external BERT interface. 0 = OFF; 1 = ON. (Host write)
++ UINT8 usBertPattern; // BERT pattern for US TX data. 0 = 2^15-1; 1 = 2^23-1. (Host write)
++ UINT8 overrideDslLinkLed_f; // Overrides DSP operation of the DSL_LINK LED. (Host write)
++ // 0 = DSP is in control; 1 = Host is in control.
++ UINT8 dslLinkLedState_f; // DSL_LINK LED state when override flag has been set. (Host write)
++ // DSL_LINK LED will be updated with this value once per frame.
++ // LED is active-low: 0 = ON, 1 = OFF.
++ UINT8 overrideDslActLed_f; // Overrides DSP operation of the DSL_ACT LED. (Host write)
++ // 0 = DSP is in control; 1 = Host is in control.
++ UINT8 dslActLedState_f; // DSL_ACT LED state when override flag has been set. (Host write)
++ // DSL_ACT LED will be updated with this value once per frame.
++ // LED is active-low: 0 = ON, 1 = OFF.
++ UINT8 dGaspLprIndicator_f; // How LPR signal (GPIO[0]) is to be interpreted. (Host write)
++ // 0 = LPR is active-low; 1 = LPR is active-high.
++ UINT8 overrideDspLprGasp_f; // Overrides DSP detection of LPR signal to send out DGASP. (Host write)
++ // 0 = DSP detects LPR; 1 = Host detects LPR and sends "HOST_DGASP" to DSP.
++ UINT8 pcbEnabled; // DS power cut back
++ UINT8 maxAvgFineGainCtrl_f; // If maxAvgFineGainCtrl_f == 0, then the datapump controls the maximum average fine gain value.
++ // If maxAvgFineGainCtrl_f == 1, then the host controls the maximum average fine gain value.
++ UINT32 reasonForDrop; // This field will tell the host what might be the reason for a dropped connection.
++ SINT16 maxAverageFineGain; // When maxAvgFineGainCtrl_f == 1, the value in maxAverageFineGain is the maximum average fine gain level in 256log2 units.
++ UINT8 reserved1; // These are for 32-bit alignment.
++ UINT8 reserved2; // These are for 32-bit alignment.
++} DEV_HOST_modemEnvPublic_t;
++
++
++// -----------------------------
++// Generic structure definition.
++// -----------------------------
++
++typedef struct
++{
++ PSINT8 parameter1_p;
++ PSINT16 parameter2_p;
++ PSINT32 parameter3_p;
++ PUINT8 parameter4_p;
++ PUINT16 parameter5_p;
++ PUINT32 parameter6_p;
++} DEV_HOST_genericStructure_t;
++
++
++// ------------------------------
++// Begin G.hs buffer definitions.
++// ------------------------------
++
++typedef struct
++{
++ UINT8 txBuf[64]; // G.hs xmt buffer
++} DEV_HOST_ghsDspTxBufDef_t;
++
++
++typedef struct
++{
++ UINT8 rxBuf[80]; // G.hs rcv buffer
++} DEV_HOST_ghsDspRxBufDef_t;
++
++// -----------------------------------------
++// Begin Constellation Display definitions.
++// -----------------------------------------
++
++typedef struct
++{
++ UINT32 consDispStartAddr; // Host write
++ UINT32 consDispCurrentAddr; // Host write
++ UINT32 consDispBufLen; // Constellation Buffer Length
++ UINT32 consDispBin; // Host write, DS band only
++} DEV_HOST_consBufDef_t;
++
++typedef struct
++{
++ PSINT16 buffer1_p; //DSP write
++ PSINT16 buffer2_p; //DSP write
++} DEV_HOST_snrBuffer_t;
++
++// --------------------------------------------------------------------------------------
++// Typedef to be used for the DEV_HOST_dspOamSharedInterface_s struct of pointers
++// (this is used in dev_host_interface.c).
++// NOTE: This struct of pointers is NEVER to be referenced anywhere else in the DSP code.
++// IMPORTANT: Only pointers to other structs go into this struct !!
++// --------------------------------------------------------------------------------------
++typedef struct
++{
++ DEV_HOST_hostIntfcVersionDef_t *hostIntfcVersion_p;
++ DEV_HOST_dspVersionDef_t *datapumpVersion_p;
++ DEV_HOST_modemStateBitField_t *modemStateBitField_p;
++ DEV_HOST_dspWrNegoParaDef_t *dspWriteNegoParams_p;
++ DEV_HOST_oamWrNegoParaDef_t *oamWriteNegoParams_p;
++ DEV_HOST_raMsgsDef_t *raMsgs_p;
++ DEV_HOST_dspWrSuperFrameCntDef_t *dspWriteSuperFrameCnt_p;
++ DEV_HOST_msg_t *atucMsg_p;
++ DEV_HOST_msg_t *aturMsg_p;
++ DEV_HOST_dspWrSharedTables_t *dspWrSharedTables_p;
++ DEV_HOST_olayDpDef_t *olayDpParms_p;
++ DEV_HOST_eocVarDef_t *eocVar_p;
++ DEV_HOST_clearEocVarDef_t *clearEocVar_p;
++ DEV_HOST_modemStatsDef_t *modemStats_p;
++ DEV_HOST_atmStats_t *atmStats_p;
++ DEV_HOST_mailboxControl_t *dspHostMailboxControl_p;
++ DEV_HOST_phyPerf_t *phyPerf_p;
++ DEV_HOST_diagAnlgInputVar_t *analogInputVar_p;
++ DEV_HOST_diagAnlgOutputVar_t *analogOutputVar_p;
++ DEV_HOST_hostInterruptMask_t *hostInterruptMask_p;
++ DEV_HOST_profileBase_t *profileList_p;
++ DEV_HOST_hostInterruptSource_t *hostInterruptSource_p;
++ DEV_HOST_dspBitSwapDef_t *dspBitSwapDstrm_p;
++ DEV_HOST_dspBitSwapDef_t *dspBitSwapUstrm_p;
++ DEV_HOST_atmDsBert_t *atmDsBert_p;
++ DEV_HOST_modemEnvPublic_t *modemEnvPublic_p;
++ DEV_HOST_genericStructure_t *genericStructure1_p;
++ DEV_HOST_genericStructure_t *genericStructure2_p;
++ DEV_HOST_ghsDspTxBufDef_t *ghsDspTxBuf_p;
++ DEV_HOST_ghsDspRxBufDef_t *ghsDspRxBuf_p;
++ DEV_HOST_consBufDef_t *consDispVar_p;
++ DEV_HOST_snrBuffer_t *snrBuffer_p;
++} DEV_HOST_dspOamSharedInterface_t;
++
++
++// ---------------------------------------------------------------------------------
++// Typedef to be used for the pointer to the DEV_HOST_dspOamSharedInterface_s struct
++// of pointers (this is used in dev_host_interface.c).
++// ---------------------------------------------------------------------------------
++typedef DEV_HOST_dspOamSharedInterface_t *DEV_HOST_dspOamSharedInterfacePtr_t;
++
++#endif
+diff -urN linux.old/drivers/atm/sangam_atm/dev_host_verdef.h linux.dev/drivers/atm/sangam_atm/dev_host_verdef.h
+--- linux.old/drivers/atm/sangam_atm/dev_host_verdef.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/dev_host_verdef.h 2005-08-23 04:46:50.091844608 +0200
+@@ -0,0 +1,102 @@
++#ifndef __DEV_HOST_VERDEF_H__
++#define __DEV_HOST_VERDEF_H__ 1
++
++//********************************************************************
++//*
++//* DMT-BASE ADSL MODEM PROGRAM
++//* TEXAS INSTRUMENTS PROPRIETARTY INFORMATION
++//* AMATI CONFIDENTIAL PROPRIETARY
++//*
++//* (c) Copyright April 1999, Texas Instruments Incorporated.
++//* All Rights Reserved.
++//*
++//* Property of Texas Instruments Incorporated and Amati Communications Corp.
++//*
++//* Restricted Rights - Use, duplication, or disclosure is subject to
++//* restrictions set forth in TI's and Amati program license agreement and
++//* associated documentation
++//*
++//*********************************************************************
++//*
++//* FILENAME: dev_host_verdef.h
++//*
++//* ABSTRACT: This file defines the version structure
++//*
++//* TARGET: Non specific.
++//*
++//* TOOLSET: Non specific.
++//*
++//* ACTIVATION:
++//*
++//* HISTORY: DATE AUTHOR DESCRIPTION
++//* 04/29/99 FLW Created
++//* 01/17/00 Barnett Mod's in support of merging NIC
++//* hardware rev 6/7 T1.413 codebases.
++//* 01/21/00 Wagner derfmake mods
++//* 05/11/00 Barnett hardware_rev is a 2 char string.
++//* 07/24/00 Barnett Rework as part of host interface redesign.
++//* 11/29/00 Hunt added chipset_id2
++//* 03/30/01 Barnett Prefixed all public elements with DSPDP_.
++//* This insures uniqueness of names that might
++//* match host names by coincidence.
++//* 03/30/01 Barnett Added DSPDP_Host_VersionDef to facilitate
++//* representing a version id for the host i/f
++//* separate from the firmware version id as
++//* a courtesy to the host.
++//* 07/23/01 JEB Changed name from verdef_u.h to dpsys_verdef.h
++//* 04/12/02 Barnett Make timestamp unsigned 32-bit field.
++//* Generalizes for all kinds of hosts.
++//* 11/15/02 JEB Changed name from dpsys_verdef.h to dev_host_verdef.h
++//* Updated structs according to coding guidelines
++//* 12/16/02 JEB Renamed some struct elements for new usage in Ax7
++//* 01/21/03 MCB Implemented Ax7 UNIT-MODULE modular software framework.
++//* 03/19/03 JEB Added back in "bugFix" elements into each struct type.
++//* Rearranged elements.
++//*
++//********************************************************************
++
++#include "env_def_typedefs.h"
++
++#define DSPDP_FLAVOR_NEWCODES 0xFF // Other values are valid old-style flavors
++
++// ------------------------------
++// ------------------------------
++// Begin DSP version definitions.
++// ------------------------------
++// ------------------------------
++
++typedef struct
++{
++ UINT32 timestamp; // Number of seconds since 01/01/1970
++ UINT8 major; // Major "00".00.00.00 revision nomenclature
++ UINT8 minor; // Minor 00."00".00.00 revision nomenclature
++ UINT8 bugFix; // Bug Fix 00.00."00".00 revision nomenclature
++ UINT8 buildNum; // Build Number 00.00.00."00" revision nomenclature
++ UINT8 netService; // Network service identifier
++ UINT8 chipsetGen; // chipset generation
++ UINT8 chipsetId; // chipset identifier
++ UINT8 chipsetId2; // second byte for "RV" chipset et al.
++ UINT8 hardwareRev1; // hardware revision, 1st char
++ UINT8 hardwareRev2; // hardware revision, 2nd char
++ UINT8 featureCode; // feature code
++ UINT8 dummy1; // dummy byte for explicit 32-bit alignment
++} DEV_HOST_dspVersionDef_t;
++
++// -------------------------------
++// -------------------------------
++// Begin host version definitions.
++// -------------------------------
++// -------------------------------
++
++typedef struct
++{
++ UINT8 major; // Major "00".00.00.00 revision nomenclature
++ UINT8 minor; // Minor 00."00".00.00 revision nomenclature
++ UINT8 bugFix; // Bug Fix 00.00."00".00 revision nomenclature
++ UINT8 buildNum; // Build Number 00.00.00."00" revision nomenclature
++ UINT8 netService; // Network service identifier
++ UINT8 dummy[3]; // dummy bytes for explicit 32-bit alignment
++} DEV_HOST_hostIntfcVersionDef_t;
++
++
++#endif // __DEV_HOST_VERDEF_H__
+diff -urN linux.old/drivers/atm/sangam_atm/dsl_hal_api.c linux.dev/drivers/atm/sangam_atm/dsl_hal_api.c
+--- linux.old/drivers/atm/sangam_atm/dsl_hal_api.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/dsl_hal_api.c 2005-08-23 04:46:50.095844000 +0200
+@@ -0,0 +1,3339 @@
++/*******************************************************************************
++* FILE PURPOSE: DSL Driver API functions for Sangam
++*
++********************************************************************************
++* FILE NAME: dsl_hal_basicapi.c
++*
++* DESCRIPTION:
++* Contains basic DSL HAL APIs for Sangam
++*
++*
++* (C) Copyright 2001-02, Texas Instruments, Inc.
++* History
++* Date Version Notes
++* 06Feb03 0.00.00 RamP Original Version Created
++* 10Mar03 0.00.01 RamP Initial Revision for Modular Code Branch
++* 19Mar03 0.00.02 RamP Fixed DSL and DSP Version API Structures
++* 20Mar03 0.00.03 RamP Changed byteswap function names
++* 21Mar03 0.00.03 RamP/ZT Malloc for DSP f/w done in dslStartup
++* 25Mar03 0.00.04 RamP Removed statistics used only by SWTC
++* Created Checkpoint 3
++* 26Mar03 0.00.05 RamP Added Memory allocation for fwimage in
++* dslStartup function.
++* 07Apr03 0.00.06 RamP Implemented new error reporting scheme
++* Changed Commenting to C style only
++* 09Apr03 0.00.07 RamP Reorganized code to delete POST_SILICON
++* 10Apr03 0.00.08 RamP Removed ptidsl from loadFWImage function
++* moved size and fwimage initialization to
++* dslStartup function
++* 14Apr03 0.00.09 RamP Moved modemStateBitField processing to a
++* support function; deleted stateHistory
++* renamed the REG32 macro
++* 15Apr03 0.00.10 RamP Changed firmware allocate to shim_
++* osAllocateVMemory function
++* 15Apr03 0.00.11 RamP Changed host version number to 07.00.00.01
++* 16Apr03 0.00.12 RamP Modified return condition on dslShutdown
++* 16Apr03 0.00.13 RamP Changed host version number to 07.00.00.02
++* 21Apr03 0.01.00 RamP Cleaned up dslShutdown function
++* Added new function calls to allocate
++* (Alpha) /free overlay pages for different OS
++* Fixed typecasting for allocate/free fxns
++* Added Interrupt Acknowledge logic
++* 22Apr03 0.01.01 RamP Moved acknowledgeInterrupt into api
++* Added static global for intr source
++* 24Apr03 0.01.02 RamP Added processing for OVERLAY_END in
++* DSP message handlers, verified crc32
++* recovery for overlays
++* 28Apr03 0.01.03 RamP Removed global variable intrSource
++* Added parameter to handleInterrupt fxn
++* (Alpha Plus) to indicate interrupt source
++* Changed version number to 01.00.01.00
++* Fixed setTrainingMode function problem
++* 07May03 0.01.04 RamP Removed delineation state check in
++* message handling functions, added more
++* safety for setting lConnected in TC_SYNC
++* Changed version number to 01.00.01.01
++* 14May03 0.01.05 RamP Added 3 Switchable Hybrid APIs
++* Added additional statistics us/ds TxPower,
++* us margin,attenuation, us/ds bitallocation
++* moved versioning to dsl_hal_version.h
++* 14May03 0.01.06 RamP Fixed problem with CMsgs2 parsing
++* 20May03 0.01.07 RamP Added Inner/Outer pair API support. Added
++* dying gasp message.
++* 29May03 0.01.08 ZT/RamP Added memory optimizations for overlay pages
++* and coProfiles; added functions to free,
++* reload overlays and profiles
++* 04Jun03 0.01.09 RamP Added tick counters, fail states reporting
++* Made statistics fixes for higher data rates
++* Added Margin per tone to statistics
++* Added configuration checks for trellis/FEC
++* 06Jun03 0.01.10 RamP Added LED, STM Bert, dGasp LPR Config APIs
++* Modified interrupt acknowledge logic
++* Added current hybrid flag as statistic
++* 09Jun03 0.01.11 RamP Added function to send dying Gasp to Modem
++* fixed problem with reading OamNegoPara var
++* (Beta) fixed problem with reading current config
++* Added function to configure ATM Bert
++* fixed memory leak due to coProfiles
++* Added us/ds R/S FEC statistics
++* Added additional config capability for LED
++* fixed problem in free memory for CO profiles
++* 18Jul03 0.01.12 RamP Fixed problem with reading modemEnv structure
++* affects LED, DGaspLpr APIs
++* Sending Dying Gasp from shutdown function
++* 01Aug03 0.01.13 RamP Added preferred training mode to statistics
++* 13Aug03 0.01.14 MCB Set rev id for D3/R1.1 (ADSL2).
++* 21Aug03 0.01.15 RamP Added g.hs and aoc bitswap message gathering
++* Added new references to bits n gains table
++* Decoupled modem idle/retrain from pair select
++* Added line length and gross gain to statistics
++* 29Sep03 0.01.16 RamP Replaced advcfg function calls with support
++* module function switches
++* 01Oct03 0.01.17 RamP Added enum translation to set training mode
++* & to read statistics
++* 08Oct03 0.01.18 RamP Fixed problems with usTxPower statistic in
++* Annex B target, fixed problem with Trellis
++* 12Oct03 0.01.19 RamP Added API calls to gather ADSL2 Messages
++* 29Oct03 0.01.20 RamP Restored TC_SYNC detect logic
++* 30Oct03 0.01.21 RamP Removed Scaling factor for adsl2DSConRate
++* Setting Showtime state upon DSP_ACTIVE
++* 14Nov03 0.01.22 RamP Fixed scaling for usTxPower & dsTxPower
++* 14Nov03 0.01.23 RamP Added logic to gather CRates1/RRates1
++* by parsing DSP_CRATES1
++* 20Nov03 0.01.24 RamP Added generic & interface Read
++* and Write functions to read from
++* DSP - Host Interface
++* 24Nov03 0.01.25 RamP Modified interface Read/Write functions
++* to seperate element offsets from pointers
++* 19Dec03 0.01.26 RamP Modified pointer accessing problems with
++* block read functions
++* 26Dec03 0.01.27 RamP Made ghsIndex a local variable & added
++* check to avoid buffer overflow
++* 30Dec03 0.01.28 RamP Added generic mailbox command function
++*******************************************************************************/
++#include "dsl_hal_register.h"
++#include "dsl_hal_support.h"
++#include "dsl_hal_logtable.h"
++#include "dsl_hal_version.h"
++
++static unsigned int hybrid_selected;
++static unsigned int showtimeFlag = FALSE;
++
++#ifdef PRE_SILICON
++/*********************************************/
++/* Base Addresses */
++/*********************************************/
++#define DEV_MDMA_BASE 0x02000500
++
++/*********************************************/
++/* MC DMA Control Registers in DSL */
++/*********************************************/
++
++#define DEV_MDMA0_SRC_ADDR (DEV_MDMA_BASE + 0x00000000)
++#define DEV_MDMA0_DST_ADDR (DEV_MDMA_BASE + 0x00000004)
++#define DEV_MDMA0_CTL_ADDR (DEV_MDMA_BASE + 0x00000008)
++#define DEV_MDMA1_SRC_ADDR (DEV_MDMA_BASE + 0x00000040)
++#define DEV_MDMA1_DST_ADDR (DEV_MDMA_BASE + 0x00000044)
++#define DEV_MDMA1_CTL_ADDR (DEV_MDMA_BASE + 0x00000048)
++#define DEV_MDMA2_SRC_ADDR (DEV_MDMA_BASE + 0x00000080)
++#define DEV_MDMA2_DST_ADDR (DEV_MDMA_BASE + 0x00000084)
++#define DEV_MDMA2_CTL_ADDR (DEV_MDMA_BASE + 0x00000088)
++#define DEV_MDMA3_SRC_ADDR (DEV_MDMA_BASE + 0x000000C0)
++#define DEV_MDMA3_DST_ADDR (DEV_MDMA_BASE + 0x000000C4)
++#define DEV_MDMA3_CTL_ADDR (DEV_MDMA_BASE + 0x000000C8)
++
++#define DEV_MDMA0_SRC (*((volatile UINT32 *) DEV_MDMA0_SRC_ADDR))
++#define DEV_MDMA0_DST (*((volatile UINT32 *) DEV_MDMA0_DST_ADDR))
++#define DEV_MDMA0_CTL (*((volatile UINT32 *) DEV_MDMA0_CTL_ADDR))
++#define DEV_MDMA1_SRC (*((volatile UINT32 *) DEV_MDMA1_SRC_ADDR))
++#define DEV_MDMA1_DST (*((volatile UINT32 *) DEV_MDMA1_DST_ADDR))
++#define DEV_MDMA1_CTL (*((volatile UINT32 *) DEV_MDMA1_CTL_ADDR))
++#define DEV_MDMA2_SRC (*((volatile UINT32 *) DEV_MDMA2_SRC_ADDR))
++#define DEV_MDMA2_DST (*((volatile UINT32 *) DEV_MDMA2_DST_ADDR))
++#define DEV_MDMA2_CTL (*((volatile UINT32 *) DEV_MDMA2_CTL_ADDR))
++#define DEV_MDMA3_SRC (*((volatile UINT32 *) DEV_MDMA3_SRC_ADDR))
++#define DEV_MDMA3_DST (*((volatile UINT32 *) DEV_MDMA3_DST_ADDR))
++#define DEV_MDMA3_CTL (*((volatile UINT32 *) DEV_MDMA3_CTL_ADDR))
++
++/* MDMA control bits */
++
++#define DEV_MDMA_START 0x80000000
++#define DEV_MDMA_STOP 0x00000000
++#define DEV_MDMA_STATUS 0x40000000
++#define DEV_MDMA_DST_INC 0x00000000
++#define DEV_MDMA_DST_FIX 0x02000000
++#define DEV_MDMA_SRC_INC 0x00000000
++#define DEV_MDMA_SRC_FIX 0x00800000
++#define DEV_MDMA_BURST1 0x00000000
++#define DEV_MDMA_BURST2 0x00100000
++#define DEV_MDMA_BURST4 0x00200000
++
++#define DEV_MDMA_LEN_SHF 2
++#define DEV_MDMA_LEN_MASK 0x0000FFFF
++
++#define DMA0 0
++#define DMA1 1
++#define DMA2 2
++#define DMA3 3
++#endif
++#ifdef DMA
++SINT32 getDmaStatus(UINT32 mask)
++{
++ if(!(IFR & mask))
++ {
++ return DSLHAL_ERROR_NO_ERRORS;
++ }
++ else
++ {
++ ICR = mask ;
++ return 1 ;
++ }
++}
++
++void programMdma(UINT32 dma, UINT32 source, UINT32 destination, UINT32 length, UINT32 wait)
++{
++ volatile UINT32 statusMask ;
++
++ switch(dma)
++ {
++ case DMA0:
++ {
++ DEV_MDMA0_SRC = source ;
++ DEV_MDMA0_DST = destination ;
++ DEV_MDMA0_CTL = (DEV_MDMA_START | DEV_MDMA_DST_INC | DEV_MDMA_SRC_INC |
++ DEV_MDMA_BURST1 | (length << DEV_MDMA_LEN_SHF)) ;
++ statusMask = 0x00000010 ;
++ }
++ break ;
++ case DMA1:
++ {
++ DEV_MDMA1_SRC = source ;
++ DEV_MDMA1_DST = destination ;
++ DEV_MDMA1_CTL = (DEV_MDMA_START | DEV_MDMA_DST_INC | DEV_MDMA_SRC_INC |
++ DEV_MDMA_BURST1 | (length << DEV_MDMA_LEN_SHF)) ;
++ statusMask = 0x00000020 ;
++ }
++ break ;
++ case DMA2:
++ {
++ DEV_MDMA2_SRC = source ;
++ DEV_MDMA2_DST = destination ;
++ DEV_MDMA2_CTL = (DEV_MDMA_START | DEV_MDMA_DST_INC | DEV_MDMA_SRC_INC |
++ DEV_MDMA_BURST1 | (length << DEV_MDMA_LEN_SHF)) ;
++ statusMask = 0x00000040 ;
++ }
++ break ;
++ case DMA3:
++ {
++ DEV_MDMA3_SRC = source ;
++ DEV_MDMA3_DST = destination ;
++ DEV_MDMA3_CTL = (DEV_MDMA_START | DEV_MDMA_DST_INC | DEV_MDMA_SRC_INC |
++ DEV_MDMA_BURST1 | (length << DEV_MDMA_LEN_SHF)) ;
++ statusMask = 0x00000080 ;
++ }
++ break ;
++
++ }
++
++ if(wait)
++ {
++ while(!(getDmaStatus(statusMask))) ;
++ }
++
++}
++#endif
++
++
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_dslStartup
++*
++*******************************************************************************************
++* DESCRIPTION: Entry point to initialize and load ax5 daughter board
++*
++* INPUT: PITIDSLHW_T *ppIHw
++*
++* RETURN: 0 --succeeded
++* 1 --Failed
++*
++*****************************************************************************************/
++
++int dslhal_api_dslStartup(PITIDSLHW_T *ppIHw)
++{
++
++ ITIDSLHW_T *ptidsl;
++ int i;
++ int rc;
++ dprintf(4,"dslhal_api_dslStartup() NEW 1\n");
++
++ ptidsl=(ITIDSLHW_T *)shim_osAllocateMemory(sizeof(ITIDSLHW_T));
++ if(ptidsl==NULL)
++ {
++ dprintf(1, "unable to allocate memory for ptidsl\n");
++ return 1;
++ }
++ *ppIHw=ptidsl;
++ shim_osZeroMemory((char *) ptidsl, sizeof(ITIDSLHW_T));
++
++ /* Unreset the ADSL Subsystem */
++ rc=dslhal_support_unresetDslSubsystem();
++ if(rc)
++ {
++ dprintf(1, "unable to reset ADSL Subsystem \n");
++ shim_osFreeMemory((void *) ptidsl, sizeof(ITIDSLHW_T));
++ return DSLHAL_ERROR_UNRESET_ADSLSS;
++ }
++ ptidsl->fwimage = shim_osAllocateVMemory(DSP_FIRMWARE_MALLOC_SIZE);
++ if(!ptidsl->fwimage)
++ {
++ dprintf(1,"Failed to Allocate Memory for DSP firmware binary \n");
++ return DSLHAL_ERROR_FIRMWARE_MALLOC;
++ }
++ /* read firmware file from flash */
++ rc=shim_osLoadFWImage(ptidsl->fwimage);
++ if(rc<0)
++ {
++ dprintf(1, "unable to get fw image\n");
++ shim_osFreeVMemory((void *)ptidsl->fwimage,DSP_FIRMWARE_MALLOC_SIZE);
++ shim_osFreeMemory((void *) ptidsl, sizeof(ITIDSLHW_T));
++ return DSLHAL_ERROR_NO_FIRMWARE_IMAGE;
++ }
++ else
++ {
++ ptidsl->imagesize = rc;
++ }
++ /* Compute the CRC checksum on the image and validate the image */
++
++ /* Validate the image in the RAM */
++
++ /* load fw to DSP */
++
++ if(dslhal_support_hostDspCodeDownload(ptidsl))
++ {
++ dprintf(0,"dsp load error\n");
++ for(i=0; i<NUM_PAGES; i++)
++ {
++ if(ptidsl->olayDpPage[i].PmemStartWtAddr !=NULL)
++ {
++ shim_osFreeDmaMemory((void *) ptidsl->olayDpPage[i].PmemStartWtAddr,
++ ptidsl->olayDpPage[i].OverlayXferCount);
++ }
++ }
++ if(ptidsl->coProfiles.PmemStartWtAddr != NULL)
++ shim_osFreeDmaMemory((void *)ptidsl->coProfiles.PmemStartWtAddr, ptidsl->coProfiles.OverlayXferCount);
++ if(ptidsl->constDisplay.PmemStartWtAddr != NULL)
++ shim_osFreeDmaMemory((void *)ptidsl->constDisplay.PmemStartWtAddr, ptidsl->constDisplay.OverlayXferCount);
++ shim_osFreeVMemory((void *)ptidsl->fwimage,DSP_FIRMWARE_MALLOC_SIZE);
++ shim_osFreeMemory((void *) ptidsl, sizeof(ITIDSLHW_T));
++ return DSLHAL_ERROR_CODE_DOWNLOAD;
++ }
++
++ /* set flag to indicated overlay pages are loaded */
++ ptidsl->bOverlayPageLoaded = 1;
++ /* set auto retrain to 1 to disble the overlay page reload */
++ ptidsl->bAutoRetrain = 1;
++
++ /* unreset Raptor */
++ /* change this to new function */
++ /* This function should basically bring DSP out of reset bit 23 of PRCR */
++ /* Function is ready but bypassed for Pre-Silicon */
++
++ rc=dslhal_support_unresetDsp();
++ if (rc)
++ {
++ dprintf(0,"unable to bring DSP out of Reset\n");
++ for(i=0; i<NUM_PAGES; i++)
++ {
++ if(ptidsl->olayDpPage[i].PmemStartWtAddr !=NULL)
++ {
++ shim_osFreeDmaMemory((void *) ptidsl->olayDpPage[i].PmemStartWtAddr,
++ ptidsl->olayDpPage[i].OverlayXferCount);
++ }
++ }
++ if(ptidsl->coProfiles.PmemStartWtAddr != NULL)
++ shim_osFreeDmaMemory((void *)ptidsl->coProfiles.PmemStartWtAddr, ptidsl->coProfiles.OverlayXferCount);
++ if(ptidsl->constDisplay.PmemStartWtAddr != NULL)
++ shim_osFreeDmaMemory((void *)ptidsl->constDisplay.PmemStartWtAddr, ptidsl->constDisplay.OverlayXferCount);
++ shim_osFreeVMemory((void *)ptidsl->fwimage,DSP_FIRMWARE_MALLOC_SIZE);
++ shim_osFreeMemory((void *) ptidsl, sizeof(ITIDSLHW_T));
++ return DSLHAL_ERROR_UNRESET_DSP;
++ }
++ shim_osFreeVMemory((void *)ptidsl->fwimage,DSP_FIRMWARE_MALLOC_SIZE);
++ dprintf(4,"dslhal_api_dslStartup() done\n");
++
++ /* Add the code to initialize the host interface variables */
++ /* Add code to tickle the host interface */
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_dslShutdown
++ *
++ *******************************************************************************************
++ * DESCRIPTION: routine to shutdown ax5 modem and free the resource
++ *
++ * INPUT: tidsl_t *ptidsl
++ *
++ * RETURN: NULL
++ *
++ *
++ *****************************************************************************************/
++
++int dslhal_api_dslShutdown(tidsl_t *ptidsl)
++{
++ int rc= DSLHAL_ERROR_NO_ERRORS;
++ int i;
++
++ dprintf(5, "dslhal_api_dslShutdown\n");
++ rc = dslhal_support_writeHostMailbox(ptidsl, HOST_DSLSS_SHUTDOWN, 0, 0, 0);
++ if(rc)
++ {
++ dprintf(1, " unable to reset DSP \n");
++ rc = DSLHAL_ERROR_RESET_DSP;
++ }
++ /* DSP need 50 ms to send out the message*/
++
++ shim_osClockWait(60 * 1000);
++
++ rc = dslhal_support_writeHostMailbox(ptidsl, HOST_DGASP, 0, 0, 0);
++
++ /* free memory allocated*/
++
++ for(i=0; i<NUM_PAGES; i++)
++ {
++ if(ptidsl->olayDpPage[i].PmemStartWtAddr !=NULL)
++ {
++ shim_osFreeDmaMemory((void *) ptidsl->olayDpPage[i].PmemStartWtAddr,
++ ptidsl->olayDpPage[i].OverlayXferCount);
++ }
++ }
++ if(ptidsl->coProfiles.PmemStartWtAddr != NULL)
++ shim_osFreeDmaMemory((void *)ptidsl->coProfiles.PmemStartWtAddr, ptidsl->coProfiles.OverlayXferCount);
++ if(ptidsl->constDisplay.PmemStartWtAddr != NULL)
++ shim_osFreeDmaMemory((void *)ptidsl->constDisplay.PmemStartWtAddr, ptidsl->constDisplay.OverlayXferCount);
++ shim_osFreeMemory((void *)ptidsl, sizeof(tidsl_t));
++ rc = dslhal_support_resetDsp();
++ if(rc)
++ {
++ dprintf(1, " unable to reset ADSL subsystem \n");
++ rc = DSLHAL_ERROR_RESET_DSP;
++ }
++ rc = dslhal_support_resetDslSubsystem();
++ if(rc)
++ {
++ dprintf(1, " unable to reset ADSL subsystem \n");
++ rc = DSLHAL_ERROR_RESET_ADSLSS;
++ }
++return rc;
++}
++
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_getDslHalVersion
++*
++*******************************************************************************************
++* DESCRIPTION: This routine supply DSL Driver version.
++*
++* INPUT: tidsl_t * ptidsl
++* void *pVer, DSP Driver Version Pointer
++*
++* RETURN: 0 --succeeded
++* 1 --Failed
++* Note: See verdef_u.h for version structure definition.
++*****************************************************************************************/
++
++void dslhal_api_getDslHalVersion(void *pVer)
++{
++ dslVer *pVersion;
++ pVersion = (dslVer *)pVer;
++ pVersion->major = (unsigned char) DSLHAL_VERSION_MAJOR;
++ pVersion->minor = (unsigned char) DSLHAL_VERSION_MINOR;
++ pVersion->bugfix = (unsigned char) DSLHAL_VERSION_BUGFIX;
++ pVersion->buildNum = (unsigned char) DSLHAL_VERSION_BUILDNUM;
++ pVersion->timeStamp = (unsigned char) DSLHAL_VERSION_TIMESTAMP;
++}
++
++/********************************************************************************************
++ * FUNCTION NAME: dslhal_api_pollTrainingStatus()
++ *
++ *********************************************************************************************
++ * DESCRIPTION: code to decode modem status and to start modem training
++ * Input: tidsl_t *ptidsl
++ *
++ * Return: modem status
++ * -1 failed
++ *
++ ********************************************************************************************/
++
++int dslhal_api_pollTrainingStatus(tidsl_t *ptidsl)
++{
++ int cmd;
++ int tag;
++ int parm1,parm2;
++ int rc;
++ unsigned int failState;
++ static unsigned int pollGhsIndex=0;
++
++ /*char *tmp;*/
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++#if SWTC
++ DEV_HOST_tcHostCommDef_t TCHostCommDef;
++#endif
++
++ dprintf(5,"dslhal_api_pollTrainingStatus\n");
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterface_t *) ptidsl->pmainAddr;
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,
++ sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++#if SWTC
++ dspOamSharedInterface.tcHostComm_p =(DEV_HOST_tcHostCommDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.tcHostComm_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.tcHostComm_p,
++ &TCHostCommDef, sizeof(DEV_HOST_tcHostCommDef_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++#endif
++
++ rc = dslhal_support_processTrainingState(ptidsl);
++ if(rc)
++ {
++ dprintf(0,"Error Reading Modem Training State \n");
++ return DSLHAL_ERROR_MODEMSTATE;
++ }
++ rc = dslhal_support_processModemStateBitField(ptidsl);
++ if(rc)
++ {
++ dprintf(0,"Error Reading Modem Training State \n");
++ return DSLHAL_ERROR_MODEMSTATE;
++ }
++ /*
++ rc = dslhal_support_readDelineationState(ptidsl);
++ if(rc)
++ {
++ dprintf(0,"Error Reading Delineation State \n");
++ return DSLHAL_ERROR_MODEMSTATE;
++ }
++ */
++ while (dslhal_support_readDspMailbox(ptidsl,&cmd, &tag, &parm1, &parm2) == DSLHAL_ERROR_NO_ERRORS )
++ {
++ dprintf(4,"mailbox message: 0x%x\n", cmd);
++ /*
++ for(rc=0;rc<8;rc++)
++ {
++ dslhal_support_readTextMailbox(ptidsl,&msg1, &msg2);
++ }
++ */
++
++ if (cmd == DSP_IDLE)
++ {
++ dprintf(4,"DSP_IDLE\n");
++ ptidsl->lConnected=0;
++ hybrid_selected=888;
++ /* add code for reload overlay pages */
++ if(ptidsl->bAutoRetrain == 0)
++ {
++ while(ptidsl->bOverlayPageLoaded == 0)
++ {
++ shim_osClockWait(6400);
++ }
++ //dslhal_support_restoreTrainingInfo(ptidsl);
++ //ptidsl->bOverlayPageLoaded = 1;
++ }
++ /* command DSP to ACTREQ */
++ if(showtimeFlag == TRUE)
++ {
++ dslhal_api_resetTrainFailureLog(ptidsl);
++ dslhal_support_advancedIdleProcessing(ptidsl);
++ showtimeFlag = FALSE;
++ }
++ failState = (unsigned int)parm1;
++ if(failState!=0)
++ {
++ ptidsl->AppData.trainFailStates[ptidsl->AppData.trainFails]=failState;
++ ptidsl->AppData.trainFails++;
++ if(ptidsl->AppData.trainFails > 30)
++ ptidsl->AppData.trainFails=0;
++ }
++ for(pollGhsIndex=0;pollGhsIndex<10;pollGhsIndex++)
++ {
++ for(rc=0;rc<62;rc++)
++ ptidsl->AppData.dsl_ghsRxBuf[pollGhsIndex][rc]=0;
++ }
++ pollGhsIndex=0;
++ rc = dslhal_support_writeHostMailbox(ptidsl,HOST_ACTREQ, 0, 0, 0);
++ if (rc)
++ return DSLHAL_ERROR_MAILBOX_WRITE;
++ }
++
++ if(cmd == DSP_ATM_TC_SYNC)
++ {
++ dprintf(4,"\nTC_SYNC\n");
++ showtimeFlag = TRUE;
++ ptidsl->lConnected=1;
++ if(ptidsl->bAutoRetrain == 0 && ptidsl->bOverlayPageLoaded == 1)
++ {
++ dslhal_support_clearTrainingInfo(ptidsl);
++ ptidsl->bOverlayPageLoaded = 0;
++ }
++ }
++ if(cmd == DSP_ACTIVE)
++ {
++ dprintf(4,"DSP_ACTIVE");
++ ptidsl->lConnected=0;
++ ptidsl->AppData.bState = RSTATE_SHOWTIME;
++ dprintf(4,"US Connect Rate: %u \n",ptidsl->AppData.USConRate);
++ dprintf(4,"DS Connect Rate: %u \n",ptidsl->AppData.DSConRate);
++ }
++ if(cmd == DSP_ATM_NO_TC_SYNC)
++ {
++ dprintf(4,"\nTC_NOSYNC\n");
++ ptidsl->lConnected=0;
++ }
++ if(cmd == DSP_DGASP)
++ {
++ dprintf(0,"\n GASP!!! \n");
++ }
++ if(cmd == DSP_OVERLAY_END)
++ {
++ dprintf(4,"Overlay Page Done %d \n",tag);
++ rc = dslhal_support_checkOverlayPage(ptidsl,tag);
++ if(rc == DSLHAL_ERROR_OVERLAY_CORRUPTED)
++ {
++ dprintf(0,"Overlay Page: %d CORRUPTED \n",tag);
++ return (0-DSLHAL_ERROR_OVERLAY_CORRUPTED);
++ }
++ }
++ if(cmd == DSP_HYBRID)
++ {
++ dprintf(2,"Hybrid Metrics Available: %d\n",tag);
++ hybrid_selected = tag;
++ }
++ if(cmd == DSP_DGASP)
++ {
++ dprintf(0,"\n GASP!!! \n");
++ }
++ if(cmd == DSP_XMITBITSWAP)
++ {
++ dslhal_support_aocBitSwapProcessing(ptidsl,0);
++ }
++ if(cmd == DSP_RCVBITSWAP)
++ {
++ dslhal_support_aocBitSwapProcessing(ptidsl,1);
++ }
++ if(cmd == DSP_GHSMSG)
++ {
++ dprintf(3,"Ghs Message Received, bytes: %d \n",tag);
++ dprintf(3,"Addr: 0x%x\n",dspOamSharedInterface.ghsDspRxBuf_p);
++ if(pollGhsIndex > 9)
++ pollGhsIndex=0;
++ rc = dslhal_support_blockRead((void *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.ghsDspRxBuf_p), &ptidsl->AppData.dsl_ghsRxBuf[pollGhsIndex++][0], tag);
++ }
++ if(cmd == DSP_CRATES1)
++ {
++ dprintf(3,"DSP C-Rates1 Data Ready \n");
++ rc = dslhal_support_gatherRateMessages(ptidsl);
++ }
++ if(cmd == DSP_SNR)
++ {
++ dprintf(3,"DSP SNR Data Ready \n");
++ rc = dslhal_support_gatherSnrPerBin(ptidsl,tag);
++ }
++ if(cmd == DSP_EOC)
++ {
++ dprintf(3,"DSP_EOC message \n");
++ rc = dslhal_support_gatherEocMessages(ptidsl,tag,parm1,parm2);
++ }
++
++ if(cmd == DSP_TRAINING_MSGS)
++ {
++ dprintf(3,"DSP_TRAINING_MSGS \n");
++ rc = dslhal_support_gatherAdsl2Messages(ptidsl,tag,parm1,parm2);
++ }
++ }
++ dprintf(6,"dslhal_api_pollTrainingStatus done\n");
++ return(ptidsl->AppData.bState);
++
++} /* end of dslhal_api_pollTrainingStatus() */
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_handleTrainingInterrupt()
++*
++*********************************************************************************************
++* DESCRIPTION: Code to handle ax5 hardware interrupts
++*
++* Input: tidsl_t *ptidsl
++* int *pMsg, pointer to returned hardware messages. Each byte represent a messge
++* int *pTag, pointer to returned hardware message tags. Each byte represent a tag.
++* Return: 0 success
++* 1 failed
++*
++********************************************************************************************/
++int dslhal_api_handleTrainingInterrupt(tidsl_t *ptidsl, int intrSource)
++{
++ int cmd;
++ int tag;
++ int parm1,parm2;
++ unsigned int msg1;
++ unsigned int msg2;
++ int rc;
++ unsigned int failState;
++ static unsigned int interruptGhsIndex=0;
++ /*char *tmp;*/
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++#if SWTC
++ DEV_HOST_tcHostCommDef_t TCHostCommDef;
++#endif
++ dprintf(6,"dslhal_api_handleTrainingInterrupt\n");
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterface_t *) ptidsl->pmainAddr;
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,
++ sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++#if SWTC
++ dspOamSharedInterface.tcHostComm_p =(DEV_HOST_tcHostCommDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.tcHostComm_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.tcHostComm_p,
++ &TCHostCommDef, sizeof(DEV_HOST_tcHostCommDef_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++#endif
++
++ if(intrSource & MASK_BITFIELD_INTERRUPTS)
++ {
++ dspOamSharedInterface.modemStateBitField_p =(DEV_HOST_modemStateBitField_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.modemStateBitField_p);
++ rc = dslhal_support_processTrainingState(ptidsl);
++ if(rc)
++ {
++ dprintf(0,"Error Reading Modem Training State \n");
++ return DSLHAL_ERROR_MODEMSTATE;
++ }
++ rc = dslhal_support_processModemStateBitField(ptidsl);
++ if(rc)
++ {
++ dprintf(0,"Error Reading Modem Training State \n");
++ return DSLHAL_ERROR_MODEMSTATE;
++ }
++ }
++ if(intrSource & MASK_MAILBOX_INTERRUPTS)
++ {
++ /*
++ rc = dslhal_support_readDelineationState(ptidsl);
++ if(rc)
++ {
++ dprintf(0,"Error Reading Delineation State \n");
++ return DSLHAL_ERROR_MODEMSTATE;
++ }
++ */
++ while (dslhal_support_readDspMailbox(ptidsl,&cmd, &tag, &parm1, &parm2) == DSLHAL_ERROR_NO_ERRORS )
++ {
++ dprintf(4,"mailbox message: 0x%x\n", cmd);
++ /*
++ for(rc=0;rc<8;rc++)
++ {
++ dslhal_support_readTextMailbox(ptidsl,&msg1, &msg2);
++ }
++ */
++ if (cmd == DSP_IDLE)
++ {
++ dprintf(4,"DSP_IDLE\n");
++ ptidsl->lConnected=0;
++ hybrid_selected=888;
++ if(showtimeFlag == TRUE)
++ {
++ dslhal_api_resetTrainFailureLog(ptidsl);
++ dslhal_support_advancedIdleProcessing(ptidsl);
++ showtimeFlag = FALSE;
++ }
++ failState = (unsigned int)parm1;
++ if(failState!=0)
++ {
++ ptidsl->AppData.trainFailStates[ptidsl->AppData.trainFails]=failState;
++ ptidsl->AppData.trainFails++;
++ if(ptidsl->AppData.trainFails > 30)
++ ptidsl->AppData.trainFails=0;
++ }
++ for(interruptGhsIndex=0;interruptGhsIndex<10;interruptGhsIndex++)
++ {
++ for(rc=0;rc<62;rc++)
++ ptidsl->AppData.dsl_ghsRxBuf[interruptGhsIndex][rc]=0;
++ }
++ interruptGhsIndex=0;
++
++ /* add code for reload overlay pages */
++ if(ptidsl->bAutoRetrain == 0 && ptidsl->bOverlayPageLoaded == 0)
++ {
++ dslhal_support_restoreTrainingInfo(ptidsl);
++ ptidsl->bOverlayPageLoaded = 1;
++ }
++ /* command DSP to ACTREQ */
++ rc = dslhal_support_writeHostMailbox(ptidsl, HOST_ACTREQ, 0, 0, 0);
++ if (rc)
++ return DSLHAL_ERROR_MAILBOX_WRITE;
++ }
++ if(cmd == DSP_ATM_TC_SYNC)
++ {
++ dprintf(4,"\nTC_SYNC\n");
++ showtimeFlag = TRUE;
++ ptidsl->lConnected=1;
++ if(ptidsl->bAutoRetrain == 0 && ptidsl->bOverlayPageLoaded == 1)
++ {
++ dslhal_support_clearTrainingInfo(ptidsl);
++ ptidsl->bOverlayPageLoaded = 0;
++ }
++ }
++ if(cmd == DSP_ACTIVE)
++ {
++ ptidsl->lConnected=0;
++ ptidsl->AppData.bState = RSTATE_SHOWTIME;
++ dprintf(4,"DSP_ACTIVE");
++ dprintf(4,"US Connect Rate: %u \n",ptidsl->AppData.USConRate);
++ dprintf(4,"DS Connect Rate: %u \n",ptidsl->AppData.DSConRate);
++ }
++ if(cmd == DSP_ATM_NO_TC_SYNC)
++ {
++ dprintf(4,"\nTC_NOSYNC\n");
++ ptidsl->lConnected=0;
++ /* add code for reload overlay pages */
++ }
++ if(cmd == DSP_OVERLAY_END)
++ {
++ dprintf(4,"Overlay Page Done %d \n",tag);
++ rc = dslhal_support_checkOverlayPage(ptidsl,tag);
++ if(rc == DSLHAL_ERROR_OVERLAY_CORRUPTED)
++ {
++ dprintf(4,"Overlay Page: %d CORRUPTED \n",tag);
++ return(0-DSLHAL_ERROR_OVERLAY_CORRUPTED);
++ }
++ }
++ if(cmd == DSP_HYBRID)
++ {
++ dprintf(2,"Hybrid Metrics Available\n");
++ hybrid_selected = tag;
++ }
++ if(cmd == DSP_XMITBITSWAP)
++ {
++ rc = dslhal_support_aocBitSwapProcessing(ptidsl,0);
++ }
++ if(cmd == DSP_RCVBITSWAP)
++ {
++ rc = dslhal_support_aocBitSwapProcessing(ptidsl,1);
++ }
++ if(cmd == DSP_GHSMSG)
++ {
++ dprintf(3,"Ghs Message Received, bytes: %d \n",tag);
++ dprintf(3,"Addr: 0x%x\n",dspOamSharedInterface.ghsDspRxBuf_p);
++ if(interruptGhsIndex > 9)
++ interruptGhsIndex=0;
++ rc = dslhal_support_blockRead((void *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.ghsDspRxBuf_p), &ptidsl->AppData.dsl_ghsRxBuf[interruptGhsIndex++][0], tag);
++ }
++ if(cmd == DSP_CRATES1)
++ {
++ dprintf(3,"DSP C-Rates1 Data Ready \n");
++ rc = dslhal_support_gatherRateMessages(ptidsl);
++ }
++ if(cmd == DSP_SNR)
++ {
++ dprintf(3,"DSP SNR Data Ready \n");
++ rc = dslhal_support_gatherSnrPerBin(ptidsl,tag);
++ }
++ if(cmd == DSP_EOC)
++ {
++ dprintf(3,"DSP_EOC message \n");
++ rc = dslhal_support_gatherEocMessages(ptidsl,tag,parm1,parm2);
++ }
++ if(cmd == DSP_TRAINING_MSGS)
++ {
++ dprintf(3,"DSP_TRAINING_MSGS \n");
++ rc = dslhal_support_gatherAdsl2Messages(ptidsl,tag,parm1,parm2);
++ }
++ }
++
++ dslhal_support_readTextMailbox(ptidsl,&msg1, &msg2);
++ dprintf(5,"Text Message Part1: 0x%x \t Text Message Part2: 0x%x \n",msg1,msg2);
++ }
++ dprintf(6,"dslhal_api_handleTrainingInterrupt done\n");
++ return(ptidsl->AppData.bState);
++} /* end of dslhal_api_handleTrainingInterrupt() */
++
++
++
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_dslRetrain(tidsl_t *ptidsl)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction sends CMD_ACTREQ to the DSP to issue a retrain
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_dslRetrain(tidsl_t *ptidsl)
++{
++ int rc;
++
++ dprintf(5, "dslhal_cfg_dslRetrain \n");
++ rc = dslhal_support_writeHostMailbox(ptidsl, HOST_QUIET, 0, 0, 0);
++ if(rc)
++ {
++ dprintf(1,"dslhal_cfg_dslRetrain failed\n");
++ return DSLHAL_ERROR_CTRL_API_FAILURE;
++ }
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_sendQuiet(tidsl_t *ptidsl)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction sends the CMD_QUIET message to the DSP
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_sendQuiet(tidsl_t *ptidsl)
++{
++ int rc;
++
++ dprintf(5, "dslhal_api_sendQuiet\n");
++ rc = dslhal_support_writeHostMailbox(ptidsl, HOST_QUIET, 0, 0, 0);
++ if(rc)
++ {
++ dprintf(1,"dslhal_api_sendQuiet failed\n");
++ return DSLHAL_ERROR_CTRL_API_FAILURE;
++ }
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_sendIdle(tidsl_t *ptidsl)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction sends the CMD_IDLE message to the DSP
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_sendIdle(tidsl_t *ptidsl)
++{
++ int rc;
++
++ dprintf(5, "dslhal_api_sendIdle\n");
++ rc = dslhal_support_writeHostMailbox(ptidsl, HOST_IDLE, 0, 0, 0);
++ if(rc)
++ {
++ dprintf(1,"dslhal_api_sendIdle failed\n");
++ return DSLHAL_ERROR_CTRL_API_FAILURE;
++ }
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_sendDgasp(tidsl_t *ptidsl)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction sends the HOST_DGASP message to the DSP
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_sendDgasp(tidsl_t *ptidsl)
++{
++ int rc;
++
++ dprintf(5, "dslhal_api_sendDgasp\n");
++ rc = dslhal_support_writeHostMailbox(ptidsl, HOST_DGASP, 0, 0, 0);
++ if(rc)
++ {
++ dprintf(1,"dslhal_api_sendDgasp failed\n");
++ return DSLHAL_ERROR_CTRL_API_FAILURE;
++ }
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_setTrainingMode(tidsl_t *ptidsl,unsigned int trainmode)
++*
++*******************************************************************************************
++* DESCRIPTION: This fuction Sets the Desired Training Mode {None/Multimode/G.dmt/lite
++*
++* INPUT: PITIDSLHW_T *ptidsl
++* unsigned int trainmode :Should be between 0 and 4; 0:No Mode 1:Multimode
++* 2: T1.413, 3:G.dmt, 4: G.lite
++* RETURN: 0 SUCCESS
++* 1 FAILED
++*
++*****************************************************************************************/
++unsigned int dslhal_api_setTrainingMode(tidsl_t *ptidsl,unsigned int trainmode)
++{
++ DEV_HOST_oamWrNegoParaDef_t NegoPara;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ int rc;
++ dprintf(5," dslhal_api_setTrainingMode()\n");
++ if(trainmode>255)
++ {
++ dprintf(3,"Invalid Value for Desired Training Mode (must be <255)\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,
++ sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.oamWriteNegoParams_p = (DEV_HOST_oamWrNegoParaDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.oamWriteNegoParams_p);
++
++ rc = dslhal_support_blockRead((PVOID) dspOamSharedInterface.oamWriteNegoParams_p,&NegoPara, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ /* Enum Translation to maintain backwards compatibility for train modes */
++ if(trainmode == DSLTRAIN_MULTI_MODE)
++ trainmode = MULTI_MODE;
++ if(trainmode == DSLTRAIN_T1413_MODE)
++ trainmode = T1413_MODE;
++ if(trainmode == DSLTRAIN_GDMT_MODE)
++ trainmode = GDMT_MODE;
++
++ NegoPara.stdMode = trainmode;
++ dprintf(5,"Train Mode: 0x%x\n",trainmode);
++ rc = dslhal_support_blockWrite(&NegoPara,(PVOID)dspOamSharedInterface.oamWriteNegoParams_p, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++ if(rc)
++ return DSLHAL_ERROR_CONFIG_API_FAILURE;
++
++ dprintf(5," dslhal_api_setTrainingMode() Done\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_getDspVersion
++*
++*******************************************************************************************
++* DESCRIPTION: This routine supply AX5 daugther card DSP version.
++*
++* INPUT: tidsl_t * ptidsl
++* void *pVer, DSP version struct is returned starting at this pointer
++*
++* RETURN: 0 --succeeded
++* 1 --Failed
++* Note: See verdef_u.h for version structure definition.
++*****************************************************************************************/
++int dslhal_api_getDspVersion(tidsl_t *ptidsl, void *pVer)
++{
++ /* DEV_HOST_dspVersionDef_t dspVersion; */
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ int rc;
++ dprintf(5, "dslhal_api_getDspVersion\n");
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++ if(!pVer)
++ return DSLHAL_ERROR_INVALID_PARAM;
++
++ *(unsigned int *) pVer = 0;
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.datapumpVersion_p = (DEV_HOST_dspVersionDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.datapumpVersion_p);
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.datapumpVersion_p,
++ pVer, sizeof(dspVer));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ pVer = (DEV_HOST_dspVersionDef_t *)(dslhal_support_byteSwap32((unsigned int)pVer));
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_gatherStatistics()
++*
++*********************************************************************************************
++* DESCRIPTION: Read statistical infromation from ax5 modem daugter card.
++* Input: tidsl_t *ptidsl
++*
++* Return: 0 success
++* 1 failed
++*
++********************************************************************************************/
++void dslhal_api_gatherStatistics(tidsl_t * ptidsl)
++{
++ int rc,optIdxU,optIdxD,i;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ DEV_HOST_dspWrNegoParaDef_t rateparms;
++ DEV_HOST_oamWrNegoParaDef_t configParms;
++ DEV_HOST_modemStatsDef_t StatisticsDef;
++ DEV_HOST_errorStats_t usIntlvError, usFastError, dsIntlvError, dsFastError;
++ DEV_HOST_atmStats_t atmStats;
++ DEV_HOST_usAtmStats_t usAtmStats0, usAtmStats1;
++ DEV_HOST_dsAtmStats_t dsAtmStats0,dsAtmStats1;
++ DEV_HOST_dspWrSuperFrameCntDef_t SuperFrameCnt;
++ DEV_HOST_msg_t atuc_msg, aturMsg;
++ DEV_HOST_eocVarDef_t eocVar;
++ DEV_HOST_dspWrSharedTables_t sharedTables;
++ DEV_HOST_phyPerf_t phyPerf;
++ unsigned char usBits[64],dsBits[256];
++ unsigned char dsPowerCutBack;
++ int usNumLoadedTones=0, dsNumLoadedTones=0;
++
++ dprintf(5, "dslhal_api_gatherStatistics\n");
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,
++ sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ if(!ptidsl->bStatisticsInitialized && ptidsl->lConnected == LINE_CONNECTED)
++ {
++ dslhal_api_initStatistics(ptidsl);
++ ptidsl->bStatisticsInitialized = TRUE;
++ }
++
++ dspOamSharedInterface.dspWriteNegoParams_p = (DEV_HOST_dspWrNegoParaDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.dspWriteNegoParams_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.dspWriteNegoParams_p,
++ &rateparms, sizeof(DEV_HOST_dspWrNegoParaDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ if(!rc)
++ {
++ /* trained mode */
++ ptidsl->AppData.dsl_modulation = (unsigned int)rateparms.trainMode;
++ if(rateparms.trainMode == T1413_MODE)
++ ptidsl->AppData.dsl_modulation = DSLTRAIN_T1413_MODE;
++ if(rateparms.trainMode == GDMT_MODE)
++ ptidsl->AppData.dsl_modulation = DSLTRAIN_GDMT_MODE;
++ /* rate */
++ /* shim_osMoveMemory((void *)ptidsl->AppData.bCRates1, (void *)rateparms.cRates1, 120); */
++ ptidsl->AppData.bCRates2 = rateparms.cRates2;
++ /* shim_osMoveMemory((void *)ptidsl->AppData.bRRates1, (void *)rateparms.rRates1, 44); */
++ ptidsl->AppData.bRRates2 = rateparms.rRates2;
++ shim_osMoveMemory((void *)ptidsl->AppData.bCMsgs1, (void *)rateparms.cMsgs1, 6);
++ shim_osMoveMemory((void *)ptidsl->AppData.bCMsgs2, (void *)rateparms.cMsgs2, 4);
++ shim_osMoveMemory((void *)ptidsl->AppData.bRMsgs2, (void *)rateparms.rMsgs2, 4);
++ ptidsl->AppData.atucVendorId = (unsigned int)rateparms.atucVendorId;
++ ptidsl->AppData.lineLength = (unsigned int)dslhal_support_byteSwap16((unsigned short)rateparms.lineLength);
++ ptidsl->AppData.atucRevisionNum = (unsigned int)rateparms.atucGhsRevisionNum;
++ ptidsl->AppData.usLineAttn = (ptidsl->AppData.bCMsgs2[3] >>2)&0x003f;
++ ptidsl->AppData.usMargin = (ptidsl->AppData.bCMsgs2[2])&0x001f;
++
++ if((rateparms.cRates2 & 0x0f) == 0x01)
++ optIdxU = 0;
++ else if((rateparms.cRates2 & 0x0f) == 0x02)
++ optIdxU = 1;
++ else if((rateparms.cRates2 & 0x0f) == 0x04)
++ optIdxU = 2;
++ else if((rateparms.cRates2 & 0x0f) == 0x08)
++ optIdxU = 3;
++ else
++ optIdxU = -1;
++
++ dprintf(5, "optIdxU=%d\n", optIdxU);
++
++ /* Obtain the US Rates using Opt# and CRates1 Table */
++ /* Rate(US) = [Bf(LS0) + Bi(LS0)]*32 */
++ if(ptidsl->AppData.dsl_modulation <= DSLTRAIN_GLITE_MODE)
++ ptidsl->AppData.USConRate = ((rateparms.cRates1[optIdxU][CRATES1_BF_LS0] + rateparms.cRates1[optIdxU][CRATES1_BI_LS0]) * 32);
++ else
++ ptidsl->AppData.USConRate = 32 * dslhal_support_byteSwap16((unsigned short)rateparms.adsl2USRate);
++
++ ptidsl->AppData.USPeakCellRate = ptidsl->AppData.USConRate;
++
++ if(((rateparms.cRates2 >> 4) & 0x0f) == 0x01)
++ optIdxD = 0;
++ else if(((rateparms.cRates2 >> 4) & 0x0f) == 0x02)
++ optIdxD = 1;
++ else if(((rateparms.cRates2 >> 4) & 0x0f) == 0x04)
++ optIdxD = 2;
++ else if(((rateparms.cRates2 >> 4) & 0x0f) == 0x08)
++ optIdxD = 3;
++ else
++ optIdxD = -1;
++ /* Obtain the DS Rates using Opt# and CRates1 Table */
++ /* Rate(DS) = [Bf(AS0) + Bi(AS0)]*32 */
++ if(ptidsl->AppData.dsl_modulation <= DSLTRAIN_GLITE_MODE)
++ ptidsl->AppData.DSConRate = (((rateparms.cRates1[optIdxD][CRATES1_BF_AS0]|((rateparms.cRates1[optIdxD][CRATES1_BF_DSRS]&0x80)<<1))+ (rateparms.cRates1[optIdxD][CRATES1_BI_AS0]|((rateparms.cRates1[optIdxD][CRATES1_BI_DSRS]&0x80)<<1)))* 32);
++ else
++ ptidsl->AppData.DSConRate = dslhal_support_byteSwap16((unsigned short)rateparms.adsl2DSRate);
++
++ dprintf(5, "ptidsl->AppData.wDSConRate=%d\n", ptidsl->AppData.DSConRate);
++ /* Determine which Path has Modem Trained with */
++ if((rateparms.cRates1[optIdxU][CRATES1_BF_LS0]) && (rateparms.cRates1[optIdxD][CRATES1_BF_AS0]))
++ ptidsl->AppData.TrainedPath = FAST_PATH;
++ else
++ ptidsl->AppData.TrainedPath = INTERLEAVED_PATH;
++
++ /* Set the mode in which the modem is trained */
++ ptidsl->AppData.TrainedMode = (unsigned int)rateparms.trainMode;
++ if(rateparms.trainMode == T1413_MODE)
++ ptidsl->AppData.TrainedMode = DSLTRAIN_T1413_MODE;
++ if(rateparms.trainMode == GDMT_MODE)
++ ptidsl->AppData.TrainedMode = DSLTRAIN_GDMT_MODE;
++
++ if(ptidsl->AppData.TrainedPath == FAST_PATH)
++ ptidsl->AppData.dsFastParityBytesPerSymbol = (rateparms.cRates1[optIdxU][CRATES1_BF_DSRS]&0x1f);
++ else
++ ptidsl->AppData.dsIntlvParityBytesPerSymbol = (rateparms.cRates1[optIdxU][CRATES1_BI_DSRS]&0x1f);
++ ptidsl->AppData.dsSymbolsPerCodeWord = (rateparms.cRates1[optIdxU][CRATES1_BFI_DSS]&0x1f);
++ ptidsl->AppData.dsInterleaverDepth = ((rateparms.cRates1[optIdxU][CRATES1_BFI_DSI])|((rateparms.cRates1[optIdxU][CRATES1_BFI_DSS]&0xc0)<<2));
++
++ if(ptidsl->AppData.TrainedPath == FAST_PATH)
++ ptidsl->AppData.usFastParityBytesPerSymbol = (rateparms.cRates1[optIdxU][CRATES1_BF_USRS]&0x1f);
++ else
++ ptidsl->AppData.usIntlvParityBytesPerSymbol = (rateparms.cRates1[optIdxU][CRATES1_BI_USRS]&0x1f);
++ ptidsl->AppData.usSymbolsPerCodeWord = (rateparms.cRates1[optIdxU][CRATES1_BFI_USS]&0x1f);
++ ptidsl->AppData.usInterleaverDepth = ((rateparms.cRates1[optIdxU][CRATES1_BFI_USI])|((rateparms.cRates1[optIdxU][CRATES1_BFI_USS]&0xc0)<<2));
++ }
++
++ dspOamSharedInterface.modemStats_p = (DEV_HOST_modemStatsDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.modemStats_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.modemStats_p,&StatisticsDef, sizeof(DEV_HOST_modemStatsDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ /* Populate the Error Structure Variables */
++
++ /* US Interleave Path Error Statistics */
++
++ /* Change the endianness of the Pointer */
++ StatisticsDef.usErrorStatsIntlv_p = (DEV_HOST_errorStats_t *) dslhal_support_byteSwap32((unsigned int)StatisticsDef.usErrorStatsIntlv_p);
++
++ rc = dslhal_support_blockRead((PVOID)StatisticsDef.usErrorStatsIntlv_p,&usIntlvError, (sizeof(DEV_HOST_errorStats_t)));
++
++ if (rc)
++ return;
++
++ /* DS Interleave Path Error Statistics */
++
++ /* Change the endianness of the Pointer */
++ StatisticsDef.dsErrorStatsIntlv_p = (DEV_HOST_errorStats_t *) dslhal_support_byteSwap32((unsigned int)StatisticsDef.dsErrorStatsIntlv_p);
++
++ rc = dslhal_support_blockRead((PVOID)StatisticsDef.dsErrorStatsIntlv_p,&dsIntlvError, (sizeof(DEV_HOST_errorStats_t)));
++
++ if (rc)
++ return;
++
++ /* US Fast Path Error Statistics */
++
++ /* Change the endianness of the Pointer */
++ StatisticsDef.usErrorStatsFast_p = (DEV_HOST_errorStats_t *) dslhal_support_byteSwap32((unsigned int)StatisticsDef.usErrorStatsFast_p);
++
++ rc = dslhal_support_blockRead((PVOID)StatisticsDef.usErrorStatsFast_p,&usFastError, (sizeof(DEV_HOST_errorStats_t)));
++
++ if (rc)
++ return;
++
++ /* DS Fast Path Error Statistics */
++
++ /* Change the endianness of the Pointer */
++ StatisticsDef.dsErrorStatsFast_p = (DEV_HOST_errorStats_t *) dslhal_support_byteSwap32((unsigned int)StatisticsDef.dsErrorStatsFast_p);
++
++ rc = dslhal_support_blockRead((PVOID)StatisticsDef.dsErrorStatsFast_p,&dsFastError, (sizeof(DEV_HOST_errorStats_t)));
++
++ if (rc)
++ return;
++ if(!rc)
++ {
++ if(ptidsl->AppData.bState > 2)
++ {
++ /* Get CRC Errors Stats for both US and DS */
++ ptidsl->AppData.dsICRC_errors = dslhal_support_byteSwap32((unsigned int)dsIntlvError.crcErrors);
++ ptidsl->AppData.dsFCRC_errors = dslhal_support_byteSwap32((unsigned int)dsFastError.crcErrors);
++ ptidsl->AppData.usICRC_errors = dslhal_support_byteSwap32((unsigned int)usIntlvError.crcErrors);
++ ptidsl->AppData.usFCRC_errors = dslhal_support_byteSwap32((unsigned int)usFastError.crcErrors);
++ /* Get FEC Errors Stats for both US and DS */
++ ptidsl->AppData.dsIFEC_errors = dslhal_support_byteSwap32((unsigned int)dsIntlvError.fecErrors);
++ ptidsl->AppData.dsFFEC_errors = dslhal_support_byteSwap32((unsigned int)dsFastError.fecErrors);
++ ptidsl->AppData.usIFEC_errors = dslhal_support_byteSwap32((unsigned int)usIntlvError.fecErrors);
++ ptidsl->AppData.usFFEC_errors = dslhal_support_byteSwap32((unsigned int)usFastError.fecErrors);
++ /* Get NCD Errors Stats for both US and DS */
++ ptidsl->AppData.dsINCD_error = dslhal_support_byteSwap32((unsigned int)dsIntlvError.ncdError);
++ ptidsl->AppData.dsFNCD_error = dslhal_support_byteSwap32((unsigned int)dsFastError.ncdError);
++ ptidsl->AppData.usINCD_error = dslhal_support_byteSwap32((unsigned int)usIntlvError.ncdError);
++ ptidsl->AppData.usFNCD_error = dslhal_support_byteSwap32((unsigned int)usFastError.ncdError);
++ /* Get LCD Errors Stats for both US and DS */
++ ptidsl->AppData.dsILCD_errors = dslhal_support_byteSwap32((unsigned int)dsIntlvError.lcdErrors);
++ ptidsl->AppData.dsFLCD_errors = dslhal_support_byteSwap32((unsigned int)dsFastError.lcdErrors);
++ ptidsl->AppData.usILCD_errors = dslhal_support_byteSwap32((unsigned int)usIntlvError.lcdErrors);
++ ptidsl->AppData.usFLCD_errors = dslhal_support_byteSwap32((unsigned int)usFastError.lcdErrors);
++ /*Get HEC Errors Stats for both US and DS */
++ ptidsl->AppData.dsIHEC_errors = dslhal_support_byteSwap32((unsigned int)dsIntlvError.hecErrors);
++ ptidsl->AppData.dsFHEC_errors = dslhal_support_byteSwap32((unsigned int)dsFastError.hecErrors);
++ ptidsl->AppData.usIHEC_errors = dslhal_support_byteSwap32((unsigned int)usIntlvError.hecErrors);
++ ptidsl->AppData.usFHEC_errors = dslhal_support_byteSwap32((unsigned int)usFastError.hecErrors);
++
++ /* Get LOS and SEF error Stats */
++ ptidsl->AppData.LOS_errors = dslhal_support_byteSwap32(StatisticsDef.losErrors);
++ ptidsl->AppData.SEF_errors = dslhal_support_byteSwap32(StatisticsDef.sefErrors);
++ ptidsl->AppData.coLosErrors = dslhal_support_byteSwap32(StatisticsDef.farEndLosErrors);
++ ptidsl->AppData.coRdiErrors = dslhal_support_byteSwap32(StatisticsDef.farEndRdiErrors);
++
++ dspOamSharedInterface.atmStats_p = (DEV_HOST_atmStats_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.atmStats_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.atmStats_p,&atmStats, sizeof(DEV_HOST_atmStats_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++
++ /* Populate the US/DS ATM Stats Variables */
++
++ /* US ATM Statistics */
++
++ /* Change the endianness of the Pointer */
++ atmStats.us0_p = (DEV_HOST_usAtmStats_t *) dslhal_support_byteSwap32((unsigned int)atmStats.us0_p);
++
++ rc = dslhal_support_blockRead((PVOID)atmStats.us0_p,&usAtmStats0, (sizeof(DEV_HOST_usAtmStats_t)));
++
++ if (rc)
++ return;
++
++ atmStats.us1_p = (DEV_HOST_usAtmStats_t *) dslhal_support_byteSwap32((unsigned int)atmStats.us1_p);
++
++ rc = dslhal_support_blockRead((PVOID)atmStats.us1_p,&usAtmStats1, (sizeof(DEV_HOST_usAtmStats_t)));
++
++ if (rc)
++ return;
++
++ /* DS ATM Statistics */
++
++ /* Change the endianness of the Pointer */
++ atmStats.ds0_p = (DEV_HOST_dsAtmStats_t *) dslhal_support_byteSwap32((unsigned int)atmStats.ds0_p);
++
++ rc = dslhal_support_blockRead((PVOID)atmStats.ds0_p,&dsAtmStats0, (sizeof(DEV_HOST_dsAtmStats_t)));
++
++ if (rc)
++ return;
++ atmStats.ds1_p = (DEV_HOST_dsAtmStats_t *) dslhal_support_byteSwap32((unsigned int)atmStats.ds1_p);
++
++ rc = dslhal_support_blockRead((PVOID)atmStats.ds1_p,&dsAtmStats1, (sizeof(DEV_HOST_dsAtmStats_t)));
++
++ if (rc)
++ return;
++
++ /* Get ATM Stats for both US and DS for Channel 0*/
++ ptidsl->AppData.usAtm_count[0] = dslhal_support_byteSwap32(usAtmStats0.goodCount);
++ ptidsl->AppData.usIdle_count[0] = dslhal_support_byteSwap32(usAtmStats0.idleCount);
++#if SWTC
++ ptidsl->AppData.usPdu_count[0] = dslhal_support_byteSwap32(usAtmStats0.pduCount);
++#endif
++ ptidsl->AppData.dsGood_count[0] = dslhal_support_byteSwap32(dsAtmStats0.goodCount);
++ ptidsl->AppData.dsIdle_count[0] = dslhal_support_byteSwap32(dsAtmStats0.idleCount);
++#if SWTC
++ ptidsl->AppData.dsPdu_count[0] = dslhal_support_byteSwap32(dsAtmStats0.pduCount);
++#endif
++ ptidsl->AppData.dsBadHec_count[0] = dslhal_support_byteSwap32((dsAtmStats0.badHecCount));
++ ptidsl->AppData.dsOVFDrop_count[0] = dslhal_support_byteSwap32((dsAtmStats0.ovflwDropCount));
++ /* Get ATM Stats for both US and DS for Channel 1*/
++ ptidsl->AppData.usAtm_count[1] = dslhal_support_byteSwap32(usAtmStats1.goodCount);
++ ptidsl->AppData.usIdle_count[1] = dslhal_support_byteSwap32(usAtmStats1.idleCount);
++#if SWTC
++ ptidsl->AppData.usPdu_count[1] = dslhal_support_byteSwap32(usAtmStats1.pduCount);
++#endif
++ ptidsl->AppData.dsGood_count[1] = dslhal_support_byteSwap32(dsAtmStats1.goodCount);
++ ptidsl->AppData.dsIdle_count[1] = dslhal_support_byteSwap32(dsAtmStats1.idleCount);
++#if SWTC
++ ptidsl->AppData.dsPdu_count[1] = dslhal_support_byteSwap32(dsAtmStats1.pduCount);
++#endif
++ ptidsl->AppData.dsBadHec_count[1] = dslhal_support_byteSwap32((dsAtmStats1.badHecCount));
++ ptidsl->AppData.dsOVFDrop_count[1] = dslhal_support_byteSwap32((dsAtmStats1.ovflwDropCount));
++
++ /* Determine the US and DS Superframe Count */
++
++ dspOamSharedInterface.dspWriteSuperFrameCnt_p = (DEV_HOST_dspWrSuperFrameCntDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.dspWriteSuperFrameCnt_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.dspWriteSuperFrameCnt_p,&SuperFrameCnt, sizeof(DEV_HOST_dspWrSuperFrameCntDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ ptidsl->AppData.usSuperFrmCnt = dslhal_support_byteSwap32(SuperFrameCnt.wSuperFrameCntUstrm);
++ ptidsl->AppData.dsSuperFrmCnt = dslhal_support_byteSwap32(SuperFrameCnt.wSuperFrameCntDstrm);
++
++ /* Determine Frame Mode and Max Frame Mode */
++
++ dspOamSharedInterface.atucMsg_p = (DEV_HOST_msg_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.atucMsg_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.atucMsg_p,&atuc_msg, sizeof(DEV_HOST_msg_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++
++ ptidsl->AppData.FrmMode = (unsigned int)atuc_msg.framingMode;
++ ptidsl->AppData.MaxFrmMode = (unsigned int)atuc_msg.maxFrameMode;
++
++ /* Determine Gross Gain */
++
++ dspOamSharedInterface.aturMsg_p = (DEV_HOST_msg_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.aturMsg_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.aturMsg_p,&aturMsg, sizeof(DEV_HOST_msg_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ ptidsl->AppData.grossGain = (unsigned int)aturMsg.grossGain;
++
++ /* Determine DS Line Attenuation & Margin */
++ dspOamSharedInterface.eocVar_p = (DEV_HOST_eocVarDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.eocVar_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.eocVar_p,&eocVar, sizeof(DEV_HOST_eocVarDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ ptidsl->AppData.dsLineAttn = (unsigned int)eocVar.lineAtten;
++ ptidsl->AppData.dsMargin = (unsigned int)eocVar.dsMargin;
++ }
++ }
++
++ /* Read in the Shared Tables structure */
++ dspOamSharedInterface.dspWrSharedTables_p = (DEV_HOST_dspWrSharedTables_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.dspWrSharedTables_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.dspWrSharedTables_p,&sharedTables, sizeof(DEV_HOST_dspWrSharedTables_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++
++ /* Read the ATU-R Bits and Gains Table */
++ sharedTables.aturBng_p = (unsigned char *)dslhal_support_byteSwap32((unsigned int)sharedTables.aturBng_p);
++ rc = dslhal_support_blockRead((PVOID)sharedTables.aturBng_p,ptidsl->AppData.rBng,255*2*sizeof(unsigned char));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ /* Read the ATU-C Bits and Gains Table */
++ sharedTables.atucBng_p = (unsigned char *)dslhal_support_byteSwap32((unsigned int)sharedTables.atucBng_p);
++ if(ptidsl->netService == 2) /* for Annex_B */
++ {
++ rc = dslhal_support_blockRead((PVOID)sharedTables.atucBng_p,ptidsl->AppData.cBng,126*sizeof(unsigned char));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ for(i=0;i<US_BNG_LENGTH*2;i++)
++ usBits[i]=0;
++ for(i=1;i<US_BNG_LENGTH*2;i++)
++ {
++ usBits[i]=((ptidsl->AppData.cBng[(i-1)*2])&0xf);
++ dprintf(5,"Bit #%d : 0x%x\n",i,usBits[i]);
++ }
++ for(i=1;i<US_BNG_LENGTH*2;i++)
++ {
++ if(usBits[i])
++ usNumLoadedTones++;
++ }
++ }
++ else
++ {
++ rc = dslhal_support_blockRead((PVOID)sharedTables.atucBng_p,ptidsl->AppData.cBng,62*sizeof(unsigned char));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ for(i=0;i<US_BNG_LENGTH;i++)
++ usBits[i]=0;
++ for(i=1;i<US_BNG_LENGTH;i++)
++ {
++ usBits[i]=((ptidsl->AppData.cBng[(i-1)*2])&0xf);
++ dprintf(5,"Bit #%d : 0x%x\n",i,usBits[i]);
++ }
++ for(i=1;i<US_BNG_LENGTH;i++)
++ {
++ if(usBits[i])
++ usNumLoadedTones++;
++ }
++ }
++
++ /* Determine Number U/S of Loaded Tones */
++
++ /* U/S Power Computation */
++ dspOamSharedInterface.phyPerf_p = (DEV_HOST_phyPerf_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.phyPerf_p);
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.phyPerf_p,
++ &phyPerf, sizeof(DEV_HOST_phyPerf_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ ptidsl->AppData.currentHybridNum = phyPerf.currentHybridNumUsed;
++ phyPerf.usAvgGain = dslhal_support_byteSwap32(phyPerf.usAvgGain);
++ ptidsl->AppData.usTxPower = LOG43125 + phyPerf.usAvgGain + (256*US_NOMINAL_POWER)+log10[usNumLoadedTones-1];
++ dprintf(7,"Avg Gain: 0x%x usNumLoadedTones: 0x%x log: 0x%x\n",phyPerf.usAvgGain, usNumLoadedTones, log10[usNumLoadedTones-1]);
++
++ /* Determine Number D/S of Loaded Tones */
++ dsBits[0]=0;
++ for(i=0;i<DS_BNG_LENGTH;i++)
++ {
++ dsBits[i]=0;
++ /* ptidsl->AppData.rBng[i-1]=dslhal_support_byteSwap32((unsigned int)ptidsl->AppData.rBng[i-1]);*/
++ }
++ for(i=1;i<DS_BNG_LENGTH;i++)
++ {
++ dsBits[i]=((ptidsl->AppData.rBng[(i-1)*2])&0xf);
++ dprintf(5,"Bit #%d : 0x%x\n",i,dsBits[i]);
++ }
++ for(i=1;i<DS_BNG_LENGTH;i++)
++ {
++ if(dsBits[i])
++ dsNumLoadedTones++;
++ }
++ /* D/S Power Computation */
++ dspOamSharedInterface.phyPerf_p = (DEV_HOST_phyPerf_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.phyPerf_p);
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.phyPerf_p,
++ &phyPerf, sizeof(DEV_HOST_phyPerf_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ /* D/S Power Cutback */
++ dsPowerCutBack = (unsigned char)((((ptidsl->AppData.bCMsgs1[0]) >>6) &0x3)+(((ptidsl->AppData.bCMsgs1[1]) &0x1) <<2));
++ phyPerf.dsAvgGain = dslhal_support_byteSwap32(phyPerf.dsAvgGain);
++ ptidsl->AppData.dsTxPower = LOG43125 + phyPerf.dsAvgGain + (256*((2*(dsPowerCutBack-1))-52)) + log10[dsNumLoadedTones-1];
++ dprintf(7,"Avg Gain: %d dsNumLoadedTones: %d log: %d pcb: %d \n",phyPerf.dsAvgGain, dsNumLoadedTones, log10[dsNumLoadedTones-1], dsPowerCutBack);
++ /* ds bit allocation */
++ sharedTables.bitAllocTblDstrm_p = (unsigned char *)dslhal_support_byteSwap32((unsigned int)sharedTables.bitAllocTblDstrm_p);
++ rc = dslhal_support_blockRead((PVOID)sharedTables.bitAllocTblDstrm_p,ptidsl->AppData.BitAllocTblDstrm, 256*sizeof(unsigned char));
++ if(rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed \n");
++ return;
++ }
++
++ /* us bit allocation */
++ sharedTables.bitAllocTblUstrm_p = (unsigned char *)dslhal_support_byteSwap32((unsigned int)sharedTables.bitAllocTblUstrm_p);
++ rc = dslhal_support_blockRead((PVOID)sharedTables.bitAllocTblUstrm_p,ptidsl->AppData.BitAllocTblUstrm, 32*sizeof(unsigned char));
++ if(rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed \n");
++ return;
++ }
++ /* margin per tone */
++ sharedTables.marginTblDstrm_p = (signed char *)dslhal_support_byteSwap32((unsigned int)sharedTables.marginTblDstrm_p);
++ rc = dslhal_support_blockRead((PVOID)sharedTables.marginTblDstrm_p,ptidsl->AppData.marginTblDstrm, 256*sizeof(signed char));
++ if(rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed \n");
++ return;
++ }
++ /* Read Configured Options */
++ dspOamSharedInterface.oamWriteNegoParams_p = (DEV_HOST_oamWrNegoParaDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.oamWriteNegoParams_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.oamWriteNegoParams_p,
++ &configParms, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ else
++ {
++ /* r-Msg1 */
++ ptidsl->AppData.StdMode = (unsigned int)configParms.stdMode;
++ if(configParms.stdMode == T1413_MODE)
++ ptidsl->AppData.StdMode = DSLTRAIN_T1413_MODE;
++ if(configParms.stdMode == GDMT_MODE)
++ ptidsl->AppData.StdMode = DSLTRAIN_GDMT_MODE;
++ if(configParms.stdMode == MULTI_MODE)
++ ptidsl->AppData.StdMode = DSLTRAIN_MULTI_MODE;
++
++ shim_osMoveMemory((void *)ptidsl->AppData.bRMsgs1, (void *)configParms.rMsgs1, 6*sizeof(char));
++ if((ptidsl->AppData.bRMsgs1[2] & 0x02) == 0x02)
++ {
++ dprintf(7,"Trellis!\n");
++ ptidsl->configFlag |= CONFIG_FLAG_TRELLIS;
++ }
++ else
++ ptidsl->configFlag &= ~CONFIG_FLAG_TRELLIS;
++ if(ptidsl->AppData.bRMsgs1[2]&0x01)
++ ptidsl->configFlag |= CONFIG_FLAG_EC;
++ else
++ ptidsl->configFlag &= ~CONFIG_FLAG_EC;
++ }
++ return;
++}
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_initStatistics()
++*
++*********************************************************************************************
++* DESCRIPTION: init statistical information of ax5 modem daugter card.
++*
++* Input: tidsl_t *ptidsl
++*
++* Return: NULL
++*
++********************************************************************************************/
++void dslhal_api_initStatistics(tidsl_t * ptidsl)
++{
++ int rc;
++ /*TCHostCommDef TCHostCommParms; */
++ int optIdxU, optIdxD;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ DEV_HOST_dspWrNegoParaDef_t rateparms;
++ DEV_HOST_modemStatsDef_t StatisticsDef;
++ DEV_HOST_errorStats_t usIntlvError, usFastError, dsIntlvError, dsFastError;
++ DEV_HOST_atmStats_t atmStats;
++ DEV_HOST_usAtmStats_t usAtmStats0, usAtmStats1;
++ DEV_HOST_dsAtmStats_t dsAtmStats0,dsAtmStats1;
++ DEV_HOST_dspWrSuperFrameCntDef_t SuperFrameCnt;
++ DEV_HOST_msg_t atuc_msg, aturMsg;
++ DEV_HOST_eocVarDef_t eocVar;
++
++ dprintf(5, "dslhal_api_initStatistics\n");
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterface_t *) ptidsl->pmainAddr;
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ dspOamSharedInterface.dspWriteNegoParams_p = (DEV_HOST_dspWrNegoParaDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.dspWriteNegoParams_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.dspWriteNegoParams_p,&rateparms, sizeof(DEV_HOST_dspWrNegoParaDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ if(!rc)
++ {
++ /* shim_osMoveMemory((void *)ptidsl->AppData.bCRates1, (void *)rateparms.cRates1, SIZE_OF_CRATES1_TABLE); */
++ ptidsl->AppData.bCRates2 = rateparms.cRates2;
++ /* shim_osMoveMemory((void *)ptidsl->AppData.bRRates1, (void *)rateparms.rRates1, 44); */
++ ptidsl->AppData.bRRates2 = rateparms.rRates2;
++ shim_osMoveMemory((void *)ptidsl->AppData.bCMsgs1, (void *)rateparms.cMsgs1, 6);
++ shim_osMoveMemory((void *)ptidsl->AppData.bCMsgs2, (void *)rateparms.cMsgs2, 4);
++ shim_osMoveMemory((void *)ptidsl->AppData.bRMsgs2, (void *)rateparms.rMsgs2, 4);
++
++ ptidsl->AppData.atucVendorId = dslhal_support_byteSwap32((unsigned int)rateparms.atucVendorId);
++ ptidsl->AppData.lineLength = (unsigned int)dslhal_support_byteSwap16((unsigned short)rateparms.lineLength);
++ ptidsl->AppData.atucRevisionNum = rateparms.atucGhsRevisionNum;
++ ptidsl->AppData.usLineAttn = (ptidsl->AppData.bCMsgs2[3] >>2)&0x003f;
++ ptidsl->AppData.usMargin = (ptidsl->AppData.bCMsgs2[2])&0x001f;
++
++ /* Get the UpStream Connection Rate */
++ /* Based on the Bit Pattern Get the Opt# */
++ if((rateparms.cRates2 & 0x0f) == 0x01)
++ optIdxU = 0;
++ else if((rateparms.cRates2 & 0x0f) == 0x02)
++ optIdxU = 1;
++ else if((rateparms.cRates2 & 0x0f) == 0x04)
++ optIdxU = 2;
++ else if((rateparms.cRates2 & 0x0f) == 0x08)
++ optIdxU = 3;
++ else
++ optIdxU = -1;
++ dprintf(5, "optIdxU=%d\n", optIdxU);
++ /* Obtain the US Rates using Opt# and CRates1 Table */
++ /* Rate(US) = [Bf(LS0) + Bi(LS0)]*32 */
++ if(ptidsl->AppData.dsl_modulation <= DSLTRAIN_GLITE_MODE)
++ ptidsl->AppData.USConRate = ((rateparms.cRates1[optIdxU][CRATES1_BF_LS0] + rateparms.cRates1[optIdxU][CRATES1_BI_LS0]) * 32);
++ else
++ ptidsl->AppData.USConRate = dslhal_support_byteSwap16((unsigned short)rateparms.adsl2USRate);
++ ptidsl->AppData.USPeakCellRate = ptidsl->AppData.USConRate;
++
++ /* Get the DownStream Connection Rate */
++ /* Based on the Bit Pattern Get the Opt# */
++ if(((rateparms.cRates2 >> 4) & 0x0f) == 0x01)
++ optIdxD = 0;
++ else if(((rateparms.cRates2 >> 4) & 0x0f) == 0x02)
++ optIdxD = 1;
++ else if(((rateparms.cRates2 >> 4) & 0x0f) == 0x04)
++ optIdxD = 2;
++ else if(((rateparms.cRates2 >> 4) & 0x0f) == 0x08)
++ optIdxD = 3;
++ else
++ optIdxD = -1;
++ /* Obtain the DS Rates using Opt# and CRates1 Table */
++ /* Rate(DS) = [Bf(AS0) + Bi(AS0)]*32 */
++ if(ptidsl->AppData.dsl_modulation <= DSLTRAIN_GLITE_MODE)
++ ptidsl->AppData.DSConRate = (((rateparms.cRates1[optIdxD][CRATES1_BF_AS0]|((rateparms.cRates1[optIdxD][CRATES1_BF_DSRS]&0x80)<<1))+ (rateparms.cRates1[optIdxD][CRATES1_BI_AS0]|((rateparms.cRates1[optIdxD][CRATES1_BI_DSRS]&0x80)<<1)))* 32);
++ else
++ ptidsl->AppData.DSConRate = dslhal_support_byteSwap16((unsigned short)rateparms.adsl2DSRate);
++ dprintf(5, "ptidsl->AppData.wDSConRate=%d\n", ptidsl->AppData.DSConRate);
++ /* Determine which Path has Modem Trained with */
++ if((rateparms.cRates1[optIdxU][CRATES1_BF_LS0]) && (rateparms.cRates1[optIdxD][CRATES1_BF_AS0]))
++ ptidsl->AppData.TrainedPath = FAST_PATH;
++ else
++ ptidsl->AppData.TrainedPath = INTERLEAVED_PATH;
++
++ /* Set the mode in which the modem is trained */
++ ptidsl->AppData.TrainedMode = (unsigned int)rateparms.trainMode;
++ if(rateparms.trainMode == T1413_MODE)
++ ptidsl->AppData.TrainedMode = DSLTRAIN_T1413_MODE;
++ if(rateparms.trainMode == GDMT_MODE)
++ ptidsl->AppData.TrainedMode = DSLTRAIN_GDMT_MODE;
++
++ if(ptidsl->AppData.TrainedPath == FAST_PATH)
++ ptidsl->AppData.dsFastParityBytesPerSymbol = (rateparms.cRates1[optIdxU][CRATES1_BF_DSRS]&0x1f);
++ else
++ ptidsl->AppData.dsIntlvParityBytesPerSymbol = (rateparms.cRates1[optIdxU][CRATES1_BI_DSRS]&0x1f);
++ ptidsl->AppData.dsSymbolsPerCodeWord = (rateparms.cRates1[optIdxU][CRATES1_BFI_DSS]&0x1f);
++ ptidsl->AppData.dsInterleaverDepth = ((rateparms.cRates1[optIdxU][CRATES1_BFI_DSI])|((rateparms.cRates1[optIdxU][CRATES1_BFI_DSS]&0xc0)<<2));
++
++ if(ptidsl->AppData.TrainedPath == FAST_PATH)
++ ptidsl->AppData.usFastParityBytesPerSymbol = (rateparms.cRates1[optIdxU][CRATES1_BF_USRS]&0x1f);
++ else
++ ptidsl->AppData.usIntlvParityBytesPerSymbol = (rateparms.cRates1[optIdxU][CRATES1_BI_USRS]&0x1f);
++ ptidsl->AppData.usSymbolsPerCodeWord = (rateparms.cRates1[optIdxU][CRATES1_BFI_USS]&0x1f);
++ ptidsl->AppData.usInterleaverDepth = ((rateparms.cRates1[optIdxU][CRATES1_BFI_USI])|((rateparms.cRates1[optIdxU][CRATES1_BFI_USS]&0xc0)<<2));
++ }
++
++ /* get the Statistics itself */
++
++ dspOamSharedInterface.modemStats_p = (DEV_HOST_modemStatsDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.modemStats_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.modemStats_p,&StatisticsDef, sizeof(DEV_HOST_modemStatsDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++
++ /* Populate the Error Structure Variables */
++
++ /* US Interleave Path Error Statistics */
++
++ /* Change the endianness of the Pointer */
++ StatisticsDef.usErrorStatsIntlv_p = (DEV_HOST_errorStats_t *) dslhal_support_byteSwap32((unsigned int)StatisticsDef.usErrorStatsIntlv_p);
++
++ rc = dslhal_support_blockRead((PVOID)StatisticsDef.usErrorStatsIntlv_p,&usIntlvError, (sizeof(DEV_HOST_errorStats_t)));
++
++ if (rc)
++ return;
++
++ /* DS Interleave Path Error Statistics */
++
++ /* Change the endianness of the Pointer */
++ StatisticsDef.dsErrorStatsIntlv_p = (DEV_HOST_errorStats_t *) dslhal_support_byteSwap32((unsigned int)StatisticsDef.dsErrorStatsIntlv_p);
++
++ rc = dslhal_support_blockRead((PVOID)StatisticsDef.dsErrorStatsIntlv_p,&dsIntlvError, (sizeof(DEV_HOST_errorStats_t)));
++
++ if (rc)
++ return;
++
++ /* US Fast Path Error Statistics */
++
++ /* Change the endianness of the Pointer */
++ StatisticsDef.usErrorStatsFast_p = (DEV_HOST_errorStats_t *) dslhal_support_byteSwap32((unsigned int)StatisticsDef.usErrorStatsFast_p);
++
++ rc = dslhal_support_blockRead((PVOID)StatisticsDef.usErrorStatsFast_p,&usFastError, (sizeof(DEV_HOST_errorStats_t)));
++
++ if (rc)
++ return;
++
++
++ /* DS Fast Path Error Statistics */
++
++ /* Change the endianness of the Pointer */
++ StatisticsDef.dsErrorStatsFast_p = (DEV_HOST_errorStats_t *) dslhal_support_byteSwap32((unsigned int)StatisticsDef.dsErrorStatsFast_p);
++
++ rc = dslhal_support_blockRead((PVOID)StatisticsDef.dsErrorStatsFast_p,&dsFastError, (sizeof(DEV_HOST_errorStats_t)));
++
++ if (rc)
++ return;
++
++ if(ptidsl->AppData.bState > 2)
++ {
++ /* Get CRC Errors Stats for both US and DS */
++ ptidsl->AppData.dsICRC_errors = dslhal_support_byteSwap32((unsigned int)dsIntlvError.crcErrors);
++ ptidsl->AppData.dsFCRC_errors = dslhal_support_byteSwap32((unsigned int)dsFastError.crcErrors);
++ ptidsl->AppData.usICRC_errors = dslhal_support_byteSwap32((unsigned int)usIntlvError.crcErrors);
++ ptidsl->AppData.usFCRC_errors = dslhal_support_byteSwap32((unsigned int)usFastError.crcErrors);
++ /* Get FEC Errors Stats for both US and DS */
++ ptidsl->AppData.dsIFEC_errors = dslhal_support_byteSwap32((unsigned int)dsIntlvError.fecErrors);
++ ptidsl->AppData.dsFFEC_errors = dslhal_support_byteSwap32((unsigned int)dsFastError.fecErrors);
++ ptidsl->AppData.usIFEC_errors = dslhal_support_byteSwap32((unsigned int)usIntlvError.fecErrors);
++ ptidsl->AppData.usFFEC_errors = dslhal_support_byteSwap32((unsigned int)usFastError.fecErrors);
++ /* Get NCD Errors Stats for both US and DS */
++ ptidsl->AppData.dsINCD_error = dslhal_support_byteSwap32((unsigned int)dsIntlvError.ncdError);
++ ptidsl->AppData.dsFNCD_error = dslhal_support_byteSwap32((unsigned int)dsFastError.ncdError);
++ ptidsl->AppData.usINCD_error = dslhal_support_byteSwap32((unsigned int)usIntlvError.ncdError);
++ ptidsl->AppData.usFNCD_error = dslhal_support_byteSwap32((unsigned int)usFastError.ncdError);
++ /* Get LCD Errors Stats for both US and DS */
++ ptidsl->AppData.dsILCD_errors = dslhal_support_byteSwap32((unsigned int)dsIntlvError.lcdErrors);
++ ptidsl->AppData.dsFLCD_errors = dslhal_support_byteSwap32((unsigned int)dsFastError.lcdErrors);
++ ptidsl->AppData.usILCD_errors = dslhal_support_byteSwap32((unsigned int)usIntlvError.lcdErrors);
++ ptidsl->AppData.usFLCD_errors = dslhal_support_byteSwap32((unsigned int)usFastError.lcdErrors);
++ /*Get HEC Errors Stats for both US and DS */
++ ptidsl->AppData.dsIHEC_errors = dslhal_support_byteSwap32((unsigned int)dsIntlvError.hecErrors);
++ ptidsl->AppData.dsFHEC_errors = dslhal_support_byteSwap32((unsigned int)dsFastError.hecErrors);
++ ptidsl->AppData.usIHEC_errors = dslhal_support_byteSwap32((unsigned int)usIntlvError.hecErrors);
++ ptidsl->AppData.usFHEC_errors = dslhal_support_byteSwap32((unsigned int)usFastError.hecErrors);
++
++ /* Get LOS and SEF error Stats */
++ ptidsl->AppData.LOS_errors = dslhal_support_byteSwap32(StatisticsDef.losErrors);
++ ptidsl->AppData.SEF_errors = dslhal_support_byteSwap32(StatisticsDef.sefErrors);
++ ptidsl->AppData.coLosErrors = dslhal_support_byteSwap32(StatisticsDef.farEndLosErrors);
++ ptidsl->AppData.coRdiErrors = dslhal_support_byteSwap32(StatisticsDef.farEndRdiErrors);
++
++ dspOamSharedInterface.atmStats_p = (DEV_HOST_atmStats_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.atmStats_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.atmStats_p,&atmStats, sizeof(DEV_HOST_atmStats_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++
++ /* Populate the US/DS ATM Stats Variables */
++
++ /* US ATM Statistics */
++
++ /* Change the endianness of the Pointer */
++ atmStats.us0_p = (DEV_HOST_usAtmStats_t *) dslhal_support_byteSwap32((unsigned int)atmStats.us0_p);
++
++ rc = dslhal_support_blockRead((PVOID)atmStats.us0_p,&usAtmStats0, (sizeof(DEV_HOST_usAtmStats_t)));
++
++ if (rc)
++ return;
++
++ /* Change the endianness of the Pointer */
++ atmStats.us1_p = (DEV_HOST_usAtmStats_t *) dslhal_support_byteSwap32((unsigned int)atmStats.us1_p);
++
++ rc = dslhal_support_blockRead((PVOID)atmStats.us1_p,&usAtmStats1, (sizeof(DEV_HOST_usAtmStats_t)));
++
++ if (rc)
++ return;
++
++
++ /* DS ATM Statistics */
++
++ /* Change the endianness of the Pointer */
++ atmStats.ds0_p = (DEV_HOST_dsAtmStats_t *) dslhal_support_byteSwap32((unsigned int)atmStats.ds0_p);
++
++ rc = dslhal_support_blockRead((PVOID)atmStats.ds0_p,&dsAtmStats0, (sizeof(DEV_HOST_dsAtmStats_t)));
++
++ if (rc)
++ return;
++
++ /* Change the endianness of the Pointer */
++ atmStats.ds1_p = (DEV_HOST_dsAtmStats_t *) dslhal_support_byteSwap32((unsigned int)atmStats.ds1_p);
++
++ rc = dslhal_support_blockRead((PVOID)atmStats.ds1_p,&dsAtmStats1, (sizeof(DEV_HOST_dsAtmStats_t)));
++
++ if (rc)
++ return;
++ /* Get ATM Stats for both US and DS Channel 0*/
++ ptidsl->AppData.usAtm_count[0] = dslhal_support_byteSwap32(usAtmStats0.goodCount);
++ ptidsl->AppData.usIdle_count[0] = dslhal_support_byteSwap32(usAtmStats0.idleCount);
++#if SWTC
++ ptidsl->AppData.usPdu_count[0] = dslhal_support_byteSwap32(usAtmStats0.pduCount);
++#endif
++ ptidsl->AppData.dsGood_count[0] = dslhal_support_byteSwap32(dsAtmStats0.goodCount);
++ ptidsl->AppData.dsIdle_count[0] = dslhal_support_byteSwap32(dsAtmStats0.idleCount);
++#if SWTC
++ ptidsl->AppData.dsPdu_count[0] = dslhal_support_byteSwap32(dsAtmStats0.pduCount);
++#endif
++ ptidsl->AppData.dsBadHec_count[0] = dslhal_support_byteSwap32((dsAtmStats0.badHecCount));
++ ptidsl->AppData.dsOVFDrop_count[0] = dslhal_support_byteSwap32((dsAtmStats0.ovflwDropCount));
++
++ /* Get ATM Stats for both US and DS Channel 1*/
++ ptidsl->AppData.usAtm_count[1] = dslhal_support_byteSwap32(usAtmStats1.goodCount);
++ ptidsl->AppData.usIdle_count[1] = dslhal_support_byteSwap32(usAtmStats1.idleCount);
++#if SWTC
++ ptidsl->AppData.usPdu_count[1] = dslhal_support_byteSwap32(usAtmStats1.pduCount);
++#endif
++ ptidsl->AppData.dsGood_count[1] = dslhal_support_byteSwap32(dsAtmStats1.goodCount);
++ ptidsl->AppData.dsIdle_count[1] = dslhal_support_byteSwap32(dsAtmStats1.idleCount);
++#if SWTC
++ ptidsl->AppData.dsPdu_count[1] = dslhal_support_byteSwap32(dsAtmStats1.pduCount);
++#endif
++ ptidsl->AppData.dsBadHec_count[1] = dslhal_support_byteSwap32((dsAtmStats1.badHecCount));
++ ptidsl->AppData.dsOVFDrop_count[1] = dslhal_support_byteSwap32((dsAtmStats1.ovflwDropCount));
++
++
++ /* Determine the US and DS Superframe Count */
++
++ dspOamSharedInterface.dspWriteSuperFrameCnt_p = (DEV_HOST_dspWrSuperFrameCntDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.dspWriteSuperFrameCnt_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.dspWriteSuperFrameCnt_p,&SuperFrameCnt, sizeof(DEV_HOST_dspWrSuperFrameCntDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++
++ ptidsl->AppData.usSuperFrmCnt = dslhal_support_byteSwap32(SuperFrameCnt.wSuperFrameCntUstrm);
++ ptidsl->AppData.dsSuperFrmCnt = dslhal_support_byteSwap32(SuperFrameCnt.wSuperFrameCntDstrm);
++
++ /* Determine Frame Mode and Max Frame Mode */
++
++ dspOamSharedInterface.atucMsg_p = (DEV_HOST_msg_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.atucMsg_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.atucMsg_p,&atuc_msg, sizeof(DEV_HOST_msg_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++
++ ptidsl->AppData.FrmMode = (unsigned int)atuc_msg.framingMode;
++ ptidsl->AppData.MaxFrmMode = (unsigned int)atuc_msg.maxFrameMode;
++
++ /* Determine Gross Gain */
++
++ dspOamSharedInterface.aturMsg_p = (DEV_HOST_msg_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.aturMsg_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.aturMsg_p,&aturMsg, sizeof(DEV_HOST_msg_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++ ptidsl->AppData.grossGain = (unsigned int)aturMsg.grossGain;
++ /* Determine DS Line Attenuation & Margin */
++ dspOamSharedInterface.eocVar_p = (DEV_HOST_eocVarDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.eocVar_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.eocVar_p,&eocVar, sizeof(DEV_HOST_eocVarDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return;
++ }
++
++ ptidsl->AppData.dsLineAttn = (unsigned int)eocVar.lineAtten;
++ ptidsl->AppData.dsMargin = (unsigned int)eocVar.dsMargin;
++ }
++
++#if __HOST_FORINTERNALUSEONLY_R_H__
++ ptidsl->AppData.BER = dslhal_INTERNAL_computeAtmBitErrorRate(ptidsl);
++#endif
++ dprintf(5, "initstatistics done\n");
++ return;
++ }
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_disableLosAlarm(tidsl_t *ptidsl,unsigned int set)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction enables/disables all the LOS alarms
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * unsigned int set; //if set is TRUE: LOS Alarms are disabled else enabled
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ * NOTES: Currently not supported in any version other than MR4 Patch release..
++ *****************************************************************************************/
++unsigned int dslhal_api_disableLosAlarm(tidsl_t *ptidsl,unsigned int set)
++{
++ DEV_HOST_oamWrNegoParaDef_t NegoPara;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ int rc;
++ dprintf(5," dslhal_api_setTrainingMode()\n");
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,
++ sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.oamWriteNegoParams_p = (DEV_HOST_oamWrNegoParaDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.oamWriteNegoParams_p);
++
++ rc = dslhal_support_blockRead((PVOID) dspOamSharedInterface.oamWriteNegoParams_p,&NegoPara, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ if(set)
++ {
++ NegoPara.disableLosAlarm = TRUE;
++ /* NegoPara.marginMonitorTrning = TRUE;
++ NegoPara.marginMonitorShwtme = TRUE;*/
++ }
++ else
++ {
++ NegoPara.disableLosAlarm = FALSE;
++ /* NegoPara.marginMonitorTrning = FALSE;
++ NegoPara.marginMonitorShwtme = FALSE;*/
++ }
++
++ rc = dslhal_support_blockWrite(&NegoPara,(PVOID)dspOamSharedInterface.oamWriteNegoParams_p, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++ if(rc)
++ return DSLHAL_ERROR_CONFIG_API_FAILURE;
++ dprintf(5," dslhal_api_disableLosAlarm() Done\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_setMarginThreshold(tidsl_t *ptidsl,int threshold)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction does sets the Margin threshold
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * int threshold
++ *
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_setMarginThreshold(tidsl_t *ptidsl, int threshold)
++{
++ DEV_HOST_oamWrNegoParaDef_t NegoPara;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ int rc;
++
++ dprintf(5," dslhal_ctrl_setThreshold()\n");
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.oamWriteNegoParams_p = (DEV_HOST_oamWrNegoParaDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.oamWriteNegoParams_p);
++
++
++ rc = dslhal_support_blockRead((PVOID) dspOamSharedInterface.oamWriteNegoParams_p,&NegoPara, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ NegoPara.marginThreshold = threshold;
++
++ rc = dslhal_support_blockWrite(&NegoPara,dspOamSharedInterface.oamWriteNegoParams_p, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++
++ if(rc)
++ return DSLHAL_ERROR_MARGIN_API_FAILURE;
++
++ dprintf(5," dslhal_api_setThreshold() Done\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_setMonitorFlags(tidsl_t *ptidsl, unsigned int trainflag,unsigned int shwtflag)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction does sets the Margin monitoring flag
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * unsigned int trainflag
++ * unsigned int shwtflag
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_setMarginMonitorFlags(tidsl_t *ptidsl,unsigned int trainflag,unsigned int shwtflag)
++{
++ DEV_HOST_oamWrNegoParaDef_t NegoPara;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ int rc;
++
++ dprintf(5," dslhal_ctrl_setMonitorFlags()\n");
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.oamWriteNegoParams_p = (DEV_HOST_oamWrNegoParaDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.oamWriteNegoParams_p);
++
++
++ rc = dslhal_support_blockRead((PVOID) dspOamSharedInterface.oamWriteNegoParams_p,&NegoPara, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ if (trainflag)
++ {
++ NegoPara.marginMonitorTrning = TRUE;
++ }
++ else
++ {
++ NegoPara.marginMonitorTrning = FALSE;
++ }
++ if (shwtflag)
++ {
++ NegoPara.marginMonitorShwtme = TRUE;
++ }
++ else
++ {
++ NegoPara.marginMonitorShwtme = FALSE;
++ }
++
++ rc = dslhal_support_blockWrite(&NegoPara,dspOamSharedInterface.oamWriteNegoParams_p, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++ if(rc)
++ return DSLHAL_ERROR_MARGIN_API_FAILURE;
++ dprintf(5," dslhal_api_setMonitorFlags() Done\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_setEocSerialNumber(tidsl_t *ptidsl,char *SerialNum)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction Sets the eoc Serial Number
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * char *SerialNum : Input eoc Serial Number
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_setEocSerialNumber(tidsl_t *ptidsl,char *SerialNumber)
++{
++ DEV_HOST_eocVarDef_t eocVar;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ int rc;
++ dprintf(5," dslhal_api_setEocSerialNumber()\n");
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.eocVar_p = (DEV_HOST_eocVarDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.eocVar_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.eocVar_p,
++ &eocVar, sizeof(DEV_HOST_eocVarDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ shim_osMoveMemory(eocVar.serialNumber,SerialNumber,32);
++
++ rc= dslhal_support_blockWrite(&eocVar,dspOamSharedInterface.eocVar_p,sizeof(DEV_HOST_eocVarDef_t));
++ if(rc)
++ return DSLHAL_ERROR_EOCREG_API_FAILURE;
++ dprintf(5," dslhal_api_setEocSerialNumber() Done\n");
++
++ return DSLHAL_ERROR_NO_ERRORS;
++
++}
++
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_setEocVendorId(tidsl_t *ptidsl,char *VendorID)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction Sets the eoc Vendor ID
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * char *VendorID : Input eoc Vendor ID
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_setEocVendorId(tidsl_t *ptidsl,char *VendorID)
++{
++ DEV_HOST_oamWrNegoParaDef_t NegoPara;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ int rc;
++ dprintf(5," dslhal_api_setEocVendorId()\n");
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.oamWriteNegoParams_p = (DEV_HOST_oamWrNegoParaDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.oamWriteNegoParams_p);
++
++
++ rc = dslhal_support_blockRead((PVOID) dspOamSharedInterface.oamWriteNegoParams_p,&NegoPara, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ shim_osMoveMemory(NegoPara.gdmtVendorId,VendorID,8);
++ rc= dslhal_support_blockWrite(&NegoPara,dspOamSharedInterface.oamWriteNegoParams_p, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++ if(rc)
++ return DSLHAL_ERROR_EOCREG_API_FAILURE;
++
++ dprintf(5," dslhal_api_setEocVendorId() Done\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_setEocRevisionNumber(tidsl_t *ptidsl,char *RevNum)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction Sets the eoc Revision Number
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * char *RevNum : Input eoc Revision Number
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_setEocRevisionNumber(tidsl_t *ptidsl,char *RevNumber)
++{
++
++ DEV_HOST_eocVarDef_t eocVar;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ int rc;
++ /*add for UR2 test */
++ UINT8 selfTestResults[2];
++ memset(selfTestResults,0x00,sizeof(selfTestResults));
++ /* add for UR2 test */
++ dprintf(5," dslhal_api_setEocRevisionNumber()\n");
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.eocVar_p = (DEV_HOST_eocVarDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.eocVar_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.eocVar_p,
++ &eocVar, sizeof(DEV_HOST_eocVarDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ shim_osMoveMemory(eocVar.revNumber,RevNumber,4);
++ /* add for UR2 test */
++ shim_osMoveMemory(eocVar.dummy,selfTestResults,2);
++ /* add for UR2 test */
++ rc=dslhal_support_blockWrite(&eocVar,dspOamSharedInterface.eocVar_p,sizeof(DEV_HOST_eocVarDef_t));
++ if(rc)
++ return DSLHAL_ERROR_EOCREG_API_FAILURE;
++ dprintf(5," dslhal_api_setEocRevisionNumber Done\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_setAturConfig(tidsl_t *ptidsl,char *ATURConfig)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction Sets the eoc ATUR Config Register
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * char *ATURConfig : Input eoc ATUR Config Register
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_setAturConfig(tidsl_t *ptidsl,char *ATURConfig)
++{
++
++ DEV_HOST_eocVarDef_t eocVar;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ int rc;
++ dprintf(5," dslhal_api_setAturConfig()\n");
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.eocVar_p = (DEV_HOST_eocVarDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.eocVar_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.eocVar_p,
++ &eocVar, sizeof(DEV_HOST_eocVarDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ shim_osMoveMemory(eocVar.aturConfig,ATURConfig,30);
++ rc= dslhal_support_blockWrite(&eocVar,dspOamSharedInterface.eocVar_p,sizeof(DEV_HOST_eocVarDef_t));
++ if(rc)
++ return DSLHAL_ERROR_EOCREG_API_FAILURE;
++ dprintf(5," dslhal_api_setAturConfig() Done\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_setRateAdaptFlag(tidsl_t *ptidsl,unsigned int flag)
++*
++*******************************************************************************************
++* DESCRIPTION: This fuction Sets the Rate Adapt Enable Flag
++*
++* INPUT: PITIDSLHW_T *ptidsl
++* unsigned int flag; //if flag = TRUE set rateadapt flag else reset it
++* RETURN: 0 SUCCESS
++* 1 FAILED
++*
++*****************************************************************************************/
++unsigned int dslhal_api_setRateAdaptFlag(tidsl_t *ptidsl,unsigned int flag)
++{
++ DEV_HOST_msg_t aturMsg;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ int rc;
++ dprintf(5," dslhal_api_setRateAdaptFlag()\n");
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.aturMsg_p = (DEV_HOST_msg_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.aturMsg_p);
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.aturMsg_p,
++ &aturMsg, sizeof(DEV_HOST_msg_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ if(flag)
++ aturMsg.rateAdapt = TRUE;
++ else
++ aturMsg.rateAdapt = FALSE;
++
++ rc= dslhal_support_blockWrite(&aturMsg,dspOamSharedInterface.aturMsg_p,sizeof(DEV_HOST_msg_t));
++ if(rc)
++ return DSLHAL_ERROR_CONFIG_API_FAILURE;
++ dprintf(5," dslhal_api_setRateAdaptFlag() Done\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_setTrellisFlag(tidsl_t *ptidsl,unsigned int flag)
++*
++*******************************************************************************************
++* DESCRIPTION: This fuction Sets the Trellis Coding Enable Flag
++*
++* INPUT: PITIDSLHW_T *ptidsl
++* unsigned int flag; // if flag = TRUE, set trellis flag else reset
++* RETURN: 0 SUCCESS
++* 1 FAILED
++*
++*****************************************************************************************/
++unsigned int dslhal_api_setTrellisFlag(tidsl_t *ptidsl,unsigned int flag)
++{
++
++ DEV_HOST_msg_t aturMsg;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ DEV_HOST_oamWrNegoParaDef_t negoPara;
++ int rc;
++ dprintf(5," dslhal_api_setTrellisFlag()\n");
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.aturMsg_p = (DEV_HOST_msg_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.aturMsg_p);
++ rc += dslhal_support_blockRead((PVOID)dspOamSharedInterface.aturMsg_p,&aturMsg, sizeof(DEV_HOST_msg_t));
++ dspOamSharedInterface.oamWriteNegoParams_p = (DEV_HOST_oamWrNegoParaDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.oamWriteNegoParams_p);
++ rc += dslhal_support_blockRead((PVOID) dspOamSharedInterface.oamWriteNegoParams_p,&negoPara, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ if(flag)
++ {
++ aturMsg.trellis = TRUE;
++ negoPara.rMsgs1[2] |= 0x02;
++ }
++ else
++ {
++ aturMsg.trellis = FALSE;
++ negoPara.rMsgs1[2] &= 0xFD;
++ }
++ rc=0;
++ rc+=dslhal_support_blockWrite(&aturMsg,dspOamSharedInterface.aturMsg_p,sizeof(DEV_HOST_msg_t));
++ rc+= dslhal_support_blockWrite(&negoPara,dspOamSharedInterface.oamWriteNegoParams_p, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++ if(rc)
++ return DSLHAL_ERROR_CONFIG_API_FAILURE;
++
++ dprintf(5," dslhal_api_setTrellisFlag() Done\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_setMaxBitsPerCarrier(tidsl_t *ptidsl,unsigned int maxbits)
++*
++*******************************************************************************************
++* DESCRIPTION: This fuction Sets the Maximum bits per carrier value
++*
++* INPUT: PITIDSLHW_T *ptidsl
++* unsigned int maxbits : should be a value between 0-15
++*
++* RETURN: 0 SUCCESS
++* 1 FAILED
++*
++*****************************************************************************************/
++unsigned int dslhal_api_setMaxBitsPerCarrier(tidsl_t *ptidsl,unsigned int maxbits)
++{
++
++ DEV_HOST_msg_t aturMsg;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ int rc;
++
++ dprintf(5," dslhal_api_setMaxBitsPerCarrier()\n");
++ if(maxbits>15)
++ {
++ dprintf(3,"Maximum Number of Bits per carrier cannot exceed 15!\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.aturMsg_p = (DEV_HOST_msg_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.aturMsg_p);
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.aturMsg_p,
++ &aturMsg, sizeof(DEV_HOST_msg_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ aturMsg.maxBits = maxbits;
++
++ rc=dslhal_support_blockWrite(&aturMsg,dspOamSharedInterface.aturMsg_p,sizeof(DEV_HOST_msg_t));
++ if(rc)
++ return DSLHAL_ERROR_CONFIG_API_FAILURE;
++ dprintf(5," dslhal_api_setMaxBitsPerCarrier() Done\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_setMaxInterleaverDepth(tidsl_t *ptidsl,unsigned int maxdepth)
++*
++*******************************************************************************************
++* DESCRIPTION: This fuction Sets the Maximum Interleave Depth Supported
++*
++* INPUT: PITIDSLHW_T *ptidsl
++* unsigned int maxdepth : Should be between 0 and 3 depending on intlv buffer
++* size 64-512
++* RETURN: 0 SUCCESS
++* 1 FAILED
++*
++*****************************************************************************************/
++unsigned int dslhal_api_setMaxInterleaverDepth(tidsl_t *ptidsl,unsigned int maxdepth)
++{
++ DEV_HOST_msg_t aturMsg;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ int rc;
++ dprintf(5," dslhal_api_setMaxInterleaverDepth()\n");
++ if(maxdepth>3)
++ {
++ dprintf(3,"Invalid Value for maximum interleave depth (must be <3)\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.aturMsg_p = (DEV_HOST_msg_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.aturMsg_p);
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.aturMsg_p,
++ &aturMsg, sizeof(DEV_HOST_msg_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ aturMsg.maxIntlvDepth = maxdepth;
++
++ rc=dslhal_support_blockWrite(&aturMsg,dspOamSharedInterface.aturMsg_p,sizeof(DEV_HOST_msg_t));
++ if(rc)
++ return DSLHAL_ERROR_CONFIG_API_FAILURE;
++ dprintf(5," dslhal_api_setMaxInterleaverDepth() Done\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_acknowledgeInterrupt()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_acknowledgeInterrupt(tidsl_t * ptidsl)
++{
++ unsigned int interruptSources=0;
++ /* Clear out the DSLSS Interrupt Registers to acknowledge Interrupt */
++ if(DSLHAL_REG32(dslhal_support_hostDspAddressTranslate(DSP_INTERRUPT_SOURCE_REGISTER))&MASK_MAILBOX_INTERRUPTS)
++ {
++ DSLHAL_REG32(dslhal_support_hostDspAddressTranslate(DSP_INTERRUPT_CLEAR_REGISTER))|=MASK_MAILBOX_INTERRUPTS;
++ dprintf(5,"Mailbox Interrupt \n");
++ }
++ if(DSLHAL_REG32(dslhal_support_hostDspAddressTranslate(DSP_INTERRUPT_SOURCE_REGISTER))&MASK_BITFIELD_INTERRUPTS)
++ {
++ DSLHAL_REG32(dslhal_support_hostDspAddressTranslate(DSP_INTERRUPT_CLEAR_REGISTER))|=MASK_BITFIELD_INTERRUPTS;
++ dprintf(5,"Bitfield Interrupt \n");
++ }
++ if(DSLHAL_REG32(dslhal_support_hostDspAddressTranslate(DSP_INTERRUPT_SOURCE_REGISTER))&MASK_HEARTBEAT_INTERRUPTS)
++ {
++ DSLHAL_REG32(dslhal_support_hostDspAddressTranslate(DSP_INTERRUPT_CLEAR_REGISTER))|=MASK_HEARTBEAT_INTERRUPTS;
++ dprintf(5,"HeartBeat Interrupt \n");
++ }
++ interruptSources = dslhal_support_parseInterruptSource(ptidsl);
++ if(interruptSources < 0)
++ return DSLHAL_ERROR_INTERRUPT_FAILURE;
++ else
++ return interruptSources;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_disableDspHybridSelect()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_disableDspHybridSelect(tidsl_t * ptidsl,unsigned int disable)
++{
++ int rc;
++ DEV_HOST_phyPerf_t phyPerf;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.phyPerf_p = (DEV_HOST_phyPerf_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.phyPerf_p);
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.phyPerf_p,
++ &phyPerf, sizeof(DEV_HOST_phyPerf_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ if(disable==1)
++ {
++ phyPerf.disableDspHybridSelect_f = TRUE;
++ // hybrid_selected = 888;
++ }
++ else
++ {
++ phyPerf.disableDspHybridSelect_f = FALSE;
++ // hybrid_selected = 888;
++ }
++ rc=dslhal_support_blockWrite(&phyPerf,dspOamSharedInterface.phyPerf_p,sizeof(DEV_HOST_phyPerf_t));
++ if(rc)
++ return DSLHAL_ERROR_HYBRID_API_FAILURE;
++ else
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_selectHybrid()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_selectHybrid(tidsl_t * ptidsl,unsigned int hybridNum)
++{
++ int rc;
++ DEV_HOST_phyPerf_t phyPerf;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ if(hybridNum<1||hybridNum>4)
++ {
++ dprintf(3,"Invalid Value for Hybrid Number \n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.phyPerf_p = (DEV_HOST_phyPerf_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.phyPerf_p);
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.phyPerf_p,
++ &phyPerf, sizeof(DEV_HOST_phyPerf_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ phyPerf.hostSelectHybridNum = hybridNum;
++ rc=dslhal_support_blockWrite(&phyPerf,dspOamSharedInterface.phyPerf_p,sizeof(DEV_HOST_phyPerf_t));
++ if(rc)
++ return DSLHAL_ERROR_HYBRID_API_FAILURE;
++ else
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_reportHybridMetrics()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_reportHybridMetrics(tidsl_t * ptidsl,int *metric)
++{
++ int rc,i;
++ DEV_HOST_phyPerf_t phyPerf;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ if(hybrid_selected>5)
++ {
++ dprintf(4,"Hybrid Metrics Not Yet Available \n");
++ }
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return (0-DSLHAL_ERROR_INVALID_PARAM);
++ }
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return (0-DSLHAL_ERROR_BLOCK_READ);
++ }
++
++ dspOamSharedInterface.phyPerf_p = (DEV_HOST_phyPerf_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.phyPerf_p);
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.phyPerf_p,
++ &phyPerf, sizeof(DEV_HOST_phyPerf_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return (0-DSLHAL_ERROR_BLOCK_READ);
++ }
++ rc = sizeof(phyPerf.hybridCost);
++ for(i=0;i<(rc/4);i++)
++ {
++ metric[i] = dslhal_support_byteSwap32(phyPerf.hybridCost[i]);
++ }
++ return hybrid_selected;
++}
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_selectInnerOuterPair(tidsl_t *ptidsl,unsigned int pairSelect)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction selects inner/outer pair on RJ11.
++ *
++ * INPUT: PITIDSLHW_T *ptidsl , unsigned int pairSelect
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_selectInnerOuterPair(tidsl_t *ptidsl,unsigned int pairSelect)
++{
++ int rc;
++
++ dprintf(5, "dslhal_api_sendQuiet\n");
++ rc = dslhal_support_writeHostMailbox(ptidsl, HOST_RJ11SELECT, (unsigned int)pairSelect, 0, 0);
++ if(rc)
++ {
++ dprintf(1,"dslhal_api_sendQuiet failed\n");
++ return DSLHAL_ERROR_CTRL_API_FAILURE;
++ }
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_resetTrainFailureLog(tidsl_t *ptidsl)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction resets the failed state log stored
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_resetTrainFailureLog(tidsl_t *ptidsl)
++{
++
++ int rc;
++ dprintf(5, "dslhal_api_resetTrainFailureLog \n");
++ for(rc=0;rc<ptidsl->AppData.trainFails;rc++)
++ {
++ ptidsl->AppData.trainFailStates[rc]=0;
++ }
++ ptidsl->AppData.trainFails = 0;
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_configureLed()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_configureLed(tidsl_t * ptidsl,unsigned int idLed, unsigned int onOff)
++{
++ int rc;
++ DEV_HOST_modemEnvPublic_t modemEnv;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ if(idLed>2 || onOff>2)
++ {
++ dprintf(3,"Invalid input parameter \n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.modemEnvPublic_p = (DEV_HOST_modemEnvPublic_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.modemEnvPublic_p);
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.modemEnvPublic_p,
++ &modemEnv, sizeof(DEV_HOST_modemEnvPublic_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ if(idLed==ID_DSL_LINK_LED)
++ {
++ modemEnv.overrideDslLinkLed_f = TRUE;
++ if(onOff!=2)
++ modemEnv.dslLinkLedState_f = onOff;
++ }
++ if(idLed==ID_DSL_ACT_LED)
++ {
++ modemEnv.overrideDslLinkLed_f = TRUE;
++ if(onOff!=2)
++ modemEnv.dslLinkLedState_f = onOff;
++ }
++ if(idLed==ID_RESTORE_DEFAULT_LED)
++ {
++ modemEnv.overrideDslLinkLed_f = FALSE;
++ modemEnv.overrideDslActLed_f = FALSE;
++ }
++ rc=dslhal_support_blockWrite(&modemEnv,dspOamSharedInterface.modemEnvPublic_p,sizeof(DEV_HOST_modemEnvPublic_t));
++ if(rc)
++ return DSLHAL_ERROR_MODEMENV_API_FAILURE;
++ else
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_configureExternBert()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_configureExternBert(tidsl_t * ptidsl,unsigned int configParm, unsigned int parmVal)
++{
++ int rc;
++ DEV_HOST_modemEnvPublic_t modemEnv;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ if(configParm>1 || parmVal>1)
++ {
++ dprintf(3,"Invalid input parameter \n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.modemEnvPublic_p = (DEV_HOST_modemEnvPublic_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.modemEnvPublic_p);
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.modemEnvPublic_p,
++ &modemEnv, sizeof(DEV_HOST_modemEnvPublic_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ if(configParm==0)
++ {
++ modemEnv.externalBert = parmVal;
++ }
++ if(configParm==1)
++ {
++ modemEnv.usBertPattern = parmVal;
++ }
++ rc=dslhal_support_blockWrite(&modemEnv,dspOamSharedInterface.modemEnvPublic_p,sizeof(DEV_HOST_modemEnvPublic_t));
++ if(rc)
++ return DSLHAL_ERROR_MODEMENV_API_FAILURE;
++ else
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_configureAtmBert()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_configureAtmBert(tidsl_t * ptidsl,unsigned int configParm, unsigned int parmVal)
++{
++ int rc;
++ DEV_HOST_atmDsBert_t atmDsBert;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ if(configParm>1 || parmVal>1)
++ {
++ dprintf(3,"Invalid input parameter \n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.atmDsBert_p = (DEV_HOST_atmDsBert_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.atmDsBert_p);
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.atmDsBert_p,
++ &atmDsBert, sizeof(DEV_HOST_atmDsBert_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ if(configParm==0)
++ {
++ atmDsBert.atmBertFlag = parmVal;
++ rc=dslhal_support_blockWrite(&atmDsBert,dspOamSharedInterface.atmDsBert_p,sizeof(DEV_HOST_atmDsBert_t));
++ if(rc)
++ return DSLHAL_ERROR_CONFIG_API_FAILURE;
++ }
++ if(configParm==1)
++ {
++ ptidsl->AppData.atmBertBitCountLow = atmDsBert.bitCountLow;
++ ptidsl->AppData.atmBertBitCountHigh = atmDsBert.bitCountHigh;
++ ptidsl->AppData.atmBertBitErrorCountLow = atmDsBert.bitErrorCountLow;
++ ptidsl->AppData.atmBertBitErrorCountHigh = atmDsBert.bitErrorCountHigh;
++ }
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_configureDgaspLpr()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Configures dying gasp LPR signal
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_configureDgaspLpr(tidsl_t * ptidsl,unsigned int configParm, unsigned int parmVal)
++{
++ int rc;
++ DEV_HOST_modemEnvPublic_t modemEnv;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ if(configParm>1 || parmVal>1)
++ {
++ dprintf(3,"Invalid input parameter \n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ if(!ptidsl)
++ {
++ dprintf(3, "Error: PTIDSL pointer invalid\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.modemEnvPublic_p = (DEV_HOST_modemEnvPublic_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.modemEnvPublic_p);
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.modemEnvPublic_p,
++ &modemEnv, sizeof(DEV_HOST_modemEnvPublic_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ if(configParm==0)
++ {
++ modemEnv.dGaspLprIndicator_f = parmVal;
++ }
++ if(configParm==1)
++ {
++ modemEnv.overrideDspLprGasp_f = parmVal;
++ }
++ rc=dslhal_support_blockWrite(&modemEnv,dspOamSharedInterface.modemEnvPublic_p,sizeof(DEV_HOST_modemEnvPublic_t));
++ if(rc)
++ return DSLHAL_ERROR_MODEMENV_API_FAILURE;
++ else
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_genericDspRead()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Reads from a Generic Location in the DSP Host Interface
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_genericDspRead(tidsl_t * ptidsl,unsigned int offset1, unsigned int offset2,
++ unsigned int offset3, unsigned char *localBuffer, unsigned int numBytes)
++{
++ int rc=0;
++ unsigned int hostIfLoc,structLoc,elementLoc;
++ hostIfLoc = (unsigned int)ptidsl->pmainAddr;
++ if(numBytes<=0 || !localBuffer || !ptidsl)
++ {
++ dprintf(3,"Invalid input parameter \n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++ rc += dslhal_support_blockRead((PVOID)(hostIfLoc+sizeof(int)*offset1), &structLoc,sizeof(int));
++ structLoc = dslhal_support_byteSwap32(structLoc);
++ rc += dslhal_support_blockRead((PVOID)(structLoc+sizeof(int)*offset2), &elementLoc,sizeof(int));
++ elementLoc = dslhal_support_byteSwap32(elementLoc);
++ dprintf(3,"Host IF Location: 0x%x Struct1 Location: 0x%x Element Location: 0x%x \n",hostIfLoc, structLoc, elementLoc);
++ rc += dslhal_support_blockRead((PVOID)(elementLoc+(offset3*4)), localBuffer,numBytes);
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_READ;
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_genericDspWrite()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Writes to a Generic Location in the DSP Host Interface
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_genericDspWrite(tidsl_t * ptidsl,unsigned int offset1, unsigned int offset2,
++ unsigned int offset3, unsigned char *localBuffer, unsigned int numBytes)
++{
++
++ int rc=0;
++ unsigned int hostIfLoc,structLoc,elementLoc;
++ hostIfLoc = (unsigned int)ptidsl->pmainAddr;
++ if(numBytes<=0 || !localBuffer || !ptidsl)
++ {
++ dprintf(3,"Invalid input parameter \n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++ rc += dslhal_support_blockRead((PVOID)(hostIfLoc+(offset1*4)), &structLoc,4);
++ structLoc = dslhal_support_byteSwap32(structLoc);
++ rc += dslhal_support_blockRead((PVOID)(structLoc+(offset2*4)), &elementLoc,4);
++ elementLoc = dslhal_support_byteSwap32(elementLoc);
++ dprintf(3,"Host IF Location: 0x%x Struct1 Location: 0x%x Element Location: 0x%x \n",hostIfLoc, structLoc, elementLoc);
++ rc += dslhal_support_blockWrite(localBuffer,(PVOID)(elementLoc+(offset3*4)),numBytes);
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_READ;
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_dspInterfaceRead()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Reads from a Generic Location in the DSP Host Interface
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_dspInterfaceRead(tidsl_t * ptidsl,unsigned int baseAddr, unsigned int numOffsets,
++ unsigned int *offsets, unsigned char *localBuffer, unsigned int numBytes)
++{
++ int rc=0, off=0;
++ unsigned int prevAddr,currAddr;
++ prevAddr = baseAddr;
++ if(numBytes<=0 || !localBuffer || !ptidsl || !offsets)
++ {
++ dprintf(3,"Invalid input parameter \n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++ for(off=0;off<numOffsets-1;off++)
++ {
++ rc += dslhal_support_blockRead((PVOID)(prevAddr+(4*offsets[off])), &currAddr,4);
++ currAddr = dslhal_support_byteSwap32(currAddr);
++ prevAddr = currAddr;
++ dprintf(5,"Curr Addr = 0x%x Current Level: %d \n",currAddr,off);
++ }
++ currAddr = currAddr + offsets[numOffsets-1]*4;
++ rc += dslhal_support_blockRead((PVOID)(currAddr),localBuffer,numBytes);
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_READ;
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_dspInterfaceWrite()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Writes to a Generic Location in the DSP Host Interface
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_dspInterfaceWrite(tidsl_t * ptidsl,unsigned int baseAddr, unsigned int numOffsets,
++ unsigned int *offsets,unsigned char *localBuffer, unsigned int numBytes)
++{
++
++ int rc=0, off=0;
++ unsigned int prevAddr,currAddr;
++ prevAddr = baseAddr;
++ if(numBytes<=0 || !localBuffer || !ptidsl || !offsets)
++ {
++ dprintf(3,"Invalid input parameter \n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++ for(off=0;off<numOffsets-1;off++)
++ {
++ rc += dslhal_support_blockRead((PVOID)(prevAddr+(4*offsets[off])), &currAddr,4);
++ currAddr = dslhal_support_byteSwap32(currAddr);
++ prevAddr = currAddr;
++ dprintf(5,"Curr Addr = 0x%x Current Level: %d \n",currAddr,off);
++ }
++ currAddr = currAddr + offsets[numOffsets-1]*4;
++ rc += dslhal_support_blockWrite(localBuffer,(PVOID)(currAddr),numBytes);
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_READ;
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_sendMailboxCommand(tidsl_t *ptidsl, unsigned int cmd)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction sends the passed mailbox command to the DSP
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * unsigned int cmd
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++/* Function is commented out for now since, its not tested */
++ /*unsigned int dslhal_api_sendMailboxCommand(tidsl_t *ptidsl, unsigned int cmd)
++{
++ int rc;
++
++ dprintf(5, "dslhal_api_sendMailboxCommand\n");
++ rc = dslhal_support_writeHostMailbox(ptidsl, cmd, 0, 0, 0);
++ if(rc)
++ {
++ dprintf(1,"dslhal_api_sendMailboxCommand failed\n");
++ return DSLHAL_ERROR_CTRL_API_FAILURE;
++ }
++ return DSLHAL_ERROR_NO_ERRORS;
++} */
++
++
+diff -urN linux.old/drivers/atm/sangam_atm/dsl_hal_api.h linux.dev/drivers/atm/sangam_atm/dsl_hal_api.h
+--- linux.old/drivers/atm/sangam_atm/dsl_hal_api.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/dsl_hal_api.h 2005-08-23 04:46:50.097843696 +0200
+@@ -0,0 +1,1721 @@
++#ifndef __DSL_HAL_API_H__
++#define __DSL_HAL_API_H__ 1
++/*******************************************************************************
++* FILE PURPOSE: DSL HAL to Application Interface for Sangam
++*
++********************************************************************************
++* FILE NAME: dsl_application_interface.h
++*
++* DESCRIPTION:
++* DSL-Application Interface Structures
++*
++*
++* By: Ramakrishnan Parasuraman
++*
++* (C) Copyright 2003, Texas Instruments, Inc.
++* History
++* Data Version By Notes
++* 06Feb03 0.00 RamP Initial Version Written
++* 07Apr03 0.01 RamP Commented out typedefs
++* 09Apr03 0.02 RamP Added deviceContext and extended
++* dspVer to include bugfixes
++* 14Apr03 0.03 RamP Added stateTransition to structure
++* 16Apr03 0.04 RamP Removed typedefs; changed dspVer
++* 22Apr03 0.05 RamP Moved acknowledgeInterrupt from
++* (alpha) support module into this
++* 24Apr03 0.06 RamP Moved the RSTATE enum from register
++*
++* 28Apr03 0.07 RamP Added additional parameter to the
++* (alpha +) handleInterrupt function for intrSrc
++* 14May03 0.08 RamP Added hybrid switching APIs
++* (alpha ++) Added statistics fields in AppData
++* Added netService identifier
++* 20May03 0.09 RamP Added Inner/Outer pair API support.
++* Added dying gasp message.
++* 29May03 0.10 RamP Added coProfile structure
++* 04Jun03 0.11 RamP Added margin per tone statistics,
++* Added timing counters, added train
++* failure functions,added config flags
++* 06Jun03 0.12 RamP Added LED, STM Bert, dGasp LPR
++* config API functions
++* 09Jun03 0.13 RamP Added ATM Bert function, CO stats
++* Moved stateTransition to ITIDSLHW
++* (Beta) Moved configFlag to ITIDSLHW,
++* Cleaned up fifoInfo structure
++* Added US/DS R/S FEC parameters
++* 21Aug03 0.14 RamP Added g.hs message buffer, us/ds
++* bits n gains table, negoMsgs struct
++* (act) bitswap stucts/indices, trainstate,
++* Added functions for advanced config
++* Added gross gain and line length
++* 29Sep03 0.15 RamP Added tokens for advanced config
++* module api functions
++* 12Oct03 0.16 RamP Added adsl2Msgs structure with worst
++* case size for variable length msgs
++* Added API function prototypes
++* 21Oct03 0.17 RamP Added typedef for current modem
++* user settings
++* 28Oct03 0.18 RamP Added function to config blackout
++* bitmap in the RMSGPCB message
++* 20Nov03 0.19 RamP Added functions for generic and
++* host interface read - write
++* 24Nov03 0.20 RamP Added enum for detailed state track
++* Added element for state bit fields
++* Addded rState for encoded main state
++* Added blackout valid flag
++* 26Dec03 0.21 RamP Added defines for oamFeature masks
++* 30Dec03 0.22 RamP Increased sizes for cMsgPcb,RMsgPcb
++* to incorporate DELT mode messages
++* 30Dec03 0.23 RamP Added generic mailbox command fxn
++*******************************************************************************/
++
++#ifdef INTERNAL_BUILD
++#include <dsl_hal_api_pvt.h>
++#endif
++
++#define NUM_PAGES 4
++#define OAMFEATURE_AUTORETRAIN_MASK 0x00000001
++#define OAMFEATURE_TC_SYNC_DETECT_MASK 0x00000002
++#define OAMFEATURE_EOCAOC_INTERRUPT_MASK 0x00000004
++#define OAMFEATURE_CONS_DISP_DISABLE_MASK 0x00000008
++#define OAMFEATURE_GHSMSG_INTERRUPT_MASK 0x00000010
++
++typedef struct tagTIOIDINFO
++{
++ unsigned int bState; /* addr->bDSPATURState */
++ unsigned int USConRate; /* US Conection Rates */
++ unsigned int DSConRate; /* DS Connection Rates */
++ unsigned int USPayload; /* ennic_tx_pullup*/
++ unsigned int DSPayload; /* ennic_indicate_receive_packet*/
++ unsigned int FrmMode; /* addr->atur_msg.framing_mode*/
++ unsigned int MaxFrmMode;
++ unsigned int TrainedPath; /* Status of the Modem in which trained (Fast or Interleaved Path) */
++ unsigned int TrainedMode; /* Status of the mode in which the modem is trained (G.dmt, T1.413, etc) */
++
++ /* Superframe Count */
++ unsigned int usSuperFrmCnt; /* Num of US Superframes */
++ unsigned int dsSuperFrmCnt; /* Num of DS Superframes */
++
++ /* LOS & SEF Stats */
++ unsigned int LOS_errors; /* Num of ADSL frames where loss-of-sync */
++ unsigned int SEF_errors; /* Num of severly errored ADSL frames - LOS > MAXBADSYNC ADSL frames */
++ unsigned int coLosErrors; /* CO LOS Defects */
++ unsigned int coRdiErrors; /* CO RDI defects */
++ /* CRC Stats */
++ unsigned int usICRC_errors; /* Num of Upstream CRC errored ADSL frames on Interleaved Path */
++ unsigned int usFCRC_errors; /* Num of Upstream CRC errored ADSL frames on Fast Path */
++ unsigned int dsICRC_errors; /* Num of Downstream CRC errored ADSL frames on Interleaved Path */
++ unsigned int dsFCRC_errors; /* Num of Downstream CRC errored ADSL frames on Fast Path */
++
++ /* FEC Stats */
++ unsigned int usIFEC_errors; /* Num of Upstream FEC errored (corrected) ADSL frames on Interleaved Path */
++ unsigned int usFFEC_errors; /* Num of Upstream FEC errored (corrected) ADSL frames on Fast Path */
++ unsigned int dsIFEC_errors; /* Num of Downstream FEC errored (corrected) ADSL frames on Interleaved Path */
++ unsigned int dsFFEC_errors; /* Num of Downstream FEC errored (corrected) ADSL frames on Fast Path */
++
++ /* NCD Stats */
++ unsigned int usINCD_error; /* UpStream No Cell Delineation on Interleaved Path */
++ unsigned int usFNCD_error; /* UpStream No Cell Delineation on Fast Path */
++ unsigned int dsINCD_error; /* Downstream No Cell Delineation on Interleaved Path */
++ unsigned int dsFNCD_error; /* Downstream No Cell Delineation on Fast Path */
++
++ /* LCD Stats */
++ unsigned int usILCD_errors; /* UpStream Loss of Cell Delineation (within the same connection) on Interleaved Path */
++ unsigned int usFLCD_errors; /* UpStream Loss of Cell Delineation (within the same connection) on Fast Path */
++ unsigned int dsILCD_errors; /* Downstream Loss of Cell Delineation (within the same connection) on Interleaved Path */
++ unsigned int dsFLCD_errors; /* Downstream Loss of Cell Delineation (within the same connection) on Fast Path */
++
++ /* HEC Stats */
++ unsigned int usIHEC_errors; /* Num of Upstream HEC errored ADSL frames on Interleaved Path */
++ unsigned int usFHEC_errors; /* Num of Upstream HEC errored ADSL frames on Fast Path */
++ unsigned int dsIHEC_errors; /* Num of Downstream HEC errored ADSL frames on Interleaved Path */
++ unsigned int dsFHEC_errors; /* Num of Downstream HEC errored ADSL frames on Fast Path */
++
++ /* Upstream ATM Stats */
++ unsigned int usAtm_count[2]; /* Upstream Good Cell Count */
++ unsigned int usIdle_count[2]; /* Upstream Idle Cell Count */
++ unsigned int usPdu_count[2]; /* UpStream PDU Count */
++
++ /* Downstream ATM Stats */
++ unsigned int dsGood_count[2]; /* Downstream Good Cell Count */
++ unsigned int dsIdle_count[2]; /* Downstream Idle Cell Count */
++ unsigned int dsBadHec_count[2]; /* Downstream Bad Hec Cell Count */
++ unsigned int dsOVFDrop_count[2]; /* Downstream Overflow Dropped Cell Count */
++ unsigned int dsPdu_count[2]; /* Downstream PDU Count */
++ /* (only looks for end of pdu on good atm cells received, */
++ /* not on Bad_Hec or Overflow cell) */
++
++ unsigned int dsLineAttn; /* DS Line Attenuation */
++ unsigned int dsMargin; /* Measured DS MArgin */
++
++ unsigned int usLineAttn;
++ unsigned int usMargin;
++
++ unsigned char bCMsgs1[6];
++ unsigned char bRMsgs1[6];
++ unsigned char bCRates2;
++ unsigned char bRRates2;
++ unsigned char bRRates1[4][11];
++ unsigned char bCMsgs2[4];
++ unsigned char bCRates1[4][30];
++ unsigned char bRMsgs2[4];
++
++ unsigned int USPeakCellRate;
++
++ unsigned int dsl_status;
++ unsigned int dsl_modulation;
++ unsigned char dsl_ghsRxBuf[10][64];
++ unsigned char dsl_GHS_msg_type[2];
++
++ int TxVCs[12];
++ int RxVCs[12];
++
++ unsigned int vci_vpi_val;
++
++ unsigned char BitAllocTblDstrm[256];
++ unsigned char BitAllocTblUstrm[32];
++ signed char marginTblDstrm[256];
++ unsigned char rBng[512];
++ unsigned char cBng[126];
++ int usTxPower;
++ int dsTxPower;
++ short rxSnrPerBin0[256];
++ short rxSnrPerBin1[256];
++ short rxSnrPerBin2[256];
++
++ unsigned int StdMode;
++ unsigned int atucVendorId;
++ unsigned char currentHybridNum;
++ unsigned char atucRevisionNum;
++ unsigned int trainFails;
++ unsigned int trainFailStates[30];
++ unsigned int idleTick;
++ unsigned int initTick;
++ unsigned int showtimeTick;
++ unsigned char dsFastParityBytesPerSymbol;
++ unsigned char dsIntlvParityBytesPerSymbol;
++ unsigned char dsSymbolsPerCodeWord;
++ unsigned int dsInterleaverDepth;
++ unsigned char usFastParityBytesPerSymbol;
++ unsigned char usIntlvParityBytesPerSymbol;
++ unsigned char usSymbolsPerCodeWord;
++ unsigned int usInterleaverDepth;
++ unsigned int atmBertBitCountLow;
++ unsigned int atmBertBitCountHigh;
++ unsigned int atmBertBitErrorCountLow;
++ unsigned int atmBertBitErrorCountHigh;
++ unsigned int lineLength;
++ unsigned int grossGain;
++ int rxNoisePower0[256];
++ int rxNoisePower1[256];
++}TIOIDINFO,*PTIOIDINFO;
++
++typedef struct{
++ unsigned char bCMsgs1[6];
++ unsigned char bCRates2;
++ unsigned char bRRates2;
++ unsigned char bRRates1[4][11];
++ unsigned char bCMsgs2[4];
++ unsigned char bCRates1[4][30];
++ unsigned char bCRatesRA[4][30];
++ unsigned char bRMsgs2[4];
++ unsigned char bRRatesRA[4];
++ unsigned char bRMsgsRA[12];
++ unsigned char bCMsgsRA[6];
++}negoMsgs;
++
++typedef struct{
++ unsigned char cMsgFmt[2];
++ unsigned char rMsgFmt[2];
++ unsigned char cMsgPcb[12];
++ unsigned char rMsgPcb[70];
++ unsigned char dummy1[2];
++ unsigned char cMsg1[40];
++ unsigned char rMsg1[4];
++ unsigned char cMsg2[8];
++ unsigned char rMsg2[64];
++ unsigned char cParams[264];
++ unsigned char rParams[2088];
++ unsigned short cMsgPcbLen;
++ unsigned short rMsgPcbLen;
++ unsigned short cMsg1Len;
++ unsigned short rMsg1Len;
++ unsigned short cMsg2Len;
++ unsigned short rMsg2Len;
++ unsigned short cParamsLen;
++ unsigned short rParamsLen;
++}adsl2Msgs;
++
++typedef struct{
++ unsigned char rMsg1Ld[16];
++ unsigned char rMsg2Ld[260];
++ unsigned char rMsg3Ld[260];
++ unsigned char rMsg4Ld[260];
++ unsigned char rMsg5Ld[260];
++ unsigned char rMsg6Ld[260];
++ unsigned char rMsg7Ld[260];
++ unsigned char rMsg8Ld[260];
++ unsigned char rMsg9Ld[260];
++ unsigned char cMsg1Ld[16];
++ unsigned char cMsg2Ld[260];
++ unsigned char cMsg3Ld[132];
++ unsigned char cMsg4Ld[68];
++ unsigned char cMsg5Ld[68];
++ unsigned short rMsg1LdLen;
++ unsigned short rMsgxLdLen;
++ unsigned short cMsg1LdLen;
++ unsigned short cMsg2LdLen;
++ unsigned short cMsg3LdLen;
++ unsigned short cMsg4LdLen;
++ unsigned short cMsg5LdLen;
++ unsigned short dummy8;
++}adsl2DeltMsgs;
++
++typedef struct{
++ unsigned char trellisFlag;
++ unsigned char rateAdaptFlag;
++ unsigned char marginMonitorTraining;
++ unsigned char marginMonitorShowtime;
++ signed char marginThreshold;
++ unsigned char disableLosFlag;
++ unsigned char aturConfig[30];
++ unsigned char eocVendorId[8];
++ unsigned char eocSerialNumber[32];
++ unsigned char eocRevisionNumber[4];
++}currentPhySettings;
++
++
++typedef struct
++{
++ unsigned int PmemStartWtAddr; /* source address in host memory */
++ unsigned int OverlayXferCount; /* number of 32bit words to be transfered */
++ unsigned int BinAddr; /* destination address in dsp's pmem */
++ unsigned int overlayHostAddr;
++ unsigned int olayPageCrc32;
++ unsigned int SecOffset;
++} OlayDP_Def;
++
++typedef struct
++{
++ unsigned int timeStamp; /* TimeStp revision */
++ unsigned char major; /* Major revision */
++ unsigned char minor; /* Minor revision */
++ unsigned char bugFix; /* BugFix revision */
++ unsigned char buildNum; /* BuildNum revision */
++ unsigned char reserved; /* for future use */
++}dspVer;
++
++typedef struct{
++ unsigned char major;
++ unsigned char minor;
++ unsigned char bugfix;
++ unsigned char buildNum;
++ unsigned int timeStamp;
++}dslVer;
++
++typedef struct{
++ unsigned char bitSwapCommand[6];
++ unsigned char bitSwapBinNum[6];
++ unsigned char bitSwapSFrmCnt;
++}dslBitSwapDef;
++
++typedef struct{
++ unsigned int aturState;
++ unsigned int subStateIndex;
++ unsigned int timeStamp;
++}trainStateInfo;
++
++typedef struct{
++ unsigned char ctrlBits;
++ unsigned char infoBits;
++}eocMessageDef;
++
++enum
++{
++ RSTATE_TEST,
++ RSTATE_IDLE,
++ RSTATE_INIT,
++ RSTATE_HS,
++ RSTATE_RTDL,
++ RSTATE_SHOWTIME,
++};
++
++typedef enum
++{
++ ATU_RZERO1 = 100,
++ ATU_RTEST = 101,
++ ATU_RIDLE = 102,
++ ATU_RINIT = 103,
++ ATU_RRESET = 104,
++ GDMT_NSFLR = 105,
++ GDMT_TONE = 106,
++ GDMT_SILENT = 107,
++ GDMT_NEGO = 108,
++ GDMT_FAIL = 109,
++ GDMT_ACKX = 110,
++ GDMT_QUIET2 = 111,
++ ATU_RZERO2 = 200,
++ T1413_NSFLR = 201,
++ T1413_ACTREQ = 202,
++ T1413_ACTMON = 203,
++ T1413_FAIL = 204,
++ T1413_ACKX = 205,
++ T1413_QUIET2 = 206,
++ ATU_RQUIET2 = 207,
++ ATU_RREVERB1 = 208,
++ ATU_RQUIET3 = 209,
++ ATU_RECT = 210,
++ ATU_RREVERB2 = 211,
++ ATU_RSEGUE1 = 212,
++ ATU_RREVERB3 = 213,
++ ATU_RSEGUE2 = 214,
++ ATU_RRATES1 = 215,
++ ATU_RMSGS1 = 216,
++ ATU_RMEDLEY = 217,
++ ATU_RREVERB4 = 218,
++ ATU_RSEGUE3 = 219,
++ ATU_RMSGSRA = 220,
++ ATU_RRATESRA = 221,
++ ATU_RREVERBRA = 222,
++ ATU_RSEGUERA = 223,
++ ATU_RMSGS2 = 224,
++ ATU_RRATES2 = 225,
++ ATU_RREVERB5 = 226,
++ ATU_RSEGUE4 = 227,
++ ATU_RBNG = 228,
++ ATU_RREVERB6 = 229,
++ ATU_RSHOWTIME = 230,
++ ATU_RZERO3 = 300,
++ ADSL2_QUIET1 = 301,
++ ADSL2_COMB1 = 302,
++ ADSL2_QUIET2 = 303,
++ ADSL2_COMB2 = 304,
++ ADSL2_ICOMB1 = 305,
++ ADSL2_LINEPROBE = 306,
++ ADSL2_QUIET3 = 307,
++ ADSL2_COMB3 = 308,
++ ADSL2_ICOMB2 = 309,
++ ADSL2_RMSGFMT = 310,
++ ADSL2_RMSGPCB = 311,
++ ADSL2_REVERB1 = 312,
++ ADSL2_QUIET4 = 313,
++ ADSL2_REVERB2 = 314,
++ ADSL2_QUIET5 = 315,
++ ADSL2_REVERB3 = 316,
++ ADSL2_ECT = 317,
++ ADSL2_REVERB4 = 318,
++ ADSL2_SEGUE1 = 319,
++ ADSL2_REVERB5 = 320,
++ ADSL2_SEGUE2 = 321,
++ ADSL2_RMSG1 = 322,
++ ADSL2_MEDLEY = 323,
++ ADSL2_EXCHANGE = 324,
++ ADSL2_RMSG2 = 325,
++ ADSL2_REVERB6 = 326,
++ ADSL2_SEGUE3 = 327,
++ ADSL2_RPARAMS = 328,
++ ADSL2_REVERB7 = 329,
++ ADSL2_SEGUE4 = 330,
++ ATU_RZERO4 = 400,
++ DELT_SEGUE1 = 401,
++ DELT_REVERB5 = 402,
++ DELT_SEGUE2 = 403,
++ DELT_EXCHANGE = 404,
++ DELT_SEGUELD = 405,
++ DELT_RMSGLD = 406,
++ DELT_QUIET1LD = 407,
++ DELT_QUIET2LD = 408,
++ DELT_RACK1 = 409,
++ DELT_RNACK1 = 410,
++ DELT_QUIETLAST = 411
++} modemStates_t;
++
++enum
++{
++ DSLTRAIN_NO_MODE,
++ DSLTRAIN_MULTI_MODE,
++ DSLTRAIN_T1413_MODE,
++ DSLTRAIN_GDMT_MODE,
++ DSLTRAIN_GLITE_MODE
++};
++
++enum
++{
++ ID_RESTORE_DEFAULT_LED,
++ ID_DSL_LINK_LED,
++ ID_DSL_ACT_LED
++};
++
++typedef struct _ITIDSLHW
++{
++ /* struct _TIDSL_IHwVtbl * pVtbl; */
++ unsigned char* fwimage;
++ void* pmainAddr;
++ void* pOsContext;
++ unsigned int ReferenceCount;
++ unsigned int netService;
++
++ int InitFlag;
++
++ int imagesize;
++
++ unsigned int lConnected;
++ unsigned int bStatisticsInitialized;
++ unsigned int rState;
++ unsigned int bShutdown;
++ unsigned int blackOutValid_f;
++ unsigned char blackOutBits[64];
++ unsigned int bAutoRetrain;
++ volatile unsigned int bOverlayPageLoaded;
++ unsigned int stateTransition;
++ unsigned int configFlag;
++ unsigned int dsBitSwapInx;
++ unsigned int usBitSwapInx;
++ unsigned int trainStateInx;
++ unsigned int usEocMsgInx;
++ unsigned int dsEocMsgInx;
++ unsigned int reasonForDrop;
++ TIOIDINFO AppData;
++ dspVer dspVer;
++
++ OlayDP_Def olayDpPage[NUM_PAGES];
++ OlayDP_Def coProfiles;
++ OlayDP_Def constDisplay;
++ dslBitSwapDef dsBitSwap[30];
++ dslBitSwapDef usBitSwap[30];
++ trainStateInfo trainHistory[120];
++ eocMessageDef usEocMsgBuf[30];
++ eocMessageDef dsEocMsgBuf[30];
++ adsl2Msgs adsl2TrainingMessages;
++ adsl2DeltMsgs adsl2DiagnosticMessages;
++ unsigned int modemStateBitField[4];
++#ifdef INTERNAL_BUILD
++ internalParameters internalVars;
++#endif
++} ITIDSLHW_T, *PITIDSLHW_T, tidsl_t;
++
++
++/**********************************************************************************
++* API proto type defines
++**********************************************************************************/
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_dslStartup
++*
++*******************************************************************************************
++* DESCRIPTION: Entry point to initialize and load ax5 daughter board
++*
++* INPUT: PITIDSLHW_T *ppIHw
++*
++* RETURN: 0 --succeeded
++* 1 --Failed
++*
++* Notes: external function osAllocateMemory(), osZeroMemory(), osLoadFWImage() are required
++*****************************************************************************************/
++int dslhal_api_dslStartup
++(
++ PITIDSLHW_T *ppIHw
++);
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_gatherStatistics
++*
++*********************************************************************************************
++* DESCRIPTION: Read statistical infromation from ax5 modem daugter card.
++* Input: tidsl_t *ptidsl
++*
++* Return: 0 success
++* 1 failed
++*
++********************************************************************************************/
++
++void dslhal_api_gatherStatistics
++(
++ tidsl_t * ptidsl
++);
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_initStatistics
++*
++*********************************************************************************************
++* DESCRIPTION: init statistical infromation of ax5 modem daugter card.
++*
++* Input: tidsl_t *ptidsl
++*
++* Return: NULL
++*
++********************************************************************************************/
++
++void dslhal_api_initStatistics
++(
++ tidsl_t * ptidsl
++);
++
++
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_getDslDriverVersion
++*
++*******************************************************************************************
++* DESCRIPTION: This routine supply DSL Driver version.
++*
++* INPUT: tidsl_t * ptidsl
++* void *pVer, DSP Driver Version Pointer
++*
++* RETURN: 0 --succeeded
++* 1 --Failed
++* Note: See verdef_u.h for version structure definition.
++*****************************************************************************************/
++
++void dslhal_api_getDslHalVersion
++(
++ void *pVer
++);
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_dslShutdown
++*
++*******************************************************************************************
++* DESCRIPTION: routine to shutdown ax5 modem and free the resource
++*
++* INPUT: tidsl_t *ptidsl
++*
++* RETURN: NULL
++*
++* Notes: external function osFreeMemory() is required.
++*****************************************************************************************/
++
++int dslhal_api_dslShutdown
++(
++ tidsl_t *ptidsl
++);
++
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_getDspVersion
++*
++*******************************************************************************************
++* DESCRIPTION: This routine supply AX5 daugther card DSP version.
++*
++* INPUT: tidsl_t * ptidsl
++* void *pVer, DSP version struct is returned starting at this pointer
++*
++* RETURN: 0 --succeeded
++* 1 --Failed
++*
++*****************************************************************************************/
++
++int dslhal_api_getDspVersion
++(
++ tidsl_t *ptidsl,
++ void *pVer
++);
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_diags_digi_memTestA()
++*
++*********************************************************************************************
++* DESCRIPTION: This function does the digital tests on the DSP. It does the DSP ID test,
++* memory tests on the external and internal memories of DSP, Codec Interconnect
++* test and Interrupt Test.
++*
++* Input: Test selects the test to be performed based on the elements set of 9 element
++* array passed the the parameter.
++*
++* Return: Status of the Tests Failed
++*
++********************************************************************************************/
++
++unsigned int dslhal_diags_digi_memTestA
++(
++unsigned int* Test
++);
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_diags_digi_memTestB()
++*
++*********************************************************************************************
++* DESCRIPTION: This function does the digital tests on the DSP. It does the DSP ID test,
++* memory tests on the external and internal memories of DSP, Codec Interconnect
++* test and Interrupt Test.
++*
++* Input: Test selects the digital test to be performed.
++*
++* Return: Status of the Tests Failed
++*
++********************************************************************************************/
++
++unsigned int dslhal_diags_digi_memTestB
++(
++unsigned int Test,
++unsigned int *Status
++);
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_diags_anlg_tonesTestA()
++*
++*********************************************************************************************
++* DESCRIPTION: This function instructs the Transciever to transmit the Reverb with missing
++* tones and Medley's with missing tones. These signals are defined in ITU
++* G.992.1 ADSL Standards.
++*
++* Input: Test selects between the Reverb or Medley tests. 0 - Reverb, 1 - Medley
++* Array is a 64 element unsigned integer type array. The element of this array
++* describe which tones are to be generated by selecting the element of
++* the array to be non zero.
++* Return: NULL
++*
++********************************************************************************************/
++
++void dslhal_diags_anlg_tonesTestA
++(
++unsigned int Test,
++unsigned int* Array
++);
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_diags_anlg_tonesTestB()
++*
++*********************************************************************************************
++* DESCRIPTION: This function instructs the Transciever to transmit the Reverb with missing
++* tones and Medley's with missing tones. These signals are defined in ITU
++* G.992.1 ADSL Standards.
++*
++* Input: Test selects between the Reverb or Medley tests. 0 - Reverb, 1 - Medley
++* Array is a 64 element unsigned integer type array. The element of this array
++* describe which tones are to be generated by selecting the element of
++* the array to be non zero.
++* Return: NULL
++*
++********************************************************************************************/
++
++void dslhal_diags_anlg_tonesTestB
++(
++unsigned int Test,
++unsigned int Tones
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_diags_anlg_rxNoiseTest()
++*
++*********************************************************************************************
++* DESCRIPTION: This function instructs the Transciever to transmit the Reverb with missing
++* tones and Medley's with missing tones. These signals are defined in ITU
++* G.992.1 ADSL Standards.
++*
++* Input: Test selects between the Reverb or Medley tests. 0 - Reverb, 1 - Medley
++* Tones selects the .
++* Return: NULL
++*
++********************************************************************************************/
++
++void dslhal_diags_anlg_rxNoiseTest
++(int agcFlag,
++short pga1,
++short pga2,
++short pga3,
++short aeq
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_diags_anlg_ecNoiseTest()
++*
++*********************************************************************************************
++* DESCRIPTION: This function instructs the Transciever to transmit the Reverb with missing
++* tones and Medley's with missing tones. These signals are defined in ITU
++* G.992.1 ADSL Standards.
++*
++* Input: Test selects between the Reverb or Medley tests. 0 - Reverb, 1 - Medley
++* Tones selects the .
++* Return: NULL
++*
++********************************************************************************************/
++
++void dslhal_diags_anlg_ecNoiseTest
++(int agcFlag,
++short pga1,
++short pga2,
++short pga3,
++short aeq
++);
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_pollTrainingStatus()
++*
++*********************************************************************************************
++* DESCRIPTION: code to decode modem status and to start modem training
++*
++* Input: tidsl_t *ptidsl
++*
++* Return: 0-? status mode training
++* -1 failed
++*
++********************************************************************************************/
++int dslhal_api_pollTrainingStatus
++(
++ tidsl_t *ptidsl
++);
++
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_handleTrainingInterrupt()
++*
++*********************************************************************************************
++* DESCRIPTION: Code to handle ax5 hardware interrupts
++*
++* Input: tidsl_t *ptidsl
++* int *pMsg, pointer to returned hardware messages. Each byte represent a messge
++* int *pTag, pointer to returned hardware message tags. Each byte represent a tag.
++* Return: 0 success
++* 1 failed
++*
++********************************************************************************************/
++int dslhal_api_handleTrainingInterrupt
++(
++ tidsl_t *ptidsl,
++ int intrSource
++);
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_setEocSerialNumber(tidsl_t *ptidsl,char *SerialNumber)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction Sets the EOC Serial Number
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * char *SerialNumber : Input EOC Serial Number
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_setEocSerialNumber
++(
++tidsl_t *ptidsl,
++char *SerialNumber
++);
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_setEocVendorId(tidsl_t *ptidsl,char *VendorID)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction Sets the EOC Serial Number
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * char *VendorID : EOC Vendor ID
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_setEocVendorId
++(
++tidsl_t *ptidsl,
++char *VendorID
++);
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_setEocRevisionNumber(tidsl_t *ptidsl,char *RevNum)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction Sets the EOC Revision Number
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * char *RevNum : Input EOC Revision Number
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_setEocRevisionNumber
++(
++tidsl_t *ptidsl,
++char *RevNumber
++);
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_setAturConfig(tidsl_t *ptidsl,char *ATURConfig)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction Sets the EOC ATUR Config Register
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * char *RevNum : Input EOC ATUR Config Register
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_setAturConfig
++(
++tidsl_t *ptidsl,
++char *ATURConfig
++);
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_disableLosAlarm(tidsl_t *ptidsl, unsigned int set)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction disables all the LOS alarms
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * unsigned int set // if set == TRUE : Disable LOS alarms, else enable
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ * NOTES: Currently not supported in any version other than MR4 Patch release..
++ *****************************************************************************************/
++unsigned int dslhal_api_disableLosAlarm
++(
++tidsl_t *ptidsl,
++unsigned int
++);
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_sendIdle(tidsl_t *ptidsl)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction sends the CMD_IDLE message to the DSP
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_sendIdle
++(
++tidsl_t *ptidsl
++);
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_sendQuiet(tidsl_t *ptidsl)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction sends the CMD_QUIET message to the DSP
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_sendQuiet
++(
++tidsl_t *ptidsl
++);
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_sendDgasp(tidsl_t *ptidsl)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction sends the HOST_DGASP message to the DSP
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_sendDgasp
++(
++tidsl_t *ptidsl
++);
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_setMarginThreshold(tidsl_t *ptidsl, int threshold)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction does sets the Margin threshold
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * int threshold
++ *
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_setMarginThreshold
++(
++tidsl_t *ptidsl,
++int threshold
++);
++
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_setMarginMonitorFlags(tidsl_t *ptidsl, unsigned int trainflag,unsigned int shwtflag)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction does sets the Margin monitoring flag
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * unsigned int trainflag
++ * unsigned int shwtflag
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_setMarginMonitorFlags
++(
++tidsl_t *ptidsl,
++unsigned int trainflag,
++unsigned int shwtflag
++);
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_setRateAdaptFlag(tidsl_t *ptidsl)
++*
++*******************************************************************************************
++* DESCRIPTION: This fuction Sets the Rate Adapt Enable Flag
++*
++* INPUT: PITIDSLHW_T *ptidsl
++* unsigned int flag //if flag = TRUE set flag else reset
++* RETURN: 0 SUCCESS
++* 1 FAILED
++*
++*****************************************************************************************/
++unsigned int dslhal_api_setRateAdaptFlag
++(
++tidsl_t *ptidsl,
++unsigned int flag
++);
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_setTrellisFlag(tidsl_t *ptidsl, unsigned int flag)
++*
++*******************************************************************************************
++* DESCRIPTION: This fuction Sets the Trellis Coding Enable Flag
++*
++* INPUT: PITIDSLHW_T *ptidsl
++* unsigned int flag //if flag = TRUE set flag else reset
++* RETURN: 0 SUCCESS
++* 1 FAILED
++*
++*****************************************************************************************/
++unsigned int dslhal_api_setTrellisFlag
++(
++tidsl_t *ptidsl,
++unsigned int flag
++);
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_setMaxBitsPerCarrier(tidsl_t *ptidsl,unsigned int maxbits)
++*
++*******************************************************************************************
++* DESCRIPTION: This fuction Sets the Maximum bits per carrier value
++*
++* INPUT: PITIDSLHW_T *ptidsl
++* unsigned int maxbits : should be a value between 0-15
++*
++* RETURN: 0 SUCCESS
++* 1 FAILED
++*
++*****************************************************************************************/
++unsigned int dslhal_api_setMaxBitsPerCarrier
++(
++tidsl_t *ptidsl,
++unsigned int maxbits
++);
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_setMaxInterleaverDepth(tidsl_t *ptidsl,unsigned int maxdepth)
++*
++*******************************************************************************************
++* DESCRIPTION: This fuction Sets the Maximum Interleave Depth Supported
++*
++* INPUT: PITIDSLHW_T *ptidsl
++* unsigned int maxdepth : Should be between 0 and 3 depending on intlv buffer
++* size 64-512
++* RETURN: 0 SUCCESS
++* 1 FAILED
++*
++*****************************************************************************************/
++unsigned int dslhal_api_setMaxInterleaverDepth
++(
++tidsl_t *ptidsl,
++unsigned int maxdepth
++);
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_api_setTrainingMode(tidsl_t *ptidsl,unsigned int trainmode)
++*
++*******************************************************************************************
++* DESCRIPTION: This fuction Sets the desired training mode(none/T1.413/G.dmt/G.lite)
++*
++* INPUT: PITIDSLHW_T *ptidsl
++* unsigned int trainmode :Should be between 0 and 4; 0:No Mode 1:Multimode
++* 2: T1.413, 3:G.dmt, 4: G.lite
++* RETURN: 0 SUCCESS
++* 1 FAILED
++*
++*****************************************************************************************/
++
++unsigned int dslhal_api_setTrainingMode
++(
++tidsl_t *ptidsl,
++unsigned int trainmode
++);
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_dslRetrain(tidsl_t *ptidsl)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction sends the CMD_QUIET message to the DSP
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_dslRetrain
++(
++tidsl_t *ptidsl
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_acknowledgeInterrupt()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_acknowledgeInterrupt
++(tidsl_t * ptidsl
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_disableDspHybridSelect()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_disableDspHybridSelect
++(tidsl_t * ptidsl,
++ unsigned int disable
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_disableDspHybridSelect()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_selectHybrid
++(tidsl_t * ptidsl,
++ unsigned int hybridNum
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_reportHybridMetrics()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_reportHybridMetrics
++(tidsl_t * ptidsl,
++ int *metric
++);
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_selectInnerOuterPair(tidsl_t *ptidsl, unsigned int pairSelect)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction sends the CMD_QUIET message to the DSP
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++
++unsigned int dslhal_api_selectInnerOuterPair
++(tidsl_t *ptidsl,
++unsigned int pairSelect
++);
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_resetTrainFailureLog(tidsl_t *ptidsl, unsigned int pairSelect)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction sends the CMD_QUIET message to the DSP
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++
++unsigned int dslhal_api_resetTrainFailureLog
++(tidsl_t *ptidsl
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_controlLed()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_configureLed
++(tidsl_t * ptidsl,
++unsigned int idLed,
++unsigned int onOff
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_configureExternBert()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_configureExternBert
++(tidsl_t * ptidsl,
++unsigned int configParm,
++unsigned int parmVal
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_configureAtmBert()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_configureAtmBert
++(tidsl_t * ptidsl,
++unsigned int configParm,
++unsigned int parmVal
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_configureDgaspLpr()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_configureDgaspLpr
++(tidsl_t * ptidsl,
++unsigned int configParm,
++unsigned int parmVal
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_onOffPcb()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_onOffPcb
++(tidsl_t * ptidsl,
++unsigned int onOff
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_onOffBitSwap()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Turns on / off the power cutback feature;
++* Input
++* usDs; 0 = us and 1 = ds;
++* onOff; 0 = OFF and 1 = ON
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_onOffBitSwap
++(tidsl_t * ptidsl,
++ unsigned int usDs,
++ unsigned int onOff
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_configDsTones()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Turns on / off specific tones in the downstream direction;
++* Input
++* pointer to the array specifying the tones to be turned on/off
++*
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_configDsTones
++(tidsl_t * ptidsl,
++ unsigned int *dsTones
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_getAocBitSwapBuffer()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Fetches the Tx/Rx AOC bitswap Buffer;
++* Input
++* Transmit / Receive buffer to be fetched
++*
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_getAocBitswapBuffer
++(tidsl_t * ptidsl,
++unsigned int usDs
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_readTrainingMessages()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Reads all the training messages on demand;
++* Input
++* tidsl_t *ptidsl : Pointer to application structure
++* void *msgStruct : Pointer to Message Structure
++*
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_readTrainingMessages
++(tidsl_t * ptidsl,
++void *msgPtr
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_getTrainingState()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Reads all the training messages on demand;
++* Input
++* tidsl_t *ptidsl : Pointer to application structure
++* void *msgStruct : Pointer to training state structure
++*
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_getTrainingState
++(tidsl_t * ptidsl,
++void *statePtr
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_resetBitSwapMessageLog()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Clears the Aoc Bitswap Message Log
++* Input
++* tidsl_t *ptidsl : Pointer to application structure
++* unsigned int usDs ; Upstream=0, Downstream=1
++*
++* Return: 0 success
++* 1 failed
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_resetBitSwapMessageLog
++(tidsl_t * ptidsl,
++ unsigned int usDs
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_setConstellationBinNumber()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Specifies the bin number for which constellation data should be fetched
++* Input
++* tidsl_t *ptidsl : Pointer to application structure
++* unsigned int binNum : constellation bin number whose data is required
++*
++* Return: 0 success
++* 1 failed
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_setConstellationBinNumber
++(tidsl_t * ptidsl,
++ unsigned int binNum
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_resetTrainStateHistory()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Clears the Training State History Log
++* Input
++* tidsl_t *ptidsl : Pointer to application structure
++*
++*
++* Return: 0 success
++* 1 failed
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_resetTrainStateHistory
++(tidsl_t * ptidsl
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_getSnrPerBin()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Get SNR data per bin
++* Input
++* tidsl_t *ptidsl : Pointer to application structure
++*
++*
++* Return: 0 success
++* 1 failed
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_getSnrPerBin
++(tidsl_t * ptidsl,
++ unsigned int snrBufferOpt
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_logEocMessages()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Logs EOC messages sent by the Modem to the CO
++* Input
++* tidsl_t *ptidsl : Pointer to application structure
++* unsigned int eocLowerBytes : Lower [1-5] bits of EOC Message
++* unsigned int eocUpperBytes : Upper [6-13] bits of EOC Message
++*
++* Return: 0 success
++* 1 failed
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_logEocMessages
++(tidsl_t * ptidsl,
++ unsigned int usDs,
++ unsigned int eocLowerBytes,
++ unsigned int eocUpperBytes
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_getReasonForDrop()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Reads the reason for dropping DSL connection;
++* Input
++* tidsl_t *ptidsl : Pointer to application structure
++
++*
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_getReasonForDrop
++(tidsl_t * ptidsl
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_ctrlMaxAvgFineGains()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Turns on / off the host control for Max Avg Fine Gains; 0 = OFF and 1 = ON
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_ctrlMaxAvgFineGains
++(tidsl_t * ptidsl,
++unsigned int onOff
++);
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_setMaxAvgFineGain()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Set the Maximum Average Fine Gain Value
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_setMaxAvgFineGain
++(tidsl_t * ptidsl,
++ short fineGain
++);
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_readPhySettings()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Reads the advanced Phy layer settings on demand;
++* Input
++* tidsl_t *ptidsl : Pointer to application structure
++* void *cfgStruct : Pointer to Phy Config Structure
++*
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_readPhySettings
++(tidsl_t * ptidsl,
++void *cfgPtr
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_advcfg_setBlackOutBits()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the Blackout Bits in the RMSGPCB message
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_advcfg_setBlackOutBits
++(tidsl_t * ptidsl
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_genericDspRead()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Reads from a generic location in the host interface
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_genericDspRead
++(tidsl_t * ptidsl,
++ unsigned int offset1,
++ unsigned int offset2,
++ unsigned int offset3,
++ unsigned char* localBuffer,
++ unsigned int numBytes
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_genericDspWrite()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Writes to a generic location in the host interface
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_genericDspWrite
++(tidsl_t * ptidsl,
++ unsigned int offset1,
++ unsigned int offset2,
++ unsigned int offset3,
++ unsigned char* localBuffer,
++ unsigned int numBytes
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_dspInterfaceRead()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Reads from a generic location in the host interface
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_dspInterfaceRead
++(tidsl_t * ptidsl,
++ unsigned int baseAddr,
++ unsigned int numOffsets,
++ unsigned int *offsets,
++ unsigned char* localBuffer,
++ unsigned int numBytes
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_api_dspInterfaceWrite()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Writes to a generic location in the host interface
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_api_dspInterfaceWrite
++(tidsl_t * ptidsl,
++ unsigned int baseAddr,
++ unsigned int numOffsets,
++ unsigned int *offsets,
++ unsigned char* localBuffer,
++ unsigned int numBytes
++);
++
++/******************************************************************************************
++ * FUNCTION NAME: dslhal_api_sendMailboxCommand(tidsl_t *ptidsl, unsigned int cmd)
++ *
++ *******************************************************************************************
++ * DESCRIPTION: This fuction sends the passed mailbox command to the DSP
++ *
++ * INPUT: PITIDSLHW_T *ptidsl
++ * unsigned int cmd
++ *
++ * RETURN: 0 SUCCESS
++ * 1 FAILED
++ *
++ *****************************************************************************************/
++unsigned int dslhal_api_sendMailboxCommand
++(tidsl_t *ptidsl,
++unsigned int cmd
++);
++
++#ifdef INTERNAL_BUILD
++#include <dsl_hal_internal_api.h>
++#endif
++
++
++#endif /* pairs #ifndef __DSL_APPLICATION_INTERFACE_H__ */
+diff -urN linux.old/drivers/atm/sangam_atm/dsl_hal_logtable.h linux.dev/drivers/atm/sangam_atm/dsl_hal_logtable.h
+--- linux.old/drivers/atm/sangam_atm/dsl_hal_logtable.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/dsl_hal_logtable.h 2005-08-23 04:46:50.097843696 +0200
+@@ -0,0 +1,259 @@
++unsigned int log10[]=
++{
++ 0,
++ 771,
++ 1221,
++ 1541,
++ 1789,
++ 1992,
++ 2163,
++ 2312,
++ 2443,
++ 2560,
++ 2666,
++ 2763,
++ 2852,
++ 2934,
++ 3011,
++ 3083,
++ 3150,
++ 3213,
++ 3274,
++ 3331,
++ 3385,
++ 3437,
++ 3486,
++ 3533,
++ 3579,
++ 3622,
++ 3664,
++ 3705,
++ 3744,
++ 3781,
++ 3818,
++ 3853,
++ 3887,
++ 3921,
++ 3953,
++ 3984,
++ 4015,
++ 4044,
++ 4073,
++ 4101,
++ 4129,
++ 4156,
++ 4182,
++ 4207,
++ 4232,
++ 4257,
++ 4281,
++ 4304,
++ 4327,
++ 4349,
++ 4371,
++ 4393,
++ 4414,
++ 4435,
++ 4455,
++ 4475,
++ 4495,
++ 4514,
++ 4533,
++ 4552,
++ 4570,
++ 4589,
++ 4606,
++ 4624,
++ 4641,
++ 4658,
++ 4675,
++ 4691,
++ 4707,
++ 4723,
++ 4739,
++ 4755,
++ 4770,
++ 4785,
++ 4800,
++ 4815,
++ 4829,
++ 4844,
++ 4858,
++ 4872,
++ 4886,
++ 4899,
++ 4913,
++ 4926,
++ 4939,
++ 4952,
++ 4965,
++ 4978,
++ 4990,
++ 5003,
++ 5015,
++ 5027,
++ 5039,
++ 5051,
++ 5063,
++ 5075,
++ 5086,
++ 5098,
++ 5109,
++ 5120,
++ 5131,
++ 5142,
++ 5153,
++ 5164,
++ 5174,
++ 5185,
++ 5195,
++ 5206,
++ 5216,
++ 5226,
++ 5236,
++ 5246,
++ 5256,
++ 5266,
++ 5275,
++ 5285,
++ 5295,
++ 5304,
++ 5313,
++ 5323,
++ 5332,
++ 5341,
++ 5350,
++ 5359,
++ 5368,
++ 5377,
++ 5386,
++ 5394,
++ 5403,
++ 5412,
++ 5420,
++ 5429,
++ 5437,
++ 5445,
++ 5454,
++ 5462,
++ 5470,
++ 5478,
++ 5486,
++ 5494,
++ 5502,
++ 5510,
++ 5518,
++ 5525,
++ 5533,
++ 5541,
++ 5548,
++ 5556,
++ 5563,
++ 5571,
++ 5578,
++ 5586,
++ 5593,
++ 5600,
++ 5607,
++ 5614,
++ 5622,
++ 5629,
++ 5636,
++ 5643,
++ 5649,
++ 5656,
++ 5663,
++ 5670,
++ 5677,
++ 5683,
++ 5690,
++ 5697,
++ 5703,
++ 5710,
++ 5716,
++ 5723,
++ 5729,
++ 5736,
++ 5742,
++ 5749,
++ 5755,
++ 5761,
++ 5767,
++ 5773,
++ 5780,
++ 5786,
++ 5792,
++ 5798,
++ 5804,
++ 5810,
++ 5816,
++ 5822,
++ 5828,
++ 5834,
++ 5839,
++ 5845,
++ 5851,
++ 5857,
++ 5862,
++ 5868,
++ 5874,
++ 5879,
++ 5885,
++ 5891,
++ 5896,
++ 5902,
++ 5907,
++ 5913,
++ 5918,
++ 5924,
++ 5929,
++ 5934,
++ 5940,
++ 5945,
++ 5950,
++ 5955,
++ 5961,
++ 5966,
++ 5971,
++ 5976,
++ 5981,
++ 5986,
++ 5992,
++ 5997,
++ 6002,
++ 6007,
++ 6012,
++ 6017,
++ 6022,
++ 6027,
++ 6031,
++ 6036,
++ 6041,
++ 6046,
++ 6051,
++ 6056,
++ 6060,
++ 6065,
++ 6070,
++ 6075,
++ 6079,
++ 6084,
++ 6089,
++ 6093,
++ 6098,
++ 6103,
++ 6107,
++ 6112,
++ 6116,
++ 6121,
++ 6125,
++ 6130,
++ 6134,
++ 6139,
++ 6143,
++ 6148,
++ 6152,
++ 6156,
++ 6161,
++ 6165
++ };
+diff -urN linux.old/drivers/atm/sangam_atm/dsl_hal_register.h linux.dev/drivers/atm/sangam_atm/dsl_hal_register.h
+--- linux.old/drivers/atm/sangam_atm/dsl_hal_register.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/dsl_hal_register.h 2005-08-23 04:46:50.097843696 +0200
+@@ -0,0 +1,337 @@
++#ifndef ___DSL_REGISTER_DEFINES_H___
++#define ___DSL_REGISTER_DEFINES_H___ 1
++
++/*******************************************************************************
++* FILE PURPOSE: DSL HAL H/W Registers and Constant Declarations for Sangam
++*
++********************************************************************************
++* FILE NAME: dsl_hal_register.h
++*
++* DESCRIPTION:
++* Contains DSL HAL APIs for Adam2 OS functions
++*
++*
++* (C) Copyright 2001-02, Texas Instruments, Inc.
++* History
++* Date Version Notes
++* 06Feb03 0.00.00 RamP Created
++* 21Mar03 0.00.01 RamP Changed header files for Modular
++* build framework
++* 21Mar03 0.00.02 RamP Introduced malloc size for DSP f/w
++* 07Apr03 0.00.03 RamP Implemented new error reporting scheme
++* Changed Commenting to C style only
++* 12Apr03 0.00.04 RamP Added Interrupt Mask defines
++* 14Apr03 0.00.05 RamP Renamed macros for REG8, REG16 & REG32
++* 21Apr03 0.01.00 RamP Added Interrupt source/clear registers
++* Changed enum RSTATE_SHOWTIME to 5
++* 24Apr03 0.01.01 RamP Moved the RSTATE enum to api.h
++* Added olay recovery error condition
++* 14May03 0.01.02 RamP Added defines for power computation
++* Added error condition for hybrids
++* 04Jun03 0.01.03 RamP Added enum for config flags,
++* Cleaned up AR5 register defines
++* Added defines for higher data rate
++* 06Jun03 0.01.04 RamP Added error & interrupt defines
++* 09Jun03 0.01.05 RamP Modified enum for current config
++* Added additional C-Rates defines
++* 18Jul03 0.01.06 RamP Modified internal build flow
++* 21Aug03 0.01.07 RamP Added constellation buffer size
++* 08Oct03 0.01.08 RamP Added us/ds Bits n gains size
++* 12Oct03 0.01.08 RamP Added ADSL2 Message sizes, lengths
++* and offsets for various formats
++* 29Oct03 0.01.09 RamP Added ADSL2 Delt offsets & sizes
++* 24Nov03 0.01.10 RamP Added bit field number, scan vector
++* 26Dec03 0.01.11 RamP Removed the oamFeature masks to api.h
++*******************************************************************************/
++
++#include "env_def_typedefs.h"
++#ifdef INTERNAL_BUILD
++#include "dev_host_internalinterface.h"
++#endif
++#include "dev_host_interface.h"
++#include "dsl_hal_api.h"
++
++#define ADSLSS_BASE 0x01000000
++#define BBIF_BASE 0x02000000
++
++#define ADSLSSADR (BBIF_BASE+0x0000)
++#define ADSLSSADRMASK 0xff000000
++#define WAKEUP_DSP 0x00000001
++
++/* Ax7 Reset Control */
++
++#define RST_CNTRL_BASE 0x8611600
++#define RST_CNTRL_PRCR (RST_CNTRL_BASE + 0x00 )
++
++#define RST_CNTRL_PRCR_GPIO 0x00000040
++#define RST_CNTRL_PRCR_ADSLSS 0x00000080
++#define RST_CNTRL_PRCR_USB 0x00000100
++#define RST_CNTRL_PRCR_SAR 0x00000200
++#define RST_CNTRL_PRCR_DSP 0x00800000
++#define RST_CNTRL_PRCR_EMAC1 0x00200000 /* EMAC1 reset */
++
++#define RST_CNTRL_SWRCR (RST_CNTRL_BASE + 0x04 )
++#define RST_SWRCR_SWR0 0x00000001
++#define RST_SWRCR_SWR1 0x00000002
++
++#define RST_CNTRL_RSR (TNETD53XX_RST_CNTRL_BASE + 0x08 )
++#define RST_RSR_RSCAUSE 0x00000003 /* Software Reset Caused by writing to SWR1 bit */
++
++
++/* ******************************************************
++Interrupt sources on Ax7 interrupt controller.
++The reserved sources are noted.
++********************************************************* */
++
++#define INTR_CNTRL_SRC_SECOND 0
++#define INTR_CNTRL_SRC_EXTERNAL0 1
++#define INTR_CNTRL_SRC_EXTERNAL1 2
++/* reserved sources ... */
++#define INTR_CNTRL_SRC_TIMER0 5
++#define INTR_CNTRL_SRC_TIMER1 6
++#define INTR_CNTRL_SRC_UART0 7
++#define INTR_CNTRL_SRC_UART1 8
++#define INTR_CNTRL_SRC_DMA0 9
++#define INTR_CNTRL_SRC_DMA1 10
++/* reserved sources ... */
++#define INTR_CNTRL_SRC_SAR 15
++/* reserved sources ... */
++#define INTR_CNTRL_SRC_EMAC0 19
++/* reserved sources ... */
++#define INTR_CNTRL_SRC_VLYNQ0 21
++#define INTR_CNTRL_SRC_CODEC_WAKE 22
++/* reserved sources ... */
++#define INTR_CNTRL_SRC_USB 24
++#define INTR_CNTRL_SRC_VLYNQ1 25
++/* reserved sources ... */
++#define INTR_CNTRL_SRC_EMAC1 28
++#define INTR_CNTRL_SRC_I2C 29
++#define INTR_CNTRL_SRC_DMA2 30
++#define INTR_CNTRL_SRC_DMA3 31
++/* reserved sources ... */
++#define INTR_CNTRL_SRC_VDMA_RX 37
++#define INTR_CNTRL_SRC_VDMA_TX 38
++#define INTR_CNTRL_SRC_ADSLSS 39
++
++#ifndef K0BASE
++#define K0BASE 0x80000000
++#endif
++
++#ifndef K1BASE
++#define K1BASE 0xA0000000
++#endif
++
++#ifndef PHYS_ADDR
++#define PHYS_ADDR(X) ((X) & 0X1FFFFFFF)
++#endif
++
++#ifndef PHYS_TO_K0
++#define PHYS_TO_K0(X) (PHYS_ADDR(X)|K0BASE)
++#endif
++
++#ifndef PHYS_TO_K1
++#define PHYS_TO_K1(X) (PHYS_ADDR(X)|K1BASE)
++#endif
++
++#ifndef DSLHAL_REG8
++#define DSLHAL_REG8( addr ) (*(volatile unsigned short *) PHYS_TO_K1(addr))
++#endif
++
++#ifndef DSLHAL_REG16
++#define DSLHAL_REG16( addr ) (*(volatile unsigned short *)PHYS_TO_K1(addr))
++#endif
++
++#ifndef DSLHAL_REG32
++#define DSLHAL_REG32( addr ) (*(volatile unsigned int *)PHYS_TO_K1(addr))
++#endif
++
++#ifndef NULL
++#define NULL 0
++#endif
++
++#ifndef TRUE
++#define TRUE (1==1)
++#endif
++
++#ifndef FALSE
++#define FALSE (1==2)
++#endif
++
++/*******************************************************************************
++* Type Defines for Library
++********************************************************************************/
++typedef unsigned int size_t;
++
++#define TIDSL_HW_CREATED 0x00000001
++#define TIDSL_HW_OPENED 0x00000002
++#define TIDSL_HW_STARTED 0x00000004
++#define TIDSL_OS_INITIALIZED 0x00000008
++
++/* Data Pump CRATES Table Defines */
++#define SIZE_OF_CRATES1_TABLE 120
++#define CRATES1_BF_LS0 7
++#define CRATES1_BI_LS0 17
++#define CRATES1_BF_AS0 0
++#define CRATES1_BI_AS0 10
++#define CRATES1_BF_DSRS 20
++#define CRATES1_BI_DSRS 21
++#define CRATES1_BFI_DSS 22
++#define CRATES1_BFI_DSI 23
++#define CRATES1_BF_USRS 25
++#define CRATES1_BI_USRS 26
++#define CRATES1_BFI_USS 27
++#define CRATES1_BFI_USI 28
++
++#define FAST_PATH 0
++#define INTERLEAVED_PATH 1
++
++#define LINE_NOT_CONNECTED 0
++#define LINE_CONNECTED 1
++#define LINE_DISCONNECTED 2
++#define LINE_NOT_TO_CONNECT 3
++
++#define MAXSECTIONS 125
++
++/*****************************************************************************************
++ * Localstructure declarations
++ *
++ ****************************************************************************************/
++enum
++{
++ DSLHAL_ERROR_NO_ERRORS, /* 00 */
++ DSLHAL_ERROR_UNRESET_ADSLSS, /* 01 */
++ DSLHAL_ERROR_RESET_ADSLSS, /* 02 */
++ DSLHAL_ERROR_UNRESET_DSP, /* 03 */
++ DSLHAL_ERROR_RESET_DSP, /* 04 */
++ DSLHAL_ERROR_NO_FIRMWARE_IMAGE, /* 05 */
++ DSLHAL_ERROR_MALLOC, /* 06 */
++ DSLHAL_ERROR_FIRMWARE_MALLOC, /* 07 */
++ DSLHAL_ERROR_DIAG_MALLOC, /* 08 */
++ DSLHAL_ERROR_OVERLAY_MALLOC, /* 09 */
++ DSLHAL_ERROR_CODE_DOWNLOAD, /* 10 */
++ DSLHAL_ERROR_DIAGCODE_DOWNLOAD, /* 11 */
++ DSLHAL_ERROR_BLOCK_READ, /* 12 */
++ DSLHAL_ERROR_BLOCK_WRITE, /* 13 */
++ DSLHAL_ERROR_MAILBOX_READ, /* 14 */
++ DSLHAL_ERROR_MAILBOX_WRITE, /* 15 */
++ DSLHAL_ERROR_MAILBOX_NOMAIL, /* 16 */
++ DSLHAL_ERROR_MAILBOX_OVERFLOW, /* 17 */
++ DSLHAL_ERROR_INVALID_PARAM, /* 18 */
++ DSLHAL_ERROR_ADDRESS_TRANSLATE, /* 19 */
++ DSLHAL_ERROR_FIRMWARE_CRC, /* 20 */
++ DSLHAL_ERROR_FIRMWARE_OFFSET, /* 21 */
++ DSLHAL_ERROR_CONFIG_API_FAILURE, /* 22 */
++ DSLHAL_ERROR_EOCREG_API_FAILURE, /* 23 */
++ DSLHAL_ERROR_VERSION_API_FAILURE, /* 24 */
++ DSLHAL_ERROR_STATS_API_FAILURE, /* 25 */
++ DSLHAL_ERROR_MARGIN_API_FAILURE, /* 26 */
++ DSLHAL_ERROR_CTRL_API_FAILURE, /* 27 */
++ DSLHAL_ERROR_HYBRID_API_FAILURE, /* 28 */
++ DSLHAL_ERROR_MODEMENV_API_FAILURE, /* 29 */
++ DSLHAL_ERROR_INTERRUPT_FAILURE, /* 30 */
++ DSLHAL_ERROR_INTERNAL_API_FAILURE, /* 31 */
++ DSLHAL_ERROR_DIGIDIAG_FAILURE, /* 32 */
++ DSLHAL_ERROR_TONETEST_FAILURE, /* 33 */
++ DSLHAL_ERROR_NOISETEST_FAILURE, /* 34 */
++ DSLHAL_ERROR_MODEMSTATE, /* 35 */
++ DSLHAL_ERROR_OVERLAY_CORRUPTED /* 36 */
++};
++
++enum
++{
++ CONFIG_FLAG_NOFLAG, /* 00 */
++ CONFIG_FLAG_TRELLIS, /* 01 */
++ CONFIG_FLAG_EC, /* 02 */
++ CONFIG_FLAG_RS /* 03 */
++};
++
++#define USE_EMIF_REV 0
++#define USE_CVR_REV 1
++#define TNETD53XX_MAXLOOP 10000
++#define REVERB 0
++#define MEDLEY 1
++#define NONINTENSE 0
++#define slavespace0 0xa1000000
++
++#define MASK_MAILBOX_INTERRUPTS 0x00000001
++#define MASK_BITFIELD_INTERRUPTS 0x00000002
++#define MASK_HEARTBEAT_INTERRUPTS 0x00000004
++#define DSP_INTERRUPT_SOURCE_REGISTER 0x020007A0
++#define DSP_INTERRUPT_CLEAR_REGISTER 0x020007A4
++
++#define DIGITAL_DIAG_MEMSIZE 1048576
++#define CRC32_QUOTIENT 0x04c11db7
++#define DSP_FIRMWARE_MALLOC_SIZE 0x7ffff
++#define DSP_CONSTELLATION_BUFFER_SIZE 1024*4
++#define LOG43125 9303
++#define US_NOMINAL_POWER (-38)
++#define US_BNG_LENGTH 32
++#define DS_BNG_LENGTH 256
++#define NUMBER_OF_BITFIELDS 4
++#define BITFIELD_SCAN 0x80000000
++
++/* ADSL Message offsets from Host Interface Pointer */
++
++/* ADSL2 Messages Index and Length defines */
++
++#define CMSGFMT_INDEX 0
++#define CMSGPCB_INDEX 1
++#define RMSGFMT_INDEX 2
++#define RMSGPCB_INDEX 3
++#define RMSG1LD_INDEX 13
++#define RMSG2LD_INDEX 14
++#define RMSG3LD_INDEX 15
++#define RMSG4LD_INDEX 16
++#define RMSG5LD_INDEX 17
++#define RMSG6LD_INDEX 18
++#define RMSG7LD_INDEX 19
++#define RMSG8LD_INDEX 20
++#define RMSG9LD_INDEX 21
++#define CMSG1LD_INDEX 22
++#define CMSG2LD_INDEX 23
++#define CMSG3LD_INDEX 24
++#define CMSG4LD_INDEX 25
++#define CMSG5LD_INDEX 26
++#define CMSGPCB2_INDEX 28
++#define CMSGPCB2L_INDEX 29
++#define RMSGFMT2_INDEX 30
++#define RMSGPCB2L_INDEX 31
++#define CMSG1ADSL2_INDEX 32
++#define RMSG1ADSL2_INDEX 33
++#define CMSG2ADSL2_INDEX 34
++#define RMSG2ADSL2_INDEX 35
++#define CPARAMS_INDEX 36
++#define RPARAMS_INDEX 37
++
++/* ADSL2 Message Sizes */
++
++#define CMSGFMT_SIZE 2
++#define RMSGFMT_SIZE 2
++#define CMSGPCB_SIZE 2
++#define CMSGPCB2_SIZE 6 /* Annex A with Blackout */
++#define CMSGPCB2L_SIZE 10 /* Annex B with Blackout */
++#define RMSGPCB_SIZE 36
++#define RMSG1LD_SIZE 16
++#define RMSGxLD_SIZE 258
++#define CMSG1LD_SIZE 16
++#define CMSG2LD_SIZE 130
++#define CMSG3LD_SIZE 66
++#define CMSG4LD_SIZE 34
++#define CMSG5LD_SIZE 34
++#define CMSG1ADSL2_SIZE 24
++#define RMSG1ADSL2_SIZE 4
++#define CMSG2ADSL2_SIZE 4
++#define RMSG2ADSL2_SIZE 32
++#define CPARAMS_SIZE 136
++#define RPARAMS_SIZE 808
++
++/* ADSL2 Plus Message Sizes (if Different from ADSL2) */
++
++#define RMSGPCB_P_SIZE 68
++#define CMSG1ADSL2P_SIZE 40 /* With Blackout */
++#define CPARAMS_PA_SIZE 168
++#define RPARAMS_PA_SIZE 2088
++#define CPARAMS_PB_SIZE 296
++#define RPARAMS_PB_SIZE 2088
++
++#endif /* pairs #ifndef ___DSL_REGISTER_DEFINES_H___ */
+diff -urN linux.old/drivers/atm/sangam_atm/dsl_hal_support.c linux.dev/drivers/atm/sangam_atm/dsl_hal_support.c
+--- linux.old/drivers/atm/sangam_atm/dsl_hal_support.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/dsl_hal_support.c 2005-08-23 04:46:50.100843240 +0200
+@@ -0,0 +1,2788 @@
++/*******************************************************************************
++* FILE PURPOSE: DSL Driver API functions for Sangam
++*********************************************************************************
++* FILE NAME: dsl_hal_support.c
++*
++* DESCRIPTION:
++* Contains DSL HAL APIs for Modem Control
++*
++*
++* (C) Copyright 2001-02, Texas Instruments, Inc.
++* History
++* Date Version Notes
++* 06Feb03 0.00.00 RamP Created
++* 21Mar03 0.00.01 RamP Inserted byteswap functions
++* 07Apr03 0.00.02 RamP Implemented new error reporting scheme
++* Changed Commenting to C style only
++* 12Apr03 0.00.03 RamP Added function to set Interrupt Bit
++* Masks for bitfield & Mailboxes
++* 14Apr03 0.00.04 RamP Added function to process modem state
++* bit fields; renamed REG32 macros
++* Changed interrupt bit field settings
++* 15Apr03 0.00.05 RamP Fixed exit condition on dslShutdown
++* 21Apr03 0.01.00 RamP Fixed dslShutdown function & changed
++* loop counter for overlay byteswaps
++* (Alpha) Added cache writeback for overlays
++* Added function acknowledgeInterrupt
++* 22Apr03 0.01.01 RamP Moved acknowledgeInterrupt into api
++* 24Apr03 0.01.02 RamP Added function to compare crc32 with
++* pre-computed value as a recovery
++* scheme for corrupt overlay pages
++* 28Apr03 0.01.03 RamP Fixed a parameter in crc32 fxn call
++* 05May03 0.01.04 RamP Fixed Message structure access in
++* writeHostMailbox function
++* 14May03 0.01.05 RamP Lookup to netService of dsp version
++* (alpha ++) to determine pots/isdn service
++* 21May03 0.01.06 RamP Added support for CO profiles
++* 29May03 0.01.07 RamP Added critical section tabs for block
++* read/write operations
++* Added functions to reload overlay pages
++* and CO Profiles
++* 04Jun03 0.01.08 RamP Added state transition timing counters
++* 06Jun03 0.01.09 RamP Added Interrupt source parsing function
++* Interrupt masking for heartbeat added
++* 09Jun03 0.01.10 RamP Modified modem state bit field processing
++* for structure changes in ITIDSLHW
++* fixed problem in free memory for CO prof
++* 18Jul03 0.01.11 RamP Optimized free memory for CO profiles &
++* overlay pages in the supporting APIs
++* 28Jul03 0.02.00 RamP Modified the process bitfield functn
++* for LED & Application State report
++* 21Aug03 0.03.00 RamP Added logic to allocate & communicate
++* memory for constellation buffer display
++* 29Sep03 0.03.01 RamP Added API switch calls to advcfg module
++* to abstract them from the API module
++* 12Oct03 0.03.02 RamP Added API to gather ADSL2 Messages
++* 14Oct03 0.03.03 RamP Added function to read CMsgsRA
++* 23Oct03 0.03.04 RamP Changed train history index to circular
++* buffer upon rollover
++* 29Oct03 0.03.05 RamP Added Adsl2 Delt Message Parsing
++* 12Nov03 0.03.06 RamP Fixed endianness issues with
++* Constellation Display
++* 14Nov03 0.03.07 RamP Added function to gather CRates1/RRates1
++* before they get overwritten by CRatesRA
++* 19Nov03 0.03.08 JohnP Revised dslhal_support_aocBitSwapProcessing to
++* prevent duplicate ATU-R bitswaps going to ACT
++* 24Nov03 0.03.09 RamP Implemented detailed State Tracking through
++* Modem State bit fields for ADSL/2
++* 12Dec03 0.03.10 RamP Tokenized advanced configuration code
++* 12Dec03 0.03.11 RamP Added state reset upon IDLE
++* 19Dec03 0.03.12 RamP Added static adsl2 byteswap function for
++* handling pointer to pointer cases
++* Changed adsl2 messages to correct pointer to
++* pointer dereferencing problems in some OS
++* 26Dec03 0.03.13 RamP Setting Current Address for Constellation
++* buffer in addition to start address
++* Added additional check to overlay page malloc
++*******************************************************************************/
++#include "dsl_hal_register.h"
++#include "dsl_hal_support.h"
++
++static unsigned int dslhal_support_adsl2ByteSwap32(unsigned int in32Bits);
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_support_unresetDslSubsystem
++*
++*******************************************************************************************
++* DESCRIPTION: This function unreset Dsl Subsystem
++*
++* INPUT: None
++*
++* RETURN: 0 if Pass; 1 if Fail
++*
++*****************************************************************************************/
++int dslhal_support_unresetDslSubsystem(void)
++{
++ dprintf(4," dslhal_support_unresetDslSubsystem()\n");
++ /* Put ADSLSS in to reset */
++ DSLHAL_REG32(0xa8611a10) = 0x1;
++ shim_osClockWait(64);
++ dprintf(5,"Selected APLL Reg \n");
++
++ DSLHAL_REG32(0xa8610a90) = 0x4;
++ shim_osClockWait(64);
++ dprintf(5,"Enable Analog PLL \n");
++
++ DSLHAL_REG32(0xa8610a90) = 0x77fe;
++ shim_osClockWait(64);
++ dprintf(5,"Set PLL for DSP\n");
++
++ /* DSLHAL_REG32(0xa8611600) = 0x007f1bdf;*/
++ DSLHAL_REG32(0xa8611600) |= RST_CNTRL_PRCR_ADSLSS;
++ shim_osClockWait(64);
++ dprintf(5,"Brought ADSLSS out of Reset \n");
++
++ DSLHAL_REG32(0xa861090c) &= ~((1<<20)|(1<<21)|(1<<22)|(1<<23)|(1<<24)|(1<<25));
++ shim_osClockWait(64);
++ dprintf(5,"Configured GPIO 20-25 for McBSP \n");
++
++ /*DSLHAL_REG32(0xa8611600) |= RST_CNTRL_PRCR_ADSLSS;*/
++
++
++ /* DSLHAL_REG32(0xa8611a04) = 0x00000001;
++ shim_osClockWait(64); */
++
++ dprintf(4," dslhal_support_unresetDslSubsystem done\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_support_resetDslSubsystem
++*
++*******************************************************************************************
++* DESCRIPTION: This function unreset Dsl Subsystem
++*
++* INPUT: None
++*
++* RETURN: 0 if Pass; 1 if Fail
++*
++*****************************************************************************************/
++int dslhal_support_resetDslSubsystem(void)
++{
++ dprintf(4, "dslhal_support_resetDslSubsystem \n");
++ /* Put ADSLSS into reset */
++ DSLHAL_REG32(0xa8611600) &= ~RST_CNTRL_PRCR_ADSLSS;
++ shim_osClockWait(64);
++ /* DSLHAL_REG32(0xa8611a04) = 0x00000000;
++ shim_osClockWait(64); */
++ dprintf(4, "dslhal_support_resetDslSubsystem Done \n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_support_unresetDsp()
++*
++*******************************************************************************************
++* DESCRIPTION: This fuction takes ax5 daugter board out of reset.
++*
++* INPUT: None
++*
++* RETURN: 0 --successful.
++* 1 --failed
++*
++*****************************************************************************************/
++int dslhal_support_unresetDsp(void)
++{
++#ifdef PRE_SILICON
++ /* unsigned char value; */
++ int rc;
++
++ rc=dslhal_support_hostDspAddressTranslate((unsigned int)DEV_MDMA0_SRC_ADDR);
++ if(rc==DSLHAL_ERROR_ADDRESS_TRANSLATE)
++ {
++ dprintf(1, "dslhal_support_hostDspAddressTranslate failed\n");
++ return DSLHAL_ERROR_ADDRESS_TRANSLATE;
++ }
++ dprintf(5,"MDMA SRC: %08x\n", rc);
++ DSLHAL_REG32(rc) = 0x80000001;
++ rc=dslhal_support_hostDspAddressTranslate((unsigned int)DEV_MDMA0_DST_ADDR);
++ if(rc==DSLHAL_ERROR_ADDRESS_TRANSLATE)
++ {
++ dprintf(1, "dslhal_support_hostDspAddressTranslate failed\n");
++ return DSLHAL_ERROR_ADDRESS_TRANSLATE;
++ }
++ dprintf(5,"MDMA DST: %08x\n", rc);
++ DSLHAL_REG32(rc) = 0x02090001;
++ rc=dslhal_support_hostDspAddressTranslate((unsigned int)DEV_MDMA0_CTL_ADDR);
++ if(rc== DSLHAL_ERROR_ADDRESS_TRANSLATE)
++ {
++ dprintf(1, "dslhal_support_hostDspAddressTranslate failed\n");
++ return DSLHAL_ERROR_ADDRESS_TRANSLATE;
++ }
++ dprintf(5,"MDMA CTL: %08x\n", rc);
++ DSLHAL_REG32(rc) = (DEV_MDMA_START | DEV_MDMA_DST_INC | DEV_MDMA_SRC_INC |
++ DEV_MDMA_BURST1 | (1 << DEV_MDMA_LEN_SHF));
++ /* statusMask = 0x00000010;*/
++#else
++ dprintf(4, "dslhal_support_unresetDsp()\n");
++
++ /* Bring the DSP core out of reset */
++ /* DSLHAL_REG32(0xa8611600) = 0x00ff1bdf; */
++ DSLHAL_REG32(0xa8611600) |= RST_CNTRL_PRCR_DSP;
++ shim_osClockWait(64);
++ dprintf(5,"Brought DSP out of Reset \n");
++ dprintf(6,"Current Contents of PRCR: 0x%x\n",(unsigned int)DSLHAL_REG32(0xa8611600));
++ /* DSLHAL_REG32(0xa8611a0c) = 0x00000007;
++ shim_osClockWait(64); */
++#endif
++
++ dprintf(4, "dslhal_support_unresetDsp() done\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_support_resetDsp()
++*
++*******************************************************************************************
++* DESCRIPTION: This fuction takes ax5 daugter board into reset.
++*
++* INPUT: None
++*
++* RETURN: 0 --successful.
++* 1 --failed
++*
++*****************************************************************************************/
++int dslhal_support_resetDsp(void)
++{
++ dprintf(4, "dslhal_support_resetDsp \n");
++ /* Put ADSLSS into reset */
++ DSLHAL_REG32(0xa8611600) &= ~RST_CNTRL_PRCR_DSP;
++ shim_osClockWait(64);
++ dprintf(4, "dslhal_support_resetDsp Done \n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_hostDspAddressTranslate()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Maps ax5 daugter card dsp memory address to avalanche memory space
++*
++* Input: unsigned int addr, dsp memory address.
++*
++* Return: >=0, unsigned int, mapped Avalanche address(VBUS address).
++* -1, mapping failed
++*
++*
++********************************************************************************************/
++/* static unsigned int bbifmap0,bbifmap1; */
++
++unsigned int dslhal_support_hostDspAddressTranslate( unsigned int addr )
++{
++ unsigned int addrMap;
++ /* This function should just be used to move the memory window of the ADSLSS */
++ dprintf(5, "dslhal_support_hostDspAddressTranslate()\n");
++
++ /* select vbus to xbus memory */
++ /* addrMap = addr & 0xff000000; */
++ addrMap = addr & ADSLSSADRMASK;
++
++ DSLHAL_REG32(ADSLSSADR) = addrMap;
++
++ dprintf(6, "dslhal_support_hostDspAddressTranslate() done\n");
++#ifdef PRE_SILICON
++ return ((ADSLSS_BASE | (~ADSLSSADRMASK & addr))+ 0x00000100);
++ /* Added 0x100 for Pre-Silicon VLNQ offset.. to be removed for Silicon */
++#else
++ return ((ADSLSS_BASE | (~ADSLSSADRMASK & addr)));
++ /* Added 0x100 for Pre-Silicon VLNQ offset.. to be removed for Silicon */
++#endif
++
++}
++
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_support_blockWrite
++*
++*******************************************************************************************
++* DESCRIPTION: This rouin simulates DSP memory write as done in ax5 pci nic card
++*
++* INPUT: void *buffer, data need to written
++* void *adde, memory address to be written
++* size_t count, number of bytes to be written
++*
++* RETURN: 0 --succeeded
++* 1 --Failed
++*
++*****************************************************************************************/
++
++int dslhal_support_blockWrite(void *buffer, void *addr, size_t count)
++{
++ int rc, byteCnt=0;
++ unsigned char* ptr;
++ union
++ {
++ unsigned char *cptr;
++ short *sptr;
++ int *iptr;
++ } src;
++ union
++ {
++ int anint; /* DSP location */
++ unsigned char *cptr; /* to avoid casts */
++ } dst;
++ union
++ {
++ unsigned int anint;
++ unsigned char byte[4];
++ }data,dword,sword;
++
++ /* Enter Critical Section */
++ shim_osCriticalEnter();
++
++ dprintf(6, "dslhal_support_blockWrite\n");
++
++ dprintf(6,"addr=0x%X, length=0x%X, buffer=0x%X\n", (unsigned int) addr, (unsigned int) count, (unsigned int)buffer);
++
++ src.cptr = (unsigned char*) buffer; /* local buffer */
++ dst.cptr = addr; /* DSP memory location */
++
++ /*Maps address first*/
++ rc=dslhal_support_hostDspAddressTranslate((unsigned int)addr);
++ dprintf(5, "NewAddr: %08x\n", rc);
++ if(rc== DSLHAL_ERROR_ADDRESS_TRANSLATE)
++ {
++ dprintf(1, "dslhal_support_hostDspAddressTranslate failed\n");
++ return DSLHAL_ERROR_ADDRESS_TRANSLATE;
++ }
++
++ dst.cptr=(unsigned char *)rc;
++
++ /* check wether address is at 32bits boundary */
++
++ if ((dst.anint & 0x3) && count)
++ {
++ sword.anint = *(unsigned int*)((unsigned int)src.cptr & 0xfffffffc);
++ dword.anint = DSLHAL_REG32((unsigned int)dst.cptr & 0xfffffffc);
++ sword.anint = (unsigned int) dslhal_support_byteSwap32(sword.anint);
++ dword.anint = (unsigned int) dslhal_support_byteSwap32(dword.anint);
++ ptr = (unsigned char *)((unsigned int)dst.cptr & 0xfffffffc);
++
++ if((dst.anint & 3) ==3) /* last byte of a dword */
++ {
++ dword.byte[3] = sword.byte[3];
++ dst.anint++; /* bump the address by one */
++ byteCnt++;
++ count--;
++ }
++
++ if((dst.anint & 3) ==1) /* second byte */
++ {
++ if(count>3)
++ {
++ dword.byte[3] = sword.byte[3];
++ dst.anint++;
++ count--;
++ byteCnt++;
++ }
++ if(count>2)
++ {
++ dword.byte[2] = sword.byte[2];
++ dst.anint++;
++ count--;
++ byteCnt++;
++ }
++ if(count)
++ {
++ dword.byte[1] = sword.byte[1];
++ dst.anint++;
++ count--;
++ byteCnt++;
++ }
++ }
++
++ if((dst.anint & 3) && (count >1))
++ {
++ dword.byte[2] = sword.byte[2];
++ dword.byte[3] = sword.byte[3];
++ byteCnt+=2;
++ dst.anint += 2; /* bump the address by two */
++ count -= 2; /* decrement the byte count by two */
++ }
++
++ if((dst.anint & 3) && (count==1))
++ {
++ dword.byte[2] = sword.byte[2];
++ dst.anint++;
++ byteCnt++;
++ count--;
++ }
++ src.cptr = (char *)((unsigned int)src.cptr & 0xfffffffc); /* fix 032802 */
++ dword.anint = dslhal_support_byteSwap32(dword.anint);
++ DSLHAL_REG32((unsigned int)ptr) = dword.anint;
++ ptr = src.cptr;
++ for(rc=0;rc<count;rc++)
++ {
++ *ptr = *(ptr+byteCnt);
++ ptr++;
++ }
++ }
++
++ /* the dst pointer should now be on a 32-bit boundary */
++
++ while (count > 3)
++ {
++ DSLHAL_REG32((unsigned int)dst.cptr) = dslhal_support_byteSwap32(*src.iptr);
++ src.iptr++; /* bump the data pointer by four */
++ dst.anint += 4; /* bump the address by four */
++ count -= 4; /* decrement the byte count by four */
++ }
++
++ /* write remaining bytes */
++ if(count)
++ {
++ int i;
++
++ data.anint= DSLHAL_REG32((unsigned int)dst.cptr);
++ data.anint=dslhal_support_byteSwap32(data.anint);
++ for (i=0; i< count; i++)
++ {
++ data.byte[i]=*(src.cptr+i);
++ }
++ data.anint=dslhal_support_byteSwap32(data.anint);
++ DSLHAL_REG32((unsigned int)dst.cptr) = data.anint;
++ src.cptr +=count;
++ dst.anint +=count;
++ count=0;
++ }
++ dprintf(6, "dslhal_support_blockWrite done\n");
++ /* Exit Critical Section */
++ shim_osCriticalExit();
++ return DSLHAL_ERROR_NO_ERRORS;
++} /* end of dslhal_support_blockWrite() */
++
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_support_blockRead
++*
++*********************************************************************************************
++* DESCRIPTION: This rouin simulates DSP memory read as done in ax5 pci nic card
++*
++* INPUT: void *addr, memory address to be read
++* void *buffer, dat buffer to be filled with from memmory
++* size_t count, number of bytes to be written
++*
++* RETURN: 0 --succeeded
++* 1 --Failed
++*
++*****************************************************************************************/
++
++int dslhal_support_blockRead(void *addr, void *buffer, size_t count)
++{
++ int rc;
++ union
++ {
++ int anint; /* DSP location */
++ char *cptr; /* to avoid casts */
++ } src;
++ union
++ {
++ char byte[4];
++ int anint; /* DSP data */
++ } data;
++ union
++ {
++ char *cptr;
++ int *iptr;
++ } dst;
++
++ /* Enter Critical Section */
++ shim_osCriticalEnter();
++
++ dprintf(6,"dslhal_support_blockRead\n");
++
++
++ src.cptr = addr; /* DSP memory location */
++ dst.cptr = buffer; /* local buffer */
++
++ dprintf(6, "Read addr=0x%X, size=0x%X\n", (unsigned int)addr, count);
++
++
++ /*Maps address first*/
++ rc=dslhal_support_hostDspAddressTranslate((unsigned int)addr);
++ if(rc== DSLHAL_ERROR_ADDRESS_TRANSLATE)
++ {
++ dprintf(1, "dslhal_support_hostDspAddressTranslate failed\n");
++ return DSLHAL_ERROR_ADDRESS_TRANSLATE;
++ }
++
++ src.cptr=(unsigned char *)rc;
++
++ /**********************************************
++ * if the source is NOT on a 32-bit boundary *
++ * then we read the full word *
++ * and ignore the first part of it *
++ **********************************************/
++
++ if ((src.anint & 3) && count)
++ {
++ unsigned int anword;
++
++ anword = DSLHAL_REG32((unsigned int)src.cptr & 0xfffffffc);
++ data.anint = dslhal_support_byteSwap32(anword);
++
++ /************************************
++ * there is no need for case 0 *
++ * notice that there are no breaks *
++ * each falls through to the next *
++ ************************************/
++
++ switch (src.anint & 3)
++ {
++ case 1:
++ /* use only byte[1-3] */
++ *(dst.cptr++) = data.byte[1];
++ src.anint++;
++ count--;
++ case 2:
++ /* use byte[2-3] */
++ if (count)
++ {
++ *(dst.cptr++) = data.byte[2];
++ src.anint++;
++ count--;
++ }
++ case 3:
++ /* use byte[3] */
++ if (count)
++ {
++ *(dst.cptr++) = data.byte[3];
++ src.anint++;
++ count--;
++ }
++ }
++ }
++
++ /* the src pointer should now be on a 32-bit boundary */
++ while (count > 3)
++ {
++ unsigned int anword;
++
++ anword=DSLHAL_REG32((unsigned int)src.cptr);
++
++ *dst.iptr = dslhal_support_byteSwap32(anword);
++ src.anint += 4; /* bump the address by four */
++ dst.iptr++; /* bump the data pointer by four */
++ count -= 4; /* decrement the byte count by four */
++ }
++
++ /*******************************
++ * if there's any count left *
++ * then we read the next word *
++ * and ignore the end of it *
++ *******************************/
++ if (count)
++ {
++ unsigned int anword;
++
++ anword= DSLHAL_REG32((unsigned int)src.cptr);
++ data.anint = dslhal_support_byteSwap32(anword);
++
++ /************************************
++ * there is no need for case 0 *
++ * notice that there are no breaks *
++ * each falls through to the next *
++ ************************************/
++ switch (count)
++ {
++ case 1:
++ /* use byte[0] */
++ *(dst.cptr++) = data.byte[0];
++ src.anint++;
++ count--;
++ break;
++ case 2:
++ /* use byte[0-1] */
++ *(dst.cptr++) = data.byte[0];
++ *(dst.cptr++) = data.byte[1];
++ src.anint +=2;
++ count -= 2;
++ break;
++ case 3:
++ /* use only byte[0-2] */
++ *(dst.cptr++) = data.byte[0];
++ *(dst.cptr++) = data.byte[1];
++ *(dst.cptr++) = data.byte[2];
++ src.anint +=3;
++ count -= 3;
++ break;
++ }
++ }
++ /* Exit Critical Section */
++ shim_osCriticalExit();
++
++ return DSLHAL_ERROR_NO_ERRORS;
++
++} /* end of dslhal_support_blockRead() */
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_readDspMailbox
++*
++*********************************************************************************************
++* DESCRIPTION: Reads a message from the mailbox
++*
++* ARGUMENTS: int *pcmd Pointer to command read
++*
++* RETURNS: 0 if successful
++* 1 if no mail
++* NZ otherwise
++*
++*****************************************************************************************/
++
++int dslhal_support_readDspMailbox(tidsl_t *ptidsl, int *pcmd, int *ptag, int *pprm1, int *pprm2)
++{
++ int rc;
++ int cmd;
++ int tag;
++ int prm1;
++ int prm2;
++ unsigned char dspOutInx;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ DEV_HOST_mailboxControl_t mailboxControl;
++ DEV_HOST_dspHostMsg_t dspMailboxMsg[DEV_HOST_DSPQUEUE_LENGTH];
++
++ dprintf(6,"dslhal_support_readDspMailbox\n");
++
++ /* get the DSP main pointer */
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,
++ sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ /* Read in the command/response buffer */
++ dspOamSharedInterface.dspHostMailboxControl_p = (DEV_HOST_mailboxControl_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.dspHostMailboxControl_p);
++
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.dspHostMailboxControl_p,
++ &mailboxControl, sizeof(DEV_HOST_mailboxControl_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ /* Change the endianness of the Mailbox Pointer */
++ mailboxControl.dspMsgBuf_p = (DEV_HOST_dspHostMsg_t *) dslhal_support_byteSwap32((unsigned int)mailboxControl.dspMsgBuf_p);
++
++ rc = dslhal_support_blockRead((PVOID)mailboxControl.dspMsgBuf_p,
++ &dspMailboxMsg, (sizeof(DEV_HOST_dspHostMsg_t)*DEV_HOST_DSPQUEUE_LENGTH));
++
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_READ;
++ /* Extract the command/response message index */
++ mailboxControl.hostInInx &= 7;
++ mailboxControl.hostOutInx &= 7;
++ mailboxControl.dspOutInx &= 7;
++ mailboxControl.dspInInx &= 7;
++
++
++ /* check for messages in the mailbox */
++
++ if (mailboxControl.dspOutInx == mailboxControl.dspInInx)
++ {
++ return DSLHAL_ERROR_MAILBOX_NOMAIL;
++ /* no messages to read */
++ }
++
++ /* use bDRESPOutInx as index to DRESPMsgBuf */
++
++ cmd = dspMailboxMsg[mailboxControl.dspOutInx].cmd;
++ tag = dspMailboxMsg[mailboxControl.dspOutInx].tag;
++ prm1= dspMailboxMsg[mailboxControl.dspOutInx].param1;
++ prm2= dspMailboxMsg[mailboxControl.dspOutInx].param2;
++
++ mailboxControl.dspOutInx++; /* increment count */
++ mailboxControl.dspOutInx &= 7; /* only two bits */
++
++ dspOutInx = mailboxControl.dspOutInx;
++
++ /* Read in the command response buffer again to take care of changes */
++ mailboxControl.dspOutInx = dspOutInx;
++ rc = dslhal_support_blockWrite(&mailboxControl.dspOutInx,
++ &dspOamSharedInterface.dspHostMailboxControl_p->dspOutInx, sizeof(BYTE));
++
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_WRITE;
++
++ /* Is the input parameter address non-zero*/
++
++ if (pcmd)
++ {
++ *pcmd = cmd;
++ }
++ if (ptag)
++ {
++ *ptag = tag;
++ }
++ if (pprm1)
++ {
++ *pprm1 = prm1;
++ }
++ if (pprm2)
++ {
++ *pprm2 = prm2;
++ }
++
++ dprintf(6,"dslhal_support_readDspMailbox done\n");
++ dprintf(6,"cmd=%d, tag=%d\n", cmd, tag);
++ dprintf(6,"dslhal_support_readDspMailbox:cmd: 0x%x, tag=%d\n", cmd, tag);
++ return DSLHAL_ERROR_NO_ERRORS;
++
++} /* end of dslhal_support_readDspMailbox() */
++
++/*******************************************************************************************
++* FUNCTION NAME: dslhal_support_writeHostMailbox
++*
++********************************************************************************************
++* DESCRIPTION: Send a message to a mailbox
++*
++* ARGUMENTS: int cmd command to write
++* int tag tag (currently unused)
++* int p1 parameter 1 (currently unused)
++* int p2 parameter 2 (currently unused)
++*
++* RETURNS: 0 if successful
++* NZ otherwise
++*
++*******************************************************************************************/
++
++int dslhal_support_writeHostMailbox(tidsl_t *ptidsl, int cmd, int tag, int p1, int p2)
++{
++ int rc;
++ int index;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ DEV_HOST_mailboxControl_t mailboxControl;
++ DEV_HOST_dspHostMsg_t hostMailboxMsg[DEV_HOST_HOSTQUEUE_LENGTH];
++ unsigned char hostInInx;
++
++ dprintf(6,"dslhal_support_writeHostMailbox:cmd: 0x%x, tag=%d\n", cmd, tag);
++
++ dprintf(6,"cmd=%d, tag=%d\n", cmd, tag);
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,
++ sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ /* Read in the command/response buffer */
++ dspOamSharedInterface.dspHostMailboxControl_p = (DEV_HOST_mailboxControl_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.dspHostMailboxControl_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.dspHostMailboxControl_p,
++ &mailboxControl, sizeof(DEV_HOST_mailboxControl_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ /* Change the endianness of the Mailbox Control Pointer */
++ mailboxControl.hostMsgBuf_p = (DEV_HOST_dspHostMsg_t *) dslhal_support_byteSwap32((unsigned int)mailboxControl.hostMsgBuf_p);
++ rc = dslhal_support_blockRead((PVOID)mailboxControl.hostMsgBuf_p,
++ &hostMailboxMsg, (sizeof(DEV_HOST_dspHostMsg_t)*DEV_HOST_HOSTQUEUE_LENGTH));
++
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_READ;
++ /* Extract the command/response message index */
++ mailboxControl.hostInInx &= 7;
++ mailboxControl.hostOutInx &= 7;
++ mailboxControl.dspOutInx &= 7;
++ mailboxControl.dspInInx &= 7;
++
++ /* make sure there's room in the mailbox */
++
++ index = mailboxControl.hostInInx;
++ mailboxControl.hostInInx++;
++ mailboxControl.hostInInx &= 7;
++ hostInInx = mailboxControl.hostInInx;
++ if (mailboxControl.hostInInx == mailboxControl.hostOutInx)
++ {
++ /* mailbox is full */
++ return DSLHAL_ERROR_MAILBOX_OVERFLOW;
++ }
++
++ /* use bOCMDInInx as index to OCMDMsgBuf */
++ hostMailboxMsg[index].cmd = (BYTE) cmd;
++ hostMailboxMsg[index].tag = (BYTE) tag;
++ hostMailboxMsg[index].param1 = (BYTE) p1;
++ hostMailboxMsg[index].param2 = (BYTE) p2;
++ rc = dslhal_support_blockWrite(&hostMailboxMsg,
++ (PVOID)mailboxControl.hostMsgBuf_p,
++ sizeof(DEV_HOST_dspHostMsg_t)*DEV_HOST_HOSTQUEUE_LENGTH);
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockWrite failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ rc = dslhal_support_blockWrite(&mailboxControl,
++ &dspOamSharedInterface.dspHostMailboxControl_p,
++ sizeof(DEV_HOST_mailboxControl_t));
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_WRITE;
++ /* update the index */
++ mailboxControl.hostInInx = hostInInx;
++ rc = dslhal_support_blockWrite(&mailboxControl.hostInInx,
++ &dspOamSharedInterface.dspHostMailboxControl_p->hostInInx,
++ sizeof(BYTE));
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_WRITE;
++
++ dprintf(6,"dslhal_support_writeHostMailbox done\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++
++}
++/* end of dslhal_support_writeHostMailbox() */
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_readTextMailbox
++*
++*********************************************************************************************
++* DESCRIPTION: Reads a message from the mailbox
++*
++* ARGUMENTS: int *pcmd Pointer to command read
++*
++* RETURNS: 0 if successful
++* 1 if no mail
++* NZ otherwise
++*
++*****************************************************************************************/
++
++int dslhal_support_readTextMailbox(tidsl_t *ptidsl, int *pmsg1, int *pmsg2)
++{
++ int rc;
++ unsigned int msg1;
++ unsigned int msg2;
++ unsigned char textOutInx;
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ DEV_HOST_mailboxControl_t mailboxControl;
++ DEV_HOST_textMsg_t textMailboxMsg[DEV_HOST_TEXTQUEUE_LENGTH];
++
++ dprintf(6,"dslhal_support_readTextMailbox\n");
++
++ /* get the DSP main pointer */
++
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterfacePtr_t) ptidsl->pmainAddr;
++
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,
++ sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ /* Read in the command/response buffer */
++ dspOamSharedInterface.dspHostMailboxControl_p = (DEV_HOST_mailboxControl_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.dspHostMailboxControl_p);
++
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.dspHostMailboxControl_p,
++ &mailboxControl, sizeof(DEV_HOST_mailboxControl_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ /* Change the endianness of the Mailbox Pointer */
++ mailboxControl.textMsgBuf_p = (DEV_HOST_textMsg_t *) dslhal_support_byteSwap32((unsigned int)mailboxControl.textMsgBuf_p);
++
++ rc = dslhal_support_blockRead((PVOID)mailboxControl.textMsgBuf_p,
++ &textMailboxMsg, (sizeof(DEV_HOST_textMsg_t)*DEV_HOST_DSPQUEUE_LENGTH));
++
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_READ;
++ /* Extract the command/response message index */
++
++ mailboxControl.textInInx &= 7;
++ mailboxControl.textOutInx &= 7;
++
++ /* check for messages in the mailbox */
++
++ if (mailboxControl.textOutInx == mailboxControl.textInInx)
++ {
++ return DSLHAL_ERROR_MAILBOX_NOMAIL;
++ /* no messages to read */
++ }
++
++ /* use bDRESPOutInx as index to DRESPMsgBuf */
++
++ msg1 = textMailboxMsg[mailboxControl.textOutInx].msgPart1;
++ msg2 = textMailboxMsg[mailboxControl.textOutInx].msgPart2;
++ msg1 = (unsigned int) dslhal_support_byteSwap32((unsigned int)msg1);
++ msg2 = (unsigned int) dslhal_support_byteSwap32((unsigned int)msg2);
++
++ mailboxControl.textOutInx++; /* increment count */
++ mailboxControl.textOutInx &= 7; /* only two bits */
++
++ textOutInx = mailboxControl.textOutInx;
++
++ /* Read in the command response buffer again to take care of changes */
++
++ mailboxControl.textOutInx = textOutInx;
++
++ rc = dslhal_support_blockWrite(&mailboxControl.textOutInx,
++ &dspOamSharedInterface.dspHostMailboxControl_p->textOutInx, sizeof(BYTE));
++
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_WRITE;
++
++ /* Is the input parameter address non-zero*/
++
++ if (pmsg1)
++ {
++ *pmsg1 = msg1;
++ }
++ if (pmsg2)
++ {
++ *pmsg2 = msg2;
++ }
++
++ dprintf(6,"dslhal_support_readTextMailbox done\n");
++ dprintf(6,"msgPart1=%d, msgPart2=%d\n", msg1, msg2);
++ dprintf(6,"dslhal_support_readTextMailbox:Message Part1: 0x%x, tag=0x%x\n", msg1, msg2);
++ return DSLHAL_ERROR_NO_ERRORS;
++
++} /* end of dslhal_support_readTextMailbox() */
++
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_hostDspCodeDownload()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* download DSP image from host memory to dsp memory
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++
++int dslhal_support_hostDspCodeDownload(tidsl_t * ptidsl)
++{
++
++ unsigned int index;
++ int rc = 0, i;
++ unsigned char *iptr; /* image pointer */
++ unsigned int numbytes,olayXfer,olayStore;
++ /* unsigned int holdSecPhyAddr=0,holdSecVirtAddr; */
++ unsigned int *olayStart;
++ size_t len; /* size of the file */
++ size_t expoffset; /* expected offset for next section header */
++ unsigned short checksum;
++ unsigned int crc32;
++ unsigned char * image;
++ char *tmp = (char *)DEV_HOST_DSP_OAM_POINTER_LOCATION;
++ DEV_HOST_dspVersionDef_t dspVersion;
++#if SWTC
++ DEV_HOST_tcHostCommDef_t TCHostCommDef;
++#endif
++ DEV_HOST_oamWrNegoParaDef_t OamWrNegoParaDef;
++ DEV_HOST_dspOamSharedInterface_t dspOamSharedInterface, *pdspOamSharedInterface;
++ DEV_HOST_olayDpDef_t olayDpParms;
++ DEV_HOST_profileBase_t profileList;
++#ifndef NO_ACT
++ DEV_HOST_consBufDef_t constDisp;
++#endif
++#if CO_PROFILES
++ DEV_HOST_coData_t coData;
++#endif
++ DEV_HOST_olayDpPageDef_t olayDpPageDef[NUM_PAGES];
++ union
++ {
++ char byte[4];
++ unsigned short hword[2];
++ unsigned int aword;
++ } data;
++
++ struct _header
++ {
++ char signature[6];
++ unsigned short sectcount;
++ unsigned int length;
++ } header;
++
++ struct _section
++ {
++ unsigned int addr;
++ unsigned int length;
++ unsigned int offset;
++ unsigned int page;
++ };/* section[MAXSECTIONS]; */
++
++ struct _section *sptr;
++ unsigned int secAddr, secLength, secOffset, secPage;
++
++
++ dprintf(5,"dslhal_support_hostDspCodeDownload\n");
++ image = ptidsl->fwimage;
++
++ if (!image)
++ {
++ dprintf(1,"no image file\n");
++ return DSLHAL_ERROR_NO_FIRMWARE_IMAGE;
++ }
++
++ iptr=image;
++
++ numbytes = sizeof(header);
++
++ shim_osMoveMemory((char *) &header, (char *)iptr, numbytes);
++ header.length = dslhal_support_byteSwap32(header.length);
++ header.sectcount = dslhal_support_byteSwap16(header.sectcount);
++#if 0
++ crc32 = dslhal_support_computeCrc32((unsigned char*)&crcTest[0],20);
++ dprintf(6,"CRC-32 for the crcTest: 0x%x",crc32);
++ dprintf(4,"header.length=%d, header.sectcount=0x%X\n", header.length, header.sectcount);
++#endif
++ /* point to the checksum */
++ /* compute the checksum on CRC32 here */
++ iptr = image + header.length-4;
++ numbytes = sizeof(data.aword);
++
++ dprintf(5,"tiload: check checksum\n");
++ shim_osMoveMemory((char *)&(data.byte), (char *)iptr, numbytes);
++
++ crc32 = dslhal_support_computeCrc32(image,ptidsl->imagesize);
++ dprintf(5,"CRC-32 for the Binary: 0x%x",crc32);
++ /* CRC currently not added to the DSP binary, so this code is commented out */
++ /*
++ data.aword = dslhal_support_byteSwap32(data.aword);
++ if (data.aword != crc32)
++ {
++ dprintf(1,"Checksum error\n");
++ }
++ */
++ /* Verify signature - Changed from "320C6x" to "TIDSL" for load 80 */
++
++ header.signature[5]='\0';
++ dprintf(5, "signature=%s\n", header.signature);
++
++ if (shim_osStringCmp(header.signature, "TIDSL"))
++ {
++ dprintf(1,"Signature not match\n");
++ return DSLHAL_ERROR_FIRMWARE_OFFSET;
++ }
++
++ dprintf(5,"tiload: check sect count\n");
++ /* check section count */
++
++ if (header.sectcount > MAXSECTIONS)
++ {
++ dprintf(1,"Section # %d exceeds max %d\n", header.sectcount, MAXSECTIONS);
++ return DSLHAL_ERROR_FIRMWARE_OFFSET;
++ }
++ else
++ {
++ dprintf(5,"found %d sections\n", header.sectcount);
++ }
++
++ /* Validation of Section offsets */
++
++ /* point to the first section */
++ len = header.length; /* file size in bytes */
++ expoffset = sizeof(struct _header) + header.sectcount * sizeof(struct _section);
++
++ dprintf(5,"tiload: check offset\n");
++ for (index=0; index<header.sectcount; index++) /* parse the sections one by one */
++ {
++ numbytes = sizeof(struct _header) + index * sizeof(struct _section); /* Compute Section Offset */
++ sptr = (struct _section *)(image + numbytes); /* Section Pointer to beginning of the section */
++
++ secAddr = dslhal_support_byteSwap32(sptr->addr);
++ secOffset = dslhal_support_byteSwap32(sptr->offset);
++ secLength = dslhal_support_byteSwap32(sptr->length);
++ secPage = dslhal_support_byteSwap32(sptr->page);
++
++ /* validate offset */
++ if ( secOffset== 0xffffffff)
++ {
++ /* special case: zero fill */
++ /* offset is valid, don't change expoffset */
++ }
++ else
++ {
++ if (secOffset > len-4)
++ {
++ dprintf(5,"Offset error\n");
++ return DSLHAL_ERROR_FIRMWARE_OFFSET;
++ }
++
++ /* determine expected offset of NEXT section */
++ expoffset = secLength + secOffset;
++
++ /* all addresses must be on word boundaries */
++ if (secAddr & 3)
++ {
++
++ }
++ }
++ }
++
++ /* check final offset - should just be a checksum left */
++/* IMPORTANT 11/24/02 --> Got this error... but bypassed for Pf of Concept*/
++ /*
++ if (expoffset != len-4)
++ {
++ dprintf(5,"Final offset error\n");
++ return DSLHAL_ERROR_FIRMWARE_OFFSET;
++ }
++ */
++
++ /* Actual Code loading to DSP Memory */
++
++ /* Initialize DSP Data Memory before code load*/
++ dprintf(5,"Zero Prefill DSP DMEM\n");
++ DSLHAL_REG32(ADSLSSADR)=0x80000000;
++ shim_osZeroMemory((char *)0xa1000000, 0x10000);
++ /* Load sections from the image */
++ for (index=0; index<header.sectcount; index++) /* Parse each section */
++ {
++ numbytes = sizeof(header) + index * sizeof(struct _section); /* Compute offset to next section */
++ sptr = (struct _section *)(image + numbytes); /* Point to next section */
++
++ secAddr = dslhal_support_byteSwap32(sptr->addr);
++ secOffset = dslhal_support_byteSwap32(sptr->offset);
++ secLength = dslhal_support_byteSwap32(sptr->length);
++ secPage = dslhal_support_byteSwap32(sptr->page);
++
++ data.aword = secAddr;
++ checksum += data.byte[0] + data.byte[1] + data.byte[2] + data.byte[3];
++
++ data.aword = secLength;
++ checksum += data.byte[0] + data.byte[1] + data.byte[2] + data.byte[3];
++
++ data.aword = secOffset;
++ checksum += data.byte[0] + data.byte[1] + data.byte[2] + data.byte[3];
++
++ data.aword = secPage;
++ checksum += data.byte[0] + data.byte[1] + data.byte[2] + data.byte[3];
++
++
++ /* validate offset */
++ if (secOffset == 0xffffffff)
++ {
++ /* special case: zero fill */
++ /* offset is valid, don't change expoffset */
++ }
++ else
++ {
++ /* real offset */
++ if(secOffset > len-4)
++ {
++ dprintf(5,"section[%u] offset too big (%X/%X)\n", index,
++ secOffset, len-4);
++
++ return DSLHAL_ERROR_FIRMWARE_OFFSET;
++ }
++
++ /* determine expected offset of NEXT section */
++ expoffset = secLength + secOffset;
++
++ }
++
++ }
++
++ /* check final offset - should just be a checksum left */
++ /*
++ if(expoffset != len-4)
++ {
++ dprintf(1,"sections don't span full file (%X/%X)\n",expoffset,len-2);
++ return DSLHAL_ERROR_FIRMWARE_OFFSET;
++ }
++ */
++ dprintf(5,"tiload: load binary\n");
++
++ for (index=0; index<header.sectcount; index++)
++ {
++ numbytes = sizeof(header) + index * sizeof(struct _section);
++ sptr = (struct _section *)(image + numbytes);
++
++ secAddr = dslhal_support_byteSwap32(sptr->addr);
++ secOffset = dslhal_support_byteSwap32(sptr->offset);
++ secLength = dslhal_support_byteSwap32(sptr->length);
++ secPage = dslhal_support_byteSwap32(sptr->page);
++ dprintf(5,"loading section %u\n", index);
++ dprintf(5,"section %u: addr: %X\n", index, secAddr);
++ dprintf(5,"section %u: length: %X\n", index, secLength);
++ dprintf(5,"section %u: offset: %X\n", index, secOffset);
++ dprintf(5,"section %u: page: %X\n", index, secPage);
++
++ /* point to the section's data */
++ if(secOffset != 0xffffffff)
++ {
++ /* Load this section of data */
++ iptr = image + secOffset;
++ dprintf(6, "iptr %8x\n", (unsigned int)iptr);
++ }
++
++ if(secPage)
++ {
++ dprintf(6,"OVERLAY PAGE #%d\n",secPage);
++ /* overlay page, don't write to dsp yet, save into host memory*/
++
++ dprintf(6,"Section Length: %d \n",secLength);
++ ptidsl->olayDpPage[secPage].PmemStartWtAddr = (unsigned int) shim_osAllocateDmaMemory(secLength);
++ if(ptidsl->olayDpPage[secPage].PmemStartWtAddr == NULL)
++ {
++ dprintf(1, "overlay page allocate error\n");
++ return DSLHAL_ERROR_OVERLAY_MALLOC;
++ }
++#ifdef PRE_SILICON
++ ptidsl->olayDpPage[secPage].overlayHostAddr = ((((ptidsl->olayDpPage[secPage].PmemStartWtAddr)-0x84000000)-0x10000000)+0x030b0000);
++#else
++ /* ptidsl->olayDpPage[secPage].overlayHostAddr = ((unsigned int)(ptidsl->olayDpPage[secPage].PmemStartWtAddr)&~0xe0000000); */
++ ptidsl->olayDpPage[secPage].overlayHostAddr = virtual2Physical((unsigned int)ptidsl->olayDpPage[secPage].PmemStartWtAddr);
++#endif
++ dprintf(6,"Allocated Addr: 0x%x \t Xlated Addr: 0x%x \n",ptidsl->olayDpPage[secPage].PmemStartWtAddr,ptidsl->olayDpPage[secPage].overlayHostAddr);
++
++ ptidsl->olayDpPage[secPage].overlayHostAddr = (unsigned int)dslhal_support_byteSwap32(ptidsl->olayDpPage[secPage].overlayHostAddr);
++ ptidsl->olayDpPage[secPage].OverlayXferCount = secLength;
++ ptidsl->olayDpPage[secPage].BinAddr = secAddr;
++ ptidsl->olayDpPage[secPage].SecOffset = secOffset;
++ shim_osMoveMemory((char *)ptidsl->olayDpPage[secPage].PmemStartWtAddr, (char *)iptr, secLength);
++ /* RamP Image ByteSwap test */
++ olayStart = (unsigned int *)ptidsl->olayDpPage[secPage].PmemStartWtAddr;
++
++ for(olayXfer=0;olayXfer< secLength/4;olayXfer++)
++ {
++ olayStore = *(unsigned int *)olayStart;
++ olayStore = (unsigned int)dslhal_support_byteSwap32(olayStore);
++ *(unsigned int*)olayStart = olayStore;
++ dprintf(5, "Addr:0x%x \t Content: 0x%x \n",olayStart,olayStore);
++ olayStart++;
++ olayStore=0;
++ }
++ /* RamP Image ByteSwap test */
++ /* compute the CRC of each overlay page and Store the Checksum in a local global variable */
++ /* This Value of CRC is to be compared with the header where all the CRC bytes are lumped together */
++ ptidsl->olayDpPage[secPage].olayPageCrc32 = dslhal_support_computeCrc32((char *)ptidsl->olayDpPage[secPage].PmemStartWtAddr, ptidsl->olayDpPage[secPage].OverlayXferCount);
++
++ shim_osWriteBackCache((void *)ptidsl->olayDpPage[secPage].PmemStartWtAddr, secLength);
++ }
++ else
++ {
++ rc = secAddr&0xff000000;
++ if(rc && rc!=0x80000000)
++ {
++ dprintf(4,"Not DSP PMEM/DMEM\n");
++ /* don't write to dsp, save into host memory*/
++ dprintf(4,"Section Addr: %x Section Length: %d \n",secAddr,secLength);
++ ptidsl->coProfiles.PmemStartWtAddr = (unsigned int) shim_osAllocateDmaMemory(secLength);
++ if(ptidsl->coProfiles.PmemStartWtAddr == NULL)
++ {
++ dprintf(1, "memory allocate error\n");
++ return DSLHAL_ERROR_OVERLAY_MALLOC;
++ }
++ ptidsl->coProfiles.overlayHostAddr = virtual2Physical((unsigned int)ptidsl->coProfiles.PmemStartWtAddr);
++ dprintf(4,"Allocated Addr: 0x%x \t Xlated Addr: 0x%x \n",ptidsl->coProfiles.PmemStartWtAddr, ptidsl->coProfiles.overlayHostAddr);
++ ptidsl->coProfiles.overlayHostAddr = (unsigned int)dslhal_support_byteSwap32(ptidsl->coProfiles.overlayHostAddr);
++ ptidsl->coProfiles.OverlayXferCount = secLength;
++ ptidsl->coProfiles.BinAddr = secAddr;
++ ptidsl->coProfiles.SecOffset = secOffset;
++
++ shim_osMoveMemory((char *)ptidsl->coProfiles.PmemStartWtAddr, (char *)iptr, secLength);
++ /* RamP Image ByteSwap test */
++ olayStart = (unsigned int *)ptidsl->coProfiles.PmemStartWtAddr;
++
++ for(olayXfer=0;olayXfer< secLength/4;olayXfer++)
++ {
++ olayStore = *(unsigned int *)olayStart;
++ olayStore = (unsigned int)dslhal_support_byteSwap32(olayStore);
++ *(unsigned int*)olayStart = olayStore;
++ dprintf(5, "Addr:0x%x \t Content: 0x%x \n",olayStart,olayStore);
++ olayStart++;
++ olayStore=0;
++ }
++ shim_osWriteBackCache((void *)ptidsl->coProfiles.PmemStartWtAddr, secLength);
++ }
++ else
++ {
++ /* IMPORTANT: write image to DSP memory */
++ rc=dslhal_support_blockWrite((void *)iptr, (void *)secAddr, secLength);
++ if(rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ shim_osClockWait(0x50000);
++ /*
++ rc=dslhal_support_blockRead((void*)secAddr, (void*)tmpBuffer, secLength);
++ if(rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ for(i=0;i<secLength;i++)
++ {
++ if(*iptr
++ }*/
++ }
++ }
++ } /* end of write dsp image */
++
++ /***********************************************************************************
++ * Start to fillup various values to our hardware structure for late use
++ ************************************************************************************/
++
++ /* get main pointer for data */
++
++ rc = dslhal_support_blockRead(tmp, &pdspOamSharedInterface, sizeof(unsigned int));
++ dprintf(5, "tmp=0x%X, addr=0x%X\n", (unsigned int)tmp, (unsigned int)pdspOamSharedInterface);
++ pdspOamSharedInterface= (DEV_HOST_dspOamSharedInterface_t *)dslhal_support_byteSwap32((unsigned int)pdspOamSharedInterface);
++ dprintf(5, "tmp=0x%X, addr=0x%X\n", (unsigned int)tmp, (unsigned int)pdspOamSharedInterface);
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ if(!pdspOamSharedInterface)
++ {
++ dprintf(1,"Couldn't read main pointer\n");
++ return DSLHAL_ERROR_INVALID_PARAM;
++ }
++
++ ptidsl->pmainAddr=pdspOamSharedInterface;
++
++ /* read the OamSharedInterfaceStructure */
++
++ dprintf(5,"ptidsl->hostIf.mainAddr=0x%X\n", (unsigned int)ptidsl->pmainAddr);
++
++ /* get the pointer to DSP-OAM Shared Interface */
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,
++ sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ /* Communicate the Allocated Memory Address to DSP to choose CO Profiles */
++
++ /* Change the Endianness of the profileList pointer */
++ dspOamSharedInterface.profileList_p = (DEV_HOST_profileBase_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.profileList_p);
++ /* Access the profileList Structure */
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.profileList_p,&profileList, sizeof(DEV_HOST_profileBase_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ dprintf(2,"Old Addr:%x New: %x \n",profileList.hostProfileBase_p,ptidsl->coProfiles.overlayHostAddr);
++ profileList.hostProfileBase_p = (DEV_HOST_coData_t *)ptidsl->coProfiles.overlayHostAddr;
++ rc = dslhal_support_blockWrite(&profileList,(PVOID)dspOamSharedInterface.profileList_p,sizeof(DEV_HOST_profileBase_t));
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_WRITE;
++
++ /* Communicate the Allocated Memory Address to DSP to do overlays */
++
++ /* Change the Endianness of the olayDpDef pointer */
++ dspOamSharedInterface.olayDpParms_p = (DEV_HOST_olayDpDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.olayDpParms_p);
++ /* Access the olayDpDef Structure */
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.olayDpParms_p,&olayDpParms, sizeof(DEV_HOST_olayDpDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++
++ for(i=1;i<NUM_PAGES;i++)
++ {
++ /* Change the endianness of the olayDpPageDef Pointer */
++ olayDpParms.olayDpPage_p[i] = (DEV_HOST_olayDpPageDef_t *) dslhal_support_byteSwap32((unsigned int)olayDpParms.olayDpPage_p[i]);
++ /* Access the olayDpPageDef Structure */
++ rc = dslhal_support_blockRead((PVOID)olayDpParms.olayDpPage_p[i],&olayDpPageDef[i],sizeof(DEV_HOST_olayDpPageDef_t));
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_READ;
++ olayDpPageDef[i].overlayHostAddr = ptidsl->olayDpPage[i].overlayHostAddr;
++ rc = dslhal_support_blockWrite(&olayDpPageDef[i],(PVOID)olayDpParms.olayDpPage_p[i],sizeof(DEV_HOST_olayDpPageDef_t));
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_WRITE;
++ }
++
++ /* Change the endianness of the Datapump Version Pointer */
++ dspOamSharedInterface.datapumpVersion_p = (DEV_HOST_dspVersionDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.datapumpVersion_p);
++
++ /* get DSPVersion itself */
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.datapumpVersion_p,&dspVersion, sizeof(DEV_HOST_dspVersionDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ /* table_dsp info */
++#if SWTC
++ dspOamSharedInterface.tcHostComm_p = (DEV_HOST_tcHostCommDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.tcHostComm_p);
++ rc = dslhal_support_blockRead(&pdspOamSharedInterface->tcHostComm_p,
++ &pTCHostCommDef, 4);
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ pTCHostCommDef=(DEV_HOST_tcHostCommDef_t *) dslhal_support_byteSwap32((unsigned int)pTCHostCommDef);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.tcHostComm_p,
++ &TCHostCommDef, sizeof(DEV_HOST_tcHostCommDef_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++#endif
++ /* Select the Multimode Training */
++ dspOamSharedInterface.oamWriteNegoParams_p = (DEV_HOST_oamWrNegoParaDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.oamWriteNegoParams_p);
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.oamWriteNegoParams_p, &OamWrNegoParaDef, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++switch(dspVersion.netService)
++ {
++ case 1: OamWrNegoParaDef.stdMode = MULTI_MODE;
++ dprintf(5,"POTS Service \n");
++ ptidsl->netService = 1;
++ break;
++ case 2: OamWrNegoParaDef.stdMode = GDMT_MODE;
++ dprintf(5,"ISDN Service \n");
++ ptidsl->netService = 2;
++ break;
++ default: OamWrNegoParaDef.stdMode = T1413_MODE;
++ dprintf(5,"Default Service \n");
++ break;
++ }
++
++ ptidsl->AppData.StdMode = (unsigned int)OamWrNegoParaDef.stdMode;
++
++ OamWrNegoParaDef.oamFeature = dslhal_support_byteSwap32((OAMFEATURE_TC_SYNC_DETECT_MASK));
++ /* Set the flag to start retraining if the margin of the modem drops below
++ default margin during showtime */
++
++ OamWrNegoParaDef.marginMonitorShwtme = FALSE;
++ /* Set the flag to start retraining if the margin of the modem drops below default margin during training */
++
++ OamWrNegoParaDef.marginMonitorTrning = FALSE;
++ OamWrNegoParaDef.dsToneTurnoff_f = 0;
++ dslhal_support_blockWrite(&OamWrNegoParaDef,
++ (PVOID)dspOamSharedInterface.oamWriteNegoParams_p, sizeof(DEV_HOST_oamWrNegoParaDef_t));
++ rc=dslhal_support_setInterruptMask(ptidsl,0);
++ if(rc!=DSLHAL_ERROR_NO_ERRORS)
++ return rc;
++ /* Co Profile Test */
++#if CO_PROFILES
++ dspOamSharedInterface.profileList_p = (DEV_HOST_profileBase_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.profileList_p);
++ /* Access the profileList Structure */
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.profileList_p,&profileList, sizeof(DEV_HOST_profileBase_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ profileList.hostProfileBase_p = (DEV_HOST_coData_t *)dslhal_support_byteSwap32((unsigned int)profileList.hostProfileBase_p);
++ rc = dslhal_support_blockRead((PVOID)profileList.hostProfileBase_p,&coData, sizeof(DEV_HOST_coData_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ dprintf(2,"Current Profile Vendor Id: %x \n",coData.phyAgcPgaTarget);
++ coData.phyAgcPgaTarget = 0xcaba;
++ rc = dslhal_support_blockWrite(&coData,(PVOID)profileList.hostProfileBase_p,sizeof(DEV_HOST_coData_t));
++ if(rc)
++ return DSLHAL_ERROR_BLOCK_WRITE;
++#endif
++ /* End of CO Profile Test */
++
++#ifndef NO_ACT
++ /* Constellation Display Buffer Allocate */
++ ptidsl->constDisplay.PmemStartWtAddr = (unsigned int) shim_osAllocateDmaMemory(DSP_CONSTELLATION_BUFFER_SIZE);
++ if(ptidsl->constDisplay.PmemStartWtAddr == NULL)
++ {
++ dprintf(1, "memory allocate error\n");
++ return DSLHAL_ERROR_OVERLAY_MALLOC;
++ }
++ shim_osZeroMemory((void*)ptidsl->constDisplay.PmemStartWtAddr,DSP_CONSTELLATION_BUFFER_SIZE);
++ ptidsl->constDisplay.overlayHostAddr = virtual2Physical((unsigned int)ptidsl->constDisplay.PmemStartWtAddr);
++ dprintf(4,"Allocated Addr: 0x%x \t Xlated Addr: 0x%x \n",ptidsl->constDisplay.PmemStartWtAddr, ptidsl->constDisplay.overlayHostAddr);
++ ptidsl->constDisplay.OverlayXferCount = DSP_CONSTELLATION_BUFFER_SIZE;
++
++ /* Communicate the Allocated Buffer for DSP load Constellation Data */
++
++ /* Change the Endianness of the profileList pointer */
++ dspOamSharedInterface.consDispVar_p = (DEV_HOST_consBufDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.consDispVar_p);
++ /* Access the profileList Structure */
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.consDispVar_p,&constDisp, sizeof(DEV_HOST_consBufDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ dprintf(2,"Constellation Old Addr:%x New: %x \n",constDisp.consDispStartAddr,ptidsl->constDisplay.overlayHostAddr);
++ constDisp.consDispStartAddr = (unsigned int)dslhal_support_byteSwap32(ptidsl->constDisplay.overlayHostAddr);
++ constDisp.consDispCurrentAddr = constDisp.consDispStartAddr;
++ constDisp.consDispBufLen = (unsigned int)dslhal_support_byteSwap32(DSP_CONSTELLATION_BUFFER_SIZE);
++ rc = dslhal_support_blockWrite(&constDisp,(PVOID)dspOamSharedInterface.consDispVar_p,sizeof(DEV_HOST_consBufDef_t));
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_WRITE;
++#endif
++ dprintf(5,"dslhal_support_hostDspCodeDownload() completed.\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++
++} /* end of dslhal_support_hostDspCodeDownload() */
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_readDelineationState()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* download DSP image from host memory to dsp memory
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++
++unsigned int dslhal_support_readDelineationState(tidsl_t * ptidsl)
++{
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ DEV_HOST_atmStats_t atmStats;
++ DEV_HOST_dsAtmStats_t dsAtmStats0;
++ unsigned int rc=0, delinState=0;
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterface_t *) ptidsl->pmainAddr;
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ dspOamSharedInterface.atmStats_p = (DEV_HOST_atmStats_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.atmStats_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.atmStats_p,&atmStats, sizeof(DEV_HOST_atmStats_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ atmStats.ds0_p = (DEV_HOST_dsAtmStats_t *) dslhal_support_byteSwap32((unsigned int)atmStats.ds0_p);
++
++ rc = dslhal_support_blockRead((PVOID)atmStats.ds0_p,&dsAtmStats0, (sizeof(DEV_HOST_dsAtmStats_t)));
++
++ if (rc)
++ return rc;
++ delinState = dslhal_support_byteSwap32(dsAtmStats0.delineationState);
++ if(delinState == TC_SYNC)
++ ptidsl->lConnected = 1;
++ else
++ ptidsl->lConnected = 0;
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_processModemStateBitField()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* download DSP image from host memory to dsp memory
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++
++unsigned int dslhal_support_processModemStateBitField(tidsl_t * ptidsl)
++{
++ int rc, offset[2]={2,0};
++ int modemStateBitFields[NUMBER_OF_BITFIELDS],changedField=0;
++ rc = dslhal_api_dspInterfaceRead(ptidsl,(unsigned int)ptidsl->pmainAddr,2,(unsigned int *)&offset,
++ (unsigned char *)&modemStateBitFields,NUMBER_OF_BITFIELDS*sizeof(int));
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_READ;
++ for(rc=0;rc<NUMBER_OF_BITFIELDS;rc++)
++ dprintf(4,"Bit Field %d: 0x%x \n",rc+1,dslhal_support_byteSwap32((unsigned int)modemStateBitFields[rc]));
++
++ for(rc=NUMBER_OF_BITFIELDS;rc>0;rc--)
++ {
++ if(ptidsl->modemStateBitField[rc-1]!=modemStateBitFields[rc-1])
++ {
++ changedField = rc;
++ break;
++ }
++ }
++ if(changedField)
++ {
++ for(rc=0;rc<32;rc++)
++ {
++ if(modemStateBitFields[changedField-1] & dslhal_support_byteSwap32((BITFIELD_SCAN >> rc)))
++ break;
++ }
++ dprintf(5,"Changed Field : %d Changed Bit : %d \n",changedField,(31-rc));
++ ptidsl->rState = ((changedField*100) + (31-rc));
++ dprintf(5,"Modem State : %d \n",ptidsl->rState);
++ shim_osMoveMemory((void *)ptidsl->modemStateBitField,(void *)modemStateBitFields, 4*NUMBER_OF_BITFIELDS);
++ }
++
++ switch(changedField)
++ {
++ case 1: if((ptidsl->rState >= ATU_RIDLE) && (ptidsl->AppData.bState < RSTATE_IDLE))
++ ptidsl->AppData.bState = RSTATE_IDLE;
++ if((ptidsl->rState >= GDMT_NSFLR) && (ptidsl->AppData.bState < RSTATE_INIT))
++ ptidsl->AppData.bState = RSTATE_INIT;
++ if((ptidsl->rState >= GDMT_ACKX) && (ptidsl->AppData.bState < RSTATE_HS))
++ ptidsl->AppData.bState = RSTATE_HS;
++ break;
++
++ case 2: if((ptidsl->rState >= T1413_NSFLR) && (ptidsl->AppData.bState < RSTATE_INIT))
++ ptidsl->AppData.bState = RSTATE_INIT;
++ if((ptidsl->rState >= T1413_ACKX) && (ptidsl->AppData.bState < RSTATE_HS))
++ ptidsl->AppData.bState = RSTATE_HS;
++ if((ptidsl->rState == ATU_RSHOWTIME) && (ptidsl->AppData.bState < RSTATE_SHOWTIME))
++ ptidsl->AppData.bState = RSTATE_SHOWTIME;
++ break;
++
++ case 3: if((ptidsl->rState >= ADSL2_COMB3) && (ptidsl->AppData.bState < RSTATE_INIT))
++ ptidsl->AppData.bState = RSTATE_INIT;
++ if((ptidsl->rState >= ADSL2_RPARAMS) && (ptidsl->AppData.bState < RSTATE_HS))
++ ptidsl->AppData.bState = RSTATE_HS;
++ break;
++
++ case 4: break;
++ default: break;
++ }
++
++ ptidsl->stateTransition = modemStateBitFields[1];
++ switch(ptidsl->AppData.bState)
++ {
++ case RSTATE_IDLE: ptidsl->AppData.idleTick=shim_osClockTick();
++ ptidsl->AppData.initTick=0;
++ ptidsl->AppData.showtimeTick=0;
++ break;
++ case RSTATE_HS: if(!ptidsl->AppData.initTick)
++ {
++ ptidsl->AppData.initTick=shim_osClockTick();
++ }
++ ptidsl->AppData.showtimeTick=0;
++ break;
++ case RSTATE_SHOWTIME: if(!ptidsl->AppData.showtimeTick)
++ ptidsl->AppData.showtimeTick=shim_osClockTick();
++ break;
++ default: break;
++ }
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_setInterruptMask()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++
++unsigned int dslhal_support_setInterruptMask(tidsl_t * ptidsl,unsigned int inputMask)
++{
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ DEV_HOST_hostInterruptMask_t interruptMask;
++ unsigned int rc=0;
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterface_t *) ptidsl->pmainAddr;
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ dspOamSharedInterface.hostInterruptMask_p =(DEV_HOST_hostInterruptMask_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.hostInterruptMask_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.hostInterruptMask_p,
++ &interruptMask, sizeof(DEV_HOST_hostInterruptMask_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ if(inputMask & MASK_MAILBOX_INTERRUPTS)
++ {
++ dprintf(7,"Mailbox Interrupts Masked \n");
++ dprintf(7,"interruptMask.maskBitField1 = %d \n",dslhal_support_byteSwap32(interruptMask.maskBitField1));
++ interruptMask.maskBitField1 |= dslhal_support_byteSwap32(MASK_MAILBOX_INTERRUPTS);
++ dprintf(7,"interruptMask.maskBitField1 = %d \n",dslhal_support_byteSwap32(interruptMask.maskBitField1));
++ }
++ if(inputMask & MASK_BITFIELD_INTERRUPTS)
++ {
++ dprintf(7,"Bit field Interrupts Masked \n");
++ dprintf(7,"interruptMask.maskBitField1 = %d \n",dslhal_support_byteSwap32(interruptMask.maskBitField1));
++ interruptMask.maskBitField1 |= dslhal_support_byteSwap32(MASK_BITFIELD_INTERRUPTS);
++ dprintf(7,"interruptMask.maskBitField1 = %d \n",dslhal_support_byteSwap32(interruptMask.maskBitField1));
++ }
++ if(inputMask & MASK_HEARTBEAT_INTERRUPTS)
++ {
++ dprintf(7,"Bit field Interrupts Masked \n");
++ dprintf(7,"interruptMask.maskBitField1 = %d \n",dslhal_support_byteSwap32(interruptMask.maskBitField1));
++ interruptMask.maskBitField1 |= dslhal_support_byteSwap32(MASK_HEARTBEAT_INTERRUPTS);
++ dprintf(7,"interruptMask.maskBitField1 = %d \n",dslhal_support_byteSwap32(interruptMask.maskBitField1));
++ }
++ dslhal_support_blockWrite(&interruptMask,
++ dspOamSharedInterface.hostInterruptMask_p, sizeof(DEV_HOST_hostInterruptMask_t));
++ dprintf(5,"dslhal_support_setInterruptMask() completed.\n");
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_parseInterruptSource()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Parses the Interrupt Source Bit Field
++*
++* Return: interrupt Code if successful
++* negative error code if failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++
++unsigned int dslhal_support_parseInterruptSource(tidsl_t * ptidsl)
++{
++ DEV_HOST_dspOamSharedInterface_t *pdspOamSharedInterface, dspOamSharedInterface;
++ DEV_HOST_hostInterruptSource_t interruptSource;
++ unsigned int rc=0,intrCode=0;
++ pdspOamSharedInterface = (DEV_HOST_dspOamSharedInterface_t *) ptidsl->pmainAddr;
++ rc = dslhal_support_blockRead(pdspOamSharedInterface, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return (0-DSLHAL_ERROR_BLOCK_READ);
++ }
++ dspOamSharedInterface.hostInterruptSource_p =(DEV_HOST_hostInterruptSource_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.hostInterruptSource_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.hostInterruptSource_p,
++ &interruptSource, sizeof(DEV_HOST_hostInterruptSource_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return (0-DSLHAL_ERROR_BLOCK_READ);
++ }
++ if(interruptSource.sourceBitField1 & dslhal_support_byteSwap32(MASK_MAILBOX_INTERRUPTS))
++ {
++ dprintf(7,"Mailbox Interrupts Acknowledge \n");
++ intrCode |= 0x00000011;
++ }
++ if(interruptSource.sourceBitField1 & dslhal_support_byteSwap32(MASK_BITFIELD_INTERRUPTS))
++ {
++ dprintf(7,"Bit field Interrupt Acknowledge \n");
++ intrCode |= 0x00001002;
++ }
++ if(interruptSource.sourceBitField1 & dslhal_support_byteSwap32(MASK_HEARTBEAT_INTERRUPTS))
++ {
++ dprintf(7,"HeartBeat Interrupt Acknowledge \n");
++ intrCode |= 0x00100004;
++ }
++
++ interruptSource.sourceBitField1 &=0x0;
++ rc=dslhal_support_blockWrite(&interruptSource,
++ dspOamSharedInterface.hostInterruptSource_p, sizeof(DEV_HOST_hostInterruptSource_t));
++ if(rc)
++ return (0-DSLHAL_ERROR_BLOCK_WRITE);
++ dprintf(5,"dslhal_support_parseInterruptSource() completed.\n");
++ return intrCode;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_byteSwap16()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* input 16 bit short, byte swap from little endian to big endian or vise versa
++*
++********************************************************************************************/
++
++unsigned short dslhal_support_byteSwap16(unsigned short in16Bits)
++{
++ unsigned short out16Bits;
++
++#ifdef EB
++ unsigned char *pchar;
++ unsigned char tmp;
++#endif
++
++ out16Bits = in16Bits;
++
++#ifdef EB
++ pchar = (unsigned char *)(&out16Bits);
++
++ tmp = *pchar;
++ *pchar = *(pchar + 1);
++ *(pchar + 1) = tmp;
++#endif
++
++ return out16Bits;
++
++} /* end of dslhal_support_byteSwap16() */
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_byteSwap32()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* input 32 bit int, byte swap from little endian to big endian or vise versa
++*
++********************************************************************************************/
++
++unsigned int dslhal_support_byteSwap32(unsigned int in32Bits)
++{
++ int out32Bits;
++
++#ifdef EB
++ unsigned char tmp;
++ unsigned char *pchar;
++#endif
++
++ out32Bits = in32Bits;
++
++#ifdef EB
++ pchar = (unsigned char *)(&out32Bits);
++
++ tmp = *pchar;
++ *pchar = *(pchar + 3);
++ *(pchar + 3) = tmp;
++
++ tmp = *(pchar + 1);
++ *(pchar + 1) = *(pchar + 2);
++ *(pchar + 2) = tmp;
++#endif
++
++ return out32Bits;
++
++} /* end of dslhal_support_byteSwap32() */
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_computeCrc32()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Computes the CRC-32 for the input data
++*
++* Return: 32 bit CRC of the input data
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_computeCrc32(unsigned char *data, int len)
++{
++ unsigned int result;
++ int i,j;
++ unsigned char octet;
++
++ if ((len < 4) || (data==NULL))
++ return(0xdeaddead);
++ result = *data++ << 24;
++ result |= *data++ << 16;
++ result |= *data++ << 8;
++ result |= *data++;
++ result = ~ result;
++
++ len -=4;
++
++ for (i=0; i<len; i++)
++ {
++ octet = *(data++);
++ for (j=0; j<8; j++)
++ {
++ if (result & 0x80000000)
++ {
++ result = (result << 1) ^ CRC32_QUOTIENT ^ (octet >> 7);
++ }
++ else
++ {
++ result = (result << 1) ^ (octet >> 7);
++ }
++ octet <<= 1;
++ }
++ }
++ return ~result; /* The complement of the remainder */
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_checkOverlayPage()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Computes the CRC-32 for the input data and compares it with reference
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_checkOverlayPage(tidsl_t *ptidsl, unsigned int tag)
++{
++ unsigned int computedCrc;
++ if((unsigned char *)ptidsl->olayDpPage[tag].PmemStartWtAddr == NULL)
++ {
++ dprintf(5,"Null Address for Page: %d\n",tag);
++ return DSLHAL_ERROR_OVERLAY_MALLOC;
++ }
++ computedCrc = dslhal_support_computeCrc32((unsigned char *)ptidsl->olayDpPage[tag].PmemStartWtAddr, ptidsl->olayDpPage[tag].OverlayXferCount);
++ dprintf(6,"\n Pre-Computed CRC32 = 0x%x \t Current CRC32 = 0x%x \n",ptidsl->olayDpPage[tag].olayPageCrc32,computedCrc);
++ if(computedCrc != ptidsl->olayDpPage[tag].olayPageCrc32)
++ return DSLHAL_ERROR_OVERLAY_CORRUPTED;
++ else
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_clearTrainingInfo()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Computes the CRC-32 for the input data and compares it with reference
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++
++int dslhal_support_clearTrainingInfo(tidsl_t *ptidsl)
++{
++ int i;
++
++ for(i=0; i<NUM_PAGES; i++)
++ {
++ if(ptidsl->olayDpPage[i].PmemStartWtAddr !=NULL)
++ {
++ shim_osFreeDmaMemory((void *) ptidsl->olayDpPage[i].PmemStartWtAddr,
++ ptidsl->olayDpPage[i].OverlayXferCount);
++ ptidsl->olayDpPage[i].PmemStartWtAddr =NULL;
++ }
++ }
++ if(ptidsl->coProfiles.PmemStartWtAddr != NULL)
++ {
++ shim_osFreeDmaMemory((void *)ptidsl->coProfiles.PmemStartWtAddr, ptidsl->coProfiles.OverlayXferCount);
++ ptidsl->coProfiles.PmemStartWtAddr = NULL;
++ }
++ return 0;
++}
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_reloadTrainingInfo()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Reload overlay pages from flash or memory
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++
++int dslhal_support_reloadTrainingInfo(tidsl_t * ptidsl)
++{
++
++ int rc = 0, i;
++ unsigned int olayXfer,olayStore;
++ unsigned int *olayStart;
++
++ unsigned int crc32;
++ DEV_HOST_dspOamSharedInterface_t dspOamSharedInterface;
++ DEV_HOST_olayDpDef_t olayDpParms;
++ DEV_HOST_olayDpPageDef_t olayDpPageDef[NUM_PAGES];
++ DEV_HOST_profileBase_t profileList;
++
++ unsigned int secLength, secOffset, secPage;
++
++ /* co profile */
++ secLength = ptidsl->coProfiles.OverlayXferCount;
++ secOffset = ptidsl->coProfiles.SecOffset;
++ ptidsl->coProfiles.PmemStartWtAddr = (unsigned int) shim_osAllocateDmaMemory(secLength);
++ if(ptidsl->coProfiles.PmemStartWtAddr == NULL)
++ {
++ dprintf(1, "memory allocate error\n");
++ return DSLHAL_ERROR_OVERLAY_MALLOC;
++ }
++ /* holdSecPhyAddr = virtual2Physical((unsigned int)holdSecVirtAddr); */
++ ptidsl->coProfiles.overlayHostAddr = virtual2Physical((unsigned int)ptidsl->coProfiles.PmemStartWtAddr);
++ dprintf(4,"Allocated Addr: 0x%x \t Xlated Addr: 0x%x \n",ptidsl->coProfiles.PmemStartWtAddr, ptidsl->coProfiles.overlayHostAddr);
++ ptidsl->coProfiles.overlayHostAddr = (unsigned int)dslhal_support_byteSwap32(ptidsl->coProfiles.overlayHostAddr);
++
++ rc = shim_read_overlay_page((void *)ptidsl->coProfiles.PmemStartWtAddr, secOffset, secLength);
++ if(rc != secLength)
++ {
++ dprintf(1, "shim_read_overlay_page failed\n");
++ return DSLHAL_ERROR_OVERLAY_MALLOC;
++ }
++
++ /*shim_osMoveMemory((char *)ptidsl->coProfiles.PmemStartWtAddr, (char *)iptr, secLength);*/
++ /* RamP Image ByteSwap test */
++ olayStart = (unsigned int *)ptidsl->coProfiles.PmemStartWtAddr;
++
++ for(olayXfer=0;olayXfer< secLength/4;olayXfer++)
++ {
++ olayStore = *(unsigned int *)olayStart;
++ olayStore = (unsigned int)dslhal_support_byteSwap32(olayStore);
++ *(unsigned int*)olayStart = olayStore;
++ dprintf(5, "Addr:0x%x \t Content: 0x%x \n",olayStart,olayStore);
++ olayStart++;
++ olayStore=0;
++ }
++ shim_osWriteBackCache((void *)ptidsl->coProfiles.PmemStartWtAddr, secLength);
++
++
++ for (secPage=1;secPage<NUM_PAGES; secPage++)
++ {
++
++ dprintf(6,"OVERLAY PAGE #%d\n",secPage);
++
++ secLength = ptidsl->olayDpPage[secPage].OverlayXferCount;
++
++ dprintf(4,"Section[%d] Length: %d \n",secPage, secLength);
++
++ secOffset = ptidsl->olayDpPage[secPage].SecOffset;
++ ptidsl->olayDpPage[secPage].PmemStartWtAddr = (unsigned int) shim_osAllocateDmaMemory(secLength);
++ if(ptidsl->olayDpPage[secPage].PmemStartWtAddr == NULL)
++ {
++ dprintf(1, "overlay page allocate error\n");
++ return DSLHAL_ERROR_OVERLAY_MALLOC;
++ }
++
++ rc = shim_read_overlay_page((void *)ptidsl->olayDpPage[secPage].PmemStartWtAddr,secOffset, secLength);
++ if(rc != secLength)
++ {
++ dprintf(1, "overlay page read error\n");
++ return DSLHAL_ERROR_OVERLAY_MALLOC;
++ }
++
++ /* ptidsl->olayDpPage[secPage].overlayHostAddr = ((unsigned int)(ptidsl->olayDpPage[secPage].PmemStartWtAddr)&~0xe0000000); */
++ ptidsl->olayDpPage[secPage].overlayHostAddr = virtual2Physical((unsigned int)ptidsl->olayDpPage[secPage].PmemStartWtAddr);
++ dprintf(6,"Allocated Addr: 0x%x \t Xlated Addr: 0x%x \n",ptidsl->olayDpPage[secPage].PmemStartWtAddr,ptidsl->olayDpPage[secPage].overlayHostAddr);
++
++ ptidsl->olayDpPage[secPage].overlayHostAddr = (unsigned int)dslhal_support_byteSwap32(ptidsl->olayDpPage[secPage].overlayHostAddr);
++ /*ptidsl->olayDpPage[secPage].OverlayXferCount = secLength;
++ ptidsl->olayDpPage[secPage].BinAddr = secAddr;
++ shim_osMoveMemory((char *)ptidsl->olayDpPage[secPage].PmemStartWtAddr, (char *)iptr, secLength);
++ */
++ olayStart = (unsigned int *)ptidsl->olayDpPage[secPage].PmemStartWtAddr;
++
++ for(olayXfer=0;olayXfer< secLength/4;olayXfer++)
++ {
++ olayStore = *(unsigned int *)olayStart;
++ olayStore = (unsigned int)dslhal_support_byteSwap32(olayStore);
++ *(unsigned int*)olayStart = olayStore;
++ dprintf(5, "Addr:0x%x \t Content: 0x%x \n",olayStart,olayStore);
++ olayStart++;
++ olayStore=0;
++ }
++ /* RamP Image ByteSwap test */
++ /* compute the CRC of each overlay page and Store the Checksum in a local global variable */
++ /* This Value of CRC is to be compared with the header where all the CRC bytes are lumped together */
++ crc32 = dslhal_support_computeCrc32((char *)ptidsl->olayDpPage[secPage].PmemStartWtAddr, ptidsl->olayDpPage[secPage].OverlayXferCount);
++ if(crc32 != ptidsl->olayDpPage[secPage].olayPageCrc32)
++ return DSLHAL_ERROR_OVERLAY_MALLOC;
++
++ shim_osWriteBackCache((void *)ptidsl->olayDpPage[secPage].PmemStartWtAddr, secLength);
++ }
++
++
++ dprintf(5,"ptidsl->hostIf.mainAddr=0x%X\n", (unsigned int)ptidsl->pmainAddr);
++
++ /* get the pointer to DSP-OAM Shared Interface */
++ rc = dslhal_support_blockRead(ptidsl->pmainAddr, &dspOamSharedInterface,
++ sizeof(DEV_HOST_dspOamSharedInterface_t));
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ /* Communicate the Allocated Memory Address to DSP to choose CO Profiles */
++
++ /* Change the Endianness of the profileList pointer */
++ dspOamSharedInterface.profileList_p = (DEV_HOST_profileBase_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.profileList_p);
++ /* Access the profileList Structure */
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.profileList_p,&profileList, sizeof(DEV_HOST_profileBase_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++ dprintf(2,"Old Addr:%x New: %x \n",profileList.hostProfileBase_p,ptidsl->coProfiles.overlayHostAddr);
++ profileList.hostProfileBase_p = (DEV_HOST_coData_t *)ptidsl->coProfiles.overlayHostAddr;
++ rc = dslhal_support_blockWrite(&profileList,(PVOID)dspOamSharedInterface.profileList_p,sizeof(DEV_HOST_profileBase_t));
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_WRITE;
++
++ /* Communicate the Allocated Memory Address to DSP to do overlays */
++
++ /* Change the Endianness of the olayDpDef pointer */
++ dspOamSharedInterface.olayDpParms_p = (DEV_HOST_olayDpDef_t *)dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.olayDpParms_p);
++ /* Access the olayDpDef Structure */
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.olayDpParms_p,&olayDpParms, sizeof(DEV_HOST_olayDpDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++
++ for(i=1;i<NUM_PAGES;i++)
++ {
++ /* Change the endianness of the olayDpPageDef Pointer */
++ olayDpParms.olayDpPage_p[i] = (DEV_HOST_olayDpPageDef_t *) dslhal_support_byteSwap32((unsigned int)olayDpParms.olayDpPage_p[i]);
++ /* Access the olayDpPageDef Structure */
++ rc = dslhal_support_blockRead((PVOID)olayDpParms.olayDpPage_p[i],&olayDpPageDef[i],sizeof(DEV_HOST_olayDpPageDef_t));
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_READ;
++ olayDpPageDef[i].overlayHostAddr = ptidsl->olayDpPage[i].overlayHostAddr;
++ rc = dslhal_support_blockWrite(&olayDpPageDef[i],(PVOID)olayDpParms.olayDpPage_p[i],sizeof(DEV_HOST_olayDpPageDef_t));
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_WRITE;
++ }
++
++ ptidsl->bOverlayPageLoaded = 1;
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++ /* end of dslhal_support_reloadTrainingInfo() */
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_restoreTrainingInfo()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Computes the CRC-32 for the input data and compares it with reference
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++
++
++int dslhal_support_restoreTrainingInfo(tidsl_t *ptidsl)
++{
++ int rc;
++
++ rc=1;
++ while(rc != 0)
++ {
++ dslhal_support_clearTrainingInfo(ptidsl);
++ //shim_osCriticalEnter();
++ rc = dslhal_support_reloadTrainingInfo(ptidsl);
++ //shim_osCriticalExit();
++ shim_osClockWait(6400);
++ }
++ return 0;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_advancedIdleProcessing()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Calls Advanced Idle State Processing Functions
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_advancedIdleProcessing(tidsl_t *ptidsl)
++{
++ int rc=0;
++ ptidsl->AppData.bState = RSTATE_IDLE;
++#ifndef NO_ACT
++ rc += dslhal_advcfg_resetBitSwapMessageLog(ptidsl,0);
++ rc += dslhal_advcfg_resetBitSwapMessageLog(ptidsl,1);
++ rc += dslhal_advcfg_resetTrainStateHistory(ptidsl);
++ rc += dslhal_advcfg_getReasonForDrop(ptidsl);
++#endif
++ if(rc)
++ return DSLHAL_ERROR_CONFIG_API_FAILURE;
++ else
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_aocBitSwapProcessing()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Calls Advanced Idle State Processing Functions
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_aocBitSwapProcessing(tidsl_t *ptidsl,unsigned int usDs)
++{
++ int rc=0;
++#ifndef NO_ACT
++ int i;
++ int differentCmd_f;
++ unsigned int dsSwapInx;
++
++ static UINT8 lastAturBitSwapCommands[6] = {0, 0, 0, 0, 0, 0};
++ static UINT8 lastAturBitSwapBinNum[6] = {0, 0, 0, 0, 0, 0};
++
++ if (usDs == 0)
++ {
++ dprintf(4," DSP_XMITBITSWAP\n");
++ rc += dslhal_advcfg_getAocBitswapBuffer(ptidsl,0);
++ ptidsl->usBitSwapInx++;
++ if (ptidsl->usBitSwapInx > 29)
++ ptidsl->usBitSwapInx=0;
++ }
++
++ if (usDs == 1)
++ {
++ dprintf(4," DSP_RCVBITSWAP\n");
++ rc += dslhal_advcfg_getAocBitswapBuffer(ptidsl,1);
++ differentCmd_f = FALSE;
++ dsSwapInx = ptidsl->dsBitSwapInx;
++ if (! rc)
++ {
++ for (i = 0; i < 6; i++)
++ {
++ if (lastAturBitSwapCommands[i] != ptidsl->dsBitSwap[dsSwapInx].bitSwapCommand[i])
++ {
++ differentCmd_f = TRUE;
++ break;
++ }
++ }
++ if (! differentCmd_f)
++ {
++ for (i = 0; i < 6; i++)
++ {
++ if (lastAturBitSwapBinNum[i] != ptidsl->dsBitSwap[dsSwapInx].bitSwapBinNum[i])
++ {
++ differentCmd_f = TRUE;
++ break;
++ }
++ }
++ }
++ //CPE data pump seems to occasionally send us the same bit swap twice in a row with different sframe counter.
++ //Since these are never counted twice by the debug output of AC5, we should not count them twice either.
++ //So, we ignore the sframe_counter in determining whether the most recent bitswap is a duplicate.
++ if (differentCmd_f)
++ {
++ shim_osMoveMemory((void *)lastAturBitSwapCommands, (void *)ptidsl->dsBitSwap[dsSwapInx].bitSwapCommand, 6);
++ shim_osMoveMemory((void *)lastAturBitSwapBinNum, (void *)ptidsl->dsBitSwap[dsSwapInx].bitSwapBinNum, 6);
++ ptidsl->dsBitSwapInx++;
++ if (ptidsl->dsBitSwapInx > 29)
++ ptidsl->dsBitSwapInx = 0;
++ }
++ }
++ }
++#endif
++ if(rc)
++ return DSLHAL_ERROR_CONFIG_API_FAILURE;
++ else
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_gatherEocMessages()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Calls Advanced EOC Buffering functions
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_gatherEocMessages(tidsl_t *ptidsl,int usDs, int msgPart1, int msgPart2)
++{
++ int rc=0;
++#ifndef NO_ACT
++ rc = dslhal_advcfg_logEocMessages(ptidsl,usDs, msgPart1, msgPart2);
++#endif
++ if(rc)
++ return DSLHAL_ERROR_CONFIG_API_FAILURE;
++ else
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_gatherSnrPerBin()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Calls Advanced Snr per bin buffering Functions
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_gatherSnrPerBin(tidsl_t *ptidsl,unsigned int snrParam)
++{
++ int rc=0;
++#ifndef NO_ACT
++ rc = dslhal_advcfg_getSnrPerBin(ptidsl,snrParam);
++#endif
++ if(rc)
++ return DSLHAL_ERROR_CONFIG_API_FAILURE;
++ else
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_processTrainingState()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Calls Advanced Training State Processing Functions
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_processTrainingState(tidsl_t *ptidsl)
++{
++ int rc=0;
++#ifndef NO_ACT
++
++ if(ptidsl->trainStateInx<120)
++ {
++ rc = dslhal_advcfg_getTrainingState(ptidsl,(void *)&ptidsl->trainHistory[ptidsl->trainStateInx++]);
++ if(ptidsl->trainHistory[(ptidsl->trainStateInx-1)].subStateIndex ==
++ ptidsl->trainHistory[(ptidsl->trainStateInx-2)].subStateIndex)
++ ptidsl->trainStateInx--;
++ }
++ else
++ ptidsl->trainStateInx = 0;
++#endif
++ if(rc)
++ return DSLHAL_ERROR_CONFIG_API_FAILURE;
++ else
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_gatherAdsl2Messages()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Gathers ADSL2 Training Messages
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_gatherAdsl2Messages(tidsl_t *ptidsl,int tag, int param1, int param2)
++{
++ int rc=0;
++ unsigned int adsl2MsgLoc;
++ switch(tag)
++ {
++ case CMSGFMT_INDEX:
++ dprintf(5,"C-Msg-FMT rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, CMSGFMT_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2TrainingMessages.cMsgFmt,CMSGFMT_SIZE);
++ break;
++ case RMSGFMT_INDEX:
++ case RMSGFMT2_INDEX:
++ dprintf(5,"R-Msg-FMT rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, RMSGFMT_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2TrainingMessages.rMsgFmt,RMSGFMT_SIZE);
++ break;
++ case CMSGPCB_INDEX:
++ dprintf(5,"C-Msg-PCB rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, CMSGPCB_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2TrainingMessages.cMsgPcb,CMSGPCB_SIZE);
++ ptidsl->adsl2TrainingMessages.cMsgPcbLen = CMSGPCB_SIZE;
++ break;
++ case CMSGPCB2_INDEX:
++ dprintf(5,"C-Msg-PCB2 rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, CMSGPCB2_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2TrainingMessages.cMsgPcb,CMSGPCB2_SIZE);
++ ptidsl->adsl2TrainingMessages.cMsgPcbLen = CMSGPCB2_SIZE;
++#ifndef NO_ACT
++ rc += dslhal_advcfg_setBlackOutBits(ptidsl);
++#endif
++ break;
++ case CMSGPCB2L_INDEX:
++ dprintf(5,"C-Msg-PCB2L rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, CMSGPCB2L_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2TrainingMessages.cMsgPcb,CMSGPCB2L_SIZE);
++ ptidsl->adsl2TrainingMessages.cMsgPcbLen = CMSGPCB2L_SIZE;
++ break;
++ case RMSGPCB_INDEX:
++ case RMSGPCB2L_INDEX:
++ dprintf(5,"R-Msg-PCB rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, RMSGPCB_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2TrainingMessages.rMsgPcb,RMSGPCB_SIZE);
++ ptidsl->adsl2TrainingMessages.rMsgPcbLen = RMSGPCB_SIZE;
++ break;
++
++ case CMSG1ADSL2_INDEX:
++ dprintf(5,"C-Msg1 rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, CMSG1ADSL2_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2TrainingMessages.cMsg1,CMSG1ADSL2_SIZE);
++ ptidsl->adsl2TrainingMessages.cMsg1Len = CMSG1ADSL2_SIZE;
++ break;
++ case CMSG2ADSL2_INDEX:
++ dprintf(5,"C-Msg2 rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, CMSG2ADSL2_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2TrainingMessages.cMsg2,CMSG2ADSL2_SIZE);
++ ptidsl->adsl2TrainingMessages.cMsg2Len = CMSG2ADSL2_SIZE;
++ break;
++ case RMSG1ADSL2_INDEX:
++ dprintf(5,"R-Msg1 rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, RMSG1ADSL2_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2TrainingMessages.rMsg1,RMSG1ADSL2_SIZE);
++ ptidsl->adsl2TrainingMessages.rMsg1Len = RMSG1ADSL2_SIZE;
++ break;
++ case RMSG2ADSL2_INDEX:
++ dprintf(5,"R-Msg2 rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, RMSG2ADSL2_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2TrainingMessages.rMsg2,RMSG2ADSL2_SIZE);
++ ptidsl->adsl2TrainingMessages.rMsg2Len = RMSG2ADSL2_SIZE;
++ break;
++ case CPARAMS_INDEX:
++ dprintf(5,"C-Params rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, CPARAMS_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2TrainingMessages.cParams,CPARAMS_SIZE);
++ ptidsl->adsl2TrainingMessages.cParamsLen = CPARAMS_SIZE;
++ break;
++ case RPARAMS_INDEX:
++ dprintf(5,"R-Params rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, RPARAMS_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2TrainingMessages.rParams,RPARAMS_SIZE);
++ ptidsl->adsl2TrainingMessages.rParamsLen = RPARAMS_SIZE;
++ break;
++ case RMSG1LD_INDEX:
++ dprintf(5,"R-Msg1 LD rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, RMSG1LD_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2DiagnosticMessages.rMsg1Ld,RMSG1LD_SIZE);
++ ptidsl->adsl2DiagnosticMessages.rMsg1LdLen = RMSG1LD_SIZE;
++ break;
++ case RMSG2LD_INDEX:
++ dprintf(5,"R-Msg2 LD rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, RMSG2LD_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2DiagnosticMessages.rMsg2Ld,RMSGxLD_SIZE);
++ ptidsl->adsl2DiagnosticMessages.rMsgxLdLen = RMSGxLD_SIZE;
++ break;
++ case RMSG3LD_INDEX:
++ dprintf(5,"R-Msg3 LD rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, RMSG3LD_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2DiagnosticMessages.rMsg3Ld,RMSGxLD_SIZE);
++ ptidsl->adsl2DiagnosticMessages.rMsgxLdLen = RMSGxLD_SIZE;
++ break;
++ case RMSG4LD_INDEX:
++ dprintf(5,"R-Msg4 LD rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, RMSG4LD_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2DiagnosticMessages.rMsg4Ld,RMSGxLD_SIZE);
++ ptidsl->adsl2DiagnosticMessages.rMsgxLdLen = RMSGxLD_SIZE;
++ break;
++ case RMSG5LD_INDEX:
++ dprintf(5,"R-Msg5 LD rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, RMSG5LD_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2DiagnosticMessages.rMsg5Ld,RMSGxLD_SIZE);
++ ptidsl->adsl2DiagnosticMessages.rMsgxLdLen = RMSGxLD_SIZE;
++ break;
++ case RMSG6LD_INDEX:
++ dprintf(5,"R-Msg6 LD rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, RMSG6LD_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2DiagnosticMessages.rMsg6Ld,RMSGxLD_SIZE);
++ ptidsl->adsl2DiagnosticMessages.rMsgxLdLen = RMSGxLD_SIZE;
++ break;
++ case RMSG7LD_INDEX:
++ dprintf(5,"R-Msg7 LD rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, RMSG7LD_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2DiagnosticMessages.rMsg7Ld,RMSGxLD_SIZE);
++ ptidsl->adsl2DiagnosticMessages.rMsgxLdLen = RMSGxLD_SIZE;
++ break;
++ case RMSG8LD_INDEX:
++ dprintf(5,"R-Msg8 LD rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, RMSG8LD_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2DiagnosticMessages.rMsg8Ld,RMSGxLD_SIZE);
++ ptidsl->adsl2DiagnosticMessages.rMsgxLdLen = RMSGxLD_SIZE;
++ break;
++ case RMSG9LD_INDEX:
++ dprintf(5,"R-Msg9 LD rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, RMSG9LD_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2DiagnosticMessages.rMsg9Ld,RMSGxLD_SIZE);
++ ptidsl->adsl2DiagnosticMessages.rMsgxLdLen = RMSGxLD_SIZE;
++ break;
++ case CMSG1LD_INDEX:
++ dprintf(5,"C-Msg1 LD rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, CMSG1LD_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2DiagnosticMessages.cMsg1Ld,CMSG1LD_SIZE);
++ ptidsl->adsl2DiagnosticMessages.cMsg1LdLen = CMSG1LD_SIZE;
++ break;
++ case CMSG2LD_INDEX:
++ dprintf(5,"C-Msg2 LD rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, CMSG2LD_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2DiagnosticMessages.cMsg2Ld,CMSG2LD_SIZE);
++ ptidsl->adsl2DiagnosticMessages.cMsg2LdLen = CMSG2LD_SIZE;
++ break;
++ case CMSG3LD_INDEX:
++ dprintf(5,"C-Msg3 LD rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, CMSG3LD_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2DiagnosticMessages.cMsg3Ld,CMSG3LD_SIZE);
++ ptidsl->adsl2DiagnosticMessages.cMsg3LdLen = CMSG3LD_SIZE;
++ break;
++ case CMSG4LD_INDEX:
++ dprintf(5,"C-Msg4 LD rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, CMSG4LD_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2DiagnosticMessages.cMsg4Ld,CMSG4LD_SIZE);
++ ptidsl->adsl2DiagnosticMessages.cMsg4LdLen = CMSG4LD_SIZE;
++ break;
++ case CMSG5LD_INDEX:
++ dprintf(5,"C-Msg5 LD rec'd\n");
++ adsl2MsgLoc = dslhal_support_getAdsl2MessageLocation
++ (ptidsl, CMSG5LD_INDEX);
++ rc += dslhal_support_blockRead((PVOID)adsl2MsgLoc,
++ ptidsl->adsl2DiagnosticMessages.cMsg5Ld,CMSG5LD_SIZE);
++ ptidsl->adsl2DiagnosticMessages.cMsg5LdLen = CMSG5LD_SIZE;
++ break;
++ default:
++ dprintf(5,"Unknown ADSL2 Message rec'd\n");
++ break;
++ }
++ if(rc)
++ return DSLHAL_ERROR_CONFIG_API_FAILURE;
++ else
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_getAdsl2MessageLocation()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Gets the address to the ADSL2 Message being looked up
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_getAdsl2MessageLocation(tidsl_t *ptidsl,int msgOffset)
++{
++ int rc=0;
++
++ DEV_HOST_dspOamSharedInterface_t *pSharedInterface, sharedInterface;
++ DEV_HOST_dspWrNegoParaDef_t dspNegoPara;
++ int adsl2MsgString, adsl2MsgAddr;
++
++ pSharedInterface = (DEV_HOST_dspOamSharedInterface_t *) ptidsl->pmainAddr;
++ rc += dslhal_support_blockRead(pSharedInterface, &sharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ sharedInterface.dspWriteNegoParams_p = (DEV_HOST_dspWrNegoParaDef_t *) dslhal_support_adsl2ByteSwap32((unsigned int)sharedInterface.dspWriteNegoParams_p);
++ rc += dslhal_support_blockRead((PVOID)sharedInterface.dspWriteNegoParams_p,&dspNegoPara, sizeof(DEV_HOST_dspWrNegoParaDef_t));
++
++ if (rc)
++ {
++ dprintf(1,"dslhal_support_blockRead failed\n");
++ return DSLHAL_ERROR_BLOCK_READ;
++ }
++
++ adsl2MsgString = dslhal_support_adsl2ByteSwap32((unsigned int)dspNegoPara.adsl2DeltMsgs_p);
++ dprintf(5,"ADSL2 Message String Address: 0x%x\n",adsl2MsgString);
++ rc += dslhal_support_blockRead((PVOID)(adsl2MsgString +
++ ((sizeof(unsigned char *)*msgOffset))),
++ &adsl2MsgAddr, sizeof(int));
++ adsl2MsgAddr = dslhal_support_adsl2ByteSwap32((unsigned int)adsl2MsgAddr);
++ dprintf(5," Message Address: 0x%x\n",adsl2MsgAddr);
++
++ if(rc)
++ return DSLHAL_ERROR_BLOCK_READ;
++ else
++ return adsl2MsgAddr;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_getCMsgsRa()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Calls Advanced Training Message functions
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_getCMsgsRa(tidsl_t *ptidsl,void *cMsg)
++{
++ int rc=0;
++ DEV_HOST_raMsgsDef_t raMsgParms;
++ DEV_HOST_dspOamSharedInterface_t dspOamSharedInterface;
++ rc += dslhal_support_blockRead(ptidsl->pmainAddr, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++
++ dspOamSharedInterface.raMsgs_p = (DEV_HOST_raMsgsDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.raMsgs_p);
++
++ rc += dslhal_support_blockRead((PVOID)dspOamSharedInterface.raMsgs_p,
++ &raMsgParms, sizeof(DEV_HOST_raMsgsDef_t));
++ shim_osMoveMemory((void *)cMsg,(void *)raMsgParms.cMsgsRaString,6);
++
++ if(rc)
++ return DSLHAL_ERROR_CONFIG_API_FAILURE;
++ else
++ return DSLHAL_ERROR_NO_ERRORS;
++}
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_gatherRateMessages()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Gathers Rate Training Messages
++* Input
++* tidsl_t *ptidsl : Pointer to application structure
++*
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_gatherRateMessages(tidsl_t * ptidsl)
++{
++ int rc;
++ DEV_HOST_dspWrNegoParaDef_t negoParms;
++ DEV_HOST_dspOamSharedInterface_t dspOamSharedInterface;
++
++ dprintf(1, "dslhal_support_gatherRateMessages\n");
++
++ rc += dslhal_support_blockRead(ptidsl->pmainAddr, &dspOamSharedInterface,sizeof(DEV_HOST_dspOamSharedInterface_t));
++ dspOamSharedInterface.dspWriteNegoParams_p = (DEV_HOST_dspWrNegoParaDef_t *) dslhal_support_byteSwap32((unsigned int)dspOamSharedInterface.dspWriteNegoParams_p);
++
++ rc = dslhal_support_blockRead((PVOID)dspOamSharedInterface.dspWriteNegoParams_p, &negoParms, sizeof(DEV_HOST_dspWrNegoParaDef_t));
++ if (rc)
++ return DSLHAL_ERROR_BLOCK_READ;
++ else
++ {
++ shim_osMoveMemory((void *)ptidsl->AppData.bCRates1, (void *)negoParms.cRates1, 120);
++ shim_osMoveMemory((void *)ptidsl->AppData.bRRates1, (void *)negoParms.rRates1, 44);
++ }
++return DSLHAL_ERROR_NO_ERRORS;
++}
++
++static unsigned int dslhal_support_adsl2ByteSwap32(unsigned int in32Bits)
++{
++ int out32Bits=0;
++
++#ifdef EB
++ out32Bits = (in32Bits << 24);
++ out32Bits |=((in32Bits & 0x0000ff00) << 8);
++ out32Bits |=((in32Bits & 0xff000000) >> 24);
++ out32Bits |=((in32Bits & 0x00ff0000) >> 8);
++#else
++ out32Bits = in32Bits;
++#endif
++
++ return out32Bits;
++
++} /* end of dslhal_support_byteSwap32() */
+diff -urN linux.old/drivers/atm/sangam_atm/dsl_hal_support.h linux.dev/drivers/atm/sangam_atm/dsl_hal_support.h
+--- linux.old/drivers/atm/sangam_atm/dsl_hal_support.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/dsl_hal_support.h 2005-08-23 04:46:50.101843088 +0200
+@@ -0,0 +1,718 @@
++#ifndef DSL_HAL_SUPPORT_H__
++#define DSL_HAL_SUPPORT_H__ 1
++
++/*******************************************************************************
++* FILE PURPOSE: DSL Driver API functions for Sangam
++*
++********************************************************************************
++* FILE NAME: dsl_hal_functiondefines.c
++*
++* DESCRIPTION:
++* Contains basic DSL HAL API declarations for Sangam
++*
++*
++* (C) Copyright 2001-02, Texas Instruments, Inc.
++* History
++* Date Version Notes
++* 06Feb03 0.00.00 RamP Created
++* 21Mar03 0.00.01 RamP Removed byteswap functions
++* 21Mar03 0.00.02 RamP Added extern osFreeVMemory declaration
++* 10Apr03 0.00.03 RamP Changed declaration for loadFWImage &
++* loadDebugFWImage to remove ptidsl param
++* 12Apr03 0.00.04 RamP Added function to set Interrupt Bit
++* Masks for bitfield & Mailboxes
++* 14Apr03 0.00.05 RamP Added modem state bit field processing
++* 15Apr03 0.00.06 RamP Added function osAllocateVMemory
++* 21Apr03 0.01.00 RamP Added function osAllocateDmaMemory
++* Added function osFreeDmaMemory
++* (Alpha) Added macro virtual2Physical,
++* 22Apr03 0.01.01 RamP Moved acknowledgeInterrupt to api.h
++* 24Apr03 0.01.02 RamP Added checkOvelayPage function
++* 29May03 0.01.03 RamP Added critical enter/exit function decl
++* 06Jun03 0.01.04 RamP Added Interrupt source parsing function
++* 06Oct03 0.01.05 RamP Added function abstraction switches
++* 12Oct03 0.01.06 RamP Added ADSL2 Message function prototypes
++* 14Nov03 0.03.07 RamP Added function to gather Rate Messages
++*******************************************************************************/
++
++#include "dsl_hal_api.h"
++
++#define virtual2Physical(a) (((int)a)&~0xe0000000)
++/* External Function Prototype Declarations */
++
++extern unsigned int shim_osGetCpuFrequency(void);
++extern void shim_osClockWait(int val);
++extern unsigned int shim_osClockTick(void);
++
++extern int shim_osStringCmp(const char *s1, const char *s2);
++
++extern void dprintf( int uDbgLevel, char * szFmt, ...);
++
++extern int shim_osLoadFWImage(unsigned char *firmwareImage);
++extern int shim_osLoadDebugFWImage(unsigned char *debugFirmwareImage);
++extern unsigned int shim_read_overlay_page(void *ptr, unsigned int secOffset, unsigned int secLength);
++extern void shim_osMoveMemory(char *dst, char *src, unsigned int numBytes);
++extern void shim_osZeroMemory(char *dst, unsigned int numBytes);
++
++extern void *shim_osAllocateMemory(unsigned int size);
++extern void *shim_osAllocateVMemory(unsigned int size);
++extern void *shim_osAllocateDmaMemory(unsigned int size);
++
++extern void shim_osFreeMemory(void *ptr, unsigned int size);
++extern void shim_osFreeVMemory(void *ptr, unsigned int size);
++extern void shim_osFreeDmaMemory(void *ptr, unsigned int size);
++
++extern void shim_osWriteBackCache(void *pMem, unsigned int size);
++extern void shim_osCriticalEnter(void);
++extern void shim_osCriticalExit(void);
++
++
++/*******************************************************************************************
++* FUNCTION NAME: dslhal_support_writeHostMailbox
++*
++********************************************************************************************
++* DESCRIPTION: Send a message to a mailbox
++*
++* ARGUMENTS: int cmd command to write
++* int tag tag (currently unused)
++* int p1 parameter 1 (currently unused)
++* int p2 parameter 2 (currently unused)
++*
++* RETURNS: 0 if successful
++* NZ otherwise
++*
++*******************************************************************************************/
++
++int dslhal_support_writeHostMailbox
++(tidsl_t *ptidsl,
++ int cmd,
++ int tag,
++ int p1,
++ int p2);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_readDspMailbox
++*
++*********************************************************************************************
++* DESCRIPTION: Reads a message from the mailbox
++*
++* ARGUMENTS: int *pcmd Pointer to command read
++*
++* RETURNS: 0 if successful
++* 1 if no mail
++* NZ otherwise
++*
++*****************************************************************************************/
++
++int dslhal_support_readDspMailbox
++(tidsl_t *ptidsl,
++ int *pcmd,
++ int *ptag,
++ int *pprm1,
++ int *pprm2);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_readTextMailbox
++*
++*********************************************************************************************
++* DESCRIPTION: Reads a message from the mailbox
++*
++* ARGUMENTS: int *pcmd Pointer to command read
++*
++* RETURNS: 0 if successful
++* 1 if no mail
++* NZ otherwise
++*
++*****************************************************************************************/
++
++int dslhal_support_readTextMailbox
++(tidsl_t *ptidsl,
++ int *pmsg1,
++ int *pmsg2);
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_support_blockRead
++*
++*********************************************************************************************
++* DESCRIPTION: This rouin simulates DSP memory read as done in ax5 pci nic card
++*
++* INPUT: void *addr, memory address to be read
++* void *buffer, dat buffer to be filled with from memmory
++* size_t count, number of bytes to be written
++*
++* RETURN: 0 --succeeded
++* 1 --Failed
++*
++*****************************************************************************************/
++
++int dslhal_support_blockRead
++(void *addr,
++ void *buffer,
++ size_t count);
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_support_blockWrite
++*
++*******************************************************************************************
++* DESCRIPTION: This rouin simulates DSP memory write as done in ax5 pci nic card
++*
++* INPUT: void *buffer, data need to written
++* void *adde, memory address to be written
++* size_t count, number of bytes to be written
++*
++* RETURN: 0 --succeeded
++* 1 --Failed
++*
++*****************************************************************************************/
++
++int dslhal_support_blockWrite
++(void *buffer,
++ void *addr,
++ size_t count);
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_support_hostDspAddressTranslate
++*
++*******************************************************************************************
++* DESCRIPTION: This function moves the address window to translate physical address
++*
++* INPUT: unsigned int addr : address that requires translation
++*
++* RETURN: Translated address or error condition
++*
++*
++*****************************************************************************************/
++
++unsigned int dslhal_support_hostDspAddressTranslate
++( unsigned int addr
++);
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_support_unresetDslSubsystem
++*
++*******************************************************************************************
++* DESCRIPTION: This function unreset Dsl Subsystem
++*
++* INPUT: None
++*
++* RETURN: 0 if Pass; 1 if Fail
++*
++*****************************************************************************************/
++int dslhal_support_unresetDslSubsystem
++(void
++);
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_support_unresetDsp()
++*
++*******************************************************************************************
++* DESCRIPTION: This fuction takes ax5 daugter board out of reset.
++*
++* INPUT: None
++*
++* RETURN: 0 --successful.
++* 1 --failed
++*
++*****************************************************************************************/
++int dslhal_support_unresetDsp
++(void
++);
++
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_support_resetDslSubsystem
++*
++*******************************************************************************************
++* DESCRIPTION: This function unreset Dsl Subsystem
++*
++* INPUT: None
++*
++* RETURN: 0 if Pass; 1 if Fail
++*
++*****************************************************************************************/
++int dslhal_support_resetDslSubsystem
++(void
++);
++
++/******************************************************************************************
++* FUNCTION NAME: dslhal_support_resetDsp()
++*
++*******************************************************************************************
++* DESCRIPTION: This fuction takes ax5 daugter board out of reset.
++*
++* INPUT: None
++*
++* RETURN: 0 --successful.
++* 1 --failed
++*
++*****************************************************************************************/
++int dslhal_support_resetDsp
++(void
++);
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_hostDspCodeDownload()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* download DSP image from host memory to dsp memory
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++
++int dslhal_support_hostDspCodeDownload
++(tidsl_t * ptidsl
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_diags_digi_assignMemTestSpace()
++*
++*********************************************************************************************
++* DESCRIPTION: Assigns Memory Space in SDRAM for External Memory Test
++* Input: tidsl_t *ptidsl
++*
++* Return: 0 success
++* 1 failed
++*
++********************************************************************************************/
++
++unsigned int dslhal_diags_digi_assignMemTestSpace
++(tidsl_t *ptidsl
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_diags_digi_readMemTestResult()
++*
++*********************************************************************************************
++* DESCRIPTION: Reads Results of External Memory Test
++* Input: tidsl_t *ptidsl
++*
++* Return: 0 success
++* 1 failed
++*
++********************************************************************************************/
++
++unsigned int dslhal_diags_digi_readMemTestResult
++(tidsl_t *ptidsl,
++unsigned int testResult
++);
++
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_diags_codeDownload()
++*
++*********************************************************************************************
++* DESCRIPTION: Brings DSLSS out of Reset, Downloads Diag Firmware,
++* brings DSP out of Reset
++* Input: tidsl_t *ptidsl
++*
++* Return: 0 success
++* 1 failed
++*
++********************************************************************************************/
++
++unsigned int dslhal_diags_codeDownload
++(tidsl_t *ptidsl,
++unsigned char* missingTones
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_diags_anlg_setPgaParams()
++*
++*********************************************************************************************
++* DESCRIPTION: This function instructs the Transciever to transmit the Reverb with missing
++* tones and Medley's with missing tones. These signals are defined in ITU
++* G.992.1 ADSL Standards.
++*
++* Input: Test selects between the Reverb or Medley tests. 0 - Reverb, 1 - Medley
++* Tones selects the .
++* Return: NULL
++*
++********************************************************************************************/
++
++unsigned int dslhal_diags_anlg_setPgaParams
++(tidsl_t *ptidsl,
++int agcFlag,
++short pga1,
++short pga2,
++short pga3,
++short aeq
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_diags_anlg_getRxNoisePower()
++*
++*********************************************************************************************
++* DESCRIPTION: This function instructs the Transciever to transmit the Reverb with missing
++* tones and Medley's with missing tones. These signals are defined in ITU
++* G.992.1 ADSL Standards.
++*
++* Input: Test selects between the Reverb or Medley tests. 0 - Reverb, 1 - Medley
++* Tones selects the .
++* Return: NULL
++*
++********************************************************************************************/
++
++unsigned int dslhal_diags_anlg_getRxNoisePower
++(tidsl_t *ptidsl
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_diags_anlg_setMissingTones()
++*
++*********************************************************************************************
++* DESCRIPTION: This function instructs the Transciever to transmit the Reverb with missing
++* tones and Medley's with missing tones. These signals are defined in ITU
++* G.992.1 ADSL Standards.
++*
++* Input: Test selects between the Reverb or Medley tests. 0 - Reverb, 1 - Medley
++* Tones selects the .
++* Return: NULL
++*
++********************************************************************************************/
++
++unsigned int dslhal_diags_anlg_setMissingTones
++(tidsl_t *ptidsl,
++unsigned char* missingTones
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_readDelineationState()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* download DSP image from host memory to dsp memory
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_readDelineationState
++(tidsl_t *ptidsl
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_processModemStateBitField()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* download DSP image from host memory to dsp memory
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_processModemStateBitField
++(tidsl_t *ptidsl
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_setInterruptMask()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++
++unsigned int dslhal_support_setInterruptMask
++(tidsl_t * ptidsl,
++unsigned int inputMask
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_computeCrc32()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Computes the CRC-32 for the input data
++*
++* Return: 32 bit CRC of the input data
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_computeCrc32
++(unsigned char *data,
++int len
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_checkOverlayPage()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Computes the CRC-32 for the input data and compares it with reference
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_checkOverlayPage
++(tidsl_t *ptidsl,
++unsigned int tag
++);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_restoreTrainingInfo()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Computes the CRC-32 for the input data and compares it with reference
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++
++int dslhal_support_restoreTrainingInfo(tidsl_t * ptidsl);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_reloadTrainingInfo()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Computes the CRC-32 for the input data and compares it with reference
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++
++int dslhal_support_reloadTrainingInfo(tidsl_t * ptidsl);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_clearTrainingInfo()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Computes the CRC-32 for the input data and compares it with reference
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++
++int dslhal_support_clearTrainingInfo(tidsl_t * ptidsl);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_parseInterruptSource()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Sets the host interrupt bit masks
++*
++* Return: 0 success
++* 1 failed
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++
++unsigned int dslhal_support_parseInterruptSource(tidsl_t * ptidsl);
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_advancedIdleProcessing()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Calls Advanced Idle State Processing Functions
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_advancedIdleProcessing(tidsl_t *ptidsl);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_aocBitSwapProcessing()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Calls Advanced Bitswap buffer Processing Functions
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_aocBitSwapProcessing(tidsl_t *ptidsl,unsigned int usDs);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_gatherEocMessages()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Calls Advanced EOC Buffering functions
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_gatherEocMessages(tidsl_t *ptidsl,int usDs, int msgPart1, int msgPart2);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_gatherSnrPerBin()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Calls Advanced Snr per bin buffering Functions
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_gatherSnrPerBin(tidsl_t *ptidsl,unsigned int snrParm);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_processTrainingState()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Calls Advanced Training State Processing Functions
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_processTrainingState(tidsl_t *ptidsl);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_gatherAdsl2Messages()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Calls Advanced EOC Buffering functions
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_gatherAdsl2Messages(tidsl_t *ptidsl,int msgTag, int param1, int param2);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_getAdsl2MsgLocation()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Gets the address to the ADSL2 Message being looked up
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_getAdsl2MessageLocation(tidsl_t *ptidsl,int msgOffset);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_getCMsgsRa()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Calls Advanced Training Message functions
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_getCMsgsRa(tidsl_t *ptidsl,void *cMsg);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_gatherRateMessages()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* Gathers Advanced Training Messages
++*
++* Return: Error Condition (if any)
++*
++*
++* NOTE:
++* DSP image is based on LITTLE endian
++*
++********************************************************************************************/
++unsigned int dslhal_support_gatherRateMessages(tidsl_t *ptidsl);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_byteSwap16()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* byteswap a short
++*
++* INPUT:
++* Return: NULL
++*
++********************************************************************************************/
++
++unsigned short dslhal_support_byteSwap16(unsigned short in16Bits);
++
++/********************************************************************************************
++* FUNCTION NAME: dslhal_support_byteSwap32()
++*
++*********************************************************************************************
++* DESCRIPTION:
++* byteswap a word
++*
++* INPUT:
++* Return: NULL
++*
++********************************************************************************************/
++
++unsigned int dslhal_support_byteSwap32(unsigned int in32Bits);
++
++#endif /* Pairs #ifndef DSL_HAL_FUNCTIONDEFINES_H__ */
+diff -urN linux.old/drivers/atm/sangam_atm/dsl_hal_version.h linux.dev/drivers/atm/sangam_atm/dsl_hal_version.h
+--- linux.old/drivers/atm/sangam_atm/dsl_hal_version.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/dsl_hal_version.h 2005-08-23 04:46:50.102842936 +0200
+@@ -0,0 +1,94 @@
++#ifndef __SYSSW_VERSION_H__
++#define __SYSSW_VERSION_H__ 1
++
++/*******************************************************************************
++* FILE PURPOSE: DSL Driver API functions for Sangam
++*
++********************************************************************************
++* FILE NAME: dsl_hal_basicapi.c
++*
++* DESCRIPTION:
++* Contains basic DSL HAL APIs for Sangam
++*
++* (C) Copyright 2003-04, Texas Instruments, Inc.
++* History
++* Date Version Notes
++* 14May03 0.00.00 RamP Original Version Created
++* 14May03 0.00.01 RamP Initial Rev numbers inserted
++* 14May03 0.00.02 RamP Bumped version numbers for Dsl Hal
++* & dhalapp for alpha plus
++* 19May03 0.00.03 MCB Bumped dslhal version number
++* because of dependant changes
++* wrt. linux-nsp atm drivers.
++* 22May03 0.00.04 RamP Bumped dslhal & dhalapp buildnum
++* for inner/outer pair & DGASP code
++* 06Jun03 0.00.05 RamP Bumped up buildnum for LED, STM,
++* interrupt processing, statistics
++* and other pre-beta features
++* 09Jun03 0.00.06 JEB Fixed error in DHALAPP bugfix/buildnum
++* 09Jun03 0.00.07 RamP Bumped up buildnum for incremental
++* changes to apis, statistics, memory
++* fixes, parameter configurations
++* 11Jun03 0.00.08 RamP Bumped up buildnum for Co profile
++* free memory fix
++* 12Jun03 0.00.09 JEB Bumped version numbers for AR7 1.00 Beta
++* 02Jul03 0.00.10 ZT Bumped HAL version for overlay page
++* 18Jul03 0.00.11 RamP Bumped HAL version for analog diags
++* 22Jul03 0.00.12 JEB Bumped DHALAPP buildnum for analog diags
++* 31Jul03 0.00.13 RamP Bumped HAL version for engr. drop
++* 04Aug03 0.00.14 JEB Bumped HAL version buildnum for CHECKPOINT65 changes
++* Bumped LINUX version buildnum for CHECKPOINT65 changes
++* 06Aug03 0.00.15 MCB Bumped all version numbers in prep for AR7 1.0 R2 release for POTS.
++* 13Aug03 0.00.16 MCB Set rev id's for D3/R1.1 (ADSL2).
++* 21Aug03 0.00.17 JEB Bumped up build numbers for merge of code additions from D1
++* 26Sep03 0.00.18 JEB Set rev id's for another D3/R1 (ADSL2).
++* 14Oct03 0.00.19 JEB Bumped Linux minor number and reset bugfix number for release.
++* Bumped build numbers on DSLHAL and DHALAPP for this checkpoint.
++* 14Oct03 0.00.20 JEB Bumped build numbers on DSLHAL and DHALAPP for CHECKPOINT15.
++* 21Oct03 0.00.21 JEB Bumped build number on DSLHAL for CHECKPOINT16.
++* 22Oct03 0.00.22 MCB Bumped all version numbers in support of D3R1 release.
++* 27Oct03 0.00.23 JEB Bumped build numbers on DSLHAL and DHALAPP for CHECKPOINT19.
++* Updated version for DSLAGENT to be 02.01.00.01 for ACT 2.1 R0.
++* 30Oct03 0.00.24 JEB Bumped bugfix number on LINUXATM Version for next release.
++* Bumped build numbers on DSLHAL and DHALAPP
++* 31Oct03 0.00.25 MCB Bumped all version numbers in support of D3R2 release.
++* 14Nov03 0.00.26 JEB Bumped build numbers on DSLHAL and DHALAPP
++* Changed version for DSLAGENT to be 02.00.01.01 for an ACT 2.0 R0
++* 20Nov03 0.00.27 JEB Bumped build number on DSLHAL.
++* Changed version for DSLAGENT to be 02.00.02.00 for the next ACT 2.0 R2
++* 21Nov03 0.00.28 MCB Bumped all version numbers in support of D3R2 release.
++* 21Nov03 0.00.29 JEB Bumped build numbers on DSLHAL and DHALAPP for D3-R0 drop on 11/21.
++* 16Dec03 0.00.30 JEB Bumped build numbers on DSLHAL and DHALAPP for CHECKPOINT31.
++* 21Dec03 0.00.31 MCB Bumped all version numbers in support of D3R2 release.
++* 05Jan04 0.00.32 JEB Bumped build numbers on DSLHAL and Linux ATM for CHECKPOINT 34.
++* 15Jan04 0.00.33 JEB Bumped build numbers on DSLHAL and Linux ATM for CHECKPOINT 36.
++* 26Jan04 0.00.34 JEB Changed Linux ATM version number to be 04.02.03.00.
++* 27Jan04 0.00.35 MCB Bumped all version numbers in support of D3R2 release.
++*******************************************************************************/
++
++/* Dsl Hal API Version Numbers */
++#define DSLHAL_VERSION_MAJOR 03
++#define DSLHAL_VERSION_MINOR 00
++#define DSLHAL_VERSION_BUGFIX 06
++#define DSLHAL_VERSION_BUILDNUM 00
++#define DSLHAL_VERSION_TIMESTAMP 00
++
++/* dhalapp Adam2 Application Version Numbers */
++#define DHALAPP_VERSION_MAJOR 03
++#define DHALAPP_VERSION_MINOR 00
++#define DHALAPP_VERSION_BUGFIX 05
++#define DHALAPP_VERSION_BUILDNUM 00
++
++/* Linux ATM Driver Version Numbers */
++#define LINUXATM_VERSION_MAJOR 04
++#define LINUXATM_VERSION_MINOR 02
++#define LINUXATM_VERSION_BUGFIX 04
++#define LINUXATM_VERSION_BUILDNUM 00
++
++/* DSL Agent Version Numbers */
++#define DSLAGENT_VERSION_MAJOR 02
++#define DSLAGENT_VERSION_MINOR 00
++#define DSLAGENT_VERSION_BUGFIX 02
++#define DSLAGENT_VERSION_BUILDNUM 00
++
++#endif /* pairs with #ifndef __SYSSW_VERSION_H__ */
+diff -urN linux.old/drivers/atm/sangam_atm/ec_errors_cpaal5.h linux.dev/drivers/atm/sangam_atm/ec_errors_cpaal5.h
+--- linux.old/drivers/atm/sangam_atm/ec_errors_cpaal5.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/ec_errors_cpaal5.h 2005-08-23 04:46:50.102842936 +0200
+@@ -0,0 +1,118 @@
++/***************************************************************************
++ Copyright(c) 2001, Texas Instruments Incorporated. All Rights Reserved.
++
++ FILE: ec_errors.h
++
++ DESCRIPTION:
++ This file contains definitions and function declarations for
++ error code support.
++
++ HISTORY:
++ 14Dec00 MJH Added masking to EC_CLASS etc macros
++ 17Sep02 GSG Added HAL support (new class&devices)
++ 03Oct02 GSG Removed C++ style comments
++***************************************************************************/
++#ifndef _INC_EC_ERRORS
++#define _INC_EC_ERRORS
++
++/*
++ 31 - CRITICAL
++ 30-28 - CLASS (ie. DIAG, KERNEL, FLASH, etc)
++ 27-24 - INSTANCE (ie. 1, 2, 3, etc )
++ 23-16 - DEVICE (ie. EMAC, IIC, etc)
++ 15-08 - FUNCTION (ie. RX, TX, INIT, etc)
++ 07-00 - ERROR CODE (ie. NO_BASE, FILE_NOT_FOUND, etc )
++*/
++
++/*---------------------------------------------------------------------------
++ Useful defines for accessing fields within error code
++---------------------------------------------------------------------------*/
++#define CRITICAL_SHIFT 31
++#define CLASS_SHIFT 28
++#define INST_SHIFT 24
++#define DEVICE_SHIFT 16
++#define FUNCTION_SHIFT 8
++#define ERROR_CODE_SHIFT 0
++
++#define CRITICAL_MASK 1
++#define CLASS_MASK 0x07
++#define DEVICE_MASK 0xFF
++#define INST_MASK 0x0F
++#define FUNCTION_MASK 0xFF
++#define ERROR_CODE_MASK 0xFF
++
++#define EC_CLASS(val) ((val&CLASS_MASK) << CLASS_SHIFT)
++#define EC_DEVICE(val) ((val&DEVICE_MASK) << DEVICE_SHIFT)
++#define EC_INST(val) ((val&INST_MASK) << INST_SHIFT)
++#define EC_FUNC(val) ((val&FUNCTION_MASK) << FUNCTION_SHIFT)
++#define EC_ERR(val) ((val&ERROR_CODE_MASK) << ERROR_CODE_SHIFT)
++
++/*---------------------------------------------------------------------------
++ Operation classes
++---------------------------------------------------------------------------*/
++#define EC_HAL EC_CLASS(0)
++#define EC_DIAG EC_CLASS(8)
++
++/*---------------------------------------------------------------------------
++ Device types
++---------------------------------------------------------------------------*/
++#define EC_DEV_EMAC EC_DEVICE(1)
++#define EC_DEV_IIC EC_DEVICE(2)
++#define EC_DEV_RESET EC_DEVICE(3)
++#define EC_DEV_ATMSAR EC_DEVICE(4)
++#define EC_DEV_MEM EC_DEVICE(5)
++#define EC_DEV_DES EC_DEVICE(6)
++#define EC_DEV_DMA EC_DEVICE(7)
++#define EC_DEV_DSP EC_DEVICE(8)
++#define EC_DEV_TMR EC_DEVICE(9)
++#define EC_DEV_WDT EC_DEVICE(10)
++#define EC_DEV_DCL EC_DEVICE(11)
++#define EC_DEV_BBIF EC_DEVICE(12)
++#define EC_DEV_PCI EC_DEVICE(13)
++#define EC_DEV_XBUS EC_DEVICE(14)
++#define EC_DEV_DSLIF EC_DEVICE(15)
++#define EC_DEV_USB EC_DEVICE(16)
++#define EC_DEV_CLKC EC_DEVICE(17)
++#define EC_DEV_RAPTOR EC_DEVICE(18)
++#define EC_DEV_DSPC EC_DEVICE(19)
++#define EC_DEV_INTC EC_DEVICE(20)
++#define EC_DEV_GPIO EC_DEVICE(21)
++#define EC_DEV_BIST EC_DEVICE(22)
++#define EC_DEV_HDLC EC_DEVICE(23)
++#define EC_DEV_UART EC_DEVICE(24)
++#define EC_DEV_VOIC EC_DEVICE(25)
++/* 9.17.02 (new HAL modules) */
++#define EC_DEV_CPSAR EC_DEVICE(0x1A)
++#define EC_DEV_AAL5 EC_DEVICE(0x1B)
++#define EC_DEV_AAL2 EC_DEVICE(0x1C)
++#define EC_DEV_CPMAC EC_DEVICE(0x1D)
++#define EC_DEV_VDMA EC_DEVICE(0x1E)
++#define EC_DEV_VLYNQ EC_DEVICE(0x1F)
++#define EC_DEV_CPPI EC_DEVICE(0x20)
++#define EC_DEV_CPMDIO EC_DEVICE(0x21)
++
++/*---------------------------------------------------------------------------
++ Function types
++---------------------------------------------------------------------------*/
++#define EC_FUNC_READ_CONF EC_FUNC(1)
++#define EC_FUNC_INIT EC_FUNC(2)
++
++/*---------------------------------------------------------------------------
++ Error codes
++---------------------------------------------------------------------------*/
++#define EC_CRITICAL (1<<CRITICAL_SHIFT)
++#define EC_NO_ERRORS 0
++#define EC_VAL_NO_BASE EC_ERR(1)
++#define EC_VAL_NO_RESET_BIT EC_ERR(2)
++#define EC_VAL_NO_RESET EC_ERR(3)
++#define EC_VAL_BAD_BASE EC_ERR(4)
++#define EC_VAL_MALLOCFAILED EC_ERR(5)
++#define EC_VAL_NO_RESETBASE EC_ERR(6)
++#define EC_DEVICE_NOT_FOUND EC_ERR(7)
++
++/*---------------------------------------------------------------------------
++ Function declarations
++---------------------------------------------------------------------------*/
++extern void ec_log_error( unsigned int );
++
++#endif /* _INC_EC_ERRORS */
+diff -urN linux.old/drivers/atm/sangam_atm/ec_errors_cpsar.h linux.dev/drivers/atm/sangam_atm/ec_errors_cpsar.h
+--- linux.old/drivers/atm/sangam_atm/ec_errors_cpsar.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/ec_errors_cpsar.h 2005-08-23 04:46:50.102842936 +0200
+@@ -0,0 +1,118 @@
++/***************************************************************************
++ Copyright(c) 2001, Texas Instruments Incorporated. All Rights Reserved.
++
++ FILE: ec_errors.h
++
++ DESCRIPTION:
++ This file contains definitions and function declarations for
++ error code support.
++
++ HISTORY:
++ 14Dec00 MJH Added masking to EC_CLASS etc macros
++ 17Sep02 GSG Added HAL support (new class&devices)
++ 03Oct02 GSG Removed C++ style comments
++***************************************************************************/
++#ifndef _INC_EC_ERRORS
++#define _INC_EC_ERRORS
++
++/*
++ 31 - CRITICAL
++ 30-28 - CLASS (ie. DIAG, KERNEL, FLASH, etc)
++ 27-24 - INSTANCE (ie. 1, 2, 3, etc )
++ 23-16 - DEVICE (ie. EMAC, IIC, etc)
++ 15-08 - FUNCTION (ie. RX, TX, INIT, etc)
++ 07-00 - ERROR CODE (ie. NO_BASE, FILE_NOT_FOUND, etc )
++*/
++
++/*---------------------------------------------------------------------------
++ Useful defines for accessing fields within error code
++---------------------------------------------------------------------------*/
++#define CRITICAL_SHIFT 31
++#define CLASS_SHIFT 28
++#define INST_SHIFT 24
++#define DEVICE_SHIFT 16
++#define FUNCTION_SHIFT 8
++#define ERROR_CODE_SHIFT 0
++
++#define CRITICAL_MASK 1
++#define CLASS_MASK 0x07
++#define DEVICE_MASK 0xFF
++#define INST_MASK 0x0F
++#define FUNCTION_MASK 0xFF
++#define ERROR_CODE_MASK 0xFF
++
++#define EC_CLASS(val) ((val&CLASS_MASK) << CLASS_SHIFT)
++#define EC_DEVICE(val) ((val&DEVICE_MASK) << DEVICE_SHIFT)
++#define EC_INST(val) ((val&INST_MASK) << INST_SHIFT)
++#define EC_FUNC(val) ((val&FUNCTION_MASK) << FUNCTION_SHIFT)
++#define EC_ERR(val) ((val&ERROR_CODE_MASK) << ERROR_CODE_SHIFT)
++
++/*---------------------------------------------------------------------------
++ Operation classes
++---------------------------------------------------------------------------*/
++#define EC_HAL EC_CLASS(0)
++#define EC_DIAG EC_CLASS(8)
++
++/*---------------------------------------------------------------------------
++ Device types
++---------------------------------------------------------------------------*/
++#define EC_DEV_EMAC EC_DEVICE(1)
++#define EC_DEV_IIC EC_DEVICE(2)
++#define EC_DEV_RESET EC_DEVICE(3)
++#define EC_DEV_ATMSAR EC_DEVICE(4)
++#define EC_DEV_MEM EC_DEVICE(5)
++#define EC_DEV_DES EC_DEVICE(6)
++#define EC_DEV_DMA EC_DEVICE(7)
++#define EC_DEV_DSP EC_DEVICE(8)
++#define EC_DEV_TMR EC_DEVICE(9)
++#define EC_DEV_WDT EC_DEVICE(10)
++#define EC_DEV_DCL EC_DEVICE(11)
++#define EC_DEV_BBIF EC_DEVICE(12)
++#define EC_DEV_PCI EC_DEVICE(13)
++#define EC_DEV_XBUS EC_DEVICE(14)
++#define EC_DEV_DSLIF EC_DEVICE(15)
++#define EC_DEV_USB EC_DEVICE(16)
++#define EC_DEV_CLKC EC_DEVICE(17)
++#define EC_DEV_RAPTOR EC_DEVICE(18)
++#define EC_DEV_DSPC EC_DEVICE(19)
++#define EC_DEV_INTC EC_DEVICE(20)
++#define EC_DEV_GPIO EC_DEVICE(21)
++#define EC_DEV_BIST EC_DEVICE(22)
++#define EC_DEV_HDLC EC_DEVICE(23)
++#define EC_DEV_UART EC_DEVICE(24)
++#define EC_DEV_VOIC EC_DEVICE(25)
++/* 9.17.02 (new HAL modules) */
++#define EC_DEV_CPSAR EC_DEVICE(0x1A)
++#define EC_DEV_AAL5 EC_DEVICE(0x1B)
++#define EC_DEV_AAL2 EC_DEVICE(0x1C)
++#define EC_DEV_CPMAC EC_DEVICE(0x1D)
++#define EC_DEV_VDMA EC_DEVICE(0x1E)
++#define EC_DEV_VLYNQ EC_DEVICE(0x1F)
++#define EC_DEV_CPPI EC_DEVICE(0x20)
++#define EC_DEV_CPMDIO EC_DEVICE(0x21)
++
++/*---------------------------------------------------------------------------
++ Function types
++---------------------------------------------------------------------------*/
++#define EC_FUNC_READ_CONF EC_FUNC(1)
++#define EC_FUNC_INIT EC_FUNC(2)
++
++/*---------------------------------------------------------------------------
++ Error codes
++---------------------------------------------------------------------------*/
++#define EC_CRITICAL (1<<CRITICAL_SHIFT)
++#define EC_NO_ERRORS 0
++#define EC_VAL_NO_BASE EC_ERR(1)
++#define EC_VAL_NO_RESET_BIT EC_ERR(2)
++#define EC_VAL_NO_RESET EC_ERR(3)
++#define EC_VAL_BAD_BASE EC_ERR(4)
++#define EC_VAL_MALLOCFAILED EC_ERR(5)
++#define EC_VAL_NO_RESETBASE EC_ERR(6)
++#define EC_DEVICE_NOT_FOUND EC_ERR(7)
++
++/*---------------------------------------------------------------------------
++ Function declarations
++---------------------------------------------------------------------------*/
++extern void ec_log_error( unsigned int );
++
++#endif /* _INC_EC_ERRORS */
+diff -urN linux.old/drivers/atm/sangam_atm/env_def_defines.h linux.dev/drivers/atm/sangam_atm/env_def_defines.h
+--- linux.old/drivers/atm/sangam_atm/env_def_defines.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/env_def_defines.h 2005-08-23 04:46:50.103842784 +0200
+@@ -0,0 +1,926 @@
++#ifndef __ENV_DEF_DEFINES_H__
++#define __ENV_DEF_DEFINES_H__ 1
++
++//********************************************************************
++//* DMT-BASE ADSL MODEM PROGRAM
++//* TEXAS INSTRUMENTS PROPRIETARTY INFORMATION
++//* AMATI CONFIDENTIAL PROPRIETARY
++//*
++//* (c) Copyright May 1999, Texas Instruments Incorporated.
++//* All Rights Reserved.
++//*
++//* Property of Texas Instruments Incorporated and Amati Communications Corp.
++//*
++//* Restricted Rights - Use, duplication, or disclosure is subject to
++//* restrictions set forth in TI's and Amati program license agreement and
++//* associated documentation
++//*
++//*********************************************************************
++//*
++//* FILENAME: dpsys_defines.h
++//*
++//* ABSTRACT: This file provides a mechanism for defining standard
++//* preprocessor flag sets for datapump.
++//*
++//* TARGET: Non specific.
++//*
++//* TOOLSET: Non specific.
++//*
++//* ACTIVATION:
++//*
++//* HISTORY: DATE AUTHOR DESCRIPTION
++//* 05/11/99 FLW Created
++//* 01/21/00 FLW derfmake changes
++//* 02/07/00 FLW/M.Seidl added _debug targets
++//* 02/23/00 FLW/M.Barnett merged in from G.lite branch
++//* 03/03/00 FLW/M.Barnett added TRELLIS token
++//* 05/11/00 Barnett Added ap036btp & ap037btp support.
++//* 02/07/00 M.Seidl added HW_TEQ, HW_DEC and DC_BIAS tokens
++//* 02/28/00 Derf/Seidl Mod's in support of suppressing compiler warnings for empty source files
++//* 02/28/00 M. Seidl added SWTC token
++//* 02/28/00 M. Seidl added ap0501tp and its _debug target
++//* 03/03/00 M. Seidl added MODPILOT token, ap0307tp_debug has SWDI and FDD enabled
++//* 03/08/00 Jack Huang Added HWRSDEC token
++//* 03/29/00 Derf/Seidl Mod's in support Soft-TC and derfmake
++//* 04/10/00 Jack Huang Added PCIMASTER token
++//* 04/11/00 Jack Huang Added STBFIX token
++//* 04/24/00 M. Seidl ap0500tp has OLAYDP turned on, ap0500tp_debug has OLAYDP turned off now
++//* 04/28/00 M.Seidl added KAPIL token for ap0501tp targets
++//* 06/02/00 P.Sexton Added OAM_EOC token
++//* 06/06/00 M. Seidl added au0501tp target
++//* 06/12/00 Michael Seidl activated h/w TEQ for KAPIL targets, disabled STBFIX for all targets
++//* 06/14/00 Derf added ap0308tp, alphabetized token lists
++//* 06/16/00 Jack Huang added au0501tp_debug target
++//* 06/22/00 M. Seidl Enabled code overlays through EMIF from external memory. Now there are 3
++//* different code overlay schemes that are differentiated by the following tokens:
++//* OLAYDP_PCI: uses PCI DMA in PCI Master Mode
++//* OLAYDP_HOST: Host downloads overlay code into DMEM upon request from DSP
++//* OLAYDP_EMIF: Host downloads overlay code into ext. mem at boot-time. DSP uses
++//* DMA channel 0 to load code into on-chip PMEM
++//* OLAYDP: turns overlays generally on or off
++//* 07/15/00 B.Srinivasan Cleaned up default tokens and tokens for au0501tp, au0501tp_debug,
++//* ap0501tp and ap0501tp_debug targets as well
++//* 07/19/00 B.Srinivasan Made changes w.r.t cleaning/fixing Rufus Interrupt related code
++//* (changed token TC_INTRPT_RUFUS to INTRPT_RUFUS
++//* 06/14/00 Derf added au0501cp
++//* 08/12/00 Yinong Ding Added DPLL_MODE token.
++//* 08/16/00 F. Mujica Moved DOUBLE_XMT_RATE, RX_HPF, and LEAKY_LMS tokens here.
++//* 09/05/00 M. Seidl Changed ap0501tp back to do overlay through PCI (OLAY_PCI = 1)
++//* 09/11/00 M. Seidl moved USB and OLAYDP_HOST definitions to be CHIPSET specific, not target specific
++//* 09/21/00 U.Dasgupta/ Added a token for separate transmit and receive buffers.
++//* F.Mujica (SEPARATE_TX_RX_BUFFERS).
++//* 10/02/00 U.Dasgupta/ Added DPLL and SEPARATE_TX_RX_BUFFER tokens for au0502 target.
++//* F.Mujica
++//* 10/02/00 M. Castellano Added new tokens for new Host/EMIF DSP code overlay.
++//* OLAYDP_2STEP: Host downloads overlay code into ext. mem upon DSP request. DSP
++//* DMA channel 0 to load code into on-chip PMEM. It is a somewhat hybrid version
++//* of OLAYDP_HOST and OLAYDP_EMIF. The test target is ap0502tp.
++//* 10/25/00 Balaji Added tokens for arv500tp target
++//* 10/31/00 U. Iyer Added TEQ_AVG token and set it one for Ax5
++//* 11/02/00 Barnett Added OAM_EOC=0 in defaults at bottom of file.
++//* 11/21/00 M. Seidl turned OLAYDP and AOC off for ap0307tp to make binary compatible w. whql'ed driver
++//* 11/28/00 Paul Hunt added FASTRETRAIN token for fast retrain specific code
++//* 11/28/00 Paul Hunt added PILOTDATA token to control channel estimation and transmission
++//* of data on the upstream pilot tone for ITU standard code loads
++//* 12/20/00 Jack Huang added EIGHTBITSRAM toekn for the targets that use 8-bit SRAM for
++//* interleaver/deinterleaver
++//* 01/11/01 U.Dasgupta Added mp targets and cleaned up GHS/PILOTDATA variables
++//* 01/23/01 U.Dasgupta Cleaned up code within GLITE tokens
++//* 01/23/00 Barnett Added in full EOC support for AP3/Ax5. Got rid of UTC. No longer needed.
++//* 02/08/01 Barnett Added DDC token.
++//* 03/09/01 Nirmal Warke Added in TOKEN definition for line diagnostics (LINE_DIAG): IMP DEPENDENCIES -
++//* TEQ_AVG must be off when LINE_DIAG is on (since they share a union buffer at the same time)
++//* 03/13/01 M. Seidl Recovered ap0500tp target. Added GHS token as PMEM saving option
++//* 03/14/01 Barnett Added ap0500mb target support. Look-and-feel is similar to ap0500tp.
++//* Added seperate-but-equal def's wrt. ISDN Annex B, Annex C, and PROP.
++//* 03/14/01 J. Bergsagel Added EXTERNBERT token.
++//* 03/15/01 Barnett/Balaji Merged AR5(H) -> 03.00.00 datapump.
++//* 03/16/01 Nirmal Warke Added in TOKEN definition for crosstalk performance mods (CROSSTALK): IMP DEPENDENCIES -
++//* TEQ_AVG must be off and LEAKY_LMS must be on when CROSSTALK is on
++//* 03/21/01 Barnett Added support for ar0500lp, ar0500mp, ar0500dp, arv500lp, arv500mp, and arv500dp.
++//* 03/26/01 M. Seidl enabled 64pt IFFT for ap0500mb (Raptor+AD11, FDM)
++//* 03/28/01 J. Bergsagel Removed EXTERNBERT token (now use host intf. var. instead)
++//* 04/03/01 J. Bergsagel Removed condition of DSPDP_CHIPSET_GEN==5 for default defines
++//* Removed LEAKY_LMS token (assumed always 1)
++//* Removed OLAYDP_HOST token (assumed always 0)
++//* Removed RX_HPF token (assumed always 1)
++//* Removed TRIBRID token (not used any more)
++//* Removed FDD token (assumed always 1)
++//* Removed HW_DEC token (assumed always 1)
++//* Removed HW_TEQ token (assumed always 1)
++//* Removed HWRSDEC token (assumed always 1)
++//* Removed ILEC_AD11_ALCATEL337 token (assumed always 0)
++//* Removed ILEC_AD11_HDSLNOISEFIX token (assumed always 0)
++//* Removed ILEC_AD11_MODULATEPILOT token (assumed always 0)
++//* Removed ILEC_AD11_NEWINTERPOLATE token (assumed always 0)
++//* Removed ILEC_AD11_USTXHPF token (assumed always 0)
++//* Removed SWDI token (assumed always 1)
++//* Removed TD_AGC token (assumed always 1)
++//* Removed DSPDP_LEGACY_TARGET token (assumed always 0)
++//* Removed AD11_20, AD11_20NL and AD11_20_NEWPREC token (always 1)
++//* Removed AI token (assumed always 1)
++//* Removed ATUC token (assumed always 0)
++//* Removed EU token (assumed always 0)
++//* Removed EVM2 token (assumed always 0)
++//* Removed INTRPT_RUFUS token (assumed always 0)
++//* Removed MODPILOT token (assumed always 0)
++//* Removed SL and SL_EVM tokens (assumed always 0)
++//* Removed STBIFX token (assumed always 0)
++//* Removed STD token (assumed always 1)
++//* Removed SWDI_LOOPBACK token (assumed always 0)
++//* Removed TID token (assumed always 0)
++//* Removed TII token (assumed always 1)
++//* Removed TIPCI token (assumed always 1)
++//* Removed UDI token (assumed always 1)
++//* Removed DC_BIAS token (assumed always 1)
++//* 04/05/01 Barnett Added DSPDP_ prefix to tokens that originate
++//* in the public interface.
++//* 05/07/01 Jack Huang Removed DOUBLE_XMT_RATE token.
++//* 05/16/01 Barnett Added back in EXTERNBERT token in support
++//* of saving PMEM.
++//* 06/05/01 Jack Huang Fixed the rules for ar0500mp_debug target
++//* 04/23/01 M. Halleck Merge Astro Wu's DDC enhancements
++//* 06/05/01 M. Capps Changed DSP_DEBUG to ENHANCED_SERIAL_DEBUG
++//* 07/03/01 M. Capps Replaced ESD token with !DDC, added DEV_DEBUG
++//* 06/26/01 J. Bergsagel Removed all the old ap03... stuff
++//* Removed OLAYDP_HOST token (again)
++//* Removed CROSSTALK token (assumed always 1)
++//* Removed TEQ_AVG token (assumed always 0)
++//* Removed DE token (assumed always 1)
++//* Removed PVAT token and au0501cp target
++//* Removed FASTRETRAIN token (assumed always 0)
++//* 07/05/01 J. Bergsagel Changed PCIMASTER token to TC_ATM_PCIMASTER
++//* 07/20/01 Umesh Iyer Added ATMBERT token. ATMBERT is conditional on SWTC definition. if SWTC is 0
++//* ATMBERT should be 0. Else it can be 0/1. Default 0.
++//* 07/23/01 J. Bergsagel Changed name from defines_u.h to dpsys_defines.h
++//* 07/24/01 Barnett Added support for build of $(TARGET)_diag mfgr'ing targets.
++//* 08/02/01 Michael Seidl renamed KAPIL token to !AD1X
++//* 08/02/01 Michael Seidl renamed GHS token to PMEMSAVE_GHS
++//* 08/03/01 S.Yim Added MFGR_DIAG token for afe diagnostic
++//* Added AFEDEV token for afe device driver
++//* Added DSPBIOSII token for dsp bios
++//* 09/21/01 Sameer Enable EXTERNBERT. Disable ATMBERT.
++//* 10/01/01 U.Dasgupta Turned off SMART_MARGIN for ap0500mb because of FECs/CRCs;
++//* 10/09/01 Barnett Added support for ar0500db.
++//* 10/12/01 Barnett Disable EXTERNBERT.
++//* 10/15/01 Barnett Turn off SMART_MARGIN.
++//* 11/07/01 Barnett Def'ed ISDN_DEBUG for all targets to avoid compiler warnings.
++//* Assumed defaul value is zero.
++//* 11/13/01 Barnett Reworked ar0500db_debug to build JTAG-bootable load.
++//* The equivalent production target should only be flash-bootable.
++//* 01/11/02 Yim Added TOKEN JTAG to build JTAG load ar0500db_diag.
++//* 01/23/02 U Iyer Added DEBUG_LOG token. Default value 0
++//* 01/31/02 Barnett Added support for ar0700mp target.
++//* 02/04/02 S.Yim Added TOKEN JTAG to build JTAG load ar0500mp_diag
++//* 02/11/02 U Iyer Added MARGIN_DELTA_RETRAIN token. Default value 1
++//* 05/15/02 Sameer V Enabled EXTERNBERT token for AR5 and AU5 platforms. EXTERNBERT is
++//* not supported on AR5H.
++//* 02/14/02 Barnett Don't ref the SWTC feature token if mfgr'ing diag target.
++//* 02/19/02 Yim Added support to build au0502db_diag target.
++//* 03/08/02 Nirmal Warke Added feature token HYBRID_SWITCH
++//* 03/15/02 U G Jani Turned ON Bitswap support for AU5I (au0502db) targets.
++//* 04/08/02 U G Jani Enabled NLNOISEADJSNR token for AU5I targets.
++//* 06/24/02 Seungmok Oh Added PERTONE_EQ token support for those targets:
++//* (ar0500mp_debug, au0502mp_debug, ar0500mp, au0502mp)
++//* 06/26/02 Mallesh Added DS_PWR_CUTBACK token. Default value 1.
++//* 06/27/02 Mallesh Changed default value of DS_PWR_CUTBACK token to 0.
++//* 06/29/02 U.Dasgupta Token cleanup: Removed ISDN_DEBUG token
++//* 04/29/02 Mannering Remove EIGHTBITSRAM, Combined DOUBLEBUFFER with
++//* BITSWAP, added FPGA token
++//* 05/03/02 Mannering cleanup token changed by the new routine names
++//* 05/06/02 Mannering Add tokens OUTBAND and INBAND for codec commands
++//* If both OUTBAND and INBAND are 0 codec register are
++//* memory mapped.
++//* 05/29/2002 S.Yim Removed AD1X, AFEDEV
++//* 08/31/2002 Paul Hunt Added PERTONE_EQ and HYBRID_SWITCH for ar0700mp
++//* 09/12/2002 Paul Hunt Added support for ar0700db target.
++//* 08/07/2002 U.Dasgupta Turned off MARGIN_DELTA_RETRAIN feature for ISDN platforms
++//* 11/14/2002 Paul Hunt Merged AX5 MR6 PC modifications into AR7 codebase, specifically
++//* turned off MARGIN_DELTA_RETRAIN feature for ar0700db target
++//* 08/26/2002 N. Warke Added DUAL_TEQ token. Active only for Ax7 target
++//* 09/26/2002 Mannering Add token CODEC_EMU for codec emulator board
++//* 10/15/2002 Iyer/Molla Added DMT_BIS token for DELT support
++//* 10/21/2002 A. Redfern Added PHY_EC_ENABLE and PHY_PATH_ENABLE tokens
++//* 10/23/2002 A. Redfern Removed LINE_DIAG token
++//* 10/28/2002 J. Bergsagel Cleaned up old targets and cleaned up the token list
++//* 10/30/2002 A. Redfern Added PHY_TDW_ENABLE
++//* 11/01/2002 A. Redfern Removed SMART_MARGIN token
++//* 11/01/2002 Mustafa Turned on SPECTRAL_SHAPING features for Lucent AnyMedia O.69 Interop.
++//* 11/15/2002 Yim/Mannering Added CODEC_EMU token for analog emulation board specifics
++//* 11/15/2002 Iyer/Molla Added DEBUG_DELT and MEM_STR token to support DELT debug
++//* 12/27/2002 Sameer V Added ATM_TC_HW token for Sangam.
++//* 01/06/2003 J. Bergsagel Added default values for NLNOISEADJSNR, ARTT and DS_PWR_CUTBACK
++//* 01/07/2003 S.Yim Modified ar0700db_diag target to turn on ISDN token
++//* 01/22/2003 J. Bergsagel Added back in defines for the debug targets.
++//* 01/21/2003 MCB Implemented Ax7 UNIT-MODULE modular software framework.
++//* 01/31/2003 J. Bergsagel Made debug targets to be for the FPGA platform; non-debug for Sangam.
++//* Turned off DUAL_TEQ, PHY_EC_ENABLE and PHY_PATH_ENABLE by default
++//* for the Sangam (non-debug) targets.
++//* Turned off OLAYDP token by default.
++//* Turned off SWTC and turned on ATM_TC_HW by default for Sangam targets.
++//* 01/29/2003 Sameer V Added ATMBERT_HW token for Sangam.
++//* 02/04/2003 D. Mannering Added CO_PROFILE token
++//* 02/19/2003 Sameer V Added back EXTERNBERT token for ar0700mp_dp and ar0700db_dp targets.
++//* Disabled EXTERNBERT for debug target since it is not supported on the
++//* FPGA platform.
++//* 02/21/2003 A. Redfern Turned off OAM_EOC, AOC and BITSWAP (until memory issues are resolved).
++//* Turned on DUAL_TEQ, PHY_PATH_ENABLE and PHY_EC_ENABLE.
++//* 02/21/2003 D. Mannering Added DEBUG_DUMP.
++//* 03/06/2003 J. Bergsagel Cleaned up tokens for each target and switched diag targets
++//* over to the Sangam platform (instead of the FPGA platform).
++//* 03/07/2003 J. Bergsagel Cleaned up TC and BERT tokens
++//* 03/11/2003 J. Bergsagel Turned on AOC and BITSWAP for Sangam POTS and ISDN targets.
++//* 03/20/2003 Mallesh Added SHALF token.
++//* 03/24/2003 F. Mujica Enable hybrid selection
++//* 03/26/2003 A. Redfern Removed PMEMSAVE_GHS (always = 1).
++//* 04/08/2003 F. Mujica Renamed HYBRID_SWITCH token to PHY_HYB_ENABLE
++//* 04/08/2003 J. Bergsagel Turned off PHY_HYB_ENABLE for _debug targets (FPGA board builds)
++//* 04/09/2003 J. Bergsagel Turned on OLAYDP only for ar0700mp and ar0700db.
++//* Turned on AOC, BITSWAP, and OAM_EOC for ar0700mp and ar0700db.
++//* 04/09/2003 J. Bergsagel Corrected name "PHY_HYB_SELECT" to "PHY_HYB_ENABLE"
++//* 04/15/2003 A. Redfern Turned on ECI_PULSECOM_INTEROP because phase optimization was enabled.
++//* 05/05/2003 D. Mannering Review Comments - turn on AOC, EXTERNBERT, SHALF, for ar0700mp; amd
++//* turn on AOC for ar0700db
++//* 05/11/2003 Prashant S Added DMT_BIS token for AR7 Soft DI work
++//* 05/13/2003 J. Bergsagel Turned on IMPROVED_STAT_SUPPORT_06_03_00 by default for necessary statistics
++//* 05/15/2003 J. Bergsagel Turned off CO_PROFILE for diag targets.
++//* 05/27/2003 U.Dasgupta Added NLNOISEADJSNR_EC token for ISDN - to take care of non-linear noise
++//* (from ISDN splitter) compensation.
++//* 06/02/2003 Z. Yang Added PHY_NDIAG_ENABLE token.
++//* 06/02/2003 Z. Yang Added COMB_LINEDIAG_ENABLE token.
++//* 06/05/2003 P. Hunt Turned on ATUC_CLEARDOWN_CHANGE token for all targets.
++//* 06/05/2003 Mallesh Turned on CENTILLIUM_VENDORID_AND_TXRATE_CHNG to enable logging the vendor ID
++//* for centillium and litespan
++//* 06/05/2003 U.Dasgupta Turned on SHALF token for ISDN.
++//* 06/06/2003 U.Dasgupta Turned on G.hs nonstandard field token for ar0700db target.
++//* 06/12/2003 J. Bergsagel Changed *_debug targets to be for JTAG=1 instead of FPGA targets
++//* IMPORTANT: For non-JTAG cases, "JTAG" should be undefined.
++//* Therefore, "JTAG" should not have a default case at the bottom (JTAG 0)
++//* 06/18/2003 A. Redfern Turned on spectral shaping token for all targets.
++//* 06/23/2003 J. Bergsagel Turned off GHS_NON_STD_FIELD token for ar0700db until bugs are fixed.
++//* 06/23/2003 U G Jani Undid the above change since the bug is fixed.
++//* 06/27/2003 Mallesh Removed all the interop tokens which are no longer required.
++//* 08/20/2003 J. Bergsagel Added default value for OVHD_PMDTEST_PARA and put default section
++//* tokens in alphabetical order.
++//* 10/09/2003 Hanyu Liu Defined token ADSL2_1BIT_TONE to support Rx one bit constellation.
++//* 10/12/2003 Hanyu Liu Defined token ADSL2_BSWP for bitswap.
++//* 10/20/2003 Xiaohui Li Added READSL2_ENABLE token.
++//* 12/01/2003 Seungmok Oh Added TXDF2B_PROFILING token, which is active only for POTS target.
++//* 12/09/2003 Jack Huang Turned on GHS_NON_STD_FIELD support for AR7 POTS targets
++//* 12/16/2003 Mustafa T. Added the necessary definitions for diag target.
++//*****************************************************************************************************
++//*
++//* The default flag settings are:
++//*
++//* -dATUC=1 -dSTD=0 -dISDN=0 -dTIPCI=0 -dTID=0 -dTII=0 -dAI=0
++//* -dEVM2=0 -dEU=0 -dSL=0 -dSL_EVM=1 -dGLITE=0
++//*
++//* and are set after all the per-suffix options have had a chance to
++//* set them. Each flag is only set if it has not previously been set, so
++//* per-suffix settings can override defaults, and command-line defines can
++//* override per-suffix settings.
++//*
++//*****************************************************************************
++
++
++//* ===========================================================================
++//* Suffix codes
++//* The command-line can include -dOBJSFX_xxx to get a flag set
++//* instead of explicitly setting each flag on each CC/ASM command-line.
++//* and the object suffix will control the settings of "feature" constants.
++//* ===========================================================================
++//
++//* ===========================================================================
++// Flag settings for new suffixes (in alphabetical order of suffix)
++// Each suffix has to specify only those flags which differ from the
++// default settings.
++//* ===========================================================================
++// NOTE: Try to keep feature flags in alphabetical order to ease maintenance.
++//* ===========================================================================
++//*
++
++#define CHIPSET_ID_UNKN '?'
++#define CHIPSET_ID_AH 'H'
++#define CHIPSET_ID_AP 'P'
++#define CHIPSET_ID_AR 'R'
++#define CHIPSET_ID_ARV 'R'
++#define CHIPSET_ID_AT 'T'
++#define CHIPSET_ID_AU 'U'
++
++#define CHIPSET_ID2_GENERIC '0'
++#define CHIPSET_ID2_ARV 'R'
++
++ #define DSPDP_IMAGE_ID_STANDARD(code) ( \
++ STANDARD_is_MULTIMODE(code) ? "M" : \
++ STANDARD_is_GDMT(code) ? "D" : \
++ STANDARD_is_GLITE(code) ? "L" : \
++ STANDARD_is_T1413(code) ? "T" : "_")
++
++ #define DSPDP_IMAGE_ID_SERVICE(code) ( \
++ SERVICE_is_POTS(code) ? "P" : \
++ SERVICE_is_ISDN_ANNEXB(code) ? "B" : \
++ SERVICE_is_ISDN_ANNEXC(code) ? "C" : \
++ SERVICE_is_ISDN_PROP(code) ? "I" : "")
++
++// Bit-codes for feature byte in new version.
++//
++// 0000 0000
++// |||| ||||
++// |||| |||+ -- POTS
++// |||| ||+---- ISDN_ANNEXB
++// |||| |+----- ISDN_ANNEXC
++// |||| +------ ISDN_PROP
++// |||+--------
++// ||+--------- GHS
++// |+---------- GLITE
++// +----------- T1413
++//
++//
++#define FEATURE_BIT_T1413 0x80
++#define FEATURE_BIT_GLITE 0x40
++#define FEATURE_BIT_GHS 0x20
++#define FEATURE_BIT_ISDN_PROP 0x08
++#define FEATURE_BIT_ISDN_ANNEXC 0x04
++#define FEATURE_BIT_ISDN_ANNEXB 0x02
++#define FEATURE_BIT_POTS 0x01
++
++#define STANDARD_BITS_MASK (FEATURE_BIT_T1413 | FEATURE_BIT_GLITE | FEATURE_BIT_GHS)
++#define STANDARD_BITS_T1413 FEATURE_BIT_T1413
++#define STANDARD_BITS_GHS FEATURE_BIT_GHS
++#define STANDARD_BITS_GLITE (FEATURE_BIT_GLITE | FEATURE_BIT_GHS)
++#define STANDARD_BITS_GDMT (STANDARD_BITS_T1413 | STANDARD_BITS_GHS)
++#define STANDARD_BITS_MULTIMODE (STANDARD_BITS_T1413 | STANDARD_BITS_GLITE | STANDARD_BITS_GDMT)
++
++#define SERVICE_BIT_ISDN_ANNEXB FEATURE_BIT_ISDN_ANNEXB
++#define SERVICE_BIT_ISDN_ANNEXC FEATURE_BIT_ISDN_ANNEXC
++#define SERVICE_BIT_ISDN_PROP FEATURE_BIT_ISDN_PROP
++#define SERVICE_BIT_POTS FEATURE_BIT_POTS
++
++//
++// Debug new-style suffixes
++//
++//
++
++#if defined(OBJSFX_ar0700db_debugobj)
++#ifndef OBJSFX_ar0700dbobj
++#define OBJSFX_ar0700dbobj 1
++#endif
++// Here, in alphabetic order, are the feature tokens that
++// distinguish this suffix from its non-_debug partner:
++// (All other tokens from the non-_debug partner that are non-conflicting will also be picked up)
++
++#ifndef JTAG
++#define JTAG 1
++#endif
++
++#elif defined(OBJSFX_ar0700mp_debugobj)
++#ifndef OBJSFX_ar0700mpobj
++#define OBJSFX_ar0700mpobj 1
++#endif
++// Here, in alphabetic order, are the feature tokens that
++// distinguish this suffix from its non-_debug partner:
++// (All other tokens from the non-_debug partner that are non-conflicting will also be picked up)
++
++#ifndef ADSL2_BSWP
++#define ADSL2_BSWP 1
++#endif
++#ifndef AOC
++#define AOC 1
++#endif
++#ifndef BITSWAP
++#define BITSWAP 1
++#endif
++#ifndef DEBUG_ADSL2
++#define DEBUG_ADSL2 0
++#endif
++#ifndef DEBUG_LOG
++#define DEBUG_LOG 0
++#endif
++#ifndef GHS_NON_STD_FIELD
++#define GHS_NON_STD_FIELD 1
++#endif
++#ifndef JTAG
++#define JTAG 1
++#endif
++#endif // end of the series of "#elif defined" for debug targets
++
++
++//
++// Standard new-style suffixes for operational and mfgr'ing diag.
++//
++
++#if defined(OBJSFX_ar0700dbobj)
++#define CHIPSET_AR07 1
++#define PLATFORM_AR0700 1
++#define DSPDP_CHIPSET_ID CHIPSET_ID_AR
++#define DSPDP_CHIPSET_ID2 CHIPSET_ID2_GENERIC
++#define DSPDP_CHIPSET_GEN 7
++#define DSPDP_HARDWARE_REV1 '0'
++#define DSPDP_HARDWARE_REV2 '0'
++#define DSPDP_FEATURE_CODE (STANDARD_BITS_GDMT|SERVICE_BIT_ISDN_ANNEXB)
++#ifndef AOC
++#define AOC 1
++#endif
++// ATM_TC_HW and SWTC are mutually exclusive
++#ifndef ATM_TC_HW
++#define ATM_TC_HW 1
++#endif
++#ifndef SWTC
++#define SWTC 0
++#endif
++#ifndef BITSWAP
++#define BITSWAP 1
++#endif
++#ifndef EXTERNBERT
++#define EXTERNBERT 0
++#endif
++#ifndef GHS_NON_STD_FIELD
++#define GHS_NON_STD_FIELD 1
++#endif
++#ifndef MARGIN_DELTA_RETRAIN
++#define MARGIN_DELTA_RETRAIN 0
++#endif
++#ifndef NLNOISEADJSNR_EC
++#define NLNOISEADJSNR_EC 1
++#endif
++#ifndef OLAYDP
++#define OLAYDP 1
++#endif
++#ifndef SHALF
++#define SHALF 1
++#endif
++
++
++#elif defined(OBJSFX_ar0700db_diagobj)
++#define CHIPSET_AR07 1
++#define PLATFORM_AR0700 1
++#define DSPDP_CHIPSET_ID CHIPSET_ID_AR
++#define DSPDP_CHIPSET_ID2 CHIPSET_ID2_GENERIC
++#define DSPDP_CHIPSET_GEN 7
++#define DSPDP_HARDWARE_REV1 '0'
++#define DSPDP_HARDWARE_REV2 '0'
++#define DSPDP_FEATURE_CODE (STANDARD_BITS_GDMT|SERVICE_BIT_ISDN_ANNEXB)
++#ifndef AOC
++#define AOC 0
++#endif
++// ATM_TC_HW and SWTC are mutually exclusive (or both must be off)
++#ifndef ATM_TC_HW
++#define ATM_TC_HW 0
++#endif
++#ifndef SWTC
++#define SWTC 0
++#endif
++#ifndef BITSWAP
++#define BITSWAP 0
++#endif
++#ifndef CO_PROFILE
++#define CO_PROFILE 0
++#endif
++#ifndef MARGIN_DELTA_RETRAIN
++#define MARGIN_DELTA_RETRAIN 0
++#endif
++#ifndef MFGR_DIAG
++#define MFGR_DIAG 1
++#endif
++#ifndef OAM_EOC
++#define OAM_EOC 0
++#endif
++#ifndef OLAYDP
++#define OLAYDP 0
++#endif
++#ifndef SNR_UPDATE
++#define SNR_UPDATE 0
++#endif
++
++#elif defined(OBJSFX_ar0700mpobj)
++#define CHIPSET_AR07 1
++#define PLATFORM_AR0700 1
++#define DSPDP_CHIPSET_ID CHIPSET_ID_AR
++#define DSPDP_CHIPSET_ID2 CHIPSET_ID2_GENERIC
++#define DSPDP_CHIPSET_GEN 7
++#define DSPDP_HARDWARE_REV1 '0'
++#define DSPDP_HARDWARE_REV2 '0'
++#define DSPDP_FEATURE_CODE (STANDARD_BITS_MULTIMODE|SERVICE_BIT_POTS)
++#ifndef AOC
++#define AOC 1
++#endif
++// ATM_TC_HW and SWTC are mutually exclusive
++#ifndef ADSL2_1BIT_TONE
++#define ADSL2_1BIT_TONE 0
++#endif
++#ifndef ADSL2_BSWP
++#define ADSL2_BSWP 1
++#endif
++#ifndef ATM_TC_HW
++#define ATM_TC_HW 1
++#endif
++#ifndef SWTC
++#define SWTC 0
++#endif
++#ifndef BITSWAP
++#define BITSWAP 1
++#endif
++#ifndef EXTERNBERT
++#define EXTERNBERT 0
++#endif
++#ifndef OLAYDP
++#define OLAYDP 1
++#endif
++#ifndef DMT_BIS
++#define DMT_BIS 1
++#endif
++#ifndef SHALF
++#define SHALF 1
++#endif
++#ifndef MEM_STR
++#define MEM_STR 0
++#endif
++#ifndef DS_LOOP_BACK
++#define DS_LOOP_BACK 0
++#endif
++#ifndef LOOP_BACK_DEBUG
++#define LOOP_BACK_DEBUG 0
++#endif
++#ifndef US_LOOP_BACK
++#define US_LOOP_BACK 0
++#endif
++#ifndef OVHD_PMDTEST_PARA
++#define OVHD_PMDTEST_PARA 0
++#endif
++#ifndef DS_RX_CODEWORD
++#define DS_RX_CODEWORD 1
++#endif
++#ifndef READSL2_ENABLE
++#define READSL2_ENABLE 1
++#endif
++#ifndef GHS_NON_STD_FIELD
++#define GHS_NON_STD_FIELD 1
++#endif
++
++#elif defined(OBJSFX_ar0700mp_diagobj)
++#define CHIPSET_AR07 1
++#define PLATFORM_AR0700 1
++#define DSPDP_CHIPSET_ID CHIPSET_ID_AR
++#define DSPDP_CHIPSET_ID2 CHIPSET_ID2_GENERIC
++#define DSPDP_CHIPSET_GEN 7
++#define DSPDP_HARDWARE_REV1 '0'
++#define DSPDP_HARDWARE_REV2 '0'
++#define DSPDP_FEATURE_CODE (STANDARD_BITS_MULTIMODE|SERVICE_BIT_POTS)
++#ifndef ADSL2_BSWP
++#define ADSL2_BSWP 0
++#endif
++#ifndef AOC
++#define AOC 0
++#endif
++// ATM_TC_HW and SWTC are mutually exclusive (or both must be off)
++#ifndef ATM_TC_HW
++#define ATM_TC_HW 0
++#endif
++#ifndef SWTC
++#define SWTC 0
++#endif
++#ifndef BITSWAP
++#define BITSWAP 0
++#endif
++#ifndef CO_PROFILE
++#define CO_PROFILE 0
++#endif
++#ifndef DMT_BIS
++#define DMT_BIS 0
++#endif
++#ifndef MARGIN_DELTA_RETRAIN
++#define MARGIN_DELTA_RETRAIN 0
++#endif
++#ifndef MFGR_DIAG
++#define MFGR_DIAG 1
++#endif
++#ifndef OAM_EOC
++#define OAM_EOC 0
++#endif
++#ifndef OLAYDP
++#define OLAYDP 0
++#endif
++#ifndef SNR_UPDATE
++#define SNR_UPDATE 0
++#endif
++#ifndef US_CRC_RETRAIN
++#define US_CRC_RETRAIN 0
++#endif
++#ifndef ADSL2_BSWP
++#define ADSL2_BSWP 0
++#endif
++#ifndef DMT_BIS
++#define DMT_BIS 0
++#endif
++#ifndef DS_RX_CODEWORD
++#define DS_RX_CODEWORD 0
++#endif
++
++#else
++#define DSPDP_CHIPSET_ID CHIPSET_ID_UNKN
++#define DSPDP_CHIPSET_ID2 CHIPSET_ID2_GENERIC
++#define DSPDP_CHIPSET_GEN 0
++#define DSPDP_HARDWARE_REV1 '0'
++#define DSPDP_HARDWARE_REV2 '0'
++#define DSPDP_FEATURE_CODE 0
++#endif
++
++// For use in checking the code in drivers -- indented to avoid .h->.ah
++ #define STANDARD_is_T1413(code) (!(((code) & STANDARD_BITS_MASK) ^ STANDARD_BITS_T1413))
++ #define STANDARD_is_GLITE(code) (!(((code) & STANDARD_BITS_MASK) ^ STANDARD_BITS_GLITE))
++ #define STANDARD_is_GHS(code) (((code) & STANDARD_BITS_MASK) & STANDARD_BITS_GHS)
++ #define STANDARD_is_GDMT(code) (!(((code) & STANDARD_BITS_MASK) ^ (STANDARD_BITS_T1413 | STANDARD_BITS_GHS)))
++ #define STANDARD_is_MULTIMODE(code) (!(((code) & STANDARD_BITS_MASK) ^ (STANDARD_BITS_T1413 | STANDARD_BITS_GLITE | STANDARD_BITS_GDMT)))
++ #define SERVICE_is_POTS(code) ((code) & SERVICE_BIT_POTS)
++ #define SERVICE_is_ISDN_ANNEXB(code) ((code) & SERVICE_BIT_ISDN_ANNEXB)
++ #define SERVICE_is_ISDN_ANNEXC(code) ((code) & SERVICE_BIT_ISDN_ANNEXC)
++ #define SERVICE_is_ISDN_PROP(code) ((code) & SERVICE_BIT_ISDN_PROP)
++
++#define STANDARD_T1413 (!((DSPDP_FEATURE_CODE & STANDARD_BITS_MASK) ^ STANDARD_BITS_T1413))
++#define STANDARD_GLITE (!((DSPDP_FEATURE_CODE & STANDARD_BITS_MASK) ^ STANDARD_BITS_GLITE))
++#define STANDARD_GHS ((DSPDP_FEATURE_CODE & STANDARD_BITS_MASK) & STANDARD_BITS_GHS)
++#define STANDARD_GDMT (!((DSPDP_FEATURE_CODE & STANDARD_BITS_MASK) ^ (STANDARD_BITS_T1413 | STANDARD_BITS_GHS)))
++#define STANDARD_MULTIMODE (!((DSPDP_FEATURE_CODE & STANDARD_BITS_MASK) ^ (STANDARD_BITS_T1413 | STANDARD_BITS_GLITE | STANDARD_BITS_GDMT)))
++
++#define SERVICE_POTS (DSPDP_FEATURE_CODE & SERVICE_BIT_POTS)
++#define SERVICE_ISDN_ANNEXB (DSPDP_FEATURE_CODE & SERVICE_BIT_ISDN_ANNEXB)
++#define SERVICE_ISDN_ANNEXC (DSPDP_FEATURE_CODE & SERVICE_BIT_ISDN_ANNEXC)
++#define SERVICE_ISDN_PROP (DSPDP_FEATURE_CODE & SERVICE_BIT_ISDN_PROP)
++#define SERVICE_ISDN (SERVICE_ISDN_ANNEXB | SERVICE_ISDN_ANNEXC | SERVICE_ISDN_PROP)
++
++
++//
++// Backwards compatibility with old tokens
++//
++
++#if (SERVICE_POTS)
++#ifndef ISDN
++#define ISDN 0
++#endif
++#endif
++
++#if (SERVICE_ISDN_ANNEXB | SERVICE_ISDN_PROP)
++#ifndef ISDN
++#define ISDN 1
++#endif
++#endif
++
++
++//
++//* ===========================================================================
++// More Default settings
++//* ===========================================================================
++//
++
++//
++// BEGIN Could automatically generate showdefs code
++//
++#ifndef AOC
++#define AOC 1
++#endif
++#ifndef ARTT
++#define ARTT 0
++#endif
++#ifndef ATMBERT
++#define ATMBERT 0
++#endif
++// ATM_TC_HW and SWTC are mutually exclusive
++#ifndef ATM_TC_HW
++#define ATM_TC_HW 1
++#endif
++#if ATM_TC_HW
++#ifndef ATMBERT_HW
++#define ATMBERT_HW 1
++#endif
++#ifndef SWTC
++#define SWTC 0
++#endif
++#else // else case for #if ATM_TC_HW
++#ifndef ATMBERT_HW
++#define ATMBERT_HW 0
++#endif
++#ifndef SWTC
++#define SWTC 1
++#endif
++#endif // end of #if ATM_TC_HW
++#ifndef ATM_TC_PATH1_ON
++#define ATM_TC_PATH1_ON 0
++#endif
++#ifndef BITSWAP
++#define BITSWAP 1
++#endif
++#ifndef COMB_LINEDIAG_ENABLE
++#define COMB_LINEDIAG_ENABLE 0
++#endif
++#ifndef CODEC_EMU
++#define CODEC_EMU 0
++#endif
++#ifndef CO_PROFILE
++#define CO_PROFILE 1
++#endif
++#ifndef DDC
++#define DDC 0
++#endif
++#ifndef DEBUG_ADSL2
++#define DEBUG_ADSL2 0
++#endif
++#ifndef DEBUG_DUMP
++#define DEBUG_DUMP 0
++#endif
++#ifndef DEBUG_LOG
++#define DEBUG_LOG 0
++#endif
++#ifndef DEV_DEBUG
++#define DEV_DEBUG 0
++#endif
++#ifndef DS_LOOP_BACK
++#define DS_LOOP_BACK 0
++#endif
++#ifndef DS_RX_CODEWORD
++#define DS_RX_CODEWORD 1
++#endif
++#ifndef LOOP_BACK_DEBUG
++#define LOOP_BACK_DEBUG 0
++#endif
++#ifndef US_LOOP_BACK
++#define US_LOOP_BACK 0
++#endif
++#ifndef DPLL_MODE
++#define DPLL_MODE 0
++#endif
++#ifndef DSPBIOSII
++#define DSPBIOSII 0
++#endif
++#ifndef DMT_BIS
++#define DMT_BIS 1
++#endif
++#ifndef ADSL2_1BIT_TONE
++#define ADSL2_1BIT_TONE 0
++#endif
++#ifndef ADSL2_BSWP
++#define ADSL2_BSWP 1
++#endif
++#ifndef MEM_STR
++#define MEM_STR 0
++#endif
++#ifndef DS_PWR_CUTBACK
++#define DS_PWR_CUTBACK 0
++#endif
++#ifndef DUAL_TEQ
++#define DUAL_TEQ 1
++#endif
++#ifndef EXTERNBERT
++#define EXTERNBERT 0
++#endif
++#ifndef FPGA
++#define FPGA 0
++#endif
++#ifndef INBAND
++#define INBAND 0
++#endif
++#ifndef ISDN
++#define ISDN 0
++#endif
++#ifndef ISDN_DEBUG
++#define ISDN_DEBUG 0
++#endif
++#ifndef LINE_DIAG
++#define LINE_DIAG 1
++#endif
++#ifndef LOOP_BACK_DEBUG
++#define LOOP_BACK_DEBUG 0
++#endif
++#ifndef MANUFACTURING_TESTS
++#define MANUFACTURING_TESTS 0
++#endif
++#ifndef MARGIN_DELTA_RETRAIN
++#define MARGIN_DELTA_RETRAIN 1
++#endif
++#ifndef MEM_STR
++#define MEM_STR 0
++#endif
++#ifndef MFGR_DIAG
++#define MFGR_DIAG 0
++#endif
++#ifndef NLNOISEADJSNR
++#define NLNOISEADJSNR 0
++#endif
++#ifndef NLNOISEADJSNR_EC
++#define NLNOISEADJSNR_EC 0
++#endif
++#ifndef NTR_MODE
++#define NTR_MODE 0
++#endif
++#ifndef OAM_EOC
++#define OAM_EOC 1
++#endif
++#ifndef OLAYDP
++#define OLAYDP 0
++#endif
++#ifndef OLAYDP_EMIF
++#define OLAYDP_EMIF 0
++#endif
++#ifndef OLAYDP_2STEP
++#define OLAYDP_2STEP 0
++#endif
++#ifndef OLAYDP_PCI
++#define OLAYDP_PCI 0
++#endif
++#ifndef OUTBAND
++#define OUTBAND 0
++#endif
++#ifndef OVHD_PMDTEST_PARA
++#define OVHD_PMDTEST_PARA 0
++#endif
++#ifndef PERTONE_EQ
++#define PERTONE_EQ 0
++#endif
++#ifndef PHY_EC_ENABLE
++#define PHY_EC_ENABLE 1
++#endif
++#ifndef PHY_HYB_ENABLE
++#define PHY_HYB_ENABLE 1
++#endif
++#ifndef PHY_NDIAG_ENABLE
++#define PHY_NDIAG_ENABLE 0
++#endif
++#ifndef PHY_PATH_ENABLE
++#define PHY_PATH_ENABLE 1
++#endif
++#ifndef PHY_TDW_ENABLE
++#define PHY_TDW_ENABLE 0
++#endif
++#ifndef TC_ATM_PCIMASTER
++#define TC_ATM_PCIMASTER 0
++#endif
++#ifndef SEPARATE_TX_RX_BUFFERS
++#define SEPARATE_TX_RX_BUFFERS 0
++#endif
++#ifndef SHALF
++#define SHALF 0
++#endif
++#ifndef SPECTRAL_SHAPING
++#define SPECTRAL_SHAPING 1
++#endif
++#ifndef SNR_UPDATE
++#define SNR_UPDATE 1
++#endif
++#ifndef TC_DEBUG
++#define TC_DEBUG 0
++#endif
++#ifndef TC_LOOPBACK
++#define TC_LOOPBACK 0
++#endif
++#ifndef TESTMODE
++#define TESTMODE 0
++#endif
++#ifndef TRELLIS
++#define TRELLIS 1
++#endif
++#ifndef TXDF2B_PROFILING
++#if (SERVICE_POTS & (!MFGR_DIAG) & (CO_PROFILE))
++#define TXDF2B_PROFILING 1
++#else
++#define TXDF2B_PROFILING 0
++#endif
++#endif
++#ifndef US_CRC_RETRAIN
++#define US_CRC_RETRAIN 1
++#endif
++#ifndef US_LOOP_BACK
++#define US_LOOP_BACK 0
++#endif
++#ifndef USB
++#define USB 0
++#endif
++#ifndef READSL2_ENABLE
++#define READSL2_ENABLE 1
++#endif
++
++// Interop tokens
++#ifndef GHS_NON_STD_FIELD
++#define GHS_NON_STD_FIELD 0
++#endif
++#ifndef LUCENT_ANYMEDIA_ENIATT_INTEROP
++#define LUCENT_ANYMEDIA_ENIATT_INTEROP 0
++#endif
++
++
++//
++// END Could automatically generate showdefs code
++//
++#if DSPDP_FEATURE_CODE
++#else
++// Unrecognized_suffix____check_spelling
++#endif
++//
++// LNK_CMD is set when running CPP to generate lnk_cpe.cmd file
++// -- the linker is not happy when it sees C code show up in the
++// result!
++//
++#ifndef LNK_CMD
++extern int compile_happy; // Keep the compiler from complaining about an empty file
++#endif
++
++#endif
++
+diff -urN linux.old/drivers/atm/sangam_atm/env_def_typedefs.h linux.dev/drivers/atm/sangam_atm/env_def_typedefs.h
+--- linux.old/drivers/atm/sangam_atm/env_def_typedefs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/env_def_typedefs.h 2005-08-23 04:46:50.104842632 +0200
+@@ -0,0 +1,228 @@
++#ifndef __ENV_DEF_TYPEDEFS_H__
++#define __ENV_DEF_TYPEDEFS_H__ 1
++
++/*******************************************************************************
++* FILE PURPOSE: Define data types for C and TMS320C6x C compilers
++********************************************************************************
++*
++* FILE NAME: dpsys_typedefs.h
++*
++* DESCRIPTION:
++* This file contains the main typedefs that we need.
++*
++* HISTORY:
++*
++* 03/11/97 Bob Lee Created
++* 03/13/97 Chishtie
++* 03/14/97 Bob Lee Format change to meet "Engineering Model
++* - System Architucture Specification"
++* Rev AP3. Jan. 29, 1997
++* 07/21/00 Barnett Moved many common typedefs from
++* host i/f header file to here.
++* 03/30/01 Barnett Mod's per driver team feedback.
++* Some tokens cannot be def'ed
++* if _WINDEF_ is def'ed.
++* 04/05/01 Barnett Added DSPDP_ prefix to tokens that originate
++* in the public interface.
++* 06/01/01 J. Bergsagel Modified to add standard typedefs
++* 07/25/01 J. Bergsagel Changed name from typedefs.h to dpsys_typedefs.h
++* 07/30/01 J. Bergsagel Moved typedefs that were conflicting with Windows
++* driver software to the "#ifndef _WINDEF_" section.
++* 08/09/01 S. Yim Moved FALSE/TRUE definitions from ctl_interface_u.h
++* (conflict with BIOS/std.h)
++* 09/03/01 S. Yim Do not include typedef char and float if _STD defined
++* (conflict with BIOS/std.h)
++* 01/21/03 MCB Implemented Ax7 UNIT-MODULE modular software framework.
++* 03/20/03 Mallesh Defined size of basic variables
++* 03/27/03 F. Mujica Added SINT40 and UINT40 definitions.
++*
++* (C) Copyright Texas Instruments Inc. 1997-2001. All rights reserved.
++*******************************************************************************/
++
++// Common type definitions
++
++// Basic constants needed everywhere
++#ifndef STD_
++#define FALSE 0
++#define TRUE 1
++#endif
++
++// Read-Write Data Types
++typedef signed char SINT8; // Signed 8-bit integer (7-bit magnitude)
++typedef unsigned char UINT8; // Unsigned 8-bit integer
++typedef signed short SINT16; // Signed 16-bit integer (15-bit magnitude)
++typedef unsigned short UINT16; // Unsigned 16-bit integer
++typedef signed int SINT32; // Signed 32-bit integer (31-bit magnitude)
++typedef unsigned int UINT32; // Unsigned 32-bit integer
++typedef long signed int SINT40; // Long signed 40-bit integer
++typedef long unsigned int UINT40; // Long unsigned 40-bit integer
++
++// All pointers are 32 bits long
++typedef SINT8 *PSINT8; // Pointer to SINT8
++typedef UINT8 *PUINT8; // Pointer to UINT8
++typedef SINT16 *PSINT16; // Pointer to SINT16
++typedef UINT16 *PUINT16; // Pointer to UINT16
++typedef SINT32 *PSINT32; // Pointer to SINT32
++typedef UINT32 *PUINT32; // Pointer to UINT32
++
++#define SIZEOF_SINT8 1
++#define SIZEOF_UINT8 1
++#define SIZEOF_SINT16 2
++#define SIZEOF_UINT16 2
++#define SIZEOF_SINT32 4
++#define SIZEOF_UINT32 4
++#define SIZEOF_SINT40 8
++#define SIZEOF_UINT40 8
++
++// Size of Read-Write Data Types - in bytes
++#define SIZEOF_char 1
++#define SIZEOF_Int8 1
++#define SIZEOF_UChar 1
++#define SIZEOF_UInt8 1
++#define SIZEOF_Float 4
++#define SIZEOF_Double 8
++#define SIZEOF_byte 1
++
++// Read-Only Data Types - should be only used for ROM code
++typedef const char CharRom; // 8 bit signed character
++typedef const signed char Int8Rom; // 8 bit signed integer
++typedef const unsigned char UCharRom; // 8 bit unsigned character
++typedef const unsigned char UInt8Rom; // 8 bit unsigned integer
++typedef const float FloatRom; // IEEE 32-bit
++typedef const double DoubleRom; // IEEE 64-bit
++
++#ifndef _WINDEF_
++
++// Read-Write Data Types
++typedef signed char Int8; // 8 bit signed integer
++typedef unsigned char UChar; // 8 bit unsigned character
++typedef unsigned char UInt8; // 8 bit unsigned integer
++#ifndef STD_
++typedef char Char; // 8 bit signed character
++typedef float Float; // IEEE 32-bit
++#endif
++typedef double Double; // IEEE 64-bit
++typedef signed char byte; // 8 bit signed integer
++
++
++// These typedefs collide with those in Win2k DDK inc\WINDEF.H
++
++// common type definition
++typedef unsigned char BYTE; // 8-bit
++typedef signed short SHORT; // 16-bit signed
++typedef unsigned short WORD; // 16-bit
++typedef unsigned int DWORD; // 32-bit, TI DSP has 40 bit longs
++
++// All pointers are 32 bits long
++typedef BYTE *PBYTE; // pointer to 8 bit data
++typedef unsigned char *PCHAR; // pointer to 8 bit data
++typedef SHORT *PSHORT; // pointer to 16 bit data
++typedef WORD *PWORD; // pointer to 16 bit data
++typedef DWORD *PDWORD; // pointer to 32 bit data
++
++#endif // #ifndef _WINDEF_
++
++
++#define SIZEOF_BYTE 1
++#define SIZEOF_SHORT 2
++#define SIZEOF_WORD 2
++#define SIZEOF_DWORD 4
++#define SIZEOF_PCHAR 4
++#define SIZEOF_PWORD 4
++#define SIZEOF_PDWORD 4
++
++// Size of Read-Only Data Types - in bytes
++#define SIZEOF_CharRom 1
++#define SIZEOF_Int8Rom 1
++#define SIZEOF_UCharRom 1
++#define SIZEOF_UInt8Rom 1
++#define SIZEOF_FloatRom 4
++#define SIZEOF_DoubleRom 8
++
++#define SIZEOF_complex_byte (2*SIZEOF_byte)
++#define SIZEOF_PTR_complex_byte 4
++typedef struct {
++ byte re;
++ byte im;
++} complex_byte, *PTR_complex_byte;
++
++#define SIZEOF_complex_short 4
++#define SIZEOF_PTR_complex_short 4
++typedef struct {
++ short re;
++ short im;
++} complex_short, *PTR_complex_short;
++
++#define SIZEOF_complex_int 8
++#define SIZEOF_PTR_complex_int 4
++typedef struct {
++ int re;
++ int im;
++} complex_int, *PTR_complex_int;
++
++typedef struct {
++ int high;
++ unsigned int low;
++} int64;
++
++typedef struct {
++ int64 real;
++ int64 imag;
++} complex_int64;
++
++#define SIZEOF_PVOID 4
++typedef void *PVOID; // pointer to void
++
++//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
++
++#if defined(_TMS320C6X) // TMS320C6xx type definitions
++
++// Read-Write Data Types
++typedef short Int16; // 16 bit signed integer
++typedef unsigned short UInt16; // 16 bit unsigned integer
++typedef int Int32; // 32 bit signed integer
++typedef unsigned int UInt32; // 32 bit unsigned signed integer
++typedef long Long40; // 40 bit signed integer
++typedef unsigned long ULong40; // 40 bit unsigned signed integer
++
++// Size of Read-Write Data Types - in bytes
++#define SIZEOF_Int16 2
++#define SIZEOF_UInt16 2
++#define SIZEOF_Int32 4
++#define SIZEOF_UInt32 4
++#define SIZEOF_Long40 5
++#define SIZEOF_ULong40 5
++
++// Read-Only Data Types - should be only used for ROM code
++typedef const short Int16Rom; // 16 bit signed integer
++typedef const unsigned short UInt16Rom; // 16 bit unsigned integer
++typedef const int Int32Rom; // 32 bit signed integer
++typedef const unsigned int UInt32Rom; // 32 bit unsigned signed integer
++typedef const long Long40Rom; // 40 bit signed integer
++typedef const unsigned long ULong40Rom; // 40 bit unsigned signed integer
++
++// Size of Read-Only Data Types - in bytes
++#define SIZEOF_Int16Rom 2
++#define SIZEOF_UInt16Rom 2
++#define SIZEOF_Int32Rom 4
++#define SIZEOF_UInt32Rom 4
++#define SIZEOF_Long40Rom 5
++#define SIZEOF_ULong40Rom 5
++
++#else // 32 bits PC Host type definitions
++
++// Read-Write Data Types
++typedef short Int16; // 16 bit signed integer
++typedef unsigned short UInt16; // 16 bit unsigned integer
++typedef int Int32; // 32 bit signed integer
++typedef unsigned int UInt32; // 32 bit unsigned integer
++
++// Read-Only Data Types - should be only used for ROM code
++typedef const short Int16Rom; // 16 bit signed integer
++typedef const unsigned short UInt16Rom; // 16 bit unsigned integer
++typedef const int Int32Rom; // 32 bit signed integer
++typedef const unsigned int UInt32Rom; // 32 bit unsigned integer
++
++#endif
++
++#endif
+diff -urN linux.old/drivers/atm/sangam_atm/Makefile linux.dev/drivers/atm/sangam_atm/Makefile
+--- linux.old/drivers/atm/sangam_atm/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/Makefile 2005-08-23 04:46:50.104842632 +0200
+@@ -0,0 +1,35 @@
++# File: drivers/net/avalanche_cpmac/Makefile
++#
++# Makefile for the Linux network (CPMAC) device drivers.
++#
++
++
++O_TARGET := tiatm.o
++obj-$(CONFIG_MIPS_SANGAM_ATM) += tiatm.o
++list-multi := tiatm.o
++
++tiatm-objs := tn7atm.o tn7dsl.o tn7sar.o dsl_hal_api.o dsl_hal_support.o cpsar.o aal5sar.o
++
++EXTRA_CFLAGS += -DEL -I$(TOPDIR)/drivers/atm/sangam_atm -DPOST_SILICON -DCOMMON_NSP -DCONFIG_LED_MODULE -DDEREGISTER_LED -DNO_ACT
++
++ifeq ($(ANNEX),B)
++EXTRA_CFLAGS += -DANNEX_B -DB
++else
++ifeq ($(ANNEX),C)
++EXTRA_CFLAGS += -DANNEX_C -DC
++else
++EXTRA_CFLAGS += -DANNEX_A -DP
++endif
++endif
++
++
++include $(TOPDIR)/Rules.make
++
++tiatm.o: $(tiatm-objs)
++ $(LD) -r -o $@ $(tiatm-objs)
++
++#avalanche_cpmac.o: $(avalanche_cpmac-objs)
++# $(LD) -r -o $@ $(avalanche_cpmac-objs)
++
++clean:
++ rm -f core *.o *.a *.s
+diff -urN linux.old/drivers/atm/sangam_atm/queue.h linux.dev/drivers/atm/sangam_atm/queue.h
+--- linux.old/drivers/atm/sangam_atm/queue.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/queue.h 2005-08-23 04:46:50.104842632 +0200
+@@ -0,0 +1,167 @@
++
++#if !defined( __QUEUE_H__ )
++#define __QUEUE_H__
++
++typedef spinlock_t OS_SPIN_LOCK;
++#define osFreeSpinLock(pLock) while(0)
++void osAcquireSpinLock(OS_SPIN_LOCK *pLock);
++void osReleaseSpinLock(OS_SPIN_LOCK *pLock);
++void osAllocateSpinLock(OS_SPIN_LOCK *pLock);
++
++//#define osAcquireSpinLock(pLock) spin_lock(pLock)
++//#define osReleaseSpinLock(pLock) spin_unlock(pLock)
++//#define osAllocateSpinLock(pLock) spin_lock_init(pLock)
++
++
++typedef struct _TI_LIST_ENTRY {
++ struct _TI_LIST_ENTRY *Flink;
++ struct _TI_LIST_ENTRY *Blink;
++} TI_LIST_ENTRY, *PTI_LIST_ENTRY, TQE, *PTQE;
++
++typedef struct _TIATM_LIST_ENTRY
++{
++ TI_LIST_ENTRY Link;
++} TIATM_LIST_ENTRY, *PTIATM_LIST_ENTRY;
++
++//-------------------------------------------------------------------------
++// QueueInitList -- Macro which will initialize a queue to NULL.
++//-------------------------------------------------------------------------
++#define QueueInitList(_L) (_L)->Link.Flink = (_L)->Link.Blink = (PTI_LIST_ENTRY)0;
++
++//-------------------------------------------------------------------------
++// QueueEmpty -- Macro which checks to see if a queue is empty.
++//-------------------------------------------------------------------------
++#define QueueEmpty(_L) (QueueGetHead((_L)) == (PTIATM_LIST_ENTRY)0)
++
++//-------------------------------------------------------------------------
++// QueueGetHead -- Macro which returns the head of the queue, but does not
++// remove the head from the queue.
++//-------------------------------------------------------------------------
++#define QueueGetHead(_L) ((PTIATM_LIST_ENTRY)((_L)->Link.Flink))
++
++#define QueueGetNext(Elem) ((PTIATM_LIST_ENTRY)((Elem)->Link.Flink))
++
++//-------------------------------------------------------------------------
++// QueuePushHead -- Macro which puts an element at the head of the queue.
++//-------------------------------------------------------------------------
++#define QueuePushHead(_L,_E) \
++ if (!((_E)->Link.Flink = (_L)->Link.Flink)) \
++ { \
++ (_L)->Link.Blink = (PTI_LIST_ENTRY)(_E); \
++ } \
++(_L)->Link.Flink = (PTI_LIST_ENTRY)(_E);
++
++//-------------------------------------------------------------------------
++// QueueRemoveHead -- Macro which removes the head of the head of queue.
++//-------------------------------------------------------------------------
++#define QueueRemoveHead(_L) \
++{ \
++ PTIATM_LIST_ENTRY ListElem; \
++ if (ListElem = (PTIATM_LIST_ENTRY)(_L)->Link.Flink) \
++ { \
++ if(!((_L)->Link.Flink = ListElem->Link.Flink)) \
++ (_L)->Link.Blink = (PTI_LIST_ENTRY) 0; \
++ } \
++}
++
++//-------------------------------------------------------------------------
++// QueuePutTail -- Macro which puts an element at the tail (end) of the queue.
++//-------------------------------------------------------------------------
++#define QueuePutTail(_L,_E) \
++{ \
++ if ((_L)->Link.Blink) \
++ { \
++ ((PTIATM_LIST_ENTRY)(_L)->Link.Blink)->Link.Flink = (PTI_LIST_ENTRY)(_E); \
++ (_L)->Link.Blink = (PTI_LIST_ENTRY)(_E); \
++ } \
++ else \
++ { \
++ (_L)->Link.Flink = \
++ (_L)->Link.Blink = (PTI_LIST_ENTRY)(_E); \
++ } \
++ (_E)->Link.Flink = (PTI_LIST_ENTRY)0; \
++}
++
++//-------------------------------------------------------------------------
++// QueuePutTailWithLock -- Macro which puts an element at the tail (end) of
++// the queue, using spin lock.
++//-------------------------------------------------------------------------
++#define QueuePutTailWithLock(_L,_E, pLock) \
++{ \
++ osAcquireSpinLock(pLock); \
++ if ((_L)->Link.Blink) \
++ { \
++ ((PTIATM_LIST_ENTRY)(_L)->Link.Blink)->Link.Flink = (PTI_LIST_ENTRY)(_E); \
++ (_L)->Link.Blink = (PTI_LIST_ENTRY)(_E); \
++ } \
++ else \
++ { \
++ (_L)->Link.Flink = \
++ (_L)->Link.Blink = (PTI_LIST_ENTRY)(_E); \
++ } \
++ (_E)->Link.Flink = (PTI_LIST_ENTRY)0; \
++ osReleaseSpinLock(pLock); \
++}
++
++//-------------------------------------------------------------------------
++// QueueGetTail -- Macro which returns the tail of the queue, but does not
++// remove the tail from the queue.
++//-------------------------------------------------------------------------
++#define QueueGetTail(_L) ((PTIATM_LIST_ENTRY)((_L)->Link.Blink))
++
++//-------------------------------------------------------------------------
++// QueuePopHead -- Macro which will pop the head off of a queue (list), and
++// return it (this differs only from queueremovehead only in
++// the 1st line)
++//-------------------------------------------------------------------------
++#define QueuePopHead(_L) \
++(PTIATM_LIST_ENTRY) (_L)->Link.Flink; QueueRemoveHead(_L);
++
++#define QueueRemoveTail(_L) \
++{ \
++ PTIATM_LIST_ENTRY ListElem; \
++ ListElem = (PTIATM_LIST_ENTRY)(_L)->Link.Flink; \
++ if(ListElem == (PTIATM_LIST_ENTRY)(_L)->Link.Blink) \
++ { \
++ (_L)->Link.Flink = (_L)->Link.Blink = (PTI_LIST_ENTRY) 0; \
++ } \
++ else \
++ { \
++ while(ListElem->Link.Flink != (PTI_LIST_ENTRY)(_L)->Link.Blink) \
++ { \
++ ListElem = (PTIATM_LIST_ENTRY)ListElem->Link.Flink; \
++ } \
++ (_L)->Link.Blink = (PTI_LIST_ENTRY) ListElem; \
++ ListElem->Link.Flink = (PTI_LIST_ENTRY)0; \
++ } \
++}
++
++#define QueueRemoveItem(_L, Elem) \
++{ \
++ PTIATM_LIST_ENTRY ListElem; \
++ ListElem = (PTIATM_LIST_ENTRY)(_L)->Link.Flink; \
++ if(ListElem == Elem) \
++ { \
++ QueueRemoveHead(_L); \
++ } \
++ else \
++ { \
++ while(ListElem) \
++ { \
++ if(Elem == (PTIATM_LIST_ENTRY)ListElem->Link.Flink) \
++ { \
++ ListElem->Link.Flink = ((PTIATM_LIST_ENTRY)Elem)->Link.Flink; \
++ if(Elem == (PTIATM_LIST_ENTRY)(_L)->Link.Blink) \
++ (_L)->Link.Blink = (PTI_LIST_ENTRY) 0; \
++ break; \
++ } \
++ ListElem = (PTIATM_LIST_ENTRY)ListElem->Link.Flink; \
++ }\
++ } \
++ ((PTIATM_LIST_ENTRY)Elem)->Link.Flink = (PTI_LIST_ENTRY) 0; \
++}
++
++#define QueuePopTail(_L) \
++((PTIATM_LIST_ENTRY)((_L)->Link.Blink)); QueueRemoveTail(_L);
++
++#endif
+diff -urN linux.old/drivers/atm/sangam_atm/release.txt linux.dev/drivers/atm/sangam_atm/release.txt
+--- linux.old/drivers/atm/sangam_atm/release.txt 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/release.txt 2005-08-23 04:46:50.104842632 +0200
+@@ -0,0 +1,118 @@
++This is release notes for AR7 Linux ATM driver.
++
++version 04.02.04.00
++-------------------
++
++1. Corrected the conditional logic from logical AND to logical OR in the case
++ of check for DSL line down condition. This is to fix PPPoA crashing
++ problem when DSL line is unplugged.
++
++version 04.02.03.00
++-------------------
++1. Changed overlay page to static allocation.
++2. Added flag to stop TX during channel closing.
++3. Changed DMA memory allocation back to "GFP_ATOMIC" flag.
++
++version 04.02.02.00
++-------------------
++1. Changed DMA memory allocation from "GFP_ATOMIC" to "GFP_KERNEL" flag.
++2. Added "DoMask" setting for VBR channel setup.
++
++version 04.02.01.01
++-------------------
++1. Modified priority check scheme per SPTC request.
++
++Version 04.02.01.00
++-------------------
++1. Add check to skb->priority to place packets to either normal or priority queue.
++2. Add spin lock to increment and decrement of queued buffer number.
++
++Version 04.02.00.00
++-------------------
++Features:
++1. Add MBS and CDVT QoS support for ATM driver.
++2. Add "stop/start queue" for ToS application.
++3. Add Showtime margin retrain based on EOC message.
++4. Add EOC vendor ID customalization logic for Annex B.
++5. Supports D3 datapump.
++
++Version 04.01.00.00
++-------------------
++Re-release of 04.00.07.00 for D1.1 datapump.
++
++Version 04.00.07.00
++-------------------
++Features:
++1. Add marging retrain capability by setting following Adam2 Env.
++ setenv enable_margin_retrain 1
++ setenv margin_threshold xx, xx is in half db, i.e., 10 means 5db.
++
++Bugfixs:
++1. New PDSP firmware that fix the F5 OAM cell loopback probelm in Cisco DSLAM.
++
++Version 04.00.06.00
++-------------------
++1. ATM interrupt pacing is defauted to 2 interrupts/s.
++2. Rx Service MAX changed ftom 16 to 8.
++
++Version 04.00.05.00
++-------------------
++Features:
++1. Add Adam2 env to disable the TurboDSL by entering "setenv TurboDSL 0".
++2. Add ability to set interrupt pacing for ATM driver.
++
++Bugfixs:
++1. Fixed the RFC2684 and CLIP problems for Cisco router.
++2. Fixed LED blinking problem when DSL cable is unplugged.
++3. Fixed problem that "selected mode" is not updated.
++
++Version 04.00.04.00
++-------------------
++Features:
++1. Added feature so OAM F5 ping will not require a corresponding PVC channel to
++ be setup.
++2. Added timeout value for F5 OAM ping. The new command are "exxxpyyycdzzzt" for
++ end-to-end and "sxxxpyyycdzzzt" for segment. "zzz" is timeout value in milli-second.
++3. Added proc entry "avsar_pvc_table" to record received VPIs and VCIs. The format is
++ vpi,vci
++ seperated by new line. To search for PVCs, an application can do the following.
++ i) Send a (or several) F5 OAM cell on a VPI/VPI pairs with command
++ echo exxxpyyycd2t > /proc/sys/dev/dslmod
++ ii) Wait >2ms or poll proc entry /proc/avalanche/avsar_oam_ping until the result
++ indicates a failure. (It will be failed all the time with 2ms timeout.)
++ iii) Repeat above two steps for new VPI/VCI pairs.
++ iv) Check proc entry /proc/avalanche/avsar_pvc_table any time for PVCs that responded.
++
++Version 04.00.03.00
++-------------------
++Bug Fixs:
++1. Fixed bug that caused crash when phone cable is unplugged.
++2. Fixed LED operation for "flexible LEDs".
++
++Features:
++1. Added the proc entry "avsar_oam_ping" to signal oam ping result.
++ 0 - failed; 1 - success; 2 - in progress.
++2. Added oam ping timeout env variable. The timeout can be specified by
++ adding Adam2 env "oam_lb_timeout". The value is in millisecond.
++
++Version 04.00.02.00
++-------------------
++1. The driver uses hardware queue for Turbo DSL.
++2. Added new modem statistics listed below:
++ US and DS TX powers, atuc Vendor ID and revision, training mode selected,
++ Hybrid Selected, and etc.
++
++Version 04.00.01.00
++-------------------
++
++1. This driver release contains all the features that exists in AR5 Linux ATM
++ 3.1 driver.
++
++2. F4 OAM generation is added.
++
++3. Software queuing is used for TURBO DSL.
++
++4. Porting guide "is created. Please look into that document for detailed
++ information.
++
++
+diff -urN linux.old/drivers/atm/sangam_atm/syssw_version.h linux.dev/drivers/atm/sangam_atm/syssw_version.h
+--- linux.old/drivers/atm/sangam_atm/syssw_version.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/syssw_version.h 2005-08-23 04:46:50.105842480 +0200
+@@ -0,0 +1,94 @@
++#ifndef __SYSSW_VERSION_H__
++#define __SYSSW_VERSION_H__ 1
++
++/*******************************************************************************
++* FILE PURPOSE: DSL Driver API functions for Sangam
++*
++********************************************************************************
++* FILE NAME: dsl_hal_basicapi.c
++*
++* DESCRIPTION:
++* Contains basic DSL HAL APIs for Sangam
++*
++* (C) Copyright 2003-04, Texas Instruments, Inc.
++* History
++* Date Version Notes
++* 14May03 0.00.00 RamP Original Version Created
++* 14May03 0.00.01 RamP Initial Rev numbers inserted
++* 14May03 0.00.02 RamP Bumped version numbers for Dsl Hal
++* & dhalapp for alpha plus
++* 19May03 0.00.03 MCB Bumped dslhal version number
++* because of dependant changes
++* wrt. linux-nsp atm drivers.
++* 22May03 0.00.04 RamP Bumped dslhal & dhalapp buildnum
++* for inner/outer pair & DGASP code
++* 06Jun03 0.00.05 RamP Bumped up buildnum for LED, STM,
++* interrupt processing, statistics
++* and other pre-beta features
++* 09Jun03 0.00.06 JEB Fixed error in DHALAPP bugfix/buildnum
++* 09Jun03 0.00.07 RamP Bumped up buildnum for incremental
++* changes to apis, statistics, memory
++* fixes, parameter configurations
++* 11Jun03 0.00.08 RamP Bumped up buildnum for Co profile
++* free memory fix
++* 12Jun03 0.00.09 JEB Bumped version numbers for AR7 1.00 Beta
++* 02Jul03 0.00.10 ZT Bumped HAL version for overlay page
++* 18Jul03 0.00.11 RamP Bumped HAL version for analog diags
++* 22Jul03 0.00.12 JEB Bumped DHALAPP buildnum for analog diags
++* 31Jul03 0.00.13 RamP Bumped HAL version for engr. drop
++* 04Aug03 0.00.14 JEB Bumped HAL version buildnum for CHECKPOINT65 changes
++* Bumped LINUX version buildnum for CHECKPOINT65 changes
++* 06Aug03 0.00.15 MCB Bumped all version numbers in prep for AR7 1.0 R2 release for POTS.
++* 13Aug03 0.00.16 MCB Set rev id's for D3/R1.1 (ADSL2).
++* 21Aug03 0.00.17 JEB Bumped up build numbers for merge of code additions from D1
++* 26Sep03 0.00.18 JEB Set rev id's for another D3/R1 (ADSL2).
++* 14Oct03 0.00.19 JEB Bumped Linux minor number and reset bugfix number for release.
++* Bumped build numbers on DSLHAL and DHALAPP for this checkpoint.
++* 14Oct03 0.00.20 JEB Bumped build numbers on DSLHAL and DHALAPP for CHECKPOINT15.
++* 21Oct03 0.00.21 JEB Bumped build number on DSLHAL for CHECKPOINT16.
++* 22Oct03 0.00.22 MCB Bumped all version numbers in support of D3R1 release.
++* 27Oct03 0.00.23 JEB Bumped build numbers on DSLHAL and DHALAPP for CHECKPOINT19.
++* Updated version for DSLAGENT to be 02.01.00.01 for ACT 2.1 R0.
++* 30Oct03 0.00.24 JEB Bumped bugfix number on LINUXATM Version for next release.
++* Bumped build numbers on DSLHAL and DHALAPP
++* 31Oct03 0.00.25 MCB Bumped all version numbers in support of D3R2 release.
++* 14Nov03 0.00.26 JEB Bumped build numbers on DSLHAL and DHALAPP
++* Changed version for DSLAGENT to be 02.00.01.01 for an ACT 2.0 R0
++* 20Nov03 0.00.27 JEB Bumped build number on DSLHAL.
++* Changed version for DSLAGENT to be 02.00.02.00 for the next ACT 2.0 R2
++* 21Nov03 0.00.28 MCB Bumped all version numbers in support of D3R2 release.
++* 21Nov03 0.00.29 JEB Bumped build numbers on DSLHAL and DHALAPP for D3-R0 drop on 11/21.
++* 16Dec03 0.00.30 JEB Bumped build numbers on DSLHAL and DHALAPP for CHECKPOINT31.
++* 21Dec03 0.00.31 MCB Bumped all version numbers in support of D3R2 release.
++* 05Jan04 0.00.32 JEB Bumped build numbers on DSLHAL and Linux ATM for CHECKPOINT 34.
++* 15Jan04 0.00.33 JEB Bumped build numbers on DSLHAL and Linux ATM for CHECKPOINT 36.
++* 26Jan04 0.00.34 JEB Changed Linux ATM version number to be 04.02.03.00.
++* 27Jan04 0.00.35 MCB Bumped all version numbers in support of D3R2 release.
++*******************************************************************************/
++
++/* Dsl Hal API Version Numbers */
++#define DSLHAL_VERSION_MAJOR 03
++#define DSLHAL_VERSION_MINOR 00
++#define DSLHAL_VERSION_BUGFIX 06
++#define DSLHAL_VERSION_BUILDNUM 00
++#define DSLHAL_VERSION_TIMESTAMP 00
++
++/* dhalapp Adam2 Application Version Numbers */
++#define DHALAPP_VERSION_MAJOR 03
++#define DHALAPP_VERSION_MINOR 00
++#define DHALAPP_VERSION_BUGFIX 05
++#define DHALAPP_VERSION_BUILDNUM 00
++
++/* Linux ATM Driver Version Numbers */
++#define LINUXATM_VERSION_MAJOR 04
++#define LINUXATM_VERSION_MINOR 02
++#define LINUXATM_VERSION_BUGFIX 04
++#define LINUXATM_VERSION_BUILDNUM 00
++
++/* DSL Agent Version Numbers */
++#define DSLAGENT_VERSION_MAJOR 02
++#define DSLAGENT_VERSION_MINOR 00
++#define DSLAGENT_VERSION_BUGFIX 02
++#define DSLAGENT_VERSION_BUILDNUM 00
++
++#endif /* pairs with #ifndef __SYSSW_VERSION_H__ */
+diff -urN linux.old/drivers/atm/sangam_atm/tn7api.h linux.dev/drivers/atm/sangam_atm/tn7api.h
+--- linux.old/drivers/atm/sangam_atm/tn7api.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/tn7api.h 2005-08-23 04:46:50.105842480 +0200
+@@ -0,0 +1,54 @@
++/*
++ * Tnetd73xx ATM driver.
++ * by Zhicheng Tang, ztang@ti.com
++ * 2000 (c) Texas Instruments Inc.
++ *
++ *
++*/
++
++#ifndef __SAPI_H
++#define __SAPI_H
++
++/* tn7atm.c */
++void xdump(unsigned char *buff, int len, int debugLev);
++int tn7atm_receive(void *os_dev, int ch, unsigned int packet_size, void *os_receive_info, void *data);
++void *tn7atm_allocate_rx_skb(void *os_dev, void **os_receive_info, unsigned int size);
++void tn7atm_free_rx_skb(void *skb);
++void tn7atm_sarhal_isr_register(void *os_dev, void *hal_isr, int interrupt_num);
++int tn7atm_send_complete(void *osSendInfo);
++int tn7atm_device_connect_status(void *priv, int state);
++int tn7atm_lut_find(short vpi, int vci);
++
++/* tn7dsl.h */
++void tn7dsl_exit(void);
++int tn7dsl_init(void *priv);
++int tn7dsl_proc_stats(char* buf, char **start, off_t offset, int count,int *eof, void *data);
++int tn7dsl_proc_modem(char* buf, char **start, off_t offset, int count,int *eof, void *data);
++int tn7dsl_handle_interrupt(void);
++void dprintf( int uDbgLevel, char * szFmt, ...);
++void tn7dsl_dslmod_sysctl_register(void);
++void tn7dsl_dslmod_sysctl_unregister(void);
++int tn7dsl_get_dslhal_version(char *pVer);
++int tn7dsl_get_dsp_version(char *pVer);
++
++int os_atoi(const char *pStr);
++int os_atoh(const char *pStr);
++unsigned long os_atoul(const char *pStr);
++
++/* tn7sar.c */
++int tn7sar_activate_vc(Tn7AtmPrivate *priv, short vpi, int vci, int pcr, int scr, int mbs, int cdvt, int chan, int qos);
++int tn7sar_init(struct atm_dev *dev, Tn7AtmPrivate *priv);
++int tn7sar_register_interrupt_handle(void *os_dev, void *hal_isr, int *interrupt_num);
++void tn7sar_exit(struct atm_dev *dev, Tn7AtmPrivate *priv);
++int tn7sar_deactivate_vc(Tn7AtmPrivate *priv, int chan);
++int tn7sar_handle_interrupt(struct atm_dev *dev, Tn7AtmPrivate *priv);
++int tn7sar_send_packet(Tn7AtmPrivate *priv, int chan, void *new_skb, void *data,unsigned int len, int priority);
++void tn7sar_get_sar_version(Tn7AtmPrivate *priv, char **pVer);
++int tn7sar_get_near_end_loopback_count(unsigned int *pF4count, unsigned int *pF5count);
++int tn7sar_oam_generation(void *privContext, int chan, int type, int vpi, int vci, int timeout);
++int tn7sar_get_stats(void *priv1);
++int tn7sar_proc_sar_stat(char* buf, char **start, off_t offset, int count,int *eof, void *data);
++void tn7sar_get_sar_firmware_version(unsigned int *pdsp_version_ms, unsigned int *pdsp_version_ls);
++int tn7sar_proc_oam_ping(char* buf, char **start, off_t offset, int count,int *eof, void *data);
++int tn7sar_proc_pvc_table(char* buf, char **start, off_t offset, int count,int *eof, void *data);
++#endif
+diff -urN linux.old/drivers/atm/sangam_atm/tn7atm.c linux.dev/drivers/atm/sangam_atm/tn7atm.c
+--- linux.old/drivers/atm/sangam_atm/tn7atm.c 2005-08-28 01:52:26.000000000 -0600
++++ linux.dev/drivers/atm/sangam_atm/tn7atm.c 2005-08-28 02:08:07.000000000 -0600
+@@ -0,0 +1,1233 @@
++/*
++ * tn7.c
++ * Linux atm module implementation.
++ * Zhicheng Tang 01/08/2003
++ * 2003 (c) Texas Instruments Inc.
++ *
++ *
++*/
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/atmdev.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/smp_lock.h>
++#include <asm/io.h>
++#include <asm/mips-boards/prom.h>
++#include <linux/proc_fs.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include "tn7atm.h"
++#include "tn7api.h"
++#include "syssw_version.h"
++
++#ifdef CONFIG_LED_MODULE
++#include <asm/ar7/ledapp.h>
++#endif
++#include <asm/ar7/avalanche_intc.h>
++
++#ifdef MODULE
++MODULE_DESCRIPTION ("Tnetd73xx ATM Device Driver");
++MODULE_AUTHOR ("Zhicheng Tang");
++#endif
++
++/* Version Information */
++//static char atm_version[] ="1.0.0.1";
++
++#define TRUE 1
++#define FALSE 0
++
++#define STOP_EMPTY_BUFF 2
++#define START_EMPTY_BUFF 3
++/* externs */
++
++/*end of externs */
++
++#define tn7atm_kfree_skb(x) dev_kfree_skb(x)
++
++/* prototypes */
++int tn7atm_open (struct atm_vcc *vcc, short vpi, int vci);
++
++void tn7atm_close (struct atm_vcc *vcc);
++
++static int tn7atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg);
++
++int tn7atm_send (struct atm_vcc *vcc, struct sk_buff *skb);
++
++static int tn7atm_change_qos (struct atm_vcc *vcc, struct atm_qos *qos,int flags);
++
++static int tn7atm_detect(void);
++static int tn7atm_init(struct atm_dev* dev);
++//static int tn7atm_reset(void);
++static int tn7atm_irq_request(struct atm_dev* dev);
++static int tn7atm_proc_version(char* buf, char **start, off_t offset, int count,int *eof, void *data);
++static void tn7atm_exit(void);
++static int tn7atm_proc_channels(char* buf, char **start, off_t offset, int count,int *eof, void *data);
++static int tn7atm_proc_private(char* buf, char **start, off_t offset, int count,int *eof,void *data);
++//static void tn7atm_free_packet(void *vcc1, void *priv, void *skb1);
++static int tn7atm_queue_packet_to_sar(void *vcc1, void *skb1);
++
++#include "turbodsl.c"
++
++/* ATM device operations */
++
++struct atm_dev *mydev;
++
++static const struct atmdev_ops tn7atm_ops = {
++ open: tn7atm_open,
++ close: tn7atm_close,
++ ioctl: tn7atm_ioctl,
++ getsockopt: NULL,
++ setsockopt: NULL,
++ send: tn7atm_send,
++ sg_send: NULL,
++ phy_put: NULL,
++ phy_get: NULL,
++ change_qos: tn7atm_change_qos,
++};
++
++
++int __guDbgLevel = 1;
++
++
++void xdump(unsigned char *buff, int len, int debugLev)
++{
++#ifdef DEBUG_BUILD
++ int i, j;
++ if( __guDbgLevel < debugLev)
++ return;
++
++ j=0;
++ for(i=0;i<len;i++)
++ {
++ printk("%02x ", buff[i]);
++ j++;
++ if(j==8)
++ {
++ j=0;
++ printk("\n");
++ }
++ }
++ printk("\n");
++#endif
++}
++
++
++#if 0 /* by nbd */
++/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * Function: int tn7atm_walk_vccs(struct atm_dev *dev, short *vcc, int *vci)
++ *
++ * Description: retrieve VPI/VCI for connection
++ *
++ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
++static int
++tn7atm_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci)
++{
++ struct atm_vcc* walk;
++
++ // printk(tn7 "tn7atm_walk_vccs\n");
++ /* find a free VPI */
++ if (*vpi == ATM_VPI_ANY) {
++
++ for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) {
++
++ if ((walk->vci == *vci) && (walk->vpi == *vpi)) {
++ (*vpi)++;
++ walk = vcc->dev->vccs;
++ }
++ }
++ }
++
++ /* find a free VCI */
++ if (*vci == ATM_VCI_ANY) {
++
++ for (*vci = ATM_NOT_RSV_VCI, walk = vcc->dev->vccs; walk; walk = walk->next) {
++
++ if ((walk->vpi = *vpi) && (walk->vci == *vci)) {
++ *vci = walk->vci + 1;
++ walk = vcc->dev->vccs;
++ }
++ }
++ }
++
++ return 0;
++}
++#endif
++
++
++/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * Function: int tn7atm_sar_irq(void)
++ *
++ * Description: tnetd73xx SAR interrupt.
++ *
++ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
++static void
++tn7atm_sar_irq(int irq , void *voiddev , struct pt_regs *regs)
++{
++ struct atm_dev *atmdev;
++ Tn7AtmPrivate *priv;
++
++ dprintf(6, "tn7atm_sar_irq\n");
++ atmdev = (struct atm_dev *) voiddev;
++ priv = (Tn7AtmPrivate *)atmdev->dev_data;
++
++ tn7sar_handle_interrupt(atmdev, priv);
++
++ dprintf(6, "Leaving tn7atm_sar_irq\n");
++}
++
++/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * Function: int tn7atm_dsl_irq(void)
++ *
++ * Description: tnetd73xx DSL interrupt.
++ *
++ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
++static void
++tn7atm_dsl_irq(int irq , void *voiddev , struct pt_regs *regs)
++{
++ struct atm_dev *atmdev;
++ Tn7AtmPrivate *priv;
++
++ dprintf(4, "tn7atm_dsl_irq\n");
++ atmdev = (struct atm_dev *) voiddev;
++ priv = (Tn7AtmPrivate *)atmdev->dev_data;
++
++ tn7dsl_handle_interrupt();
++
++ dprintf(4, "Leaving tn7atm_dsl_irq\n");
++}
++
++/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * Function: int tn7atm_Inittxcomp(struct tn7* tn7)
++ *
++ * Description: Initialize Interrupt handler
++ *
++ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
++static int __init
++tn7atm_irq_request (struct atm_dev *dev)
++{
++ Tn7AtmPrivate *priv;
++ char *ptr;
++ int ipace=2;
++
++ dprintf(4, "tn7atm_irq_request()\n");
++ priv = (Tn7AtmPrivate *) dev->dev_data;
++
++ /* Register SAR interrupt */
++ priv->sar_irq = LNXINTNUM(ATM_SAR_INT); /* Interrupt line # */
++ if (request_irq(priv->sar_irq, tn7atm_sar_irq, SA_INTERRUPT, "SAR ", dev))
++ printk ("Could not register tn7atm_sar_irq\n");
++
++ /* interrupt pacing */
++ ptr= prom_getenv("sar_ipacemax");
++ if(ptr)
++ {
++ ipace=os_atoi(ptr);
++ }
++ avalanche_request_pacing(priv->sar_irq, ATM_SAR_INT_PACING_BLOCK_NUM, ipace);
++
++ /* Reigster Receive interrupt A */
++ priv->dsl_irq = LNXINTNUM(ATM_DSL_INT); /* Interrupt line # */
++ if (request_irq(priv->dsl_irq, tn7atm_dsl_irq, SA_INTERRUPT, "DSL ", dev))
++ printk ("Could not register tn7atm_dsl_irq\n");
++
++ return 0;
++}
++
++/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * Function: int tn7atm_lut_find(struct atm_vcc *vcc)
++ *
++ * Description: find an TX DMA channel
++ * that matches a vpi/vci pair
++ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
++int
++tn7atm_lut_find(short vpi, int vci)
++{
++ int i;
++ Tn7AtmPrivate *priv;
++
++ priv = (Tn7AtmPrivate *)mydev->dev_data;
++
++ if(vci==0) // find first vpi channel
++ {
++ for(i=0; i< MAX_DMA_CHAN; i++)
++ {
++ if((priv->lut[i].vpi == vpi))
++ return i;
++ }
++ }
++
++ dprintf(4, "vpi=%d, vci=%d\n", vpi, vci);
++ for(i=0; i< MAX_DMA_CHAN; i++)
++ {
++ if((priv->lut[i].vpi == vpi) && (priv->lut[i].vci == vci))
++ return i;
++ }
++
++
++
++ return ATM_NO_DMA_CHAN;
++}
++
++/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * Function: int tn7atm_lut_clear(struct atm_vcc *vcc,int chan)
++ *
++ * Description: find an TX DMA channel
++ * that matches a vpi/vci pair
++ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
++static int
++tn7atm_lut_clear(struct atm_vcc *vcc, int chan)
++{
++ Tn7AtmPrivate *priv;
++
++ priv = (Tn7AtmPrivate *)vcc->dev->dev_data;
++
++ memset(&priv->lut[chan], 0, sizeof(priv->lut[chan]));
++
++ return 0;
++}
++
++/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * Function: int tn7atm_walk_lut(void)
++ *
++ * Description: find an available TX DMA channel
++ * and initialize LUT
++ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
++static int
++tn7atm_walk_lut(Tn7AtmPrivate *priv)
++{
++ int i;
++
++ for(i=0; i< MAX_DMA_CHAN; i++){
++ if(!priv->lut[i].inuse)
++ {
++ return i; /* return available dma channel number */
++ }
++ }
++ return ATM_NO_DMA_CHAN; /* no tx dma channels available */
++}
++
++static int
++tn7atm_set_lut(Tn7AtmPrivate *priv, struct atm_vcc *vcc, int chan)
++{
++
++ if(!priv->lut[chan].inuse)
++ {
++ priv->lut[chan].vpi = (int)vcc->vpi;
++ priv->lut[chan].vci = vcc->vci;
++ priv->lut[chan].chanid = chan;
++ priv->lut[chan].inuse = 1; /* claim the channel */
++ priv->lut[chan].vcc = (void *)vcc;
++ priv->lut[chan].bClosing = 0;
++ priv->lut[chan].ready = 0;
++ priv->lut[chan].tx_total_bufs = TX_BUFFER_NUM;
++ priv->lut[chan].tx_used_bufs[0] = 0;
++ priv->lut[chan].tx_used_bufs[1] = 0;
++ return 0;
++ }
++ return -1; /* no tx dma channels available */
++}
++
++#if 0
++static void tn7atm_free_packet(void *pVc, void *pDev, void *pPacket)
++ {
++ Tn7AtmPrivate *priv;
++ struct atm_vcc *vcc;
++ struct sk_buff *skb;
++
++ vcc = (struct atm_vcc *)pVc;
++ priv = (Tn7AtmPrivate *)pDev;
++ skb = (struct sk_buff *) pPacket;
++
++ if(vcc->pop)
++ vcc->pop(vcc, skb);
++ else
++ tn7atm_kfree_skb(skb);
++ }
++#endif
++
++static void str2eaddr(char *pMac, char *pStr)
++{
++ char tmp[3];
++ int i;
++
++ for(i=0;i<6;i++)
++ {
++ tmp[0]=pStr[i*3];
++ tmp[1]=pStr[i*3+1];
++ tmp[2]=0;
++ pMac[i]=os_atoh(tmp);
++ }
++}
++
++static int __init
++tn7atm_get_ESI(struct atm_dev *dev)
++{
++ int i;
++ char esi_addr[ESI_LEN]={0x00,0x00,0x11,0x22,0x33,0x44};
++ char *esiaddr_str = NULL;
++
++ esiaddr_str = prom_getenv("macc");
++
++ if (!esiaddr_str) {
++ //printk("macc address not set in adam2 environment space\n");
++ //printk("Using default macc address = 00:01:02:03:04:05\n");
++ esiaddr_str = "00:00:02:03:04:05";
++ }
++ str2eaddr(esi_addr, esiaddr_str);
++
++ for(i=0; i < ESI_LEN; i++)
++ dev->esi[i] = esi_addr[i];
++
++ return 0;
++}
++
++/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * Function: int tn7atm_open(struct atm_vcc *vcc, short vpi, int vci)
++ *
++ * Description: Device operation: open
++ *
++ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
++//static int
++int tn7atm_open (struct atm_vcc *vcc, short vpi, int vci)
++{
++ Tn7AtmPrivate *priv;
++ int dmachan;
++ int rc;
++ int traffic_type;
++ int pcr = 0x20000;
++ int scr = 0x20000;
++ int mbs = 0x20000;
++ int cdvt = 10000;
++ int err;
++
++ dprintf(1, "tn7atm_open()\n");
++
++ priv = (Tn7AtmPrivate *)vcc->dev->dev_data;
++ if(priv==NULL)
++ {
++ printk("null priv\n");
++ return -1;
++ }
++
++ MOD_INC_USE_COUNT;
++
++#if 0 /* by nbd */
++ /* find a free VPI/VCI */
++ tn7atm_walk_vccs(vcc, &vpi, &vci);
++#else
++ if ((err = atm_find_ci(vcc, &vpi, &vci))) {
++ printk("atm_find_ci err = %d\n", err);
++ return err;
++ }
++
++#endif
++
++ vcc->vpi = vpi;
++ vcc->vci = vci;
++
++ if (vci == ATM_VCI_UNSPEC || vpi == ATM_VCI_UNSPEC)
++ {
++ MOD_DEC_USE_COUNT;
++ return -EBUSY;
++ }
++
++ /* check to see whether PVC is opened or not */
++ if((dmachan = tn7atm_lut_find(vcc->vpi, vcc->vci)) != ATM_NO_DMA_CHAN)
++ {
++ MOD_DEC_USE_COUNT;
++ printk("PVC already opened. dmachan = %d\n", dmachan);
++ return -EBUSY;
++ }
++ /*check for available channel */
++ if((dmachan = tn7atm_walk_lut(priv)) == ATM_NO_DMA_CHAN)
++ {
++ printk("No TX DMA channels available\n");
++ return -EBUSY;
++ }
++
++ set_bit(ATM_VF_ADDR, &vcc->flags); /* claim address */
++
++ vcc->itf = vcc->dev->number; /* interface number */
++
++ switch(vcc->qos.txtp.traffic_class)
++ {
++ case ATM_CBR: /* Constant Bit Rate */
++ traffic_type = 0;
++ pcr = vcc->qos.txtp.pcr;
++ scr = vcc->qos.txtp.pcr;
++ cdvt = vcc->qos.txtp.max_cdv;
++ printk("cdvt=%d\n", cdvt);
++ break;
++ case ATM_UBR: /* Unspecified Bit Rate */
++ traffic_type = 2;
++ break;
++
++ /* Disable ATM_VBR until pppd ppoatm plugin supports it.
++ * NOTE: Support ATM_VBR requires the addition of a scr
++ * field to the atm_trafprm structure which will cause
++ * a change in the SO_ATMQOS ioctl. Make sure that the
++ * revised header file becomes visible to the pppd
++ * pppoatm plugin source, or the SO_ATMQOS ioctl will fail.
++ */
++#if 0
++ case ATM_VBR: /* Variable Bit Rate */
++ traffic_type = 1;
++ pcr = vcc->qos.txtp.pcr;
++ scr = vcc->qos.txtp.scr;
++ if(vcc->qos.txtp.max_pcr >= 0)
++ mbs = vcc->qos.txtp.max_pcr;
++ cdvt = vcc->qos.txtp.max_cdv;
++ printk("cdvt=%d\n", cdvt);
++ printk("mbs=%d\n", mbs);
++ break;
++#endif
++ default:
++ traffic_type = 2;
++ }
++
++ dprintf(4, "vpi=%d, vci=%d, pcr=%d, dmachan=%d, qos=%d\n", vpi,vci,pcr,dmachan,traffic_type);
++ /* Activate SAR channel */
++ rc = tn7sar_activate_vc(priv, vpi, vci, pcr, scr, mbs, cdvt, dmachan, traffic_type);
++ if(rc < 0)
++ {
++
++ MOD_DEC_USE_COUNT;
++ return -EBUSY;
++ }
++
++ /* insure that the the vcc struct points to the correct entry
++ in the lookup table */
++
++ tn7atm_set_lut(priv,vcc, dmachan);
++ vcc->dev_data = (void *)&priv->lut[dmachan];
++ set_bit(ATM_VF_READY, &vcc->flags);
++
++ mdelay(100);
++ priv->lut[dmachan].ready = 1;
++ dprintf (1, "Leave tn7atm_open\n");
++ return 0;
++}
++
++
++//static void
++void tn7atm_close (struct atm_vcc *vcc)
++{
++ Tn7AtmPrivate *priv;
++ int dmachan;
++
++ priv = (Tn7AtmPrivate *)vcc->dev->dev_data;
++ dprintf(4, "closing %d.%d.%d.%d\n", vcc->itf, vcc->vpi, vcc->vci, vcc->qos.aal);
++
++ clear_bit(ATM_VF_READY, &vcc->flags); /* ATM_VF_READY: channel is ready to transfer data */
++
++ dmachan = tn7atm_lut_find(vcc->vpi, vcc->vci);
++ printk("closing channel: %d\n", dmachan);
++ if(dmachan == ATM_NO_DMA_CHAN)
++ {
++ printk("Closing channel not found.\n");
++ return;
++ }
++ priv->lut[dmachan].bClosing = 1;
++ priv->lut[dmachan].ready = 0;
++ if(tn7sar_deactivate_vc(priv,dmachan)) /* tear down channel */
++ {
++ printk("failed to close channel %d.\n", dmachan);
++ }
++
++ clear_bit(ATM_VF_READY, &vcc->flags); /* ATM_VF_READY: channel is ready to transfer data */
++ tn7atm_lut_clear(vcc, dmachan);
++
++ MOD_DEC_USE_COUNT;
++
++ dprintf (1, "Leave tn7atm_close\n");
++}
++
++#define ATM_TXSTOP 0x800c61f4
++static int
++tn7atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg)
++{
++ Tn7AtmPrivate *priv;
++ priv = (Tn7AtmPrivate *) dev->dev_data;
++
++ //printk("tn7atm_ioctl\n");
++ //printk("arg = %x\n", *(int *)arg);
++ //printk("cmd =%x\n", cmd);
++ switch(cmd)
++ {
++
++ case ATM_TXSTOP: /*temp fix for SAR tear down problem */
++// printk("ioctl cmd = 0x%x (%u), arg = 0x%p (%lu)\n", cmd, cmd, arg, (unsigned long)arg);
++// printk("arg = %d\n", *(int*)arg);
++ priv->xmitStop = *(int *)arg;
++ //printk("Executing ATM_SETLOOP for tn7 \n");
++ //printk("Stop variable = :%d: \n",priv->xmitStop);
++ return 0;
++
++ //case SAR_DSL_RESET_SOFTBOOT:
++ // return tn7atm_dsl_clean_reboot();
++ case 0:
++ return 0;
++ }
++
++ return -ENOSYS;
++
++}
++
++static int
++tn7atm_change_qos (struct atm_vcc *vcc, struct atm_qos *qos,int flags)
++{
++ dprintf (1, "Enter tn7atm_change_qos\n");
++ dprintf (1, "Leave tn7atm_change_qos\n");
++ return 0;
++}
++
++
++int tn7atm_send (struct atm_vcc *vcc, struct sk_buff *skb)
++{
++
++ Tn7AtmPrivate *priv;
++ int bret;
++ int chan;
++
++ dprintf(4, "tn7atm_send()\n");
++
++ priv = (Tn7AtmPrivate*)vcc->dev->dev_data;
++
++ //if(skb->len < 64)
++ //xdump((unsigned char *)skb->data, skb->len, 1);
++ //else
++ //xdump((unsigned char *)skb->data, 64, 1);
++ /* check for dsl line connection */
++
++ /* add vcc field in skb for clip inATMARP fix */
++ ATM_SKB(skb)->vcc = vcc;
++ /* Ron change 2.3 -> 2.4 ??*/
++ //if(priv->lConnected != 1 || priv->xmitStop == 1)
++ if(priv->lConnected != 1 && priv->xmitStop == 1)
++ {
++ dprintf(4,"dsl line down\n");
++ if(vcc->pop)
++ vcc->pop(vcc, skb);
++ else
++ tn7atm_kfree_skb(skb);
++ return 1;
++ }
++
++ /* check whether PVC is closing */
++ chan = tn7atm_lut_find(vcc->vpi, vcc->vci);
++ /* set br2684 dev pointer */
++ priv->lut[chan].net_device = skb->dev;
++ if(chan == ATM_NO_DMA_CHAN || priv->lut[chan].bClosing == 1)
++ {
++ dprintf(4, "can find sar channel\n");
++ if(vcc->pop)
++ vcc->pop(vcc, skb);
++ else
++ tn7atm_kfree_skb(skb);
++ return 1;
++ }
++
++ bret=tn7atm_queue_packet_to_sar(vcc, skb);
++
++ return bret;
++}
++
++
++static int tn7atm_queue_packet_to_sar(void *vcc1, void *skb1)
++{
++ struct atm_vcc *vcc;
++ struct sk_buff *skb;
++ int priority = 1;
++ Tn7AtmPrivate *priv;
++ int dmachan;
++
++ vcc = (struct atm_vcc *)vcc1;
++ skb = (struct sk_buff *)skb1;
++
++ priv = (Tn7AtmPrivate*)vcc->dev->dev_data;
++
++ dprintf(4, "vcc->vci=%d\n", vcc->vci);
++ dmachan = tn7atm_lut_find(vcc->vpi, vcc->vci);
++ if(dmachan == ATM_NO_DMA_CHAN)
++ {
++ dprintf(4, "can find sar channel\n");
++ if(vcc->pop)
++ vcc->pop(vcc, skb);
++ else
++ tn7atm_kfree_skb(skb);
++ return 1;
++ }
++
++ // turbo dsl TCP ack check
++ if(priv->bTurboDsl)
++ priority = turbodsl_check_priority_type(skb->data);
++
++ //skb priority check
++ if(priority != 0)
++ {
++ if((skb->cb[47])>>1)
++ priority=1;
++ else
++ priority = 0;
++ }
++
++ /* add queue info here */
++ skb->cb[47] = (char)priority;
++ spin_lock_irqsave(&priv->netifqueueLock, priv->netifqueueLockFlag);
++ priv->lut[dmachan].tx_used_bufs[priority]++;
++ spin_unlock_irqrestore(&priv->netifqueueLock, priv->netifqueueLockFlag);
++
++ if(tn7sar_send_packet(priv,dmachan, skb, skb->data, skb->len, priority) != 0)
++ {
++ dprintf(1, "failed to send packet\n");
++ if(vcc->pop)
++ vcc->pop(vcc, skb);
++ else
++ tn7atm_kfree_skb(skb);
++
++ spin_lock_irqsave(&priv->netifqueueLock, priv->netifqueueLockFlag);
++ priv->lut[dmachan].tx_used_bufs[priority]--;
++ spin_unlock_irqrestore(&priv->netifqueueLock, priv->netifqueueLockFlag);
++ return 1;
++ }
++
++ /* check for whether tx queue is full or not */
++ //printk("bufs used = %d\n", priv->lut[dmachan].tx_used_bufs[1]);
++ spin_lock_irqsave(&priv->netifqueueLock, priv->netifqueueLockFlag);
++ if(priv->lut[dmachan].tx_used_bufs[1] >= (priv->lut[dmachan].tx_total_bufs - STOP_EMPTY_BUFF) ||
++ priv->lut[dmachan].tx_used_bufs[0] >= (priv->lut[dmachan].tx_total_bufs - STOP_EMPTY_BUFF))
++ {
++ //printk("net queue stoped\n");
++ netif_stop_queue(priv->lut[dmachan].net_device);
++ priv->lut[dmachan].netqueue_stop = 1;
++ }
++ spin_unlock_irqrestore(&priv->netifqueueLock, priv->netifqueueLockFlag);
++
++ return 0;
++}
++
++/* functions needed by SAR HAL */
++
++int tn7atm_send_complete(void *osSendInfo)
++{
++ Tn7AtmPrivate *priv;
++ //struct atm_dev *dev;
++ struct sk_buff *skb;
++ struct atm_vcc *vcc;
++ int chan;
++
++ dprintf(4, "tn7atm_send_complete()\n");
++
++
++ skb = (struct sk_buff *)osSendInfo;
++ //dev = (struct atm_dev *) (skb->dev);
++ priv = (Tn7AtmPrivate *)mydev->dev_data;
++ vcc =ATM_SKB(skb)->vcc;
++ if(vcc)
++ {
++ dprintf(4, "vcc->vci=%d\n",vcc->vci );
++ chan = tn7atm_lut_find(vcc->vpi, vcc->vci);
++ if(chan==ATM_NO_DMA_CHAN)
++ return 1;
++
++ /*decreament packet queued number */
++ spin_lock_irqsave(&priv->netifqueueLock, priv->netifqueueLockFlag);
++ priv->lut[chan].tx_used_bufs[(int)skb->cb[47]] --;
++ if(priv->lut[chan].tx_used_bufs[1] < priv->lut[chan].tx_total_bufs - START_EMPTY_BUFF &&
++ priv->lut[chan].tx_used_bufs[0] < priv->lut[chan].tx_total_bufs - START_EMPTY_BUFF)
++ {
++ if(priv->lut[chan].netqueue_stop)
++ {
++ //printk("net queue restarted\n");
++ netif_wake_queue(priv->lut[chan].net_device);
++ priv->lut[chan].netqueue_stop = 0;
++ }
++ }
++ spin_unlock_irqrestore(&priv->netifqueueLock, priv->netifqueueLockFlag);
++
++ if(vcc->pop)
++ {
++ dprintf(5, "free packet\n");
++ vcc->pop(vcc, skb);
++ }
++
++
++ }
++
++
++
++ /* Update Stats: There may be a better place to do this, but this is a start */
++ priv->stats.tx_packets++;
++#ifdef CONFIG_LED_MODULE
++// led_operation(MOD_ADSL, DEF_ADSL_ACTIVITY);
++#endif
++
++ /* track number of buffer used */
++
++ dprintf(4, "tn7atm_send_complete() done\n");
++
++ return 0;
++}
++
++void *tn7atm_allocate_rx_skb(void *os_dev, void **os_receive_info, unsigned int size)
++{
++ struct sk_buff *skb;
++ dprintf(4, "tn7atm_allocate_rx_skb size=%d\n", size);
++ size = ((size+3)&0xfffffffc);
++ skb = dev_alloc_skb(size);
++ if(skb==NULL)
++ {
++ //printk("rx allocate skb failed\n");
++ return NULL;
++ }
++ *os_receive_info = (void *)skb;
++ return (skb->data);
++}
++
++void tn7atm_free_rx_skb(void *skb)
++{
++ dprintf(4, "tn7atm_free_rx_skb\n");
++ tn7atm_kfree_skb((struct sk_buff *)skb);
++}
++
++
++int tn7atm_receive(void *os_dev, int ch, unsigned int packet_size, void *os_receive_info, void *data)
++{
++ Tn7AtmPrivate *priv;
++ struct atm_dev *dev;
++ struct sk_buff *skb;
++ struct atm_vcc *vcc;
++
++
++ dprintf(4, "tn7atm_receive()\n");
++ dev = (struct atm_dev *)os_dev;
++
++ priv = (Tn7AtmPrivate *)dev->dev_data;
++
++ if(priv->lConnected != 1 || priv->lut[ch].ready == 0)
++ {
++ //printk("channel not ready\n");
++ return 1;
++ }
++
++ vcc = (struct atm_vcc *)priv->lut[ch].vcc;
++ if(vcc == NULL)
++ {
++ printk("vcc=Null");
++ return 1;
++ }
++
++
++ /* assume no fragment packet for now */
++ skb = (struct sk_buff *)os_receive_info;
++
++ if(skb==NULL)
++ {
++ dprintf(1, "received empty skb.\n");
++ return 1;
++ }
++ /* see skbuff->cb definition in include/linux/skbuff.h */
++ ATM_SKB(skb)->vcc = vcc;
++
++ skb->len = packet_size;
++ dprintf(3, "skb:[0x%p]:0x%x pdu_len: 0x%04x\n",skb,skb->len,packet_size);
++ dprintf(3, "data location: 0x%x, 0x%x\n", (unsigned int)skb->data, (unsigned int)data);
++
++ /*skb_trim(skb,skb->len); */ /* skb size is incorrect for large packets > 1428 bytes ?? */
++ __skb_trim(skb,skb->len); /* change to correct > 1500 ping when firewall is on */
++
++ dprintf(3, "pushing the skb...\n");
++ skb->stamp = xtime;
++
++ xdump((unsigned char *)skb->data, skb->len, 5);
++
++ if(atm_charge(vcc, skb->truesize) == 0)
++ {
++ dprintf(1,"Receive buffers saturated for %d.%d.%d - PDU dropped\n", vcc->itf, vcc->vci, vcc->vpi);
++ return 1;
++ }
++
++ /*pass it up to kernel networking layer and update stats*/
++ vcc->push(vcc,skb);
++
++ /* Update receive packet stats */
++ priv->stats.rx_packets++;
++ atomic_inc(&vcc->stats->rx);
++
++#ifdef CONFIG_LED_MODULE
++// led_operation(MOD_ADSL, DEF_ADSL_ACTIVITY);
++#endif
++ dprintf(3, "(a) Receiving:vpi/vci[%d/%d] chan_id: %d skb len:0x%x skb truesize:0x%x\n",
++ vcc->vpi,vcc->vci,ch,skb->len, skb->truesize);
++
++ return 0;
++}
++
++static int
++tn7atm_proc_channels(char* buf, char **start, off_t offset, int count,int *eof, void *data)
++{
++ int len = 0;
++ int limit = count - 80;
++ int i;
++
++ struct atm_dev *dev;
++ Tn7AtmPrivate *priv;
++
++ dev = (struct atm_dev *)data;
++ priv = (Tn7AtmPrivate *)dev->dev_data;
++
++ if(len<=limit)
++ len += sprintf(buf+len,"Chan Inuse ChanID VPI VCI \n");
++ if(len<=limit)
++ len += sprintf(buf+len,"------------------------------------------------------------------\n");
++
++ for(i=0; i < MAX_DMA_CHAN; i++)
++ {
++ if(len<=limit)
++ {
++ len += sprintf(buf+len,
++ " %02d %05d %05d %05d %05d \n",
++ i,priv->lut[i].inuse,priv->lut[i].chanid,
++ priv->lut[i].vpi,priv->lut[i].vci);
++ }
++ }
++
++ return len;
++}
++
++static int
++tn7atm_proc_private(char* buf, char **start, off_t offset, int count,int *eof, void *data)
++{
++ int len = 0;
++ int limit = count - 80;
++ struct atm_dev *dev;
++ Tn7AtmPrivate *priv;
++
++ dev = (struct atm_dev *)data;
++ priv = (Tn7AtmPrivate *)dev->dev_data;
++
++ if(len<=limit)
++ len += sprintf(buf+len, "\nPrivate Data Structure(%s):\n",priv->name);
++ if(len<=limit)
++ len += sprintf(buf+len, "----------------------------------------\n");
++ if(len<=limit)
++ len += sprintf(buf+len, "priv: 0x%p\n",priv);
++ if(len<=limit)
++ len += sprintf(buf+len, "next: 0x%p",priv->next);
++ if(len<=limit)
++ len += sprintf(buf+len, "\tdev: 0x%p\n",priv->dev);
++
++ if(len<=limit)
++ len += sprintf(buf+len, "tx_irq: %02d",priv->sar_irq);
++ if(len<=limit)
++ len += sprintf(buf+len, "rx_irq: %02d",priv->dsl_irq);
++
++
++ return len;
++}
++
++void tn7atm_sarhal_isr_register(void *os_dev, void *hal_isr, int interrupt_num)
++{
++ struct atm_dev *dev;
++ Tn7AtmPrivate *priv;
++
++ dprintf(4, "tn7atm_sarhal_isr_register()\n");
++
++ dev = (struct atm_dev *)os_dev;
++ priv = (Tn7AtmPrivate *)dev->dev_data;
++ priv->halIsr = (void *)hal_isr;
++ priv->int_num = interrupt_num;
++}
++
++
++/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * Function: int tn7atm_exit(void)
++ *
++ * Description: Avalanche SAR exit function
++ *
++ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
++
++static void
++tn7atm_exit (void)
++{
++
++ struct atm_dev *dev;
++
++ Tn7AtmPrivate *priv;
++
++ dprintf(4, "tn7atm_exit()\n");
++
++ dev=mydev;
++ priv = (Tn7AtmPrivate *)dev->dev_data;
++ priv->lConnected = 0;
++ tn7dsl_exit();
++
++ tn7sar_exit(dev, priv);
++
++ /* freeup irq's */
++ free_irq(priv->dsl_irq,priv->dev);
++ free_irq(priv->sar_irq,priv->dev);
++
++ kfree (dev->dev_data);
++
++ // atm_dev_deregister (dev);
++ shutdown_atm_dev(dev);
++
++ /* remove proc entries */
++ remove_proc_entry("tiatm/avsar_ver",NULL);
++ remove_proc_entry("tiatm/avsar_modem_stats",NULL);
++ remove_proc_entry("tiatm/avsar_modem_training",NULL);
++ remove_proc_entry("tiatm/avsar_channels",NULL);
++ remove_proc_entry("tiatm/avsar_private",NULL);
++ remove_proc_entry("tiatm/avsar_sarhal_stats",NULL);
++ remove_proc_entry("tiatm/avsar_oam_ping",NULL);
++ remove_proc_entry("tiatm/avsar_pvc_table",NULL);
++ remove_proc_entry("tiatm",NULL);
++ tn7dsl_dslmod_sysctl_unregister();
++
++ printk ("Module Removed\n");
++
++}
++
++
++
++/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * Function: int tn7atm_registration(struct tn7* tn7)
++ *
++ * Description: ATM driver registration
++ *
++ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
++
++static int __init
++tn7atm_register (Tn7AtmPrivate * priv)
++{
++ /* allocate memory for the device */
++
++ dprintf(4,"device %s being registered\n", priv->name);
++
++ mydev = atm_dev_register (priv->proc_name, &tn7atm_ops, -1, NULL);
++
++ if (mydev == NULL)
++ {
++ printk ("atm_dev_register returning NULL\n");
++ return ATM_REG_FAILED;
++ }
++
++ printk ("registered device %s\n", priv->name);
++
++ mydev->dev_data = priv; /* setup device data in atm_dev struct */
++ priv->dev = mydev; /* setup atm_device in avalanche sar struct */
++
++ mydev->ci_range.vpi_bits = ATM_CI_MAX; /* atm supports 11 bits */
++ mydev->ci_range.vci_bits = 16; /* atm VCI max = 16 bits */
++
++
++ return ATM_REG_OK;
++}
++
++static int
++tn7atm_proc_version(char* buf, char **start, off_t offset, int count,int *eof, void *data)
++{
++ int len = 0;
++ char dslVer[8];
++ char dspVer[10];
++ char *pSarVer;
++ Tn7AtmPrivate *priv;
++ int i;
++ unsigned int pdspV1, pdspV2;
++
++ priv = mydev->dev_data;
++
++ len += sprintf(buf+len, "ATM Driver version:[%d.%02d.%02d.%02d]\n",LINUXATM_VERSION_MAJOR, LINUXATM_VERSION_MINOR,
++ LINUXATM_VERSION_BUGFIX, LINUXATM_VERSION_BUILDNUM);
++
++ tn7dsl_get_dslhal_version(dslVer);
++
++ len += sprintf(buf+len, "DSL HAL version: [%d.%02d.%02d.%02d]\n", dslVer[0], dslVer[1], dslVer[2],
++ dslVer[3]);
++ tn7dsl_get_dsp_version(dspVer);
++
++ len += sprintf(buf+len, "DSP Datapump version: [%d.%02d.%02d.%02d] ", dspVer[4], dspVer[5], dspVer[6],
++ dspVer[7]);
++ if(dspVer[8]==2) // annex B
++ len += sprintf(buf+len, "Annex B\n");
++ else if(dspVer[8]==3) //annex c
++ len += sprintf(buf+len, "Annex c\n");
++ else
++ len += sprintf(buf+len, "Annex A\n");
++
++ tn7sar_get_sar_version(priv, &pSarVer);
++
++ len += sprintf(buf+len, "SAR HAL version: [");
++ for(i=0;i<8;i++)
++ {
++ len += sprintf(buf+len, "%c", pSarVer[i+7]);
++ }
++ len += sprintf(buf+len, "]\n");
++
++ tn7sar_get_sar_firmware_version(&pdspV1, &pdspV2);
++ len += sprintf(buf+len, "PDSP Firmware version:[%01x.%02x]\n",
++ pdspV1,pdspV2);
++
++ return len;
++}
++
++/*
++static struct net_device_stats
++*tn7atm_get_stats(struct atm_dev *dev)
++{
++ Tn7AtmPrivate *priv;
++ //unsigned long flags;
++
++ //spin_lock_irqsave(&priv->stats_lock,flags);
++ priv= (Tn7AtmPrivate *)dev->dev_data;
++ //spin_unlock_irqrestore(&priv->stats_lock,flags);
++
++ return &priv->stats;
++
++}
++*/
++/* Device detection */
++
++static int __init
++tn7atm_detect (void)
++{
++ Tn7AtmPrivate *priv;
++ //static struct proc_dir_entry *proc_dir;
++
++ dprintf(4, "tn7atm_detect().\n");
++ /* Device allocated as a global static structure at top of code "mydev" */
++
++ /* Alloc priv struct */
++ priv=kmalloc(sizeof(Tn7AtmPrivate),GFP_KERNEL);
++ if(!priv)
++ {
++ printk("unable to kmalloc priv structure. Killing autoprobe.\n");
++ return -ENODEV;
++ }
++ memset(priv, 0, sizeof(Tn7AtmPrivate));
++#ifdef COMMON_NSP
++ priv->name = "TI Avalanche SAR";
++ priv->proc_name = "avsar";
++#else
++ priv->name = "TI tnetd73xx ATM Driver";
++ priv->proc_name = "tn7";
++#endif
++
++ if ((tn7atm_register (priv)) == ATM_REG_FAILED)
++ return -ENODEV;
++
++ tn7atm_init(mydev);
++
++ /* Set up proc entry for atm stats */
++ proc_mkdir("tiatm", NULL);
++ create_proc_read_entry("tiatm/avsar_modem_stats",0,NULL,tn7dsl_proc_stats,NULL);
++ create_proc_read_entry("tiatm/avsar_modem_training",0,NULL,tn7dsl_proc_modem,NULL);
++ create_proc_read_entry("tiatm/avsar_ver",0,NULL,tn7atm_proc_version,NULL);
++ create_proc_read_entry("tiatm/avsar_channels",0,NULL,tn7atm_proc_channels,mydev);
++ create_proc_read_entry("tiatm/avsar_private",0,NULL,tn7atm_proc_private,mydev);
++ create_proc_read_entry("tiatm/avsar_sarhal_stats",0,NULL,tn7sar_proc_sar_stat,mydev);
++ create_proc_read_entry("tiatm/avsar_oam_ping",0,NULL,tn7sar_proc_oam_ping,mydev);
++ create_proc_read_entry("tiatm/avsar_pvc_table",0,NULL,tn7sar_proc_pvc_table,mydev);
++
++ tn7dsl_dslmod_sysctl_register();
++
++ printk("Texas Instruments ATM driver: version:[%d.%02d.%02d.%02d]\n",LINUXATM_VERSION_MAJOR, LINUXATM_VERSION_MINOR,
++ LINUXATM_VERSION_BUGFIX, LINUXATM_VERSION_BUILDNUM);
++ return 0;
++}
++
++
++/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * Function: int tn7atm_probe(void)
++ *
++ * Description: Avalanche SAR driver probe (see net/atm/pvc.c)
++ * this is utilized when the SAR driver is built
++ * into the kernel and needs to be configured.
++ *
++ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
++int __init tn7atm_probe(void)
++{
++ tn7atm_detect();
++ return -ENODEV;
++}
++
++
++/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * Function: int tn7atm_init(struct atm_dev *dev)
++ *
++ * Description: Device Initialization
++ *
++ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
++static int __init
++tn7atm_init(struct atm_dev *dev)
++{
++ Tn7AtmPrivate *priv;
++ char *ptr;
++
++ dprintf(4, "tn7atm_init()\n");
++
++ priv = (Tn7AtmPrivate *)dev->dev_data;
++
++ if(tn7sar_init(dev, priv) != 0)
++ {
++ printk("Failed to init SAR.\n");
++ return -ENODEV;
++ }
++
++ if(tn7dsl_init(priv) < 0)
++ {
++ printk("Failed to init DSL.\n");
++ return -ENODEV;
++ }
++
++ if(tn7atm_get_ESI(dev) < 0) /* set ESI */
++ return -ENODEV;
++
++ if(tn7atm_irq_request(dev) < 0)
++ return -EBUSY;
++
++ priv->bTurboDsl = 1;
++ // read config for turbo dsl
++ ptr = prom_getenv("TurboDSL");
++ if(ptr)
++ {
++ priv->bTurboDsl = os_atoi(ptr);
++ }
++
++ return 0;
++}
++
++int tn7atm_device_connect_status(void *priv, int state)
++{
++ Tn7AtmPrivate *priv1;
++
++ dprintf(5, "tn7atm_device_connect_status()\n");
++ priv1 = (Tn7AtmPrivate *)priv;
++
++ priv1->lConnected = state;
++ dprintf(5, "priv1->lConnected=%d\n", priv1->lConnected);
++ return 0;
++}
++
++
++#ifdef MODULE
++module_init (tn7atm_detect);
++module_exit (tn7atm_exit);
++#endif /* MODULE */
+diff -urN linux.old/drivers/atm/sangam_atm/tn7atm.h linux.dev/drivers/atm/sangam_atm/tn7atm.h
+--- linux.old/drivers/atm/sangam_atm/tn7atm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/tn7atm.h 2005-08-23 04:46:50.107842176 +0200
+@@ -0,0 +1,115 @@
++/*
++ * Tnetd73xx ATM driver.
++ * by Zhicheng Tang, ztang@ti.com
++ * 2000 (c) Texas Instruments Inc.
++ *
++ *
++*/
++
++#ifndef __TN7ATM_H
++#define __TN7ATM_H
++
++//#include "mips_support.h"
++#include <linux/list.h>
++
++#define ATM_REG_OK 1
++#define ATM_REG_FAILED 0
++
++#define TX_SERVICE_MAX 32
++#define RX_SERVICE_MAX 20
++#define TX_BUFFER_NUM 64
++#define RX_BUFFER_NUM 28
++#define TX_QUEUE_NUM 2
++#define RX_BUFFER_SIZE 1582
++
++#define TX_DMA_CHAN 16 /* number of tx dma channels available */
++#define MAX_DMA_CHAN 16
++#define ATM_NO_DMA_CHAN MAX_DMA_CHAN + 1 /* no tx dma channels available */
++#define ATM_SAR_INT 15
++#define ATM_SAR_INT_PACING_BLOCK_NUM 2
++#define ATM_DSL_INT 39
++
++#define CONFIG_ATM_TN7ATM_DEBUG 0 /* Debug level (0=no mtn7s 5=verbose) */
++
++#define TN7ATM_DEV(d) ((struct tn7atm*)((d)->dev_data))
++
++
++/* Avalanche SAR state information */
++
++typedef enum tn7atm_state
++{
++ TN7ATM_STATE_REGISTER /* device registered */
++}tn7atm_state;
++
++typedef struct _sar_stat
++{
++ unsigned int txErrors;
++ unsigned int rxErrors;
++ unsigned int rxPktCnt;
++ unsigned int txPktCnt;
++ unsigned int rxBytes;
++ unsigned int txBytes;
++}sar_stat_t;
++
++/* Host based look up table to xref Channel Id's, VPI/VCI, LC, CID, packet type */
++typedef struct _tn7atm_tx_lut
++{
++ int inuse; /* is DMA channel available (1=y) */
++ int chanid; /* DMA channel ID (0-0x1f) This corresponds to the Channel ID
++ that is used in the connection config reg (TN7ATM_CONN_CONFIG) */
++ int vpi; /* Virtual path identifier */
++ int vci; /* Virtual channel identifier */
++ void *vcc;
++ int bClosing;
++ int ready;
++ void *net_device;
++ int tx_total_bufs;
++ int tx_used_bufs[2];
++ int netqueue_stop;
++}tn7atm_lut_t;
++
++/* per device data */
++
++typedef struct _tn7atm_private
++{
++ struct _tn7atm_private *next; /* next device */
++ struct atm_dev *dev; /* ATM device */
++ struct net_device_stats stats; /* Used to report Tx/Rx frames from ifconfig */
++ tn7atm_lut_t lut[MAX_DMA_CHAN]; /* Tx DMA look up table (LUT) */
++ int dsl_irq; /* ATM SAR TransmitA interrupt number */
++ int sar_irq; /* ATM SAR ReceiveA interrupt number */
++ char* name; /* device name */
++ char* proc_name; /* board name under /proc/atm */
++ unsigned int available_cell_rate; /* cell rate */
++ unsigned int connection_cell_rate; /* cell rate */
++ int lConnected;
++
++ /* Tnetd73xx CPHAL */
++ void *pSarHalDev;
++ void *pSarHalFunc;
++ void *pSarOsFunc;
++ void *halIsr;
++ int int_num;
++
++ /* turbo dsl */
++ int bTurboDsl;
++
++ /* spin lock for netifqueue */
++ spinlock_t netifqueueLock;
++ int netifqueueLockFlag;
++ int xmitStop; /* temp fix for SAR problem */
++}tn7atm_private_t, Tn7AtmPrivate;
++
++
++
++/* ATM adaptation layer id */
++typedef enum tn7atm_aal {
++ TN7ATM_AAL0 = 0,
++ TN7ATM_AAL2 = 2,
++ TN7ATM_AAL5 = 5,
++} tn7atm_aal_t;
++
++
++
++
++#endif
+diff -urN linux.old/drivers/atm/sangam_atm/tn7dsl.c linux.dev/drivers/atm/sangam_atm/tn7dsl.c
+--- linux.old/drivers/atm/sangam_atm/tn7dsl.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/tn7dsl.c 2005-08-23 04:46:50.109841872 +0200
+@@ -0,0 +1,1780 @@
++/*
++ * $Id$
++ *
++ * Avalanche SAR driver
++ *
++ * Zhicheng Tang, ztang@ti.com
++ * 2000 (c) Texas Instruments Inc.
++ *
++ *
++*/
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/atmdev.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/smp_lock.h>
++#include <asm/io.h>
++#include <asm/mips-boards/prom.h>
++#include <linux/proc_fs.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include <linux/sysctl.h>
++#include <linux/timer.h>
++#include <linux/vmalloc.h>
++#include <linux/file.h>
++#include <asm/uaccess.h>
++
++#include "tn7atm.h"
++#include "tn7api.h"
++#include "dsl_hal_api.h"
++
++#ifdef CONFIG_LED_MODULE
++#include <asm/ar7/ledapp.h>
++#define MOD_ADSL 1
++#define DEF_ADSL_IDLE 1
++#define DEF_ADSL_TRAINING 2
++#define DEF_ADSL_SYNC 3
++#define DEF_ADSL_ACTIVITY 4
++
++#define LED_NUM_1 3
++#define LED_NUM_2 4
++
++led_reg_t ledreg[2];
++
++static int led_on;
++#endif
++
++extern int __guDbgLevel;
++extern sar_stat_t sarStat;
++static int dslInSync = 0;
++static int bMarginThConfig;
++static int bMarginRetrainEnable;
++static char EOCVendorID[8]= {0xb5, 0x00, 0x54, 0x53, 0x54, 0x43, 0x00, 0x00};
++
++#define TC_SYNC 1
++#define SYNC_TIME_DELAY 500000
++
++
++#define DEV_DSLMOD 1
++#define MAX_STR_SIZE 256
++#define DSL_MOD_SIZE 256
++
++#define TRUE 1
++#define FALSE 0
++
++
++enum
++{
++ NO_MODE,
++ MULTI_MODE,
++ T1413_MODE,
++ GDMT_MODE,
++ GLITE_MODE
++};
++
++
++
++/* a structure to store all information we need
++ for our thread */
++typedef struct kthread_struct
++{
++ /* private data */
++
++ /* Linux task structure of thread */
++ struct task_struct *thread;
++ /* Task queue need to launch thread */
++ struct tq_struct tq;
++ /* function to be started as thread */
++ void (*function) (struct kthread_struct *kthread);
++ /* semaphore needed on start and creation of thread. */
++ struct semaphore startstop_sem;
++
++ /* public data */
++
++ /* queue thread is waiting on. Gets initialized by
++ init_kthread, can be used by thread itself.
++ */
++ wait_queue_head_t queue;
++ /* flag to tell thread whether to die or not.
++ When the thread receives a signal, it must check
++ the value of terminate and call exit_kthread and terminate
++ if set.
++ */
++ int terminate;
++ /* additional data to pass to kernel thread */
++ void *arg;
++} kthread_t;
++
++#ifndef ADIAG
++#define DSP_FIRMWARE_PATH "/lib/modules/ar0700xx.bin"
++#else
++#define DSP_FIRMWARE_PATH "/var/tmp/ar0700xx_diag.bin"
++#endif
++
++/* externs */
++extern struct atm_dev *mydev;
++extern unsigned int oamFarLBCount[4];
++extern int dslhal_support_restoreTrainingInfo(PITIDSLHW_T pIhw);
++/* gloabal functions */
++
++/* end of global functions */
++
++/* module wide declars */
++static PITIDSLHW_T pIhw;
++static char mod_req[16]={'\t'};
++static volatile int bshutdown;
++static char info[MAX_STR_SIZE];
++static DECLARE_MUTEX_LOCKED(adsl_sem_overlay); /* Used for DSL Polling enable */
++kthread_t overlay_thread;
++/* end of module wide declars */
++
++/* Internal Functions */
++static void tn7dsl_chng_modulation(void* data);
++static void tn7dsl_set_modulation(void* data);
++static int tn7dsl_reload_overlay(void);
++static int dslmod_sysctl(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp);
++static void tn7dsl_register_dslss_led(void);
++void tn7dsl_dslmod_sysctl_register(void);
++void tn7dsl_dslmod_sysctl_unregister(void);
++/* end of internal functions */
++
++
++
++
++
++/* prototypes */
++
++/* start new kthread (called by creator) */
++void start_kthread(void (*func)(kthread_t *), kthread_t *kthread);
++
++/* stop a running thread (called by "killer") */
++void stop_kthread(kthread_t *kthread);
++
++/* setup thread environment (called by new thread) */
++void init_kthread(kthread_t *kthread, char *name);
++
++/* cleanup thread environment (called by thread upon receiving termination signal) */
++void exit_kthread(kthread_t *kthread);
++
++
++
++/* private functions */
++static void kthread_launcher(void *data)
++{
++ kthread_t *kthread = data;
++ kernel_thread((int (*)(void *))kthread->function, (void *)kthread, 0);
++
++}
++
++/* public functions */
++
++/* create a new kernel thread. Called by the creator. */
++void start_kthread(void (*func)(kthread_t *), kthread_t *kthread)
++{
++ /* initialize the semaphore:
++ we start with the semaphore locked. The new kernel
++ thread will setup its stuff and unlock it. This
++ control flow (the one that creates the thread) blocks
++ in the down operation below until the thread has reached
++ the up() operation.
++ */
++ //init_MUTEX_LOCKED(&kthread->startstop_sem);
++
++ /* store the function to be executed in the data passed to
++ the launcher */
++ kthread->function=func;
++
++ /* create the new thread my running a task through keventd */
++
++ /* initialize the task queue structure */
++ kthread->tq.sync = 0;
++ INIT_LIST_HEAD(&kthread->tq.list);
++ kthread->tq.routine = kthread_launcher;
++ kthread->tq.data = kthread;
++
++ /* and schedule it for execution */
++ schedule_task(&kthread->tq);
++
++ /* wait till it has reached the setup_thread routine */
++ //down(&kthread->startstop_sem);
++
++}
++
++/* stop a kernel thread. Called by the removing instance */
++void stop_kthread(kthread_t *kthread)
++{
++ if (kthread->thread == NULL)
++ {
++ printk("stop_kthread: killing non existing thread!\n");
++ return;
++ }
++
++ /* this function needs to be protected with the big
++ kernel lock (lock_kernel()). The lock must be
++ grabbed before changing the terminate
++ flag and released after the down() call. */
++ lock_kernel();
++
++ /* initialize the semaphore. We lock it here, the
++ leave_thread call of the thread to be terminated
++ will unlock it. As soon as we see the semaphore
++ unlocked, we know that the thread has exited.
++ */
++ //init_MUTEX_LOCKED(&kthread->startstop_sem);
++
++ /* We need to do a memory barrier here to be sure that
++ the flags are visible on all CPUs.
++ */
++ mb();
++
++ /* set flag to request thread termination */
++ kthread->terminate = 1;
++
++ /* We need to do a memory barrier here to be sure that
++ the flags are visible on all CPUs.
++ */
++ mb();
++ kill_proc(kthread->thread->pid, SIGKILL, 1);
++
++ /* block till thread terminated */
++ //down(&kthread->startstop_sem);
++
++ /* release the big kernel lock */
++ unlock_kernel();
++
++ /* now we are sure the thread is in zombie state. We
++ notify keventd to clean the process up.
++ */
++ kill_proc(2, SIGCHLD, 1);
++
++}
++
++/* initialize new created thread. Called by the new thread. */
++void init_kthread(kthread_t *kthread, char *name)
++{
++ /* lock the kernel. A new kernel thread starts without
++ the big kernel lock, regardless of the lock state
++ of the creator (the lock level is *not* inheritated)
++ */
++ lock_kernel();
++
++ /* fill in thread structure */
++ kthread->thread = current;
++
++ /* set signal mask to what we want to respond */
++ siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
++
++ /* initialise wait queue */
++ init_waitqueue_head(&kthread->queue);
++
++ /* initialise termination flag */
++ kthread->terminate = 0;
++
++ /* set name of this process (max 15 chars + 0 !) */
++ sprintf(current->comm, name);
++
++ /* let others run */
++ unlock_kernel();
++
++ /* tell the creator that we are ready and let him continue */
++ //up(&kthread->startstop_sem);
++
++}
++
++/* cleanup of thread. Called by the exiting thread. */
++void exit_kthread(kthread_t *kthread)
++{
++ /* we are terminating */
++
++ /* lock the kernel, the exit will unlock it */
++ lock_kernel();
++ kthread->thread = NULL;
++ mb();
++
++ /* notify the stop_kthread() routine that we are terminating. */
++ //up(&kthread->startstop_sem);
++ /* the kernel_thread that called clone() does a do_exit here. */
++
++ /* there is no race here between execution of the "killer" and real termination
++ of the thread (race window between up and do_exit), since both the
++ thread and the "killer" function are running with the kernel lock held.
++ The kernel lock will be freed after the thread exited, so the code
++ is really not executed anymore as soon as the unload functions gets
++ the kernel lock back.
++ The init process may not have made the cleanup of the process here,
++ but the cleanup can be done safely with the module unloaded.
++ */
++
++}
++
++
++
++int os_atoi(const char *pStr)
++{
++ int retVal = -1;
++
++ if(*pStr=='-')
++ retVal = -simple_strtoul(pStr+1, (char **)NULL, 10);
++ else
++ retVal = simple_strtoul(pStr, (char **)NULL, 10);
++ return retVal ;
++}
++
++
++int os_atoh(const char *pStr)
++{
++ int retVal = -1;
++
++ if(*pStr=='-')
++ retVal = -simple_strtoul(pStr+1, (char **)NULL, 16);
++ else
++ retVal = simple_strtoul(pStr, (char **)NULL, 16);
++ return retVal ;
++}
++
++unsigned long os_atoul(const char *pStr)
++{
++ unsigned long retVal = -1;
++
++ retVal = simple_strtoul(pStr, (char **)NULL, 10);
++ return retVal ;
++}
++
++void dprintf( int uDbgLevel, char * szFmt, ...)
++{
++#ifdef DEBUG_BUILD
++ static char buff[256];
++ va_list ap;
++
++ if( __guDbgLevel < uDbgLevel)
++ return;
++
++ va_start( ap, szFmt);
++ vsprintf((char *)buff, szFmt, ap);
++ va_end(ap);
++ printk("%s", buff);
++#endif
++}
++
++/*int strcmp(const char *s1, const char *s2)
++{
++
++ int i=0;
++
++ while(s1[i] !=0)
++ {
++ if(s2[i]==0)
++ return -1;
++ if(s1[i] != s2[i])
++ return 1;
++ i++;
++ }
++ if(s2[i] != 0)
++ return 1;
++ return 0;
++}
++*/
++
++int shim_osLoadFWImage(unsigned char *ptr)
++{
++ unsigned int bytesRead;
++ mm_segment_t oldfs;
++ static struct file *filp;
++ unsigned int imageLength=0x4ffff;
++
++
++ dprintf(4, "tn7dsl_read_dsp()\n");
++
++ dprintf(4,"open file %s\n", DSP_FIRMWARE_PATH);
++
++ filp=filp_open(DSP_FIRMWARE_PATH
++ ,00,O_RDONLY);
++
++ if(filp ==NULL)
++ {
++ printk("Failed: Could not open DSP binary file\n");
++ return -1;
++ }
++
++ if (filp->f_op->read==NULL)
++ return -1; /* File(system) doesn't allow reads */
++
++ /* Now read bytes from postion "StartPos" */
++ filp->f_pos = 0;
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ bytesRead = filp->f_op->read(filp,ptr,imageLength,&filp->f_pos);
++
++ dprintf(4,"file length = %d\n", bytesRead);
++
++ set_fs(oldfs);
++
++ /* Close the file */
++ fput(filp);
++
++ return bytesRead;
++}
++
++unsigned int shim_read_overlay_page(void *ptr, unsigned int secOffset, unsigned int secLength)
++{
++ unsigned int bytesRead;
++ mm_segment_t oldfs;
++ struct file *filp;
++
++ dprintf(4,"shim_read_overlay_page\n");
++ //dprintf(4,"sec offset=%d, sec length =%d\n", secOffset, secLength);
++
++ filp=filp_open(DSP_FIRMWARE_PATH,00,O_RDONLY);
++ if(filp ==NULL)
++ {
++ printk("Failed: Could not open DSP binary file\n");
++ return -1;
++ }
++
++ if (filp->f_op->read==NULL)
++ return -1; /* File(system) doesn't allow reads */
++
++ /* Now read bytes from postion "StartPos" */
++
++ if(filp->f_op->llseek)
++ filp->f_op->llseek(filp,secOffset, 0);
++ oldfs = get_fs();
++ set_fs(KERNEL_DS);
++ filp->f_pos = secOffset;
++ bytesRead = filp->f_op->read(filp,ptr,secLength,&filp->f_pos);
++
++ set_fs(oldfs);
++ /* Close the file */
++ fput(filp);
++ return bytesRead;
++}
++
++int shim_osLoadDebugFWImage(unsigned char *ptr)
++{
++ return 0;
++}
++int shim_osStringCmp(const char *s1, const char *s2)
++{
++ return strcmp(s1, s2);
++}
++
++void *shim_osAllocateMemory(unsigned int size)
++{
++ return ((void *)kmalloc(size, GFP_KERNEL));
++}
++
++void *shim_osAllocateDmaMemory(unsigned int size)
++{
++ /*
++ int order;
++
++ order=1;
++ size=size/4096;
++ while(size >= 1)
++ {
++ order++;
++ size=size/2;
++ }
++
++ return ( (void *)__get_free_pages(GFP_ATOMIC, order));
++ */
++ //return ((void *)kmalloc(size, GFP_ATOMIC));
++ //return ((void *)kmalloc(size, GFP_KERNEL));
++ void *ptr;
++
++ ptr = kmalloc(size, GFP_ATOMIC);
++ if(ptr==NULL)
++ {
++ printk("failed atomic\n");
++ ptr = kmalloc(size, GFP_KERNEL);
++ if(ptr==NULL)
++ {
++ printk("failed kernel\n");
++ ptr = kmalloc(size, GFP_KERNEL|GFP_DMA);
++ }
++ }
++ printk("size=%d\n", size);
++ return ptr;
++
++}
++
++
++void shim_osFreeMemory(void *ptr, unsigned int size)
++{
++
++ kfree(ptr);
++}
++
++void shim_osFreeDmaMemory(void *ptr, unsigned int size)
++{
++/*
++ int order;
++
++ order=1;
++ size=size/4096;
++ while(size >=1)
++ {
++ order++;
++ size=size/2;
++ }
++ free_pages(ptr, order);
++*/
++ kfree(ptr);
++}
++
++void *shim_osAllocateVMemory(unsigned int size)
++{
++
++ return ((void *)vmalloc(size));
++}
++
++void shim_osFreeVMemory(void *ptr, unsigned int size)
++{
++ vfree(ptr);
++}
++
++void shim_osMoveMemory(char *dst, char *src, unsigned int numBytes)
++{
++ memcpy(dst, src, numBytes);
++}
++
++void shim_osZeroMemory(char *dst, unsigned int numBytes)
++{
++ memset(dst, 0, numBytes);
++}
++
++void shim_osWriteBackCache(void *addr, unsigned int size)
++{
++ unsigned int i,Size=(((unsigned int)addr)&0xf)+size;
++
++ for (i=0;i<Size;i+=16,addr+=16)
++ {
++ __asm__(" .set mips3 ");
++ __asm__(" cache 25, (%0)" : : "r" (addr));
++ __asm__(" .set mips0 ");
++ }
++}
++
++void shim_osInvalidateCache(void *addr, unsigned int size)
++{
++ unsigned int i,Size=(((unsigned int)addr)&0xf)+size;
++
++ for (i=0;i<Size;i+=16,addr+=16)
++ {
++ __asm__(" .set mips3 ");
++ __asm__("cache 17, (%0)" : : "r" (addr));
++ __asm__(" .set mips0 ");
++ }
++}
++
++void shim_osClockWait(int val)
++{
++ unsigned int chkvalue;
++ chkvalue=val/64;
++
++ if(chkvalue > 1000)
++ {
++ mdelay(chkvalue/1000);
++ return;
++ }
++ else
++ udelay(val/64);
++} /* end of cwait() */
++
++unsigned int shim_osClockTick(int val)
++{
++ return jiffies;
++}
++
++int flags;
++spinlock_t shimLock;
++
++void shim_osCriticalEnter(void)
++{
++ spin_lock_irqsave(&shimLock, flags);
++
++}
++
++
++void shim_osCriticalExit(void)
++{
++ spin_unlock_irqrestore(&shimLock, flags);
++}
++
++
++int tn7dsl_proc_stats(char* buf, char **start, off_t offset, int count,
++ int *eof, void *data)
++{
++
++ int len = 0;
++ int limit = count - 80;
++ int F4count, F5count;
++
++
++ /* Read Ax5 Stats */
++ dslhal_api_gatherStatistics(pIhw);
++
++ if(len<=limit)
++ len += sprintf(buf+len, "\nAR7 DSL Modem Statistics:\n");
++ if(len<=limit)
++ len += sprintf(buf+len, "--------------------------------\n");
++ /* us and ds Connection Rates */
++ if(len<=limit)
++ len += sprintf(buf+len, "[DSL Modem Stats]\n");
++
++
++ if(len<=limit)
++ {
++ if(pIhw->lConnected != 1)
++ {
++ pIhw->AppData.USConRate = 0;
++ pIhw->AppData.DSConRate = 0;
++ }
++ len += sprintf(buf+len, "\tUS Connection Rate:\t%u\tDS Connection Rate:\t%u\n",
++ (unsigned int)pIhw->AppData.USConRate,
++ (unsigned int)pIhw->AppData.DSConRate );
++ }
++ if(len<=limit)
++ len += sprintf(buf+len, "\tDS Line Attenuation:\t%u\tDS Margin:\t\t%u\n",
++ (unsigned int)pIhw->AppData.dsLineAttn/2,
++ (unsigned int)pIhw->AppData.dsMargin/2 );
++ if(len<=limit)
++ len += sprintf(buf+len, "\tUS Line Attenuation:\t%u\tUS Margin:\t\t%u\n",
++ (unsigned int)pIhw->AppData.usLineAttn,
++ (unsigned int)pIhw->AppData.usMargin );
++ if(len<=limit)
++ len += sprintf(buf+len, "\tUS Payload :\t\t%u\tDS Payload:\t\t%u\n",
++ ((unsigned int)pIhw->AppData.usAtm_count[0] + (unsigned int)pIhw->AppData.usAtm_count[1])*48,
++ ((unsigned int)pIhw->AppData.dsGood_count[0] + (unsigned int)pIhw->AppData.dsGood_count[1])*48);
++ /* Superframe Count */
++ if(len<=limit)
++ len += sprintf(buf+len, "\tUS Superframe Cnt :\t%u\tDS Superframe Cnt:\t%u\n",
++ (unsigned int)pIhw->AppData.usSuperFrmCnt,
++ (unsigned int)pIhw->AppData.dsSuperFrmCnt );
++
++ /* US and DS power */
++ if(len<=limit)
++ len += sprintf(buf+len, "\tUS Transmit Power :\t%u\tDS Transmit Power:\t%u\n",
++ (unsigned int)pIhw->AppData.usTxPower/256,
++ (unsigned int)pIhw->AppData.dsTxPower/256 );
++ /* DSL Stats Errors*/
++ if(len<=limit)
++ len += sprintf(buf+len, "\tLOS errors:\t\t%u\tSEF errors:\t\t%u\n",
++ (unsigned int)pIhw->AppData.LOS_errors,
++ (unsigned int)pIhw->AppData.SEF_errors );
++ if(len<=limit)
++ len += sprintf(buf+len, "\tFrame mode:\t\t%u\tMax Frame mode:\t\t%u\n",
++ (unsigned int)pIhw->AppData.FrmMode,
++ (unsigned int)pIhw->AppData.MaxFrmMode );
++ if(len<=limit)
++ len += sprintf(buf+len, "\tTrained Path:\t\t%u\tUS Peak Cell Rate:\t%u\n",
++ (unsigned int)pIhw->AppData.TrainedPath,
++ (unsigned int)pIhw->AppData.USConRate*1000/8/53 );
++ if(len<=limit)
++ len += sprintf(buf+len, "\tTrained Mode:\t\t%u\tSelected Mode:\t\t%u\n",
++ (unsigned int)pIhw->AppData.TrainedMode, (unsigned int)pIhw->AppData.StdMode );
++
++ if(len<=limit)
++ len += sprintf(buf+len, "\tATUC Vendor ID:\t%u\tATUC Revision:\t\t%u\n",
++ (unsigned int)pIhw->AppData.atucVendorId, pIhw->AppData.atucRevisionNum);
++ if(len<=limit)
++ len += sprintf(buf+len, "\tHybrid Selected:\t%u\n",
++ (unsigned int)pIhw->AppData.currentHybridNum);
++
++ /* Upstream Interleaved Errors */
++ if(len<=limit)
++ len += sprintf(buf+len, "\n\t[Upstream (TX) Interleave path]\n");
++ if(len<=limit)
++ len += sprintf(buf+len, "\tCRC: \t%u\tFEC: \t%u\tNCD: \t%u\n",
++ (unsigned int)pIhw->AppData.usICRC_errors,
++ (unsigned int)pIhw->AppData.usIFEC_errors,
++ (unsigned int)pIhw->AppData.usINCD_error);
++ if(len<=limit)
++ len += sprintf(buf+len, "\tLCD: \t%u\tHEC: \t%u\n",
++ (unsigned int)pIhw->AppData.usILCD_errors,
++ (unsigned int)pIhw->AppData.usIHEC_errors);
++ /* Downstream Interleaved Errors */
++ if(len<=limit)
++ len += sprintf(buf+len, "\n\t[Downstream (RX) Interleave path]\n");
++ if(len<=limit)
++ len += sprintf(buf+len, "\tCRC: \t%u\tFEC: \t%u\tNCD: \t%u\n",
++ (unsigned int)pIhw->AppData.dsICRC_errors,
++ (unsigned int)pIhw->AppData.dsIFEC_errors,
++ (unsigned int)pIhw->AppData.dsINCD_error);
++ if(len<=limit)
++ len += sprintf(buf+len, "\tLCD: \t%u\tHEC: \t%u\n",
++ (unsigned int)pIhw->AppData.dsILCD_errors,
++ (unsigned int)pIhw->AppData.dsIHEC_errors);
++ /* Upstream Fast Errors */
++ if(len<=limit)
++ len += sprintf(buf+len, "\n\t[Upstream (TX) Fast path]\n");
++ if(len<=limit)
++ len += sprintf(buf+len, "\tCRC: \t%u\tFEC: \t%u\tNCD: \t%u\n",
++ (unsigned int)pIhw->AppData.usFCRC_errors,
++ (unsigned int)pIhw->AppData.usFFEC_errors,
++ (unsigned int)pIhw->AppData.usFNCD_error);
++ if(len<=limit)
++ len += sprintf(buf+len, "\tLCD: \t%u\tHEC: \t%u\n",
++ (unsigned int)pIhw->AppData.usFLCD_errors,
++ (unsigned int)pIhw->AppData.usFHEC_errors);
++ /* Downstream Fast Errors */
++ if(len<=limit)
++ len += sprintf(buf+len, "\n\t[Downstream (RX) Fast path]\n");
++ if(len<=limit)
++ len += sprintf(buf+len, "\tCRC: \t%u\tFEC: \t%u\tNCD: \t%u\n",
++ (unsigned int)pIhw->AppData.dsFCRC_errors,
++ (unsigned int)pIhw->AppData.dsFFEC_errors,
++ (unsigned int)pIhw->AppData.dsFNCD_error);
++ if(len<=limit)
++ len += sprintf(buf+len, "\tLCD: \t%u\tHEC: \t%u\n",
++ (unsigned int)pIhw->AppData.dsFLCD_errors,
++ (unsigned int)pIhw->AppData.dsFHEC_errors);
++ /* ATM stats upstream */
++ if(len<=limit)
++ len += sprintf(buf+len, "\n[ATM Stats]");
++ if(len<=limit)
++ len += sprintf(buf+len, "\n\t[Upstream/TX]\n");
++ if(len<=limit)
++ len += sprintf(buf+len, "\tGood Cell Cnt:\t%u\n\tIdle Cell Cnt:\t%u\n\n",
++ (unsigned int)pIhw->AppData.usAtm_count[0] + (unsigned int)pIhw->AppData.usAtm_count[1],
++ (unsigned int)pIhw->AppData.usIdle_count[0] + (unsigned int)pIhw->AppData.usIdle_count[1]);
++ /* ATM stats downstream */
++ if(len<=limit)
++ len += sprintf(buf+len, "\n\t[Downstream/RX)]\n");
++ if(len<=limit)
++ len += sprintf(buf+len, "\tGood Cell Cnt:\t%u\n\tIdle Cell Cnt:\t%u\n\tBad Hec Cell Cnt:\t%u\n",
++ (unsigned int)pIhw->AppData.dsGood_count[0] + (unsigned int)pIhw->AppData.dsGood_count[1],
++ (unsigned int)pIhw->AppData.dsIdle_count[0] + (unsigned int)pIhw->AppData.dsIdle_count[1],
++ (unsigned int)pIhw->AppData.dsBadHec_count[0] + (unsigned int)pIhw->AppData.dsBadHec_count[1]);
++ if(len<=limit)
++ len += sprintf(buf+len, "\tOverflow Dropped Cell Cnt:\t%u\n",
++ (unsigned int)pIhw->AppData.dsOVFDrop_count[0] + (unsigned int)pIhw->AppData.dsOVFDrop_count[1]);
++ tn7sar_get_stats(pIhw->pOsContext);
++ if(len<=limit)
++ len += sprintf(buf+len, "\n[SAR AAL5 Stats]\n");
++ if(len<=limit)
++ len += sprintf(buf+len, "\tTx PDU's:\t%u\n\tRx PDU's:\t%u\n",
++ sarStat.txPktCnt,
++ sarStat.rxPktCnt);
++ if(len<=limit)
++ len += sprintf(buf+len, "\tTx Total Bytes:\t%u\n\tRx Total Bytes:\t%u\n",
++ sarStat.txBytes,
++ sarStat.rxBytes);
++ if(len<=limit)
++ len += sprintf(buf+len, "\tTx Total Error Counts:\t%u\n\tRx Total Error Counts:\t%u\n\n",
++ sarStat.txErrors,
++ sarStat.rxErrors);
++
++ /* oam loopback info */
++ if(len<=limit)
++ len += sprintf(buf+len, "\n[OAM Stats]\n");
++
++ tn7sar_get_near_end_loopback_count(&F4count, &F5count);
++
++ if(len<=limit)
++ {
++ len += sprintf(buf+len, "\tNear End F5 Loop Back Count:\t%u\n\tNear End F4 Loop Back Count:\t%u\n\tFar End F5 Loop Back Count:\t%u\n\tFar End F4 Loop Back Count:\t%u\n",
++ F5count,
++ F4count,
++ oamFarLBCount[0] + oamFarLBCount[2],
++ oamFarLBCount[1] + oamFarLBCount[3]);
++ }
++ return len;
++}
++
++int
++tn7dsl_proc_modem(char* buf, char **start, off_t offset, int count,
++ int *eof, void *data)
++{
++
++ int len = 0;
++ int limit = count - 80;
++
++ char *state;
++ int tag;
++
++ tag= dslhal_api_pollTrainingStatus(pIhw);
++ tag = pIhw->AppData.bState;
++
++ switch(tag){
++ case 0: state = "ACTREQ"; break;
++ case 1: state = "QUIET1"; break;
++ case 2: state = "IDLE"; break;
++ case 3: state = "INIT"; break;
++ case 4: state = "RTDL"; break;
++ case 5: state = "SHOWTIME"; break;
++ default: state = "unknown"; break;
++ }
++
++ if(pIhw->lConnected == 1)
++ state = "SHOWTIME";
++ if(len<=limit)
++ len += sprintf(buf+len,"%s\n",state);
++
++ return len;
++}
++
++
++
++int tn7dsl_handle_interrupt(void)
++{
++ int intsrc;
++ unsigned char cMsgRa[6];
++ short margin;
++
++ dprintf(4, "tn7dsl_handle_dsl_interrupt()\n");
++ if(pIhw)
++ {
++ intsrc=dslhal_api_acknowledgeInterrupt(pIhw);
++ dslhal_api_handleTrainingInterrupt(pIhw, intsrc);
++
++ if(pIhw->lConnected == TC_SYNC)
++ {
++
++ if(dslInSync == 0)
++ {
++ printk("DSL in Sync\n");
++ tn7atm_device_connect_status(pIhw->pOsContext, 1);
++ dslhal_api_initStatistics(pIhw);
++ dslhal_api_gatherStatistics(pIhw);
++#ifdef CONFIG_LED_MODULE
++// led_operation(MOD_ADSL, DEF_ADSL_SYNC);
++ led_on = DEF_ADSL_SYNC;
++#endif
++ /* add auto margin retrain */
++ if(pIhw->AppData.TrainedMode < 5)
++ {
++ if(bMarginRetrainEnable && bMarginThConfig == 0)
++ {
++ dslhal_support_getCMsgsRa(pIhw, cMsgRa);
++ margin = *(unsigned short *)&cMsgRa[4];
++ margin = (margin >> 6) & 0x3f;
++ if(margin & 0x20) // highest bit is 1
++ {
++ margin = -(margin & 0x1f);
++ }
++
++ //printk("margin = %d, cmsg-ra = %02x %02x %02x %02x %02x %02x\n", margin, cMsgRa[0],cMsgRa[1],cMsgRa[2],cMsgRa[3],cMsgRa[4],cMsgRa[5]);
++ dslhal_api_setMarginThreshold(pIhw, margin*2); /* DSL margin is in 0.5db */
++ }
++ }
++
++ }
++ dslInSync = 1;
++ }
++ else
++ {
++ if(dslInSync == 1)
++ {
++ dslInSync = 0;
++ tn7atm_device_connect_status(pIhw->pOsContext, 0);
++ up(&adsl_sem_overlay);
++ printk("DSL out of syn\n");
++ }
++#ifdef CONFIG_LED_MODULE
++ if(pIhw->AppData.bState < RSTATE_INIT)
++ {
++ if(led_on != DEF_ADSL_IDLE)
++ {
++// led_operation(MOD_ADSL, DEF_ADSL_IDLE);
++ led_on = DEF_ADSL_IDLE;
++ }
++ }
++ else
++ {
++ if(led_on != DEF_ADSL_TRAINING)
++ {
++// led_operation(MOD_ADSL, DEF_ADSL_TRAINING);
++ led_on = DEF_ADSL_TRAINING;
++ }
++
++ }
++
++#endif
++
++ }
++ }
++ return 0;
++}
++
++
++int tn7dsl_get_dslhal_version(char *pVer)
++{
++ dslVer ver;
++
++ dslhal_api_getDslHalVersion(&ver);
++
++ memcpy(pVer,&ver,8);
++ return 0;
++}
++
++int tn7dsl_get_dsp_version(char *pVer)
++{
++ dspVer ver;
++ dslhal_api_getDspVersion(pIhw, &ver);
++ memcpy(pVer, &ver, 9);
++ return 0;
++}
++
++
++static int
++tn7dsl_get_modulation(void)
++{
++ char *ptr = NULL;
++
++ dprintf(4, "tn7dsl_get_modulation\n");
++ //printk("tn7dsl_get_modulation\n");
++ ptr = prom_getenv("modulation");
++
++ if (!ptr) {
++ //printk("modulation is not set in adam2 env\n");
++ //printk("Using multimode\n");
++ return 0;
++ }
++ printk("dsl modulation = %s\n", ptr);
++
++ tn7dsl_set_modulation(ptr);
++
++ return 0;
++}
++
++
++static int tn7dsl_set_dsl(void)
++{
++
++ char *ptr = NULL;
++ int value;
++ int i, offset[2]={4,11},oamFeature=0;
++ char tmp[4];
++ char dspVer[10];
++
++ // OAM Feature Configuration
++ dslhal_api_dspInterfaceRead(pIhw,(unsigned int)pIhw->pmainAddr, 2, (unsigned int *)&offset, (unsigned char *)&oamFeature, 4);
++ oamFeature |= dslhal_support_byteSwap32(0x0000000C);
++ dslhal_api_dspInterfaceWrite(pIhw,(unsigned int)pIhw->pmainAddr, 2, (unsigned int *)&offset, (unsigned char *)&oamFeature, 4);
++
++ // modulation
++ ptr = prom_getenv("modulation");
++ if (ptr)
++ {
++ printk("dsl modulation = %s\n", ptr);
++ tn7dsl_set_modulation(ptr);
++ }
++
++ // margin retrain
++ ptr = NULL;
++ ptr = prom_getenv("enable_margin_retrain");
++ if(ptr)
++ {
++ value = os_atoi(ptr);
++ if(value == 1)
++ {
++ dslhal_api_setMarginMonitorFlags(pIhw, 0, 1);
++ bMarginRetrainEnable = 1;
++ printk("enable showtime margin monitor.\n");
++ ptr = NULL;
++ ptr = prom_getenv("margin_threshold");
++ if(ptr)
++ {
++ value = os_atoi(ptr);
++ printk("Set margin threshold to %d x 0.5 db\n",value);
++ if(value >= 0)
++ {
++ dslhal_api_setMarginThreshold(pIhw, value);
++ bMarginThConfig=1;
++ }
++ }
++ }
++ }
++
++ // rate adapt
++ ptr = NULL;
++ ptr = prom_getenv("enable_rate_adapt");
++ if(ptr)
++ {
++ dslhal_api_setRateAdaptFlag(pIhw, os_atoi(ptr));
++ }
++
++ // trellis
++ ptr = NULL;
++ ptr = prom_getenv("enable_trellis");
++ if(ptr)
++ {
++ dslhal_api_setTrellisFlag(pIhw, os_atoi(ptr));
++ }
++
++ // maximum bits per carrier
++ ptr = NULL;
++ ptr = prom_getenv("maximum_bits_per_carrier");
++ if(ptr)
++ {
++ dslhal_api_setMaxBitsPerCarrier(pIhw, os_atoi(ptr));
++ }
++
++ // maximum interleave depth
++ ptr = NULL;
++ ptr = prom_getenv("maximum_interleave_depth");
++ if(ptr)
++ {
++ dslhal_api_setMaxInterleaverDepth(pIhw, os_atoi(ptr));
++ }
++
++ // inner and outer pairs
++ ptr = NULL;
++ ptr = prom_getenv("pair_selection");
++ if(ptr)
++ {
++ dslhal_api_selectInnerOuterPair(pIhw, os_atoi(ptr));
++ }
++
++ ptr = NULL;
++ ptr = prom_getenv("dgas_polarity");
++ if(ptr)
++ {
++ dslhal_api_configureDgaspLpr(pIhw, 1, 1);
++ dslhal_api_configureDgaspLpr(pIhw, 0, os_atoi(ptr));
++ }
++
++ ptr = NULL;
++ ptr = prom_getenv("los_alarm");
++ if(ptr)
++ {
++ dslhal_api_disableLosAlarm(pIhw, os_atoi(ptr));
++ }
++
++ ptr = NULL;
++ ptr = prom_getenv("eoc_vendor_id");
++ if(ptr)
++ {
++ for(i=0;i<8;i++)
++ {
++ tmp[0]=ptr[i*2];
++ tmp[1]=ptr[i*2+1];
++ tmp[2]=0;
++ EOCVendorID[i] = os_atoh(tmp);
++ //printk("tmp=%s--", tmp);
++ //printk("ID[%d]=0x%02x ", i, (unsigned char)EOCVendorID[i]);
++ }
++ tn7dsl_get_dsp_version(dspVer);
++ //printk("Annex =%d\n", dspVer[8]);
++ if(dspVer[8]==2) // annex b
++ {
++ //printk("EOCVendorID=%02x %02x %02x %02x %02x %02x %02x %02x\n", EOCVendorID[0], EOCVendorID[1], EOCVendorID[2], EOCVendorID[3],
++ // EOCVendorID[4], EOCVendorID[5], EOCVendorID[6], EOCVendorID[7]);
++ dslhal_api_setEocVendorId(pIhw, EOCVendorID);
++ }
++
++ }
++
++ return 0;
++}
++
++
++
++
++
++/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * Function: static void tn7dsl_init(void)
++ *
++ * Description: This function initializes
++ * Ar7 DSL interface
++ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
++
++int tn7dsl_init(void *priv)
++{
++
++ printk("Initializing DSL interface\n");
++
++
++ /* start dsl */
++ if(dslhal_api_dslStartup(&pIhw) !=0 )
++ {
++ printk("DSL start failed.\n");
++ return -1;
++ }
++
++ // set dsl into overlay page reload mode
++ pIhw->bAutoRetrain = 1;
++
++ // set default training properties
++ tn7dsl_set_dsl();
++
++ pIhw->pOsContext = priv;
++
++ //start_kthread(tn7dsl_reload_overlay, &overlay_thread);
++
++ /*register dslss LED with led module */
++#ifdef CONFIG_LED_MODULE
++ tn7dsl_register_dslss_led();
++#endif
++
++
++ return 0; /* What do we return here? */
++}
++
++/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * Function: int avsar_exit(void)
++ *
++ * Description: Avalanche SAR exit function
++ *
++ *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
++
++void tn7dsl_exit (void)
++{
++
++ bshutdown = 1;
++#ifdef CONFIG_LED_MODULE
++#ifdef DEREGISTER_LED
++ //down(&adsl_sem_overlay);
++ deregister_led_drv(LED_NUM_1);
++ deregister_led_drv(LED_NUM_2);
++#else
++// led_operation(MOD_ADSL,DEF_ADSL_IDLE);
++#endif
++#endif
++ stop_kthread(&overlay_thread);
++ dslhal_api_dslShutdown(pIhw);
++
++}
++
++
++static int tn7dsl_process_oam_string(int *type, int *pvpi, int *pvci, int *pdelay)
++{
++ int i=1;
++ int j=0;
++ int vci, vpi;
++ char tmp[16];
++ int chan;
++ int tt;
++
++ while(j<8)
++ {
++ tmp[j] = mod_req[i];
++ //printk("tmp[%d]=%c, %d\n", j, tmp[j], tmp[j]);
++ if(tmp[j] == 0x50 || tmp[j] == 0x70)
++ break;
++ j++;
++ i++;
++ }
++
++ tmp[j] = 0;
++ vpi = os_atoi(tmp);
++
++ i++;
++ j=0;
++ while(j<8)
++ {
++ tmp[j] = mod_req[i];
++ //printk("tmp[%d]=%c, %d\n", j, tmp[j], tmp[j]);
++ if(tmp[j] == 0x43 || tmp[j] == 0x63)
++ break;
++
++ j++;
++ i++;
++ }
++
++ vci = os_atoi(tmp);
++
++ if(vci==0) // f4 oam
++ *type = 1;
++ else
++ *type = 0;
++
++
++ tt=5000;
++ i++;
++ j=0;
++ tmp[j] = mod_req[i];
++ if(tmp[j]==0x44 || tmp[j]==0x64)
++ {
++ i++;
++ while(j<8)
++ {
++ tmp[j] = mod_req[i];
++
++ //printk("tmp[%d]=%c, %d\n", j, tmp[j], tmp[j]);
++ if(tmp[j] == 0x54 || tmp[j] == 0x74)
++ break;
++
++ j++;
++ i++;
++ }
++ tt = os_atoi(tmp);
++ }
++
++ chan = tn7atm_lut_find(vpi, vci);
++
++ *pvci=vci;
++ *pvpi=vpi;
++ *pdelay =tt;
++ dprintf(2, "oam chan=%d, type =%d\n", chan, *type);
++
++ return chan;
++}
++
++static void tn7dsl_dump_memory(void)
++{
++ unsigned int *pUi;
++ int i=1;
++ int j=0;
++ int addr, len;
++ char tmp[16];
++
++
++ while(j<8)
++ {
++ tmp[j] = mod_req[i];
++ j++;
++ i++;
++ }
++
++ tmp[j] = 0;
++
++ addr = os_atoh(tmp);
++
++ printk("start dump address =0x%x\n", addr);
++ pUi = (unsigned int *)addr;
++ i++;
++ j=0;
++ while(j<8)
++ {
++ tmp[j] = mod_req[i];
++ //printk("tmp[%d]=%c, %d\n", j, tmp[j], tmp[j]);
++ if(tmp[j] == 0x43 || tmp[j] == 0x63)
++ break;
++
++ j++;
++ i++;
++ }
++
++ len = os_atoi(tmp);
++ j=0;
++ for(i=0; i<len; i++)
++ {
++ if(j==0)
++ printk("0x%08x: ", (unsigned int)pUi);
++ printk("%08x ", *pUi);
++ pUi++;
++ j++;
++ if(j==4)
++ {
++ printk("\n");
++ j=0;
++ }
++ }
++
++}
++
++
++
++static int dslmod_sysctl(ctl_table *ctl, int write, struct file * filp,
++ void *buffer, size_t *lenp)
++{
++ char *ptr;
++ int ret, len = 0;
++ int chan;
++ int type;
++ int vpi,vci,timeout;
++
++ if (!*lenp || (filp->f_pos && !write)) {
++ *lenp = 0;
++ return 0;
++ }
++ /* DSL MODULATION is changed */
++ if(write)
++ {
++ ret = proc_dostring(ctl, write, filp, buffer, lenp);
++
++ switch (ctl->ctl_name)
++ {
++ case DEV_DSLMOD:
++ ptr = strpbrk(info, " \t");
++ strcpy(mod_req, info);
++
++ /* parse the string to determine the action */
++ if(mod_req[0] == 0x45 || mod_req[0] == 0x65 ) // 'e', or 'E' f5 end to end
++ {
++ chan = tn7dsl_process_oam_string(&type, &vpi, &vci, &timeout);
++ tn7sar_oam_generation(pIhw->pOsContext, chan, type, vpi, vci, timeout);
++ }
++ else if(mod_req[0] == 0x53 || mod_req[0] == 0x73 ) // 's', or 'S' f5 seg to seg
++ {
++ chan=tn7dsl_process_oam_string(&type, &vpi, &vci,&timeout);
++ type = type | (1<<1);
++ tn7sar_oam_generation(pIhw->pOsContext, chan, type, vpi, vci,timeout);
++ }
++ //debug only. Dump memory
++ else if(mod_req[0] == 0x44 || mod_req[0] == 0x64 ) // 'd' or 'D'
++ tn7dsl_dump_memory();
++ else
++ tn7dsl_chng_modulation(info);
++ break;
++ }
++ }
++ else
++ {
++ len += sprintf(info+len, mod_req);
++ ret = proc_dostring(ctl, write, filp, buffer, lenp);
++ }
++ return ret;
++}
++
++
++ctl_table dslmod_table[] = {
++ {DEV_DSLMOD, "dslmod", info, DSL_MOD_SIZE, 0644, NULL, &dslmod_sysctl},
++ {0}
++ };
++
++/* Make sure that /proc/sys/dev is there */
++ctl_table dslmod_root_table[] = {
++#ifdef CONFIG_PROC_FS
++ {CTL_DEV, "dev", NULL, 0, 0555, dslmod_table},
++#endif /* CONFIG_PROC_FS */
++ {0}
++ };
++
++static struct ctl_table_header *dslmod_sysctl_header;
++
++void tn7dsl_dslmod_sysctl_register(void)
++{
++ static int initialized;
++
++ if (initialized == 1)
++ return;
++
++ dslmod_sysctl_header = register_sysctl_table(dslmod_root_table, 1);
++ dslmod_root_table->child->de->owner = THIS_MODULE;
++
++ /* set the defaults */
++ info[0] = 0;
++
++ initialized = 1;
++}
++
++void tn7dsl_dslmod_sysctl_unregister(void)
++{
++ unregister_sysctl_table(dslmod_sysctl_header);
++}
++
++static void
++tn7dsl_set_modulation(void* data)
++{
++ dprintf(4,"tn7dsl_set_modulation\n");
++
++ if(!strcmp(data, "T1413"))
++ {
++ printk("retraining in T1413 mode\n");
++ dslhal_api_setTrainingMode(pIhw, T1413_MODE);
++ return;
++ }
++ if(!strcmp(data, "GDMT"))
++ {
++ dslhal_api_setTrainingMode(pIhw, GDMT_MODE);
++ return;
++ }
++ if(!strcmp(data, "GLITE"))
++ {
++ dslhal_api_setTrainingMode(pIhw, GLITE_MODE);
++ return;
++ }
++ if(!strcmp(data, "MMODE"))
++ {
++ dslhal_api_setTrainingMode(pIhw, MULTI_MODE);
++ return;
++ }
++ if(!strcmp(data, "NMODE"))
++ {
++ dslhal_api_setTrainingMode(pIhw, NO_MODE);
++ return;
++ }
++
++ return;
++}
++
++
++/* Codes added for compiling tiadiag.o for Analog Diagnostic tests */
++#ifdef ADIAG
++
++enum
++{
++ HOST_ACTREQ, // Send R-ACKREQ and monitor for C-ACKx
++ HOST_QUIET, // Sit quietly doing nothing for about 60 seconds, DEFAULT STATE; R_IDLE
++ HOST_XMITBITSWAP, // Perform upstream bitswap - FOR INTERNAL USE ONLY
++ HOST_RCVBITSWAP, // Perform downstream bitswap - FOR INTERNAL USE ONLY
++ HOST_RTDLPKT, // Send a remote download packet - FOR INTERNAL USE ONLY
++ HOST_CHANGELED, // Read the LED settings and change accordingly
++ HOST_IDLE, // Sit quiet
++ HOST_REVERBTEST, // Generate REVERB for manufacturing test
++ HOST_CAGCTEST, // Set coarse receive gain for manufacturing test
++ HOST_DGASP, // send Dying Gasp messages through EOC channel
++ HOST_GHSREQ, // G.hs - FOR INTERNAL USE ONLY
++ HOST_GHSMSG, // G.hs - FOR INTERNAL USE ONLY
++ HOST_GHS_SENDGALF, // G.hs - FOR INTERNAL USE ONLY
++ HOST_GHSEXIT, // G.hs - FOR INTERNAL USE ONLY
++ HOST_GHSMSG1, // G.hs - FOR INTERNAL USE ONLY
++ HOST_HYBRID, // Enable/Disable automatic hybrid switch
++ HOST_RJ11SELECT, // RJ11 inner/outer pair select
++ HOST_DIGITAL_MEM, // Digital Diags: run external memory tests
++ HOST_TXREVERB, // AFE Diags: TX path Reverb
++ HOST_TXMEDLEY, // AFE Diags: TX path Medley
++ HOST_RXNOISEPOWER, // AFE Diags: RX noise power
++ HOST_ECPOWER, // AFE Diags: RX eco power
++ HOST_ALL_ADIAG, // AFE Diags: all major analog diagnostic modes. Host is responsible to initiate each diagnostic sessions
++ HOST_USER_ADIAG, // AFE Diags: Host fills in analog diagnostic input data structure as specified and requests DSP to perform measurements as specified
++ HOST_QUIT_ADIAG, // AFE Diags: Host requests DSP to quit current diagnostic session. This is used for stopping the transmit REVERB/MEDLEY
++ HOST_NO_CMD, // All others - G.hs - FOR INTERNAL USE ONLY
++ HOST_DSLSS_SHUTDOWN, // Host initiated DSLSS shutdown message
++ HOST_SET_GENERIC, // Set generic CO profile
++ HOST_UNDO_GENERIC // Set profile previous to Generic
++};
++
++enum
++{
++ DSP_IDLE, // R_IDLE state entered
++ DSP_ACTMON, // R_ACTMON state entered
++ DSP_TRAIN, // R_TRAIN state entered
++ DSP_ACTIVE, // R_ACTIVE state entered
++ DSP_XMITBITSWAP, // Upstream bitswap complete - FOR INTERNAL USE ONLY
++ DSP_RCVBITSWAP, // Downstream bitswap complete - FOR INTERNAL USE ONLY
++ DSP_RTDL, // R_RTDL state entered - FOR INTERNAL USE ONLY
++ DSP_RRTDLPKT, // RTDL packet received - FOR INTERNAL USE ONLY
++ DSP_XRTDLPKT, // RTDL packet transmitted - FOR INTERNAL USE ONLY
++ DSP_ERROR, // Command rejected, wrong state for this command
++ DSP_REVERBTEST, // Manufacturing REVERB test mode entered
++ DSP_CAGCTEST, // Manufacturing receive gain test done
++ DSP_OVERLAY_START, // Notify host that page overlay has started - overlay number indicated by "tag"
++ DSP_OVERLAY_END, // Notify host that page overlay has ended - overlay number indicated by "tag"
++ DSP_CRATES1, // CRATES1 message is valid and should be copied to host memory now
++ DSP_SNR, // SNR calculations are ready and should be copied to host memory now
++ DSP_GHSMSG, // G.hs - FOR INTERNAL USE ONLY
++ DSP_RCVBITSWAP_TIMEOUT, // Acknowledge Message was not received within ~500 msec (26 Superframes).
++ DSP_ATM_TC_SYNC, // Indicates true TC sync on both the upstream and downstream. Phy layer ready for data xfer.
++ DSP_ATM_NO_TC_SYNC, // Indicates loss of sync on phy layer on either US or DS.
++ DSP_HYBRID, // DSP completed hybrid switch
++ DSP_RJ11SELECT, // DSP completed RJ11 inner/outer pair select
++ DSP_INVALID_CMD, // Manufacturing (Digital and AFE) diags: CMD received not recognized
++ DSP_TEST_PASSED, // Manufacturing diags: test passed
++ DSP_TEST_FAILED, // Manufacturing diags: test failed
++ DSP_TXREVERB, // Manufacturing AFE diags: Response to HOST_TXREVERB
++ DSP_TXMEDLEY, // Manufacturing AFE diags: Response to HOST_TXMEDLEY
++ DSP_RXNOISEPOWER, // Manufacturing AFE diags: Response to HOST_RXNOISEPOWER
++ DSP_ECPOWER, // Manufacturing AFE diags: Response to HOST_ECPOWER
++ DSP_ALL_ADIAG, // Manufacturing AFE diags: Response to HOST_ALL_ADIAG
++ DSP_USER_ADIAG, // Manufacturing AFE diags: Response to HOST_USER_ADIAG
++ DSP_QUIT_ADIAG, // Manufacturing AFE diags: Response to HOST_QUIT_ADIAG
++ DSP_DGASP // DSP Message to indicate dying gasp
++};
++
++static unsigned char analogNoTonesTestArray[64]=
++ {
++ 0,0,0,0,0,0,0,0, // Tones 01-08
++ 0,0,0,0,0,0,0,0, // Tones 09-16
++ 0,0,0,0,0,0,0,0, // Tones 17-24
++ 0,0,0,0,0,0,0,0, // Tones 25-32
++ 0,0,0,0,0,0,0,0, // Tones 33-40
++ 0,0,0,0,0,0,0,0, // Tones 41-48
++ 0,0,0,0,0,0,0,0, // Tones 49-56
++ 0,0,0,0,0,0,0,0 // Tones 57-64
++ };
++
++static unsigned char analogAllTonesTestArray[64]=
++ {
++ 1,1,1,1,1,1,1,1, // Tones 01-08
++ 1,1,1,1,1,1,1,1, // Tones 09-16
++ 1,1,1,1,1,1,1,1, // Tones 17-24
++ 1,1,1,1,1,1,1,1, // Tones 25-32
++ 1,1,1,1,1,1,1,1, // Tones 33-40
++ 1,1,1,1,1,1,1,1, // Tones 41-48
++ 1,1,1,1,1,1,1,1, // Tones 49-56
++ 1,1,1,1,1,1,1,1 // Tones 57-64
++ };
++
++static unsigned char analogEvenTonesTestArray[64]=
++ {
++ 0,1,0,1,0,1,0,1, // Tones 01-08
++ 0,1,0,1,0,1,0,1, // Tones 09-16
++ 0,1,0,1,0,1,0,1, // Tones 17-24
++ 0,1,0,1,0,1,0,1, // Tones 25-32
++ 0,1,0,1,0,1,0,1, // Tones 33-40
++ 0,1,0,1,0,1,0,1, // Tones 41-48
++ 0,1,0,1,0,1,0,1, // Tones 49-56
++ 0,1,0,1,0,1,0,1 // Tones 57-64
++ };
++
++static unsigned char analogOddTonesTestArray[64]=
++ {
++ 1,0,1,0,1,0,1,0, // Tones 01-08
++ 1,0,1,0,1,0,1,0, // Tones 09-16
++ 1,0,1,0,1,0,1,0, // Tones 17-24
++ 1,0,1,0,1,0,1,0, // Tones 25-32
++ 1,0,1,0,1,0,1,0, // Tones 33-40
++ 1,0,1,0,1,0,1,0, // Tones 41-48
++ 1,0,1,0,1,0,1,0, // Tones 49-56
++ 1,0,1,0,1,0,1,0 // Tones 57-64
++ };
++
++unsigned int shim_osGetCpuFrequency(void)
++{
++ return 150;
++}
++
++static void tn7dsl_adiag(int Test, unsigned char *missingTones)
++{
++ int rc,cmd, tag;
++
++ rc = dslhal_diags_anlg_setMissingTones(pIhw,missingTones);
++ if(rc)
++ {
++ printk(" failed to set Missing town\n");
++ return;
++ }
++
++/*********** Start the actual test **********************/
++
++ if(Test==0)
++ {
++ printk("TX REVERB Test\n");
++ rc = dslhal_support_writeHostMailbox(pIhw, HOST_TXREVERB, 0, 0, 0);
++ if (rc)
++ {
++ printk("HOST_TXREVERB failed\n");
++ return;
++ }
++
++ }
++ if(Test==1)
++ {
++ dprintf(0,"TX MEDLEY Test\n");
++ rc = dslhal_support_writeHostMailbox(pIhw, HOST_TXMEDLEY, 0, 0, 0);
++ if (rc)
++ return;
++ }
++ dprintf(4,"dslhal_diags_anlg_testA() done\n");
++ return;
++}
++
++
++static void tn7dsl_diagnostic_test(char *data)
++{
++ if(!strcmp(data, "ADIAGRALL"))
++ {
++ printk("TX Reverb All tone\n");
++ tn7dsl_adiag(0,analogAllTonesTestArray);
++ return;
++ }
++ if(!strcmp(data, "ADIAGRNONE"))
++ {
++ printk("TX Reverb No tone\n");
++ tn7dsl_adiag(0,analogNoTonesTestArray);
++ return;
++ }
++ if(!strcmp(data, "ADIAGREVEN"))
++ {
++ printk("TX Reverb Even tone\n");
++ tn7dsl_adiag(0,analogEvenTonesTestArray);
++ return;
++ }
++ if(!strcmp(data, "ADIAGRODD"))
++ {
++ printk("TX Reverb Odd tone\n");
++ tn7dsl_adiag(0,analogOddTonesTestArray);
++ return;
++ }
++ if(!strcmp(data, "ADIAGMALL"))
++ {
++ printk("TX Mdelay All tone\n");
++ tn7dsl_adiag(1,analogAllTonesTestArray);
++ return;
++ }
++ if(!strcmp(data, "ADIAGMNONE"))
++ {
++ printk("TX Mdelay No tone\n");
++ tn7dsl_adiag(1,analogNoTonesTestArray);
++ return;
++ }
++ if(!strcmp(data, "ADIAGMEVEN"))
++ {
++ printk("TX Mdelay Even tone\n");
++ tn7dsl_adiag(1,analogEvenTonesTestArray);
++ return;
++ }
++ if(!strcmp(data, "ADIAGMODD"))
++ {
++ printk("TX Mdelay Odd tone\n");
++ tn7dsl_adiag(1,analogOddTonesTestArray);
++ return;
++ }
++ if(!strcmp(data, "ADIAGQUIET"))
++ {
++ dslhal_api_sendIdle(pIhw);
++ return;
++ }
++ if(!strncmp(data, "ADIAGRN", 7))
++ {
++ char tones[64], tmp[4];
++ int nth, i;
++
++ tmp[0]=data[7];
++ tmp[1]=data[8];
++ tmp[2]=data[9];
++
++ nth = os_atoi(tmp);
++
++ for(i=0;i<64;i++)
++ {
++ if(((i+1)% nth)==0)
++ {
++ tones[i]=0;
++ }
++ else
++ {
++ tones[i]=1;
++ }
++ }
++ printk("TX Reverb with %dth tones missing.\n", nth);
++ tn7dsl_adiag(0,tones);
++ return;
++ }
++ if(!strncmp(data, "ADIAGMN", 7))
++ {
++ char tones[64], tmp[4];
++ int nth, i;
++
++ tmp[0]=data[7];
++ tmp[1]=data[8];
++ tmp[2]=data[9];
++ nth = os_atoi(tmp);
++
++ for(i=0;i<64;i++)
++ {
++ if(((i+1)% nth)==0)
++ {
++ tones[i]=0;
++ }
++ else
++ {
++ tones[i]=1;
++ }
++ }
++ printk("TX Mdelay with %dth tones missing.\n", nth);
++ tn7dsl_adiag(1,tones);
++ return;
++ }
++
++
++}
++
++#endif
++
++static void
++tn7dsl_chng_modulation(void* data)
++{
++ //printk("DSL Modem Retraining\n");
++
++ if(!strcmp(data, "T1413"))
++ {
++ printk("retraining in T1413 mode\n");
++ dslhal_api_setTrainingMode(pIhw, T1413_MODE);
++ dslhal_api_sendQuiet(pIhw);
++ return;
++ }
++ if(!strcmp(data, "GDMT"))
++ {
++ dslhal_api_setTrainingMode(pIhw, GDMT_MODE);
++ dslhal_api_sendQuiet(pIhw);
++ return;
++ }
++ if(!strcmp(data, "GLITE"))
++ {
++ dslhal_api_setTrainingMode(pIhw, GLITE_MODE);
++ dslhal_api_sendQuiet(pIhw);
++ return;
++ }
++ if(!strcmp(data, "MMODE"))
++ {
++ dslhal_api_setTrainingMode(pIhw, MULTI_MODE);
++ dslhal_api_sendQuiet(pIhw);
++ return;
++ }
++ if(!strcmp(data, "NMODE"))
++ {
++ dslhal_api_setTrainingMode(pIhw, NO_MODE);
++ dslhal_api_sendQuiet(pIhw);
++ return;
++ }
++
++#ifdef ADIAG
++ tn7dsl_diagnostic_test(data);
++#endif
++
++
++ return;
++}
++
++#ifdef CONFIG_LED_MODULE
++static void tn7dsl_led_on(unsigned long parm)
++{
++ dslhal_api_configureLed(pIhw,parm, 0);
++}
++
++
++static void tn7dsl_led_off(unsigned long parm)
++{
++ dslhal_api_configureLed(pIhw,parm, 1);
++}
++
++static void tn7dsl_led_init(unsigned long parm)
++{
++ dslhal_api_configureLed(pIhw,parm, 2);
++}
++#endif
++
++static void tn7dsl_register_dslss_led(void)
++{
++#ifdef CONFIG_LED_MODULE
++
++ // register led0 with led module
++ ledreg[0].param = 0;
++ ledreg[0].init = (void *)tn7dsl_led_init;
++ ledreg[0].onfunc = (void *)tn7dsl_led_on;
++ ledreg[0].offfunc = (void *)tn7dsl_led_off;
++ register_led_drv(LED_NUM_1, &ledreg[0]);
++
++ // register led1 output with led module
++ ledreg[1].param = 1;
++ ledreg[1].init = (void *)tn7dsl_led_init;
++ ledreg[1].onfunc = (void *)tn7dsl_led_on;
++ ledreg[1].offfunc = (void *)tn7dsl_led_off;
++ register_led_drv(LED_NUM_2, &ledreg[1]);
++#endif
++}
++
++static int tn7dsl_reload_overlay(void)
++{
++ int overlayFlag;
++ spinlock_t overlayLock;
++
++ init_kthread(&overlay_thread, "adsl");
++ down(&adsl_sem_overlay);
++ while(1)
++ {
++ mdelay(500);
++ if(pIhw->lConnected == 0)
++ {
++ spin_lock_irqsave(&overlayLock, overlayFlag);
++ dslhal_support_restoreTrainingInfo(pIhw);
++ spin_unlock_irqrestore(&overlayLock, overlayFlag);
++ }
++ down(&adsl_sem_overlay);
++ }
++ return 0;
++}
++
++
++
++
+diff -urN linux.old/drivers/atm/sangam_atm/tn7sar.c linux.dev/drivers/atm/sangam_atm/tn7sar.c
+--- linux.old/drivers/atm/sangam_atm/tn7sar.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/tn7sar.c 2005-08-23 04:46:50.110841720 +0200
+@@ -0,0 +1,1376 @@
++/******************************************************************************
++ * FILE PURPOSE: OS files for CPSAR
++ ******************************************************************************
++ * FILE NAME: tn7sar.c
++ *
++ * DESCRIPTION: This file contains source for required os files for CPSAR
++ *
++ * (C) Copyright 2002, Texas Instruments Inc
++ *
++ *
++ * Revision History:
++ * 0/11/02 Zhicheng Tang, created.
++ *
++ *******************************************************************************/
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/atmdev.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/smp_lock.h>
++#include <asm/io.h>
++#include <asm/mips-boards/prom.h>
++#include <linux/proc_fs.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++
++
++#define _CPHAL_AAL5
++#define _CPHAL_SAR
++#define _CPHAL_HAL
++typedef void OS_PRIVATE;
++typedef void OS_DEVICE;
++typedef void OS_SENDINFO;
++typedef void OS_RECEIVEINFO;
++typedef void OS_SETUP;
++
++#include "cpswhal_cpsar.h"
++#include "tn7atm.h"
++#include "tn7api.h"
++
++
++/* PDSP Firmware files */
++#include "tnetd7300_sar_firm.h"
++
++
++enum
++{
++ PACKET_TYPE_AAL5,
++ PACKET_TYPE_NULL,
++ PACKET_TYPE_OAM,
++ PACKET_TYPE_TRANS,
++ PACKET_TYPE_AAL2
++}PACKET_TYPE;
++
++enum
++{
++ OAM_PING_FAILED,
++ OAM_PING_SUCCESS,
++ OAM_PING_PENDING,
++ OAM_PING_NOT_STARTED
++}OAM_PING;
++
++/* PDSP OAM General Purpose Registers (@todo: These need to be used in the HAL!) */
++
++#define SAR_PDSP_HOST_OAM_CONFIG_REG_ADDR 0xa3000020
++#define SAR_PDSP_OAM_CORR_REG_ADDR 0xa3000024
++#define SAR_PDSP_OAM_LB_RESULT_REG_ADDR 0xa3000028
++#define SAR_PDSP_OAM_F5LB_COUNT_REG_ADDR 0xa300002c
++#define SAR_PDSP_OAM_F4LB_COUNT_REG_ADDR 0xa3000030
++
++#define SAR_FREQUNCY 50000000
++
++#define AAL5_PARM "id=aal5, base = 0x03000000, offset = 0, int_line=15, ch0=[RxBufSize=1522; RxNumBuffers = 32; RxServiceMax = 50; TxServiceMax=50; TxNumBuffers=32; CpcsUU=0x5aa5; TxVc_CellRate=0x3000; TxVc_AtmHeader=0x00000640]"
++#define SAR_PARM "id=sar,base = 0x03000000, reset_bit = 9, offset = 0; UniNni = 0, PdspEnable = 1"
++#define RESET_PARM "id=ResetControl, base=0xA8611600"
++#define CH0_PARM "RxBufSize=1522, RxNumBuffers = 32, RxServiceMax = 50, TxServiceMax=50, TxNumBuffers=32, CpcsUU=0x5aa5, TxVc_CellRate=0x3000, TxVc_AtmHeader=0x00000640"
++
++#define MAX_PVC_TABLE_ENTRY 16
++
++sar_stat_t sarStat;
++
++typedef struct _channel_parm
++{
++ unsigned int RxBufSize;
++ unsigned int RxNumBuffers;
++ unsigned int RxServiceMax;
++ unsigned int TxServiceMax;
++ unsigned int TxNumBuffers;
++ unsigned int CpcsUU;
++ unsigned int TxVc_CellRate;
++ unsigned int TxVc_AtmHeader;
++}channel_parm_t;
++
++typedef struct _aal5_parm
++{
++ unsigned int base;
++ unsigned int offset;
++ unsigned int int_line;
++ channel_parm_t chan[8];
++}aal5_parm_t;
++
++
++typedef struct _sar_parm
++{
++ unsigned int base;
++ unsigned int reset_bit;
++ unsigned int offset;
++ unsigned int UniNni;
++}sar_parm_t;
++
++typedef struct _pvc_table
++{
++ int bInUse;
++ int vpi;
++ int vci;
++}pvc_table;
++
++static aal5_parm_t aal5Parm;
++static sar_parm_t sarParm;
++static char *pAal5, *pSar, *pReset;
++static int oam_type;
++static unsigned int oamPingStatus;
++static int oamAtmHdr;
++static int oamLbTimeout;
++static char parm_data[1024];
++static char aal5Data[1024];
++static char sarData[1024];
++static char resetData[256];
++static pvc_table pvc_result[MAX_PVC_TABLE_ENTRY];
++
++/* external function */
++extern int __guDbgLevel;
++
++/* gloabal function */
++unsigned int oamFarLBCount[4];
++/* end of gloabal function */
++
++/* internal APIs */
++static int tn7sar_atm_header(int vpi, int vci);
++static void tn7sar_record_pvc(int atmheader);
++
++/*end of internal APIs */
++spinlock_t sar_lock;
++
++/* HAL OS support functions */
++
++
++unsigned long tn7sar_strtoul(const char *str, char **endptr, int base)
++{
++ unsigned long ret;
++
++ ret= simple_strtoul(str, endptr, base);
++ return ret;
++}
++
++static void *tn7sar_malloc(unsigned int size)
++{
++ return(kmalloc(size, GFP_KERNEL));
++}
++
++static unsigned long lockflags;
++static void tn7sar_critical_on(void)
++{
++ spin_lock_irqsave(&sar_lock,lockflags);
++}
++
++static void tn7sar_critical_off(void)
++{
++ spin_unlock_irqrestore(&sar_lock,lockflags);
++}
++
++static void tn7sar_data_invalidate(void *pmem, int size)
++{
++ unsigned int i,Size=(((unsigned int)pmem)&0xf)+size;
++
++ for (i=0;i<Size;i+=16,pmem+=16)
++ {
++ __asm__(" .set mips3 ");
++ __asm__("cache 17, (%0)" : : "r" (pmem));
++ __asm__(" .set mips0 ");
++ }
++
++}
++
++static void tn7sar_data_writeback(void *pmem, int size)
++{
++ unsigned int i,Size=(((unsigned int)pmem)&0xf)+size;
++
++ for (i=0;i<Size;i+=16,pmem+=16)
++ {
++ __asm__(" .set mips3 ");
++ __asm__(" cache 25, (%0)" : : "r" (pmem));
++ __asm__(" .set mips0 ");
++ }
++}
++
++
++static int
++tn7sar_find_device(int unit, const char *find_name, void *device_info)
++{
++ int ret_val = 0;
++ char **ptr;
++
++ ptr = (char **)device_info;
++ dprintf(3,"tn7sar_find_device\n");
++ if(strcmp(find_name, "aal5")==0)
++ {
++ //dprintf(4,"pAal5=%s\n", pAal5);
++ *ptr = pAal5;
++ }
++ else if(strcmp(find_name, "sar")==0)
++ {
++ dprintf(3, "pSar=%s\n", pSar);
++ *ptr = pSar;
++ }
++ else if(strcmp(find_name, "reset")==0)
++ {
++ dprintf(3, "pReset=%s\n", pReset);
++ *ptr = pReset;
++ }
++
++ device_info = NULL;
++
++ return(ret_val);
++}
++
++static int
++tn7sar_get_device_parm_uint(void *dev_info, const char *param, unsigned int *value)
++{
++ char *dev_str;
++ char *pMatch;
++ int i=0, j=0;
++ char val_str[64];
++ unsigned int val;
++ int base = 10;
++
++ dprintf(6, "tn7sar_get_device_parm_uint()\n");
++
++ dev_str = (char *)dev_info;
++ dprintf(3, "parm=%s\n", param);
++ pMatch = strstr(dev_str, param);
++ //dprintf(4, "pMatch=%s\n", pMatch);
++ if(pMatch)
++ {
++ //get "=" position
++ while(pMatch[i] != 0x3d)
++ {
++ i++;
++ }
++ i++;
++ // get rid of spaces
++ while(pMatch[i]==0x20)
++ {
++ i++;
++ }
++ //get rid of 0x
++ if(pMatch[i]==0x30)
++ {
++ if(pMatch[i+1] == 0x58 || pMatch[i+1] == 0x78)
++ {
++ i+=2;
++ base = 16;
++ }
++ }
++
++ // get next delineator
++ while(pMatch[i] != 0x2c && pMatch[i] != 0x0)
++ {
++ val_str[j]=pMatch[i];
++ j++;
++ i++;
++ }
++ val_str[j]=0;
++ //dprintf(4, "val_str=\n%s\n", val_str);
++ //xdump(val_str, strlen(val_str) + 1, 4);
++ val = simple_strtoul(val_str, (char **)NULL, base);
++ dprintf(4, "val =%d\n", val);
++ *value = val;
++ return 0;
++ }
++
++
++ dprintf(3, "match not found.\n");
++ if(strcmp(dev_str, "debug")==0)
++ {
++ dprintf(6,"debug..\n");
++ *value = 6;
++ return 0;
++ }
++ return (1);
++}
++
++static int tn7sar_get_device_parm_value(void *dev_info, const char *param, void *value)
++{
++ char *dev_str;
++ char *pMatch;
++ int i=0, j=0;
++ char *pVal;
++
++
++ dprintf(3, "tn7sar_get_device_parm_value().\n");
++
++ pVal = (char *) parm_data;
++ dev_str = (char *)dev_info;
++ dprintf(3, "dev_info: \n%s\n", dev_str);
++ dprintf(3, "param=%s\n", param);
++ if(strcmp(param, "Ch0")==0)
++ {
++ *(char **)value = CH0_PARM;
++ dprintf(3, "value =%s\n", *(char **)value);
++ return 0;
++ }
++
++ pMatch = strstr(dev_str, param);
++ if(pMatch)
++ {
++ //get "=" position
++ while(pMatch[i] != 0x3d)
++ {
++ i++;
++ }
++ i++;
++ // get rid of spaces
++ while(pMatch[i]==0x20)
++ {
++ i++;
++ }
++
++ if(pMatch[i] != 0x5b) //"["
++ {
++ // get next delineator
++ while(pMatch[i] != 0x2c && pMatch[i] != 0x0)
++ {
++ pVal[j] = pMatch[i];
++ j++;
++ i++;
++ }
++ pVal[j]=0;
++
++ *(char **)value = pVal;
++ return 0;
++ }
++ else
++ {
++ i++; //skip "["
++ while(pMatch[i] != 0x5d)
++ {
++ if(pMatch[i] == 0x3b) //";"
++ pVal[j] = 0x2c;
++ else
++ pVal[j] = pMatch[i];
++ j++;
++ i++;
++ }
++ pVal[j] = 0;
++ *(char **)value = pVal;
++ return 0;
++ }
++
++ }
++
++ return (1);
++}
++
++static void tn7sar_free(void *pmem)
++{
++ kfree(pmem);
++}
++
++static void
++tn7sar_free_buffer(OS_RECEIVEINFO *os_receive_info, void *pmem)
++{
++ tn7atm_free_rx_skb(os_receive_info);
++}
++
++static void tn7sar_free_dev(void *pmem)
++{
++ kfree(pmem);
++}
++
++static void tn7sar_free_dma_xfer(void *pmem)
++{
++ kfree(pmem);
++}
++
++
++static int
++tn7sar_control(void *dev_info, const char *key, const char *action, void *value)
++{
++ int ret_val = -1;
++
++ if (strcmp(key, "Firmware") == 0)
++ {
++ if (strcmp(action, "Get") == 0)
++ {
++ *(int **)value = &SarPdspFirmware[0];
++ }
++ ret_val=0;
++ }
++
++ if (strcmp(key, "FirmwareSize") == 0)
++ {
++ if (strcmp(action, "Get") == 0)
++ {
++ *(int *)value = sizeof(SarPdspFirmware);
++ }
++ ret_val=0;
++ }
++
++ if (strcmp(key, "OamLbResult") == 0)
++ {
++ dprintf(2, "get looback source call back\n");
++ if (strcmp(action, "Set") == 0)
++ {
++ dprintf(2, "oam result = %d\n", *(unsigned int *)value);
++ oamFarLBCount[oam_type] = oamFarLBCount[oam_type] + *(unsigned int *)value;
++ if(oamPingStatus == OAM_PING_PENDING)
++ {
++ oamPingStatus = *(unsigned int *)value;
++ if(oamPingStatus == OAM_PING_SUCCESS)
++ {
++ /* record pvc */
++ tn7sar_record_pvc(oamAtmHdr);
++ }
++ }
++
++ }
++ ret_val=0;
++ }
++
++ if (strcmp(key, "SarFreq") == 0)
++ {
++ if (strcmp(action, "Get") == 0)
++ {
++ *(int *)value = SAR_FREQUNCY;
++ }
++ ret_val=0;
++ }
++ return(ret_val);
++}
++
++
++static void
++tn7sar_sarhal_isr_register(OS_DEVICE *os_dev, int(*hal_isr)(HAL_DEVICE *, int *), int interrupt_num)
++{
++ tn7atm_sarhal_isr_register(os_dev, hal_isr, interrupt_num);
++}
++
++static void
++tn7sar_isr_unregister(OS_DEVICE *os_dev, int interrupt_num)
++{
++ /* TODO */
++}
++
++
++static void *
++tn7sar_malloc_rxbuffer(unsigned int size, void *mem_base, unsigned int mem_range, HAL_DEVICE *hal_dev,
++ HAL_RECEIVEINFO *hal_info, OS_RECEIVEINFO **os_receive_info, OS_DEVICE *os_dev)
++{
++ return tn7atm_allocate_rx_skb(os_dev, os_receive_info, size);
++}
++
++static void *
++tn7sar_malloc_dev(unsigned int size)
++{
++ return(kmalloc(size, GFP_KERNEL));
++}
++
++static void *
++tn7sar_malloc_dma_xfer(unsigned int size, void *mem_base, unsigned int mem_range)
++{
++ dprintf(4, "tn7sar_malloc_dma_xfer, size =%d\n", size);
++
++ return (kmalloc(size, GFP_DMA |GFP_KERNEL));
++
++}
++
++static void *
++tn7sar_memset(void *dst, int set_char, size_t count)
++{
++ return (memset(dst, set_char, count));
++}
++
++static int tn7sar_printf(const char *format, ...)
++{
++ /* TODO: add debug levels */
++ static char buff[256];
++ va_list ap;
++
++ va_start( ap, format);
++ vsprintf((char *)buff, format, ap);
++ va_end(ap);
++
++ printk("SAR HAL: %s\n", buff);
++ return(0);
++}
++
++static void tn7sar_record_pvc(int atmheader)
++{
++ int vci,vpi;
++ int i;
++
++ vci = 0xffff & (atmheader >> 4);
++ vpi = 0xff & (atmheader >> 20);
++ for(i=0;i<MAX_PVC_TABLE_ENTRY;i++)
++ {
++ if(pvc_result[i].bInUse)
++ {
++ if(pvc_result[i].vpi == vpi && pvc_result[i].vci == vci)
++ {
++ return;
++ }
++ }
++ }
++ for(i=0;i<MAX_PVC_TABLE_ENTRY;i++)
++ {
++ if(pvc_result[i].bInUse == 0)
++ {
++ pvc_result[i].bInUse = 1;
++ pvc_result[i].vpi = vpi;
++ pvc_result[i].vci = vci;
++ return;
++ }
++ }
++ return;
++}
++
++static void tn7sar_clear_pvc_table(void)
++{
++ int i;
++
++ for(i=0;i<MAX_PVC_TABLE_ENTRY; i++)
++ {
++ pvc_result[i].bInUse = 0;
++ pvc_result[i].vpi = 0;
++ pvc_result[i].vci = 0;
++ }
++}
++
++int tn7sar_process_unmatched_oam(FRAGLIST *frag_list, unsigned int frag_count, unsigned int packet_size, unsigned int mode)
++{
++
++ FRAGLIST *local_list;
++ int i;
++ unsigned int atmHdr;
++
++ local_list = frag_list;
++
++ for(i=0;i<(int)frag_count;i++)
++ {
++ tn7sar_data_invalidate(local_list->data, (int)local_list->len);
++ local_list ++;
++ }
++ local_list = frag_list;
++ if((mode>>31)) /*vci, vpi is attached */
++ {
++ atmHdr = *(unsigned int *)frag_list->data;
++ tn7sar_record_pvc(atmHdr);
++ if(atmHdr & 0x8) //oam cell
++ {
++ atmHdr &= 0xfffffff0;
++ if(atmHdr == oamAtmHdr)
++ {
++ if(oamPingStatus == OAM_PING_PENDING)
++ {
++ oamPingStatus = OAM_PING_SUCCESS;
++ oamFarLBCount[oam_type] = oamFarLBCount[oam_type] + 1;
++ }
++ return 0;
++ }
++ }
++ }
++
++ return 0;
++}
++
++
++static int
++tn7sar_receive(OS_DEVICE *os_dev,FRAGLIST *frag_list, unsigned int frag_count, unsigned int packet_size,
++ HAL_RECEIVEINFO *hal_receive_info, unsigned int mode)
++{
++ int ch;
++ struct atm_dev *dev;
++ Tn7AtmPrivate *priv;
++ HAL_FUNCTIONS *pHalFunc;
++ HAL_DEVICE *pHalDev;
++ int bRet;
++
++
++ dprintf(4, "tn7sar_receive\n");
++
++ dev = (struct atm_dev *)os_dev;
++ priv= (Tn7AtmPrivate *)dev->dev_data;
++ pHalFunc = (HAL_FUNCTIONS *)priv->pSarHalFunc;
++ pHalDev = (HAL_DEVICE *)priv->pSarHalDev;
++
++
++ /* Mode contains channel info */
++ ch = (mode & 0xFF);
++
++ if(ch == 15)
++ {
++ tn7sar_process_unmatched_oam(frag_list, frag_count, packet_size, mode);
++ pHalFunc->RxReturn(hal_receive_info, 0);
++ return 0;
++ }
++
++ if(frag_count > 1 || frag_list->len == 0)
++ {
++ printk("Packet fragment count > 1, not handdle.\n");
++ return 1;
++ }
++
++ tn7sar_data_invalidate(frag_list->data, (int)frag_list->len);
++ bRet=tn7atm_receive(os_dev, ch, packet_size, frag_list->OsInfo, frag_list->data);
++
++ if(bRet==0)
++ {
++ sarStat.rxPktCnt++;
++ sarStat.rxBytes += packet_size;
++ pHalFunc->RxReturn(hal_receive_info, 1);
++ }
++ else
++ {
++ pHalFunc->RxReturn(hal_receive_info, 0);
++ }
++
++ return bRet;
++}
++
++static int
++tn7sar_send_complete(OS_SENDINFO *osSendInfo)
++{
++ return (tn7atm_send_complete(osSendInfo));
++}
++
++void
++tn7sar_teardown_complete(OS_DEVICE *OsDev, int ch, int Dir)
++{
++ return;
++}
++
++
++/*
++unsigned int tn7sar_virt(unsigned int address)
++{
++ return phys_to_virt(address);
++}
++*/
++
++int tn7sar_init_module(OS_FUNCTIONS *os_funcs)
++{
++ dprintf(4, "tn7sar_init_module\n");
++ if( os_funcs == 0 )
++ {
++ return(-1);
++ }
++ os_funcs->Control = tn7sar_control;
++ os_funcs->CriticalOn = tn7sar_critical_on;
++ os_funcs->CriticalOff = tn7sar_critical_off;
++ os_funcs->DataCacheHitInvalidate = tn7sar_data_invalidate;
++ os_funcs->DataCacheHitWriteback = tn7sar_data_writeback;
++ os_funcs->DeviceFindInfo = tn7sar_find_device;
++ os_funcs->DeviceFindParmUint = tn7sar_get_device_parm_uint;
++ os_funcs->DeviceFindParmValue = tn7sar_get_device_parm_value;
++ os_funcs->Free = tn7sar_free;
++ os_funcs->FreeRxBuffer = tn7sar_free_buffer;
++ os_funcs->FreeDev = tn7sar_free_dev;
++ os_funcs->FreeDmaXfer = tn7sar_free_dma_xfer;
++ os_funcs->IsrRegister = tn7sar_sarhal_isr_register;
++ os_funcs->IsrUnRegister = tn7sar_isr_unregister;
++ os_funcs->Malloc = tn7sar_malloc;
++ os_funcs->MallocRxBuffer = tn7sar_malloc_rxbuffer;
++ os_funcs->MallocDev = tn7sar_malloc_dev;
++ os_funcs->MallocDmaXfer = tn7sar_malloc_dma_xfer;
++ os_funcs->Memset = tn7sar_memset;
++ os_funcs->Printf = tn7sar_printf;
++ os_funcs->Receive = tn7sar_receive;
++ os_funcs->SendComplete = tn7sar_send_complete;
++ os_funcs->Strcmpi = strcmp;
++ os_funcs->Sprintf = sprintf;
++ os_funcs->Strlen = strlen;
++ os_funcs->Strstr = strstr;
++ os_funcs->Strtoul = tn7sar_strtoul;
++ os_funcs->TeardownComplete = tn7sar_teardown_complete;
++
++ return(0);
++}
++
++
++static void tn7sar_init_dev_parm(void)
++{
++ int i;
++
++
++ /* aal5 */
++ //strcpy(aal5Parm.id, "aal5");
++ aal5Parm.base = 0x03000000;
++ aal5Parm.offset = 0;
++ aal5Parm.int_line=15;
++ aal5Parm.chan[0].RxBufSize=1600;
++ aal5Parm.chan[0].RxNumBuffers = 32;
++ aal5Parm.chan[0].RxServiceMax = 50;
++ aal5Parm.chan[0].TxServiceMax=50;
++ aal5Parm.chan[0].TxNumBuffers=32;
++ aal5Parm.chan[0].CpcsUU=0x5aa5;
++ aal5Parm.chan[0].TxVc_CellRate=0x3000;
++ aal5Parm.chan[0].TxVc_AtmHeader=0x00000640;
++ for(i=1;i<8;i++)
++ {
++ memcpy(&aal5Parm.chan[i], &aal5Parm.chan[0], sizeof(aal5Parm.chan[0]));
++ }
++
++
++ /* sar */
++ //strcpy(sarParm.id, "sar");
++ sarParm.base = 0x03000000;
++ sarParm.reset_bit = 9;
++ sarParm.offset = 0;
++ sarParm.UniNni = 0;
++
++ pAal5 = aal5Data;
++ pSar = sarData;
++ pReset = resetData;
++ strcpy(pAal5, AAL5_PARM);
++ strcpy(pSar, SAR_PARM);
++ strcpy(pReset, RESET_PARM);
++
++}
++
++
++int tn7sar_get_stats(void *priv1)
++{
++ HAL_FUNCTIONS *pHalFunc;
++ HAL_DEVICE *pHalDev;
++ Tn7AtmPrivate *priv;
++ int i, j;
++ unsigned int *pSarStat, *pStateBase;
++ char statString[64];
++ int len;
++
++ dprintf(2, "tn7sar_get_stats\n");
++
++ priv = (Tn7AtmPrivate *)priv1;
++ pHalFunc = (HAL_FUNCTIONS *)priv->pSarHalFunc;
++ pHalDev = (HAL_DEVICE *)priv->pSarHalDev;
++
++ //memset(&sarStat, 0, sizeof(sarStat));
++ sarStat.txErrors = 0;
++ sarStat.rxErrors = 0;
++ for(i=0;i<MAX_DMA_CHAN;i++)
++ {
++ if(priv->lut[i].inuse)
++ {
++ for(j=0;j<1;j++)
++ {
++ len=sprintf(statString, "Stats;0;%d", priv->lut[i].chanid);
++ statString[len]=0;
++ dprintf(2, "statString=%s\n",statString);
++ pHalFunc->Control(pHalDev, statString, "Get", &pSarStat);
++ pStateBase = pSarStat;
++ while(pSarStat)
++ {
++ if((char *)*pSarStat == NULL)
++ break;
++ dprintf(2, "%s\n", (char *) *pSarStat);
++ pSarStat++;
++ dprintf(2, "%s\n", (char *) *pSarStat);
++ sarStat.rxErrors += os_atoul((char *) *pSarStat);
++ pSarStat++;
++ }
++
++ kfree(pStateBase);
++ }
++ }
++ }
++ return 0;
++}
++
++int tn7sar_setup_oam_channel(Tn7AtmPrivate *priv)
++{
++
++ CHANNEL_INFO chInfo;
++ HAL_FUNCTIONS *pHalFunc;
++ HAL_DEVICE *pHalDev;
++ int chan=15;
++ dprintf(4, "tn7sar_setup_oam_channel\n");
++
++ pHalFunc = (HAL_FUNCTIONS *)priv->pSarHalFunc;
++ pHalDev = (HAL_DEVICE *)priv->pSarHalDev;
++
++ memset(&chInfo, 0xff, sizeof(chInfo));
++
++ /* channel specific */
++ chInfo.Channel = 15; /* hardcoded for last channel */
++ chInfo.Direction = 0;
++ chInfo.Vci = 30; /* just need below 32 */
++ chInfo.Vpi = 0;
++ chInfo.TxVc_QosType = 2;
++
++ /*default */
++ chInfo.PktType = PACKET_TYPE_TRANS;
++ chInfo.TxServiceMax = 2;
++ chInfo.RxServiceMax = 2;
++ chInfo.TxNumQueues = 1;
++ chInfo.TxNumBuffers = 4;
++ chInfo.RxNumBuffers = 4;
++ chInfo.RxBufSize = 256;
++ chInfo.RxVc_OamToHost = 0;
++ chInfo.RxVp_OamToHost = 0;
++ chInfo.FwdUnkVc = 1; //enable forwarding of unknown vc
++ chInfo.TxVc_AtmHeader = tn7sar_atm_header((int)chInfo.Vpi, chInfo.Vci);
++ chInfo.RxVc_AtmHeader = tn7sar_atm_header((int)chInfo.Vpi, chInfo.Vci);
++ chInfo.TxVp_AtmHeader = tn7sar_atm_header((int)chInfo.Vpi, 0);
++ chInfo.RxVp_AtmHeader = tn7sar_atm_header((int)chInfo.Vpi, 0);
++
++ dprintf(4, "TxVc_AtmHeader=0x%x\n", chInfo.TxVc_AtmHeader);
++
++ if(pHalFunc->ChannelSetup(pHalDev, &chInfo, NULL))
++ {
++ printk("failed to setup channel =%d.\n", chan);
++ return -1;
++ }
++
++ // claiming the channel
++ priv->lut[chan].vpi = 0;
++ priv->lut[chan].vci = 30;
++ priv->lut[chan].chanid = chan;
++ priv->lut[chan].inuse = 1;
++ return 0;
++}
++
++int tn7sar_init(struct atm_dev *dev, Tn7AtmPrivate *priv)
++{
++ int retCode;
++ int hal_funcs_size;
++
++ HAL_FUNCTIONS *pHalFunc;
++ HAL_DEVICE *pHalDev;
++ OS_FUNCTIONS *pOsFunc;
++ int oamMod;
++ char *pLbTimeout;
++ int lbTimeout;
++
++
++ dprintf(4, "tn7sar_init\n");
++
++ pOsFunc = (OS_FUNCTIONS *)kmalloc(sizeof(OS_FUNCTIONS), GFP_KERNEL);
++
++
++ priv->pSarOsFunc = ( void *)pOsFunc;
++
++ /* init boot parms */
++ tn7sar_init_dev_parm();
++
++ /* init sar os call back functions */
++ retCode = tn7sar_init_module(pOsFunc);
++ if (retCode != 0) /* error */
++ {
++ printk("Failed to init SAR OS Functions\n");
++ return (1);
++ }
++
++ /* Init sar hal */
++ retCode = cpaal5InitModule(&pHalDev, (OS_DEVICE*) dev, &pHalFunc,
++ pOsFunc, sizeof(OS_FUNCTIONS), &hal_funcs_size, 0);
++ if (retCode != 0) /* error */
++ {
++ printk("Failed to init SAR HAL\n");
++ return (1);
++ }
++
++ /* sanity check */
++ if (pHalDev == NULL || pHalFunc == NULL || hal_funcs_size != sizeof(HAL_FUNCTIONS) )
++ {
++ printk("Invalid SAR hal and/or functions.\n");
++ return (1);
++ }
++
++ /* remeber HAL pointers */
++ priv->pSarHalDev = (void *)pHalDev;
++ priv->pSarHalFunc = (void *)pHalFunc;
++
++ /* Probe for the Device to get hardware info from driver */
++ retCode = pHalFunc->Probe(pHalDev);
++ if (retCode !=0)
++ {
++ printk("SAR hal probing error.\n");
++ return (1);
++ }
++
++ /* init sar hal */
++ retCode = pHalFunc->Init(pHalDev);
++ if (retCode != 0) /* error */
++ {
++
++ printk("pHalFunc->Init failed. err code =%d\n", retCode);
++ return (1);
++ }
++
++ /* open hal module */
++ retCode = pHalFunc->Open(pHalDev);
++ if (retCode != 0) /* error */
++ {
++ printk("pHalFunc->open failed, err code: %d\n",retCode );
++ return (1);
++ }
++
++ /* init sar for firmware oam */
++ oamMod= 1;
++ pHalFunc->Control(pHalDev,"OamMode", "Set", &oamMod);
++
++ /* read in oam lb timeout value */
++ pLbTimeout = prom_getenv("oam_lb_timeout");
++ if(pLbTimeout)
++ {
++ lbTimeout =tn7sar_strtoul(pLbTimeout, NULL, 10);
++ oamLbTimeout = lbTimeout;
++ pHalFunc->Control(pHalDev,"OamLbTimeout", "Set", &lbTimeout);
++ }
++ else
++ {
++ oamLbTimeout = 5000;
++ }
++
++ oamFarLBCount[0]=0;
++ oamFarLBCount[1]=0;
++ oamFarLBCount[2]=0;
++ oamFarLBCount[3]=0;
++
++ memset(&sarStat, 0 , sizeof(sarStat));
++
++ /* setup channel 15 for oam operation */
++ tn7sar_setup_oam_channel(priv);
++ dprintf(4, "tn7sar_init done");
++ return 0;
++}
++
++static int
++tn7sar_atm_header(int vpi, int vci)
++{
++ union
++ {
++ unsigned char byte[4];
++ unsigned int dword;
++ }atm_h;
++ int itmp = 0;
++
++ //vci
++ itmp = vci &0xf;
++ atm_h.byte[0] = 0;
++ atm_h.byte[0] |= (itmp << 4);
++ atm_h.byte[1] = ((vci & 0xff0) >> 4);
++ atm_h.byte[2] = 0;
++ atm_h.byte[2] |= ((vci & 0xf000) >>12);;
++ atm_h.byte[2] |= ((vpi & 0xf) << 4);
++ atm_h.byte[3] = 0;
++ atm_h.byte[3] = ((vpi & 0xff0) >> 4);
++ return atm_h.dword;
++}
++
++int tn7sar_activate_vc(Tn7AtmPrivate *priv, short vpi, int vci, int pcr, int scr, int mbs, int cdvt, int chan, int qos)
++{
++ CHANNEL_INFO chInfo;
++ HAL_FUNCTIONS *pHalFunc;
++ HAL_DEVICE *pHalDev;
++
++ dprintf(4, "tn7sar_activate_vc\n");
++
++ pHalFunc = (HAL_FUNCTIONS *)priv->pSarHalFunc;
++ pHalDev = (HAL_DEVICE *)priv->pSarHalDev;
++
++ memset(&chInfo, 0xff, sizeof(chInfo));
++
++ /* channel specific */
++ chInfo.Channel = chan;
++ chInfo.Direction = 0;
++ chInfo.Vci = vci;
++ chInfo.Vpi = vpi;
++ chInfo.TxVc_QosType = qos;
++ chInfo.Priority = qos;
++
++ if(chInfo.TxVc_QosType == 1) /* if the connection is VBR than set the DaMask value to tell the schedular to accumalte the credit */
++ {
++ chInfo.DaMask = 1;
++ }
++ chInfo.TxVc_Mbs = mbs; /* use pcr as MBS */
++ pcr = SAR_FREQUNCY/pcr;
++ scr = SAR_FREQUNCY/scr;
++ chInfo.TxVc_CellRate = scr;
++ chInfo.TxVc_Pcr = pcr;
++
++ /*default */
++ chInfo.PktType = PACKET_TYPE_AAL5;
++ chInfo.TxServiceMax = TX_SERVICE_MAX;
++ chInfo.RxServiceMax = RX_SERVICE_MAX;
++ chInfo.TxNumQueues = TX_QUEUE_NUM;
++ chInfo.TxNumBuffers = TX_BUFFER_NUM;
++ chInfo.RxNumBuffers = RX_BUFFER_NUM;
++ chInfo.RxBufSize = RX_BUFFER_SIZE;
++ chInfo.RxVc_OamToHost = 0;
++ chInfo.RxVp_OamToHost = 0;
++ chInfo.TxVc_AtmHeader = tn7sar_atm_header((int)vpi, vci);
++ chInfo.RxVc_AtmHeader = tn7sar_atm_header((int)vpi, vci);
++ chInfo.TxVp_AtmHeader = tn7sar_atm_header((int)vpi, 0);
++ chInfo.RxVp_AtmHeader = tn7sar_atm_header((int)vpi, 0);
++ chInfo.CpcsUU = 0;
++
++ dprintf(4, "TxVc_AtmHeader=0x%x\n", chInfo.TxVc_AtmHeader);
++
++ if(pHalFunc->ChannelSetup(pHalDev, &chInfo, NULL))
++ {
++ printk("failed to setup channel =%d.\n", chan);
++ return -1;
++ }
++
++
++ return 0;
++}
++
++int tn7sar_send_packet(Tn7AtmPrivate *priv, int chan, void *new_skb, void *data,unsigned int len, int priority)
++{
++ FRAGLIST fragList;
++ unsigned int mode;
++ HAL_FUNCTIONS *pHalFunc;
++ HAL_DEVICE *pHalDev;
++
++ dprintf(4, "tn7sar_send_packet\n");
++ pHalFunc = (HAL_FUNCTIONS *)priv->pSarHalFunc;
++ pHalDev = (HAL_DEVICE *)priv->pSarHalDev;
++
++ fragList.len = len;
++ fragList.data = (void *)data;
++
++ xdump((char *)fragList.data , fragList.len, 6);
++
++ /*mode bit
++ 31-19 unused
++ 18 oam cell, 1 = true, 0=false
++ 17-16 oam type, 0=F4 seg, 1=F4 End, 2=F5 seg, 3=F5 end
++ 15-08 transimit queue, current, 0=priority queue, 1=normal queue
++ 07-00 channel number
++ */
++ mode = 0;
++ mode |= (0xff & chan);
++ mode |= ((0xff & priority) << 8);
++
++ dprintf(4, "mode = %d\n", mode);
++
++ tn7sar_data_writeback(fragList.data, len);
++ if(pHalFunc->Send(pHalDev, &fragList, 1, len, new_skb, mode) != 0)
++ {
++ dprintf(1, "SAR hal failed to send packet.\n");
++ return 1;
++ }
++ //tn7sar_get_stats(priv);
++ sarStat.txPktCnt++;
++ sarStat.txBytes +=len;
++ return 0;
++}
++
++
++
++int tn7sar_handle_interrupt(struct atm_dev *dev, Tn7AtmPrivate *priv)
++{
++ int more;
++ int rc;
++ HAL_FUNCTIONS *pHalFunc;
++ HAL_DEVICE *pHalDev;
++ int (*halIsr)(HAL_DEVICE *halDev, int *work);
++
++ pHalFunc = (HAL_FUNCTIONS *)priv->pSarHalFunc;
++ pHalDev = (HAL_DEVICE *)priv->pSarHalDev;
++ halIsr = priv->halIsr;
++
++ rc = halIsr(pHalDev, &more);
++
++ pHalFunc->PacketProcessEnd(pHalDev);
++
++ return rc;
++}
++
++
++int tn7sar_deactivate_vc(Tn7AtmPrivate *priv, int chan)
++{
++ unsigned int mode;
++ HAL_FUNCTIONS *pHalFunc;
++ HAL_DEVICE *pHalDev;
++
++ dprintf(4, "tn7sar_deactivate_vc\n");
++ pHalFunc = (HAL_FUNCTIONS *)priv->pSarHalFunc;
++ pHalDev = (HAL_DEVICE *)priv->pSarHalDev;
++
++ mode = 0xf; //tear down everything, wait for return;
++
++ pHalFunc->ChannelTeardown(pHalDev, chan, mode);
++ return 0;
++}
++
++void tn7sar_exit(struct atm_dev *dev, Tn7AtmPrivate *priv)
++{
++ HAL_FUNCTIONS *pHalFunc;
++ HAL_DEVICE *pHalDev;
++
++ dprintf(4, "tn7sar_exit()\n");
++
++ pHalFunc = (HAL_FUNCTIONS *)priv->pSarHalFunc;
++ pHalDev = (HAL_DEVICE *)priv->pSarHalDev;
++
++ tn7sar_deactivate_vc(priv, 15); // de-activate oam channel
++
++ pHalFunc->Close(pHalDev, 2);
++ pHalFunc->Shutdown(pHalDev);
++
++ kfree(priv->pSarOsFunc);
++
++}
++
++void tn7sar_get_sar_version(Tn7AtmPrivate *priv, char **pVer)
++{
++ HAL_FUNCTIONS *pHalFunc;
++ HAL_DEVICE *pHalDev;
++
++ dprintf(4, "tn7sar_get_sar_version()\n");
++
++ pHalFunc = (HAL_FUNCTIONS *)priv->pSarHalFunc;
++ pHalDev = (HAL_DEVICE *)priv->pSarHalDev;
++ pHalFunc->Control(pHalDev, "Version", "Get", pVer);
++}
++
++
++int tn7sar_get_near_end_loopback_count(unsigned int *pF4count, unsigned int *pF5count)
++{
++ unsigned int f4c, f5c;
++
++ f4c = *(volatile unsigned int *)SAR_PDSP_OAM_F4LB_COUNT_REG_ADDR;
++ f5c = *(volatile unsigned int *)SAR_PDSP_OAM_F5LB_COUNT_REG_ADDR;
++ *pF4count = f4c;
++ *pF5count = f5c;
++
++ return 0;
++}
++
++
++int tn7sar_unmatched_oam_generation(void *privContext, int vpi, int vci, int type)
++{
++
++ unsigned int regv = 0;
++ int chan=15;
++ static unsigned int tag;
++ HAL_FUNCTIONS *pHalFunc;
++ HAL_DEVICE *pHalDev;
++ Tn7AtmPrivate *priv;
++ unsigned int llid[4]={0xffffffff,0xffffffff,0xffffffff,0xffffffff};
++
++ dprintf(4, "tn7sar_unknow_oam_generation()\n");
++
++ priv = (Tn7AtmPrivate *)privContext;
++ pHalFunc = (HAL_FUNCTIONS *)priv->pSarHalFunc;
++ pHalDev = (HAL_DEVICE *)priv->pSarHalDev;
++
++ if(vci==0)
++ {
++ oamPingStatus = OAM_PING_FAILED;
++ return 0;
++ }
++ /* calculate atm header */
++ oamAtmHdr = tn7sar_atm_header(vpi,vci);
++
++ /* config the atm header */
++ pHalFunc->Control(pHalDev,"TxVc_AtmHeader.15", "Set", &oamAtmHdr);
++
++ /*record oam type */
++ oam_type = type;
++
++ regv = (0xff & chan);
++
++ switch(type)
++ {
++ case 0:
++ regv |= (1<<12); //f5 end
++ dprintf(2, "f5 loop back\n");
++ break;
++ case 1:
++ regv |= (1<<13); // f4 end
++ break;
++ case 2:
++ regv |= (1<<14); //f5 seg
++ break;
++ case 3:
++ regv |= (1<<15); //f4 seg
++ break;
++ default:
++ break;
++ }
++ oamPingStatus = OAM_PING_PENDING;
++ pHalFunc->OamLoopbackConfig(pHalDev, regv, llid, tag);
++ tag++;
++ return 0;
++
++}
++
++int tn7sar_oam_generation(void *privContext, int chan, int type, int vpi, int vci, int timeout)
++{
++ unsigned int regv = 0;
++ static unsigned int tag;
++ HAL_FUNCTIONS *pHalFunc;
++ HAL_DEVICE *pHalDev;
++ Tn7AtmPrivate *priv;
++ unsigned int llid[4]={0xffffffff,0xffffffff,0xffffffff,0xffffffff};
++
++ dprintf(2, "tn7sar_oam_generation()\n");
++
++ priv = (Tn7AtmPrivate *)privContext;
++ pHalFunc = (HAL_FUNCTIONS *)priv->pSarHalFunc;
++ pHalDev = (HAL_DEVICE *)priv->pSarHalDev;
++
++ if(timeout >= 5000)
++ {
++ if(timeout == 6000)
++ {
++ tn7sar_clear_pvc_table();
++ return 0;
++ }
++ timeout = oamLbTimeout;
++ }
++
++
++ pHalFunc->Control(pHalDev,"OamLbTimeout", "Set", &timeout);
++
++ if(chan == ATM_NO_DMA_CHAN)
++ {
++ tn7sar_unmatched_oam_generation(priv, vpi, vci, type);
++ return 0;
++ }
++
++ /* calculate atm header */
++ oamAtmHdr = tn7sar_atm_header(vpi,vci);
++
++ oam_type = type;
++
++ regv = (0xff & chan);
++ switch(type)
++ {
++ case 0:
++ regv |= (1<<12); //f5 end
++ dprintf(2, "f5 loop back\n");
++ break;
++ case 1:
++ regv |= (1<<13); // f4 end
++ break;
++ case 2:
++ regv |= (1<<14); //f5 seg
++ break;
++ case 3:
++ regv |= (1<<15); //f4 seg
++ break;
++ default:
++ break;
++ }
++ oamPingStatus = OAM_PING_PENDING;
++ pHalFunc->OamLoopbackConfig(pHalDev, regv, llid, tag);
++ tag++;
++
++ return 0;
++}
++
++int tn7sar_proc_oam_ping(char* buf, char **start, off_t offset, int count,int *eof, void *data)
++{
++ int len = 0;
++
++ len += sprintf(buf+len, "%d\n", oamPingStatus);
++
++ return len;
++}
++
++int tn7sar_proc_pvc_table(char* buf, char **start, off_t offset, int count,int *eof, void *data)
++{
++ int len = 0;
++ int i;
++
++ for(i=0;i<16;i++)
++ {
++ if(pvc_result[i].bInUse)
++ {
++ len += sprintf(buf+len, "%d,%d\n", pvc_result[i].vpi,pvc_result[i].vci);
++ }
++ else
++ {
++ len += sprintf(buf+len, "0,0\n");
++ }
++ }
++ return len;
++}
++
++
++
++int tn7sar_proc_sar_stat(char* buf, char **start, off_t offset, int count,int *eof, void *data)
++{
++ int len = 0;
++ int limit = count - 80;
++ struct atm_dev *dev;
++ Tn7AtmPrivate *priv;
++ int i, j, k;
++ int stat_len;
++ char statString[32];
++ unsigned int *pStateBase, *pSarStat;
++ HAL_FUNCTIONS *pHalFunc;
++ HAL_DEVICE *pHalDev;
++ int dBytes;
++
++ dev = (struct atm_dev *)data;
++ priv = (Tn7AtmPrivate *)dev->dev_data;
++
++ pHalFunc = (HAL_FUNCTIONS *)priv->pSarHalFunc;
++ pHalDev = (HAL_DEVICE *)priv->pSarHalDev;
++
++ len += sprintf(buf+len, "SAR HAL Statistics\n");
++ for(i=0;i<MAX_DMA_CHAN;i++)
++ {
++ if(priv->lut[i].inuse)
++ {
++ if(len<=limit)
++ len += sprintf(buf+len, "\nChannel %d:\n",priv->lut[i].chanid);
++ k=0;
++ for(j=0;j<4;j++)
++ {
++ stat_len =sprintf(statString, "Stats;%d;%d", j,priv->lut[i].chanid);
++ statString[stat_len]=0;
++ pHalFunc->Control(pHalDev, statString, "Get", &pSarStat);
++ pStateBase = pSarStat;
++ while(pSarStat)
++ {
++ if((char *)*pSarStat == NULL)
++ break;
++ if(len<=limit)
++ {
++ dBytes = sprintf(buf+len, "%s: ",(char *) *pSarStat);
++ len += dBytes;
++ k += dBytes;
++ }
++ pSarStat++;
++ if(len<=limit)
++ {
++ dBytes = sprintf(buf+len, "%s; ",(char *) *pSarStat);
++ len += dBytes;
++ k += dBytes;
++ }
++ pSarStat++;
++
++ if(k > 60)
++ {
++ k=0;
++ if(len<=limit)
++ len += sprintf(buf+len, "\n");
++ }
++ }
++
++ kfree(pStateBase);
++ }
++ }
++ }
++
++ return len;
++}
++
++void tn7sar_get_sar_firmware_version(unsigned int *pdsp_version_ms, unsigned int *pdsp_version_ls)
++{
++
++ *pdsp_version_ms = (SarPdspFirmware[9]>>20) & 0xF;
++ *pdsp_version_ls = (SarPdspFirmware[9]>>12) & 0xFF;
++ return;
++}
+diff -urN linux.old/drivers/atm/sangam_atm/tnetd7300_sar_firm.h linux.dev/drivers/atm/sangam_atm/tnetd7300_sar_firm.h
+--- linux.old/drivers/atm/sangam_atm/tnetd7300_sar_firm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/tnetd7300_sar_firm.h 2005-08-23 04:46:50.111841568 +0200
+@@ -0,0 +1,988 @@
++//SarPdspFirmware Revision: 49
++
++static int SarPdspFirmware[] = {
++ 0xb0a8d1f1,
++ 0x000003d8,
++ 0x00000000,
++ 0x00000004,
++ 0x00000000,
++ 0x00000000,
++ 0x00000000,
++ 0x00000000,
++ 0x21000900,
++ 0x24049080,
++ 0x24000080,
++ 0x240000c0,
++ 0x10e0e0e1,
++ 0x10e0e0e2,
++ 0x10e0e0e3,
++ 0x10e0e0e4,
++ 0x10e0e0e5,
++ 0x10e0e0e6,
++ 0x10e0e0e7,
++ 0x10e0e0e8,
++ 0x10e0e0e9,
++ 0x10e0e0ea,
++ 0x10e0e0eb,
++ 0x10e0e0ec,
++ 0x10e0e0ed,
++ 0x10e0e0ee,
++ 0x10e0e0ef,
++ 0x10e0e0f0,
++ 0x10e0e0f1,
++ 0x10e0e0f2,
++ 0x10e0e0f3,
++ 0x10e0e0f4,
++ 0x10e0e0f5,
++ 0x10e0e0f6,
++ 0x10e0e0f7,
++ 0x10e0e0f8,
++ 0x10e0e0f9,
++ 0x10e0e0fa,
++ 0x10e0e0fb,
++ 0x10e0e0fc,
++ 0x10e0e0fd,
++ 0x10e0e0fe,
++ 0x10e0e0ff,
++ 0x81042680,
++ 0x810c2680,
++ 0x81042680,
++ 0x2483c080,
++ 0x81180b80,
++ 0x2484c080,
++ 0x811a0b80,
++ 0x2485c080,
++ 0x811c0b80,
++ 0x240100dd,
++ 0xa07d06fd,
++ 0x240400dd,
++ 0xa07d04fd,
++ 0x24c000dd,
++ 0x2400169d,
++ 0xa07d5cfd,
++ 0x511f9d03,
++ 0x01019d9d,
++ 0x7f0000fd,
++ 0xd11eff05,
++ 0x97c06890,
++ 0x1d00e5e5,
++ 0x2301229e,
++ 0x81bc2890,
++ 0x24000000,
++ 0xc917ff02,
++ 0x81000100,
++ 0x01010000,
++ 0xc918ff02,
++ 0x81000100,
++ 0x01010000,
++ 0xc919ff02,
++ 0x81000100,
++ 0xd110e70a,
++ 0xd11cff09,
++ 0x1d00e5e5,
++ 0xd100e704,
++ 0xd114ff06,
++ 0x2301179e,
++ 0x79000004,
++ 0xd70ffffd,
++ 0x91382486,
++ 0x2301059e,
++ 0xc903ff07,
++ 0xa06047e0,
++ 0xb10043e6,
++ 0xc910e602,
++ 0x81000106,
++ 0x24006025,
++ 0x2300d39e,
++ 0xd11dff09,
++ 0x1f00e5e5,
++ 0xc901e705,
++ 0xd111ff06,
++ 0x91382586,
++ 0x2301059e,
++ 0x79000003,
++ 0xd715fffc,
++ 0x2301179e,
++ 0xc910e706,
++ 0x110f2760,
++ 0x240000c6,
++ 0x24000086,
++ 0x13106006,
++ 0x7b00005a,
++ 0x11079f80,
++ 0x51008010,
++ 0xc912ff0f,
++ 0xd100ff04,
++ 0xd101ff05,
++ 0xa06046e0,
++ 0x79000004,
++ 0xa06044e0,
++ 0x79000002,
++ 0xa06045e0,
++ 0xb10043e6,
++ 0x61150602,
++ 0x2101c500,
++ 0xc910e602,
++ 0xa1001006,
++ 0x24000025,
++ 0x2300d39e,
++ 0xd11fff05,
++ 0x97c06a90,
++ 0x1f00e5e5,
++ 0x2301229e,
++ 0x81bc2a90,
++ 0xd11cff09,
++ 0x1d00e5e5,
++ 0xc900e705,
++ 0xd10fff06,
++ 0x91382486,
++ 0x2301059e,
++ 0x79000003,
++ 0xd714fffc,
++ 0x2301179e,
++ 0xc907ff07,
++ 0xa0604be0,
++ 0xb10043e6,
++ 0xc910e602,
++ 0x81000106,
++ 0x24006025,
++ 0x2300d39e,
++ 0xd111e70a,
++ 0xd11dff09,
++ 0x1f00e5e5,
++ 0xd101e704,
++ 0xd115ff06,
++ 0x2301179e,
++ 0x79000004,
++ 0xd711fffd,
++ 0x91382586,
++ 0x2301059e,
++ 0xc911e706,
++ 0x0b042760,
++ 0x240000c6,
++ 0x24000086,
++ 0x13106006,
++ 0x7b000024,
++ 0x11709f80,
++ 0x5100800e,
++ 0xc913ff0d,
++ 0xd104ff04,
++ 0xd105ff05,
++ 0xa0604ae0,
++ 0x79000004,
++ 0xa06048e0,
++ 0x79000002,
++ 0xa06049e0,
++ 0xb10043e6,
++ 0xc910e602,
++ 0xa1001106,
++ 0x24000025,
++ 0x2300d39e,
++ 0xc90bff02,
++ 0x7900000b,
++ 0xc90aff02,
++ 0x79000012,
++ 0xcf08ff89,
++ 0xb10002e0,
++ 0xcf18e087,
++ 0x790000b6,
++ 0x24000080,
++ 0x24fb00c0,
++ 0xa06003e0,
++ 0x7f000082,
++ 0xb10024e6,
++ 0xb10025e0,
++ 0xa06628e6,
++ 0xa06029e0,
++ 0x248000c6,
++ 0xa06624e6,
++ 0x671006f0,
++ 0x81082186,
++ 0x7f0000ee,
++ 0xb10027e6,
++ 0x61100604,
++ 0xa0662be6,
++ 0x810c2186,
++ 0x79000006,
++ 0xd70cffea,
++ 0xa0662be6,
++ 0x1f1be6e6,
++ 0x81382686,
++ 0x813c2680,
++ 0x248000c6,
++ 0xa06627e6,
++ 0x7f0000e3,
++ 0x110f0600,
++ 0x81100b00,
++ 0x01502545,
++ 0x90457888,
++ 0x5103091c,
++ 0x6901092a,
++ 0xc910e603,
++ 0xd108e90d,
++ 0x79000027,
++ 0x01582545,
++ 0x9045788a,
++ 0xd108e904,
++ 0x1f08e9e9,
++ 0x01552545,
++ 0x80451829,
++ 0x50eaeb20,
++ 0x0101ebeb,
++ 0x015c2545,
++ 0x8045388b,
++ 0x7900001c,
++ 0x015c2545,
++ 0x9045788b,
++ 0x6900eb05,
++ 0x1d08e9e9,
++ 0x01552545,
++ 0x80451829,
++ 0x79000004,
++ 0x0501ebeb,
++ 0x015c2545,
++ 0x8045388b,
++ 0x10ecece8,
++ 0x79000010,
++ 0x24000000,
++ 0x5110000e,
++ 0x690f6903,
++ 0x24000069,
++ 0x79000002,
++ 0x01016969,
++ 0x01010000,
++ 0x81100b69,
++ 0x01542545,
++ 0x90451809,
++ 0x6f0209f7,
++ 0xa1001069,
++ 0x81100b06,
++ 0x01572545,
++ 0x80451869,
++ 0xa06841e8,
++ 0xa1414006,
++ 0x209e0000,
++ 0x81100b06,
++ 0xd11fe603,
++ 0x9164388d,
++ 0x8108248d,
++ 0xd100e507,
++ 0x97406490,
++ 0x9108248d,
++ 0x813c2480,
++ 0x2302b4de,
++ 0x1d00e7e7,
++ 0x79000006,
++ 0x97406590,
++ 0x9108258d,
++ 0x813c2580,
++ 0x1d01e7e7,
++ 0x2302b9de,
++ 0x8164388d,
++ 0x209e0000,
++ 0x81040105,
++ 0x91002286,
++ 0x97086290,
++ 0x81042280,
++ 0xd100e504,
++ 0x2302b4de,
++ 0x1f00e7e7,
++ 0x209e0000,
++ 0x2302b9de,
++ 0x1f01e7e7,
++ 0x209e0000,
++ 0xd109ff00,
++ 0xa0702cf0,
++ 0x79000001,
++ 0xd109ff00,
++ 0xb1002de6,
++ 0xd11ee609,
++ 0xb1000de0,
++ 0xc91fe044,
++ 0x24c338c6,
++ 0x10000006,
++ 0x81382686,
++ 0x87406690,
++ 0x813c2680,
++ 0x7900003e,
++ 0x110f0600,
++ 0x81100b00,
++ 0x24000045,
++ 0x24000025,
++ 0x61100603,
++ 0x24006045,
++ 0x24006025,
++ 0x01704545,
++ 0x90451888,
++ 0x0b034600,
++ 0x11070000,
++ 0x69040004,
++ 0xc916ff2c,
++ 0x01019e9e,
++ 0x7900002f,
++ 0xc90cff04,
++ 0x6f0200fd,
++ 0xd308e8a1,
++ 0x7f0000fb,
++ 0x69020008,
++ 0xd308e89e,
++ 0xb1002fe6,
++ 0x91b82880,
++ 0xc91ce002,
++ 0x1f1ce6e6,
++ 0x10080806,
++ 0x79000015,
++ 0xb1002fe6,
++ 0x69030003,
++ 0x13c06666,
++ 0x79000011,
++ 0x91807809,
++ 0xc910ea09,
++ 0x81082689,
++ 0x01018a8a,
++ 0xc91ee60a,
++ 0x1d10eaea,
++ 0x240557c0,
++ 0x60c08a07,
++ 0x1f1de6e6,
++ 0x79000005,
++ 0x2400018a,
++ 0x1f10eaea,
++ 0x1f1fe6e6,
++ 0xd71ee6f8,
++ 0x51000002,
++ 0x11c76666,
++ 0x81382686,
++ 0x87406690,
++ 0x91082689,
++ 0x813c2680,
++ 0xb1002ee6,
++ 0xd103e609,
++ 0x81807809,
++ 0xc908e807,
++ 0x21039400,
++ 0x81002386,
++ 0x87086390,
++ 0x81042380,
++ 0xc908e802,
++ 0x21039400,
++ 0x209e0000,
++ 0xb10008ef,
++ 0x110f0f00,
++ 0x81100b00,
++ 0x24000025,
++ 0x61100f02,
++ 0x24005025,
++ 0x01952545,
++ 0x9045382e,
++ 0xc91def03,
++ 0x24000900,
++ 0x2301c09e,
++ 0xc91cef03,
++ 0x24001900,
++ 0x2301c09e,
++ 0xc91bef03,
++ 0x24000a00,
++ 0x2301c09e,
++ 0xc91aef03,
++ 0x24001a00,
++ 0x2301c09e,
++ 0x8045382e,
++ 0x01a82545,
++ 0x9045388e,
++ 0xc915ef03,
++ 0x24000000,
++ 0x2301c09e,
++ 0xc914ef03,
++ 0x24001000,
++ 0x2301c09e,
++ 0x8045388e,
++ 0x61100f02,
++ 0x24006025,
++ 0x016d2545,
++ 0x9045382e,
++ 0xc919ef03,
++ 0x24000900,
++ 0x2301c09e,
++ 0xc918ef03,
++ 0x24001900,
++ 0x2301c09e,
++ 0xc917ef03,
++ 0x24000a00,
++ 0x2301c09e,
++ 0xc916ef03,
++ 0x24001a00,
++ 0x2301c09e,
++ 0x8045382e,
++ 0x017c2545,
++ 0x9045388e,
++ 0xc913ef03,
++ 0x24000000,
++ 0x2301c09e,
++ 0xc912ef03,
++ 0x24001000,
++ 0x2301c09e,
++ 0x8045388e,
++ 0xd11eef19,
++ 0x11f02f00,
++ 0x51000017,
++ 0x24001520,
++ 0x81140b20,
++ 0x81b01a0f,
++ 0x1f02e7e7,
++ 0x24c000c0,
++ 0x24001580,
++ 0xa0605ce0,
++ 0xc90fef04,
++ 0x1d04e7e7,
++ 0x1d05e7e7,
++ 0x7900000c,
++ 0xc90eef04,
++ 0x1d04e7e7,
++ 0x1f05e7e7,
++ 0x79000008,
++ 0xc90def04,
++ 0x1f04e7e7,
++ 0x1d05e7e7,
++ 0x79000004,
++ 0xc90cef03,
++ 0x1f04e7e7,
++ 0x1f05e7e7,
++ 0x2100b900,
++ 0xd11eef03,
++ 0x1e00eeee,
++ 0x209e0000,
++ 0x1c00eeee,
++ 0x209e0000,
++ 0x110f0606,
++ 0x81140b06,
++ 0x13100606,
++ 0x91b01a83,
++ 0x24000025,
++ 0x61100304,
++ 0x24005025,
++ 0xc905e702,
++ 0x24006025,
++ 0x110f0300,
++ 0x81100b00,
++ 0x81120b00,
++ 0x51150611,
++ 0x61100302,
++ 0x24005025,
++ 0x1d01e5e5,
++ 0x51160639,
++ 0x511a0650,
++ 0x511c0657,
++ 0x5118065e,
++ 0x511e0685,
++ 0x61100302,
++ 0x24006025,
++ 0x1f01e5e5,
++ 0x51170634,
++ 0x511b064b,
++ 0x511d0652,
++ 0x51190658,
++ 0x511f067f,
++ 0xc903e708,
++ 0x1d03e7e7,
++ 0x24000060,
++ 0xa1000a60,
++ 0x244000c0,
++ 0x24001580,
++ 0xa0605ce0,
++ 0x21007d00,
++ 0xcf02e7fc,
++ 0x1d02e7e7,
++ 0x1f03e7e7,
++ 0xc904e703,
++ 0x1f08e3e3,
++ 0x79000002,
++ 0x1d08e3e3,
++ 0xc905e705,
++ 0x01682545,
++ 0x9045588d,
++ 0x2302879e,
++ 0x79000004,
++ 0x01902545,
++ 0x9045588d,
++ 0x2302819e,
++ 0x24001872,
++ 0x24000152,
++ 0xb10009e0,
++ 0x108080d3,
++ 0x10c0c092,
++ 0x2400102c,
++ 0x2302c8de,
++ 0x91021c97,
++ 0x91001cd8,
++ 0x91061c98,
++ 0x91041cd9,
++ 0x910a1c99,
++ 0x91081cda,
++ 0x910e1c9a,
++ 0x910c1cdb,
++ 0x91261d9b,
++ 0x91287d9c,
++ 0x23028dde,
++ 0x1f02e7e7,
++ 0x1d03e7e7,
++ 0x7d000070,
++ 0x01902545,
++ 0x9045798d,
++ 0x79000003,
++ 0x01682545,
++ 0x9045788d,
++ 0x0b09eee0,
++ 0x24001472,
++ 0xd108e303,
++ 0xc900e00b,
++ 0x79000002,
++ 0xc910e009,
++ 0xd101e503,
++ 0x2302819e,
++ 0x79000002,
++ 0x2302879e,
++ 0x91013d12,
++ 0x9504bd93,
++ 0x23028dde,
++ 0x7d00005d,
++ 0xd108ee03,
++ 0x1d10e7e7,
++ 0x7900009a,
++ 0x1d11e7e7,
++ 0x79000098,
++ 0x01902545,
++ 0x9045798d,
++ 0x79000003,
++ 0x01682545,
++ 0x9045788d,
++ 0x0b0aeee0,
++ 0x24001072,
++ 0x7f0000e8,
++ 0x01a02545,
++ 0x9045b98d,
++ 0x79000003,
++ 0x01742545,
++ 0x9045b88d,
++ 0x0b01efe0,
++ 0x24001172,
++ 0x7f0000e0,
++ 0x2302d1de,
++ 0x79000002,
++ 0x2302d6de,
++ 0x000c2545,
++ 0x9045198f,
++ 0xd100ef07,
++ 0x1d02efef,
++ 0xc901ef0c,
++ 0xc905ef0b,
++ 0x1d01efef,
++ 0x1d05efef,
++ 0x79000008,
++ 0xd102ef04,
++ 0x1f02efef,
++ 0x8045198f,
++ 0x79000078,
++ 0xd101ef04,
++ 0x1f01efef,
++ 0x1f05efef,
++ 0x8045198f,
++ 0x69180673,
++ 0x01ac2545,
++ 0x2302dbde,
++ 0xd100ef03,
++ 0x23036c9e,
++ 0x7900006e,
++ 0xc800e40b,
++ 0x110f0020,
++ 0x81100b20,
++ 0x100c0c45,
++ 0x61100002,
++ 0x01604545,
++ 0x9045188f,
++ 0xd101ef04,
++ 0x1f01efef,
++ 0x1f07efef,
++ 0x8045188f,
++ 0x01010000,
++ 0x6f1300f4,
++ 0x79000060,
++ 0x2302d1de,
++ 0x79000002,
++ 0x2302d6de,
++ 0x000c2545,
++ 0x9045198f,
++ 0xc903ef05,
++ 0x1d03efef,
++ 0x1f04efef,
++ 0x8045198f,
++ 0x79000056,
++ 0xc904ef55,
++ 0x1d04efef,
++ 0xc901ef04,
++ 0xc906ef03,
++ 0x1d01efef,
++ 0x1d06efef,
++ 0x8045198f,
++ 0x691e064e,
++ 0x01ac2545,
++ 0x2302dbde,
++ 0xc800e40c,
++ 0x110f0020,
++ 0x81100b20,
++ 0x100c0c45,
++ 0x61100002,
++ 0x01604545,
++ 0x9045188f,
++ 0xc901ef05,
++ 0xc908ef04,
++ 0x1d01efef,
++ 0x1d07efef,
++ 0x8045188f,
++ 0x01010000,
++ 0x6f1300f3,
++ 0x7900003d,
++ 0x10ededf0,
++ 0xc908e303,
++ 0x13401010,
++ 0x209e0000,
++ 0x13301010,
++ 0x209e0000,
++ 0x10ededf0,
++ 0xc908e303,
++ 0x130a1010,
++ 0x209e0000,
++ 0x13081010,
++ 0x209e0000,
++ 0x24000266,
++ 0x2400c800,
++ 0x24000020,
++ 0xd108ee17,
++ 0x01012020,
++ 0xc91cff09,
++ 0x6e0020fe,
++ 0xc910e702,
++ 0x20de0000,
++ 0x1f10e7e7,
++ 0x110f0600,
++ 0x11f02727,
++ 0x12002727,
++ 0x20de0000,
++ 0x1d10e7e7,
++ 0x2302b4de,
++ 0x511d0605,
++ 0x511c0602,
++ 0x7900001e,
++ 0x01a62545,
++ 0x79000002,
++ 0x01722545,
++ 0x90451880,
++ 0x01018080,
++ 0x80451880,
++ 0x79000017,
++ 0x01012020,
++ 0xc91dff09,
++ 0x6e0020fe,
++ 0xc911e702,
++ 0x20de0000,
++ 0x1f11e7e7,
++ 0x09040600,
++ 0x110f2727,
++ 0x12002727,
++ 0x20de0000,
++ 0x1d11e7e7,
++ 0x2302b9de,
++ 0x7f0000ea,
++ 0x81b82786,
++ 0x240000d1,
++ 0x87c06790,
++ 0x81bc2780,
++ 0x20de0000,
++ 0x81b82986,
++ 0x87c06990,
++ 0x81bc2980,
++ 0x20de0000,
++ 0x91b43a88,
++ 0x2301029e,
++ 0x51150608,
++ 0xc908e305,
++ 0x51120303,
++ 0x01010303,
++ 0x79000002,
++ 0x24000003,
++ 0x01012323,
++ 0x81b01a83,
++ 0x21007d00,
++ 0x902cfc88,
++ 0x10c8c893,
++ 0x108888d4,
++ 0x10c9c994,
++ 0x108989d5,
++ 0x10caca95,
++ 0x108a8ad6,
++ 0x10cbcb96,
++ 0x108b8bd7,
++ 0xd108e303,
++ 0x2400a80c,
++ 0x20de0000,
++ 0x2400aa0c,
++ 0x20de0000,
++ 0xd108e303,
++ 0x24007c0c,
++ 0x20de0000,
++ 0x24007e0c,
++ 0x20de0000,
++ 0x24000000,
++ 0x90453904,
++ 0xd108e303,
++ 0x24007c0c,
++ 0x20de0000,
++ 0x24007e0c,
++ 0x20de0000,
++ 0xb1002fe6,
++ 0x91b82880,
++ 0xc91ce002,
++ 0x209e0000,
++ 0xb1002ee6,
++ 0x69187279,
++ 0xd110f230,
++ 0xc903e769,
++ 0xc90be604,
++ 0xc904e767,
++ 0xd105e766,
++ 0x7900000c,
++ 0xc90ae604,
++ 0xd104e763,
++ 0xd105e762,
++ 0x79000008,
++ 0xc907e604,
++ 0xc904e75f,
++ 0xc905e75e,
++ 0x79000004,
++ 0xc906e65c,
++ 0xd104e75b,
++ 0xc905e75a,
++ 0x91003c80,
++ 0x6897c058,
++ 0x68d88057,
++ 0x91043c80,
++ 0x6898c055,
++ 0x68d98054,
++ 0x91083c80,
++ 0x6899c052,
++ 0x68da8051,
++ 0x910c3c80,
++ 0x689ac04f,
++ 0x68db804e,
++ 0xb10009e0,
++ 0x6892c04c,
++ 0x68d3804b,
++ 0x24000160,
++ 0xa1000a60,
++ 0x244000c0,
++ 0x24001580,
++ 0xa0605ce0,
++ 0x1d03e7e7,
++ 0x109393c8,
++ 0x10d4d488,
++ 0x109494c9,
++ 0x10d5d589,
++ 0x109595ca,
++ 0x10d6d68a,
++ 0x109696cb,
++ 0x10d7d78b,
++ 0x8110fc88,
++ 0x209e0000,
++ 0x91003c80,
++ 0x6893c00c,
++ 0x68d4800b,
++ 0x91043c80,
++ 0x6894c009,
++ 0x68d58008,
++ 0x91083c80,
++ 0x6895c006,
++ 0x68d68005,
++ 0x910c3c80,
++ 0x6896c003,
++ 0x68d78002,
++ 0x79000010,
++ 0x24ffff80,
++ 0x24ffffc0,
++ 0x68809306,
++ 0x68e0f405,
++ 0x68e0f504,
++ 0x68e0f603,
++ 0x6880d702,
++ 0x79000008,
++ 0x24000080,
++ 0x240000c0,
++ 0x68809323,
++ 0x68e0f422,
++ 0x68e0f521,
++ 0x68e0f620,
++ 0x6880d71f,
++ 0x1d10f2f2,
++ 0x2400002c,
++ 0x2302c8de,
++ 0x24000f80,
++ 0x240000c0,
++ 0x0101c0c0,
++ 0xd100e504,
++ 0xc91cff06,
++ 0x6e80c0fd,
++ 0x21016d00,
++ 0xc91dff03,
++ 0x6e80c0fa,
++ 0x21016d00,
++ 0xd104e606,
++ 0xc909e608,
++ 0xb1000ce0,
++ 0x0101e0e0,
++ 0xa0600ce0,
++ 0x79000004,
++ 0xb1000be0,
++ 0x0101e0e0,
++ 0xa0600be0,
++ 0xb1002fe6,
++ 0xd100e504,
++ 0x2302b4de,
++ 0x24000022,
++ 0x209e0000,
++ 0x2302b9de,
++ 0x24000042,
++ 0x209e0000,
++ 0xd104e609,
++ 0x01782545,
++ 0x9045180e,
++ 0x110f0e00,
++ 0x81100b00,
++ 0x2400a445,
++ 0x51002502,
++ 0x01504545,
++ 0x90451888,
++ 0xc909e87d,
++ 0xb1002fe6,
++ 0x1f1fe6e6,
++ 0x10080806,
++ 0x21015f00,
++ 0x6914721b,
++ 0x01782545,
++ 0x2303bade,
++ 0x900c188f,
++ 0x1d02efef,
++ 0xc901ef05,
++ 0xc905ef04,
++ 0x1d01efef,
++ 0x1d05efef,
++ 0x800c188f,
++ 0xc909e66e,
++ 0x2303d0de,
++ 0xc800e40c,
++ 0x110f0020,
++ 0x81100b20,
++ 0x100c0c45,
++ 0x61100002,
++ 0x01604545,
++ 0x9045188f,
++ 0xc901ef05,
++ 0xc907ef04,
++ 0x1d01efef,
++ 0x1d07efef,
++ 0x8045188f,
++ 0x01010000,
++ 0x6f1300f3,
++ 0x7900005e,
++ 0x6910725d,
++ 0x01782545,
++ 0x2303bade,
++ 0x900c188f,
++ 0x1f03efef,
++ 0xd101ef03,
++ 0x1f01efef,
++ 0x1f06efef,
++ 0x800c188f,
++ 0xc909e654,
++ 0x2303d0de,
++ 0xc800e40b,
++ 0x110f0020,
++ 0x81100b20,
++ 0x100c0c45,
++ 0x61100002,
++ 0x01604545,
++ 0x9045188f,
++ 0xd101ef04,
++ 0x1f01efef,
++ 0x1f08efef,
++ 0x8045188f,
++ 0x01010000,
++ 0x6f1300f4,
++ 0x79000045,
++ 0x01782545,
++ 0x9045788e,
++ 0x1d02efef,
++ 0x1d12efef,
++ 0xc905ef04,
++ 0x1d05efef,
++ 0x1d01efef,
++ 0x7900000c,
++ 0xc915ef04,
++ 0x1d15efef,
++ 0x1d11efef,
++ 0x79000008,
++ 0xc907ef04,
++ 0x1d07efef,
++ 0x1d01efef,
++ 0x79000004,
++ 0xc917ef03,
++ 0x1d17efef,
++ 0x1d11efef,
++ 0x017c2545,
++ 0x8045388f,
++ 0x110f0e00,
++ 0x81100b00,
++ 0x2400a845,
++ 0x51002502,
++ 0x01504545,
++ 0x9045388f,
++ 0x1d02efef,
++ 0x1d12efef,
++ 0xc905ef04,
++ 0x1d05efef,
++ 0x1d01efef,
++ 0x79000004,
++ 0xc915ef03,
++ 0x1d15efef,
++ 0x1d11efef,
++ 0x8045388f,
++ 0x7900001f,
++ 0xc909e60d,
++ 0x9045180e,
++ 0x110f0e00,
++ 0x81100b00,
++ 0xc90ae603,
++ 0x2400a80c,
++ 0x79000003,
++ 0xc90be617,
++ 0x2400aa0c,
++ 0x51002503,
++ 0x01500c0c,
++ 0x24005025,
++ 0x20de0000,
++ 0xc904e611,
++ 0xc906e603,
++ 0x24007c0c,
++ 0x79000003,
++ 0xc907e60d,
++ 0x24007e0c,
++ 0x51002502,
++ 0x01600c0c,
++ 0x20de0000,
++ 0x01ac2545,
++ 0x24000000,
++ 0x90453804,
++ 0xd10be603,
++ 0x24007c0c,
++ 0x20de0000,
++ 0x24007e0c,
++ 0x20de0000,
++ 0x209e0000};
+diff -urN linux.old/drivers/atm/sangam_atm/turbodsl.c linux.dev/drivers/atm/sangam_atm/turbodsl.c
+--- linux.old/drivers/atm/sangam_atm/turbodsl.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/atm/sangam_atm/turbodsl.c 2005-08-23 04:46:50.111841568 +0200
+@@ -0,0 +1,223 @@
++
++
++/*
++ *
++ * Turbo DSL Implementaion
++ *
++ * Zhicheng Tang ztang@ti.com
++ *
++ * 2002 (c) Texas Instruments Inc.
++ *
++*/
++
++/* defines and variables */
++#define RFC2684_BRIDGED_HDR_SIZE 10
++unsigned char LLC_BRIDGED_HEADER_2684[RFC2684_BRIDGED_HDR_SIZE] =
++ {0xAA, 0xAA, 0x03, 0x00, 0x80, 0xC2, 0x00, 0x07, 0x00, 0x00};
++
++#define RFC2684_ROUTED_HDR_SIZE 6
++unsigned char LLC_ROUTED_HEADER_2684[6] ={0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00};
++
++unsigned long PPP_LLC_HEADER = 0xCF03FEFE;
++
++/* struct definition */
++enum
++{
++ AAL5_ENCAP_PPP_LLC,
++ AAL5_ENCAP_PPP_VCMUX,
++ AAL5_ENCAP_RFC2684_LLC_BRIDGED,
++ AAL5_ENCAP_RFC2684_LLC_ROUTED
++};
++
++/* Etherent header */
++typedef struct _turbodsl_ether_header
++{
++ unsigned char dst_mac_addr[6];
++ unsigned char src_mac_addr[6];
++ unsigned short ether_type;
++} turbodsl_ether_header_t;
++
++
++/* Ip header define */
++typedef struct _turbodsl_ip_header
++{
++
++ unsigned short vit;
++ unsigned short total_length;
++ unsigned short ip_id;
++ unsigned char flag; /* bit 0 = 0, bit1 = don't fragment, bit2=more frag */
++ unsigned char fragment_offset; /* offset include remaining 5 bits above, which make it 13 bits */
++ unsigned char time_to_live;
++ unsigned char protocol;
++ unsigned short checksum;
++ unsigned int src_ip;
++ unsigned int dst_ip;
++} turbodsl_ip_header_t;
++
++/* Arp packet define */
++typedef struct _turbodsl_arp_header
++{
++ unsigned short hardware_type;
++ unsigned short protocol_type;
++ unsigned char h_len;
++ unsigned char p_len;
++ unsigned short operation ;
++ unsigned char snd_hw_address[6];
++ unsigned char snd_pt_address[4];
++ unsigned char dst_hw_address[6];
++ unsigned char dst_pt_address[4];
++} turbodsl_arp_header_t;
++
++#define FIN_FLAG 1
++#define SYN_FLAG 1<<1
++#define RST_FLAG 1<<2
++#define PSH_FLAG 1<<3
++#define ACK_FLAG 1<<4
++#define URG_FLAG 1<<5
++
++typedef struct _turbodsl_tcp_header
++{
++ unsigned short src_port;
++ unsigned short dst_port;
++ unsigned int seq_num;
++ unsigned int ack_num;
++ unsigned char offset; /* only bits 4-7 are for offset */
++ unsigned char flags; /* bits: 0-FIN, 1-SYN, 2-RST, 3-PSH, 4-ACK, 5-URG */
++ unsigned short windows;
++ unsigned short checksum;
++ unsigned short urgent_ptr;
++} turbodsl_tcp_header_t;
++
++
++
++/***************************************************************************
++ * Function: turbodsl_memory_compare
++ * Descripation: Memory compare
++ ****************************************************************************/
++int turbodsl_memory_compare(unsigned char *pIn, unsigned char *pOut, unsigned int len)
++ {
++ int i;
++
++ for(i=0;i<(int)len; i++)
++ {
++ if(pIn[i] != pOut[i])
++ return 0;
++ }
++ return 1;
++ }
++
++/***************************************************************************
++ * Function: turbodsl_check_aal5_encap_type
++ * Descripation: Determine AAL5 Encapsulation type
++ * Input:
++ * unsigned char *pData, AAL5 Packet buffer pointer
++ ****************************************************************************/
++int turbodsl_check_aal5_encap_type(unsigned char *pData)
++ {
++
++ if(turbodsl_memory_compare(pData, LLC_BRIDGED_HEADER_2684, 6))
++ return AAL5_ENCAP_RFC2684_LLC_BRIDGED;
++ if(turbodsl_memory_compare(pData, LLC_ROUTED_HEADER_2684, 6))
++ return AAL5_ENCAP_RFC2684_LLC_ROUTED;
++ if(turbodsl_memory_compare(pData, (unsigned char *)&PPP_LLC_HEADER, sizeof(PPP_LLC_HEADER)))
++ return AAL5_ENCAP_PPP_LLC;
++
++ return AAL5_ENCAP_PPP_VCMUX;
++ }
++
++/***************************************************************************
++ * Function: turbodsl_check_priority_type
++ * Descripation: Determine AAL5 Encapsulation type
++ * Input:
++ * unsigned char *pData, AAL5 Packet buffer pointer.
++ * short vpi, VPI.
++ * int vci, VCI
++ ****************************************************************************/
++int turbodsl_check_priority_type(unsigned char *pData)
++ {
++ int encap;
++ unsigned char *pP;
++ unsigned short etherType;
++ turbodsl_ip_header_t *pIp;
++ turbodsl_tcp_header_t *pTcp;
++ unsigned short ip_length;
++
++ dprintf(2, "turbodsl_check_priority_type ==>\n");
++
++ encap = turbodsl_check_aal5_encap_type(pData);
++ pP = pData;
++
++ switch(encap)
++ {
++ case AAL5_ENCAP_RFC2684_LLC_BRIDGED:
++ pP += RFC2684_BRIDGED_HDR_SIZE; //skip off aal5 encap
++ pP += 12; //skip of mac address
++ etherType = *(unsigned short *)pP;
++ if(etherType != 0x6488 && etherType != 0x0008)
++ {
++ //Not an IP packet
++ return 1;
++ }
++
++ pP +=2; //skip ether type
++ if(etherType == 0x6488)
++ {
++ pP += 6;
++ }
++ break;
++ case AAL5_ENCAP_RFC2684_LLC_ROUTED:
++ pP += RFC2684_ROUTED_HDR_SIZE; //skip of encap
++ pP += 2; //skip ether type
++ break;
++ case AAL5_ENCAP_PPP_LLC:
++ pP += sizeof(PPP_LLC_HEADER);
++ if(*pP == 0xff && *(pP+1) == 0x03) //ppp hdlc header
++ pP += 2;
++ break;
++ case AAL5_ENCAP_PPP_VCMUX:
++ if(*pP == 0xff && *(pP+1) == 0x03) //ppp hdlc header
++ pP += 2;
++ break;
++ default:
++ return 1;
++ }
++
++ pIp = (turbodsl_ip_header_t *)pP;
++ if(pIp->vit != 0x0045)
++ {
++ //Not a IP packet
++ return 1;
++ }
++
++ if(pIp->protocol != 0x06)
++ {
++ //not tcp packet
++ return 1;
++ }
++
++ pTcp = (turbodsl_tcp_header_t *)(pP + sizeof(turbodsl_ip_header_t));
++
++ ip_length = (pIp->total_length>>8) + (pIp->total_length<<8);
++
++ if((pTcp->flags & ACK_FLAG) && ip_length <=40)
++ return 0;
++
++ return 1;
++ }
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+diff -urN linux.old/include/linux/atmdev.h linux.dev/include/linux/atmdev.h
+--- linux.old/include/linux/atmdev.h 2005-08-22 23:18:37.812526104 +0200
++++ linux.dev/include/linux/atmdev.h 2005-08-23 06:33:33.425389944 +0200
+@@ -30,6 +30,9 @@
+ #define ATM_DS3_PCR (8000*12)
+ /* DS3: 12 cells in a 125 usec time slot */
+
++#define ATM_PDU_OVHD 0 /* number of bytes to charge against buffer
++ quota per PDU */
++
+ #define ATM_SD(s) ((s)->sk->protinfo.af_atm)
+
+
+@@ -94,7 +97,8 @@
+ /* set backend handler */
+ #define ATM_NEWBACKENDIF _IOW('a',ATMIOC_SPECIAL+3,atm_backend_t)
+ /* use backend to make new if */
+-
++#define ATM_STOPTX _IOW('a',ATMIOC_SPECIAL+4,struct atmif_sioc)
++ /* Stop Tx on Sangam DSL */
+ /*
+ * These are backend handkers that can be set via the ATM_SETBACKEND call
+ * above. In the future we may support dynamic loading of these - for now,
+@@ -199,7 +203,9 @@
+ "SESSION", "HASSAP", "BOUND", "CLOSE"
+
+
+-#ifdef __KERNEL__
++#ifndef __KERNEL__
++#undef __AAL_STAT_ITEMS
++#else
+
+ #include <linux/sched.h> /* wait_queue_head_t */
+ #include <linux/time.h> /* struct timeval */
+@@ -291,6 +297,7 @@
+ int (*send)(struct atm_vcc *vcc,struct sk_buff *skb);
+ void *dev_data; /* per-device data */
+ void *proto_data; /* per-protocol data */
++ struct timeval timestamp; /* AAL timestamps */
+ struct k_atm_aal_stats *stats; /* pointer to AAL stats group */
+ wait_queue_head_t sleep; /* if socket is busy */
+ struct sock *sk; /* socket backpointer */
+@@ -333,13 +340,14 @@
+ struct k_atm_dev_stats stats; /* statistics */
+ char signal; /* signal status (ATM_PHY_SIG_*) */
+ int link_rate; /* link rate (default: OC3) */
+- atomic_t refcnt; /* reference count */
+- spinlock_t lock; /* protect internal members */
++ atomic_t refcnt; /* reference count */
++ spinlock_t lock; /* protect internal members */
+ #ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *proc_entry; /* proc entry */
+ char *proc_name; /* proc entry name */
+ #endif
+- struct list_head dev_list; /* linkage */
++ struct list_head dev_list; /* linkage */
++
+ };
+
+
diff --git a/target/linux/ar7-2.4/patches/005-wdt_driver.patch b/target/linux/ar7-2.4/patches/005-wdt_driver.patch
new file mode 100644
index 0000000..9b01a35
--- /dev/null
+++ b/target/linux/ar7-2.4/patches/005-wdt_driver.patch
@@ -0,0 +1,392 @@
+diff -ruN linux-2.4.30-patch006/drivers/char/ar7_wdt.c linux-2.4.30-patch007/drivers/char/ar7_wdt.c
+--- linux-2.4.30-patch006/drivers/char/ar7_wdt.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.30-patch007/drivers/char/ar7_wdt.c 2005-10-27 09:39:40.000000000 +0200
+@@ -0,0 +1,335 @@
++/* linux/drivers/char/ar7_wdt.c
++
++ TI AR7 watch dog timer support
++
++ Copyright (c) 2005 Enrik Berkhan <Enrik.Berkhan@akk.org>
++
++ Som code taken from:
++ National Semiconductor SCx200 Watchdog support
++ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
++
++ This program is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public License as
++ published by the Free Software Foundation; either version 2 of the
++ License, or (at your option) any later version.
++
++ The author(s) of this software shall not be held liable for damages
++ of any nature resulting due to the use of this software. This
++ software is provided AS-IS with no warranties. */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/notifier.h>
++#include <linux/reboot.h>
++#include <linux/ioport.h>
++
++#include <asm/uaccess.h>
++
++#include <asm/ar7/avalanche_misc.h>
++#include <asm/ar7/sangam.h>
++
++#define NAME "ar7_wdt"
++#define LONGNAME "TI AR7 Watchdog Timer"
++
++MODULE_AUTHOR("Enrik Berkhan <Enrik.Berkhan@akk.org>");
++MODULE_DESCRIPTION(LONGNAME);
++MODULE_LICENSE("GPL");
++
++#ifndef CONFIG_WATCHDOG_NOWAYOUT
++#define CONFIG_WATCHDOG_NOWAYOUT 0
++#endif
++
++static int margin = 60;
++MODULE_PARM(margin, "i");
++MODULE_PARM_DESC(margin, "Watchdog margin in seconds (1 - ~68)");
++
++static int nowayout = CONFIG_WATCHDOG_NOWAYOUT;
++MODULE_PARM(nowayout, "i");
++MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
++
++typedef struct {
++ uint32_t kick_lock;
++ uint32_t kick;
++ uint32_t change_lock;
++ uint32_t change ;
++ uint32_t disable_lock;
++ uint32_t disable;
++ uint32_t prescale_lock;
++ uint32_t prescale;
++} ar7_wdt_t;
++
++volatile ar7_wdt_t *ar7_wdt = (ar7_wdt_t *)AVALANCHE_WATCHDOG_TIMER_BASE;
++
++static struct semaphore open_semaphore;
++static unsigned expect_close;
++
++/* XXX correct? assumed to be sysfreq/2. get this dynamically ... */
++#define vbus_freq 62500000
++
++/* XXX currently fixed, allows max margin ~68.72 secs */
++#define prescale_value 0xFFFF
++
++static void ar7_wdt_kick(uint32_t value)
++{
++ ar7_wdt->kick_lock = 0x5555;
++ if ((ar7_wdt->kick_lock & 3) == 1) {
++ ar7_wdt->kick_lock = 0xAAAA;
++ if ((ar7_wdt->kick_lock & 3) == 3) {
++ ar7_wdt->kick = value;
++ return;
++ }
++ }
++ printk(KERN_ERR NAME "failed to unlock WDT kick reg\n");
++}
++
++static void ar7_wdt_prescale(uint32_t value)
++{
++ ar7_wdt->prescale_lock = 0x5A5A;
++ if ((ar7_wdt->prescale_lock & 3) == 1) {
++ ar7_wdt->prescale_lock = 0xA5A5;
++ if ((ar7_wdt->prescale_lock & 3) == 3) {
++ ar7_wdt->prescale = value;
++ return;
++ }
++ }
++ printk(KERN_ERR NAME "failed to unlock WDT prescale reg\n");
++}
++
++static void ar7_wdt_change(uint32_t value)
++{
++ ar7_wdt->change_lock = 0x6666;
++ if ((ar7_wdt->change_lock & 3) == 1) {
++ ar7_wdt->change_lock = 0xBBBB;
++ if ((ar7_wdt->change_lock & 3) == 3) {
++ ar7_wdt->change = value;
++ return;
++ }
++ }
++ printk(KERN_ERR NAME "failed to unlock WDT change reg\n");
++}
++
++static void ar7_wdt_disable(uint32_t value)
++{
++ ar7_wdt->disable_lock = 0x7777;
++ if ((ar7_wdt->disable_lock & 3) == 1) {
++ ar7_wdt->disable_lock = 0xCCCC;
++ if ((ar7_wdt->disable_lock & 3) == 2) {
++ ar7_wdt->disable_lock = 0xDDDD;
++ if ((ar7_wdt->disable_lock & 3) == 3) {
++ ar7_wdt->disable = value;
++ return;
++ }
++ }
++ }
++ printk(KERN_ERR NAME "failed to unlock WDT disable reg\n");
++ return;
++}
++
++static void ar7_wdt_update_margin(int new_margin)
++{
++ uint32_t change;
++
++ change = new_margin * (vbus_freq / prescale_value);
++ if (change < 1) change = 1;
++ if (change > 0xFFFF) change = 0xFFFF;
++ ar7_wdt_change(change);
++ margin = change * prescale_value / vbus_freq;
++ printk(KERN_INFO NAME
++ ": timer margin %d seconds (prescale %d, change %d, freq %d)\n",
++ margin, prescale_value, change, vbus_freq);
++}
++
++static void ar7_wdt_enable_wdt(void)
++{
++ printk(KERN_DEBUG NAME ": enabling watchdog timer\n");
++ ar7_wdt_disable(1);
++ ar7_wdt_kick(1);
++}
++
++static void ar7_wdt_disable_wdt(void)
++{
++ printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
++ ar7_wdt_disable(0);
++}
++
++static int ar7_wdt_open(struct inode *inode, struct file *file)
++{
++ /* only allow one at a time */
++ if (down_trylock(&open_semaphore))
++ return -EBUSY;
++ ar7_wdt_enable_wdt();
++ expect_close = 0;
++
++ return 0;
++}
++
++static int ar7_wdt_release(struct inode *inode, struct file *file)
++{
++ if (!expect_close) {
++ printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n");
++ } else if (!nowayout) {
++ ar7_wdt_disable_wdt();
++ }
++ up(&open_semaphore);
++
++ return 0;
++}
++
++static int ar7_wdt_notify_sys(struct notifier_block *this,
++ unsigned long code, void *unused)
++{
++ if (code == SYS_HALT || code == SYS_POWER_OFF)
++ if (!nowayout)
++ ar7_wdt_disable_wdt();
++
++ return NOTIFY_DONE;
++}
++
++static struct notifier_block ar7_wdt_notifier =
++{
++ .notifier_call = ar7_wdt_notify_sys
++};
++
++static ssize_t ar7_wdt_write(struct file *file, const char *data,
++ size_t len, loff_t *ppos)
++{
++ if (ppos != &file->f_pos)
++ return -ESPIPE;
++
++ /* check for a magic close character */
++ if (len)
++ {
++ size_t i;
++
++ ar7_wdt_kick(1);
++
++ expect_close = 0;
++ for (i = 0; i < len; ++i) {
++ char c;
++ if (get_user(c, data+i))
++ return -EFAULT;
++ if (c == 'V')
++ expect_close = 1;
++ }
++
++ }
++ return len;
++}
++
++static int ar7_wdt_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ static struct watchdog_info ident = {
++ .identity = LONGNAME,
++ .firmware_version = 1,
++ .options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING),
++ };
++ int new_margin;
++
++ switch (cmd) {
++ default:
++ return -ENOTTY;
++ case WDIOC_GETSUPPORT:
++ if(copy_to_user((struct watchdog_info *)arg, &ident,
++ sizeof(ident)))
++ return -EFAULT;
++ return 0;
++ case WDIOC_GETSTATUS:
++ case WDIOC_GETBOOTSTATUS:
++ if (put_user(0, (int *)arg))
++ return -EFAULT;
++ return 0;
++ case WDIOC_KEEPALIVE:
++ ar7_wdt_kick(1);
++ return 0;
++ case WDIOC_SETTIMEOUT:
++ if (get_user(new_margin, (int *)arg))
++ return -EFAULT;
++ if (new_margin < 1)
++ return -EINVAL;
++
++ ar7_wdt_update_margin(new_margin);
++ ar7_wdt_kick(1);
++
++ case WDIOC_GETTIMEOUT:
++ if (put_user(margin, (int *)arg))
++ return -EFAULT;
++ return 0;
++ }
++}
++
++static struct file_operations ar7_wdt_fops = {
++ .owner = THIS_MODULE,
++ .write = ar7_wdt_write,
++ .ioctl = ar7_wdt_ioctl,
++ .open = ar7_wdt_open,
++ .release = ar7_wdt_release,
++};
++
++static struct miscdevice ar7_wdt_miscdev = {
++ .minor = WATCHDOG_MINOR,
++ .name = "watchdog",
++ .fops = &ar7_wdt_fops,
++};
++
++static __initdata char *last_initiator[] = {
++ [HARDWARE_RESET] = "hardware reset",
++ [SOFTWARE_RESET0] = "SW0 software reset",
++ [SOFTWARE_RESET1] = "SW1 software reset",
++ [WATCHDOG_RESET] = "watchdog"
++};
++
++static int __init ar7_wdt_init(void)
++{
++ int r;
++
++ if (!request_mem_region(AVALANCHE_WATCHDOG_TIMER_BASE,
++ sizeof(ar7_wdt_t), LONGNAME)) {
++ printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
++ return -EBUSY;
++ }
++
++ printk(KERN_INFO NAME ": last system reset initiated by %s\n",
++ last_initiator[avalanche_get_sys_last_reset_status()]);
++
++
++ ar7_wdt_disable_wdt();
++ ar7_wdt_prescale(prescale_value);
++ ar7_wdt_update_margin(margin);
++
++ sema_init(&open_semaphore, 1);
++
++ r = misc_register(&ar7_wdt_miscdev);
++ if (r) {
++ printk(KERN_ERR NAME ": unable to register misc device\n");
++ release_mem_region(AVALANCHE_WATCHDOG_TIMER_BASE,
++ sizeof(ar7_wdt_t));
++ return r;
++ }
++
++ r = register_reboot_notifier(&ar7_wdt_notifier);
++ if (r) {
++ printk(KERN_ERR NAME ": unable to register reboot notifier\n");
++ misc_deregister(&ar7_wdt_miscdev);
++ release_mem_region(AVALANCHE_WATCHDOG_TIMER_BASE,
++ sizeof(ar7_wdt_t));
++ return r;
++ }
++
++ return 0;
++}
++
++static void __exit ar7_wdt_cleanup(void)
++{
++ unregister_reboot_notifier(&ar7_wdt_notifier);
++ misc_deregister(&ar7_wdt_miscdev);
++ release_mem_region(AVALANCHE_WATCHDOG_TIMER_BASE, sizeof(ar7_wdt_t));
++}
++
++module_init(ar7_wdt_init);
++module_exit(ar7_wdt_cleanup);
+diff -ruN linux-2.4.30-patch006/drivers/char/Config.in linux-2.4.30-patch007/drivers/char/Config.in
+--- linux-2.4.30-patch006/drivers/char/Config.in 2005-10-27 11:25:29.000000000 +0200
++++ linux-2.4.30-patch007/drivers/char/Config.in 2005-10-27 11:17:32.000000000 +0200
+@@ -251,6 +251,9 @@
+ bool 'Watchdog Timer Support' CONFIG_WATCHDOG
+ if [ "$CONFIG_WATCHDOG" != "n" ]; then
+ bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
++ if [ "$CONFIG_AR7" = "y" ] ; then
++ tristate ' TI AR7 Watchdog Timer' CONFIG_AR7_WDT
++ else
+ tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
+ tristate ' Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT
+ tristate ' ALi M7101 PMU on ALi 1535D+ Watchdog Timer' CONFIG_ALIM1535_WDT
+@@ -271,7 +274,6 @@
+ tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
+ dep_tristate ' SC1200 Watchdog Timer (EXPERIMENTAL)' CONFIG_SC1200_WDT $CONFIG_EXPERIMENTAL
+ tristate ' NatSemi SCx200 Watchdog' CONFIG_SCx200_WDT
+- tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG
+ tristate ' W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT
+ tristate ' WDT Watchdog timer' CONFIG_WDT
+ tristate ' WDT PCI Watchdog timer' CONFIG_WDTPCI
+@@ -282,6 +284,8 @@
+ fi
+ fi
+ tristate ' ZF MachZ Watchdog' CONFIG_MACHZ_WDT
++ fi
++ tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG
+ if [ "$CONFIG_SGI_IP22" = "y" ]; then
+ dep_tristate ' Indy/I2 Hardware Watchdog' CONFIG_INDYDOG $CONFIG_SGI_IP22
+ fi
+diff -ruN linux-2.4.30-patch006/drivers/char/Makefile linux-2.4.30-patch007/drivers/char/Makefile
+--- linux-2.4.30-patch006/drivers/char/Makefile 2005-10-27 11:19:38.000000000 +0200
++++ linux-2.4.30-patch007/drivers/char/Makefile 2005-10-27 09:39:40.000000000 +0200
+@@ -342,6 +342,7 @@
+ obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
+ obj-$(CONFIG_INDYDOG) += indydog.o
+ obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
++obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
+
+ subdir-$(CONFIG_MWAVE) += mwave
+ ifeq ($(CONFIG_MWAVE),y)
+diff -ruN linux-2.4.30-patch006/include/asm-mips/ar7/sangam.h linux-2.4.30-patch007/include/asm-mips/ar7/sangam.h
+--- linux-2.4.30-patch006/include/asm-mips/ar7/sangam.h 2005-10-27 11:25:51.000000000 +0200
++++ linux-2.4.30-patch007/include/asm-mips/ar7/sangam.h 2005-10-27 11:13:37.000000000 +0200
+@@ -152,7 +152,7 @@
+ #define AVALANCHE_EMIF_SDRAM_CFG (AVALANCHE_EMIF_CONTROL_BASE + 0x8)
+ #define AVALANCHE_RST_CTRL_PRCR (KSEG1ADDR(0x08611600))
+ #define AVALANCHE_RST_CTRL_SWRCR (KSEG1ADDR(0x08611604))
+-#define AVALANCHE_RST_CTRL_RSR (KSEG1ADDR(0x08611600))
++#define AVALANCHE_RST_CTRL_RSR (KSEG1ADDR(0x08611608))
+
+ #define AVALANCHE_POWER_CTRL_PDCR (KSEG1ADDR(0x08610A00))
+ #define AVALANCHE_WAKEUP_CTRL_WKCR (KSEG1ADDR(0x08610A0C))
diff --git a/target/linux/ar7-2.4/patches/006-sched_use_tsc.patch b/target/linux/ar7-2.4/patches/006-sched_use_tsc.patch
new file mode 100644
index 0000000..5b64310
--- /dev/null
+++ b/target/linux/ar7-2.4/patches/006-sched_use_tsc.patch
@@ -0,0 +1,84 @@
+diff -urN linux.old/arch/mips/kernel/time.c linux.dev/arch/mips/kernel/time.c
+--- linux.old/arch/mips/kernel/time.c 2005-11-14 11:06:38.661262000 +0100
++++ linux.dev/arch/mips/kernel/time.c 2005-11-15 20:02:50.059676750 +0100
+@@ -151,6 +151,27 @@
+ unsigned int (*mips_hpt_read)(void);
+ void (*mips_hpt_init)(unsigned int);
+
++extern __u32 get_htscl(void)
++{
++ return timerhi;
++}
++
++static __u64 tscll_last = 0;
++
++extern __u64 get_tscll(void)
++{
++ __u64 h = (__u64) timerhi;
++ __u32 c = read_c0_count();
++
++ h <<= 32;
++ h += c;
++
++ while (h < tscll_last)
++ h += (((__u64) 1) << 32);
++
++ tscll_last = h;
++ return h;
++}
+
+ /*
+ * timeofday services, for syscalls.
+@@ -761,3 +782,5 @@
+ EXPORT_SYMBOL(to_tm);
+ EXPORT_SYMBOL(rtc_set_time);
+ EXPORT_SYMBOL(rtc_get_time);
++EXPORT_SYMBOL(get_htscl);
++EXPORT_SYMBOL(get_tscll);
+diff -urN linux.old/include/asm-mips/timex.h linux.dev/include/asm-mips/timex.h
+--- linux.old/include/asm-mips/timex.h 2005-11-14 11:06:38.685263500 +0100
++++ linux.dev/include/asm-mips/timex.h 2005-11-14 11:02:21.069163500 +0100
+@@ -31,6 +31,19 @@
+ return read_c0_count();
+ }
+
++extern __u32 get_htscl(void);
++extern __u64 get_tscll(void);
++
++#define rdtsc(low, high) \
++ high = get_htscl(); \
++ low = read_c0_count();
++
++#define rdtscl(low) \
++ low = read_c0_count();
++
++#define rdtscll(val) \
++ val = get_tscll();
++
+ #define vxtime_lock() do {} while (0)
+ #define vxtime_unlock() do {} while (0)
+
+diff -urN linux.old/include/net/pkt_sched.h linux.dev/include/net/pkt_sched.h
+--- linux.old/include/net/pkt_sched.h 2005-11-14 11:06:38.709265000 +0100
++++ linux.dev/include/net/pkt_sched.h 2005-11-14 11:02:21.069163500 +0100
+@@ -5,7 +5,11 @@
+ #define PSCHED_JIFFIES 2
+ #define PSCHED_CPU 3
+
++#ifdef __mips__
++#define PSCHED_CLOCK_SOURCE PSCHED_CPU
++#else
+ #define PSCHED_CLOCK_SOURCE PSCHED_JIFFIES
++#endif
+
+ #include <linux/config.h>
+ #include <linux/types.h>
+@@ -271,7 +275,7 @@
+ #define PSCHED_US2JIFFIE(delay) (((delay)+psched_clock_per_hz-1)/psched_clock_per_hz)
+ #define PSCHED_JIFFIE2US(delay) ((delay)*psched_clock_per_hz)
+
+-#ifdef CONFIG_X86_TSC
++#if defined(CONFIG_X86_TSC) || defined(__mips__)
+
+ #define PSCHED_GET_TIME(stamp) \
+ ({ u64 __cur; \
diff --git a/target/linux/aruba-2.6/Makefile b/target/linux/aruba-2.6/Makefile
new file mode 100644
index 0000000..7ffd11c
--- /dev/null
+++ b/target/linux/aruba-2.6/Makefile
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+LINUX_VERSION:=2.6.17
+LINUX_RELEASE:=1
+LINUX_KERNEL_MD5SUM:=37ddefe96625502161f075b9d907f21e
+
+include ./config
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/kernel-build.mk
+
+$(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked
+ [ -d ../generic-$(KERNEL)/patches ] && $(PATCH) $(LINUX_DIR) ../generic-$(KERNEL)/patches $(MAKE_TRACE)
+ [ -d ./patches ] && $(PATCH) $(LINUX_DIR) ./patches $(MAKE_TRACE)
+ @$(CP) config $(LINUX_DIR)/.config
+ touch $@
+
diff --git a/target/linux/aruba-2.6/config b/target/linux/aruba-2.6/config
new file mode 100644
index 0000000..82c42d4
--- /dev/null
+++ b/target/linux/aruba-2.6/config
@@ -0,0 +1,1539 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17
+# Fri Aug 25 11:20:17 2006
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+CONFIG_MACH_ARUBA=y
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_MIPS_MT is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IPSEC_NAT_TRAVERSAL is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_BRIDGE_NETFILTER is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_CT_ACCT=y
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=y
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+CONFIG_IP_NF_SIP=m
+CONFIG_IP_NF_QUEUE=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_IPP2P=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_TIME=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_IMQ=m
+# CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_ROUTE=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=y
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_SET=m
+CONFIG_IP_NF_SET_MAX=256
+CONFIG_IP_NF_SET_HASHSIZE=1024
+CONFIG_IP_NF_SET_IPMAP=m
+CONFIG_IP_NF_SET_MACIPMAP=m
+CONFIG_IP_NF_SET_PORTMAP=m
+CONFIG_IP_NF_SET_IPHASH=m
+CONFIG_IP_NF_SET_NETHASH=m
+CONFIG_IP_NF_SET_IPTREE=m
+CONFIG_IP_NF_MATCH_SET=m
+CONFIG_IP_NF_TARGET_SET=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_ESFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_PEDIT=m
+# CONFIG_NET_ACT_SIMP is not set
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+# 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_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+CONFIG_IEEE80211_SOFTMAC=m
+# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=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
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_GEOMETRY 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_OTP is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x1fc00000
+CONFIG_MTD_PHYSMAP_LEN=0x400000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=1
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_IFB is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_IMQ=m
+# CONFIG_IMQ_BEHAVIOR_AA is not set
+# CONFIG_IMQ_BEHAVIOR_AB is not set
+CONFIG_IMQ_BEHAVIOR_BA=y
+# CONFIG_IMQ_BEHAVIOR_BB is not set
+CONFIG_IMQ_NUM_DEVS=2
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_AR2313=y
+CONFIG_IDT_RC32434_ETH=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+CONFIG_NATSEMI=y
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_LAN_SAA9730 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 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)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+CONFIG_NET_WIRELESS_RTNETLINK=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+# CONFIG_PRISM54 is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+CONFIG_HOSTAP_PLX=m
+CONFIG_HOSTAP_PCI=m
+# CONFIG_BCM43XX is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=m
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# 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 Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+# CONFIG_VIDEO_V4L1 is not set
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=y
+
+#
+# Video Capture Adapters
+#
+
+#
+# Video Capture Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA2 is not set
+
+#
+# Encoders and Decoders
+#
+
+#
+# V4L USB devices
+#
+
+#
+# Radio Adapters
+#
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+
+#
+# ALSA MIPS devices
+#
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=m
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DYNAMIC_MINORS=y
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+CONFIG_USB_UHCI_HCD=m
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL 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_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_ZD1201 is not set
+CONFIG_USB_MON=y
+
+#
+# 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_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=m
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY 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 is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_FS is not set
+CONFIG_CROSSCOMPILE=y
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/target/linux/aruba-2.6/patches/000-aruba.patch b/target/linux/aruba-2.6/patches/000-aruba.patch
new file mode 100644
index 0000000..1db6831
--- /dev/null
+++ b/target/linux/aruba-2.6/patches/000-aruba.patch
@@ -0,0 +1,10521 @@
+diff -Nur linux-2.6.17/arch/mips/aruba/Makefile linux-2.6.17-owrt/arch/mips/aruba/Makefile
+--- linux-2.6.17/arch/mips/aruba/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/aruba/Makefile 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,49 @@
++###############################################################################
++#
++# BRIEF MODULE DESCRIPTION
++# Makefile for IDT EB434 BSP
++#
++# Copyright 2004 IDT Inc. (rischelp@idt.com)
++#
++# This program is free software; you can redistribute it and/or modify it
++# under the terms of the GNU General Public License as published by the
++# Free Software Foundation; either version 2 of the License, or (at your
++# option) any later version.
++#
++# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++# NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++#
++# You should have received a copy of the GNU General Public License along
++# with this program; if not, write to the Free Software Foundation, Inc.,
++# 675 Mass Ave, Cambridge, MA 02139, USA.
++#
++#
++###############################################################################
++# May 2004 rkt, neb
++#
++# Initial Release
++#
++#
++#
++###############################################################################
++
++
++# .S.s:
++# $(CPP) $(CFLAGS) $< -o $*.s
++# .S.o:
++# $(CC) $(CFLAGS) -c $< -o $*.o
++
++obj-y := prom.o setup.o irq.o time.o flash_lock.o
++obj-$(CONFIG_SERIAL_8250) += serial.o
++
++subdir-y += nvram
++obj-y += nvram/built-in.o
++
+diff -Nur linux-2.6.17/arch/mips/aruba/nvram/Makefile linux-2.6.17-owrt/arch/mips/aruba/nvram/Makefile
+--- linux-2.6.17/arch/mips/aruba/nvram/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/aruba/nvram/Makefile 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,46 @@
++###############################################################################
++#
++# BRIEF MODULE DESCRIPTION
++# Makefile for IDT EB434 nvram access routines
++#
++# Copyright 2004 IDT Inc. (rischelp@idt.com)
++#
++# This program is free software; you can redistribute it and/or modify it
++# under the terms of the GNU General Public License as published by the
++# Free Software Foundation; either version 2 of the License, or (at your
++# option) any later version.
++#
++# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++# NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++#
++# You should have received a copy of the GNU General Public License along
++# with this program; if not, write to the Free Software Foundation, Inc.,
++# 675 Mass Ave, Cambridge, MA 02139, USA.
++#
++#
++###############################################################################
++# May 2004 rkt, neb
++#
++# Initial Release
++#
++#
++#
++###############################################################################
++
++obj-y := nvram434.o
++obj-m := $(O_TARGET)
++
++
++
++
++
++
++
+diff -Nur linux-2.6.17/arch/mips/aruba/nvram/nvram434.c linux-2.6.17-owrt/arch/mips/aruba/nvram/nvram434.c
+--- linux-2.6.17/arch/mips/aruba/nvram/nvram434.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/aruba/nvram/nvram434.c 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,392 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * nvram interface routines.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#include <linux/ctype.h>
++#include <linux/string.h>
++
++//#include <asm/ds1553rtc.h>
++#include "nvram434.h"
++#define NVRAM_BASE 0xbfff8000
++
++extern void setenv (char *e, char *v, int rewrite);
++extern void unsetenv (char *e);
++extern void mapenv (int (*func)(char *, char *));
++extern char *getenv (char *s);
++extern void purgeenv(void);
++
++static void nvram_initenv(void);
++
++static unsigned char
++nvram_getbyte(int offs)
++{
++ return(*((unsigned char*)(NVRAM_BASE + offs)));
++}
++
++static void
++nvram_setbyte(int offs, unsigned char val)
++{
++ unsigned char* nvramDataPointer = (unsigned char*)(NVRAM_BASE + offs);
++
++ *nvramDataPointer = val;
++}
++
++/*
++ * BigEndian!
++ */
++static unsigned short
++nvram_getshort(int offs)
++{
++ return((nvram_getbyte(offs) << 8) | nvram_getbyte(offs + 1));
++}
++
++static void
++nvram_setshort(int offs, unsigned short val)
++{
++ nvram_setbyte(offs, (unsigned char)((val >> 8) & 0xff));
++ nvram_setbyte(offs + 1, (unsigned char)(val & 0xff));
++}
++#if 0
++static unsigned int
++nvram_getint(int offs)
++{
++ unsigned int val;
++ val = nvram_getbyte(offs) << 24;
++ val |= nvram_getbyte(offs + 1) << 16;
++ val |= nvram_getbyte(offs + 2) << 8;
++ val |= nvram_getbyte(offs + 3);
++ return(val);
++}
++
++static void
++nvram_setint(int offs, unsigned int val)
++{
++ nvram_setbyte(offs, val >> 24);
++ nvram_setbyte(offs + 1, val >> 16);
++ nvram_setbyte(offs + 2, val >> 8);
++ nvram_setbyte(offs + 3, val);
++}
++#endif
++/*
++ * calculate NVRAM checksum
++ */
++static unsigned short
++nvram_calcsum(void)
++{
++ unsigned short sum = NV_MAGIC;
++ int i;
++
++ for (i = ENV_BASE; i < ENV_TOP; i += 2)
++ sum += nvram_getshort(i);
++ return(sum);
++}
++
++/*
++ * update the nvram checksum
++ */
++static void
++nvram_updatesum (void)
++{
++ nvram_setshort(NVOFF_CSUM, nvram_calcsum());
++}
++
++/*
++ * test validity of nvram by checksumming it
++ */
++static int
++nvram_isvalid(void)
++{
++ static int is_valid;
++
++ if (is_valid)
++ return(1);
++
++ if (nvram_getshort(NVOFF_MAGIC) != NV_MAGIC) {
++ printk("nvram_isvalid FAILED\n");
++ //nvram_initenv();
++ }
++ is_valid = 1;
++ return(1);
++}
++
++/* return nvram address of environment string */
++static int
++nvram_matchenv(char *s)
++{
++ int envsize, envp, n, i, varsize;
++ char *var;
++
++ envsize = nvram_getshort(NVOFF_ENVSIZE);
++
++ if (envsize > ENV_AVAIL)
++ return(0); /* sanity */
++
++ envp = ENV_BASE;
++
++ if ((n = strlen (s)) > 255)
++ return(0);
++
++ while (envsize > 0) {
++ varsize = nvram_getbyte(envp);
++ if (varsize == 0 || (envp + varsize) > ENV_TOP)
++ return(0); /* sanity */
++ for (i = envp + 1, var = s; i <= envp + n; i++, var++) {
++ char c1 = nvram_getbyte(i);
++ char c2 = *var;
++ if (islower(c1))
++ c1 = toupper(c1);
++ if (islower(c2))
++ c2 = toupper(c2);
++ if (c1 != c2)
++ break;
++ }
++ if (i > envp + n) { /* match so far */
++ if (n == varsize - 1) /* match on boolean */
++ return(envp);
++ if (nvram_getbyte(i) == '=') /* exact match on variable */
++ return(envp);
++ }
++ envsize -= varsize;
++ envp += varsize;
++ }
++ return(0);
++}
++
++static void nvram_initenv(void)
++{
++ nvram_setshort(NVOFF_MAGIC, NV_MAGIC);
++ nvram_setshort(NVOFF_ENVSIZE, 0);
++
++ nvram_updatesum();
++}
++
++static void
++nvram_delenv(char *s)
++{
++ int nenvp, envp, envsize, nbytes;
++
++ envp = nvram_matchenv(s);
++ if (envp == 0)
++ return;
++
++ nenvp = envp + nvram_getbyte(envp);
++ envsize = nvram_getshort(NVOFF_ENVSIZE);
++ nbytes = envsize - (nenvp - ENV_BASE);
++ nvram_setshort(NVOFF_ENVSIZE, envsize - (nenvp - envp));
++ while (nbytes--) {
++ nvram_setbyte(envp, nvram_getbyte(nenvp));
++ envp++;
++ nenvp++;
++ }
++ nvram_updatesum();
++}
++
++static int
++nvram_setenv(char *s, char *v)
++{
++ int ns, nv, total;
++ int envp;
++
++ if (!nvram_isvalid())
++ return(-1);
++
++ nvram_delenv(s);
++ ns = strlen(s);
++ if (ns == 0)
++ return (-1);
++ if (v && *v) {
++ nv = strlen(v);
++ total = ns + nv + 2;
++ }
++ else {
++ nv = 0;
++ total = ns + 1;
++ }
++ if (total > 255 || total > ENV_AVAIL - nvram_getshort(NVOFF_ENVSIZE))
++ return(-1);
++
++ envp = ENV_BASE + nvram_getshort(NVOFF_ENVSIZE);
++
++ nvram_setbyte(envp, (unsigned char) total);
++ envp++;
++
++ while (ns--) {
++ nvram_setbyte(envp, *s);
++ envp++;
++ s++;
++ }
++
++ if (nv) {
++ nvram_setbyte(envp, '=');
++ envp++;
++ while (nv--) {
++ nvram_setbyte(envp, *v);
++ envp++;
++ v++;
++ }
++ }
++ nvram_setshort(NVOFF_ENVSIZE, envp-ENV_BASE);
++ nvram_updatesum();
++ return 0;
++}
++
++static char *
++nvram_getenv(char *s)
++{
++ static char buf[256]; /* FIXME: this cannot be static */
++ int envp, ns, nbytes, i;
++
++ if (!nvram_isvalid())
++ return "INVALID NVRAM"; //((char *)0);
++
++ envp = nvram_matchenv(s);
++ if (envp == 0)
++ return "NOT FOUND"; //((char *)0);
++ ns = strlen(s);
++ if (nvram_getbyte(envp) == ns + 1) /* boolean */
++ buf[0] = '\0';
++ else {
++ nbytes = nvram_getbyte(envp) - (ns + 2);
++ envp += ns + 2;
++ for (i = 0; i < nbytes; i++)
++ buf[i] = nvram_getbyte(envp++);
++ buf[i] = '\0';
++ }
++ return(buf);
++}
++
++static void
++nvram_unsetenv(char *s)
++{
++ if (!nvram_isvalid())
++ return;
++
++ nvram_delenv(s);
++}
++
++/*
++ * apply func to each string in environment
++ */
++static void
++nvram_mapenv(int (*func)(char *, char *))
++{
++ int envsize, envp, n, i, seeneql;
++ char name[256], value[256];
++ char c, *s;
++
++ if (!nvram_isvalid())
++ return;
++
++ envsize = nvram_getshort(NVOFF_ENVSIZE);
++ envp = ENV_BASE;
++
++ while (envsize > 0) {
++ value[0] = '\0';
++ seeneql = 0;
++ s = name;
++ n = nvram_getbyte(envp);
++ for (i = envp + 1; i < envp + n; i++) {
++ c = nvram_getbyte(i);
++ if ((c == '=') && !seeneql) {
++ *s = '\0';
++ s = value;
++ seeneql = 1;
++ continue;
++ }
++ *s++ = c;
++ }
++ *s = '\0';
++ (*func)(name, value);
++ envsize -= n;
++ envp += n;
++ }
++}
++#if 0
++static unsigned int
++digit(char c)
++{
++ if ('0' <= c && c <= '9')
++ return (c - '0');
++ if ('A' <= c && c <= 'Z')
++ return (10 + c - 'A');
++ if ('a' <= c && c <= 'z')
++ return (10 + c - 'a');
++ return (~0);
++}
++#endif
++/*
++ * Wrappers to allow 'special' environment variables to get processed
++ */
++void
++setenv(char *e, char *v, int rewrite)
++{
++ if (nvram_getenv(e) && !rewrite)
++ return;
++
++ nvram_setenv(e, v);
++}
++
++char *
++getenv(char *e)
++{
++ return(nvram_getenv(e));
++}
++
++void
++unsetenv(char *e)
++{
++ nvram_unsetenv(e);
++}
++
++void
++purgeenv()
++{
++ int i;
++ unsigned char* nvramDataPointer = (unsigned char*)(NVRAM_BASE);
++
++ for (i = ENV_BASE; i < ENV_TOP; i++)
++ *nvramDataPointer++ = 0;
++ nvram_setshort(NVOFF_MAGIC, NV_MAGIC);
++ nvram_setshort(NVOFF_ENVSIZE, 0);
++ nvram_setshort(NVOFF_CSUM, NV_MAGIC);
++}
++
++void
++mapenv(int (*func)(char *, char *))
++{
++ nvram_mapenv(func);
++}
+diff -Nur linux-2.6.17/arch/mips/aruba/nvram/nvram434.h linux-2.6.17-owrt/arch/mips/aruba/nvram/nvram434.h
+--- linux-2.6.17/arch/mips/aruba/nvram/nvram434.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/aruba/nvram/nvram434.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,66 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * nvram definitions.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++
++#ifndef _NVRAM_
++#define _NVRAM_
++#define NVOFFSET 0 /* use all of NVRAM */
++
++/* Offsets to reserved locations */
++ /* size description */
++#define NVOFF_MAGIC (NVOFFSET + 0) /* 2 magic value */
++#define NVOFF_CSUM (NVOFFSET + 2) /* 2 NVRAM environment checksum */
++#define NVOFF_ENVSIZE (NVOFFSET + 4) /* 2 size of 'environment' */
++#define NVOFF_TEST (NVOFFSET + 5) /* 1 cold start test byte */
++#define NVOFF_ETHADDR (NVOFFSET + 6) /* 6 decoded ethernet address */
++#define NVOFF_UNUSED (NVOFFSET + 12) /* 0 current end of table */
++
++#define NV_MAGIC 0xdeaf /* nvram magic number */
++#define NV_RESERVED 6 /* number of reserved bytes */
++
++#undef NVOFF_ETHADDR
++#define NVOFF_ETHADDR (NVOFFSET + NV_RESERVED - 6)
++
++/* number of bytes available for environment */
++#define ENV_BASE (NVOFFSET + NV_RESERVED)
++#define ENV_TOP 0x2000
++#define ENV_AVAIL (ENV_TOP - ENV_BASE)
++
++#endif /* _NVRAM_ */
++
++
+diff -Nur linux-2.6.17/arch/mips/aruba/prom.c linux-2.6.17-owrt/arch/mips/aruba/prom.c
+--- linux-2.6.17/arch/mips/aruba/prom.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/aruba/prom.c 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,111 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * prom interface routines
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/console.h>
++#include <asm/bootinfo.h>
++#include <linux/bootmem.h>
++#include <linux/ioport.h>
++#include <linux/serial.h>
++#include <linux/serialP.h>
++#include <asm/serial.h>
++#include <linux/ioport.h>
++
++unsigned int idt_cpu_freq;
++EXPORT_SYMBOL(idt_cpu_freq);
++
++unsigned int arch_has_pci=0;
++
++/* Kernel Boot parameters */
++static unsigned char bootparm[] = "console=ttyS0,9600 root=/dev/mtdblock1 rootfstype=jffs2";
++
++extern unsigned long mips_machgroup;
++extern unsigned long mips_machtype;
++
++extern void setup_serial_port(void);
++extern char * getenv(char *e);
++
++/* IDT 79EB434 memory map -- we really should be auto sizing it */
++#define RAM_SIZE 32*1024*1024
++
++char *__init prom_getcmdline(void)
++{
++ return &(arcs_cmdline[0]);
++}
++
++void __init prom_init(void)
++{
++ char *boardname;
++ sprintf(arcs_cmdline, "%s", bootparm);
++
++ /* set our arch type */
++ mips_machgroup = MACH_GROUP_ARUBA;
++ mips_machtype = MACH_ARUBA_UNKNOWN;
++
++ boardname=getenv("boardname");
++
++ if (!strcmp(boardname,"Muscat")) {
++ mips_machtype = MACH_ARUBA_AP70;
++ idt_cpu_freq = 133000000;
++ arch_has_pci=1;
++ } else if (!strcmp(boardname,"Mataro")) {
++ mips_machtype = MACH_ARUBA_AP65;
++ idt_cpu_freq = 110000000;
++ } else if (!strcmp(boardname,"Merlot")) {
++ mips_machtype = MACH_ARUBA_AP60;
++ idt_cpu_freq = 90000000;
++ }
++
++ /* turn on the console */
++ setup_serial_port();
++
++ /*
++ * give all RAM to boot allocator,
++ * except where the kernel was loaded
++ */
++ add_memory_region(0,RAM_SIZE,BOOT_MEM_RAM);
++}
++
++void prom_free_prom_memory(void)
++{
++ printk("stubbed prom_free_prom_memory()\n");
++}
+diff -Nur linux-2.6.17/arch/mips/aruba/serial.c linux-2.6.17-owrt/arch/mips/aruba/serial.c
+--- linux-2.6.17/arch/mips/aruba/serial.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/aruba/serial.c 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,94 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Serial port initialisation.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/pci.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++
++#include <asm/time.h>
++#include <asm/cpu.h>
++#include <asm/bootinfo.h>
++#include <asm/irq.h>
++#include <asm/serial.h>
++
++#include <asm/idt-boards/rc32434/rc32434.h>
++
++extern int __init early_serial_setup(struct uart_port *port);
++
++#define BASE_BAUD (1843200 / 16)
++
++extern unsigned int idt_cpu_freq;
++
++extern int __init setup_serial_port(void)
++{
++ static struct uart_port serial_req[2];
++
++ memset(serial_req, 0, sizeof(serial_req));
++ serial_req[0].type = PORT_16550A;
++ serial_req[0].line = 0;
++ serial_req[0].flags = STD_COM_FLAGS;
++ serial_req[0].iotype = SERIAL_IO_MEM;
++ serial_req[0].regshift = 2;
++
++ switch (mips_machtype) {
++ case MACH_ARUBA_AP70:
++ serial_req[0].irq = 104;
++ serial_req[0].mapbase = KSEG1ADDR(0x18058003);
++ serial_req[0].membase = (char *) KSEG1ADDR(0x18058003);
++ serial_req[0].uartclk = idt_cpu_freq;
++ break;
++ case MACH_ARUBA_AP65:
++ case MACH_ARUBA_AP60:
++ default:
++ serial_req[0].irq = 12;
++ serial_req[0].mapbase = KSEG1ADDR(0xbc000003);
++ serial_req[0].membase = (char *) KSEG1ADDR(0xbc000003);
++ serial_req[0].uartclk = idt_cpu_freq / 2;
++ break;
++ }
++
++ early_serial_setup(&serial_req[0]);
++
++ return(0);
++}
+diff -Nur linux-2.6.17/arch/mips/aruba/setup.c linux-2.6.17-owrt/arch/mips/aruba/setup.c
+--- linux-2.6.17/arch/mips/aruba/setup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/aruba/setup.c 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,134 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * setup routines for IDT EB434 boards
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/irq.h>
++#include <asm/bootinfo.h>
++#include <asm/io.h>
++#include <linux/ioport.h>
++#include <asm/mipsregs.h>
++#include <asm/pgtable.h>
++#include <asm/reboot.h>
++#include <asm/addrspace.h> /* for KSEG1ADDR() */
++#include <asm/idt-boards/rc32434/rc32434.h>
++#include <linux/pm.h>
++
++extern char *__init prom_getcmdline(void);
++
++extern void (*board_time_init) (void);
++extern void (*board_timer_setup) (struct irqaction * irq);
++extern void aruba_time_init(void);
++extern void aruba_timer_setup(struct irqaction *irq);
++extern void aruba_reset(void);
++
++#define epldMask ((volatile unsigned char *)0xB900000d)
++
++static void aruba_machine_restart(char *command)
++{
++ switch (mips_machtype) {
++ case MACH_ARUBA_AP70:
++ *(volatile u32 *)KSEG1ADDR(0x18008000) = 0x80000001;
++ break;
++ case MACH_ARUBA_AP65:
++ case MACH_ARUBA_AP60:
++ default:
++ /* Reset*/
++ *((volatile u32 *)KSEG1ADDR(0x1c003020)) = 0x00080350; // reset everything in sight
++ udelay(100);
++ *((volatile u32 *)KSEG1ADDR(0x1c003020)) = 0; // reset everything in sight
++ udelay(100);
++ *((volatile u32 *)KSEG1ADDR(0x1c003020)) = 0x3; // cold reset the cpu & system
++ break;
++ }
++}
++
++static void aruba_machine_halt(void)
++{
++ for (;;) continue;
++}
++
++extern char * getenv(char *e);
++extern void unlock_ap60_70_flash(void);
++
++void __init plat_setup(void)
++{
++ board_time_init = aruba_time_init;
++
++ board_timer_setup = aruba_timer_setup;
++
++ _machine_restart = aruba_machine_restart;
++ _machine_halt = aruba_machine_halt;
++ pm_power_off = aruba_machine_halt;
++
++ set_io_port_base(KSEG1);
++
++ /* Enable PCI interrupts in EPLD Mask register */
++ *epldMask = 0x0;
++ *(epldMask + 1) = 0x0;
++
++ write_c0_wired(0);
++ unlock_ap60_70_flash();
++
++ printk("BOARD - %s\n",getenv("boardname"));
++
++ return 0;
++}
++
++int page_is_ram(unsigned long pagenr)
++{
++ return 1;
++}
++
++const char *get_system_type(void)
++{
++ switch (mips_machtype) {
++ case MACH_ARUBA_AP70:
++ return "Aruba AP70";
++ case MACH_ARUBA_AP65:
++ return "Aruba AP65";
++ case MACH_ARUBA_AP60:
++ return "Aruba AP60/AP61";
++ default:
++ return "Aruba UNKNOWN";
++ }
++}
++
++EXPORT_SYMBOL(get_system_type);
+diff -Nur linux-2.6.17/arch/mips/aruba/time.c linux-2.6.17-owrt/arch/mips/aruba/time.c
+--- linux-2.6.17/arch/mips/aruba/time.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/aruba/time.c 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,110 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * timer routines for IDT EB434 boards
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/kernel_stat.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#include <linux/mc146818rtc.h>
++#include <linux/irq.h>
++#include <linux/timex.h>
++
++#include <linux/param.h>
++#include <asm/mipsregs.h>
++#include <asm/ptrace.h>
++#include <asm/time.h>
++#include <asm/hardirq.h>
++
++#include <asm/mipsregs.h>
++#include <asm/ptrace.h>
++#include <asm/debug.h>
++#include <asm/time.h>
++
++#include <asm/idt-boards/rc32434/rc32434.h>
++
++static unsigned long r4k_offset; /* Amount to incr compare reg each time */
++static unsigned long r4k_cur; /* What counter should be at next timer irq */
++
++extern unsigned int idt_cpu_freq;
++
++static unsigned long __init cal_r4koff(void)
++{
++ mips_hpt_frequency = idt_cpu_freq * IDT_CLOCK_MULT / 2;
++ return (mips_hpt_frequency / HZ);
++}
++
++void __init aruba_time_init(void)
++{
++ unsigned int est_freq, flags;
++ local_irq_save(flags);
++
++ printk("calculating r4koff... ");
++ r4k_offset = cal_r4koff();
++ printk("%08lx(%d)\n", r4k_offset, (int)r4k_offset);
++
++ est_freq = 2 * r4k_offset * HZ;
++ est_freq += 5000; /* round */
++ est_freq -= est_freq % 10000;
++ printk("CPU frequency %d.%02d MHz\n", est_freq / 1000000,
++ (est_freq % 1000000) * 100 / 1000000);
++ local_irq_restore(flags);
++
++}
++
++void __init aruba_timer_setup(struct irqaction *irq)
++{
++ /* we are using the cpu counter for timer interrupts */
++ setup_irq(MIPS_CPU_TIMER_IRQ, irq);
++
++ /* to generate the first timer interrupt */
++ r4k_cur = (read_c0_count() + r4k_offset);
++ write_c0_compare(r4k_cur);
++
++}
++
++asmlinkage void aruba_timer_interrupt(struct pt_regs *regs)
++{
++ int irq = MIPS_CPU_TIMER_IRQ;
++
++ irq_enter();
++ kstat_this_cpu.irqs[irq]++;
++
++ timer_interrupt(irq, NULL, regs);
++ irq_exit();
++}
+diff -Nur linux-2.6.17/arch/mips/Kconfig linux-2.6.17-owrt/arch/mips/Kconfig
+--- linux-2.6.17/arch/mips/Kconfig 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/mips/Kconfig 2006-06-18 12:44:28.000000000 +0200
+@@ -227,6 +227,17 @@
+ either a NEC Vr5432 or QED RM5231. Say Y here if you wish to build
+ a kernel for this platform.
+
++config MACH_ARUBA
++ bool "Support for the ARUBA product line"
++ select DMA_NONCOHERENT
++ select CPU_HAS_PREFETCH
++ select HW_HAS_PCI
++ select SWAP_IO_SPACE
++ select SYS_SUPPORTS_32BIT_KERNEL
++ select SYS_HAS_CPU_MIPS32_R1
++ select SYS_SUPPORTS_BIG_ENDIAN
++
++
+ config MACH_JAZZ
+ bool "Jazz family of machines"
+ select ARC
+diff -Nur linux-2.6.17/arch/mips/Makefile linux-2.6.17-owrt/arch/mips/Makefile
+--- linux-2.6.17/arch/mips/Makefile 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/mips/Makefile 2006-06-18 12:44:28.000000000 +0200
+@@ -145,6 +145,14 @@
+ #
+
+ #
++# Aruba
++#
++
++core-$(CONFIG_MACH_ARUBA) += arch/mips/aruba/
++cflags-$(CONFIG_MACH_ARUBA) += -Iinclude/asm-mips/aruba
++load-$(CONFIG_MACH_ARUBA) += 0x80100000
++
++#
+ # Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
+ #
+ core-$(CONFIG_MACH_JAZZ) += arch/mips/jazz/
+diff -Nur linux-2.6.17/arch/mips/mm/tlbex.c linux-2.6.17-owrt/arch/mips/mm/tlbex.c
+--- linux-2.6.17/arch/mips/mm/tlbex.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/mips/mm/tlbex.c 2006-06-18 12:48:27.000000000 +0200
+@@ -876,7 +876,6 @@
+ case CPU_R10000:
+ case CPU_R12000:
+ case CPU_R14000:
+- case CPU_4KC:
+ case CPU_SB1:
+ case CPU_SB1A:
+ case CPU_4KSC:
+@@ -904,6 +903,7 @@
+ tlbw(p);
+ break;
+
++ case CPU_4KC:
+ case CPU_4KEC:
+ case CPU_24K:
+ case CPU_34K:
+diff -Nur linux-2.6.17/drivers/net/Kconfig linux-2.6.17-owrt/drivers/net/Kconfig
+--- linux-2.6.17/drivers/net/Kconfig 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/drivers/net/Kconfig 2006-06-18 12:44:28.000000000 +0200
+@@ -187,6 +187,13 @@
+
+ source "drivers/net/arm/Kconfig"
+
++config IDT_RC32434_ETH
++ tristate "IDT RC32434 Local Ethernet support"
++ depends on NET_ETHERNET
++ help
++ IDT RC32434 has one local ethernet port. Say Y here to enable it.
++ To compile this driver as a module, choose M here.
++
+ config MACE
+ tristate "MACE (Power Mac ethernet) support"
+ depends on NET_ETHERNET && PPC_PMAC && PPC32
+diff -Nur linux-2.6.17/drivers/net/Makefile linux-2.6.17-owrt/drivers/net/Makefile
+--- linux-2.6.17/drivers/net/Makefile 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/drivers/net/Makefile 2006-06-18 12:44:28.000000000 +0200
+@@ -38,6 +38,7 @@
+
+ obj-$(CONFIG_OAKNET) += oaknet.o 8390.o
+
++obj-$(CONFIG_IDT_RC32434_ETH) += rc32434_eth.o
+ obj-$(CONFIG_DGRS) += dgrs.o
+ obj-$(CONFIG_VORTEX) += 3c59x.o
+ obj-$(CONFIG_TYPHOON) += typhoon.o
+diff -Nur linux-2.6.17/drivers/net/natsemi.c linux-2.6.17-owrt/drivers/net/natsemi.c
+--- linux-2.6.17/drivers/net/natsemi.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/drivers/net/natsemi.c 2006-06-18 12:44:28.000000000 +0200
+@@ -771,6 +771,49 @@
+ static int netdev_get_eeprom(struct net_device *dev, u8 *buf);
+ static struct ethtool_ops ethtool_ops;
+
++#ifdef CONFIG_MACH_ARUBA
++
++#include <linux/ctype.h>
++
++#ifndef ERR
++#define ERR(fmt, args...) printk("%s: " fmt, __func__, ##args)
++#endif
++
++static int parse_mac_addr(struct net_device *dev, char* macstr)
++{
++ int i, j;
++ unsigned char result, value;
++
++ for (i=0; i<6; i++) {
++ result = 0;
++ if (i != 5 && *(macstr+2) != ':') {
++ ERR("invalid mac address format: %d %c\n",
++ i, *(macstr+2));
++ return -EINVAL;
++ }
++ for (j=0; j<2; j++) {
++ if (isxdigit(*macstr) && (value = isdigit(*macstr) ? *macstr-'0' :
++ toupper(*macstr)-'A'+10) < 16) {
++ result = result*16 + value;
++ macstr++;
++ }
++ else {
++ ERR("invalid mac address "
++ "character: %c\n", *macstr);
++ return -EINVAL;
++ }
++ }
++
++ macstr++;
++ dev->dev_addr[i] = result;
++ }
++
++ dev->dev_addr[5]++;
++ return 0;
++}
++
++#endif
++
+ static inline void __iomem *ns_ioaddr(struct net_device *dev)
+ {
+ return (void __iomem *) dev->base_addr;
+@@ -871,6 +914,7 @@
+ goto err_ioremap;
+ }
+
++#ifndef CONFIG_MACH_ARUBA
+ /* Work around the dropped serial bit. */
+ prev_eedata = eeprom_read(ioaddr, 6);
+ for (i = 0; i < 3; i++) {
+@@ -879,6 +923,19 @@
+ dev->dev_addr[i*2+1] = eedata >> 7;
+ prev_eedata = eedata;
+ }
++#else
++ {
++ char mac[32];
++ unsigned char def_mac[6] = {00, 0x0b, 0x86, 0xba, 0xdb, 0xad};
++ extern char *getenv(char *e);
++ memset(mac, 0, 32);
++ memcpy(mac, getenv("ethaddr"), 17);
++ if (parse_mac_addr(dev, mac)){
++ printk("%s: MAC address not found\n", __func__);
++ memcpy(dev->dev_addr, def_mac, 6);
++ }
++ }
++#endif
+
+ dev->base_addr = (unsigned long __force) ioaddr;
+ dev->irq = irq;
+diff -Nur linux-2.6.17/drivers/net/rc32434_eth.c linux-2.6.17-owrt/drivers/net/rc32434_eth.c
+--- linux-2.6.17/drivers/net/rc32434_eth.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/drivers/net/rc32434_eth.c 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,1273 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Driver for the IDT RC32434 on-chip ethernet controller.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Based on the driver developed by B. Maruthanayakam, H. Kou and others.
++ *
++ * Aug 2004 Sadik
++ *
++ * Added NAPI
++ *
++ **************************************************************************
++ */
++
++#include <linux/config.h>
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/moduleparam.h>
++#include <linux/sched.h>
++#include <linux/ctype.h>
++#include <linux/types.h>
++#include <linux/fcntl.h>
++#include <linux/interrupt.h>
++#include <linux/ptrace.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/proc_fs.h>
++#include <linux/in.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/errno.h>
++#include <asm/bootinfo.h>
++#include <asm/system.h>
++#include <asm/bitops.h>
++#include <asm/pgtable.h>
++#include <asm/segment.h>
++#include <asm/io.h>
++#include <asm/dma.h>
++
++#include "rc32434_eth.h"
++
++#define DRIVER_VERSION "(mar2904)"
++
++#define DRIVER_NAME "rc32434 Ethernet driver. " DRIVER_VERSION
++
++
++#define STATION_ADDRESS_HIGH(dev) (((dev)->dev_addr[0] << 8) | \
++ ((dev)->dev_addr[1]))
++#define STATION_ADDRESS_LOW(dev) (((dev)->dev_addr[2] << 24) | \
++ ((dev)->dev_addr[3] << 16) | \
++ ((dev)->dev_addr[4] << 8) | \
++ ((dev)->dev_addr[5]))
++
++#define MII_CLOCK 1250000 /* no more than 2.5MHz */
++static char mac0[18] = "08:00:06:05:40:01";
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52)
++module_param_string(mac0, mac0, 18, 0);
++#else
++MODULE_PARM(mac0, "c18");
++#endif
++MODULE_PARM_DESC(mac0, "MAC address for RC32434 ethernet0");
++
++static struct rc32434_if_t {
++ char *name;
++ struct net_device *dev;
++ char* mac_str;
++ int weight;
++ u32 iobase;
++ u32 rxdmabase;
++ u32 txdmabase;
++ int rx_dma_irq;
++ int tx_dma_irq;
++ int rx_ovr_irq;
++ int tx_und_irq;
++} rc32434_iflist[] =
++{
++ {
++ "rc32434_eth0", NULL, mac0,
++ 64,
++ ETH0_PhysicalAddress,
++ ETH0_RX_DMA_ADDR,
++ ETH0_TX_DMA_ADDR,
++ ETH0_DMA_RX_IRQ,
++ ETH0_DMA_TX_IRQ,
++ ETH0_RX_OVR_IRQ,
++ ETH0_TX_UND_IRQ
++ }
++};
++
++
++static int parse_mac_addr(struct net_device *dev, char* macstr)
++{
++ int i, j;
++ unsigned char result, value;
++
++ for (i=0; i<6; i++) {
++ result = 0;
++ if (i != 5 && *(macstr+2) != ':') {
++ ERR("invalid mac address format: %d %c\n",
++ i, *(macstr+2));
++ return -EINVAL;
++ }
++ for (j=0; j<2; j++) {
++ if (isxdigit(*macstr) && (value = isdigit(*macstr) ? *macstr-'0' :
++ toupper(*macstr)-'A'+10) < 16) {
++ result = result*16 + value;
++ macstr++;
++ }
++ else {
++ ERR("invalid mac address "
++ "character: %c\n", *macstr);
++ return -EINVAL;
++ }
++ }
++
++ macstr++;
++ dev->dev_addr[i] = result;
++ }
++
++ return 0;
++}
++
++
++
++static inline void rc32434_abort_tx(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ rc32434_abort_dma(dev, lp->tx_dma_regs);
++
++}
++
++static inline void rc32434_abort_rx(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ rc32434_abort_dma(dev, lp->rx_dma_regs);
++
++}
++
++static inline void rc32434_start_tx(struct rc32434_local *lp, volatile DMAD_t td)
++{
++ rc32434_start_dma(lp->tx_dma_regs, CPHYSADDR(td));
++}
++
++static inline void rc32434_start_rx(struct rc32434_local *lp, volatile DMAD_t rd)
++{
++ rc32434_start_dma(lp->rx_dma_regs, CPHYSADDR(rd));
++}
++
++static inline void rc32434_chain_tx(struct rc32434_local *lp, volatile DMAD_t td)
++{
++ rc32434_chain_dma(lp->tx_dma_regs, CPHYSADDR(td));
++}
++
++static inline void rc32434_chain_rx(struct rc32434_local *lp, volatile DMAD_t rd)
++{
++ rc32434_chain_dma(lp->rx_dma_regs, CPHYSADDR(rd));
++}
++
++#ifdef RC32434_PROC_DEBUG
++static int rc32434_read_proc(char *buf, char **start, off_t fpos,
++ int length, int *eof, void *data)
++{
++ struct net_device *dev = (struct net_device *)data;
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ int len = 0;
++
++ /* print out header */
++ len += sprintf(buf + len, "\n\tRC32434 Ethernet Debug\n\n");
++ len += sprintf (buf + len,
++ "DMA halt count = %10d, DMA run count = %10d\n",
++ lp->dma_halt_cnt, lp->dma_run_cnt);
++
++ if (fpos >= len) {
++ *start = buf;
++ *eof = 1;
++ return 0;
++ }
++ *start = buf + fpos;
++
++ if ((len -= fpos) > length)
++ return length;
++ *eof = 1;
++
++ return len;
++
++}
++#endif
++
++
++/*
++ * Restart the RC32434 ethernet controller.
++ */
++static int rc32434_restart(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++
++ /*
++ * Disable interrupts
++ */
++ disable_irq(lp->rx_irq);
++ disable_irq(lp->tx_irq);
++#ifdef RC32434_REVISION
++ disable_irq(lp->ovr_irq);
++#endif
++ disable_irq(lp->und_irq);
++
++ /* Mask F E bit in Tx DMA */
++ rc32434_writel(rc32434_readl(&lp->tx_dma_regs->dmasm) | DMASM_f_m | DMASM_e_m, &lp->tx_dma_regs->dmasm);
++ /* Mask D H E bit in Rx DMA */
++ rc32434_writel(rc32434_readl(&lp->rx_dma_regs->dmasm) | DMASM_d_m | DMASM_h_m | DMASM_e_m, &lp->rx_dma_regs->dmasm);
++
++ rc32434_init(dev);
++ rc32434_multicast_list(dev);
++
++ enable_irq(lp->und_irq);
++#ifdef RC32434_REVISION
++ enable_irq(lp->ovr_irq);
++#endif
++ enable_irq(lp->tx_irq);
++ enable_irq(lp->rx_irq);
++
++ return 0;
++}
++
++int rc32434_init_module(void)
++{
++#ifdef CONFIG_MACH_ARUBA
++ if (mips_machtype != MACH_ARUBA_AP70)
++ return 1;
++#endif
++
++ printk(KERN_INFO DRIVER_NAME " \n");
++ return rc32434_probe(0);
++}
++
++static int rc32434_probe(int port_num)
++{
++ struct rc32434_if_t *bif = &rc32434_iflist[port_num];
++ struct rc32434_local *lp = NULL;
++ struct net_device *dev = NULL;
++ int i, retval,err;
++
++ dev = alloc_etherdev(sizeof(struct rc32434_local));
++ if(!dev) {
++ ERR("rc32434_eth: alloc_etherdev failed\n");
++ return -1;
++ }
++
++ SET_MODULE_OWNER(dev);
++ bif->dev = dev;
++
++#ifdef CONFIG_MACH_ARUBA
++ {
++ extern char * getenv(char *e);
++ memcpy(bif->mac_str, getenv("ethaddr"), 17);
++ }
++#endif
++
++ printk("mac: %s\n", bif->mac_str);
++ if ((retval = parse_mac_addr(dev, bif->mac_str))) {
++ ERR("MAC address parse failed\n");
++ free_netdev(dev);
++ return -1;
++ }
++
++
++ /* Initialize the device structure. */
++ if (dev->priv == NULL) {
++ lp = (struct rc32434_local *)kmalloc(sizeof(*lp), GFP_KERNEL);
++ memset(lp, 0, sizeof(struct rc32434_local));
++ }
++ else {
++ lp = (struct rc32434_local *)dev->priv;
++ }
++
++ lp->rx_irq = bif->rx_dma_irq;
++ lp->tx_irq = bif->tx_dma_irq;
++ lp->ovr_irq = bif->rx_ovr_irq;
++ lp->und_irq = bif->tx_und_irq;
++
++ lp->eth_regs = ioremap_nocache(bif->iobase, sizeof(*lp->eth_regs));
++
++ if (!lp->eth_regs) {
++ ERR("Can't remap eth registers\n");
++ retval = -ENXIO;
++ goto probe_err_out;
++ }
++
++ lp->rx_dma_regs = ioremap_nocache(bif->rxdmabase, sizeof(struct DMA_Chan_s));
++
++ if (!lp->rx_dma_regs) {
++ ERR("Can't remap Rx DMA registers\n");
++ retval = -ENXIO;
++ goto probe_err_out;
++ }
++ lp->tx_dma_regs = ioremap_nocache(bif->txdmabase,sizeof(struct DMA_Chan_s));
++
++ if (!lp->tx_dma_regs) {
++ ERR("Can't remap Tx DMA registers\n");
++ retval = -ENXIO;
++ goto probe_err_out;
++ }
++
++#ifdef RC32434_PROC_DEBUG
++ lp->ps = create_proc_read_entry (bif->name, 0, proc_net,
++ rc32434_read_proc, dev);
++#endif
++
++ lp->td_ring = (DMAD_t)kmalloc(TD_RING_SIZE + RD_RING_SIZE, GFP_KERNEL);
++ if (!lp->td_ring) {
++ ERR("Can't allocate descriptors\n");
++ retval = -ENOMEM;
++ goto probe_err_out;
++ }
++
++ dma_cache_inv((unsigned long)(lp->td_ring), TD_RING_SIZE + RD_RING_SIZE);
++
++ /* now convert TD_RING pointer to KSEG1 */
++ lp->td_ring = (DMAD_t )KSEG1ADDR(lp->td_ring);
++ lp->rd_ring = &lp->td_ring[RC32434_NUM_TDS];
++
++
++ spin_lock_init(&lp->lock);
++
++ dev->base_addr = bif->iobase;
++ /* just use the rx dma irq */
++ dev->irq = bif->rx_dma_irq;
++
++ dev->priv = lp;
++
++ dev->open = rc32434_open;
++ dev->stop = rc32434_close;
++ dev->hard_start_xmit = rc32434_send_packet;
++ dev->get_stats = rc32434_get_stats;
++ dev->set_multicast_list = &rc32434_multicast_list;
++ dev->tx_timeout = rc32434_tx_timeout;
++ dev->watchdog_timeo = RC32434_TX_TIMEOUT;
++
++#ifdef CONFIG_IDT_USE_NAPI
++ dev->poll = rc32434_poll;
++ dev->weight = bif->weight;
++ printk("Using NAPI with weight %d\n",dev->weight);
++#else
++ lp->rx_tasklet = kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
++ tasklet_init(lp->rx_tasklet, rc32434_rx_tasklet, (unsigned long)dev);
++#endif
++ lp->tx_tasklet = kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
++ tasklet_init(lp->tx_tasklet, rc32434_tx_tasklet, (unsigned long)dev);
++
++ if ((err = register_netdev(dev))) {
++ printk(KERN_ERR "rc32434 ethernet. Cannot register net device %d\n", err);
++ free_netdev(dev);
++ retval = -EINVAL;
++ goto probe_err_out;
++ }
++
++ INFO("Rx IRQ %d, Tx IRQ %d, ", bif->rx_dma_irq, bif->tx_dma_irq);
++ for (i = 0; i < 6; i++) {
++ printk("%2.2x", dev->dev_addr[i]);
++ if (i<5)
++ printk(":");
++ }
++ printk("\n");
++
++ return 0;
++
++ probe_err_out:
++ rc32434_cleanup_module();
++ ERR(" failed. Returns %d\n", retval);
++ return retval;
++
++}
++
++
++static void rc32434_cleanup_module(void)
++{
++ int i;
++
++ for (i = 0; rc32434_iflist[i].iobase; i++) {
++ struct rc32434_if_t * bif = &rc32434_iflist[i];
++ if (bif->dev != NULL) {
++ struct rc32434_local *lp = (struct rc32434_local *)bif->dev->priv;
++ if (lp != NULL) {
++ if (lp->eth_regs)
++ iounmap((void*)lp->eth_regs);
++ if (lp->rx_dma_regs)
++ iounmap((void*)lp->rx_dma_regs);
++ if (lp->tx_dma_regs)
++ iounmap((void*)lp->tx_dma_regs);
++ if (lp->td_ring)
++ kfree((void*)KSEG0ADDR(lp->td_ring));
++
++#ifdef RC32434_PROC_DEBUG
++ if (lp->ps) {
++ remove_proc_entry(bif->name, proc_net);
++ }
++#endif
++ kfree(lp);
++ }
++
++ unregister_netdev(bif->dev);
++ free_netdev(bif->dev);
++ kfree(bif->dev);
++ }
++ }
++}
++
++
++
++static int rc32434_open(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++
++ /* Initialize */
++ if (rc32434_init(dev)) {
++ ERR("Error: cannot open the Ethernet device\n");
++ return -EAGAIN;
++ }
++
++ /* Install the interrupt handler that handles the Done Finished Ovr and Und Events */
++ if (request_irq(lp->rx_irq, &rc32434_rx_dma_interrupt,
++ SA_SHIRQ | SA_INTERRUPT,
++ "rc32434 ethernet Rx", dev)) {
++ ERR(": unable to get Rx DMA IRQ %d\n",
++ lp->rx_irq);
++ return -EAGAIN;
++ }
++ if (request_irq(lp->tx_irq, &rc32434_tx_dma_interrupt,
++ SA_SHIRQ | SA_INTERRUPT,
++ "rc32434 ethernet Tx", dev)) {
++ ERR(": unable to get Tx DMA IRQ %d\n",
++ lp->tx_irq);
++ free_irq(lp->rx_irq, dev);
++ return -EAGAIN;
++ }
++
++#ifdef RC32434_REVISION
++ /* Install handler for overrun error. */
++ if (request_irq(lp->ovr_irq, &rc32434_ovr_interrupt,
++ SA_SHIRQ | SA_INTERRUPT,
++ "Ethernet Overflow", dev)) {
++ ERR(": unable to get OVR IRQ %d\n",
++ lp->ovr_irq);
++ free_irq(lp->rx_irq, dev);
++ free_irq(lp->tx_irq, dev);
++ return -EAGAIN;
++ }
++#endif
++
++ /* Install handler for underflow error. */
++ if (request_irq(lp->und_irq, &rc32434_und_interrupt,
++ SA_SHIRQ | SA_INTERRUPT,
++ "Ethernet Underflow", dev)) {
++ ERR(": unable to get UND IRQ %d\n",
++ lp->und_irq);
++ free_irq(lp->rx_irq, dev);
++ free_irq(lp->tx_irq, dev);
++#ifdef RC32434_REVISION
++ free_irq(lp->ovr_irq, dev);
++#endif
++ return -EAGAIN;
++ }
++
++
++ return 0;
++}
++
++
++
++
++static int rc32434_close(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ u32 tmp;
++
++ /* Disable interrupts */
++ disable_irq(lp->rx_irq);
++ disable_irq(lp->tx_irq);
++#ifdef RC32434_REVISION
++ disable_irq(lp->ovr_irq);
++#endif
++ disable_irq(lp->und_irq);
++
++ tmp = rc32434_readl(&lp->tx_dma_regs->dmasm);
++ tmp = tmp | DMASM_f_m | DMASM_e_m;
++ rc32434_writel(tmp, &lp->tx_dma_regs->dmasm);
++
++ tmp = rc32434_readl(&lp->rx_dma_regs->dmasm);
++ tmp = tmp | DMASM_d_m | DMASM_h_m | DMASM_e_m;
++ rc32434_writel(tmp, &lp->rx_dma_regs->dmasm);
++
++ free_irq(lp->rx_irq, dev);
++ free_irq(lp->tx_irq, dev);
++#ifdef RC32434_REVISION
++ free_irq(lp->ovr_irq, dev);
++#endif
++ free_irq(lp->und_irq, dev);
++ return 0;
++}
++
++
++/* transmit packet */
++static int rc32434_send_packet(struct sk_buff *skb, struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ unsigned long flags;
++ u32 length;
++ DMAD_t td;
++
++
++ spin_lock_irqsave(&lp->lock, flags);
++
++ td = &lp->td_ring[lp->tx_chain_tail];
++
++ /* stop queue when full, drop pkts if queue already full */
++ if(lp->tx_count >= (RC32434_NUM_TDS - 2)) {
++ lp->tx_full = 1;
++
++ if(lp->tx_count == (RC32434_NUM_TDS - 2)) {
++ netif_stop_queue(dev);
++ }
++ else {
++ lp->stats.tx_dropped++;
++ dev_kfree_skb_any(skb);
++ spin_unlock_irqrestore(&lp->lock, flags);
++ return 1;
++ }
++ }
++
++ lp->tx_count ++;
++
++ lp->tx_skb[lp->tx_chain_tail] = skb;
++
++ length = skb->len;
++
++ /* Setup the transmit descriptor. */
++ td->ca = CPHYSADDR(skb->data);
++
++ if(rc32434_readl(&(lp->tx_dma_regs->dmandptr)) == 0) {
++ if( lp->tx_chain_status == empty ) {
++ td->control = DMA_COUNT(length) |DMAD_cof_m |DMAD_iof_m; /* Update tail */
++ lp->tx_chain_tail = (lp->tx_chain_tail + 1) & RC32434_TDS_MASK; /* Move tail */
++ rc32434_writel(CPHYSADDR(&lp->td_ring[lp->tx_chain_head]), &(lp->tx_dma_regs->dmandptr)); /* Write to NDPTR */
++ lp->tx_chain_head = lp->tx_chain_tail; /* Move head to tail */
++ }
++ else {
++ td->control = DMA_COUNT(length) |DMAD_cof_m|DMAD_iof_m; /* Update tail */
++ lp->td_ring[(lp->tx_chain_tail-1)& RC32434_TDS_MASK].control &= ~(DMAD_cof_m); /* Link to prev */
++ lp->td_ring[(lp->tx_chain_tail-1)& RC32434_TDS_MASK].link = CPHYSADDR(td); /* Link to prev */
++ lp->tx_chain_tail = (lp->tx_chain_tail + 1) & RC32434_TDS_MASK; /* Move tail */
++ rc32434_writel(CPHYSADDR(&lp->td_ring[lp->tx_chain_head]), &(lp->tx_dma_regs->dmandptr)); /* Write to NDPTR */
++ lp->tx_chain_head = lp->tx_chain_tail; /* Move head to tail */
++ lp->tx_chain_status = empty;
++ }
++ }
++ else {
++ if( lp->tx_chain_status == empty ) {
++ td->control = DMA_COUNT(length) |DMAD_cof_m |DMAD_iof_m; /* Update tail */
++ lp->tx_chain_tail = (lp->tx_chain_tail + 1) & RC32434_TDS_MASK; /* Move tail */
++ lp->tx_chain_status = filled;
++ }
++ else {
++ td->control = DMA_COUNT(length) |DMAD_cof_m |DMAD_iof_m; /* Update tail */
++ lp->td_ring[(lp->tx_chain_tail-1)& RC32434_TDS_MASK].control &= ~(DMAD_cof_m); /* Link to prev */
++ lp->td_ring[(lp->tx_chain_tail-1)& RC32434_TDS_MASK].link = CPHYSADDR(td); /* Link to prev */
++ lp->tx_chain_tail = (lp->tx_chain_tail + 1) & RC32434_TDS_MASK; /* Move tail */
++ }
++ }
++
++ dev->trans_start = jiffies;
++
++ spin_unlock_irqrestore(&lp->lock, flags);
++
++ return 0;
++}
++
++
++/* Ethernet MII-PHY Handler */
++static void rc32434_mii_handler(unsigned long data)
++{
++ struct net_device *dev = (struct net_device *)data;
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ unsigned long flags;
++ unsigned long duplex_status;
++ int port_addr = (lp->rx_irq == 0x2c? 1:0) << 8;
++
++ spin_lock_irqsave(&lp->lock, flags);
++
++ /* Two ports are using the same MII, the difference is the PHY address */
++ rc32434_writel(0, &rc32434_eth0_regs->miimcfg);
++ rc32434_writel(0, &rc32434_eth0_regs->miimcmd);
++ rc32434_writel(port_addr |0x05, &rc32434_eth0_regs->miimaddr);
++ rc32434_writel(MIIMCMD_scn_m, &rc32434_eth0_regs->miimcmd);
++ while(rc32434_readl(&rc32434_eth0_regs->miimind) & MIIMIND_nv_m);
++
++ ERR("irq:%x port_addr:%x RDD:%x\n",
++ lp->rx_irq, port_addr, rc32434_readl(&rc32434_eth0_regs->miimrdd));
++ duplex_status = (rc32434_readl(&rc32434_eth0_regs->miimrdd) & 0x140)? ETHMAC2_fd_m: 0;
++ if(duplex_status != lp->duplex_mode) {
++ ERR("The MII-PHY is Auto-negotiated to %s-Duplex mode for Eth-%x\n", duplex_status? "Full":"Half", lp->rx_irq == 0x2c? 1:0);
++ lp->duplex_mode = duplex_status;
++ rc32434_restart(dev);
++ }
++
++ lp->mii_phy_timer.expires = jiffies + 10 * HZ;
++ add_timer(&lp->mii_phy_timer);
++
++ spin_unlock_irqrestore(&lp->lock, flags);
++
++}
++
++#ifdef RC32434_REVISION
++/* Ethernet Rx Overflow interrupt */
++static irqreturn_t
++rc32434_ovr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++{
++ struct net_device *dev = (struct net_device *)dev_id;
++ struct rc32434_local *lp;
++ unsigned int ovr;
++ irqreturn_t retval = IRQ_NONE;
++
++ ASSERT(dev != NULL);
++
++ lp = (struct rc32434_local *)dev->priv;
++ spin_lock(&lp->lock);
++ ovr = rc32434_readl(&lp->eth_regs->ethintfc);
++
++ if(ovr & ETHINTFC_ovr_m) {
++ netif_stop_queue(dev);
++
++ /* clear OVR bit */
++ rc32434_writel((ovr & ~ETHINTFC_ovr_m), &lp->eth_regs->ethintfc);
++
++ /* Restart interface */
++ rc32434_restart(dev);
++ retval = IRQ_HANDLED;
++ }
++ spin_unlock(&lp->lock);
++
++ return retval;
++}
++
++#endif
++
++
++/* Ethernet Tx Underflow interrupt */
++static irqreturn_t
++rc32434_und_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++{
++ struct net_device *dev = (struct net_device *)dev_id;
++ struct rc32434_local *lp;
++ unsigned int und;
++ irqreturn_t retval = IRQ_NONE;
++
++ ASSERT(dev != NULL);
++
++ lp = (struct rc32434_local *)dev->priv;
++
++ spin_lock(&lp->lock);
++
++ und = rc32434_readl(&lp->eth_regs->ethintfc);
++
++ if(und & ETHINTFC_und_m) {
++ netif_stop_queue(dev);
++
++ rc32434_writel((und & ~ETHINTFC_und_m), &lp->eth_regs->ethintfc);
++
++ /* Restart interface */
++ rc32434_restart(dev);
++ retval = IRQ_HANDLED;
++ }
++
++ spin_unlock(&lp->lock);
++
++ return retval;
++}
++
++
++/* Ethernet Rx DMA interrupt */
++static irqreturn_t
++rc32434_rx_dma_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++{
++ struct net_device *dev = (struct net_device *)dev_id;
++ struct rc32434_local* lp;
++ volatile u32 dmas,dmasm;
++ irqreturn_t retval;
++
++ ASSERT(dev != NULL);
++
++ lp = (struct rc32434_local *)dev->priv;
++
++ spin_lock(&lp->lock);
++ dmas = rc32434_readl(&lp->rx_dma_regs->dmas);
++ if(dmas & (DMAS_d_m|DMAS_h_m|DMAS_e_m)) {
++ /* Mask D H E bit in Rx DMA */
++ dmasm = rc32434_readl(&lp->rx_dma_regs->dmasm);
++ rc32434_writel(dmasm | (DMASM_d_m | DMASM_h_m | DMASM_e_m), &lp->rx_dma_regs->dmasm);
++#ifdef CONFIG_IDT_USE_NAPI
++ if(netif_rx_schedule_prep(dev))
++ __netif_rx_schedule(dev);
++#else
++ tasklet_hi_schedule(lp->rx_tasklet);
++#endif
++
++ if (dmas & DMAS_e_m)
++ ERR(": DMA error\n");
++
++ retval = IRQ_HANDLED;
++ }
++ else
++ retval = IRQ_NONE;
++
++ spin_unlock(&lp->lock);
++ return retval;
++}
++
++#ifdef CONFIG_IDT_USE_NAPI
++static int rc32434_poll(struct net_device *rx_data_dev, int *budget)
++#else
++static void rc32434_rx_tasklet(unsigned long rx_data_dev)
++#endif
++{
++ struct net_device *dev = (struct net_device *)rx_data_dev;
++ struct rc32434_local* lp = netdev_priv(dev);
++ volatile DMAD_t rd = &lp->rd_ring[lp->rx_next_done];
++ struct sk_buff *skb, *skb_new;
++ u8* pkt_buf;
++ u32 devcs, count, pkt_len, pktuncrc_len;
++ volatile u32 dmas;
++#ifdef CONFIG_IDT_USE_NAPI
++ u32 received = 0;
++ int rx_work_limit = min(*budget,dev->quota);
++#else
++ unsigned long flags;
++ spin_lock_irqsave(&lp->lock, flags);
++#endif
++
++ while ( (count = RC32434_RBSIZE - (u32)DMA_COUNT(rd->control)) != 0) {
++#ifdef CONFIG_IDT_USE_NAPI
++ if(--rx_work_limit <0)
++ {
++ break;
++ }
++#endif
++ /* init the var. used for the later operations within the while loop */
++ skb_new = NULL;
++ devcs = rd->devcs;
++ pkt_len = RCVPKT_LENGTH(devcs);
++ skb = lp->rx_skb[lp->rx_next_done];
++
++ if (count < 64) {
++ lp->stats.rx_errors++;
++ lp->stats.rx_dropped++;
++ }
++ else if ((devcs & ( ETHRX_ld_m)) != ETHRX_ld_m) {
++ /* check that this is a whole packet */
++ /* WARNING: DMA_FD bit incorrectly set in Rc32434 (errata ref #077) */
++ lp->stats.rx_errors++;
++ lp->stats.rx_dropped++;
++ }
++ else if ( (devcs & ETHRX_rok_m) ) {
++
++ {
++ /* must be the (first and) last descriptor then */
++ pkt_buf = (u8*)lp->rx_skb[lp->rx_next_done]->data;
++
++ pktuncrc_len = pkt_len - 4;
++ /* invalidate the cache */
++ dma_cache_inv((unsigned long)pkt_buf, pktuncrc_len);
++
++ /* Malloc up new buffer. */
++ skb_new = dev_alloc_skb(RC32434_RBSIZE + 2);
++
++ if (skb_new != NULL){
++ /* Make room */
++ skb_put(skb, pktuncrc_len);
++
++ skb->protocol = eth_type_trans(skb, dev);
++
++ /* pass the packet to upper layers */
++#ifdef CONFIG_IDT_USE_NAPI
++ netif_receive_skb(skb);
++#else
++ netif_rx(skb);
++#endif
++
++ dev->last_rx = jiffies;
++ lp->stats.rx_packets++;
++ lp->stats.rx_bytes += pktuncrc_len;
++
++ if (IS_RCV_MP(devcs))
++ lp->stats.multicast++;
++
++ /* 16 bit align */
++ skb_reserve(skb_new, 2);
++
++ skb_new->dev = dev;
++ lp->rx_skb[lp->rx_next_done] = skb_new;
++ }
++ else {
++ ERR("no memory, dropping rx packet.\n");
++ lp->stats.rx_errors++;
++ lp->stats.rx_dropped++;
++ }
++ }
++
++ }
++ else {
++ /* This should only happen if we enable accepting broken packets */
++ lp->stats.rx_errors++;
++ lp->stats.rx_dropped++;
++
++ /* add statistics counters */
++ if (IS_RCV_CRC_ERR(devcs)) {
++ DBG(2, "RX CRC error\n");
++ lp->stats.rx_crc_errors++;
++ }
++ else if (IS_RCV_LOR_ERR(devcs)) {
++ DBG(2, "RX LOR error\n");
++ lp->stats.rx_length_errors++;
++ }
++ else if (IS_RCV_LE_ERR(devcs)) {
++ DBG(2, "RX LE error\n");
++ lp->stats.rx_length_errors++;
++ }
++ else if (IS_RCV_OVR_ERR(devcs)) {
++ lp->stats.rx_over_errors++;
++ }
++ else if (IS_RCV_CV_ERR(devcs)) {
++ /* code violation */
++ DBG(2, "RX CV error\n");
++ lp->stats.rx_frame_errors++;
++ }
++ else if (IS_RCV_CES_ERR(devcs)) {
++ DBG(2, "RX Preamble error\n");
++ }
++ }
++
++ rd->devcs = 0;
++
++ /* restore descriptor's curr_addr */
++ if(skb_new)
++ rd->ca = CPHYSADDR(skb_new->data);
++ else
++ rd->ca = CPHYSADDR(skb->data);
++
++ rd->control = DMA_COUNT(RC32434_RBSIZE) |DMAD_cod_m |DMAD_iod_m;
++ lp->rd_ring[(lp->rx_next_done-1)& RC32434_RDS_MASK].control &= ~(DMAD_cod_m);
++
++ lp->rx_next_done = (lp->rx_next_done + 1) & RC32434_RDS_MASK;
++ rd = &lp->rd_ring[lp->rx_next_done];
++ rc32434_writel( ~DMAS_d_m, &lp->rx_dma_regs->dmas);
++ }
++#ifdef CONFIG_IDT_USE_NAPI
++ dev->quota -= received;
++ *budget =- received;
++ if(rx_work_limit < 0)
++ goto not_done;
++#endif
++
++ dmas = rc32434_readl(&lp->rx_dma_regs->dmas);
++
++ if(dmas & DMAS_h_m) {
++ rc32434_writel( ~(DMAS_h_m | DMAS_e_m), &lp->rx_dma_regs->dmas);
++#ifdef RC32434_PROC_DEBUG
++ lp->dma_halt_cnt++;
++#endif
++ rd->devcs = 0;
++ skb = lp->rx_skb[lp->rx_next_done];
++ rd->ca = CPHYSADDR(skb->data);
++ rc32434_chain_rx(lp,rd);
++ }
++
++#ifdef CONFIG_IDT_USE_NAPI
++ netif_rx_complete(dev);
++#endif
++ /* Enable D H E bit in Rx DMA */
++ rc32434_writel(rc32434_readl(&lp->rx_dma_regs->dmasm) & ~(DMASM_d_m | DMASM_h_m |DMASM_e_m), &lp->rx_dma_regs->dmasm);
++#ifdef CONFIG_IDT_USE_NAPI
++ return 0;
++ not_done:
++ return 1;
++#else
++ spin_unlock_irqrestore(&lp->lock, flags);
++ return;
++#endif
++
++
++}
++
++
++
++/* Ethernet Tx DMA interrupt */
++static irqreturn_t
++rc32434_tx_dma_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++{
++ struct net_device *dev = (struct net_device *)dev_id;
++ struct rc32434_local *lp;
++ volatile u32 dmas,dmasm;
++ irqreturn_t retval;
++
++ ASSERT(dev != NULL);
++
++ lp = (struct rc32434_local *)dev->priv;
++
++ spin_lock(&lp->lock);
++
++ dmas = rc32434_readl(&lp->tx_dma_regs->dmas);
++
++ if (dmas & (DMAS_f_m | DMAS_e_m)) {
++ dmasm = rc32434_readl(&lp->tx_dma_regs->dmasm);
++ /* Mask F E bit in Tx DMA */
++ rc32434_writel(dmasm | (DMASM_f_m | DMASM_e_m), &lp->tx_dma_regs->dmasm);
++
++ tasklet_hi_schedule(lp->tx_tasklet);
++
++ if(lp->tx_chain_status == filled && (rc32434_readl(&(lp->tx_dma_regs->dmandptr)) == 0)) {
++ rc32434_writel(CPHYSADDR(&lp->td_ring[lp->tx_chain_head]), &(lp->tx_dma_regs->dmandptr));
++ lp->tx_chain_status = empty;
++ lp->tx_chain_head = lp->tx_chain_tail;
++ dev->trans_start = jiffies;
++ }
++
++ if (dmas & DMAS_e_m)
++ ERR(": DMA error\n");
++
++ retval = IRQ_HANDLED;
++ }
++ else
++ retval = IRQ_NONE;
++
++ spin_unlock(&lp->lock);
++
++ return retval;
++}
++
++
++static void rc32434_tx_tasklet(unsigned long tx_data_dev)
++{
++ struct net_device *dev = (struct net_device *)tx_data_dev;
++ struct rc32434_local* lp = (struct rc32434_local *)dev->priv;
++ volatile DMAD_t td = &lp->td_ring[lp->tx_next_done];
++ u32 devcs;
++ unsigned long flags;
++ volatile u32 dmas;
++
++ spin_lock_irqsave(&lp->lock, flags);
++
++ /* process all desc that are done */
++ while(IS_DMA_FINISHED(td->control)) {
++ if(lp->tx_full == 1) {
++ netif_wake_queue(dev);
++ lp->tx_full = 0;
++ }
++
++ devcs = lp->td_ring[lp->tx_next_done].devcs;
++ if ((devcs & (ETHTX_fd_m | ETHTX_ld_m)) != (ETHTX_fd_m | ETHTX_ld_m)) {
++ lp->stats.tx_errors++;
++ lp->stats.tx_dropped++;
++
++ /* should never happen */
++ DBG(1, __FUNCTION__ ": split tx ignored\n");
++ }
++ else if (IS_TX_TOK(devcs)) {
++ lp->stats.tx_packets++;
++ }
++ else {
++ lp->stats.tx_errors++;
++ lp->stats.tx_dropped++;
++
++ /* underflow */
++ if (IS_TX_UND_ERR(devcs))
++ lp->stats.tx_fifo_errors++;
++
++ /* oversized frame */
++ if (IS_TX_OF_ERR(devcs))
++ lp->stats.tx_aborted_errors++;
++
++ /* excessive deferrals */
++ if (IS_TX_ED_ERR(devcs))
++ lp->stats.tx_carrier_errors++;
++
++ /* collisions: medium busy */
++ if (IS_TX_EC_ERR(devcs))
++ lp->stats.collisions++;
++
++ /* late collision */
++ if (IS_TX_LC_ERR(devcs))
++ lp->stats.tx_window_errors++;
++
++ }
++
++ /* We must always free the original skb */
++ if (lp->tx_skb[lp->tx_next_done] != NULL) {
++ dev_kfree_skb_any(lp->tx_skb[lp->tx_next_done]);
++ lp->tx_skb[lp->tx_next_done] = NULL;
++ }
++
++ lp->td_ring[lp->tx_next_done].control = DMAD_iof_m;
++ lp->td_ring[lp->tx_next_done].devcs = ETHTX_fd_m | ETHTX_ld_m;
++ lp->td_ring[lp->tx_next_done].link = 0;
++ lp->td_ring[lp->tx_next_done].ca = 0;
++ lp->tx_count --;
++
++ /* go on to next transmission */
++ lp->tx_next_done = (lp->tx_next_done + 1) & RC32434_TDS_MASK;
++ td = &lp->td_ring[lp->tx_next_done];
++
++ }
++
++ dmas = rc32434_readl(&lp->tx_dma_regs->dmas);
++ rc32434_writel( ~dmas, &lp->tx_dma_regs->dmas);
++
++ /* Enable F E bit in Tx DMA */
++ rc32434_writel(rc32434_readl(&lp->tx_dma_regs->dmasm) & ~(DMASM_f_m | DMASM_e_m), &lp->tx_dma_regs->dmasm);
++ spin_unlock_irqrestore(&lp->lock, flags);
++
++}
++
++
++static struct net_device_stats * rc32434_get_stats(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ return &lp->stats;
++}
++
++
++/*
++ * Set or clear the multicast filter for this adaptor.
++ */
++static void rc32434_multicast_list(struct net_device *dev)
++{
++ /* listen to broadcasts always and to treat */
++ /* IFF bits independantly */
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ unsigned long flags;
++ u32 recognise = ETHARC_ab_m; /* always accept broadcasts */
++
++ if (dev->flags & IFF_PROMISC) /* set promiscuous mode */
++ recognise |= ETHARC_pro_m;
++
++ if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 15))
++ recognise |= ETHARC_am_m; /* all multicast & bcast */
++ else if (dev->mc_count > 0) {
++ DBG(2, __FUNCTION__ ": mc_count %d\n", dev->mc_count);
++ recognise |= ETHARC_am_m; /* for the time being */
++ }
++
++ spin_lock_irqsave(&lp->lock, flags);
++ rc32434_writel(recognise, &lp->eth_regs->etharc);
++ spin_unlock_irqrestore(&lp->lock, flags);
++}
++
++
++static void rc32434_tx_timeout(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ unsigned long flags;
++
++ spin_lock_irqsave(&lp->lock, flags);
++ rc32434_restart(dev);
++ spin_unlock_irqrestore(&lp->lock, flags);
++
++}
++
++
++/*
++ * Initialize the RC32434 ethernet controller.
++ */
++static int rc32434_init(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ int i, j;
++
++ /* Disable DMA */
++ rc32434_abort_tx(dev);
++ rc32434_abort_rx(dev);
++
++ /* reset ethernet logic */
++ rc32434_writel(0, &lp->eth_regs->ethintfc);
++ while((rc32434_readl(&lp->eth_regs->ethintfc) & ETHINTFC_rip_m))
++ dev->trans_start = jiffies;
++
++ /* Enable Ethernet Interface */
++ rc32434_writel(ETHINTFC_en_m, &lp->eth_regs->ethintfc);
++
++#ifndef CONFIG_IDT_USE_NAPI
++ tasklet_disable(lp->rx_tasklet);
++#endif
++ tasklet_disable(lp->tx_tasklet);
++
++ /* Initialize the transmit Descriptors */
++ for (i = 0; i < RC32434_NUM_TDS; i++) {
++ lp->td_ring[i].control = DMAD_iof_m;
++ lp->td_ring[i].devcs = ETHTX_fd_m | ETHTX_ld_m;
++ lp->td_ring[i].ca = 0;
++ lp->td_ring[i].link = 0;
++ if (lp->tx_skb[i] != NULL) {
++ dev_kfree_skb_any(lp->tx_skb[i]);
++ lp->tx_skb[i] = NULL;
++ }
++ }
++ lp->tx_next_done = lp->tx_chain_head = lp->tx_chain_tail = lp->tx_full = lp->tx_count = 0;
++ lp-> tx_chain_status = empty;
++
++ /*
++ * Initialize the receive descriptors so that they
++ * become a circular linked list, ie. let the last
++ * descriptor point to the first again.
++ */
++ for (i=0; i<RC32434_NUM_RDS; i++) {
++ struct sk_buff *skb = lp->rx_skb[i];
++
++ if (lp->rx_skb[i] == NULL) {
++ skb = dev_alloc_skb(RC32434_RBSIZE + 2);
++ if (skb == NULL) {
++ ERR("No memory in the system\n");
++ for (j = 0; j < RC32434_NUM_RDS; j ++)
++ if (lp->rx_skb[j] != NULL)
++ dev_kfree_skb_any(lp->rx_skb[j]);
++
++ return 1;
++ }
++ else {
++ skb->dev = dev;
++ skb_reserve(skb, 2);
++ lp->rx_skb[i] = skb;
++ lp->rd_ring[i].ca = CPHYSADDR(skb->data);
++
++ }
++ }
++ lp->rd_ring[i].control = DMAD_iod_m | DMA_COUNT(RC32434_RBSIZE);
++ lp->rd_ring[i].devcs = 0;
++ lp->rd_ring[i].ca = CPHYSADDR(skb->data);
++ lp->rd_ring[i].link = CPHYSADDR(&lp->rd_ring[i+1]);
++
++ }
++ /* loop back */
++ lp->rd_ring[RC32434_NUM_RDS-1].link = CPHYSADDR(&lp->rd_ring[0]);
++ lp->rx_next_done = 0;
++
++ lp->rd_ring[RC32434_NUM_RDS-1].control |= DMAD_cod_m;
++ lp->rx_chain_head = 0;
++ lp->rx_chain_tail = 0;
++ lp->rx_chain_status = empty;
++
++ rc32434_writel(0, &lp->rx_dma_regs->dmas);
++ /* Start Rx DMA */
++ rc32434_start_rx(lp, &lp->rd_ring[0]);
++
++ /* Enable F E bit in Tx DMA */
++ rc32434_writel(rc32434_readl(&lp->tx_dma_regs->dmasm) & ~(DMASM_f_m | DMASM_e_m), &lp->tx_dma_regs->dmasm);
++ /* Enable D H E bit in Rx DMA */
++ rc32434_writel(rc32434_readl(&lp->rx_dma_regs->dmasm) & ~(DMASM_d_m | DMASM_h_m | DMASM_e_m), &lp->rx_dma_regs->dmasm);
++
++ /* Accept only packets destined for this Ethernet device address */
++ rc32434_writel(ETHARC_ab_m, &lp->eth_regs->etharc);
++
++ /* Set all Ether station address registers to their initial values */
++ rc32434_writel(STATION_ADDRESS_LOW(dev), &lp->eth_regs->ethsal0);
++ rc32434_writel(STATION_ADDRESS_HIGH(dev), &lp->eth_regs->ethsah0);
++
++ rc32434_writel(STATION_ADDRESS_LOW(dev), &lp->eth_regs->ethsal1);
++ rc32434_writel(STATION_ADDRESS_HIGH(dev), &lp->eth_regs->ethsah1);
++
++ rc32434_writel(STATION_ADDRESS_LOW(dev), &lp->eth_regs->ethsal2);
++ rc32434_writel(STATION_ADDRESS_HIGH(dev), &lp->eth_regs->ethsah2);
++
++ rc32434_writel(STATION_ADDRESS_LOW(dev), &lp->eth_regs->ethsal3);
++ rc32434_writel(STATION_ADDRESS_HIGH(dev), &lp->eth_regs->ethsah3);
++
++
++ /* Frame Length Checking, Pad Enable, CRC Enable, Full Duplex set */
++ rc32434_writel(ETHMAC2_pe_m | ETHMAC2_cen_m | ETHMAC2_fd_m, &lp->eth_regs->ethmac2);
++ //ETHMAC2_flc_m ETHMAC2_fd_m lp->duplex_mode
++
++ /* Back to back inter-packet-gap */
++ rc32434_writel(0x15, &lp->eth_regs->ethipgt);
++ /* Non - Back to back inter-packet-gap */
++ rc32434_writel(0x12, &lp->eth_regs->ethipgr);
++
++ /* Management Clock Prescaler Divisor */
++ /* Clock independent setting */
++ rc32434_writel(((idt_cpu_freq)/MII_CLOCK+1) & ~1,
++ &lp->eth_regs->ethmcp);
++
++ /* don't transmit until fifo contains 48b */
++ rc32434_writel(48, &lp->eth_regs->ethfifott);
++
++ rc32434_writel(ETHMAC1_re_m, &lp->eth_regs->ethmac1);
++
++#ifndef CONFIG_IDT_USE_NAPI
++ tasklet_enable(lp->rx_tasklet);
++#endif
++ tasklet_enable(lp->tx_tasklet);
++
++ netif_start_queue(dev);
++
++
++ return 0;
++
++}
++
++
++#ifndef MODULE
++
++static int __init rc32434_setup(char *options)
++{
++ /* no options yet */
++ return 1;
++}
++
++static int __init rc32434_setup_ethaddr0(char *options)
++{
++ memcpy(mac0, options, 17);
++ mac0[17]= '\0';
++ return 1;
++}
++
++__setup("rc32434eth=", rc32434_setup);
++__setup("ethaddr0=", rc32434_setup_ethaddr0);
++
++
++#endif /* MODULE */
++
++module_init(rc32434_init_module);
++module_exit(rc32434_cleanup_module);
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+diff -Nur linux-2.6.17/drivers/net/rc32434_eth.h linux-2.6.17-owrt/drivers/net/rc32434_eth.h
+--- linux-2.6.17/drivers/net/rc32434_eth.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/drivers/net/rc32434_eth.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,187 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Definitions for IDT RC32434 on-chip ethernet controller.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ * Aug 2004
++ *
++ * Added NAPI
++ *
++ **************************************************************************
++ */
++
++
++#include <asm/idt-boards/rc32434/rc32434.h>
++#include <asm/idt-boards/rc32434/rc32434_dma_v.h>
++#include <asm/idt-boards/rc32434/rc32434_eth_v.h>
++
++#define RC32434_DEBUG 2
++//#define RC32434_PROC_DEBUG
++#undef RC32434_DEBUG
++
++#ifdef RC32434_DEBUG
++
++/* use 0 for production, 1 for verification, >2 for debug */
++static int rc32434_debug = RC32434_DEBUG;
++#define ASSERT(expr) \
++ if(!(expr)) { \
++ printk( "Assertion failed! %s,%s,%s,line=%d\n", \
++ #expr,__FILE__,__FUNCTION__,__LINE__); }
++#define DBG(lvl, format, arg...) if (rc32434_debug > lvl) printk(KERN_INFO "%s: " format, dev->name , ## arg)
++#else
++#define ASSERT(expr) do {} while (0)
++#define DBG(lvl, format, arg...) do {} while (0)
++#endif
++
++#define INFO(format, arg...) printk(KERN_INFO "%s: " format, dev->name , ## arg)
++#define ERR(format, arg...) printk(KERN_ERR "%s: " format, dev->name , ## arg)
++#define WARN(format, arg...) printk(KERN_WARNING "%s: " format, dev->name , ## arg)
++
++#define ETH0_DMA_RX_IRQ GROUP1_IRQ_BASE + 0
++#define ETH0_DMA_TX_IRQ GROUP1_IRQ_BASE + 1
++#define ETH0_RX_OVR_IRQ GROUP3_IRQ_BASE + 9
++#define ETH0_TX_UND_IRQ GROUP3_IRQ_BASE + 10
++
++#define ETH0_RX_DMA_ADDR (DMA0_PhysicalAddress + 0*DMA_CHAN_OFFSET)
++#define ETH0_TX_DMA_ADDR (DMA0_PhysicalAddress + 1*DMA_CHAN_OFFSET)
++
++/* the following must be powers of two */
++#ifdef CONFIG_IDT_USE_NAPI
++#define RC32434_NUM_RDS 64 /* number of receive descriptors */
++#define RC32434_NUM_TDS 64 /* number of transmit descriptors */
++#else
++#define RC32434_NUM_RDS 128 /* number of receive descriptors */
++#define RC32434_NUM_TDS 128 /* number of transmit descriptors */
++#endif
++
++#define RC32434_RBSIZE 1536 /* size of one resource buffer = Ether MTU */
++#define RC32434_RDS_MASK (RC32434_NUM_RDS-1)
++#define RC32434_TDS_MASK (RC32434_NUM_TDS-1)
++#define RD_RING_SIZE (RC32434_NUM_RDS * sizeof(struct DMAD_s))
++#define TD_RING_SIZE (RC32434_NUM_TDS * sizeof(struct DMAD_s))
++
++#define RC32434_TX_TIMEOUT HZ * 100
++
++#define rc32434_eth0_regs ((ETH_t)(ETH0_VirtualAddress))
++#define rc32434_eth1_regs ((ETH_t)(ETH1_VirtualAddress))
++
++enum status { filled, empty};
++#define IS_DMA_FINISHED(X) (((X) & (DMAD_f_m)) != 0)
++#define IS_DMA_DONE(X) (((X) & (DMAD_d_m)) != 0)
++
++
++/* Information that need to be kept for each board. */
++struct rc32434_local {
++ ETH_t eth_regs;
++ DMA_Chan_t rx_dma_regs;
++ DMA_Chan_t tx_dma_regs;
++ volatile DMAD_t td_ring; /* transmit descriptor ring */
++ volatile DMAD_t rd_ring; /* receive descriptor ring */
++
++ struct sk_buff* tx_skb[RC32434_NUM_TDS]; /* skbuffs for pkt to trans */
++ struct sk_buff* rx_skb[RC32434_NUM_RDS]; /* skbuffs for pkt to trans */
++
++#ifndef CONFIG_IDT_USE_NAPI
++ struct tasklet_struct * rx_tasklet;
++#endif
++ struct tasklet_struct * tx_tasklet;
++
++ int rx_next_done;
++ int rx_chain_head;
++ int rx_chain_tail;
++ enum status rx_chain_status;
++
++ int tx_next_done;
++ int tx_chain_head;
++ int tx_chain_tail;
++ enum status tx_chain_status;
++ int tx_count;
++ int tx_full;
++
++ struct timer_list mii_phy_timer;
++ unsigned long duplex_mode;
++
++ int rx_irq;
++ int tx_irq;
++ int ovr_irq;
++ int und_irq;
++
++ struct net_device_stats stats;
++ spinlock_t lock;
++
++ /* debug /proc entry */
++ struct proc_dir_entry *ps;
++ int dma_halt_cnt; int dma_run_cnt;
++};
++
++extern unsigned int idt_cpu_freq;
++
++/* Index to functions, as function prototypes. */
++static int rc32434_open(struct net_device *dev);
++static int rc32434_send_packet(struct sk_buff *skb, struct net_device *dev);
++static void rc32434_mii_handler(unsigned long data);
++static irqreturn_t rc32434_und_interrupt(int irq, void *dev_id, struct pt_regs * regs);
++static irqreturn_t rc32434_rx_dma_interrupt(int irq, void *dev_id, struct pt_regs * regs);
++static irqreturn_t rc32434_tx_dma_interrupt(int irq, void *dev_id, struct pt_regs * regs);
++#ifdef RC32434_REVISION
++static irqreturn_t rc32434_ovr_interrupt(int irq, void *dev_id, struct pt_regs * regs);
++#endif
++static int rc32434_close(struct net_device *dev);
++static struct net_device_stats *rc32434_get_stats(struct net_device *dev);
++static void rc32434_multicast_list(struct net_device *dev);
++static int rc32434_init(struct net_device *dev);
++static void rc32434_tx_timeout(struct net_device *dev);
++
++static void rc32434_tx_tasklet(unsigned long tx_data_dev);
++#ifdef CONFIG_IDT_USE_NAPI
++static int rc32434_poll(struct net_device *rx_data_dev, int *budget);
++#else
++static void rc32434_rx_tasklet(unsigned long rx_data_dev);
++#endif
++static void rc32434_cleanup_module(void);
++static int rc32434_probe(int port_num);
++int rc32434_init_module(void);
++
++
++static inline void rc32434_abort_dma(struct net_device *dev, DMA_Chan_t ch)
++{
++ if (rc32434_readl(&ch->dmac) & DMAC_run_m) {
++ rc32434_writel(0x10, &ch->dmac);
++
++ while (!(rc32434_readl(&ch->dmas) & DMAS_h_m))
++ dev->trans_start = jiffies;
++
++ rc32434_writel(0, &ch->dmas);
++ }
++
++ rc32434_writel(0, &ch->dmadptr);
++ rc32434_writel(0, &ch->dmandptr);
++}
+diff -Nur linux-2.6.17/include/asm-mips/bootinfo.h linux-2.6.17-owrt/include/asm-mips/bootinfo.h
+--- linux-2.6.17/include/asm-mips/bootinfo.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/asm-mips/bootinfo.h 2006-06-18 12:44:28.000000000 +0200
+@@ -218,6 +218,17 @@
+ #define MACH_GROUP_TITAN 22 /* PMC-Sierra Titan */
+ #define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */
+
++
++/*
++ * Valid machtype for group ARUBA
++ */
++#define MACH_GROUP_ARUBA 23
++#define MACH_ARUBA_UNKNOWN 0
++#define MACH_ARUBA_AP60 1
++#define MACH_ARUBA_AP65 2
++#define MACH_ARUBA_AP70 3
++#define MACH_ARUBA_AP40 4
++
+ #define CL_SIZE COMMAND_LINE_SIZE
+
+ const char *get_system_type(void);
+diff -Nur linux-2.6.17/include/asm-mips/cpu.h linux-2.6.17-owrt/include/asm-mips/cpu.h
+--- linux-2.6.17/include/asm-mips/cpu.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/asm-mips/cpu.h 2006-06-18 12:45:56.000000000 +0200
+@@ -54,6 +54,9 @@
+ #define PRID_IMP_R14000 0x0f00
+ #define PRID_IMP_R8000 0x1000
+ #define PRID_IMP_PR4450 0x1200
++#define PRID_IMP_RC32334 0x1800
++#define PRID_IMP_RC32355 0x1900
++#define PRID_IMP_RC32365 0x1900
+ #define PRID_IMP_R4600 0x2000
+ #define PRID_IMP_R4700 0x2100
+ #define PRID_IMP_TX39 0x2200
+@@ -200,7 +203,8 @@
+ #define CPU_SB1A 62
+ #define CPU_74K 63
+ #define CPU_R14000 64
+-#define CPU_LAST 64
++#define CPU_RC32300 65
++#define CPU_LAST 65
+
+ /*
+ * ISA Level encodings
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32300.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32300.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32300.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32300.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,142 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * RC32300 helper routines
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RC32300_H__
++#define __IDT_RC32300_H__
++
++#include <linux/delay.h>
++#include <asm/io.h>
++
++
++/* cpu pipeline flush */
++static inline void rc32300_sync(void)
++{
++ __asm__ volatile ("sync");
++}
++
++static inline void rc32300_sync_udelay(int us)
++{
++ __asm__ volatile ("sync");
++ udelay(us);
++}
++
++static inline void rc32300_sync_delay(int ms)
++{
++ __asm__ volatile ("sync");
++ mdelay(ms);
++}
++
++/*
++ * Macros to access internal RC32300 registers. No byte
++ * swapping should be done when accessing the internal
++ * registers.
++ */
++
++static inline u8 rc32300_readb(unsigned long pa)
++{
++ return *((volatile u8 *)KSEG1ADDR(pa));
++}
++static inline u16 rc32300_readw(unsigned long pa)
++{
++ return *((volatile u16 *)KSEG1ADDR(pa));
++}
++static inline u32 rc32300_readl(unsigned long pa)
++{
++ return *((volatile u32 *)KSEG1ADDR(pa));
++}
++static inline void rc32300_writeb(u8 val, unsigned long pa)
++{
++ *((volatile u8 *)KSEG1ADDR(pa)) = val;
++}
++static inline void rc32300_writew(u16 val, unsigned long pa)
++{
++ *((volatile u16 *)KSEG1ADDR(pa)) = val;
++}
++static inline void rc32300_writel(u32 val, unsigned long pa)
++{
++ *((volatile u32 *)KSEG1ADDR(pa)) = val;
++}
++
++
++#define local_readb __raw_readb
++#define local_readw __raw_readw
++#define local_readl __raw_readl
++
++#define local_writeb __raw_writeb
++#define local_writew __raw_writew
++#define local_writel __raw_writel
++
++
++/*
++ * C access to CLZ and CLO instructions
++ * (count leading zeroes/ones).
++ */
++static inline int rc32300_clz(unsigned long val)
++{
++ int ret;
++ __asm__ volatile (
++ ".set\tnoreorder\n\t"
++ ".set\tnoat\n\t"
++ ".set\tmips32\n\t"
++ "clz\t%0,%1\n\t"
++ ".set\tmips0\n\t"
++ ".set\tat\n\t"
++ ".set\treorder"
++ : "=r" (ret)
++ : "r" (val));
++
++ return ret;
++}
++static inline int rc32300_clo(unsigned long val)
++{
++ int ret;
++ __asm__ volatile (
++ ".set\tnoreorder\n\t"
++ ".set\tnoat\n\t"
++ ".set\tmips32\n\t"
++ "clo\t%0,%1\n\t"
++ ".set\tmips0\n\t"
++ ".set\tat\n\t"
++ ".set\treorder"
++ : "=r" (ret)
++ : "r" (val));
++
++ return ret;
++}
++
++#endif // __IDT_RC32300_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32334.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32334.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32334.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32334.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,207 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Definitions for IDT RC32334 CPU.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++
++#ifndef __IDT_RC32334_H__
++#define __IDT_RC32334_H__
++
++#include <linux/delay.h>
++#include <asm/io.h>
++
++/* Base address of internal registers */
++#define RC32334_REG_BASE 0x18000000
++
++/* CPU and IP Bus Control */
++#define CPU_PORT_WIDTH 0xffffe200 // virtual!
++#define CPU_BTA 0xffffe204 // virtual!
++#define CPU_BUSERR_ADDR 0xffffe208 // virtual!
++#define CPU_IP_BTA (RC32334_REG_BASE + 0x0000)
++#define CPU_IP_ADDR_LATCH (RC32334_REG_BASE + 0x0004)
++#define CPU_IP_ARBITRATION (RC32334_REG_BASE + 0x0008)
++#define CPU_IP_BUSERR_CNTL (RC32334_REG_BASE + 0x0010)
++#define CPU_IP_BUSERR_ADDR (RC32334_REG_BASE + 0x0014)
++#define CPU_IP_SYSID (RC32334_REG_BASE + 0x0018)
++
++/* Memory Controller */
++#define MEM_BASE_BANK0 (RC32334_REG_BASE + 0x0080)
++#define MEM_MASK_BANK0 (RC32334_REG_BASE + 0x0084)
++#define MEM_CNTL_BANK0 (RC32334_REG_BASE + 0x0200)
++#define MEM_BASE_BANK1 (RC32334_REG_BASE + 0x0088)
++#define MEM_MASK_BANK1 (RC32334_REG_BASE + 0x008c)
++#define MEM_CNTL_BANK1 (RC32334_REG_BASE + 0x0204)
++#define MEM_CNTL_BANK2 (RC32334_REG_BASE + 0x0208)
++#define MEM_CNTL_BANK3 (RC32334_REG_BASE + 0x020c)
++#define MEM_CNTL_BANK4 (RC32334_REG_BASE + 0x0210)
++#define MEM_CNTL_BANK5 (RC32334_REG_BASE + 0x0214)
++
++/* PCI Controller */
++#define PCI_INTR_PEND (RC32334_REG_BASE + 0x05b0)
++#define PCI_INTR_MASK (RC32334_REG_BASE + 0x05b4)
++#define PCI_INTR_CLEAR (RC32334_REG_BASE + 0x05b8)
++#define CPU2PCI_INTR_PEND (RC32334_REG_BASE + 0x05c0)
++#define CPU2PCI_INTR_MASK (RC32334_REG_BASE + 0x05c4)
++#define CPU2PCI_INTR_CLEAR (RC32334_REG_BASE + 0x05c8)
++#define PCI2CPU_INTR_PEND (RC32334_REG_BASE + 0x05d0)
++#define PCI2CPU_INTR_MASK (RC32334_REG_BASE + 0x05d4)
++#define PCI2CPU_INTR_CLEAR (RC32334_REG_BASE + 0x05d8)
++#define PCI_MEM1_BASE (RC32334_REG_BASE + 0x20b0)
++#define PCI_MEM2_BASE (RC32334_REG_BASE + 0x20b8)
++#define PCI_MEM3_BASE (RC32334_REG_BASE + 0x20c0)
++#define PCI_IO1_BASE (RC32334_REG_BASE + 0x20c8)
++#define PCI_ARBITRATION (RC32334_REG_BASE + 0x20e0)
++#define PCI_CPU_MEM1_BASE (RC32334_REG_BASE + 0x20e8)
++#define PCI_CPU_IO_BASE (RC32334_REG_BASE + 0x2100)
++#define PCI_CFG_CNTL (RC32334_REG_BASE + 0x2cf8)
++#define PCI_CFG_DATA (RC32334_REG_BASE + 0x2cfc)
++
++/* Timers */
++#define TIMER0_CNTL (RC32334_REG_BASE + 0x0700)
++#define TIMER0_COUNT (RC32334_REG_BASE + 0x0704)
++#define TIMER0_COMPARE (RC32334_REG_BASE + 0x0708)
++#define TIMER_REG_OFFSET 0x10
++
++/* Programmable I/O */
++#define PIO_DATA0 (RC32334_REG_BASE + 0x0600)
++#define PIO_DATA1 (RC32334_REG_BASE + 0x0610)
++
++/*
++ * DMA
++ *
++ * NOTE: DMA_IO is a trick for non linear RC32300_IO_DMA stuff
++ *
++ * DMA0: 18001400
++ * DMA1: 18001440
++ * DMA2: 18001900
++ * DMA3: 18001940
++ * NB: dma number must be immediate value or variable.
++ * It MUST NOT be a function since it would get called twice!
++ */
++#define DMA_IO(n) (((n)>1?0x500:0)+((n)&1?0x40:0))
++
++#define RC32300_IO_DMA(n) (RC32334_REG_BASE + 0x1400 + DMA_IO(n))
++#define RC32300_DMA_CONFREG(n) RC32300_IO_DMA(n)
++#define RC32300_DMA_BASEREG(n) (RC32300_IO_DMA(n)+0x4)
++
++#define RC32300_DMA_CURRREG(n) (RC32300_IO_DMA(n)+0x8)
++#define RC32300_DMA_STATREG(n) (RC32300_IO_DMA(n)+0x10)
++#define RC32300_DMA_SRCREG(n) (RC32300_IO_DMA(n)+0x14)
++#define RC32300_DMA_DSTREG(n) (RC32300_IO_DMA(n)+0x18)
++#define RC32300_DMA_NEXTREG(n) (RC32300_IO_DMA(n)+0x1c)
++
++#define RC32300_DMA_IRQ(n) (GROUP7_IRQ_BASE+5*(n))
++
++/* Expansion Interrupt Controller */
++#define IC_GROUP0_PEND (RC32334_REG_BASE + 0x0500)
++#define IC_GROUP0_MASK (RC32334_REG_BASE + 0x0504)
++#define IC_GROUP0_CLEAR (RC32334_REG_BASE + 0x0508)
++#define IC_GROUP_OFFSET 0x10
++
++#define NUM_INTR_GROUPS 15
++/*
++ * The IRQ mapping is as follows:
++ *
++ * IRQ Mapped To
++ * --- -------------------
++ * 0 SW0 (IP0) SW0 intr
++ * 1 SW1 (IP1) SW1 intr
++ * 2 Int0 (IP2) board-specific
++ * 3 Int1 (IP3) board-specific
++ * 4 Int2 (IP4) board-specific
++ * - Int3 (IP5) not used, mapped to IRQ's 8 and up
++ * 6 Int4 (IP6) board-specific
++ * 7 Int5 (IP7) CP0 Timer
++ *
++ * IRQ's 8 and up are all mapped to Int3 (IP5), which
++ * internally on the RC32334 is routed to the Expansion
++ * Interrupt Controller.
++ */
++#define MIPS_CPU_TIMER_IRQ 7
++
++#define GROUP1_IRQ_BASE 8 // bus error
++#define GROUP2_IRQ_BASE (GROUP1_IRQ_BASE + 1) // PIO active low
++#define GROUP3_IRQ_BASE (GROUP2_IRQ_BASE + 12) // PIO active high
++#define GROUP4_IRQ_BASE (GROUP3_IRQ_BASE + 8) // Timer Rollovers
++#define GROUP5_IRQ_BASE (GROUP4_IRQ_BASE + 8) // UART0
++#define GROUP6_IRQ_BASE (GROUP5_IRQ_BASE + 3) // UART1
++#define GROUP7_IRQ_BASE (GROUP6_IRQ_BASE + 3) // DMA Ch0
++#define GROUP8_IRQ_BASE (GROUP7_IRQ_BASE + 5) // DMA Ch1
++#define GROUP9_IRQ_BASE (GROUP8_IRQ_BASE + 5) // DMA Ch2
++#define GROUP10_IRQ_BASE (GROUP9_IRQ_BASE + 5) // DMA Ch3
++#define GROUP11_IRQ_BASE (GROUP10_IRQ_BASE + 5) // PCI Ctlr errors
++#define GROUP12_IRQ_BASE (GROUP11_IRQ_BASE + 4) // PCI Satellite Mode
++#define GROUP13_IRQ_BASE (GROUP12_IRQ_BASE + 16) // PCI to CPU Mailbox
++#define GROUP14_IRQ_BASE (GROUP13_IRQ_BASE + 4) // SPI
++
++#define RC32334_NR_IRQS (GROUP14_IRQ_BASE + 1)
++
++/* 16550 UARTs */
++#ifdef __MIPSEB__
++#define RC32300_UART0_BASE (RC32334_REG_BASE + 0x0803)
++#define RC32300_UART1_BASE (RC32334_REG_BASE + 0x0823)
++#else
++#define RC32300_UART0_BASE (RC32334_REG_BASE + 0x0800)
++#define RC32300_UART1_BASE (RC32334_REG_BASE + 0x0820)
++#endif
++
++#define RC32300_UART0_IRQ GROUP5_IRQ_BASE
++#define RC32300_UART1_IRQ GROUP6_IRQ_BASE
++
++#define IDT_CLOCK_MULT 2
++
++/* NVRAM */
++#define NVRAM_BASE 0x12000000
++#define NVRAM_ENVSIZE_OFF 4
++#define NVRAM_ENVSTART_OFF 0x40
++
++/* LCD 4-digit display */
++#define LCD_CLEAR 0x14000400
++#define LCD_DIGIT0 0x1400000f
++#define LCD_DIGIT1 0x14000008
++#define LCD_DIGIT2 0x14000007
++#define LCD_DIGIT3 0x14000003
++
++/* Interrupts routed on 79S334A board (see rc32334.h) */
++#define RC32334_SCC8530_IRQ 2
++#define RC32334_PCI_INTA_IRQ 3
++#define RC32334_PCI_INTB_IRQ 4
++#define RC32334_PCI_INTC_IRQ 6
++#define RC32334_PCI_INTD_IRQ 7
++
++#define RAM_SIZE (32*1024*1024)
++
++#endif // __IDT_RC32334_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32355_dma.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32355_dma.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32355_dma.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32355_dma.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,206 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * DMA controller defines on IDT RC32355
++ *
++ * Copyright 2004 IDT Inc.
++ * Author: Integrated Device Technology Inc. rischelp@idt.com
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * May 2004 rkt
++ * Initial Release
++ *
++ **************************************************************************
++ */
++
++#ifndef BANYAN_DMA_H
++#define BANYAN_DMA_H
++#include <asm/idt-boards/rc32300/rc32300.h>
++
++/*
++ * An image of one RC32355 dma channel registers
++ */
++typedef struct {
++ u32 dmac;
++ u32 dmas;
++ u32 dmasm;
++ u32 dmadptr;
++ u32 dmandptr;
++} rc32355_dma_ch_t;
++
++/*
++ * An image of all RC32355 dma channel registers
++ */
++typedef struct {
++ rc32355_dma_ch_t ch[16];
++} rc32355_dma_regs_t;
++
++
++#define rc32355_dma_regs ((rc32355_dma_regs_t*)KSEG1ADDR(RC32355_DMA_BASE))
++
++
++/* DMAC register layout */
++
++#define DMAC_RUN 0x1 /* Halts processing when cleared */
++#define DMAC_DM 0x2 /* Done Mask, ignore DMA events */
++#define DMAC_MODE_MASK 0xC /* DMA operating mode */
++
++#define DMAC_MODE_AUTO 0x0 /* DMA Auto Request Mode */
++#define DMAC_MODE_BURST 0x4 /* DMA Burst Request Mode */
++#define DMAC_MODE_TFER 0x8 /* DMA Transfer Request Mode */
++
++/* DMAS and DMASM register layout */
++
++#define DMAS_F 0x01 /* Finished */
++#define DMAS_D 0x02 /* Done */
++#define DMAS_C 0x04 /* Chain */
++#define DMAS_E 0x08 /* Error */
++#define DMAS_H 0x10 /* Halt */
++
++/* Polling count for DMAS_H bit in DMAS register after halting DMA */
++#define DMA_HALT_TIMEOUT 500
++
++
++static inline int rc32355_halt_dma(rc32355_dma_ch_t* ch)
++{
++ int timeout=1;
++
++ if (local_readl(&ch->dmac) & DMAC_RUN) {
++ local_writel(0, &ch->dmac);
++ for (timeout = DMA_HALT_TIMEOUT; timeout > 0; timeout--) {
++ if (local_readl(&ch->dmas) & DMAS_H) {
++ local_writel(0, &ch->dmas);
++ break;
++ }
++ }
++ }
++
++ return timeout ? 0 : 1;
++}
++
++static inline void rc32355_start_dma(rc32355_dma_ch_t* ch, u32 dma_addr)
++{
++ local_writel(0, &ch->dmandptr);
++ local_writel(dma_addr, &ch->dmadptr);
++}
++
++static inline void rc32355_chain_dma(rc32355_dma_ch_t* ch, u32 dma_addr)
++{
++ local_writel(dma_addr, &ch->dmandptr);
++}
++
++
++/* The following can be used to describe DMA channels 0 to 15, and the */
++/* sub device's needed to select them in the DMADESC_DS_MASK field */
++
++#define DMA_CHAN_ATM01 0 /* ATM interface 0,1 chan */
++
++#define DMA_CHAN_ATM0IN 0 /* ATM interface 0 input */
++#define DMA_DEV_ATM0IN 0 /* ATM interface 0 input */
++
++#define DMA_CHAN_ATM1IN 0 /* ATM interface 1 input */
++#define DMA_DEV_ATM1IN 1 /* ATM interface 1 input */
++
++#define DMA_CHAN_ATM0OUT 0 /* ATM interface 0 output */
++#define DMA_DEV_ATM0OUT 2 /* ATM interface 0 output */
++
++#define DMA_CHAN_ATM1OUT 0 /* ATM interface 1 output */
++#define DMA_DEV_ATM1OUT 3 /* ATM interface 1 output */
++
++/* for entry in {0,1,2,3,4,5,6,7} - note 5,6,7 share with those below */
++#define DMA_CHAN_ATMVCC(entry) ((entry)+1) /* ATM VC cache entry */
++#define DMA_DEV_ATMVCC(entry) 0
++
++#define DMA_CHAN_MEMTOMEM 6 /* Memory to memory DMA */
++#define DMA_DEV_MEMTOMEM 1 /* Memory to memory DMA */
++
++#define DMA_CHAN_ATMFMB0 7 /* ATM Frame Mode Buffer 0 */
++#define DMA_DEV_ATMFMB0 1 /* ATM Frame Mode Buffer 0 */
++
++#define DMA_CHAN_ATMFMB1 8 /* ATM Frame Mode Buffer 1 */
++#define DMA_DEV_ATMFMB1 1 /* ATM Frame Mode Buffer 1 */
++
++#define DMA_CHAN_ETHERIN 9 /* Ethernet input */
++#define DMA_DEV_ETHERIN 0 /* Ethernet input */
++
++#define DMA_CHAN_ETHEROUT 10 /* Ethernet output */
++#define DMA_DEV_ETHEROUT 0 /* Ethernet output */
++
++#define DMA_CHAN_TDMIN 11 /* TDM Bus input */
++#define DMA_DEV_TDMIN 0 /* TDM Bus input */
++
++#define DMA_CHAN_TDMOUT 12 /* TDM Bus output */
++#define DMA_DEV_TDMOUT 0 /* TDM Bus output */
++
++#define DMA_CHAN_USBIN 13 /* USB input */
++#define DMA_DEV_USBIN 0 /* USB input */
++
++#define DMA_CHAN_USBOUT 14 /* USB output */
++#define DMA_DEV_USBOUT 0 /* USB output */
++
++#define DMA_CHAN_EXTERN 15 /* External DMA */
++#define DMA_DEV_EXTERN 0 /* External DMA */
++
++/*
++ * An RC32355 dma descriptor in system memory
++ */
++typedef struct {
++ u32 cmdstat; /* control and status */
++ u32 curr_addr; /* current address of data */
++ u32 devcs; /* peripheral-specific control and status */
++ u32 link; /* link to next descriptor */
++} rc32355_dma_desc_t;
++
++/* Values for the descriptor cmdstat word */
++
++#define DMADESC_F 0x80000000u /* Finished bit */
++#define DMADESC_D 0x40000000u /* Done bit */
++#define DMADESC_T 0x20000000u /* Terminated bit */
++#define DMADESC_IOD 0x10000000u /* Interrupt On Done */
++#define DMADESC_IOF 0x08000000u /* Interrupt On Finished */
++#define DMADESC_COD 0x04000000u /* Chain On Done */
++#define DMADESC_COF 0x02000000u /* Chain On Finished */
++
++#define DMADESC_DEVCMD_MASK 0x01C00000u /* Device Command mask */
++#define DMADESC_DEVCMD_SHIFT 22 /* Device Command shift */
++
++#define DMADESC_DS_MASK 0x00300000u /* Device Select mask */
++#define DMADESC_DS_SHIFT 20 /* Device Select shift */
++
++#define DMADESC_COUNT_MASK 0x0003FFFFu /* Byte Count mask */
++#define DMADESC_COUNT_SHIFT 0 /* Byte Count shift */
++
++#define IS_DMA_FINISHED(X) ( ( (X) & DMADESC_F ) >> 31) /* F Bit */
++#define IS_DMA_DONE(X) ( ( (X) & DMADESC_D ) >> 30) /* D Bit */
++#define IS_DMA_TERMINATED(X) ( ( (X) & DMADESC_T ) >> 29) /* T Bit */
++#define IS_DMA_USED(X) (((X) & (DMADESC_F | DMADESC_D | DMADESC_T)) != 0)
++
++#define DMA_DEVCMD(devcmd) \
++ (((devcmd) << DMADESC_DEVCMD_SHIFT) & DMADESC_DS_MASK)
++#define DMA_DS(ds) \
++ (((ds) << DMADESC_DS_SHIFT) & DMADESC_DS_MASK)
++#define DMA_COUNT(count) \
++ ((count) & DMADESC_COUNT_MASK)
++
++#endif /* RC32355_DMA_H */
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32355_eth.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32355_eth.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32355_eth.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32355_eth.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,442 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Ethernet registers on IDT RC32355
++ *
++ * Copyright 2004 IDT Inc.
++ * Author: Integrated Device Technology Inc. rischelp@idt.com
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * May 2004 rkt
++ * Initial Release
++ *
++ **************************************************************************
++ */
++
++
++#ifndef RC32355_ETHER_H
++#define RC32355_ETHER_H
++
++#include <asm/idt-boards/rc32300/rc32355_dma.h>
++
++/*
++ * A partial image of the RC32355 ethernet registers
++ */
++typedef struct {
++ u32 ethintfc;
++ u32 ethfifott;
++ u32 etharc;
++ u32 ethhash0;
++ u32 ethhash1;
++ u32 ethfifost;
++ u32 ethfifos;
++ u32 ethodeops;
++ u32 ethis;
++ u32 ethos;
++ u32 ethmcp;
++ u32 _u1;
++ u32 ethid;
++ u32 _u2;
++ u32 _u3;
++ u32 _u4;
++ u32 ethod;
++ u32 _u5;
++ u32 _u6;
++ u32 _u7;
++ u32 ethodeop;
++ u32 _u8[43];
++ u32 ethsal0;
++ u32 ethsah0;
++ u32 ethsal1;
++ u32 ethsah1;
++ u32 ethsal2;
++ u32 ethsah2;
++ u32 ethsal3;
++ u32 ethsah3;
++ u32 ethrbc;
++ u32 ethrpc;
++ u32 ethrupc;
++ u32 ethrfc;
++ u32 ethtbc;
++ u32 ethgpf;
++ u32 _u9[50];
++ u32 ethmac1;
++ u32 ethmac2;
++ u32 ethipgt;
++ u32 ethipgr;
++ u32 ethclrt;
++ u32 ethmaxf;
++ u32 _u10;
++ u32 ethmtest;
++ u32 miimcfg;
++ u32 miimcmd;
++ u32 miimaddr;
++ u32 miimwtd;
++ u32 miimrdd;
++ u32 miimind;
++ u32 _u11;
++ u32 _u12;
++ u32 ethcfsa0;
++ u32 ethcfsa1;
++ u32 ethcfsa2;
++} rc32355_eth_regs_t;
++
++#define rc32355_eth_regs ((rc32355_eth_regs_t*)KSEG1ADDR(RC32355_ETH_BASE))
++
++#define ETH_INTFC (RC32355_ETH_BASE + 0x000) /* INTerFace Control */
++#define ETH_FIFOTT (RC32355_ETH_BASE + 0x004) /* FIFO Transmit Threshold */
++#define ETH_ARC (RC32355_ETH_BASE + 0x008) /* Address Recognition Ctrl */
++#define ETH_HASH0 (RC32355_ETH_BASE + 0x00C) /* 32 multicast Hash bits */
++#define ETH_HASH1 (RC32355_ETH_BASE + 0x010) /* another 32 Hash bits */
++#define ETH_FIFOST (RC32355_ETH_BASE + 0x014) /* FIFO Status Threshold */
++#define ETH_FIFOS (RC32355_ETH_BASE + 0x018) /* FIFO Status Register */
++#define ETH_ODEOPS (RC32355_ETH_BASE + 0x01C) /* Out Data End-Of-Pkt Size */
++#define ETH_IS (RC32355_ETH_BASE + 0x020) /* Input Status */
++#define ETH_OS (RC32355_ETH_BASE + 0x024) /* Output Status */
++#define ETH_MCP (RC32355_ETH_BASE + 0x028) /* Managemt Clock Prescaler */
++#define ETH_ID (RC32355_ETH_BASE + 0x030) /* Input Data register */
++#define ETH_OD (RC32355_ETH_BASE + 0x040) /* Output Data register */
++#define ETH_ODEOP (RC32355_ETH_BASE + 0x050) /* OD End-Of-Packet Size */
++
++/* for n in { 0, 1, 2, 3 } */
++#define ETH_SAL(n) (RC32355_ETH_BASE + 0x100 + (n * 8)) /* Stn Address 2-5 */
++#define ETH_SAH(n) (RC32355_ETH_BASE + 0x104 + (n * 8)) /* Stn Address 0-1 */
++
++#define ETH_RBC (RC32355_ETH_BASE + 0x120) /* Receive Byte Count */
++#define ETH_RPC (RC32355_ETH_BASE + 0x124) /* Receive Packet Count */
++#define ETH_RUPC (RC32355_ETH_BASE + 0x128) /* Rx Undersized Pkt count */
++#define ETH_RFC (RC32355_ETH_BASE + 0x12C) /* Receive Fragment Count */
++#define ETH_TBC (RC32355_ETH_BASE + 0x130) /* Transmit Byte Count */
++#define ETH_GPF (RC32355_ETH_BASE + 0x134) /* Generate Pause Frame */
++#define ETH_MAC1 (RC32355_ETH_BASE + 0x200) /* Medium Access Control 1 */
++#define ETH_MAC2 (RC32355_ETH_BASE + 0x204) /* Medium Access Control 2 */
++#define ETH_IPGT (RC32355_ETH_BASE + 0x208) /* Back-to-back InterPkt Gap */
++#define ETH_IPGR (RC32355_ETH_BASE + 0x20C) /* Non " InterPkt Gap */
++#define ETH_CLRT (RC32355_ETH_BASE + 0x210) /* Collis'n Window and Retry */
++#define ETH_MAXF (RC32355_ETH_BASE + 0x214) /* Maximum Frame Length */
++#define ETH_MTEST (RC32355_ETH_BASE + 0x21C) /* MAC Test */
++
++#define ETHMIIM_CFG (RC32355_ETH_BASE + 0x220) /* MII Mgmt Configuration */
++#define ETHMIIM_CMD (RC32355_ETH_BASE + 0x224) /* MII Mgmt Command */
++#define ETHMIIM_ADDR (RC32355_ETH_BASE + 0x228) /* MII Mgmt Address */
++#define ETHMIIM_WTD (RC32355_ETH_BASE + 0x22C) /* MII Mgmt Write Data */
++#define ETHMIIM_RDD (RC32355_ETH_BASE + 0x230) /* MII Mgmt Read Data */
++#define ETHMIIM_IND (RC32355_ETH_BASE + 0x234) /* MII Mgmt Indicators */
++
++/* for n in { 0, 1, 2 } */
++#define ETH_CFSA(n) (RC32355_ETH_BASE + 0x240 + ((n) * 4)) /* Station Addr */
++
++
++/*
++ * Register Interpretations follow
++ */
++
++/******************************************************************************
++ * ETHINTFC register
++ *****************************************************************************/
++
++#define ETHERINTFC_EN (1<<0)
++#define ETHERINTFC_ITS (1<<1)
++#define ETHERINTFC_RES (1<<2)
++#define ETHERINTFC_RIP (1<<2)
++#define ETHERINTFC_JAM (1<<3)
++
++/******************************************************************************
++ * ETHFIFOTT register
++ *****************************************************************************/
++
++#define ETHERFIFOTT_TTH(v) (((v)&0x3f)<<0)
++
++/******************************************************************************
++ * ETHARC register
++ *****************************************************************************/
++
++#define ETHERARC_PRO (1<<0)
++#define ETHERARC_AM (1<<1)
++#define ETHERARC_AFM (1<<2)
++#define ETHERARC_AB (1<<3)
++
++/******************************************************************************
++ * ETHHASH registers
++ *****************************************************************************/
++
++#define ETHERHASH0(v) (((v)&0xffff)<<0)
++#define ETHERHASH1(v) (((v)&0xffff)<<0)
++
++/******************************************************************************
++ * ETHSA registers
++ *****************************************************************************/
++
++#define ETHERSAL0(v) (((v)&0xffff)<<0)
++#define ETHERSAL1(v) (((v)&0xffff)<<0)
++#define ETHERSAL2(v) (((v)&0xffff)<<0)
++#define ETHERSAL3(v) (((v)&0xffff)<<0)
++#define ETHERSAH0(v) (((v)&0xff)<<0)
++#define ETHERSAH1(v) (((v)&0xff)<<0)
++#define ETHERSAH2(v) (((v)&0xff)<<0)
++#define ETHERSAH3(v) (((v)&0xff)<<0)
++
++/******************************************************************************
++ * ETHFIFOST register
++ *****************************************************************************/
++
++#define ETHERFIFOST_IRTH(v) (((v)&0x3f)<<0)
++#define ETHERFIFOST_ORTH(v) (((v)&0x3f)<<16)
++
++/******************************************************************************
++ * ETHFIFOS register
++ *****************************************************************************/
++
++#define ETHERFIFOS_IR (1<<0)
++#define ETHERFIFOS_OR (1<<1)
++#define ETHERFIFOS_OVR (1<<2)
++#define ETHERFIFOS_UND (1<<3)
++
++/******************************************************************************
++ * DATA registers
++ *****************************************************************************/
++
++#define ETHERID(v) (((v)&0xffff)<<0)
++#define ETHEROD(v) (((v)&0xffff)<<0)
++
++/******************************************************************************
++ * ETHODEOPS register
++ *****************************************************************************/
++
++#define ETHERODEOPS_SIZE(v) (((v)&0x3)<<0)
++
++/******************************************************************************
++ * ETHODEOP register
++ *****************************************************************************/
++
++#define ETHERODEOP(v) (((v)&0xffff)<<0)
++
++/******************************************************************************
++ * ETHIS register
++ *****************************************************************************/
++
++#define ETHERIS_EOP (1<<0)
++#define ETHERIS_ROK (1<<2)
++#define ETHERIS_FM (1<<3)
++#define ETHERIS_MP (1<<4)
++#define ETHERIS_BP (1<<5)
++#define ETHERIS_VLT (1<<6)
++#define ETHERIS_CF (1<<7)
++#define ETHERIS_OVR (1<<8)
++#define ETHERIS_CRC (1<<9)
++#define ETHERIS_CV (1<<10)
++#define ETHERIS_DB (1<<11)
++#define ETHERIS_LE (1<<12)
++#define ETHERIS_LOR (1<<13)
++#define ETHERIS_SIZE(v) (((v)&0x3)<<14)
++#define ETHERIS_LENGTH(v) (((v)&0xff)<<16)
++
++/******************************************************************************
++ * ETHOS register
++ *****************************************************************************/
++
++#define ETHEROS_T (1<<0)
++#define ETHEROS_TOK (1<<6)
++#define ETHEROS_MP (1<<7)
++#define ETHEROS_BP (1<<8)
++#define ETHEROS_UND (1<<9)
++#define ETHEROS_OF (1<<10)
++#define ETHEROS_ED (1<<11)
++#define ETHEROS_EC (1<<12)
++#define ETHEROS_LC (1<<13)
++#define ETHEROS_TD (1<<14)
++#define ETHEROS_CRC (1<<15)
++#define ETHEROS_LE (1<<16)
++#define ETHEROS_CC(v) (((v)&0xf)<<17)
++#define ETHEROS_PFD (1<<21)
++
++/******************************************************************************
++ * Statistics registers
++ *****************************************************************************/
++
++#define ETHERRBC(v) (((v)&0xffff)<<0)
++#define ETHERRPC(v) (((v)&0xffff)<<0)
++#define ETHERRUPC(v) (((v)&0xffff)<<0)
++#define ETHERRFC(v) (((v)&0xffff)<<0)
++#define ETHERTBC(v) (((v)&0xffff)<<0)
++
++/******************************************************************************
++ * ETHGPF register
++ *****************************************************************************/
++
++#define ETHERGPF_PTV(v) (((v)&0xff)<<0)
++
++/******************************************************************************
++ * MAC registers
++ *****************************************************************************/
++//ETHMAC1
++#define ETHERMAC1_RE (1<<0)
++#define ETHERMAC1_PAF (1<<1)
++#define ETHERMAC1_RFC (1<<2)
++#define ETHERMAC1_TFC (1<<3)
++#define ETHERMAC1_LB (1<<4)
++#define ETHERMAC1_MR (1<<15)
++
++//ETHMAC2
++#define ETHERMAC2_FD (1<<0)
++#define ETHERMAC2_FLC (1<<1)
++#define ETHERMAC2_HFE (1<<2)
++#define ETHERMAC2_DC (1<<3)
++#define ETHERMAC2_CEN (1<<4)
++#define ETHERMAC2_PE (1<<5)
++#define ETHERMAC2_VPE (1<<6)
++#define ETHERMAC2_APE (1<<7)
++#define ETHERMAC2_PPE (1<<8)
++#define ETHERMAC2_LPE (1<<9)
++#define ETHERMAC2_NB (1<<12)
++#define ETHERMAC2_BP (1<<13)
++#define ETHERMAC2_ED (1<<14)
++
++//ETHIPGT
++#define ETHERIPGT(v) (((v)&0x3f)<<0)
++
++//ETHIPGR
++#define ETHERIPGR_IPGR1(v) (((v)&0x3f)<<0)
++#define ETHERIPGR_IPGR2(v) (((v)&0x3f)<<8)
++
++//ETHCLRT
++#define ETHERCLRT_MAXRET(v) (((v)&0x3f)<<0)
++#define ETHERCLRT_COLWIN(v) (((v)&0x3f)<<8)
++
++//ETHMAXF
++#define ETHERMAXF(v) (((v)&0x3f)<<0)
++
++//ETHMTEST
++#define ETHERMTEST_TB (1<<2)
++
++//ETHMCP
++#define ETHERMCP_DIV(v) (((v)&0xff)<<0)
++
++//MIIMCFG
++#define ETHERMIIMCFG_CS(v) (((v)&0x3)<<2)
++#define ETHERMIIMCFG_R (1<<15)
++
++//MIIMCMD
++#define ETHERMIIMCMD_RD (1<<0)
++#define ETHERMIIMCMD_SCN (1<<1)
++
++//MIIMADDR
++#define ETHERMIIMADDR_REGADDR(v) (((v)&0x1f)<<0)
++#define ETHERMIIMADDR_PHYADDR(v) (((v)&0x1f)<<8)
++
++//MIIMWTD
++#define ETHERMIIMWTD(v) (((v)&0xff)<<0)
++
++//MIIMRDD
++#define ETHERMIIMRDD(v) (((v)&0xff)<<0)
++
++//MIIMIND
++#define ETHERMIIMIND_BSY (1<<0)
++#define ETHERMIIMIND_SCN (1<<1)
++#define ETHERMIIMIND_NV (1<<2)
++
++//DMA DEVCS IN
++#define ETHERDMA_IN_LENGTH(v) (((v)&0xffff)<<16)
++#define ETHERDMA_IN_CES (1<<14)
++#define ETHERDMA_IN_LOR (1<<13)
++#define ETHERDMA_IN_LE (1<<12)
++#define ETHERDMA_IN_DB (1<<11)
++#define ETHERDMA_IN_CV (1<<10)
++#define ETHERDMA_IN_CRC (1<<9)
++#define ETHERDMA_IN_OVR (1<<8)
++#define ETHERDMA_IN_CF (1<<7)
++#define ETHERDMA_IN_VLT (1<<6)
++#define ETHERDMA_IN_BP (1<<5)
++#define ETHERDMA_IN_MP (1<<4)
++#define ETHERDMA_IN_FM (1<<3)
++#define ETHERDMA_IN_ROK (1<<2)
++#define ETHERDMA_IN_LD (1<<1)
++#define ETHERDMA_IN_FD (1<<0)
++
++//DMA DEVCS OUT
++#define ETHERDMA_OUT_CC(v) (((v)&0xf)<<17)
++#define ETHERDMA_OUT_CNT 0x001e0000
++#define ETHERDMA_OUT_SHFT 17
++#define ETHERDMA_OUT_LE (1<<16)
++
++#define ETHERDMA_OUT_CRC (1<<15)
++#define ETHERDMA_OUT_TD (1<<14)
++#define ETHERDMA_OUT_LC (1<<13)
++#define ETHERDMA_OUT_EC (1<<12)
++#define ETHERDMA_OUT_ED (1<<11)
++#define ETHERDMA_OUT_OF (1<<10)
++#define ETHERDMA_OUT_UND (1<<9)
++#define ETHERDMA_OUT_BP (1<<8)
++#define ETHERDMA_OUT_MP (1<<7)
++#define ETHERDMA_OUT_TOK (1<<6)
++#define ETHERDMA_OUT_HEN (1<<5)
++#define ETHERDMA_OUT_CEN (1<<4)
++#define ETHERDMA_OUT_PEN (1<<3)
++#define ETHERDMA_OUT_OEN (1<<2)
++#define ETHERDMA_OUT_LD (1<<1)
++#define ETHERDMA_OUT_FD (1<<0)
++
++#define RCV_ERRS \
++ (ETHERDMA_IN_OVR | ETHERDMA_IN_CRC | ETHERDMA_IN_CV | ETHERDMA_IN_LE)
++#define TX_ERRS \
++ (ETHERDMA_OUT_LC | ETHERDMA_OUT_EC | ETHERDMA_OUT_ED | \
++ ETHERDMA_OUT_OF | ETHERDMA_OUT_UND)
++
++#define IS_RCV_ROK(X) (((X) & (1<<2)) >> 2) /* Receive Okay */
++#define IS_RCV_FM(X) (((X) & (1<<3)) >> 3) /* Is Filter Match */
++#define IS_RCV_MP(X) (((X) & (1<<4)) >> 4) /* Is it MP */
++#define IS_RCV_BP(X) (((X) & (1<<5)) >> 5) /* Is it BP */
++#define IS_RCV_VLT(X) (((X) & (1<<6)) >> 6) /* VLAN Tag Detect */
++#define IS_RCV_CF(X) (((X) & (1<<7)) >> 7) /* Control Frame */
++#define IS_RCV_OVR_ERR(X) (((X) & (1<<8)) >> 8) /* Receive Overflow */
++#define IS_RCV_CRC_ERR(X) (((X) & (1<<9)) >> 9) /* CRC Error */
++#define IS_RCV_CV_ERR(X) (((X) & (1<<10))>>10) /* Code Violation */
++#define IS_RCV_DB_ERR(X) (((X) & (1<<11))>>11) /* Dribble Bits */
++#define IS_RCV_LE_ERR(X) (((X) & (1<<12))>>12) /* Length error */
++#define IS_RCV_LOR_ERR(X) (((X) & (1<<13))>>13) /* Length Out of
++ Range */
++#define IS_RCV_CES_ERR(X) (((X) & (1<<14))>>14) /* Preamble error */
++#define RCVPKT_LENGTH(X) (((X) & 0xFFFF0000)>>16) /* Length of the
++ received packet */
++
++#define IS_TX_TOK(X) (((X) & (1<<6) ) >> 6 ) /* Transmit Okay */
++#define IS_TX_MP(X) (((X) & (1<<7) ) >> 7 ) /* Multicast */
++
++#define IS_TX_BP(X) (((X) & (1<<8) ) >> 8 ) /* Broadcast */
++#define IS_TX_UND_ERR(X) (((X) & (1<<9) ) >> 9 ) /* Transmit FIFO
++ Underflow */
++#define IS_TX_OF_ERR(X) (((X) & (1<<10)) >>10 ) /* Oversized frame */
++#define IS_TX_ED_ERR(X) (((X) & (1<<11)) >>11 ) /* Excessive
++ deferral */
++#define IS_TX_EC_ERR(X) (((X) & (1<<12)) >>12 ) /* Excessive
++ collisions */
++#define IS_TX_LC_ERR(X) (((X) & (1<<13)) >>13 ) /* Late Collision */
++#define IS_TX_TD_ERR(X) (((X) & (1<<14)) >>14 ) /* Transmit deferred*/
++#define IS_TX_CRC_ERR(X) (((X) & (1<<15)) >>15 ) /* CRC Error */
++#define IS_TX_LE_ERR(X) (((X) & (1<<16)) >>16 ) /* Length Error */
++
++#define TX_COLLISION_COUNT(X) (((X) & 0x001E0000u)>>17) /* Collision Count */
++
++#endif /* RC32355_ETHER_H */
++
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32355.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32355.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32355.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32355.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,177 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Definitions for IDT RC32355 CPU.
++ *
++ * Copyright 2004 IDT Inc.
++ * Author: Integrated Device Technology Inc. rischelp@idt.com
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * May 2004 rkt
++ * Initial Release
++ *
++ **************************************************************************
++ */
++
++
++#ifndef _RC32355_H_
++#define _RC32355_H_
++
++#include <linux/delay.h>
++#include <asm/io.h>
++
++/* Base address of internal registers */
++#define RC32355_REG_BASE 0x18000000
++
++/* System ID Registers */
++#define CPU_SYSID (RC32355_REG_BASE + 0x00018)
++#define CPU_BTADDR (RC32355_REG_BASE + 0x0001c)
++#define CPU_REV (RC32355_REG_BASE + 0x0002c)
++
++/* Reset Controller */
++#define RESET_CNTL (RC32355_REG_BASE + 0x08000)
++
++/* Device Controller */
++#define DEV0_BASE (RC32355_REG_BASE + 0x10000)
++#define DEV0_MASK (RC32355_REG_BASE + 0x10004)
++#define DEV0_CNTL (RC32355_REG_BASE + 0x10008)
++#define DEV0_TIMING (RC32355_REG_BASE + 0x1000c)
++#define DEV_REG_OFFSET 0x10
++
++/* SDRAM Controller */
++#define SDRAM0_BASE (RC32355_REG_BASE + 0x18000)
++#define SDRAM0_MASK (RC32355_REG_BASE + 0x18004)
++#define SDRAM1_BASE (RC32355_REG_BASE + 0x18008)
++#define SDRAM1_MASK (RC32355_REG_BASE + 0x1800c)
++#define SDRAM_CNTL (RC32355_REG_BASE + 0x18010)
++
++/* Bus Arbiter */
++#define BUS_ARB_CNTL0 (RC32355_REG_BASE + 0x20000)
++#define BUS_ARB_CNTL1 (RC32355_REG_BASE + 0x20004)
++
++/* Counters/Timers */
++#define TIMER0_COUNT (RC32355_REG_BASE + 0x28000)
++#define TIMER0_COMPARE (RC32355_REG_BASE + 0x28004)
++#define TIMER0_CNTL (RC32355_REG_BASE + 0x28008)
++#define TIMER_REG_OFFSET 0x0C
++
++/* System Integrity */
++
++/* Interrupt Controller */
++#define IC_GROUP0_PEND (RC32355_REG_BASE + 0x30000)
++#define IC_GROUP0_MASK (RC32355_REG_BASE + 0x30004)
++#define IC_GROUP_OFFSET 0x08
++
++#define NUM_INTR_GROUPS 5
++/*
++ * The IRQ mapping is as follows:
++ *
++ * IRQ Mapped To
++ * --- -------------------
++ * 0 SW0 (IP0) SW0 intr
++ * 1 SW1 (IP1) SW1 intr
++ * - Int0 (IP2) mapped to GROUP0_IRQ_BASE
++ * - Int1 (IP3) mapped to GROUP1_IRQ_BASE
++ * - Int2 (IP4) mapped to GROUP2_IRQ_BASE
++ * - Int3 (IP5) mapped to GROUP3_IRQ_BASE
++ * - Int4 (IP6) mapped to GROUP4_IRQ_BASE
++ * 7 Int5 (IP7) CP0 Timer
++ *
++ * IRQ's 8 and up are all mapped to Int0-4 (IP2-IP6), which
++ * internally on the RC32355 is routed to the Expansion
++ * Interrupt Controller.
++ */
++#define MIPS_CPU_TIMER_IRQ 7
++
++#define GROUP0_IRQ_BASE 8 // Counter/Timers, UCW
++#define GROUP1_IRQ_BASE (GROUP0_IRQ_BASE + 32) // DMA
++#define GROUP2_IRQ_BASE (GROUP1_IRQ_BASE + 32) // ATM
++#define GROUP3_IRQ_BASE (GROUP2_IRQ_BASE + 32) // TDM, Eth, USB, UARTs, I2C
++#define GROUP4_IRQ_BASE (GROUP3_IRQ_BASE + 32) // GPIO
++
++#define RC32355_NR_IRQS (GROUP4_IRQ_BASE + 32)
++
++/* DMA - see rc32355_dma.h for full list of registers */
++
++#define RC32355_DMA_BASE (RC32355_REG_BASE + 0x38000)
++#define DMA_CHAN_OFFSET 0x14
++
++/* GPIO Controller */
++
++/* TDM Bus */
++
++/* 16550 UARTs */
++#ifdef __MIPSEB__
++#define RC32300_UART0_BASE (RC32355_REG_BASE + 0x50003)
++#define RC32300_UART1_BASE (RC32355_REG_BASE + 0x50023)
++#else
++#define RC32300_UART0_BASE (RC32355_REG_BASE + 0x50000)
++#define RC32300_UART1_BASE (RC32355_REG_BASE + 0x50020)
++#endif
++
++#define RC32300_UART0_IRQ (GROUP3_IRQ_BASE + 14)
++#define RC32300_UART1_IRQ (GROUP3_IRQ_BASE + 17)
++
++/* ATM */
++
++/* Ethernet - see rc32355_eth.h for full list of registers */
++
++#define RC32355_ETH_BASE (RC32355_REG_BASE + 0x60000)
++
++
++#define IDT_CLOCK_MULT 2
++
++/* Memory map of 79EB355 board */
++
++/* DRAM */
++#define RAM_BASE 0x00000000
++#define RAM_SIZE (32*1024*1024)
++
++/* SRAM (device 1) */
++#define SRAM_BASE 0x02000000
++#define SRAM_SIZE 0x00100000
++
++/* FLASH (device 2) */
++#define FLASH_BASE 0x0C000000
++#define FLASH_SIZE 0x00C00000
++
++/* ATM PHY (device 4) */
++#define ATM_PHY_BASE 0x14000000
++
++/* TDM switch (device 3) */
++#define TDM_BASE 0x1A000000
++
++/* LCD panel (device 3) */
++#define LCD_BASE 0x1A002000
++
++/* RTC (DS1511W) (device 3) */
++#define RTC_BASE 0x1A004000
++
++/* NVRAM (256 bytes internal to the DS1511 RTC) */
++#define NVRAM_ADDR RTC_BASE + 0x10
++#define NVRAM_DATA RTC_BASE + 0x13
++#define NVRAM_ENVSIZE_OFF 4
++#define NVRAM_ENVSTART_OFF 32
++
++#endif /* _RC32355_H_ */
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_dma.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_dma.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_dma.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_dma.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,226 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * RC32365/336 DMA hardware abstraction.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RC32365_DMA_H__
++#define __IDT_RC32365_DMA_H__
++
++enum
++{
++ DMA0_PhysicalAddress = 0x18038000,
++ DMA_PhysicalAddress = DMA0_PhysicalAddress, // Default
++
++ DMA0_VirtualAddress = 0xb8038000,
++ DMA_VirtualAddress = DMA0_VirtualAddress, // Default
++} ;
++
++/*
++ * DMA descriptor (in physical memory).
++ */
++
++typedef struct DMAD_s
++{
++ u32 control ; // Control. use DMAD_*
++ u32 ca ; // Current Address.
++ u32 devcs ; // Device control and status.
++ u32 link ; // Next descriptor in chain.
++} volatile *DMAD_t ;
++
++enum
++{
++ DMAD_size = sizeof (struct DMAD_s),
++ DMAD_count_b = 0, // in DMAD_t -> control
++ DMAD_count_m = 0x0003ffff, // in DMAD_t -> control
++ DMAD_ds_b = 20, // in DMAD_t -> control
++ DMAD_ds_m = 0x00300000, // in DMAD_t -> control
++ DMAD_ds_extToMem0_v = 0,
++ DMAD_ds_memToExt0_v = 1,
++ DMAD_ds_extToMem1_v = 0,
++ DMAD_ds_memToExt1_v = 1,
++ DMAD_ds_ethRcv0_v = 0,
++ DMAD_ds_ethXmt0_v = 0,
++ DMAD_ds_ethRcv1_v = 0,
++ DMAD_ds_ethXmt2_v = 0,
++ DMAD_ds_memToFifo_v = 0,
++ DMAD_ds_fifoToMem_v = 0,
++ DMAD_ds_rng_de_v = 1,//randomNumberGenerator on LC/DE
++ DMAD_ds_pciToMem_v = 0,
++ DMAD_ds_memToPci_v = 0,
++ DMAD_ds_securityInput_v = 0,
++ DMAD_ds_securityOutput_v = 0,
++ DMAD_ds_rng_se_v = 0,//randomNumberGenerator on SE
++
++ DMAD_devcmd_b = 22, // in DMAD_t -> control
++ DMAD_devcmd_m = 0x01c00000, // in DMAD_t -> control
++ DMAD_devcmd_byte_v = 0, //memory-to-memory
++ DMAD_devcmd_halfword_v = 1, //memory-to-memory
++ DMAD_devcmd_word_v = 2, //memory-to-memory
++ DMAD_devcmd_2words_v = 3, //memory-to-memory
++ DMAD_devcmd_4words_v = 4, //memory-to-memory
++ DMAD_devcmd_6words_v = 5, //memory-to-memory
++ DMAD_devcmd_8words_v = 6, //memory-to-memory
++ DMAD_devcmd_16words_v = 7, //memory-to-memory
++ DMAD_cof_b = 25, // chain on finished
++ DMAD_cof_m = 0x02000000, //
++ DMAD_cod_b = 26, // chain on done
++ DMAD_cod_m = 0x04000000, //
++ DMAD_iof_b = 27, // interrupt on finished
++ DMAD_iof_m = 0x08000000, //
++ DMAD_iod_b = 28, // interrupt on done
++ DMAD_iod_m = 0x10000000, //
++ DMAD_t_b = 29, // terminated
++ DMAD_t_m = 0x20000000, //
++ DMAD_d_b = 30, // done
++ DMAD_d_m = 0x40000000, //
++ DMAD_f_b = 31, // finished
++ DMAD_f_m = 0x80000000, //
++} ;
++
++/*
++ * DMA register (within Internal Register Map).
++ */
++
++struct DMA_Chan_s
++{
++ u32 dmac ; // Control.
++ u32 dmas ; // Status.
++ u32 dmasm ; // Mask.
++ u32 dmadptr ; // Descriptor pointer.
++ u32 dmandptr ; // Next descriptor pointer.
++};
++
++typedef struct DMA_Chan_s volatile *DMA_Chan_t ;
++
++//DMA_Channels use DMACH_count instead
++
++enum
++{
++ DMAC_run_b = 0, //
++ DMAC_run_m = 0x00000001, //
++ DMAC_dm_b = 1, // done mask
++ DMAC_dm_m = 0x00000002, //
++ DMAC_mode_b = 2, //
++ DMAC_mode_m = 0x0000000c, //
++ DMAC_mode_auto_v = 0,
++ DMAC_mode_burst_v = 1,
++ DMAC_mode_transfer_v = 2, //usually used
++ DMAC_mode_reserved_v = 3,
++ DMAC_a_b = 4, //
++ DMAC_a_m = 0x00000010, //
++
++ DMAS_f_b = 0, // finished (sticky)
++ DMAS_f_m = 0x00000001, //
++ DMAS_d_b = 1, // done (sticky)
++ DMAS_d_m = 0x00000002, //
++ DMAS_c_b = 2, // chain (sticky)
++ DMAS_c_m = 0x00000004, //
++ DMAS_e_b = 3, // error (sticky)
++ DMAS_e_m = 0x00000008, //
++ DMAS_h_b = 4, // halt (sticky)
++ DMAS_h_m = 0x00000010, //
++
++ DMASM_f_b = 0, // finished (1=mask)
++ DMASM_f_m = 0x00000001, //
++ DMASM_d_b = 1, // done (1=mask)
++ DMASM_d_m = 0x00000002, //
++ DMASM_c_b = 2, // chain (1=mask)
++ DMASM_c_m = 0x00000004, //
++ DMASM_e_b = 3, // error (1=mask)
++ DMASM_e_m = 0x00000008, //
++ DMASM_h_b = 4, // halt (1=mask)
++ DMASM_h_m = 0x00000010, //
++} ;
++
++/*
++ * DMA channel definitions
++ */
++
++enum
++{
++ DMACH_ethRcv0 = 0,
++ DMACH_ethXmt0 = 1,
++ DMACH_ethRcv1 = 2,
++ DMACH_ethXmt2 = 3,
++ DMACH_pciToMem = 4,
++ DMACH_memToPci = 5,
++ DMACH_securityInput = 6,
++ DMACH_securityOutput = 7,
++ DMACH_rng = 8,
++
++ DMACH_count //must be last
++};
++
++
++typedef struct DMAC_s
++{
++ struct DMA_Chan_s ch [DMACH_count] ; //use ch[DMACH_]
++} volatile *DMA_t ;
++
++
++/*
++ * External DMA parameters
++*/
++
++enum
++{
++ DMADEVCMD_ts_b = 0, // ts field in devcmd
++ DMADEVCMD_ts_m = 0x00000007, // ts field in devcmd
++ DMADEVCMD_ts_byte_v = 0,
++ DMADEVCMD_ts_halfword_v = 1,
++ DMADEVCMD_ts_word_v = 2,
++ DMADEVCMD_ts_2word_v = 3,
++ DMADEVCMD_ts_4word_v = 4,
++ DMADEVCMD_ts_6word_v = 5,
++ DMADEVCMD_ts_8word_v = 6,
++ DMADEVCMD_ts_16word_v = 7
++};
++
++
++#if 1 // aws - Compatibility.
++# define EXTDMA_ts_b DMADEVCMD_ts_b
++# define EXTDMA_ts_m DMADEVCMD_ts_m
++# define EXTDMA_ts_byte_v DMADEVCMD_ts_byte_v
++# define EXTDMA_ts_halfword_v DMADEVCMD_ts_halfword_v
++# define EXTDMA_ts_word_v DMADEVCMD_ts_word_v
++# define EXTDMA_ts_2word_v DMADEVCMD_ts_2word_v
++# define EXTDMA_ts_4word_v DMADEVCMD_ts_4word_v
++# define EXTDMA_ts_6word_v DMADEVCMD_ts_6word_v
++# define EXTDMA_ts_8word_v DMADEVCMD_ts_8word_v
++# define EXTDMA_ts_16word_v DMADEVCMD_ts_16word_v
++#endif // aws - Compatibility.
++
++#endif // __IDT_RC32365_DMA_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_dma_v.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_dma_v.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_dma_v.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_dma_v.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,86 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * RC32365/336 DMA interface routines.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RC32365_DMA_V_H__
++#define __IDT_RC32365_DMA_V_H__
++
++
++#include <asm/idt-boards/rc32300/rc32300.h>
++#include <asm/idt-boards/rc32300/rc32365_dma.h>
++#include <asm/idt-boards/rc32300/rc32365.h>
++
++#define DMA_CHAN_OFFSET 0x14
++#define IS_DMA_USED(X) (((X) & (DMAD_f_m | DMAD_d_m | DMAD_t_m)) != 0)
++#define IS_DMA_FINISHED(X) (((X) & (DMAD_f_m)) != 0)
++#define IS_DMA_DONE(X) (((X) & (DMAD_d_m)) != 0)
++
++#define DMA_COUNT(count) \
++ ((count) & DMAD_count_m)
++
++#define DMA_HALT_TIMEOUT 500
++
++static inline int rc32365_halt_dma(DMA_Chan_t ch)
++{
++ int timeout=1;
++ if (local_readl(&ch->dmac) & DMAC_run_m) {
++ local_writel(0, &ch->dmac);
++
++ for (timeout = DMA_HALT_TIMEOUT; timeout > 0; timeout--) {
++ if (local_readl(&ch->dmas) & DMAS_h_m) {
++ local_writel(0, &ch->dmas);
++ break;
++ }
++ }
++
++ }
++
++ return timeout ? 0 : 1;
++}
++
++
++static inline void rc32365_start_dma(DMA_Chan_t ch, u32 dma_addr)
++{
++ local_writel(0, &ch->dmandptr);
++ local_writel(dma_addr, &ch->dmadptr);
++}
++
++static inline void rc32365_chain_dma(DMA_Chan_t ch, u32 dma_addr)
++{
++ local_writel(dma_addr, &ch->dmandptr);
++}
++#endif //__IDT_RC32365_DMA_V_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_eth.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_eth.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_eth.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_eth.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,344 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * RC32365/336 Ethernet hardware abstraction.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RC32365_ETH_H__
++#define __IDT_RC32365_ETH_H__
++
++enum
++{
++ ETH0_PhysicalAddress = 0x18058000,
++ ETH_PhysicalAddress = ETH0_PhysicalAddress, // Default
++ ETH0_VirtualAddress = 0xb8058000,
++
++ ETH_VirtualAddress = ETH0_VirtualAddress, // Default
++
++ ETH1_PhysicalAddress = 0x18060000,
++ ETH1_VirtualAddress = 0xb8060000, // Default
++} ;
++
++typedef struct
++{
++ u32 ethintfc ;
++ u32 ethfifott ;
++ u32 etharc ;
++ u32 ethhash0 ;
++ u32 ethhash1 ;
++ u32 ethu0 [4] ; // Reserved.
++ u32 ethpfs ;
++ u32 ethmcp ;
++ u32 eth_u1 [10] ; // Reserved.
++ u32 ethspare ;
++ u32 eth_u2 [42] ; // Reserved.
++ u32 ethsal0 ;
++ u32 ethsah0 ;
++ u32 ethsal1 ;
++ u32 ethsah1 ;
++ u32 ethsal2 ;
++ u32 ethsah2 ;
++ u32 ethsal3 ;
++ u32 ethsah3 ;
++ u32 ethrbc ;
++ u32 ethrpc ;
++ u32 ethrupc ;
++ u32 ethrfc ;
++ u32 ethtbc ;
++ u32 ethgpf ;
++ u32 eth_u9 [50] ; // Reserved.
++ u32 ethmac1 ;
++ u32 ethmac2 ;
++ u32 ethipgt ;
++ u32 ethipgr ;
++ u32 ethclrt ;
++ u32 ethmaxf ;
++ u32 eth_u10 ; // Reserved.
++ u32 ethmtest ;
++ u32 miimcfg ;
++ u32 miimcmd ;
++ u32 miimaddr ;
++ u32 miimwtd ;
++ u32 miimrdd ;
++ u32 miimind ;
++ u32 eth_u11 ; // Reserved.
++ u32 eth_u12 ; // Reserved.
++ u32 ethcfsa0 ;
++ u32 ethcfsa1 ;
++ u32 ethcfsa2 ;
++} volatile *ETH_t;
++
++enum
++{
++ ETHINTFC_en_b = 0,
++ ETHINTFC_en_m = 0x00000001,
++ ETHINTFC_its_b = 1,
++ ETHINTFC_its_m = 0x00000002,
++ ETHINTFC_rip_b = 2,
++ ETHINTFC_rip_m = 0x00000004,
++ ETHINTFC_jam_b = 3,
++ ETHINTFC_jam_m = 0x00000008,
++ ETHINTFC_ovr_b = 4,
++ ETHINTFC_ovr_m = 0x00000010,
++ ETHINTFC_und_b = 5,
++ ETHINTFC_und_m = 0x00000020,
++
++ ETHFIFOTT_tth_b = 0,
++ ETHFIFOTT_tth_m = 0x0000007f,
++
++ ETHARC_pro_b = 0,
++ ETHARC_pro_m = 0x00000001,
++ ETHARC_am_b = 1,
++ ETHARC_am_m = 0x00000002,
++ ETHARC_afm_b = 2,
++ ETHARC_afm_m = 0x00000004,
++ ETHARC_ab_b = 3,
++ ETHARC_ab_m = 0x00000008,
++
++ ETHSAL_byte5_b = 0,
++ ETHSAL_byte5_m = 0x000000ff,
++ ETHSAL_byte4_b = 8,
++ ETHSAL_byte4_m = 0x0000ff00,
++ ETHSAL_byte3_b = 16,
++ ETHSAL_byte3_m = 0x00ff0000,
++ ETHSAL_byte2_b = 24,
++ ETHSAL_byte2_m = 0xff000000,
++
++ ETHSAH_byte1_b = 0,
++ ETHSAH_byte1_m = 0x000000ff,
++ ETHSAH_byte0_b = 8,
++ ETHSAH_byte0_m = 0x0000ff00,
++
++ ETHGPF_ptv_b = 0,
++ ETHGPF_ptv_m = 0x0000ffff,
++
++ ETHPFS_pfd_b = 0,
++ ETHPFS_pfd_m = 0x00000001,
++
++ ETHCFSA0_cfsa4_b = 0,
++ ETHCFSA0_cfsa4_m = 0x000000ff,
++ ETHCFSA0_cfsa5_b = 8,
++ ETHCFSA0_cfsa5_m = 0x0000ff00,
++
++ ETHCFSA1_cfsa2_b = 0,
++ ETHCFSA1_cfsa2_m = 0x000000ff,
++ ETHCFSA1_cfsa3_b = 8,
++ ETHCFSA1_cfsa3_m = 0x0000ff00,
++
++ ETHCFSA2_cfsa0_b = 0,
++ ETHCFSA2_cfsa0_m = 0x000000ff,
++ ETHCFSA2_cfsa1_b = 8,
++ ETHCFSA2_cfsa1_m = 0x0000ff00,
++
++ ETHMAC1_re_b = 0,
++ ETHMAC1_re_m = 0x00000001,
++ ETHMAC1_paf_b = 1,
++ ETHMAC1_paf_m = 0x00000002,
++ ETHMAC1_rfc_b = 2,
++ ETHMAC1_rfc_m = 0x00000004,
++ ETHMAC1_tfc_b = 3,
++ ETHMAC1_tfc_m = 0x00000008,
++ ETHMAC1_lb_b = 4,
++ ETHMAC1_lb_m = 0x00000010,
++ ETHMAC1_mr_b = 31,
++ ETHMAC1_mr_m = 0x80000000,
++
++ ETHMAC2_fd_b = 0,
++ ETHMAC2_fd_m = 0x00000001,
++ ETHMAC2_flc_b = 1,
++ ETHMAC2_flc_m = 0x00000002,
++ ETHMAC2_hfe_b = 2,
++ ETHMAC2_hfe_m = 0x00000004,
++ ETHMAC2_dc_b = 3,
++ ETHMAC2_dc_m = 0x00000008,
++ ETHMAC2_cen_b = 4,
++ ETHMAC2_cen_m = 0x00000010,
++ ETHMAC2_pe_b = 5,
++ ETHMAC2_pe_m = 0x00000020,
++ ETHMAC2_vpe_b = 6,
++ ETHMAC2_vpe_m = 0x00000040,
++ ETHMAC2_ape_b = 7,
++ ETHMAC2_ape_m = 0x00000080,
++ ETHMAC2_ppe_b = 8,
++ ETHMAC2_ppe_m = 0x00000100,
++ ETHMAC2_lpe_b = 9,
++ ETHMAC2_lpe_m = 0x00000200,
++ ETHMAC2_nb_b = 12,
++ ETHMAC2_nb_m = 0x00001000,
++ ETHMAC2_bp_b = 13,
++ ETHMAC2_bp_m = 0x00002000,
++ ETHMAC2_ed_b = 14,
++ ETHMAC2_ed_m = 0x00004000,
++
++ ETHIPGT_ipgt_b = 0,
++ ETHIPGT_ipgt_m = 0x0000007f,
++
++ ETHIPGR_ipgr2_b = 0,
++ ETHIPGR_ipgr2_m = 0x0000007f,
++ ETHIPGR_ipgr1_b = 8,
++ ETHIPGR_ipgr1_m = 0x00007f00,
++
++ ETHCLRT_maxret_b = 0,
++ ETHCLRT_maxret_m = 0x0000000f,
++ ETHCLRT_colwin_b = 8,
++ ETHCLRT_colwin_m = 0x00003f00,
++
++ ETHMAXF_maxf_b = 0,
++ ETHMAXF_maxf_m = 0x0000ffff,
++
++ ETHMTEST_tb_b = 2,
++ ETHMTEST_tb_m = 0x00000004,
++
++ ETHMCP_div_b = 0,
++ ETHMCP_div_m = 0x000000ff,
++
++ MIIMCFG_rsv_b = 0,
++ MIIMCFG_rsv_m = 0x0000000c,
++
++ MIIMCMD_rd_b = 0,
++ MIIMCMD_rd_m = 0x00000001,
++ MIIMCMD_scn_b = 1,
++ MIIMCMD_scn_m = 0x00000002,
++
++ MIIMADDR_regaddr_b = 0,
++ MIIMADDR_regaddr_m = 0x0000001f,
++ MIIMADDR_phyaddr_b = 8,
++ MIIMADDR_phyaddr_m = 0x00001f00,
++
++ MIIMWTD_wdata_b = 0,
++ MIIMWTD_wdata_m = 0x0000ffff,
++
++ MIIMRDD_rdata_b = 0,
++ MIIMRDD_rdata_m = 0x0000ffff,
++
++ MIIMIND_bsy_b = 0,
++ MIIMIND_bsy_m = 0x00000001,
++ MIIMIND_scn_b = 1,
++ MIIMIND_scn_m = 0x00000002,
++ MIIMIND_nv_b = 2,
++ MIIMIND_nv_m = 0x00000004,
++
++} ;
++
++/*
++ * Values for the DEVCS field of the Ethernet DMA Rx and Tx descriptors.
++ */
++enum
++{
++ ETHRX_fd_b = 0,
++ ETHRX_fd_m = 0x00000001,
++ ETHRX_ld_b = 1,
++ ETHRX_ld_m = 0x00000002,
++ ETHRX_rok_b = 2,
++ ETHRX_rok_m = 0x00000004,
++ ETHRX_fm_b = 3,
++ ETHRX_fm_m = 0x00000008,
++ ETHRX_mp_b = 4,
++ ETHRX_mp_m = 0x00000010,
++ ETHRX_bp_b = 5,
++ ETHRX_bp_m = 0x00000020,
++ ETHRX_vlt_b = 6,
++ ETHRX_vlt_m = 0x00000040,
++ ETHRX_cf_b = 7,
++ ETHRX_cf_m = 0x00000080,
++ ETHRX_ovr_b = 8,
++ ETHRX_ovr_m = 0x00000100,
++ ETHRX_crc_b = 9,
++ ETHRX_crc_m = 0x00000200,
++ ETHRX_cv_b = 10,
++ ETHRX_cv_m = 0x00000400,
++ ETHRX_db_b = 11,
++ ETHRX_db_m = 0x00000800,
++ ETHRX_le_b = 12,
++ ETHRX_le_m = 0x00001000,
++ ETHRX_lor_b = 13,
++ ETHRX_lor_m = 0x00002000,
++ ETHRX_ces_b = 14,
++ ETHRX_ces_m = 0x00004000,
++ ETHRX_length_b = 16,
++ ETHRX_length_m = 0xffff0000,
++
++ ETHTX_fd_b = 0,
++ ETHTX_fd_m = 0x00000001,
++ ETHTX_ld_b = 1,
++ ETHTX_ld_m = 0x00000002,
++ ETHTX_oen_b = 2,
++ ETHTX_oen_m = 0x00000004,
++ ETHTX_pen_b = 3,
++ ETHTX_pen_m = 0x00000008,
++ ETHTX_cen_b = 4,
++ ETHTX_cen_m = 0x00000010,
++ ETHTX_hen_b = 5,
++ ETHTX_hen_m = 0x00000020,
++ ETHTX_tok_b = 6,
++ ETHTX_tok_m = 0x00000040,
++ ETHTX_mp_b = 7,
++ ETHTX_mp_m = 0x00000080,
++ ETHTX_bp_b = 8,
++ ETHTX_bp_m = 0x00000100,
++ ETHTX_und_b = 9,
++ ETHTX_und_m = 0x00000200,
++ ETHTX_of_b = 10,
++ ETHTX_of_m = 0x00000400,
++ ETHTX_ed_b = 11,
++ ETHTX_ed_m = 0x00000800,
++ ETHTX_ec_b = 12,
++ ETHTX_ec_m = 0x00001000,
++ ETHTX_lc_b = 13,
++ ETHTX_lc_m = 0x00002000,
++ ETHTX_td_b = 14,
++ ETHTX_td_m = 0x00004000,
++ ETHTX_crc_b = 15,
++ ETHTX_crc_m = 0x00008000,
++ ETHTX_le_b = 16,
++ ETHTX_le_m = 0x00010000,
++ ETHTX_cc_b = 17,
++ ETHTX_cc_m = 0x001E0000,
++} ;
++
++enum
++{
++ ETH0_IPABMC_PhysicalAddress = 0x18040010,
++ ETH0_IPABMC_VirtualAddress = 0xb8040000,
++ ETH1_IPABMC_PhysicalAddress = 0x18040018,
++ ETH1_IPABMC_VirtualAddress = 0xb8040018,
++} ;
++
++typedef struct
++{
++ u32 ipabmcrx ;
++ u32 ipabmctx ;
++}volatile *IPABM_ETH_t;
++#endif //__IDT_RC32365_ETH_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_eth_v.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_eth_v.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_eth_v.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_eth_v.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,72 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * RC32365/336 Ethernet status checking.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RC32365_ETH_V_H__
++#define __IDT_RC32365_ETH_V_H__
++#include <asm/idt-boards/rc32300/rc32365_eth.h>
++
++#define IS_TX_TOK(X) (((X) & (1<<ETHTX_tok_b)) >> ETHTX_tok_b ) /* Transmit Okay */
++#define IS_TX_MP(X) (((X) & (1<<ETHTX_mp_b)) >> ETHTX_mp_b ) /* Multicast */
++#define IS_TX_BP(X) (((X) & (1<<ETHTX_bp_b)) >> ETHTX_bp_b ) /* Broadcast */
++#define IS_TX_UND_ERR(X) (((X) & (1<<ETHTX_und_b)) >> ETHTX_und_b ) /* Transmit FIFO Underflow */
++#define IS_TX_OF_ERR(X) (((X) & (1<<ETHTX_of_b)) >> ETHTX_of_b ) /* Oversized frame */
++#define IS_TX_ED_ERR(X) (((X) & (1<<ETHTX_ed_b)) >> ETHTX_ed_b ) /* Excessive deferral */
++#define IS_TX_EC_ERR(X) (((X) & (1<<ETHTX_ec_b)) >> ETHTX_ec_b) /* Excessive collisions */
++#define IS_TX_LC_ERR(X) (((X) & (1<<ETHTX_lc_b)) >> ETHTX_lc_b ) /* Late Collision */
++#define IS_TX_TD_ERR(X) (((X) & (1<<ETHTX_td_b)) >> ETHTX_td_b ) /* Transmit deferred*/
++#define IS_TX_CRC_ERR(X) (((X) & (1<<ETHTX_crc_b)) >> ETHTX_crc_b ) /* CRC Error */
++#define IS_TX_LE_ERR(X) (((X) & (1<<ETHTX_le_b)) >> ETHTX_le_b ) /* Length Error */
++
++#define TX_COLLISION_COUNT(X) (((X) & ETHTX_cc_m)>>ETHTX_cc_b) /* Collision Count */
++
++#define IS_RCV_ROK(X) (((X) & (1<<ETHRX_rok_b)) >> ETHRX_rok_b) /* Receive Okay */
++#define IS_RCV_FM(X) (((X) & (1<<ETHRX_fm_b)) >> ETHRX_fm_b) /* Is Filter Match */
++#define IS_RCV_MP(X) (((X) & (1<<ETHRX_mp_b)) >> ETHRX_mp_b) /* Is it MP */
++#define IS_RCV_BP(X) (((X) & (1<<ETHRX_bp_b)) >> ETHRX_bp_b) /* Is it BP */
++#define IS_RCV_VLT(X) (((X) & (1<<ETHRX_vlt_b)) >> ETHRX_vlt_b) /* VLAN Tag Detect */
++#define IS_RCV_CF(X) (((X) & (1<<ETHRX_cf_b)) >> ETHRX_cf_b) /* Control Frame */
++#define IS_RCV_OVR_ERR(X) (((X) & (1<<ETHRX_ovr_b)) >> ETHRX_ovr_b) /* Receive Overflow */
++#define IS_RCV_CRC_ERR(X) (((X) & (1<<ETHRX_crc_b)) >> ETHRX_crc_b) /* CRC Error */
++#define IS_RCV_CV_ERR(X) (((X) & (1<<ETHRX_cv_b)) >> ETHRX_cv_b) /* Code Violation */
++#define IS_RCV_DB_ERR(X) (((X) & (1<<ETHRX_db_b)) >> ETHRX_db_b) /* Dribble Bits */
++#define IS_RCV_LE_ERR(X) (((X) & (1<<ETHRX_le_b)) >> ETHRX_le_b) /* Length error */
++#define IS_RCV_LOR_ERR(X) (((X) & (1<<ETHRX_lor_b)) >> ETHRX_lor_b) /* Length Out of Range */
++#define IS_RCV_CES_ERR(X) (((X) & (1<<ETHRX_ces_b)) >> ETHRX_ces_b) /* Preamble error */
++#define RCVPKT_LENGTH(X) (((X) & ETHRX_length_m) >> ETHRX_length_b) /* Length of the received packet */
++
++#endif //__IDT_RC32365_ETH_V_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_gpio.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_gpio.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_gpio.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_gpio.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,181 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * RC32365/336 GPIO hardware abstraction.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RC32365_GPIO_H__
++#define __IDT_RC32365_GPIO_H__
++
++enum
++{
++ GPIO0_PhysicalAddress = 0x18048000,
++ GPIO_PhysicalAddress = GPIO0_PhysicalAddress, // Default
++
++ GPIO0_VirtualAddress = 0xb8048000,
++ GPIO_VirtualAddress = GPIO0_VirtualAddress, // Default
++} ;
++
++typedef struct
++{
++ u32 gpiofunc; /* GPIO Function Register
++ * gpiofunc[x]==0 bit = gpio
++ * func[x]==1 bit = altfunc
++ */
++ u32 gpiocfg; /* GPIO Configuration Register
++ * gpiocfg[x]==0 bit = input
++ * gpiocfg[x]==1 bit = output
++ */
++ u32 gpiod; /* GPIO Data Register
++ * gpiod[x] read/write gpio pinX status
++ */
++ u32 gpioilevel; /* GPIO Interrupt Status Register
++ * interrupt level (see gpioistat)
++ */
++ u32 gpioistat; /* Gpio Interrupt Status Register
++ * istat[x] = (gpiod[x] == level[x])
++ * cleared in ISR (STICKY bits)
++ */
++ u32 gpionmien; /* GPIO Non-maskable Interrupt Enable Register */
++} volatile * GPIO_t ;
++
++typedef enum
++{
++ GPIO_gpio_v = 0, // gpiofunc use pin as GPIO.
++ GPIO_alt_v = 1, // gpiofunc use pin as alt.
++ GPIO_input_v = 0, // gpiocfg use pin as input.
++ GPIO_output_v = 1, // gpiocfg use pin as output.
++ GPIO_pin0_b = 0,
++ GPIO_pin0_m = 0x00000001,
++ GPIO_pin1_b = 1,
++ GPIO_pin1_m = 0x00000002,
++ GPIO_pin2_b = 2,
++ GPIO_pin2_m = 0x00000004,
++ GPIO_pin3_b = 3,
++ GPIO_pin3_m = 0x00000008,
++ GPIO_pin4_b = 4,
++ GPIO_pin4_m = 0x00000010,
++ GPIO_pin5_b = 5,
++ GPIO_pin5_m = 0x00000020,
++ GPIO_pin6_b = 6,
++ GPIO_pin6_m = 0x00000040,
++ GPIO_pin7_b = 7,
++ GPIO_pin7_m = 0x00000080,
++ GPIO_pin8_b = 8,
++ GPIO_pin8_m = 0x00000100,
++ GPIO_pin9_b = 9,
++ GPIO_pin9_m = 0x00000200,
++ GPIO_pin10_b = 10,
++ GPIO_pin10_m = 0x00000400,
++ GPIO_pin11_b = 11,
++ GPIO_pin11_m = 0x00000800,
++ GPIO_pin12_b = 12,
++ GPIO_pin12_m = 0x00001000,
++ GPIO_pin13_b = 13,
++ GPIO_pin13_m = 0x00002000,
++ GPIO_pin14_b = 14,
++ GPIO_pin14_m = 0x00004000,
++ GPIO_pin15_b = 15,
++ GPIO_pin15_m = 0x00008000,
++
++// Alternate function pins. Corrsponding gpiofunc bit set to GPIO_alt_v.
++
++ GPIO_u0sout_b = GPIO_pin0_b, // UART 0 serial out.
++ GPIO_u0sout_m = GPIO_pin0_m,
++ GPIO_u0sout_cfg_v = GPIO_output_v,
++
++ GPIO_u0sinp_b = GPIO_pin1_b, // UART 0 serial in.
++ GPIO_u0sinp_m = GPIO_pin1_m,
++ GPIO_u0sinp_cfg_v = GPIO_input_v,
++
++ GPIO_maddr22_b = GPIO_pin2_b, // M&P bus bit 22.
++ GPIO_maddr22_m = GPIO_pin2_m,
++ GPIO_maddr22_cfg_v = GPIO_output_v,
++
++ GPIO_maddr23_b = GPIO_pin3_b, // M&P bus bit 23.
++ GPIO_maddr23_m = GPIO_pin3_m,
++ GPIO_maddr23_cfg_v = GPIO_output_v,
++
++ GPIO_maddr24_b = GPIO_pin4_b, // M&P bus bit 24.
++ GPIO_maddr24_m = GPIO_pin4_m,
++ GPIO_maddr24_cfg_v = GPIO_output_v,
++
++ GPIO_maddr25_b = GPIO_pin5_b, // M&P bus bit 25.
++ GPIO_maddr25_m = GPIO_pin5_m,
++ GPIO_maddr25_cfg_v = GPIO_output_v,
++
++ GPIO_rngclk_b = GPIO_pin6_b, // reserved.
++ GPIO_rngclk_m = GPIO_pin6_m,
++ GPIO_rngclk_cfg_v = GPIO_input_v,
++
++ GPIO_sdckenp_b = GPIO_pin7_b, // reserved.
++ GPIO_sdckenp_m = GPIO_pin7_m,
++ GPIO_sdckenp_cfg_v = GPIO_output_v,
++
++ GPIO_cen1_b = GPIO_pin8_b, // reserved.
++ GPIO_cen1_m = GPIO_pin8_m,
++ GPIO_cen1_cfg_v = GPIO_output_v,
++
++ GPIO_cen2_b = GPIO_pin9_b, // reserved.
++ GPIO_cen2_m = GPIO_pin9_m,
++ GPIO_cen2_cfg_v = GPIO_output_v,
++
++ GPIO_regn_b = GPIO_pin10_b, // reserved.
++ GPIO_regn_m = GPIO_pin10_m,
++ GPIO_regn_cfg_v = GPIO_output_v,
++
++ GPIO_iordn_b = GPIO_pin11_b, // reserved.
++ GPIO_iordn_m = GPIO_pin11_m,
++ GPIO_iordn_cfg_v = GPIO_output_v,
++
++ GPIO_iowrn_b = GPIO_pin12_b, // reserved.
++ GPIO_iowrn_m = GPIO_pin12_m,
++ GPIO_iowrn_cfg_v = GPIO_output_v,
++
++ GPIO_pcireqn2_b = GPIO_pin13_b, // PCI messaging int.
++ GPIO_pcireqn2_m = GPIO_pin13_m,
++ GPIO_pcireqn2_cfg_v = GPIO_input_v,
++
++ GPIO_pcigntn2_b = GPIO_pin14_b, // PCI messaging int.
++ GPIO_pcigntn2_m = GPIO_pin14_m,
++ GPIO_pcigntn2_cfg_v = GPIO_output_v,
++
++ GPIO_pcimuintn_b = GPIO_pin15_b, // PCI messaging int.
++ GPIO_pcimuintn_m = GPIO_pin15_m,
++ GPIO_pcimuintn_cfg_v= GPIO_output_v,
++
++} GPIO_DEFS_t;
++
++#endif //__IDT_RC32365_GPIO_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_gpio_v.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_gpio_v.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_gpio_v.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_gpio_v.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,91 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Routines to set/clear/toggle GPIO on RC32365
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++#ifndef __IDT_RC32365_GPIO_V_H__
++#define __IDT_RC32365_GPIO_V_H__
++
++
++#ifdef _LANGUAGE_ASSEMBLY
++#define SET_GPIO(pin) \
++ lui t5,0xb804 ; \
++ ori t5,t5,0x8000 ; \
++ lw t4,8(t5) ; \
++ ori t4,t4,pin ; \
++ sw t4,8(t5) ;
++
++#define CLEAR_GPIO(pin) \
++ lui t5,0xb804 ; \
++ ori t5,t5,0x8000 ; \
++ lw t4,8(t5) ; \
++ lui t6,0xFFFF; \
++ ori t6,t6,0xFFFF; \
++ xori t6,t6,pin ; \
++ and t4,t6 ; \
++ sw t4,8(t5) ;
++
++#define TOGGLE_GPIO(pin) \
++ lui t5,0xb804 ; \
++ ori t5,t5,0x8000 ; \
++ lw t4,8(t5) ; \
++ xori t4,t4,pin ; \
++ sw t4,8(t5) ;
++
++#else // !_LANGUAGE_ASSEMBLY
++#include <asm/rc32300/types.h>
++#include <asm/rc32300/rc32365_gpio.h>
++#include <asm/rc32300/rc32365.h>
++
++static inline void set_gpio(unsigned long pin)
++{
++ idt_gpio->gpiod |= pin;
++}
++
++static inline void clear_gpio(unsigned long pin)
++{
++ idt_gpio->gpiod &= ~pin;
++}
++static inline void toggle_gpio(unsigned long pin)
++{
++ idt_gpio->gpiod ^= pin;
++}
++#define SET_GPIO(pin) set_gpio(pin)
++#define CLEAR_GPIO(pin) clear_gpio(pin)
++#define TOGGLE_GPIO(pin) toggle_gpio(pin)
++#endif // _LANGUAGE_ASSEMBLY
++
++#endif //__IDT_RC32365_GPIO_V_H__
++
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,160 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Definitions for IDT RC32365 CPU.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RC32365_H__
++#define __IDT_RC32365_H__
++
++extern unsigned int cedar_za;
++
++/* Base address of internal registers */
++#define RC32365_REG_BASE 0x18000000
++
++/* System ID Registers */
++#define CPU_SYSID (RC32365_REG_BASE + 0x00018)
++#define CPU_DEVTYPE (RC32365_REG_BASE + 0x0001c)
++
++/* Reset Controller */
++#define RESET_CNTL (RC32365_REG_BASE + 0x08000)
++#define BOOT_VECTOR (RC32365_REG_BASE + 0x08004)
++
++/* Device Controller */
++#define DEV0_BASE (RC32365_REG_BASE + 0x10000)
++#define DEV0_MASK (RC32365_REG_BASE + 0x10004)
++#define DEV0_CNTL (RC32365_REG_BASE + 0x10008)
++#define DEV0_TIMING (RC32365_REG_BASE + 0x1000c)
++#define DEV_REG_OFFSET 0x10
++
++/* SDRAM Controller */
++#define SDRAM0_BASE (RC32365_REG_BASE + 0x18000)
++#define SDRAM0_MASK (RC32365_REG_BASE + 0x18004)
++#define SDRAM1_BASE (RC32365_REG_BASE + 0x18008)
++#define SDRAM1_MASK (RC32365_REG_BASE + 0x1800c)
++#define SDRAM_CNTL (RC32365_REG_BASE + 0x18010)
++
++/* Counters/Timers */
++#define TIMER0_COUNT (RC32365_REG_BASE + 0x20000)
++#define TIMER0_COMPARE (RC32365_REG_BASE + 0x20004)
++#define TIMER0_CNTL (RC32365_REG_BASE + 0x20008)
++#define TIMER0_SELECT (RC32365_REG_BASE + 0x2000c)
++#define TIMER_REG_OFFSET 0x10
++
++/* System Integrity */
++
++/* Interrupt Controller */
++#define IC_GROUP0_PEND (RC32365_REG_BASE + 0x30000)
++#define IC_GROUP0_TEST (RC32365_REG_BASE + 0x30004)
++#define IC_GROUP0_MASK (RC32365_REG_BASE + 0x30008)
++#define IC_GROUP_OFFSET 0x0c
++
++#define NUM_INTR_GROUPS 5
++/*
++ * The IRQ mapping is as follows:
++ *
++ * IRQ Mapped To
++ * --- -------------------
++ * 0 SW0 (IP0) SW0 intr
++ * 1 SW1 (IP1) SW1 intr
++ * - Int0 (IP2) mapped to GROUP0_IRQ_BASE
++ * - Int1 (IP3) mapped to GROUP1_IRQ_BASE
++ * - Int2 (IP4) mapped to GROUP2_IRQ_BASE
++ * - Int3 (IP5) mapped to GROUP3_IRQ_BASE
++ * - Int4 (IP6) mapped to GROUP4_IRQ_BASE
++ * 7 Int5 (IP7) CP0 Timer
++ *
++ * IRQ's 8 and up are all mapped to Int0-4 (IP2-IP6), which
++ * internally on the RC32365 is routed to the Expansion
++ * Interrupt Controller.
++ */
++#define MIPS_CPU_TIMER_IRQ 7
++
++#define GROUP0_IRQ_BASE 8 // Counter/Timers, UCW
++#define GROUP1_IRQ_BASE (GROUP0_IRQ_BASE + 32) // DMA
++#define GROUP2_IRQ_BASE (GROUP1_IRQ_BASE + 32) // RNG, SEC
++#define GROUP3_IRQ_BASE (GROUP2_IRQ_BASE + 32) // Eth, PCI, UARTs
++#define GROUP4_IRQ_BASE (GROUP3_IRQ_BASE + 32) // GPIO
++
++#define RC32365_NR_IRQS (GROUP4_IRQ_BASE + 32)
++
++/* DMA - see rc32365_dma.h for full list of registers */
++
++#define RC32365_DMA_BASE (RC32365_REG_BASE + 0x38000)
++#define DMA_CHAN_OFFSET 0x14
++
++/* GPIO Controller */
++#define idt_gpio ((volatile GPIO_t) GPIO0_VirtualAddress)
++
++/* 16550 UARTs */
++#ifdef __MIPSEB__
++#define RC32300_UART0_BASE (RC32365_REG_BASE + 0x50003)
++#else
++#define RC32300_UART0_BASE (RC32365_REG_BASE + 0x50000)
++#endif
++#define RC32300_UART0_IRQ (GROUP3_IRQ_BASE + 0)
++
++/* Ethernet - see rc32365_eth.h for full list of registers */
++
++#define RC32365_ETH_BASE (RC32365_REG_BASE + 0x58000)
++
++#define IDT_CLOCK_MULT 2
++
++/* FLASH (device 1) */
++#define FLASH_BASE 0x08000000
++#define FLASH_SIZE 0x00800000
++
++/* LCD 4-digit display (device 2) */
++#define LCD_DIGIT0 0x0C000003
++#define LCD_DIGIT1 0x0C000002
++#define LCD_DIGIT2 0x0C000001
++#define LCD_DIGIT3 0x0C000000
++
++/* RTC (DS1553) (device 2) */
++#define RTC_BASE 0x0c800000
++/* NVRAM */
++#define NVRAM_BASE RTC_BASE
++#define NVRAM_ENVSIZE_OFF 4
++#define NVRAM_ENVSTART_OFF 32
++
++/* Interrupts routed on 79EB365 board */
++#define RC32365_PCI_INTA_IRQ (GROUP4_IRQ_BASE + 8)
++#define RC32365_PCI_INTB_IRQ (GROUP4_IRQ_BASE + 9)
++#define RC32365_PCI_INTC_IRQ (GROUP4_IRQ_BASE + 10)
++#define RC32365_PCI_INTD_IRQ (GROUP4_IRQ_BASE + 11)
++
++#define RAM_SIZE (32 * 1024 * 1024)
++
++#endif //__IDT_RC32365_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_pci.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_pci.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_pci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_pci.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,515 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Datatype declaration for IDT 79EB365/336 PCI
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RC32365_PCI_H__
++#define __IDT_RC32365_PCI_H__
++
++enum
++{
++ PCI0_PhysicalAddress = 0x18068000,
++ PCI_PhysicalAddress = PCI0_PhysicalAddress,
++
++ PCI0_VirtualAddress = 0xb8068000,
++ PCI_VirtualAddress = PCI0_VirtualAddress,
++} ;
++
++enum
++{
++ PCI_LbaCount = 4, // Local base addresses.
++} ;
++
++typedef struct
++{
++ u32 a ; // Address.
++ u32 c ; // Control.
++ u32 m ; // mapping.
++} PCI_Map_s ;
++
++typedef struct
++{
++ u32 pcic ;
++ u32 pcis ;
++ u32 pcism ;
++ u32 pcicfga ;
++ u32 pcicfgd ;
++ PCI_Map_s pcilba [PCI_LbaCount] ;
++ u32 pcidac ;
++ u32 pcidas ;
++ u32 pcidasm ;
++ u32 pcidad ;
++ u32 pcidma8c ;
++ u32 pcidma9c ;
++ u32 pcitc ;
++} volatile *PCI_t ;
++
++// PCI messaging unit.
++enum
++{
++ PCIM_Count = 2,
++} ;
++typedef struct
++{
++ u32 pciim [PCIM_Count] ;
++ u32 pciom [PCIM_Count] ;
++ u32 pciid ;
++ u32 pciiic ;
++ u32 pciiim ;
++ u32 pciiod ;
++ u32 pciioic ;
++ u32 pciioim ;
++} volatile *PCIM_t ;
++
++/*******************************************************************************
++ *
++ * PCI Control Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCIC_en_b = 0,
++ PCIC_en_m = 0x00000001,
++ PCIC_tnr_b = 1,
++ PCIC_tnr_m = 0x00000002,
++ PCIC_sce_b = 2,
++ PCIC_sce_m = 0x00000004,
++ PCIC_ien_b = 3,
++ PCIC_ien_m = 0x00000008,
++ PCIC_aaa_b = 4,
++ PCIC_aaa_m = 0x00000010,
++ PCIC_eap_b = 5,
++ PCIC_eap_m = 0x00000020,
++ PCIC_pcim_b = 6,
++ PCIC_pcim_m = 0x000001c0,
++ PCIC_pcim_disabled_v = 0,
++ PCIC_pcim_tnr_v = 1, // Satellite - target not ready
++ PCIC_pcim_suspend_v = 2, // Satellite - suspended CPU.
++ PCIC_pcim_extern_v = 3, // Host - external arbiter.
++ PCIC_pcim_fixed_v = 4, // Host - fixed priority arb.
++ PCIC_pcim_roundrobin_v = 5, // Host - round robin priority.
++ PCIC_pcim_reserved6_v = 6,
++ PCIC_pcim_reserved7_v = 7,
++ PCIC_igm_b = 9,
++ PCIC_igm_m = 0x00000200,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Status Register
++ *
++ ******************************************************************************/
++enum {
++ PCIS_eed_b = 0,
++ PCIS_eed_m = 0x00000001,
++ PCIS_wr_b = 1,
++ PCIS_wr_m = 0x00000002,
++ PCIS_nmi_b = 2,
++ PCIS_nmi_m = 0x00000004,
++ PCIS_ii_b = 3,
++ PCIS_ii_m = 0x00000008,
++ PCIS_cwe_b = 4,
++ PCIS_cwe_m = 0x00000010,
++ PCIS_cre_b = 5,
++ PCIS_cre_m = 0x00000020,
++ PCIS_mdpe_b = 6,
++ PCIS_mdpe_m = 0x00000040,
++ PCIS_sta_b = 7,
++ PCIS_sta_m = 0x00000080,
++ PCIS_rta_b = 8,
++ PCIS_rta_m = 0x00000100,
++ PCIS_rma_b = 9,
++ PCIS_rma_m = 0x00000200,
++ PCIS_sse_b = 10,
++ PCIS_sse_m = 0x00000400,
++ PCIS_ose_b = 11,
++ PCIS_ose_m = 0x00000800,
++ PCIS_pe_b = 12,
++ PCIS_pe_m = 0x00001000,
++ PCIS_tae_b = 13,
++ PCIS_tae_m = 0x00002000,
++ PCIS_rle_b = 14,
++ PCIS_rle_m = 0x00004000,
++ PCIS_bme_b = 15,
++ PCIS_bme_m = 0x00008000,
++ PCIS_prd_b = 16,
++ PCIS_prd_m = 0x00010000,
++ PCIS_rip_b = 17,
++ PCIS_rip_m = 0x00020000,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Status Mask Register
++ *
++ ******************************************************************************/
++enum {
++ PCISM_eed_b = 0,
++ PCISM_eed_m = 0x00000001,
++ PCISM_wr_b = 1,
++ PCISM_wr_m = 0x00000002,
++ PCISM_nmi_b = 2,
++ PCISM_nmi_m = 0x00000004,
++ PCISM_ii_b = 3,
++ PCISM_ii_m = 0x00000008,
++ PCISM_cwe_b = 4,
++ PCISM_cwe_m = 0x00000010,
++ PCISM_cre_b = 5,
++ PCISM_cre_m = 0x00000020,
++ PCISM_mdpe_b = 6,
++ PCISM_mdpe_m = 0x00000040,
++ PCISM_sta_b = 7,
++ PCISM_sta_m = 0x00000080,
++ PCISM_rta_b = 8,
++ PCISM_rta_m = 0x00000100,
++ PCISM_rma_b = 9,
++ PCISM_rma_m = 0x00000200,
++ PCISM_sse_b = 10,
++ PCISM_sse_m = 0x00000400,
++ PCISM_ose_b = 11,
++ PCISM_ose_m = 0x00000800,
++ PCISM_pe_b = 12,
++ PCISM_pe_m = 0x00001000,
++ PCISM_tae_b = 13,
++ PCISM_tae_m = 0x00002000,
++ PCISM_rle_b = 14,
++ PCISM_rle_m = 0x00004000,
++ PCISM_bme_b = 15,
++ PCISM_bme_m = 0x00008000,
++ PCISM_prd_b = 16,
++ PCISM_prd_m = 0x00010000,
++ PCISM_rip_b = 17,
++ PCISM_rip_m = 0x00020000,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Configuration Address Register
++ *
++ ******************************************************************************/
++enum {
++ PCICFGA_reg_b = 2,
++ PCICFGA_reg_m = 0x000000fc,
++ PCICFGA_reg_id_v = 0x00>>2, //use PCFGID_
++ PCICFGA_reg_04_v = 0x04>>2, //use PCFG04_
++ PCICFGA_reg_08_v = 0x08>>2, //use PCFG08_
++ PCICFGA_reg_0C_v = 0x0C>>2, //use PCFG0C_
++ PCICFGA_reg_pba0_v = 0x10>>2, //use PCIPBA_
++ PCICFGA_reg_pba1_v = 0x14>>2, //use PCIPBA_
++ PCICFGA_reg_pba2_v = 0x18>>2, //use PCIPBA_
++ PCICFGA_reg_pba3_v = 0x1c>>2, //use PCIPBA_
++ PCICFGA_reg_subsystem_v = 0x2c>>2, //use PCFGSS_
++ PCICFGA_reg_3C_v = 0x3C>>2, //use PCFG3C_
++ PCICFGA_reg_pba0c_v = 0x44>>2, //use PCIPBAC_
++ PCICFGA_reg_pba0m_v = 0x48>>2,
++ PCICFGA_reg_pba1c_v = 0x4c>>2, //use PCIPBAC_
++ PCICFGA_reg_pba1m_v = 0x50>>2,
++ PCICFGA_reg_pba2c_v = 0x54>>2, //use PCIPBAC_
++ PCICFGA_reg_pba2m_v = 0x58>>2,
++ PCICFGA_reg_pba3c_v = 0x5c>>2, //use PCIPBAC_
++ PCICFGA_reg_pba3m_v = 0x60>>2,
++ PCICFGA_reg_pmgt_v = 0x64>>2,
++ PCICFGA_func_b = 8,
++ PCICFGA_func_m = 0x00000700,
++ PCICFGA_dev_b = 11,
++ PCICFGA_dev_m = 0x0000f800,
++ PCICFGA_dev_internal_v = 0,
++ PCICFGA_bus_b = 16,
++ PCICFGA_bus_m = 0x00ff0000,
++ PCICFGA_bus_type0_v = 0, //local bus
++ PCICFGA_en_b = 31, // read only
++ PCICFGA_en_m = 0x80000000,
++} ;
++
++enum {
++ PCFGID_vendor_b = 0,
++ PCFGID_vendor_m = 0x0000ffff,
++ PCFGID_vendor_IDT_v = 0x111d,
++ PCFGID_device_b = 16,
++ PCFGID_device_m = 0xffff0000,
++ PCFGID_device_Acaciade_v = 0x0207,
++
++ PCFG04_command_ioena_b = 1,
++ PCFG04_command_ioena_m = 0x00000001,
++ PCFG04_command_memena_b = 2,
++ PCFG04_command_memena_m = 0x00000002,
++ PCFG04_command_bmena_b = 3,
++ PCFG04_command_bmena_m = 0x00000004,
++ PCFG04_command_mwinv_b = 5,
++ PCFG04_command_mwinv_m = 0x00000010,
++ PCFG04_command_parena_b = 7,
++ PCFG04_command_parena_m = 0x00000040,
++ PCFG04_command_serrena_b = 9,
++ PCFG04_command_serrena_m = 0x00000100,
++ PCFG04_command_fastbbena_b = 10,
++ PCFG04_command_fastbbena_m = 0x00000200,
++ PCFG04_status_b = 16,
++ PCFG04_status_m = 0xffff0000,
++ PCFG04_status_66MHz_b = 21, // 66 MHz enable
++ PCFG04_status_66MHz_m = 0x00200000,
++ PCFG04_status_fbb_b = 23,
++ PCFG04_status_fbb_m = 0x00800000,
++ PCFG04_status_mdpe_b = 24,
++ PCFG04_status_mdpe_m = 0x01000000,
++ PCFG04_status_dst_b = 25,
++ PCFG04_status_dst_m = 0x06000000,
++ PCFG04_status_sta_b = 27,
++ PCFG04_status_sta_m = 0x08000000,
++ PCFG04_status_rta_b = 28,
++ PCFG04_status_rta_m = 0x10000000,
++ PCFG04_status_rma_b = 29,
++ PCFG04_status_rma_m = 0x20000000,
++ PCFG04_status_sse_b = 30,
++ PCFG04_status_sse_m = 0x40000000,
++ PCFG04_status_pe_b = 31,
++ PCFG04_status_pe_m = 0x40000000,
++
++ PCFG08_revId_b = 0,
++ PCFG08_revId_m = 0x000000ff,
++ PCFG08_classCode_b = 0,
++ PCFG08_classCode_m = 0xffffff00,
++ PCFG08_classCode_bridge_v = 06,
++ PCFG08_classCode_proc_v = 0x0b3000, // processor-MIPS
++ PCFG0C_cacheline_b = 0,
++ PCFG0C_cacheline_m = 0x000000ff,
++ PCFG0C_masterLatency_b = 8,
++ PCFG0C_masterLatency_m = 0x0000ff00,
++ PCFG0C_headerType_b = 16,
++ PCFG0C_headerType_m = 0x00ff0000,
++ PCFG0C_bist_b = 24,
++ PCFG0C_bist_m = 0xff000000,
++
++ PCIPBA_msi_b = 0,
++ PCIPBA_msi_m = 0x00000001,
++ PCIPBA_p_b = 3,
++ PCIPBA_p_m = 0x00000004,
++ PCIPBA_baddr_b = 8,
++ PCIPBA_baddr_m = 0xffffff00,
++
++ PCFGSS_vendorId_b = 0,
++ PCFGSS_vendorId_m = 0x0000ffff,
++ PCFGSS_id_b = 16,
++ PCFGSS_id_m = 0xffff0000,
++
++ PCFG3C_interruptLine_b = 0,
++ PCFG3C_interruptLine_m = 0x000000ff,
++ PCFG3C_interruptPin_b = 8,
++ PCFG3C_interruptPin_m = 0x0000ff00,
++ PCFG3C_minGrant_b = 16,
++ PCFG3C_minGrant_m = 0x00ff0000,
++ PCFG3C_maxLat_b = 24,
++ PCFG3C_maxLat_m = 0xff000000,
++
++ PCIPBAC_msi_b = 0,
++ PCIPBAC_msi_m = 0x00000001,
++ PCIPBAC_p_b = 1,
++ PCIPBAC_p_m = 0x00000002,
++ PCIPBAC_size_b = 2,
++ PCIPBAC_size_m = 0x0000007c,
++ PCIPBAC_sb_b = 7,
++ PCIPBAC_sb_m = 0x00000080,
++ PCIPBAC_pp_b = 8,
++ PCIPBAC_pp_m = 0x00000100,
++ PCIPBAC_mr_b = 9,
++ PCIPBAC_mr_m = 0x00000600,
++ PCIPBAC_mr_read_v =0, //no prefetching
++ PCIPBAC_mr_readLine_v =1,
++ PCIPBAC_mr_readMult_v =2,
++ PCIPBAC_mrl_b = 11,
++ PCIPBAC_mrl_m = 0x00000800,
++ PCIPBAC_mrm_b = 12,
++ PCIPBAC_mrm_m = 0x00001000,
++ PCIPBAC_trp_b = 13,
++ PCIPBAC_trp_m = 0x00002000,
++
++ PCFG40_trdyTimeout_b = 0,
++ PCFG40_trdyTimeout_m = 0x000000ff,
++ PCFG40_retryLim_b = 8,
++ PCFG40_retryLim_m = 0x0000ff00,
++};
++
++/*******************************************************************************
++ *
++ * PCI Local Base Address [0|1|2|3] Register
++ *
++ ******************************************************************************/
++enum {
++ PCILBA_baddr_b = 0, // In PCI_t -> pcilba [] .a
++ PCILBA_baddr_m = 0xffffff00,
++} ;
++/*******************************************************************************
++ *
++ * PCI Local Base Address Control Register
++ *
++ ******************************************************************************/
++enum {
++ PCILBAC_msi_b = 0, // In pPci->pcilba[i].c
++ PCILBAC_msi_m = 0x00000001,
++ PCILBAC_msi_mem_v = 0,
++ PCILBAC_msi_io_v = 1,
++ PCILBAC_size_b = 2, // In pPci->pcilba[i].c
++ PCILBAC_size_m = 0x0000007c,
++ PCILBAC_sb_b = 7, // In pPci->pcilba[i].c
++ PCILBAC_sb_m = 0x00000080,
++ PCILBAC_rt_b = 8, // In pPci->pcilba[i].c
++ PCILBAC_rt_m = 0x00000100,
++ PCILBAC_rt_noprefetch_v = 0, // mem read
++ PCILBAC_rt_prefetch_v = 1, // mem readline
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Local Base Address [0|1|2|3] Mapping Register
++ *
++ ******************************************************************************/
++enum {
++ PCILBAM_maddr_b = 8,
++ PCILBAM_maddr_m = 0xffffff00,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Decoupled Access Control Register
++ *
++ ******************************************************************************/
++enum {
++ PCIDAC_den_b = 0,
++ PCIDAC_den_m = 0x00000001,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Decoupled Access Status Register
++ *
++ ******************************************************************************/
++enum {
++ PCIDAS_d_b = 0,
++ PCIDAS_d_m = 0x00000001,
++ PCIDAS_b_b = 1,
++ PCIDAS_b_m = 0x00000002,
++ PCIDAS_e_b = 2,
++ PCIDAS_e_m = 0x00000004,
++ PCIDAS_ofe_b = 3,
++ PCIDAS_ofe_m = 0x00000008,
++ PCIDAS_off_b = 4,
++ PCIDAS_off_m = 0x00000010,
++ PCIDAS_ife_b = 5,
++ PCIDAS_ife_m = 0x00000020,
++ PCIDAS_iff_b = 6,
++ PCIDAS_iff_m = 0x00000040,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI DMA Channel 8 Configuration Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCIDMA8C_mbs_b = 0, // Maximum Burst Size.
++ PCIDMA8C_mbs_m = 0x00000fff, // { pcidma8c }
++ PCIDMA8C_our_b = 12, // Optimize Unaligned Burst Reads.
++ PCIDMA8C_our_m = 0x00001000, // { pcidma8c }
++} ;
++
++/*******************************************************************************
++ *
++ * PCI DMA Channel 9 Configuration Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCIDMA9C_mbs_b = 0, // Maximum Burst Size.
++ PCIDMA9C_mbs_m = 0x00000fff, // { pcidma9c }
++} ;
++
++/*******************************************************************************
++ *
++ * PCI to Memory(DMA Channel 8) AND Memory to PCI DMA(DMA Channel 9)Descriptors
++ *
++ ******************************************************************************/
++enum {
++ PCIDMAD_pt_b = 22, // in DEVCMD field (descriptor)
++ PCIDMAD_pt_m = 0x00c00000, // preferred transaction field
++ // These are for reads (DMA channel 8)
++ PCIDMAD_devcmd_mr_v = 0, //memory read
++ PCIDMAD_devcmd_mrl_v = 1, //memory read line
++ PCIDMAD_devcmd_mrm_v = 2, //memory read multiple
++ PCIDMAD_devcmd_ior_v = 3, //I/O read
++ // These are for writes (DMA channel 9)
++ PCIDMAD_devcmd_mw_v = 0, //memory write
++ PCIDMAD_devcmd_mwi_v = 1, //memory write invalidate
++ PCIDMAD_devcmd_iow_v = 3, //I/O write
++
++ // Swap byte field applies to both DMA channel 8 and 9
++ PCIDMAD_sb_b = 24, // in DEVCMD field (descriptor)
++ PCIDMAD_sb_m = 0x01000000, // swap byte field
++} ;
++
++
++/*******************************************************************************
++ *
++ * PCI Target Control Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCITC_rtimer_b = 0, // In PCITC_t -> pcitc
++ PCITC_rtimer_m = 0x000000ff,
++ PCITC_dtimer_b = 8, // In PCITC_t -> pcitc
++ PCITC_dtimer_m = 0x0000ff00,
++ PCITC_rdr_b = 18, // In PCITC_t -> pcitc
++ PCITC_rdr_m = 0x00040000,
++ PCITC_ddt_b = 19, // In PCITC_t -> pcitc
++ PCITC_ddt_m = 0x00080000,
++} ;
++/*******************************************************************************
++ *
++ * PCI messaging unit [applies to both inbound and outbound registers ]
++ *
++ ******************************************************************************/
++enum
++{
++ PCIM_m0_b = 0, // In PCIM_t -> {pci{iic,iim,ioic,ioim}}
++ PCIM_m0_m = 0x00000001, // inbound or outbound message 0
++ PCIM_m1_b = 1, // In PCIM_t -> {pci{iic,iim,ioic,ioim}}
++ PCIM_m1_m = 0x00000002, // inbound or outbound message 1
++ PCIM_db_b = 2, // In PCIM_t -> {pci{iic,iim,ioic,ioim}}
++ PCIM_db_m = 0x00000004, // inbound or outbound doorbell
++};
++
++
++#endif // __IDT_RC32365_PCI_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_pci_v.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_pci_v.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32300/rc32365_pci_v.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32300/rc32365_pci_v.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,217 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * PCI header values for IDT 79EB365/336
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RC32365_PCI_V_H__
++#define __IDT_RC32365_PCI_V_H__
++
++
++#define PCI_MSG_VirtualAddress 0xB806C010
++#define rc32365_pci ((volatile PCI_t) PCI0_VirtualAddress)
++#define rc32365_pci_msg ((volatile PCIM_t) PCI_MSG_VirtualAddress)
++
++#define PCIM_SHFT 0x6
++#define PCIM_BIT_LEN 0x7
++#define PCIM_H_EA 0x3
++#define PCIM_H_IA_FIX 0x4
++#define PCIM_H_IA_RR 0x5
++
++#define PCI_ADDR_START 0x50000000
++
++#define CPUTOPCI_MEM_WIN 0x02000000
++#define CPUTOPCI_IO_WIN 0x00100000
++#define PCILBA_SIZE_SHFT 2
++#define PCILBA_SIZE_MASK 0x1F
++#define SIZE_256MB 0x1C
++#define SIZE_128MB 0x1B
++#define SIZE_64MB 0x1A
++#define SIZE_32MB 0x19
++#define SIZE_16MB 0x18
++#define SIZE_4MB 0x16
++#define SIZE_2MB 0x15
++#define SIZE_1MB 0x14
++#define CEDAR_CONFIG0_ADDR 0x80000000
++#define CEDAR_CONFIG1_ADDR 0x80000004
++#define CEDAR_CONFIG2_ADDR 0x80000008
++#define CEDAR_CONFIG3_ADDR 0x8000000C
++#define CEDAR_CONFIG4_ADDR 0x80000010
++#define CEDAR_CONFIG5_ADDR 0x80000014
++#define CEDAR_CONFIG6_ADDR 0x80000018
++#define CEDAR_CONFIG7_ADDR 0x8000001C
++#define CEDAR_CONFIG8_ADDR 0x80000020
++#define CEDAR_CONFIG9_ADDR 0x80000024
++#define CEDAR_CONFIG10_ADDR 0x80000028
++#define CEDAR_CONFIG11_ADDR 0x8000002C
++#define CEDAR_CONFIG12_ADDR 0x80000030
++#define CEDAR_CONFIG13_ADDR 0x80000034
++#define CEDAR_CONFIG14_ADDR 0x80000038
++#define CEDAR_CONFIG15_ADDR 0x8000003C
++#define CEDAR_CONFIG16_ADDR 0x80000040
++#define CEDAR_CONFIG17_ADDR 0x80000044
++#define CEDAR_CONFIG18_ADDR 0x80000048
++#define CEDAR_CONFIG19_ADDR 0x8000004C
++#define CEDAR_CONFIG20_ADDR 0x80000050
++#define CEDAR_CONFIG21_ADDR 0x80000054
++#define CEDAR_CONFIG22_ADDR 0x80000058
++#define CEDAR_CONFIG23_ADDR 0x8000005C
++#define CEDAR_CONFIG24_ADDR 0x80000060
++#define CEDAR_CONFIG25_ADDR 0x80000064
++#define CEDAR_CMD (PCFG04_command_ioena_m | \
++ PCFG04_command_memena_m | \
++ PCFG04_command_bmena_m | \
++ PCFG04_command_mwinv_m | \
++ PCFG04_command_parena_m | \
++ PCFG04_command_serrena_m )
++
++#define CEDAR_STAT (PCFG04_status_mdpe_m | \
++ PCFG04_status_sta_m | \
++ PCFG04_status_rta_m | \
++ PCFG04_status_rma_m | \
++ PCFG04_status_sse_m | \
++ PCFG04_status_pe_m)
++
++#define CEDAR_CNFG1 ((CEDAR_STAT << 16) | \
++ CEDAR_CMD)
++
++#define CEDAR_REVID 0
++#define CEDAR_CLASS_CODE 0
++#define CEDAR_CNFG2 ((CEDAR_CLASS_CODE << 8) | \
++ CEDAR_REVID)
++
++#define CEDAR_CACHE_LINE_SIZE 4
++#define CEDAR_MASTER_LAT 0x3c
++#define CEDAR_HEADER_TYPE 0
++#define CEDAR_BIST 0
++
++#define CEDAR_CNFG3 ((CEDAR_BIST << 24) | \
++ (CEDAR_HEADER_TYPE << 16) | \
++ (CEDAR_MASTER_LAT << 8) | \
++ CEDAR_CACHE_LINE_SIZE)
++
++#define CEDAR_BAR0 0x00000008 /* 128 MB Memory */
++#define CEDAR_BAR1 0x18800001 /* 1 MB IO */
++#define CEDAR_BAR2 0x18000001 /* 2 MB IO window for Cedar
++ internal Registers */
++#define CEDAR_BAR3 0x48000008 /* Spare 128 MB Memory */
++
++#define CEDAR_CNFG4 CEDAR_BAR0
++#define CEDAR_CNFG5 CEDAR_BAR1
++#define CEDAR_CNFG6 CEDAR_BAR2
++#define CEDAR_CNFG7 CEDAR_BAR3
++
++#define CEDAR_SUBSYS_VENDOR_ID 0
++#define CEDAR_SUBSYSTEM_ID 0
++#define CEDAR_CNFG8 0
++#define CEDAR_CNFG9 0
++#define CEDAR_CNFG10 0
++#define CEDAR_CNFG11 ((CEDAR_SUBSYS_VENDOR_ID << 16) | \
++ CEDAR_SUBSYSTEM_ID)
++#define CEDAR_INT_LINE 1
++#define CEDAR_INT_PIN 1
++#define CEDAR_MIN_GNT 8
++#define CEDAR_MAX_LAT 0x38
++#define CEDAR_CNFG12 0
++#define CEDAR_CNFG13 0
++#define CEDAR_CNFG14 0
++#define CEDAR_CNFG15 ((CEDAR_MAX_LAT << 24) | \
++ (CEDAR_MIN_GNT << 16) | \
++ (CEDAR_INT_PIN << 8) | \
++ CEDAR_INT_LINE)
++#define CEDAR_RETRY_LIMIT 0x80
++#define CEDAR_TRDY_LIMIT 0x80
++#define CEDAR_CNFG16 ((CEDAR_RETRY_LIMIT << 8) | \
++ CEDAR_TRDY_LIMIT)
++#define PCI_PBAxC_R 0x0
++#define PCI_PBAxC_RL 0x1
++#define PCI_PBAxC_RM 0x2
++#define SIZE_SHFT 2
++#ifdef __MIPSEB__
++#define CEDAR_PBA0C (((1 & 0x3) << PCIPBAC_mr_b) | \
++ PCIPBAC_pp_m | \
++ PCIPBAC_sb_m | \
++ (SIZE_128MB << SIZE_SHFT) | \
++ PCIPBAC_p_m)
++#else
++
++#define CEDAR_PBA0C (((1 & 0x3) << PCIPBAC_mr_b) | \
++ PCIPBAC_pp_m | \
++ (SIZE_128MB << SIZE_SHFT) | \
++ PCIPBAC_p_m)
++#endif
++#define CEDAR_CNFG17 CEDAR_PBA0C
++#define CEDAR_PBA0M 0x0
++#define CEDAR_CNFG18 CEDAR_PBA0M
++
++#ifdef __MIPSEB__
++#define CEDAR_PBA1C ((SIZE_1MB << SIZE_SHFT) | \
++ PCIPBAC_sb_m | \
++ PCIPBAC_msi_m)
++#else
++#define CEDAR_PBA1C ((SIZE_1MB << SIZE_SHFT) | \
++ PCIPBAC_msi_m)
++#endif
++#define CEDAR_CNFG19 CEDAR_PBA1C
++#define CEDAR_PBA1M 0x0
++#define CEDAR_CNFG20 CEDAR_PBA1M
++
++#ifdef __MIPSEB__
++#define CEDAR_PBA2C ((SIZE_2MB << SIZE_SHFT) | \
++ PCIPBAC_sb_m | \
++ PCIPBAC_msi_m)
++#else
++#define CEDAR_PBA2C ((SIZE_2MB << SIZE_SHFT) | \
++ PCIPBAC_msi_m)
++#endif
++
++#define CEDAR_CNFG21 CEDAR_PBA2C
++#define CEDAR_PBA2M 0x18000000
++#define CEDAR_CNFG22 CEDAR_PBA2M
++
++#ifdef __MIPSEB__
++#define CEDAR_PBA3C PCIPBAC_sb_m
++#else
++#define CEDAR_PBA3C 0
++#endif
++
++#define CEDAR_CNFG23 CEDAR_PBA3C
++#define CEDAR_PBA3M 0
++#define CEDAR_CNFG24 CEDAR_PBA3M
++
++#define PCITC_DTIMER_VAL 8
++#define PCITC_RTIMER_VAL 0x10
++
++#endif //__IDT_RC32365_PCI_V_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_dma.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_dma.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_dma.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_dma.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,205 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * DMA register definition
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_DMA_H__
++#define __IDT_DMA_H__
++
++enum
++{
++ DMA0_PhysicalAddress = 0x18040000,
++ DMA_PhysicalAddress = DMA0_PhysicalAddress, // Default
++
++ DMA0_VirtualAddress = 0xb8040000,
++ DMA_VirtualAddress = DMA0_VirtualAddress, // Default
++} ;
++
++/*
++ * DMA descriptor (in physical memory).
++ */
++
++typedef struct DMAD_s
++{
++ u32 control ; // Control. use DMAD_*
++ u32 ca ; // Current Address.
++ u32 devcs ; // Device control and status.
++ u32 link ; // Next descriptor in chain.
++} volatile *DMAD_t ;
++
++enum
++{
++ DMAD_size = sizeof (struct DMAD_s),
++ DMAD_count_b = 0, // in DMAD_t -> control
++ DMAD_count_m = 0x0003ffff, // in DMAD_t -> control
++ DMAD_ds_b = 20, // in DMAD_t -> control
++ DMAD_ds_m = 0x00300000, // in DMAD_t -> control
++ DMAD_ds_ethRcv0_v = 0,
++ DMAD_ds_ethXmt0_v = 0,
++ DMAD_ds_memToFifo_v = 0,
++ DMAD_ds_fifoToMem_v = 0,
++ DMAD_ds_pciToMem_v = 0,
++ DMAD_ds_memToPci_v = 0,
++
++ DMAD_devcmd_b = 22, // in DMAD_t -> control
++ DMAD_devcmd_m = 0x01c00000, // in DMAD_t -> control
++ DMAD_devcmd_byte_v = 0, //memory-to-memory
++ DMAD_devcmd_halfword_v = 1, //memory-to-memory
++ DMAD_devcmd_word_v = 2, //memory-to-memory
++ DMAD_devcmd_2words_v = 3, //memory-to-memory
++ DMAD_devcmd_4words_v = 4, //memory-to-memory
++ DMAD_devcmd_6words_v = 5, //memory-to-memory
++ DMAD_devcmd_8words_v = 6, //memory-to-memory
++ DMAD_devcmd_16words_v = 7, //memory-to-memory
++ DMAD_cof_b = 25, // chain on finished
++ DMAD_cof_m = 0x02000000, //
++ DMAD_cod_b = 26, // chain on done
++ DMAD_cod_m = 0x04000000, //
++ DMAD_iof_b = 27, // interrupt on finished
++ DMAD_iof_m = 0x08000000, //
++ DMAD_iod_b = 28, // interrupt on done
++ DMAD_iod_m = 0x10000000, //
++ DMAD_t_b = 29, // terminated
++ DMAD_t_m = 0x20000000, //
++ DMAD_d_b = 30, // done
++ DMAD_d_m = 0x40000000, //
++ DMAD_f_b = 31, // finished
++ DMAD_f_m = 0x80000000, //
++} ;
++
++/*
++ * DMA register (within Internal Register Map).
++ */
++
++struct DMA_Chan_s
++{
++ u32 dmac ; // Control.
++ u32 dmas ; // Status.
++ u32 dmasm ; // Mask.
++ u32 dmadptr ; // Descriptor pointer.
++ u32 dmandptr ; // Next descriptor pointer.
++};
++
++typedef struct DMA_Chan_s volatile *DMA_Chan_t ;
++
++//DMA_Channels use DMACH_count instead
++
++enum
++{
++ DMAC_run_b = 0, //
++ DMAC_run_m = 0x00000001, //
++ DMAC_dm_b = 1, // done mask
++ DMAC_dm_m = 0x00000002, //
++ DMAC_mode_b = 2, //
++ DMAC_mode_m = 0x0000000c, //
++ DMAC_mode_auto_v = 0,
++ DMAC_mode_burst_v = 1,
++ DMAC_mode_transfer_v = 2, //usually used
++ DMAC_mode_reserved_v = 3,
++ DMAC_a_b = 4, //
++ DMAC_a_m = 0x00000010, //
++
++ DMAS_f_b = 0, // finished (sticky)
++ DMAS_f_m = 0x00000001, //
++ DMAS_d_b = 1, // done (sticky)
++ DMAS_d_m = 0x00000002, //
++ DMAS_c_b = 2, // chain (sticky)
++ DMAS_c_m = 0x00000004, //
++ DMAS_e_b = 3, // error (sticky)
++ DMAS_e_m = 0x00000008, //
++ DMAS_h_b = 4, // halt (sticky)
++ DMAS_h_m = 0x00000010, //
++
++ DMASM_f_b = 0, // finished (1=mask)
++ DMASM_f_m = 0x00000001, //
++ DMASM_d_b = 1, // done (1=mask)
++ DMASM_d_m = 0x00000002, //
++ DMASM_c_b = 2, // chain (1=mask)
++ DMASM_c_m = 0x00000004, //
++ DMASM_e_b = 3, // error (1=mask)
++ DMASM_e_m = 0x00000008, //
++ DMASM_h_b = 4, // halt (1=mask)
++ DMASM_h_m = 0x00000010, //
++} ;
++
++/*
++ * DMA channel definitions
++ */
++
++enum
++{
++ DMACH_ethRcv0 = 0,
++ DMACH_ethXmt0 = 1,
++ DMACH_memToFifo = 2,
++ DMACH_fifoToMem = 3,
++ DMACH_pciToMem = 4,
++ DMACH_memToPci = 5,
++
++ DMACH_count //must be last
++};
++
++
++typedef struct DMAC_s
++{
++ struct DMA_Chan_s ch [DMACH_count] ; //use ch[DMACH_]
++} volatile *DMA_t ;
++
++
++/*
++ * External DMA parameters
++*/
++
++enum
++{
++ DMADEVCMD_ts_b = 0, // ts field in devcmd
++ DMADEVCMD_ts_m = 0x00000007, // ts field in devcmd
++ DMADEVCMD_ts_byte_v = 0,
++ DMADEVCMD_ts_halfword_v = 1,
++ DMADEVCMD_ts_word_v = 2,
++ DMADEVCMD_ts_2word_v = 3,
++ DMADEVCMD_ts_4word_v = 4,
++ DMADEVCMD_ts_6word_v = 5,
++ DMADEVCMD_ts_8word_v = 6,
++ DMADEVCMD_ts_16word_v = 7
++};
++
++
++#endif // __IDT_DMA_H__
++
++
++
++
++
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_dma_v.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_dma_v.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_dma_v.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_dma_v.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,89 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Definitions for DMA controller.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_DMA_V_H__
++#define __IDT_DMA_V_H__
++
++#include <asm/idt-boards/rc32434/rc32434_dma.h>
++#include <asm/idt-boards/rc32434/rc32434.h>
++
++#define DMA_CHAN_OFFSET 0x14
++#define IS_DMA_USED(X) (((X) & (DMAD_f_m | DMAD_d_m | DMAD_t_m)) != 0)
++#define DMA_COUNT(count) \
++ ((count) & DMAD_count_m)
++
++#define DMA_HALT_TIMEOUT 500
++
++
++static inline int rc32434_halt_dma(DMA_Chan_t ch)
++{
++ int timeout=1;
++ if (rc32434_readl(&ch->dmac) & DMAC_run_m) {
++ rc32434_writel(0, &ch->dmac);
++
++ for (timeout = DMA_HALT_TIMEOUT; timeout > 0; timeout--) {
++ if (rc32434_readl(&ch->dmas) & DMAS_h_m) {
++ rc32434_writel(0, &ch->dmas);
++ break;
++ }
++ }
++
++ }
++
++ return timeout ? 0 : 1;
++}
++
++static inline void rc32434_start_dma(DMA_Chan_t ch, u32 dma_addr)
++{
++ rc32434_writel(0, &ch->dmandptr);
++ rc32434_writel(dma_addr, &ch->dmadptr);
++}
++
++static inline void rc32434_chain_dma(DMA_Chan_t ch, u32 dma_addr)
++{
++ rc32434_writel(dma_addr, &ch->dmandptr);
++}
++
++#endif // __IDT_DMA_V_H__
++
++
++
++
++
++
++
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_eth.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_eth.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_eth.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_eth.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,333 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Ethernet register definition
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_ETH_H__
++#define __IDT_ETH_H__
++
++
++enum
++{
++ ETH0_PhysicalAddress = 0x18060000,
++ ETH_PhysicalAddress = ETH0_PhysicalAddress, // Default
++
++ ETH0_VirtualAddress = 0xb8060000,
++ ETH_VirtualAddress = ETH0_VirtualAddress, // Default
++} ;
++
++typedef struct
++{
++ u32 ethintfc ;
++ u32 ethfifott ;
++ u32 etharc ;
++ u32 ethhash0 ;
++ u32 ethhash1 ;
++ u32 ethu0 [4] ; // Reserved.
++ u32 ethpfs ;
++ u32 ethmcp ;
++ u32 eth_u1 [10] ; // Reserved.
++ u32 ethspare ;
++ u32 eth_u2 [42] ; // Reserved.
++ u32 ethsal0 ;
++ u32 ethsah0 ;
++ u32 ethsal1 ;
++ u32 ethsah1 ;
++ u32 ethsal2 ;
++ u32 ethsah2 ;
++ u32 ethsal3 ;
++ u32 ethsah3 ;
++ u32 ethrbc ;
++ u32 ethrpc ;
++ u32 ethrupc ;
++ u32 ethrfc ;
++ u32 ethtbc ;
++ u32 ethgpf ;
++ u32 eth_u9 [50] ; // Reserved.
++ u32 ethmac1 ;
++ u32 ethmac2 ;
++ u32 ethipgt ;
++ u32 ethipgr ;
++ u32 ethclrt ;
++ u32 ethmaxf ;
++ u32 eth_u10 ; // Reserved.
++ u32 ethmtest ;
++ u32 miimcfg ;
++ u32 miimcmd ;
++ u32 miimaddr ;
++ u32 miimwtd ;
++ u32 miimrdd ;
++ u32 miimind ;
++ u32 eth_u11 ; // Reserved.
++ u32 eth_u12 ; // Reserved.
++ u32 ethcfsa0 ;
++ u32 ethcfsa1 ;
++ u32 ethcfsa2 ;
++} volatile *ETH_t;
++
++enum
++{
++ ETHINTFC_en_b = 0,
++ ETHINTFC_en_m = 0x00000001,
++ ETHINTFC_its_b = 1,
++ ETHINTFC_its_m = 0x00000002,
++ ETHINTFC_rip_b = 2,
++ ETHINTFC_rip_m = 0x00000004,
++ ETHINTFC_jam_b = 3,
++ ETHINTFC_jam_m = 0x00000008,
++ ETHINTFC_ovr_b = 4,
++ ETHINTFC_ovr_m = 0x00000010,
++ ETHINTFC_und_b = 5,
++ ETHINTFC_und_m = 0x00000020,
++
++ ETHFIFOTT_tth_b = 0,
++ ETHFIFOTT_tth_m = 0x0000007f,
++
++ ETHARC_pro_b = 0,
++ ETHARC_pro_m = 0x00000001,
++ ETHARC_am_b = 1,
++ ETHARC_am_m = 0x00000002,
++ ETHARC_afm_b = 2,
++ ETHARC_afm_m = 0x00000004,
++ ETHARC_ab_b = 3,
++ ETHARC_ab_m = 0x00000008,
++
++ ETHSAL_byte5_b = 0,
++ ETHSAL_byte5_m = 0x000000ff,
++ ETHSAL_byte4_b = 8,
++ ETHSAL_byte4_m = 0x0000ff00,
++ ETHSAL_byte3_b = 16,
++ ETHSAL_byte3_m = 0x00ff0000,
++ ETHSAL_byte2_b = 24,
++ ETHSAL_byte2_m = 0xff000000,
++
++ ETHSAH_byte1_b = 0,
++ ETHSAH_byte1_m = 0x000000ff,
++ ETHSAH_byte0_b = 8,
++ ETHSAH_byte0_m = 0x0000ff00,
++
++ ETHGPF_ptv_b = 0,
++ ETHGPF_ptv_m = 0x0000ffff,
++
++ ETHPFS_pfd_b = 0,
++ ETHPFS_pfd_m = 0x00000001,
++
++ ETHCFSA0_cfsa4_b = 0,
++ ETHCFSA0_cfsa4_m = 0x000000ff,
++ ETHCFSA0_cfsa5_b = 8,
++ ETHCFSA0_cfsa5_m = 0x0000ff00,
++
++ ETHCFSA1_cfsa2_b = 0,
++ ETHCFSA1_cfsa2_m = 0x000000ff,
++ ETHCFSA1_cfsa3_b = 8,
++ ETHCFSA1_cfsa3_m = 0x0000ff00,
++
++ ETHCFSA2_cfsa0_b = 0,
++ ETHCFSA2_cfsa0_m = 0x000000ff,
++ ETHCFSA2_cfsa1_b = 8,
++ ETHCFSA2_cfsa1_m = 0x0000ff00,
++
++ ETHMAC1_re_b = 0,
++ ETHMAC1_re_m = 0x00000001,
++ ETHMAC1_paf_b = 1,
++ ETHMAC1_paf_m = 0x00000002,
++ ETHMAC1_rfc_b = 2,
++ ETHMAC1_rfc_m = 0x00000004,
++ ETHMAC1_tfc_b = 3,
++ ETHMAC1_tfc_m = 0x00000008,
++ ETHMAC1_lb_b = 4,
++ ETHMAC1_lb_m = 0x00000010,
++ ETHMAC1_mr_b = 31,
++ ETHMAC1_mr_m = 0x80000000,
++
++ ETHMAC2_fd_b = 0,
++ ETHMAC2_fd_m = 0x00000001,
++ ETHMAC2_flc_b = 1,
++ ETHMAC2_flc_m = 0x00000002,
++ ETHMAC2_hfe_b = 2,
++ ETHMAC2_hfe_m = 0x00000004,
++ ETHMAC2_dc_b = 3,
++ ETHMAC2_dc_m = 0x00000008,
++ ETHMAC2_cen_b = 4,
++ ETHMAC2_cen_m = 0x00000010,
++ ETHMAC2_pe_b = 5,
++ ETHMAC2_pe_m = 0x00000020,
++ ETHMAC2_vpe_b = 6,
++ ETHMAC2_vpe_m = 0x00000040,
++ ETHMAC2_ape_b = 7,
++ ETHMAC2_ape_m = 0x00000080,
++ ETHMAC2_ppe_b = 8,
++ ETHMAC2_ppe_m = 0x00000100,
++ ETHMAC2_lpe_b = 9,
++ ETHMAC2_lpe_m = 0x00000200,
++ ETHMAC2_nb_b = 12,
++ ETHMAC2_nb_m = 0x00001000,
++ ETHMAC2_bp_b = 13,
++ ETHMAC2_bp_m = 0x00002000,
++ ETHMAC2_ed_b = 14,
++ ETHMAC2_ed_m = 0x00004000,
++
++ ETHIPGT_ipgt_b = 0,
++ ETHIPGT_ipgt_m = 0x0000007f,
++
++ ETHIPGR_ipgr2_b = 0,
++ ETHIPGR_ipgr2_m = 0x0000007f,
++ ETHIPGR_ipgr1_b = 8,
++ ETHIPGR_ipgr1_m = 0x00007f00,
++
++ ETHCLRT_maxret_b = 0,
++ ETHCLRT_maxret_m = 0x0000000f,
++ ETHCLRT_colwin_b = 8,
++ ETHCLRT_colwin_m = 0x00003f00,
++
++ ETHMAXF_maxf_b = 0,
++ ETHMAXF_maxf_m = 0x0000ffff,
++
++ ETHMTEST_tb_b = 2,
++ ETHMTEST_tb_m = 0x00000004,
++
++ ETHMCP_div_b = 0,
++ ETHMCP_div_m = 0x000000ff,
++
++ MIIMCFG_rsv_b = 0,
++ MIIMCFG_rsv_m = 0x0000000c,
++
++ MIIMCMD_rd_b = 0,
++ MIIMCMD_rd_m = 0x00000001,
++ MIIMCMD_scn_b = 1,
++ MIIMCMD_scn_m = 0x00000002,
++
++ MIIMADDR_regaddr_b = 0,
++ MIIMADDR_regaddr_m = 0x0000001f,
++ MIIMADDR_phyaddr_b = 8,
++ MIIMADDR_phyaddr_m = 0x00001f00,
++
++ MIIMWTD_wdata_b = 0,
++ MIIMWTD_wdata_m = 0x0000ffff,
++
++ MIIMRDD_rdata_b = 0,
++ MIIMRDD_rdata_m = 0x0000ffff,
++
++ MIIMIND_bsy_b = 0,
++ MIIMIND_bsy_m = 0x00000001,
++ MIIMIND_scn_b = 1,
++ MIIMIND_scn_m = 0x00000002,
++ MIIMIND_nv_b = 2,
++ MIIMIND_nv_m = 0x00000004,
++
++} ;
++
++/*
++ * Values for the DEVCS field of the Ethernet DMA Rx and Tx descriptors.
++ */
++enum
++{
++ ETHRX_fd_b = 0,
++ ETHRX_fd_m = 0x00000001,
++ ETHRX_ld_b = 1,
++ ETHRX_ld_m = 0x00000002,
++ ETHRX_rok_b = 2,
++ ETHRX_rok_m = 0x00000004,
++ ETHRX_fm_b = 3,
++ ETHRX_fm_m = 0x00000008,
++ ETHRX_mp_b = 4,
++ ETHRX_mp_m = 0x00000010,
++ ETHRX_bp_b = 5,
++ ETHRX_bp_m = 0x00000020,
++ ETHRX_vlt_b = 6,
++ ETHRX_vlt_m = 0x00000040,
++ ETHRX_cf_b = 7,
++ ETHRX_cf_m = 0x00000080,
++ ETHRX_ovr_b = 8,
++ ETHRX_ovr_m = 0x00000100,
++ ETHRX_crc_b = 9,
++ ETHRX_crc_m = 0x00000200,
++ ETHRX_cv_b = 10,
++ ETHRX_cv_m = 0x00000400,
++ ETHRX_db_b = 11,
++ ETHRX_db_m = 0x00000800,
++ ETHRX_le_b = 12,
++ ETHRX_le_m = 0x00001000,
++ ETHRX_lor_b = 13,
++ ETHRX_lor_m = 0x00002000,
++ ETHRX_ces_b = 14,
++ ETHRX_ces_m = 0x00004000,
++ ETHRX_length_b = 16,
++ ETHRX_length_m = 0xffff0000,
++
++ ETHTX_fd_b = 0,
++ ETHTX_fd_m = 0x00000001,
++ ETHTX_ld_b = 1,
++ ETHTX_ld_m = 0x00000002,
++ ETHTX_oen_b = 2,
++ ETHTX_oen_m = 0x00000004,
++ ETHTX_pen_b = 3,
++ ETHTX_pen_m = 0x00000008,
++ ETHTX_cen_b = 4,
++ ETHTX_cen_m = 0x00000010,
++ ETHTX_hen_b = 5,
++ ETHTX_hen_m = 0x00000020,
++ ETHTX_tok_b = 6,
++ ETHTX_tok_m = 0x00000040,
++ ETHTX_mp_b = 7,
++ ETHTX_mp_m = 0x00000080,
++ ETHTX_bp_b = 8,
++ ETHTX_bp_m = 0x00000100,
++ ETHTX_und_b = 9,
++ ETHTX_und_m = 0x00000200,
++ ETHTX_of_b = 10,
++ ETHTX_of_m = 0x00000400,
++ ETHTX_ed_b = 11,
++ ETHTX_ed_m = 0x00000800,
++ ETHTX_ec_b = 12,
++ ETHTX_ec_m = 0x00001000,
++ ETHTX_lc_b = 13,
++ ETHTX_lc_m = 0x00002000,
++ ETHTX_td_b = 14,
++ ETHTX_td_m = 0x00004000,
++ ETHTX_crc_b = 15,
++ ETHTX_crc_m = 0x00008000,
++ ETHTX_le_b = 16,
++ ETHTX_le_m = 0x00010000,
++ ETHTX_cc_b = 17,
++ ETHTX_cc_m = 0x001E0000,
++} ;
++
++#endif // __IDT_ETH_H__
++
++
++
++
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_eth_v.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_eth_v.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_eth_v.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_eth_v.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,77 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Ethernet register definition
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_ETH_V_H__
++#define __IDT_ETH_V_H__
++
++#include <asm/idt-boards/rc32434/rc32434_eth.h>
++
++#define IS_TX_TOK(X) (((X) & (1<<ETHTX_tok_b)) >> ETHTX_tok_b ) /* Transmit Okay */
++#define IS_TX_MP(X) (((X) & (1<<ETHTX_mp_b)) >> ETHTX_mp_b ) /* Multicast */
++#define IS_TX_BP(X) (((X) & (1<<ETHTX_bp_b)) >> ETHTX_bp_b ) /* Broadcast */
++#define IS_TX_UND_ERR(X) (((X) & (1<<ETHTX_und_b)) >> ETHTX_und_b ) /* Transmit FIFO Underflow */
++#define IS_TX_OF_ERR(X) (((X) & (1<<ETHTX_of_b)) >> ETHTX_of_b ) /* Oversized frame */
++#define IS_TX_ED_ERR(X) (((X) & (1<<ETHTX_ed_b)) >> ETHTX_ed_b ) /* Excessive deferral */
++#define IS_TX_EC_ERR(X) (((X) & (1<<ETHTX_ec_b)) >> ETHTX_ec_b) /* Excessive collisions */
++#define IS_TX_LC_ERR(X) (((X) & (1<<ETHTX_lc_b)) >> ETHTX_lc_b ) /* Late Collision */
++#define IS_TX_TD_ERR(X) (((X) & (1<<ETHTX_td_b)) >> ETHTX_td_b ) /* Transmit deferred*/
++#define IS_TX_CRC_ERR(X) (((X) & (1<<ETHTX_crc_b)) >> ETHTX_crc_b ) /* CRC Error */
++#define IS_TX_LE_ERR(X) (((X) & (1<<ETHTX_le_b)) >> ETHTX_le_b ) /* Length Error */
++
++#define TX_COLLISION_COUNT(X) (((X) & ETHTX_cc_m)>>ETHTX_cc_b) /* Collision Count */
++
++#define IS_RCV_ROK(X) (((X) & (1<<ETHRX_rok_b)) >> ETHRX_rok_b) /* Receive Okay */
++#define IS_RCV_FM(X) (((X) & (1<<ETHRX_fm_b)) >> ETHRX_fm_b) /* Is Filter Match */
++#define IS_RCV_MP(X) (((X) & (1<<ETHRX_mp_b)) >> ETHRX_mp_b) /* Is it MP */
++#define IS_RCV_BP(X) (((X) & (1<<ETHRX_bp_b)) >> ETHRX_bp_b) /* Is it BP */
++#define IS_RCV_VLT(X) (((X) & (1<<ETHRX_vlt_b)) >> ETHRX_vlt_b) /* VLAN Tag Detect */
++#define IS_RCV_CF(X) (((X) & (1<<ETHRX_cf_b)) >> ETHRX_cf_b) /* Control Frame */
++#define IS_RCV_OVR_ERR(X) (((X) & (1<<ETHRX_ovr_b)) >> ETHRX_ovr_b) /* Receive Overflow */
++#define IS_RCV_CRC_ERR(X) (((X) & (1<<ETHRX_crc_b)) >> ETHRX_crc_b) /* CRC Error */
++#define IS_RCV_CV_ERR(X) (((X) & (1<<ETHRX_cv_b)) >> ETHRX_cv_b) /* Code Violation */
++#define IS_RCV_DB_ERR(X) (((X) & (1<<ETHRX_db_b)) >> ETHRX_db_b) /* Dribble Bits */
++#define IS_RCV_LE_ERR(X) (((X) & (1<<ETHRX_le_b)) >> ETHRX_le_b) /* Length error */
++#define IS_RCV_LOR_ERR(X) (((X) & (1<<ETHRX_lor_b)) >> ETHRX_lor_b) /* Length Out of Range */
++#define IS_RCV_CES_ERR(X) (((X) & (1<<ETHRX_ces_b)) >> ETHRX_ces_b) /* Preamble error */
++#define RCVPKT_LENGTH(X) (((X) & ETHRX_length_m) >> ETHRX_length_b) /* Length of the received packet */
++#endif // __IDT_ETH_V_H__
++
++
++
++
++
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_gpio.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_gpio.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_gpio.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_gpio.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,167 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * GPIO register definition
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_GPIO_H__
++#define __IDT_GPIO_H__
++
++enum
++{
++ GPIO0_PhysicalAddress = 0x18050000,
++ GPIO_PhysicalAddress = GPIO0_PhysicalAddress, // Default
++
++ GPIO0_VirtualAddress = 0xb8050000,
++ GPIO_VirtualAddress = GPIO0_VirtualAddress, // Default
++} ;
++
++typedef struct
++{
++ u32 gpiofunc; /* GPIO Function Register
++ * gpiofunc[x]==0 bit = gpio
++ * func[x]==1 bit = altfunc
++ */
++ u32 gpiocfg; /* GPIO Configuration Register
++ * gpiocfg[x]==0 bit = input
++ * gpiocfg[x]==1 bit = output
++ */
++ u32 gpiod; /* GPIO Data Register
++ * gpiod[x] read/write gpio pinX status
++ */
++ u32 gpioilevel; /* GPIO Interrupt Status Register
++ * interrupt level (see gpioistat)
++ */
++ u32 gpioistat; /* Gpio Interrupt Status Register
++ * istat[x] = (gpiod[x] == level[x])
++ * cleared in ISR (STICKY bits)
++ */
++ u32 gpionmien; /* GPIO Non-maskable Interrupt Enable Register */
++} volatile * GPIO_t ;
++
++typedef enum
++{
++ GPIO_gpio_v = 0, // gpiofunc use pin as GPIO.
++ GPIO_alt_v = 1, // gpiofunc use pin as alt.
++ GPIO_input_v = 0, // gpiocfg use pin as input.
++ GPIO_output_v = 1, // gpiocfg use pin as output.
++ GPIO_pin0_b = 0,
++ GPIO_pin0_m = 0x00000001,
++ GPIO_pin1_b = 1,
++ GPIO_pin1_m = 0x00000002,
++ GPIO_pin2_b = 2,
++ GPIO_pin2_m = 0x00000004,
++ GPIO_pin3_b = 3,
++ GPIO_pin3_m = 0x00000008,
++ GPIO_pin4_b = 4,
++ GPIO_pin4_m = 0x00000010,
++ GPIO_pin5_b = 5,
++ GPIO_pin5_m = 0x00000020,
++ GPIO_pin6_b = 6,
++ GPIO_pin6_m = 0x00000040,
++ GPIO_pin7_b = 7,
++ GPIO_pin7_m = 0x00000080,
++ GPIO_pin8_b = 8,
++ GPIO_pin8_m = 0x00000100,
++ GPIO_pin9_b = 9,
++ GPIO_pin9_m = 0x00000200,
++ GPIO_pin10_b = 10,
++ GPIO_pin10_m = 0x00000400,
++ GPIO_pin11_b = 11,
++ GPIO_pin11_m = 0x00000800,
++ GPIO_pin12_b = 12,
++ GPIO_pin12_m = 0x00001000,
++ GPIO_pin13_b = 13,
++ GPIO_pin13_m = 0x00002000,
++
++// Alternate function pins. Corrsponding gpiofunc bit set to GPIO_alt_v.
++
++ GPIO_u0sout_b = GPIO_pin0_b, // UART 0 serial out.
++ GPIO_u0sout_m = GPIO_pin0_m,
++ GPIO_u0sout_cfg_v = GPIO_output_v,
++ GPIO_u0sinp_b = GPIO_pin1_b, // UART 0 serial in.
++ GPIO_u0sinp_m = GPIO_pin1_m,
++ GPIO_u0sinp_cfg_v = GPIO_input_v,
++ GPIO_u0rtsn_b = GPIO_pin2_b, // UART 0 req. to send.
++ GPIO_u0rtsn_m = GPIO_pin2_m,
++ GPIO_u0rtsn_cfg_v = GPIO_output_v,
++ GPIO_u0ctsn_b = GPIO_pin3_b, // UART 0 clear to send.
++ GPIO_u0ctsn_m = GPIO_pin3_m,
++ GPIO_u0ctsn_cfg_v = GPIO_input_v,
++
++ GPIO_maddr22_b = GPIO_pin4_b, // M&P bus bit 22.
++ GPIO_maddr22_m = GPIO_pin4_m,
++ GPIO_maddr22_cfg_v = GPIO_output_v,
++
++ GPIO_maddr23_b = GPIO_pin5_b, // M&P bus bit 23.
++ GPIO_maddr23_m = GPIO_pin5_m,
++ GPIO_maddr23_cfg_v = GPIO_output_v,
++
++ GPIO_maddr24_b = GPIO_pin6_b, // M&P bus bit 24.
++ GPIO_maddr24_m = GPIO_pin6_m,
++ GPIO_maddr24_cfg_v = GPIO_output_v,
++
++ GPIO_maddr25_b = GPIO_pin7_b, // M&P bus bit 25.
++ GPIO_maddr25_m = GPIO_pin7_m,
++ GPIO_maddr25_cfg_v = GPIO_output_v,
++
++ GPIO_cpudmadebug_b = GPIO_pin8_b, // CPU or DMA debug pin
++ GPIO_cpudmadebug_m = GPIO_pin8_m,
++ GPIO_cpudmadebug_cfg_v = GPIO_output_v,
++
++ GPIO_pcireq4_b = GPIO_pin9_b, // PCI Request 4
++ GPIO_pcireq4_m = GPIO_pin9_m,
++ GPIO_pcireq4_cfg_v = GPIO_input_v,
++
++ GPIO_pcigrant4_b = GPIO_pin10_b, // PCI Grant 4
++ GPIO_pcigrant4_m = GPIO_pin10_m,
++ GPIO_pcigrant4_cfg_v = GPIO_output_v,
++
++ GPIO_pcireq5_b = GPIO_pin11_b, // PCI Request 5
++ GPIO_pcireq5_m = GPIO_pin11_m,
++ GPIO_pcireq5_cfg_v = GPIO_input_v,
++
++ GPIO_pcigrant5_b = GPIO_pin12_b, // PCI Grant 5
++ GPIO_pcigrant5_m = GPIO_pin12_m,
++ GPIO_pcigrant5_cfg_v = GPIO_output_v,
++
++ GPIO_pcimuintn_b = GPIO_pin13_b, // PCI messaging int.
++ GPIO_pcimuintn_m = GPIO_pin13_m,
++ GPIO_pcimuintn_cfg_v = GPIO_output_v,
++
++} GPIO_DEFS_t;
++
++#endif // __IDT_GPIO_H__
++
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,199 @@
++ /**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Definitions for IDT RC32434 CPU
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef _RC32434_H_
++#define _RC32434_H_
++
++#include <linux/config.h>
++#include <linux/delay.h>
++#include <asm/io.h>
++#include <asm/idt-boards/rc32434/rc32434_timer.h>
++
++#define RC32434_REG_BASE 0x18000000
++
++
++#define interrupt ((volatile INT_t ) INT0_VirtualAddress)
++#define idt_timer ((volatile TIM_t) TIM0_VirtualAddress)
++#define idt_gpio ((volatile GPIO_t) GPIO0_VirtualAddress)
++
++#define IDT_CLOCK_MULT 2
++#define MIPS_CPU_TIMER_IRQ 7
++/* Interrupt Controller */
++#define IC_GROUP0_PEND (RC32434_REG_BASE + 0x38000)
++#define IC_GROUP0_MASK (RC32434_REG_BASE + 0x38008)
++#define IC_GROUP_OFFSET 0x0C
++#define RTC_BASE 0xBA001FF0
++
++#define NUM_INTR_GROUPS 5
++/* 16550 UARTs */
++
++#define GROUP0_IRQ_BASE 8 /* GRP2 IRQ numbers start here */
++#define GROUP1_IRQ_BASE (GROUP0_IRQ_BASE + 32) /* GRP3 IRQ numbers start here */
++#define GROUP2_IRQ_BASE (GROUP1_IRQ_BASE + 32) /* GRP4 IRQ numbers start here */
++#define GROUP3_IRQ_BASE (GROUP2_IRQ_BASE + 32) /* GRP5 IRQ numbers start here */
++#define GROUP4_IRQ_BASE (GROUP3_IRQ_BASE + 32)
++
++#ifdef __MIPSEB__
++
++#define RC32434_UART0_BASE (RC32434_REG_BASE + 0x58003)
++#define EB434_UART1_BASE (0x19800003)
++
++#else
++
++#define RC32434_UART0_BASE (RC32434_REG_BASE + 0x58000)
++#define EB434_UART1_BASE (0x19800000)
++
++#endif
++
++#define RC32434_UART0_IRQ GROUP3_IRQ_BASE + 0
++#define EB434_UART1_IRQ GROUP4_IRQ_BASE + 11
++
++#define RC32434_NR_IRQS (GROUP4_IRQ_BASE + 32)
++
++/* cpu pipeline flush */
++static inline void rc32434_sync(void)
++{
++ __asm__ volatile ("sync");
++}
++
++static inline void rc32434_sync_udelay(int us)
++{
++ __asm__ volatile ("sync");
++ udelay(us);
++}
++
++static inline void rc32434_sync_delay(int ms)
++{
++ __asm__ volatile ("sync");
++ mdelay(ms);
++}
++
++
++
++/*
++ * Macros to access internal RC32434 registers. No byte
++ * swapping should be done when accessing the internal
++ * registers.
++ */
++
++#define rc32434_readb __raw_readb
++#define rc32434_readw __raw_readw
++#define rc32434_readl __raw_readl
++
++#define rc32434_writeb __raw_writeb
++#define rc32434_writew __raw_writew
++#define rc32434_writel __raw_writel
++
++#if 0
++static inline u8 rc32434_readb(unsigned long pa)
++{
++ return *((volatile u8 *)KSEG1ADDR(pa));
++}
++static inline u16 rc32434_readw(unsigned long pa)
++{
++ return *((volatile u16 *)KSEG1ADDR(pa));
++}
++static inline u32 rc32434_readl(unsigned long pa)
++{
++ return *((volatile u32 *)KSEG1ADDR(pa));
++}
++static inline void rc32434_writeb(u8 val, unsigned long pa)
++{
++ *((volatile u8 *)KSEG1ADDR(pa)) = val;
++}
++static inline void rc32434_writew(u16 val, unsigned long pa)
++{
++ *((volatile u16 *)KSEG1ADDR(pa)) = val;
++}
++static inline void rc32434_writel(u32 val, unsigned long pa)
++{
++ *((volatile u32 *)KSEG1ADDR(pa)) = val;
++}
++
++#endif
++
++
++/*
++ * C access to CLZ and CLO instructions
++ * (count leading zeroes/ones).
++ */
++static inline int rc32434_clz(unsigned long val)
++{
++ int ret;
++ __asm__ volatile (
++ ".set\tnoreorder\n\t"
++ ".set\tnoat\n\t"
++ ".set\tmips32\n\t"
++ "clz\t%0,%1\n\t"
++ ".set\tmips0\n\t"
++ ".set\tat\n\t"
++ ".set\treorder"
++ : "=r" (ret)
++ : "r" (val));
++
++ return ret;
++}
++static inline int rc32434_clo(unsigned long val)
++{
++ int ret;
++ __asm__ volatile (
++ ".set\tnoreorder\n\t"
++ ".set\tnoat\n\t"
++ ".set\tmips32\n\t"
++ "clo\t%0,%1\n\t"
++ ".set\tmips0\n\t"
++ ".set\tat\n\t"
++ ".set\treorder"
++ : "=r" (ret)
++ : "r" (val));
++
++ return ret;
++}
++#endif /* _RC32434_H_ */
++
++
++
++
++
++
++
++
++
++
++
++
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_integ.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_integ.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_integ.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_integ.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,90 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * System Integrity register definition
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_INTEG_H__
++#define __IDT_INTEG_H__
++
++enum
++{
++ INTEG0_PhysicalAddress = 0x18030000,
++ INTEG_PhysicalAddress = INTEG0_PhysicalAddress, // Default
++
++ INTEG0_VirtualAddress = 0xB8030000,
++ INTEG_VirtualAddress = INTEG0_VirtualAddress, // Default
++} ;
++
++// if you are looking for CEA, try rst.h
++typedef struct
++{
++ u32 filler [0xc] ; // 0x30 bytes unused.
++ u32 errcs ; // sticky use ERRCS_
++ u32 wtcount ; // Watchdog timer count reg.
++ u32 wtcompare ; // Watchdog timer timeout value.
++ u32 wtc ; // Watchdog timer control. use WTC_
++} volatile *INTEG_t ;
++
++enum
++{
++ ERRCS_wto_b = 0, // In INTEG_t -> errcs
++ ERRCS_wto_m = 0x00000001,
++ ERRCS_wne_b = 1, // In INTEG_t -> errcs
++ ERRCS_wne_m = 0x00000002,
++ ERRCS_ucw_b = 2, // In INTEG_t -> errcs
++ ERRCS_ucw_m = 0x00000004,
++ ERRCS_ucr_b = 3, // In INTEG_t -> errcs
++ ERRCS_ucr_m = 0x00000008,
++ ERRCS_upw_b = 4, // In INTEG_t -> errcs
++ ERRCS_upw_m = 0x00000010,
++ ERRCS_upr_b = 5, // In INTEG_t -> errcs
++ ERRCS_upr_m = 0x00000020,
++ ERRCS_udw_b = 6, // In INTEG_t -> errcs
++ ERRCS_udw_m = 0x00000040,
++ ERRCS_udr_b = 7, // In INTEG_t -> errcs
++ ERRCS_udr_m = 0x00000080,
++ ERRCS_sae_b = 8, // In INTEG_t -> errcs
++ ERRCS_sae_m = 0x00000100,
++ ERRCS_wre_b = 9, // In INTEG_t -> errcs
++ ERRCS_wre_m = 0x00000200,
++
++ WTC_en_b = 0, // In INTEG_t -> wtc
++ WTC_en_m = 0x00000001,
++ WTC_to_b = 1, // In INTEG_t -> wtc
++ WTC_to_m = 0x00000002,
++} ;
++
++#endif // __IDT_INTEG_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_int.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_int.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_int.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_int.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,174 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Interrupt Controller register definition.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_INT_H__
++#define __IDT_INT_H__
++
++enum
++{
++ INT0_PhysicalAddress = 0x18038000,
++ INT_PhysicalAddress = INT0_PhysicalAddress, // Default
++
++ INT0_VirtualAddress = 0xB8038000,
++ INT_VirtualAddress = INT0_VirtualAddress, // Default
++} ;
++
++struct INT_s
++{
++ u32 ipend ; //Pending interrupts. use INT?_
++ u32 itest ; //Test bits. use INT?_
++ u32 imask ; //Interrupt disabled when set. use INT?_
++} ;
++
++enum
++{
++ IPEND2 = 0, // HW 2 interrupt to core. use INT2_
++ IPEND3 = 1, // HW 3 interrupt to core. use INT3_
++ IPEND4 = 2, // HW 4 interrupt to core. use INT4_
++ IPEND5 = 3, // HW 5 interrupt to core. use INT5_
++ IPEND6 = 4, // HW 6 interrupt to core. use INT6_
++
++ IPEND_count, // must be last (used in loops)
++ IPEND_min = IPEND2 // min IPEND (used in loops)
++};
++
++typedef struct INTC_s
++{
++ struct INT_s i [IPEND_count] ;// use i[IPEND?] = INT?_
++ u32 nmips ; // use NMIPS_
++} volatile *INT_t ;
++
++enum
++{
++ INT2_timer0_b = 0,
++ INT2_timer0_m = 0x00000001,
++ INT2_timer1_b = 1,
++ INT2_timer1_m = 0x00000002,
++ INT2_timer2_b = 2,
++ INT2_timer2_m = 0x00000004,
++ INT2_refresh_b = 3,
++ INT2_refresh_m = 0x00000008,
++ INT2_watchdogTimeout_b = 4,
++ INT2_watchdogTimeout_m = 0x00000010,
++ INT2_undecodedCpuWrite_b = 5,
++ INT2_undecodedCpuWrite_m = 0x00000020,
++ INT2_undecodedCpuRead_b = 6,
++ INT2_undecodedCpuRead_m = 0x00000040,
++ INT2_undecodedPciWrite_b = 7,
++ INT2_undecodedPciWrite_m = 0x00000080,
++ INT2_undecodedPciRead_b = 8,
++ INT2_undecodedPciRead_m = 0x00000100,
++ INT2_undecodedDmaWrite_b = 9,
++ INT2_undecodedDmaWrite_m = 0x00000200,
++ INT2_undecodedDmaRead_b = 10,
++ INT2_undecodedDmaRead_m = 0x00000400,
++ INT2_ipBusSlaveAckError_b = 11,
++ INT2_ipBusSlaveAckError_m = 0x00000800,
++
++ INT3_dmaChannel0_b = 0,
++ INT3_dmaChannel0_m = 0x00000001,
++ INT3_dmaChannel1_b = 1,
++ INT3_dmaChannel1_m = 0x00000002,
++ INT3_dmaChannel2_b = 2,
++ INT3_dmaChannel2_m = 0x00000004,
++ INT3_dmaChannel3_b = 3,
++ INT3_dmaChannel3_m = 0x00000008,
++ INT3_dmaChannel4_b = 4,
++ INT3_dmaChannel4_m = 0x00000010,
++ INT3_dmaChannel5_b = 5,
++ INT3_dmaChannel5_m = 0x00000020,
++
++ INT5_uartGeneral0_b = 0,
++ INT5_uartGeneral0_m = 0x00000001,
++ INT5_uartTxrdy0_b = 1,
++ INT5_uartTxrdy0_m = 0x00000002,
++ INT5_uartRxrdy0_b = 2,
++ INT5_uartRxrdy0_m = 0x00000004,
++ INT5_pci_b = 3,
++ INT5_pci_m = 0x00000008,
++ INT5_pciDecoupled_b = 4,
++ INT5_pciDecoupled_m = 0x00000010,
++ INT5_spi_b = 5,
++ INT5_spi_m = 0x00000020,
++ INT5_deviceDecoupled_b = 6,
++ INT5_deviceDecoupled_m = 0x00000040,
++ INT5_eth0Ovr_b = 9,
++ INT5_eth0Ovr_m = 0x00000200,
++ INT5_eth0Und_b = 10,
++ INT5_eth0Und_m = 0x00000400,
++ INT5_eth0Pfd_b = 11,
++ INT5_eth0Pfd_m = 0x00000800,
++ INT5_nvram_b = 12,
++ INT5_nvram_m = 0x00001000,
++
++ INT6_gpio0_b = 0,
++ INT6_gpio0_m = 0x00000001,
++ INT6_gpio1_b = 1,
++ INT6_gpio1_m = 0x00000002,
++ INT6_gpio2_b = 2,
++ INT6_gpio2_m = 0x00000004,
++ INT6_gpio3_b = 3,
++ INT6_gpio3_m = 0x00000008,
++ INT6_gpio4_b = 4,
++ INT6_gpio4_m = 0x00000010,
++ INT6_gpio5_b = 5,
++ INT6_gpio5_m = 0x00000020,
++ INT6_gpio6_b = 6,
++ INT6_gpio6_m = 0x00000040,
++ INT6_gpio7_b = 7,
++ INT6_gpio7_m = 0x00000080,
++ INT6_gpio8_b = 8,
++ INT6_gpio8_m = 0x00000100,
++ INT6_gpio9_b = 9,
++ INT6_gpio9_m = 0x00000200,
++ INT6_gpio10_b = 10,
++ INT6_gpio10_m = 0x00000400,
++ INT6_gpio11_b = 11,
++ INT6_gpio11_m = 0x00000800,
++ INT6_gpio12_b = 12,
++ INT6_gpio12_m = 0x00001000,
++ INT6_gpio13_b = 13,
++ INT6_gpio13_m = 0x00002000,
++
++ NMIPS_gpio_b = 0,
++ NMIPS_gpio_m = 0x00000001,
++} ;
++
++#endif // __IDT_INT_H__
++
++
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_iparb.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_iparb.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_iparb.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_iparb.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,111 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * IP Arbiter register definitions
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt,neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_IPARB_H__
++#define __IDT_IPARB_H__
++
++enum
++{
++ IPARB0_PhysicalAddress = 0x18048000,
++ IPARB_PhysicalAddress = IPARB0_PhysicalAddress, // Default
++
++ IPARB0_VirtualAddress = 0xB8048000,
++ IPARB_VirtualAddress = IPARB0_VirtualAddress, // Default
++} ;
++
++enum
++{
++ IPABMXC_ethernet0Receive = 0,
++ IPABMXC_ethernet0Transmit = 1,
++ IPABMXC_memoryToHoldFifo = 2,
++ IPABMXC_holdFifoToMemory = 3,
++ IPABMXC_pciToMemory = 4,
++ IPABMXC_memoryToPci = 5,
++ IPABMXC_pciTarget = 6,
++ IPABMXC_pciTargetStart = 7,
++ IPABMXC_cpuToIpBus = 8,
++
++ IPABMXC_Count, // Must be last in list !
++ IPABMXC_Min = IPABMXC_ethernet0Receive,
++
++ IPAPXC_PriorityCount = 4, // 3-highest, 0-lowest.
++} ;
++
++typedef struct
++{
++ u32 ipapc [IPAPXC_PriorityCount] ; // ipapc[IPAPXC_] = IPAPC_
++ u32 ipabmc [IPABMXC_Count] ; // ipabmc[IPABMXC_] = IPABMC_
++ u32 ipac ; // use IPAC_
++ u32 ipaitcc; // use IPAITCC_
++ u32 ipaspare ;
++} volatile * IPARB_t ;
++
++enum
++{
++ IPAC_dp_b = 0,
++ IPAC_dp_m = 0x00000001,
++ IPAC_dep_b = 1,
++ IPAC_dep_m = 0x00000002,
++ IPAC_drm_b = 2,
++ IPAC_drm_m = 0x00000004,
++ IPAC_dwm_b = 3,
++ IPAC_dwm_m = 0x00000008,
++ IPAC_msk_b = 4,
++ IPAC_msk_m = 0x00000010,
++
++ IPAPC_ptc_b = 0,
++ IPAPC_ptc_m = 0x00003fff,
++ IPAPC_mf_b = 14,
++ IPAPC_mf_m = 0x00004000,
++ IPAPC_cptc_b = 16,
++ IPAPC_cptc_m = 0x3fff0000,
++
++ IPAITCC_itcc = 0,
++ IPAITCC_itcc, = 0x000001ff,
++
++ IPABMC_mtc_b = 0,
++ IPABMC_mtc_m = 0x00000fff,
++ IPABMC_p_b = 12,
++ IPABMC_p_m = 0x00003000,
++ IPABMC_msk_b = 14,
++ IPABMC_msk_m = 0x00004000,
++ IPABMC_cmtc_b = 16,
++ IPABMC_cmtc_m = 0x0fff0000,
++};
++
++#endif // __IDT_IPARB_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_pci.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_pci.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_pci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_pci.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,695 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * PCI register definitio
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_PCI_H__
++#define __IDT_PCI_H__
++
++enum
++{
++ PCI0_PhysicalAddress = 0x18080000,
++ PCI_PhysicalAddress = PCI0_PhysicalAddress,
++
++ PCI0_VirtualAddress = 0xB8080000,
++ PCI_VirtualAddress = PCI0_VirtualAddress,
++} ;
++
++enum
++{
++ PCI_LbaCount = 4, // Local base addresses.
++} ;
++
++typedef struct
++{
++ u32 a ; // Address.
++ u32 c ; // Control.
++ u32 m ; // mapping.
++} PCI_Map_s ;
++
++typedef struct
++{
++ u32 pcic ;
++ u32 pcis ;
++ u32 pcism ;
++ u32 pcicfga ;
++ u32 pcicfgd ;
++ PCI_Map_s pcilba [PCI_LbaCount] ;
++ u32 pcidac ;
++ u32 pcidas ;
++ u32 pcidasm ;
++ u32 pcidad ;
++ u32 pcidma8c ;
++ u32 pcidma9c ;
++ u32 pcitc ;
++} volatile *PCI_t ;
++
++// PCI messaging unit.
++enum
++{
++ PCIM_Count = 2,
++} ;
++typedef struct
++{
++ u32 pciim [PCIM_Count] ;
++ u32 pciom [PCIM_Count] ;
++ u32 pciid ;
++ u32 pciiic ;
++ u32 pciiim ;
++ u32 pciiod ;
++ u32 pciioic ;
++ u32 pciioim ;
++} volatile *PCIM_t ;
++
++/*******************************************************************************
++ *
++ * PCI Control Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCIC_en_b = 0,
++ PCIC_en_m = 0x00000001,
++ PCIC_tnr_b = 1,
++ PCIC_tnr_m = 0x00000002,
++ PCIC_sce_b = 2,
++ PCIC_sce_m = 0x00000004,
++ PCIC_ien_b = 3,
++ PCIC_ien_m = 0x00000008,
++ PCIC_aaa_b = 4,
++ PCIC_aaa_m = 0x00000010,
++ PCIC_eap_b = 5,
++ PCIC_eap_m = 0x00000020,
++ PCIC_pcim_b = 6,
++ PCIC_pcim_m = 0x000001c0,
++ PCIC_pcim_disabled_v = 0,
++ PCIC_pcim_tnr_v = 1, // Satellite - target not ready
++ PCIC_pcim_suspend_v = 2, // Satellite - suspended CPU.
++ PCIC_pcim_extern_v = 3, // Host - external arbiter.
++ PCIC_pcim_fixed_v = 4, // Host - fixed priority arb.
++ PCIC_pcim_roundrobin_v = 5, // Host - round robin priority.
++ PCIC_pcim_reserved6_v = 6,
++ PCIC_pcim_reserved7_v = 7,
++ PCIC_igm_b = 9,
++ PCIC_igm_m = 0x00000200,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Status Register
++ *
++ ******************************************************************************/
++enum {
++ PCIS_eed_b = 0,
++ PCIS_eed_m = 0x00000001,
++ PCIS_wr_b = 1,
++ PCIS_wr_m = 0x00000002,
++ PCIS_nmi_b = 2,
++ PCIS_nmi_m = 0x00000004,
++ PCIS_ii_b = 3,
++ PCIS_ii_m = 0x00000008,
++ PCIS_cwe_b = 4,
++ PCIS_cwe_m = 0x00000010,
++ PCIS_cre_b = 5,
++ PCIS_cre_m = 0x00000020,
++ PCIS_mdpe_b = 6,
++ PCIS_mdpe_m = 0x00000040,
++ PCIS_sta_b = 7,
++ PCIS_sta_m = 0x00000080,
++ PCIS_rta_b = 8,
++ PCIS_rta_m = 0x00000100,
++ PCIS_rma_b = 9,
++ PCIS_rma_m = 0x00000200,
++ PCIS_sse_b = 10,
++ PCIS_sse_m = 0x00000400,
++ PCIS_ose_b = 11,
++ PCIS_ose_m = 0x00000800,
++ PCIS_pe_b = 12,
++ PCIS_pe_m = 0x00001000,
++ PCIS_tae_b = 13,
++ PCIS_tae_m = 0x00002000,
++ PCIS_rle_b = 14,
++ PCIS_rle_m = 0x00004000,
++ PCIS_bme_b = 15,
++ PCIS_bme_m = 0x00008000,
++ PCIS_prd_b = 16,
++ PCIS_prd_m = 0x00010000,
++ PCIS_rip_b = 17,
++ PCIS_rip_m = 0x00020000,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Status Mask Register
++ *
++ ******************************************************************************/
++enum {
++ PCISM_eed_b = 0,
++ PCISM_eed_m = 0x00000001,
++ PCISM_wr_b = 1,
++ PCISM_wr_m = 0x00000002,
++ PCISM_nmi_b = 2,
++ PCISM_nmi_m = 0x00000004,
++ PCISM_ii_b = 3,
++ PCISM_ii_m = 0x00000008,
++ PCISM_cwe_b = 4,
++ PCISM_cwe_m = 0x00000010,
++ PCISM_cre_b = 5,
++ PCISM_cre_m = 0x00000020,
++ PCISM_mdpe_b = 6,
++ PCISM_mdpe_m = 0x00000040,
++ PCISM_sta_b = 7,
++ PCISM_sta_m = 0x00000080,
++ PCISM_rta_b = 8,
++ PCISM_rta_m = 0x00000100,
++ PCISM_rma_b = 9,
++ PCISM_rma_m = 0x00000200,
++ PCISM_sse_b = 10,
++ PCISM_sse_m = 0x00000400,
++ PCISM_ose_b = 11,
++ PCISM_ose_m = 0x00000800,
++ PCISM_pe_b = 12,
++ PCISM_pe_m = 0x00001000,
++ PCISM_tae_b = 13,
++ PCISM_tae_m = 0x00002000,
++ PCISM_rle_b = 14,
++ PCISM_rle_m = 0x00004000,
++ PCISM_bme_b = 15,
++ PCISM_bme_m = 0x00008000,
++ PCISM_prd_b = 16,
++ PCISM_prd_m = 0x00010000,
++ PCISM_rip_b = 17,
++ PCISM_rip_m = 0x00020000,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Configuration Address Register
++ *
++ ******************************************************************************/
++enum {
++ PCICFGA_reg_b = 2,
++ PCICFGA_reg_m = 0x000000fc,
++ PCICFGA_reg_id_v = 0x00>>2, //use PCFGID_
++ PCICFGA_reg_04_v = 0x04>>2, //use PCFG04_
++ PCICFGA_reg_08_v = 0x08>>2, //use PCFG08_
++ PCICFGA_reg_0C_v = 0x0C>>2, //use PCFG0C_
++ PCICFGA_reg_pba0_v = 0x10>>2, //use PCIPBA_
++ PCICFGA_reg_pba1_v = 0x14>>2, //use PCIPBA_
++ PCICFGA_reg_pba2_v = 0x18>>2, //use PCIPBA_
++ PCICFGA_reg_pba3_v = 0x1c>>2, //use PCIPBA_
++ PCICFGA_reg_subsystem_v = 0x2c>>2, //use PCFGSS_
++ PCICFGA_reg_3C_v = 0x3C>>2, //use PCFG3C_
++ PCICFGA_reg_pba0c_v = 0x44>>2, //use PCIPBAC_
++ PCICFGA_reg_pba0m_v = 0x48>>2,
++ PCICFGA_reg_pba1c_v = 0x4c>>2, //use PCIPBAC_
++ PCICFGA_reg_pba1m_v = 0x50>>2,
++ PCICFGA_reg_pba2c_v = 0x54>>2, //use PCIPBAC_
++ PCICFGA_reg_pba2m_v = 0x58>>2,
++ PCICFGA_reg_pba3c_v = 0x5c>>2, //use PCIPBAC_
++ PCICFGA_reg_pba3m_v = 0x60>>2,
++ PCICFGA_reg_pmgt_v = 0x64>>2,
++ PCICFGA_func_b = 8,
++ PCICFGA_func_m = 0x00000700,
++ PCICFGA_dev_b = 11,
++ PCICFGA_dev_m = 0x0000f800,
++ PCICFGA_dev_internal_v = 0,
++ PCICFGA_bus_b = 16,
++ PCICFGA_bus_m = 0x00ff0000,
++ PCICFGA_bus_type0_v = 0, //local bus
++ PCICFGA_en_b = 31, // read only
++ PCICFGA_en_m = 0x80000000,
++} ;
++
++enum {
++ PCFGID_vendor_b = 0,
++ PCFGID_vendor_m = 0x0000ffff,
++ PCFGID_vendor_IDT_v = 0x111d,
++ PCFGID_device_b = 16,
++ PCFGID_device_m = 0xffff0000,
++ PCFGID_device_Korinade_v = 0x0214,
++
++ PCFG04_command_ioena_b = 1,
++ PCFG04_command_ioena_m = 0x00000001,
++ PCFG04_command_memena_b = 2,
++ PCFG04_command_memena_m = 0x00000002,
++ PCFG04_command_bmena_b = 3,
++ PCFG04_command_bmena_m = 0x00000004,
++ PCFG04_command_mwinv_b = 5,
++ PCFG04_command_mwinv_m = 0x00000010,
++ PCFG04_command_parena_b = 7,
++ PCFG04_command_parena_m = 0x00000040,
++ PCFG04_command_serrena_b = 9,
++ PCFG04_command_serrena_m = 0x00000100,
++ PCFG04_command_fastbbena_b = 10,
++ PCFG04_command_fastbbena_m = 0x00000200,
++ PCFG04_status_b = 16,
++ PCFG04_status_m = 0xffff0000,
++ PCFG04_status_66MHz_b = 21, // 66 MHz enable
++ PCFG04_status_66MHz_m = 0x00200000,
++ PCFG04_status_fbb_b = 23,
++ PCFG04_status_fbb_m = 0x00800000,
++ PCFG04_status_mdpe_b = 24,
++ PCFG04_status_mdpe_m = 0x01000000,
++ PCFG04_status_dst_b = 25,
++ PCFG04_status_dst_m = 0x06000000,
++ PCFG04_status_sta_b = 27,
++ PCFG04_status_sta_m = 0x08000000,
++ PCFG04_status_rta_b = 28,
++ PCFG04_status_rta_m = 0x10000000,
++ PCFG04_status_rma_b = 29,
++ PCFG04_status_rma_m = 0x20000000,
++ PCFG04_status_sse_b = 30,
++ PCFG04_status_sse_m = 0x40000000,
++ PCFG04_status_pe_b = 31,
++ PCFG04_status_pe_m = 0x40000000,
++
++ PCFG08_revId_b = 0,
++ PCFG08_revId_m = 0x000000ff,
++ PCFG08_classCode_b = 0,
++ PCFG08_classCode_m = 0xffffff00,
++ PCFG08_classCode_bridge_v = 06,
++ PCFG08_classCode_proc_v = 0x0b3000, // processor-MIPS
++ PCFG0C_cacheline_b = 0,
++ PCFG0C_cacheline_m = 0x000000ff,
++ PCFG0C_masterLatency_b = 8,
++ PCFG0C_masterLatency_m = 0x0000ff00,
++ PCFG0C_headerType_b = 16,
++ PCFG0C_headerType_m = 0x00ff0000,
++ PCFG0C_bist_b = 24,
++ PCFG0C_bist_m = 0xff000000,
++
++ PCIPBA_msi_b = 0,
++ PCIPBA_msi_m = 0x00000001,
++ PCIPBA_p_b = 3,
++ PCIPBA_p_m = 0x00000004,
++ PCIPBA_baddr_b = 8,
++ PCIPBA_baddr_m = 0xffffff00,
++
++ PCFGSS_vendorId_b = 0,
++ PCFGSS_vendorId_m = 0x0000ffff,
++ PCFGSS_id_b = 16,
++ PCFGSS_id_m = 0xffff0000,
++
++ PCFG3C_interruptLine_b = 0,
++ PCFG3C_interruptLine_m = 0x000000ff,
++ PCFG3C_interruptPin_b = 8,
++ PCFG3C_interruptPin_m = 0x0000ff00,
++ PCFG3C_minGrant_b = 16,
++ PCFG3C_minGrant_m = 0x00ff0000,
++ PCFG3C_maxLat_b = 24,
++ PCFG3C_maxLat_m = 0xff000000,
++
++ PCIPBAC_msi_b = 0,
++ PCIPBAC_msi_m = 0x00000001,
++ PCIPBAC_p_b = 1,
++ PCIPBAC_p_m = 0x00000002,
++ PCIPBAC_size_b = 2,
++ PCIPBAC_size_m = 0x0000007c,
++ PCIPBAC_sb_b = 7,
++ PCIPBAC_sb_m = 0x00000080,
++ PCIPBAC_pp_b = 8,
++ PCIPBAC_pp_m = 0x00000100,
++ PCIPBAC_mr_b = 9,
++ PCIPBAC_mr_m = 0x00000600,
++ PCIPBAC_mr_read_v =0, //no prefetching
++ PCIPBAC_mr_readLine_v =1,
++ PCIPBAC_mr_readMult_v =2,
++ PCIPBAC_mrl_b = 11,
++ PCIPBAC_mrl_m = 0x00000800,
++ PCIPBAC_mrm_b = 12,
++ PCIPBAC_mrm_m = 0x00001000,
++ PCIPBAC_trp_b = 13,
++ PCIPBAC_trp_m = 0x00002000,
++
++ PCFG40_trdyTimeout_b = 0,
++ PCFG40_trdyTimeout_m = 0x000000ff,
++ PCFG40_retryLim_b = 8,
++ PCFG40_retryLim_m = 0x0000ff00,
++};
++
++/*******************************************************************************
++ *
++ * PCI Local Base Address [0|1|2|3] Register
++ *
++ ******************************************************************************/
++enum {
++ PCILBA_baddr_b = 0, // In PCI_t -> pcilba [] .a
++ PCILBA_baddr_m = 0xffffff00,
++} ;
++/*******************************************************************************
++ *
++ * PCI Local Base Address Control Register
++ *
++ ******************************************************************************/
++enum {
++ PCILBAC_msi_b = 0, // In pPci->pcilba[i].c
++ PCILBAC_msi_m = 0x00000001,
++ PCILBAC_msi_mem_v = 0,
++ PCILBAC_msi_io_v = 1,
++ PCILBAC_size_b = 2, // In pPci->pcilba[i].c
++ PCILBAC_size_m = 0x0000007c,
++ PCILBAC_sb_b = 7, // In pPci->pcilba[i].c
++ PCILBAC_sb_m = 0x00000080,
++ PCILBAC_rt_b = 8, // In pPci->pcilba[i].c
++ PCILBAC_rt_m = 0x00000100,
++ PCILBAC_rt_noprefetch_v = 0, // mem read
++ PCILBAC_rt_prefetch_v = 1, // mem readline
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Local Base Address [0|1|2|3] Mapping Register
++ *
++ ******************************************************************************/
++enum {
++ PCILBAM_maddr_b = 8,
++ PCILBAM_maddr_m = 0xffffff00,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Decoupled Access Control Register
++ *
++ ******************************************************************************/
++enum {
++ PCIDAC_den_b = 0,
++ PCIDAC_den_m = 0x00000001,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Decoupled Access Status Register
++ *
++ ******************************************************************************/
++enum {
++ PCIDAS_d_b = 0,
++ PCIDAS_d_m = 0x00000001,
++ PCIDAS_b_b = 1,
++ PCIDAS_b_m = 0x00000002,
++ PCIDAS_e_b = 2,
++ PCIDAS_e_m = 0x00000004,
++ PCIDAS_ofe_b = 3,
++ PCIDAS_ofe_m = 0x00000008,
++ PCIDAS_off_b = 4,
++ PCIDAS_off_m = 0x00000010,
++ PCIDAS_ife_b = 5,
++ PCIDAS_ife_m = 0x00000020,
++ PCIDAS_iff_b = 6,
++ PCIDAS_iff_m = 0x00000040,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI DMA Channel 8 Configuration Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCIDMA8C_mbs_b = 0, // Maximum Burst Size.
++ PCIDMA8C_mbs_m = 0x00000fff, // { pcidma8c }
++ PCIDMA8C_our_b = 12, // Optimize Unaligned Burst Reads.
++ PCIDMA8C_our_m = 0x00001000, // { pcidma8c }
++} ;
++
++/*******************************************************************************
++ *
++ * PCI DMA Channel 9 Configuration Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCIDMA9C_mbs_b = 0, // Maximum Burst Size.
++ PCIDMA9C_mbs_m = 0x00000fff, // { pcidma9c }
++} ;
++
++/*******************************************************************************
++ *
++ * PCI to Memory(DMA Channel 8) AND Memory to PCI DMA(DMA Channel 9)Descriptors
++ *
++ ******************************************************************************/
++enum {
++ PCIDMAD_pt_b = 22, // in DEVCMD field (descriptor)
++ PCIDMAD_pt_m = 0x00c00000, // preferred transaction field
++ // These are for reads (DMA channel 8)
++ PCIDMAD_devcmd_mr_v = 0, //memory read
++ PCIDMAD_devcmd_mrl_v = 1, //memory read line
++ PCIDMAD_devcmd_mrm_v = 2, //memory read multiple
++ PCIDMAD_devcmd_ior_v = 3, //I/O read
++ // These are for writes (DMA channel 9)
++ PCIDMAD_devcmd_mw_v = 0, //memory write
++ PCIDMAD_devcmd_mwi_v = 1, //memory write invalidate
++ PCIDMAD_devcmd_iow_v = 3, //I/O write
++
++ // Swap byte field applies to both DMA channel 8 and 9
++ PCIDMAD_sb_b = 24, // in DEVCMD field (descriptor)
++ PCIDMAD_sb_m = 0x01000000, // swap byte field
++} ;
++
++
++/*******************************************************************************
++ *
++ * PCI Target Control Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCITC_rtimer_b = 0, // In PCITC_t -> pcitc
++ PCITC_rtimer_m = 0x000000ff,
++ PCITC_dtimer_b = 8, // In PCITC_t -> pcitc
++ PCITC_dtimer_m = 0x0000ff00,
++ PCITC_rdr_b = 18, // In PCITC_t -> pcitc
++ PCITC_rdr_m = 0x00040000,
++ PCITC_ddt_b = 19, // In PCITC_t -> pcitc
++ PCITC_ddt_m = 0x00080000,
++} ;
++/*******************************************************************************
++ *
++ * PCI messaging unit [applies to both inbound and outbound registers ]
++ *
++ ******************************************************************************/
++enum
++{
++ PCIM_m0_b = 0, // In PCIM_t -> {pci{iic,iim,ioic,ioim}}
++ PCIM_m0_m = 0x00000001, // inbound or outbound message 0
++ PCIM_m1_b = 1, // In PCIM_t -> {pci{iic,iim,ioic,ioim}}
++ PCIM_m1_m = 0x00000002, // inbound or outbound message 1
++ PCIM_db_b = 2, // In PCIM_t -> {pci{iic,iim,ioic,ioim}}
++ PCIM_db_m = 0x00000004, // inbound or outbound doorbell
++};
++
++
++
++
++
++
++#define PCI_MSG_VirtualAddress 0xB8088010
++#define rc32434_pci ((volatile PCI_t) PCI0_VirtualAddress)
++#define rc32434_pci_msg ((volatile PCIM_t) PCI_MSG_VirtualAddress)
++
++#define PCIM_SHFT 0x6
++#define PCIM_BIT_LEN 0x7
++#define PCIM_H_EA 0x3
++#define PCIM_H_IA_FIX 0x4
++#define PCIM_H_IA_RR 0x5
++#if 0
++#define PCI_ADDR_START 0x13000000
++#endif
++
++#define PCI_ADDR_START 0x50000000
++
++#define CPUTOPCI_MEM_WIN 0x02000000
++#define CPUTOPCI_IO_WIN 0x00100000
++#define PCILBA_SIZE_SHFT 2
++#define PCILBA_SIZE_MASK 0x1F
++#define SIZE_256MB 0x1C
++#define SIZE_128MB 0x1B
++#define SIZE_64MB 0x1A
++#define SIZE_32MB 0x19
++#define SIZE_16MB 0x18
++#define SIZE_4MB 0x16
++#define SIZE_2MB 0x15
++#define SIZE_1MB 0x14
++#define KORINA_CONFIG0_ADDR 0x80000000
++#define KORINA_CONFIG1_ADDR 0x80000004
++#define KORINA_CONFIG2_ADDR 0x80000008
++#define KORINA_CONFIG3_ADDR 0x8000000C
++#define KORINA_CONFIG4_ADDR 0x80000010
++#define KORINA_CONFIG5_ADDR 0x80000014
++#define KORINA_CONFIG6_ADDR 0x80000018
++#define KORINA_CONFIG7_ADDR 0x8000001C
++#define KORINA_CONFIG8_ADDR 0x80000020
++#define KORINA_CONFIG9_ADDR 0x80000024
++#define KORINA_CONFIG10_ADDR 0x80000028
++#define KORINA_CONFIG11_ADDR 0x8000002C
++#define KORINA_CONFIG12_ADDR 0x80000030
++#define KORINA_CONFIG13_ADDR 0x80000034
++#define KORINA_CONFIG14_ADDR 0x80000038
++#define KORINA_CONFIG15_ADDR 0x8000003C
++#define KORINA_CONFIG16_ADDR 0x80000040
++#define KORINA_CONFIG17_ADDR 0x80000044
++#define KORINA_CONFIG18_ADDR 0x80000048
++#define KORINA_CONFIG19_ADDR 0x8000004C
++#define KORINA_CONFIG20_ADDR 0x80000050
++#define KORINA_CONFIG21_ADDR 0x80000054
++#define KORINA_CONFIG22_ADDR 0x80000058
++#define KORINA_CONFIG23_ADDR 0x8000005C
++#define KORINA_CONFIG24_ADDR 0x80000060
++#define KORINA_CONFIG25_ADDR 0x80000064
++#define KORINA_CMD (PCFG04_command_ioena_m | \
++ PCFG04_command_memena_m | \
++ PCFG04_command_bmena_m | \
++ PCFG04_command_mwinv_m | \
++ PCFG04_command_parena_m | \
++ PCFG04_command_serrena_m )
++
++#define KORINA_STAT (PCFG04_status_mdpe_m | \
++ PCFG04_status_sta_m | \
++ PCFG04_status_rta_m | \
++ PCFG04_status_rma_m | \
++ PCFG04_status_sse_m | \
++ PCFG04_status_pe_m)
++
++#define KORINA_CNFG1 ((KORINA_STAT<<16)|KORINA_CMD)
++
++#define KORINA_REVID 0
++#define KORINA_CLASS_CODE 0
++#define KORINA_CNFG2 ((KORINA_CLASS_CODE<<8) | \
++ KORINA_REVID)
++
++#define KORINA_CACHE_LINE_SIZE 4
++#define KORINA_MASTER_LAT 0x3c
++#define KORINA_HEADER_TYPE 0
++#define KORINA_BIST 0
++
++#define KORINA_CNFG3 ((KORINA_BIST << 24) | \
++ (KORINA_HEADER_TYPE<<16) | \
++ (KORINA_MASTER_LAT<<8) | \
++ KORINA_CACHE_LINE_SIZE )
++
++#define KORINA_BAR0 0x00000008 /* 128 MB Memory */
++#define KORINA_BAR1 0x18800001 /* 1 MB IO */
++#define KORINA_BAR2 0x18000001 /* 2 MB IO window for Korina
++ internal Registers */
++#define KORINA_BAR3 0x48000008 /* Spare 128 MB Memory */
++
++#define KORINA_CNFG4 KORINA_BAR0
++#define KORINA_CNFG5 KORINA_BAR1
++#define KORINA_CNFG6 KORINA_BAR2
++#define KORINA_CNFG7 KORINA_BAR3
++
++#define KORINA_SUBSYS_VENDOR_ID 0x011d
++#define KORINA_SUBSYSTEM_ID 0x0214
++#define KORINA_CNFG8 0
++#define KORINA_CNFG9 0
++#define KORINA_CNFG10 0
++#define KORINA_CNFG11 ((KORINA_SUBSYS_VENDOR_ID<<16) | \
++ KORINA_SUBSYSTEM_ID)
++#define KORINA_INT_LINE 1
++#define KORINA_INT_PIN 1
++#define KORINA_MIN_GNT 8
++#define KORINA_MAX_LAT 0x38
++#define KORINA_CNFG12 0
++#define KORINA_CNFG13 0
++#define KORINA_CNFG14 0
++#define KORINA_CNFG15 ((KORINA_MAX_LAT<<24) | \
++ (KORINA_MIN_GNT<<16) | \
++ (KORINA_INT_PIN<<8) | \
++ KORINA_INT_LINE)
++#define KORINA_RETRY_LIMIT 0x80
++#define KORINA_TRDY_LIMIT 0x80
++#define KORINA_CNFG16 ((KORINA_RETRY_LIMIT<<8) | \
++ KORINA_TRDY_LIMIT)
++#define PCI_PBAxC_R 0x0
++#define PCI_PBAxC_RL 0x1
++#define PCI_PBAxC_RM 0x2
++#define SIZE_SHFT 2
++
++#if defined(__MIPSEB__)
++#define KORINA_PBA0C ( PCIPBAC_mrl_m | PCIPBAC_sb_m | \
++ ((PCI_PBAxC_RM &0x3) << PCIPBAC_mr_b) | \
++ PCIPBAC_pp_m | \
++ (SIZE_128MB<<SIZE_SHFT) | \
++ PCIPBAC_p_m)
++#else
++#define KORINA_PBA0C ( PCIPBAC_mrl_m | \
++ ((PCI_PBAxC_RM &0x3) << PCIPBAC_mr_b) | \
++ PCIPBAC_pp_m | \
++ (SIZE_128MB<<SIZE_SHFT) | \
++ PCIPBAC_p_m)
++#endif
++#define KORINA_CNFG17 KORINA_PBA0C
++#define KORINA_PBA0M 0x0
++#define KORINA_CNFG18 KORINA_PBA0M
++
++#if defined(__MIPSEB__)
++#define KORINA_PBA1C ((SIZE_1MB<<SIZE_SHFT) | PCIPBAC_sb_m | \
++ PCIPBAC_msi_m)
++#else
++#define KORINA_PBA1C ((SIZE_1MB<<SIZE_SHFT) | \
++ PCIPBAC_msi_m)
++#endif
++#define KORINA_CNFG19 KORINA_PBA1C
++#define KORINA_PBA1M 0x0
++#define KORINA_CNFG20 KORINA_PBA1M
++
++#if defined(__MIPSEB__)
++#define KORINA_PBA2C ((SIZE_2MB<<SIZE_SHFT) | PCIPBAC_sb_m | \
++ PCIPBAC_msi_m)
++#else
++#define KORINA_PBA2C ((SIZE_2MB<<SIZE_SHFT) | \
++ PCIPBAC_msi_m)
++#endif
++#define KORINA_CNFG21 KORINA_PBA2C
++#define KORINA_PBA2M 0x18000000
++#define KORINA_CNFG22 KORINA_PBA2M
++#define KORINA_PBA3C 0
++#define KORINA_CNFG23 KORINA_PBA3C
++#define KORINA_PBA3M 0
++#define KORINA_CNFG24 KORINA_PBA3M
++
++
++
++#define PCITC_DTIMER_VAL 8
++#define PCITC_RTIMER_VAL 0x10
++
++
++
++
++#endif // __IDT_PCI_H__
++
++
++
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_rst.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_rst.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_rst.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_rst.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,119 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Reset register definitions.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RST_H__
++#define __IDT_RST_H__
++
++enum
++{
++ RST0_PhysicalAddress = 0x18000000,
++ RST_PhysicalAddress = RST0_PhysicalAddress, // Default
++
++ RST0_VirtualAddress = 0xb8000000,
++ RST_VirtualAddress = RST0_VirtualAddress, // Default
++} ;
++
++typedef struct RST_s
++{
++ u32 filler [0x0006] ;
++ u32 sysid ;
++ u32 filler2 [0x2000-8] ; // Pad out to offset 0x8000
++ u32 reset ;
++ u32 bcv ;
++ u32 cea ;
++} volatile * RST_t ;
++
++enum
++{
++ SYSID_rev_b = 0,
++ SYSID_rev_m = 0x000000ff,
++ SYSID_imp_b = 8,
++ SYSID_imp_m = 0x000fff00,
++ SYSID_vendor_b = 8,
++ SYSID_vendor_m = 0xfff00000,
++
++ BCV_pll_b = 0,
++ BCV_pll_m = 0x0000000f,
++ BCV_pll_PLLBypass_v = 0x0, // PCLK=1*CLK.
++ BCV_pll_Mul3_v = 0x1, // PCLK=3*CLK.
++ BCV_pll_Mul4_v = 0x2, // PCLK=4*CLK.
++ BCV_pll_SlowMul5_v = 0x3, // PCLK=5*CLK.
++ BCV_pll_Mul5_v = 0x4, // PCLK=5*CLK.
++ BCV_pll_SlowMul6_v = 0x5, // PCLK=6*CLK.
++ BCV_pll_Mul6_v = 0x6, // PCLK=6*CLK.
++ BCV_pll_Mul8_v = 0x7, // PCLK=8*CLK.
++ BCV_pll_Mul10_v = 0x8, // PCLK=10*CLK.
++ BCV_pll_Res9_v = 0x9,
++ BCV_pll_Res10_v = 0xa,
++ BCV_pll_Res11_v = 0xb,
++ BCV_pll_Res12_v = 0xc,
++ BCV_pll_Res13_v = 0xd,
++ BCV_pll_Res14_v = 0xe,
++ BCV_pll_Res15_v = 0xf,
++ BCV_clkDiv_b = 4,
++ BCV_clkDiv_m = 0x00000030,
++ BCV_clkDiv_Div1_v = 0x0,
++ BCV_clkDiv_Div2_v = 0x1,
++ BCV_clkDiv_Div4_v = 0x2,
++ BCV_clkDiv_Res3_v = 0x3,
++ BCV_bigEndian_b = 6,
++ BCV_bigEndian_m = 0x00000040,
++ BCV_resetFast_b = 7,
++ BCV_resetFast_m = 0x00000080,
++ BCV_pciMode_b = 8,
++ BCV_pciMode_m = 0x00000700,
++ BCV_pciMode_disabled_v = 0, // PCI is disabled.
++ BCV_pciMode_tnr_v = 1, // satellite Target Not Ready.
++ BCV_pciMode_suspended_v = 2, // satellite with suspended CPU.
++ BCV_pciMode_external_v = 3, // host, external arbiter.
++ BCV_pciMode_fixed_v = 4, // host, fixed priority arbiter.
++ BCV_pciMode_roundRobin_v= 5, // host, round robin arbiter.
++ BCV_pciMode_res6_v = 6,
++ BCV_pciMode_res7_v = 7,
++ BCV_watchDisable_b = 11,
++ BCV_watchDisable_m = 0x00000800,
++ BCV_res12_b = 12,
++ BCV_res12_m = 0x00001000,
++ BCV_res13_b = 13,
++ BCV_res13_m = 0x00002000,
++ BCV_res14_b = 14,
++ BCV_res14_m = 0x00004000,
++ BCV_res15_b = 15,
++ BCV_res15_m = 0x00008000,
++} ;
++#endif // __IDT_RST_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_spi.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_spi.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_spi.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_spi.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,120 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Serial Peripheral Interface register definitions.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_SPI_H__
++#define __IDT_SPI_H__
++
++enum
++{
++ SPI0_PhysicalAddress = 0x18070000,
++ SPI_PhysicalAddress = SPI0_PhysicalAddress,
++
++ SPI0_VirtualAddress = 0xB8070000,
++ SPI_VirtualAddress = SPI0_VirtualAddress,
++} ;
++
++typedef struct
++{
++ u32 spcp ; // prescalar. 0=off, * spiClk = sysClk/(2*(spcp+1)*SPR)
++ u32 spc ; // spi control reg use SPC_
++ u32 sps ; // spi status reg use SPS_
++ u32 spd ; // spi data reg use SPD_
++ u32 siofunc ; // serial IO function use SIOFUNC_
++ u32 siocfg ; // serial IO config use SIOCFG_
++ u32 siod; // serial IO data use SIOD_
++} volatile *SPI_t ;
++
++enum
++{
++ SPCP_div_b = 0,
++ SPCP_div_m = 0x000000ff,
++ SPC_spr_b = 0,
++ SPC_spr_m = 0x00000003,
++ SPC_spr_div2_v = 0,
++ SPC_spr_div4_v = 1,
++ SPC_spr_div16_v = 2,
++ SPC_spr_div32_v = 3,
++ SPC_cpha_b = 2,
++ SPC_cpha_m = 0x00000004,
++ SPC_cpol_b = 3,
++ SPC_cpol_m = 0x00000008,
++ SPC_mstr_b = 4,
++ SPC_mstr_m = 0x00000010,
++ SPC_spe_b = 6,
++ SPC_spe_m = 0x00000040,
++ SPC_spie_b = 7,
++ SPC_spie_m = 0x00000080,
++
++ SPS_modf_b = 4,
++ SPS_modf_m = 0x00000010,
++ SPS_wcol_b = 6,
++ SPS_wcol_m = 0x00000040,
++ SPS_spif_b = 7,
++ SPS_spif_m = 0x00000070,
++
++ SPD_data_b = 0,
++ SPD_data_m = 0x000000ff,
++
++ SIOFUNC_sdo_b = 0,
++ SIOFUNC_sdo_m = 0x00000001,
++ SIOFUNC_sdi_b = 1,
++ SIOFUNC_sdi_m = 0x00000002,
++ SIOFUNC_sck_b = 2,
++ SIOFUNC_sck_m = 0x00000004,
++ SIOFUNC_pci_b = 3,
++ SIOFUNC_pci_m = 0x00000008,
++
++ SIOCFG_sdo_b = 0,
++ SIOCFG_sdo_m = 0x00000001,
++ SIOCFG_sdi_b = 1,
++ SIOCFG_sdi_m = 0x00000002,
++ SIOCFG_sck_b = 2,
++ SIOCFG_sck_m = 0x00000004,
++ SIOCFG_pci_b = 3,
++ SIOCFG_pci_m = 0x00000008,
++
++ SIOD_sdo_b = 0,
++ SIOD_sdo_m = 0x00000001,
++ SIOD_sdi_b = 1,
++ SIOD_sdi_m = 0x00000002,
++ SIOD_sck_b = 2,
++ SIOD_sck_m = 0x00000004,
++ SIOD_pci_b = 3,
++ SIOD_pci_m = 0x00000008,
++} ;
++#endif // __IDT_SPI_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_timer.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_timer.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_timer.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_timer.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,91 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Definitions for timer registers
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt,neb.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_TIM_H__
++#define __IDT_TIM_H__
++
++enum
++{
++ TIM0_PhysicalAddress = 0x18028000,
++ TIM_PhysicalAddress = TIM0_PhysicalAddress, // Default
++
++ TIM0_VirtualAddress = 0xb8028000,
++ TIM_VirtualAddress = TIM0_VirtualAddress, // Default
++} ;
++
++enum
++{
++ TIM_Count = 3,
++} ;
++
++struct TIM_CNTR_s
++{
++ u32 count ;
++ u32 compare ;
++ u32 ctc ; //use CTC_
++} ;
++
++typedef struct TIM_s
++{
++ struct TIM_CNTR_s tim [TIM_Count] ;
++ u32 rcount ; //use RCOUNT_
++ u32 rcompare ; //use RCOMPARE_
++ u32 rtc ; //use RTC_
++} volatile * TIM_t ;
++
++enum
++{
++ CTC_en_b = 0,
++ CTC_en_m = 0x00000001,
++ CTC_to_b = 1,
++ CTC_to_m = 0x00000002,
++
++ RCOUNT_count_b = 0,
++ RCOUNT_count_m = 0x0000ffff,
++ RCOMPARE_compare_b = 0,
++ RCOMPARE_compare_m = 0x0000ffff,
++ RTC_ce_b = 0,
++ RTC_ce_m = 0x00000001,
++ RTC_to_b = 1,
++ RTC_to_m = 0x00000002,
++ RTC_rqe_b = 2,
++ RTC_rqe_m = 0x00000004,
++
++} ;
++#endif // __IDT_TIM_H__
++
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_uart.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_uart.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32434/rc32434_uart.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32434/rc32434_uart.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,189 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * UART register definitions
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_UART_H__
++#define __IDT_UART_H__
++
++enum
++{
++ UART0_PhysicalAddress = 0x1c000000,
++ UART_PhysicalAddress = UART0_PhysicalAddress, // Default
++
++ UART0_VirtualAddress = 0xbc000000,
++ UART_VirtualAddress = UART0_VirtualAddress, // Default
++} ;
++
++/*
++ * Register definitions are in bytes so we can handle endian problems.
++ */
++
++typedef struct UART_s
++{
++ union
++ {
++ u32 const uartrb ; // 0x00 - DLAB=0, read.
++ u32 uartth ; // 0x00 - DLAB=0, write.
++ u32 uartdll ; // 0x00 - DLAB=1, read/write.
++ } ;
++
++ union
++ {
++ u32 uartie ; // 0x04 - DLAB=0, read/write.
++ u32 uartdlh ; // 0x04 - DLAB=1, read/write.
++ } ;
++ union
++ {
++ u32 const uartii ; // 0x08 - DLAB=0, read.
++ u32 uartfc ; // 0x08 - DLAB=0, write.
++ } ;
++
++ u32 uartlc ; // 0x0c
++ u32 uartmc ; // 0x10
++ u32 uartls ; // 0x14
++ u32 uartms ; // 0x18
++ u32 uarts ; // 0x1c
++} volatile *UART_t ;
++
++// Reset registers.
++typedef u32 volatile *UARTRR_t ;
++
++enum
++{
++ UARTIE_rda_b = 0,
++ UARTIE_rda_m = 0x00000001,
++ UARTIE_the_b = 1,
++ UARTIE_the_m = 0x00000002,
++ UARTIE_rls_b = 2,
++ UARTIE_rls_m = 0x00000004,
++ UARTIE_ems_b = 3,
++ UARTIE_ems_m = 0x00000008,
++
++ UARTII_pi_b = 0,
++ UARTII_pi_m = 0x00000001,
++ UARTII_iid_b = 1,
++ UARTII_iid_m = 0x0000000e,
++ UARTII_iid_ms_v = 0, // Modem stat-CTS,DSR,RI or DCD.
++ UARTII_iid_thre_v = 1, // Trans. Holding Reg. empty.
++ UARTII_iid_rda_v = 2, // Receive data available
++ UARTII_iid_rls_v = 3, // Overrun, parity, etc, error.
++ UARTII_iid_res4_v = 4, // reserved.
++ UARTII_iid_res5_v = 5, // reserved.
++ UARTII_iid_cto_v = 6, // Character timeout.
++ UARTII_iid_res7_v = 7, // reserved.
++
++ UARTFC_en_b = 0,
++ UARTFC_en_m = 0x00000001,
++ UARTFC_rr_b = 1,
++ UARTFC_rr_m = 0x00000002,
++ UARTFC_tr_b = 2,
++ UARTFC_tr_m = 0x00000004,
++ UARTFC_dms_b = 3,
++ UARTFC_dms_m = 0x00000008,
++ UARTFC_rt_b = 6,
++ UARTFC_rt_m = 0x000000c0,
++ UARTFC_rt_1Byte_v = 0,
++ UARTFC_rt_4Byte_v = 1,
++ UARTFC_rt_8Byte_v = 2,
++ UARTFC_rt_14Byte_v = 3,
++
++ UARTLC_wls_b = 0,
++ UARTLC_wls_m = 0x00000003,
++ UARTLC_wls_5Bits_v = 0,
++ UARTLC_wls_6Bits_v = 1,
++ UARTLC_wls_7Bits_v = 2,
++ UARTLC_wls_8Bits_v = 3,
++ UARTLC_stb_b = 2,
++ UARTLC_stb_m = 0x00000004,
++ UARTLC_pen_b = 3,
++ UARTLC_pen_m = 0x00000008,
++ UARTLC_eps_b = 4,
++ UARTLC_eps_m = 0x00000010,
++ UARTLC_sp_b = 5,
++ UARTLC_sp_m = 0x00000020,
++ UARTLC_sb_b = 6,
++ UARTLC_sb_m = 0x00000040,
++ UARTLC_dlab_b = 7,
++ UARTLC_dlab_m = 0x00000080,
++
++ UARTMC_dtr_b = 0,
++ UARTMC_dtr_m = 0x00000001,
++ UARTMC_rts_b = 1,
++ UARTMC_rts_m = 0x00000002,
++ UARTMC_o1_b = 2,
++ UARTMC_o1_m = 0x00000004,
++ UARTMC_o2_b = 3,
++ UARTMC_o2_m = 0x00000008,
++ UARTMC_lp_b = 4,
++ UARTMC_lp_m = 0x00000010,
++
++ UARTLS_dr_b = 0,
++ UARTLS_dr_m = 0x00000001,
++ UARTLS_oe_b = 1,
++ UARTLS_oe_m = 0x00000002,
++ UARTLS_pe_b = 2,
++ UARTLS_pe_m = 0x00000004,
++ UARTLS_fe_b = 3,
++ UARTLS_fe_m = 0x00000008,
++ UARTLS_bi_b = 4,
++ UARTLS_bi_m = 0x00000010,
++ UARTLS_thr_b = 5,
++ UARTLS_thr_m = 0x00000020,
++ UARTLS_te_b = 6,
++ UARTLS_te_m = 0x00000040,
++ UARTLS_rfe_b = 7,
++ UARTLS_rfe_m = 0x00000080,
++
++ UARTMS_dcts_b = 0,
++ UARTMS_dcts_m = 0x00000001,
++ UARTMS_ddsr_b = 1,
++ UARTMS_ddsr_m = 0x00000002,
++ UARTMS_teri_b = 2,
++ UARTMS_teri_m = 0x00000004,
++ UARTMS_ddcd_b = 3,
++ UARTMS_ddcd_m = 0x00000008,
++ UARTMS_cts_b = 4,
++ UARTMS_cts_m = 0x00000010,
++ UARTMS_dsr_b = 5,
++ UARTMS_dsr_m = 0x00000020,
++ UARTMS_ri_b = 6,
++ UARTMS_ri_m = 0x00000040,
++ UARTMS_dcd_b = 7,
++ UARTMS_dcd_m = 0x00000080,
++} ;
++
++#endif // __IDT_UART_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_dma.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_dma.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_dma.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_dma.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,231 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Register definitions for IDT RC32438 DMA.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++#ifndef __IDT_RC32438_DMA_H__
++#define __IDT_RC32438_DMA_H__
++enum
++{
++ DMA0_PhysicalAddress = 0x18040000,
++ DMA_PhysicalAddress = DMA0_PhysicalAddress, // Default
++
++ DMA0_VirtualAddress = 0xb8040000,
++ DMA_VirtualAddress = DMA0_VirtualAddress, // Default
++} ;
++
++/*
++ * DMA descriptor (in physical memory).
++ */
++
++typedef struct DMAD_s
++{
++ u32 control ; // Control. use DMAD_*
++ u32 ca ; // Current Address.
++ u32 devcs ; // Device control and status.
++ u32 link ; // Next descriptor in chain.
++} volatile *DMAD_t ;
++
++enum
++{
++ DMAD_size = sizeof (struct DMAD_s),
++ DMAD_count_b = 0, // in DMAD_t -> control
++ DMAD_count_m = 0x0003ffff, // in DMAD_t -> control
++ DMAD_ds_b = 20, // in DMAD_t -> control
++ DMAD_ds_m = 0x00300000, // in DMAD_t -> control
++ DMAD_ds_extToMem0_v = 0,
++ DMAD_ds_memToExt0_v = 1,
++ DMAD_ds_extToMem1_v = 0,
++ DMAD_ds_memToExt1_v = 1,
++ DMAD_ds_ethRcv0_v = 0,
++ DMAD_ds_ethXmt0_v = 0,
++ DMAD_ds_ethRcv1_v = 0,
++ DMAD_ds_ethXmt2_v = 0,
++ DMAD_ds_memToFifo_v = 0,
++ DMAD_ds_fifoToMem_v = 0,
++ DMAD_ds_rng_de_v = 1,//randomNumberGenerator on LC/DE
++ DMAD_ds_pciToMem_v = 0,
++ DMAD_ds_memToPci_v = 0,
++ DMAD_ds_securityInput_v = 0,
++ DMAD_ds_securityOutput_v = 0,
++ DMAD_ds_rng_se_v = 0,//randomNumberGenerator on SE
++
++ DMAD_devcmd_b = 22, // in DMAD_t -> control
++ DMAD_devcmd_m = 0x01c00000, // in DMAD_t -> control
++ DMAD_devcmd_byte_v = 0, //memory-to-memory
++ DMAD_devcmd_halfword_v = 1, //memory-to-memory
++ DMAD_devcmd_word_v = 2, //memory-to-memory
++ DMAD_devcmd_2words_v = 3, //memory-to-memory
++ DMAD_devcmd_4words_v = 4, //memory-to-memory
++ DMAD_devcmd_6words_v = 5, //memory-to-memory
++ DMAD_devcmd_8words_v = 6, //memory-to-memory
++ DMAD_devcmd_16words_v = 7, //memory-to-memory
++ DMAD_cof_b = 25, // chain on finished
++ DMAD_cof_m = 0x02000000, //
++ DMAD_cod_b = 26, // chain on done
++ DMAD_cod_m = 0x04000000, //
++ DMAD_iof_b = 27, // interrupt on finished
++ DMAD_iof_m = 0x08000000, //
++ DMAD_iod_b = 28, // interrupt on done
++ DMAD_iod_m = 0x10000000, //
++ DMAD_t_b = 29, // terminated
++ DMAD_t_m = 0x20000000, //
++ DMAD_d_b = 30, // done
++ DMAD_d_m = 0x40000000, //
++ DMAD_f_b = 31, // finished
++ DMAD_f_m = 0x80000000, //
++} ;
++
++/*
++ * DMA register (within Internal Register Map).
++ */
++
++struct DMA_Chan_s
++{
++ u32 dmac ; // Control.
++ u32 dmas ; // Status.
++ u32 dmasm ; // Mask.
++ u32 dmadptr ; // Descriptor pointer.
++ u32 dmandptr ; // Next descriptor pointer.
++};
++
++typedef struct DMA_Chan_s volatile *DMA_Chan_t ;
++
++//DMA_Channels use DMACH_count instead
++
++enum
++{
++ DMAC_run_b = 0, //
++ DMAC_run_m = 0x00000001, //
++ DMAC_dm_b = 1, // done mask
++ DMAC_dm_m = 0x00000002, //
++ DMAC_mode_b = 2, //
++ DMAC_mode_m = 0x0000000c, //
++ DMAC_mode_auto_v = 0,
++ DMAC_mode_burst_v = 1,
++ DMAC_mode_transfer_v = 2, //usually used
++ DMAC_mode_reserved_v = 3,
++ DMAC_a_b = 4, //
++ DMAC_a_m = 0x00000010, //
++
++ DMAS_f_b = 0, // finished (sticky)
++ DMAS_f_m = 0x00000001, //
++ DMAS_d_b = 1, // done (sticky)
++ DMAS_d_m = 0x00000002, //
++ DMAS_c_b = 2, // chain (sticky)
++ DMAS_c_m = 0x00000004, //
++ DMAS_e_b = 3, // error (sticky)
++ DMAS_e_m = 0x00000008, //
++ DMAS_h_b = 4, // halt (sticky)
++ DMAS_h_m = 0x00000010, //
++
++ DMASM_f_b = 0, // finished (1=mask)
++ DMASM_f_m = 0x00000001, //
++ DMASM_d_b = 1, // done (1=mask)
++ DMASM_d_m = 0x00000002, //
++ DMASM_c_b = 2, // chain (1=mask)
++ DMASM_c_m = 0x00000004, //
++ DMASM_e_b = 3, // error (1=mask)
++ DMASM_e_m = 0x00000008, //
++ DMASM_h_b = 4, // halt (1=mask)
++ DMASM_h_m = 0x00000010, //
++} ;
++
++/*
++ * DMA channel definitions
++ */
++
++enum
++{
++ DMACH_extToMem0 = 0,
++ DMACH_memToExt0 = 0,
++ DMACH_extToMem1 = 1,
++ DMACH_memToExt1 = 1,
++ DMACH_ethRcv0 = 2,
++ DMACH_ethXmt0 = 3,
++ DMACH_ethRcv1 = 4,
++ DMACH_ethXmt2 = 5,
++ DMACH_memToFifo = 6,
++ DMACH_fifoToMem = 7,
++ DMACH_rng_de = 7,//randomNumberGenerator on LC/DE
++ DMACH_pciToMem = 8,
++ DMACH_memToPci = 9,
++ DMACH_securityInput = 10,
++ DMACH_securityOutput = 11,
++ DMACH_rng_se = 12, //randomNumberGenerator on SE
++
++ DMACH_count //must be last
++};
++
++
++typedef struct DMAC_s
++{
++ struct DMA_Chan_s ch [DMACH_count] ; //use ch[DMACH_]
++} volatile *DMA_t ;
++
++
++/*
++ * External DMA parameters
++*/
++
++enum
++{
++ DMADEVCMD_ts_b = 0, // ts field in devcmd
++ DMADEVCMD_ts_m = 0x00000007, // ts field in devcmd
++ DMADEVCMD_ts_byte_v = 0,
++ DMADEVCMD_ts_halfword_v = 1,
++ DMADEVCMD_ts_word_v = 2,
++ DMADEVCMD_ts_2word_v = 3,
++ DMADEVCMD_ts_4word_v = 4,
++ DMADEVCMD_ts_6word_v = 5,
++ DMADEVCMD_ts_8word_v = 6,
++ DMADEVCMD_ts_16word_v = 7
++};
++
++
++#if 1 // aws - Compatibility.
++# define EXTDMA_ts_b DMADEVCMD_ts_b
++# define EXTDMA_ts_m DMADEVCMD_ts_m
++# define EXTDMA_ts_byte_v DMADEVCMD_ts_byte_v
++# define EXTDMA_ts_halfword_v DMADEVCMD_ts_halfword_v
++# define EXTDMA_ts_word_v DMADEVCMD_ts_word_v
++# define EXTDMA_ts_2word_v DMADEVCMD_ts_2word_v
++# define EXTDMA_ts_4word_v DMADEVCMD_ts_4word_v
++# define EXTDMA_ts_6word_v DMADEVCMD_ts_6word_v
++# define EXTDMA_ts_8word_v DMADEVCMD_ts_8word_v
++# define EXTDMA_ts_16word_v DMADEVCMD_ts_16word_v
++#endif // aws - Compatibility.
++
++#endif //__IDT_RC32438_DMA_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_dma_v.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_dma_v.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_dma_v.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_dma_v.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,82 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * DMA operations for IDT RC32438.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RC32438_DMA_V_H__
++#define __IDT_RC32438_DMA_V_H__
++#include <asm/idt-boards/rc32438/rc32438_dma.h>
++
++#define DMA_CHAN_OFFSET 0x14
++#define IS_DMA_USED(X) (((X) & (DMAD_f_m | DMAD_d_m | DMAD_t_m)) != 0)
++#define DMA_COUNT(count) \
++ ((count) & DMAD_count_m)
++
++#define DMA_HALT_TIMEOUT 500
++
++
++static inline int rc32438_halt_dma(DMA_Chan_t ch)
++{
++ int timeout=1;
++ if (rc32438_readl(&ch->dmac) & DMAC_run_m) {
++ rc32438_writel(0, &ch->dmac);
++
++ for (timeout = DMA_HALT_TIMEOUT; timeout > 0; timeout--) {
++ if (rc32438_readl(&ch->dmas) & DMAS_h_m) {
++ rc32438_writel(0, &ch->dmas);
++ break;
++ }
++ }
++
++ }
++
++ return timeout ? 0 : 1;
++}
++
++
++
++
++static inline void rc32438_start_dma(DMA_Chan_t ch, u32 dma_addr)
++{
++ rc32438_writel(0, &ch->dmandptr);
++ rc32438_writel(dma_addr, &ch->dmadptr);
++}
++
++static inline void rc32438_chain_dma(DMA_Chan_t ch, u32 dma_addr)
++{
++ rc32438_writel(dma_addr, &ch->dmandptr);
++}
++#endif //__IDT_RC32438_DMA_V_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_eth.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_eth.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_eth.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_eth.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,328 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Definitions for IDT EB438 ethernet
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RC32438_ETH_H__
++#define __IDT_RC32438_ETH_H__
++enum
++{
++ ETH0_PhysicalAddress = 0x18058000,
++ ETH_PhysicalAddress = ETH0_PhysicalAddress, // Default
++
++ ETH0_VirtualAddress = 0xb8058000,
++ ETH_VirtualAddress = ETH0_VirtualAddress, // Default
++ ETH1_PhysicalAddress = 0x18060000,
++ ETH1_VirtualAddress = 0xb8060000, // Default
++} ;
++
++typedef struct
++{
++ u32 ethintfc ;
++ u32 ethfifott ;
++ u32 etharc ;
++ u32 ethhash0 ;
++ u32 ethhash1 ;
++ u32 ethu0 [4] ; // Reserved.
++ u32 ethpfs ;
++ u32 ethmcp ;
++ u32 eth_u1 [10] ; // Reserved.
++ u32 ethspare ;
++ u32 eth_u2 [42] ; // Reserved.
++ u32 ethsal0 ;
++ u32 ethsah0 ;
++ u32 ethsal1 ;
++ u32 ethsah1 ;
++ u32 ethsal2 ;
++ u32 ethsah2 ;
++ u32 ethsal3 ;
++ u32 ethsah3 ;
++ u32 ethrbc ;
++ u32 ethrpc ;
++ u32 ethrupc ;
++ u32 ethrfc ;
++ u32 ethtbc ;
++ u32 ethgpf ;
++ u32 eth_u9 [50] ; // Reserved.
++ u32 ethmac1 ;
++ u32 ethmac2 ;
++ u32 ethipgt ;
++ u32 ethipgr ;
++ u32 ethclrt ;
++ u32 ethmaxf ;
++ u32 eth_u10 ; // Reserved.
++ u32 ethmtest ;
++ u32 miimcfg ;
++ u32 miimcmd ;
++ u32 miimaddr ;
++ u32 miimwtd ;
++ u32 miimrdd ;
++ u32 miimind ;
++ u32 eth_u11 ; // Reserved.
++ u32 eth_u12 ; // Reserved.
++ u32 ethcfsa0 ;
++ u32 ethcfsa1 ;
++ u32 ethcfsa2 ;
++} volatile *ETH_t;
++
++enum
++{
++ ETHINTFC_en_b = 0,
++ ETHINTFC_en_m = 0x00000001,
++ ETHINTFC_its_b = 1,
++ ETHINTFC_its_m = 0x00000002,
++ ETHINTFC_rip_b = 2,
++ ETHINTFC_rip_m = 0x00000004,
++ ETHINTFC_jam_b = 3,
++ ETHINTFC_jam_m = 0x00000008,
++ ETHINTFC_ovr_b = 4,
++ ETHINTFC_ovr_m = 0x00000010,
++ ETHINTFC_und_b = 5,
++ ETHINTFC_und_m = 0x00000020,
++
++ ETHFIFOTT_tth_b = 0,
++ ETHFIFOTT_tth_m = 0x0000007f,
++
++ ETHARC_pro_b = 0,
++ ETHARC_pro_m = 0x00000001,
++ ETHARC_am_b = 1,
++ ETHARC_am_m = 0x00000002,
++ ETHARC_afm_b = 2,
++ ETHARC_afm_m = 0x00000004,
++ ETHARC_ab_b = 3,
++ ETHARC_ab_m = 0x00000008,
++
++ ETHSAL_byte5_b = 0,
++ ETHSAL_byte5_m = 0x000000ff,
++ ETHSAL_byte4_b = 8,
++ ETHSAL_byte4_m = 0x0000ff00,
++ ETHSAL_byte3_b = 16,
++ ETHSAL_byte3_m = 0x00ff0000,
++ ETHSAL_byte2_b = 24,
++ ETHSAL_byte2_m = 0xff000000,
++
++ ETHSAH_byte1_b = 0,
++ ETHSAH_byte1_m = 0x000000ff,
++ ETHSAH_byte0_b = 8,
++ ETHSAH_byte0_m = 0x0000ff00,
++
++ ETHGPF_ptv_b = 0,
++ ETHGPF_ptv_m = 0x0000ffff,
++
++ ETHPFS_pfd_b = 0,
++ ETHPFS_pfd_m = 0x00000001,
++
++ ETHCFSA0_cfsa4_b = 0,
++ ETHCFSA0_cfsa4_m = 0x000000ff,
++ ETHCFSA0_cfsa5_b = 8,
++ ETHCFSA0_cfsa5_m = 0x0000ff00,
++
++ ETHCFSA1_cfsa2_b = 0,
++ ETHCFSA1_cfsa2_m = 0x000000ff,
++ ETHCFSA1_cfsa3_b = 8,
++ ETHCFSA1_cfsa3_m = 0x0000ff00,
++
++ ETHCFSA2_cfsa0_b = 0,
++ ETHCFSA2_cfsa0_m = 0x000000ff,
++ ETHCFSA2_cfsa1_b = 8,
++ ETHCFSA2_cfsa1_m = 0x0000ff00,
++
++ ETHMAC1_re_b = 0,
++ ETHMAC1_re_m = 0x00000001,
++ ETHMAC1_paf_b = 1,
++ ETHMAC1_paf_m = 0x00000002,
++ ETHMAC1_rfc_b = 2,
++ ETHMAC1_rfc_m = 0x00000004,
++ ETHMAC1_tfc_b = 3,
++ ETHMAC1_tfc_m = 0x00000008,
++ ETHMAC1_lb_b = 4,
++ ETHMAC1_lb_m = 0x00000010,
++ ETHMAC1_mr_b = 31,
++ ETHMAC1_mr_m = 0x80000000,
++
++ ETHMAC2_fd_b = 0,
++ ETHMAC2_fd_m = 0x00000001,
++ ETHMAC2_flc_b = 1,
++ ETHMAC2_flc_m = 0x00000002,
++ ETHMAC2_hfe_b = 2,
++ ETHMAC2_hfe_m = 0x00000004,
++ ETHMAC2_dc_b = 3,
++ ETHMAC2_dc_m = 0x00000008,
++ ETHMAC2_cen_b = 4,
++ ETHMAC2_cen_m = 0x00000010,
++ ETHMAC2_pe_b = 5,
++ ETHMAC2_pe_m = 0x00000020,
++ ETHMAC2_vpe_b = 6,
++ ETHMAC2_vpe_m = 0x00000040,
++ ETHMAC2_ape_b = 7,
++ ETHMAC2_ape_m = 0x00000080,
++ ETHMAC2_ppe_b = 8,
++ ETHMAC2_ppe_m = 0x00000100,
++ ETHMAC2_lpe_b = 9,
++ ETHMAC2_lpe_m = 0x00000200,
++ ETHMAC2_nb_b = 12,
++ ETHMAC2_nb_m = 0x00001000,
++ ETHMAC2_bp_b = 13,
++ ETHMAC2_bp_m = 0x00002000,
++ ETHMAC2_ed_b = 14,
++ ETHMAC2_ed_m = 0x00004000,
++
++ ETHIPGT_ipgt_b = 0,
++ ETHIPGT_ipgt_m = 0x0000007f,
++
++ ETHIPGR_ipgr2_b = 0,
++ ETHIPGR_ipgr2_m = 0x0000007f,
++ ETHIPGR_ipgr1_b = 8,
++ ETHIPGR_ipgr1_m = 0x00007f00,
++
++ ETHCLRT_maxret_b = 0,
++ ETHCLRT_maxret_m = 0x0000000f,
++ ETHCLRT_colwin_b = 8,
++ ETHCLRT_colwin_m = 0x00003f00,
++
++ ETHMAXF_maxf_b = 0,
++ ETHMAXF_maxf_m = 0x0000ffff,
++
++ ETHMTEST_tb_b = 2,
++ ETHMTEST_tb_m = 0x00000004,
++
++ ETHMCP_div_b = 0,
++ ETHMCP_div_m = 0x000000ff,
++
++ MIIMCFG_rsv_b = 0,
++ MIIMCFG_rsv_m = 0x0000000c,
++
++ MIIMCMD_rd_b = 0,
++ MIIMCMD_rd_m = 0x00000001,
++ MIIMCMD_scn_b = 1,
++ MIIMCMD_scn_m = 0x00000002,
++
++ MIIMADDR_regaddr_b = 0,
++ MIIMADDR_regaddr_m = 0x0000001f,
++ MIIMADDR_phyaddr_b = 8,
++ MIIMADDR_phyaddr_m = 0x00001f00,
++
++ MIIMWTD_wdata_b = 0,
++ MIIMWTD_wdata_m = 0x0000ffff,
++
++ MIIMRDD_rdata_b = 0,
++ MIIMRDD_rdata_m = 0x0000ffff,
++
++ MIIMIND_bsy_b = 0,
++ MIIMIND_bsy_m = 0x00000001,
++ MIIMIND_scn_b = 1,
++ MIIMIND_scn_m = 0x00000002,
++ MIIMIND_nv_b = 2,
++ MIIMIND_nv_m = 0x00000004,
++
++} ;
++
++/*
++ * Values for the DEVCS field of the Ethernet DMA Rx and Tx descriptors.
++ */
++enum
++{
++ ETHRX_fd_b = 0,
++ ETHRX_fd_m = 0x00000001,
++ ETHRX_ld_b = 1,
++ ETHRX_ld_m = 0x00000002,
++ ETHRX_rok_b = 2,
++ ETHRX_rok_m = 0x00000004,
++ ETHRX_fm_b = 3,
++ ETHRX_fm_m = 0x00000008,
++ ETHRX_mp_b = 4,
++ ETHRX_mp_m = 0x00000010,
++ ETHRX_bp_b = 5,
++ ETHRX_bp_m = 0x00000020,
++ ETHRX_vlt_b = 6,
++ ETHRX_vlt_m = 0x00000040,
++ ETHRX_cf_b = 7,
++ ETHRX_cf_m = 0x00000080,
++ ETHRX_ovr_b = 8,
++ ETHRX_ovr_m = 0x00000100,
++ ETHRX_crc_b = 9,
++ ETHRX_crc_m = 0x00000200,
++ ETHRX_cv_b = 10,
++ ETHRX_cv_m = 0x00000400,
++ ETHRX_db_b = 11,
++ ETHRX_db_m = 0x00000800,
++ ETHRX_le_b = 12,
++ ETHRX_le_m = 0x00001000,
++ ETHRX_lor_b = 13,
++ ETHRX_lor_m = 0x00002000,
++ ETHRX_ces_b = 14,
++ ETHRX_ces_m = 0x00004000,
++ ETHRX_length_b = 16,
++ ETHRX_length_m = 0xffff0000,
++
++ ETHTX_fd_b = 0,
++ ETHTX_fd_m = 0x00000001,
++ ETHTX_ld_b = 1,
++ ETHTX_ld_m = 0x00000002,
++ ETHTX_oen_b = 2,
++ ETHTX_oen_m = 0x00000004,
++ ETHTX_pen_b = 3,
++ ETHTX_pen_m = 0x00000008,
++ ETHTX_cen_b = 4,
++ ETHTX_cen_m = 0x00000010,
++ ETHTX_hen_b = 5,
++ ETHTX_hen_m = 0x00000020,
++ ETHTX_tok_b = 6,
++ ETHTX_tok_m = 0x00000040,
++ ETHTX_mp_b = 7,
++ ETHTX_mp_m = 0x00000080,
++ ETHTX_bp_b = 8,
++ ETHTX_bp_m = 0x00000100,
++ ETHTX_und_b = 9,
++ ETHTX_und_m = 0x00000200,
++ ETHTX_of_b = 10,
++ ETHTX_of_m = 0x00000400,
++ ETHTX_ed_b = 11,
++ ETHTX_ed_m = 0x00000800,
++ ETHTX_ec_b = 12,
++ ETHTX_ec_m = 0x00001000,
++ ETHTX_lc_b = 13,
++ ETHTX_lc_m = 0x00002000,
++ ETHTX_td_b = 14,
++ ETHTX_td_m = 0x00004000,
++ ETHTX_crc_b = 15,
++ ETHTX_crc_m = 0x00008000,
++ ETHTX_le_b = 16,
++ ETHTX_le_m = 0x00010000,
++ ETHTX_cc_b = 17,
++ ETHTX_cc_m = 0x001E0000,
++} ;
++#endif //__IDT_RC32438_ETH_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_eth_v.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_eth_v.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_eth_v.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_eth_v.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,72 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * macros for IDT EB438 ethernet
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RC32438_ETH_V_H__
++#define __IDT_RC32438_ETH_V_H__
++#include <asm/idt-boards/rc32438/rc32438_eth.h>
++
++#define IS_TX_TOK(X) (((X) & (1<<ETHTX_tok_b)) >> ETHTX_tok_b ) /* Transmit Okay */
++#define IS_TX_MP(X) (((X) & (1<<ETHTX_mp_b)) >> ETHTX_mp_b ) /* Multicast */
++#define IS_TX_BP(X) (((X) & (1<<ETHTX_bp_b)) >> ETHTX_bp_b ) /* Broadcast */
++#define IS_TX_UND_ERR(X) (((X) & (1<<ETHTX_und_b)) >> ETHTX_und_b ) /* Transmit FIFO Underflow */
++#define IS_TX_OF_ERR(X) (((X) & (1<<ETHTX_of_b)) >> ETHTX_of_b ) /* Oversized frame */
++#define IS_TX_ED_ERR(X) (((X) & (1<<ETHTX_ed_b)) >> ETHTX_ed_b ) /* Excessive deferral */
++#define IS_TX_EC_ERR(X) (((X) & (1<<ETHTX_ec_b)) >> ETHTX_ec_b) /* Excessive collisions */
++#define IS_TX_LC_ERR(X) (((X) & (1<<ETHTX_lc_b)) >> ETHTX_lc_b ) /* Late Collision */
++#define IS_TX_TD_ERR(X) (((X) & (1<<ETHTX_td_b)) >> ETHTX_td_b ) /* Transmit deferred*/
++#define IS_TX_CRC_ERR(X) (((X) & (1<<ETHTX_crc_b)) >> ETHTX_crc_b ) /* CRC Error */
++#define IS_TX_LE_ERR(X) (((X) & (1<<ETHTX_le_b)) >> ETHTX_le_b ) /* Length Error */
++
++#define TX_COLLISION_COUNT(X) (((X) & ETHTX_cc_m)>>ETHTX_cc_b) /* Collision Count */
++
++#define IS_RCV_ROK(X) (((X) & (1<<ETHRX_rok_b)) >> ETHRX_rok_b) /* Receive Okay */
++#define IS_RCV_FM(X) (((X) & (1<<ETHRX_fm_b)) >> ETHRX_fm_b) /* Is Filter Match */
++#define IS_RCV_MP(X) (((X) & (1<<ETHRX_mp_b)) >> ETHRX_mp_b) /* Is it MP */
++#define IS_RCV_BP(X) (((X) & (1<<ETHRX_bp_b)) >> ETHRX_bp_b) /* Is it BP */
++#define IS_RCV_VLT(X) (((X) & (1<<ETHRX_vlt_b)) >> ETHRX_vlt_b) /* VLAN Tag Detect */
++#define IS_RCV_CF(X) (((X) & (1<<ETHRX_cf_b)) >> ETHRX_cf_b) /* Control Frame */
++#define IS_RCV_OVR_ERR(X) (((X) & (1<<ETHRX_ovr_b)) >> ETHRX_ovr_b) /* Receive Overflow */
++#define IS_RCV_CRC_ERR(X) (((X) & (1<<ETHRX_crc_b)) >> ETHRX_crc_b) /* CRC Error */
++#define IS_RCV_CV_ERR(X) (((X) & (1<<ETHRX_cv_b)) >> ETHRX_cv_b) /* Code Violation */
++#define IS_RCV_DB_ERR(X) (((X) & (1<<ETHRX_db_b)) >> ETHRX_db_b) /* Dribble Bits */
++#define IS_RCV_LE_ERR(X) (((X) & (1<<ETHRX_le_b)) >> ETHRX_le_b) /* Length error */
++#define IS_RCV_LOR_ERR(X) (((X) & (1<<ETHRX_lor_b)) >> ETHRX_lor_b) /* Length Out of Range */
++#define IS_RCV_CES_ERR(X) (((X) & (1<<ETHRX_ces_b)) >> ETHRX_ces_b) /* Preamble error */
++#define RCVPKT_LENGTH(X) (((X) & ETHRX_length_m) >> ETHRX_length_b) /* Length of the received packet */
++
++#endif //__IDT_RC32438_ETH_V_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_gpio.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_gpio.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_gpio.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_gpio.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,257 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Definitions for IDT RC32438 GPIO.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++#ifndef __IDT_RC32438_GPIO_H__
++#define __IDT_RC32438_GPIO_H__
++enum
++{
++ GPIO0_PhysicalAddress = 0x18048000,
++ GPIO_PhysicalAddress = GPIO0_PhysicalAddress, // Default
++
++ GPIO0_VirtualAddress = 0xb8048000,
++ GPIO_VirtualAddress = GPIO0_VirtualAddress, // Default
++} ;
++
++typedef struct
++{
++ u32 gpiofunc; /* GPIO Function Register
++ * gpiofunc[x]==0 bit = gpio
++ * func[x]==1 bit = altfunc
++ */
++ u32 gpiocfg; /* GPIO Configuration Register
++ * gpiocfg[x]==0 bit = input
++ * gpiocfg[x]==1 bit = output
++ */
++ u32 gpiod; /* GPIO Data Register
++ * gpiod[x] read/write gpio pinX status
++ */
++ u32 gpioilevel; /* GPIO Interrupt Status Register
++ * interrupt level (see gpioistat)
++ */
++ u32 gpioistat; /* Gpio Interrupt Status Register
++ * istat[x] = (gpiod[x] == level[x])
++ * cleared in ISR (STICKY bits)
++ */
++ u32 gpionmien; /* GPIO Non-maskable Interrupt Enable Register */
++} volatile * GPIO_t ;
++
++typedef enum
++{
++ GPIO_gpio_v = 0, // gpiofunc use pin as GPIO.
++ GPIO_alt_v = 1, // gpiofunc use pin as alt.
++ GPIO_input_v = 0, // gpiocfg use pin as input.
++ GPIO_output_v = 1, // gpiocfg use pin as output.
++ GPIO_pin0_b = 0,
++ GPIO_pin0_m = 0x00000001,
++ GPIO_pin1_b = 1,
++ GPIO_pin1_m = 0x00000002,
++ GPIO_pin2_b = 2,
++ GPIO_pin2_m = 0x00000004,
++ GPIO_pin3_b = 3,
++ GPIO_pin3_m = 0x00000008,
++ GPIO_pin4_b = 4,
++ GPIO_pin4_m = 0x00000010,
++ GPIO_pin5_b = 5,
++ GPIO_pin5_m = 0x00000020,
++ GPIO_pin6_b = 6,
++ GPIO_pin6_m = 0x00000040,
++ GPIO_pin7_b = 7,
++ GPIO_pin7_m = 0x00000080,
++ GPIO_pin8_b = 8,
++ GPIO_pin8_m = 0x00000100,
++ GPIO_pin9_b = 9,
++ GPIO_pin9_m = 0x00000200,
++ GPIO_pin10_b = 10,
++ GPIO_pin10_m = 0x00000400,
++ GPIO_pin11_b = 11,
++ GPIO_pin11_m = 0x00000800,
++ GPIO_pin12_b = 12,
++ GPIO_pin12_m = 0x00001000,
++ GPIO_pin13_b = 13,
++ GPIO_pin13_m = 0x00002000,
++ GPIO_pin14_b = 14,
++ GPIO_pin14_m = 0x00004000,
++ GPIO_pin15_b = 15,
++ GPIO_pin15_m = 0x00008000,
++ GPIO_pin16_b = 16,
++ GPIO_pin16_m = 0x00010000,
++ GPIO_pin17_b = 17,
++ GPIO_pin17_m = 0x00020000,
++ GPIO_pin18_b = 18,
++ GPIO_pin18_m = 0x00040000,
++ GPIO_pin19_b = 19,
++ GPIO_pin19_m = 0x00080000,
++ GPIO_pin20_b = 20,
++ GPIO_pin20_m = 0x00100000,
++ GPIO_pin21_b = 21,
++ GPIO_pin21_m = 0x00200000,
++ GPIO_pin22_b = 22,
++ GPIO_pin22_m = 0x00400000,
++ GPIO_pin23_b = 23,
++ GPIO_pin23_m = 0x00800000,
++ GPIO_pin24_b = 24,
++ GPIO_pin24_m = 0x01000000,
++ GPIO_pin25_b = 25,
++ GPIO_pin25_m = 0x02000000,
++ GPIO_pin26_b = 26,
++ GPIO_pin26_m = 0x04000000,
++ GPIO_pin27_b = 27,
++ GPIO_pin27_m = 0x08000000,
++ GPIO_pin28_b = 28,
++ GPIO_pin28_m = 0x10000000,
++ GPIO_pin29_b = 29,
++ GPIO_pin29_m = 0x20000000,
++ GPIO_pin30_b = 30,
++ GPIO_pin30_m = 0x40000000,
++ GPIO_pin31_b = 31,
++ GPIO_pin31_m = 0x80000000,
++
++// Alternate function pins. Corrsponding gpiofunc bit set to GPIO_alt_v.
++
++ GPIO_u0sout_b = GPIO_pin0_b, // UART 0 serial out.
++ GPIO_u0sout_m = GPIO_pin0_m,
++ GPIO_u0sout_cfg_v = GPIO_output_v,
++ GPIO_u0sinp_b = GPIO_pin1_b, // UART 0 serial in.
++ GPIO_u0sinp_m = GPIO_pin1_m,
++ GPIO_u0sinp_cfg_v = GPIO_input_v,
++ GPIO_u0rin_b = GPIO_pin2_b, // UART 0 ring indic.
++ GPIO_u0rin_m = GPIO_pin2_m,
++ GPIO_u0rin_cfg_v = GPIO_input_v,
++ GPIO_u0dcdn_b = GPIO_pin3_b, // UART 0 data carr.det.
++ GPIO_u0dcdn_m = GPIO_pin3_m,
++ GPIO_u0dcdn_cfg_v = GPIO_input_v,
++ GPIO_u0dtrn_b = GPIO_pin4_b, // UART 0 data term rdy.
++ GPIO_u0dtrn_m = GPIO_pin4_m,
++ GPIO_u0dtrn_cfg_v = GPIO_output_v,
++ GPIO_u0dsrn_b = GPIO_pin5_b, // UART 0 data set rdy.
++ GPIO_u0dsrn_m = GPIO_pin5_m,
++ GPIO_u0dsrn_cfg_v = GPIO_input_v,
++ GPIO_u0rtsn_b = GPIO_pin6_b, // UART 0 req. to send.
++ GPIO_u0rtsn_m = GPIO_pin6_m,
++ GPIO_u0rtsn_cfg_v = GPIO_output_v,
++ GPIO_u0ctsn_b = GPIO_pin7_b, // UART 0 clear to send.
++ GPIO_u0ctsn_m = GPIO_pin7_m,
++ GPIO_u0ctsn_cfg_v = GPIO_input_v,
++
++ GPIO_u1sout_b = GPIO_pin8_b, // UART 1 serial out.
++ GPIO_u1sout_m = GPIO_pin8_m,
++ GPIO_u1sout_cfg_v = GPIO_output_v,
++ GPIO_u1sinp_b = GPIO_pin9_b, // UART 1 serial in.
++ GPIO_u1sinp_m = GPIO_pin9_m,
++ GPIO_u1sinp_cfg_v = GPIO_input_v,
++ GPIO_u1dtrn_b = GPIO_pin10_b, // UART 1 data term rdy.
++ GPIO_u1dtrn_m = GPIO_pin10_m,
++ GPIO_u1dtrn_cfg_v = GPIO_output_v,
++ GPIO_u1dsrn_b = GPIO_pin11_b, // UART 1 data set rdy.
++ GPIO_u1dsrn_m = GPIO_pin11_m,
++ GPIO_u1dsrn_cfg_v = GPIO_input_v,
++ GPIO_u1rtsn_b = GPIO_pin12_b, // UART 1 req. to send.
++ GPIO_u1rtsn_m = GPIO_pin12_m,
++ GPIO_u1rtsn_cfg_v = GPIO_output_v,
++ GPIO_u1ctsn_b = GPIO_pin13_b, // UART 1 clear to send.
++ GPIO_u1ctsn_m = GPIO_pin13_m,
++ GPIO_u1ctsn_cfg_v = GPIO_input_v,
++
++ GPIO_dmareqn0_b = GPIO_pin14_b, // Ext. DMA 0 request
++ GPIO_dmareqn0_m = GPIO_pin14_m,
++ GPIO_dmareqn0_cfg_v = GPIO_input_v,
++
++ GPIO_dmareqn1_b = GPIO_pin15_b, // Ext. DMA 1 request
++ GPIO_dmareqn1_m = GPIO_pin15_m,
++ GPIO_dmareqn1_cfg_v = GPIO_input_v,
++
++ GPIO_dmadonen0_b = GPIO_pin16_b, // Ext. DMA 0 done
++ GPIO_dmadonen0_m = GPIO_pin16_m,
++ GPIO_dmadonen0_cfg_v = GPIO_input_v,
++
++ GPIO_dmadonen1_b = GPIO_pin17_b, // Ext. DMA 1 done
++ GPIO_dmadonen1_m = GPIO_pin17_m,
++ GPIO_dmadonen1_cfg_v = GPIO_input_v,
++
++ GPIO_dmafinn0_b = GPIO_pin18_b, // Ext. DMA 0 finished
++ GPIO_dmafinn0_m = GPIO_pin18_m,
++ GPIO_dmafinn0_cfg_v = GPIO_output_v,
++
++ GPIO_dmafinn1_b = GPIO_pin19_b, // Ext. DMA 1 finished
++ GPIO_dmafinn1_m = GPIO_pin19_m,
++ GPIO_dmafinn1_cfg_v = GPIO_output_v,
++
++ GPIO_maddr22_b = GPIO_pin20_b, // M&P bus bit 22.
++ GPIO_maddr22_m = GPIO_pin20_m,
++ GPIO_maddr22_cfg_v = GPIO_output_v,
++
++ GPIO_maddr23_b = GPIO_pin21_b, // M&P bus bit 23.
++ GPIO_maddr23_m = GPIO_pin21_m,
++ GPIO_maddr23_cfg_v = GPIO_output_v,
++
++ GPIO_maddr24_b = GPIO_pin22_b, // M&P bus bit 24.
++ GPIO_maddr24_m = GPIO_pin22_m,
++ GPIO_maddr24_cfg_v = GPIO_output_v,
++
++ GPIO_maddr25_b = GPIO_pin23_b, // M&P bus bit 25.
++ GPIO_maddr25_m = GPIO_pin23_m,
++ GPIO_maddr25_cfg_v = GPIO_output_v,
++
++ GPIO_afspare6_b = GPIO_pin24_b, // reserved.
++ GPIO_afspare6_m = GPIO_pin24_m,
++ GPIO_afspare6_cfg_v = GPIO_input_v,
++ GPIO_afspare5_b = GPIO_pin25_b, // reserved.
++ GPIO_afspare5_m = GPIO_pin25_m,
++ GPIO_afspare5_cfg_v = GPIO_input_v,
++ GPIO_afspare4_b = GPIO_pin26_b, // reserved.
++ GPIO_afspare4_m = GPIO_pin26_m,
++ GPIO_afspare4_cfg_v = GPIO_input_v,
++ GPIO_afspare3_b = GPIO_pin27_b, // reserved.
++ GPIO_afspare3_m = GPIO_pin27_m,
++ GPIO_afspare3_cfg_v = GPIO_input_v,
++ GPIO_afspare2_b = GPIO_pin28_b, // reserved.
++ GPIO_afspare2_m = GPIO_pin28_m,
++ GPIO_afspare2_cfg_v = GPIO_input_v,
++ GPIO_afspare1_b = GPIO_pin29_b, // reserved.
++ GPIO_afspare1_m = GPIO_pin29_m,
++ GPIO_afspare1_cfg_v = GPIO_input_v,
++
++ GPIO_pcimuintn_b = GPIO_pin30_b, // PCI messaging int.
++ GPIO_pcimuintn_m = GPIO_pin30_m,
++ GPIO_pcimuintn_cfg_v = GPIO_output_v,
++
++ GPIO_rngclk_b = GPIO_pin31_b, // RNG external clock
++ GPIO_rngclk_m = GPIO_pin31_m,
++ GPIO_rncclk_cfg_v = GPIO_input_v,
++} GPIO_DEFS_t;
++
++#endif //__IDT_RC32438_GPIO_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,152 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Definitions for IDT RC32438 CPU.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RC32438_H__
++#define __IDT_RC32438_H__
++#include <linux/config.h>
++#include <linux/delay.h>
++#include <asm/io.h>
++#include <asm/idt-boards/rc32438/rc32438_timer.h>
++
++#define RC32438_REG_BASE 0x18000000
++
++#define interrupt ((volatile INT_t ) INT0_VirtualAddress)
++#define idttimer ((volatile TIM_t) TIM0_VirtualAddress)
++#define idt_gpio ((volatile GPIO_t) GPIO0_VirtualAddress)
++
++#define IDT_CLOCK_MULT 2
++#define MIPS_CPU_TIMER_IRQ 7
++/* Interrupt Controller */
++#define IC_GROUP0_PEND (RC32438_REG_BASE + 0x38000)
++#define IC_GROUP0_MASK (RC32438_REG_BASE + 0x38008)
++#define IC_GROUP_OFFSET 0x0C
++#define RTC_BASE 0xAC0801FF0
++
++#define NUM_INTR_GROUPS 5
++/* 16550 UARTs */
++
++#define GROUP0_IRQ_BASE 8 /* GRP2 IRQ numbers start here */
++#define GROUP1_IRQ_BASE (GROUP0_IRQ_BASE + 32) /* GRP3 IRQ numbers start here */
++#define GROUP2_IRQ_BASE (GROUP1_IRQ_BASE + 32) /* GRP4 IRQ numbers start here */
++#define GROUP3_IRQ_BASE (GROUP2_IRQ_BASE + 32) /* GRP5 IRQ numbers start here */
++#define GROUP4_IRQ_BASE (GROUP3_IRQ_BASE + 32)
++
++#ifdef __MIPSEB__
++#define RC32438_UART0_BASE (RC32438_REG_BASE + 0x50003)
++#define RC32438_UART1_BASE (RC32438_REG_BASE + 0x50023)
++#else
++#define RC32438_UART0_BASE (RC32438_REG_BASE + 0x50000)
++#define RC32438_UART1_BASE (RC32438_REG_BASE + 0x50020)
++#endif
++
++#define RC32438_UART0_IRQ GROUP3_IRQ_BASE + 0
++#define RC32438_UART1_IRQ GROUP3_IRQ_BASE + 3
++
++#define RC32438_NR_IRQS (GROUP4_IRQ_BASE + 32)
++
++
++
++/* cpu pipeline flush */
++static inline void rc32438_sync(void)
++{
++ __asm__ volatile ("sync");
++}
++
++static inline void rc32438_sync_udelay(int us)
++{
++ __asm__ volatile ("sync");
++ udelay(us);
++}
++
++static inline void rc32438_sync_delay(int ms)
++{
++ __asm__ volatile ("sync");
++ mdelay(ms);
++}
++
++/*
++ * Macros to access internal RC32438 registers. No byte
++ * swapping should be done when accessing the internal
++ * registers.
++ */
++
++#define rc32438_readb __raw_readb
++#define rc32438_readw __raw_readw
++#define rc32438_readl __raw_readl
++
++#define rc32438_writeb __raw_writeb
++#define rc32438_writew __raw_writew
++#define rc32438_writel __raw_writel
++
++/*
++ * C access to CLZ and CLO instructions
++ * (count leading zeroes/ones).
++ */
++static inline int rc32438_clz(unsigned long val)
++{
++ int ret;
++ __asm__ volatile (
++ ".set\tnoreorder\n\t"
++ ".set\tnoat\n\t"
++ ".set\tmips32\n\t"
++ "clz\t%0,%1\n\t"
++ ".set\tmips0\n\t"
++ ".set\tat\n\t"
++ ".set\treorder"
++ : "=r" (ret)
++ : "r" (val));
++
++ return ret;
++}
++static inline int rc32438_clo(unsigned long val)
++{
++ int ret;
++ __asm__ volatile (
++ ".set\tnoreorder\n\t"
++ ".set\tnoat\n\t"
++ ".set\tmips32\n\t"
++ "clo\t%0,%1\n\t"
++ ".set\tmips0\n\t"
++ ".set\tat\n\t"
++ ".set\treorder"
++ : "=r" (ret)
++ : "r" (val));
++
++ return ret;
++}
++#endif //__IDT_RC32438_H__
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_pci.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_pci.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_pci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_pci.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,510 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Definitions for IDT RC32438 PCI.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++enum
++{
++ PCI0_PhysicalAddress = 0x18080000,
++ PCI_PhysicalAddress = PCI0_PhysicalAddress,
++
++ PCI0_VirtualAddress = 0xb8080000,
++ PCI_VirtualAddress = PCI0_VirtualAddress,
++} ;
++
++enum
++{
++ PCI_LbaCount = 4, // Local base addresses.
++} ;
++
++typedef struct
++{
++ u32 a ; // Address.
++ u32 c ; // Control.
++ u32 m ; // mapping.
++} PCI_Map_s ;
++
++typedef struct
++{
++ u32 pcic ;
++ u32 pcis ;
++ u32 pcism ;
++ u32 pcicfga ;
++ u32 pcicfgd ;
++ PCI_Map_s pcilba [PCI_LbaCount] ;
++ u32 pcidac ;
++ u32 pcidas ;
++ u32 pcidasm ;
++ u32 pcidad ;
++ u32 pcidma8c ;
++ u32 pcidma9c ;
++ u32 pcitc ;
++} volatile *PCI_t ;
++
++// PCI messaging unit.
++enum
++{
++ PCIM_Count = 2,
++} ;
++typedef struct
++{
++ u32 pciim [PCIM_Count] ;
++ u32 pciom [PCIM_Count] ;
++ u32 pciid ;
++ u32 pciiic ;
++ u32 pciiim ;
++ u32 pciiod ;
++ u32 pciioic ;
++ u32 pciioim ;
++} volatile *PCIM_t ;
++
++/*******************************************************************************
++ *
++ * PCI Control Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCIC_en_b = 0,
++ PCIC_en_m = 0x00000001,
++ PCIC_tnr_b = 1,
++ PCIC_tnr_m = 0x00000002,
++ PCIC_sce_b = 2,
++ PCIC_sce_m = 0x00000004,
++ PCIC_ien_b = 3,
++ PCIC_ien_m = 0x00000008,
++ PCIC_aaa_b = 4,
++ PCIC_aaa_m = 0x00000010,
++ PCIC_eap_b = 5,
++ PCIC_eap_m = 0x00000020,
++ PCIC_pcim_b = 6,
++ PCIC_pcim_m = 0x000001c0,
++ PCIC_pcim_disabled_v = 0,
++ PCIC_pcim_tnr_v = 1, // Satellite - target not ready
++ PCIC_pcim_suspend_v = 2, // Satellite - suspended CPU.
++ PCIC_pcim_extern_v = 3, // Host - external arbiter.
++ PCIC_pcim_fixed_v = 4, // Host - fixed priority arb.
++ PCIC_pcim_roundrobin_v = 5, // Host - round robin priority.
++ PCIC_pcim_reserved6_v = 6,
++ PCIC_pcim_reserved7_v = 7,
++ PCIC_igm_b = 9,
++ PCIC_igm_m = 0x00000200,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Status Register
++ *
++ ******************************************************************************/
++enum {
++ PCIS_eed_b = 0,
++ PCIS_eed_m = 0x00000001,
++ PCIS_wr_b = 1,
++ PCIS_wr_m = 0x00000002,
++ PCIS_nmi_b = 2,
++ PCIS_nmi_m = 0x00000004,
++ PCIS_ii_b = 3,
++ PCIS_ii_m = 0x00000008,
++ PCIS_cwe_b = 4,
++ PCIS_cwe_m = 0x00000010,
++ PCIS_cre_b = 5,
++ PCIS_cre_m = 0x00000020,
++ PCIS_mdpe_b = 6,
++ PCIS_mdpe_m = 0x00000040,
++ PCIS_sta_b = 7,
++ PCIS_sta_m = 0x00000080,
++ PCIS_rta_b = 8,
++ PCIS_rta_m = 0x00000100,
++ PCIS_rma_b = 9,
++ PCIS_rma_m = 0x00000200,
++ PCIS_sse_b = 10,
++ PCIS_sse_m = 0x00000400,
++ PCIS_ose_b = 11,
++ PCIS_ose_m = 0x00000800,
++ PCIS_pe_b = 12,
++ PCIS_pe_m = 0x00001000,
++ PCIS_tae_b = 13,
++ PCIS_tae_m = 0x00002000,
++ PCIS_rle_b = 14,
++ PCIS_rle_m = 0x00004000,
++ PCIS_bme_b = 15,
++ PCIS_bme_m = 0x00008000,
++ PCIS_prd_b = 16,
++ PCIS_prd_m = 0x00010000,
++ PCIS_rip_b = 17,
++ PCIS_rip_m = 0x00020000,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Status Mask Register
++ *
++ ******************************************************************************/
++enum {
++ PCISM_eed_b = 0,
++ PCISM_eed_m = 0x00000001,
++ PCISM_wr_b = 1,
++ PCISM_wr_m = 0x00000002,
++ PCISM_nmi_b = 2,
++ PCISM_nmi_m = 0x00000004,
++ PCISM_ii_b = 3,
++ PCISM_ii_m = 0x00000008,
++ PCISM_cwe_b = 4,
++ PCISM_cwe_m = 0x00000010,
++ PCISM_cre_b = 5,
++ PCISM_cre_m = 0x00000020,
++ PCISM_mdpe_b = 6,
++ PCISM_mdpe_m = 0x00000040,
++ PCISM_sta_b = 7,
++ PCISM_sta_m = 0x00000080,
++ PCISM_rta_b = 8,
++ PCISM_rta_m = 0x00000100,
++ PCISM_rma_b = 9,
++ PCISM_rma_m = 0x00000200,
++ PCISM_sse_b = 10,
++ PCISM_sse_m = 0x00000400,
++ PCISM_ose_b = 11,
++ PCISM_ose_m = 0x00000800,
++ PCISM_pe_b = 12,
++ PCISM_pe_m = 0x00001000,
++ PCISM_tae_b = 13,
++ PCISM_tae_m = 0x00002000,
++ PCISM_rle_b = 14,
++ PCISM_rle_m = 0x00004000,
++ PCISM_bme_b = 15,
++ PCISM_bme_m = 0x00008000,
++ PCISM_prd_b = 16,
++ PCISM_prd_m = 0x00010000,
++ PCISM_rip_b = 17,
++ PCISM_rip_m = 0x00020000,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Configuration Address Register
++ *
++ ******************************************************************************/
++enum {
++ PCICFGA_reg_b = 2,
++ PCICFGA_reg_m = 0x000000fc,
++ PCICFGA_reg_id_v = 0x00>>2, //use PCFGID_
++ PCICFGA_reg_04_v = 0x04>>2, //use PCFG04_
++ PCICFGA_reg_08_v = 0x08>>2, //use PCFG08_
++ PCICFGA_reg_0C_v = 0x0C>>2, //use PCFG0C_
++ PCICFGA_reg_pba0_v = 0x10>>2, //use PCIPBA_
++ PCICFGA_reg_pba1_v = 0x14>>2, //use PCIPBA_
++ PCICFGA_reg_pba2_v = 0x18>>2, //use PCIPBA_
++ PCICFGA_reg_pba3_v = 0x1c>>2, //use PCIPBA_
++ PCICFGA_reg_subsystem_v = 0x2c>>2, //use PCFGSS_
++ PCICFGA_reg_3C_v = 0x3C>>2, //use PCFG3C_
++ PCICFGA_reg_pba0c_v = 0x44>>2, //use PCIPBAC_
++ PCICFGA_reg_pba0m_v = 0x48>>2,
++ PCICFGA_reg_pba1c_v = 0x4c>>2, //use PCIPBAC_
++ PCICFGA_reg_pba1m_v = 0x50>>2,
++ PCICFGA_reg_pba2c_v = 0x54>>2, //use PCIPBAC_
++ PCICFGA_reg_pba2m_v = 0x58>>2,
++ PCICFGA_reg_pba3c_v = 0x5c>>2, //use PCIPBAC_
++ PCICFGA_reg_pba3m_v = 0x60>>2,
++ PCICFGA_reg_pmgt_v = 0x64>>2,
++ PCICFGA_func_b = 8,
++ PCICFGA_func_m = 0x00000700,
++ PCICFGA_dev_b = 11,
++ PCICFGA_dev_m = 0x0000f800,
++ PCICFGA_dev_internal_v = 0,
++ PCICFGA_bus_b = 16,
++ PCICFGA_bus_m = 0x00ff0000,
++ PCICFGA_bus_type0_v = 0, //local bus
++ PCICFGA_en_b = 31, // read only
++ PCICFGA_en_m = 0x80000000,
++} ;
++
++enum {
++ PCFGID_vendor_b = 0,
++ PCFGID_vendor_m = 0x0000ffff,
++ PCFGID_vendor_IDT_v = 0x111d,
++ PCFGID_device_b = 16,
++ PCFGID_device_m = 0xffff0000,
++ PCFGID_device_Acaciade_v = 0x0207,
++
++ PCFG04_command_ioena_b = 1,
++ PCFG04_command_ioena_m = 0x00000001,
++ PCFG04_command_memena_b = 2,
++ PCFG04_command_memena_m = 0x00000002,
++ PCFG04_command_bmena_b = 3,
++ PCFG04_command_bmena_m = 0x00000004,
++ PCFG04_command_mwinv_b = 5,
++ PCFG04_command_mwinv_m = 0x00000010,
++ PCFG04_command_parena_b = 7,
++ PCFG04_command_parena_m = 0x00000040,
++ PCFG04_command_serrena_b = 9,
++ PCFG04_command_serrena_m = 0x00000100,
++ PCFG04_command_fastbbena_b = 10,
++ PCFG04_command_fastbbena_m = 0x00000200,
++ PCFG04_status_b = 16,
++ PCFG04_status_m = 0xffff0000,
++ PCFG04_status_66MHz_b = 21, // 66 MHz enable
++ PCFG04_status_66MHz_m = 0x00200000,
++ PCFG04_status_fbb_b = 23,
++ PCFG04_status_fbb_m = 0x00800000,
++ PCFG04_status_mdpe_b = 24,
++ PCFG04_status_mdpe_m = 0x01000000,
++ PCFG04_status_dst_b = 25,
++ PCFG04_status_dst_m = 0x06000000,
++ PCFG04_status_sta_b = 27,
++ PCFG04_status_sta_m = 0x08000000,
++ PCFG04_status_rta_b = 28,
++ PCFG04_status_rta_m = 0x10000000,
++ PCFG04_status_rma_b = 29,
++ PCFG04_status_rma_m = 0x20000000,
++ PCFG04_status_sse_b = 30,
++ PCFG04_status_sse_m = 0x40000000,
++ PCFG04_status_pe_b = 31,
++ PCFG04_status_pe_m = 0x40000000,
++
++ PCFG08_revId_b = 0,
++ PCFG08_revId_m = 0x000000ff,
++ PCFG08_classCode_b = 0,
++ PCFG08_classCode_m = 0xffffff00,
++ PCFG08_classCode_bridge_v = 06,
++ PCFG08_classCode_proc_v = 0x0b3000, // processor-MIPS
++ PCFG0C_cacheline_b = 0,
++ PCFG0C_cacheline_m = 0x000000ff,
++ PCFG0C_masterLatency_b = 8,
++ PCFG0C_masterLatency_m = 0x0000ff00,
++ PCFG0C_headerType_b = 16,
++ PCFG0C_headerType_m = 0x00ff0000,
++ PCFG0C_bist_b = 24,
++ PCFG0C_bist_m = 0xff000000,
++
++ PCIPBA_msi_b = 0,
++ PCIPBA_msi_m = 0x00000001,
++ PCIPBA_p_b = 3,
++ PCIPBA_p_m = 0x00000004,
++ PCIPBA_baddr_b = 8,
++ PCIPBA_baddr_m = 0xffffff00,
++
++ PCFGSS_vendorId_b = 0,
++ PCFGSS_vendorId_m = 0x0000ffff,
++ PCFGSS_id_b = 16,
++ PCFGSS_id_m = 0xffff0000,
++
++ PCFG3C_interruptLine_b = 0,
++ PCFG3C_interruptLine_m = 0x000000ff,
++ PCFG3C_interruptPin_b = 8,
++ PCFG3C_interruptPin_m = 0x0000ff00,
++ PCFG3C_minGrant_b = 16,
++ PCFG3C_minGrant_m = 0x00ff0000,
++ PCFG3C_maxLat_b = 24,
++ PCFG3C_maxLat_m = 0xff000000,
++
++ PCIPBAC_msi_b = 0,
++ PCIPBAC_msi_m = 0x00000001,
++ PCIPBAC_p_b = 1,
++ PCIPBAC_p_m = 0x00000002,
++ PCIPBAC_size_b = 2,
++ PCIPBAC_size_m = 0x0000007c,
++ PCIPBAC_sb_b = 7,
++ PCIPBAC_sb_m = 0x00000080,
++ PCIPBAC_pp_b = 8,
++ PCIPBAC_pp_m = 0x00000100,
++ PCIPBAC_mr_b = 9,
++ PCIPBAC_mr_m = 0x00000600,
++ PCIPBAC_mr_read_v =0, //no prefetching
++ PCIPBAC_mr_readLine_v =1,
++ PCIPBAC_mr_readMult_v =2,
++ PCIPBAC_mrl_b = 11,
++ PCIPBAC_mrl_m = 0x00000800,
++ PCIPBAC_mrm_b = 12,
++ PCIPBAC_mrm_m = 0x00001000,
++ PCIPBAC_trp_b = 13,
++ PCIPBAC_trp_m = 0x00002000,
++
++ PCFG40_trdyTimeout_b = 0,
++ PCFG40_trdyTimeout_m = 0x000000ff,
++ PCFG40_retryLim_b = 8,
++ PCFG40_retryLim_m = 0x0000ff00,
++};
++
++/*******************************************************************************
++ *
++ * PCI Local Base Address [0|1|2|3] Register
++ *
++ ******************************************************************************/
++enum {
++ PCILBA_baddr_b = 0, // In PCI_t -> pcilba [] .a
++ PCILBA_baddr_m = 0xffffff00,
++} ;
++/*******************************************************************************
++ *
++ * PCI Local Base Address Control Register
++ *
++ ******************************************************************************/
++enum {
++ PCILBAC_msi_b = 0, // In pPci->pcilba[i].c
++ PCILBAC_msi_m = 0x00000001,
++ PCILBAC_msi_mem_v = 0,
++ PCILBAC_msi_io_v = 1,
++ PCILBAC_size_b = 2, // In pPci->pcilba[i].c
++ PCILBAC_size_m = 0x0000007c,
++ PCILBAC_sb_b = 7, // In pPci->pcilba[i].c
++ PCILBAC_sb_m = 0x00000080,
++ PCILBAC_rt_b = 8, // In pPci->pcilba[i].c
++ PCILBAC_rt_m = 0x00000100,
++ PCILBAC_rt_noprefetch_v = 0, // mem read
++ PCILBAC_rt_prefetch_v = 1, // mem readline
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Local Base Address [0|1|2|3] Mapping Register
++ *
++ ******************************************************************************/
++enum {
++ PCILBAM_maddr_b = 8,
++ PCILBAM_maddr_m = 0xffffff00,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Decoupled Access Control Register
++ *
++ ******************************************************************************/
++enum {
++ PCIDAC_den_b = 0,
++ PCIDAC_den_m = 0x00000001,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Decoupled Access Status Register
++ *
++ ******************************************************************************/
++enum {
++ PCIDAS_d_b = 0,
++ PCIDAS_d_m = 0x00000001,
++ PCIDAS_b_b = 1,
++ PCIDAS_b_m = 0x00000002,
++ PCIDAS_e_b = 2,
++ PCIDAS_e_m = 0x00000004,
++ PCIDAS_ofe_b = 3,
++ PCIDAS_ofe_m = 0x00000008,
++ PCIDAS_off_b = 4,
++ PCIDAS_off_m = 0x00000010,
++ PCIDAS_ife_b = 5,
++ PCIDAS_ife_m = 0x00000020,
++ PCIDAS_iff_b = 6,
++ PCIDAS_iff_m = 0x00000040,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI DMA Channel 8 Configuration Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCIDMA8C_mbs_b = 0, // Maximum Burst Size.
++ PCIDMA8C_mbs_m = 0x00000fff, // { pcidma8c }
++ PCIDMA8C_our_b = 12, // Optimize Unaligned Burst Reads.
++ PCIDMA8C_our_m = 0x00001000, // { pcidma8c }
++} ;
++
++/*******************************************************************************
++ *
++ * PCI DMA Channel 9 Configuration Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCIDMA9C_mbs_b = 0, // Maximum Burst Size.
++ PCIDMA9C_mbs_m = 0x00000fff, // { pcidma9c }
++} ;
++
++/*******************************************************************************
++ *
++ * PCI to Memory(DMA Channel 8) AND Memory to PCI DMA(DMA Channel 9)Descriptors
++ *
++ ******************************************************************************/
++enum {
++ PCIDMAD_pt_b = 22, // in DEVCMD field (descriptor)
++ PCIDMAD_pt_m = 0x00c00000, // preferred transaction field
++ // These are for reads (DMA channel 8)
++ PCIDMAD_devcmd_mr_v = 0, //memory read
++ PCIDMAD_devcmd_mrl_v = 1, //memory read line
++ PCIDMAD_devcmd_mrm_v = 2, //memory read multiple
++ PCIDMAD_devcmd_ior_v = 3, //I/O read
++ // These are for writes (DMA channel 9)
++ PCIDMAD_devcmd_mw_v = 0, //memory write
++ PCIDMAD_devcmd_mwi_v = 1, //memory write invalidate
++ PCIDMAD_devcmd_iow_v = 3, //I/O write
++
++ // Swap byte field applies to both DMA channel 8 and 9
++ PCIDMAD_sb_b = 24, // in DEVCMD field (descriptor)
++ PCIDMAD_sb_m = 0x01000000, // swap byte field
++} ;
++
++
++/*******************************************************************************
++ *
++ * PCI Target Control Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCITC_rtimer_b = 0, // In PCITC_t -> pcitc
++ PCITC_rtimer_m = 0x000000ff,
++ PCITC_dtimer_b = 8, // In PCITC_t -> pcitc
++ PCITC_dtimer_m = 0x0000ff00,
++ PCITC_rdr_b = 18, // In PCITC_t -> pcitc
++ PCITC_rdr_m = 0x00040000,
++ PCITC_ddt_b = 19, // In PCITC_t -> pcitc
++ PCITC_ddt_m = 0x00080000,
++} ;
++/*******************************************************************************
++ *
++ * PCI messaging unit [applies to both inbound and outbound registers ]
++ *
++ ******************************************************************************/
++enum
++{
++ PCIM_m0_b = 0, // In PCIM_t -> {pci{iic,iim,ioic,ioim}}
++ PCIM_m0_m = 0x00000001, // inbound or outbound message 0
++ PCIM_m1_b = 1, // In PCIM_t -> {pci{iic,iim,ioic,ioim}}
++ PCIM_m1_m = 0x00000002, // inbound or outbound message 1
++ PCIM_db_b = 2, // In PCIM_t -> {pci{iic,iim,ioic,ioim}}
++ PCIM_db_m = 0x00000004, // inbound or outbound doorbell
++};
++
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_pci_v.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_pci_v.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_pci_v.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_pci_v.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,190 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Definitions for IDT RC32438 PCI setup.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#define PCI_MSG_VirtualAddress 0xB8088010
++#define rc32438_pci ((volatile PCI_t) PCI0_VirtualAddress)
++#define rc32438_pci_msg ((volatile PCIM_t) PCI_MSG_VirtualAddress)
++
++#define PCIM_SHFT 0x6
++#define PCIM_BIT_LEN 0x7
++#define PCIM_H_EA 0x3
++#define PCIM_H_IA_FIX 0x4
++#define PCIM_H_IA_RR 0x5
++
++#define PCI_ADDR_START 0x50000000
++
++#define CPUTOPCI_MEM_WIN 0x02000000
++#define CPUTOPCI_IO_WIN 0x00100000
++#define PCILBA_SIZE_SHFT 2
++#define PCILBA_SIZE_MASK 0x1F
++#define SIZE_256MB 0x1C
++#define SIZE_128MB 0x1B
++#define SIZE_64MB 0x1A
++#define SIZE_32MB 0x19
++#define SIZE_16MB 0x18
++#define SIZE_4MB 0x16
++#define SIZE_2MB 0x15
++#define SIZE_1MB 0x14
++#define ACACIA_CONFIG0_ADDR 0x80000000
++#define ACACIA_CONFIG1_ADDR 0x80000004
++#define ACACIA_CONFIG2_ADDR 0x80000008
++#define ACACIA_CONFIG3_ADDR 0x8000000C
++#define ACACIA_CONFIG4_ADDR 0x80000010
++#define ACACIA_CONFIG5_ADDR 0x80000014
++#define ACACIA_CONFIG6_ADDR 0x80000018
++#define ACACIA_CONFIG7_ADDR 0x8000001C
++#define ACACIA_CONFIG8_ADDR 0x80000020
++#define ACACIA_CONFIG9_ADDR 0x80000024
++#define ACACIA_CONFIG10_ADDR 0x80000028
++#define ACACIA_CONFIG11_ADDR 0x8000002C
++#define ACACIA_CONFIG12_ADDR 0x80000030
++#define ACACIA_CONFIG13_ADDR 0x80000034
++#define ACACIA_CONFIG14_ADDR 0x80000038
++#define ACACIA_CONFIG15_ADDR 0x8000003C
++#define ACACIA_CONFIG16_ADDR 0x80000040
++#define ACACIA_CONFIG17_ADDR 0x80000044
++#define ACACIA_CONFIG18_ADDR 0x80000048
++#define ACACIA_CONFIG19_ADDR 0x8000004C
++#define ACACIA_CONFIG20_ADDR 0x80000050
++#define ACACIA_CONFIG21_ADDR 0x80000054
++#define ACACIA_CONFIG22_ADDR 0x80000058
++#define ACACIA_CONFIG23_ADDR 0x8000005C
++#define ACACIA_CONFIG24_ADDR 0x80000060
++#define ACACIA_CONFIG25_ADDR 0x80000064
++#define ACACIA_CMD (PCFG04_command_ioena_m | \
++ PCFG04_command_memena_m | \
++ PCFG04_command_bmena_m | \
++ PCFG04_command_mwinv_m | \
++ PCFG04_command_parena_m | \
++ PCFG04_command_serrena_m )
++
++#define ACACIA_STAT (PCFG04_status_mdpe_m | \
++ PCFG04_status_sta_m | \
++ PCFG04_status_rta_m | \
++ PCFG04_status_rma_m | \
++ PCFG04_status_sse_m | \
++ PCFG04_status_pe_m)
++
++#define ACACIA_CNFG1 ((ACACIA_STAT<<16)|ACACIA_CMD)
++
++#define ACACIA_REVID 0
++#define ACACIA_CLASS_CODE 0
++#define ACACIA_CNFG2 ((ACACIA_CLASS_CODE<<8) | \
++ ACACIA_REVID)
++
++#define ACACIA_CACHE_LINE_SIZE 4
++#define ACACIA_MASTER_LAT 0x3c
++#define ACACIA_HEADER_TYPE 0
++#define ACACIA_BIST 0
++
++#define ACACIA_CNFG3 ((ACACIA_BIST << 24) | \
++ (ACACIA_HEADER_TYPE<<16) | \
++ (ACACIA_MASTER_LAT<<8) | \
++ ACACIA_CACHE_LINE_SIZE )
++
++#define ACACIA_BAR0 0x00000008 /* 128 MB Memory */
++#define ACACIA_BAR1 0x18800001 /* 1 MB IO */
++#define ACACIA_BAR2 0x18000001 /* 2 MB IO window for Acacia
++ internal Registers */
++#define ACACIA_BAR3 0x48000008 /* Spare 128 MB Memory */
++
++#define ACACIA_CNFG4 ACACIA_BAR0
++#define ACACIA_CNFG5 ACACIA_BAR1
++#define ACACIA_CNFG6 ACACIA_BAR2
++#define ACACIA_CNFG7 ACACIA_BAR3
++
++#define ACACIA_SUBSYS_VENDOR_ID 0
++#define ACACIA_SUBSYSTEM_ID 0
++#define ACACIA_CNFG8 0
++#define ACACIA_CNFG9 0
++#define ACACIA_CNFG10 0
++#define ACACIA_CNFG11 ((ACACIA_SUBSYS_VENDOR_ID<<16) | \
++ ACACIA_SUBSYSTEM_ID)
++#define ACACIA_INT_LINE 1
++#define ACACIA_INT_PIN 1
++#define ACACIA_MIN_GNT 8
++#define ACACIA_MAX_LAT 0x38
++#define ACACIA_CNFG12 0
++#define ACACIA_CNFG13 0
++#define ACACIA_CNFG14 0
++#define ACACIA_CNFG15 ((ACACIA_MAX_LAT<<24) | \
++ (ACACIA_MIN_GNT<<16) | \
++ (ACACIA_INT_PIN<<8) | \
++ ACACIA_INT_LINE)
++#define ACACIA_RETRY_LIMIT 0x80
++#define ACACIA_TRDY_LIMIT 0x80
++#define ACACIA_CNFG16 ((ACACIA_RETRY_LIMIT<<8) | \
++ ACACIA_TRDY_LIMIT)
++#define PCI_PBAxC_R 0x0
++#define PCI_PBAxC_RL 0x1
++#define PCI_PBAxC_RM 0x2
++#define SIZE_SHFT 2
++
++#define ACACIA_PBA0C ( PCIPBAC_mrl_m | PCIPBAC_sb_m | \
++ ((PCI_PBAxC_RM &0x3) << PCIPBAC_mr_b) | \
++ PCIPBAC_pp_m | \
++ (SIZE_128MB<<SIZE_SHFT) | \
++ PCIPBAC_p_m)
++
++#define ACACIA_CNFG17 ACACIA_PBA0C
++#define ACACIA_PBA0M 0x0
++#define ACACIA_CNFG18 ACACIA_PBA0M
++
++#define ACACIA_PBA1C ((SIZE_1MB<<SIZE_SHFT) | PCIPBAC_sb_m | \
++ PCIPBAC_msi_m)
++
++#define ACACIA_CNFG19 ACACIA_PBA1C
++#define ACACIA_PBA1M 0x0
++#define ACACIA_CNFG20 ACACIA_PBA1M
++
++#define ACACIA_PBA2C ((SIZE_2MB<<SIZE_SHFT) | PCIPBAC_sb_m | \
++ PCIPBAC_msi_m)
++
++#define ACACIA_CNFG21 ACACIA_PBA2C
++#define ACACIA_PBA2M 0x18000000
++#define ACACIA_CNFG22 ACACIA_PBA2M
++#define ACACIA_PBA3C 0
++#define ACACIA_CNFG23 ACACIA_PBA3C
++#define ACACIA_PBA3M 0
++#define ACACIA_CNFG24 ACACIA_PBA3M
++
++
++
++#define PCITC_DTIMER_VAL 8
++#define PCITC_RTIMER_VAL 0x10
++
+diff -Nur linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_timer.h linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_timer.h
+--- linux-2.6.17/include/asm-mips/idt-boards/rc32438/rc32438_timer.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/asm-mips/idt-boards/rc32438/rc32438_timer.h 2006-06-18 12:44:28.000000000 +0200
+@@ -0,0 +1,91 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Timer register definition IDT RC32438 CPU.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 P. Sadik.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_RC32438_TIM_H__
++#define __IDT_RC32438_TIM_H__
++
++enum
++{
++ TIM0_PhysicalAddress = 0x18028000,
++ TIM_PhysicalAddress = TIM0_PhysicalAddress, // Default
++
++ TIM0_VirtualAddress = 0xb8028000,
++ TIM_VirtualAddress = TIM0_VirtualAddress, // Default
++} ;
++
++enum
++{
++ TIM_Count = 3,
++} ;
++
++struct TIM_CNTR_s
++{
++ u32 count ;
++ u32 compare ;
++ u32 ctc ; //use CTC_
++} ;
++
++typedef struct TIM_s
++{
++ struct TIM_CNTR_s tim [TIM_Count] ;
++ u32 rcount ; //use RCOUNT_
++ u32 rcompare ; //use RCOMPARE_
++ u32 rtc ; //use RTC_
++} volatile * TIM_t ;
++
++enum
++{
++ CTC_en_b = 0,
++ CTC_en_m = 0x00000001,
++ CTC_to_b = 1,
++ CTC_to_m = 0x00000002,
++
++ RCOUNT_count_b = 0,
++ RCOUNT_count_m = 0x0000ffff,
++ RCOMPARE_compare_b = 0,
++ RCOMPARE_compare_m = 0x0000ffff,
++ RTC_ce_b = 0,
++ RTC_ce_m = 0x00000001,
++ RTC_to_b = 1,
++ RTC_to_m = 0x00000002,
++ RTC_rqe_b = 2,
++ RTC_rqe_m = 0x00000004,
++
++} ;
++#endif //__IDT_RC32438_TIM_H__
++
+diff -Nur linux-2.6.17/include/asm-mips/mach-generic/irq.h linux-2.6.17-owrt/include/asm-mips/mach-generic/irq.h
+--- linux-2.6.17/include/asm-mips/mach-generic/irq.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/asm-mips/mach-generic/irq.h 2006-06-18 12:44:28.000000000 +0200
+@@ -8,6 +8,6 @@
+ #ifndef __ASM_MACH_GENERIC_IRQ_H
+ #define __ASM_MACH_GENERIC_IRQ_H
+
+-#define NR_IRQS 128
++#define NR_IRQS 256
+
+ #endif /* __ASM_MACH_GENERIC_IRQ_H */
+diff -Nur linux-2.6.17/include/linux/kernel.h linux-2.6.17-owrt/include/linux/kernel.h
+--- linux-2.6.17/include/linux/kernel.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/linux/kernel.h 2006-06-18 12:44:28.000000000 +0200
+@@ -329,6 +329,7 @@
+ };
+
+ /* Force a compilation error if condition is true */
++extern void BUILD_BUG(void);
+ #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+
+ /* Trap pasters of __FUNCTION__ at compile-time */
diff --git a/target/linux/aruba-2.6/patches/001-flash.patch b/target/linux/aruba-2.6/patches/001-flash.patch
new file mode 100644
index 0000000..f0b9513
--- /dev/null
+++ b/target/linux/aruba-2.6/patches/001-flash.patch
@@ -0,0 +1,159 @@
+diff -Nur linux-2.6.15/arch/mips/aruba/flash_lock.c linux-2.6.15-openwrt/arch/mips/aruba/flash_lock.c
+--- linux-2.6.15/arch/mips/aruba/flash_lock.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-openwrt/arch/mips/aruba/flash_lock.c 2006-01-10 00:32:32.000000000 +0100
+@@ -0,0 +1,27 @@
++#include <linux/module.h>
++#include <linux/types.h>
++#include <asm/bootinfo.h>
++
++#define AP70_PROT_ADDR 0xb8010008
++#define AP70_PROT_DATA 0x8
++#define AP60_PROT_ADDR 0xB8400000
++#define AP60_PROT_DATA 0x04000000
++
++void unlock_ap60_70_flash(void)
++{
++ volatile __u32 val;
++ switch (mips_machtype) {
++ case MACH_ARUBA_AP70:
++ val = *(volatile __u32 *)AP70_PROT_ADDR;
++ val &= ~(AP70_PROT_DATA);
++ *(volatile __u32 *)AP70_PROT_ADDR = val;
++ break;
++ case MACH_ARUBA_AP65:
++ case MACH_ARUBA_AP60:
++ default:
++ val = *(volatile __u32 *)AP60_PROT_ADDR;
++ val &= ~(AP60_PROT_DATA);
++ *(volatile __u32 *)AP60_PROT_ADDR = val;
++ break;
++ }
++}
+diff -Nur linux-2.6.15/drivers/mtd/chips/cfi_probe.c linux-2.6.15-openwrt/drivers/mtd/chips/cfi_probe.c
+--- linux-2.6.15/drivers/mtd/chips/cfi_probe.c 2006-01-03 04:21:10.000000000 +0100
++++ linux-2.6.15-openwrt/drivers/mtd/chips/cfi_probe.c 2006-01-10 00:32:32.000000000 +0100
+@@ -26,6 +26,74 @@
+ static void print_cfi_ident(struct cfi_ident *);
+ #endif
+
++#if 1
++
++#define AMD_AUTOSEL_OFF1 0xAAA
++#define AMD_AUTOSEL_OFF2 0x555
++#define AMD_MANUF_ID 0x1
++#define AMD_DEVICE_ID1 0xF6 /* T */
++#define AMD_DEVICE_ID2 0xF9 /* B */
++/* Foll. are definitions for Macronix Flash Part */
++#define MCX_MANUF_ID 0xC2
++#define MCX_DEVICE_ID1 0xA7
++#define MCX_DEVICE_ID2 0xA8
++/* Foll. common to both AMD and Macronix */
++#define FACTORY_LOCKED 0x99
++#define USER_LOCKED 0x19
++
++/* NOTE: AP-70/6x use BYTE mode flash access. Therefore the
++ * lowest Addr. pin in the flash is not A0 but A-1 (A minus 1).
++ * CPU's A0 is tied to Flash's A-1, A1 to A0 and so on. This
++ * gives 4MB of byte-addressable mem. In byte mode, all addr
++ * need to be multiplied by 2 (i.e compared to word mode).
++ * NOTE: AMD_AUTOSEL_OFF1 and OFF2 are already mult. by 2
++ * Just blindly use the addr offsets suggested in the manual
++ * for byte mode and you'll be OK. Offs. in Table 6 need to
++ * be mult by 2 (for getting autosel params)
++ */
++void
++flash_detect(struct map_info *map, __u32 base, struct cfi_private *cfi)
++{
++ map_word val[3];
++ int osf = cfi->interleave * cfi->device_type; // =2 for AP70/6x
++ char *manuf, *part, *lock ;
++
++ if (osf != 1) return ;
++
++ cfi_send_gen_cmd(0xAA, AMD_AUTOSEL_OFF1, base, map, cfi, cfi->device_type, NULL);
++ cfi_send_gen_cmd(0x55, AMD_AUTOSEL_OFF2, base, map, cfi, cfi->device_type, NULL);
++ cfi_send_gen_cmd(0x90, AMD_AUTOSEL_OFF1, base, map, cfi, cfi->device_type, NULL);
++ val[0] = map_read(map, base) ; // manuf ID
++ val[1] = map_read(map, base+2) ; // device ID
++ val[2] = map_read(map, base+6) ; // lock indicator
++#if 0
++printk("v1=0x%x v2=0x%x v3=0x%x\n", val[0], val[1], val[2]) ;
++#endif
++ if (val[0].x[0] == AMD_MANUF_ID) {
++ manuf = "AMD Flash" ;
++ if (val[1].x[0] == AMD_DEVICE_ID1)
++ part = "AM29LV320D (Top)" ;
++ else if (val[1].x[0] == AMD_DEVICE_ID2)
++ part = "AM29LV320D (Bot)" ;
++ else part = "Unknown" ;
++ } else if (val[0].x[0] == MCX_MANUF_ID) {
++ manuf = "Macronix Flash" ;
++ if (val[1].x[0] == MCX_DEVICE_ID1)
++ part = "MX29LV320A (Top)" ;
++ else if (val[1].x[0] == MCX_DEVICE_ID2)
++ part = "MX29LV320A (Bot)" ;
++ else part = "Unknown" ;
++ } else
++ return ;
++ if (val[2].x[0] == FACTORY_LOCKED)
++ lock = "Factory Locked" ;
++ else if (val[2].x[0] == USER_LOCKED)
++ lock = "User Locked" ;
++ else lock = "Unknown locking" ;
++ printk("%s %s (%s)\n", manuf, part, lock) ;
++}
++#endif
++
+ static int cfi_probe_chip(struct map_info *map, __u32 base,
+ unsigned long *chip_map, struct cfi_private *cfi);
+ static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi);
+@@ -118,6 +186,10 @@
+ }
+
+ xip_disable();
++#if 1
++ //cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
++ flash_detect(map, base, cfi) ;
++#endif
+ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
+diff -Nur linux-2.6.15/drivers/mtd/maps/physmap.c linux-2.6.15-openwrt/drivers/mtd/maps/physmap.c
+--- linux-2.6.15/drivers/mtd/maps/physmap.c 2006-01-03 04:21:10.000000000 +0100
++++ linux-2.6.15-openwrt/drivers/mtd/maps/physmap.c 2006-01-10 00:32:32.000000000 +0100
+@@ -34,15 +34,31 @@
+ static struct mtd_partition *mtd_parts;
+ static int mtd_parts_nb;
+
+-static int num_physmap_partitions;
+-static struct mtd_partition *physmap_partitions;
++static int num_physmap_partitions = 3;
++static struct mtd_partition physmap_partitions[] = {
++ {
++ name: "zImage",
++ size: 0x3f0000-0x80000,
++ offset: 0x80000,
++ },
++ {
++ name: "JFFS2",
++ size: 0x3f0000-0x120000,
++ offset: 0x120000,
++ },
++ {
++ name: "NVRAM",
++ size: 0x2000,
++ offset: 0x3f8000,
++ }
++};
+
+ static const char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL};
+
+ void physmap_set_partitions(struct mtd_partition *parts, int num_parts)
+ {
+- physmap_partitions=parts;
+- num_physmap_partitions=num_parts;
++// physmap_partitions=parts;
++// num_physmap_partitions=num_parts;
+ }
+ #endif /* CONFIG_MTD_PARTITIONS */
+
diff --git a/target/linux/aruba-2.6/patches/002-irq.patch b/target/linux/aruba-2.6/patches/002-irq.patch
new file mode 100644
index 0000000..f6b9425
--- /dev/null
+++ b/target/linux/aruba-2.6/patches/002-irq.patch
@@ -0,0 +1,286 @@
+diff -Nur linux-2.6.17/arch/mips/aruba/irq.c linux-2.6.17-openwrt/arch/mips/aruba/irq.c
+--- linux-2.6.17/arch/mips/aruba/irq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-openwrt/arch/mips/aruba/irq.c 2006-10-12 14:32:40.026285000 -0700
+@@ -0,0 +1,282 @@
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/kernel_stat.h>
++#include <linux/module.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/timex.h>
++#include <linux/slab.h>
++#include <linux/random.h>
++#include <linux/delay.h>
++
++#include <asm/bitops.h>
++#include <asm/bootinfo.h>
++#include <asm/io.h>
++#include <asm/mipsregs.h>
++#include <asm/system.h>
++#include <asm/idt-boards/rc32434/rc32434.h>
++#include <asm/idt-boards/rc32434/rc32434_gpio.h>
++
++#include <asm/irq.h>
++
++extern void aruba_timer_interrupt(struct pt_regs *regs);
++
++typedef struct {
++ u32 mask;
++ volatile u32 *base_addr;
++} intr_group_t;
++
++static const intr_group_t intr_group_merlot[NUM_INTR_GROUPS] = {
++ {0x00000000, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0)},
++};
++
++#define READ_PEND_MERLOT(base) (*((volatile unsigned long *)(0xbc003010)))
++#define READ_MASK_MERLOT(base) (*((volatile unsigned long *)(0xbc003014)))
++#define WRITE_MASK_MERLOT(base, val) ((*((volatile unsigned long *)(0xbc003014))) = (val), READ_MASK_MERLOT())
++
++static const intr_group_t intr_group_muscat[NUM_INTR_GROUPS] = {
++ {0x0000efff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET)},
++ {0x00001fff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 1 * IC_GROUP_OFFSET)},
++ {0x00000007, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 2 * IC_GROUP_OFFSET)},
++ {0x0003ffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 3 * IC_GROUP_OFFSET)},
++ {0xffffffff, (u32 *) KSEG1ADDR(IC_GROUP0_PEND + 4 * IC_GROUP_OFFSET)}
++};
++
++#define READ_PEND_MUSCAT(base) (*(base))
++#define READ_MASK_MUSCAT(base) (*(base + 2))
++#define WRITE_MASK_MUSCAT(base, val) (*(base + 2) = (val))
++
++static inline int group_to_ip(unsigned int group)
++{
++ switch (mips_machtype) {
++ case MACH_ARUBA_AP70:
++ return group + 2;
++ case MACH_ARUBA_AP65:
++ case MACH_ARUBA_AP60:
++ default:
++ return 6;
++ }
++}
++
++static inline void enable_local_irq(unsigned int irq)
++{
++ clear_c0_cause(0x100 << irq);
++ set_c0_status(0x100 << irq);
++ irq_enable_hazard();
++}
++
++static inline void disable_local_irq(unsigned int irq)
++{
++ clear_c0_status(0x100 << irq);
++ clear_c0_cause(0x100 << irq);
++ irq_disable_hazard();
++}
++
++static inline void aruba_irq_enable(unsigned int irq)
++{
++ unsigned long flags;
++ unsigned int group, intr_bit;
++ volatile unsigned int *addr;
++
++ local_irq_save(flags);
++
++ if (irq < GROUP0_IRQ_BASE) {
++ enable_local_irq(irq);
++ } else {
++ int ip = irq - GROUP0_IRQ_BASE;
++ switch (mips_machtype) {
++ case MACH_ARUBA_AP70:
++ // irqs are in groups of 32
++ // ip is set to the remainder
++ group = ip >> 5;
++ ip &= 0x1f;
++
++ // bit -> 0 = unmask
++ intr_bit = 1 << ip;
++ addr = intr_group_muscat[group].base_addr;
++ WRITE_MASK_MUSCAT(addr, READ_MASK_MUSCAT(addr) & ~intr_bit);
++ break;
++
++ case MACH_ARUBA_AP65:
++ case MACH_ARUBA_AP60:
++ group = 0;
++
++ // bit -> 1 = unmasked
++ intr_bit = 1 << ip;
++ addr = intr_group_merlot[group].base_addr;
++ WRITE_MASK_MERLOT(addr, READ_MASK_MERLOT(addr) | intr_bit);
++ break;
++ }
++ enable_local_irq(group_to_ip(group));
++ }
++
++ back_to_back_c0_hazard();
++ local_irq_restore(flags);
++}
++
++static void aruba_irq_disable(unsigned int irq)
++{
++ unsigned long flags;
++ unsigned int group, intr_bit, mask;
++ volatile unsigned int *addr;
++
++ local_irq_save(flags);
++
++ if (irq < GROUP0_IRQ_BASE) {
++ disable_local_irq(irq);
++ } else {
++ int ip = irq - GROUP0_IRQ_BASE;
++ switch (mips_machtype) {
++ case MACH_ARUBA_AP70:
++ idt_gpio->gpioistat &= ~(1 << ip);
++
++ // irqs are in groups of 32
++ // ip is set to the remainder
++ group = ip >> 5;
++ ip &= 0x1f;
++
++ // bit -> 1 = mask
++ intr_bit = 1 << ip;
++ addr = intr_group_muscat[group].base_addr;
++
++ mask = READ_MASK_MUSCAT(addr);
++ mask |= intr_bit;
++ WRITE_MASK_MUSCAT(addr, mask);
++
++ if (mask == intr_group_muscat[group].mask) {
++ disable_local_irq(group_to_ip(group));
++ }
++ break;
++
++ case MACH_ARUBA_AP65:
++ case MACH_ARUBA_AP60:
++ group = 0;
++
++ // bit -> 0 = masked
++ intr_bit = 1 << ip;
++ addr = intr_group_merlot[group].base_addr;
++
++ mask = READ_MASK_MERLOT(addr);
++ mask &= ~intr_bit;
++ WRITE_MASK_MERLOT(addr, mask);
++
++ if (mask == intr_group_merlot[group].mask) {
++ disable_local_irq(group_to_ip(group));
++ }
++ break;
++ }
++ }
++
++ back_to_back_c0_hazard();
++ local_irq_restore(flags);
++}
++
++static unsigned int aruba_irq_startup(unsigned int irq)
++{
++ aruba_irq_enable(irq);
++ return 0;
++}
++
++#define aruba_irq_shutdown aruba_irq_disable
++
++static void aruba_irq_ack(unsigned int irq)
++{
++ aruba_irq_disable(irq);
++}
++
++static void aruba_irq_end(unsigned int irq)
++{
++ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
++ aruba_irq_enable(irq);
++}
++
++static struct hw_interrupt_type aruba_irq_type = {
++ .typename = "ARUBA",
++ .startup = aruba_irq_startup,
++ .shutdown = aruba_irq_shutdown,
++ .enable = aruba_irq_enable,
++ .disable = aruba_irq_disable,
++ .ack = aruba_irq_ack,
++ .end = aruba_irq_end,
++};
++
++void __init arch_init_irq(void)
++{
++ int i;
++ printk("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS);
++ memset(irq_desc, 0, sizeof(irq_desc));
++
++ for (i = 0; i < RC32434_NR_IRQS; i++) {
++ irq_desc[i].status = IRQ_DISABLED;
++ irq_desc[i].action = NULL;
++ irq_desc[i].depth = 1;
++ irq_desc[i].handler = &aruba_irq_type;
++ spin_lock_init(&irq_desc[i].lock);
++ }
++}
++
++/* Main Interrupt dispatcher */
++
++void plat_irq_dispatch(struct pt_regs *regs)
++{
++ unsigned int pend, group, ip;
++ volatile unsigned int *addr;
++ unsigned long cp0_cause = read_c0_cause() & read_c0_status() & CAUSEF_IP;
++
++ if (cp0_cause & CAUSEF_IP7)
++ return aruba_timer_interrupt(regs);
++
++ if(cp0_cause == 0) {
++ printk("INTERRUPT(S) FIRED WHILE MASKED\n");
++#ifdef ARUBA_DEBUG
++ // debuging use -- figure out which interrupt(s) fired
++ cp0_cause = read_c0_cause() & CAUSEF_IP;
++ while (cp0_cause) {
++ unsigned long intr_bit;
++ unsigned int irq_nr;
++ intr_bit = (31 - rc32434_clz(cp0_cause));
++ irq_nr = intr_bit - GROUP0_IRQ_BASE;
++ printk(" ---> MASKED IRQ %d\n",irq_nr);
++ cp0_cause &= ~(1 << intr_bit);
++ }
++#endif
++ return;
++ }
++
++ switch (mips_machtype) {
++ case MACH_ARUBA_AP70:
++ if ((ip = (cp0_cause & 0x7c00))) {
++ group = 21 - rc32434_clz(ip);
++
++ addr = intr_group_muscat[group].base_addr;
++
++ pend = READ_PEND_MUSCAT(addr);
++ pend &= ~READ_MASK_MUSCAT(addr); // only unmasked interrupts
++ pend = 39 - rc32434_clz(pend);
++ do_IRQ(pend + (group << 5), regs);
++ }
++ break;
++ case MACH_ARUBA_AP65:
++ case MACH_ARUBA_AP60:
++ default:
++ if (cp0_cause & 0x4000) { // 1 << (8 +6) == irq 6
++ // Misc Interrupt
++ group = 0;
++
++ addr = intr_group_merlot[group].base_addr;
++
++ pend = READ_PEND_MERLOT(addr);
++ pend &= READ_MASK_MERLOT(addr); // only unmasked interrupts
++ pend = 31 - rc32434_clz(pend);
++ do_IRQ(pend + GROUP0_IRQ_BASE, regs);
++ }
++ if ((ip = (cp0_cause & 0x3c00))) { // irq 2-5
++ pend = 31 - rc32434_clz(ip);
++ do_IRQ(pend - GROUP0_IRQ_BASE, regs);
++ }
++ break;
++ }
++}
diff --git a/target/linux/aruba-2.6/patches/003-pci.patch b/target/linux/aruba-2.6/patches/003-pci.patch
new file mode 100644
index 0000000..0cad12a
--- /dev/null
+++ b/target/linux/aruba-2.6/patches/003-pci.patch
@@ -0,0 +1,618 @@
+diff -Nur linux-2.6.15/arch/mips/pci/fixup-aruba.c linux-2.6.15-openwrt/arch/mips/pci/fixup-aruba.c
+--- linux-2.6.15/arch/mips/pci/fixup-aruba.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-openwrt/arch/mips/pci/fixup-aruba.c 2006-01-10 00:34:41.000000000 +0100
+@@ -0,0 +1,115 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * PCI fixups for IDT EB434 board
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <asm/idt-boards/rc32434/rc32434.h>
++#include <asm/idt-boards/rc32434/rc32434_pci.h>
++
++int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++
++ if (dev->bus->number != 0) {
++ return 0;
++ }
++
++ slot = PCI_SLOT(dev->devfn);
++ dev->irq = 0;
++
++ if (slot > 0 && slot <= 15) {
++#if 1
++ if(slot == 10) {
++ if(pin == 1) dev->irq = GROUP4_IRQ_BASE + 9; // intA
++ } else if(slot == 11) {
++ if(pin == 1) dev->irq = GROUP4_IRQ_BASE + 10; // intA
++ if(pin == 2) dev->irq = GROUP4_IRQ_BASE + 10; // intA
++ if(pin == 3) dev->irq = GROUP4_IRQ_BASE + 10; // intA
++ } else if(slot == 12) {
++ if(pin == 1) dev->irq = GROUP4_IRQ_BASE + 11; // intA
++ if(pin == 2) dev->irq = GROUP4_IRQ_BASE + 12; // intB
++ } else if (slot == 13) {
++ if(pin == 1) dev->irq = GROUP4_IRQ_BASE + 12; // intA
++ if(pin == 2) dev->irq = GROUP4_IRQ_BASE + 11; // intB
++ } else {
++ dev->irq = GROUP4_IRQ_BASE + 11;
++ }
++#else
++ switch (pin) {
++ case 1: /* INTA*/
++ dev->irq = GROUP4_IRQ_BASE + 11;
++ break;
++ case 2: /* INTB */
++ dev->irq = GROUP4_IRQ_BASE + 11;
++ break;
++ case 3: /* INTC */
++ dev->irq = GROUP4_IRQ_BASE + 11;
++ break;
++ case 4: /* INTD */
++ dev->irq = GROUP4_IRQ_BASE + 11;
++ break;
++ default:
++ dev->irq = 0xff;
++ break;
++ }
++#endif
++#ifdef DEBUG
++ printk("irq fixup: slot %d, pin %d, irq %d\n",
++ slot, pin, dev->irq);
++#endif
++ pci_write_config_byte(dev, PCI_INTERRUPT_LINE,dev->irq);
++ }
++ return (dev->irq);
++}
++
++struct pci_fixup pcibios_fixups[] = {
++ {0}
++};
++
++
++
++
++
++
++
++
++
++
++
+diff -Nur linux-2.6.15/arch/mips/pci/Makefile linux-2.6.15-openwrt/arch/mips/pci/Makefile
+--- linux-2.6.15/arch/mips/pci/Makefile 2006-01-03 04:21:10.000000000 +0100
++++ linux-2.6.15-openwrt/arch/mips/pci/Makefile 2006-01-10 00:32:32.000000000 +0100
+@@ -56,3 +56,4 @@
+ obj-$(CONFIG_TOSHIBA_RBTX4938) += fixup-tx4938.o ops-tx4938.o
+ obj-$(CONFIG_VICTOR_MPC30X) += fixup-mpc30x.o
+ obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capcella.o
++obj-$(CONFIG_MACH_ARUBA) += fixup-aruba.o ops-aruba.o pci-aruba.o
+diff -Nur linux-2.6.15/arch/mips/pci/ops-aruba.c linux-2.6.15-openwrt/arch/mips/pci/ops-aruba.c
+--- linux-2.6.15/arch/mips/pci/ops-aruba.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-openwrt/arch/mips/pci/ops-aruba.c 2006-01-10 00:32:32.000000000 +0100
+@@ -0,0 +1,204 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * pci_ops for IDT EB434 board
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++
++#include <asm/cpu.h>
++#include <asm/io.h>
++
++#include <asm/idt-boards/rc32434/rc32434.h>
++#include <asm/idt-boards/rc32434/rc32434_pci.h>
++
++#define PCI_ACCESS_READ 0
++#define PCI_ACCESS_WRITE 1
++
++
++#define PCI_CFG_SET(slot,func,off) \
++ (rc32434_pci->pcicfga = (0x80000000 | ((slot)<<11) | \
++ ((func)<<8) | (off)))
++
++static int config_access(unsigned char access_type, struct pci_bus *bus,
++ unsigned int devfn, unsigned char where,
++ u32 * data)
++{
++ /*
++ * config cycles are on 4 byte boundary only
++ */
++ unsigned int slot = PCI_SLOT(devfn);
++ u8 func = PCI_FUNC(devfn);
++
++ if (slot < 2 || slot > 15) {
++ *data = 0xFFFFFFFF;
++ return -1;
++ }
++ /* Setup address */
++ PCI_CFG_SET(slot, func, where);
++ rc32434_sync();
++
++ if (access_type == PCI_ACCESS_WRITE) {
++ rc32434_sync();
++ rc32434_pci->pcicfgd = *data;
++ } else {
++ rc32434_sync();
++ *data = rc32434_pci->pcicfgd;
++ }
++
++ rc32434_sync();
++
++ return 0;
++}
++
++
++/*
++ * We can't address 8 and 16 bit words directly. Instead we have to
++ * read/write a 32bit word and mask/modify the data we actually want.
++ */
++static int read_config_byte(struct pci_bus *bus, unsigned int devfn,
++ int where, u8 * val)
++{
++ u32 data;
++ int ret;
++
++ ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data);
++ *val = (data >> ((where & 3) << 3)) & 0xff;
++ return ret;
++}
++
++static int read_config_word(struct pci_bus *bus, unsigned int devfn,
++ int where, u16 * val)
++{
++ u32 data;
++ int ret;
++
++ ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data);
++ *val = (data >> ((where & 3) << 3)) & 0xffff;
++ return ret;
++}
++
++static int read_config_dword(struct pci_bus *bus, unsigned int devfn,
++ int where, u32 * val)
++{
++ int ret;
++
++ ret = config_access(PCI_ACCESS_READ, bus, devfn, where, val);
++ return ret;
++}
++
++static int
++write_config_byte(struct pci_bus *bus, unsigned int devfn, int where,
++ u8 val)
++{
++ u32 data = 0;
++
++ if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
++ return -1;
++
++ data = (data & ~(0xff << ((where & 3) << 3))) |
++ (val << ((where & 3) << 3));
++
++ if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
++ return -1;
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++
++static int
++write_config_word(struct pci_bus *bus, unsigned int devfn, int where,
++ u16 val)
++{
++ u32 data = 0;
++
++ if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
++ return -1;
++
++ data = (data & ~(0xffff << ((where & 3) << 3))) |
++ (val << ((where & 3) << 3));
++
++ if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
++ return -1;
++
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++
++static int
++write_config_dword(struct pci_bus *bus, unsigned int devfn, int where,
++ u32 val)
++{
++ if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val))
++ return -1;
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++static int pci_config_read(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 * val)
++{
++ switch (size) {
++ case 1:
++ return read_config_byte(bus, devfn, where, (u8 *) val);
++ case 2:
++ return read_config_word(bus, devfn, where, (u16 *) val);
++ default:
++ return read_config_dword(bus, devfn, where, val);
++ }
++}
++
++static int pci_config_write(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 val)
++{
++ switch (size) {
++ case 1:
++ return write_config_byte(bus, devfn, where, (u8) val);
++ case 2:
++ return write_config_word(bus, devfn, where, (u16) val);
++ default:
++ return write_config_dword(bus, devfn, where, val);
++ }
++}
++
++struct pci_ops rc32434_pci_ops = {
++ .read = pci_config_read,
++ .write = pci_config_write,
++};
+diff -Nur linux-2.6.15/arch/mips/pci/pci-aruba.c linux-2.6.15-openwrt/arch/mips/pci/pci-aruba.c
+--- linux-2.6.15/arch/mips/pci/pci-aruba.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-openwrt/arch/mips/pci/pci-aruba.c 2006-01-10 00:32:32.000000000 +0100
+@@ -0,0 +1,235 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * PCI initialization for IDT EB434 board
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <asm/idt-boards/rc32434/rc32434.h>
++#include <asm/idt-boards/rc32434/rc32434_pci.h>
++
++#define PCI_ACCESS_READ 0
++#define PCI_ACCESS_WRITE 1
++
++#undef DEBUG
++#ifdef DEBUG
++#define DBG(x...) printk(x)
++#else
++#define DBG(x...)
++#endif
++/* define an unsigned array for the PCI registers */
++unsigned int korinaCnfgRegs[25] = {
++ KORINA_CNFG1, KORINA_CNFG2, KORINA_CNFG3, KORINA_CNFG4,
++ KORINA_CNFG5, KORINA_CNFG6, KORINA_CNFG7, KORINA_CNFG8,
++ KORINA_CNFG9, KORINA_CNFG10, KORINA_CNFG11, KORINA_CNFG12,
++ KORINA_CNFG13, KORINA_CNFG14, KORINA_CNFG15, KORINA_CNFG16,
++ KORINA_CNFG17, KORINA_CNFG18, KORINA_CNFG19, KORINA_CNFG20,
++ KORINA_CNFG21, KORINA_CNFG22, KORINA_CNFG23, KORINA_CNFG24
++};
++
++static struct resource rc32434_res_pci_mem2;
++
++static struct resource rc32434_res_pci_mem1 = {
++ .name = "PCI MEM1",
++ .start = 0x50000000,
++ .end = 0x5FFFFFFF,
++ .flags = IORESOURCE_MEM,
++ .child = &rc32434_res_pci_mem2,
++};
++static struct resource rc32434_res_pci_mem2 = {
++ .name = "PCI MEM2",
++ .start = 0x60000000,
++ .end = 0x6FFFFFFF,
++ .flags = IORESOURCE_MEM,
++ .parent = &rc32434_res_pci_mem1,
++};
++static struct resource rc32434_res_pci_io1 = {
++ .name = "PCI I/O1",
++ .start = 0x18800000,
++ .end = 0x188FFFFF,
++ .flags = IORESOURCE_IO,
++};
++
++extern struct pci_ops rc32434_pci_ops;
++
++struct pci_controller rc32434_controller = {
++ .pci_ops = &rc32434_pci_ops,
++ .mem_resource = &rc32434_res_pci_mem1,
++ .io_resource = &rc32434_res_pci_io1,
++ .mem_offset = 0x00000000UL,
++ .io_offset = 0x00000000UL,
++};
++
++extern unsigned int arch_has_pci;
++
++static int __init rc32434_pcibridge_init(void)
++{
++
++ unsigned int pciConfigAddr = 0;/*used for writing pci config values */
++ int loopCount=0 ;/*used for the loop */
++
++ unsigned int pcicValue, pcicData=0;
++ unsigned int dummyRead, pciCntlVal = 0;
++
++ if (!arch_has_pci) return 0;
++
++ printk("PCI: Initializing PCI\n");
++
++ /* Disable the IP bus error for PCI scaning */
++ pciCntlVal=rc32434_pci->pcic;
++ pciCntlVal &= 0xFFFFFF7;
++ rc32434_pci->pcic = pciCntlVal;
++
++ ioport_resource.start = rc32434_res_pci_io1.start;
++ ioport_resource.end = rc32434_res_pci_io1.end;
++/*
++ iomem_resource.start = rc32434_res_pci_mem1.start;
++ iomem_resource.end = rc32434_res_pci_mem1.end;
++*/
++
++ pcicValue = rc32434_pci->pcic;
++ pcicValue = (pcicValue >> PCIM_SHFT) & PCIM_BIT_LEN;
++ if (!((pcicValue == PCIM_H_EA) ||
++ (pcicValue == PCIM_H_IA_FIX) ||
++ (pcicValue == PCIM_H_IA_RR))) {
++ /* Not in Host Mode, return ERROR */
++ return -1;
++ }
++
++ /* Enables the Idle Grant mode, Arbiter Parking */
++ pcicData |=(PCIC_igm_m|PCIC_eap_m|PCIC_en_m);
++ rc32434_pci->pcic = pcicData; /* Enable the PCI bus Interface */
++ /* Zero out the PCI status & PCI Status Mask */
++ for(;;) {
++ pcicData = rc32434_pci->pcis;
++ if (!(pcicData & PCIS_rip_m))
++ break;
++ }
++
++ rc32434_pci->pcis = 0;
++ rc32434_pci->pcism = 0xFFFFFFFF;
++ /* Zero out the PCI decoupled registers */
++ rc32434_pci->pcidac=0; /* disable PCI decoupled accesses at initialization */
++ rc32434_pci->pcidas=0; /* clear the status */
++ rc32434_pci->pcidasm=0x0000007F; /* Mask all the interrupts */
++ /* Mask PCI Messaging Interrupts */
++ rc32434_pci_msg->pciiic = 0;
++ rc32434_pci_msg->pciiim = 0xFFFFFFFF;
++ rc32434_pci_msg->pciioic = 0;
++ rc32434_pci_msg->pciioim = 0;
++
++ /* Setup PCILB0 as Memory Window */
++ rc32434_pci->pcilba[0].a = (unsigned int) (PCI_ADDR_START);
++
++ /* setup the PCI map address as same as the local address */
++
++ rc32434_pci->pcilba[0].m = (unsigned int) (PCI_ADDR_START);
++
++ /* Setup PCILBA1 as MEM */
++#ifdef __MIPSEB__
++ rc32434_pci->pcilba[0].c = ( ((SIZE_16MB & 0x1f) << PCILBAC_size_b) | PCILBAC_sb_m);
++#else
++ rc32434_pci->pcilba[0].c = ( ((SIZE_16MB & 0x1f) << PCILBAC_size_b));
++#endif
++ dummyRead = rc32434_pci->pcilba[0].c; /* flush the CPU write Buffers */
++
++ rc32434_pci->pcilba[1].a = 0x60000000;
++
++ rc32434_pci->pcilba[1].m = 0x60000000;
++ /* setup PCILBA2 as IO Window*/
++#ifdef __MIPSEB__
++ rc32434_pci->pcilba[1].c = ( ((SIZE_256MB & 0x1f) << PCILBAC_size_b) | PCILBAC_sb_m);
++#else
++ rc32434_pci->pcilba[1].c = ((SIZE_256MB & 0x1f) << PCILBAC_size_b);
++#endif
++ dummyRead = rc32434_pci->pcilba[1].c; /* flush the CPU write Buffers */
++ rc32434_pci->pcilba[2].a = 0x18C00000;
++
++ rc32434_pci->pcilba[2].m = 0x18FFFFFF;
++ /* setup PCILBA2 as IO Window*/
++#ifdef __MIPSEB__
++ rc32434_pci->pcilba[2].c = ( ((SIZE_4MB & 0x1f) << PCILBAC_size_b) | PCILBAC_sb_m);
++#else
++ rc32434_pci->pcilba[2].c = ((SIZE_4MB & 0x1f) << PCILBAC_size_b);
++#endif
++
++ dummyRead = rc32434_pci->pcilba[2].c; /* flush the CPU write Buffers */
++
++
++ rc32434_pci->pcilba[3].a = 0x18800000;
++
++ rc32434_pci->pcilba[3].m = 0x18800000;
++ /* Setup PCILBA3 as IO Window */
++
++#ifdef __MIPSEB__
++ rc32434_pci->pcilba[3].c = ( (((SIZE_1MB & 0x1ff) << PCILBAC_size_b) | PCILBAC_msi_m) | PCILBAC_sb_m);
++#else
++ rc32434_pci->pcilba[3].c = (((SIZE_1MB & 0x1ff) << PCILBAC_size_b) | PCILBAC_msi_m);
++#endif
++ dummyRead = rc32434_pci->pcilba[2].c; /* flush the CPU write Buffers */
++
++ pciConfigAddr = (unsigned int)(0x80000004);
++ for(loopCount = 0; loopCount < 24; loopCount++){
++ rc32434_pci->pcicfga = pciConfigAddr;
++ dummyRead = rc32434_pci->pcicfga;
++ rc32434_pci->pcicfgd = korinaCnfgRegs[loopCount];
++ dummyRead=rc32434_pci->pcicfgd;
++ pciConfigAddr += 4;
++ }
++ rc32434_pci->pcitc=(unsigned int)((PCITC_RTIMER_VAL&0xff) << PCITC_rtimer_b) |
++ ((PCITC_DTIMER_VAL&0xff)<<PCITC_dtimer_b);
++
++ pciCntlVal = rc32434_pci->pcic;
++ pciCntlVal &= ~(PCIC_tnr_m);
++ rc32434_pci->pcic = pciCntlVal;
++ pciCntlVal = rc32434_pci->pcic;
++
++ register_pci_controller(&rc32434_controller);
++
++ rc32434_sync();
++ return 0;
++}
++
++arch_initcall(rc32434_pcibridge_init);
++
++/* Do platform specific device initialization at pci_enable_device() time */
++int pcibios_plat_dev_init(struct pci_dev *dev)
++{
++ return 0;
++}
+diff -Nur linux-2.6.15/drivers/pci/access.c linux-2.6.15-openwrt/drivers/pci/access.c
+--- linux-2.6.15/drivers/pci/access.c 2006-01-03 04:21:10.000000000 +0100
++++ linux-2.6.15-openwrt/drivers/pci/access.c 2006-01-10 00:43:10.000000000 +0100
+@@ -21,6 +21,7 @@
+ #define PCI_word_BAD (pos & 1)
+ #define PCI_dword_BAD (pos & 3)
+
++#ifdef __MIPSEB__
+ #define PCI_OP_READ(size,type,len) \
+ int pci_bus_read_config_##size \
+ (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \
+@@ -31,11 +32,32 @@
+ if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
+ spin_lock_irqsave(&pci_lock, flags); \
+ res = bus->ops->read(bus, devfn, pos, len, &data); \
++ if (len == 1) \
++ *value = (type)((data >> 24) & 0xff); \
++ else if (len == 2) \
++ *value = (type)((data >> 16) & 0xffff); \
++ else \
+ *value = (type)data; \
+ spin_unlock_irqrestore(&pci_lock, flags); \
+ return res; \
+ }
++#else
+
++#define PCI_OP_READ(size,type,len) \
++int pci_bus_read_config_##size \
++ (struct pci_bus *bus, unsigned int devfn, int pos, type *value) \
++{ \
++ int res; \
++ unsigned long flags; \
++ u32 data = 0; \
++ if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
++ spin_lock_irqsave(&pci_lock, flags); \
++ res = bus->ops->read(bus, devfn, pos, len, &data); \
++ *value = (type)data; \
++ spin_unlock_irqrestore(&pci_lock, flags); \
++ return res; \
++}
++#endif
+ #define PCI_OP_WRITE(size,type,len) \
+ int pci_bus_write_config_##size \
+ (struct pci_bus *bus, unsigned int devfn, int pos, type value) \
diff --git a/target/linux/aruba-2.6/patches/004-wdt.patch b/target/linux/aruba-2.6/patches/004-wdt.patch
new file mode 100644
index 0000000..15fbffa
--- /dev/null
+++ b/target/linux/aruba-2.6/patches/004-wdt.patch
@@ -0,0 +1,126 @@
+diff -Nur linux-2.6.15.1/drivers/char/watchdog/wdt_merlot.c linux-2.6.15.1-openwrt/drivers/char/watchdog/wdt_merlot.c
+--- linux-2.6.15.1/drivers/char/watchdog/wdt_merlot.c 2006-01-26 21:14:02.204626250 -0800
++++ linux-2.6.15.1-openwrt/drivers/char/watchdog/wdt_merlot.c 2006-02-02 20:31:43.000000000 -0800
+@@ -0,0 +1,110 @@
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/fs.h>
++
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/system.h>
++#include <asm/bootinfo.h>
++
++extern unsigned long mips_machtype;
++
++static unsigned long wdt_is_open;
++static struct timer_list wdt_timer;
++
++static void wdt_merlot_refresh(void)
++{
++ volatile __u32 *wdt;
++ switch (mips_machtype) {
++ case MACH_ARUBA_AP70:
++ wdt = (__u32 *) 0xb8030034;
++ *wdt = 0x10000000;
++ break;
++ default:
++ wdt = (__u32 *) 0xbc00300c;
++ *wdt = 0x40000000;
++ break;
++ }
++}
++
++static void wdt_merlot_timer_fn(unsigned long data)
++{
++ wdt_merlot_refresh();
++ if (!test_bit(1, &wdt_is_open))
++ mod_timer(&wdt_timer, jiffies + HZ);
++}
++
++static int wdt_merlot_setup_timer(void)
++{
++
++ init_timer(&wdt_timer);
++ wdt_timer.function = wdt_merlot_timer_fn;
++ wdt_timer.data = 0;
++ wdt_timer.expires = jiffies + HZ;
++ add_timer(&wdt_timer);
++ return 0;
++}
++
++static int wdt_open(struct inode *inode, struct file *file)
++{
++ if (test_and_set_bit(0, &wdt_is_open))
++ return -EBUSY;
++ set_bit(1, &wdt_is_open);
++ return nonseekable_open(inode, file);
++}
++
++static ssize_t wdt_write(struct file *file, const char __user * buf, size_t count, loff_t * ppos)
++{
++ if (count) /* something was written */
++ wdt_merlot_refresh();
++ return count;
++}
++
++static int wdt_release(struct inode *inode, struct file *file)
++{
++ clear_bit(0, &wdt_is_open);
++ return 0;
++}
++
++static struct file_operations wdt_fops = {
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .write = wdt_write,
++ .open = wdt_open,
++ .release = wdt_release,
++};
++
++static struct miscdevice wdt_miscdev = {
++ .minor = WATCHDOG_MINOR,
++ .name = "watchdog",
++ .fops = &wdt_fops,
++};
++
++static void __exit wdt_exit(void)
++{
++ misc_deregister(&wdt_miscdev);
++}
++
++static int __init wdt_init(void)
++{
++ int ret;
++ ret = misc_register(&wdt_miscdev);
++ if (ret) {
++ printk(KERN_ERR
++ "wdt: cannot register miscdev on minor=%d (err=%d)\n",
++ WATCHDOG_MINOR, ret);
++ misc_deregister(&wdt_miscdev);
++ goto out;
++ }
++ printk("wdt: registered with refresh\n");
++ wdt_merlot_refresh();
++ wdt_merlot_setup_timer();
++ out:
++ return ret;
++}
++
++module_init(wdt_init);
++module_exit(wdt_exit);
+diff -Nur linux-2.6.15.3/drivers/char/watchdog/Makefile linux-2.6.15.3-openwrt/drivers/char/watchdog/Makefile
+--- linux-2.6.15.3/drivers/char/watchdog/Makefile 2006-02-22 10:04:18.596278000 -0800
++++ linux-2.6.15.3-openwrt/drivers/char/watchdog/Makefile 2006-02-22 10:06:21.400960000 -0800
+@@ -71,5 +71,8 @@
+
+ # SPARC64 Architecture
+
++# Aruba Architecture
++obj-$(CONFIG_MACH_ARUBA) += wdt_merlot.o
++
+ # Architecture Independant
+ obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
diff --git a/target/linux/aruba-2.6/patches/010-ar2313_enet.patch b/target/linux/aruba-2.6/patches/010-ar2313_enet.patch
new file mode 100644
index 0000000..d71d96f
--- /dev/null
+++ b/target/linux/aruba-2.6/patches/010-ar2313_enet.patch
@@ -0,0 +1,2175 @@
+diff -Nur linux-2.6.17/drivers/net/ar2313/ar2313.c linux-2.6.17-owrt/drivers/net/ar2313/ar2313.c
+--- linux-2.6.17/drivers/net/ar2313/ar2313.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/drivers/net/ar2313/ar2313.c 2006-06-19 12:57:27.000000000 +0200
+@@ -0,0 +1,1649 @@
++/*
++ * ar2313.c: Linux driver for the Atheros AR2313 Ethernet device.
++ *
++ * Copyright 2004 by Sameer Dekate, <sdekate@arubanetworks.com>.
++ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * Thanks to Atheros for providing hardware and documentation
++ * enabling me to write this driver.
++ *
++ * 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.
++ *
++ * Additional credits:
++ * This code is taken from John Taylor's Sibyte driver and then
++ * modified for the AR2313.
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++#include <linux/pci.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/mm.h>
++#include <linux/highmem.h>
++#include <linux/sockios.h>
++#include <linux/pkt_sched.h>
++#include <linux/compile.h>
++#include <linux/mii.h>
++#include <linux/ethtool.h>
++#include <linux/ctype.h>
++
++#include <net/sock.h>
++#include <net/ip.h>
++
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/byteorder.h>
++#include <asm/uaccess.h>
++#include <asm/bootinfo.h>
++
++extern char *getenv(char *e);
++
++
++#undef INDEX_DEBUG
++#define DEBUG 0
++#define DEBUG_TX 0
++#define DEBUG_RX 0
++#define DEBUG_INT 0
++#define DEBUG_MC 0
++#define DEBUG_ERR 1
++
++#ifndef __exit
++#define __exit
++#endif
++
++#ifndef min
++#define min(a,b) (((a)<(b))?(a):(b))
++#endif
++
++#ifndef SMP_CACHE_BYTES
++#define SMP_CACHE_BYTES L1_CACHE_BYTES
++#endif
++
++#ifndef SET_MODULE_OWNER
++#define SET_MODULE_OWNER(dev) {do{} while(0);}
++#define AR2313_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
++#define AR2313_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
++#else
++#define AR2313_MOD_INC_USE_COUNT {do{} while(0);}
++#define AR2313_MOD_DEC_USE_COUNT {do{} while(0);}
++#endif
++
++#define PHYSADDR(a) ((_ACAST32_ (a)) & 0x1fffffff)
++
++static char ethaddr[18] = "00:00:00:00:00:00";
++static char ifname[5] = "bond";
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52)
++module_param_string(ethaddr, ethaddr, 18, 0);
++module_param_string(ifname, ifname, 5, 0);
++#else
++MODULE_PARM(ethaddr, "c18");
++MODULE_PARM(ifname, "c5");
++#endif
++
++#define AR2313_MBOX_SET_BIT 0x8
++
++#define BOARD_IDX_STATIC 0
++#define BOARD_IDX_OVERFLOW -1
++
++/* margot includes */
++#include <asm/idt-boards/rc32434/rc32434.h>
++
++#include "ar2313_msg.h"
++#include "platform.h"
++#include "dma.h"
++#include "ar2313.h"
++
++/*
++ * New interrupt handler strategy:
++ *
++ * An old interrupt handler worked using the traditional method of
++ * replacing an skbuff with a new one when a packet arrives. However
++ * the rx rings do not need to contain a static number of buffer
++ * descriptors, thus it makes sense to move the memory allocation out
++ * of the main interrupt handler and do it in a bottom half handler
++ * and only allocate new buffers when the number of buffers in the
++ * ring is below a certain threshold. In order to avoid starving the
++ * NIC under heavy load it is however necessary to force allocation
++ * when hitting a minimum threshold. The strategy for alloction is as
++ * follows:
++ *
++ * RX_LOW_BUF_THRES - allocate buffers in the bottom half
++ * RX_PANIC_LOW_THRES - we are very low on buffers, allocate
++ * the buffers in the interrupt handler
++ * RX_RING_THRES - maximum number of buffers in the rx ring
++ *
++ * One advantagous side effect of this allocation approach is that the
++ * entire rx processing can be done without holding any spin lock
++ * since the rx rings and registers are totally independent of the tx
++ * ring and its registers. This of course includes the kmalloc's of
++ * new skb's. Thus start_xmit can run in parallel with rx processing
++ * and the memory allocation on SMP systems.
++ *
++ * Note that running the skb reallocation in a bottom half opens up
++ * another can of races which needs to be handled properly. In
++ * particular it can happen that the interrupt handler tries to run
++ * the reallocation while the bottom half is either running on another
++ * CPU or was interrupted on the same CPU. To get around this the
++ * driver uses bitops to prevent the reallocation routines from being
++ * reentered.
++ *
++ * TX handling can also be done without holding any spin lock, wheee
++ * this is fun! since tx_csm is only written to by the interrupt
++ * handler.
++ */
++
++/*
++ * Threshold values for RX buffer allocation - the low water marks for
++ * when to start refilling the rings are set to 75% of the ring
++ * sizes. It seems to make sense to refill the rings entirely from the
++ * intrrupt handler once it gets below the panic threshold, that way
++ * we don't risk that the refilling is moved to another CPU when the
++ * one running the interrupt handler just got the slab code hot in its
++ * cache.
++ */
++#define RX_RING_SIZE AR2313_DESCR_ENTRIES
++#define RX_PANIC_THRES (RX_RING_SIZE/4)
++#define RX_LOW_THRES ((3*RX_RING_SIZE)/4)
++#define CRC_LEN 4
++#define RX_OFFSET 2
++
++#define AR2313_BUFSIZE (AR2313_MTU + ETH_HLEN + CRC_LEN + RX_OFFSET)
++
++#ifdef MODULE
++MODULE_AUTHOR("Sameer Dekate<sdekate@arubanetworks.com>");
++MODULE_DESCRIPTION("AR2313 Ethernet driver");
++#endif
++
++#if DEBUG
++static char version[] __initdata =
++ "ar2313.c: v0.02 2006/06/19 sdekate@arubanetworks.com\n";
++#endif /* DEBUG */
++
++#define virt_to_phys(x) ((u32)(x) & 0x1fffffff)
++
++// prototypes
++static short armiiread(short phy, short reg);
++static void armiiwrite(short phy, short reg, short data);
++#ifdef TX_TIMEOUT
++static void ar2313_tx_timeout(struct net_device *dev);
++#endif
++static void ar2313_halt(struct net_device *dev);
++static void rx_tasklet_func(unsigned long data);
++static void ar2313_multicast_list(struct net_device *dev);
++
++static struct net_device *root_dev;
++static int probed __initdata = 0;
++static unsigned long ar_eth_base;
++static unsigned long ar_dma_base;
++static unsigned long ar_int_base;
++static unsigned long ar_int_mac_mask;
++static unsigned long ar_int_phy_mask;
++
++#ifndef ERR
++#define ERR(fmt, args...) printk("%s: " fmt, __func__, ##args)
++#endif
++
++static int parse_mac_addr(struct net_device *dev, char* macstr){
++ int i, j;
++ unsigned char result, value;
++
++ for (i=0; i<6; i++) {
++ result = 0;
++ if (i != 5 && *(macstr+2) != ':') {
++ ERR("invalid mac address format: %d %c\n",
++ i, *(macstr+2));
++ return -EINVAL;
++ }
++ for (j=0; j<2; j++) {
++ if (isxdigit(*macstr) && (value = isdigit(*macstr) ? *macstr-'0' :
++ toupper(*macstr)-'A'+10) < 16)
++ {
++ result = result*16 + value;
++ macstr++;
++ }
++ else {
++ ERR("invalid mac address "
++ "character: %c\n", *macstr);
++ return -EINVAL;
++ }
++ }
++
++ macstr++;
++ dev->dev_addr[i] = result;
++ }
++
++ return 0;
++}
++
++
++int __init ar2313_probe(void)
++{
++ struct net_device *dev;
++ struct ar2313_private *sp;
++ int version_disp;
++ char name[64] ;
++
++ if (probed)
++ return -ENODEV;
++ probed++;
++
++ version_disp = 0;
++ sprintf(name, "%s%%d", ifname) ;
++ dev = alloc_etherdev(sizeof(struct ar2313_private));
++
++ if (dev == NULL) {
++ printk(KERN_ERR "ar2313: Unable to allocate net_device structure!\n");
++ return -ENOMEM;
++ }
++
++ SET_MODULE_OWNER(dev);
++
++ sp = dev->priv;
++
++ sp->link = 0;
++ switch (mips_machtype) {
++ case MACH_ARUBA_AP60:
++ ar_eth_base = 0xb8100000;
++ ar_dma_base = ar_eth_base + 0x1000;
++ ar_int_base = 0x1C003020;
++ ar_int_mac_mask = RESET_ENET0|RESET_ENET1;
++ ar_int_phy_mask = RESET_EPHY0|RESET_EPHY1;
++ sp->mac = 1;
++ sp->phy = 1;
++ dev->irq = 4;
++ break;
++
++ case MACH_ARUBA_AP40:
++ ar_eth_base = 0xb0500000;
++ ar_dma_base = ar_eth_base + 0x1000;
++ ar_int_base = 0x11000004;
++ ar_int_mac_mask = 0x800;
++ ar_int_phy_mask = 0x400;
++ sp->mac = 0;
++ sp->phy = 1;
++ dev->irq = 4;
++ break;
++
++ case MACH_ARUBA_AP65:
++ ar_eth_base = 0xb8100000;
++ ar_dma_base = ar_eth_base + 0x1000;
++ ar_int_base = 0x1C003020;
++ ar_int_mac_mask = RESET_ENET0|RESET_ENET1;
++ ar_int_phy_mask = RESET_EPHY0|RESET_EPHY1;
++ sp->mac = 0;
++#if 0
++ // commented out, for now
++
++ if (mips_machtype == MACH_ARUBA_SAMSUNG) {
++ sp->phy = 0x1f;
++ } else {
++ sp->phy = 1;
++ }
++#else
++ sp->phy = 1;
++#endif
++ dev->irq = 3;
++ break;
++
++ default:
++ printk("%s: unsupported mips_machtype=0x%lx\n",
++ __FUNCTION__, mips_machtype) ;
++ return -ENODEV;
++ }
++
++ spin_lock_init(&sp->lock);
++
++ /* initialize func pointers */
++ dev->open = &ar2313_open;
++ dev->stop = &ar2313_close;
++ dev->hard_start_xmit = &ar2313_start_xmit;
++
++ dev->get_stats = &ar2313_get_stats;
++ dev->set_multicast_list = &ar2313_multicast_list;
++#ifdef TX_TIMEOUT
++ dev->tx_timeout = ar2313_tx_timeout;
++ dev->watchdog_timeo = AR2313_TX_TIMEOUT;
++#endif
++ dev->do_ioctl = &ar2313_ioctl;
++
++ // SAMEER: do we need this?
++ dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA;
++
++ tasklet_init(&sp->rx_tasklet, rx_tasklet_func, (unsigned long) dev);
++ tasklet_disable(&sp->rx_tasklet);
++
++ /* display version info if adapter is found */
++ if (!version_disp) {
++ /* set display flag to TRUE so that */
++ /* we only display this string ONCE */
++ version_disp = 1;
++#if DEBUG
++ printk(version);
++#endif /* DEBUG */
++ }
++
++ request_region(PHYSADDR(ETHERNET_BASE), ETHERNET_SIZE*ETHERNET_MACS,
++ "AR2313ENET");
++
++ sp->eth_regs = ioremap_nocache(PHYSADDR(ETHERNET_BASE + ETHERNET_SIZE*sp->mac),
++ sizeof(*sp->eth_regs));
++ if (!sp->eth_regs) {
++ printk("Can't remap eth registers\n");
++ return(-ENXIO);
++ }
++
++ sp->dma_regs = ioremap_nocache(PHYSADDR(DMA_BASE + DMA_SIZE*sp->mac),
++ sizeof(*sp->dma_regs));
++ dev->base_addr = (unsigned int) sp->dma_regs;
++ if (!sp->dma_regs) {
++ printk("Can't remap DMA registers\n");
++ return(-ENXIO);
++ }
++
++ sp->int_regs = ioremap_nocache(PHYSADDR(INTERRUPT_BASE),
++ sizeof(*sp->int_regs));
++ if (!sp->int_regs) {
++ printk("Can't remap INTERRUPT registers\n");
++ return(-ENXIO);
++ }
++
++ strncpy(sp->name, "Atheros AR2313", sizeof (sp->name) - 1);
++ sp->name [sizeof (sp->name) - 1] = '\0';
++
++ {
++ char mac[32];
++ extern char *getenv(char *e);
++ unsigned char def_mac[6] = {0, 0x0b, 0x86, 0xba, 0xdb, 0xad};
++ memset(mac, 0, 32);
++ memcpy(mac, getenv("ethaddr"), 17);
++ if (parse_mac_addr(dev, mac)){
++ printk("%s: MAC address not found, using default\n", __func__);
++ memcpy(dev->dev_addr, def_mac, 6);
++ }
++ }
++
++ sp->board_idx = BOARD_IDX_STATIC;
++
++ if (ar2313_init(dev)) {
++ /*
++ * ar2313_init() calls ar2313_init_cleanup() on error.
++ */
++ kfree(dev);
++ return -ENODEV;
++ }
++
++ if (register_netdev(dev)){
++ printk("%s: register_netdev failed\n", __func__);
++ return -1;
++ }
++
++ printk("%s: %s: %02x:%02x:%02x:%02x:%02x:%02x, irq %d\n",
++ dev->name, sp->name,
++ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
++ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5],
++ dev->irq);
++
++ /* start link poll timer */
++ ar2313_setup_timer(dev);
++
++ /*
++ * Register the device
++ */
++ root_dev = dev;
++
++ return 0;
++}
++
++#if 0
++static void ar2313_dump_regs(struct net_device *dev)
++{
++ unsigned int *ptr, i;
++ struct ar2313_private *sp = (struct ar2313_private *)dev->priv;
++
++ ptr = (unsigned int *)sp->eth_regs;
++ for(i=0; i< (sizeof(ETHERNET_STRUCT)/ sizeof(unsigned int)); i++, ptr++) {
++ printk("ENET: %08x = %08x\n", (int)ptr, *ptr);
++ }
++
++ ptr = (unsigned int *)sp->dma_regs;
++ for(i=0; i< (sizeof(DMA)/ sizeof(unsigned int)); i++, ptr++) {
++ printk("DMA: %08x = %08x\n", (int)ptr, *ptr);
++ }
++
++ ptr = (unsigned int *)sp->int_regs;
++ for(i=0; i< (sizeof(INTERRUPT)/ sizeof(unsigned int)); i++, ptr++){
++ printk("INT: %08x = %08x\n", (int)ptr, *ptr);
++ }
++
++ for (i = 0; i < AR2313_DESCR_ENTRIES; i++) {
++ ar2313_descr_t *td = &sp->tx_ring[i];
++ printk("Tx desc %2d: %08x %08x %08x %08x\n", i,
++ td->status, td->devcs, td->addr, td->descr);
++ }
++}
++#endif
++
++#ifdef TX_TIMEOUT
++static void
++ar2313_tx_timeout(struct net_device *dev)
++{
++ struct ar2313_private *sp = (struct ar2313_private *)dev->priv;
++ unsigned long flags;
++
++#if DEBUG_TX
++ printk("Tx timeout\n");
++#endif
++ spin_lock_irqsave(&sp->lock, flags);
++ ar2313_restart(dev);
++ spin_unlock_irqrestore(&sp->lock, flags);
++}
++#endif
++
++#if DEBUG_MC
++static void
++printMcList(struct net_device *dev)
++{
++ struct dev_mc_list *list = dev->mc_list;
++ int num=0, i;
++ while(list){
++ printk("%d MC ADDR ", num);
++ for(i=0;i<list->dmi_addrlen;i++) {
++ printk(":%02x", list->dmi_addr[i]);
++ }
++ list = list->next;
++ printk("\n");
++ }
++}
++#endif
++
++/*
++ * Set or clear the multicast filter for this adaptor.
++ * THIS IS ABSOLUTE CRAP, disabled
++ */
++static void
++ar2313_multicast_list(struct net_device *dev)
++{
++ /*
++ * Always listen to broadcasts and
++ * treat IFF bits independently
++ */
++ struct ar2313_private *sp = (struct ar2313_private *)dev->priv;
++ unsigned int recognise;
++
++ recognise = sp->eth_regs->mac_control;
++
++ if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
++ recognise |= MAC_CONTROL_PR;
++ } else {
++ recognise &= ~MAC_CONTROL_PR;
++ }
++
++ if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 15)) {
++#if DEBUG_MC
++ printMcList(dev);
++ printk("%s: all MULTICAST mc_count %d\n", __FUNCTION__, dev->mc_count);
++#endif
++ recognise |= MAC_CONTROL_PM;/* all multicast */
++ } else if (dev->mc_count > 0) {
++#if DEBUG_MC
++ printMcList(dev);
++ printk("%s: mc_count %d\n", __FUNCTION__, dev->mc_count);
++#endif
++ recognise |= MAC_CONTROL_PM; /* for the time being */
++ }
++#if DEBUG_MC
++ printk("%s: setting %08x to %08x\n", __FUNCTION__, (int)sp->eth_regs, recognise);
++#endif
++
++ sp->eth_regs->mac_control = recognise;
++}
++
++static void rx_tasklet_cleanup(struct net_device *dev)
++{
++ struct ar2313_private *sp = dev->priv;
++
++ /*
++ * Tasklet may be scheduled. Need to get it removed from the list
++ * since we're about to free the struct.
++ */
++
++ sp->unloading = 1;
++ tasklet_enable(&sp->rx_tasklet);
++ tasklet_kill(&sp->rx_tasklet);
++}
++
++static void __exit ar2313_module_cleanup(void)
++{
++ rx_tasklet_cleanup(root_dev);
++ ar2313_init_cleanup(root_dev);
++ unregister_netdev(root_dev);
++ kfree(root_dev);
++ release_region(PHYSADDR(ETHERNET_BASE), ETHERNET_SIZE*ETHERNET_MACS);
++}
++
++
++/*
++ * Restart the AR2313 ethernet controller.
++ */
++static int ar2313_restart(struct net_device *dev)
++{
++ /* disable interrupts */
++ disable_irq(dev->irq);
++
++ /* stop mac */
++ ar2313_halt(dev);
++
++ /* initialize */
++ ar2313_init(dev);
++
++ /* enable interrupts */
++ enable_irq(dev->irq);
++
++ return 0;
++}
++
++extern unsigned long mips_machtype;
++
++int __init ar2313_module_init(void)
++{
++ int status=-1;
++ switch (mips_machtype){
++ case MACH_ARUBA_AP60:
++ case MACH_ARUBA_AP65:
++ case MACH_ARUBA_AP40:
++ root_dev = NULL;
++ status = ar2313_probe();
++ break;
++ }
++ return status;
++}
++
++
++module_init(ar2313_module_init);
++module_exit(ar2313_module_cleanup);
++
++
++static void ar2313_free_descriptors(struct net_device *dev)
++{
++ struct ar2313_private *sp = dev->priv;
++ if (sp->rx_ring != NULL) {
++ kfree((void*)KSEG0ADDR(sp->rx_ring));
++ sp->rx_ring = NULL;
++ sp->tx_ring = NULL;
++ }
++}
++
++
++static int ar2313_allocate_descriptors(struct net_device *dev)
++{
++ struct ar2313_private *sp = dev->priv;
++ int size;
++ int j;
++ ar2313_descr_t *space;
++
++ if(sp->rx_ring != NULL){
++ printk("%s: already done.\n", __FUNCTION__);
++ return 0;
++ }
++
++ size = (sizeof(ar2313_descr_t) * (AR2313_DESCR_ENTRIES * AR2313_QUEUES));
++ space = kmalloc(size, GFP_KERNEL);
++ if (space == NULL)
++ return 1;
++
++ /* invalidate caches */
++ dma_cache_inv((unsigned int)space, size);
++
++ /* now convert pointer to KSEG1 */
++ space = (ar2313_descr_t *)KSEG1ADDR(space);
++
++ memset((void *)space, 0, size);
++
++ sp->rx_ring = space;
++ space += AR2313_DESCR_ENTRIES;
++
++ sp->tx_ring = space;
++ space += AR2313_DESCR_ENTRIES;
++
++ /* Initialize the transmit Descriptors */
++ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) {
++ ar2313_descr_t *td = &sp->tx_ring[j];
++ td->status = 0;
++ td->devcs = DMA_TX1_CHAINED;
++ td->addr = 0;
++ td->descr = K1_TO_PHYS(&sp->tx_ring[(j+1) & (AR2313_DESCR_ENTRIES-1)]);
++ }
++
++ return 0;
++}
++
++
++/*
++ * Generic cleanup handling data allocated during init. Used when the
++ * module is unloaded or if an error occurs during initialization
++ */
++static void ar2313_init_cleanup(struct net_device *dev)
++{
++ struct ar2313_private *sp = dev->priv;
++ struct sk_buff *skb;
++ int j;
++
++ ar2313_free_descriptors(dev);
++
++ if (sp->eth_regs) iounmap((void*)sp->eth_regs);
++ if (sp->dma_regs) iounmap((void*)sp->dma_regs);
++
++ if (sp->rx_skb) {
++ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) {
++ skb = sp->rx_skb[j];
++ if (skb) {
++ sp->rx_skb[j] = NULL;
++ dev_kfree_skb(skb);
++ }
++ }
++ kfree(sp->rx_skb);
++ sp->rx_skb = NULL;
++ }
++
++ if (sp->tx_skb) {
++ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) {
++ skb = sp->tx_skb[j];
++ if (skb) {
++ sp->tx_skb[j] = NULL;
++ dev_kfree_skb(skb);
++ }
++ }
++ kfree(sp->tx_skb);
++ sp->tx_skb = NULL;
++ }
++}
++
++static int ar2313_setup_timer(struct net_device *dev)
++{
++ struct ar2313_private *sp = dev->priv;
++
++ init_timer(&sp->link_timer);
++
++ sp->link_timer.function = ar2313_link_timer_fn;
++ sp->link_timer.data = (int) dev;
++ sp->link_timer.expires = jiffies + HZ;
++
++ add_timer(&sp->link_timer);
++ return 0;
++
++}
++
++static void ar2313_link_timer_fn(unsigned long data)
++{
++ struct net_device *dev = (struct net_device *) data;
++ struct ar2313_private *sp = dev->priv;
++
++ // see if the link status changed
++ // This was needed to make sure we set the PHY to the
++ // autonegotiated value of half or full duplex.
++ ar2313_check_link(dev);
++
++ // Loop faster when we don't have link.
++ // This was needed to speed up the AP bootstrap time.
++ if(sp->link == 0) {
++ mod_timer(&sp->link_timer, jiffies + HZ/2);
++ } else {
++ mod_timer(&sp->link_timer, jiffies + LINK_TIMER);
++ }
++}
++
++static void ar2313_check_link(struct net_device *dev)
++{
++ struct ar2313_private *sp = dev->priv;
++ u16 phyData;
++
++ phyData = armiiread(sp->phy, MII_BMSR);
++ if (sp->phyData != phyData) {
++ if (phyData & BMSR_LSTATUS) {
++ /* link is present, ready link partner ability to deterine duplexity */
++ int duplex = 0;
++ u16 reg;
++
++ sp->link = 1;
++ reg = armiiread(sp->phy, MII_BMCR);
++ if (reg & BMCR_ANENABLE) {
++ /* auto neg enabled */
++ reg = armiiread(sp->phy, MII_LPA);
++ duplex = (reg & (LPA_100FULL|LPA_10FULL))? 1:0;
++ } else {
++ /* no auto neg, just read duplex config */
++ duplex = (reg & BMCR_FULLDPLX)? 1:0;
++ }
++
++ printk(KERN_INFO "%s: Configuring MAC for %s duplex\n", dev->name,
++ (duplex)? "full":"half");
++
++ if (duplex) {
++ /* full duplex */
++ sp->eth_regs->mac_control = ((sp->eth_regs->mac_control | MAC_CONTROL_F) &
++ ~MAC_CONTROL_DRO);
++ } else {
++ /* half duplex */
++ sp->eth_regs->mac_control = ((sp->eth_regs->mac_control | MAC_CONTROL_DRO) &
++ ~MAC_CONTROL_F);
++ }
++ } else {
++ /* no link */
++ sp->link = 0;
++ }
++ sp->phyData = phyData;
++ }
++}
++
++static int
++ar2313_reset_reg(struct net_device *dev)
++{
++ struct ar2313_private *sp = (struct ar2313_private *)dev->priv;
++ unsigned int ethsal, ethsah;
++ unsigned int flags;
++
++ *sp->int_regs |= ar_int_mac_mask;
++ mdelay(10);
++ *sp->int_regs &= ~ar_int_mac_mask;
++ mdelay(10);
++ *sp->int_regs |= ar_int_phy_mask;
++ mdelay(10);
++ *sp->int_regs &= ~ar_int_phy_mask;
++ mdelay(10);
++
++ sp->dma_regs->bus_mode = (DMA_BUS_MODE_SWR);
++ mdelay(10);
++ sp->dma_regs->bus_mode = ((32 << DMA_BUS_MODE_PBL_SHIFT) | DMA_BUS_MODE_BLE);
++
++ /* enable interrupts */
++ sp->dma_regs->intr_ena = (DMA_STATUS_AIS |
++ DMA_STATUS_NIS |
++ DMA_STATUS_RI |
++ DMA_STATUS_TI |
++ DMA_STATUS_FBE);
++ sp->dma_regs->xmt_base = K1_TO_PHYS(sp->tx_ring);
++ sp->dma_regs->rcv_base = K1_TO_PHYS(sp->rx_ring);
++ sp->dma_regs->control = (DMA_CONTROL_SR | DMA_CONTROL_ST | DMA_CONTROL_SF);
++
++ sp->eth_regs->flow_control = (FLOW_CONTROL_FCE);
++ sp->eth_regs->vlan_tag = (0x8100);
++
++ /* Enable Ethernet Interface */
++ flags = (MAC_CONTROL_TE | /* transmit enable */
++ MAC_CONTROL_PM | /* pass mcast */
++ MAC_CONTROL_F | /* full duplex */
++ MAC_CONTROL_HBD); /* heart beat disabled */
++
++ if (dev->flags & IFF_PROMISC) { /* set promiscuous mode */
++ flags |= MAC_CONTROL_PR;
++ }
++ sp->eth_regs->mac_control = flags;
++
++ /* Set all Ethernet station address registers to their initial values */
++ ethsah = ((((u_int)(dev->dev_addr[5]) << 8) & (u_int)0x0000FF00) |
++ (((u_int)(dev->dev_addr[4]) << 0) & (u_int)0x000000FF));
++
++ ethsal = ((((u_int)(dev->dev_addr[3]) << 24) & (u_int)0xFF000000) |
++ (((u_int)(dev->dev_addr[2]) << 16) & (u_int)0x00FF0000) |
++ (((u_int)(dev->dev_addr[1]) << 8) & (u_int)0x0000FF00) |
++ (((u_int)(dev->dev_addr[0]) << 0) & (u_int)0x000000FF) );
++
++ sp->eth_regs->mac_addr[0] = ethsah;
++ sp->eth_regs->mac_addr[1] = ethsal;
++
++ mdelay(10);
++
++ return(0);
++}
++
++
++static int ar2313_init(struct net_device *dev)
++{
++ struct ar2313_private *sp = dev->priv;
++ int ecode=0;
++
++ /*
++ * Allocate descriptors
++ */
++ if (ar2313_allocate_descriptors(dev)) {
++ printk("%s: %s: ar2313_allocate_descriptors failed\n",
++ dev->name, __FUNCTION__);
++ ecode = -EAGAIN;
++ goto init_error;
++ }
++
++ /*
++ * Get the memory for the skb rings.
++ */
++ if(sp->rx_skb == NULL) {
++ sp->rx_skb = kmalloc(sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES, GFP_KERNEL);
++ if (!(sp->rx_skb)) {
++ printk("%s: %s: rx_skb kmalloc failed\n",
++ dev->name, __FUNCTION__);
++ ecode = -EAGAIN;
++ goto init_error;
++ }
++ }
++ memset(sp->rx_skb, 0, sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES);
++
++ if(sp->tx_skb == NULL) {
++ sp->tx_skb = kmalloc(sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES, GFP_KERNEL);
++ if (!(sp->tx_skb)) {
++ printk("%s: %s: tx_skb kmalloc failed\n",
++ dev->name, __FUNCTION__);
++ ecode = -EAGAIN;
++ goto init_error;
++ }
++ }
++ memset(sp->tx_skb, 0, sizeof(struct sk_buff *) * AR2313_DESCR_ENTRIES);
++
++ /*
++ * Set tx_csm before we start receiving interrupts, otherwise
++ * the interrupt handler might think it is supposed to process
++ * tx ints before we are up and running, which may cause a null
++ * pointer access in the int handler.
++ */
++ sp->rx_skbprd = 0;
++ sp->cur_rx = 0;
++ sp->tx_prd = 0;
++ sp->tx_csm = 0;
++
++ /*
++ * Zero the stats before starting the interface
++ */
++ memset(&sp->stats, 0, sizeof(sp->stats));
++
++ /*
++ * We load the ring here as there seem to be no way to tell the
++ * firmware to wipe the ring without re-initializing it.
++ */
++ ar2313_load_rx_ring(dev, RX_RING_SIZE);
++
++ /*
++ * Init hardware
++ */
++ ar2313_reset_reg(dev);
++
++ /*
++ * Get the IRQ
++ */
++ ecode = request_irq(dev->irq, &ar2313_interrupt, SA_SHIRQ | SA_INTERRUPT, dev->name, dev);
++ if (ecode) {
++ printk(KERN_WARNING "%s: %s: Requested IRQ %d is busy\n",
++ dev->name, __FUNCTION__, dev->irq);
++ goto init_error;
++ }
++
++#if 0
++ // commented out, for now
++
++ if(mips_machtype == MACH_ARUBA_SAMSUNG) {
++ int i;
++ /* configure Marvell 88E6060 */
++ /* reset chip */
++ armiiwrite(0x1f, 0xa, 0xa130);
++ do {
++ udelay(1000);
++ i = armiiread(sp->phy, 0xa);
++ } while (i & 0x8000);
++
++ /* configure MAC address */
++ armiiwrite(sp->phy, 0x1, dev->dev_addr[0] << 8 | dev->dev_addr[1]);
++ armiiwrite(sp->phy, 0x2, dev->dev_addr[2] << 8 | dev->dev_addr[3]);
++ armiiwrite(sp->phy, 0x3, dev->dev_addr[4] << 8 | dev->dev_addr[5]);
++
++ /* set ports to forwarding */
++ armiiwrite(0x18, 0x4, 0x3);
++ armiiwrite(0x1c, 0x4, 0x3);
++ armiiwrite(0x1d, 0x4, 0x3);
++ }
++#endif
++
++ tasklet_enable(&sp->rx_tasklet);
++
++ return 0;
++
++ init_error:
++ ar2313_init_cleanup(dev);
++ return ecode;
++}
++
++/*
++ * Load the rx ring.
++ *
++ * Loading rings is safe without holding the spin lock since this is
++ * done only before the device is enabled, thus no interrupts are
++ * generated and by the interrupt handler/tasklet handler.
++ */
++static void ar2313_load_rx_ring(struct net_device *dev, int nr_bufs)
++{
++
++ struct ar2313_private *sp = ((struct net_device *)dev)->priv;
++ short i, idx;
++
++ idx = sp->rx_skbprd;
++
++ for (i = 0; i < nr_bufs; i++) {
++ struct sk_buff *skb;
++ ar2313_descr_t *rd;
++
++ if (sp->rx_skb[idx]) {
++#if DEBUG_RX
++ printk(KERN_INFO "ar2313 rx refill full\n");
++#endif /* DEBUG */
++ break;
++ }
++
++ // partha: create additional room for the second GRE fragment
++ skb = alloc_skb(AR2313_BUFSIZE+128, GFP_ATOMIC);
++ if (!skb) {
++ printk("\n\n\n\n %s: No memory in system\n\n\n\n", __FUNCTION__);
++ break;
++ }
++ // partha: create additional room in the front for tx pkt capture
++ skb_reserve(skb, 32);
++
++ /*
++ * Make sure IP header starts on a fresh cache line.
++ */
++ skb->dev = dev;
++ skb_reserve(skb, RX_OFFSET);
++ sp->rx_skb[idx] = skb;
++
++ rd = (ar2313_descr_t *) &sp->rx_ring[idx];
++
++ /* initialize dma descriptor */
++ rd->devcs = ((AR2313_BUFSIZE << DMA_RX1_BSIZE_SHIFT) |
++ DMA_RX1_CHAINED);
++ rd->addr = virt_to_phys(skb->data);
++ rd->descr = virt_to_phys(&sp->rx_ring[(idx+1) & (AR2313_DESCR_ENTRIES-1)]);
++ rd->status = DMA_RX_OWN;
++
++ idx = DSC_NEXT(idx);
++ }
++
++ if (!i) {
++#if DEBUG_ERR
++ printk(KERN_INFO "Out of memory when allocating standard receive buffers\n");
++#endif /* DEBUG */
++ } else {
++ sp->rx_skbprd = idx;
++ }
++
++ return;
++}
++
++#define AR2313_MAX_PKTS_PER_CALL 64
++
++static int ar2313_rx_int(struct net_device *dev)
++{
++ struct ar2313_private *sp = dev->priv;
++ struct sk_buff *skb, *skb_new;
++ ar2313_descr_t *rxdesc;
++ unsigned int status;
++ u32 idx;
++ int pkts = 0;
++ int rval;
++
++ idx = sp->cur_rx;
++
++ /* process at most the entire ring and then wait for another interrupt */
++ while(1) {
++
++ rxdesc = &sp->rx_ring[idx];
++ status = rxdesc->status;
++ if (status & DMA_RX_OWN) {
++ /* SiByte owns descriptor or descr not yet filled in */
++ rval = 0;
++ break;
++ }
++
++ if (++pkts > AR2313_MAX_PKTS_PER_CALL) {
++ rval = 1;
++ break;
++ }
++
++#if DEBUG_RX
++ printk("index %d\n", idx);
++ printk("RX status %08x\n", rxdesc->status);
++ printk("RX devcs %08x\n", rxdesc->devcs );
++ printk("RX addr %08x\n", rxdesc->addr );
++ printk("RX descr %08x\n", rxdesc->descr );
++#endif
++
++ if ((status & (DMA_RX_ERROR|DMA_RX_ERR_LENGTH)) &&
++ (!(status & DMA_RX_LONG))){
++#if DEBUG_RX
++ printk("%s: rx ERROR %08x\n", __FUNCTION__, status);
++#endif
++ sp->stats.rx_errors++;
++ sp->stats.rx_dropped++;
++
++ /* add statistics counters */
++ if (status & DMA_RX_ERR_CRC) sp->stats.rx_crc_errors++;
++ if (status & DMA_RX_ERR_COL) sp->stats.rx_over_errors++;
++ if (status & DMA_RX_ERR_LENGTH)
++ sp->stats.rx_length_errors++;
++ if (status & DMA_RX_ERR_RUNT) sp->stats.rx_over_errors++;
++ if (status & DMA_RX_ERR_DESC) sp->stats.rx_over_errors++;
++
++ } else {
++ /* alloc new buffer. */
++ skb_new = dev_alloc_skb(AR2313_BUFSIZE + RX_OFFSET + 128);
++ if (skb_new != NULL) {
++
++ skb = sp->rx_skb[idx];
++ /* set skb */
++ skb_put(skb, ((status >> DMA_RX_LEN_SHIFT) & 0x3fff) - CRC_LEN);
++
++#ifdef CONFIG_MERLOT
++ if ((dev->am_pkt_handler == NULL) ||
++ (dev->am_pkt_handler(skb, dev) == 0)) {
++#endif
++ sp->stats.rx_bytes += skb->len;
++ skb->protocol = eth_type_trans(skb, dev);
++ /* pass the packet to upper layers */
++
++#ifdef CONFIG_MERLOT
++ if (dev->asap_netif_rx)
++ dev->asap_netif_rx(skb);
++ else
++#endif
++ netif_rx(skb);
++#ifdef CONFIG_MERLOT
++ }
++#endif
++ skb_new->dev = dev;
++ /* 16 bit align */
++ skb_reserve(skb_new, RX_OFFSET+32);
++ /* reset descriptor's curr_addr */
++ rxdesc->addr = virt_to_phys(skb_new->data);
++
++ sp->stats.rx_packets++;
++ sp->rx_skb[idx] = skb_new;
++
++ } else {
++ sp->stats.rx_dropped++;
++ }
++ }
++
++ rxdesc->devcs = ((AR2313_BUFSIZE << DMA_RX1_BSIZE_SHIFT) |
++ DMA_RX1_CHAINED);
++ rxdesc->status = DMA_RX_OWN;
++
++ idx = DSC_NEXT(idx);
++ }
++
++ sp->cur_rx = idx;
++
++ return rval;
++}
++
++
++static void ar2313_tx_int(struct net_device *dev)
++{
++ struct ar2313_private *sp = dev->priv;
++ u32 idx;
++ struct sk_buff *skb;
++ ar2313_descr_t *txdesc;
++ unsigned int status=0;
++
++ idx = sp->tx_csm;
++
++ while (idx != sp->tx_prd) {
++
++ txdesc = &sp->tx_ring[idx];
++
++#if DEBUG_TX
++ printk("%s: TXINT: csm=%d idx=%d prd=%d status=%x devcs=%x addr=%08x descr=%x\n",
++ dev->name, sp->tx_csm, idx, sp->tx_prd,
++ txdesc->status, txdesc->devcs, txdesc->addr, txdesc->descr);
++#endif /* DEBUG */
++
++ if ((status = txdesc->status) & DMA_TX_OWN) {
++ /* ar2313 dma still owns descr */
++ break;
++ }
++ /* done with this descriptor */
++ txdesc->status = 0;
++
++ if (status & DMA_TX_ERROR){
++ sp->stats.tx_errors++;
++ sp->stats.tx_dropped++;
++ if(status & DMA_TX_ERR_UNDER)
++ sp->stats.tx_fifo_errors++;
++ if(status & DMA_TX_ERR_HB)
++ sp->stats.tx_heartbeat_errors++;
++ if(status & (DMA_TX_ERR_LOSS |
++ DMA_TX_ERR_LINK))
++ sp->stats.tx_carrier_errors++;
++ if (status & (DMA_TX_ERR_LATE|
++ DMA_TX_ERR_COL |
++ DMA_TX_ERR_JABBER |
++ DMA_TX_ERR_DEFER))
++ sp->stats.tx_aborted_errors++;
++ } else {
++ /* transmit OK */
++ sp->stats.tx_packets++;
++ }
++
++ skb = sp->tx_skb[idx];
++ sp->tx_skb[idx] = NULL;
++ idx = DSC_NEXT(idx);
++ sp->stats.tx_bytes += skb->len;
++ dev_kfree_skb_irq(skb);
++ }
++
++ sp->tx_csm = idx;
++
++ return;
++}
++
++
++static void
++rx_tasklet_func(unsigned long data)
++{
++ struct net_device *dev = (struct net_device *) data;
++ struct ar2313_private *sp = dev->priv;
++
++ if (sp->unloading) {
++ return;
++ }
++
++ if (ar2313_rx_int(dev)) {
++ tasklet_hi_schedule(&sp->rx_tasklet);
++ }
++ else {
++ unsigned long flags;
++ spin_lock_irqsave(&sp->lock, flags);
++ sp->dma_regs->intr_ena |= DMA_STATUS_RI;
++ spin_unlock_irqrestore(&sp->lock, flags);
++ }
++}
++
++static void
++rx_schedule(struct net_device *dev)
++{
++ struct ar2313_private *sp = dev->priv;
++
++ sp->dma_regs->intr_ena &= ~DMA_STATUS_RI;
++
++ tasklet_hi_schedule(&sp->rx_tasklet);
++}
++
++static irqreturn_t ar2313_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
++{
++ struct net_device *dev = (struct net_device *)dev_id;
++ struct ar2313_private *sp = dev->priv;
++ unsigned int status, enabled;
++
++ /* clear interrupt */
++ /*
++ * Don't clear RI bit if currently disabled.
++ */
++ status = sp->dma_regs->status;
++ enabled = sp->dma_regs->intr_ena;
++ sp->dma_regs->status = status & enabled;
++
++ if (status & DMA_STATUS_NIS) {
++ /* normal status */
++ /*
++ * Don't schedule rx processing if interrupt
++ * is already disabled.
++ */
++ if (status & enabled & DMA_STATUS_RI) {
++ /* receive interrupt */
++ rx_schedule(dev);
++ }
++ if (status & DMA_STATUS_TI) {
++ /* transmit interrupt */
++ ar2313_tx_int(dev);
++ }
++ }
++
++ if (status & DMA_STATUS_AIS) {
++#if DEBUG_INT
++ printk("%s: AIS set %08x & %x\n", __FUNCTION__,
++ status, (DMA_STATUS_FBE | DMA_STATUS_TPS));
++#endif
++ /* abnormal status */
++ if (status & (DMA_STATUS_FBE | DMA_STATUS_TPS)) {
++ ar2313_restart(dev);
++ }
++ }
++ return IRQ_HANDLED;
++}
++
++
++static int ar2313_open(struct net_device *dev)
++{
++ struct ar2313_private *sp;
++
++ sp = dev->priv;
++
++ dev->mtu = 1500;
++ netif_start_queue(dev);
++
++ sp->eth_regs->mac_control |= MAC_CONTROL_RE;
++
++ AR2313_MOD_INC_USE_COUNT;
++
++ return 0;
++}
++
++static void ar2313_halt(struct net_device *dev)
++{
++ struct ar2313_private *sp = dev->priv;
++ int j;
++
++ tasklet_disable(&sp->rx_tasklet);
++
++ /* kill the MAC */
++ sp->eth_regs->mac_control &= ~(MAC_CONTROL_RE | /* disable Receives */
++ MAC_CONTROL_TE); /* disable Transmits */
++ /* stop dma */
++ sp->dma_regs->control = 0;
++ sp->dma_regs->bus_mode = DMA_BUS_MODE_SWR;
++
++ /* place phy and MAC in reset */
++ *sp->int_regs |= (ar_int_mac_mask | ar_int_phy_mask);
++
++ /* free buffers on tx ring */
++ for (j = 0; j < AR2313_DESCR_ENTRIES; j++) {
++ struct sk_buff *skb;
++ ar2313_descr_t *txdesc;
++
++ txdesc = &sp->tx_ring[j];
++ txdesc->descr = 0;
++
++ skb = sp->tx_skb[j];
++ if (skb) {
++ dev_kfree_skb(skb);
++ sp->tx_skb[j] = NULL;
++ }
++ }
++}
++
++/*
++ * close should do nothing. Here's why. It's called when
++ * 'ifconfig bond0 down' is run. If it calls free_irq then
++ * the irq is gone forever ! When bond0 is made 'up' again,
++ * the ar2313_open () does not call request_irq (). Worse,
++ * the call to ar2313_halt() generates a WDOG reset due to
++ * the write to 'sp->int_regs' and the box reboots.
++ * Commenting this out is good since it allows the
++ * system to resume when bond0 is made up again.
++ */
++static int ar2313_close(struct net_device *dev)
++{
++#if 0
++ /*
++ * Disable interrupts
++ */
++ disable_irq(dev->irq);
++
++ /*
++ * Without (or before) releasing irq and stopping hardware, this
++ * is an absolute non-sense, by the way. It will be reset instantly
++ * by the first irq.
++ */
++ netif_stop_queue(dev);
++
++ /* stop the MAC and DMA engines */
++ ar2313_halt(dev);
++
++ /* release the interrupt */
++ free_irq(dev->irq, dev);
++
++#endif
++ AR2313_MOD_DEC_USE_COUNT;
++ return 0;
++}
++
++static int ar2313_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct ar2313_private *sp = dev->priv;
++ ar2313_descr_t *td;
++ u32 idx;
++
++ idx = sp->tx_prd;
++ td = &sp->tx_ring[idx];
++
++ if (td->status & DMA_TX_OWN) {
++#if DEBUG_TX
++ printk("%s: No space left to Tx\n", __FUNCTION__);
++#endif
++ /* free skbuf and lie to the caller that we sent it out */
++ sp->stats.tx_dropped++;
++ dev_kfree_skb(skb);
++
++ /* restart transmitter in case locked */
++ sp->dma_regs->xmt_poll = 0;
++ return 0;
++ }
++
++ /* Setup the transmit descriptor. */
++ td->devcs = ((skb->len << DMA_TX1_BSIZE_SHIFT) |
++ (DMA_TX1_LS|DMA_TX1_IC|DMA_TX1_CHAINED));
++ td->addr = virt_to_phys(skb->data);
++ td->status = DMA_TX_OWN;
++
++ /* kick transmitter last */
++ sp->dma_regs->xmt_poll = 0;
++
++#if DEBUG_TX
++ printk("index %d\n", idx);
++ printk("TX status %08x\n", td->status);
++ printk("TX devcs %08x\n", td->devcs );
++ printk("TX addr %08x\n", td->addr );
++ printk("TX descr %08x\n", td->descr );
++#endif
++
++ sp->tx_skb[idx] = skb;
++ idx = DSC_NEXT(idx);
++ sp->tx_prd = idx;
++
++ //dev->trans_start = jiffies;
++
++ return 0;
++}
++
++static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
++{
++ struct ar2313_private *np = dev->priv;
++ u32 tmp;
++
++ ecmd->supported =
++ (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
++ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
++ SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
++
++ ecmd->port = PORT_TP;
++ /* only supports internal transceiver */
++ ecmd->transceiver = XCVR_INTERNAL;
++ /* not sure what this is for */
++ ecmd->phy_address = 1;
++
++ ecmd->advertising = ADVERTISED_MII;
++ tmp = armiiread(np->phy, MII_ADVERTISE);
++ if (tmp & ADVERTISE_10HALF)
++ ecmd->advertising |= ADVERTISED_10baseT_Half;
++ if (tmp & ADVERTISE_10FULL)
++ ecmd->advertising |= ADVERTISED_10baseT_Full;
++ if (tmp & ADVERTISE_100HALF)
++ ecmd->advertising |= ADVERTISED_100baseT_Half;
++ if (tmp & ADVERTISE_100FULL)
++ ecmd->advertising |= ADVERTISED_100baseT_Full;
++
++ tmp = armiiread(np->phy, MII_BMCR);
++ if (tmp & BMCR_ANENABLE) {
++ ecmd->advertising |= ADVERTISED_Autoneg;
++ ecmd->autoneg = AUTONEG_ENABLE;
++ } else {
++ ecmd->autoneg = AUTONEG_DISABLE;
++ }
++
++ if (ecmd->autoneg == AUTONEG_ENABLE) {
++ tmp = armiiread(np->phy, MII_LPA);
++ if (tmp & (LPA_100FULL|LPA_10FULL)) {
++ ecmd->duplex = DUPLEX_FULL;
++ } else {
++ ecmd->duplex = DUPLEX_HALF;
++ }
++ if (tmp & (LPA_100FULL|LPA_100HALF)) {
++ ecmd->speed = SPEED_100;
++ } else {
++ ecmd->speed = SPEED_10;
++ }
++ } else {
++ if (tmp & BMCR_FULLDPLX) {
++ ecmd->duplex = DUPLEX_FULL;
++ } else {
++ ecmd->duplex = DUPLEX_HALF;
++ }
++ if (tmp & BMCR_SPEED100) {
++ ecmd->speed = SPEED_100;
++ } else {
++ ecmd->speed = SPEED_10;
++ }
++ }
++
++ /* ignore maxtxpkt, maxrxpkt for now */
++
++ return 0;
++}
++
++static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
++{
++ struct ar2313_private *np = dev->priv;
++ u32 tmp;
++
++ if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100)
++ return -EINVAL;
++ if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
++ return -EINVAL;
++ if (ecmd->port != PORT_TP)
++ return -EINVAL;
++ if (ecmd->transceiver != XCVR_INTERNAL)
++ return -EINVAL;
++ if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
++ return -EINVAL;
++ /* ignore phy_address, maxtxpkt, maxrxpkt for now */
++
++ /* WHEW! now lets bang some bits */
++
++ tmp = armiiread(np->phy, MII_BMCR);
++ if (ecmd->autoneg == AUTONEG_ENABLE) {
++ /* turn on autonegotiation */
++ tmp |= BMCR_ANENABLE;
++ printk("%s: Enabling auto-neg\n", dev->name);
++ } else {
++ /* turn off auto negotiation, set speed and duplexity */
++ tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
++ if (ecmd->speed == SPEED_100)
++ tmp |= BMCR_SPEED100;
++ if (ecmd->duplex == DUPLEX_FULL)
++ tmp |= BMCR_FULLDPLX;
++ printk("%s: Hard coding %d/%s\n", dev->name,
++ (ecmd->speed == SPEED_100)? 100:10,
++ (ecmd->duplex == DUPLEX_FULL)? "full":"half");
++ }
++ armiiwrite(np->phy, MII_BMCR, tmp);
++ np->phyData = 0;
++ return 0;
++}
++
++static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
++{
++ struct ar2313_private *np = dev->priv;
++ u32 cmd;
++
++ if (get_user(cmd, (u32 *)useraddr))
++ return -EFAULT;
++
++ switch (cmd) {
++ /* get settings */
++ case ETHTOOL_GSET: {
++ struct ethtool_cmd ecmd = { ETHTOOL_GSET };
++ spin_lock_irq(&np->lock);
++ netdev_get_ecmd(dev, &ecmd);
++ spin_unlock_irq(&np->lock);
++ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
++ return -EFAULT;
++ return 0;
++ }
++ /* set settings */
++ case ETHTOOL_SSET: {
++ struct ethtool_cmd ecmd;
++ int r;
++ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
++ return -EFAULT;
++ spin_lock_irq(&np->lock);
++ r = netdev_set_ecmd(dev, &ecmd);
++ spin_unlock_irq(&np->lock);
++ return r;
++ }
++ /* restart autonegotiation */
++ case ETHTOOL_NWAY_RST: {
++ int tmp;
++ int r = -EINVAL;
++ /* if autoneg is off, it's an error */
++ tmp = armiiread(np->phy, MII_BMCR);
++ if (tmp & BMCR_ANENABLE) {
++ tmp |= (BMCR_ANRESTART);
++ armiiwrite(np->phy, MII_BMCR, tmp);
++ r = 0;
++ }
++ return r;
++ }
++ /* get link status */
++ case ETHTOOL_GLINK: {
++ struct ethtool_value edata = {ETHTOOL_GLINK};
++ edata.data = (armiiread(np->phy, MII_BMSR)&BMSR_LSTATUS) ? 1:0;
++ if (copy_to_user(useraddr, &edata, sizeof(edata)))
++ return -EFAULT;
++ return 0;
++ }
++ }
++
++ return -EOPNOTSUPP;
++}
++
++static int ar2313_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++ struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
++
++ switch (cmd) {
++ case SIOCDEVPRIVATE: {
++ struct ar2313_cmd scmd;
++
++ if (copy_from_user(&scmd, ifr->ifr_data, sizeof(scmd)))
++ return -EFAULT;
++
++#if DEBUG
++ printk("%s: ioctl devprivate c=%d a=%x l=%d m=%d d=%x,%x\n",
++ dev->name, scmd.cmd,
++ scmd.address, scmd.length,
++ scmd.mailbox, scmd.data[0], scmd.data[1]);
++#endif /* DEBUG */
++
++ switch (scmd.cmd) {
++ case AR2313_READ_DATA:
++ if(scmd.length==4){
++ scmd.data[0] = *((u32*)scmd.address);
++ } else if(scmd.length==2) {
++ scmd.data[0] = *((u16*)scmd.address);
++ } else if (scmd.length==1) {
++ scmd.data[0] = *((u8*)scmd.address);
++ } else {
++ return -EOPNOTSUPP;
++ }
++ if(copy_to_user(ifr->ifr_data, &scmd, sizeof(scmd)))
++ return -EFAULT;
++ break;
++
++ case AR2313_WRITE_DATA:
++ if(scmd.length==4){
++ *((u32*)scmd.address) = scmd.data[0];
++ } else if(scmd.length==2) {
++ *((u16*)scmd.address) = scmd.data[0];
++ } else if (scmd.length==1) {
++ *((u8*)scmd.address) = scmd.data[0];
++ } else {
++ return -EOPNOTSUPP;
++ }
++ break;
++
++ case AR2313_GET_VERSION:
++ // SAMEER: sprintf((char*) &scmd, "%s", ARUBA_VERSION);
++ if(copy_to_user(ifr->ifr_data, &scmd, sizeof(scmd)))
++ return -EFAULT;
++ break;
++
++ default:
++ return -EOPNOTSUPP;
++ }
++ return 0;
++ }
++
++ case SIOCETHTOOL:
++ return netdev_ethtool_ioctl(dev, (void *) ifr->ifr_data);
++
++ case SIOCGMIIPHY: /* Get address of MII PHY in use. */
++ data->phy_id = 1;
++ /* Fall Through */
++
++ case SIOCGMIIREG: /* Read MII PHY register. */
++ case SIOCDEVPRIVATE+1: /* for binary compat, remove in 2.5 */
++ data->val_out = armiiread(data->phy_id & 0x1f,
++ data->reg_num & 0x1f);
++ return 0;
++ case SIOCSMIIREG: /* Write MII PHY register. */
++ case SIOCDEVPRIVATE+2: /* for binary compat, remove in 2.5 */
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++ armiiwrite(data->phy_id & 0x1f,
++ data->reg_num & 0x1f, data->val_in);
++ return 0;
++
++ case SIOCSIFHWADDR:
++ if (copy_from_user(dev->dev_addr, ifr->ifr_data, sizeof(dev->dev_addr)))
++ return -EFAULT;
++ return 0;
++
++ case SIOCGIFHWADDR:
++ if (copy_to_user(ifr->ifr_data, dev->dev_addr, sizeof(dev->dev_addr)))
++ return -EFAULT;
++ return 0;
++
++ default:
++ break;
++ }
++
++ return -EOPNOTSUPP;
++}
++
++static struct net_device_stats *ar2313_get_stats(struct net_device *dev)
++{
++ struct ar2313_private *sp = dev->priv;
++ return &sp->stats;
++}
++
++static short
++armiiread(short phy, short reg)
++{
++ volatile ETHERNET_STRUCT * ethernet;
++
++ ethernet = (volatile ETHERNET_STRUCT *)ETHERNET_BASE; /* always MAC 0 */
++ ethernet->mii_addr = ((reg << MII_ADDR_REG_SHIFT) |
++ (phy << MII_ADDR_PHY_SHIFT));
++ while (ethernet->mii_addr & MII_ADDR_BUSY);
++ return (ethernet->mii_data >> MII_DATA_SHIFT);
++}
++
++static void
++armiiwrite(short phy, short reg, short data)
++{
++ volatile ETHERNET_STRUCT * ethernet;
++
++ ethernet = (volatile ETHERNET_STRUCT *)ETHERNET_BASE; /* always MAC 0 */
++ while (ethernet->mii_addr & MII_ADDR_BUSY);
++ ethernet->mii_data = data << MII_DATA_SHIFT;
++ ethernet->mii_addr = ((reg << MII_ADDR_REG_SHIFT) |
++ (phy << MII_ADDR_PHY_SHIFT) |
++ MII_ADDR_WRITE);
++}
++
+diff -Nur linux-2.6.17/drivers/net/ar2313/ar2313.h linux-2.6.17-owrt/drivers/net/ar2313/ar2313.h
+--- linux-2.6.17/drivers/net/ar2313/ar2313.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/drivers/net/ar2313/ar2313.h 2006-06-19 12:05:29.000000000 +0200
+@@ -0,0 +1,190 @@
++#ifndef _AR2313_H_
++#define _AR2313_H_
++
++#include <linux/config.h>
++#include <asm/bootinfo.h>
++#include "platform.h"
++
++extern unsigned long mips_machtype;
++
++#undef ETHERNET_BASE
++#define ETHERNET_BASE ar_eth_base
++#define ETHERNET_SIZE 0x00100000
++#define ETHERNET_MACS 2
++
++#undef DMA_BASE
++#define DMA_BASE ar_dma_base
++#define DMA_SIZE 0x00100000
++
++
++/*
++ * probe link timer - 5 secs
++ */
++#define LINK_TIMER (5*HZ)
++
++/*
++ * Interrupt register base address
++ */
++#define INTERRUPT_BASE PHYS_TO_K1(ar_int_base)
++
++/*
++ * Reset Register
++ */
++#define AR531X_RESET (AR531X_RESETTMR + 0x0020)
++#define RESET_SYSTEM 0x00000001 /* cold reset full system */
++#define RESET_PROC 0x00000002 /* cold reset MIPS core */
++#define RESET_WLAN0 0x00000004 /* cold reset WLAN MAC and BB */
++#define RESET_EPHY0 0x00000008 /* cold reset ENET0 phy */
++#define RESET_EPHY1 0x00000010 /* cold reset ENET1 phy */
++#define RESET_ENET0 0x00000020 /* cold reset ENET0 mac */
++#define RESET_ENET1 0x00000040 /* cold reset ENET1 mac */
++
++#define IS_DMA_TX_INT(X) (((X) & (DMA_STATUS_TI)) != 0)
++#define IS_DMA_RX_INT(X) (((X) & (DMA_STATUS_RI)) != 0)
++#define IS_DRIVER_OWNED(X) (((X) & (DMA_TX_OWN)) == 0)
++
++#ifndef K1_TO_PHYS
++// hack
++#define K1_TO_PHYS(x) (((unsigned int)(x)) & 0x1FFFFFFF) /* kseg1 to physical */
++#endif
++
++#ifndef PHYS_TO_K1
++// hack
++#define PHYS_TO_K1(x) (((unsigned int)(x)) | 0xA0000000) /* physical to kseg1 */
++#endif
++
++#define AR2313_TX_TIMEOUT (HZ/4)
++
++/*
++ * Rings
++ */
++#define DSC_RING_ENTRIES_SIZE (AR2313_DESCR_ENTRIES * sizeof(struct desc))
++#define DSC_NEXT(idx) ((idx + 1) & (AR2313_DESCR_ENTRIES - 1))
++
++static inline int tx_space (u32 csm, u32 prd)
++{
++ return (csm - prd - 1) & (AR2313_DESCR_ENTRIES - 1);
++}
++
++#if MAX_SKB_FRAGS
++#define TX_RESERVED (MAX_SKB_FRAGS+1) /* +1 for message header */
++#define tx_ring_full(csm, prd) (tx_space(csm, prd) <= TX_RESERVED)
++#else
++#define tx_ring_full 0
++#endif
++
++#define AR2313_MBGET 2
++#define AR2313_MBSET 3
++#define AR2313_PCI_RECONFIG 4
++#define AR2313_PCI_DUMP 5
++#define AR2313_TEST_PANIC 6
++#define AR2313_TEST_NULLPTR 7
++#define AR2313_READ_DATA 8
++#define AR2313_WRITE_DATA 9
++#define AR2313_GET_VERSION 10
++#define AR2313_TEST_HANG 11
++#define AR2313_SYNC 12
++
++
++struct ar2313_cmd {
++ u32 cmd;
++ u32 address; /* virtual address of image */
++ u32 length; /* size of image to download */
++ u32 mailbox; /* mailbox to get/set */
++ u32 data[2]; /* contents of mailbox to read/write */
++};
++
++
++/*
++ * Struct private for the Sibyte.
++ *
++ * Elements are grouped so variables used by the tx handling goes
++ * together, and will go into the same cache lines etc. in order to
++ * avoid cache line contention between the rx and tx handling on SMP.
++ *
++ * Frequently accessed variables are put at the beginning of the
++ * struct to help the compiler generate better/shorter code.
++ */
++struct ar2313_private
++{
++ int version;
++ u32 mb[2];
++
++ volatile ETHERNET_STRUCT *eth_regs;
++ volatile DMA *dma_regs;
++ volatile u32 *int_regs;
++
++ spinlock_t lock; /* Serialise access to device */
++
++ /*
++ * RX and TX descriptors, must be adjacent
++ */
++ ar2313_descr_t *rx_ring;
++ ar2313_descr_t *tx_ring;
++
++
++ struct sk_buff **rx_skb;
++ struct sk_buff **tx_skb;
++
++ /*
++ * RX elements
++ */
++ u32 rx_skbprd;
++ u32 cur_rx;
++
++ /*
++ * TX elements
++ */
++ u32 tx_prd;
++ u32 tx_csm;
++
++ /*
++ * Misc elements
++ */
++ int board_idx;
++ char name[48];
++ struct net_device_stats stats;
++ struct {
++ u32 address;
++ u32 length;
++ char *mapping;
++ } desc;
++
++
++ struct timer_list link_timer;
++ unsigned short phy; /* merlot phy = 1, samsung phy = 0x1f */
++ unsigned short mac;
++ unsigned short link; /* 0 - link down, 1 - link up */
++ u16 phyData;
++
++ struct tasklet_struct rx_tasklet;
++ int unloading;
++};
++
++
++/*
++ * Prototypes
++ */
++static int ar2313_init(struct net_device *dev);
++#ifdef TX_TIMEOUT
++static void ar2313_tx_timeout(struct net_device *dev);
++#endif
++#if 0
++static void ar2313_multicast_list(struct net_device *dev);
++#endif
++static int ar2313_restart(struct net_device *dev);
++#if DEBUG
++static void ar2313_dump_regs(struct net_device *dev);
++#endif
++static void ar2313_load_rx_ring(struct net_device *dev, int bufs);
++static irqreturn_t ar2313_interrupt(int irq, void *dev_id, struct pt_regs *regs);
++static int ar2313_open(struct net_device *dev);
++static int ar2313_start_xmit(struct sk_buff *skb, struct net_device *dev);
++static int ar2313_close(struct net_device *dev);
++static int ar2313_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
++static void ar2313_init_cleanup(struct net_device *dev);
++static int ar2313_setup_timer(struct net_device *dev);
++static void ar2313_link_timer_fn(unsigned long data);
++static void ar2313_check_link(struct net_device *dev);
++static struct net_device_stats *ar2313_get_stats(struct net_device *dev);
++#endif /* _AR2313_H_ */
+diff -Nur linux-2.6.17/drivers/net/ar2313/ar2313_msg.h linux-2.6.17-owrt/drivers/net/ar2313/ar2313_msg.h
+--- linux-2.6.17/drivers/net/ar2313/ar2313_msg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/drivers/net/ar2313/ar2313_msg.h 2006-06-19 12:05:29.000000000 +0200
+@@ -0,0 +1,17 @@
++#ifndef _AR2313_MSG_H_
++#define _AR2313_MSG_H_
++
++#define AR2313_MTU 1692
++#define AR2313_PRIOS 1
++#define AR2313_QUEUES (2*AR2313_PRIOS)
++
++#define AR2313_DESCR_ENTRIES 64
++
++typedef struct {
++ volatile unsigned int status; // OWN, Device control and status.
++ volatile unsigned int devcs; // pkt Control bits + Length
++ volatile unsigned int addr; // Current Address.
++ volatile unsigned int descr; // Next descriptor in chain.
++} ar2313_descr_t;
++
++#endif /* _AR2313_MSG_H_ */
+diff -Nur linux-2.6.17/drivers/net/ar2313/dma.h linux-2.6.17-owrt/drivers/net/ar2313/dma.h
+--- linux-2.6.17/drivers/net/ar2313/dma.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/drivers/net/ar2313/dma.h 2006-06-19 12:05:29.000000000 +0200
+@@ -0,0 +1,135 @@
++#ifndef __ARUBA_DMA_H__
++#define __ARUBA_DMA_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * DMA register definition.
++ *
++ * File : $Id: dma.h,v 1.3 2002/06/06 18:34:03 astichte Exp $
++ *
++ * Author : ryan.holmQVist@idt.com
++ * Date : 20011005
++ * Update :
++ * $Log: dma.h,v $
++ * Revision 1.3 2002/06/06 18:34:03 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.2 2002/06/05 18:30:46 astichte
++ * Removed IDTField
++ *
++ * Revision 1.1 2002/05/29 17:33:21 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ *
++ ******************************************************************************/
++
++#define AR_BIT(x) (1 << (x))
++#define DMA_RX_ERR_CRC AR_BIT(1)
++#define DMA_RX_ERR_DRIB AR_BIT(2)
++#define DMA_RX_ERR_MII AR_BIT(3)
++#define DMA_RX_EV2 AR_BIT(5)
++#define DMA_RX_ERR_COL AR_BIT(6)
++#define DMA_RX_LONG AR_BIT(7)
++#define DMA_RX_LS AR_BIT(8) /* last descriptor */
++#define DMA_RX_FS AR_BIT(9) /* first descriptor */
++#define DMA_RX_MF AR_BIT(10) /* multicast frame */
++#define DMA_RX_ERR_RUNT AR_BIT(11) /* runt frame */
++#define DMA_RX_ERR_LENGTH AR_BIT(12) /* length error */
++#define DMA_RX_ERR_DESC AR_BIT(14) /* descriptor error */
++#define DMA_RX_ERROR AR_BIT(15) /* error summary */
++#define DMA_RX_LEN_MASK 0x3fff0000
++#define DMA_RX_LEN_SHIFT 16
++#define DMA_RX_FILT AR_BIT(30)
++#define DMA_RX_OWN AR_BIT(31) /* desc owned by DMA controller */
++
++#define DMA_RX1_BSIZE_MASK 0x000007ff
++#define DMA_RX1_BSIZE_SHIFT 0
++#define DMA_RX1_CHAINED AR_BIT(24)
++#define DMA_RX1_RER AR_BIT(25)
++
++#define DMA_TX_ERR_UNDER AR_BIT(1) /* underflow error */
++#define DMA_TX_ERR_DEFER AR_BIT(2) /* excessive deferral */
++#define DMA_TX_COL_MASK 0x78
++#define DMA_TX_COL_SHIFT 3
++#define DMA_TX_ERR_HB AR_BIT(7) /* hearbeat failure */
++#define DMA_TX_ERR_COL AR_BIT(8) /* excessive collisions */
++#define DMA_TX_ERR_LATE AR_BIT(9) /* late collision */
++#define DMA_TX_ERR_LINK AR_BIT(10) /* no carrier */
++#define DMA_TX_ERR_LOSS AR_BIT(11) /* loss of carrier */
++#define DMA_TX_ERR_JABBER AR_BIT(14) /* transmit jabber timeout */
++#define DMA_TX_ERROR AR_BIT(15) /* frame aborted */
++#define DMA_TX_OWN AR_BIT(31) /* descr owned by DMA controller */
++
++#define DMA_TX1_BSIZE_MASK 0x000007ff
++#define DMA_TX1_BSIZE_SHIFT 0
++#define DMA_TX1_CHAINED AR_BIT(24) /* chained descriptors */
++#define DMA_TX1_TER AR_BIT(25) /* transmit end of ring */
++#define DMA_TX1_FS AR_BIT(29) /* first segment */
++#define DMA_TX1_LS AR_BIT(30) /* last segment */
++#define DMA_TX1_IC AR_BIT(31) /* interrupt on completion */
++
++#define RCVPKT_LENGTH(X) (X >> 16) /* Received pkt Length */
++
++#define MAC_CONTROL_RE AR_BIT(2) /* receive enable */
++#define MAC_CONTROL_TE AR_BIT(3) /* transmit enable */
++#define MAC_CONTROL_DC AR_BIT(5) /* Deferral check*/
++#define MAC_CONTROL_ASTP AR_BIT(8) /* Auto pad strip */
++#define MAC_CONTROL_DRTY AR_BIT(10) /* Disable retry */
++#define MAC_CONTROL_DBF AR_BIT(11) /* Disable bcast frames */
++#define MAC_CONTROL_LCC AR_BIT(12) /* late collision ctrl */
++#define MAC_CONTROL_HP AR_BIT(13) /* Hash Perfect filtering */
++#define MAC_CONTROL_HASH AR_BIT(14) /* Unicast hash filtering */
++#define MAC_CONTROL_HO AR_BIT(15) /* Hash only filtering */
++#define MAC_CONTROL_PB AR_BIT(16) /* Pass Bad frames */
++#define MAC_CONTROL_IF AR_BIT(17) /* Inverse filtering */
++#define MAC_CONTROL_PR AR_BIT(18) /* promiscuous mode (valid frames only) */
++#define MAC_CONTROL_PM AR_BIT(19) /* pass multicast */
++#define MAC_CONTROL_F AR_BIT(20) /* full-duplex */
++#define MAC_CONTROL_DRO AR_BIT(23) /* Disable Receive Own */
++#define MAC_CONTROL_HBD AR_BIT(28) /* heart-beat disabled (MUST BE SET) */
++#define MAC_CONTROL_BLE AR_BIT(30) /* big endian mode */
++#define MAC_CONTROL_RA AR_BIT(31) /* receive all (valid and invalid frames) */
++
++#define MII_ADDR_BUSY AR_BIT(0)
++#define MII_ADDR_WRITE AR_BIT(1)
++#define MII_ADDR_REG_SHIFT 6
++#define MII_ADDR_PHY_SHIFT 11
++#define MII_DATA_SHIFT 0
++
++#define FLOW_CONTROL_FCE AR_BIT(1)
++
++#define DMA_BUS_MODE_SWR AR_BIT(0) /* software reset */
++#define DMA_BUS_MODE_BLE AR_BIT(7) /* big endian mode */
++#define DMA_BUS_MODE_PBL_SHIFT 8 /* programmable burst length 32 */
++#define DMA_BUS_MODE_DBO AR_BIT(20) /* big-endian descriptors */
++
++#define DMA_STATUS_TI AR_BIT(0) /* transmit interrupt */
++#define DMA_STATUS_TPS AR_BIT(1) /* transmit process stopped */
++#define DMA_STATUS_TU AR_BIT(2) /* transmit buffer unavailable */
++#define DMA_STATUS_TJT AR_BIT(3) /* transmit buffer timeout */
++#define DMA_STATUS_UNF AR_BIT(5) /* transmit underflow */
++#define DMA_STATUS_RI AR_BIT(6) /* receive interrupt */
++#define DMA_STATUS_RU AR_BIT(7) /* receive buffer unavailable */
++#define DMA_STATUS_RPS AR_BIT(8) /* receive process stopped */
++#define DMA_STATUS_ETI AR_BIT(10) /* early transmit interrupt */
++#define DMA_STATUS_FBE AR_BIT(13) /* fatal bus interrupt */
++#define DMA_STATUS_ERI AR_BIT(14) /* early receive interrupt */
++#define DMA_STATUS_AIS AR_BIT(15) /* abnormal interrupt summary */
++#define DMA_STATUS_NIS AR_BIT(16) /* normal interrupt summary */
++#define DMA_STATUS_RS_SHIFT 17 /* receive process state */
++#define DMA_STATUS_TS_SHIFT 20 /* transmit process state */
++#define DMA_STATUS_EB_SHIFT 23 /* error bits */
++
++#define DMA_CONTROL_SR AR_BIT(1) /* start receive */
++#define DMA_CONTROL_ST AR_BIT(13) /* start transmit */
++#define DMA_CONTROL_SF AR_BIT(21) /* store and forward */
++
++#endif // __ARUBA_DMA_H__
++
++
++
++
++
+diff -Nur linux-2.6.17/drivers/net/ar2313/Makefile linux-2.6.17-owrt/drivers/net/ar2313/Makefile
+--- linux-2.6.17/drivers/net/ar2313/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/drivers/net/ar2313/Makefile 2006-06-19 12:25:58.000000000 +0200
+@@ -0,0 +1,5 @@
++#
++# Makefile for the AR2313 ethernet driver
++#
++
++obj-$(CONFIG_AR2313) += ar2313.o
+diff -Nur linux-2.6.17/drivers/net/ar2313/platform.h linux-2.6.17-owrt/drivers/net/ar2313/platform.h
+--- linux-2.6.17/drivers/net/ar2313/platform.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/drivers/net/ar2313/platform.h 2006-06-19 12:05:29.000000000 +0200
+@@ -0,0 +1,128 @@
++/********************************************************************************
++ Title: $Source: platform.h,v $
++
++ Author: Dan Steinberg
++ Copyright Integrated Device Technology 2001
++
++ Purpose: AR2313 Register/Bit Definitions
++
++ Update:
++ $Log: platform.h,v $
++
++ Notes: See Merlot architecture spec for complete details. Note, all
++ addresses are virtual addresses in kseg1 (Uncached, Unmapped).
++
++********************************************************************************/
++
++#ifndef PLATFORM_H
++#define PLATFORM_H
++
++#define BIT(x) (1 << (x))
++
++#define RESET_BASE 0xBC003020
++#define RESET_VALUE 0x00000001
++
++/********************************************************************
++ * Device controller
++ ********************************************************************/
++typedef struct {
++ volatile unsigned int flash0;
++} DEVICE;
++
++#define device (*((volatile DEVICE *) DEV_CTL_BASE))
++
++// DDRC register
++#define DEV_WP (1<<26)
++
++/********************************************************************
++ * DDR controller
++ ********************************************************************/
++typedef struct {
++ volatile unsigned int ddrc0;
++ volatile unsigned int ddrc1;
++ volatile unsigned int ddrrefresh;
++} DDR;
++
++#define ddr (*((volatile DDR *) DDR_BASE))
++
++// DDRC register
++#define DDRC_CS(i) ((i&0x3)<<0)
++#define DDRC_WE (1<<2)
++
++/********************************************************************
++ * Ethernet interfaces
++ ********************************************************************/
++#define ETHERNET_BASE 0xB8200000
++
++//
++// New Combo structure for Both Eth0 AND eth1
++//
++typedef struct {
++ volatile unsigned int mac_control; /* 0x00 */
++ volatile unsigned int mac_addr[2]; /* 0x04 - 0x08*/
++ volatile unsigned int mcast_table[2]; /* 0x0c - 0x10 */
++ volatile unsigned int mii_addr; /* 0x14 */
++ volatile unsigned int mii_data; /* 0x18 */
++ volatile unsigned int flow_control; /* 0x1c */
++ volatile unsigned int vlan_tag; /* 0x20 */
++ volatile unsigned int pad[7]; /* 0x24 - 0x3c */
++ volatile unsigned int ucast_table[8]; /* 0x40-0x5c */
++
++} ETHERNET_STRUCT;
++
++/********************************************************************
++ * Interrupt controller
++ ********************************************************************/
++
++typedef struct {
++ volatile unsigned int wdog_control; /* 0x08 */
++ volatile unsigned int wdog_timer; /* 0x0c */
++ volatile unsigned int misc_status; /* 0x10 */
++ volatile unsigned int misc_mask; /* 0x14 */
++ volatile unsigned int global_status; /* 0x18 */
++ volatile unsigned int reserved; /* 0x1c */
++ volatile unsigned int reset_control; /* 0x20 */
++} INTERRUPT;
++
++#define interrupt (*((volatile INTERRUPT *) INTERRUPT_BASE))
++
++#define INTERRUPT_MISC_TIMER BIT(0)
++#define INTERRUPT_MISC_AHBPROC BIT(1)
++#define INTERRUPT_MISC_AHBDMA BIT(2)
++#define INTERRUPT_MISC_GPIO BIT(3)
++#define INTERRUPT_MISC_UART BIT(4)
++#define INTERRUPT_MISC_UARTDMA BIT(5)
++#define INTERRUPT_MISC_WATCHDOG BIT(6)
++#define INTERRUPT_MISC_LOCAL BIT(7)
++
++#define INTERRUPT_GLOBAL_ETH BIT(2)
++#define INTERRUPT_GLOBAL_WLAN BIT(3)
++#define INTERRUPT_GLOBAL_MISC BIT(4)
++#define INTERRUPT_GLOBAL_ITIMER BIT(5)
++
++/********************************************************************
++ * DMA controller
++ ********************************************************************/
++#define DMA_BASE 0xB8201000
++
++typedef struct {
++ volatile unsigned int bus_mode; /* 0x00 (CSR0) */
++ volatile unsigned int xmt_poll; /* 0x04 (CSR1) */
++ volatile unsigned int rcv_poll; /* 0x08 (CSR2) */
++ volatile unsigned int rcv_base; /* 0x0c (CSR3) */
++ volatile unsigned int xmt_base; /* 0x10 (CSR4) */
++ volatile unsigned int status; /* 0x14 (CSR5) */
++ volatile unsigned int control; /* 0x18 (CSR6) */
++ volatile unsigned int intr_ena; /* 0x1c (CSR7) */
++ volatile unsigned int rcv_missed; /* 0x20 (CSR8) */
++ volatile unsigned int reserved[11]; /* 0x24-0x4c (CSR9-19) */
++ volatile unsigned int cur_tx_buf_addr; /* 0x50 (CSR20) */
++ volatile unsigned int cur_rx_buf_addr; /* 0x50 (CSR21) */
++} DMA;
++
++#define dma (*((volatile DMA *) DMA_BASE))
++
++// macro to convert from virtual to physical address
++#define phys_addr(x) (x & 0x1fffffff)
++
++#endif /* PLATFORM_H */
+diff -Nur linux-2.6.17/drivers/net/Kconfig linux-2.6.17-owrt/drivers/net/Kconfig
+--- linux-2.6.17/drivers/net/Kconfig 2006-06-19 12:05:01.000000000 +0200
++++ linux-2.6.17-owrt/drivers/net/Kconfig 2006-06-19 12:26:35.000000000 +0200
+@@ -310,6 +310,12 @@
+
+ source "drivers/net/arm/Kconfig"
+
++config AR2313
++ tristate "AR2313 Ethernet support"
++ depends on NET_ETHERNET && MACH_ARUBA
++ help
++ Support for the AR2313 Ethernet part on Aruba AP60/61
++
+ config IDT_RC32434_ETH
+ tristate "IDT RC32434 Local Ethernet support"
+ depends on NET_ETHERNET
+diff -Nur linux-2.6.17/drivers/net/Makefile linux-2.6.17-owrt/drivers/net/Makefile
+--- linux-2.6.17/drivers/net/Makefile 2006-06-19 12:05:01.000000000 +0200
++++ linux-2.6.17-owrt/drivers/net/Makefile 2006-06-19 12:27:02.000000000 +0200
+@@ -12,6 +12,7 @@
+ obj-$(CONFIG_CHELSIO_T1) += chelsio/
+ obj-$(CONFIG_BONDING) += bonding/
+ obj-$(CONFIG_GIANFAR) += gianfar_driver.o
++obj-$(CONFIG_AR2313) += ar2313/
+
+ gianfar_driver-objs := gianfar.o \
+ gianfar_ethtool.o \
diff --git a/target/linux/aruba-2.6/patches/011-ap6x_serial_fix.patch b/target/linux/aruba-2.6/patches/011-ap6x_serial_fix.patch
new file mode 100644
index 0000000..528d0e9
--- /dev/null
+++ b/target/linux/aruba-2.6/patches/011-ap6x_serial_fix.patch
@@ -0,0 +1,31 @@
+diff -urN linux.old/drivers/serial/8250.c linux.net/drivers/serial/8250.c
+--- linux.old/drivers/serial/8250.c 2006-01-15 07:16:02.000000000 +0100
++++ linux.net/drivers/serial/8250.c 2006-01-30 06:12:30.509342250 +0100
+@@ -1510,7 +1510,7 @@
+ {
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ unsigned long flags;
+- unsigned char lsr, iir;
++// unsigned char lsr, iir;
+ int retval;
+
+ up->capabilities = uart_config[up->port.type].flags;
+@@ -1615,6 +1615,8 @@
+
+ serial8250_set_mctrl(&up->port, up->port.mctrl);
+
++// For some reason this test causes problems on the AP6x serial console
++#if 0
+ /*
+ * Do a quick test to see if we receive an
+ * interrupt when we enable the TX irq.
+@@ -1633,7 +1635,8 @@
+ } else {
+ up->bugs &= ~UART_BUG_TXEN;
+ }
+-
++#endif
++
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
+ /*
diff --git a/target/linux/aruba-2.6/patches/012-ehci_softirq.patch b/target/linux/aruba-2.6/patches/012-ehci_softirq.patch
new file mode 100644
index 0000000..ae7f9f2
--- /dev/null
+++ b/target/linux/aruba-2.6/patches/012-ehci_softirq.patch
@@ -0,0 +1,70 @@
+diff -Nurb linux-2.6.16.1/drivers/usb/host/ehci.h linux-patched/drivers/usb/host/ehci.h
+--- linux-2.6.16.1/drivers/usb/host/ehci.h 2006-03-27 22:49:02.000000000 -0800
++++ linux-patched/drivers/usb/host/ehci.h 2006-04-07 12:07:30.000000000 -0700
+@@ -82,6 +82,7 @@
+ struct dma_pool *sitd_pool; /* sitd per split iso urb */
+
+ struct timer_list watchdog;
++ struct timer_list softirq;
+ struct notifier_block reboot_notifier;
+ unsigned long actions;
+ unsigned stamp;
+diff -Nurb linux-2.6.16.1/drivers/usb/host/ehci-hcd.c linux-patched/drivers/usb/host/ehci-hcd.c
+--- linux-2.6.16.1/drivers/usb/host/ehci-hcd.c 2006-03-27 22:49:02.000000000 -0800
++++ linux-patched/drivers/usb/host/ehci-hcd.c 2006-04-07 13:20:13.000000000 -0700
+@@ -116,6 +116,7 @@
+ #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
+ #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
+ #define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */
++#define EHCI_SOFTIRQ (HZ/400)
+
+ /* Initial IRQ latency: faster than hw default */
+ static int log2_irq_thresh = 0; // 0 to 6
+@@ -263,6 +264,16 @@
+ #include "ehci-sched.c"
+
+ /*-------------------------------------------------------------------------*/
++static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs);
++
++static void ehci_softirq (unsigned long param)
++{
++ struct ehci_hcd *ehci = (struct ehci_hcd *) param;
++
++ if (ehci_irq(ehci_to_hcd(ehci),0) != IRQ_NONE)
++ set_bit(HCD_FLAG_SAW_IRQ, &(ehci_to_hcd(ehci))->flags);
++ mod_timer (&ehci->softirq, jiffies + EHCI_SOFTIRQ);
++}
+
+ static void ehci_watchdog (unsigned long param)
+ {
+@@ -280,6 +291,10 @@
+ COUNT (ehci->stats.lost_iaa);
+ writel (STS_IAA, &ehci->regs->status);
+ ehci->reclaim_ready = 1;
++ if (!timer_pending(&ehci->softirq)) {
++ ehci_info(ehci, "switching to softirq\n");
++ mod_timer (&ehci->softirq, jiffies + EHCI_SOFTIRQ);
++ }
+ }
+ }
+
+@@ -371,6 +388,7 @@
+
+ /* no more interrupts ... */
+ del_timer_sync (&ehci->watchdog);
++ del_timer_sync (&ehci->softirq);
+
+ spin_lock_irq(&ehci->lock);
+ if (HC_IS_RUNNING (hcd->state))
+@@ -418,6 +436,10 @@
+ ehci->watchdog.function = ehci_watchdog;
+ ehci->watchdog.data = (unsigned long) ehci;
+
++ init_timer(&ehci->softirq);
++ ehci->softirq.function = ehci_softirq;
++ ehci->softirq.data = (unsigned long) ehci;
++
+ /*
+ * hw default: 1K periodic list heads, one per frame.
+ * periodic_size can shrink by USBCMD update if hcc_params allows.
+
diff --git a/target/linux/au1000-2.6/Makefile b/target/linux/au1000-2.6/Makefile
new file mode 100644
index 0000000..5d2711c
--- /dev/null
+++ b/target/linux/au1000-2.6/Makefile
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+LINUX_VERSION:=2.6.17
+LINUX_RELEASE:=1
+LINUX_KERNEL_MD5SUM:=37ddefe96625502161f075b9d907f21e
+
+include ./config
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/kernel-build.mk
+
+$(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked
+ [ -d ../generic-$(KERNEL)/patches ] && $(PATCH) $(LINUX_DIR) ../generic-$(KERNEL)/patches
+ [ -d ./patches ] && $(PATCH) $(LINUX_DIR) ./patches
+ @$(CP) config $(LINUX_DIR)/.config
+ touch $@
+
+$(LINUX_BUILD_DIR)/zImage.flash.srec: $(LINUX_DIR)/vmlinux
+ $(CP) $(LINUX_DIR)/arch/mips/boot/compressed/images/zImage.flash.srec $(LINUX_DIR)/zImage.flash.srec
+ $(CP) $(LINUX_DIR)/arch/mips/boot/compressed/images/zImage.srec $(LINUX_DIR)/zImage.srec
+
+compile: $(LINUX_BUILD_DIR)/zImage.flash.srec
diff --git a/target/linux/au1000-2.6/config b/target/linux/au1000-2.6/config
new file mode 100644
index 0000000..e94f884
--- /dev/null
+++ b/target/linux/au1000-2.6/config
@@ -0,0 +1,1595 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17
+# Mon Jul 31 19:15:16 2006
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+CONFIG_MIPS_MTX1=y
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SOC_AU1500=y
+CONFIG_SOC_AU1X00=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_MIPS_MT is not set
+CONFIG_64BIT_PHYS_ADDR=y
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_TRAD_SIGNALS=y
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=m
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_MULTIPATH_CACHED=y
+CONFIG_IP_ROUTE_MULTIPATH_RR=m
+CONFIG_IP_ROUTE_MULTIPATH_RANDOM=m
+CONFIG_IP_ROUTE_MULTIPATH_WRANDOM=m
+CONFIG_IP_ROUTE_MULTIPATH_DRR=m
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IPSEC_NAT_TRAVERSAL=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_ARPD=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+
+#
+# IPVS transport protocol load balancing support
+#
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+
+#
+# IPVS scheduler
+#
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+CONFIG_IP_VS_FTP=m
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=y
+CONFIG_IP_NF_IRC=y
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+CONFIG_IP_NF_SIP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_IPP2P=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_TIME=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+# CONFIG_IP_NF_TARGET_IMQ is not set
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_ROUTE=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=y
+CONFIG_IP_NF_NAT_FTP=y
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_SET=m
+CONFIG_IP_NF_SET_MAX=256
+CONFIG_IP_NF_SET_HASHSIZE=1024
+CONFIG_IP_NF_SET_IPMAP=m
+CONFIG_IP_NF_SET_MACIPMAP=m
+CONFIG_IP_NF_SET_PORTMAP=m
+CONFIG_IP_NF_SET_IPHASH=m
+CONFIG_IP_NF_SET_NETHASH=m
+CONFIG_IP_NF_SET_IPTREE=m
+CONFIG_IP_NF_MATCH_SET=m
+CONFIG_IP_NF_TARGET_SET=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_OWNER=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_IMQ=m
+# CONFIG_IP6_NF_TARGET_LOG is not set
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_HL is not set
+# CONFIG_IP6_NF_RAW is not set
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+CONFIG_IP_DCCP_ACKVEC=y
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP_CCID2=m
+CONFIG_IP_DCCP_CCID3=m
+CONFIG_IP_DCCP_TFRC_LIB=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+# CONFIG_TIPC_ADVANCED is not set
+# CONFIG_TIPC_DEBUG is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+CONFIG_LLC2=m
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_ESFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+CONFIG_IEEE80211_SOFTMAC=m
+# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=y
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=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
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ALCHEMY is not set
+CONFIG_MTD_MTX1=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR 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
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_IFB is not set
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+# CONFIG_EQUALIZER is not set
+CONFIG_IMQ=m
+# CONFIG_IMQ_BEHAVIOR_AA is not set
+# CONFIG_IMQ_BEHAVIOR_AB is not set
+CONFIG_IMQ_BEHAVIOR_BA=y
+# CONFIG_IMQ_BEHAVIOR_BB is not set
+CONFIG_IMQ_NUM_DEVS=2
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_MIPS_AU1X00_ENET=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+CONFIG_NET_WIRELESS_RTNETLINK=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+CONFIG_STRIP=m
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_IPW2100=m
+CONFIG_IPW2100_MONITOR=y
+CONFIG_IPW2100_DEBUG=y
+CONFIG_IPW2200=m
+CONFIG_IPW2200_MONITOR=y
+CONFIG_IPW_QOS=y
+CONFIG_IPW2200_DEBUG=y
+CONFIG_HERMES=m
+# CONFIG_PLX_HERMES is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_NORTEL_HERMES is not set
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+CONFIG_PCI_ATMEL=m
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_PRISM54=m
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+CONFIG_HOSTAP_PLX=m
+CONFIG_HOSTAP_PCI=m
+CONFIG_HOSTAP_CS=m
+CONFIG_BCM43XX=m
+CONFIG_BCM43XX_DEBUG=y
+CONFIG_BCM43XX_DMA=y
+CONFIG_BCM43XX_PIO=y
+CONFIG_BCM43XX_DMA_AND_PIO_MODE=y
+# CONFIG_BCM43XX_DMA_MODE is not set
+# CONFIG_BCM43XX_PIO_MODE is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+CONFIG_SHAPER=m
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=m
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+CONFIG_SERIAL_8250_AU1X00=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_MTX1_WATCHDOG=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+CONFIG_USB_DABUSB=m
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL 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_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+CONFIG_USB_MDC800=m
+CONFIG_USB_MICROTEK=m
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+# CONFIG_USB_NET_GL620A is not set
+CONFIG_USB_NET_NET1080=m
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_RNDIS_HOST is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+CONFIG_USB_NET_ZAURUS=m
+CONFIG_USB_ZD1201=m
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_AIRPRIME=m
+# CONFIG_USB_SERIAL_ANYDATA is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP2101=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_HP4X=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_AUERSWALD=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_LEGOTOWER=m
+CONFIG_USB_LCD=m
+CONFIG_USB_LED=m
+CONFIG_USB_CYTHERM=m
+CONFIG_USB_PHIDGETKIT=m
+CONFIG_USB_PHIDGETSERVO=m
+CONFIG_USB_IDMOUSE=m
+CONFIG_USB_LD=m
+CONFIG_USB_TEST=m
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=m
+CONFIG_RTC_CLASS=m
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=m
+CONFIG_RTC_INTF_PROC=m
+CONFIG_RTC_INTF_DEV=m
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=m
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+CONFIG_DEVFS_DEBUG=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_CONFIGFS_FS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_SQUASHFS_VMALLOC is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=m
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_FS is not set
+CONFIG_CROSSCOMPILE=y
+CONFIG_CMDLINE="init=/etc/preinit"
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=y
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/target/linux/au1000-2.6/patches/001-redefinitions_fixes.patch b/target/linux/au1000-2.6/patches/001-redefinitions_fixes.patch
new file mode 100644
index 0000000..f2c524a
--- /dev/null
+++ b/target/linux/au1000-2.6/patches/001-redefinitions_fixes.patch
@@ -0,0 +1,26 @@
+--- linux-2.6.16.2/drivers/usb/host/ohci-pci.c 2006-04-07 18:56:47.000000000 +0200
++++ linux-2.6.16.2.new/drivers/usb/host/ohci-pci.c 2006-04-11 14:20:33.000000000 +0200
+@@ -215,7 +215,7 @@
+ #endif
+ };
+
+-
++/*
+ static int __init ohci_hcd_pci_init (void)
+ {
+ printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
+@@ -227,11 +227,12 @@
+ return pci_register_driver (&ohci_pci_driver);
+ }
+ module_init (ohci_hcd_pci_init);
+-
++*/
+ /*-------------------------------------------------------------------------*/
+-
++/*
+ static void __exit ohci_hcd_pci_cleanup (void)
+ {
+ pci_unregister_driver (&ohci_pci_driver);
+ }
+ module_exit (ohci_hcd_pci_cleanup);
++*/
diff --git a/target/linux/au1000-2.6/patches/002-mtx1_flash_map.patch b/target/linux/au1000-2.6/patches/002-mtx1_flash_map.patch
new file mode 100644
index 0000000..9a6b05b
--- /dev/null
+++ b/target/linux/au1000-2.6/patches/002-mtx1_flash_map.patch
@@ -0,0 +1,16 @@
+diff -urN linux-2.6.16.7/drivers/mtd/maps/alchemy-flash.c linux-2.6.16.7.new/drivers/mtd/maps/alchemy-flash.c
+--- linux-2.6.16.7/drivers/mtd/maps/alchemy-flash.c 2006-04-17 23:53:25.000000000 +0200
++++ linux-2.6.16.7.new/drivers/mtd/maps/alchemy-flash.c 2006-04-20 19:16:26.000000000 +0200
+@@ -105,6 +105,12 @@
+ #define USE_LOCAL_ACCESSORS /* why? */
+ #endif
+
++#ifdef CONFIG_MIPS_MTX1
++#define BOARD_MAP_NAME "MTX-1 Flash"
++#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
++#define BOARD_FLASH_WIDTH 4 /* 32-bits */
++#endif
++
+ static struct map_info alchemy_map = {
+ .name = BOARD_MAP_NAME,
+ };
diff --git a/target/linux/au1000-2.6/patches/003-zImage.patch b/target/linux/au1000-2.6/patches/003-zImage.patch
new file mode 100644
index 0000000..1d4c6ad
--- /dev/null
+++ b/target/linux/au1000-2.6/patches/003-zImage.patch
@@ -0,0 +1,1364 @@
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/au1xxx/head.S linux-2.6.16.7.new/arch/mips/boot/compressed/au1xxx/head.S
+--- linux-2.6.16.7/arch/mips/boot/compressed/au1xxx/head.S 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/au1xxx/head.S 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,119 @@
++/*
++ * arch/mips/kernel/head.S
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 1994, 1995 Waldorf Electronics
++ * Written by Ralf Baechle and Andreas Busse
++ * Copyright (C) 1995 - 1999 Ralf Baechle
++ * Copyright (C) 1996 Paul M. Antoine
++ * Modified for DECStation and hence R3000 support by Paul M. Antoine
++ * Further modifications by David S. Miller and Harald Koerfgen
++ * Copyright (C) 1999 Silicon Graphics, Inc.
++ *
++ * Head.S contains the MIPS exception handler and startup code.
++ *
++ **************************************************************************
++ * 9 Nov, 2000.
++ * Added Cache Error exception handler and SBDDP EJTAG debug exception.
++ *
++ * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
++ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
++ **************************************************************************
++ */
++#include <linux/config.h>
++#include <linux/threads.h>
++
++#include <asm/asm.h>
++#include <asm/cacheops.h>
++#include <asm/mipsregs.h>
++#include <asm/cachectl.h>
++#include <asm/regdef.h>
++
++#define IndexInvalidate_I 0x00
++#define IndexWriteBack_D 0x01
++
++ .set noreorder
++ .cprestore
++ LEAF(start)
++start:
++ bal locate
++ nop
++locate:
++ subu s8, ra, 8 /* Where we were loaded */
++ la sp, (.stack + 8192)
++
++ move s0, a0 /* Save boot rom start args */
++ move s1, a1
++ move s2, a2
++ move s3, a3
++
++ la a0, start /* Where we were linked to run */
++
++ move a1, s8
++ la a2, _edata
++ subu t1, a2, a0
++ srl t1, t1, 2
++
++ /* copy text section */
++ li t0, 0
++1: lw v0, 0(a1)
++ nop
++ sw v0, 0(a0)
++ xor t0, t0, v0
++ addu a0, 4
++ bne a2, a0, 1b
++ addu a1, 4
++
++ /* Clear BSS */
++ la a0, _edata
++ la a2, _end
++2: sw zero, 0(a0)
++ bne a2, a0, 2b
++ addu a0, 4
++
++ /* push the D-Cache and invalidate I-Cache */
++ li k0, 0x80000000 # start address
++ li k1, 0x80004000 # end address (16KB I-Cache)
++ subu k1, 128
++
++1:
++ .set mips3
++ cache IndexWriteBack_D, 0(k0)
++ cache IndexWriteBack_D, 32(k0)
++ cache IndexWriteBack_D, 64(k0)
++ cache IndexWriteBack_D, 96(k0)
++ cache IndexInvalidate_I, 0(k0)
++ cache IndexInvalidate_I, 32(k0)
++ cache IndexInvalidate_I, 64(k0)
++ cache IndexInvalidate_I, 96(k0)
++ .set mips0
++
++ bne k0, k1, 1b
++ addu k0, k0, 128
++ /* done */
++
++ move a0, s8 /* load address */
++ move a1, t1 /* length in words */
++ move a2, t0 /* checksum */
++ move a3, sp
++
++ la ra, 1f
++ la k0, decompress_kernel
++ jr k0
++ nop
++1:
++
++ move a0, s0
++ move a1, s1
++ move a2, s2
++ move a3, s3
++ li k0, KERNEL_ENTRY
++ jr k0
++ nop
++3:
++ b 3b
++ END(start)
++ .comm .stack,4096*2,4
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/au1xxx/Makefile linux-2.6.16.7.new/arch/mips/boot/compressed/au1xxx/Makefile
+--- linux-2.6.16.7/arch/mips/boot/compressed/au1xxx/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/au1xxx/Makefile 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,110 @@
++# arch/mips/boot/compressed/au1xxx/Makefile
++#
++# Makefile for AMD Alchemy Semiconductor Au1x based boards.
++# All of the boot loader code was derived from the ppc
++# boot code.
++#
++# Copyright 2001,2002 MontaVista Software Inc.
++#
++# Author: Mark A. Greer
++# mgreer@mvista.com
++#
++# Copyright 2004 Embedded Alley Solutions, Inc
++# Ported and modified for mips 2.6 support by
++# Pete Popov <ppopov@embeddedalley.com>
++#
++# This program is free software; you can redistribute it and/or modify it
++# under the terms of the GNU General Public License as published by the
++# Free Software Foundation; either version 2 of the License, or (at your
++# option) any later version.
++
++boot := arch/mips/boot
++compressed := $(boot)/compressed
++utils := $(compressed)/utils
++lib := $(compressed)/lib
++images := $(compressed)/images
++common := $(compressed)/common
++
++#########################################################################
++# START BOARD SPECIFIC VARIABLES
++
++# These two variables control where the zImage is stored
++# in flash and loaded in memory. It only controls how the srec
++# file is generated, the code is the same.
++RAM_RUN_ADDR = 0x81000000
++
++ifdef CONFIG_MIPS_XXS1500
++FLASH_LOAD_ADDR = 0xBF000000
++else
++FLASH_LOAD_ADDR = 0xBFD00000
++endif
++
++# These two variables specify the free ram region
++# that can be used for temporary malloc area
++AVAIL_RAM_START=0x80500000
++AVAIL_RAM_END=0x80900000
++
++# This one must match the LOADADDR in arch/mips/Makefile!
++LOADADDR=0x80100000
++
++# WARNING WARNING WARNING
++# Note that with a LOADADDR of 0x80100000 and AVAIL_RAM_START of
++# 0x80500000, the max decompressed kernel size can be 4MB. Else we
++# start overwriting ourselve. You can change these vars as needed;
++# it would be much better if we just figured everything out on the fly.
++
++# END BOARD SPECIFIC VARIABLES
++#########################################################################
++
++OBJECTS := $(obj)/head.o $(common)/misc-common.o $(common)/misc-simple.o \
++ $(common)/au1k_uart.o
++LIBS := $(lib)/lib.a
++
++ENTRY := $(utils)/entry
++OFFSET := $(utils)/offset
++SIZE := $(utils)/size
++
++LD_ARGS := -T $(compressed)/ld.script -Ttext $(RAM_RUN_ADDR) -Bstatic
++
++ifdef CONFIG_CPU_LITTLE_ENDIAN
++OBJCOPY_ARGS = -O elf32-tradlittlemips
++else
++OBJCOPY_ARGS = -O elf32-tradbigmips
++endif
++
++$(obj)/head.o: $(obj)/head.S $(TOPDIR)/vmlinux
++ $(CC) -I $(TOPDIR)/include $(AFLAGS) \
++ -DKERNEL_ENTRY=$(shell sh $(ENTRY) $(NM) $(TOPDIR)/vmlinux ) \
++ -c -o $*.o $<
++
++$(common)/misc-simple.o:
++ $(CC) -I $(TOPDIR)/include $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 -DZIMAGE_OFFSET=0 \
++ -DAVAIL_RAM_START=$(AVAIL_RAM_START) \
++ -DAVAIL_RAM_END=$(AVAIL_RAM_END) \
++ -DLOADADDR=$(LOADADDR) \
++ -DZIMAGE_SIZE=0 -c -o $@ $*.c
++
++$(obj)/zvmlinux: $(OBJECTS) $(LIBS) $(srctree)/$(compressed)/ld.script $(images)/vmlinux.gz $(common)/dummy.o
++ $(OBJCOPY) \
++ --add-section=.image=$(images)/vmlinux.gz \
++ --set-section-flags=.image=contents,alloc,load,readonly,data \
++ $(common)/dummy.o $(common)/image.o
++ $(LD) $(LD_ARGS) -o $@ $(OBJECTS) $(common)/image.o $(LIBS)
++ $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R __kcrctab -R __ksymtab_strings \
++ -R .comment -R .stab -R .stabstr -R .initrd -R .sysmap
++
++# Here we manipulate the image in order to get it the necessary
++# srecord file we need.
++zImage: $(obj)/zvmlinux
++ mv $(obj)/zvmlinux $(images)/zImage
++ $(OBJCOPY) -O srec $(images)/zImage $(images)/zImage.srec
++ $(OBJCOPY) -O binary $(images)/zImage $(images)/zImage.bin
++
++zImage.flash: zImage
++ ( \
++ flash=${FLASH_LOAD_ADDR} ; \
++ ram=${RAM_RUN_ADDR} ; \
++ adjust=$$[ $$flash - $$ram ] ; \
++ $(OBJCOPY) -O srec --adjust-vma `printf '0x%08x' $$adjust` \
++ $(images)/zImage $(images)/zImage.flash.srec ; \
++ )
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/common/au1k_uart.c linux-2.6.16.7.new/arch/mips/boot/compressed/common/au1k_uart.c
+--- linux-2.6.16.7/arch/mips/boot/compressed/common/au1k_uart.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/common/au1k_uart.c 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,103 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ * Simple Au1000 uart routines.
++ *
++ * Copyright 2001 MontaVista Software Inc.
++ * Author: MontaVista Software, Inc.
++ * ppopov@mvista.com or source@mvista.com
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++#include <linux/config.h>
++#include <asm/io.h>
++#include <asm/mach-au1x00/au1000.h>
++#include "ns16550.h"
++
++typedef unsigned char uint8;
++typedef unsigned int uint32;
++
++#define UART16550_BAUD_2400 2400
++#define UART16550_BAUD_4800 4800
++#define UART16550_BAUD_9600 9600
++#define UART16550_BAUD_19200 19200
++#define UART16550_BAUD_38400 38400
++#define UART16550_BAUD_57600 57600
++#define UART16550_BAUD_115200 115200
++
++#define UART16550_PARITY_NONE 0
++#define UART16550_PARITY_ODD 0x08
++#define UART16550_PARITY_EVEN 0x18
++#define UART16550_PARITY_MARK 0x28
++#define UART16550_PARITY_SPACE 0x38
++
++#define UART16550_DATA_5BIT 0x0
++#define UART16550_DATA_6BIT 0x1
++#define UART16550_DATA_7BIT 0x2
++#define UART16550_DATA_8BIT 0x3
++
++#define UART16550_STOP_1BIT 0x0
++#define UART16550_STOP_2BIT 0x4
++
++/* It would be nice if we had a better way to do this.
++ * It could be a variable defined in one of the board specific files.
++ */
++#undef UART_BASE
++#ifdef CONFIG_COGENT_CSB250
++#define UART_BASE UART3_ADDR
++#else
++#define UART_BASE UART0_ADDR
++#endif
++
++/* memory-mapped read/write of the port */
++#define UART16550_READ(y) (au_readl(UART_BASE + y) & 0xff)
++#define UART16550_WRITE(y,z) (au_writel(z&0xff, UART_BASE + y))
++
++/*
++ * We use uart 0, which is already initialized by
++ * yamon.
++ */
++volatile struct NS16550 *
++serial_init(int chan)
++{
++ volatile struct NS16550 *com_port;
++ com_port = (struct NS16550 *) UART_BASE;
++ return (com_port);
++}
++
++void
++serial_putc(volatile struct NS16550 *com_port, unsigned char c)
++{
++ while ((UART16550_READ(UART_LSR)&0x40) == 0);
++ UART16550_WRITE(UART_TX, c);
++}
++
++unsigned char
++serial_getc(volatile struct NS16550 *com_port)
++{
++ while((UART16550_READ(UART_LSR) & 0x1) == 0);
++ return UART16550_READ(UART_RX);
++}
++
++int
++serial_tstc(volatile struct NS16550 *com_port)
++{
++ return((UART16550_READ(UART_LSR) & LSR_DR) != 0);
++}
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/common/dummy.c linux-2.6.16.7.new/arch/mips/boot/compressed/common/dummy.c
+--- linux-2.6.16.7/arch/mips/boot/compressed/common/dummy.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/common/dummy.c 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,4 @@
++int main(void)
++{
++ return 0;
++}
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/common/Makefile linux-2.6.16.7.new/arch/mips/boot/compressed/common/Makefile
+--- linux-2.6.16.7/arch/mips/boot/compressed/common/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/common/Makefile 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,14 @@
++#
++# arch/mips/boot/compressed/common/Makefile
++#
++# This file is subject to the terms and conditions of the GNU General Public
++# License. See the file "COPYING" in the main directory of this archive
++# for more details.
++#
++# Tom Rini January 2001
++#
++# Pete Popov, 2004
++#
++
++lib-y := misc-common.o no_initrd.o dummy.o
++lib-$(CONFIG_SOC_AU1X00) += au1k_uart.o
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/common/misc-common.c linux-2.6.16.7.new/arch/mips/boot/compressed/common/misc-common.c
+--- linux-2.6.16.7/arch/mips/boot/compressed/common/misc-common.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/common/misc-common.c 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,434 @@
++/*
++ * arch/mips/boot/compressed/common/misc-common.c
++ *
++ * Misc. bootloader code (almost) all platforms can use
++ *
++ * Author: Johnnie Peters <jpeters@mvista.com>
++ * Editor: Tom Rini <trini@mvista.com>
++ *
++ * Derived from arch/ppc/boot/prep/misc.c
++ *
++ * Ported by Pete Popov <ppopov@mvista.com> to
++ * support mips board(s). I also got rid of the vga console
++ * code.
++ *
++ * Copyright 2000-2001 MontaVista Software Inc.
++ *
++ * Ported to MIPS 2.6 by Pete Popov, <ppopov@embeddedalley.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <stdarg.h> /* for va_ bits */
++#include <linux/config.h>
++#include <linux/string.h>
++#include <linux/zlib.h>
++
++extern char *avail_ram;
++extern char *end_avail;
++extern char _end[];
++
++void puts(const char *);
++void putc(const char c);
++void puthex(unsigned long val);
++void _bcopy(char *src, char *dst, int len);
++void gunzip(void *, int, unsigned char *, int *);
++static int _cvt(unsigned long val, char *buf, long radix, char *digits);
++
++void _vprintk(void(*)(const char), const char *, va_list ap);
++
++struct NS16550 *com_port;
++
++int serial_tstc(volatile struct NS16550 *);
++unsigned char serial_getc(volatile struct NS16550 *);
++void serial_putc(volatile struct NS16550 *, unsigned char);
++
++void pause(void)
++{
++ puts("pause\n");
++}
++
++void exit(void)
++{
++ puts("exit\n");
++ while(1);
++}
++
++int tstc(void)
++{
++ return (serial_tstc(com_port));
++}
++
++int getc(void)
++{
++ while (1) {
++ if (serial_tstc(com_port))
++ return (serial_getc(com_port));
++ }
++}
++
++void
++putc(const char c)
++{
++ serial_putc(com_port, c);
++ if ( c == '\n' )
++ serial_putc(com_port, '\r');
++}
++
++void puts(const char *s)
++{
++ char c;
++ while ( ( c = *s++ ) != '\0' ) {
++ serial_putc(com_port, c);
++ if ( c == '\n' ) serial_putc(com_port, '\r');
++ }
++}
++
++void error(char *x)
++{
++ puts("\n\n");
++ puts(x);
++ puts("\n\n -- System halted");
++
++ while(1); /* Halt */
++}
++
++static void *zalloc(unsigned size)
++{
++ void *p = avail_ram;
++
++ size = (size + 7) & -8;
++ avail_ram += size;
++ if (avail_ram > end_avail) {
++ puts("oops... out of memory\n");
++ pause();
++ }
++ return p;
++}
++
++
++#define HEAD_CRC 2
++#define EXTRA_FIELD 4
++#define ORIG_NAME 8
++#define COMMENT 0x10
++#define RESERVED 0xe0
++
++#define DEFLATED 8
++
++void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
++{
++ z_stream s;
++ int r, i, flags;
++
++ /* skip header */
++ i = 10;
++ flags = src[3];
++ if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
++ puts("bad gzipped data\n");
++ exit();
++ }
++ if ((flags & EXTRA_FIELD) != 0)
++ i = 12 + src[10] + (src[11] << 8);
++ if ((flags & ORIG_NAME) != 0)
++ while (src[i++] != 0)
++ ;
++ if ((flags & COMMENT) != 0)
++ while (src[i++] != 0)
++ ;
++ if ((flags & HEAD_CRC) != 0)
++ i += 2;
++ if (i >= *lenp) {
++ puts("gunzip: ran out of data in header\n");
++ exit();
++ }
++
++ /* Initialize ourself. */
++ s.workspace = zalloc(zlib_inflate_workspacesize());
++ r = zlib_inflateInit2(&s, -MAX_WBITS);
++ if (r != Z_OK) {
++ puts("zlib_inflateInit2 returned "); puthex(r); puts("\n");
++ exit();
++ }
++ s.next_in = src + i;
++ s.avail_in = *lenp - i;
++ s.next_out = dst;
++ s.avail_out = dstlen;
++ r = zlib_inflate(&s, Z_FINISH);
++ if (r != Z_OK && r != Z_STREAM_END) {
++ puts("inflate returned "); puthex(r); puts("\n");
++ exit();
++ }
++ *lenp = s.next_out - (unsigned char *) dst;
++ zlib_inflateEnd(&s);
++}
++
++void
++puthex(unsigned long val)
++{
++
++ unsigned char buf[10];
++ int i;
++ for (i = 7; i >= 0; i--)
++ {
++ buf[i] = "0123456789ABCDEF"[val & 0x0F];
++ val >>= 4;
++ }
++ buf[8] = '\0';
++ puts(buf);
++}
++
++#define FALSE 0
++#define TRUE 1
++
++void
++_printk(char const *fmt, ...)
++{
++ va_list ap;
++
++ va_start(ap, fmt);
++ _vprintk(putc, fmt, ap);
++ va_end(ap);
++ return;
++}
++
++#define is_digit(c) ((c >= '0') && (c <= '9'))
++
++void
++_vprintk(void(*putc)(const char), const char *fmt0, va_list ap)
++{
++ char c, sign, *cp = 0;
++ int left_prec, right_prec, zero_fill, length = 0, pad, pad_on_right;
++ char buf[32];
++ long val;
++ while ((c = *fmt0++))
++ {
++ if (c == '%')
++ {
++ c = *fmt0++;
++ left_prec = right_prec = pad_on_right = 0;
++ if (c == '-')
++ {
++ c = *fmt0++;
++ pad_on_right++;
++ }
++ if (c == '0')
++ {
++ zero_fill = TRUE;
++ c = *fmt0++;
++ } else
++ {
++ zero_fill = FALSE;
++ }
++ while (is_digit(c))
++ {
++ left_prec = (left_prec * 10) + (c - '0');
++ c = *fmt0++;
++ }
++ if (c == '.')
++ {
++ c = *fmt0++;
++ zero_fill++;
++ while (is_digit(c))
++ {
++ right_prec = (right_prec * 10) + (c - '0');
++ c = *fmt0++;
++ }
++ } else
++ {
++ right_prec = left_prec;
++ }
++ sign = '\0';
++ switch (c)
++ {
++ case 'd':
++ case 'x':
++ case 'X':
++ val = va_arg(ap, long);
++ switch (c)
++ {
++ case 'd':
++ if (val < 0)
++ {
++ sign = '-';
++ val = -val;
++ }
++ length = _cvt(val, buf, 10, "0123456789");
++ break;
++ case 'x':
++ length = _cvt(val, buf, 16, "0123456789abcdef");
++ break;
++ case 'X':
++ length = _cvt(val, buf, 16, "0123456789ABCDEF");
++ break;
++ }
++ cp = buf;
++ break;
++ case 's':
++ cp = va_arg(ap, char *);
++ length = strlen(cp);
++ break;
++ case 'c':
++ c = va_arg(ap, long /*char*/);
++ (*putc)(c);
++ continue;
++ default:
++ (*putc)('?');
++ }
++ pad = left_prec - length;
++ if (sign != '\0')
++ {
++ pad--;
++ }
++ if (zero_fill)
++ {
++ c = '0';
++ if (sign != '\0')
++ {
++ (*putc)(sign);
++ sign = '\0';
++ }
++ } else
++ {
++ c = ' ';
++ }
++ if (!pad_on_right)
++ {
++ while (pad-- > 0)
++ {
++ (*putc)(c);
++ }
++ }
++ if (sign != '\0')
++ {
++ (*putc)(sign);
++ }
++ while (length-- > 0)
++ {
++ (*putc)(c = *cp++);
++ if (c == '\n')
++ {
++ (*putc)('\r');
++ }
++ }
++ if (pad_on_right)
++ {
++ while (pad-- > 0)
++ {
++ (*putc)(c);
++ }
++ }
++ } else
++ {
++ (*putc)(c);
++ if (c == '\n')
++ {
++ (*putc)('\r');
++ }
++ }
++ }
++}
++
++int
++_cvt(unsigned long val, char *buf, long radix, char *digits)
++{
++ char temp[80];
++ char *cp = temp;
++ int length = 0;
++ if (val == 0)
++ { /* Special case */
++ *cp++ = '0';
++ } else
++ while (val)
++ {
++ *cp++ = digits[val % radix];
++ val /= radix;
++ }
++ while (cp != temp)
++ {
++ *buf++ = *--cp;
++ length++;
++ }
++ *buf = '\0';
++ return (length);
++}
++
++void
++_dump_buf_with_offset(unsigned char *p, int s, unsigned char *base)
++{
++ int i, c;
++ if ((unsigned int)s > (unsigned int)p)
++ {
++ s = (unsigned int)s - (unsigned int)p;
++ }
++ while (s > 0)
++ {
++ if (base)
++ {
++ _printk("%06X: ", (int)p - (int)base);
++ } else
++ {
++ _printk("%06X: ", p);
++ }
++ for (i = 0; i < 16; i++)
++ {
++ if (i < s)
++ {
++ _printk("%02X", p[i] & 0xFF);
++ } else
++ {
++ _printk(" ");
++ }
++ if ((i % 2) == 1) _printk(" ");
++ if ((i % 8) == 7) _printk(" ");
++ }
++ _printk(" |");
++ for (i = 0; i < 16; i++)
++ {
++ if (i < s)
++ {
++ c = p[i] & 0xFF;
++ if ((c < 0x20) || (c >= 0x7F)) c = '.';
++ } else
++ {
++ c = ' ';
++ }
++ _printk("%c", c);
++ }
++ _printk("|\n");
++ s -= 16;
++ p += 16;
++ }
++}
++
++void
++_dump_buf(unsigned char *p, int s)
++{
++ _printk("\n");
++ _dump_buf_with_offset(p, s, 0);
++}
++
++/*
++ * Local variables:
++ * c-indent-level: 8
++ * c-basic-offset: 8
++ * tab-width: 8
++ * End:
++ */
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/common/misc-simple.c linux-2.6.16.7.new/arch/mips/boot/compressed/common/misc-simple.c
+--- linux-2.6.16.7/arch/mips/boot/compressed/common/misc-simple.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/common/misc-simple.c 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,122 @@
++/*
++ * arch/mips/zboot/common/misc-simple.c
++ *
++ * Misc. bootloader code for many machines. This assumes you have are using
++ * a 6xx/7xx/74xx CPU in your machine. This assumes the chunk of memory
++ * below 8MB is free. Finally, it assumes you have a NS16550-style uart for
++ * your serial console. If a machine meets these requirements, it can quite
++ * likely use this code during boot.
++ *
++ * Author: Matt Porter <mporter@mvista.com>
++ * Derived from arch/ppc/boot/prep/misc.c
++ *
++ * Copyright 2001 MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#include <linux/types.h>
++#include <linux/elf.h>
++#include <linux/config.h>
++
++#include <asm/page.h>
++
++#include "linux/zlib.h"
++
++extern struct NS16550 *com_port;
++
++char *avail_ram;
++char *end_avail;
++extern char _end[];
++char *zimage_start;
++
++#ifdef CONFIG_CMDLINE
++#define CMDLINE CONFIG_CMDLINE
++#else
++#define CMDLINE ""
++#endif
++char cmd_preset[] = CMDLINE;
++char cmd_buf[256];
++char *cmd_line = cmd_buf;
++
++/* The linker tells us where the image is.
++*/
++extern unsigned char __image_begin, __image_end;
++extern unsigned char __ramdisk_begin, __ramdisk_end;
++unsigned long initrd_size;
++
++extern void puts(const char *);
++extern void putc(const char c);
++extern void puthex(unsigned long val);
++extern void *memcpy(void * __dest, __const void * __src,
++ __kernel_size_t __n);
++extern void gunzip(void *, int, unsigned char *, int *);
++extern void udelay(long delay);
++extern int tstc(void);
++extern int getc(void);
++extern volatile struct NS16550 *serial_init(int chan);
++
++void
++decompress_kernel(unsigned long load_addr, int num_words,
++ unsigned long cksum, unsigned long *sp)
++{
++ extern unsigned long start;
++ int zimage_size;
++
++ com_port = (struct NS16550 *)serial_init(0);
++
++ initrd_size = (unsigned long)(&__ramdisk_end) -
++ (unsigned long)(&__ramdisk_begin);
++
++ /*
++ * Reveal where we were loaded at and where we
++ * were relocated to.
++ */
++ puts("loaded at: "); puthex(load_addr);
++ puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
++ if ( (unsigned long)load_addr != (unsigned long)&start )
++ {
++ puts("relocated to: "); puthex((unsigned long)&start);
++ puts(" ");
++ puthex((unsigned long)((unsigned long)&start + (4*num_words)));
++ puts("\n");
++ }
++
++ /*
++ * We link ourself to an arbitrary low address. When we run, we
++ * relocate outself to that address. __image_being points to
++ * the part of the image where the zImage is. -- Tom
++ */
++ zimage_start = (char *)(unsigned long)(&__image_begin);
++ zimage_size = (unsigned long)(&__image_end) -
++ (unsigned long)(&__image_begin);
++
++ /*
++ * The zImage and initrd will be between start and _end, so they've
++ * already been moved once. We're good to go now. -- Tom
++ */
++ puts("zimage at: "); puthex((unsigned long)zimage_start);
++ puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
++ puts("\n");
++
++ if ( initrd_size ) {
++ puts("initrd at: ");
++ puthex((unsigned long)(&__ramdisk_begin));
++ puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n");
++ }
++
++ /* assume the chunk below 8M is free */
++ avail_ram = (char *)AVAIL_RAM_START;
++ end_avail = (char *)AVAIL_RAM_END;
++
++ /* Display standard Linux/MIPS boot prompt for kernel args */
++ puts("Uncompressing Linux at load address ");
++ puthex(LOADADDR);
++ puts("\n");
++ /* I don't like this hard coded gunzip size (fixme) */
++ gunzip((void *)LOADADDR, 0x400000, zimage_start, &zimage_size);
++ puts("Now booting the kernel\n");
++}
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/common/no_initrd.c linux-2.6.16.7.new/arch/mips/boot/compressed/common/no_initrd.c
+--- linux-2.6.16.7/arch/mips/boot/compressed/common/no_initrd.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/common/no_initrd.c 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,2 @@
++char initrd_data[1];
++int initrd_len = 0;
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/images/Makefile linux-2.6.16.7.new/arch/mips/boot/compressed/images/Makefile
+--- linux-2.6.16.7/arch/mips/boot/compressed/images/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/images/Makefile 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,17 @@
++
++#
++# This dir holds all of the images for MIPS machines.
++# Tom Rini January 2001
++# Pete Popov 2004
++
++extra-y := vmlinux.bin vmlinux.gz
++
++OBJCOPYFLAGS_vmlinux.bin := -O binary
++$(obj)/vmlinux.bin: vmlinux FORCE
++ $(call if_changed,objcopy)
++
++$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
++ $(call if_changed,gzip)
++
++# Files generated that shall be removed upon make clean
++clean-files := vmlinux* zImage*
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/include/nonstdio.h linux-2.6.16.7.new/arch/mips/boot/compressed/include/nonstdio.h
+--- linux-2.6.16.7/arch/mips/boot/compressed/include/nonstdio.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/include/nonstdio.h 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,18 @@
++/*
++ * Copyright (C) Paul Mackerras 1997.
++ *
++ * 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.
++ */
++typedef int FILE;
++extern FILE *stdin, *stdout;
++#define NULL ((void *)0)
++#define EOF (-1)
++#define fopen(n, m) NULL
++#define fflush(f) 0
++#define fclose(f) 0
++extern char *fgets();
++
++#define perror(s) printf("%s: no files!\n", (s))
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/include/ns16550.h linux-2.6.16.7.new/arch/mips/boot/compressed/include/ns16550.h
+--- linux-2.6.16.7/arch/mips/boot/compressed/include/ns16550.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/include/ns16550.h 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,46 @@
++/*
++ * NS16550 Serial Port
++ */
++
++/*
++ * Figure out which file will have the definitons of COMx
++ */
++
++/* Some machines have their uart registers 16 bytes apart. Most don't.
++ * TODO: Make this work like drivers/char/serial does - Tom */
++#if !defined(UART_REG_PAD)
++#define UART_REG_PAD(x)
++#endif
++
++struct NS16550
++ {
++ unsigned char rbr; /* 0 */
++ UART_REG_PAD(rbr)
++ unsigned char ier; /* 1 */
++ UART_REG_PAD(ier)
++ unsigned char fcr; /* 2 */
++ UART_REG_PAD(fcr)
++ unsigned char lcr; /* 3 */
++ UART_REG_PAD(lcr)
++ unsigned char mcr; /* 4 */
++ UART_REG_PAD(mcr)
++ unsigned char lsr; /* 5 */
++ UART_REG_PAD(lsr)
++ unsigned char msr; /* 6 */
++ UART_REG_PAD(msr)
++ unsigned char scr; /* 7 */
++ };
++
++#define thr rbr
++#define iir fcr
++#define dll rbr
++#define dlm ier
++
++#define LSR_DR 0x01 /* Data ready */
++#define LSR_OE 0x02 /* Overrun */
++#define LSR_PE 0x04 /* Parity error */
++#define LSR_FE 0x08 /* Framing error */
++#define LSR_BI 0x10 /* Break */
++#define LSR_THRE 0x20 /* Xmit holding register empty */
++#define LSR_TEMT 0x40 /* Xmitter empty */
++#define LSR_ERR 0x80 /* Error */
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/include/pb1000_serial.h linux-2.6.16.7.new/arch/mips/boot/compressed/include/pb1000_serial.h
+--- linux-2.6.16.7/arch/mips/boot/compressed/include/pb1000_serial.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/include/pb1000_serial.h 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,20 @@
++/*
++ * arch/ppc/boot/include/sandpoint_serial.h
++ *
++ * Location of the COM ports on Motorola SPS Sandpoint machines
++ *
++ * Author: Mark A. Greer
++ * mgreer@mvista.com
++ *
++ * Copyright 2001 MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#define COM1 0xfe0003f8
++#define COM2 0xfe0002f8
++#define COM3 0x00000000 /* No COM3 */
++#define COM4 0x00000000 /* No COM4 */
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/ld.script linux-2.6.16.7.new/arch/mips/boot/compressed/ld.script
+--- linux-2.6.16.7/arch/mips/boot/compressed/ld.script 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/ld.script 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,151 @@
++OUTPUT_ARCH(mips)
++ENTRY(start)
++SECTIONS
++{
++ /* Read-only sections, merged into text segment: */
++ /* . = 0x81000000; */
++ .init : { *(.init) } =0
++ .text :
++ {
++ _ftext = . ;
++ *(.text)
++ *(.rodata) *(.rodata.*)
++ *(.rodata1)
++ /* .gnu.warning sections are handled specially by elf32.em. */
++ *(.gnu.warning)
++ } =0
++ .kstrtab : { *(.kstrtab) }
++
++ . = ALIGN(16); /* Exception table */
++ __start___ex_table = .;
++ __ex_table : { *(__ex_table) }
++ __stop___ex_table = .;
++
++ __start___dbe_table = .; /* Exception table for data bus errors */
++ __dbe_table : { *(__dbe_table) }
++ __stop___dbe_table = .;
++
++ __start___ksymtab = .; /* Kernel symbol table */
++ __ksymtab : { *(__ksymtab) }
++ __stop___ksymtab = .;
++
++ _etext = .;
++
++ . = ALIGN(8192);
++ .data.init_task : { *(.data.init_task) }
++
++ /* Startup code */
++ . = ALIGN(4096);
++ __init_begin = .;
++ .text.init : { *(.text.init) }
++ .data.init : { *(.data.init) }
++ . = ALIGN(16);
++ __setup_start = .;
++ .setup.init : { *(.setup.init) }
++ __setup_end = .;
++ __initcall_start = .;
++ .initcall.init : { *(.initcall.init) }
++ __initcall_end = .;
++ . = ALIGN(4096); /* Align double page for init_task_union */
++ __init_end = .;
++
++ . = ALIGN(4096);
++ .data.page_aligned : { *(.data.idt) }
++
++ . = ALIGN(32);
++ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
++
++ .fini : { *(.fini) } =0
++ .reginfo : { *(.reginfo) }
++ /* Adjust the address for the data segment. We want to adjust up to
++ the same address within the page on the next page up. It would
++ be more correct to do this:
++ . = .;
++ The current expression does not correctly handle the case of a
++ text segment ending precisely at the end of a page; it causes the
++ data segment to skip a page. The above expression does not have
++ this problem, but it will currently (2/95) cause BFD to allocate
++ a single segment, combining both text and data, for this case.
++ This will prevent the text segment from being shared among
++ multiple executions of the program; I think that is more
++ important than losing a page of the virtual address space (note
++ that no actual memory is lost; the page which is skipped can not
++ be referenced). */
++ . = .;
++ .data :
++ {
++ _fdata = . ;
++ *(.data)
++
++ /* Put the compressed image here, so bss is on the end. */
++ __image_begin = .;
++ *(.image)
++ __image_end = .;
++ /* Align the initial ramdisk image (INITRD) on page boundaries. */
++ . = ALIGN(4096);
++ __ramdisk_begin = .;
++ *(.initrd)
++ __ramdisk_end = .;
++ . = ALIGN(4096);
++
++ CONSTRUCTORS
++ }
++ .data1 : { *(.data1) }
++ _gp = . + 0x8000;
++ .lit8 : { *(.lit8) }
++ .lit4 : { *(.lit4) }
++ .ctors : { *(.ctors) }
++ .dtors : { *(.dtors) }
++ .got : { *(.got.plt) *(.got) }
++ .dynamic : { *(.dynamic) }
++ /* We want the small data sections together, so single-instruction offsets
++ can access them all, and initialized data all before uninitialized, so
++ we can shorten the on-disk segment size. */
++ .sdata : { *(.sdata) }
++ . = ALIGN(4);
++ _edata = .;
++ PROVIDE (edata = .);
++
++ __bss_start = .;
++ _fbss = .;
++ .sbss : { *(.sbss) *(.scommon) }
++ .bss :
++ {
++ *(.dynbss)
++ *(.bss)
++ *(COMMON)
++ . = ALIGN(4);
++ _end = . ;
++ PROVIDE (end = .);
++ }
++
++ /* Sections to be discarded */
++ /DISCARD/ :
++ {
++ *(.text.exit)
++ *(.data.exit)
++ *(.exitcall.exit)
++ }
++
++ /* This is the MIPS specific mdebug section. */
++ .mdebug : { *(.mdebug) }
++ /* These are needed for ELF backends which have not yet been
++ converted to the new style linker. */
++ .stab 0 : { *(.stab) }
++ .stabstr 0 : { *(.stabstr) }
++ /* DWARF debug sections.
++ Symbols in the .debug DWARF section are relative to the beginning of the
++ section so we begin .debug at 0. It's not clear yet what needs to happen
++ for the others. */
++ .debug 0 : { *(.debug) }
++ .debug_srcinfo 0 : { *(.debug_srcinfo) }
++ .debug_aranges 0 : { *(.debug_aranges) }
++ .debug_pubnames 0 : { *(.debug_pubnames) }
++ .debug_sfnames 0 : { *(.debug_sfnames) }
++ .line 0 : { *(.line) }
++ /* These must appear regardless of . */
++ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
++ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
++ .comment : { *(.comment) }
++ .note : { *(.note) }
++}
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/lib/Makefile linux-2.6.16.7.new/arch/mips/boot/compressed/lib/Makefile
+--- linux-2.6.16.7/arch/mips/boot/compressed/lib/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/lib/Makefile 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,11 @@
++
++#
++# Makefile for some libs needed by zImage.
++#
++
++lib-y := $(addprefix ../../../../../lib/zlib_inflate/, \
++ infblock.o infcodes.o inffast.o inflate.o inftrees.o infutil.o) \
++ $(addprefix ../../../../../lib/, ctype.o string.o) \
++ $(addprefix ../../../../../arch/mips/lib/, memcpy.o) \
++
++
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/Makefile linux-2.6.16.7.new/arch/mips/boot/compressed/Makefile
+--- linux-2.6.16.7/arch/mips/boot/compressed/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/Makefile 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,32 @@
++
++#
++# arch/mips/boot/compressed/Makefile
++#
++# This file is subject to the terms and conditions of the GNU General Public
++# License. See the file "COPYING" in the main directory of this archive
++# for more details.
++#
++# Copyright (C) 1994 by Linus Torvalds
++# Adapted for PowerPC by Gary Thomas
++# modified by Cort (cort@cs.nmt.edu)
++#
++# Ported to MIPS by Pete Popov, ppopov@embeddedalley.com
++#
++
++boot := arch/mips/boot
++compressed := arch/mips/boot/compressed
++
++CFLAGS += -fno-builtin -D__BOOTER__ -I$(compressed)/include
++
++BOOT_TARGETS = zImage zImage.flash
++
++bootdir-$(CONFIG_SOC_AU1X00) := au1xxx
++subdir-y := common lib images
++
++.PHONY: $(BOOT_TARGETS) $(bootdir-y)
++
++$(BOOT_TARGETS): $(bootdir-y)
++
++$(bootdir-y): $(addprefix $(obj)/,$(subdir-y)) \
++ $(addprefix $(obj)/,$(hostprogs-y))
++ $(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS)
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/utils/entry linux-2.6.16.7.new/arch/mips/boot/compressed/utils/entry
+--- linux-2.6.16.7/arch/mips/boot/compressed/utils/entry 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/utils/entry 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,12 @@
++#!/bin/sh
++
++# grab the kernel_entry address from the vmlinux elf image
++entry=`$1 $2 | grep kernel_entry`
++
++fs=`echo $entry | grep ffffffff` # check toolchain output
++
++if [ -n "$fs" ]; then
++ echo "0x"`$1 $2 | grep kernel_entry | cut -c9- | awk '{print $1}'`
++else
++ echo "0x"`$1 $2 | grep kernel_entry | cut -c1- | awk '{print $1}'`
++fi
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/utils/offset linux-2.6.16.7.new/arch/mips/boot/compressed/utils/offset
+--- linux-2.6.16.7/arch/mips/boot/compressed/utils/offset 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/utils/offset 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,3 @@
++#!/bin/sh
++
++echo "0x"`$1 -h $2 | grep $3 | grep -v zvmlinux| awk '{print $6}'`
+diff -urN linux-2.6.16.7/arch/mips/boot/compressed/utils/size linux-2.6.16.7.new/arch/mips/boot/compressed/utils/size
+--- linux-2.6.16.7/arch/mips/boot/compressed/utils/size 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/boot/compressed/utils/size 2006-05-04 23:08:18.000000000 +0200
+@@ -0,0 +1,4 @@
++#!/bin/sh
++
++OFFSET=`$1 -h $2 | grep $3 | grep -v zvmlinux | awk '{print $3}'`
++echo "0x"$OFFSET
+diff -urN linux-2.6.16.7/arch/mips/boot/Makefile linux-2.6.16.7.new/arch/mips/boot/Makefile
+--- linux-2.6.16.7/arch/mips/boot/Makefile 2006-04-17 23:53:25.000000000 +0200
++++ linux-2.6.16.7.new/arch/mips/boot/Makefile 2006-05-04 23:08:18.000000000 +0200
+@@ -16,6 +16,7 @@
+ E2EFLAGS =
+ endif
+
++
+ #
+ # Drop some uninteresting sections in the kernel.
+ # This is only relevant for ELF kernels but doesn't hurt a.out
+@@ -25,7 +26,10 @@
+
+ VMLINUX = vmlinux
+
+-all: vmlinux.ecoff vmlinux.srec addinitrd
++ZBOOT_TARGETS = zImage zImage.flash
++bootdir-y := compressed
++
++all: vmlinux.ecoff vmlinux.srec addinitrd zImage
+
+ vmlinux.ecoff: $(obj)/elf2ecoff $(VMLINUX)
+ $(obj)/elf2ecoff $(VMLINUX) vmlinux.ecoff $(E2EFLAGS)
+@@ -51,3 +55,11 @@
+ vmlinux.bin \
+ vmlinux.ecoff \
+ vmlinux.srec
++
++.PHONY: $(ZBOOT_TARGETS) $(bootdir-y)
++
++$(ZBOOT_TARGETS): $(bootdir-y)
++
++$(bootdir-y): $(addprefix $(obj)/,$(subdir-y)) \
++ $(addprefix $(obj)/,$(hostprogs-y))
++ $(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS)
+diff -urN linux-2.6.16.7/arch/mips/Makefile linux-2.6.16.7.new/arch/mips/Makefile
+--- linux-2.6.16.7/arch/mips/Makefile 2006-04-17 23:53:25.000000000 +0200
++++ linux-2.6.16.7.new/arch/mips/Makefile 2006-05-04 23:09:44.000000000 +0200
+@@ -831,6 +831,10 @@
+ all: vmlinux.ecoff
+ endif
+
++ifdef CONFIG_MIPS_MTX1
++all: vmlinux.srec zImage zImage.flash
++endif
++
+ vmlinux.bin: $(vmlinux-32)
+ +@$(call makeboot,$@)
+
+@@ -840,6 +844,12 @@
+ vmlinux.srec: $(vmlinux-32)
+ +@$(call makeboot,$@)
+
++zImage: vmlinux
++ +@$(call makeboot,$@)
++
++zImage.flash: vmlinux
++ +@$(call makeboot,$@)
++
+ CLEAN_FILES += vmlinux.ecoff \
+ vmlinux.srec \
+ vmlinux.rm200.tmp \
+@@ -848,6 +858,7 @@
+ archclean:
+ @$(MAKE) $(clean)=arch/mips/boot
+ @$(MAKE) $(clean)=arch/mips/lasat
++ @$(MAKE) $(clean)=arch/mips/boot/compressed
+
+ CLEAN_FILES += vmlinux.32 \
+ vmlinux.64 \
diff --git a/target/linux/au1000-2.6/patches/004-mtx1_watchdog.patch b/target/linux/au1000-2.6/patches/004-mtx1_watchdog.patch
new file mode 100644
index 0000000..c7e329b
--- /dev/null
+++ b/target/linux/au1000-2.6/patches/004-mtx1_watchdog.patch
@@ -0,0 +1,279 @@
+diff -urN linux-2.6.16.7/drivers/char/watchdog/Kconfig linux-2.6.16.7.new/drivers/char/watchdog/Kconfig
+--- linux-2.6.16.7/drivers/char/watchdog/Kconfig 2006-04-17 23:53:25.000000000 +0200
++++ linux-2.6.16.7.new/drivers/char/watchdog/Kconfig 2006-04-22 23:23:53.000000000 +0200
+@@ -460,6 +460,14 @@
+ timer expired and no process has written to /dev/watchdog during
+ that time.
+
++config MTX1_WATCHDOG
++ tristate "MTX-1 Hardware Watchdog"
++ depends on WATCHDOG && MIPS_MTX1
++ help
++ Hardware driver for the AccessCube MTX-1 watchdog. This is a
++ watchdog timer that will reboot the machine after a 100 seconds
++ timer expired.
++
+ # S390 Architecture
+
+ config ZVM_WATCHDOG
+diff -urN linux-2.6.16.7/drivers/char/watchdog/Makefile linux-2.6.16.7.new/drivers/char/watchdog/Makefile
+--- linux-2.6.16.7/drivers/char/watchdog/Makefile 2006-04-17 23:53:25.000000000 +0200
++++ linux-2.6.16.7.new/drivers/char/watchdog/Makefile 2006-04-22 23:21:18.000000000 +0200
+@@ -65,6 +65,7 @@
+
+ # MIPS Architecture
+ obj-$(CONFIG_INDYDOG) += indydog.o
++obj-$(CONFIG_MTX1_WATCHDOG) += mtx-1_watchdog.o
+
+ # S390 Architecture
+
+diff -urN linux-2.6.16.7/drivers/char/watchdog/mtx-1_watchdog.c linux-2.6.16.7.new/drivers/char/watchdog/mtx-1_watchdog.c
+--- linux-2.6.16.7/drivers/char/watchdog/mtx-1_watchdog.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/drivers/char/watchdog/mtx-1_watchdog.c 2006-04-22 23:20:53.000000000 +0200
+@@ -0,0 +1,246 @@
++/*
++ * Driver for the MTX-1 Watchdog.
++ *
++ * (c) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved.
++ * http://www.4g-systems.biz
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Neither Michael Stickel nor 4G Systems admit liability nor provide
++ * warranty for any of this software. This material is provided
++ * "AS-IS" and at no charge.
++ *
++ * (c) Copyright 2005 4G Systems <info@4g-systems.biz>
++ *
++ * Release 0.01.
++ *
++ * Author: Michael Stickel michael.stickel@4g-systems.biz
++ *
++ *
++ * The Watchdog is configured to reset the MTX-1
++ * if it is not triggered for 100 seconds.
++ * It should not be triggered more often than 1.6 seconds.
++ *
++ * A timer triggers the watchdog every 5 seconds, until
++ * it is opened for the first time. After the first open
++ * it MUST be triggered every 2..95 seconds.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <linux/fs.h>
++
++#include <asm/mach-au1x00/au1000.h>
++
++#ifndef FALSE
++# define FALSE (0)
++#endif
++
++#ifndef TRUE
++# define TRUE (!FALSE)
++#endif
++
++
++//---------[ Hardware Functions ]-----------------
++
++static void mtx1_trigger_wd (void)
++{
++ /*
++ * toggle GPIO2_15
++ */
++
++ u32 tmp = au_readl(GPIO2_DIR);
++ tmp = (tmp & ~(1<<15)) | ((~tmp) & (1<<15));
++ au_writel (tmp, GPIO2_DIR);
++}
++
++static void mtx1_enable_wd (void)
++{
++ au_writel (au_readl(GPIO2_DIR) | (u32)(1<<15), GPIO2_DIR);
++}
++
++static void mtx1_disable_wd (void)
++{
++ au_writel (au_readl(GPIO2_DIR) & ~((u32)(1<<15)), GPIO2_DIR);
++}
++
++
++//---------[ Timer Functions ]-----------------
++
++static struct timer_list wd_trigger_timer;
++static char timer_is_running = FALSE;
++
++static void wd_timer_callback (unsigned long data)
++{
++ if (timer_is_running)
++ mod_timer (&wd_trigger_timer, jiffies + 5 * HZ);
++ mtx1_trigger_wd();
++}
++
++static void start_wd_timer (void)
++{
++ if (!timer_is_running) {
++ struct timer_list *t = &wd_trigger_timer;
++
++ init_timer (t);
++ t->function = wd_timer_callback;
++ t->data = (unsigned long)0L;
++ t->expires = jiffies + 5 * HZ; // 5 seconds.
++ add_timer (t);
++ timer_is_running = TRUE;
++ }
++}
++
++
++
++static void stop_wd_timer (void)
++{
++ if (timer_is_running) {
++ del_timer(&wd_trigger_timer);
++ timer_is_running = FALSE;
++ }
++}
++
++
++//---------[ File Functions ]-----------------
++
++static char restart_after_close;
++
++static int mtx1wd_open (struct inode *inode, struct file *file)
++{
++ if (MINOR(inode->i_rdev) != WATCHDOG_MINOR) return -ENODEV;
++ //MOD_INC_USE_COUNT;
++
++ // stop the timer, if it is running. It will not be
++ // started again, until the module is loaded again.
++ stop_wd_timer();
++
++ // sleep for 2 seconds, to ensure, that the wd is
++ // not triggered more often than every 2 seconds.
++ schedule_timeout (2 * HZ);
++
++ return 0;
++}
++
++
++static int mtx1wd_release (struct inode *inode, struct file *file) {
++ if (MINOR(inode->i_rdev)==WATCHDOG_MINOR) {
++ }
++ if (restart_after_close)
++ start_wd_timer();
++ //MOD_DEC_USE_COUNT;
++ return 0;
++}
++
++
++static ssize_t mtx1wd_write (struct file *file, const char *buf, size_t count, loff_t *ppos) {
++
++ mtx1_trigger_wd ();
++
++ if (count > 0) {
++ char buffer[10];
++ int n = (count>9)?9:count;
++
++ if (copy_from_user (&buffer, buf, n))
++ return -EFAULT;
++ buffer[n]=0;
++
++ if (count >= 4 && strncmp("auto", buffer, 4)==0)
++ restart_after_close = 1;
++
++ else if (count >= 6 && strncmp("manual", buffer, 6)==0)
++ restart_after_close = 0;
++
++ return n;
++ }
++
++ return 0;
++}
++
++static ssize_t mtx1wd_read (struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++ char * state = restart_after_close ? "auto\n" : "manual\n";
++ int n = strlen(state)+1;
++
++ if (file->f_pos >= n)
++ return 0;
++
++ if (count < n)
++ return -EINVAL;
++
++ if(copy_to_user(buf, state, n))
++ return -EFAULT;
++
++ file->f_pos += n;
++
++ return n;
++}
++
++static struct file_operations mtx1wd_fops = {
++ .owner = THIS_MODULE,
++ .read = mtx1wd_read,
++ .write = mtx1wd_write,
++ .open = mtx1wd_open,
++ .release = mtx1wd_release
++};
++
++
++static struct miscdevice mtx1wd_miscdev = {
++ WATCHDOG_MINOR,
++ "watchdog",
++ &mtx1wd_fops
++};
++
++
++
++//---------[ Module Functions ]-----------------
++
++
++static int __init init_mtx1_watchdog(void)
++{
++ printk("MTX-1 watchdog driver\n");
++
++ misc_register(&mtx1wd_miscdev);
++
++ restart_after_close = 0;
++
++ mtx1_enable_wd ();
++
++ //-- trigger it for the first time.
++ //-- We do not exactly know how long it has not been triggered.
++ mtx1_trigger_wd ();
++
++ // start a timer, that calls mtx1_trigger_wd every 5 seconds.
++ start_wd_timer();
++
++ return 0;
++}
++
++static void __exit exit_mtx1_watchdog(void) {
++
++ // stop the timer, if it is running.
++ stop_wd_timer();
++
++ misc_deregister(&mtx1wd_miscdev);
++
++ mtx1_disable_wd();
++}
++
++module_init(init_mtx1_watchdog);
++module_exit(exit_mtx1_watchdog);
++
++MODULE_AUTHOR("Michael Stickel");
++MODULE_DESCRIPTION("Driver for the MTX-1 watchdog");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/au1000-2.6/patches/005-au1000_eth_link_beat.patch b/target/linux/au1000-2.6/patches/005-au1000_eth_link_beat.patch
new file mode 100644
index 0000000..946bd84
--- /dev/null
+++ b/target/linux/au1000-2.6/patches/005-au1000_eth_link_beat.patch
@@ -0,0 +1,24 @@
+diff -urN linux-2.6.16.7/drivers/net/au1000_eth.c linux-2.6.16.7.new/drivers/net/au1000_eth.c
+--- linux-2.6.16.7/drivers/net/au1000_eth.c 2006-04-17 23:53:25.000000000 +0200
++++ linux-2.6.16.7.new/drivers/net/au1000_eth.c 2006-04-23 01:42:48.000000000 +0200
+@@ -12,6 +12,9 @@
+ * Author: MontaVista Software, Inc.
+ * ppopov@mvista.com or source@mvista.com
+ *
++ * Bjoern Riemer 2004
++ * riemer@fokus.fraunhofer.de or riemer@riemer-nt.de
++ * // fixed the link beat detection with ioctls (SIOCGMIIPHY)
+ * ########################################################################
+ *
+ * This program is free software; you can distribute it and/or modify it
+@@ -1672,6 +1675,10 @@
+ aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed);
+ control = MAC_DISABLE_RX_OWN | MAC_RX_ENABLE | MAC_TX_ENABLE;
+ #ifndef CONFIG_CPU_LITTLE_ENDIAN
++ /*riemer: fix for startup without cable */
++ if (!link)
++ dev->flags &= ~IFF_RUNNING;
++
+ control |= MAC_BIG_ENDIAN;
+ #endif
+ if (link && (dev->if_port == IF_PORT_100BASEFX)) {
diff --git a/target/linux/au1000-2.6/patches/006-mtx1_system_button.patch b/target/linux/au1000-2.6/patches/006-mtx1_system_button.patch
new file mode 100644
index 0000000..511df2c
--- /dev/null
+++ b/target/linux/au1000-2.6/patches/006-mtx1_system_button.patch
@@ -0,0 +1,241 @@
+diff -urN linux-2.6.16.7/arch/mips/au1000/mtx-1/irqmap.c linux-2.6.16.7.new/arch/mips/au1000/mtx-1/irqmap.c
+--- linux-2.6.16.7/arch/mips/au1000/mtx-1/irqmap.c 2006-04-17 23:53:25.000000000 +0200
++++ linux-2.6.16.7.new/arch/mips/au1000/mtx-1/irqmap.c 2006-04-23 11:54:31.000000000 +0200
+@@ -64,6 +64,7 @@
+ { AU1500_GPIO_202, INTC_INT_LOW_LEVEL, 0 },
+ { AU1500_GPIO_203, INTC_INT_LOW_LEVEL, 0 },
+ { AU1500_GPIO_205, INTC_INT_LOW_LEVEL, 0 },
++ { AU1500_GPIO_207, INTC_INT_RISE_AND_FALL_EDGE, 0 },
+ };
+
+ int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t);
+diff -urN linux-2.6.16.7/arch/mips/au1000/mtx-1/Makefile linux-2.6.16.7.new/arch/mips/au1000/mtx-1/Makefile
+--- linux-2.6.16.7/arch/mips/au1000/mtx-1/Makefile 2006-04-17 23:53:25.000000000 +0200
++++ linux-2.6.16.7.new/arch/mips/au1000/mtx-1/Makefile 2006-04-23 14:01:36.000000000 +0200
+@@ -8,3 +8,4 @@
+ #
+
+ lib-y := init.o board_setup.o irqmap.o
++obj-y := mtx-1_sysbtn.o
+diff -urN linux-2.6.16.7/arch/mips/au1000/mtx-1/mtx-1_sysbtn.c linux-2.6.16.7.new/arch/mips/au1000/mtx-1/mtx-1_sysbtn.c
+--- linux-2.6.16.7/arch/mips/au1000/mtx-1/mtx-1_sysbtn.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7.new/arch/mips/au1000/mtx-1/mtx-1_sysbtn.c 2006-04-23 14:01:17.000000000 +0200
+@@ -0,0 +1,218 @@
++/*
++ * Driver for the MTX-1 System Button.
++ *
++ * (c) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved.
++ * http://www.4g-systems.biz
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Neither Michael Stickel nor 4G Systeme GmbH admit liability nor provide
++ * warranty for any of this software. This material is provided
++ * "AS-IS" and at no charge.
++ *
++ * (c) Copyright 2005 4G Systems <info@4g-systems.biz>
++ *
++ * Release 0.01.
++ *
++ * Author: Michael Stickel michael.stickel@4g-systems.biz
++ *
++ *
++ * After the module is loaded there is a device /dev/misc/btn
++ * that can be read. It returns one char '1' if the button
++ * has been pressed an '0' if it has been released.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/poll.h>
++#include <linux/sched.h>
++#include <linux/miscdevice.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++
++#include <asm/uaccess.h>
++
++#include <asm/mach-au1x00/au1000.h>
++
++
++#ifndef FALSE
++# define FALSE (0)
++#endif
++
++#ifndef TRUE
++# define TRUE (!FALSE)
++#endif
++
++
++//---------[ declarations ]-----------------
++
++
++static DECLARE_WAIT_QUEUE_HEAD(mtx1btn_wait_queue);
++static char state_changed;
++static char last_value;
++static char is_inuse;
++
++
++//---------[ Hardware Functions ]-----------------
++
++// The MTX-1 Button is attached to GPIO207.
++#define MTX1_GPIO2_SYSBTN (7)
++#define MTX1_SYSBTN_IRQ (AU1500_GPIO_207)
++
++
++static char mtx1_getbtn (int btnno)
++{
++ if (btnno==0) {
++ return (au_readl(GPIO2_PINSTATE) & (1<<MTX1_GPIO2_SYSBTN)) ? 0 : 1;
++ }
++ return 0;
++}
++
++static void mtx1_initbuttons (void)
++{
++ au_writel (au_readl(GPIO2_DIR) & ~(1<<MTX1_GPIO2_SYSBTN), GPIO2_DIR);
++}
++
++
++//---------[ Interrupt handling ]-----------------
++
++
++static void mtx1_btn_interrupt (int irq, void *private, struct pt_regs *regs)
++{
++ char value = mtx1_getbtn(0);
++ if (last_value != value)
++ {
++ last_value = value;
++ state_changed = 1;
++ wake_up (&mtx1btn_wait_queue);
++ }
++// kill_fasync(&async_queue, SIGIO, POLL_OUT);
++}
++
++
++static int mtx1_btn_startirq (void)
++{
++ if (!request_irq (MTX1_SYSBTN_IRQ, mtx1_btn_interrupt, 0 /* | SA_INTERRUPT */, "mtx1btn", (void *)&state_changed)) {
++ return 0;
++ }
++ return -1;
++}
++
++static int mtx1_btn_stopirq (void)
++{
++ free_irq(MTX1_SYSBTN_IRQ, (void *)&state_changed);
++ return 0;
++}
++
++
++
++//---------[ File Functions ]-----------------
++
++
++static int mtx1sysbtn_minor = -1;
++
++
++static int mtx1sysbtn_open (struct inode *inode, struct file *file)
++{
++ if (MINOR(inode->i_rdev)!=mtx1sysbtn_minor) return -ENODEV;
++ if (is_inuse) return -EBUSY;
++ is_inuse=1;
++ last_value = mtx1_getbtn(0);
++ state_changed = 0;
++ return 0;
++}
++
++
++static int mtx1sysbtn_release (struct inode *inode, struct file *file) {
++ if (MINOR(inode->i_rdev)==mtx1sysbtn_minor) {
++ is_inuse=0;
++ }
++ return 0;
++}
++
++
++static ssize_t mtx1sysbtn_read (struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++ if (count < 1)
++ return -EINVAL;
++ if (!state_changed)
++ interruptible_sleep_on (&mtx1btn_wait_queue);
++ state_changed = 0;
++ char c = last_value ? '1' : '0'; /* mtx1_getbtn(0) */
++ if(copy_to_user(buf, &c, 1))
++ return -EFAULT;
++ return 1;
++}
++
++
++static unsigned int mtx1sysbtn_poll (struct file *file, poll_table * wait)
++{
++ unsigned int mask = 0;
++
++ poll_wait (file, &mtx1btn_wait_queue, wait);
++
++ if (state_changed) // state changed since last time.
++ mask |= POLLIN | POLLRDNORM;
++
++ return mask;
++}
++
++
++static struct file_operations mtx1sysbtn_fops = {
++ .owner = THIS_MODULE,
++ .read = mtx1sysbtn_read,
++ .poll = mtx1sysbtn_poll,
++ .open = mtx1sysbtn_open,
++ .release = mtx1sysbtn_release
++};
++
++
++static struct miscdevice mtx1sysbtn_miscdev = {
++ MISC_DYNAMIC_MINOR /* SYSBTN_MINOR */ ,
++ "btn",
++ &mtx1sysbtn_fops
++};
++
++
++
++//---------[ Module Functions ]-----------------
++
++
++void __exit exit_mtx1_sysbtn (void)
++{
++ is_inuse = 1;
++ mtx1_btn_stopirq ();
++ misc_deregister(&mtx1sysbtn_miscdev);
++}
++
++
++static int __init init_mtx1_sysbtn (void)
++{
++ printk("MTX-1 System Button driver\n");
++ is_inuse = 1;
++ mtx1_initbuttons ();
++ if (misc_register (&mtx1sysbtn_miscdev) >= 0) {
++ mtx1sysbtn_minor = mtx1sysbtn_miscdev.minor;
++ if (mtx1_btn_startirq () == 0) {
++ is_inuse=0;
++ return 0;
++ }
++ misc_deregister(&mtx1sysbtn_miscdev);
++ }
++ return 1;
++}
++
++module_init(init_mtx1_sysbtn);
++module_exit(exit_mtx1_sysbtn);
++
++MODULE_AUTHOR("Michael Stickel");
++MODULE_DESCRIPTION("Driver for the MTX-1 system button");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/au1000-2.6/patches/007-mtx1_sio2.patch b/target/linux/au1000-2.6/patches/007-mtx1_sio2.patch
new file mode 100644
index 0000000..34d1005
--- /dev/null
+++ b/target/linux/au1000-2.6/patches/007-mtx1_sio2.patch
@@ -0,0 +1,13 @@
+--- linux-2.6.16.7/arch/mips/au1000/mtx-1/board_setup.c 2006-04-17 23:53:25.000000000 +0200
++++ linux-2.6.16.7.new/arch/mips/au1000/mtx-1/board_setup.c 2006-04-23 14:35:42.000000000 +0200
+@@ -71,9 +71,7 @@
+ #endif
+
+ // initialize sys_pinfunc:
+- // disable second ethernet port (SYS_PF_NI2)
+- // set U3/GPIO23 to GPIO23 (SYS_PF_U3)
+- au_writel( SYS_PF_NI2 | SYS_PF_U3, SYS_PINFUNC );
++ au_writel( SYS_PF_NI2, SYS_PINFUNC );
+
+ // initialize GPIO
+ au_writel( 0xFFFFFFFF, SYS_TRIOUTCLR );
diff --git a/target/linux/au1000-2.6/patches/008-isdel_cardbus.patch b/target/linux/au1000-2.6/patches/008-isdel_cardbus.patch
new file mode 100644
index 0000000..9e54ac1
--- /dev/null
+++ b/target/linux/au1000-2.6/patches/008-isdel_cardbus.patch
@@ -0,0 +1,63 @@
+diff -urN linux-2.6.16.7/arch/mips/au1000/mtx-1/board_setup.c linux-2.6.16.7.new/arch/mips/au1000/mtx-1/board_setup.c
+--- linux-2.6.16.7/arch/mips/au1000/mtx-1/board_setup.c 2006-04-23 14:39:21.000000000 +0200
++++ linux-2.6.16.7.new/arch/mips/au1000/mtx-1/board_setup.c 2006-04-23 14:39:03.000000000 +0200
+@@ -44,6 +44,9 @@
+ #include <asm/pgtable.h>
+ #include <asm/mach-au1x00/au1000.h>
+
++extern int (*board_pci_idsel)(unsigned int devsel, int assert);
++int mtx1_pci_idsel(unsigned int devsel, int assert);
++
+ void board_reset (void)
+ {
+ /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
+@@ -77,11 +80,37 @@
+ au_writel( 0xFFFFFFFF, SYS_TRIOUTCLR );
+ au_writel( 0x00000001, SYS_OUTPUTCLR ); // set M66EN (PCI 66MHz) to OFF
+ au_writel( 0x00000008, SYS_OUTPUTSET ); // set PCI CLKRUN# to OFF
++ au_writel( 0x00000002, SYS_OUTPUTSET ); // set EXT_IO3 ON
+ au_writel( 0x00000020, SYS_OUTPUTCLR ); // set eth PHY TX_ER to OFF
+
+ // enable LED and set it to green
+ au_writel( au_readl(GPIO2_DIR) | 0x1800, GPIO2_DIR );
+ au_writel( 0x18000800, GPIO2_OUTPUT );
+
++ board_pci_idsel = mtx1_pci_idsel;
++
+ printk("4G Systems MTX-1 Board\n");
+ }
++
++int
++mtx1_pci_idsel(unsigned int devsel, int assert)
++{
++#define MTX_IDSEL_ONLY_0_AND_3 0
++#if MTX_IDSEL_ONLY_0_AND_3
++ if (devsel != 0 && devsel != 3) {
++ printk("*** not 0 or 3\n");
++ return 0;
++ }
++#endif
++
++ if (assert && devsel != 0) {
++ // supress signal to cardbus
++ au_writel( 0x00000002, SYS_OUTPUTCLR ); // set EXT_IO3 OFF
++ }
++ else {
++ au_writel( 0x00000002, SYS_OUTPUTSET ); // set EXT_IO3 ON
++ }
++ au_sync_udelay(1);
++ return 1;
++}
++
+diff -urN linux-2.6.16.7/arch/mips/au1000/mtx-1/irqmap.c linux-2.6.16.7.new/arch/mips/au1000/mtx-1/irqmap.c
+--- linux-2.6.16.7/arch/mips/au1000/mtx-1/irqmap.c 2006-04-23 14:40:54.000000000 +0200
++++ linux-2.6.16.7.new/arch/mips/au1000/mtx-1/irqmap.c 2006-04-23 14:40:12.000000000 +0200
+@@ -48,7 +48,7 @@
+ #include <asm/mach-au1x00/au1000.h>
+
+ char irq_tab_alchemy[][5] __initdata = {
+- [0] = { -1, INTA, INTB, INTX, INTX}, /* IDSEL 00 - AdapterA-Slot0 (top) */
++ [0] = { -1, INTA, INTA, INTX, INTX}, /* IDSEL 00 - AdapterA-Slot0 (top) */
+ [1] = { -1, INTB, INTA, INTX, INTX}, /* IDSEL 01 - AdapterA-Slot1 (bottom) */
+ [2] = { -1, INTC, INTD, INTX, INTX}, /* IDSEL 02 - AdapterB-Slot0 (top) */
+ [3] = { -1, INTD, INTC, INTX, INTX}, /* IDSEL 03 - AdapterB-Slot1 (bottom) */
diff --git a/target/linux/brcm-2.4/Makefile b/target/linux/brcm-2.4/Makefile
new file mode 100644
index 0000000..33cb47c
--- /dev/null
+++ b/target/linux/brcm-2.4/Makefile
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+LINUX_VERSION:=2.4.32
+LINUX_RELEASE:=1
+LINUX_KERNEL_MD5SUM:=38f4d0830e95a20f4bfed17622d5557c
+
+include ./config
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/kernel-build.mk
+
+$(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked
+ [ -d ../generic-$(KERNEL)/patches ] && $(PATCH) $(LINUX_DIR) ../generic-$(KERNEL)/patches
+ [ -d ./patches ] && $(PATCH) $(LINUX_DIR) ./patches
+ @$(CP) config $(LINUX_DIR)/.config
+ touch $@
+
diff --git a/target/linux/brcm-2.4/config b/target/linux/brcm-2.4/config
new file mode 100644
index 0000000..7b00207
--- /dev/null
+++ b/target/linux/brcm-2.4/config
@@ -0,0 +1,1385 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_MIPS=y
+CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_FICMMP is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_HYDROGEN3 is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_COGENT_CSB250 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_CASIO_E55 is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_IBM_WORKPAD is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_PMC_BIG_SUR is not set
+# CONFIG_PMC_STRETCH is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+CONFIG_MIPS_BRCM=y
+CONFIG_BCM947XX=y
+CONFIG_BCM4710=y
+CONFIG_BCM4310=y
+CONFIG_BCM4704=y
+CONFIG_BCM5365=y
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TANBAC_TB0226 is not set
+# CONFIG_TANBAC_TB0229 is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_VICTOR_MPC30X is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=squashfs,jffs2 init=/etc/preinit noinitrd console=ttyS0,115200"
+CONFIG_PCI=y
+CONFIG_NONCOHERENT_IO=y
+CONFIG_NEW_TIME_C=y
+CONFIG_NEW_IRQ=y
+# CONFIG_MIPS_AU1000 is not set
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_VTAG_ICACHE is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+# CONFIG_CPU_HAS_LLDSCD is not set
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
+
+#
+# General setup
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_BUILD_ELF64 is not set
+CONFIG_NET=y
+CONFIG_PCI=y
+# CONFIG_PCI_NEW is not set
+CONFIG_PCI_AUTO=y
+# CONFIG_PCI_NAMES is not set
+# CONFIG_ISA is not set
+# CONFIG_TC is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+CONFIG_CARDBUS=y
+# CONFIG_TCIC is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+# CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE is not set
+# CONFIG_HOTPLUG_PCI_PCIE is not set
+# CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_ELF_AOUT is not set
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_MIPS32_O32 is not set
+# CONFIG_MIPS32_N32 is not set
+# CONFIG_BINFMT_ELF32 is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+# CONFIG_MTD_CFI_B4 is not set
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+# CONFIG_MTD_CFI_I2 is not set
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_SSTSTD=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_BCM947XX=y
+# CONFIG_MTD_PB1000 is not set
+# CONFIG_MTD_PB1500 is not set
+# CONFIG_MTD_PB1100 is not set
+# CONFIG_MTD_BOSPORUS is not set
+# CONFIG_MTD_XXS1500 is not set
+# CONFIG_MTD_MTX1 is not set
+# CONFIG_MTD_DB1X00 is not set
+# CONFIG_MTD_PB1550 is not set
+# CONFIG_MTD_HYDROGEN3 is not set
+# CONFIG_MTD_MIRAGE is not set
+# CONFIG_MTD_CSTM_MIPS_IXX is not set
+# CONFIG_MTD_OCELOT is not set
+# CONFIG_MTD_LASAT is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_SFLASH=y
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+# CONFIG_PARPORT_PC is not set
+CONFIG_PARPORT_SPLINK=m
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_IP22 is not set
+# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_1284 is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_CISS_MONITOR_THREAD is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK_DEV=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_NAT=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_TOS=y
+# CONFIG_IP_ROUTE_VERBOSE is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+CONFIG_IP_NF_FTP=y
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_IRC=y
+CONFIG_IP_NF_CT_ACCT=m
+CONFIG_IP_NF_MATCH_CONNBYTES=m
+CONFIG_IP_NF_CT_PROTO_GRE=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+CONFIG_IP_NF_MMS=m
+CONFIG_IP_NF_RTSP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_QUOTA=m
+CONFIG_IP_NF_SET=m
+CONFIG_IP_NF_SET_MAX=256
+CONFIG_IP_NF_SET_HASHSIZE=1024
+CONFIG_IP_NF_MATCH_SET=m
+CONFIG_IP_NF_TARGET_SET=m
+CONFIG_IP_NF_SET_IPMAP=m
+CONFIG_IP_NF_SET_PORTMAP=m
+CONFIG_IP_NF_SET_MACIPMAP=m
+CONFIG_IP_NF_SET_IPHASH=m
+CONFIG_IP_NF_SET_NETHASH=m
+CONFIG_IP_NF_SET_IPTREE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=y
+CONFIG_IP_NF_MATCH_MULTIPORT=y
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_TIME=m
+CONFIG_IP_NF_MATCH_CONDITION=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_IPP2P=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=y
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_CONNMARK=m
+CONFIG_IP_NF_MATCH_UNCLEAN=m
+CONFIG_IP_NF_MATCH_STRING=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_MATCH_LAYER7_MAXDATALEN=2048
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_MIRROR=m
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_PROTO_GRE=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_NAT_MMS=m
+CONFIG_IP_NF_NAT_RTSP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=y
+CONFIG_IP_NF_NAT_FTP=y
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=y
+CONFIG_IP_NF_TARGET_IMQ=m
+CONFIG_IP_NF_TARGET_CONNMARK=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+CONFIG_IP_VS=m
+# CONFIG_IP_VS_DEBUG is not set
+CONFIG_IP_VS_TAB_BITS=12
+CONFIG_IP_VS_RR=m
+CONFIG_IP_VS_WRR=m
+CONFIG_IP_VS_LC=m
+CONFIG_IP_VS_WLC=m
+CONFIG_IP_VS_LBLC=m
+CONFIG_IP_VS_LBLCR=m
+CONFIG_IP_VS_DH=m
+CONFIG_IP_VS_SH=m
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+CONFIG_IP_VS_FTP=m
+CONFIG_IPV6=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_CONDITION=m
+CONFIG_IP6_NF_MATCH_MAC=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_AHESP is not set
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+CONFIG_IP6_NF_TARGET_IMQ=m
+# CONFIG_KHTTPD is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+CONFIG_VLAN_8021Q=y
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+CONFIG_BRIDGE=y
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+CONFIG_WAN_ROUTER=m
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_CSZ=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_POLICE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_IPSEC_NAT_TRAVERSAL=y
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=m
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=m
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_IDEDISK_STROKE=y
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_DELKIN is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_BLK_DEV_OFFBOARD=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_ADMA100 is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_ATIIXP is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_PDC202XX_OLD=m
+CONFIG_PDC202XX_BURST=y
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_IDEDMA_AUTO=y
+CONFIG_IDEDMA_IVB=y
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_PDC202XX=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=m
+CONFIG_BLK_DEV_SD=m
+CONFIG_SD_EXTRA_DEVS=5
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=m
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_MEGARAID2 is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_SATA_AHCI is not set
+# CONFIG_SCSI_SATA_SVW is not set
+# CONFIG_SCSI_ATA_PIIX is not set
+# CONFIG_SCSI_SATA_NV is not set
+# CONFIG_SCSI_SATA_QSTOR is not set
+# CONFIG_SCSI_SATA_PROMISE is not set
+# CONFIG_SCSI_SATA_SX4 is not set
+# CONFIG_SCSI_SATA_SIL is not set
+# CONFIG_SCSI_SATA_SIS is not set
+# CONFIG_SCSI_SATA_ULI is not set
+# CONFIG_SCSI_SATA_VIA is not set
+# CONFIG_SCSI_SATA_VITESSE is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_SYM53C8XX is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_SCSI_PCMCIA is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_BOOT is not set
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_IMQ=m
+CONFIG_TUN=m
+CONFIG_NET_RANDOM=y
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+CONFIG_B44=y
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_LAN_SAA9730 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE_MPPC=m
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_AIRO is not set
+# CONFIG_HERMES is not set
+# CONFIG_PLX_HERMES is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_PCI_HERMES is not set
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_PCMCIA_ATMEL is not set
+# CONFIG_PRISM54 is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+CONFIG_SHAPER=m
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Amateur Radio support
+#
+CONFIG_HAMRADIO=y
+CONFIG_AX25=m
+# CONFIG_AX25_DAMA_SLAVE is not set
+# CONFIG_NETROM is not set
+# CONFIG_ROSE is not set
+
+#
+# AX.25 network device drivers
+#
+CONFIG_MKISS=m
+# CONFIG_6PACK is not set
+# CONFIG_BPQETHER is not set
+# CONFIG_SCC_DELAY is not set
+# CONFIG_SCC_TRXECHO is not set
+# CONFIG_BAYCOM_SER_FDX is not set
+# CONFIG_BAYCOM_SER_HDX is not set
+# CONFIG_BAYCOM_PAR is not set
+# CONFIG_BAYCOM_EPP is not set
+# CONFIG_SOUNDMODEM is not set
+# CONFIG_YAM is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=128
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+CONFIG_PPDEV=m
+# CONFIG_TIPAR is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SCx200_WDT is not set
+CONFIG_SOFT_WATCHDOG=m
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_SCx200 is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+
+#
+# Direct Rendering Manager (XFree86 DRI support)
+#
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+CONFIG_PCMCIA_SERIAL_CS=m
+# CONFIG_SYNCLINK_CS is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_QFMT_V2 is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=m
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_BBC_ARMLIB is not set
+# CONFIG_JFFS2_BBC_LZO is not set
+CONFIG_JFFS2_BBC_LZARI=y
+# CONFIG_JFFS2_BBC_LZHD is not set
+# CONFIG_JFFS2_BBC_LZSS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_MINIX_FS=m
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=m
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+CONFIG_CIFS_POSIX=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+# CONFIG_SOUND_AD1980 is not set
+# CONFIG_SOUND_WM97XX is not set
+
+#
+# USB support
+#
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_UHCI is not set
+CONFIG_USB_UHCI_ALT=m
+CONFIG_USB_OHCI=m
+CONFIG_USB_AUDIO=m
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_MIDI is not set
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+# CONFIG_USB_STORAGE_ISD200 is not set
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_HP8200e=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDINPUT is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+CONFIG_USB_PWC=m
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_W9968CF is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_DEBUG is not set
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_BELKIN=m
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+CONFIG_USB_SERIAL_MCT_U232=m
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+CONFIG_USB_SERIAL_PL2303=m
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+CONFIG_BLUEZ=m
+CONFIG_BLUEZ_L2CAP=m
+CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_RFCOMM=m
+CONFIG_BLUEZ_RFCOMM_TTY=y
+CONFIG_BLUEZ_BNEP=m
+CONFIG_BLUEZ_BNEP_MC_FILTER=y
+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BLUEZ_HCIUSB=m
+CONFIG_BLUEZ_HCIUSB_SCO=y
+CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIUART_H4=y
+CONFIG_BLUEZ_HCIUART_BCSP=y
+CONFIG_BLUEZ_HCIUART_BCSP_TXCRC=y
+# CONFIG_BLUEZ_HCIBFUSB is not set
+# CONFIG_BLUEZ_HCIDTL1 is not set
+# CONFIG_BLUEZ_HCIBT3C is not set
+# CONFIG_BLUEZ_HCIBLUECARD is not set
+# CONFIG_BLUEZ_HCIBTUART is not set
+# CONFIG_BLUEZ_HCIVHCI is not set
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_RUNTIME_DEBUG is not set
+# CONFIG_REMOTE_DEBUG is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_MIPS_UNCACHED is not set
+CONFIG_LOG_BUF_SHIFT=0
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+# CONFIG_FW_LOADER is not set
diff --git a/target/linux/brcm-2.4/patches/001-bcm47xx.patch b/target/linux/brcm-2.4/patches/001-bcm47xx.patch
new file mode 100644
index 0000000..726eba8
--- /dev/null
+++ b/target/linux/brcm-2.4/patches/001-bcm47xx.patch
@@ -0,0 +1,16794 @@
+diff -urN linux.old/arch/mips/bcm947xx/bcmsrom.c linux.dev/arch/mips/bcm947xx/bcmsrom.c
+--- linux.old/arch/mips/bcm947xx/bcmsrom.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/bcmsrom.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,1212 @@
++/*
++ * Misc useful routines to access NIC SROM/OTP .
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id: bcmsrom.c,v 1.1.1.14 2006/04/15 01:28:25 michael Exp $
++ */
++
++#include <typedefs.h>
++#include <bcmdefs.h>
++#include <osl.h>
++#include <bcmutils.h>
++#include <bcmsrom.h>
++#include <bcmdevs.h>
++#include <bcmendian.h>
++#include <sbpcmcia.h>
++#include <pcicfg.h>
++#include <sbutils.h>
++#include <bcmnvram.h>
++
++/* debug/trace */
++#if defined(WLTEST)
++#define BS_ERROR(args) printf args
++#else
++#define BS_ERROR(args)
++#endif /* BCMDBG_ERR || WLTEST */
++
++#define VARS_MAX 4096 /* should be reduced */
++
++#define WRITE_ENABLE_DELAY 500 /* 500 ms after write enable/disable toggle */
++#define WRITE_WORD_DELAY 20 /* 20 ms between each word write */
++
++static int initvars_srom_pci(void *sbh, void *curmap, char **vars, uint *count);
++static int initvars_cis_pcmcia(void *sbh, osl_t *osh, char **vars, uint *count);
++static int initvars_flash_sb(void *sbh, char **vars, uint *count);
++static int srom_parsecis(osl_t *osh, uint8 **pcis, uint ciscnt, char **vars, uint *count);
++static int sprom_cmd_pcmcia(osl_t *osh, uint8 cmd);
++static int sprom_read_pcmcia(osl_t *osh, uint16 addr, uint16 *data);
++static int sprom_write_pcmcia(osl_t *osh, uint16 addr, uint16 data);
++static int sprom_read_pci(osl_t *osh, uint16 *sprom, uint wordoff, uint16 *buf, uint nwords,
++ bool check_crc);
++
++static int initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count);
++static int initvars_flash(osl_t *osh, char **vp, uint len, char *devpath);
++
++/*
++ * Initialize local vars from the right source for this platform.
++ * Return 0 on success, nonzero on error.
++ */
++int
++srom_var_init(void *sbh, uint bustype, void *curmap, osl_t *osh, char **vars, uint *count)
++{
++ ASSERT(bustype == BUSTYPE(bustype));
++ if (vars == NULL || count == NULL)
++ return (0);
++
++ switch (BUSTYPE(bustype)) {
++ case SB_BUS:
++ case JTAG_BUS:
++ return initvars_flash_sb(sbh, vars, count);
++
++ case PCI_BUS:
++ ASSERT(curmap); /* can not be NULL */
++ return initvars_srom_pci(sbh, curmap, vars, count);
++
++ case PCMCIA_BUS:
++ return initvars_cis_pcmcia(sbh, osh, vars, count);
++
++
++ default:
++ ASSERT(0);
++ }
++ return (-1);
++}
++
++/* support only 16-bit word read from srom */
++int
++srom_read(uint bustype, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf)
++{
++ void *srom;
++ uint i, off, nw;
++
++ ASSERT(bustype == BUSTYPE(bustype));
++
++ /* check input - 16-bit access only */
++ if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
++ return 1;
++
++ off = byteoff / 2;
++ nw = nbytes / 2;
++
++ if (BUSTYPE(bustype) == PCI_BUS) {
++ if (!curmap)
++ return 1;
++ srom = (uchar*)curmap + PCI_BAR0_SPROM_OFFSET;
++ if (sprom_read_pci(osh, srom, off, buf, nw, FALSE))
++ return 1;
++ } else if (BUSTYPE(bustype) == PCMCIA_BUS) {
++ for (i = 0; i < nw; i++) {
++ if (sprom_read_pcmcia(osh, (uint16)(off + i), (uint16*)(buf + i)))
++ return 1;
++ }
++ } else {
++ return 1;
++ }
++
++ return 0;
++}
++
++/* support only 16-bit word write into srom */
++int
++srom_write(uint bustype, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf)
++{
++ uint16 *srom;
++ uint i, nw, crc_range;
++ uint16 image[SPROM_SIZE];
++ uint8 crc;
++ volatile uint32 val32;
++
++ ASSERT(bustype == BUSTYPE(bustype));
++
++ /* check input - 16-bit access only */
++ if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
++ return 1;
++
++ /* Are we writing the whole thing at once? */
++ if ((byteoff == 0) &&
++ ((nbytes == SPROM_SIZE) ||
++ (nbytes == (SPROM_CRC_RANGE * 2)) ||
++ (nbytes == (SROM4_WORDS * 2)))) {
++ crc_range = nbytes;
++ bcopy((void*)buf, (void*)image, nbytes);
++ nw = nbytes / 2;
++ } else {
++ if ((BUSTYPE(bustype) == PCMCIA_BUS) || (BUSTYPE(bustype) == SDIO_BUS))
++ crc_range = SPROM_SIZE;
++ else
++ crc_range = SPROM_CRC_RANGE * 2; /* Tentative */
++
++ nw = crc_range / 2;
++ /* read first 64 words from srom */
++ if (srom_read(bustype, curmap, osh, 0, nw * 2, image))
++ return 1;
++ if (image[SROM4_SIGN] == SROM4_SIGNATURE) {
++ crc_range = SROM4_WORDS;
++ nw = crc_range / 2;
++ if (srom_read(bustype, curmap, osh, 0, nw * 2, image))
++ return 1;
++ }
++ /* make changes */
++ bcopy((void*)buf, (void*)&image[byteoff / 2], nbytes);
++ }
++
++ /* calculate crc */
++ htol16_buf(image, crc_range);
++ crc = ~hndcrc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE);
++ ltoh16_buf(image, crc_range);
++ image[(crc_range / 2) - 1] = (crc << 8) | (image[(crc_range / 2) - 1] & 0xff);
++
++ if (BUSTYPE(bustype) == PCI_BUS) {
++ srom = (uint16*)((uchar*)curmap + PCI_BAR0_SPROM_OFFSET);
++ /* enable writes to the SPROM */
++ val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32));
++ val32 |= SPROM_WRITEEN;
++ OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32);
++ bcm_mdelay(WRITE_ENABLE_DELAY);
++ /* write srom */
++ for (i = 0; i < nw; i++) {
++ W_REG(osh, &srom[i], image[i]);
++ bcm_mdelay(WRITE_WORD_DELAY);
++ }
++ /* disable writes to the SPROM */
++ OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 &
++ ~SPROM_WRITEEN);
++ } else if (BUSTYPE(bustype) == PCMCIA_BUS) {
++ /* enable writes to the SPROM */
++ if (sprom_cmd_pcmcia(osh, SROM_WEN))
++ return 1;
++ bcm_mdelay(WRITE_ENABLE_DELAY);
++ /* write srom */
++ for (i = 0; i < nw; i++) {
++ sprom_write_pcmcia(osh, (uint16)(i), image[i]);
++ bcm_mdelay(WRITE_WORD_DELAY);
++ }
++ /* disable writes to the SPROM */
++ if (sprom_cmd_pcmcia(osh, SROM_WDS))
++ return 1;
++ } else {
++ return 1;
++ }
++
++ bcm_mdelay(WRITE_ENABLE_DELAY);
++ return 0;
++}
++
++
++static int
++srom_parsecis(osl_t *osh, uint8 **pcis, uint ciscnt, char **vars, uint *count)
++{
++ char eabuf[32];
++ char *vp, *base;
++ uint8 *cis, tup, tlen, sromrev = 1;
++ int i, j;
++ uint varsize;
++ bool ag_init = FALSE;
++ uint32 w32;
++
++ ASSERT(vars);
++ ASSERT(count);
++
++ base = vp = MALLOC(osh, VARS_MAX);
++ ASSERT(vp);
++ if (!vp)
++ return -2;
++
++ while (ciscnt--) {
++ cis = *pcis++;
++ i = 0;
++ do {
++ tup = cis[i++];
++ tlen = cis[i++];
++ if ((i + tlen) >= CIS_SIZE)
++ break;
++
++ switch (tup) {
++ case CISTPL_MANFID:
++ vp += sprintf(vp, "manfid=%d", (cis[i + 1] << 8) + cis[i]);
++ vp++;
++ vp += sprintf(vp, "prodid=%d", (cis[i + 3] << 8) + cis[i + 2]);
++ vp++;
++ break;
++
++ case CISTPL_FUNCE:
++ switch (cis[i]) {
++ case LAN_NID:
++ ASSERT(cis[i + 1] == 6);
++ bcm_ether_ntoa((struct ether_addr *)&cis[i + 2], eabuf);
++ vp += sprintf(vp, "il0macaddr=%s", eabuf);
++ vp++;
++ break;
++ case 1: /* SDIO Extended Data */
++ vp += sprintf(vp, "sdmaxblk=%d",
++ (cis[i + 13] << 8) | cis[i + 12]);
++ vp++;
++ break;
++ }
++ break;
++
++ case CISTPL_CFTABLE:
++ vp += sprintf(vp, "regwindowsz=%d", (cis[i + 7] << 8) | cis[i + 6]);
++ vp++;
++ break;
++
++ case CISTPL_BRCM_HNBU:
++ switch (cis[i]) {
++ case HNBU_SROMREV:
++ sromrev = cis[i + 1];
++ break;
++
++ case HNBU_CHIPID:
++ vp += sprintf(vp, "vendid=%d", (cis[i + 2] << 8) +
++ cis[i + 1]);
++ vp++;
++ vp += sprintf(vp, "devid=%d", (cis[i + 4] << 8) +
++ cis[i + 3]);
++ vp++;
++ if (tlen == 7) {
++ vp += sprintf(vp, "chiprev=%d",
++ (cis[i + 6] << 8) + cis[i + 5]);
++ vp++;
++ }
++ break;
++
++ case HNBU_BOARDREV:
++ vp += sprintf(vp, "boardrev=%d", cis[i + 1]);
++ vp++;
++ break;
++
++ case HNBU_AA:
++ vp += sprintf(vp, "aa2g=%d", cis[i + 1]);
++ vp++;
++ break;
++
++ case HNBU_AG:
++ vp += sprintf(vp, "ag0=%d", cis[i + 1]);
++ vp++;
++ ag_init = TRUE;
++ break;
++
++ case HNBU_CC:
++ ASSERT(sromrev == 1);
++ vp += sprintf(vp, "cc=%d", cis[i + 1]);
++ vp++;
++ break;
++
++ case HNBU_PAPARMS:
++ if (tlen == 2) {
++ ASSERT(sromrev == 1);
++ vp += sprintf(vp, "pa0maxpwr=%d", cis[i + 1]);
++ vp++;
++ } else if (tlen >= 9) {
++ if (tlen == 10) {
++ ASSERT(sromrev == 2);
++ vp += sprintf(vp, "opo=%d", cis[i + 9]);
++ vp++;
++ } else
++ ASSERT(tlen == 9);
++
++ for (j = 0; j < 3; j++) {
++ vp += sprintf(vp, "pa0b%d=%d", j,
++ (cis[i + (j * 2) + 2] << 8) +
++ cis[i + (j * 2) + 1]);
++ vp++;
++ }
++ vp += sprintf(vp, "pa0itssit=%d", cis[i + 7]);
++ vp++;
++ vp += sprintf(vp, "pa0maxpwr=%d", cis[i + 8]);
++ vp++;
++ } else
++ ASSERT(tlen >= 9);
++ break;
++
++ case HNBU_OEM:
++ ASSERT(sromrev == 1);
++ vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
++ cis[i + 1], cis[i + 2],
++ cis[i + 3], cis[i + 4],
++ cis[i + 5], cis[i + 6],
++ cis[i + 7], cis[i + 8]);
++ vp++;
++ break;
++
++ case HNBU_BOARDFLAGS:
++ w32 = (cis[i + 2] << 8) + cis[i + 1];
++ if (tlen == 5)
++ w32 |= (cis[i + 4] << 24) + (cis[i + 3] << 16);
++ vp += sprintf(vp, "boardflags=0x%x", w32);
++ vp++;
++ break;
++
++ case HNBU_LEDS:
++ if (cis[i + 1] != 0xff) {
++ vp += sprintf(vp, "ledbh0=%d", cis[i + 1]);
++ vp++;
++ }
++ if (cis[i + 2] != 0xff) {
++ vp += sprintf(vp, "ledbh1=%d", cis[i + 2]);
++ vp++;
++ }
++ if (cis[i + 3] != 0xff) {
++ vp += sprintf(vp, "ledbh2=%d", cis[i + 3]);
++ vp++;
++ }
++ if (cis[i + 4] != 0xff) {
++ vp += sprintf(vp, "ledbh3=%d", cis[i + 4]);
++ vp++;
++ }
++ break;
++
++ case HNBU_CCODE:
++ {
++ char str[3];
++ ASSERT(sromrev > 1);
++ str[0] = cis[i + 1];
++ str[1] = cis[i + 2];
++ str[2] = 0;
++ vp += sprintf(vp, "ccode=%s", str);
++ vp++;
++ vp += sprintf(vp, "cctl=0x%x", cis[i + 3]);
++ vp++;
++ break;
++ }
++
++ case HNBU_CCKPO:
++ ASSERT(sromrev > 2);
++ vp += sprintf(vp, "cckpo=0x%x",
++ (cis[i + 2] << 8) | cis[i + 1]);
++ vp++;
++ break;
++
++ case HNBU_OFDMPO:
++ ASSERT(sromrev > 2);
++ vp += sprintf(vp, "ofdmpo=0x%x",
++ (cis[i + 4] << 24) |
++ (cis[i + 3] << 16) |
++ (cis[i + 2] << 8) |
++ cis[i + 1]);
++ vp++;
++ break;
++ }
++ break;
++
++ }
++ i += tlen;
++ } while (tup != 0xff);
++ }
++
++ /* Set the srom version */
++ vp += sprintf(vp, "sromrev=%d", sromrev);
++ vp++;
++
++ /* if there is no antenna gain field, set default */
++ if (ag_init == FALSE) {
++ ASSERT(sromrev == 1);
++ vp += sprintf(vp, "ag0=%d", 0xff);
++ vp++;
++ }
++
++ /* final nullbyte terminator */
++ *vp++ = '\0';
++ varsize = (uint)(vp - base);
++
++ ASSERT((vp - base) < VARS_MAX);
++
++ if (varsize == VARS_MAX) {
++ *vars = base;
++ } else {
++ vp = MALLOC(osh, varsize);
++ ASSERT(vp);
++ if (vp)
++ bcopy(base, vp, varsize);
++ MFREE(osh, base, VARS_MAX);
++ *vars = vp;
++ if (!vp) {
++ *count = 0;
++ return -2;
++ }
++ }
++ *count = varsize;
++
++ return (0);
++}
++
++
++/* set PCMCIA sprom command register */
++static int
++sprom_cmd_pcmcia(osl_t *osh, uint8 cmd)
++{
++ uint8 status = 0;
++ uint wait_cnt = 1000;
++
++ /* write sprom command register */
++ OSL_PCMCIA_WRITE_ATTR(osh, SROM_CS, &cmd, 1);
++
++ /* wait status */
++ while (wait_cnt--) {
++ OSL_PCMCIA_READ_ATTR(osh, SROM_CS, &status, 1);
++ if (status & SROM_DONE)
++ return 0;
++ }
++
++ return 1;
++}
++
++/* read a word from the PCMCIA srom */
++static int
++sprom_read_pcmcia(osl_t *osh, uint16 addr, uint16 *data)
++{
++ uint8 addr_l, addr_h, data_l, data_h;
++
++ addr_l = (uint8)((addr * 2) & 0xff);
++ addr_h = (uint8)(((addr * 2) >> 8) & 0xff);
++
++ /* set address */
++ OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1);
++ OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1);
++
++ /* do read */
++ if (sprom_cmd_pcmcia(osh, SROM_READ))
++ return 1;
++
++ /* read data */
++ data_h = data_l = 0;
++ OSL_PCMCIA_READ_ATTR(osh, SROM_DATAH, &data_h, 1);
++ OSL_PCMCIA_READ_ATTR(osh, SROM_DATAL, &data_l, 1);
++
++ *data = (data_h << 8) | data_l;
++ return 0;
++}
++
++/* write a word to the PCMCIA srom */
++static int
++sprom_write_pcmcia(osl_t *osh, uint16 addr, uint16 data)
++{
++ uint8 addr_l, addr_h, data_l, data_h;
++
++ addr_l = (uint8)((addr * 2) & 0xff);
++ addr_h = (uint8)(((addr * 2) >> 8) & 0xff);
++ data_l = (uint8)(data & 0xff);
++ data_h = (uint8)((data >> 8) & 0xff);
++
++ /* set address */
++ OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRH, &addr_h, 1);
++ OSL_PCMCIA_WRITE_ATTR(osh, SROM_ADDRL, &addr_l, 1);
++
++ /* write data */
++ OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAH, &data_h, 1);
++ OSL_PCMCIA_WRITE_ATTR(osh, SROM_DATAL, &data_l, 1);
++
++ /* do write */
++ return sprom_cmd_pcmcia(osh, SROM_WRITE);
++}
++
++/*
++ * Read in and validate sprom.
++ * Return 0 on success, nonzero on error.
++ */
++static int
++sprom_read_pci(osl_t *osh, uint16 *sprom, uint wordoff, uint16 *buf, uint nwords, bool check_crc)
++{
++ int err = 0;
++ uint i;
++
++ /* read the sprom */
++ for (i = 0; i < nwords; i++)
++ buf[i] = R_REG(osh, &sprom[wordoff + i]);
++
++ if (check_crc) {
++ /* fixup the endianness so crc8 will pass */
++ htol16_buf(buf, nwords * 2);
++ if (hndcrc8((uint8*)buf, nwords * 2, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE)
++ err = 1;
++ /* now correct the endianness of the byte array */
++ ltoh16_buf(buf, nwords * 2);
++ }
++
++ return err;
++}
++
++/*
++* Create variable table from memory.
++* Return 0 on success, nonzero on error.
++*/
++static int
++initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count)
++{
++ int c = (int)(end - start);
++
++ /* do it only when there is more than just the null string */
++ if (c > 1) {
++ char *vp = MALLOC(osh, c);
++ ASSERT(vp);
++ if (!vp)
++ return BCME_NOMEM;
++ bcopy(start, vp, c);
++ *vars = vp;
++ *count = c;
++ }
++ else {
++ *vars = NULL;
++ *count = 0;
++ }
++
++ return 0;
++}
++
++/*
++ * Find variables with <devpath> from flash. 'base' points to the beginning
++ * of the table upon enter and to the end of the table upon exit when success.
++ * Return 0 on success, nonzero on error.
++ */
++static int
++initvars_flash(osl_t *osh, char **base, uint len, char *devpath)
++{
++ char *vp = *base;
++ char *flash;
++ int err;
++ char *s;
++ uint l, dl, copy_len;
++
++ /* allocate memory and read in flash */
++ if (!(flash = MALLOC(osh, NVRAM_SPACE)))
++ return BCME_NOMEM;
++ if ((err = nvram_getall(flash, NVRAM_SPACE)))
++ goto exit;
++
++ /* grab vars with the <devpath> prefix in name */
++ dl = strlen(devpath);
++ for (s = flash; s && *s; s += l + 1) {
++ l = strlen(s);
++
++ /* skip non-matching variable */
++ if (strncmp(s, devpath, dl))
++ continue;
++
++ /* is there enough room to copy? */
++ copy_len = l - dl + 1;
++ if (len < copy_len) {
++ err = BCME_BUFTOOSHORT;
++ goto exit;
++ }
++
++ /* no prefix, just the name=value */
++ strcpy(vp, &s[dl]);
++ vp += copy_len;
++ len -= copy_len;
++ }
++
++ /* add null string as terminator */
++ if (len < 1) {
++ err = BCME_BUFTOOSHORT;
++ goto exit;
++ }
++ *vp++ = '\0';
++
++ *base = vp;
++
++exit: MFREE(osh, flash, NVRAM_SPACE);
++ return err;
++}
++
++/*
++ * Initialize nonvolatile variable table from flash.
++ * Return 0 on success, nonzero on error.
++ */
++static int
++initvars_flash_sb(void *sbh, char **vars, uint *count)
++{
++ osl_t *osh = sb_osh(sbh);
++ char devpath[SB_DEVPATH_BUFSZ];
++ char *vp, *base;
++ int err;
++
++ ASSERT(vars);
++ ASSERT(count);
++
++ if ((err = sb_devpath(sbh, devpath, sizeof(devpath))))
++ return err;
++
++ base = vp = MALLOC(osh, VARS_MAX);
++ ASSERT(vp);
++ if (!vp)
++ return BCME_NOMEM;
++
++ if ((err = initvars_flash(osh, &vp, VARS_MAX, devpath)))
++ goto err;
++
++ err = initvars_table(osh, base, vp, vars, count);
++
++err: MFREE(osh, base, VARS_MAX);
++ return err;
++}
++
++#ifdef WLTEST
++char mfgsromvars[256];
++char *defaultsromvars = "il0macaddr=00:11:22:33:44:51\0"
++ "et0macaddr=00:11:22:33:44:52\0"
++ "et1macaddr=00:11:22:33:44:53\0"
++ "boardtype=0xffff\0"
++ "boardrev=0x10\0"
++ "boardflags=8\0"
++ "sromrev=2\0"
++ "aa2g=3";
++#define MFGSROM_DEFVARSLEN 147 /* default srom len */
++#endif /* WL_TEST */
++
++/*
++ * Initialize nonvolatile variable table from sprom.
++ * Return 0 on success, nonzero on error.
++ */
++static int
++initvars_srom_pci(void *sbh, void *curmap, char **vars, uint *count)
++{
++ uint16 w, *b;
++ uint8 sromrev = 0;
++ struct ether_addr ea;
++ char eabuf[32];
++ uint32 w32;
++ int woff, i;
++ char *vp, *base;
++ osl_t *osh = sb_osh(sbh);
++ bool flash = FALSE;
++ char name[SB_DEVPATH_BUFSZ+16], *value;
++ char devpath[SB_DEVPATH_BUFSZ];
++ int err;
++
++ /*
++ * Apply CRC over SROM content regardless SROM is present or not,
++ * and use variable <devpath>sromrev's existance in flash to decide
++ * if we should return an error when CRC fails or read SROM variables
++ * from flash.
++ */
++ b = MALLOC(osh, SROM_MAX);
++ ASSERT(b);
++ if (!b)
++ return -2;
++
++ err = sprom_read_pci(osh, (void*)((int8*)curmap + PCI_BAR0_SPROM_OFFSET), 0, b,
++ 64, TRUE);
++ if (err == 0) {
++ /* srom is good and is rev < 4 */
++ /* top word of sprom contains version and crc8 */
++ sromrev = b[63] & 0xff;
++ /* bcm4401 sroms misprogrammed */
++ if (sromrev == 0x10)
++ sromrev = 1;
++ } else if (b[SROM4_SIGN] == SROM4_SIGNATURE) {
++ /* If sromrev >= 4, read more */
++ err = sprom_read_pci(osh, (void*)((int8*)curmap + PCI_BAR0_SPROM_OFFSET), 0, b,
++ SROM4_WORDS, TRUE);
++ sromrev = b[SROM4_WORDS - 1] & 0xff;
++ }
++
++ if (err) {
++#ifdef WLTEST
++ BS_ERROR(("SROM Crc Error, so see if we could use a default\n"));
++ w32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32));
++ if (w32 & SPROM_OTPIN_USE) {
++ BS_ERROR(("srom crc failed with OTP, use default vars....\n"));
++ vp = base = mfgsromvars;
++ if (sb_chip(sbh) == BCM4311_CHIP_ID) {
++ BS_ERROR(("setting the devid to be 4311\n"));
++ vp += sprintf(vp, "devid=0x4311");
++ vp++;
++ }
++ bcopy(defaultsromvars, vp, MFGSROM_DEFVARSLEN);
++ vp += MFGSROM_DEFVARSLEN;
++ goto varsdone;
++ } else {
++ BS_ERROR(("srom crc failed with SPROM....\n"));
++#endif /* WLTEST */
++ if ((err = sb_devpath(sbh, devpath, sizeof(devpath))))
++ return err;
++ sprintf(name, "%ssromrev", devpath);
++ if (!(value = getvar(NULL, name)))
++ return (-1);
++ sromrev = (uint8)bcm_strtoul(value, NULL, 0);
++ flash = TRUE;
++#ifdef WLTEST
++ }
++#endif /* WLTEST */
++ }
++
++ /* srom version check */
++ if (sromrev > 4)
++ return (-2);
++
++ ASSERT(vars);
++ ASSERT(count);
++
++ base = vp = MALLOC(osh, VARS_MAX);
++ ASSERT(vp);
++ if (!vp)
++ return -2;
++
++ /* read variables from flash */
++ if (flash) {
++ if ((err = initvars_flash(osh, &vp, VARS_MAX, devpath)))
++ goto err;
++ goto varsdone;
++ }
++
++ vp += sprintf(vp, "sromrev=%d", sromrev);
++ vp++;
++
++ if (sromrev >= 4) {
++ uint path, pathbase;
++ const uint pathbases[MAX_PATH] = {SROM4_PATH0, SROM4_PATH1,
++ SROM4_PATH2, SROM4_PATH3};
++
++ vp += sprintf(vp, "boardrev=%d", b[SROM4_BREV]);
++ vp++;
++
++ vp += sprintf(vp, "boardflags=%d", (b[SROM4_BFL1] << 16) | b[SROM4_BFL0]);
++ vp++;
++
++ vp += sprintf(vp, "boardflags2=%d", (b[SROM4_BFL3] << 16) | b[SROM4_BFL2]);
++ vp++;
++
++ /* The macaddr */
++ ea.octet[0] = (b[SROM4_MACHI] >> 8) & 0xff;
++ ea.octet[1] = b[SROM4_MACHI] & 0xff;
++ ea.octet[2] = (b[SROM4_MACMID] >> 8) & 0xff;
++ ea.octet[3] = b[SROM4_MACMID] & 0xff;
++ ea.octet[4] = (b[SROM4_MACLO] >> 8) & 0xff;
++ ea.octet[5] = b[SROM4_MACLO] & 0xff;
++ bcm_ether_ntoa(&ea, eabuf);
++ vp += sprintf(vp, "macaddr=%s", eabuf);
++ vp++;
++
++ w = b[SROM4_CCODE];
++ if (w == 0)
++ vp += sprintf(vp, "ccode=");
++ else
++ vp += sprintf(vp, "ccode=%c%c", (w >> 8), (w & 0xff));
++ vp++;
++ vp += sprintf(vp, "regrev=%d", b[SROM4_REGREV]);
++ vp++;
++
++ w = b[SROM4_LEDBH10];
++ if ((w != 0) && (w != 0xffff)) {
++ /* ledbh0 */
++ vp += sprintf(vp, "ledbh0=%d", (w & 0xff));
++ vp++;
++
++ /* ledbh1 */
++ vp += sprintf(vp, "ledbh1=%d", (w >> 8) & 0xff);
++ vp++;
++ }
++ w = b[SROM4_LEDBH32];
++ if ((w != 0) && (w != 0xffff)) {
++ /* ledbh2 */
++ vp += sprintf(vp, "ledbh2=%d", w & 0xff);
++ vp++;
++
++ /* ledbh3 */
++ vp += sprintf(vp, "ledbh3=%d", (w >> 8) & 0xff);
++ vp++;
++ }
++ /* LED Powersave duty cycle (oncount >> 24) (offcount >> 8) */
++ w = b[SROM4_LEDDC];
++ w32 = ((uint32)((unsigned char)(w >> 8) & 0xff) << 24) | /* oncount */
++ ((uint32)((unsigned char)(w & 0xff)) << 8); /* offcount */
++ vp += sprintf(vp, "leddc=%d", w32);
++ vp++;
++
++ w = b[SROM4_AA];
++ vp += sprintf(vp, "aa2g=%d", w & SROM4_AA2G_MASK);
++ vp++;
++ vp += sprintf(vp, "aa5g=%d", w >> SROM4_AA5G_SHIFT);
++ vp++;
++
++ w = b[SROM4_AG10];
++ vp += sprintf(vp, "ag0=%d", w & 0xff);
++ vp++;
++ vp += sprintf(vp, "ag1=%d", (w >> 8) & 0xff);
++ vp++;
++ w = b[SROM4_AG32];
++ vp += sprintf(vp, "ag2=%d", w & 0xff);
++ vp++;
++ vp += sprintf(vp, "ag3=%d", (w >> 8) & 0xff);
++ vp++;
++
++ /* Fixed power indices when power control is disabled */
++ for (i = 0; i < 2; i++) {
++ w = b[SROM4_TXPID2G + i];
++ vp += sprintf(vp, "txpid2ga%d=%d", 2 * i, w & 0xff);
++ vp++;
++ vp += sprintf(vp, "txpid2ga%d=%d", (2 * i) + 1, (w >> 8) & 0xff);
++ vp++;
++ w = b[SROM4_TXPID5G + i];
++ vp += sprintf(vp, "txpid5ga%d=%d", 2 * i, w & 0xff);
++ vp++;
++ vp += sprintf(vp, "txpid5ga%d=%d", (2 * i) + 1, (w >> 8) & 0xff);
++ vp++;
++ w = b[SROM4_TXPID5GL + i];
++ vp += sprintf(vp, "txpid5gla%d=%d", 2 * i, w & 0xff);
++ vp++;
++ vp += sprintf(vp, "txpid5gla%d=%d", (2 * i) + 1, (w >> 8) & 0xff);
++ vp++;
++ w = b[SROM4_TXPID5GH + i];
++ vp += sprintf(vp, "txpid5gha%d=%d", 2 * i, w & 0xff);
++ vp++;
++ vp += sprintf(vp, "txpid5gha%d=%d", (2 * i) + 1, (w >> 8) & 0xff);
++ vp++;
++ }
++
++ /* Per path variables */
++ for (path = 0; path < MAX_PATH; path++) {
++ pathbase = pathbases[path];
++ w = b[pathbase + SROM4_2G_ITT_MAXP];
++ vp += sprintf(vp, "itt2ga%d=%d", path, w >> B2G_ITT_SHIFT);
++ vp++;
++ vp += sprintf(vp, "maxp2ga%d=%d", path, w & B2G_MAXP_MASK);
++ vp++;
++
++ for (i = 0; i < 4; i++) {
++ vp += sprintf(vp, "pa2gw%da%d=%d", i, path,
++ b[pathbase + SROM4_2G_PA + i]);
++ vp++;
++ }
++
++ w = b[pathbase + SROM4_5G_ITT_MAXP];
++ vp += sprintf(vp, "itt5ga%d=%d", path, w >> B5G_ITT_SHIFT);
++ vp++;
++ vp += sprintf(vp, "maxp5ga%d=%d", path, w & B5G_MAXP_MASK);
++ vp++;
++
++ w = b[pathbase + SROM4_5GLH_MAXP];
++ vp += sprintf(vp, "maxp5lga%d=%d", path, w >> B5GL_MAXP_SHIFT);
++ vp++;
++ vp += sprintf(vp, "maxp5gha%d=%d", path, w & B5GH_MAXP_MASK);
++ vp++;
++
++ for (i = 0; i < 4; i++) {
++ vp += sprintf(vp, "pa5gw%da%d=%d", i, path,
++ b[pathbase + SROM4_5G_PA + i]);
++ vp++;
++ vp += sprintf(vp, "pa5glw%da%d=%d", i, path,
++ b[pathbase + SROM4_5GL_PA + i]);
++ vp++;
++ vp += sprintf(vp, "pa5hgw%da%d=%d", i, path,
++ b[pathbase + SROM4_5GH_PA + i]);
++ vp++;
++ }
++ }
++
++ vp += sprintf(vp, "cck2gpo=%d", b[SROM4_2G_CCKPO]);
++ vp++;
++
++ w32 = ((uint32)b[SROM4_2G_OFDMPO + 1] << 16) | b[SROM4_2G_OFDMPO];
++ vp += sprintf(vp, "ofdm2gpo=%d", w32);
++ vp++;
++
++ w32 = ((uint32)b[SROM4_5G_OFDMPO + 1] << 16) | b[SROM4_5G_OFDMPO];
++ vp += sprintf(vp, "ofdm5gpo=%d", w32);
++ vp++;
++
++ w32 = ((uint32)b[SROM4_5GL_OFDMPO + 1] << 16) | b[SROM4_5GL_OFDMPO];
++ vp += sprintf(vp, "ofdm5glpo=%d", w32);
++ vp++;
++
++ w32 = ((uint32)b[SROM4_5GH_OFDMPO + 1] << 16) | b[SROM4_5GH_OFDMPO];
++ vp += sprintf(vp, "ofdm5ghpo=%d", w32);
++ vp++;
++
++ for (i = 0; i < 8; i++) {
++ vp += sprintf(vp, "mcs2gpo%d=%d", i, b[SROM4_2G_MCSPO]);
++ vp++;
++ vp += sprintf(vp, "mcs5gpo%d=%d", i, b[SROM4_5G_MCSPO]);
++ vp++;
++ vp += sprintf(vp, "mcs5glpo%d=%d", i, b[SROM4_5GL_MCSPO]);
++ vp++;
++ vp += sprintf(vp, "mcs5ghpo%d=%d", i, b[SROM4_5GH_MCSPO]);
++ vp++;
++ }
++
++ vp += sprintf(vp, "ccdpo%d=%d", i, b[SROM4_CCDPO]);
++ vp++;
++ vp += sprintf(vp, "stbcpo%d=%d", i, b[SROM4_STBCPO]);
++ vp++;
++ vp += sprintf(vp, "bw40po%d=%d", i, b[SROM4_BW40PO]);
++ vp++;
++ vp += sprintf(vp, "bwduppo%d=%d", i, b[SROM4_BWDUPPO]);
++ vp++;
++
++ goto done;
++ }
++ if (sromrev >= 3) {
++ /* New section takes over the 3th hardware function space */
++
++ /* Words 22+23 are 11a (mid) ofdm power offsets */
++ w32 = ((uint32)b[23] << 16) | b[22];
++ vp += sprintf(vp, "ofdmapo=%d", w32);
++ vp++;
++
++ /* Words 24+25 are 11a (low) ofdm power offsets */
++ w32 = ((uint32)b[25] << 16) | b[24];
++ vp += sprintf(vp, "ofdmalpo=%d", w32);
++ vp++;
++
++ /* Words 26+27 are 11a (high) ofdm power offsets */
++ w32 = ((uint32)b[27] << 16) | b[26];
++ vp += sprintf(vp, "ofdmahpo=%d", w32);
++ vp++;
++
++ /* LED Powersave duty cycle (oncount >> 24) (offcount >> 8) */
++ w32 = ((uint32)((unsigned char)(b[21] >> 8) & 0xff) << 24) | /* oncount */
++ ((uint32)((unsigned char)(b[21] & 0xff)) << 8); /* offcount */
++ vp += sprintf(vp, "leddc=%d", w32);
++
++ vp++;
++ }
++
++ if (sromrev >= 2) {
++ /* New section takes over the 4th hardware function space */
++
++ /* Word 29 is max power 11a high/low */
++ w = b[29];
++ vp += sprintf(vp, "pa1himaxpwr=%d", w & 0xff);
++ vp++;
++ vp += sprintf(vp, "pa1lomaxpwr=%d", (w >> 8) & 0xff);
++ vp++;
++
++ /* Words 30-32 set the 11alow pa settings,
++ * 33-35 are the 11ahigh ones.
++ */
++ for (i = 0; i < 3; i++) {
++ vp += sprintf(vp, "pa1lob%d=%d", i, b[30 + i]);
++ vp++;
++ vp += sprintf(vp, "pa1hib%d=%d", i, b[33 + i]);
++ vp++;
++ }
++ w = b[59];
++ if (w == 0)
++ vp += sprintf(vp, "ccode=");
++ else
++ vp += sprintf(vp, "ccode=%c%c", (w >> 8), (w & 0xff));
++ vp++;
++
++ }
++
++ /* parameter section of sprom starts at byte offset 72 */
++ woff = 72/2;
++
++ /* first 6 bytes are il0macaddr */
++ ea.octet[0] = (b[woff] >> 8) & 0xff;
++ ea.octet[1] = b[woff] & 0xff;
++ ea.octet[2] = (b[woff+1] >> 8) & 0xff;
++ ea.octet[3] = b[woff+1] & 0xff;
++ ea.octet[4] = (b[woff+2] >> 8) & 0xff;
++ ea.octet[5] = b[woff+2] & 0xff;
++ woff += 3;
++ bcm_ether_ntoa(&ea, eabuf);
++ vp += sprintf(vp, "il0macaddr=%s", eabuf);
++ vp++;
++
++ /* next 6 bytes are et0macaddr */
++ ea.octet[0] = (b[woff] >> 8) & 0xff;
++ ea.octet[1] = b[woff] & 0xff;
++ ea.octet[2] = (b[woff+1] >> 8) & 0xff;
++ ea.octet[3] = b[woff+1] & 0xff;
++ ea.octet[4] = (b[woff+2] >> 8) & 0xff;
++ ea.octet[5] = b[woff+2] & 0xff;
++ woff += 3;
++ bcm_ether_ntoa(&ea, eabuf);
++ vp += sprintf(vp, "et0macaddr=%s", eabuf);
++ vp++;
++
++ /* next 6 bytes are et1macaddr */
++ ea.octet[0] = (b[woff] >> 8) & 0xff;
++ ea.octet[1] = b[woff] & 0xff;
++ ea.octet[2] = (b[woff+1] >> 8) & 0xff;
++ ea.octet[3] = b[woff+1] & 0xff;
++ ea.octet[4] = (b[woff+2] >> 8) & 0xff;
++ ea.octet[5] = b[woff+2] & 0xff;
++ woff += 3;
++ bcm_ether_ntoa(&ea, eabuf);
++ vp += sprintf(vp, "et1macaddr=%s", eabuf);
++ vp++;
++
++ /*
++ * Enet phy settings one or two singles or a dual
++ * Bits 4-0 : MII address for enet0 (0x1f for not there)
++ * Bits 9-5 : MII address for enet1 (0x1f for not there)
++ * Bit 14 : Mdio for enet0
++ * Bit 15 : Mdio for enet1
++ */
++ w = b[woff];
++ vp += sprintf(vp, "et0phyaddr=%d", (w & 0x1f));
++ vp++;
++ vp += sprintf(vp, "et1phyaddr=%d", ((w >> 5) & 0x1f));
++ vp++;
++ vp += sprintf(vp, "et0mdcport=%d", ((w >> 14) & 0x1));
++ vp++;
++ vp += sprintf(vp, "et1mdcport=%d", ((w >> 15) & 0x1));
++ vp++;
++
++ /* Word 46 has board rev, antennas 0/1 & Country code/control */
++ w = b[46];
++ vp += sprintf(vp, "boardrev=%d", w & 0xff);
++ vp++;
++
++ if (sromrev > 1)
++ vp += sprintf(vp, "cctl=%d", (w >> 8) & 0xf);
++ else
++ vp += sprintf(vp, "cc=%d", (w >> 8) & 0xf);
++ vp++;
++
++ vp += sprintf(vp, "aa2g=%d", (w >> 12) & 0x3);
++ vp++;
++
++ vp += sprintf(vp, "aa5g=%d", (w >> 14) & 0x3);
++ vp++;
++
++ /* Words 47-49 set the (wl) pa settings */
++ woff = 47;
++
++ for (i = 0; i < 3; i++) {
++ vp += sprintf(vp, "pa0b%d=%d", i, b[woff+i]);
++ vp++;
++ vp += sprintf(vp, "pa1b%d=%d", i, b[woff+i+6]);
++ vp++;
++ }
++
++ /*
++ * Words 50-51 set the customer-configured wl led behavior.
++ * 8 bits/gpio pin. High bit: activehi=0, activelo=1;
++ * LED behavior values defined in wlioctl.h .
++ */
++ w = b[50];
++ if ((w != 0) && (w != 0xffff)) {
++ /* ledbh0 */
++ vp += sprintf(vp, "ledbh0=%d", (w & 0xff));
++ vp++;
++
++ /* ledbh1 */
++ vp += sprintf(vp, "ledbh1=%d", (w >> 8) & 0xff);
++ vp++;
++ }
++ w = b[51];
++ if ((w != 0) && (w != 0xffff)) {
++ /* ledbh2 */
++ vp += sprintf(vp, "ledbh2=%d", w & 0xff);
++ vp++;
++
++ /* ledbh */
++ vp += sprintf(vp, "ledbh3=%d", (w >> 8) & 0xff);
++ vp++;
++ }
++
++ /* Word 52 is max power 0/1 */
++ w = b[52];
++ vp += sprintf(vp, "pa0maxpwr=%d", w & 0xff);
++ vp++;
++ vp += sprintf(vp, "pa1maxpwr=%d", (w >> 8) & 0xff);
++ vp++;
++
++ /* Word 56 is idle tssi target 0/1 */
++ w = b[56];
++ vp += sprintf(vp, "pa0itssit=%d", w & 0xff);
++ vp++;
++ vp += sprintf(vp, "pa1itssit=%d", (w >> 8) & 0xff);
++ vp++;
++
++ /* Word 57 is boardflags, if not programmed make it zero */
++ w32 = (uint32)b[57];
++ if (w32 == 0xffff) w32 = 0;
++ if (sromrev > 1) {
++ /* Word 28 is the high bits of boardflags */
++ w32 |= (uint32)b[28] << 16;
++ }
++ vp += sprintf(vp, "boardflags=%d", w32);
++ vp++;
++
++ /* Word 58 is antenna gain 0/1 */
++ w = b[58];
++ vp += sprintf(vp, "ag0=%d", w & 0xff);
++ vp++;
++
++ vp += sprintf(vp, "ag1=%d", (w >> 8) & 0xff);
++ vp++;
++
++ if (sromrev == 1) {
++ /* set the oem string */
++ vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
++ ((b[59] >> 8) & 0xff), (b[59] & 0xff),
++ ((b[60] >> 8) & 0xff), (b[60] & 0xff),
++ ((b[61] >> 8) & 0xff), (b[61] & 0xff),
++ ((b[62] >> 8) & 0xff), (b[62] & 0xff));
++ vp++;
++ } else if (sromrev == 2) {
++ /* Word 60 OFDM tx power offset from CCK level */
++ /* OFDM Power Offset - opo */
++ vp += sprintf(vp, "opo=%d", b[60] & 0xff);
++ vp++;
++ } else {
++ /* Word 60: cck power offsets */
++ vp += sprintf(vp, "cckpo=%d", b[60]);
++ vp++;
++
++ /* Words 61+62: 11g ofdm power offsets */
++ w32 = ((uint32)b[62] << 16) | b[61];
++ vp += sprintf(vp, "ofdmgpo=%d", w32);
++ vp++;
++ }
++
++ /* final nullbyte terminator */
++done: *vp++ = '\0';
++
++ ASSERT((vp - base) <= VARS_MAX);
++
++varsdone:
++ err = initvars_table(osh, base, vp, vars, count);
++
++err:
++#ifdef WLTEST
++ if (base != mfgsromvars)
++#endif
++ MFREE(osh, base, VARS_MAX);
++ MFREE(osh, b, SROM_MAX);
++ return err;
++}
++
++/*
++ * Read the cis and call parsecis to initialize the vars.
++ * Return 0 on success, nonzero on error.
++ */
++static int
++initvars_cis_pcmcia(void *sbh, osl_t *osh, char **vars, uint *count)
++{
++ uint8 *cis = NULL;
++ int rc;
++ uint data_sz;
++
++ data_sz = (sb_pcmciarev(sbh) == 1) ? (SPROM_SIZE * 2) : CIS_SIZE;
++
++ if ((cis = MALLOC(osh, data_sz)) == NULL)
++ return (-2);
++
++ if (sb_pcmciarev(sbh) == 1) {
++ if (srom_read(PCMCIA_BUS, (void *)NULL, osh, 0, data_sz, (uint16 *)cis)) {
++ MFREE(osh, cis, data_sz);
++ return (-1);
++ }
++ /* fix up endianess for 16-bit data vs 8-bit parsing */
++ ltoh16_buf((uint16 *)cis, data_sz);
++ } else
++ OSL_PCMCIA_READ_ATTR(osh, 0, cis, data_sz);
++
++ rc = srom_parsecis(osh, &cis, 1, vars, count);
++
++ MFREE(osh, cis, data_sz);
++
++ return (rc);
++}
++
+diff -urN linux.old/arch/mips/bcm947xx/bcmutils.c linux.dev/arch/mips/bcm947xx/bcmutils.c
+--- linux.old/arch/mips/bcm947xx/bcmutils.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/bcmutils.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,247 @@
++/*
++ * Misc useful OS-independent routines.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id: bcmutils.c,v 1.1.1.12 2006/02/27 03:43:16 honor Exp $
++ */
++
++#include <typedefs.h>
++#include <bcmdefs.h>
++#include <stdarg.h>
++#include <bcmutils.h>
++#include <osl.h>
++#include <sbutils.h>
++#include <bcmnvram.h>
++#include <bcmendian.h>
++#include <bcmdevs.h>
++
++unsigned char bcm_ctype[] = {
++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
++ _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
++ _BCM_C, /* 8-15 */
++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
++ _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
++ _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
++ _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
++ _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
++ _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
++ _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
++ _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
++ _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
++ _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
++ _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
++ _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
++ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
++ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
++ _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
++ _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
++ _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
++};
++
++
++ulong
++bcm_strtoul(char *cp, char **endp, uint base)
++{
++ ulong result, value;
++ bool minus;
++
++ minus = FALSE;
++
++ while (bcm_isspace(*cp))
++ cp++;
++
++ if (cp[0] == '+')
++ cp++;
++ else if (cp[0] == '-') {
++ minus = TRUE;
++ cp++;
++ }
++
++ if (base == 0) {
++ if (cp[0] == '0') {
++ if ((cp[1] == 'x') || (cp[1] == 'X')) {
++ base = 16;
++ cp = &cp[2];
++ } else {
++ base = 8;
++ cp = &cp[1];
++ }
++ } else
++ base = 10;
++ } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
++ cp = &cp[2];
++ }
++
++ result = 0;
++
++ while (bcm_isxdigit(*cp) &&
++ (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
++ result = result*base + value;
++ cp++;
++ }
++
++ if (minus)
++ result = (ulong)(result * -1);
++
++ if (endp)
++ *endp = (char *)cp;
++
++ return (result);
++}
++
++uchar
++bcm_toupper(uchar c)
++{
++ if (bcm_islower(c))
++ c -= 'a'-'A';
++ return (c);
++}
++
++char*
++bcm_ether_ntoa(struct ether_addr *ea, char *buf)
++{
++ sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
++ ea->octet[0]&0xff, ea->octet[1]&0xff, ea->octet[2]&0xff,
++ ea->octet[3]&0xff, ea->octet[4]&0xff, ea->octet[5]&0xff);
++ return (buf);
++}
++
++
++/*
++ * Search the name=value vars for a specific one and return its value.
++ * Returns NULL if not found.
++ */
++char*
++getvar(char *vars, char *name)
++{
++ char *s;
++ int len;
++
++ len = strlen(name);
++
++ /* first look in vars[] */
++ for (s = vars; s && *s;) {
++ /* CSTYLED */
++ if ((memcmp(s, name, len) == 0) && (s[len] == '='))
++ return (&s[len+1]);
++
++ while (*s++)
++ ;
++ }
++
++ /* then query nvram */
++ return (nvram_get(name));
++}
++
++/*
++ * Search the vars for a specific one and return its value as
++ * an integer. Returns 0 if not found.
++ */
++int
++getintvar(char *vars, char *name)
++{
++ char *val;
++
++ if ((val = getvar(vars, name)) == NULL)
++ return (0);
++
++ return (bcm_strtoul(val, NULL, 0));
++}
++
++
++/*******************************************************************************
++ * crc8
++ *
++ * Computes a crc8 over the input data using the polynomial:
++ *
++ * x^8 + x^7 +x^6 + x^4 + x^2 + 1
++ *
++ * The caller provides the initial value (either CRC8_INIT_VALUE
++ * or the previous returned value) to allow for processing of
++ * discontiguous blocks of data. When generating the CRC the
++ * caller is responsible for complementing the final return value
++ * and inserting it into the byte stream. When checking, a final
++ * return value of CRC8_GOOD_VALUE indicates a valid CRC.
++ *
++ * Reference: Dallas Semiconductor Application Note 27
++ * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
++ * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
++ * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
++ *
++ * ****************************************************************************
++ */
++
++static uint8 crc8_table[256] = {
++ 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
++ 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
++ 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
++ 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
++ 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
++ 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
++ 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
++ 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
++ 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
++ 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
++ 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
++ 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
++ 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
++ 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
++ 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
++ 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
++ 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
++ 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
++ 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
++ 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
++ 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
++ 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
++ 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
++ 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
++ 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
++ 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
++ 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
++ 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
++ 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
++ 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
++ 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
++ 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
++};
++
++#define CRC_INNER_LOOP(n, c, x) \
++ (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
++
++uint8
++hndcrc8(
++ uint8 *pdata, /* pointer to array of data to process */
++ uint nbytes, /* number of input data bytes to process */
++ uint8 crc /* either CRC8_INIT_VALUE or previous return value */
++)
++{
++ /* hard code the crc loop instead of using CRC_INNER_LOOP macro
++ * to avoid the undefined and unnecessary (uint8 >> 8) operation.
++ */
++ while (nbytes-- > 0)
++ crc = crc8_table[(crc ^ *pdata++) & 0xff];
++
++ return crc;
++}
++
++
+diff -urN linux.old/arch/mips/bcm947xx/cfe_env.c linux.dev/arch/mips/bcm947xx/cfe_env.c
+--- linux.old/arch/mips/bcm947xx/cfe_env.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/cfe_env.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,234 @@
++/*
++ * NVRAM variable manipulation (Linux kernel half)
++ *
++ * Copyright 2001-2003, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++
++#include <typedefs.h>
++#include <osl.h>
++#include <bcmendian.h>
++#include <bcmutils.h>
++
++#define NVRAM_SIZE (0x1ff0)
++static char _nvdata[NVRAM_SIZE] __initdata;
++static char _valuestr[256] __initdata;
++
++/*
++ * TLV types. These codes are used in the "type-length-value"
++ * encoding of the items stored in the NVRAM device (flash or EEPROM)
++ *
++ * The layout of the flash/nvram is as follows:
++ *
++ * <type> <length> <data ...> <type> <length> <data ...> <type_end>
++ *
++ * The type code of "ENV_TLV_TYPE_END" marks the end of the list.
++ * The "length" field marks the length of the data section, not
++ * including the type and length fields.
++ *
++ * Environment variables are stored as follows:
++ *
++ * <type_env> <length> <flags> <name> = <value>
++ *
++ * If bit 0 (low bit) is set, the length is an 8-bit value.
++ * If bit 0 (low bit) is clear, the length is a 16-bit value
++ *
++ * Bit 7 set indicates "user" TLVs. In this case, bit 0 still
++ * indicates the size of the length field.
++ *
++ * Flags are from the constants below:
++ *
++ */
++#define ENV_LENGTH_16BITS 0x00 /* for low bit */
++#define ENV_LENGTH_8BITS 0x01
++
++#define ENV_TYPE_USER 0x80
++
++#define ENV_CODE_SYS(n,l) (((n)<<1)|(l))
++#define ENV_CODE_USER(n,l) ((((n)<<1)|(l)) | ENV_TYPE_USER)
++
++/*
++ * The actual TLV types we support
++ */
++
++#define ENV_TLV_TYPE_END 0x00
++#define ENV_TLV_TYPE_ENV ENV_CODE_SYS(0,ENV_LENGTH_8BITS)
++
++/*
++ * Environment variable flags
++ */
++
++#define ENV_FLG_NORMAL 0x00 /* normal read/write */
++#define ENV_FLG_BUILTIN 0x01 /* builtin - not stored in flash */
++#define ENV_FLG_READONLY 0x02 /* read-only - cannot be changed */
++
++#define ENV_FLG_MASK 0xFF /* mask of attributes we keep */
++#define ENV_FLG_ADMIN 0x100 /* lets us internally override permissions */
++
++
++/* *********************************************************************
++ * _nvram_read(buffer,offset,length)
++ *
++ * Read data from the NVRAM device
++ *
++ * Input parameters:
++ * buffer - destination buffer
++ * offset - offset of data to read
++ * length - number of bytes to read
++ *
++ * Return value:
++ * number of bytes read, or <0 if error occured
++ ********************************************************************* */
++static int
++_nvram_read(unsigned char *nv_buf, unsigned char *buffer, int offset, int length)
++{
++ int i;
++ if (offset > NVRAM_SIZE)
++ return -1;
++
++ for ( i = 0; i < length; i++) {
++ buffer[i] = ((volatile unsigned char*)nv_buf)[offset + i];
++ }
++ return length;
++}
++
++
++static char*
++_strnchr(const char *dest,int c,size_t cnt)
++{
++ while (*dest && (cnt > 0)) {
++ if (*dest == c) return (char *) dest;
++ dest++;
++ cnt--;
++ }
++ return NULL;
++}
++
++
++
++/*
++ * Core support API: Externally visible.
++ */
++
++/*
++ * Get the value of an NVRAM variable
++ * @param name name of variable to get
++ * @return value of variable or NULL if undefined
++ */
++
++char*
++cfe_env_get(unsigned char *nv_buf, char* name)
++{
++ int size;
++ unsigned char *buffer;
++ unsigned char *ptr;
++ unsigned char *envval;
++ unsigned int reclen;
++ unsigned int rectype;
++ int offset;
++ int flg;
++
++ size = NVRAM_SIZE;
++ buffer = &_nvdata[0];
++
++ ptr = buffer;
++ offset = 0;
++
++ /* Read the record type and length */
++ if (_nvram_read(nv_buf, ptr,offset,1) != 1) {
++ goto error;
++ }
++
++ while ((*ptr != ENV_TLV_TYPE_END) && (size > 1)) {
++
++ /* Adjust pointer for TLV type */
++ rectype = *(ptr);
++ offset++;
++ size--;
++
++ /*
++ * Read the length. It can be either 1 or 2 bytes
++ * depending on the code
++ */
++ if (rectype & ENV_LENGTH_8BITS) {
++ /* Read the record type and length - 8 bits */
++ if (_nvram_read(nv_buf, ptr,offset,1) != 1) {
++ goto error;
++ }
++ reclen = *(ptr);
++ size--;
++ offset++;
++ }
++ else {
++ /* Read the record type and length - 16 bits, MSB first */
++ if (_nvram_read(nv_buf, ptr,offset,2) != 2) {
++ goto error;
++ }
++ reclen = (((unsigned int) *(ptr)) << 8) + (unsigned int) *(ptr+1);
++ size -= 2;
++ offset += 2;
++ }
++
++ if (reclen > size)
++ break; /* should not happen, bad NVRAM */
++
++ switch (rectype) {
++ case ENV_TLV_TYPE_ENV:
++ /* Read the TLV data */
++ if (_nvram_read(nv_buf, ptr,offset,reclen) != reclen)
++ goto error;
++ flg = *ptr++;
++ envval = (unsigned char *) _strnchr(ptr,'=',(reclen-1));
++ if (envval) {
++ *envval++ = '\0';
++ memcpy(_valuestr,envval,(reclen-1)-(envval-ptr));
++ _valuestr[(reclen-1)-(envval-ptr)] = '\0';
++#if 0
++ printk(KERN_INFO "NVRAM:%s=%s\n", ptr, _valuestr);
++#endif
++ if(!strcmp(ptr, name)){
++ return _valuestr;
++ }
++ if((strlen(ptr) > 1) && !strcmp(&ptr[1], name))
++ return _valuestr;
++ }
++ break;
++
++ default:
++ /* Unknown TLV type, skip it. */
++ break;
++ }
++
++ /*
++ * Advance to next TLV
++ */
++
++ size -= (int)reclen;
++ offset += reclen;
++
++ /* Read the next record type */
++ ptr = buffer;
++ if (_nvram_read(nv_buf, ptr,offset,1) != 1)
++ goto error;
++ }
++
++error:
++ return NULL;
++
++}
++
+diff -urN linux.old/arch/mips/bcm947xx/compressed/Makefile linux.dev/arch/mips/bcm947xx/compressed/Makefile
+--- linux.old/arch/mips/bcm947xx/compressed/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/compressed/Makefile 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,33 @@
++#
++# Makefile for Broadcom BCM947XX boards
++#
++# Copyright 2001-2003, Broadcom Corporation
++# All Rights Reserved.
++#
++# THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++# KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++# SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++# FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++#
++# $Id: Makefile,v 1.2 2005/04/02 12:12:57 wbx Exp $
++#
++
++OBJCOPY_ARGS = -O binary -R .reginfo -R .note -R .comment -R .mdebug -S
++SYSTEM ?= $(TOPDIR)/vmlinux
++
++all: vmlinuz
++
++# Don't build dependencies, this may die if $(CC) isn't gcc
++dep:
++
++# Create a gzipped version named vmlinuz for compatibility
++vmlinuz: piggy
++ gzip -c9 $< > $@
++
++piggy: $(SYSTEM)
++ $(OBJCOPY) $(OBJCOPY_ARGS) $< $@
++
++mrproper: clean
++
++clean:
++ rm -f vmlinuz piggy
+diff -urN linux.old/arch/mips/bcm947xx/export.c linux.dev/arch/mips/bcm947xx/export.c
+--- linux.old/arch/mips/bcm947xx/export.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/export.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,65 @@
++#include <linux/module.h>
++
++#define _export(n) \
++ void n(void); \
++ EXPORT_SYMBOL(n);
++
++_export(bcm947xx_sbh)
++
++_export(sb_attach)
++_export(sb_kattach)
++_export(sb_boardtype)
++_export(sb_boardvendor)
++_export(sb_btcgpiowar)
++_export(sb_bus)
++_export(sb_chip)
++_export(sb_chiprev)
++_export(sb_chipcrev)
++_export(sb_chippkg)
++_export(sb_clkctl_clk)
++_export(sb_clkctl_fast_pwrup_delay)
++_export(sb_clkctl_init)
++_export(sb_clkctl_xtal)
++_export(sb_core_disable)
++_export(sb_core_reset)
++_export(sb_core_tofixup)
++_export(sb_coreflags)
++_export(sb_coreflagshi)
++_export(sb_coreidx)
++_export(sb_corerev)
++_export(sb_coreunit)
++_export(sb_detach)
++_export(sb_deviceremoved)
++_export(sb_gpiosetcore)
++_export(sb_gpiocontrol)
++_export(sb_gpioled)
++_export(sb_gpioin)
++_export(sb_gpioout)
++_export(sb_gpioouten)
++_export(sb_gpiotimerval)
++_export(sb_iscoreup)
++_export(sb_pci_setup)
++_export(sb_pcirev)
++_export(sb_pcmcia_init)
++_export(sb_pcmciarev)
++_export(sb_register_intr_callback)
++_export(sb_setcore)
++_export(sb_war16165)
++_export(sb_osh)
++
++_export(getvar)
++_export(getintvar)
++_export(bcm_strtoul)
++_export(bcm_ctype)
++_export(bcm_toupper)
++_export(bcm_ether_ntoa)
++
++_export(nvram_get)
++_export(nvram_getall)
++_export(nvram_set)
++_export(nvram_unset)
++_export(nvram_commit)
++
++_export(srom_read)
++_export(srom_write)
++
+diff -urN linux.old/arch/mips/bcm947xx/generic/int-handler.S linux.dev/arch/mips/bcm947xx/generic/int-handler.S
+--- linux.old/arch/mips/bcm947xx/generic/int-handler.S 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/generic/int-handler.S 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,51 @@
++/*
++ * Generic interrupt handler for Broadcom MIPS boards
++ *
++ * Copyright 2004, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: int-handler.S,v 1.1 2005/03/16 13:50:00 wbx Exp $
++ */
++
++#include <linux/config.h>
++
++#include <asm/asm.h>
++#include <asm/mipsregs.h>
++#include <asm/regdef.h>
++#include <asm/stackframe.h>
++
++/*
++ * MIPS IRQ Source
++ * -------- ------
++ * 0 Software (ignored)
++ * 1 Software (ignored)
++ * 2 Combined hardware interrupt (hw0)
++ * 3 Hardware
++ * 4 Hardware
++ * 5 Hardware
++ * 6 Hardware
++ * 7 R4k timer
++ */
++
++ .text
++ .set noreorder
++ .set noat
++ .align 5
++ NESTED(brcmIRQ, PT_SIZE, sp)
++ SAVE_ALL
++ CLI
++ .set at
++ .set noreorder
++
++ jal brcm_irq_dispatch
++ move a0, sp
++
++ j ret_from_irq
++ nop
++
++ END(brcmIRQ)
+diff -urN linux.old/arch/mips/bcm947xx/generic/irq.c linux.dev/arch/mips/bcm947xx/generic/irq.c
+--- linux.old/arch/mips/bcm947xx/generic/irq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/generic/irq.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,130 @@
++/*
++ * Generic interrupt control functions for Broadcom MIPS boards
++ *
++ * Copyright 2004, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: irq.c,v 1.1 2005/03/16 13:50:00 wbx Exp $
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++
++#include <asm/irq.h>
++#include <asm/mipsregs.h>
++#include <asm/gdb-stub.h>
++
++#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
++
++extern asmlinkage void brcmIRQ(void);
++extern asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs);
++
++void
++brcm_irq_dispatch(struct pt_regs *regs)
++{
++ u32 cause;
++
++ cause = read_c0_cause() &
++ read_c0_status() &
++ CAUSEF_IP;
++
++#ifdef CONFIG_KERNPROF
++ change_c0_status(cause | 1, 1);
++#else
++ clear_c0_status(cause);
++#endif
++
++ if (cause & CAUSEF_IP7)
++ do_IRQ(7, regs);
++ if (cause & CAUSEF_IP2)
++ do_IRQ(2, regs);
++ if (cause & CAUSEF_IP3)
++ do_IRQ(3, regs);
++ if (cause & CAUSEF_IP4)
++ do_IRQ(4, regs);
++ if (cause & CAUSEF_IP5)
++ do_IRQ(5, regs);
++ if (cause & CAUSEF_IP6)
++ do_IRQ(6, regs);
++}
++
++static void
++enable_brcm_irq(unsigned int irq)
++{
++ if (irq < 8)
++ set_c0_status(1 << (irq + 8));
++ else
++ set_c0_status(IE_IRQ0);
++}
++
++static void
++disable_brcm_irq(unsigned int irq)
++{
++ if (irq < 8)
++ clear_c0_status(1 << (irq + 8));
++ else
++ clear_c0_status(IE_IRQ0);
++}
++
++static void
++ack_brcm_irq(unsigned int irq)
++{
++ /* Already done in brcm_irq_dispatch */
++}
++
++static unsigned int
++startup_brcm_irq(unsigned int irq)
++{
++ enable_brcm_irq(irq);
++
++ return 0; /* never anything pending */
++}
++
++static void
++end_brcm_irq(unsigned int irq)
++{
++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
++ enable_brcm_irq(irq);
++}
++
++static struct hw_interrupt_type brcm_irq_type = {
++ typename: "MIPS",
++ startup: startup_brcm_irq,
++ shutdown: disable_brcm_irq,
++ enable: enable_brcm_irq,
++ disable: disable_brcm_irq,
++ ack: ack_brcm_irq,
++ end: end_brcm_irq,
++ NULL
++};
++
++void __init
++init_IRQ(void)
++{
++ int i;
++
++ for (i = 0; i < NR_IRQS; i++) {
++ irq_desc[i].status = IRQ_DISABLED;
++ irq_desc[i].action = 0;
++ irq_desc[i].depth = 1;
++ irq_desc[i].handler = &brcm_irq_type;
++ }
++
++ set_except_vector(0, brcmIRQ);
++ change_c0_status(ST0_IM, ALLINTS);
++
++#ifdef CONFIG_REMOTE_DEBUG
++ printk("Breaking into debugger...\n");
++ set_debug_traps();
++ breakpoint();
++#endif
++}
+diff -urN linux.old/arch/mips/bcm947xx/generic/Makefile linux.dev/arch/mips/bcm947xx/generic/Makefile
+--- linux.old/arch/mips/bcm947xx/generic/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/generic/Makefile 2006-10-02 21:26:29.000000000 +0200
+@@ -0,0 +1,16 @@
++#
++# Makefile for the BCM947xx specific kernel interface routines
++# under Linux.
++#
++EXTRA_CFLAGS += -fno-delayed-branch
++
++.S.s:
++ $(CPP) $(AFLAGS) $< -o $*.s
++.S.o:
++ $(CC) $(AFLAGS) -c $< -o $*.o
++
++O_TARGET := brcm.o
++
++obj-y := int-handler.o irq.o
++
++include $(TOPDIR)/Rules.make
+diff -urN linux.old/arch/mips/bcm947xx/gpio.c linux.dev/arch/mips/bcm947xx/gpio.c
+--- linux.old/arch/mips/bcm947xx/gpio.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/gpio.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,159 @@
++/*
++ * GPIO char driver
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <asm/uaccess.h>
++
++#include <typedefs.h>
++#include <osl.h>
++#include <bcmutils.h>
++#include <sbutils.h>
++#include <bcmdevs.h>
++
++static sb_t *gpio_sbh;
++static int gpio_major;
++static devfs_handle_t gpio_dir;
++static struct {
++ char *name;
++ devfs_handle_t handle;
++} gpio_file[] = {
++ { "in", NULL },
++ { "out", NULL },
++ { "outen", NULL },
++ { "control", NULL }
++};
++
++static int
++gpio_open(struct inode *inode, struct file * file)
++{
++ if (MINOR(inode->i_rdev) > ARRAYSIZE(gpio_file))
++ return -ENODEV;
++
++ MOD_INC_USE_COUNT;
++ return 0;
++}
++
++static int
++gpio_release(struct inode *inode, struct file * file)
++{
++ MOD_DEC_USE_COUNT;
++ return 0;
++}
++
++static ssize_t
++gpio_read(struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++ u32 val;
++
++ switch (MINOR(file->f_dentry->d_inode->i_rdev)) {
++ case 0:
++ val = sb_gpioin(gpio_sbh);
++ break;
++ case 1:
++ val = sb_gpioout(gpio_sbh, 0, 0, GPIO_DRV_PRIORITY);
++ break;
++ case 2:
++ val = sb_gpioouten(gpio_sbh, 0, 0, GPIO_DRV_PRIORITY);
++ break;
++ case 3:
++ val = sb_gpiocontrol(gpio_sbh, 0, 0, GPIO_DRV_PRIORITY);
++ break;
++ default:
++ return -ENODEV;
++ }
++
++ if (put_user(val, (u32 *) buf))
++ return -EFAULT;
++
++ return sizeof(val);
++}
++
++static ssize_t
++gpio_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
++{
++ u32 val;
++
++ if (get_user(val, (u32 *) buf))
++ return -EFAULT;
++
++ switch (MINOR(file->f_dentry->d_inode->i_rdev)) {
++ case 0:
++ return -EACCES;
++ case 1:
++ sb_gpioout(gpio_sbh, ~0, val, GPIO_DRV_PRIORITY);
++ break;
++ case 2:
++ sb_gpioouten(gpio_sbh, ~0, val, GPIO_DRV_PRIORITY);
++ break;
++ case 3:
++ sb_gpiocontrol(gpio_sbh, ~0, val, GPIO_DRV_PRIORITY);
++ break;
++ default:
++ return -ENODEV;
++ }
++
++ return sizeof(val);
++}
++
++static struct file_operations gpio_fops = {
++ owner: THIS_MODULE,
++ open: gpio_open,
++ release: gpio_release,
++ read: gpio_read,
++ write: gpio_write,
++};
++
++static int __init
++gpio_init(void)
++{
++ int i;
++
++ if (!(gpio_sbh = sb_kattach()))
++ return -ENODEV;
++
++ sb_gpiosetcore(gpio_sbh);
++
++ if ((gpio_major = devfs_register_chrdev(0, "gpio", &gpio_fops)) < 0)
++ return gpio_major;
++
++ gpio_dir = devfs_mk_dir(NULL, "gpio", NULL);
++
++ for (i = 0; i < ARRAYSIZE(gpio_file); i++) {
++ gpio_file[i].handle = devfs_register(gpio_dir,
++ gpio_file[i].name,
++ DEVFS_FL_DEFAULT, gpio_major, i,
++ S_IFCHR | S_IRUGO | S_IWUGO,
++ &gpio_fops, NULL);
++ }
++
++ return 0;
++}
++
++static void __exit
++gpio_exit(void)
++{
++ int i;
++
++ for (i = 0; i < ARRAYSIZE(gpio_file); i++)
++ devfs_unregister(gpio_file[i].handle);
++ devfs_unregister(gpio_dir);
++ devfs_unregister_chrdev(gpio_major, "gpio");
++ sb_detach(gpio_sbh);
++}
++
++module_init(gpio_init);
++module_exit(gpio_exit);
+diff -urN linux.old/arch/mips/bcm947xx/hndchipc.c linux.dev/arch/mips/bcm947xx/hndchipc.c
+--- linux.old/arch/mips/bcm947xx/hndchipc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/hndchipc.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,158 @@
++/*
++ * BCM47XX support code for some chipcommon (old extif) facilities (uart)
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: hndchipc.c,v 1.1.1.1 2006/02/27 03:43:16 honor Exp $
++ */
++
++#include <typedefs.h>
++#include <bcmdefs.h>
++#include <osl.h>
++#include <bcmutils.h>
++#include <sbutils.h>
++#include <bcmdevs.h>
++#include <bcmnvram.h>
++#include <sbconfig.h>
++#include <sbextif.h>
++#include <sbchipc.h>
++#include <hndcpu.h>
++
++/*
++ * Returns TRUE if an external UART exists at the given base
++ * register.
++ */
++static bool
++BCMINITFN(serial_exists)(osl_t *osh, uint8 *regs)
++{
++ uint8 save_mcr, status1;
++
++ save_mcr = R_REG(osh, &regs[UART_MCR]);
++ W_REG(osh, &regs[UART_MCR], UART_MCR_LOOP | 0x0a);
++ status1 = R_REG(osh, &regs[UART_MSR]) & 0xf0;
++ W_REG(osh, &regs[UART_MCR], save_mcr);
++
++ return (status1 == 0x90);
++}
++
++/*
++ * Initializes UART access. The callback function will be called once
++ * per found UART.
++ */
++void
++BCMINITFN(sb_serial_init)(sb_t *sbh, void (*add)(void *regs, uint irq, uint baud_base,
++ uint reg_shift))
++{
++ osl_t *osh;
++ void *regs;
++ ulong base;
++ uint irq;
++ int i, n;
++
++ osh = sb_osh(sbh);
++
++ if ((regs = sb_setcore(sbh, SB_EXTIF, 0))) {
++ extifregs_t *eir = (extifregs_t *) regs;
++ sbconfig_t *sb;
++
++ /* Determine external UART register base */
++ sb = (sbconfig_t *)((ulong) eir + SBCONFIGOFF);
++ base = EXTIF_CFGIF_BASE(sb_base(R_REG(osh, &sb->sbadmatch1)));
++
++ /* Determine IRQ */
++ irq = sb_irq(sbh);
++
++ /* Disable GPIO interrupt initially */
++ W_REG(osh, &eir->gpiointpolarity, 0);
++ W_REG(osh, &eir->gpiointmask, 0);
++
++ /* Search for external UARTs */
++ n = 2;
++ for (i = 0; i < 2; i++) {
++ regs = (void *) REG_MAP(base + (i * 8), 8);
++ if (serial_exists(osh, regs)) {
++ /* Set GPIO 1 to be the external UART IRQ */
++ W_REG(osh, &eir->gpiointmask, 2);
++ /* XXXDetermine external UART clock */
++ if (add)
++ add(regs, irq, 13500000, 0);
++ }
++ }
++
++ /* Add internal UART if enabled */
++ if (R_REG(osh, &eir->corecontrol) & CC_UE)
++ if (add)
++ add((void *) &eir->uartdata, irq, sb_clock(sbh), 2);
++ } else if ((regs = sb_setcore(sbh, SB_CC, 0))) {
++ chipcregs_t *cc = (chipcregs_t *) regs;
++ uint32 rev, cap, pll, baud_base, div;
++
++ /* Determine core revision and capabilities */
++ rev = sb_corerev(sbh);
++ cap = R_REG(osh, &cc->capabilities);
++ pll = cap & CAP_PLL_MASK;
++
++ /* Determine IRQ */
++ irq = sb_irq(sbh);
++
++ if (pll == PLL_TYPE1) {
++ /* PLL clock */
++ baud_base = sb_clock_rate(pll,
++ R_REG(osh, &cc->clockcontrol_n),
++ R_REG(osh, &cc->clockcontrol_m2));
++ div = 1;
++ } else {
++ /* Fixed ALP clock */
++ if (rev >= 11 && rev != 15) {
++ baud_base = 20000000;
++ div = 1;
++ /* Set the override bit so we don't divide it */
++ W_REG(osh, &cc->corecontrol, CC_UARTCLKO);
++ }
++ /* Internal backplane clock */
++ else if (rev >= 3) {
++ baud_base = sb_clock(sbh);
++ div = 2; /* Minimum divisor */
++ W_REG(osh, &cc->clkdiv,
++ ((R_REG(osh, &cc->clkdiv) & ~CLKD_UART) | div));
++ }
++ /* Fixed internal backplane clock */
++ else {
++ baud_base = 88000000;
++ div = 48;
++ }
++
++ /* Clock source depends on strapping if UartClkOverride is unset */
++ if ((rev > 0) &&
++ ((R_REG(osh, &cc->corecontrol) & CC_UARTCLKO) == 0)) {
++ if ((cap & CAP_UCLKSEL) == CAP_UINTCLK) {
++ /* Internal divided backplane clock */
++ baud_base /= div;
++ } else {
++ /* Assume external clock of 1.8432 MHz */
++ baud_base = 1843200;
++ }
++ }
++ }
++
++ /* Add internal UARTs */
++ n = cap & CAP_UARTS_MASK;
++ for (i = 0; i < n; i++) {
++ /* Register offset changed after revision 0 */
++ if (rev)
++ regs = (void *)((ulong) &cc->uart0data + (i * 256));
++ else
++ regs = (void *)((ulong) &cc->uart0data + (i * 8));
++
++ if (add)
++ add(regs, irq, baud_base, 0);
++ }
++ }
++}
++
+diff -urN linux.old/arch/mips/bcm947xx/include/bcm4710.h linux.dev/arch/mips/bcm947xx/include/bcm4710.h
+--- linux.old/arch/mips/bcm947xx/include/bcm4710.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/bcm4710.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,91 @@
++/*
++ * BCM4710 address space map and definitions
++ * Think twice before adding to this file, this is not the kitchen sink
++ * These definitions are not guaranteed for all 47xx chips, only the 4710
++ *
++ * Copyright 2004, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: bcm4710.h,v 1.3 2004/09/27 07:23:30 tallest Exp $
++ */
++
++#ifndef _bcm4710_h_
++#define _bcm4710_h_
++
++/* Address map */
++#define BCM4710_SDRAM 0x00000000 /* Physical SDRAM */
++#define BCM4710_PCI_MEM 0x08000000 /* Host Mode PCI memory access space (64 MB) */
++#define BCM4710_PCI_CFG 0x0c000000 /* Host Mode PCI configuration space (64 MB) */
++#define BCM4710_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */
++#define BCM4710_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */
++#define BCM4710_ENUM 0x18000000 /* Beginning of core enumeration space */
++
++/* Core register space */
++#define BCM4710_REG_SDRAM 0x18000000 /* SDRAM core registers */
++#define BCM4710_REG_ILINE20 0x18001000 /* InsideLine20 core registers */
++#define BCM4710_REG_EMAC0 0x18002000 /* Ethernet MAC 0 core registers */
++#define BCM4710_REG_CODEC 0x18003000 /* Codec core registers */
++#define BCM4710_REG_USB 0x18004000 /* USB core registers */
++#define BCM4710_REG_PCI 0x18005000 /* PCI core registers */
++#define BCM4710_REG_MIPS 0x18006000 /* MIPS core registers */
++#define BCM4710_REG_EXTIF 0x18007000 /* External Interface core registers */
++#define BCM4710_REG_EMAC1 0x18008000 /* Ethernet MAC 1 core registers */
++
++#define BCM4710_EXTIF 0x1f000000 /* External Interface base address */
++#define BCM4710_PCMCIA_MEM 0x1f000000 /* External Interface PCMCIA memory access */
++#define BCM4710_PCMCIA_IO 0x1f100000 /* PCMCIA I/O access */
++#define BCM4710_PCMCIA_CONF 0x1f200000 /* PCMCIA configuration */
++#define BCM4710_PROG 0x1f800000 /* Programable interface */
++#define BCM4710_FLASH 0x1fc00000 /* Flash */
++
++#define BCM4710_EJTAG 0xff200000 /* MIPS EJTAG space (2M) */
++
++#define BCM4710_UART (BCM4710_REG_EXTIF + 0x00000300)
++
++#define BCM4710_EUART (BCM4710_EXTIF + 0x00800000)
++#define BCM4710_LED (BCM4710_EXTIF + 0x00900000)
++
++#define SBFLAG_PCI 0
++#define SBFLAG_ENET0 1
++#define SBFLAG_ILINE20 2
++#define SBFLAG_CODEC 3
++#define SBFLAG_USB 4
++#define SBFLAG_EXTIF 5
++#define SBFLAG_ENET1 6
++
++#ifdef CONFIG_HWSIM
++#define BCM4710_TRACE(trval) do { *((int *)0xa0000f18) = (trval); } while (0)
++#else
++#define BCM4710_TRACE(trval)
++#endif
++
++
++/* BCM94702 CPCI -ExtIF used for LocalBus devs */
++
++#define BCM94702_CPCI_RESET_ADDR BCM4710_EXTIF
++#define BCM94702_CPCI_BOARDID_ADDR (BCM4710_EXTIF | 0x4000)
++#define BCM94702_CPCI_DOC_ADDR (BCM4710_EXTIF | 0x6000)
++#define BCM94702_DOC_ADDR BCM94702_CPCI_DOC_ADDR
++#define BCM94702_CPCI_LED_ADDR (BCM4710_EXTIF | 0xc000)
++#define BCM94702_CPCI_NVRAM_ADDR (BCM4710_EXTIF | 0xe000)
++#define BCM94702_CPCI_NVRAM_SIZE 0x1ff0 /* 8K NVRAM : DS1743/STM48txx*/
++#define BCM94702_CPCI_TOD_REG_BASE (BCM94702_CPCI_NVRAM_ADDR | 0x1ff0)
++
++#define LED_REG(x) \
++ (*(volatile unsigned char *) (KSEG1ADDR(BCM94702_CPCI_LED_ADDR) + (x)))
++
++/*
++ * Reset function implemented in PLD. Read or write should trigger hard reset
++ */
++#define SYS_HARD_RESET() \
++ { for (;;) \
++ *( (volatile unsigned char *)\
++ KSEG1ADDR(BCM94702_CPCI_RESET_ADDR) ) = 0x80; \
++ }
++
++#endif /* _bcm4710_h_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/bcmdefs.h linux.dev/arch/mips/bcm947xx/include/bcmdefs.h
+--- linux.old/arch/mips/bcm947xx/include/bcmdefs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/bcmdefs.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,106 @@
++/*
++ * Misc system wide definitions
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id: bcmdefs.h,v 1.1.1.3 2006/04/08 06:13:39 honor Exp $
++ */
++
++#ifndef _bcmdefs_h_
++#define _bcmdefs_h_
++
++/*
++ * One doesn't need to include this file explicitly, gets included automatically if
++ * typedefs.h is included.
++ */
++
++/* Reclaiming text and data :
++ * The following macros specify special linker sections that can be reclaimed
++ * after a system is considered 'up'.
++ */
++#if defined(__GNUC__) && defined(BCMRECLAIM)
++extern bool bcmreclaimed;
++#define BCMINITDATA(_data) __attribute__ ((__section__ (".dataini." #_data))) _data
++#define BCMINITFN(_fn) __attribute__ ((__section__ (".textini." #_fn))) _fn
++#else /* #if defined(__GNUC__) && defined(BCMRECLAIM) */
++#define BCMINITDATA(_data) _data
++#define BCMINITFN(_fn) _fn
++#define bcmreclaimed 0
++#endif /* #if defined(__GNUC__) && defined(BCMRECLAIM) */
++
++/* Reclaim uninit functions if BCMNODOWN is defined */
++/* and if they are not already removed by -gc-sections */
++#ifdef BCMNODOWN
++#define BCMUNINITFN(_fn) BCMINITFN(_fn)
++#else
++#define BCMUNINITFN(_fn) _fn
++#endif
++
++#ifdef BCMRECLAIM
++#define CONST
++#else
++#define CONST const
++#endif /* BCMRECLAIM */
++
++/* Compatibility with old-style BCMRECLAIM */
++#define BCMINIT(_id) _id
++
++
++/* Put some library data/code into ROM to reduce RAM requirements */
++#if defined(__GNUC__) && defined(BCMROMOFFLOAD)
++#define BCMROMDATA(_data) __attribute__ ((__section__ (".datarom." #_data))) _data
++#define BCMROMFN(_fn) __attribute__ ((__section__ (".textrom." #_fn))) _fn
++#else
++#define BCMROMDATA(_data) _data
++#define BCMROMFN(_fn) _fn
++#endif
++
++/* Bus types */
++#define SB_BUS 0 /* Silicon Backplane */
++#define PCI_BUS 1 /* PCI target */
++#define PCMCIA_BUS 2 /* PCMCIA target */
++#define SDIO_BUS 3 /* SDIO target */
++#define JTAG_BUS 4 /* JTAG */
++#define NO_BUS 0xFF /* Bus that does not support R/W REG */
++
++/* Allows optimization for single-bus support */
++#ifdef BCMBUSTYPE
++#define BUSTYPE(bus) (BCMBUSTYPE)
++#else
++#define BUSTYPE(bus) (bus)
++#endif
++
++/* Defines for DMA Address Width - Shared between OSL and HNDDMA */
++#define DMADDR_MASK_32 0x0 /* Address mask for 32-bits */
++#define DMADDR_MASK_30 0xc0000000 /* Address mask for 30-bits */
++#define DMADDR_MASK_0 0xffffffff /* Address mask for 0-bits (hi-part) */
++
++#define DMADDRWIDTH_30 30 /* 30-bit addressing capability */
++#define DMADDRWIDTH_32 32 /* 32-bit addressing capability */
++#define DMADDRWIDTH_63 63 /* 64-bit addressing capability */
++#define DMADDRWIDTH_64 64 /* 64-bit addressing capability */
++
++/* packet headroom necessary to accomodate the largest header in the system, (i.e TXOFF).
++ * By doing, we avoid the need to allocate an extra buffer for the header when bridging to WL.
++ * There is a compile time check in wlc.c which ensure that this value is at least as big
++ * as TXOFF. This value is used in dma_rxfill (hnddma.c).
++ */
++#define BCMEXTRAHDROOM 160
++
++/* Headroom required for dongle-to-host communication. Packets allocated
++ * locally in the dongle (e.g. for CDC ioctls or RNDIS messages) should
++ * leave this much room in front for low-level message headers which may
++ * be needed to get across the dongle bus to the host. (These messages
++ * don't go over the network, so room for the full WL header above would
++ * be a waste.)
++ */
++#define BCMDONGLEHDRSZ 8
++
++
++
++#endif /* _bcmdefs_h_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/bcmdevs1.h linux.dev/arch/mips/bcm947xx/include/bcmdevs1.h
+--- linux.old/arch/mips/bcm947xx/include/bcmdevs1.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/bcmdevs1.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,391 @@
++/*
++ * Broadcom device-specific manifest constants.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id$
++ */
++
++#ifndef _BCMDEVS_H
++#define _BCMDEVS_H
++
++
++/* Known PCI vendor Id's */
++#define VENDOR_EPIGRAM 0xfeda
++#define VENDOR_BROADCOM 0x14e4
++#define VENDOR_3COM 0x10b7
++#define VENDOR_NETGEAR 0x1385
++#define VENDOR_DIAMOND 0x1092
++#define VENDOR_DELL 0x1028
++#define VENDOR_HP 0x0e11
++#define VENDOR_APPLE 0x106b
++
++/* PCI Device Id's */
++#define BCM4210_DEVICE_ID 0x1072 /* never used */
++#define BCM4211_DEVICE_ID 0x4211
++#define BCM4230_DEVICE_ID 0x1086 /* never used */
++#define BCM4231_DEVICE_ID 0x4231
++
++#define BCM4410_DEVICE_ID 0x4410 /* bcm44xx family pci iline */
++#define BCM4430_DEVICE_ID 0x4430 /* bcm44xx family cardbus iline */
++#define BCM4412_DEVICE_ID 0x4412 /* bcm44xx family pci enet */
++#define BCM4432_DEVICE_ID 0x4432 /* bcm44xx family cardbus enet */
++
++#define BCM3352_DEVICE_ID 0x3352 /* bcm3352 device id */
++#define BCM3360_DEVICE_ID 0x3360 /* bcm3360 device id */
++
++#define EPI41210_DEVICE_ID 0xa0fa /* bcm4210 */
++#define EPI41230_DEVICE_ID 0xa10e /* bcm4230 */
++
++#define BCM47XX_ILINE_ID 0x4711 /* 47xx iline20 */
++#define BCM47XX_V90_ID 0x4712 /* 47xx v90 codec */
++#define BCM47XX_ENET_ID 0x4713 /* 47xx enet */
++#define BCM47XX_EXT_ID 0x4714 /* 47xx external i/f */
++#define BCM47XX_USB_ID 0x4715 /* 47xx usb */
++#define BCM47XX_USBH_ID 0x4716 /* 47xx usb host */
++#define BCM47XX_USBD_ID 0x4717 /* 47xx usb device */
++#define BCM47XX_IPSEC_ID 0x4718 /* 47xx ipsec */
++#define BCM47XX_ROBO_ID 0x4719 /* 47xx/53xx roboswitch core */
++#define BCM47XX_USB20H_ID 0x471a /* 47xx usb 2.0 host */
++#define BCM47XX_USB20D_ID 0x471b /* 47xx usb 2.0 device */
++
++#define BCM4710_DEVICE_ID 0x4710 /* 4710 primary function 0 */
++
++#define BCM4610_DEVICE_ID 0x4610 /* 4610 primary function 0 */
++#define BCM4610_ILINE_ID 0x4611 /* 4610 iline100 */
++#define BCM4610_V90_ID 0x4612 /* 4610 v90 codec */
++#define BCM4610_ENET_ID 0x4613 /* 4610 enet */
++#define BCM4610_EXT_ID 0x4614 /* 4610 external i/f */
++#define BCM4610_USB_ID 0x4615 /* 4610 usb */
++
++#define BCM4402_DEVICE_ID 0x4402 /* 4402 primary function 0 */
++#define BCM4402_ENET_ID 0x4402 /* 4402 enet */
++#define BCM4402_V90_ID 0x4403 /* 4402 v90 codec */
++#define BCM4401_ENET_ID 0x170c /* 4401b0 production enet cards */
++
++#define BCM4301_DEVICE_ID 0x4301 /* 4301 primary function 0 */
++#define BCM4301_D11B_ID 0x4301 /* 4301 802.11b */
++
++#define BCM4307_DEVICE_ID 0x4307 /* 4307 primary function 0 */
++#define BCM4307_V90_ID 0x4305 /* 4307 v90 codec */
++#define BCM4307_ENET_ID 0x4306 /* 4307 enet */
++#define BCM4307_D11B_ID 0x4307 /* 4307 802.11b */
++
++#define BCM4306_DEVICE_ID 0x4306 /* 4306 chipcommon chipid */
++#define BCM4306_D11G_ID 0x4320 /* 4306 802.11g */
++#define BCM4306_D11G_ID2 0x4325
++#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */
++#define BCM4306_UART_ID 0x4322 /* 4306 uart */
++#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */
++#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */
++
++#define BCM4309_PKG_ID 1 /* 4309 package id */
++
++#define BCM4303_D11B_ID 0x4303 /* 4303 802.11b */
++#define BCM4303_PKG_ID 2 /* 4303 package id */
++
++#define BCM4310_DEVICE_ID 0x4310 /* 4310 chipcommon chipid */
++#define BCM4310_D11B_ID 0x4311 /* 4310 802.11b */
++#define BCM4310_UART_ID 0x4312 /* 4310 uart */
++#define BCM4310_ENET_ID 0x4313 /* 4310 enet */
++#define BCM4310_USB_ID 0x4315 /* 4310 usb */
++
++#define BCMGPRS_UART_ID 0x4333 /* Uart id used by 4306/gprs card */
++#define BCMGPRS2_UART_ID 0x4344 /* Uart id used by 4306/gprs card */
++
++
++#define BCM4704_DEVICE_ID 0x4704 /* 4704 chipcommon chipid */
++#define BCM4704_ENET_ID 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */
++
++#define BCM4317_DEVICE_ID 0x4317 /* 4317 chip common chipid */
++
++#define BCM4318_DEVICE_ID 0x4318 /* 4318 chip common chipid */
++#define BCM4318_D11G_ID 0x4318 /* 4318 801.11b/g id */
++#define BCM4318_D11DUAL_ID 0x4319 /* 4318 801.11a/b/g id */
++#define BCM4318_JTAGM_ID 0x4331 /* 4318 jtagm device id */
++
++#define FPGA_JTAGM_ID 0x4330 /* ??? */
++
++/* Address map */
++#define BCM4710_SDRAM 0x00000000 /* Physical SDRAM */
++#define BCM4710_PCI_MEM 0x08000000 /* Host Mode PCI memory access space (64 MB) */
++#define BCM4710_PCI_CFG 0x0c000000 /* Host Mode PCI configuration space (64 MB) */
++#define BCM4710_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */
++#define BCM4710_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */
++#define BCM4710_ENUM 0x18000000 /* Beginning of core enumeration space */
++
++/* Core register space */
++#define BCM4710_REG_SDRAM 0x18000000 /* SDRAM core registers */
++#define BCM4710_REG_ILINE20 0x18001000 /* InsideLine20 core registers */
++#define BCM4710_REG_EMAC0 0x18002000 /* Ethernet MAC 0 core registers */
++#define BCM4710_REG_CODEC 0x18003000 /* Codec core registers */
++#define BCM4710_REG_USB 0x18004000 /* USB core registers */
++#define BCM4710_REG_PCI 0x18005000 /* PCI core registers */
++#define BCM4710_REG_MIPS 0x18006000 /* MIPS core registers */
++#define BCM4710_REG_EXTIF 0x18007000 /* External Interface core registers */
++#define BCM4710_REG_EMAC1 0x18008000 /* Ethernet MAC 1 core registers */
++
++#define BCM4710_EXTIF 0x1f000000 /* External Interface base address */
++#define BCM4710_PCMCIA_MEM 0x1f000000 /* External Interface PCMCIA memory access */
++#define BCM4710_PCMCIA_IO 0x1f100000 /* PCMCIA I/O access */
++#define BCM4710_PCMCIA_CONF 0x1f200000 /* PCMCIA configuration */
++#define BCM4710_PROG 0x1f800000 /* Programable interface */
++#define BCM4710_FLASH 0x1fc00000 /* Flash */
++
++#define BCM4710_EJTAG 0xff200000 /* MIPS EJTAG space (2M) */
++
++#define BCM4710_UART (BCM4710_REG_EXTIF + 0x00000300)
++
++#define BCM4710_EUART (BCM4710_EXTIF + 0x00800000)
++#define BCM4710_LED (BCM4710_EXTIF + 0x00900000)
++
++#define BCM4712_DEVICE_ID 0x4712 /* 4712 chipcommon chipid */
++#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */
++#define BCM4712LARGE_PKG_ID 0 /* 340pin 4712 package id */
++#define BCM4712SMALL_PKG_ID 1 /* 200pin 4712 package id */
++#define BCM4712MID_PKG_ID 2 /* 225pin 4712 package id */
++
++#define SDIOH_FPGA_ID 0x4380 /* sdio host fpga */
++
++#define BCM5365_DEVICE_ID 0x5365 /* 5365 chipcommon chipid */
++#define BCM5350_DEVICE_ID 0x5350 /* bcm5350 chipcommon chipid */
++#define BCM5352_DEVICE_ID 0x5352 /* bcm5352 chipcommon chipid */
++
++#define BCM4320_DEVICE_ID 0x4320 /* bcm4320 chipcommon chipid */
++
++/* PCMCIA vendor Id's */
++
++#define VENDOR_BROADCOM_PCMCIA 0x02d0
++
++/* SDIO vendor Id's */
++#define VENDOR_BROADCOM_SDIO 0x00BF
++
++
++/* boardflags */
++#define BFL_BTCOEXIST 0x0001 /* This board implements Bluetooth coexistance */
++#define BFL_PACTRL 0x0002 /* This board has gpio 9 controlling the PA */
++#define BFL_AIRLINEMODE 0x0004 /* This board implements gpio13 radio disable indication */
++#define BFL_ENETROBO 0x0010 /* This board has robo switch or core */
++#define BFL_CCKHIPWR 0x0040 /* Can do high-power CCK transmission */
++#define BFL_ENETADM 0x0080 /* This board has ADMtek switch */
++#define BFL_ENETVLAN 0x0100 /* This board has vlan capability */
++#define BFL_AFTERBURNER 0x0200 /* This board supports Afterburner mode */
++#define BFL_NOPCI 0x0400 /* This board leaves PCI floating */
++#define BFL_FEM 0x0800 /* This board supports the Front End Module */
++#define BFL_EXTLNA 0x1000 /* This board has an external LNA */
++#define BFL_HGPA 0x2000 /* This board has a high gain PA */
++#define BFL_BTCMOD 0x4000 /* This board' BTCOEXIST is in the alternate gpios */
++#define BFL_ALTIQ 0x8000 /* Alternate I/Q settings */
++
++/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */
++#define BOARD_GPIO_HWRAD_B 0x010 /* bit 4 is HWRAD input on 4301 */
++#define BOARD_GPIO_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistance Input */
++#define BOARD_GPIO_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistance Out */
++#define BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistance Input */
++#define BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistance Out */
++#define BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */
++#define PCI_CFG_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */
++#define PCI_CFG_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */
++#define PCI_CFG_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */
++#define PCI_CFG_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */
++
++/* Bus types */
++#define SB_BUS 0 /* Silicon Backplane */
++#define PCI_BUS 1 /* PCI target */
++#define PCMCIA_BUS 2 /* PCMCIA target */
++#define SDIO_BUS 3 /* SDIO target */
++#define JTAG_BUS 4 /* JTAG */
++
++/* Allows optimization for single-bus support */
++#ifdef BCMBUSTYPE
++#define BUSTYPE(bus) (BCMBUSTYPE)
++#else
++#define BUSTYPE(bus) (bus)
++#endif
++
++/* power control defines */
++#define PLL_DELAY 150 /* us pll on delay */
++#define FREF_DELAY 200 /* us fref change delay */
++#define MIN_SLOW_CLK 32 /* us Slow clock period */
++#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */
++
++/* Reference Board Types */
++
++#define BU4710_BOARD 0x0400
++#define VSIM4710_BOARD 0x0401
++#define QT4710_BOARD 0x0402
++
++#define BU4610_BOARD 0x0403
++#define VSIM4610_BOARD 0x0404
++
++#define BU4307_BOARD 0x0405
++#define BCM94301CB_BOARD 0x0406
++#define BCM94301PC_BOARD 0x0406 /* Pcmcia 5v card */
++#define BCM94301MP_BOARD 0x0407
++#define BCM94307MP_BOARD 0x0408
++#define BCMAP4307_BOARD 0x0409
++
++#define BU4309_BOARD 0x040a
++#define BCM94309CB_BOARD 0x040b
++#define BCM94309MP_BOARD 0x040c
++#define BCM4309AP_BOARD 0x040d
++
++#define BCM94302MP_BOARD 0x040e
++
++#define VSIM4310_BOARD 0x040f
++#define BU4711_BOARD 0x0410
++#define BCM94310U_BOARD 0x0411
++#define BCM94310AP_BOARD 0x0412
++#define BCM94310MP_BOARD 0x0414
++
++#define BU4306_BOARD 0x0416
++#define BCM94306CB_BOARD 0x0417
++#define BCM94306MP_BOARD 0x0418
++
++#define BCM94710D_BOARD 0x041a
++#define BCM94710R1_BOARD 0x041b
++#define BCM94710R4_BOARD 0x041c
++#define BCM94710AP_BOARD 0x041d
++
++
++#define BU2050_BOARD 0x041f
++
++
++#define BCM94309G_BOARD 0x0421
++
++#define BCM94301PC3_BOARD 0x0422 /* Pcmcia 3.3v card */
++
++#define BU4704_BOARD 0x0423
++#define BU4702_BOARD 0x0424
++
++#define BCM94306PC_BOARD 0x0425 /* pcmcia 3.3v 4306 card */
++
++#define BU4317_BOARD 0x0426
++
++
++#define BCM94702MN_BOARD 0x0428
++
++/* BCM4702 1U CompactPCI Board */
++#define BCM94702CPCI_BOARD 0x0429
++
++/* BCM4702 with BCM95380 VLAN Router */
++#define BCM95380RR_BOARD 0x042a
++
++/* cb4306 with SiGe PA */
++#define BCM94306CBSG_BOARD 0x042b
++
++/* mp4301 with 2050 radio */
++#define BCM94301MPL_BOARD 0x042c
++
++/* cb4306 with SiGe PA */
++#define PCSG94306_BOARD 0x042d
++
++/* bu4704 with sdram */
++#define BU4704SD_BOARD 0x042e
++
++/* Dual 11a/11g Router */
++#define BCM94704AGR_BOARD 0x042f
++
++/* 11a-only minipci */
++#define BCM94308MP_BOARD 0x0430
++
++
++
++/* BCM94317 boards */
++#define BCM94317CB_BOARD 0x0440
++#define BCM94317MP_BOARD 0x0441
++#define BCM94317PCMCIA_BOARD 0x0442
++#define BCM94317SDIO_BOARD 0x0443
++
++#define BU4712_BOARD 0x0444
++#define BU4712SD_BOARD 0x045d
++#define BU4712L_BOARD 0x045f
++
++/* BCM4712 boards */
++#define BCM94712AP_BOARD 0x0445
++#define BCM94712P_BOARD 0x0446
++
++/* BCM4318 boards */
++#define BU4318_BOARD 0x0447
++#define CB4318_BOARD 0x0448
++#define MPG4318_BOARD 0x0449
++#define MP4318_BOARD 0x044a
++#define SD4318_BOARD 0x044b
++
++/* BCM63XX boards */
++#define BCM96338_BOARD 0x6338
++#define BCM96345_BOARD 0x6345
++#define BCM96348_BOARD 0x6348
++
++/* Another mp4306 with SiGe */
++#define BCM94306P_BOARD 0x044c
++
++/* CF-like 4317 modules */
++#define BCM94317CF_BOARD 0x044d
++
++/* mp4303 */
++#define BCM94303MP_BOARD 0x044e
++
++/* mpsgh4306 */
++#define BCM94306MPSGH_BOARD 0x044f
++
++/* BRCM 4306 w/ Front End Modules */
++#define BCM94306MPM 0x0450
++#define BCM94306MPL 0x0453
++
++/* 4712agr */
++#define BCM94712AGR_BOARD 0x0451
++
++/* The real CF 4317 board */
++#define CFI4317_BOARD 0x0452
++
++/* pcmcia 4303 */
++#define PC4303_BOARD 0x0454
++
++/* 5350K */
++#define BCM95350K_BOARD 0x0455
++
++/* 5350R */
++#define BCM95350R_BOARD 0x0456
++
++/* 4306mplna */
++#define BCM94306MPLNA_BOARD 0x0457
++
++/* 4320 boards */
++#define BU4320_BOARD 0x0458
++#define BU4320S_BOARD 0x0459
++#define BCM94320PH_BOARD 0x045a
++
++/* 4306mph */
++#define BCM94306MPH_BOARD 0x045b
++
++/* 4306pciv */
++#define BCM94306PCIV_BOARD 0x045c
++
++#define BU4712SD_BOARD 0x045d
++
++#define BCM94320PFLSH_BOARD 0x045e
++
++#define BU4712L_BOARD 0x045f
++#define BCM94712LGR_BOARD 0x0460
++#define BCM94320R_BOARD 0x0461
++
++#define BU5352_BOARD 0x0462
++
++#define BCM94318MPGH_BOARD 0x0463
++
++
++#define BCM95352GR_BOARD 0x0467
++
++/* bcm95351agr */
++#define BCM95351AGR_BOARD 0x0470
++
++/* # of GPIO pins */
++#define GPIO_NUMPINS 16
++
++#endif /* _BCMDEVS_H */
+diff -urN linux.old/arch/mips/bcm947xx/include/bcmdevs.h linux.dev/arch/mips/bcm947xx/include/bcmdevs.h
+--- linux.old/arch/mips/bcm947xx/include/bcmdevs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/bcmdevs.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,369 @@
++/*
++ * Broadcom device-specific manifest constants.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id: bcmdevs.h,v 1.1.1.17 2006/04/15 01:29:08 michael Exp $
++ */
++
++#ifndef _BCMDEVS_H
++#define _BCMDEVS_H
++
++#include "bcm4710.h"
++
++/* Known PCI vendor Id's */
++#define VENDOR_EPIGRAM 0xfeda
++#define VENDOR_BROADCOM 0x14e4
++#define VENDOR_3COM 0x10b7
++#define VENDOR_NETGEAR 0x1385
++#define VENDOR_DIAMOND 0x1092
++#define VENDOR_DELL 0x1028
++#define VENDOR_HP 0x0e11
++#define VENDOR_APPLE 0x106b
++
++/* PCI Device Id's */
++#define BCM4210_DEVICE_ID 0x1072 /* never used */
++#define BCM4211_DEVICE_ID 0x4211
++#define BCM4230_DEVICE_ID 0x1086 /* never used */
++#define BCM4231_DEVICE_ID 0x4231
++
++#define BCM4410_DEVICE_ID 0x4410 /* bcm44xx family pci iline */
++#define BCM4430_DEVICE_ID 0x4430 /* bcm44xx family cardbus iline */
++#define BCM4412_DEVICE_ID 0x4412 /* bcm44xx family pci enet */
++#define BCM4432_DEVICE_ID 0x4432 /* bcm44xx family cardbus enet */
++
++#define BCM3352_DEVICE_ID 0x3352 /* bcm3352 device id */
++#define BCM3360_DEVICE_ID 0x3360 /* bcm3360 device id */
++
++#define EPI41210_DEVICE_ID 0xa0fa /* bcm4210 */
++#define EPI41230_DEVICE_ID 0xa10e /* bcm4230 */
++
++#define BCM47XX_ILINE_ID 0x4711 /* 47xx iline20 */
++#define BCM47XX_V90_ID 0x4712 /* 47xx v90 codec */
++#define BCM47XX_ENET_ID 0x4713 /* 47xx enet */
++#define BCM47XX_EXT_ID 0x4714 /* 47xx external i/f */
++#define BCM47XX_USB_ID 0x4715 /* 47xx usb */
++#define BCM47XX_USBH_ID 0x4716 /* 47xx usb host */
++#define BCM47XX_USBD_ID 0x4717 /* 47xx usb device */
++#define BCM47XX_IPSEC_ID 0x4718 /* 47xx ipsec */
++#define BCM47XX_ROBO_ID 0x4719 /* 47xx/53xx roboswitch core */
++#define BCM47XX_USB20H_ID 0x471a /* 47xx usb 2.0 host */
++#define BCM47XX_USB20D_ID 0x471b /* 47xx usb 2.0 device */
++#define BCM47XX_ATA100_ID 0x471d /* 47xx parallel ATA */
++#define BCM47XX_SATAXOR_ID 0x471e /* 47xx serial ATA & XOR DMA */
++#define BCM47XX_GIGETH_ID 0x471f /* 47xx GbE (5700) */
++
++#define BCM47XX_SMBUS_EMU_ID 0x47fe /* 47xx emulated SMBus device */
++#define BCM47XX_XOR_EMU_ID 0x47ff /* 47xx emulated XOR engine */
++
++#define BCM4710_CHIP_ID 0x4710 /* 4710 chipid returned by sb_chip() */
++#define BCM4710_DEVICE_ID 0x4710 /* 4710 primary function 0 */
++
++#define BCM4402_CHIP_ID 0x4402 /* 4402 chipid */
++#define BCM4402_ENET_ID 0x4402 /* 4402 enet */
++#define BCM4402_V90_ID 0x4403 /* 4402 v90 codec */
++#define BCM4401_ENET_ID 0x170c /* 4401b0 production enet cards */
++
++#define BCM4306_CHIP_ID 0x4306 /* 4306 chipcommon chipid */
++#define BCM4306_D11G_ID 0x4320 /* 4306 802.11g */
++#define BCM4306_D11G_ID2 0x4325
++#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */
++#define BCM4306_UART_ID 0x4322 /* 4306 uart */
++#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */
++#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */
++
++#define BCM4309_PKG_ID 1 /* 4309 package id */
++
++#define BCM4311_CHIP_ID 0x4311 /* 4311 PCIe 802.11a/b/g */
++#define BCM4311_D11G_ID 0x4311 /* 4311 802.11b/g id */
++#define BCM4311_D11DUAL_ID 0x4312 /* 4311 802.11a/b/g id */
++#define BCM4311_D11A_ID 0x4313 /* 4311 802.11a id */
++
++#define BCM4303_D11B_ID 0x4303 /* 4303 802.11b */
++#define BCM4303_PKG_ID 2 /* 4303 package id */
++
++#define BCMGPRS_UART_ID 0x4333 /* Uart id used by 4306/gprs card */
++#define BCMGPRS2_UART_ID 0x4344 /* Uart id used by 4306/gprs card */
++
++#define BCM4704_CHIP_ID 0x4704 /* 4704 chipcommon chipid */
++#define BCM4704_ENET_ID 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */
++
++#define BCM4318_CHIP_ID 0x4318 /* 4318 chip common chipid */
++#define BCM4318_D11G_ID 0x4318 /* 4318 802.11b/g id */
++#define BCM4318_D11DUAL_ID 0x4319 /* 4318 802.11a/b/g id */
++#define BCM4318_D11A_ID 0x431a /* 4318 802.11a id */
++
++#define BCM4321_CHIP_ID 0x4321 /* 4321 chip common chipid */
++#define BCM4321_D11N_ID 0x4328 /* 4321 802.11n dualband id */
++#define BCM4321_D11N2G_ID 0x4329 /* 4321 802.11n 2.4Hgz band id */
++#define BCM4321_D11N5G_ID 0x432a /* 4321 802.11n 5Ghz band id */
++
++#define BCM4331_CHIP_ID 0x4331 /* 4331 chip common chipid */
++#define BCM4331_D11N2G_ID 0x4330 /* 4331 802.11n 2.4Ghz band id */
++#define BCM4331_D11N_ID 0x4331 /* 4331 802.11n dualband id */
++#define BCM4331_D11N5G_ID 0x4332 /* 4331 802.11n 5Ghz band id */
++
++#define HDLSIM5350_PKG_ID 1 /* HDL simulator package id for a 5350 */
++#define HDLSIM_PKG_ID 14 /* HDL simulator package id */
++#define HWSIM_PKG_ID 15 /* Hardware simulator package id */
++
++#define BCM4712_CHIP_ID 0x4712 /* 4712 chipcommon chipid */
++#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */
++#define BCM4712LARGE_PKG_ID 0 /* 340pin 4712 package id */
++#define BCM4712SMALL_PKG_ID 1 /* 200pin 4712 package id */
++#define BCM4712MID_PKG_ID 2 /* 225pin 4712 package id */
++
++#define BCM5365_CHIP_ID 0x5365 /* 5365 chipcommon chipid */
++#define BCM5350_CHIP_ID 0x5350 /* bcm5350 chipcommon chipid */
++#define BCM5352_CHIP_ID 0x5352 /* bcm5352 chipcommon chipid */
++
++#define BCM4320_CHIP_ID 0x4320 /* bcm4320 chipcommon chipid */
++
++#define BCM4328_CHIP_ID 0x4328 /* bcm4328 chipcommon chipid */
++
++#define FPGA_JTAGM_ID 0x43f0 /* FPGA jtagm device id */
++#define BCM43XX_JTAGM_ID 0x43f1 /* 43xx jtagm device id */
++#define BCM43XXOLD_JTAGM_ID 0x4331 /* 43xx old jtagm device id */
++
++#define SDIOH_FPGA_ID 0x43f2 /* sdio host fpga */
++#define SDIOD_FPGA_ID 0x43f4 /* sdio device fpga */
++
++#define MIMO_FPGA_ID 0x43f8 /* FPGA mimo minimacphy device id */
++
++#define BCM4785_CHIP_ID 0x4785 /* 4785 chipcommon chipid */
++
++/* PCMCIA vendor Id's */
++
++#define VENDOR_BROADCOM_PCMCIA 0x02d0
++
++/* SDIO vendor Id's */
++#define VENDOR_BROADCOM_SDIO 0x00BF
++
++
++/* boardflags */
++#define BFL_BTCOEXIST 0x0001 /* This board implements Bluetooth coexistance */
++#define BFL_PACTRL 0x0002 /* This board has gpio 9 controlling the PA */
++#define BFL_AIRLINEMODE 0x0004 /* This board implements gpio13 radio disable indication */
++#define BFL_ENETROBO 0x0010 /* This board has robo switch or core */
++#define BFL_CCKHIPWR 0x0040 /* Can do high-power CCK transmission */
++#define BFL_ENETADM 0x0080 /* This board has ADMtek switch */
++#define BFL_ENETVLAN 0x0100 /* This board has vlan capability */
++#define BFL_AFTERBURNER 0x0200 /* This board supports Afterburner mode */
++#define BFL_NOPCI 0x0400 /* This board leaves PCI floating */
++#define BFL_FEM 0x0800 /* This board supports the Front End Module */
++#define BFL_EXTLNA 0x1000 /* This board has an external LNA */
++#define BFL_HGPA 0x2000 /* This board has a high gain PA */
++#define BFL_BTCMOD 0x4000 /* This board' BTCOEXIST is in the alternate gpios */
++#define BFL_ALTIQ 0x8000 /* Alternate I/Q settings */
++
++/* boardflags2 */
++#define BFL2_RXBB_INT_REG_DIS 0x00000001 /* This board has an external rxbb regulator */
++#define BFL2_SSWITCH_AVAIL 0x00000002 /* This board has a superswitch for > 2 antennas */
++#define BFL2_TXPWRCTRL_EN 0x00000004 /* This board permits TX Power Control to be enabled */
++
++/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */
++#define BOARD_GPIO_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistance Input */
++#define BOARD_GPIO_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistance Out */
++#define BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistance Input */
++#define BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistance Out */
++#define BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */
++#define PCI_CFG_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */
++#define PCI_CFG_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */
++#define PCI_CFG_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */
++#define PCI_CFG_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */
++
++/* power control defines */
++#define PLL_DELAY 150 /* us pll on delay */
++#define FREF_DELAY 200 /* us fref change delay */
++#define MIN_SLOW_CLK 32 /* us Slow clock period */
++#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */
++
++/* Reference Board Types */
++
++#define BU4710_BOARD 0x0400
++#define VSIM4710_BOARD 0x0401
++#define QT4710_BOARD 0x0402
++
++#define BU4309_BOARD 0x040a
++#define BCM94309CB_BOARD 0x040b
++#define BCM94309MP_BOARD 0x040c
++#define BCM4309AP_BOARD 0x040d
++
++#define BCM94302MP_BOARD 0x040e
++
++#define BU4306_BOARD 0x0416
++#define BCM94306CB_BOARD 0x0417
++#define BCM94306MP_BOARD 0x0418
++
++#define BCM94710D_BOARD 0x041a
++#define BCM94710R1_BOARD 0x041b
++#define BCM94710R4_BOARD 0x041c
++#define BCM94710AP_BOARD 0x041d
++
++#define BU2050_BOARD 0x041f
++
++
++#define BCM94309G_BOARD 0x0421
++
++#define BU4704_BOARD 0x0423
++#define BU4702_BOARD 0x0424
++
++#define BCM94306PC_BOARD 0x0425 /* pcmcia 3.3v 4306 card */
++
++
++#define BCM94702MN_BOARD 0x0428
++
++/* BCM4702 1U CompactPCI Board */
++#define BCM94702CPCI_BOARD 0x0429
++
++/* BCM4702 with BCM95380 VLAN Router */
++#define BCM95380RR_BOARD 0x042a
++
++/* cb4306 with SiGe PA */
++#define BCM94306CBSG_BOARD 0x042b
++
++/* cb4306 with SiGe PA */
++#define PCSG94306_BOARD 0x042d
++
++/* bu4704 with sdram */
++#define BU4704SD_BOARD 0x042e
++
++/* Dual 11a/11g Router */
++#define BCM94704AGR_BOARD 0x042f
++
++/* 11a-only minipci */
++#define BCM94308MP_BOARD 0x0430
++
++
++
++#define BU4712_BOARD 0x0444
++#define BU4712SD_BOARD 0x045d
++#define BU4712L_BOARD 0x045f
++
++/* BCM4712 boards */
++#define BCM94712AP_BOARD 0x0445
++#define BCM94712P_BOARD 0x0446
++
++/* BCM4318 boards */
++#define BU4318_BOARD 0x0447
++#define CB4318_BOARD 0x0448
++#define MPG4318_BOARD 0x0449
++#define MP4318_BOARD 0x044a
++#define SD4318_BOARD 0x044b
++
++/* BCM63XX boards */
++#define BCM96338_BOARD 0x6338
++#define BCM96348_BOARD 0x6348
++
++/* Another mp4306 with SiGe */
++#define BCM94306P_BOARD 0x044c
++
++/* mp4303 */
++#define BCM94303MP_BOARD 0x044e
++
++/* mpsgh4306 */
++#define BCM94306MPSGH_BOARD 0x044f
++
++/* BRCM 4306 w/ Front End Modules */
++#define BCM94306MPM 0x0450
++#define BCM94306MPL 0x0453
++
++/* 4712agr */
++#define BCM94712AGR_BOARD 0x0451
++
++/* pcmcia 4303 */
++#define PC4303_BOARD 0x0454
++
++/* 5350K */
++#define BCM95350K_BOARD 0x0455
++
++/* 5350R */
++#define BCM95350R_BOARD 0x0456
++
++/* 4306mplna */
++#define BCM94306MPLNA_BOARD 0x0457
++
++/* 4320 boards */
++#define BU4320_BOARD 0x0458
++#define BU4320S_BOARD 0x0459
++#define BCM94320PH_BOARD 0x045a
++
++/* 4306mph */
++#define BCM94306MPH_BOARD 0x045b
++
++/* 4306pciv */
++#define BCM94306PCIV_BOARD 0x045c
++
++#define BU4712SD_BOARD 0x045d
++
++#define BCM94320PFLSH_BOARD 0x045e
++
++#define BU4712L_BOARD 0x045f
++#define BCM94712LGR_BOARD 0x0460
++#define BCM94320R_BOARD 0x0461
++
++#define BU5352_BOARD 0x0462
++
++#define BCM94318MPGH_BOARD 0x0463
++
++#define BU4311_BOARD 0x0464
++#define BCM94311MC_BOARD 0x0465
++#define BCM94311MCAG_BOARD 0x0466
++
++#define BCM95352GR_BOARD 0x0467
++
++/* bcm95351agr */
++#define BCM95351AGR_BOARD 0x0470
++
++/* bcm94704mpcb */
++#define BCM94704MPCB_BOARD 0x0472
++
++/* 4785 boards */
++#define BU4785_BOARD 0x0478
++
++/* 4321 boards */
++#define BU4321_BOARD 0x046b
++#define BU4321E_BOARD 0x047c
++#define MP4321_BOARD 0x046c
++#define CB2_4321_BOARD 0x046d
++#define MC4321_BOARD 0x046e
++
++/* # of GPIO pins */
++#define GPIO_NUMPINS 16
++
++/* radio ID codes */
++#define NORADIO_ID 0xe4f5
++#define NORADIO_IDCODE 0x4e4f5246
++
++#define BCM2050_ID 0x2050
++#define BCM2050_IDCODE 0x02050000
++#define BCM2050A0_IDCODE 0x1205017f
++#define BCM2050A1_IDCODE 0x2205017f
++#define BCM2050R8_IDCODE 0x8205017f
++
++#define BCM2055_ID 0x2055
++#define BCM2055_IDCODE 0x02055000
++#define BCM2055A0_IDCODE 0x1205517f
++
++#define BCM2060_ID 0x2060
++#define BCM2060_IDCODE 0x02060000
++#define BCM2060WW_IDCODE 0x1206017f
++
++#define BCM2062_ID 0x2062
++#define BCM2062_IDCODE 0x02062000
++#define BCM2062A0_IDCODE 0x0206217f
++
++/* parts of an idcode: */
++#define IDCODE_MFG_MASK 0x00000fff
++#define IDCODE_MFG_SHIFT 0
++#define IDCODE_ID_MASK 0x0ffff000
++#define IDCODE_ID_SHIFT 12
++#define IDCODE_REV_MASK 0xf0000000
++#define IDCODE_REV_SHIFT 28
++
++#endif /* _BCMDEVS_H */
+diff -urN linux.old/arch/mips/bcm947xx/include/bcmendian.h linux.dev/arch/mips/bcm947xx/include/bcmendian.h
+--- linux.old/arch/mips/bcm947xx/include/bcmendian.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/bcmendian.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,198 @@
++/*
++ * local version of endian.h - byte order defines
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: bcmendian.h,v 1.1.1.10 2006/02/27 03:43:16 honor Exp $
++*/
++
++#ifndef _BCMENDIAN_H_
++#define _BCMENDIAN_H_
++
++#include <typedefs.h>
++
++/* Byte swap a 16 bit value */
++#define BCMSWAP16(val) \
++ ((uint16)(\
++ (((uint16)(val) & (uint16)0x00ffU) << 8) | \
++ (((uint16)(val) & (uint16)0xff00U) >> 8)))
++
++/* Byte swap a 32 bit value */
++#define BCMSWAP32(val) \
++ ((uint32)(\
++ (((uint32)(val) & (uint32)0x000000ffUL) << 24) | \
++ (((uint32)(val) & (uint32)0x0000ff00UL) << 8) | \
++ (((uint32)(val) & (uint32)0x00ff0000UL) >> 8) | \
++ (((uint32)(val) & (uint32)0xff000000UL) >> 24)))
++
++/* 2 Byte swap a 32 bit value */
++#define BCMSWAP32BY16(val) \
++ ((uint32)(\
++ (((uint32)(val) & (uint32)0x0000ffffUL) << 16) | \
++ (((uint32)(val) & (uint32)0xffff0000UL) >> 16)))
++
++
++static INLINE uint16
++bcmswap16(uint16 val)
++{
++ return BCMSWAP16(val);
++}
++
++static INLINE uint32
++bcmswap32(uint32 val)
++{
++ return BCMSWAP32(val);
++}
++
++static INLINE uint32
++bcmswap32by16(uint32 val)
++{
++ return BCMSWAP32BY16(val);
++}
++
++/* buf - start of buffer of shorts to swap */
++/* len - byte length of buffer */
++static INLINE void
++bcmswap16_buf(uint16 *buf, uint len)
++{
++ len = len/2;
++
++ while (len--) {
++ *buf = bcmswap16(*buf);
++ buf++;
++ }
++}
++
++#ifndef hton16
++#ifndef IL_BIGENDIAN
++#define HTON16(i) BCMSWAP16(i)
++#define hton16(i) bcmswap16(i)
++#define hton32(i) bcmswap32(i)
++#define ntoh16(i) bcmswap16(i)
++#define ntoh32(i) bcmswap32(i)
++#define ltoh16(i) (i)
++#define ltoh32(i) (i)
++#define htol16(i) (i)
++#define htol32(i) (i)
++#else
++#define HTON16(i) (i)
++#define hton16(i) (i)
++#define hton32(i) (i)
++#define ntoh16(i) (i)
++#define ntoh32(i) (i)
++#define ltoh16(i) bcmswap16(i)
++#define ltoh32(i) bcmswap32(i)
++#define htol16(i) bcmswap16(i)
++#define htol32(i) bcmswap32(i)
++#endif /* IL_BIGENDIAN */
++#endif /* hton16 */
++
++#ifndef IL_BIGENDIAN
++#define ltoh16_buf(buf, i)
++#define htol16_buf(buf, i)
++#else
++#define ltoh16_buf(buf, i) bcmswap16_buf((uint16*)buf, i)
++#define htol16_buf(buf, i) bcmswap16_buf((uint16*)buf, i)
++#endif /* IL_BIGENDIAN */
++
++/*
++* store 16-bit value to unaligned little endian byte array.
++*/
++static INLINE void
++htol16_ua_store(uint16 val, uint8 *bytes)
++{
++ bytes[0] = val&0xff;
++ bytes[1] = val>>8;
++}
++
++/*
++* store 32-bit value to unaligned little endian byte array.
++*/
++static INLINE void
++htol32_ua_store(uint32 val, uint8 *bytes)
++{
++ bytes[0] = val&0xff;
++ bytes[1] = (val>>8)&0xff;
++ bytes[2] = (val>>16)&0xff;
++ bytes[3] = val>>24;
++}
++
++/*
++* store 16-bit value to unaligned network(big) endian byte array.
++*/
++static INLINE void
++hton16_ua_store(uint16 val, uint8 *bytes)
++{
++ bytes[1] = val&0xff;
++ bytes[0] = val>>8;
++}
++
++/*
++* store 32-bit value to unaligned network(big) endian byte array.
++*/
++static INLINE void
++hton32_ua_store(uint32 val, uint8 *bytes)
++{
++ bytes[3] = val&0xff;
++ bytes[2] = (val>>8)&0xff;
++ bytes[1] = (val>>16)&0xff;
++ bytes[0] = val>>24;
++}
++
++/*
++* load 16-bit value from unaligned little endian byte array.
++*/
++static INLINE uint16
++ltoh16_ua(void *bytes)
++{
++ return (((uint8*)bytes)[1]<<8)+((uint8 *)bytes)[0];
++}
++
++/*
++* load 32-bit value from unaligned little endian byte array.
++*/
++static INLINE uint32
++ltoh32_ua(void *bytes)
++{
++ return (((uint8*)bytes)[3]<<24)+(((uint8*)bytes)[2]<<16)+
++ (((uint8*)bytes)[1]<<8)+((uint8*)bytes)[0];
++}
++
++/*
++* load 16-bit value from unaligned big(network) endian byte array.
++*/
++static INLINE uint16
++ntoh16_ua(void *bytes)
++{
++ return (((uint8*)bytes)[0]<<8)+((uint8*)bytes)[1];
++}
++
++/*
++* load 32-bit value from unaligned big(network) endian byte array.
++*/
++static INLINE uint32
++ntoh32_ua(void *bytes)
++{
++ return (((uint8*)bytes)[0]<<24)+(((uint8*)bytes)[1]<<16)+
++ (((uint8*)bytes)[2]<<8)+((uint8*)bytes)[3];
++}
++
++#define ltoh_ua(ptr) (\
++ sizeof(*(ptr)) == sizeof(uint8) ? *(uint8 *)ptr : \
++ sizeof(*(ptr)) == sizeof(uint16) ? (((uint8 *)ptr)[1]<<8)+((uint8 *)ptr)[0] : \
++ (((uint8 *)ptr)[3]<<24)+(((uint8 *)ptr)[2]<<16)+(((uint8 *)ptr)[1]<<8)+((uint8 *)ptr)[0] \
++)
++
++#define ntoh_ua(ptr) (\
++ sizeof(*(ptr)) == sizeof(uint8) ? *(uint8 *)ptr : \
++ sizeof(*(ptr)) == sizeof(uint16) ? (((uint8 *)ptr)[0]<<8)+((uint8 *)ptr)[1] : \
++ (((uint8 *)ptr)[0]<<24)+(((uint8 *)ptr)[1]<<16)+(((uint8 *)ptr)[2]<<8)+((uint8 *)ptr)[3] \
++)
++
++#endif /* _BCMENDIAN_H_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/bcmnvram.h linux.dev/arch/mips/bcm947xx/include/bcmnvram.h
+--- linux.old/arch/mips/bcm947xx/include/bcmnvram.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/bcmnvram.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,159 @@
++/*
++ * NVRAM variable manipulation
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: bcmnvram.h,v 1.17 2006/03/02 12:33:44 honor Exp $
++ */
++
++#ifndef _bcmnvram_h_
++#define _bcmnvram_h_
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++#include <typedefs.h>
++#include <bcmdefs.h>
++
++struct nvram_header {
++ uint32 magic;
++ uint32 len;
++ uint32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
++ uint32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */
++ uint32 config_ncdl; /* ncdl values for memc */
++};
++
++struct nvram_tuple {
++ char *name;
++ char *value;
++ struct nvram_tuple *next;
++};
++
++/*
++ * Initialize NVRAM access. May be unnecessary or undefined on certain
++ * platforms.
++ */
++extern int nvram_init(void *sbh);
++
++/*
++ * Disable NVRAM access. May be unnecessary or undefined on certain
++ * platforms.
++ */
++extern void nvram_exit(void *sbh);
++
++/*
++ * Get the value of an NVRAM variable. The pointer returned may be
++ * invalid after a set.
++ * @param name name of variable to get
++ * @return value of variable or NULL if undefined
++ */
++extern char * nvram_get(const char *name);
++
++/*
++ * Read the reset GPIO value from the nvram and set the GPIO
++ * as input
++ */
++extern int BCMINITFN(nvram_resetgpio_init)(void *sbh);
++extern int BCMINITFN(nvram_gpio_init)(const char *name, void *sbh);
++extern int BCMINITFN(nvram_gpio_set)(const char *name, void *sbh, int type);
++
++/*
++ * Get the value of an NVRAM variable.
++ * @param name name of variable to get
++ * @return value of variable or NUL if undefined
++ */
++#define nvram_safe_get(name) (nvram_get(name) ? : "")
++
++#define nvram_safe_unset(name) ({ \
++ if(nvram_get(name)) \
++ nvram_unset(name); \
++})
++
++#define nvram_safe_set(name, value) ({ \
++ if(!nvram_get(name) || strcmp(nvram_get(name), value)) \
++ nvram_set(name, value); \
++})
++
++/*
++ * Match an NVRAM variable.
++ * @param name name of variable to match
++ * @param match value to compare against value of variable
++ * @return TRUE if variable is defined and its value is string equal
++ * to match or FALSE otherwise
++ */
++static INLINE int
++nvram_match(char *name, char *match) {
++ const char *value = nvram_get(name);
++ return (value && !strcmp(value, match));
++}
++
++/*
++ * Inversely match an NVRAM variable.
++ * @param name name of variable to match
++ * @param match value to compare against value of variable
++ * @return TRUE if variable is defined and its value is not string
++ * equal to invmatch or FALSE otherwise
++ */
++static INLINE int
++nvram_invmatch(char *name, char *invmatch) {
++ const char *value = nvram_get(name);
++ return (value && strcmp(value, invmatch));
++}
++
++/*
++ * Set the value of an NVRAM variable. The name and value strings are
++ * copied into private storage. Pointers to previously set values
++ * may become invalid. The new value may be immediately
++ * retrieved but will not be permanently stored until a commit.
++ * @param name name of variable to set
++ * @param value value of variable
++ * @return 0 on success and errno on failure
++ */
++extern int nvram_set(const char *name, const char *value);
++
++/*
++ * Unset an NVRAM variable. Pointers to previously set values
++ * remain valid until a set.
++ * @param name name of variable to unset
++ * @return 0 on success and errno on failure
++ * NOTE: use nvram_commit to commit this change to flash.
++ */
++extern int nvram_unset(const char *name);
++
++/*
++ * Commit NVRAM variables to permanent storage. All pointers to values
++ * may be invalid after a commit.
++ * NVRAM values are undefined after a commit.
++ * @return 0 on success and errno on failure
++ */
++extern int nvram_commit(void);
++
++/*
++ * Get all NVRAM variables (format name=value\0 ... \0\0).
++ * @param buf buffer to store variables
++ * @param count size of buffer in bytes
++ * @return 0 on success and errno on failure
++ */
++extern int nvram_getall(char *buf, int count);
++
++extern int file2nvram(char *filename, char *varname);
++extern int nvram2file(char *varname, char *filename);
++
++#endif /* _LANGUAGE_ASSEMBLY */
++
++#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */
++#define NVRAM_CLEAR_MAGIC 0x0
++#define NVRAM_INVALID_MAGIC 0xFFFFFFFF
++#define NVRAM_VERSION 1
++#define NVRAM_HEADER_SIZE 20
++#define NVRAM_SPACE 0x8000
++
++#define NVRAM_MAX_VALUE_LEN 255
++#define NVRAM_MAX_PARAM_LEN 64
++
++#endif /* _bcmnvram_h_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/bcmsrom.h linux.dev/arch/mips/bcm947xx/include/bcmsrom.h
+--- linux.old/arch/mips/bcm947xx/include/bcmsrom.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/bcmsrom.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,108 @@
++/*
++ * Misc useful routines to access NIC local SROM/OTP .
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: bcmsrom.h,v 1.1.1.13 2006/04/15 01:29:08 michael Exp $
++ */
++
++#ifndef _bcmsrom_h_
++#define _bcmsrom_h_
++
++/* Maximum srom: 4 Kilobits == 512 bytes */
++#define SROM_MAX 512
++
++/* SROM Rev 4: Reallocate the software part of the srom to accomodate
++ * MIMO features. It assumes up to two PCIE functions and 440 bytes
++ * of useable srom i.e. the useable storage in chips with OTP that
++ * implements hardware redundancy.
++ */
++
++#define SROM4_WORDS 220
++
++#define SROM4_SIGN 32
++#define SROM4_SIGNATURE 0x5372
++
++#define SROM4_BREV 33
++
++#define SROM4_BFL0 34
++#define SROM4_BFL1 35
++#define SROM4_BFL2 36
++#define SROM4_BFL3 37
++
++#define SROM4_MACHI 38
++#define SROM4_MACMID 39
++#define SROM4_MACLO 40
++
++#define SROM4_CCODE 41
++#define SROM4_REGREV 42
++
++#define SROM4_LEDBH10 43
++#define SROM4_LEDBH32 44
++
++#define SROM4_LEDDC 45
++
++#define SROM4_AA 46
++#define SROM4_AA2G_MASK 0x00ff
++#define SROM4_AA2G_SHIFT 0
++#define SROM4_AA5G_MASK 0xff00
++#define SROM4_AA5G_SHIFT 8
++
++#define SROM4_AG10 47
++#define SROM4_AG32 48
++
++#define SROM4_TXPID2G 49
++#define SROM4_TXPID5G 51
++#define SROM4_TXPID5GL 53
++#define SROM4_TXPID5GH 55
++
++/* Per-path fields */
++#define MAX_PATH 4
++#define SROM4_PATH0 64
++#define SROM4_PATH1 87
++#define SROM4_PATH2 110
++#define SROM4_PATH3 133
++
++#define SROM4_2G_ITT_MAXP 0
++#define SROM4_2G_PA 1
++#define SROM4_5G_ITT_MAXP 5
++#define SROM4_5GLH_MAXP 6
++#define SROM4_5G_PA 7
++#define SROM4_5GL_PA 11
++#define SROM4_5GH_PA 15
++
++/* Fields in the ITT_MAXP and 5GLH_MAXP words */
++#define B2G_MAXP_MASK 0xff
++#define B2G_ITT_SHIFT 8
++#define B5G_MAXP_MASK 0xff
++#define B5G_ITT_SHIFT 8
++#define B5GH_MAXP_MASK 0xff
++#define B5GL_MAXP_SHIFT 8
++
++/* All the miriad power offsets */
++#define SROM4_2G_CCKPO 156
++#define SROM4_2G_OFDMPO 157
++#define SROM4_5G_OFDMPO 159
++#define SROM4_5GL_OFDMPO 161
++#define SROM4_5GH_OFDMPO 163
++#define SROM4_2G_MCSPO 165
++#define SROM4_5G_MCSPO 173
++#define SROM4_5GL_MCSPO 181
++#define SROM4_5GH_MCSPO 189
++#define SROM4_CCDPO 197
++#define SROM4_STBCPO 198
++#define SROM4_BW40PO 199
++#define SROM4_BWDUPPO 200
++
++extern int srom_var_init(void *sbh, uint bus, void *curmap, osl_t *osh, char **vars, uint *count);
++
++extern int srom_read(uint bus, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf);
++extern int srom_write(uint bus, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf);
++
++#endif /* _bcmsrom_h_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/bcmutils.h linux.dev/arch/mips/bcm947xx/include/bcmutils.h
+--- linux.old/arch/mips/bcm947xx/include/bcmutils.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/bcmutils.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,433 @@
++/*
++ * Misc useful os-independent macros and functions.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id: bcmutils.h,v 1.1.1.16 2006/04/08 06:13:39 honor Exp $
++ */
++
++#ifndef _bcmutils_h_
++#define _bcmutils_h_
++
++/* ** driver-only section ** */
++#ifdef BCMDRIVER
++
++#define _BCM_U 0x01 /* upper */
++#define _BCM_L 0x02 /* lower */
++#define _BCM_D 0x04 /* digit */
++#define _BCM_C 0x08 /* cntrl */
++#define _BCM_P 0x10 /* punct */
++#define _BCM_S 0x20 /* white space (space/lf/tab) */
++#define _BCM_X 0x40 /* hex digit */
++#define _BCM_SP 0x80 /* hard space (0x20) */
++
++#define GPIO_PIN_NOTDEFINED 0x20 /* Pin not defined */
++
++extern unsigned char bcm_ctype[];
++#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)])
++
++#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0)
++#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0)
++#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0)
++#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0)
++#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0)
++#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0)
++#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0)
++#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0)
++#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0)
++#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0)
++#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0)
++
++/*
++ * Spin at most 'us' microseconds while 'exp' is true.
++ * Caller should explicitly test 'exp' when this completes
++ * and take appropriate error action if 'exp' is still true.
++ */
++#define SPINWAIT(exp, us) { \
++ uint countdown = (us) + 9; \
++ while ((exp) && (countdown >= 10)) {\
++ OSL_DELAY(10); \
++ countdown -= 10; \
++ } \
++}
++
++struct ether_addr {
++ uint8 octet[6];
++} __attribute__((packed));
++
++/* string */
++extern uchar bcm_toupper(uchar c);
++extern ulong bcm_strtoul(char *cp, char **endp, uint base);
++extern char *bcmstrstr(char *haystack, char *needle);
++extern char *bcmstrcat(char *dest, const char *src);
++extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen);
++/* ethernet address */
++extern char *bcm_ether_ntoa(struct ether_addr *ea, char *buf);
++/* variable access */
++extern char *getvar(char *vars, char *name);
++extern int getintvar(char *vars, char *name);
++extern uint getgpiopin(char *vars, char *pin_name, uint def_pin);
++#ifdef BCMPERFSTATS
++extern void bcm_perf_enable(void);
++extern void bcmstats(char *fmt);
++extern void bcmlog(char *fmt, uint a1, uint a2);
++extern void bcmdumplog(char *buf, int size);
++extern int bcmdumplogent(char *buf, uint idx);
++#else
++#define bcm_perf_enable()
++#define bcmstats(fmt)
++#define bcmlog(fmt, a1, a2)
++#define bcmdumplog(buf, size) *buf = '\0'
++#define bcmdumplogent(buf, idx) -1
++#endif /* BCMPERFSTATS */
++extern char *bcm_nvram_vars(uint *length);
++extern int bcm_nvram_cache(void *sbh);
++
++/* Support for sharing code across in-driver iovar implementations.
++ * The intent is that a driver use this structure to map iovar names
++ * to its (private) iovar identifiers, and the lookup function to
++ * find the entry. Macros are provided to map ids and get/set actions
++ * into a single number space for a switch statement.
++ */
++
++/* iovar structure */
++typedef struct bcm_iovar {
++ const char *name; /* name for lookup and display */
++ uint16 varid; /* id for switch */
++ uint16 flags; /* driver-specific flag bits */
++ uint16 type; /* base type of argument */
++ uint16 minlen; /* min length for buffer vars */
++} bcm_iovar_t;
++
++/* varid definitions are per-driver, may use these get/set bits */
++
++/* IOVar action bits for id mapping */
++#define IOV_GET 0 /* Get an iovar */
++#define IOV_SET 1 /* Set an iovar */
++
++/* Varid to actionid mapping */
++#define IOV_GVAL(id) ((id)*2)
++#define IOV_SVAL(id) (((id)*2)+IOV_SET)
++#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET)
++
++/* flags are per-driver based on driver attributes */
++
++/* Base type definitions */
++#define IOVT_VOID 0 /* no value (implictly set only) */
++#define IOVT_BOOL 1 /* any value ok (zero/nonzero) */
++#define IOVT_INT8 2 /* integer values are range-checked */
++#define IOVT_UINT8 3 /* unsigned int 8 bits */
++#define IOVT_INT16 4 /* int 16 bits */
++#define IOVT_UINT16 5 /* unsigned int 16 bits */
++#define IOVT_INT32 6 /* int 32 bits */
++#define IOVT_UINT32 7 /* unsigned int 32 bits */
++#define IOVT_BUFFER 8 /* buffer is size-checked as per minlen */
++
++extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name);
++extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set);
++
++#endif /* #ifdef BCMDRIVER */
++
++/* ** driver/apps-shared section ** */
++
++#define BCME_STRLEN 64 /* Max string length for BCM errors */
++#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST))
++
++
++/*
++ * error codes could be added but the defined ones shouldn't be changed/deleted
++ * these error codes are exposed to the user code
++ * when ever a new error code is added to this list
++ * please update errorstring table with the related error string and
++ * update osl files with os specific errorcode map
++*/
++
++#define BCME_OK 0 /* Success */
++#define BCME_ERROR -1 /* Error generic */
++#define BCME_BADARG -2 /* Bad Argument */
++#define BCME_BADOPTION -3 /* Bad option */
++#define BCME_NOTUP -4 /* Not up */
++#define BCME_NOTDOWN -5 /* Not down */
++#define BCME_NOTAP -6 /* Not AP */
++#define BCME_NOTSTA -7 /* Not STA */
++#define BCME_BADKEYIDX -8 /* BAD Key Index */
++#define BCME_RADIOOFF -9 /* Radio Off */
++#define BCME_NOTBANDLOCKED -10 /* Not band locked */
++#define BCME_NOCLK -11 /* No Clock */
++#define BCME_BADRATESET -12 /* BAD Rate valueset */
++#define BCME_BADBAND -13 /* BAD Band */
++#define BCME_BUFTOOSHORT -14 /* Buffer too short */
++#define BCME_BUFTOOLONG -15 /* Buffer too long */
++#define BCME_BUSY -16 /* Busy */
++#define BCME_NOTASSOCIATED -17 /* Not Associated */
++#define BCME_BADSSIDLEN -18 /* Bad SSID len */
++#define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel */
++#define BCME_BADCHAN -20 /* Bad Channel */
++#define BCME_BADADDR -21 /* Bad Address */
++#define BCME_NORESOURCE -22 /* Not Enough Resources */
++#define BCME_UNSUPPORTED -23 /* Unsupported */
++#define BCME_BADLEN -24 /* Bad length */
++#define BCME_NOTREADY -25 /* Not Ready */
++#define BCME_EPERM -26 /* Not Permitted */
++#define BCME_NOMEM -27 /* No Memory */
++#define BCME_ASSOCIATED -28 /* Associated */
++#define BCME_RANGE -29 /* Not In Range */
++#define BCME_NOTFOUND -30 /* Not Found */
++#define BCME_WME_NOT_ENABLED -31 /* WME Not Enabled */
++#define BCME_TSPEC_NOTFOUND -32 /* TSPEC Not Found */
++#define BCME_ACM_NOTSUPPORTED -33 /* ACM Not Supported */
++#define BCME_NOT_WME_ASSOCIATION -34 /* Not WME Association */
++#define BCME_SDIO_ERROR -35 /* SDIO Bus Error */
++#define BCME_DONGLE_DOWN -36 /* Dongle Not Accessible */
++#define BCME_LAST BCME_DONGLE_DOWN
++
++/* These are collection of BCME Error strings */
++#define BCMERRSTRINGTABLE { \
++ "OK", \
++ "Undefined error", \
++ "Bad Argument", \
++ "Bad Option", \
++ "Not up", \
++ "Not down", \
++ "Not AP", \
++ "Not STA", \
++ "Bad Key Index", \
++ "Radio Off", \
++ "Not band locked", \
++ "No clock", \
++ "Bad Rate valueset", \
++ "Bad Band", \
++ "Buffer too short", \
++ "Buffer too long", \
++ "Busy", \
++ "Not Associated", \
++ "Bad SSID len", \
++ "Out of Range Channel", \
++ "Bad Channel", \
++ "Bad Address", \
++ "Not Enough Resources", \
++ "Unsupported", \
++ "Bad length", \
++ "Not Ready", \
++ "Not Permitted", \
++ "No Memory", \
++ "Associated", \
++ "Not In Range", \
++ "Not Found", \
++ "WME Not Enabled", \
++ "TSPEC Not Found", \
++ "ACM Not Supported", \
++ "Not WME Association", \
++ "SDIO Bus Error", \
++ "Dongle Not Accessible" \
++}
++
++#ifndef ABS
++#define ABS(a) (((a) < 0)?-(a):(a))
++#endif /* ABS */
++
++#ifndef MIN
++#define MIN(a, b) (((a) < (b))?(a):(b))
++#endif /* MIN */
++
++#ifndef MAX
++#define MAX(a, b) (((a) > (b))?(a):(b))
++#endif /* MAX */
++
++#define CEIL(x, y) (((x) + ((y)-1)) / (y))
++#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
++#define ISALIGNED(a, x) (((a) & ((x)-1)) == 0)
++#define ISPOWEROF2(x) ((((x)-1)&(x)) == 0)
++#define VALID_MASK(mask) !((mask) & ((mask) + 1))
++#define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member)
++#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
++
++/* bit map related macros */
++#ifndef setbit
++#ifndef NBBY /* the BSD family defines NBBY */
++#define NBBY 8 /* 8 bits per byte */
++#endif /* #ifndef NBBY */
++#define setbit(a, i) (((uint8 *)a)[(i)/NBBY] |= 1<<((i)%NBBY))
++#define clrbit(a, i) (((uint8 *)a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
++#define isset(a, i) (((uint8 *)a)[(i)/NBBY] & (1<<((i)%NBBY)))
++#define isclr(a, i) ((((uint8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
++#endif /* setbit */
++
++#define NBITS(type) (sizeof(type) * 8)
++#define NBITVAL(nbits) (1 << (nbits))
++#define MAXBITVAL(nbits) ((1 << (nbits)) - 1)
++#define NBITMASK(nbits) MAXBITVAL(nbits)
++#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8)
++
++/* basic mux operation - can be optimized on several architectures */
++#define MUX(pred, true, false) ((pred) ? (true) : (false))
++
++/* modulo inc/dec - assumes x E [0, bound - 1] */
++#define MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 1)
++#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1)
++
++/* modulo inc/dec, bound = 2^k */
++#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1))
++#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1))
++
++/* modulo add/sub - assumes x, y E [0, bound - 1] */
++#define MODADD(x, y, bound) \
++ MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y))
++#define MODSUB(x, y, bound) \
++ MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y))
++
++/* module add/sub, bound = 2^k */
++#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1))
++#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1))
++
++/* crc defines */
++#define CRC8_INIT_VALUE 0xff /* Initial CRC8 checksum value */
++#define CRC8_GOOD_VALUE 0x9f /* Good final CRC8 checksum value */
++#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */
++#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */
++#define CRC32_INIT_VALUE 0xffffffff /* Initial CRC32 checksum value */
++#define CRC32_GOOD_VALUE 0xdebb20e3 /* Good final CRC32 checksum value */
++
++/* bcm_format_flags() bit description structure */
++typedef struct bcm_bit_desc {
++ uint32 bit;
++ char* name;
++} bcm_bit_desc_t;
++
++/* tag_ID/length/value_buffer tuple */
++typedef struct bcm_tlv {
++ uint8 id;
++ uint8 len;
++ uint8 data[1];
++} bcm_tlv_t;
++
++/* Check that bcm_tlv_t fits into the given buflen */
++#define bcm_valid_tlv(elt, buflen) ((buflen) >= 2 && (int)(buflen) >= (int)(2 + (elt)->len))
++
++/* buffer length for ethernet address from bcm_ether_ntoa() */
++#define ETHER_ADDR_STR_LEN 18 /* 18-bytes of Ethernet address buffer length */
++
++/* unaligned load and store macros */
++#ifdef IL_BIGENDIAN
++static INLINE uint32
++load32_ua(uint8 *a)
++{
++ return ((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]);
++}
++
++static INLINE void
++store32_ua(uint8 *a, uint32 v)
++{
++ a[0] = (v >> 24) & 0xff;
++ a[1] = (v >> 16) & 0xff;
++ a[2] = (v >> 8) & 0xff;
++ a[3] = v & 0xff;
++}
++
++static INLINE uint16
++load16_ua(uint8 *a)
++{
++ return ((a[0] << 8) | a[1]);
++}
++
++static INLINE void
++store16_ua(uint8 *a, uint16 v)
++{
++ a[0] = (v >> 8) & 0xff;
++ a[1] = v & 0xff;
++}
++
++#else
++
++static INLINE uint32
++load32_ua(uint8 *a)
++{
++ return ((a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]);
++}
++
++static INLINE void
++store32_ua(uint8 *a, uint32 v)
++{
++ a[3] = (v >> 24) & 0xff;
++ a[2] = (v >> 16) & 0xff;
++ a[1] = (v >> 8) & 0xff;
++ a[0] = v & 0xff;
++}
++
++static INLINE uint16
++load16_ua(uint8 *a)
++{
++ return ((a[1] << 8) | a[0]);
++}
++
++static INLINE void
++store16_ua(uint8 *a, uint16 v)
++{
++ a[1] = (v >> 8) & 0xff;
++ a[0] = v & 0xff;
++}
++
++#endif /* IL_BIGENDIAN */
++
++/* externs */
++/* crc */
++extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc);
++extern uint16 hndcrc16(uint8 *p, uint nbytes, uint16 crc);
++extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc);
++/* format/print */
++extern void printfbig(char *buf);
++
++/* IE parsing */
++extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen);
++extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key);
++extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key);
++
++/* bcmerror */
++extern const char *bcmerrorstr(int bcmerror);
++
++/* multi-bool data type: set of bools, mbool is true if any is set */
++typedef uint32 mbool;
++#define mboolset(mb, bit) (mb |= bit) /* set one bool */
++#define mboolclr(mb, bit) (mb &= ~bit) /* clear one bool */
++#define mboolisset(mb, bit) ((mb & bit) != 0) /* TRUE if one bool is set */
++#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val)))
++
++/* power conversion */
++extern uint16 bcm_qdbm_to_mw(uint8 qdbm);
++extern uint8 bcm_mw_to_qdbm(uint16 mw);
++
++/* generic datastruct to help dump routines */
++struct fielddesc {
++ char *nameandfmt;
++ uint32 offset;
++ uint32 len;
++};
++
++/* Buffer structure for collecting string-formatted data
++* using bcm_bprintf() API.
++* Use bcm_binit() to initialize before use
++*/
++struct bcmstrbuf
++{
++ char *buf; /* pointer to current position in origbuf */
++ uint size; /* current (residual) size in bytes */
++ char *origbuf; /* unmodified pointer to orignal buffer */
++ uint origsize; /* unmodified orignal buffer size in bytes */
++};
++
++extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size);
++extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...);
++
++typedef uint32 (*readreg_rtn)(void *arg0, void *arg1, uint32 offset);
++extern uint bcmdumpfields(readreg_rtn func_ptr, void *arg0, void *arg1, struct fielddesc *str,
++ char *buf, uint32 bufsize);
++
++extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len);
++extern uint bcm_bitcount(uint8 *bitmap, uint bytelength);
++
++#endif /* _bcmutils_h_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/hndcpu.h linux.dev/arch/mips/bcm947xx/include/hndcpu.h
+--- linux.old/arch/mips/bcm947xx/include/hndcpu.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/hndcpu.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,28 @@
++/*
++ * HND SiliconBackplane MIPS/ARM cores software interface.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: hndcpu.h,v 1.1.1.1 2006/02/27 03:43:16 honor Exp $
++ */
++
++#ifndef _hndcpu_h_
++#define _hndcpu_h_
++
++#if defined(mips)
++#include <hndmips.h>
++#elif defined(__ARM_ARCH_4T__)
++#include <hndarm.h>
++#endif
++
++extern uint sb_irq(sb_t *sbh);
++extern uint32 sb_cpu_clock(sb_t *sbh);
++extern void sb_cpu_wait(void);
++
++#endif /* _hndcpu_h_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/hndmips.h linux.dev/arch/mips/bcm947xx/include/hndmips.h
+--- linux.old/arch/mips/bcm947xx/include/hndmips.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/hndmips.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,45 @@
++/*
++ * HND SiliconBackplane MIPS core software interface.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: hndmips.h,v 1.1.1.8 2006/02/27 03:43:16 honor Exp $
++ */
++
++#ifndef _hndmips_h_
++#define _hndmips_h_
++
++extern void sb_mips_init(sb_t *sbh, uint shirq_map_base);
++extern bool sb_mips_setclock(sb_t *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock);
++extern void enable_pfc(uint32 mode);
++extern uint32 sb_memc_get_ncdl(sb_t *sbh);
++
++#if defined(BCMPERFSTATS)
++/* enable counting - exclusive version. Only one set of counters allowed at a time */
++extern void hndmips_perf_instrcount_enable(void);
++extern void hndmips_perf_icachecount_enable(void);
++extern void hndmips_perf_dcachecount_enable(void);
++/* start and stop counting */
++#define hndmips_perf_start01() \
++ MTC0(C0_PERFORMANCE, 4, MFC0(C0_PERFORMANCE, 4) | 0x80008000)
++#define hndmips_perf_stop01() \
++ MTC0(C0_PERFORMANCE, 4, MFC0(C0_PERFORMANCE, 4) & ~0x80008000)
++/* retrieve coutners - counters *decrement* */
++#define hndmips_perf_read0() -(long)(MFC0(C0_PERFORMANCE, 0))
++#define hndmips_perf_read1() -(long)(MFC0(C0_PERFORMANCE, 1))
++#define hndmips_perf_read2() -(long)(MFC0(C0_PERFORMANCE, 2))
++/* enable counting - modular version. Each counters can be enabled separately. */
++extern void hndmips_perf_icache_hit_enable(void);
++extern void hndmips_perf_icache_miss_enable(void);
++extern uint32 hndmips_perf_read_instrcount(void);
++extern uint32 hndmips_perf_read_cache_miss(void);
++extern uint32 hndmips_perf_read_cache_hit(void);
++#endif /* defined(BCMINTERNAL) || defined (BCMPERFSTATS) */
++
++#endif /* _hndmips_h_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/hndpci.h linux.dev/arch/mips/bcm947xx/include/hndpci.h
+--- linux.old/arch/mips/bcm947xx/include/hndpci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/hndpci.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,30 @@
++/*
++ * HND SiliconBackplane PCI core software interface.
++ *
++ * $Id: hndpci.h,v 1.1.1.1 2006/02/27 03:43:16 honor Exp $
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ */
++
++#ifndef _hndpci_h_
++#define _hndpci_h_
++
++extern int sbpci_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf,
++ int len);
++extern int extpci_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf,
++ int len);
++extern int sbpci_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf,
++ int len);
++extern int extpci_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf,
++ int len);
++extern void sbpci_ban(uint16 core);
++extern int sbpci_init(sb_t *sbh);
++extern int sbpci_init_pci(sb_t *sbh);
++extern void sbpci_check(sb_t *sbh);
++
++#endif /* _hndpci_h_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/linuxver.h linux.dev/arch/mips/bcm947xx/include/linuxver.h
+--- linux.old/arch/mips/bcm947xx/include/linuxver.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/linuxver.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,417 @@
++/*
++ * Linux-specific abstractions to gain some independence from linux kernel versions.
++ * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: linuxver.h,v 1.1.1.10 2006/02/27 03:43:16 honor Exp $
++ */
++
++#ifndef _linuxver_h_
++#define _linuxver_h_
++
++#include <linux/config.h>
++#include <linux/version.h>
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0))
++/* __NO_VERSION__ must be defined for all linkables except one in 2.2 */
++#ifdef __UNDEF_NO_VERSION__
++#undef __NO_VERSION__
++#else
++#define __NO_VERSION__
++#endif
++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) */
++
++#if defined(MODULE) && defined(MODVERSIONS)
++#include <linux/modversions.h>
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
++#include <linux/moduleparam.h>
++#endif
++
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
++#define module_param(_name_, _type_, _perm_) MODULE_PARM(_name_, "i")
++#define module_param_string(_name_, _string_, _size_, _perm_) \
++ MODULE_PARM(_string_, "c" __MODULE_STRING(_size_))
++#endif
++
++/* linux/malloc.h is deprecated, use linux/slab.h instead. */
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9))
++#include <linux/malloc.h>
++#else
++#include <linux/slab.h>
++#endif
++
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/string.h>
++#include <linux/pci.h>
++#include <linux/interrupt.h>
++#include <linux/netdevice.h>
++#include <asm/io.h>
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41))
++#include <linux/workqueue.h>
++#else
++#include <linux/tqueue.h>
++#ifndef work_struct
++#define work_struct tq_struct
++#endif
++#ifndef INIT_WORK
++#define INIT_WORK(_work, _func, _data) INIT_TQUEUE((_work), (_func), (_data))
++#endif
++#ifndef schedule_work
++#define schedule_work(_work) schedule_task((_work))
++#endif
++#ifndef flush_scheduled_work
++#define flush_scheduled_work() flush_scheduled_tasks()
++#endif
++#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41) */
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
++/* Some distributions have their own 2.6.x compatibility layers */
++#ifndef IRQ_NONE
++typedef void irqreturn_t;
++#define IRQ_NONE
++#define IRQ_HANDLED
++#define IRQ_RETVAL(x)
++#endif
++#else
++typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs);
++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) */
++
++#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/cistpl.h>
++#include <pcmcia/cisreg.h>
++#include <pcmcia/ds.h>
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 69))
++/* In 2.5 (as of 2.5.69 at least) there is a cs_error exported which
++ * does this, but it's not in 2.4 so we do our own for now.
++ */
++static inline void
++cs_error(client_handle_t handle, int func, int ret)
++{
++ error_info_t err = { func, ret };
++ CardServices(ReportError, handle, &err);
++}
++#endif
++
++#endif /* CONFIG_PCMCIA */
++
++#ifndef __exit
++#define __exit
++#endif
++#ifndef __devexit
++#define __devexit
++#endif
++#ifndef __devinit
++#define __devinit __init
++#endif
++#ifndef __devinitdata
++#define __devinitdata
++#endif
++#ifndef __devexit_p
++#define __devexit_p(x) x
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0))
++
++#define pci_get_drvdata(dev) (dev)->sysdata
++#define pci_set_drvdata(dev, value) (dev)->sysdata = (value)
++
++/*
++ * New-style (2.4.x) PCI/hot-pluggable PCI/CardBus registration
++ */
++
++struct pci_device_id {
++ unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */
++ unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
++ unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */
++ unsigned long driver_data; /* Data private to the driver */
++};
++
++struct pci_driver {
++ struct list_head node;
++ char *name;
++ const struct pci_device_id *id_table; /* NULL if wants all devices */
++ int (*probe)(struct pci_dev *dev,
++ const struct pci_device_id *id); /* New device inserted */
++ void (*remove)(struct pci_dev *dev); /* Device removed (NULL if not a hot-plug
++ * capable driver)
++ */
++ void (*suspend)(struct pci_dev *dev); /* Device suspended */
++ void (*resume)(struct pci_dev *dev); /* Device woken up */
++};
++
++#define MODULE_DEVICE_TABLE(type, name)
++#define PCI_ANY_ID (~0)
++
++/* compatpci.c */
++#define pci_module_init pci_register_driver
++extern int pci_register_driver(struct pci_driver *drv);
++extern void pci_unregister_driver(struct pci_driver *drv);
++
++#endif /* PCI registration */
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18))
++#ifdef MODULE
++#define module_init(x) int init_module(void) { return x(); }
++#define module_exit(x) void cleanup_module(void) { x(); }
++#else
++#define module_init(x) __initcall(x);
++#define module_exit(x) __exitcall(x);
++#endif
++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18) */
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 48))
++#define list_for_each(pos, head) \
++ for (pos = (head)->next; pos != (head); pos = pos->next)
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 13))
++#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)])
++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 44))
++#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start)
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 23))
++#define pci_enable_device(dev) do { } while (0)
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14))
++#define net_device device
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 42))
++
++/*
++ * DMA mapping
++ *
++ * See linux/Documentation/DMA-mapping.txt
++ */
++
++#ifndef PCI_DMA_TODEVICE
++#define PCI_DMA_TODEVICE 1
++#define PCI_DMA_FROMDEVICE 2
++#endif
++
++typedef u32 dma_addr_t;
++
++/* Pure 2^n version of get_order */
++static inline int get_order(unsigned long size)
++{
++ int order;
++
++ size = (size-1) >> (PAGE_SHIFT-1);
++ order = -1;
++ do {
++ size >>= 1;
++ order++;
++ } while (size);
++ return order;
++}
++
++static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
++ dma_addr_t *dma_handle)
++{
++ void *ret;
++ int gfp = GFP_ATOMIC | GFP_DMA;
++
++ ret = (void *)__get_free_pages(gfp, get_order(size));
++
++ if (ret != NULL) {
++ memset(ret, 0, size);
++ *dma_handle = virt_to_bus(ret);
++ }
++ return ret;
++}
++static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size,
++ void *vaddr, dma_addr_t dma_handle)
++{
++ free_pages((unsigned long)vaddr, get_order(size));
++}
++#ifdef ILSIM
++extern uint pci_map_single(void *dev, void *va, uint size, int direction);
++extern void pci_unmap_single(void *dev, uint pa, uint size, int direction);
++#else
++#define pci_map_single(cookie, address, size, dir) virt_to_bus(address)
++#define pci_unmap_single(cookie, address, size, dir)
++#endif
++
++#endif /* DMA mapping */
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43))
++
++#define dev_kfree_skb_any(a) dev_kfree_skb(a)
++#define netif_down(dev) do { (dev)->start = 0; } while (0)
++
++/* pcmcia-cs provides its own netdevice compatibility layer */
++#ifndef _COMPAT_NETDEVICE_H
++
++/*
++ * SoftNet
++ *
++ * For pre-softnet kernels we need to tell the upper layer not to
++ * re-enter start_xmit() while we are in there. However softnet
++ * guarantees not to enter while we are in there so there is no need
++ * to do the netif_stop_queue() dance unless the transmit queue really
++ * gets stuck. This should also improve performance according to tests
++ * done by Aman Singla.
++ */
++
++#define dev_kfree_skb_irq(a) dev_kfree_skb(a)
++#define netif_wake_queue(dev) \
++ do { clear_bit(0, &(dev)->tbusy); mark_bh(NET_BH); } while (0)
++#define netif_stop_queue(dev) set_bit(0, &(dev)->tbusy)
++
++static inline void netif_start_queue(struct net_device *dev)
++{
++ dev->tbusy = 0;
++ dev->interrupt = 0;
++ dev->start = 1;
++}
++
++#define netif_queue_stopped(dev) (dev)->tbusy
++#define netif_running(dev) (dev)->start
++
++#endif /* _COMPAT_NETDEVICE_H */
++
++#define netif_device_attach(dev) netif_start_queue(dev)
++#define netif_device_detach(dev) netif_stop_queue(dev)
++
++/* 2.4.x renamed bottom halves to tasklets */
++#define tasklet_struct tq_struct
++static inline void tasklet_schedule(struct tasklet_struct *tasklet)
++{
++ queue_task(tasklet, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++}
++
++static inline void tasklet_init(struct tasklet_struct *tasklet,
++ void (*func)(unsigned long),
++ unsigned long data)
++{
++ tasklet->next = NULL;
++ tasklet->sync = 0;
++ tasklet->routine = (void (*)(void *))func;
++ tasklet->data = (void *)data;
++}
++#define tasklet_kill(tasklet) { do{} while (0); }
++
++/* 2.4.x introduced del_timer_sync() */
++#define del_timer_sync(timer) del_timer(timer)
++
++#else
++
++#define netif_down(dev)
++
++#endif /* SoftNet */
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3))
++
++/*
++ * Emit code to initialise a tq_struct's routine and data pointers
++ */
++#define PREPARE_TQUEUE(_tq, _routine, _data) \
++ do { \
++ (_tq)->routine = _routine; \
++ (_tq)->data = _data; \
++ } while (0)
++
++/*
++ * Emit code to initialise all of a tq_struct
++ */
++#define INIT_TQUEUE(_tq, _routine, _data) \
++ do { \
++ INIT_LIST_HEAD(&(_tq)->list); \
++ (_tq)->sync = 0; \
++ PREPARE_TQUEUE((_tq), (_routine), (_data)); \
++ } while (0)
++
++#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3) */
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6))
++
++/* Power management related routines */
++
++static inline int
++pci_save_state(struct pci_dev *dev, u32 *buffer)
++{
++ int i;
++ if (buffer) {
++ for (i = 0; i < 16; i++)
++ pci_read_config_dword(dev, i * 4, &buffer[i]);
++ }
++ return 0;
++}
++
++static inline int
++pci_restore_state(struct pci_dev *dev, u32 *buffer)
++{
++ int i;
++
++ if (buffer) {
++ for (i = 0; i < 16; i++)
++ pci_write_config_dword(dev, i * 4, buffer[i]);
++ }
++ /*
++ * otherwise, write the context information we know from bootup.
++ * This works around a problem where warm-booting from Windows
++ * combined with a D3(hot)->D0 transition causes PCI config
++ * header data to be forgotten.
++ */
++ else {
++ for (i = 0; i < 6; i ++)
++ pci_write_config_dword(dev,
++ PCI_BASE_ADDRESS_0 + (i * 4),
++ pci_resource_start(dev, i));
++ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
++ }
++ return 0;
++}
++
++#endif /* PCI power management */
++
++/* Old cp0 access macros deprecated in 2.4.19 */
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 19))
++#define read_c0_count() read_32bit_cp0_register(CP0_COUNT)
++#endif
++
++/* Module refcount handled internally in 2.6.x */
++#ifndef SET_MODULE_OWNER
++#define SET_MODULE_OWNER(dev) do {} while (0)
++#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
++#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
++#else
++#define OLD_MOD_INC_USE_COUNT do {} while (0)
++#define OLD_MOD_DEC_USE_COUNT do {} while (0)
++#endif
++
++#ifndef SET_NETDEV_DEV
++#define SET_NETDEV_DEV(net, pdev) do {} while (0)
++#endif
++
++#ifndef HAVE_FREE_NETDEV
++#define free_netdev(dev) kfree(dev)
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
++/* struct packet_type redefined in 2.6.x */
++#define af_packet_priv data
++#endif
++
++#endif /* _linuxver_h_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/mipsinc.h linux.dev/arch/mips/bcm947xx/include/mipsinc.h
+--- linux.old/arch/mips/bcm947xx/include/mipsinc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/mipsinc.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,541 @@
++/*
++ * HND Run Time Environment for standalone MIPS programs.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: mipsinc.h,v 1.1.1.5 2006/02/27 03:43:16 honor Exp $
++ */
++
++#ifndef _MISPINC_H
++#define _MISPINC_H
++
++
++/* MIPS defines */
++
++#ifdef _LANGUAGE_ASSEMBLY
++
++/*
++ * Symbolic register names for 32 bit ABI
++ */
++#define zero $0 /* wired zero */
++#define AT $1 /* assembler temp - uppercase because of ".set at" */
++#define v0 $2 /* return value */
++#define v1 $3
++#define a0 $4 /* argument registers */
++#define a1 $5
++#define a2 $6
++#define a3 $7
++#define t0 $8 /* caller saved */
++#define t1 $9
++#define t2 $10
++#define t3 $11
++#define t4 $12
++#define t5 $13
++#define t6 $14
++#define t7 $15
++#define s0 $16 /* callee saved */
++#define s1 $17
++#define s2 $18
++#define s3 $19
++#define s4 $20
++#define s5 $21
++#define s6 $22
++#define s7 $23
++#define t8 $24 /* caller saved */
++#define t9 $25
++#define jp $25 /* PIC jump register */
++#define k0 $26 /* kernel scratch */
++#define k1 $27
++#define gp $28 /* global pointer */
++#define sp $29 /* stack pointer */
++#define fp $30 /* frame pointer */
++#define s8 $30 /* same like fp! */
++#define ra $31 /* return address */
++
++
++/* CP0 Registers */
++
++#define C0_INX $0
++#define C0_RAND $1
++#define C0_TLBLO0 $2
++#define C0_TLBLO C0_TLBLO0
++#define C0_TLBLO1 $3
++#define C0_CTEXT $4
++#define C0_PGMASK $5
++#define C0_WIRED $6
++#define C0_BADVADDR $8
++#define C0_COUNT $9
++#define C0_TLBHI $10
++#define C0_COMPARE $11
++#define C0_SR $12
++#define C0_STATUS C0_SR
++#define C0_CAUSE $13
++#define C0_EPC $14
++#define C0_PRID $15
++#define C0_CONFIG $16
++#define C0_LLADDR $17
++#define C0_WATCHLO $18
++#define C0_WATCHHI $19
++#define C0_XCTEXT $20
++#define C0_DIAGNOSTIC $22
++#define C0_BROADCOM C0_DIAGNOSTIC
++#define C0_PERFORMANCE $25
++#define C0_ECC $26
++#define C0_CACHEERR $27
++#define C0_TAGLO $28
++#define C0_TAGHI $29
++#define C0_ERREPC $30
++#define C0_DESAVE $31
++
++/*
++ * LEAF - declare leaf routine
++ */
++#define LEAF(symbol) \
++ .globl symbol; \
++ .align 2; \
++ .type symbol, @function; \
++ .ent symbol, 0; \
++symbol: .frame sp, 0, ra
++
++/*
++ * END - mark end of function
++ */
++#define END(function) \
++ .end function; \
++ .size function, . - function
++
++#define _ULCAST_
++
++#define MFC0_SEL(dst, src, sel) \
++ .word\t(0x40000000 | ((dst) << 16) | ((src) << 11) | (sel))
++
++
++#define MTC0_SEL(dst, src, sel) \
++ .word\t(0x40800000 | ((dst) << 16) | ((src) << 11) | (sel))
++
++#else
++
++/*
++ * The following macros are especially useful for __asm__
++ * inline assembler.
++ */
++#ifndef __STR
++#define __STR(x) #x
++#endif
++#ifndef STR
++#define STR(x) __STR(x)
++#endif
++
++#define _ULCAST_ (unsigned long)
++
++
++/* CP0 Registers */
++
++#define C0_INX 0 /* CP0: TLB Index */
++#define C0_RAND 1 /* CP0: TLB Random */
++#define C0_TLBLO0 2 /* CP0: TLB EntryLo0 */
++#define C0_TLBLO C0_TLBLO0 /* CP0: TLB EntryLo0 */
++#define C0_TLBLO1 3 /* CP0: TLB EntryLo1 */
++#define C0_CTEXT 4 /* CP0: Context */
++#define C0_PGMASK 5 /* CP0: TLB PageMask */
++#define C0_WIRED 6 /* CP0: TLB Wired */
++#define C0_BADVADDR 8 /* CP0: Bad Virtual Address */
++#define C0_COUNT 9 /* CP0: Count */
++#define C0_TLBHI 10 /* CP0: TLB EntryHi */
++#define C0_COMPARE 11 /* CP0: Compare */
++#define C0_SR 12 /* CP0: Processor Status */
++#define C0_STATUS C0_SR /* CP0: Processor Status */
++#define C0_CAUSE 13 /* CP0: Exception Cause */
++#define C0_EPC 14 /* CP0: Exception PC */
++#define C0_PRID 15 /* CP0: Processor Revision Indentifier */
++#define C0_CONFIG 16 /* CP0: Config */
++#define C0_LLADDR 17 /* CP0: LLAddr */
++#define C0_WATCHLO 18 /* CP0: WatchpointLo */
++#define C0_WATCHHI 19 /* CP0: WatchpointHi */
++#define C0_XCTEXT 20 /* CP0: XContext */
++#define C0_DIAGNOSTIC 22 /* CP0: Diagnostic */
++#define C0_BROADCOM C0_DIAGNOSTIC /* CP0: Broadcom Register */
++#define C0_PERFORMANCE 25 /* CP0: Performance Counter/Control Registers */
++#define C0_ECC 26 /* CP0: ECC */
++#define C0_CACHEERR 27 /* CP0: CacheErr */
++#define C0_TAGLO 28 /* CP0: TagLo */
++#define C0_TAGHI 29 /* CP0: TagHi */
++#define C0_ERREPC 30 /* CP0: ErrorEPC */
++#define C0_DESAVE 31 /* CP0: DebugSave */
++
++#endif /* _LANGUAGE_ASSEMBLY */
++
++/*
++ * Memory segments (32bit kernel mode addresses)
++ */
++#undef KUSEG
++#undef KSEG0
++#undef KSEG1
++#undef KSEG2
++#undef KSEG3
++#define KUSEG 0x00000000
++#define KSEG0 0x80000000
++#define KSEG1 0xa0000000
++#define KSEG2 0xc0000000
++#define KSEG3 0xe0000000
++#define PHYSADDR_MASK 0x1fffffff
++
++/*
++ * Map an address to a certain kernel segment
++ */
++#undef PHYSADDR
++#undef KSEG0ADDR
++#undef KSEG1ADDR
++#undef KSEG2ADDR
++#undef KSEG3ADDR
++
++#define PHYSADDR(a) (_ULCAST_(a) & PHYSADDR_MASK)
++#define KSEG0ADDR(a) ((_ULCAST_(a) & PHYSADDR_MASK) | KSEG0)
++#define KSEG1ADDR(a) ((_ULCAST_(a) & PHYSADDR_MASK) | KSEG1)
++#define KSEG2ADDR(a) ((_ULCAST_(a) & PHYSADDR_MASK) | KSEG2)
++#define KSEG3ADDR(a) ((_ULCAST_(a) & PHYSADDR_MASK) | KSEG3)
++
++
++#ifndef Index_Invalidate_I
++/*
++ * Cache Operations
++ */
++#define Index_Invalidate_I 0x00
++#define Index_Writeback_Inv_D 0x01
++#define Index_Invalidate_SI 0x02
++#define Index_Writeback_Inv_SD 0x03
++#define Index_Load_Tag_I 0x04
++#define Index_Load_Tag_D 0x05
++#define Index_Load_Tag_SI 0x06
++#define Index_Load_Tag_SD 0x07
++#define Index_Store_Tag_I 0x08
++#define Index_Store_Tag_D 0x09
++#define Index_Store_Tag_SI 0x0A
++#define Index_Store_Tag_SD 0x0B
++#define Create_Dirty_Excl_D 0x0d
++#define Create_Dirty_Excl_SD 0x0f
++#define Hit_Invalidate_I 0x10
++#define Hit_Invalidate_D 0x11
++#define Hit_Invalidate_SI 0x12
++#define Hit_Invalidate_SD 0x13
++#define Fill_I 0x14
++#define Hit_Writeback_Inv_D 0x15
++ /* 0x16 is unused */
++#define Hit_Writeback_Inv_SD 0x17
++#define R5K_Page_Invalidate_S 0x17
++#define Hit_Writeback_I 0x18
++#define Hit_Writeback_D 0x19
++ /* 0x1a is unused */
++#define Hit_Writeback_SD 0x1b
++ /* 0x1c is unused */
++ /* 0x1e is unused */
++#define Hit_Set_Virtual_SI 0x1e
++#define Hit_Set_Virtual_SD 0x1f
++#endif /* !Index_Invalidate_I */
++
++
++/*
++ * R4x00 interrupt enable / cause bits
++ */
++#define IE_SW0 (_ULCAST_(1) << 8)
++#define IE_SW1 (_ULCAST_(1) << 9)
++#define IE_IRQ0 (_ULCAST_(1) << 10)
++#define IE_IRQ1 (_ULCAST_(1) << 11)
++#define IE_IRQ2 (_ULCAST_(1) << 12)
++#define IE_IRQ3 (_ULCAST_(1) << 13)
++#define IE_IRQ4 (_ULCAST_(1) << 14)
++#define IE_IRQ5 (_ULCAST_(1) << 15)
++
++#ifndef ST0_UM
++/*
++ * Bitfields in the mips32 cp0 status register
++ */
++#define ST0_IE 0x00000001
++#define ST0_EXL 0x00000002
++#define ST0_ERL 0x00000004
++#define ST0_UM 0x00000010
++#define ST0_SWINT0 0x00000100
++#define ST0_SWINT1 0x00000200
++#define ST0_HWINT0 0x00000400
++#define ST0_HWINT1 0x00000800
++#define ST0_HWINT2 0x00001000
++#define ST0_HWINT3 0x00002000
++#define ST0_HWINT4 0x00004000
++#define ST0_HWINT5 0x00008000
++#define ST0_IM 0x0000ff00
++#define ST0_NMI 0x00080000
++#define ST0_SR 0x00100000
++#define ST0_TS 0x00200000
++#define ST0_BEV 0x00400000
++#define ST0_RE 0x02000000
++#define ST0_RP 0x08000000
++#define ST0_CU 0xf0000000
++#define ST0_CU0 0x10000000
++#define ST0_CU1 0x20000000
++#define ST0_CU2 0x40000000
++#define ST0_CU3 0x80000000
++#endif /* !ST0_UM */
++
++
++/*
++ * Bitfields in the mips32 cp0 cause register
++ */
++#define C_EXC 0x0000007c
++#define C_EXC_SHIFT 2
++#define C_INT 0x0000ff00
++#define C_INT_SHIFT 8
++#define C_SW0 (_ULCAST_(1) << 8)
++#define C_SW1 (_ULCAST_(1) << 9)
++#define C_IRQ0 (_ULCAST_(1) << 10)
++#define C_IRQ1 (_ULCAST_(1) << 11)
++#define C_IRQ2 (_ULCAST_(1) << 12)
++#define C_IRQ3 (_ULCAST_(1) << 13)
++#define C_IRQ4 (_ULCAST_(1) << 14)
++#define C_IRQ5 (_ULCAST_(1) << 15)
++#define C_WP 0x00400000
++#define C_IV 0x00800000
++#define C_CE 0x30000000
++#define C_CE_SHIFT 28
++#define C_BD 0x80000000
++
++/* Values in C_EXC */
++#define EXC_INT 0
++#define EXC_TLBM 1
++#define EXC_TLBL 2
++#define EXC_TLBS 3
++#define EXC_AEL 4
++#define EXC_AES 5
++#define EXC_IBE 6
++#define EXC_DBE 7
++#define EXC_SYS 8
++#define EXC_BPT 9
++#define EXC_RI 10
++#define EXC_CU 11
++#define EXC_OV 12
++#define EXC_TR 13
++#define EXC_WATCH 23
++#define EXC_MCHK 24
++
++
++/*
++ * Bits in the cp0 config register.
++ */
++#define CONF_CM_CACHABLE_NO_WA 0
++#define CONF_CM_CACHABLE_WA 1
++#define CONF_CM_UNCACHED 2
++#define CONF_CM_CACHABLE_NONCOHERENT 3
++#define CONF_CM_CACHABLE_CE 4
++#define CONF_CM_CACHABLE_COW 5
++#define CONF_CM_CACHABLE_CUW 6
++#define CONF_CM_CACHABLE_ACCELERATED 7
++#define CONF_CM_CMASK 7
++#define CONF_CU (_ULCAST_(1) << 3)
++#define CONF_DB (_ULCAST_(1) << 4)
++#define CONF_IB (_ULCAST_(1) << 5)
++#define CONF_SE (_ULCAST_(1) << 12)
++#ifndef CONF_BE /* duplicate in mipsregs.h */
++#define CONF_BE (_ULCAST_(1) << 15)
++#endif
++#define CONF_SC (_ULCAST_(1) << 17)
++#define CONF_AC (_ULCAST_(1) << 23)
++#define CONF_HALT (_ULCAST_(1) << 25)
++#ifndef CONF_M /* duplicate in mipsregs.h */
++#define CONF_M (_ULCAST_(1) << 31)
++#endif
++
++
++/*
++ * Bits in the cp0 config register select 1.
++ */
++#define CONF1_FP 0x00000001 /* FPU present */
++#define CONF1_EP 0x00000002 /* EJTAG present */
++#define CONF1_CA 0x00000004 /* mips16 implemented */
++#define CONF1_WR 0x00000008 /* Watch registers present */
++#define CONF1_PC 0x00000010 /* Performance counters present */
++#define CONF1_DA_SHIFT 7 /* D$ associativity */
++#define CONF1_DA_MASK 0x00000380
++#define CONF1_DA_BASE 1
++#define CONF1_DL_SHIFT 10 /* D$ line size */
++#define CONF1_DL_MASK 0x00001c00
++#define CONF1_DL_BASE 2
++#define CONF1_DS_SHIFT 13 /* D$ sets/way */
++#define CONF1_DS_MASK 0x0000e000
++#define CONF1_DS_BASE 64
++#define CONF1_IA_SHIFT 16 /* I$ associativity */
++#define CONF1_IA_MASK 0x00070000
++#define CONF1_IA_BASE 1
++#define CONF1_IL_SHIFT 19 /* I$ line size */
++#define CONF1_IL_MASK 0x00380000
++#define CONF1_IL_BASE 2
++#define CONF1_IS_SHIFT 22 /* Instruction cache sets/way */
++#define CONF1_IS_MASK 0x01c00000
++#define CONF1_IS_BASE 64
++#define CONF1_MS_MASK 0x7e000000 /* Number of tlb entries */
++#define CONF1_MS_SHIFT 25
++
++/* PRID register */
++#define PRID_COPT_MASK 0xff000000
++#define PRID_COMP_MASK 0x00ff0000
++#define PRID_IMP_MASK 0x0000ff00
++#define PRID_REV_MASK 0x000000ff
++
++#define PRID_COMP_LEGACY 0x000000
++#define PRID_COMP_MIPS 0x010000
++#define PRID_COMP_BROADCOM 0x020000
++#define PRID_COMP_ALCHEMY 0x030000
++#define PRID_COMP_SIBYTE 0x040000
++#define PRID_IMP_BCM4710 0x4000
++#define PRID_IMP_BCM3302 0x9000
++#define PRID_IMP_BCM3303 0x9100
++
++#define PRID_IMP_UNKNOWN 0xff00
++
++#define BCM330X(id) \
++ (((id & (PRID_COMP_MASK | PRID_IMP_MASK)) == \
++ (PRID_COMP_BROADCOM | PRID_IMP_BCM3302)) || \
++ ((id & (PRID_COMP_MASK | PRID_IMP_MASK)) == \
++ (PRID_COMP_BROADCOM | PRID_IMP_BCM3303)))
++
++/* Bits in C0_BROADCOM */
++#define BRCM_PFC_AVAIL 0x20000000 /* PFC is available */
++#define BRCM_DC_ENABLE 0x40000000 /* Enable Data $ */
++#define BRCM_IC_ENABLE 0x80000000 /* Enable Instruction $ */
++#define BRCM_PFC_ENABLE 0x00400000 /* Obsolete? Enable PFC (at least on 4310) */
++#define BRCM_CLF_ENABLE 0x00100000 /* Enable cache line first feature */
++
++/* PreFetch Cache aka Read Ahead Cache */
++
++#define PFC_CR0 0xff400000 /* control reg 0 */
++#define PFC_CR1 0xff400004 /* control reg 1 */
++
++/* PFC operations */
++#define PFC_I 0x00000001 /* Enable PFC use for instructions */
++#define PFC_D 0x00000002 /* Enable PFC use for data */
++#define PFC_PFI 0x00000004 /* Enable seq. prefetch for instructions */
++#define PFC_PFD 0x00000008 /* Enable seq. prefetch for data */
++#define PFC_CINV 0x00000010 /* Enable selective (i/d) cacheop flushing */
++#define PFC_NCH 0x00000020 /* Disable flushing based on cacheops */
++#define PFC_DPF 0x00000040 /* Enable directional prefetching */
++#define PFC_FLUSH 0x00000100 /* Flush the PFC */
++#define PFC_BRR 0x40000000 /* Bus error indication */
++#define PFC_PWR 0x80000000 /* Disable power saving (clock gating) */
++
++/* Handy defaults */
++#define PFC_DISABLED 0
++#define PFC_AUTO 0xffffffff /* auto select the default mode */
++#define PFC_INST (PFC_I | PFC_PFI | PFC_CINV)
++#define PFC_INST_NOPF (PFC_I | PFC_CINV)
++#define PFC_DATA (PFC_D | PFC_PFD | PFC_CINV)
++#define PFC_DATA_NOPF (PFC_D | PFC_CINV)
++#define PFC_I_AND_D (PFC_INST | PFC_DATA)
++#define PFC_I_AND_D_NOPF (PFC_INST_NOPF | PFC_DATA_NOPF)
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++/*
++ * Macros to access the system control coprocessor
++ */
++
++#define MFC0(source, sel) \
++({ \
++ int __res; \
++ __asm__ __volatile__(" \
++ .set\tnoreorder; \
++ .set\tnoat; \
++ .word\t"STR(0x40010000 | ((source) << 11) | (sel))"; \
++ move\t%0, $1; \
++ .set\tat; \
++ .set\treorder" \
++ :"=r" (__res) \
++ : \
++ :"$1"); \
++ __res; \
++})
++
++#define MTC0(source, sel, value) \
++do { \
++ __asm__ __volatile__(" \
++ .set\tnoreorder; \
++ .set\tnoat; \
++ move\t$1, %z0; \
++ .word\t"STR(0x40810000 | ((source) << 11) | (sel))"; \
++ .set\tat; \
++ .set\treorder" \
++ : \
++ :"jr" (value) \
++ :"$1"); \
++} while (0)
++
++#define get_c0_count() \
++({ \
++ int __res; \
++ __asm__ __volatile__(" \
++ .set\tnoreorder; \
++ .set\tnoat; \
++ mfc0\t%0, $9; \
++ .set\tat; \
++ .set\treorder" \
++ :"=r" (__res)); \
++ __res; \
++})
++
++static INLINE void icache_probe(uint32 config1, uint *size, uint *lsize)
++{
++ uint lsz, sets, ways;
++
++ /* Instruction Cache Size = Associativity * Line Size * Sets Per Way */
++ if ((lsz = ((config1 & CONF1_IL_MASK) >> CONF1_IL_SHIFT)))
++ lsz = CONF1_IL_BASE << lsz;
++ sets = CONF1_IS_BASE << ((config1 & CONF1_IS_MASK) >> CONF1_IS_SHIFT);
++ ways = CONF1_IA_BASE + ((config1 & CONF1_IA_MASK) >> CONF1_IA_SHIFT);
++ *size = lsz * sets * ways;
++ *lsize = lsz;
++}
++
++static INLINE void dcache_probe(uint32 config1, uint *size, uint *lsize)
++{
++ uint lsz, sets, ways;
++
++ /* Data Cache Size = Associativity * Line Size * Sets Per Way */
++ if ((lsz = ((config1 & CONF1_DL_MASK) >> CONF1_DL_SHIFT)))
++ lsz = CONF1_DL_BASE << lsz;
++ sets = CONF1_DS_BASE << ((config1 & CONF1_DS_MASK) >> CONF1_DS_SHIFT);
++ ways = CONF1_DA_BASE + ((config1 & CONF1_DA_MASK) >> CONF1_DA_SHIFT);
++ *size = lsz * sets * ways;
++ *lsize = lsz;
++}
++
++#define cache_op(base, op) \
++ __asm__ __volatile__(" \
++ .set noreorder; \
++ .set mips3; \
++ cache %1, (%0); \
++ .set mips0; \
++ .set reorder" \
++ : \
++ : "r" (base), \
++ "i" (op));
++
++#define cache_unroll4(base, delta, op) \
++ __asm__ __volatile__(" \
++ .set noreorder; \
++ .set mips3; \
++ cache %1, 0(%0); \
++ cache %1, delta(%0); \
++ cache %1, (2 * delta)(%0); \
++ cache %1, (3 * delta)(%0); \
++ .set mips0; \
++ .set reorder" \
++ : \
++ : "r" (base), \
++ "i" (op));
++
++#endif /* !_LANGUAGE_ASSEMBLY */
++
++#endif /* _MISPINC_H */
+diff -urN linux.old/arch/mips/bcm947xx/include/osl.h linux.dev/arch/mips/bcm947xx/include/osl.h
+--- linux.old/arch/mips/bcm947xx/include/osl.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/osl.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,179 @@
++#ifndef __osl_h
++#define __osl_h
++
++#include <linux/delay.h>
++#include <typedefs.h>
++#include <linuxver.h>
++#include <bcmutils.h>
++#include <pcicfg.h>
++
++#define ASSERT(n)
++
++/* Pkttag flag should be part of public information */
++struct osl_pubinfo {
++ bool pkttag;
++ uint pktalloced; /* Number of allocated packet buffers */
++};
++
++struct osl_info {
++ struct osl_pubinfo pub;
++ uint magic;
++ void *pdev;
++ uint malloced;
++ uint failed;
++ void *dbgmem_list;
++};
++
++typedef struct osl_info osl_t;
++
++#define PCI_CFG_RETRY 10
++
++/* map/unmap direction */
++#define DMA_TX 1 /* TX direction for DMA */
++#define DMA_RX 2 /* RX direction for DMA */
++
++#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v))
++#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v))
++#define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val)))
++
++/* bcopy, bcmp, and bzero */
++#define bcopy(src, dst, len) memcpy((dst), (src), (len))
++#define bcmp(b1, b2, len) memcmp((b1), (b2), (len))
++#define bzero(b, len) memset((b), '\0', (len))
++
++/* uncached virtual address */
++#ifdef mips
++#define OSL_UNCACHED(va) KSEG1ADDR((va))
++#include <asm/addrspace.h>
++#else
++#define OSL_UNCACHED(va) (va)
++#endif /* mips */
++
++
++#ifndef IL_BIGENDIAN
++#define R_REG(osh, r) (\
++ sizeof(*(r)) == sizeof(uint8) ? readb((volatile uint8*)(r)) : \
++ sizeof(*(r)) == sizeof(uint16) ? readw((volatile uint16*)(r)) : \
++ readl((volatile uint32*)(r)) \
++)
++#define W_REG(osh, r, v) do { \
++ switch (sizeof(*(r))) { \
++ case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \
++ case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \
++ case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \
++ } \
++} while (0)
++#else /* IL_BIGENDIAN */
++#define R_REG(osh, r) ({ \
++ __typeof(*(r)) __osl_v; \
++ switch (sizeof(*(r))) { \
++ case sizeof(uint8): __osl_v = readb((volatile uint8*)((uint32)r^3)); break; \
++ case sizeof(uint16): __osl_v = readw((volatile uint16*)((uint32)r^2)); break; \
++ case sizeof(uint32): __osl_v = readl((volatile uint32*)(r)); break; \
++ } \
++ __osl_v; \
++})
++#define W_REG(osh, r, v) do { \
++ switch (sizeof(*(r))) { \
++ case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)((uint32)r^3)); break; \
++ case sizeof(uint16): writew((uint16)(v), (volatile uint16*)((uint32)r^2)); break; \
++ case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \
++ } \
++} while (0)
++#endif /* IL_BIGENDIAN */
++
++/* dereference an address that may cause a bus exception */
++#define BUSPROBE(val, addr) get_dbe((val), (addr))
++#include <asm/paccess.h>
++
++/* map/unmap physical to virtual I/O */
++#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size))
++#define REG_UNMAP(va) iounmap((void *)(va))
++
++/* shared (dma-able) memory access macros */
++#define R_SM(r) *(r)
++#define W_SM(r, v) (*(r) = (v))
++#define BZERO_SM(r, len) memset((r), '\0', (len))
++
++#define MALLOC(osh, size) kmalloc((size), GFP_ATOMIC)
++#define MFREE(osh, addr, size) kfree((addr))
++#define MALLOCED(osh) (0)
++
++#define osl_delay OSL_DELAY
++static inline void OSL_DELAY(uint usec)
++{
++ uint d;
++
++ while (usec > 0) {
++ d = MIN(usec, 1000);
++ udelay(d);
++ usec -= d;
++ }
++}
++
++static inline void
++bcm_mdelay(uint ms)
++{
++ uint i;
++
++ for (i = 0; i < ms; i++) {
++ OSL_DELAY(1000);
++ }
++}
++
++
++#define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size)
++#define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size)
++
++#define OSL_PCI_READ_CONFIG(osh, offset, size) \
++ osl_pci_read_config((osh), (offset), (size))
++
++static inline uint32
++osl_pci_read_config(osl_t *osh, uint offset, uint size)
++{
++ uint val;
++ uint retry = PCI_CFG_RETRY;
++
++ do {
++ pci_read_config_dword(osh->pdev, offset, &val);
++ if (val != 0xffffffff)
++ break;
++ } while (retry--);
++
++ return (val);
++}
++
++#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \
++ osl_pci_write_config((osh), (offset), (size), (val))
++static inline void
++osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val)
++{
++ uint retry = PCI_CFG_RETRY;
++
++ do {
++ pci_write_config_dword(osh->pdev, offset, val);
++ if (offset != PCI_BAR0_WIN)
++ break;
++ if (osl_pci_read_config(osh, offset, size) == val)
++ break;
++ } while (retry--);
++}
++
++
++/* return bus # for the pci device pointed by osh->pdev */
++#define OSL_PCI_BUS(osh) osl_pci_bus(osh)
++static inline uint
++osl_pci_bus(osl_t *osh)
++{
++ return ((struct pci_dev *)osh->pdev)->bus->number;
++}
++
++/* return slot # for the pci device pointed by osh->pdev */
++#define OSL_PCI_SLOT(osh) osl_pci_slot(osh)
++static inline uint
++osl_pci_slot(osl_t *osh)
++{
++ return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
++}
++
++#endif
+diff -urN linux.old/arch/mips/bcm947xx/include/pcicfg.h linux.dev/arch/mips/bcm947xx/include/pcicfg.h
+--- linux.old/arch/mips/bcm947xx/include/pcicfg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/pcicfg.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,495 @@
++/*
++ * pcicfg.h: PCI configuration constants and structures.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: pcicfg.h,v 1.1.1.11 2006/04/08 06:13:40 honor Exp $
++ */
++
++#ifndef _h_pcicfg_
++#define _h_pcicfg_
++
++/* The following inside ifndef's so we don't collide with NTDDK.H */
++#ifndef PCI_MAX_BUS
++#define PCI_MAX_BUS 0x100
++#endif
++#ifndef PCI_MAX_DEVICES
++#define PCI_MAX_DEVICES 0x20
++#endif
++#ifndef PCI_MAX_FUNCTION
++#define PCI_MAX_FUNCTION 0x8
++#endif
++
++#ifndef PCI_INVALID_VENDORID
++#define PCI_INVALID_VENDORID 0xffff
++#endif
++#ifndef PCI_INVALID_DEVICEID
++#define PCI_INVALID_DEVICEID 0xffff
++#endif
++
++
++/* Convert between bus-slot-function-register and config addresses */
++
++#define PCICFG_BUS_SHIFT 16 /* Bus shift */
++#define PCICFG_SLOT_SHIFT 11 /* Slot shift */
++#define PCICFG_FUN_SHIFT 8 /* Function shift */
++#define PCICFG_OFF_SHIFT 0 /* Register shift */
++
++#define PCICFG_BUS_MASK 0xff /* Bus mask */
++#define PCICFG_SLOT_MASK 0x1f /* Slot mask */
++#define PCICFG_FUN_MASK 7 /* Function mask */
++#define PCICFG_OFF_MASK 0xff /* Bus mask */
++
++#define PCI_CONFIG_ADDR(b, s, f, o) \
++ ((((b) & PCICFG_BUS_MASK) << PCICFG_BUS_SHIFT) \
++ | (((s) & PCICFG_SLOT_MASK) << PCICFG_SLOT_SHIFT) \
++ | (((f) & PCICFG_FUN_MASK) << PCICFG_FUN_SHIFT) \
++ | (((o) & PCICFG_OFF_MASK) << PCICFG_OFF_SHIFT))
++
++#define PCI_CONFIG_BUS(a) (((a) >> PCICFG_BUS_SHIFT) & PCICFG_BUS_MASK)
++#define PCI_CONFIG_SLOT(a) (((a) >> PCICFG_SLOT_SHIFT) & PCICFG_SLOT_MASK)
++#define PCI_CONFIG_FUN(a) (((a) >> PCICFG_FUN_SHIFT) & PCICFG_FUN_MASK)
++#define PCI_CONFIG_OFF(a) (((a) >> PCICFG_OFF_SHIFT) & PCICFG_OFF_MASK)
++
++/* PCIE Config space accessing MACROS */
++
++#define PCIECFG_BUS_SHIFT 24 /* Bus shift */
++#define PCIECFG_SLOT_SHIFT 19 /* Slot/Device shift */
++#define PCIECFG_FUN_SHIFT 16 /* Function shift */
++#define PCIECFG_OFF_SHIFT 0 /* Register shift */
++
++#define PCIECFG_BUS_MASK 0xff /* Bus mask */
++#define PCIECFG_SLOT_MASK 0x1f /* Slot/Device mask */
++#define PCIECFG_FUN_MASK 7 /* Function mask */
++#define PCIECFG_OFF_MASK 0x3ff /* Register mask */
++
++#define PCIE_CONFIG_ADDR(b, s, f, o) \
++ ((((b) & PCIECFG_BUS_MASK) << PCIECFG_BUS_SHIFT) \
++ | (((s) & PCIECFG_SLOT_MASK) << PCIECFG_SLOT_SHIFT) \
++ | (((f) & PCIECFG_FUN_MASK) << PCIECFG_FUN_SHIFT) \
++ | (((o) & PCIECFG_OFF_MASK) << PCIECFG_OFF_SHIFT))
++
++#define PCIE_CONFIG_BUS(a) (((a) >> PCIECFG_BUS_SHIFT) & PCIECFG_BUS_MASK)
++#define PCIE_CONFIG_SLOT(a) (((a) >> PCIECFG_SLOT_SHIFT) & PCIECFG_SLOT_MASK)
++#define PCIE_CONFIG_FUN(a) (((a) >> PCIECFG_FUN_SHIFT) & PCIECFG_FUN_MASK)
++#define PCIE_CONFIG_OFF(a) (((a) >> PCIECFG_OFF_SHIFT) & PCIECFG_OFF_MASK)
++
++/* The actual config space */
++
++#define PCI_BAR_MAX 6
++
++#define PCI_ROM_BAR 8
++
++#define PCR_RSVDA_MAX 2
++
++/* Bits in PCI bars' flags */
++
++#define PCIBAR_FLAGS 0xf
++#define PCIBAR_IO 0x1
++#define PCIBAR_MEM1M 0x2
++#define PCIBAR_MEM64 0x4
++#define PCIBAR_PREFETCH 0x8
++#define PCIBAR_MEM32_MASK 0xFFFFFF80
++
++/* pci config status reg has a bit to indicate that capability ptr is present */
++
++#define PCI_CAPPTR_PRESENT 0x0010
++
++typedef struct _pci_config_regs {
++ unsigned short vendor;
++ unsigned short device;
++ unsigned short command;
++ unsigned short status;
++ unsigned char rev_id;
++ unsigned char prog_if;
++ unsigned char sub_class;
++ unsigned char base_class;
++ unsigned char cache_line_size;
++ unsigned char latency_timer;
++ unsigned char header_type;
++ unsigned char bist;
++ unsigned long base[PCI_BAR_MAX];
++ unsigned long cardbus_cis;
++ unsigned short subsys_vendor;
++ unsigned short subsys_id;
++ unsigned long baserom;
++ unsigned long rsvd_a[PCR_RSVDA_MAX];
++ unsigned char int_line;
++ unsigned char int_pin;
++ unsigned char min_gnt;
++ unsigned char max_lat;
++ unsigned char dev_dep[192];
++} pci_config_regs;
++
++#define SZPCR (sizeof (pci_config_regs))
++#define MINSZPCR 64 /* offsetof (dev_dep[0] */
++
++/* A structure for the config registers is nice, but in most
++ * systems the config space is not memory mapped, so we need
++ * filed offsetts. :-(
++ */
++#define PCI_CFG_VID 0
++#define PCI_CFG_DID 2
++#define PCI_CFG_CMD 4
++#define PCI_CFG_STAT 6
++#define PCI_CFG_REV 8
++#define PCI_CFG_PROGIF 9
++#define PCI_CFG_SUBCL 0xa
++#define PCI_CFG_BASECL 0xb
++#define PCI_CFG_CLSZ 0xc
++#define PCI_CFG_LATTIM 0xd
++#define PCI_CFG_HDR 0xe
++#define PCI_CFG_BIST 0xf
++#define PCI_CFG_BAR0 0x10
++#define PCI_CFG_BAR1 0x14
++#define PCI_CFG_BAR2 0x18
++#define PCI_CFG_BAR3 0x1c
++#define PCI_CFG_BAR4 0x20
++#define PCI_CFG_BAR5 0x24
++#define PCI_CFG_CIS 0x28
++#define PCI_CFG_SVID 0x2c
++#define PCI_CFG_SSID 0x2e
++#define PCI_CFG_ROMBAR 0x30
++#define PCI_CFG_CAPPTR 0x34
++#define PCI_CFG_INT 0x3c
++#define PCI_CFG_PIN 0x3d
++#define PCI_CFG_MINGNT 0x3e
++#define PCI_CFG_MAXLAT 0x3f
++
++#ifdef __NetBSD__
++#undef PCI_CLASS_DISPLAY
++#undef PCI_CLASS_MEMORY
++#undef PCI_CLASS_BRIDGE
++#undef PCI_CLASS_INPUT
++#undef PCI_CLASS_DOCK
++#endif /* __NetBSD__ */
++
++/* Classes and subclasses */
++
++typedef enum {
++ PCI_CLASS_OLD = 0,
++ PCI_CLASS_DASDI,
++ PCI_CLASS_NET,
++ PCI_CLASS_DISPLAY,
++ PCI_CLASS_MMEDIA,
++ PCI_CLASS_MEMORY,
++ PCI_CLASS_BRIDGE,
++ PCI_CLASS_COMM,
++ PCI_CLASS_BASE,
++ PCI_CLASS_INPUT,
++ PCI_CLASS_DOCK,
++ PCI_CLASS_CPU,
++ PCI_CLASS_SERIAL,
++ PCI_CLASS_INTELLIGENT = 0xe,
++ PCI_CLASS_SATELLITE,
++ PCI_CLASS_CRYPT,
++ PCI_CLASS_DSP,
++ PCI_CLASS_XOR = 0xfe
++} pci_classes;
++
++typedef enum {
++ PCI_DASDI_SCSI,
++ PCI_DASDI_IDE,
++ PCI_DASDI_FLOPPY,
++ PCI_DASDI_IPI,
++ PCI_DASDI_RAID,
++ PCI_DASDI_OTHER = 0x80
++} pci_dasdi_subclasses;
++
++typedef enum {
++ PCI_NET_ETHER,
++ PCI_NET_TOKEN,
++ PCI_NET_FDDI,
++ PCI_NET_ATM,
++ PCI_NET_OTHER = 0x80
++} pci_net_subclasses;
++
++typedef enum {
++ PCI_DISPLAY_VGA,
++ PCI_DISPLAY_XGA,
++ PCI_DISPLAY_3D,
++ PCI_DISPLAY_OTHER = 0x80
++} pci_display_subclasses;
++
++typedef enum {
++ PCI_MMEDIA_VIDEO,
++ PCI_MMEDIA_AUDIO,
++ PCI_MMEDIA_PHONE,
++ PCI_MEDIA_OTHER = 0x80
++} pci_mmedia_subclasses;
++
++typedef enum {
++ PCI_MEMORY_RAM,
++ PCI_MEMORY_FLASH,
++ PCI_MEMORY_OTHER = 0x80
++} pci_memory_subclasses;
++
++typedef enum {
++ PCI_BRIDGE_HOST,
++ PCI_BRIDGE_ISA,
++ PCI_BRIDGE_EISA,
++ PCI_BRIDGE_MC,
++ PCI_BRIDGE_PCI,
++ PCI_BRIDGE_PCMCIA,
++ PCI_BRIDGE_NUBUS,
++ PCI_BRIDGE_CARDBUS,
++ PCI_BRIDGE_RACEWAY,
++ PCI_BRIDGE_OTHER = 0x80
++} pci_bridge_subclasses;
++
++typedef enum {
++ PCI_COMM_UART,
++ PCI_COMM_PARALLEL,
++ PCI_COMM_MULTIUART,
++ PCI_COMM_MODEM,
++ PCI_COMM_OTHER = 0x80
++} pci_comm_subclasses;
++
++typedef enum {
++ PCI_BASE_PIC,
++ PCI_BASE_DMA,
++ PCI_BASE_TIMER,
++ PCI_BASE_RTC,
++ PCI_BASE_PCI_HOTPLUG,
++ PCI_BASE_OTHER = 0x80
++} pci_base_subclasses;
++
++typedef enum {
++ PCI_INPUT_KBD,
++ PCI_INPUT_PEN,
++ PCI_INPUT_MOUSE,
++ PCI_INPUT_SCANNER,
++ PCI_INPUT_GAMEPORT,
++ PCI_INPUT_OTHER = 0x80
++} pci_input_subclasses;
++
++typedef enum {
++ PCI_DOCK_GENERIC,
++ PCI_DOCK_OTHER = 0x80
++} pci_dock_subclasses;
++
++typedef enum {
++ PCI_CPU_386,
++ PCI_CPU_486,
++ PCI_CPU_PENTIUM,
++ PCI_CPU_ALPHA = 0x10,
++ PCI_CPU_POWERPC = 0x20,
++ PCI_CPU_MIPS = 0x30,
++ PCI_CPU_COPROC = 0x40,
++ PCI_CPU_OTHER = 0x80
++} pci_cpu_subclasses;
++
++typedef enum {
++ PCI_SERIAL_IEEE1394,
++ PCI_SERIAL_ACCESS,
++ PCI_SERIAL_SSA,
++ PCI_SERIAL_USB,
++ PCI_SERIAL_FIBER,
++ PCI_SERIAL_SMBUS,
++ PCI_SERIAL_OTHER = 0x80
++} pci_serial_subclasses;
++
++typedef enum {
++ PCI_INTELLIGENT_I2O
++} pci_intelligent_subclasses;
++
++typedef enum {
++ PCI_SATELLITE_TV,
++ PCI_SATELLITE_AUDIO,
++ PCI_SATELLITE_VOICE,
++ PCI_SATELLITE_DATA,
++ PCI_SATELLITE_OTHER = 0x80
++} pci_satellite_subclasses;
++
++typedef enum {
++ PCI_CRYPT_NETWORK,
++ PCI_CRYPT_ENTERTAINMENT,
++ PCI_CRYPT_OTHER = 0x80
++} pci_crypt_subclasses;
++
++typedef enum {
++ PCI_DSP_DPIO,
++ PCI_DSP_OTHER = 0x80
++} pci_dsp_subclasses;
++
++typedef enum {
++ PCI_XOR_QDMA,
++ PCI_XOR_OTHER = 0x80
++} pci_xor_subclasses;
++
++/* Header types */
++typedef enum {
++ PCI_HEADER_NORMAL,
++ PCI_HEADER_BRIDGE,
++ PCI_HEADER_CARDBUS
++} pci_header_types;
++
++
++/* Overlay for a PCI-to-PCI bridge */
++
++#define PPB_RSVDA_MAX 2
++#define PPB_RSVDD_MAX 8
++
++typedef struct _ppb_config_regs {
++ unsigned short vendor;
++ unsigned short device;
++ unsigned short command;
++ unsigned short status;
++ unsigned char rev_id;
++ unsigned char prog_if;
++ unsigned char sub_class;
++ unsigned char base_class;
++ unsigned char cache_line_size;
++ unsigned char latency_timer;
++ unsigned char header_type;
++ unsigned char bist;
++ unsigned long rsvd_a[PPB_RSVDA_MAX];
++ unsigned char prim_bus;
++ unsigned char sec_bus;
++ unsigned char sub_bus;
++ unsigned char sec_lat;
++ unsigned char io_base;
++ unsigned char io_lim;
++ unsigned short sec_status;
++ unsigned short mem_base;
++ unsigned short mem_lim;
++ unsigned short pf_mem_base;
++ unsigned short pf_mem_lim;
++ unsigned long pf_mem_base_hi;
++ unsigned long pf_mem_lim_hi;
++ unsigned short io_base_hi;
++ unsigned short io_lim_hi;
++ unsigned short subsys_vendor;
++ unsigned short subsys_id;
++ unsigned long rsvd_b;
++ unsigned char rsvd_c;
++ unsigned char int_pin;
++ unsigned short bridge_ctrl;
++ unsigned char chip_ctrl;
++ unsigned char diag_ctrl;
++ unsigned short arb_ctrl;
++ unsigned long rsvd_d[PPB_RSVDD_MAX];
++ unsigned char dev_dep[192];
++} ppb_config_regs;
++
++
++/* PCI CAPABILITY DEFINES */
++#define PCI_CAP_POWERMGMTCAP_ID 0x01
++#define PCI_CAP_MSICAP_ID 0x05
++#define PCI_CAP_PCIECAP_ID 0x10
++
++/* Data structure to define the Message Signalled Interrupt facility
++ * Valid for PCI and PCIE configurations
++ */
++typedef struct _pciconfig_cap_msi {
++ unsigned char capID;
++ unsigned char nextptr;
++ unsigned short msgctrl;
++ unsigned int msgaddr;
++} pciconfig_cap_msi;
++
++/* Data structure to define the Power managment facility
++ * Valid for PCI and PCIE configurations
++ */
++typedef struct _pciconfig_cap_pwrmgmt {
++ unsigned char capID;
++ unsigned char nextptr;
++ unsigned short pme_cap;
++ unsigned short pme_sts_ctrl;
++ unsigned char pme_bridge_ext;
++ unsigned char data;
++} pciconfig_cap_pwrmgmt;
++
++/* Data structure to define the PCIE capability */
++typedef struct _pciconfig_cap_pcie {
++ unsigned char capID;
++ unsigned char nextptr;
++ unsigned short pcie_cap;
++ unsigned int dev_cap;
++ unsigned short dev_ctrl;
++ unsigned short dev_status;
++ unsigned int link_cap;
++ unsigned short link_ctrl;
++ unsigned short link_status;
++} pciconfig_cap_pcie;
++
++/* PCIE Enhanced CAPABILITY DEFINES */
++#define PCIE_EXTCFG_OFFSET 0x100
++#define PCIE_ADVERRREP_CAPID 0x0001
++#define PCIE_VC_CAPID 0x0002
++#define PCIE_DEVSNUM_CAPID 0x0003
++#define PCIE_PWRBUDGET_CAPID 0x0004
++
++/* Header to define the PCIE specific capabilities in the extended config space */
++typedef struct _pcie_enhanced_caphdr {
++ unsigned short capID;
++ unsigned short cap_ver : 4;
++ unsigned short next_ptr : 12;
++} pcie_enhanced_caphdr;
++
++
++/* Everything below is BRCM HND proprietary */
++
++
++/* Brcm PCI configuration registers */
++#define cap_list rsvd_a[0]
++#define bar0_window dev_dep[0x80 - 0x40]
++#define bar1_window dev_dep[0x84 - 0x40]
++#define sprom_control dev_dep[0x88 - 0x40]
++
++#define PCI_BAR0_WIN 0x80 /* backplane addres space accessed by BAR0 */
++#define PCI_BAR1_WIN 0x84 /* backplane addres space accessed by BAR1 */
++#define PCI_SPROM_CONTROL 0x88 /* sprom property control */
++#define PCI_BAR1_CONTROL 0x8c /* BAR1 region burst control */
++#define PCI_INT_STATUS 0x90 /* PCI and other cores interrupts */
++#define PCI_INT_MASK 0x94 /* mask of PCI and other cores interrupts */
++#define PCI_TO_SB_MB 0x98 /* signal backplane interrupts */
++#define PCI_BACKPLANE_ADDR 0xA0 /* address an arbitrary location on the system backplane */
++#define PCI_BACKPLANE_DATA 0xA4 /* data at the location specified by above address */
++#define PCI_GPIO_IN 0xb0 /* pci config space gpio input (>=rev3) */
++#define PCI_GPIO_OUT 0xb4 /* pci config space gpio output (>=rev3) */
++#define PCI_GPIO_OUTEN 0xb8 /* pci config space gpio output enable (>=rev3) */
++
++#define PCI_BAR0_SHADOW_OFFSET (2 * 1024) /* bar0 + 2K accesses sprom shadow (in pci core) */
++#define PCI_BAR0_SPROM_OFFSET (4 * 1024) /* bar0 + 4K accesses external sprom */
++#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) /* bar0 + 6K accesses pci core registers */
++#define PCI_BAR0_PCISBR_OFFSET (4 * 1024) /* pci core SB registers are at the end of the
++ * 8KB window, so their address is the "regular"
++ * address plus 4K
++ */
++#define PCI_BAR0_WINSZ 8192 /* bar0 window size */
++
++/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */
++#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024) /* bar0 + 8K accesses pci/pcie core registers */
++#define PCI_16KB0_CCREGS_OFFSET (12 * 1024) /* bar0 + 12K accesses chipc core registers */
++#define PCI_16KBB0_WINSZ (16 * 1024) /* bar0 window size */
++
++/* PCI_INT_STATUS */
++#define PCI_SBIM_STATUS_SERR 0x4 /* backplane SBErr interrupt status */
++
++/* PCI_INT_MASK */
++#define PCI_SBIM_SHIFT 8 /* backplane core interrupt mask bits offset */
++#define PCI_SBIM_MASK 0xff00 /* backplane core interrupt mask */
++#define PCI_SBIM_MASK_SERR 0x4 /* backplane SBErr interrupt mask */
++
++/* PCI_SPROM_CONTROL */
++#define SPROM_SZ_MSK 0x02 /* SPROM Size Mask */
++#define SPROM_LOCKED 0x08 /* SPROM Locked */
++#define SPROM_BLANK 0x04 /* indicating a blank SPROM */
++#define SPROM_WRITEEN 0x10 /* SPROM write enable */
++#define SPROM_BOOTROM_WE 0x20 /* external bootrom write enable */
++#define SPROM_OTPIN_USE 0x80 /* device OTP In use */
++
++#define SPROM_SIZE 256 /* sprom size in 16-bit */
++#define SPROM_CRC_RANGE 64 /* crc cover range in 16-bit */
++
++/* PCI_CFG_CMD_STAT */
++#define PCI_CFG_CMD_STAT_TA 0x08000000 /* target abort status */
++
++#endif /* _h_pcicfg_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/sbchipc.h linux.dev/arch/mips/bcm947xx/include/sbchipc.h
+--- linux.old/arch/mips/bcm947xx/include/sbchipc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbchipc.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,516 @@
++/*
++ * SiliconBackplane Chipcommon core hardware definitions.
++ *
++ * The chipcommon core provides chip identification, SB control,
++ * jtag, 0/1/2 uarts, clock frequency control, a watchdog interrupt timer,
++ * gpio interface, extbus, and support for serial and parallel flashes.
++ *
++ * $Id: sbchipc.h,v 1.1.1.14 2006/04/15 01:29:08 michael Exp $
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ */
++
++#ifndef _SBCHIPC_H
++#define _SBCHIPC_H
++
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++/* cpp contortions to concatenate w/arg prescan */
++#ifndef PAD
++#define _PADLINE(line) pad ## line
++#define _XSTR(line) _PADLINE(line)
++#define PAD _XSTR(__LINE__)
++#endif /* PAD */
++
++typedef volatile struct {
++ uint32 chipid; /* 0x0 */
++ uint32 capabilities;
++ uint32 corecontrol; /* corerev >= 1 */
++ uint32 bist;
++
++ /* OTP */
++ uint32 otpstatus; /* 0x10, corerev >= 10 */
++ uint32 otpcontrol;
++ uint32 otpprog;
++ uint32 PAD;
++
++ /* Interrupt control */
++ uint32 intstatus; /* 0x20 */
++ uint32 intmask;
++ uint32 chipcontrol; /* 0x28, rev >= 11 */
++ uint32 chipstatus; /* 0x2c, rev >= 11 */
++
++ /* Jtag Master */
++ uint32 jtagcmd; /* 0x30, rev >= 10 */
++ uint32 jtagir;
++ uint32 jtagdr;
++ uint32 jtagctrl;
++
++ /* serial flash interface registers */
++ uint32 flashcontrol; /* 0x40 */
++ uint32 flashaddress;
++ uint32 flashdata;
++ uint32 PAD[1];
++
++ /* Silicon backplane configuration broadcast control */
++ uint32 broadcastaddress; /* 0x50 */
++ uint32 broadcastdata;
++ uint32 PAD[2];
++
++ /* gpio - cleared only by power-on-reset */
++ uint32 gpioin; /* 0x60 */
++ uint32 gpioout;
++ uint32 gpioouten;
++ uint32 gpiocontrol;
++ uint32 gpiointpolarity;
++ uint32 gpiointmask;
++ uint32 PAD[2];
++
++ /* Watchdog timer */
++ uint32 watchdog; /* 0x80 */
++ uint32 PAD[1];
++
++ /* GPIO based LED powersave registers corerev >= 16 */
++ uint32 gpiotimerval; /* 0x88 */
++ uint32 gpiotimeroutmask;
++
++ /* clock control */
++ uint32 clockcontrol_n; /* 0x90 */
++ uint32 clockcontrol_sb; /* aka m0 */
++ uint32 clockcontrol_pci; /* aka m1 */
++ uint32 clockcontrol_m2; /* mii/uart/mipsref */
++ uint32 clockcontrol_m3; /* cpu */
++ uint32 clkdiv; /* corerev >= 3 */
++ uint32 PAD[2];
++
++ /* pll delay registers (corerev >= 4) */
++ uint32 pll_on_delay; /* 0xb0 */
++ uint32 fref_sel_delay;
++ uint32 slow_clk_ctl; /* 5 < corerev < 10 */
++ uint32 PAD[1];
++
++ /* Instaclock registers (corerev >= 10) */
++ uint32 system_clk_ctl; /* 0xc0 */
++ uint32 clkstatestretch;
++ uint32 PAD[14];
++
++ /* ExtBus control registers (corerev >= 3) */
++ uint32 pcmcia_config; /* 0x100 */
++ uint32 pcmcia_memwait;
++ uint32 pcmcia_attrwait;
++ uint32 pcmcia_iowait;
++ uint32 ide_config;
++ uint32 ide_memwait;
++ uint32 ide_attrwait;
++ uint32 ide_iowait;
++ uint32 prog_config;
++ uint32 prog_waitcount;
++ uint32 flash_config;
++ uint32 flash_waitcount;
++ uint32 PAD[44];
++
++ /* Clock control and hardware workarounds */
++ uint32 clk_ctl_st;
++ uint32 hw_war;
++ uint32 PAD[70];
++
++ /* uarts */
++ uint8 uart0data; /* 0x300 */
++ uint8 uart0imr;
++ uint8 uart0fcr;
++ uint8 uart0lcr;
++ uint8 uart0mcr;
++ uint8 uart0lsr;
++ uint8 uart0msr;
++ uint8 uart0scratch;
++ uint8 PAD[248]; /* corerev >= 1 */
++
++ uint8 uart1data; /* 0x400 */
++ uint8 uart1imr;
++ uint8 uart1fcr;
++ uint8 uart1lcr;
++ uint8 uart1mcr;
++ uint8 uart1lsr;
++ uint8 uart1msr;
++ uint8 uart1scratch;
++} chipcregs_t;
++
++#endif /* _LANGUAGE_ASSEMBLY */
++
++#define CC_CHIPID 0
++#define CC_CAPABILITIES 4
++#define CC_JTAGCMD 0x30
++#define CC_JTAGIR 0x34
++#define CC_JTAGDR 0x38
++#define CC_JTAGCTRL 0x3c
++#define CC_WATCHDOG 0x80
++#define CC_CLKC_N 0x90
++#define CC_CLKC_M0 0x94
++#define CC_CLKC_M1 0x98
++#define CC_CLKC_M2 0x9c
++#define CC_CLKC_M3 0xa0
++#define CC_CLKDIV 0xa4
++#define CC_SYS_CLK_CTL 0xc0
++#define CC_OTP 0x800
++
++/* chipid */
++#define CID_ID_MASK 0x0000ffff /* Chip Id mask */
++#define CID_REV_MASK 0x000f0000 /* Chip Revision mask */
++#define CID_REV_SHIFT 16 /* Chip Revision shift */
++#define CID_PKG_MASK 0x00f00000 /* Package Option mask */
++#define CID_PKG_SHIFT 20 /* Package Option shift */
++#define CID_CC_MASK 0x0f000000 /* CoreCount (corerev >= 4) */
++#define CID_CC_SHIFT 24
++
++/* capabilities */
++#define CAP_UARTS_MASK 0x00000003 /* Number of uarts */
++#define CAP_MIPSEB 0x00000004 /* MIPS is in big-endian mode */
++#define CAP_UCLKSEL 0x00000018 /* UARTs clock select */
++#define CAP_UINTCLK 0x00000008 /* UARTs are driven by internal divided clock */
++#define CAP_UARTGPIO 0x00000020 /* UARTs own Gpio's 15:12 */
++#define CAP_EXTBUS_MASK 0x000000c0 /* External bus mask */
++#define CAP_EXTBUS_NONE 0x00000000 /* No ExtBus present */
++#define CAP_EXTBUS_FULL 0x00000040 /* ExtBus: PCMCIA, IDE & Prog */
++#define CAP_EXTBUS_PROG 0x00000080 /* ExtBus: ProgIf only */
++#define CAP_FLASH_MASK 0x00000700 /* Type of flash */
++#define CAP_PLL_MASK 0x00038000 /* Type of PLL */
++#define CAP_PWR_CTL 0x00040000 /* Power control */
++#define CAP_OTPSIZE 0x00380000 /* OTP Size (0 = none) */
++#define CAP_OTPSIZE_SHIFT 19 /* OTP Size shift */
++#define CAP_OTPSIZE_BASE 5 /* OTP Size base */
++#define CAP_JTAGP 0x00400000 /* JTAG Master Present */
++#define CAP_ROM 0x00800000 /* Internal boot rom active */
++#define CAP_BKPLN64 0x08000000 /* 64-bit backplane */
++
++/* PLL type */
++#define PLL_NONE 0x00000000
++#define PLL_TYPE1 0x00010000 /* 48Mhz base, 3 dividers */
++#define PLL_TYPE2 0x00020000 /* 48Mhz, 4 dividers */
++#define PLL_TYPE3 0x00030000 /* 25Mhz, 2 dividers */
++#define PLL_TYPE4 0x00008000 /* 48Mhz, 4 dividers */
++#define PLL_TYPE5 0x00018000 /* 25Mhz, 4 dividers */
++#define PLL_TYPE6 0x00028000 /* 100/200 or 120/240 only */
++#define PLL_TYPE7 0x00038000 /* 25Mhz, 4 dividers */
++
++/* corecontrol */
++#define CC_UARTCLKO 0x00000001 /* Drive UART with internal clock */
++#define CC_SE 0x00000002 /* sync clk out enable (corerev >= 3) */
++
++/* chipcontrol */
++#define CHIPCTRL_4321A0_DEFAULT 0x3a4
++#define CHIPCTRL_4321A1_DEFAULT 0x0a4
++
++/* Fields in the otpstatus register */
++#define OTPS_PROGFAIL 0x80000000
++#define OTPS_PROTECT 0x00000007
++#define OTPS_HW_PROTECT 0x00000001
++#define OTPS_SW_PROTECT 0x00000002
++#define OTPS_CID_PROTECT 0x00000004
++
++/* Fields in the otpcontrol register */
++#define OTPC_RECWAIT 0xff000000
++#define OTPC_PROGWAIT 0x00ffff00
++#define OTPC_PRW_SHIFT 8
++#define OTPC_MAXFAIL 0x00000038
++#define OTPC_VSEL 0x00000006
++#define OTPC_SELVL 0x00000001
++
++/* Fields in otpprog */
++#define OTPP_COL_MASK 0x000000ff
++#define OTPP_ROW_MASK 0x0000ff00
++#define OTPP_ROW_SHIFT 8
++#define OTPP_READERR 0x10000000
++#define OTPP_VALUE 0x20000000
++#define OTPP_VALUE_SHIFT 29
++#define OTPP_READ 0x40000000
++#define OTPP_START 0x80000000
++#define OTPP_BUSY 0x80000000
++
++/* jtagcmd */
++#define JCMD_START 0x80000000
++#define JCMD_BUSY 0x80000000
++#define JCMD_PAUSE 0x40000000
++#define JCMD0_ACC_MASK 0x0000f000
++#define JCMD0_ACC_IRDR 0x00000000
++#define JCMD0_ACC_DR 0x00001000
++#define JCMD0_ACC_IR 0x00002000
++#define JCMD0_ACC_RESET 0x00003000
++#define JCMD0_ACC_IRPDR 0x00004000
++#define JCMD0_ACC_PDR 0x00005000
++#define JCMD0_IRW_MASK 0x00000f00
++#define JCMD_ACC_MASK 0x000f0000 /* Changes for corerev 11 */
++#define JCMD_ACC_IRDR 0x00000000
++#define JCMD_ACC_DR 0x00010000
++#define JCMD_ACC_IR 0x00020000
++#define JCMD_ACC_RESET 0x00030000
++#define JCMD_ACC_IRPDR 0x00040000
++#define JCMD_ACC_PDR 0x00050000
++#define JCMD_IRW_MASK 0x00001f00
++#define JCMD_IRW_SHIFT 8
++#define JCMD_DRW_MASK 0x0000003f
++
++/* jtagctrl */
++#define JCTRL_FORCE_CLK 4 /* Force clock */
++#define JCTRL_EXT_EN 2 /* Enable external targets */
++#define JCTRL_EN 1 /* Enable Jtag master */
++
++/* Fields in clkdiv */
++#define CLKD_SFLASH 0x0f000000
++#define CLKD_SFLASH_SHIFT 24
++#define CLKD_OTP 0x000f0000
++#define CLKD_OTP_SHIFT 16
++#define CLKD_JTAG 0x00000f00
++#define CLKD_JTAG_SHIFT 8
++#define CLKD_UART 0x000000ff
++
++/* intstatus/intmask */
++#define CI_GPIO 0x00000001 /* gpio intr */
++#define CI_EI 0x00000002 /* ro: ext intr pin (corerev >= 3) */
++#define CI_WDRESET 0x80000000 /* watchdog reset occurred */
++
++/* slow_clk_ctl */
++#define SCC_SS_MASK 0x00000007 /* slow clock source mask */
++#define SCC_SS_LPO 0x00000000 /* source of slow clock is LPO */
++#define SCC_SS_XTAL 0x00000001 /* source of slow clock is crystal */
++#define SCC_SS_PCI 0x00000002 /* source of slow clock is PCI */
++#define SCC_LF 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */
++#define SCC_LP 0x00000400 /* LPOPowerDown, 1: LPO is disabled,
++ * 0: LPO is enabled
++ */
++#define SCC_FS 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock,
++ * 0: power logic control
++ */
++#define SCC_IP 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors
++ * PLL clock disable requests from core
++ */
++#define SCC_XC 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't
++ * disable crystal when appropriate
++ */
++#define SCC_XP 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */
++#define SCC_CD_MASK 0xffff0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */
++#define SCC_CD_SHIFT 16
++
++/* system_clk_ctl */
++#define SYCC_IE 0x00000001 /* ILPen: Enable Idle Low Power */
++#define SYCC_AE 0x00000002 /* ALPen: Enable Active Low Power */
++#define SYCC_FP 0x00000004 /* ForcePLLOn */
++#define SYCC_AR 0x00000008 /* Force ALP (or HT if ALPen is not set */
++#define SYCC_HR 0x00000010 /* Force HT */
++#define SYCC_CD_MASK 0xffff0000 /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */
++#define SYCC_CD_SHIFT 16
++
++/* gpiotimerval */
++#define GPIO_ONTIME_SHIFT 16
++
++/* clockcontrol_n */
++#define CN_N1_MASK 0x3f /* n1 control */
++#define CN_N2_MASK 0x3f00 /* n2 control */
++#define CN_N2_SHIFT 8
++#define CN_PLLC_MASK 0xf0000 /* pll control */
++#define CN_PLLC_SHIFT 16
++
++/* clockcontrol_sb/pci/uart */
++#define CC_M1_MASK 0x3f /* m1 control */
++#define CC_M2_MASK 0x3f00 /* m2 control */
++#define CC_M2_SHIFT 8
++#define CC_M3_MASK 0x3f0000 /* m3 control */
++#define CC_M3_SHIFT 16
++#define CC_MC_MASK 0x1f000000 /* mux control */
++#define CC_MC_SHIFT 24
++
++/* N3M Clock control magic field values */
++#define CC_F6_2 0x02 /* A factor of 2 in */
++#define CC_F6_3 0x03 /* 6-bit fields like */
++#define CC_F6_4 0x05 /* N1, M1 or M3 */
++#define CC_F6_5 0x09
++#define CC_F6_6 0x11
++#define CC_F6_7 0x21
++
++#define CC_F5_BIAS 5 /* 5-bit fields get this added */
++
++#define CC_MC_BYPASS 0x08
++#define CC_MC_M1 0x04
++#define CC_MC_M1M2 0x02
++#define CC_MC_M1M2M3 0x01
++#define CC_MC_M1M3 0x11
++
++/* Type 2 Clock control magic field values */
++#define CC_T2_BIAS 2 /* n1, n2, m1 & m3 bias */
++#define CC_T2M2_BIAS 3 /* m2 bias */
++
++#define CC_T2MC_M1BYP 1
++#define CC_T2MC_M2BYP 2
++#define CC_T2MC_M3BYP 4
++
++/* Type 6 Clock control magic field values */
++#define CC_T6_MMASK 1 /* bits of interest in m */
++#define CC_T6_M0 120000000 /* sb clock for m = 0 */
++#define CC_T6_M1 100000000 /* sb clock for m = 1 */
++#define SB2MIPS_T6(sb) (2 * (sb))
++
++/* Common clock base */
++#define CC_CLOCK_BASE1 24000000 /* Half the clock freq */
++#define CC_CLOCK_BASE2 12500000 /* Alternate crystal on some PLL's */
++
++/* Clock control values for 200Mhz in 5350 */
++#define CLKC_5350_N 0x0311
++#define CLKC_5350_M 0x04020009
++
++/* Flash types in the chipcommon capabilities register */
++#define FLASH_NONE 0x000 /* No flash */
++#define SFLASH_ST 0x100 /* ST serial flash */
++#define SFLASH_AT 0x200 /* Atmel serial flash */
++#define PFLASH 0x700 /* Parallel flash */
++
++/* Bits in the ExtBus config registers */
++#define CC_CFG_EN 0x0001 /* Enable */
++#define CC_CFG_EM_MASK 0x000e /* Extif Mode */
++#define CC_CFG_EM_ASYNC 0x0000 /* Async/Parallel flash */
++#define CC_CFG_EM_SYNC 0x0002 /* Synchronous */
++#define CC_CFG_EM_PCMCIA 0x0004 /* PCMCIA */
++#define CC_CFG_EM_IDE 0x0006 /* IDE */
++#define CC_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */
++#define CC_CFG_CD_MASK 0x0060 /* Sync: Clock divisor */
++#define CC_CFG_CE 0x0080 /* Sync: Clock enable */
++#define CC_CFG_SB 0x0100 /* Sync: Size/Bytestrobe */
++
++/* ExtBus address space */
++#define CC_EB_BASE 0x1a000000 /* Chipc ExtBus base address */
++#define CC_EB_PCMCIA_MEM 0x1a000000 /* PCMCIA 0 memory base address */
++#define CC_EB_PCMCIA_IO 0x1a200000 /* PCMCIA 0 I/O base address */
++#define CC_EB_PCMCIA_CFG 0x1a400000 /* PCMCIA 0 config base address */
++#define CC_EB_IDE 0x1a800000 /* IDE memory base */
++#define CC_EB_PCMCIA1_MEM 0x1a800000 /* PCMCIA 1 memory base address */
++#define CC_EB_PCMCIA1_IO 0x1aa00000 /* PCMCIA 1 I/O base address */
++#define CC_EB_PCMCIA1_CFG 0x1ac00000 /* PCMCIA 1 config base address */
++#define CC_EB_PROGIF 0x1b000000 /* ProgIF Async/Sync base address */
++
++
++/* Start/busy bit in flashcontrol */
++#define SFLASH_OPCODE 0x000000ff
++#define SFLASH_ACTION 0x00000700
++#define SFLASH_START 0x80000000
++#define SFLASH_BUSY SFLASH_START
++
++/* flashcontrol action codes */
++#define SFLASH_ACT_OPONLY 0x0000 /* Issue opcode only */
++#define SFLASH_ACT_OP1D 0x0100 /* opcode + 1 data byte */
++#define SFLASH_ACT_OP3A 0x0200 /* opcode + 3 address bytes */
++#define SFLASH_ACT_OP3A1D 0x0300 /* opcode + 3 addres & 1 data bytes */
++#define SFLASH_ACT_OP3A4D 0x0400 /* opcode + 3 addres & 4 data bytes */
++#define SFLASH_ACT_OP3A4X4D 0x0500 /* opcode + 3 addres, 4 don't care & 4 data bytes */
++#define SFLASH_ACT_OP3A1X4D 0x0700 /* opcode + 3 addres, 1 don't care & 4 data bytes */
++
++/* flashcontrol action+opcodes for ST flashes */
++#define SFLASH_ST_WREN 0x0006 /* Write Enable */
++#define SFLASH_ST_WRDIS 0x0004 /* Write Disable */
++#define SFLASH_ST_RDSR 0x0105 /* Read Status Register */
++#define SFLASH_ST_WRSR 0x0101 /* Write Status Register */
++#define SFLASH_ST_READ 0x0303 /* Read Data Bytes */
++#define SFLASH_ST_PP 0x0302 /* Page Program */
++#define SFLASH_ST_SE 0x02d8 /* Sector Erase */
++#define SFLASH_ST_BE 0x00c7 /* Bulk Erase */
++#define SFLASH_ST_DP 0x00b9 /* Deep Power-down */
++#define SFLASH_ST_RES 0x03ab /* Read Electronic Signature */
++
++/* Status register bits for ST flashes */
++#define SFLASH_ST_WIP 0x01 /* Write In Progress */
++#define SFLASH_ST_WEL 0x02 /* Write Enable Latch */
++#define SFLASH_ST_BP_MASK 0x1c /* Block Protect */
++#define SFLASH_ST_BP_SHIFT 2
++#define SFLASH_ST_SRWD 0x80 /* Status Register Write Disable */
++
++/* flashcontrol action+opcodes for Atmel flashes */
++#define SFLASH_AT_READ 0x07e8
++#define SFLASH_AT_PAGE_READ 0x07d2
++#define SFLASH_AT_BUF1_READ
++#define SFLASH_AT_BUF2_READ
++#define SFLASH_AT_STATUS 0x01d7
++#define SFLASH_AT_BUF1_WRITE 0x0384
++#define SFLASH_AT_BUF2_WRITE 0x0387
++#define SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283
++#define SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286
++#define SFLASH_AT_BUF1_PROGRAM 0x0288
++#define SFLASH_AT_BUF2_PROGRAM 0x0289
++#define SFLASH_AT_PAGE_ERASE 0x0281
++#define SFLASH_AT_BLOCK_ERASE 0x0250
++#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382
++#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385
++#define SFLASH_AT_BUF1_LOAD 0x0253
++#define SFLASH_AT_BUF2_LOAD 0x0255
++#define SFLASH_AT_BUF1_COMPARE 0x0260
++#define SFLASH_AT_BUF2_COMPARE 0x0261
++#define SFLASH_AT_BUF1_REPROGRAM 0x0258
++#define SFLASH_AT_BUF2_REPROGRAM 0x0259
++
++/* Status register bits for Atmel flashes */
++#define SFLASH_AT_READY 0x80
++#define SFLASH_AT_MISMATCH 0x40
++#define SFLASH_AT_ID_MASK 0x38
++#define SFLASH_AT_ID_SHIFT 3
++
++/* OTP regions */
++#define OTP_HW_REGION OTPS_HW_PROTECT
++#define OTP_SW_REGION OTPS_SW_PROTECT
++#define OTP_CID_REGION OTPS_CID_PROTECT
++
++/* OTP regions (Byte offsets from otp size) */
++#define OTP_SWLIM_OFF (-8)
++#define OTP_CIDBASE_OFF 0
++#define OTP_CIDLIM_OFF 8
++
++/* Predefined OTP words (Word offset from otp size) */
++#define OTP_BOUNDARY_OFF (-4)
++#define OTP_HWSIGN_OFF (-3)
++#define OTP_SWSIGN_OFF (-2)
++#define OTP_CIDSIGN_OFF (-1)
++
++#define OTP_CID_OFF 0
++#define OTP_PKG_OFF 1
++#define OTP_FID_OFF 2
++#define OTP_RSV_OFF 3
++#define OTP_LIM_OFF 4
++
++#define OTP_SIGNATURE 0x578a
++#define OTP_MAGIC 0x4e56
++
++/*
++ * These are the UART port assignments, expressed as offsets from the base
++ * register. These assignments should hold for any serial port based on
++ * a 8250, 16450, or 16550(A).
++ */
++
++#define UART_RX 0 /* In: Receive buffer (DLAB=0) */
++#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */
++#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */
++#define UART_IER 1 /* In/Out: Interrupt Enable Register (DLAB=0) */
++#define UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */
++#define UART_IIR 2 /* In: Interrupt Identity Register */
++#define UART_FCR 2 /* Out: FIFO Control Register */
++#define UART_LCR 3 /* Out: Line Control Register */
++#define UART_MCR 4 /* Out: Modem Control Register */
++#define UART_LSR 5 /* In: Line Status Register */
++#define UART_MSR 6 /* In: Modem Status Register */
++#define UART_SCR 7 /* I/O: Scratch Register */
++#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
++#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
++#define UART_MCR_OUT2 0x08 /* MCR GPIO out 2 */
++#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
++#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
++#define UART_LSR_RXRDY 0x01 /* Receiver ready */
++#define UART_FCR_FIFO_ENABLE 1 /* FIFO control register bit controlling FIFO enable/disable */
++
++/* Interrupt Enable Register (IER) bits */
++#define UART_IER_EDSSI 8 /* enable modem status interrupt */
++#define UART_IER_ELSI 4 /* enable receiver line status interrupt */
++#define UART_IER_ETBEI 2 /* enable transmitter holding register empty interrupt */
++#define UART_IER_ERBFI 1 /* enable data available interrupt */
++
++#endif /* _SBCHIPC_H */
+diff -urN linux.old/arch/mips/bcm947xx/include/sbconfig.h linux.dev/arch/mips/bcm947xx/include/sbconfig.h
+--- linux.old/arch/mips/bcm947xx/include/sbconfig.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbconfig.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,369 @@
++/*
++ * Broadcom SiliconBackplane hardware register definitions.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: sbconfig.h,v 1.1.1.11 2006/02/27 03:43:16 honor Exp $
++ */
++
++#ifndef _SBCONFIG_H
++#define _SBCONFIG_H
++
++/* cpp contortions to concatenate w/arg prescan */
++#ifndef PAD
++#define _PADLINE(line) pad ## line
++#define _XSTR(line) _PADLINE(line)
++#define PAD _XSTR(__LINE__)
++#endif
++
++/*
++ * SiliconBackplane Address Map.
++ * All regions may not exist on all chips.
++ */
++#define SB_SDRAM_BASE 0x00000000 /* Physical SDRAM */
++#define SB_PCI_MEM 0x08000000 /* Host Mode sb2pcitranslation0 (64 MB) */
++#define SB_PCI_MEM_SZ (64 * 1024 * 1024)
++#define SB_PCI_CFG 0x0c000000 /* Host Mode sb2pcitranslation1 (64 MB) */
++#define SB_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */
++#define SB_ENUM_BASE 0x18000000 /* Enumeration space base */
++#define SB_ENUM_LIM 0x18010000 /* Enumeration space limit */
++
++#define SB_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */
++#define SB_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */
++
++#define SB_EXTIF_BASE 0x1f000000 /* External Interface region base address */
++#define SB_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */
++#define SB_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */
++
++#define SB_ROM 0x20000000 /* ARM ROM */
++#define SB_SRAM2 0x80000000 /* ARM SRAM Region 2 */
++#define SB_ARM_FLASH1 0xffff0000 /* ARM Flash Region 1 */
++#define SB_ARM_FLASH1_SZ 0x00010000 /* ARM Size of Flash Region 1 */
++
++#define SB_PCI_DMA 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */
++#define SB_PCI_DMA_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */
++#define SB_PCIE_DMA_L32 0x00000000 /* PCIE Client Mode sb2pcitranslation2
++ * (2 ZettaBytes), low 32 bits
++ */
++#define SB_PCIE_DMA_H32 0x80000000 /* PCIE Client Mode sb2pcitranslation2
++ * (2 ZettaBytes), high 32 bits
++ */
++#define SB_EUART (SB_EXTIF_BASE + 0x00800000)
++#define SB_LED (SB_EXTIF_BASE + 0x00900000)
++
++
++/* enumeration space related defs */
++#define SB_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */
++#define SB_MAXCORES ((SB_ENUM_LIM - SB_ENUM_BASE)/SB_CORE_SIZE)
++#define SB_MAXFUNCS 4 /* max. # functions per core */
++#define SBCONFIGOFF 0xf00 /* core sbconfig regs are top 256bytes of regs */
++#define SBCONFIGSIZE 256 /* sizeof (sbconfig_t) */
++
++/* mips address */
++#define SB_EJTAG 0xff200000 /* MIPS EJTAG space (2M) */
++
++/*
++ * Sonics Configuration Space Registers.
++ */
++#define SBIPSFLAG 0x08
++#define SBTPSFLAG 0x18
++#define SBTMERRLOGA 0x48 /* sonics >= 2.3 */
++#define SBTMERRLOG 0x50 /* sonics >= 2.3 */
++#define SBADMATCH3 0x60
++#define SBADMATCH2 0x68
++#define SBADMATCH1 0x70
++#define SBIMSTATE 0x90
++#define SBINTVEC 0x94
++#define SBTMSTATELOW 0x98
++#define SBTMSTATEHIGH 0x9c
++#define SBBWA0 0xa0
++#define SBIMCONFIGLOW 0xa8
++#define SBIMCONFIGHIGH 0xac
++#define SBADMATCH0 0xb0
++#define SBTMCONFIGLOW 0xb8
++#define SBTMCONFIGHIGH 0xbc
++#define SBBCONFIG 0xc0
++#define SBBSTATE 0xc8
++#define SBACTCNFG 0xd8
++#define SBFLAGST 0xe8
++#define SBIDLOW 0xf8
++#define SBIDHIGH 0xfc
++
++/* All the previous registers are above SBCONFIGOFF, but with Sonics 2.3, we have
++ * a few registers *below* that line. I think it would be very confusing to try
++ * and change the value of SBCONFIGOFF, so I'm definig them as absolute offsets here,
++ */
++
++#define SBIMERRLOGA 0xea8
++#define SBIMERRLOG 0xeb0
++#define SBTMPORTCONNID0 0xed8
++#define SBTMPORTLOCK0 0xef8
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++typedef volatile struct _sbconfig {
++ uint32 PAD[2];
++ uint32 sbipsflag; /* initiator port ocp slave flag */
++ uint32 PAD[3];
++ uint32 sbtpsflag; /* target port ocp slave flag */
++ uint32 PAD[11];
++ uint32 sbtmerrloga; /* (sonics >= 2.3) */
++ uint32 PAD;
++ uint32 sbtmerrlog; /* (sonics >= 2.3) */
++ uint32 PAD[3];
++ uint32 sbadmatch3; /* address match3 */
++ uint32 PAD;
++ uint32 sbadmatch2; /* address match2 */
++ uint32 PAD;
++ uint32 sbadmatch1; /* address match1 */
++ uint32 PAD[7];
++ uint32 sbimstate; /* initiator agent state */
++ uint32 sbintvec; /* interrupt mask */
++ uint32 sbtmstatelow; /* target state */
++ uint32 sbtmstatehigh; /* target state */
++ uint32 sbbwa0; /* bandwidth allocation table0 */
++ uint32 PAD;
++ uint32 sbimconfiglow; /* initiator configuration */
++ uint32 sbimconfighigh; /* initiator configuration */
++ uint32 sbadmatch0; /* address match0 */
++ uint32 PAD;
++ uint32 sbtmconfiglow; /* target configuration */
++ uint32 sbtmconfighigh; /* target configuration */
++ uint32 sbbconfig; /* broadcast configuration */
++ uint32 PAD;
++ uint32 sbbstate; /* broadcast state */
++ uint32 PAD[3];
++ uint32 sbactcnfg; /* activate configuration */
++ uint32 PAD[3];
++ uint32 sbflagst; /* current sbflags */
++ uint32 PAD[3];
++ uint32 sbidlow; /* identification */
++ uint32 sbidhigh; /* identification */
++} sbconfig_t;
++
++#endif /* _LANGUAGE_ASSEMBLY */
++
++/* sbipsflag */
++#define SBIPS_INT1_MASK 0x3f /* which sbflags get routed to mips interrupt 1 */
++#define SBIPS_INT1_SHIFT 0
++#define SBIPS_INT2_MASK 0x3f00 /* which sbflags get routed to mips interrupt 2 */
++#define SBIPS_INT2_SHIFT 8
++#define SBIPS_INT3_MASK 0x3f0000 /* which sbflags get routed to mips interrupt 3 */
++#define SBIPS_INT3_SHIFT 16
++#define SBIPS_INT4_MASK 0x3f000000 /* which sbflags get routed to mips interrupt 4 */
++#define SBIPS_INT4_SHIFT 24
++
++/* sbtpsflag */
++#define SBTPS_NUM0_MASK 0x3f /* interrupt sbFlag # generated by this core */
++#define SBTPS_F0EN0 0x40 /* interrupt is always sent on the backplane */
++
++/* sbtmerrlog */
++#define SBTMEL_CM 0x00000007 /* command */
++#define SBTMEL_CI 0x0000ff00 /* connection id */
++#define SBTMEL_EC 0x0f000000 /* error code */
++#define SBTMEL_ME 0x80000000 /* multiple error */
++
++/* sbimstate */
++#define SBIM_PC 0xf /* pipecount */
++#define SBIM_AP_MASK 0x30 /* arbitration policy */
++#define SBIM_AP_BOTH 0x00 /* use both timeslaces and token */
++#define SBIM_AP_TS 0x10 /* use timesliaces only */
++#define SBIM_AP_TK 0x20 /* use token only */
++#define SBIM_AP_RSV 0x30 /* reserved */
++#define SBIM_IBE 0x20000 /* inbanderror */
++#define SBIM_TO 0x40000 /* timeout */
++#define SBIM_BY 0x01800000 /* busy (sonics >= 2.3) */
++#define SBIM_RJ 0x02000000 /* reject (sonics >= 2.3) */
++
++/* sbtmstatelow */
++#define SBTML_RESET 0x1 /* reset */
++#define SBTML_REJ_MASK 0x6 /* reject */
++#define SBTML_REJ_SHIFT 1
++#define SBTML_CLK 0x10000 /* clock enable */
++#define SBTML_FGC 0x20000 /* force gated clocks on */
++#define SBTML_FL_MASK 0x3ffc0000 /* core-specific flags */
++#define SBTML_PE 0x40000000 /* pme enable */
++#define SBTML_BE 0x80000000 /* bist enable */
++
++/* sbtmstatehigh */
++#define SBTMH_SERR 0x1 /* serror */
++#define SBTMH_INT 0x2 /* interrupt */
++#define SBTMH_BUSY 0x4 /* busy */
++#define SBTMH_TO 0x00000020 /* timeout (sonics >= 2.3) */
++#define SBTMH_FL_MASK 0x1fff0000 /* core-specific flags */
++#define SBTMH_DMA64 0x10000000 /* supports DMA with 64-bit addresses */
++#define SBTMH_GCR 0x20000000 /* gated clock request */
++#define SBTMH_BISTF 0x40000000 /* bist failed */
++#define SBTMH_BISTD 0x80000000 /* bist done */
++
++
++/* sbbwa0 */
++#define SBBWA_TAB0_MASK 0xffff /* lookup table 0 */
++#define SBBWA_TAB1_MASK 0xffff /* lookup table 1 */
++#define SBBWA_TAB1_SHIFT 16
++
++/* sbimconfiglow */
++#define SBIMCL_STO_MASK 0x7 /* service timeout */
++#define SBIMCL_RTO_MASK 0x70 /* request timeout */
++#define SBIMCL_RTO_SHIFT 4
++#define SBIMCL_CID_MASK 0xff0000 /* connection id */
++#define SBIMCL_CID_SHIFT 16
++
++/* sbimconfighigh */
++#define SBIMCH_IEM_MASK 0xc /* inband error mode */
++#define SBIMCH_TEM_MASK 0x30 /* timeout error mode */
++#define SBIMCH_TEM_SHIFT 4
++#define SBIMCH_BEM_MASK 0xc0 /* bus error mode */
++#define SBIMCH_BEM_SHIFT 6
++
++/* sbadmatch0 */
++#define SBAM_TYPE_MASK 0x3 /* address type */
++#define SBAM_AD64 0x4 /* reserved */
++#define SBAM_ADINT0_MASK 0xf8 /* type0 size */
++#define SBAM_ADINT0_SHIFT 3
++#define SBAM_ADINT1_MASK 0x1f8 /* type1 size */
++#define SBAM_ADINT1_SHIFT 3
++#define SBAM_ADINT2_MASK 0x1f8 /* type2 size */
++#define SBAM_ADINT2_SHIFT 3
++#define SBAM_ADEN 0x400 /* enable */
++#define SBAM_ADNEG 0x800 /* negative decode */
++#define SBAM_BASE0_MASK 0xffffff00 /* type0 base address */
++#define SBAM_BASE0_SHIFT 8
++#define SBAM_BASE1_MASK 0xfffff000 /* type1 base address for the core */
++#define SBAM_BASE1_SHIFT 12
++#define SBAM_BASE2_MASK 0xffff0000 /* type2 base address for the core */
++#define SBAM_BASE2_SHIFT 16
++
++/* sbtmconfiglow */
++#define SBTMCL_CD_MASK 0xff /* clock divide */
++#define SBTMCL_CO_MASK 0xf800 /* clock offset */
++#define SBTMCL_CO_SHIFT 11
++#define SBTMCL_IF_MASK 0xfc0000 /* interrupt flags */
++#define SBTMCL_IF_SHIFT 18
++#define SBTMCL_IM_MASK 0x3000000 /* interrupt mode */
++#define SBTMCL_IM_SHIFT 24
++
++/* sbtmconfighigh */
++#define SBTMCH_BM_MASK 0x3 /* busy mode */
++#define SBTMCH_RM_MASK 0x3 /* retry mode */
++#define SBTMCH_RM_SHIFT 2
++#define SBTMCH_SM_MASK 0x30 /* stop mode */
++#define SBTMCH_SM_SHIFT 4
++#define SBTMCH_EM_MASK 0x300 /* sb error mode */
++#define SBTMCH_EM_SHIFT 8
++#define SBTMCH_IM_MASK 0xc00 /* int mode */
++#define SBTMCH_IM_SHIFT 10
++
++/* sbbconfig */
++#define SBBC_LAT_MASK 0x3 /* sb latency */
++#define SBBC_MAX0_MASK 0xf0000 /* maxccntr0 */
++#define SBBC_MAX0_SHIFT 16
++#define SBBC_MAX1_MASK 0xf00000 /* maxccntr1 */
++#define SBBC_MAX1_SHIFT 20
++
++/* sbbstate */
++#define SBBS_SRD 0x1 /* st reg disable */
++#define SBBS_HRD 0x2 /* hold reg disable */
++
++/* sbidlow */
++#define SBIDL_CS_MASK 0x3 /* config space */
++#define SBIDL_AR_MASK 0x38 /* # address ranges supported */
++#define SBIDL_AR_SHIFT 3
++#define SBIDL_SYNCH 0x40 /* sync */
++#define SBIDL_INIT 0x80 /* initiator */
++#define SBIDL_MINLAT_MASK 0xf00 /* minimum backplane latency */
++#define SBIDL_MINLAT_SHIFT 8
++#define SBIDL_MAXLAT 0xf000 /* maximum backplane latency */
++#define SBIDL_MAXLAT_SHIFT 12
++#define SBIDL_FIRST 0x10000 /* this initiator is first */
++#define SBIDL_CW_MASK 0xc0000 /* cycle counter width */
++#define SBIDL_CW_SHIFT 18
++#define SBIDL_TP_MASK 0xf00000 /* target ports */
++#define SBIDL_TP_SHIFT 20
++#define SBIDL_IP_MASK 0xf000000 /* initiator ports */
++#define SBIDL_IP_SHIFT 24
++#define SBIDL_RV_MASK 0xf0000000 /* sonics backplane revision code */
++#define SBIDL_RV_SHIFT 28
++#define SBIDL_RV_2_2 0x00000000 /* version 2.2 or earlier */
++#define SBIDL_RV_2_3 0x10000000 /* version 2.3 */
++
++/* sbidhigh */
++#define SBIDH_RC_MASK 0x000f /* revision code */
++#define SBIDH_RCE_MASK 0x7000 /* revision code extension field */
++#define SBIDH_RCE_SHIFT 8
++#define SBCOREREV(sbidh) \
++ ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | ((sbidh) & SBIDH_RC_MASK))
++#define SBIDH_CC_MASK 0x8ff0 /* core code */
++#define SBIDH_CC_SHIFT 4
++#define SBIDH_VC_MASK 0xffff0000 /* vendor code */
++#define SBIDH_VC_SHIFT 16
++
++#define SB_COMMIT 0xfd8 /* update buffered registers value */
++
++/* vendor codes */
++#define SB_VEND_BCM 0x4243 /* Broadcom's SB vendor code */
++
++/* core codes */
++#define SB_NODEV 0x700 /* Invalid coreid */
++#define SB_CC 0x800 /* chipcommon core */
++#define SB_ILINE20 0x801 /* iline20 core */
++#define SB_SDRAM 0x803 /* sdram core */
++#define SB_PCI 0x804 /* pci core */
++#define SB_MIPS 0x805 /* mips core */
++#define SB_ENET 0x806 /* enet mac core */
++#define SB_CODEC 0x807 /* v90 codec core */
++#define SB_USB 0x808 /* usb 1.1 host/device core */
++#define SB_ADSL 0x809 /* ADSL core */
++#define SB_ILINE100 0x80a /* iline100 core */
++#define SB_IPSEC 0x80b /* ipsec core */
++#define SB_PCMCIA 0x80d /* pcmcia core */
++#define SB_SDIOD SB_PCMCIA /* pcmcia core has sdio device */
++#define SB_SOCRAM 0x80e /* internal memory core */
++#define SB_MEMC 0x80f /* memc sdram core */
++#define SB_EXTIF 0x811 /* external interface core */
++#define SB_D11 0x812 /* 802.11 MAC core */
++#define SB_MIPS33 0x816 /* mips3302 core */
++#define SB_USB11H 0x817 /* usb 1.1 host core */
++#define SB_USB11D 0x818 /* usb 1.1 device core */
++#define SB_USB20H 0x819 /* usb 2.0 host core */
++#define SB_USB20D 0x81a /* usb 2.0 device core */
++#define SB_SDIOH 0x81b /* sdio host core */
++#define SB_ROBO 0x81c /* roboswitch core */
++#define SB_ATA100 0x81d /* parallel ATA core */
++#define SB_SATAXOR 0x81e /* serial ATA & XOR DMA core */
++#define SB_GIGETH 0x81f /* gigabit ethernet core */
++#define SB_PCIE 0x820 /* pci express core */
++#define SB_MIMO 0x821 /* MIMO phy core */
++#define SB_SRAMC 0x822 /* SRAM controller core */
++#define SB_MINIMAC 0x823 /* MINI MAC/phy core */
++#define SB_ARM11 0x824 /* ARM 1176 core */
++#define SB_ARM7 0x825 /* ARM 7tdmi core */
++
++#define SB_CC_IDX 0 /* chipc, when present, is always core 0 */
++
++/* Not really related to Silicon Backplane, but a couple of software
++ * conventions for the use the flash space:
++ */
++
++/* Minumum amount of flash we support */
++#define FLASH_MIN 0x00020000 /* Minimum flash size */
++
++/* A boot/binary may have an embedded block that describes its size */
++#define BISZ_OFFSET 0x3e0 /* At this offset into the binary */
++#define BISZ_MAGIC 0x4249535a /* Marked with this value: 'BISZ' */
++#define BISZ_MAGIC_IDX 0 /* Word 0: magic */
++#define BISZ_TXTST_IDX 1 /* 1: text start */
++#define BISZ_TXTEND_IDX 2 /* 2: text start */
++#define BISZ_DATAST_IDX 3 /* 3: text start */
++#define BISZ_DATAEND_IDX 4 /* 4: text start */
++#define BISZ_BSSST_IDX 5 /* 5: text start */
++#define BISZ_BSSEND_IDX 6 /* 6: text start */
++#define BISZ_SIZE 7 /* descriptor size in 32-bit intergers */
++
++#endif /* _SBCONFIG_H */
+diff -urN linux.old/arch/mips/bcm947xx/include/sbextif.h linux.dev/arch/mips/bcm947xx/include/sbextif.h
+--- linux.old/arch/mips/bcm947xx/include/sbextif.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbextif.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,243 @@
++/*
++ * Hardware-specific External Interface I/O core definitions
++ * for the BCM47xx family of SiliconBackplane-based chips.
++ *
++ * The External Interface core supports a total of three external chip selects
++ * supporting external interfaces. One of the external chip selects is
++ * used for Flash, one is used for PCMCIA, and the other may be
++ * programmed to support either a synchronous interface or an
++ * asynchronous interface. The asynchronous interface can be used to
++ * support external devices such as UARTs and the BCM2019 Bluetooth
++ * baseband processor.
++ * The external interface core also contains 2 on-chip 16550 UARTs, clock
++ * frequency control, a watchdog interrupt timer, and a GPIO interface.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: sbextif.h,v 1.1.1.8 2006/02/27 03:43:16 honor Exp $
++ */
++
++#ifndef _SBEXTIF_H
++#define _SBEXTIF_H
++
++/* external interface address space */
++#define EXTIF_PCMCIA_MEMBASE(x) (x)
++#define EXTIF_PCMCIA_IOBASE(x) ((x) + 0x100000)
++#define EXTIF_PCMCIA_CFGBASE(x) ((x) + 0x200000)
++#define EXTIF_CFGIF_BASE(x) ((x) + 0x800000)
++#define EXTIF_FLASH_BASE(x) ((x) + 0xc00000)
++
++/* cpp contortions to concatenate w/arg prescan */
++#ifndef PAD
++#define _PADLINE(line) pad ## line
++#define _XSTR(line) _PADLINE(line)
++#define PAD _XSTR(__LINE__)
++#endif /* PAD */
++
++/*
++ * The multiple instances of output and output enable registers
++ * are present to allow driver software for multiple cores to control
++ * gpio outputs without needing to share a single register pair.
++ */
++struct gpiouser {
++ uint32 out;
++ uint32 outen;
++};
++#define NGPIOUSER 5
++
++typedef volatile struct {
++ uint32 corecontrol;
++ uint32 extstatus;
++ uint32 PAD[2];
++
++ /* pcmcia control registers */
++ uint32 pcmcia_config;
++ uint32 pcmcia_memwait;
++ uint32 pcmcia_attrwait;
++ uint32 pcmcia_iowait;
++
++ /* programmable interface control registers */
++ uint32 prog_config;
++ uint32 prog_waitcount;
++
++ /* flash control registers */
++ uint32 flash_config;
++ uint32 flash_waitcount;
++ uint32 PAD[4];
++
++ uint32 watchdog;
++
++ /* clock control */
++ uint32 clockcontrol_n;
++ uint32 clockcontrol_sb;
++ uint32 clockcontrol_pci;
++ uint32 clockcontrol_mii;
++ uint32 PAD[3];
++
++ /* gpio */
++ uint32 gpioin;
++ struct gpiouser gpio[NGPIOUSER];
++ uint32 PAD;
++ uint32 ejtagouten;
++ uint32 gpiointpolarity;
++ uint32 gpiointmask;
++ uint32 PAD[153];
++
++ uint8 uartdata;
++ uint8 PAD[3];
++ uint8 uartimer;
++ uint8 PAD[3];
++ uint8 uartfcr;
++ uint8 PAD[3];
++ uint8 uartlcr;
++ uint8 PAD[3];
++ uint8 uartmcr;
++ uint8 PAD[3];
++ uint8 uartlsr;
++ uint8 PAD[3];
++ uint8 uartmsr;
++ uint8 PAD[3];
++ uint8 uartscratch;
++ uint8 PAD[3];
++} extifregs_t;
++
++/* corecontrol */
++#define CC_UE (1 << 0) /* uart enable */
++
++/* extstatus */
++#define ES_EM (1 << 0) /* endian mode (ro) */
++#define ES_EI (1 << 1) /* external interrupt pin (ro) */
++#define ES_GI (1 << 2) /* gpio interrupt pin (ro) */
++
++/* gpio bit mask */
++#define GPIO_BIT0 (1 << 0)
++#define GPIO_BIT1 (1 << 1)
++#define GPIO_BIT2 (1 << 2)
++#define GPIO_BIT3 (1 << 3)
++#define GPIO_BIT4 (1 << 4)
++#define GPIO_BIT5 (1 << 5)
++#define GPIO_BIT6 (1 << 6)
++#define GPIO_BIT7 (1 << 7)
++
++
++/* pcmcia/prog/flash_config */
++#define CF_EN (1 << 0) /* enable */
++#define CF_EM_MASK 0xe /* mode */
++#define CF_EM_SHIFT 1
++#define CF_EM_FLASH 0x0 /* flash/asynchronous mode */
++#define CF_EM_SYNC 0x2 /* synchronous mode */
++#define CF_EM_PCMCIA 0x4 /* pcmcia mode */
++#define CF_DS (1 << 4) /* destsize: 0=8bit, 1=16bit */
++#define CF_BS (1 << 5) /* byteswap */
++#define CF_CD_MASK 0xc0 /* clock divider */
++#define CF_CD_SHIFT 6
++#define CF_CD_DIV2 0x0 /* backplane/2 */
++#define CF_CD_DIV3 0x40 /* backplane/3 */
++#define CF_CD_DIV4 0x80 /* backplane/4 */
++#define CF_CE (1 << 8) /* clock enable */
++#define CF_SB (1 << 9) /* size/bytestrobe (synch only) */
++
++/* pcmcia_memwait */
++#define PM_W0_MASK 0x3f /* waitcount0 */
++#define PM_W1_MASK 0x1f00 /* waitcount1 */
++#define PM_W1_SHIFT 8
++#define PM_W2_MASK 0x1f0000 /* waitcount2 */
++#define PM_W2_SHIFT 16
++#define PM_W3_MASK 0x1f000000 /* waitcount3 */
++#define PM_W3_SHIFT 24
++
++/* pcmcia_attrwait */
++#define PA_W0_MASK 0x3f /* waitcount0 */
++#define PA_W1_MASK 0x1f00 /* waitcount1 */
++#define PA_W1_SHIFT 8
++#define PA_W2_MASK 0x1f0000 /* waitcount2 */
++#define PA_W2_SHIFT 16
++#define PA_W3_MASK 0x1f000000 /* waitcount3 */
++#define PA_W3_SHIFT 24
++
++/* pcmcia_iowait */
++#define PI_W0_MASK 0x3f /* waitcount0 */
++#define PI_W1_MASK 0x1f00 /* waitcount1 */
++#define PI_W1_SHIFT 8
++#define PI_W2_MASK 0x1f0000 /* waitcount2 */
++#define PI_W2_SHIFT 16
++#define PI_W3_MASK 0x1f000000 /* waitcount3 */
++#define PI_W3_SHIFT 24
++
++/* prog_waitcount */
++#define PW_W0_MASK 0x0000001f /* waitcount0 */
++#define PW_W1_MASK 0x00001f00 /* waitcount1 */
++#define PW_W1_SHIFT 8
++#define PW_W2_MASK 0x001f0000 /* waitcount2 */
++#define PW_W2_SHIFT 16
++#define PW_W3_MASK 0x1f000000 /* waitcount3 */
++#define PW_W3_SHIFT 24
++
++#define PW_W0 0x0000000c
++#define PW_W1 0x00000a00
++#define PW_W2 0x00020000
++#define PW_W3 0x01000000
++
++/* flash_waitcount */
++#define FW_W0_MASK 0x1f /* waitcount0 */
++#define FW_W1_MASK 0x1f00 /* waitcount1 */
++#define FW_W1_SHIFT 8
++#define FW_W2_MASK 0x1f0000 /* waitcount2 */
++#define FW_W2_SHIFT 16
++#define FW_W3_MASK 0x1f000000 /* waitcount3 */
++#define FW_W3_SHIFT 24
++
++/* watchdog */
++#define WATCHDOG_CLOCK 48000000 /* Hz */
++
++/* clockcontrol_n */
++#define CN_N1_MASK 0x3f /* n1 control */
++#define CN_N2_MASK 0x3f00 /* n2 control */
++#define CN_N2_SHIFT 8
++
++/* clockcontrol_sb/pci/mii */
++#define CC_M1_MASK 0x3f /* m1 control */
++#define CC_M2_MASK 0x3f00 /* m2 control */
++#define CC_M2_SHIFT 8
++#define CC_M3_MASK 0x3f0000 /* m3 control */
++#define CC_M3_SHIFT 16
++#define CC_MC_MASK 0x1f000000 /* mux control */
++#define CC_MC_SHIFT 24
++
++/* Clock control default values */
++#define CC_DEF_N 0x0009 /* Default values for bcm4710 */
++#define CC_DEF_100 0x04020011
++#define CC_DEF_33 0x11030011
++#define CC_DEF_25 0x11050011
++
++/* Clock control values for 125Mhz */
++#define CC_125_N 0x0802
++#define CC_125_M 0x04020009
++#define CC_125_M25 0x11090009
++#define CC_125_M33 0x11090005
++
++/* Clock control magic field values */
++#define CC_F6_2 0x02 /* A factor of 2 in */
++#define CC_F6_3 0x03 /* 6-bit fields like */
++#define CC_F6_4 0x05 /* N1, M1 or M3 */
++#define CC_F6_5 0x09
++#define CC_F6_6 0x11
++#define CC_F6_7 0x21
++
++#define CC_F5_BIAS 5 /* 5-bit fields get this added */
++
++#define CC_MC_BYPASS 0x08
++#define CC_MC_M1 0x04
++#define CC_MC_M1M2 0x02
++#define CC_MC_M1M2M3 0x01
++#define CC_MC_M1M3 0x11
++
++#define CC_CLOCK_BASE 24000000 /* Half the clock freq. in the 4710 */
++
++#endif /* _SBEXTIF_H */
+diff -urN linux.old/arch/mips/bcm947xx/include/sbhndmips.h linux.dev/arch/mips/bcm947xx/include/sbhndmips.h
+--- linux.old/arch/mips/bcm947xx/include/sbhndmips.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbhndmips.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,47 @@
++/*
++ * Broadcom SiliconBackplane MIPS definitions
++ *
++ * SB MIPS cores are custom MIPS32 processors with SiliconBackplane
++ * OCP interfaces. The CP0 processor ID is 0x00024000, where bits
++ * 23:16 mean Broadcom and bits 15:8 mean a MIPS core with an OCP
++ * interface. The core revision is stored in the SB ID register in SB
++ * configuration space.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: sbhndmips.h,v 1.1.1.1 2006/02/27 03:43:16 honor Exp $
++ */
++
++#ifndef _sbhndmips_h_
++#define _sbhndmips_h_
++
++#include <mipsinc.h>
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++/* cpp contortions to concatenate w/arg prescan */
++#ifndef PAD
++#define _PADLINE(line) pad ## line
++#define _XSTR(line) _PADLINE(line)
++#define PAD _XSTR(__LINE__)
++#endif /* PAD */
++
++typedef volatile struct {
++ uint32 corecontrol;
++ uint32 PAD[2];
++ uint32 biststatus;
++ uint32 PAD[4];
++ uint32 intstatus;
++ uint32 intmask;
++ uint32 timer;
++} mipsregs_t;
++
++#endif /* _LANGUAGE_ASSEMBLY */
++
++#endif /* _sbhndmips_h_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/sbmemc.h linux.dev/arch/mips/bcm947xx/include/sbmemc.h
+--- linux.old/arch/mips/bcm947xx/include/sbmemc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbmemc.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,147 @@
++/*
++ * BCM47XX Sonics SiliconBackplane DDR/SDRAM controller core hardware definitions.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: sbmemc.h,v 1.6 2006/03/02 12:33:44 honor Exp $
++ */
++
++#ifndef _SBMEMC_H
++#define _SBMEMC_H
++
++#ifdef _LANGUAGE_ASSEMBLY
++
++#define MEMC_CONTROL 0x00
++#define MEMC_CONFIG 0x04
++#define MEMC_REFRESH 0x08
++#define MEMC_BISTSTAT 0x0c
++#define MEMC_MODEBUF 0x10
++#define MEMC_BKCLS 0x14
++#define MEMC_PRIORINV 0x18
++#define MEMC_DRAMTIM 0x1c
++#define MEMC_INTSTAT 0x20
++#define MEMC_INTMASK 0x24
++#define MEMC_INTINFO 0x28
++#define MEMC_NCDLCTL 0x30
++#define MEMC_RDNCDLCOR 0x34
++#define MEMC_WRNCDLCOR 0x38
++#define MEMC_MISCDLYCTL 0x3c
++#define MEMC_DQSGATENCDL 0x40
++#define MEMC_SPARE 0x44
++#define MEMC_TPADDR 0x48
++#define MEMC_TPDATA 0x4c
++#define MEMC_BARRIER 0x50
++#define MEMC_CORE 0x54
++
++#else /* !_LANGUAGE_ASSEMBLY */
++
++/* Sonics side: MEMC core registers */
++typedef volatile struct sbmemcregs {
++ uint32 control;
++ uint32 config;
++ uint32 refresh;
++ uint32 biststat;
++ uint32 modebuf;
++ uint32 bkcls;
++ uint32 priorinv;
++ uint32 dramtim;
++ uint32 intstat;
++ uint32 intmask;
++ uint32 intinfo;
++ uint32 reserved1;
++ uint32 ncdlctl;
++ uint32 rdncdlcor;
++ uint32 wrncdlcor;
++ uint32 miscdlyctl;
++ uint32 dqsgatencdl;
++ uint32 spare;
++ uint32 tpaddr;
++ uint32 tpdata;
++ uint32 barrier;
++ uint32 core;
++} sbmemcregs_t;
++
++#endif /* _LANGUAGE_ASSEMBLY */
++
++/* MEMC Core Init values (OCP ID 0x80f) */
++
++/* For sdr: */
++#define MEMC_SD_CONFIG_INIT 0x00048000
++#define MEMC_SD_DRAMTIM2_INIT 0x000754d8
++#define MEMC_SD_DRAMTIM3_INIT 0x000754da
++#define MEMC_SD_RDNCDLCOR_INIT 0x00000000
++#define MEMC_SD_WRNCDLCOR_INIT 0x49351200
++#define MEMC_SD1_WRNCDLCOR_INIT 0x14500200 /* For corerev 1 (4712) */
++#define MEMC_SD_MISCDLYCTL_INIT 0x00061c1b
++#define MEMC_SD1_MISCDLYCTL_INIT 0x00021416 /* For corerev 1 (4712) */
++#define MEMC_SD_CONTROL_INIT0 0x00000002
++#define MEMC_SD_CONTROL_INIT1 0x00000008
++#define MEMC_SD_CONTROL_INIT2 0x00000004
++#define MEMC_SD_CONTROL_INIT3 0x00000010
++#define MEMC_SD_CONTROL_INIT4 0x00000001
++#define MEMC_SD_MODEBUF_INIT 0x00000000
++#define MEMC_SD_REFRESH_INIT 0x0000840f
++
++
++/* This is for SDRM8X8X4 */
++#define MEMC_SDR_INIT 0x0008
++#define MEMC_SDR_MODE 0x32
++#define MEMC_SDR_NCDL 0x00020032
++#define MEMC_SDR1_NCDL 0x0002020f /* For corerev 1 (4712) */
++
++/* For ddr: */
++#define MEMC_CONFIG_INIT 0x00048000
++#define MEMC_DRAMTIM2_INIT 0x000754d8
++#define MEMC_DRAMTIM25_INIT 0x000754d9
++#define MEMC_RDNCDLCOR_INIT 0x00000000
++#define MEMC_RDNCDLCOR_SIMINIT 0xf6f6f6f6 /* For hdl sim */
++#define MEMC_WRNCDLCOR_INIT 0x49351200
++#define MEMC_1_WRNCDLCOR_INIT 0x14500200
++#define MEMC_DQSGATENCDL_INIT 0x00030000
++#define MEMC_MISCDLYCTL_INIT 0x21061c1b
++#define MEMC_1_MISCDLYCTL_INIT 0x21021400
++#define MEMC_NCDLCTL_INIT 0x00002001
++#define MEMC_CONTROL_INIT0 0x00000002
++#define MEMC_CONTROL_INIT1 0x00000008
++#define MEMC_MODEBUF_INIT0 0x00004000
++#define MEMC_CONTROL_INIT2 0x00000010
++#define MEMC_MODEBUF_INIT1 0x00000100
++#define MEMC_CONTROL_INIT3 0x00000010
++#define MEMC_CONTROL_INIT4 0x00000008
++#define MEMC_REFRESH_INIT 0x0000840f
++#define MEMC_CONTROL_INIT5 0x00000004
++#define MEMC_MODEBUF_INIT2 0x00000000
++#define MEMC_CONTROL_INIT6 0x00000010
++#define MEMC_CONTROL_INIT7 0x00000001
++
++
++/* This is for DDRM16X16X2 */
++#define MEMC_DDR_INIT 0x0009
++#define MEMC_DDR_MODE 0x62
++#define MEMC_DDR_NCDL 0x0005050a
++#define MEMC_DDR1_NCDL 0x00000a0a /* For corerev 1 (4712) */
++
++/* mask for sdr/ddr calibration registers */
++#define MEMC_RDNCDLCOR_RD_MASK 0x000000ff
++#define MEMC_WRNCDLCOR_WR_MASK 0x000000ff
++#define MEMC_DQSGATENCDL_G_MASK 0x000000ff
++
++/* masks for miscdlyctl registers */
++#define MEMC_MISC_SM_MASK 0x30000000
++#define MEMC_MISC_SM_SHIFT 28
++#define MEMC_MISC_SD_MASK 0x0f000000
++#define MEMC_MISC_SD_SHIFT 24
++
++/* hw threshhold for calculating wr/rd for sdr memc */
++#define MEMC_CD_THRESHOLD 128
++
++/* Low bit of init register says if memc is ddr or sdr */
++#define MEMC_CONFIG_DDR 0x00000001
++
++#endif /* _SBMEMC_H */
+diff -urN linux.old/arch/mips/bcm947xx/include/sbpcie.h linux.dev/arch/mips/bcm947xx/include/sbpcie.h
+--- linux.old/arch/mips/bcm947xx/include/sbpcie.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbpcie.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,200 @@
++/*
++ * BCM43XX SiliconBackplane PCIE core hardware definitions.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: sbpcie.h,v 1.1.1.2 2006/02/27 03:43:16 honor Exp $
++ */
++
++#ifndef _SBPCIE_H
++#define _SBPCIE_H
++
++/* cpp contortions to concatenate w/arg prescan */
++#ifndef PAD
++#define _PADLINE(line) pad ## line
++#define _XSTR(line) _PADLINE(line)
++#define PAD _XSTR(__LINE__)
++#endif
++
++/* PCIE Enumeration space offsets */
++#define PCIE_CORE_CONFIG_OFFSET 0x0
++#define PCIE_FUNC0_CONFIG_OFFSET 0x400
++#define PCIE_FUNC1_CONFIG_OFFSET 0x500
++#define PCIE_FUNC2_CONFIG_OFFSET 0x600
++#define PCIE_FUNC3_CONFIG_OFFSET 0x700
++#define PCIE_SPROM_SHADOW_OFFSET 0x800
++#define PCIE_SBCONFIG_OFFSET 0xE00
++
++/* PCIE Bar0 Address Mapping. Each function maps 16KB config space */
++#define PCIE_DEV_BAR0_SIZE 0x4000
++#define PCIE_BAR0_WINMAPCORE_OFFSET 0x0
++#define PCIE_BAR0_EXTSPROM_OFFSET 0x1000
++#define PCIE_BAR0_PCIECORE_OFFSET 0x2000
++#define PCIE_BAR0_CCCOREREG_OFFSET 0x3000
++
++/* SB side: PCIE core and host control registers */
++typedef struct sbpcieregs {
++ uint32 PAD[3];
++ uint32 biststatus; /* bist Status: 0x00C */
++ uint32 PAD[6];
++ uint32 sbtopcimailbox; /* sb to pcie mailbox: 0x028 */
++ uint32 PAD[54];
++ uint32 sbtopcie0; /* sb to pcie translation 0: 0x100 */
++ uint32 sbtopcie1; /* sb to pcie translation 1: 0x104 */
++ uint32 sbtopcie2; /* sb to pcie translation 2: 0x108 */
++ uint32 PAD[4];
++
++ /* pcie core supports in direct access to config space */
++ uint32 configaddr; /* pcie config space access: Address field: 0x120 */
++ uint32 configdata; /* pcie config space access: Data field: 0x124 */
++
++ /* mdio access to serdes */
++ uint32 mdiocontrol; /* controls the mdio access: 0x128 */
++ uint32 mdiodata; /* Data to the mdio access: 0x12c */
++
++ /* pcie protocol phy/dllp/tlp register access mechanism */
++ uint32 pcieaddr; /* address of the internal registeru: 0x130 */
++ uint32 pciedata; /* Data to/from the internal regsiter: 0x134 */
++
++ uint32 PAD[434];
++ uint16 sprom[36]; /* SPROM shadow Area */
++} sbpcieregs_t;
++
++/* SB to PCIE translation masks */
++#define SBTOPCIE0_MASK 0xfc000000
++#define SBTOPCIE1_MASK 0xfc000000
++#define SBTOPCIE2_MASK 0xc0000000
++
++/* Access type bits (0:1) */
++#define SBTOPCIE_MEM 0
++#define SBTOPCIE_IO 1
++#define SBTOPCIE_CFG0 2
++#define SBTOPCIE_CFG1 3
++
++/* Prefetch enable bit 2 */
++#define SBTOPCIE_PF 4
++
++/* Write Burst enable for memory write bit 3 */
++#define SBTOPCIE_WR_BURST 8
++
++/* config access */
++#define CONFIGADDR_FUNC_MASK 0x7000
++#define CONFIGADDR_FUNC_SHF 12
++#define CONFIGADDR_REG_MASK 0x0FFF
++#define CONFIGADDR_REG_SHF 0
++
++/* PCIE protocol regs Indirect Address */
++#define PCIEADDR_PROT_MASK 0x300
++#define PCIEADDR_PROT_SHF 8
++#define PCIEADDR_PL_TLP 0
++#define PCIEADDR_PL_DLLP 1
++#define PCIEADDR_PL_PLP 2
++
++/* PCIE protocol PHY diagnostic registers */
++#define PCIE_PLP_MODEREG 0x200 /* Mode */
++#define PCIE_PLP_STATUSREG 0x204 /* Status */
++#define PCIE_PLP_LTSSMCTRLREG 0x208 /* LTSSM control */
++#define PCIE_PLP_LTLINKNUMREG 0x20c /* Link Training Link number */
++#define PCIE_PLP_LTLANENUMREG 0x210 /* Link Training Lane number */
++#define PCIE_PLP_LTNFTSREG 0x214 /* Link Training N_FTS */
++#define PCIE_PLP_ATTNREG 0x218 /* Attention */
++#define PCIE_PLP_ATTNMASKREG 0x21C /* Attention Mask */
++#define PCIE_PLP_RXERRCTR 0x220 /* Rx Error */
++#define PCIE_PLP_RXFRMERRCTR 0x224 /* Rx Framing Error */
++#define PCIE_PLP_RXERRTHRESHREG 0x228 /* Rx Error threshold */
++#define PCIE_PLP_TESTCTRLREG 0x22C /* Test Control reg */
++#define PCIE_PLP_SERDESCTRLOVRDREG 0x230 /* SERDES Control Override */
++#define PCIE_PLP_TIMINGOVRDREG 0x234 /* Timing param override */
++#define PCIE_PLP_RXTXSMDIAGREG 0x238 /* RXTX State Machine Diag */
++#define PCIE_PLP_LTSSMDIAGREG 0x23C /* LTSSM State Machine Diag */
++
++/* PCIE protocol DLLP diagnostic registers */
++#define PCIE_DLLP_LCREG 0x100 /* Link Control */
++#define PCIE_DLLP_LSREG 0x104 /* Link Status */
++#define PCIE_DLLP_LAREG 0x108 /* Link Attention */
++#define PCIE_DLLP_LAMASKREG 0x10C /* Link Attention Mask */
++#define PCIE_DLLP_NEXTTXSEQNUMREG 0x110 /* Next Tx Seq Num */
++#define PCIE_DLLP_ACKEDTXSEQNUMREG 0x114 /* Acked Tx Seq Num */
++#define PCIE_DLLP_PURGEDTXSEQNUMREG 0x118 /* Purged Tx Seq Num */
++#define PCIE_DLLP_RXSEQNUMREG 0x11C /* Rx Sequence Number */
++#define PCIE_DLLP_LRREG 0x120 /* Link Replay */
++#define PCIE_DLLP_LACKTOREG 0x124 /* Link Ack Timeout */
++#define PCIE_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */
++#define PCIE_DLLP_RTRYWPREG 0x12C /* Retry buffer write ptr */
++#define PCIE_DLLP_RTRYRPREG 0x130 /* Retry buffer Read ptr */
++#define PCIE_DLLP_RTRYPPREG 0x134 /* Retry buffer Purged ptr */
++#define PCIE_DLLP_RTRRWREG 0x138 /* Retry buffer Read/Write */
++#define PCIE_DLLP_ECTHRESHREG 0x13C /* Error Count Threshold */
++#define PCIE_DLLP_TLPERRCTRREG 0x140 /* TLP Error Counter */
++#define PCIE_DLLP_ERRCTRREG 0x144 /* Error Counter */
++#define PCIE_DLLP_NAKRXCTRREG 0x148 /* NAK Received Counter */
++#define PCIE_DLLP_TESTREG 0x14C /* Test */
++#define PCIE_DLLP_PKTBIST 0x150 /* Packet BIST */
++
++/* PCIE protocol TLP diagnostic registers */
++#define PCIE_TLP_CONFIGREG 0x000 /* Configuration */
++#define PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */
++#define PCIE_TLP_WRDMAUPPER 0x010 /* Write DMA Upper Address */
++#define PCIE_TLP_WRDMALOWER 0x014 /* Write DMA Lower Address */
++#define PCIE_TLP_WRDMAREQ_LBEREG 0x018 /* Write DMA Len/ByteEn Req */
++#define PCIE_TLP_RDDMAUPPER 0x01C /* Read DMA Upper Address */
++#define PCIE_TLP_RDDMALOWER 0x020 /* Read DMA Lower Address */
++#define PCIE_TLP_RDDMALENREG 0x024 /* Read DMA Len Req */
++#define PCIE_TLP_MSIDMAUPPER 0x028 /* MSI DMA Upper Address */
++#define PCIE_TLP_MSIDMALOWER 0x02C /* MSI DMA Lower Address */
++#define PCIE_TLP_MSIDMALENREG 0x030 /* MSI DMA Len Req */
++#define PCIE_TLP_SLVREQLENREG 0x034 /* Slave Request Len */
++#define PCIE_TLP_FCINPUTSREQ 0x038 /* Flow Control Inputs */
++#define PCIE_TLP_TXSMGRSREQ 0x03C /* Tx StateMachine and Gated Req */
++#define PCIE_TLP_ADRACKCNTARBLEN 0x040 /* Address Ack XferCnt and ARB Len */
++#define PCIE_TLP_DMACPLHDR0 0x044 /* DMA Completion Hdr 0 */
++#define PCIE_TLP_DMACPLHDR1 0x048 /* DMA Completion Hdr 1 */
++#define PCIE_TLP_DMACPLHDR2 0x04C /* DMA Completion Hdr 2 */
++#define PCIE_TLP_DMACPLMISC0 0x050 /* DMA Completion Misc0 */
++#define PCIE_TLP_DMACPLMISC1 0x054 /* DMA Completion Misc1 */
++#define PCIE_TLP_DMACPLMISC2 0x058 /* DMA Completion Misc2 */
++#define PCIE_TLP_SPTCTRLLEN 0x05C /* Split Controller Req len */
++#define PCIE_TLP_SPTCTRLMSIC0 0x060 /* Split Controller Misc 0 */
++#define PCIE_TLP_SPTCTRLMSIC1 0x064 /* Split Controller Misc 1 */
++#define PCIE_TLP_BUSDEVFUNC 0x068 /* Bus/Device/Func */
++#define PCIE_TLP_RESETCTR 0x06C /* Reset Counter */
++#define PCIE_TLP_RTRYBUF 0x070 /* Retry Buffer value */
++#define PCIE_TLP_TGTDEBUG1 0x074 /* Target Debug Reg1 */
++#define PCIE_TLP_TGTDEBUG2 0x078 /* Target Debug Reg2 */
++#define PCIE_TLP_TGTDEBUG3 0x07C /* Target Debug Reg3 */
++#define PCIE_TLP_TGTDEBUG4 0x080 /* Target Debug Reg4 */
++
++/* MDIO control */
++#define MDIOCTL_DIVISOR_MASK 0x7f /* clock to be used on MDIO */
++#define MDIOCTL_DIVISOR_VAL 0x2
++#define MDIOCTL_PREAM_EN 0x80 /* Enable preamble sequnce */
++#define MDIOCTL_ACCESS_DONE 0x100 /* Tranaction complete */
++
++/* MDIO Data */
++#define MDIODATA_MASK 0x0000ffff /* data 2 bytes */
++#define MDIODATA_TA 0x00020000 /* Turnaround */
++#define MDIODATA_REGADDR_SHF 18 /* Regaddr shift */
++#define MDIODATA_REGADDR_MASK 0x003c0000 /* Regaddr Mask */
++#define MDIODATA_DEVADDR_SHF 22 /* Physmedia devaddr shift */
++#define MDIODATA_DEVADDR_MASK 0x0fc00000 /* Physmedia devaddr Mask */
++#define MDIODATA_WRITE 0x10000000 /* write Transaction */
++#define MDIODATA_READ 0x20000000 /* Read Transaction */
++#define MDIODATA_START 0x40000000 /* start of Transaction */
++
++/* MDIO devices (SERDES modules) */
++#define MDIODATA_DEV_PLL 0x1d /* SERDES PLL Dev */
++#define MDIODATA_DEV_TX 0x1e /* SERDES TX Dev */
++#define MDIODATA_DEV_RX 0x1f /* SERDES RX Dev */
++
++/* SERDES registers */
++#define SERDES_RX_TIMER1 2 /* Rx Timer1 */
++#define SERDES_RX_CDR 6 /* CDR */
++#define SERDES_RX_CDRBW 7 /* CDR BW */
++
++#endif /* _SBPCIE_H */
+diff -urN linux.old/arch/mips/bcm947xx/include/sbpci.h linux.dev/arch/mips/bcm947xx/include/sbpci.h
+--- linux.old/arch/mips/bcm947xx/include/sbpci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbpci.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,114 @@
++/*
++ * HND SiliconBackplane PCI core hardware definitions.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: sbpci.h,v 1.1.1.11 2006/02/27 03:43:16 honor Exp $
++ */
++
++#ifndef _sbpci_h_
++#define _sbpci_h_
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++/* cpp contortions to concatenate w/arg prescan */
++#ifndef PAD
++#define _PADLINE(line) pad ## line
++#define _XSTR(line) _PADLINE(line)
++#define PAD _XSTR(__LINE__)
++#endif
++
++/* Sonics side: PCI core and host control registers */
++typedef struct sbpciregs {
++ uint32 control; /* PCI control */
++ uint32 PAD[3];
++ uint32 arbcontrol; /* PCI arbiter control */
++ uint32 PAD[3];
++ uint32 intstatus; /* Interrupt status */
++ uint32 intmask; /* Interrupt mask */
++ uint32 sbtopcimailbox; /* Sonics to PCI mailbox */
++ uint32 PAD[9];
++ uint32 bcastaddr; /* Sonics broadcast address */
++ uint32 bcastdata; /* Sonics broadcast data */
++ uint32 PAD[2];
++ uint32 gpioin; /* ro: gpio input (>=rev2) */
++ uint32 gpioout; /* rw: gpio output (>=rev2) */
++ uint32 gpioouten; /* rw: gpio output enable (>= rev2) */
++ uint32 gpiocontrol; /* rw: gpio control (>= rev2) */
++ uint32 PAD[36];
++ uint32 sbtopci0; /* Sonics to PCI translation 0 */
++ uint32 sbtopci1; /* Sonics to PCI translation 1 */
++ uint32 sbtopci2; /* Sonics to PCI translation 2 */
++ uint32 PAD[189];
++ uint32 pcicfg[4][64]; /* 0x400 - 0x7FF, PCI Cfg Space (>=rev8) */
++ uint16 sprom[36]; /* SPROM shadow Area */
++ uint32 PAD[46];
++} sbpciregs_t;
++
++#endif /* _LANGUAGE_ASSEMBLY */
++
++/* PCI control */
++#define PCI_RST_OE 0x01 /* When set, drives PCI_RESET out to pin */
++#define PCI_RST 0x02 /* Value driven out to pin */
++#define PCI_CLK_OE 0x04 /* When set, drives clock as gated by PCI_CLK out to pin */
++#define PCI_CLK 0x08 /* Gate for clock driven out to pin */
++
++/* PCI arbiter control */
++#define PCI_INT_ARB 0x01 /* When set, use an internal arbiter */
++#define PCI_EXT_ARB 0x02 /* When set, use an external arbiter */
++/* ParkID - for PCI corerev >= 8 */
++#define PCI_PARKID_MASK 0x1c /* Selects which agent is parked on an idle bus */
++#define PCI_PARKID_SHIFT 2
++#define PCI_PARKID_EXT0 0 /* External master 0 */
++#define PCI_PARKID_EXT1 1 /* External master 1 */
++#define PCI_PARKID_EXT2 2 /* External master 2 */
++#define PCI_PARKID_INT 3 /* Internal master */
++#define PCI_PARKID_LAST 4 /* Last active master */
++
++/* Interrupt status/mask */
++#define PCI_INTA 0x01 /* PCI INTA# is asserted */
++#define PCI_INTB 0x02 /* PCI INTB# is asserted */
++#define PCI_SERR 0x04 /* PCI SERR# has been asserted (write one to clear) */
++#define PCI_PERR 0x08 /* PCI PERR# has been asserted (write one to clear) */
++#define PCI_PME 0x10 /* PCI PME# is asserted */
++
++/* (General) PCI/SB mailbox interrupts, two bits per pci function */
++#define MAILBOX_F0_0 0x100 /* function 0, int 0 */
++#define MAILBOX_F0_1 0x200 /* function 0, int 1 */
++#define MAILBOX_F1_0 0x400 /* function 1, int 0 */
++#define MAILBOX_F1_1 0x800 /* function 1, int 1 */
++#define MAILBOX_F2_0 0x1000 /* function 2, int 0 */
++#define MAILBOX_F2_1 0x2000 /* function 2, int 1 */
++#define MAILBOX_F3_0 0x4000 /* function 3, int 0 */
++#define MAILBOX_F3_1 0x8000 /* function 3, int 1 */
++
++/* Sonics broadcast address */
++#define BCAST_ADDR_MASK 0xff /* Broadcast register address */
++
++/* Sonics to PCI translation types */
++#define SBTOPCI0_MASK 0xfc000000
++#define SBTOPCI1_MASK 0xfc000000
++#define SBTOPCI2_MASK 0xc0000000
++#define SBTOPCI_MEM 0
++#define SBTOPCI_IO 1
++#define SBTOPCI_CFG0 2
++#define SBTOPCI_CFG1 3
++#define SBTOPCI_PREF 0x4 /* prefetch enable */
++#define SBTOPCI_BURST 0x8 /* burst enable */
++#define SBTOPCI_RC_MASK 0x30 /* read command (>= rev11) */
++#define SBTOPCI_RC_READ 0x00 /* memory read */
++#define SBTOPCI_RC_READLINE 0x10 /* memory read line */
++#define SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */
++
++/* PCI core index in SROM shadow area */
++#define SRSH_PI_OFFSET 0 /* first word */
++#define SRSH_PI_MASK 0xf000 /* bit 15:12 */
++#define SRSH_PI_SHIFT 12 /* bit 15:12 */
++
++#endif /* _sbpci_h_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/sbpcmcia.h linux.dev/arch/mips/bcm947xx/include/sbpcmcia.h
+--- linux.old/arch/mips/bcm947xx/include/sbpcmcia.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbpcmcia.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,147 @@
++/*
++ * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: sbpcmcia.h,v 1.1.1.9 2006/02/27 03:43:16 honor Exp $
++ */
++
++#ifndef _SBPCMCIA_H
++#define _SBPCMCIA_H
++
++
++/* All the addresses that are offsets in attribute space are divided
++ * by two to account for the fact that odd bytes are invalid in
++ * attribute space and our read/write routines make the space appear
++ * as if they didn't exist. Still we want to show the original numbers
++ * as documented in the hnd_pcmcia core manual.
++ */
++
++/* PCMCIA Function Configuration Registers */
++#define PCMCIA_FCR (0x700 / 2)
++
++#define FCR0_OFF 0
++#define FCR1_OFF (0x40 / 2)
++#define FCR2_OFF (0x80 / 2)
++#define FCR3_OFF (0xc0 / 2)
++
++#define PCMCIA_FCR0 (0x700 / 2)
++#define PCMCIA_FCR1 (0x740 / 2)
++#define PCMCIA_FCR2 (0x780 / 2)
++#define PCMCIA_FCR3 (0x7c0 / 2)
++
++/* Standard PCMCIA FCR registers */
++
++#define PCMCIA_COR 0
++
++#define COR_RST 0x80
++#define COR_LEV 0x40
++#define COR_IRQEN 0x04
++#define COR_BLREN 0x01
++#define COR_FUNEN 0x01
++
++
++#define PCICIA_FCSR (2 / 2)
++#define PCICIA_PRR (4 / 2)
++#define PCICIA_SCR (6 / 2)
++#define PCICIA_ESR (8 / 2)
++
++
++#define PCM_MEMOFF 0x0000
++#define F0_MEMOFF 0x1000
++#define F1_MEMOFF 0x2000
++#define F2_MEMOFF 0x3000
++#define F3_MEMOFF 0x4000
++
++/* Memory base in the function fcr's */
++#define MEM_ADDR0 (0x728 / 2)
++#define MEM_ADDR1 (0x72a / 2)
++#define MEM_ADDR2 (0x72c / 2)
++
++/* PCMCIA base plus Srom access in fcr0: */
++#define PCMCIA_ADDR0 (0x072e / 2)
++#define PCMCIA_ADDR1 (0x0730 / 2)
++#define PCMCIA_ADDR2 (0x0732 / 2)
++
++#define MEM_SEG (0x0734 / 2)
++#define SROM_CS (0x0736 / 2)
++#define SROM_DATAL (0x0738 / 2)
++#define SROM_DATAH (0x073a / 2)
++#define SROM_ADDRL (0x073c / 2)
++#define SROM_ADDRH (0x073e / 2)
++
++/* Values for srom_cs: */
++#define SROM_IDLE 0
++#define SROM_WRITE 1
++#define SROM_READ 2
++#define SROM_WEN 4
++#define SROM_WDS 7
++#define SROM_DONE 8
++
++/* CIS stuff */
++
++/* The CIS stops where the FCRs start */
++#define CIS_SIZE PCMCIA_FCR
++
++/* Standard tuples we know about */
++
++#define CISTPL_MANFID 0x20 /* Manufacturer and device id */
++#define CISTPL_FUNCE 0x22 /* Function extensions */
++#define CISTPL_CFTABLE 0x1b /* Config table entry */
++
++/* Function extensions for LANs */
++
++#define LAN_TECH 1 /* Technology type */
++#define LAN_SPEED 2 /* Raw bit rate */
++#define LAN_MEDIA 3 /* Transmission media */
++#define LAN_NID 4 /* Node identification (aka MAC addr) */
++#define LAN_CONN 5 /* Connector standard */
++
++
++/* CFTable */
++#define CFTABLE_REGWIN_2K 0x08 /* 2k reg windows size */
++#define CFTABLE_REGWIN_4K 0x10 /* 4k reg windows size */
++#define CFTABLE_REGWIN_8K 0x20 /* 8k reg windows size */
++
++/* Vendor unique tuples are 0x80-0x8f. Within Broadcom we'll
++ * take one for HNBU, and use "extensions" (a la FUNCE) within it.
++ */
++
++#define CISTPL_BRCM_HNBU 0x80
++
++/* Subtypes of BRCM_HNBU: */
++
++#define HNBU_SROMREV 0x00 /* A byte with sromrev, 1 if not present */
++#define HNBU_CHIPID 0x01 /* Two 16bit values: PCI vendor & device id */
++#define HNBU_BOARDREV 0x02 /* One byte board revision */
++#define HNBU_PAPARMS 0x03 /* PA parameters: 8 (sromrev == 1)
++ * or 9 (sromrev > 1) bytes
++ */
++#define HNBU_OEM 0x04 /* Eight bytes OEM data (sromrev == 1) */
++#define HNBU_CC 0x05 /* Default country code (sromrev == 1) */
++#define HNBU_AA 0x06 /* Antennas available */
++#define HNBU_AG 0x07 /* Antenna gain */
++#define HNBU_BOARDFLAGS 0x08 /* board flags (2 or 4 bytes) */
++#define HNBU_LEDS 0x09 /* LED set */
++#define HNBU_CCODE 0x0a /* Country code (2 bytes ascii + 1 byte cctl)
++ * in rev 2
++ */
++#define HNBU_CCKPO 0x0b /* 2 byte cck power offsets in rev 3 */
++#define HNBU_OFDMPO 0x0c /* 4 byte 11g ofdm power offsets in rev 3 */
++#define HNBU_GPIOTIMER 0x0d /* 2 bytes with on/off values in rev 3 */
++
++
++/* sbtmstatelow */
++#define SBTML_INT_ACK 0x40000 /* ack the sb interrupt */
++#define SBTML_INT_EN 0x20000 /* enable sb interrupt */
++
++/* sbtmstatehigh */
++#define SBTMH_INT_STATUS 0x40000 /* sb interrupt status */
++
++#endif /* _SBPCMCIA_H */
+diff -urN linux.old/arch/mips/bcm947xx/include/sbsdram.h linux.dev/arch/mips/bcm947xx/include/sbsdram.h
+--- linux.old/arch/mips/bcm947xx/include/sbsdram.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbsdram.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,85 @@
++/*
++ * BCM47XX Sonics SiliconBackplane SDRAM controller core hardware definitions.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: sbsdram.h,v 1.1.1.9 2006/03/02 13:03:52 honor Exp $
++ */
++
++#ifndef _SBSDRAM_H
++#define _SBSDRAM_H
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++/* Sonics side: SDRAM core registers */
++typedef volatile struct sbsdramregs {
++ uint32 initcontrol; /* Generates external SDRAM initialization sequence */
++ uint32 config; /* Initializes external SDRAM mode register */
++ uint32 refresh; /* Controls external SDRAM refresh rate */
++ uint32 pad1;
++ uint32 pad2;
++} sbsdramregs_t;
++
++/* SDRAM simulation */
++#ifdef RAMSZ
++#define SDRAMSZ RAMSZ
++#else
++#define SDRAMSZ (4 * 1024 * 1024)
++#endif
++
++extern uchar sdrambuf[SDRAMSZ];
++
++#endif /* _LANGUAGE_ASSEMBLY */
++
++/* SDRAM initialization control (initcontrol) register bits */
++#define SDRAM_CBR 0x0001 /* Writing 1 generates refresh cycle and toggles bit */
++#define SDRAM_PRE 0x0002 /* Writing 1 generates precharge cycle and toggles bit */
++#define SDRAM_MRS 0x0004 /* Writing 1 generates mode register select cycle and toggles bit */
++#define SDRAM_EN 0x0008 /* When set, enables access to SDRAM */
++#define SDRAM_16Mb 0x0000 /* Use 16 Megabit SDRAM */
++#define SDRAM_64Mb 0x0010 /* Use 64 Megabit SDRAM */
++#define SDRAM_128Mb 0x0020 /* Use 128 Megabit SDRAM */
++#define SDRAM_RSVMb 0x0030 /* Use special SDRAM */
++#define SDRAM_RST 0x0080 /* Writing 1 causes soft reset of controller */
++#define SDRAM_SELFREF 0x0100 /* Writing 1 enables self refresh mode */
++#define SDRAM_PWRDOWN 0x0200 /* Writing 1 causes controller to power down */
++#define SDRAM_32BIT 0x0400 /* When set, indicates 32 bit SDRAM interface */
++#define SDRAM_9BITCOL 0x0800 /* When set, indicates 9 bit column */
++
++/* SDRAM configuration (config) register bits */
++#define SDRAM_BURSTFULL 0x0000 /* Use full page bursts */
++#define SDRAM_BURST8 0x0001 /* Use burst of 8 */
++#define SDRAM_BURST4 0x0002 /* Use burst of 4 */
++#define SDRAM_BURST2 0x0003 /* Use burst of 2 */
++#define SDRAM_CAS3 0x0000 /* Use CAS latency of 3 */
++#define SDRAM_CAS2 0x0004 /* Use CAS latency of 2 */
++
++/* SDRAM refresh control (refresh) register bits */
++#define SDRAM_REF(p) (((p)&0xff) | SDRAM_REF_EN) /* Refresh period */
++#define SDRAM_REF_EN 0x8000 /* Writing 1 enables periodic refresh */
++
++/* SDRAM Core default Init values (OCP ID 0x803) */
++#define SDRAM_INIT MEM4MX16X2
++#define SDRAM_CONFIG SDRAM_BURSTFULL
++#define SDRAM_REFRESH SDRAM_REF(0x40)
++
++#define MEM1MX16 0x009 /* 2 MB */
++#define MEM1MX16X2 0x409 /* 4 MB */
++#define MEM2MX8X2 0x809 /* 4 MB */
++#define MEM2MX8X4 0xc09 /* 8 MB */
++#define MEM2MX32 0x439 /* 8 MB */
++#define MEM4MX16 0x019 /* 8 MB */
++#define MEM4MX16X2 0x419 /* 16 MB */
++#define MEM8MX8X2 0x819 /* 16 MB */
++#define MEM8MX16 0x829 /* 16 MB */
++#define MEM4MX32 0x429 /* 16 MB */
++#define MEM8MX8X4 0xc19 /* 32 MB */
++#define MEM8MX16X2 0xc29 /* 32 MB */
++
++#endif /* _SBSDRAM_H */
+diff -urN linux.old/arch/mips/bcm947xx/include/sbsocram.h linux.dev/arch/mips/bcm947xx/include/sbsocram.h
+--- linux.old/arch/mips/bcm947xx/include/sbsocram.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbsocram.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,64 @@
++/*
++ * BCM47XX Sonics SiliconBackplane embedded ram core
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: sbsocram.h,v 1.1.1.3 2006/02/27 03:43:16 honor Exp $
++ */
++
++#ifndef _SBSOCRAM_H
++#define _SBSOCRAM_H
++
++#define SR_COREINFO 0x00
++#define SR_BWALLOC 0x04
++#define SR_BISTSTAT 0x0c
++#define SR_BANKINDEX 0x10
++#define SR_BANKSTBYCTL 0x14
++
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++/* Memcsocram core registers */
++typedef volatile struct sbsocramregs {
++ uint32 coreinfo;
++ uint32 bwalloc;
++ uint32 PAD;
++ uint32 biststat;
++ uint32 bankidx;
++ uint32 standbyctrl;
++} sbsocramregs_t;
++
++#endif
++
++/* Coreinfo register */
++#define SRCI_PT_MASK 0x30000
++#define SRCI_PT_SHIFT 16
++
++/* In corerev 0, the memory size is 2 to the power of the
++ * base plus 16 plus to the contents of the memsize field plus 1.
++ */
++#define SRCI_MS0_MASK 0xf
++#define SR_MS0_BASE 16
++
++/*
++ * In corerev 1 the bank size is 2 ^ the bank size field plus 14,
++ * the memory size is number of banks times bank size.
++ * The same applies to rom size.
++ */
++#define SRCI_ROMNB_MASK 0xf000
++#define SRCI_ROMNB_SHIFT 12
++#define SRCI_ROMBSZ_MASK 0xf00
++#define SRCI_ROMBSZ_SHIFT 8
++#define SRCI_SRNB_MASK 0xf0
++#define SRCI_SRNB_SHIFT 4
++#define SRCI_SRBSZ_MASK 0xf
++#define SRCI_SRBSZ_SHIFT 0
++
++#define SR_BSZ_BASE 14
++#endif /* _SBSOCRAM_H */
+diff -urN linux.old/arch/mips/bcm947xx/include/sbutils.h linux.dev/arch/mips/bcm947xx/include/sbutils.h
+--- linux.old/arch/mips/bcm947xx/include/sbutils.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sbutils.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,150 @@
++/*
++ * Misc utility routines for accessing chip-specific features
++ * of Broadcom HNBU SiliconBackplane-based chips.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: sbutils.h,v 1.4 2006/04/08 07:12:42 honor Exp $
++ */
++
++#ifndef _sbutils_h_
++#define _sbutils_h_
++
++/*
++ * Datastructure to export all chip specific common variables
++ * public (read-only) portion of sbutils handle returned by
++ * sb_attach()/sb_kattach()
++*/
++
++struct sb_pub {
++
++ uint bustype; /* SB_BUS, PCI_BUS */
++ uint buscoretype; /* SB_PCI, SB_PCMCIA, SB_PCIE */
++ uint buscorerev; /* buscore rev */
++ uint buscoreidx; /* buscore index */
++ int ccrev; /* chip common core rev */
++ uint boardtype; /* board type */
++ uint boardvendor; /* board vendor */
++ uint chip; /* chip number */
++ uint chiprev; /* chip revision */
++ uint chippkg; /* chip package option */
++ uint sonicsrev; /* sonics backplane rev */
++};
++
++typedef const struct sb_pub sb_t;
++
++/*
++ * Many of the routines below take an 'sbh' handle as their first arg.
++ * Allocate this by calling sb_attach(). Free it by calling sb_detach().
++ * At any one time, the sbh is logically focused on one particular sb core
++ * (the "current core").
++ * Use sb_setcore() or sb_setcoreidx() to change the association to another core.
++ */
++
++#define SB_OSH NULL /* Use for sb_kattach when no osh is available */
++/* exported externs */
++extern sb_t *sb_attach(uint pcidev, osl_t *osh, void *regs, uint bustype,
++ void *sdh, char **vars, uint *varsz);
++extern sb_t *sb_kattach(void);
++extern void sb_detach(sb_t *sbh);
++extern uint sb_chip(sb_t *sbh);
++extern uint sb_chiprev(sb_t *sbh);
++extern uint sb_chipcrev(sb_t *sbh);
++extern uint sb_chippkg(sb_t *sbh);
++extern uint sb_pcirev(sb_t *sbh);
++extern bool sb_war16165(sb_t *sbh);
++extern uint sb_pcmciarev(sb_t *sbh);
++extern uint sb_boardvendor(sb_t *sbh);
++extern uint sb_boardtype(sb_t *sbh);
++extern uint sb_bus(sb_t *sbh);
++extern uint sb_buscoretype(sb_t *sbh);
++extern uint sb_buscorerev(sb_t *sbh);
++extern uint sb_corelist(sb_t *sbh, uint coreid[]);
++extern uint sb_coreid(sb_t *sbh);
++extern uint sb_coreidx(sb_t *sbh);
++extern uint sb_coreunit(sb_t *sbh);
++extern uint sb_corevendor(sb_t *sbh);
++extern uint sb_corerev(sb_t *sbh);
++extern void *sb_osh(sb_t *sbh);
++extern void sb_setosh(sb_t *sbh, osl_t *osh);
++extern void *sb_coreregs(sb_t *sbh);
++extern uint32 sb_coreflags(sb_t *sbh, uint32 mask, uint32 val);
++extern uint32 sb_coreflagshi(sb_t *sbh, uint32 mask, uint32 val);
++extern bool sb_iscoreup(sb_t *sbh);
++extern void *sb_setcoreidx(sb_t *sbh, uint coreidx);
++extern void *sb_setcore(sb_t *sbh, uint coreid, uint coreunit);
++extern int sb_corebist(sb_t *sbh);
++extern void sb_commit(sb_t *sbh);
++extern uint32 sb_base(uint32 admatch);
++extern uint32 sb_size(uint32 admatch);
++extern void sb_core_reset(sb_t *sbh, uint32 bits, uint32 resetbits);
++extern void sb_core_tofixup(sb_t *sbh);
++extern void sb_core_disable(sb_t *sbh, uint32 bits);
++extern uint32 sb_clock_rate(uint32 pll_type, uint32 n, uint32 m);
++extern uint32 sb_clock(sb_t *sbh);
++extern void sb_pci_setup(sb_t *sbh, uint coremask);
++extern void sb_pcmcia_init(sb_t *sbh);
++extern void sb_watchdog(sb_t *sbh, uint ticks);
++extern void *sb_gpiosetcore(sb_t *sbh);
++extern uint32 sb_gpiocontrol(sb_t *sbh, uint32 mask, uint32 val, uint8 priority);
++extern uint32 sb_gpioouten(sb_t *sbh, uint32 mask, uint32 val, uint8 priority);
++extern uint32 sb_gpioout(sb_t *sbh, uint32 mask, uint32 val, uint8 priority);
++extern uint32 sb_gpioin(sb_t *sbh);
++extern uint32 sb_gpiointpolarity(sb_t *sbh, uint32 mask, uint32 val, uint8 priority);
++extern uint32 sb_gpiointmask(sb_t *sbh, uint32 mask, uint32 val, uint8 priority);
++extern uint32 sb_gpioled(sb_t *sbh, uint32 mask, uint32 val);
++extern uint32 sb_gpioreserve(sb_t *sbh, uint32 gpio_num, uint8 priority);
++extern uint32 sb_gpiorelease(sb_t *sbh, uint32 gpio_num, uint8 priority);
++
++extern void sb_clkctl_init(sb_t *sbh);
++extern uint16 sb_clkctl_fast_pwrup_delay(sb_t *sbh);
++extern bool sb_clkctl_clk(sb_t *sbh, uint mode);
++extern int sb_clkctl_xtal(sb_t *sbh, uint what, bool on);
++extern void sb_register_intr_callback(sb_t *sbh, void *intrsoff_fn, void *intrsrestore_fn,
++ void *intrsenabled_fn, void *intr_arg);
++extern uint32 sb_set_initiator_to(sb_t *sbh, uint32 to);
++extern int sb_corepciid(sb_t *sbh, uint func, uint16 *pcivendor, uint16 *pcidevice,
++ uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif,
++ uint8 *pciheader);
++extern uint sb_pcie_readreg(void *sbh, void* arg1, uint offset);
++extern uint sb_pcie_writereg(sb_t *sbh, void *arg1, uint offset, uint val);
++extern uint32 sb_gpiotimerval(sb_t *sbh, uint32 mask, uint32 val);
++extern bool sb_backplane64(sb_t *sbh);
++extern void sb_btcgpiowar(sb_t *sbh);
++
++
++
++
++extern bool sb_deviceremoved(sb_t *sbh);
++extern uint32 sb_socram_size(sb_t *sbh);
++
++/*
++* Build device path. Path size must be >= SB_DEVPATH_BUFSZ.
++* The returned path is NULL terminated and has trailing '/'.
++* Return 0 on success, nonzero otherwise.
++*/
++extern int sb_devpath(sb_t *sbh, char *path, int size);
++
++/* clkctl xtal what flags */
++#define XTAL 0x1 /* primary crystal oscillator (2050) */
++#define PLL 0x2 /* main chip pll */
++
++/* clkctl clk mode */
++#define CLK_FAST 0 /* force fast (pll) clock */
++#define CLK_DYNAMIC 2 /* enable dynamic clock control */
++
++
++/* GPIO usage priorities */
++#define GPIO_DRV_PRIORITY 0 /* Driver */
++#define GPIO_APP_PRIORITY 1 /* Application */
++
++/* device path */
++#define SB_DEVPATH_BUFSZ 16 /* min buffer size in bytes */
++
++#endif /* _sbutils_h_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/sflash.h linux.dev/arch/mips/bcm947xx/include/sflash.h
+--- linux.old/arch/mips/bcm947xx/include/sflash.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/sflash.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,36 @@
++/*
++ * Broadcom SiliconBackplane chipcommon serial flash interface
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: sflash.h,v 1.1.1.8 2006/02/27 03:43:16 honor Exp $
++ */
++
++#ifndef _sflash_h_
++#define _sflash_h_
++
++#include <typedefs.h>
++#include <sbchipc.h>
++
++struct sflash {
++ uint blocksize; /* Block size */
++ uint numblocks; /* Number of blocks */
++ uint32 type; /* Type */
++ uint size; /* Total size in bytes */
++};
++
++/* Utility functions */
++extern int sflash_poll(chipcregs_t *cc, uint offset);
++extern int sflash_read(chipcregs_t *cc, uint offset, uint len, uchar *buf);
++extern int sflash_write(chipcregs_t *cc, uint offset, uint len, const uchar *buf);
++extern int sflash_erase(chipcregs_t *cc, uint offset);
++extern int sflash_commit(chipcregs_t *cc, uint offset, uint len, const uchar *buf);
++extern struct sflash * sflash_init(chipcregs_t *cc);
++
++#endif /* _sflash_h_ */
+diff -urN linux.old/arch/mips/bcm947xx/include/trxhdr.h linux.dev/arch/mips/bcm947xx/include/trxhdr.h
+--- linux.old/arch/mips/bcm947xx/include/trxhdr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/trxhdr.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,33 @@
++/*
++ * TRX image file header format.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#include <typedefs.h>
++
++#define TRX_MAGIC 0x30524448 /* "HDR0" */
++#define TRX_VERSION 1
++#define TRX_MAX_LEN 0x3A0000
++#define TRX_NO_HEADER 1 /* Do not write TRX header */
++#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */
++#define TRX_MAX_OFFSET 3
++
++struct trx_header {
++ uint32 magic; /* "HDR0" */
++ uint32 len; /* Length of file including header */
++ uint32 crc32; /* 32-bit CRC from flag_version to end of file */
++ uint32 flag_version; /* 0:15 flags, 16:31 version */
++ uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
++};
++
++/* Compatibility */
++typedef struct trx_header TRXHDR, *PTRXHDR;
+diff -urN linux.old/arch/mips/bcm947xx/include/typedefs.h linux.dev/arch/mips/bcm947xx/include/typedefs.h
+--- linux.old/arch/mips/bcm947xx/include/typedefs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/include/typedefs.h 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,361 @@
++/*
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id: typedefs.h,v 1.1.1.12 2006/04/08 06:13:40 honor Exp $
++ */
++
++#ifndef _TYPEDEFS_H_
++#define _TYPEDEFS_H_
++
++
++/* Define 'SITE_TYPEDEFS' in the compile to include a site specific
++ * typedef file "site_typedefs.h".
++ *
++ * If 'SITE_TYPEDEFS' is not defined, then the "Inferred Typedefs"
++ * section of this file makes inferences about the compile environment
++ * based on defined symbols and possibly compiler pragmas.
++ *
++ * Following these two sections is the "Default Typedefs"
++ * section. This section is only prcessed if 'USE_TYPEDEF_DEFAULTS' is
++ * defined. This section has a default set of typedefs and a few
++ * proprocessor symbols (TRUE, FALSE, NULL, ...).
++ */
++
++#ifdef SITE_TYPEDEFS
++
++/*
++ * Site Specific Typedefs
++ *
++ */
++
++#include "site_typedefs.h"
++
++#else
++
++/*
++ * Inferred Typedefs
++ *
++ */
++
++/* Infer the compile environment based on preprocessor symbols and pramas.
++ * Override type definitions as needed, and include configuration dependent
++ * header files to define types.
++ */
++
++#ifdef __cplusplus
++
++#define TYPEDEF_BOOL
++#ifndef FALSE
++#define FALSE false
++#endif
++#ifndef TRUE
++#define TRUE true
++#endif
++
++#else /* ! __cplusplus */
++
++#if defined(_WIN32)
++
++#define TYPEDEF_BOOL
++typedef unsigned char bool; /* consistent w/BOOL */
++
++#endif /* _WIN32 */
++
++#endif /* ! __cplusplus */
++
++/* use the Windows ULONG_PTR type when compiling for 64 bit */
++#if defined(_WIN64)
++#include <basetsd.h>
++#define TYPEDEF_UINTPTR
++typedef ULONG_PTR uintptr;
++#endif
++
++
++#if defined(_MINOSL_)
++#define _NEED_SIZE_T_
++#endif
++
++#if defined(_NEED_SIZE_T_)
++typedef long unsigned int size_t;
++#endif
++
++#ifdef __DJGPP__
++typedef long unsigned int size_t;
++#endif /* __DJGPP__ */
++
++#ifdef _MSC_VER /* Microsoft C */
++#define TYPEDEF_INT64
++#define TYPEDEF_UINT64
++typedef signed __int64 int64;
++typedef unsigned __int64 uint64;
++#endif
++
++#if defined(MACOSX)
++#define TYPEDEF_BOOL
++#endif
++
++#if defined(__NetBSD__)
++#define TYPEDEF_ULONG
++#endif
++
++
++#if defined(linux)
++#define TYPEDEF_UINT
++#define TYPEDEF_USHORT
++#define TYPEDEF_ULONG
++#endif
++
++#if !defined(linux) && !defined(_WIN32) && !defined(_CFE_) && \
++ !defined(_HNDRTE_) && !defined(_MINOSL_) && !defined(__DJGPP__)
++#define TYPEDEF_UINT
++#define TYPEDEF_USHORT
++#endif
++
++
++/* Do not support the (u)int64 types with strict ansi for GNU C */
++#if defined(__GNUC__) && defined(__STRICT_ANSI__)
++#define TYPEDEF_INT64
++#define TYPEDEF_UINT64
++#endif
++
++/* ICL accepts unsigned 64 bit type only, and complains in ANSI mode
++ * for singned or unsigned
++ */
++#if defined(__ICL)
++
++#define TYPEDEF_INT64
++
++#if defined(__STDC__)
++#define TYPEDEF_UINT64
++#endif
++
++#endif /* __ICL */
++
++#if !defined(_WIN32) && !defined(_CFE_) && !defined(_MINOSL_) && \
++ !defined(__DJGPP__)
++
++/* pick up ushort & uint from standard types.h */
++#if defined(linux) && defined(__KERNEL__)
++
++#include <linux/types.h> /* sys/types.h and linux/types.h are oil and water */
++
++#else
++
++#include <sys/types.h>
++
++#endif
++
++#endif /* !_WIN32 && !PMON && !_CFE_ && !_HNDRTE_ && !_MINOSL_ && !__DJGPP__ */
++
++#if defined(MACOSX)
++
++#ifdef __BIG_ENDIAN__
++#define IL_BIGENDIAN
++#else
++#ifdef IL_BIGENDIAN
++#error "IL_BIGENDIAN was defined for a little-endian compile"
++#endif
++#endif /* __BIG_ENDIAN__ */
++
++#if !defined(__cplusplus)
++
++#if defined(__i386__)
++typedef unsigned char bool;
++#else
++typedef unsigned int bool;
++#endif
++#define TYPE_BOOL 1
++enum {
++ false = 0,
++ true = 1
++};
++
++#if defined(KERNEL)
++#include <IOKit/IOTypes.h>
++#endif /* KERNEL */
++
++#endif /* __cplusplus */
++
++#endif /* MACOSX */
++
++
++/* use the default typedefs in the next section of this file */
++#define USE_TYPEDEF_DEFAULTS
++
++#endif /* SITE_TYPEDEFS */
++
++
++/*
++ * Default Typedefs
++ *
++ */
++
++#ifdef USE_TYPEDEF_DEFAULTS
++#undef USE_TYPEDEF_DEFAULTS
++
++#ifndef TYPEDEF_BOOL
++typedef /* @abstract@ */ unsigned char bool;
++#endif
++
++/* define uchar, ushort, uint, ulong */
++
++#ifndef TYPEDEF_UCHAR
++typedef unsigned char uchar;
++#endif
++
++#ifndef TYPEDEF_USHORT
++typedef unsigned short ushort;
++#endif
++
++#ifndef TYPEDEF_UINT
++typedef unsigned int uint;
++#endif
++
++#ifndef TYPEDEF_ULONG
++typedef unsigned long ulong;
++#endif
++
++/* define [u]int8/16/32/64, uintptr */
++
++#ifndef TYPEDEF_UINT8
++typedef unsigned char uint8;
++#endif
++
++#ifndef TYPEDEF_UINT16
++typedef unsigned short uint16;
++#endif
++
++#ifndef TYPEDEF_UINT32
++typedef unsigned int uint32;
++#endif
++
++#ifndef TYPEDEF_UINT64
++typedef unsigned long long uint64;
++#endif
++
++#ifndef TYPEDEF_UINTPTR
++typedef unsigned int uintptr;
++#endif
++
++#ifndef TYPEDEF_INT8
++typedef signed char int8;
++#endif
++
++#ifndef TYPEDEF_INT16
++typedef signed short int16;
++#endif
++
++#ifndef TYPEDEF_INT32
++typedef signed int int32;
++#endif
++
++#ifndef TYPEDEF_INT64
++typedef signed long long int64;
++#endif
++
++/* define float32/64, float_t */
++
++#ifndef TYPEDEF_FLOAT32
++typedef float float32;
++#endif
++
++#ifndef TYPEDEF_FLOAT64
++typedef double float64;
++#endif
++
++/*
++ * abstracted floating point type allows for compile time selection of
++ * single or double precision arithmetic. Compiling with -DFLOAT32
++ * selects single precision; the default is double precision.
++ */
++
++#ifndef TYPEDEF_FLOAT_T
++
++#if defined(FLOAT32)
++typedef float32 float_t;
++#else /* default to double precision floating point */
++typedef float64 float_t;
++#endif
++
++#endif /* TYPEDEF_FLOAT_T */
++
++/* define macro values */
++
++#ifndef FALSE
++#define FALSE 0
++#endif
++
++#ifndef TRUE
++#define TRUE 1 /* TRUE */
++#endif
++
++#ifndef NULL
++#define NULL 0
++#endif
++
++#ifndef OFF
++#define OFF 0
++#endif
++
++#ifndef ON
++#define ON 1 /* ON = 1 */
++#endif
++
++#define AUTO (-1) /* Auto = -1 */
++
++/* define PTRSZ, INLINE */
++
++#ifndef PTRSZ
++#define PTRSZ sizeof(char*)
++#endif
++
++#ifndef INLINE
++
++#ifdef _MSC_VER
++
++#define INLINE __inline
++
++#elif __GNUC__
++
++#define INLINE __inline__
++
++#else
++
++#define INLINE
++
++#endif /* _MSC_VER */
++
++#endif /* INLINE */
++
++#undef TYPEDEF_BOOL
++#undef TYPEDEF_UCHAR
++#undef TYPEDEF_USHORT
++#undef TYPEDEF_UINT
++#undef TYPEDEF_ULONG
++#undef TYPEDEF_UINT8
++#undef TYPEDEF_UINT16
++#undef TYPEDEF_UINT32
++#undef TYPEDEF_UINT64
++#undef TYPEDEF_UINTPTR
++#undef TYPEDEF_INT8
++#undef TYPEDEF_INT16
++#undef TYPEDEF_INT32
++#undef TYPEDEF_INT64
++#undef TYPEDEF_FLOAT32
++#undef TYPEDEF_FLOAT64
++#undef TYPEDEF_FLOAT_T
++
++#endif /* USE_TYPEDEF_DEFAULTS */
++
++/*
++ * Including the bcmdefs.h here, to make sure everyone including typedefs.h
++ * gets this automatically
++*/
++#include "bcmdefs.h"
++
++#endif /* _TYPEDEFS_H_ */
+diff -urN linux.old/arch/mips/bcm947xx/Makefile linux.dev/arch/mips/bcm947xx/Makefile
+--- linux.old/arch/mips/bcm947xx/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/Makefile 2006-10-02 21:26:08.000000000 +0200
+@@ -0,0 +1,17 @@
++#
++# Makefile for the BCM947xx specific kernel interface routines
++# under Linux.
++#
++
++EXTRA_CFLAGS+=-I$(TOPDIR)/arch/mips/bcm947xx/include -DBCMDRIVER -fno-delayed-branch
++
++O_TARGET := bcm947xx.o
++
++export-objs := export.o
++obj-y := prom.o setup.o time.o sbmips.o gpio.o
++obj-y += nvram.o nvram_linux.o sflash.o cfe_env.o
++obj-y += sbutils.o bcmutils.o bcmsrom.o hndchipc.o
++obj-$(CONFIG_PCI) += sbpci.o pcibios.o
++obj-y += export.o
++
++include $(TOPDIR)/Rules.make
+diff -urN linux.old/arch/mips/bcm947xx/nvram.c linux.dev/arch/mips/bcm947xx/nvram.c
+--- linux.old/arch/mips/bcm947xx/nvram.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/nvram.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,315 @@
++/*
++ * NVRAM variable manipulation (common)
++ *
++ * Copyright 2004, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ */
++
++#include <typedefs.h>
++#include <osl.h>
++#include <bcmendian.h>
++#include <bcmnvram.h>
++#include <bcmutils.h>
++#include <sbsdram.h>
++
++extern struct nvram_tuple * BCMINIT(_nvram_realloc)(struct nvram_tuple *t, const char *name, const char *value);
++extern void BCMINIT(_nvram_free)(struct nvram_tuple *t);
++extern int BCMINIT(_nvram_read)(void *buf);
++
++char * BCMINIT(_nvram_get)(const char *name);
++int BCMINIT(_nvram_set)(const char *name, const char *value);
++int BCMINIT(_nvram_unset)(const char *name);
++int BCMINIT(_nvram_getall)(char *buf, int count);
++int BCMINIT(_nvram_commit)(struct nvram_header *header);
++int BCMINIT(_nvram_init)(void);
++void BCMINIT(_nvram_exit)(void);
++
++static struct nvram_tuple * BCMINITDATA(nvram_hash)[257];
++static struct nvram_tuple * nvram_dead;
++
++/* Free all tuples. Should be locked. */
++static void
++BCMINITFN(nvram_free)(void)
++{
++ uint i;
++ struct nvram_tuple *t, *next;
++
++ /* Free hash table */
++ for (i = 0; i < ARRAYSIZE(BCMINIT(nvram_hash)); i++) {
++ for (t = BCMINIT(nvram_hash)[i]; t; t = next) {
++ next = t->next;
++ BCMINIT(_nvram_free)(t);
++ }
++ BCMINIT(nvram_hash)[i] = NULL;
++ }
++
++ /* Free dead table */
++ for (t = nvram_dead; t; t = next) {
++ next = t->next;
++ BCMINIT(_nvram_free)(t);
++ }
++ nvram_dead = NULL;
++
++ /* Indicate to per-port code that all tuples have been freed */
++ BCMINIT(_nvram_free)(NULL);
++}
++
++/* String hash */
++static INLINE uint
++hash(const char *s)
++{
++ uint hash = 0;
++
++ while (*s)
++ hash = 31 * hash + *s++;
++
++ return hash;
++}
++
++/* (Re)initialize the hash table. Should be locked. */
++static int
++BCMINITFN(nvram_rehash)(struct nvram_header *header)
++{
++ char buf[] = "0xXXXXXXXX", *name, *value, *end, *eq;
++
++ /* (Re)initialize hash table */
++ BCMINIT(nvram_free)();
++
++ /* Parse and set "name=value\0 ... \0\0" */
++ name = (char *) &header[1];
++ end = (char *) header + NVRAM_SPACE - 2;
++ end[0] = end[1] = '\0';
++ for (; *name; name = value + strlen(value) + 1) {
++ if (!(eq = strchr(name, '=')))
++ break;
++ *eq = '\0';
++ value = eq + 1;
++ BCMINIT(_nvram_set)(name, value);
++ *eq = '=';
++ }
++
++ /* Set special SDRAM parameters */
++ if (!BCMINIT(_nvram_get)("sdram_init")) {
++ sprintf(buf, "0x%04X", (uint16)(header->crc_ver_init >> 16));
++ BCMINIT(_nvram_set)("sdram_init", buf);
++ }
++ if (!BCMINIT(_nvram_get)("sdram_config")) {
++ sprintf(buf, "0x%04X", (uint16)(header->config_refresh & 0xffff));
++ BCMINIT(_nvram_set)("sdram_config", buf);
++ }
++ if (!BCMINIT(_nvram_get)("sdram_refresh")) {
++ sprintf(buf, "0x%04X", (uint16)((header->config_refresh >> 16) & 0xffff));
++ BCMINIT(_nvram_set)("sdram_refresh", buf);
++ }
++ if (!BCMINIT(_nvram_get)("sdram_ncdl")) {
++ sprintf(buf, "0x%08X", header->config_ncdl);
++ BCMINIT(_nvram_set)("sdram_ncdl", buf);
++ }
++
++ return 0;
++}
++
++/* Get the value of an NVRAM variable. Should be locked. */
++char *
++BCMINITFN(_nvram_get)(const char *name)
++{
++ uint i;
++ struct nvram_tuple *t;
++ char *value;
++
++ if (!name)
++ return NULL;
++
++ /* Hash the name */
++ i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash));
++
++ /* Find the associated tuple in the hash table */
++ for (t = BCMINIT(nvram_hash)[i]; t && strcmp(t->name, name); t = t->next);
++
++ value = t ? t->value : NULL;
++
++ return value;
++}
++
++/* Get the value of an NVRAM variable. Should be locked. */
++int
++BCMINITFN(_nvram_set)(const char *name, const char *value)
++{
++ uint i;
++ struct nvram_tuple *t, *u, **prev;
++
++ /* Hash the name */
++ i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash));
++
++ /* Find the associated tuple in the hash table */
++ for (prev = &BCMINIT(nvram_hash)[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev);
++
++ /* (Re)allocate tuple */
++ if (!(u = BCMINIT(_nvram_realloc)(t, name, value)))
++ return -12; /* -ENOMEM */
++
++ /* Value reallocated */
++ if (t && t == u)
++ return 0;
++
++ /* Move old tuple to the dead table */
++ if (t) {
++ *prev = t->next;
++ t->next = nvram_dead;
++ nvram_dead = t;
++ }
++
++ /* Add new tuple to the hash table */
++ u->next = BCMINIT(nvram_hash)[i];
++ BCMINIT(nvram_hash)[i] = u;
++
++ return 0;
++}
++
++/* Unset the value of an NVRAM variable. Should be locked. */
++int
++BCMINITFN(_nvram_unset)(const char *name)
++{
++ uint i;
++ struct nvram_tuple *t, **prev;
++
++ if (!name)
++ return 0;
++
++ /* Hash the name */
++ i = hash(name) % ARRAYSIZE(BCMINIT(nvram_hash));
++
++ /* Find the associated tuple in the hash table */
++ for (prev = &BCMINIT(nvram_hash)[i], t = *prev; t && strcmp(t->name, name); prev = &t->next, t = *prev);
++
++ /* Move it to the dead table */
++ if (t) {
++ *prev = t->next;
++ t->next = nvram_dead;
++ nvram_dead = t;
++ }
++
++ return 0;
++}
++
++/* Get all NVRAM variables. Should be locked. */
++int
++BCMINITFN(_nvram_getall)(char *buf, int count)
++{
++ uint i;
++ struct nvram_tuple *t;
++ int len = 0;
++
++ bzero(buf, count);
++
++ /* Write name=value\0 ... \0\0 */
++ for (i = 0; i < ARRAYSIZE(BCMINIT(nvram_hash)); i++) {
++ for (t = BCMINIT(nvram_hash)[i]; t; t = t->next) {
++ if ((count - len) > (strlen(t->name) + 1 + strlen(t->value) + 1))
++ len += sprintf(buf + len, "%s=%s", t->name, t->value) + 1;
++ else
++ break;
++ }
++ }
++
++ return 0;
++}
++
++/* Regenerate NVRAM. Should be locked. */
++int
++BCMINITFN(_nvram_commit)(struct nvram_header *header)
++{
++ char *init, *config, *refresh, *ncdl;
++ char *ptr, *end;
++ int i;
++ struct nvram_tuple *t;
++ struct nvram_header tmp;
++ uint8 crc;
++
++ /* Regenerate header */
++ header->magic = NVRAM_MAGIC;
++ header->crc_ver_init = (NVRAM_VERSION << 8);
++ if (!(init = BCMINIT(_nvram_get)("sdram_init")) ||
++ !(config = BCMINIT(_nvram_get)("sdram_config")) ||
++ !(refresh = BCMINIT(_nvram_get)("sdram_refresh")) ||
++ !(ncdl = BCMINIT(_nvram_get)("sdram_ncdl"))) {
++ header->crc_ver_init |= SDRAM_INIT << 16;
++ header->config_refresh = SDRAM_CONFIG;
++ header->config_refresh |= SDRAM_REFRESH << 16;
++ header->config_ncdl = 0;
++ } else {
++ header->crc_ver_init |= (bcm_strtoul(init, NULL, 0) & 0xffff) << 16;
++ header->config_refresh = bcm_strtoul(config, NULL, 0) & 0xffff;
++ header->config_refresh |= (bcm_strtoul(refresh, NULL, 0) & 0xffff) << 16;
++ header->config_ncdl = bcm_strtoul(ncdl, NULL, 0);
++ }
++
++ /* Clear data area */
++ ptr = (char *) header + sizeof(struct nvram_header);
++ bzero(ptr, NVRAM_SPACE - sizeof(struct nvram_header));
++
++ /* Leave space for a double NUL at the end */
++ end = (char *) header + NVRAM_SPACE - 2;
++
++ /* Write out all tuples */
++ for (i = 0; i < ARRAYSIZE(BCMINIT(nvram_hash)); i++) {
++ for (t = BCMINIT(nvram_hash)[i]; t; t = t->next) {
++ if ((ptr + strlen(t->name) + 1 + strlen(t->value) + 1) > end)
++ break;
++ ptr += sprintf(ptr, "%s=%s", t->name, t->value) + 1;
++ }
++ }
++
++ /* End with a double NUL */
++ ptr += 2;
++
++ /* Set new length */
++ header->len = ROUNDUP(ptr - (char *) header, 4);
++
++ /* Little-endian CRC8 over the last 11 bytes of the header */
++ tmp.crc_ver_init = htol32(header->crc_ver_init);
++ tmp.config_refresh = htol32(header->config_refresh);
++ tmp.config_ncdl = htol32(header->config_ncdl);
++ crc = hndcrc8((char *) &tmp + 9, sizeof(struct nvram_header) - 9, CRC8_INIT_VALUE);
++
++ /* Continue CRC8 over data bytes */
++ crc = hndcrc8((char *) &header[1], header->len - sizeof(struct nvram_header), crc);
++
++ /* Set new CRC8 */
++ header->crc_ver_init |= crc;
++
++ /* Reinitialize hash table */
++ return BCMINIT(nvram_rehash)(header);
++}
++
++/* Initialize hash table. Should be locked. */
++int
++BCMINITFN(_nvram_init)(void)
++{
++ struct nvram_header *header;
++ int ret;
++
++ if (!(header = (struct nvram_header *) kmalloc(NVRAM_SPACE, GFP_ATOMIC))) {
++ return -12; /* -ENOMEM */
++ }
++
++ if ((ret = BCMINIT(_nvram_read)(header)) == 0 &&
++ header->magic == NVRAM_MAGIC)
++ BCMINIT(nvram_rehash)(header);
++
++ kfree(header);
++ return ret;
++}
++
++/* Free hash table. Should be locked. */
++void
++BCMINITFN(_nvram_exit)(void)
++{
++ BCMINIT(nvram_free)();
++}
+diff -urN linux.old/arch/mips/bcm947xx/nvram_linux.c linux.dev/arch/mips/bcm947xx/nvram_linux.c
+--- linux.old/arch/mips/bcm947xx/nvram_linux.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/nvram_linux.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,723 @@
++/*
++ * NVRAM variable manipulation (Linux kernel half)
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: nvram_linux.c,v 1.19 2006/04/08 07:12:42 honor Exp $
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/bootmem.h>
++#include <linux/wrapper.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/mtd/mtd.h>
++#include <asm/addrspace.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++
++#include <typedefs.h>
++#include <osl.h>
++#include <bcmendian.h>
++#include <bcmnvram.h>
++#include <bcmutils.h>
++#include <sbconfig.h>
++#include <sbchipc.h>
++#include <sbutils.h>
++#include <hndmips.h>
++#include <sflash.h>
++
++/* In BSS to minimize text size and page aligned so it can be mmap()-ed */
++static char nvram_buf[NVRAM_SPACE] __attribute__((aligned(PAGE_SIZE)));
++
++#ifdef MODULE
++
++#define early_nvram_get(name) nvram_get(name)
++
++#else /* !MODULE */
++
++/* Global SB handle */
++extern void *bcm947xx_sbh;
++extern spinlock_t bcm947xx_sbh_lock;
++
++static int cfe_env;
++extern char *cfe_env_get(char *nv_buf, const char *name);
++
++/* Convenience */
++#define sbh bcm947xx_sbh
++#define sbh_lock bcm947xx_sbh_lock
++#define KB * 1024
++#define MB * 1024 * 1024
++
++/* Probe for NVRAM header */
++static void __init
++early_nvram_init(void)
++{
++ struct nvram_header *header;
++ chipcregs_t *cc;
++ struct sflash *info = NULL;
++ int i;
++ uint32 base, off, lim;
++ u32 *src, *dst;
++
++ if ((cc = sb_setcore(sbh, SB_CC, 0)) != NULL) {
++ base = KSEG1ADDR(SB_FLASH2);
++ switch (readl(&cc->capabilities) & CAP_FLASH_MASK) {
++ case PFLASH:
++ lim = SB_FLASH2_SZ;
++ break;
++
++ case SFLASH_ST:
++ case SFLASH_AT:
++ if ((info = sflash_init(cc)) == NULL)
++ return;
++ lim = info->size;
++ break;
++
++ case FLASH_NONE:
++ default:
++ return;
++ }
++ } else {
++ /* extif assumed, Stop at 4 MB */
++ base = KSEG1ADDR(SB_FLASH1);
++ lim = SB_FLASH1_SZ;
++ }
++
++ /* XXX: hack for supporting the CFE environment stuff on WGT634U */
++ src = (u32 *) KSEG1ADDR(base + 8 * 1024 * 1024 - 0x2000);
++ dst = (u32 *) nvram_buf;
++ if ((lim == 0x02000000) && ((*src & 0xff00ff) == 0x000001)) {
++ printk("early_nvram_init: WGT634U NVRAM found.\n");
++
++ for (i = 0; i < 0x1ff0; i++) {
++ if (*src == 0xFFFFFFFF)
++ break;
++ *dst++ = *src++;
++ }
++ cfe_env = 1;
++ return;
++ }
++
++ off = FLASH_MIN;
++ while (off <= lim) {
++ /* Windowed flash access */
++ header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE);
++ if (header->magic == NVRAM_MAGIC)
++ goto found;
++ off <<= 1;
++ }
++
++ /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
++ header = (struct nvram_header *) KSEG1ADDR(base + 4 KB);
++ if (header->magic == NVRAM_MAGIC)
++ goto found;
++
++ header = (struct nvram_header *) KSEG1ADDR(base + 1 KB);
++ if (header->magic == NVRAM_MAGIC)
++ goto found;
++
++ printk("early_nvram_init: NVRAM not found\n");
++ return;
++
++found:
++ src = (u32 *) header;
++ dst = (u32 *) nvram_buf;
++ for (i = 0; i < sizeof(struct nvram_header); i += 4)
++ *dst++ = *src++;
++ for (; i < header->len && i < NVRAM_SPACE; i += 4)
++ *dst++ = ltoh32(*src++);
++}
++
++/* Early (before mm or mtd) read-only access to NVRAM */
++static char * __init
++early_nvram_get(const char *name)
++{
++ char *var, *value, *end, *eq;
++
++ if (!name)
++ return NULL;
++
++ /* Too early? */
++ if (sbh == NULL)
++ return NULL;
++
++ if (!nvram_buf[0])
++ early_nvram_init();
++
++ if (cfe_env)
++ return cfe_env_get(nvram_buf, name);
++
++ /* Look for name=value and return value */
++ var = &nvram_buf[sizeof(struct nvram_header)];
++ end = nvram_buf + sizeof(nvram_buf) - 2;
++ end[0] = end[1] = '\0';
++ for (; *var; var = value + strlen(value) + 1) {
++ if (!(eq = strchr(var, '=')))
++ break;
++ value = eq + 1;
++ if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
++ return value;
++ }
++
++ return NULL;
++}
++
++static int __init
++early_nvram_getall(char *buf, int count)
++{
++ char *var, *end;
++ int len = 0;
++
++ /* Too early? */
++ if (sbh == NULL)
++ return -1;
++
++ if (!nvram_buf[0])
++ early_nvram_init();
++
++ bzero(buf, count);
++
++ /* Write name=value\0 ... \0\0 */
++ var = &nvram_buf[sizeof(struct nvram_header)];
++ end = nvram_buf + sizeof(nvram_buf) - 2;
++ end[0] = end[1] = '\0';
++ for (; *var; var += strlen(var) + 1) {
++ if ((count - len) <= (strlen(var) + 1))
++ break;
++ len += sprintf(buf + len, "%s", var) + 1;
++ }
++
++ return 0;
++}
++#endif /* !MODULE */
++
++extern char * _nvram_get(const char *name);
++extern int _nvram_set(const char *name, const char *value);
++extern int _nvram_unset(const char *name);
++extern int _nvram_getall(char *buf, int count);
++extern int _nvram_commit(struct nvram_header *header);
++extern int _nvram_init(void *sbh);
++extern void _nvram_exit(void);
++
++/* Globals */
++static spinlock_t nvram_lock = SPIN_LOCK_UNLOCKED;
++static struct semaphore nvram_sem;
++static unsigned long nvram_offset = 0;
++static int nvram_major = -1;
++static devfs_handle_t nvram_handle = NULL;
++static struct mtd_info *nvram_mtd = NULL;
++
++int
++_nvram_read(char *buf)
++{
++ struct nvram_header *header = (struct nvram_header *) buf;
++ size_t len;
++
++ if (!nvram_mtd ||
++ MTD_READ(nvram_mtd, nvram_mtd->size - NVRAM_SPACE, NVRAM_SPACE, &len, buf) ||
++ len != NVRAM_SPACE ||
++ header->magic != NVRAM_MAGIC) {
++ /* Maybe we can recover some data from early initialization */
++ memcpy(buf, nvram_buf, NVRAM_SPACE);
++ }
++
++ return 0;
++}
++
++struct nvram_tuple *
++_nvram_realloc(struct nvram_tuple *t, const char *name, const char *value)
++{
++ if ((nvram_offset + strlen(value) + 1) > NVRAM_SPACE)
++ return NULL;
++
++ if (!t) {
++ if (!(t = kmalloc(sizeof(struct nvram_tuple) + strlen(name) + 1, GFP_ATOMIC)))
++ return NULL;
++
++ /* Copy name */
++ t->name = (char *) &t[1];
++ strcpy(t->name, name);
++
++ t->value = NULL;
++ }
++
++ /* Copy value */
++ if (!t->value || strcmp(t->value, value)) {
++ t->value = &nvram_buf[nvram_offset];
++ strcpy(t->value, value);
++ nvram_offset += strlen(value) + 1;
++ }
++
++ return t;
++}
++
++void
++_nvram_free(struct nvram_tuple *t)
++{
++ if (!t)
++ nvram_offset = 0;
++ else
++ kfree(t);
++}
++
++int
++nvram_set(const char *name, const char *value)
++{
++ unsigned long flags;
++ int ret;
++ struct nvram_header *header;
++
++ spin_lock_irqsave(&nvram_lock, flags);
++ if ((ret = _nvram_set(name, value))) {
++ /* Consolidate space and try again */
++ if ((header = kmalloc(NVRAM_SPACE, GFP_ATOMIC))) {
++ if (_nvram_commit(header) == 0)
++ ret = _nvram_set(name, value);
++ kfree(header);
++ }
++ }
++ spin_unlock_irqrestore(&nvram_lock, flags);
++
++ return ret;
++}
++
++char *
++real_nvram_get(const char *name)
++{
++ unsigned long flags;
++ char *value;
++
++ spin_lock_irqsave(&nvram_lock, flags);
++ value = _nvram_get(name);
++ spin_unlock_irqrestore(&nvram_lock, flags);
++
++ return value;
++}
++
++char *
++nvram_get(const char *name)
++{
++ if (nvram_major >= 0)
++ return real_nvram_get(name);
++ else
++ return early_nvram_get(name);
++}
++
++int
++nvram_unset(const char *name)
++{
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&nvram_lock, flags);
++ ret = _nvram_unset(name);
++ spin_unlock_irqrestore(&nvram_lock, flags);
++
++ return ret;
++}
++
++static void
++erase_callback(struct erase_info *done)
++{
++ wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv;
++ wake_up(wait_q);
++}
++
++int
++nvram_commit(void)
++{
++ char *buf;
++ size_t erasesize, len, magic_len;
++ unsigned int i;
++ int ret;
++ struct nvram_header *header;
++ unsigned long flags;
++ u_int32_t offset;
++ DECLARE_WAITQUEUE(wait, current);
++ wait_queue_head_t wait_q;
++ struct erase_info erase;
++ u_int32_t magic_offset = 0; /* Offset for writing MAGIC # */
++
++ if (!nvram_mtd) {
++ printk("nvram_commit: NVRAM not found\n");
++ return -ENODEV;
++ }
++
++ if (in_interrupt()) {
++ printk("nvram_commit: not committing in interrupt\n");
++ return -EINVAL;
++ }
++
++ /* Backup sector blocks to be erased */
++ erasesize = ROUNDUP(NVRAM_SPACE, nvram_mtd->erasesize);
++ if (!(buf = kmalloc(erasesize, GFP_KERNEL))) {
++ printk("nvram_commit: out of memory\n");
++ return -ENOMEM;
++ }
++
++ down(&nvram_sem);
++
++ if ((i = erasesize - NVRAM_SPACE) > 0) {
++ offset = nvram_mtd->size - erasesize;
++ len = 0;
++ ret = MTD_READ(nvram_mtd, offset, i, &len, buf);
++ if (ret || len != i) {
++ printk("nvram_commit: read error ret = %d, len = %d/%d\n", ret, len, i);
++ ret = -EIO;
++ goto done;
++ }
++ header = (struct nvram_header *)(buf + i);
++ magic_offset = i + ((void *)&header->magic - (void *)header);
++ } else {
++ offset = nvram_mtd->size - NVRAM_SPACE;
++ magic_offset = ((void *)&header->magic - (void *)header);
++ header = (struct nvram_header *)buf;
++ }
++
++ /* clear the existing magic # to mark the NVRAM as unusable
++ we can pull MAGIC bits low without erase */
++ header->magic = NVRAM_CLEAR_MAGIC; /* All zeros magic */
++
++ /* Unlock sector blocks (for Intel 28F320C3B flash) , 20060309 */
++ if(nvram_mtd->unlock)
++ nvram_mtd->unlock(nvram_mtd, offset, nvram_mtd->erasesize);
++
++ ret = MTD_WRITE(nvram_mtd, offset + magic_offset, sizeof(header->magic),
++ &magic_len, (char *)&header->magic);
++ if (ret || magic_len != sizeof(header->magic)) {
++ printk("nvram_commit: clear MAGIC error\n");
++ ret = -EIO;
++ goto done;
++ }
++
++ header->magic = NVRAM_MAGIC; /* reset MAGIC before we regenerate the NVRAM,
++ otherwise we'll have an incorrect CRC */
++ /* Regenerate NVRAM */
++ spin_lock_irqsave(&nvram_lock, flags);
++ ret = _nvram_commit(header);
++ spin_unlock_irqrestore(&nvram_lock, flags);
++ if (ret)
++ goto done;
++
++ /* Erase sector blocks */
++ init_waitqueue_head(&wait_q);
++ for (; offset < nvram_mtd->size - NVRAM_SPACE + header->len; offset += nvram_mtd->erasesize) {
++ erase.mtd = nvram_mtd;
++ erase.addr = offset;
++ erase.len = nvram_mtd->erasesize;
++ erase.callback = erase_callback;
++ erase.priv = (u_long) &wait_q;
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_wait_queue(&wait_q, &wait);
++
++ /* Unlock sector blocks */
++ if (nvram_mtd->unlock)
++ nvram_mtd->unlock(nvram_mtd, offset, nvram_mtd->erasesize);
++
++ if ((ret = MTD_ERASE(nvram_mtd, &erase))) {
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&wait_q, &wait);
++ printk("nvram_commit: erase error\n");
++ goto done;
++ }
++
++ /* Wait for erase to finish */
++ schedule();
++ remove_wait_queue(&wait_q, &wait);
++ }
++
++ /* Write partition up to end of data area */
++ header->magic = NVRAM_INVALID_MAGIC; /* All ones magic */
++ offset = nvram_mtd->size - erasesize;
++ i = erasesize - NVRAM_SPACE + header->len;
++ ret = MTD_WRITE(nvram_mtd, offset, i, &len, buf);
++ if (ret || len != i) {
++ printk("nvram_commit: write error\n");
++ ret = -EIO;
++ goto done;
++ }
++
++ /* Now mark the NVRAM in flash as "valid" by setting the correct
++ MAGIC # */
++ header->magic = NVRAM_MAGIC;
++ ret = MTD_WRITE(nvram_mtd, offset + magic_offset, sizeof(header->magic),
++ &magic_len, (char *)&header->magic);
++ if (ret || magic_len != sizeof(header->magic)) {
++ printk("nvram_commit: write MAGIC error\n");
++ ret = -EIO;
++ goto done;
++ }
++
++ /*
++ * Reading a few bytes back here will put the device
++ * back to the correct mode on certain flashes */
++ offset = nvram_mtd->size - erasesize;
++ ret = MTD_READ(nvram_mtd, offset, 4, &len, buf);
++
++ done:
++ up(&nvram_sem);
++ kfree(buf);
++
++ return ret;
++}
++
++int
++nvram_getall(char *buf, int count)
++{
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&nvram_lock, flags);
++ if (nvram_major >= 0)
++ ret = _nvram_getall(buf, count);
++ else
++ ret = early_nvram_getall(buf, count);
++ spin_unlock_irqrestore(&nvram_lock, flags);
++
++ return ret;
++}
++
++
++
++
++
++
++
++/* User mode interface below */
++
++static ssize_t
++dev_nvram_read(struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++ char tmp[100], *name = tmp, *value;
++ ssize_t ret;
++ unsigned long off;
++
++ if (count > sizeof(tmp)) {
++ if (!(name = kmalloc(count, GFP_KERNEL)))
++ return -ENOMEM;
++ }
++
++ if (copy_from_user(name, buf, count)) {
++ ret = -EFAULT;
++ goto done;
++ }
++
++ if (*name == '\0') {
++ /* Get all variables */
++ ret = nvram_getall(name, count);
++ if (ret == 0) {
++ if (copy_to_user(buf, name, count)) {
++ ret = -EFAULT;
++ goto done;
++ }
++ ret = count;
++ }
++ } else {
++ if (!(value = nvram_get(name))) {
++ ret = 0;
++ goto done;
++ }
++
++ /* Provide the offset into mmap() space */
++ off = (unsigned long) value - (unsigned long) nvram_buf;
++
++ if (put_user(off, (unsigned long *) buf)) {
++ ret = -EFAULT;
++ goto done;
++ }
++
++ ret = sizeof(unsigned long);
++ }
++
++ flush_cache_all();
++
++done:
++ if (name != tmp)
++ kfree(name);
++
++ return ret;
++}
++
++static ssize_t
++dev_nvram_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
++{
++ char tmp[100], *name = tmp, *value;
++ ssize_t ret;
++
++ if (count > sizeof(tmp)) {
++ if (!(name = kmalloc(count, GFP_KERNEL)))
++ return -ENOMEM;
++ }
++
++ if (copy_from_user(name, buf, count)) {
++ ret = -EFAULT;
++ goto done;
++ }
++
++ value = name;
++ name = strsep(&value, "=");
++ if (value)
++ ret = nvram_set(name, value) ? : count;
++ else
++ ret = nvram_unset(name) ? : count;
++
++ done:
++ if (name != tmp)
++ kfree(name);
++
++ return ret;
++}
++
++static int
++dev_nvram_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++ if (cmd != NVRAM_MAGIC)
++ return -EINVAL;
++
++ return nvram_commit();
++}
++
++static int
++dev_nvram_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ unsigned long offset = virt_to_phys(nvram_buf);
++
++ if (remap_page_range(vma->vm_start, offset, vma->vm_end-vma->vm_start,
++ vma->vm_page_prot))
++ return -EAGAIN;
++
++ return 0;
++}
++
++static int
++dev_nvram_open(struct inode *inode, struct file * file)
++{
++ MOD_INC_USE_COUNT;
++ return 0;
++}
++
++static int
++dev_nvram_release(struct inode *inode, struct file * file)
++{
++ MOD_DEC_USE_COUNT;
++ return 0;
++}
++
++static struct file_operations dev_nvram_fops = {
++ owner: THIS_MODULE,
++ open: dev_nvram_open,
++ release: dev_nvram_release,
++ read: dev_nvram_read,
++ write: dev_nvram_write,
++ ioctl: dev_nvram_ioctl,
++ mmap: dev_nvram_mmap,
++};
++
++static void
++dev_nvram_exit(void)
++{
++ int order = 0;
++ struct page *page, *end;
++
++ if (nvram_handle)
++ devfs_unregister(nvram_handle);
++
++ if (nvram_major >= 0)
++ devfs_unregister_chrdev(nvram_major, "nvram");
++
++ if (nvram_mtd)
++ put_mtd_device(nvram_mtd);
++
++ while ((PAGE_SIZE << order) < NVRAM_SPACE)
++ order++;
++ end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
++ for (page = virt_to_page(nvram_buf); page <= end; page++)
++ mem_map_unreserve(page);
++
++ _nvram_exit();
++}
++
++static int __init
++dev_nvram_init(void)
++{
++ int order = 0, ret = 0;
++ struct page *page, *end;
++ unsigned int i;
++
++ /* Allocate and reserve memory to mmap() */
++ while ((PAGE_SIZE << order) < NVRAM_SPACE)
++ order++;
++ end = virt_to_page(nvram_buf + (PAGE_SIZE << order) - 1);
++ for (page = virt_to_page(nvram_buf); page <= end; page++)
++ mem_map_reserve(page);
++
++#ifdef CONFIG_MTD
++ /* Find associated MTD device */
++ for (i = 0; i < MAX_MTD_DEVICES; i++) {
++ nvram_mtd = get_mtd_device(NULL, i);
++ if (nvram_mtd) {
++ if (!strcmp(nvram_mtd->name, "nvram") &&
++ nvram_mtd->size >= NVRAM_SPACE)
++ break;
++ put_mtd_device(nvram_mtd);
++ }
++ }
++ if (i >= MAX_MTD_DEVICES)
++ nvram_mtd = NULL;
++#endif
++
++ /* Initialize hash table lock */
++ spin_lock_init(&nvram_lock);
++
++ /* Initialize commit semaphore */
++ init_MUTEX(&nvram_sem);
++
++ /* Register char device */
++ if ((nvram_major = devfs_register_chrdev(0, "nvram", &dev_nvram_fops)) < 0) {
++ ret = nvram_major;
++ goto err;
++ }
++
++ /* Initialize hash table */
++ _nvram_init(sbh);
++
++ /* Create /dev/nvram handle */
++ nvram_handle = devfs_register(NULL, "nvram", DEVFS_FL_NONE, nvram_major, 0,
++ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, &dev_nvram_fops, NULL);
++
++ /* Set the SDRAM NCDL value into NVRAM if not already done */
++ if (getintvar(NULL, "sdram_ncdl") == 0) {
++ unsigned int ncdl;
++ char buf[] = "0x00000000";
++
++ if ((ncdl = sb_memc_get_ncdl(sbh))) {
++ sprintf(buf, "0x%08x", ncdl);
++ nvram_set("sdram_ncdl", buf);
++ nvram_commit();
++ }
++ }
++
++ return 0;
++
++ err:
++ dev_nvram_exit();
++ return ret;
++}
++
++module_init(dev_nvram_init);
++module_exit(dev_nvram_exit);
+diff -urN linux.old/arch/mips/bcm947xx/pcibios.c linux.dev/arch/mips/bcm947xx/pcibios.c
+--- linux.old/arch/mips/bcm947xx/pcibios.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/pcibios.c 2006-10-02 21:22:56.000000000 +0200
+@@ -0,0 +1,380 @@
++/*
++ * Low-Level PCI and SB support for BCM47xx (Linux support code)
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: pcibios.c,v 1.1.1.9 2006/02/27 03:42:55 honor Exp $
++ */
++
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/paccess.h>
++
++#include <typedefs.h>
++#include <osl.h>
++#include <bcmutils.h>
++#include <sbconfig.h>
++#include <sbutils.h>
++#include <hndpci.h>
++#include <pcicfg.h>
++#include <bcmdevs.h>
++#include <bcmnvram.h>
++
++/* Global SB handle */
++extern sb_t *bcm947xx_sbh;
++extern spinlock_t bcm947xx_sbh_lock;
++
++/* Convenience */
++#define sbh bcm947xx_sbh
++#define sbh_lock bcm947xx_sbh_lock
++
++static int
++sbpci_read_config_byte(struct pci_dev *dev, int where, u8 *value)
++{
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&sbh_lock, flags);
++ ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn),
++ PCI_FUNC(dev->devfn), where, value, sizeof(*value));
++ spin_unlock_irqrestore(&sbh_lock, flags);
++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
++}
++
++static int
++sbpci_read_config_word(struct pci_dev *dev, int where, u16 *value)
++{
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&sbh_lock, flags);
++ ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn),
++ PCI_FUNC(dev->devfn), where, value, sizeof(*value));
++ spin_unlock_irqrestore(&sbh_lock, flags);
++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
++}
++
++static int
++sbpci_read_config_dword(struct pci_dev *dev, int where, u32 *value)
++{
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&sbh_lock, flags);
++ ret = sbpci_read_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn),
++ PCI_FUNC(dev->devfn), where, value, sizeof(*value));
++ spin_unlock_irqrestore(&sbh_lock, flags);
++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
++}
++
++static int
++sbpci_write_config_byte(struct pci_dev *dev, int where, u8 value)
++{
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&sbh_lock, flags);
++ ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn),
++ PCI_FUNC(dev->devfn), where, &value, sizeof(value));
++ spin_unlock_irqrestore(&sbh_lock, flags);
++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
++}
++
++static int
++sbpci_write_config_word(struct pci_dev *dev, int where, u16 value)
++{
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&sbh_lock, flags);
++ ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn),
++ PCI_FUNC(dev->devfn), where, &value, sizeof(value));
++ spin_unlock_irqrestore(&sbh_lock, flags);
++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
++}
++
++static int
++sbpci_write_config_dword(struct pci_dev *dev, int where, u32 value)
++{
++ unsigned long flags;
++ int ret;
++
++ spin_lock_irqsave(&sbh_lock, flags);
++ ret = sbpci_write_config(sbh, dev->bus->number, PCI_SLOT(dev->devfn),
++ PCI_FUNC(dev->devfn), where, &value, sizeof(value));
++ spin_unlock_irqrestore(&sbh_lock, flags);
++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
++}
++
++static struct pci_ops pcibios_ops = {
++ sbpci_read_config_byte,
++ sbpci_read_config_word,
++ sbpci_read_config_dword,
++ sbpci_write_config_byte,
++ sbpci_write_config_word,
++ sbpci_write_config_dword
++};
++
++
++void __init
++pcibios_init(void)
++{
++ ulong flags;
++
++ if (!(sbh = sb_kattach()))
++ panic("sb_kattach failed");
++ spin_lock_init(&sbh_lock);
++
++ spin_lock_irqsave(&sbh_lock, flags);
++ sbpci_init(sbh);
++ spin_unlock_irqrestore(&sbh_lock, flags);
++
++ set_io_port_base((unsigned long) ioremap_nocache(SB_PCI_MEM, 0x04000000));
++
++ /* Scan the SB bus */
++ pci_scan_bus(0, &pcibios_ops, NULL);
++
++}
++
++char * __init
++pcibios_setup(char *str)
++{
++ if (!strncmp(str, "ban=", 4)) {
++ sbpci_ban(simple_strtoul(str + 4, NULL, 0));
++ return NULL;
++ }
++
++ return (str);
++}
++
++static u32 pci_iobase = 0x100;
++static u32 pci_membase = SB_PCI_DMA;
++
++void __init
++pcibios_fixup_bus(struct pci_bus *b)
++{
++ struct list_head *ln;
++ struct pci_dev *d;
++ struct resource *res;
++ int pos, size;
++ u32 *base;
++ u8 irq;
++
++ printk("PCI: Fixing up bus %d\n", b->number);
++
++ /* Fix up SB */
++ if (b->number == 0) {
++ for (ln = b->devices.next; ln != &b->devices; ln = ln->next) {
++ d = pci_dev_b(ln);
++ /* Fix up interrupt lines */
++ pci_read_config_byte(d, PCI_INTERRUPT_LINE, &irq);
++ d->irq = irq + 2;
++ pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
++ }
++ }
++
++ /* Fix up external PCI */
++ else {
++ for (ln = b->devices.next; ln != &b->devices; ln = ln->next) {
++ d = pci_dev_b(ln);
++ /* Fix up resource bases */
++ for (pos = 0; pos < 6; pos++) {
++ res = &d->resource[pos];
++ base = (res->flags & IORESOURCE_IO) ? &pci_iobase : &pci_membase;
++ if (res->end) {
++ size = res->end - res->start + 1;
++ if (*base & (size - 1))
++ *base = (*base + size) & ~(size - 1);
++ res->start = *base;
++ res->end = res->start + size - 1;
++ *base += size;
++ pci_write_config_dword(d,
++ PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
++ }
++ /* Fix up PCI bridge BAR0 only */
++ if (b->number == 1 && PCI_SLOT(d->devfn) == 0)
++ break;
++ }
++ /* Fix up interrupt lines */
++ if (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL))
++ d->irq = (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL))->irq;
++ pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
++ }
++ }
++}
++
++unsigned int
++pcibios_assign_all_busses(void)
++{
++ return 1;
++}
++
++void
++pcibios_align_resource(void *data, struct resource *res,
++ unsigned long size, unsigned long align)
++{
++}
++
++int
++pcibios_enable_resources(struct pci_dev *dev)
++{
++ u16 cmd, old_cmd;
++ int idx;
++ struct resource *r;
++
++ /* External PCI only */
++ if (dev->bus->number == 0)
++ return 0;
++
++ pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ old_cmd = cmd;
++ for (idx = 0; idx < 6; idx++) {
++ r = &dev->resource[idx];
++ 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", dev->slot_name, old_cmd, cmd);
++ pci_write_config_word(dev, PCI_COMMAND, cmd);
++ }
++ return 0;
++}
++
++int
++pcibios_enable_device(struct pci_dev *dev, int mask)
++{
++ ulong flags;
++ uint coreidx;
++ void *regs;
++
++ /* External PCI device enable */
++ if (dev->bus->number != 0)
++ return pcibios_enable_resources(dev);
++
++ /* These cores come out of reset enabled */
++ if (dev->device == SB_MIPS ||
++ dev->device == SB_MIPS33 ||
++ dev->device == SB_EXTIF ||
++ dev->device == SB_CC)
++ return 0;
++
++ spin_lock_irqsave(&sbh_lock, flags);
++ coreidx = sb_coreidx(sbh);
++ regs = sb_setcoreidx(sbh, PCI_SLOT(dev->devfn));
++ if (!regs)
++ return PCIBIOS_DEVICE_NOT_FOUND;
++
++ /*
++ * The USB core requires a special bit to be set during core
++ * reset to enable host (OHCI) mode. Resetting the SB core in
++ * pcibios_enable_device() is a hack for compatibility with
++ * vanilla usb-ohci so that it does not have to know about
++ * SB. A driver that wants to use the USB core in device mode
++ * should know about SB and should reset the bit back to 0
++ * after calling pcibios_enable_device().
++ */
++ if (sb_coreid(sbh) == SB_USB) {
++ sb_core_disable(sbh, sb_coreflags(sbh, 0, 0));
++ sb_core_reset(sbh, 1 << 29, 0);
++ }
++ /*
++ * USB 2.0 special considerations:
++ *
++ * 1. Since the core supports both OHCI and EHCI functions, it must
++ * only be reset once.
++ *
++ * 2. In addition to the standard SB reset sequence, the Host Control
++ * Register must be programmed to bring the USB core and various
++ * phy components out of reset.
++ */
++ else if (sb_coreid(sbh) == SB_USB20H) {
++ if (!sb_iscoreup(sbh)) {
++ sb_core_reset(sbh, 0, 0);
++ writel(0x7FF, (ulong)regs + 0x200);
++ udelay(1);
++ }
++ } else
++ sb_core_reset(sbh, 0, 0);
++
++ sb_setcoreidx(sbh, coreidx);
++ spin_unlock_irqrestore(&sbh_lock, flags);
++
++ return 0;
++}
++
++void
++pcibios_update_resource(struct pci_dev *dev, struct resource *root,
++ struct resource *res, int resource)
++{
++ unsigned long where, size;
++ u32 reg;
++
++ /* External PCI only */
++ if (dev->bus->number == 0)
++ return;
++
++ where = PCI_BASE_ADDRESS_0 + (resource * 4);
++ size = res->end - res->start;
++ pci_read_config_dword(dev, where, &reg);
++ reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
++ pci_write_config_dword(dev, where, reg);
++}
++
++static void __init
++quirk_sbpci_bridge(struct pci_dev *dev)
++{
++ if (dev->bus->number != 1 || PCI_SLOT(dev->devfn) != 0)
++ return;
++
++ printk("PCI: Fixing up bridge\n");
++
++ /* Enable PCI bridge bus mastering and memory space */
++ pci_set_master(dev);
++ pcibios_enable_resources(dev);
++
++ /* Enable PCI bridge BAR1 prefetch and burst */
++ pci_write_config_dword(dev, PCI_BAR1_CONTROL, 3);
++}
++
++struct pci_fixup pcibios_fixups[] = {
++ { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, quirk_sbpci_bridge },
++ { 0 }
++};
++
++/*
++ * If we set up a device for bus mastering, we need to check the latency
++ * timer as certain crappy BIOSes forget to set it properly.
++ */
++unsigned int pcibios_max_latency = 255;
++
++void pcibios_set_master(struct pci_dev *dev)
++{
++ u8 lat;
++ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
++ if (lat < 16)
++ lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
++ else if (lat > pcibios_max_latency)
++ lat = pcibios_max_latency;
++ else
++ return;
++ printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", dev->slot_name, lat);
++ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
++}
++
+diff -urN linux.old/arch/mips/bcm947xx/prom.c linux.dev/arch/mips/bcm947xx/prom.c
+--- linux.old/arch/mips/bcm947xx/prom.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/prom.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,41 @@
++/*
++ * Early initialization code for BCM94710 boards
++ *
++ * Copyright 2004, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: prom.c,v 1.1 2005/03/16 13:49:59 wbx Exp $
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <asm/bootinfo.h>
++
++void __init
++prom_init(int argc, const char **argv)
++{
++ unsigned long mem;
++
++ mips_machgroup = MACH_GROUP_BRCM;
++ mips_machtype = MACH_BCM947XX;
++
++ /* Figure out memory size by finding aliases */
++ for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) {
++ if (*(unsigned long *)((unsigned long)(prom_init) + mem) ==
++ *(unsigned long *)(prom_init))
++ break;
++ }
++ add_memory_region(0, mem, BOOT_MEM_RAM);
++}
++
++void __init
++prom_free_prom_memory(void)
++{
++}
+diff -urN linux.old/arch/mips/bcm947xx/sbmips.c linux.dev/arch/mips/bcm947xx/sbmips.c
+--- linux.old/arch/mips/bcm947xx/sbmips.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/sbmips.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,1132 @@
++/*
++ * BCM47XX Sonics SiliconBackplane MIPS core routines
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: hndmips.c,v 1.1.1.1 2006/02/27 03:43:16 honor Exp $
++ */
++
++#include <typedefs.h>
++#include <bcmdefs.h>
++#include <osl.h>
++#include <bcmutils.h>
++#include <sbutils.h>
++#include <bcmdevs.h>
++#include <bcmnvram.h>
++#include <sbconfig.h>
++#include <sbextif.h>
++#include <sbchipc.h>
++#include <sbmemc.h>
++#include <mipsinc.h>
++#include <sbhndmips.h>
++#include <hndcpu.h>
++
++/* sbipsflag register format, indexed by irq. */
++static const uint32 sbips_int_mask[] = {
++ 0, /* placeholder */
++ SBIPS_INT1_MASK,
++ SBIPS_INT2_MASK,
++ SBIPS_INT3_MASK,
++ SBIPS_INT4_MASK
++};
++
++static const uint32 sbips_int_shift[] = {
++ 0, /* placeholder */
++ SBIPS_INT1_SHIFT,
++ SBIPS_INT2_SHIFT,
++ SBIPS_INT3_SHIFT,
++ SBIPS_INT4_SHIFT
++};
++
++/*
++ * Map SB cores sharing the MIPS hardware IRQ0 to virtual dedicated OS IRQs.
++ * Per-port BSP code is required to provide necessary translations between
++ * the shared MIPS IRQ and the virtual OS IRQs based on SB core flag.
++ *
++ * See sb_irq() for the mapping.
++ */
++static uint shirq_map_base = 0;
++
++/* Returns the SB interrupt flag of the current core. */
++static uint32
++sb_getflag(sb_t *sbh)
++{
++ osl_t *osh;
++ void *regs;
++ sbconfig_t *sb;
++
++ osh = sb_osh(sbh);
++ regs = sb_coreregs(sbh);
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++
++ return (R_REG(osh, &sb->sbtpsflag) & SBTPS_NUM0_MASK);
++}
++
++/*
++ * Returns the MIPS IRQ assignment of the current core. If unassigned,
++ * 0 is returned.
++ */
++uint
++sb_irq(sb_t *sbh)
++{
++ osl_t *osh;
++ uint idx;
++ void *regs;
++ sbconfig_t *sb;
++ uint32 flag, sbipsflag;
++ uint irq = 0;
++
++ osh = sb_osh(sbh);
++ flag = sb_getflag(sbh);
++
++ idx = sb_coreidx(sbh);
++
++ if ((regs = sb_setcore(sbh, SB_MIPS, 0)) ||
++ (regs = sb_setcore(sbh, SB_MIPS33, 0))) {
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++
++ /* sbipsflag specifies which core is routed to interrupts 1 to 4 */
++ sbipsflag = R_REG(osh, &sb->sbipsflag);
++ for (irq = 1; irq <= 4; irq++) {
++ if (((sbipsflag & sbips_int_mask[irq]) >> sbips_int_shift[irq]) == flag)
++ break;
++ }
++ if (irq == 5)
++ irq = 0;
++ }
++
++ sb_setcoreidx(sbh, idx);
++
++ return irq;
++}
++
++/* Clears the specified MIPS IRQ. */
++static void
++BCMINITFN(sb_clearirq)(sb_t *sbh, uint irq)
++{
++ osl_t *osh;
++ void *regs;
++ sbconfig_t *sb;
++
++ osh = sb_osh(sbh);
++
++ if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
++ !(regs = sb_setcore(sbh, SB_MIPS33, 0)))
++ ASSERT(regs);
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++
++ if (irq == 0)
++ W_REG(osh, &sb->sbintvec, 0);
++ else
++ OR_REG(osh, &sb->sbipsflag, sbips_int_mask[irq]);
++}
++
++/*
++ * Assigns the specified MIPS IRQ to the specified core. Shared MIPS
++ * IRQ 0 may be assigned more than once.
++ *
++ * The old assignment to the specified core is removed first.
++ */
++static void
++BCMINITFN(sb_setirq)(sb_t *sbh, uint irq, uint coreid, uint coreunit)
++{
++ osl_t *osh;
++ void *regs;
++ sbconfig_t *sb;
++ uint32 flag;
++ uint oldirq;
++
++ osh = sb_osh(sbh);
++
++ regs = sb_setcore(sbh, coreid, coreunit);
++ ASSERT(regs);
++ flag = sb_getflag(sbh);
++ oldirq = sb_irq(sbh);
++ if (oldirq)
++ sb_clearirq(sbh, oldirq);
++
++ if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
++ !(regs = sb_setcore(sbh, SB_MIPS33, 0)))
++ ASSERT(regs);
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++
++ if (!oldirq)
++ AND_REG(osh, &sb->sbintvec, ~(1 << flag));
++
++ if (irq == 0)
++ OR_REG(osh, &sb->sbintvec, 1 << flag);
++ else {
++ flag <<= sbips_int_shift[irq];
++ ASSERT(!(flag & ~sbips_int_mask[irq]));
++ flag |= R_REG(osh, &sb->sbipsflag) & ~sbips_int_mask[irq];
++ W_REG(osh, &sb->sbipsflag, flag);
++ }
++}
++
++/*
++ * Initializes clocks and interrupts. SB and NVRAM access must be
++ * initialized prior to calling.
++ *
++ * 'shirqmap' enables virtual dedicated OS IRQ mapping if non-zero.
++ */
++void
++BCMINITFN(sb_mips_init)(sb_t *sbh, uint shirqmap)
++{
++ osl_t *osh;
++ ulong hz, ns, tmp;
++ extifregs_t *eir;
++ chipcregs_t *cc;
++ char *value;
++ uint irq;
++
++ osh = sb_osh(sbh);
++
++ /* Figure out current SB clock speed */
++ if ((hz = sb_clock(sbh)) == 0)
++ hz = 100000000;
++ ns = 1000000000 / hz;
++
++ /* Setup external interface timing */
++ if ((eir = sb_setcore(sbh, SB_EXTIF, 0))) {
++ /* Initialize extif so we can get to the LEDs and external UART */
++ W_REG(osh, &eir->prog_config, CF_EN);
++
++ /* Set timing for the flash */
++ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
++ tmp = tmp | (CEIL(40, ns) << FW_W1_SHIFT); /* W1 = 40nS */
++ tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
++ W_REG(osh, &eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
++
++ /* Set programmable interface timing for external uart */
++ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
++ tmp = tmp | (CEIL(20, ns) << FW_W2_SHIFT); /* W2 = 20nS */
++ tmp = tmp | (CEIL(100, ns) << FW_W1_SHIFT); /* W1 = 100nS */
++ tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
++ W_REG(osh, &eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
++ } else if ((cc = sb_setcore(sbh, SB_CC, 0))) {
++ /* Set timing for the flash */
++ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
++ tmp |= CEIL(10, ns) << FW_W1_SHIFT; /* W1 = 10nS */
++ tmp |= CEIL(120, ns); /* W0 = 120nS */
++ if ((sb_corerev(sbh) < 9) ||
++ (BCMINIT(sb_chip)(sbh) == 0x5365))
++ W_REG(osh, &cc->flash_waitcount, tmp);
++
++ if ((sb_corerev(sbh) < 9) ||
++ ((sb_chip(sbh) == BCM5350_CHIP_ID) && sb_chiprev(sbh) == 0) ||
++ (BCMINIT(sb_chip)(sbh) == 0x5365)) {
++ W_REG(osh, &cc->pcmcia_memwait, tmp);
++ }
++
++ /* Save shared IRQ mapping base */
++ shirq_map_base = shirqmap;
++ }
++
++ /* Chip specific initialization */
++ switch (sb_chip(sbh)) {
++ case BCM4710_CHIP_ID:
++ /* Clear interrupt map */
++ for (irq = 0; irq <= 4; irq++)
++ sb_clearirq(sbh, irq);
++ sb_setirq(sbh, 0, SB_CODEC, 0);
++ sb_setirq(sbh, 0, SB_EXTIF, 0);
++ sb_setirq(sbh, 2, SB_ENET, 1);
++ sb_setirq(sbh, 3, SB_ILINE20, 0);
++ sb_setirq(sbh, 4, SB_PCI, 0);
++ ASSERT(eir);
++ value = nvram_get("et0phyaddr");
++ if (value && !strcmp(value, "31")) {
++ /* Enable internal UART */
++ W_REG(osh, &eir->corecontrol, CC_UE);
++ /* Give USB its own interrupt */
++ sb_setirq(sbh, 1, SB_USB, 0);
++ } else {
++ /* Disable internal UART */
++ W_REG(osh, &eir->corecontrol, 0);
++ /* Give Ethernet its own interrupt */
++ sb_setirq(sbh, 1, SB_ENET, 0);
++ sb_setirq(sbh, 0, SB_USB, 0);
++ }
++ break;
++ case BCM5350_CHIP_ID:
++ /* Clear interrupt map */
++ for (irq = 0; irq <= 4; irq++)
++ sb_clearirq(sbh, irq);
++ sb_setirq(sbh, 0, SB_CC, 0);
++ sb_setirq(sbh, 0, SB_MIPS33, 0);
++ sb_setirq(sbh, 1, SB_D11, 0);
++ sb_setirq(sbh, 2, SB_ENET, 0);
++ sb_setirq(sbh, 3, SB_PCI, 0);
++ sb_setirq(sbh, 4, SB_USB, 0);
++ break;
++ case BCM4785_CHIP_ID:
++ /* Reassign PCI to irq 4 */
++ sb_setirq(sbh, 4, SB_PCI, 0);
++ break;
++ }
++}
++
++uint32
++BCMINITFN(sb_cpu_clock)(sb_t *sbh)
++{
++ extifregs_t *eir;
++ chipcregs_t *cc;
++ uint32 n, m;
++ uint idx;
++ uint32 pll_type, rate = 0;
++
++ /* get index of the current core */
++ idx = sb_coreidx(sbh);
++ pll_type = PLL_TYPE1;
++
++ /* switch to extif or chipc core */
++ if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
++ n = R_REG(osh, &eir->clockcontrol_n);
++ m = R_REG(osh, &eir->clockcontrol_sb);
++ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
++ pll_type = R_REG(osh, &cc->capabilities) & CAP_PLL_MASK;
++ n = R_REG(osh, &cc->clockcontrol_n);
++ if ((pll_type == PLL_TYPE2) ||
++ (pll_type == PLL_TYPE4) ||
++ (pll_type == PLL_TYPE6) ||
++ (pll_type == PLL_TYPE7))
++ m = R_REG(osh, &cc->clockcontrol_m3);
++ else if (pll_type == PLL_TYPE5) {
++ rate = 200000000;
++ goto out;
++ }
++ else if (pll_type == PLL_TYPE3) {
++ if (sb_chip(sbh) == BCM5365_CHIP_ID) {
++ rate = 200000000;
++ goto out;
++ }
++ /* 5350 uses m2 to control mips */
++ else
++ m = R_REG(osh, &cc->clockcontrol_m2);
++ } else
++ m = R_REG(osh, &cc->clockcontrol_sb);
++ } else
++ goto out;
++
++
++ /* calculate rate */
++ if (BCMINIT(sb_chip)(sbh) == 0x5365)
++ rate = 100000000;
++ else
++ rate = sb_clock_rate(pll_type, n, m);
++
++ if (pll_type == PLL_TYPE6)
++ rate = SB2MIPS_T6(rate);
++
++out:
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++
++ return rate;
++}
++
++#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
++
++static void
++BCMINITFN(handler)(void)
++{
++ __asm__(
++ ".set\tmips32\n\t"
++ "ssnop\n\t"
++ "ssnop\n\t"
++ /* Disable interrupts */
++ /* MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~(ALLINTS | STO_IE)); */
++ "mfc0 $15, $12\n\t"
++ /* Just a Hack to not to use reg 'at' which was causing problems on 4704 A2 */
++ "li $14, -31746\n\t"
++ "and $15, $15, $14\n\t"
++ "mtc0 $15, $12\n\t"
++ "eret\n\t"
++ "nop\n\t"
++ "nop\n\t"
++ ".set\tmips0");
++}
++
++/* The following MUST come right after handler() */
++static void
++BCMINITFN(afterhandler)(void)
++{
++}
++
++/*
++ * Set the MIPS, backplane and PCI clocks as closely as possible.
++ *
++ * MIPS clocks synchronization function has been moved from PLL in chipcommon
++ * core rev. 15 to a DLL inside the MIPS core in 4785.
++ */
++bool
++BCMINITFN(sb_mips_setclock)(sb_t *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock)
++{
++ extifregs_t *eir = NULL;
++ chipcregs_t *cc = NULL;
++ mipsregs_t *mipsr = NULL;
++ volatile uint32 *clockcontrol_n, *clockcontrol_sb, *clockcontrol_pci, *clockcontrol_m2;
++ uint32 orig_n, orig_sb, orig_pci, orig_m2, orig_mips, orig_ratio_parm, orig_ratio_cfg;
++ uint32 pll_type, sync_mode;
++ uint ic_size, ic_lsize;
++ uint idx, i;
++
++ /* PLL configuration: type 1 */
++ typedef struct {
++ uint32 mipsclock;
++ uint16 n;
++ uint32 sb;
++ uint32 pci33;
++ uint32 pci25;
++ } n3m_table_t;
++ static n3m_table_t BCMINITDATA(type1_table)[] = {
++ /* 96.000 32.000 24.000 */
++ { 96000000, 0x0303, 0x04020011, 0x11030011, 0x11050011 },
++ /* 100.000 33.333 25.000 */
++ { 100000000, 0x0009, 0x04020011, 0x11030011, 0x11050011 },
++ /* 104.000 31.200 24.960 */
++ { 104000000, 0x0802, 0x04020011, 0x11050009, 0x11090009 },
++ /* 108.000 32.400 24.923 */
++ { 108000000, 0x0403, 0x04020011, 0x11050009, 0x02000802 },
++ /* 112.000 32.000 24.889 */
++ { 112000000, 0x0205, 0x04020011, 0x11030021, 0x02000403 },
++ /* 115.200 32.000 24.000 */
++ { 115200000, 0x0303, 0x04020009, 0x11030011, 0x11050011 },
++ /* 120.000 30.000 24.000 */
++ { 120000000, 0x0011, 0x04020011, 0x11050011, 0x11090011 },
++ /* 124.800 31.200 24.960 */
++ { 124800000, 0x0802, 0x04020009, 0x11050009, 0x11090009 },
++ /* 128.000 32.000 24.000 */
++ { 128000000, 0x0305, 0x04020011, 0x11050011, 0x02000305 },
++ /* 132.000 33.000 24.750 */
++ { 132000000, 0x0603, 0x04020011, 0x11050011, 0x02000305 },
++ /* 136.000 32.640 24.727 */
++ { 136000000, 0x0c02, 0x04020011, 0x11090009, 0x02000603 },
++ /* 140.000 30.000 24.706 */
++ { 140000000, 0x0021, 0x04020011, 0x11050021, 0x02000c02 },
++ /* 144.000 30.857 24.686 */
++ { 144000000, 0x0405, 0x04020011, 0x01020202, 0x11090021 },
++ /* 150.857 33.000 24.000 */
++ { 150857142, 0x0605, 0x04020021, 0x02000305, 0x02000605 },
++ /* 152.000 32.571 24.000 */
++ { 152000000, 0x0e02, 0x04020011, 0x11050021, 0x02000e02 },
++ /* 156.000 31.200 24.960 */
++ { 156000000, 0x0802, 0x04020005, 0x11050009, 0x11090009 },
++ /* 160.000 32.000 24.000 */
++ { 160000000, 0x0309, 0x04020011, 0x11090011, 0x02000309 },
++ /* 163.200 32.640 24.727 */
++ { 163200000, 0x0c02, 0x04020009, 0x11090009, 0x02000603 },
++ /* 168.000 32.000 24.889 */
++ { 168000000, 0x0205, 0x04020005, 0x11030021, 0x02000403 },
++ /* 176.000 33.000 24.000 */
++ { 176000000, 0x0602, 0x04020003, 0x11050005, 0x02000602 },
++ };
++
++ /* PLL configuration: type 3 */
++ typedef struct {
++ uint32 mipsclock;
++ uint16 n;
++ uint32 m2; /* that is the clockcontrol_m2 */
++ } type3_table_t;
++ static type3_table_t type3_table[] = {
++ /* for 5350, mips clock is always double sb clock */
++ { 150000000, 0x311, 0x4020005 },
++ { 200000000, 0x311, 0x4020003 },
++ };
++
++ /* PLL configuration: type 2, 4, 7 */
++ typedef struct {
++ uint32 mipsclock;
++ uint32 sbclock;
++ uint16 n;
++ uint32 sb;
++ uint32 pci33;
++ uint32 m2;
++ uint32 m3;
++ uint32 ratio_cfg;
++ uint32 ratio_parm;
++ uint32 d11_r1;
++ uint32 d11_r2;
++ } n4m_table_t;
++ static n4m_table_t BCMINITDATA(type2_table)[] = {
++ { 120000000, 60000000, 0x0303, 0x01000200, 0x01000600, 0x01000200, 0x05000200, 11,
++ 0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 150000000, 75000000, 0x0303, 0x01000100, 0x01000600, 0x01000100, 0x05000100, 11,
++ 0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 180000000, 80000000, 0x0403, 0x01010000, 0x01020300, 0x01020600, 0x05000100, 8,
++ 0x012a00a9, 9 /* ratio 4/9 */, 0x012a00a9 },
++ { 180000000, 90000000, 0x0403, 0x01000100, 0x01020300, 0x01000100, 0x05000100, 11,
++ 0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 200000000, 100000000, 0x0303, 0x02010000, 0x02040001, 0x02010000, 0x06000001, 11,
++ 0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 211200000, 105600000, 0x0902, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 11,
++ 0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 220800000, 110400000, 0x1500, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 11,
++ 0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 230400000, 115200000, 0x0604, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 11,
++ 0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 234000000, 104000000, 0x0b01, 0x01010000, 0x01010700, 0x01020600, 0x05000100, 8,
++ 0x012a00a9, 9 /* ratio 4/9 */, 0x012a00a9 },
++ { 240000000, 120000000, 0x0803, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 11,
++ 0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 252000000, 126000000, 0x0504, 0x01000100, 0x01020500, 0x01000100, 0x05000100, 11,
++ 0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 264000000, 132000000, 0x0903, 0x01000200, 0x01020700, 0x01000200, 0x05000200, 11,
++ 0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 270000000, 120000000, 0x0703, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 8,
++ 0x012a00a9, 9 /* ratio 4/9 */, 0x012a00a9 },
++ { 276000000, 122666666, 0x1500, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 8,
++ 0x012a00a9, 9 /* ratio 4/9 */, 0x012a00a9 },
++ { 280000000, 140000000, 0x0503, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 11,
++ 0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 288000000, 128000000, 0x0604, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 8,
++ 0x012a00a9, 9 /* ratio 4/9 */, 0x012a00a9 },
++ { 288000000, 144000000, 0x0404, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 11,
++ 0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 300000000, 133333333, 0x0803, 0x01010000, 0x01020600, 0x01010100, 0x05000100, 8,
++ 0x012a00a9, 9 /* ratio 4/9 */, 0x012a00a9 },
++ { 300000000, 150000000, 0x0803, 0x01000100, 0x01020600, 0x01010100, 0x05000100, 11,
++ 0x0aaa0555, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 330000000, 132000000, 0x0903, 0x01000200, 0x00020200, 0x01010100, 0x05000100, 0,
++ 0, 10 /* ratio 4/10 */, 0x02520129 },
++ { 330000000, 146666666, 0x0903, 0x01010000, 0x00020200, 0x01010100, 0x05000100, 0,
++ 0, 9 /* ratio 4/9 */, 0x012a00a9 },
++ { 330000000, 165000000, 0x0903, 0x01000100, 0x00020200, 0x01010100, 0x05000100, 0,
++ 0, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 360000000, 120000000, 0x0a03, 0x01000300, 0x00010201, 0x01010200, 0x05000100, 0,
++ 0, 12 /* ratio 4/12 */, 0x04920492 },
++ { 360000000, 144000000, 0x0a03, 0x01000200, 0x00010201, 0x01010200, 0x05000100, 0,
++ 0, 10 /* ratio 4/10 */, 0x02520129 },
++ { 360000000, 160000000, 0x0a03, 0x01010000, 0x00010201, 0x01010200, 0x05000100, 0,
++ 0, 9 /* ratio 4/9 */, 0x012a00a9 },
++ { 360000000, 180000000, 0x0a03, 0x01000100, 0x00010201, 0x01010200, 0x05000100, 0,
++ 0, 8 /* ratio 4/8 */, 0x00aa0055 },
++ { 390000000, 130000000, 0x0b03, 0x01010100, 0x00020101, 0x01020100, 0x05000100, 0,
++ 0, 12 /* ratio 4/12 */, 0x04920492 },
++ { 390000000, 156000000, 0x0b03, 0x01000200, 0x00020101, 0x01020100, 0x05000100, 0,
++ 0, 10 /* ratio 4/10 */, 0x02520129 },
++ { 390000000, 173000000, 0x0b03, 0x01010000, 0x00020101, 0x01020100, 0x05000100, 0,
++ 0, 9 /* ratio 4/9 */, 0x012a00a9 },
++ { 390000000, 195000000, 0x0b03, 0x01000100, 0x00020101, 0x01020100, 0x05000100, 0,
++ 0, 8 /* ratio 4/8 */, 0x00aa0055 },
++ };
++ static n4m_table_t BCMINITDATA(type4_table)[] = {
++ { 120000000, 60000000, 0x0009, 0x11020009, 0x01030203, 0x11020009, 0x04000009, 11,
++ 0x0aaa0555 },
++ { 150000000, 75000000, 0x0009, 0x11050002, 0x01030203, 0x11050002, 0x04000005, 11,
++ 0x0aaa0555 },
++ { 192000000, 96000000, 0x0702, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11,
++ 0x0aaa0555 },
++ { 198000000, 99000000, 0x0603, 0x11020005, 0x11030011, 0x11020005, 0x04000005, 11,
++ 0x0aaa0555 },
++ { 200000000, 100000000, 0x0009, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 11,
++ 0x0aaa0555 },
++ { 204000000, 102000000, 0x0c02, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11,
++ 0x0aaa0555 },
++ { 208000000, 104000000, 0x0802, 0x11030002, 0x11090005, 0x11030002, 0x04000003, 11,
++ 0x0aaa0555 },
++ { 210000000, 105000000, 0x0209, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11,
++ 0x0aaa0555 },
++ { 216000000, 108000000, 0x0111, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11,
++ 0x0aaa0555 },
++ { 224000000, 112000000, 0x0205, 0x11030002, 0x02002103, 0x11030002, 0x04000003, 11,
++ 0x0aaa0555 },
++ { 228000000, 101333333, 0x0e02, 0x11030003, 0x11210005, 0x01030305, 0x04000005, 8,
++ 0x012a00a9 },
++ { 228000000, 114000000, 0x0e02, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 11,
++ 0x0aaa0555 },
++ { 240000000, 102857143, 0x0109, 0x04000021, 0x01050203, 0x11030021, 0x04000003, 13,
++ 0x254a14a9 },
++ { 240000000, 120000000, 0x0109, 0x11030002, 0x01050203, 0x11030002, 0x04000003, 11,
++ 0x0aaa0555 },
++ { 252000000, 100800000, 0x0203, 0x04000009, 0x11050005, 0x02000209, 0x04000002, 9,
++ 0x02520129 },
++ { 252000000, 126000000, 0x0203, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 11,
++ 0x0aaa0555 },
++ { 264000000, 132000000, 0x0602, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 11,
++ 0x0aaa0555 },
++ { 272000000, 116571428, 0x0c02, 0x04000021, 0x02000909, 0x02000221, 0x04000003, 13,
++ 0x254a14a9 },
++ { 280000000, 120000000, 0x0209, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 13,
++ 0x254a14a9 },
++ { 288000000, 123428571, 0x0111, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 13,
++ 0x254a14a9 },
++ { 300000000, 120000000, 0x0009, 0x04000009, 0x01030203, 0x02000902, 0x04000002, 9,
++ 0x02520129 },
++ { 300000000, 150000000, 0x0009, 0x04000005, 0x01030203, 0x04000005, 0x04000002, 11,
++ 0x0aaa0555 }
++ };
++ static n4m_table_t BCMINITDATA(type7_table)[] = {
++ { 183333333, 91666666, 0x0605, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11,
++ 0x0aaa0555 },
++ { 187500000, 93750000, 0x0a03, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11,
++ 0x0aaa0555 },
++ { 196875000, 98437500, 0x1003, 0x11020005, 0x11050011, 0x11020005, 0x04000005, 11,
++ 0x0aaa0555 },
++ { 200000000, 100000000, 0x0311, 0x04000011, 0x11030011, 0x04000009, 0x04000003, 11,
++ 0x0aaa0555 },
++ { 200000000, 100000000, 0x0311, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 11,
++ 0x0aaa0555 },
++ { 206250000, 103125000, 0x1103, 0x11020005, 0x11050011, 0x11020005, 0x04000005, 11,
++ 0x0aaa0555 },
++ { 212500000, 106250000, 0x0c05, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11,
++ 0x0aaa0555 },
++ { 215625000, 107812500, 0x1203, 0x11090009, 0x11050005, 0x11020005, 0x04000005, 11,
++ 0x0aaa0555 },
++ { 216666666, 108333333, 0x0805, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11,
++ 0x0aaa0555 },
++ { 225000000, 112500000, 0x0d03, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11,
++ 0x0aaa0555 },
++ { 233333333, 116666666, 0x0905, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11,
++ 0x0aaa0555 },
++ { 237500000, 118750000, 0x0e05, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 11,
++ 0x0aaa0555 },
++ { 240000000, 120000000, 0x0b11, 0x11020009, 0x11210009, 0x11020009, 0x04000009, 11,
++ 0x0aaa0555 },
++ { 250000000, 125000000, 0x0f03, 0x11020003, 0x11210003, 0x11020003, 0x04000003, 11,
++ 0x0aaa0555 }
++ };
++
++ ulong start, end, dst;
++ bool ret = FALSE;
++
++ volatile uint32 *dll_ctrl = (volatile uint32 *)0xff400008;
++ volatile uint32 *dll_r1 = (volatile uint32 *)0xff400010;
++ volatile uint32 *dll_r2 = (volatile uint32 *)0xff400018;
++
++ /* get index of the current core */
++ idx = sb_coreidx(sbh);
++ clockcontrol_m2 = NULL;
++
++ /* switch to extif or chipc core */
++ if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
++ pll_type = PLL_TYPE1;
++ clockcontrol_n = &eir->clockcontrol_n;
++ clockcontrol_sb = &eir->clockcontrol_sb;
++ clockcontrol_pci = &eir->clockcontrol_pci;
++ clockcontrol_m2 = &cc->clockcontrol_m2;
++ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
++ pll_type = R_REG(osh, &cc->capabilities) & CAP_PLL_MASK;
++ if (pll_type == PLL_TYPE6) {
++ clockcontrol_n = NULL;
++ clockcontrol_sb = NULL;
++ clockcontrol_pci = NULL;
++ } else {
++ clockcontrol_n = &cc->clockcontrol_n;
++ clockcontrol_sb = &cc->clockcontrol_sb;
++ clockcontrol_pci = &cc->clockcontrol_pci;
++ clockcontrol_m2 = &cc->clockcontrol_m2;
++ }
++ } else
++ goto done;
++
++ if (pll_type == PLL_TYPE6) {
++ /* Silence compilers */
++ orig_n = orig_sb = orig_pci = 0;
++ } else {
++ /* Store the current clock register values */
++ orig_n = R_REG(osh, clockcontrol_n);
++ orig_sb = R_REG(osh, clockcontrol_sb);
++ orig_pci = R_REG(osh, clockcontrol_pci);
++ }
++
++ if (pll_type == PLL_TYPE1) {
++ /* Keep the current PCI clock if not specified */
++ if (pciclock == 0) {
++ pciclock = sb_clock_rate(pll_type, R_REG(osh, clockcontrol_n),
++ R_REG(osh, clockcontrol_pci));
++ pciclock = (pciclock <= 25000000) ? 25000000 : 33000000;
++ }
++
++ /* Search for the closest MIPS clock less than or equal to a preferred value */
++ for (i = 0; i < ARRAYSIZE(type1_table); i++) {
++ ASSERT(type1_table[i].mipsclock ==
++ sb_clock_rate(pll_type, type1_table[i].n,
++ type1_table[i].sb));
++ if (type1_table[i].mipsclock > mipsclock)
++ break;
++ }
++ if (i == 0) {
++ ret = FALSE;
++ goto done;
++ } else {
++ ret = TRUE;
++ i--;
++ }
++ ASSERT(type1_table[i].mipsclock <= mipsclock);
++
++ /* No PLL change */
++ if ((orig_n == type1_table[i].n) &&
++ (orig_sb == type1_table[i].sb) &&
++ (orig_pci == type1_table[i].pci33))
++ goto done;
++
++ /* Set the PLL controls */
++ W_REG(osh, clockcontrol_n, type1_table[i].n);
++ W_REG(osh, clockcontrol_sb, type1_table[i].sb);
++ if (pciclock == 25000000)
++ W_REG(osh, clockcontrol_pci, type1_table[i].pci25);
++ else
++ W_REG(osh, clockcontrol_pci, type1_table[i].pci33);
++
++ /* Reset */
++ sb_watchdog(sbh, 1);
++ while (1);
++ } else if (pll_type == PLL_TYPE3) {
++ /* 5350 */
++ if (sb_chip(sbh) != BCM5365_CHIP_ID) {
++ /*
++ * Search for the closest MIPS clock less than or equal to
++ * a preferred value.
++ */
++ for (i = 0; i < ARRAYSIZE(type3_table); i++) {
++ if (type3_table[i].mipsclock > mipsclock)
++ break;
++ }
++ if (i == 0) {
++ ret = FALSE;
++ goto done;
++ } else {
++ ret = TRUE;
++ i--;
++ }
++ ASSERT(type3_table[i].mipsclock <= mipsclock);
++
++ /* No PLL change */
++ orig_m2 = R_REG(osh, &cc->clockcontrol_m2);
++ if ((orig_n == type3_table[i].n) &&
++ (orig_m2 == type3_table[i].m2)) {
++ goto done;
++ }
++
++ /* Set the PLL controls */
++ W_REG(osh, clockcontrol_n, type3_table[i].n);
++ W_REG(osh, clockcontrol_m2, type3_table[i].m2);
++
++ /* Reset */
++ sb_watchdog(sbh, 1);
++ while (1);
++ }
++ } else if ((pll_type == PLL_TYPE2) ||
++ (pll_type == PLL_TYPE4) ||
++ (pll_type == PLL_TYPE6) ||
++ (pll_type == PLL_TYPE7)) {
++ n4m_table_t *table = NULL, *te;
++ uint tabsz = 0;
++
++ ASSERT(cc);
++
++ orig_mips = R_REG(osh, &cc->clockcontrol_m3);
++
++ switch (pll_type) {
++ case PLL_TYPE6: {
++ uint32 new_mips = 0;
++
++ ret = TRUE;
++ if (mipsclock <= SB2MIPS_T6(CC_T6_M1))
++ new_mips = CC_T6_MMASK;
++
++ if (orig_mips == new_mips)
++ goto done;
++
++ W_REG(osh, &cc->clockcontrol_m3, new_mips);
++ goto end_fill;
++ }
++ case PLL_TYPE2:
++ table = type2_table;
++ tabsz = ARRAYSIZE(type2_table);
++ break;
++ case PLL_TYPE4:
++ table = type4_table;
++ tabsz = ARRAYSIZE(type4_table);
++ break;
++ case PLL_TYPE7:
++ table = type7_table;
++ tabsz = ARRAYSIZE(type7_table);
++ break;
++ default:
++ ASSERT("No table for plltype" == NULL);
++ break;
++ }
++
++ /* Store the current clock register values */
++ orig_m2 = R_REG(osh, &cc->clockcontrol_m2);
++ orig_ratio_parm = 0;
++ orig_ratio_cfg = 0;
++
++ /* Look up current ratio */
++ for (i = 0; i < tabsz; i++) {
++ if ((orig_n == table[i].n) &&
++ (orig_sb == table[i].sb) &&
++ (orig_pci == table[i].pci33) &&
++ (orig_m2 == table[i].m2) &&
++ (orig_mips == table[i].m3)) {
++ orig_ratio_parm = table[i].ratio_parm;
++ orig_ratio_cfg = table[i].ratio_cfg;
++ break;
++ }
++ }
++
++ /* Search for the closest MIPS clock greater or equal to a preferred value */
++ for (i = 0; i < tabsz; i++) {
++ ASSERT(table[i].mipsclock ==
++ sb_clock_rate(pll_type, table[i].n, table[i].m3));
++ if ((mipsclock <= table[i].mipsclock) &&
++ ((sbclock == 0) || (sbclock <= table[i].sbclock)))
++ break;
++ }
++ if (i == tabsz) {
++ ret = FALSE;
++ goto done;
++ } else {
++ te = &table[i];
++ ret = TRUE;
++ }
++
++ /* No PLL change */
++ if ((orig_n == te->n) &&
++ (orig_sb == te->sb) &&
++ (orig_pci == te->pci33) &&
++ (orig_m2 == te->m2) &&
++ (orig_mips == te->m3))
++ goto done;
++
++ /* Set the PLL controls */
++ W_REG(osh, clockcontrol_n, te->n);
++ W_REG(osh, clockcontrol_sb, te->sb);
++ W_REG(osh, clockcontrol_pci, te->pci33);
++ W_REG(osh, &cc->clockcontrol_m2, te->m2);
++ W_REG(osh, &cc->clockcontrol_m3, te->m3);
++
++ /* Set the chipcontrol bit to change mipsref to the backplane divider if needed */
++ if ((pll_type == PLL_TYPE7) && (te->sb != te->m2) &&
++ (sb_clock_rate(pll_type, te->n, te->m2) == 120000000))
++ W_REG(osh, &cc->chipcontrol,
++ R_REG(osh, &cc->chipcontrol) | 0x100);
++
++ /* No ratio change */
++ if (sb_chip(sbh) != BCM4785_CHIP_ID) {
++ if (orig_ratio_parm == te->ratio_parm)
++ goto end_fill;
++ }
++
++ /* Preload the code into the cache */
++ icache_probe(MFC0(C0_CONFIG, 1), &ic_size, &ic_lsize);
++ if (sb_chip(sbh) == BCM4785_CHIP_ID) {
++ start = ((ulong) &&start_fill_4785) & ~(ic_lsize - 1);
++ end = ((ulong) &&end_fill_4785 + (ic_lsize - 1)) & ~(ic_lsize - 1);
++ }
++ else {
++ start = ((ulong) &&start_fill) & ~(ic_lsize - 1);
++ end = ((ulong) &&end_fill + (ic_lsize - 1)) & ~(ic_lsize - 1);
++ }
++ while (start < end) {
++ cache_op(start, Fill_I);
++ start += ic_lsize;
++ }
++
++ /* Copy the handler */
++ start = (ulong) &handler;
++ end = (ulong) &afterhandler;
++ dst = KSEG1ADDR(0x180);
++ for (i = 0; i < (end - start); i += 4)
++ *((ulong *)(dst + i)) = *((ulong *)(start + i));
++
++ /* Preload the handler into the cache one line at a time */
++ for (i = 0; i < (end - start); i += ic_lsize)
++ cache_op(dst + i, Fill_I);
++
++ /* Clear BEV bit */
++ MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~ST0_BEV);
++
++ /* Enable interrupts */
++ MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) | (ALLINTS | ST0_IE));
++
++ /* 4785 clock freq change procedures */
++ if (sb_chip(sbh) == BCM4785_CHIP_ID) {
++ start_fill_4785:
++ /* Switch to async */
++ MTC0(C0_BROADCOM, 4, (1 << 22));
++
++ /* Set clock ratio in MIPS */
++ *dll_r1 = (*dll_r1 & 0xfffffff0) | (te->d11_r1 - 1);
++ *dll_r2 = te->d11_r2;
++
++ /* Enable new settings in MIPS */
++ *dll_r1 = *dll_r1 | 0xc0000000;
++
++ /* Set active cfg */
++ MTC0(C0_BROADCOM, 2, MFC0(C0_BROADCOM, 2) | (1 << 3) | 1);
++
++ /* Fake soft reset (clock cfg registers not reset) */
++ MTC0(C0_BROADCOM, 5, MFC0(C0_BROADCOM, 5) | (1 << 2));
++
++ /* Clear active cfg */
++ MTC0(C0_BROADCOM, 2, MFC0(C0_BROADCOM, 2) & ~(1 << 3));
++
++ /* set watchdog timer */
++ W_REG(osh, &cc->watchdog, 20);
++ (void) R_REG(osh, &cc->chipid);
++
++ /* wait for timer interrupt */
++ __asm__ __volatile__(
++ ".set\tmips3\n\t"
++ "sync\n\t"
++ "wait\n\t"
++ ".set\tmips0");
++ end_fill_4785:
++ while (1);
++ }
++ /* Generic clock freq change procedures */
++ else {
++ /* Enable MIPS timer interrupt */
++ if (!(mipsr = sb_setcore(sbh, SB_MIPS, 0)) &&
++ !(mipsr = sb_setcore(sbh, SB_MIPS33, 0)))
++ ASSERT(mipsr);
++ W_REG(osh, &mipsr->intmask, 1);
++
++ start_fill:
++ /* step 1, set clock ratios */
++ MTC0(C0_BROADCOM, 3, te->ratio_parm);
++ MTC0(C0_BROADCOM, 1, te->ratio_cfg);
++
++ /* step 2: program timer intr */
++ W_REG(osh, &mipsr->timer, 100);
++ (void) R_REG(osh, &mipsr->timer);
++
++ /* step 3, switch to async */
++ sync_mode = MFC0(C0_BROADCOM, 4);
++ MTC0(C0_BROADCOM, 4, 1 << 22);
++
++ /* step 4, set cfg active */
++ MTC0(C0_BROADCOM, 2, (1 << 3) | 1);
++
++ /* steps 5 & 6 */
++ __asm__ __volatile__(
++ ".set\tmips3\n\t"
++ "wait\n\t"
++ ".set\tmips0");
++
++ /* step 7, clear cfg active */
++ MTC0(C0_BROADCOM, 2, 0);
++
++ /* Additional Step: set back to orig sync mode */
++ MTC0(C0_BROADCOM, 4, sync_mode);
++
++ /* step 8, fake soft reset */
++ MTC0(C0_BROADCOM, 5, MFC0(C0_BROADCOM, 5) | (1 << 2));
++
++ end_fill:
++ /* set watchdog timer */
++ W_REG(osh, &cc->watchdog, 20);
++ (void) R_REG(osh, &cc->chipid);
++
++ /* wait for timer interrupt */
++ __asm__ __volatile__(
++ ".set\tmips3\n\t"
++ "sync\n\t"
++ "wait\n\t"
++ ".set\tmips0");
++ while (1);
++ }
++ }
++
++done:
++ /* Enable 4785 DLL */
++ if (sb_chip(sbh) == BCM4785_CHIP_ID) {
++ uint32 tmp;
++
++ /* set mask to 1e, enable DLL (bit 0) */
++ *dll_ctrl |= 0x0041e021;
++
++ /* enable aggressive hardware mode */
++ *dll_ctrl |= 0x00000080;
++
++ /* wait for lock flag to clear */
++ while ((*dll_ctrl & 0x2) == 0);
++
++ /* clear sticky flags (clear on write 1) */
++ tmp = *dll_ctrl;
++ *dll_ctrl = tmp;
++
++ /* set mask to 5b'10001 */
++ *dll_ctrl = (*dll_ctrl & 0xfffc1fff) | 0x00022000;
++
++ /* enable sync mode */
++ MTC0(C0_BROADCOM, 4, MFC0(C0_BROADCOM, 4) & 0xfe3fffff);
++ (void)MFC0(C0_BROADCOM, 4);
++ }
++
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++
++ return ret;
++}
++
++void
++BCMINITFN(enable_pfc)(uint32 mode)
++{
++ ulong start, end;
++ uint ic_size, ic_lsize;
++
++ /* If auto then choose the correct mode for this
++ * platform, currently we only ever select one mode
++ */
++ if (mode == PFC_AUTO)
++ mode = PFC_INST;
++
++ icache_probe(MFC0(C0_CONFIG, 1), &ic_size, &ic_lsize);
++
++ /* enable prefetch cache if available */
++ if (MFC0(C0_BROADCOM, 0) & BRCM_PFC_AVAIL) {
++ start = ((ulong) &&setpfc_start) & ~(ic_lsize - 1);
++ end = ((ulong) &&setpfc_end + (ic_lsize - 1)) & ~(ic_lsize - 1);
++
++ /* Preload setpfc code into the cache one line at a time */
++ while (start < end) {
++ cache_op(start, Fill_I);
++ start += ic_lsize;
++ }
++
++ /* Now set the pfc */
++ setpfc_start:
++ /* write range */
++ *(volatile uint32 *)PFC_CR1 = 0xffff0000;
++
++ /* enable */
++ *(volatile uint32 *)PFC_CR0 = mode;
++ setpfc_end:
++ /* Compiler foder */
++ ic_size = 0;
++ }
++}
++
++/* returns the ncdl value to be programmed into sdram_ncdl for calibration */
++uint32
++BCMINITFN(sb_memc_get_ncdl)(sb_t *sbh)
++{
++ osl_t *osh;
++ sbmemcregs_t *memc;
++ uint32 ret = 0;
++ uint32 config, rd, wr, misc, dqsg, cd, sm, sd;
++ uint idx, rev;
++
++ osh = sb_osh(sbh);
++
++ idx = sb_coreidx(sbh);
++
++ memc = (sbmemcregs_t *)sb_setcore(sbh, SB_MEMC, 0);
++ if (memc == 0)
++ goto out;
++
++ rev = sb_corerev(sbh);
++
++ config = R_REG(osh, &memc->config);
++ wr = R_REG(osh, &memc->wrncdlcor);
++ rd = R_REG(osh, &memc->rdncdlcor);
++ misc = R_REG(osh, &memc->miscdlyctl);
++ dqsg = R_REG(osh, &memc->dqsgatencdl);
++
++ rd &= MEMC_RDNCDLCOR_RD_MASK;
++ wr &= MEMC_WRNCDLCOR_WR_MASK;
++ dqsg &= MEMC_DQSGATENCDL_G_MASK;
++
++ if (config & MEMC_CONFIG_DDR) {
++ ret = (wr << 16) | (rd << 8) | dqsg;
++ } else {
++ if (rev > 0)
++ cd = rd;
++ else
++ cd = (rd == MEMC_CD_THRESHOLD) ? rd : (wr + MEMC_CD_THRESHOLD);
++ sm = (misc & MEMC_MISC_SM_MASK) >> MEMC_MISC_SM_SHIFT;
++ sd = (misc & MEMC_MISC_SD_MASK) >> MEMC_MISC_SD_SHIFT;
++ ret = (sm << 16) | (sd << 8) | cd;
++ }
++
++out:
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++
++ return ret;
++}
++
++#if defined(BCMPERFSTATS)
++/*
++ * CP0 Register 25 supports 4 semi-independent 32bit performance counters.
++ * $25 select 0, 1, 2, and 3 are the counters. The counters *decrement* (who thought this one up?)
++ * $25 select 4 and 5 each contain 2-16bit control fields, one for each of the 4 counters
++ * $25 select 6 is the global perf control register.
++ */
++/* enable and start instruction counting */
++
++void
++hndmips_perf_instrcount_enable()
++{
++ MTC0(C0_PERFORMANCE, 6, 0x80000200); /* global enable perf counters */
++ MTC0(C0_PERFORMANCE, 4,
++ 0x8044 | MFC0(C0_PERFORMANCE, 4)); /* enable instruction counting for counter 0 */
++ MTC0(C0_PERFORMANCE, 0, 0); /* zero counter zero */
++}
++
++/* enable and start I$ hit and I$ miss counting */
++void
++hndmips_perf_icachecount_enable(void)
++{
++ MTC0(C0_PERFORMANCE, 6, 0x80000218); /* enable I$ counting */
++ MTC0(C0_PERFORMANCE, 4, 0x80148018); /* count I$ hits in cntr 0 and misses in cntr 1 */
++ MTC0(C0_PERFORMANCE, 0, 0); /* zero counter 0 - # I$ hits */
++ MTC0(C0_PERFORMANCE, 1, 0); /* zero counter 1 - # I$ misses */
++}
++
++/* enable and start D$ hit and I$ miss counting */
++void
++hndmips_perf_dcachecount_enable(void)
++{
++ MTC0(C0_PERFORMANCE, 6, 0x80000211); /* enable D$ counting */
++ MTC0(C0_PERFORMANCE, 4, 0x80248028); /* count D$ hits in cntr 0 and misses in cntr 1 */
++ MTC0(C0_PERFORMANCE, 0, 0); /* zero counter 0 - # D$ hits */
++ MTC0(C0_PERFORMANCE, 1, 0); /* zero counter 1 - # D$ misses */
++}
++
++void
++hndmips_perf_icache_miss_enable()
++{
++ MTC0(C0_PERFORMANCE, 4,
++ 0x80140000 | MFC0(C0_PERFORMANCE, 4)); /* enable cache misses counting for counter 1 */
++ MTC0(C0_PERFORMANCE, 1, 0); /* zero counter one */
++}
++
++
++void
++hndmips_perf_icache_hit_enable()
++{
++ MTC0(C0_PERFORMANCE, 5, 0x8018 | MFC0(C0_PERFORMANCE, 5));
++ /* enable cache hits counting for counter 2 */
++ MTC0(C0_PERFORMANCE, 2, 0); /* zero counter 2 */
++}
++
++uint32
++hndmips_perf_read_instrcount()
++{
++ return -(long)(MFC0(C0_PERFORMANCE, 0));
++}
++
++uint32
++hndmips_perf_read_cache_miss()
++{
++ return -(long)(MFC0(C0_PERFORMANCE, 1));
++}
++
++uint32
++hndmips_perf_read_cache_hit()
++{
++ return -(long)(MFC0(C0_PERFORMANCE, 2));
++}
++
++#endif /* BCMINTERNAL | BCMPERFSTATS */
+diff -urN linux.old/arch/mips/bcm947xx/sbpci.c linux.dev/arch/mips/bcm947xx/sbpci.c
+--- linux.old/arch/mips/bcm947xx/sbpci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/sbpci.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,768 @@
++/*
++ * Low-Level PCI and SB support for BCM47xx
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: hndpci.c,v 1.1.1.3 2006/04/08 06:13:39 honor Exp $
++ */
++
++#include <typedefs.h>
++#include <osl.h>
++#include <pcicfg.h>
++#include <bcmdevs.h>
++#include <sbconfig.h>
++#include <bcmutils.h>
++#include <sbutils.h>
++#include <sbpci.h>
++#include <bcmendian.h>
++#include <bcmnvram.h>
++#include <hndcpu.h>
++#include <hndmips.h>
++#include <hndpci.h>
++
++/* debug/trace */
++#ifdef BCMDBG_PCI
++#define PCI_MSG(args) printf args
++#else
++#define PCI_MSG(args)
++#endif /* BCMDBG_PCI */
++
++/* Can free sbpci_init() memory after boot */
++#ifndef linux
++#define __init
++#endif /* linux */
++
++/* Emulated configuration space */
++typedef struct {
++ int n;
++ uint size0;
++ uint size1;
++ uint size2;
++ uint size3;
++} sb_bar_cfg_t;
++static pci_config_regs sb_config_regs[SB_MAXCORES];
++static sb_bar_cfg_t sb_bar_cfg[SB_MAXCORES];
++
++/* Links to emulated and real PCI configuration spaces */
++#define MAXFUNCS 2
++typedef struct {
++ pci_config_regs *emu; /* emulated PCI config */
++ pci_config_regs *pci; /* real PCI config */
++ sb_bar_cfg_t *bar; /* region sizes */
++} sb_pci_cfg_t;
++static sb_pci_cfg_t sb_pci_cfg[SB_MAXCORES][MAXFUNCS];
++
++/* Special emulated config space for non-existing device */
++static pci_config_regs sb_pci_null = { 0xffff, 0xffff };
++
++/* Banned cores */
++static uint16 pci_ban[SB_MAXCORES] = { 0 };
++static uint pci_banned = 0;
++
++/* CardBus mode */
++static bool cardbus = FALSE;
++
++/* Disable PCI host core */
++static bool pci_disabled = FALSE;
++
++/* Host bridge slot #, default to 0 */
++static uint8 pci_hbslot = 0;
++
++/* Internal macros */
++#define PCI_SLOTAD_MAP 16 /* SLOT<n> mapps to AD<n+16> */
++#define PCI_HBSBCFG_REV 8 /* MIN. core rev. required to
++ * access host bridge PCI cfg space
++ * from SB
++ */
++
++/*
++ * Functions for accessing external PCI configuration space
++ */
++
++/* Assume one-hot slot wiring */
++#define PCI_SLOT_MAX 16 /* Max. PCI Slots */
++
++static uint32
++config_cmd(sb_t *sbh, uint bus, uint dev, uint func, uint off)
++{
++ uint coreidx;
++ sbpciregs_t *regs;
++ uint32 addr = 0;
++ osl_t *osh;
++
++ /* CardBusMode supports only one device */
++ if (cardbus && dev > 1)
++ return 0;
++
++ osh = sb_osh(sbh);
++
++ coreidx = sb_coreidx(sbh);
++ regs = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0);
++
++ /* Type 0 transaction */
++ if (bus == 1) {
++ /* Skip unwired slots */
++ if (dev < PCI_SLOT_MAX) {
++ uint32 win;
++
++ /* Slide the PCI window to the appropriate slot */
++ win = (SBTOPCI_CFG0 | ((1 << (dev + PCI_SLOTAD_MAP)) & SBTOPCI1_MASK));
++ W_REG(osh, &regs->sbtopci1, win);
++ addr = SB_PCI_CFG |
++ ((1 << (dev + PCI_SLOTAD_MAP)) & ~SBTOPCI1_MASK) |
++ (func << PCICFG_FUN_SHIFT) |
++ (off & ~3);
++ }
++ } else {
++ /* Type 1 transaction */
++ W_REG(osh, &regs->sbtopci1, SBTOPCI_CFG1);
++ addr = SB_PCI_CFG |
++ (bus << PCICFG_BUS_SHIFT) |
++ (dev << PCICFG_SLOT_SHIFT) |
++ (func << PCICFG_FUN_SHIFT) |
++ (off & ~3);
++ }
++
++ sb_setcoreidx(sbh, coreidx);
++
++ return addr;
++}
++
++/*
++ * Read host bridge PCI config registers from Silicon Backplane (>=rev8).
++ *
++ * It returns TRUE to indicate that access to the host bridge's pci config
++ * from SB is ok, and values in 'addr' and 'val' are valid.
++ *
++ * It can only read registers at multiple of 4-bytes. Callers must pick up
++ * needed bytes from 'val' based on 'off' value. Value in 'addr' reflects
++ * the register address where value in 'val' is read.
++ */
++static bool
++sb_pcihb_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off,
++ uint32 **addr, uint32 *val)
++{
++ sbpciregs_t *regs;
++ osl_t *osh;
++ uint coreidx;
++ bool ret = FALSE;
++
++ /* sanity check */
++ ASSERT(bus == 1);
++ ASSERT(dev == pci_hbslot);
++ ASSERT(func == 0);
++
++ osh = sb_osh(sbh);
++
++ /* read pci config when core rev >= 8 */
++ coreidx = sb_coreidx(sbh);
++ regs = (sbpciregs_t *)sb_setcore(sbh, SB_PCI, 0);
++ if (regs && sb_corerev(sbh) >= PCI_HBSBCFG_REV) {
++ *addr = (uint32 *)&regs->pcicfg[func][off >> 2];
++ *val = R_REG(osh, *addr);
++ ret = TRUE;
++ }
++ sb_setcoreidx(sbh, coreidx);
++
++ return ret;
++}
++
++int
++extpci_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ uint32 addr = 0, *reg = NULL, val;
++ int ret = 0;
++
++ /*
++ * Set value to -1 when:
++ * flag 'pci_disabled' is true;
++ * value of 'addr' is zero;
++ * REG_MAP() fails;
++ * BUSPROBE() fails;
++ */
++ if (pci_disabled)
++ val = 0xffffffff;
++ else if (bus == 1 && dev == pci_hbslot && func == 0 &&
++ sb_pcihb_read_config(sbh, bus, dev, func, off, &reg, &val))
++ ;
++ else if (((addr = config_cmd(sbh, bus, dev, func, off)) == 0) ||
++ ((reg = (uint32 *)REG_MAP(addr, len)) == 0) ||
++ (BUSPROBE(val, reg) != 0))
++ val = 0xffffffff;
++
++ PCI_MSG(("%s: 0x%x <= 0x%p(0x%x), len %d, off 0x%x, buf 0x%p\n",
++ __FUNCTION__, val, reg, addr, len, off, buf));
++
++ val >>= 8 * (off & 3);
++ if (len == 4)
++ *((uint32 *) buf) = val;
++ else if (len == 2)
++ *((uint16 *) buf) = (uint16) val;
++ else if (len == 1)
++ *((uint8 *) buf) = (uint8) val;
++ else
++ ret = -1;
++
++ if (reg && addr)
++ REG_UNMAP(reg);
++
++ return ret;
++}
++
++int
++extpci_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ osl_t *osh;
++ uint32 addr = 0, *reg = NULL, val;
++ int ret = 0;
++
++ osh = sb_osh(sbh);
++
++ /*
++ * Ignore write attempt when:
++ * flag 'pci_disabled' is true;
++ * value of 'addr' is zero;
++ * REG_MAP() fails;
++ * BUSPROBE() fails;
++ */
++ if (pci_disabled)
++ return 0;
++ else if (bus == 1 && dev == pci_hbslot && func == 0 &&
++ sb_pcihb_read_config(sbh, bus, dev, func, off, &reg, &val))
++ ;
++ else if (((addr = config_cmd(sbh, bus, dev, func, off)) == 0) ||
++ ((reg = (uint32 *) REG_MAP(addr, len)) == 0) ||
++ (BUSPROBE(val, reg) != 0))
++ goto done;
++
++ if (len == 4)
++ val = *((uint32 *) buf);
++ else if (len == 2) {
++ val &= ~(0xffff << (8 * (off & 3)));
++ val |= *((uint16 *) buf) << (8 * (off & 3));
++ } else if (len == 1) {
++ val &= ~(0xff << (8 * (off & 3)));
++ val |= *((uint8 *) buf) << (8 * (off & 3));
++ } else {
++ ret = -1;
++ goto done;
++ }
++
++ PCI_MSG(("%s: 0x%x => 0x%p\n", __FUNCTION__, val, reg));
++
++ W_REG(osh, reg, val);
++
++done:
++ if (reg && addr)
++ REG_UNMAP(reg);
++
++ return ret;
++}
++
++/*
++ * Must access emulated PCI configuration at these locations even when
++ * the real PCI config space exists and is accessible.
++ *
++ * PCI_CFG_VID (0x00)
++ * PCI_CFG_DID (0x02)
++ * PCI_CFG_PROGIF (0x09)
++ * PCI_CFG_SUBCL (0x0a)
++ * PCI_CFG_BASECL (0x0b)
++ * PCI_CFG_HDR (0x0e)
++ * PCI_CFG_INT (0x3c)
++ * PCI_CFG_PIN (0x3d)
++ */
++#define FORCE_EMUCFG(off, len) \
++ ((off == PCI_CFG_VID) || (off == PCI_CFG_DID) || \
++ (off == PCI_CFG_PROGIF) || \
++ (off == PCI_CFG_SUBCL) || (off == PCI_CFG_BASECL) || \
++ (off == PCI_CFG_HDR) || \
++ (off == PCI_CFG_INT) || (off == PCI_CFG_PIN))
++
++/* Sync the emulation registers and the real PCI config registers. */
++static void
++sb_pcid_read_config(sb_t *sbh, uint coreidx, sb_pci_cfg_t *cfg,
++ uint off, uint len)
++{
++ osl_t *osh;
++ uint oldidx;
++
++ ASSERT(cfg);
++ ASSERT(cfg->emu);
++ ASSERT(cfg->pci);
++
++ /* decide if real PCI config register access is necessary */
++ if (FORCE_EMUCFG(off, len))
++ return;
++
++ osh = sb_osh(sbh);
++
++ /* access to the real pci config space only when the core is up */
++ oldidx = sb_coreidx(sbh);
++ sb_setcoreidx(sbh, coreidx);
++ if (sb_iscoreup(sbh)) {
++ if (len == 4)
++ *(uint32 *)((ulong)cfg->emu + off) =
++ htol32(R_REG(osh, (uint32 *)((ulong)cfg->pci + off)));
++ else if (len == 2)
++ *(uint16 *)((ulong)cfg->emu + off) =
++ htol16(R_REG(osh, (uint16 *)((ulong)cfg->pci + off)));
++ else if (len == 1)
++ *(uint8 *)((ulong)cfg->emu + off) =
++ R_REG(osh, (uint8 *)((ulong)cfg->pci + off));
++ }
++ sb_setcoreidx(sbh, oldidx);
++}
++
++static void
++sb_pcid_write_config(sb_t *sbh, uint coreidx, sb_pci_cfg_t *cfg,
++ uint off, uint len)
++{
++ osl_t *osh;
++ uint oldidx;
++
++ ASSERT(cfg);
++ ASSERT(cfg->emu);
++ ASSERT(cfg->pci);
++
++ osh = sb_osh(sbh);
++
++ /* decide if real PCI config register access is necessary */
++ if (FORCE_EMUCFG(off, len))
++ return;
++
++ /* access to the real pci config space only when the core is up */
++ oldidx = sb_coreidx(sbh);
++ sb_setcoreidx(sbh, coreidx);
++ if (sb_iscoreup(sbh)) {
++ if (len == 4)
++ W_REG(osh, (uint32 *)((ulong)cfg->pci + off),
++ ltoh32(*(uint32 *)((ulong)cfg->emu + off)));
++ else if (len == 2)
++ W_REG(osh, (uint16 *)((ulong)cfg->pci + off),
++ ltoh16(*(uint16 *)((ulong)cfg->emu + off)));
++ else if (len == 1)
++ W_REG(osh, (uint8 *)((ulong)cfg->pci + off),
++ *(uint8 *)((ulong)cfg->emu + off));
++ }
++ sb_setcoreidx(sbh, oldidx);
++}
++
++/*
++ * Functions for accessing translated SB configuration space
++ */
++static int
++sb_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ pci_config_regs *cfg;
++
++ if (dev >= SB_MAXCORES || func >= MAXFUNCS || (off + len) > sizeof(pci_config_regs))
++ return -1;
++ cfg = sb_pci_cfg[dev][func].emu;
++
++ ASSERT(ISALIGNED(off, len));
++ ASSERT(ISALIGNED((uintptr)buf, len));
++
++ /* use special config space if the device does not exist */
++ if (!cfg)
++ cfg = &sb_pci_null;
++ /* sync emulation with real PCI config if necessary */
++ else if (sb_pci_cfg[dev][func].pci)
++ sb_pcid_read_config(sbh, dev, &sb_pci_cfg[dev][func], off, len);
++
++ if (len == 4)
++ *((uint32 *) buf) = ltoh32(*((uint32 *)((ulong) cfg + off)));
++ else if (len == 2)
++ *((uint16 *) buf) = ltoh16(*((uint16 *)((ulong) cfg + off)));
++ else if (len == 1)
++ *((uint8 *) buf) = *((uint8 *)((ulong) cfg + off));
++ else
++ return -1;
++
++ return 0;
++}
++
++static int
++sb_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ uint coreidx;
++ void *regs;
++ pci_config_regs *cfg;
++ osl_t *osh;
++ sb_bar_cfg_t *bar;
++
++ if (dev >= SB_MAXCORES || func >= MAXFUNCS || (off + len) > sizeof(pci_config_regs))
++ return -1;
++ cfg = sb_pci_cfg[dev][func].emu;
++ if (!cfg)
++ return -1;
++
++ ASSERT(ISALIGNED(off, len));
++ ASSERT(ISALIGNED((uintptr)buf, len));
++
++ osh = sb_osh(sbh);
++
++ /* Emulate BAR sizing */
++ if (off >= OFFSETOF(pci_config_regs, base[0]) &&
++ off <= OFFSETOF(pci_config_regs, base[3]) &&
++ len == 4 && *((uint32 *) buf) == ~0) {
++ coreidx = sb_coreidx(sbh);
++ if ((regs = sb_setcoreidx(sbh, dev))) {
++ bar = sb_pci_cfg[dev][func].bar;
++ /* Highest numbered address match register */
++ if (off == OFFSETOF(pci_config_regs, base[0]))
++ cfg->base[0] = ~(bar->size0 - 1);
++ else if (off == OFFSETOF(pci_config_regs, base[1]) && bar->n >= 1)
++ cfg->base[1] = ~(bar->size1 - 1);
++ else if (off == OFFSETOF(pci_config_regs, base[2]) && bar->n >= 2)
++ cfg->base[2] = ~(bar->size2 - 1);
++ else if (off == OFFSETOF(pci_config_regs, base[3]) && bar->n >= 3)
++ cfg->base[3] = ~(bar->size3 - 1);
++ }
++ sb_setcoreidx(sbh, coreidx);
++ }
++ else if (len == 4)
++ *((uint32 *)((ulong) cfg + off)) = htol32(*((uint32 *) buf));
++ else if (len == 2)
++ *((uint16 *)((ulong) cfg + off)) = htol16(*((uint16 *) buf));
++ else if (len == 1)
++ *((uint8 *)((ulong) cfg + off)) = *((uint8 *) buf);
++ else
++ return -1;
++
++ /* sync emulation with real PCI config if necessary */
++ if (sb_pci_cfg[dev][func].pci)
++ sb_pcid_write_config(sbh, dev, &sb_pci_cfg[dev][func], off, len);
++
++ return 0;
++}
++
++int
++sbpci_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ if (bus == 0)
++ return sb_read_config(sbh, bus, dev, func, off, buf, len);
++ else
++ return extpci_read_config(sbh, bus, dev, func, off, buf, len);
++}
++
++int
++sbpci_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ if (bus == 0)
++ return sb_write_config(sbh, bus, dev, func, off, buf, len);
++ else
++ return extpci_write_config(sbh, bus, dev, func, off, buf, len);
++}
++
++void
++sbpci_ban(uint16 core)
++{
++ if (pci_banned < ARRAYSIZE(pci_ban))
++ pci_ban[pci_banned++] = core;
++}
++
++/*
++ * Initiliaze PCI core. Return 0 after a successful initialization.
++ * Otherwise return -1 to indicate there is no PCI core and return 1
++ * to indicate PCI core is disabled.
++ */
++int __init
++sbpci_init_pci(sb_t *sbh)
++{
++ uint chip, chiprev, chippkg, host;
++ uint32 boardflags;
++ sbpciregs_t *pci;
++ sbconfig_t *sb;
++ uint32 val;
++ int ret = 0;
++ char *hbslot;
++ osl_t *osh;
++
++ chip = sb_chip(sbh);
++ chiprev = sb_chiprev(sbh);
++ chippkg = sb_chippkg(sbh);
++
++ osh = sb_osh(sbh);
++
++ if (!(pci = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0))) {
++ printk("PCI: no core\n");
++ pci_disabled = TRUE;
++ return -1;
++ }
++
++ if ((chip == 0x4310) && (chiprev == 0))
++ pci_disabled = TRUE;
++
++ sb = (sbconfig_t *)((ulong) pci + SBCONFIGOFF);
++
++ boardflags = (uint32) getintvar(NULL, "boardflags");
++
++ /*
++ * The 200-pin BCM4712 package does not bond out PCI. Even when
++ * PCI is bonded out, some boards may leave the pins
++ * floating.
++ */
++ if (((chip == BCM4712_CHIP_ID) &&
++ ((chippkg == BCM4712SMALL_PKG_ID) ||
++ (chippkg == BCM4712MID_PKG_ID))) ||
++ (boardflags & BFL_NOPCI))
++ pci_disabled = TRUE;
++
++ /* Enable the core */
++ sb_core_reset(sbh, 0, 0);
++
++ /*
++ * If the PCI core should not be touched (disabled, not bonded
++ * out, or pins floating), do not even attempt to access core
++ * registers. Otherwise, try to determine if it is in host
++ * mode.
++ */
++ if (pci_disabled)
++ host = 0;
++ else
++ host = !BUSPROBE(val, &pci->control);
++
++ if (!host) {
++ ret = 1;
++
++ /* Disable PCI interrupts in client mode */
++ W_REG(osh, &sb->sbintvec, 0);
++
++ /* Disable the PCI bridge in client mode */
++ sbpci_ban(SB_PCI);
++ sb_core_disable(sbh, 0);
++
++ printk("PCI: Disabled\n");
++ } else {
++ printk("PCI: Initializing host\n");
++
++ /* Disable PCI SBReqeustTimeout for BCM4785 */
++ if (chip == BCM4785_CHIP_ID) {
++ AND_REG(osh, &sb->sbimconfiglow, ~0x00000070);
++ sb_commit(sbh);
++ }
++
++ /* Reset the external PCI bus and enable the clock */
++ W_REG(osh, &pci->control, 0x5); /* enable the tristate drivers */
++ W_REG(osh, &pci->control, 0xd); /* enable the PCI clock */
++ OSL_DELAY(150); /* delay > 100 us */
++ W_REG(osh, &pci->control, 0xf); /* deassert PCI reset */
++ /* Use internal arbiter and park REQ/GRNT at external master 0 */
++ W_REG(osh, &pci->arbcontrol, PCI_INT_ARB);
++ OSL_DELAY(1); /* delay 1 us */
++ if (sb_corerev(sbh) >= 8) {
++ val = getintvar(NULL, "parkid");
++ ASSERT(val <= PCI_PARKID_LAST);
++ OR_REG(osh, &pci->arbcontrol, val << PCI_PARKID_SHIFT);
++ OSL_DELAY(1);
++ }
++
++ /* Enable CardBusMode */
++ cardbus = getintvar(NULL, "cardbus") == 1;
++ if (cardbus) {
++ printk("PCI: Enabling CardBus\n");
++ /* GPIO 1 resets the CardBus device on bcm94710ap */
++ sb_gpioout(sbh, 1, 1, GPIO_DRV_PRIORITY);
++ sb_gpioouten(sbh, 1, 1, GPIO_DRV_PRIORITY);
++ W_REG(osh, &pci->sprom[0], R_REG(osh, &pci->sprom[0]) | 0x400);
++ }
++
++ /* 64 MB I/O access window */
++ W_REG(osh, &pci->sbtopci0, SBTOPCI_IO);
++ /* 64 MB configuration access window */
++ W_REG(osh, &pci->sbtopci1, SBTOPCI_CFG0);
++ /* 1 GB memory access window */
++ W_REG(osh, &pci->sbtopci2, SBTOPCI_MEM | SB_PCI_DMA);
++
++ /* Host bridge slot # nvram overwrite */
++ if ((hbslot = nvram_get("pcihbslot"))) {
++ pci_hbslot = bcm_strtoul(hbslot, NULL, 0);
++ ASSERT(pci_hbslot < PCI_MAX_DEVICES);
++ }
++
++ /* Enable PCI bridge BAR0 prefetch and burst */
++ val = 6;
++ sbpci_write_config(sbh, 1, pci_hbslot, 0, PCI_CFG_CMD, &val, sizeof(val));
++
++ /* Enable PCI interrupts */
++ W_REG(osh, &pci->intmask, PCI_INTA);
++ }
++
++ return ret;
++}
++
++/*
++ * Get the PCI region address and size information.
++ */
++static void __init
++sbpci_init_regions(sb_t *sbh, uint func, pci_config_regs *cfg, sb_bar_cfg_t *bar)
++{
++ osl_t *osh;
++ uint16 coreid;
++ void *regs;
++ sbconfig_t *sb;
++ uint32 base;
++
++ osh = sb_osh(sbh);
++ coreid = sb_coreid(sbh);
++ regs = sb_coreregs(sbh);
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++
++ switch (coreid) {
++ case SB_USB20H:
++ base = htol32(sb_base(R_REG(osh, &sb->sbadmatch0)));
++
++ cfg->base[0] = func == 0 ? base : base + 0x800; /* OHCI/EHCI */
++ cfg->base[1] = 0;
++ cfg->base[2] = 0;
++ cfg->base[3] = 0;
++ cfg->base[4] = 0;
++ cfg->base[5] = 0;
++ bar->n = 1;
++ bar->size0 = func == 0 ? 0x200 : 0x100; /* OHCI/EHCI */
++ bar->size1 = 0;
++ bar->size2 = 0;
++ bar->size3 = 0;
++ break;
++ default:
++ cfg->base[0] = htol32(sb_base(R_REG(osh, &sb->sbadmatch0)));
++ cfg->base[1] = htol32(sb_base(R_REG(osh, &sb->sbadmatch1)));
++ cfg->base[2] = htol32(sb_base(R_REG(osh, &sb->sbadmatch2)));
++ cfg->base[3] = htol32(sb_base(R_REG(osh, &sb->sbadmatch3)));
++ cfg->base[4] = 0;
++ cfg->base[5] = 0;
++ bar->n = (R_REG(osh, &sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT;
++ bar->size0 = sb_size(R_REG(osh, &sb->sbadmatch0));
++ bar->size1 = sb_size(R_REG(osh, &sb->sbadmatch1));
++ bar->size2 = sb_size(R_REG(osh, &sb->sbadmatch2));
++ bar->size3 = sb_size(R_REG(osh, &sb->sbadmatch3));
++ break;
++ }
++}
++
++/*
++ * Construct PCI config spaces for SB cores so that they
++ * can be accessed as if they were PCI devices.
++ */
++static void __init
++sbpci_init_cores(sb_t *sbh)
++{
++ uint chiprev, coreidx, i;
++ sbconfig_t *sb;
++ pci_config_regs *cfg, *pci;
++ sb_bar_cfg_t *bar;
++ void *regs;
++ osl_t *osh;
++ uint16 vendor, device;
++ uint16 coreid;
++ uint8 class, subclass, progif;
++ uint dev;
++ uint8 header;
++ uint func;
++
++ chiprev = sb_chiprev(sbh);
++ coreidx = sb_coreidx(sbh);
++
++ osh = sb_osh(sbh);
++
++ /* Scan the SB bus */
++ bzero(sb_config_regs, sizeof(sb_config_regs));
++ bzero(sb_bar_cfg, sizeof(sb_bar_cfg));
++ bzero(sb_pci_cfg, sizeof(sb_pci_cfg));
++ memset(&sb_pci_null, -1, sizeof(sb_pci_null));
++ cfg = sb_config_regs;
++ bar = sb_bar_cfg;
++ for (dev = 0; dev < SB_MAXCORES; dev ++) {
++ /* Check if the core exists */
++ if (!(regs = sb_setcoreidx(sbh, dev)))
++ continue;
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++
++ /* Check if this core is banned */
++ coreid = sb_coreid(sbh);
++ for (i = 0; i < pci_banned; i++)
++ if (coreid == pci_ban[i])
++ break;
++ if (i < pci_banned)
++ continue;
++
++ for (func = 0; func < MAXFUNCS; ++func) {
++ /* Make sure we won't go beyond the limit */
++ if (cfg >= &sb_config_regs[SB_MAXCORES]) {
++ printk("PCI: too many emulated devices\n");
++ goto done;
++ }
++
++ /* Convert core id to pci id */
++ if (sb_corepciid(sbh, func, &vendor, &device, &class, &subclass,
++ &progif, &header))
++ continue;
++
++ /*
++ * Differentiate real PCI config from emulated.
++ * non zero 'pci' indicate there is a real PCI config space
++ * for this device.
++ */
++ switch (device) {
++ case BCM47XX_GIGETH_ID:
++ pci = (pci_config_regs *)((uint32)regs + 0x800);
++ break;
++ case BCM47XX_SATAXOR_ID:
++ pci = (pci_config_regs *)((uint32)regs + 0x400);
++ break;
++ case BCM47XX_ATA100_ID:
++ pci = (pci_config_regs *)((uint32)regs + 0x800);
++ break;
++ default:
++ pci = NULL;
++ break;
++ }
++ /* Supported translations */
++ cfg->vendor = htol16(vendor);
++ cfg->device = htol16(device);
++ cfg->rev_id = chiprev;
++ cfg->prog_if = progif;
++ cfg->sub_class = subclass;
++ cfg->base_class = class;
++ cfg->header_type = header;
++ sbpci_init_regions(sbh, func, cfg, bar);
++ /* Save core interrupt flag */
++ cfg->int_pin = R_REG(osh, &sb->sbtpsflag) & SBTPS_NUM0_MASK;
++ /* Save core interrupt assignment */
++ cfg->int_line = sb_irq(sbh);
++ /* Indicate there is no SROM */
++ *((uint32 *) &cfg->sprom_control) = 0xffffffff;
++
++ /* Point to the PCI config spaces */
++ sb_pci_cfg[dev][func].emu = cfg;
++ sb_pci_cfg[dev][func].pci = pci;
++ sb_pci_cfg[dev][func].bar = bar;
++ cfg ++;
++ bar ++;
++ }
++ }
++
++done:
++ sb_setcoreidx(sbh, coreidx);
++}
++
++/*
++ * Initialize PCI core and construct PCI config spaces for SB cores.
++ * Must propagate sbpci_init_pci() return value to the caller to let
++ * them know the PCI core initialization status.
++ */
++int __init
++sbpci_init(sb_t *sbh)
++{
++ int status = sbpci_init_pci(sbh);
++ sbpci_init_cores(sbh);
++ return status;
++}
++
+diff -urN linux.old/arch/mips/bcm947xx/sbutils.c linux.dev/arch/mips/bcm947xx/sbutils.c
+--- linux.old/arch/mips/bcm947xx/sbutils.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/sbutils.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,3081 @@
++/*
++ * Misc utility routines for accessing chip-specific features
++ * of the SiliconBackplane-based Broadcom chips.
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id: sbutils.c,v 1.10 2006/04/08 07:12:42 honor Exp $
++ */
++
++#include <typedefs.h>
++#include <bcmdefs.h>
++#include <osl.h>
++#include <bcmutils.h>
++#include <sbutils.h>
++#include <bcmdevs.h>
++#include <sbconfig.h>
++#include <sbchipc.h>
++#include <sbpci.h>
++#include <sbpcie.h>
++#include <pcicfg.h>
++#include <sbpcmcia.h>
++#include <sbextif.h>
++#include <sbsocram.h>
++#include <bcmsrom.h>
++#ifdef __mips__
++#include <mipsinc.h>
++#endif /* __mips__ */
++
++/* debug/trace */
++#define SB_ERROR(args)
++
++typedef uint32 (*sb_intrsoff_t)(void *intr_arg);
++typedef void (*sb_intrsrestore_t)(void *intr_arg, uint32 arg);
++typedef bool (*sb_intrsenabled_t)(void *intr_arg);
++
++/* misc sb info needed by some of the routines */
++typedef struct sb_info {
++
++ struct sb_pub sb; /* back plane public state (must be first field) */
++
++ void *osh; /* osl os handle */
++ void *sdh; /* bcmsdh handle */
++
++ void *curmap; /* current regs va */
++ void *regs[SB_MAXCORES]; /* other regs va */
++
++ uint curidx; /* current core index */
++ uint dev_coreid; /* the core provides driver functions */
++
++ bool memseg; /* flag to toggle MEM_SEG register */
++
++ uint gpioidx; /* gpio control core index */
++ uint gpioid; /* gpio control coretype */
++
++ uint numcores; /* # discovered cores */
++ uint coreid[SB_MAXCORES]; /* id of each core */
++
++ void *intr_arg; /* interrupt callback function arg */
++ sb_intrsoff_t intrsoff_fn; /* turns chip interrupts off */
++ sb_intrsrestore_t intrsrestore_fn; /* restore chip interrupts */
++ sb_intrsenabled_t intrsenabled_fn; /* check if interrupts are enabled */
++
++} sb_info_t;
++
++/* local prototypes */
++static sb_info_t * sb_doattach(sb_info_t *si, uint devid, osl_t *osh, void *regs,
++ uint bustype, void *sdh, char **vars, uint *varsz);
++static void sb_scan(sb_info_t *si);
++static uint sb_corereg(sb_info_t *si, uint coreidx, uint regoff, uint mask, uint val);
++static uint _sb_coreidx(sb_info_t *si);
++static uint sb_findcoreidx(sb_info_t *si, uint coreid, uint coreunit);
++static uint sb_pcidev2chip(uint pcidev);
++static uint sb_chip2numcores(uint chip);
++static bool sb_ispcie(sb_info_t *si);
++static bool sb_find_pci_capability(sb_info_t *si, uint8 req_cap_id, uchar *buf, uint32 *buflen);
++static int sb_pci_fixcfg(sb_info_t *si);
++
++/* routines to access mdio slave device registers */
++static int sb_pcie_mdiowrite(sb_info_t *si, uint physmedia, uint readdr, uint val);
++static void sb_war30841(sb_info_t *si);
++
++/* delay needed between the mdio control/ mdiodata register data access */
++#define PR28829_DELAY() OSL_DELAY(10)
++
++/* size that can take bitfielddump */
++#define BITFIELD_DUMP_SIZE 32
++
++/* global variable to indicate reservation/release of gpio's */
++static uint32 sb_gpioreservation = 0;
++
++#define SB_INFO(sbh) (sb_info_t*)sbh
++#define SET_SBREG(si, r, mask, val) \
++ W_SBREG((si), (r), ((R_SBREG((si), (r)) & ~(mask)) | (val)))
++#define GOODCOREADDR(x) (((x) >= SB_ENUM_BASE) && ((x) <= SB_ENUM_LIM) && \
++ ISALIGNED((x), SB_CORE_SIZE))
++#define GOODREGS(regs) ((regs) && ISALIGNED((uintptr)(regs), SB_CORE_SIZE))
++#define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF)
++#define GOODIDX(idx) (((uint)idx) < SB_MAXCORES)
++#define BADIDX (SB_MAXCORES+1)
++#define NOREV -1 /* Invalid rev */
++
++#define PCI(si) ((BUSTYPE(si->sb.bustype) == PCI_BUS) && (si->sb.buscoretype == SB_PCI))
++#define PCIE(si) ((BUSTYPE(si->sb.bustype) == PCI_BUS) && (si->sb.buscoretype == SB_PCIE))
++
++/* sonicsrev */
++#define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT)
++#define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT)
++
++#define R_SBREG(si, sbr) sb_read_sbreg((si), (sbr))
++#define W_SBREG(si, sbr, v) sb_write_sbreg((si), (sbr), (v))
++#define AND_SBREG(si, sbr, v) W_SBREG((si), (sbr), (R_SBREG((si), (sbr)) & (v)))
++#define OR_SBREG(si, sbr, v) W_SBREG((si), (sbr), (R_SBREG((si), (sbr)) | (v)))
++
++/*
++ * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts before/
++ * after core switching to avoid invalid register accesss inside ISR.
++ */
++#define INTR_OFF(si, intr_val) \
++ if ((si)->intrsoff_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \
++ intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); }
++#define INTR_RESTORE(si, intr_val) \
++ if ((si)->intrsrestore_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \
++ (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); }
++
++/* dynamic clock control defines */
++#define LPOMINFREQ 25000 /* low power oscillator min */
++#define LPOMAXFREQ 43000 /* low power oscillator max */
++#define XTALMINFREQ 19800000 /* 20 MHz - 1% */
++#define XTALMAXFREQ 20200000 /* 20 MHz + 1% */
++#define PCIMINFREQ 25000000 /* 25 MHz */
++#define PCIMAXFREQ 34000000 /* 33 MHz + fudge */
++
++#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */
++#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */
++
++/* different register spaces to access thr'u pcie indirect access */
++#define PCIE_CONFIGREGS 1 /* Access to config space */
++#define PCIE_PCIEREGS 2 /* Access to pcie registers */
++
++/* GPIO Based LED powersave defines */
++#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */
++#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */
++
++#define DEFAULT_GPIOTIMERVAL ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME)
++
++static uint32
++sb_read_sbreg(sb_info_t *si, volatile uint32 *sbr)
++{
++ uint8 tmp;
++ uint32 val, intr_val = 0;
++
++
++ /*
++ * compact flash only has 11 bits address, while we needs 12 bits address.
++ * MEM_SEG will be OR'd with other 11 bits address in hardware,
++ * so we program MEM_SEG with 12th bit when necessary(access sb regsiters).
++ * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special
++ */
++ if (si->memseg) {
++ INTR_OFF(si, intr_val);
++ tmp = 1;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1);
++ sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */
++ }
++
++ val = R_REG(si->osh, sbr);
++
++ if (si->memseg) {
++ tmp = 0;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1);
++ INTR_RESTORE(si, intr_val);
++ }
++
++ return (val);
++}
++
++static void
++sb_write_sbreg(sb_info_t *si, volatile uint32 *sbr, uint32 v)
++{
++ uint8 tmp;
++ volatile uint32 dummy;
++ uint32 intr_val = 0;
++
++
++ /*
++ * compact flash only has 11 bits address, while we needs 12 bits address.
++ * MEM_SEG will be OR'd with other 11 bits address in hardware,
++ * so we program MEM_SEG with 12th bit when necessary(access sb regsiters).
++ * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special
++ */
++ if (si->memseg) {
++ INTR_OFF(si, intr_val);
++ tmp = 1;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1);
++ sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */
++ }
++
++ if (BUSTYPE(si->sb.bustype) == PCMCIA_BUS) {
++#ifdef IL_BIGENDIAN
++ dummy = R_REG(si->osh, sbr);
++ W_REG(si->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff));
++ dummy = R_REG(si->osh, sbr);
++ W_REG(si->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff));
++#else
++ dummy = R_REG(si->osh, sbr);
++ W_REG(si->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff));
++ dummy = R_REG(si->osh, sbr);
++ W_REG(si->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff));
++#endif /* IL_BIGENDIAN */
++ } else
++ W_REG(si->osh, sbr, v);
++
++ if (si->memseg) {
++ tmp = 0;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, MEM_SEG, &tmp, 1);
++ INTR_RESTORE(si, intr_val);
++ }
++}
++
++/*
++ * Allocate a sb handle.
++ * devid - pci device id (used to determine chip#)
++ * osh - opaque OS handle
++ * regs - virtual address of initial core registers
++ * bustype - pci/pcmcia/sb/sdio/etc
++ * vars - pointer to a pointer area for "environment" variables
++ * varsz - pointer to int to return the size of the vars
++ */
++sb_t *
++BCMINITFN(sb_attach)(uint devid, osl_t *osh, void *regs,
++ uint bustype, void *sdh, char **vars, uint *varsz)
++{
++ sb_info_t *si;
++
++ /* alloc sb_info_t */
++ if ((si = MALLOC(osh, sizeof (sb_info_t))) == NULL) {
++ SB_ERROR(("sb_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh)));
++ return (NULL);
++ }
++
++ if (sb_doattach(si, devid, osh, regs, bustype, sdh, vars, (uint*)varsz) == NULL) {
++ MFREE(osh, si, sizeof(sb_info_t));
++ return (NULL);
++ }
++
++ return (sb_t *)si;
++}
++
++/* Using sb_kattach depends on SB_BUS support, either implicit */
++/* no limiting BCMBUSTYPE value) or explicit (value is SB_BUS). */
++#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SB_BUS)
++
++/* global kernel resource */
++static sb_info_t ksi;
++static bool ksi_attached = FALSE;
++
++/* generic kernel variant of sb_attach() */
++sb_t *
++BCMINITFN(sb_kattach)(void)
++{
++ osl_t *osh = NULL;
++ uint32 *regs;
++
++ if (!ksi_attached) {
++ uint32 cid;
++
++ regs = (uint32 *)REG_MAP(SB_ENUM_BASE, SB_CORE_SIZE);
++ cid = R_REG(osh, (uint32 *)regs);
++ if (((cid & CID_ID_MASK) == BCM4712_CHIP_ID) &&
++ ((cid & CID_PKG_MASK) != BCM4712LARGE_PKG_ID) &&
++ ((cid & CID_REV_MASK) <= (3 << CID_REV_SHIFT))) {
++ uint32 *scc, val;
++
++ scc = (uint32 *)((uchar*)regs + OFFSETOF(chipcregs_t, slow_clk_ctl));
++ val = R_REG(osh, scc);
++ SB_ERROR((" initial scc = 0x%x\n", val));
++ val |= SCC_SS_XTAL;
++ W_REG(osh, scc, val);
++ }
++
++ if (sb_doattach(&ksi, BCM4710_DEVICE_ID, osh, (void*)regs,
++ SB_BUS, NULL, NULL, NULL) == NULL) {
++ return NULL;
++ }
++ else
++ ksi_attached = TRUE;
++ }
++
++ return (sb_t *)&ksi;
++}
++#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SB_BUS) */
++
++static sb_info_t *
++BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs,
++ uint bustype, void *sdh, char **vars, uint *varsz)
++{
++ uint origidx;
++ chipcregs_t *cc;
++ sbconfig_t *sb;
++ uint32 w;
++
++ ASSERT(GOODREGS(regs));
++
++ bzero((uchar*)si, sizeof(sb_info_t));
++
++ si->sb.buscoreidx = si->gpioidx = BADIDX;
++
++ si->curmap = regs;
++ si->sdh = sdh;
++ si->osh = osh;
++
++ /* check to see if we are a sb core mimic'ing a pci core */
++ if (bustype == PCI_BUS) {
++ if (OSL_PCI_READ_CONFIG(si->osh, PCI_SPROM_CONTROL, sizeof(uint32)) == 0xffffffff) {
++ SB_ERROR(("%s: incoming bus is PCI but it's a lie, switching to SB "
++ "devid:0x%x\n", __FUNCTION__, devid));
++ bustype = SB_BUS;
++ }
++ }
++
++ si->sb.bustype = bustype;
++ if (si->sb.bustype != BUSTYPE(si->sb.bustype)) {
++ SB_ERROR(("sb_doattach: bus type %d does not match configured bus type %d\n",
++ si->sb.bustype, BUSTYPE(si->sb.bustype)));
++ return NULL;
++ }
++
++ /* need to set memseg flag for CF card first before any sb registers access */
++ if (BUSTYPE(si->sb.bustype) == PCMCIA_BUS)
++ si->memseg = TRUE;
++
++ /* kludge to enable the clock on the 4306 which lacks a slowclock */
++ if (BUSTYPE(si->sb.bustype) == PCI_BUS)
++ sb_clkctl_xtal(&si->sb, XTAL|PLL, ON);
++
++ if (BUSTYPE(si->sb.bustype) == PCI_BUS) {
++ w = OSL_PCI_READ_CONFIG(si->osh, PCI_BAR0_WIN, sizeof(uint32));
++ if (!GOODCOREADDR(w))
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, sizeof(uint32), SB_ENUM_BASE);
++ }
++
++ /* initialize current core index value */
++ si->curidx = _sb_coreidx(si);
++
++ if (si->curidx == BADIDX) {
++ SB_ERROR(("sb_doattach: bad core index\n"));
++ return NULL;
++ }
++
++ /* get sonics backplane revision */
++ sb = REGS2SB(si->curmap);
++ si->sb.sonicsrev = (R_SBREG(si, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT;
++
++ /* keep and reuse the initial register mapping */
++ origidx = si->curidx;
++ if (BUSTYPE(si->sb.bustype) == SB_BUS)
++ si->regs[origidx] = regs;
++
++ /* is core-0 a chipcommon core? */
++ si->numcores = 1;
++ cc = (chipcregs_t*) sb_setcoreidx(&si->sb, 0);
++ if (sb_coreid(&si->sb) != SB_CC)
++ cc = NULL;
++
++ /* determine chip id and rev */
++ if (cc) {
++ /* chip common core found! */
++ si->sb.chip = R_REG(si->osh, &cc->chipid) & CID_ID_MASK;
++ si->sb.chiprev = (R_REG(si->osh, &cc->chipid) & CID_REV_MASK) >> CID_REV_SHIFT;
++ si->sb.chippkg = (R_REG(si->osh, &cc->chipid) & CID_PKG_MASK) >> CID_PKG_SHIFT;
++ } else {
++ /* no chip common core -- must convert device id to chip id */
++ if ((si->sb.chip = sb_pcidev2chip(devid)) == 0) {
++ SB_ERROR(("sb_doattach: unrecognized device id 0x%04x\n", devid));
++ sb_setcoreidx(&si->sb, origidx);
++ return NULL;
++ }
++ }
++
++ /* get chipcommon rev */
++ si->sb.ccrev = cc ? (int)sb_corerev(&si->sb) : NOREV;
++
++ /* determine numcores */
++ if (cc && ((si->sb.ccrev == 4) || (si->sb.ccrev >= 6)))
++ si->numcores = (R_REG(si->osh, &cc->chipid) & CID_CC_MASK) >> CID_CC_SHIFT;
++ else
++ si->numcores = sb_chip2numcores(si->sb.chip);
++
++ /* return to original core */
++ sb_setcoreidx(&si->sb, origidx);
++
++ /* sanity checks */
++ ASSERT(si->sb.chip);
++
++ /* scan for cores */
++ sb_scan(si);
++
++ /* fixup necessary chip/core configurations */
++ if (BUSTYPE(si->sb.bustype) == PCI_BUS) {
++ if (sb_pci_fixcfg(si)) {
++ SB_ERROR(("sb_doattach: sb_pci_fixcfg failed\n"));
++ return NULL;
++ }
++ }
++
++ /* srom_var_init() depends on sb_scan() info */
++ if (srom_var_init(si, si->sb.bustype, si->curmap, si->osh, vars, varsz)) {
++ SB_ERROR(("sb_doattach: srom_var_init failed: bad srom\n"));
++ return (NULL);
++ }
++
++ if (cc == NULL) {
++ /*
++ * The chip revision number is hardwired into all
++ * of the pci function config rev fields and is
++ * independent from the individual core revision numbers.
++ * For example, the "A0" silicon of each chip is chip rev 0.
++ * For PCMCIA we get it from the CIS instead.
++ */
++ if (BUSTYPE(si->sb.bustype) == PCMCIA_BUS) {
++ ASSERT(vars);
++ si->sb.chiprev = getintvar(*vars, "chiprev");
++ } else if (BUSTYPE(si->sb.bustype) == PCI_BUS) {
++ w = OSL_PCI_READ_CONFIG(si->osh, PCI_CFG_REV, sizeof(uint32));
++ si->sb.chiprev = w & 0xff;
++ } else
++ si->sb.chiprev = 0;
++ }
++
++ if (BUSTYPE(si->sb.bustype) == PCMCIA_BUS) {
++ w = getintvar(*vars, "regwindowsz");
++ si->memseg = (w <= CFTABLE_REGWIN_2K) ? TRUE : FALSE;
++ }
++
++ /* gpio control core is required */
++ if (!GOODIDX(si->gpioidx)) {
++ SB_ERROR(("sb_doattach: gpio control core not found\n"));
++ return NULL;
++ }
++
++ /* get boardtype and boardrev */
++ switch (BUSTYPE(si->sb.bustype)) {
++ case PCI_BUS:
++ /* do a pci config read to get subsystem id and subvendor id */
++ w = OSL_PCI_READ_CONFIG(si->osh, PCI_CFG_SVID, sizeof(uint32));
++ si->sb.boardvendor = w & 0xffff;
++ si->sb.boardtype = (w >> 16) & 0xffff;
++ break;
++
++ case PCMCIA_BUS:
++ case SDIO_BUS:
++ si->sb.boardvendor = getintvar(*vars, "manfid");
++ si->sb.boardtype = getintvar(*vars, "prodid");
++ break;
++
++ case SB_BUS:
++ case JTAG_BUS:
++ si->sb.boardvendor = VENDOR_BROADCOM;
++ if ((si->sb.boardtype = getintvar(NULL, "boardtype")) == 0)
++ si->sb.boardtype = 0xffff;
++ break;
++ }
++
++ if (si->sb.boardtype == 0) {
++ SB_ERROR(("sb_doattach: unknown board type\n"));
++ ASSERT(si->sb.boardtype);
++ }
++
++ /* setup the GPIO based LED powersave register */
++ if (si->sb.ccrev >= 16) {
++ if ((vars == NULL) || ((w = getintvar(*vars, "leddc")) == 0))
++ w = DEFAULT_GPIOTIMERVAL;
++ sb_corereg(si, 0, OFFSETOF(chipcregs_t, gpiotimerval), ~0, w);
++ }
++ if ((si->sb.chip == BCM4311_CHIP_ID) && (si->sb.chiprev <= 1)) {
++ /* set proper clk setup delays before forcing HT */
++ sb_clkctl_init((void *)si);
++ sb_corereg((void*)si, SB_CC_IDX, OFFSETOF(chipcregs_t, system_clk_ctl),
++ SYCC_HR, SYCC_HR);
++ }
++
++
++ return (si);
++}
++
++uint
++sb_coreid(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ return ((R_SBREG(si, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT);
++}
++
++uint
++sb_coreidx(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->curidx);
++}
++
++/* return current index of core */
++static uint
++_sb_coreidx(sb_info_t *si)
++{
++ sbconfig_t *sb;
++ uint32 sbaddr = 0;
++
++ ASSERT(si);
++
++ switch (BUSTYPE(si->sb.bustype)) {
++ case SB_BUS:
++ sb = REGS2SB(si->curmap);
++ sbaddr = sb_base(R_SBREG(si, &sb->sbadmatch0));
++ break;
++
++ case PCI_BUS:
++ sbaddr = OSL_PCI_READ_CONFIG(si->osh, PCI_BAR0_WIN, sizeof(uint32));
++ break;
++
++ case PCMCIA_BUS: {
++ uint8 tmp = 0;
++
++ OSL_PCMCIA_READ_ATTR(si->osh, PCMCIA_ADDR0, &tmp, 1);
++ sbaddr = (uint)tmp << 12;
++ OSL_PCMCIA_READ_ATTR(si->osh, PCMCIA_ADDR1, &tmp, 1);
++ sbaddr |= (uint)tmp << 16;
++ OSL_PCMCIA_READ_ATTR(si->osh, PCMCIA_ADDR2, &tmp, 1);
++ sbaddr |= (uint)tmp << 24;
++ break;
++ }
++
++#ifdef BCMJTAG
++ case JTAG_BUS:
++ sbaddr = (uint32)si->curmap;
++ break;
++#endif /* BCMJTAG */
++
++ default:
++ ASSERT(0);
++ }
++
++ if (!GOODCOREADDR(sbaddr))
++ return BADIDX;
++
++ return ((sbaddr - SB_ENUM_BASE) / SB_CORE_SIZE);
++}
++
++uint
++sb_corevendor(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ return ((R_SBREG(si, &sb->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT);
++}
++
++uint
++sb_corerev(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ uint sbidh;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++ sbidh = R_SBREG(si, &sb->sbidhigh);
++
++ return (SBCOREREV(sbidh));
++}
++
++void *
++sb_osh(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return si->osh;
++}
++
++void
++sb_setosh(sb_t *sbh, osl_t *osh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ if (si->osh != NULL) {
++ SB_ERROR(("osh is already set....\n"));
++ ASSERT(!si->osh);
++ }
++ si->osh = osh;
++}
++
++/* set/clear sbtmstatelow core-specific flags */
++uint32
++sb_coreflags(sb_t *sbh, uint32 mask, uint32 val)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ uint32 w;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ ASSERT((val & ~mask) == 0);
++
++ /* mask and set */
++ if (mask || val) {
++ w = (R_SBREG(si, &sb->sbtmstatelow) & ~mask) | val;
++ W_SBREG(si, &sb->sbtmstatelow, w);
++ }
++
++ /* return the new value */
++ return (R_SBREG(si, &sb->sbtmstatelow));
++}
++
++/* set/clear sbtmstatehigh core-specific flags */
++uint32
++sb_coreflagshi(sb_t *sbh, uint32 mask, uint32 val)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ uint32 w;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ ASSERT((val & ~mask) == 0);
++ ASSERT((mask & ~SBTMH_FL_MASK) == 0);
++
++ /* mask and set */
++ if (mask || val) {
++ w = (R_SBREG(si, &sb->sbtmstatehigh) & ~mask) | val;
++ W_SBREG(si, &sb->sbtmstatehigh, w);
++ }
++
++ /* return the new value */
++ return (R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_FL_MASK);
++}
++
++/* Run bist on current core. Caller needs to take care of core-specific bist hazards */
++int
++sb_corebist(sb_t *sbh)
++{
++ uint32 sblo;
++ sb_info_t *si;
++ sbconfig_t *sb;
++ int result = 0;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ sblo = R_SBREG(si, &sb->sbtmstatelow);
++ W_SBREG(si, &sb->sbtmstatelow, (sblo | SBTML_FGC | SBTML_BE));
++
++ SPINWAIT(((R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_BISTD) == 0), 100000);
++
++ if (R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_BISTF)
++ result = BCME_ERROR;
++
++ W_SBREG(si, &sb->sbtmstatelow, sblo);
++
++ return result;
++}
++
++bool
++sb_iscoreup(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ return ((R_SBREG(si, &sb->sbtmstatelow) &
++ (SBTML_RESET | SBTML_REJ_MASK | SBTML_CLK)) == SBTML_CLK);
++}
++
++/*
++ * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation,
++ * switch back to the original core, and return the new value.
++ *
++ * When using the silicon backplane, no fidleing with interrupts or core switches are needed.
++ *
++ * Also, when using pci/pcie, we can optimize away the core switching for pci registers
++ * and (on newer pci cores) chipcommon registers.
++ */
++static uint
++sb_corereg(sb_info_t *si, uint coreidx, uint regoff, uint mask, uint val)
++{
++ uint origidx = 0;
++ uint32 *r = NULL;
++ uint w;
++ uint intr_val = 0;
++ bool fast = FALSE;
++
++ ASSERT(GOODIDX(coreidx));
++ ASSERT(regoff < SB_CORE_SIZE);
++ ASSERT((val & ~mask) == 0);
++
++#ifdef notyet
++ if (si->sb.bustype == SB_BUS) {
++ /* If internal bus, we can always get at everything */
++ fast = TRUE;
++ r = (uint32 *)((uchar *)si->regs[coreidx] + regoff);
++ } else if (si->sb.bustype == PCI_BUS) {
++ /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */
++
++ if ((si->coreid[coreidx] == SB_CC) &&
++ ((si->sb.buscoretype == SB_PCIE) ||
++ (si->sb.buscorerev >= 13))) {
++ /* Chipc registers are mapped at 12KB */
++
++ fast = TRUE;
++ r = (uint32 *)((char *)si->curmap + PCI_16KB0_CCREGS_OFFSET + regoff);
++ } else if (si->sb.buscoreidx == coreidx) {
++ /* pci registers are at either in the last 2KB of an 8KB window
++ * or, in pcie and pci rev 13 at 8KB
++ */
++ fast = TRUE;
++ if ((si->sb.buscoretype == SB_PCIE) ||
++ (si->sb.buscorerev >= 13))
++ r = (uint32 *)((char *)si->curmap +
++ PCI_16KB0_PCIREGS_OFFSET + regoff);
++ else
++ r = (uint32 *)((char *)si->curmap +
++ ((regoff >= SBCONFIGOFF) ?
++ PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) +
++ regoff);
++ }
++ }
++#endif /* notyet */
++
++ if (!fast) {
++ INTR_OFF(si, intr_val);
++
++ /* save current core index */
++ origidx = sb_coreidx(&si->sb);
++
++ /* switch core */
++ r = (uint32*) ((uchar*) sb_setcoreidx(&si->sb, coreidx) + regoff);
++ }
++ ASSERT(r);
++
++ /* mask and set */
++ if (mask || val) {
++ if (regoff >= SBCONFIGOFF) {
++ w = (R_SBREG(si, r) & ~mask) | val;
++ W_SBREG(si, r, w);
++ } else {
++ w = (R_REG(si->osh, r) & ~mask) | val;
++ W_REG(si->osh, r, w);
++ }
++ }
++
++ /* readback */
++ if (regoff >= SBCONFIGOFF)
++ w = R_SBREG(si, r);
++ else
++ w = R_REG(si->osh, r);
++
++ if (!fast) {
++ /* restore core index */
++ if (origidx != coreidx)
++ sb_setcoreidx(&si->sb, origidx);
++
++ INTR_RESTORE(si, intr_val);
++ }
++
++ return (w);
++}
++
++#define DWORD_ALIGN(x) (x & ~(0x03))
++#define BYTE_POS(x) (x & 0x3)
++#define WORD_POS(x) (x & 0x1)
++
++#define BYTE_SHIFT(x) (8 * BYTE_POS(x))
++#define WORD_SHIFT(x) (16 * WORD_POS(x))
++
++#define BYTE_VAL(a, x) ((a >> BYTE_SHIFT(x)) & 0xFF)
++#define WORD_VAL(a, x) ((a >> WORD_SHIFT(x)) & 0xFFFF)
++
++#define read_pci_cfg_byte(a) \
++ (BYTE_VAL(OSL_PCI_READ_CONFIG(si->osh, DWORD_ALIGN(a), 4), a) & 0xff)
++
++#define read_pci_cfg_write(a) \
++ (WORD_VAL(OSL_PCI_READ_CONFIG(si->osh, DWORD_ALIGN(a), 4), a) & 0xffff)
++
++
++/* return TRUE if requested capability exists in the PCI config space */
++static bool
++sb_find_pci_capability(sb_info_t *si, uint8 req_cap_id, uchar *buf, uint32 *buflen)
++{
++ uint8 cap_id;
++ uint8 cap_ptr;
++ uint32 bufsize;
++ uint8 byte_val;
++
++ if (BUSTYPE(si->sb.bustype) != PCI_BUS)
++ return FALSE;
++
++ /* check for Header type 0 */
++ byte_val = read_pci_cfg_byte(PCI_CFG_HDR);
++ if ((byte_val & 0x7f) != PCI_HEADER_NORMAL)
++ return FALSE;
++
++ /* check if the capability pointer field exists */
++ byte_val = read_pci_cfg_byte(PCI_CFG_STAT);
++ if (!(byte_val & PCI_CAPPTR_PRESENT))
++ return FALSE;
++
++ cap_ptr = read_pci_cfg_byte(PCI_CFG_CAPPTR);
++ /* check if the capability pointer is 0x00 */
++ if (cap_ptr == 0x00)
++ return FALSE;
++
++
++ /* loop thr'u the capability list and see if the pcie capabilty exists */
++
++ cap_id = read_pci_cfg_byte(cap_ptr);
++
++ while (cap_id != req_cap_id) {
++ cap_ptr = read_pci_cfg_byte((cap_ptr+1));
++ if (cap_ptr == 0x00) break;
++ cap_id = read_pci_cfg_byte(cap_ptr);
++ }
++ if (cap_id != req_cap_id) {
++ return FALSE;
++ }
++ /* found the caller requested capability */
++ if ((buf != NULL) && (buflen != NULL)) {
++ bufsize = *buflen;
++ if (!bufsize) goto end;
++ *buflen = 0;
++ /* copy the cpability data excluding cap ID and next ptr */
++ cap_ptr += 2;
++ if ((bufsize + cap_ptr) > SZPCR)
++ bufsize = SZPCR - cap_ptr;
++ *buflen = bufsize;
++ while (bufsize--) {
++ *buf = read_pci_cfg_byte(cap_ptr);
++ cap_ptr++;
++ buf++;
++ }
++ }
++end:
++ return TRUE;
++}
++
++/* return TRUE if PCIE capability exists the pci config space */
++static inline bool
++sb_ispcie(sb_info_t *si)
++{
++ return (sb_find_pci_capability(si, PCI_CAP_PCIECAP_ID, NULL, NULL));
++}
++
++/* scan the sb enumerated space to identify all cores */
++static void
++BCMINITFN(sb_scan)(sb_info_t *si)
++{
++ uint origidx;
++ uint i;
++ bool pci;
++ bool pcie;
++ uint pciidx;
++ uint pcieidx;
++ uint pcirev;
++ uint pcierev;
++
++
++ /* numcores should already be set */
++ ASSERT((si->numcores > 0) && (si->numcores <= SB_MAXCORES));
++
++ /* save current core index */
++ origidx = sb_coreidx(&si->sb);
++
++ si->sb.buscorerev = NOREV;
++ si->sb.buscoreidx = BADIDX;
++
++ si->gpioidx = BADIDX;
++
++ pci = pcie = FALSE;
++ pcirev = pcierev = NOREV;
++ pciidx = pcieidx = BADIDX;
++
++ for (i = 0; i < si->numcores; i++) {
++ sb_setcoreidx(&si->sb, i);
++ si->coreid[i] = sb_coreid(&si->sb);
++
++ if (si->coreid[i] == SB_PCI) {
++ pciidx = i;
++ pcirev = sb_corerev(&si->sb);
++ pci = TRUE;
++ } else if (si->coreid[i] == SB_PCIE) {
++ pcieidx = i;
++ pcierev = sb_corerev(&si->sb);
++ pcie = TRUE;
++ } else if (si->coreid[i] == SB_PCMCIA) {
++ si->sb.buscorerev = sb_corerev(&si->sb);
++ si->sb.buscoretype = si->coreid[i];
++ si->sb.buscoreidx = i;
++ }
++ }
++ if (pci && pcie) {
++ if (sb_ispcie(si))
++ pci = FALSE;
++ else
++ pcie = FALSE;
++ }
++ if (pci) {
++ si->sb.buscoretype = SB_PCI;
++ si->sb.buscorerev = pcirev;
++ si->sb.buscoreidx = pciidx;
++ } else if (pcie) {
++ si->sb.buscoretype = SB_PCIE;
++ si->sb.buscorerev = pcierev;
++ si->sb.buscoreidx = pcieidx;
++ }
++
++ /*
++ * Find the gpio "controlling core" type and index.
++ * Precedence:
++ * - if there's a chip common core - use that
++ * - else if there's a pci core (rev >= 2) - use that
++ * - else there had better be an extif core (4710 only)
++ */
++ if (GOODIDX(sb_findcoreidx(si, SB_CC, 0))) {
++ si->gpioidx = sb_findcoreidx(si, SB_CC, 0);
++ si->gpioid = SB_CC;
++ } else if (PCI(si) && (si->sb.buscorerev >= 2)) {
++ si->gpioidx = si->sb.buscoreidx;
++ si->gpioid = SB_PCI;
++ } else if (sb_findcoreidx(si, SB_EXTIF, 0)) {
++ si->gpioidx = sb_findcoreidx(si, SB_EXTIF, 0);
++ si->gpioid = SB_EXTIF;
++ } else
++ ASSERT(si->gpioidx != BADIDX);
++
++ /* return to original core index */
++ sb_setcoreidx(&si->sb, origidx);
++}
++
++/* may be called with core in reset */
++void
++sb_detach(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint idx;
++
++ si = SB_INFO(sbh);
++
++ if (si == NULL)
++ return;
++
++ if (BUSTYPE(si->sb.bustype) == SB_BUS)
++ for (idx = 0; idx < SB_MAXCORES; idx++)
++ if (si->regs[idx]) {
++ REG_UNMAP(si->regs[idx]);
++ si->regs[idx] = NULL;
++ }
++#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SB_BUS)
++ if (si != &ksi)
++#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SB_BUS) */
++ MFREE(si->osh, si, sizeof(sb_info_t));
++
++}
++
++/* use pci dev id to determine chip id for chips not having a chipcommon core */
++static uint
++BCMINITFN(sb_pcidev2chip)(uint pcidev)
++{
++ if ((pcidev >= BCM4710_DEVICE_ID) && (pcidev <= BCM47XX_USB_ID))
++ return (BCM4710_CHIP_ID);
++ if ((pcidev >= BCM4402_ENET_ID) && (pcidev <= BCM4402_V90_ID))
++ return (BCM4402_CHIP_ID);
++ if (pcidev == BCM4401_ENET_ID)
++ return (BCM4402_CHIP_ID);
++
++ return (0);
++}
++
++/* convert chip number to number of i/o cores */
++static uint
++BCMINITFN(sb_chip2numcores)(uint chip)
++{
++ if (chip == BCM4710_CHIP_ID)
++ return (9);
++ if (chip == BCM4402_CHIP_ID)
++ return (3);
++ if (chip == BCM4306_CHIP_ID) /* < 4306c0 */
++ return (6);
++ if (chip == BCM4704_CHIP_ID)
++ return (9);
++ if (chip == BCM5365_CHIP_ID)
++ return (7);
++
++ SB_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n", chip));
++ ASSERT(0);
++ return (1);
++}
++
++/* return index of coreid or BADIDX if not found */
++static uint
++sb_findcoreidx(sb_info_t *si, uint coreid, uint coreunit)
++{
++ uint found;
++ uint i;
++
++ found = 0;
++
++ for (i = 0; i < si->numcores; i++)
++ if (si->coreid[i] == coreid) {
++ if (found == coreunit)
++ return (i);
++ found++;
++ }
++
++ return (BADIDX);
++}
++
++/*
++ * this function changes logical "focus" to the indiciated core,
++ * must be called with interrupt off.
++ * Moreover, callers should keep interrupts off during switching out of and back to d11 core
++ */
++void*
++sb_setcoreidx(sb_t *sbh, uint coreidx)
++{
++ sb_info_t *si;
++ uint32 sbaddr;
++ uint8 tmp;
++
++ si = SB_INFO(sbh);
++
++ if (coreidx >= si->numcores)
++ return (NULL);
++
++ /*
++ * If the user has provided an interrupt mask enabled function,
++ * then assert interrupts are disabled before switching the core.
++ */
++ ASSERT((si->intrsenabled_fn == NULL) || !(*(si)->intrsenabled_fn)((si)->intr_arg));
++
++ sbaddr = SB_ENUM_BASE + (coreidx * SB_CORE_SIZE);
++
++ switch (BUSTYPE(si->sb.bustype)) {
++ case SB_BUS:
++ /* map new one */
++ if (!si->regs[coreidx]) {
++ si->regs[coreidx] = (void*)REG_MAP(sbaddr, SB_CORE_SIZE);
++ ASSERT(GOODREGS(si->regs[coreidx]));
++ }
++ si->curmap = si->regs[coreidx];
++ break;
++
++ case PCI_BUS:
++ /* point bar0 window */
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, 4, sbaddr);
++ break;
++
++ case PCMCIA_BUS:
++ tmp = (sbaddr >> 12) & 0x0f;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, PCMCIA_ADDR0, &tmp, 1);
++ tmp = (sbaddr >> 16) & 0xff;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, PCMCIA_ADDR1, &tmp, 1);
++ tmp = (sbaddr >> 24) & 0xff;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, PCMCIA_ADDR2, &tmp, 1);
++ break;
++#ifdef BCMJTAG
++ case JTAG_BUS:
++ /* map new one */
++ if (!si->regs[coreidx]) {
++ si->regs[coreidx] = (void *)sbaddr;
++ ASSERT(GOODREGS(si->regs[coreidx]));
++ }
++ si->curmap = si->regs[coreidx];
++ break;
++#endif /* BCMJTAG */
++ }
++
++ si->curidx = coreidx;
++
++ return (si->curmap);
++}
++
++/*
++ * this function changes logical "focus" to the indiciated core,
++ * must be called with interrupt off.
++ * Moreover, callers should keep interrupts off during switching out of and back to d11 core
++ */
++void*
++sb_setcore(sb_t *sbh, uint coreid, uint coreunit)
++{
++ sb_info_t *si;
++ uint idx;
++
++ si = SB_INFO(sbh);
++ idx = sb_findcoreidx(si, coreid, coreunit);
++ if (!GOODIDX(idx))
++ return (NULL);
++
++ return (sb_setcoreidx(sbh, idx));
++}
++
++/* return chip number */
++uint
++sb_chip(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.chip);
++}
++
++/* return chip revision number */
++uint
++sb_chiprev(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.chiprev);
++}
++
++/* return chip common revision number */
++uint
++sb_chipcrev(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.ccrev);
++}
++
++/* return chip package option */
++uint
++sb_chippkg(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.chippkg);
++}
++
++/* return PCI core rev. */
++uint
++sb_pcirev(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.buscorerev);
++}
++
++bool
++BCMINITFN(sb_war16165)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ return (PCI(si) && (si->sb.buscorerev <= 10));
++}
++
++static void
++BCMINITFN(sb_war30841)(sb_info_t *si)
++{
++ sb_pcie_mdiowrite(si, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128);
++ sb_pcie_mdiowrite(si, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100);
++ sb_pcie_mdiowrite(si, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466);
++}
++
++/* return PCMCIA core rev. */
++uint
++BCMINITFN(sb_pcmciarev)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.buscorerev);
++}
++
++/* return board vendor id */
++uint
++sb_boardvendor(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.boardvendor);
++}
++
++/* return boardtype */
++uint
++sb_boardtype(sb_t *sbh)
++{
++ sb_info_t *si;
++ char *var;
++
++ si = SB_INFO(sbh);
++
++ if (BUSTYPE(si->sb.bustype) == SB_BUS && si->sb.boardtype == 0xffff) {
++ /* boardtype format is a hex string */
++ si->sb.boardtype = getintvar(NULL, "boardtype");
++
++ /* backward compatibility for older boardtype string format */
++ if ((si->sb.boardtype == 0) && (var = getvar(NULL, "boardtype"))) {
++ if (!strcmp(var, "bcm94710dev"))
++ si->sb.boardtype = BCM94710D_BOARD;
++ else if (!strcmp(var, "bcm94710ap"))
++ si->sb.boardtype = BCM94710AP_BOARD;
++ else if (!strcmp(var, "bu4710"))
++ si->sb.boardtype = BU4710_BOARD;
++ else if (!strcmp(var, "bcm94702mn"))
++ si->sb.boardtype = BCM94702MN_BOARD;
++ else if (!strcmp(var, "bcm94710r1"))
++ si->sb.boardtype = BCM94710R1_BOARD;
++ else if (!strcmp(var, "bcm94710r4"))
++ si->sb.boardtype = BCM94710R4_BOARD;
++ else if (!strcmp(var, "bcm94702cpci"))
++ si->sb.boardtype = BCM94702CPCI_BOARD;
++ else if (!strcmp(var, "bcm95380_rr"))
++ si->sb.boardtype = BCM95380RR_BOARD;
++ }
++ }
++
++ return (si->sb.boardtype);
++}
++
++/* return bus type of sbh device */
++uint
++sb_bus(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.bustype);
++}
++
++/* return bus core type */
++uint
++sb_buscoretype(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ return (si->sb.buscoretype);
++}
++
++/* return bus core revision */
++uint
++sb_buscorerev(sb_t *sbh)
++{
++ sb_info_t *si;
++ si = SB_INFO(sbh);
++
++ return (si->sb.buscorerev);
++}
++
++/* return list of found cores */
++uint
++sb_corelist(sb_t *sbh, uint coreid[])
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ bcopy((uchar*)si->coreid, (uchar*)coreid, (si->numcores * sizeof(uint)));
++ return (si->numcores);
++}
++
++/* return current register mapping */
++void *
++sb_coreregs(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ ASSERT(GOODREGS(si->curmap));
++
++ return (si->curmap);
++}
++
++
++/* do buffered registers update */
++void
++sb_commit(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint origidx;
++ uint intr_val = 0;
++
++ si = SB_INFO(sbh);
++
++ origidx = si->curidx;
++ ASSERT(GOODIDX(origidx));
++
++ INTR_OFF(si, intr_val);
++
++ /* switch over to chipcommon core if there is one, else use pci */
++ if (si->sb.ccrev != NOREV) {
++ chipcregs_t *ccregs = (chipcregs_t *)sb_setcore(sbh, SB_CC, 0);
++
++ /* do the buffer registers update */
++ W_REG(si->osh, &ccregs->broadcastaddress, SB_COMMIT);
++ W_REG(si->osh, &ccregs->broadcastdata, 0x0);
++ } else if (PCI(si)) {
++ sbpciregs_t *pciregs = (sbpciregs_t *)sb_setcore(sbh, SB_PCI, 0);
++
++ /* do the buffer registers update */
++ W_REG(si->osh, &pciregs->bcastaddr, SB_COMMIT);
++ W_REG(si->osh, &pciregs->bcastdata, 0x0);
++ } else
++ ASSERT(0);
++
++ /* restore core index */
++ sb_setcoreidx(sbh, origidx);
++ INTR_RESTORE(si, intr_val);
++}
++
++/* reset and re-enable a core
++ * inputs:
++ * bits - core specific bits that are set during and after reset sequence
++ * resetbits - core specific bits that are set only during reset sequence
++ */
++void
++sb_core_reset(sb_t *sbh, uint32 bits, uint32 resetbits)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ volatile uint32 dummy;
++
++ si = SB_INFO(sbh);
++ ASSERT(GOODREGS(si->curmap));
++ sb = REGS2SB(si->curmap);
++
++ /*
++ * Must do the disable sequence first to work for arbitrary current core state.
++ */
++ sb_core_disable(sbh, (bits | resetbits));
++
++ /*
++ * Now do the initialization sequence.
++ */
++
++ /* set reset while enabling the clock and forcing them on throughout the core */
++ W_SBREG(si, &sb->sbtmstatelow, (SBTML_FGC | SBTML_CLK | SBTML_RESET | bits | resetbits));
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(1);
++
++ if (R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_SERR) {
++ W_SBREG(si, &sb->sbtmstatehigh, 0);
++ }
++ if ((dummy = R_SBREG(si, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) {
++ AND_SBREG(si, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO));
++ }
++
++ /* clear reset and allow it to propagate throughout the core */
++ W_SBREG(si, &sb->sbtmstatelow, (SBTML_FGC | SBTML_CLK | bits));
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(1);
++
++ /* leave clock enabled */
++ W_SBREG(si, &sb->sbtmstatelow, (SBTML_CLK | bits));
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(1);
++}
++
++void
++sb_core_tofixup(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++
++ if ((BUSTYPE(si->sb.bustype) != PCI_BUS) || PCIE(si) ||
++ (PCI(si) && (si->sb.buscorerev >= 5)))
++ return;
++
++ ASSERT(GOODREGS(si->curmap));
++ sb = REGS2SB(si->curmap);
++
++ if (BUSTYPE(si->sb.bustype) == SB_BUS) {
++ SET_SBREG(si, &sb->sbimconfiglow,
++ SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
++ (0x5 << SBIMCL_RTO_SHIFT) | 0x3);
++ } else {
++ if (sb_coreid(sbh) == SB_PCI) {
++ SET_SBREG(si, &sb->sbimconfiglow,
++ SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
++ (0x3 << SBIMCL_RTO_SHIFT) | 0x2);
++ } else {
++ SET_SBREG(si, &sb->sbimconfiglow, (SBIMCL_RTO_MASK | SBIMCL_STO_MASK), 0);
++ }
++ }
++
++ sb_commit(sbh);
++}
++
++/*
++ * Set the initiator timeout for the "master core".
++ * The master core is defined to be the core in control
++ * of the chip and so it issues accesses to non-memory
++ * locations (Because of dma *any* core can access memeory).
++ *
++ * The routine uses the bus to decide who is the master:
++ * SB_BUS => mips
++ * JTAG_BUS => chipc
++ * PCI_BUS => pci or pcie
++ * PCMCIA_BUS => pcmcia
++ * SDIO_BUS => pcmcia
++ *
++ * This routine exists so callers can disable initiator
++ * timeouts so accesses to very slow devices like otp
++ * won't cause an abort. The routine allows arbitrary
++ * settings of the service and request timeouts, though.
++ *
++ * Returns the timeout state before changing it or -1
++ * on error.
++ */
++
++#define TO_MASK (SBIMCL_RTO_MASK | SBIMCL_STO_MASK)
++
++uint32
++sb_set_initiator_to(sb_t *sbh, uint32 to)
++{
++ sb_info_t *si;
++ uint origidx, idx;
++ uint intr_val = 0;
++ uint32 tmp, ret = 0xffffffff;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++
++ if ((to & ~TO_MASK) != 0)
++ return ret;
++
++ /* Figure out the master core */
++ idx = BADIDX;
++ switch (BUSTYPE(si->sb.bustype)) {
++ case PCI_BUS:
++ idx = si->sb.buscoreidx;
++ break;
++ case JTAG_BUS:
++ idx = SB_CC_IDX;
++ break;
++ case PCMCIA_BUS:
++ case SDIO_BUS:
++ idx = sb_findcoreidx(si, SB_PCMCIA, 0);
++ break;
++ case SB_BUS:
++ if ((idx = sb_findcoreidx(si, SB_MIPS33, 0)) == BADIDX)
++ idx = sb_findcoreidx(si, SB_MIPS, 0);
++ break;
++ default:
++ ASSERT(0);
++ }
++ if (idx == BADIDX)
++ return ret;
++
++ INTR_OFF(si, intr_val);
++ origidx = sb_coreidx(sbh);
++
++ sb = REGS2SB(sb_setcoreidx(sbh, idx));
++
++ tmp = R_SBREG(si, &sb->sbimconfiglow);
++ ret = tmp & TO_MASK;
++ W_SBREG(si, &sb->sbimconfiglow, (tmp & ~TO_MASK) | to);
++
++ sb_commit(sbh);
++ sb_setcoreidx(sbh, origidx);
++ INTR_RESTORE(si, intr_val);
++ return ret;
++}
++
++void
++sb_core_disable(sb_t *sbh, uint32 bits)
++{
++ sb_info_t *si;
++ volatile uint32 dummy;
++ uint32 rej;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++
++ ASSERT(GOODREGS(si->curmap));
++ sb = REGS2SB(si->curmap);
++
++ /* if core is already in reset, just return */
++ if (R_SBREG(si, &sb->sbtmstatelow) & SBTML_RESET)
++ return;
++
++ /* reject value changed between sonics 2.2 and 2.3 */
++ if (si->sb.sonicsrev == SONICS_2_2)
++ rej = (1 << SBTML_REJ_SHIFT);
++ else
++ rej = (2 << SBTML_REJ_SHIFT);
++
++ /* if clocks are not enabled, put into reset and return */
++ if ((R_SBREG(si, &sb->sbtmstatelow) & SBTML_CLK) == 0)
++ goto disable;
++
++ /* set target reject and spin until busy is clear (preserve core-specific bits) */
++ OR_SBREG(si, &sb->sbtmstatelow, rej);
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(1);
++ SPINWAIT((R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000);
++ if (R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_BUSY)
++ SB_ERROR(("%s: target state still busy\n", __FUNCTION__));
++
++ if (R_SBREG(si, &sb->sbidlow) & SBIDL_INIT) {
++ OR_SBREG(si, &sb->sbimstate, SBIM_RJ);
++ dummy = R_SBREG(si, &sb->sbimstate);
++ OSL_DELAY(1);
++ SPINWAIT((R_SBREG(si, &sb->sbimstate) & SBIM_BY), 100000);
++ }
++
++ /* set reset and reject while enabling the clocks */
++ W_SBREG(si, &sb->sbtmstatelow, (bits | SBTML_FGC | SBTML_CLK | rej | SBTML_RESET));
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(10);
++
++ /* don't forget to clear the initiator reject bit */
++ if (R_SBREG(si, &sb->sbidlow) & SBIDL_INIT)
++ AND_SBREG(si, &sb->sbimstate, ~SBIM_RJ);
++
++disable:
++ /* leave reset and reject asserted */
++ W_SBREG(si, &sb->sbtmstatelow, (bits | rej | SBTML_RESET));
++ OSL_DELAY(1);
++}
++
++/* set chip watchdog reset timer to fire in 'ticks' backplane cycles */
++void
++sb_watchdog(sb_t *sbh, uint ticks)
++{
++ sb_info_t *si = SB_INFO(sbh);
++
++ /* make sure we come up in fast clock mode */
++ sb_clkctl_clk(sbh, CLK_FAST);
++
++ /* instant NMI */
++ switch (si->gpioid) {
++ case SB_CC:
++#ifdef __mips__
++ if (sb_chip(sbh) == BCM4785_CHIP_ID && ticks <= 1)
++ MTC0(C0_BROADCOM, 4, (1 << 22));
++#endif /* __mips__ */
++ sb_corereg(si, 0, OFFSETOF(chipcregs_t, watchdog), ~0, ticks);
++#ifdef __mips__
++ if (sb_chip(sbh) == BCM4785_CHIP_ID && ticks <= 1) {
++ __asm__ __volatile__ (
++ ".set\tmips3\n\t"
++ "sync\n\t"
++ "wait\n\t"
++ ".set\tmips0"
++ );
++ while (1);
++ }
++#endif /* __mips__ */
++ break;
++ case SB_EXTIF:
++ sb_corereg(si, si->gpioidx, OFFSETOF(extifregs_t, watchdog), ~0, ticks);
++ break;
++ }
++}
++
++/* initialize the pcmcia core */
++void
++sb_pcmcia_init(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint8 cor = 0;
++
++ si = SB_INFO(sbh);
++
++ /* enable d11 mac interrupts */
++ OSL_PCMCIA_READ_ATTR(si->osh, PCMCIA_FCR0 + PCMCIA_COR, &cor, 1);
++ cor |= COR_IRQEN | COR_FUNEN;
++ OSL_PCMCIA_WRITE_ATTR(si->osh, PCMCIA_FCR0 + PCMCIA_COR, &cor, 1);
++
++}
++
++
++/*
++ * Configure the pci core for pci client (NIC) action
++ * coremask is the bitvec of cores by index to be enabled.
++ */
++void
++BCMINITFN(sb_pci_setup)(sb_t *sbh, uint coremask)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ sbpciregs_t *pciregs;
++ uint32 sbflag;
++ uint32 w;
++ uint idx;
++ int reg_val;
++
++ si = SB_INFO(sbh);
++
++ /* if not pci bus, we're done */
++ if (BUSTYPE(si->sb.bustype) != PCI_BUS)
++ return;
++
++ ASSERT(PCI(si) || PCIE(si));
++ ASSERT(si->sb.buscoreidx != BADIDX);
++
++ /* get current core index */
++ idx = si->curidx;
++
++ /* we interrupt on this backplane flag number */
++ ASSERT(GOODREGS(si->curmap));
++ sb = REGS2SB(si->curmap);
++ sbflag = R_SBREG(si, &sb->sbtpsflag) & SBTPS_NUM0_MASK;
++
++ /* switch over to pci core */
++ pciregs = (sbpciregs_t*) sb_setcoreidx(sbh, si->sb.buscoreidx);
++ sb = REGS2SB(pciregs);
++
++ /*
++ * Enable sb->pci interrupts. Assume
++ * PCI rev 2.3 support was added in pci core rev 6 and things changed..
++ */
++ if (PCIE(si) || (PCI(si) && ((si->sb.buscorerev) >= 6))) {
++ /* pci config write to set this core bit in PCIIntMask */
++ w = OSL_PCI_READ_CONFIG(si->osh, PCI_INT_MASK, sizeof(uint32));
++ w |= (coremask << PCI_SBIM_SHIFT);
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_INT_MASK, sizeof(uint32), w);
++ } else {
++ /* set sbintvec bit for our flag number */
++ OR_SBREG(si, &sb->sbintvec, (1 << sbflag));
++ }
++
++ if (PCI(si)) {
++ OR_REG(si->osh, &pciregs->sbtopci2, (SBTOPCI_PREF|SBTOPCI_BURST));
++ if (si->sb.buscorerev >= 11)
++ OR_REG(si->osh, &pciregs->sbtopci2, SBTOPCI_RC_READMULTI);
++ if (si->sb.buscorerev < 5) {
++ SET_SBREG(si, &sb->sbimconfiglow, SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
++ (0x3 << SBIMCL_RTO_SHIFT) | 0x2);
++ sb_commit(sbh);
++ }
++ }
++
++#ifdef PCIE_SUPPOER
++ /* PCIE workarounds */
++ if (PCIE(si)) {
++ if ((si->sb.buscorerev == 0) || (si->sb.buscorerev == 1)) {
++ reg_val = sb_pcie_readreg((void *)sbh, (void *)PCIE_PCIEREGS,
++ PCIE_TLP_WORKAROUNDSREG);
++ reg_val |= 0x8;
++ sb_pcie_writereg((void *)sbh, (void *)PCIE_PCIEREGS,
++ PCIE_TLP_WORKAROUNDSREG, reg_val);
++ }
++
++ if (si->sb.buscorerev == 1) {
++ reg_val = sb_pcie_readreg((void *)sbh, (void *)PCIE_PCIEREGS,
++ PCIE_DLLP_LCREG);
++ reg_val |= (0x40);
++ sb_pcie_writereg(sbh, (void *)PCIE_PCIEREGS, PCIE_DLLP_LCREG, reg_val);
++ }
++
++ if (si->sb.buscorerev == 0)
++ sb_war30841(si);
++ }
++#endif
++
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++}
++
++uint32
++sb_base(uint32 admatch)
++{
++ uint32 base;
++ uint type;
++
++ type = admatch & SBAM_TYPE_MASK;
++ ASSERT(type < 3);
++
++ base = 0;
++
++ if (type == 0) {
++ base = admatch & SBAM_BASE0_MASK;
++ } else if (type == 1) {
++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
++ base = admatch & SBAM_BASE1_MASK;
++ } else if (type == 2) {
++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
++ base = admatch & SBAM_BASE2_MASK;
++ }
++
++ return (base);
++}
++
++uint32
++sb_size(uint32 admatch)
++{
++ uint32 size;
++ uint type;
++
++ type = admatch & SBAM_TYPE_MASK;
++ ASSERT(type < 3);
++
++ size = 0;
++
++ if (type == 0) {
++ size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1);
++ } else if (type == 1) {
++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
++ size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1);
++ } else if (type == 2) {
++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
++ size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1);
++ }
++
++ return (size);
++}
++
++/* return the core-type instantiation # of the current core */
++uint
++sb_coreunit(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint idx;
++ uint coreid;
++ uint coreunit;
++ uint i;
++
++ si = SB_INFO(sbh);
++ coreunit = 0;
++
++ idx = si->curidx;
++
++ ASSERT(GOODREGS(si->curmap));
++ coreid = sb_coreid(sbh);
++
++ /* count the cores of our type */
++ for (i = 0; i < idx; i++)
++ if (si->coreid[i] == coreid)
++ coreunit++;
++
++ return (coreunit);
++}
++
++static INLINE uint32
++factor6(uint32 x)
++{
++ switch (x) {
++ case CC_F6_2: return 2;
++ case CC_F6_3: return 3;
++ case CC_F6_4: return 4;
++ case CC_F6_5: return 5;
++ case CC_F6_6: return 6;
++ case CC_F6_7: return 7;
++ default: return 0;
++ }
++}
++
++/* calculate the speed the SB would run at given a set of clockcontrol values */
++uint32
++sb_clock_rate(uint32 pll_type, uint32 n, uint32 m)
++{
++ uint32 n1, n2, clock, m1, m2, m3, mc;
++
++ n1 = n & CN_N1_MASK;
++ n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT;
++
++ if (pll_type == PLL_TYPE6) {
++ if (m & CC_T6_MMASK)
++ return CC_T6_M1;
++ else
++ return CC_T6_M0;
++ } else if ((pll_type == PLL_TYPE1) ||
++ (pll_type == PLL_TYPE3) ||
++ (pll_type == PLL_TYPE4) ||
++ (pll_type == PLL_TYPE7)) {
++ n1 = factor6(n1);
++ n2 += CC_F5_BIAS;
++ } else if (pll_type == PLL_TYPE2) {
++ n1 += CC_T2_BIAS;
++ n2 += CC_T2_BIAS;
++ ASSERT((n1 >= 2) && (n1 <= 7));
++ ASSERT((n2 >= 5) && (n2 <= 23));
++ } else if (pll_type == PLL_TYPE5) {
++ return (100000000);
++ } else
++ ASSERT(0);
++ /* PLL types 3 and 7 use BASE2 (25Mhz) */
++ if ((pll_type == PLL_TYPE3) ||
++ (pll_type == PLL_TYPE7)) {
++ clock = CC_CLOCK_BASE2 * n1 * n2;
++ } else
++ clock = CC_CLOCK_BASE1 * n1 * n2;
++
++ if (clock == 0)
++ return 0;
++
++ m1 = m & CC_M1_MASK;
++ m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT;
++ m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT;
++ mc = (m & CC_MC_MASK) >> CC_MC_SHIFT;
++
++ if ((pll_type == PLL_TYPE1) ||
++ (pll_type == PLL_TYPE3) ||
++ (pll_type == PLL_TYPE4) ||
++ (pll_type == PLL_TYPE7)) {
++ m1 = factor6(m1);
++ if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3))
++ m2 += CC_F5_BIAS;
++ else
++ m2 = factor6(m2);
++ m3 = factor6(m3);
++
++ switch (mc) {
++ case CC_MC_BYPASS: return (clock);
++ case CC_MC_M1: return (clock / m1);
++ case CC_MC_M1M2: return (clock / (m1 * m2));
++ case CC_MC_M1M2M3: return (clock / (m1 * m2 * m3));
++ case CC_MC_M1M3: return (clock / (m1 * m3));
++ default: return (0);
++ }
++ } else {
++ ASSERT(pll_type == PLL_TYPE2);
++
++ m1 += CC_T2_BIAS;
++ m2 += CC_T2M2_BIAS;
++ m3 += CC_T2_BIAS;
++ ASSERT((m1 >= 2) && (m1 <= 7));
++ ASSERT((m2 >= 3) && (m2 <= 10));
++ ASSERT((m3 >= 2) && (m3 <= 7));
++
++ if ((mc & CC_T2MC_M1BYP) == 0)
++ clock /= m1;
++ if ((mc & CC_T2MC_M2BYP) == 0)
++ clock /= m2;
++ if ((mc & CC_T2MC_M3BYP) == 0)
++ clock /= m3;
++
++ return (clock);
++ }
++}
++
++/* returns the current speed the SB is running at */
++uint32
++sb_clock(sb_t *sbh)
++{
++ sb_info_t *si;
++ extifregs_t *eir;
++ chipcregs_t *cc;
++ uint32 n, m;
++ uint idx;
++ uint32 pll_type, rate;
++ uint intr_val = 0;
++
++ si = SB_INFO(sbh);
++ idx = si->curidx;
++ pll_type = PLL_TYPE1;
++
++ INTR_OFF(si, intr_val);
++
++ /* switch to extif or chipc core */
++ if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
++ n = R_REG(si->osh, &eir->clockcontrol_n);
++ m = R_REG(si->osh, &eir->clockcontrol_sb);
++ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
++ pll_type = R_REG(si->osh, &cc->capabilities) & CAP_PLL_MASK;
++ if (pll_type == PLL_NONE) {
++ INTR_RESTORE(si, intr_val);
++ return 80000000;
++ }
++ n = R_REG(si->osh, &cc->clockcontrol_n);
++ if (pll_type == PLL_TYPE6)
++ m = R_REG(si->osh, &cc->clockcontrol_m3);
++ else if ((pll_type == PLL_TYPE3) && !(BCMINIT(sb_chip)(sbh) == 0x5365))
++ m = R_REG(si->osh, &cc->clockcontrol_m2);
++ else
++ m = R_REG(si->osh, &cc->clockcontrol_sb);
++ } else {
++ INTR_RESTORE(si, intr_val);
++ return 0;
++ }
++
++ /* calculate rate */
++ if (BCMINIT(sb_chip)(sbh) == 0x5365)
++ rate = 100000000;
++ else {
++ rate = sb_clock_rate(pll_type, n, m);
++
++ if (pll_type == PLL_TYPE3)
++ rate = rate / 2;
++ }
++
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++
++ INTR_RESTORE(si, intr_val);
++
++ return rate;
++}
++
++/* change logical "focus" to the gpio core for optimized access */
++void*
++sb_gpiosetcore(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ return (sb_setcoreidx(sbh, si->gpioidx));
++}
++
++/* mask&set gpiocontrol bits */
++uint32
++sb_gpiocontrol(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
++ }
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpiocontrol);
++ break;
++
++ case SB_PCI:
++ regoff = OFFSETOF(sbpciregs_t, gpiocontrol);
++ break;
++
++ case SB_EXTIF:
++ return (0);
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
++
++/* mask&set gpio output enable bits */
++uint32
++sb_gpioouten(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
++ }
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpioouten);
++ break;
++
++ case SB_PCI:
++ regoff = OFFSETOF(sbpciregs_t, gpioouten);
++ break;
++
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpio[0].outen);
++ break;
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
++
++/* mask&set gpio output bits */
++uint32
++sb_gpioout(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
++ }
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpioout);
++ break;
++
++ case SB_PCI:
++ regoff = OFFSETOF(sbpciregs_t, gpioout);
++ break;
++
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpio[0].out);
++ break;
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
++
++/* reserve one gpio */
++uint32
++sb_gpioreserve(sb_t *sbh, uint32 gpio_bitmask, uint8 priority)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* only cores on SB_BUS share GPIO's and only applcation users need to
++ * reserve/release GPIO
++ */
++ if ((BUSTYPE(si->sb.bustype) != SB_BUS) || (!priority)) {
++ ASSERT((BUSTYPE(si->sb.bustype) == SB_BUS) && (priority));
++ return -1;
++ }
++ /* make sure only one bit is set */
++ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
++ ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1)));
++ return -1;
++ }
++
++ /* already reserved */
++ if (sb_gpioreservation & gpio_bitmask)
++ return -1;
++ /* set reservation */
++ sb_gpioreservation |= gpio_bitmask;
++
++ return sb_gpioreservation;
++}
++
++/* release one gpio */
++/*
++ * releasing the gpio doesn't change the current value on the GPIO last write value
++ * persists till some one overwrites it
++*/
++
++uint32
++sb_gpiorelease(sb_t *sbh, uint32 gpio_bitmask, uint8 priority)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* only cores on SB_BUS share GPIO's and only applcation users need to
++ * reserve/release GPIO
++ */
++ if ((BUSTYPE(si->sb.bustype) != SB_BUS) || (!priority)) {
++ ASSERT((BUSTYPE(si->sb.bustype) == SB_BUS) && (priority));
++ return -1;
++ }
++ /* make sure only one bit is set */
++ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
++ ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1)));
++ return -1;
++ }
++
++ /* already released */
++ if (!(sb_gpioreservation & gpio_bitmask))
++ return -1;
++
++ /* clear reservation */
++ sb_gpioreservation &= ~gpio_bitmask;
++
++ return sb_gpioreservation;
++}
++
++/* return the current gpioin register value */
++uint32
++sb_gpioin(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpioin);
++ break;
++
++ case SB_PCI:
++ regoff = OFFSETOF(sbpciregs_t, gpioin);
++ break;
++
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpioin);
++ break;
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, 0, 0));
++}
++
++/* mask&set gpio interrupt polarity bits */
++uint32
++sb_gpiointpolarity(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
++ }
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpiointpolarity);
++ break;
++
++ case SB_PCI:
++ /* pci gpio implementation does not support interrupt polarity */
++ ASSERT(0);
++ break;
++
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpiointpolarity);
++ break;
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
++
++/* mask&set gpio interrupt mask bits */
++uint32
++sb_gpiointmask(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
++ }
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpiointmask);
++ break;
++
++ case SB_PCI:
++ /* pci gpio implementation does not support interrupt mask */
++ ASSERT(0);
++ break;
++
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpiointmask);
++ break;
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
++
++/* assign the gpio to an led */
++uint32
++sb_gpioled(sb_t *sbh, uint32 mask, uint32 val)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ if (si->sb.ccrev < 16)
++ return -1;
++
++ /* gpio led powersave reg */
++ return (sb_corereg(si, 0, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val));
++}
++
++/* mask & set gpio timer val */
++uint32
++sb_gpiotimerval(sb_t *sbh, uint32 mask, uint32 gpiotimerval)
++{
++ sb_info_t *si;
++ si = SB_INFO(sbh);
++
++ if (si->sb.ccrev < 16)
++ return -1;
++
++ return (sb_corereg(si, 0, OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval));
++}
++
++
++/* return the slow clock source - LPO, XTAL, or PCI */
++static uint
++sb_slowclk_src(sb_info_t *si)
++{
++ chipcregs_t *cc;
++
++
++ ASSERT(sb_coreid(&si->sb) == SB_CC);
++
++ if (si->sb.ccrev < 6) {
++ if ((BUSTYPE(si->sb.bustype) == PCI_BUS) &&
++ (OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUT, sizeof(uint32)) &
++ PCI_CFG_GPIO_SCS))
++ return (SCC_SS_PCI);
++ else
++ return (SCC_SS_XTAL);
++ } else if (si->sb.ccrev < 10) {
++ cc = (chipcregs_t*) sb_setcoreidx(&si->sb, si->curidx);
++ return (R_REG(si->osh, &cc->slow_clk_ctl) & SCC_SS_MASK);
++ } else /* Insta-clock */
++ return (SCC_SS_XTAL);
++}
++
++/* return the ILP (slowclock) min or max frequency */
++static uint
++sb_slowclk_freq(sb_info_t *si, bool max)
++{
++ chipcregs_t *cc;
++ uint32 slowclk;
++ uint div;
++
++
++ ASSERT(sb_coreid(&si->sb) == SB_CC);
++
++ cc = (chipcregs_t*) sb_setcoreidx(&si->sb, si->curidx);
++
++ /* shouldn't be here unless we've established the chip has dynamic clk control */
++ ASSERT(R_REG(si->osh, &cc->capabilities) & CAP_PWR_CTL);
++
++ slowclk = sb_slowclk_src(si);
++ if (si->sb.ccrev < 6) {
++ if (slowclk == SCC_SS_PCI)
++ return (max? (PCIMAXFREQ/64) : (PCIMINFREQ/64));
++ else
++ return (max? (XTALMAXFREQ/32) : (XTALMINFREQ/32));
++ } else if (si->sb.ccrev < 10) {
++ div = 4 * (((R_REG(si->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1);
++ if (slowclk == SCC_SS_LPO)
++ return (max? LPOMAXFREQ : LPOMINFREQ);
++ else if (slowclk == SCC_SS_XTAL)
++ return (max? (XTALMAXFREQ/div) : (XTALMINFREQ/div));
++ else if (slowclk == SCC_SS_PCI)
++ return (max? (PCIMAXFREQ/div) : (PCIMINFREQ/div));
++ else
++ ASSERT(0);
++ } else {
++ /* Chipc rev 10 is InstaClock */
++ div = R_REG(si->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT;
++ div = 4 * (div + 1);
++ return (max ? XTALMAXFREQ : (XTALMINFREQ/div));
++ }
++ return (0);
++}
++
++static void
++BCMINITFN(sb_clkctl_setdelay)(sb_info_t *si, void *chipcregs)
++{
++ chipcregs_t * cc;
++ uint slowmaxfreq, pll_delay, slowclk;
++ uint pll_on_delay, fref_sel_delay;
++
++ pll_delay = PLL_DELAY;
++
++ /* If the slow clock is not sourced by the xtal then add the xtal_on_delay
++ * since the xtal will also be powered down by dynamic clk control logic.
++ */
++
++ slowclk = sb_slowclk_src(si);
++ if (slowclk != SCC_SS_XTAL)
++ pll_delay += XTAL_ON_DELAY;
++
++ /* Starting with 4318 it is ILP that is used for the delays */
++ slowmaxfreq = sb_slowclk_freq(si, (si->sb.ccrev >= 10) ? FALSE : TRUE);
++
++ pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
++ fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
++
++ cc = (chipcregs_t *)chipcregs;
++ W_REG(si->osh, &cc->pll_on_delay, pll_on_delay);
++ W_REG(si->osh, &cc->fref_sel_delay, fref_sel_delay);
++}
++
++/* initialize power control delay registers */
++void
++BCMINITFN(sb_clkctl_init)(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint origidx;
++ chipcregs_t *cc;
++
++ si = SB_INFO(sbh);
++
++ origidx = si->curidx;
++
++ if ((cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0)) == NULL)
++ return;
++
++ if ((si->sb.chip == BCM4321_CHIP_ID) && (si->sb.chiprev < 2))
++ W_REG(si->osh, &cc->chipcontrol,
++ (si->sb.chiprev == 0) ? CHIPCTRL_4321A0_DEFAULT : CHIPCTRL_4321A1_DEFAULT);
++
++ if (!(R_REG(si->osh, &cc->capabilities) & CAP_PWR_CTL))
++ goto done;
++
++ /* set all Instaclk chip ILP to 1 MHz */
++ else if (si->sb.ccrev >= 10)
++ SET_REG(si->osh, &cc->system_clk_ctl, SYCC_CD_MASK,
++ (ILP_DIV_1MHZ << SYCC_CD_SHIFT));
++
++ sb_clkctl_setdelay(si, (void *)cc);
++
++done:
++ sb_setcoreidx(sbh, origidx);
++}
++
++/* return the value suitable for writing to the dot11 core FAST_PWRUP_DELAY register */
++uint16
++sb_clkctl_fast_pwrup_delay(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint origidx;
++ chipcregs_t *cc;
++ uint slowminfreq;
++ uint16 fpdelay;
++ uint intr_val = 0;
++
++ si = SB_INFO(sbh);
++ fpdelay = 0;
++ origidx = si->curidx;
++
++ INTR_OFF(si, intr_val);
++
++ if ((cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0)) == NULL)
++ goto done;
++
++ if (!(R_REG(si->osh, &cc->capabilities) & CAP_PWR_CTL))
++ goto done;
++
++ slowminfreq = sb_slowclk_freq(si, FALSE);
++ fpdelay = (((R_REG(si->osh, &cc->pll_on_delay) + 2) * 1000000) +
++ (slowminfreq - 1)) / slowminfreq;
++
++done:
++ sb_setcoreidx(sbh, origidx);
++ INTR_RESTORE(si, intr_val);
++ return (fpdelay);
++}
++
++/* turn primary xtal and/or pll off/on */
++int
++sb_clkctl_xtal(sb_t *sbh, uint what, bool on)
++{
++ sb_info_t *si;
++ uint32 in, out, outen;
++
++ si = SB_INFO(sbh);
++
++ switch (BUSTYPE(si->sb.bustype)) {
++
++
++ case PCMCIA_BUS:
++ return (0);
++
++
++ case PCI_BUS:
++
++ /* pcie core doesn't have any mapping to control the xtal pu */
++ if (PCIE(si))
++ return -1;
++
++ in = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_IN, sizeof(uint32));
++ out = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUT, sizeof(uint32));
++ outen = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUTEN, sizeof(uint32));
++
++ /*
++ * Avoid glitching the clock if GPRS is already using it.
++ * We can't actually read the state of the PLLPD so we infer it
++ * by the value of XTAL_PU which *is* readable via gpioin.
++ */
++ if (on && (in & PCI_CFG_GPIO_XTAL))
++ return (0);
++
++ if (what & XTAL)
++ outen |= PCI_CFG_GPIO_XTAL;
++ if (what & PLL)
++ outen |= PCI_CFG_GPIO_PLL;
++
++ if (on) {
++ /* turn primary xtal on */
++ if (what & XTAL) {
++ out |= PCI_CFG_GPIO_XTAL;
++ if (what & PLL)
++ out |= PCI_CFG_GPIO_PLL;
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUT,
++ sizeof(uint32), out);
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUTEN,
++ sizeof(uint32), outen);
++ OSL_DELAY(XTAL_ON_DELAY);
++ }
++
++ /* turn pll on */
++ if (what & PLL) {
++ out &= ~PCI_CFG_GPIO_PLL;
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUT,
++ sizeof(uint32), out);
++ OSL_DELAY(2000);
++ }
++ } else {
++ if (what & XTAL)
++ out &= ~PCI_CFG_GPIO_XTAL;
++ if (what & PLL)
++ out |= PCI_CFG_GPIO_PLL;
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUT, sizeof(uint32), out);
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUTEN, sizeof(uint32),
++ outen);
++ }
++
++ default:
++ return (-1);
++ }
++
++ return (0);
++}
++
++/* set dynamic clk control mode (forceslow, forcefast, dynamic) */
++/* returns true if we are forcing fast clock */
++bool
++sb_clkctl_clk(sb_t *sbh, uint mode)
++{
++ sb_info_t *si;
++ uint origidx;
++ chipcregs_t *cc;
++ uint32 scc;
++ uint intr_val = 0;
++
++ si = SB_INFO(sbh);
++
++ /* chipcommon cores prior to rev6 don't support dynamic clock control */
++ if (si->sb.ccrev < 6)
++ return (FALSE);
++
++
++ /* Chips with ccrev 10 are EOL and they don't have SYCC_HR which we use below */
++ ASSERT(si->sb.ccrev != 10);
++
++ INTR_OFF(si, intr_val);
++
++ origidx = si->curidx;
++
++ if (sb_setcore(sbh, SB_MIPS33, 0) && (sb_corerev(&si->sb) <= 7) &&
++ (BUSTYPE(si->sb.bustype) == SB_BUS) && (si->sb.ccrev >= 10))
++ goto done;
++
++ /* PR32414WAR "Force HT clock on" all the time, no dynamic clk ctl */
++ if ((si->sb.chip == BCM4311_CHIP_ID) && (si->sb.chiprev <= 1))
++ goto done;
++
++ cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0);
++ ASSERT(cc != NULL);
++
++ if (!(R_REG(si->osh, &cc->capabilities) & CAP_PWR_CTL))
++ goto done;
++
++ switch (mode) {
++ case CLK_FAST: /* force fast (pll) clock */
++ if (si->sb.ccrev < 10) {
++ /* don't forget to force xtal back on before we clear SCC_DYN_XTAL.. */
++ sb_clkctl_xtal(&si->sb, XTAL, ON);
++
++ SET_REG(si->osh, &cc->slow_clk_ctl, (SCC_XC | SCC_FS | SCC_IP), SCC_IP);
++ } else
++ OR_REG(si->osh, &cc->system_clk_ctl, SYCC_HR);
++ /* wait for the PLL */
++ OSL_DELAY(PLL_DELAY);
++ break;
++
++ case CLK_DYNAMIC: /* enable dynamic clock control */
++
++ if (si->sb.ccrev < 10) {
++ scc = R_REG(si->osh, &cc->slow_clk_ctl);
++ scc &= ~(SCC_FS | SCC_IP | SCC_XC);
++ if ((scc & SCC_SS_MASK) != SCC_SS_XTAL)
++ scc |= SCC_XC;
++ W_REG(si->osh, &cc->slow_clk_ctl, scc);
++
++ /* for dynamic control, we have to release our xtal_pu "force on" */
++ if (scc & SCC_XC)
++ sb_clkctl_xtal(&si->sb, XTAL, OFF);
++ } else {
++ /* Instaclock */
++ AND_REG(si->osh, &cc->system_clk_ctl, ~SYCC_HR);
++ }
++ break;
++
++ default:
++ ASSERT(0);
++ }
++
++done:
++ sb_setcoreidx(sbh, origidx);
++ INTR_RESTORE(si, intr_val);
++ return (mode == CLK_FAST);
++}
++
++/* register driver interrupt disabling and restoring callback functions */
++void
++sb_register_intr_callback(sb_t *sbh, void *intrsoff_fn, void *intrsrestore_fn,
++ void *intrsenabled_fn, void *intr_arg)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ si->intr_arg = intr_arg;
++ si->intrsoff_fn = (sb_intrsoff_t)intrsoff_fn;
++ si->intrsrestore_fn = (sb_intrsrestore_t)intrsrestore_fn;
++ si->intrsenabled_fn = (sb_intrsenabled_t)intrsenabled_fn;
++ /* save current core id. when this function called, the current core
++ * must be the core which provides driver functions(il, et, wl, etc.)
++ */
++ si->dev_coreid = si->coreid[si->curidx];
++}
++
++
++int
++sb_corepciid(sb_t *sbh, uint func, uint16 *pcivendor, uint16 *pcidevice,
++ uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif,
++ uint8 *pciheader)
++{
++ uint16 vendor = 0xffff, device = 0xffff;
++ uint core, unit;
++ uint chip, chippkg;
++ uint nfunc;
++ char varname[SB_DEVPATH_BUFSZ + 8];
++ uint8 class, subclass, progif;
++ char devpath[SB_DEVPATH_BUFSZ];
++ uint8 header;
++
++ core = sb_coreid(sbh);
++ unit = sb_coreunit(sbh);
++
++ chip = sb_chip(sbh);
++ chippkg = sb_chippkg(sbh);
++
++ progif = 0;
++ header = PCI_HEADER_NORMAL;
++
++ /* Verify whether the function exists for the core */
++ nfunc = (core == SB_USB20H) ? 2 : 1;
++ if (func >= nfunc)
++ return BCME_ERROR;
++
++ /* Known vendor translations */
++ switch (sb_corevendor(sbh)) {
++ case SB_VEND_BCM:
++ vendor = VENDOR_BROADCOM;
++ break;
++ default:
++ return BCME_ERROR;
++ }
++
++ /* Determine class based on known core codes */
++ switch (core) {
++ case SB_ILINE20:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_ETHER;
++ device = BCM47XX_ILINE_ID;
++ break;
++ case SB_ENET:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_ETHER;
++ device = BCM47XX_ENET_ID;
++ break;
++ case SB_GIGETH:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_ETHER;
++ device = BCM47XX_GIGETH_ID;
++ break;
++ case SB_SDRAM:
++ case SB_MEMC:
++ class = PCI_CLASS_MEMORY;
++ subclass = PCI_MEMORY_RAM;
++ device = (uint16)core;
++ break;
++ case SB_PCI:
++ case SB_PCIE:
++ class = PCI_CLASS_BRIDGE;
++ subclass = PCI_BRIDGE_PCI;
++ device = (uint16)core;
++ header = PCI_HEADER_BRIDGE;
++ break;
++ case SB_MIPS:
++ case SB_MIPS33:
++ class = PCI_CLASS_CPU;
++ subclass = PCI_CPU_MIPS;
++ device = (uint16)core;
++ break;
++ case SB_CODEC:
++ class = PCI_CLASS_COMM;
++ subclass = PCI_COMM_MODEM;
++ device = BCM47XX_V90_ID;
++ break;
++ case SB_USB:
++ class = PCI_CLASS_SERIAL;
++ subclass = PCI_SERIAL_USB;
++ progif = 0x10; /* OHCI */
++ device = BCM47XX_USB_ID;
++ break;
++ case SB_USB11H:
++ class = PCI_CLASS_SERIAL;
++ subclass = PCI_SERIAL_USB;
++ progif = 0x10; /* OHCI */
++ device = BCM47XX_USBH_ID;
++ break;
++ case SB_USB20H:
++ class = PCI_CLASS_SERIAL;
++ subclass = PCI_SERIAL_USB;
++ progif = func == 0 ? 0x10 : 0x20; /* OHCI/EHCI */
++ device = BCM47XX_USB20H_ID;
++ header = 0x80; /* multifunction */
++ break;
++ case SB_USB11D:
++ class = PCI_CLASS_SERIAL;
++ subclass = PCI_SERIAL_USB;
++ device = BCM47XX_USBD_ID;
++ break;
++ case SB_USB20D:
++ class = PCI_CLASS_SERIAL;
++ subclass = PCI_SERIAL_USB;
++ device = BCM47XX_USB20D_ID;
++ break;
++ case SB_IPSEC:
++ class = PCI_CLASS_CRYPT;
++ subclass = PCI_CRYPT_NETWORK;
++ device = BCM47XX_IPSEC_ID;
++ break;
++ case SB_ROBO:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_OTHER;
++ device = BCM47XX_ROBO_ID;
++ break;
++ case SB_EXTIF:
++ case SB_CC:
++ class = PCI_CLASS_MEMORY;
++ subclass = PCI_MEMORY_FLASH;
++ device = (uint16)core;
++ break;
++ case SB_D11:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_OTHER;
++ /* Let nvram variable override core ID */
++ sb_devpath(sbh, devpath, sizeof(devpath));
++ sprintf(varname, "%sdevid", devpath);
++ if ((device = (uint16)getintvar(NULL, varname)))
++ break;
++ /*
++ * no longer support wl%did, but keep the code
++ * here for backward compatibility.
++ */
++ sprintf(varname, "wl%did", unit);
++ if ((device = (uint16)getintvar(NULL, varname)))
++ break;
++ /* Chip specific conversion */
++ if (chip == BCM4712_CHIP_ID) {
++ if (chippkg == BCM4712SMALL_PKG_ID)
++ device = BCM4306_D11G_ID;
++ else
++ device = BCM4306_D11DUAL_ID;
++ break;
++ }
++ /* ignore it */
++ device = 0xffff;
++ break;
++ case SB_SATAXOR:
++ class = PCI_CLASS_XOR;
++ subclass = PCI_XOR_QDMA;
++ device = BCM47XX_SATAXOR_ID;
++ break;
++ case SB_ATA100:
++ class = PCI_CLASS_DASDI;
++ subclass = PCI_DASDI_IDE;
++ device = BCM47XX_ATA100_ID;
++ break;
++
++ default:
++ class = subclass = progif = 0xff;
++ device = (uint16)core;
++ break;
++ }
++
++ *pcivendor = vendor;
++ *pcidevice = device;
++ *pciclass = class;
++ *pcisubclass = subclass;
++ *pciprogif = progif;
++ *pciheader = header;
++
++ return 0;
++}
++
++
++
++/* use the mdio interface to write to mdio slaves */
++static int
++sb_pcie_mdiowrite(sb_info_t *si, uint physmedia, uint regaddr, uint val)
++{
++ uint mdiodata;
++ uint i = 0;
++ sbpcieregs_t *pcieregs;
++
++ pcieregs = (sbpcieregs_t*) sb_setcoreidx(&si->sb, si->sb.buscoreidx);
++ ASSERT(pcieregs);
++
++ /* enable mdio access to SERDES */
++ W_REG(si->osh, (&pcieregs->mdiocontrol), MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL);
++
++ mdiodata = MDIODATA_START | MDIODATA_WRITE |
++ (physmedia << MDIODATA_DEVADDR_SHF) |
++ (regaddr << MDIODATA_REGADDR_SHF) | MDIODATA_TA | val;
++
++ W_REG(si->osh, (&pcieregs->mdiodata), mdiodata);
++
++ PR28829_DELAY();
++
++ /* retry till the transaction is complete */
++ while (i < 10) {
++ if (R_REG(si->osh, &(pcieregs->mdiocontrol)) & MDIOCTL_ACCESS_DONE) {
++ /* Disable mdio access to SERDES */
++ W_REG(si->osh, (&pcieregs->mdiocontrol), 0);
++ return 0;
++ }
++ OSL_DELAY(1000);
++ i++;
++ }
++
++ SB_ERROR(("sb_pcie_mdiowrite: timed out\n"));
++ /* Disable mdio access to SERDES */
++ W_REG(si->osh, (&pcieregs->mdiocontrol), 0);
++ ASSERT(0);
++ return 1;
++
++}
++
++/* indirect way to read pcie config regs */
++uint
++sb_pcie_readreg(void *sb, void* arg1, uint offset)
++{
++ sb_info_t *si;
++ sb_t *sbh;
++ uint retval = 0xFFFFFFFF;
++ sbpcieregs_t *pcieregs;
++ uint addrtype;
++
++ sbh = (sb_t *)sb;
++ si = SB_INFO(sbh);
++ ASSERT(PCIE(si));
++
++ pcieregs = (sbpcieregs_t *)sb_setcore(sbh, SB_PCIE, 0);
++ ASSERT(pcieregs);
++
++ addrtype = (uint)((uintptr)arg1);
++ switch (addrtype) {
++ case PCIE_CONFIGREGS:
++ W_REG(si->osh, (&pcieregs->configaddr), offset);
++ retval = R_REG(si->osh, &(pcieregs->configdata));
++ break;
++ case PCIE_PCIEREGS:
++ W_REG(si->osh, &(pcieregs->pcieaddr), offset);
++ retval = R_REG(si->osh, &(pcieregs->pciedata));
++ break;
++ default:
++ ASSERT(0);
++ break;
++ }
++ return retval;
++}
++
++/* indirect way to write pcie config/mdio/pciecore regs */
++uint
++sb_pcie_writereg(sb_t *sbh, void *arg1, uint offset, uint val)
++{
++ sb_info_t *si;
++ sbpcieregs_t *pcieregs;
++ uint addrtype;
++
++ si = SB_INFO(sbh);
++ ASSERT(PCIE(si));
++
++ pcieregs = (sbpcieregs_t *)sb_setcore(sbh, SB_PCIE, 0);
++ ASSERT(pcieregs);
++
++ addrtype = (uint)((uintptr)arg1);
++
++ switch (addrtype) {
++ case PCIE_CONFIGREGS:
++ W_REG(si->osh, (&pcieregs->configaddr), offset);
++ W_REG(si->osh, (&pcieregs->configdata), val);
++ break;
++ case PCIE_PCIEREGS:
++ W_REG(si->osh, (&pcieregs->pcieaddr), offset);
++ W_REG(si->osh, (&pcieregs->pciedata), val);
++ break;
++ default:
++ ASSERT(0);
++ break;
++ }
++ return 0;
++}
++
++/* Build device path. Support SB, PCI, and JTAG for now. */
++int
++sb_devpath(sb_t *sbh, char *path, int size)
++{
++ ASSERT(path);
++ ASSERT(size >= SB_DEVPATH_BUFSZ);
++
++ switch (BUSTYPE((SB_INFO(sbh))->sb.bustype)) {
++ case SB_BUS:
++ case JTAG_BUS:
++ sprintf(path, "sb/%u/", sb_coreidx(sbh));
++ break;
++ case PCI_BUS:
++ ASSERT((SB_INFO(sbh))->osh);
++ sprintf(path, "pci/%u/%u/", OSL_PCI_BUS((SB_INFO(sbh))->osh),
++ OSL_PCI_SLOT((SB_INFO(sbh))->osh));
++ break;
++ case PCMCIA_BUS:
++ SB_ERROR(("sb_devpath: OSL_PCMCIA_BUS() not implemented, bus 1 assumed\n"));
++ SB_ERROR(("sb_devpath: OSL_PCMCIA_SLOT() not implemented, slot 1 assumed\n"));
++ sprintf(path, "pc/%u/%u/", 1, 1);
++ break;
++ case SDIO_BUS:
++ SB_ERROR(("sb_devpath: device 0 assumed\n"));
++ sprintf(path, "sd/%u/", sb_coreidx(sbh));
++ break;
++ default:
++ ASSERT(0);
++ break;
++ }
++
++ return 0;
++}
++
++/*
++ * Fixup SROMless PCI device's configuration.
++ * The current core may be changed upon return.
++ */
++static int
++sb_pci_fixcfg(sb_info_t *si)
++{
++ uint origidx, pciidx;
++ sbpciregs_t *pciregs;
++ sbpcieregs_t *pcieregs;
++ uint16 val16, *reg16;
++ char name[SB_DEVPATH_BUFSZ+16], *value;
++ char devpath[SB_DEVPATH_BUFSZ];
++
++ ASSERT(BUSTYPE(si->sb.bustype) == PCI_BUS);
++
++ /* Fixup PI in SROM shadow area to enable the correct PCI core access */
++ /* save the current index */
++ origidx = sb_coreidx(&si->sb);
++
++ /* check 'pi' is correct and fix it if not */
++ if (si->sb.buscoretype == SB_PCIE) {
++ pcieregs = (sbpcieregs_t *)sb_setcore(&si->sb, SB_PCIE, 0);
++ ASSERT(pcieregs);
++ reg16 = &pcieregs->sprom[SRSH_PI_OFFSET];
++ } else if (si->sb.buscoretype == SB_PCI) {
++ pciregs = (sbpciregs_t *)sb_setcore(&si->sb, SB_PCI, 0);
++ ASSERT(pciregs);
++ reg16 = &pciregs->sprom[SRSH_PI_OFFSET];
++ } else {
++ ASSERT(0);
++ return -1;
++ }
++ pciidx = sb_coreidx(&si->sb);
++ val16 = R_REG(si->osh, reg16);
++ if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (uint16)pciidx) {
++ val16 = (uint16)(pciidx << SRSH_PI_SHIFT) | (val16 & ~SRSH_PI_MASK);
++ W_REG(si->osh, reg16, val16);
++ }
++
++ /* restore the original index */
++ sb_setcoreidx(&si->sb, origidx);
++
++ /*
++ * Fixup bar0window in PCI config space to make the core indicated
++ * by the nvram variable the current core.
++ * !Do it last, it may change the current core!
++ */
++ if (sb_devpath(&si->sb, devpath, sizeof(devpath)))
++ return -1;
++ sprintf(name, "%sb0w", devpath);
++ if ((value = getvar(NULL, name))) {
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, sizeof(uint32),
++ bcm_strtoul(value, NULL, 16));
++ /* update curidx since the current core is changed */
++ si->curidx = _sb_coreidx(si);
++ if (si->curidx == BADIDX) {
++ SB_ERROR(("sb_pci_fixcfg: bad core index\n"));
++ return -1;
++ }
++ }
++
++ return 0;
++}
++
++static uint
++sb_chipc_capability(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ /* Make sure that there is ChipCommon core present */
++ if (si->coreid[SB_CC_IDX] == SB_CC)
++ return (sb_corereg(si, SB_CC_IDX, OFFSETOF(chipcregs_t, capabilities),
++ 0, 0));
++ return 0;
++}
++
++/* Return ADDR64 capability of the backplane */
++bool
++sb_backplane64(sb_t *sbh)
++{
++ return ((sb_chipc_capability(sbh) & CAP_BKPLN64) != 0);
++}
++
++void
++sb_btcgpiowar(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint origidx;
++ uint intr_val = 0;
++ chipcregs_t *cc;
++ si = SB_INFO(sbh);
++
++ /* Make sure that there is ChipCommon core present &&
++ * UART_TX is strapped to 1
++ */
++ if (!(sb_chipc_capability(sbh) & CAP_UARTGPIO))
++ return;
++
++ /* sb_corereg cannot be used as we have to guarantee 8-bit read/writes */
++ INTR_OFF(si, intr_val);
++
++ origidx = sb_coreidx(sbh);
++
++ cc = (chipcregs_t *)sb_setcore(sbh, SB_CC, 0);
++ if (cc == NULL)
++ goto end;
++
++ W_REG(si->osh, &cc->uart0mcr, R_REG(si->osh, &cc->uart0mcr) | 0x04);
++
++end:
++ /* restore the original index */
++ sb_setcoreidx(sbh, origidx);
++
++ INTR_RESTORE(si, intr_val);
++}
++
++/* check if the device is removed */
++bool
++sb_deviceremoved(sb_t *sbh)
++{
++ uint32 w;
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ switch (BUSTYPE(si->sb.bustype)) {
++ case PCI_BUS:
++ ASSERT(si->osh);
++ w = OSL_PCI_READ_CONFIG(si->osh, PCI_CFG_VID, sizeof(uint32));
++ if ((w & 0xFFFF) != VENDOR_BROADCOM)
++ return TRUE;
++ else
++ return FALSE;
++ default:
++ return FALSE;
++ }
++ return FALSE;
++}
++
++/* Return the RAM size of the SOCRAM core */
++uint32
++sb_socram_size(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint origidx;
++ uint intr_val = 0;
++
++ sbsocramregs_t *regs;
++ bool wasup;
++ uint corerev;
++ uint32 coreinfo;
++ uint memsize = 0;
++
++ si = SB_INFO(sbh);
++ ASSERT(si);
++
++ /* Block ints and save current core */
++ INTR_OFF(si, intr_val);
++ origidx = sb_coreidx(sbh);
++
++ /* Switch to SOCRAM core */
++ if (!(regs = sb_setcore(sbh, SB_SOCRAM, 0)))
++ goto done;
++
++ /* Get info for determining size */
++ if (!(wasup = sb_iscoreup(sbh)))
++ sb_core_reset(sbh, 0, 0);
++ corerev = sb_corerev(sbh);
++ coreinfo = R_REG(si->osh, &regs->coreinfo);
++
++ /* Calculate size from coreinfo based on rev */
++ switch (corerev) {
++ case 0:
++ memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK));
++ break;
++ default: /* rev >= 1 */
++ memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK));
++ memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
++ break;
++ }
++
++ /* Return to previous state and core */
++ if (!wasup)
++ sb_core_disable(sbh, 0);
++ sb_setcoreidx(sbh, origidx);
++
++done:
++ INTR_RESTORE(si, intr_val);
++ return memsize;
++}
++
++
+diff -urN linux.old/arch/mips/bcm947xx/setup.c linux.dev/arch/mips/bcm947xx/setup.c
+--- linux.old/arch/mips/bcm947xx/setup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/setup.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,241 @@
++/*
++ * Generic setup routines for Broadcom MIPS boards
++ *
++ * Copyright (C) 2005 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/serialP.h>
++#include <linux/ide.h>
++#include <asm/bootinfo.h>
++#include <asm/cpu.h>
++#include <asm/time.h>
++#include <asm/reboot.h>
++
++#include <typedefs.h>
++#include <osl.h>
++#include <sbutils.h>
++#include <bcmutils.h>
++#include <bcmnvram.h>
++#include <sbhndmips.h>
++#include <hndmips.h>
++#include <trxhdr.h>
++
++/* Virtual IRQ base, after last hw IRQ */
++#define SBMIPS_VIRTIRQ_BASE 6
++
++/* # IRQs, hw and sw IRQs */
++#define SBMIPS_NUMIRQS 8
++
++/* Global SB handle */
++sb_t *bcm947xx_sbh = NULL;
++spinlock_t bcm947xx_sbh_lock = SPIN_LOCK_UNLOCKED;
++
++/* Convenience */
++#define sbh bcm947xx_sbh
++#define sbh_lock bcm947xx_sbh_lock
++
++extern void bcm947xx_time_init(void);
++extern void bcm947xx_timer_setup(struct irqaction *irq);
++
++#ifdef CONFIG_REMOTE_DEBUG
++extern void set_debug_traps(void);
++extern void rs_kgdb_hook(struct serial_state *);
++extern void breakpoint(void);
++#endif
++
++#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
++extern struct ide_ops std_ide_ops;
++#endif
++
++/* Kernel command line */
++char arcs_cmdline[CL_SIZE] __initdata = CONFIG_CMDLINE;
++extern void sb_serial_init(sb_t *sbh, void (*add)(void *regs, uint irq, uint baud_base, uint reg_shift));
++
++void
++bcm947xx_machine_restart(char *command)
++{
++ printk("Please stand by while rebooting the system...\n");
++
++ /* Set the watchdog timer to reset immediately */
++ __cli();
++ sb_watchdog(sbh, 1);
++ while (1);
++}
++
++void
++bcm947xx_machine_halt(void)
++{
++ printk("System halted\n");
++
++ /* Disable interrupts and watchdog and spin forever */
++ __cli();
++ sb_watchdog(sbh, 0);
++ while (1);
++}
++
++#ifdef CONFIG_SERIAL
++
++static int ser_line = 0;
++
++typedef struct {
++ void *regs;
++ uint irq;
++ uint baud_base;
++ uint reg_shift;
++} serial_port;
++
++static serial_port ports[4];
++static int num_ports = 0;
++
++static void
++serial_add(void *regs, uint irq, uint baud_base, uint reg_shift)
++{
++ ports[num_ports].regs = regs;
++ ports[num_ports].irq = irq;
++ ports[num_ports].baud_base = baud_base;
++ ports[num_ports].reg_shift = reg_shift;
++ num_ports++;
++}
++
++static void
++do_serial_add(serial_port *port)
++{
++ void *regs;
++ uint irq;
++ uint baud_base;
++ uint reg_shift;
++ struct serial_struct s;
++
++ regs = port->regs;
++ irq = port->irq;
++ baud_base = port->baud_base;
++ reg_shift = port->reg_shift;
++
++ memset(&s, 0, sizeof(s));
++
++ s.line = ser_line++;
++ s.iomem_base = regs;
++ s.irq = irq + 2;
++ s.baud_base = baud_base / 16;
++ s.flags = ASYNC_BOOT_AUTOCONF;
++ s.io_type = SERIAL_IO_MEM;
++ s.iomem_reg_shift = reg_shift;
++
++ if (early_serial_setup(&s) != 0) {
++ printk(KERN_ERR "Serial setup failed!\n");
++ }
++}
++
++#endif /* CONFIG_SERIAL */
++
++void __init
++brcm_setup(void)
++{
++ char *s;
++ int i;
++ char *value;
++
++ /* Get global SB handle */
++ sbh = sb_kattach();
++
++ /* Initialize clocks and interrupts */
++ sb_mips_init(sbh, SBMIPS_VIRTIRQ_BASE);
++
++ if (BCM330X(current_cpu_data.processor_id) &&
++ (read_c0_diag() & BRCM_PFC_AVAIL)) {
++ /*
++ * Now that the sbh is inited set the proper PFC value
++ */
++ printk("Setting the PFC to its default value\n");
++ enable_pfc(PFC_AUTO);
++ }
++
++
++#ifdef CONFIG_SERIAL
++ sb_serial_init(sbh, serial_add);
++
++ /* reverse serial ports if nvram variable starts with console=ttyS1 */
++ /* Initialize UARTs */
++ s = nvram_get("kernel_args");
++ if (!s) s = "";
++ if (!strncmp(s, "console=ttyS1", 13)) {
++ for (i = num_ports; i; i--)
++ do_serial_add(&ports[i - 1]);
++ } else {
++ for (i = 0; i < num_ports; i++)
++ do_serial_add(&ports[i]);
++ }
++#endif
++
++#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
++ ide_ops = &std_ide_ops;
++#endif
++
++ /* Override default command line arguments */
++ value = nvram_get("kernel_cmdline");
++ if (value && strlen(value) && strncmp(value, "empty", 5))
++ strncpy(arcs_cmdline, value, sizeof(arcs_cmdline));
++
++
++ /* Generic setup */
++ _machine_restart = bcm947xx_machine_restart;
++ _machine_halt = bcm947xx_machine_halt;
++ _machine_power_off = bcm947xx_machine_halt;
++
++ board_time_init = bcm947xx_time_init;
++ board_timer_setup = bcm947xx_timer_setup;
++}
++
++const char *
++get_system_type(void)
++{
++ static char s[32];
++
++ if (bcm947xx_sbh) {
++ sprintf(s, "Broadcom BCM%X chip rev %d", sb_chip(bcm947xx_sbh),
++ sb_chiprev(bcm947xx_sbh));
++ return s;
++ }
++ else
++ return "Broadcom BCM947XX";
++}
++
++void __init
++bus_error_init(void)
++{
++}
++
+diff -urN linux.old/arch/mips/bcm947xx/sflash.c linux.dev/arch/mips/bcm947xx/sflash.c
+--- linux.old/arch/mips/bcm947xx/sflash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/sflash.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,422 @@
++/*
++ * Broadcom SiliconBackplane chipcommon serial flash interface
++ *
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: sflash.c,v 1.1.1.13 2006/02/27 03:43:16 honor Exp $
++ */
++
++#include <osl.h>
++#include <typedefs.h>
++#include <sbconfig.h>
++#include <sbchipc.h>
++#include <mipsinc.h>
++#include <bcmutils.h>
++#include <bcmdevs.h>
++#include <sflash.h>
++
++/* Private global state */
++static struct sflash sflash;
++
++/* Issue a serial flash command */
++static INLINE void
++sflash_cmd(chipcregs_t *cc, uint opcode)
++{
++ W_REG(NULL, &cc->flashcontrol, SFLASH_START | opcode);
++ while (R_REG(NULL, &cc->flashcontrol) & SFLASH_BUSY);
++}
++
++/* Initialize serial flash access */
++struct sflash *
++sflash_init(chipcregs_t *cc)
++{
++ uint32 id, id2;
++
++ bzero(&sflash, sizeof(sflash));
++
++ sflash.type = R_REG(NULL, &cc->capabilities) & CAP_FLASH_MASK;
++
++ switch (sflash.type) {
++ case SFLASH_ST:
++ /* Probe for ST chips */
++ sflash_cmd(cc, SFLASH_ST_DP);
++ sflash_cmd(cc, SFLASH_ST_RES);
++ id = R_REG(NULL, &cc->flashdata);
++ switch (id) {
++ case 0x11:
++ /* ST M25P20 2 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 4;
++ break;
++ case 0x12:
++ /* ST M25P40 4 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 8;
++ break;
++ case 0x13:
++ /* ST M25P80 8 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 16;
++ break;
++ case 0x14:
++ /* ST M25P16 16 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 32;
++ break;
++ case 0x15:
++ /* ST M25P32 32 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 64;
++ break;
++ case 0x16:
++ /* ST M25P64 64 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 128;
++ break;
++ case 0xbf:
++ W_REG(NULL, &cc->flashaddress, 1);
++ sflash_cmd(cc, SFLASH_ST_RES);
++ id2 = R_REG(NULL, &cc->flashdata);
++ if (id2 == 0x44) {
++ /* SST M25VF80 4 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 8;
++ }
++ break;
++ }
++ break;
++
++ case SFLASH_AT:
++ /* Probe for Atmel chips */
++ sflash_cmd(cc, SFLASH_AT_STATUS);
++ id = R_REG(NULL, &cc->flashdata) & 0x3c;
++ switch (id) {
++ case 0xc:
++ /* Atmel AT45DB011 1Mbit Serial Flash */
++ sflash.blocksize = 256;
++ sflash.numblocks = 512;
++ break;
++ case 0x14:
++ /* Atmel AT45DB021 2Mbit Serial Flash */
++ sflash.blocksize = 256;
++ sflash.numblocks = 1024;
++ break;
++ case 0x1c:
++ /* Atmel AT45DB041 4Mbit Serial Flash */
++ sflash.blocksize = 256;
++ sflash.numblocks = 2048;
++ break;
++ case 0x24:
++ /* Atmel AT45DB081 8Mbit Serial Flash */
++ sflash.blocksize = 256;
++ sflash.numblocks = 4096;
++ break;
++ case 0x2c:
++ /* Atmel AT45DB161 16Mbit Serial Flash */
++ sflash.blocksize = 512;
++ sflash.numblocks = 4096;
++ break;
++ case 0x34:
++ /* Atmel AT45DB321 32Mbit Serial Flash */
++ sflash.blocksize = 512;
++ sflash.numblocks = 8192;
++ break;
++ case 0x3c:
++ /* Atmel AT45DB642 64Mbit Serial Flash */
++ sflash.blocksize = 1024;
++ sflash.numblocks = 8192;
++ break;
++ }
++ break;
++ }
++
++ sflash.size = sflash.blocksize * sflash.numblocks;
++ return sflash.size ? &sflash : NULL;
++}
++
++/* Read len bytes starting at offset into buf. Returns number of bytes read. */
++int
++sflash_read(chipcregs_t *cc, uint offset, uint len, uchar *buf)
++{
++ int cnt;
++ uint32 *from, *to;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > sflash.size)
++ return -22;
++
++ if ((len >= 4) && (offset & 3))
++ cnt = 4 - (offset & 3);
++ else if ((len >= 4) && ((uint32)buf & 3))
++ cnt = 4 - ((uint32)buf & 3);
++ else
++ cnt = len;
++
++ from = (uint32 *)KSEG1ADDR(SB_FLASH2 + offset);
++ to = (uint32 *)buf;
++
++ if (cnt < 4) {
++ bcopy(from, to, cnt);
++ return cnt;
++ }
++
++ while (cnt >= 4) {
++ *to++ = *from++;
++ cnt -= 4;
++ }
++
++ return (len - cnt);
++}
++
++/* Poll for command completion. Returns zero when complete. */
++int
++sflash_poll(chipcregs_t *cc, uint offset)
++{
++ if (offset >= sflash.size)
++ return -22;
++
++ switch (sflash.type) {
++ case SFLASH_ST:
++ /* Check for ST Write In Progress bit */
++ sflash_cmd(cc, SFLASH_ST_RDSR);
++ return R_REG(NULL, &cc->flashdata) & SFLASH_ST_WIP;
++ case SFLASH_AT:
++ /* Check for Atmel Ready bit */
++ sflash_cmd(cc, SFLASH_AT_STATUS);
++ return !(R_REG(NULL, &cc->flashdata) & SFLASH_AT_READY);
++ }
++
++ return 0;
++}
++
++/* Write len bytes starting at offset into buf. Returns number of bytes
++ * written. Caller should poll for completion.
++ */
++int
++sflash_write(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
++{
++ struct sflash *sfl;
++ int ret = 0;
++ bool is4712b0;
++ uint32 page, byte, mask;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > sflash.size)
++ return -22;
++
++ sfl = &sflash;
++ switch (sfl->type) {
++ case SFLASH_ST:
++ mask = R_REG(NULL, &cc->chipid);
++ is4712b0 = (((mask & CID_ID_MASK) == BCM4712_CHIP_ID) &&
++ ((mask & CID_REV_MASK) == (3 << CID_REV_SHIFT)));
++ /* Enable writes */
++ sflash_cmd(cc, SFLASH_ST_WREN);
++ if (is4712b0) {
++ mask = 1 << 14;
++ W_REG(NULL, &cc->flashaddress, offset);
++ W_REG(NULL, &cc->flashdata, *buf++);
++ /* Set chip select */
++ OR_REG(NULL, &cc->gpioout, mask);
++ /* Issue a page program with the first byte */
++ sflash_cmd(cc, SFLASH_ST_PP);
++ ret = 1;
++ offset++;
++ len--;
++ while (len > 0) {
++ if ((offset & 255) == 0) {
++ /* Page boundary, drop cs and return */
++ AND_REG(NULL, &cc->gpioout, ~mask);
++ if (!sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -11;
++ }
++ return ret;
++ } else {
++ /* Write single byte */
++ sflash_cmd(cc, *buf++);
++ }
++ ret++;
++ offset++;
++ len--;
++ }
++ /* All done, drop cs if needed */
++ if ((offset & 255) != 1) {
++ /* Drop cs */
++ AND_REG(NULL, &cc->gpioout, ~mask);
++ if (!sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -12;
++ }
++ }
++ } else {
++ ret = 1;
++ W_REG(NULL, &cc->flashaddress, offset);
++ W_REG(NULL, &cc->flashdata, *buf);
++ /* Page program */
++ sflash_cmd(cc, SFLASH_ST_PP);
++ }
++ break;
++ case SFLASH_AT:
++ mask = sfl->blocksize - 1;
++ page = (offset & ~mask) << 1;
++ byte = offset & mask;
++ /* Read main memory page into buffer 1 */
++ if (byte || (len < sfl->blocksize)) {
++ W_REG(NULL, &cc->flashaddress, page);
++ sflash_cmd(cc, SFLASH_AT_BUF1_LOAD);
++ /* 250 us for AT45DB321B */
++ SPINWAIT(sflash_poll(cc, offset), 1000);
++ ASSERT(!sflash_poll(cc, offset));
++ }
++ /* Write into buffer 1 */
++ for (ret = 0; (ret < (int)len) && (byte < sfl->blocksize); ret++) {
++ W_REG(NULL, &cc->flashaddress, byte++);
++ W_REG(NULL, &cc->flashdata, *buf++);
++ sflash_cmd(cc, SFLASH_AT_BUF1_WRITE);
++ }
++ /* Write buffer 1 into main memory page */
++ W_REG(NULL, &cc->flashaddress, page);
++ sflash_cmd(cc, SFLASH_AT_BUF1_PROGRAM);
++ break;
++ }
++
++ return ret;
++}
++
++/* Erase a region. Returns number of bytes scheduled for erasure.
++ * Caller should poll for completion.
++ */
++int
++sflash_erase(chipcregs_t *cc, uint offset)
++{
++ struct sflash *sfl;
++
++ if (offset >= sflash.size)
++ return -22;
++
++ sfl = &sflash;
++ switch (sfl->type) {
++ case SFLASH_ST:
++ sflash_cmd(cc, SFLASH_ST_WREN);
++ W_REG(NULL, &cc->flashaddress, offset);
++ sflash_cmd(cc, SFLASH_ST_SE);
++ return sfl->blocksize;
++ case SFLASH_AT:
++ W_REG(NULL, &cc->flashaddress, offset << 1);
++ sflash_cmd(cc, SFLASH_AT_PAGE_ERASE);
++ return sfl->blocksize;
++ }
++
++ return 0;
++}
++
++/*
++ * writes the appropriate range of flash, a NULL buf simply erases
++ * the region of flash
++ */
++int
++sflash_commit(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
++{
++ struct sflash *sfl;
++ uchar *block = NULL, *cur_ptr, *blk_ptr;
++ uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
++ uint blk_offset, blk_len, copied;
++ int bytes, ret = 0;
++
++ /* Check address range */
++ if (len <= 0)
++ return 0;
++
++ sfl = &sflash;
++ if ((offset + len) > sfl->size)
++ return -1;
++
++ blocksize = sfl->blocksize;
++ mask = blocksize - 1;
++
++ /* Allocate a block of mem */
++ if (!(block = MALLOC(NULL, blocksize)))
++ return -1;
++
++ while (len) {
++ /* Align offset */
++ cur_offset = offset & ~mask;
++ cur_length = blocksize;
++ cur_ptr = block;
++
++ remainder = blocksize - (offset & mask);
++ if (len < remainder)
++ cur_retlen = len;
++ else
++ cur_retlen = remainder;
++
++ /* buf == NULL means erase only */
++ if (buf) {
++ /* Copy existing data into holding block if necessary */
++ if ((offset & mask) || (len < blocksize)) {
++ blk_offset = cur_offset;
++ blk_len = cur_length;
++ blk_ptr = cur_ptr;
++
++ /* Copy entire block */
++ while (blk_len) {
++ copied = sflash_read(cc, blk_offset, blk_len, blk_ptr);
++ blk_offset += copied;
++ blk_len -= copied;
++ blk_ptr += copied;
++ }
++ }
++
++ /* Copy input data into holding block */
++ memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
++ }
++
++ /* Erase block */
++ if ((ret = sflash_erase(cc, (uint) cur_offset)) < 0)
++ goto done;
++ while (sflash_poll(cc, (uint) cur_offset));
++
++ /* buf == NULL means erase only */
++ if (!buf) {
++ offset += cur_retlen;
++ len -= cur_retlen;
++ continue;
++ }
++
++ /* Write holding block */
++ while (cur_length > 0) {
++ if ((bytes = sflash_write(cc,
++ (uint) cur_offset,
++ (uint) cur_length,
++ (uchar *) cur_ptr)) < 0) {
++ ret = bytes;
++ goto done;
++ }
++ while (sflash_poll(cc, (uint) cur_offset));
++ cur_offset += bytes;
++ cur_length -= bytes;
++ cur_ptr += bytes;
++ }
++
++ offset += cur_retlen;
++ len -= cur_retlen;
++ buf += cur_retlen;
++ }
++
++ ret = len;
++done:
++ if (block)
++ MFREE(NULL, block, blocksize);
++ return ret;
++}
+diff -urN linux.old/arch/mips/bcm947xx/time.c linux.dev/arch/mips/bcm947xx/time.c
+--- linux.old/arch/mips/bcm947xx/time.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm947xx/time.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,104 @@
++/*
++ * Copyright 2006, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: time.c,v 1.1.1.10 2006/02/27 03:42:55 honor Exp $
++ */
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/serial_reg.h>
++#include <linux/interrupt.h>
++#include <asm/addrspace.h>
++#include <asm/io.h>
++#include <asm/time.h>
++
++#include <typedefs.h>
++#include <osl.h>
++#include <bcmnvram.h>
++#include <sbconfig.h>
++#include <sbextif.h>
++#include <sbutils.h>
++#include <hndmips.h>
++#include <mipsinc.h>
++#include <hndcpu.h>
++
++/* Global SB handle */
++extern void *bcm947xx_sbh;
++extern spinlock_t bcm947xx_sbh_lock;
++
++/* Convenience */
++#define sbh bcm947xx_sbh
++#define sbh_lock bcm947xx_sbh_lock
++
++extern int panic_timeout;
++static int watchdog = 0;
++static u8 *mcr = NULL;
++
++void __init
++bcm947xx_time_init(void)
++{
++ unsigned int hz;
++ extifregs_t *eir;
++
++ /*
++ * Use deterministic values for initial counter interrupt
++ * so that calibrate delay avoids encountering a counter wrap.
++ */
++ write_c0_count(0);
++ write_c0_compare(0xffff);
++
++ if (!(hz = sb_cpu_clock(sbh)))
++ hz = 100000000;
++
++ printk("CPU: BCM%04x rev %d at %d MHz\n", sb_chip(sbh), sb_chiprev(sbh),
++ (hz + 500000) / 1000000);
++
++ /* Set MIPS counter frequency for fixed_rate_gettimeoffset() */
++ mips_hpt_frequency = hz / 2;
++
++ /* Set watchdog interval in ms */
++ watchdog = simple_strtoul(nvram_safe_get("watchdog"), NULL, 0);
++
++ /* Please set the watchdog to 3 sec if it is less than 3 but not equal to 0 */
++ if (watchdog > 0) {
++ if (watchdog < 3000)
++ watchdog = 3000;
++ }
++
++ /* Set panic timeout in seconds */
++ panic_timeout = watchdog / 1000;
++}
++
++static void
++bcm947xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++ /* Generic MIPS timer code */
++ timer_interrupt(irq, dev_id, regs);
++
++ /* Set the watchdog timer to reset after the specified number of ms */
++ if (watchdog > 0)
++ sb_watchdog(sbh, WATCHDOG_CLOCK / 1000 * watchdog);
++}
++
++static struct irqaction bcm947xx_timer_irqaction = {
++ bcm947xx_timer_interrupt,
++ SA_INTERRUPT,
++ 0,
++ "timer",
++ NULL,
++ NULL
++};
++
++void __init
++bcm947xx_timer_setup(struct irqaction *irq)
++{
++ /* Enable the timer interrupt */
++ setup_irq(7, &bcm947xx_timer_irqaction);
++}
+diff -urN linux.old/arch/mips/config-shared.in linux.dev/arch/mips/config-shared.in
+--- linux.old/arch/mips/config-shared.in 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/arch/mips/config-shared.in 2006-10-02 21:19:59.000000000 +0200
+@@ -208,6 +208,14 @@
+ fi
+ define_bool CONFIG_MIPS_RTC y
+ fi
++dep_bool 'Support for Broadcom MIPS-based boards' CONFIG_MIPS_BRCM $CONFIG_EXPERIMENTAL
++dep_bool 'Support for Broadcom BCM947XX' CONFIG_BCM947XX $CONFIG_MIPS_BRCM
++if [ "$CONFIG_BCM947XX" = "y" ] ; then
++ bool ' Support for Broadcom BCM4710' CONFIG_BCM4710
++ bool ' Support for Broadcom BCM4310' CONFIG_BCM4310
++ bool ' Support for Broadcom BCM4704' CONFIG_BCM4704
++ bool ' Support for Broadcom BCM5365' CONFIG_BCM5365
++fi
+ bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI
+ bool 'Support for TANBAC TB0226 (Mbase)' CONFIG_TANBAC_TB0226
+ bool 'Support for TANBAC TB0229 (VR4131DIMM)' CONFIG_TANBAC_TB0229
+@@ -229,6 +237,11 @@
+ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+
+ #
++# Provide an option for a default kernel command line
++#
++string 'Default kernel command string' CONFIG_CMDLINE ""
++
++#
+ # Select some configuration options automatically based on user selections.
+ #
+ if [ "$CONFIG_ACER_PICA_61" = "y" ]; then
+@@ -554,6 +567,12 @@
+ define_bool CONFIG_SWAP_IO_SPACE_L y
+ define_bool CONFIG_BOOT_ELF32 y
+ fi
++if [ "$CONFIG_BCM947XX" = "y" ] ; then
++ define_bool CONFIG_PCI y
++ define_bool CONFIG_NONCOHERENT_IO y
++ define_bool CONFIG_NEW_TIME_C y
++ define_bool CONFIG_NEW_IRQ y
++fi
+ if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then
+ define_bool CONFIG_ARC32 y
+ define_bool CONFIG_ARC_MEMORY y
+@@ -1042,7 +1061,11 @@
+
+ bool 'Are you using a crosscompiler' CONFIG_CROSSCOMPILE
+ bool 'Enable run-time debugging' CONFIG_RUNTIME_DEBUG
+-bool 'Remote GDB kernel debugging' CONFIG_KGDB
++if [ "$CONFIG_BCM947XX" = "y" ] ; then
++ bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
++else
++ bool 'Remote GDB kernel debugging' CONFIG_KGDB
++fi
+ dep_bool ' Console output to GDB' CONFIG_GDB_CONSOLE $CONFIG_KGDB
+ if [ "$CONFIG_KGDB" = "y" ]; then
+ define_bool CONFIG_DEBUG_INFO y
+diff -urN linux.old/arch/mips/kernel/cpu-probe.c linux.dev/arch/mips/kernel/cpu-probe.c
+--- linux.old/arch/mips/kernel/cpu-probe.c 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/arch/mips/kernel/cpu-probe.c 2006-10-02 21:19:59.000000000 +0200
+@@ -162,7 +162,7 @@
+
+ static inline void cpu_probe_legacy(struct cpuinfo_mips *c)
+ {
+- switch (c->processor_id & 0xff00) {
++ switch (c->processor_id & PRID_IMP_MASK) {
+ case PRID_IMP_R2000:
+ c->cputype = CPU_R2000;
+ c->isa_level = MIPS_CPU_ISA_I;
+@@ -172,7 +172,7 @@
+ c->tlbsize = 64;
+ break;
+ case PRID_IMP_R3000:
+- if ((c->processor_id & 0xff) == PRID_REV_R3000A)
++ if ((c->processor_id & PRID_REV_MASK) == PRID_REV_R3000A)
+ if (cpu_has_confreg())
+ c->cputype = CPU_R3081E;
+ else
+@@ -187,12 +187,12 @@
+ break;
+ case PRID_IMP_R4000:
+ if (read_c0_config() & CONF_SC) {
+- if ((c->processor_id & 0xff) >= PRID_REV_R4400)
++ if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_R4400)
+ c->cputype = CPU_R4400PC;
+ else
+ c->cputype = CPU_R4000PC;
+ } else {
+- if ((c->processor_id & 0xff) >= PRID_REV_R4400)
++ if ((c->processor_id & PRID_REV_MASK) >= PRID_REV_R4400)
+ c->cputype = CPU_R4400SC;
+ else
+ c->cputype = CPU_R4000SC;
+@@ -438,7 +438,7 @@
+ static inline void cpu_probe_mips(struct cpuinfo_mips *c)
+ {
+ decode_config1(c);
+- switch (c->processor_id & 0xff00) {
++ switch (c->processor_id & PRID_IMP_MASK) {
+ case PRID_IMP_4KC:
+ c->cputype = CPU_4KC;
+ c->isa_level = MIPS_CPU_ISA_M32;
+@@ -479,10 +479,10 @@
+ {
+ decode_config1(c);
+ c->options |= MIPS_CPU_PREFETCH;
+- switch (c->processor_id & 0xff00) {
++ switch (c->processor_id & PRID_IMP_MASK) {
+ case PRID_IMP_AU1_REV1:
+ case PRID_IMP_AU1_REV2:
+- switch ((c->processor_id >> 24) & 0xff) {
++ switch ((c->processor_id >> 24) & PRID_REV_MASK) {
+ case 0:
+ c->cputype = CPU_AU1000;
+ break;
+@@ -510,10 +510,34 @@
+ }
+ }
+
++static inline void cpu_probe_broadcom(struct cpuinfo_mips *c)
++{
++ decode_config1(c);
++ c->options |= MIPS_CPU_PREFETCH;
++ switch (c->processor_id & PRID_IMP_MASK) {
++ case PRID_IMP_BCM4710:
++ c->cputype = CPU_BCM4710;
++ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
++ MIPS_CPU_4KTLB | MIPS_CPU_COUNTER;
++ c->scache.flags = MIPS_CACHE_NOT_PRESENT;
++ break;
++ case PRID_IMP_4KC:
++ case PRID_IMP_BCM3302:
++ c->cputype = CPU_BCM3302;
++ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
++ MIPS_CPU_4KTLB | MIPS_CPU_COUNTER;
++ c->scache.flags = MIPS_CACHE_NOT_PRESENT;
++ break;
++ default:
++ c->cputype = CPU_UNKNOWN;
++ break;
++ }
++}
++
+ static inline void cpu_probe_sibyte(struct cpuinfo_mips *c)
+ {
+ decode_config1(c);
+- switch (c->processor_id & 0xff00) {
++ switch (c->processor_id & PRID_IMP_MASK) {
+ case PRID_IMP_SB1:
+ c->cputype = CPU_SB1;
+ c->isa_level = MIPS_CPU_ISA_M64;
+@@ -535,7 +559,7 @@
+ static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c)
+ {
+ decode_config1(c);
+- switch (c->processor_id & 0xff00) {
++ switch (c->processor_id & PRID_IMP_MASK) {
+ case PRID_IMP_SR71000:
+ c->cputype = CPU_SR71000;
+ c->isa_level = MIPS_CPU_ISA_M64;
+@@ -560,7 +584,7 @@
+ c->cputype = CPU_UNKNOWN;
+
+ c->processor_id = read_c0_prid();
+- switch (c->processor_id & 0xff0000) {
++ switch (c->processor_id & PRID_COMP_MASK) {
+
+ case PRID_COMP_LEGACY:
+ cpu_probe_legacy(c);
+@@ -571,6 +595,9 @@
+ case PRID_COMP_ALCHEMY:
+ cpu_probe_alchemy(c);
+ break;
++ case PRID_COMP_BROADCOM:
++ cpu_probe_broadcom(c);
++ break;
+ case PRID_COMP_SIBYTE:
+ cpu_probe_sibyte(c);
+ break;
+diff -urN linux.old/arch/mips/kernel/head.S linux.dev/arch/mips/kernel/head.S
+--- linux.old/arch/mips/kernel/head.S 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/arch/mips/kernel/head.S 2006-10-02 21:19:59.000000000 +0200
+@@ -28,12 +28,20 @@
+ #include <asm/mipsregs.h>
+ #include <asm/stackframe.h>
+
++#ifdef CONFIG_BCM4710
++#undef eret
++#define eret nop; nop; eret
++#endif
++
+ .text
++ j kernel_entry
++ nop
++
+ /*
+ * Reserved space for exception handlers.
+ * Necessary for machines which link their kernels at KSEG0.
+ */
+- .fill 0x400
++ .fill 0x3f4
+
+ /* The following two symbols are used for kernel profiling. */
+ EXPORT(stext)
+diff -urN linux.old/arch/mips/kernel/proc.c linux.dev/arch/mips/kernel/proc.c
+--- linux.old/arch/mips/kernel/proc.c 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/arch/mips/kernel/proc.c 2006-10-02 21:19:59.000000000 +0200
+@@ -78,9 +78,10 @@
+ [CPU_AU1550] "Au1550",
+ [CPU_24K] "MIPS 24K",
+ [CPU_AU1200] "Au1200",
++ [CPU_BCM4710] "BCM4710",
++ [CPU_BCM3302] "BCM3302",
+ };
+
+-
+ static int show_cpuinfo(struct seq_file *m, void *v)
+ {
+ unsigned int version = current_cpu_data.processor_id;
+diff -urN linux.old/arch/mips/kernel/setup.c linux.dev/arch/mips/kernel/setup.c
+--- linux.old/arch/mips/kernel/setup.c 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/arch/mips/kernel/setup.c 2006-10-02 21:19:59.000000000 +0200
+@@ -493,6 +493,7 @@
+ void swarm_setup(void);
+ void hp_setup(void);
+ void au1x00_setup(void);
++ void brcm_setup(void);
+ void frame_info_init(void);
+
+ frame_info_init();
+@@ -691,6 +692,11 @@
+ pmc_yosemite_setup();
+ break;
+ #endif
++#if defined(CONFIG_BCM4710) || defined(CONFIG_BCM4310)
++ case MACH_GROUP_BRCM:
++ brcm_setup();
++ break;
++#endif
+ default:
+ panic("Unsupported architecture");
+ }
+diff -urN linux.old/arch/mips/kernel/traps.c linux.dev/arch/mips/kernel/traps.c
+--- linux.old/arch/mips/kernel/traps.c 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/arch/mips/kernel/traps.c 2006-10-02 21:19:59.000000000 +0200
+@@ -920,6 +920,7 @@
+ void __init trap_init(void)
+ {
+ extern char except_vec1_generic;
++ extern char except_vec2_generic;
+ extern char except_vec3_generic, except_vec3_r4000;
+ extern char except_vec_ejtag_debug;
+ extern char except_vec4;
+@@ -927,6 +928,7 @@
+
+ /* Copy the generic exception handler code to it's final destination. */
+ memcpy((void *)(KSEG0 + 0x80), &except_vec1_generic, 0x80);
++ memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80);
+
+ /*
+ * Setup default vectors
+@@ -985,6 +987,12 @@
+ set_except_vector(13, handle_tr);
+ set_except_vector(22, handle_mdmx);
+
++ if (current_cpu_data.cputype == CPU_SB1) {
++ /* Enable timer interrupt and scd mapped interrupt */
++ clear_c0_status(0xf000);
++ set_c0_status(0xc00);
++ }
++
+ if (cpu_has_fpu && !cpu_has_nofpuex)
+ set_except_vector(15, handle_fpe);
+
+diff -urN linux.old/arch/mips/Makefile linux.dev/arch/mips/Makefile
+--- linux.old/arch/mips/Makefile 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/arch/mips/Makefile 2006-10-02 21:19:59.000000000 +0200
+@@ -726,6 +726,19 @@
+ endif
+
+ #
++# Broadcom BCM947XX variants
++#
++ifdef CONFIG_BCM947XX
++LIBS += arch/mips/bcm947xx/generic/brcm.o arch/mips/bcm947xx/bcm947xx.o
++SUBDIRS += arch/mips/bcm947xx/generic arch/mips/bcm947xx
++LOADADDR := 0x80001000
++
++zImage: vmlinux
++ $(MAKE) -C arch/$(ARCH)/bcm947xx/compressed
++export LOADADDR
++endif
++
++#
+ # Choosing incompatible machines durings configuration will result in
+ # error messages during linking. Select a default linkscript if
+ # none has been choosen above.
+@@ -778,6 +791,7 @@
+ $(MAKE) -C arch/$(ARCH)/tools clean
+ $(MAKE) -C arch/mips/baget clean
+ $(MAKE) -C arch/mips/lasat clean
++ $(MAKE) -C arch/mips/bcm947xx/compressed clean
+
+ archmrproper:
+ @$(MAKEBOOT) mrproper
+diff -urN linux.old/arch/mips/mm/c-r4k.c linux.dev/arch/mips/mm/c-r4k.c
+--- linux.old/arch/mips/mm/c-r4k.c 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/arch/mips/mm/c-r4k.c 2006-10-02 21:19:59.000000000 +0200
+@@ -1166,3 +1166,47 @@
+ build_clear_page();
+ build_copy_page();
+ }
++
++#ifdef CONFIG_BCM4704
++static void __init mips32_icache_fill(unsigned long addr, uint nbytes)
++{
++ unsigned long ic_lsize = current_cpu_data.icache.linesz;
++ int i;
++ for (i = 0; i < nbytes; i += ic_lsize)
++ fill_icache_line((addr + i));
++}
++
++/*
++ * This must be run from the cache on 4704A0
++ * so there are no mips core BIU ops in progress
++ * when the PFC is enabled.
++ */
++#define PFC_CR0 0xff400000 /* control reg 0 */
++#define PFC_CR1 0xff400004 /* control reg 1 */
++static void __init enable_pfc(u32 mode)
++{
++ /* write range */
++ *(volatile u32 *)PFC_CR1 = 0xffff0000;
++
++ /* enable */
++ *(volatile u32 *)PFC_CR0 = mode;
++}
++#endif
++
++
++void check_enable_mips_pfc(int val)
++{
++
++#ifdef CONFIG_BCM4704
++ struct cpuinfo_mips *c = &current_cpu_data;
++
++ /* enable prefetch cache */
++ if (((c->processor_id & (PRID_COMP_MASK | PRID_IMP_MASK)) == PRID_IMP_BCM3302)
++ && (read_c0_diag() & (1 << 29))) {
++ mips32_icache_fill((unsigned long) &enable_pfc, 64);
++ enable_pfc(val);
++ }
++#endif
++}
++
++
+diff -urN linux.old/arch/mips/pci/Makefile linux.dev/arch/mips/pci/Makefile
+--- linux.old/arch/mips/pci/Makefile 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/arch/mips/pci/Makefile 2006-10-02 21:19:59.000000000 +0200
+@@ -13,7 +13,9 @@
+ obj-$(CONFIG_MIPS_MSC) += ops-msc.o
+ obj-$(CONFIG_MIPS_NILE4) += ops-nile4.o
+ obj-$(CONFIG_SNI_RM200_PCI) += ops-sni.o
++ifndef CONFIG_BCM947XX
+ obj-y += pci.o
++endif
+ obj-$(CONFIG_PCI_AUTO) += pci_auto.o
+
+ include $(TOPDIR)/Rules.make
+diff -urN linux.old/drivers/char/serial.c linux.dev/drivers/char/serial.c
+--- linux.old/drivers/char/serial.c 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/drivers/char/serial.c 2006-10-02 21:19:59.000000000 +0200
+@@ -444,6 +444,10 @@
+ return inb(info->port+1);
+ #endif
+ case SERIAL_IO_MEM:
++#ifdef CONFIG_BCM4310
++ readb((unsigned long) info->iomem_base +
++ (UART_SCR<<info->iomem_reg_shift));
++#endif
+ return readb((unsigned long) info->iomem_base +
+ (offset<<info->iomem_reg_shift));
+ default:
+@@ -464,6 +468,9 @@
+ case SERIAL_IO_MEM:
+ writeb(value, (unsigned long) info->iomem_base +
+ (offset<<info->iomem_reg_shift));
++#ifdef CONFIG_BCM4704
++ *((volatile unsigned int *) KSEG1ADDR(0x18000000));
++#endif
+ break;
+ default:
+ outb(value, info->port+offset);
+@@ -1728,7 +1735,7 @@
+ /* Special case since 134 is really 134.5 */
+ quot = (2*baud_base / 269);
+ else if (baud)
+- quot = baud_base / baud;
++ quot = (baud_base + (baud / 2)) / baud;
+ }
+ /* If the quotient is zero refuse the change */
+ if (!quot && old_termios) {
+@@ -1745,12 +1752,12 @@
+ /* Special case since 134 is really 134.5 */
+ quot = (2*baud_base / 269);
+ else if (baud)
+- quot = baud_base / baud;
++ quot = (baud_base + (baud / 2)) / baud;
+ }
+ }
+ /* As a last resort, if the quotient is zero, default to 9600 bps */
+ if (!quot)
+- quot = baud_base / 9600;
++ quot = (baud_base + 4800) / 9600;
+ /*
+ * Work around a bug in the Oxford Semiconductor 952 rev B
+ * chip which causes it to seriously miscalculate baud rates
+@@ -5994,6 +6001,13 @@
+ * Divisor, bytesize and parity
+ */
+ state = rs_table + co->index;
++ /*
++ * Safe guard: state structure must have been initialized
++ */
++ if (state->iomem_base == NULL) {
++ printk("!unable to setup serial console!\n");
++ return -1;
++ }
+ if (doflow)
+ state->flags |= ASYNC_CONS_FLOW;
+ info = &async_sercons;
+@@ -6007,7 +6021,7 @@
+ info->io_type = state->io_type;
+ info->iomem_base = state->iomem_base;
+ info->iomem_reg_shift = state->iomem_reg_shift;
+- quot = state->baud_base / baud;
++ quot = (state->baud_base + (baud / 2)) / baud;
+ cval = cflag & (CSIZE | CSTOPB);
+ #if defined(__powerpc__) || defined(__alpha__)
+ cval >>= 8;
+diff -urN linux.old/drivers/net/Makefile linux.dev/drivers/net/Makefile
+--- linux.old/drivers/net/Makefile 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/drivers/net/Makefile 2006-10-02 21:19:59.000000000 +0200
+@@ -3,6 +3,8 @@
+ # Makefile for the Linux network (ethercard) device drivers.
+ #
+
++EXTRA_CFLAGS := -I$(TOPDIR)/arch/mips/bcm947xx/include
++
+ obj-y :=
+ obj-m :=
+ obj-n :=
+diff -urN linux.old/drivers/parport/Config.in linux.dev/drivers/parport/Config.in
+--- linux.old/drivers/parport/Config.in 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/drivers/parport/Config.in 2006-10-02 21:19:59.000000000 +0200
+@@ -11,6 +11,7 @@
+ tristate 'Parallel port support' CONFIG_PARPORT
+ if [ "$CONFIG_PARPORT" != "n" ]; then
+ dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
++ dep_tristate ' Asus WL500g parallel port' CONFIG_PARPORT_SPLINK $CONFIG_PARPORT
+ if [ "$CONFIG_PARPORT_PC" != "n" -a "$CONFIG_SERIAL" != "n" ]; then
+ if [ "$CONFIG_SERIAL" = "m" ]; then
+ define_tristate CONFIG_PARPORT_PC_CML1 m
+diff -urN linux.old/drivers/parport/Makefile linux.dev/drivers/parport/Makefile
+--- linux.old/drivers/parport/Makefile 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/drivers/parport/Makefile 2006-10-02 21:19:59.000000000 +0200
+@@ -22,6 +22,7 @@
+
+ obj-$(CONFIG_PARPORT) += parport.o
+ obj-$(CONFIG_PARPORT_PC) += parport_pc.o
++obj-$(CONFIG_PARPORT_SPLINK) += parport_splink.o
+ obj-$(CONFIG_PARPORT_PC_PCMCIA) += parport_cs.o
+ obj-$(CONFIG_PARPORT_AMIGA) += parport_amiga.o
+ obj-$(CONFIG_PARPORT_MFC3) += parport_mfc3.o
+diff -urN linux.old/drivers/parport/parport_splink.c linux.dev/drivers/parport/parport_splink.c
+--- linux.old/drivers/parport/parport_splink.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/parport/parport_splink.c 2006-10-02 21:19:59.000000000 +0200
+@@ -0,0 +1,345 @@
++/* Low-level parallel port routines for the ASUS WL-500g built-in port
++ *
++ * Author: Nuno Grilo <nuno.grilo@netcabo.pt>
++ * Based on parport_pc source
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/parport.h>
++#include <linux/parport_pc.h>
++
++#define SPLINK_ADDRESS 0xBF800010
++
++#undef DEBUG
++
++#ifdef DEBUG
++#define DPRINTK printk
++#else
++#define DPRINTK(stuff...)
++#endif
++
++
++/* __parport_splink_frob_control differs from parport_splink_frob_control in that
++ * it doesn't do any extra masking. */
++static __inline__ unsigned char __parport_splink_frob_control (struct parport *p,
++ unsigned char mask,
++ unsigned char val)
++{
++ struct parport_pc_private *priv = p->physport->private_data;
++ unsigned char *io = (unsigned char *) p->base;
++ unsigned char ctr = priv->ctr;
++#ifdef DEBUG_PARPORT
++ printk (KERN_DEBUG
++ "__parport_splink_frob_control(%02x,%02x): %02x -> %02x\n",
++ mask, val, ctr, ((ctr & ~mask) ^ val) & priv->ctr_writable);
++#endif
++ ctr = (ctr & ~mask) ^ val;
++ ctr &= priv->ctr_writable; /* only write writable bits. */
++ *(io+2) = ctr;
++ priv->ctr = ctr; /* Update soft copy */
++ return ctr;
++}
++
++
++
++static void parport_splink_data_forward (struct parport *p)
++{
++ DPRINTK(KERN_DEBUG "parport_splink: parport_data_forward called\n");
++ __parport_splink_frob_control (p, 0x20, 0);
++}
++
++static void parport_splink_data_reverse (struct parport *p)
++{
++ DPRINTK(KERN_DEBUG "parport_splink: parport_data_forward called\n");
++ __parport_splink_frob_control (p, 0x20, 0x20);
++}
++
++/*
++static void parport_splink_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++ DPRINTK(KERN_DEBUG "parport_splink: IRQ handler called\n");
++ parport_generic_irq(irq, (struct parport *) dev_id, regs);
++}
++*/
++
++static void parport_splink_enable_irq(struct parport *p)
++{
++ DPRINTK(KERN_DEBUG "parport_splink: parport_splink_enable_irq called\n");
++ __parport_splink_frob_control (p, 0x10, 0x10);
++}
++
++static void parport_splink_disable_irq(struct parport *p)
++{
++ DPRINTK(KERN_DEBUG "parport_splink: parport_splink_disable_irq called\n");
++ __parport_splink_frob_control (p, 0x10, 0);
++}
++
++static void parport_splink_init_state(struct pardevice *dev, struct parport_state *s)
++{
++ DPRINTK(KERN_DEBUG "parport_splink: parport_splink_init_state called\n");
++ s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
++ if (dev->irq_func &&
++ dev->port->irq != PARPORT_IRQ_NONE)
++ /* Set ackIntEn */
++ s->u.pc.ctr |= 0x10;
++}
++
++static void parport_splink_save_state(struct parport *p, struct parport_state *s)
++{
++ const struct parport_pc_private *priv = p->physport->private_data;
++ DPRINTK(KERN_DEBUG "parport_splink: parport_splink_save_state called\n");
++ s->u.pc.ctr = priv->ctr;
++}
++
++static void parport_splink_restore_state(struct parport *p, struct parport_state *s)
++{
++ struct parport_pc_private *priv = p->physport->private_data;
++ unsigned char *io = (unsigned char *) p->base;
++ unsigned char ctr = s->u.pc.ctr;
++
++ DPRINTK(KERN_DEBUG "parport_splink: parport_splink_restore_state called\n");
++ *(io+2) = ctr;
++ priv->ctr = ctr;
++}
++
++static void parport_splink_setup_interrupt(void) {
++ return;
++}
++
++static void parport_splink_write_data(struct parport *p, unsigned char d) {
++ DPRINTK(KERN_DEBUG "parport_splink: write data called\n");
++ unsigned char *io = (unsigned char *) p->base;
++ *io = d;
++}
++
++static unsigned char parport_splink_read_data(struct parport *p) {
++ DPRINTK(KERN_DEBUG "parport_splink: read data called\n");
++ unsigned char *io = (unsigned char *) p->base;
++ return *io;
++}
++
++static void parport_splink_write_control(struct parport *p, unsigned char d)
++{
++ const unsigned char wm = (PARPORT_CONTROL_STROBE |
++ PARPORT_CONTROL_AUTOFD |
++ PARPORT_CONTROL_INIT |
++ PARPORT_CONTROL_SELECT);
++
++ DPRINTK(KERN_DEBUG "parport_splink: write control called\n");
++ /* Take this out when drivers have adapted to the newer interface. */
++ if (d & 0x20) {
++ printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
++ p->name, p->cad->name);
++ parport_splink_data_reverse (p);
++ }
++
++ __parport_splink_frob_control (p, wm, d & wm);
++}
++
++static unsigned char parport_splink_read_control(struct parport *p)
++{
++ const unsigned char wm = (PARPORT_CONTROL_STROBE |
++ PARPORT_CONTROL_AUTOFD |
++ PARPORT_CONTROL_INIT |
++ PARPORT_CONTROL_SELECT);
++ DPRINTK(KERN_DEBUG "parport_splink: read control called\n");
++ const struct parport_pc_private *priv = p->physport->private_data;
++ return priv->ctr & wm; /* Use soft copy */
++}
++
++static unsigned char parport_splink_frob_control (struct parport *p, unsigned char mask,
++ unsigned char val)
++{
++ const unsigned char wm = (PARPORT_CONTROL_STROBE |
++ PARPORT_CONTROL_AUTOFD |
++ PARPORT_CONTROL_INIT |
++ PARPORT_CONTROL_SELECT);
++
++ DPRINTK(KERN_DEBUG "parport_splink: frob control called\n");
++ /* Take this out when drivers have adapted to the newer interface. */
++ if (mask & 0x20) {
++ printk (KERN_DEBUG "%s (%s): use data_%s for this!\n",
++ p->name, p->cad->name,
++ (val & 0x20) ? "reverse" : "forward");
++ if (val & 0x20)
++ parport_splink_data_reverse (p);
++ else
++ parport_splink_data_forward (p);
++ }
++
++ /* Restrict mask and val to control lines. */
++ mask &= wm;
++ val &= wm;
++
++ return __parport_splink_frob_control (p, mask, val);
++}
++
++static unsigned char parport_splink_read_status(struct parport *p)
++{
++ DPRINTK(KERN_DEBUG "parport_splink: read status called\n");
++ unsigned char *io = (unsigned char *) p->base;
++ return *(io+1);
++}
++
++static void parport_splink_inc_use_count(void)
++{
++#ifdef MODULE
++ MOD_INC_USE_COUNT;
++#endif
++}
++
++static void parport_splink_dec_use_count(void)
++{
++#ifdef MODULE
++ MOD_DEC_USE_COUNT;
++#endif
++}
++
++static struct parport_operations parport_splink_ops =
++{
++ parport_splink_write_data,
++ parport_splink_read_data,
++
++ parport_splink_write_control,
++ parport_splink_read_control,
++ parport_splink_frob_control,
++
++ parport_splink_read_status,
++
++ parport_splink_enable_irq,
++ parport_splink_disable_irq,
++
++ parport_splink_data_forward,
++ parport_splink_data_reverse,
++
++ parport_splink_init_state,
++ parport_splink_save_state,
++ parport_splink_restore_state,
++
++ parport_splink_inc_use_count,
++ parport_splink_dec_use_count,
++
++ parport_ieee1284_epp_write_data,
++ parport_ieee1284_epp_read_data,
++ parport_ieee1284_epp_write_addr,
++ parport_ieee1284_epp_read_addr,
++
++ parport_ieee1284_ecp_write_data,
++ parport_ieee1284_ecp_read_data,
++ parport_ieee1284_ecp_write_addr,
++
++ parport_ieee1284_write_compat,
++ parport_ieee1284_read_nibble,
++ parport_ieee1284_read_byte,
++};
++
++/* --- Initialisation code -------------------------------- */
++
++static struct parport *parport_splink_probe_port (unsigned long int base)
++{
++ struct parport_pc_private *priv;
++ struct parport_operations *ops;
++ struct parport *p;
++
++ if (check_mem_region(base, 3)) {
++ printk (KERN_DEBUG "parport (0x%lx): iomem region not available\n", base);
++ return NULL;
++ }
++ priv = kmalloc (sizeof (struct parport_pc_private), GFP_KERNEL);
++ if (!priv) {
++ printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
++ return NULL;
++ }
++ ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL);
++ if (!ops) {
++ printk (KERN_DEBUG "parport (0x%lx): no memory for ops!\n",
++ base);
++ kfree (priv);
++ return NULL;
++ }
++ memcpy (ops, &parport_splink_ops, sizeof (struct parport_operations));
++ priv->ctr = 0xc;
++ priv->ctr_writable = 0xff;
++
++ if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
++ PARPORT_DMA_NONE, ops))) {
++ printk (KERN_DEBUG "parport (0x%lx): registration failed!\n",
++ base);
++ kfree (priv);
++ kfree (ops);
++ return NULL;
++ }
++
++ p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT;
++ p->size = (p->modes & PARPORT_MODE_EPP)?8:3;
++ p->private_data = priv;
++
++ parport_proc_register(p);
++ request_mem_region (p->base, 3, p->name);
++
++ /* Done probing. Now put the port into a sensible start-up state. */
++ parport_splink_write_data(p, 0);
++ parport_splink_data_forward (p);
++
++ /* Now that we've told the sharing engine about the port, and
++ found out its characteristics, let the high-level drivers
++ know about it. */
++ parport_announce_port (p);
++
++ DPRINTK(KERN_DEBUG "parport (0x%lx): init ok!\n",
++ base);
++ return p;
++}
++
++static void parport_splink_unregister_port(struct parport *p) {
++ struct parport_pc_private *priv = p->private_data;
++ struct parport_operations *ops = p->ops;
++
++ if (p->irq != PARPORT_IRQ_NONE)
++ free_irq(p->irq, p);
++ release_mem_region(p->base, 3);
++ parport_proc_unregister(p);
++ kfree (priv);
++ parport_unregister_port(p);
++ kfree (ops);
++}
++
++
++int parport_splink_init(void)
++{
++ int ret;
++
++ DPRINTK(KERN_DEBUG "parport_splink init called\n");
++ parport_splink_setup_interrupt();
++ ret = !parport_splink_probe_port(SPLINK_ADDRESS);
++
++ return ret;
++}
++
++void parport_splink_cleanup(void) {
++ struct parport *p = parport_enumerate(), *tmp;
++ DPRINTK(KERN_DEBUG "parport_splink cleanup called\n");
++ if (p->size) {
++ if (p->modes & PARPORT_MODE_PCSPP) {
++ while(p) {
++ tmp = p->next;
++ parport_splink_unregister_port(p);
++ p = tmp;
++ }
++ }
++ }
++}
++
++MODULE_AUTHOR("Nuno Grilo <nuno.grilo@netcabo.pt>");
++MODULE_DESCRIPTION("Parport Driver for ASUS WL-500g router builtin Port");
++MODULE_SUPPORTED_DEVICE("ASUS WL-500g builtin Parallel Port");
++MODULE_LICENSE("GPL");
++
++module_init(parport_splink_init)
++module_exit(parport_splink_cleanup)
++
+diff -urN linux.old/include/asm-mips/bootinfo.h linux.dev/include/asm-mips/bootinfo.h
+--- linux.old/include/asm-mips/bootinfo.h 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/include/asm-mips/bootinfo.h 2006-10-02 21:19:59.000000000 +0200
+@@ -37,6 +37,7 @@
+ #define MACH_GROUP_HP_LJ 20 /* Hewlett Packard LaserJet */
+ #define MACH_GROUP_LASAT 21
+ #define MACH_GROUP_TITAN 22 /* PMC-Sierra Titan */
++#define MACH_GROUP_BRCM 23 /* Broadcom */
+
+ /*
+ * Valid machtype values for group unknown (low order halfword of mips_machtype)
+@@ -197,6 +198,15 @@
+ #define MACH_TANBAC_TB0229 7 /* TANBAC TB0229 (VR4131DIMM) */
+
+ /*
++ * Valid machtypes for group Broadcom
++ */
++#define MACH_BCM93725 0
++#define MACH_BCM93725_VJ 1
++#define MACH_BCM93730 2
++#define MACH_BCM947XX 3
++#define MACH_BCM933XX 4
++
++/*
+ * Valid machtype for group TITAN
+ */
+ #define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */
+diff -urN linux.old/include/asm-mips/cpu.h linux.dev/include/asm-mips/cpu.h
+--- linux.old/include/asm-mips/cpu.h 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/include/asm-mips/cpu.h 2006-10-02 21:19:59.000000000 +0200
+@@ -22,6 +22,11 @@
+ spec.
+ */
+
++#define PRID_COPT_MASK 0xff000000
++#define PRID_COMP_MASK 0x00ff0000
++#define PRID_IMP_MASK 0x0000ff00
++#define PRID_REV_MASK 0x000000ff
++
+ #define PRID_COMP_LEGACY 0x000000
+ #define PRID_COMP_MIPS 0x010000
+ #define PRID_COMP_BROADCOM 0x020000
+@@ -58,6 +63,7 @@
+ #define PRID_IMP_RM7000 0x2700
+ #define PRID_IMP_NEVADA 0x2800 /* RM5260 ??? */
+ #define PRID_IMP_RM9000 0x3400
++#define PRID_IMP_BCM4710 0x4000
+ #define PRID_IMP_R5432 0x5400
+ #define PRID_IMP_R5500 0x5500
+ #define PRID_IMP_4KC 0x8000
+@@ -66,10 +72,16 @@
+ #define PRID_IMP_4KEC 0x8400
+ #define PRID_IMP_4KSC 0x8600
+ #define PRID_IMP_25KF 0x8800
++#define PRID_IMP_BCM3302 0x9000
++#define PRID_IMP_BCM3303 0x9100
+ #define PRID_IMP_24K 0x9300
+
+ #define PRID_IMP_UNKNOWN 0xff00
+
++#define BCM330X(id) \
++ (((id & (PRID_COMP_MASK | PRID_IMP_MASK)) == (PRID_COMP_BROADCOM | PRID_IMP_BCM3302)) \
++ || ((id & (PRID_COMP_MASK | PRID_IMP_MASK)) == (PRID_COMP_BROADCOM | PRID_IMP_BCM3303)))
++
+ /*
+ * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE
+ */
+@@ -174,7 +186,9 @@
+ #define CPU_AU1550 57
+ #define CPU_24K 58
+ #define CPU_AU1200 59
+-#define CPU_LAST 59
++#define CPU_BCM4710 60
++#define CPU_BCM3302 61
++#define CPU_LAST 61
+
+ /*
+ * ISA Level encodings
+diff -urN linux.old/include/asm-mips/r4kcache.h linux.dev/include/asm-mips/r4kcache.h
+--- linux.old/include/asm-mips/r4kcache.h 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/include/asm-mips/r4kcache.h 2006-10-02 21:19:59.000000000 +0200
+@@ -658,4 +658,17 @@
+ cache128_unroll32(addr|ws,Index_Writeback_Inv_SD);
+ }
+
++extern inline void fill_icache_line(unsigned long addr)
++{
++ __asm__ __volatile__(
++ ".set noreorder\n\t"
++ ".set mips3\n\t"
++ "cache %1, (%0)\n\t"
++ ".set mips0\n\t"
++ ".set reorder"
++ :
++ : "r" (addr),
++ "i" (Fill));
++}
++
+ #endif /* __ASM_R4KCACHE_H */
+diff -urN linux.old/include/asm-mips/serial.h linux.dev/include/asm-mips/serial.h
+--- linux.old/include/asm-mips/serial.h 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/include/asm-mips/serial.h 2006-10-02 21:19:59.000000000 +0200
+@@ -223,6 +223,13 @@
+ #define TXX927_SERIAL_PORT_DEFNS
+ #endif
+
++#ifdef CONFIG_BCM947XX
++/* reserve 4 ports to be configured at runtime */
++#define BCM947XX_SERIAL_PORT_DEFNS { 0, }, { 0, }, { 0, }, { 0, },
++#else
++#define BCM947XX_SERIAL_PORT_DEFNS
++#endif
++
+ #ifdef CONFIG_HAVE_STD_PC_SERIAL_PORT
+ #define STD_SERIAL_PORT_DEFNS \
+ /* UART CLK PORT IRQ FLAGS */ \
+@@ -470,6 +477,7 @@
+ #define SERIAL_PORT_DFNS \
+ ATLAS_SERIAL_PORT_DEFNS \
+ AU1000_SERIAL_PORT_DEFNS \
++ BCM947XX_SERIAL_PORT_DEFNS \
+ COBALT_SERIAL_PORT_DEFNS \
+ DDB5477_SERIAL_PORT_DEFNS \
+ EV96100_SERIAL_PORT_DEFNS \
+diff -urN linux.old/init/do_mounts.c linux.dev/init/do_mounts.c
+--- linux.old/init/do_mounts.c 2006-10-02 21:23:10.000000000 +0200
++++ linux.dev/init/do_mounts.c 2006-10-02 21:19:59.000000000 +0200
+@@ -254,7 +254,13 @@
+ { "ftlb", 0x2c08 },
+ { "ftlc", 0x2c10 },
+ { "ftld", 0x2c18 },
++#if defined(CONFIG_MTD_BLOCK) || defined(CONFIG_MTD_BLOCK_RO)
+ { "mtdblock", 0x1f00 },
++ { "mtdblock0",0x1f00 },
++ { "mtdblock1",0x1f01 },
++ { "mtdblock2",0x1f02 },
++ { "mtdblock3",0x1f03 },
++#endif
+ { "nb", 0x2b00 },
+ { NULL, 0 }
+ };
diff --git a/target/linux/brcm-2.4/patches/002-wl_fix.patch b/target/linux/brcm-2.4/patches/002-wl_fix.patch
new file mode 100644
index 0000000..95044b6
--- /dev/null
+++ b/target/linux/brcm-2.4/patches/002-wl_fix.patch
@@ -0,0 +1,348 @@
+diff -urN linux.old/include/linux/netdevice.h linux.dev/include/linux/netdevice.h
+--- linux.old/include/linux/netdevice.h 2006-03-19 06:32:22.000000000 +0100
++++ linux.dev/include/linux/netdevice.h 2006-03-19 06:33:21.000000000 +0100
+@@ -296,10 +296,7 @@
+ /* List of functions to handle Wireless Extensions (instead of ioctl).
+ * See <net/iw_handler.h> for details. Jean II */
+ const struct iw_handler_def * wireless_handlers;
+- /* Instance data managed by the core of Wireless Extensions. */
+- struct iw_public_data * wireless_data;
+
+- struct ethtool_ops *ethtool_ops;
+
+ /*
+ * This marks the end of the "visible" part of the structure. All
+@@ -354,8 +351,8 @@
+
+ struct Qdisc *qdisc;
+ struct Qdisc *qdisc_sleeping;
++ struct Qdisc *qdisc_list;
+ struct Qdisc *qdisc_ingress;
+- struct list_head qdisc_list;
+ unsigned long tx_queue_len; /* Max frames per queue allowed */
+
+ /* hard_start_xmit synchronizer */
+@@ -455,6 +452,10 @@
+ /* this will get initialized at each interface type init routine */
+ struct divert_blk *divert;
+ #endif /* CONFIG_NET_DIVERT */
++ struct ethtool_ops *ethtool_ops;
++
++ /* Instance data managed by the core of Wireless Extensions. */
++ struct iw_public_data * wireless_data;
+ };
+
+ /* 2.6 compatibility */
+diff -urN linux.old/include/linux/skbuff.h linux.dev/include/linux/skbuff.h
+--- linux.old/include/linux/skbuff.h 2006-03-19 06:32:22.000000000 +0100
++++ linux.dev/include/linux/skbuff.h 2006-03-19 06:29:41.000000000 +0100
+@@ -138,10 +138,6 @@
+ struct sock *sk; /* Socket we are owned by */
+ struct timeval stamp; /* Time we arrived */
+ struct net_device *dev; /* Device we arrived on/are leaving by */
+- struct net_device *real_dev; /* For support of point to point protocols
+- (e.g. 802.3ad) over bonding, we must save the
+- physical device that got the packet before
+- replacing skb->dev with the virtual device. */
+
+ /* Transport layer header */
+ union
+@@ -225,6 +221,10 @@
+ #if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
+ struct nf_info *nf_info;
+ #endif
++ struct net_device *real_dev; /* For support of point to point protocols
++ (e.g. 802.3ad) over bonding, we must save the
++ physical device that got the packet before
++ replacing skb->dev with the virtual device. */
+ };
+
+ #ifdef __KERNEL__
+diff -urN linux.old/include/net/pkt_sched.h linux.dev/include/net/pkt_sched.h
+--- linux.old/include/net/pkt_sched.h 2006-03-19 06:32:22.000000000 +0100
++++ linux.dev/include/net/pkt_sched.h 2006-03-19 06:29:41.000000000 +0100
+@@ -63,8 +63,11 @@
+ int (*enqueue)(struct sk_buff *, struct Qdisc *);
+ struct sk_buff * (*dequeue)(struct Qdisc *);
+ int (*requeue)(struct sk_buff *, struct Qdisc *);
+- unsigned int (*drop)(struct Qdisc *);
+-
++#ifdef CONFIG_BCM4710
++ int (*drop)(struct Qdisc *);
++#else
++ unsigned int (*drop)(struct Qdisc *);
++#endif
+ int (*init)(struct Qdisc *, struct rtattr *arg);
+ void (*reset)(struct Qdisc *);
+ void (*destroy)(struct Qdisc *);
+@@ -84,12 +87,19 @@
+ #define TCQ_F_THROTTLED 2
+ #define TCQ_F_INGRESS 4
+ struct Qdisc_ops *ops;
++#ifdef CONFIG_BCM4710
++ struct Qdisc *next;
++#endif
+ u32 handle;
+- u32 parent;
++#ifndef CONFIG_BCM4710
++ u32 parent;
++#endif
+ atomic_t refcnt;
+ struct sk_buff_head q;
+ struct net_device *dev;
+- struct list_head list;
++#ifndef CONFIG_BCM4710
++ struct list_head list;
++#endif
+
+ struct tc_stats stats;
+ int (*reshape_fail)(struct sk_buff *skb, struct Qdisc *q);
+diff -urN linux.old/net/core/Makefile linux.dev/net/core/Makefile
+--- linux.old/net/core/Makefile 2006-03-19 06:32:22.000000000 +0100
++++ linux.dev/net/core/Makefile 2006-03-19 06:29:41.000000000 +0100
+@@ -9,7 +9,11 @@
+
+ O_TARGET := core.o
+
++ifeq ($(CONFIG_BCM4710),y)
++export-objs := netfilter.o profile.o neighbour.o
++else
+ export-objs := netfilter.o profile.o ethtool.o neighbour.o
++endif
+
+ obj-y := sock.o skbuff.o iovec.o datagram.o scm.o
+
+@@ -21,8 +25,13 @@
+
+ obj-$(CONFIG_FILTER) += filter.o
+
++ifeq ($(CONFIG_BCM4710),y)
++obj-$(CONFIG_NET) += dev.o dev_mcast.o dst.o neighbour.o \
++ rtnetlink.o utils.o
++else
+ obj-$(CONFIG_NET) += dev.o ethtool.o dev_mcast.o dst.o neighbour.o \
+ rtnetlink.o utils.o
++endif
+
+ obj-$(CONFIG_NETFILTER) += netfilter.o
+ obj-$(CONFIG_NET_DIVERT) += dv.o
+diff -urN linux.old/net/core/dev.c linux.dev/net/core/dev.c
+--- linux.old/net/core/dev.c 2006-03-19 06:32:22.000000000 +0100
++++ linux.dev/net/core/dev.c 2006-03-19 06:29:41.000000000 +0100
+@@ -2232,6 +2232,7 @@
+ cmd == SIOCGMIIPHY ||
+ cmd == SIOCGMIIREG ||
+ cmd == SIOCSMIIREG ||
++ cmd == SIOCETHTOOL ||
+ cmd == SIOCWANDEV) {
+ if (dev->do_ioctl) {
+ if (!netif_device_present(dev))
+@@ -2324,6 +2325,7 @@
+ }
+ return ret;
+
++#ifndef CONFIG_BCM4710
+ case SIOCETHTOOL:
+ dev_load(ifr.ifr_name);
+ rtnl_lock();
+@@ -2337,6 +2339,7 @@
+ ret = -EFAULT;
+ }
+ return ret;
++#endif
+
+ /*
+ * These ioctl calls:
+@@ -2412,6 +2415,7 @@
+
+ default:
+ if (cmd == SIOCWANDEV ||
++ (cmd == SIOCETHTOOL) ||
+ (cmd >= SIOCDEVPRIVATE &&
+ cmd <= SIOCDEVPRIVATE + 15)) {
+ dev_load(ifr.ifr_name);
+diff -urN linux.old/net/sched/sch_api.c linux.dev/net/sched/sch_api.c
+--- linux.old/net/sched/sch_api.c 2006-03-19 06:32:22.000000000 +0100
++++ linux.dev/net/sched/sch_api.c 2006-03-19 06:29:41.000000000 +0100
+@@ -194,11 +194,12 @@
+ {
+ struct Qdisc *q;
+
+- list_for_each_entry(q, &dev->qdisc_list, list) {
++ for (q = dev->qdisc_list; q; q = q->next) {
+ if (q->handle == handle)
+ return q;
+ }
+ return NULL;
++
+ }
+
+ struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid)
+@@ -371,8 +372,6 @@
+ unsigned long cl = cops->get(parent, classid);
+ if (cl) {
+ err = cops->graft(parent, cl, new, old);
+- if (new)
+- new->parent = classid;
+ cops->put(parent, cl);
+ }
+ }
+@@ -427,7 +426,6 @@
+
+ memset(sch, 0, size);
+
+- INIT_LIST_HEAD(&sch->list);
+ skb_queue_head_init(&sch->q);
+
+ if (handle == TC_H_INGRESS)
+@@ -453,7 +451,8 @@
+
+ if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS-1])) == 0) {
+ write_lock(&qdisc_tree_lock);
+- list_add_tail(&sch->list, &dev->qdisc_list);
++ sch->next = dev->qdisc_list;
++ dev->qdisc_list = sch;
+ write_unlock(&qdisc_tree_lock);
+ #ifdef CONFIG_NET_ESTIMATOR
+ if (tca[TCA_RATE-1])
+@@ -808,19 +807,16 @@
+ if (idx > s_idx)
+ s_q_idx = 0;
+ read_lock(&qdisc_tree_lock);
+- q_idx = 0;
+- list_for_each_entry(q, &dev->qdisc_list, list) {
+- if (q_idx < s_q_idx) {
+- q_idx++;
+- continue;
+- }
+- if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid,
+- cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) {
+- read_unlock(&qdisc_tree_lock);
+- goto done;
+- }
+- q_idx++;
+- }
++ for (q = dev->qdisc_list, q_idx = 0; q;
++ q = q->next, q_idx++) {
++ if (q_idx < s_q_idx)
++ continue;
++ if (tc_fill_qdisc(skb, q, 0, NETLINK_CB(cb->skb).pid,
++ cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) {
++ read_unlock(&qdisc_tree_lock);
++ goto done;
++ }
++ }
+ read_unlock(&qdisc_tree_lock);
+ }
+
+@@ -1033,27 +1029,24 @@
+ t = 0;
+
+ read_lock(&qdisc_tree_lock);
+- list_for_each_entry(q, &dev->qdisc_list, list) {
+- if (t < s_t || !q->ops->cl_ops ||
+- (tcm->tcm_parent &&
+- TC_H_MAJ(tcm->tcm_parent) != q->handle)) {
+- t++;
+- continue;
+- }
+- if (t > s_t)
+- memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
+- arg.w.fn = qdisc_class_dump;
+- arg.skb = skb;
+- arg.cb = cb;
+- arg.w.stop = 0;
+- arg.w.skip = cb->args[1];
+- arg.w.count = 0;
+- q->ops->cl_ops->walk(q, &arg.w);
+- cb->args[1] = arg.w.count;
+- if (arg.w.stop)
+- break;
+- t++;
+- }
++ for (q=dev->qdisc_list, t=0; q; q = q->next, t++) {
++ if (t < s_t) continue;
++ if (!q->ops->cl_ops) continue;
++ if (tcm->tcm_parent && TC_H_MAJ(tcm->tcm_parent) != q->handle)
++ continue;
++ if (t > s_t)
++ memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
++ arg.w.fn = qdisc_class_dump;
++ arg.skb = skb;
++ arg.cb = cb;
++ arg.w.stop = 0;
++ arg.w.skip = cb->args[1];
++ arg.w.count = 0;
++ q->ops->cl_ops->walk(q, &arg.w);
++ cb->args[1] = arg.w.count;
++ if (arg.w.stop)
++ break;
++ }
+ read_unlock(&qdisc_tree_lock);
+
+ cb->args[0] = t;
+diff -urN linux.old/net/sched/sch_generic.c linux.dev/net/sched/sch_generic.c
+--- linux.old/net/sched/sch_generic.c 2006-03-19 06:32:22.000000000 +0100
++++ linux.dev/net/sched/sch_generic.c 2006-03-19 06:29:41.000000000 +0100
+@@ -399,7 +399,6 @@
+ return NULL;
+ memset(sch, 0, size);
+
+- INIT_LIST_HEAD(&sch->list);
+ skb_queue_head_init(&sch->q);
+ sch->ops = ops;
+ sch->enqueue = ops->enqueue;
+@@ -429,11 +428,22 @@
+ void qdisc_destroy(struct Qdisc *qdisc)
+ {
+ struct Qdisc_ops *ops = qdisc->ops;
++ struct net_device *dev;
+
+ if (qdisc->flags&TCQ_F_BUILTIN ||
+ !atomic_dec_and_test(&qdisc->refcnt))
+ return;
+- list_del(&qdisc->list);
++
++ dev = qdisc->dev;
++ if (dev) {
++ struct Qdisc *q, **qp;
++ for (qp = &qdisc->dev->qdisc_list; (q=*qp) != NULL; qp = &q->next) {
++ if (q == qdisc) {
++ *qp = q->next;
++ break;
++ }
++ }
++ }
+ #ifdef CONFIG_NET_ESTIMATOR
+ qdisc_kill_estimator(&qdisc->stats);
+ #endif
+@@ -462,9 +472,9 @@
+ return;
+ }
+ write_lock(&qdisc_tree_lock);
+- list_add_tail(&qdisc->list, &dev->qdisc_list);
++ qdisc->next = dev->qdisc_list;
++ dev->qdisc_list = qdisc;
+ write_unlock(&qdisc_tree_lock);
+-
+ } else {
+ qdisc = &noqueue_qdisc;
+ }
+@@ -508,7 +518,7 @@
+ dev->qdisc = &noop_qdisc;
+ spin_unlock_bh(&dev->queue_lock);
+ dev->qdisc_sleeping = &noop_qdisc;
+- INIT_LIST_HEAD(&dev->qdisc_list);
++ dev->qdisc_list = NULL;
+ write_unlock(&qdisc_tree_lock);
+
+ dev_watchdog_init(dev);
+@@ -530,7 +540,7 @@
+ qdisc_destroy(qdisc);
+ }
+ #endif
+- BUG_TRAP(list_empty(&dev->qdisc_list));
++ BUG_TRAP(dev->qdisc_list == NULL);
+ BUG_TRAP(!timer_pending(&dev->watchdog_timer));
+ spin_unlock_bh(&dev->queue_lock);
+ write_unlock(&qdisc_tree_lock);
diff --git a/target/linux/brcm-2.4/patches/003-bcm47xx_cache_fixes.patch b/target/linux/brcm-2.4/patches/003-bcm47xx_cache_fixes.patch
new file mode 100644
index 0000000..e971e7f
--- /dev/null
+++ b/target/linux/brcm-2.4/patches/003-bcm47xx_cache_fixes.patch
@@ -0,0 +1,498 @@
+diff -urN linux.old/arch/mips/kernel/entry.S linux.dev/arch/mips/kernel/entry.S
+--- linux.old/arch/mips/kernel/entry.S 2005-07-05 16:46:49.000000000 +0200
++++ linux.dev/arch/mips/kernel/entry.S 2005-07-06 11:23:55.000000000 +0200
+@@ -100,6 +100,10 @@
+ * and R4400 SC and MC versions.
+ */
+ NESTED(except_vec3_generic, 0, sp)
++#ifdef CONFIG_BCM4710
++ nop
++ nop
++#endif
+ #if R5432_CP0_INTERRUPT_WAR
+ mfc0 k0, CP0_INDEX
+ #endif
+diff -urN linux.old/arch/mips/mm/c-r4k.c linux.dev/arch/mips/mm/c-r4k.c
+--- linux.old/arch/mips/mm/c-r4k.c 2005-07-05 16:46:49.000000000 +0200
++++ linux.dev/arch/mips/mm/c-r4k.c 2005-07-06 11:23:55.000000000 +0200
+@@ -14,6 +14,12 @@
+ #include <linux/mm.h>
+ #include <linux/bitops.h>
+
++#ifdef CONFIG_BCM4710
++#include "../bcm947xx/include/typedefs.h"
++#include "../bcm947xx/include/sbconfig.h"
++#include <asm/paccess.h>
++#endif
++
+ #include <asm/bcache.h>
+ #include <asm/bootinfo.h>
+ #include <asm/cacheops.h>
+@@ -40,6 +46,8 @@
+ .bc_inv = (void *)no_sc_noop
+ };
+
++int bcm4710 = 0;
++EXPORT_SYMBOL(bcm4710);
+ struct bcache_ops *bcops = &no_sc_ops;
+
+ #define cpu_is_r4600_v1_x() ((read_c0_prid() & 0xfffffff0) == 0x2010)
+@@ -64,8 +72,10 @@
+ static inline void r4k_blast_dcache_page_setup(void)
+ {
+ unsigned long dc_lsize = current_cpu_data.dcache.linesz;
+-
+- if (dc_lsize == 16)
++
++ if (bcm4710)
++ r4k_blast_dcache_page = blast_dcache_page;
++ else if (dc_lsize == 16)
+ r4k_blast_dcache_page = blast_dcache16_page;
+ else if (dc_lsize == 32)
+ r4k_blast_dcache_page = r4k_blast_dcache_page_dc32;
+@@ -77,7 +87,9 @@
+ {
+ unsigned long dc_lsize = current_cpu_data.dcache.linesz;
+
+- if (dc_lsize == 16)
++ if (bcm4710)
++ r4k_blast_dcache_page_indexed = blast_dcache_page_indexed;
++ else if (dc_lsize == 16)
+ r4k_blast_dcache_page_indexed = blast_dcache16_page_indexed;
+ else if (dc_lsize == 32)
+ r4k_blast_dcache_page_indexed = blast_dcache32_page_indexed;
+@@ -89,7 +101,9 @@
+ {
+ unsigned long dc_lsize = current_cpu_data.dcache.linesz;
+
+- if (dc_lsize == 16)
++ if (bcm4710)
++ r4k_blast_dcache = blast_dcache;
++ else if (dc_lsize == 16)
+ r4k_blast_dcache = blast_dcache16;
+ else if (dc_lsize == 32)
+ r4k_blast_dcache = blast_dcache32;
+@@ -266,6 +280,7 @@
+ r4k_blast_dcache();
+ r4k_blast_icache();
+
++ if (!bcm4710)
+ switch (current_cpu_data.cputype) {
+ case CPU_R4000SC:
+ case CPU_R4000MC:
+@@ -304,10 +319,10 @@
+ * Kludge alert. For obscure reasons R4000SC and R4400SC go nuts if we
+ * only flush the primary caches but R10000 and R12000 behave sane ...
+ */
+- if (current_cpu_data.cputype == CPU_R4000SC ||
++ if (!bcm4710 && (current_cpu_data.cputype == CPU_R4000SC ||
+ current_cpu_data.cputype == CPU_R4000MC ||
+ current_cpu_data.cputype == CPU_R4400SC ||
+- current_cpu_data.cputype == CPU_R4400MC)
++ current_cpu_data.cputype == CPU_R4400MC))
+ r4k_blast_scache();
+ }
+
+@@ -383,12 +398,15 @@
+ unsigned long ic_lsize = current_cpu_data.icache.linesz;
+ unsigned long addr, aend;
+
++ addr = start & ~(dc_lsize - 1);
++ aend = (end - 1) & ~(dc_lsize - 1);
++
+ if (!cpu_has_ic_fills_f_dc) {
+ if (end - start > dcache_size)
+ r4k_blast_dcache();
+ else {
+- addr = start & ~(dc_lsize - 1);
+- aend = (end - 1) & ~(dc_lsize - 1);
++ BCM4710_PROTECTED_FILL_TLB(addr);
++ BCM4710_PROTECTED_FILL_TLB(aend);
+
+ while (1) {
+ /* Hit_Writeback_Inv_D */
+@@ -403,8 +421,6 @@
+ if (end - start > icache_size)
+ r4k_blast_icache();
+ else {
+- addr = start & ~(ic_lsize - 1);
+- aend = (end - 1) & ~(ic_lsize - 1);
+ while (1) {
+ /* Hit_Invalidate_I */
+ protected_flush_icache_line(addr);
+@@ -413,6 +429,9 @@
+ addr += ic_lsize;
+ }
+ }
++
++ if (bcm4710)
++ flush_cache_all();
+ }
+
+ /*
+@@ -443,7 +462,8 @@
+ if (cpu_has_subset_pcaches) {
+ unsigned long addr = (unsigned long) page_address(page);
+
+- r4k_blast_scache_page(addr);
++ if (!bcm4710)
++ r4k_blast_scache_page(addr);
+ ClearPageDcacheDirty(page);
+
+ return;
+@@ -451,6 +471,7 @@
+
+ if (!cpu_has_ic_fills_f_dc) {
+ unsigned long addr = (unsigned long) page_address(page);
++
+ r4k_blast_dcache_page(addr);
+ ClearPageDcacheDirty(page);
+ }
+@@ -477,7 +498,7 @@
+ /* Catch bad driver code */
+ BUG_ON(size == 0);
+
+- if (cpu_has_subset_pcaches) {
++ if (!bcm4710 && cpu_has_subset_pcaches) {
+ unsigned long sc_lsize = current_cpu_data.scache.linesz;
+
+ if (size >= scache_size) {
+@@ -509,6 +530,8 @@
+ R4600_HIT_CACHEOP_WAR_IMPL;
+ a = addr & ~(dc_lsize - 1);
+ end = (addr + size - 1) & ~(dc_lsize - 1);
++ BCM4710_FILL_TLB(a);
++ BCM4710_FILL_TLB(end);
+ while (1) {
+ flush_dcache_line(a); /* Hit_Writeback_Inv_D */
+ if (a == end)
+@@ -527,7 +550,7 @@
+ /* Catch bad driver code */
+ BUG_ON(size == 0);
+
+- if (cpu_has_subset_pcaches) {
++ if (!bcm4710 && (cpu_has_subset_pcaches)) {
+ unsigned long sc_lsize = current_cpu_data.scache.linesz;
+
+ if (size >= scache_size) {
+@@ -554,6 +577,8 @@
+ R4600_HIT_CACHEOP_WAR_IMPL;
+ a = addr & ~(dc_lsize - 1);
+ end = (addr + size - 1) & ~(dc_lsize - 1);
++ BCM4710_FILL_TLB(a);
++ BCM4710_FILL_TLB(end);
+ while (1) {
+ flush_dcache_line(a); /* Hit_Writeback_Inv_D */
+ if (a == end)
+@@ -577,6 +602,8 @@
+ unsigned long dc_lsize = current_cpu_data.dcache.linesz;
+
+ R4600_HIT_CACHEOP_WAR_IMPL;
++ BCM4710_PROTECTED_FILL_TLB(addr);
++ BCM4710_PROTECTED_FILL_TLB(addr + 4);
+ protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
+ protected_flush_icache_line(addr & ~(ic_lsize - 1));
+ if (MIPS4K_ICACHE_REFILL_WAR) {
+@@ -986,10 +1013,12 @@
+ case CPU_R4000MC:
+ case CPU_R4400SC:
+ case CPU_R4400MC:
+- probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache));
+- sc_present = probe_scache_kseg1(config);
+- if (sc_present)
+- c->options |= MIPS_CPU_CACHE_CDEX_S;
++ if (!bcm4710) {
++ probe_scache_kseg1 = (probe_func_t) (KSEG1ADDR(&probe_scache));
++ sc_present = probe_scache_kseg1(config);
++ if (sc_present)
++ c->options |= MIPS_CPU_CACHE_CDEX_S;
++ }
+ break;
+
+ case CPU_R10000:
+@@ -1041,6 +1070,19 @@
+ static inline void coherency_setup(void)
+ {
+ change_c0_config(CONF_CM_CMASK, CONF_CM_DEFAULT);
++
++#if defined(CONFIG_BCM4310) || defined(CONFIG_BCM4704) || defined(CONFIG_BCM5365)
++ if (BCM330X(current_cpu_data.processor_id)) {
++ uint32 cm;
++
++ cm = read_c0_diag();
++ /* Enable icache */
++ cm |= (1 << 31);
++ /* Enable dcache */
++ cm |= (1 << 30);
++ write_c0_diag(cm);
++ }
++#endif
+
+ /*
+ * c0_status.cu=0 specifies that updates by the sc instruction use
+@@ -1073,6 +1115,12 @@
+ memcpy((void *)(KSEG0 + 0x100), &except_vec2_generic, 0x80);
+ memcpy((void *)(KSEG1 + 0x100), &except_vec2_generic, 0x80);
+
++ if (current_cpu_data.cputype == CPU_BCM4710 && (current_cpu_data.processor_id & PRID_REV_MASK) == 0) {
++ printk("Enabling BCM4710A0 cache workarounds.\n");
++ bcm4710 = 1;
++ } else
++ bcm4710 = 0;
++
+ probe_pcache();
+ setup_scache();
+
+diff -urN linux.old/arch/mips/mm/tlbex-mips32.S linux.dev/arch/mips/mm/tlbex-mips32.S
+--- linux.old/arch/mips/mm/tlbex-mips32.S 2005-07-05 16:46:49.000000000 +0200
++++ linux.dev/arch/mips/mm/tlbex-mips32.S 2005-07-06 11:23:56.000000000 +0200
+@@ -90,6 +90,9 @@
+ .set noat
+ LEAF(except_vec0_r4000)
+ .set mips3
++#ifdef CONFIG_BCM4704
++ nop
++#endif
+ #ifdef CONFIG_SMP
+ mfc0 k1, CP0_CONTEXT
+ la k0, pgd_current
+diff -urN linux.old/include/asm-mips/r4kcache.h linux.dev/include/asm-mips/r4kcache.h
+--- linux.old/include/asm-mips/r4kcache.h 2005-07-05 16:46:49.000000000 +0200
++++ linux.dev/include/asm-mips/r4kcache.h 2005-07-06 12:52:57.000000000 +0200
+@@ -15,6 +15,18 @@
+ #include <asm/asm.h>
+ #include <asm/cacheops.h>
+
++#ifdef CONFIG_BCM4710
++#define BCM4710_DUMMY_RREG() (((sbconfig_t *)(KSEG1ADDR(SB_ENUM_BASE + SBCONFIGOFF)))->sbimstate)
++
++#define BCM4710_FILL_TLB(addr) (*(volatile unsigned long *)(addr))
++#define BCM4710_PROTECTED_FILL_TLB(addr) ({ unsigned long x; get_dbe(x, (volatile unsigned long *)(addr)); })
++#else
++#define BCM4710_DUMMY_RREG()
++
++#define BCM4710_FILL_TLB(addr)
++#define BCM4710_PROTECTED_FILL_TLB(addr)
++#endif
++
+ #define cache_op(op,addr) \
+ __asm__ __volatile__( \
+ " .set noreorder \n" \
+@@ -27,12 +39,25 @@
+
+ static inline void flush_icache_line_indexed(unsigned long addr)
+ {
+- cache_op(Index_Invalidate_I, addr);
++ unsigned int way;
++ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
++
++ for (way = 0; way < current_cpu_data.dcache.ways; way++) {
++ cache_op(Index_Invalidate_I, addr);
++ addr += ws_inc;
++ }
+ }
+
+ static inline void flush_dcache_line_indexed(unsigned long addr)
+ {
+- cache_op(Index_Writeback_Inv_D, addr);
++ unsigned int way;
++ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
++
++ for (way = 0; way < current_cpu_data.dcache.ways; way++) {
++ BCM4710_DUMMY_RREG();
++ cache_op(Index_Writeback_Inv_D, addr);
++ addr += ws_inc;
++ }
+ }
+
+ static inline void flush_scache_line_indexed(unsigned long addr)
+@@ -47,6 +72,7 @@
+
+ static inline void flush_dcache_line(unsigned long addr)
+ {
++ BCM4710_DUMMY_RREG();
+ cache_op(Hit_Writeback_Inv_D, addr);
+ }
+
+@@ -91,6 +117,7 @@
+ */
+ static inline void protected_writeback_dcache_line(unsigned long addr)
+ {
++ BCM4710_DUMMY_RREG();
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ ".set mips3\n"
+@@ -138,6 +165,62 @@
+ : "r" (base), \
+ "i" (op));
+
++#define cache_unroll(base,op) \
++ __asm__ __volatile__(" \
++ .set noreorder; \
++ .set mips3; \
++ cache %1, (%0); \
++ .set mips0; \
++ .set reorder" \
++ : \
++ : "r" (base), \
++ "i" (op));
++
++
++static inline void blast_dcache(void)
++{
++ unsigned long start = KSEG0;
++ unsigned long dcache_size = current_cpu_data.dcache.waysize * current_cpu_data.dcache.ways;
++ unsigned long end = (start + dcache_size);
++
++ while(start < end) {
++ BCM4710_DUMMY_RREG();
++ cache_unroll(start,Index_Writeback_Inv_D);
++ start += current_cpu_data.dcache.linesz;
++ }
++}
++
++static inline void blast_dcache_page(unsigned long page)
++{
++ unsigned long start = page;
++ unsigned long end = start + PAGE_SIZE;
++
++ BCM4710_FILL_TLB(start);
++ do {
++ BCM4710_DUMMY_RREG();
++ cache_unroll(start,Hit_Writeback_Inv_D);
++ start += current_cpu_data.dcache.linesz;
++ } while (start < end);
++}
++
++static inline void blast_dcache_page_indexed(unsigned long page)
++{
++ unsigned long start = page;
++ unsigned long end = start + PAGE_SIZE;
++ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
++ unsigned long ws_end = current_cpu_data.dcache.ways <<
++ current_cpu_data.dcache.waybit;
++ unsigned long ws, addr;
++
++ for (ws = 0; ws < ws_end; ws += ws_inc) {
++ start = page + ws;
++ for (addr = start; addr < end; addr += current_cpu_data.dcache.linesz) {
++ BCM4710_DUMMY_RREG();
++ cache_unroll(addr,Index_Writeback_Inv_D);
++ }
++ }
++}
++
+ static inline void blast_dcache16(void)
+ {
+ unsigned long start = KSEG0;
+@@ -148,8 +231,9 @@
+ unsigned long ws, addr;
+
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+- for (addr = start; addr < end; addr += 0x200)
++ for (addr = start; addr < end; addr += 0x200) {
+ cache16_unroll32(addr|ws,Index_Writeback_Inv_D);
++ }
+ }
+
+ static inline void blast_dcache16_page(unsigned long page)
+@@ -173,8 +257,9 @@
+ unsigned long ws, addr;
+
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+- for (addr = start; addr < end; addr += 0x200)
++ for (addr = start; addr < end; addr += 0x200) {
+ cache16_unroll32(addr|ws,Index_Writeback_Inv_D);
++ }
+ }
+
+ static inline void blast_icache16(void)
+@@ -196,6 +281,7 @@
+ unsigned long start = page;
+ unsigned long end = start + PAGE_SIZE;
+
++ BCM4710_FILL_TLB(start);
+ do {
+ cache16_unroll32(start,Hit_Invalidate_I);
+ start += 0x200;
+@@ -281,6 +367,7 @@
+ : "r" (base), \
+ "i" (op));
+
++
+ static inline void blast_dcache32(void)
+ {
+ unsigned long start = KSEG0;
+@@ -291,8 +378,9 @@
+ unsigned long ws, addr;
+
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+- for (addr = start; addr < end; addr += 0x400)
++ for (addr = start; addr < end; addr += 0x400) {
+ cache32_unroll32(addr|ws,Index_Writeback_Inv_D);
++ }
+ }
+
+ static inline void blast_dcache32_page(unsigned long page)
+@@ -316,8 +404,9 @@
+ unsigned long ws, addr;
+
+ for (ws = 0; ws < ws_end; ws += ws_inc)
+- for (addr = start; addr < end; addr += 0x400)
++ for (addr = start; addr < end; addr += 0x400) {
+ cache32_unroll32(addr|ws,Index_Writeback_Inv_D);
++ }
+ }
+
+ static inline void blast_icache32(void)
+@@ -339,6 +428,7 @@
+ unsigned long start = page;
+ unsigned long end = start + PAGE_SIZE;
+
++ BCM4710_FILL_TLB(start);
+ do {
+ cache32_unroll32(start,Hit_Invalidate_I);
+ start += 0x400;
+@@ -443,6 +533,7 @@
+ unsigned long start = page;
+ unsigned long end = start + PAGE_SIZE;
+
++ BCM4710_FILL_TLB(start);
+ do {
+ cache64_unroll32(start,Hit_Invalidate_I);
+ start += 0x800;
+diff -urN linux.old/include/asm-mips/stackframe.h linux.dev/include/asm-mips/stackframe.h
+--- linux.old/include/asm-mips/stackframe.h 2005-07-05 16:46:49.000000000 +0200
++++ linux.dev/include/asm-mips/stackframe.h 2005-07-06 11:23:56.000000000 +0200
+@@ -209,6 +209,20 @@
+
+ #endif
+
++#if defined(CONFIG_BCM4710) || defined(CONFIG_BCM4704)
++
++#undef RESTORE_SP_AND_RET
++#define RESTORE_SP_AND_RET \
++ lw sp, PT_R29(sp); \
++ .set mips3; \
++ nop; \
++ nop; \
++ eret; \
++ .set mips0
++
++#endif
++
++
+ #define RESTORE_SP \
+ lw sp, PT_R29(sp); \
+
+diff -urN linux.old/mm/memory.c linux.dev/mm/memory.c
+--- linux.old/mm/memory.c 2005-04-04 03:42:20.000000000 +0200
++++ linux.dev/mm/memory.c 2005-07-06 11:23:56.000000000 +0200
+@@ -925,6 +925,7 @@
+ flush_page_to_ram(new_page);
+ flush_cache_page(vma, address);
+ establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
++ flush_icache_page(vma, new_page);
+ }
+
+ /*
diff --git a/target/linux/brcm-2.4/patches/004-flash.patch b/target/linux/brcm-2.4/patches/004-flash.patch
new file mode 100644
index 0000000..de2d5b1
--- /dev/null
+++ b/target/linux/brcm-2.4/patches/004-flash.patch
@@ -0,0 +1,916 @@
+diff -urN linux.old/drivers/mtd/devices/Config.in linux.dev/drivers/mtd/devices/Config.in
+--- linux.old/drivers/mtd/devices/Config.in 2006-06-22 17:35:39.000000000 +0200
++++ linux.dev/drivers/mtd/devices/Config.in 2006-06-21 21:41:24.000000000 +0200
+@@ -5,6 +5,7 @@
+ mainmenu_option next_comment
+
+ comment 'Self-contained MTD device drivers'
++bool ' Broadcom Chipcommon Serial Flash support' CONFIG_MTD_SFLASH
+ dep_tristate ' Ramix PMC551 PCI Mezzanine RAM card support' CONFIG_MTD_PMC551 $CONFIG_MTD $CONFIG_PCI
+ if [ "$CONFIG_MTD_PMC551" = "y" -o "$CONFIG_MTD_PMC551" = "m" ]; then
+ bool ' PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX
+diff -urN linux.old/drivers/mtd/devices/Makefile linux.dev/drivers/mtd/devices/Makefile
+--- linux.old/drivers/mtd/devices/Makefile 2006-06-22 17:35:39.000000000 +0200
++++ linux.dev/drivers/mtd/devices/Makefile 2006-06-21 21:41:24.000000000 +0200
+@@ -3,6 +3,8 @@
+ #
+ # $Id: Makefile,v 1.4 2001/06/26 21:10:05 spse Exp $
+
++EXTRA_CFLAGS := -I$(TOPDIR)/arch/mips/bcm947xx/include
++
+ O_TARGET := devlink.o
+
+ # *** BIG UGLY NOTE ***
+@@ -12,6 +14,7 @@
+ # here where previously there was none. We now have to ensure that
+ # doc200[01].o are linked before docprobe.o
+
++obj-$(CONFIG_MTD_SFLASH) += sflash.o
+ obj-$(CONFIG_MTD_DOC1000) += doc1000.o
+ obj-$(CONFIG_MTD_DOC2000) += doc2000.o
+ obj-$(CONFIG_MTD_DOC2001) += doc2001.o
+diff -urN linux.old/drivers/mtd/devices/sflash.c linux.dev/drivers/mtd/devices/sflash.c
+--- linux.old/drivers/mtd/devices/sflash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/mtd/devices/sflash.c 2006-06-21 21:41:24.000000000 +0200
+@@ -0,0 +1,298 @@
++/*
++ * Broadcom SiliconBackplane chipcommon serial flash interface
++ *
++ * Copyright 2001-2003, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id: sflash.c,v 1.1.1.3 2003/11/10 17:43:38 hyin Exp $
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/ioport.h>
++#include <linux/mtd/compatmac.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/errno.h>
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <asm/io.h>
++
++#ifdef CONFIG_MTD_PARTITIONS
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/minix_fs.h>
++#include <linux/ext2_fs.h>
++#include <linux/romfs_fs.h>
++#include <linux/cramfs_fs.h>
++#include <linux/jffs2.h>
++#endif
++
++#include <typedefs.h>
++#include <bcmdevs.h>
++#include <bcmutils.h>
++#include <osl.h>
++#include <bcmutils.h>
++#include <bcmnvram.h>
++#include <sbconfig.h>
++#include <sbchipc.h>
++#include <sflash.h>
++#include <trxhdr.h>
++
++#ifdef CONFIG_MTD_PARTITIONS
++extern struct mtd_partition * init_mtd_partitions(struct mtd_info *mtd, size_t size);
++#endif
++
++struct sflash_mtd {
++ chipcregs_t *cc;
++ struct semaphore lock;
++ struct mtd_info mtd;
++ struct mtd_erase_region_info regions[1];
++};
++
++/* Private global state */
++static struct sflash_mtd sflash;
++
++static int
++sflash_mtd_poll(struct sflash_mtd *sflash, unsigned int offset, int timeout)
++{
++ int now = jiffies;
++ int ret = 0;
++
++ for (;;) {
++ if (!sflash_poll(sflash->cc, offset)) {
++ ret = 0;
++ break;
++ }
++ if (time_after(jiffies, now + timeout)) {
++ printk(KERN_ERR "sflash: timeout\n");
++ ret = -ETIMEDOUT;
++ break;
++ }
++ if (current->need_resched) {
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ schedule_timeout(timeout / 10);
++ } else
++ udelay(1);
++ }
++
++ return ret;
++}
++
++static int
++sflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
++{
++ struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
++ int bytes, ret = 0;
++
++ /* Check address range */
++ if (!len)
++ return 0;
++ if ((from + len) > mtd->size)
++ return -EINVAL;
++
++ down(&sflash->lock);
++
++ *retlen = 0;
++ while (len) {
++ if ((bytes = sflash_read(sflash->cc, (uint) from, len, buf)) < 0) {
++ ret = bytes;
++ break;
++ }
++ from += (loff_t) bytes;
++ len -= bytes;
++ buf += bytes;
++ *retlen += bytes;
++ }
++
++ up(&sflash->lock);
++
++ return ret;
++}
++
++static int
++sflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
++{
++ struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
++ int bytes, ret = 0;
++
++ /* Check address range */
++ if (!len)
++ return 0;
++ if ((to + len) > mtd->size)
++ return -EINVAL;
++
++ down(&sflash->lock);
++
++ *retlen = 0;
++ while (len) {
++ if ((bytes = sflash_write(sflash->cc, (uint) to, len, buf)) < 0) {
++ ret = bytes;
++ break;
++ }
++ if ((ret = sflash_mtd_poll(sflash, (unsigned int) to, HZ / 10)))
++ break;
++ to += (loff_t) bytes;
++ len -= bytes;
++ buf += bytes;
++ *retlen += bytes;
++ }
++
++ up(&sflash->lock);
++
++ return ret;
++}
++
++static int
++sflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
++{
++ struct sflash_mtd *sflash = (struct sflash_mtd *) mtd->priv;
++ int i, j, ret = 0;
++ unsigned int addr, len;
++
++ /* Check address range */
++ if (!erase->len)
++ return 0;
++ if ((erase->addr + erase->len) > mtd->size)
++ return -EINVAL;
++
++ addr = erase->addr;
++ len = erase->len;
++
++ down(&sflash->lock);
++
++ /* Ensure that requested region is aligned */
++ for (i = 0; i < mtd->numeraseregions; i++) {
++ for (j = 0; j < mtd->eraseregions[i].numblocks; j++) {
++ if (addr == mtd->eraseregions[i].offset + mtd->eraseregions[i].erasesize * j &&
++ len >= mtd->eraseregions[i].erasesize) {
++ if ((ret = sflash_erase(sflash->cc, addr)) < 0)
++ break;
++ if ((ret = sflash_mtd_poll(sflash, addr, 10 * HZ)))
++ break;
++ addr += mtd->eraseregions[i].erasesize;
++ len -= mtd->eraseregions[i].erasesize;
++ }
++ }
++ if (ret)
++ break;
++ }
++
++ up(&sflash->lock);
++
++ /* Set erase status */
++ if (ret)
++ erase->state = MTD_ERASE_FAILED;
++ else
++ erase->state = MTD_ERASE_DONE;
++
++ /* Call erase callback */
++ if (erase->callback)
++ erase->callback(erase);
++
++ return ret;
++}
++
++#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
++#define sflash_mtd_init init_module
++#define sflash_mtd_exit cleanup_module
++#endif
++
++mod_init_t
++sflash_mtd_init(void)
++{
++ struct pci_dev *pdev;
++ int ret = 0;
++ struct sflash *info;
++ uint bank, i;
++#ifdef CONFIG_MTD_PARTITIONS
++ struct mtd_partition *parts;
++#endif
++
++ if (!(pdev = pci_find_device(VENDOR_BROADCOM, SB_CC, NULL))) {
++ printk(KERN_ERR "sflash: chipcommon not found\n");
++ return -ENODEV;
++ }
++
++ memset(&sflash, 0, sizeof(struct sflash_mtd));
++ init_MUTEX(&sflash.lock);
++
++ /* Map registers and flash base */
++ if (!(sflash.cc = ioremap_nocache(pci_resource_start(pdev, 0),
++ pci_resource_len(pdev, 0)))) {
++ printk(KERN_ERR "sflash: error mapping registers\n");
++ ret = -EIO;
++ goto fail;
++ }
++
++ /* Initialize serial flash access */
++ info = sflash_init(sflash.cc);
++
++ if (!info) {
++ printk(KERN_ERR "sflash: found no supported devices\n");
++ ret = -ENODEV;
++ goto fail;
++ }
++
++ /* Setup banks */
++ sflash.regions[0].offset = 0;
++ sflash.regions[0].erasesize = info->blocksize;
++ sflash.regions[0].numblocks = info->numblocks;
++ if (sflash.regions[0].erasesize > sflash.mtd.erasesize)
++ sflash.mtd.erasesize = sflash.regions[0].erasesize;
++ if (sflash.regions[0].erasesize * sflash.regions[0].numblocks) {
++ sflash.mtd.size += sflash.regions[0].erasesize * sflash.regions[0].numblocks;
++ }
++ sflash.mtd.numeraseregions = 1;
++ ASSERT(sflash.mtd.size == info->size);
++
++ /* Register with MTD */
++ sflash.mtd.name = "sflash";
++ sflash.mtd.type = MTD_NORFLASH;
++ sflash.mtd.flags = MTD_CAP_NORFLASH;
++ sflash.mtd.eraseregions = sflash.regions;
++ sflash.mtd.module = THIS_MODULE;
++ sflash.mtd.erase = sflash_mtd_erase;
++ sflash.mtd.read = sflash_mtd_read;
++ sflash.mtd.write = sflash_mtd_write;
++ sflash.mtd.priv = &sflash;
++
++#ifdef CONFIG_MTD_PARTITIONS
++ parts = init_mtd_partitions(&sflash.mtd, sflash.mtd.size);
++ for (i = 0; parts[i].name; i++);
++ ret = add_mtd_partitions(&sflash.mtd, parts, i);
++#else
++ ret = add_mtd_device(&sflash.mtd);
++#endif
++ if (ret) {
++ printk(KERN_ERR "sflash: add_mtd failed\n");
++ goto fail;
++ }
++
++ return 0;
++
++ fail:
++ if (sflash.cc)
++ iounmap((void *) sflash.cc);
++ return ret;
++}
++
++mod_exit_t
++sflash_mtd_exit(void)
++{
++#ifdef CONFIG_MTD_PARTITIONS
++ del_mtd_partitions(&sflash.mtd);
++#else
++ del_mtd_device(&sflash.mtd);
++#endif
++ iounmap((void *) sflash.cc);
++}
++
++module_init(sflash_mtd_init);
++module_exit(sflash_mtd_exit);
+diff -urN linux.old/drivers/mtd/maps/bcm947xx-flash.c linux.dev/drivers/mtd/maps/bcm947xx-flash.c
+--- linux.old/drivers/mtd/maps/bcm947xx-flash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/mtd/maps/bcm947xx-flash.c 2006-06-23 18:08:46.000000000 +0200
+@@ -0,0 +1,548 @@
++/*
++ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
++ *
++ * original functions for finding root filesystem from Mike Baker
++ *
++ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * Copyright 2004, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * Flash mapping for BCM947XX boards
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/wait.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#ifdef CONFIG_MTD_PARTITIONS
++#include <linux/mtd/partitions.h>
++#endif
++#include <linux/config.h>
++#include <linux/squashfs_fs.h>
++#include <linux/jffs2.h>
++#include <linux/crc32.h>
++#include <asm/io.h>
++
++#include <typedefs.h>
++#include <osl.h>
++#include <bcmnvram.h>
++#include <bcmutils.h>
++#include <sbconfig.h>
++#include <sbchipc.h>
++#include <sbutils.h>
++#include <trxhdr.h>
++
++/* Global SB handle */
++extern void *bcm947xx_sbh;
++extern spinlock_t bcm947xx_sbh_lock;
++
++/* Convenience */
++#define sbh bcm947xx_sbh
++#define sbh_lock bcm947xx_sbh_lock
++
++#define WINDOW_ADDR 0x1fc00000
++#define WINDOW_SIZE 0x400000
++#define BUSWIDTH 2
++
++static struct mtd_info *bcm947xx_mtd;
++
++__u8 bcm947xx_map_read8(struct map_info *map, unsigned long ofs)
++{
++ if (map->map_priv_2 == 1)
++ return __raw_readb(map->map_priv_1 + ofs);
++
++ u16 val = __raw_readw(map->map_priv_1 + (ofs & ~1));
++ if (ofs & 1)
++ return ((val >> 8) & 0xff);
++ else
++ return (val & 0xff);
++}
++
++__u16 bcm947xx_map_read16(struct map_info *map, unsigned long ofs)
++{
++ return __raw_readw(map->map_priv_1 + ofs);
++}
++
++__u32 bcm947xx_map_read32(struct map_info *map, unsigned long ofs)
++{
++ return __raw_readl(map->map_priv_1 + ofs);
++}
++
++void bcm947xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++ if (len==1) {
++ memcpy_fromio(to, map->map_priv_1 + from, len);
++ } else {
++ int i;
++ u16 *dest = (u16 *) to;
++ u16 *src = (u16 *) (map->map_priv_1 + from);
++ for (i = 0; i < (len / 2); i++) {
++ dest[i] = src[i];
++ }
++ if (len & 1)
++ *((u8 *)dest+len-1) = src[i] & 0xff;
++ }
++}
++
++void bcm947xx_map_write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++ __raw_writeb(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void bcm947xx_map_write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++ __raw_writew(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void bcm947xx_map_write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++ __raw_writel(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void bcm947xx_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
++{
++ memcpy_toio(map->map_priv_1 + to, from, len);
++}
++
++struct map_info bcm947xx_map = {
++ name: "Physically mapped flash",
++ size: WINDOW_SIZE,
++ buswidth: BUSWIDTH,
++ read8: bcm947xx_map_read8,
++ read16: bcm947xx_map_read16,
++ read32: bcm947xx_map_read32,
++ copy_from: bcm947xx_map_copy_from,
++ write8: bcm947xx_map_write8,
++ write16: bcm947xx_map_write16,
++ write32: bcm947xx_map_write32,
++ copy_to: bcm947xx_map_copy_to
++};
++
++#ifdef CONFIG_MTD_PARTITIONS
++
++static struct mtd_partition bcm947xx_parts[] = {
++ { name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
++ { name: "linux", offset: 0, size: 0, },
++ { name: "rootfs", offset: 0, size: 0, },
++ { name: "nvram", offset: 0, size: 0, },
++ { name: "OpenWrt", offset: 0, size: 0, },
++ { name: NULL, },
++};
++
++static int __init
++find_cfe_size(struct mtd_info *mtd, size_t size)
++{
++ struct trx_header *trx;
++ unsigned char buf[512];
++ int off;
++ size_t len;
++ int blocksize;
++
++ trx = (struct trx_header *) buf;
++
++ blocksize = mtd->erasesize;
++ if (blocksize < 0x10000)
++ blocksize = 0x10000;
++
++ for (off = (128*1024); off < size; off += blocksize) {
++ memset(buf, 0xe5, sizeof(buf));
++
++ /*
++ * Read into buffer
++ */
++ if (MTD_READ(mtd, off, sizeof(buf), &len, buf) ||
++ len != sizeof(buf))
++ continue;
++
++ /* found a TRX header */
++ if (le32_to_cpu(trx->magic) == TRX_MAGIC) {
++ goto found;
++ }
++ }
++
++ printk(KERN_NOTICE
++ "%s: Couldn't find bootloader size\n",
++ mtd->name);
++ return -1;
++
++ found:
++ printk(KERN_NOTICE "bootloader size: %d\n", off);
++ return off;
++
++}
++
++/*
++ * Copied from mtdblock.c
++ *
++ * Cache stuff...
++ *
++ * Since typical flash erasable sectors are much larger than what Linux's
++ * buffer cache can handle, we must implement read-modify-write on flash
++ * sectors for each block write requests. To avoid over-erasing flash sectors
++ * and to speed things up, we locally cache a whole flash sector while it is
++ * being written to until a different sector is required.
++ */
++
++static void erase_callback(struct erase_info *done)
++{
++ wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
++ wake_up(wait_q);
++}
++
++static int erase_write (struct mtd_info *mtd, unsigned long pos,
++ int len, const char *buf)
++{
++ struct erase_info erase;
++ DECLARE_WAITQUEUE(wait, current);
++ wait_queue_head_t wait_q;
++ size_t retlen;
++ int ret;
++
++ /*
++ * First, let's erase the flash block.
++ */
++
++ init_waitqueue_head(&wait_q);
++ erase.mtd = mtd;
++ erase.callback = erase_callback;
++ erase.addr = pos;
++ erase.len = len;
++ erase.priv = (u_long)&wait_q;
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_wait_queue(&wait_q, &wait);
++
++ ret = MTD_ERASE(mtd, &erase);
++ if (ret) {
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&wait_q, &wait);
++ printk (KERN_WARNING "erase of region [0x%lx, 0x%x] "
++ "on \"%s\" failed\n",
++ pos, len, mtd->name);
++ return ret;
++ }
++
++ schedule(); /* Wait for erase to finish. */
++ remove_wait_queue(&wait_q, &wait);
++
++ /*
++ * Next, writhe data to flash.
++ */
++
++ ret = MTD_WRITE (mtd, pos, len, &retlen, buf);
++ if (ret)
++ return ret;
++ if (retlen != len)
++ return -EIO;
++ return 0;
++}
++
++
++
++
++static int __init
++find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part)
++{
++ struct trx_header trx, *trx2;
++ unsigned char buf[512], *block;
++ int off, blocksize;
++ u32 i, crc = ~0;
++ size_t len;
++ struct squashfs_super_block *sb = (struct squashfs_super_block *) buf;
++
++ blocksize = mtd->erasesize;
++ if (blocksize < 0x10000)
++ blocksize = 0x10000;
++
++ for (off = (128*1024); off < size; off += blocksize) {
++ memset(&trx, 0xe5, sizeof(trx));
++
++ /*
++ * Read into buffer
++ */
++ if (MTD_READ(mtd, off, sizeof(trx), &len, (char *) &trx) ||
++ len != sizeof(trx))
++ continue;
++
++ /* found a TRX header */
++ if (le32_to_cpu(trx.magic) == TRX_MAGIC) {
++ part->offset = le32_to_cpu(trx.offsets[2]) ? :
++ le32_to_cpu(trx.offsets[1]);
++ part->size = le32_to_cpu(trx.len);
++
++ part->size -= part->offset;
++ part->offset += off;
++
++ goto found;
++ }
++ }
++
++ printk(KERN_NOTICE
++ "%s: Couldn't find root filesystem\n",
++ mtd->name);
++ return -1;
++
++ found:
++ if (part->size == 0)
++ return 0;
++
++ if (MTD_READ(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf))
++ return 0;
++
++ if (*((__u32 *) buf) == SQUASHFS_MAGIC) {
++ printk(KERN_INFO "%s: Filesystem type: squashfs, size=0x%x\n", mtd->name, (u32) sb->bytes_used);
++
++ /* Update the squashfs partition size based on the superblock info */
++ part->size = sb->bytes_used;
++ len = part->offset + part->size;
++ len += (mtd->erasesize - 1);
++ len &= ~(mtd->erasesize - 1);
++ part->size = len - part->offset;
++ } else if (*((__u16 *) buf) == JFFS2_MAGIC_BITMASK) {
++ printk(KERN_INFO "%s: Filesystem type: jffs2\n", mtd->name);
++
++ /* Move the squashfs outside of the trx */
++ part->size = 0;
++ } else {
++ printk(KERN_INFO "%s: Filesystem type: unknown\n", mtd->name);
++ return 0;
++ }
++
++ if (trx.len != part->offset + part->size - off) {
++ /* Update the trx offsets and length */
++ trx.len = part->offset + part->size - off;
++
++ /* Update the trx crc32 */
++ for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) {
++ if (MTD_READ(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf))
++ return 0;
++ crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i));
++ }
++ trx.crc32 = crc;
++
++ /* read first eraseblock from the trx */
++ trx2 = block = kmalloc(mtd->erasesize, GFP_KERNEL);
++ if (MTD_READ(mtd, off, mtd->erasesize, &len, block) || len != mtd->erasesize) {
++ printk("Error accessing the first trx eraseblock\n");
++ return 0;
++ }
++
++ printk("Updating TRX offsets and length:\n");
++ printk("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32);
++ printk("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32);
++
++ /* Write updated trx header to the flash */
++ memcpy(block, &trx, sizeof(trx));
++ if (mtd->unlock)
++ mtd->unlock(mtd, off, mtd->erasesize);
++ erase_write(mtd, off, mtd->erasesize, block);
++ if (mtd->sync)
++ mtd->sync(mtd);
++ kfree(block);
++ printk("Done\n");
++ }
++
++ return part->size;
++}
++
++struct mtd_partition * __init
++init_mtd_partitions(struct mtd_info *mtd, size_t size)
++{
++ int cfe_size;
++
++ if ((cfe_size = find_cfe_size(mtd,size)) < 0)
++ return NULL;
++
++ /* boot loader */
++ bcm947xx_parts[0].offset = 0;
++ bcm947xx_parts[0].size = cfe_size;
++
++ /* nvram */
++ if (cfe_size != 384 * 1024) {
++ bcm947xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
++ bcm947xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
++ } else {
++ /* nvram (old 128kb config partition on netgear wgt634u) */
++ bcm947xx_parts[3].offset = bcm947xx_parts[0].size;
++ bcm947xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
++ }
++
++ /* linux (kernel and rootfs) */
++ if (cfe_size != 384 * 1024) {
++ bcm947xx_parts[1].offset = bcm947xx_parts[0].size;
++ bcm947xx_parts[1].size = bcm947xx_parts[3].offset -
++ bcm947xx_parts[1].offset;
++ } else {
++ /* do not count the elf loader, which is on one block */
++ bcm947xx_parts[1].offset = bcm947xx_parts[0].size +
++ bcm947xx_parts[3].size + mtd->erasesize;
++ bcm947xx_parts[1].size = size -
++ bcm947xx_parts[0].size -
++ (2*bcm947xx_parts[3].size) -
++ mtd->erasesize;
++ }
++
++ /* find and size rootfs */
++ if (find_root(mtd,size,&bcm947xx_parts[2])==0) {
++ /* entirely jffs2 */
++ bcm947xx_parts[4].name = NULL;
++ bcm947xx_parts[2].size = size - bcm947xx_parts[2].offset -
++ bcm947xx_parts[3].size;
++ } else {
++ /* legacy setup */
++ /* calculate leftover flash, and assign it to the jffs2 partition */
++ if (cfe_size != 384 * 1024) {
++ bcm947xx_parts[4].offset = bcm947xx_parts[2].offset +
++ bcm947xx_parts[2].size;
++ if ((bcm947xx_parts[4].offset % mtd->erasesize) > 0) {
++ bcm947xx_parts[4].offset += mtd->erasesize -
++ (bcm947xx_parts[4].offset % mtd->erasesize);
++ }
++ bcm947xx_parts[4].size = bcm947xx_parts[3].offset -
++ bcm947xx_parts[4].offset;
++ } else {
++ bcm947xx_parts[4].offset = bcm947xx_parts[2].offset +
++ bcm947xx_parts[2].size;
++ if ((bcm947xx_parts[4].offset % mtd->erasesize) > 0) {
++ bcm947xx_parts[4].offset += mtd->erasesize -
++ (bcm947xx_parts[4].offset % mtd->erasesize);
++ }
++ bcm947xx_parts[4].size = size - bcm947xx_parts[3].size -
++ bcm947xx_parts[4].offset;
++ }
++ }
++
++ return bcm947xx_parts;
++}
++
++#endif
++
++
++mod_init_t init_bcm947xx_map(void)
++{
++ ulong flags;
++ uint coreidx;
++ chipcregs_t *cc;
++ uint32 fltype;
++ uint window_addr = 0, window_size = 0;
++ size_t size;
++ int ret = 0;
++#ifdef CONFIG_MTD_PARTITIONS
++ struct mtd_partition *parts;
++ int i;
++#endif
++
++ spin_lock_irqsave(&sbh_lock, flags);
++ coreidx = sb_coreidx(sbh);
++
++ /* Check strapping option if chipcommon exists */
++ if ((cc = sb_setcore(sbh, SB_CC, 0))) {
++ fltype = readl(&cc->capabilities) & CAP_FLASH_MASK;
++ if (fltype == PFLASH) {
++ bcm947xx_map.map_priv_2 = 1;
++ window_addr = 0x1c000000;
++ bcm947xx_map.size = window_size = 32 * 1024 * 1024;
++ if ((readl(&cc->flash_config) & CC_CFG_DS) == 0)
++ bcm947xx_map.buswidth = 1;
++ }
++ } else {
++ fltype = PFLASH;
++ bcm947xx_map.map_priv_2 = 0;
++ window_addr = WINDOW_ADDR;
++ window_size = WINDOW_SIZE;
++ }
++
++ sb_setcoreidx(sbh, coreidx);
++ spin_unlock_irqrestore(&sbh_lock, flags);
++
++ if (fltype != PFLASH) {
++ printk(KERN_ERR "pflash: found no supported devices\n");
++ ret = -ENODEV;
++ goto fail;
++ }
++
++ bcm947xx_map.map_priv_1 = (unsigned long) ioremap(window_addr, window_size);
++
++ if (!bcm947xx_map.map_priv_1) {
++ printk(KERN_ERR "Failed to ioremap\n");
++ return -EIO;
++ }
++
++ if (!(bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map))) {
++ printk(KERN_ERR "pflash: cfi_probe failed\n");
++ iounmap((void *)bcm947xx_map.map_priv_1);
++ return -ENXIO;
++ }
++
++ bcm947xx_mtd->module = THIS_MODULE;
++
++ size = bcm947xx_mtd->size;
++
++ printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, window_addr);
++
++#ifdef CONFIG_MTD_PARTITIONS
++ parts = init_mtd_partitions(bcm947xx_mtd, size);
++ for (i = 0; parts[i].name; i++);
++ ret = add_mtd_partitions(bcm947xx_mtd, parts, i);
++ if (ret) {
++ printk(KERN_ERR "Flash: add_mtd_partitions failed\n");
++ goto fail;
++ }
++#endif
++
++ return 0;
++
++ fail:
++ if (bcm947xx_mtd)
++ map_destroy(bcm947xx_mtd);
++ if (bcm947xx_map.map_priv_1)
++ iounmap((void *) bcm947xx_map.map_priv_1);
++ bcm947xx_map.map_priv_1 = 0;
++ return ret;
++}
++
++mod_exit_t cleanup_bcm947xx_map(void)
++{
++#ifdef CONFIG_MTD_PARTITIONS
++ del_mtd_partitions(bcm947xx_mtd);
++#endif
++ map_destroy(bcm947xx_mtd);
++ iounmap((void *) bcm947xx_map.map_priv_1);
++ bcm947xx_map.map_priv_1 = 0;
++}
++
++module_init(init_bcm947xx_map);
++module_exit(cleanup_bcm947xx_map);
+diff -urN linux.old/drivers/mtd/maps/Config.in linux.dev/drivers/mtd/maps/Config.in
+--- linux.old/drivers/mtd/maps/Config.in 2006-06-22 17:35:39.000000000 +0200
++++ linux.dev/drivers/mtd/maps/Config.in 2006-06-21 21:41:24.000000000 +0200
+@@ -48,6 +48,7 @@
+ fi
+
+ if [ "$CONFIG_MIPS" = "y" ]; then
++ dep_tristate ' CFI Flash device mapped on Broadcom BCM947XX boards' CONFIG_MTD_BCM947XX $CONFIG_MTD_CFI
+ dep_tristate ' Pb1000 MTD support' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000
+ dep_tristate ' Pb1500 MTD support' CONFIG_MTD_PB1500 $CONFIG_MIPS_PB1500
+ dep_tristate ' Pb1100 MTD support' CONFIG_MTD_PB1100 $CONFIG_MIPS_PB1100
+diff -urN linux.old/drivers/mtd/maps/Makefile linux.dev/drivers/mtd/maps/Makefile
+--- linux.old/drivers/mtd/maps/Makefile 2006-06-22 17:35:39.000000000 +0200
++++ linux.dev/drivers/mtd/maps/Makefile 2006-06-21 21:41:24.000000000 +0200
+@@ -3,6 +3,8 @@
+ #
+ # $Id: Makefile,v 1.37 2003/01/24 14:26:38 dwmw2 Exp $
+
++EXTRA_CFLAGS := -I$(TOPDIR)/arch/mips/bcm947xx/include
++
+ BELOW25 := $(shell echo $(PATCHLEVEL) | sed s/[1234]/y/)
+
+ ifeq ($(BELOW25),y)
+@@ -10,6 +12,7 @@
+ endif
+
+ # Chip mappings
++obj-$(CONFIG_MTD_BCM947XX) += bcm947xx-flash.o
+ obj-$(CONFIG_MTD_CDB89712) += cdb89712.o
+ obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
+ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
diff --git a/target/linux/brcm-2.4/patches/005-bluetooth_sco_buffer_align.patch b/target/linux/brcm-2.4/patches/005-bluetooth_sco_buffer_align.patch
new file mode 100644
index 0000000..77ade1c
--- /dev/null
+++ b/target/linux/brcm-2.4/patches/005-bluetooth_sco_buffer_align.patch
@@ -0,0 +1,12 @@
+--- linux-2.4.30/drivers/bluetooth/hci_usb.c 2004-08-08 01:26:04.000000000 +0200
++++ linux-2.4.30/drivers/bluetooth/hci_usb.c 2005-07-25 20:12:11.000000000 +0200
+@@ -259,6 +259,9 @@
+ void *buf;
+
+ mtu = husb->isoc_in_ep->wMaxPacketSize;
++#ifdef CONFIG_BCM4710
++ mtu = (mtu + 1) & ~1; /* brcm: isoc buffers must be aligned on word boundary */
++#endif
+ size = mtu * HCI_MAX_ISOC_FRAMES;
+
+ buf = kmalloc(size, GFP_ATOMIC);
diff --git a/target/linux/brcm-2.4/patches/006-ide_workaround.patch b/target/linux/brcm-2.4/patches/006-ide_workaround.patch
new file mode 100644
index 0000000..9f8d2ee
--- /dev/null
+++ b/target/linux/brcm-2.4/patches/006-ide_workaround.patch
@@ -0,0 +1,18 @@
+diff -urN linux.old/arch/mips/lib/ide-std.c linux.dev/arch/mips/lib/ide-std.c
+--- linux.old/arch/mips/lib/ide-std.c 2003-08-25 13:44:40.000000000 +0200
++++ linux.dev/arch/mips/lib/ide-std.c 2005-08-12 23:55:23.886963936 +0200
+@@ -31,12 +31,14 @@
+ static ide_ioreg_t std_ide_default_io_base(int index)
+ {
+ switch (index) {
++#if 0
+ case 0: return 0x1f0;
+ case 1: return 0x170;
+ case 2: return 0x1e8;
+ case 3: return 0x168;
+ case 4: return 0x1e0;
+ case 5: return 0x160;
++#endif
+ default:
+ return 0;
+ }
diff --git a/target/linux/brcm-2.4/patches/007-sched_use_tsc.patch b/target/linux/brcm-2.4/patches/007-sched_use_tsc.patch
new file mode 100644
index 0000000..5b64310
--- /dev/null
+++ b/target/linux/brcm-2.4/patches/007-sched_use_tsc.patch
@@ -0,0 +1,84 @@
+diff -urN linux.old/arch/mips/kernel/time.c linux.dev/arch/mips/kernel/time.c
+--- linux.old/arch/mips/kernel/time.c 2005-11-14 11:06:38.661262000 +0100
++++ linux.dev/arch/mips/kernel/time.c 2005-11-15 20:02:50.059676750 +0100
+@@ -151,6 +151,27 @@
+ unsigned int (*mips_hpt_read)(void);
+ void (*mips_hpt_init)(unsigned int);
+
++extern __u32 get_htscl(void)
++{
++ return timerhi;
++}
++
++static __u64 tscll_last = 0;
++
++extern __u64 get_tscll(void)
++{
++ __u64 h = (__u64) timerhi;
++ __u32 c = read_c0_count();
++
++ h <<= 32;
++ h += c;
++
++ while (h < tscll_last)
++ h += (((__u64) 1) << 32);
++
++ tscll_last = h;
++ return h;
++}
+
+ /*
+ * timeofday services, for syscalls.
+@@ -761,3 +782,5 @@
+ EXPORT_SYMBOL(to_tm);
+ EXPORT_SYMBOL(rtc_set_time);
+ EXPORT_SYMBOL(rtc_get_time);
++EXPORT_SYMBOL(get_htscl);
++EXPORT_SYMBOL(get_tscll);
+diff -urN linux.old/include/asm-mips/timex.h linux.dev/include/asm-mips/timex.h
+--- linux.old/include/asm-mips/timex.h 2005-11-14 11:06:38.685263500 +0100
++++ linux.dev/include/asm-mips/timex.h 2005-11-14 11:02:21.069163500 +0100
+@@ -31,6 +31,19 @@
+ return read_c0_count();
+ }
+
++extern __u32 get_htscl(void);
++extern __u64 get_tscll(void);
++
++#define rdtsc(low, high) \
++ high = get_htscl(); \
++ low = read_c0_count();
++
++#define rdtscl(low) \
++ low = read_c0_count();
++
++#define rdtscll(val) \
++ val = get_tscll();
++
+ #define vxtime_lock() do {} while (0)
+ #define vxtime_unlock() do {} while (0)
+
+diff -urN linux.old/include/net/pkt_sched.h linux.dev/include/net/pkt_sched.h
+--- linux.old/include/net/pkt_sched.h 2005-11-14 11:06:38.709265000 +0100
++++ linux.dev/include/net/pkt_sched.h 2005-11-14 11:02:21.069163500 +0100
+@@ -5,7 +5,11 @@
+ #define PSCHED_JIFFIES 2
+ #define PSCHED_CPU 3
+
++#ifdef __mips__
++#define PSCHED_CLOCK_SOURCE PSCHED_CPU
++#else
+ #define PSCHED_CLOCK_SOURCE PSCHED_JIFFIES
++#endif
+
+ #include <linux/config.h>
+ #include <linux/types.h>
+@@ -271,7 +275,7 @@
+ #define PSCHED_US2JIFFIE(delay) (((delay)+psched_clock_per_hz-1)/psched_clock_per_hz)
+ #define PSCHED_JIFFIE2US(delay) ((delay)*psched_clock_per_hz)
+
+-#ifdef CONFIG_X86_TSC
++#if defined(CONFIG_X86_TSC) || defined(__mips__)
+
+ #define PSCHED_GET_TIME(stamp) \
+ ({ u64 __cur; \
diff --git a/target/linux/brcm-2.4/patches/008-b44_bcm47xx_support.patch b/target/linux/brcm-2.4/patches/008-b44_bcm47xx_support.patch
new file mode 100644
index 0000000..35c80ac
--- /dev/null
+++ b/target/linux/brcm-2.4/patches/008-b44_bcm47xx_support.patch
@@ -0,0 +1,585 @@
+diff -urN linux.old/drivers/net/b44.c linux.dev/drivers/net/b44.c
+--- linux.old/drivers/net/b44.c 2006-02-12 13:49:59.000000000 +0100
++++ linux.dev/drivers/net/b44.c 2006-03-06 22:37:14.000000000 +0100
+@@ -1,7 +1,9 @@
+ /* b44.c: Broadcom 4400 device driver.
+ *
+ * Copyright (C) 2002 David S. Miller (davem@redhat.com)
+- * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
++ * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi)
++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
++ * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org)
+ *
+ * Distribute under GPL.
+ */
+@@ -25,6 +27,41 @@
+
+ #include "b44.h"
+
++#include <typedefs.h>
++#include <bcmdevs.h>
++#include <bcmutils.h>
++#include <osl.h>
++#include <bcmutils.h>
++#include <bcmnvram.h>
++#include <sbconfig.h>
++#include <sbchipc.h>
++#include <sflash.h>
++
++#ifdef CONFIG_BCM947XX
++#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
++
++static inline void e_aton(char *str, char *dest)
++{
++ int i = 0;
++ u16 *d = (u16 *) dest;
++
++ if (str == NULL) {
++ memset(dest, 0, 6);
++ return;
++ }
++
++ for (;;) {
++ dest[i++] = (char) simple_strtoul(str, NULL, 16);
++ str += 2;
++ if (!*str++ || i == 6)
++ break;
++ }
++}
++
++static int instance = 0;
++#endif
++
++
+ #define DRV_MODULE_NAME "b44"
+ #define PFX DRV_MODULE_NAME ": "
+ #define DRV_MODULE_VERSION "0.93"
+@@ -75,7 +112,7 @@
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+ MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
+-MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver");
++MODULE_DESCRIPTION("Broadcom 4400/47xx 10/100 PCI ethernet driver");
+ MODULE_LICENSE("GPL");
+ MODULE_PARM(b44_debug, "i");
+ MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");
+@@ -89,6 +126,8 @@
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
++ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4713,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { } /* terminate list with empty entry */
+ };
+
+@@ -113,11 +152,13 @@
+ udelay(10);
+ }
+ if (i == timeout) {
++#ifdef DEBUG
+ printk(KERN_ERR PFX "%s: BUG! Timeout waiting for bit %08x of register "
+ "%lx to %s.\n",
+ bp->dev->name,
+ bit, reg,
+ (clear ? "clear" : "set"));
++#endif
+ return -ENODEV;
+ }
+ return 0;
+@@ -236,6 +277,8 @@
+ udelay(1);
+ }
+
++static int b44_4713_instance;
++
+ static int ssb_core_unit(struct b44 *bp)
+ {
+ #if 0
+@@ -258,6 +301,9 @@
+ break;
+ };
+ #endif
++ if (bp->pdev->device == PCI_DEVICE_ID_BCM4713)
++ return b44_4713_instance++;
++ else
+ return 0;
+ }
+
+@@ -267,6 +313,28 @@
+ == SBTMSLOW_CLOCK);
+ }
+
++static inline void __b44_cam_read(struct b44 *bp, unsigned char *data, int index)
++{
++ u32 val;
++
++ bw32(B44_CAM_CTRL, (CAM_CTRL_READ |
++ (index << CAM_CTRL_INDEX_SHIFT)));
++
++ b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
++
++ val = br32(B44_CAM_DATA_LO);
++
++ data[2] = (val >> 24) & 0xFF;
++ data[3] = (val >> 16) & 0xFF;
++ data[4] = (val >> 8) & 0xFF;
++ data[5] = (val >> 0) & 0xFF;
++
++ val = br32(B44_CAM_DATA_HI);
++
++ data[0] = (val >> 8) & 0xFF;
++ data[1] = (val >> 0) & 0xFF;
++}
++
+ static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
+ {
+ u32 val;
+@@ -287,7 +355,7 @@
+
+ static inline void __b44_disable_ints(struct b44 *bp)
+ {
+- bw32(B44_IMASK, 0);
++ bw32(B44_IMASK, ISTAT_TO); /* leave the timeout interrupt active */
+ }
+
+ static void b44_disable_ints(struct b44 *bp)
+@@ -303,14 +371,14 @@
+ bw32(B44_IMASK, bp->imask);
+ }
+
+-static int b44_readphy(struct b44 *bp, int reg, u32 *val)
++static int __b44_readphy(struct b44 *bp, int phy_addr, int reg, u32 *val)
+ {
+ int err;
+
+ bw32(B44_EMAC_ISTAT, EMAC_INT_MII);
+ bw32(B44_MDIO_DATA, (MDIO_DATA_SB_START |
+ (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) |
+- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
++ (phy_addr << MDIO_DATA_PMD_SHIFT) |
+ (reg << MDIO_DATA_RA_SHIFT) |
+ (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT)));
+ err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
+@@ -319,23 +387,42 @@
+ return err;
+ }
+
+-static int b44_writephy(struct b44 *bp, int reg, u32 val)
++static int b44_readphy(struct b44 *bp, int reg, u32 *val)
++{
++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
++ return 0;
++
++ return __b44_readphy(bp, bp->phy_addr, reg, val);
++}
++
++static int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val)
+ {
+ bw32(B44_EMAC_ISTAT, EMAC_INT_MII);
+ bw32(B44_MDIO_DATA, (MDIO_DATA_SB_START |
+ (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) |
+- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
++ (phy_addr << MDIO_DATA_PMD_SHIFT) |
+ (reg << MDIO_DATA_RA_SHIFT) |
+ (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) |
+ (val & MDIO_DATA_DATA)));
+ return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
+ }
+
++static int b44_writephy(struct b44 *bp, int reg, u32 val)
++{
++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
++ return 0;
++
++ return __b44_writephy(bp, bp->phy_addr, reg, val);
++}
++
+ static int b44_phy_reset(struct b44 *bp)
+ {
+ u32 val;
+ int err;
+
++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
++ return 0;
++
+ err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
+ if (err)
+ return err;
+@@ -406,6 +493,23 @@
+ u32 val;
+ int err;
+
++
++ /*
++ * workaround for bad hardware design in Linksys WAP54G v1.0
++ * see https://dev.openwrt.org/ticket/146
++ * check and reset bit "isolate"
++ */
++ if ((bp->pdev->device == PCI_DEVICE_ID_BCM4713) &&
++ (atoi(nvram_get("boardnum")) == 2) &&
++ (__b44_readphy(bp, 0, MII_BMCR, &val) == 0) &&
++ (val & BMCR_ISOLATE) &&
++ (__b44_writephy(bp, 0, MII_BMCR, val & ~BMCR_ISOLATE) != 0)) {
++ printk(KERN_WARNING PFX "PHY: cannot reset MII transceiver isolate bit.\n");
++ }
++
++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
++ return 0;
++
+ if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
+ goto out;
+ if ((err = b44_writephy(bp, B44_MII_ALEDCTRL,
+@@ -498,6 +602,19 @@
+ {
+ u32 bmsr, aux;
+
++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
++ bp->flags |= B44_FLAG_100_BASE_T;
++ bp->flags |= B44_FLAG_FULL_DUPLEX;
++ if (!netif_carrier_ok(bp->dev)) {
++ u32 val = br32(B44_TX_CTRL);
++ val |= TX_CTRL_DUPLEX;
++ bw32(B44_TX_CTRL, val);
++ netif_carrier_on(bp->dev);
++ b44_link_report(bp);
++ }
++ return;
++ }
++
+ if (!b44_readphy(bp, MII_BMSR, &bmsr) &&
+ !b44_readphy(bp, B44_MII_AUXCTRL, &aux) &&
+ (bmsr != 0xffff)) {
+@@ -765,6 +882,25 @@
+ return received;
+ }
+
++
++static inline void __b44_reset(struct b44 *bp)
++{
++ spin_lock_irq(&bp->lock);
++ b44_halt(bp);
++ b44_init_rings(bp);
++ b44_init_hw(bp);
++ spin_unlock_irq(&bp->lock);
++
++ b44_enable_ints(bp);
++ netif_wake_queue(bp->dev);
++}
++
++static inline void __b44_set_timeout(struct b44 *bp, int timeout)
++{
++ /* Set timeout for Rx to two seconds after the last Tx */
++ bw32(B44_GPTIMER, timeout ? 2 * 125000000 : 0);
++}
++
+ static int b44_poll(struct net_device *netdev, int *budget)
+ {
+ struct b44 *bp = netdev->priv;
+@@ -772,13 +908,13 @@
+
+ spin_lock_irq(&bp->lock);
+
+- if (bp->istat & (ISTAT_TX | ISTAT_TO)) {
++ if (bp->istat & ISTAT_TX) {
+ /* spin_lock(&bp->tx_lock); */
+ b44_tx(bp);
+ /* spin_unlock(&bp->tx_lock); */
+ }
+ spin_unlock_irq(&bp->lock);
+-
++
+ done = 1;
+ if (bp->istat & ISTAT_RX) {
+ int orig_budget = *budget;
+@@ -796,24 +932,18 @@
+ done = 0;
+ }
+
+- if (bp->istat & ISTAT_ERRORS) {
+- spin_lock_irq(&bp->lock);
+- b44_halt(bp);
+- b44_init_rings(bp);
+- b44_init_hw(bp);
+- netif_wake_queue(bp->dev);
+- spin_unlock_irq(&bp->lock);
+- done = 1;
+- }
+-
+ if (done) {
+ netif_rx_complete(netdev);
+ b44_enable_ints(bp);
+ }
+
++ if ((bp->core_unit == 1) && (bp->istat & (ISTAT_TX | ISTAT_RX)))
++ __b44_set_timeout(bp, (bp->istat & ISTAT_TX) ? 1 : 0);
++
+ return (done ? 0 : 1);
+ }
+
++
+ static irqreturn_t b44_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
+ struct net_device *dev = dev_id;
+@@ -832,6 +962,18 @@
+ */
+ istat &= imask;
+ if (istat) {
++ /* Workaround for the WL-500g WAN port hang */
++ if (istat & (ISTAT_TO | ISTAT_ERRORS)) {
++ /*
++ * no rx before the watchdog timeout
++ * reset the interface
++ */
++ __b44_reset(bp);
++ }
++
++ if ((bp->core_unit == 1) && (bp->istat & (ISTAT_TX | ISTAT_RX)))
++ __b44_set_timeout(bp, (bp->istat & ISTAT_TX) ? 1 : 0);
++
+ handled = 1;
+ if (netif_rx_schedule_prep(dev)) {
+ /* NOTE: These writes are posted by the readback of
+@@ -848,6 +990,7 @@
+ bw32(B44_ISTAT, istat);
+ br32(B44_ISTAT);
+ }
++
+ spin_unlock_irqrestore(&bp->lock, flags);
+ return IRQ_RETVAL(handled);
+ }
+@@ -859,16 +1002,7 @@
+ printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
+ dev->name);
+
+- spin_lock_irq(&bp->lock);
+-
+- b44_halt(bp);
+- b44_init_rings(bp);
+- b44_init_hw(bp);
+-
+- spin_unlock_irq(&bp->lock);
+-
+- b44_enable_ints(bp);
+-
++ __b44_reset(bp);
+ netif_wake_queue(dev);
+ }
+
+@@ -1092,6 +1226,8 @@
+ /* bp->lock is held. */
+ static void b44_chip_reset(struct b44 *bp)
+ {
++ unsigned int sb_clock;
++
+ if (ssb_is_core_up(bp)) {
+ bw32(B44_RCV_LAZY, 0);
+ bw32(B44_ENET_CTRL, ENET_CTRL_DISABLE);
+@@ -1105,9 +1241,10 @@
+ bw32(B44_DMARX_CTRL, 0);
+ bp->rx_prod = bp->rx_cons = 0;
+ } else {
+- ssb_pci_setup(bp, (bp->core_unit == 0 ?
+- SBINTVEC_ENET0 :
+- SBINTVEC_ENET1));
++ /*if (bp->pdev->device != PCI_DEVICE_ID_BCM4713)*/
++ ssb_pci_setup(bp, (bp->core_unit == 0 ?
++ SBINTVEC_ENET0 :
++ SBINTVEC_ENET1));
+ }
+
+ ssb_core_reset(bp);
+@@ -1115,6 +1252,11 @@
+ b44_clear_stats(bp);
+
+ /* Make PHY accessible. */
++ if (bp->pdev->device == PCI_DEVICE_ID_BCM4713)
++ sb_clock = 100000000; /* 100 MHz */
++ else
++ sb_clock = 62500000; /* 62.5 MHz */
++
+ bw32(B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
+ (0x0d & MDIO_CTRL_MAXF_MASK)));
+ br32(B44_MDIO_CTRL);
+@@ -1215,6 +1357,8 @@
+ struct b44 *bp = dev->priv;
+ int err;
+
++ netif_carrier_off(dev);
++
+ err = b44_alloc_consistent(bp);
+ if (err)
+ return err;
+@@ -1235,9 +1379,10 @@
+ bp->timer.expires = jiffies + HZ;
+ bp->timer.data = (unsigned long) bp;
+ bp->timer.function = b44_timer;
+- add_timer(&bp->timer);
++ b44_timer((unsigned long) bp);
+
+ b44_enable_ints(bp);
++ netif_start_queue(dev);
+
+ return 0;
+
+@@ -1628,7 +1773,7 @@
+ u32 mii_regval;
+
+ spin_lock_irq(&bp->lock);
+- err = b44_readphy(bp, data->reg_num & 0x1f, &mii_regval);
++ err = __b44_readphy(bp, data->phy_id & 0x1f, data->reg_num & 0x1f, &mii_regval);
+ spin_unlock_irq(&bp->lock);
+
+ data->val_out = mii_regval;
+@@ -1641,7 +1786,7 @@
+ return -EPERM;
+
+ spin_lock_irq(&bp->lock);
+- err = b44_writephy(bp, data->reg_num & 0x1f, data->val_in);
++ err = __b44_writephy(bp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
+ spin_unlock_irq(&bp->lock);
+
+ return err;
+@@ -1668,21 +1813,52 @@
+ static int __devinit b44_get_invariants(struct b44 *bp)
+ {
+ u8 eeprom[128];
++ u8 buf[32];
+ int err;
++ unsigned long flags;
+
+- err = b44_read_eeprom(bp, &eeprom[0]);
+- if (err)
+- goto out;
+-
+- bp->dev->dev_addr[0] = eeprom[79];
+- bp->dev->dev_addr[1] = eeprom[78];
+- bp->dev->dev_addr[2] = eeprom[81];
+- bp->dev->dev_addr[3] = eeprom[80];
+- bp->dev->dev_addr[4] = eeprom[83];
+- bp->dev->dev_addr[5] = eeprom[82];
+-
+- bp->phy_addr = eeprom[90] & 0x1f;
+- bp->mdc_port = (eeprom[90] >> 14) & 0x1;
++ if (bp->pdev->device == PCI_DEVICE_ID_BCM4713) {
++#ifdef CONFIG_BCM947XX
++ sprintf(buf, "et%dmacaddr", instance - 1);
++ e_aton(nvram_get(buf), bp->dev->dev_addr);
++
++ sprintf(buf, "et%dphyaddr", instance - 1);
++ bp->phy_addr = B44_PHY_ADDR_NO_PHY;
++#else
++ /*
++ * BCM47xx boards don't have a EEPROM. The MAC is stored in
++ * a NVRAM area somewhere in the flash memory. As we don't
++ * know the location and/or the format of the NVRAM area
++ * here, we simply rely on the bootloader to write the
++ * MAC into the CAM.
++ */
++ spin_lock_irqsave(&bp->lock, flags);
++ __b44_cam_read(bp, bp->dev->dev_addr, 0);
++ spin_unlock_irqrestore(&bp->lock, flags);
++
++ /*
++ * BCM47xx boards don't have a PHY. Usually there is a switch
++ * chip with multiple PHYs connected to the PHY port.
++ */
++ bp->phy_addr = B44_PHY_ADDR_NO_PHY;
++#endif
++ bp->dma_offset = 0;
++ } else {
++ err = b44_read_eeprom(bp, &eeprom[0]);
++ if (err)
++ return err;
++
++ bp->dev->dev_addr[0] = eeprom[79];
++ bp->dev->dev_addr[1] = eeprom[78];
++ bp->dev->dev_addr[2] = eeprom[81];
++ bp->dev->dev_addr[3] = eeprom[80];
++ bp->dev->dev_addr[4] = eeprom[83];
++ bp->dev->dev_addr[5] = eeprom[82];
++
++ bp->phy_addr = eeprom[90] & 0x1f;
++ bp->dma_offset = SB_PCI_DMA;
++ bp->mdc_port = (eeprom[90] >> 14) & 0x1;
++ }
+
+ /* With this, plus the rx_header prepended to the data by the
+ * hardware, we'll land the ethernet header on a 2-byte boundary.
+@@ -1692,13 +1868,12 @@
+ bp->imask = IMASK_DEF;
+
+ bp->core_unit = ssb_core_unit(bp);
+- bp->dma_offset = ssb_get_addr(bp, SBID_PCI_DMA, 0);
+
+ /* XXX - really required?
+ bp->flags |= B44_FLAG_BUGGY_TXPTR;
+ */
+-out:
+- return err;
++
++ return 0;
+ }
+
+ static int __devinit b44_init_one(struct pci_dev *pdev,
+@@ -1710,6 +1885,10 @@
+ struct b44 *bp;
+ int err, i;
+
++#ifdef CONFIG_BCM947XX
++ instance++;
++#endif
++
+ if (b44_version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
+
+@@ -1819,11 +1998,17 @@
+
+ pci_save_state(bp->pdev, bp->pci_cfg_state);
+
+- printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
++ printk(KERN_INFO "%s: Broadcom %s 10/100BaseT Ethernet ", dev->name,
++ (pdev->device == PCI_DEVICE_ID_BCM4713) ? "47xx" : "4400");
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c", dev->dev_addr[i],
+ i == 5 ? '\n' : ':');
+
++ /* Initialize phy */
++ spin_lock_irq(&bp->lock);
++ b44_chip_reset(bp);
++ spin_unlock_irq(&bp->lock);
++
+ return 0;
+
+ err_out_iounmap:
+diff -urN linux.old/drivers/net/b44.h linux.dev/drivers/net/b44.h
+--- linux.old/drivers/net/b44.h 2006-02-12 13:49:59.000000000 +0100
++++ linux.dev/drivers/net/b44.h 2006-01-24 20:52:08.000000000 +0100
+@@ -229,8 +229,6 @@
+ #define SBIPSFLAG_IMASK4 0x3f000000 /* Which sbflags --> mips interrupt 4 */
+ #define SBIPSFLAG_ISHIFT4 24
+ #define B44_SBTPSFLAG 0x0F18UL /* SB Target Port OCP Slave Flag */
+-#define SBTPS_NUM0_MASK 0x0000003f
+-#define SBTPS_F0EN0 0x00000040
+ #define B44_SBADMATCH3 0x0F60UL /* SB Address Match 3 */
+ #define B44_SBADMATCH2 0x0F68UL /* SB Address Match 2 */
+ #define B44_SBADMATCH1 0x0F70UL /* SB Address Match 1 */
+@@ -461,6 +459,8 @@
+ };
+
+ #define B44_MCAST_TABLE_SIZE 32
++#define B44_PHY_ADDR_NO_PHY 30
++#define B44_MDC_RATIO 5000000
+
+ /* SW copy of device statistics, kept up to date by periodic timer
+ * which probes HW values. Must have same relative layout as HW
+diff -urN linux.old/include/linux/pci_ids.h linux.dev/include/linux/pci_ids.h
+--- linux.old/include/linux/pci_ids.h 2006-02-12 13:49:59.000000000 +0100
++++ linux.dev/include/linux/pci_ids.h 2006-01-24 20:52:08.000000000 +0100
+@@ -1735,6 +1735,7 @@
+ #define PCI_DEVICE_ID_TIGON3_5901_2 0x170e
+ #define PCI_DEVICE_ID_BCM4401 0x4401
+ #define PCI_DEVICE_ID_BCM4401B0 0x4402
++#define PCI_DEVICE_ID_BCM4713 0x4713
+
+ #define PCI_VENDOR_ID_ENE 0x1524
+ #define PCI_DEVICE_ID_ENE_1211 0x1211
diff --git a/target/linux/brcm-2.4/patches/009-wrt54g3g_pcmcia.patch b/target/linux/brcm-2.4/patches/009-wrt54g3g_pcmcia.patch
new file mode 100644
index 0000000..0759eeb
--- /dev/null
+++ b/target/linux/brcm-2.4/patches/009-wrt54g3g_pcmcia.patch
@@ -0,0 +1,119 @@
+diff -urN linux.old/arch/mips/bcm947xx/pcibios.c linux.dev/arch/mips/bcm947xx/pcibios.c
+--- linux.old/arch/mips/bcm947xx/pcibios.c 2006-04-07 21:20:59.000000000 +0200
++++ linux.dev/arch/mips/bcm947xx/pcibios.c 2006-04-08 03:17:59.000000000 +0200
+@@ -157,6 +157,7 @@
+
+ static u32 pci_iobase = 0x100;
+ static u32 pci_membase = SB_PCI_DMA;
++static u32 pcmcia_membase = 0x40004000;
+
+ void __init
+ pcibios_fixup_bus(struct pci_bus *b)
+@@ -188,7 +189,7 @@
+ /* Fix up resource bases */
+ for (pos = 0; pos < 6; pos++) {
+ res = &d->resource[pos];
+- base = (res->flags & IORESOURCE_IO) ? &pci_iobase : &pci_membase;
++ base = (res->flags & IORESOURCE_IO) ? &pci_iobase : ((b->number == 2) ? &pcmcia_membase : &pci_membase);
+ if (res->end) {
+ size = res->end - res->start + 1;
+ if (*base & (size - 1))
+@@ -308,7 +309,12 @@
+ where = PCI_BASE_ADDRESS_0 + (resource * 4);
+ size = res->end - res->start;
+ pci_read_config_dword(dev, where, &reg);
+- reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
++
++ if (dev->bus->number == 1)
++ reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
++ else
++ reg = res->start;
++
+ pci_write_config_dword(dev, where, reg);
+ }
+
+diff -urN linux.old/drivers/pcmcia/yenta.c linux.dev/drivers/pcmcia/yenta.c
+--- linux.old/drivers/pcmcia/yenta.c 2004-11-17 12:54:21.000000000 +0100
++++ linux.dev/drivers/pcmcia/yenta.c 2006-04-11 17:47:45.000000000 +0200
+@@ -543,6 +543,9 @@
+ * Probe for usable interrupts using the force
+ * register to generate bogus card status events.
+ */
++
++#ifndef CONFIG_BCM947XX
++ /* WRT54G3G does not like this */
+ cb_writel(socket, CB_SOCKET_EVENT, -1);
+ cb_writel(socket, CB_SOCKET_MASK, CB_CSTSMASK);
+ exca_writeb(socket, I365_CSCINT, 0);
+@@ -557,7 +560,8 @@
+ }
+ cb_writel(socket, CB_SOCKET_MASK, 0);
+ exca_writeb(socket, I365_CSCINT, 0);
+-
++#endif
++
+ mask = probe_irq_mask(val) & 0xffff;
+
+ bridge_ctrl &= ~CB_BRIDGE_INTR;
+@@ -578,6 +582,12 @@
+ socket->cap.cb_dev = socket->dev;
+ socket->cap.bus = NULL;
+
++#ifdef CONFIG_BCM947XX
++ /* irq mask probing is broken for the WRT54G3G */
++ if (socket->cap.irq_mask == 0)
++ socket->cap.irq_mask = 0x6f8;
++#endif
++
+ printk(KERN_INFO "Yenta ISA IRQ mask 0x%04x, PCI irq %d\n",
+ socket->cap.irq_mask, socket->cb_irq);
+ }
+@@ -609,6 +619,15 @@
+ printk(KERN_INFO "Socket status: %08x\n",
+ cb_readl(socket, CB_SOCKET_STATE));
+
++ /* Generate an interrupt on card insert/remove */
++ config_writew(socket, CB_SOCKET_MASK, CB_CSTSMASK | CB_CDMASK);
++
++ /* Set up Multifunction Routing Status Register */
++ config_writew(socket, 0x8C, 0x1000 /* MFUNC3 to GPIO3 */ | 0x2 /* MFUNC0 to INTA */);
++
++ /* Switch interrupts to parallelized */
++ config_writeb(socket, 0x92, 0x64);
++
+ /* Register it with the pcmcia layer.. */
+ cardbus_register(socket);
+
+@@ -731,7 +750,7 @@
+ {
+ struct pci_bus *bus;
+ struct resource *root, *res;
+- u32 start, end;
++ u32 start = 0, end = 0;
+ u32 align, size, min, max;
+ unsigned offset;
+ unsigned mask;
+@@ -750,6 +769,15 @@
+ res->end = 0;
+ root = pci_find_parent_resource(socket->dev, res);
+
++#ifdef CONFIG_BCM947XX
++ /* default mem resources are completely fscked up on the wrt54g3g */
++ /* bypass the entire resource allocation stuff below and just set it statically */
++ if (type & IORESOURCE_MEM) {
++ res->start = 0x40004000;
++ res->end = res->start + 0x3fff;
++ }
++
++#else
+ if (!root)
+ return;
+
+@@ -794,6 +822,7 @@
+ res->start = res->end = 0;
+ return;
+ }
++#endif
+
+ config_writel(socket, offset, res->start);
+ config_writel(socket, offset+4, res->end);
diff --git a/target/linux/brcm-2.4/patches/010-bcm47xx-cam_absent.patch b/target/linux/brcm-2.4/patches/010-bcm47xx-cam_absent.patch
new file mode 100644
index 0000000..1deffc5
--- /dev/null
+++ b/target/linux/brcm-2.4/patches/010-bcm47xx-cam_absent.patch
@@ -0,0 +1,42 @@
+--- linux-2.4.32.orig/drivers/net/b44.h 2006-09-19 19:56:03.000000000 +0200
++++ linux-2.4.32/drivers/net/b44.h 2006-09-19 19:58:01.000000000 +0200
+@@ -122,6 +122,7 @@
+ #define RXCONFIG_FLOW 0x00000020 /* Flow Control Enable */
+ #define RXCONFIG_FLOW_ACCEPT 0x00000040 /* Accept Unicast Flow Control Frame */
+ #define RXCONFIG_RFILT 0x00000080 /* Reject Filter */
++#define RXCONFIG_CAM_ABSENT 0x00000100 /* CAM Absent */
+ #define B44_RXMAXLEN 0x0404UL /* EMAC RX Max Packet Length */
+ #define B44_TXMAXLEN 0x0408UL /* EMAC TX Max Packet Length */
+ #define B44_MDIO_CTRL 0x0410UL /* EMAC MDIO Control */
+--- linux-2.4.32.orig/drivers/net/b44.c 2006-09-19 19:56:03.000000000 +0200
++++ linux-2.4.32/drivers/net/b44.c 2006-09-19 20:08:22.000000000 +0200
+@@ -1301,6 +1301,7 @@
+ {
+ struct b44 *bp = dev->priv;
+ struct sockaddr *addr = p;
++ u32 val;
+
+ if (netif_running(dev))
+ return -EBUSY;
+@@ -1308,7 +1309,11 @@
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ spin_lock_irq(&bp->lock);
+- __b44_set_mac_addr(bp);
++
++ val = br32(B44_RXCONFIG);
++ if (!(val & RXCONFIG_CAM_ABSENT))
++ __b44_set_mac_addr(bp);
++
+ spin_unlock_irq(&bp->lock);
+
+ return 0;
+@@ -1488,7 +1493,7 @@
+
+ val = br32(B44_RXCONFIG);
+ val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
+- if (dev->flags & IFF_PROMISC) {
++ if ((dev->flags & IFF_PROMISC) || (val & RXCONFIG_CAM_ABSENT)) {
+ val |= RXCONFIG_PROMISC;
+ bw32(B44_RXCONFIG, val);
+ } else {
diff --git a/target/linux/brcm-2.6/Makefile b/target/linux/brcm-2.6/Makefile
new file mode 100644
index 0000000..0437338
--- /dev/null
+++ b/target/linux/brcm-2.6/Makefile
@@ -0,0 +1,23 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+LINUX_VERSION:=2.6.17
+LINUX_RELEASE:=1
+LINUX_KERNEL_MD5SUM:=37ddefe96625502161f075b9d907f21e
+
+include ./config
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/kernel-build.mk
+
+
+$(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked
+ [ -d ../generic-$(KERNEL)/patches ] && $(PATCH) $(LINUX_DIR) ../generic-$(KERNEL)/patches $(MAKE_TRACE)
+ [ -d ./patches ] && $(PATCH) $(LINUX_DIR) ./patches $(MAKE_TRACE)
+ @$(CP) config $(LINUX_DIR)/.config
+ touch $@
+
diff --git a/target/linux/brcm-2.6/config b/target/linux/brcm-2.6/config
new file mode 100644
index 0000000..29842b0
--- /dev/null
+++ b/target/linux/brcm-2.6/config
@@ -0,0 +1,1740 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17
+# Tue Aug 22 11:48:58 2006
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+CONFIG_BCM947XX=y
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_MIPS_MT is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+# CONFIG_PCMCIA_LOAD_CIS is not set
+# CONFIG_PCMCIA_IOCTL is not set
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+CONFIG_YENTA=m
+# CONFIG_YENTA_O2 is not set
+# CONFIG_YENTA_RICOH is not set
+# CONFIG_YENTA_TI is not set
+# CONFIG_YENTA_TOSHIBA is not set
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+CONFIG_PCCARD_NONSTATIC=m
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+CONFIG_IPSEC_NAT_TRAVERSAL=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=y
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+CONFIG_IPV6_ROUTER_PREF=y
+# CONFIG_IPV6_ROUTE_INFO is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_BRIDGE_NETFILTER is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=y
+CONFIG_IP_NF_IRC=y
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+CONFIG_IP_NF_SIP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_IPP2P=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_TIME=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_IMQ=m
+# CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_ROUTE=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=y
+CONFIG_IP_NF_NAT_FTP=y
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_SET=m
+CONFIG_IP_NF_SET_MAX=256
+CONFIG_IP_NF_SET_HASHSIZE=1024
+CONFIG_IP_NF_SET_IPMAP=m
+CONFIG_IP_NF_SET_MACIPMAP=m
+CONFIG_IP_NF_SET_PORTMAP=m
+CONFIG_IP_NF_SET_IPHASH=m
+CONFIG_IP_NF_SET_NETHASH=m
+CONFIG_IP_NF_SET_IPTREE=m
+CONFIG_IP_NF_MATCH_SET=m
+CONFIG_IP_NF_TARGET_SET=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_OWNER=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_IMQ=m
+# CONFIG_IP6_NF_TARGET_LOG is not set
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_HL is not set
+# CONFIG_IP6_NF_RAW is not set
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_CLIP_NO_ICMP=y
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_ATM_BR2684_IPFILTER=y
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_ESFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CLS_U32_MARK is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_HAMRADIO=y
+
+#
+# Packet Radio protocols
+#
+CONFIG_AX25=m
+# CONFIG_AX25_DAMA_SLAVE is not set
+# CONFIG_NETROM is not set
+# CONFIG_ROSE is not set
+
+#
+# AX.25 network device drivers
+#
+CONFIG_MKISS=m
+# CONFIG_6PACK is not set
+# CONFIG_BPQETHER is not set
+# CONFIG_BAYCOM_SER_FDX is not set
+# CONFIG_BAYCOM_SER_HDX is not set
+# CONFIG_YAM is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBTUART is not set
+# CONFIG_BT_HCIVHCI is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+# CONFIG_IEEE80211_SOFTMAC is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=m
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=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
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_BCM47XX=y
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_IMQ=m
+# CONFIG_IMQ_BEHAVIOR_AA is not set
+# CONFIG_IMQ_BEHAVIOR_AB is not set
+CONFIG_IMQ_BEHAVIOR_BA=y
+# CONFIG_IMQ_BEHAVIOR_BB is not set
+CONFIG_IMQ_NUM_DEVS=2
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+CONFIG_B44=y
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_LAN_SAA9730 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 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)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+CONFIG_NET_WIRELESS_RTNETLINK=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_PCMCIA_WAVELAN is not set
+# CONFIG_PCMCIA_NETWAVE is not set
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_IPW2100=m
+CONFIG_IPW2100_MONITOR=y
+# CONFIG_IPW2100_DEBUG is not set
+CONFIG_IPW2200=m
+CONFIG_IPW2200_MONITOR=y
+CONFIG_IPW_QOS=y
+# CONFIG_IPW2200_DEBUG is not set
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+# CONFIG_AIRO_CS is not set
+# CONFIG_PCMCIA_WL3501 is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+# CONFIG_PRISM54 is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+CONFIG_HOSTAP_PLX=m
+CONFIG_HOSTAP_PCI=m
+CONFIG_HOSTAP_CS=m
+CONFIG_NET_WIRELESS=y
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ATM drivers
+#
+CONFIG_ATM_DUMMY=m
+CONFIG_ATM_TCP=m
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+# CONFIG_ATM_FORE200E_MAYBE is not set
+# CONFIG_ATM_HE is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=m
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=m
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_CS=m
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+# CONFIG_VIDEO_V4L1 is not set
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=y
+
+#
+# Video Capture Adapters
+#
+
+#
+# Video Capture Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA2 is not set
+
+#
+# Encoders and Decoders
+#
+
+#
+# V4L USB devices
+#
+
+#
+# Radio Adapters
+#
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+
+#
+# ALSA MIPS devices
+#
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=m
+
+#
+# PCMCIA devices
+#
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_PDAUDIOCF is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_SPLIT_ISO=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_LIBUSUAL 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_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+# CONFIG_USB_SERIAL_ANYDATA is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+CONFIG_USB_SERIAL_BELKIN=m
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+CONFIG_USB_SERIAL_FTDI_SIO=m
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+CONFIG_USB_SERIAL_VISOR=m
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=m
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET 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_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+# CONFIG_USB_CXACRU is not set
+CONFIG_USB_UEAGLEATM=m
+# CONFIG_USB_XUSBATM is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=m
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_SQUASHFS_VMALLOC is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=m
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_FS is not set
+CONFIG_CROSSCOMPILE=y
+CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=squashfs,jffs2 init=/etc/preinit noinitrd console=ttyS0,115200"
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/target/linux/brcm-2.6/patches/001-bcm947xx.patch b/target/linux/brcm-2.6/patches/001-bcm947xx.patch
new file mode 100644
index 0000000..be3ac94
--- /dev/null
+++ b/target/linux/brcm-2.6/patches/001-bcm947xx.patch
@@ -0,0 +1,11862 @@
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/broadcom/bcmsrom.c linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/bcmsrom.c
+--- linux-2.6.17/arch/mips/bcm947xx/broadcom/bcmsrom.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/bcmsrom.c 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,481 @@
++/*
++ * Misc useful routines to access NIC SROM/OTP .
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id$
++ */
++
++#include <typedefs.h>
++#include <osl.h>
++#include <bcmutils.h>
++#include <bcmsrom.h>
++#include <bcmdevs.h>
++#include <bcmendian.h>
++#include <pcicfg.h>
++#include <sbutils.h>
++
++#include <proto/ethernet.h> /* for sprom content groking */
++
++#define VARS_MAX 4096 /* should be reduced */
++
++#define WRITE_ENABLE_DELAY 500 /* 500 ms after write enable/disable toggle */
++#define WRITE_WORD_DELAY 20 /* 20 ms between each word write */
++
++static int initvars_srom_pci(void *sbh, void *curmap, char **vars, int *count);
++static int sprom_read_pci(uint16 *sprom, uint wordoff, uint16 *buf, uint nwords, bool check_crc);
++
++static int initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count);
++
++/*
++ * Initialize local vars from the right source for this platform.
++ * Return 0 on success, nonzero on error.
++ */
++int
++srom_var_init(void *sbh, uint bustype, void *curmap, osl_t *osh, char **vars, int *count)
++{
++ ASSERT(bustype == BUSTYPE(bustype));
++ if (vars == NULL || count == NULL)
++ return (0);
++
++ switch (BUSTYPE(bustype)) {
++
++ case PCI_BUS:
++ ASSERT(curmap); /* can not be NULL */
++ return initvars_srom_pci(sbh, curmap, vars, count);
++
++ default:
++ return 0;
++ }
++ return (-1);
++}
++
++/* support only 16-bit word read from srom */
++int
++srom_read(uint bustype, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf)
++{
++ void *srom;
++ uint off, nw;
++
++ ASSERT(bustype == BUSTYPE(bustype));
++
++ /* check input - 16-bit access only */
++ if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
++ return 1;
++
++ off = byteoff / 2;
++ nw = nbytes / 2;
++
++ if (BUSTYPE(bustype) == PCI_BUS) {
++ if (!curmap)
++ return 1;
++ srom = (uchar*)curmap + PCI_BAR0_SPROM_OFFSET;
++ if (sprom_read_pci(srom, off, buf, nw, FALSE))
++ return 1;
++ } else {
++ return 1;
++ }
++
++ return 0;
++}
++
++/* support only 16-bit word write into srom */
++int
++srom_write(uint bustype, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf)
++{
++ uint16 *srom;
++ uint i, off, nw, crc_range;
++ uint16 image[SPROM_SIZE], *p;
++ uint8 crc;
++ volatile uint32 val32;
++
++ ASSERT(bustype == BUSTYPE(bustype));
++
++ /* check input - 16-bit access only */
++ if (byteoff & 1 || nbytes & 1 || (byteoff + nbytes) > (SPROM_SIZE * 2))
++ return 1;
++
++ crc_range = (((BUSTYPE(bustype) == SDIO_BUS)) ? SPROM_SIZE : SPROM_CRC_RANGE) * 2;
++
++ /* if changes made inside crc cover range */
++ if (byteoff < crc_range) {
++ nw = (((byteoff + nbytes) > crc_range) ? byteoff + nbytes : crc_range) / 2;
++ /* read data including entire first 64 words from srom */
++ if (srom_read(bustype, curmap, osh, 0, nw * 2, image))
++ return 1;
++ /* make changes */
++ bcopy((void*)buf, (void*)&image[byteoff / 2], nbytes);
++ /* calculate crc */
++ htol16_buf(image, crc_range);
++ crc = ~hndcrc8((uint8 *)image, crc_range - 1, CRC8_INIT_VALUE);
++ ltoh16_buf(image, crc_range);
++ image[(crc_range / 2) - 1] = (crc << 8) | (image[(crc_range / 2) - 1] & 0xff);
++ p = image;
++ off = 0;
++ } else {
++ p = buf;
++ off = byteoff / 2;
++ nw = nbytes / 2;
++ }
++
++ if (BUSTYPE(bustype) == PCI_BUS) {
++ srom = (uint16*)((uchar*)curmap + PCI_BAR0_SPROM_OFFSET);
++ /* enable writes to the SPROM */
++ val32 = OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32));
++ val32 |= SPROM_WRITEEN;
++ OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32);
++ bcm_mdelay(WRITE_ENABLE_DELAY);
++ /* write srom */
++ for (i = 0; i < nw; i++) {
++ W_REG(&srom[off + i], p[i]);
++ bcm_mdelay(WRITE_WORD_DELAY);
++ }
++ /* disable writes to the SPROM */
++ OSL_PCI_WRITE_CONFIG(osh, PCI_SPROM_CONTROL, sizeof(uint32), val32 & ~SPROM_WRITEEN);
++ } else {
++ return 1;
++ }
++
++ bcm_mdelay(WRITE_ENABLE_DELAY);
++ return 0;
++}
++
++
++/*
++ * Read in and validate sprom.
++ * Return 0 on success, nonzero on error.
++ */
++static int
++sprom_read_pci(uint16 *sprom, uint wordoff, uint16 *buf, uint nwords, bool check_crc)
++{
++ int err = 0;
++ uint i;
++
++ /* read the sprom */
++ for (i = 0; i < nwords; i++)
++ buf[i] = R_REG(&sprom[wordoff + i]);
++
++ if (check_crc) {
++ /* fixup the endianness so crc8 will pass */
++ htol16_buf(buf, nwords * 2);
++ if (hndcrc8((uint8*)buf, nwords * 2, CRC8_INIT_VALUE) != CRC8_GOOD_VALUE)
++ err = 1;
++ /* now correct the endianness of the byte array */
++ ltoh16_buf(buf, nwords * 2);
++ }
++
++ return err;
++}
++
++/*
++* Create variable table from memory.
++* Return 0 on success, nonzero on error.
++*/
++static int
++initvars_table(osl_t *osh, char *start, char *end, char **vars, uint *count)
++{
++ int c = (int)(end - start);
++
++ /* do it only when there is more than just the null string */
++ if (c > 1) {
++ char *vp = MALLOC(osh, c);
++ ASSERT(vp);
++ if (!vp)
++ return BCME_NOMEM;
++ bcopy(start, vp, c);
++ *vars = vp;
++ *count = c;
++ }
++ else {
++ *vars = NULL;
++ *count = 0;
++ }
++
++ return 0;
++}
++
++/*
++ * Initialize nonvolatile variable table from sprom.
++ * Return 0 on success, nonzero on error.
++ */
++static int
++initvars_srom_pci(void *sbh, void *curmap, char **vars, int *count)
++{
++ uint16 w, b[64];
++ uint8 sromrev;
++ struct ether_addr ea;
++ char eabuf[32];
++ uint32 w32;
++ int woff, i;
++ char *vp, *base;
++ osl_t *osh = sb_osh(sbh);
++ int err;
++
++ /*
++ * Apply CRC over SROM content regardless SROM is present or not,
++ * and use variable <devpath>sromrev's existance in flash to decide
++ * if we should return an error when CRC fails or read SROM variables
++ * from flash.
++ */
++ sprom_read_pci((void*)((int8*)curmap + PCI_BAR0_SPROM_OFFSET), 0, b, sizeof(b)/sizeof(b[0]), TRUE);
++
++ /* top word of sprom contains version and crc8 */
++ sromrev = b[63] & 0xff;
++ /* bcm4401 sroms misprogrammed */
++ if (sromrev == 0x10)
++ sromrev = 1;
++
++ /* srom version check */
++ if (sromrev > 3)
++ return (-2);
++
++ ASSERT(vars);
++ ASSERT(count);
++
++ base = vp = MALLOC(osh, VARS_MAX);
++ ASSERT(vp);
++ if (!vp)
++ return -2;
++
++ vp += sprintf(vp, "sromrev=%d", sromrev);
++ vp++;
++
++ if (sromrev >= 3) {
++ /* New section takes over the 3th hardware function space */
++
++ /* Words 22+23 are 11a (mid) ofdm power offsets */
++ w32 = ((uint32)b[23] << 16) | b[22];
++ vp += sprintf(vp, "ofdmapo=%d", w32);
++ vp++;
++
++ /* Words 24+25 are 11a (low) ofdm power offsets */
++ w32 = ((uint32)b[25] << 16) | b[24];
++ vp += sprintf(vp, "ofdmalpo=%d", w32);
++ vp++;
++
++ /* Words 26+27 are 11a (high) ofdm power offsets */
++ w32 = ((uint32)b[27] << 16) | b[26];
++ vp += sprintf(vp, "ofdmahpo=%d", w32);
++ vp++;
++
++ /*GPIO LED Powersave duty cycle (oncount >> 24) (offcount >> 8)*/
++ w32 = ((uint32)b[43] << 24) | ((uint32)b[42] << 8);
++ vp += sprintf(vp, "gpiotimerval=%d", w32);
++
++ /*GPIO LED Powersave duty cycle (oncount >> 24) (offcount >> 8)*/
++ w32 = ((uint32)((unsigned char)(b[21] >> 8) & 0xFF) << 24) | /* oncount*/
++ ((uint32)((unsigned char)(b[21] & 0xFF)) << 8); /* offcount */
++ vp += sprintf(vp, "gpiotimerval=%d", w32);
++
++ vp++;
++ }
++
++ if (sromrev >= 2) {
++ /* New section takes over the 4th hardware function space */
++
++ /* Word 29 is max power 11a high/low */
++ w = b[29];
++ vp += sprintf(vp, "pa1himaxpwr=%d", w & 0xff);
++ vp++;
++ vp += sprintf(vp, "pa1lomaxpwr=%d", (w >> 8) & 0xff);
++ vp++;
++
++ /* Words 30-32 set the 11alow pa settings,
++ * 33-35 are the 11ahigh ones.
++ */
++ for (i = 0; i < 3; i++) {
++ vp += sprintf(vp, "pa1lob%d=%d", i, b[30 + i]);
++ vp++;
++ vp += sprintf(vp, "pa1hib%d=%d", i, b[33 + i]);
++ vp++;
++ }
++ w = b[59];
++ if (w == 0)
++ vp += sprintf(vp, "ccode=");
++ else
++ vp += sprintf(vp, "ccode=%c%c", (w >> 8), (w & 0xff));
++ vp++;
++
++ }
++
++ /* parameter section of sprom starts at byte offset 72 */
++ woff = 72/2;
++
++ /* first 6 bytes are il0macaddr */
++ ea.octet[0] = (b[woff] >> 8) & 0xff;
++ ea.octet[1] = b[woff] & 0xff;
++ ea.octet[2] = (b[woff+1] >> 8) & 0xff;
++ ea.octet[3] = b[woff+1] & 0xff;
++ ea.octet[4] = (b[woff+2] >> 8) & 0xff;
++ ea.octet[5] = b[woff+2] & 0xff;
++ woff += ETHER_ADDR_LEN/2 ;
++ bcm_ether_ntoa((uchar*)&ea, eabuf);
++ vp += sprintf(vp, "il0macaddr=%s", eabuf);
++ vp++;
++
++ /* next 6 bytes are et0macaddr */
++ ea.octet[0] = (b[woff] >> 8) & 0xff;
++ ea.octet[1] = b[woff] & 0xff;
++ ea.octet[2] = (b[woff+1] >> 8) & 0xff;
++ ea.octet[3] = b[woff+1] & 0xff;
++ ea.octet[4] = (b[woff+2] >> 8) & 0xff;
++ ea.octet[5] = b[woff+2] & 0xff;
++ woff += ETHER_ADDR_LEN/2 ;
++ bcm_ether_ntoa((uchar*)&ea, eabuf);
++ vp += sprintf(vp, "et0macaddr=%s", eabuf);
++ vp++;
++
++ /* next 6 bytes are et1macaddr */
++ ea.octet[0] = (b[woff] >> 8) & 0xff;
++ ea.octet[1] = b[woff] & 0xff;
++ ea.octet[2] = (b[woff+1] >> 8) & 0xff;
++ ea.octet[3] = b[woff+1] & 0xff;
++ ea.octet[4] = (b[woff+2] >> 8) & 0xff;
++ ea.octet[5] = b[woff+2] & 0xff;
++ woff += ETHER_ADDR_LEN/2 ;
++ bcm_ether_ntoa((uchar*)&ea, eabuf);
++ vp += sprintf(vp, "et1macaddr=%s", eabuf);
++ vp++;
++
++ /*
++ * Enet phy settings one or two singles or a dual
++ * Bits 4-0 : MII address for enet0 (0x1f for not there)
++ * Bits 9-5 : MII address for enet1 (0x1f for not there)
++ * Bit 14 : Mdio for enet0
++ * Bit 15 : Mdio for enet1
++ */
++ w = b[woff];
++ vp += sprintf(vp, "et0phyaddr=%d", (w & 0x1f));
++ vp++;
++ vp += sprintf(vp, "et1phyaddr=%d", ((w >> 5) & 0x1f));
++ vp++;
++ vp += sprintf(vp, "et0mdcport=%d", ((w >> 14) & 0x1));
++ vp++;
++ vp += sprintf(vp, "et1mdcport=%d", ((w >> 15) & 0x1));
++ vp++;
++
++ /* Word 46 has board rev, antennas 0/1 & Country code/control */
++ w = b[46];
++ vp += sprintf(vp, "boardrev=%d", w & 0xff);
++ vp++;
++
++ if (sromrev > 1)
++ vp += sprintf(vp, "cctl=%d", (w >> 8) & 0xf);
++ else
++ vp += sprintf(vp, "cc=%d", (w >> 8) & 0xf);
++ vp++;
++
++ vp += sprintf(vp, "aa0=%d", (w >> 12) & 0x3);
++ vp++;
++
++ vp += sprintf(vp, "aa1=%d", (w >> 14) & 0x3);
++ vp++;
++
++ /* Words 47-49 set the (wl) pa settings */
++ woff = 47;
++
++ for (i = 0; i < 3; i++) {
++ vp += sprintf(vp, "pa0b%d=%d", i, b[woff+i]);
++ vp++;
++ vp += sprintf(vp, "pa1b%d=%d", i, b[woff+i+6]);
++ vp++;
++ }
++
++ /*
++ * Words 50-51 set the customer-configured wl led behavior.
++ * 8 bits/gpio pin. High bit: activehi=0, activelo=1;
++ * LED behavior values defined in wlioctl.h .
++ */
++ w = b[50];
++ if ((w != 0) && (w != 0xffff)) {
++ /* gpio0 */
++ vp += sprintf(vp, "wl0gpio0=%d", (w & 0xff));
++ vp++;
++
++ /* gpio1 */
++ vp += sprintf(vp, "wl0gpio1=%d", (w >> 8) & 0xff);
++ vp++;
++ }
++ w = b[51];
++ if ((w != 0) && (w != 0xffff)) {
++ /* gpio2 */
++ vp += sprintf(vp, "wl0gpio2=%d", w & 0xff);
++ vp++;
++
++ /* gpio3 */
++ vp += sprintf(vp, "wl0gpio3=%d", (w >> 8) & 0xff);
++ vp++;
++ }
++
++ /* Word 52 is max power 0/1 */
++ w = b[52];
++ vp += sprintf(vp, "pa0maxpwr=%d", w & 0xff);
++ vp++;
++ vp += sprintf(vp, "pa1maxpwr=%d", (w >> 8) & 0xff);
++ vp++;
++
++ /* Word 56 is idle tssi target 0/1 */
++ w = b[56];
++ vp += sprintf(vp, "pa0itssit=%d", w & 0xff);
++ vp++;
++ vp += sprintf(vp, "pa1itssit=%d", (w >> 8) & 0xff);
++ vp++;
++
++ /* Word 57 is boardflags, if not programmed make it zero */
++ w32 = (uint32)b[57];
++ if (w32 == 0xffff) w32 = 0;
++ if (sromrev > 1) {
++ /* Word 28 is the high bits of boardflags */
++ w32 |= (uint32)b[28] << 16;
++ }
++ vp += sprintf(vp, "boardflags=%d", w32);
++ vp++;
++
++ /* Word 58 is antenna gain 0/1 */
++ w = b[58];
++ vp += sprintf(vp, "ag0=%d", w & 0xff);
++ vp++;
++
++ vp += sprintf(vp, "ag1=%d", (w >> 8) & 0xff);
++ vp++;
++
++ if (sromrev == 1) {
++ /* set the oem string */
++ vp += sprintf(vp, "oem=%02x%02x%02x%02x%02x%02x%02x%02x",
++ ((b[59] >> 8) & 0xff), (b[59] & 0xff),
++ ((b[60] >> 8) & 0xff), (b[60] & 0xff),
++ ((b[61] >> 8) & 0xff), (b[61] & 0xff),
++ ((b[62] >> 8) & 0xff), (b[62] & 0xff));
++ vp++;
++ } else if (sromrev == 2) {
++ /* Word 60 OFDM tx power offset from CCK level */
++ /* OFDM Power Offset - opo */
++ vp += sprintf(vp, "opo=%d", b[60] & 0xff);
++ vp++;
++ } else {
++ /* Word 60: cck power offsets */
++ vp += sprintf(vp, "cckpo=%d", b[60]);
++ vp++;
++
++ /* Words 61+62: 11g ofdm power offsets */
++ w32 = ((uint32)b[62] << 16) | b[61];
++ vp += sprintf(vp, "ofdmgpo=%d", w32);
++ vp++;
++ }
++
++ /* final nullbyte terminator */
++ *vp++ = '\0';
++
++ ASSERT((vp - base) <= VARS_MAX);
++
++ err = initvars_table(osh, base, vp, vars, count);
++
++ MFREE(osh, base, VARS_MAX);
++ return err;
++}
++
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/broadcom/bcmutils.c linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/bcmutils.c
+--- linux-2.6.17/arch/mips/bcm947xx/broadcom/bcmutils.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/bcmutils.c 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,356 @@
++/*
++ * Misc useful OS-independent routines.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id$
++ */
++
++#include <typedefs.h>
++#include <osl.h>
++#include <sbutils.h>
++#include <bcmnvram.h>
++#include <bcmutils.h>
++#include <bcmendian.h>
++#include <bcmdevs.h>
++
++unsigned char bcm_ctype[] = {
++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
++ _BCM_C,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C|_BCM_S,_BCM_C,_BCM_C, /* 8-15 */
++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
++ _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
++ _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
++ _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
++ _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
++ _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
++ _BCM_P,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U|_BCM_X,_BCM_U, /* 64-71 */
++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
++ _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
++ _BCM_P,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L|_BCM_X,_BCM_L, /* 96-103 */
++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
++ _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
++ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
++ _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 160-175 */
++ _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 176-191 */
++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 192-207 */
++ _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_L, /* 208-223 */
++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 224-239 */
++ _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L /* 240-255 */
++};
++
++uchar
++bcm_toupper(uchar c)
++{
++ if (bcm_islower(c))
++ c -= 'a'-'A';
++ return (c);
++}
++
++ulong
++bcm_strtoul(char *cp, char **endp, uint base)
++{
++ ulong result, value;
++ bool minus;
++
++ minus = FALSE;
++
++ while (bcm_isspace(*cp))
++ cp++;
++
++ if (cp[0] == '+')
++ cp++;
++ else if (cp[0] == '-') {
++ minus = TRUE;
++ cp++;
++ }
++
++ if (base == 0) {
++ if (cp[0] == '0') {
++ if ((cp[1] == 'x') || (cp[1] == 'X')) {
++ base = 16;
++ cp = &cp[2];
++ } else {
++ base = 8;
++ cp = &cp[1];
++ }
++ } else
++ base = 10;
++ } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
++ cp = &cp[2];
++ }
++
++ result = 0;
++
++ while (bcm_isxdigit(*cp) &&
++ (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
++ result = result*base + value;
++ cp++;
++ }
++
++ if (minus)
++ result = (ulong)(result * -1);
++
++ if (endp)
++ *endp = (char *)cp;
++
++ return (result);
++}
++
++uint
++bcm_atoi(char *s)
++{
++ uint n;
++
++ n = 0;
++
++ while (bcm_isdigit(*s))
++ n = (n * 10) + *s++ - '0';
++ return (n);
++}
++
++/* return pointer to location of substring 'needle' in 'haystack' */
++char*
++bcmstrstr(char *haystack, char *needle)
++{
++ int len, nlen;
++ int i;
++
++ if ((haystack == NULL) || (needle == NULL))
++ return (haystack);
++
++ nlen = strlen(needle);
++ len = strlen(haystack) - nlen + 1;
++
++ for (i = 0; i < len; i++)
++ if (bcmp(needle, &haystack[i], nlen) == 0)
++ return (&haystack[i]);
++ return (NULL);
++}
++
++char*
++bcmstrcat(char *dest, const char *src)
++{
++ strcpy(&dest[strlen(dest)], src);
++ return (dest);
++}
++
++
++char*
++bcm_ether_ntoa(char *ea, char *buf)
++{
++ sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x",
++ (uchar)ea[0]&0xff, (uchar)ea[1]&0xff, (uchar)ea[2]&0xff,
++ (uchar)ea[3]&0xff, (uchar)ea[4]&0xff, (uchar)ea[5]&0xff);
++ return (buf);
++}
++
++/* parse a xx:xx:xx:xx:xx:xx format ethernet address */
++int
++bcm_ether_atoe(char *p, char *ea)
++{
++ int i = 0;
++
++ for (;;) {
++ ea[i++] = (char) bcm_strtoul(p, &p, 16);
++ if (!*p++ || i == 6)
++ break;
++ }
++
++ return (i == 6);
++}
++
++void
++bcm_mdelay(uint ms)
++{
++ uint i;
++
++ for (i = 0; i < ms; i++) {
++ OSL_DELAY(1000);
++ }
++}
++
++/*
++ * Search the name=value vars for a specific one and return its value.
++ * Returns NULL if not found.
++ */
++char*
++getvar(char *vars, char *name)
++{
++ char *s;
++ int len;
++
++ len = strlen(name);
++
++ /* first look in vars[] */
++ for (s = vars; s && *s; ) {
++ if ((bcmp(s, name, len) == 0) && (s[len] == '='))
++ return (&s[len+1]);
++
++ while (*s++)
++ ;
++ }
++
++ /* then query nvram */
++ return (BCMINIT(nvram_get)(name));
++}
++
++/*
++ * Search the vars for a specific one and return its value as
++ * an integer. Returns 0 if not found.
++ */
++int
++getintvar(char *vars, char *name)
++{
++ char *val;
++
++ if ((val = getvar(vars, name)) == NULL)
++ return (0);
++
++ return (bcm_strtoul(val, NULL, 0));
++}
++
++
++/* Search for token in comma separated token-string */
++static int
++findmatch(char *string, char *name)
++{
++ uint len;
++ char *c;
++
++ len = strlen(name);
++ while ((c = strchr(string, ',')) != NULL) {
++ if (len == (uint)(c - string) && !strncmp(string, name, len))
++ return 1;
++ string = c + 1;
++ }
++
++ return (!strcmp(string, name));
++}
++
++/* Return gpio pin number assigned to the named pin */
++/*
++* Variable should be in format:
++*
++* gpio<N>=pin_name,pin_name
++*
++* This format allows multiple features to share the gpio with mutual
++* understanding.
++*
++* 'def_pin' is returned if a specific gpio is not defined for the requested functionality
++* and if def_pin is not used by others.
++*/
++uint
++getgpiopin(char *vars, char *pin_name, uint def_pin)
++{
++ char name[] = "gpioXXXX";
++ char *val;
++ uint pin;
++
++ /* Go thru all possibilities till a match in pin name */
++ for (pin = 0; pin < GPIO_NUMPINS; pin ++) {
++ sprintf(name, "gpio%d", pin);
++ val = getvar(vars, name);
++ if (val && findmatch(val, pin_name))
++ return pin;
++ }
++
++ if (def_pin != GPIO_PIN_NOTDEFINED) {
++ /* make sure the default pin is not used by someone else */
++ sprintf(name, "gpio%d", def_pin);
++ if (getvar(vars, name)) {
++ def_pin = GPIO_PIN_NOTDEFINED;
++ }
++ }
++
++ return def_pin;
++}
++
++
++/*******************************************************************************
++ * crc8
++ *
++ * Computes a crc8 over the input data using the polynomial:
++ *
++ * x^8 + x^7 +x^6 + x^4 + x^2 + 1
++ *
++ * The caller provides the initial value (either CRC8_INIT_VALUE
++ * or the previous returned value) to allow for processing of
++ * discontiguous blocks of data. When generating the CRC the
++ * caller is responsible for complementing the final return value
++ * and inserting it into the byte stream. When checking, a final
++ * return value of CRC8_GOOD_VALUE indicates a valid CRC.
++ *
++ * Reference: Dallas Semiconductor Application Note 27
++ * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
++ * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
++ * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
++ *
++ ******************************************************************************/
++
++static uint8 crc8_table[256] = {
++ 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
++ 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
++ 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
++ 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
++ 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
++ 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
++ 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
++ 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
++ 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
++ 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
++ 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
++ 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
++ 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
++ 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
++ 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
++ 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
++ 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
++ 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
++ 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
++ 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
++ 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
++ 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
++ 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
++ 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
++ 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
++ 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
++ 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
++ 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
++ 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
++ 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
++ 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
++ 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
++};
++
++#define CRC_INNER_LOOP(n, c, x) \
++ (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
++
++uint8
++hndcrc8(
++ uint8 *pdata, /* pointer to array of data to process */
++ uint nbytes, /* number of input data bytes to process */
++ uint8 crc /* either CRC8_INIT_VALUE or previous return value */
++)
++{
++ /* hard code the crc loop instead of using CRC_INNER_LOOP macro
++ * to avoid the undefined and unnecessary (uint8 >> 8) operation. */
++ while (nbytes-- > 0)
++ crc = crc8_table[(crc ^ *pdata++) & 0xff];
++
++ return crc;
++}
++
++#ifdef notdef
++#define CLEN 1499
++#define CBUFSIZ (CLEN+4)
++#define CNBUFS 5
++
++#endif
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/broadcom/cfe_env.c linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/cfe_env.c
+--- linux-2.6.17/arch/mips/bcm947xx/broadcom/cfe_env.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/cfe_env.c 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,234 @@
++/*
++ * NVRAM variable manipulation (Linux kernel half)
++ *
++ * Copyright 2001-2003, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++
++#include <typedefs.h>
++#include <osl.h>
++#include <bcmendian.h>
++#include <bcmutils.h>
++
++#define NVRAM_SIZE (0x1ff0)
++static char _nvdata[NVRAM_SIZE] __initdata;
++static char _valuestr[256] __initdata;
++
++/*
++ * TLV types. These codes are used in the "type-length-value"
++ * encoding of the items stored in the NVRAM device (flash or EEPROM)
++ *
++ * The layout of the flash/nvram is as follows:
++ *
++ * <type> <length> <data ...> <type> <length> <data ...> <type_end>
++ *
++ * The type code of "ENV_TLV_TYPE_END" marks the end of the list.
++ * The "length" field marks the length of the data section, not
++ * including the type and length fields.
++ *
++ * Environment variables are stored as follows:
++ *
++ * <type_env> <length> <flags> <name> = <value>
++ *
++ * If bit 0 (low bit) is set, the length is an 8-bit value.
++ * If bit 0 (low bit) is clear, the length is a 16-bit value
++ *
++ * Bit 7 set indicates "user" TLVs. In this case, bit 0 still
++ * indicates the size of the length field.
++ *
++ * Flags are from the constants below:
++ *
++ */
++#define ENV_LENGTH_16BITS 0x00 /* for low bit */
++#define ENV_LENGTH_8BITS 0x01
++
++#define ENV_TYPE_USER 0x80
++
++#define ENV_CODE_SYS(n,l) (((n)<<1)|(l))
++#define ENV_CODE_USER(n,l) ((((n)<<1)|(l)) | ENV_TYPE_USER)
++
++/*
++ * The actual TLV types we support
++ */
++
++#define ENV_TLV_TYPE_END 0x00
++#define ENV_TLV_TYPE_ENV ENV_CODE_SYS(0,ENV_LENGTH_8BITS)
++
++/*
++ * Environment variable flags
++ */
++
++#define ENV_FLG_NORMAL 0x00 /* normal read/write */
++#define ENV_FLG_BUILTIN 0x01 /* builtin - not stored in flash */
++#define ENV_FLG_READONLY 0x02 /* read-only - cannot be changed */
++
++#define ENV_FLG_MASK 0xFF /* mask of attributes we keep */
++#define ENV_FLG_ADMIN 0x100 /* lets us internally override permissions */
++
++
++/* *********************************************************************
++ * _nvram_read(buffer,offset,length)
++ *
++ * Read data from the NVRAM device
++ *
++ * Input parameters:
++ * buffer - destination buffer
++ * offset - offset of data to read
++ * length - number of bytes to read
++ *
++ * Return value:
++ * number of bytes read, or <0 if error occured
++ ********************************************************************* */
++static int
++_nvram_read(unsigned char *nv_buf, unsigned char *buffer, int offset, int length)
++{
++ int i;
++ if (offset > NVRAM_SIZE)
++ return -1;
++
++ for ( i = 0; i < length; i++) {
++ buffer[i] = ((volatile unsigned char*)nv_buf)[offset + i];
++ }
++ return length;
++}
++
++
++static char*
++_strnchr(const char *dest,int c,size_t cnt)
++{
++ while (*dest && (cnt > 0)) {
++ if (*dest == c) return (char *) dest;
++ dest++;
++ cnt--;
++ }
++ return NULL;
++}
++
++
++
++/*
++ * Core support API: Externally visible.
++ */
++
++/*
++ * Get the value of an NVRAM variable
++ * @param name name of variable to get
++ * @return value of variable or NULL if undefined
++ */
++
++char*
++cfe_env_get(unsigned char *nv_buf, char* name)
++{
++ int size;
++ unsigned char *buffer;
++ unsigned char *ptr;
++ unsigned char *envval;
++ unsigned int reclen;
++ unsigned int rectype;
++ int offset;
++ int flg;
++
++ size = NVRAM_SIZE;
++ buffer = &_nvdata[0];
++
++ ptr = buffer;
++ offset = 0;
++
++ /* Read the record type and length */
++ if (_nvram_read(nv_buf, ptr,offset,1) != 1) {
++ goto error;
++ }
++
++ while ((*ptr != ENV_TLV_TYPE_END) && (size > 1)) {
++
++ /* Adjust pointer for TLV type */
++ rectype = *(ptr);
++ offset++;
++ size--;
++
++ /*
++ * Read the length. It can be either 1 or 2 bytes
++ * depending on the code
++ */
++ if (rectype & ENV_LENGTH_8BITS) {
++ /* Read the record type and length - 8 bits */
++ if (_nvram_read(nv_buf, ptr,offset,1) != 1) {
++ goto error;
++ }
++ reclen = *(ptr);
++ size--;
++ offset++;
++ }
++ else {
++ /* Read the record type and length - 16 bits, MSB first */
++ if (_nvram_read(nv_buf, ptr,offset,2) != 2) {
++ goto error;
++ }
++ reclen = (((unsigned int) *(ptr)) << 8) + (unsigned int) *(ptr+1);
++ size -= 2;
++ offset += 2;
++ }
++
++ if (reclen > size)
++ break; /* should not happen, bad NVRAM */
++
++ switch (rectype) {
++ case ENV_TLV_TYPE_ENV:
++ /* Read the TLV data */
++ if (_nvram_read(nv_buf, ptr,offset,reclen) != reclen)
++ goto error;
++ flg = *ptr++;
++ envval = (unsigned char *) _strnchr(ptr,'=',(reclen-1));
++ if (envval) {
++ *envval++ = '\0';
++ memcpy(_valuestr,envval,(reclen-1)-(envval-ptr));
++ _valuestr[(reclen-1)-(envval-ptr)] = '\0';
++#if 0
++ printk(KERN_INFO "NVRAM:%s=%s\n", ptr, _valuestr);
++#endif
++ if(!strcmp(ptr, name)){
++ return _valuestr;
++ }
++ if((strlen(ptr) > 1) && !strcmp(&ptr[1], name))
++ return _valuestr;
++ }
++ break;
++
++ default:
++ /* Unknown TLV type, skip it. */
++ break;
++ }
++
++ /*
++ * Advance to next TLV
++ */
++
++ size -= (int)reclen;
++ offset += reclen;
++
++ /* Read the next record type */
++ ptr = buffer;
++ if (_nvram_read(nv_buf, ptr,offset,1) != 1)
++ goto error;
++ }
++
++error:
++ return NULL;
++
++}
++
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/broadcom/linux_osl.c linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/linux_osl.c
+--- linux-2.6.17/arch/mips/bcm947xx/broadcom/linux_osl.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/linux_osl.c 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,102 @@
++/*
++ * Linux OS Independent Layer
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#define LINUX_OSL
++
++#include <typedefs.h>
++#include <bcmendian.h>
++#include <linux/module.h>
++#include <linuxver.h>
++#include <osl.h>
++#include <bcmutils.h>
++#include <linux/delay.h>
++#ifdef mips
++#include <asm/paccess.h>
++#endif
++#include <pcicfg.h>
++
++#define PCI_CFG_RETRY 10
++
++#define OS_HANDLE_MAGIC 0x1234abcd
++#define BCM_MEM_FILENAME_LEN 24
++
++typedef struct bcm_mem_link {
++ struct bcm_mem_link *prev;
++ struct bcm_mem_link *next;
++ uint size;
++ int line;
++ char file[BCM_MEM_FILENAME_LEN];
++} bcm_mem_link_t;
++
++struct os_handle {
++ uint magic;
++ void *pdev;
++ uint malloced;
++ uint failed;
++ bcm_mem_link_t *dbgmem_list;
++};
++
++uint32
++osl_pci_read_config(osl_t *osh, uint offset, uint size)
++{
++ uint val;
++ uint retry=PCI_CFG_RETRY;
++
++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
++
++ /* only 4byte access supported */
++ ASSERT(size == 4);
++
++ do {
++ pci_read_config_dword(osh->pdev, offset, &val);
++ if (val != 0xffffffff)
++ break;
++ } while (retry--);
++
++
++ return (val);
++}
++
++void
++osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val)
++{
++ uint retry=PCI_CFG_RETRY;
++
++ ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
++
++ /* only 4byte access supported */
++ ASSERT(size == 4);
++
++ do {
++ pci_write_config_dword(osh->pdev, offset, val);
++ if (offset!=PCI_BAR0_WIN)
++ break;
++ if (osl_pci_read_config(osh,offset,size) == val)
++ break;
++ } while (retry--);
++
++}
++
++void
++osl_delay(uint usec)
++{
++ uint d;
++
++ while (usec > 0) {
++ d = MIN(usec, 1000);
++ udelay(d);
++ usec -= d;
++ }
++}
++
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/broadcom/Makefile linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/Makefile
+--- linux-2.6.17/arch/mips/bcm947xx/broadcom/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/Makefile 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,6 @@
++#
++# Makefile for the BCM47xx specific kernel interface routines
++# under Linux.
++#
++
++obj-y := sbutils.o linux_osl.o bcmsrom.o bcmutils.o sbmips.o sbpci.o sflash.o nvram.o cfe_env.o
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/broadcom/nvram.c linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/nvram.c
+--- linux-2.6.17/arch/mips/bcm947xx/broadcom/nvram.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/nvram.c 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,192 @@
++/*
++ * NVRAM variable manipulation (Linux kernel half)
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <asm/bootinfo.h>
++#include <asm/addrspace.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++
++#include <typedefs.h>
++#include <bcmendian.h>
++#include <bcmnvram.h>
++#include <bcmutils.h>
++#include <sbconfig.h>
++#include <sbchipc.h>
++#include <sbutils.h>
++#include <sbmips.h>
++#include <sflash.h>
++
++/* In BSS to minimize text size and page aligned so it can be mmap()-ed */
++static char nvram_buf[NVRAM_SPACE] __attribute__((aligned(PAGE_SIZE)));
++
++/* Global SB handle */
++extern void *sbh;
++extern spinlock_t bcm947xx_sbh_lock;
++static int cfe_env;
++
++extern char *cfe_env_get(char *nv_buf, const char *name);
++
++
++/* Convenience */
++#define sbh_lock bcm947xx_sbh_lock
++#define KB * 1024
++#define MB * 1024 * 1024
++
++/* Probe for NVRAM header */
++static void __init
++early_nvram_init(void)
++{
++ struct nvram_header *header;
++ chipcregs_t *cc;
++ struct sflash *info = NULL;
++ int i;
++ uint32 base, off, lim;
++ u32 *src, *dst;
++
++ cfe_env = 0;
++ if ((cc = sb_setcore(sbh, SB_CC, 0)) != NULL) {
++ base = KSEG1ADDR(SB_FLASH2);
++ switch (readl(&cc->capabilities) & CAP_FLASH_MASK) {
++ case PFLASH:
++ lim = SB_FLASH2_SZ;
++ break;
++
++ case SFLASH_ST:
++ case SFLASH_AT:
++ if ((info = sflash_init(cc)) == NULL)
++ return;
++ lim = info->size;
++ break;
++
++ case FLASH_NONE:
++ default:
++ return;
++ }
++ } else {
++ /* extif assumed, Stop at 4 MB */
++ base = KSEG1ADDR(SB_FLASH1);
++ lim = SB_FLASH1_SZ;
++ }
++
++ /* XXX: hack for supporting the CFE environment stuff on WGT634U */
++ src = (u32 *) KSEG1ADDR(base + 8 * 1024 * 1024 - 0x2000);
++ dst = (u32 *) nvram_buf;
++ if ((lim == 0x02000000) && ((*src & 0xff00ff) == 0x000001)) {
++ printk("early_nvram_init: WGT634U NVRAM found.\n");
++
++ for (i = 0; i < 0x1ff0; i++) {
++ if (*src == 0xFFFFFFFF)
++ break;
++ *dst++ = *src++;
++ }
++ cfe_env = 1;
++ return;
++ }
++
++ off = FLASH_MIN;
++ while (off <= lim) {
++ /* Windowed flash access */
++ header = (struct nvram_header *) KSEG1ADDR(base + off - NVRAM_SPACE);
++ if (header->magic == NVRAM_MAGIC)
++ goto found;
++ off <<= 1;
++ }
++
++ /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
++ header = (struct nvram_header *) KSEG1ADDR(base + 4 KB);
++ if (header->magic == NVRAM_MAGIC)
++ goto found;
++
++ header = (struct nvram_header *) KSEG1ADDR(base + 1 KB);
++ if (header->magic == NVRAM_MAGIC)
++ goto found;
++
++ return;
++
++found:
++ src = (u32 *) header;
++ dst = (u32 *) nvram_buf;
++ for (i = 0; i < sizeof(struct nvram_header); i += 4)
++ *dst++ = *src++;
++ for (; i < header->len && i < NVRAM_SPACE; i += 4)
++ *dst++ = ltoh32(*src++);
++}
++
++/* Early (before mm or mtd) read-only access to NVRAM */
++char * __init early_nvram_get(const char *name)
++{
++ char *var, *value, *end, *eq;
++
++ if (!name)
++ return NULL;
++
++ /* Too early? */
++ if (sbh == NULL)
++ return NULL;
++
++ if (!nvram_buf[0])
++ early_nvram_init();
++
++ if (cfe_env)
++ return cfe_env_get(nvram_buf, name);
++
++ /* Look for name=value and return value */
++ var = &nvram_buf[sizeof(struct nvram_header)];
++ end = nvram_buf + sizeof(nvram_buf) - 2;
++ end[0] = end[1] = '\0';
++ for (; *var; var = value + strlen(value) + 1) {
++ if (!(eq = strchr(var, '=')))
++ break;
++ value = eq + 1;
++ if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
++ return value;
++ }
++
++ return NULL;
++}
++
++char *nvram_get(const char *name)
++{
++ char *var, *value, *end, *eq;
++
++ if (!name)
++ return NULL;
++
++ if (!nvram_buf[0])
++ return NULL;
++
++ /* Look for name=value and return value */
++ var = &nvram_buf[sizeof(struct nvram_header)];
++ end = nvram_buf + sizeof(nvram_buf) - 2;
++ end[0] = end[1] = '\0';
++ for (; *var; var = value + strlen(value) + 1) {
++ if (!(eq = strchr(var, '=')))
++ break;
++ value = eq + 1;
++ if ((eq - var) == strlen(name) && strncmp(var, name, (eq - var)) == 0)
++ return value;
++ }
++
++ return NULL;
++}
++
++EXPORT_SYMBOL(nvram_get);
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/broadcom/sbmips.c linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/sbmips.c
+--- linux-2.6.17/arch/mips/bcm947xx/broadcom/sbmips.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/sbmips.c 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,1055 @@
++/*
++ * BCM47XX Sonics SiliconBackplane MIPS core routines
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#include <typedefs.h>
++#include <osl.h>
++#include <sbutils.h>
++#include <bcmdevs.h>
++#include <bcmnvram.h>
++#include <bcmutils.h>
++#include <hndmips.h>
++#include <sbconfig.h>
++#include <sbextif.h>
++#include <sbchipc.h>
++#include <sbmemc.h>
++#include <mipsinc.h>
++#include <sbutils.h>
++
++/*
++ * Returns TRUE if an external UART exists at the given base
++ * register.
++ */
++static bool
++BCMINITFN(serial_exists)(uint8 *regs)
++{
++ uint8 save_mcr, status1;
++
++ save_mcr = R_REG(&regs[UART_MCR]);
++ W_REG(&regs[UART_MCR], UART_MCR_LOOP | 0x0a);
++ status1 = R_REG(&regs[UART_MSR]) & 0xf0;
++ W_REG(&regs[UART_MCR], save_mcr);
++
++ return (status1 == 0x90);
++}
++
++/*
++ * Initializes UART access. The callback function will be called once
++ * per found UART.
++ */
++void
++BCMINITFN(sb_serial_init)(sb_t *sbh, void (*add)(void *regs, uint irq, uint baud_base, uint reg_shift))
++{
++ void *regs;
++ ulong base;
++ uint irq;
++ int i, n;
++
++ if ((regs = sb_setcore(sbh, SB_EXTIF, 0))) {
++ extifregs_t *eir = (extifregs_t *) regs;
++ sbconfig_t *sb;
++
++ /* Determine external UART register base */
++ sb = (sbconfig_t *)((ulong) eir + SBCONFIGOFF);
++ base = EXTIF_CFGIF_BASE(sb_base(R_REG(&sb->sbadmatch1)));
++
++ /* Determine IRQ */
++ irq = sb_irq(sbh);
++
++ /* Disable GPIO interrupt initially */
++ W_REG(&eir->gpiointpolarity, 0);
++ W_REG(&eir->gpiointmask, 0);
++
++ /* Search for external UARTs */
++ n = 2;
++ for (i = 0; i < 2; i++) {
++ regs = (void *) REG_MAP(base + (i * 8), 8);
++ if (BCMINIT(serial_exists)(regs)) {
++ /* Set GPIO 1 to be the external UART IRQ */
++ W_REG(&eir->gpiointmask, 2);
++ if (add)
++ add(regs, irq, 13500000, 0);
++ }
++ }
++
++ /* Add internal UART if enabled */
++ if (R_REG(&eir->corecontrol) & CC_UE)
++ if (add)
++ add((void *) &eir->uartdata, irq, sb_clock(sbh), 2);
++ } else if ((regs = sb_setcore(sbh, SB_CC, 0))) {
++ chipcregs_t *cc = (chipcregs_t *) regs;
++ uint32 rev, cap, pll, baud_base, div;
++
++ /* Determine core revision and capabilities */
++ rev = sb_corerev(sbh);
++ cap = R_REG(&cc->capabilities);
++ pll = cap & CAP_PLL_MASK;
++
++ /* Determine IRQ */
++ irq = sb_irq(sbh);
++
++ if (pll == PLL_TYPE1) {
++ /* PLL clock */
++ baud_base = sb_clock_rate(pll,
++ R_REG(&cc->clockcontrol_n),
++ R_REG(&cc->clockcontrol_m2));
++ div = 1;
++ } else {
++ if (rev >= 11) {
++ /* Fixed ALP clock */
++ baud_base = 20000000;
++ div = 1;
++ /* Set the override bit so we don't divide it */
++ W_REG(&cc->corecontrol, CC_UARTCLKO);
++ } else if (rev >= 3) {
++ /* Internal backplane clock */
++ baud_base = sb_clock(sbh);
++ div = 2; /* Minimum divisor */
++ W_REG(&cc->clkdiv,
++ ((R_REG(&cc->clkdiv) & ~CLKD_UART) | div));
++ } else {
++ /* Fixed internal backplane clock */
++ baud_base = 88000000;
++ div = 48;
++ }
++
++ /* Clock source depends on strapping if UartClkOverride is unset */
++ if ((rev > 0) &&
++ ((R_REG(&cc->corecontrol) & CC_UARTCLKO) == 0)) {
++ if ((cap & CAP_UCLKSEL) == CAP_UINTCLK) {
++ /* Internal divided backplane clock */
++ baud_base /= div;
++ } else {
++ /* Assume external clock of 1.8432 MHz */
++ baud_base = 1843200;
++ }
++ }
++ }
++
++ /* Add internal UARTs */
++ n = cap & CAP_UARTS_MASK;
++ for (i = 0; i < n; i++) {
++ /* Register offset changed after revision 0 */
++ if (rev)
++ regs = (void *)((ulong) &cc->uart0data + (i * 256));
++ else
++ regs = (void *)((ulong) &cc->uart0data + (i * 8));
++
++ if (add)
++ add(regs, irq, baud_base, 0);
++ }
++ }
++}
++
++/*
++ * Initialize jtag master and return handle for
++ * jtag_rwreg. Returns NULL on failure.
++ */
++void *
++sb_jtagm_init(sb_t *sbh, uint clkd, bool exttap)
++{
++ void *regs;
++
++ if ((regs = sb_setcore(sbh, SB_CC, 0)) != NULL) {
++ chipcregs_t *cc = (chipcregs_t *) regs;
++ uint32 tmp;
++
++ /*
++ * Determine jtagm availability from
++ * core revision and capabilities.
++ */
++ tmp = sb_corerev(sbh);
++ /*
++ * Corerev 10 has jtagm, but the only chip
++ * with it does not have a mips, and
++ * the layout of the jtagcmd register is
++ * different. We'll only accept >= 11.
++ */
++ if (tmp < 11)
++ return (NULL);
++
++ tmp = R_REG(&cc->capabilities);
++ if ((tmp & CAP_JTAGP) == 0)
++ return (NULL);
++
++ /* Set clock divider if requested */
++ if (clkd != 0) {
++ tmp = R_REG(&cc->clkdiv);
++ tmp = (tmp & ~CLKD_JTAG) |
++ ((clkd << CLKD_JTAG_SHIFT) & CLKD_JTAG);
++ W_REG(&cc->clkdiv, tmp);
++ }
++
++ /* Enable jtagm */
++ tmp = JCTRL_EN | (exttap ? JCTRL_EXT_EN : 0);
++ W_REG(&cc->jtagctrl, tmp);
++ }
++
++ return (regs);
++}
++
++void
++sb_jtagm_disable(void *h)
++{
++ chipcregs_t *cc = (chipcregs_t *)h;
++
++ W_REG(&cc->jtagctrl, R_REG(&cc->jtagctrl) & ~JCTRL_EN);
++}
++
++/*
++ * Read/write a jtag register. Assumes a target with
++ * 8 bit IR and 32 bit DR.
++ */
++#define IRWIDTH 8
++#define DRWIDTH 32
++uint32
++jtag_rwreg(void *h, uint32 ir, uint32 dr)
++{
++ chipcregs_t *cc = (chipcregs_t *) h;
++ uint32 tmp;
++
++ W_REG(&cc->jtagir, ir);
++ W_REG(&cc->jtagdr, dr);
++ tmp = JCMD_START | JCMD_ACC_IRDR |
++ ((IRWIDTH - 1) << JCMD_IRW_SHIFT) |
++ (DRWIDTH - 1);
++ W_REG(&cc->jtagcmd, tmp);
++ while (((tmp = R_REG(&cc->jtagcmd)) & JCMD_BUSY) == JCMD_BUSY) {
++ /* OSL_DELAY(1); */
++ }
++
++ tmp = R_REG(&cc->jtagdr);
++ return (tmp);
++}
++
++/* Returns the SB interrupt flag of the current core. */
++uint32
++sb_flag(sb_t *sbh)
++{
++ void *regs;
++ sbconfig_t *sb;
++
++ regs = sb_coreregs(sbh);
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++
++ return (R_REG(&sb->sbtpsflag) & SBTPS_NUM0_MASK);
++}
++
++static const uint32 sbips_int_mask[] = {
++ 0,
++ SBIPS_INT1_MASK,
++ SBIPS_INT2_MASK,
++ SBIPS_INT3_MASK,
++ SBIPS_INT4_MASK
++};
++
++static const uint32 sbips_int_shift[] = {
++ 0,
++ 0,
++ SBIPS_INT2_SHIFT,
++ SBIPS_INT3_SHIFT,
++ SBIPS_INT4_SHIFT
++};
++
++/*
++ * Returns the MIPS IRQ assignment of the current core. If unassigned,
++ * 0 is returned.
++ */
++uint
++sb_irq(sb_t *sbh)
++{
++ uint idx;
++ void *regs;
++ sbconfig_t *sb;
++ uint32 flag, sbipsflag;
++ uint irq = 0;
++
++ flag = sb_flag(sbh);
++
++ idx = sb_coreidx(sbh);
++
++ if ((regs = sb_setcore(sbh, SB_MIPS, 0)) ||
++ (regs = sb_setcore(sbh, SB_MIPS33, 0))) {
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++
++ /* sbipsflag specifies which core is routed to interrupts 1 to 4 */
++ sbipsflag = R_REG(&sb->sbipsflag);
++ for (irq = 1; irq <= 4; irq++) {
++ if (((sbipsflag & sbips_int_mask[irq]) >> sbips_int_shift[irq]) == flag)
++ break;
++ }
++ if (irq == 5)
++ irq = 0;
++ }
++
++ sb_setcoreidx(sbh, idx);
++
++ return irq;
++}
++
++/* Clears the specified MIPS IRQ. */
++static void
++BCMINITFN(sb_clearirq)(sb_t *sbh, uint irq)
++{
++ void *regs;
++ sbconfig_t *sb;
++
++ if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
++ !(regs = sb_setcore(sbh, SB_MIPS33, 0)))
++ ASSERT(regs);
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++
++ if (irq == 0)
++ W_REG(&sb->sbintvec, 0);
++ else
++ OR_REG(&sb->sbipsflag, sbips_int_mask[irq]);
++}
++
++/*
++ * Assigns the specified MIPS IRQ to the specified core. Shared MIPS
++ * IRQ 0 may be assigned more than once.
++ */
++static void
++BCMINITFN(sb_setirq)(sb_t *sbh, uint irq, uint coreid, uint coreunit)
++{
++ void *regs;
++ sbconfig_t *sb;
++ uint32 flag;
++
++ regs = sb_setcore(sbh, coreid, coreunit);
++ ASSERT(regs);
++ flag = sb_flag(sbh);
++
++ if (!(regs = sb_setcore(sbh, SB_MIPS, 0)) &&
++ !(regs = sb_setcore(sbh, SB_MIPS33, 0)))
++ ASSERT(regs);
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++
++ if (irq == 0)
++ OR_REG(&sb->sbintvec, 1 << flag);
++ else {
++ flag <<= sbips_int_shift[irq];
++ ASSERT(!(flag & ~sbips_int_mask[irq]));
++ flag |= R_REG(&sb->sbipsflag) & ~sbips_int_mask[irq];
++ W_REG(&sb->sbipsflag, flag);
++ }
++}
++
++/*
++ * Initializes clocks and interrupts. SB and NVRAM access must be
++ * initialized prior to calling.
++ */
++void
++BCMINITFN(sb_mips_init)(sb_t *sbh)
++{
++ ulong hz, ns, tmp;
++ extifregs_t *eir;
++ chipcregs_t *cc;
++ char *value;
++ uint irq;
++
++ /* Figure out current SB clock speed */
++ if ((hz = sb_clock(sbh)) == 0)
++ hz = 100000000;
++ ns = 1000000000 / hz;
++
++ /* Setup external interface timing */
++ if ((eir = sb_setcore(sbh, SB_EXTIF, 0))) {
++ /* Initialize extif so we can get to the LEDs and external UART */
++ W_REG(&eir->prog_config, CF_EN);
++
++ /* Set timing for the flash */
++ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
++ tmp = tmp | (CEIL(40, ns) << FW_W1_SHIFT); /* W1 = 40nS */
++ tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
++ W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
++
++ /* Set programmable interface timing for external uart */
++ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
++ tmp = tmp | (CEIL(20, ns) << FW_W2_SHIFT); /* W2 = 20nS */
++ tmp = tmp | (CEIL(100, ns) << FW_W1_SHIFT); /* W1 = 100nS */
++ tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
++ W_REG(&eir->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
++ } else if ((cc = sb_setcore(sbh, SB_CC, 0))) {
++ /* set register for external IO to control LED. */
++ W_REG(&cc->prog_config, 0x11);
++ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
++ tmp = tmp | (CEIL(40, ns) << FW_W1_SHIFT); /* W1 = 40nS */
++ tmp = tmp | CEIL(240, ns); /* W0 = 120nS */
++ W_REG(&cc->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
++
++ /* Set timing for the flash */
++ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
++ tmp |= CEIL(10, ns) << FW_W1_SHIFT; /* W1 = 10nS */
++ tmp |= CEIL(120, ns); /* W0 = 120nS */
++
++ // Added by Chen-I for 5365
++ if (BCMINIT(sb_chip)(sbh) == BCM5365_DEVICE_ID)
++ {
++ W_REG(&cc->flash_waitcount, tmp);
++ W_REG(&cc->pcmcia_memwait, tmp);
++ }
++ else
++ {
++ if (sb_corerev(sbh) < 9)
++ W_REG(&cc->flash_waitcount, tmp);
++
++ if ((sb_corerev(sbh) < 9) ||
++ ((BCMINIT(sb_chip)(sbh) == BCM5350_DEVICE_ID) && BCMINIT(sb_chiprev)(sbh) == 0)) {
++ W_REG(&cc->pcmcia_memwait, tmp);
++ }
++ }
++ // Added by Chen-I & Yen for enabling 5350 EXTIF
++ if (BCMINIT(sb_chip)(sbh) == BCM5350_DEVICE_ID)
++ {
++ /* Set programmable interface timing for external uart */
++ tmp = CEIL(10, ns) << FW_W3_SHIFT; /* W3 = 10nS */
++ tmp = tmp | (CEIL(20, ns) << FW_W2_SHIFT); /* W2 = 20nS */
++ tmp = tmp | (CEIL(100, ns) << FW_W1_SHIFT); /* W1 = 100nS */
++ tmp = tmp | CEIL(120, ns); /* W0 = 120nS */
++ W_REG(&cc->prog_waitcount, tmp); /* 0x01020a0c for a 100Mhz clock */
++ }
++ }
++
++ /* Chip specific initialization */
++ switch (BCMINIT(sb_chip)(sbh)) {
++ case BCM4710_DEVICE_ID:
++ /* Clear interrupt map */
++ for (irq = 0; irq <= 4; irq++)
++ BCMINIT(sb_clearirq)(sbh, irq);
++ BCMINIT(sb_setirq)(sbh, 0, SB_CODEC, 0);
++ BCMINIT(sb_setirq)(sbh, 0, SB_EXTIF, 0);
++ BCMINIT(sb_setirq)(sbh, 2, SB_ENET, 1);
++ BCMINIT(sb_setirq)(sbh, 3, SB_ILINE20, 0);
++ BCMINIT(sb_setirq)(sbh, 4, SB_PCI, 0);
++ ASSERT(eir);
++ value = BCMINIT(early_nvram_get)("et0phyaddr");
++ if (value && !strcmp(value, "31")) {
++ /* Enable internal UART */
++ W_REG(&eir->corecontrol, CC_UE);
++ /* Give USB its own interrupt */
++ BCMINIT(sb_setirq)(sbh, 1, SB_USB, 0);
++ } else {
++ /* Disable internal UART */
++ W_REG(&eir->corecontrol, 0);
++ /* Give Ethernet its own interrupt */
++ BCMINIT(sb_setirq)(sbh, 1, SB_ENET, 0);
++ BCMINIT(sb_setirq)(sbh, 0, SB_USB, 0);
++ }
++ break;
++ case BCM5350_DEVICE_ID:
++ /* Clear interrupt map */
++ for (irq = 0; irq <= 4; irq++)
++ BCMINIT(sb_clearirq)(sbh, irq);
++ BCMINIT(sb_setirq)(sbh, 0, SB_CC, 0);
++ BCMINIT(sb_setirq)(sbh, 1, SB_D11, 0);
++ BCMINIT(sb_setirq)(sbh, 2, SB_ENET, 0);
++ BCMINIT(sb_setirq)(sbh, 3, SB_PCI, 0);
++ BCMINIT(sb_setirq)(sbh, 4, SB_USB, 0);
++ break;
++ }
++}
++
++uint32
++BCMINITFN(sb_mips_clock)(sb_t *sbh)
++{
++ extifregs_t *eir;
++ chipcregs_t *cc;
++ uint32 n, m;
++ uint idx;
++ uint32 pll_type, rate = 0;
++
++ /* get index of the current core */
++ idx = sb_coreidx(sbh);
++ pll_type = PLL_TYPE1;
++
++ /* switch to extif or chipc core */
++ if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
++ n = R_REG(&eir->clockcontrol_n);
++ m = R_REG(&eir->clockcontrol_sb);
++ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
++ pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
++ n = R_REG(&cc->clockcontrol_n);
++ if ((pll_type == PLL_TYPE2) ||
++ (pll_type == PLL_TYPE4) ||
++ (pll_type == PLL_TYPE6) ||
++ (pll_type == PLL_TYPE7))
++ m = R_REG(&cc->clockcontrol_mips);
++ else if (pll_type == PLL_TYPE5) {
++ rate = 200000000;
++ goto out;
++ }
++ else if (pll_type == PLL_TYPE3) {
++ if (BCMINIT(sb_chip)(sbh) == BCM5365_DEVICE_ID) { /* 5365 is also type3 */
++ rate = 200000000;
++ goto out;
++ } else
++ m = R_REG(&cc->clockcontrol_m2); /* 5350 uses m2 to control mips */
++ } else
++ m = R_REG(&cc->clockcontrol_sb);
++ } else
++ goto out;
++
++ // Added by Chen-I for 5365
++ if (BCMINIT(sb_chip)(sbh) == BCM5365_DEVICE_ID)
++ rate = 100000000;
++ else
++ /* calculate rate */
++ rate = sb_clock_rate(pll_type, n, m);
++
++ if (pll_type == PLL_TYPE6)
++ rate = SB2MIPS_T6(rate);
++
++out:
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++
++ return rate;
++}
++
++#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
++
++static void
++BCMINITFN(handler)(void)
++{
++ /* Step 11 */
++ __asm__ (
++ ".set\tmips32\n\t"
++ "ssnop\n\t"
++ "ssnop\n\t"
++ /* Disable interrupts */
++ /* MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~(ALLINTS | STO_IE)); */
++ "mfc0 $15, $12\n\t"
++ /* Just a Hack to not to use reg 'at' which was causing problems on 4704 A2 */
++ "li $14, -31746\n\t"
++ "and $15, $15, $14\n\t"
++ "mtc0 $15, $12\n\t"
++ "eret\n\t"
++ "nop\n\t"
++ "nop\n\t"
++ ".set\tmips0"
++ );
++}
++
++/* The following MUST come right after handler() */
++static void
++BCMINITFN(afterhandler)(void)
++{
++}
++
++/*
++ * Set the MIPS, backplane and PCI clocks as closely as possible.
++ */
++bool
++BCMINITFN(sb_mips_setclock)(sb_t *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock)
++{
++ extifregs_t *eir = NULL;
++ chipcregs_t *cc = NULL;
++ mipsregs_t *mipsr = NULL;
++ volatile uint32 *clockcontrol_n, *clockcontrol_sb, *clockcontrol_pci, *clockcontrol_m2;
++ uint32 orig_n, orig_sb, orig_pci, orig_m2, orig_mips, orig_ratio_parm, orig_ratio_cfg;
++ uint32 pll_type, sync_mode;
++ uint ic_size, ic_lsize;
++ uint idx, i;
++ typedef struct {
++ uint32 mipsclock;
++ uint16 n;
++ uint32 sb;
++ uint32 pci33;
++ uint32 pci25;
++ } n3m_table_t;
++ static n3m_table_t BCMINITDATA(type1_table)[] = {
++ { 96000000, 0x0303, 0x04020011, 0x11030011, 0x11050011 }, /* 96.000 32.000 24.000 */
++ { 100000000, 0x0009, 0x04020011, 0x11030011, 0x11050011 }, /* 100.000 33.333 25.000 */
++ { 104000000, 0x0802, 0x04020011, 0x11050009, 0x11090009 }, /* 104.000 31.200 24.960 */
++ { 108000000, 0x0403, 0x04020011, 0x11050009, 0x02000802 }, /* 108.000 32.400 24.923 */
++ { 112000000, 0x0205, 0x04020011, 0x11030021, 0x02000403 }, /* 112.000 32.000 24.889 */
++ { 115200000, 0x0303, 0x04020009, 0x11030011, 0x11050011 }, /* 115.200 32.000 24.000 */
++ { 120000000, 0x0011, 0x04020011, 0x11050011, 0x11090011 }, /* 120.000 30.000 24.000 */
++ { 124800000, 0x0802, 0x04020009, 0x11050009, 0x11090009 }, /* 124.800 31.200 24.960 */
++ { 128000000, 0x0305, 0x04020011, 0x11050011, 0x02000305 }, /* 128.000 32.000 24.000 */
++ { 132000000, 0x0603, 0x04020011, 0x11050011, 0x02000305 }, /* 132.000 33.000 24.750 */
++ { 136000000, 0x0c02, 0x04020011, 0x11090009, 0x02000603 }, /* 136.000 32.640 24.727 */
++ { 140000000, 0x0021, 0x04020011, 0x11050021, 0x02000c02 }, /* 140.000 30.000 24.706 */
++ { 144000000, 0x0405, 0x04020011, 0x01020202, 0x11090021 }, /* 144.000 30.857 24.686 */
++ { 150857142, 0x0605, 0x04020021, 0x02000305, 0x02000605 }, /* 150.857 33.000 24.000 */
++ { 152000000, 0x0e02, 0x04020011, 0x11050021, 0x02000e02 }, /* 152.000 32.571 24.000 */
++ { 156000000, 0x0802, 0x04020005, 0x11050009, 0x11090009 }, /* 156.000 31.200 24.960 */
++ { 160000000, 0x0309, 0x04020011, 0x11090011, 0x02000309 }, /* 160.000 32.000 24.000 */
++ { 163200000, 0x0c02, 0x04020009, 0x11090009, 0x02000603 }, /* 163.200 32.640 24.727 */
++ { 168000000, 0x0205, 0x04020005, 0x11030021, 0x02000403 }, /* 168.000 32.000 24.889 */
++ { 176000000, 0x0602, 0x04020003, 0x11050005, 0x02000602 }, /* 176.000 33.000 24.000 */
++ };
++ typedef struct {
++ uint32 mipsclock;
++ uint16 n;
++ uint32 m2; /* that is the clockcontrol_m2 */
++ } type3_table_t;
++ static type3_table_t type3_table[] = { /* for 5350, mips clock is always double sb clock */
++ { 150000000, 0x311, 0x4020005 },
++ { 200000000, 0x311, 0x4020003 },
++ };
++ typedef struct {
++ uint32 mipsclock;
++ uint32 sbclock;
++ uint16 n;
++ uint32 sb;
++ uint32 pci33;
++ uint32 m2;
++ uint32 m3;
++ uint32 ratio_cfg;
++ uint32 ratio_parm;
++ } n4m_table_t;
++
++ static n4m_table_t BCMINITDATA(type2_table)[] = {
++ { 180000000, 80000000, 0x0403, 0x01010000, 0x01020300, 0x01020600, 0x05000100, 8, 0x012a00a9 },
++ { 180000000, 90000000, 0x0403, 0x01000100, 0x01020300, 0x01000100, 0x05000100, 11, 0x0aaa0555 },
++ { 200000000, 100000000, 0x0303, 0x02010000, 0x02040001, 0x02010000, 0x06000001, 11, 0x0aaa0555 },
++ { 211200000, 105600000, 0x0902, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
++ { 220800000, 110400000, 0x1500, 0x01000200, 0x01030400, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
++ { 230400000, 115200000, 0x0604, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
++ { 234000000, 104000000, 0x0b01, 0x01010000, 0x01010700, 0x01020600, 0x05000100, 8, 0x012a00a9 },
++ { 240000000, 120000000, 0x0803, 0x01000200, 0x01020600, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
++ { 252000000, 126000000, 0x0504, 0x01000100, 0x01020500, 0x01000100, 0x05000100, 11, 0x0aaa0555 },
++ { 264000000, 132000000, 0x0903, 0x01000200, 0x01020700, 0x01000200, 0x05000200, 11, 0x0aaa0555 },
++ { 270000000, 120000000, 0x0703, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 8, 0x012a00a9 },
++ { 276000000, 122666666, 0x1500, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 8, 0x012a00a9 },
++ { 280000000, 140000000, 0x0503, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 11, 0x0aaa0555 },
++ { 288000000, 128000000, 0x0604, 0x01010000, 0x01030400, 0x01020600, 0x05000100, 8, 0x012a00a9 },
++ { 288000000, 144000000, 0x0404, 0x01000000, 0x01010600, 0x01000000, 0x05000000, 11, 0x0aaa0555 },
++ { 300000000, 133333333, 0x0803, 0x01010000, 0x01020600, 0x01020600, 0x05000100, 8, 0x012a00a9 },
++ { 300000000, 150000000, 0x0803, 0x01000100, 0x01020600, 0x01000100, 0x05000100, 11, 0x0aaa0555 }
++ };
++
++ static n4m_table_t BCMINITDATA(type4_table)[] = {
++ { 192000000, 96000000, 0x0702, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11, 0x0aaa0555 },
++ { 198000000, 99000000, 0x0603, 0x11020005, 0x11030011, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++ { 200000000, 100000000, 0x0009, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 11, 0x0aaa0555 },
++ { 204000000, 102000000, 0x0c02, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++ { 208000000, 104000000, 0x0802, 0x11030002, 0x11090005, 0x11030002, 0x04000003, 11, 0x0aaa0555 },
++ { 210000000, 105000000, 0x0209, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++ { 216000000, 108000000, 0x0111, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++ { 224000000, 112000000, 0x0205, 0x11030002, 0x02002103, 0x11030002, 0x04000003, 11, 0x0aaa0555 },
++ { 228000000, 101333333, 0x0e02, 0x11030003, 0x11210005, 0x01030305, 0x04000005, 8, 0x012a00a9 },
++ { 228000000, 114000000, 0x0e02, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++ { 240000000, 102857143, 0x0109, 0x04000021, 0x01050203, 0x11030021, 0x04000003, 13, 0x254a14a9 },
++ { 240000000, 120000000, 0x0109, 0x11030002, 0x01050203, 0x11030002, 0x04000003, 11, 0x0aaa0555 },
++ { 252000000, 100800000, 0x0203, 0x04000009, 0x11050005, 0x02000209, 0x04000002, 9, 0x02520129 },
++ { 252000000, 126000000, 0x0203, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 11, 0x0aaa0555 },
++ { 264000000, 132000000, 0x0602, 0x04000005, 0x11050005, 0x04000005, 0x04000002, 11, 0x0aaa0555 },
++ { 272000000, 116571428, 0x0c02, 0x04000021, 0x02000909, 0x02000221, 0x04000003, 13, 0x254a14a9 },
++ { 280000000, 120000000, 0x0209, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 13, 0x254a14a9 },
++ { 288000000, 123428571, 0x0111, 0x04000021, 0x01030303, 0x02000221, 0x04000003, 13, 0x254a14a9 },
++ { 300000000, 120000000, 0x0009, 0x04000009, 0x01030203, 0x02000902, 0x04000002, 9, 0x02520129 },
++ { 300000000, 150000000, 0x0009, 0x04000005, 0x01030203, 0x04000005, 0x04000002, 11, 0x0aaa0555 }
++ };
++
++ static n4m_table_t BCMINITDATA(type7_table)[] = {
++ { 183333333, 91666666, 0x0605, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11, 0x0aaa0555 },
++ { 187500000, 93750000, 0x0a03, 0x04000011, 0x11030011, 0x04000011, 0x04000003, 11, 0x0aaa0555 },
++ { 196875000, 98437500, 0x1003, 0x11020005, 0x11050011, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++ { 200000000, 100000000, 0x0311, 0x04000011, 0x11030011, 0x04000009, 0x04000003, 11, 0x0aaa0555 },
++ { 200000000, 100000000, 0x0311, 0x04020011, 0x11030011, 0x04020011, 0x04020003, 11, 0x0aaa0555 },
++ { 206250000, 103125000, 0x1103, 0x11020005, 0x11050011, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++ { 212500000, 106250000, 0x0c05, 0x11020005, 0x01030303, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++ { 215625000, 107812500, 0x1203, 0x11090009, 0x11050005, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++ { 216666666, 108333333, 0x0805, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11, 0x0aaa0555 },
++ { 225000000, 112500000, 0x0d03, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11, 0x0aaa0555 },
++ { 233333333, 116666666, 0x0905, 0x11020003, 0x11030011, 0x11020003, 0x04000003, 11, 0x0aaa0555 },
++ { 237500000, 118750000, 0x0e05, 0x11020005, 0x11210005, 0x11020005, 0x04000005, 11, 0x0aaa0555 },
++ { 240000000, 120000000, 0x0b11, 0x11020009, 0x11210009, 0x11020009, 0x04000009, 11, 0x0aaa0555 },
++ { 250000000, 125000000, 0x0f03, 0x11020003, 0x11210003, 0x11020003, 0x04000003, 11, 0x0aaa0555 }
++ };
++
++ ulong start, end, dst;
++ bool ret = FALSE;
++
++ /* get index of the current core */
++ idx = sb_coreidx(sbh);
++ clockcontrol_m2 = NULL;
++
++ /* switch to extif or chipc core */
++ if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
++ pll_type = PLL_TYPE1;
++ clockcontrol_n = &eir->clockcontrol_n;
++ clockcontrol_sb = &eir->clockcontrol_sb;
++ clockcontrol_pci = &eir->clockcontrol_pci;
++ clockcontrol_m2 = &cc->clockcontrol_m2;
++ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
++ pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
++ if (pll_type == PLL_TYPE6) {
++ clockcontrol_n = NULL;
++ clockcontrol_sb = NULL;
++ clockcontrol_pci = NULL;
++ } else {
++ clockcontrol_n = &cc->clockcontrol_n;
++ clockcontrol_sb = &cc->clockcontrol_sb;
++ clockcontrol_pci = &cc->clockcontrol_pci;
++ clockcontrol_m2 = &cc->clockcontrol_m2;
++ }
++ } else
++ goto done;
++
++ if (pll_type == PLL_TYPE6) {
++ /* Silence compilers */
++ orig_n = orig_sb = orig_pci = 0;
++ } else {
++ /* Store the current clock register values */
++ orig_n = R_REG(clockcontrol_n);
++ orig_sb = R_REG(clockcontrol_sb);
++ orig_pci = R_REG(clockcontrol_pci);
++ }
++
++ if (pll_type == PLL_TYPE1) {
++ /* Keep the current PCI clock if not specified */
++ if (pciclock == 0) {
++ pciclock = sb_clock_rate(pll_type, R_REG(clockcontrol_n), R_REG(clockcontrol_pci));
++ pciclock = (pciclock <= 25000000) ? 25000000 : 33000000;
++ }
++
++ /* Search for the closest MIPS clock less than or equal to a preferred value */
++ for (i = 0; i < ARRAYSIZE(BCMINIT(type1_table)); i++) {
++ ASSERT(BCMINIT(type1_table)[i].mipsclock ==
++ sb_clock_rate(pll_type, BCMINIT(type1_table)[i].n, BCMINIT(type1_table)[i].sb));
++ if (BCMINIT(type1_table)[i].mipsclock > mipsclock)
++ break;
++ }
++ if (i == 0) {
++ ret = FALSE;
++ goto done;
++ } else {
++ ret = TRUE;
++ i--;
++ }
++ ASSERT(BCMINIT(type1_table)[i].mipsclock <= mipsclock);
++
++ /* No PLL change */
++ if ((orig_n == BCMINIT(type1_table)[i].n) &&
++ (orig_sb == BCMINIT(type1_table)[i].sb) &&
++ (orig_pci == BCMINIT(type1_table)[i].pci33))
++ goto done;
++
++ /* Set the PLL controls */
++ W_REG(clockcontrol_n, BCMINIT(type1_table)[i].n);
++ W_REG(clockcontrol_sb, BCMINIT(type1_table)[i].sb);
++ if (pciclock == 25000000)
++ W_REG(clockcontrol_pci, BCMINIT(type1_table)[i].pci25);
++ else
++ W_REG(clockcontrol_pci, BCMINIT(type1_table)[i].pci33);
++
++ /* Reset */
++ sb_watchdog(sbh, 1);
++
++ while (1);
++ } else if ((pll_type == PLL_TYPE3) &&
++ (BCMINIT(sb_chip)(sbh) != BCM5365_DEVICE_ID)) {
++ /* 5350 */
++ /* Search for the closest MIPS clock less than or equal to a preferred value */
++
++ for (i = 0; i < ARRAYSIZE(type3_table); i++) {
++ if (type3_table[i].mipsclock > mipsclock)
++ break;
++ }
++ if (i == 0) {
++ ret = FALSE;
++ goto done;
++ } else {
++ ret = TRUE;
++ i--;
++ }
++ ASSERT(type3_table[i].mipsclock <= mipsclock);
++
++ /* No PLL change */
++ orig_m2 = R_REG(&cc->clockcontrol_m2);
++ if ((orig_n == type3_table[i].n) &&
++ (orig_m2 == type3_table[i].m2)) {
++ goto done;
++ }
++
++ /* Set the PLL controls */
++ W_REG(clockcontrol_n, type3_table[i].n);
++ W_REG(clockcontrol_m2, type3_table[i].m2);
++
++ /* Reset */
++ sb_watchdog(sbh, 1);
++ while (1);
++ } else if ((pll_type == PLL_TYPE2) ||
++ (pll_type == PLL_TYPE4) ||
++ (pll_type == PLL_TYPE6) ||
++ (pll_type == PLL_TYPE7)) {
++ n4m_table_t *table = NULL, *te;
++ uint tabsz = 0;
++
++ ASSERT(cc);
++
++ orig_mips = R_REG(&cc->clockcontrol_mips);
++
++ if (pll_type == PLL_TYPE6) {
++ uint32 new_mips = 0;
++
++ ret = TRUE;
++ if (mipsclock <= SB2MIPS_T6(CC_T6_M1))
++ new_mips = CC_T6_MMASK;
++
++ if (orig_mips == new_mips)
++ goto done;
++
++ W_REG(&cc->clockcontrol_mips, new_mips);
++ goto end_fill;
++ }
++
++ if (pll_type == PLL_TYPE2) {
++ table = BCMINIT(type2_table);
++ tabsz = ARRAYSIZE(BCMINIT(type2_table));
++ } else if (pll_type == PLL_TYPE4) {
++ table = BCMINIT(type4_table);
++ tabsz = ARRAYSIZE(BCMINIT(type4_table));
++ } else if (pll_type == PLL_TYPE7) {
++ table = BCMINIT(type7_table);
++ tabsz = ARRAYSIZE(BCMINIT(type7_table));
++ } else
++ ASSERT("No table for plltype" == NULL);
++
++ /* Store the current clock register values */
++ orig_m2 = R_REG(&cc->clockcontrol_m2);
++ orig_ratio_parm = 0;
++ orig_ratio_cfg = 0;
++
++ /* Look up current ratio */
++ for (i = 0; i < tabsz; i++) {
++ if ((orig_n == table[i].n) &&
++ (orig_sb == table[i].sb) &&
++ (orig_pci == table[i].pci33) &&
++ (orig_m2 == table[i].m2) &&
++ (orig_mips == table[i].m3)) {
++ orig_ratio_parm = table[i].ratio_parm;
++ orig_ratio_cfg = table[i].ratio_cfg;
++ break;
++ }
++ }
++
++ /* Search for the closest MIPS clock greater or equal to a preferred value */
++ for (i = 0; i < tabsz; i++) {
++ ASSERT(table[i].mipsclock ==
++ sb_clock_rate(pll_type, table[i].n, table[i].m3));
++ if ((mipsclock <= table[i].mipsclock) &&
++ ((sbclock == 0) || (sbclock <= table[i].sbclock)))
++ break;
++ }
++ if (i == tabsz) {
++ ret = FALSE;
++ goto done;
++ } else {
++ te = &table[i];
++ ret = TRUE;
++ }
++
++ /* No PLL change */
++ if ((orig_n == te->n) &&
++ (orig_sb == te->sb) &&
++ (orig_pci == te->pci33) &&
++ (orig_m2 == te->m2) &&
++ (orig_mips == te->m3))
++ goto done;
++
++ /* Set the PLL controls */
++ W_REG(clockcontrol_n, te->n);
++ W_REG(clockcontrol_sb, te->sb);
++ W_REG(clockcontrol_pci, te->pci33);
++ W_REG(&cc->clockcontrol_m2, te->m2);
++ W_REG(&cc->clockcontrol_mips, te->m3);
++
++ /* Set the chipcontrol bit to change mipsref to the backplane divider if needed */
++ if ((pll_type == PLL_TYPE7) &&
++ (te->sb != te->m2) &&
++ (sb_clock_rate(pll_type, te->n, te->m2) == 120000000))
++ W_REG(&cc->chipcontrol, R_REG(&cc->chipcontrol) | 0x100);
++
++ /* No ratio change */
++ if (orig_ratio_parm == te->ratio_parm)
++ goto end_fill;
++
++ icache_probe(MFC0(C0_CONFIG, 1), &ic_size, &ic_lsize);
++
++ /* Preload the code into the cache */
++ start = ((ulong) &&start_fill) & ~(ic_lsize - 1);
++ end = ((ulong) &&end_fill + (ic_lsize - 1)) & ~(ic_lsize - 1);
++ while (start < end) {
++ cache_op(start, Fill_I);
++ start += ic_lsize;
++ }
++
++ /* Copy the handler */
++ start = (ulong) &BCMINIT(handler);
++ end = (ulong) &BCMINIT(afterhandler);
++ dst = KSEG1ADDR(0x180);
++ for (i = 0; i < (end - start); i += 4)
++ *((ulong *)(dst + i)) = *((ulong *)(start + i));
++
++ /* Preload handler into the cache one line at a time */
++ for (i = 0; i < (end - start); i += 4)
++ cache_op(dst + i, Fill_I);
++
++ /* Clear BEV bit */
++ MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~ST0_BEV);
++
++ /* Enable interrupts */
++ MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) | (ALLINTS | ST0_IE));
++
++ /* Enable MIPS timer interrupt */
++ if (!(mipsr = sb_setcore(sbh, SB_MIPS, 0)) &&
++ !(mipsr = sb_setcore(sbh, SB_MIPS33, 0)))
++ ASSERT(mipsr);
++ W_REG(&mipsr->intmask, 1);
++
++ start_fill:
++ /* step 1, set clock ratios */
++ MTC0(C0_BROADCOM, 3, te->ratio_parm);
++ MTC0(C0_BROADCOM, 1, te->ratio_cfg);
++
++ /* step 2: program timer intr */
++ W_REG(&mipsr->timer, 100);
++ (void) R_REG(&mipsr->timer);
++
++ /* step 3, switch to async */
++ sync_mode = MFC0(C0_BROADCOM, 4);
++ MTC0(C0_BROADCOM, 4, 1 << 22);
++
++ /* step 4, set cfg active */
++ MTC0(C0_BROADCOM, 2, 0x9);
++
++
++ /* steps 5 & 6 */
++ __asm__ __volatile__ (
++ ".set\tmips3\n\t"
++ "wait\n\t"
++ ".set\tmips0"
++ );
++
++ /* step 7, clear cfg_active */
++ MTC0(C0_BROADCOM, 2, 0);
++
++ /* Additional Step: set back to orig sync mode */
++ MTC0(C0_BROADCOM, 4, sync_mode);
++
++ /* step 8, fake soft reset */
++ MTC0(C0_BROADCOM, 5, MFC0(C0_BROADCOM, 5) | 4);
++
++ end_fill:
++ /* step 9 set watchdog timer */
++ sb_watchdog(sbh, 20);
++ (void) R_REG(&cc->chipid);
++
++ /* step 11 */
++ __asm__ __volatile__ (
++ ".set\tmips3\n\t"
++ "sync\n\t"
++ "wait\n\t"
++ ".set\tmips0"
++ );
++ while (1);
++ }
++
++done:
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++
++ return ret;
++}
++
++/*
++ * This also must be run from the cache on 47xx
++ * so there are no mips core BIU ops in progress
++ * when the PFC is enabled.
++ */
++
++static void
++BCMINITFN(_enable_pfc)(uint32 mode)
++{
++ /* write range */
++ *(volatile uint32 *)PFC_CR1 = 0xffff0000;
++
++ /* enable */
++ *(volatile uint32 *)PFC_CR0 = mode;
++}
++
++void
++BCMINITFN(enable_pfc)(uint32 mode)
++{
++ ulong start, end;
++ int i;
++
++ /* If auto then choose the correct mode for this
++ platform, currently we only ever select one mode */
++ if (mode == PFC_AUTO)
++ mode = PFC_INST;
++
++ /* enable prefetch cache if available */
++ if (MFC0(C0_BROADCOM, 0) & BRCM_PFC_AVAIL) {
++ start = (ulong) &BCMINIT(_enable_pfc);
++ end = (ulong) &BCMINIT(enable_pfc);
++
++ /* Preload handler into the cache one line at a time */
++ for (i = 0; i < (end - start); i += 4)
++ cache_op(start + i, Fill_I);
++
++ BCMINIT(_enable_pfc)(mode);
++ }
++}
++
++/* returns the ncdl value to be programmed into sdram_ncdl for calibration */
++uint32
++BCMINITFN(sb_memc_get_ncdl)(sb_t *sbh)
++{
++ sbmemcregs_t *memc;
++ uint32 ret = 0;
++ uint32 config, rd, wr, misc, dqsg, cd, sm, sd;
++ uint idx, rev;
++
++ idx = sb_coreidx(sbh);
++
++ memc = (sbmemcregs_t *)sb_setcore(sbh, SB_MEMC, 0);
++ if (memc == 0)
++ goto out;
++
++ rev = sb_corerev(sbh);
++
++ config = R_REG(&memc->config);
++ wr = R_REG(&memc->wrncdlcor);
++ rd = R_REG(&memc->rdncdlcor);
++ misc = R_REG(&memc->miscdlyctl);
++ dqsg = R_REG(&memc->dqsgatencdl);
++
++ rd &= MEMC_RDNCDLCOR_RD_MASK;
++ wr &= MEMC_WRNCDLCOR_WR_MASK;
++ dqsg &= MEMC_DQSGATENCDL_G_MASK;
++
++ if (config & MEMC_CONFIG_DDR) {
++ ret = (wr << 16) | (rd << 8) | dqsg;
++ } else {
++ if (rev > 0)
++ cd = rd;
++ else
++ cd = (rd == MEMC_CD_THRESHOLD) ? rd : (wr + MEMC_CD_THRESHOLD);
++ sm = (misc & MEMC_MISC_SM_MASK) >> MEMC_MISC_SM_SHIFT;
++ sd = (misc & MEMC_MISC_SD_MASK) >> MEMC_MISC_SD_SHIFT;
++ ret = (sm << 16) | (sd << 8) | cd;
++ }
++
++out:
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++
++ return ret;
++}
++
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/broadcom/sbpci.c linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/sbpci.c
+--- linux-2.6.17/arch/mips/bcm947xx/broadcom/sbpci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/sbpci.c 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,534 @@
++/*
++ * Low-Level PCI and SB support for BCM47xx
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#include <typedefs.h>
++#include <pcicfg.h>
++#include <bcmdevs.h>
++#include <sbconfig.h>
++#include <osl.h>
++#include <sbutils.h>
++#include <sbpci.h>
++#include <bcmendian.h>
++#include <bcmutils.h>
++#include <bcmnvram.h>
++#include <hndmips.h>
++
++/* Can free sbpci_init() memory after boot */
++#ifndef linux
++#define __init
++#endif
++
++/* Emulated configuration space */
++static pci_config_regs sb_config_regs[SB_MAXCORES];
++
++/* Banned cores */
++static uint16 pci_ban[32] = { 0 };
++static uint pci_banned = 0;
++
++/* CardBus mode */
++static bool cardbus = FALSE;
++
++/* Disable PCI host core */
++static bool pci_disabled = FALSE;
++
++/*
++ * Functions for accessing external PCI configuration space
++ */
++
++/* Assume one-hot slot wiring */
++#define PCI_SLOT_MAX 16
++
++static uint32
++config_cmd(sb_t *sbh, uint bus, uint dev, uint func, uint off)
++{
++ uint coreidx;
++ sbpciregs_t *regs;
++ uint32 addr = 0;
++
++ /* CardBusMode supports only one device */
++ if (cardbus && dev > 1)
++ return 0;
++
++ coreidx = sb_coreidx(sbh);
++ regs = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0);
++
++ /* Type 0 transaction */
++ if (bus == 1) {
++ /* Skip unwired slots */
++ if (dev < PCI_SLOT_MAX) {
++ /* Slide the PCI window to the appropriate slot */
++ W_REG(&regs->sbtopci1, SBTOPCI_CFG0 | ((1 << (dev + 16)) & SBTOPCI1_MASK));
++ addr = SB_PCI_CFG | ((1 << (dev + 16)) & ~SBTOPCI1_MASK) |
++ (func << 8) | (off & ~3);
++ }
++ }
++
++ /* Type 1 transaction */
++ else {
++ W_REG(&regs->sbtopci1, SBTOPCI_CFG1);
++ addr = SB_PCI_CFG | (bus << 16) | (dev << 11) | (func << 8) | (off & ~3);
++ }
++
++ sb_setcoreidx(sbh, coreidx);
++
++ return addr;
++}
++
++static int
++extpci_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ uint32 addr, *reg = NULL, val;
++ int ret = 0;
++
++ if (pci_disabled ||
++ !(addr = config_cmd(sbh, bus, dev, func, off)) ||
++ !(reg = (uint32 *) REG_MAP(addr, len)) ||
++ BUSPROBE(val, reg))
++ val = 0xffffffff;
++
++ val >>= 8 * (off & 3);
++ if (len == 4)
++ *((uint32 *) buf) = val;
++ else if (len == 2)
++ *((uint16 *) buf) = (uint16) val;
++ else if (len == 1)
++ *((uint8 *) buf) = (uint8) val;
++ else
++ ret = -1;
++
++ if (reg)
++ REG_UNMAP(reg);
++
++ return ret;
++}
++
++static int
++extpci_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ uint32 addr, *reg = NULL, val;
++ int ret = 0;
++
++ if (pci_disabled ||
++ !(addr = config_cmd(sbh, bus, dev, func, off)) ||
++ !(reg = (uint32 *) REG_MAP(addr, len)) ||
++ BUSPROBE(val, reg))
++ goto done;
++
++ if (len == 4)
++ val = *((uint32 *) buf);
++ else if (len == 2) {
++ val &= ~(0xffff << (8 * (off & 3)));
++ val |= *((uint16 *) buf) << (8 * (off & 3));
++ } else if (len == 1) {
++ val &= ~(0xff << (8 * (off & 3)));
++ val |= *((uint8 *) buf) << (8 * (off & 3));
++ } else
++ ret = -1;
++
++ W_REG(reg, val);
++
++ done:
++ if (reg)
++ REG_UNMAP(reg);
++
++ return ret;
++}
++
++/*
++ * Functions for accessing translated SB configuration space
++ */
++
++static int
++sb_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ pci_config_regs *cfg;
++
++ if (dev >= SB_MAXCORES || (off + len) > sizeof(pci_config_regs))
++ return -1;
++ cfg = &sb_config_regs[dev];
++
++ ASSERT(ISALIGNED(off, len));
++ ASSERT(ISALIGNED((uintptr)buf, len));
++
++ if (len == 4)
++ *((uint32 *) buf) = ltoh32(*((uint32 *)((ulong) cfg + off)));
++ else if (len == 2)
++ *((uint16 *) buf) = ltoh16(*((uint16 *)((ulong) cfg + off)));
++ else if (len == 1)
++ *((uint8 *) buf) = *((uint8 *)((ulong) cfg + off));
++ else
++ return -1;
++
++ return 0;
++}
++
++static int
++sb_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ uint coreidx, n;
++ void *regs;
++ sbconfig_t *sb;
++ pci_config_regs *cfg;
++
++ if (dev >= SB_MAXCORES || (off + len) > sizeof(pci_config_regs))
++ return -1;
++ cfg = &sb_config_regs[dev];
++
++ ASSERT(ISALIGNED(off, len));
++ ASSERT(ISALIGNED((uintptr)buf, len));
++
++ /* Emulate BAR sizing */
++ if (off >= OFFSETOF(pci_config_regs, base[0]) && off <= OFFSETOF(pci_config_regs, base[3]) &&
++ len == 4 && *((uint32 *) buf) == ~0) {
++ coreidx = sb_coreidx(sbh);
++ if ((regs = sb_setcoreidx(sbh, dev))) {
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++ /* Highest numbered address match register */
++ n = (R_REG(&sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT;
++ if (off == OFFSETOF(pci_config_regs, base[0]))
++ cfg->base[0] = ~(sb_size(R_REG(&sb->sbadmatch0)) - 1);
++#if 0
++ else if (off == OFFSETOF(pci_config_regs, base[1]) && n >= 1)
++ cfg->base[1] = ~(sb_size(R_REG(&sb->sbadmatch1)) - 1);
++ else if (off == OFFSETOF(pci_config_regs, base[2]) && n >= 2)
++ cfg->base[2] = ~(sb_size(R_REG(&sb->sbadmatch2)) - 1);
++ else if (off == OFFSETOF(pci_config_regs, base[3]) && n >= 3)
++ cfg->base[3] = ~(sb_size(R_REG(&sb->sbadmatch3)) - 1);
++#endif
++ }
++ sb_setcoreidx(sbh, coreidx);
++ return 0;
++ }
++
++ if (len == 4)
++ *((uint32 *)((ulong) cfg + off)) = htol32(*((uint32 *) buf));
++ else if (len == 2)
++ *((uint16 *)((ulong) cfg + off)) = htol16(*((uint16 *) buf));
++ else if (len == 1)
++ *((uint8 *)((ulong) cfg + off)) = *((uint8 *) buf);
++ else
++ return -1;
++
++ return 0;
++}
++
++int
++sbpci_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ if (bus == 0)
++ return sb_read_config(sbh, bus, dev, func, off, buf, len);
++ else
++ return extpci_read_config(sbh, bus, dev, func, off, buf, len);
++}
++
++int
++sbpci_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len)
++{
++ if (bus == 0)
++ return sb_write_config(sbh, bus, dev, func, off, buf, len);
++ else
++ return extpci_write_config(sbh, bus, dev, func, off, buf, len);
++}
++
++void
++sbpci_ban(uint16 core)
++{
++ if (pci_banned < ARRAYSIZE(pci_ban))
++ pci_ban[pci_banned++] = core;
++}
++
++static int
++sbpci_init_pci(sb_t *sbh)
++{
++ uint chip, chiprev, chippkg, host;
++ uint32 boardflags;
++ sbpciregs_t *pci;
++ sbconfig_t *sb;
++ uint32 val;
++
++ chip = sb_chip(sbh);
++ chiprev = sb_chiprev(sbh);
++ chippkg = sb_chippkg(sbh);
++
++ if (!(pci = (sbpciregs_t *) sb_setcore(sbh, SB_PCI, 0))) {
++ printf("PCI: no core\n");
++ pci_disabled = TRUE;
++ return -1;
++ }
++ sb_core_reset(sbh, 0);
++
++ boardflags = (uint32) getintvar(NULL, "boardflags");
++
++ if ((chip == BCM4310_DEVICE_ID) && (chiprev == 0))
++ pci_disabled = TRUE;
++
++ /*
++ * The 200-pin BCM4712 package does not bond out PCI. Even when
++ * PCI is bonded out, some boards may leave the pins
++ * floating.
++ */
++ if (((chip == BCM4712_DEVICE_ID) &&
++ ((chippkg == BCM4712SMALL_PKG_ID) ||
++ (chippkg == BCM4712MID_PKG_ID))) ||
++ (chip == BCM5350_DEVICE_ID) ||
++ (boardflags & BFL_NOPCI))
++ pci_disabled = TRUE;
++
++ /*
++ * If the PCI core should not be touched (disabled, not bonded
++ * out, or pins floating), do not even attempt to access core
++ * registers. Otherwise, try to determine if it is in host
++ * mode.
++ */
++ if (pci_disabled)
++ host = 0;
++ else
++ host = !BUSPROBE(val, &pci->control);
++
++ if (!host) {
++ /* Disable PCI interrupts in client mode */
++ sb = (sbconfig_t *)((ulong) pci + SBCONFIGOFF);
++ W_REG(&sb->sbintvec, 0);
++
++ /* Disable the PCI bridge in client mode */
++ sbpci_ban(SB_PCI);
++ printf("PCI: Disabled\n");
++ } else {
++ /* Reset the external PCI bus and enable the clock */
++ W_REG(&pci->control, 0x5); /* enable the tristate drivers */
++ W_REG(&pci->control, 0xd); /* enable the PCI clock */
++ OSL_DELAY(150); /* delay > 100 us */
++ W_REG(&pci->control, 0xf); /* deassert PCI reset */
++ W_REG(&pci->arbcontrol, PCI_INT_ARB); /* use internal arbiter */
++ OSL_DELAY(1); /* delay 1 us */
++
++ /* Enable CardBusMode */
++ cardbus = nvram_match("cardbus", "1");
++ if (cardbus) {
++ printf("PCI: Enabling CardBus\n");
++ /* GPIO 1 resets the CardBus device on bcm94710ap */
++ sb_gpioout(sbh, 1, 1, GPIO_DRV_PRIORITY);
++ sb_gpioouten(sbh, 1, 1, GPIO_DRV_PRIORITY);
++ W_REG(&pci->sprom[0], R_REG(&pci->sprom[0]) | 0x400);
++ }
++
++ /* 64 MB I/O access window */
++ W_REG(&pci->sbtopci0, SBTOPCI_IO);
++ /* 64 MB configuration access window */
++ W_REG(&pci->sbtopci1, SBTOPCI_CFG0);
++ /* 1 GB memory access window */
++ W_REG(&pci->sbtopci2, SBTOPCI_MEM | SB_PCI_DMA);
++
++ /* Enable PCI bridge BAR0 prefetch and burst */
++ val = 6;
++ sbpci_write_config(sbh, 1, 0, 0, PCI_CFG_CMD, &val, sizeof(val));
++
++ /* Enable PCI interrupts */
++ W_REG(&pci->intmask, PCI_INTA);
++ }
++
++ return 0;
++}
++
++static int
++sbpci_init_cores(sb_t *sbh)
++{
++ uint chip, chiprev, chippkg, coreidx, i;
++ sbconfig_t *sb;
++ pci_config_regs *cfg;
++ void *regs;
++ char varname[8];
++ uint wlidx = 0;
++ uint16 vendor, core;
++ uint8 class, subclass, progif;
++ uint32 val;
++ uint32 sbips_int_mask[] = { 0, SBIPS_INT1_MASK, SBIPS_INT2_MASK, SBIPS_INT3_MASK, SBIPS_INT4_MASK };
++ uint32 sbips_int_shift[] = { 0, 0, SBIPS_INT2_SHIFT, SBIPS_INT3_SHIFT, SBIPS_INT4_SHIFT };
++
++ chip = sb_chip(sbh);
++ chiprev = sb_chiprev(sbh);
++ chippkg = sb_chippkg(sbh);
++ coreidx = sb_coreidx(sbh);
++
++ /* Scan the SB bus */
++ bzero(sb_config_regs, sizeof(sb_config_regs));
++ for (cfg = sb_config_regs; cfg < &sb_config_regs[SB_MAXCORES]; cfg++) {
++ cfg->vendor = 0xffff;
++ if (!(regs = sb_setcoreidx(sbh, cfg - sb_config_regs)))
++ continue;
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++
++ /* Read ID register and parse vendor and core */
++ val = R_REG(&sb->sbidhigh);
++ vendor = (val & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT;
++ core = (val & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
++ progif = 0;
++
++ /* Check if this core is banned */
++ for (i = 0; i < pci_banned; i++)
++ if (core == pci_ban[i])
++ break;
++ if (i < pci_banned)
++ continue;
++
++ /* Known vendor translations */
++ switch (vendor) {
++ case SB_VEND_BCM:
++ vendor = VENDOR_BROADCOM;
++ break;
++ }
++
++ /* Determine class based on known core codes */
++ switch (core) {
++ case SB_ILINE20:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_ETHER;
++ core = BCM47XX_ILINE_ID;
++ break;
++ case SB_ILINE100:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_ETHER;
++ core = BCM4610_ILINE_ID;
++ break;
++ case SB_ENET:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_ETHER;
++ core = BCM47XX_ENET_ID;
++ break;
++ case SB_SDRAM:
++ case SB_MEMC:
++ class = PCI_CLASS_MEMORY;
++ subclass = PCI_MEMORY_RAM;
++ break;
++ case SB_PCI:
++#if 0
++ class = PCI_CLASS_BRIDGE;
++ subclass = PCI_BRIDGE_PCI;
++ break;
++#endif
++ case SB_MIPS:
++ case SB_MIPS33:
++ class = PCI_CLASS_CPU;
++ subclass = PCI_CPU_MIPS;
++ break;
++ case SB_CODEC:
++ class = PCI_CLASS_COMM;
++ subclass = PCI_COMM_MODEM;
++ core = BCM47XX_V90_ID;
++ break;
++ case SB_USB:
++ class = PCI_CLASS_SERIAL;
++ subclass = PCI_SERIAL_USB;
++ progif = 0x10; /* OHCI */
++ core = BCM47XX_USB_ID;
++ break;
++ case SB_USB11H:
++ class = PCI_CLASS_SERIAL;
++ subclass = PCI_SERIAL_USB;
++ progif = 0x10; /* OHCI */
++ core = BCM47XX_USBH_ID;
++ break;
++ case SB_USB11D:
++ class = PCI_CLASS_SERIAL;
++ subclass = PCI_SERIAL_USB;
++ core = BCM47XX_USBD_ID;
++ break;
++ case SB_IPSEC:
++ class = PCI_CLASS_CRYPT;
++ subclass = PCI_CRYPT_NETWORK;
++ core = BCM47XX_IPSEC_ID;
++ break;
++ case SB_ROBO:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_OTHER;
++ core = BCM47XX_ROBO_ID;
++ break;
++ case SB_EXTIF:
++ case SB_CC:
++ class = PCI_CLASS_MEMORY;
++ subclass = PCI_MEMORY_FLASH;
++ break;
++ case SB_D11:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_OTHER;
++ /* Let an nvram variable override this */
++ sprintf(varname, "wl%did", wlidx);
++ wlidx++;
++ if ((core = getintvar(NULL, varname)) == 0) {
++ if (chip == BCM4712_DEVICE_ID) {
++ if (chippkg == BCM4712SMALL_PKG_ID)
++ core = BCM4306_D11G_ID;
++ else
++ core = BCM4306_D11DUAL_ID;
++ } else {
++ /* 4310 */
++ core = BCM4310_D11B_ID;
++ }
++ }
++ break;
++
++ default:
++ class = subclass = progif = 0xff;
++ break;
++ }
++
++ /* Supported translations */
++ cfg->vendor = htol16(vendor);
++ cfg->device = htol16(core);
++ cfg->rev_id = chiprev;
++ cfg->prog_if = progif;
++ cfg->sub_class = subclass;
++ cfg->base_class = class;
++ cfg->base[0] = htol32(sb_base(R_REG(&sb->sbadmatch0)));
++ cfg->base[1] = 0;//htol32(sb_base(R_REG(&sb->sbadmatch1)));
++ cfg->base[2] = 0;//htol32(sb_base(R_REG(&sb->sbadmatch2)));
++ cfg->base[3] = 0;//htol32(sb_base(R_REG(&sb->sbadmatch3)));
++ cfg->base[4] = 0;
++ cfg->base[5] = 0;
++ if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI)
++ cfg->header_type = PCI_HEADER_BRIDGE;
++ else
++ cfg->header_type = PCI_HEADER_NORMAL;
++ /* Save core interrupt flag */
++ cfg->int_pin = R_REG(&sb->sbtpsflag) & SBTPS_NUM0_MASK;
++ /* Default to MIPS shared interrupt 0 */
++ cfg->int_line = 0;
++ /* MIPS sbipsflag maps core interrupt flags to interrupts 1 through 4 */
++ if ((regs = sb_setcore(sbh, SB_MIPS, 0)) ||
++ (regs = sb_setcore(sbh, SB_MIPS33, 0))) {
++ sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
++ val = R_REG(&sb->sbipsflag);
++ for (cfg->int_line = 1; cfg->int_line <= 4; cfg->int_line++) {
++ if (((val & sbips_int_mask[cfg->int_line]) >> sbips_int_shift[cfg->int_line]) == cfg->int_pin)
++ break;
++ }
++ if (cfg->int_line > 4)
++ cfg->int_line = 0;
++ }
++ /* Emulated core */
++ *((uint32 *) &cfg->sprom_control) = 0xffffffff;
++ }
++
++ sb_setcoreidx(sbh, coreidx);
++ return 0;
++}
++
++int __init
++sbpci_init(sb_t *sbh)
++{
++ sbpci_init_pci(sbh);
++ sbpci_init_cores(sbh);
++ return 0;
++}
++
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/broadcom/sbutils.c linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/sbutils.c
+--- linux-2.6.17/arch/mips/bcm947xx/broadcom/sbutils.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/sbutils.c 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,2370 @@
++/*
++ * Misc utility routines for accessing chip-specific features
++ * of the SiliconBackplane-based Broadcom chips.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id$
++ */
++
++#include <typedefs.h>
++#include <osl.h>
++#include <sbutils.h>
++#include <bcmutils.h>
++#include <bcmdevs.h>
++#include <sbconfig.h>
++#include <sbchipc.h>
++#include <sbpci.h>
++#include <pcicfg.h>
++#include <sbextif.h>
++#include <bcmsrom.h>
++
++/* debug/trace */
++#define SB_ERROR(args)
++
++
++typedef uint32 (*sb_intrsoff_t)(void *intr_arg);
++typedef void (*sb_intrsrestore_t)(void *intr_arg, uint32 arg);
++typedef bool (*sb_intrsenabled_t)(void *intr_arg);
++
++/* misc sb info needed by some of the routines */
++typedef struct sb_info {
++
++ struct sb_pub sb; /* back plane public state(must be first field of sb_info */
++
++ void *osh; /* osl os handle */
++ void *sdh; /* bcmsdh handle */
++
++ void *curmap; /* current regs va */
++ void *regs[SB_MAXCORES]; /* other regs va */
++
++ uint curidx; /* current core index */
++ uint dev_coreid; /* the core provides driver functions */
++
++ uint gpioidx; /* gpio control core index */
++ uint gpioid; /* gpio control coretype */
++
++ uint numcores; /* # discovered cores */
++ uint coreid[SB_MAXCORES]; /* id of each core */
++
++ void *intr_arg; /* interrupt callback function arg */
++ sb_intrsoff_t intrsoff_fn; /* function turns chip interrupts off */
++ sb_intrsrestore_t intrsrestore_fn; /* function restore chip interrupts */
++ sb_intrsenabled_t intrsenabled_fn; /* function to check if chip interrupts are enabled */
++
++} sb_info_t;
++
++/* local prototypes */
++static sb_info_t * BCMINIT(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs,
++ uint bustype, void *sdh, char **vars, int *varsz);
++static void BCMINIT(sb_scan)(sb_info_t *si);
++static uint sb_corereg(sb_info_t *si, uint coreidx, uint regoff, uint mask, uint val);
++static uint _sb_coreidx(sb_info_t *si);
++static uint sb_findcoreidx(sb_info_t *si, uint coreid, uint coreunit);
++static uint BCMINIT(sb_pcidev2chip)(uint pcidev);
++static uint BCMINIT(sb_chip2numcores)(uint chip);
++static int sb_pci_fixcfg(sb_info_t *si);
++
++/* delay needed between the mdio control/ mdiodata register data access */
++#define PR28829_DELAY() OSL_DELAY(10)
++
++
++/* global variable to indicate reservation/release of gpio's*/
++static uint32 sb_gpioreservation = 0;
++
++#define SB_INFO(sbh) (sb_info_t*)sbh
++#define SET_SBREG(sbh, r, mask, val) W_SBREG((sbh), (r), ((R_SBREG((sbh), (r)) & ~(mask)) | (val)))
++#define GOODCOREADDR(x) (((x) >= SB_ENUM_BASE) && ((x) <= SB_ENUM_LIM) && ISALIGNED((x), SB_CORE_SIZE))
++#define GOODREGS(regs) ((regs) && ISALIGNED((uintptr)(regs), SB_CORE_SIZE))
++#define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF)
++#define GOODIDX(idx) (((uint)idx) < SB_MAXCORES)
++#define BADIDX (SB_MAXCORES+1)
++#define NOREV -1
++
++#define PCI(si) ((BUSTYPE(si->sb.bustype) == PCI_BUS) && (si->sb.buscoretype == SB_PCI))
++
++/* sonicsrev */
++#define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT)
++#define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT)
++
++#define R_SBREG(sbh, sbr) sb_read_sbreg((sbh), (sbr))
++#define W_SBREG(sbh, sbr, v) sb_write_sbreg((sbh), (sbr), (v))
++#define AND_SBREG(sbh, sbr, v) W_SBREG((sbh), (sbr), (R_SBREG((sbh), (sbr)) & (v)))
++#define OR_SBREG(sbh, sbr, v) W_SBREG((sbh), (sbr), (R_SBREG((sbh), (sbr)) | (v)))
++
++/*
++ * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts before/
++ * after core switching to avoid invalid register accesss inside ISR.
++ */
++#define INTR_OFF(si, intr_val) \
++ if ((si)->intrsoff_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \
++ intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); }
++#define INTR_RESTORE(si, intr_val) \
++ if ((si)->intrsrestore_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \
++ (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); }
++
++/* dynamic clock control defines */
++#define LPOMINFREQ 25000 /* low power oscillator min */
++#define LPOMAXFREQ 43000 /* low power oscillator max */
++#define XTALMINFREQ 19800000 /* 20 MHz - 1% */
++#define XTALMAXFREQ 20200000 /* 20 MHz + 1% */
++#define PCIMINFREQ 25000000 /* 25 MHz */
++#define PCIMAXFREQ 34000000 /* 33 MHz + fudge */
++
++#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */
++#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */
++
++#define MIN_DUMPBUFLEN 32 /* debug */
++
++/* GPIO Based LED powersave defines */
++#define DEFAULT_GPIO_ONTIME 10
++#define DEFAULT_GPIO_OFFTIME 90
++
++#define DEFAULT_GPIOTIMERVAL ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME)
++
++static uint32
++sb_read_sbreg(sb_info_t *si, volatile uint32 *sbr)
++{
++ uint32 val = R_REG(sbr);
++
++ return (val);
++}
++
++static void
++sb_write_sbreg(sb_info_t *si, volatile uint32 *sbr, uint32 v)
++{
++ W_REG(sbr, v);
++}
++
++/* Using sb_kattach depends on SB_BUS support, either implicit */
++/* no limiting BCMBUSTYPE value) or explicit (value is SB_BUS). */
++#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SB_BUS)
++
++/* global kernel resource */
++static sb_info_t ksi;
++
++/* generic kernel variant of sb_attach() */
++sb_t *
++BCMINITFN(sb_kattach)()
++{
++ uint32 *regs;
++
++ if (ksi.curmap == NULL) {
++ uint32 cid;
++
++ regs = (uint32 *)REG_MAP(SB_ENUM_BASE, SB_CORE_SIZE);
++ cid = R_REG((uint32 *)regs);
++ if (((cid & CID_ID_MASK) == BCM4712_DEVICE_ID) &&
++ ((cid & CID_PKG_MASK) != BCM4712LARGE_PKG_ID) &&
++ ((cid & CID_REV_MASK) <= (3 << CID_REV_SHIFT))) {
++ uint32 *scc, val;
++
++ scc = (uint32 *)((uchar*)regs + OFFSETOF(chipcregs_t, slow_clk_ctl));
++ val = R_REG(scc);
++ SB_ERROR((" initial scc = 0x%x\n", val));
++ val |= SCC_SS_XTAL;
++ W_REG(scc, val);
++ }
++
++ if (BCMINIT(sb_doattach)(&ksi, BCM4710_DEVICE_ID, NULL, (void*)regs,
++ SB_BUS, NULL, NULL, NULL) == NULL) {
++ return NULL;
++ }
++ }
++
++ return (sb_t *)&ksi;
++}
++#endif
++
++static sb_info_t *
++BCMINITFN(sb_doattach)(sb_info_t *si, uint devid, osl_t *osh, void *regs,
++ uint bustype, void *sdh, char **vars, int *varsz)
++{
++ uint origidx;
++ chipcregs_t *cc;
++ sbconfig_t *sb;
++ uint32 w;
++
++ ASSERT(GOODREGS(regs));
++
++ bzero((uchar*)si, sizeof (sb_info_t));
++
++ si->sb.buscoreidx = si->gpioidx = BADIDX;
++
++ si->osh = osh;
++ si->curmap = regs;
++ si->sdh = sdh;
++
++ /* check to see if we are a sb core mimic'ing a pci core */
++ if (bustype == PCI_BUS) {
++ if (OSL_PCI_READ_CONFIG(osh, PCI_SPROM_CONTROL, sizeof (uint32)) == 0xffffffff)
++ bustype = SB_BUS;
++ else
++ bustype = PCI_BUS;
++ }
++
++ si->sb.bustype = bustype;
++ if (si->sb.bustype != BUSTYPE(si->sb.bustype)) {
++ SB_ERROR(("sb_doattach: bus type %d does not match configured bus type %d\n",
++ si->sb.bustype, BUSTYPE(si->sb.bustype)));
++ return NULL;
++ }
++
++ /* kludge to enable the clock on the 4306 which lacks a slowclock */
++ if (BUSTYPE(si->sb.bustype) == PCI_BUS)
++ sb_clkctl_xtal(&si->sb, XTAL|PLL, ON);
++
++ if (BUSTYPE(si->sb.bustype) == PCI_BUS) {
++ w = OSL_PCI_READ_CONFIG(osh, PCI_BAR0_WIN, sizeof (uint32));
++ if (!GOODCOREADDR(w))
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, sizeof (uint32), SB_ENUM_BASE);
++ }
++
++ /* initialize current core index value */
++ si->curidx = _sb_coreidx(si);
++
++ if (si->curidx == BADIDX) {
++ SB_ERROR(("sb_doattach: bad core index\n"));
++ return NULL;
++ }
++
++ /* get sonics backplane revision */
++ sb = REGS2SB(si->curmap);
++ si->sb.sonicsrev = (R_SBREG(si, &(sb)->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT;
++
++ /* keep and reuse the initial register mapping */
++ origidx = si->curidx;
++ if (BUSTYPE(si->sb.bustype) == SB_BUS)
++ si->regs[origidx] = regs;
++
++ /* is core-0 a chipcommon core? */
++ si->numcores = 1;
++ cc = (chipcregs_t*) sb_setcoreidx(&si->sb, 0);
++ if (sb_coreid(&si->sb) != SB_CC)
++ cc = NULL;
++
++ /* determine chip id and rev */
++ if (cc) {
++ /* chip common core found! */
++ si->sb.chip = R_REG(&cc->chipid) & CID_ID_MASK;
++ si->sb.chiprev = (R_REG(&cc->chipid) & CID_REV_MASK) >> CID_REV_SHIFT;
++ si->sb.chippkg = (R_REG(&cc->chipid) & CID_PKG_MASK) >> CID_PKG_SHIFT;
++ } else {
++ /* no chip common core -- must convert device id to chip id */
++ if ((si->sb.chip = BCMINIT(sb_pcidev2chip)(devid)) == 0) {
++ SB_ERROR(("sb_doattach: unrecognized device id 0x%04x\n", devid));
++ sb_setcoreidx(&si->sb, origidx);
++ return NULL;
++ }
++ }
++
++ /* get chipcommon rev */
++ si->sb.ccrev = cc ? (int)sb_corerev(&si->sb) : NOREV;
++
++ /* determine numcores */
++ if (cc && ((si->sb.ccrev == 4) || (si->sb.ccrev >= 6)))
++ si->numcores = (R_REG(&cc->chipid) & CID_CC_MASK) >> CID_CC_SHIFT;
++ else
++ si->numcores = BCMINIT(sb_chip2numcores)(si->sb.chip);
++
++ /* return to original core */
++ sb_setcoreidx(&si->sb, origidx);
++
++ /* sanity checks */
++ ASSERT(si->sb.chip);
++
++ /* scan for cores */
++ BCMINIT(sb_scan)(si);
++
++ /* fixup necessary chip/core configurations */
++ if (BUSTYPE(si->sb.bustype) == PCI_BUS) {
++ if (sb_pci_fixcfg(si)) {
++ SB_ERROR(("sb_doattach: sb_pci_fixcfg failed\n"));
++ return NULL;
++ }
++ }
++
++ /* srom_var_init() depends on sb_scan() info */
++ if (srom_var_init(si, si->sb.bustype, si->curmap, osh, vars, varsz)) {
++ SB_ERROR(("sb_doattach: srom_var_init failed: bad srom\n"));
++ return (NULL);
++ }
++
++ if (cc == NULL) {
++ /*
++ * The chip revision number is hardwired into all
++ * of the pci function config rev fields and is
++ * independent from the individual core revision numbers.
++ * For example, the "A0" silicon of each chip is chip rev 0.
++ */
++ if (BUSTYPE(si->sb.bustype) == PCI_BUS) {
++ w = OSL_PCI_READ_CONFIG(osh, PCI_CFG_REV, sizeof (uint32));
++ si->sb.chiprev = w & 0xff;
++ } else
++ si->sb.chiprev = 0;
++ }
++
++ /* gpio control core is required */
++ if (!GOODIDX(si->gpioidx)) {
++ SB_ERROR(("sb_doattach: gpio control core not found\n"));
++ return NULL;
++ }
++
++ /* get boardtype and boardrev */
++ switch (BUSTYPE(si->sb.bustype)) {
++ case PCI_BUS:
++ /* do a pci config read to get subsystem id and subvendor id */
++ w = OSL_PCI_READ_CONFIG(osh, PCI_CFG_SVID, sizeof (uint32));
++ si->sb.boardvendor = w & 0xffff;
++ si->sb.boardtype = (w >> 16) & 0xffff;
++ break;
++
++ case SB_BUS:
++ case JTAG_BUS:
++ si->sb.boardvendor = VENDOR_BROADCOM;
++ if ((si->sb.boardtype = getintvar(NULL, "boardtype")) == 0)
++ si->sb.boardtype = 0xffff;
++ break;
++ }
++
++ if (si->sb.boardtype == 0) {
++ SB_ERROR(("sb_doattach: unknown board type\n"));
++ ASSERT(si->sb.boardtype);
++ }
++
++ /* setup the GPIO based LED powersave register */
++ if (si->sb.ccrev >= 16) {
++ w = getintvar(*vars, "gpiotimerval");
++ if (!w)
++ w = DEFAULT_GPIOTIMERVAL;
++ sb_corereg(si, 0, OFFSETOF(chipcregs_t, gpiotimerval), ~0, w);
++ }
++
++
++ return (si);
++}
++
++uint
++sb_coreid(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ return ((R_SBREG(si, &(sb)->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT);
++}
++
++uint
++sb_coreidx(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->curidx);
++}
++
++/* return current index of core */
++static uint
++_sb_coreidx(sb_info_t *si)
++{
++ sbconfig_t *sb;
++ uint32 sbaddr = 0;
++
++ ASSERT(si);
++
++ switch (BUSTYPE(si->sb.bustype)) {
++ case SB_BUS:
++ sb = REGS2SB(si->curmap);
++ sbaddr = sb_base(R_SBREG(si, &sb->sbadmatch0));
++ break;
++
++ case PCI_BUS:
++ sbaddr = OSL_PCI_READ_CONFIG(si->osh, PCI_BAR0_WIN, sizeof (uint32));
++ break;
++
++#ifdef BCMJTAG
++ case JTAG_BUS:
++ sbaddr = (uint32)si->curmap;
++ break;
++#endif /* BCMJTAG */
++
++ default:
++ ASSERT(0);
++ }
++
++ if (!GOODCOREADDR(sbaddr))
++ return BADIDX;
++
++ return ((sbaddr - SB_ENUM_BASE) / SB_CORE_SIZE);
++}
++
++uint
++sb_corevendor(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ return ((R_SBREG(si, &(sb)->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT);
++}
++
++uint
++sb_corerev(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ uint sbidh;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++ sbidh = R_SBREG(si, &(sb)->sbidhigh);
++
++ return (SBCOREREV(sbidh));
++}
++
++void *
++sb_osh(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return si->osh;
++}
++
++#define SBTML_ALLOW (SBTML_PE | SBTML_FGC | SBTML_FL_MASK)
++
++/* set/clear sbtmstatelow core-specific flags */
++uint32
++sb_coreflags(sb_t *sbh, uint32 mask, uint32 val)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ uint32 w;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ ASSERT((val & ~mask) == 0);
++ ASSERT((mask & ~SBTML_ALLOW) == 0);
++
++ /* mask and set */
++ if (mask || val) {
++ w = (R_SBREG(si, &sb->sbtmstatelow) & ~mask) | val;
++ W_SBREG(si, &sb->sbtmstatelow, w);
++ }
++
++ /* return the new value */
++ return (R_SBREG(si, &sb->sbtmstatelow) & SBTML_ALLOW);
++}
++
++/* set/clear sbtmstatehigh core-specific flags */
++uint32
++sb_coreflagshi(sb_t *sbh, uint32 mask, uint32 val)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ uint32 w;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ ASSERT((val & ~mask) == 0);
++ ASSERT((mask & ~SBTMH_FL_MASK) == 0);
++
++ /* mask and set */
++ if (mask || val) {
++ w = (R_SBREG(si, &sb->sbtmstatehigh) & ~mask) | val;
++ W_SBREG(si, &sb->sbtmstatehigh, w);
++ }
++
++ /* return the new value */
++ return (R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_FL_MASK);
++}
++
++/* caller needs to take care of core-specific bist hazards */
++int
++sb_corebist(sb_t *sbh, uint coreid, uint coreunit)
++{
++ uint32 sblo;
++ uint coreidx;
++ sb_info_t *si;
++ int result = 0;
++
++ si = SB_INFO(sbh);
++
++ coreidx = sb_findcoreidx(si, coreid, coreunit);
++ if (!GOODIDX(coreidx))
++ result = BCME_ERROR;
++ else {
++ sblo = sb_corereg(si, coreidx, SBCONFIGOFF + OFFSETOF(sbconfig_t, sbtmstatelow), 0, 0);
++ sb_corereg(si, coreidx, SBCONFIGOFF + OFFSETOF(sbconfig_t, sbtmstatelow), ~0, (sblo | SBTML_FGC | SBTML_BE));
++
++ SPINWAIT(((sb_corereg(si, coreidx, SBCONFIGOFF + OFFSETOF(sbconfig_t, sbtmstatehigh), 0, 0) & SBTMH_BISTD) == 0), 100000);
++
++ if (sb_corereg(si, coreidx, SBCONFIGOFF + OFFSETOF(sbconfig_t, sbtmstatehigh), 0, 0) & SBTMH_BISTF)
++ result = BCME_ERROR;
++
++ sb_corereg(si, coreidx, SBCONFIGOFF + OFFSETOF(sbconfig_t, sbtmstatelow), ~0, sblo);
++ }
++
++ return result;
++}
++
++bool
++sb_iscoreup(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++ sb = REGS2SB(si->curmap);
++
++ return ((R_SBREG(si, &(sb)->sbtmstatelow) & (SBTML_RESET | SBTML_REJ_MASK | SBTML_CLK)) == SBTML_CLK);
++}
++
++/*
++ * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation,
++ * switch back to the original core, and return the new value.
++ */
++static uint
++sb_corereg(sb_info_t *si, uint coreidx, uint regoff, uint mask, uint val)
++{
++ uint origidx;
++ uint32 *r;
++ uint w;
++ uint intr_val = 0;
++
++ ASSERT(GOODIDX(coreidx));
++ ASSERT(regoff < SB_CORE_SIZE);
++ ASSERT((val & ~mask) == 0);
++
++ INTR_OFF(si, intr_val);
++
++ /* save current core index */
++ origidx = sb_coreidx(&si->sb);
++
++ /* switch core */
++ r = (uint32*) ((uchar*) sb_setcoreidx(&si->sb, coreidx) + regoff);
++
++ /* mask and set */
++ if (mask || val) {
++ if (regoff >= SBCONFIGOFF) {
++ w = (R_SBREG(si, r) & ~mask) | val;
++ W_SBREG(si, r, w);
++ } else {
++ w = (R_REG(r) & ~mask) | val;
++ W_REG(r, w);
++ }
++ }
++
++ /* readback */
++ if (regoff >= SBCONFIGOFF)
++ w = R_SBREG(si, r);
++ else
++ w = R_REG(r);
++
++ /* restore core index */
++ if (origidx != coreidx)
++ sb_setcoreidx(&si->sb, origidx);
++
++ INTR_RESTORE(si, intr_val);
++ return (w);
++}
++
++#define DWORD_ALIGN(x) (x & ~(0x03))
++#define BYTE_POS(x) (x & 0x3)
++#define WORD_POS(x) (x & 0x1)
++
++#define BYTE_SHIFT(x) (8 * BYTE_POS(x))
++#define WORD_SHIFT(x) (16 * WORD_POS(x))
++
++#define BYTE_VAL(a, x) ((a >> BYTE_SHIFT(x)) & 0xFF)
++#define WORD_VAL(a, x) ((a >> WORD_SHIFT(x)) & 0xFFFF)
++
++#define read_pci_cfg_byte(a) \
++ (BYTE_VAL(OSL_PCI_READ_CONFIG(si->osh, DWORD_ALIGN(a), 4), a) & 0xff)
++
++#define read_pci_cfg_write(a) \
++ (WORD_VAL(OSL_PCI_READ_CONFIG(si->osh, DWORD_ALIGN(a), 4), a) & 0xffff)
++
++
++/* scan the sb enumerated space to identify all cores */
++static void
++BCMINITFN(sb_scan)(sb_info_t *si)
++{
++ uint origidx;
++ uint i;
++ bool pci;
++ uint pciidx;
++ uint pcirev;
++
++
++
++ /* numcores should already be set */
++ ASSERT((si->numcores > 0) && (si->numcores <= SB_MAXCORES));
++
++ /* save current core index */
++ origidx = sb_coreidx(&si->sb);
++
++ si->sb.buscorerev = NOREV;
++ si->sb.buscoreidx = BADIDX;
++
++ si->gpioidx = BADIDX;
++
++ pci = FALSE;
++ pcirev = NOREV;
++ pciidx = BADIDX;
++
++ for (i = 0; i < si->numcores; i++) {
++ sb_setcoreidx(&si->sb, i);
++ si->coreid[i] = sb_coreid(&si->sb);
++
++ if (si->coreid[i] == SB_PCI) {
++ pciidx = i;
++ pcirev = sb_corerev(&si->sb);
++ pci = TRUE;
++ }
++ }
++ if (pci) {
++ si->sb.buscoretype = SB_PCI;
++ si->sb.buscorerev = pcirev;
++ si->sb.buscoreidx = pciidx;
++ }
++
++ /*
++ * Find the gpio "controlling core" type and index.
++ * Precedence:
++ * - if there's a chip common core - use that
++ * - else if there's a pci core (rev >= 2) - use that
++ * - else there had better be an extif core (4710 only)
++ */
++ if (GOODIDX(sb_findcoreidx(si, SB_CC, 0))) {
++ si->gpioidx = sb_findcoreidx(si, SB_CC, 0);
++ si->gpioid = SB_CC;
++ } else if (PCI(si) && (si->sb.buscorerev >= 2)) {
++ si->gpioidx = si->sb.buscoreidx;
++ si->gpioid = SB_PCI;
++ } else if (sb_findcoreidx(si, SB_EXTIF, 0)) {
++ si->gpioidx = sb_findcoreidx(si, SB_EXTIF, 0);
++ si->gpioid = SB_EXTIF;
++ } else
++ ASSERT(si->gpioidx != BADIDX);
++
++ /* return to original core index */
++ sb_setcoreidx(&si->sb, origidx);
++}
++
++/* may be called with core in reset */
++void
++sb_detach(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint idx;
++
++ si = SB_INFO(sbh);
++
++ if (si == NULL)
++ return;
++
++ if (BUSTYPE(si->sb.bustype) == SB_BUS)
++ for (idx = 0; idx < SB_MAXCORES; idx++)
++ if (si->regs[idx]) {
++ REG_UNMAP(si->regs[idx]);
++ si->regs[idx] = NULL;
++ }
++
++ if (si != &ksi)
++ MFREE(si->osh, si, sizeof (sb_info_t));
++}
++
++/* use pci dev id to determine chip id for chips not having a chipcommon core */
++static uint
++BCMINITFN(sb_pcidev2chip)(uint pcidev)
++{
++ if ((pcidev >= BCM4710_DEVICE_ID) && (pcidev <= BCM47XX_USB_ID))
++ return (BCM4710_DEVICE_ID);
++ if ((pcidev >= BCM4402_DEVICE_ID) && (pcidev <= BCM4402_V90_ID))
++ return (BCM4402_DEVICE_ID);
++ if (pcidev == BCM4401_ENET_ID)
++ return (BCM4402_DEVICE_ID);
++ if ((pcidev >= BCM4307_V90_ID) && (pcidev <= BCM4307_D11B_ID))
++ return (BCM4307_DEVICE_ID);
++ if (pcidev == BCM4301_DEVICE_ID)
++ return (BCM4301_DEVICE_ID);
++
++ return (0);
++}
++
++/* convert chip number to number of i/o cores */
++static uint
++BCMINITFN(sb_chip2numcores)(uint chip)
++{
++ if (chip == BCM4710_DEVICE_ID)
++ return (9);
++ if (chip == BCM4402_DEVICE_ID)
++ return (3);
++ if ((chip == BCM4301_DEVICE_ID) || (chip == BCM4307_DEVICE_ID))
++ return (5);
++ if (chip == BCM4306_DEVICE_ID) /* < 4306c0 */
++ return (6);
++ if (chip == BCM4704_DEVICE_ID)
++ return (9);
++ if (chip == BCM5365_DEVICE_ID)
++ return (7);
++
++ SB_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n", chip));
++ ASSERT(0);
++ return (1);
++}
++
++/* return index of coreid or BADIDX if not found */
++static uint
++sb_findcoreidx( sb_info_t *si, uint coreid, uint coreunit)
++{
++ uint found;
++ uint i;
++
++ found = 0;
++
++ for (i = 0; i < si->numcores; i++)
++ if (si->coreid[i] == coreid) {
++ if (found == coreunit)
++ return (i);
++ found++;
++ }
++
++ return (BADIDX);
++}
++
++/*
++ * this function changes logical "focus" to the indiciated core,
++ * must be called with interrupt off.
++ * Moreover, callers should keep interrupts off during switching out of and back to d11 core
++ */
++void*
++sb_setcoreidx(sb_t *sbh, uint coreidx)
++{
++ sb_info_t *si;
++ uint32 sbaddr;
++
++ si = SB_INFO(sbh);
++
++ if (coreidx >= si->numcores)
++ return (NULL);
++
++ /*
++ * If the user has provided an interrupt mask enabled function,
++ * then assert interrupts are disabled before switching the core.
++ */
++ ASSERT((si->intrsenabled_fn == NULL) || !(*(si)->intrsenabled_fn)((si)->intr_arg));
++
++ sbaddr = SB_ENUM_BASE + (coreidx * SB_CORE_SIZE);
++
++ switch (BUSTYPE(si->sb.bustype)) {
++ case SB_BUS:
++ /* map new one */
++ if (!si->regs[coreidx]) {
++ si->regs[coreidx] = (void*)REG_MAP(sbaddr, SB_CORE_SIZE);
++ ASSERT(GOODREGS(si->regs[coreidx]));
++ }
++ si->curmap = si->regs[coreidx];
++ break;
++
++ case PCI_BUS:
++ /* point bar0 window */
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_BAR0_WIN, 4, sbaddr);
++ break;
++
++#ifdef BCMJTAG
++ case JTAG_BUS:
++ /* map new one */
++ if (!si->regs[coreidx]) {
++ si->regs[coreidx] = (void *)sbaddr;
++ ASSERT(GOODREGS(si->regs[coreidx]));
++ }
++ si->curmap = si->regs[coreidx];
++ break;
++#endif /* BCMJTAG */
++ }
++
++ si->curidx = coreidx;
++
++ return (si->curmap);
++}
++
++/*
++ * this function changes logical "focus" to the indiciated core,
++ * must be called with interrupt off.
++ * Moreover, callers should keep interrupts off during switching out of and back to d11 core
++ */
++void*
++sb_setcore(sb_t *sbh, uint coreid, uint coreunit)
++{
++ sb_info_t *si;
++ uint idx;
++
++ si = SB_INFO(sbh);
++ idx = sb_findcoreidx(si, coreid, coreunit);
++ if (!GOODIDX(idx))
++ return (NULL);
++
++ return (sb_setcoreidx(sbh, idx));
++}
++
++/* return chip number */
++uint
++BCMINITFN(sb_chip)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.chip);
++}
++
++/* return chip revision number */
++uint
++BCMINITFN(sb_chiprev)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.chiprev);
++}
++
++/* return chip common revision number */
++uint
++BCMINITFN(sb_chipcrev)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.ccrev);
++}
++
++/* return chip package option */
++uint
++BCMINITFN(sb_chippkg)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.chippkg);
++}
++
++/* return PCI core rev. */
++uint
++BCMINITFN(sb_pcirev)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.buscorerev);
++}
++
++bool
++BCMINITFN(sb_war16165)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ return (PCI(si) && (si->sb.buscorerev <= 10));
++}
++
++/* return board vendor id */
++uint
++BCMINITFN(sb_boardvendor)(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.boardvendor);
++}
++
++/* return boardtype */
++uint
++BCMINITFN(sb_boardtype)(sb_t *sbh)
++{
++ sb_info_t *si;
++ char *var;
++
++ si = SB_INFO(sbh);
++
++ if (BUSTYPE(si->sb.bustype) == SB_BUS && si->sb.boardtype == 0xffff) {
++ /* boardtype format is a hex string */
++ si->sb.boardtype = getintvar(NULL, "boardtype");
++
++ /* backward compatibility for older boardtype string format */
++ if ((si->sb.boardtype == 0) && (var = getvar(NULL, "boardtype"))) {
++ if (!strcmp(var, "bcm94710dev"))
++ si->sb.boardtype = BCM94710D_BOARD;
++ else if (!strcmp(var, "bcm94710ap"))
++ si->sb.boardtype = BCM94710AP_BOARD;
++ else if (!strcmp(var, "bu4710"))
++ si->sb.boardtype = BU4710_BOARD;
++ else if (!strcmp(var, "bcm94702mn"))
++ si->sb.boardtype = BCM94702MN_BOARD;
++ else if (!strcmp(var, "bcm94710r1"))
++ si->sb.boardtype = BCM94710R1_BOARD;
++ else if (!strcmp(var, "bcm94710r4"))
++ si->sb.boardtype = BCM94710R4_BOARD;
++ else if (!strcmp(var, "bcm94702cpci"))
++ si->sb.boardtype = BCM94702CPCI_BOARD;
++ else if (!strcmp(var, "bcm95380_rr"))
++ si->sb.boardtype = BCM95380RR_BOARD;
++ }
++ }
++
++ return (si->sb.boardtype);
++}
++
++/* return bus type of sbh device */
++uint
++sb_bus(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ return (si->sb.bustype);
++}
++
++/* return bus core type */
++uint
++sb_buscoretype(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ return (si->sb.buscoretype);
++}
++
++/* return bus core revision */
++uint
++sb_buscorerev(sb_t *sbh)
++{
++ sb_info_t *si;
++ si = SB_INFO(sbh);
++
++ return (si->sb.buscorerev);
++}
++
++/* return list of found cores */
++uint
++sb_corelist(sb_t *sbh, uint coreid[])
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ bcopy((uchar*)si->coreid, (uchar*)coreid, (si->numcores * sizeof (uint)));
++ return (si->numcores);
++}
++
++/* return current register mapping */
++void *
++sb_coreregs(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ ASSERT(GOODREGS(si->curmap));
++
++ return (si->curmap);
++}
++
++
++/* do buffered registers update */
++void
++sb_commit(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint origidx;
++ uint intr_val = 0;
++
++ si = SB_INFO(sbh);
++
++ origidx = si->curidx;
++ ASSERT(GOODIDX(origidx));
++
++ INTR_OFF(si, intr_val);
++
++ /* switch over to chipcommon core if there is one, else use pci */
++ if (si->sb.ccrev != NOREV) {
++ chipcregs_t *ccregs = (chipcregs_t *)sb_setcore(sbh, SB_CC, 0);
++
++ /* do the buffer registers update */
++ W_REG(&ccregs->broadcastaddress, SB_COMMIT);
++ W_REG(&ccregs->broadcastdata, 0x0);
++ } else if (PCI(si)) {
++ sbpciregs_t *pciregs = (sbpciregs_t *)sb_setcore(sbh, SB_PCI, 0);
++
++ /* do the buffer registers update */
++ W_REG(&pciregs->bcastaddr, SB_COMMIT);
++ W_REG(&pciregs->bcastdata, 0x0);
++ } else
++ ASSERT(0);
++
++ /* restore core index */
++ sb_setcoreidx(sbh, origidx);
++ INTR_RESTORE(si, intr_val);
++}
++
++/* reset and re-enable a core */
++void
++sb_core_reset(sb_t *sbh, uint32 bits)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ volatile uint32 dummy;
++
++ si = SB_INFO(sbh);
++ ASSERT(GOODREGS(si->curmap));
++ sb = REGS2SB(si->curmap);
++
++ /*
++ * Must do the disable sequence first to work for arbitrary current core state.
++ */
++ sb_core_disable(sbh, bits);
++
++ /*
++ * Now do the initialization sequence.
++ */
++
++ /* set reset while enabling the clock and forcing them on throughout the core */
++ W_SBREG(si, &sb->sbtmstatelow, (SBTML_FGC | SBTML_CLK | SBTML_RESET | bits));
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(1);
++
++ if (R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_SERR) {
++ W_SBREG(si, &sb->sbtmstatehigh, 0);
++ }
++ if ((dummy = R_SBREG(si, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) {
++ AND_SBREG(si, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO));
++ }
++
++ /* clear reset and allow it to propagate throughout the core */
++ W_SBREG(si, &sb->sbtmstatelow, (SBTML_FGC | SBTML_CLK | bits));
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(1);
++
++ /* leave clock enabled */
++ W_SBREG(si, &sb->sbtmstatelow, (SBTML_CLK | bits));
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(1);
++}
++
++void
++sb_core_tofixup(sb_t *sbh)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++
++ if ( (BUSTYPE(si->sb.bustype) != PCI_BUS) || (PCI(si) && (si->sb.buscorerev >= 5)) )
++ return;
++
++ ASSERT(GOODREGS(si->curmap));
++ sb = REGS2SB(si->curmap);
++
++ if (BUSTYPE(si->sb.bustype) == SB_BUS) {
++ SET_SBREG(si, &sb->sbimconfiglow,
++ SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
++ (0x5 << SBIMCL_RTO_SHIFT) | 0x3);
++ } else {
++ if (sb_coreid(sbh) == SB_PCI) {
++ SET_SBREG(si, &sb->sbimconfiglow,
++ SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
++ (0x3 << SBIMCL_RTO_SHIFT) | 0x2);
++ } else {
++ SET_SBREG(si, &sb->sbimconfiglow, (SBIMCL_RTO_MASK | SBIMCL_STO_MASK), 0);
++ }
++ }
++
++ sb_commit(sbh);
++}
++
++/*
++ * Set the initiator timeout for the "master core".
++ * The master core is defined to be the core in control
++ * of the chip and so it issues accesses to non-memory
++ * locations (Because of dma *any* core can access memeory).
++ *
++ * The routine uses the bus to decide who is the master:
++ * SB_BUS => mips
++ * JTAG_BUS => chipc
++ * PCI_BUS => pci
++ *
++ * This routine exists so callers can disable initiator
++ * timeouts so accesses to very slow devices like otp
++ * won't cause an abort. The routine allows arbitrary
++ * settings of the service and request timeouts, though.
++ *
++ * Returns the timeout state before changing it or -1
++ * on error.
++ */
++
++#define TO_MASK (SBIMCL_RTO_MASK | SBIMCL_STO_MASK)
++
++uint32
++sb_set_initiator_to(sb_t *sbh, uint32 to)
++{
++ sb_info_t *si;
++ uint origidx, idx;
++ uint intr_val = 0;
++ uint32 tmp, ret = 0xffffffff;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++
++ if ((to & ~TO_MASK) != 0)
++ return ret;
++
++ /* Figure out the master core */
++ idx = BADIDX;
++ switch (BUSTYPE(si->sb.bustype)) {
++ case PCI_BUS:
++ idx = si->sb.buscoreidx;
++ break;
++ case JTAG_BUS:
++ idx = SB_CC_IDX;
++ break;
++ case SB_BUS:
++ if ((idx = sb_findcoreidx(si, SB_MIPS33, 0)) == BADIDX)
++ idx = sb_findcoreidx(si, SB_MIPS, 0);
++ break;
++ default:
++ ASSERT(0);
++ }
++ if (idx == BADIDX)
++ return ret;
++
++ INTR_OFF(si, intr_val);
++ origidx = sb_coreidx(sbh);
++
++ sb = REGS2SB(sb_setcoreidx(sbh, idx));
++
++ tmp = R_SBREG(si, &sb->sbimconfiglow);
++ ret = tmp & TO_MASK;
++ W_SBREG(si, &sb->sbimconfiglow, (tmp & ~TO_MASK) | to);
++
++ sb_commit(sbh);
++ sb_setcoreidx(sbh, origidx);
++ INTR_RESTORE(si, intr_val);
++ return ret;
++}
++
++void
++sb_core_disable(sb_t *sbh, uint32 bits)
++{
++ sb_info_t *si;
++ volatile uint32 dummy;
++ uint32 rej;
++ sbconfig_t *sb;
++
++ si = SB_INFO(sbh);
++
++ ASSERT(GOODREGS(si->curmap));
++ sb = REGS2SB(si->curmap);
++
++ /* if core is already in reset, just return */
++ if (R_SBREG(si, &sb->sbtmstatelow) & SBTML_RESET)
++ return;
++
++ /* reject value changed between sonics 2.2 and 2.3 */
++ if (si->sb.sonicsrev == SONICS_2_2)
++ rej = (1 << SBTML_REJ_SHIFT);
++ else
++ rej = (2 << SBTML_REJ_SHIFT);
++
++ /* if clocks are not enabled, put into reset and return */
++ if ((R_SBREG(si, &sb->sbtmstatelow) & SBTML_CLK) == 0)
++ goto disable;
++
++ /* set target reject and spin until busy is clear (preserve core-specific bits) */
++ OR_SBREG(si, &sb->sbtmstatelow, rej);
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(1);
++ SPINWAIT((R_SBREG(si, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000);
++
++ if (R_SBREG(si, &sb->sbidlow) & SBIDL_INIT) {
++ OR_SBREG(si, &sb->sbimstate, SBIM_RJ);
++ dummy = R_SBREG(si, &sb->sbimstate);
++ OSL_DELAY(1);
++ SPINWAIT((R_SBREG(si, &sb->sbimstate) & SBIM_BY), 100000);
++ }
++
++ /* set reset and reject while enabling the clocks */
++ W_SBREG(si, &sb->sbtmstatelow, (bits | SBTML_FGC | SBTML_CLK | rej | SBTML_RESET));
++ dummy = R_SBREG(si, &sb->sbtmstatelow);
++ OSL_DELAY(10);
++
++ /* don't forget to clear the initiator reject bit */
++ if (R_SBREG(si, &sb->sbidlow) & SBIDL_INIT)
++ AND_SBREG(si, &sb->sbimstate, ~SBIM_RJ);
++
++disable:
++ /* leave reset and reject asserted */
++ W_SBREG(si, &sb->sbtmstatelow, (bits | rej | SBTML_RESET));
++ OSL_DELAY(1);
++}
++
++/* set chip watchdog reset timer to fire in 'ticks' backplane cycles */
++void
++sb_watchdog(sb_t *sbh, uint ticks)
++{
++ sb_info_t *si = SB_INFO(sbh);
++
++ /* instant NMI */
++ switch (si->gpioid) {
++ case SB_CC:
++ sb_corereg(si, 0, OFFSETOF(chipcregs_t, watchdog), ~0, ticks);
++ break;
++ case SB_EXTIF:
++ sb_corereg(si, si->gpioidx, OFFSETOF(extifregs_t, watchdog), ~0, ticks);
++ break;
++ }
++}
++
++
++/*
++ * Configure the pci core for pci client (NIC) action
++ * coremask is the bitvec of cores by index to be enabled.
++ */
++void
++sb_pci_setup(sb_t *sbh, uint coremask)
++{
++ sb_info_t *si;
++ sbconfig_t *sb;
++ sbpciregs_t *pciregs;
++ uint32 sbflag;
++ uint32 w;
++ uint idx;
++
++ si = SB_INFO(sbh);
++
++ /* if not pci bus, we're done */
++ if (BUSTYPE(si->sb.bustype) != PCI_BUS)
++ return;
++
++ ASSERT(PCI(si));
++ ASSERT(si->sb.buscoreidx != BADIDX);
++
++ /* get current core index */
++ idx = si->curidx;
++
++ /* we interrupt on this backplane flag number */
++ ASSERT(GOODREGS(si->curmap));
++ sb = REGS2SB(si->curmap);
++ sbflag = R_SBREG(si, &sb->sbtpsflag) & SBTPS_NUM0_MASK;
++
++ /* switch over to pci core */
++ pciregs = (sbpciregs_t*) sb_setcoreidx(sbh, si->sb.buscoreidx);
++ sb = REGS2SB(pciregs);
++
++ /*
++ * Enable sb->pci interrupts. Assume
++ * PCI rev 2.3 support was added in pci core rev 6 and things changed..
++ */
++ if ((PCI(si) && ((si->sb.buscorerev) >= 6))) {
++ /* pci config write to set this core bit in PCIIntMask */
++ w = OSL_PCI_READ_CONFIG(si->osh, PCI_INT_MASK, sizeof(uint32));
++ w |= (coremask << PCI_SBIM_SHIFT);
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_INT_MASK, sizeof(uint32), w);
++ } else {
++ /* set sbintvec bit for our flag number */
++ OR_SBREG(si, &sb->sbintvec, (1 << sbflag));
++ }
++
++ if (PCI(si)) {
++ OR_REG(&pciregs->sbtopci2, (SBTOPCI_PREF|SBTOPCI_BURST));
++ if (si->sb.buscorerev >= 11)
++ OR_REG(&pciregs->sbtopci2, SBTOPCI_RC_READMULTI);
++ if (si->sb.buscorerev < 5) {
++ SET_SBREG(si, &sb->sbimconfiglow, SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
++ (0x3 << SBIMCL_RTO_SHIFT) | 0x2);
++ sb_commit(sbh);
++ }
++ }
++
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++}
++
++uint32
++sb_base(uint32 admatch)
++{
++ uint32 base;
++ uint type;
++
++ type = admatch & SBAM_TYPE_MASK;
++ ASSERT(type < 3);
++
++ base = 0;
++
++ if (type == 0) {
++ base = admatch & SBAM_BASE0_MASK;
++ } else if (type == 1) {
++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
++ base = admatch & SBAM_BASE1_MASK;
++ } else if (type == 2) {
++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
++ base = admatch & SBAM_BASE2_MASK;
++ }
++
++ return (base);
++}
++
++uint32
++sb_size(uint32 admatch)
++{
++ uint32 size;
++ uint type;
++
++ type = admatch & SBAM_TYPE_MASK;
++ ASSERT(type < 3);
++
++ size = 0;
++
++ if (type == 0) {
++ size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1);
++ } else if (type == 1) {
++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
++ size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1);
++ } else if (type == 2) {
++ ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
++ size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1);
++ }
++
++ return (size);
++}
++
++/* return the core-type instantiation # of the current core */
++uint
++sb_coreunit(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint idx;
++ uint coreid;
++ uint coreunit;
++ uint i;
++
++ si = SB_INFO(sbh);
++ coreunit = 0;
++
++ idx = si->curidx;
++
++ ASSERT(GOODREGS(si->curmap));
++ coreid = sb_coreid(sbh);
++
++ /* count the cores of our type */
++ for (i = 0; i < idx; i++)
++ if (si->coreid[i] == coreid)
++ coreunit++;
++
++ return (coreunit);
++}
++
++static INLINE uint32
++factor6(uint32 x)
++{
++ switch (x) {
++ case CC_F6_2: return 2;
++ case CC_F6_3: return 3;
++ case CC_F6_4: return 4;
++ case CC_F6_5: return 5;
++ case CC_F6_6: return 6;
++ case CC_F6_7: return 7;
++ default: return 0;
++ }
++}
++
++/* calculate the speed the SB would run at given a set of clockcontrol values */
++uint32
++sb_clock_rate(uint32 pll_type, uint32 n, uint32 m)
++{
++ uint32 n1, n2, clock, m1, m2, m3, mc;
++
++ n1 = n & CN_N1_MASK;
++ n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT;
++
++ if (pll_type == PLL_TYPE6) {
++ if (m & CC_T6_MMASK)
++ return CC_T6_M1;
++ else
++ return CC_T6_M0;
++ } else if ((pll_type == PLL_TYPE1) ||
++ (pll_type == PLL_TYPE3) ||
++ (pll_type == PLL_TYPE4) ||
++ (pll_type == PLL_TYPE7)) {
++ n1 = factor6(n1);
++ n2 += CC_F5_BIAS;
++ } else if (pll_type == PLL_TYPE2) {
++ n1 += CC_T2_BIAS;
++ n2 += CC_T2_BIAS;
++ ASSERT((n1 >= 2) && (n1 <= 7));
++ ASSERT((n2 >= 5) && (n2 <= 23));
++ } else if (pll_type == PLL_TYPE5) {
++ return (100000000);
++ } else
++ ASSERT(0);
++ /* PLL types 3 and 7 use BASE2 (25Mhz) */
++ if ((pll_type == PLL_TYPE3) ||
++ (pll_type == PLL_TYPE7)) {
++ clock = CC_CLOCK_BASE2 * n1 * n2;
++ }
++ else
++ clock = CC_CLOCK_BASE1 * n1 * n2;
++
++ if (clock == 0)
++ return 0;
++
++ m1 = m & CC_M1_MASK;
++ m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT;
++ m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT;
++ mc = (m & CC_MC_MASK) >> CC_MC_SHIFT;
++
++ if ((pll_type == PLL_TYPE1) ||
++ (pll_type == PLL_TYPE3) ||
++ (pll_type == PLL_TYPE4) ||
++ (pll_type == PLL_TYPE7)) {
++ m1 = factor6(m1);
++ if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3))
++ m2 += CC_F5_BIAS;
++ else
++ m2 = factor6(m2);
++ m3 = factor6(m3);
++
++ switch (mc) {
++ case CC_MC_BYPASS: return (clock);
++ case CC_MC_M1: return (clock / m1);
++ case CC_MC_M1M2: return (clock / (m1 * m2));
++ case CC_MC_M1M2M3: return (clock / (m1 * m2 * m3));
++ case CC_MC_M1M3: return (clock / (m1 * m3));
++ default: return (0);
++ }
++ } else {
++ ASSERT(pll_type == PLL_TYPE2);
++
++ m1 += CC_T2_BIAS;
++ m2 += CC_T2M2_BIAS;
++ m3 += CC_T2_BIAS;
++ ASSERT((m1 >= 2) && (m1 <= 7));
++ ASSERT((m2 >= 3) && (m2 <= 10));
++ ASSERT((m3 >= 2) && (m3 <= 7));
++
++ if ((mc & CC_T2MC_M1BYP) == 0)
++ clock /= m1;
++ if ((mc & CC_T2MC_M2BYP) == 0)
++ clock /= m2;
++ if ((mc & CC_T2MC_M3BYP) == 0)
++ clock /= m3;
++
++ return(clock);
++ }
++}
++
++/* returns the current speed the SB is running at */
++uint32
++sb_clock(sb_t *sbh)
++{
++ sb_info_t *si;
++ extifregs_t *eir;
++ chipcregs_t *cc;
++ uint32 n, m;
++ uint idx;
++ uint32 pll_type, rate;
++ uint intr_val = 0;
++
++ si = SB_INFO(sbh);
++ idx = si->curidx;
++ pll_type = PLL_TYPE1;
++
++ INTR_OFF(si, intr_val);
++
++ /* switch to extif or chipc core */
++ if ((eir = (extifregs_t *) sb_setcore(sbh, SB_EXTIF, 0))) {
++ n = R_REG(&eir->clockcontrol_n);
++ m = R_REG(&eir->clockcontrol_sb);
++ } else if ((cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0))) {
++ pll_type = R_REG(&cc->capabilities) & CAP_PLL_MASK;
++ n = R_REG(&cc->clockcontrol_n);
++ if (pll_type == PLL_TYPE6)
++ m = R_REG(&cc->clockcontrol_mips);
++ else if (pll_type == PLL_TYPE3)
++ {
++ // Added by Chen-I for 5365
++ if (BCMINIT(sb_chip)(sbh) == BCM5365_DEVICE_ID)
++ m = R_REG(&cc->clockcontrol_sb);
++ else
++ m = R_REG(&cc->clockcontrol_m2);
++ }
++ else
++ m = R_REG(&cc->clockcontrol_sb);
++ } else {
++ INTR_RESTORE(si, intr_val);
++ return 0;
++ }
++
++ // Added by Chen-I for 5365
++ if (BCMINIT(sb_chip)(sbh) == BCM5365_DEVICE_ID)
++ {
++ rate = 100000000;
++ }
++ else
++ {
++ /* calculate rate */
++ rate = sb_clock_rate(pll_type, n, m);
++ if (pll_type == PLL_TYPE3)
++ rate = rate / 2;
++ }
++
++ /* switch back to previous core */
++ sb_setcoreidx(sbh, idx);
++
++ INTR_RESTORE(si, intr_val);
++
++ return rate;
++}
++
++/* change logical "focus" to the gpio core for optimized access */
++void*
++sb_gpiosetcore(sb_t *sbh)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ return (sb_setcoreidx(sbh, si->gpioidx));
++}
++
++/* mask&set gpiocontrol bits */
++uint32
++sb_gpiocontrol(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
++ }
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpiocontrol);
++ break;
++
++ case SB_PCI:
++ regoff = OFFSETOF(sbpciregs_t, gpiocontrol);
++ break;
++
++ case SB_EXTIF:
++ return (0);
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
++
++/* mask&set gpio output enable bits */
++uint32
++sb_gpioouten(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
++ }
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpioouten);
++ break;
++
++ case SB_PCI:
++ regoff = OFFSETOF(sbpciregs_t, gpioouten);
++ break;
++
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpio[0].outen);
++ break;
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
++
++/* mask&set gpio output bits */
++uint32
++sb_gpioout(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
++ }
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpioout);
++ break;
++
++ case SB_PCI:
++ regoff = OFFSETOF(sbpciregs_t, gpioout);
++ break;
++
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpio[0].out);
++ break;
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
++
++/* reserve one gpio */
++uint32
++sb_gpioreserve(sb_t *sbh, uint32 gpio_bitmask, uint8 priority)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* only cores on SB_BUS share GPIO's and only applcation users need to reserve/release GPIO */
++ if ( (BUSTYPE(si->sb.bustype) != SB_BUS) || (!priority)) {
++ ASSERT((BUSTYPE(si->sb.bustype) == SB_BUS) && (priority));
++ return -1;
++ }
++ /* make sure only one bit is set */
++ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
++ ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1)));
++ return -1;
++ }
++
++ /* already reserved */
++ if (sb_gpioreservation & gpio_bitmask)
++ return -1;
++ /* set reservation */
++ sb_gpioreservation |= gpio_bitmask;
++
++ return sb_gpioreservation;
++}
++
++/* release one gpio */
++/*
++ * releasing the gpio doesn't change the current value on the GPIO last write value
++ * persists till some one overwrites it
++*/
++
++uint32
++sb_gpiorelease(sb_t *sbh, uint32 gpio_bitmask, uint8 priority)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* only cores on SB_BUS share GPIO's and only applcation users need to reserve/release GPIO */
++ if ( (BUSTYPE(si->sb.bustype) != SB_BUS) || (!priority)) {
++ ASSERT((BUSTYPE(si->sb.bustype) == SB_BUS) && (priority));
++ return -1;
++ }
++ /* make sure only one bit is set */
++ if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
++ ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1)));
++ return -1;
++ }
++
++ /* already released */
++ if (!(sb_gpioreservation & gpio_bitmask))
++ return -1;
++
++ /* clear reservation */
++ sb_gpioreservation &= ~gpio_bitmask;
++
++ return sb_gpioreservation;
++}
++
++/* return the current gpioin register value */
++uint32
++sb_gpioin(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpioin);
++ break;
++
++ case SB_PCI:
++ regoff = OFFSETOF(sbpciregs_t, gpioin);
++ break;
++
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpioin);
++ break;
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, 0, 0));
++}
++
++/* mask&set gpio interrupt polarity bits */
++uint32
++sb_gpiointpolarity(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
++ }
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpiointpolarity);
++ break;
++
++ case SB_PCI:
++ /* pci gpio implementation does not support interrupt polarity */
++ ASSERT(0);
++ break;
++
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpiointpolarity);
++ break;
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
++
++/* mask&set gpio interrupt mask bits */
++uint32
++sb_gpiointmask(sb_t *sbh, uint32 mask, uint32 val, uint8 priority)
++{
++ sb_info_t *si;
++ uint regoff;
++
++ si = SB_INFO(sbh);
++ regoff = 0;
++
++ priority = GPIO_DRV_PRIORITY; /* compatibility hack */
++
++ /* gpios could be shared on router platforms */
++ if ((BUSTYPE(si->sb.bustype) == SB_BUS) && (val || mask)) {
++ mask = priority ? (sb_gpioreservation & mask) :
++ ((sb_gpioreservation | mask) & ~(sb_gpioreservation));
++ val &= mask;
++ }
++
++ switch (si->gpioid) {
++ case SB_CC:
++ regoff = OFFSETOF(chipcregs_t, gpiointmask);
++ break;
++
++ case SB_PCI:
++ /* pci gpio implementation does not support interrupt mask */
++ ASSERT(0);
++ break;
++
++ case SB_EXTIF:
++ regoff = OFFSETOF(extifregs_t, gpiointmask);
++ break;
++ }
++
++ return (sb_corereg(si, si->gpioidx, regoff, mask, val));
++}
++
++/* assign the gpio to an led */
++uint32
++sb_gpioled(sb_t *sbh, uint32 mask, uint32 val)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ if (si->sb.ccrev < 16)
++ return -1;
++
++ /* gpio led powersave reg */
++ return(sb_corereg(si, 0, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val));
++}
++
++/* mask&set gpio timer val */
++uint32
++sb_gpiotimerval(sb_t *sbh, uint32 mask, uint32 gpiotimerval)
++{
++ sb_info_t *si;
++ si = SB_INFO(sbh);
++
++ if (si->sb.ccrev < 16)
++ return -1;
++
++ return(sb_corereg(si, 0, OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval));
++}
++
++
++/* return the slow clock source - LPO, XTAL, or PCI */
++static uint
++sb_slowclk_src(sb_info_t *si)
++{
++ chipcregs_t *cc;
++
++
++ ASSERT(sb_coreid(&si->sb) == SB_CC);
++
++ if (si->sb.ccrev < 6) {
++ if ((BUSTYPE(si->sb.bustype) == PCI_BUS)
++ && (OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUT, sizeof (uint32)) & PCI_CFG_GPIO_SCS))
++ return (SCC_SS_PCI);
++ else
++ return (SCC_SS_XTAL);
++ } else if (si->sb.ccrev < 10) {
++ cc = (chipcregs_t*) sb_setcoreidx(&si->sb, si->curidx);
++ return (R_REG(&cc->slow_clk_ctl) & SCC_SS_MASK);
++ } else /* Insta-clock */
++ return (SCC_SS_XTAL);
++}
++
++/* return the ILP (slowclock) min or max frequency */
++static uint
++sb_slowclk_freq(sb_info_t *si, bool max)
++{
++ chipcregs_t *cc;
++ uint32 slowclk;
++ uint div;
++
++
++ ASSERT(sb_coreid(&si->sb) == SB_CC);
++
++ cc = (chipcregs_t*) sb_setcoreidx(&si->sb, si->curidx);
++
++ /* shouldn't be here unless we've established the chip has dynamic clk control */
++ ASSERT(R_REG(&cc->capabilities) & CAP_PWR_CTL);
++
++ slowclk = sb_slowclk_src(si);
++ if (si->sb.ccrev < 6) {
++ if (slowclk == SCC_SS_PCI)
++ return (max? (PCIMAXFREQ/64) : (PCIMINFREQ/64));
++ else
++ return (max? (XTALMAXFREQ/32) : (XTALMINFREQ/32));
++ } else if (si->sb.ccrev < 10) {
++ div = 4 * (((R_REG(&cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1);
++ if (slowclk == SCC_SS_LPO)
++ return (max? LPOMAXFREQ : LPOMINFREQ);
++ else if (slowclk == SCC_SS_XTAL)
++ return (max? (XTALMAXFREQ/div) : (XTALMINFREQ/div));
++ else if (slowclk == SCC_SS_PCI)
++ return (max? (PCIMAXFREQ/div) : (PCIMINFREQ/div));
++ else
++ ASSERT(0);
++ } else {
++ /* Chipc rev 10 is InstaClock */
++ div = R_REG(&cc->system_clk_ctl) >> SYCC_CD_SHIFT;
++ div = 4 * (div + 1);
++ return (max ? XTALMAXFREQ : (XTALMINFREQ/div));
++ }
++ return (0);
++}
++
++static void
++sb_clkctl_setdelay(sb_info_t *si, void *chipcregs)
++{
++ chipcregs_t * cc;
++ uint slowmaxfreq, pll_delay, slowclk;
++ uint pll_on_delay, fref_sel_delay;
++
++ pll_delay = PLL_DELAY;
++
++ /* If the slow clock is not sourced by the xtal then add the xtal_on_delay
++ * since the xtal will also be powered down by dynamic clk control logic.
++ */
++ slowclk = sb_slowclk_src(si);
++ if (slowclk != SCC_SS_XTAL)
++ pll_delay += XTAL_ON_DELAY;
++
++ /* Starting with 4318 it is ILP that is used for the delays */
++ slowmaxfreq = sb_slowclk_freq(si, (si->sb.ccrev >= 10) ? FALSE : TRUE);
++
++ pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
++ fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
++
++ cc = (chipcregs_t *)chipcregs;
++ W_REG(&cc->pll_on_delay, pll_on_delay);
++ W_REG(&cc->fref_sel_delay, fref_sel_delay);
++}
++
++int
++sb_pwrctl_slowclk(void *sbh, bool set, uint *div)
++{
++ sb_info_t *si;
++ uint origidx;
++ chipcregs_t *cc;
++ uint intr_val = 0;
++ uint err = 0;
++
++ si = SB_INFO(sbh);
++
++ /* chipcommon cores prior to rev6 don't support slowclkcontrol */
++ if (si->sb.ccrev < 6)
++ return 1;
++
++ /* chipcommon cores rev10 are a whole new ball game */
++ if (si->sb.ccrev >= 10)
++ return 1;
++
++ if (set && ((*div % 4) || (*div < 4)))
++ return 2;
++
++ INTR_OFF(si, intr_val);
++ origidx = si->curidx;
++ cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0);
++ ASSERT(cc != NULL);
++
++ if (!(R_REG(&cc->capabilities) & CAP_PWR_CTL)) {
++ err = 3;
++ goto done;
++ }
++
++ if (set) {
++ SET_REG(&cc->slow_clk_ctl, SCC_CD_MASK, ((*div / 4 - 1) << SCC_CD_SHIFT));
++ sb_clkctl_setdelay(sbh, (void *)cc);
++ } else
++ *div = 4 * (((R_REG(&cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1);
++
++done:
++ sb_setcoreidx(sbh, origidx);
++ INTR_RESTORE(si, intr_val);
++ return err;
++}
++
++/* initialize power control delay registers */
++void sb_clkctl_init(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint origidx;
++ chipcregs_t *cc;
++
++ si = SB_INFO(sbh);
++
++ origidx = si->curidx;
++
++ if ((cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0)) == NULL)
++ return;
++
++ if (!(R_REG(&cc->capabilities) & CAP_PWR_CTL))
++ goto done;
++
++ /* set all Instaclk chip ILP to 1 MHz */
++ if (si->sb.ccrev >= 10)
++ SET_REG(&cc->system_clk_ctl, SYCC_CD_MASK, (ILP_DIV_1MHZ << SYCC_CD_SHIFT));
++
++ sb_clkctl_setdelay(si, (void *)cc);
++
++done:
++ sb_setcoreidx(sbh, origidx);
++}
++void sb_pwrctl_init(sb_t *sbh)
++{
++sb_clkctl_init(sbh);
++}
++/* return the value suitable for writing to the dot11 core FAST_PWRUP_DELAY register */
++uint16
++sb_clkctl_fast_pwrup_delay(sb_t *sbh)
++{
++ sb_info_t *si;
++ uint origidx;
++ chipcregs_t *cc;
++ uint slowminfreq;
++ uint16 fpdelay;
++ uint intr_val = 0;
++
++ si = SB_INFO(sbh);
++ fpdelay = 0;
++ origidx = si->curidx;
++
++ INTR_OFF(si, intr_val);
++
++ if ((cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0)) == NULL)
++ goto done;
++
++ if (!(R_REG(&cc->capabilities) & CAP_PWR_CTL))
++ goto done;
++
++ slowminfreq = sb_slowclk_freq(si, FALSE);
++ fpdelay = (((R_REG(&cc->pll_on_delay) + 2) * 1000000) + (slowminfreq - 1)) / slowminfreq;
++
++done:
++ sb_setcoreidx(sbh, origidx);
++ INTR_RESTORE(si, intr_val);
++ return (fpdelay);
++}
++uint16 sb_pwrctl_fast_pwrup_delay(sb_t *sbh)
++{
++return sb_clkctl_fast_pwrup_delay(sbh);
++}
++/* turn primary xtal and/or pll off/on */
++int
++sb_clkctl_xtal(sb_t *sbh, uint what, bool on)
++{
++ sb_info_t *si;
++ uint32 in, out, outen;
++
++ si = SB_INFO(sbh);
++
++ switch (BUSTYPE(si->sb.bustype)) {
++ case PCI_BUS:
++
++ in = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_IN, sizeof (uint32));
++ out = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUT, sizeof (uint32));
++ outen = OSL_PCI_READ_CONFIG(si->osh, PCI_GPIO_OUTEN, sizeof (uint32));
++
++ /*
++ * Avoid glitching the clock if GPRS is already using it.
++ * We can't actually read the state of the PLLPD so we infer it
++ * by the value of XTAL_PU which *is* readable via gpioin.
++ */
++ if (on && (in & PCI_CFG_GPIO_XTAL))
++ return (0);
++
++ if (what & XTAL)
++ outen |= PCI_CFG_GPIO_XTAL;
++ if (what & PLL)
++ outen |= PCI_CFG_GPIO_PLL;
++
++ if (on) {
++ /* turn primary xtal on */
++ if (what & XTAL) {
++ out |= PCI_CFG_GPIO_XTAL;
++ if (what & PLL)
++ out |= PCI_CFG_GPIO_PLL;
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUT, sizeof (uint32), out);
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUTEN, sizeof (uint32), outen);
++ OSL_DELAY(XTAL_ON_DELAY);
++ }
++
++ /* turn pll on */
++ if (what & PLL) {
++ out &= ~PCI_CFG_GPIO_PLL;
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUT, sizeof (uint32), out);
++ OSL_DELAY(2000);
++ }
++ } else {
++ if (what & XTAL)
++ out &= ~PCI_CFG_GPIO_XTAL;
++ if (what & PLL)
++ out |= PCI_CFG_GPIO_PLL;
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUT, sizeof (uint32), out);
++ OSL_PCI_WRITE_CONFIG(si->osh, PCI_GPIO_OUTEN, sizeof (uint32), outen);
++ }
++
++ default:
++ return (-1);
++ }
++
++ return (0);
++}
++
++int sb_pwrctl_xtal(sb_t *sbh, uint what, bool on)
++{
++return sb_clkctl_xtal(sbh,what,on);
++}
++
++/* set dynamic clk control mode (forceslow, forcefast, dynamic) */
++/* returns true if ignore pll off is set and false if it is not */
++bool
++sb_clkctl_clk(sb_t *sbh, uint mode)
++{
++ sb_info_t *si;
++ uint origidx;
++ chipcregs_t *cc;
++ uint32 scc;
++ bool forcefastclk=FALSE;
++ uint intr_val = 0;
++
++ si = SB_INFO(sbh);
++
++ /* chipcommon cores prior to rev6 don't support dynamic clock control */
++ if (si->sb.ccrev < 6)
++ return (FALSE);
++
++ /* chipcommon cores rev10 are a whole new ball game */
++ if (si->sb.ccrev >= 10)
++ return (FALSE);
++
++ INTR_OFF(si, intr_val);
++
++ origidx = si->curidx;
++
++ cc = (chipcregs_t*) sb_setcore(sbh, SB_CC, 0);
++ ASSERT(cc != NULL);
++
++ if (!(R_REG(&cc->capabilities) & CAP_PWR_CTL))
++ goto done;
++
++ switch (mode) {
++ case CLK_FAST: /* force fast (pll) clock */
++ /* don't forget to force xtal back on before we clear SCC_DYN_XTAL.. */
++ sb_clkctl_xtal(&si->sb, XTAL, ON);
++
++ SET_REG(&cc->slow_clk_ctl, (SCC_XC | SCC_FS | SCC_IP), SCC_IP);
++ break;
++
++ case CLK_DYNAMIC: /* enable dynamic clock control */
++ scc = R_REG(&cc->slow_clk_ctl);
++ scc &= ~(SCC_FS | SCC_IP | SCC_XC);
++ if ((scc & SCC_SS_MASK) != SCC_SS_XTAL)
++ scc |= SCC_XC;
++ W_REG(&cc->slow_clk_ctl, scc);
++
++ /* for dynamic control, we have to release our xtal_pu "force on" */
++ if (scc & SCC_XC)
++ sb_clkctl_xtal(&si->sb, XTAL, OFF);
++ break;
++
++ default:
++ ASSERT(0);
++ }
++
++ /* Is the h/w forcing the use of the fast clk */
++ forcefastclk = (bool)((R_REG(&cc->slow_clk_ctl) & SCC_IP) == SCC_IP);
++
++done:
++ sb_setcoreidx(sbh, origidx);
++ INTR_RESTORE(si, intr_val);
++ return (forcefastclk);
++}
++
++bool sb_pwrctl_clk(sb_t *sbh, uint mode)
++{
++return sb_clkctl_clk(sbh, mode);
++}
++/* register driver interrupt disabling and restoring callback functions */
++void
++sb_register_intr_callback(sb_t *sbh, void *intrsoff_fn, void *intrsrestore_fn, void *intrsenabled_fn, void *intr_arg)
++{
++ sb_info_t *si;
++
++ si = SB_INFO(sbh);
++ si->intr_arg = intr_arg;
++ si->intrsoff_fn = (sb_intrsoff_t)intrsoff_fn;
++ si->intrsrestore_fn = (sb_intrsrestore_t)intrsrestore_fn;
++ si->intrsenabled_fn = (sb_intrsenabled_t)intrsenabled_fn;
++ /* save current core id. when this function called, the current core
++ * must be the core which provides driver functions(il, et, wl, etc.)
++ */
++ si->dev_coreid = si->coreid[si->curidx];
++}
++
++
++void
++sb_corepciid(sb_t *sbh, uint16 *pcivendor, uint16 *pcidevice,
++ uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif)
++{
++ uint vendor, core, unit;
++ uint chip, chippkg;
++ char varname[8];
++ uint8 class, subclass, progif;
++
++ vendor = sb_corevendor(sbh);
++ core = sb_coreid(sbh);
++ unit = sb_coreunit(sbh);
++
++ chip = BCMINIT(sb_chip)(sbh);
++ chippkg = BCMINIT(sb_chippkg)(sbh);
++
++ progif = 0;
++
++ /* Known vendor translations */
++ switch (vendor) {
++ case SB_VEND_BCM:
++ vendor = VENDOR_BROADCOM;
++ break;
++ }
++
++ /* Determine class based on known core codes */
++ switch (core) {
++ case SB_ILINE20:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_ETHER;
++ core = BCM47XX_ILINE_ID;
++ break;
++ case SB_ENET:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_ETHER;
++ core = BCM47XX_ENET_ID;
++ break;
++ case SB_SDRAM:
++ case SB_MEMC:
++ class = PCI_CLASS_MEMORY;
++ subclass = PCI_MEMORY_RAM;
++ break;
++ case SB_PCI:
++ class = PCI_CLASS_BRIDGE;
++ subclass = PCI_BRIDGE_PCI;
++ break;
++ case SB_MIPS:
++ case SB_MIPS33:
++ class = PCI_CLASS_CPU;
++ subclass = PCI_CPU_MIPS;
++ break;
++ case SB_CODEC:
++ class = PCI_CLASS_COMM;
++ subclass = PCI_COMM_MODEM;
++ core = BCM47XX_V90_ID;
++ break;
++ case SB_USB:
++ class = PCI_CLASS_SERIAL;
++ subclass = PCI_SERIAL_USB;
++ progif = 0x10; /* OHCI */
++ core = BCM47XX_USB_ID;
++ break;
++ case SB_USB11H:
++ class = PCI_CLASS_SERIAL;
++ subclass = PCI_SERIAL_USB;
++ progif = 0x10; /* OHCI */
++ core = BCM47XX_USBH_ID;
++ break;
++ case SB_USB11D:
++ class = PCI_CLASS_SERIAL;
++ subclass = PCI_SERIAL_USB;
++ core = BCM47XX_USBD_ID;
++ break;
++ case SB_IPSEC:
++ class = PCI_CLASS_CRYPT;
++ subclass = PCI_CRYPT_NETWORK;
++ core = BCM47XX_IPSEC_ID;
++ break;
++ case SB_ROBO:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_OTHER;
++ core = BCM47XX_ROBO_ID;
++ break;
++ case SB_EXTIF:
++ case SB_CC:
++ class = PCI_CLASS_MEMORY;
++ subclass = PCI_MEMORY_FLASH;
++ break;
++ case SB_D11:
++ class = PCI_CLASS_NET;
++ subclass = PCI_NET_OTHER;
++ /* Let an nvram variable override this */
++ sprintf(varname, "wl%did", unit);
++ if ((core = getintvar(NULL, varname)) == 0) {
++ if (chip == BCM4712_DEVICE_ID) {
++ if (chippkg == BCM4712SMALL_PKG_ID)
++ core = BCM4306_D11G_ID;
++ else
++ core = BCM4306_D11DUAL_ID;
++ }
++ }
++ break;
++
++ default:
++ class = subclass = progif = 0xff;
++ break;
++ }
++
++ *pcivendor = (uint16)vendor;
++ *pcidevice = (uint16)core;
++ *pciclass = class;
++ *pcisubclass = subclass;
++ *pciprogif = progif;
++}
++
++/* Fix chip's configuration. The current core may be changed upon return */
++static int
++sb_pci_fixcfg(sb_info_t *si)
++{
++ uint origidx, pciidx;
++ sbpciregs_t *pciregs;
++ uint16 val16, *reg16;
++
++ ASSERT(BUSTYPE(si->sb.bustype) == PCI_BUS);
++
++ /* Fix PCI(e) SROM shadow area */
++ /* save the current index */
++ origidx = sb_coreidx(&si->sb);
++
++ if (si->sb.buscoretype == SB_PCI) {
++ pciregs = (sbpciregs_t *)sb_setcore(&si->sb, SB_PCI, 0);
++ ASSERT(pciregs);
++ reg16 = &pciregs->sprom[SRSH_PI_OFFSET];
++ }
++ else {
++ ASSERT(0);
++ return -1;
++ }
++ pciidx = sb_coreidx(&si->sb);
++ val16 = R_REG(reg16);
++ if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (uint16)pciidx) {
++ val16 = (uint16)(pciidx << SRSH_PI_SHIFT) | (val16 & ~SRSH_PI_MASK);
++ W_REG(reg16, val16);
++ }
++
++ /* restore the original index */
++ sb_setcoreidx(&si->sb, origidx);
++
++ return 0;
++}
++
++EXPORT_SYMBOL(sb_boardtype);
++EXPORT_SYMBOL(sb_boardvendor);
++EXPORT_SYMBOL(sb_gpiocontrol);
++EXPORT_SYMBOL(sb_gpioin);
++EXPORT_SYMBOL(sb_gpiointmask);
++EXPORT_SYMBOL(sb_gpiointpolarity);
++EXPORT_SYMBOL(sb_gpioled);
++EXPORT_SYMBOL(sb_gpioout);
++EXPORT_SYMBOL(sb_gpioouten);
++EXPORT_SYMBOL(sb_gpiorelease);
++EXPORT_SYMBOL(sb_gpioreserve);
++EXPORT_SYMBOL(sb_gpiosetcore);
++EXPORT_SYMBOL(sb_gpiotimerval);
++EXPORT_SYMBOL(sb_watchdog);
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/broadcom/sflash.c linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/sflash.c
+--- linux-2.6.17/arch/mips/bcm947xx/broadcom/sflash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/broadcom/sflash.c 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,418 @@
++/*
++ * Broadcom SiliconBackplane chipcommon serial flash interface
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#include <osl.h>
++#include <typedefs.h>
++#include <sbconfig.h>
++#include <sbchipc.h>
++#include <mipsinc.h>
++#include <bcmutils.h>
++#include <bcmdevs.h>
++#include <sflash.h>
++
++/* Private global state */
++static struct sflash sflash;
++
++/* Issue a serial flash command */
++static INLINE void
++sflash_cmd(chipcregs_t *cc, uint opcode)
++{
++ W_REG(&cc->flashcontrol, SFLASH_START | opcode);
++ while (R_REG(&cc->flashcontrol) & SFLASH_BUSY);
++}
++
++/* Initialize serial flash access */
++struct sflash *
++sflash_init(chipcregs_t *cc)
++{
++ uint32 id, id2;
++
++ bzero(&sflash, sizeof(sflash));
++
++ sflash.type = R_REG(&cc->capabilities) & CAP_FLASH_MASK;
++
++ switch (sflash.type) {
++ case SFLASH_ST:
++ /* Probe for ST chips */
++ sflash_cmd(cc, SFLASH_ST_DP);
++ sflash_cmd(cc, SFLASH_ST_RES);
++ id = R_REG(&cc->flashdata);
++ switch (id) {
++ case 0x11:
++ /* ST M25P20 2 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 4;
++ break;
++ case 0x12:
++ /* ST M25P40 4 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 8;
++ break;
++ case 0x13:
++ /* ST M25P80 8 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 16;
++ break;
++ case 0x14:
++ /* ST M25P16 16 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 32;
++ break;
++ case 0x15:
++ /* ST M25P32 32 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 64;
++ break;
++ case 0xbf:
++ W_REG(&cc->flashaddress, 1);
++ sflash_cmd(cc, SFLASH_ST_RES);
++ id2 = R_REG(&cc->flashdata);
++ if (id2 == 0x44) {
++ /* SST M25VF80 4 Mbit Serial Flash */
++ sflash.blocksize = 64 * 1024;
++ sflash.numblocks = 8;
++ }
++ break;
++ }
++ break;
++
++ case SFLASH_AT:
++ /* Probe for Atmel chips */
++ sflash_cmd(cc, SFLASH_AT_STATUS);
++ id = R_REG(&cc->flashdata) & 0x3c;
++ switch (id) {
++ case 0xc:
++ /* Atmel AT45DB011 1Mbit Serial Flash */
++ sflash.blocksize = 256;
++ sflash.numblocks = 512;
++ break;
++ case 0x14:
++ /* Atmel AT45DB021 2Mbit Serial Flash */
++ sflash.blocksize = 256;
++ sflash.numblocks = 1024;
++ break;
++ case 0x1c:
++ /* Atmel AT45DB041 4Mbit Serial Flash */
++ sflash.blocksize = 256;
++ sflash.numblocks = 2048;
++ break;
++ case 0x24:
++ /* Atmel AT45DB081 8Mbit Serial Flash */
++ sflash.blocksize = 256;
++ sflash.numblocks = 4096;
++ break;
++ case 0x2c:
++ /* Atmel AT45DB161 16Mbit Serial Flash */
++ sflash.blocksize = 512;
++ sflash.numblocks = 4096;
++ break;
++ case 0x34:
++ /* Atmel AT45DB321 32Mbit Serial Flash */
++ sflash.blocksize = 512;
++ sflash.numblocks = 8192;
++ break;
++ case 0x3c:
++ /* Atmel AT45DB642 64Mbit Serial Flash */
++ sflash.blocksize = 1024;
++ sflash.numblocks = 8192;
++ break;
++ }
++ break;
++ }
++
++ sflash.size = sflash.blocksize * sflash.numblocks;
++ return sflash.size ? &sflash : NULL;
++}
++
++/* Read len bytes starting at offset into buf. Returns number of bytes read. */
++int
++sflash_read(chipcregs_t *cc, uint offset, uint len, uchar *buf)
++{
++ int cnt;
++ uint32 *from, *to;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > sflash.size)
++ return -22;
++
++ if ((len >= 4) && (offset & 3))
++ cnt = 4 - (offset & 3);
++ else if ((len >= 4) && ((uint32)buf & 3))
++ cnt = 4 - ((uint32)buf & 3);
++ else
++ cnt = len;
++
++ from = (uint32 *)KSEG1ADDR(SB_FLASH2 + offset);
++ to = (uint32 *)buf;
++
++ if (cnt < 4) {
++ bcopy(from, to, cnt);
++ return cnt;
++ }
++
++ while (cnt >= 4) {
++ *to++ = *from++;
++ cnt -= 4;
++ }
++
++ return (len - cnt);
++}
++
++/* Poll for command completion. Returns zero when complete. */
++int
++sflash_poll(chipcregs_t *cc, uint offset)
++{
++ if (offset >= sflash.size)
++ return -22;
++
++ switch (sflash.type) {
++ case SFLASH_ST:
++ /* Check for ST Write In Progress bit */
++ sflash_cmd(cc, SFLASH_ST_RDSR);
++ return R_REG(&cc->flashdata) & SFLASH_ST_WIP;
++ case SFLASH_AT:
++ /* Check for Atmel Ready bit */
++ sflash_cmd(cc, SFLASH_AT_STATUS);
++ return !(R_REG(&cc->flashdata) & SFLASH_AT_READY);
++ }
++
++ return 0;
++}
++
++/* Write len bytes starting at offset into buf. Returns number of bytes
++ * written. Caller should poll for completion.
++ */
++int
++sflash_write(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
++{
++ struct sflash *sfl;
++ int ret = 0;
++ bool is4712b0;
++ uint32 page, byte, mask;
++
++ if (!len)
++ return 0;
++
++ if ((offset + len) > sflash.size)
++ return -22;
++
++ sfl = &sflash;
++ switch (sfl->type) {
++ case SFLASH_ST:
++ mask = R_REG(&cc->chipid);
++ is4712b0 = (((mask & CID_ID_MASK) == BCM4712_DEVICE_ID) &&
++ ((mask & CID_REV_MASK) == (3 << CID_REV_SHIFT)));
++ /* Enable writes */
++ sflash_cmd(cc, SFLASH_ST_WREN);
++ if (is4712b0) {
++ mask = 1 << 14;
++ W_REG(&cc->flashaddress, offset);
++ W_REG(&cc->flashdata, *buf++);
++ /* Set chip select */
++ OR_REG(&cc->gpioout, mask);
++ /* Issue a page program with the first byte */
++ sflash_cmd(cc, SFLASH_ST_PP);
++ ret = 1;
++ offset++;
++ len--;
++ while (len > 0) {
++ if ((offset & 255) == 0) {
++ /* Page boundary, drop cs and return */
++ AND_REG(&cc->gpioout, ~mask);
++ if (!sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -11;
++ }
++ return ret;
++ } else {
++ /* Write single byte */
++ sflash_cmd(cc, *buf++);
++ }
++ ret++;
++ offset++;
++ len--;
++ }
++ /* All done, drop cs if needed */
++ if ((offset & 255) != 1) {
++ /* Drop cs */
++ AND_REG(&cc->gpioout, ~mask);
++ if (!sflash_poll(cc, offset)) {
++ /* Flash rejected command */
++ return -12;
++ }
++ }
++ } else {
++ ret = 1;
++ W_REG(&cc->flashaddress, offset);
++ W_REG(&cc->flashdata, *buf);
++ /* Page program */
++ sflash_cmd(cc, SFLASH_ST_PP);
++ }
++ break;
++ case SFLASH_AT:
++ mask = sfl->blocksize - 1;
++ page = (offset & ~mask) << 1;
++ byte = offset & mask;
++ /* Read main memory page into buffer 1 */
++ if (byte || len < sfl->blocksize) {
++ W_REG(&cc->flashaddress, page);
++ sflash_cmd(cc, SFLASH_AT_BUF1_LOAD);
++ /* 250 us for AT45DB321B */
++ SPINWAIT(sflash_poll(cc, offset), 1000);
++ ASSERT(!sflash_poll(cc, offset));
++ }
++ /* Write into buffer 1 */
++ for (ret = 0; ret < len && byte < sfl->blocksize; ret++) {
++ W_REG(&cc->flashaddress, byte++);
++ W_REG(&cc->flashdata, *buf++);
++ sflash_cmd(cc, SFLASH_AT_BUF1_WRITE);
++ }
++ /* Write buffer 1 into main memory page */
++ W_REG(&cc->flashaddress, page);
++ sflash_cmd(cc, SFLASH_AT_BUF1_PROGRAM);
++ break;
++ }
++
++ return ret;
++}
++
++/* Erase a region. Returns number of bytes scheduled for erasure.
++ * Caller should poll for completion.
++ */
++int
++sflash_erase(chipcregs_t *cc, uint offset)
++{
++ struct sflash *sfl;
++
++ if (offset >= sflash.size)
++ return -22;
++
++ sfl = &sflash;
++ switch (sfl->type) {
++ case SFLASH_ST:
++ sflash_cmd(cc, SFLASH_ST_WREN);
++ W_REG(&cc->flashaddress, offset);
++ sflash_cmd(cc, SFLASH_ST_SE);
++ return sfl->blocksize;
++ case SFLASH_AT:
++ W_REG(&cc->flashaddress, offset << 1);
++ sflash_cmd(cc, SFLASH_AT_PAGE_ERASE);
++ return sfl->blocksize;
++ }
++
++ return 0;
++}
++
++/*
++ * writes the appropriate range of flash, a NULL buf simply erases
++ * the region of flash
++ */
++int
++sflash_commit(chipcregs_t *cc, uint offset, uint len, const uchar *buf)
++{
++ struct sflash *sfl;
++ uchar *block = NULL, *cur_ptr, *blk_ptr;
++ uint blocksize = 0, mask, cur_offset, cur_length, cur_retlen, remainder;
++ uint blk_offset, blk_len, copied;
++ int bytes, ret = 0;
++
++ /* Check address range */
++ if (len <= 0)
++ return 0;
++
++ sfl = &sflash;
++ if ((offset + len) > sfl->size)
++ return -1;
++
++ blocksize = sfl->blocksize;
++ mask = blocksize - 1;
++
++ /* Allocate a block of mem */
++ if (!(block = MALLOC(NULL, blocksize)))
++ return -1;
++
++ while (len) {
++ /* Align offset */
++ cur_offset = offset & ~mask;
++ cur_length = blocksize;
++ cur_ptr = block;
++
++ remainder = blocksize - (offset & mask);
++ if (len < remainder)
++ cur_retlen = len;
++ else
++ cur_retlen = remainder;
++
++ /* buf == NULL means erase only */
++ if (buf) {
++ /* Copy existing data into holding block if necessary */
++ if ((offset & mask) || (len < blocksize)) {
++ blk_offset = cur_offset;
++ blk_len = cur_length;
++ blk_ptr = cur_ptr;
++
++ /* Copy entire block */
++ while(blk_len) {
++ copied = sflash_read(cc, blk_offset, blk_len, blk_ptr);
++ blk_offset += copied;
++ blk_len -= copied;
++ blk_ptr += copied;
++ }
++ }
++
++ /* Copy input data into holding block */
++ memcpy(cur_ptr + (offset & mask), buf, cur_retlen);
++ }
++
++ /* Erase block */
++ if ((ret = sflash_erase(cc, (uint) cur_offset)) < 0)
++ goto done;
++ while (sflash_poll(cc, (uint) cur_offset));
++
++ /* buf == NULL means erase only */
++ if (!buf) {
++ offset += cur_retlen;
++ len -= cur_retlen;
++ continue;
++ }
++
++ /* Write holding block */
++ while (cur_length > 0) {
++ if ((bytes = sflash_write(cc,
++ (uint) cur_offset,
++ (uint) cur_length,
++ (uchar *) cur_ptr)) < 0) {
++ ret = bytes;
++ goto done;
++ }
++ while (sflash_poll(cc, (uint) cur_offset));
++ cur_offset += bytes;
++ cur_length -= bytes;
++ cur_ptr += bytes;
++ }
++
++ offset += cur_retlen;
++ len -= cur_retlen;
++ buf += cur_retlen;
++ }
++
++ ret = len;
++done:
++ if (block)
++ MFREE(NULL, block, blocksize);
++ return ret;
++}
++
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/bcmdevs.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/bcmdevs.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/bcmdevs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/bcmdevs.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,391 @@
++/*
++ * Broadcom device-specific manifest constants.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id$
++ */
++
++#ifndef _BCMDEVS_H
++#define _BCMDEVS_H
++
++
++/* Known PCI vendor Id's */
++#define VENDOR_EPIGRAM 0xfeda
++#define VENDOR_BROADCOM 0x14e4
++#define VENDOR_3COM 0x10b7
++#define VENDOR_NETGEAR 0x1385
++#define VENDOR_DIAMOND 0x1092
++#define VENDOR_DELL 0x1028
++#define VENDOR_HP 0x0e11
++#define VENDOR_APPLE 0x106b
++
++/* PCI Device Id's */
++#define BCM4210_DEVICE_ID 0x1072 /* never used */
++#define BCM4211_DEVICE_ID 0x4211
++#define BCM4230_DEVICE_ID 0x1086 /* never used */
++#define BCM4231_DEVICE_ID 0x4231
++
++#define BCM4410_DEVICE_ID 0x4410 /* bcm44xx family pci iline */
++#define BCM4430_DEVICE_ID 0x4430 /* bcm44xx family cardbus iline */
++#define BCM4412_DEVICE_ID 0x4412 /* bcm44xx family pci enet */
++#define BCM4432_DEVICE_ID 0x4432 /* bcm44xx family cardbus enet */
++
++#define BCM3352_DEVICE_ID 0x3352 /* bcm3352 device id */
++#define BCM3360_DEVICE_ID 0x3360 /* bcm3360 device id */
++
++#define EPI41210_DEVICE_ID 0xa0fa /* bcm4210 */
++#define EPI41230_DEVICE_ID 0xa10e /* bcm4230 */
++
++#define BCM47XX_ILINE_ID 0x4711 /* 47xx iline20 */
++#define BCM47XX_V90_ID 0x4712 /* 47xx v90 codec */
++#define BCM47XX_ENET_ID 0x4713 /* 47xx enet */
++#define BCM47XX_EXT_ID 0x4714 /* 47xx external i/f */
++#define BCM47XX_USB_ID 0x4715 /* 47xx usb */
++#define BCM47XX_USBH_ID 0x4716 /* 47xx usb host */
++#define BCM47XX_USBD_ID 0x4717 /* 47xx usb device */
++#define BCM47XX_IPSEC_ID 0x4718 /* 47xx ipsec */
++#define BCM47XX_ROBO_ID 0x4719 /* 47xx/53xx roboswitch core */
++#define BCM47XX_USB20H_ID 0x471a /* 47xx usb 2.0 host */
++#define BCM47XX_USB20D_ID 0x471b /* 47xx usb 2.0 device */
++
++#define BCM4710_DEVICE_ID 0x4710 /* 4710 primary function 0 */
++
++#define BCM4610_DEVICE_ID 0x4610 /* 4610 primary function 0 */
++#define BCM4610_ILINE_ID 0x4611 /* 4610 iline100 */
++#define BCM4610_V90_ID 0x4612 /* 4610 v90 codec */
++#define BCM4610_ENET_ID 0x4613 /* 4610 enet */
++#define BCM4610_EXT_ID 0x4614 /* 4610 external i/f */
++#define BCM4610_USB_ID 0x4615 /* 4610 usb */
++
++#define BCM4402_DEVICE_ID 0x4402 /* 4402 primary function 0 */
++#define BCM4402_ENET_ID 0x4402 /* 4402 enet */
++#define BCM4402_V90_ID 0x4403 /* 4402 v90 codec */
++#define BCM4401_ENET_ID 0x170c /* 4401b0 production enet cards */
++
++#define BCM4301_DEVICE_ID 0x4301 /* 4301 primary function 0 */
++#define BCM4301_D11B_ID 0x4301 /* 4301 802.11b */
++
++#define BCM4307_DEVICE_ID 0x4307 /* 4307 primary function 0 */
++#define BCM4307_V90_ID 0x4305 /* 4307 v90 codec */
++#define BCM4307_ENET_ID 0x4306 /* 4307 enet */
++#define BCM4307_D11B_ID 0x4307 /* 4307 802.11b */
++
++#define BCM4306_DEVICE_ID 0x4306 /* 4306 chipcommon chipid */
++#define BCM4306_D11G_ID 0x4320 /* 4306 802.11g */
++#define BCM4306_D11G_ID2 0x4325
++#define BCM4306_D11A_ID 0x4321 /* 4306 802.11a */
++#define BCM4306_UART_ID 0x4322 /* 4306 uart */
++#define BCM4306_V90_ID 0x4323 /* 4306 v90 codec */
++#define BCM4306_D11DUAL_ID 0x4324 /* 4306 dual A+B */
++
++#define BCM4309_PKG_ID 1 /* 4309 package id */
++
++#define BCM4303_D11B_ID 0x4303 /* 4303 802.11b */
++#define BCM4303_PKG_ID 2 /* 4303 package id */
++
++#define BCM4310_DEVICE_ID 0x4310 /* 4310 chipcommon chipid */
++#define BCM4310_D11B_ID 0x4311 /* 4310 802.11b */
++#define BCM4310_UART_ID 0x4312 /* 4310 uart */
++#define BCM4310_ENET_ID 0x4313 /* 4310 enet */
++#define BCM4310_USB_ID 0x4315 /* 4310 usb */
++
++#define BCMGPRS_UART_ID 0x4333 /* Uart id used by 4306/gprs card */
++#define BCMGPRS2_UART_ID 0x4344 /* Uart id used by 4306/gprs card */
++
++
++#define BCM4704_DEVICE_ID 0x4704 /* 4704 chipcommon chipid */
++#define BCM4704_ENET_ID 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */
++
++#define BCM4317_DEVICE_ID 0x4317 /* 4317 chip common chipid */
++
++#define BCM4318_DEVICE_ID 0x4318 /* 4318 chip common chipid */
++#define BCM4318_D11G_ID 0x4318 /* 4318 801.11b/g id */
++#define BCM4318_D11DUAL_ID 0x4319 /* 4318 801.11a/b/g id */
++#define BCM4318_JTAGM_ID 0x4331 /* 4318 jtagm device id */
++
++#define FPGA_JTAGM_ID 0x4330 /* ??? */
++
++/* Address map */
++#define BCM4710_SDRAM 0x00000000 /* Physical SDRAM */
++#define BCM4710_PCI_MEM 0x08000000 /* Host Mode PCI memory access space (64 MB) */
++#define BCM4710_PCI_CFG 0x0c000000 /* Host Mode PCI configuration space (64 MB) */
++#define BCM4710_PCI_DMA 0x40000000 /* Client Mode PCI memory access space (1 GB) */
++#define BCM4710_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */
++#define BCM4710_ENUM 0x18000000 /* Beginning of core enumeration space */
++
++/* Core register space */
++#define BCM4710_REG_SDRAM 0x18000000 /* SDRAM core registers */
++#define BCM4710_REG_ILINE20 0x18001000 /* InsideLine20 core registers */
++#define BCM4710_REG_EMAC0 0x18002000 /* Ethernet MAC 0 core registers */
++#define BCM4710_REG_CODEC 0x18003000 /* Codec core registers */
++#define BCM4710_REG_USB 0x18004000 /* USB core registers */
++#define BCM4710_REG_PCI 0x18005000 /* PCI core registers */
++#define BCM4710_REG_MIPS 0x18006000 /* MIPS core registers */
++#define BCM4710_REG_EXTIF 0x18007000 /* External Interface core registers */
++#define BCM4710_REG_EMAC1 0x18008000 /* Ethernet MAC 1 core registers */
++
++#define BCM4710_EXTIF 0x1f000000 /* External Interface base address */
++#define BCM4710_PCMCIA_MEM 0x1f000000 /* External Interface PCMCIA memory access */
++#define BCM4710_PCMCIA_IO 0x1f100000 /* PCMCIA I/O access */
++#define BCM4710_PCMCIA_CONF 0x1f200000 /* PCMCIA configuration */
++#define BCM4710_PROG 0x1f800000 /* Programable interface */
++#define BCM4710_FLASH 0x1fc00000 /* Flash */
++
++#define BCM4710_EJTAG 0xff200000 /* MIPS EJTAG space (2M) */
++
++#define BCM4710_UART (BCM4710_REG_EXTIF + 0x00000300)
++
++#define BCM4710_EUART (BCM4710_EXTIF + 0x00800000)
++#define BCM4710_LED (BCM4710_EXTIF + 0x00900000)
++
++#define BCM4712_DEVICE_ID 0x4712 /* 4712 chipcommon chipid */
++#define BCM4712_MIPS_ID 0x4720 /* 4712 base devid */
++#define BCM4712LARGE_PKG_ID 0 /* 340pin 4712 package id */
++#define BCM4712SMALL_PKG_ID 1 /* 200pin 4712 package id */
++#define BCM4712MID_PKG_ID 2 /* 225pin 4712 package id */
++
++#define SDIOH_FPGA_ID 0x4380 /* sdio host fpga */
++
++#define BCM5365_DEVICE_ID 0x5365 /* 5365 chipcommon chipid */
++#define BCM5350_DEVICE_ID 0x5350 /* bcm5350 chipcommon chipid */
++#define BCM5352_DEVICE_ID 0x5352 /* bcm5352 chipcommon chipid */
++
++#define BCM4320_DEVICE_ID 0x4320 /* bcm4320 chipcommon chipid */
++
++/* PCMCIA vendor Id's */
++
++#define VENDOR_BROADCOM_PCMCIA 0x02d0
++
++/* SDIO vendor Id's */
++#define VENDOR_BROADCOM_SDIO 0x00BF
++
++
++/* boardflags */
++#define BFL_BTCOEXIST 0x0001 /* This board implements Bluetooth coexistance */
++#define BFL_PACTRL 0x0002 /* This board has gpio 9 controlling the PA */
++#define BFL_AIRLINEMODE 0x0004 /* This board implements gpio13 radio disable indication */
++#define BFL_ENETROBO 0x0010 /* This board has robo switch or core */
++#define BFL_CCKHIPWR 0x0040 /* Can do high-power CCK transmission */
++#define BFL_ENETADM 0x0080 /* This board has ADMtek switch */
++#define BFL_ENETVLAN 0x0100 /* This board has vlan capability */
++#define BFL_AFTERBURNER 0x0200 /* This board supports Afterburner mode */
++#define BFL_NOPCI 0x0400 /* This board leaves PCI floating */
++#define BFL_FEM 0x0800 /* This board supports the Front End Module */
++#define BFL_EXTLNA 0x1000 /* This board has an external LNA */
++#define BFL_HGPA 0x2000 /* This board has a high gain PA */
++#define BFL_BTCMOD 0x4000 /* This board' BTCOEXIST is in the alternate gpios */
++#define BFL_ALTIQ 0x8000 /* Alternate I/Q settings */
++
++/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */
++#define BOARD_GPIO_HWRAD_B 0x010 /* bit 4 is HWRAD input on 4301 */
++#define BOARD_GPIO_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistance Input */
++#define BOARD_GPIO_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistance Out */
++#define BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistance Input */
++#define BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistance Out */
++#define BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */
++#define PCI_CFG_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */
++#define PCI_CFG_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */
++#define PCI_CFG_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */
++#define PCI_CFG_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */
++
++/* Bus types */
++#define SB_BUS 0 /* Silicon Backplane */
++#define PCI_BUS 1 /* PCI target */
++#define PCMCIA_BUS 2 /* PCMCIA target */
++#define SDIO_BUS 3 /* SDIO target */
++#define JTAG_BUS 4 /* JTAG */
++
++/* Allows optimization for single-bus support */
++#ifdef BCMBUSTYPE
++#define BUSTYPE(bus) (BCMBUSTYPE)
++#else
++#define BUSTYPE(bus) (bus)
++#endif
++
++/* power control defines */
++#define PLL_DELAY 150 /* us pll on delay */
++#define FREF_DELAY 200 /* us fref change delay */
++#define MIN_SLOW_CLK 32 /* us Slow clock period */
++#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */
++
++/* Reference Board Types */
++
++#define BU4710_BOARD 0x0400
++#define VSIM4710_BOARD 0x0401
++#define QT4710_BOARD 0x0402
++
++#define BU4610_BOARD 0x0403
++#define VSIM4610_BOARD 0x0404
++
++#define BU4307_BOARD 0x0405
++#define BCM94301CB_BOARD 0x0406
++#define BCM94301PC_BOARD 0x0406 /* Pcmcia 5v card */
++#define BCM94301MP_BOARD 0x0407
++#define BCM94307MP_BOARD 0x0408
++#define BCMAP4307_BOARD 0x0409
++
++#define BU4309_BOARD 0x040a
++#define BCM94309CB_BOARD 0x040b
++#define BCM94309MP_BOARD 0x040c
++#define BCM4309AP_BOARD 0x040d
++
++#define BCM94302MP_BOARD 0x040e
++
++#define VSIM4310_BOARD 0x040f
++#define BU4711_BOARD 0x0410
++#define BCM94310U_BOARD 0x0411
++#define BCM94310AP_BOARD 0x0412
++#define BCM94310MP_BOARD 0x0414
++
++#define BU4306_BOARD 0x0416
++#define BCM94306CB_BOARD 0x0417
++#define BCM94306MP_BOARD 0x0418
++
++#define BCM94710D_BOARD 0x041a
++#define BCM94710R1_BOARD 0x041b
++#define BCM94710R4_BOARD 0x041c
++#define BCM94710AP_BOARD 0x041d
++
++
++#define BU2050_BOARD 0x041f
++
++
++#define BCM94309G_BOARD 0x0421
++
++#define BCM94301PC3_BOARD 0x0422 /* Pcmcia 3.3v card */
++
++#define BU4704_BOARD 0x0423
++#define BU4702_BOARD 0x0424
++
++#define BCM94306PC_BOARD 0x0425 /* pcmcia 3.3v 4306 card */
++
++#define BU4317_BOARD 0x0426
++
++
++#define BCM94702MN_BOARD 0x0428
++
++/* BCM4702 1U CompactPCI Board */
++#define BCM94702CPCI_BOARD 0x0429
++
++/* BCM4702 with BCM95380 VLAN Router */
++#define BCM95380RR_BOARD 0x042a
++
++/* cb4306 with SiGe PA */
++#define BCM94306CBSG_BOARD 0x042b
++
++/* mp4301 with 2050 radio */
++#define BCM94301MPL_BOARD 0x042c
++
++/* cb4306 with SiGe PA */
++#define PCSG94306_BOARD 0x042d
++
++/* bu4704 with sdram */
++#define BU4704SD_BOARD 0x042e
++
++/* Dual 11a/11g Router */
++#define BCM94704AGR_BOARD 0x042f
++
++/* 11a-only minipci */
++#define BCM94308MP_BOARD 0x0430
++
++
++
++/* BCM94317 boards */
++#define BCM94317CB_BOARD 0x0440
++#define BCM94317MP_BOARD 0x0441
++#define BCM94317PCMCIA_BOARD 0x0442
++#define BCM94317SDIO_BOARD 0x0443
++
++#define BU4712_BOARD 0x0444
++#define BU4712SD_BOARD 0x045d
++#define BU4712L_BOARD 0x045f
++
++/* BCM4712 boards */
++#define BCM94712AP_BOARD 0x0445
++#define BCM94712P_BOARD 0x0446
++
++/* BCM4318 boards */
++#define BU4318_BOARD 0x0447
++#define CB4318_BOARD 0x0448
++#define MPG4318_BOARD 0x0449
++#define MP4318_BOARD 0x044a
++#define SD4318_BOARD 0x044b
++
++/* BCM63XX boards */
++#define BCM96338_BOARD 0x6338
++#define BCM96345_BOARD 0x6345
++#define BCM96348_BOARD 0x6348
++
++/* Another mp4306 with SiGe */
++#define BCM94306P_BOARD 0x044c
++
++/* CF-like 4317 modules */
++#define BCM94317CF_BOARD 0x044d
++
++/* mp4303 */
++#define BCM94303MP_BOARD 0x044e
++
++/* mpsgh4306 */
++#define BCM94306MPSGH_BOARD 0x044f
++
++/* BRCM 4306 w/ Front End Modules */
++#define BCM94306MPM 0x0450
++#define BCM94306MPL 0x0453
++
++/* 4712agr */
++#define BCM94712AGR_BOARD 0x0451
++
++/* The real CF 4317 board */
++#define CFI4317_BOARD 0x0452
++
++/* pcmcia 4303 */
++#define PC4303_BOARD 0x0454
++
++/* 5350K */
++#define BCM95350K_BOARD 0x0455
++
++/* 5350R */
++#define BCM95350R_BOARD 0x0456
++
++/* 4306mplna */
++#define BCM94306MPLNA_BOARD 0x0457
++
++/* 4320 boards */
++#define BU4320_BOARD 0x0458
++#define BU4320S_BOARD 0x0459
++#define BCM94320PH_BOARD 0x045a
++
++/* 4306mph */
++#define BCM94306MPH_BOARD 0x045b
++
++/* 4306pciv */
++#define BCM94306PCIV_BOARD 0x045c
++
++#define BU4712SD_BOARD 0x045d
++
++#define BCM94320PFLSH_BOARD 0x045e
++
++#define BU4712L_BOARD 0x045f
++#define BCM94712LGR_BOARD 0x0460
++#define BCM94320R_BOARD 0x0461
++
++#define BU5352_BOARD 0x0462
++
++#define BCM94318MPGH_BOARD 0x0463
++
++
++#define BCM95352GR_BOARD 0x0467
++
++/* bcm95351agr */
++#define BCM95351AGR_BOARD 0x0470
++
++/* # of GPIO pins */
++#define GPIO_NUMPINS 16
++
++#endif /* _BCMDEVS_H */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/bcmendian.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/bcmendian.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/bcmendian.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/bcmendian.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,152 @@
++/*
++ * local version of endian.h - byte order defines
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++*/
++
++#ifndef _BCMENDIAN_H_
++#define _BCMENDIAN_H_
++
++#include <typedefs.h>
++
++/* Byte swap a 16 bit value */
++#define BCMSWAP16(val) \
++ ((uint16)( \
++ (((uint16)(val) & (uint16)0x00ffU) << 8) | \
++ (((uint16)(val) & (uint16)0xff00U) >> 8) ))
++
++/* Byte swap a 32 bit value */
++#define BCMSWAP32(val) \
++ ((uint32)( \
++ (((uint32)(val) & (uint32)0x000000ffUL) << 24) | \
++ (((uint32)(val) & (uint32)0x0000ff00UL) << 8) | \
++ (((uint32)(val) & (uint32)0x00ff0000UL) >> 8) | \
++ (((uint32)(val) & (uint32)0xff000000UL) >> 24) ))
++
++/* 2 Byte swap a 32 bit value */
++#define BCMSWAP32BY16(val) \
++ ((uint32)( \
++ (((uint32)(val) & (uint32)0x0000ffffUL) << 16) | \
++ (((uint32)(val) & (uint32)0xffff0000UL) >> 16) ))
++
++
++static INLINE uint16
++bcmswap16(uint16 val)
++{
++ return BCMSWAP16(val);
++}
++
++static INLINE uint32
++bcmswap32(uint32 val)
++{
++ return BCMSWAP32(val);
++}
++
++static INLINE uint32
++bcmswap32by16(uint32 val)
++{
++ return BCMSWAP32BY16(val);
++}
++
++/* buf - start of buffer of shorts to swap */
++/* len - byte length of buffer */
++static INLINE void
++bcmswap16_buf(uint16 *buf, uint len)
++{
++ len = len/2;
++
++ while(len--){
++ *buf = bcmswap16(*buf);
++ buf++;
++ }
++}
++
++#ifndef hton16
++#ifndef IL_BIGENDIAN
++#define HTON16(i) BCMSWAP16(i)
++#define hton16(i) bcmswap16(i)
++#define hton32(i) bcmswap32(i)
++#define ntoh16(i) bcmswap16(i)
++#define ntoh32(i) bcmswap32(i)
++#define ltoh16(i) (i)
++#define ltoh32(i) (i)
++#define htol16(i) (i)
++#define htol32(i) (i)
++#else
++#define HTON16(i) (i)
++#define hton16(i) (i)
++#define hton32(i) (i)
++#define ntoh16(i) (i)
++#define ntoh32(i) (i)
++#define ltoh16(i) bcmswap16(i)
++#define ltoh32(i) bcmswap32(i)
++#define htol16(i) bcmswap16(i)
++#define htol32(i) bcmswap32(i)
++#endif
++#endif
++
++#ifndef IL_BIGENDIAN
++#define ltoh16_buf(buf, i)
++#define htol16_buf(buf, i)
++#else
++#define ltoh16_buf(buf, i) bcmswap16_buf((uint16*)buf, i)
++#define htol16_buf(buf, i) bcmswap16_buf((uint16*)buf, i)
++#endif
++
++/*
++* load 16-bit value from unaligned little endian byte array.
++*/
++static INLINE uint16
++ltoh16_ua(uint8 *bytes)
++{
++ return (bytes[1]<<8)+bytes[0];
++}
++
++/*
++* load 32-bit value from unaligned little endian byte array.
++*/
++static INLINE uint32
++ltoh32_ua(uint8 *bytes)
++{
++ return (bytes[3]<<24)+(bytes[2]<<16)+(bytes[1]<<8)+bytes[0];
++}
++
++/*
++* load 16-bit value from unaligned big(network) endian byte array.
++*/
++static INLINE uint16
++ntoh16_ua(uint8 *bytes)
++{
++ return (bytes[0]<<8)+bytes[1];
++}
++
++/*
++* load 32-bit value from unaligned big(network) endian byte array.
++*/
++static INLINE uint32
++ntoh32_ua(uint8 *bytes)
++{
++ return (bytes[0]<<24)+(bytes[1]<<16)+(bytes[2]<<8)+bytes[3];
++}
++
++#define ltoh_ua(ptr) ( \
++ sizeof(*(ptr)) == sizeof(uint8) ? *(uint8 *)ptr : \
++ sizeof(*(ptr)) == sizeof(uint16) ? (((uint8 *)ptr)[1]<<8)+((uint8 *)ptr)[0] : \
++ (((uint8 *)ptr)[3]<<24)+(((uint8 *)ptr)[2]<<16)+(((uint8 *)ptr)[1]<<8)+((uint8 *)ptr)[0] \
++)
++
++#define ntoh_ua(ptr) ( \
++ sizeof(*(ptr)) == sizeof(uint8) ? *(uint8 *)ptr : \
++ sizeof(*(ptr)) == sizeof(uint16) ? (((uint8 *)ptr)[0]<<8)+((uint8 *)ptr)[1] : \
++ (((uint8 *)ptr)[0]<<24)+(((uint8 *)ptr)[1]<<16)+(((uint8 *)ptr)[2]<<8)+((uint8 *)ptr)[3] \
++)
++
++#endif /* _BCMENDIAN_H_ */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/bcmnvram.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/bcmnvram.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/bcmnvram.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/bcmnvram.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,95 @@
++/*
++ * NVRAM variable manipulation
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#ifndef _bcmnvram_h_
++#define _bcmnvram_h_
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++#include <typedefs.h>
++
++struct nvram_header {
++ uint32 magic;
++ uint32 len;
++ uint32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
++ uint32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */
++ uint32 config_ncdl; /* ncdl values for memc */
++};
++
++struct nvram_tuple {
++ char *name;
++ char *value;
++ struct nvram_tuple *next;
++};
++
++/*
++ * Get the value of an NVRAM variable. The pointer returned may be
++ * invalid after a set.
++ * @param name name of variable to get
++ * @return value of variable or NULL if undefined
++ */
++extern char * __init early_nvram_get(const char *name);
++
++/*
++ * Get the value of an NVRAM variable. The pointer returned may be
++ * invalid after a set.
++ * @param name name of variable to get
++ * @return value of variable or NULL if undefined
++ */
++extern char *nvram_get(const char *name);
++
++/*
++ * Get the value of an NVRAM variable.
++ * @param name name of variable to get
++ * @return value of variable or NUL if undefined
++ */
++#define nvram_safe_get(name) (BCMINIT(early_nvram_get)(name) ? : "")
++
++/*
++ * Match an NVRAM variable.
++ * @param name name of variable to match
++ * @param match value to compare against value of variable
++ * @return TRUE if variable is defined and its value is string equal
++ * to match or FALSE otherwise
++ */
++static inline int
++nvram_match(char *name, char *match) {
++ const char *value = BCMINIT(early_nvram_get)(name);
++ return (value && !strcmp(value, match));
++}
++
++/*
++ * Inversely match an NVRAM variable.
++ * @param name name of variable to match
++ * @param match value to compare against value of variable
++ * @return TRUE if variable is defined and its value is not string
++ * equal to invmatch or FALSE otherwise
++ */
++static inline int
++nvram_invmatch(char *name, char *invmatch) {
++ const char *value = BCMINIT(early_nvram_get)(name);
++ return (value && strcmp(value, invmatch));
++}
++
++#endif /* _LANGUAGE_ASSEMBLY */
++
++#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */
++#define NVRAM_VERSION 1
++#define NVRAM_HEADER_SIZE 20
++#define NVRAM_SPACE 0x8000
++
++#define NVRAM_MAX_VALUE_LEN 255
++#define NVRAM_MAX_PARAM_LEN 64
++
++#endif /* _bcmnvram_h_ */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/bcmsrom.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/bcmsrom.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/bcmsrom.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/bcmsrom.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,23 @@
++/*
++ * Misc useful routines to access NIC local SROM/OTP .
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#ifndef _bcmsrom_h_
++#define _bcmsrom_h_
++
++extern int srom_var_init(void *sbh, uint bus, void *curmap, osl_t *osh, char **vars, int *count);
++
++extern int srom_read(uint bus, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf);
++extern int srom_write(uint bus, void *curmap, osl_t *osh, uint byteoff, uint nbytes, uint16 *buf);
++
++#endif /* _bcmsrom_h_ */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/bcmutils.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/bcmutils.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/bcmutils.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/bcmutils.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,308 @@
++/*
++ * Misc useful os-independent macros and functions.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id$
++ */
++
++#ifndef _bcmutils_h_
++#define _bcmutils_h_
++
++/*** driver-only section ***/
++#include <osl.h>
++
++#define _BCM_U 0x01 /* upper */
++#define _BCM_L 0x02 /* lower */
++#define _BCM_D 0x04 /* digit */
++#define _BCM_C 0x08 /* cntrl */
++#define _BCM_P 0x10 /* punct */
++#define _BCM_S 0x20 /* white space (space/lf/tab) */
++#define _BCM_X 0x40 /* hex digit */
++#define _BCM_SP 0x80 /* hard space (0x20) */
++
++#define GPIO_PIN_NOTDEFINED 0x20
++
++extern unsigned char bcm_ctype[];
++#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)])
++
++#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0)
++#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0)
++#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0)
++#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0)
++#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0)
++#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0)
++#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0)
++#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0)
++#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0)
++#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0)
++#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0)
++
++/*
++ * Spin at most 'us' microseconds while 'exp' is true.
++ * Caller should explicitly test 'exp' when this completes
++ * and take appropriate error action if 'exp' is still true.
++ */
++#define SPINWAIT(exp, us) { \
++ uint countdown = (us) + 9; \
++ while ((exp) && (countdown >= 10)) {\
++ OSL_DELAY(10); \
++ countdown -= 10; \
++ } \
++}
++
++/* generic osl packet queue */
++struct pktq {
++ void *head; /* first packet to dequeue */
++ void *tail; /* last packet to dequeue */
++ uint len; /* number of queued packets */
++ uint maxlen; /* maximum number of queued packets */
++ bool priority; /* enqueue by packet priority */
++ uint8 prio_map[MAXPRIO+1]; /* user priority to packet enqueue policy map */
++};
++#define DEFAULT_QLEN 128
++
++#define pktq_len(q) ((q)->len)
++#define pktq_avail(q) ((q)->maxlen - (q)->len)
++#define pktq_head(q) ((q)->head)
++#define pktq_full(q) ((q)->len >= (q)->maxlen)
++#define _pktq_pri(q, pri) ((q)->prio_map[pri])
++#define pktq_tailpri(q) ((q)->tail ? _pktq_pri(q, PKTPRIO((q)->tail)) : _pktq_pri(q, 0))
++
++/* externs */
++/* packet */
++extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf);
++extern uint pkttotlen(osl_t *osh, void *);
++extern void pktq_init(struct pktq *q, uint maxlen, const uint8 prio_map[]);
++extern void pktenq(struct pktq *q, void *p, bool lifo);
++extern void *pktdeq(struct pktq *q);
++extern void *pktdeqtail(struct pktq *q);
++/* string */
++extern uint bcm_atoi(char *s);
++extern uchar bcm_toupper(uchar c);
++extern ulong bcm_strtoul(char *cp, char **endp, uint base);
++extern char *bcmstrstr(char *haystack, char *needle);
++extern char *bcmstrcat(char *dest, const char *src);
++extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen);
++/* ethernet address */
++extern char *bcm_ether_ntoa(char *ea, char *buf);
++extern int bcm_ether_atoe(char *p, char *ea);
++/* delay */
++extern void bcm_mdelay(uint ms);
++/* variable access */
++extern char *getvar(char *vars, char *name);
++extern int getintvar(char *vars, char *name);
++extern uint getgpiopin(char *vars, char *pin_name, uint def_pin);
++#define bcmlog(fmt, a1, a2)
++#define bcmdumplog(buf, size) *buf = '\0'
++#define bcmdumplogent(buf, idx) -1
++
++/*** driver/apps-shared section ***/
++
++#define BCME_STRLEN 64
++#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST))
++
++
++/*
++ * error codes could be added but the defined ones shouldn't be changed/deleted
++ * these error codes are exposed to the user code
++ * when ever a new error code is added to this list
++ * please update errorstring table with the related error string and
++ * update osl files with os specific errorcode map
++*/
++
++#define BCME_ERROR -1 /* Error generic */
++#define BCME_BADARG -2 /* Bad Argument */
++#define BCME_BADOPTION -3 /* Bad option */
++#define BCME_NOTUP -4 /* Not up */
++#define BCME_NOTDOWN -5 /* Not down */
++#define BCME_NOTAP -6 /* Not AP */
++#define BCME_NOTSTA -7 /* Not STA */
++#define BCME_BADKEYIDX -8 /* BAD Key Index */
++#define BCME_RADIOOFF -9 /* Radio Off */
++#define BCME_NOTBANDLOCKED -10 /* Not bandlocked */
++#define BCME_NOCLK -11 /* No Clock*/
++#define BCME_BADRATESET -12 /* BAD RateSet*/
++#define BCME_BADBAND -13 /* BAD Band */
++#define BCME_BUFTOOSHORT -14 /* Buffer too short */
++#define BCME_BUFTOOLONG -15 /* Buffer too Long */
++#define BCME_BUSY -16 /* Busy*/
++#define BCME_NOTASSOCIATED -17 /* Not associated*/
++#define BCME_BADSSIDLEN -18 /* BAD SSID Len */
++#define BCME_OUTOFRANGECHAN -19 /* Out of Range Channel*/
++#define BCME_BADCHAN -20 /* BAD Channel */
++#define BCME_BADADDR -21 /* BAD Address*/
++#define BCME_NORESOURCE -22 /* No resources*/
++#define BCME_UNSUPPORTED -23 /* Unsupported*/
++#define BCME_BADLEN -24 /* Bad Length*/
++#define BCME_NOTREADY -25 /* Not ready Yet*/
++#define BCME_EPERM -26 /* Not Permitted */
++#define BCME_NOMEM -27 /* No Memory */
++#define BCME_ASSOCIATED -28 /* Associated */
++#define BCME_RANGE -29 /* Range Error*/
++#define BCME_NOTFOUND -30 /* Not found */
++#define BCME_LAST BCME_NOTFOUND
++
++#ifndef ABS
++#define ABS(a) (((a)<0)?-(a):(a))
++#endif
++
++#ifndef MIN
++#define MIN(a, b) (((a)<(b))?(a):(b))
++#endif
++
++#ifndef MAX
++#define MAX(a, b) (((a)>(b))?(a):(b))
++#endif
++
++#define CEIL(x, y) (((x) + ((y)-1)) / (y))
++#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
++#define ISALIGNED(a, x) (((a) & ((x)-1)) == 0)
++#define ISPOWEROF2(x) ((((x)-1)&(x))==0)
++#define VALID_MASK(mask) !((mask) & ((mask) + 1))
++#define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member)
++#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
++
++/* bit map related macros */
++#ifndef setbit
++#define NBBY 8 /* 8 bits per byte */
++#define setbit(a,i) (((uint8 *)a)[(i)/NBBY] |= 1<<((i)%NBBY))
++#define clrbit(a,i) (((uint8 *)a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
++#define isset(a,i) (((uint8 *)a)[(i)/NBBY] & (1<<((i)%NBBY)))
++#define isclr(a,i) ((((uint8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
++#endif
++
++#define NBITS(type) (sizeof(type) * 8)
++#define NBITVAL(bits) (1 << (bits))
++#define MAXBITVAL(bits) ((1 << (bits)) - 1)
++
++/* crc defines */
++#define CRC8_INIT_VALUE 0xff /* Initial CRC8 checksum value */
++#define CRC8_GOOD_VALUE 0x9f /* Good final CRC8 checksum value */
++#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */
++#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */
++#define CRC32_INIT_VALUE 0xffffffff /* Initial CRC32 checksum value */
++#define CRC32_GOOD_VALUE 0xdebb20e3 /* Good final CRC32 checksum value */
++
++/* bcm_format_flags() bit description structure */
++typedef struct bcm_bit_desc {
++ uint32 bit;
++ char* name;
++} bcm_bit_desc_t;
++
++/* tag_ID/length/value_buffer tuple */
++typedef struct bcm_tlv {
++ uint8 id;
++ uint8 len;
++ uint8 data[1];
++} bcm_tlv_t;
++
++/* Check that bcm_tlv_t fits into the given buflen */
++#define bcm_valid_tlv(elt, buflen) ((buflen) >= 2 && (int)(buflen) >= (int)(2 + (elt)->len))
++
++/* buffer length for ethernet address from bcm_ether_ntoa() */
++#define ETHER_ADDR_STR_LEN 18
++
++/* unaligned load and store macros */
++#ifdef IL_BIGENDIAN
++static INLINE uint32
++load32_ua(uint8 *a)
++{
++ return ((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]);
++}
++
++static INLINE void
++store32_ua(uint8 *a, uint32 v)
++{
++ a[0] = (v >> 24) & 0xff;
++ a[1] = (v >> 16) & 0xff;
++ a[2] = (v >> 8) & 0xff;
++ a[3] = v & 0xff;
++}
++
++static INLINE uint16
++load16_ua(uint8 *a)
++{
++ return ((a[0] << 8) | a[1]);
++}
++
++static INLINE void
++store16_ua(uint8 *a, uint16 v)
++{
++ a[0] = (v >> 8) & 0xff;
++ a[1] = v & 0xff;
++}
++
++#else
++
++static INLINE uint32
++load32_ua(uint8 *a)
++{
++ return ((a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]);
++}
++
++static INLINE void
++store32_ua(uint8 *a, uint32 v)
++{
++ a[3] = (v >> 24) & 0xff;
++ a[2] = (v >> 16) & 0xff;
++ a[1] = (v >> 8) & 0xff;
++ a[0] = v & 0xff;
++}
++
++static INLINE uint16
++load16_ua(uint8 *a)
++{
++ return ((a[1] << 8) | a[0]);
++}
++
++static INLINE void
++store16_ua(uint8 *a, uint16 v)
++{
++ a[1] = (v >> 8) & 0xff;
++ a[0] = v & 0xff;
++}
++
++#endif
++
++/* externs */
++/* crc */
++extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc);
++/* format/print */
++/* IE parsing */
++extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen);
++extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key);
++extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key);
++
++/* bcmerror*/
++extern const char *bcmerrorstr(int bcmerror);
++
++/* multi-bool data type: set of bools, mbool is true if any is set */
++typedef uint32 mbool;
++#define mboolset(mb, bit) (mb |= bit) /* set one bool */
++#define mboolclr(mb, bit) (mb &= ~bit) /* clear one bool */
++#define mboolisset(mb, bit) ((mb & bit) != 0) /* TRUE if one bool is set */
++#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val)))
++
++/* power conversion */
++extern uint16 bcm_qdbm_to_mw(uint8 qdbm);
++extern uint8 bcm_mw_to_qdbm(uint16 mw);
++
++/* generic datastruct to help dump routines */
++struct fielddesc {
++ char *nameandfmt;
++ uint32 offset;
++ uint32 len;
++};
++
++typedef uint32 (*readreg_rtn)(void *arg0, void *arg1, uint32 offset);
++extern uint bcmdumpfields(readreg_rtn func_ptr, void *arg0, void *arg1, struct fielddesc *str, char *buf, uint32 bufsize);
++
++extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len);
++
++#endif /* _bcmutils_h_ */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/bitfuncs.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/bitfuncs.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/bitfuncs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/bitfuncs.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,85 @@
++/*
++ * bit manipulation utility functions
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id$
++ */
++
++#ifndef _BITFUNCS_H
++#define _BITFUNCS_H
++
++#include <typedefs.h>
++
++/* local prototypes */
++static INLINE uint32 find_msbit(uint32 x);
++
++
++/*
++ * find_msbit: returns index of most significant set bit in x, with index
++ * range defined as 0-31. NOTE: returns zero if input is zero.
++ */
++
++#if defined(USE_PENTIUM_BSR) && defined(__GNUC__)
++
++/*
++ * Implementation for Pentium processors and gcc. Note that this
++ * instruction is actually very slow on some processors (e.g., family 5,
++ * model 2, stepping 12, "Pentium 75 - 200"), so we use the generic
++ * implementation instead.
++ */
++static INLINE uint32 find_msbit(uint32 x)
++{
++ uint msbit;
++ __asm__("bsrl %1,%0"
++ :"=r" (msbit)
++ :"r" (x));
++ return msbit;
++}
++
++#else
++
++/*
++ * Generic Implementation
++ */
++
++#define DB_POW_MASK16 0xffff0000
++#define DB_POW_MASK8 0x0000ff00
++#define DB_POW_MASK4 0x000000f0
++#define DB_POW_MASK2 0x0000000c
++#define DB_POW_MASK1 0x00000002
++
++static INLINE uint32 find_msbit(uint32 x)
++{
++ uint32 temp_x = x;
++ uint msbit = 0;
++ if (temp_x & DB_POW_MASK16) {
++ temp_x >>= 16;
++ msbit = 16;
++ }
++ if (temp_x & DB_POW_MASK8) {
++ temp_x >>= 8;
++ msbit += 8;
++ }
++ if (temp_x & DB_POW_MASK4) {
++ temp_x >>= 4;
++ msbit += 4;
++ }
++ if (temp_x & DB_POW_MASK2) {
++ temp_x >>= 2;
++ msbit += 2;
++ }
++ if (temp_x & DB_POW_MASK1) {
++ msbit += 1;
++ }
++ return(msbit);
++}
++
++#endif
++
++#endif /* _BITFUNCS_H */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/flash.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/flash.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/flash.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/flash.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,188 @@
++/*
++ * flash.h: Common definitions for flash access.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++/* Types of flashes we know about */
++typedef enum _flash_type {OLD, BSC, SCS, AMD, SST, SFLASH} flash_type_t;
++
++/* Commands to write/erase the flases */
++typedef struct _flash_cmds{
++ flash_type_t type;
++ bool need_unlock;
++ uint16 pre_erase;
++ uint16 erase_block;
++ uint16 erase_chip;
++ uint16 write_word;
++ uint16 write_buf;
++ uint16 clear_csr;
++ uint16 read_csr;
++ uint16 read_id;
++ uint16 confirm;
++ uint16 read_array;
++} flash_cmds_t;
++
++#define UNLOCK_CMD_WORDS 2
++
++typedef struct _unlock_cmd {
++ uint addr[UNLOCK_CMD_WORDS];
++ uint16 cmd[UNLOCK_CMD_WORDS];
++} unlock_cmd_t;
++
++/* Flash descriptors */
++typedef struct _flash_desc {
++ uint16 mfgid; /* Manufacturer Id */
++ uint16 devid; /* Device Id */
++ uint size; /* Total size in bytes */
++ uint width; /* Device width in bytes */
++ flash_type_t type; /* Device type old, S, J */
++ uint bsize; /* Block size */
++ uint nb; /* Number of blocks */
++ uint ff; /* First full block */
++ uint lf; /* Last full block */
++ uint nsub; /* Number of subblocks */
++ uint *subblocks; /* Offsets for subblocks */
++ char *desc; /* Description */
++} flash_desc_t;
++
++
++#ifdef DECLARE_FLASHES
++flash_cmds_t sflash_cmd_t =
++ { SFLASH, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
++
++flash_cmds_t flash_cmds[] = {
++/* type needu preera eraseb erasech write wbuf clcsr rdcsr rdid confrm read */
++ { BSC, 0, 0x00, 0x20, 0x00, 0x40, 0x00, 0x50, 0x70, 0x90, 0xd0, 0xff },
++ { SCS, 0, 0x00, 0x20, 0x00, 0x40, 0xe8, 0x50, 0x70, 0x90, 0xd0, 0xff },
++ { AMD, 1, 0x80, 0x30, 0x10, 0xa0, 0x00, 0x00, 0x00, 0x90, 0x00, 0xf0 },
++ { SST, 1, 0x80, 0x50, 0x10, 0xa0, 0x00, 0x00, 0x00, 0x90, 0x00, 0xf0 },
++ { 0 }
++};
++
++unlock_cmd_t unlock_cmd_amd = {
++#ifdef MIPSEB
++/* addr: */ { 0x0aa8, 0x0556},
++#else
++/* addr: */ { 0x0aaa, 0x0554},
++#endif
++/* data: */ { 0xaa, 0x55}
++};
++
++unlock_cmd_t unlock_cmd_sst = {
++#ifdef MIPSEB
++/* addr: */ { 0xaaa8, 0x5556},
++#else
++/* addr: */ { 0xaaaa, 0x5554},
++#endif
++/* data: */ { 0xaa, 0x55}
++};
++
++#define AMD_CMD 0xaaa
++#define SST_CMD 0xaaaa
++
++/* intel unlock block cmds */
++#define INTEL_UNLOCK1 0x60
++#define INTEL_UNLOCK2 0xD0
++
++/* Just eight blocks of 8KB byte each */
++
++uint blk8x8k[] = { 0x00000000,
++ 0x00002000,
++ 0x00004000,
++ 0x00006000,
++ 0x00008000,
++ 0x0000a000,
++ 0x0000c000,
++ 0x0000e000,
++ 0x00010000
++};
++
++/* Funky AMD arrangement for 29xx800's */
++uint amd800[] = { 0x00000000, /* 16KB */
++ 0x00004000, /* 32KB */
++ 0x0000c000, /* 8KB */
++ 0x0000e000, /* 8KB */
++ 0x00010000, /* 8KB */
++ 0x00012000, /* 8KB */
++ 0x00014000, /* 32KB */
++ 0x0001c000, /* 16KB */
++ 0x00020000
++};
++
++/* AMD arrangement for 29xx160's */
++uint amd4112[] = { 0x00000000, /* 32KB */
++ 0x00008000, /* 8KB */
++ 0x0000a000, /* 8KB */
++ 0x0000c000, /* 16KB */
++ 0x00010000
++};
++uint amd2114[] = { 0x00000000, /* 16KB */
++ 0x00004000, /* 8KB */
++ 0x00006000, /* 8KB */
++ 0x00008000, /* 32KB */
++ 0x00010000
++};
++
++
++flash_desc_t sflash_desc =
++ { 0, 0, 0, 0, SFLASH, 0, 0, 0, 0, 0, NULL, "SFLASH" };
++
++flash_desc_t flashes[] = {
++ { 0x00b0, 0x00d0, 0x0200000, 2, SCS, 0x10000, 32, 0, 31, 0, NULL, "Intel 28F160S3/5 1Mx16" },
++ { 0x00b0, 0x00d4, 0x0400000, 2, SCS, 0x10000, 64, 0, 63, 0, NULL, "Intel 28F320S3/5 2Mx16" },
++ { 0x0089, 0x8890, 0x0200000, 2, BSC, 0x10000, 32, 0, 30, 8, blk8x8k, "Intel 28F160B3 1Mx16 TopB" },
++ { 0x0089, 0x8891, 0x0200000, 2, BSC, 0x10000, 32, 1, 31, 8, blk8x8k, "Intel 28F160B3 1Mx16 BotB" },
++ { 0x0089, 0x8896, 0x0400000, 2, BSC, 0x10000, 64, 0, 62, 8, blk8x8k, "Intel 28F320B3 2Mx16 TopB" },
++ { 0x0089, 0x8897, 0x0400000, 2, BSC, 0x10000, 64, 1, 63, 8, blk8x8k, "Intel 28F320B3 2Mx16 BotB" },
++ { 0x0089, 0x8898, 0x0800000, 2, BSC, 0x10000, 128, 0, 126, 8, blk8x8k, "Intel 28F640B3 4Mx16 TopB" },
++ { 0x0089, 0x8899, 0x0800000, 2, BSC, 0x10000, 128, 1, 127, 8, blk8x8k, "Intel 28F640B3 4Mx16 BotB" },
++ { 0x0089, 0x88C2, 0x0200000, 2, BSC, 0x10000, 32, 0, 30, 8, blk8x8k, "Intel 28F160C3 1Mx16 TopB" },
++ { 0x0089, 0x88C3, 0x0200000, 2, BSC, 0x10000, 32, 1, 31, 8, blk8x8k, "Intel 28F160C3 1Mx16 BotB" },
++ { 0x0089, 0x88C4, 0x0400000, 2, BSC, 0x10000, 64, 0, 62, 8, blk8x8k, "Intel 28F320C3 2Mx16 TopB" },
++ { 0x0089, 0x88C5, 0x0400000, 2, BSC, 0x10000, 64, 1, 63, 8, blk8x8k, "Intel 28F320C3 2Mx16 BotB" },
++ { 0x0089, 0x88CC, 0x0800000, 2, BSC, 0x10000, 128, 0, 126, 8, blk8x8k, "Intel 28F640C3 4Mx16 TopB" },
++ { 0x0089, 0x88CD, 0x0800000, 2, BSC, 0x10000, 128, 1, 127, 8, blk8x8k, "Intel 28F640C3 4Mx16 BotB" },
++ { 0x0089, 0x0014, 0x0400000, 2, SCS, 0x20000, 32, 0, 31, 0, NULL, "Intel 28F320J5 2Mx16" },
++ { 0x0089, 0x0015, 0x0800000, 2, SCS, 0x20000, 64, 0, 63, 0, NULL, "Intel 28F640J5 4Mx16" },
++ { 0x0089, 0x0016, 0x0400000, 2, SCS, 0x20000, 32, 0, 31, 0, NULL, "Intel 28F320J3 2Mx16" },
++ { 0x0089, 0x0017, 0x0800000, 2, SCS, 0x20000, 64, 0, 63, 0, NULL, "Intel 28F640J3 4Mx16" },
++ { 0x0089, 0x0018, 0x1000000, 2, SCS, 0x20000, 128, 0, 127, 0, NULL, "Intel 28F128J3 8Mx16" },
++ { 0x00b0, 0x00e3, 0x0400000, 2, BSC, 0x10000, 64, 1, 63, 8, blk8x8k, "Sharp 28F320BJE 2Mx16 BotB" },
++ { 0x0001, 0x224a, 0x0100000, 2, AMD, 0x10000, 16, 0, 13, 8, amd800, "AMD 29DL800BT 512Kx16 TopB" },
++ { 0x0001, 0x22cb, 0x0100000, 2, AMD, 0x10000, 16, 2, 15, 8, amd800, "AMD 29DL800BB 512Kx16 BotB" },
++ { 0x0001, 0x22c4, 0x0200000, 2, AMD, 0x10000, 32, 0, 30, 4, amd2114, "AMD 29lv160DT 1Mx16 TopB" },
++ { 0x0001, 0x2249, 0x0200000, 2, AMD, 0x10000, 32, 1, 31, 4, amd4112, "AMD 29lv160DB 1Mx16 BotB" },
++ { 0x0001, 0x22f6, 0x0400000, 2, AMD, 0x10000, 64, 0, 62, 8, blk8x8k, "AMD 29lv320DT 2Mx16 TopB" },
++ { 0x0001, 0x22f9, 0x0400000, 2, AMD, 0x10000, 64, 1, 63, 8, blk8x8k, "AMD 29lv320DB 2Mx16 BotB" },
++ { 0x0001, 0x227e, 0x0400000, 2, AMD, 0x10000, 64, 0, 62, 8, blk8x8k, "AMD 29lv320MT 2Mx16 TopB" },
++ { 0x0001, 0x2200, 0x0400000, 2, AMD, 0x10000, 64, 1, 63, 8, blk8x8k, "AMD 29lv320MB 2Mx16 BotB" },
++ { 0x0020, 0x22CA, 0x0400000, 2, AMD, 0x10000, 64, 0, 62, 4, amd4112, "ST 29w320DT 2Mx16 TopB" },
++ { 0x0020, 0x22CB, 0x0400000, 2, AMD, 0x10000, 64, 1, 63, 4, amd2114, "ST 29w320DB 2Mx16 BotB" },
++ { 0x00C2, 0x00A7, 0x0400000, 2, AMD, 0x10000, 64, 0, 62, 4, amd4112, "MX29LV320T 2Mx16 TopB" },
++ { 0x00C2, 0x00A8, 0x0400000, 2, AMD, 0x10000, 64, 1, 63, 4, amd2114, "MX29LV320B 2Mx16 BotB" },
++ { 0x0004, 0x22F6, 0x0400000, 2, AMD, 0x10000, 64, 0, 62, 4, amd4112, "MBM29LV320TE 2Mx16 TopB" },
++ { 0x0004, 0x22F9, 0x0400000, 2, AMD, 0x10000, 64, 1, 63, 4, amd2114, "MBM29LV320BE 2Mx16 BotB" },
++ { 0x0098, 0x009A, 0x0400000, 2, AMD, 0x10000, 64, 0, 62, 4, amd4112, "TC58FVT321 2Mx16 TopB" },
++ { 0x0098, 0x009C, 0x0400000, 2, AMD, 0x10000, 64, 1, 63, 4, amd2114, "TC58FVB321 2Mx16 BotB" },
++ { 0x00C2, 0x22A7, 0x0400000, 2, AMD, 0x10000, 64, 0, 62, 4, amd4112, "MX29LV320T 2Mx16 TopB" },
++ { 0x00C2, 0x22A8, 0x0400000, 2, AMD, 0x10000, 64, 1, 63, 4, amd2114, "MX29LV320B 2Mx16 BotB" },
++ { 0x00BF, 0x2783, 0x0400000, 2, SST, 0x10000, 64, 0, 63, 0, NULL, "SST39VF320 2Mx16" },
++ { 0, 0, 0, 0, OLD, 0, 0, 0, 0, 0, NULL, NULL },
++};
++
++#else
++
++extern flash_cmds_t flash_cmds[];
++extern unlock_cmd_t unlock_cmd;
++extern flash_desc_t flashes[];
++
++#endif
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/flashutl.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/flashutl.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/flashutl.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/flashutl.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,27 @@
++/*
++ * BCM47XX FLASH driver interface
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id$
++ */
++
++#ifndef _flashutl_h_
++#define _flashutl_h_
++
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++int sysFlashInit(char *flash_str);
++int sysFlashRead(uint off, uchar *dst, uint bytes);
++int sysFlashWrite(uint off, uchar *src, uint bytes);
++void nvWrite(unsigned short *data, unsigned int len);
++
++#endif /* _LANGUAGE_ASSEMBLY */
++
++#endif /* _flashutl_h_ */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/hndmips.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/hndmips.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/hndmips.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/hndmips.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,16 @@
++/*
++ * Alternate include file for HND sbmips.h since CFE also ships with
++ * a sbmips.h.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#include "sbmips.h"
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/linux_osl.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/linux_osl.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/linux_osl.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/linux_osl.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,331 @@
++/*
++ * Linux OS Independent Layer
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#ifndef _linux_osl_h_
++#define _linux_osl_h_
++
++#include <typedefs.h>
++
++/* use current 2.4.x calling conventions */
++#include <linuxver.h>
++
++/* assert and panic */
++#ifdef __GNUC__
++#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
++#if GCC_VERSION > 30100
++#define ASSERT(exp) do {} while (0)
++#else
++/* ASSERT could causes segmentation fault on GCC3.1, use empty instead*/
++#define ASSERT(exp)
++#endif
++#endif
++
++/* microsecond delay */
++#define OSL_DELAY(usec) osl_delay(usec)
++extern void osl_delay(uint usec);
++
++/* PCI configuration space access macros */
++#define OSL_PCI_READ_CONFIG(osh, offset, size) \
++ osl_pci_read_config((osh), (offset), (size))
++#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \
++ osl_pci_write_config((osh), (offset), (size), (val))
++extern uint32 osl_pci_read_config(osl_t *osh, uint size, uint offset);
++extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val);
++
++/* PCI device bus # and slot # */
++#define OSL_PCI_BUS(osh) osl_pci_bus(osh)
++#define OSL_PCI_SLOT(osh) osl_pci_slot(osh)
++extern uint osl_pci_bus(osl_t *osh);
++extern uint osl_pci_slot(osl_t *osh);
++
++/* OSL initialization */
++extern osl_t *osl_attach(void *pdev);
++extern void osl_detach(osl_t *osh);
++
++/* host/bus architecture-specific byte swap */
++#define BUS_SWAP32(v) (v)
++
++/* general purpose memory allocation */
++
++#define MALLOC(osh, size) kmalloc(size, GFP_ATOMIC)
++#define MFREE(osh, addr, size) kfree(addr);
++
++#define MALLOC_FAILED(osh) osl_malloc_failed((osh))
++
++extern void *osl_malloc(osl_t *osh, uint size);
++extern void osl_mfree(osl_t *osh, void *addr, uint size);
++extern uint osl_malloced(osl_t *osh);
++extern uint osl_malloc_failed(osl_t *osh);
++
++/* allocate/free shared (dma-able) consistent memory */
++#define DMA_CONSISTENT_ALIGN PAGE_SIZE
++#define DMA_ALLOC_CONSISTENT(osh, size, pap) \
++ osl_dma_alloc_consistent((osh), (size), (pap))
++#define DMA_FREE_CONSISTENT(osh, va, size, pa) \
++ osl_dma_free_consistent((osh), (void*)(va), (size), (pa))
++extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, ulong *pap);
++extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa);
++
++/* map/unmap direction */
++#define DMA_TX 1
++#define DMA_RX 2
++
++/* register access macros */
++#if defined(BCMJTAG)
++#include <bcmjtag.h>
++#define R_REG(r) bcmjtag_read(NULL, (uint32)(r), sizeof (*(r)))
++#define W_REG(r, v) bcmjtag_write(NULL, (uint32)(r), (uint32)(v), sizeof (*(r)))
++#endif
++
++/*
++ * BINOSL selects the slightly slower function-call-based binary compatible osl.
++ * Macros expand to calls to functions defined in linux_osl.c .
++ */
++#ifndef BINOSL
++
++/* string library, kernel mode */
++#define printf(fmt, args...) printk(fmt, ## args)
++#include <linux/kernel.h>
++#include <linux/string.h>
++
++/* register access macros */
++#if !defined(BCMJTAG)
++#ifndef IL_BIGENDIAN
++#define R_REG(r) ( \
++ sizeof(*(r)) == sizeof(uint8) ? readb((volatile uint8*)(r)) : \
++ sizeof(*(r)) == sizeof(uint16) ? readw((volatile uint16*)(r)) : \
++ readl((volatile uint32*)(r)) \
++)
++#define W_REG(r, v) do { \
++ switch (sizeof(*(r))) { \
++ case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \
++ case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \
++ case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \
++ } \
++} while (0)
++#else /* IL_BIGENDIAN */
++#define R_REG(r) ({ \
++ __typeof(*(r)) __osl_v; \
++ switch (sizeof(*(r))) { \
++ case sizeof(uint8): __osl_v = readb((volatile uint8*)((uint32)r^3)); break; \
++ case sizeof(uint16): __osl_v = readw((volatile uint16*)((uint32)r^2)); break; \
++ case sizeof(uint32): __osl_v = readl((volatile uint32*)(r)); break; \
++ } \
++ __osl_v; \
++})
++#define W_REG(r, v) do { \
++ switch (sizeof(*(r))) { \
++ case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)((uint32)r^3)); break; \
++ case sizeof(uint16): writew((uint16)(v), (volatile uint16*)((uint32)r^2)); break; \
++ case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \
++ } \
++} while (0)
++#endif
++#endif
++
++#define AND_REG(r, v) W_REG((r), R_REG(r) & (v))
++#define OR_REG(r, v) W_REG((r), R_REG(r) | (v))
++
++/* bcopy, bcmp, and bzero */
++#define bcopy(src, dst, len) memcpy((dst), (src), (len))
++#define bcmp(b1, b2, len) memcmp((b1), (b2), (len))
++#define bzero(b, len) memset((b), '\0', (len))
++
++/* uncached virtual address */
++#ifdef mips
++#define OSL_UNCACHED(va) KSEG1ADDR((va))
++#include <asm/addrspace.h>
++#else
++#define OSL_UNCACHED(va) (va)
++#endif
++
++/* get processor cycle count */
++#if defined(mips)
++#define OSL_GETCYCLES(x) ((x) = read_c0_count() * 2)
++#elif defined(__i386__)
++#define OSL_GETCYCLES(x) rdtscl((x))
++#else
++#define OSL_GETCYCLES(x) ((x) = 0)
++#endif
++
++/* dereference an address that may cause a bus exception */
++#ifdef mips
++#if defined(MODULE) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,17))
++#define BUSPROBE(val, addr) panic("get_dbe() will not fixup a bus exception when compiled into a module")
++#else
++#define BUSPROBE(val, addr) get_dbe((val), (addr))
++#include <asm/paccess.h>
++#endif
++#else
++#define BUSPROBE(val, addr) ({ (val) = R_REG((addr)); 0; })
++#endif
++
++/* map/unmap physical to virtual I/O */
++#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size))
++#define REG_UNMAP(va) iounmap((void *)(va))
++
++/* shared (dma-able) memory access macros */
++#define R_SM(r) *(r)
++#define W_SM(r, v) (*(r) = (v))
++#define BZERO_SM(r, len) memset((r), '\0', (len))
++
++/* packet primitives */
++#define PKTGET(osh, len, send) osl_pktget((osh), (len), (send))
++#define PKTFREE(osh, skb, send) osl_pktfree((skb))
++#define PKTDATA(osh, skb) (((struct sk_buff*)(skb))->data)
++#define PKTLEN(osh, skb) (((struct sk_buff*)(skb))->len)
++#define PKTHEADROOM(osh, skb) (PKTDATA(osh,skb)-(((struct sk_buff*)(skb))->head))
++#define PKTTAILROOM(osh, skb) ((((struct sk_buff*)(skb))->end)-(((struct sk_buff*)(skb))->tail))
++#define PKTNEXT(osh, skb) (((struct sk_buff*)(skb))->next)
++#define PKTSETNEXT(skb, x) (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x))
++#define PKTSETLEN(osh, skb, len) __skb_trim((struct sk_buff*)(skb), (len))
++#define PKTPUSH(osh, skb, bytes) skb_push((struct sk_buff*)(skb), (bytes))
++#define PKTPULL(osh, skb, bytes) skb_pull((struct sk_buff*)(skb), (bytes))
++#define PKTDUP(osh, skb) skb_clone((struct sk_buff*)(skb), GFP_ATOMIC)
++#define PKTCOOKIE(skb) ((void*)((struct sk_buff*)(skb))->csum)
++#define PKTSETCOOKIE(skb, x) (((struct sk_buff*)(skb))->csum = (uint)(x))
++#define PKTLINK(skb) (((struct sk_buff*)(skb))->prev)
++#define PKTSETLINK(skb, x) (((struct sk_buff*)(skb))->prev = (struct sk_buff*)(x))
++#define PKTPRIO(skb) (((struct sk_buff*)(skb))->priority)
++#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x))
++extern void *osl_pktget(osl_t *osh, uint len, bool send);
++extern void osl_pktfree(void *skb);
++
++#else /* BINOSL */
++
++/* string library */
++#ifndef LINUX_OSL
++#undef printf
++#define printf(fmt, args...) osl_printf((fmt), ## args)
++#undef sprintf
++#define sprintf(buf, fmt, args...) osl_sprintf((buf), (fmt), ## args)
++#undef strcmp
++#define strcmp(s1, s2) osl_strcmp((s1), (s2))
++#undef strncmp
++#define strncmp(s1, s2, n) osl_strncmp((s1), (s2), (n))
++#undef strlen
++#define strlen(s) osl_strlen((s))
++#undef strcpy
++#define strcpy(d, s) osl_strcpy((d), (s))
++#undef strncpy
++#define strncpy(d, s, n) osl_strncpy((d), (s), (n))
++#endif
++extern int osl_printf(const char *format, ...);
++extern int osl_sprintf(char *buf, const char *format, ...);
++extern int osl_strcmp(const char *s1, const char *s2);
++extern int osl_strncmp(const char *s1, const char *s2, uint n);
++extern int osl_strlen(const char *s);
++extern char* osl_strcpy(char *d, const char *s);
++extern char* osl_strncpy(char *d, const char *s, uint n);
++
++/* register access macros */
++#if !defined(BCMJTAG)
++#define R_REG(r) ( \
++ sizeof(*(r)) == sizeof(uint8) ? osl_readb((volatile uint8*)(r)) : \
++ sizeof(*(r)) == sizeof(uint16) ? osl_readw((volatile uint16*)(r)) : \
++ osl_readl((volatile uint32*)(r)) \
++)
++#define W_REG(r, v) do { \
++ switch (sizeof(*(r))) { \
++ case sizeof(uint8): osl_writeb((uint8)(v), (volatile uint8*)(r)); break; \
++ case sizeof(uint16): osl_writew((uint16)(v), (volatile uint16*)(r)); break; \
++ case sizeof(uint32): osl_writel((uint32)(v), (volatile uint32*)(r)); break; \
++ } \
++} while (0)
++#endif
++
++#define AND_REG(r, v) W_REG((r), R_REG(r) & (v))
++#define OR_REG(r, v) W_REG((r), R_REG(r) | (v))
++extern uint8 osl_readb(volatile uint8 *r);
++extern uint16 osl_readw(volatile uint16 *r);
++extern uint32 osl_readl(volatile uint32 *r);
++extern void osl_writeb(uint8 v, volatile uint8 *r);
++extern void osl_writew(uint16 v, volatile uint16 *r);
++extern void osl_writel(uint32 v, volatile uint32 *r);
++
++/* bcopy, bcmp, and bzero */
++extern void bcopy(const void *src, void *dst, int len);
++extern int bcmp(const void *b1, const void *b2, int len);
++extern void bzero(void *b, int len);
++
++/* uncached virtual address */
++#define OSL_UNCACHED(va) osl_uncached((va))
++extern void *osl_uncached(void *va);
++
++/* get processor cycle count */
++#define OSL_GETCYCLES(x) ((x) = osl_getcycles())
++extern uint osl_getcycles(void);
++
++/* dereference an address that may target abort */
++#define BUSPROBE(val, addr) osl_busprobe(&(val), (addr))
++extern int osl_busprobe(uint32 *val, uint32 addr);
++
++/* map/unmap physical to virtual */
++#define REG_MAP(pa, size) osl_reg_map((pa), (size))
++#define REG_UNMAP(va) osl_reg_unmap((va))
++extern void *osl_reg_map(uint32 pa, uint size);
++extern void osl_reg_unmap(void *va);
++
++/* shared (dma-able) memory access macros */
++#define R_SM(r) *(r)
++#define W_SM(r, v) (*(r) = (v))
++#define BZERO_SM(r, len) bzero((r), (len))
++
++/* packet primitives */
++#define PKTGET(osh, len, send) osl_pktget((osh), (len), (send))
++#define PKTFREE(osh, skb, send) osl_pktfree((skb))
++#define PKTDATA(osh, skb) osl_pktdata((osh), (skb))
++#define PKTLEN(osh, skb) osl_pktlen((osh), (skb))
++#define PKTHEADROOM(osh, skb) osl_pktheadroom((osh), (skb))
++#define PKTTAILROOM(osh, skb) osl_pkttailroom((osh), (skb))
++#define PKTNEXT(osh, skb) osl_pktnext((osh), (skb))
++#define PKTSETNEXT(skb, x) osl_pktsetnext((skb), (x))
++#define PKTSETLEN(osh, skb, len) osl_pktsetlen((osh), (skb), (len))
++#define PKTPUSH(osh, skb, bytes) osl_pktpush((osh), (skb), (bytes))
++#define PKTPULL(osh, skb, bytes) osl_pktpull((osh), (skb), (bytes))
++#define PKTDUP(osh, skb) osl_pktdup((osh), (skb))
++#define PKTCOOKIE(skb) osl_pktcookie((skb))
++#define PKTSETCOOKIE(skb, x) osl_pktsetcookie((skb), (x))
++#define PKTLINK(skb) osl_pktlink((skb))
++#define PKTSETLINK(skb, x) osl_pktsetlink((skb), (x))
++#define PKTPRIO(skb) osl_pktprio((skb))
++#define PKTSETPRIO(skb, x) osl_pktsetprio((skb), (x))
++extern void *osl_pktget(osl_t *osh, uint len, bool send);
++extern void osl_pktfree(void *skb);
++extern uchar *osl_pktdata(osl_t *osh, void *skb);
++extern uint osl_pktlen(osl_t *osh, void *skb);
++extern uint osl_pktheadroom(osl_t *osh, void *skb);
++extern uint osl_pkttailroom(osl_t *osh, void *skb);
++extern void *osl_pktnext(osl_t *osh, void *skb);
++extern void osl_pktsetnext(void *skb, void *x);
++extern void osl_pktsetlen(osl_t *osh, void *skb, uint len);
++extern uchar *osl_pktpush(osl_t *osh, void *skb, int bytes);
++extern uchar *osl_pktpull(osl_t *osh, void *skb, int bytes);
++extern void *osl_pktdup(osl_t *osh, void *skb);
++extern void *osl_pktcookie(void *skb);
++extern void osl_pktsetcookie(void *skb, void *x);
++extern void *osl_pktlink(void *skb);
++extern void osl_pktsetlink(void *skb, void *x);
++extern uint osl_pktprio(void *skb);
++extern void osl_pktsetprio(void *skb, uint x);
++
++#endif /* BINOSL */
++
++#define OSL_ERROR(bcmerror) osl_error(bcmerror)
++extern int osl_error(int bcmerror);
++
++/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */
++#define PKTBUFSZ 2048
++
++#endif /* _linux_osl_h_ */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/linuxver.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/linuxver.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/linuxver.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/linuxver.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,389 @@
++/*
++ * Linux-specific abstractions to gain some independence from linux kernel versions.
++ * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#ifndef _linuxver_h_
++#define _linuxver_h_
++
++#include <linux/config.h>
++#include <linux/version.h>
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
++/* __NO_VERSION__ must be defined for all linkables except one in 2.2 */
++#ifdef __UNDEF_NO_VERSION__
++#undef __NO_VERSION__
++#else
++#define __NO_VERSION__
++#endif
++#endif
++
++#if defined(MODULE) && defined(MODVERSIONS)
++#include <linux/modversions.h>
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
++#include <linux/moduleparam.h>
++#endif
++
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
++#define module_param(_name_, _type_, _perm_) MODULE_PARM(_name_, "i")
++#define module_param_string(_name_, _string_, _size_, _perm_) MODULE_PARM(_string_, "c" __MODULE_STRING(_size_))
++#endif
++
++/* linux/malloc.h is deprecated, use linux/slab.h instead. */
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9))
++#include <linux/malloc.h>
++#else
++#include <linux/slab.h>
++#endif
++
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/string.h>
++#include <linux/pci.h>
++#include <linux/interrupt.h>
++#include <linux/netdevice.h>
++#include <asm/io.h>
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41))
++#include <linux/workqueue.h>
++#else
++#include <linux/tqueue.h>
++#ifndef work_struct
++#define work_struct tq_struct
++#endif
++#ifndef INIT_WORK
++#define INIT_WORK(_work, _func, _data) INIT_TQUEUE((_work), (_func), (_data))
++#endif
++#ifndef schedule_work
++#define schedule_work(_work) schedule_task((_work))
++#endif
++#ifndef flush_scheduled_work
++#define flush_scheduled_work() flush_scheduled_tasks()
++#endif
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
++/* Some distributions have their own 2.6.x compatibility layers */
++#ifndef IRQ_NONE
++typedef void irqreturn_t;
++#define IRQ_NONE
++#define IRQ_HANDLED
++#define IRQ_RETVAL(x)
++#endif
++#else
++typedef irqreturn_t (*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs);
++#endif
++
++#ifndef __exit
++#define __exit
++#endif
++#ifndef __devexit
++#define __devexit
++#endif
++#ifndef __devinit
++#define __devinit __init
++#endif
++#ifndef __devinitdata
++#define __devinitdata
++#endif
++#ifndef __devexit_p
++#define __devexit_p(x) x
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
++
++#define pci_get_drvdata(dev) (dev)->sysdata
++#define pci_set_drvdata(dev, value) (dev)->sysdata=(value)
++
++/*
++ * New-style (2.4.x) PCI/hot-pluggable PCI/CardBus registration
++ */
++
++struct pci_device_id {
++ unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */
++ unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
++ unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */
++ unsigned long driver_data; /* Data private to the driver */
++};
++
++struct pci_driver {
++ struct list_head node;
++ char *name;
++ const struct pci_device_id *id_table; /* NULL if wants all devices */
++ int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */
++ void (*remove)(struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */
++ void (*suspend)(struct pci_dev *dev); /* Device suspended */
++ void (*resume)(struct pci_dev *dev); /* Device woken up */
++};
++
++#define MODULE_DEVICE_TABLE(type, name)
++#define PCI_ANY_ID (~0)
++
++/* compatpci.c */
++#define pci_module_init pci_register_driver
++extern int pci_register_driver(struct pci_driver *drv);
++extern void pci_unregister_driver(struct pci_driver *drv);
++
++#endif /* PCI registration */
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18))
++#ifdef MODULE
++#define module_init(x) int init_module(void) { return x(); }
++#define module_exit(x) void cleanup_module(void) { x(); }
++#else
++#define module_init(x) __initcall(x);
++#define module_exit(x) __exitcall(x);
++#endif
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,48))
++#define list_for_each(pos, head) \
++ for (pos = (head)->next; pos != (head); pos = pos->next)
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13))
++#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)])
++#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,44))
++#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start)
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,23))
++#define pci_enable_device(dev) do { } while (0)
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,14))
++#define net_device device
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,42))
++
++/*
++ * DMA mapping
++ *
++ * See linux/Documentation/DMA-mapping.txt
++ */
++
++#ifndef PCI_DMA_TODEVICE
++#define PCI_DMA_TODEVICE 1
++#define PCI_DMA_FROMDEVICE 2
++#endif
++
++typedef u32 dma_addr_t;
++
++/* Pure 2^n version of get_order */
++static inline int get_order(unsigned long size)
++{
++ int order;
++
++ size = (size-1) >> (PAGE_SHIFT-1);
++ order = -1;
++ do {
++ size >>= 1;
++ order++;
++ } while (size);
++ return order;
++}
++
++static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
++ dma_addr_t *dma_handle)
++{
++ void *ret;
++ int gfp = GFP_ATOMIC | GFP_DMA;
++
++ ret = (void *)__get_free_pages(gfp, get_order(size));
++
++ if (ret != NULL) {
++ memset(ret, 0, size);
++ *dma_handle = virt_to_bus(ret);
++ }
++ return ret;
++}
++static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size,
++ void *vaddr, dma_addr_t dma_handle)
++{
++ free_pages((unsigned long)vaddr, get_order(size));
++}
++#ifdef ILSIM
++extern uint pci_map_single(void *dev, void *va, uint size, int direction);
++extern void pci_unmap_single(void *dev, uint pa, uint size, int direction);
++#else
++#define pci_map_single(cookie, address, size, dir) virt_to_bus(address)
++#define pci_unmap_single(cookie, address, size, dir)
++#endif
++
++#endif /* DMA mapping */
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43))
++
++#define dev_kfree_skb_any(a) dev_kfree_skb(a)
++#define netif_down(dev) do { (dev)->start = 0; } while(0)
++
++/* pcmcia-cs provides its own netdevice compatibility layer */
++#ifndef _COMPAT_NETDEVICE_H
++
++/*
++ * SoftNet
++ *
++ * For pre-softnet kernels we need to tell the upper layer not to
++ * re-enter start_xmit() while we are in there. However softnet
++ * guarantees not to enter while we are in there so there is no need
++ * to do the netif_stop_queue() dance unless the transmit queue really
++ * gets stuck. This should also improve performance according to tests
++ * done by Aman Singla.
++ */
++
++#define dev_kfree_skb_irq(a) dev_kfree_skb(a)
++#define netif_wake_queue(dev) do { clear_bit(0, &(dev)->tbusy); mark_bh(NET_BH); } while(0)
++#define netif_stop_queue(dev) set_bit(0, &(dev)->tbusy)
++
++static inline void netif_start_queue(struct net_device *dev)
++{
++ dev->tbusy = 0;
++ dev->interrupt = 0;
++ dev->start = 1;
++}
++
++#define netif_queue_stopped(dev) (dev)->tbusy
++#define netif_running(dev) (dev)->start
++
++#endif /* _COMPAT_NETDEVICE_H */
++
++#define netif_device_attach(dev) netif_start_queue(dev)
++#define netif_device_detach(dev) netif_stop_queue(dev)
++
++/* 2.4.x renamed bottom halves to tasklets */
++#define tasklet_struct tq_struct
++static inline void tasklet_schedule(struct tasklet_struct *tasklet)
++{
++ queue_task(tasklet, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++}
++
++static inline void tasklet_init(struct tasklet_struct *tasklet,
++ void (*func)(unsigned long),
++ unsigned long data)
++{
++ tasklet->next = NULL;
++ tasklet->sync = 0;
++ tasklet->routine = (void (*)(void *))func;
++ tasklet->data = (void *)data;
++}
++#define tasklet_kill(tasklet) {do{} while(0);}
++
++/* 2.4.x introduced del_timer_sync() */
++#define del_timer_sync(timer) del_timer(timer)
++
++#else
++
++#define netif_down(dev)
++
++#endif /* SoftNet */
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3))
++
++/*
++ * Emit code to initialise a tq_struct's routine and data pointers
++ */
++#define PREPARE_TQUEUE(_tq, _routine, _data) \
++ do { \
++ (_tq)->routine = _routine; \
++ (_tq)->data = _data; \
++ } while (0)
++
++/*
++ * Emit code to initialise all of a tq_struct
++ */
++#define INIT_TQUEUE(_tq, _routine, _data) \
++ do { \
++ INIT_LIST_HEAD(&(_tq)->list); \
++ (_tq)->sync = 0; \
++ PREPARE_TQUEUE((_tq), (_routine), (_data)); \
++ } while (0)
++
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,6))
++
++/* Power management related routines */
++
++static inline int
++pci_save_state(struct pci_dev *dev, u32 *buffer)
++{
++ int i;
++ if (buffer) {
++ for (i = 0; i < 16; i++)
++ pci_read_config_dword(dev, i * 4,&buffer[i]);
++ }
++ return 0;
++}
++
++static inline int
++pci_restore_state(struct pci_dev *dev, u32 *buffer)
++{
++ int i;
++
++ if (buffer) {
++ for (i = 0; i < 16; i++)
++ pci_write_config_dword(dev,i * 4, buffer[i]);
++ }
++ /*
++ * otherwise, write the context information we know from bootup.
++ * This works around a problem where warm-booting from Windows
++ * combined with a D3(hot)->D0 transition causes PCI config
++ * header data to be forgotten.
++ */
++ else {
++ for (i = 0; i < 6; i ++)
++ pci_write_config_dword(dev,
++ PCI_BASE_ADDRESS_0 + (i * 4),
++ pci_resource_start(dev, i));
++ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
++ }
++ return 0;
++}
++
++#endif /* PCI power management */
++
++/* Old cp0 access macros deprecated in 2.4.19 */
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19))
++#define read_c0_count() read_32bit_cp0_register(CP0_COUNT)
++#endif
++
++/* Module refcount handled internally in 2.6.x */
++#ifndef SET_MODULE_OWNER
++#define SET_MODULE_OWNER(dev) do {} while (0)
++#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
++#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
++#else
++#define OLD_MOD_INC_USE_COUNT do {} while (0)
++#define OLD_MOD_DEC_USE_COUNT do {} while (0)
++#endif
++
++#ifndef SET_NETDEV_DEV
++#define SET_NETDEV_DEV(net, pdev) do {} while (0)
++#endif
++
++#ifndef HAVE_FREE_NETDEV
++#define free_netdev(dev) kfree(dev)
++#endif
++
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
++/* struct packet_type redefined in 2.6.x */
++#define af_packet_priv data
++#endif
++
++#endif /* _linuxver_h_ */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/mipsinc.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/mipsinc.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/mipsinc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/mipsinc.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,552 @@
++/*
++ * HND Run Time Environment for standalone MIPS programs.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#ifndef _MISPINC_H
++#define _MISPINC_H
++
++
++/* MIPS defines */
++
++#ifdef _LANGUAGE_ASSEMBLY
++
++/*
++ * Symbolic register names for 32 bit ABI
++ */
++#define zero $0 /* wired zero */
++#define AT $1 /* assembler temp - uppercase because of ".set at" */
++#define v0 $2 /* return value */
++#define v1 $3
++#define a0 $4 /* argument registers */
++#define a1 $5
++#define a2 $6
++#define a3 $7
++#define t0 $8 /* caller saved */
++#define t1 $9
++#define t2 $10
++#define t3 $11
++#define t4 $12
++#define t5 $13
++#define t6 $14
++#define t7 $15
++#define s0 $16 /* callee saved */
++#define s1 $17
++#define s2 $18
++#define s3 $19
++#define s4 $20
++#define s5 $21
++#define s6 $22
++#define s7 $23
++#define t8 $24 /* caller saved */
++#define t9 $25
++#define jp $25 /* PIC jump register */
++#define k0 $26 /* kernel scratch */
++#define k1 $27
++#define gp $28 /* global pointer */
++#define sp $29 /* stack pointer */
++#define fp $30 /* frame pointer */
++#define s8 $30 /* same like fp! */
++#define ra $31 /* return address */
++
++
++/*
++ * CP0 Registers
++ */
++
++#define C0_INX $0
++#define C0_RAND $1
++#define C0_TLBLO0 $2
++#define C0_TLBLO C0_TLBLO0
++#define C0_TLBLO1 $3
++#define C0_CTEXT $4
++#define C0_PGMASK $5
++#define C0_WIRED $6
++#define C0_BADVADDR $8
++#define C0_COUNT $9
++#define C0_TLBHI $10
++#define C0_COMPARE $11
++#define C0_SR $12
++#define C0_STATUS C0_SR
++#define C0_CAUSE $13
++#define C0_EPC $14
++#define C0_PRID $15
++#define C0_CONFIG $16
++#define C0_LLADDR $17
++#define C0_WATCHLO $18
++#define C0_WATCHHI $19
++#define C0_XCTEXT $20
++#define C0_DIAGNOSTIC $22
++#define C0_BROADCOM C0_DIAGNOSTIC
++#define C0_PERFORMANCE $25
++#define C0_ECC $26
++#define C0_CACHEERR $27
++#define C0_TAGLO $28
++#define C0_TAGHI $29
++#define C0_ERREPC $30
++#define C0_DESAVE $31
++
++/*
++ * LEAF - declare leaf routine
++ */
++#define LEAF(symbol) \
++ .globl symbol; \
++ .align 2; \
++ .type symbol,@function; \
++ .ent symbol,0; \
++symbol: .frame sp,0,ra
++
++/*
++ * END - mark end of function
++ */
++#define END(function) \
++ .end function; \
++ .size function,.-function
++
++#define _ULCAST_
++
++#else
++
++/*
++ * The following macros are especially useful for __asm__
++ * inline assembler.
++ */
++#ifndef __STR
++#define __STR(x) #x
++#endif
++#ifndef STR
++#define STR(x) __STR(x)
++#endif
++
++#define _ULCAST_ (unsigned long)
++
++
++/*
++ * CP0 Registers
++ */
++
++#define C0_INX 0 /* CP0: TLB Index */
++#define C0_RAND 1 /* CP0: TLB Random */
++#define C0_TLBLO0 2 /* CP0: TLB EntryLo0 */
++#define C0_TLBLO C0_TLBLO0 /* CP0: TLB EntryLo0 */
++#define C0_TLBLO1 3 /* CP0: TLB EntryLo1 */
++#define C0_CTEXT 4 /* CP0: Context */
++#define C0_PGMASK 5 /* CP0: TLB PageMask */
++#define C0_WIRED 6 /* CP0: TLB Wired */
++#define C0_BADVADDR 8 /* CP0: Bad Virtual Address */
++#define C0_COUNT 9 /* CP0: Count */
++#define C0_TLBHI 10 /* CP0: TLB EntryHi */
++#define C0_COMPARE 11 /* CP0: Compare */
++#define C0_SR 12 /* CP0: Processor Status */
++#define C0_STATUS C0_SR /* CP0: Processor Status */
++#define C0_CAUSE 13 /* CP0: Exception Cause */
++#define C0_EPC 14 /* CP0: Exception PC */
++#define C0_PRID 15 /* CP0: Processor Revision Indentifier */
++#define C0_CONFIG 16 /* CP0: Config */
++#define C0_LLADDR 17 /* CP0: LLAddr */
++#define C0_WATCHLO 18 /* CP0: WatchpointLo */
++#define C0_WATCHHI 19 /* CP0: WatchpointHi */
++#define C0_XCTEXT 20 /* CP0: XContext */
++#define C0_DIAGNOSTIC 22 /* CP0: Diagnostic */
++#define C0_BROADCOM C0_DIAGNOSTIC /* CP0: Broadcom Register */
++#define C0_PERFORMANCE 25 /* CP0: Performance Counter/Control Registers */
++#define C0_ECC 26 /* CP0: ECC */
++#define C0_CACHEERR 27 /* CP0: CacheErr */
++#define C0_TAGLO 28 /* CP0: TagLo */
++#define C0_TAGHI 29 /* CP0: TagHi */
++#define C0_ERREPC 30 /* CP0: ErrorEPC */
++#define C0_DESAVE 31 /* CP0: DebugSave */
++
++#endif /* _LANGUAGE_ASSEMBLY */
++
++/*
++ * Memory segments (32bit kernel mode addresses)
++ */
++#undef KUSEG
++#undef KSEG0
++#undef KSEG1
++#undef KSEG2
++#undef KSEG3
++#define KUSEG 0x00000000
++#define KSEG0 0x80000000
++#define KSEG1 0xa0000000
++#define KSEG2 0xc0000000
++#define KSEG3 0xe0000000
++#define PHYSADDR_MASK 0x1fffffff
++
++/*
++ * Map an address to a certain kernel segment
++ */
++#undef PHYSADDR
++#undef KSEG0ADDR
++#undef KSEG1ADDR
++#undef KSEG2ADDR
++#undef KSEG3ADDR
++
++#define PHYSADDR(a) (_ULCAST_(a) & PHYSADDR_MASK)
++#define KSEG0ADDR(a) ((_ULCAST_(a) & PHYSADDR_MASK) | KSEG0)
++#define KSEG1ADDR(a) ((_ULCAST_(a) & PHYSADDR_MASK) | KSEG1)
++#define KSEG2ADDR(a) ((_ULCAST_(a) & PHYSADDR_MASK) | KSEG2)
++#define KSEG3ADDR(a) ((_ULCAST_(a) & PHYSADDR_MASK) | KSEG3)
++
++
++#ifndef Index_Invalidate_I
++/*
++ * Cache Operations
++ */
++#define Index_Invalidate_I 0x00
++#define Index_Writeback_Inv_D 0x01
++#define Index_Invalidate_SI 0x02
++#define Index_Writeback_Inv_SD 0x03
++#define Index_Load_Tag_I 0x04
++#define Index_Load_Tag_D 0x05
++#define Index_Load_Tag_SI 0x06
++#define Index_Load_Tag_SD 0x07
++#define Index_Store_Tag_I 0x08
++#define Index_Store_Tag_D 0x09
++#define Index_Store_Tag_SI 0x0A
++#define Index_Store_Tag_SD 0x0B
++#define Create_Dirty_Excl_D 0x0d
++#define Create_Dirty_Excl_SD 0x0f
++#define Hit_Invalidate_I 0x10
++#define Hit_Invalidate_D 0x11
++#define Hit_Invalidate_SI 0x12
++#define Hit_Invalidate_SD 0x13
++#define Fill_I 0x14
++#define Hit_Writeback_Inv_D 0x15
++ /* 0x16 is unused */
++#define Hit_Writeback_Inv_SD 0x17
++#define R5K_Page_Invalidate_S 0x17
++#define Hit_Writeback_I 0x18
++#define Hit_Writeback_D 0x19
++ /* 0x1a is unused */
++#define Hit_Writeback_SD 0x1b
++ /* 0x1c is unused */
++ /* 0x1e is unused */
++#define Hit_Set_Virtual_SI 0x1e
++#define Hit_Set_Virtual_SD 0x1f
++#endif
++
++
++/*
++ * R4x00 interrupt enable / cause bits
++ */
++#define IE_SW0 (_ULCAST_(1) << 8)
++#define IE_SW1 (_ULCAST_(1) << 9)
++#define IE_IRQ0 (_ULCAST_(1) << 10)
++#define IE_IRQ1 (_ULCAST_(1) << 11)
++#define IE_IRQ2 (_ULCAST_(1) << 12)
++#define IE_IRQ3 (_ULCAST_(1) << 13)
++#define IE_IRQ4 (_ULCAST_(1) << 14)
++#define IE_IRQ5 (_ULCAST_(1) << 15)
++
++#ifndef ST0_UM
++/*
++ * Bitfields in the mips32 cp0 status register
++ */
++#define ST0_IE 0x00000001
++#define ST0_EXL 0x00000002
++#define ST0_ERL 0x00000004
++#define ST0_UM 0x00000010
++#define ST0_SWINT0 0x00000100
++#define ST0_SWINT1 0x00000200
++#define ST0_HWINT0 0x00000400
++#define ST0_HWINT1 0x00000800
++#define ST0_HWINT2 0x00001000
++#define ST0_HWINT3 0x00002000
++#define ST0_HWINT4 0x00004000
++#define ST0_HWINT5 0x00008000
++#define ST0_IM 0x0000ff00
++#define ST0_NMI 0x00080000
++#define ST0_SR 0x00100000
++#define ST0_TS 0x00200000
++#define ST0_BEV 0x00400000
++#define ST0_RE 0x02000000
++#define ST0_RP 0x08000000
++#define ST0_CU 0xf0000000
++#define ST0_CU0 0x10000000
++#define ST0_CU1 0x20000000
++#define ST0_CU2 0x40000000
++#define ST0_CU3 0x80000000
++#endif
++
++
++/*
++ * Bitfields in the mips32 cp0 cause register
++ */
++#define C_EXC 0x0000007c
++#define C_EXC_SHIFT 2
++#define C_INT 0x0000ff00
++#define C_INT_SHIFT 8
++#define C_SW0 (_ULCAST_(1) << 8)
++#define C_SW1 (_ULCAST_(1) << 9)
++#define C_IRQ0 (_ULCAST_(1) << 10)
++#define C_IRQ1 (_ULCAST_(1) << 11)
++#define C_IRQ2 (_ULCAST_(1) << 12)
++#define C_IRQ3 (_ULCAST_(1) << 13)
++#define C_IRQ4 (_ULCAST_(1) << 14)
++#define C_IRQ5 (_ULCAST_(1) << 15)
++#define C_WP 0x00400000
++#define C_IV 0x00800000
++#define C_CE 0x30000000
++#define C_CE_SHIFT 28
++#define C_BD 0x80000000
++
++/* Values in C_EXC */
++#define EXC_INT 0
++#define EXC_TLBM 1
++#define EXC_TLBL 2
++#define EXC_TLBS 3
++#define EXC_AEL 4
++#define EXC_AES 5
++#define EXC_IBE 6
++#define EXC_DBE 7
++#define EXC_SYS 8
++#define EXC_BPT 9
++#define EXC_RI 10
++#define EXC_CU 11
++#define EXC_OV 12
++#define EXC_TR 13
++#define EXC_WATCH 23
++#define EXC_MCHK 24
++
++
++/*
++ * Bits in the cp0 config register.
++ */
++#define CONF_CM_CACHABLE_NO_WA 0
++#define CONF_CM_CACHABLE_WA 1
++#define CONF_CM_UNCACHED 2
++#define CONF_CM_CACHABLE_NONCOHERENT 3
++#define CONF_CM_CACHABLE_CE 4
++#define CONF_CM_CACHABLE_COW 5
++#define CONF_CM_CACHABLE_CUW 6
++#define CONF_CM_CACHABLE_ACCELERATED 7
++#define CONF_CM_CMASK 7
++#define CONF_CU (_ULCAST_(1) << 3)
++#define CONF_DB (_ULCAST_(1) << 4)
++#define CONF_IB (_ULCAST_(1) << 5)
++#define CONF_SE (_ULCAST_(1) << 12)
++#define CONF_SC (_ULCAST_(1) << 17)
++#define CONF_AC (_ULCAST_(1) << 23)
++#define CONF_HALT (_ULCAST_(1) << 25)
++
++
++/*
++ * Bits in the cp0 config register select 1.
++ */
++#define CONF1_FP 0x00000001 /* FPU present */
++#define CONF1_EP 0x00000002 /* EJTAG present */
++#define CONF1_CA 0x00000004 /* mips16 implemented */
++#define CONF1_WR 0x00000008 /* Watch registers present */
++#define CONF1_PC 0x00000010 /* Performance counters present */
++#define CONF1_DA_SHIFT 7 /* D$ associativity */
++#define CONF1_DA_MASK 0x00000380
++#define CONF1_DA_BASE 1
++#define CONF1_DL_SHIFT 10 /* D$ line size */
++#define CONF1_DL_MASK 0x00001c00
++#define CONF1_DL_BASE 2
++#define CONF1_DS_SHIFT 13 /* D$ sets/way */
++#define CONF1_DS_MASK 0x0000e000
++#define CONF1_DS_BASE 64
++#define CONF1_IA_SHIFT 16 /* I$ associativity */
++#define CONF1_IA_MASK 0x00070000
++#define CONF1_IA_BASE 1
++#define CONF1_IL_SHIFT 19 /* I$ line size */
++#define CONF1_IL_MASK 0x00380000
++#define CONF1_IL_BASE 2
++#define CONF1_IS_SHIFT 22 /* Instruction cache sets/way */
++#define CONF1_IS_MASK 0x01c00000
++#define CONF1_IS_BASE 64
++#define CONF1_MS_MASK 0x7e000000 /* Number of tlb entries */
++#define CONF1_MS_SHIFT 25
++
++/* PRID register */
++#define PRID_COPT_MASK 0xff000000
++#define PRID_COMP_MASK 0x00ff0000
++#define PRID_IMP_MASK 0x0000ff00
++#define PRID_REV_MASK 0x000000ff
++
++#define PRID_COMP_LEGACY 0x000000
++#define PRID_COMP_MIPS 0x010000
++#define PRID_COMP_BROADCOM 0x020000
++#define PRID_COMP_ALCHEMY 0x030000
++#define PRID_COMP_SIBYTE 0x040000
++#define PRID_IMP_BCM4710 0x4000
++#define PRID_IMP_BCM3302 0x9000
++#define PRID_IMP_BCM3303 0x9100
++
++#define PRID_IMP_UNKNOWN 0xff00
++
++#define BCM330X(id) \
++ (((id & (PRID_COMP_MASK | PRID_IMP_MASK)) == (PRID_COMP_BROADCOM | PRID_IMP_BCM3302)) \
++ || ((id & (PRID_COMP_MASK | PRID_IMP_MASK)) == (PRID_COMP_BROADCOM | PRID_IMP_BCM3303)))
++
++/* Bits in C0_BROADCOM */
++#define BRCM_PFC_AVAIL 0x20000000 /* PFC is available */
++#define BRCM_DC_ENABLE 0x40000000 /* Enable Data $ */
++#define BRCM_IC_ENABLE 0x80000000 /* Enable Instruction $ */
++#define BRCM_PFC_ENABLE 0x00400000 /* Obsolete? Enable PFC (at least on 4310) */
++
++/* PreFetch Cache aka Read Ahead Cache */
++
++#define PFC_CR0 0xff400000 /* control reg 0 */
++#define PFC_CR1 0xff400004 /* control reg 1 */
++
++/* PFC operations */
++#define PFC_I 0x00000001 /* Enable PFC use for instructions */
++#define PFC_D 0x00000002 /* Enable PFC use for data */
++#define PFC_PFI 0x00000004 /* Enable seq. prefetch for instructions */
++#define PFC_PFD 0x00000008 /* Enable seq. prefetch for data */
++#define PFC_CINV 0x00000010 /* Enable selective (i/d) cacheop flushing */
++#define PFC_NCH 0x00000020 /* Disable flushing based on cacheops */
++#define PFC_DPF 0x00000040 /* Enable directional prefetching */
++#define PFC_FLUSH 0x00000100 /* Flush the PFC */
++#define PFC_BRR 0x40000000 /* Bus error indication */
++#define PFC_PWR 0x80000000 /* Disable power saving (clock gating) */
++
++/* Handy defaults */
++#define PFC_DISABLED 0
++#define PFC_AUTO 0xffffffff /* auto select the default mode */
++#define PFC_INST (PFC_I | PFC_PFI | PFC_CINV)
++#define PFC_INST_NOPF (PFC_I | PFC_CINV)
++#define PFC_DATA (PFC_D | PFC_PFD | PFC_CINV)
++#define PFC_DATA_NOPF (PFC_D | PFC_CINV)
++#define PFC_I_AND_D (PFC_INST | PFC_DATA)
++#define PFC_I_AND_D_NOPF (PFC_INST_NOPF | PFC_DATA_NOPF)
++
++
++/*
++ * These are the UART port assignments, expressed as offsets from the base
++ * register. These assignments should hold for any serial port based on
++ * a 8250, 16450, or 16550(A).
++ */
++
++#define UART_RX 0 /* In: Receive buffer (DLAB=0) */
++#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */
++#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */
++#define UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */
++#define UART_LCR 3 /* Out: Line Control Register */
++#define UART_MCR 4 /* Out: Modem Control Register */
++#define UART_LSR 5 /* In: Line Status Register */
++#define UART_MSR 6 /* In: Modem Status Register */
++#define UART_SCR 7 /* I/O: Scratch Register */
++#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
++#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
++#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
++#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
++#define UART_LSR_RXRDY 0x01 /* Receiver ready */
++
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++/*
++ * Macros to access the system control coprocessor
++ */
++
++#define MFC0(source, sel) \
++({ \
++ int __res; \
++ __asm__ __volatile__( \
++ ".set\tnoreorder\n\t" \
++ ".set\tnoat\n\t" \
++ ".word\t"STR(0x40010000 | ((source)<<11) | (sel))"\n\t" \
++ "move\t%0,$1\n\t" \
++ ".set\tat\n\t" \
++ ".set\treorder" \
++ :"=r" (__res) \
++ : \
++ :"$1"); \
++ __res; \
++})
++
++#define MTC0(source, sel, value) \
++do { \
++ __asm__ __volatile__( \
++ ".set\tnoreorder\n\t" \
++ ".set\tnoat\n\t" \
++ "move\t$1,%z0\n\t" \
++ ".word\t"STR(0x40810000 | ((source)<<11) | (sel))"\n\t" \
++ ".set\tat\n\t" \
++ ".set\treorder" \
++ : \
++ :"jr" (value) \
++ :"$1"); \
++} while (0)
++
++#define get_c0_count() \
++({ \
++ int __res; \
++ __asm__ __volatile__( \
++ ".set\tnoreorder\n\t" \
++ ".set\tnoat\n\t" \
++ "mfc0\t%0,$9\n\t" \
++ ".set\tat\n\t" \
++ ".set\treorder" \
++ :"=r" (__res)); \
++ __res; \
++})
++
++static INLINE void icache_probe(uint32 config1, uint *size, uint *lsize)
++{
++ uint lsz, sets, ways;
++
++ /* Instruction Cache Size = Associativity * Line Size * Sets Per Way */
++ if ((lsz = ((config1 & CONF1_IL_MASK) >> CONF1_IL_SHIFT)))
++ lsz = CONF1_IL_BASE << lsz;
++ sets = CONF1_IS_BASE << ((config1 & CONF1_IS_MASK) >> CONF1_IS_SHIFT);
++ ways = CONF1_IA_BASE + ((config1 & CONF1_IA_MASK) >> CONF1_IA_SHIFT);
++ *size = lsz * sets * ways;
++ *lsize = lsz;
++}
++
++static INLINE void dcache_probe(uint32 config1, uint *size, uint *lsize)
++{
++ uint lsz, sets, ways;
++
++ /* Data Cache Size = Associativity * Line Size * Sets Per Way */
++ if ((lsz = ((config1 & CONF1_DL_MASK) >> CONF1_DL_SHIFT)))
++ lsz = CONF1_DL_BASE << lsz;
++ sets = CONF1_DS_BASE << ((config1 & CONF1_DS_MASK) >> CONF1_DS_SHIFT);
++ ways = CONF1_DA_BASE + ((config1 & CONF1_DA_MASK) >> CONF1_DA_SHIFT);
++ *size = lsz * sets * ways;
++ *lsize = lsz;
++}
++
++#define cache_op(base, op) \
++ __asm__ __volatile__(" \
++ .set noreorder; \
++ .set mips3; \
++ cache %1, (%0); \
++ .set mips0; \
++ .set reorder" \
++ : \
++ : "r" (base), \
++ "i" (op));
++
++#define cache_unroll4(base, delta, op) \
++ __asm__ __volatile__(" \
++ .set noreorder; \
++ .set mips3; \
++ cache %1,0(%0); \
++ cache %1,delta(%0); \
++ cache %1,(2 * delta)(%0); \
++ cache %1,(3 * delta)(%0); \
++ .set mips0; \
++ .set reorder" \
++ : \
++ : "r" (base), \
++ "i" (op));
++
++#endif /* !_LANGUAGE_ASSEMBLY */
++
++#endif /* _MISPINC_H */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/osl.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/osl.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/osl.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/osl.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,42 @@
++/*
++ * OS Abstraction Layer
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id$
++ */
++
++#ifndef _osl_h_
++#define _osl_h_
++
++/* osl handle type forward declaration */
++typedef struct os_handle osl_t;
++
++#if defined(linux)
++#include <linux_osl.h>
++#elif defined(NDIS)
++#include <ndis_osl.h>
++#elif defined(_CFE_)
++#include <cfe_osl.h>
++#elif defined(_HNDRTE_)
++#include <hndrte_osl.h>
++#elif defined(_MINOSL_)
++#include <min_osl.h>
++#elif PMON
++#include <pmon_osl.h>
++#elif defined(MACOSX)
++#include <macosx_osl.h>
++#else
++#error "Unsupported OSL requested"
++#endif
++
++/* handy */
++#define SET_REG(r, mask, val) W_REG((r), ((R_REG(r) & ~(mask)) | (val)))
++#define MAXPRIO 7 /* 0-7 */
++
++#endif /* _osl_h_ */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/pcicfg.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/pcicfg.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/pcicfg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/pcicfg.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,398 @@
++/*
++ * pcicfg.h: PCI configuration constants and structures.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#ifndef _h_pci_
++#define _h_pci_
++
++/* The following inside ifndef's so we don't collide with NTDDK.H */
++#ifndef PCI_MAX_BUS
++#define PCI_MAX_BUS 0x100
++#endif
++#ifndef PCI_MAX_DEVICES
++#define PCI_MAX_DEVICES 0x20
++#endif
++#ifndef PCI_MAX_FUNCTION
++#define PCI_MAX_FUNCTION 0x8
++#endif
++
++#ifndef PCI_INVALID_VENDORID
++#define PCI_INVALID_VENDORID 0xffff
++#endif
++#ifndef PCI_INVALID_DEVICEID
++#define PCI_INVALID_DEVICEID 0xffff
++#endif
++
++
++/* Convert between bus-slot-function-register and config addresses */
++
++#define PCICFG_BUS_SHIFT 16 /* Bus shift */
++#define PCICFG_SLOT_SHIFT 11 /* Slot shift */
++#define PCICFG_FUN_SHIFT 8 /* Function shift */
++#define PCICFG_OFF_SHIFT 0 /* Register shift */
++
++#define PCICFG_BUS_MASK 0xff /* Bus mask */
++#define PCICFG_SLOT_MASK 0x1f /* Slot mask */
++#define PCICFG_FUN_MASK 7 /* Function mask */
++#define PCICFG_OFF_MASK 0xff /* Bus mask */
++
++#define PCI_CONFIG_ADDR(b, s, f, o) \
++ ((((b) & PCICFG_BUS_MASK) << PCICFG_BUS_SHIFT) \
++ | (((s) & PCICFG_SLOT_MASK) << PCICFG_SLOT_SHIFT) \
++ | (((f) & PCICFG_FUN_MASK) << PCICFG_FUN_SHIFT) \
++ | (((o) & PCICFG_OFF_MASK) << PCICFG_OFF_SHIFT))
++
++#define PCI_CONFIG_BUS(a) (((a) >> PCICFG_BUS_SHIFT) & PCICFG_BUS_MASK)
++#define PCI_CONFIG_SLOT(a) (((a) >> PCICFG_SLOT_SHIFT) & PCICFG_SLOT_MASK)
++#define PCI_CONFIG_FUN(a) (((a) >> PCICFG_FUN_SHIFT) & PCICFG_FUN_MASK)
++#define PCI_CONFIG_OFF(a) (((a) >> PCICFG_OFF_SHIFT) & PCICFG_OFF_MASK)
++
++/* The actual config space */
++
++#define PCI_BAR_MAX 6
++
++#define PCI_ROM_BAR 8
++
++#define PCR_RSVDA_MAX 2
++
++/* pci config status reg has a bit to indicate that capability ptr is present*/
++
++#define PCI_CAPPTR_PRESENT 0x0010
++
++typedef struct _pci_config_regs {
++ unsigned short vendor;
++ unsigned short device;
++ unsigned short command;
++ unsigned short status;
++ unsigned char rev_id;
++ unsigned char prog_if;
++ unsigned char sub_class;
++ unsigned char base_class;
++ unsigned char cache_line_size;
++ unsigned char latency_timer;
++ unsigned char header_type;
++ unsigned char bist;
++ unsigned long base[PCI_BAR_MAX];
++ unsigned long cardbus_cis;
++ unsigned short subsys_vendor;
++ unsigned short subsys_id;
++ unsigned long baserom;
++ unsigned long rsvd_a[PCR_RSVDA_MAX];
++ unsigned char int_line;
++ unsigned char int_pin;
++ unsigned char min_gnt;
++ unsigned char max_lat;
++ unsigned char dev_dep[192];
++} pci_config_regs;
++
++#define SZPCR (sizeof (pci_config_regs))
++#define MINSZPCR 64 /* offsetof (dev_dep[0] */
++
++/* A structure for the config registers is nice, but in most
++ * systems the config space is not memory mapped, so we need
++ * filed offsetts. :-(
++ */
++#define PCI_CFG_VID 0
++#define PCI_CFG_DID 2
++#define PCI_CFG_CMD 4
++#define PCI_CFG_STAT 6
++#define PCI_CFG_REV 8
++#define PCI_CFG_PROGIF 9
++#define PCI_CFG_SUBCL 0xa
++#define PCI_CFG_BASECL 0xb
++#define PCI_CFG_CLSZ 0xc
++#define PCI_CFG_LATTIM 0xd
++#define PCI_CFG_HDR 0xe
++#define PCI_CFG_BIST 0xf
++#define PCI_CFG_BAR0 0x10
++#define PCI_CFG_BAR1 0x14
++#define PCI_CFG_BAR2 0x18
++#define PCI_CFG_BAR3 0x1c
++#define PCI_CFG_BAR4 0x20
++#define PCI_CFG_BAR5 0x24
++#define PCI_CFG_CIS 0x28
++#define PCI_CFG_SVID 0x2c
++#define PCI_CFG_SSID 0x2e
++#define PCI_CFG_ROMBAR 0x30
++#define PCI_CFG_CAPPTR 0x34
++#define PCI_CFG_INT 0x3c
++#define PCI_CFG_PIN 0x3d
++#define PCI_CFG_MINGNT 0x3e
++#define PCI_CFG_MAXLAT 0x3f
++
++/* Classes and subclasses */
++
++typedef enum {
++ PCI_CLASS_OLD = 0,
++ PCI_CLASS_DASDI,
++ PCI_CLASS_NET,
++ PCI_CLASS_DISPLAY,
++ PCI_CLASS_MMEDIA,
++ PCI_CLASS_MEMORY,
++ PCI_CLASS_BRIDGE,
++ PCI_CLASS_COMM,
++ PCI_CLASS_BASE,
++ PCI_CLASS_INPUT,
++ PCI_CLASS_DOCK,
++ PCI_CLASS_CPU,
++ PCI_CLASS_SERIAL,
++ PCI_CLASS_INTELLIGENT = 0xe,
++ PCI_CLASS_SATELLITE,
++ PCI_CLASS_CRYPT,
++ PCI_CLASS_DSP,
++ PCI_CLASS_MAX
++} pci_classes;
++
++typedef enum {
++ PCI_DASDI_SCSI,
++ PCI_DASDI_IDE,
++ PCI_DASDI_FLOPPY,
++ PCI_DASDI_IPI,
++ PCI_DASDI_RAID,
++ PCI_DASDI_OTHER = 0x80
++} pci_dasdi_subclasses;
++
++typedef enum {
++ PCI_NET_ETHER,
++ PCI_NET_TOKEN,
++ PCI_NET_FDDI,
++ PCI_NET_ATM,
++ PCI_NET_OTHER = 0x80
++} pci_net_subclasses;
++
++typedef enum {
++ PCI_DISPLAY_VGA,
++ PCI_DISPLAY_XGA,
++ PCI_DISPLAY_3D,
++ PCI_DISPLAY_OTHER = 0x80
++} pci_display_subclasses;
++
++typedef enum {
++ PCI_MMEDIA_VIDEO,
++ PCI_MMEDIA_AUDIO,
++ PCI_MMEDIA_PHONE,
++ PCI_MEDIA_OTHER = 0x80
++} pci_mmedia_subclasses;
++
++typedef enum {
++ PCI_MEMORY_RAM,
++ PCI_MEMORY_FLASH,
++ PCI_MEMORY_OTHER = 0x80
++} pci_memory_subclasses;
++
++typedef enum {
++ PCI_BRIDGE_HOST,
++ PCI_BRIDGE_ISA,
++ PCI_BRIDGE_EISA,
++ PCI_BRIDGE_MC,
++ PCI_BRIDGE_PCI,
++ PCI_BRIDGE_PCMCIA,
++ PCI_BRIDGE_NUBUS,
++ PCI_BRIDGE_CARDBUS,
++ PCI_BRIDGE_RACEWAY,
++ PCI_BRIDGE_OTHER = 0x80
++} pci_bridge_subclasses;
++
++typedef enum {
++ PCI_COMM_UART,
++ PCI_COMM_PARALLEL,
++ PCI_COMM_MULTIUART,
++ PCI_COMM_MODEM,
++ PCI_COMM_OTHER = 0x80
++} pci_comm_subclasses;
++
++typedef enum {
++ PCI_BASE_PIC,
++ PCI_BASE_DMA,
++ PCI_BASE_TIMER,
++ PCI_BASE_RTC,
++ PCI_BASE_PCI_HOTPLUG,
++ PCI_BASE_OTHER = 0x80
++} pci_base_subclasses;
++
++typedef enum {
++ PCI_INPUT_KBD,
++ PCI_INPUT_PEN,
++ PCI_INPUT_MOUSE,
++ PCI_INPUT_SCANNER,
++ PCI_INPUT_GAMEPORT,
++ PCI_INPUT_OTHER = 0x80
++} pci_input_subclasses;
++
++typedef enum {
++ PCI_DOCK_GENERIC,
++ PCI_DOCK_OTHER = 0x80
++} pci_dock_subclasses;
++
++typedef enum {
++ PCI_CPU_386,
++ PCI_CPU_486,
++ PCI_CPU_PENTIUM,
++ PCI_CPU_ALPHA = 0x10,
++ PCI_CPU_POWERPC = 0x20,
++ PCI_CPU_MIPS = 0x30,
++ PCI_CPU_COPROC = 0x40,
++ PCI_CPU_OTHER = 0x80
++} pci_cpu_subclasses;
++
++typedef enum {
++ PCI_SERIAL_IEEE1394,
++ PCI_SERIAL_ACCESS,
++ PCI_SERIAL_SSA,
++ PCI_SERIAL_USB,
++ PCI_SERIAL_FIBER,
++ PCI_SERIAL_SMBUS,
++ PCI_SERIAL_OTHER = 0x80
++} pci_serial_subclasses;
++
++typedef enum {
++ PCI_INTELLIGENT_I2O,
++} pci_intelligent_subclasses;
++
++typedef enum {
++ PCI_SATELLITE_TV,
++ PCI_SATELLITE_AUDIO,
++ PCI_SATELLITE_VOICE,
++ PCI_SATELLITE_DATA,
++ PCI_SATELLITE_OTHER = 0x80
++} pci_satellite_subclasses;
++
++typedef enum {
++ PCI_CRYPT_NETWORK,
++ PCI_CRYPT_ENTERTAINMENT,
++ PCI_CRYPT_OTHER = 0x80
++} pci_crypt_subclasses;
++
++typedef enum {
++ PCI_DSP_DPIO,
++ PCI_DSP_OTHER = 0x80
++} pci_dsp_subclasses;
++
++/* Header types */
++typedef enum {
++ PCI_HEADER_NORMAL,
++ PCI_HEADER_BRIDGE,
++ PCI_HEADER_CARDBUS
++} pci_header_types;
++
++
++/* Overlay for a PCI-to-PCI bridge */
++
++#define PPB_RSVDA_MAX 2
++#define PPB_RSVDD_MAX 8
++
++typedef struct _ppb_config_regs {
++ unsigned short vendor;
++ unsigned short device;
++ unsigned short command;
++ unsigned short status;
++ unsigned char rev_id;
++ unsigned char prog_if;
++ unsigned char sub_class;
++ unsigned char base_class;
++ unsigned char cache_line_size;
++ unsigned char latency_timer;
++ unsigned char header_type;
++ unsigned char bist;
++ unsigned long rsvd_a[PPB_RSVDA_MAX];
++ unsigned char prim_bus;
++ unsigned char sec_bus;
++ unsigned char sub_bus;
++ unsigned char sec_lat;
++ unsigned char io_base;
++ unsigned char io_lim;
++ unsigned short sec_status;
++ unsigned short mem_base;
++ unsigned short mem_lim;
++ unsigned short pf_mem_base;
++ unsigned short pf_mem_lim;
++ unsigned long pf_mem_base_hi;
++ unsigned long pf_mem_lim_hi;
++ unsigned short io_base_hi;
++ unsigned short io_lim_hi;
++ unsigned short subsys_vendor;
++ unsigned short subsys_id;
++ unsigned long rsvd_b;
++ unsigned char rsvd_c;
++ unsigned char int_pin;
++ unsigned short bridge_ctrl;
++ unsigned char chip_ctrl;
++ unsigned char diag_ctrl;
++ unsigned short arb_ctrl;
++ unsigned long rsvd_d[PPB_RSVDD_MAX];
++ unsigned char dev_dep[192];
++} ppb_config_regs;
++
++
++/* PCI CAPABILITY DEFINES */
++#define PCI_CAP_POWERMGMTCAP_ID 0x01
++#define PCI_CAP_MSICAP_ID 0x05
++
++/* Data structure to define the Message Signalled Interrupt facility
++ * Valid for PCI and PCIE configurations */
++typedef struct _pciconfig_cap_msi {
++ unsigned char capID;
++ unsigned char nextptr;
++ unsigned short msgctrl;
++ unsigned int msgaddr;
++} pciconfig_cap_msi;
++
++/* Data structure to define the Power managment facility
++ * Valid for PCI and PCIE configurations */
++typedef struct _pciconfig_cap_pwrmgmt {
++ unsigned char capID;
++ unsigned char nextptr;
++ unsigned short pme_cap;
++ unsigned short pme_sts_ctrl;
++ unsigned char pme_bridge_ext;
++ unsigned char data;
++} pciconfig_cap_pwrmgmt;
++
++/* Everything below is BRCM HND proprietary */
++
++#define PCI_BAR0_WIN 0x80 /* backplane addres space accessed by BAR0 */
++#define PCI_BAR1_WIN 0x84 /* backplane addres space accessed by BAR1 */
++#define PCI_SPROM_CONTROL 0x88 /* sprom property control */
++#define PCI_BAR1_CONTROL 0x8c /* BAR1 region burst control */
++#define PCI_INT_STATUS 0x90 /* PCI and other cores interrupts */
++#define PCI_INT_MASK 0x94 /* mask of PCI and other cores interrupts */
++#define PCI_TO_SB_MB 0x98 /* signal backplane interrupts */
++#define PCI_BACKPLANE_ADDR 0xA0 /* address an arbitrary location on the system backplane */
++#define PCI_BACKPLANE_DATA 0xA4 /* data at the location specified by above address register */
++#define PCI_GPIO_IN 0xb0 /* pci config space gpio input (>=rev3) */
++#define PCI_GPIO_OUT 0xb4 /* pci config space gpio output (>=rev3) */
++#define PCI_GPIO_OUTEN 0xb8 /* pci config space gpio output enable (>=rev3) */
++
++#define PCI_BAR0_SPROM_OFFSET (4 * 1024) /* bar0 + 4K accesses external sprom */
++#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) /* bar0 + 6K accesses pci core registers */
++
++/* PCI_INT_STATUS */
++#define PCI_SBIM_STATUS_SERR 0x4 /* backplane SBErr interrupt status */
++
++/* PCI_INT_MASK */
++#define PCI_SBIM_SHIFT 8 /* backplane core interrupt mask bits offset */
++#define PCI_SBIM_MASK 0xff00 /* backplane core interrupt mask */
++#define PCI_SBIM_MASK_SERR 0x4 /* backplane SBErr interrupt mask */
++
++/* PCI_SPROM_CONTROL */
++#define SPROM_BLANK 0x04 /* indicating a blank sprom */
++#define SPROM_WRITEEN 0x10 /* sprom write enable */
++#define SPROM_BOOTROM_WE 0x20 /* external bootrom write enable */
++
++#define SPROM_SIZE 256 /* sprom size in 16-bit */
++#define SPROM_CRC_RANGE 64 /* crc cover range in 16-bit */
++
++/* PCI_CFG_CMD_STAT */
++#define PCI_CFG_CMD_STAT_TA 0x08000000 /* target abort status */
++
++#endif
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/proto/ethernet.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/proto/ethernet.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/proto/ethernet.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/proto/ethernet.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,145 @@
++/*******************************************************************************
++ * $Id$
++ * Copyright 2001-2003, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * From FreeBSD 2.2.7: Fundamental constants relating to ethernet.
++ ******************************************************************************/
++
++#ifndef _NET_ETHERNET_H_ /* use native BSD ethernet.h when available */
++#define _NET_ETHERNET_H_
++
++#ifndef _TYPEDEFS_H_
++#include "typedefs.h"
++#endif
++
++#if defined(__GNUC__)
++#define PACKED __attribute__((packed))
++#else
++#define PACKED
++#endif
++
++/*
++ * The number of bytes in an ethernet (MAC) address.
++ */
++#define ETHER_ADDR_LEN 6
++
++/*
++ * The number of bytes in the type field.
++ */
++#define ETHER_TYPE_LEN 2
++
++/*
++ * The number of bytes in the trailing CRC field.
++ */
++#define ETHER_CRC_LEN 4
++
++/*
++ * The length of the combined header.
++ */
++#define ETHER_HDR_LEN (ETHER_ADDR_LEN*2+ETHER_TYPE_LEN)
++
++/*
++ * The minimum packet length.
++ */
++#define ETHER_MIN_LEN 64
++
++/*
++ * The minimum packet user data length.
++ */
++#define ETHER_MIN_DATA 46
++
++/*
++ * The maximum packet length.
++ */
++#define ETHER_MAX_LEN 1518
++
++/*
++ * The maximum packet user data length.
++ */
++#define ETHER_MAX_DATA 1500
++
++/*
++ * Used to uniquely identify a 802.1q VLAN-tagged header.
++ */
++#define VLAN_TAG 0x8100
++
++/*
++ * Located after dest & src address in ether header.
++ */
++#define VLAN_FIELDS_OFFSET (ETHER_ADDR_LEN * 2)
++
++/*
++ * 4 bytes of vlan field info.
++ */
++#define VLAN_FIELDS_SIZE 4
++
++/* location of pri bits in 16-bit vlan fields */
++#define VLAN_PRI_SHIFT 13
++
++/* 3 bits of priority */
++#define VLAN_PRI_MASK 7
++
++/* 802.1X ethertype */
++#define ETHER_TYPE_802_1X 0x888e
++
++/*
++ * A macro to validate a length with
++ */
++#define ETHER_IS_VALID_LEN(foo) \
++ ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN)
++
++
++#ifndef __INCif_etherh /* Quick and ugly hack for VxWorks */
++/*
++ * Structure of a 10Mb/s Ethernet header.
++ */
++struct ether_header {
++ uint8 ether_dhost[ETHER_ADDR_LEN];
++ uint8 ether_shost[ETHER_ADDR_LEN];
++ uint16 ether_type;
++} PACKED ;
++
++/*
++ * Structure of a 48-bit Ethernet address.
++ */
++struct ether_addr {
++ uint8 octet[ETHER_ADDR_LEN];
++} PACKED ;
++#endif
++
++/*
++ * Takes a pointer, returns true if a 48-bit multicast address
++ * (including broadcast, since it is all ones)
++ */
++#define ETHER_ISMULTI(ea) (((uint8 *)(ea))[0] & 1)
++
++/*
++ * Takes a pointer, returns true if a 48-bit broadcast (all ones)
++ */
++#define ETHER_ISBCAST(ea) ((((uint8 *)(ea))[0] & \
++ ((uint8 *)(ea))[1] & \
++ ((uint8 *)(ea))[2] & \
++ ((uint8 *)(ea))[3] & \
++ ((uint8 *)(ea))[4] & \
++ ((uint8 *)(ea))[5]) == 0xff)
++
++static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}};
++
++/*
++ * Takes a pointer, returns true if a 48-bit null address (all zeros)
++ */
++#define ETHER_ISNULLADDR(ea) ((((uint8 *)(ea))[0] | \
++ ((uint8 *)(ea))[1] | \
++ ((uint8 *)(ea))[2] | \
++ ((uint8 *)(ea))[3] | \
++ ((uint8 *)(ea))[4] | \
++ ((uint8 *)(ea))[5]) == 0)
++
++#undef PACKED
++
++#endif /* _NET_ETHERNET_H_ */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/s5.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/s5.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/s5.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/s5.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,103 @@
++#ifndef _S5_H_
++#define _S5_H_
++/*
++ * Copyright 2003, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * Broadcom Sentry5 (S5) BCM5365, 53xx, BCM58xx SOC Internal Core
++ * and MIPS3301 (R4K) System Address Space
++ *
++ * 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, located in the file
++ * LICENSE.
++ *
++ * $Id: s5.h,v 1.3 2003/06/10 18:54:51 jfd Exp $
++ *
++ */
++
++/* BCM5365 Address map */
++#define KSEG1ADDR(x) ( (x) | 0xa0000000)
++#define BCM5365_SDRAM 0x00000000 /* 0-128MB Physical SDRAM */
++#define BCM5365_PCI_MEM 0x08000000 /* Host Mode PCI mem space (64MB) */
++#define BCM5365_PCI_CFG 0x0c000000 /* Host Mode PCI cfg space (64MB) */
++#define BCM5365_PCI_DMA 0x40000000 /* Client Mode PCI mem space (1GB)*/
++#define BCM5365_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */
++#define BCM5365_ENUM 0x18000000 /* Beginning of core enum space */
++
++/* BCM5365 Core register space */
++#define BCM5365_REG_CHIPC 0x18000000 /* Chipcommon registers */
++#define BCM5365_REG_EMAC0 0x18001000 /* Ethernet MAC0 core registers */
++#define BCM5365_REG_IPSEC 0x18002000 /* BCM582x CryptoCore registers */
++#define BCM5365_REG_USB 0x18003000 /* USB core registers */
++#define BCM5365_REG_PCI 0x18004000 /* PCI core registers */
++#define BCM5365_REG_MIPS33 0x18005000 /* MIPS core registers */
++#define BCM5365_REG_MEMC 0x18006000 /* MEMC core registers */
++#define BCM5365_REG_UARTS (BCM5365_REG_CHIPC + 0x300) /* UART regs */
++#define BCM5365_EJTAG 0xff200000 /* MIPS EJTAG space (2M) */
++
++/* COM Ports 1/2 */
++#define BCM5365_UART (BCM5365_REG_UARTS)
++#define BCM5365_UART_COM2 (BCM5365_REG_UARTS + 0x00000100)
++
++/* Registers common to MIPS33 Core used in 5365 */
++#define MIPS33_FLASH_REGION 0x1fc00000 /* Boot FLASH Region */
++#define MIPS33_EXTIF_REGION 0x1a000000 /* Chipcommon EXTIF region*/
++#define BCM5365_EXTIF 0x1b000000 /* MISC_CS */
++#define MIPS33_FLASH_REGION_AUX 0x1c000000 /* FLASH Region 2*/
++
++/* Internal Core Sonics Backplane Devices */
++#define INTERNAL_UART_COM1 BCM5365_UART
++#define INTERNAL_UART_COM2 BCM5365_UART_COM2
++#define SB_REG_CHIPC BCM5365_REG_CHIPC
++#define SB_REG_ENET0 BCM5365_REG_EMAC0
++#define SB_REG_IPSEC BCM5365_REG_IPSEC
++#define SB_REG_USB BCM5365_REG_USB
++#define SB_REG_PCI BCM5365_REG_PCI
++#define SB_REG_MIPS BCM5365_REG_MIPS33
++#define SB_REG_MEMC BCM5365_REG_MEMC
++#define SB_REG_MEMC_OFF 0x6000
++#define SB_EXTIF_SPACE MIPS33_EXTIF_REGION
++#define SB_FLASH_SPACE MIPS33_FLASH_REGION
++
++/*
++ * XXX
++ * 5365-specific backplane interrupt flag numbers. This should be done
++ * dynamically instead.
++ */
++#define SBFLAG_PCI 0
++#define SBFLAG_ENET0 1
++#define SBFLAG_ILINE20 2
++#define SBFLAG_CODEC 3
++#define SBFLAG_USB 4
++#define SBFLAG_EXTIF 5
++#define SBFLAG_ENET1 6
++
++/* BCM95365 Local Bus devices */
++#define BCM95365K_RESET_ADDR BCM5365_EXTIF
++#define BCM95365K_BOARDID_ADDR (BCM5365_EXTIF | 0x4000)
++#define BCM95365K_DOC_ADDR (BCM5365_EXTIF | 0x6000)
++#define BCM95365K_LED_ADDR (BCM5365_EXTIF | 0xc000)
++#define BCM95365K_TOD_REG_BASE (BCM95365K_NVRAM_ADDR | 0x1ff0)
++#define BCM95365K_NVRAM_ADDR (BCM5365_EXTIF | 0xe000)
++#define BCM95365K_NVRAM_SIZE 0x1ff0 /* 8K NVRAM : DS1743/STM48txx*/
++
++/* Write to DLR2416 VFD Display character RAM */
++#define LED_REG(x) \
++ (*(volatile unsigned char *) (KSEG1ADDR(BCM95365K_LED_ADDR) + (x)))
++
++#ifdef CONFIG_VSIM
++#define BCM5365_TRACE(trval) do { *((int *)0xa0002ff8) = (trval); \
++ } while (0)
++#else
++#define BCM5365_TRACE(trval) do { *((unsigned char *)\
++ KSEG1ADDR(BCM5365K_LED_ADDR)) = (trval); \
++ *((int *)0xa0002ff8) = (trval); } while (0)
++#endif
++
++/* BCM9536R Local Bus devices */
++#define BCM95365R_DOC_ADDR BCM5365_EXTIF
++
++
++
++#endif /*!_S5_H_ */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/sbchipc.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbchipc.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/sbchipc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbchipc.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,440 @@
++/*
++ * SiliconBackplane Chipcommon core hardware definitions.
++ *
++ * The chipcommon core provides chip identification, SB control,
++ * jtag, 0/1/2 uarts, clock frequency control, a watchdog interrupt timer,
++ * gpio interface, extbus, and support for serial and parallel flashes.
++ *
++ * $Id$
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ */
++
++#ifndef _SBCHIPC_H
++#define _SBCHIPC_H
++
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++/* cpp contortions to concatenate w/arg prescan */
++#ifndef PAD
++#define _PADLINE(line) pad ## line
++#define _XSTR(line) _PADLINE(line)
++#define PAD _XSTR(__LINE__)
++#endif /* PAD */
++
++typedef volatile struct {
++ uint32 chipid; /* 0x0 */
++ uint32 capabilities;
++ uint32 corecontrol; /* corerev >= 1 */
++ uint32 bist;
++
++ /* OTP */
++ uint32 otpstatus; /* 0x10, corerev >= 10 */
++ uint32 otpcontrol;
++ uint32 otpprog;
++ uint32 PAD;
++
++ /* Interrupt control */
++ uint32 intstatus; /* 0x20 */
++ uint32 intmask;
++ uint32 chipcontrol; /* 0x28, rev >= 11 */
++ uint32 chipstatus; /* 0x2c, rev >= 11 */
++
++ /* Jtag Master */
++ uint32 jtagcmd; /* 0x30, rev >= 10 */
++ uint32 jtagir;
++ uint32 jtagdr;
++ uint32 jtagctrl;
++
++ /* serial flash interface registers */
++ uint32 flashcontrol; /* 0x40 */
++ uint32 flashaddress;
++ uint32 flashdata;
++ uint32 PAD[1];
++
++ /* Silicon backplane configuration broadcast control */
++ uint32 broadcastaddress; /* 0x50 */
++ uint32 broadcastdata;
++ uint32 PAD[2];
++
++ /* gpio - cleared only by power-on-reset */
++ uint32 gpioin; /* 0x60 */
++ uint32 gpioout;
++ uint32 gpioouten;
++ uint32 gpiocontrol;
++ uint32 gpiointpolarity;
++ uint32 gpiointmask;
++ uint32 PAD[2];
++
++ /* Watchdog timer */
++ uint32 watchdog; /* 0x80 */
++ uint32 PAD[1];
++
++ /*GPIO based LED powersave registers corerev >= 16*/
++ uint32 gpiotimerval; /*0x88 */
++ uint32 gpiotimeroutmask;
++
++ /* clock control */
++ uint32 clockcontrol_n; /* 0x90 */
++ uint32 clockcontrol_sb; /* aka m0 */
++ uint32 clockcontrol_pci; /* aka m1 */
++ uint32 clockcontrol_m2; /* mii/uart/mipsref */
++ uint32 clockcontrol_mips; /* aka m3 */
++ uint32 clkdiv; /* corerev >= 3 */
++ uint32 PAD[2];
++
++ /* pll delay registers (corerev >= 4) */
++ uint32 pll_on_delay; /* 0xb0 */
++ uint32 fref_sel_delay;
++ uint32 slow_clk_ctl; /* 5 < corerev < 10 */
++ uint32 PAD[1];
++
++ /* Instaclock registers (corerev >= 10) */
++ uint32 system_clk_ctl; /* 0xc0 */
++ uint32 clkstatestretch;
++ uint32 PAD[14];
++
++ /* ExtBus control registers (corerev >= 3) */
++ uint32 pcmcia_config; /* 0x100 */
++ uint32 pcmcia_memwait;
++ uint32 pcmcia_attrwait;
++ uint32 pcmcia_iowait;
++ uint32 ide_config;
++ uint32 ide_memwait;
++ uint32 ide_attrwait;
++ uint32 ide_iowait;
++ uint32 prog_config;
++ uint32 prog_waitcount;
++ uint32 flash_config;
++ uint32 flash_waitcount;
++ uint32 PAD[116];
++
++ /* uarts */
++ uint8 uart0data; /* 0x300 */
++ uint8 uart0imr;
++ uint8 uart0fcr;
++ uint8 uart0lcr;
++ uint8 uart0mcr;
++ uint8 uart0lsr;
++ uint8 uart0msr;
++ uint8 uart0scratch;
++ uint8 PAD[248]; /* corerev >= 1 */
++
++ uint8 uart1data; /* 0x400 */
++ uint8 uart1imr;
++ uint8 uart1fcr;
++ uint8 uart1lcr;
++ uint8 uart1mcr;
++ uint8 uart1lsr;
++ uint8 uart1msr;
++ uint8 uart1scratch;
++} chipcregs_t;
++
++#endif /* _LANGUAGE_ASSEMBLY */
++
++#define CC_CHIPID 0
++#define CC_CAPABILITIES 4
++#define CC_JTAGCMD 0x30
++#define CC_JTAGIR 0x34
++#define CC_JTAGDR 0x38
++#define CC_JTAGCTRL 0x3c
++#define CC_WATCHDOG 0x80
++#define CC_CLKC_N 0x90
++#define CC_CLKC_M0 0x94
++#define CC_CLKC_M1 0x98
++#define CC_CLKC_M2 0x9c
++#define CC_CLKC_M3 0xa0
++#define CC_CLKDIV 0xa4
++#define CC_SYS_CLK_CTL 0xc0
++#define CC_OTP 0x800
++
++/* chipid */
++#define CID_ID_MASK 0x0000ffff /* Chip Id mask */
++#define CID_REV_MASK 0x000f0000 /* Chip Revision mask */
++#define CID_REV_SHIFT 16 /* Chip Revision shift */
++#define CID_PKG_MASK 0x00f00000 /* Package Option mask */
++#define CID_PKG_SHIFT 20 /* Package Option shift */
++#define CID_CC_MASK 0x0f000000 /* CoreCount (corerev >= 4) */
++#define CID_CC_SHIFT 24
++
++/* capabilities */
++#define CAP_UARTS_MASK 0x00000003 /* Number of uarts */
++#define CAP_MIPSEB 0x00000004 /* MIPS is in big-endian mode */
++#define CAP_UCLKSEL 0x00000018 /* UARTs clock select */
++#define CAP_UINTCLK 0x00000008 /* UARTs are driven by internal divided clock */
++#define CAP_UARTGPIO 0x00000020 /* UARTs own Gpio's 15:12 */
++#define CAP_EXTBUS 0x00000040 /* External bus present */
++#define CAP_FLASH_MASK 0x00000700 /* Type of flash */
++#define CAP_PLL_MASK 0x00038000 /* Type of PLL */
++#define CAP_PWR_CTL 0x00040000 /* Power control */
++#define CAP_OTPSIZE 0x00380000 /* OTP Size (0 = none) */
++#define CAP_OTPSIZE_SHIFT 19 /* OTP Size shift */
++#define CAP_OTPSIZE_BASE 5 /* OTP Size base */
++#define CAP_JTAGP 0x00400000 /* JTAG Master Present */
++#define CAP_ROM 0x00800000 /* Internal boot rom active */
++
++/* PLL type */
++#define PLL_NONE 0x00000000
++#define PLL_TYPE1 0x00010000 /* 48Mhz base, 3 dividers */
++#define PLL_TYPE2 0x00020000 /* 48Mhz, 4 dividers */
++#define PLL_TYPE3 0x00030000 /* 25Mhz, 2 dividers */
++#define PLL_TYPE4 0x00008000 /* 48Mhz, 4 dividers */
++#define PLL_TYPE5 0x00018000 /* 25Mhz, 4 dividers */
++#define PLL_TYPE6 0x00028000 /* 100/200 or 120/240 only */
++#define PLL_TYPE7 0x00038000 /* 25Mhz, 4 dividers */
++
++/* corecontrol */
++#define CC_UARTCLKO 0x00000001 /* Drive UART with internal clock */
++#define CC_SE 0x00000002 /* sync clk out enable (corerev >= 3) */
++
++/* Fields in the otpstatus register */
++#define OTPS_PROGFAIL 0x80000000
++#define OTPS_PROTECT 0x00000007
++#define OTPS_HW_PROTECT 0x00000001
++#define OTPS_SW_PROTECT 0x00000002
++#define OTPS_CID_PROTECT 0x00000004
++
++/* Fields in the otpcontrol register */
++#define OTPC_RECWAIT 0xff000000
++#define OTPC_PROGWAIT 0x00ffff00
++#define OTPC_PRW_SHIFT 8
++#define OTPC_MAXFAIL 0x00000038
++#define OTPC_VSEL 0x00000006
++#define OTPC_SELVL 0x00000001
++
++/* Fields in otpprog */
++#define OTPP_COL_MASK 0x000000ff
++#define OTPP_ROW_MASK 0x0000ff00
++#define OTPP_ROW_SHIFT 8
++#define OTPP_READERR 0x10000000
++#define OTPP_VALUE 0x20000000
++#define OTPP_VALUE_SHIFT 29
++#define OTPP_READ 0x40000000
++#define OTPP_START 0x80000000
++#define OTPP_BUSY 0x80000000
++
++/* jtagcmd */
++#define JCMD_START 0x80000000
++#define JCMD_BUSY 0x80000000
++#define JCMD_PAUSE 0x40000000
++#define JCMD0_ACC_MASK 0x0000f000
++#define JCMD0_ACC_IRDR 0x00000000
++#define JCMD0_ACC_DR 0x00001000
++#define JCMD0_ACC_IR 0x00002000
++#define JCMD0_ACC_RESET 0x00003000
++#define JCMD0_ACC_IRPDR 0x00004000
++#define JCMD0_ACC_PDR 0x00005000
++#define JCMD0_IRW_MASK 0x00000f00
++#define JCMD_ACC_MASK 0x000f0000 /* Changes for corerev 11 */
++#define JCMD_ACC_IRDR 0x00000000
++#define JCMD_ACC_DR 0x00010000
++#define JCMD_ACC_IR 0x00020000
++#define JCMD_ACC_RESET 0x00030000
++#define JCMD_ACC_IRPDR 0x00040000
++#define JCMD_ACC_PDR 0x00050000
++#define JCMD_IRW_MASK 0x00001f00
++#define JCMD_IRW_SHIFT 8
++#define JCMD_DRW_MASK 0x0000003f
++
++/* jtagctrl */
++#define JCTRL_FORCE_CLK 4 /* Force clock */
++#define JCTRL_EXT_EN 2 /* Enable external targets */
++#define JCTRL_EN 1 /* Enable Jtag master */
++
++/* Fields in clkdiv */
++#define CLKD_SFLASH 0x0f000000
++#define CLKD_SFLASH_SHIFT 24
++#define CLKD_OTP 0x000f0000
++#define CLKD_OTP_SHIFT 16
++#define CLKD_JTAG 0x00000f00
++#define CLKD_JTAG_SHIFT 8
++#define CLKD_UART 0x000000ff
++
++/* intstatus/intmask */
++#define CI_GPIO 0x00000001 /* gpio intr */
++#define CI_EI 0x00000002 /* ro: ext intr pin (corerev >= 3) */
++#define CI_WDRESET 0x80000000 /* watchdog reset occurred */
++
++/* slow_clk_ctl */
++#define SCC_SS_MASK 0x00000007 /* slow clock source mask */
++#define SCC_SS_LPO 0x00000000 /* source of slow clock is LPO */
++#define SCC_SS_XTAL 0x00000001 /* source of slow clock is crystal */
++#define SCC_SS_PCI 0x00000002 /* source of slow clock is PCI */
++#define SCC_LF 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */
++#define SCC_LP 0x00000400 /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */
++#define SCC_FS 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */
++#define SCC_IP 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors PLL clock disable requests from core */
++#define SCC_XC 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't disable crystal when appropriate */
++#define SCC_XP 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */
++#define SCC_CD_MASK 0xffff0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */
++#define SCC_CD_SHIFT 16
++
++/* system_clk_ctl */
++#define SYCC_IE 0x00000001 /* ILPen: Enable Idle Low Power */
++#define SYCC_AE 0x00000002 /* ALPen: Enable Active Low Power */
++#define SYCC_FP 0x00000004 /* ForcePLLOn */
++#define SYCC_AR 0x00000008 /* Force ALP (or HT if ALPen is not set */
++#define SYCC_HR 0x00000010 /* Force HT */
++#define SYCC_CD_MASK 0xffff0000 /* ClkDiv (ILP = 1/(4+divisor)) */
++#define SYCC_CD_SHIFT 16
++
++/* gpiotimerval*/
++#define GPIO_ONTIME_SHIFT 16
++
++/* clockcontrol_n */
++#define CN_N1_MASK 0x3f /* n1 control */
++#define CN_N2_MASK 0x3f00 /* n2 control */
++#define CN_N2_SHIFT 8
++#define CN_PLLC_MASK 0xf0000 /* pll control */
++#define CN_PLLC_SHIFT 16
++
++/* clockcontrol_sb/pci/uart */
++#define CC_M1_MASK 0x3f /* m1 control */
++#define CC_M2_MASK 0x3f00 /* m2 control */
++#define CC_M2_SHIFT 8
++#define CC_M3_MASK 0x3f0000 /* m3 control */
++#define CC_M3_SHIFT 16
++#define CC_MC_MASK 0x1f000000 /* mux control */
++#define CC_MC_SHIFT 24
++
++/* N3M Clock control magic field values */
++#define CC_F6_2 0x02 /* A factor of 2 in */
++#define CC_F6_3 0x03 /* 6-bit fields like */
++#define CC_F6_4 0x05 /* N1, M1 or M3 */
++#define CC_F6_5 0x09
++#define CC_F6_6 0x11
++#define CC_F6_7 0x21
++
++#define CC_F5_BIAS 5 /* 5-bit fields get this added */
++
++#define CC_MC_BYPASS 0x08
++#define CC_MC_M1 0x04
++#define CC_MC_M1M2 0x02
++#define CC_MC_M1M2M3 0x01
++#define CC_MC_M1M3 0x11
++
++/* Type 2 Clock control magic field values */
++#define CC_T2_BIAS 2 /* n1, n2, m1 & m3 bias */
++#define CC_T2M2_BIAS 3 /* m2 bias */
++
++#define CC_T2MC_M1BYP 1
++#define CC_T2MC_M2BYP 2
++#define CC_T2MC_M3BYP 4
++
++/* Type 6 Clock control magic field values */
++#define CC_T6_MMASK 1 /* bits of interest in m */
++#define CC_T6_M0 120000000 /* sb clock for m = 0 */
++#define CC_T6_M1 100000000 /* sb clock for m = 1 */
++#define SB2MIPS_T6(sb) (2 * (sb))
++
++/* Common clock base */
++#define CC_CLOCK_BASE1 24000000 /* Half the clock freq */
++#define CC_CLOCK_BASE2 12500000 /* Alternate crystal on some PLL's */
++
++/* Clock control values for 200Mhz in 5350 */
++#define CLKC_5350_N 0x0311
++#define CLKC_5350_M 0x04020009
++
++/* Flash types in the chipcommon capabilities register */
++#define FLASH_NONE 0x000 /* No flash */
++#define SFLASH_ST 0x100 /* ST serial flash */
++#define SFLASH_AT 0x200 /* Atmel serial flash */
++#define PFLASH 0x700 /* Parallel flash */
++
++/* Bits in the config registers */
++#define CC_CFG_EN 0x0001 /* Enable */
++#define CC_CFG_EM_MASK 0x000e /* Extif Mode */
++#define CC_CFG_EM_ASYNC 0x0002 /* Async/Parallel flash */
++#define CC_CFG_EM_SYNC 0x0004 /* Synchronous */
++#define CC_CFG_EM_PCMCIA 0x0008 /* PCMCIA */
++#define CC_CFG_EM_IDE 0x000a /* IDE */
++#define CC_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */
++#define CC_CFG_CD_MASK 0x0060 /* Sync: Clock divisor */
++#define CC_CFG_CE 0x0080 /* Sync: Clock enable */
++#define CC_CFG_SB 0x0100 /* Sync: Size/Bytestrobe */
++
++/* Start/busy bit in flashcontrol */
++#define SFLASH_START 0x80000000
++#define SFLASH_BUSY SFLASH_START
++
++/* flashcontrol opcodes for ST flashes */
++#define SFLASH_ST_WREN 0x0006 /* Write Enable */
++#define SFLASH_ST_WRDIS 0x0004 /* Write Disable */
++#define SFLASH_ST_RDSR 0x0105 /* Read Status Register */
++#define SFLASH_ST_WRSR 0x0101 /* Write Status Register */
++#define SFLASH_ST_READ 0x0303 /* Read Data Bytes */
++#define SFLASH_ST_PP 0x0302 /* Page Program */
++#define SFLASH_ST_SE 0x02d8 /* Sector Erase */
++#define SFLASH_ST_BE 0x00c7 /* Bulk Erase */
++#define SFLASH_ST_DP 0x00b9 /* Deep Power-down */
++#define SFLASH_ST_RES 0x03ab /* Read Electronic Signature */
++
++/* Status register bits for ST flashes */
++#define SFLASH_ST_WIP 0x01 /* Write In Progress */
++#define SFLASH_ST_WEL 0x02 /* Write Enable Latch */
++#define SFLASH_ST_BP_MASK 0x1c /* Block Protect */
++#define SFLASH_ST_BP_SHIFT 2
++#define SFLASH_ST_SRWD 0x80 /* Status Register Write Disable */
++
++/* flashcontrol opcodes for Atmel flashes */
++#define SFLASH_AT_READ 0x07e8
++#define SFLASH_AT_PAGE_READ 0x07d2
++#define SFLASH_AT_BUF1_READ
++#define SFLASH_AT_BUF2_READ
++#define SFLASH_AT_STATUS 0x01d7
++#define SFLASH_AT_BUF1_WRITE 0x0384
++#define SFLASH_AT_BUF2_WRITE 0x0387
++#define SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283
++#define SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286
++#define SFLASH_AT_BUF1_PROGRAM 0x0288
++#define SFLASH_AT_BUF2_PROGRAM 0x0289
++#define SFLASH_AT_PAGE_ERASE 0x0281
++#define SFLASH_AT_BLOCK_ERASE 0x0250
++#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382
++#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385
++#define SFLASH_AT_BUF1_LOAD 0x0253
++#define SFLASH_AT_BUF2_LOAD 0x0255
++#define SFLASH_AT_BUF1_COMPARE 0x0260
++#define SFLASH_AT_BUF2_COMPARE 0x0261
++#define SFLASH_AT_BUF1_REPROGRAM 0x0258
++#define SFLASH_AT_BUF2_REPROGRAM 0x0259
++
++/* Status register bits for Atmel flashes */
++#define SFLASH_AT_READY 0x80
++#define SFLASH_AT_MISMATCH 0x40
++#define SFLASH_AT_ID_MASK 0x38
++#define SFLASH_AT_ID_SHIFT 3
++
++/* OTP regions */
++#define OTP_HW_REGION OTPS_HW_PROTECT
++#define OTP_SW_REGION OTPS_SW_PROTECT
++#define OTP_CID_REGION OTPS_CID_PROTECT
++
++/* OTP regions (Byte offsets from otp size) */
++#define OTP_SWLIM_OFF (-8)
++#define OTP_CIDBASE_OFF 0
++#define OTP_CIDLIM_OFF 8
++
++/* Predefined OTP words (Word offset from otp size) */
++#define OTP_BOUNDARY_OFF (-4)
++#define OTP_HWSIGN_OFF (-3)
++#define OTP_SWSIGN_OFF (-2)
++#define OTP_CIDSIGN_OFF (-1)
++
++#define OTP_CID_OFF 0
++#define OTP_PKG_OFF 1
++#define OTP_FID_OFF 2
++#define OTP_RSV_OFF 3
++#define OTP_LIM_OFF 4
++
++#define OTP_SIGNATURE 0x578a
++#define OTP_MAGIC 0x4e56
++
++#endif /* _SBCHIPC_H */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/sbconfig.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbconfig.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/sbconfig.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbconfig.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,342 @@
++/*
++ * Broadcom SiliconBackplane hardware register definitions.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id$
++ */
++
++#ifndef _SBCONFIG_H
++#define _SBCONFIG_H
++
++/* cpp contortions to concatenate w/arg prescan */
++#ifndef PAD
++#define _PADLINE(line) pad ## line
++#define _XSTR(line) _PADLINE(line)
++#define PAD _XSTR(__LINE__)
++#endif
++
++/*
++ * SiliconBackplane Address Map.
++ * All regions may not exist on all chips.
++ */
++#define SB_SDRAM_BASE 0x00000000 /* Physical SDRAM */
++#define SB_PCI_MEM 0x08000000 /* Host Mode sb2pcitranslation0 (64 MB) */
++#define SB_PCI_CFG 0x0c000000 /* Host Mode sb2pcitranslation1 (64 MB) */
++#define SB_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */
++#define SB_ENUM_BASE 0x18000000 /* Enumeration space base */
++#define SB_ENUM_LIM 0x18010000 /* Enumeration space limit */
++
++#define SB_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */
++#define SB_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */
++
++#define SB_EXTIF_BASE 0x1f000000 /* External Interface region base address */
++#define SB_FLASH1 0x1fc00000 /* Flash Region 1 */
++#define SB_FLASH1_SZ 0x00400000 /* Size of Flash Region 1 */
++
++#define SB_PCI_DMA 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */
++#define SB_PCI_DMA_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */
++#define SB_PCIE_DMA_L32 0x00000000 /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), low 32 bits */
++#define SB_PCIE_DMA_H32 0x80000000 /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), high 32 bits */
++#define SB_EUART (SB_EXTIF_BASE + 0x00800000)
++#define SB_LED (SB_EXTIF_BASE + 0x00900000)
++
++
++/* enumeration space related defs */
++#define SB_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */
++#define SB_MAXCORES ((SB_ENUM_LIM - SB_ENUM_BASE)/SB_CORE_SIZE)
++#define SBCONFIGOFF 0xf00 /* core sbconfig regs are top 256bytes of regs */
++#define SBCONFIGSIZE 256 /* sizeof (sbconfig_t) */
++
++/* mips address */
++#define SB_EJTAG 0xff200000 /* MIPS EJTAG space (2M) */
++
++/*
++ * Sonics Configuration Space Registers.
++ */
++#define SBIPSFLAG 0x08
++#define SBTPSFLAG 0x18
++#define SBTMERRLOGA 0x48 /* sonics >= 2.3 */
++#define SBTMERRLOG 0x50 /* sonics >= 2.3 */
++#define SBADMATCH3 0x60
++#define SBADMATCH2 0x68
++#define SBADMATCH1 0x70
++#define SBIMSTATE 0x90
++#define SBINTVEC 0x94
++#define SBTMSTATELOW 0x98
++#define SBTMSTATEHIGH 0x9c
++#define SBBWA0 0xa0
++#define SBIMCONFIGLOW 0xa8
++#define SBIMCONFIGHIGH 0xac
++#define SBADMATCH0 0xb0
++#define SBTMCONFIGLOW 0xb8
++#define SBTMCONFIGHIGH 0xbc
++#define SBBCONFIG 0xc0
++#define SBBSTATE 0xc8
++#define SBACTCNFG 0xd8
++#define SBFLAGST 0xe8
++#define SBIDLOW 0xf8
++#define SBIDHIGH 0xfc
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++typedef volatile struct _sbconfig {
++ uint32 PAD[2];
++ uint32 sbipsflag; /* initiator port ocp slave flag */
++ uint32 PAD[3];
++ uint32 sbtpsflag; /* target port ocp slave flag */
++ uint32 PAD[11];
++ uint32 sbtmerrloga; /* (sonics >= 2.3) */
++ uint32 PAD;
++ uint32 sbtmerrlog; /* (sonics >= 2.3) */
++ uint32 PAD[3];
++ uint32 sbadmatch3; /* address match3 */
++ uint32 PAD;
++ uint32 sbadmatch2; /* address match2 */
++ uint32 PAD;
++ uint32 sbadmatch1; /* address match1 */
++ uint32 PAD[7];
++ uint32 sbimstate; /* initiator agent state */
++ uint32 sbintvec; /* interrupt mask */
++ uint32 sbtmstatelow; /* target state */
++ uint32 sbtmstatehigh; /* target state */
++ uint32 sbbwa0; /* bandwidth allocation table0 */
++ uint32 PAD;
++ uint32 sbimconfiglow; /* initiator configuration */
++ uint32 sbimconfighigh; /* initiator configuration */
++ uint32 sbadmatch0; /* address match0 */
++ uint32 PAD;
++ uint32 sbtmconfiglow; /* target configuration */
++ uint32 sbtmconfighigh; /* target configuration */
++ uint32 sbbconfig; /* broadcast configuration */
++ uint32 PAD;
++ uint32 sbbstate; /* broadcast state */
++ uint32 PAD[3];
++ uint32 sbactcnfg; /* activate configuration */
++ uint32 PAD[3];
++ uint32 sbflagst; /* current sbflags */
++ uint32 PAD[3];
++ uint32 sbidlow; /* identification */
++ uint32 sbidhigh; /* identification */
++} sbconfig_t;
++
++#endif /* _LANGUAGE_ASSEMBLY */
++
++/* sbipsflag */
++#define SBIPS_INT1_MASK 0x3f /* which sbflags get routed to mips interrupt 1 */
++#define SBIPS_INT1_SHIFT 0
++#define SBIPS_INT2_MASK 0x3f00 /* which sbflags get routed to mips interrupt 2 */
++#define SBIPS_INT2_SHIFT 8
++#define SBIPS_INT3_MASK 0x3f0000 /* which sbflags get routed to mips interrupt 3 */
++#define SBIPS_INT3_SHIFT 16
++#define SBIPS_INT4_MASK 0x3f000000 /* which sbflags get routed to mips interrupt 4 */
++#define SBIPS_INT4_SHIFT 24
++
++/* sbtpsflag */
++#define SBTPS_NUM0_MASK 0x3f /* interrupt sbFlag # generated by this core */
++#define SBTPS_F0EN0 0x40 /* interrupt is always sent on the backplane */
++
++/* sbtmerrlog */
++#define SBTMEL_CM 0x00000007 /* command */
++#define SBTMEL_CI 0x0000ff00 /* connection id */
++#define SBTMEL_EC 0x0f000000 /* error code */
++#define SBTMEL_ME 0x80000000 /* multiple error */
++
++/* sbimstate */
++#define SBIM_PC 0xf /* pipecount */
++#define SBIM_AP_MASK 0x30 /* arbitration policy */
++#define SBIM_AP_BOTH 0x00 /* use both timeslaces and token */
++#define SBIM_AP_TS 0x10 /* use timesliaces only */
++#define SBIM_AP_TK 0x20 /* use token only */
++#define SBIM_AP_RSV 0x30 /* reserved */
++#define SBIM_IBE 0x20000 /* inbanderror */
++#define SBIM_TO 0x40000 /* timeout */
++#define SBIM_BY 0x01800000 /* busy (sonics >= 2.3) */
++#define SBIM_RJ 0x02000000 /* reject (sonics >= 2.3) */
++
++/* sbtmstatelow */
++#define SBTML_RESET 0x1 /* reset */
++#define SBTML_REJ_MASK 0x6 /* reject */
++#define SBTML_REJ_SHIFT 1
++#define SBTML_CLK 0x10000 /* clock enable */
++#define SBTML_FGC 0x20000 /* force gated clocks on */
++#define SBTML_FL_MASK 0x3ffc0000 /* core-specific flags */
++#define SBTML_PE 0x40000000 /* pme enable */
++#define SBTML_BE 0x80000000 /* bist enable */
++
++/* sbtmstatehigh */
++#define SBTMH_SERR 0x1 /* serror */
++#define SBTMH_INT 0x2 /* interrupt */
++#define SBTMH_BUSY 0x4 /* busy */
++#define SBTMH_TO 0x00000020 /* timeout (sonics >= 2.3) */
++#define SBTMH_FL_MASK 0x1fff0000 /* core-specific flags */
++#define SBTMH_DMA64 0x10000000 /* supports DMA with 64-bit addresses */
++#define SBTMH_GCR 0x20000000 /* gated clock request */
++#define SBTMH_BISTF 0x40000000 /* bist failed */
++#define SBTMH_BISTD 0x80000000 /* bist done */
++
++
++/* sbbwa0 */
++#define SBBWA_TAB0_MASK 0xffff /* lookup table 0 */
++#define SBBWA_TAB1_MASK 0xffff /* lookup table 1 */
++#define SBBWA_TAB1_SHIFT 16
++
++/* sbimconfiglow */
++#define SBIMCL_STO_MASK 0x7 /* service timeout */
++#define SBIMCL_RTO_MASK 0x70 /* request timeout */
++#define SBIMCL_RTO_SHIFT 4
++#define SBIMCL_CID_MASK 0xff0000 /* connection id */
++#define SBIMCL_CID_SHIFT 16
++
++/* sbimconfighigh */
++#define SBIMCH_IEM_MASK 0xc /* inband error mode */
++#define SBIMCH_TEM_MASK 0x30 /* timeout error mode */
++#define SBIMCH_TEM_SHIFT 4
++#define SBIMCH_BEM_MASK 0xc0 /* bus error mode */
++#define SBIMCH_BEM_SHIFT 6
++
++/* sbadmatch0 */
++#define SBAM_TYPE_MASK 0x3 /* address type */
++#define SBAM_AD64 0x4 /* reserved */
++#define SBAM_ADINT0_MASK 0xf8 /* type0 size */
++#define SBAM_ADINT0_SHIFT 3
++#define SBAM_ADINT1_MASK 0x1f8 /* type1 size */
++#define SBAM_ADINT1_SHIFT 3
++#define SBAM_ADINT2_MASK 0x1f8 /* type2 size */
++#define SBAM_ADINT2_SHIFT 3
++#define SBAM_ADEN 0x400 /* enable */
++#define SBAM_ADNEG 0x800 /* negative decode */
++#define SBAM_BASE0_MASK 0xffffff00 /* type0 base address */
++#define SBAM_BASE0_SHIFT 8
++#define SBAM_BASE1_MASK 0xfffff000 /* type1 base address for the core */
++#define SBAM_BASE1_SHIFT 12
++#define SBAM_BASE2_MASK 0xffff0000 /* type2 base address for the core */
++#define SBAM_BASE2_SHIFT 16
++
++/* sbtmconfiglow */
++#define SBTMCL_CD_MASK 0xff /* clock divide */
++#define SBTMCL_CO_MASK 0xf800 /* clock offset */
++#define SBTMCL_CO_SHIFT 11
++#define SBTMCL_IF_MASK 0xfc0000 /* interrupt flags */
++#define SBTMCL_IF_SHIFT 18
++#define SBTMCL_IM_MASK 0x3000000 /* interrupt mode */
++#define SBTMCL_IM_SHIFT 24
++
++/* sbtmconfighigh */
++#define SBTMCH_BM_MASK 0x3 /* busy mode */
++#define SBTMCH_RM_MASK 0x3 /* retry mode */
++#define SBTMCH_RM_SHIFT 2
++#define SBTMCH_SM_MASK 0x30 /* stop mode */
++#define SBTMCH_SM_SHIFT 4
++#define SBTMCH_EM_MASK 0x300 /* sb error mode */
++#define SBTMCH_EM_SHIFT 8
++#define SBTMCH_IM_MASK 0xc00 /* int mode */
++#define SBTMCH_IM_SHIFT 10
++
++/* sbbconfig */
++#define SBBC_LAT_MASK 0x3 /* sb latency */
++#define SBBC_MAX0_MASK 0xf0000 /* maxccntr0 */
++#define SBBC_MAX0_SHIFT 16
++#define SBBC_MAX1_MASK 0xf00000 /* maxccntr1 */
++#define SBBC_MAX1_SHIFT 20
++
++/* sbbstate */
++#define SBBS_SRD 0x1 /* st reg disable */
++#define SBBS_HRD 0x2 /* hold reg disable */
++
++/* sbidlow */
++#define SBIDL_CS_MASK 0x3 /* config space */
++#define SBIDL_AR_MASK 0x38 /* # address ranges supported */
++#define SBIDL_AR_SHIFT 3
++#define SBIDL_SYNCH 0x40 /* sync */
++#define SBIDL_INIT 0x80 /* initiator */
++#define SBIDL_MINLAT_MASK 0xf00 /* minimum backplane latency */
++#define SBIDL_MINLAT_SHIFT 8
++#define SBIDL_MAXLAT 0xf000 /* maximum backplane latency */
++#define SBIDL_MAXLAT_SHIFT 12
++#define SBIDL_FIRST 0x10000 /* this initiator is first */
++#define SBIDL_CW_MASK 0xc0000 /* cycle counter width */
++#define SBIDL_CW_SHIFT 18
++#define SBIDL_TP_MASK 0xf00000 /* target ports */
++#define SBIDL_TP_SHIFT 20
++#define SBIDL_IP_MASK 0xf000000 /* initiator ports */
++#define SBIDL_IP_SHIFT 24
++#define SBIDL_RV_MASK 0xf0000000 /* sonics backplane revision code */
++#define SBIDL_RV_SHIFT 28
++#define SBIDL_RV_2_2 0x00000000 /* version 2.2 or earlier */
++#define SBIDL_RV_2_3 0x10000000 /* version 2.3 */
++
++/* sbidhigh */
++#define SBIDH_RC_MASK 0x000f /* revision code */
++#define SBIDH_RCE_MASK 0x7000 /* revision code extension field */
++#define SBIDH_RCE_SHIFT 8
++#define SBCOREREV(sbidh) \
++ ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | ((sbidh) & SBIDH_RC_MASK))
++#define SBIDH_CC_MASK 0x8ff0 /* core code */
++#define SBIDH_CC_SHIFT 4
++#define SBIDH_VC_MASK 0xffff0000 /* vendor code */
++#define SBIDH_VC_SHIFT 16
++
++#define SB_COMMIT 0xfd8 /* update buffered registers value */
++
++/* vendor codes */
++#define SB_VEND_BCM 0x4243 /* Broadcom's SB vendor code */
++
++/* core codes */
++#define SB_CC 0x800 /* chipcommon core */
++#define SB_ILINE20 0x801 /* iline20 core */
++#define SB_SDRAM 0x803 /* sdram core */
++#define SB_PCI 0x804 /* pci core */
++#define SB_MIPS 0x805 /* mips core */
++#define SB_ENET 0x806 /* enet mac core */
++#define SB_CODEC 0x807 /* v90 codec core */
++#define SB_USB 0x808 /* usb 1.1 host/device core */
++#define SB_ADSL 0x809 /* ADSL core */
++#define SB_ILINE100 0x80a /* iline100 core */
++#define SB_IPSEC 0x80b /* ipsec core */
++#define SB_PCMCIA 0x80d /* pcmcia core */
++#define SB_SOCRAM 0x80e /* internal memory core */
++#define SB_MEMC 0x80f /* memc sdram core */
++#define SB_EXTIF 0x811 /* external interface core */
++#define SB_D11 0x812 /* 802.11 MAC core */
++#define SB_MIPS33 0x816 /* mips3302 core */
++#define SB_USB11H 0x817 /* usb 1.1 host core */
++#define SB_USB11D 0x818 /* usb 1.1 device core */
++#define SB_USB20H 0x819 /* usb 2.0 host core */
++#define SB_USB20D 0x81a /* usb 2.0 device core */
++#define SB_SDIOH 0x81b /* sdio host core */
++#define SB_ROBO 0x81c /* roboswitch core */
++#define SB_ATA100 0x81d /* parallel ATA core */
++#define SB_SATAXOR 0x81e /* serial ATA & XOR DMA core */
++#define SB_GIGETH 0x81f /* gigabit ethernet core */
++#define SB_PCIE 0x820 /* pci express core */
++#define SB_SRAMC 0x822 /* SRAM controller core */
++#define SB_MINIMAC 0x823 /* MINI MAC/phy core */
++
++#define SB_CC_IDX 0 /* chipc, when present, is always core 0 */
++
++/* Not really related to Silicon Backplane, but a couple of software
++ * conventions for the use the flash space:
++ */
++
++/* Minumum amount of flash we support */
++#define FLASH_MIN 0x00020000 /* Minimum flash size */
++
++/* A boot/binary may have an embedded block that describes its size */
++#define BISZ_OFFSET 0x3e0 /* At this offset into the binary */
++#define BISZ_MAGIC 0x4249535a /* Marked with this value: 'BISZ' */
++#define BISZ_MAGIC_IDX 0 /* Word 0: magic */
++#define BISZ_TXTST_IDX 1 /* 1: text start */
++#define BISZ_TXTEND_IDX 2 /* 2: text start */
++#define BISZ_DATAST_IDX 3 /* 3: text start */
++#define BISZ_DATAEND_IDX 4 /* 4: text start */
++#define BISZ_BSSST_IDX 5 /* 5: text start */
++#define BISZ_BSSEND_IDX 6 /* 6: text start */
++#define BISZ_SIZE 7 /* descriptor size in 32-bit intergers */
++
++#endif /* _SBCONFIG_H */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/sbextif.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbextif.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/sbextif.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbextif.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,242 @@
++/*
++ * Hardware-specific External Interface I/O core definitions
++ * for the BCM47xx family of SiliconBackplane-based chips.
++ *
++ * The External Interface core supports a total of three external chip selects
++ * supporting external interfaces. One of the external chip selects is
++ * used for Flash, one is used for PCMCIA, and the other may be
++ * programmed to support either a synchronous interface or an
++ * asynchronous interface. The asynchronous interface can be used to
++ * support external devices such as UARTs and the BCM2019 Bluetooth
++ * baseband processor.
++ * The external interface core also contains 2 on-chip 16550 UARTs, clock
++ * frequency control, a watchdog interrupt timer, and a GPIO interface.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id$
++ */
++
++#ifndef _SBEXTIF_H
++#define _SBEXTIF_H
++
++/* external interface address space */
++#define EXTIF_PCMCIA_MEMBASE(x) (x)
++#define EXTIF_PCMCIA_IOBASE(x) ((x) + 0x100000)
++#define EXTIF_PCMCIA_CFGBASE(x) ((x) + 0x200000)
++#define EXTIF_CFGIF_BASE(x) ((x) + 0x800000)
++#define EXTIF_FLASH_BASE(x) ((x) + 0xc00000)
++
++/* cpp contortions to concatenate w/arg prescan */
++#ifndef PAD
++#define _PADLINE(line) pad ## line
++#define _XSTR(line) _PADLINE(line)
++#define PAD _XSTR(__LINE__)
++#endif /* PAD */
++
++/*
++ * The multiple instances of output and output enable registers
++ * are present to allow driver software for multiple cores to control
++ * gpio outputs without needing to share a single register pair.
++ */
++struct gpiouser {
++ uint32 out;
++ uint32 outen;
++};
++#define NGPIOUSER 5
++
++typedef volatile struct {
++ uint32 corecontrol;
++ uint32 extstatus;
++ uint32 PAD[2];
++
++ /* pcmcia control registers */
++ uint32 pcmcia_config;
++ uint32 pcmcia_memwait;
++ uint32 pcmcia_attrwait;
++ uint32 pcmcia_iowait;
++
++ /* programmable interface control registers */
++ uint32 prog_config;
++ uint32 prog_waitcount;
++
++ /* flash control registers */
++ uint32 flash_config;
++ uint32 flash_waitcount;
++ uint32 PAD[4];
++
++ uint32 watchdog;
++
++ /* clock control */
++ uint32 clockcontrol_n;
++ uint32 clockcontrol_sb;
++ uint32 clockcontrol_pci;
++ uint32 clockcontrol_mii;
++ uint32 PAD[3];
++
++ /* gpio */
++ uint32 gpioin;
++ struct gpiouser gpio[NGPIOUSER];
++ uint32 PAD;
++ uint32 ejtagouten;
++ uint32 gpiointpolarity;
++ uint32 gpiointmask;
++ uint32 PAD[153];
++
++ uint8 uartdata;
++ uint8 PAD[3];
++ uint8 uartimer;
++ uint8 PAD[3];
++ uint8 uartfcr;
++ uint8 PAD[3];
++ uint8 uartlcr;
++ uint8 PAD[3];
++ uint8 uartmcr;
++ uint8 PAD[3];
++ uint8 uartlsr;
++ uint8 PAD[3];
++ uint8 uartmsr;
++ uint8 PAD[3];
++ uint8 uartscratch;
++ uint8 PAD[3];
++} extifregs_t;
++
++/* corecontrol */
++#define CC_UE (1 << 0) /* uart enable */
++
++/* extstatus */
++#define ES_EM (1 << 0) /* endian mode (ro) */
++#define ES_EI (1 << 1) /* external interrupt pin (ro) */
++#define ES_GI (1 << 2) /* gpio interrupt pin (ro) */
++
++/* gpio bit mask */
++#define GPIO_BIT0 (1 << 0)
++#define GPIO_BIT1 (1 << 1)
++#define GPIO_BIT2 (1 << 2)
++#define GPIO_BIT3 (1 << 3)
++#define GPIO_BIT4 (1 << 4)
++#define GPIO_BIT5 (1 << 5)
++#define GPIO_BIT6 (1 << 6)
++#define GPIO_BIT7 (1 << 7)
++
++
++/* pcmcia/prog/flash_config */
++#define CF_EN (1 << 0) /* enable */
++#define CF_EM_MASK 0xe /* mode */
++#define CF_EM_SHIFT 1
++#define CF_EM_FLASH 0x0 /* flash/asynchronous mode */
++#define CF_EM_SYNC 0x2 /* synchronous mode */
++#define CF_EM_PCMCIA 0x4 /* pcmcia mode */
++#define CF_DS (1 << 4) /* destsize: 0=8bit, 1=16bit */
++#define CF_BS (1 << 5) /* byteswap */
++#define CF_CD_MASK 0xc0 /* clock divider */
++#define CF_CD_SHIFT 6
++#define CF_CD_DIV2 0x0 /* backplane/2 */
++#define CF_CD_DIV3 0x40 /* backplane/3 */
++#define CF_CD_DIV4 0x80 /* backplane/4 */
++#define CF_CE (1 << 8) /* clock enable */
++#define CF_SB (1 << 9) /* size/bytestrobe (synch only) */
++
++/* pcmcia_memwait */
++#define PM_W0_MASK 0x3f /* waitcount0 */
++#define PM_W1_MASK 0x1f00 /* waitcount1 */
++#define PM_W1_SHIFT 8
++#define PM_W2_MASK 0x1f0000 /* waitcount2 */
++#define PM_W2_SHIFT 16
++#define PM_W3_MASK 0x1f000000 /* waitcount3 */
++#define PM_W3_SHIFT 24
++
++/* pcmcia_attrwait */
++#define PA_W0_MASK 0x3f /* waitcount0 */
++#define PA_W1_MASK 0x1f00 /* waitcount1 */
++#define PA_W1_SHIFT 8
++#define PA_W2_MASK 0x1f0000 /* waitcount2 */
++#define PA_W2_SHIFT 16
++#define PA_W3_MASK 0x1f000000 /* waitcount3 */
++#define PA_W3_SHIFT 24
++
++/* pcmcia_iowait */
++#define PI_W0_MASK 0x3f /* waitcount0 */
++#define PI_W1_MASK 0x1f00 /* waitcount1 */
++#define PI_W1_SHIFT 8
++#define PI_W2_MASK 0x1f0000 /* waitcount2 */
++#define PI_W2_SHIFT 16
++#define PI_W3_MASK 0x1f000000 /* waitcount3 */
++#define PI_W3_SHIFT 24
++
++/* prog_waitcount */
++#define PW_W0_MASK 0x0000001f /* waitcount0 */
++#define PW_W1_MASK 0x00001f00 /* waitcount1 */
++#define PW_W1_SHIFT 8
++#define PW_W2_MASK 0x001f0000 /* waitcount2 */
++#define PW_W2_SHIFT 16
++#define PW_W3_MASK 0x1f000000 /* waitcount3 */
++#define PW_W3_SHIFT 24
++
++#define PW_W0 0x0000000c
++#define PW_W1 0x00000a00
++#define PW_W2 0x00020000
++#define PW_W3 0x01000000
++
++/* flash_waitcount */
++#define FW_W0_MASK 0x1f /* waitcount0 */
++#define FW_W1_MASK 0x1f00 /* waitcount1 */
++#define FW_W1_SHIFT 8
++#define FW_W2_MASK 0x1f0000 /* waitcount2 */
++#define FW_W2_SHIFT 16
++#define FW_W3_MASK 0x1f000000 /* waitcount3 */
++#define FW_W3_SHIFT 24
++
++/* watchdog */
++#define WATCHDOG_CLOCK 48000000 /* Hz */
++
++/* clockcontrol_n */
++#define CN_N1_MASK 0x3f /* n1 control */
++#define CN_N2_MASK 0x3f00 /* n2 control */
++#define CN_N2_SHIFT 8
++
++/* clockcontrol_sb/pci/mii */
++#define CC_M1_MASK 0x3f /* m1 control */
++#define CC_M2_MASK 0x3f00 /* m2 control */
++#define CC_M2_SHIFT 8
++#define CC_M3_MASK 0x3f0000 /* m3 control */
++#define CC_M3_SHIFT 16
++#define CC_MC_MASK 0x1f000000 /* mux control */
++#define CC_MC_SHIFT 24
++
++/* Clock control default values */
++#define CC_DEF_N 0x0009 /* Default values for bcm4710 */
++#define CC_DEF_100 0x04020011
++#define CC_DEF_33 0x11030011
++#define CC_DEF_25 0x11050011
++
++/* Clock control values for 125Mhz */
++#define CC_125_N 0x0802
++#define CC_125_M 0x04020009
++#define CC_125_M25 0x11090009
++#define CC_125_M33 0x11090005
++
++/* Clock control magic field values */
++#define CC_F6_2 0x02 /* A factor of 2 in */
++#define CC_F6_3 0x03 /* 6-bit fields like */
++#define CC_F6_4 0x05 /* N1, M1 or M3 */
++#define CC_F6_5 0x09
++#define CC_F6_6 0x11
++#define CC_F6_7 0x21
++
++#define CC_F5_BIAS 5 /* 5-bit fields get this added */
++
++#define CC_MC_BYPASS 0x08
++#define CC_MC_M1 0x04
++#define CC_MC_M1M2 0x02
++#define CC_MC_M1M2M3 0x01
++#define CC_MC_M1M3 0x11
++
++#define CC_CLOCK_BASE 24000000 /* Half the clock freq. in the 4710 */
++
++#endif /* _SBEXTIF_H */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/sbmemc.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbmemc.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/sbmemc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbmemc.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,148 @@
++/*
++ * BCM47XX Sonics SiliconBackplane DDR/SDRAM controller core hardware definitions.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#ifndef _SBMEMC_H
++#define _SBMEMC_H
++
++#ifdef _LANGUAGE_ASSEMBLY
++
++#define MEMC_CONTROL 0x00
++#define MEMC_CONFIG 0x04
++#define MEMC_REFRESH 0x08
++#define MEMC_BISTSTAT 0x0c
++#define MEMC_MODEBUF 0x10
++#define MEMC_BKCLS 0x14
++#define MEMC_PRIORINV 0x18
++#define MEMC_DRAMTIM 0x1c
++#define MEMC_INTSTAT 0x20
++#define MEMC_INTMASK 0x24
++#define MEMC_INTINFO 0x28
++#define MEMC_NCDLCTL 0x30
++#define MEMC_RDNCDLCOR 0x34
++#define MEMC_WRNCDLCOR 0x38
++#define MEMC_MISCDLYCTL 0x3c
++#define MEMC_DQSGATENCDL 0x40
++#define MEMC_SPARE 0x44
++#define MEMC_TPADDR 0x48
++#define MEMC_TPDATA 0x4c
++#define MEMC_BARRIER 0x50
++#define MEMC_CORE 0x54
++
++
++#else
++
++/* Sonics side: MEMC core registers */
++typedef volatile struct sbmemcregs {
++ uint32 control;
++ uint32 config;
++ uint32 refresh;
++ uint32 biststat;
++ uint32 modebuf;
++ uint32 bkcls;
++ uint32 priorinv;
++ uint32 dramtim;
++ uint32 intstat;
++ uint32 intmask;
++ uint32 intinfo;
++ uint32 reserved1;
++ uint32 ncdlctl;
++ uint32 rdncdlcor;
++ uint32 wrncdlcor;
++ uint32 miscdlyctl;
++ uint32 dqsgatencdl;
++ uint32 spare;
++ uint32 tpaddr;
++ uint32 tpdata;
++ uint32 barrier;
++ uint32 core;
++} sbmemcregs_t;
++
++#endif
++
++/* MEMC Core Init values (OCP ID 0x80f) */
++
++/* For sdr: */
++#define MEMC_SD_CONFIG_INIT 0x00048000
++#define MEMC_SD_DRAMTIM2_INIT 0x000754d8
++#define MEMC_SD_DRAMTIM3_INIT 0x000754da
++#define MEMC_SD_RDNCDLCOR_INIT 0x00000000
++#define MEMC_SD_WRNCDLCOR_INIT 0x49351200
++#define MEMC_SD1_WRNCDLCOR_INIT 0x14500200 /* For corerev 1 (4712) */
++#define MEMC_SD_MISCDLYCTL_INIT 0x00061c1b
++#define MEMC_SD1_MISCDLYCTL_INIT 0x00021416 /* For corerev 1 (4712) */
++#define MEMC_SD_CONTROL_INIT0 0x00000002
++#define MEMC_SD_CONTROL_INIT1 0x00000008
++#define MEMC_SD_CONTROL_INIT2 0x00000004
++#define MEMC_SD_CONTROL_INIT3 0x00000010
++#define MEMC_SD_CONTROL_INIT4 0x00000001
++#define MEMC_SD_MODEBUF_INIT 0x00000000
++#define MEMC_SD_REFRESH_INIT 0x0000840f
++
++
++/* This is for SDRM8X8X4 */
++#define MEMC_SDR_INIT 0x0008
++#define MEMC_SDR_MODE 0x32
++#define MEMC_SDR_NCDL 0x00020032
++#define MEMC_SDR1_NCDL 0x0002020f /* For corerev 1 (4712) */
++
++/* For ddr: */
++#define MEMC_CONFIG_INIT 0x00048000
++#define MEMC_DRAMTIM2_INIT 0x000754d8
++#define MEMC_DRAMTIM25_INIT 0x000754d9
++#define MEMC_RDNCDLCOR_INIT 0x00000000
++#define MEMC_RDNCDLCOR_SIMINIT 0xf6f6f6f6 /* For hdl sim */
++#define MEMC_WRNCDLCOR_INIT 0x49351200
++#define MEMC_1_WRNCDLCOR_INIT 0x14500200
++#define MEMC_DQSGATENCDL_INIT 0x00030000
++#define MEMC_MISCDLYCTL_INIT 0x21061c1b
++#define MEMC_1_MISCDLYCTL_INIT 0x21021400
++#define MEMC_NCDLCTL_INIT 0x00002001
++#define MEMC_CONTROL_INIT0 0x00000002
++#define MEMC_CONTROL_INIT1 0x00000008
++#define MEMC_MODEBUF_INIT0 0x00004000
++#define MEMC_CONTROL_INIT2 0x00000010
++#define MEMC_MODEBUF_INIT1 0x00000100
++#define MEMC_CONTROL_INIT3 0x00000010
++#define MEMC_CONTROL_INIT4 0x00000008
++#define MEMC_REFRESH_INIT 0x0000840f
++#define MEMC_CONTROL_INIT5 0x00000004
++#define MEMC_MODEBUF_INIT2 0x00000000
++#define MEMC_CONTROL_INIT6 0x00000010
++#define MEMC_CONTROL_INIT7 0x00000001
++
++
++/* This is for DDRM16X16X2 */
++#define MEMC_DDR_INIT 0x0009
++#define MEMC_DDR_MODE 0x62
++#define MEMC_DDR_NCDL 0x0005050a
++#define MEMC_DDR1_NCDL 0x00000a0a /* For corerev 1 (4712) */
++
++/* mask for sdr/ddr calibration registers */
++#define MEMC_RDNCDLCOR_RD_MASK 0x000000ff
++#define MEMC_WRNCDLCOR_WR_MASK 0x000000ff
++#define MEMC_DQSGATENCDL_G_MASK 0x000000ff
++
++/* masks for miscdlyctl registers */
++#define MEMC_MISC_SM_MASK 0x30000000
++#define MEMC_MISC_SM_SHIFT 28
++#define MEMC_MISC_SD_MASK 0x0f000000
++#define MEMC_MISC_SD_SHIFT 24
++
++/* hw threshhold for calculating wr/rd for sdr memc */
++#define MEMC_CD_THRESHOLD 128
++
++/* Low bit of init register says if memc is ddr or sdr */
++#define MEMC_CONFIG_DDR 0x00000001
++
++#endif /* _SBMEMC_H */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/sbmips.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbmips.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/sbmips.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbmips.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,62 @@
++/*
++ * Broadcom SiliconBackplane MIPS definitions
++ *
++ * SB MIPS cores are custom MIPS32 processors with SiliconBackplane
++ * OCP interfaces. The CP0 processor ID is 0x00024000, where bits
++ * 23:16 mean Broadcom and bits 15:8 mean a MIPS core with an OCP
++ * interface. The core revision is stored in the SB ID register in SB
++ * configuration space.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#ifndef _SBMIPS_H
++#define _SBMIPS_H
++
++#include <mipsinc.h>
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++/* cpp contortions to concatenate w/arg prescan */
++#ifndef PAD
++#define _PADLINE(line) pad ## line
++#define _XSTR(line) _PADLINE(line)
++#define PAD _XSTR(__LINE__)
++#endif /* PAD */
++
++typedef volatile struct {
++ uint32 corecontrol;
++ uint32 PAD[2];
++ uint32 biststatus;
++ uint32 PAD[4];
++ uint32 intstatus;
++ uint32 intmask;
++ uint32 timer;
++} mipsregs_t;
++
++extern uint32 sb_flag(sb_t *sbh);
++extern uint sb_irq(sb_t *sbh);
++
++extern void BCMINIT(sb_serial_init)(sb_t *sbh, void (*add)(void *regs, uint irq, uint baud_base, uint reg_shift));
++
++extern void *sb_jtagm_init(sb_t *sbh, uint clkd, bool exttap);
++extern void sb_jtagm_disable(void *h);
++extern uint32 jtag_rwreg(void *h, uint32 ir, uint32 dr);
++extern void BCMINIT(sb_mips_init)(sb_t *sbh);
++extern uint32 BCMINIT(sb_mips_clock)(sb_t *sbh);
++extern bool BCMINIT(sb_mips_setclock)(sb_t *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock);
++extern void BCMINIT(enable_pfc)(uint32 mode);
++extern uint32 BCMINIT(sb_memc_get_ncdl)(sb_t *sbh);
++
++
++#endif /* _LANGUAGE_ASSEMBLY */
++
++#endif /* _SBMIPS_H */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/sbpci.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbpci.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/sbpci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbpci.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,122 @@
++/*
++ * BCM47XX Sonics SiliconBackplane PCI core hardware definitions.
++ *
++ * $Id$
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ */
++
++#ifndef _SBPCI_H
++#define _SBPCI_H
++
++/* cpp contortions to concatenate w/arg prescan */
++#ifndef PAD
++#define _PADLINE(line) pad ## line
++#define _XSTR(line) _PADLINE(line)
++#define PAD _XSTR(__LINE__)
++#endif
++
++/* Sonics side: PCI core and host control registers */
++typedef struct sbpciregs {
++ uint32 control; /* PCI control */
++ uint32 PAD[3];
++ uint32 arbcontrol; /* PCI arbiter control */
++ uint32 PAD[3];
++ uint32 intstatus; /* Interrupt status */
++ uint32 intmask; /* Interrupt mask */
++ uint32 sbtopcimailbox; /* Sonics to PCI mailbox */
++ uint32 PAD[9];
++ uint32 bcastaddr; /* Sonics broadcast address */
++ uint32 bcastdata; /* Sonics broadcast data */
++ uint32 PAD[2];
++ uint32 gpioin; /* ro: gpio input (>=rev2) */
++ uint32 gpioout; /* rw: gpio output (>=rev2) */
++ uint32 gpioouten; /* rw: gpio output enable (>= rev2) */
++ uint32 gpiocontrol; /* rw: gpio control (>= rev2) */
++ uint32 PAD[36];
++ uint32 sbtopci0; /* Sonics to PCI translation 0 */
++ uint32 sbtopci1; /* Sonics to PCI translation 1 */
++ uint32 sbtopci2; /* Sonics to PCI translation 2 */
++ uint32 PAD[445];
++ uint16 sprom[36]; /* SPROM shadow Area */
++ uint32 PAD[46];
++} sbpciregs_t;
++
++/* PCI control */
++#define PCI_RST_OE 0x01 /* When set, drives PCI_RESET out to pin */
++#define PCI_RST 0x02 /* Value driven out to pin */
++#define PCI_CLK_OE 0x04 /* When set, drives clock as gated by PCI_CLK out to pin */
++#define PCI_CLK 0x08 /* Gate for clock driven out to pin */
++
++/* PCI arbiter control */
++#define PCI_INT_ARB 0x01 /* When set, use an internal arbiter */
++#define PCI_EXT_ARB 0x02 /* When set, use an external arbiter */
++#define PCI_PARKID_MASK 0x06 /* Selects which agent is parked on an idle bus */
++#define PCI_PARKID_SHIFT 1
++#define PCI_PARKID_LAST 0 /* Last requestor */
++#define PCI_PARKID_4710 1 /* 4710 */
++#define PCI_PARKID_EXTREQ0 2 /* External requestor 0 */
++#define PCI_PARKID_EXTREQ1 3 /* External requestor 1 */
++
++/* Interrupt status/mask */
++#define PCI_INTA 0x01 /* PCI INTA# is asserted */
++#define PCI_INTB 0x02 /* PCI INTB# is asserted */
++#define PCI_SERR 0x04 /* PCI SERR# has been asserted (write one to clear) */
++#define PCI_PERR 0x08 /* PCI PERR# has been asserted (write one to clear) */
++#define PCI_PME 0x10 /* PCI PME# is asserted */
++
++/* (General) PCI/SB mailbox interrupts, two bits per pci function */
++#define MAILBOX_F0_0 0x100 /* function 0, int 0 */
++#define MAILBOX_F0_1 0x200 /* function 0, int 1 */
++#define MAILBOX_F1_0 0x400 /* function 1, int 0 */
++#define MAILBOX_F1_1 0x800 /* function 1, int 1 */
++#define MAILBOX_F2_0 0x1000 /* function 2, int 0 */
++#define MAILBOX_F2_1 0x2000 /* function 2, int 1 */
++#define MAILBOX_F3_0 0x4000 /* function 3, int 0 */
++#define MAILBOX_F3_1 0x8000 /* function 3, int 1 */
++
++/* Sonics broadcast address */
++#define BCAST_ADDR_MASK 0xff /* Broadcast register address */
++
++/* Sonics to PCI translation types */
++#define SBTOPCI0_MASK 0xfc000000
++#define SBTOPCI1_MASK 0xfc000000
++#define SBTOPCI2_MASK 0xc0000000
++#define SBTOPCI_MEM 0
++#define SBTOPCI_IO 1
++#define SBTOPCI_CFG0 2
++#define SBTOPCI_CFG1 3
++#define SBTOPCI_PREF 0x4 /* prefetch enable */
++#define SBTOPCI_BURST 0x8 /* burst enable */
++#define SBTOPCI_RC_MASK 0x30 /* read command (>= rev11) */
++#define SBTOPCI_RC_READ 0x00 /* memory read */
++#define SBTOPCI_RC_READLINE 0x10 /* memory read line */
++#define SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */
++
++/* PCI core index in SROM shadow area */
++#define SRSH_PI_OFFSET 0 /* first word */
++#define SRSH_PI_MASK 0xf000 /* bit 15:12 */
++#define SRSH_PI_SHIFT 12 /* bit 15:12 */
++
++/* PCI side: Reserved PCI configuration registers (see pcicfg.h) */
++#define cap_list rsvd_a[0]
++#define bar0_window dev_dep[0x80 - 0x40]
++#define bar1_window dev_dep[0x84 - 0x40]
++#define sprom_control dev_dep[0x88 - 0x40]
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++extern int sbpci_read_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len);
++extern int sbpci_write_config(sb_t *sbh, uint bus, uint dev, uint func, uint off, void *buf, int len);
++extern void sbpci_ban(uint16 core);
++extern int sbpci_init(sb_t *sbh);
++extern void sbpci_check(sb_t *sbh);
++
++#endif /* !_LANGUAGE_ASSEMBLY */
++
++#endif /* _SBPCI_H */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/sbsdram.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbsdram.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/sbsdram.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbsdram.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,75 @@
++/*
++ * BCM47XX Sonics SiliconBackplane SDRAM controller core hardware definitions.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id$
++ */
++
++#ifndef _SBSDRAM_H
++#define _SBSDRAM_H
++
++#ifndef _LANGUAGE_ASSEMBLY
++
++/* Sonics side: SDRAM core registers */
++typedef volatile struct sbsdramregs {
++ uint32 initcontrol; /* Generates external SDRAM initialization sequence */
++ uint32 config; /* Initializes external SDRAM mode register */
++ uint32 refresh; /* Controls external SDRAM refresh rate */
++ uint32 pad1;
++ uint32 pad2;
++} sbsdramregs_t;
++
++#endif
++
++/* SDRAM initialization control (initcontrol) register bits */
++#define SDRAM_CBR 0x0001 /* Writing 1 generates refresh cycle and toggles bit */
++#define SDRAM_PRE 0x0002 /* Writing 1 generates precharge cycle and toggles bit */
++#define SDRAM_MRS 0x0004 /* Writing 1 generates mode register select cycle and toggles bit */
++#define SDRAM_EN 0x0008 /* When set, enables access to SDRAM */
++#define SDRAM_16Mb 0x0000 /* Use 16 Megabit SDRAM */
++#define SDRAM_64Mb 0x0010 /* Use 64 Megabit SDRAM */
++#define SDRAM_128Mb 0x0020 /* Use 128 Megabit SDRAM */
++#define SDRAM_RSVMb 0x0030 /* Use special SDRAM */
++#define SDRAM_RST 0x0080 /* Writing 1 causes soft reset of controller */
++#define SDRAM_SELFREF 0x0100 /* Writing 1 enables self refresh mode */
++#define SDRAM_PWRDOWN 0x0200 /* Writing 1 causes controller to power down */
++#define SDRAM_32BIT 0x0400 /* When set, indicates 32 bit SDRAM interface */
++#define SDRAM_9BITCOL 0x0800 /* When set, indicates 9 bit column */
++
++/* SDRAM configuration (config) register bits */
++#define SDRAM_BURSTFULL 0x0000 /* Use full page bursts */
++#define SDRAM_BURST8 0x0001 /* Use burst of 8 */
++#define SDRAM_BURST4 0x0002 /* Use burst of 4 */
++#define SDRAM_BURST2 0x0003 /* Use burst of 2 */
++#define SDRAM_CAS3 0x0000 /* Use CAS latency of 3 */
++#define SDRAM_CAS2 0x0004 /* Use CAS latency of 2 */
++
++/* SDRAM refresh control (refresh) register bits */
++#define SDRAM_REF(p) (((p)&0xff) | SDRAM_REF_EN) /* Refresh period */
++#define SDRAM_REF_EN 0x8000 /* Writing 1 enables periodic refresh */
++
++/* SDRAM Core default Init values (OCP ID 0x803) */
++#define SDRAM_INIT MEM4MX16X2
++#define SDRAM_CONFIG SDRAM_BURSTFULL
++#define SDRAM_REFRESH SDRAM_REF(0x40)
++
++#define MEM1MX16 0x009 /* 2 MB */
++#define MEM1MX16X2 0x409 /* 4 MB */
++#define MEM2MX8X2 0x809 /* 4 MB */
++#define MEM2MX8X4 0xc09 /* 8 MB */
++#define MEM2MX32 0x439 /* 8 MB */
++#define MEM4MX16 0x019 /* 8 MB */
++#define MEM4MX16X2 0x419 /* 16 MB */
++#define MEM8MX8X2 0x819 /* 16 MB */
++#define MEM8MX16 0x829 /* 16 MB */
++#define MEM4MX32 0x429 /* 16 MB */
++#define MEM8MX8X4 0xc19 /* 32 MB */
++#define MEM8MX16X2 0xc29 /* 32 MB */
++
++#endif /* _SBSDRAM_H */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/sbutils.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbutils.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/sbutils.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/sbutils.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,136 @@
++/*
++ * Misc utility routines for accessing chip-specific features
++ * of Broadcom HNBU SiliconBackplane-based chips.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#ifndef _sbutils_h_
++#define _sbutils_h_
++
++/*
++ * Datastructure to export all chip specific common variables
++ * public (read-only) portion of sbutils handle returned by
++ * sb_attach()/sb_kattach()
++*/
++
++struct sb_pub {
++
++ uint bustype; /* SB_BUS, PCI_BUS */
++ uint buscoretype; /* SB_PCI, SB_PCMCIA, SB_PCIE*/
++ uint buscorerev; /* buscore rev */
++ uint buscoreidx; /* buscore index */
++ int ccrev; /* chip common core rev */
++ uint boardtype; /* board type */
++ uint boardvendor; /* board vendor */
++ uint chip; /* chip number */
++ uint chiprev; /* chip revision */
++ uint chippkg; /* chip package option */
++ uint sonicsrev; /* sonics backplane rev */
++};
++
++typedef const struct sb_pub sb_t;
++
++/*
++ * Many of the routines below take an 'sbh' handle as their first arg.
++ * Allocate this by calling sb_attach(). Free it by calling sb_detach().
++ * At any one time, the sbh is logically focused on one particular sb core
++ * (the "current core").
++ * Use sb_setcore() or sb_setcoreidx() to change the association to another core.
++ */
++
++/* exported externs */
++extern sb_t * BCMINIT(sb_attach)(uint pcidev, osl_t *osh, void *regs, uint bustype, void *sdh, char **vars, int *varsz);
++extern sb_t * BCMINIT(sb_kattach)(void);
++extern void sb_detach(sb_t *sbh);
++extern uint BCMINIT(sb_chip)(sb_t *sbh);
++extern uint BCMINIT(sb_chiprev)(sb_t *sbh);
++extern uint BCMINIT(sb_chipcrev)(sb_t *sbh);
++extern uint BCMINIT(sb_chippkg)(sb_t *sbh);
++extern uint BCMINIT(sb_pcirev)(sb_t *sbh);
++extern bool BCMINIT(sb_war16165)(sb_t *sbh);
++extern uint BCMINIT(sb_boardvendor)(sb_t *sbh);
++extern uint BCMINIT(sb_boardtype)(sb_t *sbh);
++extern uint sb_bus(sb_t *sbh);
++extern uint sb_buscoretype(sb_t *sbh);
++extern uint sb_buscorerev(sb_t *sbh);
++extern uint sb_corelist(sb_t *sbh, uint coreid[]);
++extern uint sb_coreid(sb_t *sbh);
++extern uint sb_coreidx(sb_t *sbh);
++extern uint sb_coreunit(sb_t *sbh);
++extern uint sb_corevendor(sb_t *sbh);
++extern uint sb_corerev(sb_t *sbh);
++extern void *sb_osh(sb_t *sbh);
++extern void *sb_coreregs(sb_t *sbh);
++extern uint32 sb_coreflags(sb_t *sbh, uint32 mask, uint32 val);
++extern uint32 sb_coreflagshi(sb_t *sbh, uint32 mask, uint32 val);
++extern bool sb_iscoreup(sb_t *sbh);
++extern void *sb_setcoreidx(sb_t *sbh, uint coreidx);
++extern void *sb_setcore(sb_t *sbh, uint coreid, uint coreunit);
++extern int sb_corebist(sb_t *sbh, uint coreid, uint coreunit);
++extern void sb_commit(sb_t *sbh);
++extern uint32 sb_base(uint32 admatch);
++extern uint32 sb_size(uint32 admatch);
++extern void sb_core_reset(sb_t *sbh, uint32 bits);
++extern void sb_core_tofixup(sb_t *sbh);
++extern void sb_core_disable(sb_t *sbh, uint32 bits);
++extern uint32 sb_clock_rate(uint32 pll_type, uint32 n, uint32 m);
++extern uint32 sb_clock(sb_t *sbh);
++extern void sb_pci_setup(sb_t *sbh, uint coremask);
++extern void sb_watchdog(sb_t *sbh, uint ticks);
++extern void *sb_gpiosetcore(sb_t *sbh);
++extern uint32 sb_gpiocontrol(sb_t *sbh, uint32 mask, uint32 val, uint8 priority);
++extern uint32 sb_gpioouten(sb_t *sbh, uint32 mask, uint32 val, uint8 priority);
++extern uint32 sb_gpioout(sb_t *sbh, uint32 mask, uint32 val, uint8 priority);
++extern uint32 sb_gpioin(sb_t *sbh);
++extern uint32 sb_gpiointpolarity(sb_t *sbh, uint32 mask, uint32 val, uint8 priority);
++extern uint32 sb_gpiointmask(sb_t *sbh, uint32 mask, uint32 val, uint8 priority);
++extern uint32 sb_gpioled(sb_t *sbh, uint32 mask, uint32 val);
++extern uint32 sb_gpioreserve(sb_t *sbh, uint32 gpio_num, uint8 priority);
++extern uint32 sb_gpiorelease(sb_t *sbh, uint32 gpio_num, uint8 priority);
++
++extern void sb_clkctl_init(sb_t *sbh);
++extern uint16 sb_clkctl_fast_pwrup_delay(sb_t *sbh);
++extern bool sb_clkctl_clk(sb_t *sbh, uint mode);
++extern int sb_clkctl_xtal(sb_t *sbh, uint what, bool on);
++extern void sb_register_intr_callback(sb_t *sbh, void *intrsoff_fn,
++ void *intrsrestore_fn, void *intrsenabled_fn, void *intr_arg);
++extern uint32 sb_set_initiator_to(sb_t *sbh, uint32 to);
++extern void sb_corepciid(sb_t *sbh, uint16 *pcivendor, uint16 *pcidevice,
++ uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif);
++extern uint32 sb_gpiotimerval(sb_t *sbh, uint32 mask, uint32 val);
++
++
++
++/*
++* Build device path. Path size must be >= SB_DEVPATH_BUFSZ.
++* The returned path is NULL terminated and has trailing '/'.
++* Return 0 on success, nonzero otherwise.
++*/
++extern int sb_devpath(sb_t *sbh, char *path, int size);
++
++/* clkctl xtal what flags */
++#define XTAL 0x1 /* primary crystal oscillator (2050) */
++#define PLL 0x2 /* main chip pll */
++
++/* clkctl clk mode */
++#define CLK_FAST 0 /* force fast (pll) clock */
++#define CLK_DYNAMIC 2 /* enable dynamic clock control */
++
++
++/* GPIO usage priorities */
++#define GPIO_DRV_PRIORITY 0
++#define GPIO_APP_PRIORITY 1
++
++/* device path */
++#define SB_DEVPATH_BUFSZ 16 /* min buffer size in bytes */
++
++#endif /* _sbutils_h_ */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/sflash.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/sflash.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/sflash.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/sflash.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,36 @@
++/*
++ * Broadcom SiliconBackplane chipcommon serial flash interface
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#ifndef _sflash_h_
++#define _sflash_h_
++
++#include <typedefs.h>
++#include <sbchipc.h>
++
++struct sflash {
++ uint blocksize; /* Block size */
++ uint numblocks; /* Number of blocks */
++ uint32 type; /* Type */
++ uint size; /* Total size in bytes */
++};
++
++/* Utility functions */
++extern int sflash_poll(chipcregs_t *cc, uint offset);
++extern int sflash_read(chipcregs_t *cc, uint offset, uint len, uchar *buf);
++extern int sflash_write(chipcregs_t *cc, uint offset, uint len, const uchar *buf);
++extern int sflash_erase(chipcregs_t *cc, uint offset);
++extern int sflash_commit(chipcregs_t *cc, uint offset, uint len, const uchar *buf);
++extern struct sflash * sflash_init(chipcregs_t *cc);
++
++#endif /* _sflash_h_ */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/trxhdr.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/trxhdr.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/trxhdr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/trxhdr.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,33 @@
++/*
++ * TRX image file header format.
++ *
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * $Id$
++ */
++
++#include <typedefs.h>
++
++#define TRX_MAGIC 0x30524448 /* "HDR0" */
++#define TRX_VERSION 1
++#define TRX_MAX_LEN 0x3A0000
++#define TRX_NO_HEADER 1 /* Do not write TRX header */
++#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */
++#define TRX_MAX_OFFSET 3
++
++struct trx_header {
++ uint32 magic; /* "HDR0" */
++ uint32 len; /* Length of file including header */
++ uint32 crc32; /* 32-bit CRC from flag_version to end of file */
++ uint32 flag_version; /* 0:15 flags, 16:31 version */
++ uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
++};
++
++/* Compatibility */
++typedef struct trx_header TRXHDR, *PTRXHDR;
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/include/typedefs.h linux-2.6.17-owrt/arch/mips/bcm947xx/include/typedefs.h
+--- linux-2.6.17/arch/mips/bcm947xx/include/typedefs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/include/typedefs.h 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,326 @@
++/*
++ * Copyright 2005, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ * $Id$
++ */
++
++#ifndef _TYPEDEFS_H_
++#define _TYPEDEFS_H_
++
++
++/* Define 'SITE_TYPEDEFS' in the compile to include a site specific
++ * typedef file "site_typedefs.h".
++ *
++ * If 'SITE_TYPEDEFS' is not defined, then the "Inferred Typedefs"
++ * section of this file makes inferences about the compile environment
++ * based on defined symbols and possibly compiler pragmas.
++ *
++ * Following these two sections is the "Default Typedefs"
++ * section. This section is only prcessed if 'USE_TYPEDEF_DEFAULTS' is
++ * defined. This section has a default set of typedefs and a few
++ * proprocessor symbols (TRUE, FALSE, NULL, ...).
++ */
++
++#ifdef SITE_TYPEDEFS
++
++/*******************************************************************************
++ * Site Specific Typedefs
++ *******************************************************************************/
++
++#include "site_typedefs.h"
++
++#else
++
++/*******************************************************************************
++ * Inferred Typedefs
++ *******************************************************************************/
++
++/* Infer the compile environment based on preprocessor symbols and pramas.
++ * Override type definitions as needed, and include configuration dependent
++ * header files to define types.
++ */
++
++#ifdef __cplusplus
++
++#define TYPEDEF_BOOL
++#ifndef FALSE
++#define FALSE false
++#endif
++#ifndef TRUE
++#define TRUE true
++#endif
++
++#else /* ! __cplusplus */
++
++#if defined(_WIN32)
++
++#define TYPEDEF_BOOL
++typedef unsigned char bool; /* consistent w/BOOL */
++
++#endif /* _WIN32 */
++
++#endif /* ! __cplusplus */
++
++/* use the Windows ULONG_PTR type when compiling for 64 bit */
++#if defined(_WIN64)
++#include <basetsd.h>
++#define TYPEDEF_UINTPTR
++typedef ULONG_PTR uintptr;
++#endif
++
++#ifdef _HNDRTE_
++typedef long unsigned int size_t;
++#endif
++
++#ifdef _MSC_VER /* Microsoft C */
++#define TYPEDEF_INT64
++#define TYPEDEF_UINT64
++typedef signed __int64 int64;
++typedef unsigned __int64 uint64;
++#endif
++
++#if defined(MACOSX) && defined(KERNEL)
++#define TYPEDEF_BOOL
++#endif
++
++
++#if defined(linux)
++#define TYPEDEF_UINT
++#define TYPEDEF_USHORT
++#define TYPEDEF_ULONG
++#endif
++
++#if !defined(linux) && !defined(_WIN32) && !defined(PMON) && !defined(_CFE_) && !defined(_HNDRTE_) && !defined(_MINOSL_)
++#define TYPEDEF_UINT
++#define TYPEDEF_USHORT
++#endif
++
++
++/* Do not support the (u)int64 types with strict ansi for GNU C */
++#if defined(__GNUC__) && defined(__STRICT_ANSI__)
++#define TYPEDEF_INT64
++#define TYPEDEF_UINT64
++#endif
++
++/* ICL accepts unsigned 64 bit type only, and complains in ANSI mode
++ * for singned or unsigned */
++#if defined(__ICL)
++
++#define TYPEDEF_INT64
++
++#if defined(__STDC__)
++#define TYPEDEF_UINT64
++#endif
++
++#endif /* __ICL */
++
++
++#if !defined(_WIN32) && !defined(PMON) && !defined(_CFE_) && !defined(_HNDRTE_) && !defined(_MINOSL_)
++
++/* pick up ushort & uint from standard types.h */
++#if defined(linux) && defined(__KERNEL__)
++
++#include <linux/types.h> /* sys/types.h and linux/types.h are oil and water */
++
++#else
++
++#include <sys/types.h>
++
++#endif
++
++#endif /* !_WIN32 && !PMON && !_CFE_ && !_HNDRTE_ && !_MINOSL_ */
++
++#if defined(MACOSX) && defined(KERNEL)
++#include <IOKit/IOTypes.h>
++#endif
++
++
++/* use the default typedefs in the next section of this file */
++#define USE_TYPEDEF_DEFAULTS
++
++#endif /* SITE_TYPEDEFS */
++
++
++/*******************************************************************************
++ * Default Typedefs
++ *******************************************************************************/
++
++#ifdef USE_TYPEDEF_DEFAULTS
++#undef USE_TYPEDEF_DEFAULTS
++
++#ifndef TYPEDEF_BOOL
++typedef /*@abstract@*/ unsigned char bool;
++#endif
++
++/*----------------------- define uchar, ushort, uint, ulong ------------------*/
++
++#ifndef TYPEDEF_UCHAR
++typedef unsigned char uchar;
++#endif
++
++#ifndef TYPEDEF_USHORT
++typedef unsigned short ushort;
++#endif
++
++#ifndef TYPEDEF_UINT
++typedef unsigned int uint;
++#endif
++
++#ifndef TYPEDEF_ULONG
++typedef unsigned long ulong;
++#endif
++
++/*----------------------- define [u]int8/16/32/64, uintptr --------------------*/
++
++#ifndef TYPEDEF_UINT8
++typedef unsigned char uint8;
++#endif
++
++#ifndef TYPEDEF_UINT16
++typedef unsigned short uint16;
++#endif
++
++#ifndef TYPEDEF_UINT32
++typedef unsigned int uint32;
++#endif
++
++#ifndef TYPEDEF_UINT64
++typedef unsigned long long uint64;
++#endif
++
++#ifndef TYPEDEF_UINTPTR
++typedef unsigned int uintptr;
++#endif
++
++#ifndef TYPEDEF_INT8
++typedef signed char int8;
++#endif
++
++#ifndef TYPEDEF_INT16
++typedef signed short int16;
++#endif
++
++#ifndef TYPEDEF_INT32
++typedef signed int int32;
++#endif
++
++#ifndef TYPEDEF_INT64
++typedef signed long long int64;
++#endif
++
++/*----------------------- define float32/64, float_t -----------------------*/
++
++#ifndef TYPEDEF_FLOAT32
++typedef float float32;
++#endif
++
++#ifndef TYPEDEF_FLOAT64
++typedef double float64;
++#endif
++
++/*
++ * abstracted floating point type allows for compile time selection of
++ * single or double precision arithmetic. Compiling with -DFLOAT32
++ * selects single precision; the default is double precision.
++ */
++
++#ifndef TYPEDEF_FLOAT_T
++
++#if defined(FLOAT32)
++typedef float32 float_t;
++#else /* default to double precision floating point */
++typedef float64 float_t;
++#endif
++
++#endif /* TYPEDEF_FLOAT_T */
++
++/*----------------------- define macro values -----------------------------*/
++
++#ifndef FALSE
++#define FALSE 0
++#endif
++
++#ifndef TRUE
++#define TRUE 1
++#endif
++
++#ifndef NULL
++#define NULL 0
++#endif
++
++#ifndef OFF
++#define OFF 0
++#endif
++
++#ifndef ON
++#define ON 1
++#endif
++
++#define AUTO (-1)
++
++/* Reclaiming text and data :
++ The following macros specify special linker sections that can be reclaimed
++ after a system is considered 'up'.
++ */
++#if defined(__GNUC__) && defined(BCMRECLAIM)
++extern bool bcmreclaimed;
++#define BCMINITDATA(_data) __attribute__ ((__section__ (".dataini." #_data))) _data##_ini
++#define BCMINITFN(_fn) __attribute__ ((__section__ (".textini." #_fn))) _fn##_ini
++#define BCMINIT(_id) _id##_ini
++#else
++#define BCMINITDATA(_data) _data
++#define BCMINITFN(_fn) _fn
++#define BCMINIT(_id) _id
++#define bcmreclaimed 0
++#endif
++
++/*----------------------- define PTRSZ, INLINE ----------------------------*/
++
++#ifndef PTRSZ
++#define PTRSZ sizeof (char*)
++#endif
++
++#ifndef INLINE
++
++#ifdef _MSC_VER
++
++#define INLINE __inline
++
++#elif __GNUC__
++
++#define INLINE __inline__
++
++#else
++
++#define INLINE
++
++#endif /* _MSC_VER */
++
++#endif /* INLINE */
++
++#undef TYPEDEF_BOOL
++#undef TYPEDEF_UCHAR
++#undef TYPEDEF_USHORT
++#undef TYPEDEF_UINT
++#undef TYPEDEF_ULONG
++#undef TYPEDEF_UINT8
++#undef TYPEDEF_UINT16
++#undef TYPEDEF_UINT32
++#undef TYPEDEF_UINT64
++#undef TYPEDEF_UINTPTR
++#undef TYPEDEF_INT8
++#undef TYPEDEF_INT16
++#undef TYPEDEF_INT32
++#undef TYPEDEF_INT64
++#undef TYPEDEF_FLOAT32
++#undef TYPEDEF_FLOAT64
++#undef TYPEDEF_FLOAT_T
++
++#endif /* USE_TYPEDEF_DEFAULTS */
++
++#endif /* _TYPEDEFS_H_ */
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/irq.c linux-2.6.17-owrt/arch/mips/bcm947xx/irq.c
+--- linux-2.6.17/arch/mips/bcm947xx/irq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/irq.c 2006-06-18 15:32:25.000000000 +0200
+@@ -0,0 +1,64 @@
++/*
++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/config.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <linux/smp.h>
++#include <linux/types.h>
++
++#include <asm/cpu.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/irq_cpu.h>
++
++void plat_irq_dispatch(struct pt_regs *regs)
++{
++ u32 cause;
++
++ cause = read_c0_cause() & read_c0_status() & CAUSEF_IP;
++
++ clear_c0_status(cause);
++
++ if (cause & CAUSEF_IP7)
++ do_IRQ(7, regs);
++ if (cause & CAUSEF_IP2)
++ do_IRQ(2, regs);
++ if (cause & CAUSEF_IP3)
++ do_IRQ(3, regs);
++ if (cause & CAUSEF_IP4)
++ do_IRQ(4, regs);
++ if (cause & CAUSEF_IP5)
++ do_IRQ(5, regs);
++ if (cause & CAUSEF_IP6)
++ do_IRQ(6, regs);
++}
++
++void __init arch_init_irq(void)
++{
++ mips_cpu_irq_init(0);
++}
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/Makefile linux-2.6.17-owrt/arch/mips/bcm947xx/Makefile
+--- linux-2.6.17/arch/mips/bcm947xx/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/Makefile 2006-06-18 15:33:03.000000000 +0200
+@@ -0,0 +1,6 @@
++#
++# Makefile for the BCM47xx specific kernel interface routines
++# under Linux.
++#
++
++obj-y := irq.o prom.o setup.o time.o pci.o
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/pci.c linux-2.6.17-owrt/arch/mips/bcm947xx/pci.c
+--- linux-2.6.17/arch/mips/bcm947xx/pci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/pci.c 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,215 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/types.h>
++
++#include <asm/cpu.h>
++#include <asm/io.h>
++
++#include <typedefs.h>
++#include <osl.h>
++#include <sbutils.h>
++#include <sbmips.h>
++#include <sbconfig.h>
++#include <sbpci.h>
++#include <bcmdevs.h>
++#include <pcicfg.h>
++
++extern sb_t *sbh;
++extern spinlock_t sbh_lock;
++
++
++static int
++sb_pci_read_config(struct pci_bus *bus, unsigned int devfn,
++ int reg, int size, u32 *val)
++{
++ int ret;
++ unsigned long flags;
++
++ spin_lock_irqsave(&sbh_lock, flags);
++ ret = sbpci_read_config(sbh, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), reg, val, size);
++ spin_unlock_irqrestore(&sbh_lock, flags);
++
++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
++}
++
++static int
++sb_pci_write_config(struct pci_bus *bus, unsigned int devfn,
++ int reg, int size, u32 val)
++{
++ int ret;
++ unsigned long flags;
++
++ spin_lock_irqsave(&sbh_lock, flags);
++ ret = sbpci_write_config(sbh, bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), reg, &val, size);
++ spin_unlock_irqrestore(&sbh_lock, flags);
++
++ return ret ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
++}
++
++
++static struct pci_ops sb_pci_ops = {
++ .read = sb_pci_read_config,
++ .write = sb_pci_write_config,
++};
++
++static struct resource sb_pci_mem_resource = {
++ .name = "SB PCI Memory resources",
++ .start = SB_ENUM_BASE,
++ .end = SB_ENUM_LIM - 1,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct resource sb_pci_io_resource = {
++ .name = "SB PCI I/O resources",
++ .start = 0x000,
++ .end = 0x0FF,
++ .flags = IORESOURCE_IO,
++};
++
++static struct pci_controller bcm47xx_sb_pci_controller = {
++ .pci_ops = &sb_pci_ops,
++ .mem_resource = &sb_pci_mem_resource,
++ .io_resource = &sb_pci_io_resource,
++};
++
++static struct resource ext_pci_mem_resource = {
++ .name = "Ext PCI Memory resources",
++ .start = 0x40000000,
++ .end = 0x7fffffff,
++ .flags = IORESOURCE_MEM,
++};
++
++static struct resource ext_pci_io_resource = {
++ .name = "Ext PCI I/O resources",
++ .start = 0x100,
++ .end = 0x1FF,
++ .flags = IORESOURCE_IO,
++};
++
++static struct pci_controller bcm47xx_ext_pci_controller = {
++ .pci_ops = &sb_pci_ops,
++ .io_resource = &ext_pci_io_resource,
++ .mem_resource = &ext_pci_mem_resource,
++ .mem_offset = 0x24000000,
++};
++
++void bcm47xx_pci_init(void)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&sbh_lock, flags);
++ sbpci_init(sbh);
++ spin_unlock_irqrestore(&sbh_lock, flags);
++
++ set_io_port_base((unsigned long) ioremap_nocache(SB_PCI_MEM, 0x04000000));
++
++ register_pci_controller(&bcm47xx_sb_pci_controller);
++ register_pci_controller(&bcm47xx_ext_pci_controller);
++}
++
++int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++ u8 irq;
++
++ if (dev->bus->number == 1)
++ return 2;
++
++ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
++ return irq + 2;
++}
++
++u32 pci_iobase = 0x100;
++u32 pci_membase = SB_PCI_DMA;
++
++static void bcm47xx_fixup_device(struct pci_dev *d)
++{
++ struct resource *res;
++ int pos, size;
++ u32 *base;
++
++ if (d->bus->number == 0)
++ return;
++
++ printk("PCI: Fixing up device %s\n", pci_name(d));
++
++ /* Fix up resource bases */
++ for (pos = 0; pos < 6; pos++) {
++ res = &d->resource[pos];
++ base = ((res->flags & IORESOURCE_IO) ? &pci_iobase : &pci_membase);
++ if (res->end) {
++ size = res->end - res->start + 1;
++ if (*base & (size - 1))
++ *base = (*base + size) & ~(size - 1);
++ res->start = *base;
++ res->end = res->start + size - 1;
++ *base += size;
++ pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
++ }
++ /* Fix up PCI bridge BAR0 only */
++ if (d->bus->number == 1 && PCI_SLOT(d->devfn) == 0)
++ break;
++ }
++ /* Fix up interrupt lines */
++ if (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL))
++ d->irq = (pci_find_device(VENDOR_BROADCOM, SB_PCI, NULL))->irq;
++ pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
++}
++
++
++static void bcm47xx_fixup_bridge(struct pci_dev *dev)
++{
++ if (dev->bus->number != 1 || PCI_SLOT(dev->devfn) != 0)
++ return;
++
++ printk("PCI: fixing up bridge\n");
++
++ /* Enable PCI bridge bus mastering and memory space */
++ pci_set_master(dev);
++ pcibios_enable_device(dev, ~0);
++
++ /* Enable PCI bridge BAR1 prefetch and burst */
++ pci_write_config_dword(dev, PCI_BAR1_CONTROL, 3);
++}
++
++/* Do platform specific device initialization at pci_enable_device() time */
++int pcibios_plat_dev_init(struct pci_dev *dev)
++{
++ uint coreidx;
++ unsigned long flags;
++
++ bcm47xx_fixup_device(dev);
++
++ /* These cores come out of reset enabled */
++ if ((dev->bus->number != 0) ||
++ (dev->device == SB_MIPS) ||
++ (dev->device == SB_MIPS33) ||
++ (dev->device == SB_EXTIF) ||
++ (dev->device == SB_CC))
++ return 0;
++
++ /* Do a core reset */
++ spin_lock_irqsave(&sbh_lock, flags);
++ coreidx = sb_coreidx(sbh);
++ if (sb_setcoreidx(sbh, PCI_SLOT(dev->devfn)) && (sb_coreid(sbh) == SB_USB)) {
++ /*
++ * The USB core requires a special bit to be set during core
++ * reset to enable host (OHCI) mode. Resetting the SB core in
++ * pcibios_enable_device() is a hack for compatibility with
++ * vanilla usb-ohci so that it does not have to know about
++ * SB. A driver that wants to use the USB core in device mode
++ * should know about SB and should reset the bit back to 0
++ * after calling pcibios_enable_device().
++ */
++ sb_core_disable(sbh, sb_coreflags(sbh, 0, 0));
++ sb_core_reset(sbh, 1 << 29);
++ } else {
++ sb_core_reset(sbh, 0);
++ }
++ sb_setcoreidx(sbh, coreidx);
++ spin_unlock_irqrestore(&sbh_lock, flags);
++
++ return 0;
++}
++
++DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, bcm47xx_fixup_bridge);
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/prom.c linux-2.6.17-owrt/arch/mips/bcm947xx/prom.c
+--- linux-2.6.17/arch/mips/bcm947xx/prom.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/prom.c 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,59 @@
++/*
++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/bootmem.h>
++
++#include <asm/addrspace.h>
++#include <asm/bootinfo.h>
++#include <asm/pmon.h>
++
++const char *get_system_type(void)
++{
++ return "Broadcom BCM47xx";
++}
++
++void __init prom_init(void)
++{
++ unsigned long mem;
++
++ mips_machgroup = MACH_GROUP_BRCM;
++ mips_machtype = MACH_BCM47XX;
++
++ /* Figure out memory size by finding aliases */
++ for (mem = (1 << 20); mem < (128 << 20); mem += (1 << 20)) {
++ if (*(unsigned long *)((unsigned long)(prom_init) + mem) ==
++ *(unsigned long *)(prom_init))
++ break;
++ }
++
++ add_memory_region(0, mem, BOOT_MEM_RAM);
++}
++
++unsigned long __init prom_free_prom_memory(void)
++{
++ return 0;
++}
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/setup.c linux-2.6.17-owrt/arch/mips/bcm947xx/setup.c
+--- linux-2.6.17/arch/mips/bcm947xx/setup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/setup.c 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,158 @@
++/*
++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
++ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
++ * Copyright (C) 2005 Felix Fietkau <nbd@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/tty.h>
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++#include <linux/serial_reg.h>
++#include <asm/bootinfo.h>
++#include <asm/time.h>
++#include <asm/reboot.h>
++#include <linux/pm.h>
++
++#include <typedefs.h>
++#include <osl.h>
++#include <sbutils.h>
++#include <sbmips.h>
++#include <sbpci.h>
++#include <sbconfig.h>
++#include <bcmdevs.h>
++#include <bcmutils.h>
++#include <bcmnvram.h>
++
++extern void bcm47xx_pci_init(void);
++extern void bcm47xx_time_init(void);
++extern void bcm47xx_timer_setup(struct irqaction *irq);
++void *sbh;
++spinlock_t sbh_lock = SPIN_LOCK_UNLOCKED;
++int boardflags;
++
++static int ser_line = 0;
++
++typedef struct {
++ void *regs;
++ uint irq;
++ uint baud_base;
++ uint reg_shift;
++} serial_port;
++
++static serial_port ports[4];
++static int num_ports = 0;
++
++static void
++serial_add(void *regs, uint irq, uint baud_base, uint reg_shift)
++{
++ ports[num_ports].regs = regs;
++ ports[num_ports].irq = irq;
++ ports[num_ports].baud_base = baud_base;
++ ports[num_ports].reg_shift = reg_shift;
++ num_ports++;
++}
++
++static void
++do_serial_add(serial_port *port)
++{
++ void *regs;
++ uint irq;
++ uint baud_base;
++ uint reg_shift;
++ struct uart_port s;
++
++ regs = port->regs;
++ irq = port->irq;
++ baud_base = port->baud_base;
++ reg_shift = port->reg_shift;
++
++ memset(&s, 0, sizeof(s));
++
++ s.line = ser_line++;
++ s.membase = regs;
++ s.irq = irq + 2;
++ s.uartclk = baud_base;
++ s.flags = ASYNC_BOOT_AUTOCONF;
++ s.iotype = SERIAL_IO_MEM;
++ s.regshift = reg_shift;
++
++ if (early_serial_setup(&s) != 0) {
++ printk(KERN_ERR "Serial setup failed!\n");
++ }
++}
++
++static void bcm47xx_machine_restart(char *command)
++{
++ printk("Please stand by while rebooting the system...\n");
++
++ /* Set the watchdog timer to reset immediately */
++ local_irq_disable();
++ sb_watchdog(sbh, 1);
++ while (1);
++}
++
++static void bcm47xx_machine_halt(void)
++{
++ /* Disable interrupts and watchdog and spin forever */
++ local_irq_disable();
++ sb_watchdog(sbh, 0);
++ while (1);
++}
++
++void __init plat_setup(void)
++{
++ char *s;
++ int i;
++
++ sbh = (void *) sb_kattach();
++ sb_mips_init(sbh);
++
++ bcm47xx_pci_init();
++
++ sb_serial_init(sbh, serial_add);
++ boardflags = getintvar(NULL, "boardflags");
++
++ /* reverse serial ports if the nvram variable kernel_args starts with console=ttyS1 */
++ s = early_nvram_get("kernel_args");
++ if (!s) s = "";
++ if (!strncmp(s, "console=ttyS1", 13)) {
++ for (i = num_ports; i; i--)
++ do_serial_add(&ports[i - 1]);
++ } else {
++ for (i = 0; i < num_ports; i++)
++ do_serial_add(&ports[i]);
++ }
++
++ _machine_restart = bcm47xx_machine_restart;
++ _machine_halt = bcm47xx_machine_halt;
++ pm_power_off = bcm47xx_machine_halt;
++
++ board_time_init = bcm47xx_time_init;
++ board_timer_setup = bcm47xx_timer_setup;
++}
++
++EXPORT_SYMBOL(sbh);
++EXPORT_SYMBOL(sbh_lock);
++EXPORT_SYMBOL(boardflags);
+diff -Nur linux-2.6.17/arch/mips/bcm947xx/time.c linux-2.6.17-owrt/arch/mips/bcm947xx/time.c
+--- linux-2.6.17/arch/mips/bcm947xx/time.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/mips/bcm947xx/time.c 2006-06-18 15:29:23.000000000 +0200
+@@ -0,0 +1,59 @@
++/*
++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/serial_reg.h>
++#include <linux/interrupt.h>
++#include <asm/addrspace.h>
++#include <asm/io.h>
++#include <asm/time.h>
++
++void __init
++bcm47xx_time_init(void)
++{
++ unsigned int hz;
++
++ /*
++ * Use deterministic values for initial counter interrupt
++ * so that calibrate delay avoids encountering a counter wrap.
++ */
++ write_c0_count(0);
++ write_c0_compare(0xffff);
++
++ hz = 200 * 1000 * 1000;
++
++ /* Set MIPS counter frequency for fixed_rate_gettimeoffset() */
++ mips_hpt_frequency = hz / 2;
++
++}
++
++void __init
++bcm47xx_timer_setup(struct irqaction *irq)
++{
++ /* Enable the timer interrupt */
++ setup_irq(7, irq);
++}
+diff -Nur linux-2.6.17/arch/mips/Kconfig linux-2.6.17-owrt/arch/mips/Kconfig
+--- linux-2.6.17/arch/mips/Kconfig 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/mips/Kconfig 2006-06-18 15:29:23.000000000 +0200
+@@ -245,6 +245,17 @@
+ Members include the Acer PICA, MIPS Magnum 4000, MIPS Millenium and
+ Olivetti M700-10 workstations.
+
++config BCM947XX
++ bool "Support for BCM947xx based boards"
++ select DMA_NONCOHERENT
++ select HW_HAS_PCI
++ select IRQ_CPU
++ select SYS_HAS_CPU_MIPS32_R1
++ select SYS_SUPPORTS_32BIT_KERNEL
++ select SYS_SUPPORTS_LITTLE_ENDIAN
++ help
++ Support for BCM947xx based boards
++
+ config LASAT
+ bool "LASAT Networks platforms"
+ select DMA_NONCOHERENT
+diff -Nur linux-2.6.17/arch/mips/kernel/cpu-probe.c linux-2.6.17-owrt/arch/mips/kernel/cpu-probe.c
+--- linux-2.6.17/arch/mips/kernel/cpu-probe.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/mips/kernel/cpu-probe.c 2006-06-18 15:29:23.000000000 +0200
+@@ -691,6 +691,28 @@
+ }
+
+
++static inline void cpu_probe_broadcom(struct cpuinfo_mips *c)
++{
++ decode_config1(c);
++ switch (c->processor_id & 0xff00) {
++ case PRID_IMP_BCM3302:
++ c->cputype = CPU_BCM3302;
++ c->isa_level = MIPS_CPU_ISA_M32R1;
++ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
++ MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER;
++ break;
++ case PRID_IMP_BCM4710:
++ c->cputype = CPU_BCM4710;
++ c->isa_level = MIPS_CPU_ISA_M32R1;
++ c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
++ MIPS_CPU_4K_CACHE | MIPS_CPU_COUNTER;
++ break;
++ default:
++ c->cputype = CPU_UNKNOWN;
++ break;
++ }
++}
++
+ __init void cpu_probe(void)
+ {
+ struct cpuinfo_mips *c = &current_cpu_data;
+@@ -713,6 +735,9 @@
+ case PRID_COMP_SIBYTE:
+ cpu_probe_sibyte(c);
+ break;
++ case PRID_COMP_BROADCOM:
++ cpu_probe_broadcom(c);
++ break;
+ case PRID_COMP_SANDCRAFT:
+ cpu_probe_sandcraft(c);
+ break;
+diff -Nur linux-2.6.17/arch/mips/kernel/head.S linux-2.6.17-owrt/arch/mips/kernel/head.S
+--- linux-2.6.17/arch/mips/kernel/head.S 2006-06-18 12:54:51.000000000 +0200
++++ linux-2.6.17-owrt/arch/mips/kernel/head.S 2006-06-18 15:29:23.000000000 +0200
+@@ -133,6 +133,11 @@
+ j kernel_entry
+ nop
+
++#ifdef CONFIG_BCM4710
++#undef eret
++#define eret nop; nop; eret
++#endif
++
+ /*
+ * Reserved space for exception handlers.
+ * Necessary for machines which link their kernels at KSEG0.
+diff -Nur linux-2.6.17/arch/mips/kernel/proc.c linux-2.6.17-owrt/arch/mips/kernel/proc.c
+--- linux-2.6.17/arch/mips/kernel/proc.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/mips/kernel/proc.c 2006-06-18 15:29:23.000000000 +0200
+@@ -84,6 +84,8 @@
+ [CPU_VR4181] = "NEC VR4181",
+ [CPU_VR4181A] = "NEC VR4181A",
+ [CPU_SR71000] = "Sandcraft SR71000",
++ [CPU_BCM3302] = "Broadcom BCM3302",
++ [CPU_BCM4710] = "Broadcom BCM4710",
+ [CPU_PR4450] = "Philips PR4450",
+ };
+
+diff -Nur linux-2.6.17/arch/mips/Makefile linux-2.6.17-owrt/arch/mips/Makefile
+--- linux-2.6.17/arch/mips/Makefile 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/mips/Makefile 2006-06-18 15:29:23.000000000 +0200
+@@ -565,6 +565,13 @@
+ load-$(CONFIG_SIBYTE_BIGSUR) := 0xffffffff80100000
+
+ #
++# Broadcom BCM47XX boards
++#
++core-$(CONFIG_BCM947XX) += arch/mips/bcm947xx/ arch/mips/bcm947xx/broadcom/
++cflags-$(CONFIG_BCM947XX) += -Iarch/mips/bcm947xx/include
++load-$(CONFIG_BCM947XX) := 0xffffffff80001000
++
++#
+ # SNI RM200 PCI
+ #
+ core-$(CONFIG_SNI_RM200_PCI) += arch/mips/sni/
+diff -Nur linux-2.6.17/arch/mips/mm/tlbex.c linux-2.6.17-owrt/arch/mips/mm/tlbex.c
+--- linux-2.6.17/arch/mips/mm/tlbex.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/mips/mm/tlbex.c 2006-06-18 15:29:23.000000000 +0200
+@@ -882,6 +882,8 @@
+ case CPU_4KSC:
+ case CPU_20KC:
+ case CPU_25KF:
++ case CPU_BCM3302:
++ case CPU_BCM4710:
+ tlbw(p);
+ break;
+
+diff -Nur linux-2.6.17/include/asm-mips/bootinfo.h linux-2.6.17-owrt/include/asm-mips/bootinfo.h
+--- linux-2.6.17/include/asm-mips/bootinfo.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/asm-mips/bootinfo.h 2006-06-18 15:29:23.000000000 +0200
+@@ -218,6 +218,12 @@
+ #define MACH_GROUP_TITAN 22 /* PMC-Sierra Titan */
+ #define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */
+
++/*
++ * Valid machtype for group Broadcom
++ */
++#define MACH_GROUP_BRCM 23 /* Broadcom */
++#define MACH_BCM47XX 1 /* Broadcom BCM47xx */
++
+ #define CL_SIZE COMMAND_LINE_SIZE
+
+ const char *get_system_type(void);
+diff -Nur linux-2.6.17/include/asm-mips/cpu.h linux-2.6.17-owrt/include/asm-mips/cpu.h
+--- linux-2.6.17/include/asm-mips/cpu.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/asm-mips/cpu.h 2006-06-18 15:30:53.000000000 +0200
+@@ -104,6 +104,13 @@
+ #define PRID_IMP_SR71000 0x0400
+
+ /*
++ * These are the PRID's for when 23:16 == PRID_COMP_BROADCOM
++ */
++
++#define PRID_IMP_BCM4710 0x4000
++#define PRID_IMP_BCM3302 0x9000
++
++/*
+ * Definitions for 7:0 on legacy processors
+ */
+
+@@ -200,7 +207,9 @@
+ #define CPU_SB1A 62
+ #define CPU_74K 63
+ #define CPU_R14000 64
+-#define CPU_LAST 64
++#define CPU_BCM3302 65
++#define CPU_BCM4710 66
++#define CPU_LAST 66
+
+ /*
+ * ISA Level encodings
+diff -Nur linux-2.6.17/include/linux/pci_ids.h linux-2.6.17-owrt/include/linux/pci_ids.h
+--- linux-2.6.17/include/linux/pci_ids.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/linux/pci_ids.h 2006-06-18 15:29:23.000000000 +0200
+@@ -1906,6 +1906,7 @@
+ #define PCI_DEVICE_ID_TIGON3_5901_2 0x170e
+ #define PCI_DEVICE_ID_BCM4401 0x4401
+ #define PCI_DEVICE_ID_BCM4401B0 0x4402
++#define PCI_DEVICE_ID_BCM4713 0x4713
+
+ #define PCI_VENDOR_ID_TOPIC 0x151f
+ #define PCI_DEVICE_ID_TOPIC_TP560 0x0000
diff --git a/target/linux/brcm-2.6/patches/002-flash-map.patch b/target/linux/brcm-2.6/patches/002-flash-map.patch
new file mode 100644
index 0000000..9d56893
--- /dev/null
+++ b/target/linux/brcm-2.6/patches/002-flash-map.patch
@@ -0,0 +1,483 @@
+diff -urN linux.old/drivers/mtd/maps/bcm47xx-flash.c linux.dev/drivers/mtd/maps/bcm47xx-flash.c
+--- linux.old/drivers/mtd/maps/bcm47xx-flash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/mtd/maps/bcm47xx-flash.c 2006-06-23 19:54:06.000000000 +0200
+@@ -0,0 +1,452 @@
++/*
++ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
++ *
++ * original functions for finding root filesystem from Mike Baker
++ *
++ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Copyright 2001-2003, Broadcom Corporation
++ * All Rights Reserved.
++ *
++ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
++ *
++ * Flash mapping for BCM947XX boards
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/wait.h>
++#include <linux/config.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#ifdef CONFIG_MTD_PARTITIONS
++#include <linux/mtd/partitions.h>
++#endif
++#include <linux/squashfs_fs.h>
++#include <linux/jffs2.h>
++#include <linux/crc32.h>
++#include <asm/io.h>
++
++#include <trxhdr.h>
++
++#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
++#define NVRAM_SPACE 0x8000
++#define WINDOW_ADDR 0x1c000000
++#define WINDOW_SIZE 0x800000
++#define BUSWIDTH 2
++
++static struct mtd_info *bcm947xx_mtd;
++
++static void bcm947xx_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++#define MIPS_MEMCPY_ALIGN 4
++ map_word ret;
++ ssize_t transfer;
++ ssize_t done = 0;
++ if ((len >= MIPS_MEMCPY_ALIGN) && (!(from & (MIPS_MEMCPY_ALIGN - 1))) && (!(((unsigned int)to & (MIPS_MEMCPY_ALIGN - 1))))) {
++ done = len & ~(MIPS_MEMCPY_ALIGN - 1);
++ memcpy_fromio(to, map->virt + from, done);
++ }
++ while (done < len) {
++ ret = map->read(map, from + done);
++ transfer = len - done;
++ if (transfer > map->bankwidth)
++ transfer = map->bankwidth;
++ memcpy((void *)((unsigned long)to + done), &ret.x[0], transfer);
++ done += transfer;
++ }
++}
++
++static struct map_info bcm947xx_map = {
++ name: "Physically mapped flash",
++ size: WINDOW_SIZE,
++ bankwidth: BUSWIDTH,
++ phys: WINDOW_ADDR,
++};
++
++#ifdef CONFIG_MTD_PARTITIONS
++
++static struct mtd_partition bcm947xx_parts[] = {
++ { name: "cfe", offset: 0, size: 0, mask_flags: MTD_WRITEABLE, },
++ { name: "linux", offset: 0, size: 0, },
++ { name: "rootfs", offset: 0, size: 0, },
++ { name: "nvram", offset: 0, size: 0, },
++ { name: "OpenWrt", offset: 0, size: 0, },
++ { name: NULL, },
++};
++
++static int __init
++find_cfe_size(struct mtd_info *mtd, size_t size)
++{
++ struct trx_header *trx;
++ unsigned char buf[512];
++ int off;
++ size_t len;
++ int blocksize;
++
++ trx = (struct trx_header *) buf;
++
++ blocksize = mtd->erasesize;
++ if (blocksize < 0x10000)
++ blocksize = 0x10000;
++
++ for (off = (128*1024); off < size; off += blocksize) {
++ memset(buf, 0xe5, sizeof(buf));
++
++ /*
++ * Read into buffer
++ */
++ if (MTD_READ(mtd, off, sizeof(buf), &len, buf) ||
++ len != sizeof(buf))
++ continue;
++
++ /* found a TRX header */
++ if (le32_to_cpu(trx->magic) == TRX_MAGIC) {
++ goto found;
++ }
++ }
++
++ printk(KERN_NOTICE
++ "%s: Couldn't find bootloader size\n",
++ mtd->name);
++ return -1;
++
++ found:
++ printk(KERN_NOTICE "bootloader size: %d\n", off);
++ return off;
++
++}
++
++/*
++ * Copied from mtdblock.c
++ *
++ * Cache stuff...
++ *
++ * Since typical flash erasable sectors are much larger than what Linux's
++ * buffer cache can handle, we must implement read-modify-write on flash
++ * sectors for each block write requests. To avoid over-erasing flash sectors
++ * and to speed things up, we locally cache a whole flash sector while it is
++ * being written to until a different sector is required.
++ */
++
++static void erase_callback(struct erase_info *done)
++{
++ wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
++ wake_up(wait_q);
++}
++
++static int erase_write (struct mtd_info *mtd, unsigned long pos,
++ int len, const char *buf)
++{
++ struct erase_info erase;
++ DECLARE_WAITQUEUE(wait, current);
++ wait_queue_head_t wait_q;
++ size_t retlen;
++ int ret;
++
++ /*
++ * First, let's erase the flash block.
++ */
++
++ init_waitqueue_head(&wait_q);
++ erase.mtd = mtd;
++ erase.callback = erase_callback;
++ erase.addr = pos;
++ erase.len = len;
++ erase.priv = (u_long)&wait_q;
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ add_wait_queue(&wait_q, &wait);
++
++ ret = MTD_ERASE(mtd, &erase);
++ if (ret) {
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&wait_q, &wait);
++ printk (KERN_WARNING "erase of region [0x%lx, 0x%x] "
++ "on \"%s\" failed\n",
++ pos, len, mtd->name);
++ return ret;
++ }
++
++ schedule(); /* Wait for erase to finish. */
++ remove_wait_queue(&wait_q, &wait);
++
++ /*
++ * Next, writhe data to flash.
++ */
++
++ ret = MTD_WRITE (mtd, pos, len, &retlen, buf);
++ if (ret)
++ return ret;
++ if (retlen != len)
++ return -EIO;
++ return 0;
++}
++
++
++
++
++static int __init
++find_root(struct mtd_info *mtd, size_t size, struct mtd_partition *part)
++{
++ struct trx_header trx, *trx2;
++ unsigned char buf[512], *block;
++ int off, blocksize;
++ u32 i, crc = ~0;
++ size_t len;
++ struct squashfs_super_block *sb = (struct squashfs_super_block *) buf;
++
++ blocksize = mtd->erasesize;
++ if (blocksize < 0x10000)
++ blocksize = 0x10000;
++
++ for (off = (128*1024); off < size; off += blocksize) {
++ memset(&trx, 0xe5, sizeof(trx));
++
++ /*
++ * Read into buffer
++ */
++ if (MTD_READ(mtd, off, sizeof(trx), &len, (char *) &trx) ||
++ len != sizeof(trx))
++ continue;
++
++ /* found a TRX header */
++ if (le32_to_cpu(trx.magic) == TRX_MAGIC) {
++ part->offset = le32_to_cpu(trx.offsets[2]) ? :
++ le32_to_cpu(trx.offsets[1]);
++ part->size = le32_to_cpu(trx.len);
++
++ part->size -= part->offset;
++ part->offset += off;
++
++ goto found;
++ }
++ }
++
++ printk(KERN_NOTICE
++ "%s: Couldn't find root filesystem\n",
++ mtd->name);
++ return -1;
++
++ found:
++ if (part->size == 0)
++ return 0;
++
++ if (MTD_READ(mtd, part->offset, sizeof(buf), &len, buf) || len != sizeof(buf))
++ return 0;
++
++ if (*((__u32 *) buf) == SQUASHFS_MAGIC) {
++ printk(KERN_INFO "%s: Filesystem type: squashfs, size=0x%x\n", mtd->name, (u32) sb->bytes_used);
++
++ /* Update the squashfs partition size based on the superblock info */
++ part->size = sb->bytes_used;
++ len = part->offset + part->size;
++ len += (mtd->erasesize - 1);
++ len &= ~(mtd->erasesize - 1);
++ part->size = len - part->offset;
++ } else if (*((__u16 *) buf) == JFFS2_MAGIC_BITMASK) {
++ printk(KERN_INFO "%s: Filesystem type: jffs2\n", mtd->name);
++
++ /* Move the squashfs outside of the trx */
++ part->size = 0;
++ } else {
++ printk(KERN_INFO "%s: Filesystem type: unknown\n", mtd->name);
++ return 0;
++ }
++
++ if (trx.len != part->offset + part->size - off) {
++ /* Update the trx offsets and length */
++ trx.len = part->offset + part->size - off;
++
++ /* Update the trx crc32 */
++ for (i = (u32) &(((struct trx_header *)NULL)->flag_version); i <= trx.len; i += sizeof(buf)) {
++ if (MTD_READ(mtd, off + i, sizeof(buf), &len, buf) || len != sizeof(buf))
++ return 0;
++ crc = crc32_le(crc, buf, min(sizeof(buf), trx.len - i));
++ }
++ trx.crc32 = crc;
++
++ /* read first eraseblock from the trx */
++ block = kmalloc(mtd->erasesize, GFP_KERNEL);
++ trx2 = (struct trx_header *) block;
++ if (MTD_READ(mtd, off, mtd->erasesize, &len, block) || len != mtd->erasesize) {
++ printk("Error accessing the first trx eraseblock\n");
++ return 0;
++ }
++
++ printk("Updating TRX offsets and length:\n");
++ printk("old trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx2->offsets[0], trx2->offsets[1], trx2->offsets[2], trx2->len, trx2->crc32);
++ printk("new trx = [0x%08x, 0x%08x, 0x%08x], len=0x%08x crc32=0x%08x\n", trx.offsets[0], trx.offsets[1], trx.offsets[2], trx.len, trx.crc32);
++
++ /* Write updated trx header to the flash */
++ memcpy(block, &trx, sizeof(trx));
++ if (mtd->unlock)
++ mtd->unlock(mtd, off, mtd->erasesize);
++ erase_write(mtd, off, mtd->erasesize, block);
++ if (mtd->sync)
++ mtd->sync(mtd);
++ kfree(block);
++ printk("Done\n");
++ }
++
++ return part->size;
++}
++
++struct mtd_partition * __init
++init_mtd_partitions(struct mtd_info *mtd, size_t size)
++{
++ int cfe_size;
++
++ if ((cfe_size = find_cfe_size(mtd,size)) < 0)
++ return NULL;
++
++ /* boot loader */
++ bcm947xx_parts[0].offset = 0;
++ bcm947xx_parts[0].size = cfe_size;
++
++ /* nvram */
++ if (cfe_size != 384 * 1024) {
++ bcm947xx_parts[3].offset = size - ROUNDUP(NVRAM_SPACE, mtd->erasesize);
++ bcm947xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
++ } else {
++ /* nvram (old 128kb config partition on netgear wgt634u) */
++ bcm947xx_parts[3].offset = bcm947xx_parts[0].size;
++ bcm947xx_parts[3].size = ROUNDUP(NVRAM_SPACE, mtd->erasesize);
++ }
++
++ /* linux (kernel and rootfs) */
++ if (cfe_size != 384 * 1024) {
++ bcm947xx_parts[1].offset = bcm947xx_parts[0].size;
++ bcm947xx_parts[1].size = bcm947xx_parts[3].offset -
++ bcm947xx_parts[1].offset;
++ } else {
++ /* do not count the elf loader, which is on one block */
++ bcm947xx_parts[1].offset = bcm947xx_parts[0].size +
++ bcm947xx_parts[3].size + mtd->erasesize;
++ bcm947xx_parts[1].size = size -
++ bcm947xx_parts[0].size -
++ (2*bcm947xx_parts[3].size) -
++ mtd->erasesize;
++ }
++
++ /* find and size rootfs */
++ if (find_root(mtd,size,&bcm947xx_parts[2])==0) {
++ /* entirely jffs2 */
++ bcm947xx_parts[4].name = NULL;
++ bcm947xx_parts[2].size = size - bcm947xx_parts[2].offset -
++ bcm947xx_parts[3].size;
++ } else {
++ /* legacy setup */
++ /* calculate leftover flash, and assign it to the jffs2 partition */
++ if (cfe_size != 384 * 1024) {
++ bcm947xx_parts[4].offset = bcm947xx_parts[2].offset +
++ bcm947xx_parts[2].size;
++ if ((bcm947xx_parts[4].offset % mtd->erasesize) > 0) {
++ bcm947xx_parts[4].offset += mtd->erasesize -
++ (bcm947xx_parts[4].offset % mtd->erasesize);
++ }
++ bcm947xx_parts[4].size = bcm947xx_parts[3].offset -
++ bcm947xx_parts[4].offset;
++ } else {
++ bcm947xx_parts[4].offset = bcm947xx_parts[2].offset +
++ bcm947xx_parts[2].size;
++ if ((bcm947xx_parts[4].offset % mtd->erasesize) > 0) {
++ bcm947xx_parts[4].offset += mtd->erasesize -
++ (bcm947xx_parts[4].offset % mtd->erasesize);
++ }
++ bcm947xx_parts[4].size = size - bcm947xx_parts[3].size -
++ bcm947xx_parts[4].offset;
++ }
++ }
++
++ return bcm947xx_parts;
++}
++#endif
++
++int __init init_bcm947xx_map(void)
++{
++ size_t size;
++ int ret = 0;
++#ifdef CONFIG_MTD_PARTITIONS
++ struct mtd_partition *parts;
++ int i;
++#endif
++
++ bcm947xx_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
++
++ if (!bcm947xx_map.virt) {
++ printk("Failed to ioremap\n");
++ return -EIO;
++ }
++ simple_map_init(&bcm947xx_map);
++
++ bcm947xx_map.copy_from = bcm947xx_map_copy_from;
++
++ if (!(bcm947xx_mtd = do_map_probe("cfi_probe", &bcm947xx_map))) {
++ printk("Failed to do_map_probe\n");
++ iounmap((void *)bcm947xx_map.virt);
++ return -ENXIO;
++ }
++
++ bcm947xx_mtd->owner = THIS_MODULE;
++
++ size = bcm947xx_mtd->size;
++
++ printk(KERN_NOTICE "Flash device: 0x%x at 0x%x\n", size, WINDOW_ADDR);
++
++#ifdef CONFIG_MTD_PARTITIONS
++ parts = init_mtd_partitions(bcm947xx_mtd, size);
++ for (i = 0; parts[i].name; i++);
++ ret = add_mtd_partitions(bcm947xx_mtd, parts, i);
++ if (ret) {
++ printk(KERN_ERR "Flash: add_mtd_partitions failed\n");
++ goto fail;
++ }
++#endif
++ return 0;
++
++ fail:
++ if (bcm947xx_mtd)
++ map_destroy(bcm947xx_mtd);
++ if (bcm947xx_map.virt)
++ iounmap((void *)bcm947xx_map.virt);
++ bcm947xx_map.virt = 0;
++ return ret;
++}
++
++void __exit cleanup_bcm947xx_map(void)
++{
++#ifdef CONFIG_MTD_PARTITIONS
++ del_mtd_partitions(bcm947xx_mtd);
++#endif
++ map_destroy(bcm947xx_mtd);
++ iounmap((void *)bcm947xx_map.virt);
++}
++
++module_init(init_bcm947xx_map);
++module_exit(cleanup_bcm947xx_map);
+diff -urN linux.old/drivers/mtd/maps/Kconfig linux.dev/drivers/mtd/maps/Kconfig
+--- linux.old/drivers/mtd/maps/Kconfig 2006-06-23 19:13:51.000000000 +0200
++++ linux.dev/drivers/mtd/maps/Kconfig 2006-06-23 18:47:58.000000000 +0200
+@@ -299,6 +299,12 @@
+ Mapping for the Flaga digital module. If you don't have one, ignore
+ this setting.
+
++config MTD_BCM47XX
++ tristate "BCM47xx flash device"
++ depends on MIPS && MTD_CFI && BCM947XX
++ help
++ Support for the flash chips on the BCM947xx board.
++
+ config MTD_BEECH
+ tristate "CFI Flash device mapped on IBM 405LP Beech"
+ depends on MTD_CFI && BEECH
+diff -urN linux.old/drivers/mtd/maps/Makefile linux.dev/drivers/mtd/maps/Makefile
+--- linux.old/drivers/mtd/maps/Makefile 2006-06-23 19:13:51.000000000 +0200
++++ linux.dev/drivers/mtd/maps/Makefile 2006-06-23 18:47:58.000000000 +0200
+@@ -30,6 +30,7 @@
+ obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
+ obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
+ obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
++obj-$(CONFIG_MTD_BCM47XX) += bcm47xx-flash.o
+ obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
+ obj-$(CONFIG_MTD_IPAQ) += ipaq-flash.o
+ obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o
diff --git a/target/linux/brcm-2.6/patches/003-bcm4710_cache_fixes.patch b/target/linux/brcm-2.6/patches/003-bcm4710_cache_fixes.patch
new file mode 100644
index 0000000..c8a08eb
--- /dev/null
+++ b/target/linux/brcm-2.6/patches/003-bcm4710_cache_fixes.patch
@@ -0,0 +1,354 @@
+diff -Nur linux-2.6.17/arch/mips/kernel/genex.S linux-2.6.17-owrt/arch/mips/kernel/genex.S
+--- linux-2.6.17/arch/mips/kernel/genex.S 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/mips/kernel/genex.S 2006-06-18 15:36:58.000000000 +0200
+@@ -73,6 +73,10 @@
+ .set push
+ .set mips3
+ .set noat
++#ifdef CONFIG_BCM4710
++ nop
++ nop
++#endif
+ mfc0 k1, CP0_CAUSE
+ li k0, 31<<2
+ andi k1, k1, 0x7c
+diff -Nur linux-2.6.17/arch/mips/mm/c-r4k.c linux-2.6.17-owrt/arch/mips/mm/c-r4k.c
+--- linux-2.6.17/arch/mips/mm/c-r4k.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/mips/mm/c-r4k.c 2006-06-18 15:36:58.000000000 +0200
+@@ -14,6 +14,12 @@
+ #include <linux/mm.h>
+ #include <linux/bitops.h>
+
++#ifdef CONFIG_BCM4710
++#include "../bcm947xx/include/typedefs.h"
++#include "../bcm947xx/include/sbconfig.h"
++#include <asm/paccess.h>
++#endif
++
+ #include <asm/bcache.h>
+ #include <asm/bootinfo.h>
+ #include <asm/cache.h>
+@@ -30,6 +36,9 @@
+ #include <asm/cacheflush.h> /* for run_uncached() */
+
+
++/* For enabling BCM4710 cache workarounds */
++int bcm4710 = 0;
++
+ /*
+ * Special Variant of smp_call_function for use by cache functions:
+ *
+@@ -94,7 +103,9 @@
+ {
+ unsigned long dc_lsize = cpu_dcache_line_size();
+
+- if (dc_lsize == 16)
++ if (bcm4710)
++ r4k_blast_dcache_page = blast_dcache_page;
++ else if (dc_lsize == 16)
+ r4k_blast_dcache_page = blast_dcache16_page;
+ else if (dc_lsize == 32)
+ r4k_blast_dcache_page = r4k_blast_dcache_page_dc32;
+@@ -106,7 +117,9 @@
+ {
+ unsigned long dc_lsize = cpu_dcache_line_size();
+
+- if (dc_lsize == 16)
++ if (bcm4710)
++ r4k_blast_dcache_page_indexed = blast_dcache_page_indexed;
++ else if (dc_lsize == 16)
+ r4k_blast_dcache_page_indexed = blast_dcache16_page_indexed;
+ else if (dc_lsize == 32)
+ r4k_blast_dcache_page_indexed = blast_dcache32_page_indexed;
+@@ -118,7 +131,9 @@
+ {
+ unsigned long dc_lsize = cpu_dcache_line_size();
+
+- if (dc_lsize == 16)
++ if (bcm4710)
++ r4k_blast_dcache = blast_dcache;
++ else if (dc_lsize == 16)
+ r4k_blast_dcache = blast_dcache16;
+ else if (dc_lsize == 32)
+ r4k_blast_dcache = blast_dcache32;
+@@ -683,6 +698,8 @@
+ unsigned long addr = (unsigned long) arg;
+
+ R4600_HIT_CACHEOP_WAR_IMPL;
++ BCM4710_PROTECTED_FILL_TLB(addr);
++ BCM4710_PROTECTED_FILL_TLB(addr + 4);
+ protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
+ if (!cpu_icache_snoops_remote_store && scache_size)
+ protected_writeback_scache_line(addr & ~(sc_lsize - 1));
+@@ -1189,6 +1206,16 @@
+ static inline void coherency_setup(void)
+ {
+ change_c0_config(CONF_CM_CMASK, CONF_CM_DEFAULT);
++#if defined(CONFIG_BCM4310) || defined(CONFIG_BCM4704) || defined(CONFIG_BCM5365)
++ if (BCM330X(current_cpu_data.processor_id)) {
++ __u32 cm = read_c0_diag();
++ /* Enable icache */
++ cm |= (1 << 31);
++ /* Enable dcache */
++ cm |= (1 << 30);
++ write_c0_diag(cm);
++ }
++#endif
+
+ /*
+ * c0_status.cu=0 specifies that updates by the sc instruction use
+@@ -1227,6 +1254,15 @@
+
+ /* Default cache error handler for R4000 and R5000 family */
+ set_uncached_handler (0x100, &except_vec2_generic, 0x80);
++
++ /* Check if special workarounds are required */
++#ifdef CONFIG_BCM4710
++ if (current_cpu_data.cputype == CPU_BCM4710 && (current_cpu_data.processor_id & 0xff) == 0) {
++ printk("Enabling BCM4710A0 cache workarounds.\n");
++ bcm4710 = 1;
++ } else
++#endif
++ bcm4710 = 0;
+
+ probe_pcache();
+ setup_scache();
+diff -Nur linux-2.6.17/arch/mips/mm/tlbex.c linux-2.6.17-owrt/arch/mips/mm/tlbex.c
+--- linux-2.6.17/arch/mips/mm/tlbex.c 2006-06-18 15:34:19.000000000 +0200
++++ linux-2.6.17-owrt/arch/mips/mm/tlbex.c 2006-06-18 15:36:58.000000000 +0200
+@@ -38,6 +38,10 @@
+
+ /* #define DEBUG_TLB */
+
++#ifdef CONFIG_BCM4710
++extern int bcm4710;
++#endif
++
+ static __init int __attribute__((unused)) r45k_bvahwbug(void)
+ {
+ /* XXX: We should probe for the presence of this bug, but we don't. */
+@@ -1184,6 +1188,12 @@
+ memset(relocs, 0, sizeof(relocs));
+ memset(final_handler, 0, sizeof(final_handler));
+
++#ifdef CONFIG_BCM4710
++ if (bcm4710) {
++ i_nop(&p);
++ }
++#endif
++
+ /*
+ * create the plain linear handler
+ */
+diff -Nur linux-2.6.17/include/asm-mips/r4kcache.h linux-2.6.17-owrt/include/asm-mips/r4kcache.h
+--- linux-2.6.17/include/asm-mips/r4kcache.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/asm-mips/r4kcache.h 2006-06-18 15:56:57.000000000 +0200
+@@ -17,6 +17,18 @@
+ #include <asm/cpu-features.h>
+ #include <asm/mipsmtregs.h>
+
++#ifdef CONFIG_BCM4710
++#define BCM4710_DUMMY_RREG() (((sbconfig_t *)(KSEG1ADDR(SB_ENUM_BASE + SBCONFIGOFF)))->sbimstate)
++
++#define BCM4710_FILL_TLB(addr) (*(volatile unsigned long *)(addr))
++#define BCM4710_PROTECTED_FILL_TLB(addr) ({ unsigned long x; get_dbe(x, (volatile unsigned long *)(addr)); })
++#else
++#define BCM4710_DUMMY_RREG()
++
++#define BCM4710_FILL_TLB(addr)
++#define BCM4710_PROTECTED_FILL_TLB(addr)
++#endif
++
+ /*
+ * This macro return a properly sign-extended address suitable as base address
+ * for indexed cache operations. Two issues here:
+@@ -150,6 +162,7 @@
+ static inline void flush_dcache_line_indexed(unsigned long addr)
+ {
+ __dflush_prologue
++ BCM4710_DUMMY_RREG();
+ cache_op(Index_Writeback_Inv_D, addr);
+ __dflush_epilogue
+ }
+@@ -169,6 +182,7 @@
+ static inline void flush_dcache_line(unsigned long addr)
+ {
+ __dflush_prologue
++ BCM4710_DUMMY_RREG();
+ cache_op(Hit_Writeback_Inv_D, addr);
+ __dflush_epilogue
+ }
+@@ -176,6 +190,7 @@
+ static inline void invalidate_dcache_line(unsigned long addr)
+ {
+ __dflush_prologue
++ BCM4710_DUMMY_RREG();
+ cache_op(Hit_Invalidate_D, addr);
+ __dflush_epilogue
+ }
+@@ -208,6 +223,7 @@
+ */
+ static inline void protected_flush_icache_line(unsigned long addr)
+ {
++ BCM4710_DUMMY_RREG();
+ protected_cache_op(Hit_Invalidate_I, addr);
+ }
+
+@@ -219,6 +235,7 @@
+ */
+ static inline void protected_writeback_dcache_line(unsigned long addr)
+ {
++ BCM4710_DUMMY_RREG();
+ protected_cache_op(Hit_Writeback_Inv_D, addr);
+ }
+
+@@ -339,8 +356,52 @@
+ : "r" (base), \
+ "i" (op));
+
++static inline void blast_dcache(void)
++{
++ unsigned long start = KSEG0;
++ unsigned long dcache_size = current_cpu_data.dcache.waysize * current_cpu_data.dcache.ways;
++ unsigned long end = (start + dcache_size);
++
++ do {
++ BCM4710_DUMMY_RREG();
++ cache_op(Index_Writeback_Inv_D, start);
++ start += current_cpu_data.dcache.linesz;
++ } while(start < end);
++}
++
++static inline void blast_dcache_page(unsigned long page)
++{
++ unsigned long start = page;
++ unsigned long end = start + PAGE_SIZE;
++
++ BCM4710_FILL_TLB(start);
++ do {
++ BCM4710_DUMMY_RREG();
++ cache_op(Hit_Writeback_Inv_D, start);
++ start += current_cpu_data.dcache.linesz;
++ } while(start < end);
++}
++
++static inline void blast_dcache_page_indexed(unsigned long page)
++{
++ unsigned long start = page;
++ unsigned long end = start + PAGE_SIZE;
++ unsigned long ws_inc = 1UL << current_cpu_data.dcache.waybit;
++ unsigned long ws_end = current_cpu_data.dcache.ways <<
++ current_cpu_data.dcache.waybit;
++ unsigned long ws, addr;
++ for (ws = 0; ws < ws_end; ws += ws_inc) {
++ start = page + ws;
++ for (addr = start; addr < end; addr += current_cpu_data.dcache.linesz) {
++ BCM4710_DUMMY_RREG();
++ cache_op(Index_Writeback_Inv_D, addr);
++ }
++ }
++}
++
++
+ /* build blast_xxx, blast_xxx_page, blast_xxx_page_indexed */
+-#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize) \
++#define __BUILD_BLAST_CACHE(pfx, desc, indexop, hitop, lsize, war) \
+ static inline void blast_##pfx##cache##lsize(void) \
+ { \
+ unsigned long start = INDEX_BASE; \
+@@ -352,6 +413,7 @@
+ \
+ __##pfx##flush_prologue \
+ \
++ war \
+ for (ws = 0; ws < ws_end; ws += ws_inc) \
+ for (addr = start; addr < end; addr += lsize * 32) \
+ cache##lsize##_unroll32(addr|ws,indexop); \
+@@ -366,6 +428,7 @@
+ \
+ __##pfx##flush_prologue \
+ \
++ war \
+ do { \
+ cache##lsize##_unroll32(start,hitop); \
+ start += lsize * 32; \
+@@ -384,6 +447,8 @@
+ current_cpu_data.desc.waybit; \
+ unsigned long ws, addr; \
+ \
++ war \
++ \
+ __##pfx##flush_prologue \
+ \
+ for (ws = 0; ws < ws_end; ws += ws_inc) \
+@@ -393,24 +458,25 @@
+ __##pfx##flush_epilogue \
+ }
+
+-__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16)
+-__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16)
+-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16)
+-__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32)
+-__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32)
+-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32)
+-__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64)
+-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64)
+-__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128)
++__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 16, )
++__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 16, BCM4710_FILL_TLB(start);)
++__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 16, )
++__BUILD_BLAST_CACHE(d, dcache, Index_Writeback_Inv_D, Hit_Writeback_Inv_D, 32, )
++__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 32, BCM4710_FILL_TLB(start);)
++__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 32, )
++__BUILD_BLAST_CACHE(i, icache, Index_Invalidate_I, Hit_Invalidate_I, 64, BCM4710_FILL_TLB(start);)
++__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 64, )
++__BUILD_BLAST_CACHE(s, scache, Index_Writeback_Inv_SD, Hit_Writeback_Inv_SD, 128, )
+
+ /* build blast_xxx_range, protected_blast_xxx_range */
+-#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot) \
++#define __BUILD_BLAST_CACHE_RANGE(pfx, desc, hitop, prot, war) \
+ static inline void prot##blast_##pfx##cache##_range(unsigned long start, \
+ unsigned long end) \
+ { \
+ unsigned long lsize = cpu_##desc##_line_size(); \
+ unsigned long addr = start & ~(lsize - 1); \
+ unsigned long aend = (end - 1) & ~(lsize - 1); \
++ war \
+ \
+ __##pfx##flush_prologue \
+ \
+@@ -424,13 +490,13 @@
+ __##pfx##flush_epilogue \
+ }
+
+-__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_)
+-__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_)
+-__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_)
+-__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, )
+-__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, )
++__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, protected_, BCM4710_PROTECTED_FILL_TLB(addr); BCM4710_PROTECTED_FILL_TLB(aend);)
++__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, protected_, )
++__BUILD_BLAST_CACHE_RANGE(i, icache, Hit_Invalidate_I, protected_, )
++__BUILD_BLAST_CACHE_RANGE(d, dcache, Hit_Writeback_Inv_D, , BCM4710_FILL_TLB(addr); BCM4710_FILL_TLB(aend);)
++__BUILD_BLAST_CACHE_RANGE(s, scache, Hit_Writeback_Inv_SD, , )
+ /* blast_inv_dcache_range */
+-__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, )
+-__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, )
++__BUILD_BLAST_CACHE_RANGE(inv_d, dcache, Hit_Invalidate_D, , )
++__BUILD_BLAST_CACHE_RANGE(inv_s, scache, Hit_Invalidate_SD, , )
+
+ #endif /* _ASM_R4KCACHE_H */
+diff -Nur linux-2.6.17/include/asm-mips/stackframe.h linux-2.6.17-owrt/include/asm-mips/stackframe.h
+--- linux-2.6.17/include/asm-mips/stackframe.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/asm-mips/stackframe.h 2006-06-18 15:36:58.000000000 +0200
+@@ -361,6 +361,10 @@
+ .macro RESTORE_SP_AND_RET
+ LONG_L sp, PT_R29(sp)
+ .set mips3
++#ifdef CONFIG_BCM4710
++ nop
++ nop
++#endif
+ eret
+ .set mips0
+ .endm
diff --git a/target/linux/brcm-2.6/patches/004-b44_bcm47xx_support.patch b/target/linux/brcm-2.6/patches/004-b44_bcm47xx_support.patch
new file mode 100644
index 0000000..15e4297
--- /dev/null
+++ b/target/linux/brcm-2.6/patches/004-b44_bcm47xx_support.patch
@@ -0,0 +1,699 @@
+diff -Nur linux-2.6.17/drivers/net/b44.c linux-2.6.17-owrt/drivers/net/b44.c
+--- linux-2.6.17/drivers/net/b44.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/drivers/net/b44.c 2006-06-18 16:24:14.000000000 +0200
+@@ -1,7 +1,9 @@
+-/* b44.c: Broadcom 4400 device driver.
++/* b44.c: Broadcom 4400/47xx device driver.
+ *
+ * Copyright (C) 2002 David S. Miller (davem@redhat.com)
+- * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
++ * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi)
++ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
++ * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org)
+ * Copyright (C) 2006 Broadcom Corporation.
+ *
+ * Distribute under GPL.
+@@ -32,6 +34,28 @@
+ #define DRV_MODULE_VERSION "1.00"
+ #define DRV_MODULE_RELDATE "Apr 7, 2006"
+
++#ifdef CONFIG_BCM947XX
++extern char *nvram_get(char *name);
++static inline void e_aton(char *str, char *dest)
++{
++ int i = 0;
++
++ if (str == NULL) {
++ memset(dest, 0, 6);
++ return;
++ }
++
++ for (;;) {
++ dest[i++] = (char) simple_strtoul(str, NULL, 16);
++ str += 2;
++ if (!*str++ || i == 6)
++ break;
++ }
++}
++
++static int b44_4713_instance;
++#endif
++
+ #define B44_DEF_MSG_ENABLE \
+ (NETIF_MSG_DRV | \
+ NETIF_MSG_PROBE | \
+@@ -78,8 +102,8 @@
+ static char version[] __devinitdata =
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+-MODULE_AUTHOR("Florian Schirmer, Pekka Pietikainen, David S. Miller");
+-MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver");
++MODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller");
++MODULE_DESCRIPTION("Broadcom 4400/47xx 10/100 PCI ethernet driver");
+ MODULE_LICENSE("GPL");
+ MODULE_VERSION(DRV_MODULE_VERSION);
+
+@@ -94,6 +118,10 @@
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
++#ifdef CONFIG_BCM947XX
++ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4713,
++ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
++#endif
+ { } /* terminate list with empty entry */
+ };
+
+@@ -132,17 +160,6 @@
+ dma_desc_sync_size, dir);
+ }
+
+-static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
+-{
+- return readl(bp->regs + reg);
+-}
+-
+-static inline void bw32(const struct b44 *bp,
+- unsigned long reg, unsigned long val)
+-{
+- writel(val, bp->regs + reg);
+-}
+-
+ static int b44_wait_bit(struct b44 *bp, unsigned long reg,
+ u32 bit, unsigned long timeout, const int clear)
+ {
+@@ -269,6 +286,10 @@
+ break;
+ };
+ #endif
++#ifdef CONFIG_BCM947XX
++ if (bp->pdev->device == PCI_DEVICE_ID_BCM4713)
++ return b44_4713_instance++;
++#endif
+ return 0;
+ }
+
+@@ -278,6 +299,30 @@
+ == SBTMSLOW_CLOCK);
+ }
+
++#ifdef CONFIG_BCM947XX
++static inline void __b44_cam_read(struct b44 *bp, unsigned char *data, int index)
++{
++ u32 val;
++
++ bw32(bp, B44_CAM_CTRL, (CAM_CTRL_READ |
++ (index << CAM_CTRL_INDEX_SHIFT)));
++
++ b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
++
++ val = br32(bp, B44_CAM_DATA_LO);
++
++ data[2] = (val >> 24) & 0xFF;
++ data[3] = (val >> 16) & 0xFF;
++ data[4] = (val >> 8) & 0xFF;
++ data[5] = (val >> 0) & 0xFF;
++
++ val = br32(bp, B44_CAM_DATA_HI);
++
++ data[0] = (val >> 8) & 0xFF;
++ data[1] = (val >> 0) & 0xFF;
++}
++#endif
++
+ static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
+ {
+ u32 val;
+@@ -314,14 +359,14 @@
+ bw32(bp, B44_IMASK, bp->imask);
+ }
+
+-static int b44_readphy(struct b44 *bp, int reg, u32 *val)
++static int __b44_readphy(struct b44 *bp, int phy_addr, int reg, u32 *val)
+ {
+ int err;
+
+ bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
+ bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
+ (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) |
+- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
++ (phy_addr << MDIO_DATA_PMD_SHIFT) |
+ (reg << MDIO_DATA_RA_SHIFT) |
+ (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT)));
+ err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
+@@ -330,18 +375,34 @@
+ return err;
+ }
+
+-static int b44_writephy(struct b44 *bp, int reg, u32 val)
++static int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val)
+ {
+ bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
+ bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
+ (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) |
+- (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
++ (phy_addr << MDIO_DATA_PMD_SHIFT) |
+ (reg << MDIO_DATA_RA_SHIFT) |
+ (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) |
+ (val & MDIO_DATA_DATA)));
+ return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
+ }
+
++static inline int b44_readphy(struct b44 *bp, int reg, u32 *val)
++{
++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
++ return 0;
++
++ return __b44_readphy(bp, bp->phy_addr, reg, val);
++}
++
++static inline int b44_writephy(struct b44 *bp, int reg, u32 val)
++{
++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
++ return 0;
++
++ return __b44_writephy(bp, bp->phy_addr, reg, val);
++}
++
+ /* miilib interface */
+ /* FIXME FIXME: phy_id is ignored, bp->phy_addr use is unconditional
+ * due to code existing before miilib use was added to this driver.
+@@ -370,6 +431,8 @@
+ u32 val;
+ int err;
+
++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
++ return 0;
+ err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
+ if (err)
+ return err;
+@@ -433,6 +496,22 @@
+ u32 val;
+ int err;
+
++#ifdef CONFIG_BCM947XX
++ /*
++ * workaround for bad hardware design in Linksys WAP54G v1.0
++ * see https://dev.openwrt.org/ticket/146
++ * check and reset bit "isolate"
++ */
++ if ((bp->pdev->device == PCI_DEVICE_ID_BCM4713) &&
++ (atoi(nvram_get("boardnum")) == 2) &&
++ (__b44_readphy(bp, 0, MII_BMCR, &val) == 0) &&
++ (val & BMCR_ISOLATE) &&
++ (__b44_writephy(bp, 0, MII_BMCR, val & ~BMCR_ISOLATE) != 0)) {
++ printk(KERN_WARNING PFX "PHY: cannot reset MII transceiver isolate bit.\n");
++ }
++#endif
++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
++ return 0;
+ if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
+ goto out;
+ if ((err = b44_writephy(bp, B44_MII_ALEDCTRL,
+@@ -528,6 +607,19 @@
+ {
+ u32 bmsr, aux;
+
++ if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
++ bp->flags |= B44_FLAG_100_BASE_T;
++ bp->flags |= B44_FLAG_FULL_DUPLEX;
++ if (!netif_carrier_ok(bp->dev)) {
++ u32 val = br32(bp, B44_TX_CTRL);
++ val |= TX_CTRL_DUPLEX;
++ bw32(bp, B44_TX_CTRL, val);
++ netif_carrier_on(bp->dev);
++ b44_link_report(bp);
++ }
++ return;
++ }
++
+ if (!b44_readphy(bp, MII_BMSR, &bmsr) &&
+ !b44_readphy(bp, B44_MII_AUXCTRL, &aux) &&
+ (bmsr != 0xffff)) {
+@@ -1282,9 +1374,10 @@
+ bw32(bp, B44_DMARX_CTRL, 0);
+ bp->rx_prod = bp->rx_cons = 0;
+ } else {
+- ssb_pci_setup(bp, (bp->core_unit == 0 ?
+- SBINTVEC_ENET0 :
+- SBINTVEC_ENET1));
++ if (bp->pdev->device != PCI_DEVICE_ID_BCM4713)
++ ssb_pci_setup(bp, (bp->core_unit == 0 ?
++ SBINTVEC_ENET0 :
++ SBINTVEC_ENET1));
+ }
+
+ ssb_core_reset(bp);
+@@ -1292,8 +1385,14 @@
+ b44_clear_stats(bp);
+
+ /* Make PHY accessible. */
+- bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
++ if (bp->pdev->device == PCI_DEVICE_ID_BCM4713)
++ bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
++ (((100000000 + (B44_MDC_RATIO / 2)) / B44_MDC_RATIO)
++ & MDIO_CTRL_MAXF_MASK)));
++ else
++ bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
+ (0x0d & MDIO_CTRL_MAXF_MASK)));
++
+ br32(bp, B44_MDIO_CTRL);
+
+ if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) {
+@@ -1837,18 +1936,297 @@
+ .get_perm_addr = ethtool_op_get_perm_addr,
+ };
+
++static int b44_ethtool_ioctl (struct net_device *dev, void __user *useraddr)
++{
++ struct b44 *bp = dev->priv;
++ struct pci_dev *pci_dev = bp->pdev;
++ u32 ethcmd;
++
++ if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
++ return -EFAULT;
++
++ switch (ethcmd) {
++ case ETHTOOL_GDRVINFO: {
++ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
++ strcpy (info.driver, DRV_MODULE_NAME);
++ strcpy (info.version, DRV_MODULE_VERSION);
++ memset(&info.fw_version, 0, sizeof(info.fw_version));
++ strcpy (info.bus_info, pci_name(pci_dev));
++ info.eedump_len = 0;
++ info.regdump_len = 0;
++ if (copy_to_user (useraddr, &info, sizeof (info)))
++ return -EFAULT;
++ return 0;
++ }
++
++ case ETHTOOL_GSET: {
++ struct ethtool_cmd cmd = { ETHTOOL_GSET };
++
++ if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
++ return -EAGAIN;
++ cmd.supported = (SUPPORTED_Autoneg);
++ cmd.supported |= (SUPPORTED_100baseT_Half |
++ SUPPORTED_100baseT_Full |
++ SUPPORTED_10baseT_Half |
++ SUPPORTED_10baseT_Full |
++ SUPPORTED_MII);
++
++ cmd.advertising = 0;
++ if (bp->flags & B44_FLAG_ADV_10HALF)
++ cmd.advertising |= ADVERTISE_10HALF;
++ if (bp->flags & B44_FLAG_ADV_10FULL)
++ cmd.advertising |= ADVERTISE_10FULL;
++ if (bp->flags & B44_FLAG_ADV_100HALF)
++ cmd.advertising |= ADVERTISE_100HALF;
++ if (bp->flags & B44_FLAG_ADV_100FULL)
++ cmd.advertising |= ADVERTISE_100FULL;
++ cmd.advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
++ cmd.speed = (bp->flags & B44_FLAG_100_BASE_T) ?
++ SPEED_100 : SPEED_10;
++ cmd.duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ?
++ DUPLEX_FULL : DUPLEX_HALF;
++ cmd.port = 0;
++ cmd.phy_address = bp->phy_addr;
++ cmd.transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ?
++ XCVR_INTERNAL : XCVR_EXTERNAL;
++ cmd.autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ?
++ AUTONEG_DISABLE : AUTONEG_ENABLE;
++ cmd.maxtxpkt = 0;
++ cmd.maxrxpkt = 0;
++ if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
++ return -EFAULT;
++ return 0;
++ }
++ case ETHTOOL_SSET: {
++ struct ethtool_cmd cmd;
++
++ if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
++ return -EAGAIN;
++
++ if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
++ return -EFAULT;
++
++ /* We do not support gigabit. */
++ if (cmd.autoneg == AUTONEG_ENABLE) {
++ if (cmd.advertising &
++ (ADVERTISED_1000baseT_Half |
++ ADVERTISED_1000baseT_Full))
++ return -EINVAL;
++ } else if ((cmd.speed != SPEED_100 &&
++ cmd.speed != SPEED_10) ||
++ (cmd.duplex != DUPLEX_HALF &&
++ cmd.duplex != DUPLEX_FULL)) {
++ return -EINVAL;
++ }
++
++ spin_lock_irq(&bp->lock);
++
++ if (cmd.autoneg == AUTONEG_ENABLE) {
++ bp->flags &= ~B44_FLAG_FORCE_LINK;
++ bp->flags &= ~(B44_FLAG_ADV_10HALF |
++ B44_FLAG_ADV_10FULL |
++ B44_FLAG_ADV_100HALF |
++ B44_FLAG_ADV_100FULL);
++ if (cmd.advertising & ADVERTISE_10HALF)
++ bp->flags |= B44_FLAG_ADV_10HALF;
++ if (cmd.advertising & ADVERTISE_10FULL)
++ bp->flags |= B44_FLAG_ADV_10FULL;
++ if (cmd.advertising & ADVERTISE_100HALF)
++ bp->flags |= B44_FLAG_ADV_100HALF;
++ if (cmd.advertising & ADVERTISE_100FULL)
++ bp->flags |= B44_FLAG_ADV_100FULL;
++ } else {
++ bp->flags |= B44_FLAG_FORCE_LINK;
++ if (cmd.speed == SPEED_100)
++ bp->flags |= B44_FLAG_100_BASE_T;
++ if (cmd.duplex == DUPLEX_FULL)
++ bp->flags |= B44_FLAG_FULL_DUPLEX;
++ }
++
++ b44_setup_phy(bp);
++
++ spin_unlock_irq(&bp->lock);
++
++ return 0;
++ }
++
++ case ETHTOOL_GMSGLVL: {
++ struct ethtool_value edata = { ETHTOOL_GMSGLVL };
++ edata.data = bp->msg_enable;
++ if (copy_to_user(useraddr, &edata, sizeof(edata)))
++ return -EFAULT;
++ return 0;
++ }
++ case ETHTOOL_SMSGLVL: {
++ struct ethtool_value edata;
++ if (copy_from_user(&edata, useraddr, sizeof(edata)))
++ return -EFAULT;
++ bp->msg_enable = edata.data;
++ return 0;
++ }
++ case ETHTOOL_NWAY_RST: {
++ u32 bmcr;
++ int r;
++
++ spin_lock_irq(&bp->lock);
++ b44_readphy(bp, MII_BMCR, &bmcr);
++ b44_readphy(bp, MII_BMCR, &bmcr);
++ r = -EINVAL;
++ if (bmcr & BMCR_ANENABLE) {
++ b44_writephy(bp, MII_BMCR,
++ bmcr | BMCR_ANRESTART);
++ r = 0;
++ }
++ spin_unlock_irq(&bp->lock);
++
++ return r;
++ }
++ case ETHTOOL_GLINK: {
++ struct ethtool_value edata = { ETHTOOL_GLINK };
++ edata.data = netif_carrier_ok(bp->dev) ? 1 : 0;
++ if (copy_to_user(useraddr, &edata, sizeof(edata)))
++ return -EFAULT;
++ return 0;
++ }
++ case ETHTOOL_GRINGPARAM: {
++ struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
++
++ ering.rx_max_pending = B44_RX_RING_SIZE - 1;
++ ering.rx_pending = bp->rx_pending;
++
++ /* XXX ethtool lacks a tx_max_pending, oops... */
++
++ if (copy_to_user(useraddr, &ering, sizeof(ering)))
++ return -EFAULT;
++ return 0;
++ }
++ case ETHTOOL_SRINGPARAM: {
++ struct ethtool_ringparam ering;
++
++ if (copy_from_user(&ering, useraddr, sizeof(ering)))
++ return -EFAULT;
++
++ if ((ering.rx_pending > B44_RX_RING_SIZE - 1) ||
++ (ering.rx_mini_pending != 0) ||
++ (ering.rx_jumbo_pending != 0) ||
++ (ering.tx_pending > B44_TX_RING_SIZE - 1))
++ return -EINVAL;
++
++ spin_lock_irq(&bp->lock);
++
++ bp->rx_pending = ering.rx_pending;
++ bp->tx_pending = ering.tx_pending;
++
++ b44_halt(bp);
++ b44_init_rings(bp);
++ b44_init_hw(bp);
++ netif_wake_queue(bp->dev);
++ spin_unlock_irq(&bp->lock);
++
++ b44_enable_ints(bp);
++
++ return 0;
++ }
++ case ETHTOOL_GPAUSEPARAM: {
++ struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM };
++
++ epause.autoneg =
++ (bp->flags & B44_FLAG_PAUSE_AUTO) != 0;
++ epause.rx_pause =
++ (bp->flags & B44_FLAG_RX_PAUSE) != 0;
++ epause.tx_pause =
++ (bp->flags & B44_FLAG_TX_PAUSE) != 0;
++ if (copy_to_user(useraddr, &epause, sizeof(epause)))
++ return -EFAULT;
++ return 0;
++ }
++ case ETHTOOL_SPAUSEPARAM: {
++ struct ethtool_pauseparam epause;
++
++ if (copy_from_user(&epause, useraddr, sizeof(epause)))
++ return -EFAULT;
++
++ spin_lock_irq(&bp->lock);
++ if (epause.autoneg)
++ bp->flags |= B44_FLAG_PAUSE_AUTO;
++ else
++ bp->flags &= ~B44_FLAG_PAUSE_AUTO;
++ if (epause.rx_pause)
++ bp->flags |= B44_FLAG_RX_PAUSE;
++ else
++ bp->flags &= ~B44_FLAG_RX_PAUSE;
++ if (epause.tx_pause)
++ bp->flags |= B44_FLAG_TX_PAUSE;
++ else
++ bp->flags &= ~B44_FLAG_TX_PAUSE;
++ if (bp->flags & B44_FLAG_PAUSE_AUTO) {
++ b44_halt(bp);
++ b44_init_rings(bp);
++ b44_init_hw(bp);
++ } else {
++ __b44_set_flow_ctrl(bp, bp->flags);
++ }
++ spin_unlock_irq(&bp->lock);
++
++ b44_enable_ints(bp);
++
++ return 0;
++ }
++ };
++
++ return -EOPNOTSUPP;
++}
++
+ static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ {
+ struct mii_ioctl_data *data = if_mii(ifr);
+ struct b44 *bp = netdev_priv(dev);
+ int err = -EINVAL;
+
+- if (!netif_running(dev))
++ if (bp->pdev->device != PCI_DEVICE_ID_BCM4713) {
++ if (!netif_running(dev))
++ goto out;
++
++ spin_lock_irq(&bp->lock);
++ err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL);
++ spin_unlock_irq(&bp->lock);
+ goto out;
++ }
+
+- spin_lock_irq(&bp->lock);
+- err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL);
+- spin_unlock_irq(&bp->lock);
++ switch (cmd) {
++ case SIOCETHTOOL:
++ return b44_ethtool_ioctl(dev, (void __user*) ifr->ifr_data);
++
++ case SIOCGMIIPHY:
++ data->phy_id = bp->phy_addr;
++
++ /* fallthru */
++ case SIOCGMIIREG: {
++ u32 mii_regval;
++ spin_lock_irq(&bp->lock);
++ err = __b44_readphy(bp, data->phy_id & 0x1f, data->reg_num & 0x1f, &mii_regval);
++ spin_unlock_irq(&bp->lock);
++
++ data->val_out = mii_regval;
++
++ return err;
++ }
++
++ case SIOCSMIIREG:
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++
++ spin_lock_irq(&bp->lock);
++ err = __b44_writephy(bp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
++ spin_unlock_irq(&bp->lock);
++
++ return err;
++
++ default:
++ break;
++ };
++ return -EOPNOTSUPP;
++
+ out:
+ return err;
+ }
+@@ -1868,27 +2246,60 @@
+ static int __devinit b44_get_invariants(struct b44 *bp)
+ {
+ u8 eeprom[128];
+- int err;
++ u8 buf[32];
++ int err = 0;
++ unsigned long flags;
++
++#ifdef CONFIG_BCM947XX
++ if (bp->pdev->device == PCI_DEVICE_ID_BCM4713) {
++ /*
++ * BCM47xx boards don't have a EEPROM. The MAC is stored in
++ * a NVRAM area somewhere in the flash memory.
++ */
++ sprintf(buf, "et%dmacaddr", b44_4713_instance);
++ if (nvram_get(buf)) {
++ e_aton(nvram_get(buf), bp->dev->dev_addr);
++ } else {
++ /*
++ * Getting the MAC out of NVRAM failed. To make it work
++ * here, we simply rely on the bootloader to write the
++ * MAC into the CAM.
++ */
++ spin_lock_irqsave(&bp->lock, flags);
++ __b44_cam_read(bp, bp->dev->dev_addr, 0);
++ spin_unlock_irqrestore(&bp->lock, flags);
++ }
+
+- err = b44_read_eeprom(bp, &eeprom[0]);
+- if (err)
+- goto out;
++ /*
++ * BCM47xx boards don't have a PHY. Usually there is a switch
++ * chip with multiple PHYs connected to the PHY port.
++ */
++ bp->phy_addr = B44_PHY_ADDR_NO_PHY;
++ bp->dma_offset = 0;
++ } else
++#endif
++ {
++ err = b44_read_eeprom(bp, &eeprom[0]);
++ if (err)
++ goto out;
+
+- bp->dev->dev_addr[0] = eeprom[79];
+- bp->dev->dev_addr[1] = eeprom[78];
+- bp->dev->dev_addr[2] = eeprom[81];
+- bp->dev->dev_addr[3] = eeprom[80];
+- bp->dev->dev_addr[4] = eeprom[83];
+- bp->dev->dev_addr[5] = eeprom[82];
++ bp->dev->dev_addr[0] = eeprom[79];
++ bp->dev->dev_addr[1] = eeprom[78];
++ bp->dev->dev_addr[2] = eeprom[81];
++ bp->dev->dev_addr[3] = eeprom[80];
++ bp->dev->dev_addr[4] = eeprom[83];
++ bp->dev->dev_addr[5] = eeprom[82];
+
+- if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){
+- printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n");
+- return -EINVAL;
+- }
++ if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){
++ printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n");
++ return -EINVAL;
++ }
+
+- memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
++ memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
+
+- bp->phy_addr = eeprom[90] & 0x1f;
++ bp->phy_addr = eeprom[90] & 0x1f;
++ bp->dma_offset = SB_PCI_DMA;
++ }
+
+ /* With this, plus the rx_header prepended to the data by the
+ * hardware, we'll land the ethernet header on a 2-byte boundary.
+@@ -1898,7 +2309,6 @@
+ bp->imask = IMASK_DEF;
+
+ bp->core_unit = ssb_core_unit(bp);
+- bp->dma_offset = SB_PCI_DMA;
+
+ /* XXX - really required?
+ bp->flags |= B44_FLAG_BUGGY_TXPTR;
+@@ -2048,11 +2458,17 @@
+ */
+ b44_chip_reset(bp);
+
+- printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
++ printk(KERN_INFO "%s: Broadcom %s 10/100BaseT Ethernet ", dev->name,
++ (pdev->device == PCI_DEVICE_ID_BCM4713) ? "47xx" : "4400");
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c", dev->dev_addr[i],
+ i == 5 ? '\n' : ':');
+
++ /* Initialize phy */
++ spin_lock_irq(&bp->lock);
++ b44_chip_reset(bp);
++ spin_unlock_irq(&bp->lock);
++
+ return 0;
+
+ err_out_iounmap:
+diff -Nur linux-2.6.17/drivers/net/b44.h linux-2.6.17-owrt/drivers/net/b44.h
+--- linux-2.6.17/drivers/net/b44.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/drivers/net/b44.h 2006-06-18 16:01:10.000000000 +0200
+@@ -292,6 +292,10 @@
+ #define SSB_PCI_MASK1 0xfc000000
+ #define SSB_PCI_MASK2 0xc0000000
+
++#define br32(bp, REG) readl((void *)bp->regs + (REG))
++#define bw32(bp, REG,VAL) writel((VAL), (void *)bp->regs + (REG))
++#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0)
++
+ /* 4400 PHY registers */
+ #define B44_MII_AUXCTRL 24 /* Auxiliary Control */
+ #define MII_AUXCTRL_DUPLEX 0x0001 /* Full Duplex */
+@@ -345,6 +349,8 @@
+ };
+
+ #define B44_MCAST_TABLE_SIZE 32
++#define B44_PHY_ADDR_NO_PHY 30
++#define B44_MDC_RATIO 5000000
+
+ #define B44_STAT_REG_DECLARE \
+ _B44(tx_good_octets) \
+@@ -420,6 +426,7 @@
+
+ u32 dma_offset;
+ u32 flags;
++#define B44_FLAG_INIT_COMPLETE 0x00000001
+ #define B44_FLAG_BUGGY_TXPTR 0x00000002
+ #define B44_FLAG_REORDER_BUG 0x00000004
+ #define B44_FLAG_PAUSE_AUTO 0x00008000
diff --git a/target/linux/brcm-2.6/patches/010-bcm47xx-cam_absent.patch b/target/linux/brcm-2.6/patches/010-bcm47xx-cam_absent.patch
new file mode 100644
index 0000000..5120629
--- /dev/null
+++ b/target/linux/brcm-2.6/patches/010-bcm47xx-cam_absent.patch
@@ -0,0 +1,42 @@
+--- linux-2.6.17.orig/drivers/net/b44.h 2006-09-19 19:56:03.000000000 +0200
++++ linux-2.6.17/drivers/net/b44.h 2006-09-19 19:58:01.000000000 +0200
+@@ -122,6 +122,7 @@
+ #define RXCONFIG_FLOW 0x00000020 /* Flow Control Enable */
+ #define RXCONFIG_FLOW_ACCEPT 0x00000040 /* Accept Unicast Flow Control Frame */
+ #define RXCONFIG_RFILT 0x00000080 /* Reject Filter */
++#define RXCONFIG_CAM_ABSENT 0x00000100 /* CAM Absent */
+ #define B44_RXMAXLEN 0x0404UL /* EMAC RX Max Packet Length */
+ #define B44_TXMAXLEN 0x0408UL /* EMAC TX Max Packet Length */
+ #define B44_MDIO_CTRL 0x0410UL /* EMAC MDIO Control */
+--- linux-2.6.17.orig/drivers/net/b44.c 2006-09-19 19:56:03.000000000 +0200
++++ linux-2.6.17/drivers/net/b44.c 2006-09-19 20:08:22.000000000 +0200
+@@ -1435,6 +1435,7 @@
+ {
+ struct b44 *bp = netdev_priv(dev);
+ struct sockaddr *addr = p;
++ u32 val;
+
+ if (netif_running(dev))
+ return -EBUSY;
+@@ -1445,7 +1446,11 @@
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ spin_lock_irq(&bp->lock);
+- __b44_set_mac_addr(bp);
++
++ val = br32(bp, B44_RXCONFIG);
++ if (!(val & RXCONFIG_CAM_ABSENT))
++ __b44_set_mac_addr(bp);
++
+ spin_unlock_irq(&bp->lock);
+
+ return 0;
+@@ -1641,7 +1646,7 @@
+
+ val = br32(bp, B44_RXCONFIG);
+ val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
+- if (dev->flags & IFF_PROMISC) {
++ if ((dev->flags & IFF_PROMISC) || (val & RXCONFIG_CAM_ABSENT)) {
+ val |= RXCONFIG_PROMISC;
+ bw32(bp, B44_RXCONFIG, val);
+ } else {
diff --git a/target/linux/brcm63xx-2.6/Makefile b/target/linux/brcm63xx-2.6/Makefile
new file mode 100644
index 0000000..0437338
--- /dev/null
+++ b/target/linux/brcm63xx-2.6/Makefile
@@ -0,0 +1,23 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+LINUX_VERSION:=2.6.17
+LINUX_RELEASE:=1
+LINUX_KERNEL_MD5SUM:=37ddefe96625502161f075b9d907f21e
+
+include ./config
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/kernel-build.mk
+
+
+$(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked
+ [ -d ../generic-$(KERNEL)/patches ] && $(PATCH) $(LINUX_DIR) ../generic-$(KERNEL)/patches $(MAKE_TRACE)
+ [ -d ./patches ] && $(PATCH) $(LINUX_DIR) ./patches $(MAKE_TRACE)
+ @$(CP) config $(LINUX_DIR)/.config
+ touch $@
+
diff --git a/target/linux/brcm63xx-2.6/config b/target/linux/brcm63xx-2.6/config
new file mode 100644
index 0000000..ac286df
--- /dev/null
+++ b/target/linux/brcm63xx-2.6/config
@@ -0,0 +1,1629 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17
+# Thu Sep 21 15:05:29 2006
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+CONFIG_MIPS_BRCM=y
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+# CONFIG_BCM96338 is not set
+# CONFIG_BCM96345 is not set
+CONFIG_BCM96348=y
+# CONFIG_BCM_BOARD is not set
+CONFIG_BCM_SERIAL=y
+# CONFIG_BCM_ENET is not set
+# CONFIG_BCM_USB is not set
+# CONFIG_BCM_WLAN is not set
+CONFIG_BCM_PCI=y
+# CONFIG_BCM_ATMAPI is not set
+# CONFIG_BCM_ATMTEST is not set
+# CONFIG_BCM_ADSL is not set
+# CONFIG_BCM_ENDPOINT is not set
+CONFIG_BCM_PROCFS=y
+# CONFIG_BCM_VDSL is not set
+# CONFIG_BCM_SECURITY is not set
+# CONFIG_BCM_HPNA is not set
+CONFIG_BCM_BOARD_IMPL=1
+CONFIG_BCM_SERIAL_IMPL=1
+CONFIG_BCM_ENET_IMPL=1
+CONFIG_BCM_USB_IMPL=1
+CONFIG_BCM_WLAN_IMPL=1
+CONFIG_BCM_ATMAPI_IMPL=1
+CONFIG_BCM_ATMTEST_IMPL=1
+CONFIG_BCM_BLAA_IMPL=1
+CONFIG_BCM_ADSL_IMPL=1
+CONFIG_BCM_ENDPOINT_IMPL=1
+CONFIG_BCM_PROCFS_IMPL=1
+CONFIG_BCM_VDSL_IMPL=1
+CONFIG_BCM_SECURITY_IMPL=1
+CONFIG_BCM_HPNA_IMPL=0
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_MIPS_MT is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_SYSCTL=y
+CONFIG_AUDIT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_RELAY=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_LBD=y
+CONFIG_BLK_DEV_IO_TRACE=y
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DEBUG=y
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_IP_ROUTE_FWMARK is not set
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_MULTIPATH_CACHED=y
+CONFIG_IP_ROUTE_MULTIPATH_RR=m
+CONFIG_IP_ROUTE_MULTIPATH_RANDOM=m
+CONFIG_IP_ROUTE_MULTIPATH_WRANDOM=m
+CONFIG_IP_ROUTE_MULTIPATH_DRR=m
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IPSEC_NAT_TRAVERSAL=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_ARPD=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_CT_ACCT=y
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=y
+CONFIG_IP_NF_IRC=y
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=y
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+CONFIG_IP_NF_SIP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_IPP2P=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_TIME=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_IMQ=m
+# CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_ROUTE=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=y
+CONFIG_IP_NF_NAT_FTP=y
+CONFIG_IP_NF_NAT_TFTP=y
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_SET=m
+CONFIG_IP_NF_SET_MAX=256
+CONFIG_IP_NF_SET_HASHSIZE=1024
+CONFIG_IP_NF_SET_IPMAP=m
+CONFIG_IP_NF_SET_MACIPMAP=m
+CONFIG_IP_NF_SET_PORTMAP=m
+CONFIG_IP_NF_SET_IPHASH=m
+CONFIG_IP_NF_SET_NETHASH=m
+CONFIG_IP_NF_SET_IPTREE=m
+CONFIG_IP_NF_MATCH_SET=m
+CONFIG_IP_NF_TARGET_SET=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_OWNER=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_IMQ=m
+# CONFIG_IP6_NF_TARGET_LOG is not set
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_HL is not set
+# CONFIG_IP6_NF_RAW is not set
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+CONFIG_IP_DCCP_ACKVEC=y
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP_CCID2=m
+CONFIG_IP_DCCP_CCID3=m
+CONFIG_IP_DCCP_TFRC_LIB=m
+
+#
+# DCCP Kernel Hacking
+#
+# CONFIG_IP_DCCP_DEBUG is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+CONFIG_TIPC=m
+# CONFIG_TIPC_ADVANCED is not set
+# CONFIG_TIPC_DEBUG is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_CLIP_NO_ICMP=y
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_ATM_BR2684_IPFILTER=y
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+CONFIG_WAN_ROUTER=m
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+# CONFIG_NET_SCH_CLK_JIFFIES is not set
+CONFIG_NET_SCH_CLK_GETTIMEOFDAY=y
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_ESFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+# CONFIG_CLS_U32_MARK is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+# CONFIG_NET_ACT_IPT is not set
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+CONFIG_BT_HCIVHCI=m
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+# CONFIG_IEEE80211_CRYPT_TKIP is not set
+CONFIG_IEEE80211_SOFTMAC=m
+# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=3
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# 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
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_GEOMETRY 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_OTP is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+CONFIG_MTD_OBSOLETE_CHIPS=y
+# CONFIG_MTD_SHARP is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0xBFC00000
+CONFIG_MTD_PHYSMAP_LEN=0x400000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_BCM963XX is not set
+# CONFIG_MTD_CSTM_MIPS_IXX is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_IFB=m
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_IMQ=m
+# CONFIG_IMQ_BEHAVIOR_AA is not set
+# CONFIG_IMQ_BEHAVIOR_AB is not set
+CONFIG_IMQ_BEHAVIOR_BA=y
+# CONFIG_IMQ_BEHAVIOR_BB is not set
+CONFIG_IMQ_NUM_DEVS=2
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=m
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_CICADA_PHY=m
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+CONFIG_NET_WIRELESS_RTNETLINK=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_IPW2100=m
+CONFIG_IPW2100_MONITOR=y
+CONFIG_IPW2100_DEBUG=y
+CONFIG_IPW2200=m
+CONFIG_IPW2200_MONITOR=y
+CONFIG_IPW_QOS=y
+CONFIG_IPW2200_DEBUG=y
+CONFIG_HERMES=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_NORTEL_HERMES=m
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+CONFIG_PCI_ATMEL=m
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_PRISM54=m
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+CONFIG_HOSTAP_PLX=m
+CONFIG_HOSTAP_PCI=m
+CONFIG_BCM43XX=m
+CONFIG_BCM43XX_DEBUG=y
+CONFIG_BCM43XX_DMA=y
+CONFIG_BCM43XX_PIO=y
+CONFIG_BCM43XX_DMA_AND_PIO_MODE=y
+# CONFIG_BCM43XX_DMA_MODE is not set
+# CONFIG_BCM43XX_PIO_MODE is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ATM drivers
+#
+CONFIG_ATM_DUMMY=m
+CONFIG_ATM_TCP=m
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+# CONFIG_ATM_FORE200E_MAYBE is not set
+# CONFIG_ATM_HE is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+CONFIG_SHAPER=m
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=m
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=m
+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 Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=m
+# 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=m
+# 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
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=m
+CONFIG_SERIO_I8042=m
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=m
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_SPLIT_ISO=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL 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_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_ZD1201 is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+# CONFIG_USB_SERIAL_ANYDATA is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+CONFIG_USB_SERIAL_BELKIN=m
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+CONFIG_USB_SERIAL_FTDI_SIO=m
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+CONFIG_USB_SERIAL_VISOR=m
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=m
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_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_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+
+#
+# USB DSL modem support
+#
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+# CONFIG_USB_CXACRU is not set
+CONFIG_USB_UEAGLEATM=m
+# CONFIG_USB_XUSBATM is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+CONFIG_DEVFS_DEBUG=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+# 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_SQUASHFS=y
+CONFIG_SQUASHFS_EMBEDDED=y
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+CONFIG_SQUASHFS_VMALLOC=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=m
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_CROSSCOMPILE=y
+CONFIG_CMDLINE=""
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_KGDB is not set
+# CONFIG_RUNTIME_DEBUG is not set
+# CONFIG_MIPS_UNCACHED is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/target/linux/brcm63xx-2.6/patches/001-bcm963xx.patch b/target/linux/brcm63xx-2.6/patches/001-bcm963xx.patch
new file mode 100644
index 0000000..c079c5a
--- /dev/null
+++ b/target/linux/brcm63xx-2.6/patches/001-bcm963xx.patch
@@ -0,0 +1,9656 @@
+diff -urN linux.old/arch/mips/bcm963xx/bcm63xx_led.c linux.dev/arch/mips/bcm963xx/bcm63xx_led.c
+--- linux.old/arch/mips/bcm963xx/bcm63xx_led.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/bcm63xx_led.c 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,582 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ for more details.
++
++ You should have received a copy of the GNU General Public License along
++ with this program; if not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++:>
++*/
++/***************************************************************************
++ * File Name : bcm63xx_led.c
++ *
++ * Description:
++ *
++ * This file contains bcm963xx board led control API functions.
++ *
++ * To use it, do the following
++ *
++ * 1). define in the board.c the following led mappping (this is for 6345GW board):
++ * const LED_MAP_PAIR cLedMapping45GW[] =
++ * { // led name Initial state physical pin (ledMask)
++ * {kLedUsb, kLedStateOff, GPIO_LED_PIN_7},
++ * {kLedAdsl, kLedStateOff, GPIO_LED_PIN_8},
++ * {kLedPPP, kLedStateOff, GPIO_LED_PIN_9}, // PPP and WanData share PIN_9
++ * {kLedWanData, kLedStateOff, GPIO_LED_PIN_9},
++ * {kLedWireless, kLedStateOff, GPIO_LED_PIN_10},
++ * {kLedEnd, kLedStateOff, 0 } // NOTE: kLedEnd has to be at the end.
++ *
++ * 2). };To initialize led API and initial state of the leds, call the following function with the mapping
++ * pointer from the above struct
++ *
++ * boardLedInit((PLED_MAP_PAIR) &cLedMapping45R);
++ *
++ * 3). Sample call for kernel mode:
++ *
++ * kerSysLedCtrl(kLedAdsl, kLedStateBlinkOnce); // kLedxxx defines in board.h
++ *
++ * 4). Sample call for user mode
++ *
++ * sysLedCtrl(kLedAdsl, kLedStateBlinkOnce); // kLedxxx defines in board_api.h
++ *
++ *
++ * Created on : 10/28/2002 seanl
++ *
++ ***************************************************************************/
++
++/* Includes. */
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/capability.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/module.h>
++#include <linux/netdevice.h>
++#include <asm/uaccess.h>
++
++#include <bcm_map_part.h>
++#include <board.h>
++
++#define k100ms (HZ / 10) // ~100 ms
++#define kFastBlinkCount 0 // ~100ms
++#define kSlowBlinkCount 5 // ~600ms
++
++#define MAX_VIRT_LEDS 12
++
++// uncomment // for debug led
++//#define DEBUG_LED
++
++// global variables:
++struct timer_list gLedTimer;
++int gTimerOn = FALSE;
++int gLedCount = 0;
++
++typedef struct ledinfo
++{
++ unsigned short ledMask; // mask for led: ie. giop 10 = 0x0400
++ unsigned short ledActiveLow; // GPIO bit reset to turn on LED
++ unsigned short ledMaskFail; // mask for led: ie. giop 10 = 0x0400
++ unsigned short ledActiveLowFail;// GPIO bit reset to turn on LED
++ BOARD_LED_STATE ledState; // current led state
++ BOARD_LED_STATE savedLedState; // used in blink once for restore to the orignal ledState
++ int blinkCountDown; // if == 0, do blink (toggle). Is assgined value and dec by 1 at each timer.
++} LED_INFO, *PLED_INFO;
++
++static PLED_INFO gLed = NULL;
++static PLED_INFO gpVirtLeds[MAX_VIRT_LEDS];
++static HANDLE_LED_FUNC gLedHwFunc[MAX_VIRT_LEDS];
++static HANDLE_LED_FUNC gLedHwFailFunc[MAX_VIRT_LEDS];
++
++#if 0 /* BROKEN */
++#if defined(CONFIG_BCM96348) || defined(CONFIG_BCM96338)
++static int gLedOffInBridgeMode = 1;
++#elif defined(CONFIG_BCM96345)
++static int gLedOffInBridgeMode = 0;
++#endif
++#endif
++
++void ledTimerExpire(void);
++int initLedInfo( PLED_MAP_PAIR pCurMap, PLED_INFO pCurLed );
++
++//**************************************************************************************
++// LED operations
++//**************************************************************************************
++
++// turn led on and set the ledState
++void ledOn(PLED_INFO pLed)
++{
++ if( pLed->ledMask )
++ {
++ GPIO->GPIODir |= pLed->ledMask; // turn on the direction bit in case was turned off by some one
++ if( pLed->ledActiveLow )
++ GPIO->GPIOio &= ~pLed->ledMask; // turn on the led
++ else
++ GPIO->GPIOio |= pLed->ledMask; // turn on the led
++ pLed->ledState = pLed->savedLedState = kLedStateOn;
++ }
++}
++
++
++// turn led off and set the ledState
++void ledOff(PLED_INFO pLed)
++{
++ if( pLed->ledMask )
++ {
++ GPIO->GPIODir |= pLed->ledMask; // turn on the direction bit in case was turned off by some one
++ if( pLed->ledActiveLow )
++ GPIO->GPIOio |= pLed->ledMask; // turn off the led
++ else
++ GPIO->GPIOio &= ~pLed->ledMask; // turn off the led
++ pLed->ledState = pLed->savedLedState = kLedStateOff;
++ }
++}
++
++// turn led on and set the ledState
++void ledOnFail(PLED_INFO pLed)
++{
++ if( pLed->ledMaskFail )
++ {
++ GPIO->GPIODir |= pLed->ledMaskFail; // turn on the direction bit in case was turned off by some one
++ if( pLed->ledActiveLowFail )
++ GPIO->GPIOio &= ~pLed->ledMaskFail;// turn on the led
++ else
++ GPIO->GPIOio |= pLed->ledMaskFail; // turn on the led
++ pLed->ledState = pLed->savedLedState = kLedStateFail;
++ }
++}
++
++
++// turn led off and set the ledState
++void ledOffFail(PLED_INFO pLed)
++{
++ if( pLed->ledMaskFail )
++ {
++ GPIO->GPIODir |= pLed->ledMaskFail; // turn on the direction bit in case was turned off by some one
++ if( pLed->ledActiveLowFail )
++ GPIO->GPIOio |= pLed->ledMaskFail; // turn off the led
++ else
++ GPIO->GPIOio &= ~pLed->ledMaskFail;// turn off the led
++ pLed->ledState = pLed->savedLedState = kLedStateOff;
++ }
++}
++
++
++// toggle the led and return the current ledState
++BOARD_LED_STATE ledToggle(PLED_INFO pLed)
++{
++ GPIO->GPIODir |= pLed->ledMask; // turn on the direction bit in case was turned off by some one
++ if (GPIO->GPIOio & pLed->ledMask)
++ {
++ GPIO->GPIOio &= ~(pLed->ledMask);
++ return( (pLed->ledActiveLow) ? kLedStateOn : kLedStateOff );
++ }
++ else
++ {
++ GPIO->GPIOio |= pLed->ledMask;
++ return( (pLed->ledActiveLow) ? kLedStateOff : kLedStateOn );
++ }
++}
++
++
++// led timer. Will return if timer is already on
++void ledTimerStart(void)
++{
++ if (gTimerOn)
++ return;
++
++#if defined(DEBUG_LED)
++ printk("led: add_timer\n");
++#endif
++
++ init_timer(&gLedTimer);
++ gLedTimer.function = (void*)ledTimerExpire;
++ gLedTimer.expires = jiffies + k100ms; // timer expires in ~100ms
++ add_timer (&gLedTimer);
++ gTimerOn = TRUE;
++}
++
++
++// led timer expire kicks in about ~100ms and perform the led operation according to the ledState and
++// restart the timer according to ledState
++void ledTimerExpire(void)
++{
++ int i;
++ PLED_INFO pCurLed;
++
++ gTimerOn = FALSE;
++
++ for (i = 0, pCurLed = gLed; i < gLedCount; i++, pCurLed++)
++ {
++#if defined(DEBUG_LED)
++ printk("led[%d]: Mask=0x%04x, State = %d, blcd=%d\n", i, pCurLed->ledMask, pCurLed->ledState, pCurLed->blinkCountDown);
++#endif
++ switch (pCurLed->ledState)
++ {
++ case kLedStateOn:
++ case kLedStateOff:
++ case kLedStateFail:
++ pCurLed->blinkCountDown = 0; // reset the blink count down
++ break;
++
++ case kLedStateBlinkOnce:
++ ledToggle(pCurLed);
++ pCurLed->blinkCountDown = 0; // reset to 0
++ pCurLed->ledState = pCurLed->savedLedState;
++ if (pCurLed->ledState == kLedStateSlowBlinkContinues ||
++ pCurLed->ledState == kLedStateFastBlinkContinues)
++ ledTimerStart(); // start timer if in blinkContinues stats
++ break;
++
++ case kLedStateSlowBlinkContinues:
++ if (pCurLed->blinkCountDown-- == 0)
++ {
++ pCurLed->blinkCountDown = kSlowBlinkCount;
++ ledToggle(pCurLed);
++ }
++ ledTimerStart();
++ break;
++
++ case kLedStateFastBlinkContinues:
++ if (pCurLed->blinkCountDown-- == 0)
++ {
++ pCurLed->blinkCountDown = kFastBlinkCount;
++ ledToggle(pCurLed);
++ }
++ ledTimerStart();
++ break;
++
++ default:
++ printk("Invalid state = %d\n", pCurLed->ledState);
++ }
++ }
++}
++
++// initialize the gLedCount and allocate and fill gLed struct
++void __init boardLedInit(PLED_MAP_PAIR cLedMapping)
++{
++ PLED_MAP_PAIR p1, p2;
++ PLED_INFO pCurLed;
++ int needTimer = FALSE;
++ int alreadyUsed = 0;
++
++#if defined(CONFIG_BCM96348) || defined(CONFIG_BCM96338)
++ /* Set blink rate for BCM6348/BCM6338 hardware LEDs. */
++ GPIO->LEDCtrl &= ~LED_INTERVAL_SET_MASK;
++ GPIO->LEDCtrl |= LED_INTERVAL_SET_80MS;
++#endif
++
++ memset( gpVirtLeds, 0x00, sizeof(gpVirtLeds) );
++ memset( gLedHwFunc, 0x00, sizeof(gLedHwFunc) );
++ memset( gLedHwFailFunc, 0x00, sizeof(gLedHwFailFunc) );
++
++ gLedCount = 0;
++
++ // Check for multiple LED names and multiple LED GPIO pins that share the
++ // same physical board LED.
++ for( p1 = cLedMapping; p1->ledName != kLedEnd; p1++ )
++ {
++ alreadyUsed = 0;
++ for( p2 = cLedMapping; p2 != p1; p2++ )
++ {
++ if( (p1->ledMask && p1->ledMask == p2->ledMask) ||
++ (p1->ledMaskFail && p1->ledMaskFail == p2->ledMaskFail) )
++ {
++ alreadyUsed = 1;
++ break;
++ }
++ }
++
++ if( alreadyUsed == 0 )
++ gLedCount++;
++ }
++
++ gLed = (PLED_INFO) kmalloc((gLedCount * sizeof(LED_INFO)), GFP_KERNEL);
++ if( gLed == NULL )
++ {
++ printk( "LED memory allocation error.\n" );
++ return;
++ }
++
++ memset( gLed, 0x00, gLedCount * sizeof(LED_INFO) );
++
++ // initial the gLed with unique ledMask and initial state. If more than 1 ledNames share the physical led
++ // (ledMask) the first defined led's ledInitState will be used.
++ pCurLed = gLed;
++ for( p1 = cLedMapping; p1->ledName != kLedEnd; p1++ )
++ {
++ if( (int) p1->ledName > MAX_VIRT_LEDS )
++ continue;
++
++ alreadyUsed = 0;
++ for( p2 = cLedMapping; p2 != p1; p2++ )
++ {
++ if( (p1->ledMask && p1->ledMask == p2->ledMask) ||
++ (p1->ledMaskFail && p1->ledMaskFail == p2->ledMaskFail) )
++ {
++ alreadyUsed = 1;
++ break;
++ }
++ }
++
++ if( alreadyUsed == 0 )
++ {
++ // Initialize the board LED for the first time.
++ needTimer = initLedInfo( p1, pCurLed );
++ gpVirtLeds[(int) p1->ledName] = pCurLed;
++ pCurLed++;
++ }
++ else
++ {
++ PLED_INFO pLed;
++ for( pLed = gLed; pLed != pCurLed; pLed++ )
++ {
++ // Find the LED_INFO structure that has already been initialized.
++ if((pLed->ledMask && pLed->ledMask == p1->ledMask) ||
++ (pLed->ledMaskFail && pLed->ledMaskFail==p1->ledMaskFail))
++ {
++ // The board LED has already been initialized but possibly
++ // not completely initialized.
++ if( p1->ledMask )
++ {
++ pLed->ledMask = p1->ledMask;
++ pLed->ledActiveLow = p1->ledActiveLow;
++ }
++ if( p1->ledMaskFail )
++ {
++ pLed->ledMaskFail = p1->ledMaskFail;
++ pLed->ledActiveLowFail = p1->ledActiveLowFail;
++ }
++ gpVirtLeds[(int) p1->ledName] = pLed;
++ break;
++ }
++ }
++ }
++ }
++
++ if (needTimer)
++ ledTimerStart();
++
++#if defined(DEBUG_LED)
++ int i;
++ for (i=0; i < gLedCount; i++)
++ printk("initLed: led[%d]: mask=0x%04x, state=%d\n", i,(gLed+i)->ledMask, (gLed+i)->ledState);
++#endif
++
++}
++
++// Initialize a structure that contains information about a physical board LED
++// control. The board LED may contain more than one GPIO pin to control a
++// normal condition (green) or a failure condition (red).
++int initLedInfo( PLED_MAP_PAIR pCurMap, PLED_INFO pCurLed )
++{
++ int needTimer = FALSE;
++ pCurLed->ledState = pCurLed->savedLedState = pCurMap->ledInitState;
++ pCurLed->ledMask = pCurMap->ledMask;
++ pCurLed->ledActiveLow = pCurMap->ledActiveLow;
++ pCurLed->ledMaskFail = pCurMap->ledMaskFail;
++ pCurLed->ledActiveLowFail = pCurMap->ledActiveLowFail;
++
++ switch (pCurLed->ledState)
++ {
++ case kLedStateOn:
++ pCurLed->blinkCountDown = 0; // reset the blink count down
++ ledOn(pCurLed);
++ break;
++ case kLedStateOff:
++ pCurLed->blinkCountDown = 0; // reset the blink count down
++ ledOff(pCurLed);
++ break;
++ case kLedStateFail:
++ pCurLed->blinkCountDown = 0; // reset the blink count down
++ ledOnFail(pCurLed);
++ break;
++ case kLedStateBlinkOnce:
++ pCurLed->blinkCountDown = 1;
++ needTimer = TRUE;
++ break;
++ case kLedStateSlowBlinkContinues:
++ pCurLed->blinkCountDown = kSlowBlinkCount;
++ needTimer = TRUE;
++ break;
++ case kLedStateFastBlinkContinues:
++ pCurLed->blinkCountDown = kFastBlinkCount;
++ needTimer = TRUE;
++ break;
++ default:
++ printk("Invalid state = %d\n", pCurLed->ledState);
++ }
++
++ return( needTimer );
++}
++
++#if 0 /* BROKEN */
++// Determines if there is at least one interface in bridge mode. Bridge mode
++// is determined by the cfm convention of naming bridge interfaces nas17
++// through nas24.
++static int isBridgedProtocol(void)
++{
++ extern int dev_get(const char *name);
++ const int firstBridgeId = 17;
++ const int lastBridgeId = 24;
++ int i;
++ int ret = FALSE;
++ char name[16];
++
++ for( i = firstBridgeId; i <= lastBridgeId; i++ )
++ {
++ sprintf( name, "nas%d", i );
++
++ if( dev_get(name) )
++ {
++ ret = TRUE;
++ break;
++ }
++ }
++
++ return(ret);
++}
++#endif
++
++// led ctrl. Maps the ledName to the corresponding ledInfoPtr and perform the led operation
++void boardLedCtrl(BOARD_LED_NAME ledName, BOARD_LED_STATE ledState)
++{
++ PLED_INFO ledInfoPtr;
++
++ // do the mapping from virtual to physical led
++ if( (int) ledName < MAX_VIRT_LEDS )
++ ledInfoPtr = gpVirtLeds[(int) ledName];
++ else
++ ledInfoPtr = NULL;
++
++ if (ledInfoPtr == NULL)
++ return;
++
++ if( ledState != kLedStateFail && gLedHwFunc[(int) ledName] )
++ {
++ (*gLedHwFunc[(int) ledName]) (ledName, ledState);
++ ledOffFail(ledInfoPtr);
++ return;
++ }
++ else
++ if( ledState == kLedStateFail && gLedHwFailFunc[(int) ledName] )
++ {
++ (*gLedHwFailFunc[(int) ledName]) (ledName, ledState);
++ ledOff(ledInfoPtr);
++ return;
++ }
++
++#if 0 /* BROKEN */
++ // Do not blink the WAN Data LED if at least one interface is in bridge mode.
++ if(gLedOffInBridgeMode == 1 && (ledName == kLedWanData || ledName == kLedPPP))
++ {
++ static int BridgedProtocol = -1;
++
++ if( BridgedProtocol == -1 )
++ BridgedProtocol = isBridgedProtocol();
++
++ if( BridgedProtocol == TRUE )
++ return;
++ }
++#endif
++
++ // If the state is kLedStateFail and there is not a failure LED defined
++ // in the board parameters, change the state to kLedStateFastBlinkContinues.
++ if( ledState == kLedStateFail && ledInfoPtr->ledMaskFail == 0 )
++ ledState = kLedStateFastBlinkContinues;
++
++ switch (ledState)
++ {
++ case kLedStateOn:
++ // First, turn off the complimentary (failure) LED GPIO.
++ if( ledInfoPtr->ledMaskFail )
++ ledOffFail(ledInfoPtr);
++ else
++ if( gLedHwFailFunc[(int) ledName] )
++ (*gLedHwFailFunc[(int) ledName]) (ledName, kLedStateOff);
++
++ // Next, turn on the specified LED GPIO.
++ ledOn(ledInfoPtr);
++ break;
++
++ case kLedStateOff:
++ // First, turn off the complimentary (failure) LED GPIO.
++ if( ledInfoPtr->ledMaskFail )
++ ledOffFail(ledInfoPtr);
++ else
++ if( gLedHwFailFunc[(int) ledName] )
++ (*gLedHwFailFunc[(int) ledName]) (ledName, kLedStateOff);
++
++ // Next, turn off the specified LED GPIO.
++ ledOff(ledInfoPtr);
++ break;
++
++ case kLedStateFail:
++ // First, turn off the complimentary (normal) LED GPIO.
++ if( ledInfoPtr->ledMask )
++ ledOff(ledInfoPtr);
++ else
++ if( gLedHwFunc[(int) ledName] )
++ (*gLedHwFunc[(int) ledName]) (ledName, kLedStateOff);
++
++ // Next, turn on (red) the specified LED GPIO.
++ ledOnFail(ledInfoPtr);
++ break;
++
++ case kLedStateBlinkOnce:
++ // skip blinkOnce if it is already in Slow/Fast blink continues state
++ if (ledInfoPtr->savedLedState == kLedStateSlowBlinkContinues ||
++ ledInfoPtr->savedLedState == kLedStateFastBlinkContinues)
++ ;
++ else
++ {
++ if (ledInfoPtr->blinkCountDown == 0) // skip the call if it is 1
++ {
++ ledToggle(ledInfoPtr);
++ ledInfoPtr->blinkCountDown = 1; // it will be reset to 0 when timer expires
++ ledInfoPtr->ledState = kLedStateBlinkOnce;
++ ledTimerStart();
++ }
++ }
++ break;
++
++ case kLedStateSlowBlinkContinues:
++ ledInfoPtr->blinkCountDown = kSlowBlinkCount;
++ ledInfoPtr->ledState = kLedStateSlowBlinkContinues;
++ ledInfoPtr->savedLedState = kLedStateSlowBlinkContinues;
++ ledTimerStart();
++ break;
++
++ case kLedStateFastBlinkContinues:
++ ledInfoPtr->blinkCountDown = kFastBlinkCount;
++ ledInfoPtr->ledState = kLedStateFastBlinkContinues;
++ ledInfoPtr->savedLedState = kLedStateFastBlinkContinues;
++ ledTimerStart();
++ break;
++
++ default:
++ printk("Invalid led state\n");
++ }
++}
++
++// This function is called for an LED that is controlled by hardware.
++void kerSysLedRegisterHwHandler( BOARD_LED_NAME ledName,
++ HANDLE_LED_FUNC ledHwFunc, int ledFailType )
++{
++ if( (int) ledName < MAX_VIRT_LEDS )
++ {
++ if( ledFailType == 1 )
++ gLedHwFailFunc[(int) ledName] = ledHwFunc;
++ else
++ gLedHwFunc[(int) ledName] = ledHwFunc;
++ }
++}
++
+diff -urN linux.old/arch/mips/bcm963xx/board.c linux.dev/arch/mips/bcm963xx/board.c
+--- linux.old/arch/mips/bcm963xx/board.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/board.c 2006-08-27 21:02:04.000000000 +0200
+@@ -0,0 +1,559 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope 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.
++:>
++*/
++
++/* Includes. */
++#include <linux/version.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/capability.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/module.h>
++#include <linux/pagemap.h>
++#include <asm/uaccess.h>
++#include <linux/wait.h>
++#include <linux/poll.h>
++#include <linux/sched.h>
++#include <linux/list.h>
++#include <linux/if.h>
++#include <linux/spinlock.h>
++
++#include <bcm_map_part.h>
++#include <board.h>
++#include <bcmTag.h>
++#include "boardparms.h"
++#include "bcm_intr.h"
++#include "board.h"
++#include "bcm_map_part.h"
++
++static DEFINE_SPINLOCK(board_lock);
++
++/* Typedefs. */
++#if defined (NON_CONSECUTIVE_MAC)
++// used to be the last octet. Now changed to the first 5 bits of the the forth octet
++// to reduced the duplicated MAC addresses.
++#define CHANGED_OCTET 3
++#define SHIFT_BITS 3
++#else
++#define CHANGED_OCTET 1
++#define SHIFT_BITS 0
++#endif
++
++typedef struct
++{
++ unsigned long ulId;
++ char chInUse;
++ char chReserved[3];
++} MAC_ADDR_INFO, *PMAC_ADDR_INFO;
++
++typedef struct
++{
++ unsigned long ulSdramSize;
++ unsigned long ulPsiSize;
++ unsigned long ulNumMacAddrs;
++ unsigned long ucaBaseMacAddr[NVRAM_MAC_ADDRESS_LEN];
++ MAC_ADDR_INFO MacAddrs[1];
++} NVRAM_INFO, *PNVRAM_INFO;
++
++typedef struct
++{
++ unsigned long eventmask;
++} BOARD_IOC, *PBOARD_IOC;
++
++
++/*Dyinggasp callback*/
++typedef void (*cb_dgasp_t)(void *arg);
++typedef struct _CB_DGASP__LIST
++{
++ struct list_head list;
++ char name[IFNAMSIZ];
++ cb_dgasp_t cb_dgasp_fn;
++ void *context;
++}CB_DGASP_LIST , *PCB_DGASP_LIST;
++
++
++static LED_MAP_PAIR LedMapping[] =
++{ // led name Initial state physical pin (ledMask)
++ {kLedEnd, kLedStateOff, 0, 0, 0, 0},
++ {kLedEnd, kLedStateOff, 0, 0, 0, 0},
++ {kLedEnd, kLedStateOff, 0, 0, 0, 0},
++ {kLedEnd, kLedStateOff, 0, 0, 0, 0},
++ {kLedEnd, kLedStateOff, 0, 0, 0, 0},
++ {kLedEnd, kLedStateOff, 0, 0, 0, 0},
++ {kLedEnd, kLedStateOff, 0, 0, 0, 0},
++ {kLedEnd, kLedStateOff, 0, 0, 0, 0},
++ {kLedEnd, kLedStateOff, 0, 0, 0, 0} // NOTE: kLedEnd has to be at the end.
++};
++
++/* Externs. */
++extern struct file fastcall *fget_light(unsigned int fd, int *fput_needed);
++extern unsigned int nr_free_pages (void);
++extern const char *get_system_type(void);
++extern void kerSysFlashInit(void);
++extern unsigned long get_nvram_start_addr(void);
++extern unsigned long get_scratch_pad_start_addr(void);
++extern unsigned long getMemorySize(void);
++extern void __init boardLedInit(PLED_MAP_PAIR);
++extern void boardLedCtrl(BOARD_LED_NAME, BOARD_LED_STATE);
++extern void kerSysLedRegisterHandler( BOARD_LED_NAME ledName,
++ HANDLE_LED_FUNC ledHwFunc, int ledFailType );
++
++/* Prototypes. */
++void __init InitNvramInfo( void );
++
++/* DyingGasp function prototype */
++static void __init kerSysDyingGaspMapIntr(void);
++static irqreturn_t kerSysDyingGaspIsr(int irq, void * dev_id, struct pt_regs * regs);
++static void __init kerSysInitDyingGaspHandler( void );
++static void __exit kerSysDeinitDyingGaspHandler( void );
++/* -DyingGasp function prototype - */
++
++static PNVRAM_INFO g_pNvramInfo = NULL;
++static int g_ledInitialized = 0;
++static CB_DGASP_LIST *g_cb_dgasp_list_head = NULL;
++
++static int g_wakeup_monitor = 0;
++static struct file *g_monitor_file = NULL;
++static struct task_struct *g_monitor_task = NULL;
++static unsigned int (*g_orig_fop_poll)
++ (struct file *, struct poll_table_struct *) = NULL;
++
++void kerSysMipsSoftReset(void)
++{
++ if (PERF->RevID == 0x634800A1) {
++ typedef void (*FNPTR) (void);
++ FNPTR bootaddr = (FNPTR) FLASH_BASE;
++ int i;
++
++ /* Disable interrupts. */
++ //cli();
++ spin_lock_irq(&board_lock);
++
++ /* Reset all blocks. */
++ PERF->BlockSoftReset &= ~BSR_ALL_BLOCKS;
++ for( i = 0; i < 1000000; i++ )
++ ;
++ PERF->BlockSoftReset |= BSR_ALL_BLOCKS;
++ /* Jump to the power on address. */
++ (*bootaddr) ();
++ }
++ else
++ PERF->pll_control |= SOFT_RESET; // soft reset mips
++}
++
++
++int kerSysGetMacAddress( unsigned char *pucaMacAddr, unsigned long ulId )
++{
++ int nRet = 0;
++ PMAC_ADDR_INFO pMai = NULL;
++ PMAC_ADDR_INFO pMaiFreeNoId = NULL;
++ PMAC_ADDR_INFO pMaiFreeId = NULL;
++ unsigned long i = 0, ulIdxNoId = 0, ulIdxId = 0, shiftedIdx = 0;
++
++ /* CMO -- Fix le problème avec les adresses mac que l'on n'arrive pas
++ * * à relire plusieurs fois */
++ /* inv_xde */
++#if 0
++ if (boot_loader_type == BOOT_CFE)
++ memcpy( pucaMacAddr, g_pNvramInfo->ucaBaseMacAddr,
++ NVRAM_MAC_ADDRESS_LEN );
++ else {
++#endif
++ pucaMacAddr[0] = 0x00;
++ pucaMacAddr[1] = 0x07;
++ pucaMacAddr[2] = 0x3A;
++ pucaMacAddr[3] = 0xFF;
++ pucaMacAddr[4] = 0xFF;
++ pucaMacAddr[5] = 0xFF;
++#if 0
++ }
++#endif
++
++ return nRet;
++} /* kerSysGetMacAddr */
++
++int kerSysReleaseMacAddress( unsigned char *pucaMacAddr )
++{
++ int nRet = -EINVAL;
++ unsigned long ulIdx = 0;
++ int idx = (pucaMacAddr[NVRAM_MAC_ADDRESS_LEN - CHANGED_OCTET] -
++ g_pNvramInfo->ucaBaseMacAddr[NVRAM_MAC_ADDRESS_LEN - CHANGED_OCTET]);
++
++ // if overflow 255 (negitive), add 256 to have the correct index
++ if (idx < 0)
++ idx += 256;
++ ulIdx = (unsigned long) (idx >> SHIFT_BITS);
++
++ if( ulIdx < g_pNvramInfo->ulNumMacAddrs )
++ {
++ PMAC_ADDR_INFO pMai = &g_pNvramInfo->MacAddrs[ulIdx];
++ if( pMai->chInUse == 1 )
++ {
++ pMai->chInUse = 0;
++ nRet = 0;
++ }
++ }
++
++ return( nRet );
++} /* kerSysReleaseMacAddr */
++
++int kerSysGetSdramSize( void )
++{
++ if (boot_loader_type == BOOT_CFE) {
++ return( (int) g_pNvramInfo->ulSdramSize );
++ }
++ else {
++ printk("kerSysGetSdramSize : 0x%08X\n", (int)getMemorySize() + 0x00040000);
++ return((int)getMemorySize() + 0x00040000);
++ }
++} /* kerSysGetSdramSize */
++
++
++void kerSysLedCtrl(BOARD_LED_NAME ledName, BOARD_LED_STATE ledState)
++{
++ if (g_ledInitialized)
++ boardLedCtrl(ledName, ledState);
++}
++
++unsigned int kerSysMonitorPollHook( struct file *f, struct poll_table_struct *t)
++{
++ int mask = (*g_orig_fop_poll) (f, t);
++
++ if( g_wakeup_monitor == 1 && g_monitor_file == f )
++ {
++ /* If g_wakeup_monitor is non-0, the user mode application needs to
++ * return from a blocking select function. Return POLLPRI which will
++ * cause the select to return with the exception descriptor set.
++ */
++ mask |= POLLPRI;
++ g_wakeup_monitor = 0;
++ }
++
++ return( mask );
++}
++
++/* Put the user mode application that monitors link state on a run queue. */
++void kerSysWakeupMonitorTask( void )
++{
++ g_wakeup_monitor = 1;
++ if( g_monitor_task )
++ wake_up_process( g_monitor_task );
++}
++
++//<<JUNHON, 2004/09/15, get reset button status , tim hou , 05/04/12
++int kerSysGetResetHold(void)
++{
++ unsigned short gpio;
++
++ if( BpGetPressAndHoldResetGpio( &gpio ) == BP_SUCCESS )
++ {
++ unsigned long gpio_mask = GPIO_NUM_TO_MASK(gpio);
++ volatile unsigned long *gpio_reg = &GPIO->GPIOio;
++
++ if( (gpio & ~BP_ACTIVE_MASK) >= 32 )
++ {
++ gpio_mask = GPIO_NUM_TO_MASK_HIGH(gpio);
++ gpio_reg = &GPIO->GPIOio_high;
++ }
++ //printk("gpio=%04x,gpio_mask=%04x,gpio_reg=%04x\n",gpio,gpio_mask,*gpio_reg);
++ if(*gpio_reg & gpio_mask) //press down
++ return RESET_BUTTON_UP;
++ }
++ return RESET_BUTTON_PRESSDOWN;
++}
++//<<JUNHON, 2004/09/15
++
++/***************************************************************************
++ * Dying gasp ISR and functions.
++ ***************************************************************************/
++#define KERSYS_DBG printk
++
++#if defined(CONFIG_BCM96345)
++#define CYCLE_PER_US 70
++#elif defined(CONFIG_BCM96348) || defined(CONFIG_BCM96338)
++/* The BCM6348 cycles per microsecond is really variable since the BCM6348
++ * MIPS speed can vary depending on the PLL settings. However, an appoximate
++ * value of 120 will still work OK for the test being done.
++ */
++#define CYCLE_PER_US 120
++#endif
++#define DG_GLITCH_TO (100*CYCLE_PER_US)
++
++static void __init kerSysDyingGaspMapIntr()
++{
++ unsigned long ulIntr;
++
++#if defined(CONFIG_BCM96348) || defined(_BCM96348_) || defined(CONFIG_BCM96338) || defined(_BCM96338_)
++ if( BpGetAdslDyingGaspExtIntr( &ulIntr ) == BP_SUCCESS ) {
++ BcmHalMapInterrupt((FN_HANDLER)kerSysDyingGaspIsr, 0, INTERRUPT_ID_DG);
++ BcmHalInterruptEnable( INTERRUPT_ID_DG );
++ }
++#elif defined(CONFIG_BCM96345) || defined(_BCM96345_)
++ if( BpGetAdslDyingGaspExtIntr( &ulIntr ) == BP_SUCCESS ) {
++ ulIntr += INTERRUPT_ID_EXTERNAL_0;
++ BcmHalMapInterrupt((FN_HANDLER)kerSysDyingGaspIsr, 0, ulIntr);
++ BcmHalInterruptEnable( ulIntr );
++ }
++#endif
++
++}
++
++void kerSysSetWdTimer(ulong timeUs)
++{
++ TIMER->WatchDogDefCount = timeUs * (FPERIPH/1000000);
++ TIMER->WatchDogCtl = 0xFF00;
++ TIMER->WatchDogCtl = 0x00FF;
++}
++
++ulong kerSysGetCycleCount(void)
++{
++ ulong cnt;
++#ifdef _WIN32_WCE
++ cnt = 0;
++#else
++ __asm volatile("mfc0 %0, $9":"=d"(cnt));
++#endif
++ return(cnt);
++}
++
++static Bool kerSysDyingGaspCheckPowerLoss(void)
++{
++ ulong clk0;
++ ulong ulIntr;
++
++ ulIntr = 0;
++ clk0 = kerSysGetCycleCount();
++
++ UART->Data = 'D';
++ UART->Data = '%';
++ UART->Data = 'G';
++
++#if defined(CONFIG_BCM96345)
++ BpGetAdslDyingGaspExtIntr( &ulIntr );
++
++ do {
++ ulong clk1;
++
++ clk1 = kerSysGetCycleCount(); /* time cleared */
++ /* wait a little to get new reading */
++ while ((kerSysGetCycleCount()-clk1) < CYCLE_PER_US*2)
++ ;
++ } while ((0 == (PERF->ExtIrqCfg & (1 << (ulIntr + EI_STATUS_SHFT)))) && ((kerSysGetCycleCount() - clk0) < DG_GLITCH_TO));
++
++ if (PERF->ExtIrqCfg & (1 << (ulIntr + EI_STATUS_SHFT))) { /* power glitch */
++ BcmHalInterruptEnable( ulIntr + INTERRUPT_ID_EXTERNAL_0);
++ KERSYS_DBG(" - Power glitch detected. Duration: %ld us\n", (kerSysGetCycleCount() - clk0)/CYCLE_PER_US);
++ return 0;
++ }
++#elif (defined(CONFIG_BCM96348) || defined(CONFIG_BCM96338)) && !defined(VXWORKS)
++ do {
++ ulong clk1;
++
++ clk1 = kerSysGetCycleCount(); /* time cleared */
++ /* wait a little to get new reading */
++ while ((kerSysGetCycleCount()-clk1) < CYCLE_PER_US*2)
++ ;
++ } while ((PERF->IrqStatus & (1 << (INTERRUPT_ID_DG - INTERNAL_ISR_TABLE_OFFSET))) && ((kerSysGetCycleCount() - clk0) < DG_GLITCH_TO));
++
++ if (!(PERF->IrqStatus & (1 << (INTERRUPT_ID_DG - INTERNAL_ISR_TABLE_OFFSET)))) {
++ BcmHalInterruptEnable( INTERRUPT_ID_DG );
++ KERSYS_DBG(" - Power glitch detected. Duration: %ld us\n", (kerSysGetCycleCount() - clk0)/CYCLE_PER_US);
++ return 0;
++ }
++#endif
++ return 1;
++}
++
++static void kerSysDyingGaspShutdown( void )
++{
++ kerSysSetWdTimer(1000000);
++#if defined(CONFIG_BCM96345)
++ PERF->blkEnables &= ~(EMAC_CLK_EN | USB_CLK_EN | CPU_CLK_EN);
++#elif defined(CONFIG_BCM96348)
++ PERF->blkEnables &= ~(EMAC_CLK_EN | USBS_CLK_EN | USBH_CLK_EN | SAR_CLK_EN);
++#endif
++}
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++static irqreturn_t kerSysDyingGaspIsr(int irq, void * dev_id, struct pt_regs * regs)
++#else
++static unsigned int kerSysDyingGaspIsr(void)
++#endif
++{
++ struct list_head *pos;
++ CB_DGASP_LIST *tmp, *dsl = NULL;
++
++ if (kerSysDyingGaspCheckPowerLoss()) {
++
++ /* first to turn off everything other than dsl */
++ list_for_each(pos, &g_cb_dgasp_list_head->list) {
++ tmp = list_entry(pos, CB_DGASP_LIST, list);
++ if(strncmp(tmp->name, "dsl", 3)) {
++ (tmp->cb_dgasp_fn)(tmp->context);
++ }else {
++ dsl = tmp;
++ }
++ }
++
++ /* now send dgasp */
++ if(dsl)
++ (dsl->cb_dgasp_fn)(dsl->context);
++
++ /* reset and shutdown system */
++ kerSysDyingGaspShutdown();
++ }
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
++return( IRQ_HANDLED );
++#else
++ return( 1 );
++#endif
++}
++
++static void __init kerSysInitDyingGaspHandler( void )
++{
++ CB_DGASP_LIST *new_node;
++
++ if( g_cb_dgasp_list_head != NULL) {
++ printk("Error: kerSysInitDyingGaspHandler: list head is not null\n");
++ return;
++ }
++ new_node= (CB_DGASP_LIST *)kmalloc(sizeof(CB_DGASP_LIST), GFP_KERNEL);
++ memset(new_node, 0x00, sizeof(CB_DGASP_LIST));
++ INIT_LIST_HEAD(&new_node->list);
++ g_cb_dgasp_list_head = new_node;
++
++} /* kerSysInitDyingGaspHandler */
++
++static void __exit kerSysDeinitDyingGaspHandler( void )
++{
++ struct list_head *pos;
++ CB_DGASP_LIST *tmp;
++
++ if(g_cb_dgasp_list_head == NULL)
++ return;
++
++ list_for_each(pos, &g_cb_dgasp_list_head->list) {
++ tmp = list_entry(pos, CB_DGASP_LIST, list);
++ list_del(pos);
++ kfree(tmp);
++ }
++
++ kfree(g_cb_dgasp_list_head);
++ g_cb_dgasp_list_head = NULL;
++
++} /* kerSysDeinitDyingGaspHandler */
++
++void kerSysRegisterDyingGaspHandler(char *devname, void *cbfn, void *context)
++{
++ CB_DGASP_LIST *new_node;
++
++ if( g_cb_dgasp_list_head == NULL) {
++ printk("Error: kerSysRegisterDyingGaspHandler: list head is null\n");
++ return;
++ }
++
++ if( devname == NULL || cbfn == NULL ) {
++ printk("Error: kerSysRegisterDyingGaspHandler: register info not enough (%s,%x,%x)\n", devname, (unsigned int)cbfn, (unsigned int)context);
++ return;
++ }
++
++ new_node= (CB_DGASP_LIST *)kmalloc(sizeof(CB_DGASP_LIST), GFP_KERNEL);
++ memset(new_node, 0x00, sizeof(CB_DGASP_LIST));
++ INIT_LIST_HEAD(&new_node->list);
++ strncpy(new_node->name, devname, IFNAMSIZ);
++ new_node->cb_dgasp_fn = (cb_dgasp_t)cbfn;
++ new_node->context = context;
++ list_add(&new_node->list, &g_cb_dgasp_list_head->list);
++
++ printk("dgasp: kerSysRegisterDyingGaspHandler: %s registered \n", devname);
++
++} /* kerSysRegisterDyingGaspHandler */
++
++void kerSysDeregisterDyingGaspHandler(char *devname)
++{
++ struct list_head *pos;
++ CB_DGASP_LIST *tmp;
++
++ if(g_cb_dgasp_list_head == NULL) {
++ printk("Error: kerSysDeregisterDyingGaspHandler: list head is null\n");
++ return;
++ }
++
++ if(devname == NULL) {
++ printk("Error: kerSysDeregisterDyingGaspHandler: devname is null\n");
++ return;
++ }
++
++ printk("kerSysDeregisterDyingGaspHandler: %s is deregistering\n", devname);
++
++ list_for_each(pos, &g_cb_dgasp_list_head->list) {
++ tmp = list_entry(pos, CB_DGASP_LIST, list);
++ if(!strcmp(tmp->name, devname)) {
++ list_del(pos);
++ kfree(tmp);
++ printk("kerSysDeregisterDyingGaspHandler: %s is deregistered\n", devname);
++ return;
++ }
++ }
++ printk("kerSysDeregisterDyingGaspHandler: %s not (de)registered\n", devname);
++
++} /* kerSysDeregisterDyingGaspHandler */
++
++//EXPORT_SYMBOL(kerSysNvRamGet);
++EXPORT_SYMBOL(kerSysGetMacAddress);
++EXPORT_SYMBOL(kerSysReleaseMacAddress);
++EXPORT_SYMBOL(kerSysGetSdramSize);
++EXPORT_SYMBOL(kerSysLedCtrl);
++EXPORT_SYMBOL(kerSysGetResetHold);
++EXPORT_SYMBOL(kerSysLedRegisterHwHandler);
++EXPORT_SYMBOL(BpGetBoardIds);
++EXPORT_SYMBOL(BpGetSdramSize);
++EXPORT_SYMBOL(BpGetPsiSize);
++EXPORT_SYMBOL(BpGetEthernetMacInfo);
++EXPORT_SYMBOL(BpGetRj11InnerOuterPairGpios);
++EXPORT_SYMBOL(BpGetPressAndHoldResetGpio);
++EXPORT_SYMBOL(BpGetVoipResetGpio);
++EXPORT_SYMBOL(BpGetVoipIntrGpio);
++EXPORT_SYMBOL(BpGetPcmciaResetGpio);
++EXPORT_SYMBOL(BpGetRtsCtsUartGpios);
++EXPORT_SYMBOL(BpGetAdslLedGpio);
++EXPORT_SYMBOL(BpGetAdslFailLedGpio);
++EXPORT_SYMBOL(BpGetWirelessLedGpio);
++EXPORT_SYMBOL(BpGetUsbLedGpio);
++EXPORT_SYMBOL(BpGetHpnaLedGpio);
++EXPORT_SYMBOL(BpGetWanDataLedGpio);
++EXPORT_SYMBOL(BpGetPppLedGpio);
++EXPORT_SYMBOL(BpGetPppFailLedGpio);
++EXPORT_SYMBOL(BpGetVoipLedGpio);
++EXPORT_SYMBOL(BpGetWirelessExtIntr);
++EXPORT_SYMBOL(BpGetAdslDyingGaspExtIntr);
++EXPORT_SYMBOL(BpGetVoipExtIntr);
++EXPORT_SYMBOL(BpGetHpnaExtIntr);
++EXPORT_SYMBOL(BpGetHpnaChipSelect);
++EXPORT_SYMBOL(BpGetVoipChipSelect);
++EXPORT_SYMBOL(BpGetWirelessSesBtnGpio);
++EXPORT_SYMBOL(BpGetWirelessSesExtIntr);
++EXPORT_SYMBOL(BpGetWirelessSesLedGpio);
++EXPORT_SYMBOL(kerSysRegisterDyingGaspHandler);
++EXPORT_SYMBOL(kerSysDeregisterDyingGaspHandler);
++EXPORT_SYMBOL(kerSysGetCycleCount);
++EXPORT_SYMBOL(kerSysSetWdTimer);
++EXPORT_SYMBOL(kerSysWakeupMonitorTask);
++
+diff -urN linux.old/arch/mips/bcm963xx/boardparms.c linux.dev/arch/mips/bcm963xx/boardparms.c
+--- linux.old/arch/mips/bcm963xx/boardparms.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/boardparms.c 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,2391 @@
++/*
++<:copyright-gpl
++
++ Copyright 2003 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ for more details.
++
++ You should have received a copy of the GNU General Public License along
++ with this program; if not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++
++:>
++*/
++/**************************************************************************
++ * File Name : boardparms.c
++ *
++ * Description: This file contains the implementation for the BCM63xx board
++ * parameter access functions.
++ *
++ * Updates : 07/14/2003 Created.
++ ***************************************************************************/
++
++/* Includes. */
++#include "boardparms.h"
++
++/* Defines. */
++
++/* Default psi size in K bytes */
++#define BP_PSI_DEFAULT_SIZE 24
++
++/* Typedefs */
++typedef struct boardparameters
++{
++ char szBoardId[BP_BOARD_ID_LEN]; /* board id string */
++ ETHERNET_MAC_INFO EnetMacInfos[BP_MAX_ENET_MACS];
++ VOIP_DSP_INFO VoIPDspInfo[BP_MAX_VOIP_DSP];
++ unsigned short usSdramSize; /* SDRAM size and type */
++ unsigned short usPsiSize; /* persistent storage in K bytes */
++ unsigned short usGpioRj11InnerPair; /* GPIO pin or not defined */
++ unsigned short usGpioRj11OuterPair; /* GPIO pin or not defined */
++ unsigned short usGpioPressAndHoldReset; /* GPIO pin or not defined */
++ unsigned short usGpioPcmciaReset; /* GPIO pin or not defined */
++ unsigned short usGpioUartRts; /* GPIO pin or not defined */
++ unsigned short usGpioUartCts; /* GPIO pin or not defined */
++ unsigned short usGpioLedAdsl; /* GPIO pin or not defined */
++ unsigned short usGpioLedAdslFail; /* GPIO pin or not defined */
++ unsigned short usGpioLedWireless; /* GPIO pin or not defined */
++ unsigned short usGpioLedUsb; /* GPIO pin or not defined */
++ unsigned short usGpioLedHpna; /* GPIO pin or not defined */
++ unsigned short usGpioLedWanData; /* GPIO pin or not defined */
++ unsigned short usGpioLedPpp; /* GPIO pin or not defined */
++ unsigned short usGpioLedPppFail; /* GPIO pin or not defined */
++ unsigned short usGpioLedBlPowerOn; /* GPIO pin or not defined */
++ unsigned short usGpioLedBlAlarm; /* GPIO pin or not defined */
++ unsigned short usGpioLedBlResetCfg; /* GPIO pin or not defined */
++ unsigned short usGpioLedBlStop; /* GPIO pin or not defined */
++ unsigned short usExtIntrWireless; /* ext intr or not defined */
++ unsigned short usExtIntrAdslDyingGasp; /* ext intr or not defined */
++ unsigned short usExtIntrHpna; /* ext intr or not defined */
++ unsigned short usCsHpna; /* chip select not defined */
++ unsigned short usAntInUseWireless; /* antenna in use or not defined */
++ unsigned short usGpioSesBtnWireless; /* GPIO pin or not defined */
++ unsigned short usExtIntrSesBtnWireless; /* ext intr or not defined */
++ unsigned short usGpioLedSesWireless; /* GPIO pin or not defined */
++} BOARD_PARAMETERS, *PBOARD_PARAMETERS;
++
++/* Variables */
++#if defined(_BCM96338_) || defined(CONFIG_BCM96338)
++static BOARD_PARAMETERS g_bcm96338sv =
++{
++ "96338SV", /* szBoardId */
++ {{BP_ENET_INTERNAL_PHY, /* ucPhyType */
++ 0x01, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_NOT_DEFINED}, /* usReverseMii */
++ {BP_ENET_NO_PHY}}, /* ucPhyType */
++ {{BP_VOIP_NO_DSP}, /* ucDspType */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_16MB_1_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_NOT_DEFINED, /* usGpioRj11InnerPair */
++ BP_NOT_DEFINED, /* usGpioRj11OuterPair */
++ BP_NOT_DEFINED, /* usGpioPressAndHoldReset */
++ BP_NOT_DEFINED, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_NOT_DEFINED, /* usGpioLedAdsl */
++ BP_NOT_DEFINED, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_NOT_DEFINED, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_NOT_DEFINED, /* usGpioLedWanData */
++ BP_NOT_DEFINED, /* usGpioLedPpp */
++ BP_NOT_DEFINED, /* usGpioLedPppFail */
++ BP_NOT_DEFINED, /* usGpioLedBlPowerOn */
++ BP_NOT_DEFINED, /* usGpioLedBlAlarm */
++ BP_NOT_DEFINED, /* usGpioLedBlResetCfg */
++ BP_NOT_DEFINED, /* usGpioLedBlStop */
++ BP_NOT_DEFINED, /* usExtIntrWireless */
++ BP_HW_DEFINED, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_NOT_DEFINED, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++static BOARD_PARAMETERS g_bcm96338l2m8m =
++{
++ "96338L-2M-8M", /* szBoardId */
++ {{BP_ENET_INTERNAL_PHY, /* ucPhyType */
++ 0x01, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_NOT_DEFINED}, /* usReverseMii */
++ {BP_ENET_NO_PHY}}, /* ucPhyType */
++ {{BP_VOIP_NO_DSP}, /* ucDspType */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_8MB_1_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_NOT_DEFINED, /* usGpioRj11InnerPair */
++ BP_NOT_DEFINED, /* usGpioRj11OuterPair */
++ BP_NOT_DEFINED, /* usGpioPressAndHoldReset */
++ BP_NOT_DEFINED, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_NOT_DEFINED, /* usGpioLedAdsl */
++ BP_GPIO_2_AL, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_NOT_DEFINED, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_GPIO_3_AL, /* usGpioLedWanData */
++ BP_GPIO_3_AL, /* usGpioLedPpp */
++ BP_GPIO_4_AL, /* usGpioLedPppFail */
++ BP_GPIO_0_AL, /* usGpioLedBlPowerOn */
++ BP_NOT_DEFINED, /* usGpioLedBlAlarm */
++ BP_GPIO_3_AL, /* usGpioLedBlResetCfg */
++ BP_GPIO_1_AL, /* usGpioLedBlStop */
++ BP_NOT_DEFINED, /* usExtIntrWireless */
++ BP_HW_DEFINED, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_NOT_DEFINED, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++static PBOARD_PARAMETERS g_BoardParms[] =
++ {&g_bcm96338sv, &g_bcm96338l2m8m, 0};
++#endif
++
++#if defined(_BCM96345_) || defined(CONFIG_BCM96345)
++static BOARD_PARAMETERS g_bcm96345r =
++{
++ "96345R", /* szBoardId */
++ {{BP_ENET_INTERNAL_PHY, /* ucPhyType */
++ 0x01, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_NOT_DEFINED}, /* usReverseMii */
++ {BP_ENET_NO_PHY}}, /* ucPhyType */
++ {{BP_VOIP_NO_DSP}, /* ucDspType */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_8MB_1_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_GPIO_11_AH, /* usGpioRj11InnerPair */
++ BP_GPIO_12_AH, /* usGpioRj11OuterPair */
++ BP_GPIO_13_AH, /* usGpioPressAndHoldReset */
++ BP_NOT_DEFINED, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_GPIO_8_AH, /* usGpioLedAdsl */
++ BP_NOT_DEFINED, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_NOT_DEFINED, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_GPIO_8_AH, /* usGpioLedWanData */
++ BP_GPIO_9_AH, /* usGpioLedPpp */
++ BP_NOT_DEFINED, /* usGpioLedPppFail */
++ BP_NOT_DEFINED, /* usGpioLedBlPowerOn */
++ BP_GPIO_10_AH, /* usGpioLedBlAlarm */
++ BP_GPIO_9_AH, /* usGpioLedBlResetCfg */
++ BP_GPIO_8_AH, /* usGpioLedBlStop */
++ BP_NOT_DEFINED, /* usExtIntrWireless */
++ BP_EXT_INTR_0, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_NOT_DEFINED, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++
++static BOARD_PARAMETERS g_bcm96345gw2 =
++{
++ /* A hardware jumper determines whether GPIO 13 is used for Press and Hold
++ * Reset or RTS.
++ */
++ "96345GW2", /* szBoardId */
++ {{BP_ENET_EXTERNAL_SWITCH, /* ucPhyType */
++ 0x00, /* ucPhyAddress */
++ BP_GPIO_0_AH, /* usGpioPhySpiSck */
++ BP_GPIO_4_AH, /* usGpioPhySpiSs */
++ BP_GPIO_12_AH, /* usGpioPhySpiMosi */
++ BP_GPIO_11_AH, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x04, /* numSwitchPorts */
++ BP_ENET_CONFIG_GPIO, /* usConfigType */
++ BP_ENET_REVERSE_MII}, /* usReverseMii */
++ {BP_ENET_NO_PHY}}, /* ucPhyType */
++ {{BP_VOIP_DSP, /* ucDspType */
++ 0x00, /* ucDspAddress */
++ BP_EXT_INTR_1, /* usExtIntrVoip */
++ BP_GPIO_6_AH, /* usGpioVoipReset */
++ BP_GPIO_15_AH, /* usGpioVoipIntr */
++ BP_NOT_DEFINED, /* usGpioLedVoip */
++ BP_CS_2}, /* usCsVoip */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_16MB_1_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_NOT_DEFINED, /* usGpioRj11InnerPair */
++ BP_NOT_DEFINED, /* usGpioRj11OuterPair */
++ BP_GPIO_13_AH, /* usGpioPressAndHoldReset */
++ BP_GPIO_2_AH, /* usGpioPcmciaReset */
++ BP_GPIO_13_AH, /* usGpioUartRts */
++ BP_GPIO_9_AH, /* usGpioUartCts */
++ BP_GPIO_8_AH, /* usGpioLedAdsl */
++ BP_NOT_DEFINED, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_GPIO_7_AH, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_GPIO_8_AH, /* usGpioLedWanData */
++ BP_NOT_DEFINED, /* usGpioLedPpp */
++ BP_NOT_DEFINED, /* usGpioLedPppFail */
++ BP_NOT_DEFINED, /* usGpioLedBlPowerOn */
++ BP_GPIO_10_AH, /* usGpioLedBlAlarm */
++ BP_GPIO_7_AH, /* usGpioLedBlResetCfg */
++ BP_GPIO_8_AH, /* usGpioLedBlStop */
++ BP_EXT_INTR_2, /* usExtIntrWireless */
++ BP_EXT_INTR_0, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_WLAN_ANT_MAIN, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++
++static BOARD_PARAMETERS g_bcm96345gw =
++{
++ "96345GW", /* szBoardId */
++ {{BP_ENET_EXTERNAL_SWITCH, /* ucPhyType */
++ 0x00, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x04, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_ENET_NO_REVERSE_MII}, /* usReverseMii */
++ {BP_ENET_NO_PHY}}, /* ucPhyType */
++ {{BP_VOIP_DSP, /* ucDspType */
++ 0x00, /* ucDspAddress */
++ BP_EXT_INTR_1, /* usExtIntrVoip */
++ BP_GPIO_6_AH, /* usGpioVoipReset */
++ BP_GPIO_15_AH, /* usGpioVoipIntr */
++ BP_NOT_DEFINED, /* usGpioLedVoip */
++ BP_CS_2}, /* usCsVoip */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_16MB_1_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_GPIO_11_AH, /* usGpioRj11InnerPair */
++ BP_GPIO_1_AH, /* usGpioRj11OuterPair */
++ BP_GPIO_13_AH, /* usGpioPressAndHoldReset */
++ BP_GPIO_2_AH, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_GPIO_8_AH, /* usGpioLedAdsl */
++ BP_NOT_DEFINED, /* usGpioLedAdslFail */
++ BP_GPIO_10_AH, /* usGpioLedWireless */
++ BP_GPIO_7_AH, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_GPIO_8_AH, /* usGpioLedWanData */
++ BP_NOT_DEFINED, /* usGpioLedPpp */
++ BP_NOT_DEFINED, /* usGpioLedPppFail */
++ BP_NOT_DEFINED, /* usGpioLedBlPowerOn */
++ BP_GPIO_9_AH, /* usGpioLedBlAlarm */
++ BP_GPIO_10_AH, /* usGpioLedBlResetCfg */
++ BP_GPIO_8_AH, /* usGpioLedBlStop */
++ BP_EXT_INTR_2, /* usExtIntrWireless */
++ BP_EXT_INTR_0, /* usExtIntrAdslDyingGasp */
++ BP_EXT_INTR_3, /* usExtIntrHpna */
++ BP_CS_1, /* usCsHpna */
++ BP_WLAN_ANT_MAIN, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++
++static BOARD_PARAMETERS g_bcm96335r =
++{
++ "96335R", /* szBoardId */
++ {{BP_ENET_INTERNAL_PHY, /* ucPhyType */
++ 0x01, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_NOT_DEFINED}, /* usReverseMii */
++ {BP_ENET_NO_PHY}}, /* ucPhyType */
++ {{BP_VOIP_NO_DSP}, /* ucDspType */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_8MB_1_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_NOT_DEFINED, /* usGpioRj11InnerPair */
++ BP_NOT_DEFINED, /* usGpioRj11OuterPair */
++ BP_GPIO_14_AH, /* usGpioPressAndHoldReset */
++ BP_NOT_DEFINED, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_GPIO_9_AH, /* usGpioLedAdsl */
++ BP_NOT_DEFINED, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_NOT_DEFINED, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_GPIO_9_AH, /* usGpioLedWanData */
++ BP_GPIO_8_AH, /* usGpioLedPpp */
++ BP_NOT_DEFINED, /* usGpioLedPppFail */
++ BP_NOT_DEFINED, /* usGpioLedBlPowerOn */
++ BP_GPIO_10_AH, /* usGpioLedBlAlarm */
++ BP_GPIO_8_AH, /* usGpioLedBlResetCfg */
++ BP_GPIO_9_AH, /* usGpioLedBlStop */
++ BP_NOT_DEFINED, /* usExtIntrWireless */
++ BP_NOT_DEFINED, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_NOT_DEFINED, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++
++static BOARD_PARAMETERS g_bcm96345r0 =
++{
++ "96345R0", /* szBoardId */
++ {{BP_ENET_INTERNAL_PHY, /* ucPhyType */
++ 0x01, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_NOT_DEFINED}, /* usReverseMii */
++ {BP_ENET_NO_PHY}}, /* ucPhyType */
++ {{BP_VOIP_NO_DSP}, /* ucDspType */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_8MB_1_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_NOT_DEFINED, /* usGpioRj11InnerPair */
++ BP_NOT_DEFINED, /* usGpioRj11OuterPair */
++ BP_NOT_DEFINED, /* usGpioPressAndHoldReset */
++ BP_NOT_DEFINED, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_GPIO_8_AH, /* usGpioLedAdsl */
++ BP_NOT_DEFINED, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_NOT_DEFINED, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_GPIO_9_AH, /* usGpioLedWanData */
++ BP_GPIO_9_AH, /* usGpioLedPpp */
++ BP_NOT_DEFINED, /* usGpioLedPppFail */
++ BP_NOT_DEFINED, /* usGpioLedBlPowerOn */
++ BP_GPIO_9_AH, /* usGpioLedBlAlarm */
++ BP_GPIO_8_AH, /* usGpioLedBlResetCfg */
++ BP_GPIO_8_AH, /* usGpioLedBlStop */
++ BP_NOT_DEFINED, /* usExtIntrWireless */
++ BP_NOT_DEFINED, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_NOT_DEFINED, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++
++static BOARD_PARAMETERS g_bcm96345rs =
++{
++ "96345RS", /* szBoardId */
++ {{BP_ENET_EXTERNAL_SWITCH, /* ucPhyType */
++ 0x00, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_ENET_NO_REVERSE_MII}, /* usReverseMii */
++ {BP_ENET_NO_PHY}}, /* ucPhyType */
++ {{BP_VOIP_NO_DSP}, /* ucDspType */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_8MB_1_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_GPIO_11_AH, /* usGpioRj11InnerPair */
++ BP_GPIO_12_AH, /* usGpioRj11OuterPair */
++ BP_GPIO_13_AH, /* usGpioPressAndHoldReset */
++ BP_NOT_DEFINED, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_GPIO_8_AH, /* usGpioLedAdsl */
++ BP_NOT_DEFINED, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_NOT_DEFINED, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_GPIO_8_AH, /* usGpioLedWanData */
++ BP_GPIO_9_AH, /* usGpioLedPpp */
++ BP_NOT_DEFINED, /* usGpioLedPppFail */
++ BP_NOT_DEFINED, /* usGpioLedBlPowerOn */
++ BP_GPIO_10_AH, /* usGpioLedBlAlarm */
++ BP_GPIO_9_AH, /* usGpioLedBlResetCfg */
++ BP_GPIO_8_AH, /* usGpioLedBlStop */
++ BP_NOT_DEFINED, /* usExtIntrWireless */
++ BP_EXT_INTR_0, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_NOT_DEFINED, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++
++static PBOARD_PARAMETERS g_BoardParms[] =
++ {&g_bcm96345r, &g_bcm96345gw2, &g_bcm96345gw, &g_bcm96335r, &g_bcm96345r0,
++ &g_bcm96345rs, 0};
++#endif
++
++#if defined(_BCM96348_) || defined(CONFIG_BCM96348)
++
++static BOARD_PARAMETERS g_bcm96348r =
++{
++ "96348R", /* szBoardId */
++ {{BP_ENET_INTERNAL_PHY, /* ucPhyType */
++ 0x01, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_NOT_DEFINED}, /* usReverseMii */
++ {BP_ENET_NO_PHY}}, /* ucPhyType */
++ {{BP_VOIP_NO_DSP}, /* ucDspType */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_8MB_1_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_NOT_DEFINED, /* usGpioRj11InnerPair */
++ BP_NOT_DEFINED, /* usGpioRj11OuterPair */
++ BP_GPIO_7_AH, /* usGpioPressAndHoldReset */
++ BP_NOT_DEFINED, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_NOT_DEFINED, /* usGpioLedAdsl */
++ BP_GPIO_2_AL, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_NOT_DEFINED, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_GPIO_3_AL, /* usGpioLedWanData */
++ BP_GPIO_3_AL, /* usGpioLedPpp */
++ BP_GPIO_4_AL, /* usGpioLedPppFail */
++ BP_GPIO_0_AL, /* usGpioLedBlPowerOn */
++ BP_NOT_DEFINED, /* usGpioLedBlAlarm */
++ BP_GPIO_3_AL, /* usGpioLedBlResetCfg */
++ BP_GPIO_1_AL, /* usGpioLedBlStop */
++ BP_NOT_DEFINED, /* usExtIntrWireless */
++ BP_HW_DEFINED, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_NOT_DEFINED, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++
++static BOARD_PARAMETERS g_bcm96348lv =
++{
++ "96348LV", /* szBoardId */
++ {{BP_ENET_INTERNAL_PHY, /* ucPhyType */
++ 0x01, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_NOT_DEFINED}, /* usReverseMii */
++ {BP_ENET_EXTERNAL_PHY, /* ucPhyType */
++ 0x02, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_GPIO_5_AL, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_NOT_DEFINED}}, /* usReverseMii */
++ {{BP_VOIP_NO_DSP}, /* ucDspType */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_16MB_2_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_NOT_DEFINED, /* usGpioRj11InnerPair */
++ BP_NOT_DEFINED, /* usGpioRj11OuterPair */
++ BP_GPIO_7_AH, /* usGpioPressAndHoldReset */
++ BP_NOT_DEFINED, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_NOT_DEFINED, /* usGpioLedAdsl */
++ BP_GPIO_2_AL, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_NOT_DEFINED, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_GPIO_3_AL, /* usGpioLedWanData */
++ BP_GPIO_3_AL, /* usGpioLedPpp */
++ BP_GPIO_4_AL, /* usGpioLedPppFail */
++ BP_GPIO_0_AL, /* usGpioLedBlPowerOn */
++ BP_NOT_DEFINED, /* usGpioLedBlAlarm */
++ BP_GPIO_3_AL, /* usGpioLedBlResetCfg */
++ BP_GPIO_1_AL, /* usGpioLedBlStop */
++ BP_NOT_DEFINED, /* usExtIntrWireless */
++ BP_NOT_DEFINED, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_NOT_DEFINED, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++
++static BOARD_PARAMETERS g_bcm96348gw =
++{
++ "96348GW", /* szBoardId */
++ {{BP_ENET_INTERNAL_PHY, /* ucPhyType */
++ 0x01, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_NOT_DEFINED}, /* usReverseMii */
++ {BP_ENET_EXTERNAL_SWITCH, /* ucPhyType */
++ 0x00, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x03, /* numSwitchPorts */
++ BP_ENET_CONFIG_SPI_SSB_0, /* usConfigType */
++ BP_ENET_REVERSE_MII}}, /* usReverseMii */
++ {{BP_VOIP_DSP, /* ucDspType */
++ 0x00, /* ucDspAddress */
++ BP_EXT_INTR_2, /* usExtIntrVoip */
++ BP_GPIO_6_AH, /* usGpioVoipReset */
++ BP_GPIO_34_AH, /* usGpioVoipIntr */
++ BP_NOT_DEFINED, /* usGpioLedVoip */
++ BP_CS_2}, /* usCsVoip */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_16MB_2_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_NOT_DEFINED, /* usGpioRj11InnerPair */
++ BP_NOT_DEFINED, /* usGpioRj11OuterPair */
++ BP_GPIO_33_AL, /* usGpioPressAndHoldReset */
++ BP_NOT_DEFINED, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_NOT_DEFINED, /* usGpioLedAdsl */
++ BP_GPIO_2_AL, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_NOT_DEFINED, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_GPIO_3_AL, /* usGpioLedWanData */
++ BP_GPIO_3_AL, /* usGpioLedPpp */
++ BP_GPIO_4_AL, /* usGpioLedPppFail */
++ BP_GPIO_0_AL, /* usGpioLedBlPowerOn */
++ BP_NOT_DEFINED, /* usGpioLedBlAlarm */
++ BP_GPIO_3_AL, /* usGpioLedBlResetCfg */
++ BP_GPIO_1_AL, /* usGpioLedBlStop */
++ BP_NOT_DEFINED, /* usExtIntrWireless */
++ BP_HW_DEFINED, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_WLAN_ANT_MAIN, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* BP_GPIO_35_AH, */ /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* BP_EXT_INTR_3, */ /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* BP_GPIO_0_AL */ /* usGpioLedSesWireless */
++};
++
++
++static BOARD_PARAMETERS g_bcm96348gw_10 =
++{
++ "96348GW-10", /* szBoardId */
++ {{BP_ENET_INTERNAL_PHY, /* ucPhyType */
++ 0x01, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_NOT_DEFINED}, /* usReverseMii */
++ {BP_ENET_EXTERNAL_SWITCH, /* ucPhyType */
++ 0x00, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x03, /* numSwitchPorts */
++ BP_ENET_CONFIG_SPI_SSB_1, /* usConfigType */
++ BP_ENET_REVERSE_MII}}, /* usReverseMii */
++ {{BP_VOIP_DSP, /* ucDspType */
++ 0x00, /* ucDspAddress */
++ BP_EXT_INTR_2, /* usExtIntrVoip */
++ BP_GPIO_6_AH, /* usGpioVoipReset */
++ BP_GPIO_34_AH, /* usGpioVoipIntr */
++ BP_NOT_DEFINED, /* usGpioLedVoip */
++ BP_CS_2}, /* usCsVoip */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_16MB_2_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_NOT_DEFINED, /* usGpioRj11InnerPair */
++ BP_NOT_DEFINED, /* usGpioRj11OuterPair */
++ BP_GPIO_33_AL, /* usGpioPressAndHoldReset */
++ BP_NOT_DEFINED, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_NOT_DEFINED, /* usGpioLedAdsl */
++ BP_GPIO_2_AL, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_NOT_DEFINED, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_GPIO_3_AL, /* usGpioLedWanData */
++ BP_GPIO_3_AL, /* usGpioLedPpp */
++ BP_GPIO_4_AL, /* usGpioLedPppFail */
++ BP_GPIO_0_AL, /* usGpioLedBlPowerOn */
++ BP_NOT_DEFINED, /* usGpioLedBlAlarm */
++ BP_GPIO_3_AL, /* usGpioLedBlResetCfg */
++ BP_GPIO_1_AL, /* usGpioLedBlStop */
++ BP_NOT_DEFINED, /* usExtIntrWireless */
++ BP_HW_DEFINED, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_WLAN_ANT_MAIN, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++
++static BOARD_PARAMETERS g_bcm96348gw_11 =
++{
++ "96348GW-11", /* szBoardId */
++ {{BP_ENET_NO_PHY}, /* ucPhyType */
++ {BP_ENET_EXTERNAL_SWITCH, /* ucPhyType */
++ 0x00, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x04, /* numSwitchPorts */
++ BP_ENET_CONFIG_SPI_SSB_1, /* usConfigType */
++ BP_ENET_REVERSE_MII}}, /* usReverseMii */
++ {{BP_VOIP_NO_DSP}, /* ucDspType */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_16MB_2_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_NOT_DEFINED, /* usGpioRj11InnerPair */
++ BP_NOT_DEFINED, /* usGpioRj11OuterPair */
++ BP_GPIO_33_AL, /* usGpioPressAndHoldReset */
++ BP_NOT_DEFINED, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_NOT_DEFINED, /* usGpioLedAdsl */
++ BP_GPIO_2_AL, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_NOT_DEFINED, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_GPIO_3_AL, /* usGpioLedWanData */
++ BP_GPIO_3_AL, /* usGpioLedPpp */
++ BP_GPIO_4_AL, /* usGpioLedPppFail */
++ BP_GPIO_0_AL, /* usGpioLedBlPowerOn */
++ BP_NOT_DEFINED, /* usGpioLedBlAlarm */
++ BP_GPIO_3_AL, /* usGpioLedBlResetCfg */
++ BP_GPIO_1_AL, /* usGpioLedBlStop */
++ BP_NOT_DEFINED, /* usExtIntrWireless */
++ BP_HW_DEFINED, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_NOT_DEFINED, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++
++static BOARD_PARAMETERS g_bcm96348sv =
++{
++ "96348SV", /* szBoardId */
++ {{BP_ENET_INTERNAL_PHY, /* ucPhyType */
++ 0x01, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_NOT_DEFINED}, /* usReverseMii */
++ {BP_ENET_EXTERNAL_PHY, /* ucPhyType */
++ 0x1f, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_NOT_DEFINED}}, /* usReverseMii */
++ {{BP_VOIP_NO_DSP}, /* ucDspType */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_32MB_2_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_NOT_DEFINED, /* usGpioRj11InnerPair */
++ BP_NOT_DEFINED, /* usGpioRj11OuterPair */
++ BP_NOT_DEFINED, /* usGpioPressAndHoldReset */
++ BP_NOT_DEFINED, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_NOT_DEFINED, /* usGpioLedAdsl */
++ BP_NOT_DEFINED, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_NOT_DEFINED, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_NOT_DEFINED, /* usGpioLedWanData */
++ BP_NOT_DEFINED, /* usGpioLedPpp */
++ BP_NOT_DEFINED, /* usGpioLedPppFail */
++ BP_NOT_DEFINED, /* usGpioLedBlPowerOn */
++ BP_NOT_DEFINED, /* usGpioLedBlAlarm */
++ BP_NOT_DEFINED, /* usGpioLedBlResetCfg */
++ BP_NOT_DEFINED, /* usGpioLedBlStop */
++ BP_NOT_DEFINED, /* usExtIntrWireless */
++ BP_HW_DEFINED, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_NOT_DEFINED, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++
++
++static BOARD_PARAMETERS g_bcm96348gw_dualDsp =
++{
++ "96348GW-DualDSP", /* szBoardId */
++ {{BP_ENET_INTERNAL_PHY, /* ucPhyType */
++ 0x01, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_NOT_DEFINED}, /* usReverseMii */
++ {BP_ENET_EXTERNAL_SWITCH, /* ucPhyType */
++ 0x00, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x03, /* numSwitchPorts */
++ BP_ENET_CONFIG_SPI_SSB_1, /* usConfigType */
++ BP_ENET_REVERSE_MII}}, /* usReverseMii */
++ {{BP_VOIP_DSP, /* ucDspType */
++ 0x00, /* ucDspAddress */
++ BP_EXT_INTR_2, /* usExtIntrVoip */
++ BP_UNEQUIPPED, /* usGpioVoipReset */
++ BP_GPIO_34_AH, /* usGpioVoipIntr */
++ BP_NOT_DEFINED, /* usGpioLedVoip */
++ BP_CS_2}, /* usCsVoip */
++ {BP_VOIP_DSP, /* ucDspType */
++ 0x01, /* ucDspAddress */
++ BP_EXT_INTR_3, /* usExtIntrVoip */
++ BP_UNEQUIPPED , /* usGpioVoipReset */
++ BP_GPIO_35_AH, /* usGpioVoipIntr */
++ BP_NOT_DEFINED, /* usGpioLedVoip */
++ BP_CS_3}}, /* usCsVoip */
++ BP_MEMORY_16MB_2_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_NOT_DEFINED, /* usGpioRj11InnerPair */
++ BP_NOT_DEFINED, /* usGpioRj11OuterPair */
++ BP_GPIO_33_AL, /* usGpioPressAndHoldReset */
++ BP_NOT_DEFINED, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_NOT_DEFINED, /* usGpioLedAdsl */
++ BP_GPIO_2_AL, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_NOT_DEFINED, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_GPIO_3_AL, /* usGpioLedWanData */
++ BP_GPIO_3_AL, /* usGpioLedPpp */
++ BP_GPIO_4_AL, /* usGpioLedPppFail */
++ BP_GPIO_0_AL, /* usGpioLedBlPowerOn */
++ BP_NOT_DEFINED, /* usGpioLedBlAlarm */
++ BP_GPIO_3_AL, /* usGpioLedBlResetCfg */
++ BP_GPIO_1_AL, /* usGpioLedBlStop */
++ BP_NOT_DEFINED, /* usExtIntrWireless */
++ BP_HW_DEFINED, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_WLAN_ANT_MAIN, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++
++
++static BOARD_PARAMETERS g_bcmCustom_01 =
++{
++ "BCMCUST_01", /* szBoardId */
++ {{BP_ENET_INTERNAL_PHY, /* ucPhyType */
++ 0x01, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_MDIO, /* usConfigType */
++ BP_NOT_DEFINED}, /* usReverseMii */
++ {BP_ENET_NO_PHY, /* ucPhyType */
++ 0x00, /* ucPhyAddress */
++ BP_NOT_DEFINED, /* usGpioPhySpiSck */
++ BP_NOT_DEFINED, /* usGpioPhySpiSs */
++ BP_NOT_DEFINED, /* usGpioPhySpiMosi */
++ BP_NOT_DEFINED, /* usGpioPhySpiMiso */
++ BP_NOT_DEFINED, /* usGpioPhyReset */
++ 0x01, /* numSwitchPorts */
++ BP_ENET_CONFIG_SPI_SSB_1, /* usConfigType */
++ BP_ENET_REVERSE_MII}}, /* usReverseMii */
++ {{BP_VOIP_DSP, /* ucDspType */
++ 0x00, /* ucDspAddress */
++ BP_EXT_INTR_2, /* usExtIntrVoip */
++ BP_GPIO_36_AH, /* usGpioVoipReset */
++ BP_GPIO_34_AL, /* usGpioVoipIntr */
++ BP_NOT_DEFINED, /* usGpioLedVoip */
++ BP_CS_2}, /* usCsVoip */
++ {BP_VOIP_NO_DSP}}, /* ucDspType */
++ BP_MEMORY_16MB_2_CHIP, /* usSdramSize */
++ BP_PSI_DEFAULT_SIZE, /* usPsiSize */
++ BP_NOT_DEFINED, /* usGpioRj11InnerPair */
++ BP_NOT_DEFINED, /* usGpioRj11OuterPair */
++ BP_GPIO_33_AL, /* usGpioPressAndHoldReset */
++ BP_NOT_DEFINED, /* usGpioPcmciaReset */
++ BP_NOT_DEFINED, /* usGpioUartRts */
++ BP_NOT_DEFINED, /* usGpioUartCts */
++ BP_NOT_DEFINED, /* usGpioLedAdsl */
++ BP_GPIO_2_AL, /* usGpioLedAdslFail */
++ BP_NOT_DEFINED, /* usGpioLedWireless */
++ BP_NOT_DEFINED, /* usGpioLedUsb */
++ BP_NOT_DEFINED, /* usGpioLedHpna */
++ BP_GPIO_3_AL, /* usGpioLedWanData */
++ BP_GPIO_3_AL, /* usGpioLedPpp */
++ BP_GPIO_4_AL, /* usGpioLedPppFail */
++ BP_GPIO_0_AL, /* usGpioLedBlPowerOn */
++ BP_NOT_DEFINED, /* usGpioLedBlAlarm */
++ BP_GPIO_3_AL, /* usGpioLedBlResetCfg */
++ BP_GPIO_1_AL, /* usGpioLedBlStop */
++ BP_NOT_DEFINED, /* usExtIntrWireless */
++ BP_NOT_DEFINED, /* usExtIntrAdslDyingGasp */
++ BP_NOT_DEFINED, /* usExtIntrHpna */
++ BP_NOT_DEFINED, /* usCsHpna */
++ BP_NOT_DEFINED, /* usAntInUseWireless */
++ BP_NOT_DEFINED, /* usGpioSesBtnWireless */
++ BP_NOT_DEFINED, /* usExtIntrSesBtnWireless */
++ BP_NOT_DEFINED /* usGpioLedSesWireless */
++};
++
++static PBOARD_PARAMETERS g_BoardParms[] =
++ {&g_bcm96348r, &g_bcm96348lv, &g_bcm96348gw, &g_bcm96348gw_10,
++ &g_bcm96348gw_11, &g_bcm96348sv, &g_bcm96348gw_dualDsp,
++ &g_bcmCustom_01, 0};
++#endif
++
++static PBOARD_PARAMETERS g_pCurrentBp = 0;
++
++/**************************************************************************
++ * Name : bpstrcmp
++ *
++ * Description: String compare for this file so it does not depend on an OS.
++ * (Linux kernel and CFE share this source file.)
++ *
++ * Parameters : [IN] dest - destination string
++ * [IN] src - source string
++ *
++ * Returns : -1 - dest < src, 1 - dest > src, 0 dest == src
++ ***************************************************************************/
++static int bpstrcmp(const char *dest,const char *src);
++static int bpstrcmp(const char *dest,const char *src)
++{
++ while (*src && *dest)
++ {
++ if (*dest < *src) return -1;
++ if (*dest > *src) return 1;
++ dest++;
++ src++;
++ }
++
++ if (*dest && !*src) return 1;
++ if (!*dest && *src) return -1;
++ return 0;
++} /* bpstrcmp */
++
++/**************************************************************************
++ * Name : BpGetVoipDspConfig
++ *
++ * Description: Gets the DSP configuration from the board parameter
++ * structure for a given DSP index.
++ *
++ * Parameters : [IN] dspNum - DSP index (number)
++ *
++ * Returns : Pointer to DSP configuration block if found/valid, NULL
++ * otherwise.
++ ***************************************************************************/
++VOIP_DSP_INFO *BpGetVoipDspConfig( unsigned char dspNum );
++VOIP_DSP_INFO *BpGetVoipDspConfig( unsigned char dspNum )
++{
++ VOIP_DSP_INFO *pDspConfig = 0;
++ int i;
++
++ if( g_pCurrentBp )
++ {
++ for( i = 0 ; i < BP_MAX_VOIP_DSP ; i++ )
++ {
++ if( g_pCurrentBp->VoIPDspInfo[i].ucDspType != BP_VOIP_NO_DSP &&
++ g_pCurrentBp->VoIPDspInfo[i].ucDspAddress == dspNum )
++ {
++ pDspConfig = &g_pCurrentBp->VoIPDspInfo[i];
++ break;
++ }
++ }
++ }
++
++ return pDspConfig;
++}
++
++
++/**************************************************************************
++ * Name : BpSetBoardId
++ *
++ * Description: This function find the BOARD_PARAMETERS structure for the
++ * specified board id string and assigns it to a global, static
++ * variable.
++ *
++ * Parameters : [IN] pszBoardId - Board id string that is saved into NVRAM.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_FOUND - Error, board id input string does not
++ * have a board parameters configuration record.
++ ***************************************************************************/
++int BpSetBoardId( char *pszBoardId )
++{
++ int nRet = BP_BOARD_ID_NOT_FOUND;
++ PBOARD_PARAMETERS *ppBp;
++
++ for( ppBp = g_BoardParms; *ppBp; ppBp++ )
++ {
++ if( !bpstrcmp((*ppBp)->szBoardId, pszBoardId) )
++ {
++ g_pCurrentBp = *ppBp;
++ nRet = BP_SUCCESS;
++ break;
++ }
++ }
++
++ return( nRet );
++} /* BpSetBoardId */
++
++/**************************************************************************
++ * Name : BpGetBoardIds
++ *
++ * Description: This function returns all of the supported board id strings.
++ *
++ * Parameters : [OUT] pszBoardIds - Address of a buffer that the board id
++ * strings are returned in. Each id starts at BP_BOARD_ID_LEN
++ * boundary.
++ * [IN] nBoardIdsSize - Number of BP_BOARD_ID_LEN elements that
++ * were allocated in pszBoardIds.
++ *
++ * Returns : Number of board id strings returned.
++ ***************************************************************************/
++int BpGetBoardIds( char *pszBoardIds, int nBoardIdsSize )
++{
++ PBOARD_PARAMETERS *ppBp;
++ int i;
++ char *src;
++ char *dest;
++
++ for( i = 0, ppBp = g_BoardParms; *ppBp && nBoardIdsSize;
++ i++, ppBp++, nBoardIdsSize--, pszBoardIds += BP_BOARD_ID_LEN )
++ {
++ dest = pszBoardIds;
++ src = (*ppBp)->szBoardId;
++ while( *src )
++ *dest++ = *src++;
++ *dest = '\0';
++ }
++
++ return( i );
++} /* BpGetBoardIds */
++
++/**************************************************************************
++ * Name : BpGetEthernetMacInfo
++ *
++ * Description: This function returns all of the supported board id strings.
++ *
++ * Parameters : [OUT] pEnetInfos - Address of an array of ETHERNET_MAC_INFO
++ * buffers.
++ * [IN] nNumEnetInfos - Number of ETHERNET_MAC_INFO elements that
++ * are pointed to by pEnetInfos.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ ***************************************************************************/
++int BpGetEthernetMacInfo( PETHERNET_MAC_INFO pEnetInfos, int nNumEnetInfos )
++{
++ int i, nRet;
++
++ if( g_pCurrentBp )
++ {
++ for( i = 0; i < nNumEnetInfos; i++, pEnetInfos++ )
++ {
++ if( i < BP_MAX_ENET_MACS )
++ {
++ unsigned char *src = (unsigned char *)
++ &g_pCurrentBp->EnetMacInfos[i];
++ unsigned char *dest = (unsigned char *) pEnetInfos;
++ int len = sizeof(ETHERNET_MAC_INFO);
++ while( len-- )
++ *dest++ = *src++;
++ }
++ else
++ pEnetInfos->ucPhyType = BP_ENET_NO_PHY;
++ }
++
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ for( i = 0; i < nNumEnetInfos; i++, pEnetInfos++ )
++ pEnetInfos->ucPhyType = BP_ENET_NO_PHY;
++
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetEthernetMacInfo */
++
++/**************************************************************************
++ * Name : BpGetSdramSize
++ *
++ * Description: This function returns a constant that describees the board's
++ * SDRAM type and size.
++ *
++ * Parameters : [OUT] pulSdramSize - Address of short word that the SDRAM size
++ * is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ ***************************************************************************/
++int BpGetSdramSize( unsigned long *pulSdramSize )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pulSdramSize = g_pCurrentBp->usSdramSize;
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ *pulSdramSize = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetSdramSize */
++
++/**************************************************************************
++ * Name : BpGetPsiSize
++ *
++ * Description: This function returns the persistent storage size in K bytes.
++ *
++ * Parameters : [OUT] pulPsiSize - Address of short word that the persistent
++ * storage size is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ ***************************************************************************/
++int BpGetPsiSize( unsigned long *pulPsiSize )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pulPsiSize = g_pCurrentBp->usPsiSize;
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ *pulPsiSize = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetPsiSize */
++
++/**************************************************************************
++ * Name : BpGetRj11InnerOuterPairGpios
++ *
++ * Description: This function returns the GPIO pin assignments for changing
++ * between the RJ11 inner pair and RJ11 outer pair.
++ *
++ * Parameters : [OUT] pusInner - Address of short word that the RJ11 inner pair
++ * GPIO pin is returned in.
++ * [OUT] pusOuter - Address of short word that the RJ11 outer pair
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, values are returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetRj11InnerOuterPairGpios( unsigned short *pusInner,
++ unsigned short *pusOuter )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusInner = g_pCurrentBp->usGpioRj11InnerPair;
++ *pusOuter = g_pCurrentBp->usGpioRj11OuterPair;
++
++ if( g_pCurrentBp->usGpioRj11InnerPair != BP_NOT_DEFINED &&
++ g_pCurrentBp->usGpioRj11OuterPair != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusInner = *pusOuter = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetRj11InnerOuterPairGpios */
++
++/**************************************************************************
++ * Name : BpGetPressAndHoldResetGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the press
++ * and hold reset button.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the press and hold
++ * reset button GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetPressAndHoldResetGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioPressAndHoldReset;
++
++ if( g_pCurrentBp->usGpioPressAndHoldReset != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetPressAndHoldResetGpio */
++
++/**************************************************************************
++ * Name : BpGetVoipResetGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the VOIP
++ * Reset operation.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the VOIP reset
++ * GPIO pin is returned in.
++ * [IN] dspNum - Address of the DSP to query.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetVoipResetGpio( unsigned char dspNum, unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ VOIP_DSP_INFO *pDspInfo = BpGetVoipDspConfig( dspNum );
++
++ if( pDspInfo )
++ {
++ *pusValue = pDspInfo->usGpioVoipReset;
++
++ if( *pusValue != BP_NOT_DEFINED ||
++ *pusValue == BP_UNEQUIPPED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_FOUND;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetVoipResetGpio */
++
++/**************************************************************************
++ * Name : BpGetVoipIntrGpio
++ *
++ * Description: This function returns the GPIO pin assignment for VoIP interrupt.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the VOIP interrupt
++ * GPIO pin is returned in.
++ * [IN] dspNum - Address of the DSP to query.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetVoipIntrGpio( unsigned char dspNum, unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ VOIP_DSP_INFO *pDspInfo = BpGetVoipDspConfig( dspNum );
++
++ if( pDspInfo )
++ {
++ *pusValue = pDspInfo->usGpioVoipIntr;
++
++ if( *pusValue != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_FOUND;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetVoipIntrGpio */
++
++/**************************************************************************
++ * Name : BpGetPcmciaResetGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the PCMCIA
++ * Reset operation.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the PCMCIA reset
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetPcmciaResetGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioPcmciaReset;
++
++ if( g_pCurrentBp->usGpioPcmciaReset != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetPcmciaResetGpio */
++
++/**************************************************************************
++ * Name : BpGetUartRtsCtsGpios
++ *
++ * Description: This function returns the GPIO pin assignments for RTS and CTS
++ * UART signals.
++ *
++ * Parameters : [OUT] pusRts - Address of short word that the UART RTS GPIO
++ * pin is returned in.
++ * [OUT] pusCts - Address of short word that the UART CTS GPIO
++ * pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, values are returned.
++ * BP_BOARD_ID_NOT_SET - Error, board id input string does not
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetRtsCtsUartGpios( unsigned short *pusRts, unsigned short *pusCts )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusRts = g_pCurrentBp->usGpioUartRts;
++ *pusCts = g_pCurrentBp->usGpioUartCts;
++
++ if( g_pCurrentBp->usGpioUartRts != BP_NOT_DEFINED &&
++ g_pCurrentBp->usGpioUartCts != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusRts = *pusCts = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetUartRtsCtsGpios */
++
++/**************************************************************************
++ * Name : BpGetAdslLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the ADSL
++ * LED.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the ADSL LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetAdslLedGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioLedAdsl;
++
++ if( g_pCurrentBp->usGpioLedAdsl != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetAdslLedGpio */
++
++/**************************************************************************
++ * Name : BpGetAdslFailLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the ADSL
++ * LED that is used when there is a DSL connection failure.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the ADSL LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetAdslFailLedGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioLedAdslFail;
++
++ if( g_pCurrentBp->usGpioLedAdslFail != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetAdslFailLedGpio */
++
++/**************************************************************************
++ * Name : BpGetWirelessLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the Wireless
++ * LED.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the Wireless LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetWirelessLedGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioLedWireless;
++
++ if( g_pCurrentBp->usGpioLedWireless != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetWirelessLedGpio */
++
++/**************************************************************************
++ * Name : BpGetWirelessAntInUse
++ *
++ * Description: This function returns the antennas in use for wireless
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the Wireless Antenna
++ * is in use.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetWirelessAntInUse( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usAntInUseWireless;
++
++ if( g_pCurrentBp->usAntInUseWireless != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetWirelessAntInUse */
++
++/**************************************************************************
++ * Name : BpGetWirelessSesBtnGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the Wireless
++ * Ses Button.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the Wireless LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetWirelessSesBtnGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioSesBtnWireless;
++
++ if( g_pCurrentBp->usGpioSesBtnWireless != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetWirelessSesBtnGpio */
++
++/**************************************************************************
++ * Name : BpGetWirelessSesExtIntr
++ *
++ * Description: This function returns the external interrupt number for the
++ * Wireless Ses Button.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the Wireless Ses
++ * external interrup is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetWirelessSesExtIntr( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usExtIntrSesBtnWireless;
++
++ if( g_pCurrentBp->usExtIntrSesBtnWireless != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++
++} /* BpGetWirelessSesExtIntr */
++
++/**************************************************************************
++ * Name : BpGetWirelessSesLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the Wireless
++ * Ses Led.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the Wireless Ses
++ * Led GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetWirelessSesLedGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioLedSesWireless;
++
++ if( g_pCurrentBp->usGpioLedSesWireless != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++
++} /* BpGetWirelessSesLedGpio */
++
++/**************************************************************************
++ * Name : BpGetUsbLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the USB
++ * LED.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the USB LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetUsbLedGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioLedUsb;
++
++ if( g_pCurrentBp->usGpioLedUsb != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetUsbLedGpio */
++
++/**************************************************************************
++ * Name : BpGetHpnaLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the HPNA
++ * LED.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the HPNA LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetHpnaLedGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioLedHpna;
++
++ if( g_pCurrentBp->usGpioLedHpna != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetHpnaLedGpio */
++
++/**************************************************************************
++ * Name : BpGetWanDataLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the WAN Data
++ * LED.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the WAN Data LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetWanDataLedGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioLedWanData;
++
++ if( g_pCurrentBp->usGpioLedWanData != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetWanDataLedGpio */
++
++/**************************************************************************
++ * Name : BpGetPppLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the PPP
++ * LED.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the PPP LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetPppLedGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioLedPpp;
++
++ if( g_pCurrentBp->usGpioLedPpp != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetPppLedGpio */
++
++/**************************************************************************
++ * Name : BpGetPppFailLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the PPP
++ * LED that is used when there is a PPP connection failure.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the PPP LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetPppFailLedGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioLedPppFail;
++
++ if( g_pCurrentBp->usGpioLedPppFail != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetPppFailLedGpio */
++
++/**************************************************************************
++ * Name : BpGetBootloaderPowerOnLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the power
++ * on LED that is set by the bootloader.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the alarm LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetBootloaderPowerOnLedGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioLedBlPowerOn;
++
++ if( g_pCurrentBp->usGpioLedBlPowerOn != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetBootloaderPowerOn */
++
++/**************************************************************************
++ * Name : BpGetBootloaderAlarmLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the alarm
++ * LED that is set by the bootloader.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the alarm LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetBootloaderAlarmLedGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioLedBlAlarm;
++
++ if( g_pCurrentBp->usGpioLedBlAlarm != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetBootloaderAlarmLedGpio */
++
++/**************************************************************************
++ * Name : BpGetBootloaderResetCfgLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the reset
++ * configuration LED that is set by the bootloader.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the reset
++ * configuration LED GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetBootloaderResetCfgLedGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioLedBlResetCfg;
++
++ if( g_pCurrentBp->usGpioLedBlResetCfg != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetBootloaderResetCfgLedGpio */
++
++/**************************************************************************
++ * Name : BpGetBootloaderStopLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the break
++ * into bootloader LED that is set by the bootloader.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the break into
++ * bootloader LED GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetBootloaderStopLedGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pusValue = g_pCurrentBp->usGpioLedBlStop;
++
++ if( g_pCurrentBp->usGpioLedBlStop != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetBootloaderStopLedGpio */
++
++/**************************************************************************
++ * Name : BpGetVoipLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the VOIP
++ * LED.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the VOIP LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ *
++ * Note : The VoIP structure would allow for having one LED per DSP
++ * however, the board initialization function assumes only one
++ * LED per functionality (ie one LED for VoIP). Therefore in
++ * order to keep this tidy and simple we do not make usage of the
++ * one-LED-per-DSP function. Instead, we assume that the LED for
++ * VoIP is unique and associated with DSP 0 (always present on
++ * any VoIP platform). If changing this to a LED-per-DSP function
++ * then one need to update the board initialization driver in
++ * bcmdrivers\opensource\char\board\bcm963xx\impl1
++ ***************************************************************************/
++int BpGetVoipLedGpio( unsigned short *pusValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ VOIP_DSP_INFO *pDspInfo = BpGetVoipDspConfig( 0 );
++
++ if( pDspInfo )
++ {
++ *pusValue = pDspInfo->usGpioLedVoip;
++
++ if( *pusValue != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_FOUND;
++ }
++ }
++ else
++ {
++ *pusValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetVoipLedGpio */
++
++/**************************************************************************
++ * Name : BpGetWirelessExtIntr
++ *
++ * Description: This function returns the Wireless external interrupt number.
++ *
++ * Parameters : [OUT] pulValue - Address of short word that the wireless
++ * external interrupt number is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetWirelessExtIntr( unsigned long *pulValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pulValue = g_pCurrentBp->usExtIntrWireless;
++
++ if( g_pCurrentBp->usExtIntrWireless != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pulValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetWirelessExtIntr */
++
++/**************************************************************************
++ * Name : BpGetAdslDyingGaspExtIntr
++ *
++ * Description: This function returns the ADSL Dying Gasp external interrupt
++ * number.
++ *
++ * Parameters : [OUT] pulValue - Address of short word that the ADSL Dying Gasp
++ * external interrupt number is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetAdslDyingGaspExtIntr( unsigned long *pulValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pulValue = g_pCurrentBp->usExtIntrAdslDyingGasp;
++
++ if( g_pCurrentBp->usExtIntrAdslDyingGasp != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pulValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetAdslDyingGaspExtIntr */
++
++/**************************************************************************
++ * Name : BpGetVoipExtIntr
++ *
++ * Description: This function returns the VOIP external interrupt number.
++ *
++ * Parameters : [OUT] pulValue - Address of short word that the VOIP
++ * external interrupt number is returned in.
++ * [IN] dspNum - Address of the DSP to query.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetVoipExtIntr( unsigned char dspNum, unsigned long *pulValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ VOIP_DSP_INFO *pDspInfo = BpGetVoipDspConfig( dspNum );
++
++ if( pDspInfo )
++ {
++ *pulValue = pDspInfo->usExtIntrVoip;
++
++ if( *pulValue != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pulValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_FOUND;
++ }
++ }
++ else
++ {
++ *pulValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetVoipExtIntr */
++
++/**************************************************************************
++ * Name : BpGetHpnaExtIntr
++ *
++ * Description: This function returns the HPNA external interrupt number.
++ *
++ * Parameters : [OUT] pulValue - Address of short word that the HPNA
++ * external interrupt number is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetHpnaExtIntr( unsigned long *pulValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pulValue = g_pCurrentBp->usExtIntrHpna;
++
++ if( g_pCurrentBp->usExtIntrHpna != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pulValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetHpnaExtIntr */
++
++/**************************************************************************
++ * Name : BpGetHpnaChipSelect
++ *
++ * Description: This function returns the HPNA chip select number.
++ *
++ * Parameters : [OUT] pulValue - Address of short word that the HPNA
++ * chip select number is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetHpnaChipSelect( unsigned long *pulValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ *pulValue = g_pCurrentBp->usCsHpna;
++
++ if( g_pCurrentBp->usCsHpna != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pulValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetHpnaChipSelect */
++
++/**************************************************************************
++ * Name : BpGetVoipChipSelect
++ *
++ * Description: This function returns the VOIP chip select number.
++ *
++ * Parameters : [OUT] pulValue - Address of short word that the VOIP
++ * chip select number is returned in.
++ * [IN] dspNum - Address of the DSP to query.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetVoipChipSelect( unsigned char dspNum, unsigned long *pulValue )
++{
++ int nRet;
++
++ if( g_pCurrentBp )
++ {
++ VOIP_DSP_INFO *pDspInfo = BpGetVoipDspConfig( dspNum );
++
++ if( pDspInfo )
++ {
++ *pulValue = pDspInfo->usCsVoip;
++
++ if( *pulValue != BP_NOT_DEFINED )
++ {
++ nRet = BP_SUCCESS;
++ }
++ else
++ {
++ nRet = BP_VALUE_NOT_DEFINED;
++ }
++ }
++ else
++ {
++ *pulValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_FOUND;
++ }
++ }
++ else
++ {
++ *pulValue = BP_NOT_DEFINED;
++ nRet = BP_BOARD_ID_NOT_SET;
++ }
++
++ return( nRet );
++} /* BpGetVoipChipSelect */
++
+diff -urN linux.old/arch/mips/bcm963xx/boardparms.h linux.dev/arch/mips/bcm963xx/boardparms.h
+--- linux.old/arch/mips/bcm963xx/boardparms.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/boardparms.h 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,758 @@
++/*
++<:copyright-gpl
++
++ Copyright 2003 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ for more details.
++
++ You should have received a copy of the GNU General Public License along
++ with this program; if not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++
++:>
++*/
++/**************************************************************************
++ * File Name : boardparms.h
++ *
++ * Description: This file contains definitions and function prototypes for
++ * the BCM63xx board parameter access functions.
++ *
++ * Updates : 07/14/2003 Created.
++ ***************************************************************************/
++
++#if !defined(_BOARDPARMS_H)
++#define _BOARDPARMS_H
++
++/* Return codes. */
++#define BP_SUCCESS 0
++#define BP_BOARD_ID_NOT_FOUND 1
++#define BP_VALUE_NOT_DEFINED 2
++#define BP_BOARD_ID_NOT_SET 3
++
++/* Values for BpGetSdramSize. */
++#define BP_MEMORY_8MB_1_CHIP 0
++#define BP_MEMORY_16MB_1_CHIP 1
++#define BP_MEMORY_32MB_1_CHIP 2
++#define BP_MEMORY_64MB_2_CHIP 3
++#define BP_MEMORY_32MB_2_CHIP 4
++#define BP_MEMORY_16MB_2_CHIP 5
++
++/* Values for EthernetMacInfo PhyType. */
++#define BP_ENET_NO_PHY 0
++#define BP_ENET_INTERNAL_PHY 1
++#define BP_ENET_EXTERNAL_PHY 2
++#define BP_ENET_EXTERNAL_SWITCH 3
++
++/* Values for EthernetMacInfo Configuration type. */
++#define BP_ENET_CONFIG_MDIO 0 /* Internal PHY, External PHY, Switch+(no GPIO, no SPI, no MDIO Pseudo phy */
++#define BP_ENET_CONFIG_GPIO 1 /* Bcm96345GW board + Bcm5325M/E */
++#define BP_ENET_CONFIG_MDIO_PSEUDO_PHY 2 /* Bcm96348GW board + Bcm5325E */
++#define BP_ENET_CONFIG_SPI_SSB_0 3 /* Bcm96348GW board + Bcm5325M/E */
++#define BP_ENET_CONFIG_SPI_SSB_1 4 /* Bcm96348GW board + Bcm5325M/E */
++#define BP_ENET_CONFIG_SPI_SSB_2 5 /* Bcm96348GW board + Bcm5325M/E */
++#define BP_ENET_CONFIG_SPI_SSB_3 6 /* Bcm96348GW board + Bcm5325M/E */
++
++/* Values for EthernetMacInfo Reverse MII. */
++#define BP_ENET_NO_REVERSE_MII 0
++#define BP_ENET_REVERSE_MII 1
++
++/* Values for VoIPDSPInfo DSPType. */
++#define BP_VOIP_NO_DSP 0
++#define BP_VOIP_DSP 1
++
++
++/* Values for GPIO pin assignments (AH = Active High, AL = Active Low). */
++#define BP_ACTIVE_MASK 0x8000
++#define BP_ACTIVE_HIGH 0x0000
++#define BP_ACTIVE_LOW 0x8000
++#define BP_GPIO_0_AH (0 | BP_ACTIVE_HIGH)
++#define BP_GPIO_0_AL (0 | BP_ACTIVE_LOW)
++#define BP_GPIO_1_AH (1 | BP_ACTIVE_HIGH)
++#define BP_GPIO_1_AL (1 | BP_ACTIVE_LOW)
++#define BP_GPIO_2_AH (2 | BP_ACTIVE_HIGH)
++#define BP_GPIO_2_AL (2 | BP_ACTIVE_LOW)
++#define BP_GPIO_3_AH (3 | BP_ACTIVE_HIGH)
++#define BP_GPIO_3_AL (3 | BP_ACTIVE_LOW)
++#define BP_GPIO_4_AH (4 | BP_ACTIVE_HIGH)
++#define BP_GPIO_4_AL (4 | BP_ACTIVE_LOW)
++#define BP_GPIO_5_AH (5 | BP_ACTIVE_HIGH)
++#define BP_GPIO_5_AL (5 | BP_ACTIVE_LOW)
++#define BP_GPIO_6_AH (6 | BP_ACTIVE_HIGH)
++#define BP_GPIO_6_AL (6 | BP_ACTIVE_LOW)
++#define BP_GPIO_7_AH (7 | BP_ACTIVE_HIGH)
++#define BP_GPIO_7_AL (7 | BP_ACTIVE_LOW)
++#define BP_GPIO_8_AH (8 | BP_ACTIVE_HIGH)
++#define BP_GPIO_8_AL (8 | BP_ACTIVE_LOW)
++#define BP_GPIO_9_AH (9 | BP_ACTIVE_HIGH)
++#define BP_GPIO_9_AL (9 | BP_ACTIVE_LOW)
++#define BP_GPIO_10_AH (10 | BP_ACTIVE_HIGH)
++#define BP_GPIO_10_AL (10 | BP_ACTIVE_LOW)
++#define BP_GPIO_11_AH (11 | BP_ACTIVE_HIGH)
++#define BP_GPIO_11_AL (11 | BP_ACTIVE_LOW)
++#define BP_GPIO_12_AH (12 | BP_ACTIVE_HIGH)
++#define BP_GPIO_12_AL (12 | BP_ACTIVE_LOW)
++#define BP_GPIO_13_AH (13 | BP_ACTIVE_HIGH)
++#define BP_GPIO_13_AL (13 | BP_ACTIVE_LOW)
++#define BP_GPIO_14_AH (14 | BP_ACTIVE_HIGH)
++#define BP_GPIO_14_AL (14 | BP_ACTIVE_LOW)
++#define BP_GPIO_15_AH (15 | BP_ACTIVE_HIGH)
++#define BP_GPIO_15_AL (15 | BP_ACTIVE_LOW)
++#define BP_GPIO_16_AH (16 | BP_ACTIVE_HIGH)
++#define BP_GPIO_16_AL (16 | BP_ACTIVE_LOW)
++#define BP_GPIO_17_AH (17 | BP_ACTIVE_HIGH)
++#define BP_GPIO_17_AL (17 | BP_ACTIVE_LOW)
++#define BP_GPIO_18_AH (18 | BP_ACTIVE_HIGH)
++#define BP_GPIO_18_AL (18 | BP_ACTIVE_LOW)
++#define BP_GPIO_19_AH (19 | BP_ACTIVE_HIGH)
++#define BP_GPIO_19_AL (19 | BP_ACTIVE_LOW)
++#define BP_GPIO_20_AH (20 | BP_ACTIVE_HIGH)
++#define BP_GPIO_20_AL (20 | BP_ACTIVE_LOW)
++#define BP_GPIO_21_AH (21 | BP_ACTIVE_HIGH)
++#define BP_GPIO_21_AL (21 | BP_ACTIVE_LOW)
++#define BP_GPIO_22_AH (22 | BP_ACTIVE_HIGH)
++#define BP_GPIO_22_AL (22 | BP_ACTIVE_LOW)
++#define BP_GPIO_23_AH (23 | BP_ACTIVE_HIGH)
++#define BP_GPIO_23_AL (23 | BP_ACTIVE_LOW)
++#define BP_GPIO_24_AH (24 | BP_ACTIVE_HIGH)
++#define BP_GPIO_24_AL (24 | BP_ACTIVE_LOW)
++#define BP_GPIO_25_AH (25 | BP_ACTIVE_HIGH)
++#define BP_GPIO_25_AL (25 | BP_ACTIVE_LOW)
++#define BP_GPIO_26_AH (26 | BP_ACTIVE_HIGH)
++#define BP_GPIO_26_AL (26 | BP_ACTIVE_LOW)
++#define BP_GPIO_27_AH (27 | BP_ACTIVE_HIGH)
++#define BP_GPIO_27_AL (27 | BP_ACTIVE_LOW)
++#define BP_GPIO_28_AH (28 | BP_ACTIVE_HIGH)
++#define BP_GPIO_28_AL (28 | BP_ACTIVE_LOW)
++#define BP_GPIO_29_AH (29 | BP_ACTIVE_HIGH)
++#define BP_GPIO_29_AL (29 | BP_ACTIVE_LOW)
++#define BP_GPIO_30_AH (30 | BP_ACTIVE_HIGH)
++#define BP_GPIO_30_AL (30 | BP_ACTIVE_LOW)
++#define BP_GPIO_31_AH (31 | BP_ACTIVE_HIGH)
++#define BP_GPIO_31_AL (31 | BP_ACTIVE_LOW)
++#define BP_GPIO_32_AH (32 | BP_ACTIVE_HIGH)
++#define BP_GPIO_32_AL (32 | BP_ACTIVE_LOW)
++#define BP_GPIO_33_AH (33 | BP_ACTIVE_HIGH)
++#define BP_GPIO_33_AL (33 | BP_ACTIVE_LOW)
++#define BP_GPIO_34_AH (34 | BP_ACTIVE_HIGH)
++#define BP_GPIO_34_AL (34 | BP_ACTIVE_LOW)
++#define BP_GPIO_35_AH (35 | BP_ACTIVE_HIGH)
++#define BP_GPIO_35_AL (35 | BP_ACTIVE_LOW)
++#define BP_GPIO_36_AH (36 | BP_ACTIVE_HIGH)
++#define BP_GPIO_36_AL (36 | BP_ACTIVE_LOW)
++
++/* Values for external interrupt assignments. */
++#define BP_EXT_INTR_0 0
++#define BP_EXT_INTR_1 1
++#define BP_EXT_INTR_2 2
++#define BP_EXT_INTR_3 3
++
++/* Values for chip select assignments. */
++#define BP_CS_0 0
++#define BP_CS_1 1
++#define BP_CS_2 2
++#define BP_CS_3 3
++
++/* Value for GPIO and external interrupt fields that are not used. */
++#define BP_NOT_DEFINED 0xffff
++#define BP_HW_DEFINED 0xfff0
++#define BP_UNEQUIPPED 0xfff1
++
++/* Maximum size of the board id string. */
++#define BP_BOARD_ID_LEN 16
++
++/* Maximum number of Ethernet MACs. */
++#define BP_MAX_ENET_MACS 2
++
++/* Maximum number of VoIP DSPs. */
++#define BP_MAX_VOIP_DSP 2
++
++/* Wireless Antenna Settings. */
++#define BP_WLAN_ANT_MAIN 0
++#define BP_WLAN_ANT_AUX 1
++#define BP_WLAN_ANT_BOTH 3
++
++#if !defined(__ASSEMBLER__)
++
++/* Information about an Ethernet MAC. If ucPhyType is BP_ENET_NO_PHY,
++ * then the other fields are not valid.
++ */
++typedef struct EthernetMacInfo
++{
++ unsigned char ucPhyType; /* BP_ENET_xxx */
++ unsigned char ucPhyAddress; /* 0 to 31 */
++ unsigned short usGpioPhySpiSck; /* GPIO pin or not defined */
++ unsigned short usGpioPhySpiSs; /* GPIO pin or not defined */
++ unsigned short usGpioPhySpiMosi; /* GPIO pin or not defined */
++ unsigned short usGpioPhySpiMiso; /* GPIO pin or not defined */
++ unsigned short usGpioPhyReset; /* GPIO pin or not defined (96348LV) */
++ unsigned short numSwitchPorts; /* Number of PHY ports */
++ unsigned short usConfigType; /* Configuration type */
++ unsigned short usReverseMii; /* Reverse MII */
++} ETHERNET_MAC_INFO, *PETHERNET_MAC_INFO;
++
++
++/* Information about VoIP DSPs. If ucDspType is BP_VOIP_NO_DSP,
++ * then the other fields are not valid.
++ */
++typedef struct VoIPDspInfo
++{
++ unsigned char ucDspType;
++ unsigned char ucDspAddress;
++ unsigned short usExtIntrVoip;
++ unsigned short usGpioVoipReset;
++ unsigned short usGpioVoipIntr;
++ unsigned short usGpioLedVoip;
++ unsigned short usCsVoip;
++
++} VOIP_DSP_INFO;
++
++
++/**************************************************************************
++ * Name : BpSetBoardId
++ *
++ * Description: This function find the BOARD_PARAMETERS structure for the
++ * specified board id string and assigns it to a global, static
++ * variable.
++ *
++ * Parameters : [IN] pszBoardId - Board id string that is saved into NVRAM.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_FOUND - Error, board id input string does not
++ * have a board parameters configuration record.
++ ***************************************************************************/
++int BpSetBoardId( char *pszBoardId );
++
++/**************************************************************************
++ * Name : BpGetBoardIds
++ *
++ * Description: This function returns all of the supported board id strings.
++ *
++ * Parameters : [OUT] pszBoardIds - Address of a buffer that the board id
++ * strings are returned in. Each id starts at BP_BOARD_ID_LEN
++ * boundary.
++ * [IN] nBoardIdsSize - Number of BP_BOARD_ID_LEN elements that
++ * were allocated in pszBoardIds.
++ *
++ * Returns : Number of board id strings returned.
++ ***************************************************************************/
++int BpGetBoardIds( char *pszBoardIds, int nBoardIdsSize );
++
++/**************************************************************************
++ * Name : BpGetEthernetMacInfo
++ *
++ * Description: This function returns all of the supported board id strings.
++ *
++ * Parameters : [OUT] pEnetInfos - Address of an array of ETHERNET_MAC_INFO
++ * buffers.
++ * [IN] nNumEnetInfos - Number of ETHERNET_MAC_INFO elements that
++ * are pointed to by pEnetInfos.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ ***************************************************************************/
++int BpGetEthernetMacInfo( PETHERNET_MAC_INFO pEnetInfos, int nNumEnetInfos );
++
++/**************************************************************************
++ * Name : BpGetSdramSize
++ *
++ * Description: This function returns a constant that describees the board's
++ * SDRAM type and size.
++ *
++ * Parameters : [OUT] pulSdramSize - Address of short word that the SDRAM size
++ * is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ ***************************************************************************/
++int BpGetSdramSize( unsigned long *pulSdramSize );
++
++/**************************************************************************
++ * Name : BpGetPsiSize
++ *
++ * Description: This function returns the persistent storage size in K bytes.
++ *
++ * Parameters : [OUT] pulPsiSize - Address of short word that the persistent
++ * storage size is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ ***************************************************************************/
++int BpGetPsiSize( unsigned long *pulPsiSize );
++
++/**************************************************************************
++ * Name : BpGetRj11InnerOuterPairGpios
++ *
++ * Description: This function returns the GPIO pin assignments for changing
++ * between the RJ11 inner pair and RJ11 outer pair.
++ *
++ * Parameters : [OUT] pusInner - Address of short word that the RJ11 inner pair
++ * GPIO pin is returned in.
++ * [OUT] pusOuter - Address of short word that the RJ11 outer pair
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, values are returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetRj11InnerOuterPairGpios( unsigned short *pusInner,
++ unsigned short *pusOuter );
++
++/**************************************************************************
++ * Name : BpGetPressAndHoldResetGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the press
++ * and hold reset button.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the press and hold
++ * reset button GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetPressAndHoldResetGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetVoipResetGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the VOIP
++ * Reset operation.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the VOIP reset
++ * GPIO pin is returned in.
++ * [IN] dspNum - Address of the DSP to query.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetVoipResetGpio( unsigned char dspNum, unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetVoipIntrGpio
++ *
++ * Description: This function returns the GPIO pin assignment for VoIP interrupt.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the VOIP interrupt
++ * GPIO pin is returned in.
++ * [IN] dspNum - Address of the DSP to query.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetVoipIntrGpio( unsigned char dspNum, unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetPcmciaResetGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the PCMCIA
++ * Reset operation.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the PCMCIA reset
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetPcmciaResetGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetUartRtsCtsGpios
++ *
++ * Description: This function returns the GPIO pin assignments for RTS and CTS
++ * UART signals.
++ *
++ * Parameters : [OUT] pusRts - Address of short word that the UART RTS GPIO
++ * pin is returned in.
++ * [OUT] pusCts - Address of short word that the UART CTS GPIO
++ * pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, values are returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetRtsCtsUartGpios( unsigned short *pusRts, unsigned short *pusCts );
++
++/**************************************************************************
++ * Name : BpGetAdslLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the ADSL
++ * LED.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the ADSL LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetAdslLedGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetAdslFailLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the ADSL
++ * LED that is used when there is a DSL connection failure.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the ADSL LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetAdslFailLedGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetWirelessLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the Wireless
++ * LED.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the Wireless LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetWirelessLedGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetWirelessAntInUse
++ *
++ * Description: This function returns the antennas in use for wireless
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the Wireless Antenna
++ * is in use.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetWirelessAntInUse( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetWirelessSesBtnGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the Wireless
++ * Ses Button.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the Wireless Ses
++ * Button GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetWirelessSesBtnGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetWirelessSesExtIntr
++ *
++ * Description: This function returns the external interrupt number for the
++ * Wireless Ses Button.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the Wireless Ses
++ * external interrup is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetWirelessSesExtIntr( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetWirelessSesLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the Wireless
++ * Ses Led.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the Wireless Ses
++ * Led GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetWirelessSesLedGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetUsbLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the USB
++ * LED.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the USB LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetUsbLedGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetHpnaLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the HPNA
++ * LED.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the HPNA LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetHpnaLedGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetWanDataLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the WAN Data
++ * LED.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the WAN Data LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetWanDataLedGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetPppLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the PPP
++ * LED.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the PPP LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetPppLedGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetPppFailLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the PPP
++ * LED that is used when there is a PPP connection failure.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the PPP LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetPppFailLedGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetVoipLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the VOIP
++ * LED.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the VOIP LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetVoipLedGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetBootloaderPowerOnLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the power
++ * on LED that is set by the bootloader.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the alarm LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetBootloaderPowerOnLedGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetBootloaderAlarmLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the alarm
++ * LED that is set by the bootloader.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the alarm LED
++ * GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetBootloaderAlarmLedGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetBootloaderResetCfgLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the reset
++ * configuration LED that is set by the bootloader.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the reset
++ * configuration LED GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetBootloaderResetCfgLedGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetBootloaderStopLedGpio
++ *
++ * Description: This function returns the GPIO pin assignment for the break
++ * into bootloader LED that is set by the bootloader.
++ *
++ * Parameters : [OUT] pusValue - Address of short word that the break into
++ * bootloader LED GPIO pin is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetBootloaderStopLedGpio( unsigned short *pusValue );
++
++/**************************************************************************
++ * Name : BpGetWirelessExtIntr
++ *
++ * Description: This function returns the Wireless external interrupt number.
++ *
++ * Parameters : [OUT] pulValue - Address of short word that the wireless
++ * external interrupt number is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetWirelessExtIntr( unsigned long *pulValue );
++
++/**************************************************************************
++ * Name : BpGetAdslDyingGaspExtIntr
++ *
++ * Description: This function returns the ADSL Dying Gasp external interrupt
++ * number.
++ *
++ * Parameters : [OUT] pulValue - Address of short word that the ADSL Dying Gasp
++ * external interrupt number is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetAdslDyingGaspExtIntr( unsigned long *pulValue );
++
++/**************************************************************************
++ * Name : BpGetVoipExtIntr
++ *
++ * Description: This function returns the VOIP external interrupt number.
++ *
++ * Parameters : [OUT] pulValue - Address of short word that the VOIP
++ * external interrupt number is returned in.
++ * [IN] dspNum - Address of the DSP to query.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetVoipExtIntr( unsigned char dspNum, unsigned long *pulValue );
++
++/**************************************************************************
++ * Name : BpGetHpnaExtIntr
++ *
++ * Description: This function returns the HPNA external interrupt number.
++ *
++ * Parameters : [OUT] pulValue - Address of short word that the HPNA
++ * external interrupt number is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetHpnaExtIntr( unsigned long *pulValue );
++
++/**************************************************************************
++ * Name : BpGetHpnaChipSelect
++ *
++ * Description: This function returns the HPNA chip select number.
++ *
++ * Parameters : [OUT] pulValue - Address of short word that the HPNA
++ * chip select number is returned in.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetHpnaChipSelect( unsigned long *pulValue );
++
++/**************************************************************************
++ * Name : BpGetVoipChipSelect
++ *
++ * Description: This function returns the VOIP chip select number.
++ *
++ * Parameters : [OUT] pulValue - Address of short word that the VOIP
++ * chip select number is returned in.
++ * [IN] dspNum - Address of the DSP to query.
++ *
++ * Returns : BP_SUCCESS - Success, value is returned.
++ * BP_BOARD_ID_NOT_SET - Error, BpSetBoardId has not been called.
++ * BP_VALUE_NOT_DEFINED - At least one return value is not defined
++ * for the board.
++ ***************************************************************************/
++int BpGetVoipChipSelect( unsigned char dspNum, unsigned long *pulValue );
++
++#endif /* __ASSEMBLER__ */
++
++#endif /* _BOARDPARMS_H */
++
+diff -urN linux.old/arch/mips/bcm963xx/include/6338_intr.h linux.dev/arch/mips/bcm963xx/include/6338_intr.h
+--- linux.old/arch/mips/bcm963xx/include/6338_intr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/include/6338_intr.h 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,64 @@
++/*
++<:copyright-gpl
++ Copyright 2003 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ for more details.
++
++ You should have received a copy of the GNU General Public License along
++ with this program; if not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++:>
++*/
++
++#ifndef __6338_INTR_H
++#define __6338_INTR_H
++
++/*=====================================================================*/
++/* BCM6338 External Interrupt Level Assignments */
++/*=====================================================================*/
++#define INTERRUPT_ID_EXTERNAL_0 3
++#define INTERRUPT_ID_EXTERNAL_1 4
++#define INTERRUPT_ID_EXTERNAL_2 5
++#define INTERRUPT_ID_EXTERNAL_3 6
++
++/*=====================================================================*/
++/* BCM6338 Timer Interrupt Level Assignments */
++/*=====================================================================*/
++#define MIPS_TIMER_INT 7
++
++/*=====================================================================*/
++/* Peripheral ISR Table Offset */
++/*=====================================================================*/
++#define INTERNAL_ISR_TABLE_OFFSET 8
++
++/*=====================================================================*/
++/* Logical Peripheral Interrupt IDs */
++/*=====================================================================*/
++
++#define INTERRUPT_ID_TIMER (INTERNAL_ISR_TABLE_OFFSET + 0)
++#define INTERRUPT_ID_SPI (INTERNAL_ISR_TABLE_OFFSET + 1)
++#define INTERRUPT_ID_UART (INTERNAL_ISR_TABLE_OFFSET + 2)
++#define INTERRUPT_ID_DG (INTERNAL_ISR_TABLE_OFFSET + 4)
++#define INTERRUPT_ID_ADSL (INTERNAL_ISR_TABLE_OFFSET + 5)
++#define INTERRUPT_ID_ATM (INTERNAL_ISR_TABLE_OFFSET + 6)
++#define INTERRUPT_ID_USBS (INTERNAL_ISR_TABLE_OFFSET + 7)
++#define INTERRUPT_ID_EMAC1 (INTERNAL_ISR_TABLE_OFFSET + 8)
++#define INTERRUPT_ID_EPHY (INTERNAL_ISR_TABLE_OFFSET + 9)
++#define INTERRUPT_ID_SDRAM (INTERNAL_ISR_TABLE_OFFSET + 10)
++#define INTERRUPT_ID_USB_CNTL_RX_DMA (INTERNAL_ISR_TABLE_OFFSET + 11)
++#define INTERRUPT_ID_USB_CNTL_TX_DMA (INTERNAL_ISR_TABLE_OFFSET + 12)
++#define INTERRUPT_ID_USB_BULK_RX_DMA (INTERNAL_ISR_TABLE_OFFSET + 13)
++#define INTERRUPT_ID_USB_BULK_TX_DMA (INTERNAL_ISR_TABLE_OFFSET + 14)
++#define INTERRUPT_ID_EMAC1_RX_DMA (INTERNAL_ISR_TABLE_OFFSET + 15)
++#define INTERRUPT_ID_EMAC1_TX_DMA (INTERNAL_ISR_TABLE_OFFSET + 16)
++#define INTERRUPT_ID_SDIO (INTERNAL_ISR_TABLE_OFFSET + 17)
++
++#endif /* __BCM6338_H */
++
+diff -urN linux.old/arch/mips/bcm963xx/include/6338_map_part.h linux.dev/arch/mips/bcm963xx/include/6338_map_part.h
+--- linux.old/arch/mips/bcm963xx/include/6338_map_part.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/include/6338_map_part.h 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,334 @@
++/*
++<:copyright-gpl
++ Copyright 2004 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ for more details.
++
++ You should have received a copy of the GNU General Public License along
++ with this program; if not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++:>
++*/
++
++#ifndef __BCM6338_MAP_H
++#define __BCM6338_MAP_H
++
++#include "bcmtypes.h"
++
++#define PERF_BASE 0xfffe0000
++#define TIMR_BASE 0xfffe0200
++#define UART_BASE 0xfffe0300
++#define GPIO_BASE 0xfffe0400
++#define SPI_BASE 0xfffe0c00
++
++typedef struct PerfControl {
++ uint32 RevID;
++ uint16 testControl;
++ uint16 blkEnables;
++#define EMAC_CLK_EN 0x0010
++#define USBS_CLK_EN 0x0010
++#define SAR_CLK_EN 0x0020
++
++#define SPI_CLK_EN 0x0200
++
++ uint32 pll_control;
++#define SOFT_RESET 0x00000001
++
++ uint32 IrqMask;
++ uint32 IrqStatus;
++
++ uint32 ExtIrqCfg;
++#define EI_SENSE_SHFT 0
++#define EI_STATUS_SHFT 5
++#define EI_CLEAR_SHFT 10
++#define EI_MASK_SHFT 15
++#define EI_INSENS_SHFT 20
++#define EI_LEVEL_SHFT 25
++
++ uint32 unused[4]; /* (18) */
++ uint32 BlockSoftReset; /* (28) */
++#define BSR_SPI 0x00000001
++#define BSR_EMAC 0x00000004
++#define BSR_USBH 0x00000008
++#define BSR_USBS 0x00000010
++#define BSR_ADSL 0x00000020
++#define BSR_DMAMEM 0x00000040
++#define BSR_SAR 0x00000080
++#define BSR_ACLC 0x00000100
++#define BSR_ADSL_MIPS_PLL 0x00000400
++#define BSR_ALL_BLOCKS \
++ (BSR_SPI | BSR_EMAC | BSR_USBH | BSR_USBS | BSR_ADSL | BSR_DMAMEM | \
++ BSR_SAR | BSR_ACLC | BSR_ADSL_MIPS_PLL)
++} PerfControl;
++
++#define PERF ((volatile PerfControl * const) PERF_BASE)
++
++
++typedef struct Timer {
++ uint16 unused0;
++ byte TimerMask;
++#define TIMER0EN 0x01
++#define TIMER1EN 0x02
++#define TIMER2EN 0x04
++ byte TimerInts;
++#define TIMER0 0x01
++#define TIMER1 0x02
++#define TIMER2 0x04
++#define WATCHDOG 0x08
++ uint32 TimerCtl0;
++ uint32 TimerCtl1;
++ uint32 TimerCtl2;
++#define TIMERENABLE 0x80000000
++#define RSTCNTCLR 0x40000000
++ uint32 TimerCnt0;
++ uint32 TimerCnt1;
++ uint32 TimerCnt2;
++ uint32 WatchDogDefCount;
++
++ /* Write 0xff00 0x00ff to Start timer
++ * Write 0xee00 0x00ee to Stop and re-load default count
++ * Read from this register returns current watch dog count
++ */
++ uint32 WatchDogCtl;
++
++ /* Number of 40-MHz ticks for WD Reset pulse to last */
++ uint32 WDResetCount;
++} Timer;
++
++#define TIMER ((volatile Timer * const) TIMR_BASE)
++typedef struct UartChannel {
++ byte unused0;
++ byte control;
++#define BRGEN 0x80 /* Control register bit defs */
++#define TXEN 0x40
++#define RXEN 0x20
++#define LOOPBK 0x10
++#define TXPARITYEN 0x08
++#define TXPARITYEVEN 0x04
++#define RXPARITYEN 0x02
++#define RXPARITYEVEN 0x01
++
++ byte config;
++#define XMITBREAK 0x40
++#define BITS5SYM 0x00
++#define BITS6SYM 0x10
++#define BITS7SYM 0x20
++#define BITS8SYM 0x30
++#define ONESTOP 0x07
++#define TWOSTOP 0x0f
++ /* 4-LSBS represent STOP bits/char
++ * in 1/8 bit-time intervals. Zero
++ * represents 1/8 stop bit interval.
++ * Fifteen represents 2 stop bits.
++ */
++ byte fifoctl;
++#define RSTTXFIFOS 0x80
++#define RSTRXFIFOS 0x40
++ /* 5-bit TimeoutCnt is in low bits of this register.
++ * This count represents the number of characters
++ * idle times before setting receive Irq when below threshold
++ */
++ uint32 baudword;
++ /* When divide SysClk/2/(1+baudword) we should get 32*bit-rate
++ */
++
++ byte txf_levl; /* Read-only fifo depth */
++ byte rxf_levl; /* Read-only fifo depth */
++ byte fifocfg; /* Upper 4-bits are TxThresh, Lower are
++ * RxThreshold. Irq can be asserted
++ * when rx fifo> thresh, txfifo<thresh
++ */
++ byte prog_out; /* Set value of DTR (Bit0), RTS (Bit1)
++ * if these bits are also enabled to GPIO_o
++ */
++#define DTREN 0x01
++#define RTSEN 0x02
++
++ byte unused1;
++ byte DeltaIPEdgeNoSense; /* Low 4-bits, set corr bit to 1 to
++ * detect irq on rising AND falling
++ * edges for corresponding GPIO_i
++ * if enabled (edge insensitive)
++ */
++ byte DeltaIPConfig_Mask; /* Upper 4 bits: 1 for posedge sense
++ * 0 for negedge sense if
++ * not configured for edge
++ * insensitive (see above)
++ * Lower 4 bits: Mask to enable change
++ * detection IRQ for corresponding
++ * GPIO_i
++ */
++ byte DeltaIP_SyncIP; /* Upper 4 bits show which bits
++ * have changed (may set IRQ).
++ * read automatically clears bit
++ * Lower 4 bits are actual status
++ */
++
++ uint16 intMask; /* Same Bit defs for Mask and status */
++ uint16 intStatus;
++#define DELTAIP 0x0001
++#define TXUNDERR 0x0002
++#define TXOVFERR 0x0004
++#define TXFIFOTHOLD 0x0008
++#define TXREADLATCH 0x0010
++#define TXFIFOEMT 0x0020
++#define RXUNDERR 0x0040
++#define RXOVFERR 0x0080
++#define RXTIMEOUT 0x0100
++#define RXFIFOFULL 0x0200
++#define RXFIFOTHOLD 0x0400
++#define RXFIFONE 0x0800
++#define RXFRAMERR 0x1000
++#define RXPARERR 0x2000
++#define RXBRK 0x4000
++
++ uint16 unused2;
++ uint16 Data; /* Write to TX, Read from RX */
++ /* bits 11:8 are BRK,PAR,FRM errors */
++
++ uint32 unused3;
++ uint32 unused4;
++} Uart;
++
++#define UART ((volatile Uart * const) UART_BASE)
++
++typedef struct GpioControl {
++ uint32 unused0;
++ uint32 GPIODir; /* bits 7:0 */
++ uint32 unused1;
++ uint32 GPIOio; /* bits 7:0 */
++ uint32 LEDCtrl;
++#define LED3_STROBE 0x08000000
++#define LED2_STROBE 0x04000000
++#define LED1_STROBE 0x02000000
++#define LED0_STROBE 0x01000000
++#define LED_TEST 0x00010000
++#define LED3_DISABLE_LINK_ACT 0x00008000
++#define LED2_DISABLE_LINK_ACT 0x00004000
++#define LED1_DISABLE_LINK_ACT 0x00002000
++#define LED0_DISABLE_LINK_ACT 0x00001000
++#define LED_INTERVAL_SET_MASK 0x00000f00
++#define LED_INTERVAL_SET_320MS 0x00000500
++#define LED_INTERVAL_SET_160MS 0x00000400
++#define LED_INTERVAL_SET_80MS 0x00000300
++#define LED_INTERVAL_SET_40MS 0x00000200
++#define LED_INTERVAL_SET_20MS 0x00000100
++#define LED3_ON 0x00000080
++#define LED2_ON 0x00000040
++#define LED1_ON 0x00000020
++#define LED0_ON 0x00000010
++#define LED3_ENABLE 0x00000008
++#define LED2_ENABLE 0x00000004
++#define LED1_ENABLE 0x00000002
++#define LED0_ENABLE 0x00000001
++ uint32 SpiSlaveCfg;
++#define SPI_SLAVE_RESET 0x00010000
++#define SPI_RESTRICT 0x00000400
++#define SPI_DELAY_DISABLE 0x00000200
++#define SPI_PROBE_MUX_SEL_MASK 0x000001e0
++#define SPI_SER_ADDR_CFG_MASK 0x0000000c
++#define SPI_MODE 0x00000001
++ uint32 vRegConfig;
++} GpioControl;
++
++#define GPIO ((volatile GpioControl * const) GPIO_BASE)
++
++/* Number to mask conversion macro used for GPIODir and GPIOio */
++#define GPIO_NUM_MAX_BITS_MASK 0x0f
++#define GPIO_NUM_TO_MASK(X) (1 << ((X) & GPIO_NUM_MAX_BITS_MASK))
++
++/*
++** Spi Controller
++*/
++
++typedef struct SpiControl {
++ uint16 spiCmd; /* (0x0): SPI command */
++#define SPI_CMD_START_IMMEDIATE 3
++
++#define SPI_CMD_COMMAND_SHIFT 0
++#define SPI_CMD_DEVICE_ID_SHIFT 4
++#define SPI_CMD_PREPEND_BYTE_CNT_SHIFT 8
++
++ byte spiIntStatus; /* (0x2): SPI interrupt status */
++ byte spiMaskIntStatus; /* (0x3): SPI masked interrupt status */
++
++ byte spiIntMask; /* (0x4): SPI interrupt mask */
++#define SPI_INTR_CMD_DONE 0x01
++#define SPI_INTR_CLEAR_ALL 0x1f
++
++ byte spiStatus; /* (0x5): SPI status */
++
++ byte spiClkCfg; /* (0x6): SPI clock configuration */
++
++ byte spiFillByte; /* (0x7): SPI fill byte */
++
++ byte unused0;
++ byte spiMsgTail; /* (0x9): msgtail */
++ byte unused1;
++ byte spiRxTail; /* (0xB): rxtail */
++
++ uint32 unused2[13]; /* (0x0c - 0x3c) reserved */
++
++ byte spiMsgCtl; /* (0x40) control byte */
++#define HALF_DUPLEX_W 1
++#define HALF_DUPLEX_R 2
++#define SPI_MSG_TYPE_SHIFT 6
++#define SPI_BYTE_CNT_SHIFT 0
++ byte spiMsgData[63]; /* (0x41 - 0x7f) msg data */
++ byte spiRxDataFifo[64]; /* (0x80 - 0xbf) rx data */
++ byte unused3[64]; /* (0xc0 - 0xff) reserved */
++} SpiControl;
++
++#define SPI ((volatile SpiControl * const) SPI_BASE)
++
++/*
++** External Bus Interface
++*/
++typedef struct EbiChipSelect {
++ uint32 base; /* base address in upper 24 bits */
++#define EBI_SIZE_8K 0
++#define EBI_SIZE_16K 1
++#define EBI_SIZE_32K 2
++#define EBI_SIZE_64K 3
++#define EBI_SIZE_128K 4
++#define EBI_SIZE_256K 5
++#define EBI_SIZE_512K 6
++#define EBI_SIZE_1M 7
++#define EBI_SIZE_2M 8
++#define EBI_SIZE_4M 9
++#define EBI_SIZE_8M 10
++#define EBI_SIZE_16M 11
++#define EBI_SIZE_32M 12
++#define EBI_SIZE_64M 13
++#define EBI_SIZE_128M 14
++#define EBI_SIZE_256M 15
++ uint32 config;
++#define EBI_ENABLE 0x00000001 /* .. enable this range */
++#define EBI_WAIT_STATES 0x0000000e /* .. mask for wait states */
++#define EBI_WTST_SHIFT 1 /* .. for shifting wait states */
++#define EBI_WORD_WIDE 0x00000010 /* .. 16-bit peripheral, else 8 */
++#define EBI_WREN 0x00000020 /* enable posted writes */
++#define EBI_POLARITY 0x00000040 /* .. set to invert something,
++ ** don't know what yet */
++#define EBI_TS_TA_MODE 0x00000080 /* .. use TS/TA mode */
++#define EBI_TS_SEL 0x00000100 /* .. drive tsize, not bs_b */
++#define EBI_FIFO 0x00000200 /* .. use fifo */
++#define EBI_RE 0x00000400 /* .. Reverse Endian */
++} EbiChipSelect;
++
++typedef struct MpiRegisters {
++ EbiChipSelect cs[1]; /* size chip select configuration */
++} MpiRegisters;
++
++#define MPI ((volatile MpiRegisters * const) MPI_BASE)
++
++
++#endif
++
+diff -urN linux.old/arch/mips/bcm963xx/include/6345_intr.h linux.dev/arch/mips/bcm963xx/include/6345_intr.h
+--- linux.old/arch/mips/bcm963xx/include/6345_intr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/include/6345_intr.h 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,72 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ for more details.
++
++ You should have received a copy of the GNU General Public License along
++ with this program; if not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++:>
++*/
++
++#ifndef __6345_INTR_H
++#define __6345_INTR_H
++
++
++/*=====================================================================*/
++/* BCM6345 External Interrupt Level Assignments */
++/*=====================================================================*/
++#define INTERRUPT_ID_EXTERNAL_0 3
++#define INTERRUPT_ID_EXTERNAL_1 4
++#define INTERRUPT_ID_EXTERNAL_2 5
++#define INTERRUPT_ID_EXTERNAL_3 6
++
++/*=====================================================================*/
++/* BCM6345 Timer Interrupt Level Assignments */
++/*=====================================================================*/
++#define MIPS_TIMER_INT 7
++
++/*=====================================================================*/
++/* Peripheral ISR Table Offset */
++/*=====================================================================*/
++#define INTERNAL_ISR_TABLE_OFFSET 8
++#define DMA_ISR_TABLE_OFFSET (INTERNAL_ISR_TABLE_OFFSET + 13)
++
++/*=====================================================================*/
++/* Logical Peripheral Interrupt IDs */
++/*=====================================================================*/
++
++/* Internal peripheral interrupt IDs */
++#define INTERRUPT_ID_TIMER (INTERNAL_ISR_TABLE_OFFSET + 0)
++#define INTERRUPT_ID_UART (INTERNAL_ISR_TABLE_OFFSET + 2)
++#define INTERRUPT_ID_ADSL (INTERNAL_ISR_TABLE_OFFSET + 3)
++#define INTERRUPT_ID_ATM (INTERNAL_ISR_TABLE_OFFSET + 4)
++#define INTERRUPT_ID_USB (INTERNAL_ISR_TABLE_OFFSET + 5)
++#define INTERRUPT_ID_EMAC (INTERNAL_ISR_TABLE_OFFSET + 8)
++#define INTERRUPT_ID_EPHY (INTERNAL_ISR_TABLE_OFFSET + 12)
++
++/* DMA channel interrupt IDs */
++#define INTERRUPT_ID_EMAC_RX_CHAN (DMA_ISR_TABLE_OFFSET + EMAC_RX_CHAN)
++#define INTERRUPT_ID_EMAC_TX_CHAN (DMA_ISR_TABLE_OFFSET + EMAC_TX_CHAN)
++#define INTERRUPT_ID_EBI_RX_CHAN (DMA_ISR_TABLE_OFFSET + EBI_RX_CHAN)
++#define INTERRUPT_ID_EBI_TX_CHAN (DMA_ISR_TABLE_OFFSET + EBI_TX_CHAN)
++#define INTERRUPT_ID_RESERVED_RX_CHAN (DMA_ISR_TABLE_OFFSET + RESERVED_RX_CHAN)
++#define INTERRUPT_ID_RESERVED_TX_CHAN (DMA_ISR_TABLE_OFFSET + RESERVED_TX_CHAN)
++#define INTERRUPT_ID_USB_BULK_RX_CHAN (DMA_ISR_TABLE_OFFSET + USB_BULK_RX_CHAN)
++#define INTERRUPT_ID_USB_BULK_TX_CHAN (DMA_ISR_TABLE_OFFSET + USB_BULK_TX_CHAN)
++#define INTERRUPT_ID_USB_CNTL_RX_CHAN (DMA_ISR_TABLE_OFFSET + USB_CNTL_RX_CHAN)
++#define INTERRUPT_ID_USB_CNTL_TX_CHAN (DMA_ISR_TABLE_OFFSET + USB_CNTL_TX_CHAN)
++#define INTERRUPT_ID_USB_ISO_RX_CHAN (DMA_ISR_TABLE_OFFSET + USB_ISO_RX_CHAN)
++#define INTERRUPT_ID_USB_ISO_TX_CHAN (DMA_ISR_TABLE_OFFSET + USB_ISO_TX_CHAN)
++
++
++#endif /* __BCM6345_H */
++
+diff -urN linux.old/arch/mips/bcm963xx/include/6345_map_part.h linux.dev/arch/mips/bcm963xx/include/6345_map_part.h
+--- linux.old/arch/mips/bcm963xx/include/6345_map_part.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/include/6345_map_part.h 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,163 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ for more details.
++
++ You should have received a copy of the GNU General Public License along
++ with this program; if not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++:>
++*/
++
++#ifndef __BCM6345_MAP_H
++#define __BCM6345_MAP_H
++
++
++#include "bcmtypes.h"
++#include "6345_intr.h"
++
++typedef struct IntControl {
++ uint32 RevID;
++ uint16 testControl;
++ uint16 blkEnables;
++#define USB_CLK_EN 0x0100
++#define EMAC_CLK_EN 0x0080
++#define UART_CLK_EN 0x0008
++#define CPU_CLK_EN 0x0001
++
++ uint32 pll_control;
++#define SOFT_RESET 0x00000001
++
++ uint32 IrqMask;
++ uint32 IrqStatus;
++
++ uint32 ExtIrqCfg;
++#define EI_SENSE_SHFT 0
++#define EI_STATUS_SHFT 4
++#define EI_CLEAR_SHFT 8
++#define EI_MASK_SHFT 12
++#define EI_INSENS_SHFT 16
++#define EI_LEVEL_SHFT 20
++} IntControl;
++
++#define INTC_BASE 0xfffe0000
++#define PERF ((volatile IntControl * const) INTC_BASE)
++
++#define TIMR_BASE 0xfffe0200
++typedef struct Timer {
++ uint16 unused0;
++ byte TimerMask;
++#define TIMER0EN 0x01
++#define TIMER1EN 0x02
++#define TIMER2EN 0x04
++ byte TimerInts;
++#define TIMER0 0x01
++#define TIMER1 0x02
++#define TIMER2 0x04
++#define WATCHDOG 0x08
++ uint32 TimerCtl0;
++ uint32 TimerCtl1;
++ uint32 TimerCtl2;
++#define TIMERENABLE 0x80000000
++#define RSTCNTCLR 0x40000000
++ uint32 TimerCnt0;
++ uint32 TimerCnt1;
++ uint32 TimerCnt2;
++ uint32 WatchDogDefCount;
++
++ /* Write 0xff00 0x00ff to Start timer
++ * Write 0xee00 0x00ee to Stop and re-load default count
++ * Read from this register returns current watch dog count
++ */
++ uint32 WatchDogCtl;
++
++ /* Number of 40-MHz ticks for WD Reset pulse to last */
++ uint32 WDResetCount;
++} Timer;
++
++#define TIMER ((volatile Timer * const) TIMR_BASE)
++
++typedef struct UartChannel {
++ byte unused0;
++ byte control;
++#define BRGEN 0x80 /* Control register bit defs */
++#define TXEN 0x40
++#define RXEN 0x20
++#define TXPARITYEN 0x08
++#define TXPARITYEVEN 0x04
++#define RXPARITYEN 0x02
++#define RXPARITYEVEN 0x01
++ byte config;
++#define BITS5SYM 0x00
++#define BITS6SYM 0x10
++#define BITS7SYM 0x20
++#define BITS8SYM 0x30
++#define XMITBREAK 0x40
++#define ONESTOP 0x07
++#define TWOSTOP 0x0f
++
++ byte fifoctl;
++#define RSTTXFIFOS 0x80
++#define RSTRXFIFOS 0x40
++ uint32 baudword;
++
++ byte txf_levl;
++ byte rxf_levl;
++ byte fifocfg;
++ byte prog_out;
++
++ byte unused1;
++ byte DeltaIPEdgeNoSense;
++ byte DeltaIPConfig_Mask;
++ byte DeltaIP_SyncIP;
++ uint16 intMask;
++ uint16 intStatus;
++#define TXUNDERR 0x0002
++#define TXOVFERR 0x0004
++#define TXFIFOEMT 0x0020
++#define RXOVFERR 0x0080
++#define RXFIFONE 0x0800
++#define RXFRAMERR 0x1000
++#define RXPARERR 0x2000
++#define RXBRK 0x4000
++
++ uint16 unused2;
++ uint16 Data;
++ uint32 unused3;
++ uint32 unused4;
++} Uart;
++
++#define UART_BASE 0xfffe0300
++#define UART ((volatile Uart * const) UART_BASE)
++
++typedef struct GpioControl {
++ uint16 unused0;
++ byte unused1;
++ byte TBusSel;
++
++ uint16 unused2;
++ uint16 GPIODir;
++ byte unused3;
++ byte Leds;
++ uint16 GPIOio;
++
++ uint32 UartCtl;
++} GpioControl;
++
++#define GPIO_BASE 0xfffe0400
++#define GPIO ((volatile GpioControl * const) GPIO_BASE)
++
++#define GPIO_NUM_MAX_BITS_MASK 0x0f
++#define GPIO_NUM_TO_MASK(X) (1 << ((X) & GPIO_NUM_MAX_BITS_MASK))
++
++
++#endif
++
+diff -urN linux.old/arch/mips/bcm963xx/include/6348_intr.h linux.dev/arch/mips/bcm963xx/include/6348_intr.h
+--- linux.old/arch/mips/bcm963xx/include/6348_intr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/include/6348_intr.h 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,74 @@
++/*
++<:copyright-gpl
++ Copyright 2003 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ for more details.
++
++ You should have received a copy of the GNU General Public License along
++ with this program; if not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++:>
++*/
++
++#ifndef __6348_INTR_H
++#define __6348_INTR_H
++
++
++/*=====================================================================*/
++/* BCM6348 External Interrupt Level Assignments */
++/*=====================================================================*/
++#define INTERRUPT_ID_EXTERNAL_0 3
++#define INTERRUPT_ID_EXTERNAL_1 4
++#define INTERRUPT_ID_EXTERNAL_2 5
++#define INTERRUPT_ID_EXTERNAL_3 6
++
++/*=====================================================================*/
++/* BCM6348 Timer Interrupt Level Assignments */
++/*=====================================================================*/
++#define MIPS_TIMER_INT 7
++
++/*=====================================================================*/
++/* Peripheral ISR Table Offset */
++/*=====================================================================*/
++#define INTERNAL_ISR_TABLE_OFFSET 8
++
++/*=====================================================================*/
++/* Logical Peripheral Interrupt IDs */
++/*=====================================================================*/
++
++#define INTERRUPT_ID_TIMER (INTERNAL_ISR_TABLE_OFFSET + 0)
++#define INTERRUPT_ID_SPI (INTERNAL_ISR_TABLE_OFFSET + 1)
++#define INTERRUPT_ID_UART (INTERNAL_ISR_TABLE_OFFSET + 2)
++#define INTERRUPT_ID_ADSL (INTERNAL_ISR_TABLE_OFFSET + 4)
++#define INTERRUPT_ID_ATM (INTERNAL_ISR_TABLE_OFFSET + 5)
++#define INTERRUPT_ID_USBS (INTERNAL_ISR_TABLE_OFFSET + 6)
++#define INTERRUPT_ID_EMAC2 (INTERNAL_ISR_TABLE_OFFSET + 7)
++#define INTERRUPT_ID_EMAC1 (INTERNAL_ISR_TABLE_OFFSET + 8)
++#define INTERRUPT_ID_EPHY (INTERNAL_ISR_TABLE_OFFSET + 9)
++#define INTERRUPT_ID_M2M (INTERNAL_ISR_TABLE_OFFSET + 10)
++#define INTERRUPT_ID_ACLC (INTERNAL_ISR_TABLE_OFFSET + 11)
++#define INTERRUPT_ID_USBH (INTERNAL_ISR_TABLE_OFFSET + 12)
++#define INTERRUPT_ID_SDRAM (INTERNAL_ISR_TABLE_OFFSET + 13)
++#define INTERRUPT_ID_USB_CNTL_RX_DMA (INTERNAL_ISR_TABLE_OFFSET + 14)
++#define INTERRUPT_ID_USB_CNTL_TX_DMA (INTERNAL_ISR_TABLE_OFFSET + 15)
++#define INTERRUPT_ID_USB_BULK_RX_DMA (INTERNAL_ISR_TABLE_OFFSET + 16)
++#define INTERRUPT_ID_USB_BULK_TX_DMA (INTERNAL_ISR_TABLE_OFFSET + 17)
++#define INTERRUPT_ID_USB_ISO_RX_DMA (INTERNAL_ISR_TABLE_OFFSET + 18)
++#define INTERRUPT_ID_USB_ISO_TX_DMA (INTERNAL_ISR_TABLE_OFFSET + 19)
++#define INTERRUPT_ID_EMAC1_RX_DMA (INTERNAL_ISR_TABLE_OFFSET + 20)
++#define INTERRUPT_ID_EMAC1_TX_DMA (INTERNAL_ISR_TABLE_OFFSET + 21)
++#define INTERRUPT_ID_EMAC2_RX_DMA (INTERNAL_ISR_TABLE_OFFSET + 22)
++#define INTERRUPT_ID_EMAC2_TX_DMA (INTERNAL_ISR_TABLE_OFFSET + 23)
++#define INTERRUPT_ID_MPI (INTERNAL_ISR_TABLE_OFFSET + 24)
++#define INTERRUPT_ID_DG (INTERNAL_ISR_TABLE_OFFSET + 25)
++
++
++#endif /* __BCM6348_H */
++
+diff -urN linux.old/arch/mips/bcm963xx/include/6348_map_part.h linux.dev/arch/mips/bcm963xx/include/6348_map_part.h
+--- linux.old/arch/mips/bcm963xx/include/6348_map_part.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/include/6348_map_part.h 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,500 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ for more details.
++
++ You should have received a copy of the GNU General Public License along
++ with this program; if not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++:>
++*/
++
++#ifndef __BCM6348_MAP_H
++#define __BCM6348_MAP_H
++
++#include "bcmtypes.h"
++
++#define PERF_BASE 0xfffe0000
++#define TIMR_BASE 0xfffe0200
++#define UART_BASE 0xfffe0300
++#define GPIO_BASE 0xfffe0400
++#define MPI_BASE 0xfffe2000 /* MPI control registers */
++#define USB_HOST_BASE 0xfffe1b00 /* USB host registers */
++#define USB_HOST_NON_OHCI 0xfffe1c00 /* USB host non-OHCI registers */
++
++typedef struct PerfControl {
++ uint32 RevID;
++ uint16 testControl;
++ uint16 blkEnables;
++#define EMAC_CLK_EN 0x0010
++#define SAR_CLK_EN 0x0020
++#define USBS_CLK_EN 0x0040
++#define USBH_CLK_EN 0x0100
++
++ uint32 pll_control;
++#define SOFT_RESET 0x00000001
++
++ uint32 IrqMask;
++ uint32 IrqStatus;
++
++ uint32 ExtIrqCfg;
++#define EI_SENSE_SHFT 0
++#define EI_STATUS_SHFT 5
++#define EI_CLEAR_SHFT 10
++#define EI_MASK_SHFT 15
++#define EI_INSENS_SHFT 20
++#define EI_LEVEL_SHFT 25
++
++ uint32 unused[4]; /* (18) */
++ uint32 BlockSoftReset; /* (28) */
++#define BSR_SPI 0x00000001
++#define BSR_EMAC 0x00000004
++#define BSR_USBH 0x00000008
++#define BSR_USBS 0x00000010
++#define BSR_ADSL 0x00000020
++#define BSR_DMAMEM 0x00000040
++#define BSR_SAR 0x00000080
++#define BSR_ACLC 0x00000100
++#define BSR_ADSL_MIPS_PLL 0x00000400
++#define BSR_ALL_BLOCKS \
++ (BSR_SPI | BSR_EMAC | BSR_USBH | BSR_USBS | BSR_ADSL | BSR_DMAMEM | \
++ BSR_SAR | BSR_ACLC | BSR_ADSL_MIPS_PLL)
++ uint32 unused2[2]; /* (2c) */
++ uint32 PllStrap; /* (34) */
++#define PLL_N1_SHFT 20
++#define PLL_N1_MASK (7<<PLL_N1_SHFT)
++#define PLL_N2_SHFT 15
++#define PLL_N2_MASK (0x1f<<PLL_N2_SHFT)
++#define PLL_M1_REF_SHFT 12
++#define PLL_M1_REF_MASK (7<<PLL_M1_REF_SHFT)
++#define PLL_M2_REF_SHFT 9
++#define PLL_M2_REF_MASK (7<<PLL_M2_REF_SHFT)
++#define PLL_M1_CPU_SHFT 6
++#define PLL_M1_CPU_MASK (7<<PLL_M1_CPU_SHFT)
++#define PLL_M1_BUS_SHFT 3
++#define PLL_M1_BUS_MASK (7<<PLL_M1_BUS_SHFT)
++#define PLL_M2_BUS_SHFT 0
++#define PLL_M2_BUS_MASK (7<<PLL_M2_BUS_SHFT)
++} PerfControl;
++
++#define PERF ((volatile PerfControl * const) PERF_BASE)
++
++typedef struct Timer {
++ uint16 unused0;
++ byte TimerMask;
++#define TIMER0EN 0x01
++#define TIMER1EN 0x02
++#define TIMER2EN 0x04
++ byte TimerInts;
++#define TIMER0 0x01
++#define TIMER1 0x02
++#define TIMER2 0x04
++#define WATCHDOG 0x08
++ uint32 TimerCtl0;
++ uint32 TimerCtl1;
++ uint32 TimerCtl2;
++#define TIMERENABLE 0x80000000
++#define RSTCNTCLR 0x40000000
++ uint32 TimerCnt0;
++ uint32 TimerCnt1;
++ uint32 TimerCnt2;
++ uint32 WatchDogDefCount;
++
++ /* Write 0xff00 0x00ff to Start timer
++ * Write 0xee00 0x00ee to Stop and re-load default count
++ * Read from this register returns current watch dog count
++ */
++ uint32 WatchDogCtl;
++
++ /* Number of 40-MHz ticks for WD Reset pulse to last */
++ uint32 WDResetCount;
++} Timer;
++
++#define TIMER ((volatile Timer * const) TIMR_BASE)
++
++typedef struct UartChannel {
++ byte unused0;
++ byte control;
++#define BRGEN 0x80 /* Control register bit defs */
++#define TXEN 0x40
++#define RXEN 0x20
++#define LOOPBK 0x10
++#define TXPARITYEN 0x08
++#define TXPARITYEVEN 0x04
++#define RXPARITYEN 0x02
++#define RXPARITYEVEN 0x01
++
++ byte config;
++#define XMITBREAK 0x40
++#define BITS5SYM 0x00
++#define BITS6SYM 0x10
++#define BITS7SYM 0x20
++#define BITS8SYM 0x30
++#define ONESTOP 0x07
++#define TWOSTOP 0x0f
++ /* 4-LSBS represent STOP bits/char
++ * in 1/8 bit-time intervals. Zero
++ * represents 1/8 stop bit interval.
++ * Fifteen represents 2 stop bits.
++ */
++ byte fifoctl;
++#define RSTTXFIFOS 0x80
++#define RSTRXFIFOS 0x40
++ /* 5-bit TimeoutCnt is in low bits of this register.
++ * This count represents the number of characters
++ * idle times before setting receive Irq when below threshold
++ */
++ uint32 baudword;
++ /* When divide SysClk/2/(1+baudword) we should get 32*bit-rate
++ */
++
++ byte txf_levl; /* Read-only fifo depth */
++ byte rxf_levl; /* Read-only fifo depth */
++ byte fifocfg; /* Upper 4-bits are TxThresh, Lower are
++ * RxThreshold. Irq can be asserted
++ * when rx fifo> thresh, txfifo<thresh
++ */
++ byte prog_out; /* Set value of DTR (Bit0), RTS (Bit1)
++ * if these bits are also enabled to GPIO_o
++ */
++#define DTREN 0x01
++#define RTSEN 0x02
++
++ byte unused1;
++ byte DeltaIPEdgeNoSense; /* Low 4-bits, set corr bit to 1 to
++ * detect irq on rising AND falling
++ * edges for corresponding GPIO_i
++ * if enabled (edge insensitive)
++ */
++ byte DeltaIPConfig_Mask; /* Upper 4 bits: 1 for posedge sense
++ * 0 for negedge sense if
++ * not configured for edge
++ * insensitive (see above)
++ * Lower 4 bits: Mask to enable change
++ * detection IRQ for corresponding
++ * GPIO_i
++ */
++ byte DeltaIP_SyncIP; /* Upper 4 bits show which bits
++ * have changed (may set IRQ).
++ * read automatically clears bit
++ * Lower 4 bits are actual status
++ */
++
++ uint16 intMask; /* Same Bit defs for Mask and status */
++ uint16 intStatus;
++#define DELTAIP 0x0001
++#define TXUNDERR 0x0002
++#define TXOVFERR 0x0004
++#define TXFIFOTHOLD 0x0008
++#define TXREADLATCH 0x0010
++#define TXFIFOEMT 0x0020
++#define RXUNDERR 0x0040
++#define RXOVFERR 0x0080
++#define RXTIMEOUT 0x0100
++#define RXFIFOFULL 0x0200
++#define RXFIFOTHOLD 0x0400
++#define RXFIFONE 0x0800
++#define RXFRAMERR 0x1000
++#define RXPARERR 0x2000
++#define RXBRK 0x4000
++
++ uint16 unused2;
++ uint16 Data; /* Write to TX, Read from RX */
++ /* bits 11:8 are BRK,PAR,FRM errors */
++
++ uint32 unused3;
++ uint32 unused4;
++} Uart;
++
++#define UART ((volatile Uart * const) UART_BASE)
++
++typedef struct GpioControl {
++ uint32 GPIODir_high; /* bits 36:32 */
++ uint32 GPIODir; /* bits 31:00 */
++ uint32 GPIOio_high; /* bits 36:32 */
++ uint32 GPIOio; /* bits 31:00 */
++ uint32 LEDCtrl;
++#define LED3_STROBE 0x08000000
++#define LED2_STROBE 0x04000000
++#define LED1_STROBE 0x02000000
++#define LED0_STROBE 0x01000000
++#define LED_TEST 0x00010000
++#define LED3_DISABLE_LINK_ACT 0x00008000
++#define LED2_DISABLE_LINK_ACT 0x00004000
++#define LED1_DISABLE_LINK_ACT 0x00002000
++#define LED0_DISABLE_LINK_ACT 0x00001000
++#define LED_INTERVAL_SET_MASK 0x00000f00
++#define LED_INTERVAL_SET_320MS 0x00000500
++#define LED_INTERVAL_SET_160MS 0x00000400
++#define LED_INTERVAL_SET_80MS 0x00000300
++#define LED_INTERVAL_SET_40MS 0x00000200
++#define LED_INTERVAL_SET_20MS 0x00000100
++#define LED3_ON 0x00000080
++#define LED2_ON 0x00000040
++#define LED1_ON 0x00000020
++#define LED0_ON 0x00000010
++#define LED3_ENABLE 0x00000008
++#define LED2_ENABLE 0x00000004
++#define LED1_ENABLE 0x00000002
++#define LED0_ENABLE 0x00000001
++ uint32 SpiSlaveCfg;
++#define SPI_SLAVE_RESET 0x00010000
++#define SPI_RESTRICT 0x00000400
++#define SPI_DELAY_DISABLE 0x00000200
++#define SPI_PROBE_MUX_SEL_MASK 0x000001e0
++#define SPI_SER_ADDR_CFG_MASK 0x0000000c
++#define SPI_MODE 0x00000001
++ uint32 GPIOMode;
++#define GROUP4_DIAG 0x00090000
++#define GROUP4_UTOPIA 0x00080000
++#define GROUP4_LEGACY_LED 0x00030000
++#define GROUP4_MII_SNOOP 0x00020000
++#define GROUP4_EXT_EPHY 0x00010000
++#define GROUP3_DIAG 0x00009000
++#define GROUP3_UTOPIA 0x00008000
++#define GROUP3_EXT_MII 0x00007000
++#define GROUP2_DIAG 0x00000900
++#define GROUP2_PCI 0x00000500
++#define GROUP1_DIAG 0x00000090
++#define GROUP1_UTOPIA 0x00000080
++#define GROUP1_SPI_UART 0x00000060
++#define GROUP1_SPI_MASTER 0x00000060
++#define GROUP1_MII_PCCARD 0x00000040
++#define GROUP1_MII_SNOOP 0x00000020
++#define GROUP1_EXT_EPHY 0x00000010
++#define GROUP0_DIAG 0x00000009
++#define GROUP0_EXT_MII 0x00000007
++
++} GpioControl;
++
++#define GPIO ((volatile GpioControl * const) GPIO_BASE)
++
++/* Number to mask conversion macro used for GPIODir and GPIOio */
++#define GPIO_NUM_TOTAL_BITS_MASK 0x3f
++#define GPIO_NUM_MAX_BITS_MASK 0x1f
++#define GPIO_NUM_TO_MASK(X) ( (((X) & GPIO_NUM_TOTAL_BITS_MASK) < 32) ? (1 << ((X) & GPIO_NUM_MAX_BITS_MASK)) : (0) )
++
++/* Number to mask conversion macro used for GPIODir_high and GPIOio_high */
++#define GPIO_NUM_MAX_BITS_MASK_HIGH 0x07
++#define GPIO_NUM_TO_MASK_HIGH(X) ( (((X) & GPIO_NUM_TOTAL_BITS_MASK) >= 32) ? (1 << ((X-32) & GPIO_NUM_MAX_BITS_MASK_HIGH)) : (0) )
++
++
++/*
++** External Bus Interface
++*/
++typedef struct EbiChipSelect {
++ uint32 base; /* base address in upper 24 bits */
++#define EBI_SIZE_8K 0
++#define EBI_SIZE_16K 1
++#define EBI_SIZE_32K 2
++#define EBI_SIZE_64K 3
++#define EBI_SIZE_128K 4
++#define EBI_SIZE_256K 5
++#define EBI_SIZE_512K 6
++#define EBI_SIZE_1M 7
++#define EBI_SIZE_2M 8
++#define EBI_SIZE_4M 9
++#define EBI_SIZE_8M 10
++#define EBI_SIZE_16M 11
++#define EBI_SIZE_32M 12
++#define EBI_SIZE_64M 13
++#define EBI_SIZE_128M 14
++#define EBI_SIZE_256M 15
++ uint32 config;
++#define EBI_ENABLE 0x00000001 /* .. enable this range */
++#define EBI_WAIT_STATES 0x0000000e /* .. mask for wait states */
++#define EBI_WTST_SHIFT 1 /* .. for shifting wait states */
++#define EBI_WORD_WIDE 0x00000010 /* .. 16-bit peripheral, else 8 */
++#define EBI_WREN 0x00000020 /* enable posted writes */
++#define EBI_POLARITY 0x00000040 /* .. set to invert something,
++ ** don't know what yet */
++#define EBI_TS_TA_MODE 0x00000080 /* .. use TS/TA mode */
++#define EBI_TS_SEL 0x00000100 /* .. drive tsize, not bs_b */
++#define EBI_FIFO 0x00000200 /* .. use fifo */
++#define EBI_RE 0x00000400 /* .. Reverse Endian */
++} EbiChipSelect;
++
++typedef struct MpiRegisters {
++ EbiChipSelect cs[7]; /* size chip select configuration */
++#define EBI_CS0_BASE 0
++#define EBI_CS1_BASE 1
++#define EBI_CS2_BASE 2
++#define EBI_CS3_BASE 3
++#define PCMCIA_COMMON_BASE 4
++#define PCMCIA_ATTRIBUTE_BASE 5
++#define PCMCIA_IO_BASE 6
++ uint32 unused0[2]; /* reserved */
++ uint32 ebi_control; /* ebi control */
++ uint32 unused1[4]; /* reserved */
++#define EBI_ACCESS_TIMEOUT 0x000007FF
++ uint32 pcmcia_cntl1; /* pcmcia control 1 */
++#define PCCARD_CARD_RESET 0x00040000
++#define CARDBUS_ENABLE 0x00008000
++#define PCMCIA_ENABLE 0x00004000
++#define PCMCIA_GPIO_ENABLE 0x00002000
++#define CARDBUS_IDSEL 0x00001F00
++#define VS2_OEN 0x00000080
++#define VS1_OEN 0x00000040
++#define VS2_OUT 0x00000020
++#define VS1_OUT 0x00000010
++#define VS2_IN 0x00000008
++#define VS1_IN 0x00000004
++#define CD2_IN 0x00000002
++#define CD1_IN 0x00000001
++#define VS_MASK 0x0000000C
++#define CD_MASK 0x00000003
++ uint32 unused2; /* reserved */
++ uint32 pcmcia_cntl2; /* pcmcia control 2 */
++#define PCMCIA_BYTESWAP_DIS 0x00000002
++#define PCMCIA_HALFWORD_EN 0x00000001
++#define RW_ACTIVE_CNT_BIT 2
++#define INACTIVE_CNT_BIT 8
++#define CE_SETUP_CNT_BIT 16
++#define CE_HOLD_CNT_BIT 24
++ uint32 unused3[40]; /* reserved */
++
++ uint32 sp0range; /* PCI to internal system bus address space */
++ uint32 sp0remap;
++ uint32 sp0cfg;
++ uint32 sp1range;
++ uint32 sp1remap;
++ uint32 sp1cfg;
++
++ uint32 EndianCfg;
++
++ uint32 l2pcfgctl; /* internal system bus to PCI IO/Cfg control */
++#define DIR_CFG_SEL 0x80000000 /* change from PCI I/O access to PCI config access */
++#define DIR_CFG_USEREG 0x40000000 /* use this register info for PCI configuration access */
++#define DEVICE_NUMBER 0x00007C00 /* device number for the PCI configuration access */
++#define FUNC_NUMBER 0x00000300 /* function number for the PCI configuration access */
++#define REG_NUMBER 0x000000FC /* register number for the PCI configuration access */
++#define CONFIG_TYPE 0x00000003 /* configuration type for the PCI configuration access */
++
++ uint32 l2pmrange1; /* internal system bus to PCI memory space */
++#define PCI_SIZE_64K 0xFFFF0000
++#define PCI_SIZE_128K 0xFFFE0000
++#define PCI_SIZE_256K 0xFFFC0000
++#define PCI_SIZE_512K 0xFFF80000
++#define PCI_SIZE_1M 0xFFF00000
++#define PCI_SIZE_2M 0xFFE00000
++#define PCI_SIZE_4M 0xFFC00000
++#define PCI_SIZE_8M 0xFF800000
++#define PCI_SIZE_16M 0xFF000000
++#define PCI_SIZE_32M 0xFE000000
++ uint32 l2pmbase1; /* kseg0 or kseg1 address & 0x1FFFFFFF */
++ uint32 l2pmremap1;
++#define CARDBUS_MEM 0x00000004
++#define MEM_WINDOW_EN 0x00000001
++ uint32 l2pmrange2;
++ uint32 l2pmbase2;
++ uint32 l2pmremap2;
++ uint32 l2piorange; /* internal system bus to PCI I/O space */
++ uint32 l2piobase;
++ uint32 l2pioremap;
++
++ uint32 pcimodesel;
++#define PCI2_INT_BUS_RD_PREFECH 0x000000F0
++#define PCI_BAR2_NOSWAP 0x00000002 /* BAR at offset 0x20 */
++#define PCI_BAR1_NOSWAP 0x00000001 /* BAR at affset 0x1c */
++
++ uint32 pciintstat; /* PCI interrupt mask/status */
++#define MAILBOX1_SENT 0x08
++#define MAILBOX0_SENT 0x04
++#define MAILBOX1_MSG_RCV 0x02
++#define MAILBOX0_MSG_RCV 0x01
++ uint32 locbuscntrl; /* internal system bus control */
++#define DIR_U2P_NOSWAP 0x00000002
++#define EN_PCI_GPIO 0x00000001
++ uint32 locintstat; /* internal system bus interrupt mask/status */
++#define CSERR 0x0200
++#define SERR 0x0100
++#define EXT_PCI_INT 0x0080
++#define DIR_FAILED 0x0040
++#define DIR_COMPLETE 0x0020
++#define PCI_CFG 0x0010
++ uint32 unused5[7];
++
++ uint32 mailbox0;
++ uint32 mailbox1;
++
++ uint32 pcicfgcntrl; /* internal system bus PCI configuration control */
++#define PCI_CFG_REG_WRITE_EN 0x00000080
++#define PCI_CFG_ADDR 0x0000003C
++ uint32 pcicfgdata; /* internal system bus PCI configuration data */
++
++ uint32 locch2ctl; /* PCI to interrnal system bus DMA (downstream) local control */
++#define MPI_DMA_HALT 0x00000008 /* idle after finish current memory burst */
++#define MPI_DMA_PKT_HALT 0x00000004 /* idle after an EOP flag is detected */
++#define MPI_DMA_STALL 0x00000002 /* idle after an EOP flag is detected */
++#define MPI_DMA_ENABLE 0x00000001 /* set to enable channel */
++ uint32 locch2intStat;
++#define MPI_DMA_NO_DESC 0x00000004 /* no valid descriptors */
++#define MPI_DMA_DONE 0x00000002 /* packet xfer complete */
++#define MPI_DMA_BUFF_DONE 0x00000001 /* buffer done */
++ uint32 locch2intMask;
++ uint32 unused6;
++ uint32 locch2descaddr;
++ uint32 locch2status1;
++#define LOCAL_DESC_STATE 0xE0000000
++#define PCI_DESC_STATE 0x1C000000
++#define BYTE_DONE 0x03FFC000
++#define RING_ADDR 0x00003FFF
++ uint32 locch2status2;
++#define BUFPTR_OFFSET 0x1FFF0000
++#define PCI_MASTER_STATE 0x000000C0
++#define LOC_MASTER_STATE 0x00000038
++#define CONTROL_STATE 0x00000007
++ uint32 unused7;
++
++ uint32 locch1Ctl; /*internal system bus to PCI DMA (upstream) local control */
++#define DMA_U2P_LE 0x00000200 /* local bus is little endian */
++#define DMA_U2P_NOSWAP 0x00000100 /* lccal bus is little endian but no data swapped */
++ uint32 locch1intstat;
++ uint32 locch1intmask;
++ uint32 unused8;
++ uint32 locch1descaddr;
++ uint32 locch1status1;
++ uint32 locch1status2;
++ uint32 unused9;
++
++ uint32 pcich1ctl; /* internal system bus to PCI DMA PCI control */
++ uint32 pcich1intstat;
++ uint32 pcich1intmask;
++ uint32 pcich1descaddr;
++ uint32 pcich1status1;
++ uint32 pcich1status2;
++
++ uint32 pcich2Ctl; /* PCI to internal system bus DMA PCI control */
++ uint32 pcich2intstat;
++ uint32 pcich2intmask;
++ uint32 pcich2descaddr;
++ uint32 pcich2status1;
++ uint32 pcich2status2;
++
++ uint32 perm_id; /* permanent device and vendor id */
++ uint32 perm_rev; /* permanent revision id */
++} MpiRegisters;
++
++#define MPI ((volatile MpiRegisters * const) MPI_BASE)
++
++/* PCI configuration address space start offset 0x40 */
++#define BRCM_PCI_CONFIG_TIMER 0x40
++#define BRCM_PCI_CONFIG_TIMER_RETRY_MASK 0x0000FF00
++#define BRCM_PCI_CONFIG_TIMER_TRDY_MASK 0x000000FF
++
++/* USB host non-Open HCI register, USB_HOST_NON_OHCI, bit definitions. */
++#define NON_OHCI_ENABLE_PORT1 0x00000001 /* Use USB port 1 for host, not dev */
++#define NON_OHCI_BYTE_SWAP 0x00000008 /* Swap USB host registers */
++
++#define USBH_NON_OHCI ((volatile unsigned long * const) USB_HOST_NON_OHCI)
++
++#endif
++
+diff -urN linux.old/arch/mips/bcm963xx/include/bcm_intr.h linux.dev/arch/mips/bcm963xx/include/bcm_intr.h
+--- linux.old/arch/mips/bcm963xx/include/bcm_intr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/include/bcm_intr.h 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,59 @@
++/*
++<:copyright-gpl
++ Copyright 2003 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ for more details.
++
++ You should have received a copy of the GNU General Public License along
++ with this program; if not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++:>
++*/
++
++#ifndef __BCM_INTR_H
++#define __BCM_INTR_H
++
++#ifdef __cplusplus
++ extern "C" {
++#endif
++
++#if defined(CONFIG_BCM96338)
++#include <6338_intr.h>
++#endif
++#if defined(CONFIG_BCM96345)
++#include <6345_intr.h>
++#endif
++#if defined(CONFIG_BCM96348)
++#include <6348_intr.h>
++#endif
++
++/* defines */
++struct pt_regs;
++typedef int (*FN_HANDLER) (int, void *, struct pt_regs *);
++
++/* prototypes */
++extern void enable_brcm_irq(unsigned int irq);
++extern void disable_brcm_irq(unsigned int irq);
++extern int request_external_irq(unsigned int irq,
++ FN_HANDLER handler, unsigned long irqflags,
++ const char * devname, void *dev_id);
++extern unsigned int BcmHalMapInterrupt(FN_HANDLER isr, unsigned int param,
++ unsigned int interruptId);
++extern void dump_intr_regs(void);
++
++/* compatibility definitions */
++#define BcmHalInterruptEnable(irq) enable_brcm_irq( irq )
++#define BcmHalInterruptDisable(irq) disable_brcm_irq( irq )
++
++#ifdef __cplusplus
++ }
++#endif
++
++#endif
+diff -urN linux.old/arch/mips/bcm963xx/include/bcm_map_part.h linux.dev/arch/mips/bcm963xx/include/bcm_map_part.h
+--- linux.old/arch/mips/bcm963xx/include/bcm_map_part.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/include/bcm_map_part.h 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,34 @@
++/*
++<:copyright-gpl
++ Copyright 2004 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ for more details.
++
++ You should have received a copy of the GNU General Public License along
++ with this program; if not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++:>
++*/
++
++#ifndef __BCM_MAP_PART_H
++#define __BCM_MAP_PART_H
++
++#if defined(CONFIG_BCM96338)
++#include <6338_map_part.h>
++#endif
++#if defined(CONFIG_BCM96345)
++#include <6345_map_part.h>
++#endif
++#if defined(CONFIG_BCM96348)
++#include <6348_map_part.h>
++#endif
++
++#endif
++
+diff -urN linux.old/arch/mips/bcm963xx/include/bcmpci.h linux.dev/arch/mips/bcm963xx/include/bcmpci.h
+--- linux.old/arch/mips/bcm963xx/include/bcmpci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/include/bcmpci.h 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,87 @@
++/*
++<:copyright-gpl
++ Copyright 2004 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope 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.
++:>
++*/
++
++//
++// bcmpci.h - bcm96348 PCI, Cardbus, and PCMCIA definition
++//
++#ifndef BCMPCI_H
++#define BCMPCI_H
++
++/* Memory window in internal system bus address space */
++#define BCM_PCI_MEM_BASE 0x08000000
++/* IO window in internal system bus address space */
++#define BCM_PCI_IO_BASE 0x0C000000
++
++#define BCM_PCI_ADDR_MASK 0x1fffffff
++
++/* Memory window size (range) */
++#define BCM_PCI_MEM_SIZE_16MB 0x01000000
++/* IO window size (range) */
++#define BCM_PCI_IO_SIZE_64KB 0x00010000
++
++/* PCI Configuration and I/O space acesss */
++#define BCM_PCI_CFG(d, f, o) ( (d << 11) | (f << 8) | (o/4 << 2) )
++
++/* fake USB PCI slot */
++#define USB_HOST_SLOT 9
++#define USB_BAR0_MEM_SIZE 0x0800
++
++#define BCM_HOST_MEM_SPACE1 0x10000000
++#define BCM_HOST_MEM_SPACE2 0x00000000
++
++/*
++ * EBI bus clock is 33MHz and share with PCI bus
++ * each clock cycle is 30ns.
++ */
++/* attribute memory access wait cnt for 4306 */
++#define PCMCIA_ATTR_CE_HOLD 3 // data hold time 70ns
++#define PCMCIA_ATTR_CE_SETUP 3 // data setup time 50ns
++#define PCMCIA_ATTR_INACTIVE 6 // time between read/write cycles 180ns. For the total cycle time 600ns (cnt1+cnt2+cnt3+cnt4)
++#define PCMCIA_ATTR_ACTIVE 10 // OE/WE pulse width 300ns
++
++/* common memory access wait cnt for 4306 */
++#define PCMCIA_MEM_CE_HOLD 1 // data hold time 30ns
++#define PCMCIA_MEM_CE_SETUP 1 // data setup time 30ns
++#define PCMCIA_MEM_INACTIVE 2 // time between read/write cycles 40ns. For the total cycle time 250ns (cnt1+cnt2+cnt3+cnt4)
++#define PCMCIA_MEM_ACTIVE 5 // OE/WE pulse width 150ns
++
++#define PCCARD_VCC_MASK 0x00070000 // Mask Reset also
++#define PCCARD_VCC_33V 0x00010000
++#define PCCARD_VCC_50V 0x00020000
++
++typedef enum {
++ MPI_CARDTYPE_NONE, // No Card in slot
++ MPI_CARDTYPE_PCMCIA, // 16-bit PCMCIA card in slot
++ MPI_CARDTYPE_CARDBUS, // 32-bit CardBus card in slot
++} CardType;
++
++#define CARDBUS_SLOT 0 // Slot 0 is default for CardBus
++
++#define pcmciaAttrOffset 0x00200000
++#define pcmciaMemOffset 0x00000000
++// Needs to be right above PCI I/O space. Give 0x8000 (32K) to PCMCIA.
++#define pcmciaIoOffset (BCM_PCI_IO_BASE + 0x80000)
++// Base Address is that mapped into the MPI ChipSelect registers.
++// UBUS bridge MemoryWindow 0 outputs a 0x00 for the base.
++#define pcmciaBase 0xbf000000
++#define pcmciaAttr (pcmciaAttrOffset | pcmciaBase)
++#define pcmciaMem (pcmciaMemOffset | pcmciaBase)
++#define pcmciaIo (pcmciaIoOffset | pcmciaBase)
++
++#endif
+diff -urN linux.old/arch/mips/bcm963xx/include/bcmTag.h linux.dev/arch/mips/bcm963xx/include/bcmTag.h
+--- linux.old/arch/mips/bcm963xx/include/bcmTag.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/include/bcmTag.h 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,153 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ for more details.
++
++ You should have received a copy of the GNU General Public License along
++ with this program; if not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++:>
++*/
++//**************************************************************************************
++// File Name : bcmTag.h
++//
++// Description: add tag with validation system to the firmware image file to be uploaded
++// via http
++//
++// Created : 02/28/2002 seanl
++//**************************************************************************************
++
++#ifndef _BCMTAG_H_
++#define _BCMTAG_H_
++
++
++#define BCM_SIG_1 "Broadcom Corporation"
++#define BCM_SIG_2 "ver. 2.0" // was "firmware version 2.0" now it is split 6 char out for chip id.
++
++#define BCM_TAG_VER "6"
++#define BCM_TAG_VER_LAST "26"
++
++// file tag (head) structure all is in clear text except validationTokens (crc, md5, sha1, etc). Total: 128 unsigned chars
++#define TAG_LEN 256
++#define TAG_VER_LEN 4
++#define SIG_LEN 20
++#define SIG_LEN_2 14 // Original second SIG = 20 is now devided into 14 for SIG_LEN_2 and 6 for CHIP_ID
++#define CHIP_ID_LEN 6
++#define IMAGE_LEN 10
++#define ADDRESS_LEN 12
++#define FLAG_LEN 2
++#define TOKEN_LEN 20
++#define BOARD_ID_LEN 16
++#define RESERVED_LEN (TAG_LEN - TAG_VER_LEN - SIG_LEN - SIG_LEN_2 - CHIP_ID_LEN - BOARD_ID_LEN - \
++ (4*IMAGE_LEN) - (3*ADDRESS_LEN) - (3*FLAG_LEN) - (2*TOKEN_LEN))
++
++
++// TAG for downloadable image (kernel plus file system)
++typedef struct _FILE_TAG
++{
++ unsigned char tagVersion[TAG_VER_LEN]; // tag version. Will be 2 here.
++ unsigned char signiture_1[SIG_LEN]; // text line for company info
++ unsigned char signiture_2[SIG_LEN_2]; // additional info (can be version number)
++ unsigned char chipId[CHIP_ID_LEN]; // chip id
++ unsigned char boardId[BOARD_ID_LEN]; // board id
++ unsigned char bigEndian[FLAG_LEN]; // if = 1 - big, = 0 - little endia of the host
++ unsigned char totalImageLen[IMAGE_LEN]; // the sum of all the following length
++ unsigned char cfeAddress[ADDRESS_LEN]; // if non zero, cfe starting address
++ unsigned char cfeLen[IMAGE_LEN]; // if non zero, cfe size in clear ASCII text.
++ unsigned char rootfsAddress[ADDRESS_LEN]; // if non zero, filesystem starting address
++ unsigned char rootfsLen[IMAGE_LEN]; // if non zero, filesystem size in clear ASCII text.
++ unsigned char kernelAddress[ADDRESS_LEN]; // if non zero, kernel starting address
++ unsigned char kernelLen[IMAGE_LEN]; // if non zero, kernel size in clear ASCII text.
++ unsigned char dualImage[FLAG_LEN]; // if 1, dual image
++ unsigned char inactiveLen[FLAG_LEN]; // if 1, the image is INACTIVE; if 0, active
++ unsigned char reserved[RESERVED_LEN]; // reserved for later use
++ unsigned char imageValidationToken[TOKEN_LEN];// image validation token - can be crc, md5, sha; for
++ // now will be 4 unsigned char crc
++ unsigned char tagValidationToken[TOKEN_LEN]; // validation token for tag(from signiture_1 to end of // mageValidationToken)
++} FILE_TAG, *PFILE_TAG;
++
++#define CRC32_INIT_VALUE 0xffffffff /* Initial CRC32 checksum value */
++#define CRC_LEN 4
++
++// only included if for bcmTag.exe program
++#ifdef BCMTAG_EXE_USE
++
++static unsigned long Crc32_table[256] = {
++ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
++ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
++ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
++ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
++ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
++ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
++ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
++ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
++ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
++ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
++ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
++ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
++ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
++ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
++ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
++ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
++ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
++ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
++ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
++ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
++ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
++ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
++ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
++ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
++ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
++ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
++ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
++ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
++ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
++ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
++ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
++ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
++ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
++ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
++ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
++ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
++ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
++ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
++ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
++ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
++ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
++ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
++ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
++ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
++ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
++ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
++ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
++ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
++ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
++ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
++ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
++ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
++ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
++ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
++ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
++ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
++ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
++ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
++ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
++ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
++ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
++ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
++ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
++ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
++};
++#endif // BCMTAG_USE
++
++
++#endif // _BCMTAG_H_
++
+diff -urN linux.old/arch/mips/bcm963xx/include/bcmtypes.h linux.dev/arch/mips/bcm963xx/include/bcmtypes.h
+--- linux.old/arch/mips/bcm963xx/include/bcmtypes.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/include/bcmtypes.h 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,163 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope 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.
++:>
++*/
++
++//
++// bcmtypes.h - misc useful typedefs
++//
++#ifndef BCMTYPES_H
++#define BCMTYPES_H
++
++// These are also defined in typedefs.h in the application area, so I need to
++// protect against re-definition.
++
++#ifndef _TYPEDEFS_H_
++typedef unsigned char uint8;
++typedef unsigned short uint16;
++typedef unsigned long uint32;
++typedef signed char int8;
++typedef signed short int16;
++typedef signed long int32;
++#if !defined(__cplusplus)
++typedef int bool;
++#endif
++#endif
++
++typedef unsigned char byte;
++// typedef unsigned long sem_t;
++
++typedef unsigned long HANDLE,*PULONG,DWORD,*PDWORD;
++typedef signed long LONG,*PLONG;
++
++typedef unsigned int *PUINT;
++typedef signed int INT;
++
++typedef unsigned short *PUSHORT;
++typedef signed short SHORT,*PSHORT;
++typedef unsigned short WORD,*PWORD;
++
++typedef unsigned char *PUCHAR;
++typedef signed char *PCHAR;
++
++typedef void *PVOID;
++
++typedef unsigned char BOOLEAN, *PBOOL, *PBOOLEAN;
++
++typedef unsigned char BYTE,*PBYTE;
++
++//#ifndef __GNUC__
++//The following has been defined in Vxworks internally: vxTypesOld.h
++//redefine under vxworks will cause error
++typedef signed int *PINT;
++
++typedef signed char INT8;
++typedef signed short INT16;
++typedef signed long INT32;
++
++typedef unsigned char UINT8;
++typedef unsigned short UINT16;
++typedef unsigned long UINT32;
++
++typedef unsigned char UCHAR;
++typedef unsigned short USHORT;
++typedef unsigned int UINT;
++typedef unsigned long ULONG;
++
++typedef void VOID;
++typedef unsigned char BOOL;
++
++//#endif /* __GNUC__ */
++
++
++// These are also defined in typedefs.h in the application area, so I need to
++// protect against re-definition.
++#ifndef TYPEDEFS_H
++
++// Maximum and minimum values for a signed 16 bit integer.
++#define MAX_INT16 32767
++#define MIN_INT16 -32768
++
++// Useful for true/false return values. This uses the
++// Taligent notation (k for constant).
++typedef enum
++{
++ kFalse = 0,
++ kTrue = 1
++} Bool;
++
++#endif
++
++/* macros to protect against unaligned accesses */
++
++#if 0
++/* first arg is an address, second is a value */
++#define PUT16( a, d ) { \
++ *((byte *)a) = (byte)((d)>>8); \
++ *(((byte *)a)+1) = (byte)(d); \
++}
++
++#define PUT32( a, d ) { \
++ *((byte *)a) = (byte)((d)>>24); \
++ *(((byte *)a)+1) = (byte)((d)>>16); \
++ *(((byte *)a)+2) = (byte)((d)>>8); \
++ *(((byte *)a)+3) = (byte)(d); \
++}
++
++/* first arg is an address, returns a value */
++#define GET16( a ) ( \
++ (*((byte *)a) << 8) | \
++ (*(((byte *)a)+1)) \
++)
++
++#define GET32( a ) ( \
++ (*((byte *)a) << 24) | \
++ (*(((byte *)a)+1) << 16) | \
++ (*(((byte *)a)+2) << 8) | \
++ (*(((byte *)a)+3)) \
++)
++#endif
++
++#ifndef YES
++#define YES 1
++#endif
++
++#ifndef NO
++#define NO 0
++#endif
++
++#ifndef IN
++#define IN
++#endif
++
++#ifndef OUT
++#define OUT
++#endif
++
++#ifndef TRUE
++#define TRUE 1
++#endif
++
++#ifndef FALSE
++#define FALSE 0
++#endif
++
++#define READ32(addr) (*(volatile UINT32 *)((ULONG)&addr))
++#define READ16(addr) (*(volatile UINT16 *)((ULONG)&addr))
++#define READ8(addr) (*(volatile UINT8 *)((ULONG)&addr))
++
++#endif
+diff -urN linux.old/arch/mips/bcm963xx/include/board.h linux.dev/arch/mips/bcm963xx/include/board.h
+--- linux.old/arch/mips/bcm963xx/include/board.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/include/board.h 2006-08-25 01:52:34.000000000 +0200
+@@ -0,0 +1,373 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope 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.
++:>
++*/
++/***********************************************************************/
++/* */
++/* MODULE: board.h */
++/* DATE: 97/02/18 */
++/* PURPOSE: Board specific information. This module should include */
++/* all base device addresses and board specific macros. */
++/* */
++/***********************************************************************/
++#ifndef _BOARD_H
++#define _BOARD_H
++
++/*****************************************************************************/
++/* Misc board definitions */
++/*****************************************************************************/
++
++#define DYING_GASP_API
++
++/*****************************************************************************/
++/* Physical Memory Map */
++/*****************************************************************************/
++
++#define PHYS_DRAM_BASE 0x00000000 /* Dynamic RAM Base */
++#define PHYS_FLASH_BASE 0x1FC00000 /* Flash Memory */
++
++/*****************************************************************************/
++/* Note that the addresses above are physical addresses and that programs */
++/* have to use converted addresses defined below: */
++/*****************************************************************************/
++#define DRAM_BASE (0x80000000 | PHYS_DRAM_BASE) /* cached DRAM */
++#define DRAM_BASE_NOCACHE (0xA0000000 | PHYS_DRAM_BASE) /* uncached DRAM */
++#define FLASH_BASE (0xA0000000 | PHYS_FLASH_BASE) /* uncached Flash */
++
++/*****************************************************************************/
++/* Select the PLL value to get the desired CPU clock frequency. */
++/* */
++/* */
++/*****************************************************************************/
++#define FPERIPH 50000000
++
++#define ONEK 1024
++#define BLK64K (64*ONEK)
++#define FLASH45_BLKS_BOOT_ROM 1
++#define FLASH45_LENGTH_BOOT_ROM (FLASH45_BLKS_BOOT_ROM * BLK64K)
++#define FLASH_RESERVED_AT_END (64*ONEK) /*reserved for PSI, scratch pad*/
++
++/*****************************************************************************/
++/* Note that the addresses above are physical addresses and that programs */
++/* have to use converted addresses defined below: */
++/*****************************************************************************/
++#define DRAM_BASE (0x80000000 | PHYS_DRAM_BASE) /* cached DRAM */
++#define DRAM_BASE_NOCACHE (0xA0000000 | PHYS_DRAM_BASE) /* uncached DRAM */
++#define FLASH_BASE (0xA0000000 | PHYS_FLASH_BASE) /* uncached Flash */
++
++/*****************************************************************************/
++/* Select the PLL value to get the desired CPU clock frequency. */
++/* */
++/* */
++/*****************************************************************************/
++#define FPERIPH 50000000
++
++#define SDRAM_TYPE_ADDRESS_OFFSET 16
++#define NVRAM_DATA_OFFSET 0x0580
++#define NVRAM_DATA_ID 0x0f1e2d3c
++#define BOARD_SDRAM_TYPE *(unsigned long *) \
++ (FLASH_BASE + SDRAM_TYPE_ADDRESS_OFFSET)
++
++#define ONEK 1024
++#define BLK64K (64*ONEK)
++
++// nvram and psi flash definitions for 45
++#define FLASH45_LENGTH_NVRAM ONEK // 1k nvram
++#define NVRAM_PSI_DEFAULT 24 // default psi in K byes
++
++/*****************************************************************************/
++/* NVRAM Offset and definition */
++/*****************************************************************************/
++
++#define NVRAM_VERSION_NUMBER 2
++#define NVRAM_VERSION_NUMBER_ADDRESS 0
++
++#define NVRAM_BOOTLINE_LEN 256
++#define NVRAM_BOARD_ID_STRING_LEN 16
++#define NVRAM_MAC_ADDRESS_LEN 6
++#define NVRAM_MAC_COUNT_MAX 32
++
++/*****************************************************************************/
++/* Misc Offsets */
++/*****************************************************************************/
++
++#define CFE_VERSION_OFFSET 0x0570
++#define CFE_VERSION_MARK_SIZE 5
++#define CFE_VERSION_SIZE 5
++
++typedef struct
++{
++ unsigned long ulVersion;
++ char szBootline[NVRAM_BOOTLINE_LEN];
++ char szBoardId[NVRAM_BOARD_ID_STRING_LEN];
++ unsigned long ulReserved1[2];
++ unsigned long ulNumMacAddrs;
++ unsigned char ucaBaseMacAddr[NVRAM_MAC_ADDRESS_LEN];
++ char chReserved[2];
++ unsigned long ulCheckSum;
++} NVRAM_DATA, *PNVRAM_DATA;
++
++
++/*****************************************************************************/
++/* board ioctl calls for flash, led and some other utilities */
++/*****************************************************************************/
++
++
++/* Defines. for board driver */
++#define BOARD_IOCTL_MAGIC 'B'
++#define BOARD_DRV_MAJOR 206
++
++#define MAC_ADDRESS_ANY (unsigned long) -1
++
++#define BOARD_IOCTL_FLASH_INIT \
++ _IOWR(BOARD_IOCTL_MAGIC, 0, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_FLASH_WRITE \
++ _IOWR(BOARD_IOCTL_MAGIC, 1, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_FLASH_READ \
++ _IOWR(BOARD_IOCTL_MAGIC, 2, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_GET_NR_PAGES \
++ _IOWR(BOARD_IOCTL_MAGIC, 3, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_DUMP_ADDR \
++ _IOWR(BOARD_IOCTL_MAGIC, 4, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_SET_MEMORY \
++ _IOWR(BOARD_IOCTL_MAGIC, 5, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_MIPS_SOFT_RESET \
++ _IOWR(BOARD_IOCTL_MAGIC, 6, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_LED_CTRL \
++ _IOWR(BOARD_IOCTL_MAGIC, 7, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_GET_ID \
++ _IOWR(BOARD_IOCTL_MAGIC, 8, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_GET_MAC_ADDRESS \
++ _IOWR(BOARD_IOCTL_MAGIC, 9, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_RELEASE_MAC_ADDRESS \
++ _IOWR(BOARD_IOCTL_MAGIC, 10, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_GET_PSI_SIZE \
++ _IOWR(BOARD_IOCTL_MAGIC, 11, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_GET_SDRAM_SIZE \
++ _IOWR(BOARD_IOCTL_MAGIC, 12, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_SET_MONITOR_FD \
++ _IOWR(BOARD_IOCTL_MAGIC, 13, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_WAKEUP_MONITOR_TASK \
++ _IOWR(BOARD_IOCTL_MAGIC, 14, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_GET_BOOTLINE \
++ _IOWR(BOARD_IOCTL_MAGIC, 15, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_SET_BOOTLINE \
++ _IOWR(BOARD_IOCTL_MAGIC, 16, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_GET_BASE_MAC_ADDRESS \
++ _IOWR(BOARD_IOCTL_MAGIC, 17, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_GET_CHIP_ID \
++ _IOWR(BOARD_IOCTL_MAGIC, 18, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_GET_NUM_ENET \
++ _IOWR(BOARD_IOCTL_MAGIC, 19, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_GET_CFE_VER \
++ _IOWR(BOARD_IOCTL_MAGIC, 20, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_GET_ENET_CFG \
++ _IOWR(BOARD_IOCTL_MAGIC, 21, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_GET_WLAN_ANT_INUSE \
++ _IOWR(BOARD_IOCTL_MAGIC, 22, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_SET_TRIGGER_EVENT \
++ _IOWR(BOARD_IOCTL_MAGIC, 23, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_GET_TRIGGER_EVENT \
++ _IOWR(BOARD_IOCTL_MAGIC, 24, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_UNSET_TRIGGER_EVENT \
++ _IOWR(BOARD_IOCTL_MAGIC, 25, BOARD_IOCTL_PARMS)
++
++#define BOARD_IOCTL_SET_SES_LED \
++ _IOWR(BOARD_IOCTL_MAGIC, 26, BOARD_IOCTL_PARMS)
++
++//<<JUNHON, 2004/09/15, get reset button status , tim hou , 05/04/12
++#define RESET_BUTTON_UP 1
++#define RESET_BUTTON_PRESSDOWN 0
++#define BOARD_IOCTL_GET_RESETHOLD \
++ _IOWR(BOARD_IOCTL_MAGIC, 27, BOARD_IOCTL_PARMS)
++//>>JUNHON, 2004/09/15
++
++// for the action in BOARD_IOCTL_PARMS for flash operation
++typedef enum
++{
++ PERSISTENT,
++ NVRAM,
++ BCM_IMAGE_CFE,
++ BCM_IMAGE_FS,
++ BCM_IMAGE_KERNEL,
++ BCM_IMAGE_WHOLE,
++ SCRATCH_PAD,
++ FLASH_SIZE,
++} BOARD_IOCTL_ACTION;
++
++
++typedef struct boardIoctParms
++{
++ char *string;
++ char *buf;
++ int strLen;
++ int offset;
++ BOARD_IOCTL_ACTION action; /* flash read/write: nvram, persistent, bcm image */
++ int result;
++} BOARD_IOCTL_PARMS;
++
++
++// LED defines
++typedef enum
++{
++ kLedAdsl,
++ kLedWireless,
++ kLedUsb,
++ kLedHpna,
++ kLedWanData,
++ kLedPPP,
++ kLedVoip,
++ kLedSes,
++ kLedLan,
++ kLedSelfTest,
++ kLedEnd, // NOTE: Insert the new led name before this one. Alway stay at the end.
++} BOARD_LED_NAME;
++
++typedef enum
++{
++ kLedStateOff, /* turn led off */
++ kLedStateOn, /* turn led on */
++ kLedStateFail, /* turn led on red */
++ kLedStateBlinkOnce, /* blink once, ~100ms and ignore the same call during the 100ms period */
++ kLedStateSlowBlinkContinues, /* slow blink continues at ~600ms interval */
++ kLedStateFastBlinkContinues, /* fast blink continues at ~200ms interval */
++} BOARD_LED_STATE;
++
++
++// virtual and physical map pair defined in board.c
++typedef struct ledmappair
++{
++ BOARD_LED_NAME ledName; // virtual led name
++ BOARD_LED_STATE ledInitState; // initial led state when the board boots.
++ unsigned short ledMask; // physical GPIO pin mask
++ unsigned short ledActiveLow; // reset bit to turn on LED
++ unsigned short ledMaskFail; // physical GPIO pin mask for state failure
++ unsigned short ledActiveLowFail;// reset bit to turn on LED
++} LED_MAP_PAIR, *PLED_MAP_PAIR;
++
++typedef void (*HANDLE_LED_FUNC)(BOARD_LED_NAME ledName, BOARD_LED_STATE ledState);
++
++/* Flash storage address information that is determined by the flash driver. */
++typedef struct flashaddrinfo
++{
++ int flash_persistent_start_blk;
++ int flash_persistent_number_blk;
++ int flash_persistent_length;
++ unsigned long flash_persistent_blk_offset;
++ int flash_scratch_pad_start_blk; // start before psi (SP_BUF_LEN)
++ int flash_scratch_pad_number_blk;
++ int flash_scratch_pad_length;
++ unsigned long flash_scratch_pad_blk_offset;
++ int flash_nvram_start_blk;
++ int flash_nvram_number_blk;
++ int flash_nvram_length;
++ unsigned long flash_nvram_blk_offset;
++} FLASH_ADDR_INFO, *PFLASH_ADDR_INFO;
++
++// scratch pad defines
++/* SP - Persisten Scratch Pad format:
++ sp header : 32 bytes
++ tokenId-1 : 8 bytes
++ tokenId-1 len : 4 bytes
++ tokenId-1 data
++ ....
++ tokenId-n : 8 bytes
++ tokenId-n len : 4 bytes
++ tokenId-n data
++*/
++
++#define MAGIC_NUM_LEN 8
++#define MAGIC_NUMBER "gOGoBrCm"
++#define TOKEN_NAME_LEN 16
++#define SP_VERSION 1
++#define SP_MAX_LEN 8 * 1024 // 8k buf before psi
++#define SP_RESERVERD 16
++
++typedef struct _SP_HEADER
++{
++ char SPMagicNum[MAGIC_NUM_LEN]; // 8 bytes of magic number
++ int SPVersion; // version number
++ int SPUsedLen; // used sp len
++ char SPReserved[SP_RESERVERD]; // reservied, total 32 bytes
++} SP_HEADER, *PSP_HEADER;
++
++typedef struct _TOKEN_DEF
++{
++ char tokenName[TOKEN_NAME_LEN];
++ int tokenLen;
++} SP_TOKEN, *PSP_TOKEN;
++
++
++/*****************************************************************************/
++/* Function Prototypes */
++/*****************************************************************************/
++#if !defined(__ASM_ASM_H)
++void dumpaddr( unsigned char *pAddr, int nLen );
++
++int kerSysNvRamGet(char *string, int strLen, int offset);
++int kerSysNvRamSet(char *string, int strLen, int offset);
++int kerSysPersistentGet(char *string, int strLen, int offset);
++int kerSysPersistentSet(char *string, int strLen, int offset);
++int kerSysScratchPadGet(char *tokName, char *tokBuf, int tokLen);
++int kerSysScratchPadSet(char *tokName, char *tokBuf, int tokLen);
++int kerSysBcmImageSet( int flash_start_addr, char *string, int size);
++int kerSysGetMacAddress( unsigned char *pucaAddr, unsigned long ulId );
++int kerSysReleaseMacAddress( unsigned char *pucaAddr );
++int kerSysGetSdramSize( void );
++void kerSysGetBootline(char *string, int strLen);
++void kerSysSetBootline(char *string, int strLen);
++void kerSysMipsSoftReset(void);
++void kerSysLedCtrl(BOARD_LED_NAME, BOARD_LED_STATE);
++void kerSysLedRegisterHwHandler( BOARD_LED_NAME, HANDLE_LED_FUNC, int );
++int kerSysFlashSizeGet(void);
++void kerSysRegisterDyingGaspHandler(char *devname, void *cbfn, void *context);
++void kerSysDeregisterDyingGaspHandler(char *devname);
++void kerSysWakeupMonitorTask( void );
++#endif
++
++#define BOOT_CFE 0
++#define BOOT_REDBOOT 1
++
++extern int boot_loader_type;
++
++#endif /* _BOARD_H */
++
+diff -urN linux.old/arch/mips/bcm963xx/int-handler.S linux.dev/arch/mips/bcm963xx/int-handler.S
+--- linux.old/arch/mips/bcm963xx/int-handler.S 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/int-handler.S 2006-08-25 02:13:33.000000000 +0200
+@@ -0,0 +1,59 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope 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.
++:>
++*/
++/*
++ * Generic interrupt handler for Broadcom MIPS boards
++ */
++
++#include <linux/config.h>
++
++#include <asm/asm.h>
++#include <asm/mipsregs.h>
++#include <asm/regdef.h>
++#include <asm/stackframe.h>
++
++/*
++ * MIPS IRQ Source
++ * -------- ------
++ * 0 Software (ignored)
++ * 1 Software (ignored)
++ * 2 Combined hardware interrupt (hw0)
++ * 3 Hardware
++ * 4 Hardware
++ * 5 Hardware
++ * 6 Hardware
++ * 7 R4k timer
++ */
++
++ .text
++ .set noreorder
++ .set noat
++ .align 5
++ NESTED(brcmIRQ, PT_SIZE, sp)
++ SAVE_ALL
++ CLI
++ .set noreorder
++ .set at
++
++ jal plat_irq_dispatch
++ move a0, sp
++
++ j ret_from_irq
++ nop
++
++ END(brcmIRQ)
+diff -urN linux.old/arch/mips/bcm963xx/irq.c linux.dev/arch/mips/bcm963xx/irq.c
+--- linux.old/arch/mips/bcm963xx/irq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/irq.c 2006-08-25 03:54:34.000000000 +0200
+@@ -0,0 +1,256 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope 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.
++:>
++*/
++/*
++ * Interrupt control functions for Broadcom 963xx MIPS boards
++ */
++
++#include <asm/atomic.h>
++
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++
++#include <asm/irq.h>
++#include <asm/mipsregs.h>
++#include <asm/addrspace.h>
++#include <asm/signal.h>
++#include <bcm_map_part.h>
++#include <bcm_intr.h>
++
++static void irq_dispatch_int(struct pt_regs *regs)
++{
++ unsigned int pendingIrqs;
++ static unsigned int irqBit;
++ static unsigned int isrNumber = 31;
++
++ pendingIrqs = PERF->IrqStatus & PERF->IrqMask;
++ if (!pendingIrqs) {
++ return;
++ }
++
++ while (1) {
++ irqBit <<= 1;
++ isrNumber++;
++ if (isrNumber == 32) {
++ isrNumber = 0;
++ irqBit = 0x1;
++ }
++ if (pendingIrqs & irqBit) {
++ PERF->IrqMask &= ~irqBit; // mask
++ do_IRQ(isrNumber + INTERNAL_ISR_TABLE_OFFSET, regs);
++ break;
++ }
++ }
++}
++
++static void irq_dispatch_ext(uint32 irq, struct pt_regs *regs)
++{
++ if (!(PERF->ExtIrqCfg & (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)))) {
++ printk("**** Ext IRQ mask. Should not dispatch ****\n");
++ }
++ /* disable and clear interrupt in the controller */
++ PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT));
++ PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
++ do_IRQ(irq, regs);
++}
++
++
++extern void brcm_timer_interrupt(struct pt_regs *regs);
++
++asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++{
++ u32 cause;
++ while((cause = (read_c0_cause()& CAUSEF_IP))) {
++ if (cause & CAUSEF_IP7)
++ brcm_timer_interrupt(regs);
++ else if (cause & CAUSEF_IP2)
++ irq_dispatch_int(regs);
++ else if (cause & CAUSEF_IP3)
++ irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_0, regs);
++ else if (cause & CAUSEF_IP4)
++ irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_1, regs);
++ else if (cause & CAUSEF_IP5)
++ irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_2, regs);
++ else if (cause & CAUSEF_IP6)
++ irq_dispatch_ext(INTERRUPT_ID_EXTERNAL_3, regs);
++ local_irq_disable();
++ }
++}
++
++
++void enable_brcm_irq(unsigned int irq)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++ if( irq >= INTERNAL_ISR_TABLE_OFFSET ) {
++ PERF->IrqMask |= (1 << (irq - INTERNAL_ISR_TABLE_OFFSET));
++ }
++ else if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) {
++ /* enable and clear interrupt in the controller */
++ PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT));
++ PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
++ }
++ local_irq_restore(flags);
++}
++
++void disable_brcm_irq(unsigned int irq)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++ if( irq >= INTERNAL_ISR_TABLE_OFFSET ) {
++ PERF->IrqMask &= ~(1 << (irq - INTERNAL_ISR_TABLE_OFFSET));
++ }
++ else if (irq >= INTERRUPT_ID_EXTERNAL_0 && irq <= INTERRUPT_ID_EXTERNAL_3) {
++ /* disable interrupt in the controller */
++ PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT));
++ }
++ local_irq_restore(flags);
++}
++
++void ack_brcm_irq(unsigned int irq)
++{
++ /* Already done in brcm_irq_dispatch */
++}
++
++unsigned int startup_brcm_irq(unsigned int irq)
++{
++ enable_brcm_irq(irq);
++
++ return 0; /* never anything pending */
++}
++
++unsigned int startup_brcm_none(unsigned int irq)
++{
++ return 0;
++}
++
++void end_brcm_irq(unsigned int irq)
++{
++ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
++ enable_brcm_irq(irq);
++}
++
++void end_brcm_none(unsigned int irq)
++{
++}
++
++static struct hw_interrupt_type brcm_irq_type = {
++ .typename = "MIPS",
++ .startup = startup_brcm_irq,
++ .shutdown = disable_brcm_irq,
++ .enable = enable_brcm_irq,
++ .disable = disable_brcm_irq,
++ .ack = ack_brcm_irq,
++ .end = end_brcm_irq,
++ .set_affinity = NULL
++};
++
++static struct hw_interrupt_type brcm_irq_no_end_type = {
++ .typename = "MIPS",
++ .startup = startup_brcm_none,
++ .shutdown = disable_brcm_irq,
++ .enable = enable_brcm_irq,
++ .disable = disable_brcm_irq,
++ .ack = ack_brcm_irq,
++ .end = end_brcm_none,
++ .set_affinity = NULL
++};
++
++void __init arch_init_irq(void)
++{
++ int i;
++
++ clear_c0_status(ST0_BEV);
++ change_c0_status(ST0_IM, (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4));
++
++ for (i = 0; i < NR_IRQS; i++) {
++ irq_desc[i].status = IRQ_DISABLED;
++ irq_desc[i].action = 0;
++ irq_desc[i].depth = 1;
++ irq_desc[i].handler = &brcm_irq_type;
++ }
++}
++
++int request_external_irq(unsigned int irq,
++ FN_HANDLER handler,
++ unsigned long irqflags,
++ const char * devname,
++ void *dev_id)
++{
++ unsigned long flags;
++
++ local_irq_save(flags);
++
++ PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_CLEAR_SHFT)); // Clear
++ PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_MASK_SHFT)); // Mask
++ PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_INSENS_SHFT)); // Edge insesnsitive
++ PERF->ExtIrqCfg |= (1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_LEVEL_SHFT)); // Level triggered
++ PERF->ExtIrqCfg &= ~(1 << (irq - INTERRUPT_ID_EXTERNAL_0 + EI_SENSE_SHFT)); // Low level
++
++ local_irq_restore(flags);
++
++ return( request_irq(irq, handler, irqflags, devname, dev_id) );
++}
++
++/* VxWorks compatibility function(s). */
++
++unsigned int BcmHalMapInterrupt(FN_HANDLER pfunc, unsigned int param,
++ unsigned int interruptId)
++{
++ int nRet = -1;
++ char *devname;
++
++ devname = kmalloc(16, GFP_KERNEL);
++ if (devname)
++ sprintf( devname, "brcm_%d", interruptId );
++
++ /* Set the IRQ description to not automatically enable the interrupt at
++ * the end of an ISR. The driver that handles the interrupt must
++ * explicitly call BcmHalInterruptEnable or enable_brcm_irq. This behavior
++ * is consistent with interrupt handling on VxWorks.
++ */
++ irq_desc[interruptId].handler = &brcm_irq_no_end_type;
++
++ if( interruptId >= INTERNAL_ISR_TABLE_OFFSET )
++ {
++ nRet = request_irq( interruptId, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT,
++ devname, (void *) param );
++ }
++ else if (interruptId >= INTERRUPT_ID_EXTERNAL_0 && interruptId <= INTERRUPT_ID_EXTERNAL_3)
++ {
++ nRet = request_external_irq( interruptId, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT,
++ devname, (void *) param );
++ }
++
++ return( nRet );
++}
++
++
++EXPORT_SYMBOL(enable_brcm_irq);
++EXPORT_SYMBOL(disable_brcm_irq);
++EXPORT_SYMBOL(request_external_irq);
++EXPORT_SYMBOL(BcmHalMapInterrupt);
++
+diff -urN linux.old/arch/mips/bcm963xx/Kconfig linux.dev/arch/mips/bcm963xx/Kconfig
+--- linux.old/arch/mips/bcm963xx/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/Kconfig 2006-08-25 01:22:39.000000000 +0200
+@@ -0,0 +1,138 @@
++# Kernel and Driver configuration for Broadcom Commengine ADSL board
++choice
++ prompt "Broadcom Commengine ADSL board"
++ depends on MIPS_BRCM
++ default BCM96345
++ help
++ Select different Broadcom ADSL board
++
++config BCM96338
++ bool "96338 ADSL board"
++ select DMA_NONCOHERENT
++ select HW_HAS_PCI
++
++config BCM96345
++ bool "96345 ADSL board"
++ select DMA_NONCOHERENT
++ select HW_HAS_PCI
++
++config BCM96348
++ bool "96348 ADSL board"
++ select DMA_NONCOHERENT
++ select HW_HAS_PCI
++
++endchoice
++
++config BCM_BOARD
++ bool "Support for Broadcom Board"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_SERIAL
++ bool "Support for Serial Port"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_ENET
++ tristate "Support for Ethernet"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_USB
++ tristate "Support for USB"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_WLAN
++ tristate "Support for Wireless"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_PCI
++ bool "Support for PCI"
++ depends on BCM96338 || BCM96345 || BCM96348
++ select PCI
++
++config BCM_ATMAPI
++ tristate "Support for ATM"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_ATMTEST
++ tristate "Support for ATM Diagnostic"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_ADSL
++ tristate "Support for ADSL"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_ENDPOINT
++ tristate "Support for VOICE"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_PROCFS
++ tristate "Support for PROCFS"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_VDSL
++ tristate "Support for VDSL"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_SECURITY
++ tristate "Support for SECURITY"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_HPNA
++ tristate "Support for HPNA"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_BOARD_IMPL
++ int "Implementation index for ADSL Board"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_SERIAL_IMPL
++ int "Implementation index for Serial"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_ENET_IMPL
++ int "Implementation index for Ethernet"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_USB_IMPL
++ int "Implementation index for USB"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_WLAN_IMPL
++ int "Implementation index for WIRELESS"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_ATMAPI_IMPL
++ int "Implementation index for ATM"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_ATMTEST_IMPL
++ int "Implementation index for ATM Diagnostic"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_BLAA_IMPL
++ int "Implementation index for BLAA"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_ADSL_IMPL
++ int "Implementation index for ADSL"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_ENDPOINT_IMPL
++ int "Implementation index for VOICE"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_PROCFS_IMPL
++ int "Implementation index for PROCFS"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_VDSL_IMPL
++ int "Implementation index for VDSL"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_SECURITY_IMPL
++ int "Implementation index for SECURITY"
++ depends on BCM96338 || BCM96345 || BCM96348
++
++config BCM_HPNA_IMPL
++ int "Implementation index for HPNA"
++ depends on BCM96338 || BCM96345 || BCM96348
++
+diff -urN linux.old/arch/mips/bcm963xx/Makefile linux.dev/arch/mips/bcm963xx/Makefile
+--- linux.old/arch/mips/bcm963xx/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/Makefile 2006-08-25 02:04:27.000000000 +0200
+@@ -0,0 +1,23 @@
++#
++# Makefile for generic Broadcom MIPS boards
++#
++# Copyright (C) 2004 Broadcom Corporation
++#
++obj-y := irq.o prom.o setup.o time.o ser_init.o bcm63xx_led.o board.o boardparms.o int-handler.o
++
++SRCBASE := $(TOPDIR)
++EXTRA_CFLAGS += -I$(SRCBASE)/include
++#EXTRA_CFLAGS += -I$(INC_ADSLDRV_PATH) -DDBG
++EXTRA_CFLAGS += -I$(INC_ADSLDRV_PATH)
++
++
++ifeq "$(ADSL)" "ANNEX_B"
++EXTRA_CFLAGS += -DADSL_ANNEXB
++endif
++ifeq "$(ADSL)" "SADSL"
++EXTRA_CFLAGS += -DADSL_SADSL
++endif
++ifeq "$(ADSL)" "ANNEX_C"
++EXTRA_CFLAGS += -DADSL_ANNEXC
++endif
++
+diff -urN linux-2.6.17/arch/mips/bcm963xx/prom.c linux-2.6.17-brcm63xx/arch/mips/bcm963xx/prom.c
+--- linux-2.6.17/arch/mips/bcm963xx/prom.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-brcm63xx/arch/mips/bcm963xx/prom.c 2006-08-29 07:10:10.000000000 +0200
+@@ -0,0 +1,143 @@
++/*
++<:copyright-gpl
++ Copyright 2004 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope 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.
++:>
++*/
++/*
++ * prom.c: PROM library initialization code.
++ *
++ */
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/bootmem.h>
++#include <linux/blkdev.h>
++#include <asm/addrspace.h>
++#include <asm/bootinfo.h>
++#include <asm/cpu.h>
++#include <asm/time.h>
++
++#include <bcm_map_part.h>
++#include <board.h>
++#include "boardparms.h"
++#include "softdsl/AdslCoreDefs.h"
++
++
++//char arcs_cmdline[CL_SIZE] __initdata = {0};
++/* inv_xde */
++int boot_loader_type;
++int prom_argc;
++char **prom_argv, **prom_envp;
++
++extern int do_syslog(int, char *, int);
++extern void serial_init(void);
++extern void __init InitNvramInfo( void );
++extern void kerSysFlashInit( void );
++extern unsigned long get_nvram_start_addr(void);
++void __init create_root_nfs_cmdline( char *cmdline );
++
++#define MACH_BCM MACH_BCM96348
++
++const char *get_system_type(void)
++{
++ /*PNVRAM_DATA pNvramData = (PNVRAM_DATA) get_nvram_start_addr();
++
++ return( pNvramData->szBoardId );*/
++ return "brcm63xx";
++}
++
++unsigned long getMemorySize(void)
++{
++ unsigned long ulSdramType = BOARD_SDRAM_TYPE;
++
++ unsigned long ulSdramSize;
++
++ switch( ulSdramType )
++ {
++ case BP_MEMORY_16MB_1_CHIP:
++ case BP_MEMORY_16MB_2_CHIP:
++ ulSdramSize = 16 * 1024 * 1024;
++ break;
++ case BP_MEMORY_32MB_1_CHIP:
++ case BP_MEMORY_32MB_2_CHIP:
++ ulSdramSize = 32 * 1024 * 1024;
++ break;
++ case BP_MEMORY_64MB_2_CHIP:
++ ulSdramSize = 64 * 1024 * 1024;
++ break;
++ default:
++ ulSdramSize = 8 * 1024 * 1024;
++ break;
++ }
++ if (boot_loader_type == BOOT_CFE)
++ return ulSdramSize;
++ else
++ // assume that there is one contiguous memory map
++ return boot_mem_map.map[0].size;
++}
++
++/* --------------------------------------------------------------------------
++ Name: prom_init
++ -------------------------------------------------------------------------- */
++void __init prom_init(void)
++{
++ extern ulong r4k_interval;
++
++ serial_init();
++
++ prom_argc = fw_arg0;
++ prom_argv = (char **) fw_arg1;
++ prom_envp = (char **) fw_arg2;
++
++ if ((prom_argv > 0x80000000) && (prom_argv < 0x82000000)) {
++ strncpy(arcs_cmdline, prom_argv[1], CL_SIZE);
++ }
++
++ if (strncmp(arcs_cmdline, "boot_loader=RedBoot", 19) != 0) {
++ boot_loader_type = BOOT_CFE;
++ }
++ else {
++ boot_loader_type = BOOT_REDBOOT;
++ }
++
++ do_syslog(8, NULL, 8);
++
++ printk( "%s prom init\n", get_system_type() );
++
++ PERF->IrqMask = 0;
++
++ arcs_cmdline[0] = '\0';
++
++ if (boot_loader_type == BOOT_CFE)
++ add_memory_region(0, (getMemorySize() - ADSL_SDRAM_IMAGE_SIZE), BOOT_MEM_RAM);
++ else
++ add_memory_region(0, (0x01000000 - ADSL_SDRAM_IMAGE_SIZE), BOOT_MEM_RAM);
++
++ mips_machgroup = MACH_GROUP_BRCM;
++ mips_machtype = MACH_BCM;
++
++ BpSetBoardId("96348GW-10");
++}
++
++/* --------------------------------------------------------------------------
++ Name: prom_free_prom_memory
++Abstract:
++ -------------------------------------------------------------------------- */
++void __init prom_free_prom_memory(void)
++{
++
++}
++
+diff -urN linux.old/arch/mips/bcm963xx/ser_init.c linux.dev/arch/mips/bcm963xx/ser_init.c
+--- linux.old/arch/mips/bcm963xx/ser_init.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/ser_init.c 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,180 @@
++/*
++<:copyright-gpl
++ Copyright 2004 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope 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.
++:>
++*/
++/*
++ * Broadcom bcm63xx serial port initialization, also prepare for printk
++ * by registering with console_init
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/console.h>
++#include <linux/sched.h>
++
++#include <asm/addrspace.h>
++#include <asm/irq.h>
++#include <asm/reboot.h>
++#include <asm/gdb-stub.h>
++#include <asm/mc146818rtc.h>
++
++#include <bcm_map_part.h>
++#include <board.h>
++
++#define SER63XX_DEFAULT_BAUD 115200
++#define BD_BCM63XX_TIMER_CLOCK_INPUT (FPERIPH)
++#define stUart ((volatile Uart * const) UART_BASE)
++
++// Transmit interrupts
++#define TXINT (TXFIFOEMT | TXUNDERR | TXOVFERR)
++// Receive interrupts
++#define RXINT (RXFIFONE | RXOVFERR)
++
++/* --------------------------------------------------------------------------
++ Name: serial_init
++ Purpose: Initalize the UART
++-------------------------------------------------------------------------- */
++void __init serial_init(void)
++{
++ UINT32 tmpVal = SER63XX_DEFAULT_BAUD;
++ ULONG clockFreqHz;
++
++#if defined(CONFIG_BCM96345)
++ // Make sure clock is ticking
++ PERF->blkEnables |= UART_CLK_EN;
++#endif
++
++ /* Dissable channel's receiver and transmitter. */
++ stUart->control &= ~(BRGEN|TXEN|RXEN);
++
++ /*--------------------------------------------------------------------*/
++ /* Write the table value to the clock select register. */
++ /* DPullen - this is the equation to use: */
++ /* value = clockFreqHz / baud / 32-1; */
++ /* (snmod) Actually you should also take into account any necessary */
++ /* rounding. Divide by 16, look at lsb, if 0, divide by 2 */
++ /* and subtract 1. If 1, just divide by 2 */
++ /*--------------------------------------------------------------------*/
++ clockFreqHz = BD_BCM63XX_TIMER_CLOCK_INPUT;
++ tmpVal = (clockFreqHz / tmpVal) / 16;
++ if( tmpVal & 0x01 )
++ tmpVal /= 2; //Rounding up, so sub is already accounted for
++ else
++ tmpVal = (tmpVal / 2) - 1; // Rounding down so we must sub 1
++ stUart->baudword = tmpVal;
++
++ /* Finally, re-enable the transmitter and receiver. */
++ stUart->control |= (BRGEN|TXEN|RXEN);
++
++ stUart->config = (BITS8SYM | ONESTOP);
++ // Set the FIFO interrupt depth ... stUart->fifocfg = 0xAA;
++ stUart->fifoctl = RSTTXFIFOS | RSTRXFIFOS;
++ stUart->intMask = 0;
++ stUart->intMask = RXINT | TXINT;
++}
++
++
++/* prom_putc()
++ * Output a character to the UART
++ */
++void prom_putc(char c)
++{
++ /* Wait for Tx uffer to empty */
++ while (! (READ16(stUart->intStatus) & TXFIFOEMT));
++ /* Send character */
++ stUart->Data = c;
++}
++
++/* prom_puts()
++ * Write a string to the UART
++ */
++void prom_puts(const char *s)
++{
++ while (*s) {
++ if (*s == '\n') {
++ prom_putc('\r');
++ }
++ prom_putc(*s++);
++ }
++}
++
++
++/* prom_getc_nowait()
++ * Returns a character from the UART
++ * Returns -1 if no characters available or corrupted
++ */
++int prom_getc_nowait(void)
++{
++ uint16 uStatus;
++ int cData = -1;
++
++ uStatus = READ16(stUart->intStatus);
++
++ if (uStatus & RXFIFONE) { /* Do we have a character? */
++ cData = READ16(stUart->Data) & 0xff; /* Read character */
++ if (uStatus & (RXFRAMERR | RXPARERR)) { /* If we got an error, throw it away */
++ cData = -1;
++ }
++ }
++
++ return cData;
++}
++
++/* prom_getc()
++ * Returns a charcter from the serial port
++ * Will block until it receives a valid character
++*/
++char prom_getc(void)
++{
++ int cData = -1;
++
++ /* Loop until we get a valid character */
++ while(cData == -1) {
++ cData = prom_getc_nowait();
++ }
++ return (char) cData;
++}
++
++/* prom_testc()
++ * Returns 0 if no characters available
++ */
++int prom_testc(void)
++{
++ uint16 uStatus;
++
++ uStatus = READ16(stUart->intStatus);
++
++ return (uStatus & RXFIFONE);
++}
++
++#if defined (CONFIG_REMOTE_DEBUG)
++/* Prevent other code from writing to the serial port */
++void _putc(char c) { }
++void _puts(const char *ptr) { }
++#else
++/* Low level outputs call prom routines */
++void _putc(char c) {
++ prom_putc(c);
++}
++void _puts(const char *ptr) {
++ prom_puts(ptr);
++}
++#endif
+diff -urN linux.old/arch/mips/bcm963xx/setup.c linux.dev/arch/mips/bcm963xx/setup.c
+--- linux.old/arch/mips/bcm963xx/setup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/setup.c 2006-08-25 02:26:58.000000000 +0200
+@@ -0,0 +1,525 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope 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.
++:>
++*/
++/*
++ * Generic setup routines for Broadcom 963xx MIPS boards
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/kdev_t.h>
++#include <linux/types.h>
++#include <linux/console.h>
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/pm.h>
++
++#include <asm/addrspace.h>
++#include <asm/bcache.h>
++#include <asm/irq.h>
++#include <asm/time.h>
++#include <asm/reboot.h>
++#include <asm/gdb-stub.h>
++
++extern void brcm_time_init(void);
++extern void brcm_timer_setup(struct irqaction *irq);
++extern unsigned long getMemorySize(void);
++
++#if defined(CONFIG_BCM96348) && defined(CONFIG_PCI)
++#include <linux/pci.h>
++#include <linux/delay.h>
++#include <bcm_map_part.h>
++#include <bcmpci.h>
++
++static volatile MpiRegisters * mpi = (MpiRegisters *)(MPI_BASE);
++#endif
++
++/* This function should be in a board specific directory. For now,
++ * assume that all boards that include this file use a Broadcom chip
++ * with a soft reset bit in the PLL control register.
++ */
++static void brcm_machine_restart(char *command)
++{
++ const unsigned long ulSoftReset = 0x00000001;
++ unsigned long *pulPllCtrl = (unsigned long *) 0xfffe0008;
++ *pulPllCtrl |= ulSoftReset;
++}
++
++static void brcm_machine_halt(void)
++{
++ printk("System halted\n");
++ while (1);
++}
++
++#if defined(CONFIG_BCM96348) && defined(CONFIG_PCI)
++
++static void mpi_SetLocalPciConfigReg(uint32 reg, uint32 value)
++{
++ /* write index then value */
++ mpi->pcicfgcntrl = PCI_CFG_REG_WRITE_EN + reg;;
++ mpi->pcicfgdata = value;
++}
++
++static uint32 mpi_GetLocalPciConfigReg(uint32 reg)
++{
++ /* write index then get value */
++ mpi->pcicfgcntrl = PCI_CFG_REG_WRITE_EN + reg;;
++ return mpi->pcicfgdata;
++}
++
++/*
++ * mpi_ResetPcCard: Set/Reset the PcCard
++ */
++static void mpi_ResetPcCard(int cardtype, BOOL bReset)
++{
++ if (cardtype == MPI_CARDTYPE_NONE) {
++ return;
++ }
++
++ if (cardtype == MPI_CARDTYPE_CARDBUS) {
++ bReset = ! bReset;
++ }
++
++ if (bReset) {
++ mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 & ~PCCARD_CARD_RESET);
++ } else {
++ mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 | PCCARD_CARD_RESET);
++ }
++}
++
++/*
++ * mpi_ConfigCs: Configure an MPI/EBI chip select
++ */
++static void mpi_ConfigCs(uint32 cs, uint32 base, uint32 size, uint32 flags)
++{
++ mpi->cs[cs].base = ((base & 0x1FFFFFFF) | size);
++ mpi->cs[cs].config = flags;
++}
++
++/*
++ * mpi_InitPcmciaSpace
++ */
++static void mpi_InitPcmciaSpace(void)
++{
++ // ChipSelect 4 controls PCMCIA Memory accesses
++ mpi_ConfigCs(PCMCIA_COMMON_BASE, pcmciaMem, EBI_SIZE_1M, (EBI_WORD_WIDE|EBI_ENABLE));
++ // ChipSelect 5 controls PCMCIA Attribute accesses
++ mpi_ConfigCs(PCMCIA_ATTRIBUTE_BASE, pcmciaAttr, EBI_SIZE_1M, (EBI_WORD_WIDE|EBI_ENABLE));
++ // ChipSelect 6 controls PCMCIA I/O accesses
++ mpi_ConfigCs(PCMCIA_IO_BASE, pcmciaIo, EBI_SIZE_64K, (EBI_WORD_WIDE|EBI_ENABLE));
++
++ mpi->pcmcia_cntl2 = ((PCMCIA_ATTR_ACTIVE << RW_ACTIVE_CNT_BIT) |
++ (PCMCIA_ATTR_INACTIVE << INACTIVE_CNT_BIT) |
++ (PCMCIA_ATTR_CE_SETUP << CE_SETUP_CNT_BIT) |
++ (PCMCIA_ATTR_CE_HOLD << CE_HOLD_CNT_BIT));
++
++ mpi->pcmcia_cntl2 |= (PCMCIA_HALFWORD_EN | PCMCIA_BYTESWAP_DIS);
++}
++
++/*
++ * cardtype_vcc_detect: PC Card's card detect and voltage sense connection
++ *
++ * CD1#/ CD2#/ VS1#/ VS2#/ Card Initial Vcc
++ * CCD1# CCD2# CVS1 CVS2 Type
++ *
++ * GND GND open open 16-bit 5 vdc
++ *
++ * GND GND GND open 16-bit 3.3 vdc
++ *
++ * GND GND open GND 16-bit x.x vdc
++ *
++ * GND GND GND GND 16-bit 3.3 & x.x vdc
++ *
++ *====================================================================
++ *
++ * CVS1 GND CCD1# open CardBus 3.3 vdc
++ *
++ * GND CVS2 open CCD2# CardBus x.x vdc
++ *
++ * GND CVS1 CCD2# open CardBus y.y vdc
++ *
++ * GND CVS2 GND CCD2# CardBus 3.3 & x.x vdc
++ *
++ * CVS2 GND open CCD1# CardBus x.x & y.y vdc
++ *
++ * GND CVS1 CCD2# open CardBus 3.3, x.x & y.y vdc
++ *
++ */
++static int cardtype_vcc_detect(void)
++{
++ uint32 data32;
++ int cardtype;
++
++ cardtype = MPI_CARDTYPE_NONE;
++ mpi->pcmcia_cntl1 = 0x0000A000; // Turn on the output enables and drive
++ // the CVS pins to 0.
++ data32 = mpi->pcmcia_cntl1;
++ switch (data32 & 0x00000003) // Test CD1# and CD2#, see if card is plugged in.
++ {
++ case 0x00000003: // No Card is in the slot.
++ printk("mpi: No Card is in the PCMCIA slot\n");
++ break;
++
++ case 0x00000002: // Partial insertion, No CD2#.
++ printk("mpi: Card in the PCMCIA slot partial insertion, no CD2 signal\n");
++ break;
++
++ case 0x00000001: // Partial insertion, No CD1#.
++ printk("mpi: Card in the PCMCIA slot partial insertion, no CD1 signal\n");
++ break;
++
++ case 0x00000000:
++ mpi->pcmcia_cntl1 = 0x0000A0C0; // Turn off the CVS output enables and
++ // float the CVS pins.
++ mdelay(1);
++ data32 = mpi->pcmcia_cntl1;
++ // Read the Register.
++ switch (data32 & 0x0000000C) // See what is on the CVS pins.
++ {
++ case 0x00000000: // CVS1 and CVS2 are tied to ground, only 1 option.
++ printk("mpi: Detected 3.3 & x.x 16-bit PCMCIA card\n");
++ cardtype = MPI_CARDTYPE_PCMCIA;
++ break;
++
++ case 0x00000004: // CVS1 is open or tied to CCD1/CCD2 and CVS2 is tied to ground.
++ // 2 valid voltage options.
++ switch (data32 & 0x00000003) // Test the values of CCD1 and CCD2.
++ {
++ case 0x00000003: // CCD1 and CCD2 are tied to 1 of the CVS pins.
++ // This is not a valid combination.
++ printk("mpi: Unknown card plugged into slot\n");
++ break;
++
++ case 0x00000002: // CCD2 is tied to either CVS1 or CVS2.
++ mpi->pcmcia_cntl1 = 0x0000A080; // Drive CVS1 to a 0.
++ mdelay(1);
++ data32 = mpi->pcmcia_cntl1;
++ if (data32 & 0x00000002) { // CCD2 is tied to CVS2, not valid.
++ printk("mpi: Unknown card plugged into slot\n");
++ } else { // CCD2 is tied to CVS1.
++ printk("mpi: Detected 3.3, x.x and y.y Cardbus card\n");
++ cardtype = MPI_CARDTYPE_CARDBUS;
++ }
++ break;
++
++ case 0x00000001: // CCD1 is tied to either CVS1 or CVS2.
++ // This is not a valid combination.
++ printk("mpi: Unknown card plugged into slot\n");
++ break;
++
++ case 0x00000000: // CCD1 and CCD2 are tied to ground.
++ printk("mpi: Detected x.x vdc 16-bit PCMCIA card\n");
++ cardtype = MPI_CARDTYPE_PCMCIA;
++ break;
++ }
++ break;
++
++ case 0x00000008: // CVS2 is open or tied to CCD1/CCD2 and CVS1 is tied to ground.
++ // 2 valid voltage options.
++ switch (data32 & 0x00000003) // Test the values of CCD1 and CCD2.
++ {
++ case 0x00000003: // CCD1 and CCD2 are tied to 1 of the CVS pins.
++ // This is not a valid combination.
++ printk("mpi: Unknown card plugged into slot\n");
++ break;
++
++ case 0x00000002: // CCD2 is tied to either CVS1 or CVS2.
++ mpi->pcmcia_cntl1 = 0x0000A040; // Drive CVS2 to a 0.
++ mdelay(1);
++ data32 = mpi->pcmcia_cntl1;
++ if (data32 & 0x00000002) { // CCD2 is tied to CVS1, not valid.
++ printk("mpi: Unknown card plugged into slot\n");
++ } else {// CCD2 is tied to CVS2.
++ printk("mpi: Detected 3.3 and x.x Cardbus card\n");
++ cardtype = MPI_CARDTYPE_CARDBUS;
++ }
++ break;
++
++ case 0x00000001: // CCD1 is tied to either CVS1 or CVS2.
++ // This is not a valid combination.
++ printk("mpi: Unknown card plugged into slot\n");
++ break;
++
++ case 0x00000000: // CCD1 and CCD2 are tied to ground.
++ cardtype = MPI_CARDTYPE_PCMCIA;
++ printk("mpi: Detected 3.3 vdc 16-bit PCMCIA card\n");
++ break;
++ }
++ break;
++
++ case 0x0000000C: // CVS1 and CVS2 are open or tied to CCD1/CCD2.
++ // 5 valid voltage options.
++
++ switch (data32 & 0x00000003) // Test the values of CCD1 and CCD2.
++ {
++ case 0x00000003: // CCD1 and CCD2 are tied to 1 of the CVS pins.
++ // This is not a valid combination.
++ printk("mpi: Unknown card plugged into slot\n");
++ break;
++
++ case 0x00000002: // CCD2 is tied to either CVS1 or CVS2.
++ // CCD1 is tied to ground.
++ mpi->pcmcia_cntl1 = 0x0000A040; // Drive CVS2 to a 0.
++ mdelay(1);
++ data32 = mpi->pcmcia_cntl1;
++ if (data32 & 0x00000002) { // CCD2 is tied to CVS1.
++ printk("mpi: Detected y.y vdc Cardbus card\n");
++ } else { // CCD2 is tied to CVS2.
++ printk("mpi: Detected x.x vdc Cardbus card\n");
++ }
++ cardtype = MPI_CARDTYPE_CARDBUS;
++ break;
++
++ case 0x00000001: // CCD1 is tied to either CVS1 or CVS2.
++ // CCD2 is tied to ground.
++
++ mpi->pcmcia_cntl1 = 0x0000A040; // Drive CVS2 to a 0.
++ mdelay(1);
++ data32 = mpi->pcmcia_cntl1;
++ if (data32 & 0x00000001) {// CCD1 is tied to CVS1.
++ printk("mpi: Detected 3.3 vdc Cardbus card\n");
++ } else { // CCD1 is tied to CVS2.
++ printk("mpi: Detected x.x and y.y Cardbus card\n");
++ }
++ cardtype = MPI_CARDTYPE_CARDBUS;
++ break;
++
++ case 0x00000000: // CCD1 and CCD2 are tied to ground.
++ cardtype = MPI_CARDTYPE_PCMCIA;
++ printk("mpi: Detected 5 vdc 16-bit PCMCIA card\n");
++ break;
++ }
++ break;
++
++ default:
++ printk("mpi: Unknown card plugged into slot\n");
++ break;
++
++ }
++ }
++ return cardtype;
++}
++
++/*
++ * mpi_DetectPcCard: Detect the plugged in PC-Card
++ * Return: < 0 => Unknown card detected
++ * 0 => No card detected
++ * 1 => 16-bit card detected
++ * 2 => 32-bit CardBus card detected
++ */
++static int mpi_DetectPcCard(void)
++{
++ int cardtype;
++
++ cardtype = cardtype_vcc_detect();
++ switch(cardtype) {
++ case MPI_CARDTYPE_PCMCIA:
++ mpi->pcmcia_cntl1 &= ~0x0000e000; // disable enable bits
++ //mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 & ~PCCARD_CARD_RESET);
++ mpi->pcmcia_cntl1 |= (PCMCIA_ENABLE | PCMCIA_GPIO_ENABLE);
++ mpi_InitPcmciaSpace();
++ mpi_ResetPcCard(cardtype, FALSE);
++ // Hold card in reset for 10ms
++ mdelay(10);
++ mpi_ResetPcCard(cardtype, TRUE);
++ // Let card come out of reset
++ mdelay(100);
++ break;
++ case MPI_CARDTYPE_CARDBUS:
++ // 8 => CardBus Enable
++ // 1 => PCI Slot Number
++ // C => Float VS1 & VS2
++ mpi->pcmcia_cntl1 = (mpi->pcmcia_cntl1 & 0xFFFF0000) |
++ CARDBUS_ENABLE |
++ (CARDBUS_SLOT << 8)|
++ VS2_OEN |
++ VS1_OEN;
++ /* access to this memory window will be to/from CardBus */
++ mpi->l2pmremap1 |= CARDBUS_MEM;
++
++ // Need to reset the Cardbus Card. There's no CardManager to do this,
++ // and we need to be ready for PCI configuration.
++ mpi_ResetPcCard(cardtype, FALSE);
++ // Hold card in reset for 10ms
++ mdelay(10);
++ mpi_ResetPcCard(cardtype, TRUE);
++ // Let card come out of reset
++ mdelay(100);
++ break;
++ default:
++ break;
++ }
++ return cardtype;
++}
++
++static int mpi_init(void)
++{
++ unsigned long data;
++ unsigned int chipid;
++ unsigned int chiprev;
++ unsigned int sdramsize;
++
++ chipid = (PERF->RevID & 0xFFFF0000) >> 16;
++ chiprev = (PERF->RevID & 0xFF);
++ sdramsize = getMemorySize();
++ /*
++ * Init the pci interface
++ */
++ data = GPIO->GPIOMode; // GPIO mode register
++ data |= GROUP2_PCI | GROUP1_MII_PCCARD; // PCI internal arbiter + Cardbus
++ GPIO->GPIOMode = data; // PCI internal arbiter
++
++ /*
++ * In the BCM6348 CardBus support is defaulted to Slot 0
++ * because there is no external IDSEL for CardBus. To disable
++ * the CardBus and allow a standard PCI card in Slot 0
++ * set the cbus_idsel field to 0x1f.
++ */
++ /*
++ uData = mpi->pcmcia_cntl1;
++ uData |= CARDBUS_IDSEL;
++ mpi->pcmcia_cntl1 = uData;
++ */
++ // Setup PCI I/O Window range. Give 64K to PCI I/O
++ mpi->l2piorange = ~(BCM_PCI_IO_SIZE_64KB-1);
++ // UBUS to PCI I/O base address
++ mpi->l2piobase = BCM_PCI_IO_BASE & BCM_PCI_ADDR_MASK;
++ // UBUS to PCI I/O Window remap
++ mpi->l2pioremap = (BCM_PCI_IO_BASE | MEM_WINDOW_EN);
++
++ // enable PCI related GPIO pins and data swap between system and PCI bus
++ mpi->locbuscntrl = (EN_PCI_GPIO | DIR_U2P_NOSWAP);
++
++ /* Enable 6348 BusMaster and Memory access mode */
++ data = mpi_GetLocalPciConfigReg(PCI_COMMAND);
++ data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
++ mpi_SetLocalPciConfigReg(PCI_COMMAND, data);
++
++ /* Configure two 16 MByte PCI to System memory regions. */
++ /* These memory regions are used when PCI device is a bus master */
++ /* Accesses to the SDRAM from PCI bus will be "byte swapped" for this region */
++ mpi_SetLocalPciConfigReg(PCI_BASE_ADDRESS_3, BCM_HOST_MEM_SPACE1);
++ mpi->sp0remap = 0x0;
++
++ /* Accesses to the SDRAM from PCI bus will not be "byte swapped" for this region */
++ mpi_SetLocalPciConfigReg(PCI_BASE_ADDRESS_4, BCM_HOST_MEM_SPACE2);
++ mpi->sp1remap = 0x0;
++ mpi->pcimodesel |= (PCI_BAR2_NOSWAP | 0x40);
++
++ if ((chipid == 0x6348) && (chiprev == 0xb0)) {
++ mpi->sp0range = ~(sdramsize-1);
++ mpi->sp1range = ~(sdramsize-1);
++ }
++ /*
++ * Change 6348 PCI Cfg Reg. offset 0x40 to PCI memory read retry count infinity
++ * by set 0 in bit 8~15. This resolve read Bcm4306 srom return 0xffff in
++ * first read.
++ */
++ data = mpi_GetLocalPciConfigReg(BRCM_PCI_CONFIG_TIMER);
++ data &= ~BRCM_PCI_CONFIG_TIMER_RETRY_MASK;
++ data |= 0x00000080;
++ mpi_SetLocalPciConfigReg(BRCM_PCI_CONFIG_TIMER, data);
++
++ /* enable pci interrupt */
++ mpi->locintstat |= (EXT_PCI_INT << 16);
++
++ mpi_DetectPcCard();
++
++ ioport_resource.start = BCM_PCI_IO_BASE;
++ ioport_resource.end = BCM_PCI_IO_BASE + BCM_PCI_IO_SIZE_64KB;
++
++#if defined(CONFIG_USB)
++ PERF->blkEnables |= USBH_CLK_EN;
++ mdelay(100);
++ *USBH_NON_OHCI = NON_OHCI_BYTE_SWAP;
++#endif
++
++ return 0;
++}
++#endif
++
++static int __init brcm63xx_setup(void)
++{
++ extern int panic_timeout;
++
++ _machine_restart = brcm_machine_restart;
++ _machine_halt = brcm_machine_halt;
++ pm_power_off = brcm_machine_halt;
++
++ board_time_init = brcm_time_init;
++ board_timer_setup = brcm_timer_setup;
++
++ panic_timeout = 5;
++
++#if defined(CONFIG_BCM96348) && defined(CONFIG_PCI)
++ /* mpi initialization */
++ mpi_init();
++#endif
++ return 0;
++}
++
++void plat_setup(void)
++{
++ brcm63xx_setup();
++}
++
++/***************************************************************************
++ * C++ New and delete operator functions
++ ***************************************************************************/
++
++/* void *operator new(unsigned int sz) */
++void *_Znwj(unsigned int sz)
++{
++ return( kmalloc(sz, GFP_KERNEL) );
++}
++
++/* void *operator new[](unsigned int sz)*/
++void *_Znaj(unsigned int sz)
++{
++ return( kmalloc(sz, GFP_KERNEL) );
++}
++
++/* placement new operator */
++/* void *operator new (unsigned int size, void *ptr) */
++void *ZnwjPv(unsigned int size, void *ptr)
++{
++ return ptr;
++}
++
++/* void operator delete(void *m) */
++void _ZdlPv(void *m)
++{
++ kfree(m);
++}
++
++/* void operator delete[](void *m) */
++void _ZdaPv(void *m)
++{
++ kfree(m);
++}
++
++EXPORT_SYMBOL(_Znwj);
++EXPORT_SYMBOL(_Znaj);
++EXPORT_SYMBOL(ZnwjPv);
++EXPORT_SYMBOL(_ZdlPv);
++EXPORT_SYMBOL(_ZdaPv);
++
+diff -urN linux.old/arch/mips/bcm963xx/softdsl/AdslCoreDefs.h linux.dev/arch/mips/bcm963xx/softdsl/AdslCoreDefs.h
+--- linux.old/arch/mips/bcm963xx/softdsl/AdslCoreDefs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/softdsl/AdslCoreDefs.h 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,2 @@
++#define ADSL_SDRAM_IMAGE_SIZE (384*1024)
++
+diff -urN linux.old/arch/mips/bcm963xx/time.c linux.dev/arch/mips/bcm963xx/time.c
+--- linux.old/arch/mips/bcm963xx/time.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/bcm963xx/time.c 2006-08-25 03:58:22.000000000 +0200
+@@ -0,0 +1,114 @@
++/*
++<:copyright-gpl
++ Copyright 2004 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope 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.
++:>
++*/
++/*
++ * Setup time for Broadcom 963xx MIPS boards
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/kernel_stat.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/time.h>
++#include <linux/timex.h>
++
++#include <asm/mipsregs.h>
++#include <asm/ptrace.h>
++#include <asm/div64.h>
++#include <asm/time.h>
++
++#include <bcm_map_part.h>
++#include <bcm_intr.h>
++
++static unsigned long r4k_offset; /* Amount to increment compare reg each time */
++static unsigned long r4k_cur; /* What counter should be at next timer irq */
++
++/* *********************************************************************
++ * calculateCpuSpeed()
++ * Calculate the BCM6348 CPU speed by reading the PLL strap register
++ * and applying the following formula:
++ * cpu_clk = (.25 * 64MHz freq) * (N1 + 1) * (N2 + 2) / (M1_CPU + 1)
++ * Input parameters:
++ * none
++ * Return value:
++ * none
++ ********************************************************************* */
++
++static inline unsigned long __init calculateCpuSpeed(void)
++{
++ UINT32 pllStrap = PERF->PllStrap;
++ int n1 = (pllStrap & PLL_N1_MASK) >> PLL_N1_SHFT;
++ int n2 = (pllStrap & PLL_N2_MASK) >> PLL_N2_SHFT;
++ int m1cpu = (pllStrap & PLL_M1_CPU_MASK) >> PLL_M1_CPU_SHFT;
++
++ return (16 * (n1 + 1) * (n2 + 2) / (m1cpu + 1)) * 1000000;
++}
++
++
++static inline unsigned long __init cal_r4koff(void)
++{
++ mips_hpt_frequency = calculateCpuSpeed() / 2;
++ return (mips_hpt_frequency / HZ);
++}
++
++
++/*
++ * There are a lot of conceptually broken versions of the MIPS timer interrupt
++ * handler floating around. This one is rather different, but the algorithm
++ * is provably more robust.
++ */
++irqreturn_t brcm_timer_interrupt(struct pt_regs *regs)
++{
++ int irq = MIPS_TIMER_INT;
++
++ irq_enter();
++ kstat_this_cpu.irqs[irq]++;
++
++ timer_interrupt(irq, NULL, regs);
++ irq_exit();
++ return IRQ_HANDLED;
++}
++
++
++void __init brcm_time_init(void)
++{
++ unsigned int est_freq, flags;
++ local_irq_save(flags);
++
++ printk("calculating r4koff... ");
++ r4k_offset = cal_r4koff();
++ printk("%08lx(%d)\n", r4k_offset, (int)r4k_offset);
++
++ est_freq = 2 * r4k_offset * HZ;
++ est_freq += 5000; /* round */
++ est_freq -= est_freq % 10000;
++ printk("CPU frequency %d.%02d MHz\n", est_freq / 1000000,
++ (est_freq % 1000000) * 100 / 1000000);
++ local_irq_restore(flags);
++}
++
++
++void __init brcm_timer_setup(struct irqaction *irq)
++{
++ r4k_cur = (read_c0_count() + r4k_offset);
++ write_c0_compare(r4k_cur);
++ set_c0_status(IE_IRQ5);
++}
+diff -urN linux.old/arch/mips/Kconfig linux.dev/arch/mips/Kconfig
+--- linux.old/arch/mips/Kconfig 2006-08-25 00:43:39.000000000 +0200
++++ linux.dev/arch/mips/Kconfig 2006-08-25 01:57:46.000000000 +0200
+@@ -12,6 +12,15 @@
+ prompt "System type"
+ default SGI_IP22
+
++config MIPS_BRCM
++ bool "Support for the Broadcom boards"
++ select SYS_SUPPORTS_32BIT_KERNEL
++ select SYS_SUPPORTS_BIG_ENDIAN
++ select SYS_HAS_CPU_MIPS32_R1
++ select IRQ_CPU
++ help
++ This is a fmaily of boards based on the Broadcom MIPS32
++
+ config MIPS_MTX1
+ bool "4G Systems MTX-1 board"
+ select DMA_NONCOHERENT
+@@ -780,6 +789,7 @@
+
+ endchoice
+
++source "arch/mips/bcm963xx/Kconfig"
+ source "arch/mips/ddb5xxx/Kconfig"
+ source "arch/mips/gt64120/ev64120/Kconfig"
+ source "arch/mips/jazz/Kconfig"
+diff -urN linux.old/arch/mips/kernel/cpu-probe.c linux.dev/arch/mips/kernel/cpu-probe.c
+--- linux.old/arch/mips/kernel/cpu-probe.c 2006-08-25 00:43:39.000000000 +0200
++++ linux.dev/arch/mips/kernel/cpu-probe.c 2006-08-25 00:39:38.000000000 +0200
+@@ -568,6 +568,25 @@
+ return;
+ }
+
++static inline void cpu_probe_broadcom(struct cpuinfo_mips *c)
++{
++ decode_configs(c);
++ switch (c->processor_id & 0xff00) {
++ case PRID_IMP_BCM6338:
++ c->cputype = CPU_BCM6338;
++ break;
++ case PRID_IMP_BCM6345:
++ c->cputype = CPU_BCM6345;
++ break;
++ case PRID_IMP_BCM6348:
++ c->cputype = CPU_BCM6348;
++ break;
++ default:
++ c->cputype = CPU_UNKNOWN;
++ break;
++ }
++}
++
+ static inline void cpu_probe_mips(struct cpuinfo_mips *c)
+ {
+ decode_configs(c);
+@@ -704,6 +723,9 @@
+ case PRID_COMP_LEGACY:
+ cpu_probe_legacy(c);
+ break;
++ case PRID_COMP_BROADCOM:
++ cpu_probe_broadcom(c);
++ break;
+ case PRID_COMP_MIPS:
+ cpu_probe_mips(c);
+ break;
+diff -urN linux.old/arch/mips/kernel/proc.c linux.dev/arch/mips/kernel/proc.c
+--- linux.old/arch/mips/kernel/proc.c 2006-08-25 00:43:39.000000000 +0200
++++ linux.dev/arch/mips/kernel/proc.c 2006-08-25 00:39:38.000000000 +0200
+@@ -85,6 +85,9 @@
+ [CPU_VR4181A] = "NEC VR4181A",
+ [CPU_SR71000] = "Sandcraft SR71000",
+ [CPU_PR4450] = "Philips PR4450",
++ [CPU_BCM6338] = "BCM6338",
++ [CPU_BCM6345] = "BCM6345",
++ [CPU_BCM6348] = "BCM6348",
+ };
+
+
+diff -urN linux.old/arch/mips/Makefile linux.dev/arch/mips/Makefile
+--- linux.old/arch/mips/Makefile 2006-08-25 00:43:39.000000000 +0200
++++ linux.dev/arch/mips/Makefile 2006-08-25 15:39:54.000000000 +0200
+@@ -145,6 +145,15 @@
+ #
+
+ #
++# Broadcom board
++#
++core-$(CONFIG_MIPS_BRCM) += arch/mips/bcm963xx/
++cflags-$(CONFIG_MIPS_BRCM) += -Iinclude/asm-mips/mach-bcm963xx
++cflags-$(CONFIG_MIPS_BRCM) += -Iarch/mips/bcm963xx/include
++load-$(CONFIG_MIPS_BRCM) += 0xffffffff80010000
++
++
++#
+ # Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
+ #
+ core-$(CONFIG_MACH_JAZZ) += arch/mips/jazz/
+diff -urN linux.old/arch/mips/mm/c-r4k.c linux.dev/arch/mips/mm/c-r4k.c
+--- linux.old/arch/mips/mm/c-r4k.c 2006-08-25 00:43:39.000000000 +0200
++++ linux.dev/arch/mips/mm/c-r4k.c 2006-08-25 00:39:38.000000000 +0200
+@@ -914,6 +914,13 @@
+ if (!(config & MIPS_CONF_M))
+ panic("Don't know how to probe P-caches on this cpu.");
+
++ if (c->cputype == CPU_BCM6338 || c->cputype == CPU_BCM6345 || c->cputype == CPU_BCM6348)
++ {
++ printk("brcm mips: enabling icache and dcache...\n");
++ /* Enable caches */
++ write_c0_diag(read_c0_diag() | 0xC0000000);
++ }
++
+ /*
+ * So we seem to be a MIPS32 or MIPS64 CPU
+ * So let's probe the I-cache ...
+diff -urN linux.old/arch/mips/mm/tlbex.c linux.dev/arch/mips/mm/tlbex.c
+--- linux.old/arch/mips/mm/tlbex.c 2006-08-25 00:43:39.000000000 +0200
++++ linux.dev/arch/mips/mm/tlbex.c 2006-08-25 00:39:38.000000000 +0200
+@@ -882,6 +882,9 @@
+ case CPU_4KSC:
+ case CPU_20KC:
+ case CPU_25KF:
++ case CPU_BCM6338:
++ case CPU_BCM6345:
++ case CPU_BCM6348:
+ tlbw(p);
+ break;
+
+diff -urN linux-2.6.17/arch/mips/pci/fixup-bcm96348.c linux-2.6.17-brcm63xx/arch/mips/pci/fixup-bcm96348.c
+--- linux-2.6.17/arch/mips/pci/fixup-bcm96348.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-brcm63xx/arch/mips/pci/fixup-bcm96348.c 2006-08-29 10:25:22.000000000 +0200
+@@ -0,0 +1,93 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope 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/types.h>
++#include <linux/pci.h>
++
++#include <bcmpci.h>
++#include <bcm_intr.h>
++#include <bcm_map_part.h>
++
++static volatile MpiRegisters * mpi = (MpiRegisters *)(MPI_BASE);
++
++static char irq_tab_bcm96348[] __initdata = {
++ [0] = INTERRUPT_ID_MPI,
++ [1] = INTERRUPT_ID_MPI,
++#if defined(CONFIG_USB)
++ [USB_HOST_SLOT] = INTERRUPT_ID_USBH
++#endif
++};
++
++int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++ return irq_tab_bcm96348[slot];
++}
++
++static void bcm96348_fixup(struct pci_dev *dev)
++{
++ uint32 memaddr;
++ uint32 size;
++
++ memaddr = pci_resource_start(dev, 0);
++ size = pci_resource_len(dev, 0);
++
++ switch (PCI_SLOT(dev->devfn)) {
++ case 0:
++ // UBUS to PCI address range
++ // Memory Window 1. Mask determines which bits are decoded.
++ mpi->l2pmrange1 = ~(size-1);
++ // UBUS to PCI Memory base address. This is akin to the ChipSelect base
++ // register.
++ mpi->l2pmbase1 = memaddr & BCM_PCI_ADDR_MASK;
++ // UBUS to PCI Remap Address. Replaces the masked address bits in the
++ // range register with this setting.
++ // Also, enable direct I/O and direct Memory accesses
++ mpi->l2pmremap1 = (memaddr | MEM_WINDOW_EN);
++ break;
++
++ case 1:
++ // Memory Window 2
++ mpi->l2pmrange2 = ~(size-1);
++ // UBUS to PCI Memory base address.
++ mpi->l2pmbase2 = memaddr & BCM_PCI_ADDR_MASK;
++ // UBUS to PCI Remap Address
++ mpi->l2pmremap2 = (memaddr | MEM_WINDOW_EN);
++ break;
++
++#if defined(CONFIG_USB)
++ case USB_HOST_SLOT:
++ dev->resource[0].start = USB_HOST_BASE;
++ dev->resource[0].end = USB_HOST_BASE+USB_BAR0_MEM_SIZE-1;
++ break;
++#endif
++ }
++}
++
++int pcibios_plat_dev_init(struct pci_dev *dev)
++{
++ return 0;
++}
++
++DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_ANY_ID,
++ bcm96348_fixup);
++
++/*struct pci_fixup pcibios_fixups[] = {
++ { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, bcm96348_fixup },
++ {0}
++};*/
+diff -urN linux.old/arch/mips/pci/Makefile linux.dev/arch/mips/pci/Makefile
+--- linux.old/arch/mips/pci/Makefile 2006-08-25 00:43:29.000000000 +0200
++++ linux.dev/arch/mips/pci/Makefile 2006-08-25 00:39:38.000000000 +0200
+@@ -18,6 +18,7 @@
+ obj-$(CONFIG_MIPS_TX3927) += ops-tx3927.o
+ obj-$(CONFIG_PCI_VR41XX) += ops-vr41xx.o pci-vr41xx.o
+ obj-$(CONFIG_NEC_CMBVR4133) += fixup-vr4133.o
++obj-$(CONFIG_BCM_PCI) += fixup-bcm96348.o pci-bcm96348.o ops-bcm96348.o
+
+ #
+ # These are still pretty much in the old state, watch, go blind.
+diff -urN linux.old/arch/mips/pci/ops-bcm96348.c linux.dev/arch/mips/pci/ops-bcm96348.c
+--- linux.old/arch/mips/pci/ops-bcm96348.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/pci/ops-bcm96348.c 2006-08-25 00:39:38.000000000 +0200
+@@ -0,0 +1,276 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope 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/types.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <asm/addrspace.h>
++
++#include <bcm_intr.h>
++#include <bcm_map_part.h>
++#include <bcmpci.h>
++
++#include <linux/delay.h>
++
++#if defined(CONFIG_USB)
++#if 0
++#define DPRINT(x...) printk(x)
++#else
++#define DPRINT(x...)
++#endif
++
++static int
++pci63xx_int_read(unsigned int devfn, int where, u32 * value, int size);
++static int
++pci63xx_int_write(unsigned int devfn, int where, u32 * value, int size);
++
++static bool usb_mem_size_rd = FALSE;
++static uint32 usb_mem_base = 0;
++static uint32 usb_cfg_space_cmd_reg = 0;
++#endif
++static bool pci_mem_size_rd = FALSE;
++
++static volatile MpiRegisters * mpi = (MpiRegisters *)(MPI_BASE);
++
++static void mpi_SetupPciConfigAccess(uint32 addr)
++{
++ mpi->l2pcfgctl = (DIR_CFG_SEL | DIR_CFG_USEREG | addr) & ~CONFIG_TYPE;
++}
++
++static void mpi_ClearPciConfigAccess(void)
++{
++ mpi->l2pcfgctl = 0x00000000;
++}
++
++#if defined(CONFIG_USB)
++/* --------------------------------------------------------------------------
++ Name: pci63xx_int_write
++Abstract: PCI Config write on internal device(s)
++ -------------------------------------------------------------------------- */
++static int
++pci63xx_int_write(unsigned int devfn, int where, u32 * value, int size)
++{
++ if (PCI_SLOT(devfn) != USB_HOST_SLOT) {
++ return PCIBIOS_SUCCESSFUL;
++ }
++
++ switch (size) {
++ case 1:
++ DPRINT("W => Slot: %d Where: %2X Len: %d Data: %02X\n",
++ PCI_SLOT(devfn), where, size, *value);
++ break;
++ case 2:
++ DPRINT("W => Slot: %d Where: %2X Len: %d Data: %04X\n",
++ PCI_SLOT(devfn), where, size, *value);
++ switch (where) {
++ case PCI_COMMAND:
++ usb_cfg_space_cmd_reg = *value;
++ break;
++ default:
++ break;
++ }
++ break;
++ case 4:
++ DPRINT("W => Slot: %d Where: %2X Len: %d Data: %08lX\n",
++ PCI_SLOT(devfn), where, size, *value);
++ switch (where) {
++ case PCI_BASE_ADDRESS_0:
++ if (*value == 0xffffffff) {
++ usb_mem_size_rd = TRUE;
++ } else {
++ usb_mem_base = *value;
++ }
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ break;
++ }
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++/* --------------------------------------------------------------------------
++ Name: pci63xx_int_read
++Abstract: PCI Config read on internal device(s)
++ -------------------------------------------------------------------------- */
++static int
++pci63xx_int_read(unsigned int devfn, int where, u32 * value, int size)
++{
++ uint32 retValue = 0xFFFFFFFF;
++
++ if (PCI_SLOT(devfn) != USB_HOST_SLOT) {
++ return PCIBIOS_SUCCESSFUL;
++ }
++
++ // For now, this is specific to the USB Host controller. We can
++ // make it more general if we have to...
++ // Emulate PCI Config accesses
++ switch (where) {
++ case PCI_VENDOR_ID:
++ case PCI_DEVICE_ID:
++ retValue = PCI_VENDOR_ID_BROADCOM | 0x63000000;
++ break;
++ case PCI_COMMAND:
++ case PCI_STATUS:
++ retValue = (0x0006 << 16) | usb_cfg_space_cmd_reg;
++ break;
++ case PCI_CLASS_REVISION:
++ case PCI_CLASS_DEVICE:
++ retValue = (PCI_CLASS_SERIAL_USB << 16) | (0x10 << 8) | 0x01;
++ break;
++ case PCI_BASE_ADDRESS_0:
++ if (usb_mem_size_rd) {
++ retValue = USB_BAR0_MEM_SIZE;
++ } else {
++ if (usb_mem_base != 0)
++ retValue = usb_mem_base;
++ else
++ retValue = USB_HOST_BASE;
++ }
++ usb_mem_size_rd = FALSE;
++ break;
++ case PCI_CACHE_LINE_SIZE:
++ case PCI_LATENCY_TIMER:
++ retValue = 0;
++ break;
++ case PCI_HEADER_TYPE:
++ retValue = PCI_HEADER_TYPE_NORMAL;
++ break;
++ case PCI_SUBSYSTEM_VENDOR_ID:
++ retValue = PCI_VENDOR_ID_BROADCOM;
++ break;
++ case PCI_SUBSYSTEM_ID:
++ retValue = 0x6300;
++ break;
++ case PCI_INTERRUPT_LINE:
++ retValue = INTERRUPT_ID_USBH;
++ break;
++ default:
++ break;
++ }
++
++ switch (size) {
++ case 1:
++ *value = (retValue >> ((where & 3) << 3)) & 0xff;
++ DPRINT("R <= Slot: %d Where: %2X Len: %d Data: %02X\n",
++ PCI_SLOT(devfn), where, size, *value);
++ break;
++ case 2:
++ *value = (retValue >> ((where & 3) << 3)) & 0xffff;
++ DPRINT("R <= Slot: %d Where: %2X Len: %d Data: %04X\n",
++ PCI_SLOT(devfn), where, size, *value);
++ break;
++ case 4:
++ *value = retValue;
++ DPRINT("R <= Slot: %d Where: %2X Len: %d Data: %08lX\n",
++ PCI_SLOT(devfn), where, size, *value);
++ break;
++ default:
++ break;
++ }
++
++ return PCIBIOS_SUCCESSFUL;
++}
++#endif
++
++static int bcm96348_pcibios_read(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 * val)
++{
++ volatile unsigned char *ioBase = (unsigned char *)(mpi->l2piobase | KSEG1);
++ uint32 data;
++
++#if defined(CONFIG_USB)
++ if (PCI_SLOT(devfn) == USB_HOST_SLOT)
++ return pci63xx_int_read(devfn, where, val, size);
++#endif
++
++ mpi_SetupPciConfigAccess(BCM_PCI_CFG(PCI_SLOT(devfn), PCI_FUNC(devfn), where));
++ data = *(uint32 *)ioBase;
++ switch(size) {
++ case 1:
++ *val = (data >> ((where & 3) << 3)) & 0xff;
++ break;
++ case 2:
++ *val = (data >> ((where & 3) << 3)) & 0xffff;
++ break;
++ case 4:
++ *val = data;
++ /* Special case for reading PCI device range */
++ if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5)) {
++ if (pci_mem_size_rd) {
++ /* bcm6348 PCI memory window minimum size is 64K */
++ *val &= PCI_SIZE_64K;
++ }
++ }
++ break;
++ default:
++ break;
++ }
++ pci_mem_size_rd = FALSE;
++ mpi_ClearPciConfigAccess();
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++static int bcm96348_pcibios_write(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 val)
++{
++ volatile unsigned char *ioBase = (unsigned char *)(mpi->l2piobase | KSEG1);
++ uint32 data;
++
++#if defined(CONFIG_USB)
++ if (PCI_SLOT(devfn) == USB_HOST_SLOT)
++ return pci63xx_int_write(devfn, where, &val, size);
++#endif
++ mpi_SetupPciConfigAccess(BCM_PCI_CFG(PCI_SLOT(devfn), PCI_FUNC(devfn), where));
++ data = *(uint32 *)ioBase;
++ switch(size) {
++ case 1:
++ data = (data & ~(0xff << ((where & 3) << 3))) |
++ (val << ((where & 3) << 3));
++ break;
++ case 2:
++ data = (data & ~(0xffff << ((where & 3) << 3))) |
++ (val << ((where & 3) << 3));
++ break;
++ case 4:
++ data = val;
++ /* Special case for reading PCI device range */
++ if ((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_5)) {
++ if (val == 0xffffffff)
++ pci_mem_size_rd = TRUE;
++ }
++ break;
++ default:
++ break;
++ }
++ *(uint32 *)ioBase = data;
++ udelay(500);
++ mpi_ClearPciConfigAccess();
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++struct pci_ops bcm96348_pci_ops = {
++ .read = bcm96348_pcibios_read,
++ .write = bcm96348_pcibios_write
++};
+diff -urN linux-2.6.17/arch/mips/pci/pci-bcm96348.c linux-2.6.17-brcm63xx/arch/mips/pci/pci-bcm96348.c
+--- linux-2.6.17/arch/mips/pci/pci-bcm96348.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-brcm63xx/arch/mips/pci/pci-bcm96348.c 2006-08-29 10:25:13.000000000 +0200
+@@ -0,0 +1,54 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope 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/types.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++
++//#include <asm/pci_channel.h>
++#include <bcmpci.h>
++
++static struct resource bcm_pci_io_resource = {
++ .name = "bcm96348 pci IO space",
++ .start = BCM_PCI_IO_BASE,
++ .end = BCM_PCI_IO_BASE + BCM_PCI_IO_SIZE_64KB - 1,
++ .flags = IORESOURCE_IO
++};
++
++static struct resource bcm_pci_mem_resource = {
++ .name = "bcm96348 pci memory space",
++ .start = BCM_PCI_MEM_BASE,
++ .end = BCM_PCI_MEM_BASE + BCM_PCI_MEM_SIZE_16MB - 1,
++ .flags = IORESOURCE_MEM
++};
++
++extern struct pci_ops bcm96348_pci_ops;
++
++struct pci_controller bcm96348_controller = {
++ .pci_ops = &bcm96348_pci_ops,
++ .io_resource = &bcm_pci_io_resource,
++ .mem_resource = &bcm_pci_mem_resource,
++};
++
++static void bcm96348_pci_init(void)
++{
++ register_pci_controller(&bcm96348_controller);
++}
++
++arch_initcall(bcm96348_pci_init);
+diff -urN linux.old/drivers/serial/bcm63xx_cons.c linux.dev/drivers/serial/bcm63xx_cons.c
+--- linux.old/drivers/serial/bcm63xx_cons.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/serial/bcm63xx_cons.c 2006-08-25 15:37:34.000000000 +0200
+@@ -0,0 +1,1049 @@
++/*
++<:copyright-gpl
++ Copyright 2002 Broadcom Corp. All Rights Reserved.
++
++ This program is free software; you can distribute it and/or modify it
++ under the terms of the GNU General Public License (Version 2) as
++ published by the Free Software Foundation.
++
++ This program is distributed in the hope 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.
++:>
++*/
++
++/* Description: Serial port driver for the BCM963XX. */
++
++#define CARDNAME "bcm963xx_serial driver"
++#define VERSION "2.0"
++#define VER_STR CARDNAME " v" VERSION "\n"
++
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++
++/* for definition of struct console */
++#include <linux/console.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/serial.h>
++#include <linux/serialP.h>
++#include <asm/uaccess.h>
++
++#include <bcmtypes.h>
++#include <board.h>
++#include <bcm_map_part.h>
++#include <bcm_intr.h>
++
++static DEFINE_SPINLOCK(bcm963xx_serial_lock);
++
++extern void _putc(char);
++extern void _puts(const char *);
++
++typedef struct bcm_serial {
++ volatile Uart * port;
++ int type;
++ int flags;
++ int irq;
++ int baud_base;
++ int blocked_open;
++ unsigned short close_delay;
++ unsigned short closing_wait;
++ unsigned short line; /* port/line number */
++ unsigned short cflags; /* line configuration flag */
++ unsigned short x_char; /* xon/xoff character */
++ unsigned short read_status_mask; /* mask for read condition */
++ unsigned short ignore_status_mask; /* mask for ignore condition */
++ unsigned long event; /* mask used in BH */
++ int xmit_head; /* Position of the head */
++ int xmit_tail; /* Position of the tail */
++ int xmit_cnt; /* Count of the chars in the buffer */
++ int count; /* indicates how many times it has been opened */
++ int magic;
++
++ struct async_icount icount; /* keep track of things ... */
++ struct tty_struct *tty; /* tty associated */
++ struct termios normal_termios;
++
++ wait_queue_head_t open_wait;
++ wait_queue_head_t close_wait;
++
++ long session; /* Session of opening process */
++ long pgrp; /* pgrp of opening process */
++
++ unsigned char is_initialized;
++} Context;
++
++
++/*---------------------------------------------------------------------*/
++/* Define bits in the Interrupt Enable register */
++/*---------------------------------------------------------------------*/
++/* Enable receive interrupt */
++#define RXINT (RXFIFONE|RXOVFERR)
++
++/* Enable transmit interrupt */
++#define TXINT (TXFIFOEMT|TXUNDERR|TXOVFERR)
++
++/* Enable receiver line status interrupt */
++#define LSINT (RXBRK|RXPARERR|RXFRAMERR)
++
++#define BCM_NUM_UARTS 1
++
++#define BD_BCM63XX_TIMER_CLOCK_INPUT (FPERIPH)
++
++
++static struct bcm_serial multi[BCM_NUM_UARTS];
++static struct bcm_serial *lines[BCM_NUM_UARTS];
++static struct tty_driver *serial_driver;
++static struct termios *serial_termios[BCM_NUM_UARTS];
++static struct termios *serial_termios_locked[BCM_NUM_UARTS];
++
++
++static void bcm_stop (struct tty_struct *tty);
++static void bcm_start (struct tty_struct *tty);
++static inline void receive_chars (struct bcm_serial * info);
++static int startup (struct bcm_serial *info);
++static void shutdown (struct bcm_serial * info);
++static void change_speed( volatile Uart *pUart, tcflag_t cFlag );
++static void bcm63xx_cons_flush_chars (struct tty_struct *tty);
++static int bcm63xx_cons_write (struct tty_struct *tty,
++ const unsigned char *buf, int count);
++static int bcm63xx_cons_write_room (struct tty_struct *tty);
++static int bcm_chars_in_buffer (struct tty_struct *tty);
++static void bcm_flush_buffer (struct tty_struct *tty);
++static void bcm_throttle (struct tty_struct *tty);
++static void bcm_unthrottle (struct tty_struct *tty);
++static void bcm_send_xchar (struct tty_struct *tty, char ch);
++static int get_serial_info(struct bcm_serial *info, struct serial_struct *retinfo);
++static int set_serial_info (struct bcm_serial *info, struct serial_struct *new_info);
++static int get_lsr_info (struct bcm_serial *info, unsigned int *value);
++static void send_break (struct bcm_serial *info, int duration);
++static int bcm_ioctl (struct tty_struct * tty, struct file * file,
++ unsigned int cmd, unsigned long arg);
++static void bcm_set_termios (struct tty_struct *tty, struct termios *old_termios);
++static void bcm63xx_cons_close (struct tty_struct *tty, struct file *filp);
++static void bcm_hangup (struct tty_struct *tty);
++static int block_til_ready (struct tty_struct *tty, struct file *filp, struct bcm_serial *info);
++static int bcm63xx_cons_open (struct tty_struct * tty, struct file * filp);
++static int __init bcm63xx_serialinit(void);
++
++
++/*
++ * ------------------------------------------------------------
++ * rs_stop () and rs_start ()
++ *
++ * These routines are called before setting or resetting
++ * tty->stopped. They enable or disable transmitter interrupts,
++ * as necessary.
++ * ------------------------------------------------------------
++ */
++static void bcm_stop (struct tty_struct *tty)
++{
++}
++
++static void bcm_start (struct tty_struct *tty)
++{
++ _puts(CARDNAME " Start\n");
++}
++
++/*
++ * ------------------------------------------------------------
++ * receive_char ()
++ *
++ * This routine deals with inputs from any lines.
++ * ------------------------------------------------------------
++ */
++static inline void receive_chars (struct bcm_serial * info)
++{
++ struct tty_struct *tty = 0;
++ struct async_icount * icount;
++ int ignore = 0;
++ unsigned short status, tmp;
++ UCHAR ch = 0;
++ while ((status = info->port->intStatus) & RXINT)
++ {
++ char flag_char = TTY_NORMAL;
++
++ if (status & RXFIFONE)
++ ch = info->port->Data; // Read the character
++ tty = info->tty; /* now tty points to the proper dev */
++ icount = &info->icount;
++ if (! tty)
++ break;
++ if (!tty_buffer_request_room(tty, 1))
++ break;
++ icount->rx++;
++ if (status & RXBRK)
++ {
++ flag_char = TTY_BREAK;
++ icount->brk++;
++ }
++ // keep track of the statistics
++ if (status & (RXFRAMERR | RXPARERR | RXOVFERR))
++ {
++ if (status & RXPARERR) /* parity error */
++ icount->parity++;
++ else
++ if (status & RXFRAMERR) /* frame error */
++ icount->frame++;
++ if (status & RXOVFERR)
++ {
++ // Overflow. Reset the RX FIFO
++ info->port->fifoctl |= RSTRXFIFOS;
++ icount->overrun++;
++ }
++ // check to see if we should ignore the character
++ // and mask off conditions that should be ignored
++ if (status & info->ignore_status_mask)
++ {
++ if (++ignore > 100 )
++ break;
++ goto ignore_char;
++ }
++ // Mask off the error conditions we want to ignore
++ tmp = status & info->read_status_mask;
++ if (tmp & RXPARERR)
++ {
++ flag_char = TTY_PARITY;
++ }
++ else
++ if (tmp & RXFRAMERR)
++ {
++ flag_char = TTY_FRAME;
++ }
++ if (tmp & RXOVFERR)
++ {
++ tty_insert_flip_char(tty, ch, flag_char);
++ ch = 0;
++ flag_char = TTY_OVERRUN;
++ if (!tty_buffer_request_room(tty, 1))
++ break;
++ }
++ }
++ tty_insert_flip_char(tty, ch, flag_char);
++ }
++ignore_char:;
++ tty_flip_buffer_push(tty);
++ tty_schedule_flip(tty);
++
++}
++
++
++/*
++ * ------------------------------------------------------------
++ * bcm_interrupt ()
++ *
++ * this is the main interrupt routine for the chip.
++ * It deals with the multiple ports.
++ * ------------------------------------------------------------
++ */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
++static irqreturn_t bcm_interrupt (int irq, void * dev, struct pt_regs * regs)
++#else
++static void bcm_interrupt (int irq, void * dev, struct pt_regs * regs)
++#endif
++{
++ struct bcm_serial * info = lines[0];
++ UINT16 intStat;
++
++ /* get pending interrupt flags from UART */
++
++ /* Mask with only the serial interrupts that are enabled */
++ intStat = info->port->intStatus & info->port->intMask;
++ while (intStat)
++ {
++ if (intStat & RXINT)
++ receive_chars (info);
++ else
++ if (intStat & TXINT)
++ info->port->intStatus = TXINT;
++ else /* don't know what it was, so let's mask it */
++ info->port->intMask &= ~intStat;
++
++ intStat = info->port->intStatus & info->port->intMask;
++ }
++
++ // Clear the interrupt
++ BcmHalInterruptEnable (INTERRUPT_ID_UART);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
++ return IRQ_HANDLED;
++#endif
++}
++
++/*
++ * -------------------------------------------------------------------
++ * startup ()
++ *
++ * various initialization tasks
++ * -------------------------------------------------------------------
++ */
++static int startup (struct bcm_serial *info)
++{
++ // Port is already started...
++ return 0;
++}
++
++/*
++ * -------------------------------------------------------------------
++ * shutdown ()
++ *
++ * This routine will shutdown a serial port; interrupts are disabled, and
++ * DTR is dropped if the hangup on close termio flag is on.
++ * -------------------------------------------------------------------
++ */
++static void shutdown (struct bcm_serial * info)
++{
++ unsigned long flags;
++ if (!info->is_initialized)
++ return;
++
++ spin_lock_irqsave(&bcm963xx_serial_lock, flags);
++
++ info->port->control &= ~(BRGEN|TXEN|RXEN);
++ if (info->tty)
++ set_bit (TTY_IO_ERROR, &info->tty->flags);
++ info->is_initialized = 0;
++
++ spin_unlock_irqrestore(&bcm963xx_serial_lock, flags);
++}
++/*
++ * -------------------------------------------------------------------
++ * change_speed ()
++ *
++ * Set the baud rate, character size, parity and stop bits.
++ * -------------------------------------------------------------------
++ */
++static void change_speed( volatile Uart *pUart, tcflag_t cFlag )
++{
++ unsigned long ulFlags, ulBaud, ulClockFreqHz, ulTmp;
++
++ spin_lock_irqsave(&bcm963xx_serial_lock, ulFlags);
++ switch( cFlag & (CBAUD | CBAUDEX) )
++ {
++ case B115200:
++ ulBaud = 115200;
++ break;
++ case B57600:
++ ulBaud = 57600;
++ break;
++ case B38400:
++ ulBaud = 38400;
++ break;
++ case B19200:
++ ulBaud = 19200;
++ break;
++ case B9600:
++ ulBaud = 9600;
++ break;
++ case B4800:
++ ulBaud = 4800;
++ break;
++ case B2400:
++ ulBaud = 2400;
++ break;
++ case B1800:
++ ulBaud = 1800;
++ break;
++ case B1200:
++ ulBaud = 1200;
++ break;
++ case B600:
++ ulBaud = 600;
++ break;
++ case B300:
++ ulBaud = 300;
++ break;
++ case B200:
++ ulBaud = 200;
++ break;
++ case B150:
++ ulBaud = 150;
++ break;
++ case B134:
++ ulBaud = 134;
++ break;
++ case B110:
++ ulBaud = 110;
++ break;
++ case B75:
++ ulBaud = 75;
++ break;
++ case B50:
++ ulBaud = 50;
++ break;
++ default:
++ ulBaud = 115200;
++ break;
++ }
++
++ /* Calculate buad rate. */
++ ulClockFreqHz = BD_BCM63XX_TIMER_CLOCK_INPUT;
++ ulTmp = (ulClockFreqHz / ulBaud) / 16;
++ if( ulTmp & 0x01 )
++ ulTmp /= 2; /* Rounding up, so sub is already accounted for */
++ else
++ ulTmp = (ulTmp / 2) - 1; /* Rounding down so we must sub 1 */
++ pUart->baudword = ulTmp;
++
++ /* Set character size, stop bits and parity. */
++ switch( cFlag & CSIZE )
++ {
++ case CS5:
++ ulTmp = BITS5SYM; /* select transmit 5 bit data size */
++ break;
++ case CS6:
++ ulTmp = BITS6SYM; /* select transmit 6 bit data size */
++ break;
++ case CS7:
++ ulTmp = BITS7SYM; /* select transmit 7 bit data size */
++ break;
++ default:
++ ulTmp = BITS8SYM; /* select transmit 8 bit data size */
++ break;
++ }
++ if( cFlag & CSTOPB )
++ ulTmp |= TWOSTOP; /* select 2 stop bits */
++ else
++ ulTmp |= ONESTOP; /* select one stop bit */
++
++ /* Write these values into the config reg. */
++ pUart->config = ulTmp;
++ pUart->control &= ~(RXPARITYEN | TXPARITYEN | RXPARITYEVEN | TXPARITYEVEN);
++ switch( cFlag & (PARENB | PARODD) )
++ {
++ case PARENB|PARODD:
++ pUart->control |= RXPARITYEN | TXPARITYEN;
++ break;
++ case PARENB:
++ pUart->control |= RXPARITYEN | TXPARITYEN | RXPARITYEVEN | TXPARITYEVEN;
++ break;
++ default:
++ pUart->control |= 0;
++ break;
++ }
++
++ /* Reset and flush uart */
++ pUart->fifoctl = RSTTXFIFOS | RSTRXFIFOS;
++ spin_unlock_irqrestore(&bcm963xx_serial_lock, ulFlags);
++}
++
++
++/*
++ * -------------------------------------------------------------------
++ * bcm_flush_char ()
++ *
++ * Nothing to flush. Polled I/O is used.
++ * -------------------------------------------------------------------
++ */
++static void bcm63xx_cons_flush_chars (struct tty_struct *tty)
++{
++}
++
++
++/*
++ * -------------------------------------------------------------------
++ * bcm63xx_cons_write ()
++ *
++ * Main output routine using polled I/O.
++ * -------------------------------------------------------------------
++ */
++static int bcm63xx_cons_write (struct tty_struct *tty,
++ const unsigned char *buf, int count)
++{
++ int c;
++
++ for (c = 0; c < count; c++)
++ _putc(buf[c]);
++ return count;
++}
++
++/*
++ * -------------------------------------------------------------------
++ * bcm63xx_cons_write_room ()
++ *
++ * Compute the amount of space available for writing.
++ * -------------------------------------------------------------------
++ */
++static int bcm63xx_cons_write_room (struct tty_struct *tty)
++{
++ /* Pick a number. Any number. Polled I/O is used. */
++ return 1024;
++}
++
++/*
++ * -------------------------------------------------------------------
++ * bcm_chars_in_buffer ()
++ *
++ * compute the amount of char left to be transmitted
++ * -------------------------------------------------------------------
++ */
++static int bcm_chars_in_buffer (struct tty_struct *tty)
++{
++ return 0;
++}
++
++/*
++ * -------------------------------------------------------------------
++ * bcm_flush_buffer ()
++ *
++ * Empty the output buffer
++ * -------------------------------------------------------------------
++ */
++static void bcm_flush_buffer (struct tty_struct *tty)
++{
++ tty_wakeup(tty);
++}
++
++/*
++ * ------------------------------------------------------------
++ * bcm_throttle () and bcm_unthrottle ()
++ *
++ * This routine is called by the upper-layer tty layer to signal that
++ * incoming characters should be throttled (or not).
++ * ------------------------------------------------------------
++ */
++static void bcm_throttle (struct tty_struct *tty)
++{
++ struct bcm_serial *info = (struct bcm_serial *)tty->driver_data;
++ if (I_IXOFF(tty))
++ info->x_char = STOP_CHAR(tty);
++}
++
++static void bcm_unthrottle (struct tty_struct *tty)
++{
++ struct bcm_serial *info = (struct bcm_serial *)tty->driver_data;
++ if (I_IXOFF(tty))
++ {
++ if (info->x_char)
++ info->x_char = 0;
++ else
++ info->x_char = START_CHAR(tty);
++ }
++}
++
++static void bcm_send_xchar (struct tty_struct *tty, char ch)
++{
++ struct bcm_serial *info = (struct bcm_serial *)tty->driver_data;
++ info->x_char = ch;
++ if (ch)
++ bcm_start (info->tty);
++}
++
++/*
++ * ------------------------------------------------------------
++ * rs_ioctl () and friends
++ * ------------------------------------------------------------
++ */
++static int get_serial_info(struct bcm_serial *info, struct serial_struct *retinfo)
++{
++ struct serial_struct tmp;
++
++ if (!retinfo)
++ return -EFAULT;
++
++ memset (&tmp, 0, sizeof(tmp));
++ tmp.type = info->type;
++ tmp.line = info->line;
++ tmp.port = (int) info->port;
++ tmp.irq = info->irq;
++ tmp.flags = 0;
++ tmp.baud_base = info->baud_base;
++ tmp.close_delay = info->close_delay;
++ tmp.closing_wait = info->closing_wait;
++
++ return copy_to_user (retinfo, &tmp, sizeof(*retinfo));
++}
++
++static int set_serial_info (struct bcm_serial *info, struct serial_struct *new_info)
++{
++ struct serial_struct new_serial;
++ struct bcm_serial old_info;
++ int retval = 0;
++
++ if (!new_info)
++ return -EFAULT;
++
++ copy_from_user (&new_serial, new_info, sizeof(new_serial));
++ old_info = *info;
++
++ if (!capable(CAP_SYS_ADMIN))
++ return -EPERM;
++
++
++ if (info->count > 1)
++ return -EBUSY;
++
++ /* OK, past this point, all the error checking has been done.
++ * At this point, we start making changes.....
++ */
++ info->baud_base = new_serial.baud_base;
++ info->type = new_serial.type;
++ info->close_delay = new_serial.close_delay;
++ info->closing_wait = new_serial.closing_wait;
++ retval = startup (info);
++ return retval;
++}
++
++/*
++ * get_lsr_info - get line status register info
++ *
++ * Purpose: Let user call ioctl() to get info when the UART physically
++ * is emptied. On bus types like RS485, the transmitter must
++ * release the bus after transmitting. This must be done when
++ * the transmit shift register is empty, not be done when the
++ * transmit holding register is empty. This functionality
++ * allows an RS485 driver to be written in user space.
++ */
++static int get_lsr_info (struct bcm_serial *info, unsigned int *value)
++{
++ return( 0 );
++}
++
++/*
++ * This routine sends a break character out the serial port.
++ */
++static void send_break (struct bcm_serial *info, int duration)
++{
++ unsigned long flags;
++
++ if (!info->port)
++ return;
++
++ current->state = TASK_INTERRUPTIBLE;
++
++ /*save_flags (flags);
++ cli();*/
++ spin_lock_irqsave(&bcm963xx_serial_lock, flags);
++
++ info->port->control |= XMITBREAK;
++ schedule_timeout(duration);
++ info->port->control &= ~XMITBREAK;
++
++ spin_unlock_irqrestore(&bcm963xx_serial_lock, flags);
++ //restore_flags (flags);
++}
++
++static int bcm_ioctl (struct tty_struct * tty, struct file * file,
++ unsigned int cmd, unsigned long arg)
++{
++ int error;
++ struct bcm_serial * info = (struct bcm_serial *)tty->driver_data;
++ int retval;
++
++ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
++ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
++ (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT))
++ {
++ if (tty->flags & (1 << TTY_IO_ERROR))
++ return -EIO;
++ }
++ switch (cmd)
++ {
++
++ case TCSBRK: /* SVID version: non-zero arg --> no break */
++ retval = tty_check_change (tty);
++ if (retval)
++ return retval;
++ tty_wait_until_sent (tty, 0);
++ if (!arg)
++ send_break (info, HZ/4); /* 1/4 second */
++ return 0;
++
++ case TCSBRKP: /* support for POSIX tcsendbreak() */
++ retval = tty_check_change (tty);
++ if (retval)
++ return retval;
++ tty_wait_until_sent (tty, 0);
++ send_break (info, arg ? arg*(HZ/10) : HZ/4);
++ return 0;
++
++ case TIOCGSOFTCAR:
++ error = access_ok (VERIFY_WRITE, (void *)arg, sizeof(long));
++ if (!error)
++ return -EFAULT;
++ else
++ {
++ put_user (C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);
++ return 0;
++ }
++
++ case TIOCSSOFTCAR:
++ error = get_user (arg, (unsigned long *)arg);
++ if (error)
++ return error;
++ tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
++ return 0;
++
++ case TIOCGSERIAL:
++ error = access_ok (VERIFY_WRITE, (void *)arg, sizeof(struct serial_struct));
++ if (!error)
++ return -EFAULT;
++ else
++ return get_serial_info (info, (struct serial_struct *)arg);
++
++ case TIOCSSERIAL:
++ return set_serial_info (info, (struct serial_struct *) arg);
++
++ case TIOCSERGETLSR: /* Get line status register */
++ error = access_ok (VERIFY_WRITE, (void *)arg, sizeof(unsigned int));
++ if (!error)
++ return -EFAULT;
++ else
++ return get_lsr_info (info, (unsigned int *)arg);
++
++ case TIOCSERGSTRUCT:
++ error = access_ok (VERIFY_WRITE, (void *)arg, sizeof(struct bcm_serial));
++ if (!error)
++ return -EFAULT;
++ else
++ {
++ copy_to_user((struct bcm_serial *)arg, info, sizeof(struct bcm_serial));
++ return 0;
++ }
++
++ default:
++ return -ENOIOCTLCMD;
++ }
++ return 0;
++}
++
++static void bcm_set_termios (struct tty_struct *tty, struct termios *old_termios)
++{
++ struct bcm_serial *info = (struct bcm_serial *)tty->driver_data;
++
++ if( tty->termios->c_cflag != old_termios->c_cflag )
++ change_speed (info->port, tty->termios->c_cflag);
++}
++
++/*
++ * ------------------------------------------------------------
++ * bcm63xx_cons_close()
++ *
++ * This routine is called when the serial port gets closed. First, we
++ * wait for the last remaining data to be sent. Then, we turn off
++ * the transmit enable and receive enable flags.
++ * ------------------------------------------------------------
++ */
++static void bcm63xx_cons_close (struct tty_struct *tty, struct file *filp)
++{
++ struct bcm_serial * info = (struct bcm_serial *)tty->driver_data;
++ unsigned long flags;
++
++ if (!info)
++ return;
++
++ /*save_flags (flags);
++ cli();*/
++ spin_lock_irqsave(&bcm963xx_serial_lock, flags);
++
++ if (tty_hung_up_p (filp))
++ {
++ spin_unlock_irqrestore(&bcm963xx_serial_lock, flags);
++ //restore_flags (flags);
++ return;
++ }
++
++ if ((tty->count == 1) && (info->count != 1))
++ {
++
++ /* Uh, oh. tty->count is 1, which means that the tty
++ * structure will be freed. Info->count should always
++ * be one in these conditions. If it's greater than
++ * one, we've got real problems, since it means the
++ * serial port won't be shutdown.
++ */
++ printk("bcm63xx_cons_close: bad serial port count; tty->count is 1, "
++ "info->count is %d\n", info->count);
++ info->count = 1;
++ }
++
++ if (--info->count < 0)
++ {
++ printk("ds_close: bad serial port count for ttys%d: %d\n",
++ info->line, info->count);
++ info->count = 0;
++ }
++
++ if (info->count)
++ {
++ //restore_flags (flags);
++ spin_unlock_irqrestore(&bcm963xx_serial_lock, flags);
++ return;
++ }
++
++ /* Now we wait for the transmit buffer to clear; and we notify
++ * the line discipline to only process XON/XOFF characters.
++ */
++ tty->closing = 1;
++
++ /* At this point we stop accepting input. To do this, we
++ * disable the receive line status interrupts.
++ */
++ shutdown (info);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
++ if (tty->driver->flush_buffer)
++ tty->driver->flush_buffer (tty);
++#else
++ if (tty->driver.flush_buffer)
++ tty->driver.flush_buffer (tty);
++#endif
++ if (tty->ldisc.flush_buffer)
++ tty->ldisc.flush_buffer (tty);
++
++ tty->closing = 0;
++ info->event = 0;
++ info->tty = 0;
++ if (tty->ldisc.num != tty_ldisc_get(N_TTY)->num)
++ {
++ if (tty->ldisc.close)
++ (tty->ldisc.close)(tty);
++ tty->ldisc = *tty_ldisc_get(N_TTY);
++ tty->termios->c_line = N_TTY;
++ if (tty->ldisc.open)
++ (tty->ldisc.open)(tty);
++ }
++ if (info->blocked_open)
++ {
++ if (info->close_delay)
++ {
++ current->state = TASK_INTERRUPTIBLE;
++ schedule_timeout(info->close_delay);
++ }
++ wake_up_interruptible (&info->open_wait);
++ }
++ wake_up_interruptible (&info->close_wait);
++
++ //restore_flags (flags);
++ spin_unlock_irqrestore(&bcm963xx_serial_lock, flags);
++}
++
++/*
++ * bcm_hangup () --- called by tty_hangup() when a hangup is signaled.
++ */
++static void bcm_hangup (struct tty_struct *tty)
++{
++
++ struct bcm_serial *info = (struct bcm_serial *)tty->driver_data;
++
++ shutdown (info);
++ info->event = 0;
++ info->count = 0;
++ info->tty = 0;
++ wake_up_interruptible (&info->open_wait);
++}
++
++/*
++ * ------------------------------------------------------------
++ * rs_open() and friends
++ * ------------------------------------------------------------
++ */
++static int block_til_ready (struct tty_struct *tty, struct file *filp,
++ struct bcm_serial *info)
++{
++ return 0;
++}
++
++/*
++ * This routine is called whenever a serial port is opened. It
++ * enables interrupts for a serial port. It also performs the
++ * serial-specific initialization for the tty structure.
++ */
++static int bcm63xx_cons_open (struct tty_struct * tty, struct file * filp)
++{
++ struct bcm_serial *info;
++ int retval, line;
++
++ // Make sure we're only opening on of the ports we support
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
++ line = MINOR(tty->driver->cdev.dev) - tty->driver->minor_start;
++#else
++ line = MINOR(tty->device) - tty->driver.minor_start;
++#endif
++
++ if ((line < 0) || (line >= BCM_NUM_UARTS))
++ return -ENODEV;
++
++ info = lines[line];
++
++ tty->low_latency=1;
++ info->port->intMask = 0; /* Clear any pending interrupts */
++ info->port->intMask = RXINT; /* Enable RX */
++
++ info->count++;
++ tty->driver_data = info;
++ info->tty = tty;
++ BcmHalInterruptEnable (INTERRUPT_ID_UART);
++
++ // Start up serial port
++ retval = startup (info);
++ if (retval)
++ return retval;
++
++ retval = block_til_ready (tty, filp, info);
++ if (retval)
++ return retval;
++
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
++ info->pgrp = process_group(current);
++ info->session = current->signal->session;
++#else
++ info->session = current->session;
++ info->pgrp = current->pgrp;
++#endif
++
++ return 0;
++}
++
++
++static struct tty_operations rs_ops = {
++ .open = bcm63xx_cons_open,
++ .close = bcm63xx_cons_close,
++ .write = bcm63xx_cons_write,
++ .flush_chars = bcm63xx_cons_flush_chars,
++ .write_room = bcm63xx_cons_write_room,
++ .chars_in_buffer = bcm_chars_in_buffer,
++ .flush_buffer = bcm_flush_buffer,
++ .ioctl = bcm_ioctl,
++ .throttle = bcm_throttle,
++ .unthrottle = bcm_unthrottle,
++ .send_xchar = bcm_send_xchar,
++ .set_termios = bcm_set_termios,
++ .stop = bcm_stop,
++ .start = bcm_start,
++ .hangup = bcm_hangup,
++};
++
++/* --------------------------------------------------------------------------
++ Name: bcm63xx_serialinit
++ Purpose: Initialize our BCM63xx serial driver
++-------------------------------------------------------------------------- */
++static int __init bcm63xx_serialinit(void)
++{
++ int i, flags;
++ struct bcm_serial * info;
++
++ // Print the driver version information
++ printk(VER_STR);
++ serial_driver = alloc_tty_driver(BCM_NUM_UARTS);
++ if (!serial_driver)
++ return -ENOMEM;
++
++ serial_driver->owner = THIS_MODULE;
++ serial_driver->devfs_name = "tts/";
++// serial_driver.magic = TTY_DRIVER_MAGIC;
++ serial_driver->name = "ttyS";
++ serial_driver->major = TTY_MAJOR;
++ serial_driver->minor_start = 64;
++// serial_driver.num = BCM_NUM_UARTS;
++ serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
++ serial_driver->subtype = SERIAL_TYPE_NORMAL;
++ serial_driver->init_termios = tty_std_termios;
++ serial_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
++ serial_driver->flags = TTY_DRIVER_REAL_RAW;
++
++ serial_driver->termios = serial_termios;
++ serial_driver->termios_locked = serial_termios_locked;
++
++ tty_set_operations(serial_driver, &rs_ops);
++
++ if (tty_register_driver (serial_driver))
++ panic("Couldn't register serial driver\n");
++
++ //save_flags(flags); cli();
++ spin_lock_irqsave(&bcm963xx_serial_lock, flags);
++
++ for (i = 0; i < BCM_NUM_UARTS; i++)
++ {
++ info = &multi[i];
++ lines[i] = info;
++ info->magic = SERIAL_MAGIC;
++ info->port = (Uart *) ((char *)UART_BASE + (i * 0x20));
++ info->tty = 0;
++ info->irq = (2 - i) + 8;
++ info->line = i;
++ info->close_delay = 50;
++ info->closing_wait = 3000;
++ info->x_char = 0;
++ info->event = 0;
++ info->count = 0;
++ info->blocked_open = 0;
++ info->normal_termios = serial_driver->init_termios;
++ init_waitqueue_head(&info->open_wait);
++ init_waitqueue_head(&info->close_wait);
++
++ /* If we are pointing to address zero then punt - not correctly
++ * set up in setup.c to handle this.
++ */
++ if (! info->port)
++ return 0;
++ BcmHalMapInterrupt(bcm_interrupt, 0, INTERRUPT_ID_UART);
++ }
++
++ /* order matters here... the trick is that flags
++ * is updated... in request_irq - to immediatedly obliterate
++ * it is unwise.
++ */
++ spin_unlock_irqrestore(&bcm963xx_serial_lock, flags);
++ return 0;
++}
++
++module_init(bcm63xx_serialinit);
++
++/* --------------------------------------------------------------------------
++ Name: bcm_console_print
++ Purpose: bcm_console_print is registered for printk.
++ The console_lock must be held when we get here.
++-------------------------------------------------------------------------- */
++static void bcm_console_print (struct console * cons, const char * str,
++ unsigned int count)
++{
++ unsigned int i;
++ //_puts(str);
++ for(i=0; i<count; i++, str++)
++ {
++ _putc(*str);
++ if (*str == 10)
++ {
++ _putc(13);
++ }
++ }
++}
++
++static struct tty_driver * bcm_console_device(struct console * c, int *index)
++{
++ *index = c->index;
++ return serial_driver;
++}
++
++static int __init bcm_console_setup(struct console * co, char * options)
++{
++ return 0;
++}
++
++static struct console bcm_sercons = {
++ .name = "ttyS",
++ .write = bcm_console_print,
++ .device = bcm_console_device,
++ .setup = bcm_console_setup,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++};
++
++static int __init bcm63xx_console_init(void)
++{
++ register_console(&bcm_sercons);
++ return 0;
++}
++
++console_initcall(bcm63xx_console_init);
+diff -urN linux.old/drivers/serial/Makefile linux.dev/drivers/serial/Makefile
+--- linux.old/drivers/serial/Makefile 2006-06-18 03:49:35.000000000 +0200
++++ linux.dev/drivers/serial/Makefile 2006-08-25 15:38:44.000000000 +0200
+@@ -55,3 +55,4 @@
+ obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
+ obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
+ obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
++obj-$(CONFIG_BCM_SERIAL) += bcm63xx_cons.o
+diff -urN linux.old/include/asm-mips/bootinfo.h linux.dev/include/asm-mips/bootinfo.h
+--- linux.old/include/asm-mips/bootinfo.h 2006-08-25 00:43:22.000000000 +0200
++++ linux.dev/include/asm-mips/bootinfo.h 2006-08-25 00:39:38.000000000 +0200
+@@ -218,6 +218,14 @@
+ #define MACH_GROUP_TITAN 22 /* PMC-Sierra Titan */
+ #define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */
+
++/*
++ * Valid machtype for group BRCM
++ */
++#define MACH_GROUP_BRCM 23 /* Broadcom boards */
++#define MACH_BCM96338 0
++#define MACH_BCM96345 1
++#define MACH_BCM96348 2
++
+ #define CL_SIZE COMMAND_LINE_SIZE
+
+ const char *get_system_type(void);
+diff -urN linux.old/include/asm-mips/cpu.h linux.dev/include/asm-mips/cpu.h
+--- linux.old/include/asm-mips/cpu.h 2006-08-25 00:43:22.000000000 +0200
++++ linux.dev/include/asm-mips/cpu.h 2006-08-25 00:39:38.000000000 +0200
+@@ -103,6 +103,13 @@
+
+ #define PRID_IMP_SR71000 0x0400
+
++/* These are the PRID's for when 23:16 == PRID_COMP_BROADCOM
++ */
++
++#define PRID_IMP_BCM6338 0x9000
++#define PRID_IMP_BCM6345 0x8000
++#define PRID_IMP_BCM6348 0x9100
++
+ /*
+ * Definitions for 7:0 on legacy processors
+ */
+@@ -200,7 +207,10 @@
+ #define CPU_SB1A 62
+ #define CPU_74K 63
+ #define CPU_R14000 64
+-#define CPU_LAST 64
++#define CPU_BCM6338 65
++#define CPU_BCM6345 66
++#define CPU_BCM6348 67
++#define CPU_LAST 67
+
+ /*
+ * ISA Level encodings
+diff -urN linux.old/include/asm-mips/mach-bcm963xx/cpu-feature-overrides.h linux.dev/include/asm-mips/mach-bcm963xx/cpu-feature-overrides.h
+--- linux.old/include/asm-mips/mach-bcm963xx/cpu-feature-overrides.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/mach-bcm963xx/cpu-feature-overrides.h 2006-08-25 11:27:40.000000000 +0200
+@@ -0,0 +1,36 @@
++#ifndef __ASM_MACH_BCM963XX_CPU_FEATURE_OVERRIDES_H
++#define __ASM_MACH_BCM963XX_CPU_FEATURE_OVERRIDES_H
++
++#define cpu_has_tlb 1
++#define cpu_has_4kex 4
++#define cpu_has_4ktlb 8
++#define cpu_has_fpu 0
++#define cpu_has_32fpr 0
++#define cpu_has_counter 0x40
++#define cpu_has_watch 0
++#define cpu_has_mips16 0
++#define cpu_has_divec 0x200
++#define cpu_has_vce 0
++#define cpu_has_cache_cdex_p 0
++#define cpu_has_cache_cdex_s 0
++#define cpu_has_prefetch 0x40000
++#define cpu_has_mcheck 0x2000
++#define cpu_has_ejtag 0x4000
++#define cpu_has_llsc 0x10000
++#define cpu_has_vtag_icache 0
++#define cpu_has_dc_aliases 0
++#define cpu_has_ic_fills_f_dc 0
++
++#define cpu_has_nofpuex 0
++#define cpu_has_64bits 0
++#define cpu_has_64bit_zero_reg 0
++#define cpu_has_64bit_gp_regs 0
++#define cpu_has_64bit_addresses 0
++
++#define cpu_has_subset_pcaches 0
++
++#define cpu_dcache_line_size() 16
++#define cpu_icache_line_size() 16
++#define cpu_scache_line_size() 0
++
++#endif /* __ASM_MACH_BCM963XX_CPU_FEATURE_OVERRIDES_H */
+diff -urN linux.old/include/asm-mips/mach-generic/param.h linux.dev/include/asm-mips/mach-generic/param.h
+--- linux.old/include/asm-mips/mach-generic/param.h 2006-08-25 00:43:22.000000000 +0200
++++ linux.dev/include/asm-mips/mach-generic/param.h 2006-08-25 00:39:38.000000000 +0200
+@@ -8,6 +8,6 @@
+ #ifndef __ASM_MACH_GENERIC_PARAM_H
+ #define __ASM_MACH_GENERIC_PARAM_H
+
+-#define HZ 1000 /* Internal kernel timer frequency */
++#define HZ 200 /* Internal kernel timer frequency */
+
+ #endif /* __ASM_MACH_GENERIC_PARAM_H */
+diff -urN linux.old/include/asm-mips/module.h linux.dev/include/asm-mips/module.h
+--- linux.old/include/asm-mips/module.h 2006-08-25 00:43:22.000000000 +0200
++++ linux.dev/include/asm-mips/module.h 2006-08-25 00:39:38.000000000 +0200
+@@ -113,6 +113,12 @@
+ #define MODULE_PROC_FAMILY "RM9000 "
+ #elif defined CONFIG_CPU_SB1
+ #define MODULE_PROC_FAMILY "SB1 "
++#elif defined CONFIG_CPU_BCM6338
++#define MODULE_PROC_FAMILY "BCM6338 "
++#elif defined CONFIG_CPU_BCM6345
++#define MODULE_PROC_FAMILY "BCM6345 "
++#elif defined CONFIG_CPU_BCM6348
++#define MODULE_PROC_FAMILY "BCM6348 "
+ #else
+ #error MODULE_PROC_FAMILY undefined for your processor configuration
+ #endif
+
diff --git a/target/linux/brcm63xx-2.6/patches/040-bcm963xx_flashmap.patch b/target/linux/brcm63xx-2.6/patches/040-bcm963xx_flashmap.patch
new file mode 100644
index 0000000..997cc98
--- /dev/null
+++ b/target/linux/brcm63xx-2.6/patches/040-bcm963xx_flashmap.patch
@@ -0,0 +1,213 @@
+diff -urN linux-2.6.17/drivers/mtd/maps/bcm963xx-flash.c linux-2.6.17-brcm63xx/drivers/mtd/maps/bcm963xx-flash.c
+--- linux-2.6.17/drivers/mtd/maps/bcm963xx-flash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-brcm63xx/drivers/mtd/maps/bcm963xx-flash.c 2006-08-30 13:03:16.000000000 +0200
+@@ -0,0 +1,135 @@
++/*
++ * $Id$
++ * Copyright (C) 2006 Florian Fainelli
++ * Copyright (C) $Date$ $Author$
++ *
++ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/* This is the BCM963xx flash map driver, in its actual state it only supports BCM96348 devices
++ * this driver is able to manage both bootloader we found on these boards : CFE and RedBoot
++ *
++ * RedBoot :
++ * - this bootloader allows us to parse partitions and therefore deduce the MTD partition table
++ *
++ * CFE :
++ * - we have to use a "physically mapped flash" defined bellow
++ *
++ */
++
++#include <asm/io.h>
++#include <linux/init.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <board.h>
++
++#define WINDOW_ADDR 0x1e400000 /* Real address of the flash */
++#define WINDOW_SIZE 0x800000 /* Size of flash */
++#define BUSWIDTH 2 /* Buswidth */
++#define EXTENDED_SIZE 0xBE400000 /* Extended flash addresse */
++
++extern int boot_loader_type; /* For RedBoot / CFE detection */
++extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts, unsigned long fis_origin);
++static struct mtd_partition *parsed_parts;
++
++static void __exit bcm963xx_mtd_cleanup(void);
++
++static struct mtd_info *bcm963xx_mtd_info;
++
++static struct map_info bcm963xx_map = {
++ .name = "bcm963xx",
++ .size = WINDOW_SIZE,
++ .bankwidth = BUSWIDTH,
++ .phys = WINDOW_ADDR,
++};
++
++static struct mtd_partition bcm963xx_parts[] = {
++ { name: "bootloader", size: 0, offset: 0, mask_flags: MTD_WRITEABLE },
++ { name: "rootfs", size: 0, offset: 0},
++ { name: "jffs2", size: 5 * 0x10000, offset: 57*0x10000}
++};
++
++static int bcm963xx_parts_size = sizeof(bcm963xx_parts) / sizeof(bcm963xx_parts[0]);
++
++static int __init bcm963xx_mtd_init(void)
++{
++ printk("bcm963xx: 0x%08x at 0x%08x\n", WINDOW_SIZE, WINDOW_ADDR);
++ bcm963xx_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
++
++ if (!bcm963xx_map.virt) {
++ printk("bcm963xx: Failed to ioremap\n");
++ return -EIO;
++ }
++
++ simple_map_init(&bcm963xx_map);
++
++ bcm963xx_mtd_info = do_map_probe("cfi_probe", &bcm963xx_map);
++
++ if (bcm963xx_mtd_info) {
++ bcm963xx_mtd_info->owner = THIS_MODULE;
++
++ if (boot_loader_type == BOOT_CFE)
++ {
++ add_mtd_device(bcm963xx_mtd_info);
++ add_mtd_partitions(bcm963xx_mtd_info, bcm963xx_parts, bcm963xx_parts_size);
++ return 0;
++ }
++ else
++ {
++ int parsed_nr_parts = 0;
++ char * part_type;
++
++ if (bcm963xx_mtd_info->size > 0x00400000) {
++ printk("Support for extended flash memory size : 0x%08X ; ONLY 64MBIT SUPPORT\n", bcm963xx_mtd_info->size);
++ bcm963xx_map.virt = (unsigned long)(EXTENDED_SIZE);
++ }
++
++#ifdef CONFIG_MTD_REDBOOT_PARTS
++ if (parsed_nr_parts == 0) {
++ int ret = parse_redboot_partitions(bcm963xx_mtd_info, &parsed_parts, 0);
++ if (ret > 0) {
++ part_type = "RedBoot";
++ parsed_nr_parts = ret;
++ }
++ }
++#endif
++ add_mtd_partitions(bcm963xx_mtd_info, parsed_parts, parsed_nr_parts);
++
++ return 0;
++ }
++ }
++ iounmap(bcm963xx_map.virt);
++ return -ENXIO;
++}
++
++static void __exit bcm963xx_mtd_cleanup(void)
++{
++ if (bcm963xx_mtd_info) {
++ del_mtd_partitions(bcm963xx_mtd_info);
++ map_destroy(bcm963xx_mtd_info);
++ }
++
++ if (bcm963xx_map.virt) {
++ iounmap(bcm963xx_map.virt);
++ bcm963xx_map.virt = 0;
++ }
++}
++
++module_init(bcm963xx_mtd_init);
++module_exit(bcm963xx_mtd_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
+diff -urN linux-2.6.17/drivers/mtd/maps/Kconfig linux-2.6.17-brcm63xx/drivers/mtd/maps/Kconfig
+--- linux-2.6.17/drivers/mtd/maps/Kconfig 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-brcm63xx/drivers/mtd/maps/Kconfig 2006-08-30 13:03:06.000000000 +0200
+@@ -224,6 +224,13 @@
+ Flash memory access on 4G Systems MTX-1 Board. If you have one of
+ these boards and would like to use the flash chips on it, say 'Y'.
+
++config MTD_BCM963XX
++ tristate "BCM963xx Flash device"
++ depends on MIPS && MIPS_BRCM
++ help
++ Flash memory access on BCM963xx boards. Currently only works with
++ RedBoot, CFE support coming soon.
++
+ config MTD_DILNETPC
+ tristate "CFI Flash device mapped on DIL/Net PC"
+ depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT
+diff -urN linux-2.6.17/drivers/mtd/maps/Makefile linux-2.6.17-brcm63xx/drivers/mtd/maps/Makefile
+--- linux-2.6.17/drivers/mtd/maps/Makefile 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-brcm63xx/drivers/mtd/maps/Makefile 2006-08-30 13:03:06.000000000 +0200
+@@ -71,3 +71,4 @@
+ obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o
+ obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o
+ obj-$(CONFIG_MTD_TQM834x) += tqm834x.o
++obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o
+diff -urN linux-2.6.17/drivers/mtd/redboot.c linux-2.6.17-brcm63xx/drivers/mtd/redboot.c
+--- linux-2.6.17/drivers/mtd/redboot.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-brcm63xx/drivers/mtd/redboot.c 2006-08-30 13:03:06.000000000 +0200
+@@ -39,7 +39,7 @@
+ return 1;
+ }
+
+-static int parse_redboot_partitions(struct mtd_info *master,
++int parse_redboot_partitions(struct mtd_info *master,
+ struct mtd_partition **pparts,
+ unsigned long fis_origin)
+ {
+@@ -120,11 +120,19 @@
+ goto out;
+ }
+
++ if (!fis_origin) {
++ for (i = 0; i < numslots; i++) {
++ if (!strncmp(buf[i].name, "RedBoot", 8)) {
++ fis_origin = (buf[i].flash_base & (master->size << 1) - 1);
++ }
++ }
++ }
++
+ for (i = 0; i < numslots; i++) {
+ struct fis_list *new_fl, **prev;
+
+ if (buf[i].name[0] == 0xff)
+- continue;
++ break;
+ if (!redboot_checksum(&buf[i]))
+ break;
+
+@@ -135,11 +143,10 @@
+ goto out;
+ }
+ new_fl->img = &buf[i];
+- if (fis_origin) {
+- buf[i].flash_base -= fis_origin;
+- } else {
+- buf[i].flash_base &= master->size-1;
+- }
++ if (fis_origin) {
++ buf[i].flash_base -= fis_origin;
++ }
++ buf[i].flash_base &= (master->size << 1) - 1;
+
+ /* I'm sure the JFFS2 code has done me permanent damage.
+ * I now think the following is _normal_
diff --git a/target/linux/brcm63xx-2.6/patches/100-binary_hacks.patch b/target/linux/brcm63xx-2.6/patches/100-binary_hacks.patch
new file mode 100644
index 0000000..d81d978
--- /dev/null
+++ b/target/linux/brcm63xx-2.6/patches/100-binary_hacks.patch
@@ -0,0 +1,267 @@
+diff -urN linux.old/include/asm-mips/cpu-info.h linux.dev/include/asm-mips/cpu-info.h
+--- linux.old/include/asm-mips/cpu-info.h 2006-06-18 03:49:35.000000000 +0200
++++ linux.dev/include/asm-mips/cpu-info.h 2006-08-27 21:02:04.000000000 +0200
+@@ -63,7 +63,6 @@
+ * Capability and feature descriptor structure for MIPS CPU
+ */
+ unsigned long options;
+- unsigned long ases;
+ unsigned int processor_id;
+ unsigned int fpu_id;
+ unsigned int cputype;
+@@ -84,6 +83,7 @@
+ int tc_id; /* Thread Context number */
+ #endif /* CONFIG_MIPS_MT */
+ void *data; /* Additional data */
++ unsigned long ases;
+ } __attribute__((aligned(SMP_CACHE_BYTES)));
+
+ extern struct cpuinfo_mips cpu_data[];
+
+diff -urN linux.old/include/linux/netdevice.h linux.dev/include/linux/netdevice.h
+--- linux.old/include/linux/netdevice.h 2006-06-18 03:49:35.000000000 +0200
++++ linux.dev/include/linux/netdevice.h 2006-08-27 21:02:04.000000000 +0200
+@@ -266,8 +266,6 @@
+ * the interface.
+ */
+ char name[IFNAMSIZ];
+- /* device name hash chain */
+- struct hlist_node name_hlist;
+
+ /*
+ * I/O specific fields
+@@ -295,22 +293,6 @@
+
+ /* ------- Fields preinitialized in Space.c finish here ------- */
+
+- /* Net device features */
+- unsigned long features;
+-#define NETIF_F_SG 1 /* Scatter/gather IO. */
+-#define NETIF_F_IP_CSUM 2 /* Can checksum only TCP/UDP over IPv4. */
+-#define NETIF_F_NO_CSUM 4 /* Does not require checksum. F.e. loopack. */
+-#define NETIF_F_HW_CSUM 8 /* Can checksum all the packets. */
+-#define NETIF_F_HIGHDMA 32 /* Can DMA to high memory. */
+-#define NETIF_F_FRAGLIST 64 /* Scatter/gather IO. */
+-#define NETIF_F_HW_VLAN_TX 128 /* Transmit VLAN hw acceleration */
+-#define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */
+-#define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */
+-#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */
+-#define NETIF_F_TSO 2048 /* Can offload TCP/IP segmentation */
+-#define NETIF_F_LLTX 4096 /* LockLess TX */
+-#define NETIF_F_UFO 8192 /* Can offload UDP Large Send*/
+-
+ struct net_device *next_sched;
+
+ /* Interface index. Unique device identifier */
+@@ -324,8 +306,6 @@
+ /* List of functions to handle Wireless Extensions (instead of ioctl).
+ * See <net/iw_handler.h> for details. Jean II */
+ const struct iw_handler_def * wireless_handlers;
+- /* Instance data managed by the core of Wireless Extensions. */
+- struct iw_public_data * wireless_data;
+
+ struct ethtool_ops *ethtool_ops;
+
+@@ -335,33 +315,37 @@
+ * will (read: may be cleaned up at will).
+ */
+
++ /* These may be needed for future network-power-down code. */
++ unsigned long trans_start; /* Time (in jiffies) of last Tx */
++ unsigned long last_rx; /* Time of last Rx */
+
+- unsigned int flags; /* interface flags (a la BSD) */
++ unsigned short flags; /* interface flags (a la BSD) */
+ unsigned short gflags;
+ unsigned short priv_flags; /* Like 'flags' but invisible to userspace. */
+- unsigned short padded; /* How much padding added by alloc_netdev() */
+-
+- unsigned char operstate; /* RFC2863 operstate */
+- unsigned char link_mode; /* mapping policy to operstate */
++ unsigned short __useless_padding;
+
+ unsigned mtu; /* interface MTU value */
+ unsigned short type; /* interface hardware type */
+ unsigned short hard_header_len; /* hardware hdr length */
++ void *priv; /* pointer to private data */
+
+ struct net_device *master; /* Pointer to master device of a group,
+ * which this device is member of.
+ */
+
+ /* Interface address info. */
+- unsigned char perm_addr[MAX_ADDR_LEN]; /* permanent hw address */
++ unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */
++ unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address, (before bcast
++ because most packets are unicast) */
+ unsigned char addr_len; /* hardware address length */
+- unsigned short dev_id; /* for shared network cards */
+
+ struct dev_mc_list *mc_list; /* Multicast mac addresses */
+ int mc_count; /* Number of installed mcasts */
+ int promiscuity;
+ int allmulti;
+
++ int watchdog_timeo; /* used by dev_watchdog() */
++ struct timer_list watchdog_timer;
+
+ /* Protocol specific pointers */
+
+@@ -378,29 +362,17 @@
+ struct list_head poll_list ____cacheline_aligned_in_smp;
+ /* Link to poll list */
+
+- int (*poll) (struct net_device *dev, int *quota);
+ int quota;
+ int weight;
+- unsigned long last_rx; /* Time of last Rx */
+ /* Interface address info used in eth_type_trans() */
+- unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address, (before bcast
+- because most packets are unicast) */
+-
+- unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */
+-
+-/*
+- * Cache line mostly used on queue transmit path (qdisc)
+- */
+- /* device queue lock */
+- spinlock_t queue_lock ____cacheline_aligned_in_smp;
+ struct Qdisc *qdisc;
+ struct Qdisc *qdisc_sleeping;
++ struct Qdisc *qdisc_ingress;
+ struct list_head qdisc_list;
+ unsigned long tx_queue_len; /* Max frames per queue allowed */
+
+ /* ingress path synchronizer */
+ spinlock_t ingress_lock;
+- struct Qdisc *qdisc_ingress;
+
+ /*
+ * One part is mostly used on xmit path (device)
+@@ -411,16 +383,13 @@
+ if nobody entered there.
+ */
+ int xmit_lock_owner;
+- void *priv; /* pointer to private data */
+- int (*hard_start_xmit) (struct sk_buff *skb,
+- struct net_device *dev);
+- /* These may be needed for future network-power-down code. */
+- unsigned long trans_start; /* Time (in jiffies) of last Tx */
+-
+- int watchdog_timeo; /* used by dev_watchdog() */
+- struct timer_list watchdog_timer;
+
+ /*
++ * Cache line mostly used on queue transmit path (qdisc)
++ */
++ /* device queue lock */
++ spinlock_t queue_lock ____cacheline_aligned_in_smp;
++/*
+ * refcnt is a very hot point, so align it on SMP
+ */
+ /* Number of references to this device */
+@@ -428,6 +397,8 @@
+
+ /* delayed register/unregister */
+ struct list_head todo_list;
++ /* device name hash chain */
++ struct hlist_node name_hlist;
+ /* device index hash chain */
+ struct hlist_node index_hlist;
+
+@@ -439,6 +410,22 @@
+ NETREG_RELEASED, /* called free_netdev */
+ } reg_state;
+
++ /* Net device features */
++ unsigned int features;
++#define NETIF_F_SG 1 /* Scatter/gather IO. */
++#define NETIF_F_IP_CSUM 2 /* Can checksum only TCP/UDP over IPv4. */
++#define NETIF_F_NO_CSUM 4 /* Does not require checksum. F.e. loopack. */
++#define NETIF_F_HW_CSUM 8 /* Can checksum all the packets. */
++#define NETIF_F_HIGHDMA 32 /* Can DMA to high memory. */
++#define NETIF_F_FRAGLIST 64 /* Scatter/gather IO. */
++#define NETIF_F_HW_VLAN_TX 128 /* Transmit VLAN hw acceleration */
++#define NETIF_F_HW_VLAN_RX 256 /* Receive VLAN hw acceleration */
++#define NETIF_F_HW_VLAN_FILTER 512 /* Receive filtering on VLAN */
++#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */
++#define NETIF_F_TSO 2048 /* Can offload TCP/IP segmentation */
++#define NETIF_F_LLTX 4096 /* LockLess TX */
++#define NETIF_F_UFO 8192 /* Can offload UDP Large Send*/
++
+ /* Called after device is detached from network. */
+ void (*uninit)(struct net_device *dev);
+ /* Called after last user reference disappears. */
+@@ -447,7 +434,10 @@
+ /* Pointers to interface service routines. */
+ int (*open)(struct net_device *dev);
+ int (*stop)(struct net_device *dev);
++ int (*hard_start_xmit) (struct sk_buff *skb,
++ struct net_device *dev);
+ #define HAVE_NETDEV_POLL
++ int (*poll) (struct net_device *dev, int *quota);
+ int (*hard_header) (struct sk_buff *skb,
+ struct net_device *dev,
+ unsigned short type,
+@@ -490,6 +480,7 @@
+ int (*neigh_setup)(struct net_device *dev, struct neigh_parms *);
+ #ifdef CONFIG_NETPOLL
+ struct netpoll_info *npinfo;
++ int netpoll_rx;
+ #endif
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ void (*poll_controller)(struct net_device *dev);
+@@ -507,6 +498,17 @@
+ struct class_device class_dev;
+ /* space for optional statistics and wireless sysfs groups */
+ struct attribute_group *sysfs_groups[3];
++
++ unsigned char operstate; /* RFC2863 operstate */
++ unsigned char link_mode; /* mapping policy to operstate */
++ unsigned short dev_id; /* for shared network cards */
++
++ /* Instance data managed by the core of Wireless Extensions. */
++ struct iw_public_data * wireless_data;
++
++ unsigned char perm_addr[MAX_ADDR_LEN]; /* permanent hw address */
++
++ unsigned short padded; /* How much padding added by alloc_netdev() */
+ };
+
+ #define NETDEV_ALIGN 32
+@@ -587,9 +589,10 @@
+
+ struct softnet_data
+ {
+- struct net_device *output_queue;
++ int useless_padding[3];
+ struct sk_buff_head input_pkt_queue;
+ struct list_head poll_list;
++ struct net_device *output_queue;
+ struct sk_buff *completion_queue;
+
+ struct net_device backlog_dev; /* Sorry. 8) */
+diff -urN linux.old/include/linux/timer.h linux.dev/include/linux/timer.h
+--- linux.old/include/linux/timer.h 2006-06-18 03:49:35.000000000 +0200
++++ linux.dev/include/linux/timer.h 2006-08-27 21:02:04.000000000 +0200
+@@ -12,6 +12,9 @@
+ struct list_head entry;
+ unsigned long expires;
+
++ spinlock_t lock;
++ unsigned long magic;
++
+ void (*function)(unsigned long);
+ unsigned long data;
+
+diff -urN linux.old/kernel/timer.c linux.dev/kernel/timer.c
+--- linux.old/kernel/timer.c 2006-06-18 03:49:35.000000000 +0200
++++ linux.dev/kernel/timer.c 2006-08-27 21:02:04.000000000 +0200
+@@ -147,6 +147,7 @@
+ {
+ timer->entry.next = NULL;
+ timer->base = per_cpu(tvec_bases, raw_smp_processor_id());
++ spin_lock_init(&timer->lock);
+ }
+ EXPORT_SYMBOL(init_timer);
+
diff --git a/target/linux/control/kernel.control b/target/linux/control/kernel.control
new file mode 100644
index 0000000..be5f109
--- /dev/null
+++ b/target/linux/control/kernel.control
@@ -0,0 +1,4 @@
+Package: kernel
+Priority: optional
+Section: sys
+Description: Virtual package for the Kernel
diff --git a/target/linux/control/kmod-atm.control b/target/linux/control/kmod-atm.control
new file mode 100644
index 0000000..ae07126
--- /dev/null
+++ b/target/linux/control/kmod-atm.control
@@ -0,0 +1,4 @@
+Package: kmod-atm
+Priority: optional
+Section: sys
+Description: ATM/ADSL support
diff --git a/target/linux/control/kmod-ax25.control b/target/linux/control/kmod-ax25.control
new file mode 100644
index 0000000..18c4cef
--- /dev/null
+++ b/target/linux/control/kmod-ax25.control
@@ -0,0 +1,4 @@
+Package: kmod-ax25
+Priority: optional
+Section: net
+Description: Kernel AX25 driver
diff --git a/target/linux/control/kmod-bluetooth.control b/target/linux/control/kmod-bluetooth.control
new file mode 100644
index 0000000..9f5409a
--- /dev/null
+++ b/target/linux/control/kmod-bluetooth.control
@@ -0,0 +1,4 @@
+Package: kmod-bluetooth
+Priority: optional
+Section: sys
+Description: Bluetooth support
diff --git a/target/linux/control/kmod-brcm-et.control b/target/linux/control/kmod-brcm-et.control
new file mode 100644
index 0000000..3e65bc9
--- /dev/null
+++ b/target/linux/control/kmod-brcm-et.control
@@ -0,0 +1,4 @@
+Package: kmod-brcm-et
+Priority: optional
+Section: sys
+Description: Proprietary driver for Broadcom Ethernet chipsets
diff --git a/target/linux/control/kmod-brcm-wl.control b/target/linux/control/kmod-brcm-wl.control
new file mode 100644
index 0000000..cf610c3
--- /dev/null
+++ b/target/linux/control/kmod-brcm-wl.control
@@ -0,0 +1,4 @@
+Package: kmod-brcm-wl
+Priority: optional
+Section: sys
+Description: Proprietary driver for Broadcom Wireless chipsets
diff --git a/target/linux/control/kmod-brcm-wl2.control b/target/linux/control/kmod-brcm-wl2.control
new file mode 100644
index 0000000..4ae019d
--- /dev/null
+++ b/target/linux/control/kmod-brcm-wl2.control
@@ -0,0 +1,5 @@
+Package: kmod-brcm-wl2
+Priority: optional
+Section: sys
+Description: Proprietary driver for Broadcom Wireless chipsets
+ New version with multi-BSS support
diff --git a/target/linux/control/kmod-cpmac.control b/target/linux/control/kmod-cpmac.control
new file mode 100644
index 0000000..18f8e90
--- /dev/null
+++ b/target/linux/control/kmod-cpmac.control
@@ -0,0 +1,4 @@
+Package: kmod-cpmac
+Priority: optional
+Section: sys
+Description: AR7 CPMAC ethernet driver
diff --git a/target/linux/control/kmod-fs-cifs.control b/target/linux/control/kmod-fs-cifs.control
new file mode 100644
index 0000000..8322247
--- /dev/null
+++ b/target/linux/control/kmod-fs-cifs.control
@@ -0,0 +1,4 @@
+Package: kmod-fs-cifs
+Priority: optional
+Section: sys
+Description: Kernel modules for CIFS support
diff --git a/target/linux/control/kmod-fs-ext2.control b/target/linux/control/kmod-fs-ext2.control
new file mode 100644
index 0000000..ec06cff
--- /dev/null
+++ b/target/linux/control/kmod-fs-ext2.control
@@ -0,0 +1,4 @@
+Package: kmod-fs-ext2
+Priority: optional
+Section: sys
+Description: Kernel modules for EXT2 filesystem support
diff --git a/target/linux/control/kmod-fs-ext3.control b/target/linux/control/kmod-fs-ext3.control
new file mode 100644
index 0000000..7351788
--- /dev/null
+++ b/target/linux/control/kmod-fs-ext3.control
@@ -0,0 +1,4 @@
+Package: kmod-fs-ext3
+Priority: optional
+Section: sys
+Description: Kernel modules for EXT3 filesystem support
diff --git a/target/linux/control/kmod-fs-hfsplus.control b/target/linux/control/kmod-fs-hfsplus.control
new file mode 100644
index 0000000..bb59553
--- /dev/null
+++ b/target/linux/control/kmod-fs-hfsplus.control
@@ -0,0 +1,4 @@
+Package: kmod-fs-hfsplus
+Priority: optional
+Section: sys
+Description: Kernel modules for HFS+ filesystem support
diff --git a/target/linux/control/kmod-fs-minix.control b/target/linux/control/kmod-fs-minix.control
new file mode 100644
index 0000000..2169ba6
--- /dev/null
+++ b/target/linux/control/kmod-fs-minix.control
@@ -0,0 +1,4 @@
+Package: kmod-fs-minix
+Priority: optional
+Section: sys
+Description: Kernel modules for MINIX filesystem support
diff --git a/target/linux/control/kmod-fs-nfs.control b/target/linux/control/kmod-fs-nfs.control
new file mode 100644
index 0000000..32dc9ff
--- /dev/null
+++ b/target/linux/control/kmod-fs-nfs.control
@@ -0,0 +1,4 @@
+Package: kmod-fs-nfs
+Priority: optional
+Section: sys
+Description: Kernel modules for NFS support
diff --git a/target/linux/control/kmod-fs-vfat.control b/target/linux/control/kmod-fs-vfat.control
new file mode 100644
index 0000000..cc29833
--- /dev/null
+++ b/target/linux/control/kmod-fs-vfat.control
@@ -0,0 +1,4 @@
+Package: kmod-fs-vfat
+Priority: optional
+Section: sys
+Description: Kernel modules for VFAT filesystem support
diff --git a/target/linux/control/kmod-fs-xfs.control b/target/linux/control/kmod-fs-xfs.control
new file mode 100644
index 0000000..8efd35a
--- /dev/null
+++ b/target/linux/control/kmod-fs-xfs.control
@@ -0,0 +1,4 @@
+Package: kmod-fs-xfs
+Priority: optional
+Section: sys
+Description: Kernel modules for XFS filesystem support
diff --git a/target/linux/control/kmod-imq.control b/target/linux/control/kmod-imq.control
new file mode 100644
index 0000000..78925a4
--- /dev/null
+++ b/target/linux/control/kmod-imq.control
@@ -0,0 +1,4 @@
+Package: kmod-imq
+Priority: optional
+Section: net
+Description: Kernel support for the Intermediate Queueing device
diff --git a/target/linux/control/kmod-iptables-extra.control b/target/linux/control/kmod-iptables-extra.control
new file mode 100644
index 0000000..96a3b1a
--- /dev/null
+++ b/target/linux/control/kmod-iptables-extra.control
@@ -0,0 +1,4 @@
+Package: kmod-iptables-extra
+Priority: optional
+Section: net
+Description: Extra kernel modules for iptables
diff --git a/target/linux/control/kmod-iptables.control b/target/linux/control/kmod-iptables.control
new file mode 100644
index 0000000..7f97cc4
--- /dev/null
+++ b/target/linux/control/kmod-iptables.control
@@ -0,0 +1,4 @@
+Package: kmod-iptables
+Priority: optional
+Section: net
+Description: kernel modules for iptables
diff --git a/target/linux/control/kmod-loop.control b/target/linux/control/kmod-loop.control
new file mode 100644
index 0000000..48bcb83
--- /dev/null
+++ b/target/linux/control/kmod-loop.control
@@ -0,0 +1,4 @@
+Package: kmod-loop
+Priority: optional
+Section: sys
+Description: Kernel module for mount loopback support
diff --git a/target/linux/control/kmod-lp.control b/target/linux/control/kmod-lp.control
new file mode 100644
index 0000000..5d40813
--- /dev/null
+++ b/target/linux/control/kmod-lp.control
@@ -0,0 +1,4 @@
+Package: kmod-lp
+Priority: optional
+Section: sys
+Description: Kernel modules for parallel port support and line printer
diff --git a/target/linux/control/kmod-nbd.control b/target/linux/control/kmod-nbd.control
new file mode 100644
index 0000000..3c46722
--- /dev/null
+++ b/target/linux/control/kmod-nbd.control
@@ -0,0 +1,4 @@
+Package: kmod-nbd
+Priority: optional
+Section: sys
+Description: Kernel module for network block device
diff --git a/target/linux/control/kmod-net-airo.control b/target/linux/control/kmod-net-airo.control
new file mode 100644
index 0000000..3693df5
--- /dev/null
+++ b/target/linux/control/kmod-net-airo.control
@@ -0,0 +1,4 @@
+Package: kmod-net-airo
+Priority: optional
+Section: sys
+Description: Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards kernel support
diff --git a/target/linux/control/kmod-net-hermes-pci.control b/target/linux/control/kmod-net-hermes-pci.control
new file mode 100644
index 0000000..911609d
--- /dev/null
+++ b/target/linux/control/kmod-net-hermes-pci.control
@@ -0,0 +1,4 @@
+Package: kmod-net-hermes-pci
+Priority: optional
+Section: sys
+Description: Intersil Prism 2.5 PCI 802.11b adaptor support
diff --git a/target/linux/control/kmod-net-hermes-plx.control b/target/linux/control/kmod-net-hermes-plx.control
new file mode 100644
index 0000000..8df0727
--- /dev/null
+++ b/target/linux/control/kmod-net-hermes-plx.control
@@ -0,0 +1,4 @@
+Package: kmod-net-hermes-plx
+Priority: optional
+Section: sys
+Description: Hermes in PLX9052 based PCI adaptor (Netgear MA301, etc.) kernel support
diff --git a/target/linux/control/kmod-net-hermes.control b/target/linux/control/kmod-net-hermes.control
new file mode 100644
index 0000000..7fa91a9
--- /dev/null
+++ b/target/linux/control/kmod-net-hermes.control
@@ -0,0 +1,4 @@
+Package: kmod-net-hermes
+Priority: optional
+Section: sys
+Description: Hermes chipset 802.11b support (Orinoco/Prism2/Symbol) kernel support
diff --git a/target/linux/control/kmod-net-prism54.control b/target/linux/control/kmod-net-prism54.control
new file mode 100644
index 0000000..2ba3111
--- /dev/null
+++ b/target/linux/control/kmod-net-prism54.control
@@ -0,0 +1,4 @@
+Package: kmod-net-prism54
+Priority: optional
+Section: sys
+Description: Intersil Prism GT/Duette/Indigo PCI/PCMCIA cards kernel support
diff --git a/target/linux/control/kmod-nls-base.control b/target/linux/control/kmod-nls-base.control
new file mode 100644
index 0000000..067f5de
--- /dev/null
+++ b/target/linux/control/kmod-nls-base.control
@@ -0,0 +1,4 @@
+Package: kmod-nls-base
+Priority: optional
+Section: sys
+Description: Kernel modules for basic native language support
diff --git a/target/linux/control/kmod-nls-cp437.control b/target/linux/control/kmod-nls-cp437.control
new file mode 100644
index 0000000..f471460
--- /dev/null
+++ b/target/linux/control/kmod-nls-cp437.control
@@ -0,0 +1,4 @@
+Package: kmod-nls-cp437
+Priority: optional
+Section: sys
+Description: Kernel module for codepage 437
diff --git a/target/linux/control/kmod-nls-cp850.control b/target/linux/control/kmod-nls-cp850.control
new file mode 100644
index 0000000..1a7d083
--- /dev/null
+++ b/target/linux/control/kmod-nls-cp850.control
@@ -0,0 +1,4 @@
+Package: kmod-nls-cp850
+Priority: optional
+Section: sys
+Description: Kernel module for codepage 850
diff --git a/target/linux/control/kmod-nls-iso8859-1.control b/target/linux/control/kmod-nls-iso8859-1.control
new file mode 100644
index 0000000..91e40fa
--- /dev/null
+++ b/target/linux/control/kmod-nls-iso8859-1.control
@@ -0,0 +1,4 @@
+Package: kmod-nls-iso8859-1
+Priority: optional
+Section: sys
+Description: Kernel module for iso8859-1 charset support
diff --git a/target/linux/control/kmod-nls-iso8859-15.control b/target/linux/control/kmod-nls-iso8859-15.control
new file mode 100644
index 0000000..f565e37
--- /dev/null
+++ b/target/linux/control/kmod-nls-iso8859-15.control
@@ -0,0 +1,4 @@
+Package: kmod-nls-iso8859-15
+Priority: optional
+Section: sys
+Description: Kernel module for iso8859-15 charset support
diff --git a/target/linux/control/kmod-nls-utf8.control b/target/linux/control/kmod-nls-utf8.control
new file mode 100644
index 0000000..8c5b23c
--- /dev/null
+++ b/target/linux/control/kmod-nls-utf8.control
@@ -0,0 +1,4 @@
+Package: kmod-nls-utf8
+Priority: optional
+Section: sys
+Description: Kernel module for utf8 support
diff --git a/target/linux/control/kmod-pcmcia-core.control b/target/linux/control/kmod-pcmcia-core.control
new file mode 100644
index 0000000..3e137ea
--- /dev/null
+++ b/target/linux/control/kmod-pcmcia-core.control
@@ -0,0 +1,4 @@
+Package: kmod-pcmcia-core
+Priority: optional
+Section: sys
+Description: PCMCIA/CardBus kernel support
diff --git a/target/linux/control/kmod-pcmcia-serial.control b/target/linux/control/kmod-pcmcia-serial.control
new file mode 100644
index 0000000..7e8a03c
--- /dev/null
+++ b/target/linux/control/kmod-pcmcia-serial.control
@@ -0,0 +1,4 @@
+Package: kmod-pcmcia-serial
+Priority: optional
+Section: sys
+Description: PCMCIA/CardBus serial device support
diff --git a/target/linux/control/kmod-pwc.control b/target/linux/control/kmod-pwc.control
new file mode 100644
index 0000000..2860eed
--- /dev/null
+++ b/target/linux/control/kmod-pwc.control
@@ -0,0 +1,4 @@
+Package: kmod-pwc
+Priority: optional
+Section: sys
+Description: Kernel driver for USB Philips Cameras
diff --git a/target/linux/control/kmod-sangam-atm-annex-a.control b/target/linux/control/kmod-sangam-atm-annex-a.control
new file mode 100644
index 0000000..e07e724
--- /dev/null
+++ b/target/linux/control/kmod-sangam-atm-annex-a.control
@@ -0,0 +1,4 @@
+Package: kmod-sangam-atm-annex-a
+Priority: optional
+Section: sys
+Description: AR7 Sangam ATM/ADSL driver (Annex A version)
diff --git a/target/linux/control/kmod-sangam-atm-annex-b.control b/target/linux/control/kmod-sangam-atm-annex-b.control
new file mode 100644
index 0000000..7e6ff3f
--- /dev/null
+++ b/target/linux/control/kmod-sangam-atm-annex-b.control
@@ -0,0 +1,4 @@
+Package: kmod-sangam-atm-annex-b
+Priority: optional
+Section: sys
+Description: AR7 Sangam ATM/ADSL driver (Annex B version)
diff --git a/target/linux/control/kmod-softdog.control b/target/linux/control/kmod-softdog.control
new file mode 100644
index 0000000..01aff7f
--- /dev/null
+++ b/target/linux/control/kmod-softdog.control
@@ -0,0 +1,4 @@
+Package: kmod-softdog
+Priority: optional
+Section: sys
+Description: Kernel software watchdog driver
diff --git a/target/linux/control/kmod-soundcore.control b/target/linux/control/kmod-soundcore.control
new file mode 100644
index 0000000..6b4fffa
--- /dev/null
+++ b/target/linux/control/kmod-soundcore.control
@@ -0,0 +1,4 @@
+Package: kmod-soundcore
+Priority: optional
+Section: sys
+Description: Kernel support for audio soundcards
diff --git a/target/linux/control/kmod-usb-acm.control b/target/linux/control/kmod-usb-acm.control
new file mode 100644
index 0000000..8d1fca4
--- /dev/null
+++ b/target/linux/control/kmod-usb-acm.control
@@ -0,0 +1,4 @@
+Package: kmod-usb-acm
+Priority: optional
+Section: sys
+Description: Kernel modules for USB modems and ISDN
diff --git a/target/linux/control/kmod-usb-atm-speedtouch.control b/target/linux/control/kmod-usb-atm-speedtouch.control
new file mode 100644
index 0000000..e8ded69
--- /dev/null
+++ b/target/linux/control/kmod-usb-atm-speedtouch.control
@@ -0,0 +1,4 @@
+Package: kmod-usb-atm-speedtouch
+Priority: optional
+Section: sys
+Description: Kernel driver for USB Speedtouch ADSL modem
diff --git a/target/linux/control/kmod-usb-atm.control b/target/linux/control/kmod-usb-atm.control
new file mode 100644
index 0000000..0f4adad
--- /dev/null
+++ b/target/linux/control/kmod-usb-atm.control
@@ -0,0 +1,5 @@
+Package: kmod-usb-atm
+Priority: optional
+Section: sys
+Source: buildroot internal
+Description: Kernel modules for USB ATM support
diff --git a/target/linux/control/kmod-usb-audio.control b/target/linux/control/kmod-usb-audio.control
new file mode 100644
index 0000000..d30b8f2
--- /dev/null
+++ b/target/linux/control/kmod-usb-audio.control
@@ -0,0 +1,5 @@
+Package: kmod-usb-audio
+Priority: optional
+Section: sys
+Depends: kmod-soundcore
+Description: Kernel Support for USB Soundcards
diff --git a/target/linux/control/kmod-usb-core.control b/target/linux/control/kmod-usb-core.control
new file mode 100644
index 0000000..fa1c13b
--- /dev/null
+++ b/target/linux/control/kmod-usb-core.control
@@ -0,0 +1,4 @@
+Package: kmod-usb-core
+Priority: optional
+Section: sys
+Description: Kernel Support for USB
diff --git a/target/linux/control/kmod-usb-ohci.control b/target/linux/control/kmod-usb-ohci.control
new file mode 100644
index 0000000..3d0edc8
--- /dev/null
+++ b/target/linux/control/kmod-usb-ohci.control
@@ -0,0 +1,4 @@
+Package: kmod-usb-ohci
+Priority: optional
+Section: sys
+Description: Kernel driver for OHCI USB controllers
diff --git a/target/linux/control/kmod-usb-printer.control b/target/linux/control/kmod-usb-printer.control
new file mode 100644
index 0000000..1c47a3d
--- /dev/null
+++ b/target/linux/control/kmod-usb-printer.control
@@ -0,0 +1,4 @@
+Package: kmod-usb-printer
+Priority: optional
+Section: sys
+Description: Kernel modules for USB Printer support
diff --git a/target/linux/control/kmod-usb-serial-belkin.control b/target/linux/control/kmod-usb-serial-belkin.control
new file mode 100644
index 0000000..d907a97
--- /dev/null
+++ b/target/linux/control/kmod-usb-serial-belkin.control
@@ -0,0 +1,4 @@
+Package: kmod-usb-serial-belkin
+Priority: optional
+Section: sys
+Description: Kernel Support for Belkin USB-to-Serial converters
diff --git a/target/linux/control/kmod-usb-serial-ftdi.control b/target/linux/control/kmod-usb-serial-ftdi.control
new file mode 100644
index 0000000..e845294
--- /dev/null
+++ b/target/linux/control/kmod-usb-serial-ftdi.control
@@ -0,0 +1,4 @@
+Package: kmod-usb-serial-ftdi
+Priority: optional
+Section: sys
+Description: Kernel Support for FTDI USB-to-Serial converters
diff --git a/target/linux/control/kmod-usb-serial-mct-u232.control b/target/linux/control/kmod-usb-serial-mct-u232.control
new file mode 100644
index 0000000..b52b7ca
--- /dev/null
+++ b/target/linux/control/kmod-usb-serial-mct-u232.control
@@ -0,0 +1,4 @@
+Package: kmod-usb-serial-mct-u232
+Priority: optional
+Section: sys
+Description: Kernel Support for Magic Control Technology USB-to-Serial converters
diff --git a/target/linux/control/kmod-usb-serial-pl2303.control b/target/linux/control/kmod-usb-serial-pl2303.control
new file mode 100644
index 0000000..4de43bd
--- /dev/null
+++ b/target/linux/control/kmod-usb-serial-pl2303.control
@@ -0,0 +1,4 @@
+Package: kmod-usb-serial-pl2303
+Priority: optional
+Section: sys
+Description: Kernel Support for Prolific PL2303 USB-to-Serial converters
diff --git a/target/linux/control/kmod-usb-serial-visor.control b/target/linux/control/kmod-usb-serial-visor.control
new file mode 100644
index 0000000..951c00c
--- /dev/null
+++ b/target/linux/control/kmod-usb-serial-visor.control
@@ -0,0 +1,4 @@
+Package: kmod-usb-serial-visor
+Priority: optional
+Section: sys
+Description: Kernel Support for Handspring Visor / Palm m50x / Sony Clie Driver
diff --git a/target/linux/control/kmod-usb-serial.control b/target/linux/control/kmod-usb-serial.control
new file mode 100644
index 0000000..136fca7
--- /dev/null
+++ b/target/linux/control/kmod-usb-serial.control
@@ -0,0 +1,4 @@
+Package: kmod-usb-serial
+Priority: optional
+Section: sys
+Description: Kernel Support for USB-to-Serial converters
diff --git a/target/linux/control/kmod-usb-storage.control b/target/linux/control/kmod-usb-storage.control
new file mode 100644
index 0000000..4ee70eb
--- /dev/null
+++ b/target/linux/control/kmod-usb-storage.control
@@ -0,0 +1,4 @@
+Package: kmod-usb-storage
+Priority: optional
+Section: sys
+Description: Kernel modules for USB storage support
diff --git a/target/linux/control/kmod-usb-uhci.control b/target/linux/control/kmod-usb-uhci.control
new file mode 100644
index 0000000..09966a8
--- /dev/null
+++ b/target/linux/control/kmod-usb-uhci.control
@@ -0,0 +1,4 @@
+Package: kmod-usb-uhci
+Priority: optional
+Section: sys
+Description: Kernel driver for UHCI USB controllers
diff --git a/target/linux/control/kmod-usb2.control b/target/linux/control/kmod-usb2.control
new file mode 100644
index 0000000..338865e
--- /dev/null
+++ b/target/linux/control/kmod-usb2.control
@@ -0,0 +1,4 @@
+Package: kmod-usb2
+Priority: optional
+Section: sys
+Description: Kernel driver for USB2 controllers
diff --git a/target/linux/control/kmod-videodev.control b/target/linux/control/kmod-videodev.control
new file mode 100644
index 0000000..57c0b1c
--- /dev/null
+++ b/target/linux/control/kmod-videodev.control
@@ -0,0 +1,4 @@
+Package: kmod-videodev
+Priority: optional
+Section: sys
+Description: Video For Linux kernel support
diff --git a/target/linux/control/kmod-wd1100.control b/target/linux/control/kmod-wd1100.control
new file mode 100644
index 0000000..3216320
--- /dev/null
+++ b/target/linux/control/kmod-wd1100.control
@@ -0,0 +1,4 @@
+Package: kmod-wd1100
+Priority: optional
+Section: sys
+Description: NatSemi SC1x00 series Watchdog kernel support
diff --git a/target/linux/generic-2.4/README b/target/linux/generic-2.4/README
new file mode 100644
index 0000000..15d9523
--- /dev/null
+++ b/target/linux/generic-2.4/README
@@ -0,0 +1,98 @@
+Description of kernel patches:
+
+
+generic/
+ Generic patches for vanilla Linux kernel
+
+000-linux_mips.patch
+ This is the diff between vanilla linux-2.4.32 and linux-mips.org kernel
+ (CVS tag 2_4_32-rc1 used). The kernel source from linux-mips.org CVS repository has
+ newer drivers and code then vanilla linux-2.4.32 especially for the mips architecture.
+
+001-squashfs.patch
+ Support for the squashfs filesystem. It has better compression ratio then cramfs.
+
+002-squashfs_lzma.patch
+ LZMA Addon patch from Oleg I. Vdovikin for the squashfs filesystem.
+ Even better compression ratio.
+
+003-jffs2_compression.patch
+ Compression for jffs2 filesystem.
+
+004-exec_pagesize.patch
+
+005-mtd_flashtypes.patch
+ Additional mtd drivers for flash chips
+
+100-ebtables.patch
+ Filtering packets on ethernet layer. See http://ebtables.sf.net
+
+101-netfilter_ipp2p.patch
+ Netfilter ipp2p match module (matches traffic of most P2P networks)
+
+102-netfilter_layer7.patch
+
+103-netfilter_nat_pptp.patch
+ NAT support for PPTP and GRE
+
+104-netfilter_maxconn.patch
+
+105-netfilter_TTL.patch
+ Netfilter target for manipulating the TTL of IP packets
+
+106-mppe_mppc.patch
+ Microsoft PPP Encryption/Compression
+
+107-cifs.patch
+ CIFS (Common Internet File System) module.
+
+108-optional_aout_support.patch
+
+109-ipsec_nat_traversal.patch
+ Openswan patch for allowing IPSec through NAT
+
+110-netdev_random_core.patch
+ Support for gathering entropy from network devices for /dev/random
+
+200-i4l.patch
+
+201-hfc_usb_backport.patch
+
+202-pl2303_backport.patch
+
+203-hfsplus_fix.patch
+
+204-net_b44.patch
+ Support for the BCM47xx chipset in the b44 driver
+
+206-gcc_3.4_fixes.patch
+ mips specific gcc 3.4 fixes
+
+207-gcc_4.0_fixes.patch
+ gcc 4.0 fixes
+
+
+brcm/
+ Broadcom specific patches
+
+001-bcm47xx.patch
+ This is the broadcom specific code from asus (1941) GPL source tarball.
+ There are many small patches included, so it works with linux 2.4.32 kernel.
+ The original code is based on Linux 2.4.20.
+
+002-wl_fix.patch
+ The driver for the wireless lan chip on brcm47xx based routers is binary only.
+ This means it depends on older data structures in the kernel. We backported some
+ of the changes or changed some of the data structures to work with the binary modul.
+ This is a really bad hack, but without source code, there is no better chance to get
+ the driver working with newer kernels.
+
+003-bcm47xx_cache_fixes.patch
+
+
+ar7/
+ TI AR7 specific patches
+
+000-ar7_support.patch
+
+001-flash_map.patch
diff --git a/target/linux/generic-2.4/patches/000-linux_mips.patch b/target/linux/generic-2.4/patches/000-linux_mips.patch
new file mode 100644
index 0000000..16177c5
--- /dev/null
+++ b/target/linux/generic-2.4/patches/000-linux_mips.patch
@@ -0,0 +1,27959 @@
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/common/au1xxx_irqmap.c linux-2.4.32-rc1.mips/arch/mips/au1000/common/au1xxx_irqmap.c
+--- linux-2.4.32-rc1/arch/mips/au1000/common/au1xxx_irqmap.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/common/au1xxx_irqmap.c 2005-01-30 09:01:27.000000000 +0100
+@@ -172,14 +172,14 @@
+ { AU1550_PSC1_INT, INTC_INT_HIGH_LEVEL, 0},
+ { AU1550_PSC2_INT, INTC_INT_HIGH_LEVEL, 0},
+ { AU1550_PSC3_INT, INTC_INT_HIGH_LEVEL, 0},
+- { AU1550_TOY_INT, INTC_INT_RISE_EDGE, 0 },
+- { AU1550_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
+- { AU1550_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
+- { AU1550_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
+- { AU1550_RTC_INT, INTC_INT_RISE_EDGE, 0 },
+- { AU1550_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
+- { AU1550_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
+- { AU1550_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
++ { AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 },
++ { AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
++ { AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
++ { AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
++ { AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 },
++ { AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
++ { AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
++ { AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
+ { AU1550_NAND_INT, INTC_INT_RISE_EDGE, 0},
+ { AU1550_USB_DEV_REQ_INT, INTC_INT_HIGH_LEVEL, 0 },
+ { AU1550_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
+@@ -200,14 +200,14 @@
+ { AU1200_PSC1_INT, INTC_INT_HIGH_LEVEL, 0},
+ { AU1200_AES_INT, INTC_INT_HIGH_LEVEL, 0},
+ { AU1200_CAMERA_INT, INTC_INT_HIGH_LEVEL, 0},
+- { AU1200_TOY_INT, INTC_INT_RISE_EDGE, 0 },
+- { AU1200_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
+- { AU1200_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
+- { AU1200_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
+- { AU1200_RTC_INT, INTC_INT_RISE_EDGE, 0 },
+- { AU1200_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
+- { AU1200_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
+- { AU1200_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
++ { AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 },
++ { AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
++ { AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
++ { AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
++ { AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 },
++ { AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
++ { AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
++ { AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
+ { AU1200_NAND_INT, INTC_INT_RISE_EDGE, 0},
+ { AU1200_USB_INT, INTC_INT_HIGH_LEVEL, 0 },
+ { AU1200_LCD_INT, INTC_INT_HIGH_LEVEL, 0},
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/common/cputable.c linux-2.4.32-rc1.mips/arch/mips/au1000/common/cputable.c
+--- linux-2.4.32-rc1/arch/mips/au1000/common/cputable.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/common/cputable.c 2005-01-30 09:01:27.000000000 +0100
+@@ -39,7 +39,8 @@
+ { 0xffffffff, 0x02030203, "Au1100 BD", 0, 1 },
+ { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 },
+ { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 },
+- { 0xffffffff, 0x04030200, "Au1200 AA", 0, 1 },
++ { 0xffffffff, 0x04030200, "Au1200 AB", 0, 0 },
++ { 0xffffffff, 0x04030201, "Au1200 AC", 0, 0 },
+ { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 },
+ };
+
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/common/dbdma.c linux-2.4.32-rc1.mips/arch/mips/au1000/common/dbdma.c
+--- linux-2.4.32-rc1/arch/mips/au1000/common/dbdma.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/common/dbdma.c 2005-02-08 07:28:37.000000000 +0100
+@@ -41,6 +41,8 @@
+ #include <asm/au1xxx_dbdma.h>
+ #include <asm/system.h>
+
++#include <linux/module.h>
++
+ #if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
+
+ /*
+@@ -60,37 +62,10 @@
+ */
+ #define ALIGN_ADDR(x, a) ((((u32)(x)) + (a-1)) & ~(a-1))
+
+-static volatile dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE;
+-static int dbdma_initialized;
++static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE;
++static int dbdma_initialized=0;
+ static void au1xxx_dbdma_init(void);
+
+-typedef struct dbdma_device_table {
+- u32 dev_id;
+- u32 dev_flags;
+- u32 dev_tsize;
+- u32 dev_devwidth;
+- u32 dev_physaddr; /* If FIFO */
+- u32 dev_intlevel;
+- u32 dev_intpolarity;
+-} dbdev_tab_t;
+-
+-typedef struct dbdma_chan_config {
+- u32 chan_flags;
+- u32 chan_index;
+- dbdev_tab_t *chan_src;
+- dbdev_tab_t *chan_dest;
+- au1x_dma_chan_t *chan_ptr;
+- au1x_ddma_desc_t *chan_desc_base;
+- au1x_ddma_desc_t *get_ptr, *put_ptr, *cur_ptr;
+- void *chan_callparam;
+- void (*chan_callback)(int, void *, struct pt_regs *);
+-} chan_tab_t;
+-
+-#define DEV_FLAGS_INUSE (1 << 0)
+-#define DEV_FLAGS_ANYUSE (1 << 1)
+-#define DEV_FLAGS_OUT (1 << 2)
+-#define DEV_FLAGS_IN (1 << 3)
+-
+ static dbdev_tab_t dbdev_tab[] = {
+ #ifdef CONFIG_SOC_AU1550
+ /* UARTS */
+@@ -156,13 +131,13 @@
+ { DSCR_CMD0_MAE_BOTH, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+ { DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+
+- { DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
+- { DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+- { DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
+- { DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
++ { DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8, 0x10600000, 0, 0 },
++ { DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 4, 8, 0x10600004, 0, 0 },
++ { DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 4, 8, 0x10680000, 0, 0 },
++ { DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 4, 8, 0x10680004, 0, 0 },
+
+- { DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
+- { DSCR_CMD0_AES_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
++ { DSCR_CMD0_AES_RX, DEV_FLAGS_IN , 4, 32, 0x10300008, 0, 0 },
++ { DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 4, 32, 0x10300004, 0, 0 },
+
+ { DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 },
+ { DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 },
+@@ -172,9 +147,9 @@
+ { DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 },
+ { DSCR_CMD0_PSC1_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+
+- { DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+- { DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+- { DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
++ { DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 32, 0x14004020, 0, 0 },
++ { DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 32, 0x14004040, 0, 0 },
++ { DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 32, 0x14004060, 0, 0 },
+ { DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+
+ { DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+@@ -183,6 +158,24 @@
+
+ { DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+ { DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
++
++ /* Provide 16 user definable device types */
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
++ { 0, 0, 0, 0, 0, 0, 0 },
+ };
+
+ #define DBDEV_TAB_SIZE (sizeof(dbdev_tab) / sizeof(dbdev_tab_t))
+@@ -202,6 +195,30 @@
+ return NULL;
+ }
+
++u32
++au1xxx_ddma_add_device(dbdev_tab_t *dev)
++{
++ u32 ret = 0;
++ dbdev_tab_t *p=NULL;
++ static u16 new_id=0x1000;
++
++ p = find_dbdev_id(0);
++ if ( NULL != p )
++ {
++ memcpy(p, dev, sizeof(dbdev_tab_t));
++ p->dev_id = DSCR_DEV2CUSTOM_ID(new_id,dev->dev_id);
++ ret = p->dev_id;
++ new_id++;
++#if 0
++ printk("add_device: id:%x flags:%x padd:%x\n",
++ p->dev_id, p->dev_flags, p->dev_physaddr );
++#endif
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL(au1xxx_ddma_add_device);
++
+ /* Allocate a channel and return a non-zero descriptor if successful.
+ */
+ u32
+@@ -214,7 +231,7 @@
+ int i;
+ dbdev_tab_t *stp, *dtp;
+ chan_tab_t *ctp;
+- volatile au1x_dma_chan_t *cp;
++ au1x_dma_chan_t *cp;
+
+ /* We do the intialization on the first channel allocation.
+ * We have to wait because of the interrupt handler initialization
+@@ -224,9 +241,6 @@
+ au1xxx_dbdma_init();
+ dbdma_initialized = 1;
+
+- if ((srcid > DSCR_NDEV_IDS) || (destid > DSCR_NDEV_IDS))
+- return 0;
+-
+ if ((stp = find_dbdev_id(srcid)) == NULL) return 0;
+ if ((dtp = find_dbdev_id(destid)) == NULL) return 0;
+
+@@ -268,9 +282,9 @@
+ /* If kmalloc fails, it is caught below same
+ * as a channel not available.
+ */
+- ctp = (chan_tab_t *)kmalloc(sizeof(chan_tab_t), GFP_KERNEL);
++ ctp = (chan_tab_t *)
++ kmalloc(sizeof(chan_tab_t), GFP_KERNEL);
+ chan_tab_ptr[i] = ctp;
+- ctp->chan_index = chan = i;
+ break;
+ }
+ }
+@@ -278,10 +292,11 @@
+
+ if (ctp != NULL) {
+ memset(ctp, 0, sizeof(chan_tab_t));
++ ctp->chan_index = chan = i;
+ dcp = DDMA_CHANNEL_BASE;
+ dcp += (0x0100 * chan);
+ ctp->chan_ptr = (au1x_dma_chan_t *)dcp;
+- cp = (volatile au1x_dma_chan_t *)dcp;
++ cp = (au1x_dma_chan_t *)dcp;
+ ctp->chan_src = stp;
+ ctp->chan_dest = dtp;
+ ctp->chan_callback = callback;
+@@ -298,6 +313,9 @@
+ i |= DDMA_CFG_DED;
+ if (dtp->dev_intpolarity)
+ i |= DDMA_CFG_DP;
++ if ((stp->dev_flags & DEV_FLAGS_SYNC) ||
++ (dtp->dev_flags & DEV_FLAGS_SYNC))
++ i |= DDMA_CFG_SYNC;
+ cp->ddma_cfg = i;
+ au_sync();
+
+@@ -308,14 +326,14 @@
+ rv = (u32)(&chan_tab_ptr[chan]);
+ }
+ else {
+- /* Release devices.
+- */
++ /* Release devices */
+ stp->dev_flags &= ~DEV_FLAGS_INUSE;
+ dtp->dev_flags &= ~DEV_FLAGS_INUSE;
+ }
+ }
+ return rv;
+ }
++EXPORT_SYMBOL(au1xxx_dbdma_chan_alloc);
+
+ /* Set the device width if source or destination is a FIFO.
+ * Should be 8, 16, or 32 bits.
+@@ -343,6 +361,7 @@
+
+ return rv;
+ }
++EXPORT_SYMBOL(au1xxx_dbdma_set_devwidth);
+
+ /* Allocate a descriptor ring, initializing as much as possible.
+ */
+@@ -369,7 +388,8 @@
+ * and if we try that first we are likely to not waste larger
+ * slabs of memory.
+ */
+- desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t), GFP_KERNEL);
++ desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t),
++ GFP_KERNEL|GFP_DMA);
+ if (desc_base == 0)
+ return 0;
+
+@@ -380,7 +400,7 @@
+ kfree((const void *)desc_base);
+ i = entries * sizeof(au1x_ddma_desc_t);
+ i += (sizeof(au1x_ddma_desc_t) - 1);
+- if ((desc_base = (u32)kmalloc(i, GFP_KERNEL)) == 0)
++ if ((desc_base = (u32)kmalloc(i, GFP_KERNEL|GFP_DMA)) == 0)
+ return 0;
+
+ desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t));
+@@ -460,9 +480,14 @@
+ /* If source input is fifo, set static address.
+ */
+ if (stp->dev_flags & DEV_FLAGS_IN) {
+- src0 = stp->dev_physaddr;
+- src1 |= DSCR_SRC1_SAM(DSCR_xAM_STATIC);
++ if ( stp->dev_flags & DEV_FLAGS_BURSTABLE )
++ src1 |= DSCR_SRC1_SAM(DSCR_xAM_BURST);
++ else
++ src1 |= DSCR_SRC1_SAM(DSCR_xAM_STATIC);
++
+ }
++ if (stp->dev_physaddr)
++ src0 = stp->dev_physaddr;
+
+ /* Set up dest1. For now, assume no stride and increment.
+ * A channel attribute update can change this later.
+@@ -486,10 +511,18 @@
+ /* If destination output is fifo, set static address.
+ */
+ if (dtp->dev_flags & DEV_FLAGS_OUT) {
+- dest0 = dtp->dev_physaddr;
++ if ( dtp->dev_flags & DEV_FLAGS_BURSTABLE )
++ dest1 |= DSCR_DEST1_DAM(DSCR_xAM_BURST);
++ else
+ dest1 |= DSCR_DEST1_DAM(DSCR_xAM_STATIC);
+ }
++ if (dtp->dev_physaddr)
++ dest0 = dtp->dev_physaddr;
+
++#if 0
++ printk("did:%x sid:%x cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n",
++ dtp->dev_id, stp->dev_id, cmd0, cmd1, src0, src1, dest0, dest1 );
++#endif
+ for (i=0; i<entries; i++) {
+ dp->dscr_cmd0 = cmd0;
+ dp->dscr_cmd1 = cmd1;
+@@ -498,6 +531,7 @@
+ dp->dscr_dest0 = dest0;
+ dp->dscr_dest1 = dest1;
+ dp->dscr_stat = 0;
++ dp->sw_context = dp->sw_status = 0;
+ dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(dp + 1));
+ dp++;
+ }
+@@ -510,13 +544,14 @@
+
+ return (u32)(ctp->chan_desc_base);
+ }
++EXPORT_SYMBOL(au1xxx_dbdma_ring_alloc);
+
+ /* Put a source buffer into the DMA ring.
+ * This updates the source pointer and byte count. Normally used
+ * for memory to fifo transfers.
+ */
+ u32
+-au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes)
++_au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags)
+ {
+ chan_tab_t *ctp;
+ au1x_ddma_desc_t *dp;
+@@ -543,24 +578,40 @@
+ */
+ dp->dscr_source0 = virt_to_phys(buf);
+ dp->dscr_cmd1 = nbytes;
+- dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */
+- ctp->chan_ptr->ddma_dbell = 0xffffffff; /* Make it go */
+-
++ /* Check flags */
++ if (flags & DDMA_FLAGS_IE)
++ dp->dscr_cmd0 |= DSCR_CMD0_IE;
++ if (flags & DDMA_FLAGS_NOIE)
++ dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
+ /* Get next descriptor pointer.
+ */
+ ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
+
++ /*
++ * There is an errata on the Au1200/Au1550 parts that could result
++ * in "stale" data being DMA'd. It has to do with the snoop logic on
++ * the dache eviction buffer. NONCOHERENT_IO is on by default for
++ * these parts. If it is fixedin the future, these dma_cache_inv will
++ * just be nothing more than empty macros. See io.h.
++ * */
++ dma_cache_wback_inv(buf,nbytes);
++ dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */
++ au_sync();
++ dma_cache_wback_inv(dp, sizeof(dp));
++ ctp->chan_ptr->ddma_dbell = 0;
++
+ /* return something not zero.
+ */
+ return nbytes;
+ }
++EXPORT_SYMBOL(_au1xxx_dbdma_put_source);
+
+ /* Put a destination buffer into the DMA ring.
+ * This updates the destination pointer and byte count. Normally used
+ * to place an empty buffer into the ring for fifo to memory transfers.
+ */
+ u32
+-au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes)
++_au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags)
+ {
+ chan_tab_t *ctp;
+ au1x_ddma_desc_t *dp;
+@@ -582,11 +633,33 @@
+ if (dp->dscr_cmd0 & DSCR_CMD0_V)
+ return 0;
+
+- /* Load up buffer address and byte count.
+- */
++ /* Load up buffer address and byte count */
++
++ /* Check flags */
++ if (flags & DDMA_FLAGS_IE)
++ dp->dscr_cmd0 |= DSCR_CMD0_IE;
++ if (flags & DDMA_FLAGS_NOIE)
++ dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
++
+ dp->dscr_dest0 = virt_to_phys(buf);
+ dp->dscr_cmd1 = nbytes;
++#if 0
++ printk("cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n",
++ dp->dscr_cmd0, dp->dscr_cmd1, dp->dscr_source0,
++ dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1 );
++#endif
++ /*
++ * There is an errata on the Au1200/Au1550 parts that could result in
++ * "stale" data being DMA'd. It has to do with the snoop logic on the
++ * dache eviction buffer. NONCOHERENT_IO is on by default for these
++ * parts. If it is fixedin the future, these dma_cache_inv will just
++ * be nothing more than empty macros. See io.h.
++ * */
++ dma_cache_inv(buf,nbytes);
+ dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */
++ au_sync();
++ dma_cache_wback_inv(dp, sizeof(dp));
++ ctp->chan_ptr->ddma_dbell = 0;
+
+ /* Get next descriptor pointer.
+ */
+@@ -596,6 +669,7 @@
+ */
+ return nbytes;
+ }
++EXPORT_SYMBOL(_au1xxx_dbdma_put_dest);
+
+ /* Get a destination buffer into the DMA ring.
+ * Normally used to get a full buffer from the ring during fifo
+@@ -645,7 +719,7 @@
+ au1xxx_dbdma_stop(u32 chanid)
+ {
+ chan_tab_t *ctp;
+- volatile au1x_dma_chan_t *cp;
++ au1x_dma_chan_t *cp;
+ int halt_timeout = 0;
+
+ ctp = *((chan_tab_t **)chanid);
+@@ -665,6 +739,7 @@
+ cp->ddma_stat |= (DDMA_STAT_DB | DDMA_STAT_V);
+ au_sync();
+ }
++EXPORT_SYMBOL(au1xxx_dbdma_stop);
+
+ /* Start using the current descriptor pointer. If the dbdma encounters
+ * a not valid descriptor, it will stop. In this case, we can just
+@@ -674,17 +749,17 @@
+ au1xxx_dbdma_start(u32 chanid)
+ {
+ chan_tab_t *ctp;
+- volatile au1x_dma_chan_t *cp;
++ au1x_dma_chan_t *cp;
+
+ ctp = *((chan_tab_t **)chanid);
+-
+ cp = ctp->chan_ptr;
+ cp->ddma_desptr = virt_to_phys(ctp->cur_ptr);
+ cp->ddma_cfg |= DDMA_CFG_EN; /* Enable channel */
+ au_sync();
+- cp->ddma_dbell = 0xffffffff; /* Make it go */
++ cp->ddma_dbell = 0;
+ au_sync();
+ }
++EXPORT_SYMBOL(au1xxx_dbdma_start);
+
+ void
+ au1xxx_dbdma_reset(u32 chanid)
+@@ -703,15 +778,21 @@
+
+ do {
+ dp->dscr_cmd0 &= ~DSCR_CMD0_V;
++ /* reset our SW status -- this is used to determine
++ * if a descriptor is in use by upper level SW. Since
++ * posting can reset 'V' bit.
++ */
++ dp->sw_status = 0;
+ dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
+ } while (dp != ctp->chan_desc_base);
+ }
++EXPORT_SYMBOL(au1xxx_dbdma_reset);
+
+ u32
+ au1xxx_get_dma_residue(u32 chanid)
+ {
+ chan_tab_t *ctp;
+- volatile au1x_dma_chan_t *cp;
++ au1x_dma_chan_t *cp;
+ u32 rv;
+
+ ctp = *((chan_tab_t **)chanid);
+@@ -746,15 +827,16 @@
+
+ kfree(ctp);
+ }
++EXPORT_SYMBOL(au1xxx_dbdma_chan_free);
+
+ static void
+ dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
+- u32 intstat;
++ u32 intstat, flags;
+ u32 chan_index;
+ chan_tab_t *ctp;
+ au1x_ddma_desc_t *dp;
+- volatile au1x_dma_chan_t *cp;
++ au1x_dma_chan_t *cp;
+
+ intstat = dbdma_gptr->ddma_intstat;
+ au_sync();
+@@ -773,18 +855,26 @@
+ (ctp->chan_callback)(irq, ctp->chan_callparam, regs);
+
+ ctp->cur_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
+-
+ }
+
+-static void
+-au1xxx_dbdma_init(void)
++static void au1xxx_dbdma_init(void)
+ {
++ int irq_nr;
++
+ dbdma_gptr->ddma_config = 0;
+ dbdma_gptr->ddma_throttle = 0;
+ dbdma_gptr->ddma_inten = 0xffff;
+ au_sync();
+
+- if (request_irq(AU1550_DDMA_INT, dbdma_interrupt, SA_INTERRUPT,
++#if defined(CONFIG_SOC_AU1550)
++ irq_nr = AU1550_DDMA_INT;
++#elif defined(CONFIG_SOC_AU1200)
++ irq_nr = AU1200_DDMA_INT;
++#else
++ #error Unknown Au1x00 SOC
++#endif
++
++ if (request_irq(irq_nr, dbdma_interrupt, SA_INTERRUPT,
+ "Au1xxx dbdma", (void *)dbdma_gptr))
+ printk("Can't get 1550 dbdma irq");
+ }
+@@ -795,7 +885,8 @@
+ chan_tab_t *ctp;
+ au1x_ddma_desc_t *dp;
+ dbdev_tab_t *stp, *dtp;
+- volatile au1x_dma_chan_t *cp;
++ au1x_dma_chan_t *cp;
++ u32 i = 0;
+
+ ctp = *((chan_tab_t **)chanid);
+ stp = ctp->chan_src;
+@@ -820,15 +911,64 @@
+ dp = ctp->chan_desc_base;
+
+ do {
+- printk("dp %08x, cmd0 %08x, cmd1 %08x\n",
+- (u32)dp, dp->dscr_cmd0, dp->dscr_cmd1);
+- printk("src0 %08x, src1 %08x, dest0 %08x\n",
+- dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0);
+- printk("dest1 %08x, stat %08x, nxtptr %08x\n",
+- dp->dscr_dest1, dp->dscr_stat, dp->dscr_nxtptr);
++ printk("Dp[%d]= %08x, cmd0 %08x, cmd1 %08x\n",
++ i++, (u32)dp, dp->dscr_cmd0, dp->dscr_cmd1);
++ printk("src0 %08x, src1 %08x, dest0 %08x, dest1 %08x\n",
++ dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
++ printk("stat %08x, nxtptr %08x\n",
++ dp->dscr_stat, dp->dscr_nxtptr);
+ dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
+ } while (dp != ctp->chan_desc_base);
+ }
+
++/* Put a descriptor into the DMA ring.
++ * This updates the source/destination pointers and byte count.
++ */
++u32
++au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr )
++{
++ chan_tab_t *ctp;
++ au1x_ddma_desc_t *dp;
++ u32 nbytes=0;
++
++ /* I guess we could check this to be within the
++ * range of the table......
++ */
++ ctp = *((chan_tab_t **)chanid);
++
++ /* We should have multiple callers for a particular channel,
++ * an interrupt doesn't affect this pointer nor the descriptor,
++ * so no locking should be needed.
++ */
++ dp = ctp->put_ptr;
++
++ /* If the descriptor is valid, we are way ahead of the DMA
++ * engine, so just return an error condition.
++ */
++ if (dp->dscr_cmd0 & DSCR_CMD0_V)
++ return 0;
++
++ /* Load up buffer addresses and byte count.
++ */
++ dp->dscr_dest0 = dscr->dscr_dest0;
++ dp->dscr_source0 = dscr->dscr_source0;
++ dp->dscr_dest1 = dscr->dscr_dest1;
++ dp->dscr_source1 = dscr->dscr_source1;
++ dp->dscr_cmd1 = dscr->dscr_cmd1;
++ nbytes = dscr->dscr_cmd1;
++ /* Allow the caller to specifiy if an interrupt is generated */
++ dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
++ dp->dscr_cmd0 |= dscr->dscr_cmd0 | DSCR_CMD0_V;
++ ctp->chan_ptr->ddma_dbell = 0;
++
++ /* Get next descriptor pointer.
++ */
++ ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
++
++ /* return something not zero.
++ */
++ return nbytes;
++}
++
+ #endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */
+
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/common/gpio.c linux-2.4.32-rc1.mips/arch/mips/au1000/common/gpio.c
+--- linux-2.4.32-rc1/arch/mips/au1000/common/gpio.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/common/gpio.c 2005-01-30 09:01:27.000000000 +0100
+@@ -0,0 +1,118 @@
++/*
++ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <asm/au1000.h>
++#include <asm/au1xxx_gpio.h>
++
++#define gpio1 sys
++#if !defined(CONFIG_SOC_AU1000)
++static AU1X00_GPIO2 * const gpio2 = (AU1X00_GPIO2 *)GPIO2_BASE;
++
++#define GPIO2_OUTPUT_ENABLE_MASK 0x00010000
++
++int au1xxx_gpio2_read(int signal)
++{
++ signal -= 200;
++/* gpio2->dir &= ~(0x01 << signal); //Set GPIO to input */
++ return ((gpio2->pinstate >> signal) & 0x01);
++}
++
++void au1xxx_gpio2_write(int signal, int value)
++{
++ signal -= 200;
++
++ gpio2->output = (GPIO2_OUTPUT_ENABLE_MASK << signal) |
++ (value << signal);
++}
++
++void au1xxx_gpio2_tristate(int signal)
++{
++ signal -= 200;
++ gpio2->dir &= ~(0x01 << signal); /* Set GPIO to input */
++}
++#endif
++
++int au1xxx_gpio1_read(int signal)
++{
++/* gpio1->trioutclr |= (0x01 << signal); */
++ return ((gpio1->pinstaterd >> signal) & 0x01);
++}
++
++void au1xxx_gpio1_write(int signal, int value)
++{
++ if(value)
++ gpio1->outputset = (0x01 << signal);
++ else
++ gpio1->outputclr = (0x01 << signal); /* Output a Zero */
++}
++
++void au1xxx_gpio1_tristate(int signal)
++{
++ gpio1->trioutclr = (0x01 << signal); /* Tristate signal */
++}
++
++
++int au1xxx_gpio_read(int signal)
++{
++ if(signal >= 200)
++#if defined(CONFIG_SOC_AU1000)
++ return 0;
++#else
++ return au1xxx_gpio2_read(signal);
++#endif
++ else
++ return au1xxx_gpio1_read(signal);
++}
++
++void au1xxx_gpio_write(int signal, int value)
++{
++ if(signal >= 200)
++#if defined(CONFIG_SOC_AU1000)
++ ;
++#else
++ au1xxx_gpio2_write(signal, value);
++#endif
++ else
++ au1xxx_gpio1_write(signal, value);
++}
++
++void au1xxx_gpio_tristate(int signal)
++{
++ if(signal >= 200)
++#if defined(CONFIG_SOC_AU1000)
++ ;
++#else
++ au1xxx_gpio2_tristate(signal);
++#endif
++ else
++ au1xxx_gpio1_tristate(signal);
++}
++
++void au1xxx_gpio1_set_inputs(void)
++{
++ gpio1->pininputen = 0;
++}
++
++EXPORT_SYMBOL(au1xxx_gpio1_set_inputs);
++EXPORT_SYMBOL(au1xxx_gpio_tristate);
++EXPORT_SYMBOL(au1xxx_gpio_write);
++EXPORT_SYMBOL(au1xxx_gpio_read);
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/common/irq.c linux-2.4.32-rc1.mips/arch/mips/au1000/common/irq.c
+--- linux-2.4.32-rc1/arch/mips/au1000/common/irq.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/common/irq.c 2005-03-13 08:56:57.000000000 +0100
+@@ -303,8 +303,30 @@
+ };
+
+ #ifdef CONFIG_PM
+-void startup_match20_interrupt(void)
++void startup_match20_interrupt(void (*handler)(int, void *, struct pt_regs *))
+ {
++ static struct irqaction action;
++ /* This is a big problem.... since we didn't use request_irq
++ when kernel/irq.c calls probe_irq_xxx this interrupt will
++ be probed for usage. This will end up disabling the device :(
++
++ Give it a bogus "action" pointer -- this will keep it from
++ getting auto-probed!
++
++ By setting the status to match that of request_irq() we
++ can avoid it. --cgray
++ */
++ action.dev_id = handler;
++ action.flags = 0;
++ action.mask = 0;
++ action.name = "Au1xxx TOY";
++ action.handler = handler;
++ action.next = NULL;
++
++ irq_desc[AU1000_TOY_MATCH2_INT].action = &action;
++ irq_desc[AU1000_TOY_MATCH2_INT].status
++ &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);
++
+ local_enable_irq(AU1000_TOY_MATCH2_INT);
+ }
+ #endif
+@@ -508,6 +530,7 @@
+
+ if (!intc0_req0) return;
+
++#ifdef AU1000_USB_DEV_REQ_INT
+ /*
+ * Because of the tight timing of SETUP token to reply
+ * transactions, the USB devices-side packet complete
+@@ -518,6 +541,7 @@
+ do_IRQ(AU1000_USB_DEV_REQ_INT, regs);
+ return;
+ }
++#endif
+
+ irq = au_ffs(intc0_req0) - 1;
+ intc0_req0 &= ~(1<<irq);
+@@ -536,17 +560,7 @@
+
+ irq = au_ffs(intc0_req1) - 1;
+ intc0_req1 &= ~(1<<irq);
+-#ifdef CONFIG_PM
+- if (irq == AU1000_TOY_MATCH2_INT) {
+- mask_and_ack_rise_edge_irq(irq);
+- counter0_irq(irq, NULL, regs);
+- local_enable_irq(irq);
+- }
+- else
+-#endif
+- {
+- do_IRQ(irq, regs);
+- }
++ do_IRQ(irq, regs);
+ }
+
+
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/common/Makefile linux-2.4.32-rc1.mips/arch/mips/au1000/common/Makefile
+--- linux-2.4.32-rc1/arch/mips/au1000/common/Makefile 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/common/Makefile 2005-01-30 09:01:27.000000000 +0100
+@@ -19,9 +19,9 @@
+ export-objs = prom.o clocks.o power.o usbdev.o
+
+ obj-y := prom.o int-handler.o irq.o puts.o time.o reset.o cputable.o \
+- au1xxx_irqmap.o clocks.o power.o setup.o sleeper.o dma.o dbdma.o
++ au1xxx_irqmap.o clocks.o power.o setup.o sleeper.o dma.o dbdma.o gpio.o
+
+-export-objs += dma.o dbdma.o
++export-objs += dma.o dbdma.o gpio.o
+
+ obj-$(CONFIG_AU1X00_USB_DEVICE) += usbdev.o
+ obj-$(CONFIG_KGDB) += dbg_io.o
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/common/pci_fixup.c linux-2.4.32-rc1.mips/arch/mips/au1000/common/pci_fixup.c
+--- linux-2.4.32-rc1/arch/mips/au1000/common/pci_fixup.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/common/pci_fixup.c 2004-12-03 09:00:32.000000000 +0100
+@@ -75,9 +75,13 @@
+
+ #ifdef CONFIG_NONCOHERENT_IO
+ /*
+- * Set the NC bit in controller for pre-AC silicon
++ * Set the NC bit in controller for Au1500 pre-AC silicon
+ */
+- au_writel( 1<<16 | au_readl(Au1500_PCI_CFG), Au1500_PCI_CFG);
++ u32 prid = read_c0_prid();
++ if ( (prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) {
++ au_writel( 1<<16 | au_readl(Au1500_PCI_CFG), Au1500_PCI_CFG);
++ printk("Non-coherent PCI accesses enabled\n");
++ }
+ printk("Non-coherent PCI accesses enabled\n");
+ #endif
+
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/common/pci_ops.c linux-2.4.32-rc1.mips/arch/mips/au1000/common/pci_ops.c
+--- linux-2.4.32-rc1/arch/mips/au1000/common/pci_ops.c 2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/common/pci_ops.c 2005-02-27 23:14:24.000000000 +0100
+@@ -162,6 +162,7 @@
+ static int config_access(unsigned char access_type, struct pci_dev *dev,
+ unsigned char where, u32 * data)
+ {
++ int error = PCIBIOS_SUCCESSFUL;
+ #if defined( CONFIG_SOC_AU1500 ) || defined( CONFIG_SOC_AU1550 )
+ unsigned char bus = dev->bus->number;
+ unsigned int dev_fn = dev->devfn;
+@@ -170,7 +171,6 @@
+ unsigned long offset, status;
+ unsigned long cfg_base;
+ unsigned long flags;
+- int error = PCIBIOS_SUCCESSFUL;
+ unsigned long entryLo0, entryLo1;
+
+ if (device > 19) {
+@@ -205,9 +205,8 @@
+ last_entryLo0 = last_entryLo1 = 0xffffffff;
+ }
+
+- /* Since the Au1xxx doesn't do the idsel timing exactly to spec,
+- * many board vendors implement their own off-chip idsel, so call
+- * it now. If it doesn't succeed, may as well bail out at this point.
++ /* Allow board vendors to implement their own off-chip idsel.
++ * If it doesn't succeed, may as well bail out at this point.
+ */
+ if (board_pci_idsel) {
+ if (board_pci_idsel(device, 1) == 0) {
+@@ -271,8 +270,11 @@
+ }
+
+ local_irq_restore(flags);
+- return error;
++#else
++ /* Fake out Config space access with no responder */
++ *data = 0xFFFFFFFF;
+ #endif
++ return error;
+ }
+ #endif
+
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/common/power.c linux-2.4.32-rc1.mips/arch/mips/au1000/common/power.c
+--- linux-2.4.32-rc1/arch/mips/au1000/common/power.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/common/power.c 2005-04-07 02:37:19.000000000 +0200
+@@ -50,7 +50,6 @@
+
+ static void calibrate_delay(void);
+
+-extern void set_au1x00_speed(unsigned int new_freq);
+ extern unsigned int get_au1x00_speed(void);
+ extern unsigned long get_au1x00_uart_baud_base(void);
+ extern void set_au1x00_uart_baud_base(unsigned long new_baud_base);
+@@ -116,6 +115,7 @@
+ sleep_uart0_clkdiv = au_readl(UART0_ADDR + UART_CLK);
+ sleep_uart0_enable = au_readl(UART0_ADDR + UART_MOD_CNTRL);
+
++#ifndef CONFIG_SOC_AU1200
+ /* Shutdown USB host/device.
+ */
+ sleep_usbhost_enable = au_readl(USB_HOST_CONFIG);
+@@ -127,6 +127,7 @@
+
+ sleep_usbdev_enable = au_readl(USBD_ENABLE);
+ au_writel(0, USBD_ENABLE); au_sync();
++#endif
+
+ /* Save interrupt controller state.
+ */
+@@ -212,14 +213,12 @@
+ int au_sleep(void)
+ {
+ unsigned long wakeup, flags;
+- extern void save_and_sleep(void);
++ extern unsigned int save_and_sleep(void);
+
+ spin_lock_irqsave(&pm_lock,flags);
+
+ save_core_regs();
+
+- flush_cache_all();
+-
+ /** The code below is all system dependent and we should probably
+ ** have a function call out of here to set this up. You need
+ ** to configure the GPIO or timer interrupts that will bring
+@@ -227,27 +226,26 @@
+ ** For testing, the TOY counter wakeup is useful.
+ **/
+
+-#if 0
++#if 1
+ au_writel(au_readl(SYS_PINSTATERD) & ~(1 << 11), SYS_PINSTATERD);
+
+ /* gpio 6 can cause a wake up event */
+ wakeup = au_readl(SYS_WAKEMSK);
+ wakeup &= ~(1 << 8); /* turn off match20 wakeup */
+- wakeup |= 1 << 6; /* turn on gpio 6 wakeup */
++ wakeup = 1 << 5; /* turn on gpio 6 wakeup */
+ #else
+- /* For testing, allow match20 to wake us up.
+- */
++ /* For testing, allow match20 to wake us up. */
+ #ifdef SLEEP_TEST_TIMEOUT
+ wakeup_counter0_set(sleep_ticks);
+ #endif
+ wakeup = 1 << 8; /* turn on match20 wakeup */
+ wakeup = 0;
+ #endif
+- au_writel(1, SYS_WAKESRC); /* clear cause */
++ au_writel(0, SYS_WAKESRC); /* clear cause */
+ au_sync();
+ au_writel(wakeup, SYS_WAKEMSK);
+ au_sync();
+-
++ DPRINTK("Entering sleep!\n");
+ save_and_sleep();
+
+ /* after a wakeup, the cpu vectors back to 0x1fc00000 so
+@@ -255,6 +253,7 @@
+ */
+ restore_core_regs();
+ spin_unlock_irqrestore(&pm_lock, flags);
++ DPRINTK("Leaving sleep!\n");
+ return 0;
+ }
+
+@@ -285,7 +284,6 @@
+
+ if (retval)
+ return retval;
+-
+ au_sleep();
+ retval = pm_send_all(PM_RESUME, (void *) 0);
+ }
+@@ -296,7 +294,6 @@
+ void *buffer, size_t * len)
+ {
+ int retval = 0;
+- void au1k_wait(void);
+
+ if (!write) {
+ *len = 0;
+@@ -305,119 +302,9 @@
+ if (retval)
+ return retval;
+ suspend_mode = 1;
+- au1k_wait();
+- retval = pm_send_all(PM_RESUME, (void *) 0);
+- }
+- return retval;
+-}
+
+-
+-static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
+- void *buffer, size_t * len)
+-{
+- int retval = 0, i;
+- unsigned long val, pll;
+-#define TMPBUFLEN 64
+-#define MAX_CPU_FREQ 396
+- char buf[TMPBUFLEN], *p;
+- unsigned long flags, intc0_mask, intc1_mask;
+- unsigned long old_baud_base, old_cpu_freq, baud_rate, old_clk,
+- old_refresh;
+- unsigned long new_baud_base, new_cpu_freq, new_clk, new_refresh;
+-
+- spin_lock_irqsave(&pm_lock, flags);
+- if (!write) {
+- *len = 0;
+- } else {
+- /* Parse the new frequency */
+- if (*len > TMPBUFLEN - 1) {
+- spin_unlock_irqrestore(&pm_lock, flags);
+- return -EFAULT;
+- }
+- if (copy_from_user(buf, buffer, *len)) {
+- spin_unlock_irqrestore(&pm_lock, flags);
+- return -EFAULT;
+- }
+- buf[*len] = 0;
+- p = buf;
+- val = simple_strtoul(p, &p, 0);
+- if (val > MAX_CPU_FREQ) {
+- spin_unlock_irqrestore(&pm_lock, flags);
+- return -EFAULT;
+- }
+-
+- pll = val / 12;
+- if ((pll > 33) || (pll < 7)) { /* 396 MHz max, 84 MHz min */
+- /* revisit this for higher speed cpus */
+- spin_unlock_irqrestore(&pm_lock, flags);
+- return -EFAULT;
+- }
+-
+- old_baud_base = get_au1x00_uart_baud_base();
+- old_cpu_freq = get_au1x00_speed();
+-
+- new_cpu_freq = pll * 12 * 1000000;
+- new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16));
+- set_au1x00_speed(new_cpu_freq);
+- set_au1x00_uart_baud_base(new_baud_base);
+-
+- old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff;
+- new_refresh =
+- ((old_refresh * new_cpu_freq) /
+- old_cpu_freq) | (au_readl(MEM_SDREFCFG) & ~0x1ffffff);
+-
+- au_writel(pll, SYS_CPUPLL);
+- au_sync_delay(1);
+- au_writel(new_refresh, MEM_SDREFCFG);
+- au_sync_delay(1);
+-
+- for (i = 0; i < 4; i++) {
+- if (au_readl
+- (UART_BASE + UART_MOD_CNTRL +
+- i * 0x00100000) == 3) {
+- old_clk =
+- au_readl(UART_BASE + UART_CLK +
+- i * 0x00100000);
+- // baud_rate = baud_base/clk
+- baud_rate = old_baud_base / old_clk;
+- /* we won't get an exact baud rate and the error
+- * could be significant enough that our new
+- * calculation will result in a clock that will
+- * give us a baud rate that's too far off from
+- * what we really want.
+- */
+- if (baud_rate > 100000)
+- baud_rate = 115200;
+- else if (baud_rate > 50000)
+- baud_rate = 57600;
+- else if (baud_rate > 30000)
+- baud_rate = 38400;
+- else if (baud_rate > 17000)
+- baud_rate = 19200;
+- else
+- (baud_rate = 9600);
+- // new_clk = new_baud_base/baud_rate
+- new_clk = new_baud_base / baud_rate;
+- au_writel(new_clk,
+- UART_BASE + UART_CLK +
+- i * 0x00100000);
+- au_sync_delay(10);
+- }
+- }
++ retval = pm_send_all(PM_RESUME, (void *) 0);
+ }
+-
+-
+- /* We don't want _any_ interrupts other than
+- * match20. Otherwise our calibrate_delay()
+- * calculation will be off, potentially a lot.
+- */
+- intc0_mask = save_local_and_disable(0);
+- intc1_mask = save_local_and_disable(1);
+- local_enable_irq(AU1000_TOY_MATCH2_INT);
+- spin_unlock_irqrestore(&pm_lock, flags);
+- calibrate_delay();
+- restore_local_and_enable(0, intc0_mask);
+- restore_local_and_enable(1, intc1_mask);
+ return retval;
+ }
+
+@@ -425,7 +312,6 @@
+ static struct ctl_table pm_table[] = {
+ {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, &pm_do_suspend},
+ {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &pm_do_sleep},
+- {CTL_ACPI, "freq", NULL, 0, 0600, NULL, &pm_do_freq},
+ {0}
+ };
+
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/common/reset.c linux-2.4.32-rc1.mips/arch/mips/au1000/common/reset.c
+--- linux-2.4.32-rc1/arch/mips/au1000/common/reset.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/common/reset.c 2005-03-19 08:17:51.000000000 +0100
+@@ -37,8 +37,6 @@
+ #include <asm/system.h>
+ #include <asm/au1000.h>
+
+-extern int au_sleep(void);
+-
+ void au1000_restart(char *command)
+ {
+ /* Set all integrated peripherals to disabled states */
+@@ -144,6 +142,26 @@
+ au_writel(0x00, 0xb1900064); /* sys_auxpll */
+ au_writel(0x00, 0xb1900100); /* sys_pininputen */
+ break;
++ case 0x04000000: /* Au1200 */
++ au_writel(0x00, 0xb400300c); /* ddma */
++ au_writel(0x00, 0xb1a00004); /* psc 0 */
++ au_writel(0x00, 0xb1b00004); /* psc 1 */
++ au_writel(0x00d02000, 0xb4020004); /* ehci, ohci, udc, otg */
++ au_writel(0x00, 0xb5000004); /* lcd */
++ au_writel(0x00, 0xb060000c); /* sd0 */
++ au_writel(0x00, 0xb068000c); /* sd1 */
++ au_writel(0x00, 0xb1100100); /* swcnt */
++ au_writel(0x00, 0xb0300000); /* aes */
++ au_writel(0x00, 0xb4004000); /* cim */
++ au_writel(0x00, 0xb1100100); /* uart0_enable */
++ au_writel(0x00, 0xb1200100); /* uart1_enable */
++ au_writel(0x00, 0xb1900020); /* sys_freqctrl0 */
++ au_writel(0x00, 0xb1900024); /* sys_freqctrl1 */
++ au_writel(0x00, 0xb1900028); /* sys_clksrc */
++ au_writel(0x10, 0xb1900060); /* sys_cpupll */
++ au_writel(0x00, 0xb1900064); /* sys_auxpll */
++ au_writel(0x00, 0xb1900100); /* sys_pininputen */
++ break;
+
+ default:
+ break;
+@@ -163,32 +181,23 @@
+
+ void au1000_halt(void)
+ {
+-#if defined(CONFIG_MIPS_PB1550)
+- /* power off system */
+- printk("\n** Powering off Pb1550\n");
+- au_writew(au_readw(0xAF00001C) | (3<<14), 0xAF00001C);
+- au_sync();
+- while(1); /* should not get here */
+-#endif
+- printk(KERN_NOTICE "\n** You can safely turn off the power\n");
+-#ifdef CONFIG_MIPS_MIRAGE
+- au_writel((1 << 26) | (1 << 10), GPIO2_OUTPUT);
+-#endif
+-#ifdef CONFIG_PM
+- au_sleep();
+-
+- /* should not get here */
+- printk(KERN_ERR "Unable to put cpu in sleep mode\n");
+- while(1);
+-#else
+- while (1)
++ /* Use WAIT in a low-power infinite spin loop */
++ while (1) {
+ __asm__(".set\tmips3\n\t"
+ "wait\n\t"
+ ".set\tmips0");
+-#endif
++ }
+ }
+
+ void au1000_power_off(void)
+ {
++ extern void board_power_off (void);
++
++ printk(KERN_NOTICE "\n** You can safely turn off the power\n");
++
++ /* Give board a chance to power-off */
++ board_power_off();
++
++ /* If board can't power-off, spin forever */
+ au1000_halt();
+ }
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/common/setup.c linux-2.4.32-rc1.mips/arch/mips/au1000/common/setup.c
+--- linux-2.4.32-rc1/arch/mips/au1000/common/setup.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/common/setup.c 2005-01-30 09:01:27.000000000 +0100
+@@ -174,6 +174,40 @@
+ initrd_end = (unsigned long)&__rd_end;
+ #endif
+
++#if defined(CONFIG_SOC_AU1200)
++#ifdef CONFIG_USB_EHCI_HCD
++ if ((argptr = strstr(argptr, "usb_ehci=")) == NULL) {
++ char usb_args[80];
++ argptr = prom_getcmdline();
++ memset(usb_args, 0, sizeof(usb_args));
++ sprintf(usb_args, " usb_ehci=base:0x%x,len:0x%x,irq:%d",
++ USB_EHCI_BASE, USB_EHCI_LEN, AU1000_USB_HOST_INT);
++ strcat(argptr, usb_args);
++ }
++#ifdef CONFIG_USB_AMD5536UDC
++ /* enable EHC + OHC + UDC clocks, memory and bus mastering */
++/* au_writel( 0x00DF207F, USB_MSR_BASE + 4); */
++ au_writel( 0xC0DF207F, USB_MSR_BASE + 4); // incl. prefetch
++#else
++ /* enable EHC + OHC clocks, memory and bus mastering */
++/* au_writel( 0x00DB200F, USB_MSR_BASE + 4); */
++ au_writel( 0xC0DB200F, USB_MSR_BASE + 4); /* incl. prefetch */
++#endif
++ udelay(1000);
++
++#else /* CONFIG_USB_EHCI_HCD */
++
++#ifdef CONFIG_USB_AMD5536UDC
++#ifndef CONFIG_USB_OHCI
++ /* enable UDC clocks, memory and bus mastering */
++/* au_writel( 0x00DC2070, USB_MSR_BASE + 4); */
++ au_writel( 0xC0DC2070, USB_MSR_BASE + 4); // incl. prefetch
++ udelay(1000);
++#endif
++#endif
++#endif /* CONFIG_USB_EHCI_HCD */
++#endif /* CONFIG_SOC_AU1200 */
++
+ #if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
+ #ifdef CONFIG_USB_OHCI
+ if ((argptr = strstr(argptr, "usb_ohci=")) == NULL) {
+@@ -187,19 +221,38 @@
+ #endif
+
+ #ifdef CONFIG_USB_OHCI
+- // enable host controller and wait for reset done
++#if defined(CONFIG_SOC_AU1200)
++#ifndef CONFIG_USB_EHCI_HCD
++#ifdef CONFIG_USB_AMD5536UDC
++ /* enable OHC + UDC clocks, memory and bus mastering */
++/* au_writel( 0x00DD2073, USB_MSR_BASE + 4); */
++ au_writel( 0xC0DD2073, USB_MSR_BASE + 4); // incl. prefetch
++#else
++ /* enable OHC clocks, memory and bus mastering */
++ au_writel( 0x00D12003, USB_MSR_BASE + 4);
++#endif
++ udelay(1000);
++printk("DEBUG: Reading Au1200 USB2 reg 0x%x\n", au_readl(USB_MSR_BASE + 4));
++#endif
++#else
++ /* Au1000, Au1500, Au1100, Au1550 */
++ /* enable host controller and wait for reset done */
+ au_writel(0x08, USB_HOST_CONFIG);
+ udelay(1000);
+ au_writel(0x0E, USB_HOST_CONFIG);
+ udelay(1000);
+- au_readl(USB_HOST_CONFIG); // throw away first read
++ au_readl(USB_HOST_CONFIG); /* throw away first read */
+ while (!(au_readl(USB_HOST_CONFIG) & 0x10))
+ au_readl(USB_HOST_CONFIG);
++#endif /* CONFIG_SOC_AU1200 */
+ #endif
+-#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
++#else
++
++#endif /* defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE) */
++
+
+ #ifdef CONFIG_FB
+- // Needed if PCI video card in use
++ /* Needed if PCI video card in use */
+ conswitchp = &dummy_con;
+ #endif
+
+@@ -209,8 +262,7 @@
+ #endif
+
+ #ifdef CONFIG_BLK_DEV_IDE
+- /* Board setup takes precedence for unique devices.
+- */
++ /* Board setup takes precedence for unique devices. */
+ if ((ide_ops == NULL) || (ide_ops == &no_ide_ops))
+ ide_ops = &std_ide_ops;
+ #endif
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/common/sleeper.S linux-2.4.32-rc1.mips/arch/mips/au1000/common/sleeper.S
+--- linux-2.4.32-rc1/arch/mips/au1000/common/sleeper.S 2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/common/sleeper.S 2005-01-30 09:01:27.000000000 +0100
+@@ -15,17 +15,48 @@
+ #include <asm/addrspace.h>
+ #include <asm/regdef.h>
+ #include <asm/stackframe.h>
++#include <asm/au1000.h>
++
++/*
++ * Note: This file is *not* conditional on CONFIG_PM since Alchemy sleep
++ * need not be tied to any particular power management scheme.
++ */
++
++ .extern ___flush_cache_all
+
+ .text
+- .set macro
+- .set noat
+ .align 5
+
+-/* Save all of the processor general registers and go to sleep.
+- * A wakeup condition will get us back here to restore the registers.
++/*
++ * Save the processor general registers and go to sleep. A wakeup
++ * condition will get us back here to restore the registers.
+ */
+-LEAF(save_and_sleep)
+
++/* still need to fix alignment issues here */
++save_and_sleep_frmsz = 48
++NESTED(save_and_sleep, save_and_sleep_frmsz, ra)
++ .set noreorder
++ .set nomacro
++ .set noat
++ subu sp, save_and_sleep_frmsz
++ sw ra, save_and_sleep_frmsz-4(sp)
++ sw s0, save_and_sleep_frmsz-8(sp)
++ sw s1, save_and_sleep_frmsz-12(sp)
++ sw s2, save_and_sleep_frmsz-16(sp)
++ sw s3, save_and_sleep_frmsz-20(sp)
++ sw s4, save_and_sleep_frmsz-24(sp)
++ sw s5, save_and_sleep_frmsz-28(sp)
++ sw s6, save_and_sleep_frmsz-32(sp)
++ sw s7, save_and_sleep_frmsz-36(sp)
++ sw s8, save_and_sleep_frmsz-40(sp)
++ sw gp, save_and_sleep_frmsz-44(sp)
++
++ /* We only need to save the registers that the calling function
++ * hasn't saved for us. 0 is always zero. 8 - 15, 24 and 25 are
++ * temporaries and can be used without saving. 26 and 27 are reserved
++ * for interrupt/trap handling and expected to change. 29 is the
++ * stack pointer which is handled as a special case here.
++ */
+ subu sp, PT_SIZE
+ sw $1, PT_R1(sp)
+ sw $2, PT_R2(sp)
+@@ -34,14 +65,6 @@
+ sw $5, PT_R5(sp)
+ sw $6, PT_R6(sp)
+ sw $7, PT_R7(sp)
+- sw $8, PT_R8(sp)
+- sw $9, PT_R9(sp)
+- sw $10, PT_R10(sp)
+- sw $11, PT_R11(sp)
+- sw $12, PT_R12(sp)
+- sw $13, PT_R13(sp)
+- sw $14, PT_R14(sp)
+- sw $15, PT_R15(sp)
+ sw $16, PT_R16(sp)
+ sw $17, PT_R17(sp)
+ sw $18, PT_R18(sp)
+@@ -50,32 +73,47 @@
+ sw $21, PT_R21(sp)
+ sw $22, PT_R22(sp)
+ sw $23, PT_R23(sp)
+- sw $24, PT_R24(sp)
+- sw $25, PT_R25(sp)
+- sw $26, PT_R26(sp)
+- sw $27, PT_R27(sp)
+ sw $28, PT_R28(sp)
+- sw $29, PT_R29(sp)
+ sw $30, PT_R30(sp)
+ sw $31, PT_R31(sp)
++#define PT_C0STATUS PT_LO
++#define PT_CONTEXT PT_HI
++#define PT_PAGEMASK PT_EPC
++#define PT_CONFIG PT_BVADDR
+ mfc0 k0, CP0_STATUS
+- sw k0, 0x20(sp)
++ sw k0, PT_C0STATUS(sp) // 0x20
+ mfc0 k0, CP0_CONTEXT
+- sw k0, 0x1c(sp)
++ sw k0, PT_CONTEXT(sp) // 0x1c
+ mfc0 k0, CP0_PAGEMASK
+- sw k0, 0x18(sp)
++ sw k0, PT_PAGEMASK(sp) // 0x18
+ mfc0 k0, CP0_CONFIG
+- sw k0, 0x14(sp)
++ sw k0, PT_CONFIG(sp) // 0x14
++
++ .set macro
++ .set at
++
++ li t0, SYS_SLPPWR
++ sw zero, 0(t0) /* Get the processor ready to sleep */
++ sync
+
+ /* Now set up the scratch registers so the boot rom will
+ * return to this point upon wakeup.
++ * sys_scratch0 : SP
++ * sys_scratch1 : RA
++ */
++ li t0, SYS_SCRATCH0
++ li t1, SYS_SCRATCH1
++ sw sp, 0(t0)
++ la k0, resume_from_sleep
++ sw k0, 0(t1)
++
++/*
++ * Flush DCACHE to make sure context is in memory
+ */
+- la k0, 1f
+- lui k1, 0xb190
+- ori k1, 0x18
+- sw sp, 0(k1)
+- ori k1, 0x1c
+- sw k0, 0(k1)
++ la t1,___flush_cache_all /* _flush_cache_all is a function pointer */
++ lw t0,0(t1)
++ jal t0
++ nop
+
+ /* Put SDRAM into self refresh. Preload instructions into cache,
+ * issue a precharge, then auto refresh, then sleep commands to it.
+@@ -88,30 +126,65 @@
+ cache 0x14, 96(t0)
+ .set mips0
+
++ /* Put SDRAM to sleep */
+ sdsleep:
+- lui k0, 0xb400
+- sw zero, 0x001c(k0) /* Precharge */
+- sw zero, 0x0020(k0) /* Auto refresh */
+- sw zero, 0x0030(k0) /* SDRAM sleep */
++ li a0, MEM_PHYS_ADDR
++ or a0, a0, 0xA0000000
++#if defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100) || defined(CONFIG_SOC_AU1500)
++ lw k0, MEM_SDMODE0(a0)
++ sw zero, MEM_SDPRECMD(a0) /* Precharge */
++ sw zero, MEM_SDAUTOREF(a0) /* Auto Refresh */
++ sw zero, MEM_SDSLEEP(a0) /* Sleep */
+ sync
+-
+- lui k1, 0xb190
+- sw zero, 0x0078(k1) /* get ready to sleep */
++#endif
++#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
++ sw zero, MEM_SDPRECMD(a0) /* Precharge */
++ sw zero, MEM_SDSREF(a0)
++
++ #lw t0, MEM_SDSTAT(a0)
++ #and t0, t0, 0x01000000
++ li t0, 0x01000000
++refresh_not_set:
++ lw t1, MEM_SDSTAT(a0)
++ and t2, t1, t0
++ beq zero, t2, refresh_not_set
++ nop
++
++ li t0, ~0x30000000
++ lw t1, MEM_SDCONFIGA(a0)
++ and t1, t0, t1
++ sw t1, MEM_SDCONFIGA(a0)
+ sync
+- sw zero, 0x007c(k1) /* Put processor to sleep */
++#endif
++
++ li t0, SYS_SLEEP
++ sw zero, 0(t0) /* Put processor to sleep */
+ sync
++ nop
++ nop
++ nop
++ nop
++ nop
++ nop
++ nop
++ nop
++
+
+ /* This is where we return upon wakeup.
+ * Reload all of the registers and return.
+ */
+-1: nop
+- lw k0, 0x20(sp)
++resume_from_sleep:
++ nop
++ .set nomacro
++ .set noat
++
++ lw k0, PT_C0STATUS(sp) // 0x20
+ mtc0 k0, CP0_STATUS
+- lw k0, 0x1c(sp)
++ lw k0, PT_CONTEXT(sp) // 0x1c
+ mtc0 k0, CP0_CONTEXT
+- lw k0, 0x18(sp)
++ lw k0, PT_PAGEMASK(sp) // 0x18
+ mtc0 k0, CP0_PAGEMASK
+- lw k0, 0x14(sp)
++ lw k0, PT_CONFIG(sp) // 0x14
+ mtc0 k0, CP0_CONFIG
+ lw $1, PT_R1(sp)
+ lw $2, PT_R2(sp)
+@@ -120,14 +193,6 @@
+ lw $5, PT_R5(sp)
+ lw $6, PT_R6(sp)
+ lw $7, PT_R7(sp)
+- lw $8, PT_R8(sp)
+- lw $9, PT_R9(sp)
+- lw $10, PT_R10(sp)
+- lw $11, PT_R11(sp)
+- lw $12, PT_R12(sp)
+- lw $13, PT_R13(sp)
+- lw $14, PT_R14(sp)
+- lw $15, PT_R15(sp)
+ lw $16, PT_R16(sp)
+ lw $17, PT_R17(sp)
+ lw $18, PT_R18(sp)
+@@ -136,15 +201,36 @@
+ lw $21, PT_R21(sp)
+ lw $22, PT_R22(sp)
+ lw $23, PT_R23(sp)
+- lw $24, PT_R24(sp)
+- lw $25, PT_R25(sp)
+- lw $26, PT_R26(sp)
+- lw $27, PT_R27(sp)
+ lw $28, PT_R28(sp)
+- lw $29, PT_R29(sp)
+ lw $30, PT_R30(sp)
+ lw $31, PT_R31(sp)
++
++ .set macro
++ .set at
++
++ /* clear the wake source, but save it as the return value of the function */
++ li t0, SYS_WAKESRC
++ lw v0, 0(t0)
++ sw v0, PT_R2(sp)
++ sw zero, 0(t0)
++
+ addiu sp, PT_SIZE
+
++ lw gp, save_and_sleep_frmsz-44(sp)
++ lw s8, save_and_sleep_frmsz-40(sp)
++ lw s7, save_and_sleep_frmsz-36(sp)
++ lw s6, save_and_sleep_frmsz-32(sp)
++ lw s5, save_and_sleep_frmsz-28(sp)
++ lw s4, save_and_sleep_frmsz-24(sp)
++ lw s3, save_and_sleep_frmsz-20(sp)
++ lw s2, save_and_sleep_frmsz-16(sp)
++ lw s1, save_and_sleep_frmsz-12(sp)
++ lw s0, save_and_sleep_frmsz-8(sp)
++ lw ra, save_and_sleep_frmsz-4(sp)
++
++ addu sp, save_and_sleep_frmsz
+ jr ra
++ nop
++ .set reorder
+ END(save_and_sleep)
++
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/common/time.c linux-2.4.32-rc1.mips/arch/mips/au1000/common/time.c
+--- linux-2.4.32-rc1/arch/mips/au1000/common/time.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/common/time.c 2005-04-08 10:33:17.000000000 +0200
+@@ -50,7 +50,6 @@
+ #include <linux/mc146818rtc.h>
+ #include <linux/timex.h>
+
+-extern void startup_match20_interrupt(void);
+ extern void do_softirq(void);
+ extern volatile unsigned long wall_jiffies;
+ unsigned long missed_heart_beats = 0;
+@@ -59,14 +58,14 @@
+ static unsigned long r4k_cur; /* What counter should be at next timer irq */
+ extern rwlock_t xtime_lock;
+ int no_au1xxx_32khz;
+-void (*au1k_wait_ptr)(void);
++extern int allow_au1k_wait; /* default off for CP0 Counter */
+
+ /* Cycle counter value at the previous timer interrupt.. */
+ static unsigned int timerhi = 0, timerlo = 0;
+
+ #ifdef CONFIG_PM
+ #define MATCH20_INC 328
+-extern void startup_match20_interrupt(void);
++extern void startup_match20_interrupt(void (*handler)(int, void *, struct pt_regs *));
+ static unsigned long last_pc0, last_match20;
+ #endif
+
+@@ -385,7 +384,6 @@
+ {
+ unsigned int est_freq;
+ extern unsigned long (*do_gettimeoffset)(void);
+- extern void au1k_wait(void);
+
+ printk("calculating r4koff... ");
+ r4k_offset = cal_r4koff();
+@@ -437,9 +435,6 @@
+ au_writel(0, SYS_TOYWRITE);
+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);
+
+- au_writel(au_readl(SYS_WAKEMSK) | (1<<8), SYS_WAKEMSK);
+- au_writel(~0, SYS_WAKESRC);
+- au_sync();
+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
+
+ /* setup match20 to interrupt once every 10ms */
+@@ -447,13 +442,13 @@
+ au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
+ au_sync();
+ while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
+- startup_match20_interrupt();
++ startup_match20_interrupt(counter0_irq);
+
+ do_gettimeoffset = do_fast_pm_gettimeoffset;
+
+ /* We can use the real 'wait' instruction.
+ */
+- au1k_wait_ptr = au1k_wait;
++ allow_au1k_wait = 1;
+ }
+
+ #else
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/db1x00/board_setup.c linux-2.4.32-rc1.mips/arch/mips/au1000/db1x00/board_setup.c
+--- linux-2.4.32-rc1/arch/mips/au1000/db1x00/board_setup.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/db1x00/board_setup.c 2005-03-19 08:17:51.000000000 +0100
+@@ -46,10 +46,22 @@
+ #include <asm/au1000.h>
+ #include <asm/db1x00.h>
+
+-extern struct rtc_ops no_rtc_ops;
++#if defined(CONFIG_BLK_DEV_IDE_AU1XXX) && defined(CONFIG_MIPS_DB1550)
++#include <asm/au1xxx_dbdma.h>
++extern struct ide_ops *ide_ops;
++extern struct ide_ops au1xxx_ide_ops;
++extern u32 au1xxx_ide_virtbase;
++extern u64 au1xxx_ide_physbase;
++extern int au1xxx_ide_irq;
++
++/* Ddma */
++chan_tab_t *ide_read_ch, *ide_write_ch;
++u32 au1xxx_ide_ddma_enable = 0, switch4ddma = 1; // PIO+ddma
++
++dbdev_tab_t new_dbdev_tab_element = { DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 };
++#endif /* end CONFIG_BLK_DEV_IDE_AU1XXX */
+
+-/* not correct for db1550 */
+-static BCSR * const bcsr = (BCSR *)0xAE000000;
++extern struct rtc_ops no_rtc_ops;
+
+ void board_reset (void)
+ {
+@@ -57,6 +69,13 @@
+ au_writel(0x00000000, 0xAE00001C);
+ }
+
++void board_power_off (void)
++{
++#ifdef CONFIG_MIPS_MIRAGE
++ au_writel((1 << 26) | (1 << 10), GPIO2_OUTPUT);
++#endif
++}
++
+ void __init board_setup(void)
+ {
+ u32 pin_func;
+@@ -108,8 +127,42 @@
+ au_writel(0x02000200, GPIO2_OUTPUT);
+ #endif
+
++#if defined(CONFIG_AU1XXX_SMC91111)
++#define CPLD_CONTROL (0xAF00000C)
++ {
++ extern uint32_t au1xxx_smc91111_base;
++ extern unsigned int au1xxx_smc91111_irq;
++ extern int au1xxx_smc91111_nowait;
++
++ au1xxx_smc91111_base = 0xAC000300;
++ au1xxx_smc91111_irq = AU1000_GPIO_8;
++ au1xxx_smc91111_nowait = 1;
++
++ /* set up the Static Bus timing - only 396Mhz */
++ bcsr->resets |= 0x7;
++ au_writel(0x00010003, MEM_STCFG0);
++ au_writel(0x000c00c0, MEM_STCFG2);
++ au_writel(0x85E1900D, MEM_STTIME2);
++ }
++#endif /* end CONFIG_SMC91111 */
+ au_sync();
+
++#if defined(CONFIG_BLK_DEV_IDE_AU1XXX) && defined(CONFIG_MIPS_DB1550)
++ /*
++ * Iniz IDE parameters
++ */
++ ide_ops = &au1xxx_ide_ops;
++ au1xxx_ide_irq = DAUGHTER_CARD_IRQ;
++ au1xxx_ide_physbase = AU1XXX_ATA_PHYS_ADDR;
++ au1xxx_ide_virtbase = KSEG1ADDR(AU1XXX_ATA_PHYS_ADDR);
++
++ /*
++ * change PIO or PIO+Ddma
++ * check the GPIO-6 pin condition. db1550:s6_dot
++ */
++ switch4ddma = (au_readl(SYS_PINSTATERD) & (1 << 6)) ? 1 : 0;
++#endif
++
+ #ifdef CONFIG_MIPS_DB1000
+ printk("AMD Alchemy Au1000/Db1000 Board\n");
+ #endif
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/db1x00/irqmap.c linux-2.4.32-rc1.mips/arch/mips/au1000/db1x00/irqmap.c
+--- linux-2.4.32-rc1/arch/mips/au1000/db1x00/irqmap.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/db1x00/irqmap.c 2005-01-30 09:06:19.000000000 +0100
+@@ -53,6 +53,7 @@
+ #ifdef CONFIG_MIPS_DB1550
+ { AU1000_GPIO_3, INTC_INT_LOW_LEVEL, 0 }, // PCMCIA Card 0 IRQ#
+ { AU1000_GPIO_5, INTC_INT_LOW_LEVEL, 0 }, // PCMCIA Card 1 IRQ#
++ { AU1000_GPIO_8, INTC_INT_LOW_LEVEL, 0 }, // Daughtercard IRQ#
+ #else
+ { AU1000_GPIO_0, INTC_INT_LOW_LEVEL, 0 }, // PCMCIA Card 0 Fully_Interted#
+ { AU1000_GPIO_1, INTC_INT_LOW_LEVEL, 0 }, // PCMCIA Card 0 STSCHG#
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/db1x00/Makefile linux-2.4.32-rc1.mips/arch/mips/au1000/db1x00/Makefile
+--- linux-2.4.32-rc1/arch/mips/au1000/db1x00/Makefile 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/db1x00/Makefile 2005-01-30 09:06:19.000000000 +0100
+@@ -17,4 +17,11 @@
+ obj-y := init.o board_setup.o irqmap.o
+ obj-$(CONFIG_WM97XX_COMODULE) += mirage_ts.o
+
++ifdef CONFIG_MIPS_DB1100
++ifdef CONFIG_MMC
++obj-y += mmc_support.o
++export-objs += mmc_support.o
++endif
++endif
++
+ include $(TOPDIR)/Rules.make
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/db1x00/mmc_support.c linux-2.4.32-rc1.mips/arch/mips/au1000/db1x00/mmc_support.c
+--- linux-2.4.32-rc1/arch/mips/au1000/db1x00/mmc_support.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/db1x00/mmc_support.c 2005-01-30 09:07:01.000000000 +0100
+@@ -0,0 +1,126 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ *
++ * MMC support routines for DB1100.
++ *
++ *
++ * Copyright (c) 2003-2004 Embedded Edge, LLC.
++ * Author: Embedded Edge, LLC.
++ * Contact: dan@embeddededge.com
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++
++#include <asm/irq.h>
++#include <asm/au1000.h>
++#include <asm/au1100_mmc.h>
++#include <asm/db1x00.h>
++
++
++/* SD/MMC controller support functions */
++
++/*
++ * Detect card.
++ */
++void mmc_card_inserted(int _n_, int *_res_)
++{
++ u32 gpios = au_readl(SYS_PINSTATERD);
++ u32 emptybit = (_n_) ? (1<<20) : (1<<19);
++ *_res_ = ((gpios & emptybit) == 0);
++}
++
++/*
++ * Check card write protection.
++ */
++void mmc_card_writable(int _n_, int *_res_)
++{
++ BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++ unsigned long mmc_wp, board_specific;
++
++ if (_n_) {
++ mmc_wp = BCSR_BOARD_SD1_WP;
++ } else {
++ mmc_wp = BCSR_BOARD_SD0_WP;
++ }
++
++ board_specific = au_readl((unsigned long)(&bcsr->specific));
++
++ if (!(board_specific & mmc_wp)) {/* low means card writable */
++ *_res_ = 1;
++ } else {
++ *_res_ = 0;
++ }
++}
++
++/*
++ * Apply power to card slot.
++ */
++void mmc_power_on(int _n_)
++{
++ BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++ unsigned long mmc_pwr, board_specific;
++
++ if (_n_) {
++ mmc_pwr = BCSR_BOARD_SD1_PWR;
++ } else {
++ mmc_pwr = BCSR_BOARD_SD0_PWR;
++ }
++
++ board_specific = au_readl((unsigned long)(&bcsr->specific));
++ board_specific |= mmc_pwr;
++
++ au_writel(board_specific, (int)(&bcsr->specific));
++ au_sync_delay(1);
++}
++
++/*
++ * Remove power from card slot.
++ */
++void mmc_power_off(int _n_)
++{
++ BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++ unsigned long mmc_pwr, board_specific;
++
++ if (_n_) {
++ mmc_pwr = BCSR_BOARD_SD1_PWR;
++ } else {
++ mmc_pwr = BCSR_BOARD_SD0_PWR;
++ }
++
++ board_specific = au_readl((unsigned long)(&bcsr->specific));
++ board_specific &= ~mmc_pwr;
++
++ au_writel(board_specific, (int)(&bcsr->specific));
++ au_sync_delay(1);
++}
++
++EXPORT_SYMBOL(mmc_card_inserted);
++EXPORT_SYMBOL(mmc_card_writable);
++EXPORT_SYMBOL(mmc_power_on);
++EXPORT_SYMBOL(mmc_power_off);
++
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/ficmmp/au1200_ibutton.c linux-2.4.32-rc1.mips/arch/mips/au1000/ficmmp/au1200_ibutton.c
+--- linux-2.4.32-rc1/arch/mips/au1000/ficmmp/au1200_ibutton.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/ficmmp/au1200_ibutton.c 2005-02-03 07:35:29.000000000 +0100
+@@ -0,0 +1,270 @@
++/* ----------------------------------------------------------------------
++ * mtwilson_keys.c
++ *
++ * Copyright (C) 2003 Intrinsyc Software Inc.
++ *
++ * Intel Personal Media Player buttons
++ *
++ * 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.
++ *
++ * May 02, 2003 : Initial version [FB]
++ *
++ ------------------------------------------------------------------------*/
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/sched.h>
++#include <linux/miscdevice.h>
++#include <linux/errno.h>
++#include <linux/poll.h>
++#include <linux/delay.h>
++#include <linux/input.h>
++
++#include <asm/au1000.h>
++#include <asm/uaccess.h>
++#include <asm/au1xxx_gpio.h>
++#include <asm/irq.h>
++#include <asm/keyboard.h>
++#include <linux/time.h>
++
++#define DRIVER_VERSION "V1.0"
++#define DRIVER_AUTHOR "FIC"
++#define DRIVER_DESC "FIC Travis Media Player Button Driver"
++#define DRIVER_NAME "Au1200Button"
++
++#define BUTTON_MAIN (1<<1)
++#define BUTTON_SELECT (1<<6)
++#define BUTTON_GUIDE (1<<12)
++#define BUTTON_DOWN (1<<17)
++#define BUTTON_LEFT (1<<19)
++#define BUTTON_RIGHT (1<<26)
++#define BUTTON_UP (1<<28)
++
++#define BUTTON_MASK (\
++ BUTTON_MAIN \
++ | BUTTON_SELECT \
++ | BUTTON_GUIDE \
++ | BUTTON_DOWN \
++ | BUTTON_LEFT \
++ | BUTTON_RIGHT \
++ | BUTTON_UP \
++ )
++
++#define BUTTON_INVERT (\
++ BUTTON_MAIN \
++ | 0 \
++ | BUTTON_GUIDE \
++ | 0 \
++ | 0 \
++ | 0 \
++ | 0 \
++ )
++
++char button_map[32]={0,KEY_S,0,0,0,0,KEY_ENTER,0,0,0,0,0,KEY_G,0,0,0,0,KEY_DOWN,0,KEY_LEFT,0,0,0,0,0,0,KEY_RIGHT,0,KEY_UP,0,0,0};
++//char button_map[32]={0,0,0,0,0,0,KEY_ENTER,0,0,0,0,0,KEY_G,0,0,0,0,KEY_DOWN,0,KEY_LEFT,0,0,0,0,0,0,KEY_RIGHT,0,KEY_UP,0,0,0};
++
++//char button_map[32]={0,KEY_TAB,0,0,0,0,KEY_M,0,0,0,0,0,KEY_S,0,0,0,0,KEY_DOWN,0,KEY_LEFT,0,0,0,0,0,0,KEY_RIGHT,0,KEY_UP,0,0,0};
++//char button_map[32]={0,0,0,0,0,0,KEY_M,0,0,0,0,0,KEY_S,0,0,0,0,KEY_DOWN,0,KEY_LEFT,0,0,0,0,0,0,KEY_RIGHT,0,KEY_UP,0,0,0};
++
++#define BUTTON_COUNT (sizeof (button_map) / sizeof (button_map[0]))
++
++struct input_dev dev;
++struct timeval cur_tv;
++
++static unsigned int old_tv_usec = 0;
++
++static unsigned int read_button_state(void)
++{
++ unsigned int state;
++
++ state = au_readl(SYS_PINSTATERD) & BUTTON_MASK; /* get gpio status */
++
++ state ^= BUTTON_INVERT; /* invert main & guide button */
++
++ /* printk("au1200_ibutton.c: button state [0x%X]\r\n",state); */
++ return state;
++}
++
++//This function returns 0 if the allowed microseconds have elapsed since the last call to ths function, otherwise it returns 1 to indicate a bounce condition
++static unsigned int bounce()
++{
++
++ unsigned int elapsed_time;
++
++ do_gettimeofday (&cur_tv);
++
++ if (!old_tv_usec) {
++ old_tv_usec = cur_tv.tv_usec;
++ return 0;
++ }
++
++ if(cur_tv.tv_usec > old_tv_usec) {
++ /* If there hasn't been rollover */
++ elapsed_time = ((cur_tv.tv_usec - old_tv_usec));
++ }
++ else {
++ /* Accounting for rollover */
++ elapsed_time = ((1000000 - old_tv_usec + cur_tv.tv_usec));
++ }
++
++ if (elapsed_time > 250000) {
++ old_tv_usec = 0; /* reset the bounce time */
++ return 0;
++ }
++
++ return 1;
++}
++
++/* button interrupt handler */
++static void button_interrupt(int irq, void *dev, struct pt_regs *regs)
++{
++
++ unsigned int i,bit_mask, key_choice;
++ u32 button_state;
++
++ /* Report state to upper level */
++
++ button_state = read_button_state() & BUTTON_MASK; /* get new gpio status */
++
++ /* Return if this is a repeated (bouncing) event */
++ if(bounce())
++ return;
++
++ /* we want to make keystrokes */
++ for( i=0; i< BUTTON_COUNT; i++) {
++ bit_mask = 1<<i;
++ if (button_state & bit_mask) {
++ key_choice = button_map[i];
++ /* toggle key down */
++ input_report_key(dev, key_choice, 1);
++ /* toggle key up */
++ input_report_key(dev, key_choice, 0);
++ printk("ibutton gpio %d stat %x scan code %d\r\n",
++ i, button_state, key_choice);
++ /* Only report the first key event; it doesn't make
++ * sense for two keys to be pressed at the same time,
++ * and causes problems with the directional keys
++ * return;
++ */
++ }
++ }
++}
++
++static int
++button_translate(unsigned char scancode, unsigned char *keycode, char raw_mode)
++{
++ static int prev_scancode;
++
++ printk( "ibutton.c: translate: scancode=%x raw_mode=%x\n",
++ scancode, raw_mode);
++
++ if (scancode == 0xe0 || scancode == 0xe1) {
++ prev_scancode = scancode;
++ return 0;
++ }
++
++ if (scancode == 0x00 || scancode == 0xff) {
++ prev_scancode = 0;
++ return 0;
++ }
++
++ *keycode = scancode;
++
++ return 1;
++}
++
++/* init button hardware */
++static int button_hw_init(void)
++{
++ unsigned int ipinfunc=0;
++
++ printk("au1200_ibutton.c: Initializing buttons hardware\n");
++
++ // initialize GPIO pin function assignments
++
++ ipinfunc = au_readl(SYS_PINFUNC);
++
++ ipinfunc &= ~(SYS_PINFUNC_DMA | SYS_PINFUNC_S0A | SYS_PINFUNC_S0B);
++ au_writel( ipinfunc ,SYS_PINFUNC);
++
++ ipinfunc |= (SYS_PINFUNC_S0C);
++ au_writel( ipinfunc ,SYS_PINFUNC);
++
++ return 0;
++}
++
++/* button driver init */
++static int __init button_init(void)
++{
++ int ret, i;
++ unsigned int flag=0;
++
++ printk("au1200_ibutton.c: button_init()\r\n");
++
++ button_hw_init();
++
++ /* register all button irq handler */
++
++ for(i=0; i< sizeof(button_map)/sizeof(button_map[0]); i++)
++ {
++ /* register irq <-- gpio 1 ,6 ,12 , 17 ,19 , 26 ,28 */
++ if(button_map[i] != 0)
++ {
++ ret = request_irq(AU1000_GPIO_0 + i ,
++ &button_interrupt , SA_INTERRUPT ,
++ DRIVER_NAME , &dev);
++ if(ret) flag |= 1<<i;
++ }
++ }
++
++ printk("au1200_ibutton.c: request_irq,ret:0x%x\r\n",ret);
++
++ if (ret) {
++ printk("au1200_ibutton.c: request_irq:%X failed\r\n",flag);
++ return ret;
++ }
++
++ dev.name = DRIVER_NAME;
++ dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
++
++ for (i=0;i<sizeof(button_map)/sizeof(button_map[0]);i++)
++ {
++ dev.keybit[LONG(button_map[i])] |= BIT(button_map[i]);
++ }
++
++ input_register_device(&dev);
++
++ /* ready to receive interrupts */
++
++ return 0;
++}
++
++/* button driver exit */
++static void __exit button_exit(void)
++{
++ int i;
++
++ for(i=0;i<sizeof(button_map)/sizeof(button_map[0]);i++)
++ {
++ if(button_map[i] != 0)
++ {
++ free_irq( AU1000_GPIO_0 + i, &dev);
++ }
++ }
++
++ input_unregister_device(&dev);
++
++ printk("au1200_ibutton.c: button_exit()\r\n");
++}
++
++module_init(button_init);
++module_exit(button_exit);
++
++MODULE_AUTHOR( DRIVER_AUTHOR );
++MODULE_DESCRIPTION( DRIVER_DESC );
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/ficmmp/au1xxx_dock.c linux-2.4.32-rc1.mips/arch/mips/au1000/ficmmp/au1xxx_dock.c
+--- linux-2.4.32-rc1/arch/mips/au1000/ficmmp/au1xxx_dock.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/ficmmp/au1xxx_dock.c 2005-01-30 09:01:27.000000000 +0100
+@@ -0,0 +1,261 @@
++/*
++ * Copyright (C) 2003 Metrowerks, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/sched.h>
++#include <linux/miscdevice.h>
++#include <linux/errno.h>
++#include <linux/poll.h>
++#include <asm/au1000.h>
++#include <asm/uaccess.h>
++#include <asm/au1xxx_gpio.h>
++
++
++#if defined(CONFIG_MIPS_FICMMP)
++ #define DOCK_GPIO 215
++#else
++ #error Unsupported Au1xxx Platform
++#endif
++
++#define MAKE_FLAG 0x20
++
++#undef DEBUG
++
++#define DEBUG 0
++//#define DEBUG 1
++
++#if DEBUG
++#define DPRINTK(format, args...) printk(__FUNCTION__ ": " format, ## args)
++#else
++#define DPRINTK(format, args...) do { } while (0)
++#endif
++
++/* Please note that this driver is based on a timer and is not interrupt
++ * driven. If you are going to make use of this driver, you will need to have
++ * your application open the dock listing from the /dev directory first.
++ */
++
++struct au1xxx_dock {
++ struct fasync_struct *fasync;
++ wait_queue_head_t read_wait;
++ int open_count;
++ unsigned int debounce;
++ unsigned int current;
++ unsigned int last;
++};
++
++static struct au1xxx_dock dock_info;
++
++
++static void dock_timer_periodic(void *data);
++
++static struct tq_struct dock_task = {
++ routine: dock_timer_periodic,
++ data: NULL
++};
++
++static int cleanup_flag = 0;
++static DECLARE_WAIT_QUEUE_HEAD(cleanup_wait_queue);
++
++
++static unsigned int read_dock_state(void)
++{
++ u32 state;
++
++ state = au1xxx_gpio_read(DOCK_GPIO);
++
++ /* printk( "Current Dock State: %d\n", state ); */
++
++ return state;
++}
++
++
++static void dock_timer_periodic(void *data)
++{
++ struct au1xxx_dock *dock = (struct au1xxx_dock *)data;
++ unsigned long dock_state;
++
++ /* If cleanup wants us to die */
++ if (cleanup_flag) {
++ /* now cleanup_module can return */
++ wake_up(&cleanup_wait_queue);
++ } else {
++ /* put ourselves back in the task queue */
++ queue_task(&dock_task, &tq_timer);
++ }
++
++ /* read current dock */
++ dock_state = read_dock_state();
++
++ /* if dock states hasn't changed */
++ /* save time and be done. */
++ if (dock_state == dock->current) {
++ return;
++ }
++
++ if (dock_state == dock->debounce) {
++ dock->current = dock_state;
++ } else {
++ dock->debounce = dock_state;
++ }
++ if (dock->current != dock->last) {
++ if (waitqueue_active(&dock->read_wait)) {
++ wake_up_interruptible(&dock->read_wait);
++ }
++ }
++}
++
++
++static ssize_t au1xxx_dock_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
++{
++ struct au1xxx_dock *dock = filp->private_data;
++ char event[3];
++ int last;
++ int cur;
++ int err;
++
++try_again:
++
++ while (dock->current == dock->last) {
++ if (filp->f_flags & O_NONBLOCK) {
++ return -EAGAIN;
++ }
++ interruptible_sleep_on(&dock->read_wait);
++ if (signal_pending(current)) {
++ return -ERESTARTSYS;
++ }
++ }
++
++ cur = dock->current;
++ last = dock->last;
++
++ if(cur != last)
++ {
++ event[0] = cur ? 'D' : 'U';
++ event[1] = '\r';
++ event[2] = '\n';
++ }
++ else
++ goto try_again;
++
++ dock->last = cur;
++ err = copy_to_user(buffer, &event, 3);
++ if (err) {
++ return err;
++ }
++
++ return 3;
++}
++
++
++static int au1xxx_dock_open(struct inode *inode, struct file *filp)
++{
++ struct au1xxx_dock *dock = &dock_info;
++
++ MOD_INC_USE_COUNT;
++
++ filp->private_data = dock;
++
++ if (dock->open_count++ == 0) {
++ dock_task.data = dock;
++ cleanup_flag = 0;
++ queue_task(&dock_task, &tq_timer);
++ }
++
++ return 0;
++}
++
++
++static unsigned int au1xxx_dock_poll(struct file *filp, poll_table *wait)
++{
++ struct au1xxx_dock *dock = filp->private_data;
++ int ret = 0;
++
++ DPRINTK("start\n");
++ poll_wait(filp, &dock->read_wait, wait);
++ if (dock->current != dock->last) {
++ ret = POLLIN | POLLRDNORM;
++ }
++ return ret;
++}
++
++
++static int au1xxx_dock_release(struct inode *inode, struct file *filp)
++{
++ struct au1xxx_dock *dock = filp->private_data;
++
++ DPRINTK("start\n");
++
++ if (--dock->open_count == 0) {
++ cleanup_flag = 1;
++ sleep_on(&cleanup_wait_queue);
++ }
++ MOD_DEC_USE_COUNT;
++
++ return 0;
++}
++
++
++
++static struct file_operations au1xxx_dock_fops = {
++ owner: THIS_MODULE,
++ read: au1xxx_dock_read,
++ poll: au1xxx_dock_poll,
++ open: au1xxx_dock_open,
++ release: au1xxx_dock_release,
++};
++
++/*
++ * The au1xxx dock is a misc device:
++ * Major 10 char
++ * Minor 22 /dev/dock
++ *
++ * This is /dev/misc/dock if devfs is used.
++ */
++
++static struct miscdevice au1xxx_dock_dev = {
++ minor: 23,
++ name: "dock",
++ fops: &au1xxx_dock_fops,
++};
++
++static int __init au1xxx_dock_init(void)
++{
++ struct au1xxx_dock *dock = &dock_info;
++ int ret;
++
++ DPRINTK("Initializing dock driver\n");
++ dock->open_count = 0;
++ cleanup_flag = 0;
++ init_waitqueue_head(&dock->read_wait);
++
++
++ /* yamon configures GPIO pins for the dock
++ * no initialization needed
++ */
++
++ ret = misc_register(&au1xxx_dock_dev);
++
++ DPRINTK("dock driver fully initialized.\n");
++
++ return ret;
++}
++
++
++static void __exit au1xxx_dock_exit(void)
++{
++ DPRINTK("unloading dock driver\n");
++ misc_deregister(&au1xxx_dock_dev);
++}
++
++
++module_init(au1xxx_dock_init);
++module_exit(au1xxx_dock_exit);
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/ficmmp/board_setup.c linux-2.4.32-rc1.mips/arch/mips/au1000/ficmmp/board_setup.c
+--- linux-2.4.32-rc1/arch/mips/au1000/ficmmp/board_setup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/ficmmp/board_setup.c 2005-03-19 08:17:51.000000000 +0100
+@@ -0,0 +1,226 @@
++/*
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Alchemy Pb1200 board setup.
++ *
++ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/console.h>
++#include <linux/mc146818rtc.h>
++#include <linux/delay.h>
++#include <linux/ide.h>
++
++#if defined(CONFIG_BLK_DEV_IDE_AU1XXX)
++#include <linux/ide.h>
++#endif
++
++#include <asm/cpu.h>
++#include <asm/bootinfo.h>
++#include <asm/irq.h>
++#include <asm/keyboard.h>
++#include <asm/mipsregs.h>
++#include <asm/reboot.h>
++#include <asm/pgtable.h>
++#include <asm/au1000.h>
++#include <asm/ficmmp.h>
++#include <asm/au1xxx_dbdma.h>
++#include <asm/au1xxx_gpio.h>
++
++extern struct rtc_ops no_rtc_ops;
++
++/* value currently in the board configuration register */
++u16 ficmmp_config = 0;
++
++#if defined(CONFIG_BLK_DEV_IDE_AU1XXX)
++extern struct ide_ops *ide_ops;
++extern struct ide_ops au1xxx_ide_ops;
++extern u32 au1xxx_ide_virtbase;
++extern u64 au1xxx_ide_physbase;
++extern int au1xxx_ide_irq;
++
++u32 led_base_addr;
++/* Ddma */
++chan_tab_t *ide_read_ch, *ide_write_ch;
++u32 au1xxx_ide_ddma_enable = 0, switch4ddma = 1; // PIO+ddma
++
++dbdev_tab_t new_dbdev_tab_element = { DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 };
++#endif /* end CONFIG_BLK_DEV_IDE_AU1XXX */
++
++void board_reset (void)
++{
++ au_writel(0, 0xAD80001C);
++}
++
++void board_power_off (void)
++{
++}
++
++void __init board_setup(void)
++{
++ char *argptr = NULL;
++ u32 pin_func;
++ rtc_ops = &no_rtc_ops;
++
++ ficmmp_config_init(); //Initialize FIC control register
++
++#if 0
++ /* Enable PSC1 SYNC for AC97. Normaly done in audio driver,
++ * but it is board specific code, so put it here.
++ */
++ pin_func = au_readl(SYS_PINFUNC);
++ au_sync();
++ pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1;
++ au_writel(pin_func, SYS_PINFUNC);
++
++ au_writel(0, (u32)bcsr|0x10); /* turn off pcmcia power */
++ au_sync();
++#endif
++
++#if defined( CONFIG_I2C_ALGO_AU1550 )
++ {
++ u32 freq0, clksrc;
++
++ /* Select SMBUS in CPLD */
++ /* bcsr->resets &= ~(BCSR_RESETS_PCS0MUX); */
++
++ pin_func = au_readl(SYS_PINFUNC);
++ au_sync();
++ pin_func &= ~(3<<17 | 1<<4);
++ /* Set GPIOs correctly */
++ pin_func |= 2<<17;
++ au_writel(pin_func, SYS_PINFUNC);
++ au_sync();
++
++ /* The i2c driver depends on 50Mhz clock */
++ freq0 = au_readl(SYS_FREQCTRL0);
++ au_sync();
++ freq0 &= ~(SYS_FC_FRDIV1_MASK | SYS_FC_FS1 | SYS_FC_FE1);
++ freq0 |= (3<<SYS_FC_FRDIV1_BIT);
++ /* 396Mhz / (3+1)*2 == 49.5Mhz */
++ au_writel(freq0, SYS_FREQCTRL0);
++ au_sync();
++ freq0 |= SYS_FC_FE1;
++ au_writel(freq0, SYS_FREQCTRL0);
++ au_sync();
++
++ clksrc = au_readl(SYS_CLKSRC);
++ au_sync();
++ clksrc &= ~0x01f00000;
++ /* bit 22 is EXTCLK0 for PSC0 */
++ clksrc |= (0x3 << 22);
++ au_writel(clksrc, SYS_CLKSRC);
++ au_sync();
++ }
++#endif
++
++#ifdef CONFIG_FB_AU1200
++ argptr = prom_getcmdline();
++ strcat(argptr, " video=au1200fb:");
++#endif
++
++#if defined(CONFIG_BLK_DEV_IDE_AU1XXX)
++ /*
++ * Iniz IDE parameters
++ */
++ ide_ops = &au1xxx_ide_ops;
++ au1xxx_ide_irq = FICMMP_IDE_INT;
++ au1xxx_ide_physbase = AU1XXX_ATA_PHYS_ADDR;
++ au1xxx_ide_virtbase = KSEG1ADDR(AU1XXX_ATA_PHYS_ADDR);
++ switch4ddma = 0;
++ /*
++ ide_ops = &au1xxx_ide_ops;
++ au1xxx_ide_irq = FICMMP_IDE_INT;
++ au1xxx_ide_base = KSEG1ADDR(AU1XXX_ATA_BASE);
++ */
++ au1xxx_gpio_write(9, 1);
++ printk("B4001010: %X\n", *((u32*)0xB4001010));
++ printk("B4001014: %X\n", *((u32*)0xB4001014));
++ printk("B4001018: %X\n", *((u32*)0xB4001018));
++ printk("B1900100: %X\n", *((u32*)0xB1900100));
++
++#if 0
++ ficmmp_config_clear(FICMMP_CONFIG_IDERST);
++ mdelay(100);
++ ficmmp_config_set(FICMMP_CONFIG_IDERST);
++ mdelay(100);
++#endif
++ /*
++ * change PIO or PIO+Ddma
++ * check the GPIO-5 pin condition. pb1200:s18_dot
++ */
++/* switch4ddma = 0; //(au_readl(SYS_PINSTATERD) & (1 << 5)) ? 1 : 0; */
++#endif
++
++ /* The Pb1200 development board uses external MUX for PSC0 to
++ support SMB/SPI. bcsr->resets bit 12: 0=SMB 1=SPI
++ */
++#if defined(CONFIG_AU1550_PSC_SPI) && defined(CONFIG_I2C_ALGO_AU1550)
++ #error I2C and SPI are mutually exclusive. Both are physically connected to PSC0.\
++ Refer to Pb1200 documentation.
++#elif defined( CONFIG_AU1550_PSC_SPI )
++ //bcsr->resets |= BCSR_RESETS_PCS0MUX;
++#elif defined( CONFIG_I2C_ALGO_AU1550 )
++ //bcsr->resets &= (~BCSR_RESETS_PCS0MUX);
++#endif
++ au_sync();
++
++ printk("FIC Multimedia Player Board\n");
++ au1xxx_gpio_tristate(5);
++ printk("B1900100: %X\n", *((volatile u32*)0xB1900100));
++ printk("B190002C: %X\n", *((volatile u32*)0xB190002C));
++}
++
++int
++board_au1200fb_panel (void)
++{
++ au1xxx_gpio_tristate(6);
++
++ if (au1xxx_gpio_read(12) == 0)
++ return 9; /* FS453_640x480 (Composite/S-Video) */
++ else
++ return 7; /* Sharp 320x240 TFT */
++}
++
++int
++board_au1200fb_panel_init (void)
++{
++ /*Enable data buffers*/
++ ficmmp_config_clear(FICMMP_CONFIG_LCMDATAOUT);
++ /*Take LCD out of reset*/
++ ficmmp_config_set(FICMMP_CONFIG_LCMPWREN | FICMMP_CONFIG_LCMEN);
++ return 0;
++}
++
++int
++board_au1200fb_panel_shutdown (void)
++{
++ /*Disable data buffers*/
++ ficmmp_config_set(FICMMP_CONFIG_LCMDATAOUT);
++ /*Put LCD in reset, remove power*/
++ ficmmp_config_clear(FICMMP_CONFIG_LCMEN | FICMMP_CONFIG_LCMPWREN);
++ return 0;
++}
++
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/ficmmp/init.c linux-2.4.32-rc1.mips/arch/mips/au1000/ficmmp/init.c
+--- linux-2.4.32-rc1/arch/mips/au1000/ficmmp/init.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/ficmmp/init.c 2005-01-30 09:01:27.000000000 +0100
+@@ -0,0 +1,76 @@
++/*
++ *
++ * BRIEF MODULE DESCRIPTION
++ * PB1200 board setup
++ *
++ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/bootmem.h>
++#include <asm/addrspace.h>
++#include <asm/bootinfo.h>
++#include <linux/config.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++
++int prom_argc;
++char **prom_argv, **prom_envp;
++extern void __init prom_init_cmdline(void);
++extern char *prom_getenv(char *envname);
++
++const char *get_system_type(void)
++{
++ return "FIC Multimedia Player (Au1200)";
++}
++
++u32 mae_memsize = 0;
++
++int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
++{
++ unsigned char *memsize_str;
++ unsigned long memsize;
++
++ prom_argc = argc;
++ prom_argv = argv;
++ prom_envp = envp;
++
++ mips_machgroup = MACH_GROUP_ALCHEMY;
++ mips_machtype = MACH_PB1000; /* set the platform # */
++ prom_init_cmdline();
++
++ memsize_str = prom_getenv("memsize");
++ if (!memsize_str) {
++ memsize = 0x08000000;
++ } else {
++ memsize = simple_strtol(memsize_str, NULL, 0);
++ }
++
++ /* reserved 32MB for MAE driver */
++ memsize -= (32 * 1024 * 1024);
++ add_memory_region(0, memsize, BOOT_MEM_RAM);
++ mae_memsize = memsize; /* for drivers/char/au1xxx_mae.c */
++ return 0;
++}
++
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/ficmmp/irqmap.c linux-2.4.32-rc1.mips/arch/mips/au1000/ficmmp/irqmap.c
+--- linux-2.4.32-rc1/arch/mips/au1000/ficmmp/irqmap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/ficmmp/irqmap.c 2005-01-30 09:01:27.000000000 +0100
+@@ -0,0 +1,61 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ * Au1xxx irq map table
++ *
++ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++#include <linux/kernel_stat.h>
++#include <linux/module.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/timex.h>
++#include <linux/slab.h>
++#include <linux/random.h>
++#include <linux/delay.h>
++
++#include <asm/bitops.h>
++#include <asm/bootinfo.h>
++#include <asm/io.h>
++#include <asm/mipsregs.h>
++#include <asm/system.h>
++#include <asm/au1000.h>
++#include <asm/ficmmp.h>
++
++au1xxx_irq_map_t au1xxx_irq_map[] = {
++ { FICMMP_IDE_INT, INTC_INT_HIGH_LEVEL, 0 },
++ { AU1XXX_SMC91111_IRQ, INTC_INT_HIGH_LEVEL, 0 },
++ { AU1000_GPIO_1 , INTC_INT_FALL_EDGE, 0 }, // main button
++ { AU1000_GPIO_6 , INTC_INT_RISE_EDGE, 0 }, // select button
++ { AU1000_GPIO_12, INTC_INT_FALL_EDGE, 0 }, // guide button
++ { AU1000_GPIO_17, INTC_INT_RISE_EDGE, 0 }, // down button
++ { AU1000_GPIO_19, INTC_INT_RISE_EDGE, 0 }, // left button
++ { AU1000_GPIO_26, INTC_INT_RISE_EDGE, 0 }, // right button
++ { AU1000_GPIO_28, INTC_INT_RISE_EDGE, 0 }, // up button
++};
++
++int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t);
++
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/ficmmp/Makefile linux-2.4.32-rc1.mips/arch/mips/au1000/ficmmp/Makefile
+--- linux-2.4.32-rc1/arch/mips/au1000/ficmmp/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/ficmmp/Makefile 2005-01-30 09:01:27.000000000 +0100
+@@ -0,0 +1,25 @@
++#
++# Copyright 2000 MontaVista Software Inc.
++# Author: MontaVista Software, Inc.
++# ppopov@mvista.com or source@mvista.com
++#
++# Makefile for the Alchemy Semiconductor FIC board.
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++
++USE_STANDARD_AS_RULE := true
++
++O_TARGET := ficmmp.o
++
++obj-y := init.o board_setup.o irqmap.o au1200_ibutton.o au1xxx_dock.o
++
++ifdef CONFIG_MMC
++obj-y += mmc_support.o
++export-objs +=mmc_support.o
++endif
++
++
++include $(TOPDIR)/Rules.make
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/hydrogen3/board_setup.c linux-2.4.32-rc1.mips/arch/mips/au1000/hydrogen3/board_setup.c
+--- linux-2.4.32-rc1/arch/mips/au1000/hydrogen3/board_setup.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/hydrogen3/board_setup.c 2005-03-19 08:17:51.000000000 +0100
+@@ -51,12 +51,19 @@
+ {
+ }
+
++void board_power_off (void)
++{
++}
++
+ void __init board_setup(void)
+ {
+ u32 pin_func;
+
+ rtc_ops = &no_rtc_ops;
+
++ /* Set GPIO14 high to make CD/DAT1 high for MMC to work */
++ au_writel(1<<14, SYS_OUTPUTSET);
++
+ #ifdef CONFIG_AU1X00_USB_DEVICE
+ // 2nd USB port is USB device
+ pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/hydrogen3/buttons.c linux-2.4.32-rc1.mips/arch/mips/au1000/hydrogen3/buttons.c
+--- linux-2.4.32-rc1/arch/mips/au1000/hydrogen3/buttons.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/hydrogen3/buttons.c 2005-02-11 22:09:55.000000000 +0100
+@@ -0,0 +1,308 @@
++/*
++ * Copyright (C) 2003 Metrowerks, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/sched.h>
++#include <linux/miscdevice.h>
++#include <linux/errno.h>
++#include <linux/poll.h>
++#include <asm/au1000.h>
++#include <asm/uaccess.h>
++
++#define BUTTON_SELECT (1<<1)
++#define BUTTON_1 (1<<2)
++#define BUTTON_2 (1<<3)
++#define BUTTON_ONOFF (1<<6)
++#define BUTTON_3 (1<<7)
++#define BUTTON_4 (1<<8)
++#define BUTTON_LEFT (1<<9)
++#define BUTTON_DOWN (1<<10)
++#define BUTTON_RIGHT (1<<11)
++#define BUTTON_UP (1<<12)
++
++#define BUTTON_MASK (\
++ BUTTON_SELECT \
++ | BUTTON_1 \
++ | BUTTON_2 \
++ | BUTTON_ONOFF \
++ | BUTTON_3 \
++ | BUTTON_4 \
++ | BUTTON_LEFT \
++ | BUTTON_DOWN \
++ | BUTTON_RIGHT \
++ | BUTTON_UP \
++ )
++
++#define BUTTON_INVERT (\
++ BUTTON_SELECT \
++ | BUTTON_1 \
++ | BUTTON_2 \
++ | BUTTON_3 \
++ | BUTTON_4 \
++ | BUTTON_LEFT \
++ | BUTTON_DOWN \
++ | BUTTON_RIGHT \
++ | BUTTON_UP \
++ )
++
++
++
++#define MAKE_FLAG 0x20
++
++#undef DEBUG
++
++#define DEBUG 0
++//#define DEBUG 1
++
++#if DEBUG
++#define DPRINTK(format, args...) printk(__FUNCTION__ ": " format, ## args)
++#else
++#define DPRINTK(format, args...) do { } while (0)
++#endif
++
++/* Please note that this driver is based on a timer and is not interrupt
++ * driven. If you are going to make use of this driver, you will need to have
++ * your application open the buttons listing from the /dev directory first.
++ */
++
++struct hydrogen3_buttons {
++ struct fasync_struct *fasync;
++ wait_queue_head_t read_wait;
++ int open_count;
++ unsigned int debounce;
++ unsigned int current;
++ unsigned int last;
++};
++
++static struct hydrogen3_buttons buttons_info;
++
++
++static void button_timer_periodic(void *data);
++
++static struct tq_struct button_task = {
++ routine: button_timer_periodic,
++ data: NULL
++};
++
++static int cleanup_flag = 0;
++static DECLARE_WAIT_QUEUE_HEAD(cleanup_wait_queue);
++
++
++static unsigned int read_button_state(void)
++{
++ unsigned long state;
++
++ state = inl(SYS_PINSTATERD) & BUTTON_MASK;
++ state ^= BUTTON_INVERT;
++
++ DPRINTK( "Current Button State: %d\n", state );
++
++ return state;
++}
++
++
++static void button_timer_periodic(void *data)
++{
++ struct hydrogen3_buttons *buttons = (struct hydrogen3_buttons *)data;
++ unsigned long button_state;
++
++ // If cleanup wants us to die
++ if (cleanup_flag) {
++ wake_up(&cleanup_wait_queue); // now cleanup_module can return
++ } else {
++ queue_task(&button_task, &tq_timer); // put ourselves back in the task queue
++ }
++
++ // read current buttons
++ button_state = read_button_state();
++
++ // if no buttons are down and nothing to do then
++ // save time and be done.
++ if ((button_state == 0) && (buttons->current == 0)) {
++ return;
++ }
++
++ if (button_state == buttons->debounce) {
++ buttons->current = button_state;
++ } else {
++ buttons->debounce = button_state;
++ }
++// printk("0x%04x\n", button_state);
++ if (buttons->current != buttons->last) {
++ if (waitqueue_active(&buttons->read_wait)) {
++ wake_up_interruptible(&buttons->read_wait);
++ }
++ }
++}
++
++
++static ssize_t hydrogen3_buttons_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
++{
++ struct hydrogen3_buttons *buttons = filp->private_data;
++ char events[16];
++ int index;
++ int last;
++ int cur;
++ int bit;
++ int bit_mask;
++ int err;
++
++ DPRINTK("start\n");
++
++try_again:
++
++ while (buttons->current == buttons->last) {
++ if (filp->f_flags & O_NONBLOCK) {
++ return -EAGAIN;
++ }
++ interruptible_sleep_on(&buttons->read_wait);
++ if (signal_pending(current)) {
++ return -ERESTARTSYS;
++ }
++ }
++
++ cur = buttons->current;
++ last = buttons->last;
++
++ index = 0;
++ bit_mask = 1;
++ for (bit = 0; (bit < 16) && count; bit++) {
++ if ((cur ^ last) & bit_mask) {
++ if (cur & bit_mask) {
++ events[index] = (bit | MAKE_FLAG) + 'A';
++ last |= bit_mask;
++ } else {
++ events[index] = bit + 'A';
++ last &= ~bit_mask;
++ }
++ index++;
++ count--;
++ }
++ bit_mask <<= 1;
++ }
++ buttons->last = last;
++
++ if (index == 0) {
++ goto try_again;
++ }
++
++ err = copy_to_user(buffer, events, index);
++ if (err) {
++ return err;
++ }
++
++ return index;
++}
++
++
++static int hydrogen3_buttons_open(struct inode *inode, struct file *filp)
++{
++ struct hydrogen3_buttons *buttons = &buttons_info;
++
++ DPRINTK("start\n");
++ MOD_INC_USE_COUNT;
++
++ filp->private_data = buttons;
++
++ if (buttons->open_count++ == 0) {
++ button_task.data = buttons;
++ cleanup_flag = 0;
++ queue_task(&button_task, &tq_timer);
++ }
++
++ return 0;
++}
++
++
++static unsigned int hydrogen3_buttons_poll(struct file *filp, poll_table *wait)
++{
++ struct hydrogen3_buttons *buttons = filp->private_data;
++ int ret = 0;
++
++ DPRINTK("start\n");
++ poll_wait(filp, &buttons->read_wait, wait);
++ if (buttons->current != buttons->last) {
++ ret = POLLIN | POLLRDNORM;
++ }
++ return ret;
++}
++
++
++static int hydrogen3_buttons_release(struct inode *inode, struct file *filp)
++{
++ struct hydrogen3_buttons *buttons = filp->private_data;
++
++ DPRINTK("start\n");
++
++ if (--buttons->open_count == 0) {
++ cleanup_flag = 1;
++ sleep_on(&cleanup_wait_queue);
++ }
++ MOD_DEC_USE_COUNT;
++
++ return 0;
++}
++
++
++
++static struct file_operations hydrogen3_buttons_fops = {
++ owner: THIS_MODULE,
++ read: hydrogen3_buttons_read,
++ poll: hydrogen3_buttons_poll,
++ open: hydrogen3_buttons_open,
++ release: hydrogen3_buttons_release,
++};
++
++/*
++ * The hydrogen3 buttons is a misc device:
++ * Major 10 char
++ * Minor 22 /dev/buttons
++ *
++ * This is /dev/misc/buttons if devfs is used.
++ */
++
++static struct miscdevice hydrogen3_buttons_dev = {
++ minor: 22,
++ name: "buttons",
++ fops: &hydrogen3_buttons_fops,
++};
++
++static int __init hydrogen3_buttons_init(void)
++{
++ struct hydrogen3_buttons *buttons = &buttons_info;
++ int ret;
++
++ DPRINTK("Initializing buttons driver\n");
++ buttons->open_count = 0;
++ cleanup_flag = 0;
++ init_waitqueue_head(&buttons->read_wait);
++
++
++ // yamon configures GPIO pins for the buttons
++ // no initialization needed
++
++ ret = misc_register(&hydrogen3_buttons_dev);
++
++ DPRINTK("Buttons driver fully initialized.\n");
++
++ return ret;
++}
++
++
++static void __exit hydrogen3_buttons_exit(void)
++{
++ DPRINTK("unloading buttons driver\n");
++ misc_deregister(&hydrogen3_buttons_dev);
++}
++
++
++module_init(hydrogen3_buttons_init);
++module_exit(hydrogen3_buttons_exit);
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/hydrogen3/Makefile linux-2.4.32-rc1.mips/arch/mips/au1000/hydrogen3/Makefile
+--- linux-2.4.32-rc1/arch/mips/au1000/hydrogen3/Makefile 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/hydrogen3/Makefile 2005-02-11 22:09:55.000000000 +0100
+@@ -14,6 +14,11 @@
+
+ O_TARGET := hydrogen3.o
+
+-obj-y := init.o board_setup.o irqmap.o
++obj-y := init.o board_setup.o irqmap.o buttons.o
++
++ifdef CONFIG_MMC
++obj-y += mmc_support.o
++export-objs +=mmc_support.o
++endif
+
+ include $(TOPDIR)/Rules.make
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/hydrogen3/mmc_support.c linux-2.4.32-rc1.mips/arch/mips/au1000/hydrogen3/mmc_support.c
+--- linux-2.4.32-rc1/arch/mips/au1000/hydrogen3/mmc_support.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/hydrogen3/mmc_support.c 2005-02-02 05:27:06.000000000 +0100
+@@ -0,0 +1,89 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ *
++ * MMC support routines for Hydrogen3.
++ *
++ *
++ * Copyright (c) 2003-2004 Embedded Edge, LLC.
++ * Author: Embedded Edge, LLC.
++ * Contact: dan@embeddededge.com
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++
++#include <asm/irq.h>
++#include <asm/au1000.h>
++#include <asm/au1100_mmc.h>
++
++#define GPIO_17_WP 0x20000
++
++/* SD/MMC controller support functions */
++
++/*
++ * Detect card.
++ */
++void mmc_card_inserted(int _n_, int *_res_)
++{
++ u32 gpios = au_readl(SYS_PINSTATERD);
++ u32 emptybit = (1<<16);
++ *_res_ = ((gpios & emptybit) == 0);
++}
++
++/*
++ * Check card write protection.
++ */
++void mmc_card_writable(int _n_, int *_res_)
++{
++ unsigned long mmc_wp, board_specific;
++ board_specific = au_readl(SYS_OUTPUTSET);
++ mmc_wp=GPIO_17_WP;
++ if (!(board_specific & mmc_wp)) {/* low means card writable */
++ *_res_ = 1;
++ } else {
++ *_res_ = 0;
++ }
++}
++/*
++ * Apply power to card slot.
++ */
++void mmc_power_on(int _n_)
++{
++}
++
++/*
++ * Remove power from card slot.
++ */
++void mmc_power_off(int _n_)
++{
++}
++
++EXPORT_SYMBOL(mmc_card_inserted);
++EXPORT_SYMBOL(mmc_card_writable);
++EXPORT_SYMBOL(mmc_power_on);
++EXPORT_SYMBOL(mmc_power_off);
++
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/mtx-1/board_setup.c linux-2.4.32-rc1.mips/arch/mips/au1000/mtx-1/board_setup.c
+--- linux-2.4.32-rc1/arch/mips/au1000/mtx-1/board_setup.c 2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/mtx-1/board_setup.c 2004-11-26 09:37:16.000000000 +0100
+@@ -48,6 +48,12 @@
+
+ extern struct rtc_ops no_rtc_ops;
+
++void board_reset (void)
++{
++ /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
++ au_writel(0x00000000, 0xAE00001C);
++}
++
+ void __init board_setup(void)
+ {
+ rtc_ops = &no_rtc_ops;
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/mtx-1/irqmap.c linux-2.4.32-rc1.mips/arch/mips/au1000/mtx-1/irqmap.c
+--- linux-2.4.32-rc1/arch/mips/au1000/mtx-1/irqmap.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/mtx-1/irqmap.c 2004-11-26 09:37:16.000000000 +0100
+@@ -72,10 +72,10 @@
+ * A B C D
+ */
+ {
+- {INTA, INTB, INTC, INTD}, /* IDSEL 0 */
+- {INTA, INTB, INTC, INTD}, /* IDSEL 1 */
+- {INTA, INTB, INTC, INTD}, /* IDSEL 2 */
+- {INTA, INTB, INTC, INTD}, /* IDSEL 3 */
++ {INTA, INTB, INTX, INTX}, /* IDSEL 0 */
++ {INTB, INTA, INTX, INTX}, /* IDSEL 1 */
++ {INTC, INTD, INTX, INTX}, /* IDSEL 2 */
++ {INTD, INTC, INTX, INTX}, /* IDSEL 3 */
+ };
+ const long min_idsel = 0, max_idsel = 3, irqs_per_slot = 4;
+ return PCI_IRQ_TABLE_LOOKUP;
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/pb1000/board_setup.c linux-2.4.32-rc1.mips/arch/mips/au1000/pb1000/board_setup.c
+--- linux-2.4.32-rc1/arch/mips/au1000/pb1000/board_setup.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/pb1000/board_setup.c 2005-03-19 08:17:51.000000000 +0100
+@@ -58,6 +58,10 @@
+ {
+ }
+
++void board_power_off (void)
++{
++}
++
+ void __init board_setup(void)
+ {
+ u32 pin_func, static_cfg0;
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/pb1100/board_setup.c linux-2.4.32-rc1.mips/arch/mips/au1000/pb1100/board_setup.c
+--- linux-2.4.32-rc1/arch/mips/au1000/pb1100/board_setup.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/pb1100/board_setup.c 2005-03-19 08:17:51.000000000 +0100
+@@ -62,6 +62,10 @@
+ au_writel(0x00000000, 0xAE00001C);
+ }
+
++void board_power_off (void)
++{
++}
++
+ void __init board_setup(void)
+ {
+ u32 pin_func;
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/pb1100/Makefile linux-2.4.32-rc1.mips/arch/mips/au1000/pb1100/Makefile
+--- linux-2.4.32-rc1/arch/mips/au1000/pb1100/Makefile 2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/pb1100/Makefile 2005-01-30 09:10:29.000000000 +0100
+@@ -16,4 +16,10 @@
+
+ obj-y := init.o board_setup.o irqmap.o
+
++
++ifdef CONFIG_MMC
++obj-y += mmc_support.o
++export-objs += mmc_support.o
++endif
++
+ include $(TOPDIR)/Rules.make
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/pb1100/mmc_support.c linux-2.4.32-rc1.mips/arch/mips/au1000/pb1100/mmc_support.c
+--- linux-2.4.32-rc1/arch/mips/au1000/pb1100/mmc_support.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/pb1100/mmc_support.c 2005-01-30 09:10:29.000000000 +0100
+@@ -0,0 +1,126 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ *
++ * MMC support routines for PB1100.
++ *
++ *
++ * Copyright (c) 2003-2004 Embedded Edge, LLC.
++ * Author: Embedded Edge, LLC.
++ * Contact: dan@embeddededge.com
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++
++#include <asm/irq.h>
++#include <asm/au1000.h>
++#include <asm/au1100_mmc.h>
++#include <asm/pb1100.h>
++
++
++/* SD/MMC controller support functions */
++
++/*
++ * Detect card.
++ */
++void mmc_card_inserted(int _n_, int *_res_)
++{
++ u32 gpios = au_readl(SYS_PINSTATERD);
++ u32 emptybit = (_n_) ? (1<<15) : (1<<14);
++ *_res_ = ((gpios & emptybit) == 0);
++}
++
++/*
++ * Check card write protection.
++ */
++void mmc_card_writable(int _n_, int *_res_)
++{
++ BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++ unsigned long mmc_wp, board_specific;
++
++ if (_n_) {
++ mmc_wp = BCSR_PCMCIA_SD1_WP;
++ } else {
++ mmc_wp = BCSR_PCMCIA_SD0_WP;
++ }
++
++ board_specific = au_readl((unsigned long)(&bcsr->pcmcia));
++
++ if (!(board_specific & mmc_wp)) {/* low means card writable */
++ *_res_ = 1;
++ } else {
++ *_res_ = 0;
++ }
++}
++
++/*
++ * Apply power to card slot.
++ */
++void mmc_power_on(int _n_)
++{
++ BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++ unsigned long mmc_pwr, board_specific;
++
++ if (_n_) {
++ mmc_pwr = BCSR_PCMCIA_SD1_PWR;
++ } else {
++ mmc_pwr = BCSR_PCMCIA_SD0_PWR;
++ }
++
++ board_specific = au_readl((unsigned long)(&bcsr->pcmcia));
++ board_specific |= mmc_pwr;
++
++ au_writel(board_specific, (int)(&bcsr->pcmcia));
++ au_sync_delay(1);
++}
++
++/*
++ * Remove power from card slot.
++ */
++void mmc_power_off(int _n_)
++{
++ BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++ unsigned long mmc_pwr, board_specific;
++
++ if (_n_) {
++ mmc_pwr = BCSR_PCMCIA_SD1_PWR;
++ } else {
++ mmc_pwr = BCSR_PCMCIA_SD0_PWR;
++ }
++
++ board_specific = au_readl((unsigned long)(&bcsr->pcmcia));
++ board_specific &= ~mmc_pwr;
++
++ au_writel(board_specific, (int)(&bcsr->pcmcia));
++ au_sync_delay(1);
++}
++
++EXPORT_SYMBOL(mmc_card_inserted);
++EXPORT_SYMBOL(mmc_card_writable);
++EXPORT_SYMBOL(mmc_power_on);
++EXPORT_SYMBOL(mmc_power_off);
++
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/pb1200/board_setup.c linux-2.4.32-rc1.mips/arch/mips/au1000/pb1200/board_setup.c
+--- linux-2.4.32-rc1/arch/mips/au1000/pb1200/board_setup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/pb1200/board_setup.c 2005-03-19 08:17:51.000000000 +0100
+@@ -0,0 +1,221 @@
++/*
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Alchemy Pb1200 board setup.
++ *
++ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/console.h>
++#include <linux/mc146818rtc.h>
++#include <linux/delay.h>
++
++#if defined(CONFIG_BLK_DEV_IDE_AU1XXX)
++#include <linux/ide.h>
++#endif
++
++#include <asm/cpu.h>
++#include <asm/bootinfo.h>
++#include <asm/irq.h>
++#include <asm/keyboard.h>
++#include <asm/mipsregs.h>
++#include <asm/reboot.h>
++#include <asm/pgtable.h>
++#include <asm/au1000.h>
++#include <asm/au1xxx_dbdma.h>
++
++#ifdef CONFIG_MIPS_PB1200
++#include <asm/pb1200.h>
++#endif
++
++#ifdef CONFIG_MIPS_DB1200
++#include <asm/db1200.h>
++#define PB1200_ETH_INT DB1200_ETH_INT
++#define PB1200_IDE_INT DB1200_IDE_INT
++#endif
++
++extern struct rtc_ops no_rtc_ops;
++
++extern void _board_init_irq(void);
++extern void (*board_init_irq)(void);
++
++#ifdef CONFIG_BLK_DEV_IDE_AU1XXX
++extern struct ide_ops *ide_ops;
++extern struct ide_ops au1xxx_ide_ops;
++extern u32 au1xxx_ide_virtbase;
++extern u64 au1xxx_ide_physbase;
++extern int au1xxx_ide_irq;
++
++u32 led_base_addr;
++/* Ddma */
++chan_tab_t *ide_read_ch, *ide_write_ch;
++u32 au1xxx_ide_ddma_enable = 0, switch4ddma = 1; // PIO+ddma
++
++dbdev_tab_t new_dbdev_tab_element = { DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 };
++#endif /* end CONFIG_BLK_DEV_IDE_AU1XXX */
++
++void board_reset (void)
++{
++ bcsr->resets = 0;
++}
++
++void board_power_off (void)
++{
++ bcsr->resets = 0xC000;
++}
++
++void __init board_setup(void)
++{
++ char *argptr = NULL;
++ u32 pin_func;
++ rtc_ops = &no_rtc_ops;
++
++#if 0
++ /* Enable PSC1 SYNC for AC97. Normaly done in audio driver,
++ * but it is board specific code, so put it here.
++ */
++ pin_func = au_readl(SYS_PINFUNC);
++ au_sync();
++ pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1;
++ au_writel(pin_func, SYS_PINFUNC);
++
++ au_writel(0, (u32)bcsr|0x10); /* turn off pcmcia power */
++ au_sync();
++#endif
++
++#if defined( CONFIG_I2C_ALGO_AU1550 )
++ {
++ u32 freq0, clksrc;
++
++ /* Select SMBUS in CPLD */
++ bcsr->resets &= ~(BCSR_RESETS_PCS0MUX);
++
++ pin_func = au_readl(SYS_PINFUNC);
++ au_sync();
++ pin_func &= ~(3<<17 | 1<<4);
++ /* Set GPIOs correctly */
++ pin_func |= 2<<17;
++ au_writel(pin_func, SYS_PINFUNC);
++ au_sync();
++
++ /* The i2c driver depends on 50Mhz clock */
++ freq0 = au_readl(SYS_FREQCTRL0);
++ au_sync();
++ freq0 &= ~(SYS_FC_FRDIV1_MASK | SYS_FC_FS1 | SYS_FC_FE1);
++ freq0 |= (3<<SYS_FC_FRDIV1_BIT);
++ /* 396Mhz / (3+1)*2 == 49.5Mhz */
++ au_writel(freq0, SYS_FREQCTRL0);
++ au_sync();
++ freq0 |= SYS_FC_FE1;
++ au_writel(freq0, SYS_FREQCTRL0);
++ au_sync();
++
++ clksrc = au_readl(SYS_CLKSRC);
++ au_sync();
++ clksrc &= ~0x01f00000;
++ /* bit 22 is EXTCLK0 for PSC0 */
++ clksrc |= (0x3 << 22);
++ au_writel(clksrc, SYS_CLKSRC);
++ au_sync();
++ }
++#endif
++
++#ifdef CONFIG_FB_AU1200
++ argptr = prom_getcmdline();
++ strcat(argptr, " video=au1200fb:");
++#endif
++
++#if defined(CONFIG_BLK_DEV_IDE_AU1XXX)
++ /*
++ * Iniz IDE parameters
++ */
++ ide_ops = &au1xxx_ide_ops;
++ au1xxx_ide_irq = PB1200_IDE_INT;
++ au1xxx_ide_physbase = AU1XXX_ATA_PHYS_ADDR;
++ au1xxx_ide_virtbase = KSEG1ADDR(AU1XXX_ATA_PHYS_ADDR);
++ /*
++ * change PIO or PIO+Ddma
++ * check the GPIO-5 pin condition. pb1200:s18_dot */
++ switch4ddma = (au_readl(SYS_PINSTATERD) & (1 << 5)) ? 1 : 0;
++#endif
++
++ /* The Pb1200 development board uses external MUX for PSC0 to
++ support SMB/SPI. bcsr->resets bit 12: 0=SMB 1=SPI
++ */
++#if defined(CONFIG_AU1550_PSC_SPI) && defined(CONFIG_I2C_ALGO_AU1550)
++ #error I2C and SPI are mutually exclusive. Both are physically connected to PSC0.\
++ Refer to Pb1200/Db1200 documentation.
++#elif defined( CONFIG_AU1550_PSC_SPI )
++ bcsr->resets |= BCSR_RESETS_PCS0MUX;
++#elif defined( CONFIG_I2C_ALGO_AU1550 )
++ bcsr->resets &= (~BCSR_RESETS_PCS0MUX);
++#endif
++ au_sync();
++
++#ifdef CONFIG_MIPS_PB1200
++ printk("AMD Alchemy Pb1200 Board\n");
++#endif
++#ifdef CONFIG_MIPS_DB1200
++ printk("AMD Alchemy Db1200 Board\n");
++#endif
++
++ /* Setup Pb1200 External Interrupt Controller */
++ {
++ extern void (*board_init_irq)(void);
++ extern void _board_init_irq(void);
++ board_init_irq = _board_init_irq;
++ }
++}
++
++int
++board_au1200fb_panel (void)
++{
++ BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++ int p;
++
++ p = bcsr->switches;
++ p >>= 8;
++ p &= 0x0F;
++ return p;
++}
++
++int
++board_au1200fb_panel_init (void)
++{
++ /* Apply power */
++ BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++ bcsr->board |= (BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | BCSR_BOARD_LCDBL);
++ return 0;
++}
++
++int
++board_au1200fb_panel_shutdown (void)
++{
++ /* Remove power */
++ BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++ bcsr->board &= ~(BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | BCSR_BOARD_LCDBL);
++ return 0;
++}
++
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/pb1200/init.c linux-2.4.32-rc1.mips/arch/mips/au1000/pb1200/init.c
+--- linux-2.4.32-rc1/arch/mips/au1000/pb1200/init.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/pb1200/init.c 2005-01-30 09:01:28.000000000 +0100
+@@ -0,0 +1,72 @@
++/*
++ *
++ * BRIEF MODULE DESCRIPTION
++ * PB1200 board setup
++ *
++ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/bootmem.h>
++#include <asm/addrspace.h>
++#include <asm/bootinfo.h>
++#include <linux/config.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++
++int prom_argc;
++char **prom_argv, **prom_envp;
++extern void __init prom_init_cmdline(void);
++extern char *prom_getenv(char *envname);
++
++const char *get_system_type(void)
++{
++ return "AMD Alchemy Au1200/Pb1200";
++}
++
++u32 mae_memsize = 0;
++
++int __init prom_init(int argc, char **argv, char **envp, int *prom_vec)
++{
++ unsigned char *memsize_str;
++ unsigned long memsize;
++
++ prom_argc = argc;
++ prom_argv = argv;
++ prom_envp = envp;
++
++ mips_machgroup = MACH_GROUP_ALCHEMY;
++ mips_machtype = MACH_PB1000; /* set the platform # */
++ prom_init_cmdline();
++
++ memsize_str = prom_getenv("memsize");
++ if (!memsize_str) {
++ memsize = 0x08000000;
++ } else {
++ memsize = simple_strtol(memsize_str, NULL, 0);
++ }
++ add_memory_region(0, memsize, BOOT_MEM_RAM);
++ return 0;
++}
++
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/pb1200/irqmap.c linux-2.4.32-rc1.mips/arch/mips/au1000/pb1200/irqmap.c
+--- linux-2.4.32-rc1/arch/mips/au1000/pb1200/irqmap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/pb1200/irqmap.c 2005-01-30 09:01:28.000000000 +0100
+@@ -0,0 +1,180 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ * Au1xxx irq map table
++ *
++ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/irq.h>
++#include <linux/kernel_stat.h>
++#include <linux/module.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/timex.h>
++#include <linux/slab.h>
++#include <linux/random.h>
++#include <linux/delay.h>
++
++#include <asm/bitops.h>
++#include <asm/bootinfo.h>
++#include <asm/io.h>
++#include <asm/mipsregs.h>
++#include <asm/system.h>
++#include <asm/au1000.h>
++
++#ifdef CONFIG_MIPS_PB1200
++#include <asm/pb1200.h>
++#endif
++
++#ifdef CONFIG_MIPS_DB1200
++#include <asm/db1200.h>
++#define PB1200_INT_BEGIN DB1200_INT_BEGIN
++#define PB1200_INT_END DB1200_INT_END
++#endif
++
++au1xxx_irq_map_t au1xxx_irq_map[] = {
++ { AU1000_GPIO_7, INTC_INT_LOW_LEVEL, 0 }, // This is exteranl interrupt cascade
++};
++
++int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t);
++
++/*
++ * Support for External interrupts on the PbAu1200 Development platform.
++ */
++static volatile int pb1200_cascade_en=0;
++
++void pb1200_cascade_handler( int irq, void *dev_id, struct pt_regs *regs)
++{
++ unsigned short bisr = bcsr->int_status;
++ int extirq_nr = 0;
++
++ /* Clear all the edge interrupts. This has no effect on level */
++ bcsr->int_status = bisr;
++ for( ; bisr; bisr &= (bisr-1) )
++ {
++ extirq_nr = (PB1200_INT_BEGIN-1) + au_ffs(bisr);
++ /* Ack and dispatch IRQ */
++ do_IRQ(extirq_nr,regs);
++ }
++}
++
++inline void pb1200_enable_irq(unsigned int irq_nr)
++{
++ bcsr->intset_mask = 1<<(irq_nr - PB1200_INT_BEGIN);
++ bcsr->intset = 1<<(irq_nr - PB1200_INT_BEGIN);
++}
++
++inline void pb1200_disable_irq(unsigned int irq_nr)
++{
++ bcsr->intclr_mask = 1<<(irq_nr - PB1200_INT_BEGIN);
++ bcsr->intclr = 1<<(irq_nr - PB1200_INT_BEGIN);
++}
++
++static unsigned int pb1200_startup_irq( unsigned int irq_nr )
++{
++ if (++pb1200_cascade_en == 1)
++ {
++ request_irq(AU1000_GPIO_7, &pb1200_cascade_handler,
++ 0, "Pb1200 Cascade", &pb1200_cascade_handler );
++#ifdef CONFIG_MIPS_PB1200
++ /* We have a problem with CPLD rev3. Enable a workaround */
++ if( ((bcsr->whoami & BCSR_WHOAMI_CPLD)>>4) <= 3)
++ {
++ printk("\nWARNING!!!\n");
++ printk("\nWARNING!!!\n");
++ printk("\nWARNING!!!\n");
++ printk("\nWARNING!!!\n");
++ printk("\nWARNING!!!\n");
++ printk("\nWARNING!!!\n");
++ printk("Pb1200 must be at CPLD rev4. Please have Pb1200\n");
++ printk("updated to latest revision. This software will not\n");
++ printk("work on anything less than CPLD rev4\n");
++ printk("\nWARNING!!!\n");
++ printk("\nWARNING!!!\n");
++ printk("\nWARNING!!!\n");
++ printk("\nWARNING!!!\n");
++ printk("\nWARNING!!!\n");
++ printk("\nWARNING!!!\n");
++ while(1);
++ }
++#endif
++ }
++ pb1200_enable_irq(irq_nr);
++ return 0;
++}
++
++static void pb1200_shutdown_irq( unsigned int irq_nr )
++{
++ pb1200_disable_irq(irq_nr);
++ if (--pb1200_cascade_en == 0)
++ {
++ free_irq(AU1000_GPIO_7,&pb1200_cascade_handler );
++ }
++ return;
++}
++
++static inline void pb1200_mask_and_ack_irq(unsigned int irq_nr)
++{
++ pb1200_disable_irq( irq_nr );
++}
++
++static void pb1200_end_irq(unsigned int irq_nr)
++{
++ if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
++ pb1200_enable_irq(irq_nr);
++ }
++}
++
++static struct hw_interrupt_type external_irq_type =
++{
++#ifdef CONFIG_MIPS_PB1200
++ "Pb1200 Ext",
++#endif
++#ifdef CONFIG_MIPS_DB1200
++ "Db1200 Ext",
++#endif
++ pb1200_startup_irq,
++ pb1200_shutdown_irq,
++ pb1200_enable_irq,
++ pb1200_disable_irq,
++ pb1200_mask_and_ack_irq,
++ pb1200_end_irq,
++ NULL
++};
++
++void _board_init_irq(void)
++{
++ int irq_nr;
++
++ for (irq_nr = PB1200_INT_BEGIN; irq_nr <= PB1200_INT_END; irq_nr++)
++ {
++ irq_desc[irq_nr].handler = &external_irq_type;
++ pb1200_disable_irq(irq_nr);
++ }
++
++ /* GPIO_7 can not be hooked here, so it is hooked upon first
++ request of any source attached to the cascade */
++}
++
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/pb1200/Makefile linux-2.4.32-rc1.mips/arch/mips/au1000/pb1200/Makefile
+--- linux-2.4.32-rc1/arch/mips/au1000/pb1200/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/pb1200/Makefile 2005-01-30 09:01:27.000000000 +0100
+@@ -0,0 +1,25 @@
++#
++# Copyright 2000 MontaVista Software Inc.
++# Author: MontaVista Software, Inc.
++# ppopov@mvista.com or source@mvista.com
++#
++# Makefile for the Alchemy Semiconductor PB1000 board.
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++
++USE_STANDARD_AS_RULE := true
++
++O_TARGET := pb1200.o
++
++obj-y := init.o board_setup.o irqmap.o
++
++ifdef CONFIG_MMC
++obj-y += mmc_support.o
++export-objs +=mmc_support.o
++endif
++
++
++include $(TOPDIR)/Rules.make
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/pb1200/mmc_support.c linux-2.4.32-rc1.mips/arch/mips/au1000/pb1200/mmc_support.c
+--- linux-2.4.32-rc1/arch/mips/au1000/pb1200/mmc_support.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/pb1200/mmc_support.c 2005-01-30 09:01:28.000000000 +0100
+@@ -0,0 +1,141 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ *
++ * MMC support routines for PB1200.
++ *
++ *
++ * Copyright (c) 2003-2004 Embedded Edge, LLC.
++ * Author: Embedded Edge, LLC.
++ * Contact: dan@embeddededge.com
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++
++#include <asm/irq.h>
++#include <asm/au1000.h>
++#include <asm/au1100_mmc.h>
++
++#ifdef CONFIG_MIPS_PB1200
++#include <asm/pb1200.h>
++#endif
++
++#ifdef CONFIG_MIPS_DB1200
++/* NOTE: DB1200 only has SD0 pinned out and usable */
++#include <asm/db1200.h>
++#endif
++
++/* SD/MMC controller support functions */
++
++/*
++ * Detect card.
++ */
++void mmc_card_inserted(int socket, int *result)
++{
++ u16 mask;
++
++ if (socket)
++#ifdef CONFIG_MIPS_DB1200
++ mask = 0;
++#else
++ mask = BCSR_INT_SD1INSERT;
++#endif
++ else
++ mask = BCSR_INT_SD0INSERT;
++
++ *result = ((bcsr->sig_status & mask) != 0);
++}
++
++/*
++ * Check card write protection.
++ */
++void mmc_card_writable(int socket, int *result)
++{
++ u16 mask;
++
++ if (socket)
++#ifdef CONFIG_MIPS_DB1200
++ mask = 0;
++#else
++ mask = BCSR_STATUS_SD1WP;
++#endif
++ else
++ mask = BCSR_STATUS_SD0WP;
++
++ /* low means card writable */
++ if (!(bcsr->status & mask)) {
++ *result = 1;
++ } else {
++ *result = 0;
++ }
++}
++
++/*
++ * Apply power to card slot.
++ */
++void mmc_power_on(int socket)
++{
++ u16 mask;
++
++ if (socket)
++#ifdef CONFIG_MIPS_DB1200
++ mask = 0;
++#else
++ mask = BCSR_BOARD_SD1PWR;
++#endif
++ else
++ mask = BCSR_BOARD_SD0PWR;
++
++ bcsr->board |= mask;
++ au_sync_delay(1);
++}
++
++/*
++ * Remove power from card slot.
++ */
++void mmc_power_off(int socket)
++{
++ u16 mask;
++
++ if (socket)
++#ifdef CONFIG_MIPS_DB1200
++ mask = 0;
++#else
++ mask = BCSR_BOARD_SD1PWR;
++#endif
++ else
++ mask = BCSR_BOARD_SD0PWR;
++
++ bcsr->board &= ~mask;
++ au_sync_delay(1);
++}
++
++EXPORT_SYMBOL(mmc_card_inserted);
++EXPORT_SYMBOL(mmc_card_writable);
++EXPORT_SYMBOL(mmc_power_on);
++EXPORT_SYMBOL(mmc_power_off);
++
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/pb1500/board_setup.c linux-2.4.32-rc1.mips/arch/mips/au1000/pb1500/board_setup.c
+--- linux-2.4.32-rc1/arch/mips/au1000/pb1500/board_setup.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/pb1500/board_setup.c 2005-03-19 08:17:51.000000000 +0100
+@@ -62,6 +62,10 @@
+ au_writel(0x00000000, 0xAE00001C);
+ }
+
++void board_power_off (void)
++{
++}
++
+ void __init board_setup(void)
+ {
+ u32 pin_func;
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/pb1550/board_setup.c linux-2.4.32-rc1.mips/arch/mips/au1000/pb1550/board_setup.c
+--- linux-2.4.32-rc1/arch/mips/au1000/pb1550/board_setup.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/pb1550/board_setup.c 2005-03-19 08:17:51.000000000 +0100
+@@ -48,12 +48,31 @@
+
+ extern struct rtc_ops no_rtc_ops;
+
++#if defined(CONFIG_BLK_DEV_IDE_AU1XXX)
++extern struct ide_ops *ide_ops;
++extern struct ide_ops au1xxx_ide_ops;
++extern u32 au1xxx_ide_virtbase;
++extern u64 au1xxx_ide_physbase;
++extern unsigned int au1xxx_ide_irq;
++
++u32 au1xxx_ide_ddma_enable = 0, switch4ddma = 1; // PIO+ddma
++#endif /* end CONFIG_BLK_DEV_IDE_AU1XXX */
++
+ void board_reset (void)
+ {
+ /* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
+ au_writew(au_readw(0xAF00001C) & ~(1<<15), 0xAF00001C);
+ }
+
++void board_power_off (void)
++{
++ /* power off system */
++ printk("\n** Powering off Pb1550\n");
++ au_writew(au_readw(0xAF00001C) | (3<<14), 0xAF00001C);
++ au_sync();
++ while(1); /* should not get here */
++}
++
+ void __init board_setup(void)
+ {
+ u32 pin_func;
+@@ -78,5 +97,36 @@
+ au_writel(0, (u32)bcsr|0x10); /* turn off pcmcia power */
+ au_sync();
+
++#if defined(CONFIG_AU1XXX_SMC91111)
++#if defined(CONFIG_BLK_DEV_IDE_AU1XXX)
++#error "Resource conflict occured. Disable either Ethernet or IDE daughter card."
++#else
++#define CPLD_CONTROL (0xAF00000C)
++ {
++ /* set up the Static Bus timing */
++ /* only 396Mhz */
++ /* reset the DC */
++ au_writew(au_readw(CPLD_CONTROL) | 0x0f, CPLD_CONTROL);
++ au_writel(0x00010003, MEM_STCFG0);
++ au_writel(0x000c00c0, MEM_STCFG2);
++ au_writel(0x85E1900D, MEM_STTIME2);
++ }
++#endif
++#endif /* end CONFIG_SMC91111 */
++
++#if defined(CONFIG_BLK_DEV_IDE_AU1XXX)
++ /*
++ * Iniz IDE parameters
++ */
++ ide_ops = &au1xxx_ide_ops;
++ au1xxx_ide_irq = DAUGHTER_CARD_IRQ;;
++ au1xxx_ide_physbase = AU1XXX_ATA_PHYS_ADDR;
++ au1xxx_ide_virtbase = KSEG1ADDR(AU1XXX_ATA_PHYS_ADDR);
++ /*
++ * change PIO or PIO+Ddma
++ * check the GPIO-6 pin condition. pb1550:s15_dot
++ */
++ switch4ddma = (au_readl(SYS_PINSTATERD) & (1 << 6)) ? 1 : 0;
++#endif
+ printk("AMD Alchemy Pb1550 Board\n");
+ }
+diff -Nur linux-2.4.32-rc1/arch/mips/au1000/pb1550/irqmap.c linux-2.4.32-rc1.mips/arch/mips/au1000/pb1550/irqmap.c
+--- linux-2.4.32-rc1/arch/mips/au1000/pb1550/irqmap.c 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/au1000/pb1550/irqmap.c 2005-01-30 09:01:28.000000000 +0100
+@@ -50,6 +50,9 @@
+ au1xxx_irq_map_t au1xxx_irq_map[] = {
+ { AU1000_GPIO_0, INTC_INT_LOW_LEVEL, 0 },
+ { AU1000_GPIO_1, INTC_INT_LOW_LEVEL, 0 },
++#ifdef CONFIG_AU1XXX_SMC91111
++ { AU1000_GPIO_3, INTC_INT_LOW_LEVEL, 0 },
++#endif
+ };
+
+ int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t);
+diff -Nur linux-2.4.32-rc1/arch/mips/config-shared.in linux-2.4.32-rc1.mips/arch/mips/config-shared.in
+--- linux-2.4.32-rc1/arch/mips/config-shared.in 2005-01-19 15:09:27.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/config-shared.in 2005-01-30 09:01:26.000000000 +0100
+@@ -21,16 +21,19 @@
+ comment 'Machine selection'
+ dep_bool 'Support for Acer PICA 1 chipset (EXPERIMENTAL)' CONFIG_ACER_PICA_61 $CONFIG_EXPERIMENTAL
+ dep_bool 'Support for Alchemy Bosporus board' CONFIG_MIPS_BOSPORUS $CONFIG_MIPS32
++dep_bool 'Support for FIC Multimedia Player board' CONFIG_MIPS_FICMMP $CONFIG_MIPS32
+ dep_bool 'Support for Alchemy Mirage board' CONFIG_MIPS_MIRAGE $CONFIG_MIPS32
+ dep_bool 'Support for Alchemy Db1000 board' CONFIG_MIPS_DB1000 $CONFIG_MIPS32
+ dep_bool 'Support for Alchemy Db1100 board' CONFIG_MIPS_DB1100 $CONFIG_MIPS32
+ dep_bool 'Support for Alchemy Db1500 board' CONFIG_MIPS_DB1500 $CONFIG_MIPS32
+ dep_bool 'Support for Alchemy Db1550 board' CONFIG_MIPS_DB1550 $CONFIG_MIPS32
++dep_bool 'Support for Alchemy Db1200 board' CONFIG_MIPS_DB1200 $CONFIG_MIPS32
+ dep_bool 'Support for Alchemy PB1000 board' CONFIG_MIPS_PB1000 $CONFIG_MIPS32
+ dep_bool 'Support for Alchemy PB1100 board' CONFIG_MIPS_PB1100 $CONFIG_MIPS32
+ dep_bool 'Support for Alchemy PB1500 board' CONFIG_MIPS_PB1500 $CONFIG_MIPS32
+-dep_bool 'Support for Alchemy Hydrogen3 board' CONFIG_MIPS_HYDROGEN3 $CONFIG_MIPS32
+ dep_bool 'Support for Alchemy PB1550 board' CONFIG_MIPS_PB1550 $CONFIG_MIPS32
++dep_bool 'Support for Alchemy PB1200 board' CONFIG_MIPS_PB1200 $CONFIG_MIPS32
++dep_bool 'Support for Alchemy Hydrogen3 board' CONFIG_MIPS_HYDROGEN3 $CONFIG_MIPS32
+ dep_bool 'Support for MyCable XXS1500 board' CONFIG_MIPS_XXS1500 $CONFIG_MIPS32
+ dep_bool 'Support for 4G Systems MTX-1 board' CONFIG_MIPS_MTX1 $CONFIG_MIPS32
+ dep_bool 'Support for Cogent CSB250 board' CONFIG_COGENT_CSB250 $CONFIG_MIPS32
+@@ -249,6 +252,12 @@
+ define_bool CONFIG_PC_KEYB y
+ define_bool CONFIG_NONCOHERENT_IO y
+ fi
++if [ "$CONFIG_MIPS_FICMMP" = "y" ]; then
++ define_bool CONFIG_SOC_AU1X00 y
++ define_bool CONFIG_SOC_AU1200 y
++ define_bool CONFIG_NONCOHERENT_IO y
++ define_bool CONFIG_PC_KEYB y
++fi
+ if [ "$CONFIG_MIPS_BOSPORUS" = "y" ]; then
+ define_bool CONFIG_SOC_AU1X00 y
+ define_bool CONFIG_SOC_AU1500 y
+@@ -263,6 +272,12 @@
+ define_bool CONFIG_SWAP_IO_SPACE_W y
+ define_bool CONFIG_SWAP_IO_SPACE_L y
+ fi
++if [ "$CONFIG_MIPS_PB1500" = "y" ]; then
++ define_bool CONFIG_SOC_AU1X00 y
++ define_bool CONFIG_SOC_AU1500 y
++ define_bool CONFIG_NONCOHERENT_IO y
++ define_bool CONFIG_PC_KEYB y
++fi
+ if [ "$CONFIG_MIPS_PB1100" = "y" ]; then
+ define_bool CONFIG_SOC_AU1X00 y
+ define_bool CONFIG_SOC_AU1100 y
+@@ -271,9 +286,15 @@
+ define_bool CONFIG_SWAP_IO_SPACE_W y
+ define_bool CONFIG_SWAP_IO_SPACE_L y
+ fi
+-if [ "$CONFIG_MIPS_PB1500" = "y" ]; then
++if [ "$CONFIG_MIPS_PB1550" = "y" ]; then
+ define_bool CONFIG_SOC_AU1X00 y
+- define_bool CONFIG_SOC_AU1500 y
++ define_bool CONFIG_SOC_AU1550 y
++ define_bool CONFIG_NONCOHERENT_IO n
++ define_bool CONFIG_PC_KEYB y
++fi
++if [ "$CONFIG_MIPS_PB1200" = "y" ]; then
++ define_bool CONFIG_SOC_AU1X00 y
++ define_bool CONFIG_SOC_AU1200 y
+ define_bool CONFIG_NONCOHERENT_IO y
+ define_bool CONFIG_PC_KEYB y
+ fi
+@@ -290,18 +311,24 @@
+ define_bool CONFIG_NONCOHERENT_IO y
+ define_bool CONFIG_PC_KEYB y
+ fi
++if [ "$CONFIG_MIPS_DB1100" = "y" ]; then
++ define_bool CONFIG_SOC_AU1X00 y
++ define_bool CONFIG_SOC_AU1100 y
++ define_bool CONFIG_NONCOHERENT_IO y
++ define_bool CONFIG_PC_KEYB y
++ define_bool CONFIG_SWAP_IO_SPACE y
++fi
+ if [ "$CONFIG_MIPS_DB1550" = "y" ]; then
+ define_bool CONFIG_SOC_AU1X00 y
+ define_bool CONFIG_SOC_AU1550 y
+ define_bool CONFIG_NONCOHERENT_IO y
+ define_bool CONFIG_PC_KEYB y
+ fi
+-if [ "$CONFIG_MIPS_DB1100" = "y" ]; then
++if [ "$CONFIG_MIPS_DB1200" = "y" ]; then
+ define_bool CONFIG_SOC_AU1X00 y
+- define_bool CONFIG_SOC_AU1100 y
++ define_bool CONFIG_SOC_AU1200 y
+ define_bool CONFIG_NONCOHERENT_IO y
+ define_bool CONFIG_PC_KEYB y
+- define_bool CONFIG_SWAP_IO_SPACE y
+ fi
+ if [ "$CONFIG_MIPS_HYDROGEN3" = "y" ]; then
+ define_bool CONFIG_SOC_AU1X00 y
+@@ -327,12 +354,6 @@
+ define_bool CONFIG_NONCOHERENT_IO y
+ define_bool CONFIG_PC_KEYB y
+ fi
+-if [ "$CONFIG_MIPS_PB1550" = "y" ]; then
+- define_bool CONFIG_SOC_AU1X00 y
+- define_bool CONFIG_SOC_AU1550 y
+- define_bool CONFIG_NONCOHERENT_IO n
+- define_bool CONFIG_PC_KEYB y
+-fi
+ if [ "$CONFIG_MIPS_COBALT" = "y" ]; then
+ define_bool CONFIG_BOOT_ELF32 y
+ define_bool CONFIG_COBALT_LCD y
+@@ -729,6 +750,13 @@
+ "$CONFIG_MIPS_PB1000" = "y" -o \
+ "$CONFIG_MIPS_PB1100" = "y" -o \
+ "$CONFIG_MIPS_PB1500" = "y" -o \
++ "$CONFIG_MIPS_PB1550" = "y" -o \
++ "$CONFIG_MIPS_PB1200" = "y" -o \
++ "$CONFIG_MIPS_DB1000" = "y" -o \
++ "$CONFIG_MIPS_DB1100" = "y" -o \
++ "$CONFIG_MIPS_DB1500" = "y" -o \
++ "$CONFIG_MIPS_DB1550" = "y" -o \
++ "$CONFIG_MIPS_DB1200" = "y" -o \
+ "$CONFIG_NEC_OSPREY" = "y" -o \
+ "$CONFIG_NEC_EAGLE" = "y" -o \
+ "$CONFIG_NINO" = "y" -o \
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig linux-2.4.32-rc1.mips/arch/mips/defconfig
+--- linux-2.4.32-rc1/arch/mips/defconfig 2005-01-19 15:09:27.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -235,11 +235,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -319,9 +314,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -465,7 +462,6 @@
+ # CONFIG_SERIAL is not set
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-atlas linux-2.4.32-rc1.mips/arch/mips/defconfig-atlas
+--- linux-2.4.32-rc1/arch/mips/defconfig-atlas 2005-01-19 15:09:27.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-atlas 2005-03-18 13:13:21.000000000 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -235,11 +235,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -317,9 +312,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -528,7 +525,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-bosporus linux-2.4.32-rc1.mips/arch/mips/defconfig-bosporus
+--- linux-2.4.32-rc1/arch/mips/defconfig-bosporus 2005-01-19 15:09:27.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-bosporus 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -208,9 +208,7 @@
+ CONFIG_MTD_BOSPORUS=y
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -229,7 +227,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -373,11 +370,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -457,9 +449,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -681,7 +675,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-capcella linux-2.4.32-rc1.mips/arch/mips/defconfig-capcella
+--- linux-2.4.32-rc1/arch/mips/defconfig-capcella 2005-01-19 15:09:27.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-capcella 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -228,11 +228,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -472,7 +467,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-cobalt linux-2.4.32-rc1.mips/arch/mips/defconfig-cobalt
+--- linux-2.4.32-rc1/arch/mips/defconfig-cobalt 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-cobalt 2005-03-18 13:13:21.000000000 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -222,11 +222,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -505,7 +500,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=16
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-csb250 linux-2.4.32-rc1.mips/arch/mips/defconfig-csb250
+--- linux-2.4.32-rc1/arch/mips/defconfig-csb250 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-csb250 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ CONFIG_COGENT_CSB250=y
+@@ -268,11 +268,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -556,7 +551,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-db1000 linux-2.4.32-rc1.mips/arch/mips/defconfig-db1000
+--- linux-2.4.32-rc1/arch/mips/defconfig-db1000 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-db1000 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -214,11 +214,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-CONFIG_MTD_DB1X00=y
+-CONFIG_MTD_DB1X00_BOOT=y
+-CONFIG_MTD_DB1X00_USER=y
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -237,7 +233,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -342,11 +337,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -636,7 +626,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-db1100 linux-2.4.32-rc1.mips/arch/mips/defconfig-db1100
+--- linux-2.4.32-rc1/arch/mips/defconfig-db1100 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-db1100 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -214,11 +214,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-CONFIG_MTD_DB1X00=y
+-# CONFIG_MTD_DB1X00_BOOT is not set
+-CONFIG_MTD_DB1X00_USER=y
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -237,7 +233,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -342,11 +337,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -636,7 +626,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+@@ -884,6 +873,7 @@
+ # CONFIG_FB_PM2 is not set
+ # CONFIG_FB_PM3 is not set
+ # CONFIG_FB_CYBER2000 is not set
++CONFIG_FB_AU1100=y
+ # CONFIG_FB_MATROX is not set
+ # CONFIG_FB_ATY is not set
+ # CONFIG_FB_RADEON is not set
+@@ -895,7 +885,6 @@
+ # CONFIG_FB_VOODOO1 is not set
+ # CONFIG_FB_TRIDENT is not set
+ # CONFIG_FB_E1356 is not set
+-CONFIG_FB_AU1100=y
+ # CONFIG_FB_IT8181 is not set
+ # CONFIG_FB_VIRTUAL is not set
+ CONFIG_FBCON_ADVANCED=y
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-db1200 linux-2.4.32-rc1.mips/arch/mips/defconfig-db1200
+--- linux-2.4.32-rc1/arch/mips/defconfig-db1200 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-db1200 2005-03-18 13:13:21.000000000 +0100
+@@ -0,0 +1,1032 @@
++#
++# Automatically generated make config: don't edit
++#
++CONFIG_MIPS=y
++CONFIG_MIPS32=y
++# CONFIG_MIPS64 is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# Machine selection
++#
++# CONFIG_ACER_PICA_61 is not set
++# CONFIG_MIPS_BOSPORUS is not set
++# CONFIG_MIPS_MIRAGE is not set
++# CONFIG_MIPS_DB1000 is not set
++# CONFIG_MIPS_DB1100 is not set
++# CONFIG_MIPS_DB1500 is not set
++# CONFIG_MIPS_DB1550 is not set
++# CONFIG_MIPS_PB1000 is not set
++# CONFIG_MIPS_PB1100 is not set
++# CONFIG_MIPS_PB1500 is not set
++# CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
++# CONFIG_MIPS_XXS1500 is not set
++# CONFIG_MIPS_MTX1 is not set
++# CONFIG_COGENT_CSB250 is not set
++# CONFIG_BAGET_MIPS is not set
++# CONFIG_CASIO_E55 is not set
++# CONFIG_MIPS_COBALT is not set
++# CONFIG_DECSTATION is not set
++# CONFIG_MIPS_EV64120 is not set
++# CONFIG_MIPS_EV96100 is not set
++# CONFIG_MIPS_IVR is not set
++# CONFIG_HP_LASERJET is not set
++# CONFIG_IBM_WORKPAD is not set
++# CONFIG_LASAT is not set
++# CONFIG_MIPS_ITE8172 is not set
++# CONFIG_MIPS_ATLAS is not set
++# CONFIG_MIPS_MAGNUM_4000 is not set
++# CONFIG_MIPS_MALTA is not set
++# CONFIG_MIPS_SEAD is not set
++# CONFIG_MOMENCO_OCELOT is not set
++# CONFIG_MOMENCO_OCELOT_G is not set
++# CONFIG_MOMENCO_OCELOT_C is not set
++# CONFIG_MOMENCO_JAGUAR_ATX is not set
++# CONFIG_PMC_BIG_SUR is not set
++# CONFIG_PMC_STRETCH is not set
++# CONFIG_PMC_YOSEMITE is not set
++# CONFIG_DDB5074 is not set
++# CONFIG_DDB5476 is not set
++# CONFIG_DDB5477 is not set
++# CONFIG_NEC_OSPREY is not set
++# CONFIG_NEC_EAGLE is not set
++# CONFIG_OLIVETTI_M700 is not set
++# CONFIG_NINO is not set
++# CONFIG_SGI_IP22 is not set
++# CONFIG_SGI_IP27 is not set
++# CONFIG_SIBYTE_SB1xxx_SOC is not set
++# CONFIG_SNI_RM200_PCI is not set
++# CONFIG_TANBAC_TB0226 is not set
++# CONFIG_TANBAC_TB0229 is not set
++# CONFIG_TOSHIBA_JMR3927 is not set
++# CONFIG_TOSHIBA_RBTX4927 is not set
++# CONFIG_VICTOR_MPC30X is not set
++# CONFIG_ZAO_CAPCELLA is not set
++# CONFIG_HIGHMEM is not set
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_MIPS_AU1000 is not set
++
++#
++# CPU selection
++#
++CONFIG_CPU_MIPS32=y
++# CONFIG_CPU_MIPS64 is not set
++# CONFIG_CPU_R3000 is not set
++# CONFIG_CPU_TX39XX is not set
++# CONFIG_CPU_VR41XX is not set
++# CONFIG_CPU_R4300 is not set
++# CONFIG_CPU_R4X00 is not set
++# CONFIG_CPU_TX49XX is not set
++# CONFIG_CPU_R5000 is not set
++# CONFIG_CPU_R5432 is not set
++# CONFIG_CPU_R6000 is not set
++# CONFIG_CPU_NEVADA is not set
++# CONFIG_CPU_R8000 is not set
++# CONFIG_CPU_R10000 is not set
++# CONFIG_CPU_RM7000 is not set
++# CONFIG_CPU_RM9000 is not set
++# CONFIG_CPU_SB1 is not set
++CONFIG_PAGE_SIZE_4KB=y
++# CONFIG_PAGE_SIZE_16KB is not set
++# CONFIG_PAGE_SIZE_64KB is not set
++CONFIG_CPU_HAS_PREFETCH=y
++# CONFIG_VTAG_ICACHE is not set
++CONFIG_64BIT_PHYS_ADDR=y
++# CONFIG_CPU_ADVANCED is not set
++CONFIG_CPU_HAS_LLSC=y
++# CONFIG_CPU_HAS_LLDSCD is not set
++# CONFIG_CPU_HAS_WB is not set
++CONFIG_CPU_HAS_SYNC=y
++
++#
++# General setup
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++# CONFIG_BUILD_ELF64 is not set
++CONFIG_NET=y
++CONFIG_PCI=y
++CONFIG_PCI_NEW=y
++CONFIG_PCI_AUTO=y
++# CONFIG_PCI_NAMES is not set
++# CONFIG_ISA is not set
++# CONFIG_TC is not set
++# CONFIG_MCA is not set
++# CONFIG_SBUS is not set
++CONFIG_HOTPLUG=y
++
++#
++# PCMCIA/CardBus support
++#
++CONFIG_PCMCIA=m
++# CONFIG_CARDBUS is not set
++# CONFIG_TCIC is not set
++# CONFIG_I82092 is not set
++# CONFIG_I82365 is not set
++
++#
++# PCI Hotplug Support
++#
++# CONFIG_HOTPLUG_PCI is not set
++# CONFIG_HOTPLUG_PCI_COMPAQ is not set
++# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
++# CONFIG_HOTPLUG_PCI_SHPC is not set
++# CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE is not set
++# CONFIG_HOTPLUG_PCI_PCIE is not set
++# CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set
++CONFIG_SYSVIPC=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++CONFIG_SYSCTL=y
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_MIPS32_COMPAT is not set
++# CONFIG_MIPS32_O32 is not set
++# CONFIG_MIPS32_N32 is not set
++# CONFIG_BINFMT_ELF32 is not set
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_OOM_KILLER is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="mem=96M"
++
++#
++# Memory Technology Devices (MTD)
++#
++# CONFIG_MTD is not set
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_CISS_MONITOR_THREAD is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_SX8 is not set
++CONFIG_BLK_DEV_LOOP=y
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_RAM is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_BLK_STATS is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++# CONFIG_NETLINK_DEV is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_FILTER=y
++CONFIG_UNIX=y
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_IP_NF_CONNTRACK is not set
++# CONFIG_IP_NF_QUEUE is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES is not set
++# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
++# CONFIG_IP_NF_COMPAT_IPFWADM is not set
++
++#
++# IP: Virtual Server Configuration
++#
++# CONFIG_IP_VS is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++
++#
++#
++#
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Telephony Support
++#
++# CONFIG_PHONE is not set
++# CONFIG_PHONE_IXJ is not set
++# CONFIG_PHONE_IXJ_PCMCIA is not set
++
++#
++# ATA/IDE/MFM/RLL support
++#
++CONFIG_IDE=y
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=y
++
++#
++# Please see Documentation/ide.txt for help/info on IDE drives
++#
++# CONFIG_BLK_DEV_HD_IDE is not set
++# CONFIG_BLK_DEV_HD is not set
++# CONFIG_BLK_DEV_IDE_SATA is not set
++CONFIG_BLK_DEV_IDEDISK=y
++CONFIG_IDEDISK_MULTI_MODE=y
++CONFIG_IDEDISK_STROKE=y
++CONFIG_BLK_DEV_IDECS=m
++# CONFIG_BLK_DEV_DELKIN is not set
++# CONFIG_BLK_DEV_IDECD is not set
++# CONFIG_BLK_DEV_IDETAPE is not set
++# CONFIG_BLK_DEV_IDEFLOPPY is not set
++# CONFIG_BLK_DEV_IDESCSI is not set
++# CONFIG_IDE_TASK_IOCTL is not set
++
++#
++# IDE chipset support/bugfixes
++#
++# CONFIG_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++# CONFIG_BLK_DEV_IDEPCI is not set
++# CONFIG_IDE_CHIPSETS is not set
++# CONFIG_IDEDMA_AUTO is not set
++# CONFIG_DMA_NONPCI is not set
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set
++# CONFIG_BLK_DEV_ATARAID_SII is not set
++
++#
++# SCSI support
++#
++CONFIG_SCSI=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++CONFIG_SD_EXTRA_DEVS=40
++CONFIG_CHR_DEV_ST=y
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_SR_EXTRA_DEVS=2
++# CONFIG_CHR_DEV_SG is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++# CONFIG_SCSI_DEBUG_QUEUES is not set
++# CONFIG_SCSI_MULTI_LUN is not set
++CONFIG_SCSI_CONSTANTS=y
++# CONFIG_SCSI_LOGGING is not set
++
++#
++# SCSI low-level drivers
++#
++# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
++# CONFIG_SCSI_7000FASST is not set
++# CONFIG_SCSI_ACARD is not set
++# CONFIG_SCSI_AHA152X is not set
++# CONFIG_SCSI_AHA1542 is not set
++# CONFIG_SCSI_AHA1740 is not set
++# CONFIG_SCSI_AACRAID is not set
++# CONFIG_SCSI_AIC7XXX is not set
++# CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC7XXX_OLD is not set
++# CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_SCSI_ADVANSYS is not set
++# CONFIG_SCSI_IN2000 is not set
++# CONFIG_SCSI_AM53C974 is not set
++# CONFIG_SCSI_MEGARAID is not set
++# CONFIG_SCSI_MEGARAID2 is not set
++# CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
++# CONFIG_SCSI_SATA_SVW is not set
++# CONFIG_SCSI_ATA_PIIX is not set
++# CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
++# CONFIG_SCSI_SATA_PROMISE is not set
++# CONFIG_SCSI_SATA_SX4 is not set
++# CONFIG_SCSI_SATA_SIL is not set
++# CONFIG_SCSI_SATA_SIS is not set
++# CONFIG_SCSI_SATA_ULI is not set
++# CONFIG_SCSI_SATA_VIA is not set
++# CONFIG_SCSI_SATA_VITESSE is not set
++# CONFIG_SCSI_BUSLOGIC is not set
++# CONFIG_SCSI_CPQFCTS is not set
++# CONFIG_SCSI_DMX3191D is not set
++# CONFIG_SCSI_DTC3280 is not set
++# CONFIG_SCSI_EATA is not set
++# CONFIG_SCSI_EATA_DMA is not set
++# CONFIG_SCSI_EATA_PIO is not set
++# CONFIG_SCSI_FUTURE_DOMAIN is not set
++# CONFIG_SCSI_GDTH is not set
++# CONFIG_SCSI_GENERIC_NCR5380 is not set
++# CONFIG_SCSI_INITIO is not set
++# CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_NCR53C406A is not set
++# CONFIG_SCSI_NCR53C7xx is not set
++# CONFIG_SCSI_SYM53C8XX_2 is not set
++# CONFIG_SCSI_NCR53C8XX is not set
++# CONFIG_SCSI_SYM53C8XX is not set
++# CONFIG_SCSI_PAS16 is not set
++# CONFIG_SCSI_PCI2000 is not set
++# CONFIG_SCSI_PCI2220I is not set
++# CONFIG_SCSI_PSI240I is not set
++# CONFIG_SCSI_QLOGIC_FAS is not set
++# CONFIG_SCSI_QLOGIC_ISP is not set
++# CONFIG_SCSI_QLOGIC_FC is not set
++# CONFIG_SCSI_QLOGIC_1280 is not set
++# CONFIG_SCSI_SIM710 is not set
++# CONFIG_SCSI_SYM53C416 is not set
++# CONFIG_SCSI_DC390T is not set
++# CONFIG_SCSI_T128 is not set
++# CONFIG_SCSI_U14_34F is not set
++# CONFIG_SCSI_NSP32 is not set
++# CONFIG_SCSI_DEBUG is not set
++
++#
++# PCMCIA SCSI adapter support
++#
++# CONFIG_SCSI_PCMCIA is not set
++
++#
++# Fusion MPT device support
++#
++# CONFIG_FUSION is not set
++# CONFIG_FUSION_BOOT is not set
++# CONFIG_FUSION_ISENSE is not set
++# CONFIG_FUSION_CTL is not set
++# CONFIG_FUSION_LAN is not set
++
++#
++# IEEE 1394 (FireWire) support (EXPERIMENTAL)
++#
++# CONFIG_IEEE1394 is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_PCI is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_SUNLANCE is not set
++# CONFIG_HAPPYMEAL is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++# CONFIG_NET_VENDOR_SMC is not set
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_HP100 is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_E1000 is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_R8169 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# PCMCIA network device support
++#
++# CONFIG_NET_PCMCIA is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++CONFIG_INPUT=y
++CONFIG_INPUT_KEYBDEV=y
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_UINPUT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++# CONFIG_VT_CONSOLE is not set
++# CONFIG_SERIAL is not set
++# CONFIG_SERIAL_EXTENDED is not set
++CONFIG_SERIAL_NONSTANDARD=y
++# CONFIG_COMPUTONE is not set
++# CONFIG_ROCKETPORT is not set
++# CONFIG_CYCLADES is not set
++# CONFIG_DIGIEPCA is not set
++# CONFIG_DIGI is not set
++# CONFIG_ESPSERIAL is not set
++# CONFIG_MOXA_INTELLIO is not set
++# CONFIG_MOXA_SMARTIO is not set
++# CONFIG_ISI is not set
++# CONFIG_SYNCLINK is not set
++# CONFIG_SYNCLINKMP is not set
++# CONFIG_N_HDLC is not set
++# CONFIG_RISCOM8 is not set
++# CONFIG_SPECIALIX is not set
++# CONFIG_SX is not set
++# CONFIG_RIO is not set
++# CONFIG_STALDRV is not set
++# CONFIG_SERIAL_TX3912 is not set
++# CONFIG_SERIAL_TX3912_CONSOLE is not set
++# CONFIG_SERIAL_TXX9 is not set
++# CONFIG_SERIAL_TXX9_CONSOLE is not set
++# CONFIG_TXX927_SERIAL is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# Mice
++#
++# CONFIG_BUSMOUSE is not set
++# CONFIG_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_INPUT_NS558 is not set
++# CONFIG_INPUT_LIGHTNING is not set
++# CONFIG_INPUT_PCIGAME is not set
++# CONFIG_INPUT_CS461X is not set
++# CONFIG_INPUT_EMU10K1 is not set
++# CONFIG_INPUT_SERIO is not set
++# CONFIG_INPUT_SERPORT is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_ANALOG is not set
++# CONFIG_INPUT_A3D is not set
++# CONFIG_INPUT_ADI is not set
++# CONFIG_INPUT_COBRA is not set
++# CONFIG_INPUT_GF2K is not set
++# CONFIG_INPUT_GRIP is not set
++# CONFIG_INPUT_INTERACT is not set
++# CONFIG_INPUT_TMDC is not set
++# CONFIG_INPUT_SIDEWINDER is not set
++# CONFIG_INPUT_IFORCE_USB is not set
++# CONFIG_INPUT_IFORCE_232 is not set
++# CONFIG_INPUT_WARRIOR is not set
++# CONFIG_INPUT_MAGELLAN is not set
++# CONFIG_INPUT_SPACEORB is not set
++# CONFIG_INPUT_SPACEBALL is not set
++# CONFIG_INPUT_STINGER is not set
++# CONFIG_INPUT_DB9 is not set
++# CONFIG_INPUT_GAMECON is not set
++# CONFIG_INPUT_TURBOGRAFX is not set
++# CONFIG_QIC02_TAPE is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_IPMI_PANIC_EVENT is not set
++# CONFIG_IPMI_DEVICE_INTERFACE is not set
++# CONFIG_IPMI_KCS is not set
++# CONFIG_IPMI_WATCHDOG is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_SCx200 is not set
++# CONFIG_SCx200_GPIO is not set
++# CONFIG_AMD_PM768 is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++
++#
++# Direct Rendering Manager (XFree86 DRI support)
++#
++# CONFIG_DRM is not set
++
++#
++# PCMCIA character devices
++#
++# CONFIG_PCMCIA_SERIAL_CS is not set
++# CONFIG_SYNCLINK_CS is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++# CONFIG_QFMT_V2 is not set
++CONFIG_AUTOFS_FS=y
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BEFS_DEBUG is not set
++# CONFIG_BFS_FS is not set
++CONFIG_EXT3_FS=y
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++# CONFIG_UMSDOS_FS is not set
++CONFIG_VFAT_FS=y
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++# CONFIG_JFFS2_FS is not set
++# CONFIG_CRAMFS is not set
++CONFIG_TMPFS=y
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_JFS_DEBUG is not set
++# CONFIG_JFS_STATISTICS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++# CONFIG_DEVFS_FS is not set
++# CONFIG_DEVFS_MOUNT is not set
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_XFS_QUOTA is not set
++# CONFIG_XFS_RT is not set
++# CONFIG_XFS_TRACE is not set
++# CONFIG_XFS_DEBUG is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_DIRECTIO is not set
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++# CONFIG_NFSD_TCP is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++# CONFIG_NLS_CODEPAGE_437 is not set
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ISO8859_1 is not set
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# Console drivers
++#
++# CONFIG_VGA_CONSOLE is not set
++# CONFIG_MDA_CONSOLE is not set
++
++#
++# Frame-buffer support
++#
++CONFIG_FB=y
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FB_RIVA is not set
++# CONFIG_FB_CLGEN is not set
++# CONFIG_FB_PM2 is not set
++# CONFIG_FB_PM3 is not set
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_MATROX is not set
++# CONFIG_FB_ATY is not set
++# CONFIG_FB_RADEON is not set
++# CONFIG_FB_ATY128 is not set
++# CONFIG_FB_INTEL is not set
++# CONFIG_FB_SIS is not set
++# CONFIG_FB_NEOMAGIC is not set
++# CONFIG_FB_3DFX is not set
++# CONFIG_FB_VOODOO1 is not set
++# CONFIG_FB_TRIDENT is not set
++# CONFIG_FB_E1356 is not set
++# CONFIG_FB_IT8181 is not set
++# CONFIG_FB_VIRTUAL is not set
++CONFIG_FBCON_ADVANCED=y
++# CONFIG_FBCON_MFB is not set
++# CONFIG_FBCON_CFB2 is not set
++# CONFIG_FBCON_CFB4 is not set
++# CONFIG_FBCON_CFB8 is not set
++CONFIG_FBCON_CFB16=y
++# CONFIG_FBCON_CFB24 is not set
++CONFIG_FBCON_CFB32=y
++# CONFIG_FBCON_AFB is not set
++# CONFIG_FBCON_ILBM is not set
++# CONFIG_FBCON_IPLAN2P2 is not set
++# CONFIG_FBCON_IPLAN2P4 is not set
++# CONFIG_FBCON_IPLAN2P8 is not set
++# CONFIG_FBCON_MAC is not set
++# CONFIG_FBCON_VGA_PLANES is not set
++# CONFIG_FBCON_VGA is not set
++# CONFIG_FBCON_HGA is not set
++# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
++CONFIG_FBCON_FONTS=y
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++# CONFIG_FONT_SUN8x16 is not set
++# CONFIG_FONT_SUN12x22 is not set
++# CONFIG_FONT_6x11 is not set
++# CONFIG_FONT_PEARL_8x8 is not set
++# CONFIG_FONT_ACORN_8x8 is not set
++
++#
++# Sound
++#
++CONFIG_SOUND=y
++# CONFIG_SOUND_ALI5455 is not set
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_CMPCI is not set
++# CONFIG_SOUND_EMU10K1 is not set
++# CONFIG_MIDI_EMU10K1 is not set
++# CONFIG_SOUND_FUSION is not set
++# CONFIG_SOUND_CS4281 is not set
++# CONFIG_SOUND_ES1370 is not set
++# CONFIG_SOUND_ES1371 is not set
++# CONFIG_SOUND_ESSSOLO1 is not set
++# CONFIG_SOUND_MAESTRO is not set
++# CONFIG_SOUND_MAESTRO3 is not set
++# CONFIG_SOUND_FORTE is not set
++# CONFIG_SOUND_ICH is not set
++# CONFIG_SOUND_RME96XX is not set
++# CONFIG_SOUND_SONICVIBES is not set
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++# CONFIG_MIDI_VIA82CXXX is not set
++# CONFIG_SOUND_OSS is not set
++# CONFIG_SOUND_TVMIXER is not set
++# CONFIG_SOUND_AD1980 is not set
++# CONFIG_SOUND_WM97XX is not set
++
++#
++# USB support
++#
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++# CONFIG_USB_BANDWIDTH is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_EHCI_HCD is not set
++# CONFIG_USB_UHCI is not set
++# CONFIG_USB_UHCI_ALT is not set
++CONFIG_USB_OHCI=y
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_AUDIO is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_BLUETOOTH is not set
++# CONFIG_USB_MIDI is not set
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_DPCM is not set
++# CONFIG_USB_STORAGE_HP8200e is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++
++#
++# USB Human Interface Devices (HID)
++#
++CONFIG_USB_HID=y
++CONFIG_USB_HIDINPUT=y
++CONFIG_USB_HIDDEV=y
++# CONFIG_USB_AIPTEK is not set
++# CONFIG_USB_WACOM is not set
++# CONFIG_USB_KBTAB is not set
++# CONFIG_USB_POWERMATE is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_DC2XX is not set
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_SCANNER is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USB_HPUSBSCSI is not set
++
++#
++# USB Multimedia devices
++#
++
++#
++# Video4Linux support is needed for USB Multimedia device support
++#
++
++#
++# USB Network adaptors
++#
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_CDCETHER is not set
++# CONFIG_USB_USBNET is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_USS720 is not set
++
++#
++# USB Serial Converter support
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_AUERSWALD is not set
++# CONFIG_USB_TIGL is not set
++# CONFIG_USB_BRLVGER is not set
++# CONFIG_USB_LCD is not set
++
++#
++# Support for USB gadgets
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_CROSSCOMPILE=y
++# CONFIG_RUNTIME_DEBUG is not set
++# CONFIG_KGDB is not set
++# CONFIG_GDB_CONSOLE is not set
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_MIPS_UNCACHED is not set
++CONFIG_LOG_BUF_SHIFT=0
++
++#
++# Cryptographic options
++#
++# CONFIG_CRYPTO is not set
++
++#
++# Library routines
++#
++# CONFIG_CRC32 is not set
++CONFIG_ZLIB_INFLATE=m
++CONFIG_ZLIB_DEFLATE=m
++# CONFIG_FW_LOADER is not set
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-db1500 linux-2.4.32-rc1.mips/arch/mips/defconfig-db1500
+--- linux-2.4.32-rc1/arch/mips/defconfig-db1500 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-db1500 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -267,11 +267,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -555,7 +550,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-db1550 linux-2.4.32-rc1.mips/arch/mips/defconfig-db1550
+--- linux-2.4.32-rc1/arch/mips/defconfig-db1550 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-db1550 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -213,11 +213,9 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ CONFIG_MTD_PB1550=y
+ CONFIG_MTD_PB1550_BOOT=y
+ CONFIG_MTD_PB1550_USER=y
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -236,7 +234,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -343,11 +340,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -633,7 +625,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-ddb5476 linux-2.4.32-rc1.mips/arch/mips/defconfig-ddb5476
+--- linux-2.4.32-rc1/arch/mips/defconfig-ddb5476 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-ddb5476 2005-03-18 13:13:21.000000000 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -226,11 +226,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -517,7 +512,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-ddb5477 linux-2.4.32-rc1.mips/arch/mips/defconfig-ddb5477
+--- linux-2.4.32-rc1/arch/mips/defconfig-ddb5477 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-ddb5477 2005-03-18 13:13:21.000000000 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -226,11 +226,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -434,7 +429,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-decstation linux-2.4.32-rc1.mips/arch/mips/defconfig-decstation
+--- linux-2.4.32-rc1/arch/mips/defconfig-decstation 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-decstation 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -223,11 +223,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -306,9 +301,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -477,7 +474,6 @@
+ CONFIG_SERIAL_DEC_CONSOLE=y
+ CONFIG_DZ=y
+ CONFIG_ZS=y
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-e55 linux-2.4.32-rc1.mips/arch/mips/defconfig-e55
+--- linux-2.4.32-rc1/arch/mips/defconfig-e55 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-e55 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -222,11 +222,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -426,7 +421,6 @@
+ # CONFIG_SERIAL_MULTIPORT is not set
+ # CONFIG_HUB6 is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-eagle linux-2.4.32-rc1.mips/arch/mips/defconfig-eagle
+--- linux-2.4.32-rc1/arch/mips/defconfig-eagle 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-eagle 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -208,8 +208,8 @@
+ # Mapping drivers for chip access
+ #
+ CONFIG_MTD_PHYSMAP=y
+-CONFIG_MTD_PHYSMAP_START=1c000000
+-CONFIG_MTD_PHYSMAP_LEN=2000000
++CONFIG_MTD_PHYSMAP_START=0x1c000000
++CONFIG_MTD_PHYSMAP_LEN=0x2000000
+ CONFIG_MTD_PHYSMAP_BUSWIDTH=4
+ # CONFIG_MTD_PB1000 is not set
+ # CONFIG_MTD_PB1500 is not set
+@@ -217,9 +217,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -238,7 +236,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -327,11 +324,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -587,7 +579,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-ev64120 linux-2.4.32-rc1.mips/arch/mips/defconfig-ev64120
+--- linux-2.4.32-rc1/arch/mips/defconfig-ev64120 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-ev64120 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -230,11 +230,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -443,7 +438,6 @@
+ # CONFIG_SERIAL_CONSOLE is not set
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-ev96100 linux-2.4.32-rc1.mips/arch/mips/defconfig-ev96100
+--- linux-2.4.32-rc1/arch/mips/defconfig-ev96100 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-ev96100 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -232,11 +232,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -441,7 +436,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-ficmmp linux-2.4.32-rc1.mips/arch/mips/defconfig-ficmmp
+--- linux-2.4.32-rc1/arch/mips/defconfig-ficmmp 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-ficmmp 2005-03-18 13:13:21.000000000 +0100
+@@ -0,0 +1,862 @@
++#
++# Automatically generated make config: don't edit
++#
++CONFIG_MIPS=y
++CONFIG_MIPS32=y
++# CONFIG_MIPS64 is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# Machine selection
++#
++# CONFIG_ACER_PICA_61 is not set
++# CONFIG_MIPS_BOSPORUS is not set
++# CONFIG_MIPS_MIRAGE is not set
++# CONFIG_MIPS_DB1000 is not set
++# CONFIG_MIPS_DB1100 is not set
++# CONFIG_MIPS_DB1500 is not set
++# CONFIG_MIPS_DB1550 is not set
++# CONFIG_MIPS_PB1000 is not set
++# CONFIG_MIPS_PB1100 is not set
++# CONFIG_MIPS_PB1500 is not set
++# CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
++# CONFIG_MIPS_XXS1500 is not set
++# CONFIG_MIPS_MTX1 is not set
++# CONFIG_COGENT_CSB250 is not set
++# CONFIG_BAGET_MIPS is not set
++# CONFIG_CASIO_E55 is not set
++# CONFIG_MIPS_COBALT is not set
++# CONFIG_DECSTATION is not set
++# CONFIG_MIPS_EV64120 is not set
++# CONFIG_MIPS_EV96100 is not set
++# CONFIG_MIPS_IVR is not set
++# CONFIG_HP_LASERJET is not set
++# CONFIG_IBM_WORKPAD is not set
++# CONFIG_LASAT is not set
++# CONFIG_MIPS_ITE8172 is not set
++# CONFIG_MIPS_ATLAS is not set
++# CONFIG_MIPS_MAGNUM_4000 is not set
++# CONFIG_MIPS_MALTA is not set
++# CONFIG_MIPS_SEAD is not set
++# CONFIG_MOMENCO_OCELOT is not set
++# CONFIG_MOMENCO_OCELOT_G is not set
++# CONFIG_MOMENCO_OCELOT_C is not set
++# CONFIG_MOMENCO_JAGUAR_ATX is not set
++# CONFIG_PMC_BIG_SUR is not set
++# CONFIG_PMC_STRETCH is not set
++# CONFIG_PMC_YOSEMITE is not set
++# CONFIG_DDB5074 is not set
++# CONFIG_DDB5476 is not set
++# CONFIG_DDB5477 is not set
++# CONFIG_NEC_OSPREY is not set
++# CONFIG_NEC_EAGLE is not set
++# CONFIG_OLIVETTI_M700 is not set
++# CONFIG_NINO is not set
++# CONFIG_SGI_IP22 is not set
++# CONFIG_SGI_IP27 is not set
++# CONFIG_SIBYTE_SB1xxx_SOC is not set
++# CONFIG_SNI_RM200_PCI is not set
++# CONFIG_TANBAC_TB0226 is not set
++# CONFIG_TANBAC_TB0229 is not set
++# CONFIG_TOSHIBA_JMR3927 is not set
++# CONFIG_TOSHIBA_RBTX4927 is not set
++# CONFIG_VICTOR_MPC30X is not set
++# CONFIG_ZAO_CAPCELLA is not set
++# CONFIG_HIGHMEM is not set
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_MIPS_AU1000 is not set
++
++#
++# CPU selection
++#
++CONFIG_CPU_MIPS32=y
++# CONFIG_CPU_MIPS64 is not set
++# CONFIG_CPU_R3000 is not set
++# CONFIG_CPU_TX39XX is not set
++# CONFIG_CPU_VR41XX is not set
++# CONFIG_CPU_R4300 is not set
++# CONFIG_CPU_R4X00 is not set
++# CONFIG_CPU_TX49XX is not set
++# CONFIG_CPU_R5000 is not set
++# CONFIG_CPU_R5432 is not set
++# CONFIG_CPU_R6000 is not set
++# CONFIG_CPU_NEVADA is not set
++# CONFIG_CPU_R8000 is not set
++# CONFIG_CPU_R10000 is not set
++# CONFIG_CPU_RM7000 is not set
++# CONFIG_CPU_RM9000 is not set
++# CONFIG_CPU_SB1 is not set
++CONFIG_PAGE_SIZE_4KB=y
++# CONFIG_PAGE_SIZE_16KB is not set
++# CONFIG_PAGE_SIZE_64KB is not set
++CONFIG_CPU_HAS_PREFETCH=y
++# CONFIG_VTAG_ICACHE is not set
++CONFIG_64BIT_PHYS_ADDR=y
++# CONFIG_CPU_ADVANCED is not set
++CONFIG_CPU_HAS_LLSC=y
++# CONFIG_CPU_HAS_LLDSCD is not set
++# CONFIG_CPU_HAS_WB is not set
++CONFIG_CPU_HAS_SYNC=y
++
++#
++# General setup
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++# CONFIG_BUILD_ELF64 is not set
++CONFIG_NET=y
++# CONFIG_PCI is not set
++# CONFIG_PCI_NEW is not set
++CONFIG_PCI_AUTO=y
++# CONFIG_ISA is not set
++# CONFIG_TC is not set
++# CONFIG_MCA is not set
++# CONFIG_SBUS is not set
++# CONFIG_HOTPLUG is not set
++# CONFIG_PCMCIA is not set
++# CONFIG_HOTPLUG_PCI is not set
++CONFIG_SYSVIPC=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++CONFIG_SYSCTL=y
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_MIPS32_COMPAT is not set
++# CONFIG_MIPS32_O32 is not set
++# CONFIG_MIPS32_N32 is not set
++# CONFIG_BINFMT_ELF32 is not set
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_OOM_KILLER is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="ide3=dma mem=96M root=/dev/hda2 rootflags=data=journal"
++
++#
++# Memory Technology Devices (MTD)
++#
++# CONFIG_MTD is not set
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_CISS_MONITOR_THREAD is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_SX8 is not set
++CONFIG_BLK_DEV_LOOP=y
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_RAM is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_BLK_STATS is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++# CONFIG_NETLINK_DEV is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_FILTER=y
++CONFIG_UNIX=y
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_IP_NF_CONNTRACK is not set
++# CONFIG_IP_NF_QUEUE is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES is not set
++# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
++# CONFIG_IP_NF_COMPAT_IPFWADM is not set
++
++#
++# IP: Virtual Server Configuration
++#
++# CONFIG_IP_VS is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++
++#
++#
++#
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Telephony Support
++#
++# CONFIG_PHONE is not set
++# CONFIG_PHONE_IXJ is not set
++# CONFIG_PHONE_IXJ_PCMCIA is not set
++
++#
++# ATA/IDE/MFM/RLL support
++#
++CONFIG_IDE=y
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=y
++
++#
++# Please see Documentation/ide.txt for help/info on IDE drives
++#
++CONFIG_BLK_DEV_HD_IDE=y
++CONFIG_BLK_DEV_HD=y
++# CONFIG_BLK_DEV_IDE_SATA is not set
++CONFIG_BLK_DEV_IDEDISK=y
++CONFIG_IDEDISK_MULTI_MODE=y
++CONFIG_IDEDISK_STROKE=y
++# CONFIG_BLK_DEV_IDECS is not set
++# CONFIG_BLK_DEV_DELKIN is not set
++# CONFIG_BLK_DEV_IDECD is not set
++# CONFIG_BLK_DEV_IDETAPE is not set
++# CONFIG_BLK_DEV_IDEFLOPPY is not set
++# CONFIG_BLK_DEV_IDESCSI is not set
++# CONFIG_IDE_TASK_IOCTL is not set
++
++#
++# IDE chipset support/bugfixes
++#
++# CONFIG_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++# CONFIG_IDE_CHIPSETS is not set
++# CONFIG_IDEDMA_AUTO is not set
++# CONFIG_DMA_NONPCI is not set
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set
++# CONFIG_BLK_DEV_ATARAID_SII is not set
++
++#
++# SCSI support
++#
++CONFIG_SCSI=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++CONFIG_SD_EXTRA_DEVS=40
++CONFIG_CHR_DEV_ST=y
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_SR_EXTRA_DEVS=2
++# CONFIG_CHR_DEV_SG is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++# CONFIG_SCSI_DEBUG_QUEUES is not set
++# CONFIG_SCSI_MULTI_LUN is not set
++CONFIG_SCSI_CONSTANTS=y
++# CONFIG_SCSI_LOGGING is not set
++
++#
++# SCSI low-level drivers
++#
++# CONFIG_SCSI_7000FASST is not set
++# CONFIG_SCSI_ACARD is not set
++# CONFIG_SCSI_AHA152X is not set
++# CONFIG_SCSI_AHA1542 is not set
++# CONFIG_SCSI_AHA1740 is not set
++# CONFIG_SCSI_AACRAID is not set
++# CONFIG_SCSI_AIC7XXX is not set
++# CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC7XXX_OLD is not set
++# CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_SCSI_ADVANSYS is not set
++# CONFIG_SCSI_IN2000 is not set
++# CONFIG_SCSI_AM53C974 is not set
++# CONFIG_SCSI_MEGARAID is not set
++# CONFIG_SCSI_MEGARAID2 is not set
++# CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
++# CONFIG_SCSI_SATA_SVW is not set
++# CONFIG_SCSI_ATA_PIIX is not set
++# CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
++# CONFIG_SCSI_SATA_PROMISE is not set
++# CONFIG_SCSI_SATA_SX4 is not set
++# CONFIG_SCSI_SATA_SIL is not set
++# CONFIG_SCSI_SATA_SIS is not set
++# CONFIG_SCSI_SATA_ULI is not set
++# CONFIG_SCSI_SATA_VIA is not set
++# CONFIG_SCSI_SATA_VITESSE is not set
++# CONFIG_SCSI_BUSLOGIC is not set
++# CONFIG_SCSI_DMX3191D is not set
++# CONFIG_SCSI_DTC3280 is not set
++# CONFIG_SCSI_EATA is not set
++# CONFIG_SCSI_EATA_DMA is not set
++# CONFIG_SCSI_EATA_PIO is not set
++# CONFIG_SCSI_FUTURE_DOMAIN is not set
++# CONFIG_SCSI_GDTH is not set
++# CONFIG_SCSI_GENERIC_NCR5380 is not set
++# CONFIG_SCSI_INITIO is not set
++# CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_NCR53C406A is not set
++# CONFIG_SCSI_NCR53C7xx is not set
++# CONFIG_SCSI_PAS16 is not set
++# CONFIG_SCSI_PCI2000 is not set
++# CONFIG_SCSI_PCI2220I is not set
++# CONFIG_SCSI_PSI240I is not set
++# CONFIG_SCSI_QLOGIC_FAS is not set
++# CONFIG_SCSI_SIM710 is not set
++# CONFIG_SCSI_SYM53C416 is not set
++# CONFIG_SCSI_T128 is not set
++# CONFIG_SCSI_U14_34F is not set
++# CONFIG_SCSI_NSP32 is not set
++# CONFIG_SCSI_DEBUG is not set
++
++#
++# Fusion MPT device support
++#
++# CONFIG_FUSION is not set
++# CONFIG_FUSION_BOOT is not set
++# CONFIG_FUSION_ISENSE is not set
++# CONFIG_FUSION_CTL is not set
++# CONFIG_FUSION_LAN is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++# CONFIG_NET_VENDOR_SMC is not set
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_E1000 is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_R8169 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++CONFIG_INPUT=y
++CONFIG_INPUT_KEYBDEV=y
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_UINPUT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++# CONFIG_SERIAL is not set
++# CONFIG_SERIAL_EXTENDED is not set
++CONFIG_SERIAL_NONSTANDARD=y
++# CONFIG_COMPUTONE is not set
++# CONFIG_ROCKETPORT is not set
++# CONFIG_CYCLADES is not set
++# CONFIG_DIGIEPCA is not set
++# CONFIG_DIGI is not set
++# CONFIG_ESPSERIAL is not set
++# CONFIG_MOXA_INTELLIO is not set
++# CONFIG_MOXA_SMARTIO is not set
++# CONFIG_ISI is not set
++# CONFIG_SYNCLINK is not set
++# CONFIG_SYNCLINKMP is not set
++# CONFIG_N_HDLC is not set
++# CONFIG_RISCOM8 is not set
++# CONFIG_SPECIALIX is not set
++# CONFIG_SX is not set
++# CONFIG_RIO is not set
++# CONFIG_STALDRV is not set
++# CONFIG_SERIAL_TX3912 is not set
++# CONFIG_SERIAL_TX3912_CONSOLE is not set
++# CONFIG_SERIAL_TXX9 is not set
++# CONFIG_SERIAL_TXX9_CONSOLE is not set
++# CONFIG_TXX927_SERIAL is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_SCx200_ACB is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_CHARDEV is not set
++# CONFIG_I2C_PROC is not set
++
++#
++# Mice
++#
++# CONFIG_BUSMOUSE is not set
++# CONFIG_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_INPUT_NS558 is not set
++# CONFIG_INPUT_LIGHTNING is not set
++# CONFIG_INPUT_PCIGAME is not set
++# CONFIG_INPUT_CS461X is not set
++# CONFIG_INPUT_EMU10K1 is not set
++# CONFIG_INPUT_SERIO is not set
++# CONFIG_INPUT_SERPORT is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_ANALOG is not set
++# CONFIG_INPUT_A3D is not set
++# CONFIG_INPUT_ADI is not set
++# CONFIG_INPUT_COBRA is not set
++# CONFIG_INPUT_GF2K is not set
++# CONFIG_INPUT_GRIP is not set
++# CONFIG_INPUT_INTERACT is not set
++# CONFIG_INPUT_TMDC is not set
++# CONFIG_INPUT_SIDEWINDER is not set
++# CONFIG_INPUT_IFORCE_USB is not set
++# CONFIG_INPUT_IFORCE_232 is not set
++# CONFIG_INPUT_WARRIOR is not set
++# CONFIG_INPUT_MAGELLAN is not set
++# CONFIG_INPUT_SPACEORB is not set
++# CONFIG_INPUT_SPACEBALL is not set
++# CONFIG_INPUT_STINGER is not set
++# CONFIG_INPUT_DB9 is not set
++# CONFIG_INPUT_GAMECON is not set
++# CONFIG_INPUT_TURBOGRAFX is not set
++# CONFIG_QIC02_TAPE is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_IPMI_PANIC_EVENT is not set
++# CONFIG_IPMI_DEVICE_INTERFACE is not set
++# CONFIG_IPMI_KCS is not set
++# CONFIG_IPMI_WATCHDOG is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_SCx200 is not set
++# CONFIG_SCx200_GPIO is not set
++# CONFIG_AMD_PM768 is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++
++#
++# Direct Rendering Manager (XFree86 DRI support)
++#
++# CONFIG_DRM is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++# CONFIG_QFMT_V2 is not set
++CONFIG_AUTOFS_FS=y
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BEFS_DEBUG is not set
++# CONFIG_BFS_FS is not set
++CONFIG_EXT3_FS=y
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++# CONFIG_UMSDOS_FS is not set
++CONFIG_VFAT_FS=y
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++# CONFIG_JFFS2_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_TMPFS is not set
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_JFS_DEBUG is not set
++# CONFIG_JFS_STATISTICS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++# CONFIG_DEVFS_FS is not set
++# CONFIG_DEVFS_MOUNT is not set
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_XFS_QUOTA is not set
++# CONFIG_XFS_RT is not set
++# CONFIG_XFS_TRACE is not set
++# CONFIG_XFS_DEBUG is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++# CONFIG_NFS_FS is not set
++# CONFIG_NFS_V3 is not set
++# CONFIG_NFS_DIRECTIO is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++# CONFIG_NFSD_TCP is not set
++# CONFIG_SUNRPC is not set
++# CONFIG_LOCKD is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++# CONFIG_NLS_CODEPAGE_437 is not set
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ISO8859_1 is not set
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# Console drivers
++#
++# CONFIG_VGA_CONSOLE is not set
++# CONFIG_MDA_CONSOLE is not set
++
++#
++# Frame-buffer support
++#
++CONFIG_FB=y
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_VIRTUAL is not set
++CONFIG_FBCON_ADVANCED=y
++# CONFIG_FBCON_MFB is not set
++# CONFIG_FBCON_CFB2 is not set
++# CONFIG_FBCON_CFB4 is not set
++# CONFIG_FBCON_CFB8 is not set
++CONFIG_FBCON_CFB16=y
++# CONFIG_FBCON_CFB24 is not set
++# CONFIG_FBCON_CFB32 is not set
++# CONFIG_FBCON_AFB is not set
++# CONFIG_FBCON_ILBM is not set
++# CONFIG_FBCON_IPLAN2P2 is not set
++# CONFIG_FBCON_IPLAN2P4 is not set
++# CONFIG_FBCON_IPLAN2P8 is not set
++# CONFIG_FBCON_MAC is not set
++# CONFIG_FBCON_VGA_PLANES is not set
++# CONFIG_FBCON_VGA is not set
++# CONFIG_FBCON_HGA is not set
++# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
++CONFIG_FBCON_FONTS=y
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++# CONFIG_FONT_SUN8x16 is not set
++# CONFIG_FONT_SUN12x22 is not set
++# CONFIG_FONT_6x11 is not set
++# CONFIG_FONT_PEARL_8x8 is not set
++# CONFIG_FONT_ACORN_8x8 is not set
++
++#
++# Sound
++#
++CONFIG_SOUND=y
++# CONFIG_SOUND_ALI5455 is not set
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_CMPCI is not set
++# CONFIG_SOUND_EMU10K1 is not set
++# CONFIG_MIDI_EMU10K1 is not set
++# CONFIG_SOUND_FUSION is not set
++# CONFIG_SOUND_CS4281 is not set
++# CONFIG_SOUND_ES1370 is not set
++# CONFIG_SOUND_ES1371 is not set
++# CONFIG_SOUND_ESSSOLO1 is not set
++# CONFIG_SOUND_MAESTRO is not set
++# CONFIG_SOUND_MAESTRO3 is not set
++# CONFIG_SOUND_FORTE is not set
++# CONFIG_SOUND_ICH is not set
++# CONFIG_SOUND_RME96XX is not set
++# CONFIG_SOUND_SONICVIBES is not set
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++# CONFIG_MIDI_VIA82CXXX is not set
++# CONFIG_SOUND_OSS is not set
++# CONFIG_SOUND_TVMIXER is not set
++# CONFIG_SOUND_AD1980 is not set
++# CONFIG_SOUND_WM97XX is not set
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++
++#
++# Support for USB gadgets
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_CROSSCOMPILE=y
++# CONFIG_RUNTIME_DEBUG is not set
++# CONFIG_KGDB is not set
++# CONFIG_GDB_CONSOLE is not set
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_MIPS_UNCACHED is not set
++CONFIG_LOG_BUF_SHIFT=0
++
++#
++# Cryptographic options
++#
++# CONFIG_CRYPTO is not set
++
++#
++# Library routines
++#
++# CONFIG_CRC32 is not set
++CONFIG_ZLIB_INFLATE=m
++CONFIG_ZLIB_DEFLATE=m
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-hp-lj linux-2.4.32-rc1.mips/arch/mips/defconfig-hp-lj
+--- linux-2.4.32-rc1/arch/mips/defconfig-hp-lj 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-hp-lj 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -184,8 +184,8 @@
+ # Mapping drivers for chip access
+ #
+ CONFIG_MTD_PHYSMAP=y
+-CONFIG_MTD_PHYSMAP_START=10040000
+-CONFIG_MTD_PHYSMAP_LEN=00fc0000
++CONFIG_MTD_PHYSMAP_START=0x10040000
++CONFIG_MTD_PHYSMAP_LEN=0x00fc0000
+ CONFIG_MTD_PHYSMAP_BUSWIDTH=4
+ # CONFIG_MTD_PB1000 is not set
+ # CONFIG_MTD_PB1500 is not set
+@@ -193,9 +193,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -214,7 +212,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -304,11 +301,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -604,7 +596,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_UNIX98_PTYS is not set
+
+ #
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-hydrogen3 linux-2.4.32-rc1.mips/arch/mips/defconfig-hydrogen3
+--- linux-2.4.32-rc1/arch/mips/defconfig-hydrogen3 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-hydrogen3 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-CONFIG_MIPS_HYDROGEN3=y
+ # CONFIG_MIPS_PB1550 is not set
++CONFIG_MIPS_HYDROGEN3=y
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -214,9 +214,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-CONFIG_MTD_HYDROGEN3=y
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -235,7 +233,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -340,11 +337,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -590,7 +582,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-CONFIG_MIPS_HYDROGEN3_BUTTONS=y
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+@@ -838,6 +829,7 @@
+ # CONFIG_FB_PM2 is not set
+ # CONFIG_FB_PM3 is not set
+ # CONFIG_FB_CYBER2000 is not set
++CONFIG_FB_AU1100=y
+ # CONFIG_FB_MATROX is not set
+ # CONFIG_FB_ATY is not set
+ # CONFIG_FB_RADEON is not set
+@@ -849,7 +841,6 @@
+ # CONFIG_FB_VOODOO1 is not set
+ # CONFIG_FB_TRIDENT is not set
+ # CONFIG_FB_E1356 is not set
+-CONFIG_FB_AU1100=y
+ # CONFIG_FB_IT8181 is not set
+ # CONFIG_FB_VIRTUAL is not set
+ CONFIG_FBCON_ADVANCED=y
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-ip22 linux-2.4.32-rc1.mips/arch/mips/defconfig-ip22
+--- linux-2.4.32-rc1/arch/mips/defconfig-ip22 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-ip22 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -235,11 +235,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -319,9 +314,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -465,7 +462,6 @@
+ # CONFIG_SERIAL is not set
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-it8172 linux-2.4.32-rc1.mips/arch/mips/defconfig-it8172
+--- linux-2.4.32-rc1/arch/mips/defconfig-it8172 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-it8172 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -186,8 +186,8 @@
+ # Mapping drivers for chip access
+ #
+ CONFIG_MTD_PHYSMAP=y
+-CONFIG_MTD_PHYSMAP_START=8000000
+-CONFIG_MTD_PHYSMAP_LEN=2000000
++CONFIG_MTD_PHYSMAP_START=0x8000000
++CONFIG_MTD_PHYSMAP_LEN=0x2000000
+ CONFIG_MTD_PHYSMAP_BUSWIDTH=4
+ # CONFIG_MTD_PB1000 is not set
+ # CONFIG_MTD_PB1500 is not set
+@@ -195,9 +195,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -216,7 +214,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -304,11 +301,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -592,7 +584,6 @@
+ CONFIG_PC_KEYB=y
+ # CONFIG_IT8172_SCR0 is not set
+ # CONFIG_IT8172_SCR1 is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-ivr linux-2.4.32-rc1.mips/arch/mips/defconfig-ivr
+--- linux-2.4.32-rc1/arch/mips/defconfig-ivr 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-ivr 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -226,11 +226,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -516,7 +511,6 @@
+ CONFIG_QTRONIX_KEYBOARD=y
+ CONFIG_IT8172_CIR=y
+ # CONFIG_IT8172_SCR0 is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-jmr3927 linux-2.4.32-rc1.mips/arch/mips/defconfig-jmr3927
+--- linux-2.4.32-rc1/arch/mips/defconfig-jmr3927 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-jmr3927 2005-03-18 13:13:21.000000000 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -225,11 +225,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -454,7 +449,6 @@
+ # CONFIG_SERIAL_TXX9_CONSOLE is not set
+ CONFIG_TXX927_SERIAL=y
+ CONFIG_TXX927_SERIAL_CONSOLE=y
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_UNIX98_PTYS is not set
+
+ #
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-lasat linux-2.4.32-rc1.mips/arch/mips/defconfig-lasat
+--- linux-2.4.32-rc1/arch/mips/defconfig-lasat 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-lasat 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -198,9 +198,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -219,7 +217,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -303,11 +300,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -584,7 +576,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-malta linux-2.4.32-rc1.mips/arch/mips/defconfig-malta
+--- linux-2.4.32-rc1/arch/mips/defconfig-malta 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-malta 2005-04-19 14:19:34.000000000 +0200
+@@ -22,16 +22,19 @@
+ #
+ # CONFIG_ACER_PICA_61 is not set
+ # CONFIG_MIPS_BOSPORUS is not set
++# CONFIG_MIPS_FICMMP is not set
+ # CONFIG_MIPS_MIRAGE is not set
+ # CONFIG_MIPS_DB1000 is not set
+ # CONFIG_MIPS_DB1100 is not set
+ # CONFIG_MIPS_DB1500 is not set
+ # CONFIG_MIPS_DB1550 is not set
++# CONFIG_MIPS_DB1200 is not set
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_PB1200 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -237,11 +240,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -273,8 +271,83 @@
+ #
+ # ATA/IDE/MFM/RLL support
+ #
+-# CONFIG_IDE is not set
++CONFIG_IDE=y
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=y
++
++#
++# Please see Documentation/ide.txt for help/info on IDE drives
++#
++# CONFIG_BLK_DEV_HD_IDE is not set
+ # CONFIG_BLK_DEV_HD is not set
++# CONFIG_BLK_DEV_IDE_SATA is not set
++CONFIG_BLK_DEV_IDEDISK=y
++# CONFIG_IDEDISK_MULTI_MODE is not set
++# CONFIG_IDEDISK_STROKE is not set
++# CONFIG_BLK_DEV_IDECS is not set
++# CONFIG_BLK_DEV_DELKIN is not set
++CONFIG_BLK_DEV_IDECD=y
++CONFIG_BLK_DEV_IDETAPE=y
++CONFIG_BLK_DEV_IDEFLOPPY=y
++CONFIG_BLK_DEV_IDESCSI=y
++# CONFIG_IDE_TASK_IOCTL is not set
++
++#
++# IDE chipset support/bugfixes
++#
++# CONFIG_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++CONFIG_BLK_DEV_IDEPCI=y
++CONFIG_BLK_DEV_GENERIC=y
++CONFIG_IDEPCI_SHARE_IRQ=y
++CONFIG_BLK_DEV_IDEDMA_PCI=y
++# CONFIG_BLK_DEV_OFFBOARD is not set
++CONFIG_BLK_DEV_IDEDMA_FORCED=y
++CONFIG_IDEDMA_PCI_AUTO=y
++# CONFIG_IDEDMA_ONLYDISK is not set
++CONFIG_BLK_DEV_IDEDMA=y
++# CONFIG_IDEDMA_PCI_WIP is not set
++# CONFIG_BLK_DEV_ADMA100 is not set
++# CONFIG_BLK_DEV_AEC62XX is not set
++# CONFIG_BLK_DEV_ALI15X3 is not set
++# CONFIG_WDC_ALI15X3 is not set
++# CONFIG_BLK_DEV_AMD74XX is not set
++# CONFIG_AMD74XX_OVERRIDE is not set
++# CONFIG_BLK_DEV_ATIIXP is not set
++# CONFIG_BLK_DEV_CMD64X is not set
++# CONFIG_BLK_DEV_TRIFLEX is not set
++# CONFIG_BLK_DEV_CY82C693 is not set
++# CONFIG_BLK_DEV_CS5530 is not set
++# CONFIG_BLK_DEV_HPT34X is not set
++# CONFIG_HPT34X_AUTODMA is not set
++# CONFIG_BLK_DEV_HPT366 is not set
++CONFIG_BLK_DEV_PIIX=y
++# CONFIG_BLK_DEV_NS87415 is not set
++# CONFIG_BLK_DEV_OPTI621 is not set
++# CONFIG_BLK_DEV_PDC202XX_OLD is not set
++# CONFIG_PDC202XX_BURST is not set
++# CONFIG_BLK_DEV_PDC202XX_NEW is not set
++# CONFIG_BLK_DEV_RZ1000 is not set
++# CONFIG_BLK_DEV_SC1200 is not set
++# CONFIG_BLK_DEV_SVWKS is not set
++# CONFIG_BLK_DEV_SIIMAGE is not set
++# CONFIG_BLK_DEV_SIS5513 is not set
++# CONFIG_BLK_DEV_SLC90E66 is not set
++# CONFIG_BLK_DEV_TRM290 is not set
++# CONFIG_BLK_DEV_VIA82CXXX is not set
++# CONFIG_IDE_CHIPSETS is not set
++CONFIG_IDEDMA_AUTO=y
++# CONFIG_IDEDMA_IVB is not set
++# CONFIG_DMA_NONPCI is not set
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set
++# CONFIG_BLK_DEV_ATARAID_SII is not set
+
+ #
+ # SCSI support
+@@ -319,9 +392,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -524,7 +599,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-mirage linux-2.4.32-rc1.mips/arch/mips/defconfig-mirage
+--- linux-2.4.32-rc1/arch/mips/defconfig-mirage 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-mirage 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -209,9 +209,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ CONFIG_MTD_MIRAGE=y
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -230,7 +228,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -335,11 +332,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -560,7 +552,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-mpc30x linux-2.4.32-rc1.mips/arch/mips/defconfig-mpc30x
+--- linux-2.4.32-rc1/arch/mips/defconfig-mpc30x 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-mpc30x 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -228,11 +228,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -400,7 +395,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-mtx-1 linux-2.4.32-rc1.mips/arch/mips/defconfig-mtx-1
+--- linux-2.4.32-rc1/arch/mips/defconfig-mtx-1 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-mtx-1 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ CONFIG_MIPS_MTX1=y
+ # CONFIG_COGENT_CSB250 is not set
+@@ -193,9 +193,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ CONFIG_MTD_MTX1=y
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -214,7 +212,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -371,11 +368,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ CONFIG_BRIDGE=m
+ # CONFIG_X25 is not set
+@@ -479,9 +471,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -700,7 +694,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-nino linux-2.4.32-rc1.mips/arch/mips/defconfig-nino
+--- linux-2.4.32-rc1/arch/mips/defconfig-nino 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-nino 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -226,11 +226,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -339,7 +334,6 @@
+ # CONFIG_SERIAL_TXX9 is not set
+ # CONFIG_SERIAL_TXX9_CONSOLE is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_UNIX98_PTYS is not set
+
+ #
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-ocelot linux-2.4.32-rc1.mips/arch/mips/defconfig-ocelot
+--- linux-2.4.32-rc1/arch/mips/defconfig-ocelot 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-ocelot 2005-03-18 13:13:21.000000000 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -194,9 +194,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ CONFIG_MTD_OCELOT=y
+@@ -215,7 +213,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ CONFIG_MTD_DOC2000=y
+ # CONFIG_MTD_DOC2001 is not set
+ CONFIG_MTD_DOCPROBE=y
+@@ -307,11 +304,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -513,7 +505,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-osprey linux-2.4.32-rc1.mips/arch/mips/defconfig-osprey
+--- linux-2.4.32-rc1/arch/mips/defconfig-osprey 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-osprey 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -227,11 +227,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -388,7 +383,6 @@
+ # CONFIG_SERIAL_MULTIPORT is not set
+ # CONFIG_HUB6 is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-pb1000 linux-2.4.32-rc1.mips/arch/mips/defconfig-pb1000
+--- linux-2.4.32-rc1/arch/mips/defconfig-pb1000 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-pb1000 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ CONFIG_MIPS_PB1000=y
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -215,9 +215,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -236,7 +234,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -324,11 +321,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -622,7 +614,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+@@ -707,7 +698,7 @@
+ #
+ # CONFIG_PCMCIA_SERIAL_CS is not set
+ # CONFIG_SYNCLINK_CS is not set
+-CONFIG_AU1X00_GPIO=m
++CONFIG_AU1X00_GPIO=y
+ # CONFIG_TS_AU1X00_ADS7846 is not set
+
+ #
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-pb1100 linux-2.4.32-rc1.mips/arch/mips/defconfig-pb1100
+--- linux-2.4.32-rc1/arch/mips/defconfig-pb1100 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-pb1100 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ CONFIG_MIPS_PB1100=y
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -198,9 +198,7 @@
+ # CONFIG_MTD_MTX1 is not set
+ CONFIG_MTD_PB1500_BOOT=y
+ CONFIG_MTD_PB1500_USER=y
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -219,7 +217,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -324,11 +321,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -613,7 +605,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+@@ -859,6 +850,7 @@
+ # CONFIG_FB_PM2 is not set
+ # CONFIG_FB_PM3 is not set
+ # CONFIG_FB_CYBER2000 is not set
++CONFIG_FB_AU1100=y
+ # CONFIG_FB_MATROX is not set
+ # CONFIG_FB_ATY is not set
+ # CONFIG_FB_RADEON is not set
+@@ -870,7 +862,6 @@
+ # CONFIG_FB_VOODOO1 is not set
+ # CONFIG_FB_TRIDENT is not set
+ # CONFIG_FB_E1356 is not set
+-CONFIG_FB_AU1100=y
+ # CONFIG_FB_IT8181 is not set
+ # CONFIG_FB_VIRTUAL is not set
+ CONFIG_FBCON_ADVANCED=y
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-pb1200 linux-2.4.32-rc1.mips/arch/mips/defconfig-pb1200
+--- linux-2.4.32-rc1/arch/mips/defconfig-pb1200 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-pb1200 2005-03-18 13:13:21.000000000 +0100
+@@ -0,0 +1,1060 @@
++#
++# Automatically generated make config: don't edit
++#
++CONFIG_MIPS=y
++CONFIG_MIPS32=y
++# CONFIG_MIPS64 is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# Machine selection
++#
++# CONFIG_ACER_PICA_61 is not set
++# CONFIG_MIPS_BOSPORUS is not set
++# CONFIG_MIPS_MIRAGE is not set
++# CONFIG_MIPS_DB1000 is not set
++# CONFIG_MIPS_DB1100 is not set
++# CONFIG_MIPS_DB1500 is not set
++# CONFIG_MIPS_DB1550 is not set
++# CONFIG_MIPS_PB1000 is not set
++# CONFIG_MIPS_PB1100 is not set
++# CONFIG_MIPS_PB1500 is not set
++# CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
++# CONFIG_MIPS_XXS1500 is not set
++# CONFIG_MIPS_MTX1 is not set
++# CONFIG_COGENT_CSB250 is not set
++# CONFIG_BAGET_MIPS is not set
++# CONFIG_CASIO_E55 is not set
++# CONFIG_MIPS_COBALT is not set
++# CONFIG_DECSTATION is not set
++# CONFIG_MIPS_EV64120 is not set
++# CONFIG_MIPS_EV96100 is not set
++# CONFIG_MIPS_IVR is not set
++# CONFIG_HP_LASERJET is not set
++# CONFIG_IBM_WORKPAD is not set
++# CONFIG_LASAT is not set
++# CONFIG_MIPS_ITE8172 is not set
++# CONFIG_MIPS_ATLAS is not set
++# CONFIG_MIPS_MAGNUM_4000 is not set
++# CONFIG_MIPS_MALTA is not set
++# CONFIG_MIPS_SEAD is not set
++# CONFIG_MOMENCO_OCELOT is not set
++# CONFIG_MOMENCO_OCELOT_G is not set
++# CONFIG_MOMENCO_OCELOT_C is not set
++# CONFIG_MOMENCO_JAGUAR_ATX is not set
++# CONFIG_PMC_BIG_SUR is not set
++# CONFIG_PMC_STRETCH is not set
++# CONFIG_PMC_YOSEMITE is not set
++# CONFIG_DDB5074 is not set
++# CONFIG_DDB5476 is not set
++# CONFIG_DDB5477 is not set
++# CONFIG_NEC_OSPREY is not set
++# CONFIG_NEC_EAGLE is not set
++# CONFIG_OLIVETTI_M700 is not set
++# CONFIG_NINO is not set
++# CONFIG_SGI_IP22 is not set
++# CONFIG_SGI_IP27 is not set
++# CONFIG_SIBYTE_SB1xxx_SOC is not set
++# CONFIG_SNI_RM200_PCI is not set
++# CONFIG_TANBAC_TB0226 is not set
++# CONFIG_TANBAC_TB0229 is not set
++# CONFIG_TOSHIBA_JMR3927 is not set
++# CONFIG_TOSHIBA_RBTX4927 is not set
++# CONFIG_VICTOR_MPC30X is not set
++# CONFIG_ZAO_CAPCELLA is not set
++# CONFIG_HIGHMEM is not set
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++CONFIG_SOC_AU1X00=y
++CONFIG_SOC_AU1200=y
++CONFIG_NONCOHERENT_IO=y
++CONFIG_PC_KEYB=y
++# CONFIG_MIPS_AU1000 is not set
++
++#
++# CPU selection
++#
++CONFIG_CPU_MIPS32=y
++# CONFIG_CPU_MIPS64 is not set
++# CONFIG_CPU_R3000 is not set
++# CONFIG_CPU_TX39XX is not set
++# CONFIG_CPU_VR41XX is not set
++# CONFIG_CPU_R4300 is not set
++# CONFIG_CPU_R4X00 is not set
++# CONFIG_CPU_TX49XX is not set
++# CONFIG_CPU_R5000 is not set
++# CONFIG_CPU_R5432 is not set
++# CONFIG_CPU_R6000 is not set
++# CONFIG_CPU_NEVADA is not set
++# CONFIG_CPU_R8000 is not set
++# CONFIG_CPU_R10000 is not set
++# CONFIG_CPU_RM7000 is not set
++# CONFIG_CPU_RM9000 is not set
++# CONFIG_CPU_SB1 is not set
++CONFIG_PAGE_SIZE_4KB=y
++# CONFIG_PAGE_SIZE_16KB is not set
++# CONFIG_PAGE_SIZE_64KB is not set
++CONFIG_CPU_HAS_PREFETCH=y
++# CONFIG_VTAG_ICACHE is not set
++CONFIG_64BIT_PHYS_ADDR=y
++# CONFIG_CPU_ADVANCED is not set
++CONFIG_CPU_HAS_LLSC=y
++# CONFIG_CPU_HAS_LLDSCD is not set
++# CONFIG_CPU_HAS_WB is not set
++CONFIG_CPU_HAS_SYNC=y
++
++#
++# General setup
++#
++CONFIG_CPU_LITTLE_ENDIAN=y
++# CONFIG_BUILD_ELF64 is not set
++CONFIG_NET=y
++CONFIG_PCI=y
++CONFIG_PCI_NEW=y
++CONFIG_PCI_AUTO=y
++# CONFIG_PCI_NAMES is not set
++# CONFIG_ISA is not set
++# CONFIG_TC is not set
++# CONFIG_MCA is not set
++# CONFIG_SBUS is not set
++CONFIG_HOTPLUG=y
++
++#
++# PCMCIA/CardBus support
++#
++CONFIG_PCMCIA=m
++# CONFIG_CARDBUS is not set
++# CONFIG_TCIC is not set
++# CONFIG_I82092 is not set
++# CONFIG_I82365 is not set
++CONFIG_PCMCIA_AU1X00=m
++
++#
++# PCI Hotplug Support
++#
++# CONFIG_HOTPLUG_PCI is not set
++# CONFIG_HOTPLUG_PCI_COMPAQ is not set
++# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
++# CONFIG_HOTPLUG_PCI_SHPC is not set
++# CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE is not set
++# CONFIG_HOTPLUG_PCI_PCIE is not set
++# CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set
++CONFIG_SYSVIPC=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++CONFIG_SYSCTL=y
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_MIPS32_COMPAT is not set
++# CONFIG_MIPS32_O32 is not set
++# CONFIG_MIPS32_N32 is not set
++# CONFIG_BINFMT_ELF32 is not set
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_OOM_KILLER is not set
++CONFIG_CMDLINE_BOOL=y
++CONFIG_CMDLINE="mem=96M"
++# CONFIG_PM is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++# CONFIG_MTD is not set
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_CISS_MONITOR_THREAD is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_SX8 is not set
++CONFIG_BLK_DEV_LOOP=y
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_RAM is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_BLK_STATS is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++# CONFIG_NETLINK_DEV is not set
++CONFIG_NETFILTER=y
++# CONFIG_NETFILTER_DEBUG is not set
++CONFIG_FILTER=y
++CONFIG_UNIX=y
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++
++#
++# IP: Netfilter Configuration
++#
++# CONFIG_IP_NF_CONNTRACK is not set
++# CONFIG_IP_NF_QUEUE is not set
++# CONFIG_IP_NF_IPTABLES is not set
++# CONFIG_IP_NF_ARPTABLES is not set
++# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
++# CONFIG_IP_NF_COMPAT_IPFWADM is not set
++
++#
++# IP: Virtual Server Configuration
++#
++# CONFIG_IP_VS is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++
++#
++# SCTP Configuration (EXPERIMENTAL)
++#
++# CONFIG_IP_SCTP is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++
++#
++#
++#
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Telephony Support
++#
++# CONFIG_PHONE is not set
++# CONFIG_PHONE_IXJ is not set
++# CONFIG_PHONE_IXJ_PCMCIA is not set
++
++#
++# ATA/IDE/MFM/RLL support
++#
++CONFIG_IDE=y
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=y
++
++#
++# Please see Documentation/ide.txt for help/info on IDE drives
++#
++# CONFIG_BLK_DEV_HD_IDE is not set
++# CONFIG_BLK_DEV_HD is not set
++# CONFIG_BLK_DEV_IDE_SATA is not set
++CONFIG_BLK_DEV_IDEDISK=y
++CONFIG_IDEDISK_MULTI_MODE=y
++CONFIG_IDEDISK_STROKE=y
++CONFIG_BLK_DEV_IDECS=m
++# CONFIG_BLK_DEV_DELKIN is not set
++# CONFIG_BLK_DEV_IDECD is not set
++# CONFIG_BLK_DEV_IDETAPE is not set
++# CONFIG_BLK_DEV_IDEFLOPPY is not set
++# CONFIG_BLK_DEV_IDESCSI is not set
++# CONFIG_IDE_TASK_IOCTL is not set
++
++#
++# IDE chipset support/bugfixes
++#
++# CONFIG_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++# CONFIG_BLK_DEV_IDEPCI is not set
++# CONFIG_IDE_CHIPSETS is not set
++# CONFIG_IDEDMA_AUTO is not set
++# CONFIG_DMA_NONPCI is not set
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set
++# CONFIG_BLK_DEV_ATARAID_SII is not set
++
++#
++# SCSI support
++#
++CONFIG_SCSI=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++CONFIG_SD_EXTRA_DEVS=40
++CONFIG_CHR_DEV_ST=y
++# CONFIG_CHR_DEV_OSST is not set
++CONFIG_BLK_DEV_SR=y
++# CONFIG_BLK_DEV_SR_VENDOR is not set
++CONFIG_SR_EXTRA_DEVS=2
++# CONFIG_CHR_DEV_SG is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++# CONFIG_SCSI_DEBUG_QUEUES is not set
++# CONFIG_SCSI_MULTI_LUN is not set
++CONFIG_SCSI_CONSTANTS=y
++# CONFIG_SCSI_LOGGING is not set
++
++#
++# SCSI low-level drivers
++#
++# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
++# CONFIG_SCSI_7000FASST is not set
++# CONFIG_SCSI_ACARD is not set
++# CONFIG_SCSI_AHA152X is not set
++# CONFIG_SCSI_AHA1542 is not set
++# CONFIG_SCSI_AHA1740 is not set
++# CONFIG_SCSI_AACRAID is not set
++# CONFIG_SCSI_AIC7XXX is not set
++# CONFIG_SCSI_AIC79XX is not set
++# CONFIG_SCSI_AIC7XXX_OLD is not set
++# CONFIG_SCSI_DPT_I2O is not set
++# CONFIG_SCSI_ADVANSYS is not set
++# CONFIG_SCSI_IN2000 is not set
++# CONFIG_SCSI_AM53C974 is not set
++# CONFIG_SCSI_MEGARAID is not set
++# CONFIG_SCSI_MEGARAID2 is not set
++# CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
++# CONFIG_SCSI_SATA_SVW is not set
++# CONFIG_SCSI_ATA_PIIX is not set
++# CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
++# CONFIG_SCSI_SATA_PROMISE is not set
++# CONFIG_SCSI_SATA_SX4 is not set
++# CONFIG_SCSI_SATA_SIL is not set
++# CONFIG_SCSI_SATA_SIS is not set
++# CONFIG_SCSI_SATA_ULI is not set
++# CONFIG_SCSI_SATA_VIA is not set
++# CONFIG_SCSI_SATA_VITESSE is not set
++# CONFIG_SCSI_BUSLOGIC is not set
++# CONFIG_SCSI_CPQFCTS is not set
++# CONFIG_SCSI_DMX3191D is not set
++# CONFIG_SCSI_DTC3280 is not set
++# CONFIG_SCSI_EATA is not set
++# CONFIG_SCSI_EATA_DMA is not set
++# CONFIG_SCSI_EATA_PIO is not set
++# CONFIG_SCSI_FUTURE_DOMAIN is not set
++# CONFIG_SCSI_GDTH is not set
++# CONFIG_SCSI_GENERIC_NCR5380 is not set
++# CONFIG_SCSI_INITIO is not set
++# CONFIG_SCSI_INIA100 is not set
++# CONFIG_SCSI_NCR53C406A is not set
++# CONFIG_SCSI_NCR53C7xx is not set
++# CONFIG_SCSI_SYM53C8XX_2 is not set
++# CONFIG_SCSI_NCR53C8XX is not set
++# CONFIG_SCSI_SYM53C8XX is not set
++# CONFIG_SCSI_PAS16 is not set
++# CONFIG_SCSI_PCI2000 is not set
++# CONFIG_SCSI_PCI2220I is not set
++# CONFIG_SCSI_PSI240I is not set
++# CONFIG_SCSI_QLOGIC_FAS is not set
++# CONFIG_SCSI_QLOGIC_ISP is not set
++# CONFIG_SCSI_QLOGIC_FC is not set
++# CONFIG_SCSI_QLOGIC_1280 is not set
++# CONFIG_SCSI_SIM710 is not set
++# CONFIG_SCSI_SYM53C416 is not set
++# CONFIG_SCSI_DC390T is not set
++# CONFIG_SCSI_T128 is not set
++# CONFIG_SCSI_U14_34F is not set
++# CONFIG_SCSI_NSP32 is not set
++# CONFIG_SCSI_DEBUG is not set
++
++#
++# PCMCIA SCSI adapter support
++#
++# CONFIG_SCSI_PCMCIA is not set
++
++#
++# Fusion MPT device support
++#
++# CONFIG_FUSION is not set
++# CONFIG_FUSION_BOOT is not set
++# CONFIG_FUSION_ISENSE is not set
++# CONFIG_FUSION_CTL is not set
++# CONFIG_FUSION_LAN is not set
++
++#
++# IEEE 1394 (FireWire) support (EXPERIMENTAL)
++#
++# CONFIG_IEEE1394 is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_PCI is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_MIPS_AU1X00_ENET is not set
++# CONFIG_SUNLANCE is not set
++# CONFIG_HAPPYMEAL is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++# CONFIG_NET_VENDOR_SMC is not set
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_HP100 is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_E1000 is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_R8169 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++CONFIG_PPP=m
++CONFIG_PPP_MULTILINK=y
++# CONFIG_PPP_FILTER is not set
++CONFIG_PPP_ASYNC=m
++# CONFIG_PPP_SYNC_TTY is not set
++CONFIG_PPP_DEFLATE=m
++# CONFIG_PPP_BSDCOMP is not set
++CONFIG_PPPOE=m
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# PCMCIA network device support
++#
++# CONFIG_NET_PCMCIA is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++CONFIG_INPUT=y
++CONFIG_INPUT_KEYBDEV=y
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_UINPUT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++# CONFIG_VT_CONSOLE is not set
++# CONFIG_SERIAL is not set
++# CONFIG_SERIAL_EXTENDED is not set
++CONFIG_SERIAL_NONSTANDARD=y
++# CONFIG_COMPUTONE is not set
++# CONFIG_ROCKETPORT is not set
++# CONFIG_CYCLADES is not set
++# CONFIG_DIGIEPCA is not set
++# CONFIG_DIGI is not set
++# CONFIG_ESPSERIAL is not set
++# CONFIG_MOXA_INTELLIO is not set
++# CONFIG_MOXA_SMARTIO is not set
++# CONFIG_ISI is not set
++# CONFIG_SYNCLINK is not set
++# CONFIG_SYNCLINKMP is not set
++# CONFIG_N_HDLC is not set
++# CONFIG_RISCOM8 is not set
++# CONFIG_SPECIALIX is not set
++# CONFIG_SX is not set
++# CONFIG_RIO is not set
++# CONFIG_STALDRV is not set
++# CONFIG_SERIAL_TX3912 is not set
++# CONFIG_SERIAL_TX3912_CONSOLE is not set
++# CONFIG_SERIAL_TXX9 is not set
++# CONFIG_SERIAL_TXX9_CONSOLE is not set
++CONFIG_AU1X00_UART=y
++CONFIG_AU1X00_SERIAL_CONSOLE=y
++# CONFIG_AU1X00_USB_TTY is not set
++# CONFIG_AU1X00_USB_RAW is not set
++# CONFIG_TXX927_SERIAL is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_SCx200_ACB is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_CHARDEV is not set
++CONFIG_I2C_PROC=y
++
++#
++# Mice
++#
++# CONFIG_BUSMOUSE is not set
++# CONFIG_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_INPUT_NS558 is not set
++# CONFIG_INPUT_LIGHTNING is not set
++# CONFIG_INPUT_PCIGAME is not set
++# CONFIG_INPUT_CS461X is not set
++# CONFIG_INPUT_EMU10K1 is not set
++# CONFIG_INPUT_SERIO is not set
++# CONFIG_INPUT_SERPORT is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_ANALOG is not set
++# CONFIG_INPUT_A3D is not set
++# CONFIG_INPUT_ADI is not set
++# CONFIG_INPUT_COBRA is not set
++# CONFIG_INPUT_GF2K is not set
++# CONFIG_INPUT_GRIP is not set
++# CONFIG_INPUT_INTERACT is not set
++# CONFIG_INPUT_TMDC is not set
++# CONFIG_INPUT_SIDEWINDER is not set
++# CONFIG_INPUT_IFORCE_USB is not set
++# CONFIG_INPUT_IFORCE_232 is not set
++# CONFIG_INPUT_WARRIOR is not set
++# CONFIG_INPUT_MAGELLAN is not set
++# CONFIG_INPUT_SPACEORB is not set
++# CONFIG_INPUT_SPACEBALL is not set
++# CONFIG_INPUT_STINGER is not set
++# CONFIG_INPUT_DB9 is not set
++# CONFIG_INPUT_GAMECON is not set
++# CONFIG_INPUT_TURBOGRAFX is not set
++# CONFIG_QIC02_TAPE is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_IPMI_PANIC_EVENT is not set
++# CONFIG_IPMI_DEVICE_INTERFACE is not set
++# CONFIG_IPMI_KCS is not set
++# CONFIG_IPMI_WATCHDOG is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_SCx200 is not set
++# CONFIG_SCx200_GPIO is not set
++# CONFIG_AMD_PM768 is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++
++#
++# Direct Rendering Manager (XFree86 DRI support)
++#
++# CONFIG_DRM is not set
++
++#
++# PCMCIA character devices
++#
++# CONFIG_PCMCIA_SERIAL_CS is not set
++# CONFIG_SYNCLINK_CS is not set
++# CONFIG_AU1X00_GPIO is not set
++# CONFIG_TS_AU1X00_ADS7846 is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++# CONFIG_QFMT_V2 is not set
++CONFIG_AUTOFS_FS=y
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BEFS_DEBUG is not set
++# CONFIG_BFS_FS is not set
++CONFIG_EXT3_FS=y
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++# CONFIG_UMSDOS_FS is not set
++CONFIG_VFAT_FS=y
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++# CONFIG_JFFS2_FS is not set
++# CONFIG_CRAMFS is not set
++CONFIG_TMPFS=y
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_JFS_DEBUG is not set
++# CONFIG_JFS_STATISTICS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++# CONFIG_DEVFS_FS is not set
++# CONFIG_DEVFS_MOUNT is not set
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_XFS_QUOTA is not set
++# CONFIG_XFS_RT is not set
++# CONFIG_XFS_TRACE is not set
++# CONFIG_XFS_DEBUG is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_DIRECTIO is not set
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++# CONFIG_NFSD_TCP is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++# CONFIG_NLS_CODEPAGE_437 is not set
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++# CONFIG_NLS_ISO8859_1 is not set
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# Console drivers
++#
++# CONFIG_VGA_CONSOLE is not set
++# CONFIG_MDA_CONSOLE is not set
++
++#
++# Frame-buffer support
++#
++CONFIG_FB=y
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FB_RIVA is not set
++# CONFIG_FB_CLGEN is not set
++# CONFIG_FB_PM2 is not set
++# CONFIG_FB_PM3 is not set
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_MATROX is not set
++# CONFIG_FB_ATY is not set
++# CONFIG_FB_RADEON is not set
++# CONFIG_FB_ATY128 is not set
++# CONFIG_FB_INTEL is not set
++# CONFIG_FB_SIS is not set
++# CONFIG_FB_NEOMAGIC is not set
++# CONFIG_FB_3DFX is not set
++# CONFIG_FB_VOODOO1 is not set
++# CONFIG_FB_TRIDENT is not set
++# CONFIG_FB_E1356 is not set
++# CONFIG_FB_IT8181 is not set
++# CONFIG_FB_VIRTUAL is not set
++CONFIG_FBCON_ADVANCED=y
++# CONFIG_FBCON_MFB is not set
++# CONFIG_FBCON_CFB2 is not set
++# CONFIG_FBCON_CFB4 is not set
++# CONFIG_FBCON_CFB8 is not set
++CONFIG_FBCON_CFB16=y
++# CONFIG_FBCON_CFB24 is not set
++CONFIG_FBCON_CFB32=y
++# CONFIG_FBCON_AFB is not set
++# CONFIG_FBCON_ILBM is not set
++# CONFIG_FBCON_IPLAN2P2 is not set
++# CONFIG_FBCON_IPLAN2P4 is not set
++# CONFIG_FBCON_IPLAN2P8 is not set
++# CONFIG_FBCON_MAC is not set
++# CONFIG_FBCON_VGA_PLANES is not set
++# CONFIG_FBCON_VGA is not set
++# CONFIG_FBCON_HGA is not set
++# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
++CONFIG_FBCON_FONTS=y
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++# CONFIG_FONT_SUN8x16 is not set
++# CONFIG_FONT_SUN12x22 is not set
++# CONFIG_FONT_6x11 is not set
++# CONFIG_FONT_PEARL_8x8 is not set
++# CONFIG_FONT_ACORN_8x8 is not set
++
++#
++# Sound
++#
++CONFIG_SOUND=y
++# CONFIG_SOUND_ALI5455 is not set
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_CMPCI is not set
++# CONFIG_SOUND_EMU10K1 is not set
++# CONFIG_MIDI_EMU10K1 is not set
++# CONFIG_SOUND_FUSION is not set
++# CONFIG_SOUND_CS4281 is not set
++# CONFIG_SOUND_ES1370 is not set
++# CONFIG_SOUND_ES1371 is not set
++# CONFIG_SOUND_ESSSOLO1 is not set
++# CONFIG_SOUND_MAESTRO is not set
++# CONFIG_SOUND_MAESTRO3 is not set
++# CONFIG_SOUND_FORTE is not set
++# CONFIG_SOUND_ICH is not set
++# CONFIG_SOUND_RME96XX is not set
++# CONFIG_SOUND_SONICVIBES is not set
++# CONFIG_SOUND_AU1X00 is not set
++CONFIG_SOUND_AU1550_PSC=y
++# CONFIG_SOUND_AU1550_I2S is not set
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++# CONFIG_MIDI_VIA82CXXX is not set
++# CONFIG_SOUND_OSS is not set
++# CONFIG_SOUND_TVMIXER is not set
++# CONFIG_SOUND_AD1980 is not set
++# CONFIG_SOUND_WM97XX is not set
++
++#
++# USB support
++#
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++# CONFIG_USB_BANDWIDTH is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_EHCI_HCD is not set
++# CONFIG_USB_UHCI is not set
++# CONFIG_USB_UHCI_ALT is not set
++CONFIG_USB_OHCI=y
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_AUDIO is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_BLUETOOTH is not set
++# CONFIG_USB_MIDI is not set
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_DPCM is not set
++# CONFIG_USB_STORAGE_HP8200e is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++
++#
++# USB Human Interface Devices (HID)
++#
++CONFIG_USB_HID=y
++CONFIG_USB_HIDINPUT=y
++CONFIG_USB_HIDDEV=y
++# CONFIG_USB_AIPTEK is not set
++# CONFIG_USB_WACOM is not set
++# CONFIG_USB_KBTAB is not set
++# CONFIG_USB_POWERMATE is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_DC2XX is not set
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_SCANNER is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USB_HPUSBSCSI is not set
++
++#
++# USB Multimedia devices
++#
++
++#
++# Video4Linux support is needed for USB Multimedia device support
++#
++
++#
++# USB Network adaptors
++#
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_CDCETHER is not set
++# CONFIG_USB_USBNET is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_USS720 is not set
++
++#
++# USB Serial Converter support
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_AUERSWALD is not set
++# CONFIG_USB_TIGL is not set
++# CONFIG_USB_BRLVGER is not set
++# CONFIG_USB_LCD is not set
++
++#
++# Support for USB gadgets
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_CROSSCOMPILE=y
++# CONFIG_RUNTIME_DEBUG is not set
++# CONFIG_KGDB is not set
++# CONFIG_GDB_CONSOLE is not set
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_MIPS_UNCACHED is not set
++CONFIG_LOG_BUF_SHIFT=0
++
++#
++# Cryptographic options
++#
++# CONFIG_CRYPTO is not set
++
++#
++# Library routines
++#
++# CONFIG_CRC32 is not set
++CONFIG_ZLIB_INFLATE=m
++CONFIG_ZLIB_DEFLATE=m
++# CONFIG_FW_LOADER is not set
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-pb1500 linux-2.4.32-rc1.mips/arch/mips/defconfig-pb1500
+--- linux-2.4.32-rc1/arch/mips/defconfig-pb1500 2005-01-19 15:09:28.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-pb1500 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ CONFIG_MIPS_PB1500=y
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -215,9 +215,7 @@
+ # CONFIG_MTD_MTX1 is not set
+ CONFIG_MTD_PB1500_BOOT=y
+ # CONFIG_MTD_PB1500_USER is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -236,7 +234,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -341,11 +338,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -675,7 +667,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-pb1550 linux-2.4.32-rc1.mips/arch/mips/defconfig-pb1550
+--- linux-2.4.32-rc1/arch/mips/defconfig-pb1550 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-pb1550 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ CONFIG_MIPS_PB1550=y
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -213,11 +213,9 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ # CONFIG_MTD_XXS1500 is not set
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ CONFIG_MTD_PB1550=y
+ CONFIG_MTD_PB1550_BOOT=y
+ CONFIG_MTD_PB1550_USER=y
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -236,7 +234,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -343,11 +340,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -633,7 +625,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-rbtx4927 linux-2.4.32-rc1.mips/arch/mips/defconfig-rbtx4927
+--- linux-2.4.32-rc1/arch/mips/defconfig-rbtx4927 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-rbtx4927 2005-03-18 13:13:21.000000000 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -223,11 +223,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -466,7 +461,6 @@
+ CONFIG_SERIAL_TXX9=y
+ CONFIG_SERIAL_TXX9_CONSOLE=y
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_UNIX98_PTYS is not set
+
+ #
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-rm200 linux-2.4.32-rc1.mips/arch/mips/defconfig-rm200
+--- linux-2.4.32-rc1/arch/mips/defconfig-rm200 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-rm200 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -229,11 +229,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -340,7 +335,6 @@
+ # CONFIG_SERIAL is not set
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-sb1250-swarm linux-2.4.32-rc1.mips/arch/mips/defconfig-sb1250-swarm
+--- linux-2.4.32-rc1/arch/mips/defconfig-sb1250-swarm 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-sb1250-swarm 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -90,6 +90,7 @@
+ # CONFIG_SIBYTE_TBPROF is not set
+ CONFIG_SIBYTE_GENBUS_IDE=y
+ CONFIG_SMP_CAPABLE=y
++CONFIG_MIPS_RTC=y
+ # CONFIG_SNI_RM200_PCI is not set
+ # CONFIG_TANBAC_TB0226 is not set
+ # CONFIG_TANBAC_TB0229 is not set
+@@ -253,11 +254,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -469,7 +465,6 @@
+ CONFIG_SIBYTE_SB1250_DUART=y
+ CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y
+ CONFIG_SERIAL_CONSOLE=y
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-sead linux-2.4.32-rc1.mips/arch/mips/defconfig-sead
+--- linux-2.4.32-rc1/arch/mips/defconfig-sead 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-sead 2005-03-18 13:13:21.000000000 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -244,7 +244,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_UNIX98_PTYS is not set
+
+ #
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-stretch linux-2.4.32-rc1.mips/arch/mips/defconfig-stretch
+--- linux-2.4.32-rc1/arch/mips/defconfig-stretch 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-stretch 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -240,11 +240,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -324,9 +319,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -516,7 +513,6 @@
+ # CONFIG_SERIAL_TXX9 is not set
+ # CONFIG_SERIAL_TXX9_CONSOLE is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-tb0226 linux-2.4.32-rc1.mips/arch/mips/defconfig-tb0226
+--- linux-2.4.32-rc1/arch/mips/defconfig-tb0226 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-tb0226 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -228,11 +228,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -312,9 +307,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -518,7 +515,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-tb0229 linux-2.4.32-rc1.mips/arch/mips/defconfig-tb0229
+--- linux-2.4.32-rc1/arch/mips/defconfig-tb0229 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-tb0229 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -230,11 +230,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -445,7 +440,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-ti1500 linux-2.4.32-rc1.mips/arch/mips/defconfig-ti1500
+--- linux-2.4.32-rc1/arch/mips/defconfig-ti1500 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-ti1500 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ CONFIG_MIPS_XXS1500=y
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -213,9 +213,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ CONFIG_MTD_XXS1500=y
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -234,7 +232,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -339,11 +336,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -600,7 +592,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-workpad linux-2.4.32-rc1.mips/arch/mips/defconfig-workpad
+--- linux-2.4.32-rc1/arch/mips/defconfig-workpad 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-workpad 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -222,11 +222,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -426,7 +421,6 @@
+ # CONFIG_SERIAL_MULTIPORT is not set
+ # CONFIG_HUB6 is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_VR41XX_KIU is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-xxs1500 linux-2.4.32-rc1.mips/arch/mips/defconfig-xxs1500
+--- linux-2.4.32-rc1/arch/mips/defconfig-xxs1500 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-xxs1500 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ CONFIG_MIPS_XXS1500=y
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -213,9 +213,7 @@
+ # CONFIG_MTD_BOSPORUS is not set
+ CONFIG_MTD_XXS1500=y
+ # CONFIG_MTD_MTX1 is not set
+-# CONFIG_MTD_DB1X00 is not set
+ # CONFIG_MTD_PB1550 is not set
+-# CONFIG_MTD_HYDROGEN3 is not set
+ # CONFIG_MTD_MIRAGE is not set
+ # CONFIG_MTD_CSTM_MIPS_IXX is not set
+ # CONFIG_MTD_OCELOT is not set
+@@ -234,7 +232,6 @@
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
+ # CONFIG_MTD_DOCPROBE is not set
+@@ -339,11 +336,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -671,7 +663,6 @@
+ # CONFIG_AU1X00_USB_TTY is not set
+ # CONFIG_AU1X00_USB_RAW is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/defconfig-yosemite linux-2.4.32-rc1.mips/arch/mips/defconfig-yosemite
+--- linux-2.4.32-rc1/arch/mips/defconfig-yosemite 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/defconfig-yosemite 2005-03-18 13:13:21.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -227,11 +227,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -310,9 +305,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -477,7 +474,6 @@
+ # CONFIG_SERIAL_TXX9 is not set
+ # CONFIG_SERIAL_TXX9_CONSOLE is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips/kernel/cpu-probe.c linux-2.4.32-rc1.mips/arch/mips/kernel/cpu-probe.c
+--- linux-2.4.32-rc1/arch/mips/kernel/cpu-probe.c 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/kernel/cpu-probe.c 2005-05-25 15:33:22.000000000 +0200
+@@ -34,21 +34,16 @@
+ ".set\tmips0");
+ }
+
+-/* The Au1xxx wait is available only if we run CONFIG_PM and
+- * the timer setup found we had a 32KHz counter available.
+- * There are still problems with functions that may call au1k_wait
+- * directly, but that will be discovered pretty quickly.
+- */
+-extern void (*au1k_wait_ptr)(void);
+-void au1k_wait(void)
++/* The Au1xxx wait is available only if using 32khz counter or
++ * external timer source, but specifically not CP0 Counter. */
++int allow_au1k_wait;
++
++static void au1k_wait(void)
+ {
+-#ifdef CONFIG_PM
+- unsigned long addr;
+ /* using the wait instruction makes CP0 counter unusable */
+- __asm__("la %0,au1k_wait\n\t"
+- ".set mips3\n\t"
+- "cache 0x14,0(%0)\n\t"
+- "cache 0x14,32(%0)\n\t"
++ __asm__(".set mips3\n\t"
++ "cache 0x14, 0(%0)\n\t"
++ "cache 0x14, 32(%0)\n\t"
+ "sync\n\t"
+ "nop\n\t"
+ "wait\n\t"
+@@ -57,11 +52,7 @@
+ "nop\n\t"
+ "nop\n\t"
+ ".set mips0\n\t"
+- : : "r" (addr));
+-#else
+- __asm__("nop\n\t"
+- "nop");
+-#endif
++ : : "r" (au1k_wait));
+ }
+
+ static inline void check_wait(void)
+@@ -100,20 +91,17 @@
+ cpu_wait = r4k_wait;
+ printk(" available.\n");
+ break;
+-#ifdef CONFIG_PM
+ case CPU_AU1000:
+ case CPU_AU1100:
+ case CPU_AU1500:
+ case CPU_AU1550:
+- if (au1k_wait_ptr != NULL) {
+- cpu_wait = au1k_wait_ptr;
++ case CPU_AU1200:
++ if (allow_au1k_wait) {
++ cpu_wait = au1k_wait;
+ printk(" available.\n");
+- }
+- else {
++ } else
+ printk(" unavailable.\n");
+- }
+ break;
+-#endif
+ default:
+ printk(" unavailable.\n");
+ break;
+diff -Nur linux-2.4.32-rc1/arch/mips/kernel/head.S linux-2.4.32-rc1.mips/arch/mips/kernel/head.S
+--- linux-2.4.32-rc1/arch/mips/kernel/head.S 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/kernel/head.S 2004-11-22 14:38:23.000000000 +0100
+@@ -43,9 +43,9 @@
+
+ /* Cache Error */
+ LEAF(except_vec2_generic)
++ .set push
+ .set noreorder
+ .set noat
+- .set mips0
+ /*
+ * This is a very bad place to be. Our cache error
+ * detection has triggered. If we have write-back data
+@@ -64,10 +64,9 @@
+
+ j cache_parity_error
+ nop
++ .set pop
+ END(except_vec2_generic)
+
+- .set at
+-
+ /*
+ * Special interrupt vector for embedded MIPS. This is a
+ * dedicated interrupt vector which reduces interrupt processing
+@@ -76,8 +75,11 @@
+ * size!
+ */
+ NESTED(except_vec4, 0, sp)
++ .set push
++ .set noreorder
+ 1: j 1b /* Dummy, will be replaced */
+ nop
++ .set pop
+ END(except_vec4)
+
+ /*
+@@ -87,8 +89,11 @@
+ * unconditional jump to this vector.
+ */
+ NESTED(except_vec_ejtag_debug, 0, sp)
++ .set push
++ .set noreorder
+ j ejtag_debug_handler
+ nop
++ .set pop
+ END(except_vec_ejtag_debug)
+
+ __FINIT
+@@ -97,6 +102,7 @@
+ * EJTAG debug exception handler.
+ */
+ NESTED(ejtag_debug_handler, PT_SIZE, sp)
++ .set push
+ .set noat
+ .set noreorder
+ mtc0 k0, CP0_DESAVE
+@@ -120,7 +126,7 @@
+ deret
+ .set mips0
+ nop
+- .set at
++ .set pop
+ END(ejtag_debug_handler)
+
+ __INIT
+@@ -132,13 +138,17 @@
+ * unconditional jump to this vector.
+ */
+ NESTED(except_vec_nmi, 0, sp)
++ .set push
++ .set noreorder
+ j nmi_handler
+ nop
++ .set pop
+ END(except_vec_nmi)
+
+ __FINIT
+
+ NESTED(nmi_handler, PT_SIZE, sp)
++ .set push
+ .set noat
+ .set noreorder
+ .set mips3
+@@ -147,8 +157,7 @@
+ move a0, sp
+ RESTORE_ALL
+ eret
+- .set at
+- .set mips0
++ .set pop
+ END(nmi_handler)
+
+ __INIT
+@@ -157,7 +166,20 @@
+ * Kernel entry point
+ */
+ NESTED(kernel_entry, 16, sp)
++ .set push
++ /*
++ * For the moment disable interrupts and mark the kernel mode.
++ * A full initialization of the CPU's status register is done
++ * later in per_cpu_trap_init().
++ */
++ mfc0 t0, CP0_STATUS
++ or t0, ST0_CU0|0x1f
++ xor t0, 0x1f
++ mtc0 t0, CP0_STATUS
++
+ .set noreorder
++ sll zero,3 # ehb
++ .set reorder
+
+ /*
+ * The firmware/bootloader passes argc/argp/envp
+@@ -170,8 +192,8 @@
+ la t1, (_end - 4)
+ 1:
+ addiu t0, 4
++ sw zero, (t0)
+ bne t0, t1, 1b
+- sw zero, (t0)
+
+ /*
+ * Stack for kernel and init, current variable
+@@ -182,7 +204,7 @@
+ sw t0, kernelsp
+
+ jal init_arch
+- nop
++ .set pop
+ END(kernel_entry)
+
+
+@@ -193,17 +215,26 @@
+ * function after setting up the stack and gp registers.
+ */
+ LEAF(smp_bootstrap)
+- .set push
+- .set noreorder
+- mtc0 zero, CP0_WIRED
+- CLI
++ .set push
++ /*
++ * For the moment disable interrupts and bootstrap exception
++ * vectors and mark the kernel mode. A full initialization of
++ * the CPU's status register is done later in
++ * per_cpu_trap_init().
++ */
+ mfc0 t0, CP0_STATUS
+- li t1, ~(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX|ST0_UX)
+- and t0, t1
+- or t0, (ST0_CU0);
++ or t0, ST0_CU0|ST0_BEV|0x1f
++ xor t0, ST0_BEV|0x1f
++ mtc0 t0, CP0_STATUS
++
++ .set noreorder
++ sll zero,3 # ehb
++ .set reorder
++
++ mtc0 zero, CP0_WIRED
++
+ jal start_secondary
+- mtc0 t0, CP0_STATUS
+- .set pop
++ .set pop
+ END(smp_bootstrap)
+ #endif
+
+diff -Nur linux-2.4.32-rc1/arch/mips/kernel/process.c linux-2.4.32-rc1.mips/arch/mips/kernel/process.c
+--- linux-2.4.32-rc1/arch/mips/kernel/process.c 2003-08-25 13:44:40.000000000 +0200
++++ linux-2.4.32-rc1.mips/arch/mips/kernel/process.c 2005-04-14 12:41:44.000000000 +0200
+@@ -128,6 +128,26 @@
+ return 1;
+ }
+
++void dump_regs(elf_greg_t *gp, struct pt_regs *regs)
++{
++ int i;
++
++ for (i = 0; i < EF_REG0; i++)
++ gp[i] = 0;
++ gp[EF_REG0] = 0;
++ for (i = 1; i <= 31; i++)
++ gp[EF_REG0 + i] = regs->regs[i];
++ gp[EF_REG26] = 0;
++ gp[EF_REG27] = 0;
++ gp[EF_LO] = regs->lo;
++ gp[EF_HI] = regs->hi;
++ gp[EF_CP0_EPC] = regs->cp0_epc;
++ gp[EF_CP0_BADVADDR] = regs->cp0_badvaddr;
++ gp[EF_CP0_STATUS] = regs->cp0_status;
++ gp[EF_CP0_CAUSE] = regs->cp0_cause;
++ gp[EF_UNUSED0] = 0;
++}
++
+ /*
+ * Create a kernel thread
+ */
+diff -Nur linux-2.4.32-rc1/arch/mips/kernel/scall_o32.S linux-2.4.32-rc1.mips/arch/mips/kernel/scall_o32.S
+--- linux-2.4.32-rc1/arch/mips/kernel/scall_o32.S 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/kernel/scall_o32.S 2005-02-07 22:21:53.000000000 +0100
+@@ -121,15 +121,14 @@
+
+ trace_a_syscall:
+ SAVE_STATIC
+- sw t2, PT_R1(sp)
++ move s0, t2
+ jal syscall_trace
+- lw t2, PT_R1(sp)
+
+ lw a0, PT_R4(sp) # Restore argument registers
+ lw a1, PT_R5(sp)
+ lw a2, PT_R6(sp)
+ lw a3, PT_R7(sp)
+- jalr t2
++ jalr s0
+
+ li t0, -EMAXERRNO - 1 # error?
+ sltu t0, t0, v0
+diff -Nur linux-2.4.32-rc1/arch/mips/kernel/setup.c linux-2.4.32-rc1.mips/arch/mips/kernel/setup.c
+--- linux-2.4.32-rc1/arch/mips/kernel/setup.c 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/kernel/setup.c 2005-01-13 22:15:57.000000000 +0100
+@@ -5,7 +5,7 @@
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Copyright (C) 1995 Waldorf Electronics
+- * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001 Ralf Baechle
++ * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 01, 05 Ralf Baechle
+ * Copyright (C) 1996 Stoned Elipot
+ * Copyright (C) 2000, 2001, 2002 Maciej W. Rozycki
+ */
+@@ -71,6 +71,8 @@
+ extern struct rtc_ops no_rtc_ops;
+ struct rtc_ops *rtc_ops;
+
++EXPORT_SYMBOL(rtc_ops);
++
+ #ifdef CONFIG_PC_KEYB
+ struct kbd_ops *kbd_ops;
+ #endif
+@@ -132,10 +134,6 @@
+ */
+ load_mmu();
+
+- /* Disable coprocessors and set FPU for 16/32 FPR register model */
+- clear_c0_status(ST0_CU1|ST0_CU2|ST0_CU3|ST0_KX|ST0_SX|ST0_FR);
+- set_c0_status(ST0_CU0);
+-
+ start_kernel();
+ }
+
+diff -Nur linux-2.4.32-rc1/arch/mips/kernel/traps.c linux-2.4.32-rc1.mips/arch/mips/kernel/traps.c
+--- linux-2.4.32-rc1/arch/mips/kernel/traps.c 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/kernel/traps.c 2005-04-12 22:25:34.000000000 +0200
+@@ -452,9 +452,10 @@
+ }
+ ll_task = current;
+
++ compute_return_epc(regs);
++
+ regs->regs[(opcode & RT) >> 16] = value;
+
+- compute_return_epc(regs);
+ return;
+
+ sig:
+@@ -485,8 +486,8 @@
+ goto sig;
+ }
+ if (ll_bit == 0 || ll_task != current) {
+- regs->regs[reg] = 0;
+ compute_return_epc(regs);
++ regs->regs[reg] = 0;
+ return;
+ }
+
+@@ -495,9 +496,9 @@
+ goto sig;
+ }
+
++ compute_return_epc(regs);
+ regs->regs[reg] = 1;
+
+- compute_return_epc(regs);
+ return;
+
+ sig:
+@@ -887,12 +888,18 @@
+ void __init per_cpu_trap_init(void)
+ {
+ unsigned int cpu = smp_processor_id();
++ unsigned int status_set = ST0_CU0;
+
+- /* Some firmware leaves the BEV flag set, clear it. */
+- clear_c0_status(ST0_CU3|ST0_CU2|ST0_CU1|ST0_BEV|ST0_KX|ST0_SX|ST0_UX);
+-
++ /*
++ * Disable coprocessors and 64-bit addressing and set FPU for
++ * the 16/32 FPR register model. Reset the BEV flag that some
++ * firmware may have left set and the TS bit (for IP27). Set
++ * XX for ISA IV code to work.
++ */
+ if (current_cpu_data.isa_level == MIPS_CPU_ISA_IV)
+- set_c0_status(ST0_XX);
++ status_set |= ST0_XX;
++ change_c0_status(ST0_CU|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX,
++ status_set);
+
+ /*
+ * Some MIPS CPUs have a dedicated interrupt vector which reduces the
+@@ -902,7 +909,7 @@
+ set_c0_cause(CAUSEF_IV);
+
+ cpu_data[cpu].asid_cache = ASID_FIRST_VERSION;
+- write_c0_context(cpu << 23);
++ TLBMISS_HANDLER_SETUP();
+
+ atomic_inc(&init_mm.mm_count);
+ current->active_mm = &init_mm;
+@@ -918,8 +925,6 @@
+ extern char except_vec4;
+ unsigned long i;
+
+- per_cpu_trap_init();
+-
+ /* Copy the generic exception handler code to it's final destination. */
+ memcpy((void *)(KSEG0 + 0x80), &except_vec1_generic, 0x80);
+
+@@ -1020,10 +1025,5 @@
+
+ flush_icache_range(KSEG0, KSEG0 + 0x400);
+
+- atomic_inc(&init_mm.mm_count); /* XXX UP? */
+- current->active_mm = &init_mm;
+-
+- /* XXX Must be done for all CPUs */
+- current_cpu_data.asid_cache = ASID_FIRST_VERSION;
+- TLBMISS_HANDLER_SETUP();
++ per_cpu_trap_init();
+ }
+diff -Nur linux-2.4.32-rc1/arch/mips/lib/rtc-no.c linux-2.4.32-rc1.mips/arch/mips/lib/rtc-no.c
+--- linux-2.4.32-rc1/arch/mips/lib/rtc-no.c 2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/lib/rtc-no.c 2005-01-13 22:15:57.000000000 +0100
+@@ -6,10 +6,9 @@
+ * Stub RTC routines to keep Linux from crashing on machine which don't
+ * have a RTC chip.
+ *
+- * Copyright (C) 1998, 2001 by Ralf Baechle
++ * Copyright (C) 1998, 2001, 2005 by Ralf Baechle
+ */
+ #include <linux/kernel.h>
+-#include <linux/module.h>
+ #include <linux/mc146818rtc.h>
+
+ static unsigned int shouldnt_happen(void)
+@@ -29,5 +28,3 @@
+ .rtc_write_data = (void *) &shouldnt_happen,
+ .rtc_bcd_mode = (void *) &shouldnt_happen
+ };
+-
+-EXPORT_SYMBOL(rtc_ops);
+diff -Nur linux-2.4.32-rc1/arch/mips/lib/rtc-std.c linux-2.4.32-rc1.mips/arch/mips/lib/rtc-std.c
+--- linux-2.4.32-rc1/arch/mips/lib/rtc-std.c 2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/lib/rtc-std.c 2005-01-13 22:15:57.000000000 +0100
+@@ -5,9 +5,8 @@
+ *
+ * RTC routines for PC style attached Dallas chip.
+ *
+- * Copyright (C) 1998, 2001 by Ralf Baechle
++ * Copyright (C) 1998, 2001, 05 by Ralf Baechle
+ */
+-#include <linux/module.h>
+ #include <linux/mc146818rtc.h>
+ #include <asm/io.h>
+
+@@ -33,5 +32,3 @@
+ &std_rtc_write_data,
+ &std_rtc_bcd_mode
+ };
+-
+-EXPORT_SYMBOL(rtc_ops);
+diff -Nur linux-2.4.32-rc1/arch/mips/Makefile linux-2.4.32-rc1.mips/arch/mips/Makefile
+--- linux-2.4.32-rc1/arch/mips/Makefile 2005-01-19 15:09:26.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/Makefile 2005-01-30 09:01:26.000000000 +0100
+@@ -211,7 +211,7 @@
+ endif
+
+ #
+-# Au1000 (Alchemy Semi PB1000) eval board
++# Au1x AMD Alchemy eval boards
+ #
+ ifdef CONFIG_MIPS_PB1000
+ LIBS += arch/mips/au1000/pb1000/pb1000.o \
+@@ -220,9 +220,6 @@
+ LOADADDR := 0x80100000
+ endif
+
+-#
+-# Au1100 (Alchemy Semi PB1100) eval board
+-#
+ ifdef CONFIG_MIPS_PB1100
+ LIBS += arch/mips/au1000/pb1100/pb1100.o \
+ arch/mips/au1000/common/au1000.o
+@@ -230,9 +227,6 @@
+ LOADADDR += 0x80100000
+ endif
+
+-#
+-# Au1500 (Alchemy Semi PB1500) eval board
+-#
+ ifdef CONFIG_MIPS_PB1500
+ LIBS += arch/mips/au1000/pb1500/pb1500.o \
+ arch/mips/au1000/common/au1000.o
+@@ -240,9 +234,6 @@
+ LOADADDR := 0x80100000
+ endif
+
+-#
+-# Au1x00 (AMD/Alchemy) eval boards
+-#
+ ifdef CONFIG_MIPS_DB1000
+ LIBS += arch/mips/au1000/db1x00/db1x00.o \
+ arch/mips/au1000/common/au1000.o
+@@ -313,6 +304,27 @@
+ LOADADDR += 0x80100000
+ endif
+
++ifdef CONFIG_MIPS_PB1200
++LIBS += arch/mips/au1000/pb1200/pb1200.o \
++ arch/mips/au1000/common/au1000.o
++SUBDIRS += arch/mips/au1000/pb1200 arch/mips/au1000/common
++LOADADDR += 0x80100000
++endif
++
++ifdef CONFIG_MIPS_DB1200
++LIBS += arch/mips/au1000/pb1200/pb1200.o \
++ arch/mips/au1000/common/au1000.o
++SUBDIRS += arch/mips/au1000/pb1200 arch/mips/au1000/common
++LOADADDR += 0x80100000
++endif
++
++ifdef CONFIG_MIPS_FICMMP
++LIBS += arch/mips/au1000/ficmmp/ficmmp.o \
++ arch/mips/au1000/common/au1000.o
++SUBDIRS += arch/mips/au1000/ficmmp arch/mips/au1000/common
++LOADADDR += 0x80100000
++endif
++
+
+ #
+ # Cogent CSB250
+diff -Nur linux-2.4.32-rc1/arch/mips/mm/cerr-sb1.c linux-2.4.32-rc1.mips/arch/mips/mm/cerr-sb1.c
+--- linux-2.4.32-rc1/arch/mips/mm/cerr-sb1.c 2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/mm/cerr-sb1.c 2004-12-13 18:37:23.000000000 +0100
+@@ -252,14 +252,14 @@
+
+ /* Masks to select bits for Hamming parity, mask_72_64[i] for bit[i] */
+ static const uint64_t mask_72_64[8] = {
+- 0x0738C808099264FFL,
+- 0x38C808099264FF07L,
+- 0xC808099264FF0738L,
+- 0x08099264FF0738C8L,
+- 0x099264FF0738C808L,
+- 0x9264FF0738C80809L,
+- 0x64FF0738C8080992L,
+- 0xFF0738C808099264L
++ 0x0738C808099264FFULL,
++ 0x38C808099264FF07ULL,
++ 0xC808099264FF0738ULL,
++ 0x08099264FF0738C8ULL,
++ 0x099264FF0738C808ULL,
++ 0x9264FF0738C80809ULL,
++ 0x64FF0738C8080992ULL,
++ 0xFF0738C808099264ULL
+ };
+
+ /* Calculate the parity on a range of bits */
+@@ -331,9 +331,9 @@
+ ((lru >> 4) & 0x3),
+ ((lru >> 6) & 0x3));
+ }
+- va = (taglo & 0xC0000FFFFFFFE000) | addr;
++ va = (taglo & 0xC0000FFFFFFFE000ULL) | addr;
+ if ((taglo & (1 << 31)) && (((taglo >> 62) & 0x3) == 3))
+- va |= 0x3FFFF00000000000;
++ va |= 0x3FFFF00000000000ULL;
+ valid = ((taghi >> 29) & 1);
+ if (valid) {
+ tlo_tmp = taglo & 0xfff3ff;
+@@ -474,7 +474,7 @@
+ : "r" ((way << 13) | addr));
+
+ taglo = ((unsigned long long)taglohi << 32) | taglolo;
+- pa = (taglo & 0xFFFFFFE000) | addr;
++ pa = (taglo & 0xFFFFFFE000ULL) | addr;
+ if (way == 0) {
+ lru = (taghi >> 14) & 0xff;
+ prom_printf("[Bank %d Set 0x%02x] LRU > %d %d %d %d > MRU\n",
+diff -Nur linux-2.4.32-rc1/arch/mips/mm/c-r4k.c linux-2.4.32-rc1.mips/arch/mips/mm/c-r4k.c
+--- linux-2.4.32-rc1/arch/mips/mm/c-r4k.c 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/mm/c-r4k.c 2005-02-06 22:55:42.000000000 +0100
+@@ -867,9 +867,16 @@
+ * normally they'd suffer from aliases but magic in the hardware deals
+ * with that for us so we don't need to take care ourselves.
+ */
+- if (c->cputype != CPU_R10000 && c->cputype != CPU_R12000)
+- if (c->dcache.waysize > PAGE_SIZE)
+- c->dcache.flags |= MIPS_CACHE_ALIASES;
++ switch (c->cputype) {
++ case CPU_R10000:
++ case CPU_R12000:
++ break;
++ case CPU_24K:
++ if (!(read_c0_config7() & (1 << 16)))
++ default:
++ if (c->dcache.waysize > PAGE_SIZE)
++ c->dcache.flags |= MIPS_CACHE_ALIASES;
++ }
+
+ switch (c->cputype) {
+ case CPU_20KC:
+@@ -1069,9 +1076,6 @@
+ probe_pcache();
+ setup_scache();
+
+- if (c->dcache.sets * c->dcache.ways > PAGE_SIZE)
+- c->dcache.flags |= MIPS_CACHE_ALIASES;
+-
+ r4k_blast_dcache_page_setup();
+ r4k_blast_dcache_page_indexed_setup();
+ r4k_blast_dcache_setup();
+diff -Nur linux-2.4.32-rc1/arch/mips/mm/tlbex-mips32.S linux-2.4.32-rc1.mips/arch/mips/mm/tlbex-mips32.S
+--- linux-2.4.32-rc1/arch/mips/mm/tlbex-mips32.S 2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/mm/tlbex-mips32.S 2004-11-29 00:33:15.000000000 +0100
+@@ -196,7 +196,7 @@
+ .set noat; \
+ SAVE_ALL; \
+ mfc0 a2, CP0_BADVADDR; \
+- STI; \
++ KMODE; \
+ .set at; \
+ move a0, sp; \
+ jal do_page_fault; \
+diff -Nur linux-2.4.32-rc1/arch/mips/mm/tlbex-r4k.S linux-2.4.32-rc1.mips/arch/mips/mm/tlbex-r4k.S
+--- linux-2.4.32-rc1/arch/mips/mm/tlbex-r4k.S 2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/mm/tlbex-r4k.S 2005-06-06 16:46:22.000000000 +0200
+@@ -184,13 +184,10 @@
+ P_MTC0 k0, CP0_ENTRYLO0 # load it
+ PTE_SRL k1, k1, 6 # convert to entrylo1
+ P_MTC0 k1, CP0_ENTRYLO1 # load it
+- b 1f
+- rm9000_tlb_hazard
++ mtc0_tlbw_hazard
+ tlbwr # write random tlb entry
+-1:
+- nop
+- rm9000_tlb_hazard
+- eret # return from trap
++ tlbw_eret_hazard
++ eret
+ END(except_vec0_r4000)
+
+ /* TLB refill, EXL == 0, R4600 version */
+@@ -468,13 +465,9 @@
+ PTE_PRESENT(k0, k1, nopage_tlbl)
+ PTE_MAKEVALID(k0, k1)
+ PTE_RELOAD(k1, k0)
+- rm9000_tlb_hazard
+- nop
+- b 1f
+- tlbwi
+-1:
+- nop
+- rm9000_tlb_hazard
++ mtc0_tlbw_hazard
++ tlbwi
++ tlbw_eret_hazard
+ .set mips3
+ eret
+ .set mips0
+@@ -496,13 +489,9 @@
+ PTE_WRITABLE(k0, k1, nopage_tlbs)
+ PTE_MAKEWRITE(k0, k1)
+ PTE_RELOAD(k1, k0)
+- rm9000_tlb_hazard
+- nop
+- b 1f
+- tlbwi
+-1:
+- nop
+- rm9000_tlb_hazard
++ mtc0_tlbw_hazard
++ tlbwi
++ tlbw_eret_hazard
+ .set mips3
+ eret
+ .set mips0
+@@ -529,13 +518,9 @@
+
+ /* Now reload the entry into the tlb. */
+ PTE_RELOAD(k1, k0)
+- rm9000_tlb_hazard
+- nop
+- b 1f
+- tlbwi
+-1:
+- rm9000_tlb_hazard
+- nop
++ mtc0_tlbw_hazard
++ tlbwi
++ tlbw_eret_hazard
+ .set mips3
+ eret
+ .set mips0
+diff -Nur linux-2.4.32-rc1/arch/mips/mm/tlb-r4k.c linux-2.4.32-rc1.mips/arch/mips/mm/tlb-r4k.c
+--- linux-2.4.32-rc1/arch/mips/mm/tlb-r4k.c 2005-01-19 15:09:29.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips/mm/tlb-r4k.c 2004-11-25 23:18:38.000000000 +0100
+@@ -3,17 +3,12 @@
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+- * r4xx0.c: R4000 processor variant specific MMU/Cache routines.
+- *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle ralf@gnu.org
+- *
+- * To do:
+- *
+- * - this code is a overbloated pig
+- * - many of the bug workarounds are not efficient at all, but at
+- * least they are functional ...
++ * Carsten Langgaard, carstenl@mips.com
++ * Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved.
+ */
++#include <linux/config.h>
+ #include <linux/init.h>
+ #include <linux/sched.h>
+ #include <linux/mm.h>
+@@ -25,9 +20,6 @@
+ #include <asm/pgtable.h>
+ #include <asm/system.h>
+
+-#undef DEBUG_TLB
+-#undef DEBUG_TLBUPDATE
+-
+ extern char except_vec0_nevada, except_vec0_r4000, except_vec0_r4600;
+
+ /* CP0 hazard avoidance. */
+@@ -41,33 +33,23 @@
+ unsigned long old_ctx;
+ int entry;
+
+-#ifdef DEBUG_TLB
+- printk("[tlball]");
+-#endif
+-
+ local_irq_save(flags);
+ /* Save old context and create impossible VPN2 value */
+ old_ctx = read_c0_entryhi();
+ write_c0_entrylo0(0);
+ write_c0_entrylo1(0);
+- BARRIER;
+
+ entry = read_c0_wired();
+
+ /* Blast 'em all away. */
+ while (entry < current_cpu_data.tlbsize) {
+- /*
+- * Make sure all entries differ. If they're not different
+- * MIPS32 will take revenge ...
+- */
+ write_c0_entryhi(KSEG0 + entry*0x2000);
+ write_c0_index(entry);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_write_indexed();
+- BARRIER;
+ entry++;
+ }
+- BARRIER;
++ tlbw_use_hazard();
+ write_c0_entryhi(old_ctx);
+ local_irq_restore(flags);
+ }
+@@ -76,12 +58,8 @@
+ {
+ int cpu = smp_processor_id();
+
+- if (cpu_context(cpu, mm) != 0) {
+-#ifdef DEBUG_TLB
+- printk("[tlbmm<%d>]", cpu_context(cpu, mm));
+-#endif
++ if (cpu_context(cpu, mm) != 0)
+ drop_mmu_context(mm,cpu);
+- }
+ }
+
+ void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+@@ -93,10 +71,6 @@
+ unsigned long flags;
+ int size;
+
+-#ifdef DEBUG_TLB
+- printk("[tlbrange<%02x,%08lx,%08lx>]",
+- cpu_asid(cpu, mm), start, end);
+-#endif
+ local_irq_save(flags);
+ size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ size = (size + 1) >> 1;
+@@ -112,7 +86,7 @@
+
+ write_c0_entryhi(start | newpid);
+ start += (PAGE_SIZE << 1);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_probe();
+ BARRIER;
+ idx = read_c0_index();
+@@ -122,10 +96,10 @@
+ continue;
+ /* Make sure all entries differ. */
+ write_c0_entryhi(KSEG0 + idx*0x2000);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_write_indexed();
+- BARRIER;
+ }
++ tlbw_use_hazard();
+ write_c0_entryhi(oldpid);
+ } else {
+ drop_mmu_context(mm, cpu);
+@@ -138,34 +112,30 @@
+ {
+ int cpu = smp_processor_id();
+
+- if (!vma || cpu_context(cpu, vma->vm_mm) != 0) {
++ if (cpu_context(cpu, vma->vm_mm) != 0) {
+ unsigned long flags;
+- int oldpid, newpid, idx;
++ unsigned long oldpid, newpid, idx;
+
+-#ifdef DEBUG_TLB
+- printk("[tlbpage<%d,%08lx>]", cpu_context(cpu, vma->vm_mm),
+- page);
+-#endif
+ newpid = cpu_asid(cpu, vma->vm_mm);
+ page &= (PAGE_MASK << 1);
+ local_irq_save(flags);
+ oldpid = read_c0_entryhi();
+ write_c0_entryhi(page | newpid);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_probe();
+ BARRIER;
+ idx = read_c0_index();
+ write_c0_entrylo0(0);
+ write_c0_entrylo1(0);
+- if(idx < 0)
++ if (idx < 0)
+ goto finish;
+ /* Make sure all entries differ. */
+ write_c0_entryhi(KSEG0+idx*0x2000);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_write_indexed();
++ tlbw_use_hazard();
+
+ finish:
+- BARRIER;
+ write_c0_entryhi(oldpid);
+ local_irq_restore(flags);
+ }
+@@ -185,7 +155,7 @@
+
+ local_irq_save(flags);
+ write_c0_entryhi(page);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_probe();
+ BARRIER;
+ idx = read_c0_index();
+@@ -194,18 +164,19 @@
+ if (idx >= 0) {
+ /* Make sure all entries differ. */
+ write_c0_entryhi(KSEG0+idx*0x2000);
++ mtc0_tlbw_hazard();
+ tlb_write_indexed();
++ tlbw_use_hazard();
+ }
+- BARRIER;
+ write_c0_entryhi(oldpid);
++
+ local_irq_restore(flags);
+ }
+
+ EXPORT_SYMBOL(local_flush_tlb_one);
+
+-/* We will need multiple versions of update_mmu_cache(), one that just
+- * updates the TLB with the new pte(s), and another which also checks
+- * for the R4k "end of page" hardware bug and does the needy.
++/*
++ * Updates the TLB with the new pte(s).
+ */
+ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
+ {
+@@ -223,25 +194,16 @@
+
+ pid = read_c0_entryhi() & ASID_MASK;
+
+-#ifdef DEBUG_TLB
+- if ((pid != cpu_asid(cpu, vma->vm_mm)) ||
+- (cpu_context(vma->vm_mm) == 0)) {
+- printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d "
+- "tlbpid=%d\n", (int) (cpu_asid(cpu, vma->vm_mm)), pid);
+- }
+-#endif
+-
+ local_irq_save(flags);
+ address &= (PAGE_MASK << 1);
+ write_c0_entryhi(address | pid);
+ pgdp = pgd_offset(vma->vm_mm, address);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_probe();
+ BARRIER;
+ pmdp = pmd_offset(pgdp, address);
+ idx = read_c0_index();
+ ptep = pte_offset(pmdp, address);
+- BARRIER;
+ #if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32)
+ write_c0_entrylo0(ptep->pte_high);
+ ptep++;
+@@ -251,15 +213,13 @@
+ write_c0_entrylo1(pte_val(*ptep) >> 6);
+ #endif
+ write_c0_entryhi(address | pid);
+- BARRIER;
+- if (idx < 0) {
++ mtc0_tlbw_hazard();
++ if (idx < 0)
+ tlb_write_random();
+- } else {
++ else
+ tlb_write_indexed();
+- }
+- BARRIER;
++ tlbw_use_hazard();
+ write_c0_entryhi(pid);
+- BARRIER;
+ local_irq_restore(flags);
+ }
+
+@@ -279,24 +239,26 @@
+ asid = read_c0_entryhi() & ASID_MASK;
+ write_c0_entryhi(address | asid);
+ pgdp = pgd_offset(vma->vm_mm, address);
++ mtc0_tlbw_hazard();
+ tlb_probe();
++ BARRIER;
+ pmdp = pmd_offset(pgdp, address);
+ idx = read_c0_index();
+ ptep = pte_offset(pmdp, address);
+ write_c0_entrylo0(pte_val(*ptep++) >> 6);
+ write_c0_entrylo1(pte_val(*ptep) >> 6);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ if (idx < 0)
+ tlb_write_random();
+ else
+ tlb_write_indexed();
+- BARRIER;
++ tlbw_use_hazard();
+ local_irq_restore(flags);
+ }
+ #endif
+
+ void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+- unsigned long entryhi, unsigned long pagemask)
++ unsigned long entryhi, unsigned long pagemask)
+ {
+ unsigned long flags;
+ unsigned long wired;
+@@ -315,9 +277,9 @@
+ write_c0_entryhi(entryhi);
+ write_c0_entrylo0(entrylo0);
+ write_c0_entrylo1(entrylo1);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_write_indexed();
+- BARRIER;
++ tlbw_use_hazard();
+
+ write_c0_entryhi(old_ctx);
+ BARRIER;
+@@ -355,17 +317,15 @@
+ }
+
+ write_c0_index(temp_tlb_entry);
+- BARRIER;
+ write_c0_pagemask(pagemask);
+ write_c0_entryhi(entryhi);
+ write_c0_entrylo0(entrylo0);
+ write_c0_entrylo1(entrylo1);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_write_indexed();
+- BARRIER;
++ tlbw_use_hazard();
+
+ write_c0_entryhi(old_ctx);
+- BARRIER;
+ write_c0_pagemask(old_pagemask);
+ out:
+ local_irq_restore(flags);
+@@ -375,7 +335,7 @@
+ static void __init probe_tlb(unsigned long config)
+ {
+ struct cpuinfo_mips *c = &current_cpu_data;
+- unsigned int reg;
++ unsigned int config1;
+
+ /*
+ * If this isn't a MIPS32 / MIPS64 compliant CPU. Config 1 register
+@@ -385,16 +345,16 @@
+ if ((c->processor_id & 0xff0000) == PRID_COMP_LEGACY)
+ return;
+
+- reg = read_c0_config1();
++ config1 = read_c0_config1();
+ if (!((config >> 7) & 3))
+ panic("No TLB present");
+
+- c->tlbsize = ((reg >> 25) & 0x3f) + 1;
++ c->tlbsize = ((config1 >> 25) & 0x3f) + 1;
+ }
+
+ void __init r4k_tlb_init(void)
+ {
+- u32 config = read_c0_config();
++ unsigned int config = read_c0_config();
+
+ /*
+ * You should never change this register:
+diff -Nur linux-2.4.32-rc1/arch/mips64/defconfig linux-2.4.32-rc1.mips/arch/mips64/defconfig
+--- linux-2.4.32-rc1/arch/mips64/defconfig 2005-01-19 15:09:30.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/defconfig 2005-03-18 13:13:23.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -470,9 +470,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -658,7 +660,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips64/defconfig-atlas linux-2.4.32-rc1.mips/arch/mips64/defconfig-atlas
+--- linux-2.4.32-rc1/arch/mips64/defconfig-atlas 2005-01-19 15:09:30.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/defconfig-atlas 2005-03-18 13:13:23.000000000 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -232,11 +232,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -314,9 +309,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -474,7 +471,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips64/defconfig-decstation linux-2.4.32-rc1.mips/arch/mips64/defconfig-decstation
+--- linux-2.4.32-rc1/arch/mips64/defconfig-decstation 2005-01-19 15:09:30.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/defconfig-decstation 2005-03-18 13:13:23.000000000 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -224,11 +224,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -307,9 +302,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -477,7 +474,6 @@
+ CONFIG_SERIAL_DEC_CONSOLE=y
+ # CONFIG_DZ is not set
+ CONFIG_ZS=y
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips64/defconfig-ip22 linux-2.4.32-rc1.mips/arch/mips64/defconfig-ip22
+--- linux-2.4.32-rc1/arch/mips64/defconfig-ip22 2005-01-19 15:09:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/defconfig-ip22 2005-03-18 13:13:23.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -235,11 +235,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -319,9 +314,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -488,7 +485,6 @@
+ # CONFIG_SERIAL_TXX9_CONSOLE is not set
+ # CONFIG_TXX927_SERIAL is not set
+ CONFIG_IP22_SERIAL=y
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips64/defconfig-ip27 linux-2.4.32-rc1.mips/arch/mips64/defconfig-ip27
+--- linux-2.4.32-rc1/arch/mips64/defconfig-ip27 2005-01-19 15:09:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/defconfig-ip27 2005-03-18 13:13:23.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -470,9 +470,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -658,7 +660,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips64/defconfig-jaguar linux-2.4.32-rc1.mips/arch/mips64/defconfig-jaguar
+--- linux-2.4.32-rc1/arch/mips64/defconfig-jaguar 2005-01-19 15:09:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/defconfig-jaguar 2005-03-18 13:13:23.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -227,11 +227,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -403,7 +398,6 @@
+ # CONFIG_SERIAL_TXX9 is not set
+ # CONFIG_SERIAL_TXX9_CONSOLE is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips64/defconfig-malta linux-2.4.32-rc1.mips/arch/mips64/defconfig-malta
+--- linux-2.4.32-rc1/arch/mips64/defconfig-malta 2005-01-19 15:09:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/defconfig-malta 2005-04-19 14:19:34.000000000 +0200
+@@ -22,16 +22,19 @@
+ #
+ # CONFIG_ACER_PICA_61 is not set
+ # CONFIG_MIPS_BOSPORUS is not set
++# CONFIG_MIPS_FICMMP is not set
+ # CONFIG_MIPS_MIRAGE is not set
+ # CONFIG_MIPS_DB1000 is not set
+ # CONFIG_MIPS_DB1100 is not set
+ # CONFIG_MIPS_DB1500 is not set
+ # CONFIG_MIPS_DB1550 is not set
++# CONFIG_MIPS_DB1200 is not set
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_PB1200 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -146,9 +149,9 @@
+ CONFIG_BINFMT_ELF=y
+ CONFIG_MIPS32_COMPAT=y
+ CONFIG_MIPS32_O32=y
+-# CONFIG_MIPS32_N32 is not set
++CONFIG_MIPS32_N32=y
+ CONFIG_BINFMT_ELF32=y
+-# CONFIG_BINFMT_MISC is not set
++CONFIG_BINFMT_MISC=y
+ # CONFIG_OOM_KILLER is not set
+ # CONFIG_CMDLINE_BOOL is not set
+
+@@ -235,11 +238,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -271,8 +269,83 @@
+ #
+ # ATA/IDE/MFM/RLL support
+ #
+-# CONFIG_IDE is not set
++CONFIG_IDE=y
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=y
++
++#
++# Please see Documentation/ide.txt for help/info on IDE drives
++#
++# CONFIG_BLK_DEV_HD_IDE is not set
+ # CONFIG_BLK_DEV_HD is not set
++# CONFIG_BLK_DEV_IDE_SATA is not set
++CONFIG_BLK_DEV_IDEDISK=y
++# CONFIG_IDEDISK_MULTI_MODE is not set
++# CONFIG_IDEDISK_STROKE is not set
++# CONFIG_BLK_DEV_IDECS is not set
++# CONFIG_BLK_DEV_DELKIN is not set
++CONFIG_BLK_DEV_IDECD=y
++CONFIG_BLK_DEV_IDETAPE=y
++CONFIG_BLK_DEV_IDEFLOPPY=y
++# CONFIG_BLK_DEV_IDESCSI is not set
++# CONFIG_IDE_TASK_IOCTL is not set
++
++#
++# IDE chipset support/bugfixes
++#
++# CONFIG_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++CONFIG_BLK_DEV_IDEPCI=y
++CONFIG_BLK_DEV_GENERIC=y
++CONFIG_IDEPCI_SHARE_IRQ=y
++CONFIG_BLK_DEV_IDEDMA_PCI=y
++# CONFIG_BLK_DEV_OFFBOARD is not set
++CONFIG_BLK_DEV_IDEDMA_FORCED=y
++CONFIG_IDEDMA_PCI_AUTO=y
++# CONFIG_IDEDMA_ONLYDISK is not set
++CONFIG_BLK_DEV_IDEDMA=y
++# CONFIG_IDEDMA_PCI_WIP is not set
++# CONFIG_BLK_DEV_ADMA100 is not set
++# CONFIG_BLK_DEV_AEC62XX is not set
++# CONFIG_BLK_DEV_ALI15X3 is not set
++# CONFIG_WDC_ALI15X3 is not set
++# CONFIG_BLK_DEV_AMD74XX is not set
++# CONFIG_AMD74XX_OVERRIDE is not set
++# CONFIG_BLK_DEV_ATIIXP is not set
++# CONFIG_BLK_DEV_CMD64X is not set
++# CONFIG_BLK_DEV_TRIFLEX is not set
++# CONFIG_BLK_DEV_CY82C693 is not set
++# CONFIG_BLK_DEV_CS5530 is not set
++# CONFIG_BLK_DEV_HPT34X is not set
++# CONFIG_HPT34X_AUTODMA is not set
++# CONFIG_BLK_DEV_HPT366 is not set
++CONFIG_BLK_DEV_PIIX=y
++# CONFIG_BLK_DEV_NS87415 is not set
++# CONFIG_BLK_DEV_OPTI621 is not set
++# CONFIG_BLK_DEV_PDC202XX_OLD is not set
++# CONFIG_PDC202XX_BURST is not set
++# CONFIG_BLK_DEV_PDC202XX_NEW is not set
++# CONFIG_BLK_DEV_RZ1000 is not set
++# CONFIG_BLK_DEV_SC1200 is not set
++# CONFIG_BLK_DEV_SVWKS is not set
++# CONFIG_BLK_DEV_SIIMAGE is not set
++# CONFIG_BLK_DEV_SIS5513 is not set
++# CONFIG_BLK_DEV_SLC90E66 is not set
++# CONFIG_BLK_DEV_TRM290 is not set
++# CONFIG_BLK_DEV_VIA82CXXX is not set
++# CONFIG_IDE_CHIPSETS is not set
++CONFIG_IDEDMA_AUTO=y
++# CONFIG_IDEDMA_IVB is not set
++# CONFIG_DMA_NONPCI is not set
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++# CONFIG_BLK_DEV_ATARAID_MEDLEY is not set
++# CONFIG_BLK_DEV_ATARAID_SII is not set
+
+ #
+ # SCSI support
+@@ -317,9 +390,11 @@
+ # CONFIG_SCSI_MEGARAID is not set
+ # CONFIG_SCSI_MEGARAID2 is not set
+ # CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_SATA_AHCI is not set
+ # CONFIG_SCSI_SATA_SVW is not set
+ # CONFIG_SCSI_ATA_PIIX is not set
+ # CONFIG_SCSI_SATA_NV is not set
++# CONFIG_SCSI_SATA_QSTOR is not set
+ # CONFIG_SCSI_SATA_PROMISE is not set
+ # CONFIG_SCSI_SATA_SX4 is not set
+ # CONFIG_SCSI_SATA_SIL is not set
+@@ -477,7 +552,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips64/defconfig-ocelotc linux-2.4.32-rc1.mips/arch/mips64/defconfig-ocelotc
+--- linux-2.4.32-rc1/arch/mips64/defconfig-ocelotc 2005-01-19 15:09:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/defconfig-ocelotc 2005-03-18 13:13:23.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -231,11 +231,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -453,7 +448,6 @@
+ # CONFIG_SERIAL_TXX9 is not set
+ # CONFIG_SERIAL_TXX9_CONSOLE is not set
+ # CONFIG_TXX927_SERIAL is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips64/defconfig-sb1250-swarm linux-2.4.32-rc1.mips/arch/mips64/defconfig-sb1250-swarm
+--- linux-2.4.32-rc1/arch/mips64/defconfig-sb1250-swarm 2005-01-19 15:09:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/defconfig-sb1250-swarm 2005-03-18 13:13:23.000000000 +0100
+@@ -30,8 +30,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -90,6 +90,7 @@
+ # CONFIG_SIBYTE_TBPROF is not set
+ CONFIG_SIBYTE_GENBUS_IDE=y
+ CONFIG_SMP_CAPABLE=y
++CONFIG_MIPS_RTC=y
+ # CONFIG_SNI_RM200_PCI is not set
+ # CONFIG_TANBAC_TB0226 is not set
+ # CONFIG_TANBAC_TB0229 is not set
+@@ -253,11 +254,6 @@
+ #
+ # CONFIG_IPX is not set
+ # CONFIG_ATALK is not set
+-
+-#
+-# Appletalk devices
+-#
+-# CONFIG_DEV_APPLETALK is not set
+ # CONFIG_DECNET is not set
+ # CONFIG_BRIDGE is not set
+ # CONFIG_X25 is not set
+@@ -432,7 +428,6 @@
+ CONFIG_SIBYTE_SB1250_DUART=y
+ CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y
+ CONFIG_SERIAL_CONSOLE=y
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ CONFIG_UNIX98_PTYS=y
+ CONFIG_UNIX98_PTY_COUNT=256
+
+diff -Nur linux-2.4.32-rc1/arch/mips64/defconfig-sead linux-2.4.32-rc1.mips/arch/mips64/defconfig-sead
+--- linux-2.4.32-rc1/arch/mips64/defconfig-sead 2005-01-19 15:09:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/defconfig-sead 2005-03-18 13:13:23.000000000 +0100
+@@ -28,8 +28,8 @@
+ # CONFIG_MIPS_PB1000 is not set
+ # CONFIG_MIPS_PB1100 is not set
+ # CONFIG_MIPS_PB1500 is not set
+-# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_PB1550 is not set
++# CONFIG_MIPS_HYDROGEN3 is not set
+ # CONFIG_MIPS_XXS1500 is not set
+ # CONFIG_MIPS_MTX1 is not set
+ # CONFIG_COGENT_CSB250 is not set
+@@ -242,7 +242,6 @@
+ CONFIG_SERIAL_CONSOLE=y
+ # CONFIG_SERIAL_EXTENDED is not set
+ # CONFIG_SERIAL_NONSTANDARD is not set
+-# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+ # CONFIG_UNIX98_PTYS is not set
+
+ #
+diff -Nur linux-2.4.32-rc1/arch/mips64/kernel/binfmt_elfn32.c linux-2.4.32-rc1.mips/arch/mips64/kernel/binfmt_elfn32.c
+--- linux-2.4.32-rc1/arch/mips64/kernel/binfmt_elfn32.c 2003-08-25 13:44:40.000000000 +0200
++++ linux-2.4.32-rc1.mips/arch/mips64/kernel/binfmt_elfn32.c 2005-01-26 03:40:47.000000000 +0100
+@@ -116,4 +116,7 @@
+ #undef MODULE_DESCRIPTION
+ #undef MODULE_AUTHOR
+
++#undef TASK_SIZE
++#define TASK_SIZE TASK_SIZE32
++
+ #include "../../../fs/binfmt_elf.c"
+diff -Nur linux-2.4.32-rc1/arch/mips64/kernel/binfmt_elfo32.c linux-2.4.32-rc1.mips/arch/mips64/kernel/binfmt_elfo32.c
+--- linux-2.4.32-rc1/arch/mips64/kernel/binfmt_elfo32.c 2003-08-25 13:44:40.000000000 +0200
++++ linux-2.4.32-rc1.mips/arch/mips64/kernel/binfmt_elfo32.c 2005-01-26 03:40:47.000000000 +0100
+@@ -137,4 +137,7 @@
+ #undef MODULE_DESCRIPTION
+ #undef MODULE_AUTHOR
+
++#undef TASK_SIZE
++#define TASK_SIZE TASK_SIZE32
++
+ #include "../../../fs/binfmt_elf.c"
+diff -Nur linux-2.4.32-rc1/arch/mips64/kernel/head.S linux-2.4.32-rc1.mips/arch/mips64/kernel/head.S
+--- linux-2.4.32-rc1/arch/mips64/kernel/head.S 2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/kernel/head.S 2004-11-22 14:38:26.000000000 +0100
+@@ -91,6 +91,21 @@
+ __INIT
+
+ NESTED(kernel_entry, 16, sp) # kernel entry point
++ .set push
++ /*
++ * For the moment disable interrupts, mark the kernel mode and
++ * set ST0_KX so that the CPU does not spit fire when using
++ * 64-bit addresses. A full initialization of the CPU's status
++ * register is done later in per_cpu_trap_init().
++ */
++ mfc0 t0, CP0_STATUS
++ or t0, ST0_CU0|ST0_KX|0x1f
++ xor t0, 0x1f
++ mtc0 t0, CP0_STATUS
++
++ .set noreorder
++ sll zero,3 # ehb
++ .set reorder
+
+ ori sp, 0xf # align stack on 16 byte.
+ xori sp, 0xf
+@@ -103,8 +118,6 @@
+
+ ARC64_TWIDDLE_PC
+
+- CLI # disable interrupts
+-
+ /*
+ * The firmware/bootloader passes argc/argp/envp
+ * to us as arguments. But clear bss first because
+@@ -125,6 +138,7 @@
+ dsubu sp, 4*SZREG # init stack pointer
+
+ j init_arch
++ .set pop
+ END(kernel_entry)
+
+ #ifdef CONFIG_SMP
+@@ -133,6 +147,23 @@
+ * function after setting up the stack and gp registers.
+ */
+ NESTED(smp_bootstrap, 16, sp)
++ .set push
++ /*
++ * For the moment disable interrupts and bootstrap exception
++ * vectors, mark the kernel mode and set ST0_KX so that the CPU
++ * does not spit fire when using 64-bit addresses. A full
++ * initialization of the CPU's status register is done later in
++ * per_cpu_trap_init().
++ */
++ mfc0 t0, CP0_STATUS
++ or t0, ST0_CU0|ST0_BEV|ST0_KX|0x1f
++ xor t0, ST0_BEV|0x1f
++ mtc0 t0, CP0_STATUS
++
++ .set noreorder
++ sll zero,3 # ehb
++ .set reorder
++
+ #ifdef CONFIG_SGI_IP27
+ GET_NASID_ASM t1
+ dli t0, KLDIR_OFFSET + (KLI_KERN_VARS * KLDIR_ENT_SIZE) + \
+@@ -146,19 +177,8 @@
+ ARC64_TWIDDLE_PC
+ #endif /* CONFIG_SGI_IP27 */
+
+- CLI
+-
+- /*
+- * For the moment set ST0_KU so the CPU will not spit fire when
+- * executing 64-bit instructions. The full initialization of the
+- * CPU's status register is done later in per_cpu_trap_init().
+- */
+- mfc0 t0, CP0_STATUS
+- or t0, ST0_KX
+- mtc0 t0, CP0_STATUS
+-
+ jal start_secondary # XXX: IP27: cboot
+-
++ .set pop
+ END(smp_bootstrap)
+ #endif /* CONFIG_SMP */
+
+diff -Nur linux-2.4.32-rc1/arch/mips64/kernel/ioctl32.c linux-2.4.32-rc1.mips/arch/mips64/kernel/ioctl32.c
+--- linux-2.4.32-rc1/arch/mips64/kernel/ioctl32.c 2005-01-19 15:09:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/kernel/ioctl32.c 2005-01-26 03:36:17.000000000 +0100
+@@ -2352,7 +2352,7 @@
+ IOCTL32_HANDLER(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout),
+ IOCTL32_DEFAULT(AUTOFS_IOC_EXPIRE),
+ IOCTL32_DEFAULT(AUTOFS_IOC_EXPIRE_MULTI),
+- IOCTL32_DEFAULT(AUTOFS_IOC_PROTSUBVER),
++ IOCTL32_DEFAULT(AUTOFS_IOC_PROTOSUBVER),
+ IOCTL32_DEFAULT(AUTOFS_IOC_ASKREGHOST),
+ IOCTL32_DEFAULT(AUTOFS_IOC_TOGGLEREGHOST),
+ IOCTL32_DEFAULT(AUTOFS_IOC_ASKUMOUNT),
+diff -Nur linux-2.4.32-rc1/arch/mips64/kernel/linux32.c linux-2.4.32-rc1.mips/arch/mips64/kernel/linux32.c
+--- linux-2.4.32-rc1/arch/mips64/kernel/linux32.c 2005-04-04 03:42:19.000000000 +0200
++++ linux-2.4.32-rc1.mips/arch/mips64/kernel/linux32.c 2005-04-22 15:01:00.000000000 +0200
+@@ -1101,6 +1101,7 @@
+ * specially as they have atomicity guarantees and can handle
+ * iovec's natively
+ */
++ inode = file->f_dentry->d_inode;
+ if (inode->i_sock) {
+ int err;
+ err = sock_readv_writev(type, inode, file, iov, count, tot_len);
+@@ -1187,72 +1188,19 @@
+ lseek back to original location. They fail just like lseek does on
+ non-seekable files. */
+
+-asmlinkage ssize_t sys32_pread(unsigned int fd, char * buf,
+- size_t count, u32 unused, u64 a4, u64 a5)
++asmlinkage ssize_t sys32_pread(unsigned int fd, char *buf,
++ size_t count, u32 unused, u64 a4, u64 a5)
+ {
+- ssize_t ret;
+- struct file * file;
+- ssize_t (*read)(struct file *, char *, size_t, loff_t *);
+- loff_t pos;
+-
+- ret = -EBADF;
+- file = fget(fd);
+- if (!file)
+- goto bad_file;
+- if (!(file->f_mode & FMODE_READ))
+- goto out;
+- pos = merge_64(a4, a5);
+- ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
+- file, pos, count);
+- if (ret)
+- goto out;
+- ret = -EINVAL;
+- if (!file->f_op || !(read = file->f_op->read))
+- goto out;
+- if (pos < 0)
+- goto out;
+- ret = read(file, buf, count, &pos);
+- if (ret > 0)
+- dnotify_parent(file->f_dentry, DN_ACCESS);
+-out:
+- fput(file);
+-bad_file:
+- return ret;
++ return sys_pread(fd, buf, count, merge_64(a4, a5));
+ }
+
+ asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char * buf,
+ size_t count, u32 unused, u64 a4, u64 a5)
+ {
+- ssize_t ret;
+- struct file * file;
+- ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+- loff_t pos;
++ return sys_pwrite(fd, buf, count, merge_64(a4, a5));
++}
+
+- ret = -EBADF;
+- file = fget(fd);
+- if (!file)
+- goto bad_file;
+- if (!(file->f_mode & FMODE_WRITE))
+- goto out;
+- pos = merge_64(a4, a5);
+- ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
+- file, pos, count);
+- if (ret)
+- goto out;
+- ret = -EINVAL;
+- if (!file->f_op || !(write = file->f_op->write))
+- goto out;
+- if (pos < 0)
+- goto out;
+
+- ret = write(file, buf, count, &pos);
+- if (ret > 0)
+- dnotify_parent(file->f_dentry, DN_MODIFY);
+-out:
+- fput(file);
+-bad_file:
+- return ret;
+-}
+ /*
+ * Ooo, nasty. We need here to frob 32-bit unsigned longs to
+ * 64-bit unsigned longs.
+diff -Nur linux-2.4.32-rc1/arch/mips64/kernel/process.c linux-2.4.32-rc1.mips/arch/mips64/kernel/process.c
+--- linux-2.4.32-rc1/arch/mips64/kernel/process.c 2003-08-25 13:44:40.000000000 +0200
++++ linux-2.4.32-rc1.mips/arch/mips64/kernel/process.c 2005-04-14 12:41:44.000000000 +0200
+@@ -125,6 +125,25 @@
+ return 1;
+ }
+
++void dump_regs(elf_greg_t *gp, struct pt_regs *regs)
++{
++ int i;
++
++ for (i = 0; i < EF_REG0; i++)
++ gp[i] = 0;
++ gp[EF_REG0] = 0;
++ for (i = 1; i <= 31; i++)
++ gp[EF_REG0 + i] = regs->regs[i];
++ gp[EF_REG26] = 0;
++ gp[EF_REG27] = 0;
++ gp[EF_LO] = regs->lo;
++ gp[EF_HI] = regs->hi;
++ gp[EF_CP0_EPC] = regs->cp0_epc;
++ gp[EF_CP0_BADVADDR] = regs->cp0_badvaddr;
++ gp[EF_CP0_STATUS] = regs->cp0_status;
++ gp[EF_CP0_CAUSE] = regs->cp0_cause;
++}
++
+ /*
+ * Create a kernel thread
+ */
+diff -Nur linux-2.4.32-rc1/arch/mips64/kernel/scall_64.S linux-2.4.32-rc1.mips/arch/mips64/kernel/scall_64.S
+--- linux-2.4.32-rc1/arch/mips64/kernel/scall_64.S 2005-01-19 15:09:32.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/kernel/scall_64.S 2005-02-07 22:21:54.000000000 +0100
+@@ -102,15 +102,14 @@
+
+ trace_a_syscall:
+ SAVE_STATIC
+- sd t2,PT_R1(sp)
++ move s0, t2
+ jal syscall_trace
+- ld t2,PT_R1(sp)
+
+ ld a0, PT_R4(sp) # Restore argument registers
+ ld a1, PT_R5(sp)
+ ld a2, PT_R6(sp)
+ ld a3, PT_R7(sp)
+- jalr t2
++ jalr s0
+
+ li t0, -EMAXERRNO - 1 # error?
+ sltu t0, t0, v0
+diff -Nur linux-2.4.32-rc1/arch/mips64/kernel/scall_n32.S linux-2.4.32-rc1.mips/arch/mips64/kernel/scall_n32.S
+--- linux-2.4.32-rc1/arch/mips64/kernel/scall_n32.S 2005-01-19 15:09:32.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/kernel/scall_n32.S 2005-02-07 22:21:54.000000000 +0100
+@@ -106,15 +106,14 @@
+
+ trace_a_syscall:
+ SAVE_STATIC
+- sd t2,PT_R1(sp)
++ move s0, t2
+ jal syscall_trace
+- ld t2,PT_R1(sp)
+
+ ld a0, PT_R4(sp) # Restore argument registers
+ ld a1, PT_R5(sp)
+ ld a2, PT_R6(sp)
+ ld a3, PT_R7(sp)
+- jalr t2
++ jalr s0
+
+ li t0, -EMAXERRNO - 1 # error?
+ sltu t0, t0, v0
+diff -Nur linux-2.4.32-rc1/arch/mips64/kernel/scall_o32.S linux-2.4.32-rc1.mips/arch/mips64/kernel/scall_o32.S
+--- linux-2.4.32-rc1/arch/mips64/kernel/scall_o32.S 2005-01-19 15:09:32.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/kernel/scall_o32.S 2005-02-14 04:52:57.000000000 +0100
+@@ -118,9 +118,8 @@
+ sd a6, PT_R10(sp)
+ sd a7, PT_R11(sp)
+
+- sd t2,PT_R1(sp)
++ move s0, t2
+ jal syscall_trace
+- ld t2,PT_R1(sp)
+
+ ld a0, PT_R4(sp) # Restore argument registers
+ ld a1, PT_R5(sp)
+@@ -129,7 +128,7 @@
+ ld a4, PT_R8(sp)
+ ld a5, PT_R9(sp)
+
+- jalr t2
++ jalr s0
+
+ li t0, -EMAXERRNO - 1 # error?
+ sltu t0, t0, v0
+@@ -576,6 +575,8 @@
+ sys_call_table:
+ syscalltable
+
++ .purgem sys
++
+ .macro sys function, nargs
+ .byte \nargs
+ .endm
+diff -Nur linux-2.4.32-rc1/arch/mips64/kernel/setup.c linux-2.4.32-rc1.mips/arch/mips64/kernel/setup.c
+--- linux-2.4.32-rc1/arch/mips64/kernel/setup.c 2005-01-19 15:09:32.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/kernel/setup.c 2004-11-22 14:38:26.000000000 +0100
+@@ -129,14 +129,6 @@
+ */
+ load_mmu();
+
+- /*
+- * On IP27, I am seeing the TS bit set when the kernel is loaded.
+- * Maybe because the kernel is in ckseg0 and not xkphys? Clear it
+- * anyway ...
+- */
+- clear_c0_status(ST0_BEV|ST0_TS|ST0_CU1|ST0_CU2|ST0_CU3);
+- set_c0_status(ST0_CU0|ST0_KX|ST0_SX|ST0_FR);
+-
+ start_kernel();
+ }
+
+diff -Nur linux-2.4.32-rc1/arch/mips64/kernel/signal_n32.c linux-2.4.32-rc1.mips/arch/mips64/kernel/signal_n32.c
+--- linux-2.4.32-rc1/arch/mips64/kernel/signal_n32.c 2005-01-19 15:09:33.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/kernel/signal_n32.c 2005-02-07 22:10:53.000000000 +0100
+@@ -68,7 +68,7 @@
+ };
+
+ extern asmlinkage int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc);
+-extern int inline setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc);
++extern int setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc);
+
+ asmlinkage void sysn32_rt_sigreturn(abi64_no_regargs, struct pt_regs regs)
+ {
+diff -Nur linux-2.4.32-rc1/arch/mips64/kernel/traps.c linux-2.4.32-rc1.mips/arch/mips64/kernel/traps.c
+--- linux-2.4.32-rc1/arch/mips64/kernel/traps.c 2005-01-19 15:09:33.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/kernel/traps.c 2005-04-12 22:25:34.000000000 +0200
+@@ -462,9 +462,10 @@
+ }
+ ll_task = current;
+
++ compute_return_epc(regs);
++
+ regs->regs[(opcode & RT) >> 16] = value;
+
+- compute_return_epc(regs);
+ return;
+
+ sig:
+@@ -495,8 +496,8 @@
+ goto sig;
+ }
+ if (ll_bit == 0 || ll_task != current) {
+- regs->regs[reg] = 0;
+ compute_return_epc(regs);
++ regs->regs[reg] = 0;
+ return;
+ }
+
+@@ -505,9 +506,9 @@
+ goto sig;
+ }
+
++ compute_return_epc(regs);
+ regs->regs[reg] = 1;
+
+- compute_return_epc(regs);
+ return;
+
+ sig:
+@@ -809,13 +810,18 @@
+ void __init per_cpu_trap_init(void)
+ {
+ unsigned int cpu = smp_processor_id();
++ unsigned int status_set = ST0_CU0|ST0_FR|ST0_KX|ST0_SX|ST0_UX;
+
+- /* Some firmware leaves the BEV flag set, clear it. */
+- clear_c0_status(ST0_CU1|ST0_CU2|ST0_CU3|ST0_BEV);
+- set_c0_status(ST0_CU0|ST0_FR|ST0_KX|ST0_SX|ST0_UX);
+-
++ /*
++ * Disable coprocessors, enable 64-bit addressing and set FPU
++ * for the 32/32 FPR register model. Reset the BEV flag that
++ * some firmware may have left set and the TS bit (for IP27).
++ * Set XX for ISA IV code to work.
++ */
+ if (current_cpu_data.isa_level == MIPS_CPU_ISA_IV)
+- set_c0_status(ST0_XX);
++ status_set |= ST0_XX;
++ change_c0_status(ST0_CU|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX,
++ status_set);
+
+ /*
+ * Some MIPS CPUs have a dedicated interrupt vector which reduces the
+@@ -825,13 +831,11 @@
+ set_c0_cause(CAUSEF_IV);
+
+ cpu_data[cpu].asid_cache = ASID_FIRST_VERSION;
+- write_c0_context(((long)(&pgd_current[cpu])) << 23);
+- write_c0_wired(0);
++ TLBMISS_HANDLER_SETUP();
+
+ atomic_inc(&init_mm.mm_count);
+ current->active_mm = &init_mm;
+- if (current->mm)
+- BUG();
++ BUG_ON(current->mm);
+ enter_lazy_tlb(&init_mm, current, cpu);
+ }
+
+@@ -842,8 +846,6 @@
+ extern char except_vec4;
+ unsigned long i;
+
+- per_cpu_trap_init();
+-
+ /* Copy the generic exception handlers to their final destination. */
+ memcpy((void *) KSEG0 , &except_vec0_generic, 0x80);
+ memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic, 0x80);
+@@ -933,6 +935,5 @@
+
+ flush_icache_range(KSEG0, KSEG0 + 0x400);
+
+- atomic_inc(&init_mm.mm_count); /* XXX UP? */
+- current->active_mm = &init_mm;
++ per_cpu_trap_init();
+ }
+diff -Nur linux-2.4.32-rc1/arch/mips64/mm/cerr-sb1.c linux-2.4.32-rc1.mips/arch/mips64/mm/cerr-sb1.c
+--- linux-2.4.32-rc1/arch/mips64/mm/cerr-sb1.c 2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/mm/cerr-sb1.c 2004-12-13 18:37:26.000000000 +0100
+@@ -252,14 +252,14 @@
+
+ /* Masks to select bits for Hamming parity, mask_72_64[i] for bit[i] */
+ static const uint64_t mask_72_64[8] = {
+- 0x0738C808099264FFL,
+- 0x38C808099264FF07L,
+- 0xC808099264FF0738L,
+- 0x08099264FF0738C8L,
+- 0x099264FF0738C808L,
+- 0x9264FF0738C80809L,
+- 0x64FF0738C8080992L,
+- 0xFF0738C808099264L
++ 0x0738C808099264FFULL,
++ 0x38C808099264FF07ULL,
++ 0xC808099264FF0738ULL,
++ 0x08099264FF0738C8ULL,
++ 0x099264FF0738C808ULL,
++ 0x9264FF0738C80809ULL,
++ 0x64FF0738C8080992ULL,
++ 0xFF0738C808099264ULL
+ };
+
+ /* Calculate the parity on a range of bits */
+@@ -331,9 +331,9 @@
+ ((lru >> 4) & 0x3),
+ ((lru >> 6) & 0x3));
+ }
+- va = (taglo & 0xC0000FFFFFFFE000) | addr;
++ va = (taglo & 0xC0000FFFFFFFE000ULL) | addr;
+ if ((taglo & (1 << 31)) && (((taglo >> 62) & 0x3) == 3))
+- va |= 0x3FFFF00000000000;
++ va |= 0x3FFFF00000000000ULL;
+ valid = ((taghi >> 29) & 1);
+ if (valid) {
+ tlo_tmp = taglo & 0xfff3ff;
+@@ -474,7 +474,7 @@
+ : "r" ((way << 13) | addr));
+
+ taglo = ((unsigned long long)taglohi << 32) | taglolo;
+- pa = (taglo & 0xFFFFFFE000) | addr;
++ pa = (taglo & 0xFFFFFFE000ULL) | addr;
+ if (way == 0) {
+ lru = (taghi >> 14) & 0xff;
+ prom_printf("[Bank %d Set 0x%02x] LRU > %d %d %d %d > MRU\n",
+diff -Nur linux-2.4.32-rc1/arch/mips64/mm/c-r4k.c linux-2.4.32-rc1.mips/arch/mips64/mm/c-r4k.c
+--- linux-2.4.32-rc1/arch/mips64/mm/c-r4k.c 2005-01-19 15:09:33.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/mm/c-r4k.c 2005-02-06 22:55:42.000000000 +0100
+@@ -867,9 +867,16 @@
+ * normally they'd suffer from aliases but magic in the hardware deals
+ * with that for us so we don't need to take care ourselves.
+ */
+- if (c->cputype != CPU_R10000 && c->cputype != CPU_R12000)
+- if (c->dcache.waysize > PAGE_SIZE)
+- c->dcache.flags |= MIPS_CACHE_ALIASES;
++ switch (c->cputype) {
++ case CPU_R10000:
++ case CPU_R12000:
++ break;
++ case CPU_24K:
++ if (!(read_c0_config7() & (1 << 16)))
++ default:
++ if (c->dcache.waysize > PAGE_SIZE)
++ c->dcache.flags |= MIPS_CACHE_ALIASES;
++ }
+
+ switch (c->cputype) {
+ case CPU_20KC:
+@@ -1070,9 +1077,6 @@
+ setup_scache();
+ coherency_setup();
+
+- if (c->dcache.sets * c->dcache.ways > PAGE_SIZE)
+- c->dcache.flags |= MIPS_CACHE_ALIASES;
+-
+ r4k_blast_dcache_page_setup();
+ r4k_blast_dcache_page_indexed_setup();
+ r4k_blast_dcache_setup();
+diff -Nur linux-2.4.32-rc1/arch/mips64/mm/tlbex-r4k.S linux-2.4.32-rc1.mips/arch/mips64/mm/tlbex-r4k.S
+--- linux-2.4.32-rc1/arch/mips64/mm/tlbex-r4k.S 2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/mm/tlbex-r4k.S 2005-06-06 16:46:22.000000000 +0200
+@@ -125,6 +125,33 @@
+ nop
+ END(except_vec1_r4k)
+
++ __FINIT
++
++ .align 5
++LEAF(handle_vec1_r4k)
++ .set noat
++ LOAD_PTE2 k1 k0 9f
++ ld k0, 0(k1) # get even pte
++ ld k1, 8(k1) # get odd pte
++ PTE_RELOAD k0 k1
++ mtc0_tlbw_hazard
++ tlbwr
++ tlbw_eret_hazard
++ eret
++
++9: # handle the vmalloc range
++ LOAD_KPTE2 k1 k0 invalid_vmalloc_address
++ ld k0, 0(k1) # get even pte
++ ld k1, 8(k1) # get odd pte
++ PTE_RELOAD k0 k1
++ mtc0_tlbw_hazard
++ tlbwr
++ tlbw_eret_hazard
++ eret
++END(handle_vec1_r4k)
++
++ __INIT
++
+ LEAF(except_vec1_sb1)
+ #if BCM1250_M3_WAR
+ dmfc0 k0, CP0_BADVADDR
+@@ -134,28 +161,24 @@
+ bnez k0, 1f
+ #endif
+ .set noat
+- dla k0, handle_vec1_r4k
++ dla k0, handle_vec1_sb1
+ jr k0
+ nop
+
+ 1: eret
+- nop
+ END(except_vec1_sb1)
+
+ __FINIT
+
+ .align 5
+-LEAF(handle_vec1_r4k)
++LEAF(handle_vec1_sb1)
+ .set noat
+ LOAD_PTE2 k1 k0 9f
+ ld k0, 0(k1) # get even pte
+ ld k1, 8(k1) # get odd pte
+ PTE_RELOAD k0 k1
+- rm9000_tlb_hazard
+- b 1f
+- tlbwr
+-1: nop
+- rm9000_tlb_hazard
++ mtc0_tlbw_hazard
++ tlbwr
+ eret
+
+ 9: # handle the vmalloc range
+@@ -163,13 +186,10 @@
+ ld k0, 0(k1) # get even pte
+ ld k1, 8(k1) # get odd pte
+ PTE_RELOAD k0 k1
+- rm9000_tlb_hazard
+- b 1f
+- tlbwr
+-1: nop
+- rm9000_tlb_hazard
++ mtc0_tlbw_hazard
++ tlbwr
+ eret
+-END(handle_vec1_r4k)
++END(handle_vec1_sb1)
+
+
+ __INIT
+@@ -195,10 +215,8 @@
+ ld k0, 0(k1) # get even pte
+ ld k1, 8(k1) # get odd pte
+ PTE_RELOAD k0 k1
+- rm9000_tlb_hazard
+- nop
++ mtc0_tlbw_hazard
+ tlbwr
+- rm9000_tlb_hazard
+ eret
+
+ 9: # handle the vmalloc range
+@@ -206,10 +224,8 @@
+ ld k0, 0(k1) # get even pte
+ ld k1, 8(k1) # get odd pte
+ PTE_RELOAD k0 k1
+- rm9000_tlb_hazard
+- nop
++ mtc0_tlbw_hazard
+ tlbwr
+- rm9000_tlb_hazard
+ eret
+ END(handle_vec1_r10k)
+
+diff -Nur linux-2.4.32-rc1/arch/mips64/mm/tlb-r4k.c linux-2.4.32-rc1.mips/arch/mips64/mm/tlb-r4k.c
+--- linux-2.4.32-rc1/arch/mips64/mm/tlb-r4k.c 2005-01-19 15:09:33.000000000 +0100
++++ linux-2.4.32-rc1.mips/arch/mips64/mm/tlb-r4k.c 2004-11-25 23:18:38.000000000 +0100
+@@ -1,24 +1,12 @@
+ /*
+- * Carsten Langgaard, carstenl@mips.com
+- * Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved.
+- *
+- * This program is free software; you can distribute it and/or modify it
+- * under the terms of the GNU General Public License (Version 2) as
+- * published by the Free Software Foundation.
+- *
+- * This program is distributed in the hope 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
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+- * 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.
+- *
+- * MIPS64 CPU variant specific MMU routines.
+- * These routine are not optimized in any way, they are done in a generic way
+- * so they can be used on all MIPS64 compliant CPUs, and also done in an
+- * attempt not to break anything for the R4xx0 style CPUs.
++ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
++ * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle ralf@gnu.org
++ * Carsten Langgaard, carstenl@mips.com
++ * Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved.
+ */
+ #include <linux/init.h>
+ #include <linux/sched.h>
+@@ -30,9 +18,6 @@
+ #include <asm/pgtable.h>
+ #include <asm/system.h>
+
+-#undef DEBUG_TLB
+-#undef DEBUG_TLBUPDATE
+-
+ extern void except_vec1_r4k(void);
+
+ /* CP0 hazard avoidance. */
+@@ -46,31 +31,23 @@
+ unsigned long old_ctx;
+ int entry;
+
+-#ifdef DEBUG_TLB
+- printk("[tlball]");
+-#endif
+-
+ local_irq_save(flags);
+ /* Save old context and create impossible VPN2 value */
+ old_ctx = read_c0_entryhi();
+- write_c0_entryhi(XKPHYS);
+ write_c0_entrylo0(0);
+ write_c0_entrylo1(0);
+- BARRIER;
+
+ entry = read_c0_wired();
+
+ /* Blast 'em all away. */
+- while(entry < current_cpu_data.tlbsize) {
+- /* Make sure all entries differ. */
+- write_c0_entryhi(XKPHYS+entry*0x2000);
++ while (entry < current_cpu_data.tlbsize) {
++ write_c0_entryhi(XKPHYS + entry*0x2000);
+ write_c0_index(entry);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_write_indexed();
+- BARRIER;
+ entry++;
+ }
+- BARRIER;
++ tlbw_use_hazard();
+ write_c0_entryhi(old_ctx);
+ local_irq_restore(flags);
+ }
+@@ -79,12 +56,8 @@
+ {
+ int cpu = smp_processor_id();
+
+- if (cpu_context(cpu, mm) != 0) {
+-#ifdef DEBUG_TLB
+- printk("[tlbmm<%d>]", mm->context);
+-#endif
++ if (cpu_context(cpu, mm) != 0)
+ drop_mmu_context(mm,cpu);
+- }
+ }
+
+ void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+@@ -96,10 +69,6 @@
+ unsigned long flags;
+ int size;
+
+-#ifdef DEBUG_TLB
+- printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & ASID_MASK),
+- start, end);
+-#endif
+ local_irq_save(flags);
+ size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ size = (size + 1) >> 1;
+@@ -110,25 +79,25 @@
+ start &= (PAGE_MASK << 1);
+ end += ((PAGE_SIZE << 1) - 1);
+ end &= (PAGE_MASK << 1);
+- while(start < end) {
++ while (start < end) {
+ int idx;
+
+ write_c0_entryhi(start | newpid);
+ start += (PAGE_SIZE << 1);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_probe();
+ BARRIER;
+ idx = read_c0_index();
+ write_c0_entrylo0(0);
+ write_c0_entrylo1(0);
+- if(idx < 0)
++ if (idx < 0)
+ continue;
+ /* Make sure all entries differ. */
+ write_c0_entryhi(XKPHYS+idx*0x2000);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_write_indexed();
+- BARRIER;
+ }
++ tlbw_use_hazard();
+ write_c0_entryhi(oldpid);
+ } else {
+ drop_mmu_context(mm, cpu);
+@@ -145,28 +114,26 @@
+ unsigned long flags;
+ unsigned long oldpid, newpid, idx;
+
+-#ifdef DEBUG_TLB
+- printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
+-#endif
+ newpid = cpu_asid(cpu, vma->vm_mm);
+ page &= (PAGE_MASK << 1);
+ local_irq_save(flags);
+ oldpid = read_c0_entryhi();
+ write_c0_entryhi(page | newpid);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_probe();
+ BARRIER;
+ idx = read_c0_index();
+ write_c0_entrylo0(0);
+ write_c0_entrylo1(0);
+- if(idx < 0)
++ if (idx < 0)
+ goto finish;
+ /* Make sure all entries differ. */
+ write_c0_entryhi(XKPHYS+idx*0x2000);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_write_indexed();
++ tlbw_use_hazard();
++
+ finish:
+- BARRIER;
+ write_c0_entryhi(oldpid);
+ local_irq_restore(flags);
+ }
+@@ -186,7 +153,7 @@
+
+ local_irq_save(flags);
+ write_c0_entryhi(page);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_probe();
+ BARRIER;
+ idx = read_c0_index();
+@@ -195,10 +162,12 @@
+ if (idx >= 0) {
+ /* Make sure all entries differ. */
+ write_c0_entryhi(KSEG0+idx*0x2000);
++ mtc0_tlbw_hazard();
+ tlb_write_indexed();
++ tlbw_use_hazard();
+ }
+- BARRIER;
+ write_c0_entryhi(oldpid);
++
+ local_irq_restore(flags);
+ }
+
+@@ -208,7 +177,6 @@
+ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
+ {
+ unsigned long flags;
+- unsigned int asid;
+ pgd_t *pgdp;
+ pmd_t *pmdp;
+ pte_t *ptep;
+@@ -222,70 +190,58 @@
+
+ pid = read_c0_entryhi() & ASID_MASK;
+
+-#ifdef DEBUG_TLB
+- if ((pid != (cpu_asid(smp_processor_id(), vma->vm_mm))) ||
+- (cpu_context(smp_processor_id(), vma->vm_mm) == 0)) {
+- printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d"
+- "tlbpid=%d\n", (int) (cpu_context(smp_processor_id(),
+- vma->vm_mm) & ASID_MASK), pid);
+- }
+-#endif
+-
+ local_irq_save(flags);
+ address &= (PAGE_MASK << 1);
+- write_c0_entryhi(address | (pid));
++ write_c0_entryhi(address | pid);
+ pgdp = pgd_offset(vma->vm_mm, address);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_probe();
+ BARRIER;
+ pmdp = pmd_offset(pgdp, address);
+ idx = read_c0_index();
+ ptep = pte_offset(pmdp, address);
+- BARRIER;
+ write_c0_entrylo0(pte_val(*ptep++) >> 6);
+ write_c0_entrylo1(pte_val(*ptep) >> 6);
+- write_c0_entryhi(address | (pid));
+- BARRIER;
+- if(idx < 0) {
++ write_c0_entryhi(address | pid);
++ mtc0_tlbw_hazard();
++ if (idx < 0)
+ tlb_write_random();
+- } else {
++ else
+ tlb_write_indexed();
+- }
+- BARRIER;
++ tlbw_use_hazard();
+ write_c0_entryhi(pid);
+- BARRIER;
+ local_irq_restore(flags);
+ }
+
+-void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+- unsigned long entryhi, unsigned long pagemask)
++void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
++ unsigned long entryhi, unsigned long pagemask)
+ {
+- unsigned long flags;
+- unsigned long wired;
+- unsigned long old_pagemask;
+- unsigned long old_ctx;
+-
+- local_irq_save(flags);
+- /* Save old context and create impossible VPN2 value */
+- old_ctx = (read_c0_entryhi() & ASID_MASK);
+- old_pagemask = read_c0_pagemask();
+- wired = read_c0_wired();
+- write_c0_wired(wired + 1);
+- write_c0_index(wired);
+- BARRIER;
+- write_c0_pagemask(pagemask);
+- write_c0_entryhi(entryhi);
+- write_c0_entrylo0(entrylo0);
+- write_c0_entrylo1(entrylo1);
+- BARRIER;
+- tlb_write_indexed();
+- BARRIER;
+-
+- write_c0_entryhi(old_ctx);
+- BARRIER;
+- write_c0_pagemask(old_pagemask);
+- local_flush_tlb_all();
+- local_irq_restore(flags);
++ unsigned long flags;
++ unsigned long wired;
++ unsigned long old_pagemask;
++ unsigned long old_ctx;
++
++ local_irq_save(flags);
++ /* Save old context and create impossible VPN2 value */
++ old_ctx = read_c0_entryhi() & ASID_MASK;
++ old_pagemask = read_c0_pagemask();
++ wired = read_c0_wired();
++ write_c0_wired(wired + 1);
++ write_c0_index(wired);
++ BARRIER;
++ write_c0_pagemask(pagemask);
++ write_c0_entryhi(entryhi);
++ write_c0_entrylo0(entrylo0);
++ write_c0_entrylo1(entrylo1);
++ mtc0_tlbw_hazard();
++ tlb_write_indexed();
++ tlbw_use_hazard();
++
++ write_c0_entryhi(old_ctx);
++ BARRIER;
++ write_c0_pagemask(old_pagemask);
++ local_flush_tlb_all();
++ local_irq_restore(flags);
+ }
+
+ /*
+@@ -317,17 +273,15 @@
+ }
+
+ write_c0_index(temp_tlb_entry);
+- BARRIER;
+ write_c0_pagemask(pagemask);
+ write_c0_entryhi(entryhi);
+ write_c0_entrylo0(entrylo0);
+ write_c0_entrylo1(entrylo1);
+- BARRIER;
++ mtc0_tlbw_hazard();
+ tlb_write_indexed();
+- BARRIER;
++ tlbw_use_hazard();
+
+ write_c0_entryhi(old_ctx);
+- BARRIER;
+ write_c0_pagemask(old_pagemask);
+ out:
+ local_irq_restore(flags);
+@@ -348,15 +302,23 @@
+ return;
+
+ config1 = read_c0_config1();
+- if (!((config1 >> 7) & 3))
+- panic("No MMU present");
++ if (!((config >> 7) & 3))
++ panic("No TLB present");
+
+ c->tlbsize = ((config1 >> 25) & 0x3f) + 1;
+ }
+
+ void __init r4k_tlb_init(void)
+ {
+- unsigned long config = read_c0_config();
++ unsigned int config = read_c0_config();
++
++ /*
++ * You should never change this register:
++ * - On R4600 1.7 the tlbp never hits for pages smaller than
++ * the value in the c0_pagemask register.
++ * - The entire mm handling assumes the c0_pagemask register to
++ * be set for 4kb pages.
++ */
+ probe_tlb(config);
+ write_c0_pagemask(PM_DEFAULT_MASK);
+ write_c0_wired(0);
+diff -Nur linux-2.4.32-rc1/drivers/char/au1000_gpio.c linux-2.4.32-rc1.mips/drivers/char/au1000_gpio.c
+--- linux-2.4.32-rc1/drivers/char/au1000_gpio.c 2003-08-25 13:44:41.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/char/au1000_gpio.c 2003-12-20 14:18:51.000000000 +0100
+@@ -246,7 +246,7 @@
+
+ static struct miscdevice au1000gpio_miscdev =
+ {
+- GPIO_MINOR,
++ MISC_DYNAMIC_MINOR,
+ "au1000_gpio",
+ &au1000gpio_fops
+ };
+diff -Nur linux-2.4.32-rc1/drivers/char/au1550_psc_spi.c linux-2.4.32-rc1.mips/drivers/char/au1550_psc_spi.c
+--- linux-2.4.32-rc1/drivers/char/au1550_psc_spi.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/char/au1550_psc_spi.c 2005-02-11 21:37:24.000000000 +0100
+@@ -0,0 +1,466 @@
++/*
++ * Driver for Alchemy Au1550 SPI on the PSC.
++ *
++ * Copyright 2004 Embedded Edge, LLC.
++ * dan@embeddededge.com
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/au1000.h>
++#include <asm/au1550_spi.h>
++#include <asm/au1xxx_psc.h>
++
++#ifdef CONFIG_MIPS_PB1550
++#include <asm/pb1550.h>
++#endif
++
++#ifdef CONFIG_MIPS_DB1550
++#include <asm/db1x00.h>
++#endif
++
++#ifdef CONFIG_MIPS_PB1200
++#include <asm/pb1200.h>
++#endif
++
++/* This is just a simple programmed I/O SPI interface on the PSC of the 1550.
++ * We support open, close, write, and ioctl. The SPI is a full duplex
++ * interface, you can't read without writing. So, the write system call
++ * copies the bytes out to the SPI, and whatever is returned is placed
++ * in the same buffer. Kinda weird, maybe we'll change it, but for now
++ * it works OK.
++ * I didn't implement any DMA yet, and it's a debate about the necessity.
++ * The SPI clocks are usually quite fast, so data is sent/received as
++ * quickly as you can stuff the FIFO. The overhead of DMA and interrupts
++ * are usually far greater than the data transfer itself. If, however,
++ * we find applications that move large amounts of data, we may choose
++ * use the overhead of buffering and DMA to do the work.
++ */
++
++/* The maximum clock rate specified in the manual is 2mHz.
++*/
++#define MAX_BAUD_RATE (2 * 1000000)
++#define PSC_INTCLK_RATE (32 * 1000000)
++
++static int inuse;
++
++/* We have to know what the user requested for the data length
++ * so we know how to stuff the fifo. The FIFO is 32 bits wide,
++ * and we have to load it with the bits to go in a single transfer.
++ */
++static uint spi_datalen;
++
++static int
++au1550spi_master_done( int ms )
++{
++ int timeout=ms;
++ volatile psc_spi_t *sp;
++
++ sp = (volatile psc_spi_t *)SPI_PSC_BASE;
++
++ /* Loop until MD is set or timeout has expired */
++ while(!(sp->psc_spievent & PSC_SPIEVNT_MD) && timeout--) udelay(1000);
++
++ if ( !timeout )
++ return 0;
++ else
++ sp->psc_spievent |= PSC_SPIEVNT_MD;
++
++ return 1;
++}
++
++static int
++au1550spi_open(struct inode *inode, struct file *file)
++{
++ if (inuse)
++ return -EBUSY;
++
++ inuse = 1;
++
++ MOD_INC_USE_COUNT;
++
++ return 0;
++}
++
++static ssize_t
++au1550spi_write(struct file *fp, const char *bp, size_t count, loff_t *ppos)
++{
++ int bytelen, i;
++ size_t rcount, retval;
++ unsigned char sb, *rp, *wp;
++ uint fifoword, pcr, stat;
++ volatile psc_spi_t *sp;
++
++ /* Get the number of bytes per transfer.
++ */
++ bytelen = ((spi_datalen - 1) / 8) + 1;
++
++ /* User needs to send us multiple of this count.
++ */
++ if ((count % bytelen) != 0)
++ return -EINVAL;
++
++ rp = wp = (unsigned char *)bp;
++ retval = rcount = count;
++
++ /* Reset the FIFO.
++ */
++ sp = (volatile psc_spi_t *)SPI_PSC_BASE;
++ sp->psc_spipcr = (PSC_SPIPCR_RC | PSC_SPIPCR_TC);
++ au_sync();
++ do {
++ pcr = sp->psc_spipcr;
++ au_sync();
++ } while (pcr != 0);
++
++ /* Prime the transmit FIFO.
++ */
++ while (count > 0) {
++ fifoword = 0;
++ for (i=0; i<bytelen; i++) {
++ fifoword <<= 8;
++ if (get_user(sb, wp) < 0)
++ return -EFAULT;
++ fifoword |= sb;
++ wp++;
++ }
++ count -= bytelen;
++ if (count <= 0)
++ fifoword |= PSC_SPITXRX_LC;
++ sp->psc_spitxrx = fifoword;
++ au_sync();
++ stat = sp->psc_spistat;
++ au_sync();
++ if (stat & PSC_SPISTAT_TF)
++ break;
++ }
++
++ /* Start the transfer.
++ */
++ sp->psc_spipcr = PSC_SPIPCR_MS;
++ au_sync();
++
++ /* Now, just keep the transmit fifo full and empty the receive.
++ */
++ while (count > 0) {
++ stat = sp->psc_spistat;
++ au_sync();
++ while ((stat & PSC_SPISTAT_RE) == 0) {
++ fifoword = sp->psc_spitxrx;
++ au_sync();
++ for (i=0; i<bytelen; i++) {
++ sb = fifoword & 0xff;
++ if (put_user(sb, rp) < 0)
++ return -EFAULT;
++ fifoword >>= 8;
++ rp++;
++ }
++ rcount -= bytelen;
++ stat = sp->psc_spistat;
++ au_sync();
++ }
++ if ((stat & PSC_SPISTAT_TF) == 0) {
++ fifoword = 0;
++ for (i=0; i<bytelen; i++) {
++ fifoword <<= 8;
++ if (get_user(sb, wp) < 0)
++ return -EFAULT;
++ fifoword |= sb;
++ wp++;
++ }
++ count -= bytelen;
++ if (count <= 0)
++ fifoword |= PSC_SPITXRX_LC;
++ sp->psc_spitxrx = fifoword;
++ au_sync();
++ }
++ }
++
++ /* All of the bytes for transmit have been written. Hang
++ * out waiting for any residual bytes that are yet to be
++ * read from the fifo.
++ */
++ while (rcount > 0) {
++ stat = sp->psc_spistat;
++ au_sync();
++ if ((stat & PSC_SPISTAT_RE) == 0) {
++ fifoword = sp->psc_spitxrx;
++ au_sync();
++ for (i=0; i<bytelen; i++) {
++ sb = fifoword & 0xff;
++ if (put_user(sb, rp) < 0)
++ return -EFAULT;
++ fifoword >>= 8;
++ rp++;
++ }
++ rcount -= bytelen;
++ }
++ }
++
++ /* Wait for MasterDone event. 30ms timeout */
++ if (!au1550spi_master_done(30) ) retval = -EFAULT;
++ return retval;
++}
++
++static int
++au1550spi_release(struct inode *inode, struct file *file)
++{
++ MOD_DEC_USE_COUNT;
++
++ inuse = 0;
++
++ return 0;
++}
++
++/* Set the baud rate closest to the request, then return the actual
++ * value we are using.
++ */
++static uint
++set_baud_rate(uint baud)
++{
++ uint rate, tmpclk, brg, ctl, stat;
++ volatile psc_spi_t *sp;
++
++ /* For starters, the input clock is divided by two.
++ */
++ tmpclk = PSC_INTCLK_RATE/2;
++
++ rate = tmpclk / baud;
++
++ /* The dividers work as follows:
++ * baud = tmpclk / (2 * (brg + 1))
++ */
++ brg = (rate/2) - 1;
++
++ /* Test BRG to ensure it will fit into the 6 bits allocated.
++ */
++
++ /* Make sure the device is disabled while we make the change.
++ */
++ sp = (volatile psc_spi_t *)SPI_PSC_BASE;
++ ctl = sp->psc_spicfg;
++ au_sync();
++ sp->psc_spicfg = ctl & ~PSC_SPICFG_DE_ENABLE;
++ au_sync();
++ ctl = PSC_SPICFG_CLR_BAUD(ctl);
++ ctl |= PSC_SPICFG_SET_BAUD(brg);
++ sp->psc_spicfg = ctl;
++ au_sync();
++
++ /* If the device was running prior to getting here, wait for
++ * it to restart.
++ */
++ if (ctl & PSC_SPICFG_DE_ENABLE) {
++ do {
++ stat = sp->psc_spistat;
++ au_sync();
++ } while ((stat & PSC_SPISTAT_DR) == 0);
++ }
++
++ /* Return the actual value.
++ */
++ rate = tmpclk / (2 * (brg + 1));
++
++ return(rate);
++}
++
++static uint
++set_word_len(uint len)
++{
++ uint ctl, stat;
++ volatile psc_spi_t *sp;
++
++ if ((len < 4) || (len > 24))
++ return -EINVAL;
++
++ /* Make sure the device is disabled while we make the change.
++ */
++ sp = (volatile psc_spi_t *)SPI_PSC_BASE;
++ ctl = sp->psc_spicfg;
++ au_sync();
++ sp->psc_spicfg = ctl & ~PSC_SPICFG_DE_ENABLE;
++ au_sync();
++ ctl = PSC_SPICFG_CLR_LEN(ctl);
++ ctl |= PSC_SPICFG_SET_LEN(len);
++ sp->psc_spicfg = ctl;
++ au_sync();
++
++ /* If the device was running prior to getting here, wait for
++ * it to restart.
++ */
++ if (ctl & PSC_SPICFG_DE_ENABLE) {
++ do {
++ stat = sp->psc_spistat;
++ au_sync();
++ } while ((stat & PSC_SPISTAT_DR) == 0);
++ }
++
++ return 0;
++}
++
++static int
++au1550spi_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ int status;
++ u32 val;
++
++ status = 0;
++
++ switch(cmd) {
++ case AU1550SPI_WORD_LEN:
++ status = set_word_len(arg);
++ break;
++
++ case AU1550SPI_SET_BAUD:
++ if (get_user(val, (u32 *)arg))
++ return -EFAULT;
++
++ val = set_baud_rate(val);
++ if (put_user(val, (u32 *)arg))
++ return -EFAULT;
++ break;
++
++ default:
++ status = -ENOIOCTLCMD;
++
++ }
++
++ return status;
++}
++
++
++static struct file_operations au1550spi_fops =
++{
++ owner: THIS_MODULE,
++ write: au1550spi_write,
++ ioctl: au1550spi_ioctl,
++ open: au1550spi_open,
++ release: au1550spi_release,
++};
++
++
++static struct miscdevice au1550spi_miscdev =
++{
++ MISC_DYNAMIC_MINOR,
++ "au1550_spi",
++ &au1550spi_fops
++};
++
++
++int __init
++au1550spi_init(void)
++{
++ uint clk, rate, stat;
++ volatile psc_spi_t *sp;
++
++ /* Wire up Freq3 as a clock for the SPI. The PSC does
++ * factor of 2 divisor, so run a higher rate so we can
++ * get some granularity to the clock speeds.
++ * We can't do this in board set up because the frequency
++ * is computed too late.
++ */
++ rate = get_au1x00_speed();
++ rate /= PSC_INTCLK_RATE;
++
++ /* The FRDIV in the frequency control is (FRDIV + 1) * 2
++ */
++ rate /=2;
++ rate--;
++ clk = au_readl(SYS_FREQCTRL1);
++ au_sync();
++ clk &= ~SYS_FC_FRDIV3_MASK;
++ clk |= (rate << SYS_FC_FRDIV3_BIT);
++ clk |= SYS_FC_FE3;
++ au_writel(clk, SYS_FREQCTRL1);
++ au_sync();
++
++ /* Set up the clock source routing to get Freq3 to PSC0_intclk.
++ */
++ clk = au_readl(SYS_CLKSRC);
++ au_sync();
++ clk &= ~0x03e0;
++ clk |= (5 << 7);
++ au_writel(clk, SYS_CLKSRC);
++ au_sync();
++
++ /* Set up GPIO pin function to drive PSC0_SYNC1, which is
++ * the SPI Select.
++ */
++ clk = au_readl(SYS_PINFUNC);
++ au_sync();
++ clk |= 1;
++ au_writel(clk, SYS_PINFUNC);
++ au_sync();
++
++ /* Now, set up the PSC for SPI PIO mode.
++ */
++ sp = (volatile psc_spi_t *)SPI_PSC_BASE;
++ sp->psc_ctrl = PSC_CTRL_DISABLE;
++ au_sync();
++ sp->psc_sel = PSC_SEL_PS_SPIMODE;
++ sp->psc_spicfg = 0;
++ au_sync();
++ sp->psc_ctrl = PSC_CTRL_ENABLE;
++ au_sync();
++ do {
++ stat = sp->psc_spistat;
++ au_sync();
++ } while ((stat & PSC_SPISTAT_SR) == 0);
++
++ sp->psc_spicfg = (PSC_SPICFG_RT_FIFO8 | PSC_SPICFG_TT_FIFO8 |
++ PSC_SPICFG_DD_DISABLE | PSC_SPICFG_MO);
++ sp->psc_spicfg |= PSC_SPICFG_SET_LEN(8);
++ spi_datalen = 8;
++ sp->psc_spimsk = PSC_SPIMSK_ALLMASK;
++ au_sync();
++
++ set_baud_rate(1000000);
++
++ sp->psc_spicfg |= PSC_SPICFG_DE_ENABLE;
++ do {
++ stat = sp->psc_spistat;
++ au_sync();
++ } while ((stat & PSC_SPISTAT_DR) == 0);
++
++ misc_register(&au1550spi_miscdev);
++ printk("Au1550 SPI driver\n");
++ return 0;
++}
++
++
++void __exit
++au1550spi_exit(void)
++{
++ misc_deregister(&au1550spi_miscdev);
++}
++
++
++module_init(au1550spi_init);
++module_exit(au1550spi_exit);
+diff -Nur linux-2.4.32-rc1/drivers/char/Config.in linux-2.4.32-rc1.mips/drivers/char/Config.in
+--- linux-2.4.32-rc1/drivers/char/Config.in 2004-08-08 01:26:04.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/char/Config.in 2005-02-11 22:09:56.000000000 +0100
+@@ -313,14 +313,11 @@
+ if [ "$CONFIG_OBSOLETE" = "y" -a "$CONFIG_ALPHA_BOOK1" = "y" ]; then
+ bool 'Tadpole ANA H8 Support (OBSOLETE)' CONFIG_H8
+ fi
+-if [ "$CONFIG_MIPS" = "y" -a "$CONFIG_NEW_TIME_C" = "y" ]; then
+- tristate 'Generic MIPS RTC Support' CONFIG_MIPS_RTC
+-fi
+ if [ "$CONFIG_SGI_IP22" = "y" ]; then
+- bool 'SGI DS1286 RTC support' CONFIG_SGI_DS1286
++ tristate 'Dallas DS1286 RTC support' CONFIG_DS1286
+ fi
+ if [ "$CONFIG_SGI_IP27" = "y" ]; then
+- bool 'SGI M48T35 RTC support' CONFIG_SGI_IP27_RTC
++ tristate 'SGI M48T35 RTC support' CONFIG_SGI_IP27_RTC
+ fi
+ if [ "$CONFIG_TOSHIBA_RBTX4927" = "y" -o "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then
+ tristate 'Dallas DS1742 RTC support' CONFIG_DS1742
+@@ -383,6 +380,11 @@
+ source drivers/char/drm/Config.in
+ fi
+ fi
++
++if [ "$CONFIG_X86" = "y" ]; then
++ tristate 'ACP Modem (Mwave) support' CONFIG_MWAVE
++fi
++
+ endmenu
+
+ if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
+@@ -391,6 +393,7 @@
+ if [ "$CONFIG_SOC_AU1X00" = "y" ]; then
+ tristate ' Alchemy Au1x00 GPIO device support' CONFIG_AU1X00_GPIO
+ tristate ' Au1000/ADS7846 touchscreen support' CONFIG_TS_AU1X00_ADS7846
++ #tristate ' Alchemy Au1550 PSC SPI support' CONFIG_AU1550_PSC_SPI
+ fi
+ if [ "$CONFIG_MIPS_ITE8172" = "y" ]; then
+ tristate ' ITE GPIO' CONFIG_ITE_GPIO
+diff -Nur linux-2.4.32-rc1/drivers/char/decserial.c linux-2.4.32-rc1.mips/drivers/char/decserial.c
+--- linux-2.4.32-rc1/drivers/char/decserial.c 2003-08-25 13:44:41.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/char/decserial.c 2004-09-28 02:53:01.000000000 +0200
+@@ -3,95 +3,105 @@
+ * choose the right serial device at boot time
+ *
+ * triemer 6-SEP-1998
+- * sercons.c is designed to allow the three different kinds
++ * sercons.c is designed to allow the three different kinds
+ * of serial devices under the decstation world to co-exist
+- * in the same kernel. The idea here is to abstract
++ * in the same kernel. The idea here is to abstract
+ * the pieces of the drivers that are common to this file
+ * so that they do not clash at compile time and runtime.
+ *
+ * HK 16-SEP-1998 v0.002
+ * removed the PROM console as this is not a real serial
+ * device. Added support for PROM console in drivers/char/tty_io.c
+- * instead. Although it may work to enable more than one
++ * instead. Although it may work to enable more than one
+ * console device I strongly recommend to use only one.
++ *
++ * Copyright (C) 2004 Maciej W. Rozycki
+ */
+
+ #include <linux/config.h>
++#include <linux/errno.h>
+ #include <linux/init.h>
++
+ #include <asm/dec/machtype.h>
++#include <asm/dec/serial.h>
++
++extern int register_zs_hook(unsigned int channel,
++ struct dec_serial_hook *hook);
++extern int unregister_zs_hook(unsigned int channel);
++
++extern int register_dz_hook(unsigned int channel,
++ struct dec_serial_hook *hook);
++extern int unregister_dz_hook(unsigned int channel);
+
++int register_dec_serial_hook(unsigned int channel,
++ struct dec_serial_hook *hook)
++{
+ #ifdef CONFIG_ZS
+-extern int zs_init(void);
++ if (IOASIC)
++ return register_zs_hook(channel, hook);
+ #endif
+-
+ #ifdef CONFIG_DZ
+-extern int dz_init(void);
++ if (!IOASIC)
++ return register_dz_hook(channel, hook);
+ #endif
++ return 0;
++}
+
+-#ifdef CONFIG_SERIAL_DEC_CONSOLE
+-
++int unregister_dec_serial_hook(unsigned int channel)
++{
+ #ifdef CONFIG_ZS
+-extern void zs_serial_console_init(void);
++ if (IOASIC)
++ return unregister_zs_hook(channel);
+ #endif
+-
+ #ifdef CONFIG_DZ
+-extern void dz_serial_console_init(void);
+-#endif
+-
++ if (!IOASIC)
++ return unregister_dz_hook(channel);
+ #endif
++ return 0;
++}
+
+-/* rs_init - starts up the serial interface -
+- handle normal case of starting up the serial interface */
+
+-#ifdef CONFIG_SERIAL_DEC
++extern int zs_init(void);
++extern int dz_init(void);
+
++/*
++ * rs_init - starts up the serial interface -
++ * handle normal case of starting up the serial interface
++ */
+ int __init rs_init(void)
+ {
+-
+-#if defined(CONFIG_ZS) && defined(CONFIG_DZ)
+- if (IOASIC)
+- return zs_init();
+- else
+- return dz_init();
+-#else
+-
+ #ifdef CONFIG_ZS
+- return zs_init();
++ if (IOASIC)
++ return zs_init();
+ #endif
+-
+ #ifdef CONFIG_DZ
+- return dz_init();
+-#endif
+-
++ if (!IOASIC)
++ return dz_init();
+ #endif
++ return -ENXIO;
+ }
+
+ __initcall(rs_init);
+
+-#endif
+
+ #ifdef CONFIG_SERIAL_DEC_CONSOLE
+
+-/* dec_serial_console_init handles the special case of starting
+- * up the console on the serial port
++extern void zs_serial_console_init(void);
++extern void dz_serial_console_init(void);
++
++/*
++ * dec_serial_console_init handles the special case of starting
++ * up the console on the serial port
+ */
+ void __init dec_serial_console_init(void)
+ {
+-#if defined(CONFIG_ZS) && defined(CONFIG_DZ)
+- if (IOASIC)
+- zs_serial_console_init();
+- else
+- dz_serial_console_init();
+-#else
+-
+ #ifdef CONFIG_ZS
+- zs_serial_console_init();
++ if (IOASIC)
++ zs_serial_console_init();
+ #endif
+-
+ #ifdef CONFIG_DZ
+- dz_serial_console_init();
+-#endif
+-
++ if (!IOASIC)
++ dz_serial_console_init();
+ #endif
+ }
+
+diff -Nur linux-2.4.32-rc1/drivers/char/ds1286.c linux-2.4.32-rc1.mips/drivers/char/ds1286.c
+--- linux-2.4.32-rc1/drivers/char/ds1286.c 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/char/ds1286.c 2004-01-10 06:21:39.000000000 +0100
+@@ -1,6 +1,10 @@
+ /*
+ * DS1286 Real Time Clock interface for Linux
+ *
++ * Copyright (C) 2003 TimeSys Corp.
++ * S. James Hill (James.Hill@timesys.com)
++ * (sjhill@realitydiluted.com)
++ *
+ * Copyright (C) 1998, 1999, 2000 Ralf Baechle
+ *
+ * Based on code written by Paul Gortmaker.
+@@ -29,6 +33,7 @@
+ #include <linux/types.h>
+ #include <linux/errno.h>
+ #include <linux/miscdevice.h>
++#include <linux/module.h>
+ #include <linux/slab.h>
+ #include <linux/ioport.h>
+ #include <linux/fcntl.h>
+@@ -95,6 +100,12 @@
+ return -EIO;
+ }
+
++void rtc_ds1286_wait(void)
++{
++ unsigned char sec = CMOS_READ(RTC_SECONDS);
++ while (sec == CMOS_READ(RTC_SECONDS));
++}
++
+ static int ds1286_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+ {
+@@ -249,23 +260,22 @@
+ {
+ spin_lock_irq(&ds1286_lock);
+
+- if (ds1286_status & RTC_IS_OPEN)
+- goto out_busy;
++ if (ds1286_status & RTC_IS_OPEN) {
++ spin_unlock_irq(&ds1286_lock);
++ return -EBUSY;
++ }
+
+ ds1286_status |= RTC_IS_OPEN;
+
+- spin_lock_irq(&ds1286_lock);
++ spin_unlock_irq(&ds1286_lock);
+ return 0;
+-
+-out_busy:
+- spin_lock_irq(&ds1286_lock);
+- return -EBUSY;
+ }
+
+ static int ds1286_release(struct inode *inode, struct file *file)
+ {
++ spin_lock_irq(&ds1286_lock);
+ ds1286_status &= ~RTC_IS_OPEN;
+-
++ spin_unlock_irq(&ds1286_lock);
+ return 0;
+ }
+
+@@ -276,32 +286,6 @@
+ return 0;
+ }
+
+-/*
+- * The various file operations we support.
+- */
+-
+-static struct file_operations ds1286_fops = {
+- .llseek = no_llseek,
+- .read = ds1286_read,
+- .poll = ds1286_poll,
+- .ioctl = ds1286_ioctl,
+- .open = ds1286_open,
+- .release = ds1286_release,
+-};
+-
+-static struct miscdevice ds1286_dev=
+-{
+- .minor = RTC_MINOR,
+- .name = "rtc",
+- .fops = &ds1286_fops,
+-};
+-
+-int __init ds1286_init(void)
+-{
+- printk(KERN_INFO "DS1286 Real Time Clock Driver v%s\n", DS1286_VERSION);
+- return misc_register(&ds1286_dev);
+-}
+-
+ static char *days[] = {
+ "***", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+@@ -528,3 +512,38 @@
+ BCD_TO_BIN(alm_tm->tm_hour);
+ alm_tm->tm_sec = 0;
+ }
++
++static struct file_operations ds1286_fops = {
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .read = ds1286_read,
++ .poll = ds1286_poll,
++ .ioctl = ds1286_ioctl,
++ .open = ds1286_open,
++ .release = ds1286_release,
++};
++
++static struct miscdevice ds1286_dev =
++{
++ .minor = RTC_MINOR,
++ .name = "rtc",
++ .fops = &ds1286_fops,
++};
++
++static int __init ds1286_init(void)
++{
++ printk(KERN_INFO "DS1286 Real Time Clock Driver v%s\n", DS1286_VERSION);
++ return misc_register(&ds1286_dev);
++}
++
++static void __exit ds1286_exit(void)
++{
++ misc_deregister(&ds1286_dev);
++}
++
++module_init(ds1286_init);
++module_exit(ds1286_exit);
++EXPORT_NO_SYMBOLS;
++
++MODULE_AUTHOR("Ralf Baechle");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.4.32-rc1/drivers/char/ds1742.c linux-2.4.32-rc1.mips/drivers/char/ds1742.c
+--- linux-2.4.32-rc1/drivers/char/ds1742.c 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/char/ds1742.c 2004-01-09 20:27:16.000000000 +0100
+@@ -142,6 +142,7 @@
+ CMOS_WRITE(RTC_WRITE, RTC_CONTROL);
+
+ /* convert */
++ memset(&tm, 0, sizeof(struct rtc_time));
+ to_tm(t, &tm);
+
+ /* check each field one by one */
+@@ -216,6 +217,7 @@
+ unsigned long curr_time;
+
+ curr_time = rtc_ds1742_get_time();
++ memset(&tm, 0, sizeof(struct rtc_time));
+ to_tm(curr_time, &tm);
+
+ p = buf;
+@@ -251,8 +253,8 @@
+
+ void rtc_ds1742_wait(void)
+ {
+- while (CMOS_READ(RTC_SECONDS) & 1);
+- while (!(CMOS_READ(RTC_SECONDS) & 1));
++ unsigned char sec = CMOS_READ(RTC_SECONDS);
++ while (sec == CMOS_READ(RTC_SECONDS));
+ }
+
+ static int ds1742_ioctl(struct inode *inode, struct file *file,
+@@ -264,6 +266,7 @@
+ switch (cmd) {
+ case RTC_RD_TIME: /* Read the time/date from RTC */
+ curr_time = rtc_ds1742_get_time();
++ memset(&rtc_tm, 0, sizeof(struct rtc_time));
+ to_tm(curr_time, &rtc_tm);
+ rtc_tm.tm_year -= 1900;
+ return copy_to_user((void *) arg, &rtc_tm, sizeof(rtc_tm)) ?
+diff -Nur linux-2.4.32-rc1/drivers/char/dummy_keyb.c linux-2.4.32-rc1.mips/drivers/char/dummy_keyb.c
+--- linux-2.4.32-rc1/drivers/char/dummy_keyb.c 2003-08-25 13:44:41.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/char/dummy_keyb.c 2004-01-09 09:53:08.000000000 +0100
+@@ -140,3 +140,7 @@
+ {
+ printk("Dummy keyboard driver installed.\n");
+ }
++#ifdef CONFIG_MAGIC_SYSRQ
++unsigned char kbd_sysrq_key;
++unsigned char kbd_sysrq_xlate[128];
++#endif
+diff -Nur linux-2.4.32-rc1/drivers/char/dz.c linux-2.4.32-rc1.mips/drivers/char/dz.c
+--- linux-2.4.32-rc1/drivers/char/dz.c 2005-01-19 15:09:44.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/char/dz.c 2004-12-27 05:13:42.000000000 +0100
+@@ -1,11 +1,13 @@
+ /*
+- * dz.c: Serial port driver for DECStations equiped
++ * dz.c: Serial port driver for DECstations equipped
+ * with the DZ chipset.
+ *
+ * Copyright (C) 1998 Olivier A. D. Lebaillif
+ *
+ * Email: olivier.lebaillif@ifrsys.com
+ *
++ * Copyright (C) 2004 Maciej W. Rozycki
++ *
+ * [31-AUG-98] triemer
+ * Changed IRQ to use Harald's dec internals interrupts.h
+ * removed base_addr code - moving address assignment to setup.c
+@@ -24,6 +26,7 @@
+ #undef DEBUG_DZ
+
+ #include <linux/config.h>
++#include <linux/delay.h>
+ #include <linux/version.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+@@ -54,33 +57,56 @@
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+
+-#define CONSOLE_LINE (3) /* for definition of struct console */
++#ifdef CONFIG_MAGIC_SYSRQ
++#include <linux/sysrq.h>
++#endif
+
+ #include "dz.h"
+
+-#define DZ_INTR_DEBUG 1
+-
+ DECLARE_TASK_QUEUE(tq_serial);
+
+-static struct dz_serial *lines[4];
+-static unsigned char tmp_buffer[256];
++static struct dz_serial multi[DZ_NB_PORT]; /* Four serial lines in the DZ chip */
++static struct tty_driver serial_driver, callout_driver;
++
++static struct tty_struct *serial_table[DZ_NB_PORT];
++static struct termios *serial_termios[DZ_NB_PORT];
++static struct termios *serial_termios_locked[DZ_NB_PORT];
++
++static int serial_refcount;
+
+-#ifdef DEBUG_DZ
+ /*
+- * debugging code to send out chars via prom
++ * tmp_buf is used as a temporary buffer by serial_write. We need to
++ * lock it in case the copy_from_user blocks while swapping in a page,
++ * and some other program tries to do a serial write at the same time.
++ * Since the lock will only come under contention when the system is
++ * swapping and available memory is low, it makes sense to share one
++ * buffer across all the serial ports, since it significantly saves
++ * memory if large numbers of serial ports are open.
+ */
+-static void debug_console(const char *s, int count)
+-{
+- unsigned i;
++static unsigned char *tmp_buf;
++static DECLARE_MUTEX(tmp_buf_sem);
+
+- for (i = 0; i < count; i++) {
+- if (*s == 10)
+- prom_printf("%c", 13);
+- prom_printf("%c", *s++);
+- }
+-}
++static char *dz_name __initdata = "DECstation DZ serial driver version ";
++static char *dz_version __initdata = "1.03";
++
++static struct dz_serial *lines[DZ_NB_PORT];
++static unsigned char tmp_buffer[256];
++
++#ifdef CONFIG_SERIAL_DEC_CONSOLE
++static struct console dz_sercons;
++#endif
++#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
++ !defined(MODULE)
++static unsigned long break_pressed; /* break, really ... */
+ #endif
+
++static void change_speed (struct dz_serial *);
++
++static int baud_table[] = {
++ 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
++ 9600, 0
++};
++
+ /*
+ * ------------------------------------------------------------
+ * dz_in () and dz_out ()
+@@ -94,15 +120,16 @@
+ {
+ volatile unsigned short *addr =
+ (volatile unsigned short *) (info->port + offset);
++
+ return *addr;
+ }
+
+ static inline void dz_out(struct dz_serial *info, unsigned offset,
+ unsigned short value)
+ {
+-
+ volatile unsigned short *addr =
+ (volatile unsigned short *) (info->port + offset);
++
+ *addr = value;
+ }
+
+@@ -143,25 +170,24 @@
+
+ tmp |= mask; /* set the TX flag */
+ dz_out(info, DZ_TCR, tmp);
+-
+ }
+
+ /*
+ * ------------------------------------------------------------
+- * Here starts the interrupt handling routines. All of the
+- * following subroutines are declared as inline and are folded
+- * into dz_interrupt. They were separated out for readability's
+- * sake.
+ *
+- * Note: rs_interrupt() is a "fast" interrupt, which means that it
++ * Here starts the interrupt handling routines. All of the following
++ * subroutines are declared as inline and are folded into
++ * dz_interrupt(). They were separated out for readability's sake.
++ *
++ * Note: dz_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off. People who may want to modify
+- * rs_interrupt() should try to keep the interrupt handler as fast as
++ * dz_interrupt() should try to keep the interrupt handler as fast as
+ * possible. After you are done making modifications, it is not a bad
+ * idea to do:
+ *
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer dz.c
+ *
+- * and look at the resulting assemble code in serial.s.
++ * and look at the resulting assemble code in dz.s.
+ *
+ * ------------------------------------------------------------
+ */
+@@ -188,101 +214,97 @@
+ * This routine deals with inputs from any lines.
+ * ------------------------------------------------------------
+ */
+-static inline void receive_chars(struct dz_serial *info_in)
++static inline void receive_chars(struct dz_serial *info_in,
++ struct pt_regs *regs)
+ {
+-
+ struct dz_serial *info;
+- struct tty_struct *tty = 0;
++ struct tty_struct *tty;
+ struct async_icount *icount;
+- int ignore = 0;
+- unsigned short status, tmp;
+- unsigned char ch;
+-
+- /* this code is going to be a problem...
+- the call to tty_flip_buffer is going to need
+- to be rethought...
+- */
+- do {
+- status = dz_in(info_in, DZ_RBUF);
+- info = lines[LINE(status)];
++ int lines_rx[DZ_NB_PORT] = { [0 ... DZ_NB_PORT - 1] = 0 };
++ unsigned short status;
++ unsigned char ch, flag;
++ int i;
+
+- /* punt so we don't get duplicate characters */
+- if (!(status & DZ_DVAL))
+- goto ignore_char;
+-
+- ch = UCHAR(status); /* grab the char */
+-
+-#if 0
+- if (info->is_console) {
+- if (ch == 0)
+- return; /* it's a break ... */
+- }
+-#endif
++ while ((status = dz_in(info_in, DZ_RBUF)) & DZ_DVAL) {
++ info = lines[LINE(status)];
++ tty = info->tty; /* point to the proper dev */
+
+- tty = info->tty; /* now tty points to the proper dev */
+- icount = &info->icount;
++ ch = UCHAR(status); /* grab the char */
+
+- if (!tty)
+- break;
+- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+- break;
++ if (!tty && (!info->hook || !info->hook->rx_char))
++ continue;
+
+- *tty->flip.char_buf_ptr = ch;
+- *tty->flip.flag_buf_ptr = 0;
++ icount = &info->icount;
+ icount->rx++;
+
+- /* keep track of the statistics */
+- if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) {
+- if (status & DZ_PERR) /* parity error */
+- icount->parity++;
+- else if (status & DZ_FERR) /* frame error */
+- icount->frame++;
+- if (status & DZ_OERR) /* overrun error */
+- icount->overrun++;
+-
+- /* check to see if we should ignore the character
+- and mask off conditions that should be ignored
++ flag = 0;
++ if (status & DZ_FERR) { /* frame error */
++ /*
++ * There is no separate BREAK status bit, so
++ * treat framing errors as BREAKs for Magic SysRq
++ * and SAK; normally, otherwise.
+ */
+-
+- if (status & info->ignore_status_mask) {
+- if (++ignore > 100)
+- break;
+- goto ignore_char;
++#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
++ !defined(MODULE)
++ if (info->line == dz_sercons.index) {
++ if (!break_pressed)
++ break_pressed = jiffies;
++ continue;
+ }
+- /* mask off the error conditions we want to ignore */
+- tmp = status & info->read_status_mask;
+-
+- if (tmp & DZ_PERR) {
+- *tty->flip.flag_buf_ptr = TTY_PARITY;
+-#ifdef DEBUG_DZ
+- debug_console("PERR\n", 5);
+-#endif
+- } else if (tmp & DZ_FERR) {
+- *tty->flip.flag_buf_ptr = TTY_FRAME;
+-#ifdef DEBUG_DZ
+- debug_console("FERR\n", 5);
+ #endif
++ flag = TTY_BREAK;
++ if (info->flags & DZ_SAK)
++ do_SAK(tty);
++ else
++ flag = TTY_FRAME;
++ } else if (status & DZ_OERR) /* overrun error */
++ flag = TTY_OVERRUN;
++ else if (status & DZ_PERR) /* parity error */
++ flag = TTY_PARITY;
++
++#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
++ !defined(MODULE)
++ if (break_pressed && info->line == dz_sercons.index) {
++ if (time_before(jiffies, break_pressed + HZ * 5)) {
++ handle_sysrq(ch, regs, NULL, NULL);
++ break_pressed = 0;
++ continue;
+ }
+- if (tmp & DZ_OERR) {
+-#ifdef DEBUG_DZ
+- debug_console("OERR\n", 5);
++ break_pressed = 0;
++ }
+ #endif
+- if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+- tty->flip.count++;
+- tty->flip.flag_buf_ptr++;
+- tty->flip.char_buf_ptr++;
+- *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+- }
+- }
++
++ if (info->hook && info->hook->rx_char) {
++ (*info->hook->rx_char)(ch, flag);
++ return;
+ }
+- tty->flip.flag_buf_ptr++;
+- tty->flip.char_buf_ptr++;
+- tty->flip.count++;
+- ignore_char:
+- } while (status & DZ_DVAL);
+
+- if (tty)
+- tty_flip_buffer_push(tty);
++ /* keep track of the statistics */
++ switch (flag) {
++ case TTY_FRAME:
++ icount->frame++;
++ break;
++ case TTY_PARITY:
++ icount->parity++;
++ break;
++ case TTY_OVERRUN:
++ icount->overrun++;
++ break;
++ case TTY_BREAK:
++ icount->brk++;
++ break;
++ default:
++ break;
++ }
++
++ if ((status & info->ignore_status_mask) == 0) {
++ tty_insert_flip_char(tty, ch, flag);
++ lines_rx[LINE(status)] = 1;
++ }
++ }
++ for (i = 0; i < DZ_NB_PORT; i++)
++ if (lines_rx[i])
++ tty_flip_buffer_push(lines[i]->tty);
+ }
+
+ /*
+@@ -292,20 +314,34 @@
+ * This routine deals with outputs to any lines.
+ * ------------------------------------------------------------
+ */
+-static inline void transmit_chars(struct dz_serial *info)
++static inline void transmit_chars(struct dz_serial *info_in)
+ {
++ struct dz_serial *info;
++ unsigned short status;
+ unsigned char tmp;
+
++ status = dz_in(info_in, DZ_CSR);
++ info = lines[LINE(status)];
+
++ if (info->hook || !info->tty) {
++ unsigned short mask, tmp;
+
+- if (info->x_char) { /* XON/XOFF chars */
++ mask = 1 << info->line;
++ tmp = dz_in(info, DZ_TCR); /* read the TX flag */
++ tmp &= ~mask; /* clear the TX flag */
++ dz_out(info, DZ_TCR, tmp);
++ return;
++ }
++
++ if (info->x_char) { /* XON/XOFF chars */
+ dz_out(info, DZ_TDR, info->x_char);
+ info->icount.tx++;
+ info->x_char = 0;
+ return;
+ }
+ /* if nothing to do or stopped or hardware stopped */
+- if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped) {
++ if (info->xmit_cnt <= 0 ||
++ info->tty->stopped || info->tty->hw_stopped) {
+ dz_stop(info->tty);
+ return;
+ }
+@@ -359,15 +395,14 @@
+ */
+ static void dz_interrupt(int irq, void *dev, struct pt_regs *regs)
+ {
+- struct dz_serial *info;
++ struct dz_serial *info = (struct dz_serial *)dev;
+ unsigned short status;
+
+ /* get the reason why we just got an irq */
+- status = dz_in((struct dz_serial *) dev, DZ_CSR);
+- info = lines[LINE(status)]; /* re-arrange info the proper port */
++ status = dz_in(info, DZ_CSR);
+
+ if (status & DZ_RDONE)
+- receive_chars(info); /* the receive function */
++ receive_chars(info, regs);
+
+ if (status & DZ_TRDY)
+ transmit_chars(info);
+@@ -514,7 +549,7 @@
+
+
+ info->cflags &= ~DZ_CREAD; /* turn off receive enable flag */
+- dz_out(info, DZ_LPR, info->cflags);
++ dz_out(info, DZ_LPR, info->cflags | info->line);
+
+ if (info->xmit_buf) { /* free Tx buffer */
+ free_page((unsigned long) info->xmit_buf);
+@@ -545,18 +580,21 @@
+ {
+ unsigned long flags;
+ unsigned cflag;
+- int baud;
++ int baud, i;
+
+- if (!info->tty || !info->tty->termios)
+- return;
++ if (!info->hook) {
++ if (!info->tty || !info->tty->termios)
++ return;
++ cflag = info->tty->termios->c_cflag;
++ } else {
++ cflag = info->hook->cflags;
++ }
+
+ save_flags(flags);
+ cli();
+
+ info->cflags = info->line;
+
+- cflag = info->tty->termios->c_cflag;
+-
+ switch (cflag & CSIZE) {
+ case CS5:
+ info->cflags |= DZ_CS5;
+@@ -579,7 +617,16 @@
+ if (cflag & PARODD)
+ info->cflags |= DZ_PARODD;
+
+- baud = tty_get_baud_rate(info->tty);
++ i = cflag & CBAUD;
++ if (i & CBAUDEX) {
++ i &= ~CBAUDEX;
++ if (!info->hook)
++ info->tty->termios->c_cflag &= ~CBAUDEX;
++ else
++ info->hook->cflags &= ~CBAUDEX;
++ }
++ baud = baud_table[i];
++
+ switch (baud) {
+ case 50:
+ info->cflags |= DZ_B50;
+@@ -629,16 +676,16 @@
+ }
+
+ info->cflags |= DZ_RXENAB;
+- dz_out(info, DZ_LPR, info->cflags);
++ dz_out(info, DZ_LPR, info->cflags | info->line);
+
+ /* setup accept flag */
+ info->read_status_mask = DZ_OERR;
+- if (I_INPCK(info->tty))
++ if (info->tty && I_INPCK(info->tty))
+ info->read_status_mask |= (DZ_FERR | DZ_PERR);
+
+ /* characters to ignore */
+ info->ignore_status_mask = 0;
+- if (I_IGNPAR(info->tty))
++ if (info->tty && I_IGNPAR(info->tty))
+ info->ignore_status_mask |= (DZ_FERR | DZ_PERR);
+
+ restore_flags(flags);
+@@ -694,7 +741,7 @@
+
+ down(&tmp_buf_sem);
+ while (1) {
+- c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head));
++ c = min(count, min(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+
+@@ -707,7 +754,7 @@
+ save_flags(flags);
+ cli();
+
+- c = MIN(c, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head));
++ c = min(c, min(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ info->xmit_head = ((info->xmit_head + c) & (DZ_XMIT_SIZE - 1));
+ info->xmit_cnt += c;
+@@ -727,7 +774,7 @@
+ save_flags(flags);
+ cli();
+
+- c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head));
++ c = min(count, min(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head));
+ if (c <= 0) {
+ restore_flags(flags);
+ break;
+@@ -845,7 +892,7 @@
+
+ /*
+ * ------------------------------------------------------------
+- * rs_ioctl () and friends
++ * dz_ioctl () and friends
+ * ------------------------------------------------------------
+ */
+ static int get_serial_info(struct dz_serial *info,
+@@ -958,6 +1005,9 @@
+ struct dz_serial *info = (struct dz_serial *) tty->driver_data;
+ int retval;
+
++ if (info->hook)
++ return -ENODEV;
++
+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
+ (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+@@ -1252,19 +1302,14 @@
+ int retval, line;
+
+ line = MINOR(tty->device) - tty->driver.minor_start;
+-
+- /* The dz lines for the mouse/keyboard must be
+- * opened using their respective drivers.
+- */
+ if ((line < 0) || (line >= DZ_NB_PORT))
+ return -ENODEV;
++ info = lines[line];
+
+- if ((line == DZ_KEYBOARD) || (line == DZ_MOUSE))
++ if (info->hook)
+ return -ENODEV;
+
+- info = lines[line];
+ info->count++;
+-
+ tty->driver_data = info;
+ info->tty = tty;
+
+@@ -1285,14 +1330,21 @@
+ else
+ *tty->termios = info->callout_termios;
+ change_speed(info);
+-
+ }
++#ifdef CONFIG_SERIAL_DEC_CONSOLE
++ if (dz_sercons.cflag && dz_sercons.index == line) {
++ tty->termios->c_cflag = dz_sercons.cflag;
++ dz_sercons.cflag = 0;
++ change_speed(info);
++ }
++#endif
++
+ info->session = current->session;
+ info->pgrp = current->pgrp;
+ return 0;
+ }
+
+-static void show_serial_version(void)
++static void __init show_serial_version(void)
+ {
+ printk("%s%s\n", dz_name, dz_version);
+ }
+@@ -1300,7 +1352,6 @@
+ int __init dz_init(void)
+ {
+ int i;
+- long flags;
+ struct dz_serial *info;
+
+ /* Setup base handler, and timer table. */
+@@ -1311,9 +1362,9 @@
+ memset(&serial_driver, 0, sizeof(struct tty_driver));
+ serial_driver.magic = TTY_DRIVER_MAGIC;
+ #if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
+- serial_driver.name = "ttyS";
+-#else
+ serial_driver.name = "tts/%d";
++#else
++ serial_driver.name = "ttyS";
+ #endif
+ serial_driver.major = TTY_MAJOR;
+ serial_driver.minor_start = 64;
+@@ -1352,9 +1403,9 @@
+ */
+ callout_driver = serial_driver;
+ #if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
+- callout_driver.name = "cua";
+-#else
+ callout_driver.name = "cua/%d";
++#else
++ callout_driver.name = "cua";
+ #endif
+ callout_driver.major = TTYAUX_MAJOR;
+ callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+@@ -1363,25 +1414,27 @@
+ panic("Couldn't register serial driver");
+ if (tty_register_driver(&callout_driver))
+ panic("Couldn't register callout driver");
+- save_flags(flags);
+- cli();
+
+ for (i = 0; i < DZ_NB_PORT; i++) {
+ info = &multi[i];
+ lines[i] = info;
+- info->magic = SERIAL_MAGIC;
+-
++ info->tty = 0;
++ info->x_char = 0;
+ if (mips_machtype == MACH_DS23100 ||
+ mips_machtype == MACH_DS5100)
+ info->port = (unsigned long) KN01_DZ11_BASE;
+ else
+ info->port = (unsigned long) KN02_DZ11_BASE;
+-
+ info->line = i;
+- info->tty = 0;
++
++ if (info->hook && info->hook->init_info) {
++ (*info->hook->init_info)(info);
++ continue;
++ }
++
++ info->magic = SERIAL_MAGIC;
+ info->close_delay = 50;
+ info->closing_wait = 3000;
+- info->x_char = 0;
+ info->event = 0;
+ info->count = 0;
+ info->blocked_open = 0;
+@@ -1393,25 +1446,16 @@
+ info->normal_termios = serial_driver.init_termios;
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+-
+- /*
+- * If we are pointing to address zero then punt - not correctly
+- * set up in setup.c to handle this.
+- */
+- if (!info->port)
+- return 0;
+-
+- printk("ttyS%02d at 0x%08x (irq = %d)\n", info->line,
+- info->port, dec_interrupt[DEC_IRQ_DZ11]);
+-
++ printk("ttyS%02d at 0x%08x (irq = %d) is a DC7085 DZ\n",
++ info->line, info->port, dec_interrupt[DEC_IRQ_DZ11]);
+ tty_register_devfs(&serial_driver, 0,
+- serial_driver.minor_start + info->line);
++ serial_driver.minor_start + info->line);
+ tty_register_devfs(&callout_driver, 0,
+- callout_driver.minor_start + info->line);
++ callout_driver.minor_start + info->line);
+ }
+
+- /* reset the chip */
+ #ifndef CONFIG_SERIAL_DEC_CONSOLE
++ /* reset the chip */
+ dz_out(info, DZ_CSR, DZ_CLR);
+ while (dz_in(info, DZ_CSR) & DZ_CLR);
+ iob();
+@@ -1420,43 +1464,104 @@
+ dz_out(info, DZ_CSR, DZ_MSE);
+ #endif
+
+- /* order matters here... the trick is that flags
+- is updated... in request_irq - to immediatedly obliterate
+- it is unwise. */
+- restore_flags(flags);
+-
+-
+ if (request_irq(dec_interrupt[DEC_IRQ_DZ11], dz_interrupt,
+- SA_INTERRUPT, "DZ", lines[0]))
++ 0, "DZ", lines[0]))
+ panic("Unable to register DZ interrupt");
+
++ for (i = 0; i < DZ_NB_PORT; i++)
++ if (lines[i]->hook) {
++ startup(lines[i]);
++ if (lines[i]->hook->init_channel)
++ (*lines[i]->hook->init_channel)(lines[i]);
++ }
++
+ return 0;
+ }
+
+-#ifdef CONFIG_SERIAL_DEC_CONSOLE
+-static void dz_console_put_char(unsigned char ch)
++/*
++ * polling I/O routines
++ */
++static int dz_poll_tx_char(void *handle, unsigned char ch)
+ {
+ unsigned long flags;
+- int loops = 2500;
+- unsigned short tmp = ch;
+- /* this code sends stuff out to serial device - spinning its
+- wheels and waiting. */
++ struct dz_serial *info = handle;
++ unsigned short csr, tcr, trdy, mask;
++ int loops = 10000;
++ int ret;
+
+- /* force the issue - point it at lines[3] */
+- dz_console = &multi[CONSOLE_LINE];
++ local_irq_save(flags);
++ csr = dz_in(info, DZ_CSR);
++ dz_out(info, DZ_CSR, csr & ~DZ_TIE);
++ tcr = dz_in(info, DZ_TCR);
++ tcr |= 1 << info->line;
++ mask = tcr;
++ dz_out(info, DZ_TCR, mask);
++ iob();
++ local_irq_restore(flags);
+
+- save_flags(flags);
+- cli();
++ while (loops--) {
++ trdy = dz_in(info, DZ_CSR);
++ if (!(trdy & DZ_TRDY))
++ continue;
++ trdy = (trdy & DZ_TLINE) >> 8;
++ if (trdy == info->line)
++ break;
++ mask &= ~(1 << trdy);
++ dz_out(info, DZ_TCR, mask);
++ iob();
++ udelay(2);
++ }
+
++ if (loops) {
++ dz_out(info, DZ_TDR, ch);
++ ret = 0;
++ } else
++ ret = -EAGAIN;
+
+- /* spin our wheels */
+- while (((dz_in(dz_console, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--);
++ dz_out(info, DZ_TCR, tcr);
++ dz_out(info, DZ_CSR, csr);
+
+- /* Actually transmit the character. */
+- dz_out(dz_console, DZ_TDR, tmp);
++ return ret;
++}
+
+- restore_flags(flags);
++static int dz_poll_rx_char(void *handle)
++{
++ return -ENODEV;
++}
++
++int register_dz_hook(unsigned int channel, struct dec_serial_hook *hook)
++{
++ struct dz_serial *info = multi + channel;
++
++ if (info->hook) {
++ printk("%s: line %d has already a hook registered\n",
++ __FUNCTION__, channel);
++
++ return 0;
++ } else {
++ hook->poll_rx_char = dz_poll_rx_char;
++ hook->poll_tx_char = dz_poll_tx_char;
++ info->hook = hook;
++
++ return 1;
++ }
++}
++
++int unregister_dz_hook(unsigned int channel)
++{
++ struct dz_serial *info = &multi[channel];
++
++ if (info->hook) {
++ info->hook = NULL;
++ return 1;
++ } else {
++ printk("%s: trying to unregister hook on line %d,"
++ " but none is registered\n", __FUNCTION__, channel);
++ return 0;
++ }
+ }
++
++#ifdef CONFIG_SERIAL_DEC_CONSOLE
+ /*
+ * -------------------------------------------------------------------
+ * dz_console_print ()
+@@ -1465,17 +1570,19 @@
+ * The console must be locked when we get here.
+ * -------------------------------------------------------------------
+ */
+-static void dz_console_print(struct console *cons,
++static void dz_console_print(struct console *co,
+ const char *str,
+ unsigned int count)
+ {
++ struct dz_serial *info = multi + co->index;
++
+ #ifdef DEBUG_DZ
+ prom_printf((char *) str);
+ #endif
+ while (count--) {
+ if (*str == '\n')
+- dz_console_put_char('\r');
+- dz_console_put_char(*str++);
++ dz_poll_tx_char(info, '\r');
++ dz_poll_tx_char(info, *str++);
+ }
+ }
+
+@@ -1486,12 +1593,12 @@
+
+ static int __init dz_console_setup(struct console *co, char *options)
+ {
++ struct dz_serial *info = multi + co->index;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int cflag = CREAD | HUPCL | CLOCAL;
+ char *s;
+- unsigned short mask, tmp;
+
+ if (options) {
+ baud = simple_strtoul(options, NULL, 10);
+@@ -1542,44 +1649,31 @@
+ }
+ co->cflag = cflag;
+
+- /* TOFIX: force to console line */
+- dz_console = &multi[CONSOLE_LINE];
+ if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100))
+- dz_console->port = KN01_DZ11_BASE;
++ info->port = KN01_DZ11_BASE;
+ else
+- dz_console->port = KN02_DZ11_BASE;
+- dz_console->line = CONSOLE_LINE;
++ info->port = KN02_DZ11_BASE;
++ info->line = co->index;
+
+- dz_out(dz_console, DZ_CSR, DZ_CLR);
+- while ((tmp = dz_in(dz_console, DZ_CSR)) & DZ_CLR);
++ dz_out(info, DZ_CSR, DZ_CLR);
++ while (dz_in(info, DZ_CSR) & DZ_CLR);
+
+ /* enable scanning */
+- dz_out(dz_console, DZ_CSR, DZ_MSE);
++ dz_out(info, DZ_CSR, DZ_MSE);
+
+ /* Set up flags... */
+- dz_console->cflags = 0;
+- dz_console->cflags |= DZ_B9600;
+- dz_console->cflags |= DZ_CS8;
+- dz_console->cflags |= DZ_PARENB;
+- dz_out(dz_console, DZ_LPR, dz_console->cflags);
+-
+- mask = 1 << dz_console->line;
+- tmp = dz_in(dz_console, DZ_TCR); /* read the TX flag */
+- if (!(tmp & mask)) {
+- tmp |= mask; /* set the TX flag */
+- dz_out(dz_console, DZ_TCR, tmp);
+- }
++ dz_out(info, DZ_LPR, cflag | info->line);
++
+ return 0;
+ }
+
+-static struct console dz_sercons =
+-{
+- .name = "ttyS",
+- .write = dz_console_print,
+- .device = dz_console_device,
+- .setup = dz_console_setup,
+- .flags = CON_CONSDEV | CON_PRINTBUFFER,
+- .index = CONSOLE_LINE,
++static struct console dz_sercons = {
++ .name = "ttyS",
++ .write = dz_console_print,
++ .device = dz_console_device,
++ .setup = dz_console_setup,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
+ };
+
+ void __init dz_serial_console_init(void)
+diff -Nur linux-2.4.32-rc1/drivers/char/dz.h linux-2.4.32-rc1.mips/drivers/char/dz.h
+--- linux-2.4.32-rc1/drivers/char/dz.h 2002-08-03 02:39:43.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/char/dz.h 2004-09-28 02:53:01.000000000 +0200
+@@ -10,6 +10,8 @@
+ #ifndef DZ_SERIAL_H
+ #define DZ_SERIAL_H
+
++#include <asm/dec/serial.h>
++
+ #define SERIAL_MAGIC 0x5301
+
+ /*
+@@ -17,6 +19,7 @@
+ */
+ #define DZ_TRDY 0x8000 /* Transmitter empty */
+ #define DZ_TIE 0x4000 /* Transmitter Interrupt Enable */
++#define DZ_TLINE 0x0300 /* Transmitter Line Number */
+ #define DZ_RDONE 0x0080 /* Receiver data ready */
+ #define DZ_RIE 0x0040 /* Receive Interrupt Enable */
+ #define DZ_MSE 0x0020 /* Master Scan Enable */
+@@ -37,19 +40,30 @@
+ #define UCHAR(x) (unsigned char)(x & DZ_RBUF_MASK)
+
+ /*
+- * Definitions for the Transmit Register.
++ * Definitions for the Transmit Control Register.
+ */
+ #define DZ_LINE_KEYBOARD 0x0001
+ #define DZ_LINE_MOUSE 0x0002
+ #define DZ_LINE_MODEM 0x0004
+ #define DZ_LINE_PRINTER 0x0008
+
++#define DZ_MODEM_RTS 0x0800 /* RTS for the modem line (2) */
+ #define DZ_MODEM_DTR 0x0400 /* DTR for the modem line (2) */
++#define DZ_PRINT_RTS 0x0200 /* RTS for the printer line (3) */
++#define DZ_PRINT_DTR 0x0100 /* DTR for the printer line (3) */
++#define DZ_LNENB 0x000f /* Transmitter Line Enable */
+
+ /*
+ * Definitions for the Modem Status Register.
+ */
++#define DZ_MODEM_RI 0x0800 /* RI for the modem line (2) */
++#define DZ_MODEM_CD 0x0400 /* CD for the modem line (2) */
+ #define DZ_MODEM_DSR 0x0200 /* DSR for the modem line (2) */
++#define DZ_MODEM_CTS 0x0100 /* CTS for the modem line (2) */
++#define DZ_PRINT_RI 0x0008 /* RI for the printer line (2) */
++#define DZ_PRINT_CD 0x0004 /* CD for the printer line (2) */
++#define DZ_PRINT_DSR 0x0002 /* DSR for the printer line (2) */
++#define DZ_PRINT_CTS 0x0001 /* CTS for the printer line (2) */
+
+ /*
+ * Definitions for the Transmit Data Register.
+@@ -115,9 +129,6 @@
+
+ #define DZ_EVENT_WRITE_WAKEUP 0
+
+-#ifndef MIN
+-#define MIN(a,b) ((a) < (b) ? (a) : (b))
+-
+ #define DZ_INITIALIZED 0x80000000 /* Serial port was initialized */
+ #define DZ_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
+ #define DZ_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
+@@ -129,6 +140,7 @@
+ #define DZ_CLOSING_WAIT_INF 0
+ #define DZ_CLOSING_WAIT_NONE 65535
+
++#define DZ_SAK 0x0004 /* Secure Attention Key (Orange book) */
+ #define DZ_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+ #define DZ_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+ #define DZ_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
+@@ -166,79 +178,9 @@
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+
++ struct dec_serial_hook *hook; /* Hook on this channel. */
+ unsigned char is_console; /* flag indicating a serial console */
+ unsigned char is_initialized;
+ };
+
+-static struct dz_serial multi[DZ_NB_PORT]; /* Four serial lines in the DZ chip */
+-static struct dz_serial *dz_console;
+-static struct tty_driver serial_driver, callout_driver;
+-
+-static struct tty_struct *serial_table[DZ_NB_PORT];
+-static struct termios *serial_termios[DZ_NB_PORT];
+-static struct termios *serial_termios_locked[DZ_NB_PORT];
+-
+-static int serial_refcount;
+-
+-/*
+- * tmp_buf is used as a temporary buffer by serial_write. We need to
+- * lock it in case the copy_from_user blocks while swapping in a page,
+- * and some other program tries to do a serial write at the same time.
+- * Since the lock will only come under contention when the system is
+- * swapping and available memory is low, it makes sense to share one
+- * buffer across all the serial ports, since it significantly saves
+- * memory if large numbers of serial ports are open.
+- */
+-static unsigned char *tmp_buf;
+-static DECLARE_MUTEX(tmp_buf_sem);
+-
+-static char *dz_name = "DECstation DZ serial driver version ";
+-static char *dz_version = "1.02";
+-
+-static inline unsigned short dz_in (struct dz_serial *, unsigned);
+-static inline void dz_out (struct dz_serial *, unsigned, unsigned short);
+-
+-static inline void dz_sched_event (struct dz_serial *, int);
+-static inline void receive_chars (struct dz_serial *);
+-static inline void transmit_chars (struct dz_serial *);
+-static inline void check_modem_status (struct dz_serial *);
+-
+-static void dz_stop (struct tty_struct *);
+-static void dz_start (struct tty_struct *);
+-static void dz_interrupt (int, void *, struct pt_regs *);
+-static void do_serial_bh (void);
+-static void do_softint (void *);
+-static void do_serial_hangup (void *);
+-static void change_speed (struct dz_serial *);
+-static void dz_flush_chars (struct tty_struct *);
+-static void dz_console_print (struct console *, const char *, unsigned int);
+-static void dz_flush_buffer (struct tty_struct *);
+-static void dz_throttle (struct tty_struct *);
+-static void dz_unthrottle (struct tty_struct *);
+-static void dz_send_xchar (struct tty_struct *, char);
+-static void shutdown (struct dz_serial *);
+-static void send_break (struct dz_serial *, int);
+-static void dz_set_termios (struct tty_struct *, struct termios *);
+-static void dz_close (struct tty_struct *, struct file *);
+-static void dz_hangup (struct tty_struct *);
+-static void show_serial_version (void);
+-
+-static int dz_write (struct tty_struct *, int, const unsigned char *, int);
+-static int dz_write_room (struct tty_struct *);
+-static int dz_chars_in_buffer (struct tty_struct *);
+-static int startup (struct dz_serial *);
+-static int get_serial_info (struct dz_serial *, struct serial_struct *);
+-static int set_serial_info (struct dz_serial *, struct serial_struct *);
+-static int get_lsr_info (struct dz_serial *, unsigned int *);
+-static int dz_ioctl (struct tty_struct *, struct file *, unsigned int, unsigned long);
+-static int block_til_ready (struct tty_struct *, struct file *, struct dz_serial *);
+-static int dz_open (struct tty_struct *, struct file *);
+-
+-#ifdef MODULE
+-int init_module (void)
+-void cleanup_module (void)
+-#endif
+-
+-#endif
+-
+ #endif /* DZ_SERIAL_H */
+diff -Nur linux-2.4.32-rc1/drivers/char/ibm_workpad_keymap.map linux-2.4.32-rc1.mips/drivers/char/ibm_workpad_keymap.map
+--- linux-2.4.32-rc1/drivers/char/ibm_workpad_keymap.map 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/char/ibm_workpad_keymap.map 2003-12-20 15:20:44.000000000 +0100
+@@ -0,0 +1,343 @@
++# Keymap for IBM Workpad z50
++# US Mapping
++#
++# by Michael Klar <wyldfier@iname.com>
++#
++# This is a great big mess on account of how the Caps Lock key is handled as
++# LeftShift-RightShift. Right shift key had to be broken out, so don't use
++# use this map file as a basis for other keyboards that don't do the same
++# thing with Caps Lock.
++#
++# This file is subject to the terms and conditions of the GNU General Public
++# License. See the file "COPYING" in the main directory of this archive
++# for more details.
++
++keymaps 0-2,4-5,8,12,32-33,36-37
++strings as usual
++
++keycode 0 = F1 F11 Console_13
++ shiftr keycode 0 = F11
++ shift shiftr keycode 0 = F11
++ control keycode 0 = F1
++ alt keycode 0 = Console_1
++ control alt keycode 0 = Console_1
++keycode 1 = F3 F13 Console_15
++ shiftr keycode 1 = F13
++ shift shiftr keycode 1 = F13
++ control keycode 1 = F3
++ alt keycode 1 = Console_3
++ control alt keycode 1 = Console_3
++keycode 2 = F5 F15 Console_17
++ shiftr keycode 2 = F15
++ shift shiftr keycode 2 = F15
++ control keycode 2 = F5
++ alt keycode 2 = Console_5
++ control alt keycode 2 = Console_5
++keycode 3 = F7 F17 Console_19
++ shiftr keycode 3 = F17
++ shift shiftr keycode 3 = F17
++ control keycode 3 = F7
++ alt keycode 3 = Console_7
++ control alt keycode 3 = Console_7
++keycode 4 = F9 F19 Console_21
++ shiftr keycode 4 = F19
++ shift shiftr keycode 4 = F19
++ control keycode 4 = F9
++ alt keycode 4 = Console_9
++ control alt keycode 4 = Console_9
++#keycode 5 is contrast down
++#keycode 6 is contrast up
++keycode 7 = F11 F11 Console_23
++ shiftr keycode 7 = F11
++ shift shiftr keycode 7 = F11
++ control keycode 7 = F11
++ alt keycode 7 = Console_11
++ control alt keycode 7 = Console_11
++keycode 8 = F2 F12 Console_14
++ shiftr keycode 8 = F12
++ shift shiftr keycode 8 = F12
++ control keycode 8 = F2
++ alt keycode 8 = Console_2
++ control alt keycode 8 = Console_2
++keycode 9 = F4 F14 Console_16
++ shiftr keycode 9 = F14
++ shift shiftr keycode 9 = F14
++ control keycode 9 = F4
++ alt keycode 9 = Console_4
++ control alt keycode 9 = Console_4
++keycode 10 = F6 F16 Console_18
++ shiftr keycode 10 = F16
++ shift shiftr keycode 10 = F16
++ control keycode 10 = F6
++ alt keycode 10 = Console_6
++ control alt keycode 10 = Console_6
++keycode 11 = F8 F18 Console_20
++ shiftr keycode 11 = F18
++ shift shiftr keycode 11 = F18
++ control keycode 11 = F8
++ alt keycode 11 = Console_8
++ control alt keycode 11 = Console_8
++keycode 12 = F10 F20 Console_22
++ shiftr keycode 12 = F20
++ shift shiftr keycode 12 = F20
++ control keycode 12 = F10
++ alt keycode 12 = Console_10
++ control alt keycode 12 = Console_10
++#keycode 13 is brightness down
++#keycode 14 is brightness up
++keycode 15 = F12 F12 Console_24
++ shiftr keycode 15 = F12
++ shift shiftr keycode 15 = F12
++ control keycode 15 = F12
++ alt keycode 15 = Console_12
++ control alt keycode 15 = Console_12
++keycode 16 = apostrophe quotedbl
++ shiftr keycode 16 = quotedbl
++ shift shiftr keycode 16 = quotedbl
++ control keycode 16 = Control_g
++ alt keycode 16 = Meta_apostrophe
++keycode 17 = bracketleft braceleft
++ shiftr keycode 17 = braceleft
++ shift shiftr keycode 17 = braceleft
++ control keycode 17 = Escape
++ alt keycode 17 = Meta_bracketleft
++keycode 18 = minus underscore backslash
++ shiftr keycode 18 = underscore
++ shift shiftr keycode 18 = underscore
++ control keycode 18 = Control_underscore
++ shift control keycode 18 = Control_underscore
++ shiftr control keycode 18 = Control_underscore
++ shift shiftr control keycode 18 = Control_underscore
++ alt keycode 18 = Meta_minus
++keycode 19 = zero parenright braceright
++ shiftr keycode 19 = parenright
++ shift shiftr keycode 19 = parenright
++ alt keycode 19 = Meta_zero
++keycode 20 = p
++ shiftr keycode 20 = +P
++ shift shiftr keycode 20 = +p
++keycode 21 = semicolon colon
++ shiftr keycode 21 = colon
++ shift shiftr keycode 21 = colon
++ alt keycode 21 = Meta_semicolon
++keycode 22 = Up Scroll_Backward
++ shiftr keycode 22 = Scroll_Backward
++ shift shiftr keycode 22 = Scroll_Backward
++ alt keycode 22 = Prior
++keycode 23 = slash question
++ shiftr keycode 23 = question
++ shift shiftr keycode 23 = question
++ control keycode 23 = Delete
++ alt keycode 23 = Meta_slash
++
++keycode 27 = nine parenleft bracketright
++ shiftr keycode 27 = parenleft
++ shift shiftr keycode 27 = parenleft
++ alt keycode 27 = Meta_nine
++keycode 28 = o
++ shiftr keycode 28 = +O
++ shift shiftr keycode 28 = +o
++keycode 29 = l
++ shiftr keycode 29 = +L
++ shift shiftr keycode 29 = +l
++keycode 30 = period greater
++ shiftr keycode 30 = greater
++ shift shiftr keycode 30 = greater
++ control keycode 30 = Compose
++ alt keycode 30 = Meta_period
++
++keycode 32 = Left Decr_Console
++ shiftr keycode 32 = Decr_Console
++ shift shiftr keycode 32 = Decr_Console
++ alt keycode 32 = Home
++keycode 33 = bracketright braceright asciitilde
++ shiftr keycode 33 = braceright
++ shift shiftr keycode 33 = braceright
++ control keycode 33 = Control_bracketright
++ alt keycode 33 = Meta_bracketright
++keycode 34 = equal plus
++ shiftr keycode 34 = plus
++ shift shiftr keycode 34 = plus
++ alt keycode 34 = Meta_equal
++keycode 35 = eight asterisk bracketleft
++ shiftr keycode 35 = asterisk
++ shift shiftr keycode 35 = asterisk
++ control keycode 35 = Delete
++ alt keycode 35 = Meta_eight
++keycode 36 = i
++ shiftr keycode 36 = +I
++ shift shiftr keycode 36 = +i
++keycode 37 = k
++ shiftr keycode 37 = +K
++ shift shiftr keycode 37 = +k
++keycode 38 = comma less
++ shiftr keycode 38 = less
++ shift shiftr keycode 38 = less
++ alt keycode 38 = Meta_comma
++
++keycode 40 = h
++ shiftr keycode 40 = +H
++ shift shiftr keycode 40 = +h
++keycode 41 = y
++ shiftr keycode 41 = +Y
++ shift shiftr keycode 41 = +y
++keycode 42 = six asciicircum
++ shiftr keycode 42 = asciicircum
++ shift shiftr keycode 42 = asciicircum
++ control keycode 42 = Control_asciicircum
++ alt keycode 42 = Meta_six
++keycode 43 = seven ampersand braceleft
++ shiftr keycode 43 = ampersand
++ shift shiftr keycode 43 = ampersand
++ control keycode 43 = Control_underscore
++ alt keycode 43 = Meta_seven
++keycode 44 = u
++ shiftr keycode 44 = +U
++ shift shiftr keycode 44 = +u
++keycode 45 = j
++ shiftr keycode 45 = +J
++ shift shiftr keycode 45 = +j
++keycode 46 = m
++ shiftr keycode 46 = +M
++ shift shiftr keycode 46 = +m
++keycode 47 = n
++ shiftr keycode 47 = +N
++ shift shiftr keycode 47 = +n
++
++# This is the "Backspace" key:
++keycode 49 = Delete Delete
++ shiftr keycode 49 = Delete
++ shift shiftr keycode 49 = Delete
++ control keycode 49 = BackSpace
++ alt keycode 49 = Meta_Delete
++keycode 50 = Num_Lock
++ shift keycode 50 = Bare_Num_Lock
++ shiftr keycode 50 = Bare_Num_Lock
++ shift shiftr keycode 50 = Bare_Num_Lock
++# This is the "Delete" key:
++keycode 51 = Remove
++ control alt keycode 51 = Boot
++
++keycode 53 = backslash bar
++ shiftr keycode 53 = bar
++ shift shiftr keycode 53 = bar
++ control keycode 53 = Control_backslash
++ alt keycode 53 = Meta_backslash
++keycode 54 = Return
++ alt keycode 54 = Meta_Control_m
++keycode 55 = space space
++ shiftr keycode 55 = space
++ shift shiftr keycode 55 = space
++ control keycode 55 = nul
++ alt keycode 55 = Meta_space
++keycode 56 = g
++ shiftr keycode 56 = +G
++ shift shiftr keycode 56 = +g
++keycode 57 = t
++ shiftr keycode 57 = +T
++ shift shiftr keycode 57 = +t
++keycode 58 = five percent
++ shiftr keycode 58 = percent
++ shift shiftr keycode 58 = percent
++ control keycode 58 = Control_bracketright
++ alt keycode 58 = Meta_five
++keycode 59 = four dollar dollar
++ shiftr keycode 59 = dollar
++ shift shiftr keycode 59 = dollar
++ control keycode 59 = Control_backslash
++ alt keycode 59 = Meta_four
++keycode 60 = r
++ shiftr keycode 60 = +R
++ shift shiftr keycode 60 = +r
++keycode 61 = f
++ shiftr keycode 61 = +F
++ shift shiftr keycode 61 = +f
++ altgr keycode 61 = Hex_F
++keycode 62 = v
++ shiftr keycode 62 = +V
++ shift shiftr keycode 62 = +v
++keycode 63 = b
++ shiftr keycode 63 = +B
++ shift shiftr keycode 63 = +b
++ altgr keycode 63 = Hex_B
++
++keycode 67 = three numbersign
++ shiftr keycode 67 = numbersign
++ shift shiftr keycode 67 = numbersign
++ control keycode 67 = Escape
++ alt keycode 67 = Meta_three
++keycode 68 = e
++ shiftr keycode 68 = +E
++ shift shiftr keycode 68 = +e
++ altgr keycode 68 = Hex_E
++keycode 69 = d
++ shiftr keycode 69 = +D
++ shift shiftr keycode 69 = +d
++ altgr keycode 69 = Hex_D
++keycode 70 = c
++ shiftr keycode 70 = +C
++ shift shiftr keycode 70 = +c
++ altgr keycode 70 = Hex_C
++keycode 71 = Right Incr_Console
++ shiftr keycode 71 = Incr_Console
++ shift shiftr keycode 71 = Incr_Console
++ alt keycode 71 = End
++
++keycode 75 = two at at
++ shiftr keycode 75 = at
++ shift shiftr keycode 75 = at
++ control keycode 75 = nul
++ shift control keycode 75 = nul
++ shiftr control keycode 75 = nul
++ shift shiftr control keycode 75 = nul
++ alt keycode 75 = Meta_two
++keycode 76 = w
++ shiftr keycode 76 = +W
++ shift shiftr keycode 76 = +w
++keycode 77 = s
++ shiftr keycode 77 = +S
++ shift shiftr keycode 77 = +s
++keycode 78 = x
++ shiftr keycode 78 = +X
++ shift shiftr keycode 78 = +x
++keycode 79 = Down Scroll_Forward
++ shiftr keycode 79 = Scroll_Forward
++ shift shiftr keycode 79 = Scroll_Forward
++ alt keycode 79 = Next
++keycode 80 = Escape Escape
++ shiftr keycode 80 = Escape
++ shift shiftr keycode 80 = Escape
++ alt keycode 80 = Meta_Escape
++keycode 81 = Tab Tab
++ shiftr keycode 81 = Tab
++ shift shiftr keycode 81 = Tab
++ alt keycode 81 = Meta_Tab
++keycode 82 = grave asciitilde
++ shiftr keycode 82 = asciitilde
++ shift shiftr keycode 82 = asciitilde
++ control keycode 82 = nul
++ alt keycode 82 = Meta_grave
++keycode 83 = one exclam
++ shiftr keycode 83 = exclam
++ shift shiftr keycode 83 = exclam
++ alt keycode 83 = Meta_one
++keycode 84 = q
++ shiftr keycode 84 = +Q
++ shift shiftr keycode 84 = +q
++keycode 85 = a
++ shiftr keycode 85 = +A
++ shift shiftr keycode 85 = +a
++ altgr keycode 85 = Hex_A
++keycode 86 = z
++ shiftr keycode 86 = +Z
++ shift shiftr keycode 86 = +z
++
++# This is the windows key:
++keycode 88 = Decr_Console
++keycode 89 = Shift
++keycode 90 = Control
++keycode 91 = Control
++keycode 92 = Alt
++keycode 93 = AltGr
++keycode 94 = ShiftR
++ shift keycode 94 = Caps_Lock
+diff -Nur linux-2.4.32-rc1/drivers/char/indydog.c linux-2.4.32-rc1.mips/drivers/char/indydog.c
+--- linux-2.4.32-rc1/drivers/char/indydog.c 2003-08-25 13:44:41.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/char/indydog.c 2004-06-22 17:32:07.000000000 +0200
+@@ -1,5 +1,5 @@
+ /*
+- * IndyDog 0.2 A Hardware Watchdog Device for SGI IP22
++ * IndyDog 0.3 A Hardware Watchdog Device for SGI IP22
+ *
+ * (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved.
+ *
+@@ -7,10 +7,10 @@
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+- *
++ *
+ * based on softdog.c by Alan Cox <alan@redhat.com>
+ */
+-
++
+ #include <linux/module.h>
+ #include <linux/config.h>
+ #include <linux/types.h>
+@@ -19,13 +19,12 @@
+ #include <linux/mm.h>
+ #include <linux/miscdevice.h>
+ #include <linux/watchdog.h>
+-#include <linux/smp_lock.h>
+ #include <linux/init.h>
+ #include <asm/uaccess.h>
+ #include <asm/sgi/mc.h>
+
+-static unsigned long indydog_alive;
+-static int expect_close = 0;
++#define PFX "indydog: "
++static int indydog_alive;
+
+ #ifdef CONFIG_WATCHDOG_NOWAYOUT
+ static int nowayout = 1;
+@@ -33,10 +32,30 @@
+ static int nowayout = 0;
+ #endif
+
++#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
++
+ MODULE_PARM(nowayout,"i");
+ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+-static inline void indydog_ping(void)
++static void indydog_start(void)
++{
++ u32 mc_ctrl0 = sgimc->cpuctrl0;
++
++ mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG;
++ sgimc->cpuctrl0 = mc_ctrl0;
++}
++
++static void indydog_stop(void)
++{
++ u32 mc_ctrl0 = sgimc->cpuctrl0;
++
++ mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
++ sgimc->cpuctrl0 = mc_ctrl0;
++
++ printk(KERN_INFO PFX "Stopped watchdog timer.\n");
++}
++
++static void indydog_ping(void)
+ {
+ sgimc->watchdogt = 0;
+ }
+@@ -46,18 +65,14 @@
+ */
+ static int indydog_open(struct inode *inode, struct file *file)
+ {
+- u32 mc_ctrl0;
+-
+- if (test_and_set_bit(0,&indydog_alive))
++ if (indydog_alive)
+ return -EBUSY;
+
+- if (nowayout) {
++ if (nowayout)
+ MOD_INC_USE_COUNT;
+- }
+
+ /* Activate timer */
+- mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG;
+- sgimc->cpuctrl0 = mc_ctrl0;
++ indydog_start();
+ indydog_ping();
+
+ indydog_alive = 1;
+@@ -69,63 +84,48 @@
+ static int indydog_release(struct inode *inode, struct file *file)
+ {
+ /* Shut off the timer.
+- * Lock it in if it's a module and we set nowayout. */
+- lock_kernel();
+- if (expect_close) {
+- u32 mc_ctrl0 = sgimc->cpuctrl0;
++ * Lock it in if it's a module and we defined ...NOWAYOUT */
++ if (!nowayout) {
++ u32 mc_ctrl0 = sgimc->cpuctrl0;
+ mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
+ sgimc->cpuctrl0 = mc_ctrl0;
+ printk(KERN_INFO "Stopped watchdog timer.\n");
+- } else
+- printk(KERN_CRIT "WDT device closed unexpectedly. WDT will not stop!\n");
+- clear_bit(0, &indydog_alive);
+- unlock_kernel();
++ }
++ indydog_alive = 0;
+
+ return 0;
+ }
+
+ static ssize_t indydog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
+ {
+- /* Can't seek (pwrite) on this device */
++ /* Can't seek (pwrite) on this device */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+- /*
+- * Refresh the timer.
+- */
++ /* Refresh the timer. */
+ if (len) {
+- if (!nowayout) {
+- size_t i;
+-
+- /* In case it was set long ago */
+- expect_close = 0;
+-
+- for (i = 0; i != len; i++) {
+- char c;
+- if (get_user(c, data + i))
+- return -EFAULT;
+- if (c == 'V')
+- expect_close = 1;
+- }
+- }
+ indydog_ping();
+- return 1;
+ }
+- return 0;
++ return len;
+ }
+
+ static int indydog_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+ {
++ int options, retval = -EINVAL;
+ static struct watchdog_info ident = {
+- options: WDIOF_MAGICCLOSE,
+- identity: "Hardware Watchdog for SGI IP22",
++ .options = WDIOF_KEEPALIVEPING |
++ WDIOF_MAGICCLOSE,
++ .firmware_version = 0,
++ .identity = "Hardware Watchdog for SGI IP22",
+ };
++
+ switch (cmd) {
+ default:
+ return -ENOIOCTLCMD;
+ case WDIOC_GETSUPPORT:
+- if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
++ if (copy_to_user((struct watchdog_info *)arg,
++ &ident, sizeof(ident)))
+ return -EFAULT;
+ return 0;
+ case WDIOC_GETSTATUS:
+@@ -134,31 +134,53 @@
+ case WDIOC_KEEPALIVE:
+ indydog_ping();
+ return 0;
++ case WDIOC_GETTIMEOUT:
++ return put_user(WATCHDOG_TIMEOUT,(int *)arg);
++ case WDIOC_SETOPTIONS:
++ {
++ if (get_user(options, (int *)arg))
++ return -EFAULT;
++
++ if (options & WDIOS_DISABLECARD) {
++ indydog_stop();
++ retval = 0;
++ }
++
++ if (options & WDIOS_ENABLECARD) {
++ indydog_start();
++ retval = 0;
++ }
++
++ return retval;
++ }
+ }
+ }
+
+ static struct file_operations indydog_fops = {
+- owner: THIS_MODULE,
+- write: indydog_write,
+- ioctl: indydog_ioctl,
+- open: indydog_open,
+- release: indydog_release,
++ .owner = THIS_MODULE,
++ .write = indydog_write,
++ .ioctl = indydog_ioctl,
++ .open = indydog_open,
++ .release = indydog_release,
+ };
+
+ static struct miscdevice indydog_miscdev = {
+- minor: WATCHDOG_MINOR,
+- name: "watchdog",
+- fops: &indydog_fops,
++ .minor = WATCHDOG_MINOR,
++ .name = "watchdog",
++ .fops = &indydog_fops,
+ };
+
+-static const char banner[] __initdata = KERN_INFO "Hardware Watchdog Timer for SGI IP22: 0.2\n";
++static char banner[] __initdata =
++ KERN_INFO PFX "Hardware Watchdog Timer for SGI IP22: 0.3\n";
+
+ static int __init watchdog_init(void)
+ {
+ int ret = misc_register(&indydog_miscdev);
+-
+- if (ret)
++ if (ret) {
++ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
++ WATCHDOG_MINOR, ret);
+ return ret;
++ }
+
+ printk(banner);
+
+@@ -172,4 +194,7 @@
+
+ module_init(watchdog_init);
+ module_exit(watchdog_exit);
++
++MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
++MODULE_DESCRIPTION("Hardware Watchdog Device for SGI IP22");
+ MODULE_LICENSE("GPL");
+diff -Nur linux-2.4.32-rc1/drivers/char/ip27-rtc.c linux-2.4.32-rc1.mips/drivers/char/ip27-rtc.c
+--- linux-2.4.32-rc1/drivers/char/ip27-rtc.c 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/char/ip27-rtc.c 2004-04-06 03:35:30.000000000 +0200
+@@ -44,6 +44,7 @@
+ #include <asm/sn/klconfig.h>
+ #include <asm/sn/sn0/ip27.h>
+ #include <asm/sn/sn0/hub.h>
++#include <asm/sn/sn_private.h>
+
+ static int rtc_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+@@ -209,11 +210,8 @@
+
+ static int __init rtc_init(void)
+ {
+- nasid_t nid;
+-
+- nid = get_nasid();
+ rtc = (struct m48t35_rtc *)
+- (KL_CONFIG_CH_CONS_INFO(nid)->memory_base + IOC3_BYTEBUS_DEV0);
++ (KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base + IOC3_BYTEBUS_DEV0);
+
+ printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
+ if (misc_register(&rtc_dev)) {
+@@ -325,3 +323,7 @@
+
+ rtc_tm->tm_mon--;
+ }
++
++MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
++MODULE_DESCRIPTION("SGI IP27 M48T35 RTC driver");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.4.32-rc1/drivers/char/Makefile linux-2.4.32-rc1.mips/drivers/char/Makefile
+--- linux-2.4.32-rc1/drivers/char/Makefile 2004-08-08 01:26:04.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/char/Makefile 2005-02-11 22:09:56.000000000 +0100
+@@ -48,7 +48,12 @@
+ KEYBD =
+ endif
+ ifeq ($(CONFIG_VR41XX_KIU),y)
+- KEYMAP =
++ ifeq ($(CONFIG_IBM_WORKPAD),y)
++ KEYMAP = ibm_workpad_keymap.o
++ endif
++ ifeq ($(CONFIG_VICTOR_MPC30X),y)
++ KEYMAP = victor_mpc30x_keymap.o
++ endif
+ KEYBD = vr41xx_keyb.o
+ endif
+ endif
+@@ -251,7 +256,6 @@
+ obj-$(CONFIG_RTC) += rtc.o
+ obj-$(CONFIG_GEN_RTC) += genrtc.o
+ obj-$(CONFIG_EFI_RTC) += efirtc.o
+-obj-$(CONFIG_SGI_DS1286) += ds1286.o
+ obj-$(CONFIG_MIPS_RTC) += mips_rtc.o
+ obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
+ ifeq ($(CONFIG_PPC),)
+@@ -259,6 +263,7 @@
+ endif
+ obj-$(CONFIG_TOSHIBA) += toshiba.o
+ obj-$(CONFIG_I8K) += i8k.o
++obj-$(CONFIG_DS1286) += ds1286.o
+ obj-$(CONFIG_DS1620) += ds1620.o
+ obj-$(CONFIG_DS1742) += ds1742.o
+ obj-$(CONFIG_INTEL_RNG) += i810_rng.o
+@@ -269,6 +274,7 @@
+
+ obj-$(CONFIG_ITE_GPIO) += ite_gpio.o
+ obj-$(CONFIG_AU1X00_GPIO) += au1000_gpio.o
++obj-$(CONFIG_AU1550_PSC_SPI) += au1550_psc_spi.o
+ obj-$(CONFIG_AU1X00_USB_TTY) += au1000_usbtty.o
+ obj-$(CONFIG_AU1X00_USB_RAW) += au1000_usbraw.o
+ obj-$(CONFIG_COBALT_LCD) += lcd.o
+@@ -353,3 +359,9 @@
+
+ qtronixmap.c: qtronixmap.map
+ set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
++
++ibm_workpad_keymap.c: ibm_workpad_keymap.map
++ set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
++
++victor_mpc30x_keymap.c: victor_mpc30x_keymap.map
++ set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@
+diff -Nur linux-2.4.32-rc1/drivers/char/mips_rtc.c linux-2.4.32-rc1.mips/drivers/char/mips_rtc.c
+--- linux-2.4.32-rc1/drivers/char/mips_rtc.c 2004-01-05 14:53:56.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/char/mips_rtc.c 2004-06-28 14:54:53.000000000 +0200
+@@ -53,14 +53,6 @@
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+-
+-/*
+- * Check machine
+- */
+-#if !defined(CONFIG_MIPS) || !defined(CONFIG_NEW_TIME_C)
+-#error "This driver is for MIPS machines with CONFIG_NEW_TIME_C defined"
+-#endif
+-
+ #include <asm/time.h>
+
+ static unsigned long rtc_status = 0; /* bitmapped status byte. */
+diff -Nur linux-2.4.32-rc1/drivers/char/sb1250_duart.c linux-2.4.32-rc1.mips/drivers/char/sb1250_duart.c
+--- linux-2.4.32-rc1/drivers/char/sb1250_duart.c 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/char/sb1250_duart.c 2004-09-17 01:25:44.000000000 +0200
+@@ -328,10 +328,11 @@
+ if (c <= 0) break;
+
+ if (from_user) {
++ spin_unlock_irqrestore(&us->outp_lock, flags);
+ if (copy_from_user(us->outp_buf + us->outp_tail, buf, c)) {
+- spin_unlock_irqrestore(&us->outp_lock, flags);
+ return -EFAULT;
+ }
++ spin_lock_irqsave(&us->outp_lock, flags);
+ } else {
+ memcpy(us->outp_buf + us->outp_tail, buf, c);
+ }
+@@ -498,9 +499,31 @@
+ duart_set_cflag(us->line, tty->termios->c_cflag);
+ }
+
++static int get_serial_info(uart_state_t *us, struct serial_struct * retinfo) {
++
++ struct serial_struct tmp;
++
++ memset(&tmp, 0, sizeof(tmp));
++
++ tmp.type=PORT_SB1250;
++ tmp.line=us->line;
++ tmp.port=A_DUART_CHANREG(tmp.line,0);
++ tmp.irq=K_INT_UART_0 + tmp.line;
++ tmp.xmit_fifo_size=16; /* fixed by hw */
++ tmp.baud_base=5000000;
++ tmp.io_type=SERIAL_IO_MEM;
++
++ if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
++ return -EFAULT;
++
++ return 0;
++}
++
+ static int duart_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+ {
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++
+ /* if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+ return -ENODEV;*/
+ switch (cmd) {
+@@ -517,7 +540,7 @@
+ printk("Ignoring TIOCMSET\n");
+ break;
+ case TIOCGSERIAL:
+- printk("Ignoring TIOCGSERIAL\n");
++ return get_serial_info(us,(struct serial_struct *) arg);
+ break;
+ case TIOCSSERIAL:
+ printk("Ignoring TIOCSSERIAL\n");
+diff -Nur linux-2.4.32-rc1/drivers/char/serial.c linux-2.4.32-rc1.mips/drivers/char/serial.c
+--- linux-2.4.32-rc1/drivers/char/serial.c 2005-10-24 11:33:29.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/char/serial.c 2005-09-23 22:41:22.000000000 +0200
+@@ -62,6 +62,12 @@
+ * Robert Schwebel <robert@schwebel.de>,
+ * Juergen Beisert <jbeisert@eurodsn.de>,
+ * Theodore Ts'o <tytso@mit.edu>
++ *
++ * 10/00: Added suport for MIPS Atlas board.
++ * 11/00: Hooks for serial kernel debug port support added.
++ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard,
++ * carstenl@mips.com
++ * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
+ */
+
+ static char *serial_version = "5.05c";
+@@ -413,6 +419,22 @@
+ return 0;
+ }
+
++#if defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_SEAD)
++
++#include <asm/mips-boards/atlas.h>
++
++static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
++{
++ return (*(volatile unsigned int *)(mips_io_port_base + ATLAS_UART_REGS_BASE + offset*8) & 0xff);
++}
++
++static _INLINE_ void serial_out(struct async_struct *info, int offset, int value)
++{
++ *(volatile unsigned int *)(mips_io_port_base + ATLAS_UART_REGS_BASE + offset*8) = value;
++}
++
++#else
++
+ static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
+ {
+ switch (info->io_type) {
+@@ -447,6 +469,8 @@
+ outb(value, info->port+offset);
+ }
+ }
++#endif
++
+
+ /*
+ * We used to support using pause I/O for certain machines. We
+diff -Nur linux-2.4.32-rc1/drivers/char/victor_mpc30x_keymap.map linux-2.4.32-rc1.mips/drivers/char/victor_mpc30x_keymap.map
+--- linux-2.4.32-rc1/drivers/char/victor_mpc30x_keymap.map 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/char/victor_mpc30x_keymap.map 2004-02-05 18:04:42.000000000 +0100
+@@ -0,0 +1,102 @@
++# Victor Interlink MP-C303/304 keyboard keymap
++#
++# Copyright (C) 2003 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
++#
++# This file is subject to the terms and conditions of the GNU General Public
++# License. See the file "COPYING" in the main directory of this archive
++# for more details.
++keymaps 0-1,4-5,8-9,12
++alt_is_meta
++strings as usual
++compose as usual for "iso-8859-1"
++
++# First line
++keycode 89 = Escape
++keycode 9 = Delete
++
++# 2nd line
++keycode 73 = one exclam
++keycode 18 = two quotedbl
++keycode 92 = three numbersign
++ control keycode 92 = Escape
++keycode 53 = four dollar
++ control keycode 53 = Control_backslash
++keycode 21 = five percent
++ control keycode 21 = Control_bracketright
++keycode 50 = six ampersand
++ control keycode 50 = Control_underscore
++keycode 48 = seven apostrophe
++keycode 51 = eight parenleft
++keycode 16 = nine parenright
++keycode 80 = zero asciitilde
++ control keycode 80 = nul
++keycode 49 = minus equal
++keycode 30 = asciicircum asciitilde
++ control keycode 30 = Control_asciicircum
++keycode 5 = backslash bar
++ control keycode 5 = Control_backslash
++keycode 13 = BackSpace
++# 3rd line
++keycode 57 = Tab
++keycode 74 = q
++keycode 26 = w
++keycode 81 = e
++keycode 29 = r
++keycode 37 = t
++keycode 45 = y
++keycode 72 = u
++keycode 24 = i
++keycode 32 = o
++keycode 41 = p
++keycode 1 = at grave
++ control keycode 1 = nul
++keycode 54 = bracketleft braceleft
++keycode 63 = Return
++ alt keycode 63 = Meta_Control_m
++# 4th line
++keycode 23 = Caps_Lock
++keycode 34 = a
++keycode 66 = s
++keycode 52 = d
++keycode 20 = f
++keycode 84 = g
++keycode 67 = h
++keycode 64 = j
++keycode 17 = k
++keycode 83 = l
++keycode 22 = semicolon plus
++keycode 61 = colon asterisk
++ control keycode 61 = Control_g
++keycode 65 = bracketright braceright
++ control keycode 65 = Control_bracketright
++# 5th line
++keycode 91 = Shift
++keycode 76 = z
++keycode 68 = x
++keycode 28 = c
++keycode 36 = v
++keycode 44 = b
++keycode 19 = n
++keycode 27 = m
++keycode 35 = comma less
++keycode 3 = period greater
++ control keycode 3 = Compose
++keycode 38 = slash question
++ control keycode 38 = Delete
++ shift control keycode 38 = Delete
++keycode 6 = backslash underscore
++ control keycode 6 = Control_backslash
++keycode 55 = Up
++ alt keycode 55 = PageUp
++keycode 14 = Shift
++# 6th line
++keycode 56 = Control
++keycode 42 = Alt
++keycode 33 = space
++ control keycode 33 = nul
++keycode 7 = Left
++ alt keycode 7 = Home
++keycode 31 = Down
++ alt keycode 31 = PageDown
++keycode 47 = Right
++ alt keycode 47 = End
+diff -Nur linux-2.4.32-rc1/drivers/char/vr41xx_keyb.c linux-2.4.32-rc1.mips/drivers/char/vr41xx_keyb.c
+--- linux-2.4.32-rc1/drivers/char/vr41xx_keyb.c 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/char/vr41xx_keyb.c 2004-02-17 13:08:55.000000000 +0100
+@@ -308,7 +308,7 @@
+ if (found != 0) {
+ kiu_base = VRC4173_KIU_OFFSET;
+ mkiuintreg = VRC4173_MKIUINTREG_OFFSET;
+- vrc4173_clock_supply(VRC4173_KIU_CLOCK);
++ vrc4173_supply_clock(VRC4173_KIU_CLOCK);
+ }
+ }
+ #endif
+@@ -325,7 +325,7 @@
+
+ if (current_cpu_data.cputype == CPU_VR4111 ||
+ current_cpu_data.cputype == CPU_VR4121)
+- vr41xx_clock_supply(KIU_CLOCK);
++ vr41xx_supply_clock(KIU_CLOCK);
+
+ kiu_writew(KIURST_KIURST, KIURST);
+
+diff -Nur linux-2.4.32-rc1/drivers/i2c/Config.in linux-2.4.32-rc1.mips/drivers/i2c/Config.in
+--- linux-2.4.32-rc1/drivers/i2c/Config.in 2004-04-14 15:05:29.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/i2c/Config.in 2005-02-11 20:49:04.000000000 +0100
+@@ -57,6 +57,10 @@
+ if [ "$CONFIG_SGI_IP22" = "y" ]; then
+ dep_tristate 'I2C SGI interfaces' CONFIG_I2C_ALGO_SGI $CONFIG_I2C
+ fi
++
++ if [ "$CONFIG_SOC_AU1550" = "y" -o "$CONFIG_SOC_AU1200" ]; then
++ dep_tristate 'Au1550/Au1200 SMBus interface' CONFIG_I2C_ALGO_AU1550 $CONFIG_I2C
++ fi
+
+ # This is needed for automatic patch generation: sensors code starts here
+ # This is needed for automatic patch generation: sensors code ends here
+diff -Nur linux-2.4.32-rc1/drivers/i2c/i2c-algo-au1550.c linux-2.4.32-rc1.mips/drivers/i2c/i2c-algo-au1550.c
+--- linux-2.4.32-rc1/drivers/i2c/i2c-algo-au1550.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/i2c/i2c-algo-au1550.c 2005-02-11 20:49:04.000000000 +0100
+@@ -0,0 +1,340 @@
++/*
++ * i2c-algo-au1550.c: SMBus (i2c) driver algorithms for Alchemy PSC interface
++ * Copyright (C) 2004 Embedded Edge, LLC <dan@embeddededge.com>
++ *
++ * The documentation describes this as an SMBus controller, but it doesn't
++ * understand any of the SMBus protocol in hardware. It's really an I2C
++ * controller that could emulate most of the SMBus in software.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++
++#include <asm/au1000.h>
++#include <asm/au1xxx_psc.h>
++
++#include <linux/i2c.h>
++#include <linux/i2c-algo-au1550.h>
++
++static int
++wait_xfer_done(struct i2c_algo_au1550_data *adap)
++{
++ u32 stat;
++ int i;
++ volatile psc_smb_t *sp;
++
++ sp = (volatile psc_smb_t *)(adap->psc_base);
++
++ /* Wait for Tx FIFO Underflow.
++ */
++ for (i = 0; i < adap->xfer_timeout; i++) {
++ stat = sp->psc_smbevnt;
++ au_sync();
++ if ((stat & PSC_SMBEVNT_TU) != 0) {
++ /* Clear it. */
++ sp->psc_smbevnt = PSC_SMBEVNT_TU;
++ au_sync();
++ return 0;
++ }
++ udelay(1);
++ }
++
++ return -ETIMEDOUT;
++}
++
++static int
++wait_ack(struct i2c_algo_au1550_data *adap)
++{
++ u32 stat;
++ volatile psc_smb_t *sp;
++
++ if (wait_xfer_done(adap))
++ return -ETIMEDOUT;
++
++ sp = (volatile psc_smb_t *)(adap->psc_base);
++
++ stat = sp->psc_smbevnt;
++ au_sync();
++
++ if ((stat & (PSC_SMBEVNT_DN | PSC_SMBEVNT_AN | PSC_SMBEVNT_AL)) != 0)
++ return -ETIMEDOUT;
++
++ return 0;
++}
++
++static int
++wait_master_done(struct i2c_algo_au1550_data *adap)
++{
++ u32 stat;
++ int i;
++ volatile psc_smb_t *sp;
++
++ sp = (volatile psc_smb_t *)(adap->psc_base);
++
++ /* Wait for Master Done.
++ */
++ for (i = 0; i < adap->xfer_timeout; i++) {
++ stat = sp->psc_smbevnt;
++ au_sync();
++ if ((stat & PSC_SMBEVNT_MD) != 0)
++ return 0;
++ udelay(1);
++ }
++
++ return -ETIMEDOUT;
++}
++
++static int
++do_address(struct i2c_algo_au1550_data *adap, unsigned int addr, int rd)
++{
++ volatile psc_smb_t *sp;
++ u32 stat;
++
++ sp = (volatile psc_smb_t *)(adap->psc_base);
++
++ /* Reset the FIFOs, clear events.
++ */
++ sp->psc_smbpcr = PSC_SMBPCR_DC;
++ sp->psc_smbevnt = PSC_SMBEVNT_ALLCLR;
++ au_sync();
++ do {
++ stat = sp->psc_smbpcr;
++ au_sync();
++ } while ((stat & PSC_SMBPCR_DC) != 0);
++
++ /* Write out the i2c chip address and specify operation
++ */
++ addr <<= 1;
++ if (rd)
++ addr |= 1;
++
++ /* Put byte into fifo, start up master.
++ */
++ sp->psc_smbtxrx = addr;
++ au_sync();
++ sp->psc_smbpcr = PSC_SMBPCR_MS;
++ au_sync();
++ if (wait_ack(adap))
++ return -EIO;
++ return 0;
++}
++
++static u32
++wait_for_rx_byte(struct i2c_algo_au1550_data *adap, u32 *ret_data)
++{
++ int j;
++ u32 data, stat;
++ volatile psc_smb_t *sp;
++
++ if (wait_xfer_done(adap))
++ return -EIO;
++
++ sp = (volatile psc_smb_t *)(adap->psc_base);
++
++ j = adap->xfer_timeout * 100;
++ do {
++ j--;
++ if (j <= 0)
++ return -EIO;
++
++ stat = sp->psc_smbstat;
++ au_sync();
++ if ((stat & PSC_SMBSTAT_RE) == 0)
++ j = 0;
++ else
++ udelay(1);
++ } while (j > 0);
++ data = sp->psc_smbtxrx;
++ au_sync();
++ *ret_data = data;
++
++ return 0;
++}
++
++static int
++i2c_read(struct i2c_algo_au1550_data *adap, unsigned char *buf,
++ unsigned int len)
++{
++ int i;
++ u32 data;
++ volatile psc_smb_t *sp;
++
++ if (len == 0)
++ return 0;
++
++ /* A read is performed by stuffing the transmit fifo with
++ * zero bytes for timing, waiting for bytes to appear in the
++ * receive fifo, then reading the bytes.
++ */
++
++ sp = (volatile psc_smb_t *)(adap->psc_base);
++
++ i = 0;
++ while (i < (len-1)) {
++ sp->psc_smbtxrx = 0;
++ au_sync();
++ if (wait_for_rx_byte(adap, &data))
++ return -EIO;
++
++ buf[i] = data;
++ i++;
++ }
++
++ /* The last byte has to indicate transfer done.
++ */
++ sp->psc_smbtxrx = PSC_SMBTXRX_STP;
++ au_sync();
++ if (wait_master_done(adap))
++ return -EIO;
++
++ data = sp->psc_smbtxrx;
++ au_sync();
++ buf[i] = data;
++ return 0;
++}
++
++static int
++i2c_write(struct i2c_algo_au1550_data *adap, unsigned char *buf,
++ unsigned int len)
++{
++ int i;
++ u32 data;
++ volatile psc_smb_t *sp;
++
++ if (len == 0)
++ return 0;
++
++ sp = (volatile psc_smb_t *)(adap->psc_base);
++
++ i = 0;
++ while (i < (len-1)) {
++ data = buf[i];
++ sp->psc_smbtxrx = data;
++ au_sync();
++ if (wait_ack(adap))
++ return -EIO;
++ i++;
++ }
++
++ /* The last byte has to indicate transfer done.
++ */
++ data = buf[i];
++ data |= PSC_SMBTXRX_STP;
++ sp->psc_smbtxrx = data;
++ au_sync();
++ if (wait_master_done(adap))
++ return -EIO;
++ return 0;
++}
++
++static int
++au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
++{
++ struct i2c_algo_au1550_data *adap = i2c_adap->algo_data;
++ struct i2c_msg *p;
++ int i, err = 0;
++
++ for (i = 0; !err && i < num; i++) {
++ p = &msgs[i];
++ err = do_address(adap, p->addr, p->flags & I2C_M_RD);
++ if (err || !p->len)
++ continue;
++ if (p->flags & I2C_M_RD)
++ err = i2c_read(adap, p->buf, p->len);
++ else
++ err = i2c_write(adap, p->buf, p->len);
++ }
++
++ /* Return the number of messages processed, or the error code.
++ */
++ if (err == 0)
++ err = num;
++ return err;
++}
++
++static u32
++au1550_func(struct i2c_adapter *adap)
++{
++ return I2C_FUNC_I2C;
++}
++
++static struct i2c_algorithm au1550_algo = {
++ .name = "Au1550 algorithm",
++ .id = I2C_ALGO_AU1550,
++ .master_xfer = au1550_xfer,
++ .functionality = au1550_func,
++};
++
++/*
++ * registering functions to load algorithms at runtime
++ * Prior to calling us, the 50MHz clock frequency and routing
++ * must have been set up for the PSC indicated by the adapter.
++ */
++int
++i2c_au1550_add_bus(struct i2c_adapter *i2c_adap)
++{
++ struct i2c_algo_au1550_data *adap = i2c_adap->algo_data;
++ volatile psc_smb_t *sp;
++ u32 stat;
++
++ i2c_adap->algo = &au1550_algo;
++
++ /* Now, set up the PSC for SMBus PIO mode.
++ */
++ sp = (volatile psc_smb_t *)(adap->psc_base);
++ sp->psc_ctrl = PSC_CTRL_DISABLE;
++ au_sync();
++ sp->psc_sel = PSC_SEL_PS_SMBUSMODE;
++ sp->psc_smbcfg = 0;
++ au_sync();
++ sp->psc_ctrl = PSC_CTRL_ENABLE;
++ au_sync();
++ do {
++ stat = sp->psc_smbstat;
++ au_sync();
++ } while ((stat & PSC_SMBSTAT_SR) == 0);
++
++ sp->psc_smbcfg = (PSC_SMBCFG_RT_FIFO8 | PSC_SMBCFG_TT_FIFO8 |
++ PSC_SMBCFG_DD_DISABLE);
++
++ /* Divide by 8 to get a 6.25 MHz clock. The later protocol
++ * timings are based on this clock.
++ */
++ sp->psc_smbcfg |= PSC_SMBCFG_SET_DIV(PSC_SMBCFG_DIV2);
++ sp->psc_smbmsk = PSC_SMBMSK_ALLMASK;
++ au_sync();
++
++ /* Set the protocol timer values. See Table 71 in the
++ * Au1550 Data Book for standard timing values.
++ */
++ sp->psc_smbtmr = PSC_SMBTMR_SET_TH(2) | PSC_SMBTMR_SET_PS(15) | \
++ PSC_SMBTMR_SET_PU(11) | PSC_SMBTMR_SET_SH(11) | \
++ PSC_SMBTMR_SET_SU(11) | PSC_SMBTMR_SET_CL(15) | \
++ PSC_SMBTMR_SET_CH(11);
++ au_sync();
++
++ sp->psc_smbcfg |= PSC_SMBCFG_DE_ENABLE;
++ do {
++ stat = sp->psc_smbstat;
++ au_sync();
++ } while ((stat & PSC_SMBSTAT_DR) == 0);
++
++ return i2c_add_adapter(i2c_adap);
++}
++
++
++int
++i2c_au1550_del_bus(struct i2c_adapter *adap)
++{
++ return i2c_del_adapter(adap);
++}
++
++EXPORT_SYMBOL(i2c_au1550_add_bus);
++EXPORT_SYMBOL(i2c_au1550_del_bus);
++
++MODULE_AUTHOR("Dan Malek <dan@embeddededge.com>");
++MODULE_DESCRIPTION("SMBus Au1550 algorithm");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.4.32-rc1/drivers/i2c/i2c-au1550.c linux-2.4.32-rc1.mips/drivers/i2c/i2c-au1550.c
+--- linux-2.4.32-rc1/drivers/i2c/i2c-au1550.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/i2c/i2c-au1550.c 2005-02-11 20:49:04.000000000 +0100
+@@ -0,0 +1,154 @@
++/*
++ * i2c-au1550.c: SMBus (i2c) adapter for Alchemy PSC interface
++ * Copyright (C) 2004 Embedded Edge, LLC <dan@embeddededge.com>
++ *
++ * This is just a skeleton adapter to use with the Au1550 PSC
++ * algorithm. It was developed for the Pb1550, but will work with
++ * any Au1550 board that has a similar PSC configuration.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++
++#include <asm/au1000.h>
++#include <asm/au1xxx_psc.h>
++#if defined( CONFIG_MIPS_PB1550 )
++ #include <asm/pb1550.h>
++#endif
++#if defined( CONFIG_MIPS_PB1200 )
++ #include <asm/pb1200.h>
++#endif
++#if defined( CONFIG_MIPS_DB1200 )
++ #include <asm/db1200.h>
++#endif
++#if defined( CONFIG_MIPS_FICMMP )
++ #include <asm/ficmmp.h>
++#endif
++
++#include <linux/i2c.h>
++#include <linux/i2c-algo-au1550.h>
++
++
++
++static int
++pb1550_reg(struct i2c_client *client)
++{
++ return 0;
++}
++
++static int
++pb1550_unreg(struct i2c_client *client)
++{
++ return 0;
++}
++
++static void
++pb1550_inc_use(struct i2c_adapter *adap)
++{
++#ifdef MODULE
++ MOD_INC_USE_COUNT;
++#endif
++}
++
++static void
++pb1550_dec_use(struct i2c_adapter *adap)
++{
++#ifdef MODULE
++ MOD_DEC_USE_COUNT;
++#endif
++}
++
++static struct i2c_algo_au1550_data pb1550_i2c_info = {
++ SMBUS_PSC_BASE, 200, 200
++};
++
++static struct i2c_adapter pb1550_board_adapter = {
++ name: "pb1550 adapter",
++ id: I2C_HW_AU1550_PSC,
++ algo: NULL,
++ algo_data: &pb1550_i2c_info,
++ inc_use: pb1550_inc_use,
++ dec_use: pb1550_dec_use,
++ client_register: pb1550_reg,
++ client_unregister: pb1550_unreg,
++ client_count: 0,
++};
++
++int __init
++i2c_pb1550_init(void)
++{
++ /* This is where we would set up a 50MHz clock source
++ * and routing. On the Pb1550, the SMBus is PSC2, which
++ * uses a shared clock with USB. This has been already
++ * configured by Yamon as a 48MHz clock, close enough
++ * for our work.
++ */
++ if (i2c_au1550_add_bus(&pb1550_board_adapter) < 0)
++ return -ENODEV;
++
++ return 0;
++}
++
++/* BIG hack to support the control interface on the Wolfson WM8731
++ * audio codec on the Pb1550 board. We get an address and two data
++ * bytes to write, create an i2c message, and send it across the
++ * i2c transfer function. We do this here because we have access to
++ * the i2c adapter structure.
++ */
++static struct i2c_msg wm_i2c_msg; /* We don't want this stuff on the stack */
++static u8 i2cbuf[2];
++
++int
++pb1550_wm_codec_write(u8 addr, u8 reg, u8 val)
++{
++ wm_i2c_msg.addr = addr;
++ wm_i2c_msg.flags = 0;
++ wm_i2c_msg.buf = i2cbuf;
++ wm_i2c_msg.len = 2;
++ i2cbuf[0] = reg;
++ i2cbuf[1] = val;
++
++ return pb1550_board_adapter.algo->master_xfer(&pb1550_board_adapter, &wm_i2c_msg, 1);
++}
++
++/* the next function is needed by DVB driver. */
++int pb1550_i2c_xfer(struct i2c_msg msgs[], int num)
++{
++ return pb1550_board_adapter.algo->master_xfer(&pb1550_board_adapter, msgs, num);
++}
++
++EXPORT_SYMBOL(pb1550_wm_codec_write);
++EXPORT_SYMBOL(pb1550_i2c_xfer);
++
++MODULE_AUTHOR("Dan Malek, Embedded Edge, LLC.");
++MODULE_DESCRIPTION("SMBus adapter Alchemy pb1550");
++MODULE_LICENSE("GPL");
++
++int
++init_module(void)
++{
++ return i2c_pb1550_init();
++}
++
++void
++cleanup_module(void)
++{
++ i2c_au1550_del_bus(&pb1550_board_adapter);
++}
+diff -Nur linux-2.4.32-rc1/drivers/i2c/i2c-core.c linux-2.4.32-rc1.mips/drivers/i2c/i2c-core.c
+--- linux-2.4.32-rc1/drivers/i2c/i2c-core.c 2005-06-01 02:56:56.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/i2c/i2c-core.c 2005-05-23 14:12:30.000000000 +0200
+@@ -1280,6 +1280,9 @@
+ #ifdef CONFIG_I2C_MAX1617
+ extern int i2c_max1617_init(void);
+ #endif
++#ifdef CONFIG_I2C_ALGO_AU1550
++ extern int i2c_pb1550_init(void);
++#endif
+
+ #ifdef CONFIG_I2C_PROC
+ extern int sensors_init(void);
+@@ -1335,6 +1338,10 @@
+ i2c_max1617_init();
+ #endif
+
++#ifdef CONFIG_I2C_ALGO_AU1550
++ i2c_pb1550_init();
++#endif
++
+ /* -------------- proc interface ---- */
+ #ifdef CONFIG_I2C_PROC
+ sensors_init();
+diff -Nur linux-2.4.32-rc1/drivers/i2c/Makefile linux-2.4.32-rc1.mips/drivers/i2c/Makefile
+--- linux-2.4.32-rc1/drivers/i2c/Makefile 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/i2c/Makefile 2005-02-11 20:49:04.000000000 +0100
+@@ -6,7 +6,7 @@
+
+ export-objs := i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \
+ i2c-algo-ite.o i2c-algo-sibyte.o i2c-algo-sgi.o \
+- i2c-proc.o
++ i2c-algo-au1550.o i2c-proc.o i2c-au1550.o
+
+ obj-$(CONFIG_I2C) += i2c-core.o
+ obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
+@@ -25,6 +25,7 @@
+ obj-$(CONFIG_I2C_ALGO_SIBYTE) += i2c-algo-sibyte.o i2c-sibyte.o
+ obj-$(CONFIG_I2C_MAX1617) += i2c-max1617.o
+ obj-$(CONFIG_I2C_ALGO_SGI) += i2c-algo-sgi.o
++obj-$(CONFIG_I2C_ALGO_AU1550) += i2c-algo-au1550.o i2c-au1550.o
+
+ # This is needed for automatic patch generation: sensors code starts here
+ # This is needed for automatic patch generation: sensors code ends here
+diff -Nur linux-2.4.32-rc1/drivers/media/video/indycam.c linux-2.4.32-rc1.mips/drivers/media/video/indycam.c
+--- linux-2.4.32-rc1/drivers/media/video/indycam.c 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/media/video/indycam.c 2004-12-09 21:32:05.000000000 +0100
+@@ -50,13 +50,14 @@
+ 0x80, /* INDYCAM_GAMMA */
+ };
+
+- int err = 0;
+ struct indycam *camera;
+ struct i2c_client *client;
++ int err = 0;
+
+ client = kmalloc(sizeof(*client), GFP_KERNEL);
+- if (!client)
++ if (!client)
+ return -ENOMEM;
++
+ camera = kmalloc(sizeof(*camera), GFP_KERNEL);
+ if (!camera) {
+ err = -ENOMEM;
+@@ -67,7 +68,7 @@
+ client->adapter = adap;
+ client->addr = addr;
+ client->driver = &i2c_driver_indycam;
+- strcpy(client->name, "IndyCam client");
++ strcpy(client->name, "IndyCam client");
+ camera->client = client;
+
+ err = i2c_attach_client(client);
+@@ -75,18 +76,18 @@
+ goto out_free_camera;
+
+ camera->version = i2c_smbus_read_byte_data(client, INDYCAM_VERSION);
+- if (camera->version != CAMERA_VERSION_INDY &&
+- camera->version != CAMERA_VERSION_MOOSE) {
++ if ((camera->version != CAMERA_VERSION_INDY) &&
++ (camera->version != CAMERA_VERSION_MOOSE)) {
+ err = -ENODEV;
+ goto out_detach_client;
+ }
+- printk(KERN_INFO "Indycam v%d.%d detected.\n",
++ printk(KERN_INFO "IndyCam v%d.%d detected.\n",
+ INDYCAM_VERSION_MAJOR(camera->version),
+ INDYCAM_VERSION_MINOR(camera->version));
+
+ err = i2c_master_send(client, initseq, sizeof(initseq));
+ if (err)
+- printk(KERN_INFO "IndyCam initalization failed\n");
++ printk(KERN_ERR "IndyCam initalization failed.\n");
+
+ MOD_INC_USE_COUNT;
+ return 0;
+diff -Nur linux-2.4.32-rc1/drivers/media/video/vino.c linux-2.4.32-rc1.mips/drivers/media/video/vino.c
+--- linux-2.4.32-rc1/drivers/media/video/vino.c 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/media/video/vino.c 2004-12-10 05:02:54.000000000 +0100
+@@ -5,6 +5,8 @@
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
++ * Copyright (C) 2004 Mikael Nousiainen <tmnousia@cc.hut.fi>
++ *
+ */
+
+ #include <linux/module.h>
+@@ -37,13 +39,23 @@
+ #define DEBUG(x...)
+ #endif
+
++/* Channels (who could have guessed) */
++#define VINO_CHAN_NONE 0
++#define VINO_CHAN_A 1
++#define VINO_CHAN_B 2
++
+ /* VINO video size */
+ #define VINO_PAL_WIDTH 768
+ #define VINO_PAL_HEIGHT 576
+ #define VINO_NTSC_WIDTH 646
+ #define VINO_NTSC_HEIGHT 486
+
+-/* set this to some sensible values. note: VINO_MIN_WIDTH has to be 8*x */
++/* Minimum value for Y-clipping (for smaller values the images
++ * will be corrupted) */
++#define VINO_MIN_Y_CLIPPING 2
++
++/* Set these to some sensible values.
++ * Note: the picture width has to be divisible by 8 */
+ #define VINO_MIN_WIDTH 32
+ #define VINO_MIN_HEIGHT 32
+
+@@ -64,9 +76,7 @@
+
+ struct vino_device {
+ struct video_device vdev;
+-#define VINO_CHAN_A 1
+-#define VINO_CHAN_B 2
+- int chan;
++ int chan; /* VINO_CHAN_NONE, VINO_CHAN_A or VINO_CHAN_B */
+ int alpha;
+ /* clipping... */
+ unsigned int left, right, top, bottom;
+@@ -106,7 +116,7 @@
+
+ struct vino_client {
+ struct i2c_client *driver;
+- int owner;
++ int owner; /* VINO_CHAN_NONE, VINO_CHAN_A or VINO_CHAN_B */
+ };
+
+ struct vino_video {
+@@ -362,6 +372,7 @@
+ static int dma_setup(struct vino_device *v)
+ {
+ u32 ctrl, intr;
++ int ofs;
+ struct sgi_vino_channel *ch;
+
+ ch = (v->chan == VINO_CHAN_A) ? &vino->a : &vino->b;
+@@ -377,14 +388,24 @@
+ ch->line_size = v->line_size - 8;
+ /* set the alpha register */
+ ch->alpha = v->alpha;
+- /* set cliping registers */
+- ch->clip_start = VINO_CLIP_ODD(v->top) | VINO_CLIP_EVEN(v->top+1) |
++ /* Set the clipping registers, this is the constant source of fun :)
++ * Y clipping start has to be >= 2 and end has to be start + height/2
++ * The values of top and bottom are even so dividing is not a problem
++ *
++ * The docs say that clipping values for the even field should be
++ * odd_end + something_to_skip_vertical_blanking + some_lines and
++ * even_start + height/2, though the image is good this way also
++ *
++ * TODO: for analog sources (SAA7191), the clipping values are a bit
++ * different and that case isn't yet handled
++ */
++ ofs = VINO_MIN_Y_CLIPPING; /* Should depend on input source */
++ ch->clip_start = VINO_CLIP_ODD(ofs + v->top / 2) |
++ VINO_CLIP_EVEN(ofs + v->top / 2 + 1) |
+ VINO_CLIP_X(v->left);
+- ch->clip_end = VINO_CLIP_ODD(v->bottom) | VINO_CLIP_EVEN(v->bottom+1) |
++ ch->clip_end = VINO_CLIP_ODD(ofs + v->bottom / 2 - 1) |
++ VINO_CLIP_EVEN(ofs + v->bottom / 2) |
+ VINO_CLIP_X(v->right);
+- /* FIXME: end-of-field bug workaround
+- VINO_CLIP_X(VINO_PAL_WIDTH);
+- */
+ /* init the frame rate and norm (full frame rate only for now...) */
+ ch->frame_rate = VINO_FRAMERT_RT(0x1fff) |
+ (get_capture_norm(v) == VIDEO_MODE_PAL ?
+@@ -510,6 +531,7 @@
+ static void vino_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
+ u32 intr, ctrl;
++ int a_eof, b_eof;
+
+ spin_lock(&Vino->vino_lock);
+ ctrl = vino->control;
+@@ -525,12 +547,14 @@
+ vino->control = ctrl;
+ clear_eod(&Vino->chB);
+ }
++ a_eof = intr & VINO_INTSTAT_A_EOF;
++ b_eof = intr & VINO_INTSTAT_B_EOF;
+ vino->intr_status = ~intr;
+ spin_unlock(&Vino->vino_lock);
+- /* FIXME: For now we are assuming that interrupt means that frame is
+- * done. That's not true, but we can live with such brokeness for
+- * a while ;-) */
+- field_done(&Vino->chA);
++ if (a_eof)
++ field_done(&Vino->chA);
++ if (b_eof)
++ field_done(&Vino->chB);
+ }
+
+ static int vino_grab(struct vino_device *v, int frame)
+diff -Nur linux-2.4.32-rc1/drivers/mtd/devices/docprobe.c linux-2.4.32-rc1.mips/drivers/mtd/devices/docprobe.c
+--- linux-2.4.32-rc1/drivers/mtd/devices/docprobe.c 2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/mtd/devices/docprobe.c 2003-06-16 01:42:21.000000000 +0200
+@@ -89,10 +89,10 @@
+ 0xe4000000,
+ #elif defined(CONFIG_MOMENCO_OCELOT)
+ 0x2f000000,
+- 0xff000000,
++ 0xff000000,
+ #elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C)
+- 0xff000000,
+-##else
++ 0xff000000,
++#else
+ #warning Unknown architecture for DiskOnChip. No default probe locations defined
+ #endif
+ 0 };
+diff -Nur linux-2.4.32-rc1/drivers/mtd/devices/ms02-nv.c linux-2.4.32-rc1.mips/drivers/mtd/devices/ms02-nv.c
+--- linux-2.4.32-rc1/drivers/mtd/devices/ms02-nv.c 2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/mtd/devices/ms02-nv.c 2004-07-30 12:22:40.000000000 +0200
+@@ -1,10 +1,10 @@
+ /*
+- * Copyright (c) 2001 Maciej W. Rozycki
++ * Copyright (c) 2001 Maciej W. Rozycki
+ *
+- * 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 free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
+ *
+ * $Id: ms02-nv.c,v 1.2 2003/01/24 14:05:17 dwmw2 Exp $
+ */
+@@ -29,18 +29,18 @@
+
+
+ static char version[] __initdata =
+- "ms02-nv.c: v.1.0.0 13 Aug 2001 Maciej W. Rozycki.\n";
++ "ms02-nv.c: v.1.0.0 13 Aug 2001 Maciej W. Rozycki.\n";
+
+-MODULE_AUTHOR("Maciej W. Rozycki <macro@ds2.pg.gda.pl>");
++MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
+ MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver");
+ MODULE_LICENSE("GPL");
+
+
+ /*
+ * Addresses we probe for an MS02-NV at. Modules may be located
+- * at any 8MB boundary within a 0MB up to 112MB range or at any 32MB
+- * boundary within a 0MB up to 448MB range. We don't support a module
+- * at 0MB, though.
++ * at any 8MiB boundary within a 0MiB up to 112MiB range or at any 32MiB
++ * boundary within a 0MiB up to 448MiB range. We don't support a module
++ * at 0MiB, though.
+ */
+ static ulong ms02nv_addrs[] __initdata = {
+ 0x07000000, 0x06800000, 0x06000000, 0x05800000, 0x05000000,
+@@ -130,7 +130,7 @@
+
+ int ret = -ENODEV;
+
+- /* The module decodes 8MB of address space. */
++ /* The module decodes 8MiB of address space. */
+ mod_res = kmalloc(sizeof(*mod_res), GFP_KERNEL);
+ if (!mod_res)
+ return -ENOMEM;
+@@ -233,7 +233,7 @@
+ goto err_out_csr_res;
+ }
+
+- printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMB.\n",
++ printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMiB.\n",
+ mtd->index, ms02nv_name, addr, size >> 20);
+
+ mp->next = root_ms02nv_mtd;
+@@ -293,12 +293,12 @@
+
+ switch (mips_machtype) {
+ case MACH_DS5000_200:
+- csr = (volatile u32 *)KN02_CSR_ADDR;
++ csr = (volatile u32 *)KN02_CSR_BASE;
+ if (*csr & KN02_CSR_BNK32M)
+ stride = 2;
+ break;
+ case MACH_DS5000_2X0:
+- case MACH_DS5000:
++ case MACH_DS5900:
+ csr = (volatile u32 *)KN03_MCR_BASE;
+ if (*csr & KN03_MCR_BNK32M)
+ stride = 2;
+diff -Nur linux-2.4.32-rc1/drivers/mtd/devices/ms02-nv.h linux-2.4.32-rc1.mips/drivers/mtd/devices/ms02-nv.h
+--- linux-2.4.32-rc1/drivers/mtd/devices/ms02-nv.h 2002-11-29 00:53:13.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/mtd/devices/ms02-nv.h 2004-07-30 12:22:40.000000000 +0200
+@@ -1,32 +1,96 @@
+ /*
+- * Copyright (c) 2001 Maciej W. Rozycki
++ * Copyright (c) 2001, 2003 Maciej W. Rozycki
+ *
+- * 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.
++ * DEC MS02-NV (54-20948-01) battery backed-up NVRAM module for
++ * DECstation/DECsystem 5000/2x0 and DECsystem 5900 and 5900/260
++ * systems.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * $Id: ms02-nv.h,v 1.3 2003/08/19 09:25:36 dwmw2 Exp $
+ */
+
+ #include <linux/ioport.h>
+ #include <linux/mtd/mtd.h>
+
++/*
++ * Addresses are decoded as follows:
++ *
++ * 0x000000 - 0x3fffff SRAM
++ * 0x400000 - 0x7fffff CSR
++ *
++ * Within the SRAM area the following ranges are forced by the system
++ * firmware:
++ *
++ * 0x000000 - 0x0003ff diagnostic area, destroyed upon a reboot
++ * 0x000400 - ENDofRAM storage area, available to operating systems
++ *
++ * but we can't really use the available area right from 0x000400 as
++ * the first word is used by the firmware as a status flag passed
++ * from an operating system. If anything but the valid data magic
++ * ID value is found, the firmware considers the SRAM clean, i.e.
++ * containing no valid data, and disables the battery resulting in
++ * data being erased as soon as power is switched off. So the choice
++ * for the start address of the user-available is 0x001000 which is
++ * nicely page aligned. The area between 0x000404 and 0x000fff may
++ * be used by the driver for own needs.
++ *
++ * The diagnostic area defines two status words to be read by an
++ * operating system, a magic ID to distinguish a MS02-NV board from
++ * anything else and a status information providing results of tests
++ * as well as the size of SRAM available, which can be 1MiB or 2MiB
++ * (that's what the firmware handles; no idea if 2MiB modules ever
++ * existed).
++ *
++ * The firmware only handles the MS02-NV board if installed in the
++ * last (15th) slot, so for any other location the status information
++ * stored in the SRAM cannot be relied upon. But from the hardware
++ * point of view there is no problem using up to 14 such boards in a
++ * system -- only the 1st slot needs to be filled with a DRAM module.
++ * The MS02-NV board is ECC-protected, like other MS02 memory boards.
++ *
++ * The state of the battery as provided by the CSR is reflected on
++ * the two onboard LEDs. When facing the battery side of the board,
++ * with the LEDs at the top left and the battery at the bottom right
++ * (i.e. looking from the back side of the system box), their meaning
++ * is as follows (the system has to be powered on):
++ *
++ * left LED battery disable status: lit = enabled
++ * right LED battery condition status: lit = OK
++ */
++
+ /* MS02-NV iomem register offsets. */
+ #define MS02NV_CSR 0x400000 /* control & status register */
+
++/* MS02-NV CSR status bits. */
++#define MS02NV_CSR_BATT_OK 0x01 /* battery OK */
++#define MS02NV_CSR_BATT_OFF 0x02 /* battery disabled */
++
++
+ /* MS02-NV memory offsets. */
+ #define MS02NV_DIAG 0x0003f8 /* diagnostic status */
+ #define MS02NV_MAGIC 0x0003fc /* MS02-NV magic ID */
+-#define MS02NV_RAM 0x000400 /* general-purpose RAM start */
++#define MS02NV_VALID 0x000400 /* valid data magic ID */
++#define MS02NV_RAM 0x001000 /* user-exposed RAM start */
+
+-/* MS02-NV diagnostic status constants. */
+-#define MS02NV_DIAG_SIZE_MASK 0xf0 /* RAM size mask */
+-#define MS02NV_DIAG_SIZE_SHIFT 0x10 /* RAM size shift (left) */
++/* MS02-NV diagnostic status bits. */
++#define MS02NV_DIAG_TEST 0x01 /* SRAM test done (?) */
++#define MS02NV_DIAG_RO 0x02 /* SRAM r/o test done */
++#define MS02NV_DIAG_RW 0x04 /* SRAM r/w test done */
++#define MS02NV_DIAG_FAIL 0x08 /* SRAM test failed */
++#define MS02NV_DIAG_SIZE_MASK 0xf0 /* SRAM size mask */
++#define MS02NV_DIAG_SIZE_SHIFT 0x10 /* SRAM size shift (left) */
+
+ /* MS02-NV general constants. */
+ #define MS02NV_ID 0x03021966 /* MS02-NV magic ID value */
++#define MS02NV_VALID_ID 0xbd100248 /* valid data magic ID value */
+ #define MS02NV_SLOT_SIZE 0x800000 /* size of the address space
+ decoded by the module */
+
++
+ typedef volatile u32 ms02nv_uint;
+
+ struct ms02nv_private {
+diff -Nur linux-2.4.32-rc1/drivers/mtd/maps/Config.in linux-2.4.32-rc1.mips/drivers/mtd/maps/Config.in
+--- linux-2.4.32-rc1/drivers/mtd/maps/Config.in 2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/mtd/maps/Config.in 2004-02-26 01:46:35.000000000 +0100
+@@ -51,11 +51,26 @@
+ dep_tristate ' Pb1000 MTD support' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000
+ dep_tristate ' Pb1500 MTD support' CONFIG_MTD_PB1500 $CONFIG_MIPS_PB1500
+ dep_tristate ' Pb1100 MTD support' CONFIG_MTD_PB1100 $CONFIG_MIPS_PB1100
++ dep_tristate ' Bosporus MTD support' CONFIG_MTD_BOSPORUS $CONFIG_MIPS_BOSPORUS
++ dep_tristate ' XXS1500 boot flash device' CONFIG_MTD_XXS1500 $CONFIG_MIPS_XXS1500
++ dep_tristate ' MTX-1 flash device' CONFIG_MTD_MTX1 $CONFIG_MIPS_MTX1
+ if [ "$CONFIG_MTD_PB1500" = "y" -o "$CONFIG_MTD_PB1500" = "m" \
+ -o "$CONFIG_MTD_PB1100" = "y" -o "$CONFIG_MTD_PB1100" = "m" ]; then
+ bool ' Pb[15]00 boot flash device' CONFIG_MTD_PB1500_BOOT
+ bool ' Pb[15]00 user flash device (2nd 32MiB bank)' CONFIG_MTD_PB1500_USER
+ fi
++ tristate ' Db1x00 MTD support' CONFIG_MTD_DB1X00
++ if [ "$CONFIG_MTD_DB1X00" = "y" -o "$CONFIG_MTD_DB1X00" = "m" ]; then
++ bool ' Db1x00 boot flash device' CONFIG_MTD_DB1X00_BOOT
++ bool ' Db1x00 user flash device (2nd bank)' CONFIG_MTD_DB1X00_USER
++ fi
++ tristate ' Pb1550 MTD support' CONFIG_MTD_PB1550
++ if [ "$CONFIG_MTD_PB1550" = "y" -o "$CONFIG_MTD_PB1550" = "m" ]; then
++ bool ' Pb1550 Boot Flash' CONFIG_MTD_PB1550_BOOT
++ bool ' Pb1550 User Parameter Flash' CONFIG_MTD_PB1550_USER
++ fi
++ dep_tristate ' Hydrogen 3 MTD support' CONFIG_MTD_HYDROGEN3 $CONFIG_MIPS_HYDROGEN3
++ dep_tristate ' Mirage MTD support' CONFIG_MTD_MIRAGE $CONFIG_MIPS_MIRAGE
+ dep_tristate ' Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board' CONFIG_MTD_CSTM_MIPS_IXX $CONFIG_MTD_CFI $CONFIG_MTD_JEDEC $CONFIG_MTD_PARTITIONS
+ if [ "$CONFIG_MTD_CSTM_MIPS_IXX" = "y" -o "$CONFIG_MTD_CSTM_MIPS_IXX" = "m" ]; then
+ hex ' Physical start address of flash mapping' CONFIG_MTD_CSTM_MIPS_IXX_START 0x8000000
+diff -Nur linux-2.4.32-rc1/drivers/mtd/maps/db1x00-flash.c linux-2.4.32-rc1.mips/drivers/mtd/maps/db1x00-flash.c
+--- linux-2.4.32-rc1/drivers/mtd/maps/db1x00-flash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/mtd/maps/db1x00-flash.c 2005-02-03 07:35:29.000000000 +0100
+@@ -0,0 +1,283 @@
++/*
++ * Flash memory access on Alchemy Db1xxx boards
++ *
++ * (C) 2003 Pete Popov <ppopov@pacbell.net>
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/io.h>
++#include <asm/au1000.h>
++#include <asm/db1x00.h>
++
++#ifdef DEBUG_RW
++#define DBG(x...) printk(x)
++#else
++#define DBG(x...)
++#endif
++
++static unsigned long window_addr;
++static unsigned long window_size;
++static unsigned long flash_size;
++
++__u8 physmap_read8(struct map_info *map, unsigned long ofs)
++{
++ __u8 ret;
++ ret = __raw_readb(map->map_priv_1 + ofs);
++ DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++__u16 physmap_read16(struct map_info *map, unsigned long ofs)
++{
++ __u16 ret;
++ ret = __raw_readw(map->map_priv_1 + ofs);
++ DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++__u32 physmap_read32(struct map_info *map, unsigned long ofs)
++{
++ __u32 ret;
++ ret = __raw_readl(map->map_priv_1 + ofs);
++ DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++ DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to);
++ memcpy_fromio(to, map->map_priv_1 + from, len);
++}
++
++void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++ DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writeb(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++ DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writew(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++ DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writel(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
++{
++ DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from);
++ memcpy_toio(map->map_priv_1 + to, from, len);
++}
++
++static struct map_info db1x00_map = {
++ name: "Db1x00 flash",
++ read8: physmap_read8,
++ read16: physmap_read16,
++ read32: physmap_read32,
++ copy_from: physmap_copy_from,
++ write8: physmap_write8,
++ write16: physmap_write16,
++ write32: physmap_write32,
++ copy_to: physmap_copy_to,
++};
++
++static unsigned char flash_buswidth = 4;
++
++/*
++ * The Db1x boards support different flash densities. We setup
++ * the mtd_partition structures below for default of 64Mbit
++ * flash densities, and override the partitions sizes, if
++ * necessary, after we check the board status register.
++ */
++
++#ifdef DB1X00_BOTH_BANKS
++/* both banks will be used. Combine the first bank and the first
++ * part of the second bank together into a single jffs/jffs2
++ * partition.
++ */
++static struct mtd_partition db1x00_partitions[] = {
++ {
++ name: "User FS",
++ size: 0x1c00000,
++ offset: 0x0000000
++ },{
++ name: "yamon",
++ size: 0x0100000,
++ offset: MTDPART_OFS_APPEND,
++ mask_flags: MTD_WRITEABLE
++ },{
++ name: "raw kernel",
++ size: (0x300000-0x40000), /* last 256KB is yamon env */
++ offset: MTDPART_OFS_APPEND,
++ }
++};
++#elif defined(DB1X00_BOOT_ONLY)
++static struct mtd_partition db1x00_partitions[] = {
++ {
++ name: "User FS",
++ size: 0x00c00000,
++ offset: 0x0000000
++ },{
++ name: "yamon",
++ size: 0x0100000,
++ offset: MTDPART_OFS_APPEND,
++ mask_flags: MTD_WRITEABLE
++ },{
++ name: "raw kernel",
++ size: (0x300000-0x40000), /* last 256KB is yamon env */
++ offset: MTDPART_OFS_APPEND,
++ }
++};
++#elif defined(DB1X00_USER_ONLY)
++static struct mtd_partition db1x00_partitions[] = {
++ {
++ name: "User FS",
++ size: 0x0e00000,
++ offset: 0x0000000
++ },{
++ name: "raw kernel",
++ size: MTDPART_SIZ_FULL,
++ offset: MTDPART_OFS_APPEND,
++ }
++};
++#else
++#error MTD_DB1X00 define combo error /* should never happen */
++#endif
++
++
++#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
++
++static struct mtd_partition *parsed_parts;
++static struct mtd_info *mymtd;
++
++/*
++ * Probe the flash density and setup window address and size
++ * based on user CONFIG options. There are times when we don't
++ * want the MTD driver to be probing the boot or user flash,
++ * so having the option to enable only one bank is important.
++ */
++int setup_flash_params()
++{
++ switch ((bcsr->status >> 14) & 0x3) {
++ case 0: /* 64Mbit devices */
++ flash_size = 0x800000; /* 8MB per part */
++#if defined(DB1X00_BOTH_BANKS)
++ window_addr = 0x1E000000;
++ window_size = 0x2000000;
++#elif defined(DB1X00_BOOT_ONLY)
++ window_addr = 0x1F000000;
++ window_size = 0x1000000;
++#else /* USER ONLY */
++ window_addr = 0x1E000000;
++ window_size = 0x1000000;
++#endif
++ break;
++ case 1:
++ /* 128 Mbit devices */
++ flash_size = 0x1000000; /* 16MB per part */
++#if defined(DB1X00_BOTH_BANKS)
++ window_addr = 0x1C000000;
++ window_size = 0x4000000;
++ /* USERFS from 0x1C00 0000 to 0x1FC0 0000 */
++ db1x00_partitions[0].size = 0x3C00000;
++#elif defined(DB1X00_BOOT_ONLY)
++ window_addr = 0x1E000000;
++ window_size = 0x2000000;
++ /* USERFS from 0x1E00 0000 to 0x1FC0 0000 */
++ db1x00_partitions[0].size = 0x1C00000;
++#else /* USER ONLY */
++ window_addr = 0x1C000000;
++ window_size = 0x2000000;
++ /* USERFS from 0x1C00 0000 to 0x1DE00000 */
++ db1x00_partitions[0].size = 0x1DE0000;
++#endif
++ break;
++ case 2:
++ /* 256 Mbit devices */
++ flash_size = 0x4000000; /* 64MB per part */
++#if defined(DB1X00_BOTH_BANKS)
++ return 1;
++#elif defined(DB1X00_BOOT_ONLY)
++ /* Boot ROM flash bank only; no user bank */
++ window_addr = 0x1C000000;
++ window_size = 0x4000000;
++ /* USERFS from 0x1C00 0000 to 0x1FC00000 */
++ db1x00_partitions[0].size = 0x3C00000;
++#else /* USER ONLY */
++ return 1;
++#endif
++ break;
++ default:
++ return 1;
++ }
++ return 0;
++}
++
++int __init db1x00_mtd_init(void)
++{
++ struct mtd_partition *parts;
++ int nb_parts = 0;
++ char *part_type;
++
++ /* Default flash buswidth */
++ db1x00_map.buswidth = flash_buswidth;
++
++ if (setup_flash_params())
++ return -ENXIO;
++
++ /*
++ * Static partition definition selection
++ */
++ part_type = "static";
++ parts = db1x00_partitions;
++ nb_parts = NB_OF(db1x00_partitions);
++ db1x00_map.size = window_size;
++
++ /*
++ * Now let's probe for the actual flash. Do it here since
++ * specific machine settings might have been set above.
++ */
++ printk(KERN_NOTICE "Db1xxx flash: probing %d-bit flash bus\n",
++ db1x00_map.buswidth*8);
++ db1x00_map.map_priv_1 =
++ (unsigned long)ioremap(window_addr, window_size);
++ mymtd = do_map_probe("cfi_probe", &db1x00_map);
++ if (!mymtd) return -ENXIO;
++ mymtd->module = THIS_MODULE;
++
++ add_mtd_partitions(mymtd, parts, nb_parts);
++ return 0;
++}
++
++static void __exit db1x00_mtd_cleanup(void)
++{
++ if (mymtd) {
++ del_mtd_partitions(mymtd);
++ map_destroy(mymtd);
++ if (parsed_parts)
++ kfree(parsed_parts);
++ }
++}
++
++module_init(db1x00_mtd_init);
++module_exit(db1x00_mtd_cleanup);
++
++MODULE_AUTHOR("Pete Popov");
++MODULE_DESCRIPTION("Db1x00 mtd map driver");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.4.32-rc1/drivers/mtd/maps/hydrogen3-flash.c linux-2.4.32-rc1.mips/drivers/mtd/maps/hydrogen3-flash.c
+--- linux-2.4.32-rc1/drivers/mtd/maps/hydrogen3-flash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/mtd/maps/hydrogen3-flash.c 2004-01-10 23:40:18.000000000 +0100
+@@ -0,0 +1,189 @@
++/*
++ * Flash memory access on Alchemy HydrogenIII boards
++ *
++ * (C) 2003 Pete Popov <ppopov@pacbell.net>
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/io.h>
++#include <asm/au1000.h>
++
++#ifdef DEBUG_RW
++#define DBG(x...) printk(x)
++#else
++#define DBG(x...)
++#endif
++
++#define WINDOW_ADDR 0x1E000000
++#define WINDOW_SIZE 0x02000000
++
++
++__u8 physmap_read8(struct map_info *map, unsigned long ofs)
++{
++ __u8 ret;
++ ret = __raw_readb(map->map_priv_1 + ofs);
++ DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++__u16 physmap_read16(struct map_info *map, unsigned long ofs)
++{
++ __u16 ret;
++ ret = __raw_readw(map->map_priv_1 + ofs);
++ DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++__u32 physmap_read32(struct map_info *map, unsigned long ofs)
++{
++ __u32 ret;
++ ret = __raw_readl(map->map_priv_1 + ofs);
++ DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++ DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to);
++ memcpy_fromio(to, map->map_priv_1 + from, len);
++}
++
++void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++ DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writeb(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++ DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writew(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++ DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writel(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
++{
++ DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from);
++ memcpy_toio(map->map_priv_1 + to, from, len);
++}
++
++static struct map_info hydrogen3_map = {
++ name: "HydrogenIII flash",
++ read8: physmap_read8,
++ read16: physmap_read16,
++ read32: physmap_read32,
++ copy_from: physmap_copy_from,
++ write8: physmap_write8,
++ write16: physmap_write16,
++ write32: physmap_write32,
++ copy_to: physmap_copy_to,
++};
++
++static unsigned char flash_buswidth = 4;
++
++/* MTDPART_OFS_APPEND is vastly preferred to any attempt at statically lining
++ * up the offsets. */
++static struct mtd_partition hydrogen3_partitions[] = {
++ {
++ name: "User FS",
++ size: 0x1c00000,
++ offset: 0x0000000
++ },{
++ name: "yamon",
++ size: 0x0100000,
++ offset: MTDPART_OFS_APPEND,
++ mask_flags: MTD_WRITEABLE
++ },{
++ name: "raw kernel",
++ size: 0x02c0000,
++ offset: MTDPART_OFS_APPEND
++ }
++};
++
++#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
++
++static struct mtd_partition *parsed_parts;
++static struct mtd_info *mymtd;
++
++int __init hydrogen3_mtd_init(void)
++{
++ struct mtd_partition *parts;
++ int nb_parts = 0;
++ char *part_type;
++
++ /* Default flash buswidth */
++ hydrogen3_map.buswidth = flash_buswidth;
++
++ /*
++ * Static partition definition selection
++ */
++ part_type = "static";
++ parts = hydrogen3_partitions;
++ nb_parts = NB_OF(hydrogen3_partitions);
++ hydrogen3_map.size = WINDOW_SIZE;
++
++ /*
++ * Now let's probe for the actual flash. Do it here since
++ * specific machine settings might have been set above.
++ */
++ printk(KERN_NOTICE "HydrogenIII flash: probing %d-bit flash bus\n",
++ hydrogen3_map.buswidth*8);
++ hydrogen3_map.map_priv_1 =
++ (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
++ mymtd = do_map_probe("cfi_probe", &hydrogen3_map);
++ if (!mymtd) return -ENXIO;
++ mymtd->module = THIS_MODULE;
++
++ add_mtd_partitions(mymtd, parts, nb_parts);
++ return 0;
++}
++
++static void __exit hydrogen3_mtd_cleanup(void)
++{
++ if (mymtd) {
++ del_mtd_partitions(mymtd);
++ map_destroy(mymtd);
++ if (parsed_parts)
++ kfree(parsed_parts);
++ }
++}
++
++/*#ifndef MODULE
++
++static int __init _bootflashonly(char *str)
++{
++ bootflashonly = simple_strtol(str, NULL, 0);
++ return 1;
++}
++
++
++__setup("bootflashonly=", _bootflashonly);
++
++#endif*/
++
++
++module_init(hydrogen3_mtd_init);
++module_exit(hydrogen3_mtd_cleanup);
++
++MODULE_PARM(bootflashonly, "i");
++MODULE_PARM_DESC(bootflashonly, "1=use \"boot flash only\"");
++MODULE_AUTHOR("Pete Popov");
++MODULE_DESCRIPTION("HydrogenIII mtd map driver");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.4.32-rc1/drivers/mtd/maps/lasat.c linux-2.4.32-rc1.mips/drivers/mtd/maps/lasat.c
+--- linux-2.4.32-rc1/drivers/mtd/maps/lasat.c 2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/mtd/maps/lasat.c 2003-08-18 04:59:02.000000000 +0200
+@@ -1,15 +1,6 @@
+ /*
+ * Flash device on lasat 100 and 200 boards
+ *
+- * Presumably (C) 2002 Brian Murphy <brian@murphy.dk> or whoever he
+- * works for.
+- *
+- * 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.
+- *
+- * $Id: lasat.c,v 1.1 2003/01/24 14:26:38 dwmw2 Exp $
+- *
+ */
+
+ #include <linux/module.h>
+@@ -21,7 +12,6 @@
+ #include <linux/mtd/partitions.h>
+ #include <linux/config.h>
+ #include <asm/lasat/lasat.h>
+-#include <asm/lasat/lasat_mtd.h>
+
+ static struct mtd_info *mymtd;
+
+@@ -69,30 +59,33 @@
+ }
+
+ static struct map_info sp_map = {
+- .name = "SP flash",
+- .buswidth = 4,
+- .read8 = sp_read8,
+- .read16 = sp_read16,
+- .read32 = sp_read32,
+- .copy_from = sp_copy_from,
+- .write8 = sp_write8,
+- .write16 = sp_write16,
+- .write32 = sp_write32,
+- .copy_to = sp_copy_to
++ name: "SP flash",
++ buswidth: 4,
++ read8: sp_read8,
++ read16: sp_read16,
++ read32: sp_read32,
++ copy_from: sp_copy_from,
++ write8: sp_write8,
++ write16: sp_write16,
++ write32: sp_write32,
++ copy_to: sp_copy_to
+ };
+
+ static struct mtd_partition partition_info[LASAT_MTD_LAST];
+-static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Filesystem", "Config"};
++static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Config", "Filesystem"};
+
+ static int __init init_sp(void)
+ {
+ int i;
++ int nparts = 0;
+ /* this does not play well with the old flash code which
+ * protects and uprotects the flash when necessary */
+ printk(KERN_NOTICE "Unprotecting flash\n");
+ *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit;
+
+- sp_map.map_priv_1 = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER);
++ sp_map.map_priv_1 = ioremap_nocache(
++ lasat_flash_partition_start(LASAT_MTD_BOOTLOADER),
++ lasat_board_info.li_flash_size);
+ sp_map.size = lasat_board_info.li_flash_size;
+
+ printk(KERN_NOTICE "sp flash device: %lx at %lx\n",
+@@ -109,12 +102,15 @@
+
+ for (i=0; i < LASAT_MTD_LAST; i++) {
+ size = lasat_flash_partition_size(i);
+- partition_info[i].size = size;
+- partition_info[i].offset = offset;
+- offset += size;
++ if (size != 0) {
++ nparts++;
++ partition_info[i].size = size;
++ partition_info[i].offset = offset;
++ offset += size;
++ }
+ }
+
+- add_mtd_partitions( mymtd, partition_info, LASAT_MTD_LAST );
++ add_mtd_partitions( mymtd, partition_info, nparts );
+ return 0;
+ }
+
+@@ -124,11 +120,11 @@
+ static void __exit cleanup_sp(void)
+ {
+ if (mymtd) {
+- del_mtd_partitions(mymtd);
+- map_destroy(mymtd);
++ del_mtd_partitions(mymtd);
++ map_destroy(mymtd);
+ }
+ if (sp_map.map_priv_1) {
+- sp_map.map_priv_1 = 0;
++ sp_map.map_priv_1 = 0;
+ }
+ }
+
+diff -Nur linux-2.4.32-rc1/drivers/mtd/maps/Makefile linux-2.4.32-rc1.mips/drivers/mtd/maps/Makefile
+--- linux-2.4.32-rc1/drivers/mtd/maps/Makefile 2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/mtd/maps/Makefile 2004-02-26 01:46:35.000000000 +0100
+@@ -52,7 +52,13 @@
+ obj-$(CONFIG_MTD_PB1000) += pb1xxx-flash.o
+ obj-$(CONFIG_MTD_PB1100) += pb1xxx-flash.o
+ obj-$(CONFIG_MTD_PB1500) += pb1xxx-flash.o
++obj-$(CONFIG_MTD_XXS1500) += xxs1500.o
++obj-$(CONFIG_MTD_MTX1) += mtx-1.o
+ obj-$(CONFIG_MTD_LASAT) += lasat.o
++obj-$(CONFIG_MTD_DB1X00) += db1x00-flash.o
++obj-$(CONFIG_MTD_PB1550) += pb1550-flash.o
++obj-$(CONFIG_MTD_HYDROGEN3) += hydrogen3-flash.o
++obj-$(CONFIG_MTD_BOSPORUS) += pb1xxx-flash.o
+ obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
+ obj-$(CONFIG_MTD_EDB7312) += edb7312.o
+ obj-$(CONFIG_MTD_IMPA7) += impa7.o
+@@ -61,5 +67,6 @@
+ obj-$(CONFIG_MTD_UCLINUX) += uclinux.o
+ obj-$(CONFIG_MTD_NETtel) += nettel.o
+ obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o
++obj-$(CONFIG_MTD_MIRAGE) += mirage-flash.o
+
+ include $(TOPDIR)/Rules.make
+diff -Nur linux-2.4.32-rc1/drivers/mtd/maps/mirage-flash.c linux-2.4.32-rc1.mips/drivers/mtd/maps/mirage-flash.c
+--- linux-2.4.32-rc1/drivers/mtd/maps/mirage-flash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/mtd/maps/mirage-flash.c 2003-12-22 04:37:22.000000000 +0100
+@@ -0,0 +1,194 @@
++/*
++ * Flash memory access on AMD Mirage board.
++ *
++ * (C) 2003 Embedded Edge
++ * based on mirage-flash.c:
++ * (C) 2003 Pete Popov <ppopov@pacbell.net>
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/io.h>
++#include <asm/au1000.h>
++//#include <asm/mirage.h>
++
++#ifdef DEBUG_RW
++#define DBG(x...) printk(x)
++#else
++#define DBG(x...)
++#endif
++
++static unsigned long window_addr;
++static unsigned long window_size;
++static unsigned long flash_size;
++
++__u8 physmap_read8(struct map_info *map, unsigned long ofs)
++{
++ __u8 ret;
++ ret = __raw_readb(map->map_priv_1 + ofs);
++ DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++__u16 physmap_read16(struct map_info *map, unsigned long ofs)
++{
++ __u16 ret;
++ ret = __raw_readw(map->map_priv_1 + ofs);
++ DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++__u32 physmap_read32(struct map_info *map, unsigned long ofs)
++{
++ __u32 ret;
++ ret = __raw_readl(map->map_priv_1 + ofs);
++ DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++ DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to);
++ memcpy_fromio(to, map->map_priv_1 + from, len);
++}
++
++void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++ DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writeb(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++ DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writew(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++ DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writel(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
++{
++ DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from);
++ memcpy_toio(map->map_priv_1 + to, from, len);
++}
++
++static struct map_info mirage_map = {
++ name: "Mirage flash",
++ read8: physmap_read8,
++ read16: physmap_read16,
++ read32: physmap_read32,
++ copy_from: physmap_copy_from,
++ write8: physmap_write8,
++ write16: physmap_write16,
++ write32: physmap_write32,
++ copy_to: physmap_copy_to,
++};
++
++static unsigned char flash_buswidth = 4;
++
++static struct mtd_partition mirage_partitions[] = {
++ {
++ name: "User FS",
++ size: 0x1c00000,
++ offset: 0x0000000
++ },{
++ name: "yamon",
++ size: 0x0100000,
++ offset: MTDPART_OFS_APPEND,
++ mask_flags: MTD_WRITEABLE
++ },{
++ name: "raw kernel",
++ size: (0x300000-0x40000), /* last 256KB is yamon env */
++ offset: MTDPART_OFS_APPEND,
++ }
++};
++
++#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
++
++static struct mtd_partition *parsed_parts;
++static struct mtd_info *mymtd;
++
++/*
++ * Probe the flash density and setup window address and size
++ * based on user CONFIG options. There are times when we don't
++ * want the MTD driver to be probing the boot or user flash,
++ * so having the option to enable only one bank is important.
++ */
++int setup_flash_params()
++{
++ flash_size = 0x4000000; /* 64MB per part */
++ /* Boot ROM flash bank only; no user bank */
++ window_addr = 0x1C000000;
++ window_size = 0x4000000;
++ /* USERFS from 0x1C00 0000 to 0x1FC00000 */
++ mirage_partitions[0].size = 0x3C00000;
++ return 0;
++}
++
++int __init mirage_mtd_init(void)
++{
++ struct mtd_partition *parts;
++ int nb_parts = 0;
++ char *part_type;
++
++ /* Default flash buswidth */
++ mirage_map.buswidth = flash_buswidth;
++
++ if (setup_flash_params())
++ return -ENXIO;
++
++ /*
++ * Static partition definition selection
++ */
++ part_type = "static";
++ parts = mirage_partitions;
++ nb_parts = NB_OF(mirage_partitions);
++ mirage_map.size = window_size;
++
++ /*
++ * Now let's probe for the actual flash. Do it here since
++ * specific machine settings might have been set above.
++ */
++ printk(KERN_NOTICE "Mirage flash: probing %d-bit flash bus\n",
++ mirage_map.buswidth*8);
++ mirage_map.map_priv_1 =
++ (unsigned long)ioremap(window_addr, window_size);
++ mymtd = do_map_probe("cfi_probe", &mirage_map);
++ if (!mymtd) return -ENXIO;
++ mymtd->module = THIS_MODULE;
++
++ add_mtd_partitions(mymtd, parts, nb_parts);
++ return 0;
++}
++
++static void __exit mirage_mtd_cleanup(void)
++{
++ if (mymtd) {
++ del_mtd_partitions(mymtd);
++ map_destroy(mymtd);
++ if (parsed_parts)
++ kfree(parsed_parts);
++ }
++}
++
++module_init(mirage_mtd_init);
++module_exit(mirage_mtd_cleanup);
++
++MODULE_AUTHOR("Embedded Edge");
++MODULE_DESCRIPTION("Mirage mtd map driver");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.4.32-rc1/drivers/mtd/maps/mtx-1.c linux-2.4.32-rc1.mips/drivers/mtd/maps/mtx-1.c
+--- linux-2.4.32-rc1/drivers/mtd/maps/mtx-1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/mtd/maps/mtx-1.c 2003-06-27 02:04:35.000000000 +0200
+@@ -0,0 +1,181 @@
++/*
++ * Flash memory access on 4G Systems MTX-1 board
++ *
++ * (C) 2003 Pete Popov <ppopov@mvista.com>
++ * Bruno Randolf <bruno.randolf@4g-systems.de>
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/io.h>
++#include <asm/au1000.h>
++
++#ifdef DEBUG_RW
++#define DBG(x...) printk(x)
++#else
++#define DBG(x...)
++#endif
++
++#ifdef CONFIG_MIPS_MTX1
++#define WINDOW_ADDR 0x1E000000
++#define WINDOW_SIZE 0x2000000
++#endif
++
++__u8 physmap_read8(struct map_info *map, unsigned long ofs)
++{
++ __u8 ret;
++ ret = __raw_readb(map->map_priv_1 + ofs);
++ DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++__u16 physmap_read16(struct map_info *map, unsigned long ofs)
++{
++ __u16 ret;
++ ret = __raw_readw(map->map_priv_1 + ofs);
++ DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++__u32 physmap_read32(struct map_info *map, unsigned long ofs)
++{
++ __u32 ret;
++ ret = __raw_readl(map->map_priv_1 + ofs);
++ DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++ DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to);
++ memcpy_fromio(to, map->map_priv_1 + from, len);
++}
++
++void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++ DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writeb(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++ DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writew(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++ DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writel(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
++{
++ DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from);
++ memcpy_toio(map->map_priv_1 + to, from, len);
++}
++
++
++
++static struct map_info mtx1_map = {
++ name: "MTX-1 flash",
++ read8: physmap_read8,
++ read16: physmap_read16,
++ read32: physmap_read32,
++ copy_from: physmap_copy_from,
++ write8: physmap_write8,
++ write16: physmap_write16,
++ write32: physmap_write32,
++ copy_to: physmap_copy_to,
++};
++
++
++static unsigned long flash_size = 0x01000000;
++static unsigned char flash_buswidth = 4;
++static struct mtd_partition mtx1_partitions[] = {
++ {
++ name: "user fs",
++ size: 0x1c00000,
++ offset: 0,
++ },{
++ name: "yamon",
++ size: 0x0100000,
++ offset: MTDPART_OFS_APPEND,
++ mask_flags: MTD_WRITEABLE
++ },{
++ name: "raw kernel",
++ size: 0x02c0000,
++ offset: MTDPART_OFS_APPEND,
++ },{
++ name: "yamon env vars",
++ size: 0x0040000,
++ offset: MTDPART_OFS_APPEND,
++ mask_flags: MTD_WRITEABLE
++ }
++};
++
++
++#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
++
++static struct mtd_partition *parsed_parts;
++static struct mtd_info *mymtd;
++
++int __init mtx1_mtd_init(void)
++{
++ struct mtd_partition *parts;
++ int nb_parts = 0;
++ char *part_type;
++
++ /* Default flash buswidth */
++ mtx1_map.buswidth = flash_buswidth;
++
++ /*
++ * Static partition definition selection
++ */
++ part_type = "static";
++ parts = mtx1_partitions;
++ nb_parts = NB_OF(mtx1_partitions);
++ mtx1_map.size = flash_size;
++
++ /*
++ * Now let's probe for the actual flash. Do it here since
++ * specific machine settings might have been set above.
++ */
++ printk(KERN_NOTICE "MTX-1 flash: probing %d-bit flash bus\n",
++ mtx1_map.buswidth*8);
++ mtx1_map.map_priv_1 =
++ (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
++ mymtd = do_map_probe("cfi_probe", &mtx1_map);
++ if (!mymtd) return -ENXIO;
++ mymtd->module = THIS_MODULE;
++
++ add_mtd_partitions(mymtd, parts, nb_parts);
++ return 0;
++}
++
++static void __exit mtx1_mtd_cleanup(void)
++{
++ if (mymtd) {
++ del_mtd_partitions(mymtd);
++ map_destroy(mymtd);
++ if (parsed_parts)
++ kfree(parsed_parts);
++ }
++}
++
++module_init(mtx1_mtd_init);
++module_exit(mtx1_mtd_cleanup);
++
++MODULE_AUTHOR("Pete Popov");
++MODULE_DESCRIPTION("MTX-1 CFI map driver");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.4.32-rc1/drivers/mtd/maps/pb1550-flash.c linux-2.4.32-rc1.mips/drivers/mtd/maps/pb1550-flash.c
+--- linux-2.4.32-rc1/drivers/mtd/maps/pb1550-flash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/mtd/maps/pb1550-flash.c 2004-02-26 01:48:48.000000000 +0100
+@@ -0,0 +1,270 @@
++/*
++ * Flash memory access on Alchemy Pb1550 board
++ *
++ * (C) 2004 Embedded Edge, LLC, based on pb1550-flash.c:
++ * (C) 2003 Pete Popov <ppopov@pacbell.net>
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/io.h>
++#include <asm/au1000.h>
++#include <asm/pb1550.h>
++
++#ifdef DEBUG_RW
++#define DBG(x...) printk(x)
++#else
++#define DBG(x...)
++#endif
++
++static unsigned long window_addr;
++static unsigned long window_size;
++
++__u8 physmap_read8(struct map_info *map, unsigned long ofs)
++{
++ __u8 ret;
++ ret = __raw_readb(map->map_priv_1 + ofs);
++ DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++__u16 physmap_read16(struct map_info *map, unsigned long ofs)
++{
++ __u16 ret;
++ ret = __raw_readw(map->map_priv_1 + ofs);
++ DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++__u32 physmap_read32(struct map_info *map, unsigned long ofs)
++{
++ __u32 ret;
++ ret = __raw_readl(map->map_priv_1 + ofs);
++ DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++ DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to);
++ memcpy_fromio(to, map->map_priv_1 + from, len);
++}
++
++void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++ DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writeb(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++ DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writew(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++ DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writel(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
++{
++ DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from);
++ memcpy_toio(map->map_priv_1 + to, from, len);
++}
++
++static struct map_info pb1550_map = {
++ name: "Pb1550 flash",
++ read8: physmap_read8,
++ read16: physmap_read16,
++ read32: physmap_read32,
++ copy_from: physmap_copy_from,
++ write8: physmap_write8,
++ write16: physmap_write16,
++ write32: physmap_write32,
++ copy_to: physmap_copy_to,
++};
++
++static unsigned char flash_buswidth = 4;
++
++/*
++ * Support only 64MB NOR Flash parts
++ */
++
++#ifdef PB1550_BOTH_BANKS
++/* both banks will be used. Combine the first bank and the first
++ * part of the second bank together into a single jffs/jffs2
++ * partition.
++ */
++static struct mtd_partition pb1550_partitions[] = {
++ /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
++ * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
++ * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
++ */
++ {
++ name: "User FS",
++ size: (0x1FC00000 - 0x18000000),
++ offset: 0x0000000
++ },{
++ name: "yamon",
++ size: 0x0100000,
++ offset: MTDPART_OFS_APPEND,
++ mask_flags: MTD_WRITEABLE
++ },{
++ name: "raw kernel",
++ size: (0x300000 - 0x40000), /* last 256KB is yamon env */
++ offset: MTDPART_OFS_APPEND,
++ }
++};
++#elif defined(PB1550_BOOT_ONLY)
++static struct mtd_partition pb1550_partitions[] = {
++ /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
++ * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
++ */
++ {
++ name: "User FS",
++ size: 0x03c00000,
++ offset: 0x0000000
++ },{
++ name: "yamon",
++ size: 0x0100000,
++ offset: MTDPART_OFS_APPEND,
++ mask_flags: MTD_WRITEABLE
++ },{
++ name: "raw kernel",
++ size: (0x300000-0x40000), /* last 256KB is yamon env */
++ offset: MTDPART_OFS_APPEND,
++ }
++};
++#elif defined(PB1550_USER_ONLY)
++static struct mtd_partition pb1550_partitions[] = {
++ /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
++ * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
++ */
++ {
++ name: "User FS",
++ size: (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */
++ offset: 0x0000000
++ },{
++ name: "raw kernel",
++ size: MTDPART_SIZ_FULL,
++ offset: MTDPART_OFS_APPEND,
++ }
++};
++#else
++#error MTD_PB1550 define combo error /* should never happen */
++#endif
++
++#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
++
++static struct mtd_partition *parsed_parts;
++static struct mtd_info *mymtd;
++
++/*
++ * Probe the flash density and setup window address and size
++ * based on user CONFIG options. There are times when we don't
++ * want the MTD driver to be probing the boot or user flash,
++ * so having the option to enable only one bank is important.
++ */
++int setup_flash_params()
++{
++ u16 boot_swapboot;
++ boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) |
++ ((bcsr->status >> 6) & 0x1);
++ printk("Pb1550 MTD: boot:swap %d\n", boot_swapboot);
++
++ switch (boot_swapboot) {
++ case 0: /* 512Mbit devices, both enabled */
++ case 1:
++ case 8:
++ case 9:
++#if defined(PB1550_BOTH_BANKS)
++ window_addr = 0x18000000;
++ window_size = 0x8000000;
++#elif defined(PB1550_BOOT_ONLY)
++ window_addr = 0x1C000000;
++ window_size = 0x4000000;
++#else /* USER ONLY */
++ window_addr = 0x1E000000;
++ window_size = 0x1000000;
++#endif
++ break;
++ case 0xC:
++ case 0xD:
++ case 0xE:
++ case 0xF:
++ /* 64 MB Boot NOR Flash is disabled */
++ /* and the start address is moved to 0x0C00000 */
++ window_addr = 0x0C000000;
++ window_size = 0x4000000;
++ default:
++ printk("Pb1550 MTD: unsupported boot:swap setting\n");
++ return 1;
++ }
++ return 0;
++}
++
++int __init pb1550_mtd_init(void)
++{
++ struct mtd_partition *parts;
++ int nb_parts = 0;
++ char *part_type;
++
++ /* Default flash buswidth */
++ pb1550_map.buswidth = flash_buswidth;
++
++ if (setup_flash_params())
++ return -ENXIO;
++
++ /*
++ * Static partition definition selection
++ */
++ part_type = "static";
++ parts = pb1550_partitions;
++ nb_parts = NB_OF(pb1550_partitions);
++ pb1550_map.size = window_size;
++
++ /*
++ * Now let's probe for the actual flash. Do it here since
++ * specific machine settings might have been set above.
++ */
++ printk(KERN_NOTICE "Pb1550 flash: probing %d-bit flash bus\n",
++ pb1550_map.buswidth*8);
++ pb1550_map.map_priv_1 =
++ (unsigned long)ioremap(window_addr, window_size);
++ mymtd = do_map_probe("cfi_probe", &pb1550_map);
++ if (!mymtd) return -ENXIO;
++ mymtd->module = THIS_MODULE;
++
++ add_mtd_partitions(mymtd, parts, nb_parts);
++ return 0;
++}
++
++static void __exit pb1550_mtd_cleanup(void)
++{
++ if (mymtd) {
++ del_mtd_partitions(mymtd);
++ map_destroy(mymtd);
++ if (parsed_parts)
++ kfree(parsed_parts);
++ }
++}
++
++module_init(pb1550_mtd_init);
++module_exit(pb1550_mtd_cleanup);
++
++MODULE_AUTHOR("Embedded Edge, LLC");
++MODULE_DESCRIPTION("Pb1550 mtd map driver");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.4.32-rc1/drivers/mtd/maps/pb1xxx-flash.c linux-2.4.32-rc1.mips/drivers/mtd/maps/pb1xxx-flash.c
+--- linux-2.4.32-rc1/drivers/mtd/maps/pb1xxx-flash.c 2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/mtd/maps/pb1xxx-flash.c 2003-05-19 08:27:22.000000000 +0200
+@@ -192,6 +192,34 @@
+ #else
+ #error MTD_PB1500 define combo error /* should never happen */
+ #endif
++#elif defined(CONFIG_MTD_BOSPORUS)
++static unsigned char flash_buswidth = 2;
++static unsigned long flash_size = 0x02000000;
++#define WINDOW_ADDR 0x1F000000
++#define WINDOW_SIZE 0x2000000
++static struct mtd_partition pb1xxx_partitions[] = {
++ {
++ name: "User FS",
++ size: 0x00400000,
++ offset: 0x00000000,
++ },{
++ name: "Yamon-2",
++ size: 0x00100000,
++ offset: 0x00400000,
++ },{
++ name: "Root FS",
++ size: 0x00700000,
++ offset: 0x00500000,
++ },{
++ name: "Yamon-1",
++ size: 0x00100000,
++ offset: 0x00C00000,
++ },{
++ name: "Kernel",
++ size: 0x00300000,
++ offset: 0x00D00000,
++ }
++};
+ #else
+ #error Unsupported board
+ #endif
+diff -Nur linux-2.4.32-rc1/drivers/mtd/maps/xxs1500.c linux-2.4.32-rc1.mips/drivers/mtd/maps/xxs1500.c
+--- linux-2.4.32-rc1/drivers/mtd/maps/xxs1500.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/mtd/maps/xxs1500.c 2003-08-02 04:06:01.000000000 +0200
+@@ -0,0 +1,186 @@
++/*
++ * Flash memory access on MyCable XXS1500 board
++ *
++ * (C) 2003 Pete Popov <ppopov@mvista.com>
++ *
++ * $Id: xxs1500.c,v 1.1.2.1 2003/06/13 21:15:46 ppopov Exp $
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/io.h>
++#include <asm/au1000.h>
++
++#ifdef DEBUG_RW
++#define DBG(x...) printk(x)
++#else
++#define DBG(x...)
++#endif
++
++#ifdef CONFIG_MIPS_XXS1500
++#define WINDOW_ADDR 0x1F000000
++#define WINDOW_SIZE 0x1000000
++#endif
++
++__u8 physmap_read8(struct map_info *map, unsigned long ofs)
++{
++ __u8 ret;
++ ret = __raw_readb(map->map_priv_1 + ofs);
++ DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++__u16 physmap_read16(struct map_info *map, unsigned long ofs)
++{
++ __u16 ret;
++ ret = __raw_readw(map->map_priv_1 + ofs);
++ DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++__u32 physmap_read32(struct map_info *map, unsigned long ofs)
++{
++ __u32 ret;
++ ret = __raw_readl(map->map_priv_1 + ofs);
++ DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret);
++ return ret;
++}
++
++void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++ DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to);
++ memcpy_fromio(to, map->map_priv_1 + from, len);
++}
++
++void physmap_write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++ DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writeb(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++ DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writew(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++ DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d);
++ __raw_writel(d, map->map_priv_1 + adr);
++ mb();
++}
++
++void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
++{
++ DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from);
++ memcpy_toio(map->map_priv_1 + to, from, len);
++}
++
++
++
++static struct map_info xxs1500_map = {
++ name: "XXS1500 flash",
++ read8: physmap_read8,
++ read16: physmap_read16,
++ read32: physmap_read32,
++ copy_from: physmap_copy_from,
++ write8: physmap_write8,
++ write16: physmap_write16,
++ write32: physmap_write32,
++ copy_to: physmap_copy_to,
++};
++
++
++static unsigned long flash_size = 0x00800000;
++static unsigned char flash_buswidth = 4;
++static struct mtd_partition xxs1500_partitions[] = {
++ {
++ name: "kernel image",
++ size: 0x00200000,
++ offset: 0,
++ },{
++ name: "user fs 0",
++ size: (0x00C00000-0x200000),
++ offset: MTDPART_OFS_APPEND,
++ },{
++ name: "yamon",
++ size: 0x00100000,
++ offset: MTDPART_OFS_APPEND,
++ mask_flags: MTD_WRITEABLE
++ },{
++ name: "user fs 1",
++ size: 0x2c0000,
++ offset: MTDPART_OFS_APPEND,
++ },{
++ name: "yamon env vars",
++ size: 0x040000,
++ offset: MTDPART_OFS_APPEND,
++ mask_flags: MTD_WRITEABLE
++ }
++};
++
++
++#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
++
++static struct mtd_partition *parsed_parts;
++static struct mtd_info *mymtd;
++
++int __init xxs1500_mtd_init(void)
++{
++ struct mtd_partition *parts;
++ int nb_parts = 0;
++ char *part_type;
++
++ /* Default flash buswidth */
++ xxs1500_map.buswidth = flash_buswidth;
++
++ /*
++ * Static partition definition selection
++ */
++ part_type = "static";
++ parts = xxs1500_partitions;
++ nb_parts = NB_OF(xxs1500_partitions);
++ xxs1500_map.size = flash_size;
++
++ /*
++ * Now let's probe for the actual flash. Do it here since
++ * specific machine settings might have been set above.
++ */
++ printk(KERN_NOTICE "XXS1500 flash: probing %d-bit flash bus\n",
++ xxs1500_map.buswidth*8);
++ xxs1500_map.map_priv_1 =
++ (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
++ mymtd = do_map_probe("cfi_probe", &xxs1500_map);
++ if (!mymtd) return -ENXIO;
++ mymtd->module = THIS_MODULE;
++
++ add_mtd_partitions(mymtd, parts, nb_parts);
++ return 0;
++}
++
++static void __exit xxs1500_mtd_cleanup(void)
++{
++ if (mymtd) {
++ del_mtd_partitions(mymtd);
++ map_destroy(mymtd);
++ if (parsed_parts)
++ kfree(parsed_parts);
++ }
++}
++
++module_init(xxs1500_mtd_init);
++module_exit(xxs1500_mtd_cleanup);
++
++MODULE_AUTHOR("Pete Popov");
++MODULE_DESCRIPTION("XXS1500 CFI map driver");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.4.32-rc1/drivers/net/defxx.c linux-2.4.32-rc1.mips/drivers/net/defxx.c
+--- linux-2.4.32-rc1/drivers/net/defxx.c 2004-11-17 12:54:21.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/net/defxx.c 2004-11-19 01:28:39.000000000 +0100
+@@ -10,24 +10,18 @@
+ *
+ * Abstract:
+ * A Linux device driver supporting the Digital Equipment Corporation
+- * FDDI EISA and PCI controller families. Supported adapters include:
++ * FDDI TURBOchannel, EISA and PCI controller families. Supported
++ * adapters include:
+ *
+- * DEC FDDIcontroller/EISA (DEFEA)
+- * DEC FDDIcontroller/PCI (DEFPA)
++ * DEC FDDIcontroller/TURBOchannel (DEFTA)
++ * DEC FDDIcontroller/EISA (DEFEA)
++ * DEC FDDIcontroller/PCI (DEFPA)
+ *
+- * Maintainers:
+- * LVS Lawrence V. Stefani
+- *
+- * Contact:
+- * The author may be reached at:
++ * The original author:
++ * LVS Lawrence V. Stefani <lstefani@yahoo.com>
+ *
+- * Inet: stefani@lkg.dec.com
+- * (NOTE! this address no longer works -jgarzik)
+- *
+- * Mail: Digital Equipment Corporation
+- * 550 King Street
+- * M/S: LKG1-3/M07
+- * Littleton, MA 01460
++ * Maintainers:
++ * macro Maciej W. Rozycki <macro@linux-mips.org>
+ *
+ * Credits:
+ * I'd like to thank Patricia Cross for helping me get started with
+@@ -197,16 +191,16 @@
+ * Sep 2000 tjeerd Fix leak on unload, cosmetic code cleanup
+ * Feb 2001 Skb allocation fixes
+ * Feb 2001 davej PCI enable cleanups.
++ * 04 Aug 2003 macro Converted to the DMA API.
++ * 14 Aug 2004 macro Fix device names reported.
++ * 26 Sep 2004 macro TURBOchannel support.
+ */
+
+ /* Include files */
+
+ #include <linux/module.h>
+-
+ #include <linux/kernel.h>
+-#include <linux/sched.h>
+ #include <linux/string.h>
+-#include <linux/ptrace.h>
+ #include <linux/errno.h>
+ #include <linux/ioport.h>
+ #include <linux/slab.h>
+@@ -215,19 +209,33 @@
+ #include <linux/delay.h>
+ #include <linux/init.h>
+ #include <linux/netdevice.h>
++#include <linux/fddidevice.h>
++#include <linux/skbuff.h>
++
+ #include <asm/byteorder.h>
+ #include <asm/bitops.h>
+ #include <asm/io.h>
+
+-#include <linux/fddidevice.h>
+-#include <linux/skbuff.h>
++#ifdef CONFIG_TC
++#include <asm/dec/tc.h>
++#else
++static int search_tc_card(const char *name) { return -ENODEV; }
++static void claim_tc_card(int slot) { }
++static void release_tc_card(int slot) { }
++static unsigned long get_tc_base_addr(int slot) { return 0; }
++static unsigned long get_tc_irq_nr(int slot) { return -1; }
++#endif
+
+ #include "defxx.h"
+
+-/* Version information string - should be updated prior to each new release!!! */
++/* Version information string should be updated prior to each new release! */
++#define DRV_NAME "defxx"
++#define DRV_VERSION "v1.07T"
++#define DRV_RELDATE "2004/09/26"
+
+ static char version[] __devinitdata =
+- "defxx.c:v1.05e 2001/02/03 Lawrence V. Stefani and others\n";
++ DRV_NAME ": " DRV_VERSION " " DRV_RELDATE
++ " Lawrence V. Stefani and others\n";
+
+ #define DYNAMIC_BUFFERS 1
+
+@@ -243,7 +251,7 @@
+ static void dfx_bus_init(struct net_device *dev);
+ static void dfx_bus_config_check(DFX_board_t *bp);
+
+-static int dfx_driver_init(struct net_device *dev);
++static int dfx_driver_init(struct net_device *dev, const char *print_name);
+ static int dfx_adap_init(DFX_board_t *bp, int get_buffers);
+
+ static int dfx_open(struct net_device *dev);
+@@ -337,48 +345,84 @@
+ int offset,
+ u8 data
+ )
++{
++ if (bp->bus_type == DFX_BUS_TYPE_TC)
++ {
++ volatile u8 *addr = (void *)(bp->base_addr + offset);
+
++ *addr = data;
++ mb();
++ }
++ else
+ {
+ u16 port = bp->base_addr + offset;
+
+ outb(data, port);
+ }
++}
+
+ static inline void dfx_port_read_byte(
+ DFX_board_t *bp,
+ int offset,
+ u8 *data
+ )
++{
++ if (bp->bus_type == DFX_BUS_TYPE_TC)
++ {
++ volatile u8 *addr = (void *)(bp->base_addr + offset);
+
++ mb();
++ *data = *addr;
++ }
++ else
+ {
+ u16 port = bp->base_addr + offset;
+
+ *data = inb(port);
+ }
++}
+
+ static inline void dfx_port_write_long(
+ DFX_board_t *bp,
+ int offset,
+ u32 data
+ )
++{
++ if (bp->bus_type == DFX_BUS_TYPE_TC)
++ {
++ volatile u32 *addr = (void *)(bp->base_addr + offset);
+
++ *addr = data;
++ mb();
++ }
++ else
+ {
+ u16 port = bp->base_addr + offset;
+
+ outl(data, port);
+ }
++}
+
+ static inline void dfx_port_read_long(
+ DFX_board_t *bp,
+ int offset,
+ u32 *data
+ )
++{
++ if (bp->bus_type == DFX_BUS_TYPE_TC)
++ {
++ volatile u32 *addr = (void *)(bp->base_addr + offset);
+
++ mb();
++ *data = *addr;
++ }
++ else
+ {
+ u16 port = bp->base_addr + offset;
+
+ *data = inl(port);
+ }
++}
+
+
+ /*
+@@ -393,8 +437,9 @@
+ * Condition code
+ *
+ * Arguments:
+- * pdev - pointer to pci device information (NULL for EISA)
+- * ioaddr - pointer to port (NULL for PCI)
++ * pdev - pointer to pci device information (NULL for EISA or TURBOchannel)
++ * bus_type - bus type (one of DFX_BUS_TYPE_*)
++ * handle - bus-specific data: slot (TC), pointer to port (EISA), NULL (PCI)
+ *
+ * Functional Description:
+ *
+@@ -410,54 +455,68 @@
+ * initialized and the board resources are read and stored in
+ * the device structure.
+ */
+-static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr)
++static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, u32 bus_type, long handle)
+ {
++ static int version_disp;
++ char *print_name = DRV_NAME;
+ struct net_device *dev;
+ DFX_board_t *bp; /* board pointer */
++ long ioaddr; /* pointer to port */
++ unsigned long len; /* resource length */
++ int alloc_size; /* total buffer size used */
+ int err;
+
+-#ifndef MODULE
+- static int version_disp;
+-
+- if (!version_disp) /* display version info if adapter is found */
+- {
++ if (!version_disp) { /* display version info if adapter is found */
+ version_disp = 1; /* set display flag to TRUE so that */
+ printk(version); /* we only display this string ONCE */
+ }
+-#endif
+
+- /*
+- * init_fddidev() allocates a device structure with private data, clears the device structure and private data,
+- * and calls fddi_setup() and register_netdev(). Not much left to do for us here.
+- */
+- dev = init_fddidev(NULL, sizeof(*bp));
++ if (pdev != NULL)
++ print_name = pdev->slot_name;
++
++ dev = alloc_fddidev(sizeof(*bp));
+ if (!dev) {
+- printk (KERN_ERR "defxx: unable to allocate fddidev, aborting\n");
++ printk(KERN_ERR "%s: unable to allocate fddidev, aborting\n",
++ print_name);
+ return -ENOMEM;
+ }
+
+ /* Enable PCI device. */
+- if (pdev != NULL) {
++ if (bus_type == DFX_BUS_TYPE_PCI) {
+ err = pci_enable_device (pdev);
+ if (err) goto err_out;
+ ioaddr = pci_resource_start (pdev, 1);
+ }
+
+ SET_MODULE_OWNER(dev);
++ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ bp = dev->priv;
+
+- if (!request_region (ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, dev->name)) {
+- printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n",
+- dev->name, PFI_K_CSR_IO_LEN, ioaddr);
++ if (bus_type == DFX_BUS_TYPE_TC) {
++ /* TURBOchannel board */
++ bp->slot = handle;
++ claim_tc_card(bp->slot);
++ ioaddr = get_tc_base_addr(handle) + PI_TC_K_CSR_OFFSET;
++ len = PI_TC_K_CSR_LEN;
++ } else if (bus_type == DFX_BUS_TYPE_EISA) {
++ /* EISA board */
++ ioaddr = handle;
++ len = PI_ESIC_K_CSR_IO_LEN;
++ } else
++ /* PCI board */
++ len = PFI_K_CSR_IO_LEN;
++ dev->base_addr = ioaddr; /* save port (I/O) base address */
++
++ if (!request_region(ioaddr, len, print_name)) {
++ printk(KERN_ERR "%s: Cannot reserve I/O resource "
++ "0x%lx @ 0x%lx, aborting\n", print_name, len, ioaddr);
+ err = -EBUSY;
+ goto err_out;
+ }
+
+ /* Initialize new device structure */
+
+- dev->base_addr = ioaddr; /* save port (I/O) base address */
+-
+ dev->get_stats = dfx_ctl_get_stats;
+ dev->open = dfx_open;
+ dev->stop = dfx_close;
+@@ -465,37 +524,54 @@
+ dev->set_multicast_list = dfx_ctl_set_multicast_list;
+ dev->set_mac_address = dfx_ctl_set_mac_address;
+
+- if (pdev == NULL) {
+- /* EISA board */
+- bp->bus_type = DFX_BUS_TYPE_EISA;
++ bp->bus_type = bus_type;
++ if (bus_type == DFX_BUS_TYPE_TC || bus_type == DFX_BUS_TYPE_EISA) {
++ /* TURBOchannel or EISA board */
+ bp->next = root_dfx_eisa_dev;
+ root_dfx_eisa_dev = dev;
+ } else {
+ /* PCI board */
+- bp->bus_type = DFX_BUS_TYPE_PCI;
+ bp->pci_dev = pdev;
+ pci_set_drvdata (pdev, dev);
+ pci_set_master (pdev);
+ }
+
+- if (dfx_driver_init(dev) != DFX_K_SUCCESS) {
++
++ if (dfx_driver_init(dev, print_name) != DFX_K_SUCCESS) {
+ err = -ENODEV;
+ goto err_out_region;
+ }
+
++ err = register_netdev(dev);
++ if (err)
++ goto err_out_kfree;
++
++ printk("%s: registered as %s\n", print_name, dev->name);
+ return 0;
+
++err_out_kfree:
++ alloc_size = sizeof(PI_DESCR_BLOCK) +
++ PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX +
++#ifndef DYNAMIC_BUFFERS
++ (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) +
++#endif
++ sizeof(PI_CONSUMER_BLOCK) +
++ (PI_ALIGN_K_DESC_BLK - 1);
++ if (bp->kmalloced)
++ pci_free_consistent(pdev, alloc_size,
++ bp->kmalloced, bp->kmalloced_dma);
+ err_out_region:
+- release_region(ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN);
++ release_region(ioaddr, len);
+ err_out:
+- unregister_netdev(dev);
+- kfree(dev);
++ if (bp->bus_type == DFX_BUS_TYPE_TC)
++ release_tc_card(bp->slot);
++ free_netdev(dev);
+ return err;
+ }
+
+ static int __devinit dfx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+ {
+- return dfx_init_one_pci_or_eisa(pdev, 0);
++ return dfx_init_one_pci_or_eisa(pdev, DFX_BUS_TYPE_PCI, 0);
+ }
+
+ static int __init dfx_eisa_init(void)
+@@ -507,6 +583,7 @@
+
+ DBG_printk("In dfx_eisa_init...\n");
+
++#ifdef CONFIG_EISA
+ /* Scan for FDDI EISA controllers */
+
+ for (i=0; i < DFX_MAX_EISA_SLOTS; i++) /* only scan for up to 16 EISA slots */
+@@ -517,9 +594,27 @@
+ {
+ port = (i << 12); /* recalc base addr */
+
+- if (dfx_init_one_pci_or_eisa(NULL, port) == 0) rc = 0;
++ if (dfx_init_one_pci_or_eisa(NULL, DFX_BUS_TYPE_EISA, port) == 0) rc = 0;
+ }
+ }
++#endif
++ return rc;
++}
++
++static int __init dfx_tc_init(void)
++{
++ int rc = -ENODEV;
++ int slot; /* TC slot number */
++
++ DBG_printk("In dfx_tc_init...\n");
++
++ /* Scan for FDDI TC controllers */
++ while ((slot = search_tc_card("PMAF-F")) >= 0) {
++ if (dfx_init_one_pci_or_eisa(NULL, DFX_BUS_TYPE_TC, slot) == 0)
++ rc = 0;
++ else
++ break;
++ }
+ return rc;
+ }
+
+@@ -583,8 +678,9 @@
+
+ /* Initialize adapter based on bus type */
+
+- if (bp->bus_type == DFX_BUS_TYPE_EISA)
+- {
++ if (bp->bus_type == DFX_BUS_TYPE_TC) {
++ dev->irq = get_tc_irq_nr(bp->slot);
++ } else if (bp->bus_type == DFX_BUS_TYPE_EISA) {
+ /* Get the interrupt level from the ESIC chip */
+
+ dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val);
+@@ -766,6 +862,7 @@
+ *
+ * Arguments:
+ * dev - pointer to device information
++ * print_name - printable device name
+ *
+ * Functional Description:
+ * This function allocates additional resources such as the host memory
+@@ -780,20 +877,21 @@
+ * or read adapter MAC address
+ *
+ * Assumptions:
+- * Memory allocated from kmalloc() call is physically contiguous, locked
+- * memory whose physical address equals its virtual address.
++ * Memory allocated from pci_alloc_consistent() call is physically
++ * contiguous, locked memory.
+ *
+ * Side Effects:
+ * Adapter is reset and should be in DMA_UNAVAILABLE state before
+ * returning from this routine.
+ */
+
+-static int __devinit dfx_driver_init(struct net_device *dev)
++static int __devinit dfx_driver_init(struct net_device *dev,
++ const char *print_name)
+ {
+ DFX_board_t *bp = dev->priv;
+ int alloc_size; /* total buffer size needed */
+ char *top_v, *curr_v; /* virtual addrs into memory block */
+- u32 top_p, curr_p; /* physical addrs into memory block */
++ dma_addr_t top_p, curr_p; /* physical addrs into memory block */
+ u32 data; /* host data register value */
+
+ DBG_printk("In dfx_driver_init...\n");
+@@ -837,26 +935,20 @@
+
+ /* Read the factory MAC address from the adapter then save it */
+
+- if (dfx_hw_port_ctrl_req(bp,
+- PI_PCTRL_M_MLA,
+- PI_PDATA_A_MLA_K_LO,
+- 0,
+- &data) != DFX_K_SUCCESS)
+- {
+- printk("%s: Could not read adapter factory MAC address!\n", dev->name);
++ if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_LO, 0,
++ &data) != DFX_K_SUCCESS) {
++ printk("%s: Could not read adapter factory MAC address!\n",
++ print_name);
+ return(DFX_K_FAILURE);
+- }
++ }
+ memcpy(&bp->factory_mac_addr[0], &data, sizeof(u32));
+
+- if (dfx_hw_port_ctrl_req(bp,
+- PI_PCTRL_M_MLA,
+- PI_PDATA_A_MLA_K_HI,
+- 0,
+- &data) != DFX_K_SUCCESS)
+- {
+- printk("%s: Could not read adapter factory MAC address!\n", dev->name);
++ if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_HI, 0,
++ &data) != DFX_K_SUCCESS) {
++ printk("%s: Could not read adapter factory MAC address!\n",
++ print_name);
+ return(DFX_K_FAILURE);
+- }
++ }
+ memcpy(&bp->factory_mac_addr[4], &data, sizeof(u16));
+
+ /*
+@@ -867,28 +959,27 @@
+ */
+
+ memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN);
+- if (bp->bus_type == DFX_BUS_TYPE_EISA)
+- printk("%s: DEFEA at I/O addr = 0x%lX, IRQ = %d, Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
+- dev->name,
+- dev->base_addr,
+- dev->irq,
+- dev->dev_addr[0],
+- dev->dev_addr[1],
+- dev->dev_addr[2],
+- dev->dev_addr[3],
+- dev->dev_addr[4],
+- dev->dev_addr[5]);
++ if (bp->bus_type == DFX_BUS_TYPE_TC)
++ printk("%s: DEFTA at addr = 0x%lX, IRQ = %d, "
++ "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
++ print_name, dev->base_addr, dev->irq,
++ dev->dev_addr[0], dev->dev_addr[1],
++ dev->dev_addr[2], dev->dev_addr[3],
++ dev->dev_addr[4], dev->dev_addr[5]);
++ else if (bp->bus_type == DFX_BUS_TYPE_EISA)
++ printk("%s: DEFEA at I/O addr = 0x%lX, IRQ = %d, "
++ "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
++ print_name, dev->base_addr, dev->irq,
++ dev->dev_addr[0], dev->dev_addr[1],
++ dev->dev_addr[2], dev->dev_addr[3],
++ dev->dev_addr[4], dev->dev_addr[5]);
+ else
+- printk("%s: DEFPA at I/O addr = 0x%lX, IRQ = %d, Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
+- dev->name,
+- dev->base_addr,
+- dev->irq,
+- dev->dev_addr[0],
+- dev->dev_addr[1],
+- dev->dev_addr[2],
+- dev->dev_addr[3],
+- dev->dev_addr[4],
+- dev->dev_addr[5]);
++ printk("%s: DEFPA at I/O addr = 0x%lX, IRQ = %d, "
++ "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
++ print_name, dev->base_addr, dev->irq,
++ dev->dev_addr[0], dev->dev_addr[1],
++ dev->dev_addr[2], dev->dev_addr[3],
++ dev->dev_addr[4], dev->dev_addr[5]);
+
+ /*
+ * Get memory for descriptor block, consumer block, and other buffers
+@@ -903,14 +994,15 @@
+ #endif
+ sizeof(PI_CONSUMER_BLOCK) +
+ (PI_ALIGN_K_DESC_BLK - 1);
+- bp->kmalloced = top_v = (char *) kmalloc(alloc_size, GFP_KERNEL);
+- if (top_v == NULL)
+- {
+- printk("%s: Could not allocate memory for host buffers and structures!\n", dev->name);
++ bp->kmalloced = top_v = pci_alloc_consistent(bp->pci_dev, alloc_size,
++ &bp->kmalloced_dma);
++ if (top_v == NULL) {
++ printk("%s: Could not allocate memory for host buffers "
++ "and structures!\n", print_name);
+ return(DFX_K_FAILURE);
+- }
++ }
+ memset(top_v, 0, alloc_size); /* zero out memory before continuing */
+- top_p = virt_to_bus(top_v); /* get physical address of buffer */
++ top_p = bp->kmalloced_dma; /* get physical address of buffer */
+
+ /*
+ * To guarantee the 8K alignment required for the descriptor block, 8K - 1
+@@ -924,7 +1016,7 @@
+ * for allocating the needed memory.
+ */
+
+- curr_p = (u32) (ALIGN(top_p, PI_ALIGN_K_DESC_BLK));
++ curr_p = ALIGN(top_p, PI_ALIGN_K_DESC_BLK);
+ curr_v = top_v + (curr_p - top_p);
+
+ /* Reserve space for descriptor block */
+@@ -965,14 +1057,20 @@
+
+ /* Display virtual and physical addresses if debug driver */
+
+- DBG_printk("%s: Descriptor block virt = %0lX, phys = %0X\n", dev->name, (long)bp->descr_block_virt, bp->descr_block_phys);
+- DBG_printk("%s: Command Request buffer virt = %0lX, phys = %0X\n", dev->name, (long)bp->cmd_req_virt, bp->cmd_req_phys);
+- DBG_printk("%s: Command Response buffer virt = %0lX, phys = %0X\n", dev->name, (long)bp->cmd_rsp_virt, bp->cmd_rsp_phys);
+- DBG_printk("%s: Receive buffer block virt = %0lX, phys = %0X\n", dev->name, (long)bp->rcv_block_virt, bp->rcv_block_phys);
+- DBG_printk("%s: Consumer block virt = %0lX, phys = %0X\n", dev->name, (long)bp->cons_block_virt, bp->cons_block_phys);
++ DBG_printk("%s: Descriptor block virt = %0lX, phys = %0X\n",
++ print_name,
++ (long)bp->descr_block_virt, bp->descr_block_phys);
++ DBG_printk("%s: Command Request buffer virt = %0lX, phys = %0X\n",
++ print_name, (long)bp->cmd_req_virt, bp->cmd_req_phys);
++ DBG_printk("%s: Command Response buffer virt = %0lX, phys = %0X\n",
++ print_name, (long)bp->cmd_rsp_virt, bp->cmd_rsp_phys);
++ DBG_printk("%s: Receive buffer block virt = %0lX, phys = %0X\n",
++ print_name, (long)bp->rcv_block_virt, bp->rcv_block_phys);
++ DBG_printk("%s: Consumer block virt = %0lX, phys = %0X\n",
++ print_name, (long)bp->cons_block_virt, bp->cons_block_phys);
+
+ return(DFX_K_SUCCESS);
+- }
++}
+
+
+ /*
+@@ -1218,7 +1316,9 @@
+
+ /* Register IRQ - support shared interrupts by passing device ptr */
+
+- ret = request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev);
++ ret = request_irq(dev->irq, (void *)dfx_interrupt,
++ (bp->bus_type == DFX_BUS_TYPE_TC) ? 0 : SA_SHIRQ,
++ dev->name, dev);
+ if (ret) {
+ printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
+ return ret;
+@@ -1737,7 +1837,7 @@
+ dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL,
+ (PFI_MODE_M_PDQ_INT_ENB + PFI_MODE_M_DMA_ENB));
+ }
+- else
++ else if (bp->bus_type == DFX_BUS_TYPE_EISA)
+ {
+ /* Disable interrupts at the ESIC */
+
+@@ -1755,6 +1855,13 @@
+ tmp |= PI_CONFIG_STAT_0_M_INT_ENB;
+ dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp);
+ }
++ else {
++ /* TC doesn't share interrupts so no need to disable them */
++
++ /* Call interrupt service routine for this adapter */
++
++ dfx_int_common(dev);
++ }
+
+ spin_unlock(&bp->lock);
+ }
+@@ -2663,12 +2770,12 @@
+
+ static void my_skb_align(struct sk_buff *skb, int n)
+ {
+- u32 x=(u32)skb->data; /* We only want the low bits .. */
+- u32 v;
++ unsigned long x = (unsigned long)skb->data;
++ unsigned long v;
+
+- v=(x+n-1)&~(n-1); /* Where we want to be */
++ v = ALIGN(x, n); /* Where we want to be */
+
+- skb_reserve(skb, v-x);
++ skb_reserve(skb, v - x);
+ }
+
+
+@@ -2745,7 +2852,10 @@
+ */
+
+ my_skb_align(newskb, 128);
+- bp->descr_block_virt->rcv_data[i+j].long_1 = virt_to_bus(newskb->data);
++ bp->descr_block_virt->rcv_data[i + j].long_1 =
++ (u32)pci_map_single(bp->pci_dev, newskb->data,
++ NEW_SKB_SIZE,
++ PCI_DMA_FROMDEVICE);
+ /*
+ * p_rcv_buff_va is only used inside the
+ * kernel so we put the skb pointer here.
+@@ -2859,9 +2969,17 @@
+
+ my_skb_align(newskb, 128);
+ skb = (struct sk_buff *)bp->p_rcv_buff_va[entry];
++ pci_unmap_single(bp->pci_dev,
++ bp->descr_block_virt->rcv_data[entry].long_1,
++ NEW_SKB_SIZE,
++ PCI_DMA_FROMDEVICE);
+ skb_reserve(skb, RCV_BUFF_K_PADDING);
+ bp->p_rcv_buff_va[entry] = (char *)newskb;
+- bp->descr_block_virt->rcv_data[entry].long_1 = virt_to_bus(newskb->data);
++ bp->descr_block_virt->rcv_data[entry].long_1 =
++ (u32)pci_map_single(bp->pci_dev,
++ newskb->data,
++ NEW_SKB_SIZE,
++ PCI_DMA_FROMDEVICE);
+ } else
+ skb = NULL;
+ } else
+@@ -2934,7 +3052,7 @@
+ * is contained in a single physically contiguous buffer
+ * in which the virtual address of the start of packet
+ * (skb->data) can be converted to a physical address
+- * by using virt_to_bus().
++ * by using pci_map_single().
+ *
+ * Since the adapter architecture requires a three byte
+ * packet request header to prepend the start of packet,
+@@ -3082,12 +3200,13 @@
+ * skb->data.
+ * 6. The physical address of the start of packet
+ * can be determined from the virtual address
+- * by using virt_to_bus() and is only 32-bits
++ * by using pci_map_single() and is only 32-bits
+ * wide.
+ */
+
+ p_xmt_descr->long_0 = (u32) (PI_XMT_DESCR_M_SOP | PI_XMT_DESCR_M_EOP | ((skb->len) << PI_XMT_DESCR_V_SEG_LEN));
+- p_xmt_descr->long_1 = (u32) virt_to_bus(skb->data);
++ p_xmt_descr->long_1 = (u32)pci_map_single(bp->pci_dev, skb->data,
++ skb->len, PCI_DMA_TODEVICE);
+
+ /*
+ * Verify that descriptor is actually available
+@@ -3171,6 +3290,7 @@
+ {
+ XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */
+ PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */
++ u8 comp; /* local transmit completion index */
+ int freed = 0; /* buffers freed */
+
+ /* Service all consumed transmit frames */
+@@ -3188,7 +3308,11 @@
+ bp->xmt_total_bytes += p_xmt_drv_descr->p_skb->len;
+
+ /* Return skb to operating system */
+-
++ comp = bp->rcv_xmt_reg.index.xmt_comp;
++ pci_unmap_single(bp->pci_dev,
++ bp->descr_block_virt->xmt_data[comp].long_1,
++ p_xmt_drv_descr->p_skb->len,
++ PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(p_xmt_drv_descr->p_skb);
+
+ /*
+@@ -3297,6 +3421,7 @@
+ {
+ u32 prod_cons; /* rcv/xmt consumer block longword */
+ XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */
++ u8 comp; /* local transmit completion index */
+
+ /* Flush all outstanding transmit frames */
+
+@@ -3307,7 +3432,11 @@
+ p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[bp->rcv_xmt_reg.index.xmt_comp]);
+
+ /* Return skb to operating system */
+-
++ comp = bp->rcv_xmt_reg.index.xmt_comp;
++ pci_unmap_single(bp->pci_dev,
++ bp->descr_block_virt->xmt_data[comp].long_1,
++ p_xmt_drv_descr->p_skb->len,
++ PCI_DMA_TODEVICE);
+ dev_kfree_skb(p_xmt_drv_descr->p_skb);
+
+ /* Increment transmit error counter */
+@@ -3337,12 +3466,36 @@
+
+ static void __devexit dfx_remove_one_pci_or_eisa(struct pci_dev *pdev, struct net_device *dev)
+ {
+- DFX_board_t *bp = dev->priv;
++ DFX_board_t *bp = dev->priv;
++ unsigned long len; /* resource length */
++ int alloc_size; /* total buffer size used */
+
++ if (bp->bus_type == DFX_BUS_TYPE_TC) {
++ /* TURBOchannel board */
++ len = PI_TC_K_CSR_LEN;
++ } else if (bp->bus_type == DFX_BUS_TYPE_EISA) {
++ /* EISA board */
++ len = PI_ESIC_K_CSR_IO_LEN;
++ } else {
++ len = PFI_K_CSR_IO_LEN;
++ }
+ unregister_netdev(dev);
+- release_region(dev->base_addr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN );
+- if (bp->kmalloced) kfree(bp->kmalloced);
+- kfree(dev);
++ release_region(dev->base_addr, len);
++
++ if (bp->bus_type == DFX_BUS_TYPE_TC)
++ release_tc_card(bp->slot);
++
++ alloc_size = sizeof(PI_DESCR_BLOCK) +
++ PI_CMD_REQ_K_SIZE_MAX + PI_CMD_RSP_K_SIZE_MAX +
++#ifndef DYNAMIC_BUFFERS
++ (bp->rcv_bufs_to_post * PI_RCV_DATA_K_SIZE_MAX) +
++#endif
++ sizeof(PI_CONSUMER_BLOCK) +
++ (PI_ALIGN_K_DESC_BLK - 1);
++ if (bp->kmalloced)
++ pci_free_consistent(pdev, alloc_size, bp->kmalloced,
++ bp->kmalloced_dma);
++ free_netdev(dev);
+ }
+
+ static void __devexit dfx_remove_one (struct pci_dev *pdev)
+@@ -3353,21 +3506,22 @@
+ pci_set_drvdata(pdev, NULL);
+ }
+
+-static struct pci_device_id dfx_pci_tbl[] __devinitdata = {
++static struct pci_device_id dfx_pci_tbl[] = {
+ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, PCI_ANY_ID, PCI_ANY_ID, },
+ { 0, }
+ };
+ MODULE_DEVICE_TABLE(pci, dfx_pci_tbl);
+
+ static struct pci_driver dfx_driver = {
+- name: "defxx",
+- probe: dfx_init_one,
+- remove: __devexit_p(dfx_remove_one),
+- id_table: dfx_pci_tbl,
++ .name = "defxx",
++ .probe = dfx_init_one,
++ .remove = __devexit_p(dfx_remove_one),
++ .id_table = dfx_pci_tbl,
+ };
+
+ static int dfx_have_pci;
+ static int dfx_have_eisa;
++static int dfx_have_tc;
+
+
+ static void __exit dfx_eisa_cleanup(void)
+@@ -3388,12 +3542,7 @@
+
+ static int __init dfx_init(void)
+ {
+- int rc_pci, rc_eisa;
+-
+-/* when a module, this is printed whether or not devices are found in probe */
+-#ifdef MODULE
+- printk(version);
+-#endif
++ int rc_pci, rc_eisa, rc_tc;
+
+ rc_pci = pci_module_init(&dfx_driver);
+ if (rc_pci >= 0) dfx_have_pci = 1;
+@@ -3401,20 +3550,27 @@
+ rc_eisa = dfx_eisa_init();
+ if (rc_eisa >= 0) dfx_have_eisa = 1;
+
+- return ((rc_eisa < 0) ? 0 : rc_eisa) + ((rc_pci < 0) ? 0 : rc_pci);
++ rc_tc = dfx_tc_init();
++ if (rc_tc >= 0) dfx_have_tc = 1;
++
++ return ((rc_tc < 0) ? 0 : rc_tc) +
++ ((rc_eisa < 0) ? 0 : rc_eisa) +
++ ((rc_pci < 0) ? 0 : rc_pci);
+ }
+
+ static void __exit dfx_cleanup(void)
+ {
+ if (dfx_have_pci)
+ pci_unregister_driver(&dfx_driver);
+- if (dfx_have_eisa)
++ if (dfx_have_eisa || dfx_have_tc)
+ dfx_eisa_cleanup();
+-
+ }
+
+ module_init(dfx_init);
+ module_exit(dfx_cleanup);
++MODULE_AUTHOR("Lawrence V. Stefani");
++MODULE_DESCRIPTION("DEC FDDIcontroller EISA/PCI (DEFEA/DEFPA) driver "
++ DRV_VERSION " " DRV_RELDATE);
+ MODULE_LICENSE("GPL");
+
+
+diff -Nur linux-2.4.32-rc1/drivers/net/defxx.h linux-2.4.32-rc1.mips/drivers/net/defxx.h
+--- linux-2.4.32-rc1/drivers/net/defxx.h 2001-02-13 22:15:05.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/net/defxx.h 2004-10-03 20:06:48.000000000 +0200
+@@ -12,17 +12,11 @@
+ * Contains all definitions specified by port specification and required
+ * by the defxx.c driver.
+ *
+- * Maintainers:
+- * LVS Lawrence V. Stefani
+- *
+- * Contact:
+- * The author may be reached at:
++ * The original author:
++ * LVS Lawrence V. Stefani <lstefani@yahoo.com>
+ *
+- * Inet: stefani@lkg.dec.com
+- * Mail: Digital Equipment Corporation
+- * 550 King Street
+- * M/S: LKG1-3/M07
+- * Littleton, MA 01460
++ * Maintainers:
++ * macro Maciej W. Rozycki <macro@linux-mips.org>
+ *
+ * Modification History:
+ * Date Name Description
+@@ -30,6 +24,7 @@
+ * 09-Sep-96 LVS Added group_prom field. Moved read/write I/O
+ * macros to DEFXX.C.
+ * 12-Sep-96 LVS Removed packet request header pointers.
++ * 04 Aug 2003 macro Converted to the DMA API.
+ */
+
+ #ifndef _DEFXX_H_
+@@ -1467,6 +1462,11 @@
+
+ #endif /* #ifndef BIG_ENDIAN */
+
++/* Define TC PDQ CSR offset and length */
++
++#define PI_TC_K_CSR_OFFSET 0x100000
++#define PI_TC_K_CSR_LEN 0x80 /* 128 bytes */
++
+ /* Define EISA controller register offsets */
+
+ #define PI_ESIC_K_BURST_HOLDOFF 0x040
+@@ -1634,6 +1634,7 @@
+
+ #define DFX_BUS_TYPE_PCI 0 /* type code for DEC FDDIcontroller/PCI */
+ #define DFX_BUS_TYPE_EISA 1 /* type code for DEC FDDIcontroller/EISA */
++#define DFX_BUS_TYPE_TC 2 /* type code for DEC FDDIcontroller/TURBOchannel */
+
+ #define DFX_FC_PRH2_PRH1_PRH0 0x54003820 /* Packet Request Header bytes + FC */
+ #define DFX_PRH0_BYTE 0x20 /* Packet Request Header byte 0 */
+@@ -1704,17 +1705,19 @@
+ {
+ /* Keep virtual and physical pointers to locked, physically contiguous memory */
+
+- char *kmalloced; /* kfree this on unload */
++ char *kmalloced; /* pci_free_consistent this on unload */
++ dma_addr_t kmalloced_dma;
++ /* DMA handle for the above */
+ PI_DESCR_BLOCK *descr_block_virt; /* PDQ descriptor block virt address */
+- u32 descr_block_phys; /* PDQ descriptor block phys address */
++ dma_addr_t descr_block_phys; /* PDQ descriptor block phys address */
+ PI_DMA_CMD_REQ *cmd_req_virt; /* Command request buffer virt address */
+- u32 cmd_req_phys; /* Command request buffer phys address */
++ dma_addr_t cmd_req_phys; /* Command request buffer phys address */
+ PI_DMA_CMD_RSP *cmd_rsp_virt; /* Command response buffer virt address */
+- u32 cmd_rsp_phys; /* Command response buffer phys address */
++ dma_addr_t cmd_rsp_phys; /* Command response buffer phys address */
+ char *rcv_block_virt; /* LLC host receive queue buf blk virt */
+- u32 rcv_block_phys; /* LLC host receive queue buf blk phys */
++ dma_addr_t rcv_block_phys; /* LLC host receive queue buf blk phys */
+ PI_CONSUMER_BLOCK *cons_block_virt; /* PDQ consumer block virt address */
+- u32 cons_block_phys; /* PDQ consumer block phys address */
++ dma_addr_t cons_block_phys; /* PDQ consumer block phys address */
+
+ /* Keep local copies of Type 1 and Type 2 register data */
+
+@@ -1758,8 +1761,9 @@
+
+ struct net_device *dev; /* pointer to device structure */
+ struct net_device *next;
+- u32 bus_type; /* bus type (0 == PCI, 1 == EISA) */
+- u16 base_addr; /* base I/O address (same as dev->base_addr) */
++ u32 bus_type; /* bus type (0 == PCI, 1 == EISA, 2 == TC) */
++ long base_addr; /* base I/O address (same as dev->base_addr) */
++ int slot; /* TC slot number */
+ struct pci_dev * pci_dev;
+ u32 full_duplex_enb; /* FDDI Full Duplex enable (1 == on, 2 == off) */
+ u32 req_ttrt; /* requested TTRT value (in 80ns units) */
+diff -Nur linux-2.4.32-rc1/drivers/net/hamradio/hdlcdrv.c linux-2.4.32-rc1.mips/drivers/net/hamradio/hdlcdrv.c
+--- linux-2.4.32-rc1/drivers/net/hamradio/hdlcdrv.c 2002-02-25 20:37:59.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/net/hamradio/hdlcdrv.c 2004-05-04 14:04:27.000000000 +0200
+@@ -587,6 +587,8 @@
+ return -EINVAL;
+ s = (struct hdlcdrv_state *)dev->priv;
+
++ netif_stop_queue(dev);
++
+ if (s->ops && s->ops->close)
+ i = s->ops->close(dev);
+ if (s->skb)
+diff -Nur linux-2.4.32-rc1/drivers/net/irda/au1k_ir.c linux-2.4.32-rc1.mips/drivers/net/irda/au1k_ir.c
+--- linux-2.4.32-rc1/drivers/net/irda/au1k_ir.c 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/net/irda/au1k_ir.c 2005-02-03 07:35:29.000000000 +0100
+@@ -81,10 +81,6 @@
+
+ #define RUN_AT(x) (jiffies + (x))
+
+-#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
+-static BCSR * const bcsr = (BCSR *)0xAE000000;
+-#endif
+-
+ static spinlock_t ir_lock = SPIN_LOCK_UNLOCKED;
+
+ /*
+diff -Nur linux-2.4.32-rc1/drivers/net/sgiseeq.c linux-2.4.32-rc1.mips/drivers/net/sgiseeq.c
+--- linux-2.4.32-rc1/drivers/net/sgiseeq.c 2005-01-19 15:09:56.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/net/sgiseeq.c 2005-09-23 16:35:27.000000000 +0200
+@@ -24,16 +24,16 @@
+ #include <asm/io.h>
+ #include <asm/system.h>
+ #include <asm/bitops.h>
++#include <asm/paccess.h>
+ #include <asm/page.h>
+ #include <asm/pgtable.h>
++#include <asm/sgi/mc.h>
+ #include <asm/sgi/hpc3.h>
+ #include <asm/sgi/ip22.h>
+ #include <asm/sgialib.h>
+
+ #include "sgiseeq.h"
+
+-static char *version = "sgiseeq.c: David S. Miller (dm@engr.sgi.com)\n";
+-
+ static char *sgiseeqstr = "SGI Seeq8003";
+
+ /*
+@@ -113,9 +113,9 @@
+
+ static inline void hpc3_eth_reset(struct hpc3_ethregs *hregs)
+ {
+- hregs->rx_reset = HPC3_ERXRST_CRESET | HPC3_ERXRST_CLRIRQ;
++ hregs->reset = HPC3_ERST_CRESET | HPC3_ERST_CLRIRQ;
+ udelay(20);
+- hregs->rx_reset = 0;
++ hregs->reset = 0;
+ }
+
+ static inline void reset_hpc3_and_seeq(struct hpc3_ethregs *hregs,
+@@ -238,7 +238,6 @@
+
+ #define TSTAT_INIT_SEEQ (SEEQ_TCMD_IPT|SEEQ_TCMD_I16|SEEQ_TCMD_IC|SEEQ_TCMD_IUF)
+ #define TSTAT_INIT_EDLC ((TSTAT_INIT_SEEQ) | SEEQ_TCMD_RB2)
+-#define RDMACFG_INIT (HPC3_ERXDCFG_FRXDC | HPC3_ERXDCFG_FEOP | HPC3_ERXDCFG_FIRQ)
+
+ static int init_seeq(struct net_device *dev, struct sgiseeq_private *sp,
+ struct sgiseeq_regs *sregs)
+@@ -260,8 +259,6 @@
+ sregs->tstat = TSTAT_INIT_SEEQ;
+ }
+
+- hregs->rx_dconfig |= RDMACFG_INIT;
+-
+ hregs->rx_ndptr = PHYSADDR(&sp->srings.rx_desc[0]);
+ hregs->tx_ndptr = PHYSADDR(&sp->srings.tx_desc[0]);
+
+@@ -432,7 +429,7 @@
+ spin_lock(&sp->tx_lock);
+
+ /* Ack the IRQ and set software state. */
+- hregs->rx_reset = HPC3_ERXRST_CLRIRQ;
++ hregs->reset = HPC3_ERST_CLRIRQ;
+
+ /* Always check for received packets. */
+ sgiseeq_rx(dev, sp, hregs, sregs);
+@@ -616,7 +613,7 @@
+
+ #define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf))
+
+-int sgiseeq_init(struct hpc3_regs* regs, int irq)
++int sgiseeq_init(struct hpc3_regs* hpcregs, int irq, int has_eeprom)
+ {
+ struct net_device *dev;
+ struct sgiseeq_private *sp;
+@@ -629,7 +626,7 @@
+ goto err_out;
+ }
+ /* Make private data page aligned */
+- sp = (struct sgiseeq_private *) get_zeroed_page(GFP_KERNEL);
++ sp = (struct sgiseeq_private *) get_zeroed_page(GFP_KERNEL);
+ if (!sp) {
+ printk(KERN_ERR "Sgiseeq: Page alloc failed, aborting.\n");
+ err = -ENOMEM;
+@@ -644,7 +641,9 @@
+
+ #define EADDR_NVOFS 250
+ for (i = 0; i < 3; i++) {
+- unsigned short tmp = ip22_nvram_read(EADDR_NVOFS / 2 + i);
++ unsigned short tmp = has_eeprom ?
++ ip22_eeprom_read(&hpcregs->eeprom, EADDR_NVOFS / 2+i) :
++ ip22_nvram_read(EADDR_NVOFS / 2+i);
+
+ dev->dev_addr[2 * i] = tmp >> 8;
+ dev->dev_addr[2 * i + 1] = tmp & 0xff;
+@@ -654,8 +653,8 @@
+ gpriv = sp;
+ gdev = dev;
+ #endif
+- sp->sregs = (struct sgiseeq_regs *) &hpc3c0->eth_ext[0];
+- sp->hregs = &hpc3c0->ethregs;
++ sp->sregs = (struct sgiseeq_regs *) &hpcregs->eth_ext[0];
++ sp->hregs = &hpcregs->ethregs;
+ sp->name = sgiseeqstr;
+ sp->mode = SEEQ_RCMD_RBCAST;
+
+@@ -672,6 +671,11 @@
+ setup_rx_ring(sp->srings.rx_desc, SEEQ_RX_BUFFERS);
+ setup_tx_ring(sp->srings.tx_desc, SEEQ_TX_BUFFERS);
+
++ /* Setup PIO and DMA transfer timing */
++ sp->hregs->pconfig = 0x161;
++ sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
++ HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026;
++
+ /* Reset the chip. */
+ hpc3_eth_reset(sp->hregs);
+
+@@ -699,7 +703,7 @@
+ goto err_out_free_irq;
+ }
+
+- printk(KERN_INFO "%s: SGI Seeq8003 ", dev->name);
++ printk(KERN_INFO "%s: %s ", dev->name, sgiseeqstr);
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+
+@@ -721,10 +725,22 @@
+
+ static int __init sgiseeq_probe(void)
+ {
+- printk(version);
++ unsigned int tmp, ret1, ret2 = 0;
+
+ /* On board adapter on 1st HPC is always present */
+- return sgiseeq_init(hpc3c0, SGI_ENET_IRQ);
++ ret1 = sgiseeq_init(hpc3c0, SGI_ENET_IRQ, 0);
++ /* Let's see if second HPC is there */
++ if (!(ip22_is_fullhouse()) &&
++ get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1]) == 0) {
++ sgimc->giopar |= SGIMC_GIOPAR_MASTEREXP1 |
++ SGIMC_GIOPAR_EXP164 |
++ SGIMC_GIOPAR_HPC264;
++ hpc3c1->pbus_piocfg[0][0] = 0x3ffff;
++ /* interrupt/config register on Challenge S Mezz board */
++ hpc3c1->pbus_extregs[0][0] = 0x30;
++ ret2 = sgiseeq_init(hpc3c1, SGI_GIO_0_IRQ, 1);
++ }
++ return (ret1 & ret2) ? ret1 : 0;
+ }
+
+ static void __exit sgiseeq_exit(void)
+@@ -747,4 +763,6 @@
+ module_init(sgiseeq_probe);
+ module_exit(sgiseeq_exit);
+
++MODULE_DESCRIPTION("SGI Seeq 8003 driver");
++MODULE_AUTHOR("David S. Miller");
+ MODULE_LICENSE("GPL");
+diff -Nur linux-2.4.32-rc1/drivers/pci/pci.c linux-2.4.32-rc1.mips/drivers/pci/pci.c
+--- linux-2.4.32-rc1/drivers/pci/pci.c 2004-11-17 12:54:21.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/pci/pci.c 2004-11-19 01:28:41.000000000 +0100
+@@ -1281,11 +1281,17 @@
+ {
+ unsigned int buses;
+ unsigned short cr;
++ unsigned short bctl;
+ struct pci_bus *child;
+ int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
+
+ pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
+ DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n", dev->slot_name, buses & 0xffffff, pass);
++ /* Disable MasterAbortMode during probing to avoid reporting
++ of bus errors (in some architectures) */
++ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bctl);
++ pci_write_config_word(dev, PCI_BRIDGE_CONTROL,
++ bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT);
+ if ((buses & 0xffff00) && !pcibios_assign_all_busses()) {
+ /*
+ * Bus already configured by firmware, process it in the first
+@@ -1351,6 +1357,7 @@
+ pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
+ pci_write_config_word(dev, PCI_COMMAND, cr);
+ }
++ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl);
+ sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
+ return max;
+ }
+diff -Nur linux-2.4.32-rc1/drivers/pcmcia/au1000_db1x00.c linux-2.4.32-rc1.mips/drivers/pcmcia/au1000_db1x00.c
+--- linux-2.4.32-rc1/drivers/pcmcia/au1000_db1x00.c 2005-01-19 15:09:57.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/pcmcia/au1000_db1x00.c 2005-02-03 07:35:30.000000000 +0100
+@@ -1,6 +1,6 @@
+ /*
+ *
+- * Alchemy Semi Db1x00 boards specific pcmcia routines.
++ * AMD Alchemy DUAL-SLOT Db1x00 boards' specific pcmcia routines.
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+@@ -54,9 +54,20 @@
+ #include <asm/au1000.h>
+ #include <asm/au1000_pcmcia.h>
+
++#if defined(CONFIG_MIPS_PB1200)
++#include <asm/pb1200.h>
++#elif defined(CONFIG_MIPS_DB1200)
++#include <asm/db1200.h>
++#else
+ #include <asm/db1x00.h>
++#endif
+
+-static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++#define PCMCIA_MAX_SOCK 1
++#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK+1)
++
++/* VPP/VCC */
++#define SET_VCC_VPP(VCC, VPP, SLOT)\
++ ((((VCC)<<2) | ((VPP)<<0)) << ((SLOT)*8))
+
+ static int db1x00_pcmcia_init(struct pcmcia_init *init)
+ {
+@@ -76,7 +87,7 @@
+ db1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
+ {
+ u32 inserted;
+- unsigned char vs;
++ u16 vs;
+
+ if(sock > PCMCIA_MAX_SOCK) return -1;
+
+@@ -87,11 +98,11 @@
+
+ if (sock == 0) {
+ vs = bcsr->status & 0x3;
+- inserted = !(bcsr->status & (1<<4));
++ inserted = BOARD_CARD_INSERTED(0);
+ }
+ else {
+ vs = (bcsr->status & 0xC)>>2;
+- inserted = !(bcsr->status & (1<<5));
++ inserted = BOARD_CARD_INSERTED(1);
+ }
+
+ DEBUG(KERN_DEBUG "db1x00 socket %d: inserted %d, vs %d\n",
+@@ -144,16 +155,9 @@
+ if(info->sock > PCMCIA_MAX_SOCK) return -1;
+
+ if(info->sock == 0)
+-#ifdef CONFIG_MIPS_DB1550
+- info->irq = AU1000_GPIO_3;
++ info->irq = BOARD_PC0_INT;
+ else
+- info->irq = AU1000_GPIO_5;
+-#else
+- info->irq = AU1000_GPIO_2;
+- else
+- info->irq = AU1000_GPIO_5;
+-#endif
+-
++ info->irq = BOARD_PC1_INT;
+ return 0;
+ }
+
+diff -Nur linux-2.4.32-rc1/drivers/pcmcia/Config.in linux-2.4.32-rc1.mips/drivers/pcmcia/Config.in
+--- linux-2.4.32-rc1/drivers/pcmcia/Config.in 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/pcmcia/Config.in 2004-02-22 06:21:34.000000000 +0100
+@@ -30,16 +30,14 @@
+ dep_tristate ' M8xx support' CONFIG_PCMCIA_M8XX $CONFIG_PCMCIA
+ fi
+ if [ "$CONFIG_SOC_AU1X00" = "y" ]; then
+- dep_tristate ' Au1x00 PCMCIA support' CONFIG_PCMCIA_AU1X00 $CONFIG_PCMCIA
+- if [ "$CONFIG_PCMCIA_AU1X00" != "n" ]; then
+- bool ' Pb1x00 board support' CONFIG_PCMCIA_PB1X00
+- bool ' Db1x00 board support' CONFIG_PCMCIA_DB1X00
+- bool ' XXS1500 board support' CONFIG_PCMCIA_XXS1500
+- fi
++ dep_tristate ' Au1x00 PCMCIA support' CONFIG_PCMCIA_AU1X00 $CONFIG_PCMCIA
+ fi
+ if [ "$CONFIG_SIBYTE_SB1xxx_SOC" = "y" ]; then
+ dep_bool ' SiByte PCMCIA support' CONFIG_PCMCIA_SIBYTE $CONFIG_PCMCIA $CONFIG_BLK_DEV_IDE_SIBYTE
+ fi
++ if [ "$CONFIG_VRC4171" = "y" -o "$CONFIG_VRC4171" = "m" ]; then
++ dep_tristate ' NEC VRC4171 Card Controllers support' CONFIG_PCMCIA_VRC4171 $CONFIG_PCMCIA
++ fi
+ if [ "$CONFIG_VRC4173" = "y" -o "$CONFIG_VRC4173" = "m" ]; then
+ dep_tristate ' NEC VRC4173 CARDU support' CONFIG_PCMCIA_VRC4173 $CONFIG_PCMCIA
+ fi
+diff -Nur linux-2.4.32-rc1/drivers/pcmcia/Makefile linux-2.4.32-rc1.mips/drivers/pcmcia/Makefile
+--- linux-2.4.32-rc1/drivers/pcmcia/Makefile 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/pcmcia/Makefile 2005-02-03 07:35:30.000000000 +0100
+@@ -61,9 +61,18 @@
+
+ obj-$(CONFIG_PCMCIA_AU1X00) += au1x00_ss.o
+ au1000_ss-objs-y := au1000_generic.o
+-au1000_ss-objs-$(CONFIG_PCMCIA_PB1X00) += au1000_pb1x00.o
+-au1000_ss-objs-$(CONFIG_PCMCIA_DB1X00) += au1000_db1x00.o
+-au1000_ss-objs-$(CONFIG_PCMCIA_XXS1500) += au1000_xxs1500.o
++au1000_ss-objs-$(CONFIG_MIPS_PB1000) += au1000_pb1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_PB1100) += au1000_pb1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_PB1500) += au1000_pb1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_PB1550) += au1000_pb1550.o
++au1000_ss-objs-$(CONFIG_MIPS_PB1200) += au1000_db1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_DB1000) += au1000_db1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_DB1100) += au1000_db1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_DB1500) += au1000_db1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_DB1550) += au1000_db1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_DB1200) += au1000_db1x00.o
++au1000_ss-objs-$(CONFIG_MIPS_HYDROGEN3) += au1000_hydrogen3.o
++au1000_ss-objs-$(CONFIG_MIPS_XXS1500) += au1000_xxs1500.o
+
+ obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o
+ obj-$(CONFIG_PCMCIA_M8XX) += m8xx_pcmcia.o
+@@ -89,6 +98,7 @@
+ sa1100_cs-objs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o sa1111_generic.o
+ sa1100_cs-objs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o
+
++obj-$(CONFIG_PCMCIA_VRC4171) += vrc4171_card.o
+ obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o
+
+ include $(TOPDIR)/Rules.make
+diff -Nur linux-2.4.32-rc1/drivers/pcmcia/vrc4171_card.c linux-2.4.32-rc1.mips/drivers/pcmcia/vrc4171_card.c
+--- linux-2.4.32-rc1/drivers/pcmcia/vrc4171_card.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/pcmcia/vrc4171_card.c 2004-01-19 16:54:58.000000000 +0100
+@@ -0,0 +1,886 @@
++/*
++ * vrc4171_card.c, NEC VRC4171 Card Controller driver for Socket Services.
++ *
++ * Copyright (C) 2003 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
++ *
++ * 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/ioport.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++
++#include <asm/io.h>
++#include <asm/vr41xx/vrc4171.h>
++
++#include <pcmcia/ss.h>
++
++#include "i82365.h"
++
++MODULE_DESCRIPTION("NEC VRC4171 Card Controllers driver for Socket Services");
++MODULE_AUTHOR("Yoichi Yuasa <yuasa@hh.iij4u.or.jp>");
++MODULE_LICENSE("GPL");
++
++#define CARD_MAX_SLOTS 2
++#define CARD_SLOTA 0
++#define CARD_SLOTB 1
++#define CARD_SLOTB_OFFSET 0x40
++
++#define CARD_MEM_START 0x10000000
++#define CARD_MEM_END 0x13ffffff
++#define CARD_MAX_MEM_OFFSET 0x3ffffff
++#define CARD_MAX_MEM_SPEED 1000
++
++#define CARD_CONTROLLER_INDEX 0x03e0
++#define CARD_CONTROLLER_DATA 0x03e1
++#define CARD_CONTROLLER_SIZE 2
++ /* Power register */
++ #define VPP_GET_VCC 0x01
++ #define POWER_ENABLE 0x10
++ #define CARD_VOLTAGE_SENSE 0x1f
++ #define VCC_3VORXV_CAPABLE 0x00
++ #define VCC_XV_ONLY 0x01
++ #define VCC_3V_CAPABLE 0x02
++ #define VCC_5V_ONLY 0x03
++ #define CARD_VOLTAGE_SELECT 0x2f
++ #define VCC_3V 0x01
++ #define VCC_5V 0x00
++ #define VCC_XV 0x02
++ #define VCC_STATUS_3V 0x02
++ #define VCC_STATUS_5V 0x01
++ #define VCC_STATUS_XV 0x03
++ #define GLOBAL_CONTROL 0x1e
++ #define EXWRBK 0x04
++ #define IRQPM_EN 0x08
++ #define CLRPMIRQ 0x10
++
++#define IO_MAX_MAPS 2
++#define MEM_MAX_MAPS 5
++
++enum {
++ SLOTB_PROBE = 0,
++ SLOTB_NOPROBE_IO,
++ SLOTB_NOPROBE_MEM,
++ SLOTB_NOPROBE_ALL
++};
++
++typedef struct vrc4171_socket {
++ int noprobe;
++ void (*handler)(void *, unsigned int);
++ void *info;
++ socket_cap_t cap;
++ spinlock_t event_lock;
++ uint16_t events;
++ struct socket_info_t *pcmcia_socket;
++ struct tq_struct tq_task;
++ char name[24];
++ int csc_irq;
++ int io_irq;
++} vrc4171_socket_t;
++
++static vrc4171_socket_t vrc4171_sockets[CARD_MAX_SLOTS];
++static int vrc4171_slotb = SLOTB_IS_NONE;
++static unsigned int vrc4171_irq;
++static uint16_t vrc4171_irq_mask = 0xdeb8;
++
++extern struct socket_info_t *pcmcia_register_socket(int slot,
++ struct pccard_operations *vtable,
++ int use_bus_pm);
++extern void pcmcia_unregister_socket(struct socket_info_t *s);
++
++static inline uint8_t exca_read_byte(int slot, uint8_t index)
++{
++ if (slot == CARD_SLOTB)
++ index += CARD_SLOTB_OFFSET;
++
++ outb(index, CARD_CONTROLLER_INDEX);
++ return inb(CARD_CONTROLLER_DATA);
++}
++
++static inline uint16_t exca_read_word(int slot, uint8_t index)
++{
++ uint16_t data;
++
++ if (slot == CARD_SLOTB)
++ index += CARD_SLOTB_OFFSET;
++
++ outb(index++, CARD_CONTROLLER_INDEX);
++ data = inb(CARD_CONTROLLER_DATA);
++
++ outb(index, CARD_CONTROLLER_INDEX);
++ data |= ((uint16_t)inb(CARD_CONTROLLER_DATA)) << 8;
++
++ return data;
++}
++
++static inline uint8_t exca_write_byte(int slot, uint8_t index, uint8_t data)
++{
++ if (slot == CARD_SLOTB)
++ index += CARD_SLOTB_OFFSET;
++
++ outb(index, CARD_CONTROLLER_INDEX);
++ outb(data, CARD_CONTROLLER_DATA);
++
++ return data;
++}
++
++static inline uint16_t exca_write_word(int slot, uint8_t index, uint16_t data)
++{
++ if (slot == CARD_SLOTB)
++ index += CARD_SLOTB_OFFSET;
++
++ outb(index++, CARD_CONTROLLER_INDEX);
++ outb(data, CARD_CONTROLLER_DATA);
++
++ outb(index, CARD_CONTROLLER_INDEX);
++ outb((uint8_t)(data >> 8), CARD_CONTROLLER_DATA);
++
++ return data;
++}
++
++static inline int search_nonuse_irq(void)
++{
++ int i;
++
++ for (i = 0; i < 16; i++) {
++ if (vrc4171_irq_mask & (1 << i)) {
++ vrc4171_irq_mask &= ~(1 << i);
++ return i;
++ }
++ }
++
++ return -1;
++}
++
++static int pccard_init(unsigned int slot)
++{
++ vrc4171_socket_t *socket = &vrc4171_sockets[slot];
++
++ socket->cap.features |= SS_CAP_PCCARD | SS_CAP_PAGE_REGS;
++ socket->cap.irq_mask = 0;
++ socket->cap.pci_irq = vrc4171_irq;
++ socket->cap.map_size = 0x1000;
++ socket->events = 0;
++ spin_lock_init(socket->event_lock);
++ socket->csc_irq = search_nonuse_irq();
++ socket->io_irq = search_nonuse_irq();
++
++ return 0;
++}
++
++static int pccard_suspend(unsigned int slot)
++{
++ return -EINVAL;
++}
++
++static int pccard_register_callback(unsigned int slot,
++ void (*handler)(void *, unsigned int),
++ void *info)
++{
++ vrc4171_socket_t *socket;
++
++ if (slot >= CARD_MAX_SLOTS)
++ return -EINVAL;
++
++ socket = &vrc4171_sockets[slot];
++
++ socket->handler = handler;
++ socket->info = info;
++
++ if (handler)
++ MOD_INC_USE_COUNT;
++ else
++ MOD_DEC_USE_COUNT;
++
++ return 0;
++}
++
++static int pccard_inquire_socket(unsigned int slot, socket_cap_t *cap)
++{
++ vrc4171_socket_t *socket;
++
++ if (slot >= CARD_MAX_SLOTS || cap == NULL)
++ return -EINVAL;
++
++ socket = &vrc4171_sockets[slot];
++
++ *cap = socket->cap;
++
++ return 0;
++}
++
++static int pccard_get_status(unsigned int slot, u_int *value)
++{
++ uint8_t status, sense;
++ u_int val = 0;
++
++ if (slot >= CARD_MAX_SLOTS || value == NULL)
++ return -EINVAL;
++
++ status = exca_read_byte(slot, I365_STATUS);
++ if (exca_read_byte(slot, I365_INTCTL) & I365_PC_IOCARD) {
++ if (status & I365_CS_STSCHG)
++ val |= SS_STSCHG;
++ } else {
++ if (!(status & I365_CS_BVD1))
++ val |= SS_BATDEAD;
++ else if ((status & (I365_CS_BVD1 | I365_CS_BVD2)) == I365_CS_BVD1)
++ val |= SS_BATWARN;
++ }
++ if ((status & I365_CS_DETECT) == I365_CS_DETECT)
++ val |= SS_DETECT;
++ if (status & I365_CS_WRPROT)
++ val |= SS_WRPROT;
++ if (status & I365_CS_READY)
++ val |= SS_READY;
++ if (status & I365_CS_POWERON)
++ val |= SS_POWERON;
++
++ sense = exca_read_byte(slot, CARD_VOLTAGE_SENSE);
++ switch (sense) {
++ case VCC_3VORXV_CAPABLE:
++ val |= SS_3VCARD | SS_XVCARD;
++ break;
++ case VCC_XV_ONLY:
++ val |= SS_XVCARD;
++ break;
++ case VCC_3V_CAPABLE:
++ val |= SS_3VCARD;
++ break;
++ default:
++ /* 5V only */
++ break;
++ }
++
++ *value = val;
++
++ return 0;
++}
++
++static inline u_char get_Vcc_value(uint8_t voltage)
++{
++ switch (voltage) {
++ case VCC_STATUS_3V:
++ return 33;
++ case VCC_STATUS_5V:
++ return 50;
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++static inline u_char get_Vpp_value(uint8_t power, u_char Vcc)
++{
++ if ((power & 0x03) == 0x01 || (power & 0x03) == 0x02)
++ return Vcc;
++
++ return 0;
++}
++
++static int pccard_get_socket(unsigned int slot, socket_state_t *state)
++{
++ vrc4171_socket_t *socket;
++ uint8_t power, voltage, control, cscint;
++
++ if (slot >= CARD_MAX_SLOTS || state == NULL)
++ return -EINVAL;
++
++ socket = &vrc4171_sockets[slot];
++
++ power = exca_read_byte(slot, I365_POWER);
++ voltage = exca_read_byte(slot, CARD_VOLTAGE_SELECT);
++
++ state->Vcc = get_Vcc_value(voltage);
++ state->Vpp = get_Vpp_value(power, state->Vcc);
++
++ state->flags = 0;
++ if (power & POWER_ENABLE)
++ state->flags |= SS_PWR_AUTO;
++ if (power & I365_PWR_OUT)
++ state->flags |= SS_OUTPUT_ENA;
++
++ control = exca_read_byte(slot, I365_INTCTL);
++ if (control & I365_PC_IOCARD)
++ state->flags |= SS_IOCARD;
++ if (!(control & I365_PC_RESET))
++ state->flags |= SS_RESET;
++
++ cscint = exca_read_byte(slot, I365_CSCINT);
++ state->csc_mask = 0;
++ if (state->flags & SS_IOCARD) {
++ if (cscint & I365_CSC_STSCHG)
++ state->flags |= SS_STSCHG;
++ } else {
++ if (cscint & I365_CSC_BVD1)
++ state->csc_mask |= SS_BATDEAD;
++ if (cscint & I365_CSC_BVD2)
++ state->csc_mask |= SS_BATWARN;
++ }
++ if (cscint & I365_CSC_READY)
++ state->csc_mask |= SS_READY;
++ if (cscint & I365_CSC_DETECT)
++ state->csc_mask |= SS_DETECT;
++
++ return 0;
++}
++
++static inline uint8_t set_Vcc_value(u_char Vcc)
++{
++ switch (Vcc) {
++ case 33:
++ return VCC_3V;
++ case 50:
++ return VCC_5V;
++ }
++
++ /* Small voltage is chosen for safety. */
++ return VCC_3V;
++}
++
++static int pccard_set_socket(unsigned int slot, socket_state_t *state)
++{
++ vrc4171_socket_t *socket;
++ uint8_t voltage, power, control, cscint;
++
++ if (slot >= CARD_MAX_SLOTS ||
++ (state->Vpp != state->Vcc && state->Vpp != 0) ||
++ (state->Vcc != 50 && state->Vcc != 33 && state->Vcc != 0))
++ return -EINVAL;
++
++ socket = &vrc4171_sockets[slot];
++
++ spin_lock_irq(&socket->event_lock);
++
++ voltage = set_Vcc_value(state->Vcc);
++ exca_write_byte(slot, CARD_VOLTAGE_SELECT, voltage);
++
++ power = POWER_ENABLE;
++ if (state->Vpp == state->Vcc)
++ power |= VPP_GET_VCC;
++ if (state->flags & SS_OUTPUT_ENA)
++ power |= I365_PWR_OUT;
++ exca_write_byte(slot, I365_POWER, power);
++
++ control = 0;
++ if (state->io_irq != 0)
++ control |= socket->io_irq;
++ if (state->flags & SS_IOCARD)
++ control |= I365_PC_IOCARD;
++ if (state->flags & SS_RESET)
++ control &= ~I365_PC_RESET;
++ else
++ control |= I365_PC_RESET;
++ exca_write_byte(slot, I365_INTCTL, control);
++
++ cscint = 0;
++ exca_write_byte(slot, I365_CSCINT, cscint);
++ exca_read_byte(slot, I365_CSC); /* clear CardStatus change */
++ if (state->csc_mask != 0)
++ cscint |= socket->csc_irq << 8;
++ if (state->flags & SS_IOCARD) {
++ if (state->csc_mask & SS_STSCHG)
++ cscint |= I365_CSC_STSCHG;
++ } else {
++ if (state->csc_mask & SS_BATDEAD)
++ cscint |= I365_CSC_BVD1;
++ if (state->csc_mask & SS_BATWARN)
++ cscint |= I365_CSC_BVD2;
++ }
++ if (state->csc_mask & SS_READY)
++ cscint |= I365_CSC_READY;
++ if (state->csc_mask & SS_DETECT)
++ cscint |= I365_CSC_DETECT;
++ exca_write_byte(slot, I365_CSCINT, cscint);
++
++ spin_unlock_irq(&socket->event_lock);
++
++ return 0;
++}
++
++static int pccard_get_io_map(unsigned int slot, struct pccard_io_map *io)
++{
++ vrc4171_socket_t *socket;
++ uint8_t ioctl, addrwin;
++ u_char map;
++
++ if (slot >= CARD_MAX_SLOTS || io == NULL ||
++ io->map >= IO_MAX_MAPS)
++ return -EINVAL;
++
++ socket = &vrc4171_sockets[slot];
++ map = io->map;
++
++ io->start = exca_read_word(slot, I365_IO(map)+I365_W_START);
++ io->stop = exca_read_word(slot, I365_IO(map)+I365_W_STOP);
++
++ ioctl = exca_read_byte(slot, I365_IOCTL);
++ if (io->flags & I365_IOCTL_WAIT(map))
++ io->speed = 1;
++ else
++ io->speed = 0;
++
++ io->flags = 0;
++ if (ioctl & I365_IOCTL_16BIT(map))
++ io->flags |= MAP_16BIT;
++ if (ioctl & I365_IOCTL_IOCS16(map))
++ io->flags |= MAP_AUTOSZ;
++ if (ioctl & I365_IOCTL_0WS(map))
++ io->flags |= MAP_0WS;
++
++ addrwin = exca_read_byte(slot, I365_ADDRWIN);
++ if (addrwin & I365_ENA_IO(map))
++ io->flags |= MAP_ACTIVE;
++
++ return 0;
++}
++
++static int pccard_set_io_map(unsigned int slot, struct pccard_io_map *io)
++{
++ vrc4171_socket_t *socket;
++ uint8_t ioctl, addrwin;
++ u_char map;
++
++ if (slot >= CARD_MAX_SLOTS ||
++ io == NULL || io->map >= IO_MAX_MAPS ||
++ io->start > 0xffff || io->stop > 0xffff || io->start > io->stop)
++ return -EINVAL;
++
++ socket = &vrc4171_sockets[slot];
++ map = io->map;
++
++ addrwin = exca_read_byte(slot, I365_ADDRWIN);
++ if (addrwin & I365_ENA_IO(map)) {
++ addrwin &= ~I365_ENA_IO(map);
++ exca_write_byte(slot, I365_ADDRWIN, addrwin);
++ }
++
++ exca_write_word(slot, I365_IO(map)+I365_W_START, io->start);
++ exca_write_word(slot, I365_IO(map)+I365_W_STOP, io->stop);
++
++ ioctl = 0;
++ if (io->speed > 0)
++ ioctl |= I365_IOCTL_WAIT(map);
++ if (io->flags & MAP_16BIT)
++ ioctl |= I365_IOCTL_16BIT(map);
++ if (io->flags & MAP_AUTOSZ)
++ ioctl |= I365_IOCTL_IOCS16(map);
++ if (io->flags & MAP_0WS)
++ ioctl |= I365_IOCTL_0WS(map);
++ exca_write_byte(slot, I365_IOCTL, ioctl);
++
++ if (io->flags & MAP_ACTIVE) {
++ addrwin |= I365_ENA_IO(map);
++ exca_write_byte(slot, I365_ADDRWIN, addrwin);
++ }
++
++ return 0;
++}
++
++static int pccard_get_mem_map(unsigned int slot, struct pccard_mem_map *mem)
++{
++ vrc4171_socket_t *socket;
++ uint8_t addrwin;
++ u_long start, stop;
++ u_int offset;
++ u_char map;
++
++ if (slot >= CARD_MAX_SLOTS || mem == NULL || mem->map >= MEM_MAX_MAPS)
++ return -EINVAL;
++
++ socket = &vrc4171_sockets[slot];
++ map = mem->map;
++
++ mem->flags = 0;
++ mem->speed = 0;
++
++ addrwin = exca_read_byte(slot, I365_ADDRWIN);
++ if (addrwin & I365_ENA_MEM(map))
++ mem->flags |= MAP_ACTIVE;
++
++ start = exca_read_word(slot, I365_MEM(map)+I365_W_START);
++ if (start & I365_MEM_16BIT)
++ mem->flags |= MAP_16BIT;
++ mem->sys_start = (start & 0x3fffUL) << 12;
++
++ stop = exca_read_word(slot, I365_MEM(map)+I365_W_STOP);
++ if (start & I365_MEM_WS0)
++ mem->speed += 1;
++ if (start & I365_MEM_WS1)
++ mem->speed += 2;
++ mem->sys_stop = ((stop & 0x3fffUL) << 12) + 0xfffUL;
++
++ offset = exca_read_word(slot, I365_MEM(map)+I365_W_OFF);
++ if (offset & I365_MEM_REG)
++ mem->flags |= MAP_ATTRIB;
++ if (offset & I365_MEM_WRPROT)
++ mem->flags |= MAP_WRPROT;
++ mem->card_start = (offset & 0x3fffUL) << 12;
++
++ mem->sys_start += CARD_MEM_START;
++ mem->sys_stop += CARD_MEM_START;
++
++ return 0;
++}
++
++static int pccard_set_mem_map(unsigned int slot, struct pccard_mem_map *mem)
++{
++ vrc4171_socket_t *socket;
++ uint16_t start, stop, offset;
++ uint8_t addrwin;
++ u_char map;
++
++ if (slot >= CARD_MAX_SLOTS ||
++ mem == NULL || mem->map >= MEM_MAX_MAPS ||
++ mem->sys_start < CARD_MEM_START || mem->sys_start > CARD_MEM_END ||
++ mem->sys_stop < CARD_MEM_START || mem->sys_stop > CARD_MEM_END ||
++ mem->sys_start > mem->sys_stop ||
++ mem->card_start > CARD_MAX_MEM_OFFSET ||
++ mem->speed > CARD_MAX_MEM_SPEED)
++ return -EINVAL;
++
++ socket = &vrc4171_sockets[slot];
++ map = mem->map;
++
++ addrwin = exca_read_byte(slot, I365_ADDRWIN);
++ if (addrwin & I365_ENA_MEM(map)) {
++ addrwin &= ~I365_ENA_MEM(map);
++ exca_write_byte(slot, I365_ADDRWIN, addrwin);
++ }
++
++ start = (mem->sys_start >> 12) & 0x3fff;
++ if (mem->flags & MAP_16BIT)
++ start |= I365_MEM_16BIT;
++ exca_write_word(slot, I365_MEM(map)+I365_W_START, start);
++
++ stop = (mem->sys_stop >> 12) & 0x3fff;
++ switch (mem->speed) {
++ case 0:
++ break;
++ case 1:
++ stop |= I365_MEM_WS0;
++ break;
++ case 2:
++ stop |= I365_MEM_WS1;
++ break;
++ default:
++ stop |= I365_MEM_WS0 | I365_MEM_WS1;
++ break;
++ }
++ exca_write_word(slot, I365_MEM(map)+I365_W_STOP, stop);
++
++ offset = (mem->card_start >> 12) & 0x3fff;
++ if (mem->flags & MAP_ATTRIB)
++ offset |= I365_MEM_REG;
++ if (mem->flags & MAP_WRPROT)
++ offset |= I365_MEM_WRPROT;
++ exca_write_word(slot, I365_MEM(map)+I365_W_OFF, offset);
++
++ if (mem->flags & MAP_ACTIVE) {
++ addrwin |= I365_ENA_MEM(map);
++ exca_write_byte(slot, I365_ADDRWIN, addrwin);
++ }
++
++ return 0;
++}
++
++static void pccard_proc_setup(unsigned int slot, struct proc_dir_entry *base)
++{
++}
++
++static struct pccard_operations vrc4171_pccard_operations = {
++ .init = pccard_init,
++ .suspend = pccard_suspend,
++ .register_callback = pccard_register_callback,
++ .inquire_socket = pccard_inquire_socket,
++ .get_status = pccard_get_status,
++ .get_socket = pccard_get_socket,
++ .set_socket = pccard_set_socket,
++ .get_io_map = pccard_get_io_map,
++ .set_io_map = pccard_set_io_map,
++ .get_mem_map = pccard_get_mem_map,
++ .set_mem_map = pccard_set_mem_map,
++ .proc_setup = pccard_proc_setup,
++};
++
++static void pccard_bh(void *data)
++{
++ vrc4171_socket_t *socket = (vrc4171_socket_t *)data;
++ uint16_t events;
++
++ spin_lock_irq(&socket->event_lock);
++ events = socket->events;
++ socket->events = 0;
++ spin_unlock_irq(&socket->event_lock);
++
++ if (socket->handler)
++ socket->handler(socket->info, events);
++}
++
++static inline uint16_t get_events(int slot)
++{
++ uint16_t events = 0;
++ uint8_t status, csc;
++
++ status = exca_read_byte(slot, I365_STATUS);
++ csc = exca_read_byte(slot, I365_CSC);
++
++ if (exca_read_byte(slot, I365_INTCTL) & I365_PC_IOCARD) {
++ if ((csc & I365_CSC_STSCHG) && (status & I365_CS_STSCHG))
++ events |= SS_STSCHG;
++ } else {
++ if (csc & (I365_CSC_BVD1 | I365_CSC_BVD2)) {
++ if (!(status & I365_CS_BVD1))
++ events |= SS_BATDEAD;
++ else if ((status & (I365_CS_BVD1 | I365_CS_BVD2)) == I365_CS_BVD1)
++ events |= SS_BATWARN;
++ }
++ }
++ if ((csc & I365_CSC_READY) && (status & I365_CS_READY))
++ events |= SS_READY;
++ if ((csc & I365_CSC_DETECT) && ((status & I365_CS_DETECT) == I365_CS_DETECT))
++ events |= SS_DETECT;
++
++ return events;
++}
++
++static void pccard_status_change(int slot, vrc4171_socket_t *socket)
++{
++ uint16_t events;
++
++ socket->tq_task.routine = pccard_bh;
++ socket->tq_task.data = socket;
++
++ events = get_events(slot);
++ if (events) {
++ spin_lock(&socket->event_lock);
++ socket->events |= events;
++ spin_unlock(&socket->event_lock);
++ schedule_task(&socket->tq_task);
++ }
++}
++
++static void pccard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++ vrc4171_socket_t *socket;
++ uint16_t status;
++
++ status = vrc4171_get_irq_status();
++ if (status & IRQ_A) {
++ socket = &vrc4171_sockets[CARD_SLOTA];
++ if (socket->noprobe == SLOTB_PROBE) {
++ if (status & (1 << socket->csc_irq))
++ pccard_status_change(CARD_SLOTA, socket);
++ }
++ }
++
++ if (status & IRQ_B) {
++ socket = &vrc4171_sockets[CARD_SLOTB];
++ if (socket->noprobe == SLOTB_PROBE) {
++ if (status & (1 << socket->csc_irq))
++ pccard_status_change(CARD_SLOTB, socket);
++ }
++ }
++}
++
++static inline void reserve_using_irq(int slot)
++{
++ unsigned int irq;
++
++ irq = exca_read_byte(slot, I365_INTCTL);
++ irq &= 0x0f;
++ vrc4171_irq_mask &= ~(1 << irq);
++
++ irq = exca_read_byte(slot, I365_CSCINT);
++ irq = (irq & 0xf0) >> 4;
++ vrc4171_irq_mask &= ~(1 << irq);
++}
++
++static int __devinit vrc4171_add_socket(int slot)
++{
++ vrc4171_socket_t *socket;
++
++ if (slot >= CARD_MAX_SLOTS)
++ return -EINVAL;
++
++ socket = &vrc4171_sockets[slot];
++ if (socket->noprobe != SLOTB_PROBE) {
++ uint8_t addrwin;
++
++ switch (socket->noprobe) {
++ case SLOTB_NOPROBE_MEM:
++ addrwin = exca_read_byte(slot, I365_ADDRWIN);
++ addrwin &= 0x1f;
++ exca_write_byte(slot, I365_ADDRWIN, addrwin);
++ break;
++ case SLOTB_NOPROBE_IO:
++ addrwin = exca_read_byte(slot, I365_ADDRWIN);
++ addrwin &= 0xc0;
++ exca_write_byte(slot, I365_ADDRWIN, addrwin);
++ break;
++ default:
++ break;
++ }
++
++ reserve_using_irq(slot);
++
++ return 0;
++ }
++
++ sprintf(socket->name, "NEC VRC4171 Card Slot %1c", 'A' + slot);
++
++ socket->pcmcia_socket = pcmcia_register_socket(slot, &vrc4171_pccard_operations, 1);
++ if (socket->pcmcia_socket == NULL)
++ return -ENOMEM;
++
++ exca_write_byte(slot, I365_ADDRWIN, 0);
++
++ exca_write_byte(slot, GLOBAL_CONTROL, 0);
++
++ return 0;
++}
++
++static void vrc4171_remove_socket(int slot)
++{
++ vrc4171_socket_t *socket;
++
++ if (slot >= CARD_MAX_SLOTS)
++ return;
++
++ socket = &vrc4171_sockets[slot];
++
++ if (socket->pcmcia_socket != NULL) {
++ pcmcia_unregister_socket(socket->pcmcia_socket);
++ socket->pcmcia_socket = NULL;
++ }
++}
++
++static int __devinit vrc4171_card_setup(char *options)
++{
++ if (options == NULL || *options == '\0')
++ return 0;
++
++ if (strncmp(options, "irq:", 4) == 0) {
++ int irq;
++ options += 4;
++ irq = simple_strtoul(options, &options, 0);
++ if (irq >= 0 && irq < NR_IRQS)
++ vrc4171_irq = irq;
++
++ if (*options != ',')
++ return 0;
++ options++;
++ }
++
++ if (strncmp(options, "slota:", 6) == 0) {
++ options += 6;
++ if (*options != '\0') {
++ if (strncmp(options, "noprobe", 7) == 0) {
++ vrc4171_sockets[CARD_SLOTA].noprobe = 1;
++ options += 7;
++ }
++
++ if (*options != ',')
++ return 0;
++ options++;
++ } else
++ return 0;
++
++ }
++
++ if (strncmp(options, "slotb:", 6) == 0) {
++ options += 6;
++ if (*options != '\0') {
++ if (strncmp(options, "pccard", 6) == 0) {
++ vrc4171_slotb = SLOTB_IS_PCCARD;
++ options += 6;
++ } else if (strncmp(options, "cf", 2) == 0) {
++ vrc4171_slotb = SLOTB_IS_CF;
++ options += 2;
++ } else if (strncmp(options, "flashrom", 8) == 0) {
++ vrc4171_slotb = SLOTB_IS_FLASHROM;
++ options += 8;
++ } else if (strncmp(options, "none", 4) == 0) {
++ vrc4171_slotb = SLOTB_IS_NONE;
++ options += 4;
++ }
++
++ if (*options != ',')
++ return 0;
++ options++;
++
++ if ( strncmp(options, "memnoprobe", 10) == 0)
++ vrc4171_sockets[CARD_SLOTB].noprobe = SLOTB_NOPROBE_MEM;
++ if ( strncmp(options, "ionoprobe", 9) == 0)
++ vrc4171_sockets[CARD_SLOTB].noprobe = SLOTB_NOPROBE_IO;
++ if ( strncmp(options, "noprobe", 7) == 0)
++ vrc4171_sockets[CARD_SLOTB].noprobe = SLOTB_NOPROBE_ALL;
++ }
++ }
++
++ return 0;
++}
++
++__setup("vrc4171_card=", vrc4171_card_setup);
++
++static int __devinit vrc4171_card_init(void)
++{
++ int retval, slot;
++
++ vrc4171_set_multifunction_pin(vrc4171_slotb);
++
++ if (request_region(CARD_CONTROLLER_INDEX, CARD_CONTROLLER_SIZE,
++ "NEC VRC4171 Card Controller") == NULL)
++ return -EBUSY;
++
++ for (slot = 0; slot < CARD_MAX_SLOTS; slot++) {
++ if (slot == CARD_SLOTB && vrc4171_slotb == SLOTB_IS_NONE)
++ break;
++
++ retval = vrc4171_add_socket(slot);
++ if (retval != 0)
++ return retval;
++ }
++
++ retval = request_irq(vrc4171_irq, pccard_interrupt, SA_SHIRQ,
++ "NEC VRC4171 Card Controller", vrc4171_sockets);
++ if (retval < 0) {
++ for (slot = 0; slot < CARD_MAX_SLOTS; slot++)
++ vrc4171_remove_socket(slot);
++
++ return retval;
++ }
++
++ printk(KERN_INFO "NEC VRC4171 Card Controller, connected to IRQ %d\n", vrc4171_irq);
++
++ return 0;
++}
++
++static void __devexit vrc4171_card_exit(void)
++{
++ int slot;
++
++ for (slot = 0; slot < CARD_MAX_SLOTS; slot++)
++ vrc4171_remove_socket(slot);
++
++ release_region(CARD_CONTROLLER_INDEX, CARD_CONTROLLER_SIZE);
++}
++
++module_init(vrc4171_card_init);
++module_exit(vrc4171_card_exit);
+diff -Nur linux-2.4.32-rc1/drivers/scsi/NCR53C9x.h linux-2.4.32-rc1.mips/drivers/scsi/NCR53C9x.h
+--- linux-2.4.32-rc1/drivers/scsi/NCR53C9x.h 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/scsi/NCR53C9x.h 2003-12-15 19:19:51.000000000 +0100
+@@ -144,12 +144,7 @@
+
+ #ifndef MULTIPLE_PAD_SIZES
+
+-#ifdef CONFIG_CPU_HAS_WB
+-#include <asm/wbflush.h>
+-#define esp_write(__reg, __val) do{(__reg) = (__val); wbflush();} while(0)
+-#else
+-#define esp_write(__reg, __val) ((__reg) = (__val))
+-#endif
++#define esp_write(__reg, __val) do{(__reg) = (__val); iob();} while(0)
+ #define esp_read(__reg) (__reg)
+
+ struct ESP_regs {
+diff -Nur linux-2.4.32-rc1/drivers/sound/au1550_i2s.c linux-2.4.32-rc1.mips/drivers/sound/au1550_i2s.c
+--- linux-2.4.32-rc1/drivers/sound/au1550_i2s.c 2005-01-19 15:10:04.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/sound/au1550_i2s.c 2005-02-08 08:07:50.000000000 +0100
+@@ -41,6 +41,7 @@
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
++
+ #include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/string.h>
+@@ -62,7 +63,45 @@
+ #include <asm/uaccess.h>
+ #include <asm/hardirq.h>
+ #include <asm/au1000.h>
++
++#if defined(CONFIG_SOC_AU1550)
+ #include <asm/pb1550.h>
++#endif
++
++#if defined(CONFIG_MIPS_PB1200)
++#define WM8731
++#define WM_MODE_USB
++#include <asm/pb1200.h>
++#endif
++
++#if defined(CONFIG_MIPS_FICMMP)
++#define WM8721
++#define WM_MODE_NORMAL
++#include <asm/ficmmp.h>
++#endif
++
++
++#define WM_VOLUME_MIN 47
++#define WM_VOLUME_SCALE 80
++
++#if defined(WM8731)
++ /* OSS interface to the wm i2s.. */
++ #define CODEC_NAME "Wolfson WM8731 I2S"
++ #define WM_I2S_STEREO_MASK (SOUND_MASK_PCM | SOUND_MASK_LINE)
++ #define WM_I2S_SUPPORTED_MASK (WM_I2S_STEREO_MASK | SOUND_MASK_MIC)
++ #define WM_I2S_RECORD_MASK (SOUND_MASK_MIC | SOUND_MASK_LINE1 | SOUND_MASK_LINE)
++#elif defined(WM8721)
++ #define CODEC_NAME "Wolfson WM8721 I2S"
++ #define WM_I2S_STEREO_MASK (SOUND_MASK_PCM)
++ #define WM_I2S_SUPPORTED_MASK (WM_I2S_STEREO_MASK)
++ #define WM_I2S_RECORD_MASK (0)
++#endif
++
++
++#define supported_mixer(FOO) ((FOO >= 0) && \
++ (FOO < SOUND_MIXER_NRDEVICES) && \
++ WM_I2S_SUPPORTED_MASK & (1<<FOO) )
++
+ #include <asm/au1xxx_psc.h>
+ #include <asm/au1xxx_dbdma.h>
+
+@@ -98,13 +137,51 @@
+ * 0 = no VRA, 1 = use VRA if codec supports it
+ * The framework is here, but we currently force no VRA.
+ */
++#if defined(CONFIG_MIPS_PB1200) | defined(CONFIG_MIPS_PB1550)
+ static int vra = 0;
++#elif defined(CONFIG_MIPS_FICMMP)
++static int vra = 1;
++#endif
++
++#define WM_REG_L_HEADPHONE_OUT 0x02
++#define WM_REG_R_HEADPHONE_OUT 0x03
++#define WM_REG_ANALOGUE_AUDIO_PATH_CTRL 0x04
++#define WM_REG_DIGITAL_AUDIO_PATH_CTRL 0x05
++#define WM_REG_POWER_DOWN_CTRL 0x06
++#define WM_REG_DIGITAL_AUDIO_IF 0x07
++#define WM_REG_SAMPLING_CONTROL 0x08
++#define WM_REG_ACTIVE_CTRL 0x09
++#define WM_REG_RESET 0x0F
++#define WM_SC_SR_96000 (0x7<<2)
++#define WM_SC_SR_88200 (0xF<<2)
++#define WM_SC_SR_48000 (0x0<<2)
++#define WM_SC_SR_44100 (0x8<<2)
++#define WM_SC_SR_32000 (0x6<<2)
++#define WM_SC_SR_8018 (0x9<<2)
++#define WM_SC_SR_8000 (0x1<<2)
++#define WM_SC_MODE_USB 1
++#define WM_SC_MODE_NORMAL 0
++#define WM_SC_BOSR_250FS (0<<1)
++#define WM_SC_BOSR_272FS (1<<1)
++#define WM_SC_BOSR_256FS (0<<1)
++#define WM_SC_BOSR_128FS (0<<1)
++#define WM_SC_BOSR_384FS (1<<1)
++#define WM_SC_BOSR_192FS (1<<1)
++
++#define WS_64FS 31
++#define WS_96FS 47
++#define WS_128FS 63
++#define WS_192FS 95
++
++#define MIN_Q_COUNT 2
++
+ MODULE_PARM(vra, "i");
+ MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
+
+ static struct au1550_state {
+ /* soundcore stuff */
+ int dev_audio;
++ int dev_mixer;
+
+ spinlock_t lock;
+ struct semaphore open_sem;
+@@ -114,6 +191,11 @@
+ int no_vra;
+ volatile psc_i2s_t *psc_addr;
+
++ int level_line;
++ int level_mic;
++ int level_left;
++ int level_right;
++
+ struct dmabuf {
+ u32 dmanr;
+ unsigned sample_rate;
+@@ -195,60 +277,224 @@
+ }
+ }
+
+-/* Just a place holder. The Wolfson codec is a write only device,
+- * so we would have to keep a local copy of the data.
+- */
+-#if 0
+-static u8
+-rdcodec(u8 addr)
+-{
+- return 0 /* data */;
+-}
+-#endif
+-
+-
+ static void
+-wrcodec(u8 ctlreg, u8 val)
++wrcodec(u8 ctlreg, u16 val)
+ {
+ int rcnt;
+ extern int pb1550_wm_codec_write(u8 addr, u8 reg, u8 val);
+-
+ /* The codec is a write only device, with a 16-bit control/data
+ * word. Although it is written as two bytes on the I2C, the
+ * format is actually 7 bits of register and 9 bits of data.
+ * The ls bit of the first byte is the ms bit of the data.
+ */
+ rcnt = 0;
+- while ((pb1550_wm_codec_write((0x36 >> 1), ctlreg, val) != 1)
+- && (rcnt < 50)) {
++ while ((pb1550_wm_codec_write((0x36 >> 1),
++ (ctlreg << 1) | ((val >> 8) & 0x01),
++ (u8) (val & 0x00FF)) != 1) &&
++ (rcnt < 50)) {
+ rcnt++;
+-#if 0
+- printk("Codec write retry %02x %02x\n", ctlreg, val);
+-#endif
+ }
++
++ au1550_delay(10);
++}
++
++static int
++au1550_open_mixdev(struct inode *inode, struct file *file)
++{
++ file->private_data = &au1550_state;
++ return 0;
++}
++
++static int
++au1550_release_mixdev(struct inode *inode, struct file *file)
++{
++ return 0;
++}
++
++static int wm_i2s_read_mixer(struct au1550_state *s, int oss_channel)
++{
++ int ret = 0;
++
++ if (WM_I2S_STEREO_MASK & (1 << oss_channel)) {
++ /* nice stereo mixers .. */
++
++ ret = s->level_left | (s->level_right << 8);
++ } else if (oss_channel == SOUND_MIXER_MIC) {
++ ret = 0;
++ /* TODO: Implement read mixer for input/output codecs */
++ }
++
++ return ret;
+ }
+
++static void wm_i2s_write_mixer(struct au1550_state *s, int oss_channel, unsigned int left, unsigned int right)
++{
++ if (WM_I2S_STEREO_MASK & (1 << oss_channel)) {
++ /* stereo mixers */
++ s->level_left = left;
++ s->level_right = right;
++
++ right = (right * WM_VOLUME_SCALE) / 100;
++ left = (left * WM_VOLUME_SCALE) / 100;
++ if (right > WM_VOLUME_SCALE)
++ right = WM_VOLUME_SCALE;
++ if (left > WM_VOLUME_SCALE)
++ left = WM_VOLUME_SCALE;
++
++ right += WM_VOLUME_MIN;
++ left += WM_VOLUME_MIN;
++
++ wrcodec(WM_REG_L_HEADPHONE_OUT, left);
++ wrcodec(WM_REG_R_HEADPHONE_OUT, right);
++
++ }else if (oss_channel == SOUND_MIXER_MIC) {
++ /* TODO: implement write mixer for input/output codecs */
++ }
++}
++
++/* a thin wrapper for write_mixer */
++static void wm_i2s_set_mixer(struct au1550_state *s, unsigned int oss_mixer, unsigned int val )
++{
++ unsigned int left,right;
++
++ /* cleanse input a little */
++ right = ((val >> 8) & 0xff) ;
++ left = (val & 0xff) ;
++
++ if (right > 100) right = 100;
++ if (left > 100) left = 100;
++
++ wm_i2s_write_mixer(s, oss_mixer, left, right);
++}
++
++static int
++au1550_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++ struct au1550_state *s = (struct au1550_state *)file->private_data;
++
++ int i, val = 0;
++
++ if (cmd == SOUND_MIXER_INFO) {
++ mixer_info info;
++ strncpy(info.id, CODEC_NAME, sizeof(info.id));
++ strncpy(info.name, CODEC_NAME, sizeof(info.name));
++ info.modify_counter = 0;
++ if (copy_to_user((void *)arg, &info, sizeof(info)))
++ return -EFAULT;
++ return 0;
++ }
++ if (cmd == SOUND_OLD_MIXER_INFO) {
++ _old_mixer_info info;
++ strncpy(info.id, CODEC_NAME, sizeof(info.id));
++ strncpy(info.name, CODEC_NAME, sizeof(info.name));
++ if (copy_to_user((void *)arg, &info, sizeof(info)))
++ return -EFAULT;
++ return 0;
++ }
++
++ if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
++ return -EINVAL;
++
++ if (cmd == OSS_GETVERSION)
++ return put_user(SOUND_VERSION, (int *)arg);
++
++ if (_SIOC_DIR(cmd) == _SIOC_READ) {
++ switch (_IOC_NR(cmd)) {
++ case SOUND_MIXER_RECSRC: /* give them the current record src */
++ val = 0;
++ /*
++ if (!codec->recmask_io) {
++ val = 0;
++ } else {
++ val = codec->recmask_io(codec, 1, 0);
++ }*/
++ break;
++
++ case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
++ val = WM_I2S_SUPPORTED_MASK;
++ break;
++
++ case SOUND_MIXER_RECMASK:
++ /* Arg contains a bit for each supported recording
++ * source */
++ val = WM_I2S_RECORD_MASK;
++ break;
++
++ case SOUND_MIXER_STEREODEVS:
++ /* Mixer channels supporting stereo */
++ val = WM_I2S_STEREO_MASK;
++ break;
++
++ case SOUND_MIXER_CAPS:
++ val = SOUND_CAP_EXCL_INPUT;
++ break;
++
++ default: /* read a specific mixer */
++ i = _IOC_NR(cmd);
++
++ if (!supported_mixer(i))
++ return -EINVAL;
++
++ val = wm_i2s_read_mixer(s, i);
++ break;
++ }
++ return put_user(val, (int *)arg);
++ }
++
++ if (_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) {
++ if (get_user(val, (int *)arg))
++ return -EFAULT;
++
++ switch (_IOC_NR(cmd)) {
++ case SOUND_MIXER_RECSRC:
++ /* Arg contains a bit for each recording source */
++ if (!WM_I2S_RECORD_MASK)
++ return -EINVAL;
++ if (!val)
++ return 0;
++ if (!(val &= WM_I2S_RECORD_MASK))
++ return -EINVAL;
++
++ return 0;
++ default: /* write a specific mixer */
++ i = _IOC_NR(cmd);
++
++ if (!supported_mixer(i))
++ return -EINVAL;
++
++ wm_i2s_set_mixer(s, i, val);
++
++ return 0;
++ }
++}
++ return -EINVAL;
++}
++
++static loff_t
++au1550_llseek(struct file *file, loff_t offset, int origin)
++{
++ return -ESPIPE;
++}
++
++static /*const */ struct file_operations au1550_mixer_fops = {
++ owner:THIS_MODULE,
++ llseek:au1550_llseek,
++ ioctl:au1550_ioctl_mixdev,
++ open:au1550_open_mixdev,
++ release:au1550_release_mixdev,
++};
++
+ void
+-codec_init(void)
++codec_init(struct au1550_state *s)
+ {
+- wrcodec(0x1e, 0x00); /* Reset */
+- au1550_delay(200);
+- wrcodec(0x0c, 0x00); /* Power up everything */
+- au1550_delay(10);
+- wrcodec(0x12, 0x00); /* Deactivate codec */
+- au1550_delay(10);
+- wrcodec(0x08, 0x10); /* Select DAC outputs to line out */
+- au1550_delay(10);
+- wrcodec(0x0a, 0x00); /* Disable output mute */
+- au1550_delay(10);
+- wrcodec(0x05, 0x70); /* lower output volume on headphone */
+- au1550_delay(10);
+- wrcodec(0x0e, 0x02); /* Set slave, 16-bit, I2S modes */
+- au1550_delay(10);
+- wrcodec(0x10, 0x01); /* 12MHz (USB), 250fs */
+- au1550_delay(10);
+- wrcodec(0x12, 0x01); /* Activate codec */
+- au1550_delay(10);
++ wrcodec(WM_REG_RESET, 0x00); /* Reset */
++ wrcodec(WM_REG_POWER_DOWN_CTRL, 0x00); /* Power up everything */
++ wrcodec(WM_REG_ACTIVE_CTRL, 0x00); /* Deactivate codec */
++ wrcodec(WM_REG_ANALOGUE_AUDIO_PATH_CTRL, 0x10); /* Select DAC outputs to line out */
++ wrcodec(WM_REG_DIGITAL_AUDIO_PATH_CTRL, 0x00); /* Disable output mute */
++ wm_i2s_write_mixer(s, SOUND_MIXER_PCM, 74, 74);
++ wrcodec(WM_REG_DIGITAL_AUDIO_IF, 0x02); /* Set slave, 16-bit, I2S modes */
++ wrcodec(WM_REG_ACTIVE_CTRL, 0x01); /* Activate codec */
+ }
+
+ /* stop the ADC before calling */
+@@ -256,27 +502,16 @@
+ set_adc_rate(struct au1550_state *s, unsigned rate)
+ {
+ struct dmabuf *adc = &s->dma_adc;
+- struct dmabuf *dac = &s->dma_dac;
+
+- if (s->no_vra) {
+- /* calc SRC factor
+- */
++ #if defined(WM_MODE_USB)
+ adc->src_factor = (((SAMP_RATE*2) / rate) + 1) >> 1;
+ adc->sample_rate = SAMP_RATE / adc->src_factor;
+ return;
+- }
++ #else
++ //TODO: Need code for normal mode
++ #endif
+
+ adc->src_factor = 1;
+-
+-
+-#if 0
+- rate = rate > SAMP_RATE ? SAMP_RATE : rate;
+-
+- wrcodec(0, 0); /* I don't yet know what to write here if we vra */
+-
+- adc->sample_rate = rate;
+- dac->sample_rate = rate;
+-#endif
+ }
+
+ /* stop the DAC before calling */
+@@ -284,26 +519,89 @@
+ set_dac_rate(struct au1550_state *s, unsigned rate)
+ {
+ struct dmabuf *dac = &s->dma_dac;
+- struct dmabuf *adc = &s->dma_adc;
+
+- if (s->no_vra) {
+- /* calc SRC factor
+- */
+- dac->src_factor = (((SAMP_RATE*2) / rate) + 1) >> 1;
+- dac->sample_rate = SAMP_RATE / dac->src_factor;
+- return;
++ u16 sr, ws, div, bosr, mode;
++ volatile psc_i2s_t* ip = (volatile psc_i2s_t *)I2S_PSC_BASE;
++ u32 cfg;
++
++ #if defined(CONFIG_MIPS_FICMMP)
++ rate = ficmmp_set_i2s_sample_rate(rate);
++ #endif
++
++ switch(rate)
++ {
++ case 96000:
++ sr = WM_SC_SR_96000;
++ ws = WS_64FS;
++ div = PSC_I2SCFG_DIV2;
++ break;
++ case 88200:
++ sr = WM_SC_SR_88200;
++ ws = WS_64FS;
++ div = PSC_I2SCFG_DIV2;
++ break;
++ case 44100:
++ sr = WM_SC_SR_44100;
++ ws = WS_128FS;
++ div = PSC_I2SCFG_DIV2;
++ break;
++ case 48000:
++ sr = WM_SC_SR_48000;
++ ws = WS_128FS;
++ div = PSC_I2SCFG_DIV2;
++ break;
++ case 32000:
++ sr = WM_SC_SR_32000;
++ ws = WS_96FS;
++ div = PSC_I2SCFG_DIV4;
++ break;
++ case 8018:
++ sr = WM_SC_SR_8018;
++ ws = WS_128FS;
++ div = PSC_I2SCFG_DIV2;
++ break;
++ case 8000:
++ default:
++ sr = WM_SC_SR_8000;
++ ws = WS_96FS;
++ div = PSC_I2SCFG_DIV16;
++ break;
+ }
+
++ #if defined(WM_MODE_USB)
++ mode = WM_SC_MODE_USB;
++ #else
++ mode = WM_SC_MODE_NORMAL;
++ #endif
++
++ bosr = 0;
++
+ dac->src_factor = 1;
++ dac->sample_rate = rate;
+
+-#if 0
+- rate = rate > SAMP_RATE ? SAMP_RATE : rate;
++ /* Deactivate codec */
++ wrcodec(WM_REG_ACTIVE_CTRL, 0x00);
+
+- wrcodec(0, 0); /* I don't yet know what to write here if we vra */
++ /* Disable I2S controller */
++ ip->psc_i2scfg &= ~PSC_I2SCFG_DE_ENABLE;
++ /* Wait for device disabled */
++ while ((ip->psc_i2sstat & PSC_I2SSTAT_DR) == 1);
++
++ cfg = ip->psc_i2scfg;
++ /* Clear WS and DIVIDER values */
++ cfg &= ~(PSC_I2SCFG_WS_MASK | PSC_I2SCFG_DIV_MASK);
++ cfg |= PSC_I2SCFG_WS(ws) | div;
++ /* Reconfigure and enable */
++ ip->psc_i2scfg = cfg | PSC_I2SCFG_DE_ENABLE;
+
+- adc->sample_rate = rate;
+- dac->sample_rate = rate;
+-#endif
++ /* Wait for device enabled */
++ while ((ip->psc_i2sstat & PSC_I2SSTAT_DR) == 0);
++
++ /* Set appropriate sampling rate */
++ wrcodec(WM_REG_SAMPLING_CONTROL, bosr | mode | sr);
++
++ /* Activate codec */
++ wrcodec(WM_REG_ACTIVE_CTRL, 0x01);
+ }
+
+ static void
+@@ -354,8 +652,7 @@
+ ip->psc_i2spcr = PSC_I2SPCR_RP;
+ au_sync();
+
+- /* Wait for Receive Busy to show disabled.
+- */
++ /* Wait for Receive Busy to show disabled. */
+ do {
+ stat = ip->psc_i2sstat;
+ au_sync();
+@@ -463,7 +760,6 @@
+ if (db->num_channels == 1)
+ db->cnt_factor *= 2;
+ db->cnt_factor *= db->src_factor;
+-
+ db->count = 0;
+ db->dma_qcount = 0;
+ db->nextIn = db->nextOut = db->rawbuf;
+@@ -546,12 +842,13 @@
+ if (i2s_stat & (PSC_I2SSTAT_TF | PSC_I2SSTAT_TR | PSC_I2SSTAT_TF))
+ dbg("I2S status = 0x%08x", i2s_stat);
+ #endif
++
+ db->dma_qcount--;
+
+ if (db->count >= db->fragsize) {
+- if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut,
+- db->fragsize) == 0) {
+- err("qcount < 2 and no ring room!");
++ if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut, db->fragsize) == 0)
++ {
++ err("qcount < MIN_Q_COUNT and no ring room!");
+ }
+ db->nextOut += db->fragsize;
+ if (db->nextOut >= db->rawbuf + db->dmasize)
+@@ -606,65 +903,43 @@
+
+ }
+
+-static loff_t
+-au1550_llseek(struct file *file, loff_t offset, int origin)
+-{
+- return -ESPIPE;
+-}
+-
+-
+-#if 0
+-static int
+-au1550_open_mixdev(struct inode *inode, struct file *file)
+-{
+- file->private_data = &au1550_state;
+- return 0;
+-}
+-
+-static int
+-au1550_release_mixdev(struct inode *inode, struct file *file)
+-{
+- return 0;
+-}
+-
+-static int
+-mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
+- unsigned long arg)
+-{
+- return codec->mixer_ioctl(codec, cmd, arg);
+-}
+-
+-static int
+-au1550_ioctl_mixdev(struct inode *inode, struct file *file,
+- unsigned int cmd, unsigned long arg)
+-{
+- struct au1550_state *s = (struct au1550_state *)file->private_data;
+- struct ac97_codec *codec = s->codec;
+-
+- return mixdev_ioctl(codec, cmd, arg);
+-}
+-
+-static /*const */ struct file_operations au1550_mixer_fops = {
+- owner:THIS_MODULE,
+- llseek:au1550_llseek,
+- ioctl:au1550_ioctl_mixdev,
+- open:au1550_open_mixdev,
+- release:au1550_release_mixdev,
+-};
+-#endif
+-
+ static int
+ drain_dac(struct au1550_state *s, int nonblock)
+ {
+ unsigned long flags;
+ int count, tmo;
+
++ struct dmabuf *db = &s->dma_dac;
++
++ //DPRINTF();
+ if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped)
+ return 0;
+
+ for (;;) {
+ spin_lock_irqsave(&s->lock, flags);
+- count = s->dma_dac.count;
++ count = db->count;
++
++ /* Pad the ddma buffer with zeros if the amount remaining
++ * is not a multiple of fragsize */
++ if(count % db->fragsize != 0)
++ {
++ int pad = db->fragsize - (count % db->fragsize);
++ char* bufptr = db->nextIn;
++ char* bufend = db->rawbuf + db->dmasize;
++
++ if((bufend - bufptr) < pad)
++ printk("Error! ddma padding is bigger than available ring space!\n");
++ else
++ {
++ memset((void*)bufptr, 0, pad);
++ count += pad;
++ db->nextIn += pad;
++ db->count += pad;
++ if (db->dma_qcount == 0)
++ start_dac(s);
++ db->dma_qcount++;
++ }
++ }
+ spin_unlock_irqrestore(&s->lock, flags);
+ if (count <= 0)
+ break;
+@@ -672,9 +947,9 @@
+ break;
+ if (nonblock)
+ return -EBUSY;
+- tmo = 1000 * count / (s->no_vra ?
+- SAMP_RATE : s->dma_dac.sample_rate);
++ tmo = 1000 * count / s->dma_dac.sample_rate;
+ tmo /= s->dma_dac.dma_bytes_per_sample;
++
+ au1550_delay(tmo);
+ }
+ if (signal_pending(current))
+@@ -698,8 +973,7 @@
+ * If interpolating (no VRA), duplicate every audio frame src_factor times.
+ */
+ static int
+-translate_from_user(struct dmabuf *db, char* dmabuf, char* userbuf,
+- int dmacount)
++translate_from_user(struct dmabuf *db, char* dmabuf, char* userbuf, int dmacount)
+ {
+ int sample, i;
+ int interp_bytes_per_sample;
+@@ -737,11 +1011,12 @@
+
+ /* duplicate every audio frame src_factor times
+ */
+- for (i = 0; i < db->src_factor; i++)
++ for (i = 0; i < db->src_factor; i++) {
+ memcpy(dmabuf, dmasample, db->dma_bytes_per_sample);
++ dmabuf += interp_bytes_per_sample;
++ }
+
+ userbuf += db->user_bytes_per_sample;
+- dmabuf += interp_bytes_per_sample;
+ }
+
+ return num_samples * interp_bytes_per_sample;
+@@ -996,15 +1271,14 @@
+ * on the dma queue. If the queue count reaches zero,
+ * we know the dma has stopped.
+ */
+- while ((db->dma_qcount < 2) && (db->count >= db->fragsize)) {
++ while ((db->dma_qcount < MIN_Q_COUNT) && (db->count >= db->fragsize)) {
+ if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut,
+ db->fragsize) == 0) {
+- err("qcount < 2 and no ring room!");
++ err("qcount < MIN_Q_COUNT and no ring room!");
+ }
+ db->nextOut += db->fragsize;
+ if (db->nextOut >= db->rawbuf + db->dmasize)
+ db->nextOut -= db->dmasize;
+- db->count -= db->fragsize;
+ db->total_bytes += db->dma_fragsize;
+ if (db->dma_qcount == 0)
+ start_dac(s);
+@@ -1017,7 +1291,6 @@
+ buffer += usercnt;
+ ret += usercnt;
+ } /* while (count > 0) */
+-
+ out:
+ up(&s->sem);
+ out2:
+@@ -1371,9 +1644,6 @@
+ s->dma_dac.cnt_factor;
+ abinfo.fragstotal = s->dma_dac.numfrag;
+ abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
+-#ifdef AU1000_VERBOSE_DEBUG
+- dbg("bytes=%d, fragments=%d", abinfo.bytes, abinfo.fragments);
+-#endif
+ return copy_to_user((void *) arg, &abinfo,
+ sizeof(abinfo)) ? -EFAULT : 0;
+
+@@ -1536,13 +1806,9 @@
+ case SNDCTL_DSP_SETSYNCRO:
+ case SOUND_PCM_READ_FILTER:
+ return -EINVAL;
++ default: break;
+ }
+-
+-#if 0
+- return mixdev_ioctl(s->codec, cmd, arg);
+-#else
+ return 0;
+-#endif
+ }
+
+
+@@ -1664,15 +1930,15 @@
+ MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com");
+ MODULE_DESCRIPTION("Au1550 Audio Driver");
+
++#if defined(WM_MODE_USB)
+ /* Set up an internal clock for the PSC3. This will then get
+ * driven out of the Au1550 as the master.
+ */
+ static void
+ intclk_setup(void)
+ {
+- uint clk, rate, stat;
+-
+- /* Wire up Freq4 as a clock for the PSC3.
++ uint clk, rate;
++ /* Wire up Freq4 as a clock for the PSC.
+ * We know SMBus uses Freq3.
+ * By making changes to this rate, plus the word strobe
+ * size, we can make fine adjustments to the actual data rate.
+@@ -1700,11 +1966,17 @@
+ */
+ clk = au_readl(SYS_CLKSRC);
+ au_sync();
++#if defined(CONFIG_SOC_AU1550)
+ clk &= ~0x01f00000;
+ clk |= (6 << 22);
++#elif defined(CONFIG_SOC_AU1200)
++ clk &= ~0x3e000000;
++ clk |= (6 << 27);
++#endif
+ au_writel(clk, SYS_CLKSRC);
+ au_sync();
+ }
++#endif
+
+ static int __devinit
+ au1550_probe(void)
+@@ -1724,6 +1996,11 @@
+ init_MUTEX(&s->open_sem);
+ spin_lock_init(&s->lock);
+
++ /* CPLD Mux for I2s */
++
++#if defined(CONFIG_MIPS_PB1200)
++ bcsr->resets |= BCSR_RESETS_PCS1MUX;
++#endif
+
+ s->psc_addr = (volatile psc_i2s_t *)I2S_PSC_BASE;
+ ip = s->psc_addr;
+@@ -1765,9 +2042,8 @@
+
+ if ((s->dev_audio = register_sound_dsp(&au1550_audio_fops, -1)) < 0)
+ goto err_dev1;
+-#if 0
+- if ((s->codec->dev_mixer =
+- register_sound_mixer(&au1550_mixer_fops, -1)) < 0)
++#if 1
++ if ((s->dev_mixer = register_sound_mixer(&au1550_mixer_fops, -1)) < 0)
+ goto err_dev2;
+ #endif
+
+@@ -1777,7 +2053,6 @@
+ proc_au1550_dump, NULL);
+ #endif /* AU1550_DEBUG */
+
+- intclk_setup();
+
+ /* The GPIO for the appropriate PSC was configured by the
+ * board specific start up.
+@@ -1786,7 +2061,12 @@
+ */
+ ip->psc_ctrl = PSC_CTRL_DISABLE; /* Disable PSC */
+ au_sync();
++#if defined(WM_MODE_USB)
++ intclk_setup();
+ ip->psc_sel = (PSC_SEL_CLK_INTCLK | PSC_SEL_PS_I2SMODE);
++#else
++ ip->psc_sel = (PSC_SEL_CLK_EXTCLK | PSC_SEL_PS_I2SMODE);
++#endif
+ au_sync();
+
+ /* Enable PSC
+@@ -1806,42 +2086,18 @@
+ * Actual I2S mode (first bit delayed by one clock).
+ * Master mode (We provide the clock from the PSC).
+ */
+- val = PSC_I2SCFG_SET_LEN(16);
+-#ifdef TRY_441KHz
+- /* This really should be 250, but it appears that all of the
+- * PLLs, dividers and so on in the chain shift it. That's the
+- * problem with sourceing the clock instead of letting the very
+- * stable codec provide it. But, the PSC doesn't appear to want
+- * to work in slave mode, so this is what we get. It's not
+- * studio quality timing, but it's good enough for listening
+- * to mp3s.
+- */
+- val |= PSC_I2SCFG_SET_WS(252);
+-#else
+- val |= PSC_I2SCFG_SET_WS(250);
+-#endif
+- val |= PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8 | \
++
++ val = PSC_I2SCFG_SET_LEN(16) | PSC_I2SCFG_WS(WS_128FS) | PSC_I2SCFG_RT_FIFO8 | PSC_I2SCFG_TT_FIFO8 | \
+ PSC_I2SCFG_BI | PSC_I2SCFG_XM;
+
+- ip->psc_i2scfg = val;
+- au_sync();
+- val |= PSC_I2SCFG_DE_ENABLE;
+- ip->psc_i2scfg = val;
+- au_sync();
++ ip->psc_i2scfg = val | PSC_I2SCFG_DE_ENABLE;
+
+- /* Wait for Device ready.
+- */
+- do {
+- val = ip->psc_i2sstat;
+- au_sync();
+- } while ((val & PSC_I2SSTAT_DR) == 0);
++ set_dac_rate(s, 8000); //Set default rate
+
+- val = ip->psc_i2scfg;
+- au_sync();
++ codec_init(s);
+
+- codec_init();
++ s->no_vra = vra ? 0 : 1;
+
+- s->no_vra = 1;
+ if (s->no_vra)
+ info("no VRA, interpolating and decimating");
+
+@@ -1866,6 +2122,8 @@
+ err_dev2:
+ unregister_sound_dsp(s->dev_audio);
+ #endif
++ err_dev2:
++ unregister_sound_dsp(s->dev_audio);
+ err_dev1:
+ au1xxx_dbdma_chan_free(s->dma_adc.dmanr);
+ err_dma2:
+diff -Nur linux-2.4.32-rc1/drivers/sound/au1550_psc.c linux-2.4.32-rc1.mips/drivers/sound/au1550_psc.c
+--- linux-2.4.32-rc1/drivers/sound/au1550_psc.c 2005-01-19 15:10:04.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/sound/au1550_psc.c 2005-01-30 09:01:28.000000000 +0100
+@@ -30,6 +30,7 @@
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
++
+ #include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/string.h>
+@@ -63,6 +64,14 @@
+ #include <asm/db1x00.h>
+ #endif
+
++#ifdef CONFIG_MIPS_PB1200
++#include <asm/pb1200.h>
++#endif
++
++#ifdef CONFIG_MIPS_DB1200
++#include <asm/db1200.h>
++#endif
++
+ #undef OSS_DOCUMENTED_MIXER_SEMANTICS
+
+ #define AU1550_MODULE_NAME "Au1550 psc audio"
+@@ -521,7 +530,14 @@
+ spin_unlock_irqrestore(&s->lock, flags);
+ }
+
+-
++/*
++ NOTE: The xmit slots cannot be changed on the fly when in full-duplex
++ because the AC'97 block must be stopped/started. When using this driver
++ in full-duplex (in & out at the same time), the DMA engine will stop if
++ you disable the block.
++ TODO: change implementation to properly restart adc/dac after setting
++ xmit slots.
++*/
+ static void
+ set_xmit_slots(int num_channels)
+ {
+@@ -565,6 +581,14 @@
+ } while ((stat & PSC_AC97STAT_DR) == 0);
+ }
+
++/*
++ NOTE: The recv slots cannot be changed on the fly when in full-duplex
++ because the AC'97 block must be stopped/started. When using this driver
++ in full-duplex (in & out at the same time), the DMA engine will stop if
++ you disable the block.
++ TODO: change implementation to properly restart adc/dac after setting
++ recv slots.
++*/
+ static void
+ set_recv_slots(int num_channels)
+ {
+@@ -608,7 +632,6 @@
+
+ spin_lock_irqsave(&s->lock, flags);
+
+- set_xmit_slots(db->num_channels);
+ au_writel(PSC_AC97PCR_TC, PSC_AC97PCR);
+ au_sync();
+ au_writel(PSC_AC97PCR_TS, PSC_AC97PCR);
+@@ -640,7 +663,6 @@
+ db->nextIn -= db->dmasize;
+ }
+
+- set_recv_slots(db->num_channels);
+ au1xxx_dbdma_start(db->dmanr);
+ au_writel(PSC_AC97PCR_RC, PSC_AC97PCR);
+ au_sync();
+@@ -752,12 +774,16 @@
+ if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE))
+ dbg("AC97C status = 0x%08x", ac97c_stat);
+ #endif
++ /* There is a possiblity that we are getting 1 interrupt for
++ multiple descriptors. Use ddma api to find out how many
++ completed.
++ */
+ db->dma_qcount--;
+
+ if (db->count >= db->fragsize) {
+ if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut,
+ db->fragsize) == 0) {
+- err("qcount < 2 and no ring room!");
++ err("qcount < 2 and no ring room1!");
+ }
+ db->nextOut += db->fragsize;
+ if (db->nextOut >= db->rawbuf + db->dmasize)
+@@ -941,11 +967,12 @@
+
+ /* duplicate every audio frame src_factor times
+ */
+- for (i = 0; i < db->src_factor; i++)
++ for (i = 0; i < db->src_factor; i++) {
+ memcpy(dmabuf, dmasample, db->dma_bytes_per_sample);
++ dmabuf += interp_bytes_per_sample;
++ }
+
+ userbuf += db->user_bytes_per_sample;
+- dmabuf += interp_bytes_per_sample;
+ }
+
+ return num_samples * interp_bytes_per_sample;
+@@ -1203,7 +1230,7 @@
+ while ((db->dma_qcount < 2) && (db->count >= db->fragsize)) {
+ if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut,
+ db->fragsize) == 0) {
+- err("qcount < 2 and no ring room!");
++ err("qcount < 2 and no ring room!0");
+ }
+ db->nextOut += db->fragsize;
+ if (db->nextOut >= db->rawbuf + db->dmasize)
+@@ -1481,6 +1508,7 @@
+ return -EINVAL;
+ stop_adc(s);
+ s->dma_adc.num_channels = val;
++ set_recv_slots(val);
+ if ((ret = prog_dmabuf_adc(s)))
+ return ret;
+ }
+@@ -1538,6 +1566,7 @@
+ }
+
+ s->dma_dac.num_channels = val;
++ set_xmit_slots(val);
+ if ((ret = prog_dmabuf_dac(s)))
+ return ret;
+ }
+@@ -1832,10 +1861,8 @@
+ down(&s->open_sem);
+ }
+
+- stop_dac(s);
+- stop_adc(s);
+-
+ if (file->f_mode & FMODE_READ) {
++ stop_adc(s);
+ s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
+ s->dma_adc.subdivision = s->dma_adc.total_bytes = 0;
+ s->dma_adc.num_channels = 1;
+@@ -1846,6 +1873,7 @@
+ }
+
+ if (file->f_mode & FMODE_WRITE) {
++ stop_dac(s);
+ s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
+ s->dma_dac.subdivision = s->dma_dac.total_bytes = 0;
+ s->dma_dac.num_channels = 1;
+@@ -2091,6 +2119,9 @@
+ ac97_read_proc, &s->codec);
+ #endif
+
++ set_xmit_slots(1);
++ set_recv_slots(1);
++
+ return 0;
+
+ err_dev3:
+diff -Nur linux-2.4.32-rc1/drivers/sound/Config.in linux-2.4.32-rc1.mips/drivers/sound/Config.in
+--- linux-2.4.32-rc1/drivers/sound/Config.in 2005-01-19 15:10:04.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/sound/Config.in 2005-04-21 07:53:07.000000000 +0200
+@@ -72,10 +72,15 @@
+ if [ "$CONFIG_DDB5477" = "y" ]; then
+ dep_tristate ' NEC Vrc5477 AC97 sound' CONFIG_SOUND_VRC5477 $CONFIG_SOUND
+ fi
+-if [ "$CONFIG_SOC_AU1X00" = "y" -o "$CONFIG_SOC_AU1500" = "y" ]; then
+- dep_tristate ' Au1x00 Sound' CONFIG_SOUND_AU1X00 $CONFIG_SOUND
+- dep_tristate ' Au1550 PSC Sound' CONFIG_SOUND_AU1550_PSC $CONFIG_SOUND
+- dep_tristate ' Au1550 I2S Sound' CONFIG_SOUND_AU1550_I2S $CONFIG_SOUND
++if [ "$CONFIG_SOC_AU1000" = "y" -o \
++ "$CONFIG_SOC_AU1500" = "y" -o \
++ "$CONFIG_SOC_AU1100" = "y" ]; then
++ dep_tristate ' Au1x00 AC97 Sound' CONFIG_SOUND_AU1X00 $CONFIG_SOUND
++fi
++if [ "$CONFIG_SOC_AU1550" = "y" -o \
++ "$CONFIG_SOC_AU1200" = "y" ]; then
++ dep_tristate ' Au1550/Au1200 PSC AC97 Sound' CONFIG_SOUND_AU1550_PSC $CONFIG_SOUND
++ dep_tristate ' Au1550/Au1200 PSC I2S Sound' CONFIG_SOUND_AU1550_I2S $CONFIG_SOUND
+ fi
+
+ dep_tristate ' Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core' CONFIG_SOUND_TRIDENT $CONFIG_SOUND $CONFIG_PCI
+diff -Nur linux-2.4.32-rc1/drivers/tc/lk201.c linux-2.4.32-rc1.mips/drivers/tc/lk201.c
+--- linux-2.4.32-rc1/drivers/tc/lk201.c 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/tc/lk201.c 2004-09-28 02:53:04.000000000 +0200
+@@ -5,7 +5,7 @@
+ * for more details.
+ *
+ * Copyright (C) 1999-2002 Harald Koerfgen <hkoerfg@web.de>
+- * Copyright (C) 2001, 2002, 2003 Maciej W. Rozycki <macro@ds2.pg.gda.pl>
++ * Copyright (C) 2001, 2002, 2003, 2004 Maciej W. Rozycki
+ */
+
+ #include <linux/config.h>
+@@ -23,8 +23,8 @@
+ #include <asm/keyboard.h>
+ #include <asm/dec/tc.h>
+ #include <asm/dec/machtype.h>
++#include <asm/dec/serial.h>
+
+-#include "zs.h"
+ #include "lk201.h"
+
+ /*
+@@ -55,19 +55,20 @@
+ unsigned char kbd_sysrq_key = -1;
+ #endif
+
+-#define KEYB_LINE 3
++#define KEYB_LINE_ZS 3
++#define KEYB_LINE_DZ 0
+
+-static int __init lk201_init(struct dec_serial *);
+-static void __init lk201_info(struct dec_serial *);
+-static void lk201_kbd_rx_char(unsigned char, unsigned char);
++static int __init lk201_init(void *);
++static void __init lk201_info(void *);
++static void lk201_rx_char(unsigned char, unsigned char);
+
+-struct zs_hook lk201_kbdhook = {
++static struct dec_serial_hook lk201_hook = {
+ .init_channel = lk201_init,
+ .init_info = lk201_info,
+ .rx_char = NULL,
+ .poll_rx_char = NULL,
+ .poll_tx_char = NULL,
+- .cflags = B4800 | CS8 | CSTOPB | CLOCAL
++ .cflags = B4800 | CS8 | CSTOPB | CLOCAL,
+ };
+
+ /*
+@@ -93,28 +94,28 @@
+ LK_CMD_ENB_BELL, LK_PARAM_VOLUME(4),
+ };
+
+-static struct dec_serial* lk201kbd_info;
++static void *lk201_handle;
+
+-static int lk201_send(struct dec_serial *info, unsigned char ch)
++static int lk201_send(unsigned char ch)
+ {
+- if (info->hook->poll_tx_char(info, ch)) {
++ if (lk201_hook.poll_tx_char(lk201_handle, ch)) {
+ printk(KERN_ERR "lk201: transmit timeout\n");
+ return -EIO;
+ }
+ return 0;
+ }
+
+-static inline int lk201_get_id(struct dec_serial *info)
++static inline int lk201_get_id(void)
+ {
+- return lk201_send(info, LK_CMD_REQ_ID);
++ return lk201_send(LK_CMD_REQ_ID);
+ }
+
+-static int lk201_reset(struct dec_serial *info)
++static int lk201_reset(void)
+ {
+ int i, r;
+
+ for (i = 0; i < sizeof(lk201_reset_string); i++) {
+- r = lk201_send(info, lk201_reset_string[i]);
++ r = lk201_send(lk201_reset_string[i]);
+ if (r < 0)
+ return r;
+ }
+@@ -203,24 +204,26 @@
+
+ static int write_kbd_rate(struct kbd_repeat *rep)
+ {
+- struct dec_serial* info = lk201kbd_info;
+ int delay, rate;
+ int i;
+
+ delay = rep->delay / 5;
+ rate = rep->rate;
+ for (i = 0; i < 4; i++) {
+- if (info->hook->poll_tx_char(info, LK_CMD_RPT_RATE(i)))
++ if (lk201_hook.poll_tx_char(lk201_handle,
++ LK_CMD_RPT_RATE(i)))
+ return 1;
+- if (info->hook->poll_tx_char(info, LK_PARAM_DELAY(delay)))
++ if (lk201_hook.poll_tx_char(lk201_handle,
++ LK_PARAM_DELAY(delay)))
+ return 1;
+- if (info->hook->poll_tx_char(info, LK_PARAM_RATE(rate)))
++ if (lk201_hook.poll_tx_char(lk201_handle,
++ LK_PARAM_RATE(rate)))
+ return 1;
+ }
+ return 0;
+ }
+
+-static int lk201kbd_rate(struct kbd_repeat *rep)
++static int lk201_kbd_rate(struct kbd_repeat *rep)
+ {
+ if (rep == NULL)
+ return -EINVAL;
+@@ -237,10 +240,8 @@
+ return 0;
+ }
+
+-static void lk201kd_mksound(unsigned int hz, unsigned int ticks)
++static void lk201_kd_mksound(unsigned int hz, unsigned int ticks)
+ {
+- struct dec_serial* info = lk201kbd_info;
+-
+ if (!ticks)
+ return;
+
+@@ -253,20 +254,19 @@
+ ticks = 7;
+ ticks = 7 - ticks;
+
+- if (info->hook->poll_tx_char(info, LK_CMD_ENB_BELL))
++ if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_ENB_BELL))
+ return;
+- if (info->hook->poll_tx_char(info, LK_PARAM_VOLUME(ticks)))
++ if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_VOLUME(ticks)))
+ return;
+- if (info->hook->poll_tx_char(info, LK_CMD_BELL))
++ if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_BELL))
+ return;
+ }
+
+ void kbd_leds(unsigned char leds)
+ {
+- struct dec_serial* info = lk201kbd_info;
+ unsigned char l = 0;
+
+- if (!info) /* FIXME */
++ if (!lk201_handle) /* FIXME */
+ return;
+
+ /* FIXME -- Only Hold and Lock LEDs for now. --macro */
+@@ -275,13 +275,13 @@
+ if (leds & LED_CAP)
+ l |= LK_LED_LOCK;
+
+- if (info->hook->poll_tx_char(info, LK_CMD_LEDS_ON))
++ if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_LEDS_ON))
+ return;
+- if (info->hook->poll_tx_char(info, LK_PARAM_LED_MASK(l)))
++ if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_LED_MASK(l)))
+ return;
+- if (info->hook->poll_tx_char(info, LK_CMD_LEDS_OFF))
++ if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_LEDS_OFF))
+ return;
+- if (info->hook->poll_tx_char(info, LK_PARAM_LED_MASK(~l)))
++ if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_LED_MASK(~l)))
+ return;
+ }
+
+@@ -307,7 +307,7 @@
+ return 0x80;
+ }
+
+-static void lk201_kbd_rx_char(unsigned char ch, unsigned char stat)
++static void lk201_rx_char(unsigned char ch, unsigned char fl)
+ {
+ static unsigned char id[6];
+ static int id_i;
+@@ -316,9 +316,8 @@
+ static int prev_scancode;
+ unsigned char c = scancodeRemap[ch];
+
+- if (stat && stat != TTY_OVERRUN) {
+- printk(KERN_ERR "lk201: keyboard receive error: 0x%02x\n",
+- stat);
++ if (fl != TTY_NORMAL && fl != TTY_OVERRUN) {
++ printk(KERN_ERR "lk201: keyboard receive error: 0x%02x\n", fl);
+ return;
+ }
+
+@@ -335,7 +334,7 @@
+ /* OK, the power-up concluded. */
+ lk201_report(id);
+ if (id[2] == LK_STAT_PWRUP_OK)
+- lk201_get_id(lk201kbd_info);
++ lk201_get_id();
+ else {
+ id_i = 0;
+ printk(KERN_ERR "lk201: keyboard power-up "
+@@ -345,7 +344,7 @@
+ /* We got the ID; report it and start operation. */
+ id_i = 0;
+ lk201_id(id);
+- lk201_reset(lk201kbd_info);
++ lk201_reset();
+ }
+ return;
+ }
+@@ -398,29 +397,28 @@
+ tasklet_schedule(&keyboard_tasklet);
+ }
+
+-static void __init lk201_info(struct dec_serial *info)
++static void __init lk201_info(void *handle)
+ {
+ }
+
+-static int __init lk201_init(struct dec_serial *info)
++static int __init lk201_init(void *handle)
+ {
+ /* First install handlers. */
+- lk201kbd_info = info;
+- kbd_rate = lk201kbd_rate;
+- kd_mksound = lk201kd_mksound;
++ lk201_handle = handle;
++ kbd_rate = lk201_kbd_rate;
++ kd_mksound = lk201_kd_mksound;
+
+- info->hook->rx_char = lk201_kbd_rx_char;
++ lk201_hook.rx_char = lk201_rx_char;
+
+ /* Then just issue a reset -- the handlers will do the rest. */
+- lk201_send(info, LK_CMD_POWER_UP);
++ lk201_send(LK_CMD_POWER_UP);
+
+ return 0;
+ }
+
+ void __init kbd_init_hw(void)
+ {
+- extern int register_zs_hook(unsigned int, struct zs_hook *);
+- extern int unregister_zs_hook(unsigned int);
++ int keyb_line;
+
+ /* Maxine uses LK501 at the Access.Bus. */
+ if (!LK_IFACE)
+@@ -428,19 +426,15 @@
+
+ printk(KERN_INFO "lk201: DECstation LK keyboard driver v0.05.\n");
+
+- if (LK_IFACE_ZS) {
+- /*
+- * kbd_init_hw() is being called before
+- * rs_init() so just register the kbd hook
+- * and let zs_init do the rest :-)
+- */
+- if(!register_zs_hook(KEYB_LINE, &lk201_kbdhook))
+- unregister_zs_hook(KEYB_LINE);
+- } else {
+- /*
+- * TODO: modify dz.c to allow similar hooks
+- * for LK201 handling on DS2100, DS3100, and DS5000/200
+- */
+- printk(KERN_ERR "lk201: support for DZ11 not yet ready.\n");
+- }
++ /*
++ * kbd_init_hw() is being called before
++ * rs_init() so just register the kbd hook
++ * and let zs_init do the rest :-)
++ */
++ if (LK_IFACE_ZS)
++ keyb_line = KEYB_LINE_ZS;
++ else
++ keyb_line = KEYB_LINE_DZ;
++ if (!register_dec_serial_hook(keyb_line, &lk201_hook))
++ unregister_dec_serial_hook(keyb_line);
+ }
+diff -Nur linux-2.4.32-rc1/drivers/tc/zs.c linux-2.4.32-rc1.mips/drivers/tc/zs.c
+--- linux-2.4.32-rc1/drivers/tc/zs.c 2005-01-19 15:10:05.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/tc/zs.c 2004-12-27 05:13:50.000000000 +0100
+@@ -68,6 +68,8 @@
+ #include <asm/bitops.h>
+ #include <asm/uaccess.h>
+ #include <asm/bootinfo.h>
++#include <asm/dec/serial.h>
++
+ #ifdef CONFIG_DECSTATION
+ #include <asm/dec/interrupts.h>
+ #include <asm/dec/machtype.h>
+@@ -160,8 +162,8 @@
+ #ifdef CONFIG_SERIAL_DEC_CONSOLE
+ static struct console sercons;
+ #endif
+-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) \
+- && !defined(MODULE)
++#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
++ !defined(MODULE)
+ static unsigned long break_pressed; /* break, really ... */
+ #endif
+
+@@ -196,7 +198,6 @@
+ /*
+ * Debugging.
+ */
+-#undef SERIAL_DEBUG_INTR
+ #undef SERIAL_DEBUG_OPEN
+ #undef SERIAL_DEBUG_FLOW
+ #undef SERIAL_DEBUG_THROTTLE
+@@ -221,10 +222,6 @@
+ static struct termios *serial_termios[NUM_CHANNELS];
+ static struct termios *serial_termios_locked[NUM_CHANNELS];
+
+-#ifndef MIN
+-#define MIN(a,b) ((a) < (b) ? (a) : (b))
+-#endif
+-
+ /*
+ * tmp_buf is used as a temporary buffer by serial_write. We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+@@ -386,8 +383,6 @@
+ * -----------------------------------------------------------------------
+ */
+
+-static int tty_break; /* Set whenever BREAK condition is detected. */
+-
+ /*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+@@ -414,20 +409,15 @@
+ if (!tty && (!info->hook || !info->hook->rx_char))
+ continue;
+
+- if (tty_break) {
+- tty_break = 0;
+-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
+- if (info->line == sercons.index) {
+- if (!break_pressed) {
+- break_pressed = jiffies;
+- goto ignore_char;
+- }
+- break_pressed = 0;
+- }
+-#endif
++ flag = TTY_NORMAL;
++ if (info->tty_break) {
++ info->tty_break = 0;
+ flag = TTY_BREAK;
+ if (info->flags & ZILOG_SAK)
+ do_SAK(tty);
++ /* Ignore the null char got when BREAK is removed. */
++ if (ch == 0)
++ continue;
+ } else {
+ if (stat & Rx_OVR) {
+ flag = TTY_OVERRUN;
+@@ -435,20 +425,22 @@
+ flag = TTY_FRAME;
+ } else if (stat & PAR_ERR) {
+ flag = TTY_PARITY;
+- } else
+- flag = 0;
+- if (flag)
++ }
++ if (flag != TTY_NORMAL)
+ /* reset the error indication */
+ write_zsreg(info->zs_channel, R0, ERR_RES);
+ }
+
+-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
++#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
++ !defined(MODULE)
+ if (break_pressed && info->line == sercons.index) {
+- if (ch != 0 &&
+- time_before(jiffies, break_pressed + HZ*5)) {
++ /* Ignore the null char got when BREAK is removed. */
++ if (ch == 0)
++ continue;
++ if (time_before(jiffies, break_pressed + HZ * 5)) {
+ handle_sysrq(ch, regs, NULL, NULL);
+ break_pressed = 0;
+- goto ignore_char;
++ continue;
+ }
+ break_pressed = 0;
+ }
+@@ -459,23 +451,7 @@
+ return;
+ }
+
+- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+- static int flip_buf_ovf;
+- ++flip_buf_ovf;
+- continue;
+- }
+- tty->flip.count++;
+- {
+- static int flip_max_cnt;
+- if (flip_max_cnt < tty->flip.count)
+- flip_max_cnt = tty->flip.count;
+- }
+-
+- *tty->flip.flag_buf_ptr++ = flag;
+- *tty->flip.char_buf_ptr++ = ch;
+-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
+- ignore_char:
+-#endif
++ tty_insert_flip_char(tty, ch, flag);
+ }
+ if (tty)
+ tty_flip_buffer_push(tty);
+@@ -517,11 +493,15 @@
+ /* Get status from Read Register 0 */
+ stat = read_zsreg(info->zs_channel, R0);
+
+- if (stat & BRK_ABRT) {
+-#ifdef SERIAL_DEBUG_INTR
+- printk("handling break....");
++ if ((stat & BRK_ABRT) && !(info->read_reg_zero & BRK_ABRT)) {
++#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
++ !defined(MODULE)
++ if (info->line == sercons.index) {
++ if (!break_pressed)
++ break_pressed = jiffies;
++ } else
+ #endif
+- tty_break = 1;
++ info->tty_break = 1;
+ }
+
+ if (info->zs_channel != info->zs_chan_a) {
+@@ -957,7 +937,7 @@
+ save_flags(flags);
+ while (1) {
+ cli();
+- c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
++ c = min(count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0)
+ break;
+@@ -965,7 +945,7 @@
+ if (from_user) {
+ down(&tmp_buf_sem);
+ copy_from_user(tmp_buf, buf, c);
+- c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
++ c = min(c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+ up(&tmp_buf_sem);
+@@ -1282,46 +1262,48 @@
+ }
+
+ switch (cmd) {
+- case TIOCMGET:
+- error = verify_area(VERIFY_WRITE, (void *) arg,
+- sizeof(unsigned int));
+- if (error)
+- return error;
+- return get_modem_info(info, (unsigned int *) arg);
+- case TIOCMBIS:
+- case TIOCMBIC:
+- case TIOCMSET:
+- return set_modem_info(info, cmd, (unsigned int *) arg);
+- case TIOCGSERIAL:
+- error = verify_area(VERIFY_WRITE, (void *) arg,
+- sizeof(struct serial_struct));
+- if (error)
+- return error;
+- return get_serial_info(info,
+- (struct serial_struct *) arg);
+- case TIOCSSERIAL:
+- return set_serial_info(info,
+- (struct serial_struct *) arg);
+- case TIOCSERGETLSR: /* Get line status register */
+- error = verify_area(VERIFY_WRITE, (void *) arg,
+- sizeof(unsigned int));
+- if (error)
+- return error;
+- else
+- return get_lsr_info(info, (unsigned int *) arg);
++ case TIOCMGET:
++ error = verify_area(VERIFY_WRITE, (void *)arg,
++ sizeof(unsigned int));
++ if (error)
++ return error;
++ return get_modem_info(info, (unsigned int *)arg);
+
+- case TIOCSERGSTRUCT:
+- error = verify_area(VERIFY_WRITE, (void *) arg,
+- sizeof(struct dec_serial));
+- if (error)
+- return error;
+- copy_from_user((struct dec_serial *) arg,
+- info, sizeof(struct dec_serial));
+- return 0;
++ case TIOCMBIS:
++ case TIOCMBIC:
++ case TIOCMSET:
++ return set_modem_info(info, cmd, (unsigned int *)arg);
+
+- default:
+- return -ENOIOCTLCMD;
+- }
++ case TIOCGSERIAL:
++ error = verify_area(VERIFY_WRITE, (void *)arg,
++ sizeof(struct serial_struct));
++ if (error)
++ return error;
++ return get_serial_info(info, (struct serial_struct *)arg);
++
++ case TIOCSSERIAL:
++ return set_serial_info(info, (struct serial_struct *)arg);
++
++ case TIOCSERGETLSR: /* Get line status register */
++ error = verify_area(VERIFY_WRITE, (void *)arg,
++ sizeof(unsigned int));
++ if (error)
++ return error;
++ else
++ return get_lsr_info(info, (unsigned int *)arg);
++
++ case TIOCSERGSTRUCT:
++ error = verify_area(VERIFY_WRITE, (void *)arg,
++ sizeof(struct dec_serial));
++ if (error)
++ return error;
++ copy_from_user((struct dec_serial *)arg, info,
++ sizeof(struct dec_serial));
++ return 0;
++
++ default:
++ return -ENOIOCTLCMD;
++ }
+ return 0;
+ }
+
+@@ -1446,7 +1428,8 @@
+ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+ {
+ struct dec_serial *info = (struct dec_serial *) tty->driver_data;
+- unsigned long orig_jiffies, char_time;
++ unsigned long orig_jiffies;
++ int char_time;
+
+ if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
+ return;
+@@ -1462,7 +1445,7 @@
+ if (char_time == 0)
+ char_time = 1;
+ if (timeout)
+- char_time = MIN(char_time, timeout);
++ char_time = min(char_time, timeout);
+ while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 0) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(char_time);
+@@ -1714,7 +1697,7 @@
+
+ static void __init show_serial_version(void)
+ {
+- printk("DECstation Z8530 serial driver version 0.08\n");
++ printk("DECstation Z8530 serial driver version 0.09\n");
+ }
+
+ /* Initialize Z8530s zs_channels
+@@ -1994,8 +1977,9 @@
+ * polling I/O routines
+ */
+ static int
+-zs_poll_tx_char(struct dec_serial *info, unsigned char ch)
++zs_poll_tx_char(void *handle, unsigned char ch)
+ {
++ struct dec_serial *info = handle;
+ struct dec_zschannel *chan = info->zs_channel;
+ int ret;
+
+@@ -2017,8 +2001,9 @@
+ }
+
+ static int
+-zs_poll_rx_char(struct dec_serial *info)
++zs_poll_rx_char(void *handle)
+ {
++ struct dec_serial *info = handle;
+ struct dec_zschannel *chan = info->zs_channel;
+ int ret;
+
+@@ -2038,12 +2023,13 @@
+ return -ENODEV;
+ }
+
+-unsigned int register_zs_hook(unsigned int channel, struct zs_hook *hook)
++int register_zs_hook(unsigned int channel, struct dec_serial_hook *hook)
+ {
+ struct dec_serial *info = &zs_soft[channel];
+
+ if (info->hook) {
+- printk(__FUNCTION__": line %d has already a hook registered\n", channel);
++ printk("%s: line %d has already a hook registered\n",
++ __FUNCTION__, channel);
+
+ return 0;
+ } else {
+@@ -2055,7 +2041,7 @@
+ }
+ }
+
+-unsigned int unregister_zs_hook(unsigned int channel)
++int unregister_zs_hook(unsigned int channel)
+ {
+ struct dec_serial *info = &zs_soft[channel];
+
+@@ -2063,8 +2049,8 @@
+ info->hook = NULL;
+ return 1;
+ } else {
+- printk(__FUNCTION__": trying to unregister hook on line %d,"
+- " but none is registered\n", channel);
++ printk("%s: trying to unregister hook on line %d,"
++ " but none is registered\n", __FUNCTION__, channel);
+ return 0;
+ }
+ }
+@@ -2319,22 +2305,23 @@
+ write_zsreg(chan, 9, nine);
+ }
+
+-static int kgdbhook_init_channel(struct dec_serial* info)
++static int kgdbhook_init_channel(void *handle)
+ {
+ return 0;
+ }
+
+-static void kgdbhook_init_info(struct dec_serial* info)
++static void kgdbhook_init_info(void *handle)
+ {
+ }
+
+-static void kgdbhook_rx_char(struct dec_serial* info,
+- unsigned char ch, unsigned char stat)
++static void kgdbhook_rx_char(void *handle, unsigned char ch, unsigned char fl)
+ {
++ struct dec_serial *info = handle;
++
++ if (fl != TTY_NORMAL)
++ return;
+ if (ch == 0x03 || ch == '$')
+ breakpoint();
+- if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
+- write_zsreg(info->zs_channel, 0, ERR_RES);
+ }
+
+ /* This sets up the serial port we're using, and turns on
+@@ -2360,11 +2347,11 @@
+ * for /dev/ttyb which is determined in setup_arch() from the
+ * boot command line flags.
+ */
+-struct zs_hook zs_kgdbhook = {
+- init_channel : kgdbhook_init_channel,
+- init_info : kgdbhook_init_info,
+- cflags : B38400|CS8|CLOCAL,
+- rx_char : kgdbhook_rx_char,
++struct dec_serial_hook zs_kgdbhook = {
++ .init_channel = kgdbhook_init_channel,
++ .init_info = kgdbhook_init_info,
++ .rx_char = kgdbhook_rx_char,
++ .cflags = B38400 | CS8 | CLOCAL,
+ }
+
+ void __init zs_kgdb_hook(int tty_num)
+diff -Nur linux-2.4.32-rc1/drivers/tc/zs.h linux-2.4.32-rc1.mips/drivers/tc/zs.h
+--- linux-2.4.32-rc1/drivers/tc/zs.h 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/tc/zs.h 2004-07-01 15:28:54.000000000 +0200
+@@ -1,14 +1,18 @@
+ /*
+- * macserial.h: Definitions for the Macintosh Z8530 serial driver.
++ * drivers/tc/zs.h: Definitions for the DECstation Z85C30 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
++ * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
++ * Copyright (C) 2004 Maciej W. Rozycki
+ */
+ #ifndef _DECSERIAL_H
+ #define _DECSERIAL_H
+
++#include <asm/dec/serial.h>
++
+ #define NUM_ZSREGS 16
+
+ struct serial_struct {
+@@ -89,63 +93,50 @@
+ unsigned char curregs[NUM_ZSREGS];
+ };
+
+-struct dec_serial;
+-
+-struct zs_hook {
+- int (*init_channel)(struct dec_serial* info);
+- void (*init_info)(struct dec_serial* info);
+- void (*rx_char)(unsigned char ch, unsigned char stat);
+- int (*poll_rx_char)(struct dec_serial* info);
+- int (*poll_tx_char)(struct dec_serial* info,
+- unsigned char ch);
+- unsigned cflags;
+-};
+-
+ struct dec_serial {
+- struct dec_serial *zs_next; /* For IRQ servicing chain */
+- struct dec_zschannel *zs_channel; /* Channel registers */
+- struct dec_zschannel *zs_chan_a; /* A side registers */
+- unsigned char read_reg_zero;
+-
+- char soft_carrier; /* Use soft carrier on this channel */
+- char break_abort; /* Is serial console in, so process brk/abrt */
+- struct zs_hook *hook; /* Hook on this channel */
+- char is_cons; /* Is this our console. */
+- unsigned char tx_active; /* character is being xmitted */
+- unsigned char tx_stopped; /* output is suspended */
+-
+- /* We need to know the current clock divisor
+- * to read the bps rate the chip has currently
+- * loaded.
++ struct dec_serial *zs_next; /* For IRQ servicing chain. */
++ struct dec_zschannel *zs_channel; /* Channel registers. */
++ struct dec_zschannel *zs_chan_a; /* A side registers. */
++ unsigned char read_reg_zero;
++
++ struct dec_serial_hook *hook; /* Hook on this channel. */
++ int tty_break; /* Set on BREAK condition. */
++ int is_cons; /* Is this our console. */
++ int tx_active; /* Char is being xmitted. */
++ int tx_stopped; /* Output is suspended. */
++
++ /*
++ * We need to know the current clock divisor
++ * to read the bps rate the chip has currently loaded.
+ */
+- unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */
+- int zs_baud;
++ int clk_divisor; /* May be 1, 16, 32, or 64. */
++ int zs_baud;
+
+- char change_needed;
++ char change_needed;
+
+ int magic;
+ int baud_base;
+ int port;
+ int irq;
+- int flags; /* defined in tty.h */
+- int type; /* UART type */
++ int flags; /* Defined in tty.h. */
++ int type; /* UART type. */
+ struct tty_struct *tty;
+ int read_status_mask;
+ int ignore_status_mask;
+ int timeout;
+ int xmit_fifo_size;
+ int custom_divisor;
+- int x_char; /* xon/xoff character */
++ int x_char; /* XON/XOFF character. */
+ int close_delay;
+ unsigned short closing_wait;
+ unsigned short closing_wait2;
+ unsigned long event;
+ unsigned long last_active;
+ int line;
+- int count; /* # of fd on device */
+- int blocked_open; /* # of blocked opens */
+- long session; /* Session of opening process */
+- long pgrp; /* pgrp of opening process */
++ int count; /* # of fds on device. */
++ int blocked_open; /* # of blocked opens. */
++ long session; /* Sess of opening process. */
++ long pgrp; /* Pgrp of opening process. */
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+diff -Nur linux-2.4.32-rc1/drivers/video/au1200fb.c linux-2.4.32-rc1.mips/drivers/video/au1200fb.c
+--- linux-2.4.32-rc1/drivers/video/au1200fb.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/video/au1200fb.c 2005-03-13 09:04:16.000000000 +0100
+@@ -0,0 +1,1564 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ * Au1200 LCD Driver.
++ *
++ * Copyright 2004 AMD
++ * Author: AMD
++ *
++ * Based on:
++ * linux/drivers/video/skeletonfb.c -- Skeleton for a frame buffer device
++ * Created 28 Dec 1997 by Geert Uytterhoeven
++ *
++ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/tty.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/fb.h>
++#include <linux/init.h>
++#include <asm/uaccess.h>
++
++#include <asm/au1000.h>
++#include <asm/au1xxx_gpio.h>
++#include "au1200fb.h"
++
++#include <video/fbcon.h>
++#include <video/fbcon-cfb16.h>
++#include <video/fbcon-cfb32.h>
++#define CMAPSIZE 16
++
++#define AU1200_LCD_GET_WINENABLE 1
++#define AU1200_LCD_SET_WINENABLE 2
++#define AU1200_LCD_GET_WINLOCATION 3
++#define AU1200_LCD_SET_WINLOCATION 4
++#define AU1200_LCD_GET_WINSIZE 5
++#define AU1200_LCD_SET_WINSIZE 6
++#define AU1200_LCD_GET_BACKCOLOR 7
++#define AU1200_LCD_SET_BACKCOLOR 8
++#define AU1200_LCD_GET_COLORKEY 9
++#define AU1200_LCD_SET_COLORKEY 10
++#define AU1200_LCD_GET_PANEL 11
++#define AU1200_LCD_SET_PANEL 12
++
++typedef struct au1200_lcd_getset_t
++{
++ unsigned int subcmd;
++ union {
++ struct {
++ int enable;
++ } winenable;
++ struct {
++ int x, y;
++ } winlocation;
++ struct {
++ int hsz, vsz;
++ } winsize;
++ struct {
++ unsigned int color;
++ } backcolor;
++ struct {
++ unsigned int key;
++ unsigned int mask;
++ } colorkey;
++ struct {
++ int panel;
++ char desc[80];
++ } panel;
++ };
++} au1200_lcd_getset_t;
++
++AU1200_LCD *lcd = (AU1200_LCD *)AU1200_LCD_ADDR;
++static int window_index = 0; /* default is zero */
++static int panel_index = -1; /* default is call board_au1200fb_panel */
++
++struct window_settings
++{
++ unsigned char name[64];
++ uint32 mode_backcolor;
++ uint32 mode_colorkey;
++ uint32 mode_colorkeymsk;
++ struct
++ {
++ int xres;
++ int yres;
++ int xpos;
++ int ypos;
++ uint32 mode_winctrl1; /* winctrl1[FRM,CCO,PO,PIPE] */
++ uint32 mode_winenable;
++ } w[4];
++};
++
++struct panel_settings
++{
++ unsigned char name[64];
++ /* panel physical dimensions */
++ uint32 Xres;
++ uint32 Yres;
++ /* panel timings */
++ uint32 mode_screen;
++ uint32 mode_horztiming;
++ uint32 mode_verttiming;
++ uint32 mode_clkcontrol;
++ uint32 mode_pwmdiv;
++ uint32 mode_pwmhi;
++ uint32 mode_outmask;
++ uint32 mode_fifoctrl;
++ uint32 mode_toyclksrc;
++ uint32 mode_backlight;
++ uint32 mode_auxpll;
++ int (*device_init)(void);
++ int (*device_shutdown)(void);
++};
++
++#if defined(__BIG_ENDIAN)
++#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_00
++#else
++#define LCD_WINCTRL1_PO_16BPP LCD_WINCTRL1_PO_01
++#endif
++
++extern int board_au1200fb_panel (void);
++extern int board_au1200fb_panel_init (void);
++extern int board_au1200fb_panel_shutdown (void);
++
++#if defined(CONFIG_FOCUS_ENHANCEMENTS)
++extern int board_au1200fb_focus_init_hdtv(void);
++extern int board_au1200fb_focus_init_component(void);
++extern int board_au1200fb_focus_init_cvsv(void);
++extern int board_au1200fb_focus_shutdown(void);
++#endif
++
++/*
++ * Default window configurations
++ */
++static struct window_settings windows[] =
++{
++ { /* Index 0 */
++ "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
++ /* mode_backcolor */ 0x006600ff,
++ /* mode_colorkey,msk*/ 0, 0,
++ {
++ {
++ /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
++ /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565|LCD_WINCTRL1_PO_16BPP,
++ /* mode_winenable*/ LCD_WINENABLE_WEN0,
++ },
++ {
++ /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
++ /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565|LCD_WINCTRL1_PO_16BPP,
++ /* mode_winenable*/ 0,
++ },
++ {
++ /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
++ /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565|LCD_WINCTRL1_PO_16BPP|LCD_WINCTRL1_PIPE,
++ /* mode_winenable*/ 0,
++ },
++ {
++ /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
++ /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565|LCD_WINCTRL1_PO_16BPP|LCD_WINCTRL1_PIPE,
++ /* mode_winenable*/ 0,
++ },
++ },
++ },
++
++ { /* Index 1 */
++ "0-FS gfx, 1-video, 2-ovly gfx, 3-ovly gfx",
++ /* mode_backcolor */ 0x006600ff,
++ /* mode_colorkey,msk*/ 0, 0,
++ {
++ {
++ /* xres, yres, xpos, ypos */ 320, 240, 5, 5,
++#if 0
++ /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565|LCD_WINCTRL1_PO_16BPP,
++#endif
++ /* mode_winctrl1 */ LCD_WINCTRL1_FRM_24BPP|LCD_WINCTRL1_PO_00,
++ /* mode_winenable*/ LCD_WINENABLE_WEN0,
++ },
++ {
++ /* xres, yres, xpos, ypos */ 0, 0, 0, 0,
++ /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565|LCD_WINCTRL1_PO_16BPP,
++ /* mode_winenable*/ 0,
++ },
++ {
++ /* xres, yres, xpos, ypos */ 100, 100, 0, 0,
++ /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565|LCD_WINCTRL1_PO_16BPP|LCD_WINCTRL1_PIPE,
++ /* mode_winenable*/ 0/*LCD_WINENABLE_WEN2*/,
++ },
++ {
++ /* xres, yres, xpos, ypos */ 200, 25, 0, 0,
++ /* mode_winctrl1 */ LCD_WINCTRL1_FRM_16BPP565|LCD_WINCTRL1_PO_16BPP|LCD_WINCTRL1_PIPE,
++ /* mode_winenable*/ 0,
++ },
++ },
++ },
++ /* Need VGA 640 @ 24bpp, @ 32bpp */
++ /* Need VGA 800 @ 24bpp, @ 32bpp */
++ /* Need VGA 1024 @ 24bpp, @ 32bpp */
++} ;
++
++/*
++ * Controller configurations for various panels.
++ */
++static struct panel_settings panels[] =
++{
++ { /* Index 0: QVGA 320x240 H:33.3kHz V:110Hz */
++ "VGA_320x240",
++ 320, 240,
++ /* mode_screen */ LCD_SCREEN_SX_N(320) | LCD_SCREEN_SY_N(240),
++ /* mode_horztiming */ 0x00c4623b,
++ /* mode_verttiming */ 0x00502814,
++ /* mode_clkcontrol */ 0x00020002, /* /4=24Mhz */
++ /* mode_pwmdiv */ 0x00000000,
++ /* mode_pwmhi */ 0x00000000,
++ /* mode_outmask */ 0x00FFFFFF,
++ /* mode_fifoctrl */ 0x2f2f2f2f,
++ /* mode_toyclksrc */ 0x00000004, /* 96MHz AUXPLL directly */
++ /* mode_backlight */ 0x00000000,
++ /* mode_auxpll */ 8, /* 96MHz AUXPLL */
++ /* device_init */ NULL,
++ /* device_shutdown */ NULL,
++ },
++
++ { /* Index 1: VGA 640x480 H:30.3kHz V:58Hz */
++ "VGA_640x480",
++ 640, 480,
++ /* mode_screen */ 0x13f9df80,
++ /* mode_horztiming */ 0x003c5859,
++ /* mode_verttiming */ 0x00741201,
++ /* mode_clkcontrol */ 0x00020001, /* /4=24Mhz */
++ /* mode_pwmdiv */ 0x00000000,
++ /* mode_pwmhi */ 0x00000000,
++ /* mode_outmask */ 0x00FFFFFF,
++ /* mode_fifoctrl */ 0x2f2f2f2f,
++ /* mode_toyclksrc */ 0x00000004, /* AUXPLL directly */
++ /* mode_backlight */ 0x00000000,
++ /* mode_auxpll */ 8, /* 96MHz AUXPLL */
++ /* device_init */ NULL,
++ /* device_shutdown */ NULL,
++ },
++
++ { /* Index 2: SVGA 800x600 H:46.1kHz V:69Hz */
++ "SVGA_800x600",
++ 800, 600,
++ /* mode_screen */ 0x18fa5780,
++ /* mode_horztiming */ 0x00dc7e77,
++ /* mode_verttiming */ 0x00584805,
++ /* mode_clkcontrol */ 0x00020000, /* /2=48Mhz */
++ /* mode_pwmdiv */ 0x00000000,
++ /* mode_pwmhi */ 0x00000000,
++ /* mode_outmask */ 0x00FFFFFF,
++ /* mode_fifoctrl */ 0x2f2f2f2f,
++ /* mode_toyclksrc */ 0x00000004, /* AUXPLL directly */
++ /* mode_backlight */ 0x00000000,
++ /* mode_auxpll */ 8, /* 96MHz AUXPLL */
++ /* device_init */ NULL,
++ /* device_shutdown */ NULL,
++ },
++
++ { /* Index 3: XVGA 1024x768 H:56.2kHz V:70Hz */
++ "XVGA_1024x768",
++ 1024, 768,
++ /* mode_screen */ 0x1ffaff80,
++ /* mode_horztiming */ 0x007d0e57,
++ /* mode_verttiming */ 0x00740a01,
++ /* mode_clkcontrol */ 0x000A0000, /* /1 */
++ /* mode_pwmdiv */ 0x00000000,
++ /* mode_pwmhi */ 0x00000000,
++ /* mode_outmask */ 0x00FFFFFF,
++ /* mode_fifoctrl */ 0x2f2f2f2f,
++ /* mode_toyclksrc */ 0x00000004, /* AUXPLL directly */
++ /* mode_backlight */ 0x00000000,
++ /* mode_auxpll */ 6, /* 72MHz AUXPLL */
++ /* device_init */ NULL,
++ /* device_shutdown */ NULL,
++ },
++
++ { /* Index 4: XVGA 1280x1024 H:68.5kHz V:65Hz */
++ "XVGA_1280x1024",
++ 1280, 1024,
++ /* mode_screen */ 0x27fbff80,
++ /* mode_horztiming */ 0x00cdb2c7,
++ /* mode_verttiming */ 0x00600002,
++ /* mode_clkcontrol */ 0x000A0000, /* /1 */
++ /* mode_pwmdiv */ 0x00000000,
++ /* mode_pwmhi */ 0x00000000,
++ /* mode_outmask */ 0x00FFFFFF,
++ /* mode_fifoctrl */ 0x2f2f2f2f,
++ /* mode_toyclksrc */ 0x00000004, /* AUXPLL directly */
++ /* mode_backlight */ 0x00000000,
++ /* mode_auxpll */ 10, /* 120MHz AUXPLL */
++ /* device_init */ NULL,
++ /* device_shutdown */ NULL,
++ },
++
++ { /* Index 5: Samsung 1024x768 TFT */
++ "Samsung_1024x768_TFT",
++ 1024, 768,
++ /* mode_screen */ 0x1ffaff80,
++ /* mode_horztiming */ 0x018cc677,
++ /* mode_verttiming */ 0x00241217,
++ /* mode_clkcontrol */ 0x00000000, /* SCB 0x1 /4=24Mhz */
++ /* mode_pwmdiv */ 0x8000063f, /* SCB 0x0 */
++ /* mode_pwmhi */ 0x03400000, /* SCB 0x0 */
++ /* mode_outmask */ 0x00fcfcfc,
++ /* mode_fifoctrl */ 0x2f2f2f2f,
++ /* mode_toyclksrc */ 0x00000004, /* 96MHz AUXPLL directly */
++ /* mode_backlight */ 0x00000000,
++ /* mode_auxpll */ 8, /* 96MHz AUXPLL */
++ /* device_init */ board_au1200fb_panel_init,
++ /* device_shutdown */ board_au1200fb_panel_shutdown,
++ },
++
++ { /* Index 6: Toshiba 640x480 TFT */
++ "Toshiba_640x480_TFT",
++ 640, 480,
++ /* mode_screen */ LCD_SCREEN_SX_N(640) | LCD_SCREEN_SY_N(480),
++ /* mode_horztiming */ LCD_HORZTIMING_HPW_N(96) | LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(51),
++ /* mode_verttiming */ LCD_VERTTIMING_VPW_N(2) | LCD_VERTTIMING_VND1_N(11) | LCD_VERTTIMING_VND2_N(32) ,
++ /* mode_clkcontrol */ 0x00000000, /* /4=24Mhz */
++ /* mode_pwmdiv */ 0x8000063f,
++ /* mode_pwmhi */ 0x03400000,
++ /* mode_outmask */ 0x00fcfcfc,
++ /* mode_fifoctrl */ 0x2f2f2f2f,
++ /* mode_toyclksrc */ 0x00000004, /* 96MHz AUXPLL directly */
++ /* mode_backlight */ 0x00000000,
++ /* mode_auxpll */ 8, /* 96MHz AUXPLL */
++ /* device_init */ board_au1200fb_panel_init,
++ /* device_shutdown */ board_au1200fb_panel_shutdown,
++ },
++
++ { /* Index 7: Sharp 320x240 TFT */
++ "Sharp_320x240_TFT",
++ 320, 240,
++ /* mode_screen */ LCD_SCREEN_SX_N(320) | LCD_SCREEN_SY_N(240),
++ /* mode_horztiming */ LCD_HORZTIMING_HPW_N(60) | LCD_HORZTIMING_HND1_N(13) | LCD_HORZTIMING_HND2_N(2),
++ /* mode_verttiming */ LCD_VERTTIMING_VPW_N(2) | LCD_VERTTIMING_VND1_N(2) | LCD_VERTTIMING_VND2_N(5) ,
++ /* mode_clkcontrol */ LCD_CLKCONTROL_PCD_N(7), /* /16=6Mhz */
++ /* mode_pwmdiv */ 0x8000063f,
++ /* mode_pwmhi */ 0x03400000,
++ /* mode_outmask */ 0x00fcfcfc,
++ /* mode_fifoctrl */ 0x2f2f2f2f,
++ /* mode_toyclksrc */ 0x00000004, /* 96MHz AUXPLL directly */
++ /* mode_backlight */ 0x00000000,
++ /* mode_auxpll */ 8, /* 96MHz AUXPLL */
++ /* device_init */ board_au1200fb_panel_init,
++ /* device_shutdown */ board_au1200fb_panel_shutdown,
++ },
++ { /* Index 8: Toppoly TD070WGCB2 7" 854x480 TFT */
++ "Toppoly_TD070WGCB2",
++ 854, 480,
++ /* mode_screen */ LCD_SCREEN_SX_N(854) | LCD_SCREEN_SY_N(480),
++ /* mode_horztiming */ LCD_HORZTIMING_HND2_N(44) | LCD_HORZTIMING_HND1_N(44) | LCD_HORZTIMING_HPW_N(114),
++ /* mode_verttiming */ LCD_VERTTIMING_VND2_N(20) | LCD_VERTTIMING_VND1_N(21) | LCD_VERTTIMING_VPW_N(4),
++ /* mode_clkcontrol */ 0x00020001, /* /4=24Mhz */
++ /* mode_pwmdiv */ 0x8000063f,
++ /* mode_pwmhi */ 0x03400000,
++ /* mode_outmask */ 0x00FCFCFC,
++ /* mode_fifoctrl */ 0x2f2f2f2f,
++ /* mode_toyclksrc */ 0x00000004, /* AUXPLL directly */
++ /* mode_backlight */ 0x00000000,
++ /* mode_auxpll */ 8, /* 96MHz AUXPLL */
++ /* device_init */ board_au1200fb_panel_init,
++ /* device_shutdown */ board_au1200fb_panel_shutdown,
++ },
++#if defined(CONFIG_FOCUS_ENHANCEMENTS)
++ { /* Index 9: Focus FS453 TV-Out 640x480 */
++ "FS453_640x480 (Composite/S-Video)",
++ 640, 480,
++ /* mode_screen */ LCD_SCREEN_SX_N(640) | LCD_SCREEN_SY_N(480),
++ /* mode_horztiming */ LCD_HORZTIMING_HND2_N(143) | LCD_HORZTIMING_HND1_N(143) | LCD_HORZTIMING_HPW_N(10),
++ /* mode_verttiming */ LCD_VERTTIMING_VND2_N(30) | LCD_VERTTIMING_VND1_N(30) | LCD_VERTTIMING_VPW_N(5),
++ /* mode_clkcontrol */ 0x00480000 | (1<<17) | (1<<18), /* External Clock, 1:1 clock ratio */
++ /* mode_pwmdiv */ 0x00000000,
++ /* mode_pwmhi */ 0x00000000,
++ /* mode_outmask */ 0x00FFFFFF,
++ /* mode_fifoctrl */ 0x2f2f2f2f,
++ /* mode_toyclksrc */ 0x00000000,
++ /* mode_backlight */ 0x00000000,
++ /* mode_auxpll */ 8, /* 96MHz AUXPLL */
++ /* device_init */ board_au1200fb_focus_init_cvsv,
++ /* device_shutdown */ board_au1200fb_focus_shutdown,
++ },
++
++ { /* Index 10: Focus FS453 TV-Out 640x480 */
++ "FS453_640x480 (Component Video)",
++ 640, 480,
++ /* mode_screen */ LCD_SCREEN_SX_N(640) | LCD_SCREEN_SY_N(480),
++ /* mode_horztiming */ LCD_HORZTIMING_HND2_N(143) | LCD_HORZTIMING_HND1_N(143) | LCD_HORZTIMING_HPW_N(10),
++ /* mode_verttiming */ LCD_VERTTIMING_VND2_N(30) | LCD_VERTTIMING_VND1_N(30) | LCD_VERTTIMING_VPW_N(5),
++ /* mode_clkcontrol */ 0x00480000 | (1<<17) | (1<<18), /* External Clock, 1:1 clock ratio */
++ /* mode_pwmdiv */ 0x00000000,
++ /* mode_pwmhi */ 0x00000000,
++ /* mode_outmask */ 0x00FFFFFF,
++ /* mode_fifoctrl */ 0x2f2f2f2f,
++ /* mode_toyclksrc */ 0x00000000,
++ /* mode_backlight */ 0x00000000,
++ /* mode_auxpll */ 8, /* 96MHz AUXPLL */
++ /* device_init */ board_au1200fb_focus_init_component,
++ /* device_shutdown */ board_au1200fb_focus_shutdown,
++ },
++
++ { /* Index 11: Focus FS453 TV-Out 640x480 */
++ "FS453_640x480 (HDTV)",
++ 720, 480,
++ /* mode_screen */ LCD_SCREEN_SX_N(720) | LCD_SCREEN_SY_N(480),
++ /* mode_horztiming */ LCD_HORZTIMING_HND2_N(28) | LCD_HORZTIMING_HND1_N(46) | LCD_HORZTIMING_HPW_N(64),
++ /* mode_verttiming */ LCD_VERTTIMING_VND2_N(7) | LCD_VERTTIMING_VND1_N(31) | LCD_VERTTIMING_VPW_N(7),
++ /* mode_clkcontrol */ 0x00480000 | (1<<17) | (1<<18), /* External Clock, 1:1 clock ratio */
++ /* mode_pwmdiv */ 0x00000000,
++ /* mode_pwmhi */ 0x00000000,
++ /* mode_outmask */ 0x00FFFFFF,
++ /* mode_fifoctrl */ 0x2f2f2f2f,
++ /* mode_toyclksrc */ 0x00000000,
++ /* mode_backlight */ 0x00000000,
++ /* mode_auxpll */ 8, /* 96MHz AUXPLL */
++ /* device_init */ board_au1200fb_focus_init_hdtv,
++ /* device_shutdown */ board_au1200fb_focus_shutdown,
++ },
++#endif
++};
++
++#define NUM_PANELS (sizeof(panels) / sizeof(struct panel_settings))
++
++static struct window_settings *win;
++static struct panel_settings *panel;
++
++struct au1200fb_info {
++ struct fb_info_gen gen;
++ unsigned long fb_virt_start;
++ unsigned long fb_size;
++ unsigned long fb_phys;
++ int mmaped;
++ int nohwcursor;
++ int noblanking;
++
++ struct { unsigned red, green, blue, pad; } palette[256];
++
++#if defined(FBCON_HAS_CFB16)
++ u16 fbcon_cmap16[16];
++#endif
++#if defined(FBCON_HAS_CFB32)
++ u32 fbcon_cmap32[16];
++#endif
++};
++
++
++struct au1200fb_par {
++ struct fb_var_screeninfo var;
++
++ int line_length; /* in bytes */
++ int cmap_len; /* color-map length */
++};
++
++#ifndef CONFIG_FB_AU1200_DEVS
++#define CONFIG_FB_AU1200_DEVS 1
++#endif
++
++static struct au1200fb_info fb_infos[CONFIG_FB_AU1200_DEVS];
++static struct au1200fb_par fb_pars[CONFIG_FB_AU1200_DEVS];
++static struct display disps[CONFIG_FB_AU1200_DEVS];
++
++int au1200fb_init(void);
++void au1200fb_setup(char *options, int *ints);
++static int au1200fb_mmap(struct fb_info *fb, struct file *file,
++ struct vm_area_struct *vma);
++static int au1200_blank(int blank_mode, struct fb_info_gen *info);
++static int au1200fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
++ u_long arg, int con, struct fb_info *info);
++
++void au1200_nocursor(struct display *p, int mode, int xx, int yy){};
++
++static int au1200_setlocation (int plane, int xpos, int ypos);
++static int au1200_setsize (int plane, int xres, int yres);
++static void au1200_setmode(int plane);
++static void au1200_setpanel (struct panel_settings *newpanel);
++
++static struct fb_ops au1200fb_ops = {
++ owner: THIS_MODULE,
++ fb_get_fix: fbgen_get_fix,
++ fb_get_var: fbgen_get_var,
++ fb_set_var: fbgen_set_var,
++ fb_get_cmap: fbgen_get_cmap,
++ fb_set_cmap: fbgen_set_cmap,
++ fb_pan_display: fbgen_pan_display,
++ fb_ioctl: au1200fb_ioctl,
++ fb_mmap: au1200fb_mmap,
++};
++
++
++static int
++winbpp (unsigned int winctrl1)
++{
++ /* how many bytes of memory are needed for each pixel format */
++ switch (winctrl1 & LCD_WINCTRL1_FRM)
++ {
++ case LCD_WINCTRL1_FRM_1BPP: return 1; break;
++ case LCD_WINCTRL1_FRM_2BPP: return 2; break;
++ case LCD_WINCTRL1_FRM_4BPP: return 4; break;
++ case LCD_WINCTRL1_FRM_8BPP: return 8; break;
++ case LCD_WINCTRL1_FRM_12BPP: return 16; break;
++ case LCD_WINCTRL1_FRM_16BPP655: return 16; break;
++ case LCD_WINCTRL1_FRM_16BPP565: return 16; break;
++ case LCD_WINCTRL1_FRM_16BPP556: return 16; break;
++ case LCD_WINCTRL1_FRM_16BPPI1555: return 16; break;
++ case LCD_WINCTRL1_FRM_16BPPI5551: return 16; break;
++ case LCD_WINCTRL1_FRM_16BPPA1555: return 16; break;
++ case LCD_WINCTRL1_FRM_16BPPA5551: return 16; break;
++ case LCD_WINCTRL1_FRM_24BPP: return 32; break;
++ case LCD_WINCTRL1_FRM_32BPP: return 32; break;
++ default: return 0; break;
++ }
++}
++
++static int
++fbinfo2index (struct fb_info *fb_info)
++{
++ int i;
++ for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i)
++ {
++ if (fb_info == (struct fb_info *)(&fb_infos[i]))
++ return i;
++ }
++ printk("au1200fb: ERROR: fbinfo2index failed!\n");
++ return -1;
++}
++
++static void au1200_detect(void)
++{
++ /*
++ * This function should detect the current video mode settings
++ * and store it as the default video mode
++ * Yeh, well, we're not going to change any settings so we're
++ * always stuck with the default ...
++ */
++}
++
++static int au1200_encode_fix(struct fb_fix_screeninfo *fix,
++ const void *_par, struct fb_info_gen *_info)
++{
++ struct au1200fb_info *info = (struct au1200fb_info *) _info;
++ struct au1200fb_par *par = (struct au1200fb_par *) _par;
++ int plane;
++
++ plane = fbinfo2index(info);
++
++ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
++
++ fix->smem_start = info->fb_phys;
++ fix->smem_len = info->fb_size;
++ fix->type = FB_TYPE_PACKED_PIXELS;
++ fix->type_aux = 0;
++ fix->visual = (par->var.bits_per_pixel == 8) ?
++ FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
++ fix->ywrapstep = 0;
++ fix->xpanstep = 1;
++ fix->ypanstep = 1;
++ /* FIX!!!! why doesn't par->line_length work???? it does for au1100 */
++ fix->line_length = fb_pars[plane].line_length; /*par->line_length;*/
++ return 0;
++}
++
++static void set_color_bitfields(struct fb_var_screeninfo *var, int plane)
++{
++ if (var->bits_per_pixel == 8)
++ {
++ var->red.offset = 0;
++ var->red.length = 8;
++ var->green.offset = 0;
++ var->green.length = 8;
++ var->blue.offset = 0;
++ var->blue.length = 8;
++ var->transp.offset = 0;
++ var->transp.length = 0;
++ }
++ else
++
++ if (var->bits_per_pixel == 16)
++ {
++ /* FIX!!! How does CCO affect this ? */
++ /* FIX!!! Not exactly sure how many of these work with FB */
++ switch (win->w[plane].mode_winctrl1 & LCD_WINCTRL1_FRM)
++ {
++ case LCD_WINCTRL1_FRM_16BPP655:
++ var->red.offset = 10;
++ var->red.length = 6;
++ var->green.offset = 5;
++ var->green.length = 5;
++ var->blue.offset = 0;
++ var->blue.length = 5;
++ var->transp.offset = 0;
++ var->transp.length = 0;
++ break;
++
++ case LCD_WINCTRL1_FRM_16BPP565:
++ var->red.offset = 11;
++ var->red.length = 5;
++ var->green.offset = 5;
++ var->green.length = 6;
++ var->blue.offset = 0;
++ var->blue.length = 5;
++ var->transp.offset = 0;
++ var->transp.length = 0;
++ break;
++
++ case LCD_WINCTRL1_FRM_16BPP556:
++ var->red.offset = 11;
++ var->red.length = 5;
++ var->green.offset = 6;
++ var->green.length = 5;
++ var->blue.offset = 0;
++ var->blue.length = 6;
++ var->transp.offset = 0;
++ var->transp.length = 0;
++ break;
++
++ case LCD_WINCTRL1_FRM_16BPPI1555:
++ var->red.offset = 10;
++ var->red.length = 5;
++ var->green.offset = 5;
++ var->green.length = 5;
++ var->blue.offset = 0;
++ var->blue.length = 5;
++ var->transp.offset = 0;
++ var->transp.length = 0;
++ break;
++
++ case LCD_WINCTRL1_FRM_16BPPI5551:
++ var->red.offset = 11;
++ var->red.length = 5;
++ var->green.offset = 6;
++ var->green.length = 5;
++ var->blue.offset = 1;
++ var->blue.length = 5;
++ var->transp.offset = 0;
++ var->transp.length = 0;
++ break;
++
++ case LCD_WINCTRL1_FRM_16BPPA1555:
++ var->red.offset = 10;
++ var->red.length = 5;
++ var->green.offset = 5;
++ var->green.length = 5;
++ var->blue.offset = 0;
++ var->blue.length = 5;
++ var->transp.offset = 15;
++ var->transp.length = 1;
++ break;
++
++ case LCD_WINCTRL1_FRM_16BPPA5551:
++ var->red.offset = 11;
++ var->red.length = 5;
++ var->green.offset = 6;
++ var->green.length = 5;
++ var->blue.offset = 1;
++ var->blue.length = 5;
++ var->transp.offset = 0;
++ var->transp.length = 1;
++ break;
++
++ default:
++ printk("ERROR: Invalid PIXEL FORMAT!!!\n"); break;
++ }
++ }
++ else
++
++ if (var->bits_per_pixel == 32)
++ {
++ switch (win->w[plane].mode_winctrl1 & LCD_WINCTRL1_FRM)
++ {
++ case LCD_WINCTRL1_FRM_24BPP:
++ var->red.offset = 16;
++ var->red.length = 8;
++ var->green.offset = 8;
++ var->green.length = 8;
++ var->blue.offset = 0;
++ var->blue.length = 8;
++ var->transp.offset = 0;
++ var->transp.length = 0;
++ break;
++
++ case LCD_WINCTRL1_FRM_32BPP:
++ var->red.offset = 16;
++ var->red.length = 8;
++ var->green.offset = 8;
++ var->green.length = 8;
++ var->blue.offset = 0;
++ var->blue.length = 8;
++ var->transp.offset = 24;
++ var->transp.length = 8;
++ break;
++ }
++ }
++ var->red.msb_right = 0;
++ var->green.msb_right = 0;
++ var->blue.msb_right = 0;
++ var->transp.msb_right = 0;
++#if 0
++printk("set_color_bitfields(a=%d, r=%d..%d, g=%d..%d, b=%d..%d)\n",
++ var->transp.offset,
++ var->red.offset+var->red.length-1, var->red.offset,
++ var->green.offset+var->green.length-1, var->green.offset,
++ var->blue.offset+var->blue.length-1, var->blue.offset);
++#endif
++}
++
++static int au1200_decode_var(const struct fb_var_screeninfo *var,
++ void *_par, struct fb_info_gen *_info)
++{
++ struct au1200fb_par *par = (struct au1200fb_par *)_par;
++ int plane, bpp;
++
++ plane = fbinfo2index((struct fb_info *)_info);
++
++ /*
++ * Don't allow setting any of these yet: xres and yres don't
++ * make sense for LCD panels.
++ */
++ if (var->xres != win->w[plane].xres ||
++ var->yres != win->w[plane].yres ||
++ var->xres != win->w[plane].xres ||
++ var->yres != win->w[plane].yres) {
++ return -EINVAL;
++ }
++
++ bpp = winbpp(win->w[plane].mode_winctrl1);
++ if(var->bits_per_pixel != bpp) {
++ /* on au1200, window pixel format is independent of panel pixel */
++ printk("WARNING: bits_per_pizel != panel->bpp\n");
++ }
++
++ memset(par, 0, sizeof(struct au1200fb_par));
++ par->var = *var;
++
++ /* FIX!!! */
++ switch (var->bits_per_pixel) {
++ case 8:
++ par->var.bits_per_pixel = 8;
++ break;
++ case 16:
++ par->var.bits_per_pixel = 16;
++ break;
++ case 24:
++ case 32:
++ par->var.bits_per_pixel = 32;
++ break;
++ default:
++ printk("color depth %d bpp not supported\n",
++ var->bits_per_pixel);
++ return -EINVAL;
++
++ }
++ set_color_bitfields(&par->var, plane);
++ /* FIX!!! what is this for 24/32bpp? */
++ par->cmap_len = (par->var.bits_per_pixel == 8) ? 256 : 16;
++ return 0;
++}
++
++static int au1200_encode_var(struct fb_var_screeninfo *var,
++ const void *par, struct fb_info_gen *_info)
++{
++ *var = ((struct au1200fb_par *)par)->var;
++ return 0;
++}
++
++static void
++au1200_get_par(void *_par, struct fb_info_gen *_info)
++{
++ int index;
++
++ index = fbinfo2index((struct fb_info *)_info);
++ *(struct au1200fb_par *)_par = fb_pars[index];
++}
++
++static void au1200_set_par(const void *par, struct fb_info_gen *info)
++{
++ /* nothing to do: we don't change any settings */
++}
++
++static int au1200_getcolreg(unsigned regno, unsigned *red, unsigned *green,
++ unsigned *blue, unsigned *transp,
++ struct fb_info *info)
++{
++ struct au1200fb_info* i = (struct au1200fb_info*)info;
++
++ if (regno > 255)
++ return 1;
++
++ *red = i->palette[regno].red;
++ *green = i->palette[regno].green;
++ *blue = i->palette[regno].blue;
++ *transp = 0;
++
++ return 0;
++}
++
++static int au1200_setcolreg(unsigned regno, unsigned red, unsigned green,
++ unsigned blue, unsigned transp,
++ struct fb_info *info)
++{
++ struct au1200fb_info* i = (struct au1200fb_info *)info;
++ u32 rgbcol;
++ int plane, bpp;
++
++ plane = fbinfo2index((struct fb_info *)info);
++ bpp = winbpp(win->w[plane].mode_winctrl1);
++
++ if (regno > 255)
++ return 1;
++
++ i->palette[regno].red = red;
++ i->palette[regno].green = green;
++ i->palette[regno].blue = blue;
++
++ switch(bpp) {
++#ifdef FBCON_HAS_CFB8
++ case 8:
++ red >>= 10;
++ green >>= 10;
++ blue >>= 10;
++ panel_reg->lcd_pallettebase[regno] = (blue&0x1f) |
++ ((green&0x3f)<<5) | ((red&0x1f)<<11);
++ break;
++#endif
++#ifdef FBCON_HAS_CFB16
++/* FIX!!!! depends upon pixel format */
++ case 16:
++ i->fbcon_cmap16[regno] =
++ ((red & 0xf800) >> 0) |
++ ((green & 0xfc00) >> 5) |
++ ((blue & 0xf800) >> 11);
++ break;
++#endif
++#ifdef FBCON_HAS_CFB32
++ case 32:
++ i->fbcon_cmap32[regno] =
++ (((u32 )transp & 0xff00) << 16) |
++ (((u32 )red & 0xff00) << 8) |
++ (((u32 )green & 0xff00)) |
++ (((u32 )blue & 0xff00) >> 8);
++ break;
++#endif
++ default:
++ printk("unsupported au1200_setcolreg(%d)\n", bpp);
++ break;
++ }
++
++ return 0;
++}
++
++
++static int au1200_blank(int blank_mode, struct fb_info_gen *_info)
++{
++ struct au1200fb_info *fb_info = (struct au1200fb_info *)_info;
++ int plane;
++
++ /* Short-circuit screen blanking */
++ if (fb_info->noblanking)
++ return 0;
++
++ plane = fbinfo2index((struct fb_info *)_info);
++
++ switch (blank_mode) {
++ case VESA_NO_BLANKING:
++ /* printk("turn on panel\n"); */
++ au1200_setpanel(panel);
++ break;
++
++ case VESA_VSYNC_SUSPEND:
++ case VESA_HSYNC_SUSPEND:
++ case VESA_POWERDOWN:
++ /* printk("turn off panel\n"); */
++ au1200_setpanel(NULL);
++ break;
++ default:
++ break;
++
++ }
++ return 0;
++}
++
++static void au1200_set_disp(const void *unused, struct display *disp,
++ struct fb_info_gen *info)
++{
++ struct au1200fb_info *fb_info;
++ int plane;
++
++ fb_info = (struct au1200fb_info *)info;
++
++ disp->screen_base = (char *)fb_info->fb_virt_start;
++
++ switch (disp->var.bits_per_pixel) {
++#ifdef FBCON_HAS_CFB8
++ case 8:
++ disp->dispsw = &fbcon_cfb8;
++ if (fb_info->nohwcursor)
++ fbcon_cfb8.cursor = au1200_nocursor;
++ break;
++#endif
++#ifdef FBCON_HAS_CFB16
++ case 16:
++ disp->dispsw = &fbcon_cfb16;
++ disp->dispsw_data = fb_info->fbcon_cmap16;
++ if (fb_info->nohwcursor)
++ fbcon_cfb16.cursor = au1200_nocursor;
++ break;
++#endif
++#ifdef FBCON_HAS_CFB32
++ case 32:
++ disp->dispsw = &fbcon_cfb32;
++ disp->dispsw_data = fb_info->fbcon_cmap32;
++ if (fb_info->nohwcursor)
++ fbcon_cfb32.cursor = au1200_nocursor;
++ break;
++#endif
++ default:
++ disp->dispsw = &fbcon_dummy;
++ disp->dispsw_data = NULL;
++ break;
++ }
++}
++
++static int
++au1200fb_mmap(struct fb_info *_fb,
++ struct file *file,
++ struct vm_area_struct *vma)
++{
++ unsigned int len;
++ unsigned long start=0, off;
++
++ struct au1200fb_info *fb_info = (struct au1200fb_info *)_fb;
++
++ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
++ return -EINVAL;
++ }
++
++ start = fb_info->fb_phys & PAGE_MASK;
++ len = PAGE_ALIGN((start & ~PAGE_MASK) + fb_info->fb_size);
++
++ off = vma->vm_pgoff << PAGE_SHIFT;
++
++ if ((vma->vm_end - vma->vm_start + off) > len) {
++ return -EINVAL;
++ }
++
++ off += start;
++ vma->vm_pgoff = off >> PAGE_SHIFT;
++
++ pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
++ pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
++
++ /* This is an IO map - tell maydump to skip this VMA */
++ vma->vm_flags |= VM_IO;
++
++ if (io_remap_page_range(vma->vm_start, off,
++ vma->vm_end - vma->vm_start,
++ vma->vm_page_prot)) {
++ return -EAGAIN;
++ }
++
++ fb_info->mmaped = 1;
++ return 0;
++}
++
++int au1200_pan_display(const struct fb_var_screeninfo *var,
++ struct fb_info_gen *info)
++{
++ return 0;
++}
++
++
++static int au1200fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
++ u_long arg, int con, struct fb_info *info)
++{
++ int plane;
++
++ plane = fbinfo2index(info);
++
++ /* printk("au1200fb: ioctl %d on plane %d\n", cmd, plane); */
++
++ if (cmd == 0x46FF)
++ {
++ au1200_lcd_getset_t iodata;
++
++ if (copy_from_user(&iodata, (void *) arg, sizeof(au1200_lcd_getset_t)))
++ return -EFAULT;
++
++ switch (iodata.subcmd)
++ {
++ case AU1200_LCD_GET_WINENABLE:
++ iodata.winenable.enable = (lcd->winenable & (1<<plane)) ? 1 : 0;
++ break;
++ case AU1200_LCD_SET_WINENABLE:
++ {
++ u32 winenable;
++ winenable = lcd->winenable;
++ winenable &= ~(1<<plane);
++ winenable |= (iodata.winenable.enable) ? (1<<plane) : 0;
++ lcd->winenable = winenable;
++ }
++ break;
++ case AU1200_LCD_GET_WINLOCATION:
++ iodata.winlocation.x =
++ (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OX) >> 21;
++ iodata.winlocation.y =
++ (lcd->window[plane].winctrl0 & LCD_WINCTRL0_OY) >> 10;
++ break;
++ case AU1200_LCD_SET_WINLOCATION:
++ au1200_setlocation(plane, iodata.winlocation.x, iodata.winlocation.y);
++ break;
++ case AU1200_LCD_GET_WINSIZE:
++ iodata.winsize.hsz =
++ (lcd->window[plane].winctrl1 & LCD_WINCTRL1_SZX) >> 11;
++ iodata.winsize.vsz =
++ (lcd->window[plane].winctrl0 & LCD_WINCTRL1_SZY) >> 0;
++ break;
++ case AU1200_LCD_SET_WINSIZE:
++ au1200_setsize(plane, iodata.winsize.hsz, iodata.winsize.vsz);
++ break;
++ case AU1200_LCD_GET_BACKCOLOR:
++ iodata.backcolor.color = lcd->backcolor;
++ break;
++ case AU1200_LCD_SET_BACKCOLOR:
++ lcd->backcolor = iodata.backcolor.color;
++ break;
++ case AU1200_LCD_GET_COLORKEY:
++ iodata.colorkey.key = lcd->colorkey;
++ iodata.colorkey.mask = lcd->colorkeymsk;
++ break;
++ case AU1200_LCD_SET_COLORKEY:
++ lcd->colorkey = iodata.colorkey.key;
++ lcd->colorkeymsk = iodata.colorkey.mask;
++ break;
++ case AU1200_LCD_GET_PANEL:
++ iodata.panel.panel = panel_index;
++ break;
++ case AU1200_LCD_SET_PANEL:
++ if ((iodata.panel.panel >= 0) && (iodata.panel.panel < NUM_PANELS))
++ {
++ struct panel_settings *newpanel;
++ panel_index = iodata.panel.panel;
++ newpanel = &panels[panel_index];
++ au1200_setpanel(newpanel);
++ }
++ break;
++ }
++
++ return copy_to_user((void *) arg, &iodata, sizeof(au1200_lcd_getset_t)) ? -EFAULT : 0;
++ }
++
++ return -EINVAL;
++}
++
++static struct fbgen_hwswitch au1200_switch = {
++ au1200_detect,
++ au1200_encode_fix,
++ au1200_decode_var,
++ au1200_encode_var,
++ au1200_get_par,
++ au1200_set_par,
++ au1200_getcolreg,
++ au1200_setcolreg,
++ au1200_pan_display,
++ au1200_blank,
++ au1200_set_disp
++};
++
++static void au1200_setpanel (struct panel_settings *newpanel)
++{
++ /*
++ * Perform global setup/init of LCD controller
++ */
++ uint32 winenable;
++
++ /* Make sure all windows disabled */
++ winenable = lcd->winenable;
++ lcd->winenable = 0;
++
++ /*
++ * Ensure everything is disabled before reconfiguring
++ */
++ if (lcd->screen & LCD_SCREEN_SEN)
++ {
++ /* Wait for vertical sync period */
++ lcd->intstatus = LCD_INT_SS;
++ while ((lcd->intstatus & LCD_INT_SS) == 0)
++ ;
++
++ lcd->screen &= ~LCD_SCREEN_SEN; /*disable the controller*/
++
++ do
++ {
++ lcd->intstatus = lcd->intstatus; /*clear interrupts*/
++ }
++ /*wait for controller to shut down*/
++ while ((lcd->intstatus & LCD_INT_SD) == 0);
++
++ /* Call shutdown of current panel (if up) */
++ /* this must occur last, because if an external clock is driving
++ the controller, the clock cannot be turned off before first
++ shutting down the controller.
++ */
++ if (panel->device_shutdown != NULL) panel->device_shutdown();
++ }
++
++ /* Check if only needing to turn off panel */
++ if (panel == NULL) return;
++
++ panel = newpanel;
++
++ printk("Panel(%s), %dx%d\n", panel->name, panel->Xres, panel->Yres);
++
++ /*
++ * Setup clocking if internal LCD clock source (assumes sys_auxpll valid)
++ */
++ if (!(panel->mode_clkcontrol & LCD_CLKCONTROL_EXT))
++ {
++ uint32 sys_clksrc;
++ /* WARNING! This should really be a check since other peripherals can
++ be affected by changins sys_auxpll */
++ au_writel(panel->mode_auxpll, SYS_AUXPLL);
++ sys_clksrc = au_readl(SYS_CLKSRC) & ~0x0000001f;
++ sys_clksrc |= panel->mode_toyclksrc;
++ au_writel(sys_clksrc, SYS_CLKSRC);
++ }
++
++ /*
++ * Configure panel timings
++ */
++ lcd->screen = panel->mode_screen;
++ lcd->horztiming = panel->mode_horztiming;
++ lcd->verttiming = panel->mode_verttiming;
++ lcd->clkcontrol = panel->mode_clkcontrol;
++ lcd->pwmdiv = panel->mode_pwmdiv;
++ lcd->pwmhi = panel->mode_pwmhi;
++ lcd->outmask = panel->mode_outmask;
++ lcd->fifoctrl = panel->mode_fifoctrl;
++ au_sync();
++
++ /* FIX!!! Check window settings to make sure still valid for new geometry */
++ au1200_setlocation(0, win->w[0].xpos, win->w[0].ypos);
++ au1200_setlocation(1, win->w[1].xpos, win->w[1].ypos);
++ au1200_setlocation(2, win->w[2].xpos, win->w[2].ypos);
++ au1200_setlocation(3, win->w[3].xpos, win->w[3].ypos);
++ lcd->winenable = winenable;
++
++ /*
++ * Re-enable screen now that it is configured
++ */
++ lcd->screen |= LCD_SCREEN_SEN;
++ au_sync();
++
++ /* Call init of panel */
++ if (panel->device_init != NULL) panel->device_init();
++
++#if 0
++#define D(X) printk("%25s: %08X\n", #X, X)
++ D(lcd->screen);
++ D(lcd->horztiming);
++ D(lcd->verttiming);
++ D(lcd->clkcontrol);
++ D(lcd->pwmdiv);
++ D(lcd->pwmhi);
++ D(lcd->outmask);
++ D(lcd->fifoctrl);
++ D(lcd->window[0].winctrl0);
++ D(lcd->window[0].winctrl1);
++ D(lcd->window[0].winctrl2);
++ D(lcd->window[0].winbuf0);
++ D(lcd->window[0].winbuf1);
++ D(lcd->window[0].winbufctrl);
++ D(lcd->window[1].winctrl0);
++ D(lcd->window[1].winctrl1);
++ D(lcd->window[1].winctrl2);
++ D(lcd->window[1].winbuf0);
++ D(lcd->window[1].winbuf1);
++ D(lcd->window[1].winbufctrl);
++ D(lcd->window[2].winctrl0);
++ D(lcd->window[2].winctrl1);
++ D(lcd->window[2].winctrl2);
++ D(lcd->window[2].winbuf0);
++ D(lcd->window[2].winbuf1);
++ D(lcd->window[2].winbufctrl);
++ D(lcd->window[3].winctrl0);
++ D(lcd->window[3].winctrl1);
++ D(lcd->window[3].winctrl2);
++ D(lcd->window[3].winbuf0);
++ D(lcd->window[3].winbuf1);
++ D(lcd->window[3].winbufctrl);
++ D(lcd->winenable);
++ D(lcd->intenable);
++ D(lcd->intstatus);
++ D(lcd->backcolor);
++ D(lcd->winenable);
++ D(lcd->colorkey);
++ D(lcd->colorkeymsk);
++ D(lcd->hwc.cursorctrl);
++ D(lcd->hwc.cursorpos);
++ D(lcd->hwc.cursorcolor0);
++ D(lcd->hwc.cursorcolor1);
++ D(lcd->hwc.cursorcolor2);
++ D(lcd->hwc.cursorcolor3);
++#endif
++}
++
++static int au1200_setsize (int plane, int xres, int yres)
++{
++#if 0
++ uint32 winctrl0, winctrl1, winenable;
++ int xsz, ysz;
++
++ /* FIX!!! X*Y can not surpass allocated memory */
++
++ printk("setsize: x %d y %d\n", xres, yres);
++ winctrl1 = lcd->window[plane].winctrl1;
++ printk("org winctrl1 %08X\n", winctrl1);
++ winctrl1 &= ~(LCD_WINCTRL1_SZX | LCD_WINCTRL1_SZY);
++
++ xres -= 1;
++ yres -= 1;
++ winctrl1 |= (xres << 11);
++ winctrl1 |= (yres << 0);
++
++ printk("new winctrl1 %08X\n", winctrl1);
++
++ /*winenable = lcd->winenable & (1 << plane); */
++ /*lcd->winenable &= ~(1 << plane); */
++ lcd->window[plane].winctrl1 = winctrl1;
++ /*lcd->winenable |= winenable; */
++#endif
++ return 0;
++}
++
++static int au1200_setlocation (int plane, int xpos, int ypos)
++{
++ uint32 winctrl0, winctrl1, winenable, fb_offset = 0;
++ int xsz, ysz;
++
++ /* FIX!!! NOT CHECKING FOR COMPLETE OFFSCREEN YET */
++
++ winctrl0 = lcd->window[plane].winctrl0;
++ winctrl1 = lcd->window[plane].winctrl1;
++ winctrl0 &= (LCD_WINCTRL0_A | LCD_WINCTRL0_AEN);
++ winctrl1 &= ~(LCD_WINCTRL1_SZX | LCD_WINCTRL1_SZY);
++
++ /* Check for off-screen adjustments */
++ xsz = win->w[plane].xres;
++ ysz = win->w[plane].yres;
++ if ((xpos + win->w[plane].xres) > panel->Xres)
++ {
++ /* Off-screen to the right */
++ xsz = panel->Xres - xpos; /* off by 1 ??? */
++ /*printk("off screen right\n");*/
++ }
++
++ if ((ypos + win->w[plane].yres) > panel->Yres)
++ {
++ /* Off-screen to the bottom */
++ ysz = panel->Yres - ypos; /* off by 1 ??? */
++ /*printk("off screen bottom\n");*/
++ }
++
++ if (xpos < 0)
++ {
++ /* Off-screen to the left */
++ xsz = win->w[plane].xres + xpos;
++ fb_offset += (((0 - xpos) * winbpp(lcd->window[plane].winctrl1))/8);
++ xpos = 0;
++ /*printk("off screen left\n");*/
++ }
++
++ if (ypos < 0)
++ {
++ /* Off-screen to the top */
++ ysz = win->w[plane].yres + ypos;
++ fb_offset += ((0 - ypos) * fb_pars[plane].line_length);
++ ypos = 0;
++ /*printk("off screen top\n");*/
++ }
++
++ /* record settings */
++ win->w[plane].xpos = xpos;
++ win->w[plane].ypos = ypos;
++
++ xsz -= 1;
++ ysz -= 1;
++ winctrl0 |= (xpos << 21);
++ winctrl0 |= (ypos << 10);
++ winctrl1 |= (xsz << 11);
++ winctrl1 |= (ysz << 0);
++
++ /* Disable the window while making changes, then restore WINEN */
++ winenable = lcd->winenable & (1 << plane);
++ lcd->winenable &= ~(1 << plane);
++ lcd->window[plane].winctrl0 = winctrl0;
++ lcd->window[plane].winctrl1 = winctrl1;
++ lcd->window[plane].winbuf0 =
++ lcd->window[plane].winbuf1 = fb_infos[plane].fb_phys + fb_offset;
++ lcd->window[plane].winbufctrl = 0; /* select winbuf0 */
++ lcd->winenable |= winenable;
++
++ return 0;
++}
++
++static void au1200_setmode(int plane)
++{
++ /* Window/plane setup */
++ lcd->window[plane].winctrl1 = ( 0
++ | LCD_WINCTRL1_PRI_N(plane)
++ | win->w[plane].mode_winctrl1 /* FRM,CCO,PO,PIPE */
++ ) ;
++
++ au1200_setlocation(plane, win->w[plane].xpos, win->w[plane].ypos);
++
++ lcd->window[plane].winctrl2 = ( 0
++ | LCD_WINCTRL2_CKMODE_00
++ | LCD_WINCTRL2_DBM
++/* | LCD_WINCTRL2_RAM */
++ | LCD_WINCTRL2_BX_N(fb_pars[plane].line_length)
++ | LCD_WINCTRL2_SCX_1
++ | LCD_WINCTRL2_SCY_1
++ ) ;
++ lcd->winenable |= win->w[plane].mode_winenable;
++ au_sync();
++
++}
++
++static unsigned long
++au1200fb_alloc_fbmem (unsigned long size)
++{
++ /* __get_free_pages() fulfills a max request of 2MB */
++ /* do multiple requests to obtain large contigous mem */
++#define MAX_GFP 0x00200000
++
++ unsigned long mem, amem, alloced = 0, allocsize;
++
++ size += 0x1000;
++ allocsize = (size < MAX_GFP) ? size : MAX_GFP;
++
++ /* Get first chunk */
++ mem = (unsigned long )
++ __get_free_pages(GFP_ATOMIC | GFP_DMA, get_order(allocsize));
++ if (mem != 0) alloced = allocsize;
++
++ /* Get remaining, contiguous chunks */
++ while (alloced < size)
++ {
++ amem = (unsigned long )
++ __get_free_pages(GFP_ATOMIC | GFP_DMA, get_order(allocsize));
++ if (amem != 0)
++ alloced += allocsize;
++
++ /* check for contiguous mem alloced */
++ if ((amem == 0) || (amem + allocsize) != mem)
++ break;
++ else
++ mem = amem;
++ }
++ return mem;
++}
++
++int __init au1200fb_init(void)
++{
++ int num_panels = sizeof(panels)/sizeof(struct panel_settings);
++ struct au1200fb_info *fb_info;
++ struct display *disp;
++ struct au1200fb_par *par;
++ unsigned long page;
++ int plane, bpp;
++
++ /*
++ * Get the panel information/display mode
++ */
++ if (panel_index < 0)
++ panel_index = board_au1200fb_panel();
++ if ((panel_index < 0) || (panel_index >= num_panels)) {
++ printk("ERROR: INVALID PANEL %d\n", panel_index);
++ return -EINVAL;
++ }
++ panel = &panels[panel_index];
++ win = &windows[window_index];
++
++ printk("au1200fb: Panel %d %s\n", panel_index, panel->name);
++ printk("au1200fb: Win %d %s\n", window_index, win->name);
++
++ /* Global setup/init */
++ au1200_setpanel(panel);
++ lcd->intenable = 0;
++ lcd->intstatus = ~0;
++ lcd->backcolor = win->mode_backcolor;
++ lcd->winenable = 0;
++
++ /* Setup Color Key - FIX!!! */
++ lcd->colorkey = win->mode_colorkey;
++ lcd->colorkeymsk = win->mode_colorkeymsk;
++
++ /* Setup HWCursor - FIX!!! Need to support this eventually */
++ lcd->hwc.cursorctrl = 0;
++ lcd->hwc.cursorpos = 0;
++ lcd->hwc.cursorcolor0 = 0;
++ lcd->hwc.cursorcolor1 = 0;
++ lcd->hwc.cursorcolor2 = 0;
++ lcd->hwc.cursorcolor3 = 0;
++
++ /* Register each plane as a frame buffer device */
++ for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane)
++ {
++ fb_info = &fb_infos[plane];
++ disp = &disps[plane];
++ par = &fb_pars[plane];
++
++ bpp = winbpp(win->w[plane].mode_winctrl1);
++ if (win->w[plane].xres == 0)
++ win->w[plane].xres = panel->Xres;
++ if (win->w[plane].yres == 0)
++ win->w[plane].yres = panel->Yres;
++
++ par->var.xres =
++ par->var.xres_virtual = win->w[plane].xres;
++ par->var.yres =
++ par->var.yres_virtual = win->w[plane].yres;
++ par->var.bits_per_pixel = bpp;
++ par->line_length = win->w[plane].xres * bpp / 8; /* in bytes */
++ /*
++ * Allocate LCD framebuffer from system memory
++ * Set page reserved so that mmap will work. This is necessary
++ * since we'll be remapping normal memory.
++ */
++ fb_info->fb_size = (win->w[plane].xres * win->w[plane].yres * bpp) / 8;
++ fb_info->fb_virt_start = au1200fb_alloc_fbmem(fb_info->fb_size);
++ if (!fb_info->fb_virt_start) {
++ printk("Unable to allocate fb memory\n");
++ return -ENOMEM;
++ }
++ fb_info->fb_phys = virt_to_bus((void *)fb_info->fb_virt_start);
++ for (page = fb_info->fb_virt_start;
++ page < PAGE_ALIGN(fb_info->fb_virt_start + fb_info->fb_size);
++ page += PAGE_SIZE) {
++ SetPageReserved(virt_to_page(page));
++ }
++ /* Convert to kseg1 */
++ fb_info->fb_virt_start =
++ (void *)((u32)fb_info->fb_virt_start | 0xA0000000);
++ /* FIX!!! may wish to avoid this to save startup time??? */
++ memset((void *)fb_info->fb_virt_start, 0, fb_info->fb_size);
++
++ fb_info->gen.parsize = sizeof(struct au1200fb_par);
++ fb_info->gen.fbhw = &au1200_switch;
++ strcpy(fb_info->gen.info.modename, "Au1200 LCD");
++ fb_info->gen.info.changevar = NULL;
++ fb_info->gen.info.node = -1;
++
++ fb_info->gen.info.fbops = &au1200fb_ops;
++ fb_info->gen.info.disp = disp;
++ fb_info->gen.info.switch_con = &fbgen_switch;
++ fb_info->gen.info.updatevar = &fbgen_update_var;
++ fb_info->gen.info.blank = &fbgen_blank;
++ fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT;
++
++ fb_info->nohwcursor = 1;
++ fb_info->noblanking = 1;
++
++ /* This should give a reasonable default video mode */
++ fbgen_get_var(&disp->var, -1, &fb_info->gen.info);
++ fbgen_do_set_var(&disp->var, 1, &fb_info->gen);
++ fbgen_set_disp(-1, &fb_info->gen);
++ fbgen_install_cmap(0, &fb_info->gen);
++
++ /* Turn on plane */
++ au1200_setmode(plane);
++
++ if (register_framebuffer(&fb_info->gen.info) < 0)
++ return -EINVAL;
++
++ printk(KERN_INFO "fb%d: %s plane %d @ %08X (%d x %d x %d)\n",
++ GET_FB_IDX(fb_info->gen.info.node),
++ fb_info->gen.info.modename, plane, fb_info->fb_phys,
++ win->w[plane].xres, win->w[plane].yres, bpp);
++ }
++ /* uncomment this if your driver cannot be unloaded */
++ /* MOD_INC_USE_COUNT; */
++ return 0;
++}
++
++void au1200fb_setup(char *options, int *ints)
++{
++ char* this_opt;
++ int i;
++ int num_panels = sizeof(panels)/sizeof(struct panel_settings);
++
++ if (!options || !*options)
++ return;
++
++ for(this_opt=strtok(options, ","); this_opt;
++ this_opt=strtok(NULL, ",")) {
++ if (!strncmp(this_opt, "panel:", 6)) {
++ int i;
++ long int li;
++ char *endptr;
++ this_opt += 6;
++
++ /* Panel name can be name, "bs" for board-switch, or number/index */
++ li = simple_strtol(this_opt, &endptr, 0);
++ if (*endptr == '\0') {
++ panel_index = (int)li;
++ }
++ else if (strcmp(this_opt, "bs") == 0) {
++ panel_index = board_au1200fb_panel();
++ }
++ else
++ for (i=0; i<num_panels; i++) {
++ if (!strcmp(this_opt, panels[i].name)) {
++ panel_index = i;
++ break;
++ }
++ }
++ }
++ else if (!strncmp(this_opt, "nohwcursor", 10)) {
++ printk("nohwcursor\n");
++ fb_infos[0].nohwcursor = 1;
++ }
++ }
++
++ printk("au1200fb: Panel %d %s\n", panel_index,
++ panels[panel_index].name);
++}
++
++
++
++#ifdef MODULE
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Au1200 LCD framebuffer driver");
++
++void au1200fb_cleanup(struct fb_info *info)
++{
++ unregister_framebuffer(info);
++}
++
++module_init(au1200fb_init);
++module_exit(au1200fb_cleanup);
++#endif /* MODULE */
++
++
+diff -Nur linux-2.4.32-rc1/drivers/video/au1200fb.h linux-2.4.32-rc1.mips/drivers/video/au1200fb.h
+--- linux-2.4.32-rc1/drivers/video/au1200fb.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/video/au1200fb.h 2005-02-11 22:16:44.000000000 +0100
+@@ -0,0 +1,288 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ * Hardware definitions for the Au1200 LCD controller
++ *
++ * Copyright 2004 AMD
++ * Author: AMD
++ *
++ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef _AU1200LCD_H
++#define _AU1200LCD_H
++
++/********************************************************************/
++#define AU1200_LCD_ADDR 0xB5000000
++
++#define uint8 unsigned char
++#define uint32 unsigned int
++
++typedef volatile struct
++{
++ uint32 reserved0;
++ uint32 screen;
++ uint32 backcolor;
++ uint32 horztiming;
++ uint32 verttiming;
++ uint32 clkcontrol;
++ uint32 pwmdiv;
++ uint32 pwmhi;
++ uint32 reserved1;
++ uint32 winenable;
++ uint32 colorkey;
++ uint32 colorkeymsk;
++ struct
++ {
++ uint32 cursorctrl;
++ uint32 cursorpos;
++ uint32 cursorcolor0;
++ uint32 cursorcolor1;
++ uint32 cursorcolor2;
++ uint32 cursorcolor3;
++ } hwc;
++ uint32 intstatus;
++ uint32 intenable;
++ uint32 outmask;
++ uint32 fifoctrl;
++ uint32 reserved2[(0x0100-0x0058)/4];
++ struct
++ {
++ uint32 winctrl0;
++ uint32 winctrl1;
++ uint32 winctrl2;
++ uint32 winbuf0;
++ uint32 winbuf1;
++ uint32 winbufctrl;
++ uint32 winreserved0;
++ uint32 winreserved1;
++ } window[4];
++
++ uint32 reserved3[(0x0400-0x0180)/4];
++
++ uint32 palette[(0x0800-0x0400)/4];
++
++ uint8 cursorpattern[256];
++
++} AU1200_LCD;
++
++/* lcd_screen */
++#define LCD_SCREEN_SEN (1<<31)
++#define LCD_SCREEN_SX (0x07FF<<19)
++#define LCD_SCREEN_SY (0x07FF<< 8)
++#define LCD_SCREEN_SWP (1<<7)
++#define LCD_SCREEN_SWD (1<<6)
++#define LCD_SCREEN_ST (7<<0)
++#define LCD_SCREEN_ST_TFT (0<<0)
++#define LCD_SCREEN_SX_N(WIDTH) ((WIDTH-1)<<19)
++#define LCD_SCREEN_SY_N(HEIGHT) ((HEIGHT-1)<<8)
++#define LCD_SCREEN_ST_CSTN (1<<0)
++#define LCD_SCREEN_ST_CDSTN (2<<0)
++#define LCD_SCREEN_ST_M8STN (3<<0)
++#define LCD_SCREEN_ST_M4STN (4<<0)
++
++/* lcd_backcolor */
++#define LCD_BACKCOLOR_SBGR (0xFF<<16)
++#define LCD_BACKCOLOR_SBGG (0xFF<<8)
++#define LCD_BACKCOLOR_SBGB (0xFF<<0)
++#define LCD_BACKCOLOR_SBGR_N(N) ((N)<<16)
++#define LCD_BACKCOLOR_SBGG_N(N) ((N)<<8)
++#define LCD_BACKCOLOR_SBGB_N(N) ((N)<<0)
++
++/* lcd_winenable */
++#define LCD_WINENABLE_WEN3 (1<<3)
++#define LCD_WINENABLE_WEN2 (1<<2)
++#define LCD_WINENABLE_WEN1 (1<<1)
++#define LCD_WINENABLE_WEN0 (1<<0)
++
++/* lcd_colorkey */
++#define LCD_COLORKEY_CKR (0xFF<<16)
++#define LCD_COLORKEY_CKG (0xFF<<8)
++#define LCD_COLORKEY_CKB (0xFF<<0)
++#define LCD_COLORKEY_CKR_N(N) ((N)<<16)
++#define LCD_COLORKEY_CKG_N(N) ((N)<<8)
++#define LCD_COLORKEY_CKB_N(N) ((N)<<0)
++
++/* lcd_colorkeymsk */
++#define LCD_COLORKEYMSK_CKMR (0xFF<<16)
++#define LCD_COLORKEYMSK_CKMG (0xFF<<8)
++#define LCD_COLORKEYMSK_CKMB (0xFF<<0)
++#define LCD_COLORKEYMSK_CKMR_N(N) ((N)<<16)
++#define LCD_COLORKEYMSK_CKMG_N(N) ((N)<<8)
++#define LCD_COLORKEYMSK_CKMB_N(N) ((N)<<0)
++
++/* lcd windows control 0 */
++#define LCD_WINCTRL0_OX (0x07FF<<21)
++#define LCD_WINCTRL0_OY (0x07FF<<10)
++#define LCD_WINCTRL0_A (0x00FF<<2)
++#define LCD_WINCTRL0_AEN (1<<1)
++#define LCD_WINCTRL0_OX_N(N) ((N)<<21)
++#define LCD_WINCTRL0_OY_N(N) ((N)<<10)
++#define LCD_WINCTRL0_A_N(N) ((N)<<2)
++
++/* lcd windows control 1 */
++#define LCD_WINCTRL1_PRI (3<<30)
++#define LCD_WINCTRL1_PIPE (1<<29)
++#define LCD_WINCTRL1_FRM (0xF<<25)
++#define LCD_WINCTRL1_CCO (1<<24)
++#define LCD_WINCTRL1_PO (3<<22)
++#define LCD_WINCTRL1_SZX (0x07FF<<11)
++#define LCD_WINCTRL1_SZY (0x07FF<<0)
++#define LCD_WINCTRL1_FRM_1BPP (0<<25)
++#define LCD_WINCTRL1_FRM_2BPP (1<<25)
++#define LCD_WINCTRL1_FRM_4BPP (2<<25)
++#define LCD_WINCTRL1_FRM_8BPP (3<<25)
++#define LCD_WINCTRL1_FRM_12BPP (4<<25)
++#define LCD_WINCTRL1_FRM_16BPP655 (5<<25)
++#define LCD_WINCTRL1_FRM_16BPP565 (6<<25)
++#define LCD_WINCTRL1_FRM_16BPP556 (7<<25)
++#define LCD_WINCTRL1_FRM_16BPPI1555 (8<<25)
++#define LCD_WINCTRL1_FRM_16BPPI5551 (9<<25)
++#define LCD_WINCTRL1_FRM_16BPPA1555 (10<<25)
++#define LCD_WINCTRL1_FRM_16BPPA5551 (11<<25)
++#define LCD_WINCTRL1_FRM_24BPP (12<<25)
++#define LCD_WINCTRL1_FRM_32BPP (13<<25)
++#define LCD_WINCTRL1_PRI_N(N) ((N)<<30)
++#define LCD_WINCTRL1_PO_00 (0<<22)
++#define LCD_WINCTRL1_PO_01 (1<<22)
++#define LCD_WINCTRL1_PO_10 (2<<22)
++#define LCD_WINCTRL1_PO_11 (3<<22)
++#define LCD_WINCTRL1_SZX_N(N) ((N-1)<<11)
++#define LCD_WINCTRL1_SZY_N(N) ((N-1)<<0)
++
++/* lcd windows control 2 */
++#define LCD_WINCTRL2_CKMODE (3<<24)
++#define LCD_WINCTRL2_DBM (1<<23)
++#define LCD_WINCTRL2_RAM (3<<21)
++#define LCD_WINCTRL2_BX (0x1FFF<<8)
++#define LCD_WINCTRL2_SCX (0xF<<4)
++#define LCD_WINCTRL2_SCY (0xF<<0)
++#define LCD_WINCTRL2_CKMODE_00 (0<<24)
++#define LCD_WINCTRL2_CKMODE_01 (1<<24)
++#define LCD_WINCTRL2_CKMODE_10 (2<<24)
++#define LCD_WINCTRL2_CKMODE_11 (3<<24)
++#define LCD_WINCTRL2_RAM_NONE (0<<21)
++#define LCD_WINCTRL2_RAM_PALETTE (1<<21)
++#define LCD_WINCTRL2_RAM_GAMMA (2<<21)
++#define LCD_WINCTRL2_RAM_BUFFER (3<<21)
++#define LCD_WINCTRL2_BX_N(N) ((N)<<8)
++#define LCD_WINCTRL2_SCX_1 (0<<4)
++#define LCD_WINCTRL2_SCX_2 (1<<4)
++#define LCD_WINCTRL2_SCX_4 (2<<4)
++#define LCD_WINCTRL2_SCY_1 (0<<0)
++#define LCD_WINCTRL2_SCY_2 (1<<0)
++#define LCD_WINCTRL2_SCY_4 (2<<0)
++
++/* lcd windows buffer control */
++#define LCD_WINBUFCTRL_DB (1<<1)
++#define LCD_WINBUFCTRL_DBN (1<<0)
++
++/* lcd_intstatus, lcd_intenable */
++#define LCD_INT_IFO (0xF<<14)
++#define LCD_INT_IFU (0xF<<10)
++#define LCD_INT_OFO (1<<9)
++#define LCD_INT_OFU (1<<8)
++#define LCD_INT_WAIT (1<<3)
++#define LCD_INT_SD (1<<2)
++#define LCD_INT_SA (1<<1)
++#define LCD_INT_SS (1<<0)
++
++/* lcd_horztiming */
++#define LCD_HORZTIMING_HND2 (0x1FF<<18)
++#define LCD_HORZTIMING_HND1 (0x1FF<<9)
++#define LCD_HORZTIMING_HPW (0x1FF<<0)
++#define LCD_HORZTIMING_HND2_N(N)(((N)-1)<<18)
++#define LCD_HORZTIMING_HND1_N(N)(((N)-1)<<9)
++#define LCD_HORZTIMING_HPW_N(N) (((N)-1)<<0)
++
++/* lcd_verttiming */
++#define LCD_VERTTIMING_VND2 (0x1FF<<18)
++#define LCD_VERTTIMING_VND1 (0x1FF<<9)
++#define LCD_VERTTIMING_VPW (0x1FF<<0)
++#define LCD_VERTTIMING_VND2_N(N)(((N)-1)<<18)
++#define LCD_VERTTIMING_VND1_N(N)(((N)-1)<<9)
++#define LCD_VERTTIMING_VPW_N(N) (((N)-1)<<0)
++
++/* lcd_clkcontrol */
++#define LCD_CLKCONTROL_EXT (1<<22)
++#define LCD_CLKCONTROL_DELAY (3<<20)
++#define LCD_CLKCONTROL_CDD (1<<19)
++#define LCD_CLKCONTROL_IB (1<<18)
++#define LCD_CLKCONTROL_IC (1<<17)
++#define LCD_CLKCONTROL_IH (1<<16)
++#define LCD_CLKCONTROL_IV (1<<15)
++#define LCD_CLKCONTROL_BF (0x1F<<10)
++#define LCD_CLKCONTROL_PCD (0x3FF<<0)
++#define LCD_CLKCONTROL_BF_N(N) (((N)-1)<<10)
++#define LCD_CLKCONTROL_PCD_N(N) ((N)<<0)
++
++/* lcd_pwmdiv */
++#define LCD_PWMDIV_EN (1<<31)
++#define LCD_PWMDIV_PWMDIV (0x1FFFF<<0)
++#define LCD_PWMDIV_PWMDIV_N(N) ((N)<<0)
++
++/* lcd_pwmhi */
++#define LCD_PWMHI_PWMHI1 (0xFFFF<<16)
++#define LCD_PWMHI_PWMHI0 (0xFFFF<<0)
++#define LCD_PWMHI_PWMHI1_N(N) ((N)<<16)
++#define LCD_PWMHI_PWMHI0_N(N) ((N)<<0)
++
++/* lcd_hwccon */
++#define LCD_HWCCON_EN (1<<0)
++
++/* lcd_cursorpos */
++#define LCD_CURSORPOS_HWCXOFF (0x1F<<27)
++#define LCD_CURSORPOS_HWCXPOS (0x07FF<<16)
++#define LCD_CURSORPOS_HWCYOFF (0x1F<<11)
++#define LCD_CURSORPOS_HWCYPOS (0x07FF<<0)
++#define LCD_CURSORPOS_HWCXOFF_N(N) ((N)<<27)
++#define LCD_CURSORPOS_HWCXPOS_N(N) ((N)<<16)
++#define LCD_CURSORPOS_HWCYOFF_N(N) ((N)<<11)
++#define LCD_CURSORPOS_HWCYPOS_N(N) ((N)<<0)
++
++/* lcd_cursorcolor */
++#define LCD_CURSORCOLOR_HWCA (0xFF<<24)
++#define LCD_CURSORCOLOR_HWCR (0xFF<<16)
++#define LCD_CURSORCOLOR_HWCG (0xFF<<8)
++#define LCD_CURSORCOLOR_HWCB (0xFF<<0)
++#define LCD_CURSORCOLOR_HWCA_N(N) ((N)<<24)
++#define LCD_CURSORCOLOR_HWCR_N(N) ((N)<<16)
++#define LCD_CURSORCOLOR_HWCG_N(N) ((N)<<8)
++#define LCD_CURSORCOLOR_HWCB_N(N) ((N)<<0)
++
++/* lcd_fifoctrl */
++#define LCD_FIFOCTRL_F3IF (1<<29)
++#define LCD_FIFOCTRL_F3REQ (0x1F<<24)
++#define LCD_FIFOCTRL_F2IF (1<<29)
++#define LCD_FIFOCTRL_F2REQ (0x1F<<16)
++#define LCD_FIFOCTRL_F1IF (1<<29)
++#define LCD_FIFOCTRL_F1REQ (0x1F<<8)
++#define LCD_FIFOCTRL_F0IF (1<<29)
++#define LCD_FIFOCTRL_F0REQ (0x1F<<0)
++#define LCD_FIFOCTRL_F3REQ_N(N) ((N-1)<<24)
++#define LCD_FIFOCTRL_F2REQ_N(N) ((N-1)<<16)
++#define LCD_FIFOCTRL_F1REQ_N(N) ((N-1)<<8)
++#define LCD_FIFOCTRL_F0REQ_N(N) ((N-1)<<0)
++
++/* lcd_outmask */
++#define LCD_OUTMASK_MASK (0x00FFFFFF)
++
++/********************************************************************/
++#endif /* _AU1200LCD_H */
+diff -Nur linux-2.4.32-rc1/drivers/video/Config.in linux-2.4.32-rc1.mips/drivers/video/Config.in
+--- linux-2.4.32-rc1/drivers/video/Config.in 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/video/Config.in 2005-02-11 22:16:44.000000000 +0100
+@@ -87,8 +87,8 @@
+ if [ "$CONFIG_HP300" = "y" ]; then
+ define_bool CONFIG_FB_HP300 y
+ fi
+- if [ "$ARCH" = "alpha" ]; then
+- tristate ' TGA framebuffer support' CONFIG_FB_TGA
++ if [ "$ARCH" = "alpha" -o "$CONFIG_TC" = "y" ]; then
++ tristate ' TGA/SFB+ framebuffer support' CONFIG_FB_TGA
+ fi
+ if [ "$CONFIG_X86" = "y" ]; then
+ bool ' VESA VGA graphics console' CONFIG_FB_VESA
+@@ -121,6 +121,17 @@
+ hex ' Framebuffer Base Address' CONFIG_E1355_FB_BASE a8200000
+ fi
+ fi
++ if [ "$CONFIG_SOC_AU1100" = "y" ]; then
++ bool ' Au1100 LCD Driver' CONFIG_FB_AU1100
++ fi
++
++ if [ "$CONFIG_SOC_AU1200" = "y" ]; then
++ bool ' Au1200 LCD Driver' CONFIG_FB_AU1200
++ if [ "$CONFIG_FB_AU1200" = "y" ]; then
++ int ' Number of planes (1 to 4)' CONFIG_FB_AU1200_DEVS 1
++ fi
++ fi
++
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ if [ "$CONFIG_PCI" != "n" ]; then
+ tristate ' Matrox acceleration (EXPERIMENTAL)' CONFIG_FB_MATROX
+@@ -178,9 +189,6 @@
+ bool ' Use CRT on Pb1100 ' CONFIG_PB1500_CRT
+ bool ' Use TFT Panel on Pb1100 ' CONFIG_PB1500_TFT
+ fi
+- if [ "$CONFIG_SOC_AU1100" = "y" ]; then
+- bool ' Au1100 LCD Driver' CONFIG_FB_AU1100
+- fi
+ fi
+ fi
+ fi
+diff -Nur linux-2.4.32-rc1/drivers/video/fbmem.c linux-2.4.32-rc1.mips/drivers/video/fbmem.c
+--- linux-2.4.32-rc1/drivers/video/fbmem.c 2005-06-01 02:56:56.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/video/fbmem.c 2005-05-25 19:14:24.000000000 +0200
+@@ -139,6 +139,8 @@
+ extern int e1356fb_setup(char*);
+ extern int au1100fb_init(void);
+ extern int au1100fb_setup(char*);
++extern int au1200fb_init(void);
++extern int au1200fb_setup(char*);
+ extern int pvr2fb_init(void);
+ extern int pvr2fb_setup(char*);
+ extern int sstfb_init(void);
+@@ -331,6 +333,9 @@
+ #ifdef CONFIG_FB_AU1100
+ { "au1100fb", au1100fb_init, au1100fb_setup },
+ #endif
++#ifdef CONFIG_FB_AU1200
++ { "au1200fb", au1200fb_init, au1200fb_setup },
++#endif
+ #ifdef CONFIG_FB_IT8181
+ { "it8181fb", it8181fb_init, it8181fb_setup },
+ #endif
+diff -Nur linux-2.4.32-rc1/drivers/video/ims332.h linux-2.4.32-rc1.mips/drivers/video/ims332.h
+--- linux-2.4.32-rc1/drivers/video/ims332.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/video/ims332.h 2003-12-22 17:02:20.000000000 +0100
+@@ -0,0 +1,275 @@
++/*
++ * linux/drivers/video/ims332.h
++ *
++ * Copyright 2003 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
++ *
++ * This file is subject to the terms and conditions of the GNU General
++ * Public License. See the file COPYING in the main directory of this
++ * archive for more details.
++ */
++#include <linux/types.h>
++
++/*
++ * IMS332 16-bit wide, 128-bit aligned registers.
++ */
++struct _ims332_reg {
++ volatile u16 r;
++ u16 pad[7];
++};
++
++struct _ims332_regs {
++#define IMS332_BOOT_PLL_MUTLIPLIER 0x00001f
++#define IMS332_BOOT_CLOCK_SOURCE_SEL 0x000020
++#define IMS332_BOOT_ADDRESS_ALIGNMENT 0x000040
++#define IMS332_BOOT_WRITE_ZERO 0xffff80
++ struct _ims332_reg boot;
++ struct _ims332_reg pad0[0x020 - 0x000];
++ struct _ims332_reg half_sync;
++ struct _ims332_reg back_porch;
++ struct _ims332_reg display;
++ struct _ims332_reg short_display;
++ struct _ims332_reg broad_pulse;
++ struct _ims332_reg vsync;
++ struct _ims332_reg vpre_equalise;
++ struct _ims332_reg vpost_equalise;
++ struct _ims332_reg vblank;
++ struct _ims332_reg vdisplay;
++ struct _ims332_reg line_time;
++ struct _ims332_reg line_start;
++ struct _ims332_reg mem_init;
++ struct _ims332_reg transfer_delay;
++ struct _ims332_reg pad1[0x03f - 0x02e];
++ struct _ims332_reg pixel_address_mask;
++ struct _ims332_reg pad2[0x05f - 0x040];
++
++#define IMS332_CTRL_A_BOOT_ENABLE_VTG 0x000001
++#define IMS332_CTRL_A_SCREEN_FORMAT 0x000002
++#define IMS332_CTRL_A_INTERLACED_STANDARD 0x000004
++#define IMS332_CTRL_A_OPERATING_MODE 0x000008
++#define IMS332_CTRL_A_FRAME_FLYBACK_PATTERN 0x000010
++#define IMS332_CTRL_A_DIGITAL_SYNC_FORMAT 0x000020
++#define IMS332_CTRL_A_ANALOGUE_VIDEO_FORMAT 0x000040
++#define IMS332_CTRL_A_BLANK_LEVEL 0x000080
++#define IMS332_CTRL_A_BLANK_IO 0x000100
++#define IMS332_CTRL_A_BLANK_FUNCTION_SWITCH 0x000200
++#define IMS332_CTRL_A_FORCE_BLANKING 0x000400
++#define IMS332_CTRL_A_TURN_OFF_BLANKING 0x000800
++#define IMS332_CTRL_A_VRAM_ADDRESS_INCREMENT 0x003000
++#define IMS332_CTRL_A_TURN_OFF_DMA 0x004000
++#define IMS332_CTRL_A_SYNC_DELAY 0x038000
++#define IMS332_CTRL_A_PIXEL_PORT_INTERLEAVING 0x040000
++#define IMS332_CTRL_A_DELAYED_SAMPLING 0x080000
++#define IMS332_CTRL_A_BITS_PER_PIXEL 0x700000
++#define IMS332_CTRL_A_CURSOR_DISABLE 0x800000
++ struct _ims332_reg config_control_a;
++ struct _ims332_reg pad3[0x06f - 0x060];
++
++#define IMS332_CTRL_B_WRITE_ZERO 0xffffff
++ struct _ims332_reg config_control_b;
++ struct _ims332_reg pad4[0x07f - 0x070];
++ struct _ims332_reg screen_top;
++ struct _ims332_reg pad5[0x0a0 - 0x080];
++ /* cursor color palette, 3 entries, reg no. 0xa1 - 0xa3 */
++ struct _ims332_reg cursor_color_palette0;
++ struct _ims332_reg cursor_color_palette1;
++ struct _ims332_reg cursor_color_palette2;
++ struct _ims332_reg pad6[0x0bf - 0x0a3];
++ struct _ims332_reg rgb_frame_checksum0;
++ struct _ims332_reg rgb_frame_checksum1;
++ struct _ims332_reg rgb_frame_checksum2;
++ struct _ims332_reg pad7[0x0c6 - 0x0c2];
++ struct _ims332_reg cursor_start;
++ struct _ims332_reg pad8[0x0ff - 0x0c7];
++ /* color palette, 256 entries of form 0x00BBGGRR, reg no. 0x100 - 0x1ff */
++ struct _ims332_reg color_palette[0x1ff - 0x0ff];
++ /* hardware cursor bitmap, reg no. 0x200 - 0x3ff */
++ struct _ims332_reg cursor_ram[0x3ff - 0x1ff];
++};
++
++/*
++ * In the functions below we use some weird looking helper variables to
++ * access most members of this struct, otherwise the compiler splits
++ * the read/write in two byte accesses.
++ */
++struct ims332_regs {
++ struct _ims332_regs rw;
++ char pad0[0x80000 - sizeof (struct _ims332_regs)];
++ struct _ims332_regs r;
++ char pad1[0xa0000 - (sizeof (struct _ims332_regs) + 0x80000)];
++ struct _ims332_regs w;
++} __attribute__((packed));
++
++static inline void ims332_control_reg_bits(struct ims332_regs *regs, u32 mask,
++ u32 val)
++{
++ volatile u16 *ctr = &(regs->r.config_control_a.r);
++ volatile u16 *ctw = &(regs->w.config_control_a.r);
++ u32 ctrl;
++
++ mb();
++ ctrl = *ctr;
++ rmb();
++ ctrl |= ((regs->rw.boot.r << 8) & 0x00ff0000);
++ ctrl |= val & mask;
++ ctrl &= ~(~val & mask);
++ wmb();
++ regs->rw.boot.r = (ctrl >> 8) & 0xff00;
++ wmb();
++ *ctw = ctrl & 0xffff;
++}
++
++/* FIXME: This is maxinefb specific. */
++static inline void ims332_bootstrap(struct ims332_regs *regs)
++{
++ volatile u16 *ctw = &(regs->w.config_control_a.r);
++ u32 ctrl = IMS332_CTRL_A_BOOT_ENABLE_VTG | IMS332_CTRL_A_TURN_OFF_DMA;
++
++ /* bootstrap sequence */
++ mb();
++ regs->rw.boot.r = 0;
++ wmb();
++ *ctw = 0;
++
++ /* init control A register */
++ wmb();
++ regs->rw.boot.r = (ctrl >> 8) & 0xff00;
++ wmb();
++ *ctw = ctrl & 0xffff;
++}
++
++static inline void ims332_blank_screen(struct ims332_regs *regs, int blank)
++{
++ ims332_control_reg_bits(regs, IMS332_CTRL_A_FORCE_BLANKING,
++ blank ? IMS332_CTRL_A_FORCE_BLANKING : 0);
++}
++
++static inline void ims332_set_color_depth(struct ims332_regs *regs, u32 depth)
++{
++ u32 dp;
++ u32 mask = (IMS332_CTRL_A_PIXEL_PORT_INTERLEAVING
++ | IMS332_CTRL_A_DELAYED_SAMPLING
++ | IMS332_CTRL_A_BITS_PER_PIXEL);
++
++ switch (depth) {
++ case 1: dp = 0 << 20; break;
++ case 2: dp = 1 << 20; break;
++ case 4: dp = 2 << 20; break;
++ case 8: dp = 3 << 20; break;
++ case 15: dp = (4 << 20) | IMS332_CTRL_A_PIXEL_PORT_INTERLEAVING; break;
++ case 16: dp = (5 << 20) | IMS332_CTRL_A_PIXEL_PORT_INTERLEAVING; break;
++ default: return;
++ }
++ ims332_control_reg_bits(regs, mask, dp);
++
++ if (depth <= 8) {
++ volatile u16 *pmask = &(regs->w.pixel_address_mask.r);
++ u32 dm = (1 << depth) - 1;
++
++ wmb();
++ regs->rw.boot.r = dm << 8;
++ wmb();
++ *pmask = dm << 8 | dm;
++ }
++}
++
++static inline void ims332_set_screen_top(struct ims332_regs *regs, u16 top)
++{
++ volatile u16 *st = &(regs->w.screen_top.r);
++
++ mb();
++ *st = top & 0xffff;
++}
++
++static inline void ims332_enable_cursor(struct ims332_regs *regs, int on)
++{
++ ims332_control_reg_bits(regs, IMS332_CTRL_A_CURSOR_DISABLE,
++ on ? 0 : IMS332_CTRL_A_CURSOR_DISABLE);
++}
++
++static inline void ims332_position_cursor(struct ims332_regs *regs,
++ u16 x, u16 y)
++{
++ volatile u16 *cp = &(regs->w.cursor_start.r);
++ u32 val = ((x & 0xfff) << 12) | (y & 0xfff);
++
++ if (x > 2303 || y > 2303)
++ return;
++
++ mb();
++ regs->rw.boot.r = (val >> 8) & 0xff00;
++ wmb();
++ *cp = val & 0xffff;
++}
++
++static inline void ims332_set_font(struct ims332_regs *regs, u8 fgc,
++ u16 width, u16 height)
++{
++ volatile u16 *cp0 = &(regs->w.cursor_color_palette0.r);
++ int i;
++
++ mb();
++ for (i = 0; i < 0x200; i++) {
++ volatile u16 *cram = &(regs->w.cursor_ram[i].r);
++
++ if (height << 6 <= i << 3)
++ *cram = 0x0000;
++ else if (width <= i % 8 << 3)
++ *cram = 0x0000;
++ else if (((width >> 3) & 0xffff) > i % 8)
++ *cram = 0x5555;
++ else
++ *cram = 0x5555 & ~(0xffff << (width % 8 << 1));
++ wmb();
++ }
++ regs->rw.boot.r = fgc << 8;
++ wmb();
++ *cp0 = fgc << 8 | fgc;
++}
++
++static inline void ims332_read_cmap(struct ims332_regs *regs, u8 reg,
++ u8* red, u8* green, u8* blue)
++{
++ volatile u16 *rptr = &(regs->r.color_palette[reg].r);
++ u16 val;
++
++ mb();
++ val = *rptr;
++ *red = val & 0xff;
++ *green = (val >> 8) & 0xff;
++ rmb();
++ *blue = (regs->rw.boot.r >> 8) & 0xff;
++}
++
++static inline void ims332_write_cmap(struct ims332_regs *regs, u8 reg,
++ u8 red, u8 green, u8 blue)
++{
++ volatile u16 *wptr = &(regs->w.color_palette[reg].r);
++
++ mb();
++ regs->rw.boot.r = blue << 8;
++ wmb();
++ *wptr = (green << 8) + red;
++}
++
++static inline void ims332_dump_regs(struct ims332_regs *regs)
++{
++ int i;
++
++ printk(__FUNCTION__);
++ ims332_control_reg_bits(regs, IMS332_CTRL_A_BOOT_ENABLE_VTG, 0);
++ for (i = 0; i < 0x100; i++) {
++ volatile u16 *cpad = (u16 *)((char *)(&regs->r) + sizeof(struct _ims332_reg) * i);
++ u32 val;
++
++ val = *cpad;
++ rmb();
++ val |= regs->rw.boot.r << 8;
++ rmb();
++ if (! (i % 8))
++ printk("\n%02x:", i);
++ printk(" %06x", val);
++ }
++ ims332_control_reg_bits(regs, IMS332_CTRL_A_BOOT_ENABLE_VTG,
++ IMS332_CTRL_A_BOOT_ENABLE_VTG);
++ printk("\n");
++}
+diff -Nur linux-2.4.32-rc1/drivers/video/Makefile linux-2.4.32-rc1.mips/drivers/video/Makefile
+--- linux-2.4.32-rc1/drivers/video/Makefile 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/video/Makefile 2005-02-11 22:16:44.000000000 +0100
+@@ -87,6 +87,7 @@
+ obj-$(CONFIG_FB_MAXINE) += maxinefb.o
+ obj-$(CONFIG_FB_TX3912) += tx3912fb.o
+ obj-$(CONFIG_FB_AU1100) += au1100fb.o fbgen.o
++obj-$(CONFIG_FB_AU1200) += au1200fb.o fbgen.o
+ obj-$(CONFIG_FB_IT8181) += it8181fb.o fbgen.o
+
+ subdir-$(CONFIG_STI_CONSOLE) += sti
+diff -Nur linux-2.4.32-rc1/drivers/video/maxinefb.h linux-2.4.32-rc1.mips/drivers/video/maxinefb.h
+--- linux-2.4.32-rc1/drivers/video/maxinefb.h 2003-08-25 13:44:42.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/video/maxinefb.h 1970-01-01 01:00:00.000000000 +0100
+@@ -1,38 +0,0 @@
+-/*
+- * linux/drivers/video/maxinefb.h
+- *
+- * DECstation 5000/xx onboard framebuffer support, Copyright (C) 1999 by
+- * Michael Engel <engel@unix-ag.org> and Karsten Merker <merker@guug.de>
+- * This file is subject to the terms and conditions of the GNU General
+- * Public License. See the file COPYING in the main directory of this
+- * archive for more details.
+- */
+-
+-#include <asm/addrspace.h>
+-
+-/*
+- * IMS332 video controller register base address
+- */
+-#define MAXINEFB_IMS332_ADDRESS KSEG1ADDR(0x1c140000)
+-
+-/*
+- * Begin of DECstation 5000/xx onboard framebuffer memory, default resolution
+- * is 1024x768x8
+- */
+-#define DS5000_xx_ONBOARD_FBMEM_START KSEG1ADDR(0x0a000000)
+-
+-/*
+- * The IMS 332 video controller used in the DECstation 5000/xx series
+- * uses 32 bits wide registers; the following defines declare the
+- * register numbers, to get the real offset, these have to be multiplied
+- * by four.
+- */
+-
+-#define IMS332_REG_CURSOR_RAM 0x200 /* hardware cursor bitmap */
+-
+-/*
+- * The color palette entries have the form 0x00BBGGRR
+- */
+-#define IMS332_REG_COLOR_PALETTE 0x100 /* color palette, 256 entries */
+-#define IMS332_REG_CURSOR_COLOR_PALETTE 0x0a1 /* cursor color palette, */
+- /* 3 entries */
+diff -Nur linux-2.4.32-rc1/drivers/video/newport_con.c linux-2.4.32-rc1.mips/drivers/video/newport_con.c
+--- linux-2.4.32-rc1/drivers/video/newport_con.c 2003-08-25 13:44:42.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/video/newport_con.c 2004-09-23 15:32:29.000000000 +0200
+@@ -22,6 +22,7 @@
+ #include <linux/module.h>
+ #include <linux/slab.h>
+
++#include <asm/io.h>
+ #include <asm/uaccess.h>
+ #include <asm/system.h>
+ #include <asm/page.h>
+@@ -77,7 +78,7 @@
+ static inline void newport_render_background(int xstart, int ystart,
+ int xend, int yend, int ci)
+ {
+- newport_wait();
++ newport_wait(npregs);
+ npregs->set.wrmask = 0xffffffff;
+ npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+ NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX
+@@ -94,7 +95,7 @@
+ unsigned short i;
+
+ for (i = 0; i < 16; i++) {
+- newport_bfwait();
++ newport_bfwait(npregs);
+ newport_cmap_setaddr(npregs, color_table[i]);
+ newport_cmap_setrgb(npregs,
+ default_red[i],
+@@ -107,7 +108,7 @@
+ unsigned long i;
+
+ for (i = 0; i < LINUX_LOGO_COLORS; i++) {
+- newport_bfwait();
++ newport_bfwait(npregs);
+ newport_cmap_setaddr(npregs, i + 0x20);
+ newport_cmap_setrgb(npregs,
+ linux_logo_red[i],
+@@ -115,13 +116,13 @@
+ linux_logo_blue[i]);
+ }
+
+- newport_wait();
++ newport_wait(npregs);
+ npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+ NPORT_DMODE0_CHOST);
+
+ npregs->set.xystarti = ((newport_xsize - LOGO_W) << 16) | (0);
+ npregs->set.xyendi = ((newport_xsize - 1) << 16);
+- newport_wait();
++ newport_wait(npregs);
+
+ for (i = 0; i < LOGO_W * LOGO_H; i++)
+ npregs->go.hostrw0 = linux_logo[i] << 24;
+@@ -133,7 +134,7 @@
+ if (logo_active)
+ return;
+
+- newport_wait();
++ newport_wait(npregs);
+ npregs->set.wrmask = 0xffffffff;
+ npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+ NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX
+@@ -155,7 +156,7 @@
+ unsigned short treg;
+ int i;
+
+- newport_wait();
++ newport_wait(npregs);
+ treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
+ newport_vc2_set(npregs, VC2_IREG_CONTROL,
+ (treg | VC2_CTRL_EVIDEO));
+@@ -165,7 +166,7 @@
+ npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
+ NPORT_DMODE_W2 | VC2_PROTOCOL);
+ for (i = 0; i < 128; i++) {
+- newport_bfwait();
++ newport_bfwait(npregs);
+ if (i == 92 || i == 94)
+ npregs->set.dcbdata0.byshort.s1 = 0xff00;
+ else
+@@ -205,7 +206,7 @@
+ npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
+ NPORT_DMODE_W2 | VC2_PROTOCOL);
+ for (i = 0; i < 128; i++) {
+- newport_bfwait();
++ newport_bfwait(npregs);
+ linetable[i] = npregs->set.dcbdata0.byshort.s1;
+ }
+
+@@ -216,12 +217,12 @@
+ npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
+ NPORT_DMODE_W2 | VC2_PROTOCOL);
+ do {
+- newport_bfwait();
++ newport_bfwait(npregs);
+ treg = npregs->set.dcbdata0.byshort.s1;
+ if ((treg & 1) == 0)
+ cols += (treg >> 7) & 0xfe;
+ if ((treg & 0x80) == 0) {
+- newport_bfwait();
++ newport_bfwait(npregs);
+ treg = npregs->set.dcbdata0.byshort.s1;
+ }
+ } while ((treg & 0x8000) == 0);
+@@ -291,16 +292,16 @@
+
+ if (!sgi_gfxaddr)
+ return NULL;
+- npregs = (struct newport_regs *) (KSEG1 + sgi_gfxaddr);
++ npregs = (struct newport_regs *) /* ioremap cannot fail */
++ ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
+ npregs->cset.config = NPORT_CFG_GD0;
+
+- if (newport_wait()) {
+- return NULL;
+- }
++ if (newport_wait(npregs))
++ goto out_unmap;
+
+ npregs->set.xstarti = TESTVAL;
+ if (npregs->set._xstart.word != XSTI_TO_FXSTART(TESTVAL))
+- return NULL;
++ goto out_unmap;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ font_data[i] = FONT_DATA;
+@@ -310,6 +311,10 @@
+ newport_get_screensize();
+
+ return "SGI Newport";
++
++out_unmap:
++ iounmap((void *)npregs);
++ return NULL;
+ }
+
+ static void newport_init(struct vc_data *vc, int init)
+@@ -363,7 +368,7 @@
+ (charattr & 0xf0) >> 4);
+
+ /* Set the color and drawing mode. */
+- newport_wait();
++ newport_wait(npregs);
+ npregs->set.colori = charattr & 0xf;
+ npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+ NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
+@@ -372,7 +377,7 @@
+ /* Set coordinates for bitmap operation. */
+ npregs->set.xystarti = (xpos << 16) | ((ypos + topscan) & 0x3ff);
+ npregs->set.xyendi = ((xpos + 7) << 16);
+- newport_wait();
++ newport_wait(npregs);
+
+ /* Go, baby, go... */
+ RENDER(npregs, p);
+@@ -396,7 +401,7 @@
+ xpos + ((count - 1) << 3), ypos,
+ (charattr & 0xf0) >> 4);
+
+- newport_wait();
++ newport_wait(npregs);
+
+ /* Set the color and drawing mode. */
+ npregs->set.colori = charattr & 0xf;
+@@ -407,7 +412,7 @@
+ for (i = 0; i < count; i++, xpos += 8) {
+ p = &font_data[vc->vc_num][(scr_readw(s++) & 0xff) << 4];
+
+- newport_wait();
++ newport_wait(npregs);
+
+ /* Set coordinates for bitmap operation. */
+ npregs->set.xystarti =
+@@ -689,7 +694,7 @@
+ xe = xs;
+ xs = tmp;
+ }
+- newport_wait();
++ newport_wait(npregs);
+ npregs->set.drawmode0 = (NPORT_DMODE0_S2S | NPORT_DMODE0_BLOCK |
+ NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX
+ | NPORT_DMODE0_STOPY);
+@@ -706,35 +711,35 @@
+ #define DUMMY (void *) newport_dummy
+
+ const struct consw newport_con = {
+- con_startup: newport_startup,
+- con_init: newport_init,
+- con_deinit: newport_deinit,
+- con_clear: newport_clear,
+- con_putc: newport_putc,
+- con_putcs: newport_putcs,
+- con_cursor: newport_cursor,
+- con_scroll: newport_scroll,
+- con_bmove: newport_bmove,
+- con_switch: newport_switch,
+- con_blank: newport_blank,
+- con_font_op: newport_font_op,
+- con_set_palette: newport_set_palette,
+- con_scrolldelta: newport_scrolldelta,
+- con_set_origin: DUMMY,
+- con_save_screen: DUMMY
++ .con_startup = newport_startup,
++ .con_init = newport_init,
++ .con_deinit = newport_deinit,
++ .con_clear = newport_clear,
++ .con_putc = newport_putc,
++ .con_putcs = newport_putcs,
++ .con_cursor = newport_cursor,
++ .con_scroll = newport_scroll,
++ .con_bmove = newport_bmove,
++ .con_switch = newport_switch,
++ .con_blank = newport_blank,
++ .con_font_op = newport_font_op,
++ .con_set_palette = newport_set_palette,
++ .con_scrolldelta = newport_scrolldelta,
++ .con_set_origin = DUMMY,
++ .con_save_screen = DUMMY
+ };
+
+ #ifdef MODULE
+ static int __init newport_console_init(void)
+ {
+ take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
+-
+ return 0;
+ }
+
+ static void __exit newport_console_exit(void)
+ {
+ give_up_console(&newport_con);
++ iounmap((void *)npregs);
+ }
+
+ module_init(newport_console_init);
+diff -Nur linux-2.4.32-rc1/drivers/video/tgafb.c linux-2.4.32-rc1.mips/drivers/video/tgafb.c
+--- linux-2.4.32-rc1/drivers/video/tgafb.c 2001-11-14 23:52:20.000000000 +0100
++++ linux-2.4.32-rc1.mips/drivers/video/tgafb.c 2004-10-30 01:15:02.000000000 +0200
+@@ -45,6 +45,15 @@
+ #include <linux/console.h>
+ #include <asm/io.h>
+
++#ifdef CONFIG_TC
++#include <asm/dec/tc.h>
++#else
++static int search_tc_card(const char *) { return -1; }
++static void claim_tc_card(int) { }
++static void release_tc_card(int) { }
++static unsigned long get_tc_base_addr(int) { return 0; }
++#endif
++
+ #include <video/fbcon.h>
+ #include <video/fbcon-cfb8.h>
+ #include <video/fbcon-cfb32.h>
+@@ -84,10 +93,10 @@
+ };
+
+ static unsigned int deep_presets[4] = {
+- 0x00014000,
+- 0x0001440d,
++ 0x00004000,
++ 0x0000440d,
+ 0xffffffff,
+- 0x0001441d
++ 0x0000441d
+ };
+
+ static unsigned int rasterop_presets[4] = {
+@@ -131,6 +140,13 @@
+ 0,
+ FB_VMODE_NONINTERLACED
+ }},
++ { "1280x1024-72", { /* mode #0 of PMAGD boards */
++ 1280, 1024, 1280, 1024, 0, 0, 0, 0,
++ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
++ 0, 0, -1, -1, FB_ACCELF_TEXT, 7692, 232, 32, 34, 3, 160, 3,
++ FB_SYNC_ON_GREEN,
++ FB_VMODE_NONINTERLACED
++ }},
+ { "800x600-56", {
+ 800, 600, 800, 600, 0, 0, 0, 0,
+ {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+@@ -488,7 +504,8 @@
+ continue;
+
+ mb();
+- TGA_WRITE_REG(deep_presets[fb_info.tga_type], TGA_DEEP_REG);
++ TGA_WRITE_REG(deep_presets[fb_info.tga_type] |
++ (par->sync_on_green ? 0x0 : 0x00010000), TGA_DEEP_REG);
+ while (TGA_READ_REG(TGA_CMD_STAT_REG) & 1) /* wait for not busy */
+ continue;
+ mb();
+@@ -548,7 +565,7 @@
+ BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_0, 0x40);
+ BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_1, 0x08);
+ BT463_WRITE(BT463_REG_ACC, BT463_CMD_REG_2,
+- (par->sync_on_green ? 0x80 : 0x40));
++ (par->sync_on_green ? 0xc0 : 0x40));
+
+ BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_0, 0xff);
+ BT463_WRITE(BT463_REG_ACC, BT463_READ_MASK_1, 0xff);
+@@ -921,19 +938,34 @@
+ int __init tgafb_init(void)
+ {
+ struct pci_dev *pdev;
++ int slot;
+
+ pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, NULL);
+ if (!pdev)
++ slot = search_tc_card("PMAGD");
++ if (!pdev && slot < 0)
+ return -ENXIO;
+
+ /* divine board type */
+
+- fb_info.tga_mem_base = (unsigned long)ioremap(pdev->resource[0].start, 0);
+- fb_info.tga_type = (readl(fb_info.tga_mem_base) >> 12) & 0x0f;
+- fb_info.tga_regs_base = fb_info.tga_mem_base + TGA_REGS_OFFSET;
+- fb_info.tga_fb_base = (fb_info.tga_mem_base
++ if (pdev) {
++ fb_info.tga_mem_base = (unsigned long)ioremap(pdev->resource[0].start,
++ 0);
++ fb_info.tga_type = (readl(fb_info.tga_mem_base) >> 12) & 0x0f;
++ fb_info.tga_regs_base = fb_info.tga_mem_base + TGA_REGS_OFFSET;
++ fb_info.tga_fb_base = (fb_info.tga_mem_base
+ + fb_offset_presets[fb_info.tga_type]);
+- pci_read_config_byte(pdev, PCI_REVISION_ID, &fb_info.tga_chip_rev);
++ pci_read_config_byte(pdev, PCI_REVISION_ID, &fb_info.tga_chip_rev);
++
++ } else {
++ claim_tc_card(slot);
++ fb_info.tga_mem_base = get_tc_base_addr(slot);
++ fb_info.tga_type = (readl(fb_info.tga_mem_base) >> 12) & 0x0f; /* ? */
++ fb_info.tga_regs_base = fb_info.tga_mem_base + TGA_REGS_OFFSET;
++ fb_info.tga_fb_base = (fb_info.tga_mem_base
++ + fb_offset_presets[fb_info.tga_type]);
++ fb_info.tga_chip_rev = TGA_READ_REG(TGA_START_REG) & 0xff;
++ }
+
+ /* setup framebuffer */
+
+@@ -950,40 +982,62 @@
+ fb_info.gen.fbhw = &tgafb_hwswitch;
+ fb_info.gen.fbhw->detect();
+
+- printk (KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n", fb_info.tga_chip_rev);
+- printk (KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n",
+- pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
++ if (pdev) {
++ printk (KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n",
++ fb_info.tga_chip_rev);
++ printk (KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n",
++ pdev->bus->number,
++ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
++ } else {
++ printk (KERN_INFO "tgafb: SFB+ detected, rev=0x%02x\n",
++ fb_info.tga_chip_rev);
++ }
+
+ switch (fb_info.tga_type)
+ {
+ case TGA_TYPE_8PLANE:
+- strcpy (fb_info.gen.info.modename,"Digital ZLXp-E1");
++ if (pdev)
++ strcpy (fb_info.gen.info.modename,"Digital ZLXp-E1");
++ else
++ strcpy (fb_info.gen.info.modename,"Digital ZLX-E1");
+ break;
+
+ case TGA_TYPE_24PLANE:
+- strcpy (fb_info.gen.info.modename,"Digital ZLXp-E2");
++ if (pdev)
++ strcpy (fb_info.gen.info.modename,"Digital ZLXp-E2");
++ else
++ strcpy (fb_info.gen.info.modename,"Digital ZLX-E2");
+ break;
+
+ case TGA_TYPE_24PLUSZ:
+- strcpy (fb_info.gen.info.modename,"Digital ZLXp-E3");
++ if (pdev)
++ strcpy (fb_info.gen.info.modename,"Digital ZLXp-E3");
++ else
++ strcpy (fb_info.gen.info.modename,"Digital ZLX-E3");
+ break;
+ }
+
+ /* This should give a reasonable default video mode */
+
+ if (!default_var_valid) {
+- default_var = tgafb_predefined[0].var;
++ if (pdev)
++ default_var = tgafb_predefined[0].var;
++ else
++ default_var = tgafb_predefined[1].var;
+ }
+ fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
+ disp.var.activate = FB_ACTIVATE_NOW;
+ fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
+ fbgen_set_disp(-1, &fb_info.gen);
+ fbgen_install_cmap(0, &fb_info.gen);
+- if (register_framebuffer(&fb_info.gen.info) < 0)
++ if (register_framebuffer(&fb_info.gen.info) < 0) {
++ if (slot >= 0)
++ release_tc_card(slot);
+ return -EINVAL;
+- printk(KERN_INFO "fb%d: %s frame buffer device at 0x%lx\n",
++ }
++ printk(KERN_INFO "fb%d: %s frame buffer device at 0x%llx\n",
+ GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename,
+- pdev->resource[0].start);
++ fb_info.tga_mem_base);
+ return 0;
+ }
+
+diff -Nur linux-2.4.32-rc1/drivers/video/tgafb.h linux-2.4.32-rc1.mips/drivers/video/tgafb.h
+--- linux-2.4.32-rc1/drivers/video/tgafb.h 2000-04-12 18:47:28.000000000 +0200
++++ linux-2.4.32-rc1.mips/drivers/video/tgafb.h 2004-10-30 01:15:02.000000000 +0200
+@@ -36,6 +36,7 @@
+ #define TGA_RASTEROP_REG 0x0034
+ #define TGA_PIXELSHIFT_REG 0x0038
+ #define TGA_DEEP_REG 0x0050
++#define TGA_START_REG 0x0054
+ #define TGA_PIXELMASK_REG 0x005c
+ #define TGA_CURSOR_BASE_REG 0x0060
+ #define TGA_HORIZ_REG 0x0064
+diff -Nur linux-2.4.32-rc1/fs/binfmt_elf.c linux-2.4.32-rc1.mips/fs/binfmt_elf.c
+--- linux-2.4.32-rc1/fs/binfmt_elf.c 2005-06-01 02:56:56.000000000 +0200
++++ linux-2.4.32-rc1.mips/fs/binfmt_elf.c 2005-05-23 14:12:31.000000000 +0200
+@@ -660,6 +660,9 @@
+ bprm->argc++;
+ }
+ }
++ } else {
++ /* Executables without an interpreter also need a personality */
++ SET_PERSONALITY(elf_ex, ibcs2_interpreter);
+ }
+
+ /* Flush all traces of the currently running executable */
+@@ -1211,7 +1214,11 @@
+ elf.e_entry = 0;
+ elf.e_phoff = sizeof(elf);
+ elf.e_shoff = 0;
++#ifdef ELF_CORE_EFLAGS
++ elf.e_flags = ELF_CORE_EFLAGS;
++#else
+ elf.e_flags = 0;
++#endif
+ elf.e_ehsize = sizeof(elf);
+ elf.e_phentsize = sizeof(struct elf_phdr);
+ elf.e_phnum = segs+1; /* Include notes */
+diff -Nur linux-2.4.32-rc1/fs/partitions/sgi.c linux-2.4.32-rc1.mips/fs/partitions/sgi.c
+--- linux-2.4.32-rc1/fs/partitions/sgi.c 2001-10-02 05:03:26.000000000 +0200
++++ linux-2.4.32-rc1.mips/fs/partitions/sgi.c 2004-08-11 22:30:07.000000000 +0200
+@@ -17,6 +17,11 @@
+ #include "check.h"
+ #include "sgi.h"
+
++#if CONFIG_BLK_DEV_MD
++extern void md_autodetect_dev(kdev_t dev);
++#endif
++
++
+ int sgi_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int current_minor)
+ {
+ int i, csum, magic;
+@@ -77,6 +82,10 @@
+ if(!blocks)
+ continue;
+ add_gd_partition(hd, current_minor, start, blocks);
++#ifdef CONFIG_BLK_DEV_MD
++ if (be32_to_cpu(p->type) == LINUX_RAID_PARTITION)
++ md_autodetect_dev(MKDEV(hd->major, current_minor));
++#endif
+ current_minor++;
+ }
+ printk("\n");
+diff -Nur linux-2.4.32-rc1/fs/proc/array.c linux-2.4.32-rc1.mips/fs/proc/array.c
+--- linux-2.4.32-rc1/fs/proc/array.c 2005-01-19 15:10:11.000000000 +0100
++++ linux-2.4.32-rc1.mips/fs/proc/array.c 2004-11-29 18:47:18.000000000 +0100
+@@ -368,15 +368,15 @@
+ task->cmin_flt,
+ task->maj_flt,
+ task->cmaj_flt,
+- task->times.tms_utime,
+- task->times.tms_stime,
+- task->times.tms_cutime,
+- task->times.tms_cstime,
++ hz_to_std(task->times.tms_utime),
++ hz_to_std(task->times.tms_stime),
++ hz_to_std(task->times.tms_cutime),
++ hz_to_std(task->times.tms_cstime),
+ priority,
+ nice,
+ 0UL /* removed */,
+ task->it_real_value,
+- task->start_time,
++ hz_to_std(task->start_time),
+ vsize,
+ mm ? mm->rss : 0, /* you might want to shift this left 3 */
+ task->rlim[RLIMIT_RSS].rlim_cur,
+@@ -615,14 +615,14 @@
+
+ len = sprintf(buffer,
+ "cpu %lu %lu\n",
+- task->times.tms_utime,
+- task->times.tms_stime);
++ hz_to_std(task->times.tms_utime),
++ hz_to_std(task->times.tms_stime));
+
+ for (i = 0 ; i < smp_num_cpus; i++)
+ len += sprintf(buffer + len, "cpu%d %lu %lu\n",
+ i,
+- task->per_cpu_utime[cpu_logical_map(i)],
+- task->per_cpu_stime[cpu_logical_map(i)]);
++ hz_to_std(task->per_cpu_utime[cpu_logical_map(i)]),
++ hz_to_std(task->per_cpu_stime[cpu_logical_map(i)]));
+
+ return len;
+ }
+diff -Nur linux-2.4.32-rc1/fs/proc/proc_misc.c linux-2.4.32-rc1.mips/fs/proc/proc_misc.c
+--- linux-2.4.32-rc1/fs/proc/proc_misc.c 2004-08-08 01:26:06.000000000 +0200
++++ linux-2.4.32-rc1.mips/fs/proc/proc_misc.c 2004-08-14 20:39:01.000000000 +0200
+@@ -308,16 +308,16 @@
+ {
+ int i, len = 0;
+ extern unsigned long total_forks;
+- unsigned long jif = jiffies;
++ unsigned long jif = hz_to_std(jiffies);
+ unsigned int sum = 0, user = 0, nice = 0, system = 0;
+ int major, disk;
+
+ for (i = 0 ; i < smp_num_cpus; i++) {
+ int cpu = cpu_logical_map(i), j;
+
+- user += kstat.per_cpu_user[cpu];
+- nice += kstat.per_cpu_nice[cpu];
+- system += kstat.per_cpu_system[cpu];
++ user += hz_to_std(kstat.per_cpu_user[cpu]);
++ nice += hz_to_std(kstat.per_cpu_nice[cpu]);
++ system += hz_to_std(kstat.per_cpu_system[cpu]);
+ #if !defined(CONFIG_ARCH_S390)
+ for (j = 0 ; j < NR_IRQS ; j++)
+ sum += kstat.irqs[cpu][j];
+@@ -331,10 +331,10 @@
+ proc_sprintf(page, &off, &len,
+ "cpu%d %u %u %u %lu\n",
+ i,
+- kstat.per_cpu_user[cpu_logical_map(i)],
+- kstat.per_cpu_nice[cpu_logical_map(i)],
+- kstat.per_cpu_system[cpu_logical_map(i)],
+- jif - ( kstat.per_cpu_user[cpu_logical_map(i)] \
++ hz_to_std(kstat.per_cpu_user[cpu_logical_map(i)]),
++ hz_to_std(kstat.per_cpu_nice[cpu_logical_map(i)]),
++ hz_to_std(kstat.per_cpu_system[cpu_logical_map(i)]),
++ jif - hz_to_std( kstat.per_cpu_user[cpu_logical_map(i)] \
+ + kstat.per_cpu_nice[cpu_logical_map(i)] \
+ + kstat.per_cpu_system[cpu_logical_map(i)]));
+ proc_sprintf(page, &off, &len,
+diff -Nur linux-2.4.32-rc1/include/asm-alpha/param.h linux-2.4.32-rc1.mips/include/asm-alpha/param.h
+--- linux-2.4.32-rc1/include/asm-alpha/param.h 2000-11-08 08:37:31.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-alpha/param.h 2000-11-28 04:59:03.000000000 +0100
+@@ -13,6 +13,9 @@
+ # else
+ # define HZ 1200
+ # endif
++#ifdef __KERNEL__
++# define hz_to_std(a) (a)
++#endif
+ #endif
+
+ #define EXEC_PAGESIZE 8192
+diff -Nur linux-2.4.32-rc1/include/asm-i386/param.h linux-2.4.32-rc1.mips/include/asm-i386/param.h
+--- linux-2.4.32-rc1/include/asm-i386/param.h 2000-10-27 20:04:43.000000000 +0200
++++ linux-2.4.32-rc1.mips/include/asm-i386/param.h 2000-11-23 03:00:55.000000000 +0100
+@@ -3,6 +3,9 @@
+
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
+ #endif
+
+ #define EXEC_PAGESIZE 4096
+diff -Nur linux-2.4.32-rc1/include/asm-ia64/param.h linux-2.4.32-rc1.mips/include/asm-ia64/param.h
+--- linux-2.4.32-rc1/include/asm-ia64/param.h 2004-04-14 15:05:40.000000000 +0200
++++ linux-2.4.32-rc1.mips/include/asm-ia64/param.h 2004-04-16 05:14:20.000000000 +0200
+@@ -7,9 +7,15 @@
+ * Based on <asm-i386/param.h>.
+ *
+ * Modified 1998, 1999, 2002-2003
+- * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
++ * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
+ */
+
++#include <linux/config.h>
++
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
++
+ #define EXEC_PAGESIZE 65536
+
+ #ifndef NGROUPS
+diff -Nur linux-2.4.32-rc1/include/asm-m68k/param.h linux-2.4.32-rc1.mips/include/asm-m68k/param.h
+--- linux-2.4.32-rc1/include/asm-m68k/param.h 2001-01-04 22:00:55.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-m68k/param.h 2001-01-11 05:02:45.000000000 +0100
+@@ -3,6 +3,9 @@
+
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
+ #endif
+
+ #define EXEC_PAGESIZE 8192
+diff -Nur linux-2.4.32-rc1/include/asm-mips/au1000_gpio.h linux-2.4.32-rc1.mips/include/asm-mips/au1000_gpio.h
+--- linux-2.4.32-rc1/include/asm-mips/au1000_gpio.h 2002-11-29 00:53:15.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/au1000_gpio.h 2005-01-30 09:01:28.000000000 +0100
+@@ -30,6 +30,13 @@
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
++/*
++ * Revision history
++ * 01/31/02 0.01 Initial release. Steve Longerbeam, MontaVista
++ * 10/12/03 0.1 Added Au1100/Au1500, GPIO2, and bit operations. K.C. Nishio, AMD
++ * 08/05/04 0.11 Added Au1550 and Au1200. K.C. Nishio
++ */
++
+ #ifndef __AU1000_GPIO_H
+ #define __AU1000_GPIO_H
+
+@@ -44,13 +51,94 @@
+ #define AU1000GPIO_TRISTATE _IOW (AU1000GPIO_IOC_MAGIC, 4, int)
+ #define AU1000GPIO_AVAIL_MASK _IOR (AU1000GPIO_IOC_MAGIC, 5, int)
+
++// bit operations
++#define AU1000GPIO_BIT_READ _IOW (AU1000GPIO_IOC_MAGIC, 6, int)
++#define AU1000GPIO_BIT_SET _IOW (AU1000GPIO_IOC_MAGIC, 7, int)
++#define AU1000GPIO_BIT_CLEAR _IOW (AU1000GPIO_IOC_MAGIC, 8, int)
++#define AU1000GPIO_BIT_TRISTATE _IOW (AU1000GPIO_IOC_MAGIC, 9, int)
++#define AU1000GPIO_BIT_INIT _IOW (AU1000GPIO_IOC_MAGIC, 10, int)
++#define AU1000GPIO_BIT_TERM _IOW (AU1000GPIO_IOC_MAGIC, 11, int)
++
++/* set this major numer same as the CRIS GPIO driver */
++#define AU1X00_GPIO_MAJOR (120)
++
++#define ENABLED_ZERO (0)
++#define ENABLED_ONE (1)
++#define ENABLED_10 (0x2)
++#define ENABLED_11 (0x3)
++#define ENABLED_111 (0x7)
++#define NOT_AVAIL (-1)
++#define AU1X00_MAX_PRIMARY_GPIO (32)
++
++#define AU1000_GPIO_MINOR_MAX AU1X00_MAX_PRIMARY_GPIO
++/* Au1100, 1500, 1550 and 1200 have the secondary GPIO block */
++#define AU1XX0_GPIO_MINOR_MAX (48)
++
++#define AU1X00_GPIO_NAME "gpio"
++
++/* GPIO pins which are not multiplexed */
++#if defined(CONFIG_SOC_AU1000)
++ #define NATIVE_GPIOPIN ((1 << 15) | (1 << 8) | (1 << 7) | (1 << 1) | (1 << 0))
++ #define NATIVE_GPIO2PIN (0)
++#elif defined(CONFIG_SOC_AU1100)
++ #define NATIVE_GPIOPIN ((1 << 23) | (1 << 22) | (1 << 21) | (1 << 20) | (1 << 19) | (1 << 18) | \
++ (1 << 17) | (1 << 16) | (1 << 7) | (1 << 1) | (1 << 0))
++ #define NATIVE_GPIO2PIN (0)
++#elif defined(CONFIG_SOC_AU1500)
++ #define NATIVE_GPIOPIN ((1 << 15) | (1 << 8) | (1 << 7) | (1 << 1) | (1 << 0))
++ /* exclude the PCI reset output signal: GPIO[200], DMA_REQ2 and DMA_REQ3 */
++ #define NATIVE_GPIO2PIN (0xfffe & ~((1 << 9) | (1 << 8)))
++#elif defined(CONFIG_SOC_AU1550)
++ #define NATIVE_GPIOPIN ((1 << 15) | (1 << 8) | (1 << 7) | (1 << 6) | (1 << 1) | (1 << 0))
++ /* please refere Au1550 Data Book, chapter 15 */
++ #define NATIVE_GPIO2PIN (1 << 5)
++#elif defined(CONFIG_SOC_AU1200)
++ #define NATIVE_GPIOPIN ((1 << 7) | (1 << 5))
++ #define NATIVE_GPIO2PIN (0)
++#endif
++
++/* minor as u32 */
++#define MINOR_TO_GPIOPIN(minor) ((minor < AU1X00_MAX_PRIMARY_GPIO) ? minor : (minor - AU1X00_MAX_PRIMARY_GPIO))
++#define IS_PRIMARY_GPIOPIN(minor) ((minor < AU1X00_MAX_PRIMARY_GPIO) ? 1 : 0)
++
++/*
++ * pin to minor mapping.
++ * GPIO0-GPIO31, minor=0-31.
++ * GPIO200-GPIO215, minor=32-47.
++ */
++typedef struct _au1x00_gpio_bit_ctl {
++ int direction; // The direction of this GPIO pin. 0: IN, 1: OUT.
++ int data; // Pin output when itized (0/1), or at the term. 0/1/-1 (tristate).
++} au1x00_gpio_bit_ctl;
++
++typedef struct _au1x00_gpio_driver {
++ const char *driver_name;
++ const char *name;
++ int name_base; /* offset of printed name */
++ short major; /* major device number */
++ short minor_start; /* start of minor device number*/
++ short num; /* number of devices */
++} au1x00_gpio_driver;
++
+ #ifdef __KERNEL__
+-extern u32 get_au1000_avail_gpio_mask(void);
+-extern int au1000gpio_tristate(u32 data);
+-extern int au1000gpio_in(u32 *data);
+-extern int au1000gpio_set(u32 data);
+-extern int au1000gpio_clear(u32 data);
+-extern int au1000gpio_out(u32 data);
++extern u32 get_au1000_avail_gpio_mask(u32 *avail_gpio2);
++extern int au1000gpio_tristate(u32 minor, u32 data);
++extern int au1000gpio_in(u32 minor, u32 *data);
++extern int au1000gpio_set(u32 minor, u32 data);
++extern int au1000gpio_clear(u32 minor, u32 data);
++extern int au1000gpio_out(u32 minor, u32 data);
++extern int au1000gpio_bit_read(u32 minor, u32 *read_data);
++extern int au1000gpio_bit_set(u32 minor);
++extern int au1000gpio_bit_clear(u32 minor);
++extern int au1000gpio_bit_tristate(u32 minor);
++extern int check_minor_to_gpio(u32 minor);
++extern int au1000gpio_bit_init(u32 minor, au1x00_gpio_bit_ctl *bit_opt);
++extern int au1000gpio_bit_term(u32 minor, au1x00_gpio_bit_ctl *bit_opt);
++
++extern void gpio_register_devfs (au1x00_gpio_driver *driver, unsigned int flags, unsigned minor);
++extern void gpio_unregister_devfs (au1x00_gpio_driver *driver, unsigned minor);
++extern int gpio_register_driver(au1x00_gpio_driver *driver);
++extern int gpio_unregister_driver(au1x00_gpio_driver *driver);
+ #endif
+
+ #endif
+diff -Nur linux-2.4.32-rc1/include/asm-mips/au1000.h linux-2.4.32-rc1.mips/include/asm-mips/au1000.h
+--- linux-2.4.32-rc1/include/asm-mips/au1000.h 2005-01-19 15:10:11.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/au1000.h 2005-01-30 09:01:28.000000000 +0100
+@@ -160,28 +160,356 @@
+ #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
+ #endif
+
+-/* SDRAM Controller */
++/*
++ * SDRAM Register Offsets
++ */
+ #if defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1100)
+-#define MEM_SDMODE0 0xB4000000
+-#define MEM_SDMODE1 0xB4000004
+-#define MEM_SDMODE2 0xB4000008
+-
+-#define MEM_SDADDR0 0xB400000C
+-#define MEM_SDADDR1 0xB4000010
+-#define MEM_SDADDR2 0xB4000014
+-
+-#define MEM_SDREFCFG 0xB4000018
+-#define MEM_SDPRECMD 0xB400001C
+-#define MEM_SDAUTOREF 0xB4000020
+-
+-#define MEM_SDWRMD0 0xB4000024
+-#define MEM_SDWRMD1 0xB4000028
+-#define MEM_SDWRMD2 0xB400002C
++#define MEM_SDMODE0 (0x0000)
++#define MEM_SDMODE1 (0x0004)
++#define MEM_SDMODE2 (0x0008)
++#define MEM_SDADDR0 (0x000C)
++#define MEM_SDADDR1 (0x0010)
++#define MEM_SDADDR2 (0x0014)
++#define MEM_SDREFCFG (0x0018)
++#define MEM_SDPRECMD (0x001C)
++#define MEM_SDAUTOREF (0x0020)
++#define MEM_SDWRMD0 (0x0024)
++#define MEM_SDWRMD1 (0x0028)
++#define MEM_SDWRMD2 (0x002C)
++#define MEM_SDSLEEP (0x0030)
++#define MEM_SDSMCKE (0x0034)
++
++#ifndef ASSEMBLER
++/*typedef volatile struct
++{
++ uint32 sdmode0;
++ uint32 sdmode1;
++ uint32 sdmode2;
++ uint32 sdaddr0;
++ uint32 sdaddr1;
++ uint32 sdaddr2;
++ uint32 sdrefcfg;
++ uint32 sdautoref;
++ uint32 sdwrmd0;
++ uint32 sdwrmd1;
++ uint32 sdwrmd2;
++ uint32 sdsleep;
++ uint32 sdsmcke;
++
++} AU1X00_SDRAM;*/
++#endif
++
++/*
++ * MEM_SDMODE register content definitions
++ */
++#define MEM_SDMODE_F (1<<22)
++#define MEM_SDMODE_SR (1<<21)
++#define MEM_SDMODE_BS (1<<20)
++#define MEM_SDMODE_RS (3<<18)
++#define MEM_SDMODE_CS (7<<15)
++#define MEM_SDMODE_TRAS (15<<11)
++#define MEM_SDMODE_TMRD (3<<9)
++#define MEM_SDMODE_TWR (3<<7)
++#define MEM_SDMODE_TRP (3<<5)
++#define MEM_SDMODE_TRCD (3<<3)
++#define MEM_SDMODE_TCL (7<<0)
++
++#define MEM_SDMODE_BS_2Bank (0<<20)
++#define MEM_SDMODE_BS_4Bank (1<<20)
++#define MEM_SDMODE_RS_11Row (0<<18)
++#define MEM_SDMODE_RS_12Row (1<<18)
++#define MEM_SDMODE_RS_13Row (2<<18)
++#define MEM_SDMODE_RS_N(N) ((N)<<18)
++#define MEM_SDMODE_CS_7Col (0<<15)
++#define MEM_SDMODE_CS_8Col (1<<15)
++#define MEM_SDMODE_CS_9Col (2<<15)
++#define MEM_SDMODE_CS_10Col (3<<15)
++#define MEM_SDMODE_CS_11Col (4<<15)
++#define MEM_SDMODE_CS_N(N) ((N)<<15)
++#define MEM_SDMODE_TRAS_N(N) ((N)<<11)
++#define MEM_SDMODE_TMRD_N(N) ((N)<<9)
++#define MEM_SDMODE_TWR_N(N) ((N)<<7)
++#define MEM_SDMODE_TRP_N(N) ((N)<<5)
++#define MEM_SDMODE_TRCD_N(N) ((N)<<3)
++#define MEM_SDMODE_TCL_N(N) ((N)<<0)
++
++/*
++ * MEM_SDADDR register contents definitions
++ */
++#define MEM_SDADDR_E (1<<20)
++#define MEM_SDADDR_CSBA (0x03FF<<10)
++#define MEM_SDADDR_CSMASK (0x03FF<<0)
++#define MEM_SDADDR_CSBA_N(N) ((N)&(0x03FF<<22)>>12)
++#define MEM_SDADDR_CSMASK_N(N) ((N)&(0x03FF<<22)>>22)
++
++/*
++ * MEM_SDREFCFG register content definitions
++ */
++#define MEM_SDREFCFG_TRC (15<<28)
++#define MEM_SDREFCFG_TRPM (3<<26)
++#define MEM_SDREFCFG_E (1<<25)
++#define MEM_SDREFCFG_RE (0x1ffffff<<0)
++#define MEM_SDREFCFG_TRC_N(N) ((N)<<MEM_SDREFCFG_TRC)
++#define MEM_SDREFCFG_TRPM_N(N) ((N)<<MEM_SDREFCFG_TRPM)
++#define MEM_SDREFCFG_REF_N(N) (N)
++#endif
++
++/***********************************************************************/
++
++/*
++ * Au1550 SDRAM Register Offsets
++ */
++
++/***********************************************************************/
++
++#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
++#define MEM_SDMODE0 (0x0800)
++#define MEM_SDMODE1 (0x0808)
++#define MEM_SDMODE2 (0x0810)
++#define MEM_SDADDR0 (0x0820)
++#define MEM_SDADDR1 (0x0828)
++#define MEM_SDADDR2 (0x0830)
++#define MEM_SDCONFIGA (0x0840)
++#define MEM_SDCONFIGB (0x0848)
++#define MEM_SDSTAT (0x0850)
++#define MEM_SDERRADDR (0x0858)
++#define MEM_SDSTRIDE0 (0x0860)
++#define MEM_SDSTRIDE1 (0x0868)
++#define MEM_SDSTRIDE2 (0x0870)
++#define MEM_SDWRMD0 (0x0880)
++#define MEM_SDWRMD1 (0x0888)
++#define MEM_SDWRMD2 (0x0890)
++#define MEM_SDPRECMD (0x08C0)
++#define MEM_SDAUTOREF (0x08C8)
++#define MEM_SDSREF (0x08D0)
++#define MEM_SDSLEEP MEM_SDSREF
++
++#ifndef ASSEMBLER
++/*typedef volatile struct
++{
++ uint32 sdmode0;
++ uint32 reserved0;
++ uint32 sdmode1;
++ uint32 reserved1;
++ uint32 sdmode2;
++ uint32 reserved2[3];
++ uint32 sdaddr0;
++ uint32 reserved3;
++ uint32 sdaddr1;
++ uint32 reserved4;
++ uint32 sdaddr2;
++ uint32 reserved5[3];
++ uint32 sdconfiga;
++ uint32 reserved6;
++ uint32 sdconfigb;
++ uint32 reserved7;
++ uint32 sdstat;
++ uint32 reserved8;
++ uint32 sderraddr;
++ uint32 reserved9;
++ uint32 sdstride0;
++ uint32 reserved10;
++ uint32 sdstride1;
++ uint32 reserved11;
++ uint32 sdstride2;
++ uint32 reserved12[3];
++ uint32 sdwrmd0;
++ uint32 reserved13;
++ uint32 sdwrmd1;
++ uint32 reserved14;
++ uint32 sdwrmd2;
++ uint32 reserved15[11];
++ uint32 sdprecmd;
++ uint32 reserved16;
++ uint32 sdautoref;
++ uint32 reserved17;
++ uint32 sdsref;
++
++} AU1550_SDRAM;*/
++#endif
++#endif
++
++/*
++ * Physical base addresses for integrated peripherals
++ */
++
++#ifdef CONFIG_SOC_AU1000
++#define MEM_PHYS_ADDR 0x14000000
++#define STATIC_MEM_PHYS_ADDR 0x14001000
++#define DMA0_PHYS_ADDR 0x14002000
++#define DMA1_PHYS_ADDR 0x14002100
++#define DMA2_PHYS_ADDR 0x14002200
++#define DMA3_PHYS_ADDR 0x14002300
++#define DMA4_PHYS_ADDR 0x14002400
++#define DMA5_PHYS_ADDR 0x14002500
++#define DMA6_PHYS_ADDR 0x14002600
++#define DMA7_PHYS_ADDR 0x14002700
++#define IC0_PHYS_ADDR 0x10400000
++#define IC1_PHYS_ADDR 0x11800000
++#define AC97_PHYS_ADDR 0x10000000
++#define USBH_PHYS_ADDR 0x10100000
++#define USBD_PHYS_ADDR 0x10200000
++#define IRDA_PHYS_ADDR 0x10300000
++#define MAC0_PHYS_ADDR 0x10500000
++#define MAC1_PHYS_ADDR 0x10510000
++#define MACEN_PHYS_ADDR 0x10520000
++#define MACDMA0_PHYS_ADDR 0x14004000
++#define MACDMA1_PHYS_ADDR 0x14004200
++#define I2S_PHYS_ADDR 0x11000000
++#define UART0_PHYS_ADDR 0x11100000
++#define UART1_PHYS_ADDR 0x11200000
++#define UART2_PHYS_ADDR 0x11300000
++#define UART3_PHYS_ADDR 0x11400000
++#define SSI0_PHYS_ADDR 0x11600000
++#define SSI1_PHYS_ADDR 0x11680000
++#define SYS_PHYS_ADDR 0x11900000
++#define PCMCIA_IO_PHYS_ADDR 0xF00000000
++#define PCMCIA_ATTR_PHYS_ADDR 0xF40000000
++#define PCMCIA_MEM_PHYS_ADDR 0xF80000000
++#endif
++
++/********************************************************************/
+
+-#define MEM_SDSLEEP 0xB4000030
+-#define MEM_SDSMCKE 0xB4000034
++#ifdef CONFIG_SOC_AU1500
++#define MEM_PHYS_ADDR 0x14000000
++#define STATIC_MEM_PHYS_ADDR 0x14001000
++#define DMA0_PHYS_ADDR 0x14002000
++#define DMA1_PHYS_ADDR 0x14002100
++#define DMA2_PHYS_ADDR 0x14002200
++#define DMA3_PHYS_ADDR 0x14002300
++#define DMA4_PHYS_ADDR 0x14002400
++#define DMA5_PHYS_ADDR 0x14002500
++#define DMA6_PHYS_ADDR 0x14002600
++#define DMA7_PHYS_ADDR 0x14002700
++#define IC0_PHYS_ADDR 0x10400000
++#define IC1_PHYS_ADDR 0x11800000
++#define AC97_PHYS_ADDR 0x10000000
++#define USBH_PHYS_ADDR 0x10100000
++#define USBD_PHYS_ADDR 0x10200000
++#define PCI_PHYS_ADDR 0x14005000
++#define MAC0_PHYS_ADDR 0x11500000
++#define MAC1_PHYS_ADDR 0x11510000
++#define MACEN_PHYS_ADDR 0x11520000
++#define MACDMA0_PHYS_ADDR 0x14004000
++#define MACDMA1_PHYS_ADDR 0x14004200
++#define I2S_PHYS_ADDR 0x11000000
++#define UART0_PHYS_ADDR 0x11100000
++#define UART3_PHYS_ADDR 0x11400000
++#define GPIO2_PHYS_ADDR 0x11700000
++#define SYS_PHYS_ADDR 0x11900000
++#define PCI_MEM_PHYS_ADDR 0x400000000
++#define PCI_IO_PHYS_ADDR 0x500000000
++#define PCI_CONFIG0_PHYS_ADDR 0x600000000
++#define PCI_CONFIG1_PHYS_ADDR 0x680000000
++#define PCMCIA_IO_PHYS_ADDR 0xF00000000
++#define PCMCIA_ATTR_PHYS_ADDR 0xF40000000
++#define PCMCIA_MEM_PHYS_ADDR 0xF80000000
+ #endif
+
++/********************************************************************/
++
++#ifdef CONFIG_SOC_AU1100
++#define MEM_PHYS_ADDR 0x14000000
++#define STATIC_MEM_PHYS_ADDR 0x14001000
++#define DMA0_PHYS_ADDR 0x14002000
++#define DMA1_PHYS_ADDR 0x14002100
++#define DMA2_PHYS_ADDR 0x14002200
++#define DMA3_PHYS_ADDR 0x14002300
++#define DMA4_PHYS_ADDR 0x14002400
++#define DMA5_PHYS_ADDR 0x14002500
++#define DMA6_PHYS_ADDR 0x14002600
++#define DMA7_PHYS_ADDR 0x14002700
++#define IC0_PHYS_ADDR 0x10400000
++#define SD0_PHYS_ADDR 0x10600000
++#define SD1_PHYS_ADDR 0x10680000
++#define IC1_PHYS_ADDR 0x11800000
++#define AC97_PHYS_ADDR 0x10000000
++#define USBH_PHYS_ADDR 0x10100000
++#define USBD_PHYS_ADDR 0x10200000
++#define IRDA_PHYS_ADDR 0x10300000
++#define MAC0_PHYS_ADDR 0x10500000
++#define MACEN_PHYS_ADDR 0x10520000
++#define MACDMA0_PHYS_ADDR 0x14004000
++#define MACDMA1_PHYS_ADDR 0x14004200
++#define I2S_PHYS_ADDR 0x11000000
++#define UART0_PHYS_ADDR 0x11100000
++#define UART1_PHYS_ADDR 0x11200000
++#define UART3_PHYS_ADDR 0x11400000
++#define SSI0_PHYS_ADDR 0x11600000
++#define SSI1_PHYS_ADDR 0x11680000
++#define GPIO2_PHYS_ADDR 0x11700000
++#define SYS_PHYS_ADDR 0x11900000
++#define LCD_PHYS_ADDR 0x15000000
++#define PCMCIA_IO_PHYS_ADDR 0xF00000000
++#define PCMCIA_ATTR_PHYS_ADDR 0xF40000000
++#define PCMCIA_MEM_PHYS_ADDR 0xF80000000
++#endif
++
++/***********************************************************************/
++
++#ifdef CONFIG_SOC_AU1550
++#define MEM_PHYS_ADDR 0x14000000
++#define STATIC_MEM_PHYS_ADDR 0x14001000
++#define IC0_PHYS_ADDR 0x10400000
++#define IC1_PHYS_ADDR 0x11800000
++#define USBH_PHYS_ADDR 0x14020000
++#define USBD_PHYS_ADDR 0x10200000
++#define PCI_PHYS_ADDR 0x14005000
++#define MAC0_PHYS_ADDR 0x10500000
++#define MAC1_PHYS_ADDR 0x10510000
++#define MACEN_PHYS_ADDR 0x10520000
++#define MACDMA0_PHYS_ADDR 0x14004000
++#define MACDMA1_PHYS_ADDR 0x14004200
++#define UART0_PHYS_ADDR 0x11100000
++#define UART1_PHYS_ADDR 0x11200000
++#define UART3_PHYS_ADDR 0x11400000
++#define GPIO2_PHYS_ADDR 0x11700000
++#define SYS_PHYS_ADDR 0x11900000
++#define DDMA_PHYS_ADDR 0x14002000
++#define PE_PHYS_ADDR 0x14008000
++#define PSC0_PHYS_ADDR 0x11A00000
++#define PSC1_PHYS_ADDR 0x11B00000
++#define PSC2_PHYS_ADDR 0x10A00000
++#define PSC3_PHYS_ADDR 0x10B00000
++#define PCI_MEM_PHYS_ADDR 0x400000000
++#define PCI_IO_PHYS_ADDR 0x500000000
++#define PCI_CONFIG0_PHYS_ADDR 0x600000000
++#define PCI_CONFIG1_PHYS_ADDR 0x680000000
++#define PCMCIA_IO_PHYS_ADDR 0xF00000000
++#define PCMCIA_ATTR_PHYS_ADDR 0xF40000000
++#define PCMCIA_MEM_PHYS_ADDR 0xF80000000
++#endif
++
++/***********************************************************************/
++
++#ifdef CONFIG_SOC_AU1200
++#define MEM_PHYS_ADDR 0x14000000
++#define STATIC_MEM_PHYS_ADDR 0x14001000
++#define AES_PHYS_ADDR 0x10300000
++#define CIM_PHYS_ADDR 0x14004000
++#define IC0_PHYS_ADDR 0x10400000
++#define IC1_PHYS_ADDR 0x11800000
++#define USBM_PHYS_ADDR 0x14020000
++#define USBH_PHYS_ADDR 0x14020100
++#define UART0_PHYS_ADDR 0x11100000
++#define UART1_PHYS_ADDR 0x11200000
++#define GPIO2_PHYS_ADDR 0x11700000
++#define SYS_PHYS_ADDR 0x11900000
++#define DDMA_PHYS_ADDR 0x14002000
++#define PSC0_PHYS_ADDR 0x11A00000
++#define PSC1_PHYS_ADDR 0x11B00000
++#define PCMCIA_IO_PHYS_ADDR 0xF00000000
++#define PCMCIA_ATTR_PHYS_ADDR 0xF40000000
++#define PCMCIA_MEM_PHYS_ADDR 0xF80000000
++#define SD0_PHYS_ADDR 0x10600000
++#define SD1_PHYS_ADDR 0x10680000
++#define LCD_PHYS_ADDR 0x15000000
++#define SWCNT_PHYS_ADDR 0x1110010C
++#define MAEFE_PHYS_ADDR 0x14012000
++#define MAEBE_PHYS_ADDR 0x14010000
++#endif
++
++
+ /* Static Bus Controller */
+ #define MEM_STCFG0 0xB4001000
+ #define MEM_STTIME0 0xB4001004
+@@ -367,7 +695,7 @@
+ #define AU1000_MAC0_ENABLE 0xB0520000
+ #define AU1000_MAC1_ENABLE 0xB0520004
+ #define NUM_ETH_INTERFACES 2
+-#endif // CONFIG_SOC_AU1000
++#endif /* CONFIG_SOC_AU1000 */
+
+ /* Au1500 */
+ #ifdef CONFIG_SOC_AU1500
+@@ -438,7 +766,7 @@
+ #define AU1500_MAC0_ENABLE 0xB1520000
+ #define AU1500_MAC1_ENABLE 0xB1520004
+ #define NUM_ETH_INTERFACES 2
+-#endif // CONFIG_SOC_AU1500
++#endif /* CONFIG_SOC_AU1500 */
+
+ /* Au1100 */
+ #ifdef CONFIG_SOC_AU1100
+@@ -483,6 +811,22 @@
+ #define AU1000_GPIO_13 45
+ #define AU1000_GPIO_14 46
+ #define AU1000_GPIO_15 47
++#define AU1000_GPIO_16 48
++#define AU1000_GPIO_17 49
++#define AU1000_GPIO_18 50
++#define AU1000_GPIO_19 51
++#define AU1000_GPIO_20 52
++#define AU1000_GPIO_21 53
++#define AU1000_GPIO_22 54
++#define AU1000_GPIO_23 55
++#define AU1000_GPIO_24 56
++#define AU1000_GPIO_25 57
++#define AU1000_GPIO_26 58
++#define AU1000_GPIO_27 59
++#define AU1000_GPIO_28 60
++#define AU1000_GPIO_29 61
++#define AU1000_GPIO_30 62
++#define AU1000_GPIO_31 63
+
+ #define UART0_ADDR 0xB1100000
+ #define UART1_ADDR 0xB1200000
+@@ -494,7 +838,7 @@
+ #define AU1100_ETH0_BASE 0xB0500000
+ #define AU1100_MAC0_ENABLE 0xB0520000
+ #define NUM_ETH_INTERFACES 1
+-#endif // CONFIG_SOC_AU1100
++#endif /* CONFIG_SOC_AU1100 */
+
+ #ifdef CONFIG_SOC_AU1550
+ #define AU1550_UART0_INT 0
+@@ -511,14 +855,14 @@
+ #define AU1550_PSC1_INT 11
+ #define AU1550_PSC2_INT 12
+ #define AU1550_PSC3_INT 13
+-#define AU1550_TOY_INT 14
+-#define AU1550_TOY_MATCH0_INT 15
+-#define AU1550_TOY_MATCH1_INT 16
+-#define AU1550_TOY_MATCH2_INT 17
+-#define AU1550_RTC_INT 18
+-#define AU1550_RTC_MATCH0_INT 19
+-#define AU1550_RTC_MATCH1_INT 20
+-#define AU1550_RTC_MATCH2_INT 21
++#define AU1000_TOY_INT 14
++#define AU1000_TOY_MATCH0_INT 15
++#define AU1000_TOY_MATCH1_INT 16
++#define AU1000_TOY_MATCH2_INT 17
++#define AU1000_RTC_INT 18
++#define AU1000_RTC_MATCH0_INT 19
++#define AU1000_RTC_MATCH1_INT 20
++#define AU1000_RTC_MATCH2_INT 21
+ #define AU1550_NAND_INT 23
+ #define AU1550_USB_DEV_REQ_INT 24
+ #define AU1550_USB_DEV_SUS_INT 25
+@@ -573,7 +917,7 @@
+ #define AU1550_MAC0_ENABLE 0xB0520000
+ #define AU1550_MAC1_ENABLE 0xB0520004
+ #define NUM_ETH_INTERFACES 2
+-#endif // CONFIG_SOC_AU1550
++#endif /* CONFIG_SOC_AU1550 */
+
+ #ifdef CONFIG_SOC_AU1200
+ #define AU1200_UART0_INT 0
+@@ -590,14 +934,14 @@
+ #define AU1200_PSC1_INT 11
+ #define AU1200_AES_INT 12
+ #define AU1200_CAMERA_INT 13
+-#define AU1200_TOY_INT 14
+-#define AU1200_TOY_MATCH0_INT 15
+-#define AU1200_TOY_MATCH1_INT 16
+-#define AU1200_TOY_MATCH2_INT 17
+-#define AU1200_RTC_INT 18
+-#define AU1200_RTC_MATCH0_INT 19
+-#define AU1200_RTC_MATCH1_INT 20
+-#define AU1200_RTC_MATCH2_INT 21
++#define AU1000_TOY_INT 14
++#define AU1000_TOY_MATCH0_INT 15
++#define AU1000_TOY_MATCH1_INT 16
++#define AU1000_TOY_MATCH2_INT 17
++#define AU1000_RTC_INT 18
++#define AU1000_RTC_MATCH0_INT 19
++#define AU1000_RTC_MATCH1_INT 20
++#define AU1000_RTC_MATCH2_INT 21
+ #define AU1200_NAND_INT 23
+ #define AU1200_GPIO_204 24
+ #define AU1200_GPIO_205 25
+@@ -605,6 +949,7 @@
+ #define AU1200_GPIO_207 27
+ #define AU1200_GPIO_208_215 28 // Logical OR of 208:215
+ #define AU1200_USB_INT 29
++#define AU1000_USB_HOST_INT AU1200_USB_INT
+ #define AU1200_LCD_INT 30
+ #define AU1200_MAE_BOTH_INT 31
+ #define AU1000_GPIO_0 32
+@@ -643,21 +988,36 @@
+ #define UART0_ADDR 0xB1100000
+ #define UART1_ADDR 0xB1200000
+
+-#define USB_OHCI_BASE 0x14020000 // phys addr for ioremap
+-#define USB_HOST_CONFIG 0xB4027ffc
++#define USB_UOC_BASE 0x14020020
++#define USB_UOC_LEN 0x20
++#define USB_OHCI_BASE 0x14020100
++#define USB_OHCI_LEN 0x100
++#define USB_EHCI_BASE 0x14020200
++#define USB_EHCI_LEN 0x100
++#define USB_UDC_BASE 0x14022000
++#define USB_UDC_LEN 0x2000
++#define USB_MSR_BASE 0xB4020000
++#define USB_MSR_MCFG 4
++#define USBMSRMCFG_OMEMEN 0
++#define USBMSRMCFG_OBMEN 1
++#define USBMSRMCFG_EMEMEN 2
++#define USBMSRMCFG_EBMEN 3
++#define USBMSRMCFG_DMEMEN 4
++#define USBMSRMCFG_DBMEN 5
++#define USBMSRMCFG_GMEMEN 6
++#define USBMSRMCFG_OHCCLKEN 16
++#define USBMSRMCFG_EHCCLKEN 17
++#define USBMSRMCFG_UDCCLKEN 18
++#define USBMSRMCFG_PHYPLLEN 19
++#define USBMSRMCFG_RDCOMB 30
++#define USBMSRMCFG_PFEN 31
+
+-// these are here for prototyping on au1550 (do not exist on au1200)
+-#define AU1200_ETH0_BASE 0xB0500000
+-#define AU1200_ETH1_BASE 0xB0510000
+-#define AU1200_MAC0_ENABLE 0xB0520000
+-#define AU1200_MAC1_ENABLE 0xB0520004
+-#define NUM_ETH_INTERFACES 2
+-#endif // CONFIG_SOC_AU1200
++#endif /* CONFIG_SOC_AU1200 */
+
+ #define AU1000_LAST_INTC0_INT 31
++#define AU1000_LAST_INTC1_INT 63
+ #define AU1000_MAX_INTR 63
+
+-
+ /* Programmable Counters 0 and 1 */
+ #define SYS_BASE 0xB1900000
+ #define SYS_COUNTER_CNTRL (SYS_BASE + 0x14)
+@@ -728,6 +1088,8 @@
+ #define I2S_CONTROL_D (1<<1)
+ #define I2S_CONTROL_CE (1<<0)
+
++#ifndef CONFIG_SOC_AU1200
++
+ /* USB Host Controller */
+ #define USB_OHCI_LEN 0x00100000
+
+@@ -773,6 +1135,8 @@
+ #define USBDEV_ENABLE (1<<1)
+ #define USBDEV_CE (1<<0)
+
++#endif /* !CONFIG_SOC_AU1200 */
++
+ /* Ethernet Controllers */
+
+ /* 4 byte offsets from AU1000_ETH_BASE */
+@@ -1171,6 +1535,37 @@
+ #define SYS_PF_PSC1_S1 (1 << 1)
+ #define SYS_PF_MUST_BE_SET ((1 << 5) | (1 << 2))
+
++/* Au1200 Only */
++#ifdef CONFIG_SOC_AU1200
++#define SYS_PINFUNC_DMA (1<<31)
++#define SYS_PINFUNC_S0A (1<<30)
++#define SYS_PINFUNC_S1A (1<<29)
++#define SYS_PINFUNC_LP0 (1<<28)
++#define SYS_PINFUNC_LP1 (1<<27)
++#define SYS_PINFUNC_LD16 (1<<26)
++#define SYS_PINFUNC_LD8 (1<<25)
++#define SYS_PINFUNC_LD1 (1<<24)
++#define SYS_PINFUNC_LD0 (1<<23)
++#define SYS_PINFUNC_P1A (3<<21)
++#define SYS_PINFUNC_P1B (1<<20)
++#define SYS_PINFUNC_FS3 (1<<19)
++#define SYS_PINFUNC_P0A (3<<17)
++#define SYS_PINFUNC_CS (1<<16)
++#define SYS_PINFUNC_CIM (1<<15)
++#define SYS_PINFUNC_P1C (1<<14)
++#define SYS_PINFUNC_U1T (1<<12)
++#define SYS_PINFUNC_U1R (1<<11)
++#define SYS_PINFUNC_EX1 (1<<10)
++#define SYS_PINFUNC_EX0 (1<<9)
++#define SYS_PINFUNC_U0R (1<<8)
++#define SYS_PINFUNC_MC (1<<7)
++#define SYS_PINFUNC_S0B (1<<6)
++#define SYS_PINFUNC_S0C (1<<5)
++#define SYS_PINFUNC_P0B (1<<4)
++#define SYS_PINFUNC_U0T (1<<3)
++#define SYS_PINFUNC_S1B (1<<2)
++#endif
++
+ #define SYS_TRIOUTRD 0xB1900100
+ #define SYS_TRIOUTCLR 0xB1900100
+ #define SYS_OUTPUTRD 0xB1900108
+@@ -1298,7 +1693,6 @@
+ #define SD1_XMIT_FIFO 0xB0680000
+ #define SD1_RECV_FIFO 0xB0680004
+
+-
+ #if defined (CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550)
+ /* Au1500 PCI Controller */
+ #define Au1500_CFG_BASE 0xB4005000 // virtual, kseg0 addr
+@@ -1388,9 +1782,60 @@
+
+ #endif
+
++#ifndef _LANGUAGE_ASSEMBLY
++typedef volatile struct
++{
++ /* 0x0000 */ u32 toytrim;
++ /* 0x0004 */ u32 toywrite;
++ /* 0x0008 */ u32 toymatch0;
++ /* 0x000C */ u32 toymatch1;
++ /* 0x0010 */ u32 toymatch2;
++ /* 0x0014 */ u32 cntrctrl;
++ /* 0x0018 */ u32 scratch0;
++ /* 0x001C */ u32 scratch1;
++ /* 0x0020 */ u32 freqctrl0;
++ /* 0x0024 */ u32 freqctrl1;
++ /* 0x0028 */ u32 clksrc;
++ /* 0x002C */ u32 pinfunc;
++ /* 0x0030 */ u32 reserved0;
++ /* 0x0034 */ u32 wakemsk;
++ /* 0x0038 */ u32 endian;
++ /* 0x003C */ u32 powerctrl;
++ /* 0x0040 */ u32 toyread;
++ /* 0x0044 */ u32 rtctrim;
++ /* 0x0048 */ u32 rtcwrite;
++ /* 0x004C */ u32 rtcmatch0;
++ /* 0x0050 */ u32 rtcmatch1;
++ /* 0x0054 */ u32 rtcmatch2;
++ /* 0x0058 */ u32 rtcread;
++ /* 0x005C */ u32 wakesrc;
++ /* 0x0060 */ u32 cpupll;
++ /* 0x0064 */ u32 auxpll;
++ /* 0x0068 */ u32 reserved1;
++ /* 0x006C */ u32 reserved2;
++ /* 0x0070 */ u32 reserved3;
++ /* 0x0074 */ u32 reserved4;
++ /* 0x0078 */ u32 slppwr;
++ /* 0x007C */ u32 sleep;
++ /* 0x0080 */ u32 reserved5[32];
++ /* 0x0100 */ u32 trioutrd;
++#define trioutclr trioutrd
++ /* 0x0104 */ u32 reserved6;
++ /* 0x0108 */ u32 outputrd;
++#define outputset outputrd
++ /* 0x010C */ u32 outputclr;
++ /* 0x0110 */ u32 pinstaterd;
++#define pininputen pinstaterd
++
++} AU1X00_SYS;
++
++static AU1X00_SYS* const sys = (AU1X00_SYS *)SYS_BASE;
++
++#endif
+ /* Processor information base on prid.
+ * Copied from PowerPC.
+ */
++#ifndef _LANGUAGE_ASSEMBLY
+ struct cpu_spec {
+ /* CPU is matched via (PRID & prid_mask) == prid_value */
+ unsigned int prid_mask;
+@@ -1404,3 +1849,6 @@
+ extern struct cpu_spec cpu_specs[];
+ extern struct cpu_spec *cur_cpu_spec[];
+ #endif
++
++#endif
++
+diff -Nur linux-2.4.32-rc1/include/asm-mips/au1000_pcmcia.h linux-2.4.32-rc1.mips/include/asm-mips/au1000_pcmcia.h
+--- linux-2.4.32-rc1/include/asm-mips/au1000_pcmcia.h 2005-01-19 15:10:11.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/au1000_pcmcia.h 2005-01-30 09:01:28.000000000 +0100
+@@ -38,16 +38,41 @@
+ #define AU1X_SOCK0_PHYS_MEM 0xF80000000
+
+ /* pcmcia socket 1 needs external glue logic so the memory map
+- * differs from board to board.
++ * differs from board to board. the general rule is that
++ * static bus address bit 26 should be used to decode socket 0
++ * from socket 1. alas, some boards dont follow this...
++ * These really belong in a board-specific header file...
+ */
+-#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500)
+-#define AU1X_SOCK1_IO 0xF08000000
+-#define AU1X_SOCK1_PHYS_ATTR 0xF48000000
+-#define AU1X_SOCK1_PHYS_MEM 0xF88000000
+-#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_PB1550) || defined(CONFIG_MIPS_DB1550)
+-#define AU1X_SOCK1_IO 0xF04000000
+-#define AU1X_SOCK1_PHYS_ATTR 0xF44000000
+-#define AU1X_SOCK1_PHYS_MEM 0xF84000000
++#ifdef CONFIG_MIPS_PB1000
++#define SOCK1_DECODE (1<<27)
++#endif
++#ifdef CONFIG_MIPS_DB1000
++#define SOCK1_DECODE (1<<26)
++#endif
++#ifdef CONFIG_MIPS_DB1500
++#define SOCK1_DECODE (1<<26)
++#endif
++#ifdef CONFIG_MIPS_DB1100
++#define SOCK1_DECODE (1<<26)
++#endif
++#ifdef CONFIG_MIPS_DB1550
++#define SOCK1_DECODE (1<<26)
++#endif
++#ifdef CONFIG_MIPS_DB1200
++#define SOCK1_DECODE (1<<26)
++#endif
++#ifdef CONFIG_MIPS_PB1550
++#define SOCK1_DECODE (1<<26)
++#endif
++#ifdef CONFIG_MIPS_PB1200
++#define SOCK1_DECODE (1<<26)
++#endif
++
++/* The board has a second PCMCIA socket */
++#ifdef SOCK1_DECODE
++#define AU1X_SOCK1_IO (0xF00000000|SOCK1_DECODE)
++#define AU1X_SOCK1_PHYS_ATTR (0xF40000000|SOCK1_DECODE)
++#define AU1X_SOCK1_PHYS_MEM (0xF80000000|SOCK1_DECODE)
+ #endif
+
+ struct pcmcia_state {
+diff -Nur linux-2.4.32-rc1/include/asm-mips/au1100_mmc.h linux-2.4.32-rc1.mips/include/asm-mips/au1100_mmc.h
+--- linux-2.4.32-rc1/include/asm-mips/au1100_mmc.h 2005-01-19 15:10:11.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/au1100_mmc.h 2005-01-30 09:01:28.000000000 +0100
+@@ -39,16 +39,22 @@
+ #define __ASM_AU1100_MMC_H
+
+
+-#define NUM_AU1100_MMC_CONTROLLERS 2
+-
+-
+-#define AU1100_SD_IRQ 2
+-
++#if defined(CONFIG_SOC_AU1100)
++#define NUM_MMC_CONTROLLERS 2
++#define AU1X_MMC_INT AU1100_SD_INT
++#endif
++
++#if defined(CONFIG_SOC_AU1200)
++#define NUM_MMC_CONTROLLERS 2
++#define AU1X_MMC_INT AU1200_SD_INT
++#endif
+
+ #define SD0_BASE 0xB0600000
+ #define SD1_BASE 0xB0680000
+
+
++
++
+ /*
+ * Register offsets.
+ */
+@@ -201,5 +207,12 @@
+ #define SD_CMD_RT_1B (0x00810000)
+
+
++/* support routines required on a platform-specific basis */
++extern void mmc_card_inserted(int _n_, int *_res_);
++extern void mmc_card_writable(int _n_, int *_res_);
++extern void mmc_power_on(int _n_);
++extern void mmc_power_off(int _n_);
++
++
+ #endif /* __ASM_AU1100_MMC_H */
+
+diff -Nur linux-2.4.32-rc1/include/asm-mips/au1xxx_dbdma.h linux-2.4.32-rc1.mips/include/asm-mips/au1xxx_dbdma.h
+--- linux-2.4.32-rc1/include/asm-mips/au1xxx_dbdma.h 2005-01-19 15:10:11.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/au1xxx_dbdma.h 2005-01-30 09:01:28.000000000 +0100
+@@ -43,7 +43,7 @@
+ #define DDMA_GLOBAL_BASE 0xb4003000
+ #define DDMA_CHANNEL_BASE 0xb4002000
+
+-typedef struct dbdma_global {
++typedef volatile struct dbdma_global {
+ u32 ddma_config;
+ u32 ddma_intstat;
+ u32 ddma_throttle;
+@@ -60,7 +60,7 @@
+
+ /* The structure of a DMA Channel.
+ */
+-typedef struct au1xxx_dma_channel {
++typedef volatile struct au1xxx_dma_channel {
+ u32 ddma_cfg; /* See below */
+ u32 ddma_desptr; /* 32-byte aligned pointer to descriptor */
+ u32 ddma_statptr; /* word aligned pointer to status word */
+@@ -96,7 +96,7 @@
+ /* "Standard" DDMA Descriptor.
+ * Must be 32-byte aligned.
+ */
+-typedef struct au1xxx_ddma_desc {
++typedef volatile struct au1xxx_ddma_desc {
+ u32 dscr_cmd0; /* See below */
+ u32 dscr_cmd1; /* See below */
+ u32 dscr_source0; /* source phys address */
+@@ -105,6 +105,12 @@
+ u32 dscr_dest1; /* See below */
+ u32 dscr_stat; /* completion status */
+ u32 dscr_nxtptr; /* Next descriptor pointer (mostly) */
++ /* First 32bytes are HW specific!!!
++ Lets have some SW data following.. make sure its 32bytes
++ */
++ u32 sw_status;
++ u32 sw_context;
++ u32 sw_reserved[6];
+ } au1x_ddma_desc_t;
+
+ #define DSCR_CMD0_V (1 << 31) /* Descriptor valid */
+@@ -123,6 +129,8 @@
+ #define DSCR_CMD0_CV (0x1 << 2) /* Clear Valid when done */
+ #define DSCR_CMD0_ST_MASK (0x3 << 0) /* Status instruction */
+
++#define SW_STATUS_INUSE (1<<0)
++
+ /* Command 0 device IDs.
+ */
+ #ifdef CONFIG_SOC_AU1550
+@@ -169,8 +177,8 @@
+ #define DSCR_CMD0_SDMS_RX0 9
+ #define DSCR_CMD0_SDMS_TX1 10
+ #define DSCR_CMD0_SDMS_RX1 11
+-#define DSCR_CMD0_AES_TX 12
+-#define DSCR_CMD0_AES_RX 13
++#define DSCR_CMD0_AES_TX 13
++#define DSCR_CMD0_AES_RX 12
+ #define DSCR_CMD0_PSC0_TX 14
+ #define DSCR_CMD0_PSC0_RX 15
+ #define DSCR_CMD0_PSC1_TX 16
+@@ -189,6 +197,10 @@
+ #define DSCR_CMD0_THROTTLE 30
+ #define DSCR_CMD0_ALWAYS 31
+ #define DSCR_NDEV_IDS 32
++/* THis macro is used to find/create custom device types */
++#define DSCR_DEV2CUSTOM_ID(x,d) (((((x)&0xFFFF)<<8)|0x32000000)|((d)&0xFF))
++#define DSCR_CUSTOM2DEV_ID(x) ((x)&0xFF)
++
+
+ #define DSCR_CMD0_SID(x) (((x) & 0x1f) << 25)
+ #define DSCR_CMD0_DID(x) (((x) & 0x1f) << 20)
+@@ -277,6 +289,43 @@
+ */
+ #define NUM_DBDMA_CHANS 16
+
++/*
++ * Ddma API definitions
++ * FIXME: may not fit to this header file
++ */
++typedef struct dbdma_device_table {
++ u32 dev_id;
++ u32 dev_flags;
++ u32 dev_tsize;
++ u32 dev_devwidth;
++ u32 dev_physaddr; /* If FIFO */
++ u32 dev_intlevel;
++ u32 dev_intpolarity;
++} dbdev_tab_t;
++
++
++typedef struct dbdma_chan_config {
++ spinlock_t lock;
++
++ u32 chan_flags;
++ u32 chan_index;
++ dbdev_tab_t *chan_src;
++ dbdev_tab_t *chan_dest;
++ au1x_dma_chan_t *chan_ptr;
++ au1x_ddma_desc_t *chan_desc_base;
++ au1x_ddma_desc_t *get_ptr, *put_ptr, *cur_ptr;
++ void *chan_callparam;
++ void (*chan_callback)(int, void *, struct pt_regs *);
++} chan_tab_t;
++
++#define DEV_FLAGS_INUSE (1 << 0)
++#define DEV_FLAGS_ANYUSE (1 << 1)
++#define DEV_FLAGS_OUT (1 << 2)
++#define DEV_FLAGS_IN (1 << 3)
++#define DEV_FLAGS_BURSTABLE (1 << 4)
++#define DEV_FLAGS_SYNC (1 << 5)
++/* end Ddma API definitions */
++
+ /* External functions for drivers to use.
+ */
+ /* Use this to allocate a dbdma channel. The device ids are one of the
+@@ -299,8 +348,8 @@
+
+ /* Put buffers on source/destination descriptors.
+ */
+-u32 au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes);
+-u32 au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes);
++u32 _au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags);
++u32 _au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags);
+
+ /* Get a buffer from the destination descriptor.
+ */
+@@ -314,5 +363,25 @@
+ void au1xxx_dbdma_chan_free(u32 chanid);
+ void au1xxx_dbdma_dump(u32 chanid);
+
++u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr );
++
++u32 au1xxx_ddma_add_device( dbdev_tab_t *dev );
++
++/*
++ Some compatibilty macros --
++ Needed to make changes to API without breaking existing drivers
++*/
++#define au1xxx_dbdma_put_source(chanid,buf,nbytes)_au1xxx_dbdma_put_source(chanid, buf, nbytes, DDMA_FLAGS_IE)
++#define au1xxx_dbdma_put_source_flags(chanid,buf,nbytes,flags) _au1xxx_dbdma_put_source(chanid, buf, nbytes, flags)
++
++#define au1xxx_dbdma_put_dest(chanid,buf,nbytes) _au1xxx_dbdma_put_dest(chanid, buf, nbytes, DDMA_FLAGS_IE)
++#define au1xxx_dbdma_put_dest_flags(chanid,buf,nbytes,flags) _au1xxx_dbdma_put_dest(chanid, buf, nbytes, flags)
++
++/*
++ * Flags for the put_source/put_dest functions.
++ */
++#define DDMA_FLAGS_IE (1<<0)
++#define DDMA_FLAGS_NOIE (1<<1)
++
+ #endif /* _LANGUAGE_ASSEMBLY */
+ #endif /* _AU1000_DBDMA_H_ */
+diff -Nur linux-2.4.32-rc1/include/asm-mips/au1xxx_gpio.h linux-2.4.32-rc1.mips/include/asm-mips/au1xxx_gpio.h
+--- linux-2.4.32-rc1/include/asm-mips/au1xxx_gpio.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/au1xxx_gpio.h 2005-01-30 09:01:28.000000000 +0100
+@@ -0,0 +1,22 @@
++
++
++#ifndef __AU1XXX_GPIO_H
++#define __AU1XXX_GPIO_H
++
++void au1xxx_gpio1_set_inputs(void);
++void au1xxx_gpio_tristate(int signal);
++void au1xxx_gpio_write(int signal, int value);
++int au1xxx_gpio_read(int signal);
++
++typedef volatile struct
++{
++ u32 dir;
++ u32 reserved;
++ u32 output;
++ u32 pinstate;
++ u32 inten;
++ u32 enable;
++
++} AU1X00_GPIO2;
++
++#endif //__AU1XXX_GPIO_H
+diff -Nur linux-2.4.32-rc1/include/asm-mips/au1xxx_psc.h linux-2.4.32-rc1.mips/include/asm-mips/au1xxx_psc.h
+--- linux-2.4.32-rc1/include/asm-mips/au1xxx_psc.h 2005-01-19 15:10:11.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/au1xxx_psc.h 2005-01-30 09:01:28.000000000 +0100
+@@ -41,6 +41,11 @@
+ #define PSC3_BASE_ADDR 0xb0d00000
+ #endif
+
++#ifdef CONFIG_SOC_AU1200
++#define PSC0_BASE_ADDR 0xb1a00000
++#define PSC1_BASE_ADDR 0xb1b00000
++#endif
++
+ /* The PSC select and control registers are common to
+ * all protocols.
+ */
+@@ -226,6 +231,8 @@
+ #define PSC_I2SCFG_DD_DISABLE (1 << 27)
+ #define PSC_I2SCFG_DE_ENABLE (1 << 26)
+ #define PSC_I2SCFG_SET_WS(x) (((((x) / 2) - 1) & 0x7f) << 16)
++#define PSC_I2SCFG_WS(n) ((n&0xFF)<<16)
++#define PSC_I2SCFG_WS_MASK (PSC_I2SCFG_WS(0x3F))
+ #define PSC_I2SCFG_WI (1 << 15)
+
+ #define PSC_I2SCFG_DIV_MASK (3 << 13)
+diff -Nur linux-2.4.32-rc1/include/asm-mips/bootinfo.h linux-2.4.32-rc1.mips/include/asm-mips/bootinfo.h
+--- linux-2.4.32-rc1/include/asm-mips/bootinfo.h 2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/bootinfo.h 2005-01-30 09:01:28.000000000 +0100
+@@ -180,6 +180,9 @@
+ #define MACH_MTX1 7 /* 4G MTX-1 Au1500-based board */
+ #define MACH_CSB250 8 /* Cogent Au1500 */
+ #define MACH_PB1550 9 /* Au1550-based eval board */
++#define MACH_PB1200 10 /* Au1200-based eval board */
++#define MACH_DB1550 11 /* Au1550-based eval board */
++#define MACH_DB1200 12 /* Au1200-based eval board */
+
+ /*
+ * Valid machtype for group NEC_VR41XX
+diff -Nur linux-2.4.32-rc1/include/asm-mips/db1200.h linux-2.4.32-rc1.mips/include/asm-mips/db1200.h
+--- linux-2.4.32-rc1/include/asm-mips/db1200.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/db1200.h 2005-01-30 09:02:45.000000000 +0100
+@@ -0,0 +1,214 @@
++/*
++ * AMD Alchemy DB1200 Referrence Board
++ * Board Registers defines.
++ *
++ * ########################################################################
++ *
++ * This program is free software; you can distribute it and/or modify it
++ * under the terms of the GNU General Public License (Version 2) as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * ########################################################################
++ *
++ *
++ */
++#ifndef __ASM_DB1200_H
++#define __ASM_DB1200_H
++
++#include <linux/types.h>
++
++// This is defined in au1000.h with bogus value
++#undef AU1X00_EXTERNAL_INT
++
++#define DBDMA_AC97_TX_CHAN DSCR_CMD0_PSC1_TX
++#define DBDMA_AC97_RX_CHAN DSCR_CMD0_PSC1_RX
++#define DBDMA_I2S_TX_CHAN DSCR_CMD0_PSC1_TX
++#define DBDMA_I2S_RX_CHAN DSCR_CMD0_PSC1_RX
++
++/* SPI and SMB are muxed on the Pb1200 board.
++ Refer to board documentation.
++ */
++#define SPI_PSC_BASE PSC0_BASE_ADDR
++#define SMBUS_PSC_BASE PSC0_BASE_ADDR
++/* AC97 and I2S are muxed on the Pb1200 board.
++ Refer to board documentation.
++ */
++#define AC97_PSC_BASE PSC1_BASE_ADDR
++#define I2S_PSC_BASE PSC1_BASE_ADDR
++
++#define BCSR_KSEG1_ADDR 0xB9800000
++
++typedef volatile struct
++{
++ /*00*/ u16 whoami;
++ u16 reserved0;
++ /*04*/ u16 status;
++ u16 reserved1;
++ /*08*/ u16 switches;
++ u16 reserved2;
++ /*0C*/ u16 resets;
++ u16 reserved3;
++
++ /*10*/ u16 pcmcia;
++ u16 reserved4;
++ /*14*/ u16 board;
++ u16 reserved5;
++ /*18*/ u16 disk_leds;
++ u16 reserved6;
++ /*1C*/ u16 system;
++ u16 reserved7;
++
++ /*20*/ u16 intclr;
++ u16 reserved8;
++ /*24*/ u16 intset;
++ u16 reserved9;
++ /*28*/ u16 intclr_mask;
++ u16 reserved10;
++ /*2C*/ u16 intset_mask;
++ u16 reserved11;
++
++ /*30*/ u16 sig_status;
++ u16 reserved12;
++ /*34*/ u16 int_status;
++ u16 reserved13;
++ /*38*/ u16 reserved14;
++ u16 reserved15;
++ /*3C*/ u16 reserved16;
++ u16 reserved17;
++
++} BCSR;
++
++static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++
++/*
++ * Register bit definitions for the BCSRs
++ */
++#define BCSR_WHOAMI_DCID 0x000F
++#define BCSR_WHOAMI_CPLD 0x00F0
++#define BCSR_WHOAMI_BOARD 0x0F00
++
++#define BCSR_STATUS_PCMCIA0VS 0x0003
++#define BCSR_STATUS_PCMCIA1VS 0x000C
++#define BCSR_STATUS_SWAPBOOT 0x0040
++#define BCSR_STATUS_FLASHBUSY 0x0100
++#define BCSR_STATUS_IDECBLID 0x0200
++#define BCSR_STATUS_SD0WP 0x0400
++#define BCSR_STATUS_U0RXD 0x1000
++#define BCSR_STATUS_U1RXD 0x2000
++
++#define BCSR_SWITCHES_OCTAL 0x00FF
++#define BCSR_SWITCHES_DIP_1 0x0080
++#define BCSR_SWITCHES_DIP_2 0x0040
++#define BCSR_SWITCHES_DIP_3 0x0020
++#define BCSR_SWITCHES_DIP_4 0x0010
++#define BCSR_SWITCHES_DIP_5 0x0008
++#define BCSR_SWITCHES_DIP_6 0x0004
++#define BCSR_SWITCHES_DIP_7 0x0002
++#define BCSR_SWITCHES_DIP_8 0x0001
++#define BCSR_SWITCHES_ROTARY 0x0F00
++
++#define BCSR_RESETS_ETH 0x0001
++#define BCSR_RESETS_CAMERA 0x0002
++#define BCSR_RESETS_DC 0x0004
++#define BCSR_RESETS_IDE 0x0008
++#define BCSR_RESETS_TV 0x0010
++/* not resets but in the same register */
++#define BCSR_RESETS_PWMR1mUX 0x0800
++#define BCSR_RESETS_PCS0MUX 0x1000
++#define BCSR_RESETS_PCS1MUX 0x2000
++#define BCSR_RESETS_SPISEL 0x4000
++
++#define BCSR_PCMCIA_PC0VPP 0x0003
++#define BCSR_PCMCIA_PC0VCC 0x000C
++#define BCSR_PCMCIA_PC0DRVEN 0x0010
++#define BCSR_PCMCIA_PC0RST 0x0080
++#define BCSR_PCMCIA_PC1VPP 0x0300
++#define BCSR_PCMCIA_PC1VCC 0x0C00
++#define BCSR_PCMCIA_PC1DRVEN 0x1000
++#define BCSR_PCMCIA_PC1RST 0x8000
++
++#define BCSR_BOARD_LCDVEE 0x0001
++#define BCSR_BOARD_LCDVDD 0x0002
++#define BCSR_BOARD_LCDBL 0x0004
++#define BCSR_BOARD_CAMSNAP 0x0010
++#define BCSR_BOARD_CAMPWR 0x0020
++#define BCSR_BOARD_SD0PWR 0x0040
++
++#define BCSR_LEDS_DECIMALS 0x0003
++#define BCSR_LEDS_LED0 0x0100
++#define BCSR_LEDS_LED1 0x0200
++#define BCSR_LEDS_LED2 0x0400
++#define BCSR_LEDS_LED3 0x0800
++
++#define BCSR_SYSTEM_POWEROFF 0x4000
++#define BCSR_SYSTEM_RESET 0x8000
++
++/* Bit positions for the different interrupt sources */
++#define BCSR_INT_IDE 0x0001
++#define BCSR_INT_ETH 0x0002
++#define BCSR_INT_PC0 0x0004
++#define BCSR_INT_PC0STSCHG 0x0008
++#define BCSR_INT_PC1 0x0010
++#define BCSR_INT_PC1STSCHG 0x0020
++#define BCSR_INT_DC 0x0040
++#define BCSR_INT_FLASHBUSY 0x0080
++#define BCSR_INT_PC0INSERT 0x0100
++#define BCSR_INT_PC0EJECT 0x0200
++#define BCSR_INT_PC1INSERT 0x0400
++#define BCSR_INT_PC1EJECT 0x0800
++#define BCSR_INT_SD0INSERT 0x1000
++#define BCSR_INT_SD0EJECT 0x2000
++
++#define AU1XXX_SMC91111_PHYS_ADDR (0x19000300)
++#define AU1XXX_SMC91111_IRQ DB1200_ETH_INT
++
++#define AU1XXX_ATA_PHYS_ADDR (0x18800000)
++#define AU1XXX_ATA_PHYS_LEN (0x100)
++#define AU1XXX_ATA_REG_OFFSET (5)
++#define AU1XXX_ATA_INT DB1200_IDE_INT
++#define AU1XXX_ATA_DDMA_REQ DSCR_CMD0_DMA_REQ1;
++#define AU1XXX_ATA_RQSIZE 128
++
++#define NAND_PHYS_ADDR 0x20000000
++
++/*
++ * External Interrupts for Pb1200 as of 8/6/2004.
++ * Bit positions in the CPLD registers can be calculated by taking
++ * the interrupt define and subtracting the DB1200_INT_BEGIN value.
++ * *example: IDE bis pos is = 64 - 64
++ ETH bit pos is = 65 - 64
++ */
++#define DB1200_INT_BEGIN (AU1000_LAST_INTC1_INT + 1)
++#define DB1200_IDE_INT (DB1200_INT_BEGIN + 0)
++#define DB1200_ETH_INT (DB1200_INT_BEGIN + 1)
++#define DB1200_PC0_INT (DB1200_INT_BEGIN + 2)
++#define DB1200_PC0_STSCHG_INT (DB1200_INT_BEGIN + 3)
++#define DB1200_PC1_INT (DB1200_INT_BEGIN + 4)
++#define DB1200_PC1_STSCHG_INT (DB1200_INT_BEGIN + 5)
++#define DB1200_DC_INT (DB1200_INT_BEGIN + 6)
++#define DB1200_FLASHBUSY_INT (DB1200_INT_BEGIN + 7)
++#define DB1200_PC0_INSERT_INT (DB1200_INT_BEGIN + 8)
++#define DB1200_PC0_EJECT_INT (DB1200_INT_BEGIN + 9)
++#define DB1200_PC1_INSERT_INT (DB1200_INT_BEGIN + 10)
++#define DB1200_PC1_EJECT_INT (DB1200_INT_BEGIN + 11)
++#define DB1200_SD0_INSERT_INT (DB1200_INT_BEGIN + 12)
++#define DB1200_SD0_EJECT_INT (DB1200_INT_BEGIN + 13)
++
++#define DB1200_INT_END (DB1200_INT_BEGIN + 15)
++
++/* For drivers/pcmcia/au1000_db1x00.c */
++#define BOARD_PC0_INT DB1200_PC0_INT
++#define BOARD_PC1_INT DB1200_PC1_INT
++#define BOARD_CARD_INSERTED(SOCKET) bcsr->sig_status & (1<<(8+(2*SOCKET)))
++
++#endif /* __ASM_DB1200_H */
++
+diff -Nur linux-2.4.32-rc1/include/asm-mips/db1x00.h linux-2.4.32-rc1.mips/include/asm-mips/db1x00.h
+--- linux-2.4.32-rc1/include/asm-mips/db1x00.h 2005-01-19 15:10:11.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/db1x00.h 2005-01-30 09:06:19.000000000 +0100
+@@ -1,5 +1,5 @@
+ /*
+- * AMD Alchemy DB1x00 Reference Boards
++ * AMD Alchemy DB1x00 Reference Boards (BUT NOT DB1200)
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+@@ -36,9 +36,18 @@
+ #define AC97_PSC_BASE PSC1_BASE_ADDR
+ #define SMBUS_PSC_BASE PSC2_BASE_ADDR
+ #define I2S_PSC_BASE PSC3_BASE_ADDR
++#define NAND_CS 1
++/* for drivers/pcmcia/au1000_db1x00.c */
++#define BOARD_PC0_INT AU1000_GPIO_3
++#define BOARD_PC1_INT AU1000_GPIO_5
++#define BOARD_CARD_INSERTED(SOCKET) !(bcsr->status & (1<<(4+SOCKET)))
+
+ #else
+ #define BCSR_KSEG1_ADDR 0xAE000000
++/* for drivers/pcmcia/au1000_db1x00.c */
++#define BOARD_PC0_INT AU1000_GPIO_2
++#define BOARD_PC1_INT AU1000_GPIO_5
++#define BOARD_CARD_INSERTED(SOCKET) !(bcsr->status & (1<<(4+SOCKET)))
+ #endif
+
+ /*
+@@ -66,6 +75,7 @@
+
+ } BCSR;
+
++static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
+
+ /*
+ * Register/mask bit definitions for the BCSRs
+@@ -130,14 +140,6 @@
+
+ #define BCSR_SWRESET_RESET 0x0080
+
+-/* PCMCIA Db1x00 specific defines */
+-#define PCMCIA_MAX_SOCK 1
+-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK+1)
+-
+-/* VPP/VCC */
+-#define SET_VCC_VPP(VCC, VPP, SLOT)\
+- ((((VCC)<<2) | ((VPP)<<0)) << ((SLOT)*8))
+-
+ /* MTD CONFIG OPTIONS */
+ #if defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER)
+ #define DB1X00_BOTH_BANKS
+@@ -147,48 +149,15 @@
+ #define DB1X00_USER_ONLY
+ #endif
+
+-/* SD controller macros */
+-/*
+- * Detect card.
+- */
+-#define mmc_card_inserted(_n_, _res_) \
+- do { \
+- BCSR * const bcsr = (BCSR *)0xAE000000; \
+- unsigned long mmc_wp, board_specific; \
+- if ((_n_)) { \
+- mmc_wp = BCSR_BOARD_SD1_WP; \
+- } else { \
+- mmc_wp = BCSR_BOARD_SD0_WP; \
+- } \
+- board_specific = au_readl((unsigned long)(&bcsr->specific)); \
+- if (!(board_specific & mmc_wp)) {/* low means card present */ \
+- *(int *)(_res_) = 1; \
+- } else { \
+- *(int *)(_res_) = 0; \
+- } \
+- } while (0)
+-
++#if defined(CONFIG_BLK_DEV_IDE_AU1XXX) && defined(CONFIG_MIPS_DB1550)
+ /*
+- * Apply power to card slot(s).
++ * Daughter card information.
+ */
+-#define mmc_power_on(_n_) \
+- do { \
+- BCSR * const bcsr = (BCSR *)0xAE000000; \
+- unsigned long mmc_pwr, mmc_wp, board_specific; \
+- if ((_n_)) { \
+- mmc_pwr = BCSR_BOARD_SD1_PWR; \
+- mmc_wp = BCSR_BOARD_SD1_WP; \
+- } else { \
+- mmc_pwr = BCSR_BOARD_SD0_PWR; \
+- mmc_wp = BCSR_BOARD_SD0_WP; \
+- } \
+- board_specific = au_readl((unsigned long)(&bcsr->specific)); \
+- if (!(board_specific & mmc_wp)) {/* low means card present */ \
+- board_specific |= mmc_pwr; \
+- au_writel(board_specific, (int)(&bcsr->specific)); \
+- au_sync(); \
+- } \
+- } while (0)
++#define DAUGHTER_CARD_IRQ (AU1000_GPIO_8)
++/* DC_IDE */
++#define AU1XXX_ATA_PHYS_ADDR (0x0C000000)
++#define AU1XXX_ATA_REG_OFFSET (5)
++#endif /* CONFIG_MIPS_DB1550 */
+
+ #endif /* __ASM_DB1X00_H */
+
+diff -Nur linux-2.4.32-rc1/include/asm-mips/elf.h linux-2.4.32-rc1.mips/include/asm-mips/elf.h
+--- linux-2.4.32-rc1/include/asm-mips/elf.h 2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/elf.h 2005-04-14 12:41:44.000000000 +0200
+@@ -66,9 +66,10 @@
+ #define USE_ELF_CORE_DUMP
+ #define ELF_EXEC_PAGESIZE PAGE_SIZE
+
+-#define ELF_CORE_COPY_REGS(_dest,_regs) \
+- memcpy((char *) &_dest, (char *) _regs, \
+- sizeof(struct pt_regs));
++extern void dump_regs(elf_greg_t *, struct pt_regs *regs);
++
++#define ELF_CORE_COPY_REGS(elf_regs, regs) \
++ dump_regs((elf_greg_t *)&(elf_regs), regs);
+
+ /* This yields a mask that user programs can use to figure out what
+ instruction set this cpu supports. This could be done in userspace,
+diff -Nur linux-2.4.32-rc1/include/asm-mips/ficmmp.h linux-2.4.32-rc1.mips/include/asm-mips/ficmmp.h
+--- linux-2.4.32-rc1/include/asm-mips/ficmmp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/ficmmp.h 2005-01-30 09:01:28.000000000 +0100
+@@ -0,0 +1,156 @@
++/*
++ * FIC MMP
++ *
++ * ########################################################################
++ *
++ * This program is free software; you can distribute it and/or modify it
++ * under the terms of the GNU General Public License (Version 2) as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * ########################################################################
++ *
++ *
++ */
++#ifndef __ASM_FICMMP_H
++#define __ASM_FICMMP_H
++
++#include <linux/types.h>
++#include <asm/au1000.h>
++#include <asm/au1xxx_gpio.h>
++
++// This is defined in au1000.h with bogus value
++#undef AU1X00_EXTERNAL_INT
++
++#define DBDMA_AC97_TX_CHAN DSCR_CMD0_PSC1_TX
++#define DBDMA_AC97_RX_CHAN DSCR_CMD0_PSC1_RX
++#define DBDMA_I2S_TX_CHAN DSCR_CMD0_PSC1_TX
++#define DBDMA_I2S_RX_CHAN DSCR_CMD0_PSC1_RX
++/* SPI and SMB are muxed on the Pb1200 board.
++ Refer to board documentation.
++ */
++#define SPI_PSC_BASE PSC0_BASE_ADDR
++#define SMBUS_PSC_BASE PSC0_BASE_ADDR
++/* AC97 and I2S are muxed on the Pb1200 board.
++ Refer to board documentation.
++ */
++#define AC97_PSC_BASE PSC1_BASE_ADDR
++#define I2S_PSC_BASE PSC1_BASE_ADDR
++
++
++/*
++ * SMSC LAN91C111
++ */
++#define AU1XXX_SMC91111_PHYS_ADDR (0xAC000300)
++#define AU1XXX_SMC91111_IRQ AU1000_GPIO_5
++
++/* DC_IDE and DC_ETHERNET */
++#define FICMMP_IDE_INT AU1000_GPIO_4
++
++#define AU1XXX_ATA_PHYS_ADDR (0x0C800000)
++#define AU1XXX_ATA_REG_OFFSET (5)
++/*
++#define AU1XXX_ATA_BASE (0x0C800000)
++#define AU1XXX_ATA_END (0x0CFFFFFF)
++#define AU1XXX_ATA_MEM_SIZE (AU1XXX_ATA_END - AU1XXX_ATA_BASE +1)
++
++#define AU1XXX_ATA_REG_OFFSET (5)
++*/
++/* VPP/VCC */
++#define SET_VCC_VPP(VCC, VPP, SLOT)\
++ ((((VCC)<<2) | ((VPP)<<0)) << ((SLOT)*8))
++
++
++#define FICMMP_CONFIG_BASE 0xAD000000
++#define FICMMP_CONFIG_ENABLE 13
++
++#define FICMMP_CONFIG_I2SFREQ(N) (N<<0)
++#define FICMMP_CONFIG_I2SXTAL0 (1<<0)
++#define FICMMP_CONFIG_I2SXTAL1 (1<<1)
++#define FICMMP_CONFIG_I2SXTAL2 (1<<2)
++#define FICMMP_CONFIG_I2SXTAL3 (1<<3)
++#define FICMMP_CONFIG_ADV1 (1<<4)
++#define FICMMP_CONFIG_IDERST (1<<5)
++#define FICMMP_CONFIG_LCMEN (1<<6)
++#define FICMMP_CONFIG_CAMPWDN (1<<7)
++#define FICMMP_CONFIG_USBPWREN (1<<8)
++#define FICMMP_CONFIG_LCMPWREN (1<<9)
++#define FICMMP_CONFIG_TVOUTPWREN (1<<10)
++#define FICMMP_CONFIG_RS232PWREN (1<<11)
++#define FICMMP_CONFIG_LCMDATAOUT (1<<12)
++#define FICMMP_CONFIG_TVODATAOUT (1<<13)
++#define FICMMP_CONFIG_ADV3 (1<<14)
++#define FICMMP_CONFIG_ADV4 (1<<15)
++
++#define I2S_FREQ_8_192 (0x0)
++#define I2S_FREQ_11_2896 (0x1)
++#define I2S_FREQ_12_288 (0x2)
++#define I2S_FREQ_24_576 (0x3)
++//#define I2S_FREQ_12_288 (0x4)
++#define I2S_FREQ_16_9344 (0x5)
++#define I2S_FREQ_18_432 (0x6)
++#define I2S_FREQ_36_864 (0x7)
++#define I2S_FREQ_16_384 (0x8)
++#define I2S_FREQ_22_5792 (0x9)
++//#define I2S_FREQ_24_576 (0x10)
++#define I2S_FREQ_49_152 (0x11)
++//#define I2S_FREQ_24_576 (0x12)
++#define I2S_FREQ_33_8688 (0x13)
++//#define I2S_FREQ_36_864 (0x14)
++#define I2S_FREQ_73_728 (0x15)
++
++#define FICMMP_IDE_PWR 9
++#define FICMMP_FOCUS_RST 2
++
++static __inline void ficmmp_config_set(u16 bits)
++{
++ extern u16 ficmmp_config;
++ //printk("set_config: %X, Old: %X, New: %X\n", bits, ficmmp_config, ficmmp_config | bits);
++ ficmmp_config |= bits;
++ *((u16*)FICMMP_CONFIG_BASE) = ficmmp_config;
++}
++
++static __inline void ficmmp_config_clear(u16 bits)
++{
++ extern u16 ficmmp_config;
++// printk("clear_config: %X, Old: %X, New: %X\n", bits, ficmmp_config, ficmmp_config & ~bits);
++ ficmmp_config &= ~bits;
++ *((u16*)FICMMP_CONFIG_BASE) = ficmmp_config;
++}
++
++static __inline void ficmmp_config_init(void)
++{
++ au1xxx_gpio_write(FICMMP_CONFIG_ENABLE, 0); //Enable configuration latch
++ ficmmp_config_set(FICMMP_CONFIG_LCMDATAOUT | FICMMP_CONFIG_TVODATAOUT | FICMMP_CONFIG_IDERST); //Disable display data buffers
++ ficmmp_config_set(FICMMP_CONFIG_I2SFREQ(I2S_FREQ_36_864));
++}
++
++static __inline u32 ficmmp_set_i2s_sample_rate(u32 rate)
++{
++ u32 freq;
++
++ switch(rate)
++ {
++ case 88200:
++ case 44100:
++ case 8018: freq = I2S_FREQ_11_2896; break;
++ case 48000:
++ case 32000: //freq = I2S_FREQ_18_432; break;
++ case 8000: freq = I2S_FREQ_12_288; break;
++ default: freq = I2S_FREQ_12_288; rate = 8000;
++ }
++ ficmmp_config_clear(FICMMP_CONFIG_I2SFREQ(0xF));
++ ficmmp_config_set(FICMMP_CONFIG_I2SFREQ(freq));
++ return rate;
++}
++
++#endif /* __ASM_FICMMP_H */
++
+diff -Nur linux-2.4.32-rc1/include/asm-mips/hazards.h linux-2.4.32-rc1.mips/include/asm-mips/hazards.h
+--- linux-2.4.32-rc1/include/asm-mips/hazards.h 2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/hazards.h 2005-06-06 16:46:22.000000000 +0200
+@@ -3,7 +3,7 @@
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+- * Copyright (C) 2003 Ralf Baechle
++ * Copyright (C) 2003, 2004 Ralf Baechle
+ */
+ #ifndef _ASM_HAZARDS_H
+ #define _ASM_HAZARDS_H
+@@ -12,38 +12,200 @@
+
+ #ifdef __ASSEMBLY__
+
++ .macro _ssnop
++ sll $0, $0, 1
++ .endm
++
+ /*
+ * RM9000 hazards. When the JTLB is updated by tlbwi or tlbwr, a subsequent
+ * use of the JTLB for instructions should not occur for 4 cpu cycles and use
+ * for data translations should not occur for 3 cpu cycles.
+ */
+ #ifdef CONFIG_CPU_RM9000
+-#define rm9000_tlb_hazard \
++
++#define mtc0_tlbw_hazard \
+ .set push; \
+ .set mips32; \
+- ssnop; ssnop; ssnop; ssnop; \
++ _ssnop; _ssnop; _ssnop; _ssnop; \
+ .set pop
++
++#define tlbw_eret_hazard \
++ .set push; \
++ .set mips32; \
++ _ssnop; _ssnop; _ssnop; _ssnop; \
++ .set pop
++
+ #else
+-#define rm9000_tlb_hazard
++
++/*
++ * The taken branch will result in a two cycle penalty for the two killed
++ * instructions on R4000 / R4400. Other processors only have a single cycle
++ * hazard so this is nice trick to have an optimal code for a range of
++ * processors.
++ */
++#define mtc0_tlbw_hazard \
++ b . + 8
++#define tlbw_eret_hazard \
++ nop
+ #endif
+
++/*
++ * mtc0->mfc0 hazard
++ * The 24K has a 2 cycle mtc0/mfc0 execution hazard.
++ * It is a MIPS32R2 processor so ehb will clear the hazard.
++ */
++
++#ifdef CONFIG_CPU_MIPSR2
++/*
++ * Use a macro for ehb unless explicit support for MIPSR2 is enabled
++ */
++ .macro ehb
++ sll $0, $0, 3
++ .endm
++
++#define irq_enable_hazard \
++ ehb # irq_enable_hazard
++
++#define irq_disable_hazard \
++ ehb # irq_disable_hazard
++
++#elif defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_RM9000)
++
++/*
++ * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
++ */
++
++#define irq_enable_hazard
++
++#define irq_disable_hazard
++
+ #else
+
+ /*
++ * Classic MIPS needs 1 - 3 nops or ssnops
++ */
++#define irq_enable_hazard
++#define irq_disable_hazard \
++ _ssnop; _ssnop; _ssnop
++
++#endif
++
++#else /* __ASSEMBLY__ */
++
++/*
+ * RM9000 hazards. When the JTLB is updated by tlbwi or tlbwr, a subsequent
+ * use of the JTLB for instructions should not occur for 4 cpu cycles and use
+ * for data translations should not occur for 3 cpu cycles.
+ */
+ #ifdef CONFIG_CPU_RM9000
+-#define rm9000_tlb_hazard() \
++
++#define mtc0_tlbw_hazard() \
+ __asm__ __volatile__( \
+ ".set\tmips32\n\t" \
+- "ssnop; ssnop; ssnop; ssnop\n\t" \
++ "_ssnop; _ssnop; _ssnop; _ssnop\n\t" \
++ ".set\tmips0")
++
++#define tlbw_use_hazard() \
++ __asm__ __volatile__( \
++ ".set\tmips32\n\t" \
++ "_ssnop; _ssnop; _ssnop; _ssnop\n\t" \
+ ".set\tmips0")
+ #else
+-#define rm9000_tlb_hazard() do { } while (0)
++
++/*
++ * Overkill warning ...
++ */
++#define mtc0_tlbw_hazard() \
++ __asm__ __volatile__( \
++ ".set noreorder\n\t" \
++ "nop; nop; nop; nop; nop; nop;\n\t" \
++ ".set reorder\n\t")
++
++#define tlbw_use_hazard() \
++ __asm__ __volatile__( \
++ ".set noreorder\n\t" \
++ "nop; nop; nop; nop; nop; nop;\n\t" \
++ ".set reorder\n\t")
++
+ #endif
+
++/*
++ * mtc0->mfc0 hazard
++ * The 24K has a 2 cycle mtc0/mfc0 execution hazard.
++ * It is a MIPS32R2 processor so ehb will clear the hazard.
++ */
++
++#ifdef CONFIG_CPU_MIPSR2
++/*
++ * Use a macro for ehb unless explicit support for MIPSR2 is enabled
++ */
++__asm__(
++ " .macro ehb \n\t"
++ " sll $0, $0, 3 \n\t"
++ " .endm \n\t"
++ " \n\t"
++ " .macro\tirq_enable_hazard \n\t"
++ " ehb \n\t"
++ " .endm \n\t"
++ " \n\t"
++ " .macro\tirq_disable_hazard \n\t"
++ " ehb \n\t"
++ " .endm");
++
++#define irq_enable_hazard() \
++ __asm__ __volatile__( \
++ "ehb\t\t\t\t# irq_enable_hazard")
++
++#define irq_disable_hazard() \
++ __asm__ __volatile__( \
++ "ehb\t\t\t\t# irq_disable_hazard")
++
++#elif defined(CONFIG_CPU_R10000)
++
++/*
++ * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
++ */
++
++__asm__(
++ " .macro\tirq_enable_hazard \n\t"
++ " .endm \n\t"
++ " \n\t"
++ " .macro\tirq_disable_hazard \n\t"
++ " .endm");
++
++#define irq_enable_hazard() do { } while (0)
++#define irq_disable_hazard() do { } while (0)
++
++#else
++
++/*
++ * Default for classic MIPS processors. Assume worst case hazards but don't
++ * care about the irq_enable_hazard - sooner or later the hardware will
++ * enable it and we don't care when exactly.
++ */
++
++__asm__(
++ " .macro _ssnop \n\t"
++ " sll $0, $2, 1 \n\t"
++ " .endm \n\t"
++ " \n\t"
++ " # \n\t"
++ " # There is a hazard but we do not care \n\t"
++ " # \n\t"
++ " .macro\tirq_enable_hazard \n\t"
++ " .endm \n\t"
++ " \n\t"
++ " .macro\tirq_disable_hazard \n\t"
++ " _ssnop; _ssnop; _ssnop \n\t"
++ " .endm");
++
++#define irq_enable_hazard() do { } while (0)
++#define irq_disable_hazard() \
++ __asm__ __volatile__( \
++ "_ssnop; _ssnop; _ssnop;\t\t# irq_disable_hazard")
++
+ #endif
+
++#endif /* __ASSEMBLY__ */
++
+ #endif /* _ASM_HAZARDS_H */
+diff -Nur linux-2.4.32-rc1/include/asm-mips/ide.h linux-2.4.32-rc1.mips/include/asm-mips/ide.h
+--- linux-2.4.32-rc1/include/asm-mips/ide.h 2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.32-rc1.mips/include/asm-mips/ide.h 2005-04-19 14:26:53.000000000 +0200
+@@ -32,12 +32,12 @@
+
+ extern struct ide_ops *ide_ops;
+
+-static __inline__ int ide_default_irq(ide_ioreg_t base)
++static inline int ide_default_irq(ide_ioreg_t base)
+ {
+ return ide_ops->ide_default_irq(base);
+ }
+
+-static __inline__ ide_ioreg_t ide_default_io_base(int index)
++static inline ide_ioreg_t ide_default_io_base(int index)
+ {
+ return ide_ops->ide_default_io_base(index);
+ }
+@@ -48,7 +48,7 @@
+ ide_ops->ide_init_hwif_ports(hw, data_port, ctrl_port, irq);
+ }
+
+-static __inline__ void ide_init_default_hwifs(void)
++static inline void ide_init_default_hwifs(void)
+ {
+ #ifndef CONFIG_BLK_DEV_IDEPCI
+ hw_regs_t hw;
+@@ -68,7 +68,89 @@
+ #define ide_ack_intr(hwif) ((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1)
+ #endif
+
+-#include <asm-generic/ide_iops.h>
++/* MIPS port and memory-mapped I/O string operations. */
++
++static inline void __ide_flush_dcache_range(unsigned long addr, unsigned long size)
++{
++ if (cpu_has_dc_aliases) {
++ unsigned long end = addr + size;
++ for (; addr < end; addr += PAGE_SIZE)
++ flush_dcache_page(virt_to_page(addr));
++ }
++}
++
++static inline void __ide_insw(unsigned long port, void *addr,
++ unsigned int count)
++{
++ insw(port, addr, count);
++ __ide_flush_dcache_range((unsigned long)addr, count * 2);
++}
++
++static inline void __ide_insl(unsigned long port, void *addr, unsigned int count)
++{
++ insl(port, addr, count);
++ __ide_flush_dcache_range((unsigned long)addr, count * 4);
++}
++
++static inline void __ide_outsw(unsigned long port, const void *addr,
++ unsigned long count)
++{
++ outsw(port, addr, count);
++ __ide_flush_dcache_range((unsigned long)addr, count * 2);
++}
++
++static inline void __ide_outsl(unsigned long port, const void *addr,
++ unsigned long count)
++{
++ outsl(port, addr, count);
++ __ide_flush_dcache_range((unsigned long)addr, count * 4);
++}
++
++static inline void __ide_mm_insw(unsigned long port, void *addr, u32 count)
++{
++ unsigned long start = (unsigned long) addr;
++
++ while (count--) {
++ *(u16 *)addr = readw(port);
++ addr += 2;
++ }
++ __ide_flush_dcache_range(start, count * 2);
++}
++
++static inline void __ide_mm_insl(unsigned long port, void *addr, u32 count)
++{
++ unsigned long start = (unsigned long) addr;
++
++ while (count--) {
++ *(u32 *)addr = readl(port);
++ addr += 4;
++ }
++ __ide_flush_dcache_range(start, count * 4);
++}
++
++static inline void __ide_mm_outsw(unsigned long port, const void *addr,
++ u32 count)
++{
++ unsigned long start = (unsigned long) addr;
++
++ while (count--) {
++ writew(*(u16 *)addr, port);
++ addr += 2;
++ }
++ __ide_flush_dcache_range(start, count * 2);
++}
++
++static inline void __ide_mm_outsl(unsigned long port, const void *addr,
++ u32 count)
++{
++ unsigned long start = (unsigned long) addr;
++
++ while (count--) {
++ writel(*(u32 *)addr, port);
++ addr += 4;
++ }
++ __ide_flush_dcache_range(start, count * 4);
++}
+
+ #endif /* __KERNEL__ */
+
+diff -Nur linux-2.4.32-rc1/include/asm-mips/io.h linux-2.4.32-rc1.mips/include/asm-mips/io.h
+--- linux-2.4.32-rc1/include/asm-mips/io.h 2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.32-rc1.mips/include/asm-mips/io.h 2005-04-19 14:24:16.000000000 +0200
+@@ -392,7 +392,8 @@
+ return __ioswab32(__val);
+ }
+
+-static inline void __outsb(unsigned long port, void *addr, unsigned int count)
++static inline void __outsb(unsigned long port, const void *addr,
++ unsigned int count)
+ {
+ while (count--) {
+ outb(*(u8 *)addr, port);
+@@ -408,7 +409,8 @@
+ }
+ }
+
+-static inline void __outsw(unsigned long port, void *addr, unsigned int count)
++static inline void __outsw(unsigned long port, const void *addr,
++ unsigned int count)
+ {
+ while (count--) {
+ outw(*(u16 *)addr, port);
+@@ -424,7 +426,8 @@
+ }
+ }
+
+-static inline void __outsl(unsigned long port, void *addr, unsigned int count)
++static inline void __outsl(unsigned long port, const void *addr,
++ unsigned int count)
+ {
+ while (count--) {
+ outl(*(u32 *)addr, port);
+diff -Nur linux-2.4.32-rc1/include/asm-mips/mipsregs.h linux-2.4.32-rc1.mips/include/asm-mips/mipsregs.h
+--- linux-2.4.32-rc1/include/asm-mips/mipsregs.h 2005-01-19 15:10:12.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/mipsregs.h 2005-02-06 22:24:22.000000000 +0100
+@@ -757,10 +757,18 @@
+ #define read_c0_config1() __read_32bit_c0_register($16, 1)
+ #define read_c0_config2() __read_32bit_c0_register($16, 2)
+ #define read_c0_config3() __read_32bit_c0_register($16, 3)
++#define read_c0_config4() __read_32bit_c0_register($16, 4)
++#define read_c0_config5() __read_32bit_c0_register($16, 5)
++#define read_c0_config6() __read_32bit_c0_register($16, 6)
++#define read_c0_config7() __read_32bit_c0_register($16, 7)
+ #define write_c0_config(val) __write_32bit_c0_register($16, 0, val)
+ #define write_c0_config1(val) __write_32bit_c0_register($16, 1, val)
+ #define write_c0_config2(val) __write_32bit_c0_register($16, 2, val)
+ #define write_c0_config3(val) __write_32bit_c0_register($16, 3, val)
++#define write_c0_config4(val) __write_32bit_c0_register($16, 4, val)
++#define write_c0_config5(val) __write_32bit_c0_register($16, 5, val)
++#define write_c0_config6(val) __write_32bit_c0_register($16, 6, val)
++#define write_c0_config7(val) __write_32bit_c0_register($16, 7, val)
+
+ /*
+ * The WatchLo register. There may be upto 8 of them.
+@@ -874,42 +882,34 @@
+ */
+ static inline void tlb_probe(void)
+ {
+- rm9000_tlb_hazard();
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ "tlbp\n\t"
+ ".set reorder");
+- rm9000_tlb_hazard();
+ }
+
+ static inline void tlb_read(void)
+ {
+- rm9000_tlb_hazard();
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ "tlbr\n\t"
+ ".set reorder");
+- rm9000_tlb_hazard();
+ }
+
+ static inline void tlb_write_indexed(void)
+ {
+- rm9000_tlb_hazard();
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ "tlbwi\n\t"
+ ".set reorder");
+- rm9000_tlb_hazard();
+ }
+
+ static inline void tlb_write_random(void)
+ {
+- rm9000_tlb_hazard();
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ "tlbwr\n\t"
+ ".set reorder");
+- rm9000_tlb_hazard();
+ }
+
+ /*
+diff -Nur linux-2.4.32-rc1/include/asm-mips/mmu_context.h linux-2.4.32-rc1.mips/include/asm-mips/mmu_context.h
+--- linux-2.4.32-rc1/include/asm-mips/mmu_context.h 2005-01-19 15:10:12.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/mmu_context.h 2004-11-22 14:38:29.000000000 +0100
+@@ -27,7 +27,7 @@
+ #define TLBMISS_HANDLER_SETUP_PGD(pgd) \
+ pgd_current[smp_processor_id()] = (unsigned long)(pgd)
+ #define TLBMISS_HANDLER_SETUP() \
+- write_c0_context((unsigned long) smp_processor_id() << (23 + 3)); \
++ write_c0_context((unsigned long) smp_processor_id() << 23); \
+ TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir)
+ extern unsigned long pgd_current[];
+
+diff -Nur linux-2.4.32-rc1/include/asm-mips/pb1100.h linux-2.4.32-rc1.mips/include/asm-mips/pb1100.h
+--- linux-2.4.32-rc1/include/asm-mips/pb1100.h 2003-08-25 13:44:44.000000000 +0200
++++ linux-2.4.32-rc1.mips/include/asm-mips/pb1100.h 2005-01-30 09:10:29.000000000 +0100
+@@ -1,5 +1,5 @@
+ /*
+- * Alchemy Semi PB1100 Referrence Board
++ * AMD Alchemy PB1100 Reference Boards
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+@@ -27,55 +27,108 @@
+ #ifndef __ASM_PB1100_H
+ #define __ASM_PB1100_H
+
+-#define PB1100_IDENT 0xAE000000
+-#define BOARD_STATUS_REG 0xAE000004
+- #define PB1100_ROM_SEL (1<<15)
+- #define PB1100_ROM_SIZ (1<<14)
+- #define PB1100_SWAP_BOOT (1<<13)
+- #define PB1100_FLASH_WP (1<<12)
+- #define PB1100_ROM_H_STS (1<<11)
+- #define PB1100_ROM_L_STS (1<<10)
+- #define PB1100_FLASH_H_STS (1<<9)
+- #define PB1100_FLASH_L_STS (1<<8)
+- #define PB1100_SRAM_SIZ (1<<7)
+- #define PB1100_TSC_BUSY (1<<6)
+- #define PB1100_PCMCIA_VS_MASK (3<<4)
+- #define PB1100_RS232_CD (1<<3)
+- #define PB1100_RS232_CTS (1<<2)
+- #define PB1100_RS232_DSR (1<<1)
+- #define PB1100_RS232_RI (1<<0)
+-
+-#define PB1100_IRDA_RS232 0xAE00000C
+- #define PB1100_IRDA_FULL (0<<14) /* full power */
+- #define PB1100_IRDA_SHUTDOWN (1<<14)
+- #define PB1100_IRDA_TT (2<<14) /* 2/3 power */
+- #define PB1100_IRDA_OT (3<<14) /* 1/3 power */
+- #define PB1100_IRDA_FIR (1<<13)
+-
+-#define PCMCIA_BOARD_REG 0xAE000010
+- #define PB1100_SD_WP1_RO (1<<15) /* read only */
+- #define PB1100_SD_WP0_RO (1<<14) /* read only */
+- #define PB1100_SD_PWR1 (1<<11) /* applies power to SD1 */
+- #define PB1100_SD_PWR0 (1<<10) /* applies power to SD0 */
+- #define PB1100_SEL_SD_CONN1 (1<<9)
+- #define PB1100_SEL_SD_CONN0 (1<<8)
+- #define PC_DEASSERT_RST (1<<7)
+- #define PC_DRV_EN (1<<4)
+-
+-#define PB1100_G_CONTROL 0xAE000014 /* graphics control */
+-
+-#define PB1100_RST_VDDI 0xAE00001C
+- #define PB1100_SOFT_RESET (1<<15) /* clear to reset the board */
+- #define PB1100_VDDI_MASK (0x1F)
++#define BCSR_KSEG1_ADDR 0xAE000000
++
++/*
++ * Overlay data structure of the Pb1100 board registers.
++ * Registers located at physical 0E0000xx, KSEG1 0xAE0000xx
++ */
++typedef volatile struct
++{
++ /*00*/ unsigned short whoami;
++ unsigned short reserved0;
++ /*04*/ unsigned short status;
++ unsigned short reserved1;
++ /*08*/ unsigned short switches;
++ unsigned short reserved2;
++ /*0C*/ unsigned short resets;
++ unsigned short reserved3;
++ /*10*/ unsigned short pcmcia;
++ unsigned short reserved4;
++ /*14*/ unsigned short graphics;
++ unsigned short reserved5;
++ /*18*/ unsigned short leds;
++ unsigned short reserved6;
++ /*1C*/ unsigned short swreset;
++ unsigned short reserved7;
++
++} BCSR;
+
+-#define PB1100_LEDS 0xAE000018
+
+-/* 11:8 is 4 discreet LEDs. Clearing a bit illuminates the LED.
+- * 7:0 is the LED Display's decimal points.
++/*
++ * Register/mask bit definitions for the BCSRs
+ */
+-#define PB1100_HEX_LED 0xAE000018
++#define BCSR_WHOAMI_DCID 0x000F
++#define BCSR_WHOAMI_CPLD 0x00F0
++#define BCSR_WHOAMI_BOARD 0x0F00
++
++#define BCSR_STATUS_RS232_RI 0x0001
++#define BCSR_STATUS_RS232_DSR 0x0002
++#define BCSR_STATUS_RS232_CTS 0x0004
++#define BCSR_STATUS_RS232_CD 0x0008
++#define BCSR_STATUS_PCMCIA_VS_MASK 0x0030
++#define BCSR_STATUS_TSC_BUSY 0x0040
++#define BCSR_STATUS_SRAM_SIZ 0x0080
++#define BCSR_STATUS_FLASH_L_STS 0x0100
++#define BCSR_STATUS_FLASH_H_STS 0x0200
++#define BCSR_STATUS_ROM_H_STS 0x0400
++#define BCSR_STATUS_ROM_L_STS 0x0800
++#define BCSR_STATUS_FLASH_WP 0x1000
++#define BCSR_STATUS_SWAP_BOOT 0x2000
++#define BCSR_STATUS_ROM_SIZ 0x4000
++#define BCSR_STATUS_ROM_SEL 0x8000
++
++#define BCSR_SWITCHES_DIP 0x00FF
++#define BCSR_SWITCHES_DIP_1 0x0080
++#define BCSR_SWITCHES_DIP_2 0x0040
++#define BCSR_SWITCHES_DIP_3 0x0020
++#define BCSR_SWITCHES_DIP_4 0x0010
++#define BCSR_SWITCHES_DIP_5 0x0008
++#define BCSR_SWITCHES_DIP_6 0x0004
++#define BCSR_SWITCHES_DIP_7 0x0002
++#define BCSR_SWITCHES_DIP_8 0x0001
++#define BCSR_SWITCHES_ROTARY 0x0F00
++#define BCSR_SWITCHES_SDO_CL 0x8000
++
++#define BCSR_RESETS_PHY0 0x0001
++#define BCSR_RESETS_PHY1 0x0002
++#define BCSR_RESETS_DC 0x0004
++#define BCSR_RESETS_RS232_RTS 0x0100
++#define BCSR_RESETS_RS232_DTR 0x0200
++#define BCSR_RESETS_FIR_SEL 0x2000
++#define BCSR_RESETS_IRDA_MODE_MASK 0xC000
++#define BCSR_RESETS_IRDA_MODE_FULL 0x0000
++#define BCSR_RESETS_IRDA_MODE_OFF 0x4000
++#define BCSR_RESETS_IRDA_MODE_2_3 0x8000
++#define BCSR_RESETS_IRDA_MODE_1_3 0xC000
++
++#define BCSR_PCMCIA_PC0VPP 0x0003
++#define BCSR_PCMCIA_PC0VCC 0x000C
++#define BCSR_PCMCIA_PC0_DR_VEN 0x0010
++#define BCSR_PCMCIA_PC0RST 0x0080
++#define BCSR_PCMCIA_SEL_SD_CON0 0x0100
++#define BCSR_PCMCIA_SEL_SD_CON1 0x0200
++#define BCSR_PCMCIA_SD0_PWR 0x0400
++#define BCSR_PCMCIA_SD1_PWR 0x0800
++#define BCSR_PCMCIA_SD0_WP 0x4000
++#define BCSR_PCMCIA_SD1_WP 0x8000
++
++#define PB1100_G_CONTROL 0xAE000014
++#define BCSR_GRAPHICS_GPX_SMPASS 0x0010
++#define BCSR_GRAPHICS_GPX_BIG_ENDIAN 0x0020
++#define BCSR_GRAPHICS_GPX_RST 0x0040
++
++#define BCSR_LEDS_DECIMALS 0x00FF
++#define BCSR_LEDS_LED0 0x0100
++#define BCSR_LEDS_LED1 0x0200
++#define BCSR_LEDS_LED2 0x0400
++#define BCSR_LEDS_LED3 0x0800
++
++#define BCSR_SWRESET_RESET 0x0080
++#define BCSR_VDDI_VDI 0x001F
+
+-/* PCMCIA PB1100 specific defines */
++
++ /* PCMCIA Pb1x00 specific defines */
+ #define PCMCIA_MAX_SOCK 0
+ #define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK+1)
+
+@@ -83,3 +136,4 @@
+ #define SET_VCC_VPP(VCC, VPP) (((VCC)<<2) | ((VPP)<<0))
+
+ #endif /* __ASM_PB1100_H */
++
+diff -Nur linux-2.4.32-rc1/include/asm-mips/pb1200.h linux-2.4.32-rc1.mips/include/asm-mips/pb1200.h
+--- linux-2.4.32-rc1/include/asm-mips/pb1200.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/pb1200.h 2005-01-30 09:01:28.000000000 +0100
+@@ -0,0 +1,244 @@
++/*
++ * AMD Alchemy PB1200 Referrence Board
++ * Board Registers defines.
++ *
++ * ########################################################################
++ *
++ * This program is free software; you can distribute it and/or modify it
++ * under the terms of the GNU General Public License (Version 2) as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
++ * for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
++ *
++ * ########################################################################
++ *
++ *
++ */
++#ifndef __ASM_PB1200_H
++#define __ASM_PB1200_H
++
++#include <linux/types.h>
++
++// This is defined in au1000.h with bogus value
++#undef AU1X00_EXTERNAL_INT
++
++#define DBDMA_AC97_TX_CHAN DSCR_CMD0_PSC1_TX
++#define DBDMA_AC97_RX_CHAN DSCR_CMD0_PSC1_RX
++#define DBDMA_I2S_TX_CHAN DSCR_CMD0_PSC1_TX
++#define DBDMA_I2S_RX_CHAN DSCR_CMD0_PSC1_RX
++
++/* SPI and SMB are muxed on the Pb1200 board.
++ Refer to board documentation.
++ */
++#define SPI_PSC_BASE PSC0_BASE_ADDR
++#define SMBUS_PSC_BASE PSC0_BASE_ADDR
++/* AC97 and I2S are muxed on the Pb1200 board.
++ Refer to board documentation.
++ */
++#define AC97_PSC_BASE PSC1_BASE_ADDR
++#define I2S_PSC_BASE PSC1_BASE_ADDR
++
++#define BCSR_KSEG1_ADDR 0xAD800000
++
++typedef volatile struct
++{
++ /*00*/ u16 whoami;
++ u16 reserved0;
++ /*04*/ u16 status;
++ u16 reserved1;
++ /*08*/ u16 switches;
++ u16 reserved2;
++ /*0C*/ u16 resets;
++ u16 reserved3;
++
++ /*10*/ u16 pcmcia;
++ u16 reserved4;
++ /*14*/ u16 board;
++ u16 reserved5;
++ /*18*/ u16 disk_leds;
++ u16 reserved6;
++ /*1C*/ u16 system;
++ u16 reserved7;
++
++ /*20*/ u16 intclr;
++ u16 reserved8;
++ /*24*/ u16 intset;
++ u16 reserved9;
++ /*28*/ u16 intclr_mask;
++ u16 reserved10;
++ /*2C*/ u16 intset_mask;
++ u16 reserved11;
++
++ /*30*/ u16 sig_status;
++ u16 reserved12;
++ /*34*/ u16 int_status;
++ u16 reserved13;
++ /*38*/ u16 reserved14;
++ u16 reserved15;
++ /*3C*/ u16 reserved16;
++ u16 reserved17;
++
++} BCSR;
++
++static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
++
++/*
++ * Register bit definitions for the BCSRs
++ */
++#define BCSR_WHOAMI_DCID 0x000F
++#define BCSR_WHOAMI_CPLD 0x00F0
++#define BCSR_WHOAMI_BOARD 0x0F00
++
++#define BCSR_STATUS_PCMCIA0VS 0x0003
++#define BCSR_STATUS_PCMCIA1VS 0x000C
++#define BCSR_STATUS_SWAPBOOT 0x0040
++#define BCSR_STATUS_FLASHBUSY 0x0100
++#define BCSR_STATUS_IDECBLID 0x0200
++#define BCSR_STATUS_SD0WP 0x0400
++#define BCSR_STATUS_SD1WP 0x0800
++#define BCSR_STATUS_U0RXD 0x1000
++#define BCSR_STATUS_U1RXD 0x2000
++
++#define BCSR_SWITCHES_OCTAL 0x00FF
++#define BCSR_SWITCHES_DIP_1 0x0080
++#define BCSR_SWITCHES_DIP_2 0x0040
++#define BCSR_SWITCHES_DIP_3 0x0020
++#define BCSR_SWITCHES_DIP_4 0x0010
++#define BCSR_SWITCHES_DIP_5 0x0008
++#define BCSR_SWITCHES_DIP_6 0x0004
++#define BCSR_SWITCHES_DIP_7 0x0002
++#define BCSR_SWITCHES_DIP_8 0x0001
++#define BCSR_SWITCHES_ROTARY 0x0F00
++
++#define BCSR_RESETS_ETH 0x0001
++#define BCSR_RESETS_CAMERA 0x0002
++#define BCSR_RESETS_DC 0x0004
++#define BCSR_RESETS_IDE 0x0008
++/* not resets but in the same register */
++#define BCSR_RESETS_WSCFSM 0x0800
++#define BCSR_RESETS_PCS0MUX 0x1000
++#define BCSR_RESETS_PCS1MUX 0x2000
++#define BCSR_RESETS_SPISEL 0x4000
++#define BCSR_RESETS_SD1MUX 0x8000
++
++#define BCSR_PCMCIA_PC0VPP 0x0003
++#define BCSR_PCMCIA_PC0VCC 0x000C
++#define BCSR_PCMCIA_PC0DRVEN 0x0010
++#define BCSR_PCMCIA_PC0RST 0x0080
++#define BCSR_PCMCIA_PC1VPP 0x0300
++#define BCSR_PCMCIA_PC1VCC 0x0C00
++#define BCSR_PCMCIA_PC1DRVEN 0x1000
++#define BCSR_PCMCIA_PC1RST 0x8000
++
++#define BCSR_BOARD_LCDVEE 0x0001
++#define BCSR_BOARD_LCDVDD 0x0002
++#define BCSR_BOARD_LCDBL 0x0004
++#define BCSR_BOARD_CAMSNAP 0x0010
++#define BCSR_BOARD_CAMPWR 0x0020
++#define BCSR_BOARD_SD0PWR 0x0040
++#define BCSR_BOARD_SD1PWR 0x0080
++
++#define BCSR_LEDS_DECIMALS 0x00FF
++#define BCSR_LEDS_LED0 0x0100
++#define BCSR_LEDS_LED1 0x0200
++#define BCSR_LEDS_LED2 0x0400
++#define BCSR_LEDS_LED3 0x0800
++
++#define BCSR_SYSTEM_VDDI 0x001F
++#define BCSR_SYSTEM_POWEROFF 0x4000
++#define BCSR_SYSTEM_RESET 0x8000
++
++/* Bit positions for the different interrupt sources */
++#define BCSR_INT_IDE 0x0001
++#define BCSR_INT_ETH 0x0002
++#define BCSR_INT_PC0 0x0004
++#define BCSR_INT_PC0STSCHG 0x0008
++#define BCSR_INT_PC1 0x0010
++#define BCSR_INT_PC1STSCHG 0x0020
++#define BCSR_INT_DC 0x0040
++#define BCSR_INT_FLASHBUSY 0x0080
++#define BCSR_INT_PC0INSERT 0x0100
++#define BCSR_INT_PC0EJECT 0x0200
++#define BCSR_INT_PC1INSERT 0x0400
++#define BCSR_INT_PC1EJECT 0x0800
++#define BCSR_INT_SD0INSERT 0x1000
++#define BCSR_INT_SD0EJECT 0x2000
++#define BCSR_INT_SD1INSERT 0x4000
++#define BCSR_INT_SD1EJECT 0x8000
++
++#define AU1XXX_SMC91111_PHYS_ADDR (0x0D000300)
++#define AU1XXX_SMC91111_IRQ PB1200_ETH_INT
++
++#define AU1XXX_ATA_PHYS_ADDR (0x0C800000)
++#define AU1XXX_ATA_PHYS_LEN (0x100)
++#define AU1XXX_ATA_REG_OFFSET (5)
++#define AU1XXX_ATA_INT PB1200_IDE_INT
++#define AU1XXX_ATA_DDMA_REQ DSCR_CMD0_DMA_REQ1;
++#define AU1XXX_ATA_RQSIZE 128
++
++#define NAND_PHYS_ADDR 0x1C000000
++
++/* Timing values as described in databook, * ns value stripped of
++ * lower 2 bits.
++ * These defines are here rather than an SOC1200 generic file because
++ * the parts chosen on another board may be different and may require
++ * different timings.
++ */
++#define NAND_T_H (18 >> 2)
++#define NAND_T_PUL (30 >> 2)
++#define NAND_T_SU (30 >> 2)
++#define NAND_T_WH (30 >> 2)
++
++/* Bitfield shift amounts */
++#define NAND_T_H_SHIFT 0
++#define NAND_T_PUL_SHIFT 4
++#define NAND_T_SU_SHIFT 8
++#define NAND_T_WH_SHIFT 12
++
++#define NAND_TIMING ((NAND_T_H & 0xF) << NAND_T_H_SHIFT) | \
++ ((NAND_T_PUL & 0xF) << NAND_T_PUL_SHIFT) | \
++ ((NAND_T_SU & 0xF) << NAND_T_SU_SHIFT) | \
++ ((NAND_T_WH & 0xF) << NAND_T_WH_SHIFT)
++
++
++/*
++ * External Interrupts for Pb1200 as of 8/6/2004.
++ * Bit positions in the CPLD registers can be calculated by taking
++ * the interrupt define and subtracting the PB1200_INT_BEGIN value.
++ * *example: IDE bis pos is = 64 - 64
++ ETH bit pos is = 65 - 64
++ */
++#define PB1200_INT_BEGIN (AU1000_LAST_INTC1_INT + 1)
++#define PB1200_IDE_INT (PB1200_INT_BEGIN + 0)
++#define PB1200_ETH_INT (PB1200_INT_BEGIN + 1)
++#define PB1200_PC0_INT (PB1200_INT_BEGIN + 2)
++#define PB1200_PC0_STSCHG_INT (PB1200_INT_BEGIN + 3)
++#define PB1200_PC1_INT (PB1200_INT_BEGIN + 4)
++#define PB1200_PC1_STSCHG_INT (PB1200_INT_BEGIN + 5)
++#define PB1200_DC_INT (PB1200_INT_BEGIN + 6)
++#define PB1200_FLASHBUSY_INT (PB1200_INT_BEGIN + 7)
++#define PB1200_PC0_INSERT_INT (PB1200_INT_BEGIN + 8)
++#define PB1200_PC0_EJECT_INT (PB1200_INT_BEGIN + 9)
++#define PB1200_PC1_INSERT_INT (PB1200_INT_BEGIN + 10)
++#define PB1200_PC1_EJECT_INT (PB1200_INT_BEGIN + 11)
++#define PB1200_SD0_INSERT_INT (PB1200_INT_BEGIN + 12)
++#define PB1200_SD0_EJECT_INT (PB1200_INT_BEGIN + 13)
++#define PB1200_SD1_INSERT_INT (PB1200_INT_BEGIN + 14)
++#define PB1200_SD1_EJECT_INT (PB1200_INT_BEGIN + 15)
++
++#define PB1200_INT_END (PB1200_INT_BEGIN + 15)
++
++/* For drivers/pcmcia/au1000_db1x00.c */
++#define BOARD_PC0_INT PB1200_PC0_INT
++#define BOARD_PC1_INT PB1200_PC1_INT
++#define BOARD_CARD_INSERTED(SOCKET) bcsr->sig_status & (1<<(8+(2*SOCKET)))
++
++#endif /* __ASM_PB1200_H */
++
+diff -Nur linux-2.4.32-rc1/include/asm-mips/pb1550.h linux-2.4.32-rc1.mips/include/asm-mips/pb1550.h
+--- linux-2.4.32-rc1/include/asm-mips/pb1550.h 2005-01-19 15:10:12.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/pb1550.h 2005-01-30 09:01:28.000000000 +0100
+@@ -30,13 +30,11 @@
+
+ #define DBDMA_AC97_TX_CHAN DSCR_CMD0_PSC1_TX
+ #define DBDMA_AC97_RX_CHAN DSCR_CMD0_PSC1_RX
+-#define DBDMA_I2S_TX_CHAN DSCR_CMD0_PSC3_TX
+-#define DBDMA_I2S_RX_CHAN DSCR_CMD0_PSC3_RX
+-
+ #define SPI_PSC_BASE PSC0_BASE_ADDR
+ #define AC97_PSC_BASE PSC1_BASE_ADDR
+ #define SMBUS_PSC_BASE PSC2_BASE_ADDR
+ #define I2S_PSC_BASE PSC3_BASE_ADDR
++#define NAND_CS 1
+
+ #define BCSR_PHYS_ADDR 0xAF000000
+
+@@ -160,9 +158,23 @@
+ #define NAND_T_SU_SHIFT 8
+ #define NAND_T_WH_SHIFT 12
+
+-#define NAND_TIMING ((NAND_T_H & 0xF) << NAND_T_H_SHIFT) | \
+- ((NAND_T_PUL & 0xF) << NAND_T_PUL_SHIFT) | \
+- ((NAND_T_SU & 0xF) << NAND_T_SU_SHIFT) | \
+- ((NAND_T_WH & 0xF) << NAND_T_WH_SHIFT)
++#define NAND_TIMING ((NAND_T_H & 0xF) << NAND_T_H_SHIFT) | \
++ ((NAND_T_PUL & 0xF) << NAND_T_PUL_SHIFT) | \
++ ((NAND_T_SU & 0xF) << NAND_T_SU_SHIFT) | \
++ ((NAND_T_WH & 0xF) << NAND_T_WH_SHIFT)
++
++/*
++ * Daughter card information.
++ */
++#define DAUGHTER_CARD_BASE (0xAC000000)
++#define DAUGHTER_CARD_MEM_SIZE (0xADFFFFFF - DAUGHTER_CARD_BASE + 1)
++#define DAUGHTER_CARD_IRQ (AU1000_GPIO_3)
++
++/* DC_IDE and DC_ETHERNET */
++#define AU1XXX_ATA_PHYS_ADDR (0x0C000000)
++#define AU1XXX_ATA_REG_OFFSET (5)
++
++#define AU1XXX_SMC91111_PHYS_ADDR (0x0C000300)
++#define AU1XXX_SMC91111_IRQ AU1000_GPIO_3
+
+ #endif /* __ASM_PB1550_H */
+diff -Nur linux-2.4.32-rc1/include/asm-mips/reg.h linux-2.4.32-rc1.mips/include/asm-mips/reg.h
+--- linux-2.4.32-rc1/include/asm-mips/reg.h 2002-08-03 02:39:45.000000000 +0200
++++ linux-2.4.32-rc1.mips/include/asm-mips/reg.h 2005-04-14 12:41:44.000000000 +0200
+@@ -45,6 +45,9 @@
+ /*
+ * k0/k1 unsaved
+ */
++#define EF_REG26 32
++#define EF_REG27 33
++
+ #define EF_REG28 34
+ #define EF_REG29 35
+ #define EF_REG30 36
+@@ -60,6 +63,7 @@
+ #define EF_CP0_BADVADDR 41
+ #define EF_CP0_STATUS 42
+ #define EF_CP0_CAUSE 43
++#define EF_UNUSED0 44
+
+ #define EF_SIZE 180 /* size in bytes */
+
+diff -Nur linux-2.4.32-rc1/include/asm-mips/sgi/hpc3.h linux-2.4.32-rc1.mips/include/asm-mips/sgi/hpc3.h
+--- linux-2.4.32-rc1/include/asm-mips/sgi/hpc3.h 2003-08-25 13:44:44.000000000 +0200
++++ linux-2.4.32-rc1.mips/include/asm-mips/sgi/hpc3.h 2005-09-23 16:35:27.000000000 +0200
+@@ -128,26 +128,26 @@
+ volatile u32 rx_gfptr; /* current GIO fifo ptr */
+ volatile u32 rx_dfptr; /* current device fifo ptr */
+ u32 _unused1; /* padding */
+- volatile u32 rx_reset; /* reset register */
+-#define HPC3_ERXRST_CRESET 0x1 /* Reset dma channel and external controller */
+-#define HPC3_ERXRST_CLRIRQ 0x2 /* Clear channel interrupt */
+-#define HPC3_ERXRST_LBACK 0x4 /* Enable diagnostic loopback mode of Seeq8003 */
+-
+- volatile u32 rx_dconfig; /* DMA configuration register */
+-#define HPC3_ERXDCFG_D1 0x0000f /* Cycles to spend in D1 state for PIO */
+-#define HPC3_ERXDCFG_D2 0x000f0 /* Cycles to spend in D2 state for PIO */
+-#define HPC3_ERXDCFG_D3 0x00f00 /* Cycles to spend in D3 state for PIO */
+-#define HPC3_ERXDCFG_WCTRL 0x01000 /* Enable writes of desc into ex ctrl port */
+-#define HPC3_ERXDCFG_FRXDC 0x02000 /* Clear eop stat bits upon rxdc, hw seeq fix */
+-#define HPC3_ERXDCFG_FEOP 0x04000 /* Bad packet marker timeout enable */
+-#define HPC3_ERXDCFG_FIRQ 0x08000 /* Another bad packet timeout enable */
+-#define HPC3_ERXDCFG_PTO 0x30000 /* Programmed timeout value for above two */
+-
+- volatile u32 rx_pconfig; /* PIO configuration register */
+-#define HPC3_ERXPCFG_P1 0x000f /* Cycles to spend in P1 state for PIO */
+-#define HPC3_ERXPCFG_P2 0x00f0 /* Cycles to spend in P2 state for PIO */
+-#define HPC3_ERXPCFG_P3 0x0f00 /* Cycles to spend in P3 state for PIO */
+-#define HPC3_ERXPCFG_TST 0x1000 /* Diagnistic ram test feature bit */
++ volatile u32 reset; /* reset register */
++#define HPC3_ERST_CRESET 0x1 /* Reset dma channel and external controller */
++#define HPC3_ERST_CLRIRQ 0x2 /* Clear channel interrupt */
++#define HPC3_ERST_LBACK 0x4 /* Enable diagnostic loopback mode of Seeq8003 */
++
++ volatile u32 dconfig; /* DMA configuration register */
++#define HPC3_EDCFG_D1 0x0000f /* Cycles to spend in D1 state for PIO */
++#define HPC3_EDCFG_D2 0x000f0 /* Cycles to spend in D2 state for PIO */
++#define HPC3_EDCFG_D3 0x00f00 /* Cycles to spend in D3 state for PIO */
++#define HPC3_EDCFG_WCTRL 0x01000 /* Enable writes of desc into ex ctrl port */
++#define HPC3_EDCFG_FRXDC 0x02000 /* Clear eop stat bits upon rxdc, hw seeq fix */
++#define HPC3_EDCFG_FEOP 0x04000 /* Bad packet marker timeout enable */
++#define HPC3_EDCFG_FIRQ 0x08000 /* Another bad packet timeout enable */
++#define HPC3_EDCFG_PTO 0x30000 /* Programmed timeout value for above two */
++
++ volatile u32 pconfig; /* PIO configuration register */
++#define HPC3_EPCFG_P1 0x000f /* Cycles to spend in P1 state for PIO */
++#define HPC3_EPCFG_P2 0x00f0 /* Cycles to spend in P2 state for PIO */
++#define HPC3_EPCFG_P3 0x0f00 /* Cycles to spend in P3 state for PIO */
++#define HPC3_EPCFG_TST 0x1000 /* Diagnistic ram test feature bit */
+
+ u32 _unused2[0x1000/4 - 8]; /* padding */
+
+@@ -221,7 +221,7 @@
+ #define HPC3_BESTAT_PIDMASK 0x3f700 /* DMA channel parity identifier */
+
+ u32 _unused1[0x14000/4 - 5]; /* padding */
+-
++
+ /* Now direct PIO per-HPC3 peripheral access to external regs. */
+ volatile u32 scsi0_ext[256]; /* SCSI channel 0 external regs */
+ u32 _unused2[0x7c00/4];
+@@ -304,7 +304,7 @@
+ volatile u32 bbram[8192-50-14]; /* Battery backed ram */
+ };
+
+-/*
++/*
+ * It is possible to have two HPC3's within the address space on
+ * one machine, though only having one is more likely on an Indy.
+ */
+diff -Nur linux-2.4.32-rc1/include/asm-mips/tx4927/tx4927.h linux-2.4.32-rc1.mips/include/asm-mips/tx4927/tx4927.h
+--- linux-2.4.32-rc1/include/asm-mips/tx4927/tx4927.h 2003-08-25 13:44:44.000000000 +0200
++++ linux-2.4.32-rc1.mips/include/asm-mips/tx4927/tx4927.h 2004-11-22 19:02:10.000000000 +0100
+@@ -88,8 +88,8 @@
+
+
+ /* TX4927 Configuration registers (64-bit registers) */
+-#define TX4927_CONFIG_BASE 0xe300
+-#define TX4927_CONFIG_CCFG 0xe300
++#define TX4927_CONFIG_BASE 0xe000
++#define TX4927_CONFIG_CCFG 0xe000
+ #define TX4927_CONFIG_CCFG_RESERVED_42_63 BM_63_42
+ #define TX4927_CONFIG_CCFG_WDRST BM_41_41
+ #define TX4927_CONFIG_CCFG_WDREXEN BM_40_40
+@@ -124,14 +124,14 @@
+ #define TX4927_CONFIG_CCFG_ENDIAN BM_02_02
+ #define TX4927_CONFIG_CCFG_ARMODE BM_01_01
+ #define TX4927_CONFIG_CCFG_ACEHOLD BM_00_00
+-#define TX4927_CONFIG_REVID 0xe308
++#define TX4927_CONFIG_REVID 0xe008
+ #define TX4927_CONFIG_REVID_RESERVED_32_63 BM_32_63
+ #define TX4927_CONFIG_REVID_PCODE BM_16_31
+ #define TX4927_CONFIG_REVID_MJERREV BM_12_15
+ #define TX4927_CONFIG_REVID_MINEREV BM_08_11
+ #define TX4927_CONFIG_REVID_MJREV BM_04_07
+ #define TX4927_CONFIG_REVID_MINREV BM_00_03
+-#define TX4927_CONFIG_PCFG 0xe310
++#define TX4927_CONFIG_PCFG 0xe010
+ #define TX4927_CONFIG_PCFG_RESERVED_57_63 BM_57_63
+ #define TX4927_CONFIG_PCFG_DRVDATA BM_56_56
+ #define TX4927_CONFIG_PCFG_DRVCB BM_55_55
+@@ -197,10 +197,10 @@
+ #define TX4927_CONFIG_PCFG_DMASEL0_SIO1 BM_00_00
+ #define TX4927_CONFIG_PCFG_DMASEL0_ACLC0 BM_01_01
+ #define TX4927_CONFIG_PCFG_DMASEL0_ACLC2 BM_00_01
+-#define TX4927_CONFIG_TOEA 0xe318
++#define TX4927_CONFIG_TOEA 0xe018
+ #define TX4927_CONFIG_TOEA_RESERVED_36_63 BM_36_63
+ #define TX4927_CONFIG_TOEA_TOEA BM_00_35
+-#define TX4927_CONFIG_CLKCTR 0xe320
++#define TX4927_CONFIG_CLKCTR 0xe020
+ #define TX4927_CONFIG_CLKCTR_RESERVED_26_63 BM_26_63
+ #define TX4927_CONFIG_CLKCTR_ACLCKD BM_25_25
+ #define TX4927_CONFIG_CLKCTR_PIOCKD BM_24_24
+@@ -223,7 +223,7 @@
+ #define TX4927_CONFIG_CLKCTR_TM2RST BM_02_02
+ #define TX4927_CONFIG_CLKCTR_SIO0RST BM_01_01
+ #define TX4927_CONFIG_CLKCTR_SIO1RST BM_00_00
+-#define TX4927_CONFIG_GARBC 0xe330
++#define TX4927_CONFIG_GARBC 0xe030
+ #define TX4927_CONFIG_GARBC_RESERVED_10_63 BM_10_63
+ #define TX4927_CONFIG_GARBC_SET_09 BM_09_09
+ #define TX4927_CONFIG_GARBC_ARBMD BM_08_08
+@@ -243,7 +243,7 @@
+ #define TX4927_CONFIG_GARBC_PRIORITY_H3_PDMAC BM_00_00
+ #define TX4927_CONFIG_GARBC_PRIORITY_H3_DMAC BM_01_01
+ #define TX4927_CONFIG_GARBC_PRIORITY_H3_BAD_VALUE BM_00_01
+-#define TX4927_CONFIG_RAMP 0xe348
++#define TX4927_CONFIG_RAMP 0xe048
+ #define TX4927_CONFIG_RAMP_RESERVED_20_63 BM_20_63
+ #define TX4927_CONFIG_RAMP_RAMP BM_00_19
+ #define TX4927_CONFIG_LIMIT 0xefff
+@@ -456,7 +456,7 @@
+ #define TX4927_ACLC_ACINTSTS 0xf710
+ #define TX4927_ACLC_ACINTMSTS 0xf714
+ #define TX4927_ACLC_ACINTEN 0xf718
+-#define TX4927_ACLC_ACINTDIS 0xfR71c
++#define TX4927_ACLC_ACINTDIS 0xf71c
+ #define TX4927_ACLC_ACSEMAPH 0xf720
+ #define TX4927_ACLC_ACGPIDAT 0xf740
+ #define TX4927_ACLC_ACGPODAT 0xf744
+diff -Nur linux-2.4.32-rc1/include/asm-mips/unistd.h linux-2.4.32-rc1.mips/include/asm-mips/unistd.h
+--- linux-2.4.32-rc1/include/asm-mips/unistd.h 2005-01-19 15:10:12.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips/unistd.h 2004-11-24 21:30:06.000000000 +0100
+@@ -760,7 +760,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ /*
+@@ -788,7 +788,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #define _syscall2(type,name,atype,a,btype,b) \
+@@ -813,7 +813,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #define _syscall3(type,name,atype,a,btype,b,ctype,c) \
+@@ -839,7 +839,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \
+@@ -865,7 +865,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #if (_MIPS_SIM == _MIPS_SIM_ABI32)
+@@ -902,7 +902,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #define _syscall6(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e,ftype,f) \
+@@ -935,7 +935,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #endif /* (_MIPS_SIM == _MIPS_SIM_ABI32) */
+@@ -966,7 +966,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #define _syscall6(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e,ftype,f) \
+@@ -995,7 +995,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #endif /* (_MIPS_SIM == _MIPS_SIM_NABI32) || (_MIPS_SIM == _MIPS_SIM_ABI64) */
+diff -Nur linux-2.4.32-rc1/include/asm-mips64/checksum.h linux-2.4.32-rc1.mips/include/asm-mips64/checksum.h
+--- linux-2.4.32-rc1/include/asm-mips64/checksum.h 2005-01-19 15:10:12.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips64/checksum.h 2005-09-20 12:58:50.000000000 +0200
+@@ -144,7 +144,7 @@
+ "daddu\t%0, %4\n\t"
+ "dsll32\t$1, %0, 0\n\t"
+ "daddu\t%0, $1\n\t"
+- "dsrl32\t%0, %0, 0\n\t"
++ "dsra32\t%0, %0, 0\n\t"
+ ".set\tat"
+ : "=&r" (sum)
+ : "0" (daddr), "r"(saddr),
+diff -Nur linux-2.4.32-rc1/include/asm-mips64/elf.h linux-2.4.32-rc1.mips/include/asm-mips64/elf.h
+--- linux-2.4.32-rc1/include/asm-mips64/elf.h 2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips64/elf.h 2005-04-14 12:41:44.000000000 +0200
+@@ -64,9 +64,10 @@
+ #define USE_ELF_CORE_DUMP
+ #define ELF_EXEC_PAGESIZE PAGE_SIZE
+
+-#define ELF_CORE_COPY_REGS(_dest,_regs) \
+- memcpy((char *) &_dest, (char *) _regs, \
+- sizeof(struct pt_regs));
++extern void dump_regs(elf_greg_t *, struct pt_regs *regs);
++
++#define ELF_CORE_COPY_REGS(elf_regs, regs) \
++ dump_regs((elf_greg_t *)&(elf_regs), regs);
+
+ /* This yields a mask that user programs can use to figure out what
+ instruction set this cpu supports. This could be done in userspace,
+diff -Nur linux-2.4.32-rc1/include/asm-mips64/hazards.h linux-2.4.32-rc1.mips/include/asm-mips64/hazards.h
+--- linux-2.4.32-rc1/include/asm-mips64/hazards.h 2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips64/hazards.h 2005-06-06 16:46:22.000000000 +0200
+@@ -3,7 +3,7 @@
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+- * Copyright (C) 2003 Ralf Baechle
++ * Copyright (C) 2003, 2004 Ralf Baechle
+ */
+ #ifndef _ASM_HAZARDS_H
+ #define _ASM_HAZARDS_H
+@@ -12,37 +12,200 @@
+
+ #ifdef __ASSEMBLY__
+
++ .macro _ssnop
++ sll $0, $0, 1
++ .endm
++
+ /*
+ * RM9000 hazards. When the JTLB is updated by tlbwi or tlbwr, a subsequent
+ * use of the JTLB for instructions should not occur for 4 cpu cycles and use
+ * for data translations should not occur for 3 cpu cycles.
+ */
+ #ifdef CONFIG_CPU_RM9000
+-#define rm9000_tlb_hazard \
++
++#define mtc0_tlbw_hazard \
++ .set push; \
+ .set mips32; \
+- ssnop; ssnop; ssnop; ssnop; \
+- .set mips0
++ _ssnop; _ssnop; _ssnop; _ssnop; \
++ .set pop
++
++#define tlbw_eret_hazard \
++ .set push; \
++ .set mips32; \
++ _ssnop; _ssnop; _ssnop; _ssnop; \
++ .set pop
++
+ #else
+-#define rm9000_tlb_hazard
++
++/*
++ * The taken branch will result in a two cycle penalty for the two killed
++ * instructions on R4000 / R4400. Other processors only have a single cycle
++ * hazard so this is nice trick to have an optimal code for a range of
++ * processors.
++ */
++#define mtc0_tlbw_hazard \
++ b . + 8
++#define tlbw_eret_hazard \
++ nop
+ #endif
+
++/*
++ * mtc0->mfc0 hazard
++ * The 24K has a 2 cycle mtc0/mfc0 execution hazard.
++ * It is a MIPS32R2 processor so ehb will clear the hazard.
++ */
++
++#ifdef CONFIG_CPU_MIPSR2
++/*
++ * Use a macro for ehb unless explicit support for MIPSR2 is enabled
++ */
++ .macro ehb
++ sll $0, $0, 3
++ .endm
++
++#define irq_enable_hazard \
++ ehb # irq_enable_hazard
++
++#define irq_disable_hazard \
++ ehb # irq_disable_hazard
++
++#elif defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_RM9000)
++
++/*
++ * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
++ */
++
++#define irq_enable_hazard
++
++#define irq_disable_hazard
++
+ #else
+
+ /*
++ * Classic MIPS needs 1 - 3 nops or ssnops
++ */
++#define irq_enable_hazard
++#define irq_disable_hazard \
++ _ssnop; _ssnop; _ssnop
++
++#endif
++
++#else /* __ASSEMBLY__ */
++
++/*
+ * RM9000 hazards. When the JTLB is updated by tlbwi or tlbwr, a subsequent
+ * use of the JTLB for instructions should not occur for 4 cpu cycles and use
+ * for data translations should not occur for 3 cpu cycles.
+ */
+ #ifdef CONFIG_CPU_RM9000
+-#define rm9000_tlb_hazard() \
++
++#define mtc0_tlbw_hazard() \
++ __asm__ __volatile__( \
++ ".set\tmips32\n\t" \
++ "_ssnop; _ssnop; _ssnop; _ssnop\n\t" \
++ ".set\tmips0")
++
++#define tlbw_use_hazard() \
+ __asm__ __volatile__( \
+ ".set\tmips32\n\t" \
+- "ssnop; ssnop; ssnop; ssnop\n\t" \
++ "_ssnop; _ssnop; _ssnop; _ssnop\n\t" \
+ ".set\tmips0")
+ #else
+-#define rm9000_tlb_hazard() do { } while (0)
++
++/*
++ * Overkill warning ...
++ */
++#define mtc0_tlbw_hazard() \
++ __asm__ __volatile__( \
++ ".set noreorder\n\t" \
++ "nop; nop; nop; nop; nop; nop;\n\t" \
++ ".set reorder\n\t")
++
++#define tlbw_use_hazard() \
++ __asm__ __volatile__( \
++ ".set noreorder\n\t" \
++ "nop; nop; nop; nop; nop; nop;\n\t" \
++ ".set reorder\n\t")
++
+ #endif
+
++/*
++ * mtc0->mfc0 hazard
++ * The 24K has a 2 cycle mtc0/mfc0 execution hazard.
++ * It is a MIPS32R2 processor so ehb will clear the hazard.
++ */
++
++#ifdef CONFIG_CPU_MIPSR2
++/*
++ * Use a macro for ehb unless explicit support for MIPSR2 is enabled
++ */
++__asm__(
++ " .macro ehb \n\t"
++ " sll $0, $0, 3 \n\t"
++ " .endm \n\t"
++ " \n\t"
++ " .macro\tirq_enable_hazard \n\t"
++ " ehb \n\t"
++ " .endm \n\t"
++ " \n\t"
++ " .macro\tirq_disable_hazard \n\t"
++ " ehb \n\t"
++ " .endm");
++
++#define irq_enable_hazard() \
++ __asm__ __volatile__( \
++ "ehb\t\t\t\t# irq_enable_hazard")
++
++#define irq_disable_hazard() \
++ __asm__ __volatile__( \
++ "ehb\t\t\t\t# irq_disable_hazard")
++
++#elif defined(CONFIG_CPU_R10000)
++
++/*
++ * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
++ */
++
++__asm__(
++ " .macro\tirq_enable_hazard \n\t"
++ " .endm \n\t"
++ " \n\t"
++ " .macro\tirq_disable_hazard \n\t"
++ " .endm");
++
++#define irq_enable_hazard() do { } while (0)
++#define irq_disable_hazard() do { } while (0)
++
++#else
++
++/*
++ * Default for classic MIPS processors. Assume worst case hazards but don't
++ * care about the irq_enable_hazard - sooner or later the hardware will
++ * enable it and we don't care when exactly.
++ */
++
++__asm__(
++ " .macro _ssnop \n\t"
++ " sll $0, $2, 1 \n\t"
++ " .endm \n\t"
++ " \n\t"
++ " # \n\t"
++ " # There is a hazard but we do not care \n\t"
++ " # \n\t"
++ " .macro\tirq_enable_hazard \n\t"
++ " .endm \n\t"
++ " \n\t"
++ " .macro\tirq_disable_hazard \n\t"
++ " _ssnop; _ssnop; _ssnop \n\t"
++ " .endm");
++
++#define irq_enable_hazard() do { } while (0)
++#define irq_disable_hazard() \
++ __asm__ __volatile__( \
++ "_ssnop; _ssnop; _ssnop;\t\t# irq_disable_hazard")
++
+ #endif
+
++#endif /* __ASSEMBLY__ */
++
+ #endif /* _ASM_HAZARDS_H */
+diff -Nur linux-2.4.32-rc1/include/asm-mips64/ide.h linux-2.4.32-rc1.mips/include/asm-mips64/ide.h
+--- linux-2.4.32-rc1/include/asm-mips64/ide.h 2003-08-25 13:44:44.000000000 +0200
++++ linux-2.4.32-rc1.mips/include/asm-mips64/ide.h 2005-04-19 14:26:53.000000000 +0200
+@@ -32,12 +32,12 @@
+
+ extern struct ide_ops *ide_ops;
+
+-static __inline__ int ide_default_irq(ide_ioreg_t base)
++static inline int ide_default_irq(ide_ioreg_t base)
+ {
+ return ide_ops->ide_default_irq(base);
+ }
+
+-static __inline__ ide_ioreg_t ide_default_io_base(int index)
++static inline ide_ioreg_t ide_default_io_base(int index)
+ {
+ return ide_ops->ide_default_io_base(index);
+ }
+@@ -48,7 +48,7 @@
+ ide_ops->ide_init_hwif_ports(hw, data_port, ctrl_port, irq);
+ }
+
+-static __inline__ void ide_init_default_hwifs(void)
++static inline void ide_init_default_hwifs(void)
+ {
+ #ifndef CONFIG_BLK_DEV_IDEPCI
+ hw_regs_t hw;
+@@ -68,7 +68,89 @@
+ #define ide_ack_intr(hwif) ((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1)
+ #endif
+
+-#include <asm-generic/ide_iops.h>
++/* MIPS port and memory-mapped I/O string operations. */
++
++static inline void __ide_flush_dcache_range(unsigned long addr, unsigned long size)
++{
++ if (cpu_has_dc_aliases) {
++ unsigned long end = addr + size;
++ for (; addr < end; addr += PAGE_SIZE)
++ flush_dcache_page(virt_to_page(addr));
++ }
++}
++
++static inline void __ide_insw(unsigned long port, void *addr,
++ unsigned int count)
++{
++ insw(port, addr, count);
++ __ide_flush_dcache_range((unsigned long)addr, count * 2);
++}
++
++static inline void __ide_insl(unsigned long port, void *addr, unsigned int count)
++{
++ insl(port, addr, count);
++ __ide_flush_dcache_range((unsigned long)addr, count * 4);
++}
++
++static inline void __ide_outsw(unsigned long port, const void *addr,
++ unsigned long count)
++{
++ outsw(port, addr, count);
++ __ide_flush_dcache_range((unsigned long)addr, count * 2);
++}
++
++static inline void __ide_outsl(unsigned long port, const void *addr,
++ unsigned long count)
++{
++ outsl(port, addr, count);
++ __ide_flush_dcache_range((unsigned long)addr, count * 4);
++}
++
++static inline void __ide_mm_insw(unsigned long port, void *addr, u32 count)
++{
++ unsigned long start = (unsigned long) addr;
++
++ while (count--) {
++ *(u16 *)addr = readw(port);
++ addr += 2;
++ }
++ __ide_flush_dcache_range(start, count * 2);
++}
++
++static inline void __ide_mm_insl(unsigned long port, void *addr, u32 count)
++{
++ unsigned long start = (unsigned long) addr;
++
++ while (count--) {
++ *(u32 *)addr = readl(port);
++ addr += 4;
++ }
++ __ide_flush_dcache_range(start, count * 4);
++}
++
++static inline void __ide_mm_outsw(unsigned long port, const void *addr,
++ u32 count)
++{
++ unsigned long start = (unsigned long) addr;
++
++ while (count--) {
++ writew(*(u16 *)addr, port);
++ addr += 2;
++ }
++ __ide_flush_dcache_range(start, count * 2);
++}
++
++static inline void __ide_mm_outsl(unsigned long port, const void *addr,
++ u32 count)
++{
++ unsigned long start = (unsigned long) addr;
++
++ while (count--) {
++ writel(*(u32 *)addr, port);
++ addr += 4;
++ }
++ __ide_flush_dcache_range(start, count * 4);
++}
+
+ #endif /* __KERNEL__ */
+
+diff -Nur linux-2.4.32-rc1/include/asm-mips64/io.h linux-2.4.32-rc1.mips/include/asm-mips64/io.h
+--- linux-2.4.32-rc1/include/asm-mips64/io.h 2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips64/io.h 2005-04-19 14:24:53.000000000 +0200
+@@ -414,7 +414,8 @@
+ return __ioswab32(__val);
+ }
+
+-static inline void __outsb(unsigned long port, void *addr, unsigned int count)
++static inline void __outsb(unsigned long port, const void *addr,
++ unsigned int count)
+ {
+ while (count--) {
+ outb(*(u8 *)addr, port);
+@@ -430,7 +431,8 @@
+ }
+ }
+
+-static inline void __outsw(unsigned long port, void *addr, unsigned int count)
++static inline void __outsw(unsigned long port, const void *addr,
++ unsigned int count)
+ {
+ while (count--) {
+ outw(*(u16 *)addr, port);
+@@ -446,7 +448,8 @@
+ }
+ }
+
+-static inline void __outsl(unsigned long port, void *addr, unsigned int count)
++static inline void __outsl(unsigned long port, const void *addr,
++ unsigned int count)
+ {
+ while (count--) {
+ outl(*(u32 *)addr, port);
+diff -Nur linux-2.4.32-rc1/include/asm-mips64/mipsregs.h linux-2.4.32-rc1.mips/include/asm-mips64/mipsregs.h
+--- linux-2.4.32-rc1/include/asm-mips64/mipsregs.h 2005-01-19 15:10:12.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips64/mipsregs.h 2005-02-06 22:24:22.000000000 +0100
+@@ -757,10 +757,18 @@
+ #define read_c0_config1() __read_32bit_c0_register($16, 1)
+ #define read_c0_config2() __read_32bit_c0_register($16, 2)
+ #define read_c0_config3() __read_32bit_c0_register($16, 3)
++#define read_c0_config4() __read_32bit_c0_register($16, 4)
++#define read_c0_config5() __read_32bit_c0_register($16, 5)
++#define read_c0_config6() __read_32bit_c0_register($16, 6)
++#define read_c0_config7() __read_32bit_c0_register($16, 7)
+ #define write_c0_config(val) __write_32bit_c0_register($16, 0, val)
+ #define write_c0_config1(val) __write_32bit_c0_register($16, 1, val)
+ #define write_c0_config2(val) __write_32bit_c0_register($16, 2, val)
+ #define write_c0_config3(val) __write_32bit_c0_register($16, 3, val)
++#define write_c0_config4(val) __write_32bit_c0_register($16, 4, val)
++#define write_c0_config5(val) __write_32bit_c0_register($16, 5, val)
++#define write_c0_config6(val) __write_32bit_c0_register($16, 6, val)
++#define write_c0_config7(val) __write_32bit_c0_register($16, 7, val)
+
+ /*
+ * The WatchLo register. There may be upto 8 of them.
+@@ -856,42 +864,34 @@
+ */
+ static inline void tlb_probe(void)
+ {
+- rm9000_tlb_hazard();
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ "tlbp\n\t"
+ ".set reorder");
+- rm9000_tlb_hazard();
+ }
+
+ static inline void tlb_read(void)
+ {
+- rm9000_tlb_hazard();
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ "tlbr\n\t"
+ ".set reorder");
+- rm9000_tlb_hazard();
+ }
+
+ static inline void tlb_write_indexed(void)
+ {
+- rm9000_tlb_hazard();
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ "tlbwi\n\t"
+ ".set reorder");
+- rm9000_tlb_hazard();
+ }
+
+ static inline void tlb_write_random(void)
+ {
+- rm9000_tlb_hazard();
+ __asm__ __volatile__(
+ ".set noreorder\n\t"
+ "tlbwr\n\t"
+ ".set reorder");
+- rm9000_tlb_hazard();
+ }
+
+ /*
+diff -Nur linux-2.4.32-rc1/include/asm-mips64/reg.h linux-2.4.32-rc1.mips/include/asm-mips64/reg.h
+--- linux-2.4.32-rc1/include/asm-mips64/reg.h 2003-08-25 13:44:44.000000000 +0200
++++ linux-2.4.32-rc1.mips/include/asm-mips64/reg.h 2005-04-14 12:41:44.000000000 +0200
+@@ -46,6 +46,9 @@
+ /*
+ * k0/k1 unsaved
+ */
++#define EF_REG26 26
++#define EF_REG27 27
++
+ #define EF_REG28 28
+ #define EF_REG29 29
+ #define EF_REG30 30
+diff -Nur linux-2.4.32-rc1/include/asm-mips64/sgi/hpc3.h linux-2.4.32-rc1.mips/include/asm-mips64/sgi/hpc3.h
+--- linux-2.4.32-rc1/include/asm-mips64/sgi/hpc3.h 2003-08-25 13:44:44.000000000 +0200
++++ linux-2.4.32-rc1.mips/include/asm-mips64/sgi/hpc3.h 2005-09-23 16:35:27.000000000 +0200
+@@ -128,26 +128,26 @@
+ volatile u32 rx_gfptr; /* current GIO fifo ptr */
+ volatile u32 rx_dfptr; /* current device fifo ptr */
+ u32 _unused1; /* padding */
+- volatile u32 rx_reset; /* reset register */
+-#define HPC3_ERXRST_CRESET 0x1 /* Reset dma channel and external controller */
+-#define HPC3_ERXRST_CLRIRQ 0x2 /* Clear channel interrupt */
+-#define HPC3_ERXRST_LBACK 0x4 /* Enable diagnostic loopback mode of Seeq8003 */
+-
+- volatile u32 rx_dconfig; /* DMA configuration register */
+-#define HPC3_ERXDCFG_D1 0x0000f /* Cycles to spend in D1 state for PIO */
+-#define HPC3_ERXDCFG_D2 0x000f0 /* Cycles to spend in D2 state for PIO */
+-#define HPC3_ERXDCFG_D3 0x00f00 /* Cycles to spend in D3 state for PIO */
+-#define HPC3_ERXDCFG_WCTRL 0x01000 /* Enable writes of desc into ex ctrl port */
+-#define HPC3_ERXDCFG_FRXDC 0x02000 /* Clear eop stat bits upon rxdc, hw seeq fix */
+-#define HPC3_ERXDCFG_FEOP 0x04000 /* Bad packet marker timeout enable */
+-#define HPC3_ERXDCFG_FIRQ 0x08000 /* Another bad packet timeout enable */
+-#define HPC3_ERXDCFG_PTO 0x30000 /* Programmed timeout value for above two */
+-
+- volatile u32 rx_pconfig; /* PIO configuration register */
+-#define HPC3_ERXPCFG_P1 0x000f /* Cycles to spend in P1 state for PIO */
+-#define HPC3_ERXPCFG_P2 0x00f0 /* Cycles to spend in P2 state for PIO */
+-#define HPC3_ERXPCFG_P3 0x0f00 /* Cycles to spend in P3 state for PIO */
+-#define HPC3_ERXPCFG_TST 0x1000 /* Diagnistic ram test feature bit */
++ volatile u32 reset; /* reset register */
++#define HPC3_ERST_CRESET 0x1 /* Reset dma channel and external controller */
++#define HPC3_ERST_CLRIRQ 0x2 /* Clear channel interrupt */
++#define HPC3_ERST_LBACK 0x4 /* Enable diagnostic loopback mode of Seeq8003 */
++
++ volatile u32 dconfig; /* DMA configuration register */
++#define HPC3_EDCFG_D1 0x0000f /* Cycles to spend in D1 state for PIO */
++#define HPC3_EDCFG_D2 0x000f0 /* Cycles to spend in D2 state for PIO */
++#define HPC3_EDCFG_D3 0x00f00 /* Cycles to spend in D3 state for PIO */
++#define HPC3_EDCFG_WCTRL 0x01000 /* Enable writes of desc into ex ctrl port */
++#define HPC3_EDCFG_FRXDC 0x02000 /* Clear eop stat bits upon rxdc, hw seeq fix */
++#define HPC3_EDCFG_FEOP 0x04000 /* Bad packet marker timeout enable */
++#define HPC3_EDCFG_FIRQ 0x08000 /* Another bad packet timeout enable */
++#define HPC3_EDCFG_PTO 0x30000 /* Programmed timeout value for above two */
++
++ volatile u32 pconfig; /* PIO configuration register */
++#define HPC3_EPCFG_P1 0x000f /* Cycles to spend in P1 state for PIO */
++#define HPC3_EPCFG_P2 0x00f0 /* Cycles to spend in P2 state for PIO */
++#define HPC3_EPCFG_P3 0x0f00 /* Cycles to spend in P3 state for PIO */
++#define HPC3_EPCFG_TST 0x1000 /* Diagnistic ram test feature bit */
+
+ u32 _unused2[0x1000/4 - 8]; /* padding */
+
+@@ -221,7 +221,7 @@
+ #define HPC3_BESTAT_PIDMASK 0x3f700 /* DMA channel parity identifier */
+
+ u32 _unused1[0x14000/4 - 5]; /* padding */
+-
++
+ /* Now direct PIO per-HPC3 peripheral access to external regs. */
+ volatile u32 scsi0_ext[256]; /* SCSI channel 0 external regs */
+ u32 _unused2[0x7c00/4];
+@@ -304,7 +304,7 @@
+ volatile u32 bbram[8192-50-14]; /* Battery backed ram */
+ };
+
+-/*
++/*
+ * It is possible to have two HPC3's within the address space on
+ * one machine, though only having one is more likely on an Indy.
+ */
+diff -Nur linux-2.4.32-rc1/include/asm-mips64/sn/nmi.h linux-2.4.32-rc1.mips/include/asm-mips64/sn/nmi.h
+--- linux-2.4.32-rc1/include/asm-mips64/sn/nmi.h 2002-11-29 00:53:15.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips64/sn/nmi.h 2002-08-06 01:53:40.000000000 +0200
+@@ -8,7 +8,7 @@
+ #ifndef __ASM_SN_NMI_H
+ #define __ASM_SN_NMI_H
+
+-#ident "$Revision: 1.2.4.2 $"
++#ident "$Revision: 1.2.4.1 $"
+
+ #include <asm/sn/addrs.h>
+
+diff -Nur linux-2.4.32-rc1/include/asm-mips64/unistd.h linux-2.4.32-rc1.mips/include/asm-mips64/unistd.h
+--- linux-2.4.32-rc1/include/asm-mips64/unistd.h 2005-01-19 15:10:12.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-mips64/unistd.h 2004-11-24 21:30:06.000000000 +0100
+@@ -760,7 +760,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ /*
+@@ -788,7 +788,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #define _syscall2(type,name,atype,a,btype,b) \
+@@ -813,7 +813,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #define _syscall3(type,name,atype,a,btype,b,ctype,c) \
+@@ -839,7 +839,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \
+@@ -865,7 +865,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #if (_MIPS_SIM == _MIPS_SIM_ABI32)
+@@ -902,7 +902,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #define _syscall6(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e,ftype,f) \
+@@ -935,7 +935,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #endif /* (_MIPS_SIM == _MIPS_SIM_ABI32) */
+@@ -966,7 +966,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #define _syscall6(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e,ftype,f) \
+@@ -995,7 +995,7 @@
+ if (__a3 == 0) \
+ return (type) __v0; \
+ errno = __v0; \
+- return -1; \
++ return (type)-1; \
+ }
+
+ #endif /* (_MIPS_SIM == _MIPS_SIM_NABI32) || (_MIPS_SIM == _MIPS_SIM_ABI64) */
+diff -Nur linux-2.4.32-rc1/include/asm-ppc/param.h linux-2.4.32-rc1.mips/include/asm-ppc/param.h
+--- linux-2.4.32-rc1/include/asm-ppc/param.h 2003-06-13 16:51:38.000000000 +0200
++++ linux-2.4.32-rc1.mips/include/asm-ppc/param.h 2003-07-05 05:23:46.000000000 +0200
+@@ -3,6 +3,9 @@
+
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
+ #endif
+
+ #define EXEC_PAGESIZE 4096
+diff -Nur linux-2.4.32-rc1/include/asm-s390/param.h linux-2.4.32-rc1.mips/include/asm-s390/param.h
+--- linux-2.4.32-rc1/include/asm-s390/param.h 2001-02-13 23:13:44.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-s390/param.h 2001-03-09 21:34:48.000000000 +0100
+@@ -11,6 +11,9 @@
+
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
+ #endif
+
+ #define EXEC_PAGESIZE 4096
+diff -Nur linux-2.4.32-rc1/include/asm-sh/param.h linux-2.4.32-rc1.mips/include/asm-sh/param.h
+--- linux-2.4.32-rc1/include/asm-sh/param.h 2001-01-04 22:19:13.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-sh/param.h 2001-01-11 05:02:45.000000000 +0100
+@@ -3,6 +3,9 @@
+
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
+ #endif
+
+ #define EXEC_PAGESIZE 4096
+diff -Nur linux-2.4.32-rc1/include/asm-sparc/param.h linux-2.4.32-rc1.mips/include/asm-sparc/param.h
+--- linux-2.4.32-rc1/include/asm-sparc/param.h 2000-10-30 23:34:12.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-sparc/param.h 2000-11-23 03:00:56.000000000 +0100
+@@ -4,6 +4,9 @@
+
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
+ #endif
+
+ #define EXEC_PAGESIZE 8192 /* Thanks for sun4's we carry baggage... */
+diff -Nur linux-2.4.32-rc1/include/asm-sparc64/param.h linux-2.4.32-rc1.mips/include/asm-sparc64/param.h
+--- linux-2.4.32-rc1/include/asm-sparc64/param.h 2000-10-30 23:34:12.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/asm-sparc64/param.h 2000-11-23 03:00:56.000000000 +0100
+@@ -4,6 +4,9 @@
+
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
+ #endif
+
+ #define EXEC_PAGESIZE 8192 /* Thanks for sun4's we carry baggage... */
+diff -Nur linux-2.4.32-rc1/include/linux/i2c-algo-au1550.h linux-2.4.32-rc1.mips/include/linux/i2c-algo-au1550.h
+--- linux-2.4.32-rc1/include/linux/i2c-algo-au1550.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/linux/i2c-algo-au1550.h 2004-07-07 02:38:02.000000000 +0200
+@@ -0,0 +1,31 @@
++/*
++ * Copyright (C) 2004 Embedded Edge, LLC <dan@embeddededge.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#ifndef I2C_ALGO_AU1550_H
++#define I2C_ALGO_AU1550_H 1
++
++struct i2c_algo_au1550_data {
++ u32 psc_base;
++ int xfer_timeout;
++ int ack_timeout;
++};
++
++int i2c_au1550_add_bus(struct i2c_adapter *);
++int i2c_au1550_del_bus(struct i2c_adapter *);
++
++#endif /* I2C_ALGO_AU1550_H */
+diff -Nur linux-2.4.32-rc1/include/linux/i2c-id.h linux-2.4.32-rc1.mips/include/linux/i2c-id.h
+--- linux-2.4.32-rc1/include/linux/i2c-id.h 2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/linux/i2c-id.h 2004-07-07 02:38:02.000000000 +0200
+@@ -156,6 +156,8 @@
+
+ #define I2C_ALGO_SGI 0x130000 /* SGI algorithm */
+
++#define I2C_ALGO_AU1550 0x140000 /* Alchemy Au1550 PSC */
++
+ #define I2C_ALGO_EXP 0x800000 /* experimental */
+
+ #define I2C_ALGO_MASK 0xff0000 /* Mask for algorithms */
+@@ -204,6 +206,9 @@
+ #define I2C_HW_SGI_VINO 0x00
+ #define I2C_HW_SGI_MACE 0x01
+
++/* --- Au1550 PSC adapters */
++#define I2C_HW_AU1550_PSC 0x00
++
+ /* --- SMBus only adapters */
+ #define I2C_HW_SMBUS_PIIX4 0x00
+ #define I2C_HW_SMBUS_ALI15X3 0x01
+diff -Nur linux-2.4.32-rc1/include/linux/sched.h linux-2.4.32-rc1.mips/include/linux/sched.h
+--- linux-2.4.32-rc1/include/linux/sched.h 2005-01-19 15:10:12.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/linux/sched.h 2004-11-29 18:47:18.000000000 +0100
+@@ -617,6 +617,10 @@
+ extern int in_group_p(gid_t);
+ extern int in_egroup_p(gid_t);
+
++extern ATTRIB_NORET void cpu_idle(void);
++
++extern void release_task(struct task_struct * p);
++
+ extern void proc_caches_init(void);
+ extern void flush_signals(struct task_struct *);
+ extern void flush_signal_handlers(struct task_struct *);
+diff -Nur linux-2.4.32-rc1/include/linux/serial.h linux-2.4.32-rc1.mips/include/linux/serial.h
+--- linux-2.4.32-rc1/include/linux/serial.h 2002-08-03 02:39:45.000000000 +0200
++++ linux-2.4.32-rc1.mips/include/linux/serial.h 2004-07-31 02:17:57.000000000 +0200
+@@ -75,7 +75,8 @@
+ #define PORT_16654 11
+ #define PORT_16850 12
+ #define PORT_RSA 13 /* RSA-DV II/S card */
+-#define PORT_MAX 13
++#define PORT_SB1250 14
++#define PORT_MAX 14
+
+ #define SERIAL_IO_PORT 0
+ #define SERIAL_IO_HUB6 1
+diff -Nur linux-2.4.32-rc1/include/linux/swap.h linux-2.4.32-rc1.mips/include/linux/swap.h
+--- linux-2.4.32-rc1/include/linux/swap.h 2005-01-19 15:10:12.000000000 +0100
++++ linux-2.4.32-rc1.mips/include/linux/swap.h 2004-11-29 18:47:18.000000000 +0100
+@@ -1,6 +1,12 @@
+ #ifndef _LINUX_SWAP_H
+ #define _LINUX_SWAP_H
+
++#include <linux/config.h>
++
++#define MAX_SWAPFILES 32
++
++#ifdef __KERNEL__
++
+ #include <linux/spinlock.h>
+ #include <asm/page.h>
+
+@@ -8,8 +14,6 @@
+ #define SWAP_FLAG_PRIO_MASK 0x7fff
+ #define SWAP_FLAG_PRIO_SHIFT 0
+
+-#define MAX_SWAPFILES 32
+-
+ /*
+ * Magic header for a swap area. The first part of the union is
+ * what the swap magic looks like for the old (limited to 128MB)
+@@ -39,8 +43,6 @@
+ } info;
+ };
+
+-#ifdef __KERNEL__
+-
+ /*
+ * Max bad pages in the new format..
+ */
+diff -Nur linux-2.4.32-rc1/include/video/newport.h linux-2.4.32-rc1.mips/include/video/newport.h
+--- linux-2.4.32-rc1/include/video/newport.h 2001-04-12 21:20:31.000000000 +0200
++++ linux-2.4.32-rc1.mips/include/video/newport.h 2004-09-23 15:32:29.000000000 +0200
+@@ -291,8 +291,6 @@
+ unsigned int _unused2[0x1ef];
+ struct newport_cregs cgo;
+ };
+-extern struct newport_regs *npregs;
+-
+
+ typedef struct {
+ unsigned int drawmode1;
+@@ -450,38 +448,26 @@
+
+ /* Miscellaneous NEWPORT routines. */
+ #define BUSY_TIMEOUT 100000
+-static __inline__ int newport_wait(void)
++static __inline__ int newport_wait(struct newport_regs *regs)
+ {
+- int i = 0;
++ int t = BUSY_TIMEOUT;
+
+- while(i < BUSY_TIMEOUT)
+- if(!(npregs->cset.status & NPORT_STAT_GBUSY))
++ while (t--)
++ if (!(regs->cset.status & NPORT_STAT_GBUSY))
+ break;
+- if(i == BUSY_TIMEOUT)
+- return 1;
+- return 0;
++ return !t;
+ }
+
+-static __inline__ int newport_bfwait(void)
++static __inline__ int newport_bfwait(struct newport_regs *regs)
+ {
+- int i = 0;
++ int t = BUSY_TIMEOUT;
+
+- while(i < BUSY_TIMEOUT)
+- if(!(npregs->cset.status & NPORT_STAT_BBUSY))
++ while (t--)
++ if(!(regs->cset.status & NPORT_STAT_BBUSY))
+ break;
+- if(i == BUSY_TIMEOUT)
+- return 1;
+- return 0;
++ return !t;
+ }
+
+-/* newport.c and cons_newport.c routines */
+-extern struct graphics_ops *newport_probe (int, const char **);
+-
+-void newport_save (void *);
+-void newport_restore (void *);
+-void newport_reset (void);
+-int newport_ioctl (int card, int cmd, unsigned long arg);
+-
+ /*
+ * DCBMODE register defines:
+ */
+@@ -564,7 +550,7 @@
+ {
+ rex->set.dcbmode = DCB_XMAP0 | XM9_CRS_FIFO_AVAIL |
+ DCB_DATAWIDTH_1 | R_DCB_XMAP9_PROTOCOL;
+- newport_bfwait ();
++ newport_bfwait (rex);
+
+ while ((rex->set.dcbdata0.bybytes.b3 & 3) != XM9_FIFO_EMPTY)
+ ;
+diff -Nur linux-2.4.32-rc1/init/main.c linux-2.4.32-rc1.mips/init/main.c
+--- linux-2.4.32-rc1/init/main.c 2004-11-17 12:54:22.000000000 +0100
++++ linux-2.4.32-rc1.mips/init/main.c 2004-11-19 01:28:52.000000000 +0100
+@@ -296,7 +296,6 @@
+
+
+ extern void setup_arch(char **);
+-extern void cpu_idle(void);
+
+ unsigned long wait_init_idle;
+
+diff -Nur linux-2.4.32-rc1/kernel/exit.c linux-2.4.32-rc1.mips/kernel/exit.c
+--- linux-2.4.32-rc1/kernel/exit.c 2002-11-29 00:53:15.000000000 +0100
++++ linux-2.4.32-rc1.mips/kernel/exit.c 2003-01-11 18:53:18.000000000 +0100
+@@ -26,7 +26,7 @@
+
+ int getrusage(struct task_struct *, int, struct rusage *);
+
+-static void release_task(struct task_struct * p)
++void release_task(struct task_struct * p)
+ {
+ if (p != current) {
+ #ifdef CONFIG_SMP
+diff -Nur linux-2.4.32-rc1/kernel/signal.c linux-2.4.32-rc1.mips/kernel/signal.c
+--- linux-2.4.32-rc1/kernel/signal.c 2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.32-rc1.mips/kernel/signal.c 2004-01-20 16:10:34.000000000 +0100
+@@ -14,6 +14,7 @@
+ #include <linux/init.h>
+ #include <linux/sched.h>
+
++#include <asm/param.h>
+ #include <asm/uaccess.h>
+
+ /*
+@@ -28,6 +29,14 @@
+ #define SIG_SLAB_DEBUG 0
+ #endif
+
++#define DEBUG_SIG 0
++
++#if DEBUG_SIG
++#define SIG_SLAB_DEBUG (SLAB_DEBUG_FREE | SLAB_RED_ZONE /* | SLAB_POISON */)
++#else
++#define SIG_SLAB_DEBUG 0
++#endif
++
+ static kmem_cache_t *sigqueue_cachep;
+
+ atomic_t nr_queued_signals;
+@@ -270,6 +279,11 @@
+ signal_pending(current));
+ #endif
+
++#if DEBUG_SIG
++printk("SIG dequeue (%s:%d): %d ", current->comm, current->pid,
++ signal_pending(current));
++#endif
++
+ sig = next_signal(current, mask);
+ if (sig) {
+ if (current->notifier) {
+@@ -293,6 +307,10 @@
+ printk(" %d -> %d\n", signal_pending(current), sig);
+ #endif
+
++#if DEBUG_SIG
++printk(" %d -> %d\n", signal_pending(current), sig);
++#endif
++
+ return sig;
+ }
+
+@@ -540,6 +558,11 @@
+ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
+ #endif
+
++
++#if DEBUG_SIG
++printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
++#endif
++
+ ret = -EINVAL;
+ if (sig < 0 || sig > _NSIG)
+ goto out_nolock;
+@@ -778,8 +801,8 @@
+ info.si_uid = tsk->uid;
+
+ /* FIXME: find out whether or not this is supposed to be c*time. */
+- info.si_utime = tsk->times.tms_utime;
+- info.si_stime = tsk->times.tms_stime;
++ info.si_utime = hz_to_std(tsk->times.tms_utime);
++ info.si_stime = hz_to_std(tsk->times.tms_stime);
+
+ status = tsk->exit_code & 0x7f;
+ why = SI_KERNEL; /* shouldn't happen */
+diff -Nur linux-2.4.32-rc1/kernel/sys.c linux-2.4.32-rc1.mips/kernel/sys.c
+--- linux-2.4.32-rc1/kernel/sys.c 2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.32-rc1.mips/kernel/sys.c 2003-11-17 02:07:47.000000000 +0100
+@@ -801,16 +801,23 @@
+
+ asmlinkage long sys_times(struct tms * tbuf)
+ {
++ struct tms temp;
++
+ /*
+ * In the SMP world we might just be unlucky and have one of
+ * the times increment as we use it. Since the value is an
+ * atomically safe type this is just fine. Conceptually its
+ * as if the syscall took an instant longer to occur.
+ */
+- if (tbuf)
+- if (copy_to_user(tbuf, &current->times, sizeof(struct tms)))
++ if (tbuf) {
++ temp.tms_utime = hz_to_std(current->times.tms_utime);
++ temp.tms_stime = hz_to_std(current->times.tms_stime);
++ temp.tms_cutime = hz_to_std(current->times.tms_cutime);
++ temp.tms_cstime = hz_to_std(current->times.tms_cstime);
++ if (copy_to_user(tbuf, &temp, sizeof(struct tms)))
+ return -EFAULT;
+- return jiffies;
++ }
++ return hz_to_std(jiffies);
+ }
+
+ /*
+diff -Nur linux-2.4.32-rc1/lib/Makefile linux-2.4.32-rc1.mips/lib/Makefile
+--- linux-2.4.32-rc1/lib/Makefile 2004-04-14 15:05:40.000000000 +0200
++++ linux-2.4.32-rc1.mips/lib/Makefile 2004-04-16 05:14:21.000000000 +0200
+@@ -27,6 +27,7 @@
+ subdir-$(CONFIG_ZLIB_INFLATE) += zlib_inflate
+ subdir-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate
+
++-include $(TOPDIR)/arch/$(ARCH)/Makefile.lib
+ include $(TOPDIR)/drivers/net/Makefile.lib
+ include $(TOPDIR)/drivers/usb/Makefile.lib
+ include $(TOPDIR)/drivers/bluetooth/Makefile.lib
+diff -Nur linux-2.4.32-rc1/Makefile linux-2.4.32-rc1.mips/Makefile
+--- linux-2.4.32-rc1/Makefile 2005-10-24 11:33:30.000000000 +0200
++++ linux-2.4.32-rc1.mips/Makefile 2005-09-23 22:41:15.000000000 +0200
+@@ -462,10 +462,11 @@
+ $(MAKE) -C Documentation/DocBook mrproper
+
+ distclean: mrproper
+- rm -f core `find . \( -not -type d \) -and \
+- \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
+- -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
+- -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -type f -print` TAGS tags
++ find . \( -not -type d \) -and \
++ \( -name core -o -name '*.orig' -o -name '*.rej' \
++ -o -name '*~' -o -name '*.bak' -o -name '#*#' \
++ -o -name '.*.rej' -o -name '.SUMS' -o -size 0 \
++ -o -name TAGS -o -name tags \) -print | env -i xargs rm -f
+
+ backup: mrproper
+ cd .. && tar cf - linux/ | gzip -9 > backup.gz
+@@ -492,7 +493,7 @@
+ $(MAKE) -C Documentation/DocBook man
+
+ sums:
+- find . -type f -print | sort | xargs sum > .SUMS
++ find . -type f -print | sort | env -i xargs sum > .SUMS
+
+ dep-files: scripts/mkdep archdep include/linux/version.h
+ rm -f .depend .hdepend
diff --git a/target/linux/generic-2.4/patches/001-squashfs.patch b/target/linux/generic-2.4/patches/001-squashfs.patch
new file mode 100644
index 0000000..b2d9cf3
--- /dev/null
+++ b/target/linux/generic-2.4/patches/001-squashfs.patch
@@ -0,0 +1,4070 @@
+diff --new-file -urp linux-2.4.32/fs/Config.in linux-2.4.32-squashfs3.0/fs/Config.in
+--- linux-2.4.32/fs/Config.in 2004-11-17 11:54:21.000000000 +0000
++++ linux-2.4.32-squashfs3.0/fs/Config.in 2006-03-07 21:12:36.000000000 +0000
+@@ -51,6 +51,14 @@ if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFI
+ int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0
+ fi
+ tristate 'Compressed ROM file system support' CONFIG_CRAMFS
++tristate 'Squashed file system support' CONFIG_SQUASHFS
++if [ "$CONFIG_SQUASHFS" = "y" -o "$CONFIG_SQUASHFS" = "m" ] ; then
++bool 'Additional options for memory constrained systems ' CONFIG_SQUASHFS_EMBEDDED
++fi
++if [ "$CONFIG_SQUASHFS_EMBEDDED" = "y" ] ; then
++int 'Number of fragments cached' CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE 3
++bool 'Use Vmalloc rather than Kmalloc' CONFIG_SQUASHFS_VMALLOC
++fi
+ bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS
+ define_bool CONFIG_RAMFS y
+
+diff --new-file -urp linux-2.4.32/fs/Makefile linux-2.4.32-squashfs3.0/fs/Makefile
+--- linux-2.4.32/fs/Makefile 2004-02-18 13:36:31.000000000 +0000
++++ linux-2.4.32-squashfs3.0/fs/Makefile 2006-03-07 21:12:36.000000000 +0000
+@@ -65,6 +65,7 @@ subdir-$(CONFIG_REISERFS_FS) += reiserfs
+ subdir-$(CONFIG_DEVPTS_FS) += devpts
+ subdir-$(CONFIG_SUN_OPENPROMFS) += openpromfs
+ subdir-$(CONFIG_BEFS_FS) += befs
++subdir-$(CONFIG_SQUASHFS) += squashfs
+ subdir-$(CONFIG_JFS_FS) += jfs
+ subdir-$(CONFIG_XFS_FS) += xfs
+
+diff --new-file -urp linux-2.4.32/fs/squashfs/inode.c linux-2.4.32-squashfs3.0/fs/squashfs/inode.c
+--- linux-2.4.32/fs/squashfs/inode.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-squashfs3.0/fs/squashfs/inode.c 2006-03-07 21:12:36.000000000 +0000
+@@ -0,0 +1,2028 @@
++/*
++ * Squashfs - a compressed read only filesystem for Linux
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.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,
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * inode.c
++ */
++
++#include <linux/types.h>
++#include <linux/squashfs_fs.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/smp_lock.h>
++#include <linux/locks.h>
++#include <linux/init.h>
++#include <linux/dcache.h>
++#include <linux/wait.h>
++#include <linux/zlib.h>
++#include <linux/blkdev.h>
++#include <linux/vmalloc.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++
++#include "squashfs.h"
++
++static struct super_block *squashfs_read_super(struct super_block *, void *, int);
++static void squashfs_put_super(struct super_block *);
++static int squashfs_statfs(struct super_block *, struct statfs *);
++static int squashfs_symlink_readpage(struct file *file, struct page *page);
++static int squashfs_readpage(struct file *file, struct page *page);
++static int squashfs_readpage4K(struct file *file, struct page *page);
++static int squashfs_readdir(struct file *, void *, filldir_t);
++static struct dentry *squashfs_lookup(struct inode *, struct dentry *);
++static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode);
++static long long read_blocklist(struct inode *inode, int index,
++ int readahead_blks, char *block_list,
++ unsigned short **block_p, unsigned int *bsize);
++
++static z_stream stream;
++
++static DECLARE_FSTYPE_DEV(squashfs_fs_type, "squashfs", squashfs_read_super);
++
++static unsigned char squashfs_filetype_table[] = {
++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
++};
++
++static struct super_operations squashfs_ops = {
++ .statfs = squashfs_statfs,
++ .put_super = squashfs_put_super,
++};
++
++SQSH_EXTERN struct address_space_operations squashfs_symlink_aops = {
++ .readpage = squashfs_symlink_readpage
++};
++
++SQSH_EXTERN struct address_space_operations squashfs_aops = {
++ .readpage = squashfs_readpage
++};
++
++SQSH_EXTERN struct address_space_operations squashfs_aops_4K = {
++ .readpage = squashfs_readpage4K
++};
++
++static struct file_operations squashfs_dir_ops = {
++ .read = generic_read_dir,
++ .readdir = squashfs_readdir
++};
++
++static struct inode_operations squashfs_dir_inode_ops = {
++ .lookup = squashfs_lookup
++};
++
++static struct buffer_head *get_block_length(struct super_block *s,
++ int *cur_index, int *offset, int *c_byte)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ unsigned short temp;
++ struct buffer_head *bh;
++
++ if (!(bh = sb_bread(s, *cur_index)))
++ goto out;
++
++ if (msblk->devblksize - *offset == 1) {
++ if (msblk->swap)
++ ((unsigned char *) &temp)[1] = *((unsigned char *)
++ (bh->b_data + *offset));
++ else
++ ((unsigned char *) &temp)[0] = *((unsigned char *)
++ (bh->b_data + *offset));
++ brelse(bh);
++ if (!(bh = sb_bread(s, ++(*cur_index))))
++ goto out;
++ if (msblk->swap)
++ ((unsigned char *) &temp)[0] = *((unsigned char *)
++ bh->b_data);
++ else
++ ((unsigned char *) &temp)[1] = *((unsigned char *)
++ bh->b_data);
++ *c_byte = temp;
++ *offset = 1;
++ } else {
++ if (msblk->swap) {
++ ((unsigned char *) &temp)[1] = *((unsigned char *)
++ (bh->b_data + *offset));
++ ((unsigned char *) &temp)[0] = *((unsigned char *)
++ (bh->b_data + *offset + 1));
++ } else {
++ ((unsigned char *) &temp)[0] = *((unsigned char *)
++ (bh->b_data + *offset));
++ ((unsigned char *) &temp)[1] = *((unsigned char *)
++ (bh->b_data + *offset + 1));
++ }
++ *c_byte = temp;
++ *offset += 2;
++ }
++
++ if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
++ if (*offset == msblk->devblksize) {
++ brelse(bh);
++ if (!(bh = sb_bread(s, ++(*cur_index))))
++ goto out;
++ *offset = 0;
++ }
++ if (*((unsigned char *) (bh->b_data + *offset)) !=
++ SQUASHFS_MARKER_BYTE) {
++ ERROR("Metadata block marker corrupt @ %x\n",
++ *cur_index);
++ brelse(bh);
++ goto out;
++ }
++ (*offset)++;
++ }
++ return bh;
++
++out:
++ return NULL;
++}
++
++
++SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
++ long long index, unsigned int length,
++ long long *next_index)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >>
++ msblk->devblksize_log2) + 2];
++ unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
++ unsigned int cur_index = index >> msblk->devblksize_log2;
++ int bytes, avail_bytes, b = 0, k;
++ char *c_buffer;
++ unsigned int compressed;
++ unsigned int c_byte = length;
++
++ if (c_byte) {
++ bytes = msblk->devblksize - offset;
++ compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
++ c_buffer = compressed ? msblk->read_data : buffer;
++ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
++
++ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
++ ? "" : "un", (unsigned int) c_byte);
++
++ if (!(bh[0] = sb_getblk(s, cur_index)))
++ goto block_release;
++
++ for (b = 1; bytes < c_byte; b++) {
++ if (!(bh[b] = sb_getblk(s, ++cur_index)))
++ goto block_release;
++ bytes += msblk->devblksize;
++ }
++ ll_rw_block(READ, b, bh);
++ } else {
++ if (!(bh[0] = get_block_length(s, &cur_index, &offset,
++ &c_byte)))
++ goto read_failure;
++
++ bytes = msblk->devblksize - offset;
++ compressed = SQUASHFS_COMPRESSED(c_byte);
++ c_buffer = compressed ? msblk->read_data : buffer;
++ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
++
++ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
++ ? "" : "un", (unsigned int) c_byte);
++
++ for (b = 1; bytes < c_byte; b++) {
++ if (!(bh[b] = sb_getblk(s, ++cur_index)))
++ goto block_release;
++ bytes += msblk->devblksize;
++ }
++ ll_rw_block(READ, b - 1, bh + 1);
++ }
++
++ if (compressed)
++ down(&msblk->read_data_mutex);
++
++ for (bytes = 0, k = 0; k < b; k++) {
++ avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
++ msblk->devblksize - offset :
++ c_byte - bytes;
++ wait_on_buffer(bh[k]);
++ if (!buffer_uptodate(bh[k]))
++ goto block_release;
++ memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes);
++ bytes += avail_bytes;
++ offset = 0;
++ brelse(bh[k]);
++ }
++
++ /*
++ * uncompress block
++ */
++ if (compressed) {
++ int zlib_err;
++
++ stream.next_in = c_buffer;
++ stream.avail_in = c_byte;
++ stream.next_out = buffer;
++ stream.avail_out = msblk->read_size;
++
++ if (((zlib_err = zlib_inflateInit(&stream)) != Z_OK) ||
++ ((zlib_err = zlib_inflate(&stream, Z_FINISH))
++ != Z_STREAM_END) || ((zlib_err =
++ zlib_inflateEnd(&stream)) != Z_OK)) {
++ ERROR("zlib_fs returned unexpected result 0x%x\n",
++ zlib_err);
++ bytes = 0;
++ } else
++ bytes = stream.total_out;
++
++ up(&msblk->read_data_mutex);
++ }
++
++ if (next_index)
++ *next_index = index + c_byte + (length ? 0 :
++ (SQUASHFS_CHECK_DATA(msblk->sblk.flags)
++ ? 3 : 2));
++ return bytes;
++
++block_release:
++ while (--b >= 0)
++ brelse(bh[b]);
++
++read_failure:
++ ERROR("sb_bread failed reading block 0x%x\n", cur_index);
++ return 0;
++}
++
++
++SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer,
++ long long block, unsigned int offset,
++ int length, long long *next_block,
++ unsigned int *next_offset)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ int n, i, bytes, return_length = length;
++ long long next_index;
++
++ TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
++
++ while ( 1 ) {
++ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
++ if (msblk->block_cache[i].block == block)
++ break;
++
++ down(&msblk->block_cache_mutex);
++
++ if (i == SQUASHFS_CACHED_BLKS) {
++ /* read inode header block */
++ for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS;
++ n ; n --, i = (i + 1) %
++ SQUASHFS_CACHED_BLKS)
++ if (msblk->block_cache[i].block !=
++ SQUASHFS_USED_BLK)
++ break;
++
++ if (n == 0) {
++ wait_queue_t wait;
++
++ init_waitqueue_entry(&wait, current);
++ add_wait_queue(&msblk->waitq, &wait);
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ up(&msblk->block_cache_mutex);
++ schedule();
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&msblk->waitq, &wait);
++ continue;
++ }
++ msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
++
++ if (msblk->block_cache[i].block ==
++ SQUASHFS_INVALID_BLK) {
++ if (!(msblk->block_cache[i].data =
++ kmalloc(SQUASHFS_METADATA_SIZE,
++ GFP_KERNEL))) {
++ ERROR("Failed to allocate cache"
++ "block\n");
++ up(&msblk->block_cache_mutex);
++ goto out;
++ }
++ }
++
++ msblk->block_cache[i].block = SQUASHFS_USED_BLK;
++ up(&msblk->block_cache_mutex);
++
++ if (!(msblk->block_cache[i].length =
++ squashfs_read_data(s,
++ msblk->block_cache[i].data,
++ block, 0, &next_index))) {
++ ERROR("Unable to read cache block [%llx:%x]\n",
++ block, offset);
++ goto out;
++ }
++
++ down(&msblk->block_cache_mutex);
++ wake_up(&msblk->waitq);
++ msblk->block_cache[i].block = block;
++ msblk->block_cache[i].next_index = next_index;
++ TRACE("Read cache block [%llx:%x]\n", block, offset);
++ }
++
++ if (msblk->block_cache[i].block != block) {
++ up(&msblk->block_cache_mutex);
++ continue;
++ }
++
++ if ((bytes = msblk->block_cache[i].length - offset) >= length) {
++ if (buffer)
++ memcpy(buffer, msblk->block_cache[i].data +
++ offset, length);
++ if (msblk->block_cache[i].length - offset == length) {
++ *next_block = msblk->block_cache[i].next_index;
++ *next_offset = 0;
++ } else {
++ *next_block = block;
++ *next_offset = offset + length;
++ }
++ up(&msblk->block_cache_mutex);
++ goto finish;
++ } else {
++ if (buffer) {
++ memcpy(buffer, msblk->block_cache[i].data +
++ offset, bytes);
++ buffer += bytes;
++ }
++ block = msblk->block_cache[i].next_index;
++ up(&msblk->block_cache_mutex);
++ length -= bytes;
++ offset = 0;
++ }
++ }
++
++finish:
++ return return_length;
++out:
++ return 0;
++}
++
++
++static int get_fragment_location(struct super_block *s, unsigned int fragment,
++ long long *fragment_start_block,
++ unsigned int *fragment_size)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ long long start_block =
++ msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
++ struct squashfs_fragment_entry fragment_entry;
++
++ if (msblk->swap) {
++ struct squashfs_fragment_entry sfragment_entry;
++
++ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
++ start_block, offset,
++ sizeof(sfragment_entry), &start_block,
++ &offset))
++ goto out;
++ SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
++ } else
++ if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
++ start_block, offset,
++ sizeof(fragment_entry), &start_block,
++ &offset))
++ goto out;
++
++ *fragment_start_block = fragment_entry.start_block;
++ *fragment_size = fragment_entry.size;
++
++ return 1;
++
++out:
++ return 0;
++}
++
++
++SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct
++ squashfs_fragment_cache *fragment)
++{
++ down(&msblk->fragment_mutex);
++ fragment->locked --;
++ wake_up(&msblk->fragment_wait_queue);
++ up(&msblk->fragment_mutex);
++}
++
++
++SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block
++ *s, long long start_block,
++ int length)
++{
++ int i, n;
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++
++ while ( 1 ) {
++ down(&msblk->fragment_mutex);
++
++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
++ msblk->fragment[i].block != start_block; i++);
++
++ if (i == SQUASHFS_CACHED_FRAGMENTS) {
++ for (i = msblk->next_fragment, n =
++ SQUASHFS_CACHED_FRAGMENTS; n &&
++ msblk->fragment[i].locked; n--, i = (i + 1) %
++ SQUASHFS_CACHED_FRAGMENTS);
++
++ if (n == 0) {
++ wait_queue_t wait;
++
++ init_waitqueue_entry(&wait, current);
++ add_wait_queue(&msblk->fragment_wait_queue,
++ &wait);
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ up(&msblk->fragment_mutex);
++ schedule();
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&msblk->fragment_wait_queue,
++ &wait);
++ continue;
++ }
++ msblk->next_fragment = (msblk->next_fragment + 1) %
++ SQUASHFS_CACHED_FRAGMENTS;
++
++ if (msblk->fragment[i].data == NULL)
++ if (!(msblk->fragment[i].data = SQUASHFS_ALLOC
++ (SQUASHFS_FILE_MAX_SIZE))) {
++ ERROR("Failed to allocate fragment "
++ "cache block\n");
++ up(&msblk->fragment_mutex);
++ goto out;
++ }
++
++ msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
++ msblk->fragment[i].locked = 1;
++ up(&msblk->fragment_mutex);
++
++ if (!(msblk->fragment[i].length = squashfs_read_data(s,
++ msblk->fragment[i].data,
++ start_block, length, NULL))) {
++ ERROR("Unable to read fragment cache block "
++ "[%llx]\n", start_block);
++ msblk->fragment[i].locked = 0;
++ goto out;
++ }
++
++ msblk->fragment[i].block = start_block;
++ TRACE("New fragment %d, start block %lld, locked %d\n",
++ i, msblk->fragment[i].block,
++ msblk->fragment[i].locked);
++ break;
++ }
++
++ msblk->fragment[i].locked++;
++ up(&msblk->fragment_mutex);
++ TRACE("Got fragment %d, start block %lld, locked %d\n", i,
++ msblk->fragment[i].block,
++ msblk->fragment[i].locked);
++ break;
++ }
++
++ return &msblk->fragment[i];
++
++out:
++ return NULL;
++}
++
++
++static struct inode *squashfs_new_inode(struct super_block *s,
++ struct squashfs_base_inode_header *inodeb)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ struct inode *i = new_inode(s);
++
++ if (i) {
++ i->i_ino = inodeb->inode_number;
++ i->i_mtime = inodeb->mtime;
++ i->i_atime = inodeb->mtime;
++ i->i_ctime = inodeb->mtime;
++ i->i_uid = msblk->uid[inodeb->uid];
++ i->i_mode = inodeb->mode;
++ i->i_size = 0;
++ if (inodeb->guid == SQUASHFS_GUIDS)
++ i->i_gid = i->i_uid;
++ else
++ i->i_gid = msblk->guid[inodeb->guid];
++ }
++
++ return i;
++}
++
++
++static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode)
++{
++ struct inode *i;
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ long long block = SQUASHFS_INODE_BLK(inode) +
++ sblk->inode_table_start;
++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
++ long long next_block;
++ unsigned int next_offset;
++ union squashfs_inode_header id, sid;
++ struct squashfs_base_inode_header *inodeb = &id.base,
++ *sinodeb = &sid.base;
++
++ TRACE("Entered squashfs_iget\n");
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
++ offset, sizeof(*sinodeb), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb,
++ sizeof(*sinodeb));
++ } else
++ if (!squashfs_get_cached_block(s, (char *) inodeb, block,
++ offset, sizeof(*inodeb), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ switch(inodeb->inode_type) {
++ case SQUASHFS_FILE_TYPE: {
++ unsigned int frag_size;
++ long long frag_blk;
++ struct squashfs_reg_inode_header *inodep = &id.reg;
++ struct squashfs_reg_inode_header *sinodep = &sid.reg;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ frag_blk = SQUASHFS_INVALID_BLK;
++ if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
++ !get_fragment_location(s,
++ inodep->fragment, &frag_blk, &frag_size))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb)) == NULL)
++ goto failed_read1;
++
++ i->i_nlink = 1;
++ i->i_size = inodep->file_size;
++ i->i_fop = &generic_ro_fops;
++ i->i_mode |= S_IFREG;
++ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
++ i->i_blksize = PAGE_CACHE_SIZE;
++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
++ SQUASHFS_I(i)->start_block = inodep->start_block;
++ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
++ SQUASHFS_I(i)->offset = next_offset;
++ if (sblk->block_size > 4096)
++ i->i_data.a_ops = &squashfs_aops;
++ else
++ i->i_data.a_ops = &squashfs_aops_4K;
++
++ TRACE("File inode %x:%x, start_block %llx, "
++ "block_list_start %llx, offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ inodep->start_block, next_block,
++ next_offset);
++ break;
++ }
++ case SQUASHFS_LREG_TYPE: {
++ unsigned int frag_size;
++ long long frag_blk;
++ struct squashfs_lreg_inode_header *inodep = &id.lreg;
++ struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ frag_blk = SQUASHFS_INVALID_BLK;
++ if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
++ !get_fragment_location(s,
++ inodep->fragment, &frag_blk, &frag_size))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb)) == NULL)
++ goto failed_read1;
++
++ i->i_nlink = inodep->nlink;
++ i->i_size = inodep->file_size;
++ i->i_fop = &generic_ro_fops;
++ i->i_mode |= S_IFREG;
++ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
++ i->i_blksize = PAGE_CACHE_SIZE;
++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
++ SQUASHFS_I(i)->start_block = inodep->start_block;
++ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
++ SQUASHFS_I(i)->offset = next_offset;
++ if (sblk->block_size > 4096)
++ i->i_data.a_ops = &squashfs_aops;
++ else
++ i->i_data.a_ops = &squashfs_aops_4K;
++
++ TRACE("File inode %x:%x, start_block %llx, "
++ "block_list_start %llx, offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ inodep->start_block, next_block,
++ next_offset);
++ break;
++ }
++ case SQUASHFS_DIR_TYPE: {
++ struct squashfs_dir_inode_header *inodep = &id.dir;
++ struct squashfs_dir_inode_header *sinodep = &sid.dir;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb)) == NULL)
++ goto failed_read1;
++
++ i->i_nlink = inodep->nlink;
++ i->i_size = inodep->file_size;
++ i->i_op = &squashfs_dir_inode_ops;
++ i->i_fop = &squashfs_dir_ops;
++ i->i_mode |= S_IFDIR;
++ SQUASHFS_I(i)->start_block = inodep->start_block;
++ SQUASHFS_I(i)->offset = inodep->offset;
++ SQUASHFS_I(i)->u.s2.directory_index_count = 0;
++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
++
++ TRACE("Directory inode %x:%x, start_block %x, offset "
++ "%x\n", SQUASHFS_INODE_BLK(inode),
++ offset, inodep->start_block,
++ inodep->offset);
++ break;
++ }
++ case SQUASHFS_LDIR_TYPE: {
++ struct squashfs_ldir_inode_header *inodep = &id.ldir;
++ struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep,
++ sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb)) == NULL)
++ goto failed_read1;
++
++ i->i_nlink = inodep->nlink;
++ i->i_size = inodep->file_size;
++ i->i_op = &squashfs_dir_inode_ops;
++ i->i_fop = &squashfs_dir_ops;
++ i->i_mode |= S_IFDIR;
++ SQUASHFS_I(i)->start_block = inodep->start_block;
++ SQUASHFS_I(i)->offset = inodep->offset;
++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
++ SQUASHFS_I(i)->u.s2.directory_index_offset =
++ next_offset;
++ SQUASHFS_I(i)->u.s2.directory_index_count =
++ inodep->i_count;
++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
++
++ TRACE("Long directory inode %x:%x, start_block %x, "
++ "offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ inodep->start_block, inodep->offset);
++ break;
++ }
++ case SQUASHFS_SYMLINK_TYPE: {
++ struct squashfs_symlink_inode_header *inodep =
++ &id.symlink;
++ struct squashfs_symlink_inode_header *sinodep =
++ &sid.symlink;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep,
++ sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb)) == NULL)
++ goto failed_read1;
++
++ i->i_nlink = inodep->nlink;
++ i->i_size = inodep->symlink_size;
++ i->i_op = &page_symlink_inode_operations;
++ i->i_data.a_ops = &squashfs_symlink_aops;
++ i->i_mode |= S_IFLNK;
++ SQUASHFS_I(i)->start_block = next_block;
++ SQUASHFS_I(i)->offset = next_offset;
++
++ TRACE("Symbolic link inode %x:%x, start_block %llx, "
++ "offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ next_block, next_offset);
++ break;
++ }
++ case SQUASHFS_BLKDEV_TYPE:
++ case SQUASHFS_CHRDEV_TYPE: {
++ struct squashfs_dev_inode_header *inodep = &id.dev;
++ struct squashfs_dev_inode_header *sinodep = &sid.dev;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if ((i = squashfs_new_inode(s, inodeb)) == NULL)
++ goto failed_read1;
++
++ i->i_nlink = inodep->nlink;
++ i->i_mode |= (inodeb->inode_type ==
++ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR :
++ S_IFBLK;
++ init_special_inode(i, i->i_mode, inodep->rdev);
++
++ TRACE("Device inode %x:%x, rdev %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ inodep->rdev);
++ break;
++ }
++ case SQUASHFS_FIFO_TYPE:
++ case SQUASHFS_SOCKET_TYPE: {
++ struct squashfs_ipc_inode_header *inodep = &id.ipc;
++ struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if ((i = squashfs_new_inode(s, inodeb)) == NULL)
++ goto failed_read1;
++
++ i->i_nlink = inodep->nlink;
++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
++ ? S_IFIFO : S_IFSOCK;
++ init_special_inode(i, i->i_mode, 0);
++ break;
++ }
++ default:
++ ERROR("Unknown inode type %d in squashfs_iget!\n",
++ inodeb->inode_type);
++ goto failed_read1;
++ }
++
++ insert_inode_hash(i);
++ return i;
++
++failed_read:
++ ERROR("Unable to read inode [%llx:%x]\n", block, offset);
++
++failed_read1:
++ return NULL;
++}
++
++
++int read_fragment_index_table(struct super_block *s)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++
++ if (!(msblk->fragment_index = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES
++ (sblk->fragments), GFP_KERNEL))) {
++ ERROR("Failed to allocate uid/gid table\n");
++ return 0;
++ }
++
++ if (SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments) &&
++ !squashfs_read_data(s, (char *)
++ msblk->fragment_index,
++ sblk->fragment_table_start,
++ SQUASHFS_FRAGMENT_INDEX_BYTES
++ (sblk->fragments) |
++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++ ERROR("unable to read fragment index table\n");
++ return 0;
++ }
++
++ if (msblk->swap) {
++ int i;
++ long long fragment;
++
++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments);
++ i++) {
++ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
++ &msblk->fragment_index[i], 1);
++ msblk->fragment_index[i] = fragment;
++ }
++ }
++
++ return 1;
++}
++
++
++static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
++{
++ struct squashfs_super_block *sblk = &msblk->sblk;
++
++ msblk->iget = squashfs_iget;
++ msblk->read_blocklist = read_blocklist;
++ msblk->read_fragment_index_table = read_fragment_index_table;
++
++ if (sblk->s_major == 1) {
++ if (!squashfs_1_0_supported(msblk)) {
++ SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
++ "are unsupported\n");
++ SERROR("Please recompile with "
++ "Squashfs 1.0 support enabled\n");
++ return 0;
++ }
++ } else if (sblk->s_major == 2) {
++ if (!squashfs_2_0_supported(msblk)) {
++ SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
++ "are unsupported\n");
++ SERROR("Please recompile with "
++ "Squashfs 2.0 support enabled\n");
++ return 0;
++ }
++ } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
++ SQUASHFS_MINOR) {
++ SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
++ "filesystem\n", sblk->s_major, sblk->s_minor);
++ SERROR("Please update your kernel\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++
++static struct super_block *squashfs_read_super(struct super_block *s,
++ void *data, int silent)
++{
++ kdev_t dev = s->s_dev;
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ int i;
++ struct inode *root;
++
++ msblk->devblksize = get_hardsect_size(dev);
++ if(msblk->devblksize < BLOCK_SIZE)
++ msblk->devblksize = BLOCK_SIZE;
++ msblk->devblksize_log2 = ffz(~msblk->devblksize);
++ set_blocksize(dev, msblk->devblksize);
++ s->s_blocksize = msblk->devblksize;
++ s->s_blocksize_bits = msblk->devblksize_log2;
++
++ init_MUTEX(&msblk->read_data_mutex);
++ init_MUTEX(&msblk->read_page_mutex);
++ init_MUTEX(&msblk->block_cache_mutex);
++ init_MUTEX(&msblk->fragment_mutex);
++
++ init_waitqueue_head(&msblk->waitq);
++ init_waitqueue_head(&msblk->fragment_wait_queue);
++
++ if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
++ sizeof(struct squashfs_super_block) |
++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++ SERROR("unable to read superblock\n");
++ goto failed_mount;
++ }
++
++ /* Check it is a SQUASHFS superblock */
++ msblk->swap = 0;
++ if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
++ if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
++ struct squashfs_super_block ssblk;
++
++ WARNING("Mounting a different endian SQUASHFS "
++ "filesystem on %s\n", bdevname(dev));
++
++ SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
++ memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
++ msblk->swap = 1;
++ } else {
++ SERROR("Can't find a SQUASHFS superblock on %s\n",
++ bdevname(dev));
++ goto failed_mount;
++ }
++ }
++
++ /* Check the MAJOR & MINOR versions */
++ if(!supported_squashfs_filesystem(msblk, silent))
++ goto failed_mount;
++
++ TRACE("Found valid superblock on %s\n", bdevname(dev));
++ TRACE("Inodes are %scompressed\n",
++ SQUASHFS_UNCOMPRESSED_INODES
++ (sblk->flags) ? "un" : "");
++ TRACE("Data is %scompressed\n",
++ SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
++ ? "un" : "");
++ TRACE("Check data is %s present in the filesystem\n",
++ SQUASHFS_CHECK_DATA(sblk->flags) ?
++ "" : "not");
++ TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
++ TRACE("Block size %d\n", sblk->block_size);
++ TRACE("Number of inodes %d\n", sblk->inodes);
++ if (sblk->s_major > 1)
++ TRACE("Number of fragments %d\n", sblk->fragments);
++ TRACE("Number of uids %d\n", sblk->no_uids);
++ TRACE("Number of gids %d\n", sblk->no_guids);
++ TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
++ TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
++ if (sblk->s_major > 1)
++ TRACE("sblk->fragment_table_start %llx\n",
++ sblk->fragment_table_start);
++ TRACE("sblk->uid_start %llx\n", sblk->uid_start);
++
++ s->s_flags |= MS_RDONLY;
++ s->s_op = &squashfs_ops;
++
++ /* Init inode_table block pointer array */
++ if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
++ SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
++ ERROR("Failed to allocate block cache\n");
++ goto failed_mount;
++ }
++
++ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
++ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
++
++ msblk->next_cache = 0;
++
++ /* Allocate read_data block */
++ msblk->read_size = (sblk->block_size < SQUASHFS_METADATA_SIZE) ?
++ SQUASHFS_METADATA_SIZE :
++ sblk->block_size;
++
++ if (!(msblk->read_data = kmalloc(msblk->read_size, GFP_KERNEL))) {
++ ERROR("Failed to allocate read_data block\n");
++ goto failed_mount;
++ }
++
++ /* Allocate read_page block */
++ if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) {
++ ERROR("Failed to allocate read_page block\n");
++ goto failed_mount;
++ }
++
++ /* Allocate uid and gid tables */
++ if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
++ sizeof(unsigned int), GFP_KERNEL))) {
++ ERROR("Failed to allocate uid/gid table\n");
++ goto failed_mount;
++ }
++ msblk->guid = msblk->uid + sblk->no_uids;
++
++ if (msblk->swap) {
++ unsigned int suid[sblk->no_uids + sblk->no_guids];
++
++ if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
++ ((sblk->no_uids + sblk->no_guids) *
++ sizeof(unsigned int)) |
++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++ ERROR("unable to read uid/gid table\n");
++ goto failed_mount;
++ }
++
++ SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
++ sblk->no_guids), (sizeof(unsigned int) * 8));
++ } else
++ if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
++ ((sblk->no_uids + sblk->no_guids) *
++ sizeof(unsigned int)) |
++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++ ERROR("unable to read uid/gid table\n");
++ goto failed_mount;
++ }
++
++
++ if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
++ goto allocate_root;
++
++ if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) *
++ SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) {
++ ERROR("Failed to allocate fragment block cache\n");
++ goto failed_mount;
++ }
++
++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
++ msblk->fragment[i].locked = 0;
++ msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
++ msblk->fragment[i].data = NULL;
++ }
++
++ msblk->next_fragment = 0;
++
++ /* Allocate fragment index table */
++ if(msblk->read_fragment_index_table(s) == 0)
++ goto failed_mount;
++
++allocate_root:
++ if ((root = (msblk->iget)(s, sblk->root_inode)) == NULL)
++ goto failed_mount;
++
++ if ((s->s_root = d_alloc_root(root)) == NULL) {
++ ERROR("Root inode create failed\n");
++ iput(root);
++ goto failed_mount;
++ }
++
++ TRACE("Leaving squashfs_read_super\n");
++ return s;
++
++failed_mount:
++ kfree(msblk->fragment_index);
++ kfree(msblk->fragment);
++ kfree(msblk->uid);
++ kfree(msblk->read_page);
++ kfree(msblk->read_data);
++ kfree(msblk->block_cache);
++ kfree(msblk->fragment_index_2);
++ return NULL;
++}
++
++
++static int squashfs_statfs(struct super_block *s, struct statfs *buf)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++
++ TRACE("Entered squashfs_statfs\n");
++
++ buf->f_type = SQUASHFS_MAGIC;
++ buf->f_bsize = sblk->block_size;
++ buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
++ buf->f_bfree = buf->f_bavail = 0;
++ buf->f_files = sblk->inodes;
++ buf->f_ffree = 0;
++ buf->f_namelen = SQUASHFS_NAME_LEN;
++
++ return 0;
++}
++
++
++static int squashfs_symlink_readpage(struct file *file, struct page *page)
++{
++ struct inode *inode = page->mapping->host;
++ int index = page->index << PAGE_CACHE_SHIFT, length, bytes;
++ long long block = SQUASHFS_I(inode)->start_block;
++ int offset = SQUASHFS_I(inode)->offset;
++ void *pageaddr = kmap(page);
++
++ TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
++ "%llx, offset %x\n", page->index,
++ SQUASHFS_I(inode)->start_block,
++ SQUASHFS_I(inode)->offset);
++
++ for (length = 0; length < index; length += bytes) {
++ if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL,
++ block, offset, PAGE_CACHE_SIZE, &block,
++ &offset))) {
++ ERROR("Unable to read symbolic link [%llx:%x]\n", block,
++ offset);
++ goto skip_read;
++ }
++ }
++
++ if (length != index) {
++ ERROR("(squashfs_symlink_readpage) length != index\n");
++ bytes = 0;
++ goto skip_read;
++ }
++
++ bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE :
++ i_size_read(inode) - length;
++
++ if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block,
++ offset, bytes, &block, &offset)))
++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
++
++skip_read:
++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
++ kunmap(page);
++ SetPageUptodate(page);
++ UnlockPage(page);
++
++ return 0;
++}
++
++
++struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
++{
++ struct meta_index *meta = NULL;
++ struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
++ int i;
++
++ down(&msblk->meta_index_mutex);
++
++ TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
++
++ if(msblk->meta_index == NULL)
++ goto not_allocated;
++
++ for (i = 0; i < SQUASHFS_META_NUMBER; i ++)
++ if (msblk->meta_index[i].inode_number == inode->i_ino &&
++ msblk->meta_index[i].offset >= offset &&
++ msblk->meta_index[i].offset <= index &&
++ msblk->meta_index[i].locked == 0) {
++ TRACE("locate_meta_index: entry %d, offset %d\n", i,
++ msblk->meta_index[i].offset);
++ meta = &msblk->meta_index[i];
++ offset = meta->offset;
++ }
++
++ if (meta)
++ meta->locked = 1;
++
++not_allocated:
++ up(&msblk->meta_index_mutex);
++
++ return meta;
++}
++
++
++struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
++{
++ struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
++ struct meta_index *meta = NULL;
++ int i;
++
++ down(&msblk->meta_index_mutex);
++
++ TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
++
++ if(msblk->meta_index == NULL) {
++ if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) *
++ SQUASHFS_META_NUMBER, GFP_KERNEL))) {
++ ERROR("Failed to allocate meta_index\n");
++ goto failed;
++ }
++ for(i = 0; i < SQUASHFS_META_NUMBER; i++) {
++ msblk->meta_index[i].inode_number = 0;
++ msblk->meta_index[i].locked = 0;
++ }
++ msblk->next_meta_index = 0;
++ }
++
++ for(i = SQUASHFS_META_NUMBER; i &&
++ msblk->meta_index[msblk->next_meta_index].locked; i --)
++ msblk->next_meta_index = (msblk->next_meta_index + 1) %
++ SQUASHFS_META_NUMBER;
++
++ if(i == 0) {
++ TRACE("empty_meta_index: failed!\n");
++ goto failed;
++ }
++
++ TRACE("empty_meta_index: returned meta entry %d, %p\n",
++ msblk->next_meta_index,
++ &msblk->meta_index[msblk->next_meta_index]);
++
++ meta = &msblk->meta_index[msblk->next_meta_index];
++ msblk->next_meta_index = (msblk->next_meta_index + 1) %
++ SQUASHFS_META_NUMBER;
++
++ meta->inode_number = inode->i_ino;
++ meta->offset = offset;
++ meta->skip = skip;
++ meta->entries = 0;
++ meta->locked = 1;
++
++failed:
++ up(&msblk->meta_index_mutex);
++ return meta;
++}
++
++
++void release_meta_index(struct inode *inode, struct meta_index *meta)
++{
++ meta->locked = 0;
++}
++
++
++static int read_block_index(struct super_block *s, int blocks, char *block_list,
++ long long *start_block, int *offset)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ unsigned int *block_listp;
++ int block = 0;
++
++ if (msblk->swap) {
++ char sblock_list[blocks << 2];
++
++ if (!squashfs_get_cached_block(s, sblock_list, *start_block,
++ *offset, blocks << 2, start_block, offset)) {
++ ERROR("Unable to read block list [%llx:%x]\n",
++ *start_block, *offset);
++ goto failure;
++ }
++ SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
++ ((unsigned int *)sblock_list), blocks);
++ } else
++ if (!squashfs_get_cached_block(s, block_list, *start_block,
++ *offset, blocks << 2, start_block, offset)) {
++ ERROR("Unable to read block list [%llx:%x]\n",
++ *start_block, *offset);
++ goto failure;
++ }
++
++ for (block_listp = (unsigned int *) block_list; blocks;
++ block_listp++, blocks --)
++ block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
++
++ return block;
++
++failure:
++ return -1;
++}
++
++
++#define SIZE 256
++
++static inline int calculate_skip(int blocks) {
++ int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
++ return skip >= 7 ? 7 : skip + 1;
++}
++
++
++static int get_meta_index(struct inode *inode, int index,
++ long long *index_block, int *index_offset,
++ long long *data_block, char *block_list)
++{
++ struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
++ int offset = 0;
++ struct meta_index *meta;
++ struct meta_entry *meta_entry;
++ long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
++ int cur_offset = SQUASHFS_I(inode)->offset;
++ long long cur_data_block = SQUASHFS_I(inode)->start_block;
++ int i;
++
++ index /= SQUASHFS_META_INDEXES * skip;
++
++ while ( offset < index ) {
++ meta = locate_meta_index(inode, index, offset + 1);
++
++ if (meta == NULL) {
++ if ((meta = empty_meta_index(inode, offset + 1,
++ skip)) == NULL)
++ goto all_done;
++ } else {
++ offset = index < meta->offset + meta->entries ? index :
++ meta->offset + meta->entries - 1;
++ meta_entry = &meta->meta_entry[offset - meta->offset];
++ cur_index_block = meta_entry->index_block + sblk->inode_table_start;
++ cur_offset = meta_entry->offset;
++ cur_data_block = meta_entry->data_block;
++ TRACE("get_meta_index: offset %d, meta->offset %d, "
++ "meta->entries %d\n", offset, meta->offset,
++ meta->entries);
++ TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
++ " data_block 0x%llx\n", cur_index_block,
++ cur_offset, cur_data_block);
++ }
++
++ for (i = meta->offset + meta->entries; i <= index &&
++ i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
++ int blocks = skip * SQUASHFS_META_INDEXES;
++
++ while (blocks) {
++ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) :
++ blocks;
++ int res = read_block_index(inode->i_sb, block,
++ block_list, &cur_index_block,
++ &cur_offset);
++
++ if (res == -1)
++ goto failed;
++
++ cur_data_block += res;
++ blocks -= block;
++ }
++
++ meta_entry = &meta->meta_entry[i - meta->offset];
++ meta_entry->index_block = cur_index_block - sblk->inode_table_start;
++ meta_entry->offset = cur_offset;
++ meta_entry->data_block = cur_data_block;
++ meta->entries ++;
++ offset ++;
++ }
++
++ TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
++ meta->offset, meta->entries);
++
++ release_meta_index(inode, meta);
++ }
++
++all_done:
++ *index_block = cur_index_block;
++ *index_offset = cur_offset;
++ *data_block = cur_data_block;
++
++ return offset * SQUASHFS_META_INDEXES * skip;
++
++failed:
++ release_meta_index(inode, meta);
++ return -1;
++}
++
++
++static long long read_blocklist(struct inode *inode, int index,
++ int readahead_blks, char *block_list,
++ unsigned short **block_p, unsigned int *bsize)
++{
++ long long block_ptr;
++ int offset;
++ long long block;
++ int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
++ block_list);
++
++ TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
++ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset,
++ block);
++
++ if(res == -1)
++ goto failure;
++
++ index -= res;
++
++ while ( index ) {
++ int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
++ int res = read_block_index(inode->i_sb, blocks, block_list,
++ &block_ptr, &offset);
++ if (res == -1)
++ goto failure;
++ block += res;
++ index -= blocks;
++ }
++
++ if (read_block_index(inode->i_sb, 1, block_list,
++ &block_ptr, &offset) == -1)
++ goto failure;
++ *bsize = *((unsigned int *) block_list);
++
++ return block;
++
++failure:
++ return 0;
++}
++
++
++static int squashfs_readpage(struct file *file, struct page *page)
++{
++ struct inode *inode = page->mapping->host;
++ struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ unsigned char block_list[SIZE];
++ long long block;
++ unsigned int bsize, i = 0, bytes = 0, byte_offset = 0;
++ int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
++ void *pageaddr;
++ struct squashfs_fragment_cache *fragment = NULL;
++ char *data_ptr = msblk->read_page;
++
++ int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
++ int start_index = page->index & ~mask;
++ int end_index = start_index | mask;
++
++ TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
++ page->index,
++ SQUASHFS_I(inode)->start_block);
++
++ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
++ PAGE_CACHE_SHIFT))
++ goto skip_read;
++
++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
++ || index < (i_size_read(inode) >>
++ sblk->block_log)) {
++ if ((block = (msblk->read_blocklist)(inode, index, 1,
++ block_list, NULL, &bsize)) == 0)
++ goto skip_read;
++
++ down(&msblk->read_page_mutex);
++
++ if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page,
++ block, bsize, NULL))) {
++ ERROR("Unable to read page, block %llx, size %x\n", block,
++ bsize);
++ up(&msblk->read_page_mutex);
++ goto skip_read;
++ }
++ } else {
++ if ((fragment = get_cached_fragment(inode->i_sb,
++ SQUASHFS_I(inode)->
++ u.s1.fragment_start_block,
++ SQUASHFS_I(inode)->u.s1.fragment_size))
++ == NULL) {
++ ERROR("Unable to read page, block %llx, size %x\n",
++ SQUASHFS_I(inode)->
++ u.s1.fragment_start_block,
++ (int) SQUASHFS_I(inode)->
++ u.s1.fragment_size);
++ goto skip_read;
++ }
++ bytes = SQUASHFS_I(inode)->u.s1.fragment_offset +
++ (i_size_read(inode) & (sblk->block_size
++ - 1));
++ byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset;
++ data_ptr = fragment->data;
++ }
++
++ for (i = start_index; i <= end_index && byte_offset < bytes;
++ i++, byte_offset += PAGE_CACHE_SIZE) {
++ struct page *push_page;
++ int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ?
++ PAGE_CACHE_SIZE : bytes - byte_offset;
++
++ TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n",
++ bytes, i, byte_offset, available_bytes);
++
++ if (i == page->index) {
++ pageaddr = kmap_atomic(page, KM_USER0);
++ memcpy(pageaddr, data_ptr + byte_offset,
++ available_bytes);
++ memset(pageaddr + available_bytes, 0,
++ PAGE_CACHE_SIZE - available_bytes);
++ kunmap_atomic(pageaddr, KM_USER0);
++ flush_dcache_page(page);
++ SetPageUptodate(page);
++ UnlockPage(page);
++ } else if ((push_page =
++ grab_cache_page_nowait(page->mapping, i))) {
++ pageaddr = kmap_atomic(push_page, KM_USER0);
++
++ memcpy(pageaddr, data_ptr + byte_offset,
++ available_bytes);
++ memset(pageaddr + available_bytes, 0,
++ PAGE_CACHE_SIZE - available_bytes);
++ kunmap_atomic(pageaddr, KM_USER0);
++ flush_dcache_page(push_page);
++ SetPageUptodate(push_page);
++ UnlockPage(push_page);
++ page_cache_release(push_page);
++ }
++ }
++
++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
++ || index < (i_size_read(inode) >>
++ sblk->block_log))
++ up(&msblk->read_page_mutex);
++ else
++ release_cached_fragment(msblk, fragment);
++
++ return 0;
++
++skip_read:
++ pageaddr = kmap_atomic(page, KM_USER0);
++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
++ kunmap_atomic(pageaddr, KM_USER0);
++ flush_dcache_page(page);
++ SetPageUptodate(page);
++ UnlockPage(page);
++
++ return 0;
++}
++
++
++static int squashfs_readpage4K(struct file *file, struct page *page)
++{
++ struct inode *inode = page->mapping->host;
++ struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ unsigned char block_list[SIZE];
++ long long block;
++ unsigned int bsize, bytes = 0;
++ void *pageaddr;
++
++ TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n",
++ page->index,
++ SQUASHFS_I(inode)->start_block);
++
++ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
++ PAGE_CACHE_SHIFT)) {
++ pageaddr = kmap_atomic(page, KM_USER0);
++ goto skip_read;
++ }
++
++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
++ || page->index < (i_size_read(inode) >>
++ sblk->block_log)) {
++ block = (msblk->read_blocklist)(inode, page->index, 1,
++ block_list, NULL, &bsize);
++
++ down(&msblk->read_page_mutex);
++ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
++ bsize, NULL);
++ pageaddr = kmap_atomic(page, KM_USER0);
++ if (bytes)
++ memcpy(pageaddr, msblk->read_page, bytes);
++ else
++ ERROR("Unable to read page, block %llx, size %x\n",
++ block, bsize);
++ up(&msblk->read_page_mutex);
++ } else {
++ struct squashfs_fragment_cache *fragment =
++ get_cached_fragment(inode->i_sb,
++ SQUASHFS_I(inode)->
++ u.s1.fragment_start_block,
++ SQUASHFS_I(inode)-> u.s1.fragment_size);
++ pageaddr = kmap_atomic(page, KM_USER0);
++ if (fragment) {
++ bytes = i_size_read(inode) & (sblk->block_size - 1);
++ memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
++ u.s1.fragment_offset, bytes);
++ release_cached_fragment(msblk, fragment);
++ } else
++ ERROR("Unable to read page, block %llx, size %x\n",
++ SQUASHFS_I(inode)->
++ u.s1.fragment_start_block, (int)
++ SQUASHFS_I(inode)-> u.s1.fragment_size);
++ }
++
++skip_read:
++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
++ kunmap_atomic(pageaddr, KM_USER0);
++ flush_dcache_page(page);
++ SetPageUptodate(page);
++ UnlockPage(page);
++
++ return 0;
++}
++
++
++static int get_dir_index_using_offset(struct super_block *s, long long
++ *next_block, unsigned int *next_offset,
++ long long index_start,
++ unsigned int index_offset, int i_count,
++ long long f_pos)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ int i, length = 0;
++ struct squashfs_dir_index index;
++
++ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
++ i_count, (unsigned int) f_pos);
++
++ f_pos -= 3;
++ if (f_pos == 0)
++ goto finish;
++
++ for (i = 0; i < i_count; i++) {
++ if (msblk->swap) {
++ struct squashfs_dir_index sindex;
++ squashfs_get_cached_block(s, (char *) &sindex,
++ index_start, index_offset,
++ sizeof(sindex), &index_start,
++ &index_offset);
++ SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
++ } else
++ squashfs_get_cached_block(s, (char *) &index,
++ index_start, index_offset,
++ sizeof(index), &index_start,
++ &index_offset);
++
++ if (index.index > f_pos)
++ break;
++
++ squashfs_get_cached_block(s, NULL, index_start, index_offset,
++ index.size + 1, &index_start,
++ &index_offset);
++
++ length = index.index;
++ *next_block = index.start_block + sblk->directory_table_start;
++ }
++
++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++
++finish:
++ return length + 3;
++}
++
++
++static int get_dir_index_using_name(struct super_block *s, long long
++ *next_block, unsigned int *next_offset,
++ long long index_start,
++ unsigned int index_offset, int i_count,
++ const char *name, int size)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ int i, length = 0;
++ char buffer[sizeof(struct squashfs_dir_index) + SQUASHFS_NAME_LEN + 1];
++ struct squashfs_dir_index *index = (struct squashfs_dir_index *) buffer;
++ char str[SQUASHFS_NAME_LEN + 1];
++
++ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
++
++ strncpy(str, name, size);
++ str[size] = '\0';
++
++ for (i = 0; i < i_count; i++) {
++ if (msblk->swap) {
++ struct squashfs_dir_index sindex;
++ squashfs_get_cached_block(s, (char *) &sindex,
++ index_start, index_offset,
++ sizeof(sindex), &index_start,
++ &index_offset);
++ SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
++ } else
++ squashfs_get_cached_block(s, (char *) index,
++ index_start, index_offset,
++ sizeof(struct squashfs_dir_index),
++ &index_start, &index_offset);
++
++ squashfs_get_cached_block(s, index->name, index_start,
++ index_offset, index->size + 1,
++ &index_start, &index_offset);
++
++ index->name[index->size + 1] = '\0';
++
++ if (strcmp(index->name, str) > 0)
++ break;
++
++ length = index->index;
++ *next_block = index->start_block + sblk->directory_table_start;
++ }
++
++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++ return length + 3;
++}
++
++
++static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
++{
++ struct inode *i = file->f_dentry->d_inode;
++ struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ long long next_block = SQUASHFS_I(i)->start_block +
++ sblk->directory_table_start;
++ int next_offset = SQUASHFS_I(i)->offset, length = 0, dirs_read = 0,
++ dir_count;
++ struct squashfs_dir_header dirh;
++ char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
++ struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
++
++ TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
++
++ while(file->f_pos < 3) {
++ char *name;
++ int size, i_ino;
++
++ if(file->f_pos == 0) {
++ name = ".";
++ size = 1;
++ i_ino = i->i_ino;
++ } else {
++ name = "..";
++ size = 2;
++ i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
++ }
++ TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
++ (unsigned int) dirent, name, size, (int)
++ file->f_pos, i_ino,
++ squashfs_filetype_table[1]);
++
++ if (filldir(dirent, name, size,
++ file->f_pos, i_ino,
++ squashfs_filetype_table[1]) < 0) {
++ TRACE("Filldir returned less than 0\n");
++ goto finish;
++ }
++ file->f_pos += size;
++ dirs_read++;
++ }
++
++ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_start,
++ SQUASHFS_I(i)->u.s2.directory_index_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_count,
++ file->f_pos);
++
++ while (length < i_size_read(i)) {
++ /* read directory header */
++ if (msblk->swap) {
++ struct squashfs_dir_header sdirh;
++
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++ next_block, next_offset, sizeof(sdirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdirh);
++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++ next_block, next_offset, sizeof(dirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(dirh);
++ }
++
++ dir_count = dirh.count + 1;
++ while (dir_count--) {
++ if (msblk->swap) {
++ struct squashfs_dir_entry sdire;
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ &sdire, next_block, next_offset,
++ sizeof(sdire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdire);
++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ dire, next_block, next_offset,
++ sizeof(*dire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(*dire);
++ }
++
++ if (!squashfs_get_cached_block(i->i_sb, dire->name,
++ next_block, next_offset,
++ dire->size + 1, &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += dire->size + 1;
++
++ if (file->f_pos >= length)
++ continue;
++
++ dire->name[dire->size + 1] = '\0';
++
++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
++ (unsigned int) dirent, dire->name,
++ dire->size + 1, (int) file->f_pos,
++ dirh.start_block, dire->offset,
++ dirh.inode_number + dire->inode_number,
++ squashfs_filetype_table[dire->type]);
++
++ if (filldir(dirent, dire->name, dire->size + 1,
++ file->f_pos,
++ dirh.inode_number + dire->inode_number,
++ squashfs_filetype_table[dire->type])
++ < 0) {
++ TRACE("Filldir returned less than 0\n");
++ goto finish;
++ }
++ file->f_pos = length;
++ dirs_read++;
++ }
++ }
++
++finish:
++ return dirs_read;
++
++failed_read:
++ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++ next_offset);
++ return 0;
++}
++
++
++static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry)
++{
++ const unsigned char *name = dentry->d_name.name;
++ int len = dentry->d_name.len;
++ struct inode *inode = NULL;
++ struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ long long next_block = SQUASHFS_I(i)->start_block +
++ sblk->directory_table_start;
++ int next_offset = SQUASHFS_I(i)->offset, length = 0,
++ dir_count;
++ struct squashfs_dir_header dirh;
++ char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN];
++ struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
++
++ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
++
++ if (len > SQUASHFS_NAME_LEN)
++ goto exit_loop;
++
++ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_start,
++ SQUASHFS_I(i)->u.s2.directory_index_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_count, name,
++ len);
++
++ while (length < i_size_read(i)) {
++ /* read directory header */
++ if (msblk->swap) {
++ struct squashfs_dir_header sdirh;
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++ next_block, next_offset, sizeof(sdirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdirh);
++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++ next_block, next_offset, sizeof(dirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(dirh);
++ }
++
++ dir_count = dirh.count + 1;
++ while (dir_count--) {
++ if (msblk->swap) {
++ struct squashfs_dir_entry sdire;
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ &sdire, next_block,next_offset,
++ sizeof(sdire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdire);
++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ dire, next_block,next_offset,
++ sizeof(*dire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(*dire);
++ }
++
++ if (!squashfs_get_cached_block(i->i_sb, dire->name,
++ next_block, next_offset, dire->size + 1,
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += dire->size + 1;
++
++ if (name[0] < dire->name[0])
++ goto exit_loop;
++
++ if ((len == dire->size + 1) && !strncmp(name,
++ dire->name, len)) {
++ squashfs_inode_t ino =
++ SQUASHFS_MKINODE(dirh.start_block,
++ dire->offset);
++
++ TRACE("calling squashfs_iget for directory "
++ "entry %s, inode %x:%x, %d\n", name,
++ dirh.start_block, dire->offset,
++ dirh.inode_number + dire->inode_number);
++
++ inode = (msblk->iget)(i->i_sb, ino);
++
++ goto exit_loop;
++ }
++ }
++ }
++
++exit_loop:
++ d_add(dentry, inode);
++ return ERR_PTR(0);
++
++failed_read:
++ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++ next_offset);
++ goto exit_loop;
++}
++
++
++static void squashfs_put_super(struct super_block *s)
++{
++ int i;
++
++ struct squashfs_sb_info *sbi = &s->u.squashfs_sb;
++ if (sbi->block_cache)
++ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
++ if (sbi->block_cache[i].block !=
++ SQUASHFS_INVALID_BLK)
++ kfree(sbi->block_cache[i].data);
++ if (sbi->fragment)
++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++)
++ SQUASHFS_FREE(sbi->fragment[i].data);
++ kfree(sbi->fragment);
++ kfree(sbi->block_cache);
++ kfree(sbi->read_data);
++ kfree(sbi->read_page);
++ kfree(sbi->uid);
++ kfree(sbi->fragment_index);
++ kfree(sbi->fragment_index_2);
++ sbi->block_cache = NULL;
++ sbi->uid = NULL;
++ sbi->read_data = NULL;
++ sbi->read_page = NULL;
++ sbi->fragment = NULL;
++ sbi->fragment_index = NULL;
++ sbi->fragment_index_2 = NULL;
++}
++
++
++static int __init init_squashfs_fs(void)
++{
++
++ printk(KERN_INFO "squashfs: version 3.0 (2006/03/15) "
++ "Phillip Lougher\n");
++
++ if (!(stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
++ ERROR("Failed to allocate zlib workspace\n");
++ return -ENOMEM;
++ }
++ return register_filesystem(&squashfs_fs_type);
++}
++
++
++static void __exit exit_squashfs_fs(void)
++{
++ vfree(stream.workspace);
++ unregister_filesystem(&squashfs_fs_type);
++}
++
++
++EXPORT_NO_SYMBOLS;
++
++module_init(init_squashfs_fs);
++module_exit(exit_squashfs_fs);
++MODULE_DESCRIPTION("squashfs, a compressed read-only filesystem");
++MODULE_AUTHOR("Phillip Lougher <phillip@lougher.org.uk>");
++MODULE_LICENSE("GPL");
+diff --new-file -urp linux-2.4.32/fs/squashfs/Makefile linux-2.4.32-squashfs3.0/fs/squashfs/Makefile
+--- linux-2.4.32/fs/squashfs/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-squashfs3.0/fs/squashfs/Makefile 2006-03-07 21:12:36.000000000 +0000
+@@ -0,0 +1,11 @@
++#
++# Makefile for the linux squashfs routines.
++#
++
++O_TARGET := squashfs.o
++
++obj-y := inode.o squashfs2_0.o
++
++obj-m := $(O_TARGET)
++
++include $(TOPDIR)/Rules.make
+diff --new-file -urp linux-2.4.32/fs/squashfs/squashfs2_0.c linux-2.4.32-squashfs3.0/fs/squashfs/squashfs2_0.c
+--- linux-2.4.32/fs/squashfs/squashfs2_0.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-squashfs3.0/fs/squashfs/squashfs2_0.c 2006-03-07 21:12:36.000000000 +0000
+@@ -0,0 +1,751 @@
++/*
++ * Squashfs - a compressed read only filesystem for Linux
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.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,
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs2_0.c
++ */
++
++#include <linux/types.h>
++#include <linux/squashfs_fs.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/smp_lock.h>
++#include <linux/locks.h>
++#include <linux/init.h>
++#include <linux/dcache.h>
++#include <linux/wait.h>
++#include <linux/zlib.h>
++#include <linux/blkdev.h>
++#include <linux/vmalloc.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++#include "squashfs.h"
++
++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
++static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry);
++
++static struct file_operations squashfs_dir_ops_2 = {
++ .read = generic_read_dir,
++ .readdir = squashfs_readdir_2
++};
++
++static struct inode_operations squashfs_dir_inode_ops_2 = {
++ .lookup = squashfs_lookup_2
++};
++
++static unsigned char squashfs_filetype_table[] = {
++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
++};
++
++static int read_fragment_index_table_2(struct super_block *s)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++
++ if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2
++ (sblk->fragments), GFP_KERNEL))) {
++ ERROR("Failed to allocate uid/gid table\n");
++ return 0;
++ }
++
++ if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) &&
++ !squashfs_read_data(s, (char *)
++ msblk->fragment_index_2,
++ sblk->fragment_table_start,
++ SQUASHFS_FRAGMENT_INDEX_BYTES_2
++ (sblk->fragments) |
++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++ ERROR("unable to read fragment index table\n");
++ return 0;
++ }
++
++ if (msblk->swap) {
++ int i;
++ unsigned int fragment;
++
++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments);
++ i++) {
++ SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment),
++ &msblk->fragment_index_2[i], 1);
++ msblk->fragment_index_2[i] = fragment;
++ }
++ }
++
++ return 1;
++}
++
++
++static int get_fragment_location_2(struct super_block *s, unsigned int fragment,
++ long long *fragment_start_block,
++ unsigned int *fragment_size)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ long long start_block =
++ msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)];
++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment);
++ struct squashfs_fragment_entry_2 fragment_entry;
++
++ if (msblk->swap) {
++ struct squashfs_fragment_entry_2 sfragment_entry;
++
++ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
++ start_block, offset,
++ sizeof(sfragment_entry), &start_block,
++ &offset))
++ goto out;
++ SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry);
++ } else
++ if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
++ start_block, offset,
++ sizeof(fragment_entry), &start_block,
++ &offset))
++ goto out;
++
++ *fragment_start_block = fragment_entry.start_block;
++ *fragment_size = fragment_entry.size;
++
++ return 1;
++
++out:
++ return 0;
++}
++
++
++static struct inode *squashfs_new_inode(struct super_block *s,
++ struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ struct inode *i = new_inode(s);
++
++ if (i) {
++ i->i_ino = ino;
++ i->i_mtime = sblk->mkfs_time;
++ i->i_atime = sblk->mkfs_time;
++ i->i_ctime = sblk->mkfs_time;
++ i->i_uid = msblk->uid[inodeb->uid];
++ i->i_mode = inodeb->mode;
++ i->i_nlink = 1;
++ i->i_size = 0;
++ if (inodeb->guid == SQUASHFS_GUIDS)
++ i->i_gid = i->i_uid;
++ else
++ i->i_gid = msblk->guid[inodeb->guid];
++ }
++
++ return i;
++}
++
++
++static struct inode *squashfs_iget_2(struct super_block *s, squashfs_inode_t inode)
++{
++ struct inode *i;
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ unsigned int block = SQUASHFS_INODE_BLK(inode) +
++ sblk->inode_table_start;
++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
++ unsigned int ino = SQUASHFS_MK_VFS_INODE(block
++ - sblk->inode_table_start, offset);
++ long long next_block;
++ unsigned int next_offset;
++ union squashfs_inode_header_2 id, sid;
++ struct squashfs_base_inode_header_2 *inodeb = &id.base,
++ *sinodeb = &sid.base;
++
++ TRACE("Entered squashfs_iget\n");
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
++ offset, sizeof(*sinodeb), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
++ sizeof(*sinodeb));
++ } else
++ if (!squashfs_get_cached_block(s, (char *) inodeb, block,
++ offset, sizeof(*inodeb), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ switch(inodeb->inode_type) {
++ case SQUASHFS_FILE_TYPE: {
++ struct squashfs_reg_inode_header_2 *inodep = &id.reg;
++ struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
++ long long frag_blk;
++ unsigned int frag_size;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ frag_blk = SQUASHFS_INVALID_BLK;
++ if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
++ !get_fragment_location_2(s,
++ inodep->fragment, &frag_blk, &frag_size))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++ goto failed_read1;
++
++ i->i_size = inodep->file_size;
++ i->i_fop = &generic_ro_fops;
++ i->i_mode |= S_IFREG;
++ i->i_mtime = inodep->mtime;
++ i->i_atime = inodep->mtime;
++ i->i_ctime = inodep->mtime;
++ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
++ i->i_blksize = PAGE_CACHE_SIZE;
++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
++ SQUASHFS_I(i)->start_block = inodep->start_block;
++ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
++ SQUASHFS_I(i)->offset = next_offset;
++ if (sblk->block_size > 4096)
++ i->i_data.a_ops = &squashfs_aops;
++ else
++ i->i_data.a_ops = &squashfs_aops_4K;
++
++ TRACE("File inode %x:%x, start_block %x, "
++ "block_list_start %llx, offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ inodep->start_block, next_block,
++ next_offset);
++ break;
++ }
++ case SQUASHFS_DIR_TYPE: {
++ struct squashfs_dir_inode_header_2 *inodep = &id.dir;
++ struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++ goto failed_read1;
++
++ i->i_size = inodep->file_size;
++ i->i_op = &squashfs_dir_inode_ops_2;
++ i->i_fop = &squashfs_dir_ops_2;
++ i->i_mode |= S_IFDIR;
++ i->i_mtime = inodep->mtime;
++ i->i_atime = inodep->mtime;
++ i->i_ctime = inodep->mtime;
++ SQUASHFS_I(i)->start_block = inodep->start_block;
++ SQUASHFS_I(i)->offset = inodep->offset;
++ SQUASHFS_I(i)->u.s2.directory_index_count = 0;
++ SQUASHFS_I(i)->u.s2.parent_inode = 0;
++
++ TRACE("Directory inode %x:%x, start_block %x, offset "
++ "%x\n", SQUASHFS_INODE_BLK(inode),
++ offset, inodep->start_block,
++ inodep->offset);
++ break;
++ }
++ case SQUASHFS_LDIR_TYPE: {
++ struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
++ struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
++ sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++ goto failed_read1;
++
++ i->i_size = inodep->file_size;
++ i->i_op = &squashfs_dir_inode_ops_2;
++ i->i_fop = &squashfs_dir_ops_2;
++ i->i_mode |= S_IFDIR;
++ i->i_mtime = inodep->mtime;
++ i->i_atime = inodep->mtime;
++ i->i_ctime = inodep->mtime;
++ SQUASHFS_I(i)->start_block = inodep->start_block;
++ SQUASHFS_I(i)->offset = inodep->offset;
++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
++ SQUASHFS_I(i)->u.s2.directory_index_offset =
++ next_offset;
++ SQUASHFS_I(i)->u.s2.directory_index_count =
++ inodep->i_count;
++ SQUASHFS_I(i)->u.s2.parent_inode = 0;
++
++ TRACE("Long directory inode %x:%x, start_block %x, "
++ "offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ inodep->start_block, inodep->offset);
++ break;
++ }
++ case SQUASHFS_SYMLINK_TYPE: {
++ struct squashfs_symlink_inode_header_2 *inodep =
++ &id.symlink;
++ struct squashfs_symlink_inode_header_2 *sinodep =
++ &sid.symlink;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
++ sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++ goto failed_read1;
++
++ i->i_size = inodep->symlink_size;
++ i->i_op = &page_symlink_inode_operations;
++ i->i_data.a_ops = &squashfs_symlink_aops;
++ i->i_mode |= S_IFLNK;
++ SQUASHFS_I(i)->start_block = next_block;
++ SQUASHFS_I(i)->offset = next_offset;
++
++ TRACE("Symbolic link inode %x:%x, start_block %llx, "
++ "offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ next_block, next_offset);
++ break;
++ }
++ case SQUASHFS_BLKDEV_TYPE:
++ case SQUASHFS_CHRDEV_TYPE: {
++ struct squashfs_dev_inode_header_2 *inodep = &id.dev;
++ struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++ goto failed_read1;
++
++ i->i_mode |= (inodeb->inode_type ==
++ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR :
++ S_IFBLK;
++ init_special_inode(i, i->i_mode, inodep->rdev);
++
++ TRACE("Device inode %x:%x, rdev %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ inodep->rdev);
++ break;
++ }
++ case SQUASHFS_FIFO_TYPE:
++ case SQUASHFS_SOCKET_TYPE: {
++ if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++ goto failed_read1;
++
++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
++ ? S_IFIFO : S_IFSOCK;
++ init_special_inode(i, i->i_mode, 0);
++ break;
++ }
++ default:
++ ERROR("Unknown inode type %d in squashfs_iget!\n",
++ inodeb->inode_type);
++ goto failed_read1;
++ }
++
++ insert_inode_hash(i);
++ return i;
++
++failed_read:
++ ERROR("Unable to read inode [%x:%x]\n", block, offset);
++
++failed_read1:
++ return NULL;
++}
++
++
++static int get_dir_index_using_offset(struct super_block *s, long long
++ *next_block, unsigned int *next_offset,
++ long long index_start,
++ unsigned int index_offset, int i_count,
++ long long f_pos)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ int i, length = 0;
++ struct squashfs_dir_index_2 index;
++
++ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
++ i_count, (unsigned int) f_pos);
++
++ if (f_pos == 0)
++ goto finish;
++
++ for (i = 0; i < i_count; i++) {
++ if (msblk->swap) {
++ struct squashfs_dir_index_2 sindex;
++ squashfs_get_cached_block(s, (char *) &sindex,
++ index_start, index_offset,
++ sizeof(sindex), &index_start,
++ &index_offset);
++ SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex);
++ } else
++ squashfs_get_cached_block(s, (char *) &index,
++ index_start, index_offset,
++ sizeof(index), &index_start,
++ &index_offset);
++
++ if (index.index > f_pos)
++ break;
++
++ squashfs_get_cached_block(s, NULL, index_start, index_offset,
++ index.size + 1, &index_start,
++ &index_offset);
++
++ length = index.index;
++ *next_block = index.start_block + sblk->directory_table_start;
++ }
++
++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++
++finish:
++ return length;
++}
++
++
++static int get_dir_index_using_name(struct super_block *s, long long
++ *next_block, unsigned int *next_offset,
++ long long index_start,
++ unsigned int index_offset, int i_count,
++ const char *name, int size)
++{
++ struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ int i, length = 0;
++ char buffer[sizeof(struct squashfs_dir_index_2) + SQUASHFS_NAME_LEN + 1];
++ struct squashfs_dir_index_2 *index = (struct squashfs_dir_index_2 *) buffer;
++ char str[SQUASHFS_NAME_LEN + 1];
++
++ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
++
++ strncpy(str, name, size);
++ str[size] = '\0';
++
++ for (i = 0; i < i_count; i++) {
++ if (msblk->swap) {
++ struct squashfs_dir_index_2 sindex;
++ squashfs_get_cached_block(s, (char *) &sindex,
++ index_start, index_offset,
++ sizeof(sindex), &index_start,
++ &index_offset);
++ SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex);
++ } else
++ squashfs_get_cached_block(s, (char *) index,
++ index_start, index_offset,
++ sizeof(struct squashfs_dir_index_2),
++ &index_start, &index_offset);
++
++ squashfs_get_cached_block(s, index->name, index_start,
++ index_offset, index->size + 1,
++ &index_start, &index_offset);
++
++ index->name[index->size + 1] = '\0';
++
++ if (strcmp(index->name, str) > 0)
++ break;
++
++ length = index->index;
++ *next_block = index->start_block + sblk->directory_table_start;
++ }
++
++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++ return length;
++}
++
++
++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
++{
++ struct inode *i = file->f_dentry->d_inode;
++ struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ long long next_block = SQUASHFS_I(i)->start_block +
++ sblk->directory_table_start;
++ int next_offset = SQUASHFS_I(i)->offset, length = 0, dirs_read = 0,
++ dir_count;
++ struct squashfs_dir_header_2 dirh;
++ char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1];
++ struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer;
++
++ TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
++
++ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_start,
++ SQUASHFS_I(i)->u.s2.directory_index_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_count,
++ file->f_pos);
++
++ while (length < i_size_read(i)) {
++ /* read directory header */
++ if (msblk->swap) {
++ struct squashfs_dir_header_2 sdirh;
++
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++ next_block, next_offset, sizeof(sdirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdirh);
++ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++ next_block, next_offset, sizeof(dirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(dirh);
++ }
++
++ dir_count = dirh.count + 1;
++ while (dir_count--) {
++ if (msblk->swap) {
++ struct squashfs_dir_entry_2 sdire;
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ &sdire, next_block, next_offset,
++ sizeof(sdire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdire);
++ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ dire, next_block, next_offset,
++ sizeof(*dire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(*dire);
++ }
++
++ if (!squashfs_get_cached_block(i->i_sb, dire->name,
++ next_block, next_offset,
++ dire->size + 1, &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += dire->size + 1;
++
++ if (file->f_pos >= length)
++ continue;
++
++ dire->name[dire->size + 1] = '\0';
++
++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
++ (unsigned int) dirent, dire->name,
++ dire->size + 1, (int) file->f_pos,
++ dirh.start_block, dire->offset,
++ squashfs_filetype_table[dire->type]);
++
++ if (filldir(dirent, dire->name, dire->size + 1,
++ file->f_pos, SQUASHFS_MK_VFS_INODE(
++ dirh.start_block, dire->offset),
++ squashfs_filetype_table[dire->type])
++ < 0) {
++ TRACE("Filldir returned less than 0\n");
++ goto finish;
++ }
++ file->f_pos = length;
++ dirs_read++;
++ }
++ }
++
++finish:
++ return dirs_read;
++
++failed_read:
++ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++ next_offset);
++ return 0;
++}
++
++
++static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry)
++{
++ const unsigned char *name = dentry->d_name.name;
++ int len = dentry->d_name.len;
++ struct inode *inode = NULL;
++ struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ long long next_block = SQUASHFS_I(i)->start_block +
++ sblk->directory_table_start;
++ int next_offset = SQUASHFS_I(i)->offset, length = 0,
++ dir_count;
++ struct squashfs_dir_header_2 dirh;
++ char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN];
++ struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer;
++ int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
++
++ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
++
++ if (len > SQUASHFS_NAME_LEN)
++ goto exit_loop;
++
++ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_start,
++ SQUASHFS_I(i)->u.s2.directory_index_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_count, name,
++ len);
++
++ while (length < i_size_read(i)) {
++ /* read directory header */
++ if (msblk->swap) {
++ struct squashfs_dir_header_2 sdirh;
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++ next_block, next_offset, sizeof(sdirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdirh);
++ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++ next_block, next_offset, sizeof(dirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(dirh);
++ }
++
++ dir_count = dirh.count + 1;
++ while (dir_count--) {
++ if (msblk->swap) {
++ struct squashfs_dir_entry_2 sdire;
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ &sdire, next_block,next_offset,
++ sizeof(sdire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdire);
++ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ dire, next_block,next_offset,
++ sizeof(*dire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(*dire);
++ }
++
++ if (!squashfs_get_cached_block(i->i_sb, dire->name,
++ next_block, next_offset, dire->size + 1,
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += dire->size + 1;
++
++ if (sorted && name[0] < dire->name[0])
++ goto exit_loop;
++
++ if ((len == dire->size + 1) && !strncmp(name,
++ dire->name, len)) {
++ squashfs_inode_t ino =
++ SQUASHFS_MKINODE(dirh.start_block,
++ dire->offset);
++
++ TRACE("calling squashfs_iget for directory "
++ "entry %s, inode %x:%x, %d\n", name,
++ dirh.start_block, dire->offset, ino);
++
++ inode = (msblk->iget)(i->i_sb, ino);
++
++ goto exit_loop;
++ }
++ }
++ }
++
++exit_loop:
++ d_add(dentry, inode);
++ return ERR_PTR(0);
++
++failed_read:
++ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++ next_offset);
++ goto exit_loop;
++}
++
++
++int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
++{
++ struct squashfs_super_block *sblk = &msblk->sblk;
++
++ msblk->iget = squashfs_iget_2;
++ msblk->read_fragment_index_table = read_fragment_index_table_2;
++
++ sblk->bytes_used = sblk->bytes_used_2;
++ sblk->uid_start = sblk->uid_start_2;
++ sblk->guid_start = sblk->guid_start_2;
++ sblk->inode_table_start = sblk->inode_table_start_2;
++ sblk->directory_table_start = sblk->directory_table_start_2;
++ sblk->fragment_table_start = sblk->fragment_table_start_2;
++
++ return 1;
++}
+diff --new-file -urp linux-2.4.32/fs/squashfs/squashfs.h linux-2.4.32-squashfs3.0/fs/squashfs/squashfs.h
+--- linux-2.4.32/fs/squashfs/squashfs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-squashfs3.0/fs/squashfs/squashfs.h 2006-03-07 21:12:36.000000000 +0000
+@@ -0,0 +1,85 @@
++/*
++ * Squashfs - a compressed read only filesystem for Linux
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.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,
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs.h
++ */
++
++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++#endif
++#ifdef SQUASHFS_TRACE
++#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args)
++#else
++#define TRACE(s, args...) {}
++#endif
++
++#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args)
++
++#define SERROR(s, args...) do { \
++ if (!silent) \
++ printk(KERN_ERR "SQUASHFS error: "s, ## args);\
++ } while(0)
++
++#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args)
++
++#define SQUASHFS_I(INO) (&INO->u.squashfs_i)
++
++#define i_size_read(INO) (INO->i_size)
++
++#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY)
++#define SQSH_EXTERN
++extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
++ long long index, unsigned int length,
++ long long *next_index);
++extern int squashfs_get_cached_block(struct super_block *s, char *buffer,
++ long long block, unsigned int offset,
++ int length, long long *next_block,
++ unsigned int *next_offset);
++extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct
++ squashfs_fragment_cache *fragment);
++extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block
++ *s, long long start_block,
++ int length);
++extern struct address_space_operations squashfs_symlink_aops;
++extern struct address_space_operations squashfs_aops;
++extern struct address_space_operations squashfs_aops_4K;
++extern struct file_operations squashfs_dir_ops;
++extern struct inode_operations squashfs_dir_inode_ops;
++#else
++#define SQSH_EXTERN static
++#endif
++
++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk);
++#else
++static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk)
++{
++ return 0;
++}
++#endif
++
++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk);
++#else
++static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
++{
++ return 0;
++}
++#endif
+diff --new-file -urp linux-2.4.32/include/linux/fs.h linux-2.4.32-squashfs3.0/include/linux/fs.h
+--- linux-2.4.32/include/linux/fs.h 2005-04-04 02:42:20.000000000 +0100
++++ linux-2.4.32-squashfs3.0/include/linux/fs.h 2006-03-07 21:12:36.000000000 +0000
+@@ -324,6 +324,7 @@ extern void set_bh_page(struct buffer_he
+ #include <linux/usbdev_fs_i.h>
+ #include <linux/jffs2_fs_i.h>
+ #include <linux/cramfs_fs_sb.h>
++#include <linux/squashfs_fs_i.h>
+
+ /*
+ * Attribute flags. These should be or-ed together to figure out what
+@@ -519,6 +520,7 @@ struct inode {
+ struct socket socket_i;
+ struct usbdev_inode_info usbdev_i;
+ struct jffs2_inode_info jffs2_i;
++ struct squashfs_inode_info squashfs_i;
+ void *generic_ip;
+ } u;
+ };
+@@ -734,6 +736,7 @@ struct nameidata {
+ #include <linux/usbdev_fs_sb.h>
+ #include <linux/cramfs_fs_sb.h>
+ #include <linux/jffs2_fs_sb.h>
++#include <linux/squashfs_fs_sb.h>
+
+ extern struct list_head super_blocks;
+ extern spinlock_t sb_lock;
+@@ -793,6 +796,7 @@ struct super_block {
+ struct usbdev_sb_info usbdevfs_sb;
+ struct jffs2_sb_info jffs2_sb;
+ struct cramfs_sb_info cramfs_sb;
++ struct squashfs_sb_info squashfs_sb;
+ void *generic_sbp;
+ } u;
+ /*
+diff --new-file -urp linux-2.4.32/include/linux/squashfs_fs.h linux-2.4.32-squashfs3.0/include/linux/squashfs_fs.h
+--- linux-2.4.32/include/linux/squashfs_fs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-squashfs3.0/include/linux/squashfs_fs.h 2006-03-07 21:12:36.000000000 +0000
+@@ -0,0 +1,915 @@
++#ifndef SQUASHFS_FS
++#define SQUASHFS_FS
++
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.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,
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs_fs.h
++ */
++
++#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
++#endif
++
++#ifdef CONFIG_SQUASHFS_VMALLOC
++#define SQUASHFS_ALLOC(a) vmalloc(a)
++#define SQUASHFS_FREE(a) vfree(a)
++#else
++#define SQUASHFS_ALLOC(a) kmalloc(a, GFP_KERNEL)
++#define SQUASHFS_FREE(a) kfree(a)
++#endif
++#ifdef CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
++#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
++#else
++#define SQUASHFS_CACHED_FRAGMENTS 3
++#endif
++#define SQUASHFS_MAJOR 3
++#define SQUASHFS_MINOR 0
++#define SQUASHFS_MAGIC 0x73717368
++#define SQUASHFS_MAGIC_SWAP 0x68737173
++#define SQUASHFS_START 0
++
++/* size of metadata (inode and directory) blocks */
++#define SQUASHFS_METADATA_SIZE 8192
++#define SQUASHFS_METADATA_LOG 13
++
++/* default size of data blocks */
++#define SQUASHFS_FILE_SIZE 65536
++#define SQUASHFS_FILE_LOG 16
++
++#define SQUASHFS_FILE_MAX_SIZE 65536
++
++/* Max number of uids and gids */
++#define SQUASHFS_UIDS 256
++#define SQUASHFS_GUIDS 255
++
++/* Max length of filename (not 255) */
++#define SQUASHFS_NAME_LEN 256
++
++#define SQUASHFS_INVALID ((long long) 0xffffffffffff)
++#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff)
++#define SQUASHFS_INVALID_BLK ((long long) -1)
++#define SQUASHFS_USED_BLK ((long long) -2)
++
++/* Filesystem flags */
++#define SQUASHFS_NOI 0
++#define SQUASHFS_NOD 1
++#define SQUASHFS_CHECK 2
++#define SQUASHFS_NOF 3
++#define SQUASHFS_NO_FRAG 4
++#define SQUASHFS_ALWAYS_FRAG 5
++#define SQUASHFS_DUPLICATE 6
++
++#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1)
++
++#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \
++ SQUASHFS_NOI)
++
++#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \
++ SQUASHFS_NOD)
++
++#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
++ SQUASHFS_NOF)
++
++#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
++ SQUASHFS_NO_FRAG)
++
++#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
++ SQUASHFS_ALWAYS_FRAG)
++
++#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \
++ SQUASHFS_DUPLICATE)
++
++#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \
++ SQUASHFS_CHECK)
++
++#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
++ duplicate_checking) (noi | (nod << 1) | (check_data << 2) \
++ | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
++ (duplicate_checking << 6))
++
++/* Max number of types and file types */
++#define SQUASHFS_DIR_TYPE 1
++#define SQUASHFS_FILE_TYPE 2
++#define SQUASHFS_SYMLINK_TYPE 3
++#define SQUASHFS_BLKDEV_TYPE 4
++#define SQUASHFS_CHRDEV_TYPE 5
++#define SQUASHFS_FIFO_TYPE 6
++#define SQUASHFS_SOCKET_TYPE 7
++#define SQUASHFS_LDIR_TYPE 8
++#define SQUASHFS_LREG_TYPE 9
++
++/* 1.0 filesystem type definitions */
++#define SQUASHFS_TYPES 5
++#define SQUASHFS_IPC_TYPE 0
++
++/* Flag whether block is compressed or uncompressed, bit is set if block is
++ * uncompressed */
++#define SQUASHFS_COMPRESSED_BIT (1 << 15)
++
++#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
++ (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT)
++
++#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT))
++
++#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
++
++#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & \
++ ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \
++ ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK)
++
++#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
++
++/*
++ * Inode number ops. Inodes consist of a compressed block number, and an
++ * uncompressed offset within that block
++ */
++#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16))
++
++#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff))
++
++#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\
++ << 16) + (B)))
++
++/* Compute 32 bit VFS inode number from squashfs inode number */
++#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \
++ ((b) >> 2) + 1))
++/* XXX */
++
++/* Translate between VFS mode and squashfs mode */
++#define SQUASHFS_MODE(a) ((a) & 0xfff)
++
++/* fragment and fragment table defines */
++#define SQUASHFS_FRAGMENT_BYTES(A) (A * sizeof(struct squashfs_fragment_entry))
++
++#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \
++ SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \
++ SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \
++ SQUASHFS_METADATA_SIZE - 1) / \
++ SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\
++ sizeof(long long))
++
++/* cached data constants for filesystem */
++#define SQUASHFS_CACHED_BLKS 8
++
++#define SQUASHFS_MAX_FILE_SIZE_LOG 64
++
++#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \
++ (SQUASHFS_MAX_FILE_SIZE_LOG - 2))
++
++#define SQUASHFS_MARKER_BYTE 0xff
++
++/* meta index cache */
++#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
++#define SQUASHFS_META_ENTRIES 31
++#define SQUASHFS_META_NUMBER 8
++#define SQUASHFS_SLOTS 4
++
++struct meta_entry {
++ long long data_block;
++ unsigned int index_block;
++ unsigned short offset;
++ unsigned short pad;
++};
++
++struct meta_index {
++ unsigned int inode_number;
++ unsigned int offset;
++ unsigned short entries;
++ unsigned short skip;
++ unsigned short locked;
++ unsigned short pad;
++ struct meta_entry meta_entry[SQUASHFS_META_ENTRIES];
++};
++
++
++/*
++ * definitions for structures on disk
++ */
++
++typedef long long squashfs_block_t;
++typedef long long squashfs_inode_t;
++
++struct squashfs_super_block {
++ unsigned int s_magic;
++ unsigned int inodes;
++ unsigned int bytes_used_2;
++ unsigned int uid_start_2;
++ unsigned int guid_start_2;
++ unsigned int inode_table_start_2;
++ unsigned int directory_table_start_2;
++ unsigned int s_major:16;
++ unsigned int s_minor:16;
++ unsigned int block_size_1:16;
++ unsigned int block_log:16;
++ unsigned int flags:8;
++ unsigned int no_uids:8;
++ unsigned int no_guids:8;
++ unsigned int mkfs_time /* time of filesystem creation */;
++ squashfs_inode_t root_inode;
++ unsigned int block_size;
++ unsigned int fragments;
++ unsigned int fragment_table_start_2;
++ long long bytes_used;
++ long long uid_start;
++ long long guid_start;
++ long long inode_table_start;
++ long long directory_table_start;
++ long long fragment_table_start;
++ long long unused;
++} __attribute__ ((packed));
++
++struct squashfs_dir_index {
++ unsigned int index;
++ unsigned int start_block;
++ unsigned char size;
++ unsigned char name[0];
++} __attribute__ ((packed));
++
++#define SQUASHFS_BASE_INODE_HEADER \
++ unsigned int inode_type:4; \
++ unsigned int mode:12; \
++ unsigned int uid:8; \
++ unsigned int guid:8; \
++ unsigned int mtime; \
++ unsigned int inode_number;
++
++struct squashfs_base_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++} __attribute__ ((packed));
++
++struct squashfs_ipc_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++ unsigned int nlink;
++} __attribute__ ((packed));
++
++struct squashfs_dev_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++ unsigned int nlink;
++ unsigned short rdev;
++} __attribute__ ((packed));
++
++struct squashfs_symlink_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++ unsigned int nlink;
++ unsigned short symlink_size;
++ char symlink[0];
++} __attribute__ ((packed));
++
++struct squashfs_reg_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++ squashfs_block_t start_block;
++ unsigned int fragment;
++ unsigned int offset;
++ unsigned int file_size;
++ unsigned short block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_lreg_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++ unsigned int nlink;
++ squashfs_block_t start_block;
++ unsigned int fragment;
++ unsigned int offset;
++ long long file_size;
++ unsigned short block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++ unsigned int nlink;
++ unsigned int file_size:19;
++ unsigned int offset:13;
++ unsigned int start_block;
++ unsigned int parent_inode;
++} __attribute__ ((packed));
++
++struct squashfs_ldir_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++ unsigned int nlink;
++ unsigned int file_size:27;
++ unsigned int offset:13;
++ unsigned int start_block;
++ unsigned int i_count:16;
++ unsigned int parent_inode;
++ struct squashfs_dir_index index[0];
++} __attribute__ ((packed));
++
++union squashfs_inode_header {
++ struct squashfs_base_inode_header base;
++ struct squashfs_dev_inode_header dev;
++ struct squashfs_symlink_inode_header symlink;
++ struct squashfs_reg_inode_header reg;
++ struct squashfs_lreg_inode_header lreg;
++ struct squashfs_dir_inode_header dir;
++ struct squashfs_ldir_inode_header ldir;
++ struct squashfs_ipc_inode_header ipc;
++};
++
++struct squashfs_dir_entry {
++ unsigned int offset:13;
++ unsigned int type:3;
++ unsigned int size:8;
++ int inode_number:16;
++ char name[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_header {
++ unsigned int count:8;
++ unsigned int start_block;
++ unsigned int inode_number;
++} __attribute__ ((packed));
++
++struct squashfs_fragment_entry {
++ long long start_block;
++ unsigned int size;
++ unsigned int unused;
++} __attribute__ ((packed));
++
++extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
++extern int squashfs_uncompress_init(void);
++extern int squashfs_uncompress_exit(void);
++
++/*
++ * macros to convert each packed bitfield structure from little endian to big
++ * endian and vice versa. These are needed when creating or using a filesystem
++ * on a machine with different byte ordering to the target architecture.
++ *
++ */
++
++#define SQUASHFS_SWAP_START \
++ int bits;\
++ int b_pos;\
++ unsigned long long val;\
++ unsigned char *s;\
++ unsigned char *d;
++
++#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
++ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
++ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
++ SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
++ SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
++ SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
++ SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
++ SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
++ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
++ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
++ SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
++ SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
++ SQUASHFS_SWAP((s)->flags, d, 288, 8);\
++ SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
++ SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
++ SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
++ SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
++ SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
++ SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
++ SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
++ SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
++ SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
++ SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
++ SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
++ SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
++ SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
++ SQUASHFS_SWAP((s)->unused, d, 888, 64);\
++}
++
++#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
++ SQUASHFS_MEMSET(s, d, n);\
++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\
++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\
++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
++ SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
++
++#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
++}
++
++#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++ sizeof(struct squashfs_ipc_inode_header))\
++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++}
++
++#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++ sizeof(struct squashfs_dev_inode_header)); \
++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++ SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
++}
++
++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++ sizeof(struct squashfs_symlink_inode_header));\
++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++ SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
++}
++
++#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++ sizeof(struct squashfs_reg_inode_header));\
++ SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
++ SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
++ SQUASHFS_SWAP((s)->offset, d, 192, 32);\
++ SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
++}
++
++#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++ sizeof(struct squashfs_lreg_inode_header));\
++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
++ SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
++ SQUASHFS_SWAP((s)->offset, d, 224, 32);\
++ SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
++}
++
++#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++ sizeof(struct squashfs_dir_inode_header));\
++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++ SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
++ SQUASHFS_SWAP((s)->offset, d, 147, 13);\
++ SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
++ SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
++}
++
++#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++ sizeof(struct squashfs_ldir_inode_header));\
++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++ SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
++ SQUASHFS_SWAP((s)->offset, d, 155, 13);\
++ SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
++ SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
++ SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
++ SQUASHFS_SWAP((s)->index, d, 0, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
++ SQUASHFS_SWAP((s)->size, d, 64, 8);\
++}
++
++#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
++ SQUASHFS_SWAP((s)->count, d, 0, 8);\
++ SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
++ SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\
++ SQUASHFS_SWAP((s)->type, d, 13, 3);\
++ SQUASHFS_SWAP((s)->size, d, 16, 8);\
++ SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
++ SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
++ SQUASHFS_SWAP((s)->size, d, 64, 32);\
++}
++
++#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
++ int entry;\
++ int bit_position;\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, n * 2);\
++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++ 16)\
++ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
++}
++
++#define SQUASHFS_SWAP_INTS(s, d, n) {\
++ int entry;\
++ int bit_position;\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, n * 4);\
++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++ 32)\
++ SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
++}
++
++#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
++ int entry;\
++ int bit_position;\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, n * 8);\
++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++ 64)\
++ SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
++}
++
++#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
++ int entry;\
++ int bit_position;\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, n * bits / 8);\
++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++ bits)\
++ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
++
++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++
++struct squashfs_base_inode_header_1 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:4; /* index into uid table */
++ unsigned int guid:4; /* index into guid table */
++} __attribute__ ((packed));
++
++struct squashfs_ipc_inode_header_1 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:4; /* index into uid table */
++ unsigned int guid:4; /* index into guid table */
++ unsigned int type:4;
++ unsigned int offset:4;
++} __attribute__ ((packed));
++
++struct squashfs_dev_inode_header_1 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:4; /* index into uid table */
++ unsigned int guid:4; /* index into guid table */
++ unsigned short rdev;
++} __attribute__ ((packed));
++
++struct squashfs_symlink_inode_header_1 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:4; /* index into uid table */
++ unsigned int guid:4; /* index into guid table */
++ unsigned short symlink_size;
++ char symlink[0];
++} __attribute__ ((packed));
++
++struct squashfs_reg_inode_header_1 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:4; /* index into uid table */
++ unsigned int guid:4; /* index into guid table */
++ unsigned int mtime;
++ unsigned int start_block;
++ unsigned int file_size:32;
++ unsigned short block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_inode_header_1 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:4; /* index into uid table */
++ unsigned int guid:4; /* index into guid table */
++ unsigned int file_size:19;
++ unsigned int offset:13;
++ unsigned int mtime;
++ unsigned int start_block:24;
++} __attribute__ ((packed));
++
++#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
++ SQUASHFS_MEMSET(s, d, n);\
++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
++ SQUASHFS_SWAP((s)->uid, d, 16, 4);\
++ SQUASHFS_SWAP((s)->guid, d, 20, 4);
++
++#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
++}
++
++#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++ sizeof(struct squashfs_ipc_inode_header_1));\
++ SQUASHFS_SWAP((s)->type, d, 24, 4);\
++ SQUASHFS_SWAP((s)->offset, d, 28, 4);\
++}
++
++#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++ sizeof(struct squashfs_dev_inode_header_1));\
++ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
++}
++
++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++ sizeof(struct squashfs_symlink_inode_header_1));\
++ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
++}
++
++#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++ sizeof(struct squashfs_reg_inode_header_1));\
++ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
++ SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++ sizeof(struct squashfs_dir_inode_header_1));\
++ SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
++ SQUASHFS_SWAP((s)->offset, d, 43, 13);\
++ SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
++}
++
++#endif
++
++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++
++struct squashfs_dir_index_2 {
++ unsigned int index:27;
++ unsigned int start_block:29;
++ unsigned char size;
++ unsigned char name[0];
++} __attribute__ ((packed));
++
++struct squashfs_base_inode_header_2 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:8; /* index into uid table */
++ unsigned int guid:8; /* index into guid table */
++} __attribute__ ((packed));
++
++struct squashfs_ipc_inode_header_2 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:8; /* index into uid table */
++ unsigned int guid:8; /* index into guid table */
++} __attribute__ ((packed));
++
++struct squashfs_dev_inode_header_2 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:8; /* index into uid table */
++ unsigned int guid:8; /* index into guid table */
++ unsigned short rdev;
++} __attribute__ ((packed));
++
++struct squashfs_symlink_inode_header_2 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:8; /* index into uid table */
++ unsigned int guid:8; /* index into guid table */
++ unsigned short symlink_size;
++ char symlink[0];
++} __attribute__ ((packed));
++
++struct squashfs_reg_inode_header_2 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:8; /* index into uid table */
++ unsigned int guid:8; /* index into guid table */
++ unsigned int mtime;
++ unsigned int start_block;
++ unsigned int fragment;
++ unsigned int offset;
++ unsigned int file_size:32;
++ unsigned short block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_inode_header_2 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:8; /* index into uid table */
++ unsigned int guid:8; /* index into guid table */
++ unsigned int file_size:19;
++ unsigned int offset:13;
++ unsigned int mtime;
++ unsigned int start_block:24;
++} __attribute__ ((packed));
++
++struct squashfs_ldir_inode_header_2 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:8; /* index into uid table */
++ unsigned int guid:8; /* index into guid table */
++ unsigned int file_size:27;
++ unsigned int offset:13;
++ unsigned int mtime;
++ unsigned int start_block:24;
++ unsigned int i_count:16;
++ struct squashfs_dir_index_2 index[0];
++} __attribute__ ((packed));
++
++union squashfs_inode_header_2 {
++ struct squashfs_base_inode_header_2 base;
++ struct squashfs_dev_inode_header_2 dev;
++ struct squashfs_symlink_inode_header_2 symlink;
++ struct squashfs_reg_inode_header_2 reg;
++ struct squashfs_dir_inode_header_2 dir;
++ struct squashfs_ldir_inode_header_2 ldir;
++ struct squashfs_ipc_inode_header_2 ipc;
++};
++
++struct squashfs_dir_header_2 {
++ unsigned int count:8;
++ unsigned int start_block:24;
++} __attribute__ ((packed));
++
++struct squashfs_dir_entry_2 {
++ unsigned int offset:13;
++ unsigned int type:3;
++ unsigned int size:8;
++ char name[0];
++} __attribute__ ((packed));
++
++struct squashfs_fragment_entry_2 {
++ unsigned int start_block;
++ unsigned int size;
++} __attribute__ ((packed));
++
++#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
++ SQUASHFS_MEMSET(s, d, n);\
++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\
++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\
++
++#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
++}
++
++#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
++ SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
++
++#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++ sizeof(struct squashfs_dev_inode_header_2)); \
++ SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
++}
++
++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++ sizeof(struct squashfs_symlink_inode_header_2));\
++ SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
++}
++
++#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++ sizeof(struct squashfs_reg_inode_header_2));\
++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
++ SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
++ SQUASHFS_SWAP((s)->offset, d, 128, 32);\
++ SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++ sizeof(struct squashfs_dir_inode_header_2));\
++ SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
++ SQUASHFS_SWAP((s)->offset, d, 51, 13);\
++ SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
++}
++
++#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++ sizeof(struct squashfs_ldir_inode_header_2));\
++ SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
++ SQUASHFS_SWAP((s)->offset, d, 59, 13);\
++ SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
++ SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
++}
++
++#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
++ SQUASHFS_SWAP((s)->index, d, 0, 27);\
++ SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
++ SQUASHFS_SWAP((s)->size, d, 56, 8);\
++}
++#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
++ SQUASHFS_SWAP((s)->count, d, 0, 8);\
++ SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
++}
++
++#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\
++ SQUASHFS_SWAP((s)->type, d, 13, 3);\
++ SQUASHFS_SWAP((s)->size, d, 16, 8);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
++ SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
++ SQUASHFS_SWAP((s)->size, d, 32, 32);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
++
++/* fragment and fragment table defines */
++#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2))
++
++#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \
++ SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \
++ SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \
++ SQUASHFS_METADATA_SIZE - 1) / \
++ SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\
++ sizeof(int))
++
++#endif
++
++#ifdef __KERNEL__
++
++/*
++ * macros used to swap each structure entry, taking into account
++ * bitfields and different bitfield placing conventions on differing
++ * architectures
++ */
++
++#include <asm/byteorder.h>
++
++#ifdef __BIG_ENDIAN
++ /* convert from little endian to big endian */
++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
++ tbits, b_pos)
++#else
++ /* convert from big endian to little endian */
++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
++ tbits, 64 - tbits - b_pos)
++#endif
++
++#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
++ b_pos = pos % 8;\
++ val = 0;\
++ s = (unsigned char *)p + (pos / 8);\
++ d = ((unsigned char *) &val) + 7;\
++ for(bits = 0; bits < (tbits + b_pos); bits += 8) \
++ *d-- = *s++;\
++ value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
++}
++
++#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n);
++
++#endif
++#endif
+diff --new-file -urp linux-2.4.32/include/linux/squashfs_fs_i.h linux-2.4.32-squashfs3.0/include/linux/squashfs_fs_i.h
+--- linux-2.4.32/include/linux/squashfs_fs_i.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-squashfs3.0/include/linux/squashfs_fs_i.h 2006-03-07 21:12:36.000000000 +0000
+@@ -0,0 +1,44 @@
++#ifndef SQUASHFS_FS_I
++#define SQUASHFS_FS_I
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.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,
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs_fs_i.h
++ */
++
++struct squashfs_inode_info {
++ long long start_block;
++ unsigned int offset;
++ union {
++ struct {
++ long long fragment_start_block;
++ unsigned int fragment_size;
++ unsigned int fragment_offset;
++ long long block_list_start;
++ } s1;
++ struct {
++ long long directory_index_start;
++ unsigned int directory_index_offset;
++ unsigned int directory_index_count;
++ unsigned int parent_inode;
++ } s2;
++ } u;
++};
++#endif
+diff --new-file -urp linux-2.4.32/include/linux/squashfs_fs_sb.h linux-2.4.32-squashfs3.0/include/linux/squashfs_fs_sb.h
+--- linux-2.4.32/include/linux/squashfs_fs_sb.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-squashfs3.0/include/linux/squashfs_fs_sb.h 2006-03-07 21:12:36.000000000 +0000
+@@ -0,0 +1,74 @@
++#ifndef SQUASHFS_FS_SB
++#define SQUASHFS_FS_SB
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.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,
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs_fs_sb.h
++ */
++
++#include <linux/squashfs_fs.h>
++
++struct squashfs_cache {
++ long long block;
++ int length;
++ long long next_index;
++ char *data;
++};
++
++struct squashfs_fragment_cache {
++ long long block;
++ int length;
++ unsigned int locked;
++ char *data;
++};
++
++struct squashfs_sb_info {
++ struct squashfs_super_block sblk;
++ int devblksize;
++ int devblksize_log2;
++ int swap;
++ struct squashfs_cache *block_cache;
++ struct squashfs_fragment_cache *fragment;
++ int next_cache;
++ int next_fragment;
++ int next_meta_index;
++ unsigned int *uid;
++ unsigned int *guid;
++ long long *fragment_index;
++ unsigned int *fragment_index_2;
++ unsigned int read_size;
++ char *read_data;
++ char *read_page;
++ struct semaphore read_data_mutex;
++ struct semaphore read_page_mutex;
++ struct semaphore block_cache_mutex;
++ struct semaphore fragment_mutex;
++ struct semaphore meta_index_mutex;
++ wait_queue_head_t waitq;
++ wait_queue_head_t fragment_wait_queue;
++ struct meta_index *meta_index;
++ struct inode *(*iget)(struct super_block *s, squashfs_inode_t \
++ inode);
++ long long (*read_blocklist)(struct inode *inode, int \
++ index, int readahead_blks, char *block_list, \
++ unsigned short **block_p, unsigned int *bsize);
++ int (*read_fragment_index_table)(struct super_block *s);
++};
++#endif
+diff --new-file -urp linux-2.4.32/init/do_mounts.c linux-2.4.32-squashfs3.0/init/do_mounts.c
+--- linux-2.4.32/init/do_mounts.c 2003-11-28 18:26:21.000000000 +0000
++++ linux-2.4.32-squashfs3.0/init/do_mounts.c 2006-03-07 21:12:36.000000000 +0000
+@@ -15,6 +15,7 @@
+ #include <linux/minix_fs.h>
+ #include <linux/ext2_fs.h>
+ #include <linux/romfs_fs.h>
++#include <linux/squashfs_fs.h>
+ #include <linux/cramfs_fs.h>
+
+ #define BUILD_CRAMDISK
+@@ -476,6 +477,7 @@ static int __init crd_load(int in_fd, in
+ * minix
+ * ext2
+ * romfs
++ * squashfs
+ * cramfs
+ * gzip
+ */
+@@ -486,6 +488,7 @@ identify_ramdisk_image(int fd, int start
+ struct minix_super_block *minixsb;
+ struct ext2_super_block *ext2sb;
+ struct romfs_super_block *romfsb;
++ struct squashfs_super_block *squashfsb;
+ struct cramfs_super *cramfsb;
+ int nblocks = -1;
+ unsigned char *buf;
+@@ -497,6 +500,7 @@ identify_ramdisk_image(int fd, int start
+ minixsb = (struct minix_super_block *) buf;
+ ext2sb = (struct ext2_super_block *) buf;
+ romfsb = (struct romfs_super_block *) buf;
++ squashfsb = (struct squashfs_super_block *) buf;
+ cramfsb = (struct cramfs_super *) buf;
+ memset(buf, 0xe5, size);
+
+@@ -535,6 +539,15 @@ identify_ramdisk_image(int fd, int start
+ goto done;
+ }
+
++ /* squashfs is at block zero too */
++ if (squashfsb->s_magic == SQUASHFS_MAGIC) {
++ printk(KERN_NOTICE
++ "RAMDISK: squashfs filesystem found at block %d\n",
++ start_block);
++ nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
++ goto done;
++ }
++
+ /*
+ * Read block 1 to test for minix and ext2 superblock
+ */
+diff --new-file -urp linux-2.4.32/lib/Config.in linux-2.4.32-squashfs3.0/lib/Config.in
+--- linux-2.4.32/lib/Config.in 2003-11-28 18:26:21.000000000 +0000
++++ linux-2.4.32-squashfs3.0/lib/Config.in 2006-03-07 21:12:36.000000000 +0000
+@@ -10,6 +10,7 @@ tristate 'CRC32 functions' CONFIG_CRC32
+ # Do we need the compression support?
+ #
+ if [ "$CONFIG_CRAMFS" = "y" -o \
++ "$CONFIG_SQUASHFS" = "y" -o \
+ "$CONFIG_PPP_DEFLATE" = "y" -o \
+ "$CONFIG_CRYPTO_DEFLATE" = "y" -o \
+ "$CONFIG_JFFS2_FS" = "y" -o \
+@@ -17,6 +18,7 @@ if [ "$CONFIG_CRAMFS" = "y" -o \
+ define_tristate CONFIG_ZLIB_INFLATE y
+ else
+ if [ "$CONFIG_CRAMFS" = "m" -o \
++ "$CONFIG_SQUASHFS" = "m" -o \
+ "$CONFIG_PPP_DEFLATE" = "m" -o \
+ "$CONFIG_CRYPTO_DEFLATE" = "m" -o \
+ "$CONFIG_JFFS2_FS" = "m" -o \
diff --git a/target/linux/generic-2.4/patches/002-squashfs_lzma.patch b/target/linux/generic-2.4/patches/002-squashfs_lzma.patch
new file mode 100644
index 0000000..d534154
--- /dev/null
+++ b/target/linux/generic-2.4/patches/002-squashfs_lzma.patch
@@ -0,0 +1,883 @@
+diff -Nur linux-2.4.32/fs/squashfs/inode.c linux-2.4.32-owrt/fs/squashfs/inode.c
+--- linux-2.4.32/fs/squashfs/inode.c 2006-03-21 13:06:10.000000000 +0100
++++ linux-2.4.32-owrt/fs/squashfs/inode.c 2006-03-21 13:12:07.000000000 +0100
+@@ -4,6 +4,9 @@
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
++ * LZMA decompressor support added by Oleg I. Vdovikin
++ * Copyright (c) 2005 Oleg I.Vdovikin <oleg@cs.msu.su>
++ *
+ * 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,
+@@ -21,6 +24,7 @@
+ * inode.c
+ */
+
++#define SQUASHFS_LZMA
+ #include <linux/types.h>
+ #include <linux/squashfs_fs.h>
+ #include <linux/module.h>
+@@ -40,6 +44,20 @@
+
+ #include "squashfs.h"
+
++#ifdef SQUASHFS_LZMA
++#include "LzmaDecode.h"
++
++/* default LZMA settings, should be in sync with mksquashfs */
++#define LZMA_LC 3
++#define LZMA_LP 0
++#define LZMA_PB 2
++
++#define LZMA_WORKSPACE_SIZE ((LZMA_BASE_SIZE + \
++ (LZMA_LIT_SIZE << (LZMA_LC + LZMA_LP))) * sizeof(CProb))
++
++#endif
++
++
+ static struct super_block *squashfs_read_super(struct super_block *, void *, int);
+ static void squashfs_put_super(struct super_block *);
+ static int squashfs_statfs(struct super_block *, struct statfs *);
+@@ -53,7 +71,11 @@
+ int readahead_blks, char *block_list,
+ unsigned short **block_p, unsigned int *bsize);
+
++#ifdef SQUASHFS_LZMA
++static unsigned char lzma_workspace[LZMA_WORKSPACE_SIZE];
++#else
+ static z_stream stream;
++#endif
+
+ static DECLARE_FSTYPE_DEV(squashfs_fs_type, "squashfs", squashfs_read_super);
+
+@@ -229,6 +251,15 @@
+ if (compressed) {
+ int zlib_err;
+
++#ifdef SQUASHFS_LZMA
++ if ((zlib_err = LzmaDecode(lzma_workspace,
++ LZMA_WORKSPACE_SIZE, LZMA_LC, LZMA_LP, LZMA_PB,
++ c_buffer, c_byte, buffer, msblk->read_size, &bytes)) != LZMA_RESULT_OK)
++ {
++ ERROR("lzma returned unexpected result 0x%x\n", zlib_err);
++ bytes = 0;
++ }
++#else
+ stream.next_in = c_buffer;
+ stream.avail_in = c_byte;
+ stream.next_out = buffer;
+@@ -243,6 +274,7 @@
+ bytes = 0;
+ } else
+ bytes = stream.total_out;
++#endif
+
+ up(&msblk->read_data_mutex);
+ }
+@@ -2004,17 +2036,21 @@
+ printk(KERN_INFO "squashfs: version 3.0 (2006/03/15) "
+ "Phillip Lougher\n");
+
++#ifndef SQUASHFS_LZMA
+ if (!(stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
+ ERROR("Failed to allocate zlib workspace\n");
+ return -ENOMEM;
+ }
++#endif
+ return register_filesystem(&squashfs_fs_type);
+ }
+
+
+ static void __exit exit_squashfs_fs(void)
+ {
++#ifndef SQUASHFS_LZMA
+ vfree(stream.workspace);
++#endif
+ unregister_filesystem(&squashfs_fs_type);
+ }
+
+diff -Nur linux-2.4.32/fs/squashfs/LzmaDecode.c linux-2.4.32-owrt/fs/squashfs/LzmaDecode.c
+--- linux-2.4.32/fs/squashfs/LzmaDecode.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-owrt/fs/squashfs/LzmaDecode.c 2006-03-21 13:06:33.000000000 +0100
+@@ -0,0 +1,663 @@
++/*
++ LzmaDecode.c
++ LZMA Decoder
++
++ LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
++ http://www.7-zip.org/
++
++ LZMA SDK is licensed under two licenses:
++ 1) GNU Lesser General Public License (GNU LGPL)
++ 2) Common Public License (CPL)
++ It means that you can select one of these two licenses and
++ follow rules of that license.
++
++ SPECIAL EXCEPTION:
++ Igor Pavlov, as the author of this code, expressly permits you to
++ statically or dynamically link your code (or bind by name) to the
++ interfaces of this file without subjecting your linked code to the
++ terms of the CPL or GNU LGPL. Any modifications or additions
++ to this file, however, are subject to the LGPL or CPL terms.
++*/
++
++#include "LzmaDecode.h"
++
++#ifndef Byte
++#define Byte unsigned char
++#endif
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++
++typedef struct _CRangeDecoder
++{
++ Byte *Buffer;
++ Byte *BufferLim;
++ UInt32 Range;
++ UInt32 Code;
++ #ifdef _LZMA_IN_CB
++ ILzmaInCallback *InCallback;
++ int Result;
++ #endif
++ int ExtraBytes;
++} CRangeDecoder;
++
++Byte RangeDecoderReadByte(CRangeDecoder *rd)
++{
++ if (rd->Buffer == rd->BufferLim)
++ {
++ #ifdef _LZMA_IN_CB
++ UInt32 size;
++ rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size);
++ rd->BufferLim = rd->Buffer + size;
++ if (size == 0)
++ #endif
++ {
++ rd->ExtraBytes = 1;
++ return 0xFF;
++ }
++ }
++ return (*rd->Buffer++);
++}
++
++/* #define ReadByte (*rd->Buffer++) */
++#define ReadByte (RangeDecoderReadByte(rd))
++
++void RangeDecoderInit(CRangeDecoder *rd,
++ #ifdef _LZMA_IN_CB
++ ILzmaInCallback *inCallback
++ #else
++ Byte *stream, UInt32 bufferSize
++ #endif
++ )
++{
++ int i;
++ #ifdef _LZMA_IN_CB
++ rd->InCallback = inCallback;
++ rd->Buffer = rd->BufferLim = 0;
++ #else
++ rd->Buffer = stream;
++ rd->BufferLim = stream + bufferSize;
++ #endif
++ rd->ExtraBytes = 0;
++ rd->Code = 0;
++ rd->Range = (0xFFFFFFFF);
++ for(i = 0; i < 5; i++)
++ rd->Code = (rd->Code << 8) | ReadByte;
++}
++
++#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code;
++#define RC_FLUSH_VAR rd->Range = range; rd->Code = code;
++#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; }
++
++UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits)
++{
++ RC_INIT_VAR
++ UInt32 result = 0;
++ int i;
++ for (i = numTotalBits; i > 0; i--)
++ {
++ /* UInt32 t; */
++ range >>= 1;
++
++ result <<= 1;
++ if (code >= range)
++ {
++ code -= range;
++ result |= 1;
++ }
++ /*
++ t = (code - range) >> 31;
++ t &= 1;
++ code -= range & (t - 1);
++ result = (result + result) | (1 - t);
++ */
++ RC_NORMALIZE
++ }
++ RC_FLUSH_VAR
++ return result;
++}
++
++int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd)
++{
++ UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob;
++ if (rd->Code < bound)
++ {
++ rd->Range = bound;
++ *prob += (kBitModelTotal - *prob) >> kNumMoveBits;
++ if (rd->Range < kTopValue)
++ {
++ rd->Code = (rd->Code << 8) | ReadByte;
++ rd->Range <<= 8;
++ }
++ return 0;
++ }
++ else
++ {
++ rd->Range -= bound;
++ rd->Code -= bound;
++ *prob -= (*prob) >> kNumMoveBits;
++ if (rd->Range < kTopValue)
++ {
++ rd->Code = (rd->Code << 8) | ReadByte;
++ rd->Range <<= 8;
++ }
++ return 1;
++ }
++}
++
++#define RC_GET_BIT2(prob, mi, A0, A1) \
++ UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \
++ if (code < bound) \
++ { A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \
++ else \
++ { A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \
++ RC_NORMALIZE
++
++#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;)
++
++int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
++{
++ int mi = 1;
++ int i;
++ #ifdef _LZMA_LOC_OPT
++ RC_INIT_VAR
++ #endif
++ for(i = numLevels; i > 0; i--)
++ {
++ #ifdef _LZMA_LOC_OPT
++ CProb *prob = probs + mi;
++ RC_GET_BIT(prob, mi)
++ #else
++ mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd);
++ #endif
++ }
++ #ifdef _LZMA_LOC_OPT
++ RC_FLUSH_VAR
++ #endif
++ return mi - (1 << numLevels);
++}
++
++int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
++{
++ int mi = 1;
++ int i;
++ int symbol = 0;
++ #ifdef _LZMA_LOC_OPT
++ RC_INIT_VAR
++ #endif
++ for(i = 0; i < numLevels; i++)
++ {
++ #ifdef _LZMA_LOC_OPT
++ CProb *prob = probs + mi;
++ RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i))
++ #else
++ int bit = RangeDecoderBitDecode(probs + mi, rd);
++ mi = mi + mi + bit;
++ symbol |= (bit << i);
++ #endif
++ }
++ #ifdef _LZMA_LOC_OPT
++ RC_FLUSH_VAR
++ #endif
++ return symbol;
++}
++
++Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd)
++{
++ int symbol = 1;
++ #ifdef _LZMA_LOC_OPT
++ RC_INIT_VAR
++ #endif
++ do
++ {
++ #ifdef _LZMA_LOC_OPT
++ CProb *prob = probs + symbol;
++ RC_GET_BIT(prob, symbol)
++ #else
++ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
++ #endif
++ }
++ while (symbol < 0x100);
++ #ifdef _LZMA_LOC_OPT
++ RC_FLUSH_VAR
++ #endif
++ return symbol;
++}
++
++Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte)
++{
++ int symbol = 1;
++ #ifdef _LZMA_LOC_OPT
++ RC_INIT_VAR
++ #endif
++ do
++ {
++ int bit;
++ int matchBit = (matchByte >> 7) & 1;
++ matchByte <<= 1;
++ #ifdef _LZMA_LOC_OPT
++ {
++ CProb *prob = probs + ((1 + matchBit) << 8) + symbol;
++ RC_GET_BIT2(prob, symbol, bit = 0, bit = 1)
++ }
++ #else
++ bit = RangeDecoderBitDecode(probs + ((1 + matchBit) << 8) + symbol, rd);
++ symbol = (symbol << 1) | bit;
++ #endif
++ if (matchBit != bit)
++ {
++ while (symbol < 0x100)
++ {
++ #ifdef _LZMA_LOC_OPT
++ CProb *prob = probs + symbol;
++ RC_GET_BIT(prob, symbol)
++ #else
++ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
++ #endif
++ }
++ break;
++ }
++ }
++ while (symbol < 0x100);
++ #ifdef _LZMA_LOC_OPT
++ RC_FLUSH_VAR
++ #endif
++ return symbol;
++}
++
++#define kNumPosBitsMax 4
++#define kNumPosStatesMax (1 << kNumPosBitsMax)
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define LenChoice 0
++#define LenChoice2 (LenChoice + 1)
++#define LenLow (LenChoice2 + 1)
++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
++#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
++
++int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState)
++{
++ if(RangeDecoderBitDecode(p + LenChoice, rd) == 0)
++ return RangeDecoderBitTreeDecode(p + LenLow +
++ (posState << kLenNumLowBits), kLenNumLowBits, rd);
++ if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0)
++ return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid +
++ (posState << kLenNumMidBits), kLenNumMidBits, rd);
++ return kLenNumLowSymbols + kLenNumMidSymbols +
++ RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd);
++}
++
++#define kNumStates 12
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
++
++#define kNumPosSlotBits 6
++#define kNumLenToPosStates 4
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++
++#define kMatchMinLen 2
++
++#define IsMatch 0
++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
++#define IsRepG0 (IsRep + kNumStates)
++#define IsRepG1 (IsRepG0 + kNumStates)
++#define IsRepG2 (IsRepG1 + kNumStates)
++#define IsRep0Long (IsRepG2 + kNumStates)
++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
++#define LenCoder (Align + kAlignTableSize)
++#define RepLenCoder (LenCoder + kNumLenProbs)
++#define Literal (RepLenCoder + kNumLenProbs)
++
++#if Literal != LZMA_BASE_SIZE
++StopCompilingDueBUG
++#endif
++
++#ifdef _LZMA_OUT_READ
++
++typedef struct _LzmaVarState
++{
++ CRangeDecoder RangeDecoder;
++ Byte *Dictionary;
++ UInt32 DictionarySize;
++ UInt32 DictionaryPos;
++ UInt32 GlobalPos;
++ UInt32 Reps[4];
++ int lc;
++ int lp;
++ int pb;
++ int State;
++ int PreviousIsMatch;
++ int RemainLen;
++} LzmaVarState;
++
++int LzmaDecoderInit(
++ unsigned char *buffer, UInt32 bufferSize,
++ int lc, int lp, int pb,
++ unsigned char *dictionary, UInt32 dictionarySize,
++ #ifdef _LZMA_IN_CB
++ ILzmaInCallback *inCallback
++ #else
++ unsigned char *inStream, UInt32 inSize
++ #endif
++ )
++{
++ LzmaVarState *vs = (LzmaVarState *)buffer;
++ CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
++ UInt32 i;
++ if (bufferSize < numProbs * sizeof(CProb) + sizeof(LzmaVarState))
++ return LZMA_RESULT_NOT_ENOUGH_MEM;
++ vs->Dictionary = dictionary;
++ vs->DictionarySize = dictionarySize;
++ vs->DictionaryPos = 0;
++ vs->GlobalPos = 0;
++ vs->Reps[0] = vs->Reps[1] = vs->Reps[2] = vs->Reps[3] = 1;
++ vs->lc = lc;
++ vs->lp = lp;
++ vs->pb = pb;
++ vs->State = 0;
++ vs->PreviousIsMatch = 0;
++ vs->RemainLen = 0;
++ dictionary[dictionarySize - 1] = 0;
++ for (i = 0; i < numProbs; i++)
++ p[i] = kBitModelTotal >> 1;
++ RangeDecoderInit(&vs->RangeDecoder,
++ #ifdef _LZMA_IN_CB
++ inCallback
++ #else
++ inStream, inSize
++ #endif
++ );
++ return LZMA_RESULT_OK;
++}
++
++int LzmaDecode(unsigned char *buffer,
++ unsigned char *outStream, UInt32 outSize,
++ UInt32 *outSizeProcessed)
++{
++ LzmaVarState *vs = (LzmaVarState *)buffer;
++ CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
++ CRangeDecoder rd = vs->RangeDecoder;
++ int state = vs->State;
++ int previousIsMatch = vs->PreviousIsMatch;
++ Byte previousByte;
++ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
++ UInt32 nowPos = 0;
++ UInt32 posStateMask = (1 << (vs->pb)) - 1;
++ UInt32 literalPosMask = (1 << (vs->lp)) - 1;
++ int lc = vs->lc;
++ int len = vs->RemainLen;
++ UInt32 globalPos = vs->GlobalPos;
++
++ Byte *dictionary = vs->Dictionary;
++ UInt32 dictionarySize = vs->DictionarySize;
++ UInt32 dictionaryPos = vs->DictionaryPos;
++
++ if (len == -1)
++ {
++ *outSizeProcessed = 0;
++ return LZMA_RESULT_OK;
++ }
++
++ while(len > 0 && nowPos < outSize)
++ {
++ UInt32 pos = dictionaryPos - rep0;
++ if (pos >= dictionarySize)
++ pos += dictionarySize;
++ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
++ if (++dictionaryPos == dictionarySize)
++ dictionaryPos = 0;
++ len--;
++ }
++ if (dictionaryPos == 0)
++ previousByte = dictionary[dictionarySize - 1];
++ else
++ previousByte = dictionary[dictionaryPos - 1];
++#else
++
++int LzmaDecode(
++ Byte *buffer, UInt32 bufferSize,
++ int lc, int lp, int pb,
++ #ifdef _LZMA_IN_CB
++ ILzmaInCallback *inCallback,
++ #else
++ unsigned char *inStream, UInt32 inSize,
++ #endif
++ unsigned char *outStream, UInt32 outSize,
++ UInt32 *outSizeProcessed)
++{
++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
++ CProb *p = (CProb *)buffer;
++ CRangeDecoder rd;
++ UInt32 i;
++ int state = 0;
++ int previousIsMatch = 0;
++ Byte previousByte = 0;
++ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
++ UInt32 nowPos = 0;
++ UInt32 posStateMask = (1 << pb) - 1;
++ UInt32 literalPosMask = (1 << lp) - 1;
++ int len = 0;
++ if (bufferSize < numProbs * sizeof(CProb))
++ return LZMA_RESULT_NOT_ENOUGH_MEM;
++ for (i = 0; i < numProbs; i++)
++ p[i] = kBitModelTotal >> 1;
++ RangeDecoderInit(&rd,
++ #ifdef _LZMA_IN_CB
++ inCallback
++ #else
++ inStream, inSize
++ #endif
++ );
++#endif
++
++ *outSizeProcessed = 0;
++ while(nowPos < outSize)
++ {
++ int posState = (int)(
++ (nowPos
++ #ifdef _LZMA_OUT_READ
++ + globalPos
++ #endif
++ )
++ & posStateMask);
++ #ifdef _LZMA_IN_CB
++ if (rd.Result != LZMA_RESULT_OK)
++ return rd.Result;
++ #endif
++ if (rd.ExtraBytes != 0)
++ return LZMA_RESULT_DATA_ERROR;
++ if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0)
++ {
++ CProb *probs = p + Literal + (LZMA_LIT_SIZE *
++ (((
++ (nowPos
++ #ifdef _LZMA_OUT_READ
++ + globalPos
++ #endif
++ )
++ & literalPosMask) << lc) + (previousByte >> (8 - lc))));
++
++ if (state < 4) state = 0;
++ else if (state < 10) state -= 3;
++ else state -= 6;
++ if (previousIsMatch)
++ {
++ Byte matchByte;
++ #ifdef _LZMA_OUT_READ
++ UInt32 pos = dictionaryPos - rep0;
++ if (pos >= dictionarySize)
++ pos += dictionarySize;
++ matchByte = dictionary[pos];
++ #else
++ matchByte = outStream[nowPos - rep0];
++ #endif
++ previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte);
++ previousIsMatch = 0;
++ }
++ else
++ previousByte = LzmaLiteralDecode(probs, &rd);
++ outStream[nowPos++] = previousByte;
++ #ifdef _LZMA_OUT_READ
++ dictionary[dictionaryPos] = previousByte;
++ if (++dictionaryPos == dictionarySize)
++ dictionaryPos = 0;
++ #endif
++ }
++ else
++ {
++ previousIsMatch = 1;
++ if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1)
++ {
++ if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0)
++ {
++ if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0)
++ {
++ #ifdef _LZMA_OUT_READ
++ UInt32 pos;
++ #endif
++ if (
++ (nowPos
++ #ifdef _LZMA_OUT_READ
++ + globalPos
++ #endif
++ )
++ == 0)
++ return LZMA_RESULT_DATA_ERROR;
++ state = state < 7 ? 9 : 11;
++ #ifdef _LZMA_OUT_READ
++ pos = dictionaryPos - rep0;
++ if (pos >= dictionarySize)
++ pos += dictionarySize;
++ previousByte = dictionary[pos];
++ dictionary[dictionaryPos] = previousByte;
++ if (++dictionaryPos == dictionarySize)
++ dictionaryPos = 0;
++ #else
++ previousByte = outStream[nowPos - rep0];
++ #endif
++ outStream[nowPos++] = previousByte;
++ continue;
++ }
++ }
++ else
++ {
++ UInt32 distance;
++ if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0)
++ distance = rep1;
++ else
++ {
++ if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0)
++ distance = rep2;
++ else
++ {
++ distance = rep3;
++ rep3 = rep2;
++ }
++ rep2 = rep1;
++ }
++ rep1 = rep0;
++ rep0 = distance;
++ }
++ len = LzmaLenDecode(p + RepLenCoder, &rd, posState);
++ state = state < 7 ? 8 : 11;
++ }
++ else
++ {
++ int posSlot;
++ rep3 = rep2;
++ rep2 = rep1;
++ rep1 = rep0;
++ state = state < 7 ? 7 : 10;
++ len = LzmaLenDecode(p + LenCoder, &rd, posState);
++ posSlot = RangeDecoderBitTreeDecode(p + PosSlot +
++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
++ kNumPosSlotBits), kNumPosSlotBits, &rd);
++ if (posSlot >= kStartPosModelIndex)
++ {
++ int numDirectBits = ((posSlot >> 1) - 1);
++ rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits);
++ if (posSlot < kEndPosModelIndex)
++ {
++ rep0 += RangeDecoderReverseBitTreeDecode(
++ p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd);
++ }
++ else
++ {
++ rep0 += RangeDecoderDecodeDirectBits(&rd,
++ numDirectBits - kNumAlignBits) << kNumAlignBits;
++ rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd);
++ }
++ }
++ else
++ rep0 = posSlot;
++ rep0++;
++ }
++ if (rep0 == (UInt32)(0))
++ {
++ /* it's for stream version */
++ len = -1;
++ break;
++ }
++ if (rep0 > nowPos
++ #ifdef _LZMA_OUT_READ
++ + globalPos
++ #endif
++ )
++ {
++ return LZMA_RESULT_DATA_ERROR;
++ }
++ len += kMatchMinLen;
++ do
++ {
++ #ifdef _LZMA_OUT_READ
++ UInt32 pos = dictionaryPos - rep0;
++ if (pos >= dictionarySize)
++ pos += dictionarySize;
++ previousByte = dictionary[pos];
++ dictionary[dictionaryPos] = previousByte;
++ if (++dictionaryPos == dictionarySize)
++ dictionaryPos = 0;
++ #else
++ previousByte = outStream[nowPos - rep0];
++ #endif
++ outStream[nowPos++] = previousByte;
++ len--;
++ }
++ while(len > 0 && nowPos < outSize);
++ }
++ }
++
++ #ifdef _LZMA_OUT_READ
++ vs->RangeDecoder = rd;
++ vs->DictionaryPos = dictionaryPos;
++ vs->GlobalPos = globalPos + nowPos;
++ vs->Reps[0] = rep0;
++ vs->Reps[1] = rep1;
++ vs->Reps[2] = rep2;
++ vs->Reps[3] = rep3;
++ vs->State = state;
++ vs->PreviousIsMatch = previousIsMatch;
++ vs->RemainLen = len;
++ #endif
++
++ *outSizeProcessed = nowPos;
++ return LZMA_RESULT_OK;
++}
+diff -Nur linux-2.4.32/fs/squashfs/LzmaDecode.h linux-2.4.32-owrt/fs/squashfs/LzmaDecode.h
+--- linux-2.4.32/fs/squashfs/LzmaDecode.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32-owrt/fs/squashfs/LzmaDecode.h 2006-03-21 13:06:33.000000000 +0100
+@@ -0,0 +1,100 @@
++/*
++ LzmaDecode.h
++ LZMA Decoder interface
++
++ LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
++ http://www.7-zip.org/
++
++ LZMA SDK is licensed under two licenses:
++ 1) GNU Lesser General Public License (GNU LGPL)
++ 2) Common Public License (CPL)
++ It means that you can select one of these two licenses and
++ follow rules of that license.
++
++ SPECIAL EXCEPTION:
++ Igor Pavlov, as the author of this code, expressly permits you to
++ statically or dynamically link your code (or bind by name) to the
++ interfaces of this file without subjecting your linked code to the
++ terms of the CPL or GNU LGPL. Any modifications or additions
++ to this file, however, are subject to the LGPL or CPL terms.
++*/
++
++#ifndef __LZMADECODE_H
++#define __LZMADECODE_H
++
++/* #define _LZMA_IN_CB */
++/* Use callback for input data */
++
++/* #define _LZMA_OUT_READ */
++/* Use read function for output data */
++
++/* #define _LZMA_PROB32 */
++/* It can increase speed on some 32-bit CPUs,
++ but memory usage will be doubled in that case */
++
++/* #define _LZMA_LOC_OPT */
++/* Enable local speed optimizations inside code */
++
++#ifndef UInt32
++#ifdef _LZMA_UINT32_IS_ULONG
++#define UInt32 unsigned long
++#else
++#define UInt32 unsigned int
++#endif
++#endif
++
++#ifdef _LZMA_PROB32
++#define CProb UInt32
++#else
++#define CProb unsigned short
++#endif
++
++#define LZMA_RESULT_OK 0
++#define LZMA_RESULT_DATA_ERROR 1
++#define LZMA_RESULT_NOT_ENOUGH_MEM 2
++
++#ifdef _LZMA_IN_CB
++typedef struct _ILzmaInCallback
++{
++ int (*Read)(void *object, unsigned char **buffer, UInt32 *bufferSize);
++} ILzmaInCallback;
++#endif
++
++#define LZMA_BASE_SIZE 1846
++#define LZMA_LIT_SIZE 768
++
++/*
++bufferSize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb)
++bufferSize += 100 in case of _LZMA_OUT_READ
++by default CProb is unsigned short,
++but if specify _LZMA_PROB_32, CProb will be UInt32(unsigned int)
++*/
++
++#ifdef _LZMA_OUT_READ
++int LzmaDecoderInit(
++ unsigned char *buffer, UInt32 bufferSize,
++ int lc, int lp, int pb,
++ unsigned char *dictionary, UInt32 dictionarySize,
++ #ifdef _LZMA_IN_CB
++ ILzmaInCallback *inCallback
++ #else
++ unsigned char *inStream, UInt32 inSize
++ #endif
++);
++#endif
++
++int LzmaDecode(
++ unsigned char *buffer,
++ #ifndef _LZMA_OUT_READ
++ UInt32 bufferSize,
++ int lc, int lp, int pb,
++ #ifdef _LZMA_IN_CB
++ ILzmaInCallback *inCallback,
++ #else
++ unsigned char *inStream, UInt32 inSize,
++ #endif
++ #endif
++ unsigned char *outStream, UInt32 outSize,
++ UInt32 *outSizeProcessed);
++
++#endif
+diff -Nur linux-2.4.32/fs/squashfs/Makefile linux-2.4.32-owrt/fs/squashfs/Makefile
+--- linux-2.4.32/fs/squashfs/Makefile 2006-03-21 13:06:10.000000000 +0100
++++ linux-2.4.32-owrt/fs/squashfs/Makefile 2006-03-21 13:12:39.000000000 +0100
+@@ -4,7 +4,7 @@
+
+ O_TARGET := squashfs.o
+
+-obj-y := inode.o squashfs2_0.o
++obj-y := inode.o squashfs2_0.o LzmaDecode.o
+
+ obj-m := $(O_TARGET)
+
diff --git a/target/linux/generic-2.4/patches/003-jffs2_compression.patch b/target/linux/generic-2.4/patches/003-jffs2_compression.patch
new file mode 100644
index 0000000..56c5b3c
--- /dev/null
+++ b/target/linux/generic-2.4/patches/003-jffs2_compression.patch
@@ -0,0 +1,9119 @@
+diff -Nur linux-mips-cvs/Documentation/Configure.help linux-mips/Documentation/Configure.help
+--- linux-mips-cvs/Documentation/Configure.help 2005-01-20 03:19:21.000000000 +0100
++++ linux-mips/Documentation/Configure.help 2005-02-07 05:08:35.000000000 +0100
+@@ -17528,6 +17528,32 @@
+ If reporting bugs, please try to have available a full dump of the
+ messages at debug level 1 while the misbehaviour was occurring.
+
++ARMLIB compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_ARMLIB
++ This enables ARMLIB support for BBC.
++
++LZO1X-* compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZO
++ This enables LZO1X-1 and LZO1X-999 support for BBC. (fast & good
++ compressor, beats ZLIB in everything)
++
++LZARI compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZARI
++ This enables LempelZiv-Storer-Szymanski compression for BBC with
++ additional arithmetic coding (damn slow, but best compresor).
++
++LZHD compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZHD
++ This enables LempelZiv-Storer-Szymanski compression for BBC with
++ additional dynamic Huffman coding (a little faster than LZARI, and
++ it's compression ratio is a little worse than LZARI's)
++
++LZSS compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZSS
++ This enables simple LempelZiv-Storer-Szymanski compression for BBC
++ (faster than LZHD, and, and has a not-so-good compression ratio,
++ was included just for testing)
++
+ JFFS stats available in /proc filesystem
+ CONFIG_JFFS_PROC_FS
+ Enabling this option will cause statistics from mounted JFFS file systems
+diff -Nur linux-mips-cvs/fs/Config.in linux-mips/fs/Config.in
+--- linux-mips-cvs/fs/Config.in 2004-11-19 01:28:47.000000000 +0100
++++ linux-mips/fs/Config.in 2005-02-07 05:08:34.000000000 +0100
+@@ -50,6 +50,12 @@
+ if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFIG_JFFS2_FS" = "m" ] ; then
+ int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0
+ fi
++dep_mbool ' ARMLIB compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_ARMLIB $CONFIG_JFFS2_FS
++dep_mbool ' LZO1X-* compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZO $CONFIG_JFFS2_FS
++dep_mbool ' LZARI compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZARI $CONFIG_JFFS2_FS
++dep_mbool ' LZHD compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZHD $CONFIG_JFFS2_FS
++dep_mbool ' LZSS compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZSS $CONFIG_JFFS2_FS
++
+ tristate 'Compressed ROM file system support' CONFIG_CRAMFS
+ bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS
+ define_bool CONFIG_RAMFS y
+diff -Nur linux-mips-cvs/fs/jffs2/Config.in.bbc.inc linux-mips/fs/jffs2/Config.in.bbc.inc
+--- linux-mips-cvs/fs/jffs2/Config.in.bbc.inc 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/Config.in.bbc.inc 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,5 @@
++dep_mbool ' ARMLIB compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_ARMLIB $CONFIG_JFFS2_FS
++dep_mbool ' LZO1X-* compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZO $CONFIG_JFFS2_FS
++dep_mbool ' LZARI compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZARI $CONFIG_JFFS2_FS
++dep_mbool ' LZHD compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZHD $CONFIG_JFFS2_FS
++dep_mbool ' LZSS compression support for BBC (EXPERIMENTAL)' CONFIG_JFFS2_BBC_LZSS $CONFIG_JFFS2_FS
+diff -Nur linux-mips-cvs/fs/jffs2/Configure.help.bbc.inc linux-mips/fs/jffs2/Configure.help.bbc.inc
+--- linux-mips-cvs/fs/jffs2/Configure.help.bbc.inc 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/Configure.help.bbc.inc 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,25 @@
++ARMLIB compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_ARMLIB
++ This enables ARMLIB support for BBC.
++
++LZO1X-* compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZO
++ This enables LZO1X-1 and LZO1X-999 support for BBC. (fast & good
++ compressor, beats ZLIB in everything)
++
++LZARI compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZARI
++ This enables LempelZiv-Storer-Szymanski compression for BBC with
++ additional arithmetic coding (damn slow, but best compresor).
++
++LZHD compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZHD
++ This enables LempelZiv-Storer-Szymanski compression for BBC with
++ additional dynamic Huffman coding (a little faster than LZARI, and
++ it's compression ratio is a little worse than LZARI's)
++
++LZSS compression support for BBC (EXPERIMENTAL)
++CONFIG_JFFS2_BBC_LZSS
++ This enables simple LempelZiv-Storer-Szymanski compression for BBC
++ (faster than LZHD, and, and has a not-so-good compression ratio,
++ was included just for testing)
+diff -Nur linux-mips-cvs/fs/jffs2/Kconfig.bbc.inc linux-mips/fs/jffs2/Kconfig.bbc.inc
+--- linux-mips-cvs/fs/jffs2/Kconfig.bbc.inc 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/Kconfig.bbc.inc 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,40 @@
++config JFFS2_BBC_ARMLIB
++ bool "ARMLIB compression support for BBC (EXPERIMENTAL)"
++ depends on JFFS2_FS && EXPERIMENTAL
++ default y
++ help
++ This enables ARMLIB support for BBC.
++
++config JFFS2_BBC_LZO
++ bool "LZO1X-* compression support for BBC (EXPERIMENTAL)"
++ depends on JFFS2_FS && EXPERIMENTAL
++ default y
++ help
++ This enables LZO1X-1 and LZO1X-999 support for BBC. (fast & good
++ compressor)
++
++config JFFS2_BBC_LZARI
++ bool "LZARI compression support for BBC (EXPERIMENTAL)"
++ depends on JFFS2_FS && EXPERIMENTAL
++ default y
++ help
++ This enables LempelZiv-Storer-Szymanski compression for BBC with
++ additional arithmetic coding (damn slow, but best compresor).
++
++config JFFS2_BBC_LZHD
++ bool "LZHD compression support for BBC (EXPERIMENTAL)"
++ depends on JFFS2_FS && EXPERIMENTAL
++ default y
++ help
++ This enables LempelZiv-Storer-Szymanski compression for BBC with
++ additional dynamic Huffman coding (a little faster than LZARI, and
++ it's compression ratio is a little worse than LZARI's)
++
++config JFFS2_BBC_LZSS
++ bool "LZSS compression support for BBC (EXPERIMENTAL)"
++ depends on JFFS2_FS && EXPERIMENTAL
++ default y
++ help
++ This enables simple LempelZiv-Storer-Szymanski compression for BBC
++ (faster than LZHD, and, and has a not-so-good compression ratio,
++ was included just for testing)
+diff -Nur linux-mips-cvs/fs/jffs2/Makefile linux-mips/fs/jffs2/Makefile
+--- linux-mips-cvs/fs/jffs2/Makefile 2003-08-13 19:19:25.000000000 +0200
++++ linux-mips/fs/jffs2/Makefile 2005-02-07 05:08:34.000000000 +0100
+@@ -10,9 +10,23 @@
+ # Note 2! The CFLAGS definitions are now in the main makefile...
+
+
++JFFS2_BBC_KERNEL_OBJS-y = jffs2_bbc_framework.o jffs2_bbc_fs.o
++
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_ARMLIB) += jffs2_bbc_armlib_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZO) += jffs2_bbc_lzo_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZSS) += jffs2_bbc_lzss_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZARI) += jffs2_bbc_lzari_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZHD) += jffs2_bbc_lzhd_comp.o
++
++JFFS2_BBC_KERNEL_OBJS := $(JFFS2_BBC_KERNEL_OBJS-y)
++
++JFFS2_BBC_MKFS_OBJS = jffs2_bbc_mkfs.o jffs2_bbc_framework.o jffs2_bbc_armlib_comp.o jffs2_bbc_lzo_comp.o\
++ jffs2_bbc_lzss_comp.o jffs2_bbc_lzari_comp.o jffs2_bbc_lzhd_comp.o
++
+ COMPR_OBJS := compr.o compr_rubin.o compr_rtime.o pushpull.o \
+ compr_zlib.o
+ JFFS2_OBJS := dir.o file.o ioctl.o nodelist.o malloc.o \
++ $(JFFS2_BBC_KERNEL_OBJS) \
+ read.o nodemgmt.o readinode.o super.o write.o scan.o gc.o \
+ symlink.o build.o erase.o background.o
+
+diff -Nur linux-mips-cvs/fs/jffs2/Makefile.bbc.inc linux-mips/fs/jffs2/Makefile.bbc.inc
+--- linux-mips-cvs/fs/jffs2/Makefile.bbc.inc 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/Makefile.bbc.inc 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,12 @@
++JFFS2_BBC_KERNEL_OBJS-y = jffs2_bbc_framework.o jffs2_bbc_fs.o
++
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_ARMLIB) += jffs2_bbc_armlib_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZO) += jffs2_bbc_lzo_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZSS) += jffs2_bbc_lzss_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZARI) += jffs2_bbc_lzari_comp.o
++JFFS2_BBC_KERNEL_OBJS-$(CONFIG_JFFS2_BBC_LZHD) += jffs2_bbc_lzhd_comp.o
++
++JFFS2_BBC_KERNEL_OBJS := $(JFFS2_BBC_KERNEL_OBJS-y)
++
++JFFS2_BBC_MKFS_OBJS = jffs2_bbc_mkfs.o jffs2_bbc_framework.o jffs2_bbc_armlib_comp.o jffs2_bbc_lzo_comp.o\
++ jffs2_bbc_lzss_comp.o jffs2_bbc_lzari_comp.o jffs2_bbc_lzhd_comp.o
+diff -Nur linux-mips-cvs/fs/jffs2/compr_zlib.c linux-mips/fs/jffs2/compr_zlib.c
+--- linux-mips-cvs/fs/jffs2/compr_zlib.c 2003-01-11 18:53:17.000000000 +0100
++++ linux-mips/fs/jffs2/compr_zlib.c 2005-02-07 05:08:35.000000000 +0100
+@@ -85,7 +85,7 @@
+ vfree(inflate_workspace);
+ }
+
+-int zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
++int jffs2_zlib_compress2(unsigned char *data_in, unsigned char *cpage_out,
+ __u32 *sourcelen, __u32 *dstlen)
+ {
+ z_stream strm;
+@@ -145,7 +145,7 @@
+ return 0;
+ }
+
+-void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
++void jffs2_zlib_decompress2(unsigned char *data_in, unsigned char *cpage_out,
+ __u32 srclen, __u32 destlen)
+ {
+ z_stream strm;
+@@ -175,3 +175,19 @@
+ zlib_inflateEnd(&strm);
+ up(&inflate_sem);
+ }
++
++extern int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 * sourcelen, __u32 * dstlen);
++extern void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
++
++int zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
++ __u32 *sourcelen, __u32 *dstlen)
++{
++ return jffs2_zlib_compress(data_in,cpage_out,sourcelen,dstlen);
++}
++
++void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
++ __u32 srclen, __u32 destlen)
++{
++ jffs2_zlib_decompress(data_in,cpage_out,srclen,destlen);
++}
++
+diff -Nur linux-mips-cvs/fs/jffs2/file.c linux-mips/fs/jffs2/file.c
+--- linux-mips-cvs/fs/jffs2/file.c 2003-11-17 02:07:44.000000000 +0100
++++ linux-mips/fs/jffs2/file.c 2005-02-07 05:08:35.000000000 +0100
+@@ -35,6 +35,7 @@
+ *
+ */
+
++#include "jffs2_bbc_framework.h" /**BBC**/
+ #include <linux/kernel.h>
+ #include <linux/mtd/compatmac.h> /* for min() */
+ #include <linux/slab.h>
+@@ -459,6 +460,7 @@
+
+ comprbuf = kmalloc(cdatalen, GFP_KERNEL);
+ if (comprbuf) {
++ jffs2_bbc_model_set_act_sb(c); /**BBC**/
+ comprtype = jffs2_compress(page_address(pg)+ (file_ofs & (PAGE_CACHE_SIZE-1)), comprbuf, &datalen, &cdatalen);
+ }
+ if (comprtype == JFFS2_COMPR_NONE) {
+diff -Nur linux-mips-cvs/fs/jffs2/gc.c linux-mips/fs/jffs2/gc.c
+--- linux-mips-cvs/fs/jffs2/gc.c 2003-11-17 02:07:44.000000000 +0100
++++ linux-mips/fs/jffs2/gc.c 2005-02-07 05:08:35.000000000 +0100
+@@ -35,6 +35,7 @@
+ *
+ */
+
++#include "jffs2_bbc_framework.h" /**BBC**/
+ #include <linux/kernel.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/slab.h>
+@@ -651,6 +652,7 @@
+ writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1));
+
+ if (comprbuf) {
++ jffs2_bbc_model_set_act_sb(c); /**BBC**/
+ comprtype = jffs2_compress(writebuf, comprbuf, &datalen, &cdatalen);
+ }
+ if (comprtype) {
+diff -Nur linux-mips-cvs/fs/jffs2/hpatch linux-mips/fs/jffs2/hpatch
+--- linux-mips-cvs/fs/jffs2/hpatch 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/hpatch 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,191 @@
++#!/usr/bin/perl
++# A patch-like utility
++# Designed for patching different version of jffs2 with the same hpatch file
++#
++# Copyright (C) 2004, Ferenc Havasi
++#
++# 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.
++
++$filename_tmp1="file1.tmp";
++$filename_tmp2="file2.tmp";
++
++$filename_in="";
++$filename_out=$filename_tmp1;
++$filename_cnt=0;
++
++# Modes:
++# 0: expecting =
++# 1: normal_cmd
++# 2: skip until =
++# 3: expecting F (first state)
++$mode=3;
++
++%rules = ();
++
++sub file_end {
++ if (($mode!=2)&&($modified==1)) {
++ while (<SRC>) {
++ print DST $_;
++ }
++ close(SRC);
++ close(DST);
++ if ($cmd_name ne "") { $rules{"$cmd_name"}=1; }
++ $filename_result=$filename_out;
++ if ($filename_result ne $filename_in_save) {
++ open(RES,"<$filename_result") or die "Cannot open $filename_result.\n";
++ open(DST,">$filename_in_save") or die "Cannot open $filename_in_save.\n";
++ while (<RES>) {
++ print DST $_;
++ }
++ close(DST);
++ close(RES);
++ }
++ unlink($filename_tmp1) && unlink($filename_tmp2);
++ }
++ else {
++ close(SRC);
++ close(DST);
++ $filename_result=$filename_in;
++ if ($filename_result ne $filename_in_save) {
++ open(RES,"<$filename_result") or die "Cannot open $filename_result.\n";
++ open(DST,">$filename_in_save") or die "Cannot open $filename_in_save.\n";
++ while (<RES>) {
++ print DST $_;
++ }
++ close(DST);
++ close(RES);
++ }
++ unlink($filename_tmp1);
++ }
++ $modified=0;
++ foreach $rulename (keys %rules) {
++ if ($rules{"$rulename"}==0) { print(STDERR "On $filename_in_save error applying rule $rulename.\n"); }
++ }
++ %rules = ();
++}
++
++if ($#ARGV<0) {
++ print ("usage: hpatch hpatch_file\n");
++ exit;
++}
++
++open(CMD,"<$ARGV[0]") or die "Cannot open $ARGV[0].\n";
++$cmd_linenum=0;
++
++while (chomp($cmd_line=<CMD>)) {
++ $cmd_linenum++;
++ if ($cmd_line eq "") {next;}
++ #$cmd_line =~ s/\#.*//;
++ $cmd_line =~ s/\ *$//;
++ if ($cmd_line eq "") {next;}
++ if ($cmd_line =~ /^F(.*)/) {
++ $tmp_filename_in=$1;
++ if ($mode!=3) {
++ file_end();
++ }
++ $filename_in=$tmp_filename_in;
++ $filename_in_save=$filename_in;
++ open(SRC,"<$filename_in") or die "Cannot open $filename_in.\n";
++ open(DST,">$filename_out") or die "Cannot open $filename_out.\n";;
++ $modified=0;
++ $mode=0;
++ next;
++ }
++ if ($mode==3) {die "error: F expression expected in line $cmd_linenum\n";}
++ if ($cmd_line =~ /^=(.*)/) {
++ $tmp_cmd_name=$1;
++ if (($mode!=2)&&($modified==1)) {
++ while (<SRC>) {
++ print DST $_;
++ }
++ close(SRC);
++ close(DST);
++ if (($cmd_name ne "")) {$rules{"$cmd_name"}=1;};
++ $filename_cnt++;
++ if ($filename_cnt%2==1) {
++ $filename_in=$filename_tmp1;
++ $filename_out=$filename_tmp2;
++ }
++ else {
++ $filename_in=$filename_tmp2;
++ $filename_out=$filename_tmp1;
++ }
++ }
++ else {
++ close(SRC);
++ close(DST);
++ }
++ $mode=1;
++ $cmd_name=$tmp_cmd_name;
++ if (($cmd_name ne "")) {
++ if ($rules{"$cmd_name"}==1) {
++ $mode=2;
++ }
++ else {
++ $rules{"$cmd_name"}=0;
++ }
++ }
++ open(SRC,"<$filename_in") or die "Cannot open $filename_in.\n";
++ open(DST,">$filename_out") or die "Cannot open $filename_out.\n";
++ $modified=0;
++ next;
++ }
++ if ($mode == 0) {die "error: = expression expected in line $cmd_linenum\n";}
++ if ($mode == 2) {next;}
++ if ($cmd_line =~ /^!(.*)/) {
++ print "$1\n";
++ $modified=1;
++ next;
++ }
++ if ($cmd_line =~ /^\?(.*)/) {
++ $search_str=$1;
++ $found=0;
++ while (<SRC>) {
++ print DST $_;
++ if (index($_,$search_str)>=0) {$found=1; last;}
++ }
++ if ($found==0) { $mode=2; }
++ next;
++ }
++ if ($cmd_line =~ /^\+(.*)/) {
++ print DST "$1\n";
++ $modified=1;
++ next;
++ }
++ if ($cmd_line =~ /^\-(.*)/) {
++ $search_str=$1;
++ $found=0;
++ while (<SRC>) {
++ if (index($_,$search_str)>=0) {$saved_line=$_; $found=1; $modified=1; last;}
++ print DST $_;
++ }
++ if ($found==0) { $mode=2; }
++ next;
++ }
++ if ($cmd_line =~ /^i(.*)/) {
++ $filename_inc=$1;
++ open(INCSRC,"<$filename_inc") or die "Cannot open $filename_inc.\n";
++ while (<INCSRC>) {
++ print DST $_;
++ }
++ next;
++ }
++ if ($cmd_line =~ /^I/) {
++ print DST $saved_line;
++ next;
++ }
++}
++file_end();
++close(CMD);
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_armlib_comp.c linux-mips/fs/jffs2/jffs2_bbc_armlib_comp.c
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_armlib_comp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_armlib_comp.c 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,2224 @@
++/*
++ * JFFS2-BBC: armlib compressor plugin
++ *
++ * $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++ *
++ * Copyright (C) 2004, Ferenc Havasi & Tamas Gergely
++ *
++ * 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 "jffs2_bbc_framework.h"
++
++#ifdef __KERNEL__
++#include <linux/string.h>
++#else
++#include <string.h>
++#endif
++
++//ORIGIN: include/DataStructures/TypeDefs.h
++
++/*******************************************************************************
++* FILE: TypeDefs.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef TYPEDEFS_H
++#define TYPEDEFS_H
++
++#pragma pack(4)
++
++#ifndef bool
++#define bool char
++#define true 1
++#define false 0
++#endif
++
++#ifndef u8
++#define u8 unsigned char
++#endif
++#ifndef u16
++#define u16 unsigned short
++#endif
++#ifndef u32
++#define u32 unsigned long
++#endif
++#ifndef s8
++#define s8 signed char
++#endif
++#ifndef s16
++#define s16 signed short
++#endif
++#ifndef s32
++#define s32 signed long
++#endif
++
++typedef struct
++{
++ u32 capacity;
++ u32 size;
++ u32 alloc_size;
++ void *ptr;
++} vector;
++
++#define VECTOR_P_END(vct) ((void*)(((char*)((vct)->ptr)) + (vct)->size))
++#define VECTOR_S_END(vct) ((void*)(((char*)((vct).ptr)) + (vct).size))
++
++static void vector_clear(vector *);
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++static void vector_reset(vector *);
++static void vector_clr_ptr(vector *);
++static void vector_add_u8(vector *, u8);
++static void vector_add_u16(vector *, u16);
++static void vector_add_u32(vector *, u32);
++static void vector_add_s8(vector *, s8);
++static void vector_add_s16(vector *, s16);
++static void vector_add_s32(vector *, s32);
++static void vector_add_ptr(vector *, void *);
++static void vector_concat(vector *, vector *);
++#endif
++
++#endif
++
++//ORIGIN: include/DataStructures/DataTypes.h
++
++/*******************************************************************************
++* FILE: DataTypes.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef DATATYPES_H
++#define DATATYPES_H
++
++//#include "DataStructures/TypeDefs.h"
++
++typedef u16 THUMB_DataType;
++typedef u32 ARM_DataType;
++typedef u8 TokenType;
++typedef u8 PredictorType;
++typedef u8 *ProbDist;
++
++typedef vector RawData;
++typedef vector RawBlocks;
++typedef vector TokenStream;
++typedef vector TokenBlocks;
++typedef vector LatType;
++
++#define THUMB_DATA_LENGTH 16
++#define ARM_DATA_LENGTH 32
++#define TOKEN_LENGTH 8
++#define TOKEN_MAXVALUE 0xff
++#define PREDICTOR_LENGTH 8
++#define PREDICTOR_MAXVALUE 0xff
++
++#endif
++
++//ORIGIN: include/DataStructures/BitVector.h
++
++/*******************************************************************************
++* FILE: BitVector.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef BITVECTOR_H
++#define BITVECTOR_H
++
++//#include "DataStructures/TypeDefs.h"
++
++typedef vector BitBlocks;
++
++#pragma pack(4)
++
++typedef struct
++{
++ u32 freebits;
++ u32 capacity;
++ u32 size;
++ u8 *base;
++ u8 *ptr;
++} BitVector;
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++static void bitblocks_clear(BitBlocks *);
++static void bitvector_clear(BitVector *);
++static void bitvector_W_reset(BitVector *);
++static void bitvector_W_add0(BitVector *);
++static void bitvector_W_add1(BitVector *);
++static void bitvector_W_concat_b(BitVector *, BitVector *);
++static void bitvector_W_concat_v(BitVector *, vector *);
++static void bitvector_W_flush(BitVector *);
++static void bitvector_R_reset(BitVector *);
++static u8 bitvector_R_get1(BitVector *);
++static u8 bitvector_R_get8(BitVector *);
++#endif
++
++#define BITVECTOR_P_END(bv) ((void*)(((bv)->base)+((bv)->size)))
++#define BITVECTOR_S_END(bv) ((void*)( ((bv).base)+ ((bv).size)))
++#define BITVECTOR_SKIP(bv,num) ((bv)->ptr) += (num)
++
++#endif
++
++//ORIGIN: include/DataStructures/DecisionTree.h
++
++/*******************************************************************************
++* FILE: DecisionTree.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef DECISIONTREE_H
++#define DECISIONTREE_H
++
++//#include "DataStructures/DataTypes.h"
++
++#pragma pack(4)
++
++#define TREENODETYPE_NULLNODE 0
++#define TREENODETYPE_NODE_BINARY_EQ 1
++#define TREENODETYPE_LEAF_P 2
++#define TREENODETYPE_LEAF_C 3
++#define TREENODETYPE_NODE_BINARY_LT 5
++#define TREENODETYPE_IS_NODE(n) (((n) == TREENODETYPE_NODE_BINARY_EQ) || \
++ ((n) == TREENODETYPE_NODE_BINARY_LT))
++#define TREENODETYPE_IS_NODE_BINARY(n) (((n) == TREENODETYPE_NODE_BINARY_EQ) || \
++ ((n) == TREENODETYPE_NODE_BINARY_LT))
++
++#define TREENODETYPE_IS_LEAF(n) (((n) == TREENODETYPE_LEAF_P) || \
++ ((n) == TREENODETYPE_LEAF_C))
++
++
++#define TREE_SUBTREE_RELATION_LEFT_EQ !=
++#define TREE_SUBTREE_RELATION_RIGHT_EQ ==
++#define TREE_SUBTREE_RELATION_LEFT_LT <
++#define TREE_SUBTREE_RELATION_RIGHT_LT >=
++
++#define GET_NODE_PTR_TYPE(n) (((TreeNodeDummy*)(n))->type)
++
++typedef struct
++{
++ u8 type;
++} TreeNodeDummy;
++
++typedef struct
++{
++ u8 type; // [TREENODETYPE_NODE_BINARY]
++ u8 attribute;
++ PredictorType value;
++ void *left;
++ void *right;
++} TreeNodeBinary;
++
++typedef struct
++{
++ u8 type; // [TREENODETYPE_LEAF_P]
++ u16 pairs;
++ PredictorType *probabilities;
++} TreeLeafP;
++
++typedef struct
++{
++ u8 type; // [TREENODETYPE_LEAF_C]
++ PredictorType predicted_class;
++} TreeLeafC;
++
++typedef struct
++{
++ u32 high;
++ u32 low;
++ u32 max;
++} ProbabilityType;
++
++
++typedef struct
++{
++ void *root;
++ u16 number_of_classes;
++ u16 number_of_predictors;
++ PredictorType *predictor_max_values;
++} DecisionTree;
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++static void decisiontree_delete(DecisionTree *);
++static void decisiontree_get_probability_for_token(void *, PredictorType *, TokenType, ProbabilityType *);
++static TokenType decisiontree_get_token_for_range(void *, PredictorType *, u32, u32, ProbabilityType *);
++#endif
++
++#endif
++
++//ORIGIN: include/DataStructures/PredictorTable.h
++
++/*******************************************************************************
++* FILE: PredictorTable.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef PREDICTORTABLE_H
++#define PREDICTORTABLE_H
++
++//#include "DataStructures/TypeDefs.h"
++//#include "DataStructures/DataTypes.h"
++////#include "DataStructures/Filter.h"
++////#include "DataStructures/Converter.h"
++////#include "DataStructures/Manipulator.h"
++
++#define NUMBER_OF_PREDICTORS_ARM 17
++
++#ifndef __KERNEL__
++#define NUMBER_OF_PREDICTORS_TXT 2
++#else
++#undef TXT_TOKENS
++#endif // __KERNEL__
++
++#ifdef TXT_TOKENS
++#define NUMBER_OF_PREDICTORS NUMBER_OF_PREDICTORS_TXT
++#define predictortable_reset predictortable_resetTXT
++#define predictortable_update predictortable_updateTXT
++#define predictortable_minvalue predictortable_minvalueTXT
++#define predictortable_maxvalue predictortable_maxvalueTXT
++#else
++#define NUMBER_OF_PREDICTORS NUMBER_OF_PREDICTORS_ARM
++#define predictortable_reset predictortable_resetARM
++#define predictortable_update predictortable_updateARM
++#define predictortable_minvalue predictortable_minvalueARM
++#define predictortable_maxvalue predictortable_maxvalueARM
++#endif
++
++
++#pragma pack(4)
++
++typedef struct
++{
++ PredictorType *predictors;
++} PredictorTable;
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++static void predictortable_clear(PredictorTable *);
++static void predictortable_free(PredictorTable *);
++static void predictortable_resetARM(PredictorTable *);
++static void predictortable_updateARM(PredictorTable *, TokenType);
++static PredictorType predictortable_minvalueARM(PredictorTable *, u32);
++static PredictorType predictortable_maxvalueARM(PredictorTable *, u32);
++#endif
++
++#ifndef __KERNEL__
++/*
++static void predictortable_resetTXT(PredictorTable *);
++static void predictortable_updateTXT(PredictorTable *, TokenType);
++static PredictorType predictortable_minvalueTXT(PredictorTable *, u32);
++static PredictorType predictortable_maxvalueTXT(PredictorTable *, u32);
++*/
++#endif // __KERNEL__
++
++#endif
++
++//ORIGIN: include/DataStructures/ipack_model.h
++
++/*******************************************************************************
++* FILE: ipack_model.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef IPACK_MODEL_H
++#define IPACK_MODEL_H
++
++//#include "DataStructures/DataTypes.h"
++//#include "DataStructures/DecisionTree.h"
++//#include "DataStructures/PredictorTable.h"
++
++#define PROBABILITY_SHIFT 12
++#define PROBABILITY_MAX 0x00001000l
++
++#define NUMBER_OF_TOKENS_ARM 16
++#define NUMBER_OF_TOKENS_PER_INSTRUCTION_ARM 8
++
++#ifndef __KERNEL__
++#define NUMBER_OF_TOKENS_TXT 256
++#define NUMBER_OF_TOKENS_PER_INSTRUCTION_TXT 4
++#else
++#undef TXT_TOKENS
++#endif // __KERNEL__
++
++#ifdef TXT_TOKENS
++#define NUMBER_OF_TOKENS NUMBER_OF_TOKENS_TXT
++#define NUMBER_OF_TOKENS_PER_INSTRUCTION NUMBER_OF_TOKENS_PER_INSTRUCTION_TXT
++#else
++#define NUMBER_OF_TOKENS NUMBER_OF_TOKENS_ARM
++#define NUMBER_OF_TOKENS_PER_INSTRUCTION NUMBER_OF_TOKENS_PER_INSTRUCTION_ARM
++#endif
++
++#pragma pack(4)
++
++/*
++ Data structure of an internal node of the tree
++*/
++typedef struct
++{
++ PredictorType *attribute_ptr;
++ u32 value; // PredictorType
++ void *right_child_ptr;
++} ipack_treenodeBin;
++/*
++ Data structure of a leaf with probabilities
++*/
++typedef struct
++{
++ u16 probabilities[0]; // PredictorType[0]
++} ipack_treeleafP;
++/*
++ Data structure of a leaf with class prediction
++*/
++typedef struct
++{
++ PredictorType predicted_class; // PredictorType
++} ipack_treeleafC;
++/*
++ Possible data structures of a tree node
++*/
++typedef union
++{
++ ipack_treenodeBin nodeBin;
++ ipack_treeleafP leafP;
++ ipack_treeleafC leafC;
++} ipack_node_data;
++/*
++ Tree node
++*/
++typedef struct
++{
++ u32 type; // u8
++ ipack_node_data data; // ipack_node_data
++} ipack_nodetype;
++/*
++ Nullnode
++*/
++typedef struct
++{
++ u32 type;
++ u16 probabilities[NUMBER_OF_TOKENS];
++} ipack_nullnode;
++/*
++ Model for ipack project
++*/
++typedef struct
++{
++ char ID[4]; // char[4]
++ char block_sign[4]; // only the first 2 are used!
++ void *tree_root_ptr; // void*
++ void *tree_code; // generated ARM code
++ PredictorType *predictors_ptr; // PredictorType*
++ ipack_nullnode nullnode;
++} ipack_model_type;
++
++typedef struct
++{
++ u32 high;
++ u32 low;
++} ipack_probability_type;
++
++
++static void ipack_model_get_probability_for_token(ipack_nodetype *, TokenType, ipack_probability_type *);
++static TokenType ipack_model_get_token_for_range(ipack_nodetype *, u32, u32, ipack_probability_type *);
++/*void ipack_model_predictortable_reset (PredictorType*);
++void ipack_model_predictortable_update (PredictorType*, TokenType);*/
++
++#ifndef __KERNEL__
++/*static void ipack_model_printinfo(ipack_model_type *);
++static void ipack_dumpmodel(void *);*/
++#endif
++
++#endif
++
++//ORIGIN: include/Builders/PredictorGenerator.h
++
++/*******************************************************************************
++* FILE: PredictorGenerator.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef PREDICTORGENERATOR_H
++#define PREDICTORGENERATOR_H
++
++//#include "DataStructures.h"
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++static PredictorTable *predictorgenerator_generate(void);
++#endif
++
++#endif
++
++//ORIGIN: include/Builders/Coder.h
++
++/*******************************************************************************
++* FILE: Coder.h
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++#ifndef CODER_H
++#define CODER_H
++
++#define CODER_VALUEBITS 16
++#define CODER_VALUEMAX 0x00010000l
++#define CODER_VALUE3RD 0x0000c000l
++#define CODER_VALUEHLF 0x00008000l
++#define CODER_VALUE1ST 0x00004000l
++
++#endif
++
++//ORIGIN: DataStructures/src/TypeDefs.c
++
++/*******************************************************************************
++* FILE: TypeDefs.c
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++//#include "ipack_common.h"
++//#include "DataStructures/TypeDefs.h"
++#ifndef __KERNEL__
++#include <memory.h>
++#endif
++
++#define VECTOR_ALLOC_SIZE 0x00001000
++
++static void vector_clear(vector * vct)
++{
++ if (vct->ptr)
++ jffs2_bbc_free(vct->ptr);
++ vct->capacity = 0;
++ vct->size = 0;
++ vct->ptr = 0;
++}
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++static void vector_extend(vector * vct)
++{
++ void *tmp;
++ vct->capacity += vct->alloc_size;
++ tmp = jffs2_bbc_malloc(vct->capacity);
++ if (vct->ptr) {
++ memcpy(tmp, vct->ptr, vct->size);
++ jffs2_bbc_free(vct->ptr);
++ }
++ vct->ptr = tmp;
++}
++
++static void vector_reset(vector * vct)
++{
++ vct->capacity = 0;
++ vct->size = 0;
++ vct->alloc_size = VECTOR_ALLOC_SIZE;
++ vct->ptr = 0;
++}
++
++static void vector_clr_ptr(vector * vct)
++{
++ void **it;
++ void *end_it;
++ for (it = vct->ptr, end_it = (((char *) (vct->ptr)) + vct->size); it != end_it; it++) {
++ vector_clear(*it);
++ jffs2_bbc_free(*it);
++ }
++ if (vct->ptr)
++ jffs2_bbc_free(vct->ptr);
++ vct->capacity = 0;
++ vct->size = 0;
++ vct->ptr = 0;
++}
++
++static void vector_add_u8(vector * vct, u8 val)
++{
++ if ((vct->size) + sizeof(u8) > (vct->capacity)) {
++ vector_extend(vct);
++ }
++ *(u8 *) ((char *) (vct->ptr) + (vct->size)) = val;
++ vct->size += sizeof(u8);
++};
++
++static void vector_add_u16(vector * vct, u16 val)
++{
++ if ((vct->size) + sizeof(u16) > (vct->capacity)) {
++ vector_extend(vct);
++ }
++ *(u16 *) ((char *) (vct->ptr) + (vct->size)) = val;
++ vct->size += sizeof(u16);
++};
++
++static void vector_add_u32(vector * vct, u32 val)
++{
++ if ((vct->size) + sizeof(u32) > (vct->capacity)) {
++ vector_extend(vct);
++ }
++ *(u32 *) ((char *) (vct->ptr) + (vct->size)) = val;
++ vct->size += sizeof(u32);
++};
++
++static void vector_add_s8(vector * vct, s8 val)
++{
++ if ((vct->size) + sizeof(s8) > (vct->capacity)) {
++ vector_extend(vct);
++ }
++ *(s8 *) ((char *) (vct->ptr) + (vct->size)) = val;
++ vct->size += sizeof(s8);
++};
++
++static void vector_add_s16(vector * vct, s16 val)
++{
++ if ((vct->size) + sizeof(s16) > (vct->capacity)) {
++ vector_extend(vct);
++ }
++ *(s16 *) ((char *) (vct->ptr) + (vct->size)) = val;
++ vct->size += sizeof(s16);
++};
++
++static void vector_add_s32(vector * vct, s32 val)
++{
++ if ((vct->size) + sizeof(s32) > (vct->capacity)) {
++ vector_extend(vct);
++ }
++ *(s32 *) ((char *) (vct->ptr) + (vct->size)) = val;
++ vct->size += sizeof(s32);
++};
++
++static void vector_add_ptr(vector * vct, void *ptr)
++{
++ if ((vct->size) + sizeof(void *) > (vct->capacity)) {
++ vector_extend(vct);
++ }
++ *(void **) ((char *) (vct->ptr) + (vct->size)) = ptr;
++ vct->size += sizeof(void *);
++}
++
++static void vector_concat(vector * lhs, vector * rhs)
++{
++ void *tmp;
++ if (!(rhs->size)) {
++ return;
++ }
++ tmp = lhs->ptr;
++ lhs->capacity = (lhs->size) + (rhs->size);
++ lhs->ptr = jffs2_bbc_malloc(lhs->capacity);
++ if (tmp) {
++ memcpy(lhs->ptr, tmp, lhs->size);
++ jffs2_bbc_free(tmp);
++ }
++ memcpy((((u8 *) lhs->ptr) + lhs->size), rhs->ptr, rhs->size);
++ lhs->size += rhs->size;
++}
++
++#endif
++
++//ORIGIN: DataStructures/src/BitVector.c
++
++/*******************************************************************************
++* FILE: BitVector.c
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++//#include "ipack_common.h"
++//#include "DataStructures/BitVector.h"
++#ifndef __KERNEL__
++#include <memory.h>
++#endif
++
++#define VECTOR_ALLOC_SIZE 0x00001000
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++
++static void bitblocks_clear(BitBlocks * this)
++{
++ BitVector **it;
++ void *end_it;
++ for (it = this->ptr, end_it = VECTOR_P_END(this); it != end_it; it++) {
++ bitvector_clear(*it);
++ jffs2_bbc_free(*it);
++ }
++ jffs2_bbc_free(this->ptr);
++ this->ptr = 0;
++}
++
++static void bitvector_clear(BitVector * this)
++{
++ if (this->base) {
++ jffs2_bbc_free(this->base);
++ }
++ this->freebits = 0;
++ this->capacity = 0;
++ this->size = 0;
++ this->base = 0;
++ this->ptr = 0;
++}
++
++static void bitvector_W_reset(BitVector * this)
++{
++ this->freebits = 0;
++ this->capacity = 0;
++ this->size = 0;
++ this->base = 0;
++ this->ptr = 0;
++}
++
++static void bitvector_W_add0(BitVector * this)
++{
++ if (!(this->freebits)) {
++ if (this->size == this->capacity) {
++ void *tmp = this->base;
++ this->capacity += VECTOR_ALLOC_SIZE;
++ this->base = jffs2_bbc_malloc(this->capacity);
++ this->ptr = ((u8 *) (this->base)) + this->size;
++ memcpy(this->base, tmp, this->size);
++ jffs2_bbc_free(tmp);
++ }
++ else {
++ this->ptr++;
++ }
++ this->size++;
++ this->freebits = 7;
++ *(this->ptr) = 0x00;
++ }
++ else {
++ this->freebits--;
++ (*(this->ptr)) <<= 1;
++ }
++}
++
++static void bitvector_W_add1(BitVector * this)
++{
++ if (!(this->freebits)) {
++ if (this->size == this->capacity) {
++ void *tmp = this->base;
++ this->capacity += VECTOR_ALLOC_SIZE;
++ this->base = jffs2_bbc_malloc(this->capacity);
++ this->ptr = ((u8 *) (this->base)) + this->size;
++ memcpy(this->base, tmp, this->size);
++ jffs2_bbc_free(tmp);
++ }
++ else {
++ this->ptr++;
++ }
++ this->size++;
++ this->freebits = 7;
++ *(this->ptr) = 0x01;
++ }
++ else {
++ this->freebits--;
++ (*(this->ptr)) <<= 1;
++ (*(this->ptr)) |= 0x01;
++ }
++}
++
++static void bitvector_W_concat_b(BitVector * lhs, BitVector * rhs)
++{
++ void *tmp;
++ if (!(rhs->size)) {
++ return;
++ }
++ tmp = lhs->base;
++ lhs->capacity = ((((lhs->size) + (rhs->size) - 1) / VECTOR_ALLOC_SIZE) + 1) * VECTOR_ALLOC_SIZE;
++ lhs->base = jffs2_bbc_malloc(lhs->capacity);
++ if (tmp) {
++ memcpy(lhs->base, tmp, lhs->size);
++ jffs2_bbc_free(tmp);
++ }
++ memcpy((((u8 *) (lhs->base)) + lhs->size), rhs->base, rhs->size);
++ lhs->freebits = 0;
++ lhs->size += rhs->size;
++ lhs->ptr = ((u8 *) (lhs->base)) + lhs->size;
++}
++
++static void bitvector_W_concat_v(BitVector * lhs, vector * rhs)
++{
++ void *tmp;
++ if (!(rhs->size)) {
++ return;
++ }
++ tmp = lhs->base;
++ lhs->capacity = ((((lhs->size) + (rhs->size) - 1) / VECTOR_ALLOC_SIZE) + 1) * VECTOR_ALLOC_SIZE;
++ lhs->base = jffs2_bbc_malloc(lhs->capacity);
++ if (tmp) {
++ memcpy(lhs->base, tmp, lhs->size);
++ jffs2_bbc_free(tmp);
++ }
++ memcpy((((u8 *) (lhs->base)) + lhs->size), rhs->ptr, rhs->size);
++ lhs->freebits = 0;
++ lhs->size += rhs->size;
++ lhs->ptr = ((u8 *) (lhs->base)) + lhs->size;
++}
++
++static void bitvector_W_flush(BitVector * this)
++{
++ (*(this->ptr)) <<= this->freebits;
++ this->freebits = 0;
++}
++
++static void bitvector_R_reset(BitVector * this)
++{
++ this->freebits = 7;
++ this->ptr = this->base;
++}
++
++static u8 bitvector_R_get1(BitVector * this)
++{
++ u8 tmp = ((*(this->ptr)) >> this->freebits) & 0x01;
++ if (!(this->freebits)) {
++ this->freebits = 7;
++ this->ptr++;
++ }
++ else {
++ this->freebits--;
++ }
++ return tmp;
++}
++
++static u8 bitvector_R_get8(BitVector * this)
++{
++ u8 tmp = (*(this->ptr));
++ this->ptr++;
++ return tmp;
++}
++
++#endif
++
++//ORIGIN: DataStructures/src/DecisionTree.c
++
++/*******************************************************************************
++* FILE: DecisionTree.c
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++//#include "ipack_common.h"
++//#include "DataStructures/DecisionTree.h"
++
++static void decisiontree_delete_node(void *root)
++{
++ u8 tmp = GET_NODE_PTR_TYPE(root);
++ if (TREENODETYPE_IS_NODE_BINARY(tmp)) {
++ decisiontree_delete_node(((TreeNodeBinary *) root)->left);
++ decisiontree_delete_node(((TreeNodeBinary *) root)->right);
++ }
++ else if ((tmp) == TREENODETYPE_LEAF_P) {
++ if (((TreeLeafP *) root)->probabilities) {
++ jffs2_bbc_free(((TreeLeafP *) root)->probabilities);
++ }
++ }
++ else if ((tmp) == TREENODETYPE_LEAF_C) {
++ }
++ jffs2_bbc_free(root);
++}
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++
++static void decisiontree_delete(DecisionTree * dt)
++{
++ decisiontree_delete_node(dt->root);
++ jffs2_bbc_free(dt->predictor_max_values);
++}
++
++static void decisiontree_get_probability_for_token(void *root, PredictorType * preds, TokenType token, ProbabilityType * prob)
++{
++ void *tmp = root;
++ while (TREENODETYPE_IS_NODE(((TreeNodeBinary *) tmp)->type)) {
++ if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_NODE_BINARY_EQ) {
++ if (preds[((TreeNodeBinary *) tmp)->attribute] TREE_SUBTREE_RELATION_LEFT_EQ((TreeNodeBinary *) tmp)->value) {
++ tmp = ((TreeNodeBinary *) tmp)->left;
++ }
++ else {
++ tmp = ((TreeNodeBinary *) tmp)->right;
++ }
++ }
++ else if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_NODE_BINARY_LT) {
++ if (preds[((TreeNodeBinary *) tmp)->attribute] TREE_SUBTREE_RELATION_LEFT_LT((TreeNodeBinary *) tmp)->value) {
++ tmp = ((TreeNodeBinary *) tmp)->left;
++ }
++ else {
++ tmp = ((TreeNodeBinary *) tmp)->right;
++ }
++ }
++ }
++ prob->high = 0;
++ prob->low = 0;
++ prob->max = 0;
++ if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_LEAF_P) {
++ u32 i;
++ u32 lngth = ((TreeLeafP *) tmp)->pairs << 1;
++ for (i = 0; i < lngth;) {
++ TokenType at = ((TreeLeafP *) tmp)->probabilities[i++];
++ TokenType av = ((TreeLeafP *) tmp)->probabilities[i++];
++ if (token > at)
++ prob->low += av;
++ if (token >= at)
++ prob->high += av;
++ prob->max += av;
++ }
++ }
++ else if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_LEAF_C) {
++ if (((TreeLeafC *) tmp)->predicted_class == token) {
++ prob->high = TOKEN_MAXVALUE;
++ prob->max = TOKEN_MAXVALUE;
++ }
++ }
++}
++
++static TokenType decisiontree_get_token_for_range(void *root, PredictorType * preds, u32 value, u32 range, ProbabilityType * prob)
++{
++ void *tmp = root;
++ TokenType token = 0;
++ while (TREENODETYPE_IS_NODE(((TreeNodeBinary *) tmp)->type)) {
++ if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_NODE_BINARY_EQ) {
++ if (preds[((TreeNodeBinary *) tmp)->attribute] TREE_SUBTREE_RELATION_LEFT_EQ((TreeNodeBinary *) tmp)->value) {
++ tmp = ((TreeNodeBinary *) tmp)->left;
++ }
++ else {
++ tmp = ((TreeNodeBinary *) tmp)->right;
++ }
++ }
++ else if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_NODE_BINARY_LT) {
++ if (preds[((TreeNodeBinary *) tmp)->attribute] TREE_SUBTREE_RELATION_LEFT_LT((TreeNodeBinary *) tmp)->value) {
++ tmp = ((TreeNodeBinary *) tmp)->left;
++ }
++ else {
++ tmp = ((TreeNodeBinary *) tmp)->right;
++ }
++ }
++ }
++ prob->high = 0;
++ prob->low = 0;
++ prob->max = 0;
++ if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_LEAF_P) {
++ u32 i;
++ u32 norm;
++ TokenType at = 0;
++ TokenType av;
++ u32 lngth = ((TreeLeafP *) tmp)->pairs << 1;
++ for (i = 0; i < lngth;) {
++ i++;
++ prob->max += ((TreeLeafP *) tmp)->probabilities[i++];
++ }
++ norm = (value * prob->max - 1) / range;
++ for (i = 0; prob->high <= norm;) {
++ at = ((TreeLeafP *) tmp)->probabilities[i++];
++ av = ((TreeLeafP *) tmp)->probabilities[i++];
++ prob->high += av;
++ if (prob->high <= norm)
++ prob->low += av;
++ }
++ token = at;
++ }
++ else if (((TreeNodeBinary *) tmp)->type == TREENODETYPE_LEAF_C) {
++ token = ((TreeLeafC *) tmp)->predicted_class;
++ prob->high = TOKEN_MAXVALUE;
++ prob->max = TOKEN_MAXVALUE;
++ }
++ return token;
++}
++#endif
++
++//ORIGIN: DataStructures/src/PredictorTable.c
++
++/*******************************************************************************
++* FILE: PredictorTable.c
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++//#include "ipack_common.h"
++//#include "DataStructures/PredictorTable.h"
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++
++static void predictortable_clear(PredictorTable * table)
++{
++ table->predictors = 0;
++}
++
++static void predictortable_free(PredictorTable * table)
++{
++ if (table->predictors) {
++ jffs2_bbc_free(table->predictors);
++ table->predictors = 0;
++ }
++}
++
++static void predictortable_resetARM(PredictorTable * table)
++{
++ register PredictorType *ptr = table->predictors;
++ register PredictorType *end = ptr + NUMBER_OF_PREDICTORS_ARM;
++ while (ptr < end) {
++ *(ptr++) = 0;
++ }
++}
++
++static void predictortable_updateARM(PredictorTable * table, TokenType token)
++{
++ register PredictorType *ptr = table->predictors;
++ register u32 ndx = ptr[0] + 1;
++ ptr[ndx + 8] = ptr[ndx];
++ ptr[ndx] = token;
++ if (ndx == 8) {
++ ptr[0] = 0;
++ }
++ else {
++ ++ptr[0];
++ }
++}
++
++static PredictorType predictortable_minvalueARM(PredictorTable * table, u32 index)
++{
++ return 0;
++}
++
++static PredictorType predictortable_maxvalueARM(PredictorTable * table, u32 index)
++{
++ if (index == 0) {
++ return 7;
++ }
++ else {
++ return 15;
++ }
++}
++
++#endif
++
++#ifndef __KERNEL__
++
++/*static void predictortable_resetTXT(PredictorTable * table)
++{
++ register PredictorType *ptr = table->predictors;
++ register PredictorType *end = ptr + NUMBER_OF_PREDICTORS_TXT;
++ while (ptr < end) {
++ *(ptr++) = 0;
++ }
++}
++
++static void predictortable_updateTXT(PredictorTable * table, TokenType token)
++{ //TODO: modify
++ register PredictorType *ptr = table->predictors;
++// register u32 ndx;
++ ptr[0] = token;
++ if ((('a' <= token) && (token <= 'z')) || (('A' <= token) && (token <= 'Z'))) {
++ ++(ptr[1]);
++ }
++ else {
++ ptr[1] = 0;
++ }
++}
++
++static PredictorType predictortable_minvalueTXT(PredictorTable * table, u32 index)
++{
++ return 0;
++}
++
++static PredictorType predictortable_maxvalueTXT(PredictorTable * table, u32 index)
++{ //TODO: modify
++ return 254;
++}*/
++
++#endif // __KERNEL__
++
++//ORIGIN: DataStructures/src/ipack_model.c
++
++/*******************************************************************************
++* FILE: ipack_model.c
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++//#include "DataStructures/ipack_model.h"
++//#include "measuredef.h"
++//#include "ipack_common.h"
++
++#ifdef __MEASURE_TIME_MODEL_GETPROB
++#define __MT_P_MAX 256
++#define __MT_P_DIV 128
++#define __MT_P_MIN 0
++#endif
++
++static void ipack_model_get_probability_for_token(ipack_nodetype * tmp, TokenType token, ipack_probability_type * prob)
++{
++// register ipack_nodetype* tmp = model->tree_root_ptr;
++// register ipack_nodetype* tmp = root;
++ while (TREENODETYPE_IS_NODE(tmp->type)) {
++ if (tmp->type == TREENODETYPE_NODE_BINARY_EQ) {
++ if (*(tmp->data.nodeBin.attribute_ptr) TREE_SUBTREE_RELATION_LEFT_EQ tmp->data.nodeBin.value) {
++ ((char *) tmp) += sizeof(tmp->type) + sizeof(ipack_treenodeBin);
++ }
++ else {
++ tmp = tmp->data.nodeBin.right_child_ptr;
++ }
++ }
++ else if (tmp->type == TREENODETYPE_NODE_BINARY_LT) {
++ if (*(tmp->data.nodeBin.attribute_ptr) TREE_SUBTREE_RELATION_LEFT_LT tmp->data.nodeBin.value) {
++ ((char *) tmp) += sizeof(tmp->type) + sizeof(ipack_treenodeBin);
++ }
++ else {
++ tmp = tmp->data.nodeBin.right_child_ptr;
++ }
++ }
++ }
++ prob->high = 0;
++ prob->low = 0;
++// prob->max = 0;
++ if (tmp->type == TREENODETYPE_LEAF_P) {
++ if (token) {
++ prob->low = tmp->data.leafP.probabilities[token - 1];
++ }
++ prob->high = tmp->data.leafP.probabilities[token];
++// prob->max = tmp->data.leafP.probabilities[15];
++ }
++ else if (tmp->type == TREENODETYPE_LEAF_C) {
++ if (tmp->data.leafC.predicted_class == token) {
++ prob->high = TOKEN_MAXVALUE;
++// prob->max = TOKEN_MAXVALUE;
++ }
++ }
++}
++
++#ifndef IPACK_ARM_ASM
++
++//return ipack_model_get_token_for_range2(tmp,value,range,prob);
++
++static TokenType ipack_model_get_token_for_range(ipack_nodetype * tmp, u32 value, u32 range, ipack_probability_type * prob)
++{
++// register ipack_nodetype* tmp = model->tree_root_ptr;
++// register ipack_nodetype* tmp = root;
++ register TokenType token = 0;
++ while (TREENODETYPE_IS_NODE(tmp->type)) {
++ if (tmp->type == TREENODETYPE_NODE_BINARY_EQ) {
++ if (*(tmp->data.nodeBin.attribute_ptr) TREE_SUBTREE_RELATION_LEFT_EQ tmp->data.nodeBin.value) {
++ ((char *) tmp) += sizeof(tmp->type) + sizeof(ipack_treenodeBin);
++ }
++ else {
++ tmp = tmp->data.nodeBin.right_child_ptr;
++ }
++ }
++ else if (tmp->type == TREENODETYPE_NODE_BINARY_LT) {
++ if (*(tmp->data.nodeBin.attribute_ptr) TREE_SUBTREE_RELATION_LEFT_LT tmp->data.nodeBin.value) {
++ ((char *) tmp) += sizeof(tmp->type) + sizeof(ipack_treenodeBin);
++ }
++ else {
++ tmp = tmp->data.nodeBin.right_child_ptr;
++ }
++ }
++ }
++ prob->high = 0;
++ prob->low = 0;
++// prob->max = 0;
++ if (tmp->type == TREENODETYPE_LEAF_P) {
++ u32 i;
++ u32 norm;
++// prob->max = tmp->data.leafP.probabilities[15];
++/* norm = (value * prob->max -1)/range;
++ for(i = 0; i < 15; ++i) {
++ if(tmp->data.leafP.probabilities[i] > norm) {
++ break;
++ }
++ }*/
++ norm = ((value << PROBABILITY_SHIFT) - 1);
++ for (i = 0; i < NUMBER_OF_TOKENS; ++i) {
++ if (range * tmp->data.leafP.probabilities[i] > norm) {
++ break;
++ }
++ }
++ token = (TokenType) i;
++ prob->high = tmp->data.leafP.probabilities[i];
++ if (token) {
++ prob->low = tmp->data.leafP.probabilities[token - 1];
++ }
++ }
++ else if (tmp->type == TREENODETYPE_LEAF_C) {
++ token = tmp->data.leafC.predicted_class;
++ prob->high = PROBABILITY_MAX;
++// prob->max = PROBABILITY_MAX;
++ }
++ return token;
++}
++#endif
++/*
++void ipack_model_predictortable_reset(PredictorType* ptr)
++{
++// register PredictorType* ptr = model->predictors_ptr;
++// register PredictorType* ptr = preds;
++ register PredictorType* end = ptr + NUMBER_OF_PREDICTORS;
++ while(ptr < end) {
++ *(ptr++) = 0;
++ }
++}
++
++void ipack_model_predictortable_update(PredictorType* ptr, TokenType token)
++{
++// register PredictorType* ptr = model->predictors_ptr;
++// register PredictorType* ptr = preds;
++ register u32 ndx = ptr[0] + 1;
++ ptr[ndx + 8] = ptr[ndx];
++ ptr[ndx] = token;
++ if(ndx == 8) {
++ ptr[0] = 0;
++ } else {
++ ++ ptr[0];
++ }
++}*/
++/****************************************************************************/
++
++#ifndef __KERNEL__
++static void ipack_model_countpreds(void *ptr, ipack_nodetype * node, double *table, double val)
++{
++ if ((node->type == TREENODETYPE_NODE_BINARY_EQ) || (node->type == TREENODETYPE_NODE_BINARY_LT)) {
++ table[(u32) (node->data.nodeBin.attribute_ptr) - (u32) (ptr)] += val;
++ ipack_model_countpreds(ptr, (void *) (((u8 *) (node)) + sizeof(node->type) + sizeof(ipack_treenodeBin)), table, val / 2);
++ ipack_model_countpreds(ptr, node->data.nodeBin.right_child_ptr, table, val / 2);
++ }
++ else {
++ }
++}
++
++/*static void ipack_model_printinfo(ipack_model_type * model)
++{
++ double *prcnt = jffs2_bbc_malloc(sizeof(double) * NUMBER_OF_PREDICTORS);
++ u32 i;
++ for (i = 0; i < NUMBER_OF_PREDICTORS; i++) {
++ prcnt[i] = 0.0;
++ }
++ ipack_model_countpreds(model->predictors_ptr, model->tree_root_ptr, prcnt, 100);
++ for (i = 0; i < NUMBER_OF_PREDICTORS; i++) {
++ jffs2_bbc_print3(" p[%3d] = %10.6lf\n", (int) i, prcnt[i]);
++ }
++ jffs2_bbc_free(prcnt);
++}*/
++
++static void ipack_dumpnode(unsigned char **ptr, FILE * file, char *prefs)
++{
++ switch (*((*ptr)++)) {
++ u32 i;
++ u32 j;
++ u32 x;
++ u32 y;
++ case TREENODETYPE_NODE_BINARY_EQ:
++ x = *((*ptr)++);
++ y = *((*ptr)++);
++ fprintf(file, "%s+->\tBinary node: P[%u] equals %u\n", prefs, (unsigned int)x, (unsigned int)y);
++ for (j = 0; j < 4096 && prefs[j]; ++j);
++ prefs[j] = '\t';
++ prefs[++j] = '|';
++ ipack_dumpnode(ptr, file, prefs);
++ prefs[j--] = 0;
++ ipack_dumpnode(ptr, file, prefs);
++ prefs[j] = 0;
++ break;
++ case TREENODETYPE_NODE_BINARY_LT:
++ x = *((*ptr)++);
++ y = *((*ptr)++);
++ fprintf(file, "%s+->\tBinary node: P[%u] greater than %u\n", prefs, (unsigned int)x, (unsigned int)y);
++ for (j = 0; j < 4096 && prefs[j]; ++j);
++ prefs[j] = '\t';
++ prefs[++j] = '|';
++ ipack_dumpnode(ptr, file, prefs);
++ prefs[j--] = 0;
++ ipack_dumpnode(ptr, file, prefs);
++ prefs[j] = 0;
++ break;
++ case TREENODETYPE_LEAF_P:
++ x = *((*ptr)++);
++ fprintf(file, "%s+->\tLeaf: %u pairs\n", prefs, (unsigned int)x);
++ (*ptr) += (x << 1);
++ break;
++ case TREENODETYPE_LEAF_C:
++ x = *((*ptr)++);
++ fprintf(file, "%s+->\tLeaf: class %u\n", prefs, (unsigned int)x);
++ break;
++ default:
++ fprintf(file, "%s+->\tLeaf: nullnode\n", prefs);
++ }
++}
++
++/*static void ipack_dumpmodel(void *model)
++{
++ unsigned char *tmp_ptr = model;
++ FILE *file;
++ char C[4096];
++ if ((file = fopen("DUMPED_MODEL", "wa"))) {
++ int i;
++ for (i = 0; i < 4096; C[i++] = 0);
++ tmp_ptr += 8;
++ tmp_ptr += sizeof(u32);
++ ipack_dumpnode(&tmp_ptr, file, C);
++ fclose(file);
++ }
++}*/
++
++#endif
++
++//ORIGIN: Builders/src/PredictorGenerator.c
++
++/*******************************************************************************
++* FILE: PredictorGenerator.c
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++//#include "ipack_common.h"
++//#include "Builders/PredictorGenerator.h"
++
++#ifdef JFFS2_BBC_ARMLIB_MODELGEN
++static PredictorTable *predictorgenerator_generate( /*PredictorGeneratorSettings* settings */ )
++{
++ PredictorTable *ptr = jffs2_bbc_malloc(sizeof(PredictorTable));
++ predictortable_clear(ptr);
++ ptr->predictors = jffs2_bbc_malloc(NUMBER_OF_PREDICTORS * sizeof(PredictorType));
++ return ptr;
++}
++#endif
++
++//ORIGIN: Builders/src/ipack_armlib_compressor.c
++
++/*******************************************************************************
++* FILE: ipack_armlim_compressor.c
++* AUTHOR: Tamás Gergely
++* MODIFIED: $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*******************************************************************************/
++
++//#include "ipack_common.h"
++//#include "DataStructures.h"
++//#include "Builders/PredictorGenerator.h"
++//#include "Builders/Tokenizer.h"
++//#include "Builders/Coder.h"
++
++#define EC_NO_ERROR 0
++#define EC_NOT_IPMF_FILE -1
++#define EC_NOT_IPMF_MODEL -2
++#define EC_NOT_HG_BLOCK -3
++#define EC_WRONG_INPUT_LENGTH -501
++#define EC_CODER_WRONG_PROBABILITY 1
++#define EC_CODER_WRONG_RANGE 2
++#define EC_BUFFER_OVERFLOW 501
++#define EC_BUFFER_UNDERFLOW 502
++#define EC_UNKNOWN_TOKEN_TYPE 1001
++#define EC_UNKNOWN_FILTER 1002
++#define EC_UNKNOWN_CONVERTER 1003
++#define EC_UNKNOWN_MANIPULATOR 1004
++
++/*******************************************************************************
++
++ COMPRESSOR INIT FUNCTIONS
++
++*******************************************************************************/
++
++#define ROUND_UP_TO_DWORD(val) ( ( (val) + 3 ) & 0xfffffffc )
++
++#ifndef __KERNEL__
++int ipack_glb_endian_X;
++#endif
++
++static int ipack_compressor_init_tree(unsigned char **ptr, ipack_model_type * model, ipack_nodetype * node, void *nullnode)
++{
++ int retval = 0;
++ node->type = *((*ptr)++);
++ switch (node->type) {
++ u32 i;
++ u32 j;
++ u32 lngth;
++ u32 tmpret;
++ TokenType at;
++ u16 av;
++ case TREENODETYPE_NODE_BINARY_EQ:
++ case TREENODETYPE_NODE_BINARY_LT:
++ node->data.nodeBin.attribute_ptr = (model->predictors_ptr) + (*((*ptr)++));
++ node->data.nodeBin.value = *((*ptr)++);
++ retval = sizeof(node->data.nodeBin);
++ retval += ipack_compressor_init_tree(ptr, model, (void *) ROUND_UP_TO_DWORD(((u32) node) + sizeof(node->type) + sizeof(node->data.nodeBin)), nullnode);
++ node->data.nodeBin.right_child_ptr = (void *) ROUND_UP_TO_DWORD(((u32) node) + retval + sizeof(node->type));
++ retval += ipack_compressor_init_tree(ptr, model, node->data.nodeBin.right_child_ptr, nullnode);
++ break;
++ case TREENODETYPE_LEAF_P:
++ lngth = *((*ptr)++);
++ av = 0;
++ for (i = 0, j = 0; i < lngth; ++i) {
++ at = *((*ptr)++);
++ while (j < at) {
++ node->data.leafP.probabilities[j++] = av;
++ }
++ av += *((*ptr)++);
++ }
++ while (j < NUMBER_OF_TOKENS) {
++ node->data.leafP.probabilities[j++] = av;
++ }
++ for (i = 0; i < NUMBER_OF_TOKENS; ++i) {
++ node->data.leafP.probabilities[i] = ((node->data.leafP.probabilities[i] << PROBABILITY_SHIFT) / node->data.leafP.probabilities[NUMBER_OF_TOKENS - 1]);
++ }
++ retval = ROUND_UP_TO_DWORD(NUMBER_OF_TOKENS * sizeof(u16));
++ break;
++ case TREENODETYPE_LEAF_C:
++ node->data.leafC.predicted_class = *((*ptr)++);
++ retval = sizeof(node->data.leafC);
++ retval = ROUND_UP_TO_DWORD(retval);
++ break;
++ default:
++ return 0;
++ }
++ return retval + sizeof(node->type);
++}
++
++#define IPACK_TREE_CONVERT_REPLACE 0
++#define IPACK_TREE_CONVERT_KEEP 1
++
++static void *ipack_tree_to_code(ipack_model_type * model, int *code_size);
++
++static int ipack_armlib_convert_tree_to_code(ipack_model_type * model_img, int mode)
++{
++#ifdef IPACK_TREE_TO_CODE
++ int tree_size;
++
++ model_img->tree_code = ipack_tree_to_code(model_img, &tree_size);
++ jffs2_bbc_print2("Convertation done. Code size=%d\n", tree_size);
++ if (mode == IPACK_TREE_CONVERT_REPLACE) {
++ jffs2_bbc_print1("Freeing original tree.\n");
++ jffs2_bbc_free(model_img->tree_root_ptr);
++ model_img->tree_root_ptr = NULL;
++ }
++#endif
++ return 0;
++}
++
++
++static int ipack_armlib_compressor_init(void **model)
++{
++ int retval = EC_NO_ERROR;
++ unsigned char *tmp_ptr = *model;
++ u32 i;
++ ipack_model_type *model_img;
++ char tmp_c[2];
++
++ if (*(tmp_ptr++) != 'i') {
++ return EC_NOT_IPMF_FILE;
++ }
++ else if (*(tmp_ptr++) != 'P') {
++ return EC_NOT_IPMF_FILE;
++ }
++ else if (*(tmp_ptr++) != 'M') {
++ return EC_NOT_IPMF_FILE;
++ }
++ else if (*(tmp_ptr++) != 'F') {
++ return EC_NOT_IPMF_FILE;
++ }
++ tmp_c[0] = *(tmp_ptr++);
++ tmp_c[1] = *(tmp_ptr++);
++ tmp_ptr += 2;
++
++ //model_img = jffs2_bbc_malloc(*((u32*)tmp_ptr));
++ model_img = jffs2_bbc_malloc(sizeof(ipack_model_type) + ROUND_UP_TO_DWORD(NUMBER_OF_PREDICTORS));
++ model_img->tree_root_ptr = jffs2_bbc_malloc(*((u32 *) tmp_ptr)); //it is smaller a little but, but...
++
++ tmp_ptr += sizeof(u32);
++
++ model_img->ID[0] = 'i';
++ model_img->ID[1] = 'P';
++ model_img->ID[2] = 'M';
++ model_img->ID[3] = 'F';
++
++ model_img->block_sign[0] = tmp_c[0];
++ model_img->block_sign[1] = tmp_c[1];
++
++ model_img->nullnode.type = TREENODETYPE_LEAF_P;
++ for (i = 0; i < NUMBER_OF_TOKENS; ++i) {
++ model_img->nullnode.probabilities[i] = 0;
++ }
++ model_img->predictors_ptr = (void *) (((u32) model_img) + sizeof(ipack_model_type));
++ //model_img->tree_root_ptr = (void*)ROUND_UP_TO_DWORD(((u32)(model_img->predictors_ptr)) + NUMBER_OF_PREDICTORS);//ALIGN
++
++ ipack_compressor_init_tree(&tmp_ptr, model_img, model_img->tree_root_ptr, &(model_img->nullnode));
++
++#ifdef IPACK_TREE_TO_CODE
++#ifdef IPACK_AUTO_TREE_TO_CODE
++ jffs2_bbc_print1("Automatically converting tree to ARM code...\n");
++ ipack_armlib_convert_tree_to_code(model_img, IPACK_TREE_CONVERT_REPLACE);
++#else
++ model_img->tree_code = NULL;
++#endif
++#else
++ model_img->tree_code = NULL;
++#endif
++
++ jffs2_bbc_free(*model);
++ *model = model_img;
++ return retval;
++}
++
++/*******************************************************************************
++
++ COMPRESSOR DEINIT FUNCTIONS
++
++*******************************************************************************/
++
++
++/* Descructor of compressor (model will be freed with jffs2_bbc_free() after it)*/
++static void ipack_armlib_compressor_deinit(void)
++{
++}
++
++/*******************************************************************************
++
++ COMPRESS FUNCTIONS
++
++*******************************************************************************/
++
++static int writebits0(unsigned char **dest, u8 * freebits, u32 * opposite, unsigned char *end)
++{
++ if (!(*freebits)) {
++ ++(*dest);
++ *freebits = 7;
++ **dest = 0x00;
++ }
++ else {
++ --(*freebits);
++ (**dest) <<= 1;
++ }
++ if ((*dest == end) && !(*freebits)) {
++ return EC_BUFFER_OVERFLOW;
++ }
++ while (*opposite) {
++ --(*opposite);
++ if (!(*freebits)) {
++ ++(*dest);
++ *freebits = 7;
++ **dest = 0x01;
++ }
++ else {
++ --(*freebits);
++ (**dest) <<= 1;
++ (**dest) |= 0x01;
++ }
++ if ((*dest == end) && !(*freebits)) {
++ return EC_BUFFER_OVERFLOW;
++ }
++ }
++ return 0;
++}
++
++static int writebits1(unsigned char **dest, u8 * freebits, u32 * opposite, unsigned char *end)
++{
++ if (!(*freebits)) {
++ ++(*dest);
++ *freebits = 7;
++ **dest = 0x01;
++ }
++ else {
++ --(*freebits);
++ (**dest) <<= 1;
++ (**dest) |= 0x01;
++ }
++ if ((*dest == end) && !(*freebits)) {
++ return EC_BUFFER_OVERFLOW;
++ }
++ while (*opposite) {
++ --(*opposite);
++ if (!(*freebits)) {
++ ++(*dest);
++ *freebits = 7;
++ **dest = 0x00;
++ }
++ else {
++ --(*freebits);
++ (**dest) <<= 1;
++ }
++ if ((*dest == end) && !(*freebits)) {
++ return EC_BUFFER_OVERFLOW;
++ }
++ }
++ return 0;
++}
++
++
++
++
++/* Compress block
++ * *dstlen bytes are allocated.
++ * if it is not enough write *sourcelen over to the processed amount of data
++ * returns non zero if fails
++ */
++static int ipack_armlib_compress(void *model, unsigned char *input, unsigned char *output, unsigned long *sourcelen, unsigned long *dstlen)
++{
++ register u32 coder_high = CODER_VALUEMAX - 1;
++ register u32 coder_low = 0;
++ u32 coder_opbits = 0;
++ u8 bitvector_freebits = 8;
++ unsigned char *bitvector_ptr = output;
++ unsigned char *bitvector_end = output + (*dstlen - 1);
++ ARM_DataType *tmpp;
++ TokenStream tmpv;
++ TokenType *it;
++ void *end_it;
++
++ ipack_nodetype *treeroot = ((ipack_model_type *) model)->tree_root_ptr;
++ PredictorType *predctrs = ((ipack_model_type *) model)->predictors_ptr;
++
++#ifdef IPACK_TREE_TO_CODE
++ void (*treefunc) (ipack_nodetype *, TokenType, ipack_probability_type *);
++
++ treefunc = ((ipack_model_type *) model)->tree_code;
++ if (treefunc != NULL)
++ treefunc += 4;
++#endif
++
++ if ((*sourcelen % 4) != 0) {
++ return EC_WRONG_INPUT_LENGTH;
++ }
++ if (*dstlen <= 4) {
++ return EC_BUFFER_OVERFLOW;
++ }
++
++ if (((ipack_model_type *) model)->ID[0] != 'i') {
++ return EC_NOT_IPMF_MODEL;
++ }
++ else if (((ipack_model_type *) model)->ID[1] != 'P') {
++ return EC_NOT_IPMF_MODEL;
++ }
++ else if (((ipack_model_type *) model)->ID[2] != 'M') {
++ return EC_NOT_IPMF_MODEL;
++ }
++ else if (((ipack_model_type *) model)->ID[3] != 'F') {
++ return EC_NOT_IPMF_MODEL;
++ }
++#ifdef TXT_TOKENS
++ tmpv.capacity = (*sourcelen);
++#else
++ tmpv.capacity = (*sourcelen) << 1;
++#endif
++ tmpv.size = tmpv.capacity;
++ tmpv.ptr = jffs2_bbc_malloc(tmpv.size);
++ it = tmpv.ptr;
++
++#ifndef __KERNEL__
++ if (ipack_glb_endian_X) {
++ for (tmpp = (void *) input; (u32) tmpp < (u32) (input + *sourcelen); ++tmpp) {
++#ifdef TXT_TOKENS
++ *(it++) = (u8) ((*tmpp & 0xff000000) >> 24);
++ *(it++) = (u8) ((*tmpp & 0x00ff0000) >> 16);
++ *(it++) = (u8) ((*tmpp & 0x0000ff00) >> 8);
++ *(it++) = (u8) ((*tmpp & 0x000000ff));
++#else
++ *(it++) = (u8) ((*tmpp & 0x0000f000) >> 12);
++ *(it++) = (u8) ((*tmpp & 0x0000000f));
++ *(it++) = (u8) ((*tmpp & 0xf0000000) >> 28);
++ *(it++) = (u8) ((*tmpp & 0x000f0000) >> 16);
++ *(it++) = (u8) ((*tmpp & 0x00000f00) >> 8);
++ *(it++) = (u8) ((*tmpp & 0x00f00000) >> 20);
++ *(it++) = (u8) ((*tmpp & 0x0f000000) >> 24);
++ *(it++) = (u8) ((*tmpp & 0x000000f0) >> 4);
++#endif //TXT_TOKENS
++ }
++ }
++ else {
++#endif
++ for (tmpp = (void *) input; (u32) tmpp < (u32) (input + *sourcelen); ++tmpp) {
++#ifdef TXT_TOKENS
++ *(it++) = (u8) ((*tmpp & 0x000000ff));
++ *(it++) = (u8) ((*tmpp & 0x0000ff00) >> 8);
++ *(it++) = (u8) ((*tmpp & 0x00ff0000) >> 16);
++ *(it++) = (u8) ((*tmpp & 0xff000000) >> 24);
++#else
++ *(it++) = (u8) ((*tmpp & 0x00f00000) >> 20);
++ *(it++) = (u8) ((*tmpp & 0x0f000000) >> 24);
++ *(it++) = (u8) ((*tmpp & 0x000000f0) >> 4);
++ *(it++) = (u8) ((*tmpp & 0x00000f00) >> 8);
++ *(it++) = (u8) ((*tmpp & 0x000f0000) >> 16);
++ *(it++) = (u8) ((*tmpp & 0x0000f000) >> 12);
++ *(it++) = (u8) ((*tmpp & 0x0000000f));
++ *(it++) = (u8) ((*tmpp & 0xf0000000) >> 28);
++#endif //TXT_TOKENS
++ }
++#ifndef __KERNEL__
++ }
++#endif
++/*
++ ENCODE
++*/
++ { //predictor reset
++ register PredictorType *ptr = predctrs;
++ register PredictorType *end = ptr + NUMBER_OF_PREDICTORS;
++ while (ptr < end) {
++ *(ptr++) = 0;
++ }
++ }
++
++ //*(bitvector_ptr++) = 'H';
++ //*(bitvector_ptr++) = 'G';
++ *(bitvector_ptr++) = ((ipack_model_type *) model)->block_sign[0];
++ *(bitvector_ptr++) = ((ipack_model_type *) model)->block_sign[1];
++
++ *(bitvector_ptr++) = (unsigned char) (((*sourcelen) >> 8) & 0xff);
++ *(bitvector_ptr++) = (unsigned char) ((*sourcelen) & 0xff);
++ for (it = tmpv.ptr, end_it = VECTOR_S_END(tmpv); it != end_it; ++it) {
++ ipack_probability_type prob;
++ u32 range;
++
++#ifdef IPACK_TREE_TO_CODE
++ if (treefunc != NULL)
++ (*treefunc) (treeroot, *it, &prob);
++ else
++ ipack_model_get_probability_for_token(treeroot, *it, &prob);
++#else
++ ipack_model_get_probability_for_token(treeroot, *it, &prob);
++#endif
++
++ if (prob.high == prob.low) {
++ vector_clear(&tmpv);
++ return EC_CODER_WRONG_PROBABILITY;
++ }
++ range = coder_high - coder_low + 1;
++ coder_high = coder_low + ((range * prob.high) >> PROBABILITY_SHIFT) - 1;
++ coder_low += ((range * prob.low) >> PROBABILITY_SHIFT);
++ for (;;) {
++ if (coder_high < CODER_VALUEHLF) {
++ if (writebits0(&bitvector_ptr, &bitvector_freebits, &coder_opbits, bitvector_end)) {
++ vector_clear(&tmpv);
++ return EC_BUFFER_OVERFLOW;
++ }
++ }
++ else if (coder_low >= CODER_VALUEHLF) {
++ if (writebits1(&bitvector_ptr, &bitvector_freebits, &coder_opbits, bitvector_end)) {
++ vector_clear(&tmpv);
++ return EC_BUFFER_OVERFLOW;
++ }
++ coder_high -= CODER_VALUEHLF;
++ coder_low -= CODER_VALUEHLF;
++ }
++ else if ((CODER_VALUE1ST <= coder_low) && (coder_high < CODER_VALUE3RD)) {
++ ++coder_opbits;
++ coder_high -= CODER_VALUE1ST;
++ coder_low -= CODER_VALUE1ST;
++ }
++ else {
++ break;
++ }
++ coder_high <<= 1;
++ ++coder_high;
++ coder_low <<= 1;
++ if (coder_high < coder_low) {
++ vector_clear(&tmpv);
++ return EC_CODER_WRONG_RANGE;
++ }
++ }
++ {
++#ifdef TXT_TOKENS
++// register u32 ndx;
++ predctrs[0] = *it;
++ if ((('a' <= *it) && (*it <= 'z')) || (('A' <= *it) && (*it <= 'Z'))) {
++ ++(predctrs[1]);
++ }
++ else {
++ predctrs[1] = 0;
++ }
++#else
++ register u32 ndx = predctrs[0] + 1;
++ predctrs[ndx + 8] = predctrs[ndx];
++ predctrs[ndx] = *it;
++ if (ndx == 8) {
++ predctrs[0] = 0;
++ }
++ else {
++ ++predctrs[0];
++ }
++#endif
++ }
++
++ }
++ vector_clear(&tmpv);
++ ++coder_opbits;
++ if (coder_low < CODER_VALUE1ST) {
++ if (writebits0(&bitvector_ptr, &bitvector_freebits, &coder_opbits, bitvector_end)) {
++ return EC_BUFFER_OVERFLOW;
++ }
++ }
++ else {
++ if (writebits1(&bitvector_ptr, &bitvector_freebits, &coder_opbits, bitvector_end)) {
++ return EC_BUFFER_OVERFLOW;
++ }
++ }
++ (*(bitvector_ptr)) <<= bitvector_freebits;
++ *dstlen = ((u32) bitvector_ptr - (u32) output + 1);
++ return EC_NO_ERROR;
++}
++
++/*******************************************************************************
++
++ DECOMPRESS FUNCTIONS
++
++*******************************************************************************/
++
++typedef struct
++{
++ u32 high;
++ u32 low;
++ u32 value;
++ u32 overread;
++} ipack_decompressor_values;
++
++typedef struct
++{
++ u8 freebits;
++ unsigned char *ptr;
++ unsigned char *end;
++} ipack_decompressor_bitvector;
++
++static u8 ipack_bitvector_R_get1(ipack_decompressor_bitvector * bv)
++{
++ u8 tmp;
++ if (bv->ptr == bv->end) {
++ bv->freebits = 0;
++ return 0;
++ }
++ tmp = (*(bv->ptr) >> bv->freebits) & 0x01;
++ if (!(bv->freebits)) {
++ bv->freebits = 7;
++ ++(bv->ptr);
++ }
++ else {
++ --(bv->freebits);
++ }
++ return tmp;
++}
++
++/* Decompress block
++ * returns non zero if fails
++ */
++static int ipack_armlib_decompress(void *model, unsigned char *input, unsigned char *output, unsigned long sourcelen, unsigned long dstlen)
++{
++ ARM_DataType *data;
++ register u32 coder_high = CODER_VALUEMAX - 1;
++ register u32 coder_low = 0;
++ register u32 coder_value = 0;
++ u32 coder_overread = 0;
++ ipack_decompressor_bitvector bitvector;
++ u32 lngth;
++ u32 i;
++ u32 cntbytes;
++ TokenType tkns[8];
++ TokenType *tptr;
++
++ ipack_nodetype *treeroot = ((ipack_model_type *) model)->tree_root_ptr;
++ PredictorType *predctrs = ((ipack_model_type *) model)->predictors_ptr;
++
++#ifdef IPACK_TREE_TO_CODE
++ TokenType(*treefunc) (ipack_nodetype *, u32, u32, ipack_probability_type *);
++
++ treefunc = ((ipack_model_type *) model)->tree_code;
++#endif
++
++
++ if (((ipack_model_type *) model)->ID[0] != 'i') {
++ return EC_NOT_IPMF_MODEL;
++ }
++ else if (((ipack_model_type *) model)->ID[1] != 'P') {
++ return EC_NOT_IPMF_MODEL;
++ }
++ else if (((ipack_model_type *) model)->ID[2] != 'M') {
++ return EC_NOT_IPMF_MODEL;
++ }
++ else if (((ipack_model_type *) model)->ID[3] != 'F') {
++ return EC_NOT_IPMF_MODEL;
++ }
++
++ bitvector.freebits = 7;
++ bitvector.ptr = input;
++ bitvector.end = input + sourcelen;
++
++ /*if(*(bitvector.ptr++) != 'H') {
++ return EC_NOT_HG_BLOCK;
++ } else if(*(bitvector.ptr++) != 'G') {
++ return EC_NOT_HG_BLOCK;
++ } */
++ bitvector.ptr++;
++ bitvector.ptr++;
++
++ data = (void *) output;
++ cntbytes = *(bitvector.ptr++);
++ cntbytes <<= 8;
++ cntbytes += *(bitvector.ptr++);
++
++ { //predictor reset
++ register PredictorType *ptr = predctrs;
++ register PredictorType *end = ptr + NUMBER_OF_PREDICTORS;
++ while (ptr < end) {
++ *(ptr++) = 0;
++ }
++ }
++ for (i = 0; i < CODER_VALUEBITS; ++i) {
++ coder_value <<= 1;
++ coder_value += ipack_bitvector_R_get1(&bitvector);
++ }
++ lngth = dstlen >> 2;
++ if (lngth > (cntbytes >> 2)) {
++ lngth = cntbytes >> 2;
++ }
++ for (i = 0; (i < lngth); ++i) {
++ TokenType itoken;
++ u32 j;
++ tptr = tkns;
++ for (j = 0; j < NUMBER_OF_TOKENS_PER_INSTRUCTION; ++j) {
++ ipack_probability_type prob;
++ u32 range = coder_high - coder_low + 1;
++
++#ifdef IPACK_TREE_TO_CODE
++ if (treefunc != NULL)
++ itoken = (*treefunc) (treeroot, coder_value - coder_low + 1, range, &prob);
++ else
++#endif
++ itoken = ipack_model_get_token_for_range(treeroot, coder_value - coder_low + 1, range, &prob);
++
++
++ if (prob.high == prob.low) {
++ return EC_CODER_WRONG_PROBABILITY;
++ }
++ coder_high = coder_low + ((range * prob.high) >> PROBABILITY_SHIFT) - 1;
++ coder_low += ((range * prob.low) >> PROBABILITY_SHIFT);
++ for (;;) {
++ if (coder_high < CODER_VALUEHLF) {
++ }
++ else if (CODER_VALUEHLF <= coder_low) {
++ coder_value -= CODER_VALUEHLF;
++ coder_high -= CODER_VALUEHLF;
++ coder_low -= CODER_VALUEHLF;
++ }
++ else if ((CODER_VALUE1ST <= coder_low) && (coder_high < CODER_VALUE3RD)) {
++ coder_value -= CODER_VALUE1ST;
++ coder_high -= CODER_VALUE1ST;
++ coder_low -= CODER_VALUE1ST;
++ }
++ else {
++ break;
++ }
++ coder_low <<= 1;
++ coder_high <<= 1;
++ ++(coder_high);
++ coder_value <<= 1;
++ if (bitvector.ptr == bitvector.end) {
++ bitvector.freebits = 0;
++ }
++ coder_value += ((*(bitvector.ptr) >> bitvector.freebits) & 0x01);
++ if (bitvector.freebits) {
++ --bitvector.freebits;
++ }
++ else {
++ bitvector.freebits = 7;
++ ++bitvector.ptr;
++ }
++ if (coder_high < coder_low) {
++ return EC_CODER_WRONG_RANGE;
++ }
++ if ((bitvector.ptr == bitvector.end) && !(bitvector.freebits)) {
++ if ((coder_overread++) > CODER_VALUEBITS) {
++ return EC_BUFFER_UNDERFLOW;
++ }
++ }
++ }
++ {
++#ifdef TXT_TOKENS
++// register u32 ndx;
++ predctrs[0] = itoken;
++ if ((('a' <= itoken) && (itoken <= 'z')) || (('A' <= itoken) && (itoken <= 'Z'))) {
++ ++(predctrs[1]);
++ }
++ else {
++ predctrs[1] = 0;
++ }
++
++#else
++ register u32 ndx = predctrs[0] + 1;
++ predctrs[ndx + 8] = predctrs[ndx];
++ predctrs[ndx] = itoken;
++ if (ndx == 8) {
++ predctrs[0] = 0;
++ }
++ else {
++ ++predctrs[0];
++ }
++#endif
++ }
++
++ (*(tptr++)) = itoken;
++ }
++ tptr = tkns;
++#ifndef __KERNEL__
++ if (ipack_glb_endian_X) {
++#ifdef TXT_TOKENS
++ (*data) = ((*tptr) << 24);
++ ++tptr;
++ (*data) |= ((*tptr) << 16);
++ ++tptr;
++ (*data) |= ((*tptr) << 8);
++ ++tptr;
++ (*data) |= (*tptr);
++ ++data;
++#else
++ (*data) = (((*tptr) & 0xf) << 12);
++ ++tptr;
++ (*data) |= ((*tptr) & 0xf);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 28);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 16);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 8);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 20);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 24);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 4);
++ ++data;
++#endif
++ }
++ else {
++#endif
++#ifdef TXT_TOKENS
++ (*data) = (*tptr);
++ ++tptr;
++ (*data) |= ((*tptr) << 8);
++ ++tptr;
++ (*data) |= ((*tptr) << 16);
++ ++tptr;
++ (*data) |= ((*tptr) << 24);
++ ++data;
++#else
++ (*data) = (((*tptr) & 0xf) << 20);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 24);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 4);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 8);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 16);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 12);
++ ++tptr;
++ (*data) |= ((*tptr) & 0xf);
++ ++tptr;
++ (*data) |= (((*tptr) & 0xf) << 28);
++ ++data;
++#endif
++#ifndef __KERNEL__
++ }
++#endif
++ }
++ return EC_NO_ERROR;
++}
++
++static int ipack_armlib_estimate(void *model, unsigned char *input, unsigned long sourcelen, unsigned long *dstlen, unsigned long *readtime, unsigned long *writetime)
++{
++ int i, tmp, tmp2, max, maxi;
++ int cnt_cond[] = { 0, 0, 0, 0 };
++ int cnt_inst[] = { 0, 0, 0, 0 };
++
++ // TODO: make a more precise estimation!!!
++ *readtime = JFFS2_BBC_ZLIB_READ_TIME * 6;
++ *writetime = JFFS2_BBC_ZLIB_WRITE_TIME * 2;
++
++ if (sourcelen % 4 != 0) {
++ *dstlen = sourcelen;
++ return 0;
++ }
++ for (i = 0; i < sourcelen; i++, input++) {
++ tmp2 = tmp = *input;
++ tmp = ((tmp) & 0xf0) >> 4;
++ tmp2 = tmp2 & 0xf;
++ if (tmp == 14)
++ cnt_cond[i % 4]++;
++ if ((tmp2 == 2) || (tmp2 == 3))
++ cnt_inst[i % 4]++;
++ }
++ maxi = -1;
++ max = -1;
++ for (i = 0; i < 4; i++)
++ if (max < cnt_cond[i]) {
++ max = cnt_cond[i];
++ maxi = i;
++ }
++ /*jffs2_bbc_print("armlib_EST: %d/%d : %d/%d %d/%d %d/%d %d/%d",
++ cnt_cond[maxi],cnt_inst[maxi],
++ cnt_cond[0],cnt_inst[0],
++ cnt_cond[1],cnt_inst[1],
++ cnt_cond[2],cnt_inst[2],
++ cnt_cond[3],cnt_inst[3]); */
++
++ if (cnt_cond[maxi] < (sourcelen >> 4)) {
++ *dstlen = sourcelen;
++ }
++ else {
++ *dstlen = sourcelen / 3;
++ }
++
++ return 0;
++}
++
++static char *ipack_armlib_proc_info(void);
++static int ipack_armlib_proc_command(char *command);
++static void ipack_armlib_destroy_model(void **model);
++
++struct jffs2_bbc_compressor_type jffs2_bbc_armlib = {
++ "armlib",
++ 0x464d5069,
++ {0, 0, 0, 0},
++ NULL, // init
++ ipack_armlib_compressor_init, // init_model
++ ipack_armlib_destroy_model, // destroy_model
++ ipack_armlib_compressor_deinit, // deinit
++ ipack_armlib_compress,
++ ipack_armlib_estimate,
++ ipack_armlib_decompress,
++ ipack_armlib_proc_info,
++ ipack_armlib_proc_command
++};
++
++
++static char *ipack_armlib_proc_info()
++{
++#ifdef IPACK_TREE_TO_CODE
++#ifdef IPACK_AUTO_TREE_TO_CODE
++ return "automatic tree to code conversion";
++#else
++ return "manual tree to code conversion possibility";
++#endif
++#else
++ return "tree in memory version";
++#endif
++}
++
++static int ipack_armlib_proc_command(char *command)
++{
++ struct jffs2_bbc_model_list_node *model;
++ ipack_model_type *armlib_model;
++
++ if ((*command == 'g') || (*command == 'G')) {
++ jffs2_bbc_print1("Converting tree(s) to ARM code... (keeping original)\n");
++ model = jffs2_bbc_armlib.models;
++ if (model == NULL)
++ jffs2_bbc_print1("no model found!\n");
++ while (model != NULL) {
++ armlib_model = model->model;
++ if (armlib_model == NULL) {
++ jffs2_bbc_print1("Error: NULL model!\n");
++ }
++ else {
++ ipack_armlib_convert_tree_to_code(armlib_model, IPACK_TREE_CONVERT_KEEP);
++ }
++ model = model->next_compr_model;
++ }
++ }
++ else if ((*command == 'r') || (*command == 'R')) {
++ jffs2_bbc_print1("Converting tree(s) to ARM code... (deleting original)\n");
++ model = jffs2_bbc_armlib.models;
++ if (model == NULL)
++ jffs2_bbc_print1("no model found!\n");
++ while (model != NULL) {
++ armlib_model = model->model;
++ if (armlib_model == NULL) {
++ jffs2_bbc_print1("Error: NULL model!\n");
++ }
++ else {
++ //armlib_model->tree_code = ipack_tree_to_code(armlib_model, &tree_size);
++ //jffs2_bbc_print("Convertation done. Code size=%d\n",tree_size);
++ ipack_armlib_convert_tree_to_code(armlib_model, IPACK_TREE_CONVERT_REPLACE);
++ }
++ model = model->next_compr_model;
++ }
++ }
++ else if ((*command == 'c') || (*command == 'C')) {
++ jffs2_bbc_print1("Deleting ARM representation of the tree(s)...\n");
++ model = jffs2_bbc_armlib.models;
++ if (model == NULL)
++ jffs2_bbc_print1("no model found!\n");
++ while (model != NULL) {
++ armlib_model = model->model;
++ if (armlib_model == NULL) {
++ jffs2_bbc_print1("Error: NULL model!\n");
++ }
++ else {
++ if (armlib_model->tree_code == NULL) {
++ jffs2_bbc_print1("already deleted.\n");
++ }
++ else {
++ if (armlib_model->tree_root_ptr == NULL) {
++ jffs2_bbc_print1("cannot delete this ARM tree - original tree has deleted\n");
++ }
++ else {
++ jffs2_bbc_print1("deleting...");
++ jffs2_bbc_free(armlib_model->tree_code);
++ armlib_model->tree_code = NULL;
++ jffs2_bbc_print1("done.\n");
++ }
++ }
++ }
++ model = model->next_compr_model;
++ }
++ }
++ else if (*command == '?') {
++ jffs2_bbc_print1("ARMLIB commands:\n");
++ jffs2_bbc_print1(" g: convert TREEs to ARM code and keep the original\n");
++ jffs2_bbc_print1(" r: convert TREEs to ARM code and remove the original\n");
++ jffs2_bbc_print1(" c: delete the original TREEs - if there is any\n");
++ }
++ else {
++ jffs2_bbc_print1("Unknown command.\n");
++ }
++ return 0;
++}
++
++static void ipack_armlib_destroy_model(void **model)
++{
++ ipack_model_type *model_img;
++
++ model_img = *model;
++ if (model_img == NULL) {
++ jffs2_bbc_print1("jffs2.bbc: armlib: NULL model at destoying model!\n");
++ return;
++ }
++ if (model_img->tree_code != NULL) {
++ //jffs2_bbc_print1("jffs2.bbc: armlib: debug: freeing code...\n");
++ jffs2_bbc_free(model_img->tree_code);
++ model_img->tree_code = NULL;
++ }
++ if (model_img->tree_root_ptr != NULL) {
++ //jffs2_bbc_print1("jffs2.bbc: armlib: debug: freeing tree...\n");
++ jffs2_bbc_free(model_img->tree_root_ptr);
++ model_img->tree_root_ptr = NULL;
++ }
++
++ jffs2_bbc_free(model_img);
++ *model = NULL;
++}
++
++struct jffs2_bbc_compressor_type *jffs2_bbc_armlib_init(int mode)
++{
++ if (jffs2_bbc_register_compressor(&jffs2_bbc_armlib) == 0)
++ return &jffs2_bbc_armlib;
++ else
++ return NULL;
++}
++
++void jffs2_bbc_armlib_deinit(void)
++{
++ jffs2_bbc_unregister_compressor(&jffs2_bbc_armlib);
++}
++
++/*END OF ARMLIB*/
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_framework.c linux-mips/fs/jffs2/jffs2_bbc_framework.c
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_framework.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_framework.c 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,1324 @@
++/*
++ * JFFS2-BBC: Compression Framework
++ *
++ * $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++ *
++ * Copyright (C) 2004, Ferenc Havasi
++ *
++ * 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.
++ *
++ */
++
++/* USE JFFS2_BBC_STANDALONE define if you don't want to compile without JFFS2 */
++
++//#define DEBUG_COMPRESSORS
++//#define DEBUG_SHOW_BLOCK_SIZES
++
++#define JFFS2_BBC_STAT_BUFF_SIZE 8000
++
++#ifndef __KERNEL__
++
++#include <stdio.h>
++#include <malloc.h>
++typedef unsigned long uint32_t;
++
++#else
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++
++#endif
++
++#define JFFS2_BBC_ZLIB_BLOCK_SIGN_0 (120)
++#define JFFS2_BBC_ZLIB_BLOCK_SIGN_1 (94)
++
++#define JFFS2_BBC_DUMMY_BLOCKSIGN_0 (0x54)
++#define JFFS2_BBC_DUMMY_BLOCKSIGN_1 (0x01)
++
++#ifndef NULL
++#define NULL ((void*)(0))
++#endif
++
++#include "jffs2_bbc_framework.h"
++
++/*********************************************************************
++ * Global data *
++ *********************************************************************/
++
++static int jffs2_bbc_compression_mode = JFFS2_BBC_ZLIB_MODE;
++static struct jffs2_bbc_compressor_type *jffs2_bbc_manual_compressor = NULL;
++static struct jffs2_bbc_compressor_type *jffs2_bbc_compressors = NULL;
++static struct jffs2_bbc_model_list_node *jffs2_bbc_model_list = NULL;
++static void *last_sb = NULL; /* previously activated sb */
++
++/*********************************************************************
++ * Compressor initialization *
++ *********************************************************************/
++
++#ifndef JFFS2_BBC_STANDALONE
++
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_ARMLIB)
++struct jffs2_bbc_compressor_type *jffs2_bbc_armlib_init(void);
++void jffs2_bbc_armlib_deinit(void);
++#endif
++
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZO)
++struct jffs2_bbc_compressor_type *jffs2_bbc_lzo_init(void);
++void jffs2_bbc_lzo_deinit(void);
++#endif
++
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZSS)
++struct jffs2_bbc_compressor_type *jffs2_bbc_lzss_init(void);
++void jffs2_bbc_lzss_deinit(void);
++#endif
++
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZARI)
++struct jffs2_bbc_compressor_type *jffs2_bbc_lzari_init(void);
++void jffs2_bbc_lzari_deinit(void);
++#endif
++
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZHD)
++struct jffs2_bbc_compressor_type *jffs2_bbc_lzhd_init(void);
++void jffs2_bbc_lzhd_deinit(void);
++#endif
++
++void jffs2_bbc_compressor_init()
++{
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_ARMLIB)
++ jffs2_bbc_armlib_init();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZO)
++ jffs2_bbc_lzo_init();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZSS)
++ jffs2_bbc_lzss_init();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZARI)
++ jffs2_bbc_lzari_init();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZHD)
++ jffs2_bbc_lzhd_init();
++#endif
++}
++
++void jffs2_bbc_compressor_deinit()
++{
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZHD)
++ jffs2_bbc_lzhd_deinit();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZARI)
++ jffs2_bbc_lzari_deinit();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZSS)
++ jffs2_bbc_lzss_deinit();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_LZO)
++ jffs2_bbc_lzo_deinit();
++#endif
++#if !defined(__KERNEL__) || defined(CONFIG_JFFS2_BBC_ARMLIB)
++ jffs2_bbc_armlib_deinit();
++#endif
++}
++
++#endif
++
++#ifndef JFFS2_BBC_STANDALONE
++
++/*********************************************************************
++ * ZLIB COMPRESSOR *
++ *********************************************************************/
++
++extern int jffs2_zlib_compress2(unsigned char *data_in, unsigned char *cpage_out, uint32_t * sourcelen, uint32_t * dstlen);
++extern void jffs2_zlib_decompress2(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
++
++static int jffs2_bbc_zlib_compress(void *model, unsigned char *input, unsigned char *output, unsigned long *sourcelen, unsigned long *dstlen)
++{
++ return jffs2_zlib_compress2(input, output, sourcelen, dstlen);
++}
++
++static int jffs2_bbc_zlib_decompress(void *model, unsigned char *input, unsigned char *output, unsigned long sourcelen, unsigned long dstlen)
++{
++ jffs2_zlib_decompress2(input, output, sourcelen, dstlen);
++ return 0;
++}
++
++static int jffs2_bbc_zlib_estimate(void *model, unsigned char *input, unsigned long sourcelen, unsigned long *dstlen, unsigned long *readtime, unsigned long *writetime)
++{
++ *dstlen = sourcelen * 65 / 100;
++ *readtime = JFFS2_BBC_ZLIB_READ_TIME;
++ *writetime = JFFS2_BBC_ZLIB_WRITE_TIME;
++ return 0;
++}
++
++static struct jffs2_bbc_compressor_type jffs2_bbc_zlib = {
++ "zlib",
++ 0,
++ {JFFS2_BBC_ZLIB_BLOCK_SIGN_0, JFFS2_BBC_ZLIB_BLOCK_SIGN_1, 0, 0},
++ NULL,
++ NULL,
++ NULL,
++ NULL,
++ jffs2_bbc_zlib_compress,
++ jffs2_bbc_zlib_estimate,
++ jffs2_bbc_zlib_decompress,
++ NULL,
++ NULL,
++ 1
++};
++
++static struct jffs2_bbc_compressor_type *jffs2_bbc_original_compressor = &jffs2_bbc_zlib;
++
++#endif
++
++/*********************************************************************
++ * Compression mode handling *
++ *********************************************************************/
++
++int jffs2_bbc_get_compression_mode(void)
++{
++ return jffs2_bbc_compression_mode;
++}
++
++void jffs2_bbc_set_compression_mode(int mode)
++{
++ jffs2_bbc_compression_mode = mode;
++}
++
++void jffs2_bbc_set_manual_compressor(struct jffs2_bbc_compressor_type *c)
++{
++ jffs2_bbc_manual_compressor = c;
++ jffs2_bbc_set_compression_mode(JFFS2_BBC_MANUAL_MODE);
++}
++
++int jffs2_bbc_set_manual_compressor_by_name(char *name)
++{
++ struct jffs2_bbc_compressor_type *l;
++ int i;
++
++ l = jffs2_bbc_compressors;
++ while (l != NULL) {
++ for (i = 0; i < 1000; i++) {
++ if (l->name[i] == 0) {
++ jffs2_bbc_set_manual_compressor(l);
++ return 0;
++ }
++ else if (name[i] == 0)
++ i = 1000;
++ else if (name[i] != l->name[i])
++ i = 1000;
++ }
++ l = l->next;
++ }
++ jffs2_bbc_set_manual_compressor(NULL);
++ return 1;
++}
++
++static struct jffs2_bbc_compressor_type *jffs2_bbc_get_compressor_by_name(char *name)
++{
++ struct jffs2_bbc_compressor_type *l;
++ int i;
++
++#ifndef JFFS2_BBC_STANDALONE
++ l = jffs2_bbc_original_compressor;
++ for (i = 0; i < 1000; i++) {
++ if (l->name[i] == 0) {
++ return l;
++ }
++ else if (name[i] == 0)
++ i = 1000;
++ else if (name[i] != l->name[i])
++ i = 1000;
++ }
++#endif
++
++ l = jffs2_bbc_compressors;
++ while (l != NULL) {
++ for (i = 0; i < 1000; i++) {
++ if (l->name[i] == 0) {
++ return l;
++ }
++ else if (name[i] == 0)
++ i = 1000;
++ else if (name[i] != l->name[i])
++ i = 1000;
++ }
++ l = l->next;
++ }
++
++ return NULL;
++}
++
++int jffs2_bbc_disable_compressor_by_name(char *name)
++{
++ struct jffs2_bbc_compressor_type *l;
++
++ l = jffs2_bbc_get_compressor_by_name(name);
++ if (l == NULL) return 1;
++ l->enabled = 0;
++ return 0;
++}
++
++int jffs2_bbc_enable_compressor_by_name(char *name)
++{
++ struct jffs2_bbc_compressor_type *l;
++
++ l = jffs2_bbc_get_compressor_by_name(name);
++ if (l == NULL) return 1;
++ l->enabled = 1;
++ return 0;
++}
++
++void jffs2_bbc_compressor_command_by_name(char *name_and_command)
++{
++ struct jffs2_bbc_compressor_type *l;
++ int i;
++
++ l = jffs2_bbc_compressors;
++ while (l != NULL) {
++ for (i = 0; i < 1000; i++) {
++ if (l->name[i] == 0) {
++ if (name_and_command[i] != ':') {
++ jffs2_bbc_print1("jffs2.bbc: ':' missing after compressor name\n");
++ }
++ else {
++ if (l->proc_command != NULL)
++ l->proc_command(name_and_command + i + 1);
++ }
++ i = 1000;
++ return;
++ }
++ else if (name_and_command[i] == 0) {
++ i = 1000;
++ }
++ else if (name_and_command[i] != l->name[i]) {
++ i = 1000;
++ }
++ }
++ l = l->next;
++ }
++}
++
++struct jffs2_bbc_compressor_type *jffs2_bbc_get_manual_compressor(void)
++{
++ if (jffs2_bbc_get_compression_mode() != JFFS2_BBC_MANUAL_MODE) {
++ jffs2_bbc_manual_compressor = NULL;
++ }
++ return jffs2_bbc_manual_compressor;
++}
++
++/*********************************************************************
++ * Compressor handling *
++ *********************************************************************/
++
++struct jffs2_bbc_compressor_type *jffs2_bbc_get_compressor_list(void)
++{
++ return jffs2_bbc_compressors;
++}
++
++struct jffs2_bbc_model_list_node *jffs2_bbc_get_model_list(void)
++{
++ return jffs2_bbc_model_list;
++}
++
++int jffs2_bbc_register_compressor(struct jffs2_bbc_compressor_type *c)
++{
++ struct jffs2_bbc_compressor_type *l;
++ struct jffs2_bbc_model_list_node *l2;
++ int model_found = 0;
++
++ l = jffs2_bbc_compressors;
++ /* Check for confilcts */
++ while (l != NULL) {
++ c->name[15] = 0;
++ /*if (strcmp(c->name,l->name)==0) {
++ jffs2_bbc_print1("jffs2.bbc: compressor is already loaded.");
++ return -1;
++ } */
++ if ((l->model_file_sign == c->model_file_sign) && (c->model_file_sign != 0)) {
++ jffs2_bbc_print1("jffs2.bbc: already used model file sign. fail.");
++ return -1;
++ }
++ l = l->next;
++ }
++ /* Search and initialize model */
++ c->models = NULL;
++ c->mounted = 0;
++ if (c->init != NULL) {
++ if (c->init() != 0) {
++ jffs2_bbc_print2("jffs2.bbc: cannot initialize compressor %s.\n", c->name);
++ return -1;
++ }
++ }
++ if (c->model_file_sign != 0) {
++ l2 = jffs2_bbc_model_list;
++ while (1) {
++ if (l2 == NULL)
++ break;
++ if (c->model_file_sign == l2->sign) {
++ if (l2->compressor != NULL) {
++ jffs2_bbc_print2("jffs2.bbc: register for %s: BUG, model file already reserved!!!!\n", c->name);
++ }
++ else {
++ if (c->init_model(&(l2->model)) != 0) {
++ jffs2_bbc_print2("jffs2.bbc: cannot initialize compressor %s for a model", c->name);
++ }
++ else {
++ l2->compressor = c;
++ l2->next_compr_model = c->models;
++ c->models = l2;
++ c->mounted++;
++ model_found++;
++ }
++ }
++ }
++ l2 = l2->next_model;
++ }
++ /*if (model_found==0) {
++ jffs2_bbc_print2("jffs2.bbc: no macthing model file found for %s at this time (maybe later)\n",c->name);
++ } */
++ }
++ /* Insert to the end of the compressor list */
++ c->enabled = 1;
++ c->buffer = NULL;
++ c->buffer_size = 0;
++ c->stat_compr_orig = c->stat_compr_new = c->stat_decompr = 0;
++ c->next = NULL;
++ if (jffs2_bbc_compressors == NULL) {
++ jffs2_bbc_compressors = c;
++ }
++ else {
++ l = jffs2_bbc_compressors;
++ while (l->next != NULL)
++ l = l->next;
++ l->next = c;
++ }
++ return 0;
++}
++
++int jffs2_bbc_unregister_compressor(struct jffs2_bbc_compressor_type *c)
++{
++ struct jffs2_bbc_compressor_type *l;
++ struct jffs2_bbc_model_list_node *l2;
++
++ if (c->mounted != 0) {
++ jffs2_bbc_print1("jffs2.bbc: Compressor is in use. Sorry.");
++ return -1;
++ }
++ if (jffs2_bbc_compressors == NULL) {
++ jffs2_bbc_print1("jffs2.bbc: unregister: empty list.");
++ return -1;
++ }
++ else if (jffs2_bbc_compressors == c) {
++ if (c->deinit != NULL)
++ c->deinit();
++ jffs2_bbc_compressors = c->next;
++ }
++ else {
++ l = jffs2_bbc_compressors;
++ while (l->next != c) {
++ if (l->next == NULL) {
++ jffs2_bbc_print2("jffs2.bbc: unregister: cannot find compressor %s in the list.", c->name);
++ return -1;
++ }
++ l = l->next;
++ }
++ if (c->deinit != NULL)
++ c->deinit();
++ l->next = c->next;
++ }
++ if (c->buffer != NULL) {
++ jffs2_bbc_free(c->buffer);
++ c->buffer = NULL;
++ c->buffer_size = 0;
++ }
++
++ l2 = jffs2_bbc_model_list;
++ while (l2 != NULL) {
++ if (l2->compressor == c) {
++ jffs2_bbc_print1("jffs2.bbc: unregister: BUG: model found!!!");
++ l2->compressor = NULL;
++ l2->next_compr_model = NULL;
++ }
++ l2 = l2->next_model;
++ }
++
++ return 0;
++}
++
++int jffs2_bbc_model_new(void *sb, int i_num, void *model)
++{
++ struct jffs2_bbc_model_list_node *node;
++ struct jffs2_bbc_compressor_type *l;
++ char block_sign[2];
++
++ int sign;
++
++ /* check for conflicts... */
++ sign = *((int *) model);
++ block_sign[0] = *(((char *) model) + 4);
++ block_sign[1] = *(((char *) model) + 5);
++ node = jffs2_bbc_model_list;
++ while (node != NULL) {
++ if ((node->block_sign[0] == block_sign[0]) && (node->block_sign[1] == block_sign[1]) && (node->sb == sb)) {
++ //jffs2_bbc_print2("jffs2.bbc: model_new: model conflict (inode=%d)!\n",i_num);
++ return -1;
++ }
++ node = node->next_model;
++ }
++
++ /* insertion */
++ node = jffs2_bbc_malloc_small((long)sizeof(struct jffs2_bbc_model_list_node));
++ node->sb = sb;
++ node->model = model;
++ node->sign = *((int *) model);
++ node->block_sign[0] = *(((char *) model) + 4);
++ node->block_sign[1] = *(((char *) model) + 5);
++ node->inode = i_num;
++ node->next_model = jffs2_bbc_model_list;
++ node->compressor = NULL;
++ node->stat_decompr = 0;
++ node->next_compr_model = NULL;
++ jffs2_bbc_model_list = node;
++
++ /* search for matching compressor */
++ l = jffs2_bbc_compressors;
++ while (l != NULL) {
++ if (l->model_file_sign == sign) {
++ //jffs2_bbc_print2("jffs2.bbc: compressor for model found: %s ",l->name);
++ if (l->init_model(&(node->model)) != 0) {
++ jffs2_bbc_print1("jffs2.bbc: cannot initialize compressor for a model");
++ }
++ else {
++ l->mounted++;
++ node->compressor = l;
++ node->next_compr_model = l->models;
++ l->models = node;
++ }
++ break;
++ }
++ l = l->next;
++ }
++ return 0;
++}
++
++static void jffs2_bbc_model_del_from_compressor(struct jffs2_bbc_model_list_node *node)
++{
++ struct jffs2_bbc_model_list_node *l;
++
++ if (node->model != NULL) {
++ if (node->compressor != NULL) {
++ if (node->compressor->destroy_model == NULL) {
++ jffs2_bbc_free(node->model);
++ node->model = NULL;
++ }
++ else {
++ node->compressor->destroy_model(&(node->model));
++ if (node->model != NULL)
++ jffs2_bbc_print1("jffs2.bbc: warning: not NULL model after destroying!\n");
++ }
++ }
++ }
++
++ if (node->compressor == NULL) {
++ jffs2_bbc_print1("jffs2.bbc: jffs2_bbc_model_del_from_compressor: no compressor!\n");
++ return;
++ }
++ l = node->compressor->models;
++ if (l == NULL) {
++ jffs2_bbc_print1("jffs2.bbc: jffs2_bbc_model_del_from_compressor error, models=NULL!\n");
++ return;
++ }
++ if (l == node) {
++ node->compressor->models = node->next_compr_model;
++ node->compressor->mounted--;
++ return;
++ }
++ while (1) {
++ if (l->next_compr_model == node) {
++ l->next_compr_model = node->next_compr_model;
++ node->compressor->mounted--;
++ return;
++ }
++ l = l->next_compr_model;
++ if (l == NULL) {
++ jffs2_bbc_print1("jffs2.bbc: jffs2_bbc_model_del_from_compressor: not found\n");
++ return;
++ }
++ }
++}
++
++void jffs2_bbc_model_del(void *sb)
++{
++ struct jffs2_bbc_model_list_node *l, *l2;
++
++ l = jffs2_bbc_model_list;
++ if (l == NULL)
++ return;
++ if (l->sb == sb) {
++ jffs2_bbc_model_list = l->next_model;
++ jffs2_bbc_model_del_from_compressor(l);
++ jffs2_bbc_free_small(l);
++ jffs2_bbc_model_del(sb);
++ return;
++ }
++ while (1) {
++ if (l->next_model == NULL) {
++ break;
++ }
++ if (l->next_model->sb == sb) {
++ l2 = l->next_model;
++ l->next_model = l->next_model->next_model;
++ jffs2_bbc_model_del_from_compressor(l2);
++ jffs2_bbc_free_small(l2);
++ jffs2_bbc_model_del(sb);
++ return;
++ }
++ l = l->next_model;
++ }
++ last_sb = NULL;
++}
++
++void jffs2_bbc_model_set_act_sb(void *sb)
++{
++ last_sb = sb;
++}
++
++void *jffs2_bbc_model_get_act_sb(void)
++{
++ return last_sb;
++}
++
++void *jffs2_bbc_model_get_newest(struct jffs2_bbc_compressor_type *compressor)
++{
++ struct jffs2_bbc_model_list_node *m, *best_m;
++ int max_sign, sign;
++
++ if (compressor == NULL) {
++ jffs2_bbc_print1("jffs2.bbc: jffs2_bbc_model_get: NULL!!\n");
++ return NULL;
++ }
++
++ best_m = NULL;
++ max_sign = -1;
++ m = compressor->models;
++ while (m != NULL) {
++ if (m->sb == last_sb) {
++ sign = (int) (m->block_sign[0]) * 256 + (int) (m->block_sign[1]);
++ if (sign > max_sign) {
++ max_sign = sign;
++ best_m = m;
++ }
++ }
++ m = m->next_compr_model;
++ }
++ if (best_m != NULL)
++ return best_m->model;
++ else
++ return NULL;
++}
++
++/*********************************************************************
++ * Statistics *
++ *********************************************************************/
++
++static char *jffs2_bbc_stat_buff = NULL;
++
++char *jffs2_bbc_get_model_stats(void)
++{
++ char *b;
++ struct jffs2_bbc_model_list_node *m;
++ struct jffs2_bbc_compressor_type *c;
++
++ if (jffs2_bbc_stat_buff == NULL)
++ jffs2_bbc_stat_buff = jffs2_bbc_malloc(8000);
++
++ b = jffs2_bbc_stat_buff;
++
++ b += sprintf(b, "Loaded compressors:");
++ c = jffs2_bbc_compressors;
++ while (c != NULL) {
++ b += sprintf(b, "\n %s (%d) ", c->name, c->enabled);
++ if (c->model_file_sign != 0) {
++ b += sprintf(b, "m_sign=%d ", c->model_file_sign);
++ b += sprintf(b, "models=");
++ m = c->models;
++ while (m != NULL) {
++ b += sprintf(b, "(inode=%d)", m->inode);
++ m = m->next_compr_model;
++ }
++ }
++ else {
++ b += sprintf(b, "b_sign=(%d,%d) nomodel", (int) (c->block_sign[0]), (int) (c->block_sign[1]));
++ }
++ if (c->proc_info != NULL) {
++ b += sprintf(b, "\n %s", c->proc_info());
++ }
++ c = c->next;
++ }
++
++ m = jffs2_bbc_model_list;
++
++ if (m == NULL) {
++ b += sprintf(b, "\nPresent models: NONE\n");
++ }
++ else {
++ b += sprintf(b, "\nPresent models:\n");
++ while (m != NULL) {
++ b += sprintf(b, " b_sign=(%d,%d),inode=%d,decompr=%d", (int) (m->block_sign[0]), (int) (m->block_sign[1]), m->inode, m->stat_decompr);
++ if (m->compressor == NULL)
++ b += sprintf(b, ",compressor=NULL\n");
++ else
++ b += sprintf(b, ",compressor=%s\n", m->compressor->name);
++ m = m->next_model;
++ }
++ }
++
++ return jffs2_bbc_stat_buff;
++}
++
++/*********************************************************************
++ * Memory handling, debug *
++ *********************************************************************/
++
++static int jffs2_bbc_mem_counter = 0;
++
++#ifdef __KERNEL__
++
++void *jffs2_bbc_malloc(long size)
++{
++ void *addr = vmalloc(size);
++ if (addr != NULL)
++ jffs2_bbc_mem_counter++;
++ else {
++ jffs2_bbc_print2("DEBUG: not enough memory (%ld)\n", size);
++ }
++ return addr;
++}
++
++void jffs2_bbc_free(void *addr)
++{
++ jffs2_bbc_mem_counter--;
++ vfree(addr);
++}
++
++void *jffs2_bbc_malloc_small(long size)
++{
++ void *addr;
++ addr = kmalloc(size, 0);
++ if (addr != NULL)
++ jffs2_bbc_mem_counter++;
++ return addr;
++}
++
++void jffs2_bbc_free_small(void *addr)
++{
++ jffs2_bbc_mem_counter--;
++ kfree(addr);
++}
++
++#else
++
++void *jffs2_bbc_malloc(long size)
++{
++ void *addr = malloc(size);
++ if (addr != NULL)
++ jffs2_bbc_mem_counter++;
++ return addr;
++}
++
++void jffs2_bbc_free(void *addr)
++{
++ jffs2_bbc_mem_counter--;
++ free(addr);
++}
++
++void *jffs2_bbc_malloc_small(long size)
++{
++ return jffs2_bbc_malloc(size);
++}
++
++void jffs2_bbc_free_small(void *addr)
++{
++ jffs2_bbc_free(addr);
++}
++
++#endif
++
++int jffs2_bbc_test_memory_counter(int verbose)
++{
++ if (verbose > 0) {
++ jffs2_bbc_print2("jffs2.bbc: mem_counter=%d!\n", jffs2_bbc_mem_counter);
++ }
++ return jffs2_bbc_mem_counter;
++}
++
++int jffs2_bbc_get_memory_counter(void)
++{
++ return jffs2_bbc_mem_counter;
++}
++
++static char mem_stat[200];
++
++char *jffs2_bbc_get_mem_stats(void)
++{
++ sprintf(mem_stat, "Memcounter=%d\n", jffs2_bbc_mem_counter);
++ return mem_stat;
++}
++
++void jffs2_bbc_print_flush(void)
++{
++#ifdef __KERNEL__
++ return;
++#else
++ fflush(stdout);
++ fflush(stderr);
++#endif
++}
++
++/*********************************************************************
++ * FRAMEWORK - ZLIB REPLACEMENT *
++ *********************************************************************/
++
++#ifndef JFFS2_BBC_STANDALONE
++
++/* Temorary buffers */
++static char stat_str[JFFS2_BBC_STAT_BUFF_SIZE];
++static int tmp_buffer_size = 0;
++static char *tmp_buffer = NULL;
++
++/* Statistic - used by /proc/jffs2_bbc and mkfs.jffs2 */
++char *jffs2_bbc_get_compr_stats(void)
++{
++ struct jffs2_bbc_compressor_type *l;
++ char *s = stat_str;
++
++ s += sprintf(s, "Compression statistics:\n");
++ l = jffs2_bbc_original_compressor;
++ //s += sprintf(s, " zlib: compr=%d/%d decompr=%d\n", stat_zlib_compr_new, stat_zlib_compr_orig, stat_zlib_decompr);
++ s += sprintf(s, " %s: compr=%d/%d decompr=%d\n", l->name, l->stat_compr_new, l->stat_compr_orig, l->stat_decompr);
++ l = jffs2_bbc_get_compressor_list();
++ while (l != NULL) {
++ s += sprintf(s, " %s: compr=%d/%d decompr=%d\n", l->name, l->stat_compr_new, l->stat_compr_orig, l->stat_decompr);
++ l = l->next;
++ }
++ return stat_str;
++}
++
++static void jffs2_bbc_buffer_fill(unsigned char *buff, int size)
++{
++ for (; size > 0; size--, buff++)
++ *buff = 255;
++}
++
++
++static int jffs2_bbc_update_compr_buf(unsigned long size)
++{
++ struct jffs2_bbc_compressor_type *l;
++
++ if (size < 5000)
++ size = 5000;
++ if (tmp_buffer == NULL) {
++ tmp_buffer = jffs2_bbc_malloc(size);
++ jffs2_bbc_buffer_fill(tmp_buffer, size);
++ tmp_buffer_size = size;
++ }
++ else if (tmp_buffer_size < size) {
++ jffs2_bbc_free(tmp_buffer);
++ tmp_buffer = jffs2_bbc_malloc(size);
++ jffs2_bbc_buffer_fill(tmp_buffer, size);
++ tmp_buffer_size = size;
++ }
++ l = jffs2_bbc_get_compressor_list();
++ while (l != NULL) {
++ if (l->buffer == NULL) {
++ l->buffer_size = size;
++ l->buffer = jffs2_bbc_malloc(size);
++ jffs2_bbc_buffer_fill(l->buffer, size);
++ }
++ else if (l->buffer_size < size) {
++ jffs2_bbc_free(l->buffer);
++ l->buffer_size = size;
++ l->buffer = jffs2_bbc_malloc(size);
++ jffs2_bbc_buffer_fill(l->buffer, size);
++ }
++ l = l->next;
++ }
++ return 0;
++}
++
++#ifdef DEBUG_COMPRESSORS
++
++static unsigned char *debug_tmp_buff = NULL;
++static long debug_orig_srclen = -1;
++static long debug_orig_dstlen = -1;
++static int debug_mem_counter = -1;
++
++
++void debug_before_compress(struct jffs2_bbc_compressor_type *c, void *model, unsigned char *input, unsigned char *output, long *sourcelen, long *dstlen)
++{
++
++ debug_orig_srclen = *sourcelen; // for buffer overflow test
++ debug_orig_dstlen = *dstlen; // for buffer overflow test
++ output[debug_orig_dstlen + 1] = 255;
++
++ debug_mem_counter = jffs2_bbc_get_memory_counter(); // for memory guard
++}
++
++void debug_after_compress(struct jffs2_bbc_compressor_type *c, int back, void *model, unsigned char *input, unsigned char *output, long *sourcelen, long *dstlen)
++{
++ long dst_len = *dstlen;
++ long src_len = *sourcelen;
++ int i;
++
++ // Memory guard
++ if (debug_mem_counter != jffs2_bbc_get_memory_counter()) {
++ jffs2_bbc_print4("!!!!!!!! %s error: possible COMPRESSOR MEMORY LEAK: %d->%d\n", c->name, debug_mem_counter, jffs2_bbc_get_memory_counter());
++ debug_mem_counter = jffs2_bbc_get_memory_counter();
++ }
++
++ // Buffer overflow test
++ if (output[debug_orig_dstlen + 1] != 255) {
++ jffs2_bbc_print7("!!!!!!!! %s error: BUFFER OVERFLOW !!!!!!!!!!!! b[%d]=%d (srclen=%d dstlen=%d, back=%d)\n", c->name, (int) (debug_orig_dstlen + 1), (int) (output[debug_orig_dstlen + 1]), (int) (debug_orig_srclen), (int) (*dstlen), back);
++ }
++
++ // Decompression check
++ if (back == 0) {
++ if (debug_tmp_buff == NULL)
++ debug_tmp_buff = jffs2_bbc_malloc(17000);
++ for (i = 0; i < src_len; i++) debug_tmp_buff[i] = 0xf6;
++ c->decompress(model, output, debug_tmp_buff, dst_len, src_len);
++ // Memory guard for decompressor
++ if (debug_mem_counter != jffs2_bbc_get_memory_counter()) {
++ jffs2_bbc_print4("!!!!!!!! %s error: possible DECOMPRESSOR MEMORY LEAK: %d->%d\n", c->name, debug_mem_counter, jffs2_bbc_get_memory_counter());
++ debug_mem_counter = jffs2_bbc_get_memory_counter();
++ }
++
++ for (i = 0; i < src_len; i++)
++ if (input[i] != debug_tmp_buff[i]) {
++ jffs2_bbc_print7("!!!!!!!! %s error: BLOCK DECOMPRESSED BADLY (first bad: %d in %d: %d!=%d (compressed size=%d)) !!!!!!!!!!!!\n", c->name, i, src_len, (int)input[i], (int)debug_tmp_buff[i], dst_len);
++ break;
++ }
++ return;
++ }
++
++ // Return value test
++ //jffs2_bbc_print3("!!!!!!!! %s error: %d !!!!!!!!!!!!\n", c->name, back);
++}
++
++#endif
++
++int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t * sourcelen, uint32_t * dstlen)
++{
++ struct jffs2_bbc_compressor_type *c;
++ int back, back_zlib, mode, min, i, i2;
++ long tmp = 0, tmp_read_time = 1000, tmp_write_time = 1000, orig_src, orig_dest, src, dest;
++ struct jffs2_bbc_model_list_node *m;
++ void *sb;
++ unsigned char *tmp_p = NULL;
++
++ sb = jffs2_bbc_model_get_act_sb();
++
++ orig_src = *sourcelen;
++ orig_dest = *dstlen;
++
++ mode = jffs2_bbc_get_compression_mode();
++
++ if (mode == JFFS2_BBC_DUMMY_MODE) {
++ i=0; i2=0;
++ if (*dstlen>2) {
++ cpage_out[i++]=JFFS2_BBC_DUMMY_BLOCKSIGN_0;
++ cpage_out[i++]=JFFS2_BBC_DUMMY_BLOCKSIGN_1;
++ i2=i;
++ }
++ for (;((i < *dstlen) && (i < (*sourcelen)+i2));i++) {
++ cpage_out[i] = data_in[i-i2];
++ }
++ *sourcelen=i-i2;
++ *dstlen=i;
++ return 0;
++ }
++
++ if (mode == JFFS2_BBC_ZLIB_MODE) {
++ /*if (!jffs2_bbc_original_compressor->enabled) {
++ jffs2_bbc_print2("jffs2.bbc: WARNING: ZLIB mode but %s disabled! Enabling for this procedure...\n",jffs2_bbc_original_compressor->name);
++ }*/
++ back = jffs2_bbc_original_compressor->compress(NULL, data_in, cpage_out, sourcelen, dstlen);
++ jffs2_bbc_original_compressor->stat_compr_orig += *sourcelen;
++ jffs2_bbc_original_compressor->stat_compr_new += *dstlen;
++ return back;
++ }
++
++ jffs2_bbc_update_compr_buf(orig_dest);
++
++ if (mode == JFFS2_BBC_SIZE_MODE) {
++ // Testing all compressors
++ if (!jffs2_bbc_original_compressor->enabled) {
++ min = -1;
++ }
++ else {
++ back_zlib = jffs2_bbc_original_compressor->compress(NULL, data_in, cpage_out, sourcelen, dstlen);
++ min = *dstlen;
++ }
++ c = jffs2_bbc_get_compressor_list();
++ while (c != NULL) {
++ c->buffer_cnt = -1;
++ if (c->enabled == 0) {
++ c = c->next;
++ continue;
++ }
++ if (c->model_file_sign == 0) {
++ src = orig_src;
++ dest = orig_dest;
++#ifdef DEBUG_COMPRESSORS
++ debug_before_compress(c, NULL, data_in, c->buffer, &src, &dest);
++#endif
++ back = c->compress(NULL, data_in, c->buffer, &src, &dest);
++#ifdef DEBUG_COMPRESSORS
++ debug_after_compress(c, back, NULL, data_in, c->buffer, &src, &dest);
++#endif
++ if (back == 0) {
++ c->buffer_cnt = dest;
++ if ((min < 0) || (min > dest))
++ min = dest;
++ }
++ }
++ else {
++ m = c->models;
++ while (m != NULL) {
++ src = orig_src;
++ dest = orig_dest;
++ if (m->sb == sb) {
++ if (c->buffer_cnt == -1) {
++#ifdef DEBUG_COMPRESSORS
++ debug_before_compress(c, m->model, data_in, c->buffer, (long *) (&src), (long *) (&dest));
++#endif
++ back = c->compress(m->model, data_in, c->buffer, (long *) (&src), (long *) (&dest));
++#ifdef DEBUG_COMPRESSORS
++ debug_after_compress(c, back, m->model, data_in, c->buffer, (long *) (&src), (long *) (&dest));
++#endif
++ if (back == 0) {
++ c->buffer_cnt = dest;
++ if ((min < 0) || (min > dest))
++ min = dest;
++ }
++ }
++ else {
++#ifdef DEBUG_COMPRESSORS
++ debug_before_compress(c, m->model, data_in, tmp_buffer, &src, &dest);
++#endif
++ back = c->compress(m->model, data_in, tmp_buffer, &src, &dest);
++#ifdef DEBUG_COMPRESSORS
++ debug_after_compress(c, back, m->model, data_in, tmp_buffer, &src, &dest);
++#endif
++ if (back == 0) {
++ if (c->buffer_cnt > dest) {
++ c->buffer_cnt = dest;
++ tmp_p = c->buffer;
++ c->buffer = tmp_buffer;
++ tmp_buffer = tmp_p;
++ if ((min < 0) || (min > dest))
++ min = dest;
++ }
++ }
++ }
++ }
++ m = m->next_compr_model;
++ }
++ }
++ c = c->next;
++ }
++ //Finding the best and copy its result
++
++#ifdef DEBUG_SHOW_BLOCK_SIZES
++ jffs2_bbc_print1("\n");
++ if (jffs2_bbc_original_compressor->enabled) {
++ if (min == *dstlen) {
++ jffs2_bbc_print3("%s:%d* ", jffs2_bbc_original_compressor->name, (int) (*dstlen));
++ }
++ else {
++ jffs2_bbc_print3("%s:%d ", jffs2_bbc_original_compressor->name, (int) (*dstlen));
++ }
++ }
++ c = jffs2_bbc_get_compressor_list();
++ while (c != NULL) {
++ if (c->enabled == 0) {
++ c = c->next;
++ continue;
++ }
++ if (c->buffer_cnt == min)
++ jffs2_bbc_print3("%s:%d* ", c->name, c->buffer_cnt);
++ else
++ jffs2_bbc_print3("%s:%d ", c->name, c->buffer_cnt);
++ c = c->next;
++ }
++#endif
++
++ if (min == -1) {
++ return -1; // none of compressors work (maybe too short output buffer)
++ }
++
++ if (jffs2_bbc_original_compressor->enabled) {
++ if (min == *dstlen) {
++ jffs2_bbc_original_compressor->stat_compr_orig += *sourcelen;
++ jffs2_bbc_original_compressor->stat_compr_new += *dstlen;
++ return back_zlib;
++ }
++ }
++
++ c = jffs2_bbc_get_compressor_list();
++ while (c != NULL) {
++ if (c->enabled == 0) {
++ c = c->next;
++ continue;
++ }
++ if (c->buffer_cnt == min) {
++ *dstlen = c->buffer_cnt;
++ *sourcelen = orig_src;
++ for (i = 0; i < *dstlen; i++) {
++ cpage_out[i] = c->buffer[i];
++ }
++ c->stat_compr_orig += *sourcelen;
++ c->stat_compr_new += *dstlen;
++ return 0;
++ }
++ c = c->next;
++ }
++ jffs2_bbc_print1("jffs2.bbc: compr (full): BUG!!!\n");
++ return 0;
++ }
++
++ if ((mode == JFFS2_BBC_FASTR_MODE)||(mode == JFFS2_BBC_FASTW_MODE)||(mode == JFFS2_BBC_FASTS_MODE)) {
++ // Estimating all compressors
++ if (jffs2_bbc_original_compressor->enabled) {
++ back = jffs2_bbc_original_compressor->estimate(NULL, data_in, *sourcelen, &tmp, &tmp_read_time, &tmp_write_time);
++ }
++ else {
++ tmp = -1;
++ tmp_read_time = -1;
++ tmp_write_time = -1;
++ }
++ if (mode == JFFS2_BBC_FASTR_MODE) tmp = tmp_read_time;
++ if (mode == JFFS2_BBC_FASTW_MODE) tmp = tmp_write_time;
++ min = tmp;
++ c = jffs2_bbc_get_compressor_list();
++ while (c != NULL) {
++ src = orig_src;
++ dest = orig_dest;
++ c->buffer_cnt = -1;
++ if (c->enabled == 0) {
++ c = c->next;
++ continue;
++ }
++ if ((c->model_file_sign == 0) || (jffs2_bbc_model_get_newest(c) != NULL)) {
++ back = c->estimate(jffs2_bbc_model_get_newest(c), data_in, src, &dest, &tmp_read_time, &tmp_write_time);
++ if (mode == JFFS2_BBC_FASTR_MODE) dest = tmp_read_time;
++ if (mode == JFFS2_BBC_FASTW_MODE) dest = tmp_write_time;
++ if (back == 0) {
++ c->buffer_cnt = dest;
++ if ((min < 0) || (min > dest))
++ min = dest;
++ }
++ else {
++ c->buffer_cnt = -1;
++ }
++ }
++ c = c->next;
++ }
++ // Finding the best and compress with it
++ if (min == -1) {
++ return -1;
++ }
++ if (jffs2_bbc_original_compressor->enabled) {
++ if (min == tmp) {
++ back = jffs2_bbc_original_compressor->compress(NULL, data_in, cpage_out, sourcelen, dstlen);
++ jffs2_bbc_original_compressor->stat_compr_orig += *sourcelen;
++ jffs2_bbc_original_compressor->stat_compr_new += *dstlen;
++ return back;
++ }
++ }
++ c = jffs2_bbc_get_compressor_list();
++ while (c != NULL) {
++ if (c->enabled == 0) {
++ c = c->next;
++ continue;
++ }
++ if (c->buffer_cnt == min) {
++ back = c->compress(jffs2_bbc_model_get_newest(c), data_in, cpage_out, (unsigned long*)sourcelen, (unsigned long*)dstlen);
++ if ((back == 0) && (*dstlen < orig_dest) && (*dstlen > 4)) {
++ c->stat_compr_orig += *sourcelen;
++ c->stat_compr_new += *dstlen;
++ }
++ else { // fallback will always be available
++ *sourcelen = orig_src;
++ *dstlen = orig_dest;
++ back = jffs2_bbc_original_compressor->compress(NULL, data_in, cpage_out, sourcelen, dstlen);
++ jffs2_bbc_original_compressor->stat_compr_orig += *sourcelen;
++ jffs2_bbc_original_compressor->stat_compr_new += *dstlen;
++ return back;
++ }
++ return 0;
++ }
++ c = c->next;
++ }
++ jffs2_bbc_print1("jffs2.bbc: compress (fastX mode): BUG!!!\n");
++ return 0;
++ }
++
++ if (mode == JFFS2_BBC_MANUAL_MODE) {
++ c = jffs2_bbc_get_manual_compressor();
++ if (c != NULL) {
++ if (c->model_file_sign == 0) {
++ src = orig_src;
++ dest = orig_dest;
++ back = c->compress(NULL, data_in, cpage_out, &src, &dest);
++ if (back == 0) {
++ *dstlen = dest;
++ *sourcelen = src;
++ c->stat_compr_orig += *sourcelen;
++ c->stat_compr_new += *dstlen;
++ return 0;
++ }
++ }
++ else {
++ c->buffer_cnt = -1;
++ m = c->models;
++ min = -1;
++ while (m != NULL) {
++ src = orig_src;
++ dest = orig_dest;
++ if (m->sb == sb) {
++ if (min == -1) {
++ back = c->compress(m->model, data_in, cpage_out, (unsigned long*)sourcelen, (unsigned long*)dstlen);
++ if ((back == 0) && (*dstlen < orig_dest) && (*dstlen > 4)) {
++ min = dest;
++ tmp_p = cpage_out;
++ }
++ }
++ else {
++ back = c->compress(m->model, data_in, tmp_buffer, &src, &dest);
++ if ((back == 0) && (dest < orig_dest) && (dest > 4)) {
++ if (c->buffer_cnt > dest) {
++ if (min > dest) {
++ min = dest;
++ tmp_p = tmp_buffer;
++ }
++ }
++ }
++ }
++ }
++ m = m->next_compr_model;
++ }
++ if (min != -1) {
++ if (tmp_p != cpage_out) {
++ for (i = 0; i < min; i++)
++ cpage_out[i] = tmp_p[i];
++ *sourcelen = orig_src;
++ *dstlen = min;
++ }
++ c->stat_compr_orig += *sourcelen;
++ c->stat_compr_new += *dstlen;
++ return 0;
++ }
++ }
++ }
++ /*else {
++ jffs2_bbc_print1("iPack: manual mode without selected compressor!\n");
++ } */
++
++ /*if (!jffs2_bbc_original_compressor->enabled) {
++ jffs2_bbc_print2("jffs2.bbc: WARNING: %s must be enabled! Enabling for this procedure...\n",jffs2_bbc_original_compressor->name);
++ }*/
++ back = jffs2_bbc_original_compressor->compress(NULL, data_in, cpage_out, sourcelen, dstlen);
++ jffs2_bbc_original_compressor->stat_compr_orig += *sourcelen;
++ jffs2_bbc_original_compressor->stat_compr_new += *dstlen;
++ return back;
++
++
++ }
++
++ jffs2_bbc_print1("jffs2.bbc: compress: unimlemented compress mode!!!\n");
++ return 0;
++}
++
++void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen)
++{
++ struct jffs2_bbc_model_list_node *m;
++ struct jffs2_bbc_compressor_type *c;
++ char d[2];
++ void *sb;
++ int i;
++
++ /* If the input too small... */
++ if (destlen<=2) {
++ cpage_out[0]=data_in[0];
++ if (destlen==2) cpage_out[1]=data_in[1];
++ return;
++ }
++
++ sb = jffs2_bbc_model_get_act_sb();
++ d[0] = *(data_in);
++ d[1] = *(data_in + 1);
++
++ d[0] &= 0x7f; // Variants support...
++
++ /* Search for model based decompressors... */
++ m = jffs2_bbc_get_model_list();
++ while (m != NULL) {
++ if ((d[0] == m->block_sign[0]) && (d[1] == m->block_sign[1]) && (sb == m->sb)) {
++ if (m->compressor == NULL) {
++ jffs2_bbc_print3("jffs2.bbc: decompressor for block_sign (%d,%d) not loaded!\n", (int) (d[0]), (int) (d[1]));
++ }
++ else {
++ m->compressor->decompress(m->model, data_in, cpage_out, srclen, destlen);
++ m->compressor->stat_decompr++;
++ m->stat_decompr++;
++ }
++ return;
++ }
++ m = m->next_model;
++ }
++ /* Is it ZLIB? */
++ if ((((int) d[0]) == (int)(jffs2_bbc_original_compressor->block_sign[0])) && (((int) d[1]) == (int)(jffs2_bbc_original_compressor->block_sign[1]))) {
++ jffs2_bbc_original_compressor->decompress(NULL, data_in, cpage_out, srclen, destlen);
++ jffs2_bbc_original_compressor->stat_decompr++;
++ return;
++ }
++ /* Search for non model based decompressors... */
++ c = jffs2_bbc_get_compressor_list();
++ while (c != NULL) {
++ if (c->model_file_sign == 0) {
++ if (((int) (d[0]) == (int) (c->block_sign[0])) && ((int) (d[1]) == (int) (c->block_sign[1]))) {
++ c->decompress(NULL, data_in, cpage_out, srclen, destlen);
++ c->stat_decompr++;
++ return;
++ }
++ }
++ c = c->next;
++ }
++ /* Is it DUMMY? */
++ if ((((int) d[0]) == JFFS2_BBC_DUMMY_BLOCKSIGN_0) && (((int) d[1]) == JFFS2_BBC_DUMMY_BLOCKSIGN_1)) {
++ for (i=0;i<destlen;i++) {
++ cpage_out[i]=data_in[i+2];
++ }
++ return;
++ }
++ /* No matching decompressor found... */
++ jffs2_bbc_print4("jffs2.bbc: cannot find model for decompress: bsign=(%d,%d),sb=%d. Using zlib.\n", (int) d[0], (int) d[1], (int) sb);
++ jffs2_bbc_original_compressor->decompress(NULL, data_in, cpage_out, srclen, destlen);
++ jffs2_bbc_original_compressor->stat_decompr++;
++}
++
++#endif
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_framework.h linux-mips/fs/jffs2/jffs2_bbc_framework.h
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_framework.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_framework.h 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,202 @@
++/*
++ * JFFS2-BBC: Compression Framework - headers
++ *
++ * $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++ *
++ * Copyright (C) 2004, Ferenc Havasi
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ */
++
++#ifndef __JFFS2_BBC_FRAMEWORK_H__
++
++#define __JFFS2_BBC_FRAMEWORK_H__
++
++#define JFFS2_BBC_VERSION "0.54.3"
++
++#define JFFS2_BBC_CONFIG_FILE "bbc.conf"
++
++/*********************************************************************
++ * Compression mode handling *
++ *********************************************************************/
++
++#define JFFS2_BBC_ZLIB_MODE 1
++#define JFFS2_BBC_SIZE_MODE 2
++#define JFFS2_BBC_FASTR_MODE 3
++#define JFFS2_BBC_FASTW_MODE 4
++#define JFFS2_BBC_FASTS_MODE 5
++#define JFFS2_BBC_MANUAL_MODE 6
++#define JFFS2_BBC_DUMMY_MODE 7
++
++int jffs2_bbc_get_compression_mode(void);
++void jffs2_bbc_set_compression_mode(int mode);
++
++/*********************************************************************
++ * Read/write speed unit *
++ * everything is relative to the speed of zlib *
++ * bigger number means slower speed! *
++ *********************************************************************/
++
++#define JFFS2_BBC_ZLIB_READ_TIME 10000
++#define JFFS2_BBC_ZLIB_WRITE_TIME 10000
++
++/*********************************************************************
++ * Compressor handling *
++ *********************************************************************/
++
++struct jffs2_bbc_compressor_type
++{
++ char name[16];
++ int model_file_sign; /* 0 for no model file needed */
++ char block_sign[4]; /* only nomodel compressors, and only the first 2 _bytes are used! */
++ int (*init)(void);
++ int (*init_model)(void **model);
++ void (*destroy_model)(void **model);
++ void (*deinit)(void);
++ /* Compress block
++ * *dstlen bytes are allocated.
++ * if it is not enough write *sourcelen over to the processed amount of data
++ * returns non zero if fails
++ */
++ int (*compress)(void *model, unsigned char *input, unsigned char *output, unsigned long *sourcelen, unsigned long *dstlen);
++ int (*estimate)(void *model, unsigned char *input, unsigned long sourcelen,
++ unsigned long *dstlen, unsigned long *readtime, unsigned long *writetime);
++ /* Decompress block
++ * returns non zero if fails
++ */
++ int (*decompress)(void *model, unsigned char *input, unsigned char *output, unsigned long sourcelen, unsigned long dstlen);
++ char *(*proc_info)(void);
++ int (*proc_command)(char *command);
++ int enabled; /* filled by BBC */
++ int mounted; /* filled by BBC */
++ void *models; /* filled by BBC */
++ char *buffer; /* filled by BBC */
++ int buffer_size; /* filled by BBC */
++ int buffer_cnt; /* filled by BBC */
++ int buffer_tmp; /* filled by BBC */
++ int stat_compr_orig; /* filled by BBC */
++ int stat_compr_new; /* filled by BBC */
++ int stat_decompr; /* filled by BBC */
++ struct jffs2_bbc_compressor_type *next; /* filled by BBC */
++};
++
++/* It sets the compression mode to JFFS2_BBC_MANUAL_MODE */
++
++void jffs2_bbc_set_manual_compressor(struct jffs2_bbc_compressor_type *c); /* NULL = ZLIB */
++int jffs2_bbc_set_manual_compressor_by_name(char *name);
++int jffs2_bbc_disable_compressor_by_name(char *name);
++int jffs2_bbc_enable_compressor_by_name(char *name);
++void jffs2_bbc_compressor_command_by_name(char *name_and_command);
++
++/* If the compression mode is JFFS2_BCC_MANUAL_MODE the manually setted
++ compressor can be get using it. Otherwise it returns with NULL. */
++
++struct jffs2_bbc_compressor_type *jffs2_bbc_get_manual_compressor(void);
++
++struct jffs2_bbc_model_list_node
++{
++ void *sb; /* FS idendifier (JFFS2_SB_INFO(sb) at this moment) */
++ void *model; /* model data */
++ int sign; /* sign of the model (first 4 bytes) */
++ char block_sign[4]; /* block sign - only the first 2 bytes are used! */
++ int inode; /* inode number of the model file */
++ int stat_decompr;
++ struct jffs2_bbc_compressor_type *compressor;
++ struct jffs2_bbc_model_list_node *next_model;
++ struct jffs2_bbc_model_list_node *next_compr_model;
++};
++
++struct jffs2_bbc_compressor_type *jffs2_bbc_get_compressor_list(void);
++struct jffs2_bbc_model_list_node *jffs2_bbc_get_model_list(void);
++
++int jffs2_bbc_register_compressor(struct jffs2_bbc_compressor_type *c);
++int jffs2_bbc_unregister_compressor(struct jffs2_bbc_compressor_type *c);
++
++int jffs2_bbc_model_new(void *sb, int i_num, void *model);
++void jffs2_bbc_model_del(void *sb);
++void jffs2_bbc_model_set_act_sb(void *sb);
++void *jffs2_bbc_model_get_act_sb(void);
++void *jffs2_bbc_model_get_newest(struct jffs2_bbc_compressor_type *compressor);
++
++/*********************************************************************
++ * Compressor init function *
++ *********************************************************************/
++
++void jffs2_bbc_compressor_init(void);
++void jffs2_bbc_compressor_deinit(void);
++
++/*********************************************************************
++ * Statistics *
++ *********************************************************************/
++
++char *jffs2_bbc_get_compr_stats(void);
++char *jffs2_bbc_get_model_stats(void);
++
++/*********************************************************************
++ * Other *
++ *********************************************************************/
++
++
++void jffs2_bbc_print_flush(void);
++
++#ifdef __KERNEL__
++#include <linux/kernel.h>
++#define jffs2_bbc_print1(a) printk(a)
++#define jffs2_bbc_print2(a,b) printk(a,b)
++#define jffs2_bbc_print3(a,b,c) printk(a,b,c)
++#define jffs2_bbc_print4(a,b,c,d) printk(a,b,c,d)
++#define jffs2_bbc_print5(a,b,c,d,e) printk(a,b,c,d,e)
++#define jffs2_bbc_print6(a,b,c,d,e,f) printk(a,b,c,d,e,f)
++#define jffs2_bbc_print7(a,b,c,d,e,f,g) printk(a,b,c,d,e,f,g)
++#define jffs2_bbc_print8(a,b,c,d,e,f,g,h) printk(a,b,c,d,e,f,g,h)
++#define jffs2_bbc_print9(a,b,c,d,e,f,g,h,i) printk(a,b,c,d,e,f,g,h,i)
++#else
++#include <stdio.h>
++#define jffs2_bbc_print1(a) fprintf(stderr,a)
++#define jffs2_bbc_print2(a,b) fprintf(stderr,a,b)
++#define jffs2_bbc_print3(a,b,c) fprintf(stderr,a,b,c)
++#define jffs2_bbc_print4(a,b,c,d) fprintf(stderr,a,b,c,d)
++#define jffs2_bbc_print5(a,b,c,d,e) fprintf(stderr,a,b,c,d,e)
++#define jffs2_bbc_print6(a,b,c,d,e,f) fprintf(stderr,a,b,c,d,e,f)
++#define jffs2_bbc_print7(a,b,c,d,e,f,g) fprintf(stderr,a,b,c,d,e,f,g)
++#define jffs2_bbc_print8(a,b,c,d,e,f,g,h) fprintf(stderr,a,b,c,d,e,f,g,h)
++#define jffs2_bbc_print9(a,b,c,d,e,f,g,h,i) fprintf(stderr,a,b,c,d,e,f,g,h,i)
++#endif
++
++/* Handle endianness */
++#ifndef __KERNEL__
++
++#define ENDIAN_HOST_AND_TARGET_SAME 0
++#define ENDIAN_HOST_AND_TARGET_DIFFERENT 1
++
++extern int jffs2_bbc_glb_endian_X;
++
++#endif
++
++/* Allocating more than one page (tip. 4096 byte) */
++void *jffs2_bbc_malloc(long size);
++void jffs2_bbc_free(void *addr);
++
++/* Allocating less than one page (tip. 4096 byte) */
++void *jffs2_bbc_malloc_small(long size);
++void jffs2_bbc_free_small(void *addr);
++
++/* Memory guarding */
++int jffs2_bbc_test_memory_counter(int verbose);
++char *jffs2_bbc_get_mem_stats(void);
++int jffs2_bbc_get_memory_counter(void);
++
++#endif
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_fs.c linux-mips/fs/jffs2/jffs2_bbc_fs.c
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_fs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_fs.c 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,331 @@
++/*
++ * JFFS2-BBC: File System Extension for Linux Kernel
++ *
++ * $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++ *
++ * Copyright (C) 2004, Ferenc Havasi
++ *
++ * 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/kernel.h>
++#include <linux/fs.h>
++#include <linux/jffs2.h>
++#include <linux/proc_fs.h>
++#include <linux/version.h>
++
++#include "nodelist.h"
++
++#include "jffs2_bbc_framework.h"
++
++struct jffs2_bbc_fs_sb_list {
++ struct super_block *sb;
++ struct jffs2_bbc_fs_sb_list *next;
++};
++
++static struct jffs2_bbc_fs_sb_list *sb_list = NULL;
++
++void jffs2_bbc_proc_init(void);
++void jffs2_bbc_proc_deinit(void);
++
++void jffs2_bbc_load_model(void *sb_par) {
++ struct jffs2_sb_info *c;
++ //struct jffs2_inode_info *f;
++ struct dentry *config_dentry,*model_dentry;
++ struct qstr config_name,model_name;
++ struct file *config_file,*model_file;
++ char *buff=NULL,*model_buff;
++ int config_size,model_size;
++ int i,prev_i;
++ struct super_block *sb;
++ struct jffs2_bbc_fs_sb_list *sb_l;
++
++ sb = sb_par;
++ sb_l = jffs2_bbc_malloc_small(sizeof(struct jffs2_bbc_fs_sb_list));
++ sb_l->sb = sb;
++ sb_l->next = sb_list;
++ sb_list = sb_l;
++ config_name.name = JFFS2_BBC_CONFIG_FILE;
++ config_name.len = strlen(config_name.name);
++ config_name.hash = full_name_hash(config_name.name,config_name.len);
++ config_dentry = d_alloc(sb->s_root,&config_name);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
++ sb->s_root->d_inode->i_op->lookup(sb->s_root->d_inode,config_dentry);
++#else
++ sb->s_root->d_inode->i_op->lookup(sb->s_root->d_inode,config_dentry,NULL);
++#endif
++
++ if (config_dentry->d_inode != NULL) {
++ config_size = config_dentry->d_inode->i_size;
++ //printk("config_file_size=%d\n",config_size);
++ if (config_size > 0) {
++ buff = jffs2_bbc_malloc(config_size+1);
++ config_file = dentry_open(config_dentry,NULL,O_RDONLY);
++ kernel_read(config_file,0,buff,config_size);
++ buff[config_size] = 0;
++ for (prev_i = i = 0 ; i < config_size+1 ; i++) {
++ if (buff[i] == '\n') buff[i]=0;
++ if (buff[i] == 0) {
++ if (prev_i != i) {
++ if ((buff[prev_i] == '-') && (buff[prev_i+1] == 0)) break;
++ printk("reading model file %s... ",buff+prev_i);
++ model_name.name = buff+prev_i;
++ model_name.len = strlen(buff+prev_i);
++ model_name.hash = full_name_hash(model_name.name,model_name.len);
++ model_dentry = d_alloc(sb->s_root,&model_name);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
++ sb->s_root->d_inode->i_op->lookup(sb->s_root->d_inode,model_dentry);
++#else
++ sb->s_root->d_inode->i_op->lookup(sb->s_root->d_inode,model_dentry,NULL);
++#endif
++ if (model_dentry->d_inode != NULL) {
++ c = JFFS2_SB_INFO(model_dentry->d_inode->i_sb);
++ //f = JFFS2_INODE_INFO(model_dentry->d_inode);
++ model_size = model_dentry->d_inode->i_size;
++ model_buff = jffs2_bbc_malloc(model_size);
++ model_file = dentry_open(model_dentry,NULL,O_RDONLY);
++ kernel_read(model_file,0,model_buff,model_size);
++ if (jffs2_bbc_model_new(c,model_dentry->d_inode->i_ino,model_buff) != 0) {
++ printk("already loaded.\n");
++ jffs2_bbc_free(model_buff);
++ }
++ else {
++ printk("done (%d bytes readed from inode %d).\n",model_size,(int)(model_dentry->d_inode->i_ino));
++ }
++ }
++ else {
++ printk("not found.\n");
++ }
++ dput(model_dentry);
++ }
++ prev_i = i+1;
++ }
++ }
++ }
++ }
++ dput(config_dentry);
++ if (buff != NULL) jffs2_bbc_free(buff);
++}
++
++void jffs2_bbc_unload_model(void *sb_par)
++{
++ struct jffs2_sb_info *c;
++ struct super_block *sb = sb_par;
++ struct jffs2_bbc_fs_sb_list *sb_l,*sb_l2;
++ int done = 0;
++
++ c = JFFS2_SB_INFO(sb);
++ jffs2_bbc_model_del(c);
++ if (sb_list == NULL) printk("jffs2.bbc: error! NULL sb list!\n");
++ else {
++ if (sb_list->sb == sb) {
++ jffs2_bbc_free_small(sb_list);
++ sb_list = NULL;
++ done = 1;
++ }
++ else {
++ sb_l = sb_list;
++ while (sb_l->next != NULL) {
++ if (sb_l->next->sb == sb) {
++ sb_l2 = sb_l->next->next;
++ jffs2_bbc_free_small(sb_l->next);
++ sb_l->next = sb_l2;
++ done = 1;
++ }
++ sb_l = sb_l->next;
++ }
++
++ }
++ if (done == 0) {
++ printk("jffs2.bbc: cannot delete sb from sblist!\n");
++ }
++ }
++}
++
++static int jffs2_bbc_get_mounted(void) {
++ struct jffs2_bbc_fs_sb_list *sb_l;
++ int num = 0;
++
++ sb_l = sb_list;
++ while (sb_l != NULL) {
++ num++;
++ sb_l = sb_l->next;
++ }
++ return num;
++
++}
++
++int jffs2_bbc_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data)
++{
++ int len = 0, mode;
++
++ mode = jffs2_bbc_get_compression_mode();
++ len += sprintf(buf + len, "BBC version: %s\n", JFFS2_BBC_VERSION);
++ len += sprintf(buf+len,"Mounted jffs2 filesystems: %d\n",jffs2_bbc_get_mounted());
++ //len += sprintf(buf+len,"actual model file inode: %d\n",jffs2_bbc_model_get_inum());
++ len += sprintf(buf + len, "Compression mode: ");
++ if (mode == JFFS2_BBC_ZLIB_MODE)
++ len += sprintf(buf + len, "ZLIB mode");
++ else if (mode == JFFS2_BBC_SIZE_MODE)
++ len += sprintf(buf + len, "SIZE mode");
++ else if (mode == JFFS2_BBC_FASTR_MODE)
++ len += sprintf(buf + len, "FASTR mode");
++ else if (mode == JFFS2_BBC_FASTW_MODE)
++ len += sprintf(buf + len, "FASTW mode");
++ else if (mode == JFFS2_BBC_FASTS_MODE)
++ len += sprintf(buf + len, "FASTS mode");
++ else if (mode == JFFS2_BBC_DUMMY_MODE)
++ len += sprintf(buf + len, "DUMMY mode");
++ else if (mode == JFFS2_BBC_MANUAL_MODE) {
++ len += sprintf(buf + len, "MANUAL mode (");
++ if (jffs2_bbc_get_manual_compressor() != NULL)
++ len += sprintf(buf + len, "%s)", jffs2_bbc_get_manual_compressor()->name);
++ else
++ len += sprintf(buf + len, "ZLIB)");
++ }
++ else
++ len += sprintf(buf + len, "unknown mode");
++ len += sprintf(buf + len, "\n");
++ len += sprintf(buf + len, "%s", jffs2_bbc_get_compr_stats());
++ len += sprintf(buf + len, "%s", jffs2_bbc_get_model_stats());
++ len += sprintf(buf + len, "%s", jffs2_bbc_get_mem_stats());
++ *eof = 1;
++ return len;
++}
++
++int jffs2_bbc_proc_write(struct file *file, const char *buffer_orig, unsigned long count, void *data)
++{
++ char *buffer;
++ int i;
++ struct jffs2_bbc_fs_sb_list *sb_l;
++
++ if (buffer_orig == NULL) return 0;
++
++ buffer = jffs2_bbc_malloc(count+2);
++ for (i=0;i<count;i++) buffer[i]=buffer_orig[i];
++ buffer[count] = 0;
++ if ((*buffer == 'z') || (*buffer == 'Z')) {
++ jffs2_bbc_set_compression_mode(JFFS2_BBC_ZLIB_MODE);
++ jffs2_bbc_print1("jffs2.bbc: ZLIB compression mode activated.\n");
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if ((*buffer == 's') || (*buffer == 'S')) {
++ jffs2_bbc_set_compression_mode(JFFS2_BBC_SIZE_MODE);
++ jffs2_bbc_print1("jffs2.bbc: SIZE compression mode activated.\n");
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if ((*buffer == 'd') || (*buffer == 'D')) {
++ jffs2_bbc_set_compression_mode(JFFS2_BBC_DUMMY_MODE);
++ jffs2_bbc_print1("jffs2.bbc: DUMMY compression mode activated.\n");
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if (((*buffer == 'm') || (*buffer == 'M')) && (count >= 3) && (buffer[1] == ':')) {
++ jffs2_bbc_print1("jffs2.bbc: activating MANUAL mode.\n");
++ jffs2_bbc_set_manual_compressor_by_name(buffer + 2);
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if (((*buffer == '0')) && (count >= 3) && (buffer[1] == ':')) {
++ jffs2_bbc_print1("jffs2.bbc: disabling a compressor... ");
++ if (jffs2_bbc_disable_compressor_by_name(buffer + 2) == 0) {
++ jffs2_bbc_print1("done.\n");
++ }
++ else {
++ jffs2_bbc_print1("not found.\n");
++ }
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if (((*buffer == '1')) && (count >= 3) && (buffer[1] == ':')) {
++ jffs2_bbc_print1("jffs2.bbc: enabling a compressor... ");
++ if (jffs2_bbc_enable_compressor_by_name(buffer + 2) == 0) {
++ jffs2_bbc_print1("done.\n");
++ }
++ else {
++ jffs2_bbc_print1("not found.\n");
++ }
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if (((*buffer == 'c') || (*buffer == 'C')) && (count >= 3) && (buffer[1] == ':')) {
++ jffs2_bbc_compressor_command_by_name(buffer + 2);
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if ((*buffer == 'r') || (*buffer == 'R')) {
++ jffs2_bbc_print1("jffs2.bbc: reloading model files:\n");
++ sb_l = sb_list;
++ while (sb_l != NULL) {
++ jffs2_bbc_unload_model(sb_l->sb);
++ jffs2_bbc_load_model(sb_l->sb);
++ sb_l = sb_l->next;
++ }
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if (((buffer[0] == 'f') || (buffer[0] == 'F'))&&((buffer[1] == 'r') || (buffer[1] == 'R'))) {
++ jffs2_bbc_set_compression_mode(JFFS2_BBC_FASTR_MODE);
++ jffs2_bbc_print1("jffs2.bbc: FASTR compression mode activated.\n");
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if (((buffer[0] == 'f') || (buffer[0] == 'F'))&&((buffer[1] == 'w') || (buffer[1] == 'W'))) {
++ jffs2_bbc_set_compression_mode(JFFS2_BBC_FASTW_MODE);
++ jffs2_bbc_print1("jffs2.bbc: FASTW compression mode activated.\n");
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++ else if (((buffer[0] == 'f') || (buffer[0] == 'F'))&&((buffer[1] == 's') || (buffer[1] == 'S'))) {
++ jffs2_bbc_set_compression_mode(JFFS2_BBC_FASTS_MODE);
++ jffs2_bbc_print1("jffs2.bbc: FASTS compression mode activated.\n");
++ jffs2_bbc_free(buffer);
++ return count;
++ }
++
++ jffs2_bbc_print1("jffs2.bbc: unkown command. Valid commands are:\n"
++ " z = switch to ZLIB compression mode\n"
++ " s = switch to SIZE compression mode\n"
++ " d = switch to DUMMY compression mode\n"
++ " fr = switch to FASTR compression mode\n"
++ " fw = switch to FASTW compression mode\n"
++ " fs = switch to FASTS compression mode\n"
++ " r = reread model files from actual file system\n"
++ " m:compressor_name = switch to MANUAL compression mode\n"
++ " 0:compressor_name = disable a compressor\n"
++ " 1:compressor_name = enable a compressor\n"
++ " c:compressor_name:command = enable a compressor\n");
++ jffs2_bbc_free(buffer);
++ return count;
++}
++
++void jffs2_bbc_proc_init()
++{
++ struct proc_dir_entry *res = create_proc_entry("jffs2_bbc", 0, NULL);
++ jffs2_bbc_compressor_init();
++ if (res) {
++ res->read_proc = jffs2_bbc_proc_read;
++ res->write_proc = jffs2_bbc_proc_write;
++ }
++}
++
++void jffs2_bbc_proc_deinit()
++{
++ jffs2_bbc_compressor_deinit();
++ remove_proc_entry("jffs2_bbc", NULL);
++}
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_fs.h linux-mips/fs/jffs2/jffs2_bbc_fs.h
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_fs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_fs.h 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,30 @@
++/*
++ * JFFS2 BBC: File System Extension for Linux Kernel - headers
++ *
++ * $Id: 301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++ *
++ * Copyright (C) 2004, Ferenc Havasi
++ *
++ * 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.
++ *
++ */
++
++extern int jffs2_bbc_inode_not_found;
++
++void jffs2_bbc_load_model(void *sb);
++void jffs2_bbc_unload_model(void *sb);
++
++void jffs2_bbc_proc_init(void);
++void jffs2_bbc_proc_deinit(void);
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_lzari_comp.c linux-mips/fs/jffs2/jffs2_bbc_lzari_comp.c
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_lzari_comp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_lzari_comp.c 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,788 @@
++/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
++
++/*
++ jffs2_bbc_lzari_comp.c -- Lempel-Ziv-Arithmetic coding compression module for jffs2
++ Copyright (C) 2004 Patrik Kluba
++ Based on the LZARI source included in LDS (lossless datacompression sources)
++ Block-compression and bitstream modifications by Patrik Kluba
++ $Header: /openwrt/openwrt/package/linux/kernel-patches/301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*/
++
++/*
++Original copyright follows:
++
++**************************************************************
++ LZARI.C -- A Data Compression Program
++ (tab = 4 spaces)
++**************************************************************
++ 4/7/1989 Haruhiko Okumura
++ Use, distribute, and modify this program freely.
++ Please send me your improved versions.
++ PC-VAN SCIENCE
++ NIFTY-Serve PAF01022
++ CompuServe 74050,1022
++**************************************************************
++
++LZARI.C (c)1989 by Haruyasu Yoshizaki, Haruhiko Okumura, and Kenji Rikitake.
++All rights reserved. Permission granted for non-commercial use.
++
++*/
++
++/*
++
++ 2004-02-18 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
++ Removed unused variables and fixed no return value
++
++ 2004-02-16 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
++ Initial release
++
++*/
++
++/* lzari.c */
++
++#define N 4096 /* size of ring buffer */
++#define F 60 /* upper limit for match_length */
++#define THRESHOLD 2 /* encode string into position and length
++ if match_length is greater than this */
++#define NIL N /* index for root of binary search trees */
++
++static unsigned char
++ text_buf[N + F - 1]; /* ring buffer of size N,
++ with extra F-1 bytes to facilitate string comparison */
++static unsigned long match_position, match_length, /* of longest match. These are
++ set by the InsertNode() procedure. */
++ lson[N + 1], rson[N + 257], dad[N + 1]; /* left & right children &
++ parents -- These constitute binary search trees. */
++
++static void InitTree(void) /* Initialize trees */
++{
++ unsigned long i;
++
++ /* For i = 0 to N - 1, rson[i] and lson[i] will be the right and
++ left children of node i. These nodes need not be initialized.
++ Also, dad[i] is the parent of node i. These are initialized to
++ NIL (= N), which stands for 'not used.'
++ For i = 0 to 255, rson[N + i + 1] is the root of the tree
++ for strings that begin with character i. These are initialized
++ to NIL. Note there are 256 trees. */
++
++ for (i = N + 1; i <= N + 256; i++) rson[i] = NIL; /* root */
++ for (i = 0; i < N; i++) dad[i] = NIL; /* node */
++}
++
++static void InsertNode(unsigned long r)
++ /* Inserts string of length F, text_buf[r..r+F-1], into one of the
++ trees (text_buf[r]'th tree) and returns the longest-match position
++ and length via the global variables match_position and match_length.
++ If match_length = F, then removes the old node in favor of the new
++ one, because the old one will be deleted sooner.
++ Note r plays double role, as tree node and position in buffer. */
++{
++ unsigned long i, p, temp;
++ unsigned char *key;
++ signed long cmp;
++
++ cmp = 1; key = &text_buf[r]; p = N + 1 + key[0];
++ rson[r] = lson[r] = NIL; match_length = 0;
++ for ( ; ; ) {
++ if (cmp >= 0) {
++ if (rson[p] != NIL) p = rson[p];
++ else { rson[p] = r; dad[r] = p; return; }
++ } else {
++ if (lson[p] != NIL) p = lson[p];
++ else { lson[p] = r; dad[r] = p; return; }
++ }
++ for (i = 1; i < F; i++)
++ if ((cmp = key[i] - text_buf[p + i]) != 0) break;
++ if (i > THRESHOLD) {
++ if (i > match_length) {
++ match_position = (r - p) & (N - 1);
++ if ((match_length = i) >= F) break;
++ } else if (i == match_length) {
++ if ((temp = (r - p) & (N - 1)) < match_position)
++ match_position = temp;
++ }
++ }
++ }
++ dad[r] = dad[p]; lson[r] = lson[p]; rson[r] = rson[p];
++ dad[lson[p]] = r; dad[rson[p]] = r;
++ if (rson[dad[p]] == p) rson[dad[p]] = r;
++ else lson[dad[p]] = r;
++ dad[p] = NIL; /* remove p */
++}
++
++static void DeleteNode(unsigned long p) /* Delete node p from tree */
++{
++ unsigned long q;
++
++ if (dad[p] == NIL) return; /* not in tree */
++ if (rson[p] == NIL) q = lson[p];
++ else if (lson[p] == NIL) q = rson[p];
++ else {
++ q = lson[p];
++ if (rson[q] != NIL) {
++ do { q = rson[q]; } while (rson[q] != NIL);
++ rson[dad[q]] = lson[q]; dad[lson[q]] = dad[q];
++ lson[q] = lson[p]; dad[lson[p]] = q;
++ }
++ rson[q] = rson[p]; dad[rson[p]] = q;
++ }
++ dad[q] = dad[p];
++ if (rson[dad[p]] == p) rson[dad[p]] = q;
++ else lson[dad[p]] = q;
++ dad[p] = NIL;
++}
++
++/********** Arithmetic Compression **********/
++
++/* If you are not familiar with arithmetic compression, you should read
++ I. E. Witten, R. M. Neal, and J. G. Cleary,
++ Communications of the ACM, Vol. 30, pp. 520-540 (1987),
++ from which much have been borrowed. */
++
++#define M 15
++
++/* Q1 (= 2 to the M) must be sufficiently large, but not so
++ large as the unsigned long 4 * Q1 * (Q1 - 1) overflows. */
++
++#define Q1 (1UL << M)
++#define Q2 (2 * Q1)
++#define Q3 (3 * Q1)
++#define Q4 (4 * Q1)
++#define MAX_CUM (Q1 - 1)
++
++#define N_CHAR (256 - THRESHOLD + F)
++ /* character code = 0, 1, ..., N_CHAR - 1 */
++
++static unsigned long char_to_sym[N_CHAR], sym_to_char[N_CHAR + 1];
++static unsigned long
++ sym_freq[N_CHAR + 1], /* frequency for symbols */
++ sym_cum[N_CHAR + 1], /* cumulative freq for symbols */
++ position_cum[N + 1]; /* cumulative freq for positions */
++
++static void StartModel(void) /* Initialize model */
++{
++ unsigned long ch, sym, i;
++
++ sym_cum[N_CHAR] = 0;
++ for (sym = N_CHAR; sym >= 1; sym--) {
++ ch = sym - 1;
++ char_to_sym[ch] = sym; sym_to_char[sym] = ch;
++ sym_freq[sym] = 1;
++ sym_cum[sym - 1] = sym_cum[sym] + sym_freq[sym];
++ }
++ sym_freq[0] = 0; /* sentinel (!= sym_freq[1]) */
++ position_cum[N] = 0;
++ for (i = N; i >= 1; i--)
++ position_cum[i - 1] = position_cum[i] + 10000 / (i + 200);
++ /* empirical distribution function (quite tentative) */
++ /* Please devise a better mechanism! */
++}
++
++static void UpdateModel(unsigned long sym)
++{
++ unsigned long c, ch_i, ch_sym;
++ unsigned long i;
++ if (sym_cum[0] >= MAX_CUM) {
++ c = 0;
++ for (i = N_CHAR; i > 0; i--) {
++ sym_cum[i] = c;
++ c += (sym_freq[i] = (sym_freq[i] + 1) >> 1);
++ }
++ sym_cum[0] = c;
++ }
++ for (i = sym; sym_freq[i] == sym_freq[i - 1]; i--) ;
++ if (i < sym) {
++ ch_i = sym_to_char[i]; ch_sym = sym_to_char[sym];
++ sym_to_char[i] = ch_sym; sym_to_char[sym] = ch_i;
++ char_to_sym[ch_i] = sym; char_to_sym[ch_sym] = i;
++ }
++ sym_freq[i]++;
++ while (--i > 0) sym_cum[i]++;
++ sym_cum[0]++;
++}
++
++static unsigned long BinarySearchSym(unsigned long x)
++ /* 1 if x >= sym_cum[1],
++ N_CHAR if sym_cum[N_CHAR] > x,
++ i such that sym_cum[i - 1] > x >= sym_cum[i] otherwise */
++{
++ unsigned long i, j, k;
++
++ i = 1; j = N_CHAR;
++ while (i < j) {
++ k = (i + j) / 2;
++ if (sym_cum[k] > x) i = k + 1; else j = k;
++ }
++ return i;
++}
++
++unsigned long BinarySearchPos(unsigned long x)
++ /* 0 if x >= position_cum[1],
++ N - 1 if position_cum[N] > x,
++ i such that position_cum[i] > x >= position_cum[i + 1] otherwise */
++{
++ unsigned long i, j, k;
++
++ i = 1; j = N;
++ while (i < j) {
++ k = (i + j) / 2;
++ if (position_cum[k] > x) i = k + 1; else j = k;
++ }
++ return i - 1;
++}
++
++/* modified for block compression */
++/* on return, srclen will contain the number of successfully compressed bytes
++ and dstlen will contain completed compressed bytes */
++
++static int Encode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long *srclen,
++ unsigned long *dstlen)
++{
++ unsigned long c, i, len, r, s, last_match_length, sym, range;
++ unsigned long low = 0;
++ unsigned long high = Q4;
++ unsigned long shifts = 0; /* counts for magnifying low and high around Q2 */
++ unsigned char *ip, *op;
++ unsigned long written = 0;
++ unsigned long read = 0;
++ unsigned char buffer = 0;
++ unsigned char mask = 128;
++ unsigned char *srcend = srcbuf + *srclen;
++ unsigned char *dstend = dstbuf + *dstlen;
++ ip = srcbuf;
++ op = dstbuf;
++ StartModel();
++ InitTree(); /* initialize trees */
++ s = 0; r = N - F;
++ for (i = s; i < r; i++) text_buf[i] = ' '; /* Clear the buffer with
++ any character that will appear often. */
++ for (len = 0; (len < F) && (ip < srcend); len++)
++ text_buf[r + len] = *(ip++); /* Read F bytes into the last F bytes of
++ the buffer */
++ read = len;
++ for (i = 1; i <= F; i++) InsertNode(r - i); /* Insert the F strings,
++ each of which begins with one or more 'space' characters. Note
++ the order in which these strings are inserted. This way,
++ degenerate trees will be less likely to occur. */
++ InsertNode(r); /* Finally, insert the whole string just read. The
++ global variables match_length and match_position are set. */
++ do {
++ if (match_length > len) match_length = len; /* match_length
++ may be spuriously long near the end of text. */
++ if (match_length <= THRESHOLD) {
++ match_length = 1; /* Not long enough match. Send one byte. */
++ sym = char_to_sym[text_buf[r]];
++ range = high - low;
++ high = low + (range * sym_cum[sym - 1]) / sym_cum[0];
++ low += (range * sym_cum[sym ]) / sym_cum[0];
++ for ( ; ; ) {
++ if (high <= Q2) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ } else if (low >= Q2) {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ low -= Q2;
++ high -= Q2;
++ } else if (low >= Q1 && high <= Q3) {
++ shifts++;
++ low -= Q1;
++ high -= Q1;
++ } else break;
++ low += low; high += high;
++ }
++ UpdateModel(sym);
++ } else {
++ sym = char_to_sym[255 - THRESHOLD + match_length];
++ range = high - low;
++ high = low + (range * sym_cum[sym - 1]) / sym_cum[0];
++ low += (range * sym_cum[sym ]) / sym_cum[0];
++ for ( ; ; ) {
++ if (high <= Q2) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ } else if (low >= Q2) {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ low -= Q2;
++ high -= Q2;
++ } else if (low >= Q1 && high <= Q3) {
++ shifts++;
++ low -= Q1;
++ high -= Q1;
++ } else break;
++ low += low; high += high;
++ }
++ UpdateModel(sym);
++ range = high - low;
++ high = low + (range * position_cum[match_position - 1]) / position_cum[0];
++ low += (range * position_cum[match_position ]) / position_cum[0];
++ for ( ; ; ) {
++ if (high <= Q2) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ } else {
++ if (low >= Q2) {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ low -= Q2;
++ high -= Q2;
++ } else {
++ if ((low >= Q1) && (high <= Q3)) {
++ shifts++;
++ low -= Q1;
++ high -= Q1;
++ } else {
++ break;
++ }
++ }
++ }
++ low += low;
++ high += high;
++ }
++ }
++ last_match_length = match_length;
++ for (i = 0; (i < last_match_length) && (ip < srcend); i++) {
++ c = *(ip++);
++ DeleteNode(s);
++ text_buf[s] = c;
++ if (s < F - 1)
++ text_buf[s + N] = c;
++ s = (s + 1) & (N - 1);
++ r = (r + 1) & (N - 1);
++ InsertNode(r);
++ }
++ read += i;
++ while (i++ < last_match_length) {
++ DeleteNode(s);
++ s = (s + 1) & (N - 1);
++ r = (r + 1) & (N - 1);
++ if (--len) InsertNode(r);
++ }
++ } while (len > 0);
++ shifts++;
++ if (low < Q1) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ } else {
++ buffer |= mask;
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ for ( ; shifts > 0; shifts--) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ }
++ for (i = 0; i < 7; i++) {
++ if ((mask >>= 1) == 0) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = buffer;
++ buffer = 0;
++ mask = 128;
++ written++;
++ *srclen = read;
++ }
++ }
++ *dstlen = written;
++ return 0;
++}
++
++static int Decode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long srclen,
++ unsigned long dstlen) /* Just the reverse of Encode(). */
++{
++ unsigned long i, r, j, k, c, range, sym;
++ unsigned char *ip, *op;
++ unsigned char *srcend = srcbuf + srclen;
++ unsigned char *dstend = dstbuf + dstlen;
++ unsigned char buffer = 0;
++ unsigned char mask = 0;
++ unsigned long low = 0;
++ unsigned long high = Q4;
++ unsigned long value = 0;
++ ip = srcbuf;
++ op = dstbuf;
++ for (i = 0; i < M + 2; i++) {
++ value *= 2;
++ if ((mask >>= 1) == 0) {
++ buffer = (ip >= srcend) ? 0 : *(ip++);
++ mask = 128;
++ }
++ value += ((buffer & mask) != 0);
++ }
++ StartModel();
++ for (i = 0; i < N - F; i++) text_buf[i] = ' ';
++ r = N - F;
++ while (op < dstend) {
++ range = high - low;
++ sym = BinarySearchSym((unsigned long)
++ (((value - low + 1) * sym_cum[0] - 1) / range));
++ high = low + (range * sym_cum[sym - 1]) / sym_cum[0];
++ low += (range * sym_cum[sym ]) / sym_cum[0];
++ for ( ; ; ) {
++ if (low >= Q2) {
++ value -= Q2; low -= Q2; high -= Q2;
++ } else if (low >= Q1 && high <= Q3) {
++ value -= Q1; low -= Q1; high -= Q1;
++ } else if (high > Q2) break;
++ low += low; high += high;
++ value *= 2;
++ if ((mask >>= 1) == 0) {
++ buffer = (ip >= srcend) ? 0 : *(ip++);
++ mask = 128;
++ }
++ value += ((buffer & mask) != 0);
++ }
++ c = sym_to_char[sym];
++ UpdateModel(sym);
++ if (c < 256) {
++ if (op >= dstend) return -1;
++ *(op++) = c;
++ text_buf[r++] = c;
++ r &= (N - 1);
++ } else {
++ j = c - 255 + THRESHOLD;
++ range = high - low;
++ i = BinarySearchPos((unsigned long)
++ (((value - low + 1) * position_cum[0] - 1) / range));
++ high = low + (range * position_cum[i ]) / position_cum[0];
++ low += (range * position_cum[i + 1]) / position_cum[0];
++ for ( ; ; ) {
++ if (low >= Q2) {
++ value -= Q2; low -= Q2; high -= Q2;
++ } else if (low >= Q1 && high <= Q3) {
++ value -= Q1; low -= Q1; high -= Q1;
++ } else if (high > Q2) break;
++ low += low; high += high;
++ value *= 2;
++ if ((mask >>= 1) == 0) {
++ buffer = (ip >= srcend) ? 0 : *(ip++);
++ mask = 128;
++ }
++ value += ((buffer & mask) != 0);
++ }
++ i = (r - i - 1) & (N - 1);
++ for (k = 0; k < j; k++) {
++ c = text_buf[(i + k) & (N - 1)];
++ if (op >= dstend) return -1;
++ *(op++) = c;
++ text_buf[r++] = c;
++ r &= (N - 1);
++ }
++ }
++ }
++ return 0;
++}
++
++/* interface to jffs2 bbc follows */
++
++#include "jffs2_bbc_framework.h"
++
++#define JFFS2_BBC_LZARI_BLOCK_SIGN {0x73, 0x9a, 0x1c, 0x4d}
++
++static int
++jffs2_bbc_lzari_compressor_init (void);
++
++static void
++jffs2_bbc_lzari_compressor_deinit (void);
++
++static int
++jffs2_bbc_lzari_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen);
++
++static int
++jffs2_bbc_lzari_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime);
++
++static int
++jffs2_bbc_lzari_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen);
++
++static char *
++jffs2_bbc_lzari_proc_info (void);
++
++static int
++jffs2_bbc_lzari_proc_command (char *command);
++
++struct jffs2_bbc_compressor_type jffs2_bbc_lzari = {
++ "lzari",
++ 0,
++ JFFS2_BBC_LZARI_BLOCK_SIGN,
++ jffs2_bbc_lzari_compressor_init,
++ NULL,
++ NULL,
++ jffs2_bbc_lzari_compressor_deinit,
++ jffs2_bbc_lzari_compress,
++ jffs2_bbc_lzari_estimate,
++ jffs2_bbc_lzari_decompress,
++ jffs2_bbc_lzari_proc_info,
++ jffs2_bbc_lzari_proc_command
++};
++
++static int
++jffs2_bbc_lzari_compressor_init (void)
++{
++ return 0;
++}
++
++static void
++jffs2_bbc_lzari_compressor_deinit (void)
++{
++}
++
++static int
++jffs2_bbc_lzari_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen)
++{
++ int retval;
++ unsigned long dst = *dstlen;
++ *(output++) = jffs2_bbc_lzari.block_sign[0];
++ *(output++) = jffs2_bbc_lzari.block_sign[1];
++ dst -= 2;
++ retval = Encode(input, output, sourcelen, &dst);
++ dst += 2;
++ *dstlen = dst;
++ return retval;
++}
++
++static int
++jffs2_bbc_lzari_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime)
++{
++ *dstlen = sourcelen / 2;
++ *readtime = JFFS2_BBC_ZLIB_READ_TIME * 15;
++ *writetime = JFFS2_BBC_ZLIB_WRITE_TIME * 7;
++ return 0;
++}
++
++static int
++jffs2_bbc_lzari_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen)
++{
++ if ( ( *(input++) != (unsigned char)jffs2_bbc_lzari.block_sign[0] ) ||
++ ( *(input++) != (unsigned char)jffs2_bbc_lzari.block_sign[1] )
++ ) {
++ return -1;
++ } else {
++ return Decode(input, output, sourcelen - 2, dstlen);
++ }
++}
++
++static char *
++jffs2_bbc_lzari_proc_info (void)
++{
++ return "Lempel-Ziv-Arithmetic coding compression module";
++}
++
++static int
++jffs2_bbc_lzari_proc_command (char *command)
++{
++ return 0;
++}
++
++struct jffs2_bbc_compressor_type *
++jffs2_bbc_lzari_init (int mode)
++{
++ if (jffs2_bbc_register_compressor (&jffs2_bbc_lzari) == 0)
++ {
++ return &jffs2_bbc_lzari;
++ }
++ else
++ {
++ return NULL;
++ }
++}
++
++void
++jffs2_bbc_lzari_deinit (void)
++{
++ jffs2_bbc_unregister_compressor (&jffs2_bbc_lzari);
++}
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_lzhd_comp.c linux-mips/fs/jffs2/jffs2_bbc_lzhd_comp.c
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_lzhd_comp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_lzhd_comp.c 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,747 @@
++/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
++
++/*
++ jffs2_bbc_lzhd_comp.c -- Lempel-Ziv-(dynamic) Huffman compression module for jffs2
++ Copyright (C) 2004 Patrik Kluba
++ Based on the LZHUF source included in LDS (lossless datacompression sources)
++ Block-compression and bitstream modifications by Patrik Kluba
++ $Header: /openwrt/openwrt/package/linux/kernel-patches/301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*/
++
++/*
++Original copyright follows:
++
++**************************************************************
++ lzhuf.c
++ written by Haruyasu Yoshizaki 11/20/1988
++ some minor changes 4/6/1989
++ comments translated by Haruhiko Okumura 4/7/1989
++**************************************************************
++
++LZHUF.C (c)1989 by Haruyasu Yoshizaki, Haruhiko Okumura, and Kenji Rikitake.
++All rights reserved. Permission granted for non-commercial use.
++
++*/
++
++/*
++
++ 2004-02-18 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
++ Replaced name lzh-d with lzhd
++ Fixed no return value
++
++ 2004-02-16 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
++ Initial release
++
++*/
++
++/* required because of memmove */
++#ifndef __KERNEL__
++ #include <string.h>
++#else
++ #include <linux/string.h>
++#endif
++
++/* lzhuf.c */
++
++#define N 4096 /* size of ring buffer */
++#define F 60 /* upper limit for match_length */
++#define THRESHOLD 2 /* encode string into position and length
++ if match_length is greater than this */
++#define NIL N /* index for root of binary search trees */
++
++static unsigned char
++ text_buf[N + F - 1]; /* ring buffer of size N,
++ with extra F-1 bytes to facilitate string comparison */
++static unsigned long match_position, match_length, /* of longest match. These are
++ set by the InsertNode() procedure. */
++ lson[N + 1], rson[N + 257], dad[N + 1]; /* left & right children &
++ parents -- These constitute binary search trees. */
++
++static void InitTree(void) /* initialize trees */
++{
++ unsigned long i;
++
++ /* For i = 0 to N - 1, rson[i] and lson[i] will be the right and
++ left children of node i. These nodes need not be initialized.
++ Also, dad[i] is the parent of node i. These are initialized to
++ NIL (= N), which stands for 'not used.'
++ For i = 0 to 255, rson[N + i + 1] is the root of the tree
++ for strings that begin with character i. These are initialized
++ to NIL. Note there are 256 trees. */
++
++ for (i = N + 1; i <= N + 256; i++) rson[i] = NIL;
++ for (i = 0; i < N; i++) dad[i] = NIL;
++}
++
++static void InsertNode(unsigned long r)
++ /* Inserts string of length F, text_buf[r..r+F-1], into one of the
++ trees (text_buf[r]'th tree) and returns the longest-match position
++ and length via the global variables match_position and match_length.
++ If match_length = F, then removes the old node in favor of the new
++ one, because the old one will be deleted sooner.
++ Note r plays double role, as tree node and position in buffer. */
++{
++ unsigned long i, p, c;
++ signed long cmp;
++ unsigned char *key;
++
++ cmp = 1; key = &text_buf[r]; p = N + 1 + key[0];
++ rson[r] = lson[r] = NIL; match_length = 0;
++ for ( ; ; ) {
++ if (cmp >= 0) {
++ if (rson[p] != NIL) p = rson[p];
++ else { rson[p] = r; dad[r] = p; return; }
++ } else {
++ if (lson[p] != NIL) p = lson[p];
++ else { lson[p] = r; dad[r] = p; return; }
++ }
++ for (i = 1; i < F; i++)
++ if ((cmp = key[i] - text_buf[p + i]) != 0) break;
++ if (i > THRESHOLD) {
++ if (i > match_length) {
++ match_position = ((r - p) & (N - 1)) - 1;
++ if ((match_length = i) >= F) break;
++ }
++ if (i == match_length) {
++ if ((c = ((r - p) & (N - 1)) - 1) < match_position) {
++ match_position = c;
++ }
++ }
++ }
++ }
++ dad[r] = dad[p]; lson[r] = lson[p]; rson[r] = rson[p];
++ dad[lson[p]] = r; dad[rson[p]] = r;
++ if (rson[dad[p]] == p) rson[dad[p]] = r;
++ else lson[dad[p]] = r;
++ dad[p] = NIL; /* remove p */
++}
++
++static void DeleteNode(unsigned long p) /* deletes node p from tree */
++{
++ unsigned long q;
++
++ if (dad[p] == NIL) return; /* not in tree */
++ if (rson[p] == NIL) q = lson[p];
++ else if (lson[p] == NIL) q = rson[p];
++ else {
++ q = lson[p];
++ if (rson[q] != NIL) {
++ do { q = rson[q]; } while (rson[q] != NIL);
++ rson[dad[q]] = lson[q]; dad[lson[q]] = dad[q];
++ lson[q] = lson[p]; dad[lson[p]] = q;
++ }
++ rson[q] = rson[p]; dad[rson[p]] = q;
++ }
++ dad[q] = dad[p];
++ if (rson[dad[p]] == p) rson[dad[p]] = q; else lson[dad[p]] = q;
++ dad[p] = NIL;
++}
++
++/* Huffman coding */
++
++#define N_CHAR (256 - THRESHOLD + F)
++ /* kinds of characters (character code = 0..N_CHAR-1) */
++#define T (N_CHAR * 2 - 1) /* size of table */
++#define R (T - 1) /* position of root */
++#define MAX_FREQ 0x8000 /* updates tree when the */
++ /* root frequency comes to this value. */
++
++typedef unsigned long uchar; // much-much faster
++
++/* table for encoding and decoding the upper 6 bits of position */
++
++/* for encoding */
++static uchar p_len[64] = {
++ 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
++ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
++};
++
++static uchar p_code[64] = {
++ 0x00, 0x20, 0x30, 0x40, 0x50, 0x58, 0x60, 0x68,
++ 0x70, 0x78, 0x80, 0x88, 0x90, 0x94, 0x98, 0x9C,
++ 0xA0, 0xA4, 0xA8, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC,
++ 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE,
++ 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
++ 0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE,
++ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
++ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
++};
++
++/* for decoding */
++static uchar d_code[256] = {
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
++ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
++ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
++ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
++ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09,
++ 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A,
++ 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
++ 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D,
++ 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F,
++ 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11,
++ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13,
++ 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15,
++ 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17,
++ 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B,
++ 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F,
++ 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23,
++ 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
++ 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
++ 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F,
++ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
++ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
++};
++
++static uchar d_len[256] = {
++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
++ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
++ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
++ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
++ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
++};
++
++static unsigned long freq[T + 1]; /* frequency table */
++
++static unsigned long prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */
++ /* elements [T..T + N_CHAR - 1] which are used to get */
++ /* the positions of leaves corresponding to the codes. */
++
++static unsigned long son[T]; /* pointers to child nodes (son[], son[] + 1) */
++
++/* initialization of tree */
++
++static void StartHuff(void)
++{
++ unsigned long i, j;
++
++ for (i = 0; i < N_CHAR; i++) {
++ freq[i] = 1;
++ son[i] = i + T;
++ prnt[i + T] = i;
++ }
++ i = 0; j = N_CHAR;
++ while (j <= R) {
++ freq[j] = freq[i] + freq[i + 1];
++ son[j] = i;
++ prnt[i] = prnt[i + 1] = j;
++ i += 2; j++;
++ }
++ freq[T] = 0xffff;
++ prnt[R] = 0;
++}
++
++/* reconstruction of tree */
++
++static void reconst(void)
++{
++ unsigned long f, l, i, j, k;
++
++ /* collect leaf nodes in the first half of the table */
++ /* and replace the freq by (freq + 1) / 2. */
++ j = 0;
++ for (i = 0; i < T; i++) {
++ if (son[i] >= T) {
++ freq[j] = (freq[i] + 1) / 2;
++ son[j] = son[i];
++ j++;
++ }
++ }
++ /* begin constructing tree by connecting sons */
++ for (i = 0, j = N_CHAR; j < T; i += 2, j++) {
++ k = i + 1;
++ f = freq[j] = freq[i] + freq[k];
++ for (k = j - 1; f < freq[k]; k--);
++ k++;
++ l = (j - k) * 2;
++ memmove(&freq[k + 1], &freq[k], l*sizeof(unsigned long));
++ freq[k] = f;
++ memmove(&son[k + 1], &son[k], l*sizeof(unsigned long));
++ son[k] = i;
++ }
++ /* connect prnt */
++ for (i = 0; i < T; i++) {
++ if ((k = son[i]) >= T) {
++ prnt[k] = i;
++ } else {
++ prnt[k] = prnt[k + 1] = i;
++ }
++ }
++}
++
++/* increment frequency of given code by one, and update tree */
++
++static void update(unsigned long c)
++{
++ unsigned long i, j, k, l;
++
++ if (freq[R] == MAX_FREQ) {
++ reconst();
++ }
++ c = prnt[c + T];
++ do {
++ k = ++freq[c];
++
++ /* if the order is disturbed, exchange nodes */
++ if (k > freq[l = c + 1]) {
++ while (k > freq[++l]);
++ l--;
++ freq[c] = freq[l];
++ freq[l] = k;
++
++ i = son[c];
++ prnt[i] = l;
++ if (i < T) prnt[i + 1] = l;
++
++ j = son[l];
++ son[l] = i;
++
++ prnt[j] = c;
++ if (j < T) prnt[j + 1] = c;
++ son[c] = j;
++
++ c = l;
++ }
++ } while (c = prnt[c]); /* repeat up to root */
++}
++
++/* modified for block compression */
++/* on return, srclen will contain the number of successfully compressed bytes
++ and dstlen will contain completed compressed bytes */
++
++static int Encode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long *srclen,
++ unsigned long *dstlen)
++{
++ unsigned long c, i, j, k, len, r, s, last_match_length, code_buf_ptr;
++ unsigned char code_buf[17], mask;
++ unsigned char *ip, *op;
++ unsigned long written = 0;
++ unsigned long read = 0;
++ unsigned short putbuf = 0;
++ uchar putlen = 0;
++ unsigned char *srcend = srcbuf + *srclen;
++ unsigned char *dstend = dstbuf + *dstlen;
++ ip = srcbuf;
++ op = dstbuf;
++ StartHuff();
++ InitTree(); /* initialize trees */
++ code_buf[0] = 0; /* code_buf[1..16] saves eight units of code, and
++ code_buf[0] works as eight flags, "1" representing that the unit
++ is an unencoded letter (1 byte), "0" a position-and-length pair
++ (2 bytes). Thus, eight units require at most 16 bytes of code. */
++ code_buf_ptr = mask = 1;
++ s = 0; r = N - F;
++ for (i = s; i < r; i++) text_buf[i] = ' '; /* Clear the buffer with
++ any character that will appear often. */
++ for (len = 0; (len < F) && (ip < srcend); len++)
++ text_buf[r + len] = *(ip++); /* Read F bytes into the last F bytes of
++ the buffer */
++ read = len;
++ for (i = 1; i <= F; i++) InsertNode(r - i); /* Insert the F strings,
++ each of which begins with one or more 'space' characters. Note
++ the order in which these strings are inserted. This way,
++ degenerate trees will be less likely to occur. */
++ InsertNode(r); /* Finally, insert the whole string just read. The
++ global variables match_length and match_position are set. */
++ do {
++ if (match_length > len) match_length = len; /* match_length
++ may be spuriously long near the end of text. */
++ if (match_length <= THRESHOLD) {
++ match_length = 1; /* Not long enough match. Send one byte. */
++ c = text_buf[r];
++ i = 0; j = 0; k = prnt[c + T];
++ do {
++ i >>= 1;
++ /* if node's address is odd-numbered, choose bigger brother node */
++ if (k & 1) i |= 0x8000;
++ j++;
++ } while ((k = prnt[k]) != R);
++ putbuf |= i >> putlen;
++ if ((putlen += j) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf >> 8;
++ if ((putlen -= 8) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf;
++ written += 2;
++ putlen -= 8;
++ putbuf = i << (j - putlen); /**warm**/
++ } else {
++ putbuf <<= 8;
++ written++;
++ }
++ *srclen = read;
++ }
++ update(c);
++ } else {
++ c = 255 - THRESHOLD + match_length;
++ i = 0; j = 0; k = prnt[c + T];
++ do {
++ i >>= 1;
++ /* if node's address is odd-numbered, choose bigger brother node */
++ if (k & 1) i |= 0x8000;
++ j++;
++ } while ((k = prnt[k]) != R);
++ putbuf |= i >> putlen;
++ if ((putlen += j) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf >> 8;
++ if ((putlen -= 8) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf;
++ written += 2;
++ putlen -= 8;
++ putbuf = i << (j - putlen); /**warm**/
++ } else {
++ putbuf <<= 8;
++ written++;
++ }
++ *srclen = read;
++ }
++ update(c);
++ j = p_len[match_position >> 6];
++ i = p_code[match_position >> 6] << 8;
++ putbuf |= i >> putlen;
++ if ((putlen += j) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf >> 8;
++ if ((putlen -= 8) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf;
++ written += 2;
++ putlen -= 8;
++ putbuf = i << (j - putlen); /**hot**/
++ } else {
++ putbuf <<= 8;
++ written++;
++ }
++ *srclen = read;
++ }
++ j = 6;
++ i = (match_position & 0x3f) << 10;
++ putbuf |= i >> putlen;
++ if ((putlen += j) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf >> 8;
++ if ((putlen -= 8) >= 8) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf;
++ written += 2;
++ putlen -= 8;
++ putbuf = i << (j - putlen); /**hot**/
++ } else {
++ putbuf <<= 8;
++ written++;
++ }
++ *srclen = read;
++ }
++ }
++ last_match_length = match_length;
++ for (i = 0; (i < last_match_length) && (ip < srcend); i++) {
++ c = *(ip++);
++ DeleteNode(s);
++ text_buf[s] = c;
++ if (s < F - 1)
++ text_buf[s + N] = c;
++ s = (s + 1) & (N - 1);
++ r = (r + 1) & (N - 1);
++ InsertNode(r);
++ }
++ read += i;
++ while (i++ < last_match_length) {
++ DeleteNode(s);
++ s = (s + 1) & (N - 1);
++ r = (r + 1) & (N - 1);
++ if (--len) InsertNode(r);
++ }
++ } while (len > 0);
++ if (putlen) {
++ if (op >= dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ *(op++) = putbuf >> 8;
++ written++;
++ *srclen = read;
++ }
++ *dstlen = written;
++ return 0;
++}
++
++static int Decode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long srclen,
++ unsigned long dstlen) /* Just the reverse of Encode(). */
++{
++ unsigned long i, r, j, k, c;
++ unsigned char *ip, *op;
++ unsigned char *srcend = srcbuf + srclen;
++ unsigned char *dstend = dstbuf + dstlen;
++ unsigned short getbuf = 0;
++ uchar getlen = 0;
++ ip = srcbuf;
++ op = dstbuf;
++ StartHuff();
++ for (i = 0; i < N - F; i++) text_buf[i] = ' ';
++ r = N - F;
++ while (op < dstend) {
++ c = son[R];
++ /* travel from root to leaf, */
++ /* choosing the smaller child node (son[]) if the read bit is 0, */
++ /* the bigger (son[]+1} if 1 */
++ while (c < T) {
++ while (getlen <= 8) {
++ unsigned short t;
++ t = (ip >= srcend) ? 0 : *(ip++);
++ getbuf |= t << (8 - getlen);
++ getlen += 8;
++ }
++ c += ((signed short)getbuf < 0);
++ getbuf <<= 1;
++ getlen--;
++ c = son[c];
++ }
++ c -= T;
++ update(c);
++ if (c < 256) {
++ if (op >= dstend) return -1;
++ *(op++) = c;
++ text_buf[r++] = c;
++ r &= (N - 1);
++ } else {
++ j = c - 255 + THRESHOLD;
++ while (getlen <= 8) {
++ unsigned short t;
++ t = (ip >= srcend) ? 0 : *(ip++);
++ getbuf |= t << (8 - getlen);
++ getlen += 8;
++ }
++ i = getbuf >> 8;
++ getbuf <<= 8;
++ getlen -= 8;
++ c = d_code[i] << 6;
++ k = d_len[i];
++ /* read lower 6 bits verbatim */
++ k -= 2;
++ while (k--) {
++ while (getlen <= 8) {
++ unsigned short t;
++ t = (ip >= srcend) ? 0 : *(ip++);
++ getbuf |= t << (8 - getlen);
++ getlen += 8;
++ }
++ i = (i << 1) + ((signed short)getbuf < 0);
++ getbuf <<= 1;
++ getlen--;
++ }
++ i = c | (i & 0x3F);
++ i = r - i - 1;
++ i &= (N - 1);
++ for (k = 0; k < j; k++) {
++ c = text_buf[(i + k) & (N - 1)];
++ if (op >= dstend) return -1;
++ *(op++) = c;
++ text_buf[r++] = c;
++ r &= (N - 1);
++ }
++ }
++ }
++ return 0;
++}
++
++/* interface to jffs2 bbc follows */
++
++#include "jffs2_bbc_framework.h"
++
++
++#define JFFS2_BBC_LZHD_BLOCK_SIGN {0x3a, 0x98, 0xf7, 0xda}
++
++static int
++jffs2_bbc_lzhd_compressor_init (void);
++
++static void
++jffs2_bbc_lzhd_compressor_deinit (void);
++
++static int
++jffs2_bbc_lzhd_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen);
++
++static int
++jffs2_bbc_lzhd_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime);
++
++static int
++jffs2_bbc_lzhd_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen);
++
++static char *
++jffs2_bbc_lzhd_proc_info (void);
++
++static int
++jffs2_bbc_lzhd_proc_command (char *command);
++
++struct jffs2_bbc_compressor_type jffs2_bbc_lzhd = {
++ "lzhd",
++ 0,
++ JFFS2_BBC_LZHD_BLOCK_SIGN,
++ jffs2_bbc_lzhd_compressor_init,
++ NULL,
++ NULL,
++ jffs2_bbc_lzhd_compressor_deinit,
++ jffs2_bbc_lzhd_compress,
++ jffs2_bbc_lzhd_estimate,
++ jffs2_bbc_lzhd_decompress,
++ jffs2_bbc_lzhd_proc_info,
++ jffs2_bbc_lzhd_proc_command
++};
++
++static int
++jffs2_bbc_lzhd_compressor_init (void)
++{
++ return 0;
++}
++
++static void
++jffs2_bbc_lzhd_compressor_deinit (void)
++{
++}
++
++static int
++jffs2_bbc_lzhd_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen)
++{
++ int retval;
++ unsigned long dst = *dstlen;
++ *(output++) = jffs2_bbc_lzhd.block_sign[0];
++ *(output++) = jffs2_bbc_lzhd.block_sign[1];
++ dst -= 2;
++ retval = Encode(input, output, sourcelen, &dst);
++ dst += 2;
++ *dstlen = dst;
++ return retval;
++}
++
++static int
++jffs2_bbc_lzhd_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime)
++{
++ *dstlen = sourcelen * 55 / 100;
++ *readtime = JFFS2_BBC_ZLIB_READ_TIME * 8;
++ *writetime = JFFS2_BBC_ZLIB_WRITE_TIME * 65 / 10;
++ return 0;
++}
++
++static int
++jffs2_bbc_lzhd_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen)
++{
++ if ( ( *(input++) != (unsigned char)jffs2_bbc_lzhd.block_sign[0] ) ||
++ ( *(input++) != (unsigned char)jffs2_bbc_lzhd.block_sign[1] )
++ ) {
++ return -1;
++ } else {
++ return Decode(input, output, sourcelen - 2, dstlen);
++ }
++}
++
++static char *
++jffs2_bbc_lzhd_proc_info (void)
++{
++ return "Lempel-Ziv-(dynamic) Huffman compression module";
++}
++
++static int
++jffs2_bbc_lzhd_proc_command (char *command)
++{
++ return 0;
++}
++
++struct jffs2_bbc_compressor_type *
++jffs2_bbc_lzhd_init (int mode)
++{
++ if (jffs2_bbc_register_compressor (&jffs2_bbc_lzhd) == 0)
++ {
++ return &jffs2_bbc_lzhd;
++ }
++ else
++ {
++ return NULL;
++ }
++}
++
++void
++jffs2_bbc_lzhd_deinit (void)
++{
++ jffs2_bbc_unregister_compressor (&jffs2_bbc_lzhd);
++}
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_lzo_comp.c linux-mips/fs/jffs2/jffs2_bbc_lzo_comp.c
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_lzo_comp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_lzo_comp.c 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,2435 @@
++/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
++
++/*
++ jffs2_bbc_lzo_comp.c -- LZO1X-1 (and -999) compression module for jffs2
++ Copyright (C) 2004 Patrik Kluba
++ Based on the original LZO sources
++ $Header: /openwrt/openwrt/package/linux/kernel-patches/301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*/
++
++/*
++ Original copyright notice follows:
++
++ lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm
++ lzo_ptr.h -- low-level pointer constructs
++ lzo_swd.ch -- sliding window dictionary
++ lzoconf.h -- configuration for the LZO real-time data compression library
++ lzo_mchw.ch -- matching functions using a window
++ minilzo.c -- mini subset of the LZO real-time data compression library
++ config1x.h -- configuration for the LZO1X algorithm
++ lzo1x.h -- public interface of the LZO1X compression algorithm
++
++ These files are part of the LZO real-time data compression library.
++
++ Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer
++ All Rights Reserved.
++
++ The LZO library 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.
++
++ The LZO library 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 the LZO library; see the file COPYING.
++ If not, write to the Free Software Foundation, Inc.,
++ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++
++ Markus F.X.J. Oberhumer
++ <markus@oberhumer.com>
++*/
++
++/*
++
++ 2004-02-16 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
++ Initial release
++ -removed all 16 bit code
++ -all sensitive data will be on 4 byte boundary
++ -removed check parts for library use
++ -removed all but LZO1X-* compression
++
++*/
++
++#ifndef __KERNEL__
++ #include <sys/types.h>
++ #include <stddef.h>
++ #include <string.h>
++ #include <limits.h>
++#else
++ #include <linux/kernel.h>
++ #include <linux/types.h>
++ #include <linux/stddef.h>
++ #include <linux/string.h>
++ #define USHRT_MAX 65535
++ /* #define UINT_MAX 4294967295U */
++#endif
++
++/* data type definitions */
++#define U32 unsigned long
++#define S32 signed long
++#define I32 long
++#define U16 unsigned short
++#define S16 signed short
++#define I16 short
++#define U8 unsigned char
++#define S8 signed char
++#define I8 char
++
++/*************************************/
++
++/* lzo_swd.ch */
++
++#define SWD_N N
++#define SWD_F F
++#define SWD_THRESHOLD THRESHOLD
++
++/* shortest unsigned int that 2 * SWD_F + SWD_N (currently 53248) fits in */
++typedef unsigned short swd_uint;
++/* upper limit of that data type */
++#define SWD_UINT_MAX USHRT_MAX
++
++/* minilzo.c */
++
++#define LZO_VERSION_DATE "Jul 12 2002"
++#define LZO_VERSION_STRING "1.08"
++#define LZO_VERSION 0x1080
++
++/* lzo_ptr.h */
++
++/* Integral types that have *exactly* the same number of bits as a lzo_voidp */
++typedef unsigned long lzo_ptr_t;
++typedef long lzo_sptr_t;
++
++
++/*************************************/
++
++/* config1x.h */
++
++#define M1_MAX_OFFSET 0x0400
++#define M2_MAX_OFFSET 0x0800
++#define M3_MAX_OFFSET 0x4000
++#define M4_MAX_OFFSET 0xbfff
++
++#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET)
++
++#define M1_MIN_LEN 2
++#define M1_MAX_LEN 2
++#define M2_MIN_LEN 3
++#define M2_MAX_LEN 8
++#define M3_MIN_LEN 3
++#define M3_MAX_LEN 33
++#define M4_MIN_LEN 3
++#define M4_MAX_LEN 9
++
++#define M1_MARKER 0
++#define M2_MARKER 64
++#define M3_MARKER 32
++#define M4_MARKER 16
++
++#define MIN_LOOKAHEAD (M2_MAX_LEN + 1)
++
++/* minilzo.c */
++
++#define LZO_BYTE(x) ((unsigned char) ((x) & 0xff))
++
++#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b))
++#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b))
++#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
++#define LZO_MIN3(a,b,c) ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c))
++
++#define lzo_sizeof(type) ((lzo_uint) (sizeof(type)))
++
++#define LZO_HIGH(array) ((lzo_uint) (sizeof(array)/sizeof(*(array))))
++
++#define LZO_SIZE(bits) (1u << (bits))
++#define LZO_MASK(bits) (LZO_SIZE(bits) - 1)
++
++#define LZO_LSIZE(bits) (1ul << (bits))
++#define LZO_LMASK(bits) (LZO_LSIZE(bits) - 1)
++
++#define LZO_USIZE(bits) ((lzo_uint) 1 << (bits))
++#define LZO_UMASK(bits) (LZO_USIZE(bits) - 1)
++
++#define LZO_STYPE_MAX(b) (((1l << (8*(b)-2)) - 1l) + (1l << (8*(b)-2)))
++#define LZO_UTYPE_MAX(b) (((1ul << (8*(b)-1)) - 1ul) + (1ul << (8*(b)-1)))
++
++#define _LZO_STRINGIZE(x) #x
++#define _LZO_MEXPAND(x) _LZO_STRINGIZE(x)
++
++#define _LZO_CONCAT2(a,b) a ## b
++#define _LZO_CONCAT3(a,b,c) a ## b ## c
++#define _LZO_CONCAT4(a,b,c,d) a ## b ## c ## d
++#define _LZO_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e
++
++#define _LZO_ECONCAT2(a,b) _LZO_CONCAT2(a,b)
++#define _LZO_ECONCAT3(a,b,c) _LZO_CONCAT3(a,b,c)
++#define _LZO_ECONCAT4(a,b,c,d) _LZO_CONCAT4(a,b,c,d)
++#define _LZO_ECONCAT5(a,b,c,d,e) _LZO_CONCAT5(a,b,c,d,e)
++
++#define lzo_dict_t const lzo_bytep
++#define lzo_dict_p lzo_dict_t *
++#define lzo_moff_t lzo_uint
++
++#define MEMCPY8_DS(dest,src,len) \
++ memcpy(dest,src,len); \
++ dest += len; \
++ src += len
++
++#define MEMCPY_DS(dest,src,len) \
++ do *dest++ = *src++; \
++ while (--len > 0)
++
++#define MEMMOVE_DS(dest,src,len) \
++ do *dest++ = *src++; \
++ while (--len > 0)
++
++#define BZERO8_PTR(s,l,n) memset((s),0,(lzo_uint)(l)*(n))
++
++#define LZO_BASE 65521u
++#define LZO_NMAX 5552
++
++#define LZO_DO1(buf,i) {s1 += buf[i]; s2 += s1;}
++#define LZO_DO2(buf,i) LZO_DO1(buf,i); LZO_DO1(buf,i+1);
++#define LZO_DO4(buf,i) LZO_DO2(buf,i); LZO_DO2(buf,i+2);
++#define LZO_DO8(buf,i) LZO_DO4(buf,i); LZO_DO4(buf,i+4);
++#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8);
++
++#define IS_SIGNED(type) (((type) (-1)) < ((type) 0))
++#define IS_UNSIGNED(type) (((type) (-1)) > ((type) 0))
++
++#define IS_POWER_OF_2(x) (((x) & ((x) - 1)) == 0)
++
++#define D_BITS 14
++#define D_INDEX1(d,p) d = DM((0x21*DX3(p,5,5,6)) >> 5)
++#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
++
++#define LZO_HASH LZO_HASH_LZO_INCREMENTAL_B
++
++#define DL_MIN_LEN M2_MIN_LEN
++
++#define D_SIZE LZO_SIZE(D_BITS)
++#define D_MASK LZO_MASK(D_BITS)
++
++#define D_HIGH ((D_MASK >> 1) + 1)
++
++#define DINDEX1 D_INDEX1
++#define DINDEX2 D_INDEX2
++
++#define DX2(p,s1,s2) \
++ (((((lzo_uint32)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])
++
++#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])
++#define DMS(v,s) ((lzo_uint) (((v) & (D_MASK >> (s))) << (s)))
++#define DM(v) DMS(v,0)
++
++#define DENTRY(p,in) (p)
++#define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex]
++
++#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
++ (m_pos == NULL || (m_off = (lzo_moff_t) (ip - m_pos)) > max_offset)
++
++#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
++ (BOUNDS_CHECKING_OFF_IN_EXPR( \
++ (PTR_LT(m_pos,in) || \
++ (m_off = (lzo_moff_t) PTR_DIFF(ip,m_pos)) <= 0 || \
++ m_off > max_offset) ))
++
++#define BOUNDS_CHECKING_OFF_IN_EXPR(expr) (expr)
++
++#define DD_BITS 0
++#define DD_SIZE LZO_SIZE(DD_BITS)
++#define DD_MASK LZO_MASK(DD_BITS)
++
++#define DL_BITS (D_BITS - DD_BITS)
++#define DL_SIZE LZO_SIZE(DL_BITS)
++#define DL_MASK LZO_MASK(DL_BITS)
++
++#define UPDATE_D(dict,drun,dv,p,in) dict[ DINDEX(dv,p) ] = DENTRY(p,in)
++#define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in)
++#define UPDATE_P(ptr,drun,p,in) (ptr)[0] = DENTRY(p,in)
++
++#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
++#define COPY4(dst,src) __COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src))
++
++#define TEST_IP (ip < ip_end)
++#define TEST_OP (op <= op_end)
++
++#define NEED_IP(x) \
++ if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun
++#define NEED_OP(x) \
++ if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun
++#define TEST_LOOKBEHIND(m_pos,out) if (m_pos < out) goto lookbehind_overrun
++
++/* lzo1x_9x.c */
++
++#define LZO_UINT_MAX UINT_MAX
++#define N M4_MAX_OFFSET
++#define THRESHOLD 1
++#define F 2048
++
++#define SWD_BEST_OFF (LZO_MAX3( M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN ) + 1)
++
++/* ../include/lzoconf.h */
++
++typedef U32 lzo_uint32;
++typedef I32 lzo_int32;
++typedef U32 lzo_uint;
++typedef I32 lzo_int;
++typedef int lzo_bool;
++
++#define lzo_byte U8
++#define lzo_bytep U8 *
++#define lzo_charp char *
++#define lzo_voidp void *
++#define lzo_shortp short *
++#define lzo_ushortp unsigned short *
++#define lzo_uint32p lzo_uint32 *
++#define lzo_int32p lzo_int32 *
++#define lzo_uintp lzo_uint *
++#define lzo_intp lzo_int *
++#define lzo_voidpp lzo_voidp *
++#define lzo_bytepp lzo_bytep *
++#define lzo_sizeof_dict_t sizeof(lzo_bytep)
++
++#define LZO_E_OK 0
++#define LZO_E_ERROR (-1)
++#define LZO_E_OUT_OF_MEMORY (-2) /* not used right now */
++#define LZO_E_NOT_COMPRESSIBLE (-3) /* not used right now */
++#define LZO_E_INPUT_OVERRUN (-4)
++#define LZO_E_OUTPUT_OVERRUN (-5)
++#define LZO_E_LOOKBEHIND_OVERRUN (-6)
++#define LZO_E_EOF_NOT_FOUND (-7)
++#define LZO_E_INPUT_NOT_CONSUMED (-8)
++
++#define LZO_PTR_ALIGN_UP(_ptr,_size) \
++ ((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size)))
++#define LZO_ALIGN(_ptr,_size) LZO_PTR_ALIGN_UP(_ptr,_size)
++
++typedef int
++ (*lzo_compress_t) (const lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len,
++ lzo_voidp wrkmem);
++
++typedef int
++ (*lzo_decompress_t) (const lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len,
++ lzo_voidp wrkmem);
++
++typedef int
++ (*lzo_optimize_t) (lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len,
++ lzo_voidp wrkmem);
++
++typedef int
++ (*lzo_compress_dict_t) (const lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len,
++ lzo_voidp wrkmem,
++ const lzo_byte * dict, lzo_uint dict_len);
++
++typedef int
++ (*lzo_decompress_dict_t) (const lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len,
++ lzo_voidp wrkmem,
++ const lzo_byte * dict, lzo_uint dict_len);
++
++typedef int
++ (*lzo_compress_asm_t) (const lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len,
++ lzo_voidp wrkmem);
++
++typedef int
++ (*lzo_decompress_asm_t) (const lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len,
++ lzo_voidp wrkmem);
++
++typedef void (*lzo_progress_callback_t) (lzo_uint, lzo_uint);
++
++typedef union
++{
++ lzo_bytep p;
++ lzo_uint u;
++} __lzo_pu_u;
++typedef union
++{
++ lzo_bytep p;
++ lzo_uint32 u32;
++} __lzo_pu32_u;
++typedef union
++{
++ void *vp;
++ lzo_bytep bp;
++ lzo_uint32 u32;
++ long l;
++} lzo_align_t;
++
++/* lzo1x.h */
++
++#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
++#define LZO1X_999_MEM_COMPRESS ((lzo_uint32) (14 * 16384L * sizeof(short)))
++
++/* lzo_ptr.h */
++
++#define PTR(a) ((lzo_ptr_t) (a))
++#define PTR_LINEAR(a) PTR(a)
++#define PTR_ALIGNED_4(a) ((PTR_LINEAR(a) & 3) == 0)
++#define PTR_ALIGNED_8(a) ((PTR_LINEAR(a) & 7) == 0)
++#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0)
++#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0)
++#define PTR_LT(a,b) (PTR(a) < PTR(b))
++#define PTR_GE(a,b) (PTR(a) >= PTR(b))
++#define PTR_DIFF(a,b) ((lzo_ptrdiff_t) (PTR(a) - PTR(b)))
++#define pd(a,b) ((lzo_uint) ((a)-(b)))
++
++typedef ptrdiff_t lzo_ptrdiff_t;
++
++typedef union
++{
++ char a_char;
++ unsigned char a_uchar;
++ short a_short;
++ unsigned short a_ushort;
++ int a_int;
++ unsigned int a_uint;
++ long a_long;
++ unsigned long a_ulong;
++ lzo_int a_lzo_int;
++ lzo_uint a_lzo_uint;
++ lzo_int32 a_lzo_int32;
++ lzo_uint32 a_lzo_uint32;
++ ptrdiff_t a_ptrdiff_t;
++ lzo_ptrdiff_t a_lzo_ptrdiff_t;
++ lzo_ptr_t a_lzo_ptr_t;
++ lzo_voidp a_lzo_voidp;
++ void *a_void_p;
++ lzo_bytep a_lzo_bytep;
++ lzo_bytepp a_lzo_bytepp;
++ lzo_uintp a_lzo_uintp;
++ lzo_uint *a_lzo_uint_p;
++ lzo_uint32p a_lzo_uint32p;
++ lzo_uint32 *a_lzo_uint32_p;
++ unsigned char *a_uchar_p;
++ char *a_char_p;
++}
++lzo_full_align_t;
++
++/* lzo_mchw.ch */
++
++typedef struct
++{
++ int init;
++
++ lzo_uint look;
++
++ lzo_uint m_len;
++ lzo_uint m_off;
++
++ lzo_uint last_m_len;
++ lzo_uint last_m_off;
++
++ const lzo_byte *bp;
++ const lzo_byte *ip;
++ const lzo_byte *in;
++ const lzo_byte *in_end;
++ lzo_byte *out;
++
++ lzo_progress_callback_t cb;
++
++ lzo_uint textsize;
++ lzo_uint codesize;
++ lzo_uint printcount;
++
++ unsigned long lit_bytes;
++ unsigned long match_bytes;
++ unsigned long rep_bytes;
++ unsigned long lazy;
++
++ lzo_uint r1_lit;
++ lzo_uint r1_m_len;
++
++ unsigned long m1a_m, m1b_m, m2_m, m3_m, m4_m;
++ unsigned long lit1_r, lit2_r, lit3_r;
++}
++lzo1x_999_t;
++
++#define getbyte(c) ((c).ip < (c).in_end ? *((c).ip)++ : (-1))
++
++/* lzo_swd.ch */
++
++#define SWD_UINT(x) ((swd_uint)(x))
++#define SWD_HSIZE 16384
++#define SWD_MAX_CHAIN 2048
++#define HEAD3(b,p) \
++ (((0x9f5f*(((((lzo_uint32)b[p]<<5)^b[p+1])<<5)^b[p+2]))>>5) & (SWD_HSIZE-1))
++#define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8))
++#define NIL2 SWD_UINT_MAX
++
++typedef struct
++{
++ lzo_uint n;
++ lzo_uint f;
++ lzo_uint threshold;
++
++ lzo_uint max_chain;
++ lzo_uint nice_length;
++ lzo_bool use_best_off;
++ lzo_uint lazy_insert;
++
++ lzo_uint m_len;
++ lzo_uint m_off;
++ lzo_uint look;
++ int b_char;
++
++ lzo_uint best_off[SWD_BEST_OFF];
++
++ lzo1x_999_t *c;
++ lzo_uint m_pos;
++
++ lzo_uint best_pos[SWD_BEST_OFF];
++
++ const lzo_byte *dict;
++ const lzo_byte *dict_end;
++ lzo_uint dict_len;
++
++ lzo_uint ip;
++ lzo_uint bp;
++ lzo_uint rp;
++ lzo_uint b_size;
++
++ unsigned char *b_wrap;
++
++ lzo_uint node_count;
++ lzo_uint first_rp;
++
++ unsigned char b[SWD_N + SWD_F + SWD_F];
++ swd_uint head3[SWD_HSIZE];
++ swd_uint succ3[SWD_N + SWD_F];
++ swd_uint best3[SWD_N + SWD_F];
++ swd_uint llen3[SWD_HSIZE];
++
++ swd_uint head2[65536L];
++}
++lzo1x_999_swd_t;
++
++#define s_head3(s,key) s->head3[key]
++#define swd_pos2off(s,pos) \
++ (s->bp > (pos) ? s->bp - (pos) : s->b_size - ((pos) - s->bp))
++
++static __inline__ void
++swd_getbyte (lzo1x_999_swd_t * s)
++{
++ int c;
++
++ if ((c = getbyte (*(s->c))) < 0)
++ {
++ if (s->look > 0)
++ --s->look;
++ }
++ else
++ {
++ s->b[s->ip] = LZO_BYTE (c);
++ if (s->ip < s->f)
++ s->b_wrap[s->ip] = LZO_BYTE (c);
++ }
++ if (++s->ip == s->b_size)
++ s->ip = 0;
++ if (++s->bp == s->b_size)
++ s->bp = 0;
++ if (++s->rp == s->b_size)
++ s->rp = 0;
++}
++
++static void
++swd_initdict (lzo1x_999_swd_t * s, const lzo_byte * dict, lzo_uint dict_len)
++{
++ s->dict = s->dict_end = NULL;
++ s->dict_len = 0;
++
++ if (!dict || dict_len <= 0)
++ return;
++ if (dict_len > s->n)
++ {
++ dict += dict_len - s->n;
++ dict_len = s->n;
++ }
++
++ s->dict = dict;
++ s->dict_len = dict_len;
++ s->dict_end = dict + dict_len;
++ memcpy (s->b, dict, dict_len);
++ s->ip = dict_len;
++}
++
++static void
++swd_insertdict (lzo1x_999_swd_t * s, lzo_uint node, lzo_uint len)
++{
++ lzo_uint key;
++
++ s->node_count = s->n - len;
++ s->first_rp = node;
++
++ while (len-- > 0)
++ {
++ key = HEAD3 (s->b, node);
++ s->succ3[node] = s_head3 (s, key);
++ s->head3[key] = SWD_UINT (node);
++ s->best3[node] = SWD_UINT (s->f + 1);
++ s->llen3[key]++;
++
++ key = HEAD2 (s->b, node);
++ s->head2[key] = SWD_UINT (node);
++
++ node++;
++ }
++}
++
++static int
++swd_init (lzo1x_999_swd_t * s, const lzo_byte * dict, lzo_uint dict_len)
++{
++
++ s->n = SWD_N;
++ s->f = SWD_F;
++ s->threshold = SWD_THRESHOLD;
++
++
++
++ s->max_chain = SWD_MAX_CHAIN;
++ s->nice_length = SWD_F;
++ s->use_best_off = 0;
++ s->lazy_insert = 0;
++
++ s->b_size = s->n + s->f;
++ if (2 * s->f >= s->n || s->b_size + s->f >= NIL2)
++ return LZO_E_ERROR;
++ s->b_wrap = s->b + s->b_size;
++ s->node_count = s->n;
++
++ memset (s->llen3, 0, sizeof (s->llen3[0]) * SWD_HSIZE);
++ memset (s->head2, 0xff, sizeof (s->head2[0]) * 65536L);
++
++ s->ip = 0;
++ swd_initdict (s, dict, dict_len);
++ s->bp = s->ip;
++ s->first_rp = s->ip;
++
++ s->look = (lzo_uint) (s->c->in_end - s->c->ip);
++ if (s->look > 0)
++ {
++ if (s->look > s->f)
++ s->look = s->f;
++ memcpy (&s->b[s->ip], s->c->ip, s->look);
++ s->c->ip += s->look;
++ s->ip += s->look;
++ }
++
++ if (s->ip == s->b_size)
++ s->ip = 0;
++
++ if (s->look >= 2 && s->dict_len > 0)
++ swd_insertdict (s, 0, s->dict_len);
++
++ s->rp = s->first_rp;
++ if (s->rp >= s->node_count)
++ s->rp -= s->node_count;
++ else
++ s->rp += s->b_size - s->node_count;
++
++ return LZO_E_OK;
++}
++
++static __inline__ void
++swd_remove_node (lzo1x_999_swd_t * s, lzo_uint node)
++{
++ if (s->node_count == 0)
++ {
++ lzo_uint key;
++
++ key = HEAD3 (s->b, node);
++
++ --s->llen3[key];
++
++ key = HEAD2 (s->b, node);
++
++ if ((lzo_uint) s->head2[key] == node)
++ s->head2[key] = NIL2;
++ }
++ else
++ --s->node_count;
++}
++
++static void
++swd_accept (lzo1x_999_swd_t * s, lzo_uint n)
++{
++
++ while (n--)
++ {
++ lzo_uint key;
++
++ swd_remove_node (s, s->rp);
++
++ key = HEAD3 (s->b, s->bp);
++ s->succ3[s->bp] = s_head3 (s, key);
++ s->head3[key] = SWD_UINT (s->bp);
++ s->best3[s->bp] = SWD_UINT (s->f + 1);
++ s->llen3[key]++;
++
++ key = HEAD2 (s->b, s->bp);
++ s->head2[key] = SWD_UINT (s->bp);;
++
++ swd_getbyte (s);
++ }
++}
++
++static void
++swd_search (lzo1x_999_swd_t * s, lzo_uint node, lzo_uint cnt)
++{
++ const unsigned char *p1;
++ const unsigned char *p2;
++ const unsigned char *px;
++
++ lzo_uint m_len = s->m_len;
++ const unsigned char *b = s->b;
++ const unsigned char *bp = s->b + s->bp;
++ const unsigned char *bx = s->b + s->bp + s->look;
++ unsigned char scan_end1;
++
++ scan_end1 = bp[m_len - 1];
++ for (; cnt-- > 0; node = s->succ3[node])
++ {
++ p1 = bp;
++ p2 = b + node;
++ px = bx;
++
++ if (p2[m_len - 1] == scan_end1 &&
++ p2[m_len] == p1[m_len] &&
++ p2[0] == p1[0] && p2[1] == p1[1])
++ {
++ lzo_uint i;
++
++ p1 += 2;
++ p2 += 2;
++ do
++ {
++ }
++ while (++p1 < px && *p1 == *++p2);
++
++ i = p1 - bp;
++
++ if (i < SWD_BEST_OFF)
++ {
++ if (s->best_pos[i] == 0)
++ s->best_pos[i] = node + 1;
++ }
++
++ if (i > m_len)
++ {
++ s->m_len = m_len = i;
++ s->m_pos = node;
++ if (m_len == s->look)
++ return;
++ if (m_len >= s->nice_length)
++ return;
++ if (m_len > (lzo_uint) s->best3[node])
++ return;
++ scan_end1 = bp[m_len - 1];
++ }
++ }
++ }
++}
++
++static lzo_bool
++swd_search2 (lzo1x_999_swd_t * s)
++{
++ lzo_uint key;
++
++ key = s->head2[HEAD2 (s->b, s->bp)];
++ if (key == NIL2)
++ return 0;
++
++ if (s->best_pos[2] == 0)
++ s->best_pos[2] = key + 1;
++
++ if (s->m_len < 2)
++ {
++ s->m_len = 2;
++ s->m_pos = key;
++ }
++ return 1;
++}
++
++static void
++swd_findbest (lzo1x_999_swd_t * s)
++{
++ lzo_uint key;
++ lzo_uint cnt, node;
++ lzo_uint len;
++
++ key = HEAD3 (s->b, s->bp);
++ node = s->succ3[s->bp] = s_head3 (s, key);
++ cnt = s->llen3[key]++;
++
++ if (cnt > s->max_chain && s->max_chain > 0)
++ cnt = s->max_chain;
++ s->head3[key] = SWD_UINT (s->bp);
++
++ s->b_char = s->b[s->bp];
++ len = s->m_len;
++ if (s->m_len >= s->look)
++ {
++ if (s->look == 0)
++ s->b_char = -1;
++ s->m_off = 0;
++ s->best3[s->bp] = SWD_UINT (s->f + 1);
++ }
++ else
++ {
++
++ if (swd_search2 (s))
++
++ if (s->look >= 3)
++ swd_search (s, node, cnt);
++ if (s->m_len > len)
++ s->m_off = swd_pos2off (s, s->m_pos);
++ s->best3[s->bp] = SWD_UINT (s->m_len);
++
++ if (s->use_best_off)
++ {
++ int i;
++ for (i = 2; i < SWD_BEST_OFF; i++)
++ if (s->best_pos[i] > 0)
++ s->best_off[i] =
++ swd_pos2off (s,
++ s->best_pos[i] -
++ 1);
++ else
++ s->best_off[i] = 0;
++ }
++
++ }
++
++ swd_remove_node (s, s->rp);
++
++ key = HEAD2 (s->b, s->bp);
++ s->head2[key] = SWD_UINT (s->bp);
++
++}
++
++/* lzo_mchw.ch */
++
++static int
++init_match (lzo1x_999_t * c, lzo1x_999_swd_t * s,
++ const lzo_byte * dict, lzo_uint dict_len, lzo_uint32 flags)
++{
++ int r;
++
++ c->init = 1;
++
++ s->c = c;
++
++ c->last_m_len = c->last_m_off = 0;
++
++ c->textsize = c->codesize = c->printcount = 0;
++ c->lit_bytes = c->match_bytes = c->rep_bytes = 0;
++ c->lazy = 0;
++
++ r = swd_init (s, dict, dict_len);
++ if (r != 0)
++ return r;
++
++ s->use_best_off = (flags & 1) ? 1 : 0;
++ return r;
++}
++
++static int
++find_match (lzo1x_999_t * c, lzo1x_999_swd_t * s,
++ lzo_uint this_len, lzo_uint skip)
++{
++ if (skip > 0)
++ {
++ swd_accept (s, this_len - skip);
++ c->textsize += this_len - skip + 1;
++ }
++ else
++ {
++ c->textsize += this_len - skip;
++ }
++
++ s->m_len = 1;
++ s->m_len = 1;
++
++ if (s->use_best_off)
++ memset (s->best_pos, 0, sizeof (s->best_pos));
++
++ swd_findbest (s);
++ c->m_len = s->m_len;
++ c->m_off = s->m_off;
++
++ swd_getbyte (s);
++
++ if (s->b_char < 0)
++ {
++ c->look = 0;
++ c->m_len = 0;
++ }
++ else
++ {
++ c->look = s->look + 1;
++ }
++ c->bp = c->ip - c->look;
++
++ if (c->cb && c->textsize > c->printcount)
++ {
++ (*c->cb) (c->textsize, c->codesize);
++ c->printcount += 1024;
++ }
++
++ return LZO_E_OK;
++}
++
++/* lzo1x_9x.c */
++
++static lzo_byte *
++code_match (lzo1x_999_t * c, lzo_byte * op, lzo_uint m_len, lzo_uint m_off)
++{
++ lzo_uint x_len = m_len;
++ lzo_uint x_off = m_off;
++
++ c->match_bytes += m_len;
++
++ if (m_len == 2)
++ {
++ m_off -= 1;
++
++ *op++ = LZO_BYTE (M1_MARKER | ((m_off & 3) << 2));
++ *op++ = LZO_BYTE (m_off >> 2);
++
++ c->m1a_m++;
++ }
++
++ else if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
++
++ {
++
++ m_off -= 1;
++ *op++ = LZO_BYTE (((m_len - 1) << 5) | ((m_off & 7) << 2));
++ *op++ = LZO_BYTE (m_off >> 3);
++ c->m2_m++;
++ }
++ else if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET
++ && c->r1_lit >= 4)
++ {
++ m_off -= 1 + M2_MAX_OFFSET;
++
++ *op++ = LZO_BYTE (M1_MARKER | ((m_off & 3) << 2));
++ *op++ = LZO_BYTE (m_off >> 2);
++
++ c->m1b_m++;
++ }
++ else if (m_off <= M3_MAX_OFFSET)
++ {
++ m_off -= 1;
++ if (m_len <= M3_MAX_LEN)
++ *op++ = LZO_BYTE (M3_MARKER | (m_len - 2));
++ else
++ {
++ m_len -= M3_MAX_LEN;
++ *op++ = M3_MARKER | 0;
++ while (m_len > 255)
++ {
++ m_len -= 255;
++ *op++ = 0;
++ }
++ *op++ = LZO_BYTE (m_len);
++ }
++
++ *op++ = LZO_BYTE (m_off << 2);
++ *op++ = LZO_BYTE (m_off >> 6);
++
++ c->m3_m++;
++ }
++ else
++ {
++ lzo_uint k;
++
++ m_off -= 0x4000;
++ k = (m_off & 0x4000) >> 11;
++ if (m_len <= M4_MAX_LEN)
++ *op++ = LZO_BYTE (M4_MARKER | k | (m_len - 2));
++ else
++ {
++ m_len -= M4_MAX_LEN;
++ *op++ = LZO_BYTE (M4_MARKER | k | 0);
++ while (m_len > 255)
++ {
++ m_len -= 255;
++ *op++ = 0;
++ }
++ *op++ = LZO_BYTE (m_len);
++ }
++
++ *op++ = LZO_BYTE (m_off << 2);
++ *op++ = LZO_BYTE (m_off >> 6);
++
++ c->m4_m++;
++ }
++
++ c->last_m_len = x_len;
++ c->last_m_off = x_off;
++ return op;
++}
++
++static lzo_byte *
++STORE_RUN (lzo1x_999_t * c, lzo_byte * op, const lzo_byte * ii, lzo_uint t)
++{
++ c->lit_bytes += t;
++
++ if (op == c->out && t <= 238)
++ {
++ *op++ = LZO_BYTE (17 + t);
++ }
++ else if (t <= 3)
++ {
++ op[-2] |= LZO_BYTE (t);
++
++ c->lit1_r++;
++ }
++ else if (t <= 18)
++ {
++ *op++ = LZO_BYTE (t - 3);
++ c->lit2_r++;
++ }
++ else
++ {
++ lzo_uint tt = t - 18;
++
++ *op++ = 0;
++ while (tt > 255)
++ {
++ tt -= 255;
++ *op++ = 0;
++ }
++ *op++ = LZO_BYTE (tt);
++ c->lit3_r++;
++ }
++ do
++ *op++ = *ii++;
++ while (--t > 0);
++
++ return op;
++}
++
++static lzo_byte *
++code_run (lzo1x_999_t * c, lzo_byte * op, const lzo_byte * ii,
++ lzo_uint lit, lzo_uint m_len)
++{
++ if (lit > 0)
++ {
++ op = STORE_RUN (c, op, ii, lit);
++ c->r1_m_len = m_len;
++ c->r1_lit = lit;
++ }
++ else
++ {
++ c->r1_m_len = 0;
++ c->r1_lit = 0;
++ }
++
++ return op;
++}
++
++static int
++len_of_coded_match (lzo_uint m_len, lzo_uint m_off, lzo_uint lit)
++{
++ int n = 4;
++
++ if (m_len < 2)
++ return -1;
++ if (m_len == 2)
++ return (m_off <= M1_MAX_OFFSET && lit > 0
++ && lit < 4) ? 2 : -1;
++ if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
++ return 2;
++ if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && lit >= 4)
++ return 2;
++ if (m_off <= M3_MAX_OFFSET)
++ {
++ if (m_len <= M3_MAX_LEN)
++ return 3;
++ m_len -= M3_MAX_LEN;
++ while (m_len > 255)
++ {
++ m_len -= 255;
++ n++;
++ }
++ return n;
++ }
++ if (m_off <= M4_MAX_OFFSET)
++ {
++ if (m_len <= M4_MAX_LEN)
++ return 3;
++ m_len -= M4_MAX_LEN;
++ while (m_len > 255)
++ {
++ m_len -= 255;
++ n++;
++ }
++ return n;
++ }
++ return -1;
++}
++
++static lzo_int
++min_gain (lzo_uint ahead, lzo_uint lit1, lzo_uint lit2, int l1, int l2,
++ int l3)
++{
++ lzo_int lazy_match_min_gain = 0;
++
++ lazy_match_min_gain += ahead;
++
++ if (lit1 <= 3)
++ lazy_match_min_gain += (lit2 <= 3) ? 0 : 2;
++ else if (lit1 <= 18)
++ lazy_match_min_gain += (lit2 <= 18) ? 0 : 1;
++
++ lazy_match_min_gain += (l2 - l1) * 2;
++ if (l3 > 0)
++ lazy_match_min_gain -= (ahead - l3) * 2;
++
++ if (lazy_match_min_gain < 0)
++ lazy_match_min_gain = 0;
++
++ return lazy_match_min_gain;
++}
++
++static void
++better_match (const lzo1x_999_swd_t * swd, lzo_uint * m_len, lzo_uint * m_off)
++{
++ if (*m_len <= M2_MIN_LEN)
++ return;
++
++ if (*m_off <= M2_MAX_OFFSET)
++ return;
++
++ if (*m_off > M2_MAX_OFFSET &&
++ *m_len >= M2_MIN_LEN + 1 && *m_len <= M2_MAX_LEN + 1 &&
++ swd->best_off[*m_len - 1]
++ && swd->best_off[*m_len - 1] <= M2_MAX_OFFSET)
++ {
++ *m_len = *m_len - 1;
++ *m_off = swd->best_off[*m_len];
++ return;
++ }
++
++ if (*m_off > M3_MAX_OFFSET &&
++ *m_len >= M4_MAX_LEN + 1 && *m_len <= M2_MAX_LEN + 2 &&
++ swd->best_off[*m_len - 2]
++ && swd->best_off[*m_len - 2] <= M2_MAX_OFFSET)
++ {
++ *m_len = *m_len - 2;
++ *m_off = swd->best_off[*m_len];
++ return;
++ }
++
++ if (*m_off > M3_MAX_OFFSET &&
++ *m_len >= M4_MAX_LEN + 1 && *m_len <= M3_MAX_LEN + 1 &&
++ swd->best_off[*m_len - 1]
++ && swd->best_off[*m_len - 1] <= M3_MAX_OFFSET)
++ {
++ *m_len = *m_len - 1;
++ *m_off = swd->best_off[*m_len];
++ }
++
++}
++
++/* minilzo.c */
++
++static lzo_bool
++lzo_assert (int expr)
++{
++ return (expr) ? 1 : 0;
++}
++
++/* lzo1x_9x.c */
++
++static int
++lzo1x_999_compress_internal (const lzo_byte * in, lzo_uint in_len,
++ lzo_byte * out, lzo_uintp out_len,
++ lzo_voidp wrkmem,
++ const lzo_byte * dict, lzo_uint dict_len,
++ lzo_progress_callback_t cb,
++ int try_lazy,
++ lzo_uint good_length,
++ lzo_uint max_lazy,
++ lzo_uint nice_length,
++ lzo_uint max_chain, lzo_uint32 flags)
++{
++ lzo_byte *op;
++ const lzo_byte *ii;
++ lzo_uint lit;
++ lzo_uint m_len, m_off;
++ lzo1x_999_t cc;
++ lzo1x_999_t *const c = &cc;
++ lzo1x_999_swd_t *const swd = (lzo1x_999_swd_t *) wrkmem;
++ int r;
++
++ if (!lzo_assert
++ (LZO1X_999_MEM_COMPRESS >= lzo_sizeof (lzo1x_999_swd_t)))
++ return LZO_E_ERROR;
++
++ if (try_lazy < 0)
++ try_lazy = 1;
++
++ if (good_length <= 0)
++ good_length = 32;
++
++ if (max_lazy <= 0)
++ max_lazy = 32;
++
++ if (nice_length <= 0)
++ nice_length = 0;
++
++ if (max_chain <= 0)
++ max_chain = SWD_MAX_CHAIN;
++
++ c->init = 0;
++ c->ip = c->in = in;
++ c->in_end = in + in_len;
++ c->out = out;
++ c->cb = cb;
++ c->m1a_m = c->m1b_m = c->m2_m = c->m3_m = c->m4_m = 0;
++ c->lit1_r = c->lit2_r = c->lit3_r = 0;
++
++ op = out;
++ ii = c->ip;
++ lit = 0;
++ c->r1_lit = c->r1_m_len = 0;
++
++ r = init_match (c, swd, dict, dict_len, flags);
++ if (r != 0)
++ return r;
++ if (max_chain > 0)
++ swd->max_chain = max_chain;
++ if (nice_length > 0)
++ swd->nice_length = nice_length;
++
++ r = find_match (c, swd, 0, 0);
++ if (r != 0)
++ return r;
++ while (c->look > 0)
++ {
++ lzo_uint ahead;
++ lzo_uint max_ahead;
++ int l1, l2, l3;
++
++ c->codesize = op - out;
++
++ m_len = c->m_len;
++ m_off = c->m_off;
++
++ if (lit == 0)
++ ii = c->bp;
++
++ if (m_len < 2 ||
++ (m_len == 2
++ && (m_off > M1_MAX_OFFSET || lit == 0 || lit >= 4))
++ || (m_len == 2 && op == out) || (op == out && lit == 0))
++ {
++
++ m_len = 0;
++ }
++ else if (m_len == M2_MIN_LEN)
++ {
++
++ if (m_off > MX_MAX_OFFSET && lit >= 4)
++ m_len = 0;
++ }
++
++ if (m_len == 0)
++ {
++
++ lit++;
++ swd->max_chain = max_chain;
++ r = find_match (c, swd, 1, 0);
++ continue;
++ }
++
++ if (swd->use_best_off)
++ better_match (swd, &m_len, &m_off);
++
++ ahead = 0;
++ if (try_lazy <= 0 || m_len >= max_lazy)
++ {
++
++ l1 = 0;
++ max_ahead = 0;
++ }
++ else
++ {
++
++ l1 = len_of_coded_match (m_len, m_off, lit);
++
++ max_ahead = LZO_MIN (try_lazy, l1 - 1);
++
++ }
++
++ while (ahead < max_ahead && c->look > m_len)
++ {
++ lzo_int lazy_match_min_gain;
++
++ if (m_len >= good_length)
++ swd->max_chain = max_chain >> 2;
++ else
++ swd->max_chain = max_chain;
++ r = find_match (c, swd, 1, 0);
++ ahead++;
++
++ if (c->m_len < m_len)
++ continue;
++
++ if (c->m_len == m_len && c->m_off >= m_off)
++ continue;
++
++ if (swd->use_best_off)
++ better_match (swd, &c->m_len, &c->m_off);
++
++ l2 = len_of_coded_match (c->m_len, c->m_off,
++ lit + ahead);
++ if (l2 < 0)
++ continue;
++
++ l3 = (op == out) ? -1 : len_of_coded_match (ahead,
++ m_off,
++ lit);
++
++ lazy_match_min_gain =
++ min_gain (ahead, lit, lit + ahead, l1, l2,
++ l3);
++ if (c->m_len >= m_len + lazy_match_min_gain)
++ {
++ c->lazy++;
++
++ if (l3 > 0)
++ {
++
++ op = code_run (c, op, ii, lit, ahead);
++ lit = 0;
++
++ op = code_match (c, op, ahead, m_off);
++ }
++ else
++ {
++ lit += ahead;
++ }
++ goto lazy_match_done;
++ }
++ }
++
++ op = code_run (c, op, ii, lit, m_len);
++ lit = 0;
++
++ op = code_match (c, op, m_len, m_off);
++ swd->max_chain = max_chain;
++ r = find_match (c, swd, m_len, 1 + ahead);
++
++ lazy_match_done:;
++ }
++
++ if (lit > 0)
++ op = STORE_RUN (c, op, ii, lit);
++
++ *op++ = M4_MARKER | 1;
++ *op++ = 0;
++ *op++ = 0;
++
++ c->codesize = op - out;
++
++ *out_len = op - out;
++
++ if (c->cb)
++ (*c->cb) (c->textsize, c->codesize);
++
++ return LZO_E_OK;
++}
++
++static int
++lzo1x_999_compress_level (const lzo_byte * in, lzo_uint in_len,
++ lzo_byte * out, lzo_uintp out_len,
++ lzo_voidp wrkmem,
++ const lzo_byte * dict, lzo_uint dict_len,
++ lzo_progress_callback_t cb, int compression_level)
++{
++ static const struct
++ {
++ int try_lazy;
++ lzo_uint good_length;
++ lzo_uint max_lazy;
++ lzo_uint nice_length;
++ lzo_uint max_chain;
++ lzo_uint32 flags;
++ } c[9] =
++ {
++ {
++ 0, 0, 0, 8, 4, 0},
++ {
++ 0, 0, 0, 16, 8, 0},
++ {
++ 0, 0, 0, 32, 16, 0},
++ {
++ 1, 4, 4, 16, 16, 0},
++ {
++ 1, 8, 16, 32, 32, 0},
++ {
++ 1, 8, 16, 128, 128, 0},
++ {
++ 2, 8, 32, 128, 256, 0},
++ {
++ 2, 32, 128, F, 2048, 1},
++ {
++ 2, F, F, F, 4096, 1}
++ };
++
++ if (compression_level < 1 || compression_level > 9)
++ return LZO_E_ERROR;
++
++ compression_level -= 1;
++ return lzo1x_999_compress_internal (in, in_len, out, out_len, wrkmem,
++ dict, dict_len, cb,
++ c[compression_level].try_lazy,
++ c[compression_level].good_length,
++ c[compression_level].max_lazy,
++ 0,
++ c[compression_level].max_chain,
++ c[compression_level].flags);
++}
++
++static int
++lzo1x_999_compress (const lzo_byte * in, lzo_uint in_len,
++ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
++{
++ return lzo1x_999_compress_level (in, in_len, out, out_len, wrkmem,
++ NULL, 0, 0, 8);
++}
++
++/* minilzo.c */
++
++static const lzo_byte __lzo_copyright[] = LZO_VERSION_STRING;
++
++static lzo_uint
++_lzo1x_1_do_compress (const lzo_byte * in, lzo_uint in_len,
++ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
++{
++
++ register const lzo_byte *ip;
++
++ lzo_byte *op;
++ const lzo_byte *const in_end = in + in_len;
++ const lzo_byte *const ip_end = in + in_len - 8 - 5;
++ const lzo_byte *ii;
++ lzo_dict_p const dict = (lzo_dict_p) wrkmem;
++
++ op = out;
++ ip = in;
++ ii = ip;
++
++ ip += 4;
++ for (;;)
++ {
++ register const lzo_byte *m_pos;
++
++ lzo_uint m_off;
++ lzo_uint m_len;
++ lzo_uint dindex;
++
++ DINDEX1 (dindex, ip);
++ GINDEX (m_pos, m_off, dict, dindex, in);
++ if (LZO_CHECK_MPOS_NON_DET
++ (m_pos, m_off, in, ip, M4_MAX_OFFSET))
++ goto literal;
++
++ if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
++ goto try_match;
++ DINDEX2 (dindex, ip);
++ GINDEX (m_pos, m_off, dict, dindex, in);
++
++ if (LZO_CHECK_MPOS_NON_DET
++ (m_pos, m_off, in, ip, M4_MAX_OFFSET))
++ goto literal;
++ if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
++ goto try_match;
++ goto literal;
++
++ try_match:
++ if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
++ {
++ }
++ else
++ {
++ if (m_pos[2] == ip[2])
++ {
++ goto match;
++ }
++ else
++ {
++ }
++ }
++
++ literal:
++ UPDATE_I (dict, 0, dindex, ip, in);
++ ++ip;
++ if (ip >= ip_end)
++ break;
++ continue;
++
++ match:
++ UPDATE_I (dict, 0, dindex, ip, in);
++
++ if (pd (ip, ii) > 0)
++ {
++ register lzo_uint t = pd (ip, ii);
++
++ if (t <= 3)
++ {
++ op[-2] |= LZO_BYTE (t);
++ }
++ else if (t <= 18)
++ *op++ = LZO_BYTE (t - 3);
++ else
++ {
++ register lzo_uint tt = t - 18;
++
++ *op++ = 0;
++ while (tt > 255)
++ {
++ tt -= 255;
++ *op++ = 0;
++ }
++ *op++ = LZO_BYTE (tt);;
++ }
++ do
++ *op++ = *ii++;
++ while (--t > 0);
++ }
++
++ ip += 3;
++ if (m_pos[3] != *ip++ || m_pos[4] != *ip++
++ || m_pos[5] != *ip++ || m_pos[6] != *ip++
++ || m_pos[7] != *ip++ || m_pos[8] != *ip++)
++ {
++ --ip;
++ m_len = ip - ii;
++
++ if (m_off <= M2_MAX_OFFSET)
++ {
++ m_off -= 1;
++
++ *op++ = LZO_BYTE (((m_len -
++ 1) << 5) | ((m_off & 7) <<
++ 2));
++ *op++ = LZO_BYTE (m_off >> 3);
++ }
++ else if (m_off <= M3_MAX_OFFSET)
++ {
++ m_off -= 1;
++ *op++ = LZO_BYTE (M3_MARKER | (m_len - 2));
++ goto m3_m4_offset;
++ }
++ else
++
++ {
++ m_off -= 0x4000;
++
++ *op++ = LZO_BYTE (M4_MARKER |
++ ((m_off & 0x4000) >> 11) |
++ (m_len - 2));
++ goto m3_m4_offset;
++ }
++ }
++ else
++ {
++ {
++ const lzo_byte *end = in_end;
++ const lzo_byte *m = m_pos + M2_MAX_LEN + 1;
++ while (ip < end && *m == *ip)
++ m++, ip++;
++ m_len = (ip - ii);
++ }
++
++
++ if (m_off <= M3_MAX_OFFSET)
++ {
++ m_off -= 1;
++ if (m_len <= 33)
++ *op++ = LZO_BYTE (M3_MARKER |
++ (m_len - 2));
++ else
++ {
++ m_len -= 33;
++ *op++ = M3_MARKER | 0;
++ goto m3_m4_len;
++ }
++ }
++ else
++ {
++ m_off -= 0x4000;
++
++ if (m_len <= M4_MAX_LEN)
++ *op++ = LZO_BYTE (M4_MARKER |
++ ((m_off & 0x4000) >>
++ 11) | (m_len - 2));
++
++ else
++ {
++ m_len -= M4_MAX_LEN;
++ *op++ = LZO_BYTE (M4_MARKER |
++ ((m_off & 0x4000) >>
++ 11));
++ m3_m4_len:
++ while (m_len > 255)
++ {
++ m_len -= 255;
++ *op++ = 0;
++ }
++
++ *op++ = LZO_BYTE (m_len);
++ }
++ }
++
++ m3_m4_offset:
++ *op++ = LZO_BYTE ((m_off & 63) << 2);
++ *op++ = LZO_BYTE (m_off >> 6);
++ }
++ ii = ip;
++ if (ip >= ip_end)
++ break;
++ }
++
++ *out_len = op - out;
++ return pd (in_end, ii);
++}
++
++static int
++lzo1x_1_compress (const lzo_byte * in, lzo_uint in_len,
++ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
++{
++ lzo_byte *op = out;
++ lzo_uint t;
++
++ if (in_len <= M2_MAX_LEN + 5)
++ t = in_len;
++ else
++ {
++ t = _lzo1x_1_do_compress (in, in_len, op, out_len, wrkmem);
++ op += *out_len;
++ }
++
++ if (t > 0)
++ {
++ const lzo_byte *ii = in + in_len - t;
++
++ if (op == out && t <= 238)
++ *op++ = LZO_BYTE (17 + t);
++ else if (t <= 3)
++ op[-2] |= LZO_BYTE (t);
++ else if (t <= 18)
++ *op++ = LZO_BYTE (t - 3);
++ else
++ {
++ lzo_uint tt = t - 18;
++
++ *op++ = 0;
++ while (tt > 255)
++ {
++ tt -= 255;
++ *op++ = 0;
++ }
++
++ *op++ = LZO_BYTE (tt);
++ }
++ do
++ *op++ = *ii++;
++ while (--t > 0);
++ }
++
++ *op++ = M4_MARKER | 1;
++ *op++ = 0;
++ *op++ = 0;
++
++ *out_len = op - out;
++ return 0;
++}
++
++static int
++lzo1x_decompress (const lzo_byte * in, lzo_uint in_len,
++ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
++{
++ register lzo_byte *op;
++ register const lzo_byte *ip;
++ register lzo_uint t;
++
++ register const lzo_byte *m_pos;
++
++ const lzo_byte *const ip_end = in + in_len;
++ lzo_byte *const op_end = out + *out_len;
++
++ *out_len = 0;
++
++ op = out;
++ ip = in;
++
++ if (*ip > 17)
++ {
++ t = *ip++ - 17;
++ if (t < 4)
++ goto match_next;
++ NEED_OP (t);
++ NEED_IP (t + 1);
++ do
++ *op++ = *ip++;
++ while (--t > 0);
++ goto first_literal_run;
++ }
++
++ while (TEST_IP && TEST_OP)
++ {
++ t = *ip++;
++ if (t >= 16)
++ goto match;
++ if (t == 0)
++ {
++ NEED_IP (1);
++ while (*ip == 0)
++ {
++ t += 255;
++ ip++;
++ NEED_IP (1);
++ }
++ t += 15 + *ip++;
++ }
++ NEED_OP (t + 3);
++ NEED_IP (t + 4);
++ if (PTR_ALIGNED2_4 (op, ip))
++ {
++ COPY4 (op, ip);
++
++ op += 4;
++ ip += 4;
++ if (--t > 0)
++ {
++ if (t >= 4)
++ {
++ do
++ {
++ COPY4 (op, ip);
++ op += 4;
++ ip += 4;
++ t -= 4;
++ }
++ while (t >= 4);
++ if (t > 0)
++ do
++ *op++ = *ip++;
++ while (--t > 0);
++ }
++ else
++ do
++ *op++ = *ip++;
++ while (--t > 0);
++ }
++ }
++ else
++ {
++ *op++ = *ip++;
++ *op++ = *ip++;
++ *op++ = *ip++;
++ do
++ *op++ = *ip++;
++ while (--t > 0);
++ }
++ first_literal_run:
++
++ t = *ip++;
++ if (t >= 16)
++ goto match;
++
++ m_pos = op - (1 + M2_MAX_OFFSET);
++ m_pos -= t >> 2;
++ m_pos -= *ip++ << 2;
++ TEST_LOOKBEHIND (m_pos, out);
++ NEED_OP (3);
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ *op++ = *m_pos;
++
++ goto match_done;
++
++ while (TEST_IP && TEST_OP)
++ {
++ match:
++ if (t >= 64)
++ {
++ m_pos = op - 1;
++ m_pos -= (t >> 2) & 7;
++ m_pos -= *ip++ << 3;
++ t = (t >> 5) - 1;
++ TEST_LOOKBEHIND (m_pos, out);
++ NEED_OP (t + 3 - 1);
++ goto copy_match;
++
++ }
++ else if (t >= 32)
++ {
++ t &= 31;
++ if (t == 0)
++ {
++ NEED_IP (1);
++ while (*ip == 0)
++ {
++ t += 255;
++ ip++;
++ NEED_IP (1);
++ }
++ t += 31 + *ip++;
++ }
++
++ m_pos = op - 1;
++ m_pos -= (ip[0] >> 2) + (ip[1] << 6);
++
++ ip += 2;
++ }
++ else if (t >= 16)
++ {
++ m_pos = op;
++ m_pos -= (t & 8) << 11;
++
++ t &= 7;
++ if (t == 0)
++ {
++ NEED_IP (1);
++ while (*ip == 0)
++ {
++ t += 255;
++ ip++;
++ NEED_IP (1);
++ }
++ t += 7 + *ip++;
++ }
++
++ m_pos -= (ip[0] >> 2) + (ip[1] << 6);
++
++ ip += 2;
++ if (m_pos == op)
++ goto eof_found;
++ m_pos -= 0x4000;
++ }
++ else
++ {
++
++ m_pos = op - 1;
++ m_pos -= t >> 2;
++ m_pos -= *ip++ << 2;
++ TEST_LOOKBEHIND (m_pos, out);
++ NEED_OP (2);
++ *op++ = *m_pos++;
++ *op++ = *m_pos;
++
++ goto match_done;
++ }
++
++ TEST_LOOKBEHIND (m_pos, out);
++ NEED_OP (t + 3 - 1);
++ if (t >= 2 * 4 - (3 - 1)
++ && PTR_ALIGNED2_4 (op, m_pos))
++ {
++ COPY4 (op, m_pos);
++ op += 4;
++ m_pos += 4;
++ t -= 4 - (3 - 1);
++ do
++ {
++ COPY4 (op, m_pos);
++ op += 4;
++ m_pos += 4;
++ t -= 4;
++ }
++ while (t >= 4);
++ if (t > 0)
++ do
++ *op++ = *m_pos++;
++ while (--t > 0);
++ }
++ else
++
++ {
++ copy_match:
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ do
++ *op++ = *m_pos++;
++ while (--t > 0);
++ }
++
++ match_done:
++ t = ip[-2] & 3;
++
++ if (t == 0)
++ break;
++
++ match_next:
++ NEED_OP (t);
++ NEED_IP (t + 1);
++ do
++ *op++ = *ip++;
++ while (--t > 0);
++ t = *ip++;
++ }
++ }
++ *out_len = op - out;
++ return LZO_E_EOF_NOT_FOUND;
++
++ eof_found:
++ *out_len = op - out;
++ return (ip == ip_end ? LZO_E_OK :
++ (ip <
++ ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
++
++ input_overrun:
++ *out_len = op - out;
++ return LZO_E_INPUT_OVERRUN;
++
++ output_overrun:
++ *out_len = op - out;
++ return LZO_E_OUTPUT_OVERRUN;
++
++ lookbehind_overrun:
++ *out_len = op - out;
++ return LZO_E_LOOKBEHIND_OVERRUN;
++}
++
++/* lzo1x_oo.ch */
++
++#define NO_LIT LZO_UINT_MAX
++
++static void
++copy2 (lzo_byte * ip, const lzo_byte * m_pos, lzo_ptrdiff_t off)
++{
++ ip[0] = m_pos[0];
++ if (off == 1)
++ ip[1] = m_pos[0];
++ else
++ ip[1] = m_pos[1];
++}
++
++static void
++copy3 (lzo_byte * ip, const lzo_byte * m_pos, lzo_ptrdiff_t off)
++{
++ ip[0] = m_pos[0];
++ if (off == 1)
++ {
++ ip[2] = ip[1] = m_pos[0];
++ }
++ else if (off == 2)
++ {
++ ip[1] = m_pos[1];
++ ip[2] = m_pos[0];
++ }
++ else
++ {
++ ip[1] = m_pos[1];
++ ip[2] = m_pos[2];
++ }
++}
++
++static int
++lzo1x_optimize (lzo_byte * in, lzo_uint in_len,
++ lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem)
++{
++ register lzo_byte *op;
++ register lzo_byte *ip;
++ register lzo_uint t;
++ register lzo_byte *m_pos;
++ lzo_uint nl;
++ const lzo_byte *const ip_end = in + in_len;
++ const lzo_byte *const op_end = out + *out_len;
++ lzo_byte *litp = NULL;
++ lzo_uint lit = 0;
++ lzo_uint next_lit = NO_LIT;
++ long o_m1_a = 0, o_m1_b = 0, o_m2 = 0, o_m3_a = 0, o_m3_b = 0;
++
++ *out_len = 0;
++
++ op = out;
++ ip = in;
++
++ if (*ip > 17)
++ {
++ t = *ip++ - 17;
++ if (t < 4)
++ goto match_next;
++ goto first_literal_run;
++ }
++
++ while (TEST_IP && TEST_OP)
++ {
++ t = *ip++;
++ if (t >= 16)
++ goto match;
++ litp = ip - 1;
++ if (t == 0)
++ {
++ t = 15;
++ while (*ip == 0)
++ t += 255, ip++;
++ t += *ip++;
++ }
++ lit = t + 3;
++ copy_literal_run:
++ *op++ = *ip++;
++ *op++ = *ip++;
++ *op++ = *ip++;
++ first_literal_run:
++ do
++ *op++ = *ip++;
++ while (--t > 0);
++
++ t = *ip++;
++
++ if (t >= 16)
++ goto match;
++ m_pos = op - 1 - 0x800;
++ m_pos -= t >> 2;
++ m_pos -= *ip++ << 2;
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ lit = 0;
++ goto match_done;
++
++ while (TEST_IP && TEST_OP)
++ {
++ if (t < 16)
++ {
++ m_pos = op - 1;
++ m_pos -= t >> 2;
++ m_pos -= *ip++ << 2;
++
++ if (litp == NULL)
++ goto copy_m1;
++
++ nl = ip[-2] & 3;
++ if (nl == 0 && lit == 1 && ip[0] >= 16)
++ {
++ next_lit = nl;
++ lit += 2;
++ *litp = LZO_BYTE ((*litp & ~3) | lit);
++ copy2 (ip - 2, m_pos, op - m_pos);
++ o_m1_a++;
++ }
++ else if (nl == 0 && ip[0] < 16 && ip[0] != 0
++ && (lit + 2 + ip[0] < 16))
++ {
++ t = *ip++;
++ *litp &= ~3;
++ copy2 (ip - 3 + 1, m_pos, op - m_pos);
++ litp += 2;
++ if (lit > 0)
++ memmove (litp + 1, litp, lit);
++ lit += 2 + t + 3;
++ *litp = LZO_BYTE (lit - 3);
++
++ o_m1_b++;
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ goto copy_literal_run;
++ }
++ copy_m1:
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ }
++ else
++ {
++ match:
++ if (t >= 64)
++ {
++ m_pos = op - 1;
++ m_pos -= (t >> 2) & 7;
++ m_pos -= *ip++ << 3;
++ t = (t >> 5) - 1;
++ if (litp == NULL)
++ goto copy_m;
++
++ nl = ip[-2] & 3;
++ if (t == 1 && lit > 3 && nl == 0 &&
++ ip[0] < 16 && ip[0] != 0
++ && (lit + 3 + ip[0] < 16))
++ {
++ t = *ip++;
++ copy3 (ip - 1 - 2, m_pos,
++ op - m_pos);
++ lit += 3 + t + 3;
++ *litp = LZO_BYTE (lit - 3);
++ o_m2++;
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ goto copy_literal_run;
++ }
++ }
++ else
++ {
++ if (t >= 32)
++ {
++ t &= 31;
++ if (t == 0)
++ {
++ t = 31;
++ while (*ip == 0)
++ t += 255,
++ ip++;
++ t += *ip++;
++ }
++ m_pos = op - 1;
++ m_pos -= *ip++ >> 2;
++ m_pos -= *ip++ << 6;
++ }
++ else
++ {
++ m_pos = op;
++ m_pos -= (t & 8) << 11;
++ t &= 7;
++ if (t == 0)
++ {
++ t = 7;
++ while (*ip == 0)
++ t += 255,
++ ip++;
++ t += *ip++;
++ }
++ m_pos -= *ip++ >> 2;
++ m_pos -= *ip++ << 6;
++ if (m_pos == op)
++ goto eof_found;
++ m_pos -= 0x4000;
++ }
++ if (litp == NULL)
++ goto copy_m;
++
++ nl = ip[-2] & 3;
++ if (t == 1 && lit == 0 && nl == 0
++ && ip[0] >= 16)
++ {
++ next_lit = nl;
++ lit += 3;
++ *litp = LZO_BYTE ((*litp & ~3)
++ | lit);
++ copy3 (ip - 3, m_pos,
++ op - m_pos);
++ o_m3_a++;
++ }
++ else if (t == 1 && lit <= 3 && nl == 0
++ && ip[0] < 16 && ip[0] != 0
++ && (lit + 3 + ip[0] < 16))
++ {
++ t = *ip++;
++ *litp &= ~3;
++ copy3 (ip - 4 + 1, m_pos,
++ op - m_pos);
++ litp += 2;
++ if (lit > 0)
++ memmove (litp + 1,
++ litp, lit);
++ lit += 3 + t + 3;
++ *litp = LZO_BYTE (lit - 3);
++
++ o_m3_b++;
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ goto copy_literal_run;
++ }
++ }
++ copy_m:
++ *op++ = *m_pos++;
++ *op++ = *m_pos++;
++ do
++ *op++ = *m_pos++;
++ while (--t > 0);
++ }
++
++ match_done:
++ if (next_lit == NO_LIT)
++ {
++ t = ip[-2] & 3;
++ lit = t;
++ litp = ip - 2;
++ }
++ else
++ t = next_lit;
++ next_lit = NO_LIT;
++ if (t == 0)
++ break;
++ match_next:
++ do
++ *op++ = *ip++;
++ while (--t > 0);
++ t = *ip++;
++ }
++ }
++
++ *out_len = op - out;
++ return LZO_E_EOF_NOT_FOUND;
++
++ eof_found:
++ *out_len = op - out;
++ return (ip == ip_end ? LZO_E_OK :
++ (ip <
++ ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
++}
++
++/* interface to jffs2 bbc follows */
++
++#include "jffs2_bbc_framework.h"
++
++#define BLOCKSIZE 4096
++#define OUTBLOCKSIZE (BLOCKSIZE + BLOCKSIZE / 64 + 16 + 3)
++
++#define JFFS2_BBC_LZO_BLOCK_SIGN {0x3f, 0x47, 0x5a, 0x18}
++
++static int
++jffs2_bbc_lzo_compressor_init (void);
++
++static void
++jffs2_bbc_lzo_compressor_deinit (void);
++
++static int
++jffs2_bbc_lzo_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen);
++
++static int
++jffs2_bbc_lzo_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime);
++
++static int
++jffs2_bbc_lzo_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen);
++
++static char *
++jffs2_bbc_lzo_proc_info (void);
++
++static int
++jffs2_bbc_lzo_proc_command (char *command);
++
++struct jffs2_bbc_compressor_type jffs2_bbc_lzo = {
++ "lzo",
++ 0,
++ JFFS2_BBC_LZO_BLOCK_SIGN,
++ jffs2_bbc_lzo_compressor_init,
++ NULL,
++ NULL,
++ jffs2_bbc_lzo_compressor_deinit,
++ jffs2_bbc_lzo_compress,
++ jffs2_bbc_lzo_estimate,
++ jffs2_bbc_lzo_decompress,
++ jffs2_bbc_lzo_proc_info,
++ jffs2_bbc_lzo_proc_command
++};
++
++static int
++no_lzo1x_optimize (lzo_byte * src, lzo_uint src_len,
++ lzo_byte * dst, lzo_uintp dst_len, lzo_voidp wrkmem)
++{
++ return 0;
++}
++
++#ifdef __KERNEL__
++static lzo_compress_t lzo1x_compressor = lzo1x_1_compress;
++static lzo_optimize_t lzo1x_optimizer = no_lzo1x_optimize;
++static int lzo1x_compressor_type = 1;
++static int lzo1x_optimize_type = 0;
++static unsigned long lzo1x_compressor_memsize = LZO1X_1_MEM_COMPRESS;
++#else
++static lzo_compress_t lzo1x_compressor = lzo1x_999_compress;
++static lzo_optimize_t lzo1x_optimizer = lzo1x_optimize;
++static int lzo1x_compressor_type = 999;
++static int lzo1x_optimize_type = 1;
++static unsigned long lzo1x_compressor_memsize = LZO1X_999_MEM_COMPRESS;
++#endif
++
++static lzo_bytep wrkmem = NULL; /* temporary buffer for compression, used by lzo */
++static lzo_bytep cmprssmem = NULL; /* temporary buffer for compression, used by interface */
++
++static int
++jffs2_bbc_lzo_compressor_init (void)
++{
++ wrkmem = (lzo_bytep) jffs2_bbc_malloc (lzo1x_compressor_memsize);
++ cmprssmem = (lzo_bytep) jffs2_bbc_malloc (OUTBLOCKSIZE);
++ return !(wrkmem && cmprssmem);
++}
++
++static void
++jffs2_bbc_lzo_compressor_deinit (void)
++{
++ jffs2_bbc_free (wrkmem);
++ jffs2_bbc_free (cmprssmem);
++}
++
++static int
++jffs2_bbc_lzo_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen)
++{
++ lzo_uint csize = OUTBLOCKSIZE;
++ lzo_uint isize = *sourcelen;
++ int retval;
++ if ((retval =
++ lzo1x_compressor (input, *sourcelen, cmprssmem, &csize,
++ wrkmem)) != LZO_E_OK)
++ {
++ *sourcelen = *dstlen = 0;
++ return retval;
++ }
++ else
++ {
++ retval = lzo1x_optimizer (cmprssmem, csize, input, &isize,
++ NULL);
++ csize += 2;
++ if (csize <= *dstlen) {
++ *dstlen = csize;
++ *(output++) = jffs2_bbc_lzo.block_sign[0];
++ *(output++) = jffs2_bbc_lzo.block_sign[1];
++ memcpy (output, cmprssmem, csize - 2);
++ return retval;
++ } else {
++ *sourcelen = *dstlen = 0;
++ return -1;
++ }
++ }
++}
++
++static int
++jffs2_bbc_lzo_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime)
++{
++ *dstlen = sourcelen * 55 / 100;
++ *readtime = JFFS2_BBC_ZLIB_READ_TIME / 2;
++ *writetime = JFFS2_BBC_ZLIB_WRITE_TIME * 8 / 10; /* LZO1X-1 is much-much faster,
++ but LZO1X-999 is slow. The default mode for inside kernel compression is LZO1X-1
++ This should be *0.4 really */
++ return 0;
++}
++
++static int
++jffs2_bbc_lzo_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen)
++{
++ lzo_uint outlen = dstlen;
++ if ( ( *(input++) != (unsigned char)jffs2_bbc_lzo.block_sign[0] ) ||
++ ( *(input++) != (unsigned char)jffs2_bbc_lzo.block_sign[1] )
++ ) {
++ return -1;
++ } else {
++ return lzo1x_decompress (input, sourcelen - 2, output, &outlen, NULL);
++ }
++}
++
++static char *
++jffs2_bbc_lzo_proc_info (void)
++{
++ if (lzo1x_compressor_type == 1)
++ {
++ if (lzo1x_optimize_type == 1)
++ {
++ return "LZO1X-1 compression with optimization";
++ }
++ else
++ {
++ return "LZO1X-1 compression without optimization";
++ }
++ }
++ else if (lzo1x_compressor_type == 999)
++ {
++ if (lzo1x_optimize_type == 1)
++ {
++ return "LZO1X-999 compression with optimization";
++ }
++ else
++ {
++ return "LZO1X-999 compression without optimization";
++ }
++ }
++ else
++ {
++ return "Unknown configuration!";
++ }
++}
++
++static int
++jffs2_bbc_lzo_proc_command (char *command)
++{
++ switch (*command)
++ {
++ case 'o':
++ /* switch optimization off */
++ lzo1x_optimizer = no_lzo1x_optimize;
++ lzo1x_optimize_type = 0;
++ jffs2_bbc_print1 ("Compression optimization switched off.\n");
++ return 0;
++ case 'O':
++ /* switch optimization on */
++ lzo1x_optimizer = lzo1x_optimize;
++ lzo1x_optimize_type = 1;
++ jffs2_bbc_print1 ("Compression optimization switched on.\n");
++ return 0;
++ case '1':
++ /* switch compression to LZO1X-1 */
++ jffs2_bbc_free (wrkmem);
++ lzo1x_compressor_type = 1;
++ lzo1x_compressor = lzo1x_1_compress;
++ lzo1x_compressor_memsize = LZO1X_1_MEM_COMPRESS;
++ wrkmem = (lzo_bytep)
++ jffs2_bbc_malloc (lzo1x_compressor_memsize);
++ jffs2_bbc_print1 ("Compression type switched to LZO1X-1.\n");
++ return 0;
++ case '9':
++ /* switch compression to LZO1X-999 */
++ jffs2_bbc_free (wrkmem);
++ lzo1x_compressor_type = 999;
++ lzo1x_compressor = lzo1x_999_compress;
++ lzo1x_compressor_memsize = LZO1X_999_MEM_COMPRESS;
++ wrkmem = (lzo_bytep)
++ jffs2_bbc_malloc (lzo1x_compressor_memsize);
++ jffs2_bbc_print1
++ ("Compression type switched to LZO1X-999.\n");
++ return 0;
++ default:
++ jffs2_bbc_print1 ("Unknown command!\n");
++ return 0;
++ }
++}
++
++
++struct jffs2_bbc_compressor_type *
++jffs2_bbc_lzo_init (int mode)
++{
++ if (jffs2_bbc_register_compressor (&jffs2_bbc_lzo) == 0)
++ {
++ return &jffs2_bbc_lzo;
++ }
++ else
++ {
++ return NULL;
++ }
++}
++
++void
++jffs2_bbc_lzo_deinit (void)
++{
++ jffs2_bbc_unregister_compressor (&jffs2_bbc_lzo);
++}
+diff -Nur linux-mips-cvs/fs/jffs2/jffs2_bbc_lzss_comp.c linux-mips/fs/jffs2/jffs2_bbc_lzss_comp.c
+--- linux-mips-cvs/fs/jffs2/jffs2_bbc_lzss_comp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/jffs2_bbc_lzss_comp.c 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,385 @@
++/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
++
++/*
++ jffs2_bbc_lzss_comp.c -- Lempel-Ziv-Storer-Szymanski compression module for jffs2
++ Copyright (C) 2004 Patrik Kluba
++ Based on the LZSS source included in LDS (lossless datacompression sources)
++ Block-compression modifications by Patrik Kluba
++ $Header: /openwrt/openwrt/package/linux/kernel-patches/301-jffs-compression,v 1.1 2005/03/26 10:33:31 wbx Exp $
++*/
++
++/*
++Original copyright follows:
++
++**************************************************************
++ LZSS.C -- A Data Compression Program
++**************************************************************
++ 4/6/1989 Haruhiko Okumura
++ Use, distribute, and modify this program freely.
++ Please send me your improved versions.
++ PC-VAN SCIENCE
++ NIFTY-Serve PAF01022
++ CompuServe 74050,1022
++**************************************************************
++
++*/
++
++/*
++
++ 2004-02-16 pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu>
++ Initial release
++
++*/
++
++/* lzss.c */
++
++#define N 4096 /* size of ring buffer */
++#define F 18 /* upper limit for match_length */
++#define THRESHOLD 2 /* encode string into position and length
++ if match_length is greater than this */
++#define NIL N /* index for root of binary search trees */
++
++static unsigned char
++ text_buf[N + F - 1]; /* ring buffer of size N,
++ with extra F-1 bytes to facilitate string comparison */
++static unsigned long match_position, match_length; /* of longest match. These are
++ set by the InsertNode() procedure. */
++static unsigned long lson[N + 1], rson[N + 257], dad[N + 1]; /* left & right children &
++ parents -- These constitute binary search trees. */
++
++static void InitTree(void) /* initialize trees */
++{
++ unsigned long i;
++
++ /* For i = 0 to N - 1, rson[i] and lson[i] will be the right and
++ left children of node i. These nodes need not be initialized.
++ Also, dad[i] is the parent of node i. These are initialized to
++ NIL (= N), which stands for 'not used.'
++ For i = 0 to 255, rson[N + i + 1] is the root of the tree
++ for strings that begin with character i. These are initialized
++ to NIL. Note there are 256 trees. */
++
++ for (i = N + 1; i <= N + 256; i++) rson[i] = NIL;
++ for (i = 0; i < N; i++) dad[i] = NIL;
++}
++
++static void InsertNode(unsigned long r)
++ /* Inserts string of length F, text_buf[r..r+F-1], into one of the
++ trees (text_buf[r]'th tree) and returns the longest-match position
++ and length via the global variables match_position and match_length.
++ If match_length = F, then removes the old node in favor of the new
++ one, because the old one will be deleted sooner.
++ Note r plays double role, as tree node and position in buffer. */
++{
++ unsigned long i, p;
++ unsigned char *key;
++ signed long cmp;
++
++ cmp = 1; key = &text_buf[r]; p = N + 1 + key[0];
++ rson[r] = lson[r] = NIL; match_length = 0;
++ for ( ; ; ) {
++ if (cmp >= 0) {
++ if (rson[p] != NIL) p = rson[p];
++ else { rson[p] = r; dad[r] = p; return; }
++ } else {
++ if (lson[p] != NIL) p = lson[p];
++ else { lson[p] = r; dad[r] = p; return; }
++ }
++ for (i = 1; i < F; i++)
++ if ((cmp = key[i] - text_buf[p + i]) != 0) break;
++ if (i > match_length) {
++ match_position = p;
++ if ((match_length = i) >= F) break;
++ }
++ }
++ dad[r] = dad[p]; lson[r] = lson[p]; rson[r] = rson[p];
++ dad[lson[p]] = r; dad[rson[p]] = r;
++ if (rson[dad[p]] == p) rson[dad[p]] = r;
++ else lson[dad[p]] = r;
++ dad[p] = NIL; /* remove p */
++}
++
++static void DeleteNode(unsigned long p) /* deletes node p from tree */
++{
++ unsigned long q;
++
++ if (dad[p] == NIL) return; /* not in tree */
++ if (rson[p] == NIL) q = lson[p];
++ else if (lson[p] == NIL) q = rson[p];
++ else {
++ q = lson[p];
++ if (rson[q] != NIL) {
++ do { q = rson[q]; } while (rson[q] != NIL);
++ rson[dad[q]] = lson[q]; dad[lson[q]] = dad[q];
++ lson[q] = lson[p]; dad[lson[p]] = q;
++ }
++ rson[q] = rson[p]; dad[rson[p]] = q;
++ }
++ dad[q] = dad[p];
++ if (rson[dad[p]] == p) rson[dad[p]] = q; else lson[dad[p]] = q;
++ dad[p] = NIL;
++}
++
++/* modified for block compression */
++/* on return, srclen will contain the number of successfully compressed bytes
++ and dstlen will contain completed compressed bytes */
++
++static int Encode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long *srclen,
++ unsigned long *dstlen)
++{
++ unsigned long i, len, r, c, s, last_match_length, code_buf_ptr;
++ unsigned char code_buf[17], mask;
++ unsigned char *ip, *op;
++ unsigned long written = 0;
++ unsigned long read = 0;
++ unsigned char *srcend = srcbuf + *srclen;
++ unsigned char *dstend = dstbuf + *dstlen;
++ ip = srcbuf;
++ op = dstbuf;
++ InitTree(); /* initialize trees */
++ code_buf[0] = 0; /* code_buf[1..16] saves eight units of code, and
++ code_buf[0] works as eight flags, "1" representing that the unit
++ is an unencoded letter (1 byte), "0" a position-and-length pair
++ (2 bytes). Thus, eight units require at most 16 bytes of code. */
++ code_buf_ptr = mask = 1;
++ s = 0; r = N - F;
++ for (i = s; i < r; i++) text_buf[i] = ' '; /* Clear the buffer with
++ any character that will appear often. */
++ for (len = 0; (len < F) && (ip < srcend); len++)
++ text_buf[r + len] = *(ip++); /* Read F bytes into the last F bytes of
++ the buffer */
++ read = len;
++ for (i = 1; i <= F; i++) InsertNode(r - i); /* Insert the F strings,
++ each of which begins with one or more 'space' characters. Note
++ the order in which these strings are inserted. This way,
++ degenerate trees will be less likely to occur. */
++ InsertNode(r); /* Finally, insert the whole string just read. The
++ global variables match_length and match_position are set. */
++ do {
++ if (match_length > len) match_length = len; /* match_length
++ may be spuriously long near the end of text. */
++ if (match_length <= THRESHOLD) {
++ match_length = 1; /* Not long enough match. Send one byte. */
++ code_buf[0] |= mask; /* 'send one byte' flag */
++ code_buf[code_buf_ptr++] = text_buf[r]; /* Send uncoded. */
++ } else {
++ code_buf[code_buf_ptr++] = match_position;
++ code_buf[code_buf_ptr++] = (((match_position >> 4) & 0xf0)
++ | (match_length - (THRESHOLD + 1))); /* Send position and
++ length pair. Note match_length > THRESHOLD. */
++ }
++ if ((mask <<= 1) == 0) { /* Shift mask left one bit. */
++ if ((op + code_buf_ptr) > dstend) {
++ *dstlen = written; /* written contains bytes of complete compressed
++ code */
++ return -1;
++ };
++ for (i = 0; i < code_buf_ptr; *(op++) = code_buf[i++]); /* Send at most 8 units of */
++ /* code together */
++ written += code_buf_ptr;
++ *srclen = read; /* this many bytes have been successfully compressed */
++ code_buf[0] = 0; code_buf_ptr = mask = 1;
++ }
++ last_match_length = match_length;
++ for (i = 0; (i < last_match_length) && (ip < srcend); i++) {
++ c = *(ip++);
++ DeleteNode(s); /* Delete old strings and */
++ text_buf[s] = c; /* read new bytes */
++ if (s < F - 1) text_buf[s + N] = c; /* If the position is
++ near the end of buffer, extend the buffer to make
++ string comparison easier. */
++ s = (s + 1) & (N - 1); r = (r + 1) & (N - 1);
++ /* Since this is a ring buffer, increment the position
++ modulo N. */
++ InsertNode(r); /* Register the string in text_buf[r..r+F-1] */
++ }
++ read += i;
++ while (i++ < last_match_length) { /* After the end of text, */
++ DeleteNode(s); /* no need to read, but */
++ s = (s + 1) & (N - 1); r = (r + 1) & (N - 1);
++ if (--len) InsertNode(r); /* buffer may not be empty. */
++ }
++ } while (len > 0); /* until length of string to be processed is zero */
++ if (code_buf_ptr > 1) { /* Send remaining code. */
++ if ((op + code_buf_ptr) > dstend) {
++ *dstlen = written;
++ return -1;
++ }
++ for (i = 0; i < code_buf_ptr; *(op++) = code_buf[i++]);
++ written += code_buf_ptr;
++ *srclen = read;
++ }
++ *dstlen = written;
++ return 0;
++}
++
++static int Decode(unsigned char *srcbuf, unsigned char *dstbuf, unsigned long srclen,
++ unsigned long dstlen) /* Just the reverse of Encode(). */
++{
++ unsigned long i, r, c, j, k, flags;
++ unsigned char *ip, *op;
++ unsigned long written;
++ unsigned long read;
++ unsigned char *srcend = srcbuf + srclen;
++ unsigned char *dstend = dstbuf + dstlen;
++ read = written = 0;
++ ip = srcbuf;
++ op = dstbuf;
++ for (i = 0; i < N - F; i++) text_buf[i] = ' ';
++ r = N - F; flags = 0;
++ for ( ; ; ) {
++ if (((flags >>= 1) & 256) == 0) {
++ if (ip >= srcend) return 0;
++ c = *(ip++);
++ flags = c | 0xff00; /* uses higher byte cleverly */
++ } /* to count eight */
++ if (flags & 1) {
++ if (ip >= srcend) return 0;
++ c = *(ip++);
++ if (op >= dstend) return -1;
++ *(op++) = text_buf[r++] = c; r &= (N - 1);
++ } else {
++ if ((ip + 2) > srcend) return 0;
++ i = *(ip++);
++ j = *(ip++);
++ i |= ((j & 0xf0) << 4); j = (j & 0x0f) + THRESHOLD;
++ if ((op + j + 1) > dstend) return -1;
++ for (k = 0; k <= j; k++) {
++ c = text_buf[(i + k) & (N - 1)];
++ *(op++) = text_buf[r++] = c; r &= (N - 1);
++ }
++ }
++ }
++}
++
++/* interface to jffs2 bbc follows */
++
++#include "jffs2_bbc_framework.h"
++
++
++#define JFFS2_BBC_LZSS_BLOCK_SIGN {0x27, 0x6f, 0x12, 0xc4}
++
++static int
++jffs2_bbc_lzss_compressor_init (void);
++
++static void
++jffs2_bbc_lzss_compressor_deinit (void);
++
++static int
++jffs2_bbc_lzss_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen);
++
++static int
++jffs2_bbc_lzss_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime);
++
++static int
++jffs2_bbc_lzss_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen);
++
++static char *
++jffs2_bbc_lzss_proc_info (void);
++
++static int
++jffs2_bbc_lzss_proc_command (char *command);
++
++struct jffs2_bbc_compressor_type jffs2_bbc_lzss = {
++ "lzss",
++ 0,
++ JFFS2_BBC_LZSS_BLOCK_SIGN,
++ jffs2_bbc_lzss_compressor_init,
++ NULL,
++ NULL,
++ jffs2_bbc_lzss_compressor_deinit,
++ jffs2_bbc_lzss_compress,
++ jffs2_bbc_lzss_estimate,
++ jffs2_bbc_lzss_decompress,
++ jffs2_bbc_lzss_proc_info,
++ jffs2_bbc_lzss_proc_command
++};
++
++static int
++jffs2_bbc_lzss_compressor_init (void)
++{
++ return 0;
++}
++
++static void
++jffs2_bbc_lzss_compressor_deinit (void)
++{
++}
++
++static int
++jffs2_bbc_lzss_compress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long *sourcelen,
++ unsigned long *dstlen)
++{
++ int retval;
++ unsigned long dst = *dstlen;
++ *(output++) = jffs2_bbc_lzss.block_sign[0];
++ *(output++) = jffs2_bbc_lzss.block_sign[1];
++ dst -= 2;
++ retval = Encode(input, output, sourcelen, &dst);
++ dst += 2;
++ *dstlen = dst;
++ return retval;
++}
++
++static int
++jffs2_bbc_lzss_estimate (void *model, unsigned char *input,
++ unsigned long sourcelen, unsigned long *dstlen,
++ unsigned long *readtime, unsigned long *writetime)
++{
++ *dstlen = sourcelen * 60 / 100;
++ *readtime = JFFS2_BBC_ZLIB_READ_TIME * 12 / 10;
++ *writetime = JFFS2_BBC_ZLIB_WRITE_TIME * 3;
++ return 0;
++}
++
++static int
++jffs2_bbc_lzss_decompress (void *model, unsigned char *input,
++ unsigned char *output, unsigned long sourcelen,
++ unsigned long dstlen)
++{
++ if ( ( *(input++) != (unsigned char)jffs2_bbc_lzss.block_sign[0] ) ||
++ ( *(input++) != (unsigned char)jffs2_bbc_lzss.block_sign[1] )
++ ) {
++ return -1;
++ } else {
++ return Decode(input, output, sourcelen - 2, dstlen);
++ }
++}
++
++static char *
++jffs2_bbc_lzss_proc_info (void)
++{
++ return "Lempel-Ziv-Storer-Szymanski compression module";
++}
++
++static int
++jffs2_bbc_lzss_proc_command (char *command)
++{
++ return 0;
++}
++
++struct jffs2_bbc_compressor_type *
++jffs2_bbc_lzss_init (int mode)
++{
++ if (jffs2_bbc_register_compressor (&jffs2_bbc_lzss) == 0)
++ {
++ return &jffs2_bbc_lzss;
++ }
++ else
++ {
++ return NULL;
++ }
++}
++
++void
++jffs2_bbc_lzss_deinit (void)
++{
++ jffs2_bbc_unregister_compressor (&jffs2_bbc_lzss);
++}
+diff -Nur linux-mips-cvs/fs/jffs2/linux-2.4.25.hpatch linux-mips/fs/jffs2/linux-2.4.25.hpatch
+--- linux-mips-cvs/fs/jffs2/linux-2.4.25.hpatch 1970-01-01 01:00:00.000000000 +0100
++++ linux-mips/fs/jffs2/linux-2.4.25.hpatch 2005-02-07 05:08:34.000000000 +0100
+@@ -0,0 +1,97 @@
++FMakefile
++=BBC insertion
++-COMPR_OBJS
++iMakefile.bbc.inc
+++
++I
++?JFFS2_OBJS
+++ $(JFFS2_BBC_KERNEL_OBJS) \
++
++F../Config.in
++=BBC insertion
++-tristate 'Compressed ROM file system support' CONFIG_CRAMFS
++iConfig.in.bbc.inc
+++
++I
++F../../Documentation/Configure.help
++=BBC insertion
++-JFFS stats available
++iConfigure.help.bbc.inc
+++
++I
++Fcompr_zlib.c
++=(de)compress->(de)compress2
++-int zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
+++int jffs2_zlib_compress2(unsigned char *data_in, unsigned char *cpage_out,
++-void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
+++void jffs2_zlib_decompress2(unsigned char *data_in, unsigned char *cpage_out,
++?inflateEnd(&strm);
++?}
+++
+++extern int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 * sourcelen, __u32 * dstlen);
+++extern void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
+++
+++int zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
+++ __u32 *sourcelen, __u32 *dstlen)
+++{
+++ return jffs2_zlib_compress(data_in,cpage_out,sourcelen,dstlen);
+++}
+++
+++void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
+++ __u32 srclen, __u32 destlen)
+++{
+++ jffs2_zlib_decompress(data_in,cpage_out,srclen,destlen);
+++}
+++
++
++Ffile.c
++=set_act_sb before write
++-#include
+++#include "jffs2_bbc_framework.h" /**BBC**/
++I
++?int jffs2_commit_write
++-jffs2_compress(
+++ jffs2_bbc_model_set_act_sb(c); /**BBC**/
++I
++
++Fgc.c
++=set_act_sb before write
++-#include
+++#include "jffs2_bbc_framework.h" /**BBC**/
++I
++?int jffs2_garbage_collect_dnode(
++-jffs2_compress(
+++ jffs2_bbc_model_set_act_sb(c); /**BBC**/
++I
++
++Fread.c
++=set_act_sb before read
++-#include
+++#include "jffs2_bbc_framework.h" /**BBC**/
++I
++?int jffs2_read_dnode(
++-jffs2_decompress(
+++ jffs2_bbc_model_set_act_sb(c); /**BBC**/
++I
++
++Fsuper.c
++=init, load_model
++-#include
+++#include "jffs2_bbc_fs.h" /**BBC**/
++I
++?struct super_block *jffs2_read_super(
++-return sb;
+++ jffs2_bbc_load_model(sb); /**BBC**/
++I
++?void jffs2_put_super
++?c = JFFS2_SB_INFO
+++ jffs2_bbc_unload_model(sb); /**BBC**/
++?init_jffs2_fs(void)
++?int ret;
+++
+++ jffs2_bbc_proc_init(); /**BBC**/
+++
++?exit_jffs2_fs(void)
++?{
+++ jffs2_bbc_proc_deinit(); /**BBC**/
+++
+diff -Nur linux-mips-cvs/fs/jffs2/read.c linux-mips/fs/jffs2/read.c
+--- linux-mips-cvs/fs/jffs2/read.c 2003-11-17 02:07:44.000000000 +0100
++++ linux-mips/fs/jffs2/read.c 2005-02-07 05:08:35.000000000 +0100
+@@ -35,6 +35,7 @@
+ *
+ */
+
++#include "jffs2_bbc_framework.h" /**BBC**/
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/jffs2.h>
+@@ -140,6 +141,7 @@
+ D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc));
+ if (ri->compr != JFFS2_COMPR_NONE) {
+ D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n", ri->csize, readbuf, ri->dsize, decomprbuf));
++ jffs2_bbc_model_set_act_sb(c); /**BBC**/
+ ret = jffs2_decompress(ri->compr, readbuf, decomprbuf, ri->csize, ri->dsize);
+ if (ret) {
+ printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret);
+diff -Nur linux-mips-cvs/fs/jffs2/super.c linux-mips/fs/jffs2/super.c
+--- linux-mips-cvs/fs/jffs2/super.c 2003-01-11 18:53:17.000000000 +0100
++++ linux-mips/fs/jffs2/super.c 2005-02-07 05:08:35.000000000 +0100
+@@ -35,6 +35,7 @@
+ *
+ */
+
++#include "jffs2_bbc_fs.h" /**BBC**/
+ #include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+@@ -272,6 +273,7 @@
+ sb->s_magic = JFFS2_SUPER_MAGIC;
+ if (!(sb->s_flags & MS_RDONLY))
+ jffs2_start_garbage_collect_thread(c);
++ jffs2_bbc_load_model(sb); /**BBC**/
+ return sb;
+
+ out_root_i:
+@@ -288,6 +290,7 @@
+ void jffs2_put_super (struct super_block *sb)
+ {
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
++ jffs2_bbc_unload_model(sb); /**BBC**/
+
+ D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
+
+@@ -344,6 +347,9 @@
+ {
+ int ret;
+
++ jffs2_bbc_proc_init(); /**BBC**/
++
++
+ printk(KERN_NOTICE "JFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB.\n");
+
+ #ifdef JFFS2_OUT_OF_KERNEL
+@@ -388,6 +394,8 @@
+
+ static void __exit exit_jffs2_fs(void)
+ {
++ jffs2_bbc_proc_deinit(); /**BBC**/
++
+ jffs2_destroy_slab_caches();
+ jffs2_zlib_exit();
+ unregister_filesystem(&jffs2_fs_type);
diff --git a/target/linux/generic-2.4/patches/004-exec_pagesize.patch b/target/linux/generic-2.4/patches/004-exec_pagesize.patch
new file mode 100644
index 0000000..a7b1d04
--- /dev/null
+++ b/target/linux/generic-2.4/patches/004-exec_pagesize.patch
@@ -0,0 +1,11 @@
+--- linux.old/include/asm-mips/param.h 2005-01-19 15:10:12.000000000 +0100
++++ linux.dev/include/asm-mips/param.h 2005-05-30 02:42:06.000000000 +0200
+@@ -55,7 +55,7 @@
+ #endif /* defined(__KERNEL__) */
+ #endif /* defined(HZ) */
+
+-#define EXEC_PAGESIZE 65536
++#define EXEC_PAGESIZE 4096
+
+ #ifndef NGROUPS
+ #define NGROUPS 32
diff --git a/target/linux/generic-2.4/patches/005-mtd_flashtypes.patch b/target/linux/generic-2.4/patches/005-mtd_flashtypes.patch
new file mode 100644
index 0000000..9115b9f
--- /dev/null
+++ b/target/linux/generic-2.4/patches/005-mtd_flashtypes.patch
@@ -0,0 +1,925 @@
+diff -Nur linux-2.4.30/drivers/mtd/chips/Config.in linux-2.4.30.openwrt/drivers/mtd/chips/Config.in
+--- linux-2.4.30/drivers/mtd/chips/Config.in 2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.30.openwrt/drivers/mtd/chips/Config.in 2005-06-28 11:26:26.000000000 +0200
+@@ -45,6 +45,7 @@
+ dep_tristate ' Support for Intel/Sharp flash chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_GEN_PROBE
+ dep_tristate ' Support for AMD/Fujitsu flash chips' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_GEN_PROBE
+ dep_tristate ' Support for ST (Advanced Architecture) flash chips' CONFIG_MTD_CFI_STAA $CONFIG_MTD_GEN_PROBE
++dep_tristate ' Support for SST flash chips' CONFIG_MTD_CFI_SSTSTD $CONFIG_MTD_GEN_PROBE
+
+ dep_tristate ' Support for RAM chips in bus mapping' CONFIG_MTD_RAM $CONFIG_MTD
+ dep_tristate ' Support for ROM chips in bus mapping' CONFIG_MTD_ROM $CONFIG_MTD
+diff -Nur linux-2.4.30/drivers/mtd/chips/Makefile linux-2.4.30.openwrt/drivers/mtd/chips/Makefile
+--- linux-2.4.30/drivers/mtd/chips/Makefile 2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.30.openwrt/drivers/mtd/chips/Makefile 2005-06-28 11:26:26.000000000 +0200
+@@ -18,6 +18,7 @@
+ obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o
+ obj-$(CONFIG_MTD_CFI) += cfi_probe.o
+ obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o
++obj-$(CONFIG_MTD_CFI_SSTSTD) += cfi_cmdset_0701.o
+ obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o
+ obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o
+ obj-$(CONFIG_MTD_GEN_PROBE) += gen_probe.o
+diff -Nur linux-2.4.30/drivers/mtd/chips/cfi_cmdset_0701.c linux-2.4.30.openwrt/drivers/mtd/chips/cfi_cmdset_0701.c
+--- linux-2.4.30/drivers/mtd/chips/cfi_cmdset_0701.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.30.openwrt/drivers/mtd/chips/cfi_cmdset_0701.c 2005-06-28 11:26:26.000000000 +0200
+@@ -0,0 +1,855 @@
++/*
++ * Common Flash Interface support:
++ * SST Standard Vendor Command Set (ID 0x0701)
++ *
++ * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp>
++ *
++ * 2_by_8 routines added by Simon Munton
++ *
++ * This code is GPL
++ *
++ * $Id: cfi_cmdset_0701.c,v 1.1 2005/03/16 13:50:00 wbx Exp $
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <asm/io.h>
++#include <asm/byteorder.h>
++
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/cfi.h>
++
++static int cfi_sststd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
++static int cfi_sststd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
++static int cfi_sststd_erase_onesize(struct mtd_info *, struct erase_info *);
++static int cfi_sststd_erase_varsize(struct mtd_info *, struct erase_info *);
++static void cfi_sststd_sync (struct mtd_info *);
++static int cfi_sststd_suspend (struct mtd_info *);
++static void cfi_sststd_resume (struct mtd_info *);
++
++static void cfi_sststd_destroy(struct mtd_info *);
++
++struct mtd_info *cfi_cmdset_0701(struct map_info *, int);
++static struct mtd_info *cfi_sststd_setup (struct map_info *);
++
++
++static struct mtd_chip_driver cfi_sststd_chipdrv = {
++ probe: NULL, /* Not usable directly */
++ destroy: cfi_sststd_destroy,
++ name: "cfi_cmdset_0701",
++ module: THIS_MODULE
++};
++
++struct mtd_info *cfi_cmdset_0701(struct map_info *map, int primary)
++{
++ struct cfi_private *cfi = map->fldrv_priv;
++ int ofs_factor = cfi->interleave * cfi->device_type;
++ int i;
++ __u8 major, minor;
++ __u32 base = cfi->chips[0].start;
++
++ if (cfi->cfi_mode==1){
++ __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR;
++
++ cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
++ cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
++ cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL);
++
++ major = cfi_read_query(map, base + (adr+3)*ofs_factor);
++ minor = cfi_read_query(map, base + (adr+4)*ofs_factor);
++
++ printk(" SST Query Table v%c.%c at 0x%4.4X\n",
++ major, minor, adr);
++ cfi_send_gen_cmd(0xf0, 0x5555, base, map, cfi, cfi->device_type, NULL);
++
++ cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
++ cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
++ cfi_send_gen_cmd(0x90, 0x5555, base, map, cfi, cfi->device_type, NULL);
++ cfi->mfr = cfi_read_query(map, base);
++ cfi->id = cfi_read_query(map, base + ofs_factor);
++
++ cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
++ cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
++ cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL);
++
++ switch (cfi->device_type) {
++ case CFI_DEVICETYPE_X16:
++ cfi->addr_unlock1 = 0x5555;
++ cfi->addr_unlock2 = 0x2AAA;
++ break;
++ default:
++ printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0701 device type %d\n", cfi->device_type);
++ return NULL;
++ }
++ } /* CFI mode */
++
++ for (i=0; i< cfi->numchips; i++) {
++ cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
++ cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
++ cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
++ }
++
++ map->fldrv = &cfi_sststd_chipdrv;
++ MOD_INC_USE_COUNT;
++
++ cfi_send_gen_cmd(0xf0, 0x5555, base, map, cfi, cfi->device_type, NULL);
++ return cfi_sststd_setup(map);
++}
++
++static struct mtd_info *cfi_sststd_setup(struct map_info *map)
++{
++ struct cfi_private *cfi = map->fldrv_priv;
++ struct mtd_info *mtd;
++ unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
++
++ mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
++ printk("number of %s chips: %d\n", (cfi->cfi_mode)?"JEDEC":"CFI",cfi->numchips);
++
++ if (!mtd) {
++ printk("Failed to allocate memory for MTD device\n");
++ kfree(cfi->cmdset_priv);
++ return NULL;
++ }
++
++ memset(mtd, 0, sizeof(*mtd));
++ mtd->priv = map;
++ mtd->type = MTD_NORFLASH;
++ /* Also select the correct geometry setup too */
++ mtd->size = devsize * cfi->numchips;
++
++ if (cfi->cfiq->NumEraseRegions == 1) {
++ /* No need to muck about with multiple erase sizes */
++ mtd->erasesize = ((cfi->cfiq->EraseRegionInfo[0] >> 8) & ~0xff) * cfi->interleave;
++ } else {
++ unsigned long offset = 0;
++ int i,j;
++
++ mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
++ mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL);
++ if (!mtd->eraseregions) {
++ printk("Failed to allocate memory for MTD erase region info\n");
++ kfree(cfi->cmdset_priv);
++ return NULL;
++ }
++
++ for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
++ unsigned long ernum, ersize;
++ ersize = ((cfi->cfiq->EraseRegionInfo[i] >> 8) & ~0xff) * cfi->interleave;
++ ernum = (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1;
++
++ if (mtd->erasesize < ersize) {
++ mtd->erasesize = ersize;
++ }
++ for (j=0; j<cfi->numchips; j++) {
++ mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].offset = (j*devsize)+offset;
++ mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].erasesize = ersize;
++ mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
++ }
++ offset += (ersize * ernum);
++ }
++
++ // debug
++ for (i=0; i<mtd->numeraseregions;i++){
++ printk("%d: offset=0x%x,size=0x%x,blocks=%d\n",
++ i,mtd->eraseregions[i].offset,
++ mtd->eraseregions[i].erasesize,
++ mtd->eraseregions[i].numblocks);
++ }
++ }
++
++ switch (CFIDEV_BUSWIDTH)
++ {
++ case 1:
++ case 2:
++ case 4:
++ if (mtd->numeraseregions > 1)
++ mtd->erase = cfi_sststd_erase_varsize;
++ else
++ mtd->erase = cfi_sststd_erase_onesize;
++ mtd->read = cfi_sststd_read;
++ mtd->write = cfi_sststd_write;
++ break;
++
++ default:
++ printk("Unsupported buswidth\n");
++ kfree(mtd);
++ kfree(cfi->cmdset_priv);
++ return NULL;
++ break;
++ }
++ mtd->sync = cfi_sststd_sync;
++ mtd->suspend = cfi_sststd_suspend;
++ mtd->resume = cfi_sststd_resume;
++ mtd->flags = MTD_CAP_NORFLASH;
++ map->fldrv = &cfi_sststd_chipdrv;
++ mtd->name = map->name;
++ MOD_INC_USE_COUNT;
++ return mtd;
++}
++
++static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
++{
++ DECLARE_WAITQUEUE(wait, current);
++ unsigned long timeo = jiffies + HZ;
++
++ retry:
++ cfi_spin_lock(chip->mutex);
++
++ if (chip->state != FL_READY){
++ printk("Waiting for chip to read, status = %d\n", chip->state);
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ add_wait_queue(&chip->wq, &wait);
++
++ cfi_spin_unlock(chip->mutex);
++
++ schedule();
++ remove_wait_queue(&chip->wq, &wait);
++ timeo = jiffies + HZ;
++
++ goto retry;
++ }
++
++ adr += chip->start;
++
++ chip->state = FL_READY;
++
++ map->copy_from(map, buf, adr, len);
++
++ wake_up(&chip->wq);
++ cfi_spin_unlock(chip->mutex);
++
++ return 0;
++}
++
++static int cfi_sststd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
++{
++ struct map_info *map = mtd->priv;
++ struct cfi_private *cfi = map->fldrv_priv;
++ unsigned long ofs;
++ int chipnum;
++ int ret = 0;
++
++ /* ofs: offset within the first chip that the first read should start */
++
++ chipnum = (from >> cfi->chipshift);
++ ofs = from - (chipnum << cfi->chipshift);
++
++
++ *retlen = 0;
++
++ while (len) {
++ unsigned long thislen;
++
++ if (chipnum >= cfi->numchips)
++ break;
++
++ if ((len + ofs -1) >> cfi->chipshift)
++ thislen = (1<<cfi->chipshift) - ofs;
++ else
++ thislen = len;
++
++ ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
++ if (ret)
++ break;
++
++ *retlen += thislen;
++ len -= thislen;
++ buf += thislen;
++
++ ofs = 0;
++ chipnum++;
++ }
++ return ret;
++}
++
++static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum, int fast)
++{
++ unsigned long timeo = jiffies + HZ;
++ unsigned int Last[4];
++ unsigned long Count = 0;
++ struct cfi_private *cfi = map->fldrv_priv;
++ DECLARE_WAITQUEUE(wait, current);
++ int ret = 0;
++
++ retry:
++ cfi_spin_lock(chip->mutex);
++
++ if (chip->state != FL_READY){
++ printk("Waiting for chip to write, status = %d\n", chip->state);
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ add_wait_queue(&chip->wq, &wait);
++
++ cfi_spin_unlock(chip->mutex);
++
++ schedule();
++ remove_wait_queue(&chip->wq, &wait);
++ printk("Wake up to write:\n");
++ timeo = jiffies + HZ;
++
++ goto retry;
++ }
++
++ chip->state = FL_WRITING;
++
++ adr += chip->start;
++ ENABLE_VPP(map);
++ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
++ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
++ cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
++
++ cfi_write(map, datum, adr);
++
++ cfi_spin_unlock(chip->mutex);
++ cfi_udelay(chip->word_write_time);
++ cfi_spin_lock(chip->mutex);
++
++ Last[0] = cfi_read(map, adr);
++ // printk("Last[0] is %x\n", Last[0]);
++ Last[1] = cfi_read(map, adr);
++ // printk("Last[1] is %x\n", Last[1]);
++ Last[2] = cfi_read(map, adr);
++ // printk("Last[2] is %x\n", Last[2]);
++
++ for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && Count < 10000; Count++){
++ cfi_spin_unlock(chip->mutex);
++ cfi_udelay(10);
++ cfi_spin_lock(chip->mutex);
++
++ Last[Count % 4] = cfi_read(map, adr);
++ // printk("Last[%d%%4] is %x\n", Count, Last[Count%4]);
++ }
++
++ if (Last[(Count - 1) % 4] != datum){
++ printk("Last[%ld] is %x, datum is %x\n",(Count - 1) % 4,Last[(Count - 1) % 4],datum);
++ cfi_send_gen_cmd(0xF0, 0, chip->start, map, cfi, cfi->device_type, NULL);
++ DISABLE_VPP(map);
++ ret = -EIO;
++ }
++ DISABLE_VPP(map);
++ chip->state = FL_READY;
++ wake_up(&chip->wq);
++ cfi_spin_unlock(chip->mutex);
++
++ return ret;
++}
++
++static int cfi_sststd_write (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf)
++{
++ struct map_info *map = mtd->priv;
++ struct cfi_private *cfi = map->fldrv_priv;
++ int ret = 0;
++ int chipnum;
++ unsigned long ofs, chipstart;
++
++ *retlen = 0;
++ if (!len)
++ return 0;
++
++ chipnum = to >> cfi->chipshift;
++ ofs = to - (chipnum << cfi->chipshift);
++ chipstart = cfi->chips[chipnum].start;
++
++ /* If it's not bus-aligned, do the first byte write */
++ if (ofs & (CFIDEV_BUSWIDTH-1)) {
++ unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1);
++ int i = ofs - bus_ofs;
++ int n = 0;
++ u_char tmp_buf[4];
++ __u32 datum;
++
++ map->copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
++ while (len && i < CFIDEV_BUSWIDTH)
++ tmp_buf[i++] = buf[n++], len--;
++
++ if (cfi_buswidth_is_2()) {
++ datum = *(__u16*)tmp_buf;
++ } else if (cfi_buswidth_is_4()) {
++ datum = *(__u32*)tmp_buf;
++ } else {
++ return -EINVAL; /* should never happen, but be safe */
++ }
++
++ ret = do_write_oneword(map, &cfi->chips[chipnum],
++ bus_ofs, datum, 0);
++ if (ret)
++ return ret;
++
++ ofs += n;
++ buf += n;
++ (*retlen) += n;
++
++ if (ofs >> cfi->chipshift) {
++ chipnum ++;
++ ofs = 0;
++ if (chipnum == cfi->numchips)
++ return 0;
++ }
++ }
++
++ /* We are now aligned, write as much as possible */
++ while(len >= CFIDEV_BUSWIDTH) {
++ __u32 datum;
++
++ if (cfi_buswidth_is_1()) {
++ datum = *(__u8*)buf;
++ } else if (cfi_buswidth_is_2()) {
++ datum = *(__u16*)buf;
++ } else if (cfi_buswidth_is_4()) {
++ datum = *(__u32*)buf;
++ } else {
++ return -EINVAL;
++ }
++ ret = do_write_oneword(map, &cfi->chips[chipnum],
++ ofs, datum, cfi->fast_prog);
++ if (ret) {
++ return ret;
++ }
++
++ ofs += CFIDEV_BUSWIDTH;
++ buf += CFIDEV_BUSWIDTH;
++ (*retlen) += CFIDEV_BUSWIDTH;
++ len -= CFIDEV_BUSWIDTH;
++
++ if (ofs >> cfi->chipshift) {
++ chipnum ++;
++ ofs = 0;
++ if (chipnum == cfi->numchips)
++ return 0;
++ chipstart = cfi->chips[chipnum].start;
++ }
++ }
++
++ if (len & (CFIDEV_BUSWIDTH-1)) {
++ int i = 0, n = 0;
++ u_char tmp_buf[4];
++ __u32 datum;
++
++ map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH);
++ while (len--)
++ tmp_buf[i++] = buf[n++];
++
++ if (cfi_buswidth_is_2()) {
++ datum = *(__u16*)tmp_buf;
++ } else if (cfi_buswidth_is_4()) {
++ datum = *(__u32*)tmp_buf;
++ } else {
++ return -EINVAL; /* should never happen, but be safe */
++ }
++
++ ret = do_write_oneword(map, &cfi->chips[chipnum],
++ ofs, datum, 0);
++ if (ret)
++ return ret;
++
++ (*retlen) += n;
++ }
++
++ return 0;
++}
++
++static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr)
++{
++ unsigned int status;
++ unsigned long timeo = jiffies + HZ;
++ struct cfi_private *cfi = map->fldrv_priv;
++ unsigned int rdy_mask;
++ DECLARE_WAITQUEUE(wait, current);
++
++ retry:
++ cfi_spin_lock(chip->mutex);
++
++ if (chip->state != FL_READY){
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ add_wait_queue(&chip->wq, &wait);
++
++ cfi_spin_unlock(chip->mutex);
++
++ schedule();
++ remove_wait_queue(&chip->wq, &wait);
++ timeo = jiffies + HZ;
++
++ goto retry;
++ }
++
++ chip->state = FL_ERASING;
++
++ adr += chip->start;
++ ENABLE_VPP(map);
++ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
++ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
++ cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
++ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
++ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X16, NULL);
++ cfi_write(map, CMD(0x30), adr);
++
++ timeo = jiffies + (HZ*20);
++
++ cfi_spin_unlock(chip->mutex);
++ schedule_timeout(HZ);
++ cfi_spin_lock(chip->mutex);
++
++ rdy_mask = CMD(0x80);
++
++ /* Once the state machine's known to be working I'll do that */
++
++ while ( ( (status = cfi_read(map,adr)) & rdy_mask ) != rdy_mask ) {
++ static int z=0;
++
++ if (chip->state != FL_ERASING) {
++ /* Someone's suspended the erase. Sleep */
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ add_wait_queue(&chip->wq, &wait);
++
++ cfi_spin_unlock(chip->mutex);
++ printk("erase suspended. Sleeping\n");
++
++ schedule();
++ remove_wait_queue(&chip->wq, &wait);
++ timeo = jiffies + (HZ*2);
++ cfi_spin_lock(chip->mutex);
++ continue;
++ }
++
++ /* OK Still waiting */
++ if (time_after(jiffies, timeo)) {
++ chip->state = FL_READY;
++ cfi_spin_unlock(chip->mutex);
++ printk("waiting for erase to complete timed out.");
++ DISABLE_VPP(map);
++ return -EIO;
++ }
++
++ /* Latency issues. Drop the lock, wait a while and retry */
++ cfi_spin_unlock(chip->mutex);
++
++ z++;
++ if ( 0 && !(z % 100 ))
++ printk("chip not ready yet after erase. looping\n");
++
++ cfi_udelay(1);
++
++ cfi_spin_lock(chip->mutex);
++ continue;
++ }
++
++ /* Done and happy. */
++ DISABLE_VPP(map);
++ chip->state = FL_READY;
++ wake_up(&chip->wq);
++ cfi_spin_unlock(chip->mutex);
++ return 0;
++}
++
++static int cfi_sststd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr)
++{
++ struct map_info *map = mtd->priv;
++ struct cfi_private *cfi = map->fldrv_priv;
++ unsigned long adr, len;
++ int chipnum, ret = 0;
++ int i, first;
++ struct mtd_erase_region_info *regions = mtd->eraseregions;
++
++ if (instr->addr > mtd->size)
++ return -EINVAL;
++
++ if ((instr->len + instr->addr) > mtd->size)
++ return -EINVAL;
++
++ /* Check that both start and end of the requested erase are
++ * aligned with the erasesize at the appropriate addresses.
++ */
++
++ i = 0;
++
++ /* Skip all erase regions which are ended before the start of
++ the requested erase. Actually, to save on the calculations,
++ we skip to the first erase region which starts after the
++ start of the requested erase, and then go back one.
++ */
++
++ while (i < mtd->numeraseregions && instr->addr >= regions[i].offset)
++ i++;
++ i--;
++
++ /* OK, now i is pointing at the erase region in which this
++ erase request starts. Check the start of the requested
++ erase range is aligned with the erase size which is in
++ effect here.
++ */
++
++ if (instr->addr & (regions[i].erasesize-1))
++ return -EINVAL;
++
++ /* Remember the erase region we start on */
++ first = i;
++
++ /* Next, check that the end of the requested erase is aligned
++ * with the erase region at that address.
++ */
++
++ while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset)
++ i++;
++
++ /* As before, drop back one to point at the region in which
++ the address actually falls
++ */
++ i--;
++
++ if ((instr->addr + instr->len) & (regions[i].erasesize-1))
++ return -EINVAL;
++
++ chipnum = instr->addr >> cfi->chipshift;
++ adr = instr->addr - (chipnum << cfi->chipshift);
++ len = instr->len;
++
++ i=first;
++
++ while(len) {
++ ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
++
++ if (ret)
++ return ret;
++
++ adr += regions[i].erasesize;
++ len -= regions[i].erasesize;
++
++ if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift)))
++ i++;
++
++ if (adr >> cfi->chipshift) {
++ adr = 0;
++ chipnum++;
++
++ if (chipnum >= cfi->numchips)
++ break;
++ }
++ }
++
++ instr->state = MTD_ERASE_DONE;
++ if (instr->callback)
++ instr->callback(instr);
++
++ return 0;
++}
++
++static int cfi_sststd_erase_onesize(struct mtd_info *mtd, struct erase_info *instr)
++{
++ struct map_info *map = mtd->priv;
++ struct cfi_private *cfi = map->fldrv_priv;
++ unsigned long adr, len;
++ int chipnum, ret = 0;
++
++ if (instr->addr & (mtd->erasesize - 1))
++ return -EINVAL;
++
++ if (instr->len & (mtd->erasesize -1))
++ return -EINVAL;
++
++ if ((instr->len + instr->addr) > mtd->size)
++ return -EINVAL;
++
++ chipnum = instr->addr >> cfi->chipshift;
++ adr = instr->addr - (chipnum << cfi->chipshift);
++ len = instr->len;
++
++ while(len) {
++ ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr);
++
++ if (ret)
++ return ret;
++
++ adr += mtd->erasesize;
++ len -= mtd->erasesize;
++
++ if (adr >> cfi->chipshift) {
++ adr = 0;
++ chipnum++;
++
++ if (chipnum >= cfi->numchips)
++ break;
++ }
++ }
++
++ instr->state = MTD_ERASE_DONE;
++ if (instr->callback)
++ instr->callback(instr);
++
++ return 0;
++}
++
++static void cfi_sststd_sync (struct mtd_info *mtd)
++{
++ struct map_info *map = mtd->priv;
++ struct cfi_private *cfi = map->fldrv_priv;
++ int i;
++ struct flchip *chip;
++ int ret = 0;
++ DECLARE_WAITQUEUE(wait, current);
++
++ for (i=0; !ret && i<cfi->numchips; i++) {
++ chip = &cfi->chips[i];
++
++ retry:
++ cfi_spin_lock(chip->mutex);
++
++ switch(chip->state) {
++ case FL_READY:
++ case FL_STATUS:
++ case FL_CFI_QUERY:
++ case FL_JEDEC_QUERY:
++ chip->oldstate = chip->state;
++ chip->state = FL_SYNCING;
++ /* No need to wake_up() on this state change -
++ * as the whole point is that nobody can do anything
++ * with the chip now anyway.
++ */
++ case FL_SYNCING:
++ cfi_spin_unlock(chip->mutex);
++ break;
++
++ default:
++ /* Not an idle state */
++ add_wait_queue(&chip->wq, &wait);
++
++ cfi_spin_unlock(chip->mutex);
++
++ schedule();
++
++ remove_wait_queue(&chip->wq, &wait);
++
++ goto retry;
++ }
++ }
++
++ /* Unlock the chips again */
++
++ for (i--; i >=0; i--) {
++ chip = &cfi->chips[i];
++
++ cfi_spin_lock(chip->mutex);
++
++ if (chip->state == FL_SYNCING) {
++ chip->state = chip->oldstate;
++ wake_up(&chip->wq);
++ }
++ cfi_spin_unlock(chip->mutex);
++ }
++}
++
++
++static int cfi_sststd_suspend(struct mtd_info *mtd)
++{
++ struct map_info *map = mtd->priv;
++ struct cfi_private *cfi = map->fldrv_priv;
++ int i;
++ struct flchip *chip;
++ int ret = 0;
++//printk("suspend\n");
++
++ for (i=0; !ret && i<cfi->numchips; i++) {
++ chip = &cfi->chips[i];
++
++ cfi_spin_lock(chip->mutex);
++
++ switch(chip->state) {
++ case FL_READY:
++ case FL_STATUS:
++ case FL_CFI_QUERY:
++ case FL_JEDEC_QUERY:
++ chip->oldstate = chip->state;
++ chip->state = FL_PM_SUSPENDED;
++ /* No need to wake_up() on this state change -
++ * as the whole point is that nobody can do anything
++ * with the chip now anyway.
++ */
++ case FL_PM_SUSPENDED:
++ break;
++
++ default:
++ ret = -EAGAIN;
++ break;
++ }
++ cfi_spin_unlock(chip->mutex);
++ }
++
++ /* Unlock the chips again */
++
++ if (ret) {
++ for (i--; i >=0; i--) {
++ chip = &cfi->chips[i];
++
++ cfi_spin_lock(chip->mutex);
++
++ if (chip->state == FL_PM_SUSPENDED) {
++ chip->state = chip->oldstate;
++ wake_up(&chip->wq);
++ }
++ cfi_spin_unlock(chip->mutex);
++ }
++ }
++
++ return ret;
++}
++
++static void cfi_sststd_resume(struct mtd_info *mtd)
++{
++ struct map_info *map = mtd->priv;
++ struct cfi_private *cfi = map->fldrv_priv;
++ int i;
++ struct flchip *chip;
++//printk("resume\n");
++
++ for (i=0; i<cfi->numchips; i++) {
++
++ chip = &cfi->chips[i];
++
++ cfi_spin_lock(chip->mutex);
++
++ if (chip->state == FL_PM_SUSPENDED) {
++ chip->state = FL_READY;
++ cfi_write(map, CMD(0xF0), chip->start);
++ wake_up(&chip->wq);
++ }
++ else
++ printk("Argh. Chip not in PM_SUSPENDED state upon resume()\n");
++
++ cfi_spin_unlock(chip->mutex);
++ }
++}
++
++static void cfi_sststd_destroy(struct mtd_info *mtd)
++{
++ struct map_info *map = mtd->priv;
++ struct cfi_private *cfi = map->fldrv_priv;
++ kfree(cfi->cmdset_priv);
++ kfree(cfi);
++}
++
++#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE)
++#define cfi_sststd_init init_module
++#define cfi_sststd_exit cleanup_module
++#endif
++
++static char im_name[]="cfi_cmdset_0701";
++
++mod_init_t cfi_sststd_init(void)
++{
++ inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0701);
++ return 0;
++}
++
++mod_exit_t cfi_sststd_exit(void)
++{
++ inter_module_unregister(im_name);
++}
++
++module_init(cfi_sststd_init);
++module_exit(cfi_sststd_exit);
++
+diff -Nur linux-2.4.30/drivers/mtd/chips/cfi_probe.c linux-2.4.30.openwrt/drivers/mtd/chips/cfi_probe.c
+--- linux-2.4.30/drivers/mtd/chips/cfi_probe.c 2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.30.openwrt/drivers/mtd/chips/cfi_probe.c 2005-06-28 11:26:26.000000000 +0200
+@@ -67,8 +67,15 @@
+ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
+
+- if (!qry_present(map,base,cfi))
+- return 0;
++ if (!qry_present(map,base,cfi)) {
++ /* rather broken SST cfi probe (requires SST unlock) */
++ cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
++ cfi_send_gen_cmd(0xAA, 0x5555, base, map, cfi, cfi->device_type, NULL);
++ cfi_send_gen_cmd(0x55, 0x2AAA, base, map, cfi, cfi->device_type, NULL);
++ cfi_send_gen_cmd(0x98, 0x5555, base, map, cfi, cfi->device_type, NULL);
++ if (!qry_present(map,base,cfi))
++ return 0;
++ }
+
+ if (!cfi->numchips) {
+ /* This is the first time we're called. Set up the CFI
+diff -Nur linux-2.4.30/drivers/mtd/chips/gen_probe.c linux-2.4.30.openwrt/drivers/mtd/chips/gen_probe.c
+--- linux-2.4.30/drivers/mtd/chips/gen_probe.c 2003-08-25 13:44:42.000000000 +0200
++++ linux-2.4.30.openwrt/drivers/mtd/chips/gen_probe.c 2005-06-28 11:29:23.000000000 +0200
+@@ -328,13 +328,18 @@
+ return cfi_cmdset_0001(map, primary);
+ #endif
+ #ifdef CONFIG_MTD_CFI_AMDSTD
++ case 0x0006:
+ case 0x0002:
+ return cfi_cmdset_0002(map, primary);
+ #endif
+ #ifdef CONFIG_MTD_CFI_STAA
+- case 0x0020:
++ case 0x0020:
+ return cfi_cmdset_0020(map, primary);
+ #endif
++#ifdef CONFIG_MTD_CFI_SSTSTD
++ case 0x0701:
++ return cfi_cmdset_0701(map, primary);
++#endif
+ }
+
+ return cfi_cmdset_unknown(map, primary);
diff --git a/target/linux/generic-2.4/patches/006-gcc4_fixes.patch b/target/linux/generic-2.4/patches/006-gcc4_fixes.patch
new file mode 100644
index 0000000..4034d1b
--- /dev/null
+++ b/target/linux/generic-2.4/patches/006-gcc4_fixes.patch
@@ -0,0 +1,522 @@
+diff -rupN linux-2.4.32/Makefile linux-2.4.32.gcc4-fixes-v12/Makefile
+--- linux-2.4.32/Makefile 2005-11-17 13:27:30.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/Makefile 2005-11-17 13:32:13.000000000 +0100
+@@ -93,11 +93,17 @@ CPPFLAGS := -D__KERNEL__ -I$(HPATH)
+
+ CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
+ -fno-strict-aliasing -fno-common
++CFLAGS += -fno-builtin-sprintf
+ ifndef CONFIG_FRAME_POINTER
+ CFLAGS += -fomit-frame-pointer
+ endif
+ AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS)
+
++check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
++
++# disable pointer signedness warnings in gcc 4.0
++CFLAGS += $(call check_gcc,-Wno-pointer-sign,)
++
+ #
+ # ROOT_DEV specifies the default root-device when making the image.
+ # This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case
+diff -rupN linux-2.4.32/arch/i386/Makefile linux-2.4.32.gcc4-fixes-v12/arch/i386/Makefile
+--- linux-2.4.32/arch/i386/Makefile 2004-11-17 18:36:41.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/arch/i386/Makefile 2005-11-17 13:32:13.000000000 +0100
+@@ -23,8 +23,6 @@ LINKFLAGS =-T $(TOPDIR)/arch/i386/vmlinu
+
+ CFLAGS += -pipe
+
+-check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
+-
+ # prevent gcc from keeping the stack 16 byte aligned
+ CFLAGS += $(call check_gcc,-mpreferred-stack-boundary=2,)
+
+diff -rupN linux-2.4.32/arch/mips/Makefile linux-2.4.32.gcc4-fixes-v12/arch/mips/Makefile
+--- linux-2.4.32/arch/mips/Makefile 2005-01-19 18:00:52.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/arch/mips/Makefile 2005-11-17 13:32:13.000000000 +0100
+@@ -30,8 +30,6 @@ endif
+
+ MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+
+-check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
+-
+ #
+ #
+ # GCC uses -G 0 -mabicalls -fpic as default. We don't want PIC in the kernel
+diff -rupN linux-2.4.32/arch/mips64/Makefile linux-2.4.32.gcc4-fixes-v12/arch/mips64/Makefile
+--- linux-2.4.32/arch/mips64/Makefile 2005-01-19 18:00:52.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/arch/mips64/Makefile 2005-11-17 13:32:13.000000000 +0100
+@@ -26,7 +26,6 @@ ifdef CONFIG_CROSSCOMPILE
+ CROSS_COMPILE = $(tool-prefix)
+ endif
+
+-check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
+ check_gas = $(shell if $(CC) $(1) -Wa,-Z -c -o /dev/null -xassembler /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
+
+ #
+diff -rupN linux-2.4.32/arch/ppc/kernel/open_pic_defs.h linux-2.4.32.gcc4-fixes-v12/arch/ppc/kernel/open_pic_defs.h
+--- linux-2.4.32/arch/ppc/kernel/open_pic_defs.h 2003-06-14 13:30:19.000000000 +0200
++++ linux-2.4.32.gcc4-fixes-v12/arch/ppc/kernel/open_pic_defs.h 2005-11-17 13:32:13.000000000 +0100
+@@ -172,9 +172,6 @@ struct OpenPIC {
+ OpenPIC_Processor Processor[OPENPIC_MAX_PROCESSORS];
+ };
+
+-extern volatile struct OpenPIC *OpenPIC;
+-
+-
+ /*
+ * Current Task Priority Register
+ */
+diff -rupN linux-2.4.32/arch/x86_64/Makefile linux-2.4.32.gcc4-fixes-v12/arch/x86_64/Makefile
+--- linux-2.4.32/arch/x86_64/Makefile 2004-04-14 20:22:20.000000000 +0200
++++ linux-2.4.32.gcc4-fixes-v12/arch/x86_64/Makefile 2005-11-17 13:32:13.000000000 +0100
+@@ -38,8 +38,6 @@ OBJCOPY=$(CROSS_COMPILE)objcopy -O binar
+ LDFLAGS=-e stext
+ LINKFLAGS =-T $(TOPDIR)/arch/x86_64/vmlinux.lds $(LDFLAGS)
+
+-check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1 ; then echo "$(1)"; else echo "$(2)"; fi)
+-
+ CFLAGS += -mno-red-zone
+ CFLAGS += -mcmodel=kernel
+ CFLAGS += -pipe
+diff -rupN linux-2.4.32/arch/x86_64/ia32/ia32entry.S linux-2.4.32.gcc4-fixes-v12/arch/x86_64/ia32/ia32entry.S
+--- linux-2.4.32/arch/x86_64/ia32/ia32entry.S 2005-01-19 18:00:53.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/arch/x86_64/ia32/ia32entry.S 2005-11-17 13:32:13.000000000 +0100
+@@ -113,9 +113,18 @@ quiet_ni_syscall:
+ PTREGSCALL stub32_fork, sys32_fork
+ PTREGSCALL stub32_clone, sys32_clone
+ PTREGSCALL stub32_vfork, sys32_vfork
+- PTREGSCALL stub32_iopl, sys_iopl
+ PTREGSCALL stub32_rt_sigsuspend, sys_rt_sigsuspend
+
++ .macro PTREGSCALL3 label, func, arg
++ .globl \label
++\label:
++ leaq \func(%rip),%rax
++ leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
++ jmp ia32_ptregs_common
++ .endm
++
++ PTREGSCALL3 stub32_iopl, sys_iopl, %rsi
++
+ ENTRY(ia32_ptregs_common)
+ popq %r11
+ SAVE_REST
+diff -rupN linux-2.4.32/arch/x86_64/kernel/entry.S linux-2.4.32.gcc4-fixes-v12/arch/x86_64/kernel/entry.S
+--- linux-2.4.32/arch/x86_64/kernel/entry.S 2003-11-29 00:28:11.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/arch/x86_64/kernel/entry.S 2005-11-17 13:32:13.000000000 +0100
+@@ -249,7 +249,16 @@ intret_signal_test:
+ PTREGSCALL stub_vfork, sys_vfork
+ PTREGSCALL stub_rt_sigsuspend, sys_rt_sigsuspend
+ PTREGSCALL stub_sigaltstack, sys_sigaltstack
+- PTREGSCALL stub_iopl, sys_iopl
++
++ .macro PTREGSCALL3 label,func,arg
++ .globl \label
++\label:
++ leaq \func(%rip),%rax
++ leaq -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
++ jmp ptregscall_common
++ .endm
++
++ PTREGSCALL3 stub_iopl, sys_iopl, %rsi
+
+ ENTRY(ptregscall_common)
+ popq %r11
+diff -rupN linux-2.4.32/arch/x86_64/kernel/ioport.c linux-2.4.32.gcc4-fixes-v12/arch/x86_64/kernel/ioport.c
+--- linux-2.4.32/arch/x86_64/kernel/ioport.c 2003-11-29 00:28:11.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/arch/x86_64/kernel/ioport.c 2005-11-17 13:32:13.000000000 +0100
+@@ -81,9 +81,9 @@ asmlinkage long sys_ioperm(unsigned long
+ * code.
+ */
+
+-asmlinkage long sys_iopl(unsigned int level, struct pt_regs regs)
++asmlinkage long sys_iopl(unsigned int level, struct pt_regs *regs)
+ {
+- unsigned int old = (regs.eflags >> 12) & 3;
++ unsigned int old = (regs->eflags >> 12) & 3;
+
+ if (level > 3)
+ return -EINVAL;
+@@ -92,6 +92,6 @@ asmlinkage long sys_iopl(unsigned int le
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ }
+- regs.eflags = (regs.eflags & 0xffffffffffffcfff) | (level << 12);
++ regs->eflags = (regs->eflags &~ 0x3000UL) | (level << 12);
+ return 0;
+ }
+diff -rupN linux-2.4.32/drivers/acpi/bus.c linux-2.4.32.gcc4-fixes-v12/drivers/acpi/bus.c
+--- linux-2.4.32/drivers/acpi/bus.c 2005-01-19 18:00:53.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/drivers/acpi/bus.c 2005-11-17 13:32:13.000000000 +0100
+@@ -623,7 +623,7 @@ acpi_bus_generate_event (
+ int data)
+ {
+ struct acpi_bus_event *event = NULL;
+- u32 flags = 0;
++ unsigned long flags = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_generate_event");
+
+@@ -656,7 +656,7 @@ int
+ acpi_bus_receive_event (
+ struct acpi_bus_event *event)
+ {
+- u32 flags = 0;
++ unsigned long flags = 0;
+ struct acpi_bus_event *entry = NULL;
+
+ DECLARE_WAITQUEUE(wait, current);
+diff -rupN linux-2.4.32/drivers/sound/sound_firmware.c linux-2.4.32.gcc4-fixes-v12/drivers/sound/sound_firmware.c
+--- linux-2.4.32/drivers/sound/sound_firmware.c 2001-02-22 15:23:46.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/drivers/sound/sound_firmware.c 2005-11-17 13:32:13.000000000 +0100
+@@ -4,10 +4,11 @@
+ #include <linux/fs.h>
+ #include <linux/mm.h>
+ #include <linux/slab.h>
+-#include <linux/unistd.h>
++static int my_errno;
++#define errno my_errno
++#include <asm/unistd.h>
+ #include <asm/uaccess.h>
+
+-static int errno;
+ static int do_mod_firmware_load(const char *fn, char **fp)
+ {
+ int fd;
+diff -rupN linux-2.4.32/drivers/usb/host/ehci-q.c linux-2.4.32.gcc4-fixes-v12/drivers/usb/host/ehci-q.c
+--- linux-2.4.32/drivers/usb/host/ehci-q.c 2005-01-19 18:00:53.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/drivers/usb/host/ehci-q.c 2005-11-17 13:32:13.000000000 +0100
+@@ -199,8 +199,6 @@ ehci_urb_done (struct ehci_hcd *ehci, st
+ #ifdef INTR_AUTOMAGIC
+ struct urb *resubmit = 0;
+ struct usb_device *dev = 0;
+-
+- static int ehci_urb_enqueue (struct usb_hcd *, struct urb *, int);
+ #endif
+
+ if (likely (urb->hcpriv != 0)) {
+diff -rupN linux-2.4.32/drivers/usb/inode.c linux-2.4.32.gcc4-fixes-v12/drivers/usb/inode.c
+--- linux-2.4.32/drivers/usb/inode.c 2004-02-18 15:16:23.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/drivers/usb/inode.c 2005-11-17 13:32:13.000000000 +0100
+@@ -41,6 +41,9 @@
+ #include <linux/usbdevice_fs.h>
+ #include <asm/uaccess.h>
+
++static struct inode_operations usbdevfs_bus_inode_operations;
++static struct file_operations usbdevfs_bus_file_operations;
++
+ /* --------------------------------------------------------------------- */
+
+ /*
+diff -rupN linux-2.4.32/fs/hfs/trans.c linux-2.4.32.gcc4-fixes-v12/fs/hfs/trans.c
+--- linux-2.4.32/fs/hfs/trans.c 2001-02-22 15:23:47.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/fs/hfs/trans.c 2005-11-17 13:32:13.000000000 +0100
+@@ -33,6 +33,7 @@
+ #include <linux/hfs_fs_sb.h>
+ #include <linux/hfs_fs_i.h>
+ #include <linux/hfs_fs.h>
++#include <linux/compiler.h>
+
+ /*================ File-local variables ================*/
+
+@@ -78,7 +79,7 @@ static unsigned char mac2latin_map[128]
+ *
+ * Given a hexadecimal digit in ASCII, return the integer representation.
+ */
+-static inline const unsigned char dehex(char c) {
++static inline __attribute_const__ unsigned char dehex(char c) {
+ if ((c>='0')&&(c<='9')) {
+ return c-'0';
+ }
+diff -rupN linux-2.4.32/include/asm-i386/byteorder.h linux-2.4.32.gcc4-fixes-v12/include/asm-i386/byteorder.h
+--- linux-2.4.32/include/asm-i386/byteorder.h 2003-06-14 13:30:27.000000000 +0200
++++ linux-2.4.32.gcc4-fixes-v12/include/asm-i386/byteorder.h 2005-11-17 13:32:13.000000000 +0100
+@@ -2,6 +2,7 @@
+ #define _I386_BYTEORDER_H
+
+ #include <asm/types.h>
++#include <linux/compiler.h>
+
+ #ifdef __GNUC__
+
+@@ -10,7 +11,7 @@
+ #include <linux/config.h>
+ #endif
+
+-static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
++static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x)
+ {
+ #ifdef CONFIG_X86_BSWAP
+ __asm__("bswap %0" : "=r" (x) : "0" (x));
+@@ -26,7 +27,7 @@ static __inline__ __const__ __u32 ___arc
+
+ /* gcc should generate this for open coded C now too. May be worth switching to
+ it because inline assembly cannot be scheduled. -AK */
+-static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
++static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 x)
+ {
+ __asm__("xchgb %b0,%h0" /* swap bytes */
+ : "=q" (x)
+diff -rupN linux-2.4.32/include/asm-i386/processor.h linux-2.4.32.gcc4-fixes-v12/include/asm-i386/processor.h
+--- linux-2.4.32/include/asm-i386/processor.h 2004-02-18 15:16:24.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/include/asm-i386/processor.h 2005-11-17 13:32:13.000000000 +0100
+@@ -72,7 +72,6 @@ struct cpuinfo_x86 {
+ */
+
+ extern struct cpuinfo_x86 boot_cpu_data;
+-extern struct tss_struct init_tss[NR_CPUS];
+
+ #ifdef CONFIG_SMP
+ extern struct cpuinfo_x86 cpu_data[];
+@@ -357,6 +356,8 @@ struct tss_struct {
+ unsigned long __cacheline_filler[5];
+ };
+
++extern struct tss_struct init_tss[NR_CPUS];
++
+ struct thread_struct {
+ unsigned long esp0;
+ unsigned long eip;
+diff -rupN linux-2.4.32/include/asm-i386/string.h linux-2.4.32.gcc4-fixes-v12/include/asm-i386/string.h
+--- linux-2.4.32/include/asm-i386/string.h 2001-08-12 11:35:53.000000000 +0200
++++ linux-2.4.32.gcc4-fixes-v12/include/asm-i386/string.h 2005-11-17 13:32:13.000000000 +0100
+@@ -337,7 +337,7 @@ extern void __struct_cpy_bug (void);
+ #define struct_cpy(x,y) \
+ ({ \
+ if (sizeof(*(x)) != sizeof(*(y))) \
+- __struct_cpy_bug; \
++ __struct_cpy_bug(); \
+ memcpy(x, y, sizeof(*(x))); \
+ })
+
+diff -rupN linux-2.4.32/include/asm-m68k/setup.h linux-2.4.32.gcc4-fixes-v12/include/asm-m68k/setup.h
+--- linux-2.4.32/include/asm-m68k/setup.h 2000-01-29 13:07:40.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/include/asm-m68k/setup.h 2005-11-17 13:32:13.000000000 +0100
+@@ -361,12 +361,13 @@ extern int m68k_is040or060;
+ #ifndef __ASSEMBLY__
+ extern int m68k_num_memory; /* # of memory blocks found (and used) */
+ extern int m68k_realnum_memory; /* real # of memory blocks found */
+-extern struct mem_info m68k_memory[NUM_MEMINFO];/* memory description */
+
+ struct mem_info {
+ unsigned long addr; /* physical address of memory chunk */
+ unsigned long size; /* length of memory chunk (in bytes) */
+ };
++
++extern struct mem_info m68k_memory[NUM_MEMINFO];/* memory description */
+ #endif
+
+ #endif /* __KERNEL__ */
+diff -rupN linux-2.4.32/include/asm-ppc/byteorder.h linux-2.4.32.gcc4-fixes-v12/include/asm-ppc/byteorder.h
+--- linux-2.4.32/include/asm-ppc/byteorder.h 2003-06-14 13:30:28.000000000 +0200
++++ linux-2.4.32.gcc4-fixes-v12/include/asm-ppc/byteorder.h 2005-11-17 13:32:13.000000000 +0100
+@@ -2,6 +2,7 @@
+ #define _PPC_BYTEORDER_H
+
+ #include <asm/types.h>
++#include <linux/compiler.h>
+
+ #ifdef __GNUC__
+ #ifdef __KERNEL__
+@@ -50,7 +51,7 @@ extern __inline__ void st_le64(volatile
+ __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (taddr+4));
+ }
+
+-static __inline__ __const__ __u16 ___arch__swab16(__u16 value)
++static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 value)
+ {
+ __u16 result;
+
+@@ -58,7 +59,7 @@ static __inline__ __const__ __u16 ___arc
+ return result;
+ }
+
+-static __inline__ __const__ __u32 ___arch__swab32(__u32 value)
++static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 value)
+ {
+ __u32 result;
+
+diff -rupN linux-2.4.32/include/asm-ppc/time.h linux-2.4.32.gcc4-fixes-v12/include/asm-ppc/time.h
+--- linux-2.4.32/include/asm-ppc/time.h 2003-08-25 20:07:49.000000000 +0200
++++ linux-2.4.32.gcc4-fixes-v12/include/asm-ppc/time.h 2005-11-17 13:32:13.000000000 +0100
+@@ -12,6 +12,7 @@
+ #include <linux/config.h>
+ #include <linux/mc146818rtc.h>
+ #include <linux/threads.h>
++#include <linux/compiler.h>
+
+ #include <asm/processor.h>
+
+@@ -57,7 +58,7 @@ static __inline__ void set_dec(unsigned
+ /* Accessor functions for the timebase (RTC on 601) registers. */
+ /* If one day CONFIG_POWER is added just define __USE_RTC as 1 */
+ #ifdef CONFIG_6xx
+-extern __inline__ int const __USE_RTC(void) {
++extern __inline__ int __attribute_const__ __USE_RTC(void) {
+ return (mfspr(SPRN_PVR)>>16) == 1;
+ }
+ #else
+diff -rupN linux-2.4.32/include/asm-x86_64/byteorder.h linux-2.4.32.gcc4-fixes-v12/include/asm-x86_64/byteorder.h
+--- linux-2.4.32/include/asm-x86_64/byteorder.h 2002-11-30 17:12:31.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/include/asm-x86_64/byteorder.h 2005-11-17 13:32:13.000000000 +0100
+@@ -2,16 +2,17 @@
+ #define _X86_64_BYTEORDER_H
+
+ #include <asm/types.h>
++#include <linux/compiler.h>
+
+ #ifdef __GNUC__
+
+-static __inline__ __const__ __u64 ___arch__swab64(__u64 x)
++static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 x)
+ {
+ __asm__("bswapq %0" : "=r" (x) : "0" (x));
+ return x;
+ }
+
+-static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
++static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 x)
+ {
+ __asm__("bswapl %0" : "=r" (x) : "0" (x));
+ return x;
+diff -rupN linux-2.4.32/include/asm-x86_64/processor.h linux-2.4.32.gcc4-fixes-v12/include/asm-x86_64/processor.h
+--- linux-2.4.32/include/asm-x86_64/processor.h 2005-11-17 13:27:30.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/include/asm-x86_64/processor.h 2005-11-17 13:32:13.000000000 +0100
+@@ -68,7 +68,6 @@ struct cpuinfo_x86 {
+ #define X86_VENDOR_UNKNOWN 0xff
+
+ extern struct cpuinfo_x86 boot_cpu_data;
+-extern struct tss_struct init_tss[NR_CPUS];
+
+ #ifdef CONFIG_SMP
+ extern struct cpuinfo_x86 cpu_data[];
+@@ -300,6 +299,8 @@ struct tss_struct {
+ u32 io_bitmap[IO_BITMAP_SIZE];
+ } __attribute__((packed)) ____cacheline_aligned;
+
++extern struct tss_struct init_tss[NR_CPUS];
++
+ struct thread_struct {
+ unsigned long rsp0;
+ unsigned long rip;
+diff -rupN linux-2.4.32/include/linux/byteorder/swab.h linux-2.4.32.gcc4-fixes-v12/include/linux/byteorder/swab.h
+--- linux-2.4.32/include/linux/byteorder/swab.h 2002-11-30 17:12:31.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/include/linux/byteorder/swab.h 2005-11-17 13:32:13.000000000 +0100
+@@ -15,6 +15,8 @@
+ *
+ */
+
++#include <linux/compiler.h>
++
+ /* casts are necessary for constants, because we never know how for sure
+ * how U/UL/ULL map to __u16, __u32, __u64. At least not in a portable way.
+ */
+@@ -156,7 +158,7 @@
+ #endif /* OPTIMIZE */
+
+
+-static __inline__ __const__ __u16 __fswab16(__u16 x)
++static __inline__ __attribute_const__ __u16 __fswab16(__u16 x)
+ {
+ return __arch__swab16(x);
+ }
+@@ -169,7 +171,7 @@ static __inline__ void __swab16s(__u16 *
+ __arch__swab16s(addr);
+ }
+
+-static __inline__ __const__ __u32 __fswab24(__u32 x)
++static __inline__ __attribute_const__ __u32 __fswab24(__u32 x)
+ {
+ return __arch__swab24(x);
+ }
+@@ -182,7 +184,7 @@ static __inline__ void __swab24s(__u32 *
+ __arch__swab24s(addr);
+ }
+
+-static __inline__ __const__ __u32 __fswab32(__u32 x)
++static __inline__ __attribute_const__ __u32 __fswab32(__u32 x)
+ {
+ return __arch__swab32(x);
+ }
+@@ -196,7 +198,7 @@ static __inline__ void __swab32s(__u32 *
+ }
+
+ #ifdef __BYTEORDER_HAS_U64__
+-static __inline__ __const__ __u64 __fswab64(__u64 x)
++static __inline__ __attribute_const__ __u64 __fswab64(__u64 x)
+ {
+ # ifdef __SWAB_64_THRU_32__
+ __u32 h = x >> 32;
+diff -rupN linux-2.4.32/include/linux/compiler.h linux-2.4.32.gcc4-fixes-v12/include/linux/compiler.h
+--- linux-2.4.32/include/linux/compiler.h 2004-11-17 18:36:42.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/include/linux/compiler.h 2005-11-17 13:32:13.000000000 +0100
+@@ -27,6 +27,12 @@
+ #define __attribute_used__ /* not implemented */
+ #endif /* __GNUC__ */
+
++#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
++#define __attribute_const__ __attribute__((__const__))
++#else
++#define __attribute_const__ /* unimplemented */
++#endif
++
+ #if __GNUC__ == 3
+ #if __GNUC_MINOR__ >= 1
+ # define inline __inline__ __attribute__((always_inline))
+diff -rupN linux-2.4.32/include/linux/fs.h linux-2.4.32.gcc4-fixes-v12/include/linux/fs.h
+--- linux-2.4.32/include/linux/fs.h 2005-04-04 19:56:05.000000000 +0200
++++ linux-2.4.32.gcc4-fixes-v12/include/linux/fs.h 2005-11-17 13:32:13.000000000 +0100
+@@ -1559,7 +1559,6 @@ static inline int is_mounted(kdev_t dev)
+ unsigned long generate_cluster(kdev_t, int b[], int);
+ unsigned long generate_cluster_swab32(kdev_t, int b[], int);
+ extern kdev_t ROOT_DEV;
+-extern char root_device_name[];
+
+
+ extern void show_buffers(void);
+diff -rupN linux-2.4.32/include/linux/ufs_fs.h linux-2.4.32.gcc4-fixes-v12/include/linux/ufs_fs.h
+--- linux-2.4.32/include/linux/ufs_fs.h 2001-11-23 22:40:15.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/include/linux/ufs_fs.h 2005-11-17 13:32:13.000000000 +0100
+@@ -555,7 +555,6 @@ extern struct buffer_head * ufs_bread (s
+ extern struct file_operations ufs_dir_operations;
+
+ /* super.c */
+-extern struct file_system_type ufs_fs_type;
+ extern void ufs_warning (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+ extern void ufs_error (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+ extern void ufs_panic (struct super_block *, const char *, const char *, ...) __attribute__ ((format (printf, 3, 4)));
+diff -rupN linux-2.4.32/include/linux/usbdevice_fs.h linux-2.4.32.gcc4-fixes-v12/include/linux/usbdevice_fs.h
+--- linux-2.4.32/include/linux/usbdevice_fs.h 2003-11-29 00:28:14.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/include/linux/usbdevice_fs.h 2005-11-17 13:32:13.000000000 +0100
+@@ -185,8 +185,6 @@ extern struct file_operations usbdevfs_d
+ extern struct file_operations usbdevfs_devices_fops;
+ extern struct file_operations usbdevfs_device_file_operations;
+ extern struct inode_operations usbdevfs_device_inode_operations;
+-extern struct inode_operations usbdevfs_bus_inode_operations;
+-extern struct file_operations usbdevfs_bus_file_operations;
+ extern void usbdevfs_conn_disc_event(void);
+
+ #endif /* __KERNEL__ */
+diff -rupN linux-2.4.32/include/net/icmp.h linux-2.4.32.gcc4-fixes-v12/include/net/icmp.h
+--- linux-2.4.32/include/net/icmp.h 2001-04-28 12:35:26.000000000 +0200
++++ linux-2.4.32.gcc4-fixes-v12/include/net/icmp.h 2005-11-17 13:32:13.000000000 +0100
+@@ -23,6 +23,7 @@
+
+ #include <net/sock.h>
+ #include <net/protocol.h>
++#include <net/snmp.h>
+
+ struct icmp_err {
+ int errno;
+diff -rupN linux-2.4.32/include/net/ipv6.h linux-2.4.32.gcc4-fixes-v12/include/net/ipv6.h
+--- linux-2.4.32/include/net/ipv6.h 2004-11-17 18:36:43.000000000 +0100
++++ linux-2.4.32.gcc4-fixes-v12/include/net/ipv6.h 2005-11-17 13:32:13.000000000 +0100
+@@ -101,6 +101,7 @@ struct frag_hdr {
+ #ifdef __KERNEL__
+
+ #include <net/sock.h>
++#include <net/snmp.h>
+
+ /* sysctls */
+ extern int sysctl_ipv6_bindv6only;
diff --git a/target/linux/generic-2.4/patches/007-more_gcc4_fixes.patch b/target/linux/generic-2.4/patches/007-more_gcc4_fixes.patch
new file mode 100644
index 0000000..b234c70
--- /dev/null
+++ b/target/linux/generic-2.4/patches/007-more_gcc4_fixes.patch
@@ -0,0 +1,1339 @@
+diff -rupN linux-2.4.32/drivers/atm/fore200e.c linux-2.4.32.more-gcc4-fixes-v1/drivers/atm/fore200e.c
+--- linux-2.4.32/drivers/atm/fore200e.c 2004-11-17 18:36:41.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/atm/fore200e.c 2005-11-17 13:31:16.000000000 +0100
+@@ -112,8 +112,8 @@
+ #endif
+
+
+-extern const struct atmdev_ops fore200e_ops;
+-extern const struct fore200e_bus fore200e_bus[];
++static const struct atmdev_ops fore200e_ops;
++static const struct fore200e_bus fore200e_bus[];
+
+ static struct fore200e* fore200e_boards = NULL;
+
+diff -rupN linux-2.4.32/drivers/atm/horizon.c linux-2.4.32.more-gcc4-fixes-v1/drivers/atm/horizon.c
+--- linux-2.4.32/drivers/atm/horizon.c 2004-02-18 15:16:22.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/atm/horizon.c 2005-11-17 13:31:16.000000000 +0100
+@@ -481,6 +481,7 @@ static inline void dump_skb (char * pref
+ return;
+ }
+
++#if 0 /* unused and in conflict with <asm-ppc/system.h> */
+ static inline void dump_regs (hrz_dev * dev) {
+ #ifdef DEBUG_HORIZON
+ PRINTD (DBG_REGS, "CONTROL 0: %#x", rd_regl (dev, CONTROL_0_REG));
+@@ -494,6 +495,7 @@ static inline void dump_regs (hrz_dev *
+ #endif
+ return;
+ }
++#endif
+
+ static inline void dump_framer (hrz_dev * dev) {
+ #ifdef DEBUG_HORIZON
+diff -rupN linux-2.4.32/drivers/atm/iphase.c linux-2.4.32.more-gcc4-fixes-v1/drivers/atm/iphase.c
+--- linux-2.4.32/drivers/atm/iphase.c 2004-11-17 18:36:41.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/atm/iphase.c 2005-11-17 13:31:16.000000000 +0100
+@@ -82,6 +82,7 @@ static IADEV *ia_dev[8];
+ static struct atm_dev *_ia_dev[8];
+ static int iadev_count;
+ static void ia_led_timer(unsigned long arg);
++static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb);
+ static struct timer_list ia_timer = { function: ia_led_timer };
+ struct atm_vcc *vcc_close_que[100];
+ static int IA_TX_BUF = DFL_TX_BUFFERS, IA_TX_BUF_SZ = DFL_TX_BUF_SZ;
+@@ -627,7 +628,6 @@ static int ia_que_tx (IADEV *iadev) {
+ int num_desc;
+ struct atm_vcc *vcc;
+ struct ia_vcc *iavcc;
+- static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb);
+ num_desc = ia_avail_descs(iadev);
+ while (num_desc && (skb = skb_dequeue(&iadev->tx_backlog))) {
+ if (!(vcc = ATM_SKB(skb)->vcc)) {
+diff -rupN linux-2.4.32/drivers/atm/iphase.h linux-2.4.32.more-gcc4-fixes-v1/drivers/atm/iphase.h
+--- linux-2.4.32/drivers/atm/iphase.h 2003-06-14 13:30:20.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/atm/iphase.h 2005-11-17 13:31:16.000000000 +0100
+@@ -68,8 +68,6 @@
+ #define IF_IADBG_SUNI_STAT 0x02000000 // suni statistics
+ #define IF_IADBG_RESET 0x04000000
+
+-extern unsigned int IADebugFlag;
+-
+ #define IF_IADBG(f) if (IADebugFlag & (f))
+
+ #ifdef CONFIG_ATM_IA_DEBUG /* Debug build */
+diff -rupN linux-2.4.32/drivers/block/nbd.c linux-2.4.32.more-gcc4-fixes-v1/drivers/block/nbd.c
+--- linux-2.4.32/drivers/block/nbd.c 2005-04-04 19:56:04.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/block/nbd.c 2005-11-17 13:31:16.000000000 +0100
+@@ -74,6 +74,29 @@ static int requests_in;
+ static int requests_out;
+ #endif
+
++static void
++nbd_end_request(struct request *req)
++{
++ struct buffer_head *bh;
++ unsigned nsect;
++ unsigned long flags;
++ int uptodate = (req->errors == 0) ? 1 : 0;
++
++#ifdef PARANOIA
++ requests_out++;
++#endif
++ spin_lock_irqsave(&io_request_lock, flags);
++ while((bh = req->bh) != NULL) {
++ nsect = bh->b_size >> 9;
++ blk_finished_io(nsect);
++ req->bh = bh->b_reqnext;
++ bh->b_reqnext = NULL;
++ bh->b_end_io(bh, uptodate);
++ }
++ blkdev_release_request(req);
++ spin_unlock_irqrestore(&io_request_lock, flags);
++}
++
+ static int nbd_open(struct inode *inode, struct file *file)
+ {
+ int dev;
+diff -rupN linux-2.4.32/drivers/block/paride/pd.c linux-2.4.32.more-gcc4-fixes-v1/drivers/block/paride/pd.c
+--- linux-2.4.32/drivers/block/paride/pd.c 2002-11-30 17:12:24.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/block/paride/pd.c 2005-11-17 13:31:16.000000000 +0100
+@@ -343,7 +343,14 @@ static char *pd_errs[17] = { "ERR","INDE
+
+ /* kernel glue structures */
+
+-extern struct block_device_operations pd_fops;
++static struct block_device_operations pd_fops = {
++ owner: THIS_MODULE,
++ open: pd_open,
++ release: pd_release,
++ ioctl: pd_ioctl,
++ check_media_change: pd_check_media,
++ revalidate: pd_revalidate
++};
+
+ static struct gendisk pd_gendisk = {
+ major: PD_MAJOR,
+@@ -355,15 +362,6 @@ static struct gendisk pd_gendisk = {
+ fops: &pd_fops,
+ };
+
+-static struct block_device_operations pd_fops = {
+- owner: THIS_MODULE,
+- open: pd_open,
+- release: pd_release,
+- ioctl: pd_ioctl,
+- check_media_change: pd_check_media,
+- revalidate: pd_revalidate
+-};
+-
+ void pd_init_units( void )
+
+ { int unit, j;
+diff -rupN linux-2.4.32/drivers/block/xd.c linux-2.4.32.more-gcc4-fixes-v1/drivers/block/xd.c
+--- linux-2.4.32/drivers/block/xd.c 2002-11-30 17:12:24.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/block/xd.c 2005-11-17 13:31:16.000000000 +0100
+@@ -125,7 +125,12 @@ static int xd_sizes[XD_MAXDRIVES << 6],
+ static int xd_blocksizes[XD_MAXDRIVES << 6];
+ static int xd_maxsect[XD_MAXDRIVES << 6];
+
+-extern struct block_device_operations xd_fops;
++static struct block_device_operations xd_fops = {
++ owner: THIS_MODULE,
++ open: xd_open,
++ release: xd_release,
++ ioctl: xd_ioctl,
++};
+
+ static struct gendisk xd_gendisk = {
+ major: MAJOR_NR,
+@@ -138,13 +143,6 @@ static struct gendisk xd_gendisk = {
+ fops: &xd_fops,
+ };
+
+-static struct block_device_operations xd_fops = {
+- owner: THIS_MODULE,
+- open: xd_open,
+- release: xd_release,
+- ioctl: xd_ioctl,
+-};
+-
+ static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int);
+ static DECLARE_WAIT_QUEUE_HEAD(xd_wait_open);
+ static u8 xd_valid[XD_MAXDRIVES] = { 0,0 };
+diff -rupN linux-2.4.32/drivers/cdrom/sbpcd.c linux-2.4.32.more-gcc4-fixes-v1/drivers/cdrom/sbpcd.c
+--- linux-2.4.32/drivers/cdrom/sbpcd.c 2001-11-06 12:12:06.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/cdrom/sbpcd.c 2005-11-17 13:31:16.000000000 +0100
+@@ -525,6 +525,8 @@ static int sbp_data(struct request *req)
+ static int cmd_out(void);
+ static int DiskInfo(void);
+ static int sbpcd_chk_disk_change(kdev_t);
++static int cmd_out_T(void);
++static int cc_DriveReset(void);
+
+ /*==========================================================================*/
+
+@@ -1213,8 +1215,6 @@ static int get_state_T(void)
+ {
+ int i;
+
+- static int cmd_out_T(void);
+-
+ clr_cmdbuf();
+ D_S[d].n_bytes=1;
+ drvcmd[0]=CMDT_STATUS;
+@@ -1362,7 +1362,6 @@ static int cmd_out_T(void)
+ #define CMDT_TRIES 1000
+ #define TEST_FALSE_FF 1
+
+- static int cc_DriveReset(void);
+ int i, j, l=0, m, ntries;
+ long flags;
+
+diff -rupN linux-2.4.32/drivers/char/ip2/i2lib.c linux-2.4.32.more-gcc4-fixes-v1/drivers/char/ip2/i2lib.c
+--- linux-2.4.32/drivers/char/ip2/i2lib.c 2005-01-19 18:00:53.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/char/ip2/i2lib.c 2005-11-17 13:31:16.000000000 +0100
+@@ -1262,7 +1262,7 @@ i2RetryFlushOutput(i2ChanStrPtr pCh)
+
+ }
+ if ( old_flags & STOPFL_FLAG ) {
+- if ( 1 == i2QueueCommands(PTYPE_INLINE, pCh, 0, 1, CMD_STOPFL) > 0 ) {
++ if ( 1 == i2QueueCommands(PTYPE_INLINE, pCh, 0, 1, CMD_STOPFL)) {
+ old_flags = 0; // Success - clear flags
+ }
+
+diff -rupN linux-2.4.32/drivers/char/rio/rio_linux.c linux-2.4.32.more-gcc4-fixes-v1/drivers/char/rio/rio_linux.c
+--- linux-2.4.32/drivers/char/rio/rio_linux.c 2002-02-26 13:26:56.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/char/rio/rio_linux.c 2005-11-17 13:31:16.000000000 +0100
+@@ -1205,8 +1205,8 @@ static int __init rio_init(void)
+ hp->Ivec = get_irq (pdev);
+ if (((1 << hp->Ivec) & rio_irqmask) == 0)
+ hp->Ivec = 0;
+- hp->CardP = (struct DpRam *)
+ hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
++ hp->CardP = (struct DpRam *) hp->Caddr;
+ hp->Type = RIO_PCI;
+ hp->Copy = rio_pcicopy;
+ hp->Mode = RIO_PCI_BOOT_FROM_RAM;
+@@ -1277,8 +1277,8 @@ static int __init rio_init(void)
+ if (((1 << hp->Ivec) & rio_irqmask) == 0)
+ hp->Ivec = 0;
+ hp->Ivec |= 0x8000; /* Mark as non-sharable */
+- hp->CardP = (struct DpRam *)
+ hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
++ hp->CardP = (struct DpRam *) hp->Caddr;
+ hp->Type = RIO_PCI;
+ hp->Copy = rio_pcicopy;
+ hp->Mode = RIO_PCI_BOOT_FROM_RAM;
+@@ -1329,8 +1329,8 @@ static int __init rio_init(void)
+ hp->PaddrP = rio_probe_addrs[i];
+ /* There was something about the IRQs of these cards. 'Forget what.--REW */
+ hp->Ivec = 0;
+- hp->CardP = (struct DpRam *)
+ hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
++ hp->CardP = (struct DpRam *) hp->Caddr;
+ hp->Type = RIO_AT;
+ hp->Copy = rio_pcicopy; /* AT card PCI???? - PVDL
+ * -- YES! this is now a normal copy. Only the
+diff -rupN linux-2.4.32/drivers/char/sonypi.c linux-2.4.32.more-gcc4-fixes-v1/drivers/char/sonypi.c
+--- linux-2.4.32/drivers/char/sonypi.c 2004-04-14 20:22:20.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/char/sonypi.c 2005-11-17 13:31:16.000000000 +0100
+@@ -60,6 +60,35 @@ static int compat; /* = 0 */
+ static int useinput = 1;
+ static unsigned long mask = 0xffffffff;
+
++static inline int sonypi_ec_write(u8 addr, u8 value) {
++#ifdef CONFIG_ACPI_EC
++ if (SONYPI_ACPI_ACTIVE)
++ return ec_write(addr, value);
++#endif
++ wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
++ outb_p(0x81, SONYPI_CST_IOPORT);
++ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
++ outb_p(addr, SONYPI_DATA_IOPORT);
++ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
++ outb_p(value, SONYPI_DATA_IOPORT);
++ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
++ return 0;
++}
++
++static inline int sonypi_ec_read(u8 addr, u8 *value) {
++#ifdef CONFIG_ACPI_EC
++ if (SONYPI_ACPI_ACTIVE)
++ return ec_read(addr, value);
++#endif
++ wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
++ outb_p(0x80, SONYPI_CST_IOPORT);
++ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
++ outb_p(addr, SONYPI_DATA_IOPORT);
++ wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
++ *value = inb_p(SONYPI_DATA_IOPORT);
++ return 0;
++}
++
+ /* Inits the queue */
+ static inline void sonypi_initq(void) {
+ sonypi_device.queue.head = sonypi_device.queue.tail = 0;
+diff -rupN linux-2.4.32/drivers/char/sonypi.h linux-2.4.32.more-gcc4-fixes-v1/drivers/char/sonypi.h
+--- linux-2.4.32/drivers/char/sonypi.h 2004-04-14 20:22:20.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/char/sonypi.h 2005-11-17 13:31:16.000000000 +0100
+@@ -401,37 +401,6 @@ struct sonypi_device {
+ #define SONYPI_ACPI_ACTIVE 0
+ #endif /* CONFIG_ACPI */
+
+-extern int verbose;
+-
+-static inline int sonypi_ec_write(u8 addr, u8 value) {
+-#ifdef CONFIG_ACPI_EC
+- if (SONYPI_ACPI_ACTIVE)
+- return ec_write(addr, value);
+-#endif
+- wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
+- outb_p(0x81, SONYPI_CST_IOPORT);
+- wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+- outb_p(addr, SONYPI_DATA_IOPORT);
+- wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+- outb_p(value, SONYPI_DATA_IOPORT);
+- wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+- return 0;
+-}
+-
+-static inline int sonypi_ec_read(u8 addr, u8 *value) {
+-#ifdef CONFIG_ACPI_EC
+- if (SONYPI_ACPI_ACTIVE)
+- return ec_read(addr, value);
+-#endif
+- wait_on_command(1, inb_p(SONYPI_CST_IOPORT) & 3, ITERATIONS_LONG);
+- outb_p(0x80, SONYPI_CST_IOPORT);
+- wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+- outb_p(addr, SONYPI_DATA_IOPORT);
+- wait_on_command(0, inb_p(SONYPI_CST_IOPORT) & 2, ITERATIONS_LONG);
+- *value = inb_p(SONYPI_DATA_IOPORT);
+- return 0;
+-}
+-
+ #endif /* __KERNEL__ */
+
+ #endif /* _SONYPI_PRIV_H_ */
+diff -rupN linux-2.4.32/drivers/char/sx.c linux-2.4.32.more-gcc4-fixes-v1/drivers/char/sx.c
+--- linux-2.4.32/drivers/char/sx.c 2005-01-19 18:00:53.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/char/sx.c 2005-11-17 13:31:16.000000000 +0100
+@@ -522,13 +522,13 @@ static int sx_busy_wait_eq (struct sx_bo
+
+ func_enter ();
+
+- for (i=0; i < TIMEOUT_1 > 0;i++)
++ for (i=0; i < TIMEOUT_1 ;i++)
+ if ((read_sx_byte (board, offset) & mask) == correctval) {
+ func_exit ();
+ return 1;
+ }
+
+- for (i=0; i < TIMEOUT_2 > 0;i++) {
++ for (i=0; i < TIMEOUT_2 ;i++) {
+ if ((read_sx_byte (board, offset) & mask) == correctval) {
+ func_exit ();
+ return 1;
+@@ -548,13 +548,13 @@ static int sx_busy_wait_neq (struct sx_b
+
+ func_enter ();
+
+- for (i=0; i < TIMEOUT_1 > 0;i++)
++ for (i=0; i < TIMEOUT_1 ;i++)
+ if ((read_sx_byte (board, offset) & mask) != badval) {
+ func_exit ();
+ return 1;
+ }
+
+- for (i=0; i < TIMEOUT_2 > 0;i++) {
++ for (i=0; i < TIMEOUT_2 ;i++) {
+ if ((read_sx_byte (board, offset) & mask) != badval) {
+ func_exit ();
+ return 1;
+diff -rupN linux-2.4.32/drivers/char/tpqic02.c linux-2.4.32.more-gcc4-fixes-v1/drivers/char/tpqic02.c
+--- linux-2.4.32/drivers/char/tpqic02.c 2004-08-08 10:56:31.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/char/tpqic02.c 2005-11-17 13:31:16.000000000 +0100
+@@ -202,6 +202,7 @@ static int mode_access; /* access mode:
+
+ static int qic02_get_resources(void);
+ static void qic02_release_resources(void);
++static void finish_rw(int cmd);
+
+ /* This is a pointer to the actual kernel buffer where the interrupt routines
+ * read from/write to. It is needed because the DMA channels 1 and 3 cannot
+@@ -820,7 +821,6 @@ static int get_ext_status3(void)
+ static int tp_sense(int ignore)
+ {
+ unsigned err = 0, exnr = 0, gs = 0;
+- static void finish_rw(int cmd);
+
+ if (TPQDBG(SENSE_TEXT))
+ printk(TPQIC02_NAME ": tp_sense(ignore=0x%x) enter\n",
+@@ -2173,16 +2173,6 @@ static ssize_t qic02_tape_write(struct f
+ * Don't rewind if the minor bits specify density 0.
+ */
+
+-static int qic02_tape_open(struct inode *inode, struct file *filp)
+-{
+- static int qic02_tape_open_no_use_count(struct inode *,
+- struct file *);
+- int open_error;
+-
+- open_error = qic02_tape_open_no_use_count(inode, filp);
+- return open_error;
+-}
+-
+ static int qic02_tape_open_no_use_count(struct inode *inode,
+ struct file *filp)
+ {
+@@ -2385,6 +2375,14 @@ static int qic02_tape_open_no_use_count(
+ } /* qic02_tape_open */
+
+
++static int qic02_tape_open(struct inode *inode, struct file *filp)
++{
++ int open_error;
++
++ open_error = qic02_tape_open_no_use_count(inode, filp);
++ return open_error;
++}
++
+ static int qic02_tape_release(struct inode *inode, struct file *filp)
+ {
+ kdev_t dev = inode->i_rdev;
+diff -rupN linux-2.4.32/drivers/i2c/i2c-core.c linux-2.4.32.more-gcc4-fixes-v1/drivers/i2c/i2c-core.c
+--- linux-2.4.32/drivers/i2c/i2c-core.c 2005-06-01 18:02:21.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/i2c/i2c-core.c 2005-11-17 13:31:16.000000000 +0100
+@@ -720,7 +720,7 @@ int i2cproc_cleanup(void)
+ * ----------------------------------------------------
+ */
+
+-int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg msgs[],int num)
++int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs,int num)
+ {
+ int ret;
+
+@@ -750,7 +750,7 @@ int i2c_master_send(struct i2c_client *c
+ msg.addr = client->addr;
+ msg.flags = client->flags & I2C_M_TEN;
+ msg.len = count;
+- (const char *)msg.buf = buf;
++ msg.buf = (char *)buf;
+
+ DEB2(printk(KERN_DEBUG "i2c-core.o: master_send: writing %d bytes on %s.\n",
+ count,client->adapter->name));
+diff -rupN linux-2.4.32/drivers/i2c/i2c-proc.c linux-2.4.32.more-gcc4-fixes-v1/drivers/i2c/i2c-proc.c
+--- linux-2.4.32/drivers/i2c/i2c-proc.c 2005-01-19 18:00:53.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/i2c/i2c-proc.c 2005-11-17 13:31:16.000000000 +0100
+@@ -205,7 +205,7 @@ void i2c_deregister_entry(int id)
+ table = i2c_entries[id]->ctl_table;
+ unregister_sysctl_table(i2c_entries[id]);
+ /* 2-step kfree needed to keep gcc happy about const points */
+- (const char *) temp = table[4].procname;
++ temp = (char *) table[4].procname;
+ kfree(temp);
+ kfree(table);
+ i2c_entries[id] = NULL;
+@@ -287,7 +287,7 @@ int i2c_proc_chips(ctl_table * ctl, int
+ if(copy_to_user(buffer, BUF, buflen))
+ return -EFAULT;
+ curbufsize += buflen;
+- (char *) buffer += buflen;
++ buffer = (char *) buffer + buflen;
+ }
+ *lenp = curbufsize;
+ filp->f_pos += curbufsize;
+@@ -318,7 +318,7 @@ int i2c_sysctl_chips(ctl_table * table,
+ sizeof(struct
+ i2c_chips_data)))
+ return -EFAULT;
+- (char *) oldval +=
++ oldval = (char *) oldval +
+ sizeof(struct i2c_chips_data);
+ nrels++;
+ }
+@@ -473,7 +473,7 @@ int i2c_parse_reals(int *nrels, void *bu
+ !((ret=get_user(nextchar, (char *) buffer))) &&
+ isspace((int) nextchar)) {
+ bufsize--;
+- ((char *) buffer)++;
++ buffer = (char *) buffer + 1;
+ }
+
+ if (ret)
+@@ -492,7 +492,7 @@ int i2c_parse_reals(int *nrels, void *bu
+ && (nextchar == '-')) {
+ min = 1;
+ bufsize--;
+- ((char *) buffer)++;
++ buffer = (char *) buffer + 1;
+ }
+ if (ret)
+ return -EFAULT;
+@@ -503,7 +503,7 @@ int i2c_parse_reals(int *nrels, void *bu
+ isdigit((int) nextchar)) {
+ res = res * 10 + nextchar - '0';
+ bufsize--;
+- ((char *) buffer)++;
++ buffer = (char *) buffer + 1;
+ }
+ if (ret)
+ return -EFAULT;
+@@ -517,7 +517,7 @@ int i2c_parse_reals(int *nrels, void *bu
+ if (bufsize && (nextchar == '.')) {
+ /* Skip the dot */
+ bufsize--;
+- ((char *) buffer)++;
++ buffer = (char *) buffer + 1;
+
+ /* Read digits while they are significant */
+ while (bufsize && (mag > 0) &&
+@@ -526,7 +526,7 @@ int i2c_parse_reals(int *nrels, void *bu
+ res = res * 10 + nextchar - '0';
+ mag--;
+ bufsize--;
+- ((char *) buffer)++;
++ buffer = (char *) buffer + 1;
+ }
+ if (ret)
+ return -EFAULT;
+@@ -542,7 +542,7 @@ int i2c_parse_reals(int *nrels, void *bu
+ !((ret=get_user(nextchar, (char *) buffer))) &&
+ !isspace((int) nextchar)) {
+ bufsize--;
+- ((char *) buffer)++;
++ buffer = (char *) buffer + 1;
+ }
+ if (ret)
+ return -EFAULT;
+@@ -574,7 +574,7 @@ int i2c_write_reals(int nrels, void *buf
+ if(put_user(' ', (char *) buffer))
+ return -EFAULT;
+ curbufsize++;
+- ((char *) buffer)++;
++ buffer = (char *) buffer + 1;
+ }
+
+ /* Fill BUF with the representation of the next string */
+@@ -615,7 +615,7 @@ int i2c_write_reals(int nrels, void *buf
+ if(copy_to_user(buffer, BUF, buflen))
+ return -EFAULT;
+ curbufsize += buflen;
+- (char *) buffer += buflen;
++ buffer = (char *) buffer + buflen;
+
+ nr++;
+ }
+diff -rupN linux-2.4.32/drivers/ide/legacy/hd.c linux-2.4.32.more-gcc4-fixes-v1/drivers/ide/legacy/hd.c
+--- linux-2.4.32/drivers/ide/legacy/hd.c 2003-06-14 13:30:22.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/ide/legacy/hd.c 2005-11-17 13:31:16.000000000 +0100
+@@ -694,7 +694,11 @@ static int hd_release(struct inode * ino
+ return 0;
+ }
+
+-extern struct block_device_operations hd_fops;
++static struct block_device_operations hd_fops = {
++ open: hd_open,
++ release: hd_release,
++ ioctl: hd_ioctl,
++};
+
+ static struct gendisk hd_gendisk = {
+ major: MAJOR_NR,
+@@ -718,12 +722,6 @@ static void hd_interrupt(int irq, void *
+ sti();
+ }
+
+-static struct block_device_operations hd_fops = {
+- open: hd_open,
+- release: hd_release,
+- ioctl: hd_ioctl,
+-};
+-
+ /*
+ * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags
+ * means we run the IRQ-handler with interrupts disabled: this is bad for
+diff -rupN linux-2.4.32/drivers/ieee1394/highlevel.c linux-2.4.32.more-gcc4-fixes-v1/drivers/ieee1394/highlevel.c
+--- linux-2.4.32/drivers/ieee1394/highlevel.c 2003-11-29 00:28:11.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/ieee1394/highlevel.c 2005-11-17 13:31:16.000000000 +0100
+@@ -500,7 +500,7 @@ int highlevel_read(struct hpsb_host *hos
+ rcode = RCODE_TYPE_ERROR;
+ }
+
+- (u8 *)data += partlength;
++ data += partlength;
+ length -= partlength;
+ addr += partlength;
+
+@@ -546,7 +546,7 @@ int highlevel_write(struct hpsb_host *ho
+ rcode = RCODE_TYPE_ERROR;
+ }
+
+- (u8 *)data += partlength;
++ data += partlength;
+ length -= partlength;
+ addr += partlength;
+
+diff -rupN linux-2.4.32/drivers/isdn/eicon/eicon.h linux-2.4.32.more-gcc4-fixes-v1/drivers/isdn/eicon/eicon.h
+--- linux-2.4.32/drivers/isdn/eicon/eicon.h 2002-08-07 00:52:20.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/isdn/eicon/eicon.h 2005-11-17 13:31:16.000000000 +0100
+@@ -344,7 +344,6 @@ typedef struct eicon_card {
+
+ #include "eicon_idi.h"
+
+-extern eicon_card *cards;
+ extern char *eicon_ctype_name[];
+
+
+diff -rupN linux-2.4.32/drivers/isdn/hisax/hfc_pci.c linux-2.4.32.more-gcc4-fixes-v1/drivers/isdn/hisax/hfc_pci.c
+--- linux-2.4.32/drivers/isdn/hisax/hfc_pci.c 2004-11-17 18:36:42.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/isdn/hisax/hfc_pci.c 2005-11-17 13:31:16.000000000 +0100
+@@ -1742,7 +1742,7 @@ setup_hfcpci(struct IsdnCard *card)
+ /* Allocate memory for FIFOS */
+ /* Because the HFC-PCI needs a 32K physical alignment, we */
+ /* need to allocate the double mem and align the address */
+- if (!((void *) cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) {
++ if (!(cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) {
+ printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n");
+ return 0;
+ }
+diff -rupN linux-2.4.32/drivers/md/lvm-internal.h linux-2.4.32.more-gcc4-fixes-v1/drivers/md/lvm-internal.h
+--- linux-2.4.32/drivers/md/lvm-internal.h 2003-11-29 00:28:12.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/md/lvm-internal.h 2005-11-17 13:31:16.000000000 +0100
+@@ -45,7 +45,6 @@ extern int loadtime;
+ extern const char *const lvm_name;
+
+
+-extern uint vg_count;
+ extern vg_t *vg[];
+ extern struct file_operations lvm_chr_fops;
+
+diff -rupN linux-2.4.32/drivers/media/video/bttvp.h linux-2.4.32.more-gcc4-fixes-v1/drivers/media/video/bttvp.h
+--- linux-2.4.32/drivers/media/video/bttvp.h 2003-11-29 00:28:12.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/media/video/bttvp.h 2005-11-17 13:31:16.000000000 +0100
+@@ -58,7 +58,6 @@ extern int pvr_boot(struct bttv *btv);
+
+ #define BTTV_MAX 16
+ extern unsigned int bttv_num; /* number of Bt848s in use */
+-extern struct bttv bttvs[BTTV_MAX];
+
+ #define UNSET -1U
+
+@@ -203,6 +202,8 @@ struct bttv {
+ int shutdown;
+ void (*audio_hook)(struct bttv *btv, struct video_audio *v, int set);
+ };
++
++extern struct bttv bttvs[BTTV_MAX];
+ #endif
+
+ #define btwrite(dat,adr) writel((dat), (char *) (btv->bt848_mem+(adr)))
+diff -rupN linux-2.4.32/drivers/media/video/videodev.c linux-2.4.32.more-gcc4-fixes-v1/drivers/media/video/videodev.c
+--- linux-2.4.32/drivers/media/video/videodev.c 2004-08-08 10:56:31.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/media/video/videodev.c 2005-11-17 13:31:16.000000000 +0100
+@@ -489,7 +489,18 @@ static void videodev_proc_destroy_dev (s
+
+ #endif /* CONFIG_VIDEO_PROC_FS */
+
+-extern struct file_operations video_fops;
++static struct file_operations video_fops=
++{
++ owner: THIS_MODULE,
++ llseek: no_llseek,
++ read: video_read,
++ write: video_write,
++ ioctl: video_ioctl,
++ mmap: video_mmap,
++ open: video_open,
++ release: video_release,
++ poll: video_poll,
++};
+
+ /**
+ * video_register_device - register video4linux devices
+@@ -633,19 +644,6 @@ void video_unregister_device(struct vide
+ }
+
+
+-static struct file_operations video_fops=
+-{
+- owner: THIS_MODULE,
+- llseek: no_llseek,
+- read: video_read,
+- write: video_write,
+- ioctl: video_ioctl,
+- mmap: video_mmap,
+- open: video_open,
+- release: video_release,
+- poll: video_poll,
+-};
+-
+ /*
+ * Initialise video for linux
+ */
+diff -rupN linux-2.4.32/drivers/net/3c507.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/3c507.c
+--- linux-2.4.32/drivers/net/3c507.c 2003-11-29 00:28:12.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/3c507.c 2005-11-17 13:31:16.000000000 +0100
+@@ -306,6 +306,7 @@ static void el16_tx_timeout (struct net_
+ static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
+ static void init_82586_mem(struct net_device *dev);
+ static struct ethtool_ops netdev_ethtool_ops;
++static void init_rx_bufs(struct net_device *);
+
+
+ /* Check for a network adaptor of this type, and return '0' iff one exists.
+@@ -602,7 +603,6 @@ static void el16_interrupt(int irq, void
+ }
+
+ if ((status & 0x0070) != 0x0040 && netif_running(dev)) {
+- static void init_rx_bufs(struct net_device *);
+ /* The Rx unit is not ready, it must be hung. Restart the receiver by
+ initializing the rx buffers, and issuing an Rx start command. */
+ if (net_debug)
+diff -rupN linux-2.4.32/drivers/net/acenic.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/acenic.c
+--- linux-2.4.32/drivers/net/acenic.c 2003-08-25 20:07:43.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/acenic.c 2005-11-17 13:31:16.000000000 +0100
+@@ -594,6 +594,7 @@ static struct net_device *root_dev;
+
+ static int probed __initdata = 0;
+
++static void ace_watchdog(struct net_device *dev);
+
+ int __devinit acenic_probe (ACE_PROBE_ARG)
+ {
+@@ -665,7 +666,6 @@ int __devinit acenic_probe (ACE_PROBE_AR
+ dev->vlan_rx_kill_vid = ace_vlan_rx_kill_vid;
+ #endif
+ if (1) {
+- static void ace_watchdog(struct net_device *dev);
+ dev->tx_timeout = &ace_watchdog;
+ dev->watchdog_timeo = 5*HZ;
+ }
+diff -rupN linux-2.4.32/drivers/net/arcnet/arcnet.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/arcnet/arcnet.c
+--- linux-2.4.32/drivers/net/arcnet/arcnet.c 2003-08-25 20:07:43.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/arcnet/arcnet.c 2005-11-17 13:31:16.000000000 +0100
+@@ -277,7 +277,7 @@ static void release_arcbuf(struct net_de
+ BUGLVL(D_DURING) {
+ BUGMSG(D_DURING, "release_arcbuf: freed #%d; buffer queue is now: ",
+ bufnum);
+- for (i = lp->next_buf; i != lp->first_free_buf; i = ++i % 5)
++ for (i = lp->next_buf; i != lp->first_free_buf; i = (i+1) % 5)
+ BUGMSG2(D_DURING, "#%d ", lp->buf_queue[i]);
+ BUGMSG2(D_DURING, "\n");
+ }
+@@ -310,7 +310,7 @@ static int get_arcbuf(struct net_device
+
+ BUGLVL(D_DURING) {
+ BUGMSG(D_DURING, "get_arcbuf: got #%d; buffer queue is now: ", buf);
+- for (i = lp->next_buf; i != lp->first_free_buf; i = ++i % 5)
++ for (i = lp->next_buf; i != lp->first_free_buf; i = (i+1) % 5)
+ BUGMSG2(D_DURING, "#%d ", lp->buf_queue[i]);
+ BUGMSG2(D_DURING, "\n");
+ }
+diff -rupN linux-2.4.32/drivers/net/arlan.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/arlan.c
+--- linux-2.4.32/drivers/net/arlan.c 2002-08-07 00:52:20.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/arlan.c 2005-11-17 13:31:16.000000000 +0100
+@@ -12,7 +12,7 @@
+ # error FIXME: this driver requires a 32-bit platform
+ #endif
+
+-static const char *arlan_version = "C.Jennigs 97 & Elmer.Joandi@ut.ee Oct'98, http://www.ylenurme.ee/~elmer/655/";
++const char *arlan_version = "C.Jennigs 97 & Elmer.Joandi@ut.ee Oct'98, http://www.ylenurme.ee/~elmer/655/";
+
+ struct net_device *arlan_device[MAX_ARLANS];
+ int last_arlan;
+diff -rupN linux-2.4.32/drivers/net/arlan.h linux-2.4.32.more-gcc4-fixes-v1/drivers/net/arlan.h
+--- linux-2.4.32/drivers/net/arlan.h 2001-03-30 19:05:06.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/arlan.h 2005-11-17 13:31:16.000000000 +0100
+@@ -47,7 +47,6 @@ extern int init_arlan_proc(void);
+
+ extern struct net_device *arlan_device[MAX_ARLANS];
+ extern int arlan_debug;
+-extern char * siteName;
+ extern int arlan_entry_debug;
+ extern int arlan_exit_debug;
+ extern int testMemory;
+diff -rupN linux-2.4.32/drivers/net/bonding/bond_alb.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/bonding/bond_alb.c
+--- linux-2.4.32/drivers/net/bonding/bond_alb.c 2004-04-14 20:22:20.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/bonding/bond_alb.c 2005-11-17 13:31:16.000000000 +0100
+@@ -1275,7 +1275,7 @@ void bond_alb_deinitialize(struct bondin
+ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
+ {
+ struct bonding *bond = bond_dev->priv;
+- struct ethhdr *eth_data = (struct ethhdr *)skb->mac.raw = skb->data;
++ struct ethhdr *eth_data;
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+ struct slave *tx_slave = NULL;
+ static u32 ip_bcast = 0xffffffff;
+@@ -1285,6 +1285,9 @@ int bond_alb_xmit(struct sk_buff *skb, s
+ u8 *hash_start = NULL;
+ int res = 1;
+
++ skb->mac.raw = (unsigned char *)skb->data;
++ eth_data = (struct ethhdr *)skb->mac.raw;
++
+ /* make sure that the curr_active_slave and the slaves list do
+ * not change during tx
+ */
+diff -rupN linux-2.4.32/drivers/net/de4x5.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/de4x5.c
+--- linux-2.4.32/drivers/net/de4x5.c 2004-02-18 15:16:23.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/de4x5.c 2005-11-17 13:31:16.000000000 +0100
+@@ -5109,7 +5109,7 @@ mii_get_phy(struct net_device *dev)
+ lp->useMII = TRUE;
+
+ /* Search the MII address space for possible PHY devices */
+- for (n=0, lp->mii_cnt=0, i=1; !((i==1) && (n==1)); i=(++i)%DE4X5_MAX_MII) {
++ for (n=0, lp->mii_cnt=0, i=1; !((i==1) && (n==1)); i=(i+1)%DE4X5_MAX_MII) {
+ lp->phy[lp->active].addr = i;
+ if (i==0) n++; /* Count cycles */
+ while (de4x5_reset_phy(dev)<0) udelay(100);/* Wait for reset */
+diff -rupN linux-2.4.32/drivers/net/depca.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/depca.c
+--- linux-2.4.32/drivers/net/depca.c 2003-06-14 13:30:23.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/depca.c 2005-11-17 13:31:16.000000000 +0100
+@@ -1746,7 +1746,7 @@ static int load_packet(struct net_device
+
+ /* set up the buffer descriptors */
+ len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+- for (i = entry; i != end; i = (++i) & lp->txRingMask) {
++ for (i = entry; i != end; i = (i+1) & lp->txRingMask) {
+ /* clean out flags */
+ writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base);
+ writew(0x0000, &lp->tx_ring[i].misc); /* clears other error flags */
+diff -rupN linux-2.4.32/drivers/net/hamradio/baycom_epp.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/hamradio/baycom_epp.c
+--- linux-2.4.32/drivers/net/hamradio/baycom_epp.c 2002-11-30 17:12:25.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/hamradio/baycom_epp.c 2005-11-17 13:31:16.000000000 +0100
+@@ -60,8 +60,10 @@
+ #include <net/ax25.h>
+ #endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
+
++static int my_errno;
++#define errno my_errno
+ #define __KERNEL_SYSCALLS__
+-#include <linux/unistd.h>
++#include <asm/unistd.h>
+
+ /* --------------------------------------------------------------------- */
+
+@@ -370,8 +372,6 @@ static char eppconfig_path[256] = "/usr/
+
+ static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL };
+
+-static int errno;
+-
+ static int exec_eppfpga(void *b)
+ {
+ struct baycom_state *bc = (struct baycom_state *)b;
+diff -rupN linux-2.4.32/drivers/net/hamradio/soundmodem/sm.h linux-2.4.32.more-gcc4-fixes-v1/drivers/net/hamradio/soundmodem/sm.h
+--- linux-2.4.32/drivers/net/hamradio/soundmodem/sm.h 2002-08-07 00:52:20.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/hamradio/soundmodem/sm.h 2005-11-17 13:31:16.000000000 +0100
+@@ -151,7 +151,6 @@ struct hardware_info {
+ /* --------------------------------------------------------------------- */
+
+ extern const char sm_drvname[];
+-extern const char sm_drvinfo[];
+
+ /* --------------------------------------------------------------------- */
+ /*
+@@ -353,7 +352,6 @@ extern const struct hardware_info sm_hw_
+
+ extern const struct modem_tx_info *sm_modem_tx_table[];
+ extern const struct modem_rx_info *sm_modem_rx_table[];
+-extern const struct hardware_info *sm_hardware_table[];
+
+ /* --------------------------------------------------------------------- */
+
+diff -rupN linux-2.4.32/drivers/net/irda/donauboe.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/irda/donauboe.c
+--- linux-2.4.32/drivers/net/irda/donauboe.c 2003-06-14 13:30:23.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/irda/donauboe.c 2005-11-17 13:31:16.000000000 +0100
+@@ -209,7 +209,11 @@ static int do_probe = DO_PROBE;
+ #ifdef CRC_EXPORTED
+ extern __u16 const irda_crc16_table[];
+ #else
+-static __u16 const irda_crc16_table[256] = {
++/* Our local version of irda_crc16_table must have a unique
++ name to prevent extern-redefined-as-static compile errors.
++ This #define redirects the irda_fcs() macro to our version. */
++#define irda_crc16_table donauboe_irda_crc16_table
++static __u16 const donauboe_irda_crc16_table[256] = {
+ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+diff -rupN linux-2.4.32/drivers/net/rrunner.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/rrunner.c
+--- linux-2.4.32/drivers/net/rrunner.c 2003-06-14 13:30:23.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/rrunner.c 2005-11-17 13:31:16.000000000 +0100
+@@ -234,7 +234,7 @@ int __init rr_hippi_probe (struct net_de
+ * Don't access any registes before this point!
+ */
+ #ifdef __BIG_ENDIAN
+- writel(readl(&regs->HostCtrl) | NO_SWAP, &regs->HostCtrl);
++ writel(readl(&rrpriv->regs->HostCtrl) | NO_SWAP, &rrpriv->regs->HostCtrl);
+ #endif
+ /*
+ * Need to add a case for little-endian 64-bit hosts here.
+diff -rupN linux-2.4.32/drivers/net/sk98lin/skvpd.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/sk98lin/skvpd.c
+--- linux-2.4.32/drivers/net/sk98lin/skvpd.c 2005-04-04 19:56:04.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/sk98lin/skvpd.c 2005-11-17 13:31:16.000000000 +0100
+@@ -472,7 +472,7 @@ SK_IOC IoC) /* IO Context */
+ ((unsigned char)pAC->vpd.vpd_buf[0x40] == 0x3c) &&
+ ((unsigned char)pAC->vpd.vpd_buf[0x41] == 0x45) ) {
+ printk(KERN_INFO "sk98lin : humm... Asus mainboard with buggy VPD ? correcting data.\n");
+- (unsigned char)pAC->vpd.vpd_buf[0x40] = 0x38;
++ pAC->vpd.vpd_buf[0x40] = 0x38;
+ }
+
+ /* find the end tag of the RO area */
+diff -rupN linux-2.4.32/drivers/net/wan/comx-hw-comx.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/wan/comx-hw-comx.c
+--- linux-2.4.32/drivers/net/wan/comx-hw-comx.c 2002-11-30 17:12:26.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/wan/comx-hw-comx.c 2005-11-17 13:31:16.000000000 +0100
+@@ -92,9 +92,9 @@ struct comx_privdata {
+ };
+
+ static struct net_device *memory_used[(COMX_MEM_MAX - COMX_MEM_MIN) / 0x10000];
+-extern struct comx_hardware hicomx_hw;
+-extern struct comx_hardware comx_hw;
+-extern struct comx_hardware cmx_hw;
++static struct comx_hardware hicomx_hw;
++static struct comx_hardware comx_hw;
++static struct comx_hardware cmx_hw;
+
+ static void COMX_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+diff -rupN linux-2.4.32/drivers/net/wan/comx.h linux-2.4.32.more-gcc4-fixes-v1/drivers/net/wan/comx.h
+--- linux-2.4.32/drivers/net/wan/comx.h 2001-08-16 23:47:01.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/wan/comx.h 2005-11-17 13:31:16.000000000 +0100
+@@ -212,8 +212,6 @@ typedef u16 word;
+ #define SEEK_END 2
+ #endif
+
+-extern struct proc_dir_entry * comx_root_dir;
+-
+ extern int comx_register_hardware(struct comx_hardware *comx_hw);
+ extern int comx_unregister_hardware(char *name);
+ extern int comx_register_protocol(struct comx_protocol *comx_line);
+diff -rupN linux-2.4.32/drivers/net/wan/sdla_fr.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/wan/sdla_fr.c
+--- linux-2.4.32/drivers/net/wan/sdla_fr.c 2003-11-29 00:28:12.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/wan/sdla_fr.c 2005-11-17 13:31:16.000000000 +0100
+@@ -3929,7 +3929,7 @@ static int process_udp_mgmt_pkt(sdla_t*
+ break;
+ }
+
+- (void *)ptr_trc_el = card->u.f.curr_trc_el;
++ ptr_trc_el = (void *)card->u.f.curr_trc_el;
+
+ buffer_length = 0;
+ fr_udp_pkt->data[0x00] = 0x00;
+@@ -3980,7 +3980,7 @@ static int process_udp_mgmt_pkt(sdla_t*
+
+ ptr_trc_el ++;
+ if((void *)ptr_trc_el > card->u.f.trc_el_last)
+- (void*)ptr_trc_el = card->u.f.trc_el_base;
++ ptr_trc_el = (void*)card->u.f.trc_el_base;
+
+ buffer_length += sizeof(fpipemon_trc_hdr_t);
+ if(fpipemon_trc->fpipemon_trc_hdr.data_passed) {
+diff -rupN linux-2.4.32/drivers/net/wan/sdladrv.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/wan/sdladrv.c
+--- linux-2.4.32/drivers/net/wan/sdladrv.c 2001-09-23 21:06:34.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/wan/sdladrv.c 2005-11-17 13:31:16.000000000 +0100
+@@ -1002,7 +1002,7 @@ int sdla_peek (sdlahw_t* hw, unsigned lo
+ peek_by_4 ((unsigned long)hw->dpmbase + curpos, buf,
+ curlen);
+ addr += curlen;
+- (char*)buf += curlen;
++ buf = (char*)buf + curlen;
+ len -= curlen;
+ }
+
+@@ -1086,7 +1086,7 @@ int sdla_poke (sdlahw_t* hw, unsigned lo
+ poke_by_4 ((unsigned long)hw->dpmbase + curpos, buf,
+ curlen);
+ addr += curlen;
+- (char*)buf += curlen;
++ buf = (char*)buf + curlen;
+ len -= curlen;
+ }
+
+@@ -2127,10 +2127,10 @@ static int detect_s514 (sdlahw_t* hw)
+ modname, hw->irq);
+
+ /* map the physical PCI memory to virtual memory */
+- (void *)hw->dpmbase = ioremap((unsigned long)S514_mem_base_addr,
++ hw->dpmbase = (void *)ioremap((unsigned long)S514_mem_base_addr,
+ (unsigned long)MAX_SIZEOF_S514_MEMORY);
+ /* map the physical control register memory to virtual memory */
+- (void *)hw->vector = ioremap(
++ hw->vector = (unsigned long)ioremap(
+ (unsigned long)(S514_mem_base_addr + S514_CTRL_REG_BYTE),
+ (unsigned long)16);
+
+diff -rupN linux-2.4.32/drivers/net/wan/sdlamain.c linux-2.4.32.more-gcc4-fixes-v1/drivers/net/wan/sdlamain.c
+--- linux-2.4.32/drivers/net/wan/sdlamain.c 2003-11-29 00:28:12.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/net/wan/sdlamain.c 2005-11-17 13:31:16.000000000 +0100
+@@ -1027,7 +1027,7 @@ static int ioctl_dump (sdla_t* card, sdl
+ #endif
+ dump.length -= len;
+ dump.offset += len;
+- (char*)dump.ptr += len;
++ dump.ptr = (char*)dump.ptr + len;
+ }
+
+ sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */
+diff -rupN linux-2.4.32/drivers/scsi/advansys.c linux-2.4.32.more-gcc4-fixes-v1/drivers/scsi/advansys.c
+--- linux-2.4.32/drivers/scsi/advansys.c 2005-01-19 18:00:53.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/scsi/advansys.c 2005-11-17 13:31:16.000000000 +0100
+@@ -3456,9 +3456,9 @@ do { \
+ /*
+ * Default EEPROM Configuration structure defined in a_init.c.
+ */
+-extern ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
+-extern ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
+-extern ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
++static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
++static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
++static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
+
+ /*
+ * DvcGetPhyAddr() flag arguments
+@@ -7171,7 +7171,7 @@ asc_isr_callback(ASC_DVC_VAR *asc_dvc_va
+ * then return the number of underrun bytes.
+ */
+ if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
+- qdonep->remain_bytes <= scp->request_bufflen != 0) {
++ qdonep->remain_bytes <= scp->request_bufflen) {
+ ASC_DBG1(1, "asc_isr_callback: underrun condition %u bytes\n",
+ (unsigned) qdonep->remain_bytes);
+ scp->resid = qdonep->remain_bytes;
+diff -rupN linux-2.4.32/drivers/scsi/atp870u.c linux-2.4.32.more-gcc4-fixes-v1/drivers/scsi/atp870u.c
+--- linux-2.4.32/drivers/scsi/atp870u.c 2002-08-07 00:52:21.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/scsi/atp870u.c 2005-11-17 13:31:16.000000000 +0100
+@@ -807,19 +807,19 @@ oktosend:
+ bttl = virt_to_bus(sgpnt[j].address);
+ l = sgpnt[j].length;
+ while (l > 0x10000) {
+- (unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0x0000;
+- (unsigned short int) (((unsigned short int *) (prd))[i + 2]) = 0x0000;
+- (unsigned long) (((unsigned long *) (prd))[i >> 1]) = bttl;
++ (((unsigned short int *) (prd))[i + 3]) = 0x0000;
++ (((unsigned short int *) (prd))[i + 2]) = 0x0000;
++ (((unsigned long *) (prd))[i >> 1]) = bttl;
+ l -= 0x10000;
+ bttl += 0x10000;
+ i += 0x04;
+ }
+- (unsigned long) (((unsigned long *) (prd))[i >> 1]) = bttl;
+- (unsigned short int) (((unsigned short int *) (prd))[i + 2]) = l;
+- (unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0;
++ (((unsigned long *) (prd))[i >> 1]) = bttl;
++ (((unsigned short int *) (prd))[i + 2]) = l;
++ (((unsigned short int *) (prd))[i + 3]) = 0;
+ i += 0x04;
+ }
+- (unsigned short int) (((unsigned short int *) (prd))[i - 1]) = 0x8000;
++ (((unsigned short int *) (prd))[i - 1]) = 0x8000;
+ } else {
+ /*
+ * For a linear request write a chain of blocks
+@@ -828,16 +828,16 @@ oktosend:
+ l = workrequ->request_bufflen;
+ i = 0;
+ while (l > 0x10000) {
+- (unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0x0000;
+- (unsigned short int) (((unsigned short int *) (prd))[i + 2]) = 0x0000;
+- (unsigned long) (((unsigned long *) (prd))[i >> 1]) = bttl;
++ (((unsigned short int *) (prd))[i + 3]) = 0x0000;
++ (((unsigned short int *) (prd))[i + 2]) = 0x0000;
++ (((unsigned long *) (prd))[i >> 1]) = bttl;
+ l -= 0x10000;
+ bttl += 0x10000;
+ i += 0x04;
+ }
+- (unsigned short int) (((unsigned short int *) (prd))[i + 3]) = 0x8000;
+- (unsigned short int) (((unsigned short int *) (prd))[i + 2]) = l;
+- (unsigned long) (((unsigned long *) (prd))[i >> 1]) = bttl;
++ (((unsigned short int *) (prd))[i + 3]) = 0x8000;
++ (((unsigned short int *) (prd))[i + 2]) = l;
++ (((unsigned long *) (prd))[i >> 1]) = bttl;
+ }
+ tmpcip = tmpcip + 4;
+ dev->id[target_id].prdaddru = virt_to_bus(dev->id[target_id].prd_tableu);
+diff -rupN linux-2.4.32/drivers/scsi/cpqfcTSstructs.h linux-2.4.32.more-gcc4-fixes-v1/drivers/scsi/cpqfcTSstructs.h
+--- linux-2.4.32/drivers/scsi/cpqfcTSstructs.h 2004-02-18 15:16:23.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/scsi/cpqfcTSstructs.h 2005-11-17 13:31:16.000000000 +0100
+@@ -965,7 +965,6 @@ void fcSestReset(CPQFCHBA *);
+
+ void cpqfc_pci_unmap(struct pci_dev *pcidev, Scsi_Cmnd * cmd, PTACHYON fcChip, __u32 x_ID);
+
+-extern const __u8 valid_al_pa[];
+ extern const int number_of_al_pa;
+
+ #define FCP_RESID_UNDER 0x80000
+diff -rupN linux-2.4.32/drivers/scsi/cpqfcTSworker.c linux-2.4.32.more-gcc4-fixes-v1/drivers/scsi/cpqfcTSworker.c
+--- linux-2.4.32/drivers/scsi/cpqfcTSworker.c 2003-06-14 13:30:24.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/scsi/cpqfcTSworker.c 2005-11-17 13:31:16.000000000 +0100
+@@ -48,6 +48,7 @@
+ #include "cpqfcTSchip.h"
+ #include "cpqfcTSstructs.h"
+ #include "cpqfcTStrigger.h"
++static const __u8 valid_al_pa[];
+
+ //#define LOGIN_DBG 1
+
+diff -rupN linux-2.4.32/drivers/sound/wavfront.c linux-2.4.32.more-gcc4-fixes-v1/drivers/sound/wavfront.c
+--- linux-2.4.32/drivers/sound/wavfront.c 2001-10-11 13:34:42.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/sound/wavfront.c 2005-11-17 13:31:16.000000000 +0100
+@@ -2484,11 +2484,11 @@ static int __init detect_wavefront (int
+ #include <linux/fs.h>
+ #include <linux/mm.h>
+ #include <linux/slab.h>
+-#include <linux/unistd.h>
++static int my_errno;
++#define errno my_errno
++#include <asm/unistd.h>
+ #include <asm/uaccess.h>
+
+-static int errno;
+-
+ static int
+ wavefront_download_firmware (char *path)
+
+diff -rupN linux-2.4.32/drivers/usb/audio.c linux-2.4.32.more-gcc4-fixes-v1/drivers/usb/audio.c
+--- linux-2.4.32/drivers/usb/audio.c 2004-11-17 18:36:42.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/drivers/usb/audio.c 2005-11-17 13:31:16.000000000 +0100
+@@ -462,6 +462,7 @@ struct usb_audio_state {
+
+ /* prevent picking up a bogus abs macro */
+ #undef abs
++#define abs my_abs
+ static inline int abs(int x)
+ {
+ if (x < 0)
+diff -rupN linux-2.4.32/fs/intermezzo/presto.c linux-2.4.32.more-gcc4-fixes-v1/fs/intermezzo/presto.c
+--- linux-2.4.32/fs/intermezzo/presto.c 2002-11-30 17:12:28.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/fs/intermezzo/presto.c 2005-11-17 13:31:16.000000000 +0100
+@@ -344,8 +344,8 @@ int izo_mark_cache(struct dentry *dentry
+ return -EBADF;
+ }
+
+- ((int)cache->cache_flags) &= and_flag;
+- ((int)cache->cache_flags) |= or_flag;
++ cache->cache_flags &= and_flag;
++ cache->cache_flags |= or_flag;
+ if (res)
+ *res = (int)cache->cache_flags;
+
+@@ -383,8 +383,8 @@ int izo_mark_fset(struct dentry *dentry,
+ make_bad_inode(dentry->d_inode);
+ return -EBADF;
+ }
+- ((int)fset->fset_flags) &= and_flag;
+- ((int)fset->fset_flags) |= or_flag;
++ fset->fset_flags &= and_flag;
++ fset->fset_flags |= or_flag;
+ if (res)
+ *res = (int)fset->fset_flags;
+
+diff -rupN linux-2.4.32/include/asm-ppc/spinlock.h linux-2.4.32.more-gcc4-fixes-v1/include/asm-ppc/spinlock.h
+--- linux-2.4.32/include/asm-ppc/spinlock.h 2003-06-14 13:30:28.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/include/asm-ppc/spinlock.h 2005-11-17 13:31:16.000000000 +0100
+@@ -40,7 +40,6 @@ typedef struct {
+ extern void _spin_lock(spinlock_t *lock);
+ extern void _spin_unlock(spinlock_t *lock);
+ extern int spin_trylock(spinlock_t *lock);
+-extern unsigned long __spin_trylock(volatile unsigned long *lock);
+
+ #define spin_lock(lp) _spin_lock(lp)
+ #define spin_unlock(lp) _spin_unlock(lp)
+diff -rupN linux-2.4.32/include/linux/fsfilter.h linux-2.4.32.more-gcc4-fixes-v1/include/linux/fsfilter.h
+--- linux-2.4.32/include/linux/fsfilter.h 2004-11-17 18:36:42.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/include/linux/fsfilter.h 2005-11-17 13:31:16.000000000 +0100
+@@ -70,7 +70,6 @@ struct filter_fs {
+ #define FILTER_FS_XFS 3
+ #define FILTER_FS_OBDFS 4
+ #define FILTER_FS_TMPFS 5
+-extern struct filter_fs filter_oppar[FILTER_FS_TYPES];
+
+ struct filter_fs *filter_get_filter_fs(const char *cache_type);
+ void filter_setup_journal_ops(struct filter_fs *ops, char *cache_type);
+diff -rupN linux-2.4.32/include/linux/generic_serial.h linux-2.4.32.more-gcc4-fixes-v1/include/linux/generic_serial.h
+--- linux-2.4.32/include/linux/generic_serial.h 2002-02-26 13:26:58.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/include/linux/generic_serial.h 2005-11-17 13:31:16.000000000 +0100
+@@ -98,6 +98,4 @@ int gs_setserial(struct gs_port *port,
+ int gs_getserial(struct gs_port *port, struct serial_struct *sp);
+ void gs_got_break(struct gs_port *port);
+
+-extern int gs_debug;
+-
+ #endif
+diff -rupN linux-2.4.32/include/linux/i2c.h linux-2.4.32.more-gcc4-fixes-v1/include/linux/i2c.h
+--- linux-2.4.32/include/linux/i2c.h 2005-06-01 18:02:21.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/include/linux/i2c.h 2005-11-17 13:31:16.000000000 +0100
+@@ -70,7 +70,7 @@ extern int i2c_master_recv(struct i2c_cl
+
+ /* Transfer num messages.
+ */
+-extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],int num);
++extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msg,int num);
+
+ /*
+ * Some adapter types (i.e. PCF 8584 based ones) may support slave behaviuor.
+@@ -197,7 +197,7 @@ struct i2c_algorithm {
+ to NULL. If an adapter algorithm can do SMBus access, set
+ smbus_xfer. If set to NULL, the SMBus protocol is simulated
+ using common I2C messages */
+- int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg msgs[],
++ int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs,
+ int num);
+ int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+diff -rupN linux-2.4.32/include/linux/intermezzo_fs.h linux-2.4.32.more-gcc4-fixes-v1/include/linux/intermezzo_fs.h
+--- linux-2.4.32/include/linux/intermezzo_fs.h 2005-01-19 18:00:53.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/include/linux/intermezzo_fs.h 2005-11-17 13:31:16.000000000 +0100
+@@ -321,7 +321,6 @@ int presto_fwrite(struct file *file, con
+ int presto_ispresto(struct inode *);
+
+ /* super.c */
+-extern struct file_system_type presto_fs_type;
+ extern int init_intermezzo_fs(void);
+
+ /* fileset.c */
+diff -rupN linux-2.4.32/include/linux/nbd.h linux-2.4.32.more-gcc4-fixes-v1/include/linux/nbd.h
+--- linux-2.4.32/include/linux/nbd.h 2002-08-07 00:52:26.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/include/linux/nbd.h 2005-11-17 13:31:16.000000000 +0100
+@@ -29,34 +29,6 @@
+
+ #include <linux/blk.h>
+
+-#ifdef PARANOIA
+-extern int requests_in;
+-extern int requests_out;
+-#endif
+-
+-static void
+-nbd_end_request(struct request *req)
+-{
+- struct buffer_head *bh;
+- unsigned nsect;
+- unsigned long flags;
+- int uptodate = (req->errors == 0) ? 1 : 0;
+-
+-#ifdef PARANOIA
+- requests_out++;
+-#endif
+- spin_lock_irqsave(&io_request_lock, flags);
+- while((bh = req->bh) != NULL) {
+- nsect = bh->b_size >> 9;
+- blk_finished_io(nsect);
+- req->bh = bh->b_reqnext;
+- bh->b_reqnext = NULL;
+- bh->b_end_io(bh, uptodate);
+- }
+- blkdev_release_request(req);
+- spin_unlock_irqrestore(&io_request_lock, flags);
+-}
+-
+ #define MAX_NBD 128
+
+ struct nbd_device {
+diff -rupN linux-2.4.32/include/net/irda/irlan_event.h linux-2.4.32.more-gcc4-fixes-v1/include/net/irda/irlan_event.h
+--- linux-2.4.32/include/net/irda/irlan_event.h 1999-03-09 11:36:02.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/include/net/irda/irlan_event.h 2005-11-17 13:31:16.000000000 +0100
+@@ -67,8 +67,6 @@ typedef enum {
+ IRLAN_WATCHDOG_TIMEOUT,
+ } IRLAN_EVENT;
+
+-extern char *irlan_state[];
+-
+ void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event,
+ struct sk_buff *skb);
+
+diff -rupN linux-2.4.32/include/net/irda/irttp.h linux-2.4.32.more-gcc4-fixes-v1/include/net/irda/irttp.h
+--- linux-2.4.32/include/net/irda/irttp.h 2003-06-14 13:30:29.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/include/net/irda/irttp.h 2005-11-17 13:31:16.000000000 +0100
+@@ -209,6 +209,4 @@ static inline int irttp_is_primary(struc
+ return(irlap_is_primary(self->lsap->lap->irlap));
+ }
+
+-extern struct irttp_cb *irttp;
+-
+ #endif /* IRTTP_H */
+diff -rupN linux-2.4.32/include/net/irda/qos.h linux-2.4.32.more-gcc4-fixes-v1/include/net/irda/qos.h
+--- linux-2.4.32/include/net/irda/qos.h 2001-07-21 11:47:34.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/include/net/irda/qos.h 2005-11-17 13:31:16.000000000 +0100
+@@ -83,7 +83,6 @@ struct qos_info {
+ extern int sysctl_max_baud_rate;
+ extern int sysctl_max_inactive_time;
+
+-extern __u32 baud_rates[];
+ extern __u32 data_sizes[];
+ extern __u32 min_turn_times[];
+ extern __u32 add_bofs[];
+diff -rupN linux-2.4.32/include/net/udp.h linux-2.4.32.more-gcc4-fixes-v1/include/net/udp.h
+--- linux-2.4.32/include/net/udp.h 2005-01-19 18:00:53.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/include/net/udp.h 2005-11-17 13:31:16.000000000 +0100
+@@ -25,6 +25,7 @@
+ #include <linux/udp.h>
+ #include <linux/poll.h>
+ #include <net/sock.h>
++#include <net/snmp.h>
+
+ #define UDP_HTABLE_SIZE 128
+
+diff -rupN linux-2.4.32/net/ipv6/ip6_fib.c linux-2.4.32.more-gcc4-fixes-v1/net/ipv6/ip6_fib.c
+--- linux-2.4.32/net/ipv6/ip6_fib.c 2005-11-17 13:27:30.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/net/ipv6/ip6_fib.c 2005-11-17 13:31:16.000000000 +0100
+@@ -95,7 +95,7 @@ static __u32 rt_sernum = 0;
+
+ static struct timer_list ip6_fib_timer = { function: fib6_run_gc };
+
+-static struct fib6_walker_t fib6_walker_list = {
++struct fib6_walker_t fib6_walker_list = {
+ &fib6_walker_list, &fib6_walker_list,
+ };
+
+diff -rupN linux-2.4.32/net/ipv6/sysctl_net_ipv6.c linux-2.4.32.more-gcc4-fixes-v1/net/ipv6/sysctl_net_ipv6.c
+--- linux-2.4.32/net/ipv6/sysctl_net_ipv6.c 2004-04-14 20:22:21.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/net/ipv6/sysctl_net_ipv6.c 2005-11-17 13:31:16.000000000 +0100
+@@ -31,17 +31,14 @@ ctl_table ipv6_table[] = {
+
+ #ifdef MODULE
+ static struct ctl_table_header *ipv6_sysctl_header;
+-static struct ctl_table ipv6_root_table[];
+-static struct ctl_table ipv6_net_table[];
+
+-
+-ctl_table ipv6_root_table[] = {
+- {CTL_NET, "net", NULL, 0, 0555, ipv6_net_table},
++static ctl_table ipv6_net_table[] = {
++ {NET_IPV6, "ipv6", NULL, 0, 0555, ipv6_table},
+ {0}
+ };
+
+-ctl_table ipv6_net_table[] = {
+- {NET_IPV6, "ipv6", NULL, 0, 0555, ipv6_table},
++static ctl_table ipv6_root_table[] = {
++ {CTL_NET, "net", NULL, 0, 0555, ipv6_net_table},
+ {0}
+ };
+
+diff -rupN linux-2.4.32/net/irda/qos.c linux-2.4.32.more-gcc4-fixes-v1/net/irda/qos.c
+--- linux-2.4.32/net/irda/qos.c 2003-11-29 00:28:15.000000000 +0100
++++ linux-2.4.32.more-gcc4-fixes-v1/net/irda/qos.c 2005-11-17 13:31:16.000000000 +0100
+@@ -97,7 +97,7 @@ static int irlap_param_min_turn_time(voi
+ int get);
+
+ __u32 min_turn_times[] = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */
+-__u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000,
++static __u32 baud_rates[] = { 2400, 9600, 19200, 38400, 57600, 115200, 576000,
+ 1152000, 4000000, 16000000 }; /* bps */
+ __u32 data_sizes[] = { 64, 128, 256, 512, 1024, 2048 }; /* bytes */
+ __u32 add_bofs[] = { 48, 24, 12, 5, 3, 2, 1, 0 }; /* bytes */
+diff -rupN linux-2.4.32/net/khttpd/prototypes.h linux-2.4.32.more-gcc4-fixes-v1/net/khttpd/prototypes.h
+--- linux-2.4.32/net/khttpd/prototypes.h 2001-08-16 23:47:03.000000000 +0200
++++ linux-2.4.32.more-gcc4-fixes-v1/net/khttpd/prototypes.h 2005-11-17 13:31:16.000000000 +0100
+@@ -49,7 +49,6 @@ extern int sysctl_khttpd_stop;
+ extern struct khttpd_threadinfo threadinfo[CONFIG_KHTTPD_NUMCPU];
+ extern char CurrentTime[];
+ extern atomic_t ConnectCount;
+-extern struct wait_queue main_wait[CONFIG_KHTTPD_NUMCPU];
+
+ /* misc.c */
+
diff --git a/target/linux/generic-2.4/patches/008-intel_flashchip_fix.patch b/target/linux/generic-2.4/patches/008-intel_flashchip_fix.patch
new file mode 100644
index 0000000..b2397f6
--- /dev/null
+++ b/target/linux/generic-2.4/patches/008-intel_flashchip_fix.patch
@@ -0,0 +1,101 @@
+diff -urN linux.old/drivers/mtd/chips/cfi_cmdset_0001.c linux.dev/drivers/mtd/chips/cfi_cmdset_0001.c
+--- linux.old/drivers/mtd/chips/cfi_cmdset_0001.c 2004-11-17 12:54:21.000000000 +0100
++++ linux.dev/drivers/mtd/chips/cfi_cmdset_0001.c 2006-03-16 17:25:04.000000000 +0100
+@@ -28,10 +28,18 @@
+ #include <linux/slab.h>
+ #include <linux/delay.h>
+ #include <linux/interrupt.h>
++#include <linux/notifier.h>
++#include <linux/reboot.h>
+ #include <linux/mtd/map.h>
+ #include <linux/mtd/cfi.h>
+ #include <linux/mtd/compatmac.h>
+
++#ifndef container_of
++#define container_of(ptr, type, member) ({ \
++ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
++ (type *)( (char *)__mptr - offsetof(type,member) );})
++#endif
++
+ // debugging, turns off buffer write mode #define FORCE_WORD_WRITE
+
+ static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+@@ -45,6 +53,7 @@
+ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
+ static int cfi_intelext_suspend (struct mtd_info *);
+ static void cfi_intelext_resume (struct mtd_info *);
++static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val, void *v);
+
+ static void cfi_intelext_destroy(struct mtd_info *);
+
+@@ -288,6 +297,9 @@
+ map->fldrv = &cfi_intelext_chipdrv;
+ MOD_INC_USE_COUNT;
+ mtd->name = map->name;
++ mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
++ register_reboot_notifier(&mtd->reboot_notifier);
++
+ return mtd;
+
+ setup_err:
+@@ -1960,10 +1972,40 @@
+ }
+ }
+
++
++static void cfi_intelext_reset(struct mtd_info *mtd)
++{
++ struct map_info *map = mtd->priv;
++ struct cfi_private *cfi = map->fldrv_priv;
++ int i;
++ struct flchip *chip;
++
++ cfi_intelext_sync(mtd);
++ for (i=0; i<cfi->numchips; i++) {
++ chip = &cfi->chips[i];
++
++ spin_lock(chip->mutex);
++ cfi_write(map, CMD(0xFF), 0);
++ chip->state = FL_READY;
++ spin_unlock(chip->mutex);
++ }
++}
++
++static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val, void *v)
++{
++ struct mtd_info *mtd;
++
++ mtd = container_of(nb, struct mtd_info, reboot_notifier);
++ cfi_intelext_reset(mtd);
++ return NOTIFY_DONE;
++}
++
+ static void cfi_intelext_destroy(struct mtd_info *mtd)
+ {
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
++ cfi_intelext_reset(mtd);
++ unregister_reboot_notifier(&mtd->reboot_notifier);
+ kfree(cfi->cmdset_priv);
+ kfree(cfi->cfiq);
+ kfree(cfi);
+diff -urN linux.old/include/linux/mtd/mtd.h linux.dev/include/linux/mtd/mtd.h
+--- linux.old/include/linux/mtd/mtd.h 2003-08-25 13:44:44.000000000 +0200
++++ linux.dev/include/linux/mtd/mtd.h 2006-03-16 17:00:10.000000000 +0100
+@@ -10,6 +10,7 @@
+ #include <linux/version.h>
+ #include <linux/types.h>
+ #include <linux/mtd/compatmac.h>
++#include <linux/notifier.h>
+ #include <linux/module.h>
+ #include <linux/uio.h>
+
+@@ -217,6 +218,8 @@
+ int (*suspend) (struct mtd_info *mtd);
+ void (*resume) (struct mtd_info *mtd);
+
++ struct notifier_block reboot_notifier;
++
+ void *priv;
+ };
+
diff --git a/target/linux/generic-2.4/patches/009-calibrate_section.patch b/target/linux/generic-2.4/patches/009-calibrate_section.patch
new file mode 100644
index 0000000..aedf6fd
--- /dev/null
+++ b/target/linux/generic-2.4/patches/009-calibrate_section.patch
@@ -0,0 +1,11 @@
+--- linux.old/init/main.c 2006-09-02 20:59:53.000000000 +0200
++++ linux.dev/init/main.c 2006-09-02 21:00:01.000000000 +0200
+@@ -167,7 +167,7 @@
+ better than 1% */
+ #define LPS_PREC 8
+
+-void __init calibrate_delay(void)
++void calibrate_delay(void)
+ {
+ unsigned long ticks, loopbit;
+ int lps_precision = LPS_PREC;
diff --git a/target/linux/generic-2.4/patches/010-disable_old_squashfs_compatibility.patch b/target/linux/generic-2.4/patches/010-disable_old_squashfs_compatibility.patch
new file mode 100644
index 0000000..8647652
--- /dev/null
+++ b/target/linux/generic-2.4/patches/010-disable_old_squashfs_compatibility.patch
@@ -0,0 +1,25 @@
+diff -Nur linux-2.4.32/fs/squashfs/Makefile linux-2.4.32-owrt/fs/squashfs/Makefile
+--- linux-2.4.32/fs/squashfs/Makefile 2006-03-21 13:47:50.000000000 +0100
++++ linux-2.4.32-owrt/fs/squashfs/Makefile 2006-03-21 13:48:49.000000000 +0100
+@@ -4,7 +4,7 @@
+
+ O_TARGET := squashfs.o
+
+-obj-y := inode.o squashfs2_0.o LzmaDecode.o
++obj-y := inode.o LzmaDecode.o
+
+ obj-m := $(O_TARGET)
+
+diff -Nur linux-2.4.32/fs/squashfs/squashfs.h linux-2.4.32-owrt/fs/squashfs/squashfs.h
+--- linux-2.4.32/fs/squashfs/squashfs.h 2006-03-21 13:06:10.000000000 +0100
++++ linux-2.4.32-owrt/fs/squashfs/squashfs.h 2006-03-21 13:48:36.000000000 +0100
+@@ -24,6 +24,9 @@
+ #ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+ #undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+ #endif
++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++#undef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++#endif
+ #ifdef SQUASHFS_TRACE
+ #define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args)
+ #else
diff --git a/target/linux/generic-2.4/patches/050-build_flags.patch b/target/linux/generic-2.4/patches/050-build_flags.patch
new file mode 100644
index 0000000..14a207d
--- /dev/null
+++ b/target/linux/generic-2.4/patches/050-build_flags.patch
@@ -0,0 +1,83 @@
+diff -ur linux-2.4.32/arch/mips/Makefile linux-2.4.32-openwrt/arch/mips/Makefile
+--- linux-2.4.32/arch/mips/Makefile 2005-12-15 13:53:59.000000000 +0100
++++ linux-2.4.32-openwrt/arch/mips/Makefile 2005-12-15 14:02:33.000000000 +0100
+@@ -44,10 +44,10 @@
+ GCCFLAGS := -I $(TOPDIR)/include/asm/gcc
+ GCCFLAGS += -G 0 -mno-abicalls -fno-pic -pipe
+ GCCFLAGS += $(call check_gcc, -finline-limit=100000,)
+-LINKFLAGS += -G 0 -static -n
+-MODFLAGS += -mlong-calls
++LINKFLAGS += -G 0 -static -n -nostdlib
++MODFLAGS += -mlong-calls -fno-common
+
+-ifdef CONFIG_DEBUG_INFO
++ifdef CONFIG_REMOTE_DEBUG
+ GCCFLAGS += -g
+ ifdef CONFIG_SB1XXX_CORELIS
+ GCCFLAGS += -mno-sched-prolog -fno-omit-frame-pointer
+@@ -69,13 +69,13 @@
+ set_gccflags = $(shell \
+ while :; do \
+ cpu=$(1); isa=-$(2); \
+- for gcc_opt in -march= -mcpu=; do \
++ for gcc_opt in -march= -mtune=; do \
+ $(CC) $$gcc_opt$$cpu $$isa -S -o /dev/null \
+ -xc /dev/null > /dev/null 2>&1 && \
+ break 2; \
+ done; \
+ cpu=$(3); isa=-$(4); \
+- for gcc_opt in -march= -mcpu=; do \
++ for gcc_opt in -march= -mtune=; do \
+ $(CC) $$gcc_opt$$cpu $$isa -S -o /dev/null \
+ -xc /dev/null > /dev/null 2>&1 && \
+ break 2; \
+@@ -90,7 +90,7 @@
+ fi; \
+ gas_abi=-Wa,-32; gas_cpu=$$cpu; gas_isa=-Wa,$$isa; \
+ while :; do \
+- for gas_opt in -Wa,-march= -Wa,-mcpu=; do \
++ for gas_opt in -Wa,-march= -Wa,-mtune=; do \
+ $(CC) $$gas_abi $$gas_opt$$cpu $$gas_isa -Wa,-Z -c \
+ -o /dev/null -xassembler /dev/null > /dev/null 2>&1 && \
+ break 2; \
+@@ -172,6 +172,7 @@
+ endif
+
+ AFLAGS += $(GCCFLAGS)
++ASFLAGS += $(GCCFLAGS)
+ CFLAGS += $(GCCFLAGS)
+
+ LD += -m $(ld-emul)
+diff -ur linux-2.4.32/Makefile linux-2.4.32-openwrt/Makefile
+--- linux-2.4.32/Makefile 2005-12-15 13:53:59.000000000 +0100
++++ linux-2.4.32-openwrt/Makefile 2005-12-15 13:59:30.000000000 +0100
+@@ -17,7 +17,7 @@
+ FINDHPATH = $(HPATH)/asm $(HPATH)/linux $(HPATH)/scsi $(HPATH)/net $(HPATH)/math-emu
+
+ HOSTCC = gcc
+-HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
++HOSTCFLAGS = -Wall -Wstrict-prototypes -Os -fomit-frame-pointer
+
+ CROSS_COMPILE =
+
+@@ -88,10 +88,9 @@
+ #
+ # standard CFLAGS
+ #
+-
+ CPPFLAGS := -D__KERNEL__ -I$(HPATH)
+
+-CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \
++CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -Os \
+ -fno-strict-aliasing -fno-common
+ CFLAGS += -fno-builtin-sprintf
+ ifndef CONFIG_FRAME_POINTER
+@@ -104,6 +103,8 @@
+ # disable pointer signedness warnings in gcc 4.0
+ CFLAGS += $(call check_gcc,-Wno-pointer-sign,)
+
++CFLAGS += $(call check_gcc, -funit-at-a-time,)
++
+ #
+ # ROOT_DEV specifies the default root-device when making the image.
+ # This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case
diff --git a/target/linux/generic-2.4/patches/051-remove_pcmcia_modinst_compat.patch b/target/linux/generic-2.4/patches/051-remove_pcmcia_modinst_compat.patch
new file mode 100644
index 0000000..091e4ba
--- /dev/null
+++ b/target/linux/generic-2.4/patches/051-remove_pcmcia_modinst_compat.patch
@@ -0,0 +1,21 @@
+--- linux.old/Makefile Tue Oct 10 22:24:41 2006
++++ linux.dev/Makefile Tue Oct 10 22:26:19 2006
+@@ -427,17 +427,8 @@
+ depmod_opts := -b $(INSTALL_MOD_PATH) -r
+ endif
+ .PHONY: _modinst_post
+-_modinst_post: _modinst_post_pcmcia
++_modinst_post:
+ if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
+-
+-# Backwards compatibilty symlinks for people still using old versions
+-# of pcmcia-cs with hard coded pathnames on insmod. Remove
+-# _modinst_post_pcmcia for kernel 2.4.1.
+-.PHONY: _modinst_post_pcmcia
+-_modinst_post_pcmcia:
+- cd $(MODLIB); \
+- mkdir -p pcmcia; \
+- find kernel -path '*/pcmcia/*' -name '*.o' | xargs -i -r ln -sf ../{} pcmcia
+
+ .PHONY: $(patsubst %, _modinst_%, $(SUBDIRS))
+ $(patsubst %, _modinst_%, $(SUBDIRS)) :
diff --git a/target/linux/generic-2.4/patches/100-wireless-extension.patch b/target/linux/generic-2.4/patches/100-wireless-extension.patch
new file mode 100644
index 0000000..88e9183
--- /dev/null
+++ b/target/linux/generic-2.4/patches/100-wireless-extension.patch
@@ -0,0 +1,1121 @@
+diff -Nur linux-2.4.32/include/linux/netdevice.h linux-2.4.32-we/include/linux/netdevice.h
+--- linux-2.4.32/include/linux/netdevice.h 2004-11-17 12:54:22.000000000 +0100
++++ linux-2.4.32-we/include/linux/netdevice.h 2006-03-13 12:10:57.000000000 +0100
+@@ -295,7 +295,9 @@
+
+ /* List of functions to handle Wireless Extensions (instead of ioctl).
+ * See <net/iw_handler.h> for details. Jean II */
+- struct iw_handler_def * wireless_handlers;
++ const struct iw_handler_def * wireless_handlers;
++ /* Instance data managed by the core of Wireless Extensions. */
++ struct iw_public_data * wireless_data;
+
+ struct ethtool_ops *ethtool_ops;
+
+diff -Nur linux-2.4.32/include/linux/wireless.h linux-2.4.32-we/include/linux/wireless.h
+--- linux-2.4.32/include/linux/wireless.h 2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.32-we/include/linux/wireless.h 2006-03-13 12:11:02.000000000 +0100
+@@ -1,10 +1,10 @@
+ /*
+ * This file define a set of standard wireless extensions
+ *
+- * Version : 16 2.4.03
++ * Version : 18 12.3.05
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved.
+ */
+
+ #ifndef _LINUX_WIRELESS_H
+@@ -47,12 +47,12 @@
+ * # include/net/iw_handler.h
+ *
+ * Note as well that /proc/net/wireless implementation has now moved in :
+- * # include/linux/wireless.c
++ * # net/core/wireless.c
+ *
+ * Wireless Events (2002 -> onward) :
+ * --------------------------------
+ * Events are defined at the end of this file, and implemented in :
+- * # include/linux/wireless.c
++ * # net/core/wireless.c
+ *
+ * Other comments :
+ * --------------
+@@ -82,7 +82,7 @@
+ * (there is some stuff that will be added in the future...)
+ * I just plan to increment with each new version.
+ */
+-#define WIRELESS_EXT 16
++#define WIRELESS_EXT 18
+
+ /*
+ * Changes :
+@@ -175,6 +175,28 @@
+ * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support
+ * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
+ * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index
++ *
++ * V16 to V17
++ * ----------
++ * - Add flags to frequency -> auto/fixed
++ * - Document (struct iw_quality *)->updated, add new flags (INVALID)
++ * - Wireless Event capability in struct iw_range
++ * - Add support for relative TxPower (yick !)
++ *
++ * V17 to V18 (From Jouni Malinen <jkmaline@cc.hut.fi>)
++ * ----------
++ * - Add support for WPA/WPA2
++ * - Add extended encoding configuration (SIOCSIWENCODEEXT and
++ * SIOCGIWENCODEEXT)
++ * - Add SIOCSIWGENIE/SIOCGIWGENIE
++ * - Add SIOCSIWMLME
++ * - Add SIOCSIWPMKSA
++ * - Add struct iw_range bit field for supported encoding capabilities
++ * - Add optional scan request parameters for SIOCSIWSCAN
++ * - Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA
++ * related parameters (extensible up to 4096 parameter values)
++ * - Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE,
++ * IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND
+ */
+
+ /**************************** CONSTANTS ****************************/
+@@ -249,9 +271,33 @@
+ #define SIOCSIWPOWER 0x8B2C /* set Power Management settings */
+ #define SIOCGIWPOWER 0x8B2D /* get Power Management settings */
+
++/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM).
++ * This ioctl uses struct iw_point and data buffer that includes IE id and len
++ * fields. More than one IE may be included in the request. Setting the generic
++ * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers
++ * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers
++ * are required to report the used IE as a wireless event, e.g., when
++ * associating with an AP. */
++#define SIOCSIWGENIE 0x8B30 /* set generic IE */
++#define SIOCGIWGENIE 0x8B31 /* get generic IE */
++
++/* WPA : IEEE 802.11 MLME requests */
++#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses
++ * struct iw_mlme */
++/* WPA : Authentication mode parameters */
++#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */
++#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */
++
++/* WPA : Extended version of encoding configuration */
++#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */
++#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */
++
++/* WPA2 : PMKSA cache management */
++#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */
++
+ /* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
+
+-/* These 16 ioctl are wireless device private.
++/* These 32 ioctl are wireless device private, for 16 commands.
+ * Each driver is free to use them for whatever purpose it chooses,
+ * however the driver *must* export the description of those ioctls
+ * with SIOCGIWPRIV and *must* use arguments as defined below.
+@@ -266,8 +312,8 @@
+ * We now have 32 commands, so a bit more space ;-).
+ * Also, all 'odd' commands are only usable by root and don't return the
+ * content of ifr/iwr to user (but you are not obliged to use the set/get
+- * convention, just use every other two command).
+- * And I repeat : you are not obliged to use them with iwspy, but you
++ * convention, just use every other two command). More details in iwpriv.c.
++ * And I repeat : you are not forced to use them with iwpriv, but you
+ * must be compliant with it.
+ */
+
+@@ -290,6 +336,34 @@
+ #define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */
+ #define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */
+ #define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */
++#define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..)
++ * (scan results); This includes id and
++ * length fields. One IWEVGENIE may
++ * contain more than one IE. Scan
++ * results may contain one or more
++ * IWEVGENIE events. */
++#define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure
++ * (struct iw_michaelmicfailure)
++ */
++#define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request.
++ * The data includes id and length
++ * fields and may contain more than one
++ * IE. This event is required in
++ * Managed mode if the driver
++ * generates its own WPA/RSN IE. This
++ * should be sent just before
++ * IWEVREGISTERED event for the
++ * association. */
++#define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association
++ * Response. The data includes id and
++ * length fields and may contain more
++ * than one IE. This may be sent
++ * between IWEVASSOCREQIE and
++ * IWEVREGISTERED events for the
++ * association. */
++#define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN
++ * pre-authentication
++ * (struct iw_pmkid_cand) */
+
+ #define IWEVFIRST 0x8C00
+
+@@ -352,6 +426,18 @@
+ #define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */
+ #define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */
+
++/* Statistics flags (bitmask in updated) */
++#define IW_QUAL_QUAL_UPDATED 0x1 /* Value was updated since last read */
++#define IW_QUAL_LEVEL_UPDATED 0x2
++#define IW_QUAL_NOISE_UPDATED 0x4
++#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */
++#define IW_QUAL_LEVEL_INVALID 0x20
++#define IW_QUAL_NOISE_INVALID 0x40
++
++/* Frequency flags */
++#define IW_FREQ_AUTO 0x00 /* Let the driver decides */
++#define IW_FREQ_FIXED 0x01 /* Force a specific value */
++
+ /* Maximum number of size of encoding token available
+ * they are listed in the range structure */
+ #define IW_MAX_ENCODING_SIZES 8
+@@ -390,6 +476,7 @@
+ #define IW_TXPOW_TYPE 0x00FF /* Type of value */
+ #define IW_TXPOW_DBM 0x0000 /* Value is in dBm */
+ #define IW_TXPOW_MWATT 0x0001 /* Value is in mW */
++#define IW_TXPOW_RELATIVE 0x0002 /* Value is in arbitrary units */
+ #define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */
+
+ /* Retry limits and lifetime flags available */
+@@ -412,12 +499,113 @@
+ #define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */
+ #define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */
+ #define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */
++/* struct iw_scan_req scan_type */
++#define IW_SCAN_TYPE_ACTIVE 0
++#define IW_SCAN_TYPE_PASSIVE 1
+ /* Maximum size of returned data */
+ #define IW_SCAN_MAX_DATA 4096 /* In bytes */
+
+ /* Max number of char in custom event - use multiple of them if needed */
+ #define IW_CUSTOM_MAX 256 /* In bytes */
+
++/* Generic information element */
++#define IW_GENERIC_IE_MAX 1024
++
++/* MLME requests (SIOCSIWMLME / struct iw_mlme) */
++#define IW_MLME_DEAUTH 0
++#define IW_MLME_DISASSOC 1
++
++/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */
++#define IW_AUTH_INDEX 0x0FFF
++#define IW_AUTH_FLAGS 0xF000
++/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095)
++ * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the
++ * parameter that is being set/get to; value will be read/written to
++ * struct iw_param value field) */
++#define IW_AUTH_WPA_VERSION 0
++#define IW_AUTH_CIPHER_PAIRWISE 1
++#define IW_AUTH_CIPHER_GROUP 2
++#define IW_AUTH_KEY_MGMT 3
++#define IW_AUTH_TKIP_COUNTERMEASURES 4
++#define IW_AUTH_DROP_UNENCRYPTED 5
++#define IW_AUTH_80211_AUTH_ALG 6
++#define IW_AUTH_WPA_ENABLED 7
++#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8
++#define IW_AUTH_ROAMING_CONTROL 9
++#define IW_AUTH_PRIVACY_INVOKED 10
++
++/* IW_AUTH_WPA_VERSION values (bit field) */
++#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001
++#define IW_AUTH_WPA_VERSION_WPA 0x00000002
++#define IW_AUTH_WPA_VERSION_WPA2 0x00000004
++
++/* IW_AUTH_PAIRWISE_CIPHER and IW_AUTH_GROUP_CIPHER values (bit field) */
++#define IW_AUTH_CIPHER_NONE 0x00000001
++#define IW_AUTH_CIPHER_WEP40 0x00000002
++#define IW_AUTH_CIPHER_TKIP 0x00000004
++#define IW_AUTH_CIPHER_CCMP 0x00000008
++#define IW_AUTH_CIPHER_WEP104 0x00000010
++
++/* IW_AUTH_KEY_MGMT values (bit field) */
++#define IW_AUTH_KEY_MGMT_802_1X 1
++#define IW_AUTH_KEY_MGMT_PSK 2
++
++/* IW_AUTH_80211_AUTH_ALG values (bit field) */
++#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001
++#define IW_AUTH_ALG_SHARED_KEY 0x00000002
++#define IW_AUTH_ALG_LEAP 0x00000004
++
++/* IW_AUTH_ROAMING_CONTROL values */
++#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */
++#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming
++ * control */
++
++/* SIOCSIWENCODEEXT definitions */
++#define IW_ENCODE_SEQ_MAX_SIZE 8
++/* struct iw_encode_ext ->alg */
++#define IW_ENCODE_ALG_NONE 0
++#define IW_ENCODE_ALG_WEP 1
++#define IW_ENCODE_ALG_TKIP 2
++#define IW_ENCODE_ALG_CCMP 3
++/* struct iw_encode_ext ->ext_flags */
++#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001
++#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002
++#define IW_ENCODE_EXT_GROUP_KEY 0x00000004
++#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008
++
++/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */
++#define IW_MICFAILURE_KEY_ID 0x00000003 /* Key ID 0..3 */
++#define IW_MICFAILURE_GROUP 0x00000004
++#define IW_MICFAILURE_PAIRWISE 0x00000008
++#define IW_MICFAILURE_STAKEY 0x00000010
++#define IW_MICFAILURE_COUNT 0x00000060 /* 1 or 2 (0 = count not supported)
++ */
++
++/* Bit field values for enc_capa in struct iw_range */
++#define IW_ENC_CAPA_WPA 0x00000001
++#define IW_ENC_CAPA_WPA2 0x00000002
++#define IW_ENC_CAPA_CIPHER_TKIP 0x00000004
++#define IW_ENC_CAPA_CIPHER_CCMP 0x00000008
++
++/* Event capability macros - in (struct iw_range *)->event_capa
++ * Because we have more than 32 possible events, we use an array of
++ * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */
++#define IW_EVENT_CAPA_BASE(cmd) ((cmd >= SIOCIWFIRSTPRIV) ? \
++ (cmd - SIOCIWFIRSTPRIV + 0x60) : \
++ (cmd - SIOCSIWCOMMIT))
++#define IW_EVENT_CAPA_INDEX(cmd) (IW_EVENT_CAPA_BASE(cmd) >> 5)
++#define IW_EVENT_CAPA_MASK(cmd) (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F))
++/* Event capability constants - event autogenerated by the kernel
++ * This list is valid for most 802.11 devices, customise as needed... */
++#define IW_EVENT_CAPA_K_0 (IW_EVENT_CAPA_MASK(0x8B04) | \
++ IW_EVENT_CAPA_MASK(0x8B06) | \
++ IW_EVENT_CAPA_MASK(0x8B1A))
++#define IW_EVENT_CAPA_K_1 (IW_EVENT_CAPA_MASK(0x8B2A))
++/* "Easy" macro to set events in iw_range (less efficient) */
++#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd))
++#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; }
++
++
+ /****************************** TYPES ******************************/
+
+ /* --------------------------- SUBTYPES --------------------------- */
+@@ -456,7 +644,7 @@
+ __s32 m; /* Mantissa */
+ __s16 e; /* Exponent */
+ __u8 i; /* List index (when in range struct) */
+- __u8 pad; /* Unused - just for alignement */
++ __u8 flags; /* Flags (fixed/auto) */
+ };
+
+ /*
+@@ -507,6 +695,132 @@
+ struct iw_quality high; /* High threshold */
+ };
+
++/*
++ * Optional data for scan request
++ *
++ * Note: these optional parameters are controlling parameters for the
++ * scanning behavior, these do not apply to getting scan results
++ * (SIOCGIWSCAN). Drivers are expected to keep a local BSS table and
++ * provide a merged results with all BSSes even if the previous scan
++ * request limited scanning to a subset, e.g., by specifying an SSID.
++ * Especially, scan results are required to include an entry for the
++ * current BSS if the driver is in Managed mode and associated with an AP.
++ */
++struct iw_scan_req
++{
++ __u8 scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */
++ __u8 essid_len;
++ __u8 num_channels; /* num entries in channel_list;
++ * 0 = scan all allowed channels */
++ __u8 flags; /* reserved as padding; use zero, this may
++ * be used in the future for adding flags
++ * to request different scan behavior */
++ struct sockaddr bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or
++ * individual address of a specific BSS */
++
++ /*
++ * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using
++ * the current ESSID. This allows scan requests for specific ESSID
++ * without having to change the current ESSID and potentially breaking
++ * the current association.
++ */
++ __u8 essid[IW_ESSID_MAX_SIZE];
++
++ /*
++ * Optional parameters for changing the default scanning behavior.
++ * These are based on the MLME-SCAN.request from IEEE Std 802.11.
++ * TU is 1.024 ms. If these are set to 0, driver is expected to use
++ * reasonable default values. min_channel_time defines the time that
++ * will be used to wait for the first reply on each channel. If no
++ * replies are received, next channel will be scanned after this. If
++ * replies are received, total time waited on the channel is defined by
++ * max_channel_time.
++ */
++ __u32 min_channel_time; /* in TU */
++ __u32 max_channel_time; /* in TU */
++
++ struct iw_freq channel_list[IW_MAX_FREQUENCIES];
++};
++
++/* ------------------------- WPA SUPPORT ------------------------- */
++
++/*
++ * Extended data structure for get/set encoding (this is used with
++ * SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_*
++ * flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and
++ * only the data contents changes (key data -> this structure, including
++ * key data).
++ *
++ * If the new key is the first group key, it will be set as the default
++ * TX key. Otherwise, default TX key index is only changed if
++ * IW_ENCODE_EXT_SET_TX_KEY flag is set.
++ *
++ * Key will be changed with SIOCSIWENCODEEXT in all cases except for
++ * special "change TX key index" operation which is indicated by setting
++ * key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY.
++ *
++ * tx_seq/rx_seq are only used when respective
++ * IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal
++ * TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start
++ * TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally
++ * used only by an Authenticator (AP or an IBSS station) to get the
++ * current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and
++ * RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for
++ * debugging/testing.
++ */
++struct iw_encode_ext
++{
++ __u32 ext_flags; /* IW_ENCODE_EXT_* */
++ __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
++ __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
++ struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast
++ * (group) keys or unicast address for
++ * individual keys */
++ __u16 alg; /* IW_ENCODE_ALG_* */
++ __u16 key_len;
++ __u8 key[0];
++};
++
++/* SIOCSIWMLME data */
++struct iw_mlme
++{
++ __u16 cmd; /* IW_MLME_* */
++ __u16 reason_code;
++ struct sockaddr addr;
++};
++
++/* SIOCSIWPMKSA data */
++#define IW_PMKSA_ADD 1
++#define IW_PMKSA_REMOVE 2
++#define IW_PMKSA_FLUSH 3
++
++#define IW_PMKID_LEN 16
++
++struct iw_pmksa
++{
++ __u32 cmd; /* IW_PMKSA_* */
++ struct sockaddr bssid;
++ __u8 pmkid[IW_PMKID_LEN];
++};
++
++/* IWEVMICHAELMICFAILURE data */
++struct iw_michaelmicfailure
++{
++ __u32 flags;
++ struct sockaddr src_addr;
++ __u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
++};
++
++/* IWEVPMKIDCAND data */
++#define IW_PMKID_CAND_PREAUTH 0x00000001 /* RNS pre-authentication enabled */
++struct iw_pmkid_cand
++{
++ __u32 flags; /* IW_PMKID_CAND_* */
++ __u32 index; /* the smaller the index, the higher the
++ * priority */
++ struct sockaddr bssid;
++};
++
+ /* ------------------------ WIRELESS STATS ------------------------ */
+ /*
+ * Wireless statistics (used for /proc/net/wireless)
+@@ -610,11 +924,12 @@
+ /* Old Frequency (backward compat - moved lower ) */
+ __u16 old_num_channels;
+ __u8 old_num_frequency;
+- /* Filler to keep "version" at the same offset */
+- __s32 old_freq[6];
++
++ /* Wireless event capability bitmasks */
++ __u32 event_capa[6];
+
+ /* signal level threshold range */
+- __s32 sensitivity;
++ __s32 sensitivity;
+
+ /* Quality of link & SNR stuff */
+ /* Quality range (link, level, noise)
+@@ -685,6 +1000,8 @@
+ struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */
+ /* Note : this frequency list doesn't need to fit channel numbers,
+ * because each entry contain its channel index */
++
++ __u32 enc_capa; /* IW_ENC_CAPA_* bit field */
+ };
+
+ /*
+diff -Nur linux-2.4.32/include/net/iw_handler.h linux-2.4.32-we/include/net/iw_handler.h
+--- linux-2.4.32/include/net/iw_handler.h 2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.32-we/include/net/iw_handler.h 2006-03-13 12:10:57.000000000 +0100
+@@ -1,10 +1,10 @@
+ /*
+ * This file define the new driver API for Wireless Extensions
+ *
+- * Version : 5 4.12.02
++ * Version : 6 21.6.04
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 2001-2004 Jean Tourrilhes, All Rights Reserved.
+ */
+
+ #ifndef _IW_HANDLER_H
+@@ -206,7 +206,7 @@
+ * will be needed...
+ * I just plan to increment with each new version.
+ */
+-#define IW_HANDLER_VERSION 5
++#define IW_HANDLER_VERSION 6
+
+ /*
+ * Changes :
+@@ -224,11 +224,18 @@
+ * V4 to V5
+ * --------
+ * - Add new spy support : struct iw_spy_data & prototypes
++ *
++ * V5 to V6
++ * --------
++ * - Change the way we get to spy_data method for added safety
++ * - Remove spy #ifdef, they are always on -> cleaner code
++ * - Add IW_DESCR_FLAG_NOMAX flag for very large requests
++ * - Start migrating get_wireless_stats to struct iw_handler_def
+ */
+
+ /**************************** CONSTANTS ****************************/
+
+-/* Enable enhanced spy support. Disable to reduce footprint */
++/* Enhanced spy support available */
+ #define IW_WIRELESS_SPY
+ #define IW_WIRELESS_THRSPY
+
+@@ -258,6 +265,7 @@
+ #define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */
+ #define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */
+ /* SET : Omit payload from generated iwevent */
++#define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */
+ /* Driver level flags */
+ #define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */
+
+@@ -311,23 +319,25 @@
+ /* Array of handlers for standard ioctls
+ * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
+ */
+- iw_handler * standard;
++ const iw_handler * standard;
+
+ /* Array of handlers for private ioctls
+ * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
+ */
+- iw_handler * private;
++ const iw_handler * private;
+
+ /* Arguments of private handler. This one is just a list, so you
+ * can put it in any order you want and should not leave holes...
+ * We will automatically export that to user space... */
+- struct iw_priv_args * private_args;
++ const struct iw_priv_args * private_args;
+
+- /* Driver enhanced spy support */
+- long spy_offset; /* Spy data offset */
++ /* This field will be *removed* in the next version of WE */
++ long spy_offset; /* DO NOT USE */
+
+- /* In the long term, get_wireless_stats will move from
+- * 'struct net_device' to here, to minimise bloat. */
++ /* New location of get_wireless_stats, to de-bloat struct net_device.
++ * The old pointer in struct net_device will be gradually phased
++ * out, and drivers are encouraged to use this one... */
++ struct iw_statistics* (*get_wireless_stats)(struct net_device *dev);
+ };
+
+ /* ---------------------- IOCTL DESCRIPTION ---------------------- */
+@@ -374,18 +384,29 @@
+ */
+ struct iw_spy_data
+ {
+-#ifdef IW_WIRELESS_SPY
+ /* --- Standard spy support --- */
+ int spy_number;
+ u_char spy_address[IW_MAX_SPY][ETH_ALEN];
+ struct iw_quality spy_stat[IW_MAX_SPY];
+-#ifdef IW_WIRELESS_THRSPY
+ /* --- Enhanced spy support (event) */
+ struct iw_quality spy_thr_low; /* Low threshold */
+ struct iw_quality spy_thr_high; /* High threshold */
+ u_char spy_thr_under[IW_MAX_SPY];
+-#endif /* IW_WIRELESS_THRSPY */
+-#endif /* IW_WIRELESS_SPY */
++};
++
++/* --------------------- DEVICE WIRELESS DATA --------------------- */
++/*
++ * This is all the wireless data specific to a device instance that
++ * is managed by the core of Wireless Extensions.
++ * We only keep pointer to those structures, so that a driver is free
++ * to share them between instances.
++ * This structure should be initialised before registering the device.
++ * Access to this data follow the same rules as any other struct net_device
++ * data (i.e. valid as long as struct net_device exist, same locking rules).
++ */
++struct iw_public_data {
++ /* Driver enhanced spy support */
++ struct iw_spy_data * spy_data;
+ };
+
+ /**************************** PROTOTYPES ****************************/
+diff -Nur linux-2.4.32/net/core/dev.c linux-2.4.32-we/net/core/dev.c
+--- linux-2.4.32/net/core/dev.c 2005-04-04 03:42:20.000000000 +0200
++++ linux-2.4.32-we/net/core/dev.c 2006-03-13 12:10:57.000000000 +0100
+@@ -2426,7 +2426,7 @@
+ /* Follow me in net/core/wireless.c */
+ ret = wireless_process_ioctl(&ifr, cmd);
+ rtnl_unlock();
+- if (!ret && IW_IS_GET(cmd) &&
++ if (IW_IS_GET(cmd) &&
+ copy_to_user(arg, &ifr, sizeof(struct ifreq)))
+ return -EFAULT;
+ return ret;
+diff -Nur linux-2.4.32/net/core/wireless.c linux-2.4.32-we/net/core/wireless.c
+--- linux-2.4.32/net/core/wireless.c 2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.32-we/net/core/wireless.c 2006-03-13 12:11:02.000000000 +0100
+@@ -2,7 +2,7 @@
+ * This file implement the Wireless Extensions APIs.
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 1997-2003 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved.
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+@@ -48,6 +48,16 @@
+ * o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
+ * o Add enhanced spy support : iw_handler_set_thrspy() and event.
+ * o Add WIRELESS_EXT version display in /proc/net/wireless
++ *
++ * v6 - 18.06.04 - Jean II
++ * o Change get_spydata() method for added safety
++ * o Remove spy #ifdef, they are always on -> cleaner code
++ * o Allow any size GET request if user specifies length > max
++ * and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV
++ * o Start migrating get_wireless_stats to struct iw_handler_def
++ * o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
++ * Based on patch from Pavel Roskin <proski@gnu.org> :
++ * o Fix kernel data leak to user space in private handler handling
+ */
+
+ /***************************** INCLUDES *****************************/
+@@ -64,11 +74,7 @@
+
+ /**************************** CONSTANTS ****************************/
+
+-/* Enough lenience, let's make sure things are proper... */
+-#define WE_STRICT_WRITE /* Check write buffer size */
+-/* I'll probably drop both the define and kernel message in the next version */
+-
+-/* Debuging stuff */
++/* Debugging stuff */
+ #undef WE_IOCTL_DEBUG /* Debug IOCTL API */
+ #undef WE_EVENT_DEBUG /* Debug Event dispatcher */
+ #undef WE_SPY_DEBUG /* Debug enhanced spy support */
+@@ -131,14 +137,14 @@
+ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+ /* SIOCGIWAP */
+ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+- /* -- hole -- */
+- { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++ /* SIOCSIWMLME */
++ { IW_HEADER_TYPE_POINT, 0, 1, sizeof(struct iw_mlme), sizeof(struct iw_mlme), 0},
+ /* SIOCGIWAPLIST */
+- { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
++ { IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, IW_DESCR_FLAG_NOMAX},
+ /* SIOCSIWSCAN */
+- { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++ { IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_scan_req), 0},
+ /* SIOCGIWSCAN */
+- { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0},
++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, IW_DESCR_FLAG_NOMAX},
+ /* SIOCSIWESSID */
+ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT},
+ /* SIOCGIWESSID */
+@@ -179,6 +185,25 @@
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ /* SIOCGIWPOWER */
+ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++ /* -- hole -- */
++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++ /* -- hole -- */
++ { IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++ /* SIOCSIWGENIE */
++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_GENERIC_IE_MAX, 0},
++ /* SIOCGIWGENIE */
++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_GENERIC_IE_MAX, 0},
++ /* SIOCSIWAUTH */
++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++ /* SIOCGIWAUTH */
++ { IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++ /* SIOCSIWENCODEEXT */
++ { IW_HEADER_TYPE_POINT, 0, 1, sizeof(struct iw_encode_ext), sizeof(struct iw_encode_ext) + IW_ENCODING_TOKEN_MAX, 0},
++ /* SIOCGIWENCODEEXT */
++ { IW_HEADER_TYPE_POINT, 0, 1, sizeof(struct iw_encode_ext), sizeof(struct iw_encode_ext) + IW_ENCODING_TOKEN_MAX, 0},
++ /* SIOCSIWPMKSA */
++ { IW_HEADER_TYPE_POINT, 0, 1, sizeof(struct iw_pmksa), sizeof(struct iw_pmksa), 0},
++ /* -- hole -- */
+ };
+ static const int standard_ioctl_num = (sizeof(standard_ioctl) /
+ sizeof(struct iw_ioctl_description));
+@@ -198,12 +223,22 @@
+ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+ /* IWEVEXPIRED */
+ { IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
++ /* IWEVGENIE */
++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_GENERIC_IE_MAX, 0},
++ /* IWEVMICHAELMICFAILURE */
++ { IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_michaelmicfailure), 0},
++ /* IWEVASSOCREQIE */
++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_GENERIC_IE_MAX, 0},
++ /* IWEVASSOCRESPIE */
++ { IW_HEADER_TYPE_POINT, 0, 1, 0, IW_GENERIC_IE_MAX, 0},
++ /* IWEVPMKIDCAND */
++ { IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_pmkid_cand), 0},
+ };
+ static const int standard_event_num = (sizeof(standard_event) /
+ sizeof(struct iw_ioctl_description));
+
+ /* Size (in bytes) of the various private data types */
+-static const char priv_type_size[] = {
++static const char iw_priv_type_size[] = {
+ 0, /* IW_PRIV_TYPE_NONE */
+ 1, /* IW_PRIV_TYPE_BYTE */
+ 1, /* IW_PRIV_TYPE_CHAR */
+@@ -270,12 +305,15 @@
+ */
+ static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
+ {
++ /* New location */
++ if((dev->wireless_handlers != NULL) &&
++ (dev->wireless_handlers->get_wireless_stats != NULL))
++ return dev->wireless_handlers->get_wireless_stats(dev);
++
++ /* Old location, will be phased out in next WE */
+ return (dev->get_wireless_stats ?
+ dev->get_wireless_stats(dev) :
+ (struct iw_statistics *) NULL);
+- /* In the future, get_wireless_stats may move from 'struct net_device'
+- * to 'struct iw_handler_def', to de-bloat struct net_device.
+- * Definitely worse a thought... */
+ }
+
+ /* ---------------------------------------------------------------- */
+@@ -310,14 +348,32 @@
+
+ /* ---------------------------------------------------------------- */
+ /*
+- * Number of private arguments
++ * Calculate size of private arguments
+ */
+ static inline int get_priv_size(__u16 args)
+ {
+ int num = args & IW_PRIV_SIZE_MASK;
+ int type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+- return num * priv_type_size[type];
++ return num * iw_priv_type_size[type];
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Re-calculate the size of private arguments
++ */
++static inline int adjust_priv_size(__u16 args,
++ union iwreq_data * wrqu)
++{
++ int num = wrqu->data.length;
++ int max = args & IW_PRIV_SIZE_MASK;
++ int type = (args & IW_PRIV_TYPE_MASK) >> 12;
++
++ /* Make sure the driver doesn't goof up */
++ if (max < num)
++ num = max;
++
++ return num * iw_priv_type_size[type];
+ }
+
+
+@@ -350,11 +406,14 @@
+ dev->name,
+ stats->status,
+ stats->qual.qual,
+- stats->qual.updated & 1 ? '.' : ' ',
++ stats->qual.updated & IW_QUAL_QUAL_UPDATED
++ ? '.' : ' ',
+ ((__u8) stats->qual.level),
+- stats->qual.updated & 2 ? '.' : ' ',
++ stats->qual.updated & IW_QUAL_LEVEL_UPDATED
++ ? '.' : ' ',
+ ((__u8) stats->qual.noise),
+- stats->qual.updated & 4 ? '.' : ' ',
++ stats->qual.updated & IW_QUAL_NOISE_UPDATED
++ ? '.' : ' ',
+ stats->discard.nwid,
+ stats->discard.code,
+ stats->discard.fragment,
+@@ -470,13 +529,15 @@
+ /* Check NULL pointer */
+ if(iwr->u.data.pointer == NULL)
+ return -EFAULT;
+-#ifdef WE_STRICT_WRITE
++
+ /* Check if there is enough buffer up there */
+ if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
+- printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
++ /* User space can't know in advance how large the buffer
++ * needs to be. Give it a hint, so that we can support
++ * any size buffer we want somewhat efficiently... */
++ iwr->u.data.length = dev->wireless_handlers->num_private_args;
+ return -E2BIG;
+ }
+-#endif /* WE_STRICT_WRITE */
+
+ /* Set the number of available ioctls. */
+ iwr->u.data.length = dev->wireless_handlers->num_private_args;
+@@ -505,7 +566,6 @@
+ const struct iw_ioctl_description * descr;
+ struct iw_request_info info;
+ int ret = -EINVAL;
+- int user_size = 0;
+
+ /* Get the description of the IOCTL */
+ if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+@@ -536,8 +596,14 @@
+ #endif /* WE_SET_EVENT */
+ } else {
+ char * extra;
++ int extra_size;
++ int user_length = 0;
+ int err;
+
++ /* Calculate space needed by arguments. Always allocate
++ * for max space. Easier, and won't last long... */
++ extra_size = descr->max_tokens * descr->token_size;
++
+ /* Check what user space is giving us */
+ if(IW_IS_SET(cmd)) {
+ /* Check NULL pointer */
+@@ -554,18 +620,33 @@
+ if(iwr->u.data.pointer == NULL)
+ return -EFAULT;
+ /* Save user space buffer size for checking */
+- user_size = iwr->u.data.length;
++ user_length = iwr->u.data.length;
++
++ /* Don't check if user_length > max to allow forward
++ * compatibility. The test user_length < min is
++ * implied by the test at the end. */
++
++ /* Support for very large requests */
++ if((descr->flags & IW_DESCR_FLAG_NOMAX) &&
++ (user_length > descr->max_tokens)) {
++ /* Allow userspace to GET more than max so
++ * we can support any size GET requests.
++ * There is still a limit : -ENOMEM. */
++ extra_size = user_length * descr->token_size;
++ /* Note : user_length is originally a __u16,
++ * and token_size is controlled by us,
++ * so extra_size won't get negative and
++ * won't overflow... */
++ }
+ }
+
+ #ifdef WE_IOCTL_DEBUG
+ printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
+- dev->name, descr->max_tokens * descr->token_size);
++ dev->name, extra_size);
+ #endif /* WE_IOCTL_DEBUG */
+
+- /* Always allocate for max space. Easier, and won't last
+- * long... */
+- extra = kmalloc(descr->max_tokens * descr->token_size,
+- GFP_KERNEL);
++ /* Create the kernel buffer */
++ extra = kmalloc(extra_size, GFP_KERNEL);
+ if (extra == NULL) {
+ return -ENOMEM;
+ }
+@@ -591,14 +672,11 @@
+
+ /* If we have something to return to the user */
+ if (!ret && IW_IS_GET(cmd)) {
+-#ifdef WE_STRICT_WRITE
+ /* Check if there is enough buffer up there */
+- if(user_size < iwr->u.data.length) {
+- printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
++ if(user_length < iwr->u.data.length) {
+ kfree(extra);
+ return -E2BIG;
+ }
+-#endif /* WE_STRICT_WRITE */
+
+ err = copy_to_user(iwr->u.data.pointer, extra,
+ iwr->u.data.length *
+@@ -661,7 +739,7 @@
+ iw_handler handler)
+ {
+ struct iwreq * iwr = (struct iwreq *) ifr;
+- struct iw_priv_args * descr = NULL;
++ const struct iw_priv_args * descr = NULL;
+ struct iw_request_info info;
+ int extra_size = 0;
+ int i;
+@@ -701,7 +779,7 @@
+ ((extra_size + offset) <= IFNAMSIZ))
+ extra_size = 0;
+ } else {
+- /* Size of set arguments */
++ /* Size of get arguments */
+ extra_size = get_priv_size(descr->get_args);
+
+ /* Does it fits in iwr ? */
+@@ -771,6 +849,14 @@
+
+ /* If we have something to return to the user */
+ if (!ret && IW_IS_GET(cmd)) {
++
++ /* Adjust for the actual length if it's variable,
++ * avoid leaking kernel bits outside. */
++ if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
++ extra_size = adjust_priv_size(descr->get_args,
++ &(iwr->u));
++ }
++
+ err = copy_to_user(iwr->u.data.pointer, extra,
+ extra_size);
+ if (err)
+@@ -1042,9 +1128,25 @@
+ * One of the main advantage of centralising spy support here is that
+ * it becomes much easier to improve and extend it without having to touch
+ * the drivers. One example is the addition of the Spy-Threshold events.
+- * Note : IW_WIRELESS_SPY is defined in iw_handler.h
+ */
+
++/* ---------------------------------------------------------------- */
++/*
++ * Return the pointer to the spy data in the driver.
++ * Because this is called on the Rx path via wireless_spy_update(),
++ * we want it to be efficient...
++ */
++static inline struct iw_spy_data * get_spydata(struct net_device *dev)
++{
++ /* This is the new way */
++ if(dev->wireless_data)
++ return(dev->wireless_data->spy_data);
++
++ /* This is the old way. Doesn't work for multi-headed drivers.
++ * It will be removed in the next version of WE. */
++ return (dev->priv + dev->wireless_handlers->spy_offset);
++}
++
+ /*------------------------------------------------------------------*/
+ /*
+ * Standard Wireless Handler : set Spy List
+@@ -1054,16 +1156,26 @@
+ union iwreq_data * wrqu,
+ char * extra)
+ {
+-#ifdef IW_WIRELESS_SPY
+- struct iw_spy_data * spydata = (dev->priv +
+- dev->wireless_handlers->spy_offset);
++ struct iw_spy_data * spydata = get_spydata(dev);
+ struct sockaddr * address = (struct sockaddr *) extra;
+
++ /* Make sure driver is not buggy or using the old API */
++ if(!spydata)
++ return -EOPNOTSUPP;
++
+ /* Disable spy collection while we copy the addresses.
+- * As we don't disable interrupts, we need to do this to avoid races.
+- * As we are the only writer, this is good enough. */
++ * While we copy addresses, any call to wireless_spy_update()
++ * will NOP. This is OK, as anyway the addresses are changing. */
+ spydata->spy_number = 0;
+
++ /* We want to operate without locking, because wireless_spy_update()
++ * most likely will happen in the interrupt handler, and therefore
++ * have its own locking constraints and needs performance.
++ * The rtnl_lock() make sure we don't race with the other iw_handlers.
++ * This make sure wireless_spy_update() "see" that the spy list
++ * is temporarily disabled. */
++ wmb();
++
+ /* Are there are addresses to copy? */
+ if(wrqu->data.length > 0) {
+ int i;
+@@ -1089,13 +1201,14 @@
+ spydata->spy_address[i][5]);
+ #endif /* WE_SPY_DEBUG */
+ }
++
++ /* Make sure above is updated before re-enabling */
++ wmb();
++
+ /* Enable addresses */
+ spydata->spy_number = wrqu->data.length;
+
+ return 0;
+-#else /* IW_WIRELESS_SPY */
+- return -EOPNOTSUPP;
+-#endif /* IW_WIRELESS_SPY */
+ }
+
+ /*------------------------------------------------------------------*/
+@@ -1107,12 +1220,14 @@
+ union iwreq_data * wrqu,
+ char * extra)
+ {
+-#ifdef IW_WIRELESS_SPY
+- struct iw_spy_data * spydata = (dev->priv +
+- dev->wireless_handlers->spy_offset);
++ struct iw_spy_data * spydata = get_spydata(dev);
+ struct sockaddr * address = (struct sockaddr *) extra;
+ int i;
+
++ /* Make sure driver is not buggy or using the old API */
++ if(!spydata)
++ return -EOPNOTSUPP;
++
+ wrqu->data.length = spydata->spy_number;
+
+ /* Copy addresses. */
+@@ -1129,9 +1244,6 @@
+ for(i = 0; i < spydata->spy_number; i++)
+ spydata->spy_stat[i].updated = 0;
+ return 0;
+-#else /* IW_WIRELESS_SPY */
+- return -EOPNOTSUPP;
+-#endif /* IW_WIRELESS_SPY */
+ }
+
+ /*------------------------------------------------------------------*/
+@@ -1143,11 +1255,13 @@
+ union iwreq_data * wrqu,
+ char * extra)
+ {
+-#ifdef IW_WIRELESS_THRSPY
+- struct iw_spy_data * spydata = (dev->priv +
+- dev->wireless_handlers->spy_offset);
++ struct iw_spy_data * spydata = get_spydata(dev);
+ struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
+
++ /* Make sure driver is not buggy or using the old API */
++ if(!spydata)
++ return -EOPNOTSUPP;
++
+ /* Just do it */
+ memcpy(&(spydata->spy_thr_low), &(threshold->low),
+ 2 * sizeof(struct iw_quality));
+@@ -1160,9 +1274,6 @@
+ #endif /* WE_SPY_DEBUG */
+
+ return 0;
+-#else /* IW_WIRELESS_THRSPY */
+- return -EOPNOTSUPP;
+-#endif /* IW_WIRELESS_THRSPY */
+ }
+
+ /*------------------------------------------------------------------*/
+@@ -1174,22 +1285,20 @@
+ union iwreq_data * wrqu,
+ char * extra)
+ {
+-#ifdef IW_WIRELESS_THRSPY
+- struct iw_spy_data * spydata = (dev->priv +
+- dev->wireless_handlers->spy_offset);
++ struct iw_spy_data * spydata = get_spydata(dev);
+ struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
+
++ /* Make sure driver is not buggy or using the old API */
++ if(!spydata)
++ return -EOPNOTSUPP;
++
+ /* Just do it */
+ memcpy(&(threshold->low), &(spydata->spy_thr_low),
+ 2 * sizeof(struct iw_quality));
+
+ return 0;
+-#else /* IW_WIRELESS_THRSPY */
+- return -EOPNOTSUPP;
+-#endif /* IW_WIRELESS_THRSPY */
+ }
+
+-#ifdef IW_WIRELESS_THRSPY
+ /*------------------------------------------------------------------*/
+ /*
+ * Prepare and send a Spy Threshold event
+@@ -1227,7 +1336,6 @@
+ /* Send event to user space */
+ wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
+ }
+-#endif /* IW_WIRELESS_THRSPY */
+
+ /* ---------------------------------------------------------------- */
+ /*
+@@ -1240,12 +1348,14 @@
+ unsigned char * address,
+ struct iw_quality * wstats)
+ {
+-#ifdef IW_WIRELESS_SPY
+- struct iw_spy_data * spydata = (dev->priv +
+- dev->wireless_handlers->spy_offset);
++ struct iw_spy_data * spydata = get_spydata(dev);
+ int i;
+ int match = -1;
+
++ /* Make sure driver is not buggy or using the old API */
++ if(!spydata)
++ return;
++
+ #ifdef WE_SPY_DEBUG
+ printk(KERN_DEBUG "wireless_spy_update() : offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
+ #endif /* WE_SPY_DEBUG */
+@@ -1257,7 +1367,7 @@
+ sizeof(struct iw_quality));
+ match = i;
+ }
+-#ifdef IW_WIRELESS_THRSPY
++
+ /* Generate an event if we cross the spy threshold.
+ * To avoid event storms, we have a simple hysteresis : we generate
+ * event only when we go under the low threshold or above the
+@@ -1277,6 +1387,4 @@
+ }
+ }
+ }
+-#endif /* IW_WIRELESS_THRSPY */
+-#endif /* IW_WIRELESS_SPY */
+ }
diff --git a/target/linux/generic-2.4/patches/106-mppe_mppc.patch b/target/linux/generic-2.4/patches/106-mppe_mppc.patch
new file mode 100644
index 0000000..382b462
--- /dev/null
+++ b/target/linux/generic-2.4/patches/106-mppe_mppc.patch
@@ -0,0 +1,1649 @@
+MPPE/MPPC kernel module for Linux
+
+Microsoft Point-to-Point Encryption / Compression support
+
+ http://www.polbox.com/h/hs001/linux-2.4.29-mppe-mppc-1.3.patch.gz
+
+diff -ruN linux-2.4.29.orig/Documentation/Configure.help linux-2.4.29/Documentation/Configure.help
+--- linux-2.4.29.orig/Documentation/Configure.help 2005-02-02 22:18:18.000000000 +0100
++++ linux-2.4.29/Documentation/Configure.help 2005-02-02 22:26:37.000000000 +0100
+@@ -9969,6 +9969,28 @@
+ module; it is called bsd_comp.o and will show up in the directory
+ modules once you have said "make modules". If unsure, say N.
+
++Microsoft PPP compression/encryption (MPPC/MPPE)
++CONFIG_PPP_MPPE_MPPC
++ Support for the Microsoft Point-To-Point Compression (RFC2118) and
++ Microsoft Point-To-Point Encryption (RFC3078). These protocols are
++ supported by Microsoft Windows and wide range of "hardware" access
++ servers. MPPE is common protocol in Virtual Private Networks. According
++ to RFC3078, MPPE supports 40, 56 and 128-bit key lengths. Depending on
++ PPP daemon configuration on both ends of the link, following scenarios
++ are possible:
++ - only compression (MPPC) is used,
++ - only encryption (MPPE) is used,
++ - compression and encryption (MPPC+MPPE) are used.
++
++ Please note that Hi/Fn (http://www.hifn.com) holds patent on MPPC so
++ you should check if this patent is valid in your country in order to
++ avoid legal problems.
++
++ For more information please visit http://free.polbox.pl/h/hs001
++
++ To compile this driver as a module, choose M here. The module will
++ be called ppp_mppe_mppc.o.
++
+ PPP over Ethernet
+ CONFIG_PPPOE
+ Support for PPP over Ethernet.
+diff -ruN linux-2.4.29.orig/crypto/Config.in linux-2.4.29/crypto/Config.in
+--- linux-2.4.29.orig/crypto/Config.in 2005-02-02 22:18:14.000000000 +0100
++++ linux-2.4.29/crypto/Config.in 2005-02-02 22:26:37.000000000 +0100
+@@ -11,7 +11,9 @@
+ "$CONFIG_INET6_AH" = "y" -o \
+ "$CONFIG_INET6_AH" = "m" -o \
+ "$CONFIG_INET6_ESP" = "y" -o \
+- "$CONFIG_INET6_ESP" = "m" ]; then
++ "$CONFIG_INET6_ESP" = "m" -o \
++ "$CONFIG_PPP_MPPE_MPPC" = "y" -o \
++ "$CONFIG_PPP_MPPE_MPPC" = "m" ]; then
+ define_bool CONFIG_CRYPTO y
+ else
+ bool 'Cryptographic API' CONFIG_CRYPTO
+@@ -51,11 +53,24 @@
+ "$CONFIG_INET6_AH" = "y" -o \
+ "$CONFIG_INET6_AH" = "m" -o \
+ "$CONFIG_INET6_ESP" = "y" -o \
+- "$CONFIG_INET6_ESP" = "m" ]; then
+- define_bool CONFIG_CRYPTO_SHA1 y
+- else
+- tristate ' SHA1 digest algorithm' CONFIG_CRYPTO_SHA1
++ "$CONFIG_INET6_ESP" = "m" -o \
++ "$CONFIG_PPP_MPPE_MPPC" = "y" -o \
++ "$CONFIG_PPP_MPPE_MPPC" = "m" ]; then
++ if [ "$CONFIG_INET_AH" = "y" -o \
++ "$CONFIG_INET_ESP" = "y" -o \
++ "$CONFIG_INET6_AH" = "y" -o \
++ "$CONFIG_INET6_ESP" = "y" -o \
++ "$CONFIG_PPP_MPPE_MPPC" = "y" ]; then
++ define_tristate CONFIG_CRYPTO_SHA1 y
++ else
++ if [ "$CONFIG_CRYPTO_SHA1" != "y" -a \
++ "$CONFIG_CRYPTO_SHA1" != "m" ]; then
++ define_tristate CONFIG_CRYPTO_SHA1 m
++ fi
++ fi
+ fi
++ tristate ' SHA1 digest algorithm' CONFIG_CRYPTO_SHA1
++
+ tristate ' SHA256 digest algorithm' CONFIG_CRYPTO_SHA256
+ tristate ' SHA384 and SHA512 digest algorithms' CONFIG_CRYPTO_SHA512
+ tristate ' Whirlpool digest algorithms' CONFIG_CRYPTO_WP512
+@@ -76,7 +91,20 @@
+ tristate ' TEA and XTEA cipher algorithms' CONFIG_CRYPTO_TEA
+ tristate ' Khazad cipher algorithm' CONFIG_CRYPTO_KHAZAD
+ tristate ' Anubis cipher algorithm' CONFIG_CRYPTO_ANUBIS
++
++ if [ "$CONFIG_PPP_MPPE_MPPC" = "y" -o \
++ "$CONFIG_PPP_MPPE_MPPC" = "m" ]; then
++ if [ "$CONFIG_PPP_MPPE_MPPC" = "y" ]; then
++ define_tristate CONFIG_CRYPTO_ARC4 y
++ else
++ if [ "$CONFIG_CRYPTO_ARC4" != "y" -a \
++ "$CONFIG_CRYPTO_ARC4" != "m" ]; then
++ define_tristate CONFIG_CRYPTO_ARC4 m
++ fi
++ fi
++ fi
+ tristate ' ARC4 cipher algorithm' CONFIG_CRYPTO_ARC4
++
+ if [ "$CONFIG_INET_IPCOMP" = "y" -o \
+ "$CONFIG_INET_IPCOMP" = "m" -o \
+ "$CONFIG_INET6_IPCOMP" = "y" -o \
+diff -ruN linux-2.4.29.orig/drivers/net/Config.in linux-2.4.29/drivers/net/Config.in
+--- linux-2.4.29.orig/drivers/net/Config.in 2005-02-02 22:17:31.000000000 +0100
++++ linux-2.4.29/drivers/net/Config.in 2005-02-02 22:26:37.000000000 +0100
+@@ -332,6 +332,7 @@
+ dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
+ dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
+ dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP
++ dep_tristate ' Microsoft PPP compression/encryption (MPPC/MPPE)' CONFIG_PPP_MPPE_MPPC $CONFIG_PPP
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP
+ fi
+diff -ruN linux-2.4.29.orig/drivers/net/Makefile linux-2.4.29/drivers/net/Makefile
+--- linux-2.4.29.orig/drivers/net/Makefile 2005-02-02 22:17:23.000000000 +0100
++++ linux-2.4.29/drivers/net/Makefile 2005-02-02 22:26:37.000000000 +0100
+@@ -163,6 +163,7 @@
+ obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
+ obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
+ obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
++obj-$(CONFIG_PPP_MPPE_MPPC) += ppp_mppe_mppc.o
+ obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
+
+ obj-$(CONFIG_SLIP) += slip.o
+diff -ruN linux-2.4.29.orig/drivers/net/ppp_generic.c linux-2.4.29/drivers/net/ppp_generic.c
+--- linux-2.4.29.orig/drivers/net/ppp_generic.c 2005-02-02 22:17:24.000000000 +0100
++++ linux-2.4.29/drivers/net/ppp_generic.c 2005-02-02 22:26:37.000000000 +0100
+@@ -19,7 +19,7 @@
+ * PPP driver, written by Michael Callahan and Al Longyear, and
+ * subsequently hacked by Paul Mackerras.
+ *
+- * ==FILEVERSION 20020217==
++ * ==FILEVERSION 20040509==
+ */
+
+ #include <linux/config.h>
+@@ -102,6 +102,7 @@
+ spinlock_t rlock; /* lock for receive side 58 */
+ spinlock_t wlock; /* lock for transmit side 5c */
+ int mru; /* max receive unit 60 */
++ int mru_alloc; /* MAX(1500,MRU) for dev_alloc_skb() */
+ unsigned int flags; /* control bits 64 */
+ unsigned int xstate; /* transmit state bits 68 */
+ unsigned int rstate; /* receive state bits 6c */
+@@ -552,7 +553,9 @@
+ case PPPIOCSMRU:
+ if (get_user(val, (int *) arg))
+ break;
+- ppp->mru = val;
++ ppp->mru_alloc = ppp->mru = val;
++ if (ppp->mru_alloc < PPP_MRU)
++ ppp->mru_alloc = PPP_MRU; /* increase for broken peers */
+ err = 0;
+ break;
+
+@@ -1025,14 +1028,37 @@
+ case PPP_CCP:
+ /* peek at outbound CCP frames */
+ ppp_ccp_peek(ppp, skb, 0);
++ /*
++ * When LZS or MPPE/MPPC has been negotiated we don't send
++ * CCP_RESETACK after receiving CCP_RESETREQ; in fact pppd
++ * sends such a packet but we silently discard it here
++ */
++ if (CCP_CODE(skb->data+2) == CCP_RESETACK
++ && (ppp->xcomp->compress_proto == CI_MPPE
++ || ppp->xcomp->compress_proto == CI_LZS)) {
++ --ppp->stats.tx_packets;
++ ppp->stats.tx_bytes -= skb->len - 2;
++ kfree_skb(skb);
++ return;
++ }
+ break;
+ }
+
+ /* try to do packet compression */
+ if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
+ && proto != PPP_LCP && proto != PPP_CCP) {
+- new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len,
+- GFP_ATOMIC);
++ int comp_ovhd = 0;
++ /*
++ * because of possible data expansion when MPPC or LZS
++ * is used, allocate compressor's buffer 12.5% bigger
++ * than MTU
++ */
++ if (ppp->xcomp->compress_proto == CI_MPPE)
++ comp_ovhd = ((ppp->dev->mtu * 9) / 8) + 1 + MPPE_OVHD;
++ else if (ppp->xcomp->compress_proto == CI_LZS)
++ comp_ovhd = ((ppp->dev->mtu * 9) / 8) + 1 + LZS_OVHD;
++ new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len
++ + comp_ovhd, GFP_ATOMIC);
+ if (new_skb == 0) {
+ printk(KERN_ERR "PPP: no memory (comp pkt)\n");
+ goto drop;
+@@ -1050,9 +1076,21 @@
+ skb = new_skb;
+ skb_put(skb, len);
+ skb_pull(skb, 2); /* pull off A/C bytes */
+- } else {
++ } else if (len == 0) {
+ /* didn't compress, or CCP not up yet */
+ kfree_skb(new_skb);
++ } else {
++ /*
++ * (len < 0)
++ * MPPE requires that we do not send unencrypted
++ * frames. The compressor will return -1 if we
++ * should drop the frame. We cannot simply test
++ * the compress_proto because MPPE and MPPC share
++ * the same number.
++ */
++ printk(KERN_ERR "ppp: compressor dropped pkt\n");
++ kfree_skb(new_skb);
++ goto drop;
+ }
+ }
+
+@@ -1540,14 +1578,15 @@
+ int len;
+
+ if (proto == PPP_COMP) {
+- ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN);
++ ns = dev_alloc_skb(ppp->mru_alloc + PPP_HDRLEN);
+ if (ns == 0) {
+ printk(KERN_ERR "ppp_decompress_frame: no memory\n");
+ goto err;
+ }
+ /* the decompressor still expects the A/C bytes in the hdr */
+ len = ppp->rcomp->decompress(ppp->rc_state, skb->data - 2,
+- skb->len + 2, ns->data, ppp->mru + PPP_HDRLEN);
++ skb->len + 2, ns->data,
++ ppp->mru_alloc + PPP_HDRLEN);
+ if (len < 0) {
+ /* Pass the compressed frame to pppd as an
+ error indication. */
+@@ -1573,7 +1612,14 @@
+ return skb;
+
+ err:
+- ppp->rstate |= SC_DC_ERROR;
++ if (ppp->rcomp->compress_proto != CI_MPPE
++ && ppp->rcomp->compress_proto != CI_LZS) {
++ /*
++ * If decompression protocol isn't MPPE/MPPC or LZS, we set
++ * SC_DC_ERROR flag and wait for CCP_RESETACK
++ */
++ ppp->rstate |= SC_DC_ERROR;
++ }
+ ppp_receive_error(ppp);
+ return skb;
+ }
+@@ -2253,6 +2299,7 @@
+ /* Initialize the new ppp unit */
+ ppp->file.index = unit;
+ ppp->mru = PPP_MRU;
++ ppp->mru_alloc = PPP_MRU;
+ init_ppp_file(&ppp->file, INTERFACE);
+ ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */
+ for (i = 0; i < NUM_NP; ++i)
+diff -ruN linux-2.4.29.orig/drivers/net/ppp_mppe_mppc.c linux-2.4.29/drivers/net/ppp_mppe_mppc.c
+--- linux-2.4.29.orig/drivers/net/ppp_mppe_mppc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/drivers/net/ppp_mppe_mppc.c 2005-02-02 23:07:40.000000000 +0100
+@@ -0,0 +1,1312 @@
++/*
++ * ppp_mppe_mppc.c - MPPC/MPPE "compressor/decompressor" module.
++ *
++ * Copyright (c) 1994 Árpád Magosányi <mag@bunuel.tii.matav.hu>
++ * Copyright (c) 1999 Tim Hockin, Cobalt Networks Inc. <thockin@cobaltnet.com>
++ * Copyright (c) 2002-2005 Jan Dubiec <jdx@slackware.pl>
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies. This software is provided without any
++ * warranty, express or implied.
++ *
++ * The code is based on MPPE kernel module written by Árpád Magosányi and
++ * Tim Hockin which can be found on http://planetmirror.com/pub/mppe/.
++ * I have added MPPC and 56 bit session keys support in MPPE.
++ *
++ * WARNING! Although this is open source code, its usage in some countries
++ * (in particular in the USA) may violate Stac Inc. patent for MPPC.
++ *
++ * ==FILEVERSION 20050202==
++ *
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <asm/scatterlist.h>
++#include <linux/vmalloc.h>
++#include <linux/crypto.h>
++
++#include <linux/ppp_defs.h>
++#include <linux/ppp-comp.h>
++
++/*
++ * In 2.4.x kernels macro offset_in_page() is not defined in linux/mm.h so
++ * we define it here; PAGE_MASK is defined in asm/page.h which is included
++ * by linux/mm.h.
++ */
++#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
++
++/*
++ * State for a mppc/mppe "(de)compressor".
++ */
++struct ppp_mppe_state {
++ struct crypto_tfm *arc4_tfm;
++ struct crypto_tfm *sha1_tfm;
++ u8 *sha1_digest;
++ u8 master_key[MPPE_MAX_KEY_LEN];
++ u8 session_key[MPPE_MAX_KEY_LEN];
++ u8 mppc; /* do we use compression (MPPC)? */
++ u8 mppe; /* do we use encryption (MPPE)? */
++ u8 keylen; /* key length in bytes */
++ u8 bitkeylen; /* key length in bits */
++ u16 ccount; /* coherency counter */
++ u16 bits; /* MPPC/MPPE control bits */
++ u8 stateless; /* do we use stateless mode? */
++ u8 nextflushed; /* set A bit in the next outgoing packet;
++ used only by compressor*/
++ u8 flushexpected; /* drop packets until A bit is received;
++ used only by decompressor*/
++ u8 *hist; /* MPPC history */
++ u16 *hash; /* Hash table; used only by compressor */
++ u16 histptr; /* history "cursor" */
++ int unit;
++ int debug;
++ int mru;
++ struct compstat stats;
++};
++
++#define MPPE_HIST_LEN 8192 /* MPPC history size */
++#define MPPE_MAX_CCOUNT 0x0FFF /* max. coherency counter value */
++
++#define MPPE_BIT_FLUSHED 0x80 /* bit A */
++#define MPPE_BIT_RESET 0x40 /* bit B */
++#define MPPE_BIT_COMP 0x20 /* bit C */
++#define MPPE_BIT_ENCRYPTED 0x10 /* bit D */
++
++#define MPPE_SALT0 0xD1 /* values used in MPPE key derivation */
++#define MPPE_SALT1 0x26 /* according to RFC3079 */
++#define MPPE_SALT2 0x9E
++
++#define MPPE_CCOUNT(x) ((((x)[4] & 0x0f) << 8) + (x)[5])
++#define MPPE_BITS(x) ((x)[4] & 0xf0)
++#define MPPE_CTRLHI(x) ((((x)->ccount & 0xf00)>>8)|((x)->bits))
++#define MPPE_CTRLLO(x) ((x)->ccount & 0xff)
++
++/*
++ * Kernel Crypto API needs its arguments to be in kmalloc'd memory, not in the
++ * module static data area. That means sha_pad needs to be kmalloc'd. It is done
++ * in mppe_module_init(). This has been pointed out on 30th July 2004 by Oleg
++ * Makarenko on pptpclient-devel mailing list.
++ */
++#define SHA1_PAD_SIZE 40
++struct sha_pad {
++ unsigned char sha_pad1[SHA1_PAD_SIZE];
++ unsigned char sha_pad2[SHA1_PAD_SIZE];
++};
++static struct sha_pad *sha_pad;
++
++static inline void
++setup_sg(struct scatterlist *sg, const void *address, unsigned int length)
++{
++ sg[0].page = virt_to_page(address);
++ sg[0].offset = offset_in_page(address);
++ sg[0].length = length;
++}
++
++static inline void
++arc4_setkey(struct ppp_mppe_state *state, const unsigned char *key,
++ const unsigned int keylen)
++{
++ crypto_cipher_setkey(state->arc4_tfm, key, keylen);
++}
++
++static inline void
++arc4_encrypt(struct ppp_mppe_state *state, const unsigned char *in,
++ const unsigned int len, unsigned char *out)
++{
++ struct scatterlist sgin[4], sgout[4];
++
++ setup_sg(sgin, in, len);
++ setup_sg(sgout, out, len);
++ crypto_cipher_encrypt(state->arc4_tfm, sgout, sgin, len);
++}
++
++#define arc4_decrypt arc4_encrypt
++
++/*
++ * Key Derivation, from RFC 3078, RFC 3079.
++ * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079.
++ */
++static void
++get_new_key_from_sha(struct ppp_mppe_state *state, unsigned char *interim_key)
++{
++ struct scatterlist sg[4];
++
++ setup_sg(&sg[0], state->master_key, state->keylen);
++ setup_sg(&sg[1], sha_pad->sha_pad1, sizeof(sha_pad->sha_pad1));
++ setup_sg(&sg[2], state->session_key, state->keylen);
++ setup_sg(&sg[3], sha_pad->sha_pad2, sizeof(sha_pad->sha_pad2));
++
++ crypto_digest_digest (state->sha1_tfm, sg, 4, state->sha1_digest);
++
++ memcpy(interim_key, state->sha1_digest, state->keylen);
++}
++
++static void
++mppe_change_key(struct ppp_mppe_state *state, int initialize)
++{
++ unsigned char interim_key[MPPE_MAX_KEY_LEN];
++
++ get_new_key_from_sha(state, interim_key);
++ if (initialize) {
++ memcpy(state->session_key, interim_key, state->keylen);
++ } else {
++ arc4_setkey(state, interim_key, state->keylen);
++ arc4_encrypt(state, interim_key, state->keylen, state->session_key);
++ }
++ if (state->keylen == 8) {
++ if (state->bitkeylen == 40) {
++ state->session_key[0] = MPPE_SALT0;
++ state->session_key[1] = MPPE_SALT1;
++ state->session_key[2] = MPPE_SALT2;
++ } else {
++ state->session_key[0] = MPPE_SALT0;
++ }
++ }
++ arc4_setkey(state, state->session_key, state->keylen);
++}
++
++/* increase 12-bit coherency counter */
++static inline void
++mppe_increase_ccount(struct ppp_mppe_state *state)
++{
++ state->ccount = (state->ccount + 1) & MPPE_MAX_CCOUNT;
++ if (state->mppe) {
++ if (state->stateless) {
++ mppe_change_key(state, 0);
++ state->nextflushed = 1;
++ } else {
++ if ((state->ccount & 0xff) == 0xff) {
++ mppe_change_key(state, 0);
++ }
++ }
++ }
++}
++
++/* allocate space for a MPPE/MPPC (de)compressor. */
++/* comp != 0 -> init compressor */
++/* comp = 0 -> init decompressor */
++static void *
++mppe_alloc(unsigned char *options, int opt_len, int comp)
++{
++ struct ppp_mppe_state *state;
++ unsigned int digestsize;
++ u8* fname;
++
++ fname = comp ? "mppe_comp_alloc" : "mppe_decomp_alloc";
++
++ /*
++ * Hack warning - additionally to the standard MPPC/MPPE configuration
++ * options, pppd passes to the (de)copressor 8 or 16 byte session key.
++ * Therefore options[1] contains MPPC/MPPE configuration option length
++ * (CILEN_MPPE = 6), but the real options length, depending on the key
++ * length, is 6+8 or 6+16.
++ */
++ if (opt_len < CILEN_MPPE) {
++ printk(KERN_WARNING "%s: wrong options length: %u\n", fname, opt_len);
++ return NULL;
++ }
++
++ if (options[0] != CI_MPPE || options[1] != CILEN_MPPE ||
++ (options[2] & ~MPPE_STATELESS) != 0 ||
++ options[3] != 0 || options[4] != 0 ||
++ (options[5] & ~(MPPE_128BIT|MPPE_56BIT|MPPE_40BIT|MPPE_MPPC)) != 0 ||
++ (options[5] & (MPPE_128BIT|MPPE_56BIT|MPPE_40BIT|MPPE_MPPC)) == 0) {
++ printk(KERN_WARNING "%s: options rejected: o[0]=%02x, o[1]=%02x, "
++ "o[2]=%02x, o[3]=%02x, o[4]=%02x, o[5]=%02x\n", fname, options[0],
++ options[1], options[2], options[3], options[4], options[5]);
++ return NULL;
++ }
++
++ state = (struct ppp_mppe_state *)kmalloc(sizeof(*state), GFP_KERNEL);
++ if (state == NULL) {
++ printk(KERN_ERR "%s: cannot allocate space for %scompressor\n", fname,
++ comp ? "" : "de");
++ return NULL;
++ }
++ memset(state, 0, sizeof(struct ppp_mppe_state));
++
++ state->mppc = options[5] & MPPE_MPPC; /* Do we use MPPC? */
++ state->mppe = options[5] & (MPPE_128BIT | MPPE_56BIT |
++ MPPE_40BIT); /* Do we use MPPE? */
++
++ if (state->mppc) {
++ /* allocate MPPC history */
++ state->hist = (u8*)vmalloc(2*MPPE_HIST_LEN*sizeof(u8));
++ if (state->hist == NULL) {
++ kfree(state);
++ printk(KERN_ERR "%s: cannot allocate space for MPPC history\n",
++ fname);
++ return NULL;
++ }
++
++ /* allocate hashtable for MPPC compressor */
++ if (comp) {
++ state->hash = (u16*)vmalloc(MPPE_HIST_LEN*sizeof(u16));
++ if (state->hash == NULL) {
++ vfree(state->hist);
++ kfree(state);
++ printk(KERN_ERR "%s: cannot allocate space for MPPC history\n",
++ fname);
++ return NULL;
++ }
++ }
++ }
++
++ if (state->mppe) { /* specific for MPPE */
++ /* Load ARC4 algorithm */
++ state->arc4_tfm = crypto_alloc_tfm("arc4", 0);
++ if (state->arc4_tfm == NULL) {
++ if (state->mppc) {
++ vfree(state->hash);
++ if (comp)
++ vfree(state->hist);
++ }
++ kfree(state);
++ printk(KERN_ERR "%s: cannot load ARC4 module\n", fname);
++ return NULL;
++ }
++
++ /* Load SHA1 algorithm */
++ state->sha1_tfm = crypto_alloc_tfm("sha1", 0);
++ if (state->sha1_tfm == NULL) {
++ crypto_free_tfm(state->arc4_tfm);
++ if (state->mppc) {
++ vfree(state->hash);
++ if (comp)
++ vfree(state->hist);
++ }
++ kfree(state);
++ printk(KERN_ERR "%s: cannot load SHA1 module\n", fname);
++ return NULL;
++ }
++
++ digestsize = crypto_tfm_alg_digestsize(state->sha1_tfm);
++ if (digestsize < MPPE_MAX_KEY_LEN) {
++ crypto_free_tfm(state->sha1_tfm);
++ crypto_free_tfm(state->arc4_tfm);
++ if (state->mppc) {
++ vfree(state->hash);
++ if (comp)
++ vfree(state->hist);
++ }
++ kfree(state);
++ printk(KERN_ERR "%s: CryptoAPI SHA1 digest size too small\n", fname);
++ }
++
++ state->sha1_digest = kmalloc(digestsize, GFP_KERNEL);
++ if (!state->sha1_digest) {
++ crypto_free_tfm(state->sha1_tfm);
++ crypto_free_tfm(state->arc4_tfm);
++ if (state->mppc) {
++ vfree(state->hash);
++ if (comp)
++ vfree(state->hist);
++ }
++ kfree(state);
++ printk(KERN_ERR "%s: cannot allocate space for SHA1 digest\n", fname);
++ }
++
++ memcpy(state->master_key, options+CILEN_MPPE, MPPE_MAX_KEY_LEN);
++ memcpy(state->session_key, state->master_key, MPPE_MAX_KEY_LEN);
++ /* initial key generation is done in mppe_init() */
++ }
++
++ MOD_INC_USE_COUNT;
++
++ return (void *) state;
++}
++
++static void *
++mppe_comp_alloc(unsigned char *options, int opt_len)
++{
++ return mppe_alloc(options, opt_len, 1);
++}
++
++static void *
++mppe_decomp_alloc(unsigned char *options, int opt_len)
++{
++ return mppe_alloc(options, opt_len, 0);
++}
++
++/* cleanup the (de)compressor */
++static void
++mppe_comp_free(void *arg)
++{
++ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
++
++ if (state != NULL) {
++ if (state->mppe) {
++ if (state->sha1_tfm != NULL)
++ crypto_free_tfm(state->sha1_tfm);
++ if (state->arc4_tfm != NULL)
++ crypto_free_tfm(state->arc4_tfm);
++ }
++ if (state->hist != NULL)
++ vfree(state->hist);
++ if (state->hash != NULL)
++ vfree(state->hash);
++ kfree(state);
++ }
++
++ MOD_DEC_USE_COUNT;
++}
++
++/* init MPPC/MPPE (de)compresor */
++/* comp != 0 -> init compressor */
++/* comp = 0 -> init decompressor */
++static int
++mppe_init(void *arg, unsigned char *options, int opt_len, int unit,
++ int hdrlen, int mru, int debug, int comp)
++{
++ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
++ u8* fname;
++
++ fname = comp ? "mppe_comp_init" : "mppe_decomp_init";
++
++ if (opt_len < CILEN_MPPE) {
++ if (debug)
++ printk(KERN_WARNING "%s: wrong options length: %u\n",
++ fname, opt_len);
++ return 0;
++ }
++
++ if (options[0] != CI_MPPE || options[1] != CILEN_MPPE ||
++ (options[2] & ~MPPE_STATELESS) != 0 ||
++ options[3] != 0 || options[4] != 0 ||
++ (options[5] & ~(MPPE_56BIT|MPPE_128BIT|MPPE_40BIT|MPPE_MPPC)) != 0 ||
++ (options[5] & (MPPE_56BIT|MPPE_128BIT|MPPE_40BIT|MPPE_MPPC)) == 0) {
++ if (debug)
++ printk(KERN_WARNING "%s: options rejected: o[0]=%02x, o[1]=%02x, "
++ "o[2]=%02x, o[3]=%02x, o[4]=%02x, o[5]=%02x\n", fname,
++ options[0], options[1], options[2], options[3], options[4],
++ options[5]);
++ return 0;
++ }
++
++ if ((options[5] & ~MPPE_MPPC) != MPPE_128BIT &&
++ (options[5] & ~MPPE_MPPC) != MPPE_56BIT &&
++ (options[5] & ~MPPE_MPPC) != MPPE_40BIT &&
++ (options[5] & MPPE_MPPC) != MPPE_MPPC) {
++ if (debug)
++ printk(KERN_WARNING "%s: don't know what to do: o[5]=%02x\n",
++ fname, options[5]);
++ return 0;
++ }
++
++ state->mppc = options[5] & MPPE_MPPC; /* Do we use MPPC? */
++ state->mppe = options[5] & (MPPE_128BIT | MPPE_56BIT |
++ MPPE_40BIT); /* Do we use MPPE? */
++ state->stateless = options[2] & MPPE_STATELESS; /* Do we use stateless mode? */
++
++ switch (state->mppe) {
++ case MPPE_40BIT: /* 40 bit key */
++ state->keylen = 8;
++ state->bitkeylen = 40;
++ break;
++ case MPPE_56BIT: /* 56 bit key */
++ state->keylen = 8;
++ state->bitkeylen = 56;
++ break;
++ case MPPE_128BIT: /* 128 bit key */
++ state->keylen = 16;
++ state->bitkeylen = 128;
++ break;
++ default:
++ state->keylen = 0;
++ state->bitkeylen = 0;
++ }
++
++ state->ccount = MPPE_MAX_CCOUNT;
++ state->bits = 0;
++ state->unit = unit;
++ state->debug = debug;
++ state->histptr = MPPE_HIST_LEN;
++ if (state->mppc) { /* reset history if MPPC was negotiated */
++ memset(state->hist, 0, 2*MPPE_HIST_LEN*sizeof(u8));
++ }
++
++ if (state->mppe) { /* generate initial session keys */
++ mppe_change_key(state, 1);
++ }
++
++ if (comp) { /* specific for compressor */
++ state->nextflushed = 1;
++ } else { /* specific for decompressor */
++ state->mru = mru;
++ state->flushexpected = 1;
++ }
++
++ return 1;
++}
++
++static int
++mppe_comp_init(void *arg, unsigned char *options, int opt_len, int unit,
++ int hdrlen, int debug)
++{
++ return mppe_init(arg, options, opt_len, unit, hdrlen, 0, debug, 1);
++}
++
++
++static int
++mppe_decomp_init(void *arg, unsigned char *options, int opt_len, int unit,
++ int hdrlen, int mru, int debug)
++{
++ return mppe_init(arg, options, opt_len, unit, hdrlen, mru, debug, 0);
++}
++
++static void
++mppe_comp_reset(void *arg)
++{
++ struct ppp_mppe_state *state = (struct ppp_mppe_state *)arg;
++
++ if (state->debug)
++ printk(KERN_DEBUG "%s%d: resetting MPPC/MPPE compressor\n",
++ __FUNCTION__, state->unit);
++
++ state->nextflushed = 1;
++ if (state->mppe)
++ arc4_setkey(state, state->session_key, state->keylen);
++}
++
++static void
++mppe_decomp_reset(void *arg)
++{
++ /* When MPPC/MPPE is in use, we shouldn't receive any CCP Reset-Ack.
++ But when we receive such a packet, we just ignore it. */
++ return;
++}
++
++static void
++mppe_stats(void *arg, struct compstat *stats)
++{
++ struct ppp_mppe_state *state = (struct ppp_mppe_state *)arg;
++
++ *stats = state->stats;
++}
++
++/***************************/
++/**** Compression stuff ****/
++/***************************/
++/* inserts 1 to 8 bits into the output buffer */
++static inline void putbits8(u8 *buf, u32 val, const u32 n, u32 *i, u32 *l)
++{
++ buf += *i;
++ if (*l >= n) {
++ *l = (*l) - n;
++ val <<= *l;
++ *buf = *buf | (val & 0xff);
++ if (*l == 0) {
++ *l = 8;
++ (*i)++;
++ *(++buf) = 0;
++ }
++ } else {
++ (*i)++;
++ *l = 8 - n + (*l);
++ val <<= *l;
++ *buf = *buf | ((val >> 8) & 0xff);
++ *(++buf) = val & 0xff;
++ }
++}
++
++/* inserts 9 to 16 bits into the output buffer */
++static inline void putbits16(u8 *buf, u32 val, const u32 n, u32 *i, u32 *l)
++{
++ buf += *i;
++ if (*l >= n - 8) {
++ (*i)++;
++ *l = 8 - n + (*l);
++ val <<= *l;
++ *buf = *buf | ((val >> 8) & 0xff);
++ *(++buf) = val & 0xff;
++ if (*l == 0) {
++ *l = 8;
++ (*i)++;
++ *(++buf) = 0;
++ }
++ } else {
++ (*i)++; (*i)++;
++ *l = 16 - n + (*l);
++ val <<= *l;
++ *buf = *buf | ((val >> 16) & 0xff);
++ *(++buf) = (val >> 8) & 0xff;
++ *(++buf) = val & 0xff;
++ }
++}
++
++/* inserts 17 to 24 bits into the output buffer */
++static inline void putbits24(u8 *buf, u32 val, const u32 n, u32 *i, u32 *l)
++{
++ buf += *i;
++ if (*l >= n - 16) {
++ (*i)++; (*i)++;
++ *l = 16 - n + (*l);
++ val <<= *l;
++ *buf = *buf | ((val >> 16) & 0xff);
++ *(++buf) = (val >> 8) & 0xff;
++ *(++buf) = val & 0xff;
++ if (*l == 0) {
++ *l = 8;
++ (*i)++;
++ *(++buf) = 0;
++ }
++ } else {
++ (*i)++; (*i)++; (*i)++;
++ *l = 24 - n + (*l);
++ val <<= *l;
++ *buf = *buf | ((val >> 24) & 0xff);
++ *(++buf) = (val >> 16) & 0xff;
++ *(++buf) = (val >> 8) & 0xff;
++ *(++buf) = val & 0xff;
++ }
++}
++
++static int
++mppc_compress(struct ppp_mppe_state *state, unsigned char *ibuf,
++ unsigned char *obuf, int isize, int osize)
++{
++ u32 olen, off, len, idx, i, l;
++ u8 *hist, *sbuf, *p, *q, *r, *s;
++
++ /*
++ At this point, to avoid possible buffer overflow caused by packet
++ expansion during/after compression, we should make sure that
++ osize >= (((isize*9)/8)+1)+2, but we don't do that because in
++ ppp_generic.c we simply allocate bigger obuf.
++
++ Maximum MPPC packet expansion is 12.5%. This is the worst case when
++ all octets in the input buffer are >= 0x80 and we cannot find any
++ repeated tokens. Additionally we have to reserve 2 bytes for MPPE/MPPC
++ status bits and coherency counter.
++ */
++
++ hist = state->hist + MPPE_HIST_LEN;
++ /* check if there is enough room at the end of the history */
++ if (state->histptr + isize >= 2*MPPE_HIST_LEN) {
++ state->bits |= MPPE_BIT_RESET;
++ state->histptr = MPPE_HIST_LEN;
++ memcpy(state->hist, hist, MPPE_HIST_LEN);
++ }
++ /* add packet to the history; isize must be <= MPPE_HIST_LEN */
++ sbuf = state->hist + state->histptr;
++ memcpy(sbuf, ibuf, isize);
++ state->histptr += isize;
++
++ /* compress data */
++ r = sbuf + isize;
++ *obuf = olen = i = 0;
++ l = 8;
++ while (i < isize - 2) {
++ s = q = sbuf + i;
++ idx = ((40543*((((s[0]<<4)^s[1])<<4)^s[2]))>>4) & 0x1fff;
++ p = hist + state->hash[idx];
++ state->hash[idx] = (u16) (s - hist);
++ off = s - p;
++ if (off > MPPE_HIST_LEN - 1 || off < 1 || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++) {
++ /* no match found; encode literal byte */
++ if (ibuf[i] < 0x80) { /* literal byte < 0x80 */
++ putbits8(obuf, (u32) ibuf[i], 8, &olen, &l);
++ } else { /* literal byte >= 0x80 */
++ putbits16(obuf, (u32) (0x100|(ibuf[i]&0x7f)), 9, &olen, &l);
++ }
++ ++i;
++ continue;
++ }
++ if (r - q >= 64) {
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++ || *p++ != *s++ || *p++ != *s++ || *p++ != *s++ ||
++ *p++ != *s++;
++ if (s - q == 64) {
++ p--; s--;
++ while((*p++ == *s++) && (s < r) && (p < q));
++ }
++ } else {
++ while((*p++ == *s++) && (s < r) && (p < q));
++ }
++ len = s - q - 1;
++ i += len;
++
++ /* at least 3 character match found; code data */
++ /* encode offset */
++ if (off < 64) { /* 10-bit offset; 0 <= offset < 64 */
++ putbits16(obuf, 0x3c0|off, 10, &olen, &l);
++ } else if (off < 320) { /* 12-bit offset; 64 <= offset < 320 */
++ putbits16(obuf, 0xe00|(off-64), 12, &olen, &l);
++ } else if (off < 8192) { /* 16-bit offset; 320 <= offset < 8192 */
++ putbits16(obuf, 0xc000|(off-320), 16, &olen, &l);
++ } else {
++ /* This shouldn't happen; we return 0 what means "packet expands",
++ and we send packet uncompressed. */
++ if (state->debug)
++ printk(KERN_DEBUG "%s%d: wrong offset value: %d\n",
++ __FUNCTION__, state->unit, off);
++ return 0;
++ }
++ /* encode length of match */
++ if (len < 4) { /* length = 3 */
++ putbits8(obuf, 0, 1, &olen, &l);
++ } else if (len < 8) { /* 4 <= length < 8 */
++ putbits8(obuf, 0x08|(len&0x03), 4, &olen, &l);
++ } else if (len < 16) { /* 8 <= length < 16 */
++ putbits8(obuf, 0x30|(len&0x07), 6, &olen, &l);
++ } else if (len < 32) { /* 16 <= length < 32 */
++ putbits8(obuf, 0xe0|(len&0x0f), 8, &olen, &l);
++ } else if (len < 64) { /* 32 <= length < 64 */
++ putbits16(obuf, 0x3c0|(len&0x1f), 10, &olen, &l);
++ } else if (len < 128) { /* 64 <= length < 128 */
++ putbits16(obuf, 0xf80|(len&0x3f), 12, &olen, &l);
++ } else if (len < 256) { /* 128 <= length < 256 */
++ putbits16(obuf, 0x3f00|(len&0x7f), 14, &olen, &l);
++ } else if (len < 512) { /* 256 <= length < 512 */
++ putbits16(obuf, 0xfe00|(len&0xff), 16, &olen, &l);
++ } else if (len < 1024) { /* 512 <= length < 1024 */
++ putbits24(obuf, 0x3fc00|(len&0x1ff), 18, &olen, &l);
++ } else if (len < 2048) { /* 1024 <= length < 2048 */
++ putbits24(obuf, 0xff800|(len&0x3ff), 20, &olen, &l);
++ } else if (len < 4096) { /* 2048 <= length < 4096 */
++ putbits24(obuf, 0x3ff000|(len&0x7ff), 22, &olen, &l);
++ } else if (len < 8192) { /* 4096 <= length < 8192 */
++ putbits24(obuf, 0xffe000|(len&0xfff), 24, &olen, &l);
++ } else {
++ /* This shouldn't happen; we return 0 what means "packet expands",
++ and send packet uncompressed. */
++ if (state->debug)
++ printk(KERN_DEBUG "%s%d: wrong length of match value: %d\n",
++ __FUNCTION__, state->unit, len);
++ return 0;
++ }
++ }
++
++ /* Add remaining octets to the output */
++ while(isize - i > 0) {
++ if (ibuf[i] < 0x80) { /* literal byte < 0x80 */
++ putbits8(obuf, (u32) ibuf[i++], 8, &olen, &l);
++ } else { /* literal byte >= 0x80 */
++ putbits16(obuf, (u32) (0x100|(ibuf[i++]&0x7f)), 9, &olen, &l);
++ }
++ }
++ /* Reset unused bits of the last output octet */
++ if ((l != 0) && (l != 8)) {
++ putbits8(obuf, 0, l, &olen, &l);
++ }
++
++ return (int) olen;
++}
++
++int
++mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
++ int isize, int osize)
++{
++ struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
++ int proto, olen, complen, off;
++ unsigned char *wptr;
++
++ /* Check that the protocol is in the range we handle. */
++ proto = PPP_PROTOCOL(ibuf);
++ if (proto < 0x0021 || proto > 0x00fa)
++ return 0;
++
++ wptr = obuf;
++ /* Copy over the PPP header */
++ wptr[0] = PPP_ADDRESS(ibuf);
++ wptr[1] = PPP_CONTROL(ibuf);
++ wptr[2] = PPP_COMP >> 8;
++ wptr[3] = PPP_COMP;
++ wptr += PPP_HDRLEN + (MPPE_OVHD / 2); /* Leave two octets for MPPE/MPPC bits */
++
++ /*
++ * In ver. 0.99 protocol field was compressed. Deflate and BSD compress
++ * do PFC before actual compression, RCF2118 and RFC3078 are not precise
++ * on this topic so I decided to do PFC. Unfortunately this change caused
++ * incompatibility with older/other MPPE/MPPC modules. I have received
++ * a lot of complaints from unexperienced users so I have decided to revert
++ * to previous state, i.e. the protocol field is sent uncompressed now.
++ * Although this may be changed in the future.
++ *
++ * Receiving side (mppe_decompress()) still accepts packets with compressed
++ * and uncompressed protocol field so you shouldn't get "Unsupported protocol
++ * 0x2145 received" messages anymore.
++ */
++ //off = (proto > 0xff) ? 2 : 3; /* PFC - skip first protocol byte if 0 */
++ off = 2;
++
++ ibuf += off;
++
++ mppe_increase_ccount(state);
++
++ if (state->nextflushed) {
++ state->bits |= MPPE_BIT_FLUSHED;
++ state->nextflushed = 0;
++ if (state->mppe && !state->stateless) {
++ /*
++ * If this is the flag packet, the key has been already changed in
++ * mppe_increase_ccount() so we dont't do it once again.
++ */
++ if ((state->ccount & 0xff) != 0xff) {
++ arc4_setkey(state, state->session_key, state->keylen);
++ }
++ }
++ if (state->mppc) { /* reset history */
++ state->bits |= MPPE_BIT_RESET;
++ state->histptr = MPPE_HIST_LEN;
++ memset(state->hist + MPPE_HIST_LEN, 0, MPPE_HIST_LEN*sizeof(u8));
++ }
++ }
++
++ if (state->mppc && !state->mppe) { /* Do only compression */
++ complen = mppc_compress(state, ibuf, wptr, isize - off,
++ osize - PPP_HDRLEN - (MPPE_OVHD / 2));
++ /*
++ * TODO: Implement an heuristics to handle packet expansion in a smart
++ * way. Now, when a packet expands, we send it as uncompressed and
++ * when next packet is sent we have to reset compressor's history.
++ * Maybe it would be better to send such packet as compressed in order
++ * to keep history's continuity.
++ */
++ if ((complen > isize) || (complen > osize - PPP_HDRLEN) ||
++ (complen == 0)) {
++ /* packet expands */
++ state->nextflushed = 1;
++ memcpy(wptr, ibuf, isize - off);
++ olen = isize - (off - 2) + MPPE_OVHD;
++ (state->stats).inc_bytes += olen;
++ (state->stats).inc_packets++;
++ } else {
++ state->bits |= MPPE_BIT_COMP;
++ olen = complen + PPP_HDRLEN + (MPPE_OVHD / 2);
++ (state->stats).comp_bytes += olen;
++ (state->stats).comp_packets++;
++ }
++ } else { /* Do encryption with or without compression */
++ state->bits |= MPPE_BIT_ENCRYPTED;
++ if (!state->mppc && state->mppe) { /* Do only encryption */
++ /* read from ibuf, write to wptr, adjust for PPP_HDRLEN */
++ arc4_encrypt(state, ibuf, isize - off, wptr);
++ olen = isize - (off - 2) + MPPE_OVHD;
++ (state->stats).inc_bytes += olen;
++ (state->stats).inc_packets++;
++ } else { /* Do compression and then encryption - RFC3078 */
++ complen = mppc_compress(state, ibuf, wptr, isize - off,
++ osize - PPP_HDRLEN - (MPPE_OVHD / 2));
++ /*
++ * TODO: Implement an heuristics to handle packet expansion in a smart
++ * way. Now, when a packet expands, we send it as uncompressed and
++ * when next packet is sent we have to reset compressor's history.
++ * Maybe it would be good to send such packet as compressed in order
++ * to keep history's continuity.
++ */
++ if ((complen > isize) || (complen > osize - PPP_HDRLEN) ||
++ (complen == 0)) {
++ /* packet expands */
++ state->nextflushed = 1;
++ arc4_encrypt(state, ibuf, isize - off, wptr);
++ olen = isize - (off - 2) + MPPE_OVHD;
++ (state->stats).inc_bytes += olen;
++ (state->stats).inc_packets++;
++ } else {
++ state->bits |= MPPE_BIT_COMP;
++ /* Hack warning !!! RC4 implementation which we use does
++ encryption "in place" - it means that input and output
++ buffers can be *the same* memory area. Therefore we don't
++ need to use a temporary buffer. But be careful - other
++ implementations don't have to be so nice.
++ I used to use ibuf as temporary buffer here, but it led
++ packet sniffers into error. Thanks to Wilfried Weissmann
++ for pointing that. */
++ arc4_encrypt(state, wptr, complen, wptr);
++ olen = complen + PPP_HDRLEN + (MPPE_OVHD / 2);
++ (state->stats).comp_bytes += olen;
++ (state->stats).comp_packets++;
++ }
++ }
++ }
++
++ /* write status bits and coherency counter into the output buffer */
++ wptr = obuf + PPP_HDRLEN;
++ wptr[0] = MPPE_CTRLHI(state);
++ wptr[1] = MPPE_CTRLLO(state);
++
++ state->bits = 0;
++
++ (state->stats).unc_bytes += isize;
++ (state->stats).unc_packets++;
++
++ return olen;
++}
++
++/***************************/
++/*** Decompression stuff ***/
++/***************************/
++static inline u32 getbits(const u8 *buf, const u32 n, u32 *i, u32 *l)
++{
++ static const u32 m[] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
++ u32 res, ol;
++
++ ol = *l;
++ if (*l >= n) {
++ *l = (*l) - n;
++ res = (buf[*i] & m[ol]) >> (*l);
++ if (*l == 0) {
++ *l = 8;
++ (*i)++;
++ }
++ } else {
++ *l = 8 - n + (*l);
++ res = (buf[(*i)++] & m[ol]) << 8;
++ res = (res | buf[*i]) >> (*l);
++ }
++
++ return res;
++}
++
++static inline u32 getbyte(const u8 *buf, const u32 i, const u32 l)
++{
++ if (l == 8) {
++ return buf[i];
++ } else {
++ return (((buf[i] << 8) | buf[i+1]) >> l) & 0xff;
++ }
++}
++
++static inline void lamecopy(u8 *dst, u8 *src, u32 len)
++{
++ while (len--)
++ *dst++ = *src++;
++}
++
++static int
++mppc_decompress(struct ppp_mppe_state *state, unsigned char *ibuf,
++ unsigned char *obuf, int isize, int osize)
++{
++ u32 olen, off, len, bits, val, sig, i, l;
++ u8 *history, *s;
++
++ history = state->hist + state->histptr;
++ olen = len = i = 0;
++ l = 8;
++ bits = isize * 8;
++ while (bits >= 8) {
++ val = getbyte(ibuf, i++, l);
++ if (val < 0x80) { /* literal byte < 0x80 */
++ if (state->histptr < 2*MPPE_HIST_LEN) {
++ /* copy uncompressed byte to the history */
++ (state->hist)[(state->histptr)++] = (u8) val;
++ } else {
++ /* buffer overflow; drop packet */
++ if (state->debug)
++ printk(KERN_ERR "%s%d: trying to write outside history "
++ "buffer\n", __FUNCTION__, state->unit);
++ return DECOMP_ERROR;
++ }
++ olen++;
++ bits -= 8;
++ continue;
++ }
++
++ sig = val & 0xc0;
++ if (sig == 0x80) { /* literal byte >= 0x80 */
++ if (state->histptr < 2*MPPE_HIST_LEN) {
++ /* copy uncompressed byte to the history */
++ (state->hist)[(state->histptr)++] =
++ (u8) (0x80|((val&0x3f)<<1)|getbits(ibuf, 1 , &i ,&l));
++ } else {
++ /* buffer overflow; drop packet */
++ if (state->debug)
++ printk(KERN_ERR "%s%d: trying to write outside history "
++ "buffer\n", __FUNCTION__, state->unit);
++ return DECOMP_ERROR;
++ }
++ olen++;
++ bits -= 9;
++ continue;
++ }
++
++ /* Not a literal byte so it must be an (offset,length) pair */
++ /* decode offset */
++ sig = val & 0xf0;
++ if (sig == 0xf0) { /* 10-bit offset; 0 <= offset < 64 */
++ off = (((val&0x0f)<<2)|getbits(ibuf, 2 , &i ,&l));
++ bits -= 10;
++ } else {
++ if (sig == 0xe0) { /* 12-bit offset; 64 <= offset < 320 */
++ off = ((((val&0x0f)<<4)|getbits(ibuf, 4 , &i ,&l))+64);
++ bits -= 12;
++ } else {
++ if ((sig&0xe0) == 0xc0) {/* 16-bit offset; 320 <= offset < 8192 */
++ off = ((((val&0x1f)<<8)|getbyte(ibuf, i++, l))+320);
++ bits -= 16;
++ if (off > MPPE_HIST_LEN - 1) {
++ if (state->debug)
++ printk(KERN_DEBUG "%s%d: too big offset value: %d\n",
++ __FUNCTION__, state->unit, off);
++ return DECOMP_ERROR;
++ }
++ } else { /* this shouldn't happen */
++ if (state->debug)
++ printk(KERN_DEBUG "%s%d: cannot decode offset value\n",
++ __FUNCTION__, state->unit);
++ return DECOMP_ERROR;
++ }
++ }
++ }
++ /* decode length of match */
++ val = getbyte(ibuf, i, l);
++ if ((val & 0x80) == 0x00) { /* len = 3 */
++ len = 3;
++ bits--;
++ getbits(ibuf, 1 , &i ,&l);
++ } else if ((val & 0xc0) == 0x80) { /* 4 <= len < 8 */
++ len = 0x04 | ((val>>4) & 0x03);
++ bits -= 4;
++ getbits(ibuf, 4 , &i ,&l);
++ } else if ((val & 0xe0) == 0xc0) { /* 8 <= len < 16 */
++ len = 0x08 | ((val>>2) & 0x07);
++ bits -= 6;
++ getbits(ibuf, 6 , &i ,&l);
++ } else if ((val & 0xf0) == 0xe0) { /* 16 <= len < 32 */
++ len = 0x10 | (val & 0x0f);
++ bits -= 8;
++ i++;
++ } else {
++ bits -= 8;
++ val = (val << 8) | getbyte(ibuf, ++i, l);
++ if ((val & 0xf800) == 0xf000) { /* 32 <= len < 64 */
++ len = 0x0020 | ((val >> 6) & 0x001f);
++ bits -= 2;
++ getbits(ibuf, 2 , &i ,&l);
++ } else if ((val & 0xfc00) == 0xf800) { /* 64 <= len < 128 */
++ len = 0x0040 | ((val >> 4) & 0x003f);
++ bits -= 4;
++ getbits(ibuf, 4 , &i ,&l);
++ } else if ((val & 0xfe00) == 0xfc00) { /* 128 <= len < 256 */
++ len = 0x0080 | ((val >> 2) & 0x007f);
++ bits -= 6;
++ getbits(ibuf, 6 , &i ,&l);
++ } else if ((val & 0xff00) == 0xfe00) { /* 256 <= len < 512 */
++ len = 0x0100 | (val & 0x00ff);
++ bits -= 8;
++ i++;
++ } else {
++ bits -= 8;
++ val = (val << 8) | getbyte(ibuf, ++i, l);
++ if ((val & 0xff8000) == 0xff0000) { /* 512 <= len < 1024 */
++ len = 0x000200 | ((val >> 6) & 0x0001ff);
++ bits -= 2;
++ getbits(ibuf, 2 , &i ,&l);
++ } else if ((val & 0xffc000) == 0xff8000) {/* 1024 <= len < 2048 */
++ len = 0x000400 | ((val >> 4) & 0x0003ff);
++ bits -= 4;
++ getbits(ibuf, 4 , &i ,&l);
++ } else if ((val & 0xffe000) == 0xffc000) {/* 2048 <= len < 4096 */
++ len = 0x000800 | ((val >> 2) & 0x0007ff);
++ bits -= 6;
++ getbits(ibuf, 6 , &i ,&l);
++ } else if ((val & 0xfff000) == 0xffe000) {/* 4096 <= len < 8192 */
++ len = 0x001000 | (val & 0x000fff);
++ bits -= 8;
++ i++;
++ } else { /* this shouldn't happen */
++ if (state->debug)
++ printk(KERN_DEBUG "%s%d: wrong length code: 0x%X\n",
++ __FUNCTION__, state->unit, val);
++ return DECOMP_ERROR;
++ }
++ }
++ }
++ s = state->hist + state->histptr;
++ state->histptr += len;
++ olen += len;
++ if (state->histptr < 2*MPPE_HIST_LEN) {
++ /* copy uncompressed bytes to the history */
++
++ /* In some cases len may be greater than off. It means that memory
++ * areas pointed by s and s-off overlap. I had used memmove() here
++ * because I thought that it acts as libc's version. Unfortunately,
++ * I was wrong. :-) I got strange errors sometimes. Wilfried suggested
++ * using of byte by byte copying here and strange errors disappeared.
++ */
++ lamecopy(s, s - off, len);
++ } else {
++ /* buffer overflow; drop packet */
++ if (state->debug)
++ printk(KERN_ERR "%s%d: trying to write outside history "
++ "buffer\n", __FUNCTION__, state->unit);
++ return DECOMP_ERROR;
++ }
++ }
++
++ /* Do PFC decompression */
++ len = olen;
++ if ((history[0] & 0x01) != 0) {
++ obuf[0] = 0;
++ obuf++;
++ len++;
++ }
++
++ if (len <= osize) {
++ /* copy uncompressed packet to the output buffer */
++ memcpy(obuf, history, olen);
++ } else {
++ /* buffer overflow; drop packet */
++ if (state->debug)
++ printk(KERN_ERR "%s%d: too big uncompressed packet: %d\n",
++ __FUNCTION__, state->unit, len + (PPP_HDRLEN / 2));
++ return DECOMP_ERROR;
++ }
++
++ return (int) len;
++}
++
++int
++mppe_decompress(void *arg, unsigned char *ibuf, int isize,
++ unsigned char *obuf, int osize)
++{
++ struct ppp_mppe_state *state = (struct ppp_mppe_state *)arg;
++ int seq, bits, uncomplen;
++
++ if (isize <= PPP_HDRLEN + MPPE_OVHD) {
++ if (state->debug) {
++ printk(KERN_DEBUG "%s%d: short packet (len=%d)\n", __FUNCTION__,
++ state->unit, isize);
++ }
++ return DECOMP_ERROR;
++ }
++
++ /* Get coherency counter and control bits from input buffer */
++ seq = MPPE_CCOUNT(ibuf);
++ bits = MPPE_BITS(ibuf);
++
++ if (state->stateless) {
++ /* RFC 3078, sec 8.1. */
++ mppe_increase_ccount(state);
++ if ((seq != state->ccount) && state->debug)
++ printk(KERN_DEBUG "%s%d: bad sequence number: %d, expected: %d\n",
++ __FUNCTION__, state->unit, seq, state->ccount);
++ while (seq != state->ccount)
++ mppe_increase_ccount(state);
++ } else {
++ /* RFC 3078, sec 8.2. */
++ if (state->flushexpected) { /* discard state */
++ if ((bits & MPPE_BIT_FLUSHED)) { /* we received expected FLUSH bit */
++ while (seq != state->ccount)
++ mppe_increase_ccount(state);
++ state->flushexpected = 0;
++ } else /* drop packet*/
++ return DECOMP_ERROR;
++ } else { /* normal state */
++ mppe_increase_ccount(state);
++ if (seq != state->ccount) {
++ /* Packet loss detected, enter the discard state. */
++ if (state->debug)
++ printk(KERN_DEBUG "%s%d: bad sequence number: %d, expected: %d\n",
++ __FUNCTION__, state->unit, seq, state->ccount);
++ state->flushexpected = 1;
++ return DECOMP_ERROR;
++ }
++ }
++ if (state->mppe && (bits & MPPE_BIT_FLUSHED)) {
++ arc4_setkey(state, state->session_key, state->keylen);
++ }
++ }
++
++ if (state->mppc && (bits & (MPPE_BIT_FLUSHED | MPPE_BIT_RESET))) {
++ state->histptr = MPPE_HIST_LEN;
++ if ((bits & MPPE_BIT_FLUSHED)) {
++ memset(state->hist + MPPE_HIST_LEN, 0, MPPE_HIST_LEN*sizeof(u8));
++ } else
++ if ((bits & MPPE_BIT_RESET)) {
++ memcpy(state->hist, state->hist + MPPE_HIST_LEN, MPPE_HIST_LEN);
++ }
++ }
++
++ /* Fill in the first part of the PPP header. The protocol field
++ comes from the decompressed data. */
++ obuf[0] = PPP_ADDRESS(ibuf);
++ obuf[1] = PPP_CONTROL(ibuf);
++ obuf += PPP_HDRLEN / 2;
++
++ if (state->mppe) { /* process encrypted packet */
++ if ((bits & MPPE_BIT_ENCRYPTED)) {
++ /* OK, packet encrypted, so decrypt it */
++ if (state->mppc && (bits & MPPE_BIT_COMP)) {
++ /* Hack warning !!! RC4 implementation which we use does
++ decryption "in place" - it means that input and output
++ buffers can be *the same* memory area. Therefore we don't
++ need to use a temporary buffer. But be careful - other
++ implementations don't have to be so nice. */
++ arc4_decrypt(state, ibuf + PPP_HDRLEN + (MPPE_OVHD / 2), isize -
++ PPP_HDRLEN - (MPPE_OVHD / 2), ibuf + PPP_HDRLEN +
++ (MPPE_OVHD / 2));
++ uncomplen = mppc_decompress(state, ibuf + PPP_HDRLEN +
++ (MPPE_OVHD / 2), obuf, isize -
++ PPP_HDRLEN - (MPPE_OVHD / 2),
++ osize - (PPP_HDRLEN / 2));
++ if (uncomplen == DECOMP_ERROR) {
++ state->flushexpected = 1;
++ return DECOMP_ERROR;
++ }
++ uncomplen += PPP_HDRLEN / 2;
++ (state->stats).comp_bytes += isize;
++ (state->stats).comp_packets++;
++ } else {
++ uncomplen = isize - MPPE_OVHD;
++ /* Decrypt the first byte in order to check if it is
++ compressed or uncompressed protocol field */
++ arc4_decrypt(state, ibuf + PPP_HDRLEN + (MPPE_OVHD / 2), 1, obuf);
++ /* Do PFC decompression */
++ if ((obuf[0] & 0x01) != 0) {
++ obuf[1] = obuf[0];
++ obuf[0] = 0;
++ obuf++;
++ uncomplen++;
++ }
++ /* And finally, decrypt the rest of the frame. */
++ arc4_decrypt(state, ibuf + PPP_HDRLEN + (MPPE_OVHD / 2) + 1,
++ isize - PPP_HDRLEN - (MPPE_OVHD / 2) - 1, obuf + 1);
++ (state->stats).inc_bytes += isize;
++ (state->stats).inc_packets++;
++ }
++ } else { /* this shouldn't happen */
++ if (state->debug)
++ printk(KERN_ERR "%s%d: encryption negotiated but not an "
++ "encrypted packet received\n", __FUNCTION__, state->unit);
++ mppe_change_key(state, 0);
++ state->flushexpected = 1;
++ return DECOMP_ERROR;
++ }
++ } else {
++ if (state->mppc) { /* no MPPE, only MPPC */
++ if ((bits & MPPE_BIT_COMP)) {
++ uncomplen = mppc_decompress(state, ibuf + PPP_HDRLEN +
++ (MPPE_OVHD / 2), obuf, isize -
++ PPP_HDRLEN - (MPPE_OVHD / 2),
++ osize - (PPP_HDRLEN / 2));
++ if (uncomplen == DECOMP_ERROR) {
++ state->flushexpected = 1;
++ return DECOMP_ERROR;
++ }
++ uncomplen += PPP_HDRLEN / 2;
++ (state->stats).comp_bytes += isize;
++ (state->stats).comp_packets++;
++ } else {
++ memcpy(obuf, ibuf + PPP_HDRLEN + (MPPE_OVHD / 2), isize -
++ PPP_HDRLEN - (MPPE_OVHD / 2));
++ uncomplen = isize - MPPE_OVHD;
++ (state->stats).inc_bytes += isize;
++ (state->stats).inc_packets++;
++ }
++ } else { /* this shouldn't happen */
++ if (state->debug)
++ printk(KERN_ERR "%s%d: error - not an MPPC or MPPE frame "
++ "received\n", __FUNCTION__, state->unit);
++ state->flushexpected = 1;
++ return DECOMP_ERROR;
++ }
++ }
++
++ (state->stats).unc_bytes += uncomplen;
++ (state->stats).unc_packets++;
++
++ return uncomplen;
++}
++
++
++/************************************************************
++ * Module interface table
++ ************************************************************/
++
++/* These are in ppp_generic.c */
++extern int ppp_register_compressor (struct compressor *cp);
++extern void ppp_unregister_compressor (struct compressor *cp);
++
++/*
++ * Functions exported to ppp_generic.c.
++ *
++ * In case of MPPC/MPPE there is no need to process incompressible data
++ * because such a data is sent in MPPC/MPPE frame. Therefore the (*incomp)
++ * callback function isn't needed.
++ */
++struct compressor ppp_mppe = {
++ CI_MPPE, /* compress_proto */
++ mppe_comp_alloc, /* comp_alloc */
++ mppe_comp_free, /* comp_free */
++ mppe_comp_init, /* comp_init */
++ mppe_comp_reset, /* comp_reset */
++ mppe_compress, /* compress */
++ mppe_stats, /* comp_stat */
++ mppe_decomp_alloc, /* decomp_alloc */
++ mppe_comp_free, /* decomp_free */
++ mppe_decomp_init, /* decomp_init */
++ mppe_decomp_reset, /* decomp_reset */
++ mppe_decompress, /* decompress */
++ NULL, /* incomp */
++ mppe_stats, /* decomp_stat */
++};
++
++/************************************************************
++ * Module support routines
++ ************************************************************/
++
++int __init mppe_module_init(void)
++{
++ int answer;
++
++ /* When the module is compiled into kernel, it is initialized before
++ * CryptoAPI. Therefore the code below reports that there is no crypto
++ * stuff in the kernel. Marlon de Boer who has pointed out the problem,
++ * has sent also a message to CryptoAPI developers, so maybe in the future
++ * the code will be uncommented.
++ *
++ if (!(crypto_alg_available("arc4", 0) && crypto_alg_available("sha1", 0))) {
++ printk(KERN_ERR "Kernel doesn't provide ARC4 and/or SHA1 algorithms "
++ "required by MPPE/MPPC. Check CryptoAPI configuration.\n");
++ return -ENODEV;
++ }
++ */
++
++ /* Allocate space for SHAPad1, SHAPad2 and ... */
++ sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL);
++ if (sha_pad == NULL)
++ return -ENOMEM;
++ /* ... initialize them */
++ memset(sha_pad->sha_pad1, 0x00, sizeof(sha_pad->sha_pad1));
++ memset(sha_pad->sha_pad2, 0xf2, sizeof(sha_pad->sha_pad2));
++
++ answer = ppp_register_compressor(&ppp_mppe);
++ if (answer == 0) {
++ printk(KERN_INFO "MPPE/MPPC encryption/compression module registered\n");
++ }
++ return answer;
++}
++
++void __exit mppe_module_cleanup(void)
++{
++ kfree(sha_pad);
++ ppp_unregister_compressor(&ppp_mppe);
++ printk(KERN_INFO "MPPE/MPPC encryption/compression module unregistered\n");
++}
++
++module_init(mppe_module_init);
++module_exit(mppe_module_cleanup);
++
++MODULE_AUTHOR("Jan Dubiec <jdx@slackware.pl>");
++MODULE_DESCRIPTION("MPPE/MPPC encryption/compression module for Linux");
++MODULE_LICENSE("Dual BSD/GPL");
+diff -ruN linux-2.4.29.orig/include/linux/ppp-comp.h linux-2.4.29/include/linux/ppp-comp.h
+--- linux-2.4.29.orig/include/linux/ppp-comp.h 2005-02-02 22:18:25.000000000 +0100
++++ linux-2.4.29/include/linux/ppp-comp.h 2005-02-02 22:41:01.000000000 +0100
+@@ -28,7 +28,7 @@
+ */
+
+ /*
+- * ==FILEVERSION 980319==
++ * ==FILEVERSION 20040509==
+ *
+ * NOTE TO MAINTAINERS:
+ * If you modify this file at all, please set the above date.
+@@ -78,7 +78,7 @@
+
+ /* Compress a packet */
+ int (*compress) (void *state, unsigned char *rptr,
+- unsigned char *obuf, int isize, int osize);
++ unsigned char *obuf, int isize, int osize);
+
+ /* Return compression statistics */
+ void (*comp_stat) (void *state, struct compstat *stats);
+@@ -99,7 +99,7 @@
+
+ /* Decompress a packet. */
+ int (*decompress) (void *state, unsigned char *ibuf, int isize,
+- unsigned char *obuf, int osize);
++ unsigned char *obuf, int osize);
+
+ /* Update state for an incompressible packet received */
+ void (*incomp) (void *state, unsigned char *ibuf, int icnt);
+@@ -187,6 +187,42 @@
+ #define DEFLATE_CHK_SEQUENCE 0
+
+ /*
++ * Definitions for MPPE/MPPC.
++ */
++
++#define CI_MPPE 18 /* config option for MPPE */
++#define CILEN_MPPE 6 /* length of config option */
++
++#define MPPE_OVHD 4 /* MPPE overhead */
++#define MPPE_MAX_KEY_LEN 16 /* largest key length (128-bit) */
++
++#define MPPE_STATELESS 0x01 /* configuration bit H */
++#define MPPE_40BIT 0x20 /* configuration bit L */
++#define MPPE_56BIT 0x80 /* configuration bit M */
++#define MPPE_128BIT 0x40 /* configuration bit S */
++#define MPPE_MPPC 0x01 /* configuration bit C */
++
++/*
++ * Definitions for Stac LZS.
++ */
++
++#define CI_LZS 17 /* config option for Stac LZS */
++#define CILEN_LZS 5 /* length of config option */
++
++#define LZS_OVHD 4 /* max. LZS overhead */
++#define LZS_HIST_LEN 2048 /* LZS history size */
++#define LZS_MAX_CCOUNT 0x0FFF /* max. coherency counter value */
++
++#define LZS_MODE_NONE 0
++#define LZS_MODE_LCB 1
++#define LZS_MODE_CRC 2
++#define LZS_MODE_SEQ 3
++#define LZS_MODE_EXT 4
++
++#define LZS_EXT_BIT_FLUSHED 0x80 /* bit A */
++#define LZS_EXT_BIT_COMP 0x20 /* bit C */
++
++/*
+ * Definitions for other, as yet unsupported, compression methods.
+ */
+
diff --git a/target/linux/generic-2.4/patches/107-cifs.patch b/target/linux/generic-2.4/patches/107-cifs.patch
new file mode 100644
index 0000000..bdccf4d
--- /dev/null
+++ b/target/linux/generic-2.4/patches/107-cifs.patch
@@ -0,0 +1,22022 @@
+diff -urN linux-2.4.29.old/Documentation/Configure.help linux-2.4.29/Documentation/Configure.help
+--- linux-2.4.29.old/Documentation/Configure.help 2005-03-21 19:30:22.000000000 +0100
++++ linux-2.4.29/Documentation/Configure.help 2005-03-21 19:36:51.000000000 +0100
+@@ -17943,6 +17943,34 @@
+
+ If you don't know what all this is about, say N.
+
++CIFS (Common Internet File System) support
++CONFIG_CIFS
++ This is the client VFS module for the Common Internet File System
++ (CIFS) protocol which is the successor to the Server Message Block
++ (SMB) protocol, the native file sharing mechanism for most early
++ PC operating systems. CIFS is fully supported by current network
++ file servers such as Windows 2000, Windows 2003 (including
++ Windows XP) as well by Samba (which provides excellent CIFS
++ server support for Linux and many other operating systems).
++ The smbfs module should be used instead of this cifs module for
++ mounting to older SMB servers such as OS/2. The smbfs and cifs
++ modules can coexist and do not conflict.
++
++ The intent of this module is to provide the most advanced network
++ file system function for CIFS compliant servers, including better
++ POSIX compliance, secure per-user session establishment, high
++ performance safe distributed caching (oplock), optional packet
++ signing, Unicode support and other internationalization improvements
++ For more information see the project page at
++ http://us1.samba.org/samba/Linux_CIFS_client.html
++
++CIFS Debugging
++CONFIG_CIFS_DEBUG
++ If you are experiencing any problems with the CIFS filesystem, say
++ Y here. This will result in additional debugging messages to be
++ written to the system log. Under normal circumstances, this
++ results in very little overhead.
++
+ SMB file system support (to mount Windows shares etc.)
+ CONFIG_SMB_FS
+ SMB (Server Message Block) is the protocol Windows for Workgroups
+diff -urN linux-2.4.29.old/Documentation/filesystems/00-INDEX linux-2.4.29/Documentation/filesystems/00-INDEX
+--- linux-2.4.29.old/Documentation/filesystems/00-INDEX 2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.29/Documentation/filesystems/00-INDEX 2005-03-21 19:36:51.000000000 +0100
+@@ -10,6 +10,8 @@
+ - info for the BeOS file system (BFS)
+ bfs.txt
+ - info for the SCO UnixWare Boot Filesystem (BFS).
++cifs.txt
++ - info on the Common Internet File System (CIFS)
+ coda.txt
+ - description of the CODA filesystem.
+ cramfs.txt
+diff -urN linux-2.4.29.old/Documentation/filesystems/cifs.txt linux-2.4.29/Documentation/filesystems/cifs.txt
+--- linux-2.4.29.old/Documentation/filesystems/cifs.txt 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/Documentation/filesystems/cifs.txt 2005-03-21 19:36:51.000000000 +0100
+@@ -0,0 +1,51 @@
++ This is the client VFS module for the Common Internet File System
++ (CIFS) protocol which is the successor to the Server Message Block
++ (SMB) protocol, the native file sharing mechanism for most early
++ PC operating systems. CIFS is fully supported by current network
++ file servers such as Windows 2000, Windows 2003 (including
++ Windows XP) as well by Samba (which provides excellent CIFS
++ server support for Linux and many other operating systems), so
++ this network filesystem client can mount to a wide variety of
++ servers. The smbfs module should be used instead of this cifs module
++ for mounting to older SMB servers such as OS/2. The smbfs and cifs
++ modules can coexist and do not conflict. The CIFS VFS filesystem
++ module is designed to work well with servers that implement the
++ newer versions (dialects) of the SMB/CIFS protocol such as Samba,
++ the program written by Andrew Tridgell that turns any Unix host
++ into a SMB/CIFS file server.
++
++ The intent of this module is to provide the most advanced network
++ file system function for CIFS compliant servers, including better
++ POSIX compliance, secure per-user session establishment, high
++ performance safe distributed caching (oplock), optional packet
++ signing, large files, Unicode support and other internationalization
++ improvements. Since both Samba server and this filesystem client support
++ the CIFS Unix extensions, the combination can provide a reasonable
++ alternative to NFSv4 for fileserving in some Linux to Linux environments,
++ not just in Linux to Windows environments.
++
++ This filesystem has an optional mount utility (mount.cifs) that can
++ be obtained from the project page and installed in the path in the same
++ directory with the other mount helpers (such as mount.smbfs).
++ Mounting using the cifs filesystem without installing the mount helper
++ requires specifying the server's ip address.
++
++ For Linux 2.4:
++ mount //anything/here /mnt_target -o
++ user=username,pass=password,unc=//ip_address_of_server/sharename
++
++ For Linux 2.5:
++ mount //ip_address_of_server/sharename /mnt_target -o user=username, pass=password
++
++
++ For more information on the module see the project page at
++
++ http://us1.samba.org/samba/Linux_CIFS_client.html
++
++ For more information on CIFS see:
++
++ http://www.snia.org/tech_activities/CIFS
++
++ or the Samba site:
++
++ http://www.samba.org
+diff -urN linux-2.4.29.old/fs/cifs/asn1.c linux-2.4.29/fs/cifs/asn1.c
+--- linux-2.4.29.old/fs/cifs/asn1.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/asn1.c 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,614 @@
++/*
++ * The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in
++ * turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich
++ *
++ * Copyright (c) 2000 RP Internet (www.rpi.net.au).
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include "cifspdu.h"
++#include "cifsglob.h"
++#include "cifs_debug.h"
++
++/*****************************************************************************
++ *
++ * Basic ASN.1 decoding routines (gxsnmp author Dirk Wisse)
++ *
++ *****************************************************************************/
++
++/* Class */
++#define ASN1_UNI 0 /* Universal */
++#define ASN1_APL 1 /* Application */
++#define ASN1_CTX 2 /* Context */
++#define ASN1_PRV 3 /* Private */
++
++/* Tag */
++#define ASN1_EOC 0 /* End Of Contents or N/A */
++#define ASN1_BOL 1 /* Boolean */
++#define ASN1_INT 2 /* Integer */
++#define ASN1_BTS 3 /* Bit String */
++#define ASN1_OTS 4 /* Octet String */
++#define ASN1_NUL 5 /* Null */
++#define ASN1_OJI 6 /* Object Identifier */
++#define ASN1_OJD 7 /* Object Description */
++#define ASN1_EXT 8 /* External */
++#define ASN1_SEQ 16 /* Sequence */
++#define ASN1_SET 17 /* Set */
++#define ASN1_NUMSTR 18 /* Numerical String */
++#define ASN1_PRNSTR 19 /* Printable String */
++#define ASN1_TEXSTR 20 /* Teletext String */
++#define ASN1_VIDSTR 21 /* Video String */
++#define ASN1_IA5STR 22 /* IA5 String */
++#define ASN1_UNITIM 23 /* Universal Time */
++#define ASN1_GENTIM 24 /* General Time */
++#define ASN1_GRASTR 25 /* Graphical String */
++#define ASN1_VISSTR 26 /* Visible String */
++#define ASN1_GENSTR 27 /* General String */
++
++/* Primitive / Constructed methods*/
++#define ASN1_PRI 0 /* Primitive */
++#define ASN1_CON 1 /* Constructed */
++
++/*
++ * Error codes.
++ */
++#define ASN1_ERR_NOERROR 0
++#define ASN1_ERR_DEC_EMPTY 2
++#define ASN1_ERR_DEC_EOC_MISMATCH 3
++#define ASN1_ERR_DEC_LENGTH_MISMATCH 4
++#define ASN1_ERR_DEC_BADVALUE 5
++
++#define SPNEGO_OID_LEN 7
++#define NTLMSSP_OID_LEN 10
++unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 };
++unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 };
++
++/*
++ * ASN.1 context.
++ */
++struct asn1_ctx {
++ int error; /* Error condition */
++ unsigned char *pointer; /* Octet just to be decoded */
++ unsigned char *begin; /* First octet */
++ unsigned char *end; /* Octet after last octet */
++};
++
++/*
++ * Octet string (not null terminated)
++ */
++struct asn1_octstr {
++ unsigned char *data;
++ unsigned int len;
++};
++
++static void
++asn1_open(struct asn1_ctx *ctx, unsigned char *buf, unsigned int len)
++{
++ ctx->begin = buf;
++ ctx->end = buf + len;
++ ctx->pointer = buf;
++ ctx->error = ASN1_ERR_NOERROR;
++}
++
++static unsigned char
++asn1_octet_decode(struct asn1_ctx *ctx, unsigned char *ch)
++{
++ if (ctx->pointer >= ctx->end) {
++ ctx->error = ASN1_ERR_DEC_EMPTY;
++ return 0;
++ }
++ *ch = *(ctx->pointer)++;
++ return 1;
++}
++
++static unsigned char
++asn1_tag_decode(struct asn1_ctx *ctx, unsigned int *tag)
++{
++ unsigned char ch;
++
++ *tag = 0;
++
++ do {
++ if (!asn1_octet_decode(ctx, &ch))
++ return 0;
++ *tag <<= 7;
++ *tag |= ch & 0x7F;
++ } while ((ch & 0x80) == 0x80);
++ return 1;
++}
++
++static unsigned char
++asn1_id_decode(struct asn1_ctx *ctx,
++ unsigned int *cls, unsigned int *con, unsigned int *tag)
++{
++ unsigned char ch;
++
++ if (!asn1_octet_decode(ctx, &ch))
++ return 0;
++
++ *cls = (ch & 0xC0) >> 6;
++ *con = (ch & 0x20) >> 5;
++ *tag = (ch & 0x1F);
++
++ if (*tag == 0x1F) {
++ if (!asn1_tag_decode(ctx, tag))
++ return 0;
++ }
++ return 1;
++}
++
++static unsigned char
++asn1_length_decode(struct asn1_ctx *ctx, unsigned int *def, unsigned int *len)
++{
++ unsigned char ch, cnt;
++
++ if (!asn1_octet_decode(ctx, &ch))
++ return 0;
++
++ if (ch == 0x80)
++ *def = 0;
++ else {
++ *def = 1;
++
++ if (ch < 0x80)
++ *len = ch;
++ else {
++ cnt = (unsigned char) (ch & 0x7F);
++ *len = 0;
++
++ while (cnt > 0) {
++ if (!asn1_octet_decode(ctx, &ch))
++ return 0;
++ *len <<= 8;
++ *len |= ch;
++ cnt--;
++ }
++ }
++ }
++ return 1;
++}
++
++static unsigned char
++asn1_header_decode(struct asn1_ctx *ctx,
++ unsigned char **eoc,
++ unsigned int *cls, unsigned int *con, unsigned int *tag)
++{
++ unsigned int def, len;
++
++ if (!asn1_id_decode(ctx, cls, con, tag))
++ return 0;
++
++ if (!asn1_length_decode(ctx, &def, &len))
++ return 0;
++
++ if (def)
++ *eoc = ctx->pointer + len;
++ else
++ *eoc = NULL;
++ return 1;
++}
++
++static unsigned char
++asn1_eoc_decode(struct asn1_ctx *ctx, unsigned char *eoc)
++{
++ unsigned char ch;
++
++ if (eoc == 0) {
++ if (!asn1_octet_decode(ctx, &ch))
++ return 0;
++
++ if (ch != 0x00) {
++ ctx->error = ASN1_ERR_DEC_EOC_MISMATCH;
++ return 0;
++ }
++
++ if (!asn1_octet_decode(ctx, &ch))
++ return 0;
++
++ if (ch != 0x00) {
++ ctx->error = ASN1_ERR_DEC_EOC_MISMATCH;
++ return 0;
++ }
++ return 1;
++ } else {
++ if (ctx->pointer != eoc) {
++ ctx->error = ASN1_ERR_DEC_LENGTH_MISMATCH;
++ return 0;
++ }
++ return 1;
++ }
++}
++
++/* static unsigned char asn1_null_decode(struct asn1_ctx *ctx,
++ unsigned char *eoc)
++{
++ ctx->pointer = eoc;
++ return 1;
++}
++
++static unsigned char asn1_long_decode(struct asn1_ctx *ctx,
++ unsigned char *eoc, long *integer)
++{
++ unsigned char ch;
++ unsigned int len;
++
++ if (!asn1_octet_decode(ctx, &ch))
++ return 0;
++
++ *integer = (signed char) ch;
++ len = 1;
++
++ while (ctx->pointer < eoc) {
++ if (++len > sizeof(long)) {
++ ctx->error = ASN1_ERR_DEC_BADVALUE;
++ return 0;
++ }
++
++ if (!asn1_octet_decode(ctx, &ch))
++ return 0;
++
++ *integer <<= 8;
++ *integer |= ch;
++ }
++ return 1;
++}
++
++static unsigned char asn1_uint_decode(struct asn1_ctx *ctx,
++ unsigned char *eoc,
++ unsigned int *integer)
++{
++ unsigned char ch;
++ unsigned int len;
++
++ if (!asn1_octet_decode(ctx, &ch))
++ return 0;
++
++ *integer = ch;
++ if (ch == 0)
++ len = 0;
++ else
++ len = 1;
++
++ while (ctx->pointer < eoc) {
++ if (++len > sizeof(unsigned int)) {
++ ctx->error = ASN1_ERR_DEC_BADVALUE;
++ return 0;
++ }
++
++ if (!asn1_octet_decode(ctx, &ch))
++ return 0;
++
++ *integer <<= 8;
++ *integer |= ch;
++ }
++ return 1;
++}
++
++static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx,
++ unsigned char *eoc,
++ unsigned long *integer)
++{
++ unsigned char ch;
++ unsigned int len;
++
++ if (!asn1_octet_decode(ctx, &ch))
++ return 0;
++
++ *integer = ch;
++ if (ch == 0)
++ len = 0;
++ else
++ len = 1;
++
++ while (ctx->pointer < eoc) {
++ if (++len > sizeof(unsigned long)) {
++ ctx->error = ASN1_ERR_DEC_BADVALUE;
++ return 0;
++ }
++
++ if (!asn1_octet_decode(ctx, &ch))
++ return 0;
++
++ *integer <<= 8;
++ *integer |= ch;
++ }
++ return 1;
++}
++
++static unsigned char
++asn1_octets_decode(struct asn1_ctx *ctx,
++ unsigned char *eoc,
++ unsigned char **octets, unsigned int *len)
++{
++ unsigned char *ptr;
++
++ *len = 0;
++
++ *octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC);
++ if (*octets == NULL) {
++ return 0;
++ }
++
++ ptr = *octets;
++ while (ctx->pointer < eoc) {
++ if (!asn1_octet_decode(ctx, (unsigned char *) ptr++)) {
++ kfree(*octets);
++ *octets = NULL;
++ return 0;
++ }
++ (*len)++;
++ }
++ return 1;
++} */
++
++static unsigned char
++asn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid)
++{
++ unsigned char ch;
++
++ *subid = 0;
++
++ do {
++ if (!asn1_octet_decode(ctx, &ch))
++ return 0;
++
++ *subid <<= 7;
++ *subid |= ch & 0x7F;
++ } while ((ch & 0x80) == 0x80);
++ return 1;
++}
++
++static unsigned char
++asn1_oid_decode(struct asn1_ctx *ctx,
++ unsigned char *eoc, unsigned long **oid, unsigned int *len)
++{
++ unsigned long subid;
++ unsigned int size;
++ unsigned long *optr;
++
++ size = eoc - ctx->pointer + 1;
++ *oid = kmalloc(size * sizeof (unsigned long), GFP_ATOMIC);
++ if (*oid == NULL) {
++ return 0;
++ }
++
++ optr = *oid;
++
++ if (!asn1_subid_decode(ctx, &subid)) {
++ kfree(*oid);
++ *oid = NULL;
++ return 0;
++ }
++
++ if (subid < 40) {
++ optr[0] = 0;
++ optr[1] = subid;
++ } else if (subid < 80) {
++ optr[0] = 1;
++ optr[1] = subid - 40;
++ } else {
++ optr[0] = 2;
++ optr[1] = subid - 80;
++ }
++
++ *len = 2;
++ optr += 2;
++
++ while (ctx->pointer < eoc) {
++ if (++(*len) > size) {
++ ctx->error = ASN1_ERR_DEC_BADVALUE;
++ kfree(*oid);
++ *oid = NULL;
++ return 0;
++ }
++
++ if (!asn1_subid_decode(ctx, optr++)) {
++ kfree(*oid);
++ *oid = NULL;
++ return 0;
++ }
++ }
++ return 1;
++}
++
++static int
++compare_oid(unsigned long *oid1, unsigned int oid1len,
++ unsigned long *oid2, unsigned int oid2len)
++{
++ unsigned int i;
++
++ if (oid1len != oid2len)
++ return 0;
++ else {
++ for (i = 0; i < oid1len; i++) {
++ if (oid1[i] != oid2[i])
++ return 0;
++ }
++ return 1;
++ }
++}
++
++ /* BB check for endian conversion issues here */
++
++int
++decode_negTokenInit(unsigned char *security_blob, int length,
++ enum securityEnum *secType)
++{
++ struct asn1_ctx ctx;
++ unsigned char *end;
++ unsigned char *sequence_end;
++ unsigned long *oid;
++ unsigned int cls, con, tag, oidlen, rc;
++ int use_ntlmssp = FALSE;
++
++ *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default */
++
++ /* cifs_dump_mem(" Received SecBlob ", security_blob, length); */
++
++ asn1_open(&ctx, security_blob, length);
++
++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
++ cFYI(1, ("Error decoding negTokenInit header "));
++ return 0;
++ } else if ((cls != ASN1_APL) || (con != ASN1_CON)
++ || (tag != ASN1_EOC)) {
++ cFYI(1, ("cls = %d con = %d tag = %d", cls, con, tag));
++ return 0;
++ } else {
++ /* remember to free obj->oid */
++ rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
++ if (rc) {
++ if ((tag == ASN1_OJI) && (cls == ASN1_PRI)) {
++ rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);
++ if (rc) {
++ rc = compare_oid(oid, oidlen,
++ SPNEGO_OID,
++ SPNEGO_OID_LEN);
++ kfree(oid);
++ }
++ } else
++ rc = 0;
++ }
++
++ if (!rc) {
++ cFYI(1, ("Error decoding negTokenInit header"));
++ return 0;
++ }
++
++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
++ cFYI(1, ("Error decoding negTokenInit "));
++ return 0;
++ } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
++ || (tag != ASN1_EOC)) {
++ cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 0",
++ cls, con, tag, end, *end));
++ return 0;
++ }
++
++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
++ cFYI(1, ("Error decoding negTokenInit "));
++ return 0;
++ } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
++ || (tag != ASN1_SEQ)) {
++ cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 1",
++ cls, con, tag, end, *end));
++ return 0;
++ }
++
++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
++ cFYI(1, ("Error decoding 2nd part of negTokenInit "));
++ return 0;
++ } else if ((cls != ASN1_CTX) || (con != ASN1_CON)
++ || (tag != ASN1_EOC)) {
++ cFYI(1,
++ ("cls = %d con = %d tag = %d end = %p (%d) exit 0",
++ cls, con, tag, end, *end));
++ return 0;
++ }
++
++ if (asn1_header_decode
++ (&ctx, &sequence_end, &cls, &con, &tag) == 0) {
++ cFYI(1, ("Error decoding 2nd part of negTokenInit "));
++ return 0;
++ } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
++ || (tag != ASN1_SEQ)) {
++ cFYI(1,
++ ("cls = %d con = %d tag = %d end = %p (%d) exit 1",
++ cls, con, tag, end, *end));
++ return 0;
++ }
++
++ while (!asn1_eoc_decode(&ctx, sequence_end)) {
++ rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
++ if (!rc) {
++ cFYI(1,
++ ("Error 1 decoding negTokenInit header exit 2"));
++ return 0;
++ }
++ if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
++ asn1_oid_decode(&ctx, end, &oid, &oidlen);
++ cFYI(1,
++ ("OID len = %d oid = 0x%lx 0x%lx 0x%lx 0x%lx",
++ oidlen, *oid, *(oid + 1), *(oid + 2),
++ *(oid + 3)));
++ rc = compare_oid(oid, oidlen, NTLMSSP_OID,
++ NTLMSSP_OID_LEN);
++ kfree(oid);
++ if (rc)
++ use_ntlmssp = TRUE;
++ } else {
++ cFYI(1,("This should be an oid what is going on? "));
++ }
++ }
++
++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
++ cFYI(1,
++ ("Error decoding last part of negTokenInit exit 3"));
++ return 0;
++ } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { /* tag = 3 indicating mechListMIC */
++ cFYI(1,
++ ("Exit 4 cls = %d con = %d tag = %d end = %p (%d)",
++ cls, con, tag, end, *end));
++ return 0;
++ }
++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
++ cFYI(1,
++ ("Error decoding last part of negTokenInit exit 5"));
++ return 0;
++ } else if ((cls != ASN1_UNI) || (con != ASN1_CON)
++ || (tag != ASN1_SEQ)) {
++ cFYI(1,
++ ("Exit 6 cls = %d con = %d tag = %d end = %p (%d)",
++ cls, con, tag, end, *end));
++ }
++
++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
++ cFYI(1,
++ ("Error decoding last part of negTokenInit exit 7"));
++ return 0;
++ } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
++ cFYI(1,
++ ("Exit 8 cls = %d con = %d tag = %d end = %p (%d)",
++ cls, con, tag, end, *end));
++ return 0;
++ }
++ if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
++ cFYI(1,
++ ("Error decoding last part of negTokenInit exit 9"));
++ return 0;
++ } else if ((cls != ASN1_UNI) || (con != ASN1_PRI)
++ || (tag != ASN1_GENSTR)) {
++ cFYI(1,
++ ("Exit 10 cls = %d con = %d tag = %d end = %p (%d)",
++ cls, con, tag, end, *end));
++ return 0;
++ }
++ cFYI(1, ("Need to call asn1_octets_decode() function for this %s", ctx.pointer)); /* is this UTF-8 or ASCII? */
++ }
++
++ /* if (use_kerberos)
++ *secType = Kerberos
++ else */
++ if (use_ntlmssp) {
++ *secType = NTLMSSP;
++ }
++
++ return 1;
++}
+diff -urN linux-2.4.29.old/fs/cifs/AUTHORS linux-2.4.29/fs/cifs/AUTHORS
+--- linux-2.4.29.old/fs/cifs/AUTHORS 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/AUTHORS 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,37 @@
++Original Author
++===============
++Steve French (sfrench@samba.org)
++
++The author wishes to express his appreciation and thanks to:
++Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS
++improvements. Thanks to IBM for allowing me the time and test resources to pursue
++this project. Jim McDonough from IBM (and the Samba Team) for his help.
++The IBM Linux JFS team for explaining many esoteric Linux filesystem features.
++Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client)
++for proving years ago that a very good smb/cifs client could be done on a Unix like
++operating system. Volker Lendecke, Andrew Tridgell, Urban Widmark, John Newbigin
++and others for their work on the Linux smbfs module over the years. Thanks to
++the other members of the Storage Network Industry Association CIFS Technical
++Workgroup for their work specifying this highly complex protocol and finally
++thanks to the Samba team for their technical advice and encouragement.
++
++Patch Contributors
++------------------
++Zwane Mwaikambo
++Andi Kleen
++Amrut Joshi
++Shobhit Dayal
++Sergey Vlasov
++Richard Hughes
++Yury Umanets
++
++Test case and Bug Report contributors
++-------------------------------------
++Thanks to those in the community who have submitted detailed bug reports
++and debug of problems they have found: Jochen Dolze, David Blaine,
++Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori,
++Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen,
++Olaf Kirch, Kieron Briggs, Nick Millington and others.
++
++And thanks to the IBM LTC and Power test teams and SuSE testers for
++finding multiple bugs during excellent stress test runs.
+diff -urN linux-2.4.29.old/fs/cifs/CHANGES linux-2.4.29/fs/cifs/CHANGES
+--- linux-2.4.29.old/fs/cifs/CHANGES 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/CHANGES 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,572 @@
++Version 1.20
++------------
++Make transaction counts more consistent. Merge /proc/fs/cifs/SimultaneousOps
++info into /proc/fs/cifs/DebugData. Fix oops in rare oops in readdir
++(in build_wildcard_path_from_dentry). Fix mknod to pass type field
++(block/char/fifo) properly. Remove spurious mount warning log entry when
++credentials passed as mount argument. Set major/minor device number in
++inode for block and char devices when unix extensions enabled.
++
++Version 1.19
++------------
++Fix /proc/fs/cifs/Stats and DebugData display to handle larger
++amounts of return data. Properly limit requests to MAX_REQ (50
++is the usual maximum active multiplex SMB/CIFS requests per server).
++Do not kill cifsd (and thus hurt the other SMB session) when more than one
++session to the same server (but with different userids) exists and one
++of the two user's smb sessions is being removed while leaving the other.
++Do not loop reconnecting in cifsd demultiplex thread when admin
++kills the thread without going through unmount.
++
++Version 1.18
++------------
++Do not rename hardlinked files (since that should be a noop). Flush
++cached write behind data when reopening a file after session abend,
++except when already in write. Grab per socket sem during reconnect
++to avoid oops in sendmsg if overlapping with reconnect. Do not
++reset cached inode file size on readdir for files open for write on
++client.
++
++
++Version 1.17
++------------
++Update number of blocks in file so du command is happier (in Linux a fake
++blocksize of 512 is required for calculating number of blocks in inode).
++Fix prepare write of partial pages to read in data from server if possible.
++Fix race on tcpStatus field between unmount and reconnection code, causing
++cifsd process sometimes to hang around forever. Improve out of memory
++checks in cifs_filldir
++
++Version 1.16
++------------
++Fix incorrect file size in file handle based setattr on big endian hardware.
++Fix oops in build_path_from_dentry when out of memory. Add checks for invalid
++and closing file structs in writepage/partialpagewrite. Add statistics
++for each mounted share (new menuconfig option). Fix endianness problem in
++volume information displayed in /proc/fs/cifs/DebugData (only affects
++affects big endian architectures). Prevent renames while constructing
++path names for open, mkdir and rmdir.
++
++Version 1.15
++------------
++Change to mempools for alloc smb request buffers and multiplex structs
++to better handle low memory problems (and potential deadlocks).
++
++Version 1.14
++------------
++Fix incomplete listings of large directories on Samba servers when Unix
++extensions enabled. Fix oops when smb_buffer can not be allocated. Fix
++rename deadlock when writing out dirty pages at same time.
++
++Version 1.13
++------------
++Fix open of files in which O_CREATE can cause the mode to change in
++some cases. Fix case in which retry of write overlaps file close.
++Fix PPC64 build error. Reduce excessive stack usage in smb password
++hashing. Fix overwrite of Linux user's view of file mode to Windows servers.
++
++Version 1.12
++------------
++Fixes for large file copy, signal handling, socket retry, buffer
++allocation and low memory situations.
++
++Version 1.11
++------------
++Better port 139 support to Windows servers (RFC1001/RFC1002 Session_Initialize)
++also now allowing support for specifying client netbiosname. NT4 support added.
++
++Version 1.10
++------------
++Fix reconnection (and certain failed mounts) to properly wake up the
++blocked users thread so it does not seem hung (in some cases was blocked
++until the cifs receive timeout expired). Fix spurious error logging
++to kernel log when application with open network files killed.
++
++Version 1.09
++------------
++Fix /proc/fs module unload warning message (that could be logged
++to the kernel log). Fix intermittent failure in connectathon
++test7 (hardlink count not immediately refreshed in case in which
++inode metadata can be incorrectly kept cached when time near zero)
++
++Version 1.08
++------------
++Allow file_mode and dir_mode (specified at mount time) to be enforced
++locally (the server already enforced its own ACLs too) for servers
++that do not report the correct mode (do not support the
++CIFS Unix Extensions).
++
++Version 1.07
++------------
++Fix some small memory leaks in some unmount error paths. Fix major leak
++of cache pages in readpages causing multiple read oriented stress
++testcases (including fsx, and even large file copy) to fail over time.
++
++Version 1.06
++------------
++Send NTCreateX with ATTR_POSIX if Linux/Unix extensions negotiated with server.
++This allows files that differ only in case and improves performance of file
++creation and file open to such servers. Fix semaphore conflict which causes
++slow delete of open file to Samba (which unfortunately can cause an oplock
++break to self while vfs_unlink held i_sem) which can hang for 20 seconds.
++
++Version 1.05
++------------
++fixes to cifs_readpages for fsx test case
++
++Version 1.04
++------------
++Fix caching data integrity bug when extending file size especially when no
++oplock on file. Fix spurious logging of valid already parsed mount options
++that are parsed outside of the cifs vfs such as nosuid.
++
++
++Version 1.03
++------------
++Connect to server when port number override not specified, and tcp port
++unitialized. Reset search to restart at correct file when kernel routine
++filldir returns error during large directory searches (readdir).
++
++Version 1.02
++------------
++Fix caching problem when files opened by multiple clients in which
++page cache could contain stale data, and write through did
++not occur often enough while file was still open when read ahead
++(read oplock) not allowed. Treat "sep=" when first mount option
++as an overrride of comma as the default separator between mount
++options.
++
++Version 1.01
++------------
++Allow passwords longer than 16 bytes. Allow null password string.
++
++Version 1.00
++------------
++Gracefully clean up failed mounts when attempting to mount to servers such as
++Windows 98 that terminate tcp sessions during prototocol negotiation. Handle
++embedded commas in mount parsing of passwords.
++
++Version 0.99
++------------
++Invalidate local inode cached pages on oplock break and when last file
++instance is closed so that the client does not continue using stale local
++copy rather than later modified server copy of file. Do not reconnect
++when server drops the tcp session prematurely before negotiate
++protocol response. Fix oops in roepen_file when dentry freed. Allow
++the support for CIFS Unix Extensions to be disabled via proc interface.
++
++Version 0.98
++------------
++Fix hang in commit_write during reconnection of open files under heavy load.
++Fix unload_nls oops in a mount failure path. Serialize writes to same socket
++which also fixes any possible races when cifs signatures are enabled in SMBs
++being sent out of signature sequence number order.
++
++Version 0.97
++------------
++Fix byte range locking bug (endian problem) causing bad offset and
++length.
++
++Version 0.96
++------------
++Fix oops (in send_sig) caused by CIFS unmount code trying to
++wake up the demultiplex thread after it had exited. Do not log
++error on harmless oplock release of closed handle.
++
++Version 0.95
++------------
++Fix unsafe global variable usage and password hash failure on gcc 3.3.1
++Fix problem reconnecting secondary mounts to same server after session
++failure. Fix invalid dentry - race in mkdir when directory gets created
++by another client between the lookup and mkdir.
++
++Version 0.94
++------------
++Fix to list processing in reopen_files. Fix reconnection when server hung
++but tcpip session still alive. Set proper timeout on socket read.
++
++Version 0.93
++------------
++Add missing mount options including iocharset. SMP fixes in write and open.
++Fix errors in reconnecting after TCP session failure. Fix module unloading
++of default nls codepage
++
++Version 0.92
++------------
++Active smb transactions should never go negative (fix double FreeXid). Fix
++list processing in file routines. Check return code on kmalloc in open.
++Fix spinlock usage for SMP.
++
++Version 0.91
++------------
++Fix oops in reopen_files when invalid dentry. drop dentry on server rename
++and on revalidate errors. Fix cases where pid is now tgid. Fix return code
++on create hard link when server does not support them.
++
++Version 0.90
++------------
++Fix scheduling while atomic error in getting inode info on newly created file.
++Fix truncate of existing files opened with O_CREAT but not O_TRUNC set.
++
++Version 0.89
++------------
++Fix oops on write to dead tcp session. Remove error log write for case when file open
++O_CREAT but not O_EXCL
++
++Version 0.88
++------------
++Fix non-POSIX behavior on rename of open file and delete of open file by taking
++advantage of trans2 SetFileInfo rename facility if available on target server.
++Retry on ENOSPC and EAGAIN socket errors.
++
++Version 0.87
++------------
++Fix oops on big endian readdir. Set blksize to be even power of two (2**blkbits) to fix
++allocation size miscalculation. After oplock token lost do not read through
++cache.
++
++Version 0.86
++------------
++Fix oops on empty file readahead. Fix for file size handling for locally cached files.
++
++Version 0.85
++------------
++Fix oops in mkdir when server fails to return inode info. Fix oops in reopen_files
++during auto reconnection to server after server recovered from failure.
++
++Version 0.84
++------------
++Finish support for Linux 2.5 open/create changes, which removes the
++redundant NTCreate/QPathInfo/close that was sent during file create.
++Enable oplock by default. Enable packet signing by default (needed to
++access many recent Windows servers)
++
++Version 0.83
++------------
++Fix oops when mounting to long server names caused by inverted parms to kmalloc.
++Fix MultiuserMount (/proc/fs/cifs configuration setting) so that when enabled
++we will choose a cifs user session (smb uid) that better matches the local
++uid if a) the mount uid does not match the current uid and b) we have another
++session to the same server (ip address) for a different mount which
++matches the current local uid.
++
++Version 0.82
++------------
++Add support for mknod of block or character devices. Fix oplock
++code (distributed caching) to properly send response to oplock
++break from server.
++
++Version 0.81
++------------
++Finish up CIFS packet digital signing for the default
++NTLM security case. This should help Windows 2003
++network interoperability since it is common for
++packet signing to be required now. Fix statfs (stat -f)
++which recently started returning errors due to
++invalid value (-1 instead of 0) being set in the
++struct kstatfs f_ffiles field.
++
++Version 0.80
++-----------
++Fix oops on stopping oplock thread when removing cifs when
++built as module.
++
++Version 0.79
++------------
++Fix mount options for ro (readonly), uid, gid and file and directory mode.
++
++Version 0.78
++------------
++Fix errors displayed on failed mounts to be more understandable.
++Fixed various incorrect or misleading smb to posix error code mappings.
++
++Version 0.77
++------------
++Fix display of NTFS DFS junctions to display as symlinks.
++They are the network equivalent. Fix oops in
++cifs_partialpagewrite caused by missing spinlock protection
++of openfile linked list. Allow writebehind caching errors to
++be returned to the application at file close.
++
++Version 0.76
++------------
++Clean up options displayed in /proc/mounts by show_options to
++be more consistent with other filesystems.
++
++Version 0.75
++------------
++Fix delete of readonly file to Windows servers. Reflect
++presence or absence of read only dos attribute in mode
++bits for servers that do not support CIFS Unix extensions.
++Fix shortened results on readdir of large directories to
++servers supporting CIFS Unix extensions (caused by
++incorrect resume key).
++
++Version 0.74
++------------
++Fix truncate bug (set file size) that could cause hangs e.g. running fsx
++
++Version 0.73
++------------
++unload nls if mount fails.
++
++Version 0.72
++------------
++Add resume key support to search (readdir) code to workaround
++Windows bug. Add /proc/fs/cifs/LookupCacheEnable which
++allows disabling caching of attribute information for
++lookups.
++
++Version 0.71
++------------
++Add more oplock handling (distributed caching code). Remove
++dead code. Remove excessive stack space utilization from
++symlink routines.
++
++Version 0.70
++------------
++Fix oops in get dfs referral (triggered when null path sent in to
++mount). Add support for overriding rsize at mount time.
++
++Version 0.69
++------------
++Fix buffer overrun in readdir which caused intermittent kernel oopses.
++Fix writepage code to release kmap on write data. Allow "-ip=" new
++mount option to be passed in on parameter distinct from the first part
++(server name portion of) the UNC name. Allow override of the
++tcp port of the target server via new mount option "-port="
++
++Version 0.68
++------------
++Fix search handle leak on rewind. Fix setuid and gid so that they are
++reflected in the local inode immediately. Cleanup of whitespace
++to make 2.4 and 2.5 versions more consistent.
++
++
++Version 0.67
++------------
++Fix signal sending so that captive thread (cifsd) exits on umount
++(which was causing the warning in kmem_cache_free of the request buffers
++at rmmod time). This had broken as a sideeffect of the recent global
++kernel change to daemonize. Fix memory leak in readdir code which
++showed up in "ls -R" (and applications that did search rewinding).
++
++Version 0.66
++------------
++Reconnect tids and fids after session reconnection (still do not
++reconnect byte range locks though). Fix problem caching
++lookup information for directory inodes, improving performance,
++especially in deep directory trees. Fix various build warnings.
++
++Version 0.65
++------------
++Finish fixes to commit write for caching/readahead consistency. fsx
++now works to Samba servers. Fix oops caused when readahead
++was interrupted by a signal.
++
++Version 0.64
++------------
++Fix data corruption (in partial page after truncate) that caused fsx to
++fail to Windows servers. Cleaned up some extraneous error logging in
++common error paths. Add generic sendfile support.
++
++Version 0.63
++------------
++Fix memory leak in AllocMidQEntry.
++Finish reconnection logic, so connection with server can be dropped
++(or server rebooted) and the cifs client will reconnect.
++
++Version 0.62
++------------
++Fix temporary socket leak when bad userid or password specified
++(or other SMBSessSetup failure). Increase maximum buffer size to slightly
++over 16K to allow negotiation of up to Samba and Windows server default read
++sizes. Add support for readpages
++
++Version 0.61
++------------
++Fix oops when username not passed in on mount. Extensive fixes and improvements
++to error logging (strip redundant newlines, change debug macros to ensure newline
++passed in and to be more consistent). Fix writepage wrong file handle problem,
++a readonly file handle could be incorrectly used to attempt to write out
++file updates through the page cache to multiply open files. This could cause
++the iozone benchmark to fail on the fwrite test. Fix bug mounting two different
++shares to the same Windows server when using different usernames
++(doing this to Samba servers worked but Windows was rejecting it) - now it is
++possible to use different userids when connecting to the same server from a
++Linux client. Fix oops when treeDisconnect called during unmount on
++previously freed socket.
++
++Version 0.60
++------------
++Fix oops in readpages caused by not setting address space operations in inode in
++rare code path.
++
++Version 0.59
++------------
++Includes support for deleting of open files and renaming over existing files (per POSIX
++requirement). Add readlink support for Windows junction points (directory symlinks).
++
++Version 0.58
++------------
++Changed read and write to go through pagecache. Added additional address space operations.
++Memory mapped operations now working.
++
++Version 0.57
++------------
++Added writepage code for additional memory mapping support. Fixed leak in xids causing
++the simultaneous operations counter (/proc/fs/cifs/SimultaneousOps) to increase on
++every stat call. Additional formatting cleanup.
++
++Version 0.56
++------------
++Fix bigendian bug in order of time conversion. Merge 2.5 to 2.4 version. Formatting cleanup.
++
++Version 0.55
++------------
++Fixes from Zwane Mwaikambo for adding missing return code checking in a few places.
++Also included a modified version of his fix to protect global list manipulation of
++the smb session and tree connection and mid related global variables.
++
++Version 0.54
++------------
++Fix problem with captive thread hanging around at unmount time. Adjust to 2.5.42-pre
++changes to superblock layout. Remove wasteful allocation of smb buffers (now the send
++buffer is reused for responses). Add more oplock handling. Additional minor cleanup.
++
++Version 0.53
++------------
++More stylistic updates to better match kernel style. Add additional statistics
++for filesystem which can be viewed via /proc/fs/cifs. Add more pieces of NTLMv2
++and CIFS Packet Signing enablement.
++
++Version 0.52
++------------
++Replace call to sleep_on with safer wait_on_event.
++Make stylistic changes to better match kernel style recommendations.
++Remove most typedef usage (except for the PDUs themselves).
++
++Version 0.51
++------------
++Update mount so the -unc mount option is no longer required (the ip address can be specified
++in a UNC style device name. Implementation of readpage/writepage started.
++
++Version 0.50
++------------
++Fix intermittent problem with incorrect smb header checking on badly
++fragmented tcp responses
++
++Version 0.49
++------------
++Fixes to setting of allocation size and file size.
++
++Version 0.48
++------------
++Various 2.5.38 fixes. Now works on 2.5.38
++
++Version 0.47
++------------
++Prepare for 2.5 kernel merge. Remove ifdefs.
++
++Version 0.46
++------------
++Socket buffer management fixes. Fix dual free.
++
++Version 0.45
++------------
++Various big endian fixes for hardlinks and symlinks and also for dfs.
++
++Version 0.44
++------------
++Various big endian fixes for servers with Unix extensions such as Samba
++
++Version 0.43
++------------
++Various FindNext fixes for incorrect filenames on large directory searches on big endian
++clients. basic posix file i/o tests now work on big endian machines, not just le
++
++Version 0.42
++------------
++SessionSetup and NegotiateProtocol now work from Big Endian machines.
++Various Big Endian fixes found during testing on the Linux on 390. Various fixes for compatibility with older
++versions of 2.4 kernel (now builds and works again on kernels at least as early as 2.4.7).
++
++Version 0.41
++------------
++Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked
++files now return the correct rumber of links on fstat as they are repeatedly linked and unlinked.
++
++Version 0.40
++------------
++Implemented "Raw" (i.e. not encapsulated in SPNEGO) NTLMSSP (i.e. the Security Provider Interface used to negotiate
++session advanced session authentication). Raw NTLMSSP is preferred by Windows 2000 Professional and Windows XP.
++Began implementing support for SPNEGO encapsulation of NTLMSSP based session authentication blobs
++(which is the mechanism preferred by Windows 2000 server in the absence of Kerberos).
++
++Version 0.38
++------------
++Introduced optional mount helper utility mount.cifs and made coreq changes to cifs vfs to enable
++it. Fixed a few bugs in the DFS code (e.g. bcc two bytes too short and incorrect uid in PDU).
++
++Version 0.37
++------------
++Rewrote much of connection and mount/unmount logic to handle bugs with
++multiple uses to same share, multiple users to same server etc.
++
++Version 0.36
++------------
++Fixed major problem with dentry corruption (missing call to dput)
++
++Version 0.35
++------------
++Rewrite of readdir code to fix bug. Various fixes for bigendian machines.
++Begin adding oplock support. Multiusermount and oplockEnabled flags added to /proc/fs/cifs
++although corresponding function not fully implemented in the vfs yet
++
++Version 0.34
++------------
++Fixed dentry caching bug, misc. cleanup
++
++Version 0.33
++------------
++Fixed 2.5 support to handle build and configure changes as well as misc. 2.5 changes. Now can build
++on current 2.5 beta version (2.5.24) of the Linux kernel as well as on 2.4 Linux kernels.
++Support for STATUS codes (newer 32 bit NT error codes) added. DFS support begun to be added.
++
++Version 0.32
++------------
++Unix extensions (symlink, readlink, hardlink, chmod and some chgrp and chown) implemented
++and tested against Samba 2.2.5
++
++
++Version 0.31
++------------
++1) Fixed lockrange to be correct (it was one byte too short)
++
++2) Fixed GETLK (i.e. the fcntl call to test a range of bytes in a file to see if locked) to correctly
++show range as locked when there is a conflict with an existing lock.
++
++3) default file perms are now 2767 (indicating support for mandatory locks) instead of 777 for directories
++in most cases. Eventually will offer optional ability to query server for the correct perms.
++
++3) Fixed eventual trap when mounting twice to different shares on the same server when the first succeeded
++but the second one was invalid and failed (the second one was incorrectly disconnecting the tcp and smb
++session)
++
++4) Fixed error logging of valid mount options
++
++5) Removed logging of password field.
++
++6) Moved negotiate, treeDisconnect and uloggoffX (only tConx and SessSetup remain in connect.c) to cifssmb.c
++and cleaned them up and made them more consistent with other cifs functions.
++
++7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways
++(with or without Unix exentions) but FindNext and QueryPathInfo with the Unix extensions are not completed,
++nor is the symlink support using the Unix extensions
++
++8) Started adding the readlink and follow_link code
++
++Version 0.3
++-----------
++Initial drop
++
+diff -urN linux-2.4.29.old/fs/cifs/cifs_debug.c linux-2.4.29/fs/cifs/cifs_debug.c
+--- linux-2.4.29.old/fs/cifs/cifs_debug.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/cifs_debug.c 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,797 @@
++/*
++ * fs/cifs_debug.c
++ *
++ * Copyright (C) International Business Machines Corp., 2000,2003
++ *
++ * Modified by Steve French (sfrench@us.ibm.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
++ * the GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#include <linux/fs.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include <linux/module.h>
++#include <linux/proc_fs.h>
++#include <asm/uaccess.h>
++#include "cifspdu.h"
++#include "cifsglob.h"
++#include "cifsproto.h"
++#include "cifs_debug.h"
++
++void
++cifs_dump_mem(char *label, void *data, int length)
++{
++ int i, j;
++ int *intptr = data;
++ char *charptr = data;
++ char buf[10], line[80];
++
++ printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n",
++ label, length, data);
++ for (i = 0; i < length; i += 16) {
++ line[0] = 0;
++ for (j = 0; (j < 4) && (i + j * 4 < length); j++) {
++ sprintf(buf, " %08x", intptr[i / 4 + j]);
++ strcat(line, buf);
++ }
++ buf[0] = ' ';
++ buf[2] = 0;
++ for (j = 0; (j < 16) && (i + j < length); j++) {
++ buf[1] = isprint(charptr[i + j]) ? charptr[i + j] : '.';
++ strcat(line, buf);
++ }
++ printk(KERN_DEBUG "%s\n", line);
++ }
++}
++
++#ifdef CONFIG_PROC_FS
++int
++cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
++ int count, int *eof, void *data)
++{
++ struct list_head *tmp;
++ struct list_head *tmp1;
++ struct mid_q_entry * mid_entry;
++ struct cifsSesInfo *ses;
++ struct cifsTconInfo *tcon;
++ int i;
++ int length = 0;
++ char * original_buf = buf;
++
++ *beginBuffer = buf + offset;
++
++
++ length =
++ sprintf(buf,
++ "Display Internal CIFS Data Structures for Debugging\n"
++ "---------------------------------------------------\n");
++ buf += length;
++
++ length = sprintf(buf, "Servers:\n");
++ buf += length;
++
++ i = 0;
++ read_lock(&GlobalSMBSeslock);
++ list_for_each(tmp, &GlobalSMBSessionList) {
++ i++;
++ ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
++ length =
++ sprintf(buf,
++ "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\tTCP status: %d",
++ i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse),
++ ses->serverOS, ses->serverNOS, ses->capabilities,ses->status,ses->server->tcpStatus);
++ buf += length;
++ if(ses->server) {
++ buf += sprintf(buf, "\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d",
++ atomic_read(&ses->server->socketUseCount),
++ ses->server->secMode,
++ atomic_read(&ses->server->inFlight));
++
++ length = sprintf(buf, "\nMIDs: \n");
++ buf += length;
++
++ spin_lock(&GlobalMid_Lock);
++ list_for_each(tmp1, &ses->server->pending_mid_q) {
++ mid_entry = list_entry(tmp1, struct
++ mid_q_entry,
++ qhead);
++ if(mid_entry) {
++ length = sprintf(buf,"State: %d com: %d pid: %d tsk: %p mid %d\n",mid_entry->midState,mid_entry->command,mid_entry->pid,mid_entry->tsk,mid_entry->mid);
++ buf += length;
++ }
++ }
++ spin_unlock(&GlobalMid_Lock);
++ }
++
++ }
++ read_unlock(&GlobalSMBSeslock);
++ sprintf(buf, "\n");
++ buf++;
++
++ length = sprintf(buf, "\nShares:\n");
++ buf += length;
++
++ i = 0;
++ read_lock(&GlobalSMBSeslock);
++ list_for_each(tmp, &GlobalTreeConnectionList) {
++ i++;
++ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
++ length =
++ sprintf(buf,
++ "\n%d) %s Uses: %d Type: %s Characteristics: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d",
++ i, tcon->treeName,
++ atomic_read(&tcon->useCount),
++ tcon->nativeFileSystem,
++ tcon->fsDevInfo.DeviceCharacteristics,
++ tcon->fsAttrInfo.Attributes,
++ tcon->fsAttrInfo.MaxPathNameComponentLength,tcon->tidStatus);
++ buf += length;
++ if (tcon->fsDevInfo.DeviceType == FILE_DEVICE_DISK)
++ length = sprintf(buf, " type: DISK ");
++ else if (tcon->fsDevInfo.DeviceType == FILE_DEVICE_CD_ROM)
++ length = sprintf(buf, " type: CDROM ");
++ else
++ length =
++ sprintf(buf, " type: %d ",
++ tcon->fsDevInfo.DeviceType);
++ buf += length;
++ if(tcon->tidStatus == CifsNeedReconnect) {
++ buf += sprintf(buf, "\tDISCONNECTED ");
++ length += 14;
++ }
++ }
++ read_unlock(&GlobalSMBSeslock);
++
++ length = sprintf(buf, "\n");
++ buf += length;
++
++ /* BB add code to dump additional info such as TCP session info now */
++ /* Now calculate total size of returned data */
++ length = buf - original_buf;
++
++ if(offset + count >= length)
++ *eof = 1;
++ if(length < offset) {
++ *eof = 1;
++ return 0;
++ } else {
++ length = length - offset;
++ }
++ if (length > count)
++ length = count;
++
++ return length;
++}
++
++#ifdef CONFIG_CIFS_STATS
++int
++cifs_stats_read(char *buf, char **beginBuffer, off_t offset,
++ int count, int *eof, void *data)
++{
++ int item_length,i,length;
++ struct list_head *tmp;
++ struct cifsTconInfo *tcon;
++
++ *beginBuffer = buf + offset;
++
++ length = sprintf(buf,
++ "Resources in use\nCIFS Session: %d\n",
++ sesInfoAllocCount.counter);
++ buf += length;
++ item_length =
++ sprintf(buf,"Share (unique mount targets): %d\n",
++ tconInfoAllocCount.counter);
++ length += item_length;
++ buf += item_length;
++ item_length =
++ sprintf(buf,"SMB Request/Response Buffer: %d\n",
++ bufAllocCount.counter);
++ length += item_length;
++ buf += item_length;
++ item_length =
++ sprintf(buf,"Operations (MIDs): %d\n",
++ midCount.counter);
++ length += item_length;
++ buf += item_length;
++ item_length = sprintf(buf,
++ "\n%d session %d share reconnects\n",
++ tcpSesReconnectCount.counter,tconInfoReconnectCount.counter);
++ length += item_length;
++ buf += item_length;
++
++ item_length = sprintf(buf,
++ "Total vfs operations: %d maximum at one time: %d\n",
++ GlobalCurrentXid,GlobalMaxActiveXid);
++ length += item_length;
++ buf += item_length;
++
++ i = 0;
++ read_lock(&GlobalSMBSeslock);
++ list_for_each(tmp, &GlobalTreeConnectionList) {
++ i++;
++ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
++ item_length = sprintf(buf,"\n%d) %s",i, tcon->treeName);
++ buf += item_length;
++ length += item_length;
++ if(tcon->tidStatus == CifsNeedReconnect) {
++ buf += sprintf(buf, "\tDISCONNECTED ");
++ length += 14;
++ }
++ item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d",
++ atomic_read(&tcon->num_smbs_sent),
++ atomic_read(&tcon->num_oplock_brks));
++ buf += item_length;
++ length += item_length;
++ item_length = sprintf(buf,"\nReads: %d Bytes %lld",
++ atomic_read(&tcon->num_reads),
++ (long long)(tcon->bytes_read));
++ buf += item_length;
++ length += item_length;
++ item_length = sprintf(buf,"\nWrites: %d Bytes: %lld",
++ atomic_read(&tcon->num_writes),
++ (long long)(tcon->bytes_written));
++ buf += item_length;
++ length += item_length;
++ item_length = sprintf(buf,
++ "\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d",
++ atomic_read(&tcon->num_opens),
++ atomic_read(&tcon->num_deletes),
++ atomic_read(&tcon->num_mkdirs),
++ atomic_read(&tcon->num_rmdirs));
++ buf += item_length;
++ length += item_length;
++ item_length = sprintf(buf,
++ "\nRenames: %d T2 Renames %d",
++ atomic_read(&tcon->num_renames),
++ atomic_read(&tcon->num_t2renames));
++ buf += item_length;
++ length += item_length;
++ }
++ read_unlock(&GlobalSMBSeslock);
++
++ buf += sprintf(buf,"\n");
++ length++;
++
++ if(offset + count >= length)
++ *eof = 1;
++ if(length < offset) {
++ *eof = 1;
++ return 0;
++ } else {
++ length = length - offset;
++ }
++ if (length > count)
++ length = count;
++
++ return length;
++}
++#endif
++
++struct proc_dir_entry *proc_fs_cifs;
++read_proc_t cifs_txanchor_read;
++static read_proc_t cifsFYI_read;
++static write_proc_t cifsFYI_write;
++static read_proc_t oplockEnabled_read;
++static write_proc_t oplockEnabled_write;
++static read_proc_t lookupFlag_read;
++static write_proc_t lookupFlag_write;
++static read_proc_t traceSMB_read;
++static write_proc_t traceSMB_write;
++static read_proc_t multiuser_mount_read;
++static write_proc_t multiuser_mount_write;
++static read_proc_t extended_security_read;
++static write_proc_t extended_security_write;
++static read_proc_t ntlmv2_enabled_read;
++static write_proc_t ntlmv2_enabled_write;
++static read_proc_t packet_signing_enabled_read;
++static write_proc_t packet_signing_enabled_write;
++static read_proc_t quotaEnabled_read;
++static write_proc_t quotaEnabled_write;
++static read_proc_t linuxExtensionsEnabled_read;
++static write_proc_t linuxExtensionsEnabled_write;
++
++void
++cifs_proc_init(void)
++{
++ struct proc_dir_entry *pde;
++
++ proc_fs_cifs = proc_mkdir("cifs", proc_root_fs);
++ if (proc_fs_cifs == NULL)
++ return;
++
++ proc_fs_cifs->owner = THIS_MODULE;
++ create_proc_read_entry("DebugData", 0, proc_fs_cifs,
++ cifs_debug_data_read, NULL);
++
++#ifdef CONFIG_CIFS_STATS
++ create_proc_read_entry("Stats", 0, proc_fs_cifs,
++ cifs_stats_read, NULL);
++#endif
++ pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs,
++ cifsFYI_read, NULL);
++ if (pde)
++ pde->write_proc = cifsFYI_write;
++
++ pde =
++ create_proc_read_entry("traceSMB", 0, proc_fs_cifs,
++ traceSMB_read, NULL);
++ if (pde)
++ pde->write_proc = traceSMB_write;
++
++ pde = create_proc_read_entry("OplockEnabled", 0, proc_fs_cifs,
++ oplockEnabled_read, NULL);
++ if (pde)
++ pde->write_proc = oplockEnabled_write;
++
++ pde = create_proc_read_entry("QuotaEnabled", 0, proc_fs_cifs,
++ quotaEnabled_read, NULL);
++ if (pde)
++ pde->write_proc = quotaEnabled_write;
++
++ pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs,
++ linuxExtensionsEnabled_read, NULL);
++ if (pde)
++ pde->write_proc = linuxExtensionsEnabled_write;
++
++ pde =
++ create_proc_read_entry("MultiuserMount", 0, proc_fs_cifs,
++ multiuser_mount_read, NULL);
++ if (pde)
++ pde->write_proc = multiuser_mount_write;
++
++ pde =
++ create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs,
++ extended_security_read, NULL);
++ if (pde)
++ pde->write_proc = extended_security_write;
++
++ pde =
++ create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs,
++ lookupFlag_read, NULL);
++ if (pde)
++ pde->write_proc = lookupFlag_write;
++
++ pde =
++ create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
++ ntlmv2_enabled_read, NULL);
++ if (pde)
++ pde->write_proc = ntlmv2_enabled_write;
++
++ pde =
++ create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs,
++ packet_signing_enabled_read, NULL);
++ if (pde)
++ pde->write_proc = packet_signing_enabled_write;
++}
++
++void
++cifs_proc_clean(void)
++{
++ if (proc_fs_cifs == NULL)
++ return;
++
++ remove_proc_entry("DebugData", proc_fs_cifs);
++ remove_proc_entry("cifsFYI", proc_fs_cifs);
++ remove_proc_entry("traceSMB", proc_fs_cifs);
++#ifdef CONFIG_CIFS_STATS
++ remove_proc_entry("Stats", proc_fs_cifs);
++#endif
++ remove_proc_entry("MultiuserMount", proc_fs_cifs);
++ remove_proc_entry("OplockEnabled", proc_fs_cifs);
++ remove_proc_entry("NTLMV2Enabled",proc_fs_cifs);
++ remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
++ remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
++ remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
++ remove_proc_entry("QuotaEnabled",proc_fs_cifs);
++ remove_proc_entry("LookupCacheEnabled",proc_fs_cifs);
++ remove_proc_entry("cifs", proc_root_fs);
++}
++
++static int
++cifsFYI_read(char *page, char **start, off_t off, int count,
++ int *eof, void *data)
++{
++ int len;
++
++ len = sprintf(page, "%d\n", cifsFYI);
++
++ len -= off;
++ *start = page + off;
++
++ if (len > count)
++ len = count;
++ else
++ *eof = 1;
++
++ if (len < 0)
++ len = 0;
++
++ return len;
++}
++static int
++cifsFYI_write(struct file *file, const char *buffer,
++ unsigned long count, void *data)
++{
++ char c;
++ int rc;
++
++ rc = get_user(c, buffer);
++ if (rc)
++ return rc;
++ if (c == '0' || c == 'n' || c == 'N')
++ cifsFYI = 0;
++ else if (c == '1' || c == 'y' || c == 'Y')
++ cifsFYI = 1;
++
++ return count;
++}
++
++static int
++oplockEnabled_read(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len;
++
++ len = sprintf(page, "%d\n", oplockEnabled);
++
++ len -= off;
++ *start = page + off;
++
++ if (len > count)
++ len = count;
++ else
++ *eof = 1;
++
++ if (len < 0)
++ len = 0;
++
++ return len;
++}
++static int
++oplockEnabled_write(struct file *file, const char *buffer,
++ unsigned long count, void *data)
++{
++ char c;
++ int rc;
++
++ rc = get_user(c, buffer);
++ if (rc)
++ return rc;
++ if (c == '0' || c == 'n' || c == 'N')
++ oplockEnabled = 0;
++ else if (c == '1' || c == 'y' || c == 'Y')
++ oplockEnabled = 1;
++
++ return count;
++}
++
++static int
++quotaEnabled_read(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len;
++
++ len = sprintf(page, "%d\n", quotaEnabled);
++/* could also check if quotas are enabled in kernel
++ as a whole first */
++ len -= off;
++ *start = page + off;
++
++ if (len > count)
++ len = count;
++ else
++ *eof = 1;
++
++ if (len < 0)
++ len = 0;
++
++ return len;
++}
++static int
++quotaEnabled_write(struct file *file, const char *buffer,
++ unsigned long count, void *data)
++{
++ char c;
++ int rc;
++
++ rc = get_user(c, buffer);
++ if (rc)
++ return rc;
++ if (c == '0' || c == 'n' || c == 'N')
++ quotaEnabled = 0;
++ else if (c == '1' || c == 'y' || c == 'Y')
++ quotaEnabled = 1;
++
++ return count;
++}
++
++static int
++linuxExtensionsEnabled_read(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len;
++
++ len = sprintf(page, "%d\n", linuxExtEnabled);
++/* could also check if quotas are enabled in kernel
++ as a whole first */
++ len -= off;
++ *start = page + off;
++
++ if (len > count)
++ len = count;
++ else
++ *eof = 1;
++
++ if (len < 0)
++ len = 0;
++
++ return len;
++}
++static int
++linuxExtensionsEnabled_write(struct file *file, const char *buffer,
++ unsigned long count, void *data)
++{
++ char c;
++ int rc;
++
++ rc = get_user(c, buffer);
++ if (rc)
++ return rc;
++ if (c == '0' || c == 'n' || c == 'N')
++ linuxExtEnabled = 0;
++ else if (c == '1' || c == 'y' || c == 'Y')
++ linuxExtEnabled = 1;
++
++ return count;
++}
++
++
++static int
++lookupFlag_read(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len;
++
++ len = sprintf(page, "%d\n", lookupCacheEnabled);
++
++ len -= off;
++ *start = page + off;
++
++ if (len > count)
++ len = count;
++ else
++ *eof = 1;
++
++ if (len < 0)
++ len = 0;
++
++ return len;
++}
++static int
++lookupFlag_write(struct file *file, const char *buffer,
++ unsigned long count, void *data)
++{
++ char c;
++ int rc;
++
++ rc = get_user(c, buffer);
++ if (rc)
++ return rc;
++ if (c == '0' || c == 'n' || c == 'N')
++ lookupCacheEnabled = 0;
++ else if (c == '1' || c == 'y' || c == 'Y')
++ lookupCacheEnabled = 1;
++
++ return count;
++}
++static int
++traceSMB_read(char *page, char **start, off_t off, int count,
++ int *eof, void *data)
++{
++ int len;
++
++ len = sprintf(page, "%d\n", traceSMB);
++
++ len -= off;
++ *start = page + off;
++
++ if (len > count)
++ len = count;
++ else
++ *eof = 1;
++
++ if (len < 0)
++ len = 0;
++
++ return len;
++}
++static int
++traceSMB_write(struct file *file, const char *buffer,
++ unsigned long count, void *data)
++{
++ char c;
++ int rc;
++
++ rc = get_user(c, buffer);
++ if (rc)
++ return rc;
++ if (c == '0' || c == 'n' || c == 'N')
++ traceSMB = 0;
++ else if (c == '1' || c == 'y' || c == 'Y')
++ traceSMB = 1;
++
++ return count;
++}
++
++static int
++multiuser_mount_read(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len;
++
++ len = sprintf(page, "%d\n", multiuser_mount);
++
++ len -= off;
++ *start = page + off;
++
++ if (len > count)
++ len = count;
++ else
++ *eof = 1;
++
++ if (len < 0)
++ len = 0;
++
++ return len;
++}
++static int
++multiuser_mount_write(struct file *file, const char *buffer,
++ unsigned long count, void *data)
++{
++ char c;
++ int rc;
++
++ rc = get_user(c, buffer);
++ if (rc)
++ return rc;
++ if (c == '0' || c == 'n' || c == 'N')
++ multiuser_mount = 0;
++ else if (c == '1' || c == 'y' || c == 'Y')
++ multiuser_mount = 1;
++
++ return count;
++}
++
++static int
++extended_security_read(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len;
++
++ len = sprintf(page, "%d\n", extended_security);
++
++ len -= off;
++ *start = page + off;
++
++ if (len > count)
++ len = count;
++ else
++ *eof = 1;
++
++ if (len < 0)
++ len = 0;
++
++ return len;
++}
++static int
++extended_security_write(struct file *file, const char *buffer,
++ unsigned long count, void *data)
++{
++ char c;
++ int rc;
++
++ rc = get_user(c, buffer);
++ if (rc)
++ return rc;
++ if (c == '0' || c == 'n' || c == 'N')
++ extended_security = 0;
++ else if (c == '1' || c == 'y' || c == 'Y')
++ extended_security = 1;
++
++ return count;
++}
++
++static int
++ntlmv2_enabled_read(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len;
++
++ len = sprintf(page, "%d\n", ntlmv2_support);
++
++ len -= off;
++ *start = page + off;
++
++ if (len > count)
++ len = count;
++ else
++ *eof = 1;
++
++ if (len < 0)
++ len = 0;
++
++ return len;
++}
++static int
++ntlmv2_enabled_write(struct file *file, const char *buffer,
++ unsigned long count, void *data)
++{
++ char c;
++ int rc;
++
++ rc = get_user(c, buffer);
++ if (rc)
++ return rc;
++ if (c == '0' || c == 'n' || c == 'N')
++ ntlmv2_support = 0;
++ else if (c == '1' || c == 'y' || c == 'Y')
++ ntlmv2_support = 1;
++
++ return count;
++}
++
++static int
++packet_signing_enabled_read(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ int len;
++
++ len = sprintf(page, "%d\n", sign_CIFS_PDUs);
++
++ len -= off;
++ *start = page + off;
++
++ if (len > count)
++ len = count;
++ else
++ *eof = 1;
++
++ if (len < 0)
++ len = 0;
++
++ return len;
++}
++static int
++packet_signing_enabled_write(struct file *file, const char *buffer,
++ unsigned long count, void *data)
++{
++ char c;
++ int rc;
++
++ rc = get_user(c, buffer);
++ if (rc)
++ return rc;
++ if (c == '0' || c == 'n' || c == 'N')
++ sign_CIFS_PDUs = 0;
++ else if (c == '1' || c == 'y' || c == 'Y')
++ sign_CIFS_PDUs = 1;
++ else if (c == '2')
++ sign_CIFS_PDUs = 2;
++
++ return count;
++}
++
++
++#endif
+diff -urN linux-2.4.29.old/fs/cifs/cifs_debug.h linux-2.4.29/fs/cifs/cifs_debug.h
+--- linux-2.4.29.old/fs/cifs/cifs_debug.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/cifs_debug.h 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,66 @@
++/*
++ *
++ * Copyright (c) International Business Machines Corp., 2000,2002
++ * Modified by Steve French (sfrench@us.ibm.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
++ * the GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++*/
++#define CIFS_DEBUG /* BB temporary */
++
++#ifndef _H_CIFS_DEBUG
++#define _H_CIFS_DEBUG
++
++void cifs_dump_mem(char *label, void *data, int length);
++extern int traceSMB; /* flag which enables the function below */
++void dump_smb(struct smb_hdr *, int);
++
++/*
++ * debug ON
++ * --------
++ */
++#ifdef CIFS_DEBUG
++
++
++/* information message: e.g., configuration, major event */
++extern int cifsFYI;
++#define cifsfyi(format,arg...) if (cifsFYI) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg)
++
++#define cFYI(button,prspec) if (button) cifsfyi prspec
++
++#define cifswarn(format, arg...) printk(KERN_WARNING ": " format "\n" , ## arg)
++
++/* debug event message: */
++extern int cifsERROR;
++
++#define cEVENT(format,arg...) if (cifsERROR) printk(KERN_EVENT __FILE__ ": " format "\n" , ## arg)
++
++/* error event message: e.g., i/o error */
++#define cifserror(format,arg...) if (cifsERROR) printk(KERN_ERR " CIFS VFS: " format "\n" "" , ## arg)
++
++#define cERROR(button, prspec) if (button) cifserror prspec
++
++/*
++ * debug OFF
++ * ---------
++ */
++#else /* _CIFS_DEBUG */
++#define cERROR(button,prspec)
++#define cEVENT(format,arg...)
++#define cFYI(button, prspec)
++#define cifserror(format,arg...)
++#endif /* _CIFS_DEBUG */
++
++#endif /* _H_CIFS_DEBUG */
+diff -urN linux-2.4.29.old/fs/cifs/cifsencrypt.c linux-2.4.29/fs/cifs/cifsencrypt.c
+--- linux-2.4.29.old/fs/cifs/cifsencrypt.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/cifsencrypt.c 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,204 @@
++/*
++ * fs/cifs/cifsencrypt.c
++ *
++ * Copyright (C) International Business Machines Corp., 2003
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/fs.h>
++#include "cifspdu.h"
++#include "cifsglob.h"
++#include "cifs_debug.h"
++#include "md5.h"
++#include "cifs_unicode.h"
++
++/* Calculate and return the CIFS signature based on the mac key and the smb pdu */
++/* the 16 byte signature must be allocated by the caller */
++/* Note we only use the 1st eight bytes */
++/* Note that the smb header signature field on input contains the
++ sequence number before this function is called */
++
++extern void mdfour(unsigned char *out, unsigned char *in, int n);
++extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
++
++static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature)
++{
++ struct MD5Context context;
++
++ if((cifs_pdu == NULL) || (signature == NULL))
++ return -EINVAL;
++
++ MD5Init(&context);
++ MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16);
++ MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length);
++ MD5Final(signature,&context);
++ return 0;
++}
++
++int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses,
++ __u32 * pexpected_response_sequence_number)
++{
++ int rc = 0;
++ char smb_signature[20];
++
++ /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */
++ /* BB remember to add code to save expected sequence number in midQ entry BB */
++
++ if((cifs_pdu == NULL) || (ses == NULL))
++ return -EINVAL;
++
++ if((le32_to_cpu(cifs_pdu->Flags2) & SMBFLG2_SECURITY_SIGNATURE) == 0)
++ return rc;
++
++ spin_lock(&GlobalMid_Lock);
++ cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number);
++ cifs_pdu->Signature.Sequence.Reserved = 0;
++
++ *pexpected_response_sequence_number = ses->sequence_number++;
++ ses->sequence_number++;
++ spin_unlock(&GlobalMid_Lock);
++
++ rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature);
++ if(rc)
++ memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
++ else
++ memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
++
++ return rc;
++}
++
++int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key,
++ __u32 expected_sequence_number)
++{
++ unsigned int rc;
++ char server_response_sig[8];
++ char what_we_think_sig_should_be[20];
++
++ if((cifs_pdu == NULL) || (mac_key == NULL))
++ return -EINVAL;
++
++ if (cifs_pdu->Command == SMB_COM_NEGOTIATE)
++ return 0;
++
++ if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
++ struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)cifs_pdu;
++ if(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
++ return 0;
++ }
++
++ /* BB what if signatures are supposed to be on for session but server does not
++ send one? BB */
++
++ /* Do not need to verify session setups with signature "BSRSPYL " */
++ if(memcmp(cifs_pdu->Signature.SecuritySignature,"BSRSPYL ",8)==0)
++ cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command));
++
++ expected_sequence_number = cpu_to_le32(expected_sequence_number);
++
++ /* save off the origiginal signature so we can modify the smb and check
++ its signature against what the server sent */
++ memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8);
++
++ cifs_pdu->Signature.Sequence.SequenceNumber = expected_sequence_number;
++ cifs_pdu->Signature.Sequence.Reserved = 0;
++
++ rc = cifs_calculate_signature(cifs_pdu, mac_key,
++ what_we_think_sig_should_be);
++
++ if(rc)
++ return rc;
++
++
++/* cifs_dump_mem("what we think it should be: ",what_we_think_sig_should_be,16); */
++
++ if(memcmp(server_response_sig, what_we_think_sig_should_be, 8))
++ return -EACCES;
++ else
++ return 0;
++
++}
++
++/* We fill in key by putting in 40 byte array which was allocated by caller */
++int cifs_calculate_mac_key(char * key, const char * rn, const char * password)
++{
++ char temp_key[16];
++ if ((key == NULL) || (rn == NULL))
++ return -EINVAL;
++
++ E_md4hash(password, temp_key);
++ mdfour(key,temp_key,16);
++ memcpy(key+16,rn, CIFS_SESSION_KEY_SIZE);
++ return 0;
++}
++
++int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info)
++{
++ char temp_hash[16];
++ struct HMACMD5Context ctx;
++ char * ucase_buf;
++ wchar_t * unicode_buf;
++ unsigned int i,user_name_len,dom_name_len;
++
++ if(ses)
++ return -EINVAL;
++
++ E_md4hash(ses->password, temp_hash);
++
++ hmac_md5_init_limK_to_64(temp_hash, 16, &ctx);
++ user_name_len = strlen(ses->userName);
++ if(user_name_len > MAX_USERNAME_SIZE)
++ return -EINVAL;
++ dom_name_len = strlen(ses->domainName);
++ if(dom_name_len > MAX_USERNAME_SIZE)
++ return -EINVAL;
++
++ ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL);
++ unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL);
++
++ for(i=0;i<user_name_len;i++)
++ ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]];
++ ucase_buf[i] = 0;
++ user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info);
++ unicode_buf[user_name_len] = 0;
++ user_name_len++;
++
++ for(i=0;i<dom_name_len;i++)
++ ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]];
++ ucase_buf[i] = 0;
++ dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info);
++
++ unicode_buf[user_name_len + dom_name_len] = 0;
++ hmac_md5_update((const unsigned char *) unicode_buf,
++ (user_name_len+dom_name_len)*2,&ctx);
++
++ hmac_md5_final(ses->mac_signing_key,&ctx);
++ kfree(ucase_buf);
++ kfree(unicode_buf);
++ return 0;
++}
++void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response)
++{
++ struct HMACMD5Context context;
++ memcpy(v2_session_response + 8, ses->server->cryptKey,8);
++ /* gen_blob(v2_session_response + 16); */
++ hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context);
++
++ hmac_md5_update(ses->server->cryptKey,8,&context);
++/* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */
++
++ hmac_md5_final(v2_session_response,&context);
++}
+diff -urN linux-2.4.29.old/fs/cifs/cifserr.c linux-2.4.29/fs/cifs/cifserr.c
+--- linux-2.4.29.old/fs/cifs/cifserr.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/cifserr.c 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,70 @@
++/*
++ * fs/cifserr.c
++ *
++ * Copyright (c) International Business Machines Corp., 2002
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/smbno.h>
++#include "cifsfs.h"
++
++int map_cifs_error(int error_class, int error_code,
++ int status_codes_negotiated)
++{
++
++
++ if (status_codes_negotiated) {
++ switch (error_code) {
++ default:
++ return EIO;
++ }
++ } else
++ switch (error_class) {
++ case SUCCESS:
++ return 0;
++
++ case ERRDOS:
++ switch (error_code) {
++ case ERRbadfunc:
++ return EINVAL;
++ default:
++ return EIO;
++ }
++
++ case ERRSRV:
++ switch (error_code) {
++ default:
++ return EIO;
++ }
++
++ case ERRHRD:
++ switch (error_code) {
++ default:
++ return EIO;
++ }
++ default:
++ return EIO;
++ }
++ return 0;
++}
++
++int map_smb_error(int error_class, int error_code)
++{
++ return map_cifs_error(error_class, error_code, FALSE);
++}
+diff -urN linux-2.4.29.old/fs/cifs/cifsfs.c linux-2.4.29/fs/cifs/cifsfs.c
+--- linux-2.4.29.old/fs/cifs/cifsfs.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/cifsfs.c 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,769 @@
++/*
++ * fs/cifs/cifsfs.c
++ *
++ * Copyright (C) International Business Machines Corp., 2002,2004
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * Common Internet FileSystem (CIFS) client
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/* Note that BB means BUGBUG (ie something to fix eventually) */
++
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/mount.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/version.h>
++#include <linux/list.h>
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15))
++#include <linux/seq_file.h>
++#endif
++#include <linux/vfs.h>
++#include "cifsfs.h"
++#include "cifspdu.h"
++#define DECLARE_GLOBALS_HERE
++#include "cifsglob.h"
++#include "cifsproto.h"
++#include "cifs_debug.h"
++#include "cifs_fs_sb.h"
++#include <linux/mm.h>
++#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
++/* BB when mempool_resize is added back in, we will resize pool on new mount */
++#define CIFS_MIN_RCV_POOL 11 /* enough for progress to five servers */
++
++#ifdef CONFIG_CIFS_QUOTA
++static struct quotactl_ops cifs_quotactl_ops;
++#endif
++
++extern struct file_system_type cifs_fs_type;
++
++int cifsFYI = 0;
++int cifsERROR = 1;
++int traceSMB = 0;
++unsigned int oplockEnabled = 1;
++unsigned int quotaEnabled = 0;
++unsigned int linuxExtEnabled = 1;
++unsigned int lookupCacheEnabled = 1;
++unsigned int multiuser_mount = 0;
++unsigned int extended_security = 0;
++unsigned int ntlmv2_support = 0;
++unsigned int sign_CIFS_PDUs = 1;
++unsigned int CIFSMaximumBufferSize = CIFS_MAX_MSGSIZE;
++struct task_struct * oplockThread = NULL;
++
++extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
++ const char *);
++extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
++void cifs_proc_init(void);
++void cifs_proc_clean(void);
++
++static DECLARE_COMPLETION(cifs_oplock_exited);
++
++
++struct super_block *
++cifs_read_super(struct super_block *sb, void *data, int silent)
++{
++ struct inode *inode;
++ struct cifs_sb_info *cifs_sb;
++ int rc = 0;
++
++ sb->s_flags |= MS_NODIRATIME; /* and probably even noatime */
++ cifs_sb = CIFS_SB(sb);
++ if(cifs_sb == NULL)
++ return 0;
++ else
++ memset(cifs_sb,0,sizeof(struct cifs_sb_info));
++
++
++ rc = cifs_mount(sb, cifs_sb, data, NULL);
++
++ if (rc) {
++ if (!silent)
++ cERROR(1,
++ ("cifs_mount failed w/return code = %d", rc));
++ goto out_mount_failed;
++ }
++
++ sb->s_magic = CIFS_MAGIC_NUMBER;
++ sb->s_op = &cifs_super_ops;
++/* if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
++ sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
++#ifdef CONFIG_CIFS_QUOTA
++ sb->s_qcop = &cifs_quotactl_ops;
++#endif
++ sb->s_blocksize = CIFS_MAX_MSGSIZE;
++ sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */
++ inode = iget(sb, ROOT_I);
++
++ if (!inode) {
++ goto out_no_root;
++ }
++
++ sb->s_root = d_alloc_root(inode);
++
++ if (!sb->s_root) {
++ goto out_no_root;
++ }
++
++ return sb;
++
++out_no_root:
++ cERROR(1, ("cifs_read_super: get root inode failed"));
++ if (inode)
++ iput(inode);
++
++out_mount_failed:
++ if(cifs_sb->local_nls)
++ unload_nls(cifs_sb->local_nls);
++ sb->s_dev = 0;
++ return 0;
++}
++
++static void
++cifs_put_super(struct super_block *sb)
++{
++ int rc = 0;
++ struct cifs_sb_info *cifs_sb;
++
++ cFYI(1, ("In cifs_put_super"));
++ cifs_sb = CIFS_SB(sb);
++ if(cifs_sb == NULL) {
++ cFYI(1,("Empty cifs superblock info passed to unmount"));
++ return;
++ }
++ rc = cifs_umount(sb, cifs_sb);
++ if (rc) {
++ cERROR(1, ("cifs_umount failed with return code %d", rc));
++ }
++ unload_nls(cifs_sb->local_nls);
++ return;
++}
++
++static int
++cifs_statfs(struct super_block *sb, struct statfs *buf)
++{
++ int xid, rc;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++
++ xid = GetXid();
++
++ cifs_sb = CIFS_SB(sb);
++ pTcon = cifs_sb->tcon;
++
++ buf->f_type = CIFS_MAGIC_NUMBER;
++
++ /* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */
++ buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would presumably
++ be length of total path, note that some servers may be
++ able to support more than this, but best to be safe
++ since Win2k and others can not handle very long filenames */
++ buf->f_files = 0; /* undefined */
++ buf->f_ffree = 0; /* unlimited */
++
++ rc = CIFSSMBQFSInfo(xid, pTcon, buf, cifs_sb->local_nls);
++
++ /*
++ int f_type;
++ __fsid_t f_fsid;
++ int f_namelen; */
++ /* BB get from info put in tcon struct at mount time with call to QFSAttrInfo */
++ FreeXid(xid);
++ return 0; /* always return success? what if volume is no longer available? */
++}
++
++static int cifs_permission(struct inode * inode, int mask)
++{
++ /* the server does permission checks, we do not need to do it here */
++ return 0;
++}
++
++kmem_cache_t *cifs_req_cachep;
++kmem_cache_t *cifs_mid_cachep;
++kmem_cache_t *cifs_oplock_cachep;
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
++static struct inode *
++cifs_alloc_inode(struct super_block *sb)
++{
++ struct cifsInodeInfo *cifs_inode;
++ cifs_inode =
++ (struct cifsInodeInfo *) kmem_cache_alloc(cifs_inode_cachep,
++ SLAB_KERNEL);
++ if (!cifs_inode)
++ return NULL;
++ cifs_inode->cifsAttrs = 0x20; /* default */
++ atomic_set(&cifs_inode->inUse, 0);
++ cifs_inode->time = 0;
++ /* Until the file is open and we have gotten oplock
++ info back from the server, can not assume caching of
++ file data or metadata */
++ cifs_inode->clientCanCacheRead = FALSE;
++ cifs_inode->clientCanCacheAll = FALSE;
++ INIT_LIST_HEAD(&cifs_inode->openFileList);
++ return &cifs_inode->vfs_inode;
++}
++
++static void
++cifs_destroy_inode(struct inode *inode)
++{
++ kmem_cache_free(cifs_inode_cachep, CIFS_I(inode));
++}
++#endif
++
++/*
++ * cifs_show_options() is for displaying mount options in /proc/mounts.
++ * Not all settable options are displayed but most of the important
++ * ones are.
++ */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15))
++static int
++cifs_show_options(struct seq_file *s, struct vfsmount *m)
++{
++ struct cifs_sb_info *cifs_sb;
++
++ cifs_sb = CIFS_SB(m->mnt_sb);
++
++ if (cifs_sb) {
++ if (cifs_sb->tcon) {
++ seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
++ if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->userName))
++ seq_printf(s, ",username=%s",
++ cifs_sb->tcon->ses->userName);
++ if(cifs_sb->tcon->ses->domainName)
++ seq_printf(s, ",domain=%s",
++ cifs_sb->tcon->ses->domainName);
++ }
++ seq_printf(s, ",rsize=%d",cifs_sb->rsize);
++ seq_printf(s, ",wsize=%d",cifs_sb->wsize);
++ }
++ return 0;
++}
++#endif
++
++#ifdef CONFIG_CIFS_QUOTA
++int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid,
++ struct fs_disk_quota * pdquota)
++{
++ int xid;
++ int rc = 0;
++ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
++ struct cifsTconInfo *pTcon;
++
++ if(cifs_sb)
++ pTcon = cifs_sb->tcon;
++ else
++ return -EIO;
++
++
++ xid = GetXid();
++ if(pTcon) {
++ cFYI(1,("set type: 0x%x id: %d",quota_type,qid));
++ } else {
++ return -EIO;
++ }
++
++ FreeXid(xid);
++ return rc;
++}
++
++int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid,
++ struct fs_disk_quota * pdquota)
++{
++ int xid;
++ int rc = 0;
++ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
++ struct cifsTconInfo *pTcon;
++
++ if(cifs_sb)
++ pTcon = cifs_sb->tcon;
++ else
++ return -EIO;
++
++ xid = GetXid();
++ if(pTcon) {
++ cFYI(1,("set type: 0x%x id: %d",quota_type,qid));
++ } else {
++ rc = -EIO;
++ }
++
++ FreeXid(xid);
++ return rc;
++}
++
++int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation)
++{
++ int xid;
++ int rc = 0;
++ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
++ struct cifsTconInfo *pTcon;
++
++ if(cifs_sb)
++ pTcon = cifs_sb->tcon;
++ else
++ return -EIO;
++
++ xid = GetXid();
++ if(pTcon) {
++ cFYI(1,("flags: 0x%x operation: 0x%x",flags,operation));
++ } else {
++ rc = -EIO;
++ }
++
++ FreeXid(xid);
++ return rc;
++}
++
++int cifs_xstate_get(struct super_block * sb, struct fs_quota_stat *qstats)
++{
++ int xid;
++ int rc = 0;
++ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
++ struct cifsTconInfo *pTcon;
++
++ if(cifs_sb) {
++ pTcon = cifs_sb->tcon;
++ } else {
++ return -EIO;
++ }
++ xid = GetXid();
++ if(pTcon) {
++ cFYI(1,("pqstats %p",qstats));
++ } else {
++ rc = -EIO;
++ }
++
++ FreeXid(xid);
++ return rc;
++}
++
++static struct quotactl_ops cifs_quotactl_ops = {
++ .set_xquota = cifs_xquota_set,
++ .get_xquota = cifs_xquota_set,
++ .set_xstate = cifs_xstate_set,
++ .get_xstate = cifs_xstate_get,
++};
++#endif
++
++static int cifs_remount(struct super_block *sb, int *flags, char *data)
++{
++ *flags |= MS_NODIRATIME;
++ return 0;
++}
++
++struct super_operations cifs_super_ops = {
++ .read_inode = cifs_read_inode,
++ .put_super = cifs_put_super,
++ .statfs = cifs_statfs,
++/* .alloc_inode = cifs_alloc_inode,
++ .destroy_inode = cifs_destroy_inode, */
++/* .drop_inode = generic_delete_inode,
++ .delete_inode = cifs_delete_inode, *//* Do not need the above two functions
++ unless later we add lazy close of inodes or unless the kernel forgets to call
++ us with the same number of releases (closes) as opens */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15))
++ .show_options = cifs_show_options,
++#endif
++/* .umount_begin = cifs_umount_begin, *//* consider adding in the future */
++};
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
++static struct super_block *
++cifs_get_sb(struct file_system_type *fs_type,
++ int flags, const char *dev_name, void *data)
++{
++ int rc;
++ struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL);
++
++ cFYI(1, ("Devname: %s flags: %d ", dev_name, flags));
++
++ if (IS_ERR(sb))
++ return sb;
++
++ sb->s_flags = flags;
++
++ rc = cifs_read_super(sb, data, dev_name, flags & MS_VERBOSE ? 1 : 0);
++ if (rc) {
++ up_write(&sb->s_umount);
++ deactivate_super(sb);
++ return ERR_PTR(rc);
++ }
++ sb->s_flags |= MS_ACTIVE;
++ return sb;
++}
++#endif
++
++static ssize_t
++cifs_read_wrapper(struct file * file, char *read_data, size_t read_size,
++ loff_t * poffset)
++{
++ if(file == NULL)
++ return -EIO;
++ else if(file->f_dentry == NULL)
++ return -EIO;
++ else if(file->f_dentry->d_inode == NULL)
++ return -EIO;
++
++ if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) {
++ return generic_file_read(file,read_data,read_size,poffset);
++ } else {
++ /* BB do we need to lock inode from here until after invalidate? */
++/* if(file->f_dentry->d_inode->i_mapping) {
++ filemap_fdatawrite(file->f_dentry->d_inode->i_mapping);
++ filemap_fdatawait(file->f_dentry->d_inode->i_mapping);
++ }*/
++/* cifs_revalidate(file->f_dentry);*/ /* BB fixme */
++
++ /* BB we should make timer configurable - perhaps
++ by simply calling cifs_revalidate here */
++ /* invalidate_remote_inode(file->f_dentry->d_inode);*/
++ return generic_file_read(file,read_data,read_size,poffset);
++ }
++}
++
++static ssize_t
++cifs_write_wrapper(struct file * file, const char *write_data,
++ size_t write_size, loff_t * poffset)
++{
++ ssize_t written;
++
++ if(file == NULL)
++ return -EIO;
++ else if(file->f_dentry == NULL)
++ return -EIO;
++ else if(file->f_dentry->d_inode == NULL)
++ return -EIO;
++
++ /* check whether we can cache writes locally */
++ written = generic_file_write(file,write_data,write_size,poffset);
++ if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) {
++ if(file->f_dentry->d_inode->i_mapping) {
++ filemap_fdatasync(file->f_dentry->d_inode->i_mapping);
++ }
++ }
++ return written;
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
++static struct file_system_type cifs_fs_type = {
++ .owner = THIS_MODULE,
++ .name = "cifs",
++ .get_sb = cifs_get_sb,
++ .kill_sb = kill_anon_super,
++ /* .fs_flags */
++};
++#endif
++
++static DECLARE_FSTYPE(cifs_fs_type, "cifs", cifs_read_super,0);
++
++
++struct inode_operations cifs_dir_inode_ops = {
++ .create = cifs_create,
++ .lookup = cifs_lookup,
++ .unlink = cifs_unlink,
++ .link = cifs_hardlink,
++ .mkdir = cifs_mkdir,
++ .rmdir = cifs_rmdir,
++ .rename = cifs_rename,
++ .permission = cifs_permission,
++ .revalidate = cifs_revalidate,
++ .setattr = cifs_setattr,
++ .symlink = cifs_symlink,
++ .mknod = cifs_mknod,
++};
++
++struct inode_operations cifs_file_inode_ops = {
++ .revalidate = cifs_revalidate,
++ .setattr = cifs_setattr,
++/* .getattr = cifs_getattr,*/
++ .rename = cifs_rename,
++ .permission = cifs_permission,
++#ifdef CONFIG_CIFS_XATTR
++ .setxattr = cifs_setxattr,
++ .getxattr = cifs_getxattr,
++ .listxattr = cifs_listxattr,
++ .removexattr = cifs_removexattr,
++#endif
++};
++
++struct inode_operations cifs_symlink_inode_ops = {
++ .readlink = cifs_readlink,
++ .follow_link = cifs_follow_link,
++ .permission = cifs_permission,
++ /* BB add the following two eventually */
++ /* revalidate: cifs_revalidate,
++ setattr: cifs_notify_change, *//* BB do we need notify change */
++#ifdef CONFIG_CIFS_XATTR
++ .setxattr = cifs_setxattr,
++ .getxattr = cifs_getxattr,
++ .listxattr = cifs_listxattr,
++ .removexattr = cifs_removexattr,
++#endif
++};
++
++struct file_operations cifs_file_ops = {
++ .read = cifs_read_wrapper,
++ .write = cifs_write_wrapper,
++ .open = cifs_open,
++ .release = cifs_close,
++ .lock = cifs_lock,
++ .fsync = cifs_fsync,
++ .flush = cifs_flush,
++ .mmap = cifs_file_mmap,
++/* .sendfile = generic_file_sendfile,*/
++#ifdef CONFIG_CIFS_FCNTL
++ .fcntl = cifs_fcntl,
++#endif
++};
++
++struct file_operations cifs_dir_ops = {
++ .readdir = cifs_readdir,
++ .release = cifs_closedir,
++ .read = generic_read_dir,
++#ifdef CONFIG_CIFS_FCNTL
++ .fcntl = cifs_fcntl,
++#endif
++};
++/*
++static void
++cifs_init_once(void *inode, kmem_cache_t * cachep, unsigned long flags)
++{
++ struct cifsInodeInfo *cifsi = (struct cifsInodeInfo *) inode;
++
++ if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
++ SLAB_CTOR_CONSTRUCTOR) {
++ inode_init_once(&cifsi->vfs_inode);
++ INIT_LIST_HEAD(&cifsi->lockList);
++ }
++}
++
++static int
++cifs_init_inodecache(void)
++{
++ cifs_inode_cachep = kmem_cache_create("cifs_inode_cache",
++ sizeof (struct cifsInodeInfo),
++ 0, SLAB_HWCACHE_ALIGN,
++ cifs_init_once, NULL);
++ if (cifs_inode_cachep == NULL)
++ return -ENOMEM;
++
++
++ return 0;
++}
++
++static void
++cifs_destroy_inodecache(void)
++{
++ if (kmem_cache_destroy(cifs_inode_cachep))
++ printk(KERN_WARNING "cifs_inode_cache: error freeing\n");
++} */
++
++static int
++cifs_init_request_bufs(void)
++{
++ cifs_req_cachep = kmem_cache_create("cifs_request",
++ CIFS_MAX_MSGSIZE +
++ MAX_CIFS_HDR_SIZE, 0,
++ SLAB_HWCACHE_ALIGN, NULL, NULL);
++ if (cifs_req_cachep == NULL)
++ return -ENOMEM;
++
++ return 0;
++}
++
++static void
++cifs_destroy_request_bufs(void)
++{
++ if (kmem_cache_destroy(cifs_req_cachep))
++ printk(KERN_WARNING
++ "cifs_destroy_request_cache: error not all structures were freed\n");
++}
++
++static int
++cifs_init_mids(void)
++{
++ cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids",
++ sizeof (struct mid_q_entry), 0,
++ SLAB_HWCACHE_ALIGN, NULL, NULL);
++ if (cifs_mid_cachep == NULL)
++ return -ENOMEM;
++ cifs_oplock_cachep = kmem_cache_create("cifs_oplock_struct",
++ sizeof (struct oplock_q_entry), 0,
++ SLAB_HWCACHE_ALIGN, NULL, NULL);
++ if (cifs_oplock_cachep == NULL) {
++ kmem_cache_destroy(cifs_mid_cachep);
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++static void
++cifs_destroy_mids(void)
++{
++ if (kmem_cache_destroy(cifs_mid_cachep))
++ printk(KERN_WARNING
++ "cifs_destroy_mids: error not all structures were freed\n");
++ if (kmem_cache_destroy(cifs_oplock_cachep))
++ printk(KERN_WARNING
++ "error not all oplock structures were freed\n");
++}
++
++static int cifs_oplock_thread(void * dummyarg)
++{
++ struct oplock_q_entry * oplock_item;
++ struct cifsTconInfo *pTcon;
++ struct inode * inode;
++ __u16 netfid;
++ int rc = 0;
++
++ daemonize();
++ sprintf(current->comm,"cifsoplockd");
++
++ oplockThread = current;
++ do {
++ set_current_state(TASK_INTERRUPTIBLE);
++
++ schedule_timeout(1*HZ);
++ spin_lock(&GlobalMid_Lock);
++ if(list_empty(&GlobalOplock_Q)) {
++ spin_unlock(&GlobalMid_Lock);
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(39*HZ);
++ } else {
++ oplock_item = list_entry(GlobalOplock_Q.next,
++ struct oplock_q_entry, qhead);
++ if(oplock_item) {
++ cFYI(1,("found oplock item to write out"));
++ pTcon = oplock_item->tcon;
++ inode = oplock_item->pinode;
++ netfid = oplock_item->netfid;
++ spin_unlock(&GlobalMid_Lock);
++ DeleteOplockQEntry(oplock_item);
++ /* can not grab inode sem here since it would
++ deadlock when oplock received on delete
++ since vfs_unlink holds the i_sem across
++ the call */
++ /* down(&inode->i_sem);*/
++ if (S_ISREG(inode->i_mode)) {
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17))
++ rc = filemap_fdatasync(inode->i_mapping);
++ if(rc)
++ CIFS_I(inode)->write_behind_rc = rc;
++#else
++ filemap_fdatasync(inode->i_mapping);
++#endif
++ if(CIFS_I(inode)->clientCanCacheRead == 0)
++ invalidate_inode_pages(inode);
++ } else
++ rc = 0;
++ /* releasing a stale oplock after recent reconnection
++ of smb session using a now incorrect file
++ handle is not a data integrity issue but do
++ not bother sending an oplock release if session
++ to server still is disconnected since oplock
++ already released by the server in that case */
++ if(pTcon->tidStatus != CifsNeedReconnect) {
++ rc = CIFSSMBLock(0, pTcon,
++ netfid,
++ 0 /* len */ , 0 /* offset */, 0,
++ 0, LOCKING_ANDX_OPLOCK_RELEASE,
++ 0 /* wait flag */);
++ cFYI(1,("Oplock release rc = %d ",rc));
++ }
++ } else
++ spin_unlock(&GlobalMid_Lock);
++ }
++ } while(!signal_pending(current));
++ complete_and_exit (&cifs_oplock_exited, 0);
++}
++
++static int __init
++init_cifs(void)
++{
++ int rc = 0;
++#if CONFIG_PROC_FS
++ cifs_proc_init();
++#endif
++ INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */
++ INIT_LIST_HEAD(&GlobalSMBSessionList);
++ INIT_LIST_HEAD(&GlobalTreeConnectionList);
++ INIT_LIST_HEAD(&GlobalOplock_Q);
++/*
++ * Initialize Global counters
++ */
++ atomic_set(&sesInfoAllocCount, 0);
++ atomic_set(&tconInfoAllocCount, 0);
++ atomic_set(&tcpSesReconnectCount, 0);
++ atomic_set(&tconInfoReconnectCount, 0);
++
++ atomic_set(&bufAllocCount, 0);
++ atomic_set(&midCount, 0);
++ GlobalCurrentXid = 0;
++ GlobalTotalActiveXid = 0;
++ GlobalMaxActiveXid = 0;
++ GlobalSMBSeslock = RW_LOCK_UNLOCKED;
++ GlobalMid_Lock = SPIN_LOCK_UNLOCKED;
++
++/* rc = cifs_init_inodecache();*/
++ if (!rc) {
++ rc = cifs_init_mids();
++ if (!rc) {
++ rc = cifs_init_request_bufs();
++ if (!rc) {
++ rc = register_filesystem(&cifs_fs_type);
++ if (!rc) {
++ kernel_thread(cifs_oplock_thread, NULL,
++ CLONE_FS | CLONE_FILES | CLONE_VM);
++ return rc; /* Success */
++ } else
++ cifs_destroy_request_bufs();
++ }
++ cifs_destroy_mids();
++ }
++/* cifs_destroy_inodecache(); */
++ }
++#if CONFIG_PROC_FS
++ cifs_proc_clean();
++#endif
++ return rc;
++}
++
++static void __exit
++exit_cifs(void)
++{
++ cFYI(0, ("In unregister ie exit_cifs"));
++#if CONFIG_PROC_FS
++ cifs_proc_clean();
++#endif
++ unregister_filesystem(&cifs_fs_type);
++/* cifs_destroy_inodecache();*/
++ cifs_destroy_mids();
++ cifs_destroy_request_bufs();
++ if(oplockThread) {
++ send_sig(SIGTERM, oplockThread, 1);
++ wait_for_completion(&cifs_oplock_exited);
++ }
++}
++
++MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
++MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */
++MODULE_DESCRIPTION
++ ("VFS to access servers complying with the SNIA CIFS Specification e.g. Samba and Windows");
++module_init(init_cifs)
++module_exit(exit_cifs)
+diff -urN linux-2.4.29.old/fs/cifs/cifsfs.h linux-2.4.29/fs/cifs/cifsfs.h
+--- linux-2.4.29.old/fs/cifs/cifsfs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/cifsfs.h 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,97 @@
++/*
++ * fs/cifs/cifsfs.h
++ *
++ * Copyright (c) International Business Machines Corp., 2002
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef _CIFSFS_H
++#define _CIFSFS_H
++
++#define ROOT_I 2
++
++#ifndef FALSE
++#define FALSE 0
++#endif
++
++#ifndef TRUE
++#define TRUE 1
++#endif
++
++extern int map_cifs_error(int error_class, int error_code,
++ int status_codes_negotiated);
++
++extern struct address_space_operations cifs_addr_ops;
++
++/* Functions related to super block operations */
++extern struct super_operations cifs_super_ops;
++extern void cifs_put_inode(struct inode *);
++extern void cifs_read_inode(struct inode *);
++extern void cifs_delete_inode(struct inode *);
++/* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */
++
++/* Functions related to inodes */
++extern struct inode_operations cifs_dir_inode_ops;
++extern int cifs_create(struct inode *, struct dentry *, int);
++extern struct dentry *cifs_lookup(struct inode *, struct dentry *);
++extern int cifs_unlink(struct inode *, struct dentry *);
++extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
++extern int cifs_mknod(struct inode *, struct dentry *, int, int);
++extern int cifs_mkdir(struct inode *, struct dentry *, int);
++extern int cifs_rmdir(struct inode *, struct dentry *);
++extern int cifs_rename(struct inode *, struct dentry *, struct inode *,
++ struct dentry *);
++extern int cifs_revalidate(struct dentry *);
++extern int cifs_setattr(struct dentry *, struct iattr *);
++
++extern struct inode_operations cifs_file_inode_ops;
++extern void cifs_truncate_file(struct inode *);
++extern struct inode_operations cifs_symlink_inode_ops;
++
++/* Functions related to files and directories */
++extern struct file_operations cifs_file_ops;
++extern int cifs_open(struct inode *inode, struct file *file);
++extern int cifs_close(struct inode *inode, struct file *file);
++extern int cifs_closedir(struct inode *inode, struct file *file);
++extern ssize_t cifs_read(struct file *file, char *read_data,
++ size_t read_size, loff_t * poffset);
++extern ssize_t cifs_write(struct file *file, const char *write_data,
++ size_t write_size, loff_t * poffset);
++extern int cifs_lock(struct file *, int, struct file_lock *);
++extern int cifs_fsync(struct file *, struct dentry *, int);
++extern int cifs_flush(struct file *);
++extern int cifs_file_mmap(struct file * , struct vm_area_struct *);
++extern struct file_operations cifs_dir_ops;
++extern int cifs_dir_open(struct inode *inode, struct file *file);
++extern int cifs_readdir(struct file *file, void *direntry, filldir_t filldir);
++extern long cifs_fcntl(int, unsigned int, unsigned long, struct file *);
++
++/* Functions related to dir entries */
++extern struct dentry_operations cifs_dentry_ops;
++
++/* Functions related to symlinks */
++extern int cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
++extern int cifs_readlink(struct dentry *direntry, char *buffer, int buflen);
++extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
++ const char *symname);
++extern int cifs_removexattr(struct dentry *, const char *);
++extern int cifs_setxattr(struct dentry *, const char *, const void *,
++ size_t, int);
++extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
++extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
++#define CIFS_VERSION "1.20"
++#endif /* _CIFSFS_H */
+diff -urN linux-2.4.29.old/fs/cifs/cifs_fs_sb.h linux-2.4.29/fs/cifs/cifs_fs_sb.h
+--- linux-2.4.29.old/fs/cifs/cifs_fs_sb.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/cifs_fs_sb.h 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,32 @@
++/*
++ * fs/cifs/cifs_fs_sb.h
++ *
++ * Copyright (c) International Business Machines Corp., 2002
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ */
++#ifndef _CIFS_FS_SB_H
++#define _CIFS_FS_SB_H
++
++struct cifs_sb_info {
++ struct cifsTconInfo *tcon; /* primary mount */
++ struct list_head nested_tcon_q;
++ struct nls_table *local_nls;
++ unsigned int rsize;
++ unsigned int wsize;
++ uid_t mnt_uid;
++ gid_t mnt_gid;
++ mode_t mnt_file_mode;
++ mode_t mnt_dir_mode;
++};
++#endif /* _CIFS_FS_SB_H */
+diff -urN linux-2.4.29.old/fs/cifs/cifsglob.h linux-2.4.29/fs/cifs/cifsglob.h
+--- linux-2.4.29.old/fs/cifs/cifsglob.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/cifsglob.h 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,413 @@
++/*
++ * fs/cifs/cifsglob.h
++ *
++ * Copyright (C) International Business Machines Corp., 2002,2003
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ */
++#include <linux/in.h>
++#include <linux/in6.h>
++#include "cifs_fs_sb.h"
++/*
++ * The sizes of various internal tables and strings
++ */
++#define MAX_UID_INFO 16
++#define MAX_SES_INFO 2
++#define MAX_TCON_INFO 4
++
++#define MAX_TREE_SIZE 2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1
++#define MAX_SERVER_SIZE 15
++#define MAX_SHARE_SIZE 64 /* used to be 20 - this should still be enough */
++#define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null
++ termination then *2 for unicode versions */
++#define MAX_PASSWORD_SIZE 16
++
++/*
++ * MAX_REQ is the maximum number of requests that WE will send
++ * on one socket concurently. It also matches the most common
++ * value of max multiplex returned by servers. We may
++ * eventually want to use the negotiated value (in case
++ * future servers can handle more) when we are more confident that
++ * we will not have problems oveloading the socket with pending
++ * write data.
++ */
++#define CIFS_MAX_REQ 50
++
++#define SERVER_NAME_LENGTH 15
++#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1)
++
++/* used to define string lengths for reversing unicode strings */
++/* (256+1)*2 = 514 */
++/* (max path length + 1 for null) * 2 for unicode */
++#define MAX_NAME 514
++
++#include "cifspdu.h"
++
++#ifndef FALSE
++#define FALSE 0
++#endif
++
++#ifndef TRUE
++#define TRUE 1
++#endif
++
++#ifndef XATTR_DOS_ATTRIB
++#define XATTR_DOS_ATTRIB "user.DOSATTRIB"
++#endif
++
++/*
++ * This information is kept on every Server we know about.
++ *
++ * Some things to note:
++ *
++ */
++#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1)
++
++/*
++ * CIFS vfs client Status information (based on what we know.)
++ */
++
++ /* associated with each tcp and smb session */
++enum statusEnum {
++ CifsNew = 0,
++ CifsGood,
++ CifsExiting,
++ CifsNeedReconnect
++};
++
++enum securityEnum {
++ NTLM = 0, /* Legacy NTLM012 auth with NTLM hash */
++ NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */
++ RawNTLMSSP, /* NTLMSSP without SPNEGO */
++ NTLMSSP, /* NTLMSSP via SPNEGO */
++ Kerberos /* Kerberos via SPNEGO */
++};
++
++enum protocolEnum {
++ IPV4 = 0,
++ IPV6,
++ SCTP
++ /* Netbios frames protocol not supported at this time */
++};
++
++/*
++ *****************************************************************
++ * Except the CIFS PDUs themselves all the
++ * globally interesting structs should go here
++ *****************************************************************
++ */
++
++struct TCP_Server_Info {
++ char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20'in 16th */
++ char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; /* Unicode version of server_Name */
++ struct socket *ssocket;
++ union {
++ struct sockaddr_in sockAddr;
++ struct sockaddr_in6 sockAddr6;
++ } addr;
++ wait_queue_head_t response_q;
++ wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
++ struct list_head pending_mid_q;
++ void *Server_NlsInfo; /* BB - placeholder for future NLS info */
++ unsigned short server_codepage; /* codepage for the server */
++ unsigned long ip_address; /* IP addr for the server if known */
++ enum protocolEnum protocolType;
++ char versionMajor;
++ char versionMinor;
++ int svlocal:1; /* local server or remote */
++ atomic_t socketUseCount; /* number of open cifs sessions on socket */
++ atomic_t inFlight; /* number of requests on the wire to server */
++ enum statusEnum tcpStatus; /* what we think the status is */
++ struct semaphore tcpSem;
++ struct task_struct *tsk;
++ char server_GUID[16];
++ char secMode;
++ enum securityEnum secType;
++ unsigned int maxReq; /* Clients should submit no more */
++ /* than maxReq distinct unanswered SMBs to the server when using */
++ /* multiplexed reads or writes */
++ unsigned int maxBuf; /* maxBuf specifies the maximum */
++ /* message size the server can send or receive for non-raw SMBs */
++ unsigned int maxRw; /* maxRw specifies the maximum */
++ /* message size the server can send or receive for */
++ /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */
++ char sessid[4]; /* unique token id for this session */
++ /* (returned on Negotiate */
++ int capabilities; /* allow selective disabling of caps by smb sess */
++ __u16 timeZone;
++ char cryptKey[CIFS_CRYPTO_KEY_SIZE];
++ char workstation_RFC1001_name[16]; /* 16th byte is always zero */
++};
++
++/*
++ * The following is our shortcut to user information. We surface the uid,
++ * and name. We always get the password on the fly in case it
++ * has changed. We also hang a list of sessions owned by this user off here.
++ */
++struct cifsUidInfo {
++ struct list_head userList;
++ struct list_head sessionList; /* SMB sessions for this user */
++ uid_t linux_uid;
++ char user[MAX_USERNAME_SIZE + 1]; /* ascii name of user */
++ /* BB may need ptr or callback for PAM or WinBind info */
++};
++
++/*
++ * Session structure. One of these for each uid session with a particular host
++ */
++struct cifsSesInfo {
++ struct list_head cifsSessionList;
++ struct semaphore sesSem;
++ struct cifsUidInfo *uidInfo; /* pointer to user info */
++ struct TCP_Server_Info *server; /* pointer to server info */
++ atomic_t inUse; /* # of mounts (tree connections) on this ses */
++ enum statusEnum status;
++ __u32 sequence_number; /* needed for CIFS PDU signature */
++ __u16 ipc_tid; /* special tid for connection to IPC share */
++ char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16];
++ char *serverOS; /* name of operating system underlying the server */
++ char *serverNOS; /* name of network operating system that the server is running */
++ char *serverDomain; /* security realm of server */
++ int Suid; /* remote smb uid */
++ uid_t linux_uid; /* local Linux uid */
++ int capabilities;
++ char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */
++ char userName[MAX_USERNAME_SIZE + 1];
++ char domainName[MAX_USERNAME_SIZE + 1];
++ char * password;
++};
++
++/*
++ * there is one of these for each connection to a resource on a particular
++ * session
++ */
++struct cifsTconInfo {
++ struct list_head cifsConnectionList;
++ struct list_head openFileList;
++ struct semaphore tconSem;
++ struct cifsSesInfo *ses; /* pointer to session associated with */
++ char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */
++ char *nativeFileSystem;
++ __u16 tid; /* The 2 byte tree id */
++ __u16 Flags; /* optional support bits */
++ enum statusEnum tidStatus;
++ atomic_t useCount; /* how many mounts (explicit or implicit) to this share */
++#ifdef CONFIG_CIFS_STATS
++ atomic_t num_smbs_sent;
++ atomic_t num_writes;
++ atomic_t num_reads;
++ atomic_t num_oplock_brks;
++ atomic_t num_opens;
++ atomic_t num_deletes;
++ atomic_t num_mkdirs;
++ atomic_t num_rmdirs;
++ atomic_t num_renames;
++ atomic_t num_t2renames;
++ __u64 bytes_read;
++ __u64 bytes_written;
++ spinlock_t stat_lock;
++#endif
++ FILE_SYSTEM_DEVICE_INFO fsDevInfo;
++ FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */
++ FILE_SYSTEM_UNIX_INFO fsUnixInfo;
++ int retry:1;
++ /* BB add field for back pointer to sb struct? */
++};
++
++/*
++ * This info hangs off the cifsFileInfo structure. This is used to track
++ * byte stream locks on the file
++ */
++struct cifsLockInfo {
++ struct cifsLockInfo *next;
++ int start;
++ int length;
++ int type;
++};
++
++/*
++ * One of these for each open instance of a file
++ */
++struct cifsFileInfo {
++ struct list_head tlist; /* pointer to next fid owned by tcon */
++ struct list_head flist; /* next fid (file instance) for this inode */
++ unsigned int uid; /* allows finding which FileInfo structure */
++ __u32 pid; /* process id who opened file */
++ __u16 netfid; /* file id from remote */
++ /* BB add lock scope info here if needed */ ;
++ /* lock scope id (0 if none) */
++ struct file * pfile; /* needed for writepage */
++ struct inode * pInode; /* needed for oplock break */
++ int endOfSearch:1; /* we have reached end of search */
++ int closePend:1; /* file is marked to close */
++ int emptyDir:1;
++ int invalidHandle:1; /* file closed via session abend */
++ struct semaphore fh_sem; /* prevents reopen race after dead ses*/
++ char * search_resume_name;
++ unsigned int resume_name_length;
++ __u32 resume_key;
++};
++
++/*
++ * One of these for each file inode
++ */
++
++struct cifsInodeInfo {
++ struct list_head lockList;
++ /* BB add in lists for dirty pages - i.e. write caching info for oplock */
++ struct list_head openFileList;
++ int write_behind_rc;
++ __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
++ atomic_t inUse; /* num concurrent users (local openers cifs) of file*/
++ unsigned long time; /* jiffies of last update/check of inode */
++ int clientCanCacheRead:1; /* read oplock */
++ int clientCanCacheAll:1; /* read and writebehind oplock */
++ int oplockPending:1;
++ struct inode vfs_inode;
++};
++
++static inline struct cifsInodeInfo * CIFS_I(struct inode *inode)
++{
++ return (struct cifsInodeInfo *)&(inode->u);
++}
++
++static inline struct cifs_sb_info * CIFS_SB(struct super_block *sb)
++{
++ return (struct cifs_sb_info *) &(sb->u);
++}
++
++
++/* one of these for every pending CIFS request to the server */
++struct mid_q_entry {
++ struct list_head qhead; /* mids waiting on reply from this server */
++ __u16 mid; /* multiplex id */
++ __u16 pid; /* process id */
++ __u32 sequence_number; /* for CIFS signing */
++ __u16 command; /* smb command code */
++ struct timeval when_sent; /* time when smb sent */
++ struct cifsSesInfo *ses; /* smb was sent to this server */
++ struct task_struct *tsk; /* task waiting for response */
++ struct smb_hdr *resp_buf; /* response buffer */
++ int midState; /* wish this were enum but can not pass to wait_event */
++};
++
++struct oplock_q_entry {
++ struct list_head qhead;
++ struct inode * pinode;
++ struct cifsTconInfo * tcon;
++ __u16 netfid;
++};
++
++#define MID_FREE 0
++#define MID_REQUEST_ALLOCATED 1
++#define MID_REQUEST_SUBMITTED 2
++#define MID_RESPONSE_RECEIVED 4
++#define MID_RETRY_NEEDED 8 /* session closed while this request out */
++
++/*
++ *****************************************************************
++ * All constants go here
++ *****************************************************************
++ */
++
++#define UID_HASH (16)
++
++/*
++ * Note that ONE module should define _DECLARE_GLOBALS_HERE to cause the
++ * following to be declared.
++ */
++
++/****************************************************************************
++ * Locking notes. All updates to global variables and lists should be
++ * protected by spinlocks or semaphores.
++ *
++ * Spinlocks
++ * ---------
++ * GlobalMid_Lock protects:
++ * list operations on pending_mid_q and oplockQ
++ * updates to XID counters, multiplex id and SMB sequence numbers
++ * GlobalSMBSesLock protects:
++ * list operations on tcp and SMB session lists and tCon lists
++ * f_owner.lock protects certain per file struct operations
++ * mapping->page_lock protects certain per page operations
++ *
++ * Semaphores
++ * ----------
++ * sesSem operations on smb session
++ * tconSem operations on tree connection
++ * fh_sem file handle reconnection operations
++ *
++ ****************************************************************************/
++
++#ifdef DECLARE_GLOBALS_HERE
++#define GLOBAL_EXTERN
++#else
++#define GLOBAL_EXTERN extern
++#endif
++
++/*
++ * The list of servers that did not respond with NT LM 0.12.
++ * This list helps improve performance and eliminate the messages indicating
++ * that we had a communications error talking to the server in this list.
++ */
++GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */
++
++/*
++ * The following is a hash table of all the users we know about.
++ */
++GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH];
++
++GLOBAL_EXTERN struct list_head GlobalServerList; /* BB not implemented yet */
++GLOBAL_EXTERN struct list_head GlobalSMBSessionList;
++GLOBAL_EXTERN struct list_head GlobalTreeConnectionList;
++GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */
++
++GLOBAL_EXTERN struct list_head GlobalOplock_Q;
++
++/*
++ * Global transaction id (XID) information
++ */
++GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */
++GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */
++GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */
++GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above and list operations */
++ /* on midQ entries */
++GLOBAL_EXTERN char Local_System_Name[15];
++
++/*
++ * Global counters, updated atomically
++ */
++GLOBAL_EXTERN atomic_t sesInfoAllocCount;
++GLOBAL_EXTERN atomic_t tconInfoAllocCount;
++
++GLOBAL_EXTERN atomic_t tcpSesReconnectCount;
++GLOBAL_EXTERN atomic_t tconInfoReconnectCount;
++
++/* Various Debug counters to remove someday (BB) */
++GLOBAL_EXTERN atomic_t bufAllocCount;
++GLOBAL_EXTERN atomic_t midCount;
++
++/* Misc globals */
++GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
++ to be established on existing mount if we
++ have the uid/password or Kerberos credential
++ or equivalent for current user */
++GLOBAL_EXTERN unsigned int oplockEnabled;
++GLOBAL_EXTERN unsigned int quotaEnabled;
++GLOBAL_EXTERN unsigned int lookupCacheEnabled;
++GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
++ with more secure ntlmssp2 challenge/resp */
++GLOBAL_EXTERN unsigned int ntlmv2_support; /* better optional password hash */
++GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
++GLOBAL_EXTERN unsigned int linuxExtEnabled; /* enable Linux/Unix CIFS extensions */
++
+diff -urN linux-2.4.29.old/fs/cifs/cifspdu.h linux-2.4.29/fs/cifs/cifspdu.h
+--- linux-2.4.29.old/fs/cifs/cifspdu.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/cifspdu.h 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,1793 @@
++/*
++ * fs/cifs/cifspdu.h
++ *
++ * Copyright (c) International Business Machines Corp., 2002
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef _CIFSPDU_H
++#define _CIFSPDU_H
++
++#include <net/sock.h>
++
++#define CIFS_PROT 0
++#define BAD_PROT CIFS_PROT+1
++
++/* SMB command codes */
++#define SMB_COM_CREATE_DIRECTORY 0x00
++#define SMB_COM_DELETE_DIRECTORY 0x01
++#define SMB_COM_CLOSE 0x04
++#define SMB_COM_DELETE 0x06
++#define SMB_COM_RENAME 0x07
++#define SMB_COM_LOCKING_ANDX 0x24
++#define SMB_COM_COPY 0x29
++#define SMB_COM_READ_ANDX 0x2E
++#define SMB_COM_WRITE_ANDX 0x2F
++#define SMB_COM_TRANSACTION2 0x32
++#define SMB_COM_TRANSACTION2_SECONDARY 0x33
++#define SMB_COM_FIND_CLOSE2 0x34
++#define SMB_COM_TREE_DISCONNECT 0x71
++#define SMB_COM_NEGOTIATE 0x72
++#define SMB_COM_SESSION_SETUP_ANDX 0x73
++#define SMB_COM_LOGOFF_ANDX 0x74
++#define SMB_COM_TREE_CONNECT_ANDX 0x75
++#define SMB_COM_NT_TRANSACT 0xA0
++#define SMB_COM_NT_TRANSACT_SECONDARY 0xA1
++#define SMB_COM_NT_CREATE_ANDX 0xA2
++#define SMB_COM_NT_RENAME 0xA5
++
++/* Transact2 subcommand codes */
++#define TRANS2_OPEN 0x00
++#define TRANS2_FIND_FIRST 0x01
++#define TRANS2_FIND_NEXT 0x02
++#define TRANS2_QUERY_FS_INFORMATION 0x03
++#define TRANS2_QUERY_PATH_INFORMATION 0x05
++#define TRANS2_SET_PATH_INFORMATION 0x06
++#define TRANS2_QUERY_FILE_INFORMATION 0x07
++#define TRANS2_SET_FILE_INFORMATION 0x08
++#define TRANS2_GET_DFS_REFERRAL 0x10
++#define TRANS2_REPORT_DFS_INCOSISTENCY 0x11
++
++/* NT Transact subcommand codes */
++#define NT_TRANSACT_CREATE 0x01
++#define NT_TRANSACT_IOCTL 0x02
++#define NT_TRANSACT_SET_SECURITY_DESC 0x03
++#define NT_TRANSACT_NOTIFY_CHANGE 0x04
++#define NT_TRANSACT_RENAME 0x05
++#define NT_TRANSACT_QUERY_SECURITY_DESC 0x06
++#define NT_TRANSACT_GET_USER_QUOTA 0x07
++#define NT_TRANSACT_SET_USER_QUOTA 0x08
++
++#define MAX_CIFS_HDR_SIZE 256 /* chained NTCreateXReadX will probably be biggest */
++
++/* internal cifs vfs structures */
++/*****************************************************************
++ * All constants go here
++ *****************************************************************
++ */
++
++/*
++ * Starting value for maximum SMB size negotiation
++ */
++#define CIFS_MAX_MSGSIZE (4*4096)
++
++/*
++ * Size of encrypted user password in bytes
++ */
++#define CIFS_ENCPWD_SIZE (16)
++
++/*
++ * Size of the crypto key returned on the negotiate SMB in bytes
++ */
++#define CIFS_CRYPTO_KEY_SIZE (8)
++
++/*
++ * Size of the session key (crypto key encrypted with the password
++ */
++#define CIFS_SESSION_KEY_SIZE (24)
++
++/*
++ * Maximum user name length
++ */
++#define CIFS_UNLEN (20)
++
++/*
++ * Flags on SMB open
++ */
++#define SMBOPEN_WRITE_THROUGH 0x4000
++#define SMBOPEN_DENY_ALL 0x0010
++#define SMBOPEN_DENY_WRITE 0x0020
++#define SMBOPEN_DENY_READ 0x0030
++#define SMBOPEN_DENY_NONE 0x0040
++#define SMBOPEN_READ 0x0000
++#define SMBOPEN_WRITE 0x0001
++#define SMBOPEN_READWRITE 0x0002
++#define SMBOPEN_EXECUTE 0x0003
++
++#define SMBOPEN_OCREATE 0x0010
++#define SMBOPEN_OTRUNC 0x0002
++#define SMBOPEN_OAPPEND 0x0001
++
++/*
++ * SMB flag definitions
++ */
++#define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock primitives */
++#define SMBFLG_RCV_POSTED 0x02 /* obsolete */
++#define SMBFLG_RSVD 0x04
++#define SMBFLG_CASELESS 0x08 /* all pathnames treated as caseless (off implies case sensitive file handling requested) */
++#define SMBFLG_CANONICAL_PATH_FORMAT 0x10 /* obsolete */
++#define SMBFLG_OLD_OPLOCK 0x20 /* obsolete */
++#define SMBFLG_OLD_OPLOCK_NOTIFY 0x40 /* obsolete */
++#define SMBFLG_RESPONSE 0x80 /* this PDU is a response from server */
++
++/*
++ * SMB flag2 definitions
++ */
++#define SMBFLG2_KNOWS_LONG_NAMES 0x0001 /* can send long (non-8.3) path names in response */
++#define SMBFLG2_KNOWS_EAS 0x0002
++#define SMBFLG2_SECURITY_SIGNATURE 0x0004
++#define SMBFLG2_IS_LONG_NAME 0x0040
++#define SMBFLG2_EXT_SEC 0x0800
++#define SMBFLG2_DFS 0x1000
++#define SMBFLG2_PAGING_IO 0x2000
++#define SMBFLG2_ERR_STATUS 0x4000
++#define SMBFLG2_UNICODE 0x8000
++
++/*
++ * These are the file access permission bits defined in CIFS for the
++ * NTCreateAndX as well as the level 0x107
++ * TRANS2_QUERY_PATH_INFORMATION API. The level 0x107, SMB_QUERY_FILE_ALL_INFO
++ * responds with the AccessFlags.
++ * The AccessFlags specifies the access permissions a caller has to the
++ * file and can have any suitable combination of the following values:
++ */
++
++#define FILE_READ_DATA 0x00000001 /* Data can be read from the file */
++#define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */
++#define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */
++#define FILE_READ_EA 0x00000008 /* Extended attributes associated */
++ /* with the file can be read */
++#define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */
++ /* with the file can be written */
++#define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */
++ /* the file using system paging I/O */
++#define FILE_DELETE_CHILD 0x00000040
++#define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */
++ /* file can be read */
++#define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */
++ /* file can be written */
++#define DELETE 0x00010000 /* The file can be deleted */
++#define READ_CONTROL 0x00020000 /* The access control list and */
++ /* ownership associated with the */
++ /* file can be read */
++#define WRITE_DAC 0x00040000 /* The access control list and */
++ /* ownership associated with the */
++ /* file can be written. */
++#define WRITE_OWNER 0x00080000 /* Ownership information associated */
++ /* with the file can be written */
++#define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */
++ /* synchronize with the completion */
++ /* of an input/output request */
++#define GENERIC_ALL 0x10000000
++#define GENERIC_EXECUTE 0x20000000
++#define GENERIC_WRITE 0x40000000
++#define GENERIC_READ 0x80000000
++ /* In summary - Relevant file */
++ /* access flags from CIFS are */
++ /* file_read_data, file_write_data */
++ /* file_execute, file_read_attributes */
++ /* write_dac, and delete. */
++
++/*
++ * Invalid readdir handle
++ */
++#define CIFS_NO_HANDLE 0xFFFF
++
++/* IPC$ in ASCII */
++#define CIFS_IPC_RESOURCE "\x49\x50\x43\x24"
++
++/* IPC$ in Unicode */
++#define CIFS_IPC_UNICODE_RESOURCE "\x00\x49\x00\x50\x00\x43\x00\x24\x00\x00"
++
++/* Unicode Null terminate 2 bytes of 0 */
++#define UNICODE_NULL "\x00\x00"
++#define ASCII_NULL 0x00
++
++/*
++ * Server type values (returned on EnumServer API
++ */
++#define CIFS_SV_TYPE_DC 0x00000008
++#define CIFS_SV_TYPE_BACKDC 0x00000010
++
++/*
++ * Alias type flags (From EnumAlias API call
++ */
++#define CIFS_ALIAS_TYPE_FILE 0x0001
++#define CIFS_SHARE_TYPE_FILE 0x0000
++
++/*
++ * File Attribute flags
++ */
++#define ATTR_READONLY 0x0001
++#define ATTR_HIDDEN 0x0002
++#define ATTR_SYSTEM 0x0004
++#define ATTR_VOLUME 0x0008
++#define ATTR_DIRECTORY 0x0010
++#define ATTR_ARCHIVE 0x0020
++#define ATTR_DEVICE 0x0040
++#define ATTR_NORMAL 0x0080
++#define ATTR_TEMPORARY 0x0100
++#define ATTR_SPARSE 0x0200
++#define ATTR_REPARSE 0x0400
++#define ATTR_COMPRESSED 0x0800
++#define ATTR_OFFLINE 0x1000 /* ie file not immediately available - offline storage */
++#define ATTR_NOT_CONTENT_INDEXED 0x2000
++#define ATTR_ENCRYPTED 0x4000
++#define ATTR_POSIX_SEMANTICS 0x01000000
++#define ATTR_BACKUP_SEMANTICS 0x02000000
++#define ATTR_DELETE_ON_CLOSE 0x04000000
++#define ATTR_SEQUENTIAL_SCAN 0x08000000
++#define ATTR_RANDOM_ACCESS 0x10000000
++#define ATTR_NO_BUFFERING 0x20000000
++#define ATTR_WRITE_THROUGH 0x80000000
++
++/* ShareAccess flags */
++#define FILE_NO_SHARE 0x00000000
++#define FILE_SHARE_READ 0x00000001
++#define FILE_SHARE_WRITE 0x00000002
++#define FILE_SHARE_DELETE 0x00000004
++#define FILE_SHARE_ALL 0x00000007
++
++/* CreateDisposition flags */
++#define FILE_SUPERSEDE 0x00000000
++#define FILE_OPEN 0x00000001
++#define FILE_CREATE 0x00000002
++#define FILE_OPEN_IF 0x00000003
++#define FILE_OVERWRITE 0x00000004
++#define FILE_OVERWRITE_IF 0x00000005
++
++/* CreateOptions */
++#define CREATE_NOT_FILE 0x00000001 /* if set must not be file */
++#define CREATE_WRITE_THROUGH 0x00000002
++#define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */
++#define CREATE_RANDOM_ACCESS 0x00000800
++#define CREATE_DELETE_ON_CLOSE 0x00001000
++#define OPEN_REPARSE_POINT 0x00200000
++
++/* ImpersonationLevel flags */
++#define SECURITY_ANONYMOUS 0
++#define SECURITY_IDENTIFICATION 1
++#define SECURITY_IMPERSONATION 2
++#define SECURITY_DELEGATION 3
++
++/* SecurityFlags */
++#define SECURITY_CONTEXT_TRACKING 0x01
++#define SECURITY_EFFECTIVE_ONLY 0x02
++
++/*
++ * Default PID value, used in all SMBs where the PID is not important
++ */
++#define CIFS_DFT_PID 0x1234
++
++/*
++ * We use the same routine for Copy and Move SMBs. This flag is used to
++ * distinguish
++ */
++#define CIFS_COPY_OP 1
++#define CIFS_RENAME_OP 2
++
++#define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */
++#define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */
++
++#pragma pack(1)
++
++struct smb_hdr {
++ __u32 smb_buf_length; /* big endian on wire *//* BB length is only two or three bytes - with one or two byte type preceding it but that is always zero - we could mask the type byte off just in case BB */
++ __u8 Protocol[4];
++ __u8 Command;
++ union {
++ struct {
++ __u8 ErrorClass;
++ __u8 Reserved;
++ __u16 Error; /* note: treated as little endian (le) on wire */
++ } DosError;
++ __u32 CifsError; /* note: le */
++ } Status;
++ __u8 Flags;
++ __u16 Flags2; /* note: le */
++ __u16 PidHigh; /* note: le */
++ union {
++ struct {
++ __u32 SequenceNumber; /* le */
++ __u32 Reserved; /* zero */
++ } Sequence;
++ __u8 SecuritySignature[8]; /* le */
++ } Signature;
++ __u8 pad[2];
++ __u16 Tid;
++ __u16 Pid; /* note: le */
++ __u16 Uid;
++ __u16 Mid;
++ __u8 WordCount;
++};
++/* given a pointer to an smb_hdr retrieve the value of byte count */
++#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) )
++
++/* given a pointer to an smb_hdr retrieve the pointer to the byte area */
++#define pByteArea(smb_var) ((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 )
++
++/*
++ * Computer Name Length
++ */
++#define CNLEN 15
++
++/*
++ * Share Name Length @S8A
++ * Note: This length is limited by the SMB used to get @S8A
++ * the Share info. NetShareEnum only returns 13 @S8A
++ * chars, including the null termination. @S8A
++ */
++#define SNLEN 12 /*@S8A */
++
++/*
++ * Comment Length
++ */
++#define MAXCOMMENTLEN 40
++
++/*
++ * The OS/2 maximum path name
++ */
++#define MAX_PATHCONF 256
++
++/*
++ * SMB frame definitions (following must be packed structs)
++ * See the SNIA CIFS Specification for details.
++ *
++ * The Naming convention is the lower case version of the
++ * smb command code name for the struct and this is typedef to the
++ * uppercase version of the same name with the prefix SMB_ removed
++ * for brevity. Although typedefs are not commonly used for
++ * structure definitions in the Linux kernel, their use in the
++ * CIFS standards document, which this code is based on, may
++ * make this one of the cases where typedefs for structures make
++ * sense to improve readability for readers of the standards doc.
++ * Typedefs can always be removed later if they are too distracting
++ * and they are only used for the CIFSs PDUs themselves, not
++ * internal cifs vfs structures
++ *
++ */
++
++typedef struct negotiate_req {
++ struct smb_hdr hdr; /* wct = 0 */
++ __u16 ByteCount;
++ unsigned char DialectsArray[1];
++} NEGOTIATE_REQ;
++
++typedef struct negotiate_rsp {
++ struct smb_hdr hdr; /* wct = 17 */
++ __u16 DialectIndex;
++ __u8 SecurityMode;
++ __u16 MaxMpxCount;
++ __u16 MaxNumberVcs;
++ __u32 MaxBufferSize;
++ __u32 MaxRawSize;
++ __u32 SessionKey;
++ __u32 Capabilities; /* see below */
++ __u32 SystemTimeLow;
++ __u32 SystemTimeHigh;
++ __u16 ServerTimeZone;
++ __u8 EncryptionKeyLength;
++ __u16 ByteCount;
++ union {
++ unsigned char EncryptionKey[1]; /* if cap extended security is off */
++ /* followed by Domain name - if extended security is off */
++ /* followed by 16 bytes of server GUID */
++ /* followed by security blob if cap_extended_security negotiated */
++ struct {
++ unsigned char GUID[16];
++ unsigned char SecurityBlob[1];
++ } extended_response;
++ } u;
++} NEGOTIATE_RSP;
++
++/* SecurityMode bits */
++#define SECMODE_USER 0x01 /* off indicates share level security */
++#define SECMODE_PW_ENCRYPT 0x02
++#define SECMODE_SIGN_ENABLED 0x04 /* SMB security signatures enabled */
++#define SECMODE_SIGN_REQUIRED 0x08 /* SMB security signatures required */
++
++/* Negotiate response Capabilities */
++#define CAP_RAW_MODE 0x00000001
++#define CAP_MPX_MODE 0x00000002
++#define CAP_UNICODE 0x00000004
++#define CAP_LARGE_FILES 0x00000008
++#define CAP_NT_SMBS 0x00000010 /* implies CAP_NT_FIND */
++#define CAP_RPC_REMOTE_APIS 0x00000020
++#define CAP_STATUS32 0x00000040
++#define CAP_LEVEL_II_OPLOCKS 0x00000080
++#define CAP_LOCK_AND_READ 0x00000100
++#define CAP_NT_FIND 0x00000200
++#define CAP_DFS 0x00001000
++#define CAP_INFOLEVEL_PASSTHRU 0x00002000
++#define CAP_LARGE_READ_X 0x00004000
++#define CAP_LARGE_WRITE_X 0x00008000
++#define CAP_UNIX 0x00800000
++#define CAP_RESERVED 0x02000000
++#define CAP_BULK_TRANSFER 0x20000000
++#define CAP_COMPRESSED_DATA 0x40000000
++#define CAP_EXTENDED_SECURITY 0x80000000
++
++typedef union smb_com_session_setup_andx {
++ struct { /* request format */
++ struct smb_hdr hdr; /* wct = 12 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 MaxBufferSize;
++ __u16 MaxMpxCount;
++ __u16 VcNumber;
++ __u32 SessionKey;
++ __u16 SecurityBlobLength;
++ __u32 Reserved;
++ __u32 Capabilities; /* see below */
++ __u16 ByteCount;
++ unsigned char SecurityBlob[1]; /* followed by */
++ /* STRING NativeOS */
++ /* STRING NativeLanMan */
++ } req; /* NTLM request format (with extended security */
++
++ struct { /* request format */
++ struct smb_hdr hdr; /* wct = 13 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 MaxBufferSize;
++ __u16 MaxMpxCount;
++ __u16 VcNumber;
++ __u32 SessionKey;
++ __u16 CaseInsensitivePasswordLength; /* ASCII password length */
++ __u16 CaseSensitivePasswordLength; /* Unicode password length */
++ __u32 Reserved; /* see below */
++ __u32 Capabilities;
++ __u16 ByteCount;
++ unsigned char CaseInsensitivePassword[1]; /* followed by: */
++ /* unsigned char * CaseSensitivePassword; */
++ /* STRING AccountName */
++ /* STRING PrimaryDomain */
++ /* STRING NativeOS */
++ /* STRING NativeLanMan */
++ } req_no_secext; /* NTLM request format (without extended security */
++
++ struct { /* default (NTLM) response format */
++ struct smb_hdr hdr; /* wct = 4 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 Action; /* see below */
++ __u16 SecurityBlobLength;
++ __u16 ByteCount;
++ unsigned char SecurityBlob[1]; /* followed by */
++/* unsigned char * NativeOS; */
++/* unsigned char * NativeLanMan; */
++/* unsigned char * PrimaryDomain; */
++ } resp; /* NTLM response format (with or without extended security */
++
++ struct { /* request format */
++ struct smb_hdr hdr; /* wct = 10 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 MaxBufferSize;
++ __u16 MaxMpxCount;
++ __u16 VcNumber;
++ __u32 SessionKey;
++ __u16 PassswordLength;
++ __u32 Reserved;
++ __u16 ByteCount;
++ unsigned char AccountPassword[1]; /* followed by */
++ /* STRING AccountName */
++ /* STRING PrimaryDomain */
++ /* STRING NativeOS */
++ /* STRING NativeLanMan */
++ } old_req; /* pre-NTLM (LANMAN2.1) request format */
++
++ struct { /* default (NTLM) response format */
++ struct smb_hdr hdr; /* wct = 3 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 Action; /* see below */
++ __u16 ByteCount;
++ unsigned char NativeOS[1]; /* followed by */
++/* unsigned char * NativeLanMan; */
++/* unsigned char * PrimaryDomain; */
++ } old_resp; /* pre-NTLM (LANMAN2.1) response format */
++} SESSION_SETUP_ANDX;
++
++#define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux"
++
++/* Capabilities bits (for NTLM SessSetup request) */
++#define CAP_UNICODE 0x00000004
++#define CAP_LARGE_FILES 0x00000008
++#define CAP_NT_SMBS 0x00000010
++#define CAP_STATUS32 0x00000040
++#define CAP_LEVEL_II_OPLOCKS 0x00000080
++#define CAP_NT_FIND 0x00000200 /* reserved should be zero (presumably because NT_SMBs implies the same thing) */
++#define CAP_BULK_TRANSFER 0x20000000
++#define CAP_EXTENDED_SECURITY 0x80000000
++
++/* Action bits */
++#define GUEST_LOGIN 1
++
++typedef struct smb_com_tconx_req {
++ struct smb_hdr hdr; /* wct = 4 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 Flags; /* see below */
++ __u16 PasswordLength;
++ __u16 ByteCount;
++ unsigned char Password[1]; /* followed by */
++/* STRING Path *//* \\server\share name */
++ /* STRING Service */
++} TCONX_REQ;
++
++typedef struct smb_com_tconx_rsp {
++ struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 OptionalSupport; /* see below */
++ __u16 ByteCount;
++ unsigned char Service[1]; /* always ASCII, not Unicode */
++ /* STRING NativeFileSystem */
++} TCONX_RSP;
++
++/* tree connect Flags */
++#define DISCONNECT_TID 0x0001
++#define TCON_EXTENDED_SECINFO 0x0008
++/* OptionalSupport bits */
++#define SMB_SUPPORT_SEARCH_BITS 0x0001 /* must have bits (exclusive searches suppt. */
++#define SMB_SHARE_IS_IN_DFS 0x0002
++
++typedef struct smb_com_logoff_andx_req {
++
++ struct smb_hdr hdr; /* wct = 2 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 ByteCount;
++} LOGOFF_ANDX_REQ;
++
++typedef struct smb_com_logoff_andx_rsp {
++ struct smb_hdr hdr; /* wct = 2 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 ByteCount;
++} LOGOFF_ANDX_RSP;
++
++typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */
++ struct {
++ struct smb_hdr hdr; /* wct = 0 */
++ __u16 ByteCount; /* bcc = 0 */
++ } req;
++ struct {
++ struct smb_hdr hdr; /* wct = 0 */
++ __u16 ByteCount; /* bcc = 0 */
++ } resp;
++} TREE_DISCONNECT;
++
++typedef struct smb_com_close_req {
++ struct smb_hdr hdr; /* wct = 3 */
++ __u16 FileID;
++ __u32 LastWriteTime; /* should be zero */
++ __u16 ByteCount; /* 0 */
++} CLOSE_REQ;
++
++typedef struct smb_com_close_rsp {
++ struct smb_hdr hdr; /* wct = 0 */
++ __u16 ByteCount; /* bct = 0 */
++} CLOSE_RSP;
++
++typedef struct smb_com_findclose_req {
++ struct smb_hdr hdr; /* wct = 1 */
++ __u16 FileID;
++ __u16 ByteCount; /* 0 */
++} FINDCLOSE_REQ;
++
++/* OpenFlags */
++#define REQ_OPLOCK 0x00000002
++#define REQ_BATCHOPLOCK 0x00000004
++#define REQ_OPENDIRONLY 0x00000008
++
++typedef struct smb_com_open_req { /* also handles create */
++ struct smb_hdr hdr; /* wct = 24 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u8 Reserved; /* Must Be Zero */
++ __u16 NameLength;
++ __u32 OpenFlags;
++ __u32 RootDirectoryFid;
++ __u32 DesiredAccess;
++ __u64 AllocationSize;
++ __u32 FileAttributes;
++ __u32 ShareAccess;
++ __u32 CreateDisposition;
++ __u32 CreateOptions;
++ __u32 ImpersonationLevel;
++ __u8 SecurityFlags;
++ __u16 ByteCount;
++ char fileName[1];
++} OPEN_REQ;
++
++/* open response: oplock levels */
++#define OPLOCK_NONE 0
++#define OPLOCK_EXCLUSIVE 1
++#define OPLOCK_BATCH 2
++#define OPLOCK_READ 3 /* level 2 oplock */
++
++/* open response for CreateAction shifted left */
++#define CIFS_CREATE_ACTION 0x20000 /* file created */
++
++typedef struct smb_com_open_rsp {
++ struct smb_hdr hdr; /* wct = 34 BB */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u8 OplockLevel;
++ __u16 Fid;
++ __u32 CreateAction;
++ __u64 CreationTime;
++ __u64 LastAccessTime;
++ __u64 LastWriteTime;
++ __u64 ChangeTime;
++ __u32 FileAttributes;
++ __u64 AllocationSize;
++ __u64 EndOfFile;
++ __u16 FileType;
++ __u16 DeviceState;
++ __u8 DirectoryFlag;
++ __u16 ByteCount; /* bct = 0 */
++} OPEN_RSP;
++
++typedef struct smb_com_write_req {
++ struct smb_hdr hdr; /* wct = 14 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 Fid;
++ __u32 OffsetLow;
++ __u32 Reserved;
++ __u16 WriteMode;
++ __u16 Remaining;
++ __u16 DataLengthHigh;
++ __u16 DataLengthLow;
++ __u16 DataOffset;
++ __u32 OffsetHigh;
++ __u16 ByteCount;
++ __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */
++ char Data[1];
++} WRITE_REQ;
++
++typedef struct smb_com_write_rsp {
++ struct smb_hdr hdr; /* wct = 6 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 Count;
++ __u16 Remaining;
++ __u32 Reserved;
++ __u16 ByteCount;
++} WRITE_RSP;
++
++typedef struct smb_com_read_req {
++ struct smb_hdr hdr; /* wct = 12 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 Fid;
++ __u32 OffsetLow;
++ __u16 MaxCount;
++ __u16 MinCount; /* obsolete */
++ __u32 MaxCountHigh;
++ __u16 Remaining;
++ __u32 OffsetHigh;
++ __u16 ByteCount;
++} READ_REQ;
++
++typedef struct smb_com_read_rsp {
++ struct smb_hdr hdr; /* wct = 12 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 Remaining;
++ __u16 DataCompactionMode;
++ __u16 Reserved;
++ __u16 DataLength;
++ __u16 DataOffset;
++ __u16 DataLengthHigh;
++ __u64 Reserved2;
++ __u16 ByteCount;
++ __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */
++ char Data[1];
++} READ_RSP;
++
++typedef struct locking_andx_range {
++ __u16 Pid;
++ __u16 Pad;
++ __u32 OffsetHigh;
++ __u32 OffsetLow;
++ __u32 LengthHigh;
++ __u32 LengthLow;
++} LOCKING_ANDX_RANGE;
++
++#define LOCKING_ANDX_SHARED_LOCK 0x01
++#define LOCKING_ANDX_OPLOCK_RELEASE 0x02
++#define LOCKING_ANDX_CHANGE_LOCKTYPE 0x04
++#define LOCKING_ANDX_CANCEL_LOCK 0x08
++#define LOCKING_ANDX_LARGE_FILES 0x10 /* always on for us */
++
++typedef struct smb_com_lock_req {
++ struct smb_hdr hdr; /* wct = 8 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 Fid;
++ __u8 LockType;
++ __u8 OplockLevel;
++ __u32 Timeout;
++ __u16 NumberOfUnlocks;
++ __u16 NumberOfLocks;
++ __u16 ByteCount;
++ LOCKING_ANDX_RANGE Locks[1];
++} LOCK_REQ;
++
++typedef struct smb_com_lock_rsp {
++ struct smb_hdr hdr; /* wct = 2 */
++ __u8 AndXCommand;
++ __u8 AndXReserved;
++ __u16 AndXOffset;
++ __u16 ByteCount;
++} LOCK_RSP;
++
++typedef struct smb_com_rename_req {
++ struct smb_hdr hdr; /* wct = 1 */
++ __u16 SearchAttributes; /* target file attributes */
++ __u16 ByteCount;
++ __u8 BufferFormat; /* 4 = ASCII or Unicode */
++ unsigned char OldFileName[1];
++ /* followed by __u8 BufferFormat2 */
++ /* followed by NewFileName */
++} RENAME_REQ;
++
++ /* copy request flags */
++#define COPY_MUST_BE_FILE 0x0001
++#define COPY_MUST_BE_DIR 0x0002
++#define COPY_TARGET_MODE_ASCII 0x0004 /* if not set, binary */
++#define COPY_SOURCE_MODE_ASCII 0x0008 /* if not set, binary */
++#define COPY_VERIFY_WRITES 0x0010
++#define COPY_TREE 0x0020
++
++typedef struct smb_com_copy_req {
++ struct smb_hdr hdr; /* wct = 3 */
++ __u16 Tid2;
++ __u16 OpenFunction;
++ __u16 Flags;
++ __u16 ByteCount;
++ __u8 BufferFormat; /* 4 = ASCII or Unicode */
++ unsigned char OldFileName[1];
++ /* followed by __u8 BufferFormat2 */
++ /* followed by NewFileName string */
++} COPY_REQ;
++
++typedef struct smb_com_copy_rsp {
++ struct smb_hdr hdr; /* wct = 1 */
++ __u16 CopyCount; /* number of files copied */
++ __u16 ByteCount; /* may be zero */
++ __u8 BufferFormat; /* 0x04 - only present if errored file follows */
++ unsigned char ErrorFileName[1]; /* only present if error in copy */
++} COPY_RSP;
++
++#define CREATE_HARD_LINK 0x103
++#define MOVEFILE_COPY_ALLOWED 0x0002
++#define MOVEFILE_REPLACE_EXISTING 0x0001
++
++typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */
++ struct smb_hdr hdr; /* wct = 4 */
++ __u16 SearchAttributes; /* target file attributes */
++ __u16 Flags; /* spec says Information Level */
++ __u32 ClusterCount;
++ __u16 ByteCount;
++ __u8 BufferFormat; /* 4 = ASCII or Unicode */
++ unsigned char OldFileName[1];
++ /* followed by __u8 BufferFormat2 */
++ /* followed by NewFileName */
++} NT_RENAME_REQ;
++
++typedef struct smb_com_rename_rsp {
++ struct smb_hdr hdr; /* wct = 0 */
++ __u16 ByteCount; /* bct = 0 */
++} RENAME_RSP;
++
++typedef struct smb_com_delete_file_req {
++ struct smb_hdr hdr; /* wct = 1 */
++ __u16 SearchAttributes;
++ __u16 ByteCount;
++ __u8 BufferFormat; /* 4 = ASCII */
++ unsigned char fileName[1];
++} DELETE_FILE_REQ;
++
++typedef struct smb_com_delete_file_rsp {
++ struct smb_hdr hdr; /* wct = 0 */
++ __u16 ByteCount; /* bct = 0 */
++} DELETE_FILE_RSP;
++
++typedef struct smb_com_delete_directory_req {
++ struct smb_hdr hdr; /* wct = 0 */
++ __u16 ByteCount;
++ __u8 BufferFormat; /* 4 = ASCII */
++ unsigned char DirName[1];
++} DELETE_DIRECTORY_REQ;
++
++typedef struct smb_com_delete_directory_rsp {
++ struct smb_hdr hdr; /* wct = 0 */
++ __u16 ByteCount; /* bct = 0 */
++} DELETE_DIRECTORY_RSP;
++
++typedef struct smb_com_create_directory_req {
++ struct smb_hdr hdr; /* wct = 0 */
++ __u16 ByteCount;
++ __u8 BufferFormat; /* 4 = ASCII */
++ unsigned char DirName[1];
++} CREATE_DIRECTORY_REQ;
++
++typedef struct smb_com_create_directory_rsp {
++ struct smb_hdr hdr; /* wct = 0 */
++ __u16 ByteCount; /* bct = 0 */
++} CREATE_DIRECTORY_RSP;
++
++/***************************************************/
++/* NT Transact structure defintions follow */
++/* Currently only ioctl and notify are implemented */
++/***************************************************/
++typedef struct smb_com_transaction_ioctl_req {
++ struct smb_hdr hdr; /* wct = 23 */
++ __u8 MaxSetupCount;
++ __u16 Reserved;
++ __u32 TotalParameterCount;
++ __u32 TotalDataCount;
++ __u32 MaxParameterCount;
++ __u32 MaxDataCount;
++ __u32 ParameterCount;
++ __u32 ParameterOffset;
++ __u32 DataCount;
++ __u32 DataOffset;
++ __u8 SetupCount; /* four setup words follow subcommand */
++ /* SNIA spec incorrectly included spurious pad here */
++ __u16 SubCommand;/* 2 = IOCTL/FSCTL */
++ __u32 FunctionCode;
++ __u16 Fid;
++ __u8 IsFsctl; /* 1 = File System Control, 0 = device control (IOCTL)*/
++ __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS share)*/
++ __u16 ByteCount;
++ __u8 Pad[3];
++ __u8 Data[1];
++} TRANSACT_IOCTL_REQ;
++
++typedef struct smb_com_transaction_ioctl_rsp {
++ struct smb_hdr hdr; /* wct = 19 */
++ __u8 Reserved[3];
++ __u32 TotalParameterCount;
++ __u32 TotalDataCount;
++ __u32 ParameterCount;
++ __u32 ParameterOffset;
++ __u32 ParameterDisplacement;
++ __u32 DataCount;
++ __u32 DataOffset;
++ __u32 DataDisplacement;
++ __u8 SetupCount; /* 1 */
++ __u16 ReturnedDataLen;
++ __u16 ByteCount;
++ __u8 Pad[3];
++} TRANSACT_IOCTL_RSP;
++
++typedef struct smb_com_transaction_change_notify_req {
++ struct smb_hdr hdr; /* wct = 23 */
++ __u8 MaxSetupCount;
++ __u16 Reserved;
++ __u32 TotalParameterCount;
++ __u32 TotalDataCount;
++ __u32 MaxParameterCount;
++ __u32 MaxDataCount;
++ __u32 ParameterCount;
++ __u32 ParameterOffset;
++ __u32 DataCount;
++ __u32 DataOffset;
++ __u8 SetupCount; /* four setup words follow subcommand */
++ /* SNIA spec incorrectly included spurious pad here */
++ __u16 SubCommand;/* 4 = Change Notify */
++ __u32 CompletionFilter; /* operation to monitor */
++ __u16 Fid;
++ __u8 WatchTree; /* 1 = Monitor subdirectories */
++ __u8 Reserved2;
++ __u16 ByteCount;
++/* __u8 Pad[3];*/
++/* __u8 Data[1];*/
++} TRANSACT_CHANGE_NOTIFY_REQ;
++
++typedef struct smb_com_transaction_change_notify_rsp {
++ struct smb_hdr hdr; /* wct = 18 */
++ __u8 Reserved[3];
++ __u32 TotalParameterCount;
++ __u32 TotalDataCount;
++ __u32 ParameterCount;
++ __u32 ParameterOffset;
++ __u32 ParameterDisplacement;
++ __u32 DataCount;
++ __u32 DataOffset;
++ __u32 DataDisplacement;
++ __u8 SetupCount; /* 0 */
++ __u16 ByteCount;
++ /* __u8 Pad[3]; */
++} TRANSACT_CHANGE_NOTIFY_RSP;
++/* Completion Filter flags for Notify */
++#define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001
++#define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002
++#define FILE_NOTIFY_CHANGE_NAME 0x00000003
++#define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x00000004
++#define FILE_NOTIFY_CHANGE_SIZE 0x00000008
++#define FILE_NOTIFY_CHANGE_LAST_WRITE 0x00000010
++#define FILE_NOTIFY_CHANGE_LAST_ACCESS 0x00000020
++#define FILE_NOTIFY_CHANGE_CREATION 0x00000040
++#define FILE_NOTIFY_CHANGE_EA 0x00000080
++#define FILE_NOTIFY_CHANGE_SECURITY 0x00000100
++#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
++#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
++#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
++
++#define FILE_ACTION_ADDED 0x00000001
++#define FILE_ACTION_REMOVED 0x00000002
++#define FILE_ACTION_MODIFIED 0x00000003
++#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004
++#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005
++#define FILE_ACTION_ADDED_STREAM 0x00000006
++#define FILE_ACTION_REMOVED_STREAM 0x00000007
++#define FILE_ACTION_MODIFIED_STREAM 0x00000008
++
++/* response contains array of the following structures */
++struct file_notify_information {
++ __u32 NextEntryOffset;
++ __u32 Action;
++ __u32 FileNameLength;
++ __u8 FileName[1];
++};
++
++struct reparse_data {
++ __u32 ReparseTag;
++ __u16 ReparseDataLength;
++ __u16 Reserved;
++ __u16 AltNameOffset;
++ __u16 AltNameLen;
++ __u16 TargetNameOffset;
++ __u16 TargetNameLen;
++ char LinkNamesBuf[1];
++};
++
++struct cifs_quota_data {
++ __u32 rsrvd1; /* 0 */
++ __u32 sid_size;
++ __u64 rsrvd2; /* 0 */
++ __u64 space_used;
++ __u64 soft_limit;
++ __u64 hard_limit;
++ char sid[1]; /* variable size? */
++};
++
++/* quota sub commands */
++#define QUOTA_LIST_CONTINUE 0
++#define QUOTA_LIST_START 0x100
++#define QUOTA_FOR_SID 0x101
++
++typedef union smb_com_transaction2 {
++ struct {
++ struct smb_hdr hdr; /* wct = 14+ */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 MaxParameterCount;
++ __u16 MaxDataCount;
++ __u8 MaxSetupCount;
++ __u8 Reserved;
++ __u16 Flags;
++ __u32 Timeout;
++ __u16 Reserved2;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u8 SetupCount;
++ __u8 Reserved3;
++ __u16 SubCommand; /* 1st setup word - can be followed by SetupCount words */
++ __u16 ByteCount; /* careful - setupcount is not always one */
++ } req;
++ struct {
++ struct smb_hdr hdr; /* wct = 0 */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 Reserved;
++ __u16 ParameterCount;
++ __u16 ParamterOffset;
++ __u16 ParameterDisplacement;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u16 DataDisplacement;
++ __u8 SetupCount;
++ __u8 Reserved1; /* should be zero setup words following */
++ __u16 ByteCount;
++ __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
++ /* data area follows */
++ } resp;
++} TRANSACTION2;
++
++/* PathInfo/FileInfo infolevels */
++#define SMB_INFO_STANDARD 1
++#define SMB_INFO_QUERY_EAS_FROM_LIST 3
++#define SMB_INFO_QUERY_ALL_EAS 4
++#define SMB_INFO_IS_NAME_VALID 6
++#define SMB_QUERY_FILE_BASIC_INFO 0x101
++#define SMB_QUERY_FILE_STANDARD_INFO 0x102
++#define SMB_QUERY_FILE_EA_INFO 0x103
++#define SMB_QUERY_FILE_NAME_INFO 0x104
++#define SMB_QUERY_FILE_ALLOCATION_INFO 0x105
++#define SMB_QUERY_FILE_END_OF_FILEINFO 0x106
++#define SMB_QUERY_FILE_ALL_INFO 0x107
++#define SMB_QUERY_ALT_NAME_INFO 0x108
++#define SMB_QUERY_FILE_STREAM_INFO 0x109
++#define SMB_QUERY_FILE_COMPRESSION_INFO 0x10B
++#define SMB_QUERY_FILE_UNIX_BASIC 0x200
++#define SMB_QUERY_FILE_UNIX_LINK 0x201
++
++#define SMB_SET_FILE_BASIC_INFO 0x101
++#define SMB_SET_FILE_DISPOSITION_INFO 0x102
++#define SMB_SET_FILE_ALLOCATION_INFO 0x103
++#define SMB_SET_FILE_END_OF_FILE_INFO 0x104
++#define SMB_SET_FILE_UNIX_BASIC 0x200
++#define SMB_SET_FILE_UNIX_LINK 0x201
++#define SMB_SET_FILE_UNIX_HLINK 0x203
++#define SMB_SET_FILE_BASIC_INFO2 0x3ec
++#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2
++#define SMB_FILE_ALL_INFO2 0x3fa
++#define SMB_SET_FILE_ALLOCATION_INFO2 0x3fb
++#define SMB_SET_FILE_END_OF_FILE_INFO2 0x3fc
++#define SMB_FILE_MOVE_CLUSTER_INFO 0x407
++#define SMB_FILE_QUOTA_INFO 0x408
++#define SMB_FILE_REPARSEPOINT_INFO 0x409
++#define SMB_FILE_MAXIMUM_INFO 0x40d
++
++/* Find File infolevels */
++#define SMB_FIND_FILE_DIRECTORY_INFO 0x101
++#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
++#define SMB_FIND_FILE_NAMES_INFO 0x103
++#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104
++#define SMB_FIND_FILE_UNIX 0x202
++
++typedef struct smb_com_transaction2_qpi_req {
++ struct smb_hdr hdr; /* wct = 14+ */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 MaxParameterCount;
++ __u16 MaxDataCount;
++ __u8 MaxSetupCount;
++ __u8 Reserved;
++ __u16 Flags;
++ __u32 Timeout;
++ __u16 Reserved2;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u8 SetupCount;
++ __u8 Reserved3;
++ __u16 SubCommand; /* one setup word */
++ __u16 ByteCount;
++ __u8 Pad;
++ __u16 InformationLevel;
++ __u32 Reserved4;
++ char FileName[1];
++} TRANSACTION2_QPI_REQ;
++
++typedef struct smb_com_transaction2_qpi_rsp {
++ struct smb_hdr hdr; /* wct = 10 + SetupCount */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 Reserved;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 ParameterDisplacement;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u16 DataDisplacement;
++ __u8 SetupCount;
++ __u8 Reserved1; /* should be zero setup words following */
++ __u16 ByteCount;
++ __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
++} TRANSACTION2_QPI_RSP;
++
++typedef struct smb_com_transaction2_spi_req {
++ struct smb_hdr hdr; /* wct = 15 */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 MaxParameterCount;
++ __u16 MaxDataCount;
++ __u8 MaxSetupCount;
++ __u8 Reserved;
++ __u16 Flags;
++ __u32 Timeout;
++ __u16 Reserved2;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u8 SetupCount;
++ __u8 Reserved3;
++ __u16 SubCommand; /* one setup word */
++ __u16 ByteCount;
++ __u8 Pad;
++ __u16 Pad1;
++ __u16 InformationLevel;
++ __u32 Reserved4;
++ char FileName[1];
++} TRANSACTION2_SPI_REQ;
++
++typedef struct smb_com_transaction2_spi_rsp {
++ struct smb_hdr hdr; /* wct = 10 + SetupCount */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 Reserved;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 ParameterDisplacement;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u16 DataDisplacement;
++ __u8 SetupCount;
++ __u8 Reserved1; /* should be zero setup words following */
++ __u16 ByteCount;
++ __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
++} TRANSACTION2_SPI_RSP;
++
++struct set_file_rename {
++ __u32 overwrite; /* 1 = overwrite dest */
++ __u32 root_fid; /* zero */
++ __u32 target_name_len;
++ char target_name[0]; /* Must be unicode */
++};
++
++struct smb_com_transaction2_sfi_req {
++ struct smb_hdr hdr; /* wct = 15 */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 MaxParameterCount;
++ __u16 MaxDataCount;
++ __u8 MaxSetupCount;
++ __u8 Reserved;
++ __u16 Flags;
++ __u32 Timeout;
++ __u16 Reserved2;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u8 SetupCount;
++ __u8 Reserved3;
++ __u16 SubCommand; /* one setup word */
++ __u16 ByteCount;
++ __u8 Pad;
++ __u16 Pad1;
++ __u16 Fid;
++ __u16 InformationLevel;
++ __u16 Reserved4;
++};
++
++struct smb_com_transaction2_sfi_rsp {
++ struct smb_hdr hdr; /* wct = 10 + SetupCount */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 Reserved;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 ParameterDisplacement;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u16 DataDisplacement;
++ __u8 SetupCount;
++ __u8 Reserved1; /* should be zero setup words following */
++ __u16 ByteCount;
++ __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
++};
++
++
++/*
++ * Flags on T2 FINDFIRST and FINDNEXT
++ */
++#define CIFS_SEARCH_CLOSE_ALWAYS 0x0001
++#define CIFS_SEARCH_CLOSE_AT_END 0x0002
++#define CIFS_SEARCH_RETURN_RESUME 0x0004
++#define CIFS_SEARCH_CONTINUE_FROM_LAST 0x0008
++#define CIFS_SEARCH_BACKUP_SEARCH 0x0010
++
++/*
++ * Size of the resume key on FINDFIRST and FINDNEXT calls
++ */
++#define CIFS_SMB_RESUME_KEY_SIZE 4
++
++typedef struct smb_com_transaction2_ffirst_req {
++ struct smb_hdr hdr; /* wct = 15 */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 MaxParameterCount;
++ __u16 MaxDataCount;
++ __u8 MaxSetupCount;
++ __u8 Reserved;
++ __u16 Flags;
++ __u32 Timeout;
++ __u16 Reserved2;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u8 SetupCount; /* one */
++ __u8 Reserved3;
++ __u16 SubCommand; /* TRANS2_FIND_FIRST */
++ __u16 ByteCount;
++ __u8 Pad;
++ __u16 SearchAttributes;
++ __u16 SearchCount;
++ __u16 SearchFlags;
++ __u16 InformationLevel;
++ __u32 SearchStorageType;
++ char FileName[1];
++} TRANSACTION2_FFIRST_REQ;
++
++typedef struct smb_com_transaction2_ffirst_rsp {
++ struct smb_hdr hdr; /* wct = 10 */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 Reserved;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 ParameterDisplacement;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u16 DataDisplacement;
++ __u8 SetupCount;
++ __u8 Reserved1; /* should be zero setup words following */
++ __u16 ByteCount;
++} TRANSACTION2_FFIRST_RSP;
++
++typedef struct smb_com_transaction2_ffirst_rsp_parms {
++ __u16 SearchHandle;
++ __u16 SearchCount;
++ __u16 EndofSearch;
++ __u16 EAErrorOffset;
++ __u16 LastNameOffset;
++} T2_FFIRST_RSP_PARMS;
++
++typedef struct smb_com_transaction2_fnext_req {
++ struct smb_hdr hdr; /* wct = 15 */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 MaxParameterCount;
++ __u16 MaxDataCount;
++ __u8 MaxSetupCount;
++ __u8 Reserved;
++ __u16 Flags;
++ __u32 Timeout;
++ __u16 Reserved2;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u8 SetupCount; /* one */
++ __u8 Reserved3;
++ __u16 SubCommand; /* TRANS2_FIND_NEXT */
++ __u16 ByteCount;
++ __u8 Pad;
++ __u16 SearchHandle;
++ __u16 SearchCount;
++ __u16 InformationLevel;
++ __u32 ResumeKey;
++ __u16 SearchFlags;
++ char ResumeFileName[1];
++} TRANSACTION2_FNEXT_REQ;
++
++typedef struct smb_com_transaction2_fnext_rsp {
++ struct smb_hdr hdr; /* wct = 10 */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 Reserved;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 ParameterDisplacement;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u16 DataDisplacement;
++ __u8 SetupCount;
++ __u8 Reserved1; /* should be zero setup words following */
++ __u16 ByteCount;
++} TRANSACTION2_FNEXT_RSP;
++
++typedef struct smb_com_transaction2_fnext_rsp_parms {
++ __u16 SearchCount;
++ __u16 EndofSearch;
++ __u16 EAErrorOffset;
++ __u16 LastNameOffset;
++} T2_FNEXT_RSP_PARMS;
++
++/* QFSInfo Levels */
++#define SMB_INFO_ALLOCATION 1
++#define SMB_INFO_VOLUME 2
++#define SMB_QUERY_FS_VOLUME_INFO 0x102
++#define SMB_QUERY_FS_SIZE_INFO 0x103
++#define SMB_QUERY_FS_DEVICE_INFO 0x104
++#define SMB_QUERY_FS_ATTRIBUTE_INFO 0x105
++#define SMB_QUERY_CIFS_UNIX_INFO 0x200
++#define SMB_QUERY_LABEL_INFO 0x3ea
++#define SMB_QUERY_FS_QUOTA_INFO 0x3ee
++
++typedef struct smb_com_transaction2_qfsi_req {
++ struct smb_hdr hdr; /* wct = 14+ */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 MaxParameterCount;
++ __u16 MaxDataCount;
++ __u8 MaxSetupCount;
++ __u8 Reserved;
++ __u16 Flags;
++ __u32 Timeout;
++ __u16 Reserved2;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u8 SetupCount;
++ __u8 Reserved3;
++ __u16 SubCommand; /* one setup word */
++ __u16 ByteCount;
++ __u8 Pad;
++ __u16 InformationLevel;
++} TRANSACTION2_QFSI_REQ;
++
++typedef struct smb_com_transaction_qfsi_rsp {
++ struct smb_hdr hdr; /* wct = 10 + SetupCount */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 Reserved;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 ParameterDisplacement;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u16 DataDisplacement;
++ __u8 SetupCount;
++ __u8 Reserved1; /* should be zero setup words following */
++ __u16 ByteCount;
++ __u8 Pad; /* may be three bytes *//* followed by data area */
++} TRANSACTION2_QFSI_RSP;
++
++typedef struct smb_com_transaction2_get_dfs_refer_req {
++ struct smb_hdr hdr; /* wct = 15 */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 MaxParameterCount;
++ __u16 MaxDataCount;
++ __u8 MaxSetupCount;
++ __u8 Reserved;
++ __u16 Flags;
++ __u32 Timeout;
++ __u16 Reserved2;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u8 SetupCount;
++ __u8 Reserved3;
++ __u16 SubCommand; /* one setup word */
++ __u16 ByteCount;
++ __u8 Pad[3]; /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */
++ __u16 MaxReferralLevel;
++ char RequestFileName[1];
++} TRANSACTION2_GET_DFS_REFER_REQ;
++
++typedef struct dfs_referral_level_3 {
++ __u16 VersionNumber;
++ __u16 ReferralSize;
++ __u16 ServerType; /* 0x0001 = CIFS server */
++ __u16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */
++ __u16 TimeToLive;
++ __u16 Proximity;
++ __u16 DfsPathOffset;
++ __u16 DfsAlternatePathOffset;
++ __u16 NetworkAddressOffset;
++} REFERRAL3;
++
++typedef struct smb_com_transaction_get_dfs_refer_rsp {
++ struct smb_hdr hdr; /* wct = 10 */
++ __u16 TotalParameterCount;
++ __u16 TotalDataCount;
++ __u16 Reserved;
++ __u16 ParameterCount;
++ __u16 ParameterOffset;
++ __u16 ParameterDisplacement;
++ __u16 DataCount;
++ __u16 DataOffset;
++ __u16 DataDisplacement;
++ __u8 SetupCount;
++ __u8 Reserved1; /* zero setup words following */
++ __u16 ByteCount;
++ __u8 Pad;
++ __u16 PathConsumed;
++ __u16 NumberOfReferrals;
++ __u16 DFSFlags;
++ __u16 Pad2;
++ REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */
++ /* followed by the strings pointed to by the referral structures */
++} TRANSACTION2_GET_DFS_REFER_RSP;
++
++/* DFS Flags */
++#define DFSREF_REFERRAL_SERVER 0x0001
++#define DFSREF_STORAGE_SERVER 0x0002
++
++/* IOCTL information */
++/* List of ioctl function codes that look to be of interest to remote clients like this. */
++/* Need to do some experimentation to make sure they all work remotely. */
++/* Some of the following such as the encryption/compression ones would be */
++/* invoked from tools via a specialized hook into the VFS rather than via the */
++/* standard vfs entry points */
++#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000
++#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004
++#define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008
++#define FSCTL_LOCK_VOLUME 0x00090018
++#define FSCTL_UNLOCK_VOLUME 0x0009001C
++#define FSCTL_GET_COMPRESSION 0x0009003C
++#define FSCTL_SET_COMPRESSION 0x0009C040
++#define FSCTL_REQUEST_FILTER_OPLOCK 0x0009008C
++#define FSCTL_FILESYS_GET_STATISTICS 0x00090090
++#define FSCTL_SET_REPARSE_POINT 0x000900A4
++#define FSCTL_GET_REPARSE_POINT 0x000900A8
++#define FSCTL_DELETE_REPARSE_POINT 0x000900AC
++#define FSCTL_SET_SPARSE 0x000900C4
++#define FSCTL_SET_ZERO_DATA 0x000900C8
++#define FSCTL_SET_ENCRYPTION 0x000900D7
++#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB
++#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF
++#define FSCTL_READ_RAW_ENCRYPTED 0x000900E3
++#define FSCTL_SIS_COPYFILE 0x00090100
++#define FSCTL_SIS_LINK_FILES 0x0009C104
++
++#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003
++#define IO_REPARSE_TAG_HSM 0xC0000004
++#define IO_REPARSE_TAG_SIS 0x80000007
++
++/*
++ ************************************************************************
++ * All structs for everything above the SMB PDUs themselves
++ * (such as the T2 level specific data) go here
++ ************************************************************************
++ */
++
++/*
++ * Information on a server
++ */
++
++struct serverInfo {
++ char name[16];
++ unsigned char versionMajor;
++ unsigned char versionMinor;
++ unsigned long type;
++ unsigned int commentOffset;
++};
++
++/*
++ * The following structure is the format of the data returned on a NetShareEnum
++ * with level "90" (x5A)
++ */
++
++struct shareInfo {
++ char shareName[13];
++ char pad;
++ unsigned short type;
++ unsigned int commentOffset;
++};
++
++struct aliasInfo {
++ char aliasName[9];
++ char pad;
++ unsigned int commentOffset;
++ unsigned char type[2];
++};
++
++struct aliasInfo92 {
++ int aliasNameOffset;
++ int serverNameOffset;
++ int shareNameOffset;
++};
++
++typedef struct {
++ __u64 TotalAllocationUnits;
++ __u64 FreeAllocationUnits;
++ __u32 SectorsPerAllocationUnit;
++ __u32 BytesPerSector;
++} FILE_SYSTEM_INFO; /* size info, level 0x103 */
++
++typedef struct {
++ __u16 MajorVersionNumber;
++ __u16 MinorVersionNumber;
++ __u64 Capability;
++} FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */
++/* Linux/Unix extensions capability flags */
++#define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */
++#define CIFS_UNIX_POSIX_ACL_CAP 0x00000002
++
++/* DeviceType Flags */
++#define FILE_DEVICE_CD_ROM 0x00000002
++#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003
++#define FILE_DEVICE_DFS 0x00000006
++#define FILE_DEVICE_DISK 0x00000007
++#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
++#define FILE_DEVICE_FILE_SYSTEM 0x00000009
++#define FILE_DEVICE_NAMED_PIPE 0x00000011
++#define FILE_DEVICE_NETWORK 0x00000012
++#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
++#define FILE_DEVICE_NULL 0x00000015
++#define FILE_DEVICE_PARALLEL_PORT 0x00000016
++#define FILE_DEVICE_PRINTER 0x00000018
++#define FILE_DEVICE_SERIAL_PORT 0x0000001b
++#define FILE_DEVICE_STREAMS 0x0000001e
++#define FILE_DEVICE_TAPE 0x0000001f
++#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
++#define FILE_DEVICE_VIRTUAL_DISK 0x00000024
++#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028
++
++typedef struct {
++ __u32 DeviceType;
++ __u32 DeviceCharacteristics;
++} FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */
++
++typedef struct {
++ __u32 Attributes;
++ __u32 MaxPathNameComponentLength;
++ __u32 FileSystemNameLen;
++ char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */
++} FILE_SYSTEM_ATTRIBUTE_INFO;
++
++typedef struct { /* data block encoding of response to level 263 QPathInfo */
++ __u64 CreationTime;
++ __u64 LastAccessTime;
++ __u64 LastWriteTime;
++ __u64 ChangeTime;
++ __u32 Attributes;
++ __u32 Pad1;
++ __u64 AllocationSize;
++ __u64 EndOfFile; /* size ie offset to first free byte in file */
++ __u32 NumberOfLinks; /* hard links */
++ __u8 DeletePending;
++ __u8 Directory;
++ __u16 Pad2;
++ __u64 IndexNumber;
++ __u32 EASize;
++ __u32 AccessFlags;
++ __u64 IndexNumber1;
++ __u64 CurrentByteOffset;
++ __u32 Mode;
++ __u32 AlignmentRequirement;
++ __u32 FileNameLength;
++ char FileName[1];
++} FILE_ALL_INFO; /* level 263 QPathInfo */
++
++typedef struct {
++ __u64 EndOfFile;
++ __u64 NumOfBytes;
++ __u64 LastStatusChange; /*SNIA spec says DCE time for the three time fields */
++ __u64 LastAccessTime;
++ __u64 LastModificationTime;
++ __u64 Uid;
++ __u64 Gid;
++ __u32 Type;
++ __u64 DevMajor;
++ __u64 DevMinor;
++ __u64 UniqueId;
++ __u64 Permissions;
++ __u64 Nlinks;
++} FILE_UNIX_BASIC_INFO; /* level 512 QPathInfo */
++
++typedef struct {
++ char LinkDest[1];
++} FILE_UNIX_LINK_INFO; /* level 513 QPathInfo */
++
++/* defines for enumerating possible values of the Unix type field below */
++#define UNIX_FILE 0
++#define UNIX_DIR 1
++#define UNIX_SYMLINK 2
++#define UNIX_CHARDEV 3
++#define UNIX_BLOCKDEV 4
++#define UNIX_FIFO 5
++#define UNIX_SOCKET 6
++
++typedef struct {
++ __u32 NextEntryOffset;
++ __u32 ResumeKey;
++ __u64 EndOfFile;
++ __u64 NumOfBytes;
++ __u64 LastStatusChange; /*SNIA spec says DCE time for the three time fields */
++ __u64 LastAccessTime;
++ __u64 LastModificationTime;
++ __u64 Uid;
++ __u64 Gid;
++ __u32 Type;
++ __u64 DevMajor;
++ __u64 DevMinor;
++ __u64 UniqueId;
++ __u64 Permissions;
++ __u64 Nlinks;
++ char FileName[1];
++} FILE_UNIX_INFO;
++
++typedef struct {
++ __u64 CreationTime;
++ __u64 LastAccessTime;
++ __u64 LastWriteTime;
++ __u64 ChangeTime;
++ __u32 Attributes;
++ __u32 Pad;
++} FILE_BASIC_INFO; /* size info, level 0x101 */
++
++struct file_allocation_info {
++ __u64 AllocationSize;
++}; /* size info, level 0x103 */
++
++struct file_end_of_file_info {
++ __u64 FileSize; /* offset to end of file */
++}; /* size info, level 0x104 */
++
++typedef struct {
++ __u32 NextEntryOffset;
++ __u32 FileIndex;
++ __u64 CreationTime;
++ __u64 LastAccessTime;
++ __u64 LastWriteTime;
++ __u64 ChangeTime;
++ __u64 EndOfFile;
++ __u64 AllocationSize;
++ __u32 ExtFileAttributes;
++ __u32 FileNameLength;
++ char FileName[1];
++} FILE_DIRECTORY_INFO; /* level 257 FF response data area */
++
++struct gea {
++ unsigned char cbName;
++ char szName[1];
++};
++
++struct gealist {
++ unsigned long cbList;
++ struct gea list[1];
++};
++
++struct fea {
++ unsigned char EA_flags;
++ __u8 name_len;
++ __u16 value_len;
++ char szName[1];
++ /* optionally followed by value */
++};
++/* flags for _FEA.fEA */
++#define FEA_NEEDEA 0x80 /* need EA bit */
++
++struct fealist {
++ __u32 list_len;
++ struct fea list[1];
++};
++
++/* used to hold an arbitrary blob of data */
++struct data_blob {
++ __u8 *data;
++ size_t length;
++ void (*free) (struct data_blob * data_blob);
++};
++
++#ifdef CONFIG_CIFS_POSIX
++/*
++ For better POSIX semantics from Linux client, (even better
++ than the existing CIFS Unix Extensions) we need updated PDUs for:
++
++ 1) PosixCreateX - to set and return the mode, inode#, device info and
++ perhaps add a CreateDevice - to create Pipes and other special .inodes
++ Also note POSIX open flags
++ 2) Close - to return the last write time to do cache across close more safely
++ 3) PosixQFSInfo - to return statfs info
++ 4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes)
++ 5) Mkdir - set mode
++
++ And under consideration:
++ 6) FindClose2 (return nanosecond timestamp ??)
++ 7) Use nanosecond timestamps throughout all time fields if
++ corresponding attribute flag is set
++ 8) sendfile - handle based copy
++ 9) Direct i/o
++ 10) "POSIX ACL" support
++ 11) Misc fcntls?
++
++ what about fixing 64 bit alignment
++
++ There are also various legacy SMB/CIFS requests used as is
++
++ From existing Lanman and NTLM dialects:
++ --------------------------------------
++ NEGOTIATE
++ SESSION_SETUP_ANDX (BB which?)
++ TREE_CONNECT_ANDX (BB which wct?)
++ TREE_DISCONNECT (BB add volume timestamp on response)
++ LOGOFF_ANDX
++ DELETE (note delete open file behavior)
++ DELETE_DIRECTORY
++ READ_AND_X
++ WRITE_AND_X
++ LOCKING_AND_X (note posix lock semantics)
++ RENAME (note rename across dirs and open file rename posix behaviors)
++ NT_RENAME (for hardlinks) Is this good enough for all features?
++ FIND_CLOSE2
++ TRANSACTION2 (18 cases)
++ SMB_SET_FILE_END_OF_FILE_INFO2 SMB_SET_PATH_END_OF_FILE_INFO2
++ (BB verify that never need to set allocation size)
++ SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via Unix ext?)
++
++ COPY (note support for copy across directories) - FUTURE, OPTIONAL
++ setting/getting OS/2 EAs - FUTURE (BB can this handle
++ setting Linux xattrs perfectly) - OPTIONAL
++ dnotify - FUTURE, OPTIONAL
++ quota - FUTURE, OPTIONAL
++
++ Note that various requests implemented for NT interop such as
++ NT_TRANSACT (IOCTL) QueryReparseInfo
++ are unneeded to servers compliant with the CIFS POSIX extensions
++
++ From CIFS Unix Extensions:
++ -------------------------
++ T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks
++ T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2)
++ T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK)
++ T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields
++ Actually need QUERY_FILE_UNIX_INFO since has inode num
++ BB what about a) blksize/blkbits/blocks
++ b) i_version
++ c) i_rdev
++ d) notify mask?
++ e) generation
++ f) size_seqcount
++ T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX
++ TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended
++ T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL
++
++
++ */
++#endif
++
++#pragma pack() /* resume default structure packing */
++
++#endif /* _CIFSPDU_H */
+diff -urN linux-2.4.29.old/fs/cifs/cifsproto.h linux-2.4.29/fs/cifs/cifsproto.h
+--- linux-2.4.29.old/fs/cifs/cifsproto.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/cifsproto.h 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,254 @@
++/*
++ * fs/cifs/cifsproto.h
++ *
++ * Copyright (c) International Business Machines Corp., 2002
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#ifndef _CIFSPROTO_H
++#define _CIFSPROTO_H
++#include <linux/nls.h>
++
++struct statfs;
++
++/*
++ *****************************************************************
++ * All Prototypes
++ *****************************************************************
++ */
++
++extern struct smb_hdr *cifs_buf_get(void);
++extern void cifs_buf_release(void *);
++extern int smb_send(struct socket *, struct smb_hdr *,
++ unsigned int /* length */ , struct sockaddr *);
++extern unsigned int _GetXid(void);
++extern void _FreeXid(unsigned int);
++#define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__FUNCTION__, xid,current->fsuid));
++#define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__FUNCTION__,curr_xid,rc));}
++extern char *build_path_from_dentry(struct dentry *);
++extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
++extern void renew_parental_timestamps(struct dentry *direntry);
++extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
++ struct smb_hdr * /* input */ ,
++ struct smb_hdr * /* out */ ,
++ int * /* bytes returned */ , const int long_op);
++extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
++extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
++extern int is_valid_oplock_break(struct smb_hdr *smb);
++extern unsigned int smbCalcSize(struct smb_hdr *ptr);
++extern int decode_negTokenInit(unsigned char *security_blob, int length,
++ enum securityEnum *secType);
++extern int map_smb_to_linux_error(struct smb_hdr *smb);
++extern void header_assemble(struct smb_hdr *, char /* command */ ,
++ const struct cifsTconInfo *, int
++ /* length of fixed section (word count) in two byte units */
++ );
++struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *);
++void DeleteOplockQEntry(struct oplock_q_entry *);
++extern time_t cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
++extern u64 cifs_UnixTimeToNT(time_t);
++extern int cifs_get_inode_info(struct inode **pinode,
++ const unsigned char *search_path,
++ FILE_ALL_INFO * pfile_info,
++ struct super_block *sb, int xid);
++extern int cifs_get_inode_info_unix(struct inode **pinode,
++ const unsigned char *search_path,
++ struct super_block *sb,int xid);
++
++extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
++ struct nls_table * nls_info);
++extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses);
++
++extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
++ const char *tree, struct cifsTconInfo *tcon,
++ const struct nls_table *);
++
++extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
++ const char *searchName,
++ FILE_DIRECTORY_INFO * findData,
++ T2_FFIRST_RSP_PARMS * findParms,
++ const struct nls_table *nls_codepage,
++ int *pUnicodeFlag,
++ int *pUnixFlag /* if Unix extensions used */ );
++extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
++ FILE_DIRECTORY_INFO * findData,
++ T2_FNEXT_RSP_PARMS * findParms,
++ const __u16 searchHandle, char * resume_name,
++ int name_length, __u32 resume_key,
++ int *UnicodeFlag, int *pUnixFlag);
++
++extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
++ const __u16 search_handle);
++
++extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
++ const unsigned char *searchName,
++ FILE_ALL_INFO * findData,
++ const struct nls_table *nls_codepage);
++
++extern int CIFSSMBUnixQPathInfo(const int xid,
++ struct cifsTconInfo *tcon,
++ const unsigned char *searchName,
++ FILE_UNIX_BASIC_INFO * pFindData,
++ const struct nls_table *nls_codepage);
++
++extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
++ const unsigned char *searchName,
++ unsigned char **targetUNCs,
++ unsigned int *number_of_UNC_in_array,
++ const struct nls_table *nls_codepage);
++
++extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
++ const char *old_path,
++ const struct nls_table *nls_codepage);
++extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
++ const char *old_path, const struct nls_table *nls_codepage,
++ unsigned int *pnum_referrals, unsigned char ** preferrals);
++extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
++ struct statfs *FSData,
++ const struct nls_table *nls_codepage);
++extern int CIFSSMBQFSAttributeInfo(const int xid,
++ struct cifsTconInfo *tcon,
++ const struct nls_table *nls_codepage);
++extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon,
++ const struct nls_table *nls_codepage);
++extern int CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
++ const struct nls_table *nls_codepage);
++
++extern int CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon,
++ char *fileName, FILE_BASIC_INFO * data,
++ const struct nls_table *nls_codepage);
++extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon,
++ char *fileName, __u64 size,int setAllocationSizeFlag,
++ const struct nls_table *nls_codepage);
++extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon,
++ __u64 size, __u16 fileHandle,__u32 opener_pid, int AllocSizeFlag);
++extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon,
++ char *full_path, __u64 mode, __u64 uid,
++ __u64 gid, dev_t dev, const struct nls_table *nls_codepage);
++
++extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
++ const char *newName,
++ const struct nls_table *nls_codepage);
++extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
++ const char *name, const struct nls_table *nls_codepage);
++
++extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
++ const char *name,
++ const struct nls_table *nls_codepage);
++extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
++ const char *fromName, const char *toName,
++ const struct nls_table *nls_codepage);
++extern int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
++ int netfid, char * target_name, const struct nls_table *nls_codepage);
++extern int CIFSCreateHardLink(const int xid,
++ struct cifsTconInfo *tcon,
++ const char *fromName, const char *toName,
++ const struct nls_table *nls_codepage);
++extern int CIFSUnixCreateHardLink(const int xid,
++ struct cifsTconInfo *tcon,
++ const char *fromName, const char *toName,
++ const struct nls_table *nls_codepage);
++extern int CIFSUnixCreateSymLink(const int xid,
++ struct cifsTconInfo *tcon,
++ const char *fromName, const char *toName,
++ const struct nls_table *nls_codepage);
++extern int CIFSSMBUnixQuerySymLink(const int xid,
++ struct cifsTconInfo *tcon,
++ const unsigned char *searchName,
++ char *syminfo, const int buflen,
++ const struct nls_table *nls_codepage);
++extern int CIFSSMBQueryReparseLinkInfo(const int xid,
++ struct cifsTconInfo *tcon,
++ const unsigned char *searchName,
++ char *symlinkinfo, const int buflen, __u16 fid,
++ const struct nls_table *nls_codepage);
++
++extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
++ const char *fileName, const int disposition,
++ const int access_flags, const int omode,
++ __u16 * netfid, int *pOplock, FILE_ALL_INFO *,
++ const struct nls_table *nls_codepage);
++extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
++ const int smb_file_id);
++
++extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
++ const int netfid, unsigned int count,
++ const __u64 lseek, unsigned int *nbytes, char **buf);
++extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
++ const int netfid, const unsigned int count,
++ const __u64 lseek, unsigned int *nbytes,
++ const char *buf, const int long_op);
++extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
++ const __u16 netfid, const __u64 len,
++ const __u64 offset, const __u32 numUnlock,
++ const __u32 numLock, const __u8 lockType,
++ const int waitFlag);
++
++extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon);
++extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses);
++
++extern struct cifsSesInfo *sesInfoAlloc(void);
++extern void sesInfoFree(struct cifsSesInfo *);
++extern struct cifsTconInfo *tconInfoAlloc(void);
++extern void tconInfoFree(struct cifsTconInfo *);
++
++extern int cifs_reconnect(struct TCP_Server_Info *server);
++
++extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *);
++extern int cifs_verify_signature(const struct smb_hdr *, const char * mac_key,
++ __u32 expected_sequence_number);
++extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
++extern void CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *);
++extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * );
++
++extern int CIFSBuildServerList(int xid, char *serverBufferList,
++ int recordlength, int *entries,
++ int *totalEntries, int *topoChangedFlag);
++extern int CIFSSMBQueryShares(int xid, struct cifsTconInfo *tcon,
++ struct shareInfo *shareList, int bufferLen,
++ int *entries, int *totalEntries);
++extern int CIFSSMBQueryAlias(int xid, struct cifsTconInfo *tcon,
++ struct aliasInfo *aliasList, int bufferLen,
++ int *entries, int *totalEntries);
++extern int CIFSSMBAliasInfo(int xid, struct cifsTconInfo *tcon,
++ char *aliasName, char *serverName,
++ char *shareName, char *comment);
++extern int CIFSSMBGetShareInfo(int xid, struct cifsTconInfo *tcon,
++ char *share, char *comment);
++extern int CIFSSMBGetUserPerms(int xid, struct cifsTconInfo *tcon,
++ char *userName, char *searchName, int *perms);
++extern int CIFSSMBSync(int xid, struct cifsTconInfo *tcon, int netfid, int pid);
++
++extern int CIFSSMBSeek(int xid,
++ struct cifsTconInfo *tcon,
++ int netfid,
++ int pid,
++ int whence, unsigned long offset, long long *newoffset);
++
++extern int CIFSSMBCopy(int xid,
++ struct cifsTconInfo *source_tcon,
++ const char *fromName,
++ const __u16 target_tid,
++ const char *toName, const int flags,
++ const struct nls_table *nls_codepage);
++extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
++ const int notify_subdirs,const __u16 netfid,__u32 filter,
++ const struct nls_table *nls_codepage);
++extern int CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
++ const unsigned char *searchName,
++ char * EAData, size_t size,
++ const struct nls_table *nls_codepage);
++#endif /* _CIFSPROTO_H */
+diff -urN linux-2.4.29.old/fs/cifs/cifssmb.c linux-2.4.29/fs/cifs/cifssmb.c
+--- linux-2.4.29.old/fs/cifs/cifssmb.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/cifssmb.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,3016 @@
++/*
++ * fs/cifs/cifssmb.c
++ *
++ * Copyright (C) International Business Machines Corp., 2002,2003
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * Contains the routines for constructing the SMB PDUs themselves
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++ /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
++ /* These are mostly routines that operate on a pathname, or on a tree id */
++ /* (mounted volume), but there are eight handle based routines which must be */
++ /* treated slightly different for reconnection purposes since we never want */
++ /* to reuse a stale file handle and the caller knows the file handle */
++
++#include <linux/fs.h>
++#include <linux/kernel.h>
++#include <linux/vfs.h>
++#include <asm/uaccess.h>
++#include "cifspdu.h"
++#include "cifsglob.h"
++#include "cifsproto.h"
++#include "cifs_unicode.h"
++#include "cifs_debug.h"
++
++#ifdef CONFIG_CIFS_POSIX
++static struct {
++ int index;
++ char *name;
++} protocols[] = {
++ {CIFS_PROT, "\2NT LM 0.12"},
++ {CIFS_PROT, "\2POSIX 2"},
++ {BAD_PROT, "\2"}
++};
++#else
++static struct {
++ int index;
++ char *name;
++} protocols[] = {
++ {CIFS_PROT, "\2NT LM 0.12"},
++ {BAD_PROT, "\2"}
++};
++#endif
++
++
++/* Mark as invalid, all open files on tree connections since they
++ were closed when session to server was lost */
++static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
++{
++ struct cifsFileInfo *open_file = NULL;
++ struct list_head * tmp;
++ struct list_head * tmp1;
++
++/* list all files open on tree connection and mark them invalid */
++ write_lock(&GlobalSMBSeslock);
++ list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
++ open_file = list_entry(tmp,struct cifsFileInfo, tlist);
++ if(open_file) {
++ open_file->invalidHandle = TRUE;
++ }
++ }
++ write_unlock(&GlobalSMBSeslock);
++ /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */
++}
++
++static int
++smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
++ void **request_buf /* returned */ ,
++ void **response_buf /* returned */ )
++{
++ int rc = 0;
++ int timeout = 10 * HZ;
++
++ /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
++ check for tcp and smb session status done differently
++ for those three - in the calling routine */
++ if(tcon) {
++ if((tcon->ses) && (tcon->ses->server)){
++ struct nls_table *nls_codepage;
++ /* Give Demultiplex thread up to 10 seconds to
++ reconnect, should be greater than cifs socket
++ timeout which is 7 seconds */
++ while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
++ while ((tcon->ses->server->tcpStatus != CifsGood) && (timeout > 0)){
++ timeout = interruptible_sleep_on_timeout(&tcon->ses->server->response_q,timeout);
++ }
++ if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
++ /* on "soft" mounts we wait once */
++ if((tcon->retry == FALSE) ||
++ (tcon->ses->status == CifsExiting)) {
++ cFYI(1,("gave up waiting on reconnect in smb_init"));
++ return -EHOSTDOWN;
++ } /* else "hard" mount - keep retrying until
++ process is killed or server comes back up */
++ } else /* TCP session is reestablished now */
++ break;
++
++ }
++
++ nls_codepage = load_nls_default();
++ /* need to prevent multiple threads trying to
++ simultaneously reconnect the same SMB session */
++ down(&tcon->ses->sesSem);
++ if(tcon->ses->status == CifsNeedReconnect)
++ rc = cifs_setup_session(0, tcon->ses, nls_codepage);
++ if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
++ mark_open_files_invalid(tcon);
++ rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
++ nls_codepage);
++ up(&tcon->ses->sesSem);
++ if(rc == 0)
++ atomic_inc(&tconInfoReconnectCount);
++
++ cFYI(1, ("reconnect tcon rc = %d", rc));
++ /* Removed call to reopen open files here -
++ it is safer (and faster) to reopen files
++ one at a time as needed in read and write */
++
++ /* Check if handle based operation so we
++ know whether we can continue or not without
++ returning to caller to reset file handle */
++ switch(smb_command) {
++ case SMB_COM_READ_ANDX:
++ case SMB_COM_WRITE_ANDX:
++ case SMB_COM_CLOSE:
++ case SMB_COM_FIND_CLOSE2:
++ case SMB_COM_LOCKING_ANDX: {
++ unload_nls(nls_codepage);
++ return -EAGAIN;
++ }
++ }
++ } else {
++ up(&tcon->ses->sesSem);
++ }
++ unload_nls(nls_codepage);
++
++ } else {
++ return -EIO;
++ }
++ }
++ if(rc)
++ return rc;
++
++ *request_buf = cifs_buf_get();
++ if (*request_buf == 0) {
++ /* BB should we add a retry in here if not a writepage? */
++ return -ENOMEM;
++ }
++ /* Although the original thought was we needed the response buf for */
++ /* potential retries of smb operations it turns out we can determine */
++ /* from the mid flags when the request buffer can be resent without */
++ /* having to use a second distinct buffer for the response */
++ *response_buf = *request_buf;
++
++ header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
++ wct /*wct */ );
++
++#ifdef CONFIG_CIFS_STATS
++ if(tcon != NULL) {
++ atomic_inc(&tcon->num_smbs_sent);
++ }
++#endif
++ return rc;
++}
++
++int
++CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
++{
++ NEGOTIATE_REQ *pSMB;
++ NEGOTIATE_RSP *pSMBr;
++ int rc = 0;
++ int bytes_returned;
++ struct TCP_Server_Info * server;
++
++ if(ses->server)
++ server = ses->server;
++ else {
++ rc = -EIO;
++ return rc;
++ }
++ rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
++ (void **) &pSMB, (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
++ if (extended_security)
++ pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
++
++ pSMB->ByteCount = strlen(protocols[0].name) + 1;
++ strncpy(pSMB->DialectsArray, protocols[0].name, 30);
++ /* null guaranteed to be at end of source and target buffers anyway */
++
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc == 0) {
++ server->secMode = pSMBr->SecurityMode;
++ server->secType = NTLM; /* BB override default for NTLMv2 or krb*/
++ /* one byte - no need to convert this or EncryptionKeyLen from le,*/
++ server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
++ /* probably no need to store and check maxvcs */
++ server->maxBuf =
++ min(le32_to_cpu(pSMBr->MaxBufferSize),
++ (__u32) CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE);
++ server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
++ cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
++ GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
++ server->capabilities = le32_to_cpu(pSMBr->Capabilities);
++ server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
++ /* BB with UTC do we ever need to be using srvr timezone? */
++ if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
++ memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
++ CIFS_CRYPTO_KEY_SIZE);
++ } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
++ && (pSMBr->EncryptionKeyLength == 0)) {
++ /* decode security blob */
++ } else
++ rc = -EIO;
++
++ /* BB might be helpful to save off the domain of server here */
++
++ if (pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) {
++ if (pSMBr->ByteCount < 16)
++ rc = -EIO;
++ else if (pSMBr->ByteCount == 16) {
++ server->secType = RawNTLMSSP;
++ if (server->socketUseCount.counter > 1) {
++ if (memcmp
++ (server->server_GUID,
++ pSMBr->u.extended_response.
++ GUID, 16) != 0) {
++ cFYI(1,
++ ("UID of server does not match previous connection to same ip address"));
++ memcpy(server->
++ server_GUID,
++ pSMBr->u.
++ extended_response.
++ GUID, 16);
++ }
++ } else
++ memcpy(server->server_GUID,
++ pSMBr->u.extended_response.
++ GUID, 16);
++ } else {
++ rc = decode_negTokenInit(pSMBr->u.
++ extended_response.
++ SecurityBlob,
++ pSMBr->ByteCount -
++ 16, &server->secType);
++ }
++ } else
++ server->capabilities &= ~CAP_EXTENDED_SECURITY;
++ if(sign_CIFS_PDUs == FALSE) {
++ if(server->secMode & SECMODE_SIGN_REQUIRED)
++ cERROR(1,
++ ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
++ server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
++ } else if(sign_CIFS_PDUs == 1) {
++ if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
++ server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
++ }
++
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++ return rc;
++}
++
++int
++CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
++{
++ struct smb_hdr *smb_buffer;
++ struct smb_hdr *smb_buffer_response;
++ int rc = 0;
++ int length;
++
++ cFYI(1, ("In tree disconnect"));
++ /*
++ * If last user of the connection and
++ * connection alive - disconnect it
++ * If this is the last connection on the server session disconnect it
++ * (and inside session disconnect we should check if tcp socket needs
++ * to be freed and kernel thread woken up).
++ */
++ if (tcon)
++ down(&tcon->tconSem);
++ else
++ return -EIO;
++
++ atomic_dec(&tcon->useCount);
++ if (atomic_read(&tcon->useCount) > 0) {
++ up(&tcon->tconSem);
++ return -EBUSY;
++ }
++
++ /* No need to return error on this operation if tid invalidated and
++ closed on server already e.g. due to tcp session crashing */
++ if(tcon->tidStatus == CifsNeedReconnect) {
++ up(&tcon->tconSem);
++ return 0;
++ }
++
++ if((tcon->ses == 0) || (tcon->ses->server == 0)) {
++ up(&tcon->tconSem);
++ return -EIO;
++ }
++
++ rc = smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
++ (void **) &smb_buffer, (void **) &smb_buffer_response);
++ if (rc) {
++ up(&tcon->tconSem);
++ return rc;
++ }
++ rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
++ &length, 0);
++ if (rc)
++ cFYI(1, (" Tree disconnect failed %d", rc));
++
++ if (smb_buffer)
++ cifs_buf_release(smb_buffer);
++ up(&tcon->tconSem);
++
++ /* No need to return error on this operation if tid invalidated and
++ closed on server already e.g. due to tcp session crashing */
++ if (rc == -EAGAIN)
++ rc = 0;
++
++ return rc;
++}
++
++int
++CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
++{
++ struct smb_hdr *smb_buffer_response;
++ LOGOFF_ANDX_REQ *pSMB;
++ int rc = 0;
++ int length;
++
++ cFYI(1, ("In SMBLogoff for session disconnect"));
++ if (ses)
++ down(&ses->sesSem);
++ else
++ return -EIO;
++
++ atomic_dec(&ses->inUse);
++ if (atomic_read(&ses->inUse) > 0) {
++ up(&ses->sesSem);
++ return -EBUSY;
++ }
++
++ rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL /* no tcon anymore */,
++ (void **) &pSMB, (void **) &smb_buffer_response);
++
++ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
++ pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
++
++ if (rc) {
++ up(&ses->sesSem);
++ return rc;
++ }
++
++ pSMB->hdr.Uid = ses->Suid;
++
++ pSMB->AndXCommand = 0xFF;
++ rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
++ smb_buffer_response, &length, 0);
++ if (ses->server) {
++ atomic_dec(&ses->server->socketUseCount);
++ if (atomic_read(&ses->server->socketUseCount) == 0) {
++ spin_lock(&GlobalMid_Lock);
++ ses->server->tcpStatus = CifsExiting;
++ spin_unlock(&GlobalMid_Lock);
++ rc = -ESHUTDOWN;
++ }
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++ up(&ses->sesSem);
++
++ /* if session dead then we do not need to do ulogoff,
++ since server closed smb session, no sense reporting
++ error */
++ if (rc == -EAGAIN)
++ rc = 0;
++ return rc;
++}
++
++int
++CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
++ const char *fileName, const struct nls_table *nls_codepage)
++{
++ DELETE_FILE_REQ *pSMB = NULL;
++ DELETE_FILE_RSP *pSMBr = NULL;
++ int rc = 0;
++ int bytes_returned;
++ int name_len;
++
++DelFileRetry:
++ rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len =
++ cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(fileName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->fileName, fileName, name_len);
++ }
++ pSMB->SearchAttributes =
++ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
++ pSMB->ByteCount = name_len + 1;
++ pSMB->BufferFormat = 0x04;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Error in RMFile = %d", rc));
++ }
++#ifdef CONFIG_CIFS_STATS
++ else {
++ atomic_inc(&tcon->num_deletes);
++ }
++#endif
++
++ if (pSMB)
++ cifs_buf_release(pSMB);
++ if (rc == -EAGAIN)
++ goto DelFileRetry;
++
++ return rc;
++}
++
++int
++CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
++ const char *dirName, const struct nls_table *nls_codepage)
++{
++ DELETE_DIRECTORY_REQ *pSMB = NULL;
++ DELETE_DIRECTORY_RSP *pSMBr = NULL;
++ int rc = 0;
++ int bytes_returned;
++ int name_len;
++
++ cFYI(1, ("In CIFSSMBRmDir"));
++RmDirRetry:
++ rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(dirName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->DirName, dirName, name_len);
++ }
++
++ pSMB->ByteCount = name_len + 1;
++ pSMB->BufferFormat = 0x04;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Error in RMDir = %d", rc));
++ }
++#ifdef CONFIG_CIFS_STATS
++ else {
++ atomic_inc(&tcon->num_rmdirs);
++ }
++#endif
++
++ if (pSMB)
++ cifs_buf_release(pSMB);
++ if (rc == -EAGAIN)
++ goto RmDirRetry;
++ return rc;
++}
++
++int
++CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
++ const char *name, const struct nls_table *nls_codepage)
++{
++ int rc = 0;
++ CREATE_DIRECTORY_REQ *pSMB = NULL;
++ CREATE_DIRECTORY_RSP *pSMBr = NULL;
++ int bytes_returned;
++ int name_len;
++
++ cFYI(1, ("In CIFSSMBMkDir"));
++MkDirRetry:
++ rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(name, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->DirName, name, name_len);
++ }
++
++ pSMB->ByteCount = name_len + 1 /* for buf format */ ;
++ pSMB->BufferFormat = 0x04;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Error in Mkdir = %d", rc));
++ }
++#ifdef CONFIG_CIFS_STATS
++ else {
++ atomic_inc(&tcon->num_mkdirs);
++ }
++#endif
++ if (pSMB)
++ cifs_buf_release(pSMB);
++ if (rc == -EAGAIN)
++ goto MkDirRetry;
++ return rc;
++}
++
++int
++CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
++ const char *fileName, const int openDisposition,
++ const int access_flags, const int create_options, __u16 * netfid,
++ int *pOplock, FILE_ALL_INFO * pfile_info,
++ const struct nls_table *nls_codepage)
++{
++ int rc = -EACCES;
++ OPEN_REQ *pSMB = NULL;
++ OPEN_RSP *pSMBr = NULL;
++ int bytes_returned;
++ int name_len;
++
++openRetry:
++ rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ pSMB->AndXCommand = 0xFF; /* none */
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ pSMB->ByteCount = 1; /* account for one byte pad to word boundary */
++ name_len =
++ cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1),
++ fileName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ pSMB->NameLength = cpu_to_le16(name_len);
++ } else { /* BB improve the check for buffer overruns BB */
++ pSMB->ByteCount = 0; /* no pad */
++ name_len = strnlen(fileName, 530);
++ name_len++; /* trailing null */
++ pSMB->NameLength = cpu_to_le16(name_len);
++ strncpy(pSMB->fileName, fileName, name_len);
++ }
++ if (*pOplock & REQ_OPLOCK)
++ pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
++ else if (*pOplock & REQ_BATCHOPLOCK) {
++ pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
++ }
++ pSMB->DesiredAccess = cpu_to_le32(access_flags);
++ pSMB->AllocationSize = 0;
++ pSMB->FileAttributes = ATTR_NORMAL;
++ /* XP does not handle ATTR_POSIX_SEMANTICS */
++ /* but it helps speed up case sensitive checks for other
++ servers such as Samba */
++ if (tcon->ses->capabilities & CAP_UNIX)
++ pSMB->FileAttributes |= ATTR_POSIX_SEMANTICS;
++
++ /* if ((omode & S_IWUGO) == 0)
++ pSMB->FileAttributes |= ATTR_READONLY;*/
++ /* Above line causes problems due to vfs splitting create into two
++ pieces - need to set mode after file created not while it is
++ being created */
++ pSMB->FileAttributes = cpu_to_le32(pSMB->FileAttributes);
++ pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
++ pSMB->CreateDisposition = cpu_to_le32(openDisposition);
++ pSMB->CreateOptions = cpu_to_le32(create_options);
++ pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ??*/
++ pSMB->SecurityFlags =
++ cpu_to_le32(SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY);
++
++ pSMB->ByteCount += name_len;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++ /* long_op set to 1 to allow for oplock break timeouts */
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 1);
++ if (rc) {
++ cFYI(1, ("Error in Open = %d", rc));
++ } else {
++ *pOplock = pSMBr->OplockLevel; /* one byte no need to le_to_cpu */
++ *netfid = pSMBr->Fid; /* cifs fid stays in le */
++ /* Let caller know file was created so we can set the mode. */
++ /* Do we care about the CreateAction in any other cases? */
++ if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
++ *pOplock |= CIFS_CREATE_ACTION;
++ if(pfile_info) {
++ memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
++ 36 /* CreationTime to Attributes */);
++ /* the file_info buf is endian converted by caller */
++ pfile_info->AllocationSize = pSMBr->AllocationSize;
++ pfile_info->EndOfFile = pSMBr->EndOfFile;
++ pfile_info->NumberOfLinks = cpu_to_le32(1);
++ }
++
++#ifdef CONFIG_CIFS_STATS
++ atomic_inc(&tcon->num_opens);
++#endif
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++ if (rc == -EAGAIN)
++ goto openRetry;
++ return rc;
++}
++
++/* If no buffer passed in, then caller wants to do the copy
++ as in the case of readpages so the SMB buffer must be
++ freed by the caller */
++
++int
++CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
++ const int netfid, const unsigned int count,
++ const __u64 lseek, unsigned int *nbytes, char **buf)
++{
++ int rc = -EACCES;
++ READ_REQ *pSMB = NULL;
++ READ_RSP *pSMBr = NULL;
++ char *pReadData = NULL;
++ int bytes_returned;
++
++ *nbytes = 0;
++ rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ /* tcon and ses pointer are checked in smb_init */
++ if (tcon->ses->server == NULL)
++ return -ECONNABORTED;
++
++ pSMB->AndXCommand = 0xFF; /* none */
++ pSMB->Fid = netfid;
++ pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
++ pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
++ pSMB->Remaining = 0;
++ pSMB->MaxCount = cpu_to_le16(count);
++ pSMB->MaxCountHigh = 0;
++ pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cERROR(1, ("Send error in read = %d", rc));
++ } else {
++ pSMBr->DataLength = le16_to_cpu(pSMBr->DataLength);
++ *nbytes = pSMBr->DataLength;
++ /*check that DataLength would not go beyond end of SMB */
++ if ((pSMBr->DataLength > CIFS_MAX_MSGSIZE)
++ || (pSMBr->DataLength > count)) {
++ cFYI(1,("bad length %d for count %d",pSMBr->DataLength,count));
++ rc = -EIO;
++ *nbytes = 0;
++ } else {
++ pReadData =
++ (char *) (&pSMBr->hdr.Protocol) +
++ le16_to_cpu(pSMBr->DataOffset);
++/* if(rc = copy_to_user(buf, pReadData, pSMBr->DataLength)) {
++ cERROR(1,("Faulting on read rc = %d",rc));
++ rc = -EFAULT;
++ }*/ /* can not use copy_to_user when using page cache*/
++ if(*buf)
++ memcpy(*buf,pReadData,pSMBr->DataLength);
++ }
++ }
++ if (pSMB) {
++ if(*buf)
++ cifs_buf_release(pSMB);
++ else
++ *buf = (char *)pSMB;
++ }
++
++ /* Note: On -EAGAIN error only caller can retry on handle based calls
++ since file handle passed in no longer valid */
++ return rc;
++}
++
++int
++CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
++ const int netfid, const unsigned int count,
++ const __u64 offset, unsigned int *nbytes, const char *buf,
++ const int long_op)
++{
++ int rc = -EACCES;
++ WRITE_REQ *pSMB = NULL;
++ WRITE_RSP *pSMBr = NULL;
++ int bytes_returned;
++
++ rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++ /* tcon and ses pointer are checked in smb_init */
++ if (tcon->ses->server == NULL)
++ return -ECONNABORTED;
++
++ pSMB->AndXCommand = 0xFF; /* none */
++ pSMB->Fid = netfid;
++ pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
++ pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
++ pSMB->Remaining = 0;
++ if (count > ((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00))
++ pSMB->DataLengthLow =
++ (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00;
++ else
++ pSMB->DataLengthLow = count;
++ pSMB->DataLengthHigh = 0;
++ pSMB->DataOffset =
++ cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
++
++ memcpy(pSMB->Data,buf,pSMB->DataLengthLow);
++
++ pSMB->ByteCount += pSMB->DataLengthLow + 1 /* pad */ ;
++ pSMB->DataLengthLow = cpu_to_le16(pSMB->DataLengthLow);
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
++ if (rc) {
++ cFYI(1, ("Send error in write = %d", rc));
++ *nbytes = 0;
++ } else
++ *nbytes = le16_to_cpu(pSMBr->Count);
++
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ /* Note: On -EAGAIN error only caller can retry on handle based calls
++ since file handle passed in no longer valid */
++
++ return rc;
++}
++
++int
++CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
++ const __u16 smb_file_id, const __u64 len,
++ const __u64 offset, const __u32 numUnlock,
++ const __u32 numLock, const __u8 lockType, const int waitFlag)
++{
++ int rc = 0;
++ LOCK_REQ *pSMB = NULL;
++ LOCK_RSP *pSMBr = NULL;
++ int bytes_returned;
++ int timeout = 0;
++ __u64 temp;
++
++ cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
++ rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
++ timeout = -1; /* no response expected */
++ pSMB->Timeout = 0;
++ } else if (waitFlag == TRUE) {
++ timeout = 3; /* blocking operation, no timeout */
++ pSMB->Timeout = -1; /* blocking - do not time out */
++ } else {
++ pSMB->Timeout = 0;
++ }
++
++ pSMB->NumberOfLocks = cpu_to_le32(numLock);
++ pSMB->NumberOfUnlocks = cpu_to_le32(numUnlock);
++ pSMB->LockType = lockType;
++ pSMB->AndXCommand = 0xFF; /* none */
++ pSMB->Fid = smb_file_id; /* netfid stays le */
++
++ if(numLock != 0) {
++ pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
++ /* BB where to store pid high? */
++ temp = cpu_to_le64(len);
++ pSMB->Locks[0].LengthLow = (__u32)(temp & 0xFFFFFFFF);
++ pSMB->Locks[0].LengthHigh = (__u32)(temp>>32);
++ temp = cpu_to_le64(offset);
++ pSMB->Locks[0].OffsetLow = (__u32)(temp & 0xFFFFFFFF);
++ pSMB->Locks[0].OffsetHigh = (__u32)(temp>>32);
++ pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE);
++ } else {
++ /* oplock break */
++ pSMB->ByteCount = 0;
++ }
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
++
++ if (rc) {
++ cFYI(1, ("Send error in Lock = %d", rc));
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ /* Note: On -EAGAIN error only caller can retry on handle based calls
++ since file handle passed in no longer valid */
++ return rc;
++}
++
++int
++CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
++{
++ int rc = 0;
++ CLOSE_REQ *pSMB = NULL;
++ CLOSE_RSP *pSMBr = NULL;
++ int bytes_returned;
++ cFYI(1, ("In CIFSSMBClose"));
++
++/* do not retry on dead session on close */
++ rc = smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if(rc == -EAGAIN)
++ return 0;
++ if (rc)
++ return rc;
++
++ pSMB->FileID = (__u16) smb_file_id;
++ pSMB->LastWriteTime = 0;
++ pSMB->ByteCount = 0;
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ if(rc!=-EINTR) {
++ /* EINTR is expected when user ctl-c to kill app */
++ cERROR(1, ("Send error in Close = %d", rc));
++ }
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ /* Since session is dead, file will be closed on server already */
++ if(rc == -EAGAIN)
++ rc = 0;
++
++ return rc;
++}
++
++int
++CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
++ const char *fromName, const char *toName,
++ const struct nls_table *nls_codepage)
++{
++ int rc = 0;
++ RENAME_REQ *pSMB = NULL;
++ RENAME_RSP *pSMBr = NULL;
++ int bytes_returned;
++ int name_len, name_len2;
++
++ cFYI(1, ("In CIFSSMBRename"));
++renameRetry:
++ rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ pSMB->BufferFormat = 0x04;
++ pSMB->SearchAttributes =
++ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
++ ATTR_DIRECTORY);
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len =
++ cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ pSMB->OldFileName[name_len] = 0x04; /* pad */
++ /* protocol requires ASCII signature byte on Unicode string */
++ pSMB->OldFileName[name_len + 1] = 0x00;
++ name_len2 =
++ cifs_strtoUCS((wchar_t *) & pSMB->
++ OldFileName[name_len + 2], toName, 530,
++ nls_codepage);
++ name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
++ name_len2 *= 2; /* convert to bytes */
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(fromName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->OldFileName, fromName, name_len);
++ name_len2 = strnlen(toName, 530);
++ name_len2++; /* trailing null */
++ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
++ strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
++ name_len2++; /* trailing null */
++ name_len2++; /* signature byte */
++ }
++
++ pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Send error in rename = %d", rc));
++ }
++
++#ifdef CONFIG_CIFS_STATS
++ else {
++ atomic_inc(&tcon->num_renames);
++ }
++#endif
++
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ if (rc == -EAGAIN)
++ goto renameRetry;
++
++ return rc;
++}
++
++int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
++ int netfid, char * target_name, const struct nls_table * nls_codepage)
++{
++ struct smb_com_transaction2_sfi_req *pSMB = NULL;
++ struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
++ struct set_file_rename * rename_info;
++ char *data_offset;
++ char dummy_string[30];
++ int rc = 0;
++ int bytes_returned = 0;
++ int len_of_str;
++
++ cFYI(1, ("Rename to File by handle"));
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ pSMB->ParameterCount = 6;
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req,
++ Fid) - 4;
++ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
++
++ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
++ rename_info = (struct set_file_rename *) data_offset;
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
++ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount;
++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
++ pSMB->TotalParameterCount = pSMB->ParameterCount;
++ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
++ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
++ /* construct random name ".cifs_tmp<inodenum><mid>" */
++ rename_info->overwrite = cpu_to_le32(1);
++ rename_info->root_fid = 0;
++ /* unicode only call */
++ if(target_name == NULL) {
++ sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
++ len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage);
++ } else {
++ len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, 530, nls_codepage);
++ }
++ rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
++ pSMB->DataCount = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
++ pSMB->ByteCount += pSMB->DataCount;
++ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
++ pSMB->TotalDataCount = pSMB->DataCount;
++ pSMB->Fid = netfid;
++ pSMB->InformationLevel =
++ cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
++ pSMB->Reserved4 = 0;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++ rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1,("Send error in Rename (by file handle) = %d", rc));
++ }
++#ifdef CONFIG_CIFS_STATS
++ else {
++ atomic_inc(&pTcon->num_t2renames);
++ }
++#endif
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ /* Note: On -EAGAIN error only caller can retry on handle based calls
++ since file handle passed in no longer valid */
++
++ return rc;
++}
++
++int
++CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
++ const __u16 target_tid, const char *toName, const int flags,
++ const struct nls_table *nls_codepage)
++{
++ int rc = 0;
++ COPY_REQ *pSMB = NULL;
++ COPY_RSP *pSMBr = NULL;
++ int bytes_returned;
++ int name_len, name_len2;
++
++ cFYI(1, ("In CIFSSMBCopy"));
++copyRetry:
++ rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ pSMB->BufferFormat = 0x04;
++ pSMB->Tid2 = target_tid;
++
++ if(flags & COPY_TREE)
++ pSMB->Flags |= COPY_TREE;
++ pSMB->Flags = cpu_to_le16(pSMB->Flags);
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName,
++ fromName,
++ 530 /* find define for this maxpathcomponent */,
++ nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ pSMB->OldFileName[name_len] = 0x04; /* pad */
++ /* protocol requires ASCII signature byte on Unicode string */
++ pSMB->OldFileName[name_len + 1] = 0x00;
++ name_len2 = cifs_strtoUCS((wchar_t *) & pSMB->
++ OldFileName[name_len + 2], toName, 530,
++ nls_codepage);
++ name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
++ name_len2 *= 2; /* convert to bytes */
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(fromName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->OldFileName, fromName, name_len);
++ name_len2 = strnlen(toName, 530);
++ name_len2++; /* trailing null */
++ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
++ strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
++ name_len2++; /* trailing null */
++ name_len2++; /* signature byte */
++ }
++
++ pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Send error in copy = %d with %d files copied",
++ rc, pSMBr->CopyCount));
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ if (rc == -EAGAIN)
++ goto copyRetry;
++
++ return rc;
++}
++
++int
++CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
++ const char *fromName, const char *toName,
++ const struct nls_table *nls_codepage)
++{
++ TRANSACTION2_SPI_REQ *pSMB = NULL;
++ TRANSACTION2_SPI_RSP *pSMBr = NULL;
++ char *data_offset;
++ int name_len;
++ int name_len_target;
++ int rc = 0;
++ int bytes_returned = 0;
++
++ cFYI(1, ("In Symlink Unix style"));
++createSymLinkRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len =
++ cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(fromName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->FileName, fromName, name_len);
++ }
++ pSMB->ParameterCount = 6 + name_len;
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
++ InformationLevel) - 4;
++ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
++
++ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len_target =
++ cifs_strtoUCS((wchar_t *) data_offset, toName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len_target++; /* trailing null */
++ name_len_target *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len_target = strnlen(toName, 530);
++ name_len_target++; /* trailing null */
++ strncpy(data_offset, toName, name_len_target);
++ }
++
++ pSMB->DataCount = name_len_target;
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ /* BB find exact max on data count below from sess */
++ pSMB->MaxDataCount = cpu_to_le16(1000);
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
++ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount;
++ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
++ pSMB->TotalDataCount = pSMB->DataCount;
++ pSMB->TotalParameterCount = pSMB->ParameterCount;
++ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
++ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
++ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
++ pSMB->Reserved4 = 0;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1,
++ ("Send error in SetPathInfo (create symlink) = %d",
++ rc));
++ }
++
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ if (rc == -EAGAIN)
++ goto createSymLinkRetry;
++
++ return rc;
++}
++
++int
++CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
++ const char *fromName, const char *toName,
++ const struct nls_table *nls_codepage)
++{
++ TRANSACTION2_SPI_REQ *pSMB = NULL;
++ TRANSACTION2_SPI_RSP *pSMBr = NULL;
++ char *data_offset;
++ int name_len;
++ int name_len_target;
++ int rc = 0;
++ int bytes_returned = 0;
++
++ cFYI(1, ("In Create Hard link Unix style"));
++createHardLinkRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(toName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->FileName, toName, name_len);
++ }
++ pSMB->ParameterCount = 6 + name_len;
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
++ InformationLevel) - 4;
++ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
++
++ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len_target =
++ cifs_strtoUCS((wchar_t *) data_offset, fromName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len_target++; /* trailing null */
++ name_len_target *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len_target = strnlen(fromName, 530);
++ name_len_target++; /* trailing null */
++ strncpy(data_offset, fromName, name_len_target);
++ }
++
++ pSMB->DataCount = name_len_target;
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ /* BB find exact max on data count below from sess*/
++ pSMB->MaxDataCount = cpu_to_le16(1000);
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
++ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount;
++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
++ pSMB->TotalParameterCount = pSMB->ParameterCount;
++ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
++ pSMB->TotalDataCount = pSMB->DataCount;
++ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
++ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
++ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
++ pSMB->Reserved4 = 0;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
++ }
++
++ if (pSMB)
++ cifs_buf_release(pSMB);
++ if (rc == -EAGAIN)
++ goto createHardLinkRetry;
++
++ return rc;
++}
++
++int
++CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
++ const char *fromName, const char *toName,
++ const struct nls_table *nls_codepage)
++{
++ int rc = 0;
++ NT_RENAME_REQ *pSMB = NULL;
++ RENAME_RSP *pSMBr = NULL;
++ int bytes_returned;
++ int name_len, name_len2;
++
++ cFYI(1, ("In CIFSCreateHardLink"));
++winCreateHardLinkRetry:
++
++ rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ pSMB->SearchAttributes =
++ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
++ ATTR_DIRECTORY);
++ pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
++ pSMB->ClusterCount = 0;
++
++ pSMB->BufferFormat = 0x04;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len =
++ cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ pSMB->OldFileName[name_len] = 0; /* pad */
++ pSMB->OldFileName[name_len + 1] = 0x04;
++ name_len2 =
++ cifs_strtoUCS((wchar_t *) & pSMB->
++ OldFileName[name_len + 2], toName, 530,
++ nls_codepage);
++ name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
++ name_len2 *= 2; /* convert to bytes */
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(fromName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->OldFileName, fromName, name_len);
++ name_len2 = strnlen(toName, 530);
++ name_len2++; /* trailing null */
++ pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
++ strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
++ name_len2++; /* trailing null */
++ name_len2++; /* signature byte */
++ }
++
++ pSMB->ByteCount = 1 /* string type byte */ + name_len + name_len2;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++ if (rc == -EAGAIN)
++ goto winCreateHardLinkRetry;
++
++ return rc;
++}
++
++int
++CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
++ const unsigned char *searchName,
++ char *symlinkinfo, const int buflen,
++ const struct nls_table *nls_codepage)
++{
++/* SMB_QUERY_FILE_UNIX_LINK */
++ TRANSACTION2_QPI_REQ *pSMB = NULL;
++ TRANSACTION2_QPI_RSP *pSMBr = NULL;
++ int rc = 0;
++ int bytes_returned;
++ int name_len;
++
++ cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
++
++querySymLinkRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len =
++ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(searchName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->FileName, searchName, name_len);
++ }
++
++ pSMB->TotalParameterCount =
++ 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
++ pSMB->TotalDataCount = 0;
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ /* BB find exact max data count below from sess structure BB */
++ pSMB->MaxDataCount = cpu_to_le16(4000);
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ParameterOffset = cpu_to_le16(offsetof(
++ struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
++ pSMB->DataCount = 0;
++ pSMB->DataOffset = 0;
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
++ pSMB->ParameterCount = pSMB->TotalParameterCount;
++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
++ pSMB->Reserved4 = 0;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
++ } else { /* decode response */
++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
++ pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
++ if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512))
++ /* BB also check enough total bytes returned */
++ rc = -EIO; /* bad smb */
++ else {
++ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len = UniStrnlen((wchar_t *) ((char *)
++ &pSMBr->hdr.Protocol +pSMBr->DataOffset),
++ min_t(const int, buflen,pSMBr->DataCount) / 2);
++ cifs_strfromUCS_le(symlinkinfo,
++ (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
++ pSMBr->DataOffset),
++ name_len, nls_codepage);
++ } else {
++ strncpy(symlinkinfo,
++ (char *) &pSMBr->hdr.Protocol +
++ pSMBr->DataOffset,
++ min_t(const int, buflen, pSMBr->DataCount));
++ }
++ symlinkinfo[buflen] = 0;
++ /* just in case so calling code does not go off the end of buffer */
++ }
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++ if (rc == -EAGAIN)
++ goto querySymLinkRetry;
++ return rc;
++}
++
++
++
++int
++CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
++ const unsigned char *searchName,
++ char *symlinkinfo, const int buflen,__u16 fid,
++ const struct nls_table *nls_codepage)
++{
++ int rc = 0;
++ int bytes_returned;
++ int name_len;
++ struct smb_com_transaction_ioctl_req * pSMB;
++ struct smb_com_transaction_ioctl_rsp * pSMBr;
++
++ cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
++ rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ pSMB->TotalParameterCount = 0 ;
++ pSMB->TotalDataCount = 0;
++ pSMB->MaxParameterCount = cpu_to_le32(2);
++ /* BB find exact data count max from sess structure BB */
++ pSMB->MaxDataCount = cpu_to_le32(4000);
++ pSMB->MaxSetupCount = 4;
++ pSMB->Reserved = 0;
++ pSMB->ParameterOffset = 0;
++ pSMB->DataCount = 0;
++ pSMB->DataOffset = 0;
++ pSMB->SetupCount = 4;
++ pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
++ pSMB->ParameterCount = pSMB->TotalParameterCount;
++ pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
++ pSMB->IsFsctl = 1; /* FSCTL */
++ pSMB->IsRootFlag = 0;
++ pSMB->Fid = fid; /* file handle always le */
++ pSMB->ByteCount = 0;
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
++ } else { /* decode response */
++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
++ pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
++ if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512))
++ /* BB also check enough total bytes returned */
++ rc = -EIO; /* bad smb */
++ else {
++ if(pSMBr->DataCount && (pSMBr->DataCount < 2048)) {
++ /* could also validate reparse tag && better check name length */
++ struct reparse_data * reparse_buf = (struct reparse_data *)
++ ((char *)&pSMBr->hdr.Protocol + pSMBr->DataOffset);
++ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len = UniStrnlen((wchar_t *)
++ (reparse_buf->LinkNamesBuf +
++ reparse_buf->TargetNameOffset),
++ min(buflen/2, reparse_buf->TargetNameLen / 2));
++ cifs_strfromUCS_le(symlinkinfo,
++ (wchar_t *) (reparse_buf->LinkNamesBuf +
++ reparse_buf->TargetNameOffset),
++ name_len, nls_codepage);
++ } else { /* ASCII names */
++ strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
++ reparse_buf->TargetNameOffset,
++ min_t(const int, buflen, reparse_buf->TargetNameLen));
++ }
++ } else {
++ rc = -EIO;
++ cFYI(1,("Invalid return data count on get reparse info ioctl"));
++ }
++ symlinkinfo[buflen] = 0; /* just in case so the caller
++ does not go off the end of the buffer */
++ cFYI(1,("readlink result - %s ",symlinkinfo));
++ }
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ /* Note: On -EAGAIN error only caller can retry on handle based calls
++ since file handle passed in no longer valid */
++
++ return rc;
++}
++
++int
++CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
++ const unsigned char *searchName,
++ FILE_ALL_INFO * pFindData,
++ const struct nls_table *nls_codepage)
++{
++/* level 263 SMB_QUERY_FILE_ALL_INFO */
++ TRANSACTION2_QPI_REQ *pSMB = NULL;
++ TRANSACTION2_QPI_RSP *pSMBr = NULL;
++ int rc = 0;
++ int bytes_returned;
++ int name_len;
++
++ cFYI(1, ("In QPathInfo path %s", searchName));
++QPathInfoRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len =
++ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(searchName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->FileName, searchName, name_len);
++ }
++
++ pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ +
++ name_len /* includes null */ ;
++ pSMB->TotalDataCount = 0;
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ParameterOffset = cpu_to_le16(offsetof(
++ struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
++ pSMB->DataCount = 0;
++ pSMB->DataOffset = 0;
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
++ pSMB->ParameterCount = pSMB->TotalParameterCount;
++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
++ pSMB->Reserved4 = 0;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Send error in QPathInfo = %d", rc));
++ } else { /* decode response */
++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
++ /* BB also check enough total bytes returned */
++ /* BB we need to improve the validity checking
++ of these trans2 responses */
++ if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512))
++ rc = -EIO; /* bad smb */
++ else if (pFindData){
++ memcpy((char *) pFindData,
++ (char *) &pSMBr->hdr.Protocol +
++ pSMBr->DataOffset, sizeof (FILE_ALL_INFO));
++ } else
++ rc = -ENOMEM;
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++ if (rc == -EAGAIN)
++ goto QPathInfoRetry;
++
++ return rc;
++}
++
++int
++CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
++ const unsigned char *searchName,
++ FILE_UNIX_BASIC_INFO * pFindData,
++ const struct nls_table *nls_codepage)
++{
++/* SMB_QUERY_FILE_UNIX_BASIC */
++ TRANSACTION2_QPI_REQ *pSMB = NULL;
++ TRANSACTION2_QPI_RSP *pSMBr = NULL;
++ int rc = 0;
++ int bytes_returned = 0;
++ int name_len;
++
++ cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
++UnixQPathInfoRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len =
++ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(searchName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->FileName, searchName, name_len);
++ }
++
++ pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ +
++ name_len /* includes null */ ;
++ pSMB->TotalDataCount = 0;
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ /* BB find exact max SMB PDU from sess structure BB */
++ pSMB->MaxDataCount = cpu_to_le16(4000);
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ParameterOffset = cpu_to_le16(offsetof(
++ struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
++ pSMB->DataCount = 0;
++ pSMB->DataOffset = 0;
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
++ pSMB->ParameterCount = pSMB->TotalParameterCount;
++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
++ pSMB->Reserved4 = 0;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Send error in QPathInfo = %d", rc));
++ } else { /* decode response */
++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
++ /* BB also check if enough total bytes returned */
++ if ((pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO)) ||
++ (pSMBr->DataOffset > 512) ||
++ (pSMBr->DataOffset < sizeof(struct smb_hdr))) {
++ cFYI(1,("UnixQPathinfo invalid data offset %d bytes returned %d",
++ (int)pSMBr->DataOffset,bytes_returned));
++ rc = -EIO; /* bad smb */
++ } else {
++ memcpy((char *) pFindData,
++ (char *) &pSMBr->hdr.Protocol +
++ pSMBr->DataOffset,
++ sizeof (FILE_UNIX_BASIC_INFO));
++ }
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++ if (rc == -EAGAIN)
++ goto UnixQPathInfoRetry;
++
++ return rc;
++}
++
++int
++CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
++ const char *searchName, FILE_ALL_INFO * findData,
++ const struct nls_table *nls_codepage)
++{
++/* level 257 SMB_ */
++ TRANSACTION2_FFIRST_REQ *pSMB = NULL;
++ TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
++ int rc = 0;
++ int bytes_returned;
++ int name_len;
++
++ cFYI(1, ("In FindUnique"));
++findUniqueRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len =
++ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(searchName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->FileName, searchName, name_len);
++ }
++
++ pSMB->TotalParameterCount = 12 + name_len /* includes null */ ;
++ pSMB->TotalDataCount = 0; /* no EAs */
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ParameterOffset = cpu_to_le16(
++ offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
++ pSMB->DataCount = 0;
++ pSMB->DataOffset = 0;
++ pSMB->SetupCount = 1; /* one byte, no need to le convert */
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalDataCount);
++ pSMB->ParameterCount = pSMB->TotalParameterCount;
++ pSMB->SearchAttributes =
++ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
++ ATTR_DIRECTORY);
++ pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
++ pSMB->SearchFlags = cpu_to_le16(1);
++ pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
++ pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++
++ if (rc) {
++ cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
++ } else { /* decode response */
++
++ /* BB fill in */
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++ if (rc == -EAGAIN)
++ goto findUniqueRetry;
++
++ return rc;
++}
++
++int
++CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
++ const char *searchName, FILE_DIRECTORY_INFO * findData,
++ T2_FFIRST_RSP_PARMS * findParms,
++ const struct nls_table *nls_codepage, int *pUnicodeFlag,
++ int *pUnixFlag)
++{
++/* level 257 SMB_ */
++ TRANSACTION2_FFIRST_REQ *pSMB = NULL;
++ TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
++ char *response_data;
++ int rc = 0;
++ int bytes_returned;
++ int name_len;
++
++ cFYI(1, ("In FindFirst"));
++findFirstRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len =
++ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(searchName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->FileName, searchName, name_len);
++ }
++
++ pSMB->TotalParameterCount = 12 + name_len /* includes null */ ;
++ pSMB->TotalDataCount = 0; /* no EAs */
++ pSMB->MaxParameterCount = cpu_to_le16(10);
++ pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
++ MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
++ pSMB->ParameterCount = pSMB->TotalParameterCount;
++ pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
++ smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
++ pSMB->DataCount = 0;
++ pSMB->DataOffset = 0;
++ pSMB->SetupCount = 1; /* one byte no need to make endian neutral */
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
++ pSMB->SearchAttributes =
++ cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
++ ATTR_DIRECTORY);
++ pSMB->SearchCount = cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO)); /* should this be shrunk even more ? */
++ pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
++
++ /* test for Unix extensions */
++ if (tcon->ses->capabilities & CAP_UNIX) {
++ pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
++ *pUnixFlag = TRUE;
++ } else {
++ pSMB->InformationLevel =
++ cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
++ *pUnixFlag = FALSE;
++ }
++ pSMB->SearchStorageType = 0; /* BB what should we set this to? It is not clear if it matters BB */
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++
++ if (rc) { /* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
++ cFYI(1, ("Error in FindFirst = %d", rc));
++ } else { /* decode response */
++ /* BB add safety checks for these memcpys */
++ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
++ *pUnicodeFlag = TRUE;
++ else
++ *pUnicodeFlag = FALSE;
++ memcpy(findParms,
++ (char *) &pSMBr->hdr.Protocol +
++ le16_to_cpu(pSMBr->ParameterOffset),
++ sizeof (T2_FFIRST_RSP_PARMS));
++ /* search handle can stay LE and EAoffset not needed so not converted */
++ findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch);
++ findParms->LastNameOffset =
++ le16_to_cpu(findParms->LastNameOffset);
++ findParms->SearchCount = le16_to_cpu(findParms->SearchCount);
++ response_data =
++ (char *) &pSMBr->hdr.Protocol +
++ le16_to_cpu(pSMBr->DataOffset);
++ memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount));
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ if (rc == -EAGAIN)
++ goto findFirstRetry;
++
++ return rc;
++}
++
++int
++CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
++ FILE_DIRECTORY_INFO * findData, T2_FNEXT_RSP_PARMS * findParms,
++ const __u16 searchHandle, char * resume_file_name, int name_len,
++ __u32 resume_key, int *pUnicodeFlag, int *pUnixFlag)
++{
++/* level 257 SMB_ */
++ TRANSACTION2_FNEXT_REQ *pSMB = NULL;
++ TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
++ char *response_data;
++ int rc = 0;
++ int bytes_returned;
++
++ cFYI(1, ("In FindNext"));
++
++ if(resume_file_name == NULL) {
++ return -EIO;
++ }
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ pSMB->TotalParameterCount = 14; /* includes 2 bytes of null string, converted to LE below */
++ pSMB->TotalDataCount = 0; /* no EAs */
++ pSMB->MaxParameterCount = cpu_to_le16(8);
++ pSMB->MaxDataCount =
++ cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ParameterOffset = cpu_to_le16(offsetof(
++ struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
++ pSMB->DataCount = 0;
++ pSMB->DataOffset = 0;
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
++ pSMB->SearchHandle = searchHandle; /* always kept as le */
++ findParms->SearchCount = 0; /* set to zero in case of error */
++ pSMB->SearchCount =
++ cpu_to_le16(CIFS_MAX_MSGSIZE / sizeof (FILE_DIRECTORY_INFO));
++ /* test for Unix extensions */
++ if (tcon->ses->capabilities & CAP_UNIX) {
++ pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
++ *pUnixFlag = TRUE;
++ } else {
++ pSMB->InformationLevel =
++ cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
++ *pUnixFlag = FALSE;
++ }
++ pSMB->ResumeKey = resume_key;
++ pSMB->SearchFlags =
++ cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
++ /* BB add check to make sure we do not cross end of smb */
++ if(name_len < CIFS_MAX_MSGSIZE) {
++ memcpy(pSMB->ResumeFileName, resume_file_name, name_len);
++ pSMB->ByteCount += name_len;
++ }
++ pSMB->TotalParameterCount += name_len;
++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
++ pSMB->ParameterCount = pSMB->TotalParameterCount;
++ /* BB improve error handling here */
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++
++ if (rc) {
++ if (rc == -EBADF)
++ rc = 0; /* search probably was closed at end of search above */
++ else
++ cFYI(1, ("FindNext returned = %d", rc));
++ } else { /* decode response */
++ /* BB add safety checks for these memcpys */
++ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
++ *pUnicodeFlag = TRUE;
++ else
++ *pUnicodeFlag = FALSE;
++ memcpy(findParms,
++ (char *) &pSMBr->hdr.Protocol +
++ le16_to_cpu(pSMBr->ParameterOffset),
++ sizeof (T2_FNEXT_RSP_PARMS));
++ findParms->EndofSearch = le16_to_cpu(findParms->EndofSearch);
++ findParms->LastNameOffset =
++ le16_to_cpu(findParms->LastNameOffset);
++ findParms->SearchCount = le16_to_cpu(findParms->SearchCount);
++ response_data =
++ (char *) &pSMBr->hdr.Protocol +
++ le16_to_cpu(pSMBr->DataOffset);
++ memcpy(findData, response_data, le16_to_cpu(pSMBr->DataCount));
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ /* Note: On -EAGAIN error only caller can retry on handle based calls
++ since file handle passed in no longer valid */
++
++ return rc;
++}
++
++int
++CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
++{
++ int rc = 0;
++ FINDCLOSE_REQ *pSMB = NULL;
++ CLOSE_RSP *pSMBr = NULL;
++ int bytes_returned;
++
++ cFYI(1, ("In CIFSSMBFindClose"));
++ rc = smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ /* no sense returning error if session restarted
++ file handle has been closed */
++ if(rc == -EAGAIN)
++ return 0;
++ if (rc)
++ return rc;
++
++ pSMB->FileID = searchHandle;
++ pSMB->ByteCount = 0;
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cERROR(1, ("Send error in FindClose = %d", rc));
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ /* Since session is dead, search handle closed on server already */
++ if (rc == -EAGAIN)
++ rc = 0;
++
++ return rc;
++}
++
++int
++CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
++ const unsigned char *searchName,
++ unsigned char **targetUNCs,
++ unsigned int *number_of_UNC_in_array,
++ const struct nls_table *nls_codepage)
++{
++/* TRANS2_GET_DFS_REFERRAL */
++ TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
++ TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
++ struct dfs_referral_level_3 * referrals = NULL;
++ int rc = 0;
++ int bytes_returned;
++ int name_len;
++ unsigned int i;
++ char * temp;
++ *number_of_UNC_in_array = 0;
++ *targetUNCs = NULL;
++
++ cFYI(1, ("In GetDFSRefer the path %s", searchName));
++ if (ses == NULL)
++ return -ENODEV;
++getDFSRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ pSMB->hdr.Tid = ses->ipc_tid;
++ pSMB->hdr.Uid = ses->Suid;
++ if (ses->capabilities & CAP_STATUS32) {
++ pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
++ }
++ if (ses->capabilities & CAP_DFS) {
++ pSMB->hdr.Flags2 |= SMBFLG2_DFS;
++ }
++
++ if (ses->capabilities & CAP_UNICODE) {
++ pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
++ name_len =
++ cifs_strtoUCS((wchar_t *) pSMB->RequestFileName,
++ searchName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(searchName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->RequestFileName, searchName, name_len);
++ }
++
++ pSMB->ParameterCount = 2 /* level */ + name_len /*includes null */ ;
++ pSMB->TotalDataCount = 0;
++ pSMB->DataCount = 0;
++ pSMB->DataOffset = 0;
++ pSMB->MaxParameterCount = 0;
++ pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ParameterOffset = cpu_to_le16(offsetof(
++ struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
++ pSMB->ByteCount = pSMB->ParameterCount + 3 /* pad */ ;
++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
++ pSMB->TotalParameterCount = pSMB->ParameterCount;
++ pSMB->MaxReferralLevel = cpu_to_le16(3);
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Send error in GetDFSRefer = %d", rc));
++ } else { /* decode response */
++/* BB Add logic to parse referrals here */
++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
++ pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
++ cFYI(1,
++ ("Decoding GetDFSRefer response. BCC: %d Offset %d",
++ pSMBr->ByteCount, pSMBr->DataOffset));
++ if ((pSMBr->ByteCount < 17) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */
++ rc = -EIO; /* bad smb */
++ else {
++ referrals =
++ (struct dfs_referral_level_3 *)
++ (8 /* sizeof start of data block */ +
++ pSMBr->DataOffset +
++ (char *) &pSMBr->hdr.Protocol);
++ cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",pSMBr->NumberOfReferrals,pSMBr->DFSFlags, referrals->ReferralSize,referrals->ServerType,referrals->ReferralFlags,referrals->TimeToLive));
++ /* BB This field is actually two bytes in from start of
++ data block so we could do safety check that DataBlock
++ begins at address of pSMBr->NumberOfReferrals */
++ *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
++
++ /* BB Fix below so can return more than one referral */
++ if(*number_of_UNC_in_array > 1)
++ *number_of_UNC_in_array = 1;
++
++ /* get the length of the strings describing refs */
++ name_len = 0;
++ for(i=0;i<*number_of_UNC_in_array;i++) {
++ /* make sure that DfsPathOffset not past end */
++ referrals->DfsPathOffset = le16_to_cpu(referrals->DfsPathOffset);
++ if(referrals->DfsPathOffset > pSMBr->DataCount) {
++ /* if invalid referral, stop here and do
++ not try to copy any more */
++ *number_of_UNC_in_array = i;
++ break;
++ }
++ temp = ((char *)referrals) + referrals->DfsPathOffset;
++
++ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len += UniStrnlen((wchar_t *)temp,pSMBr->DataCount);
++ } else {
++ name_len += strnlen(temp,pSMBr->DataCount);
++ }
++ referrals++;
++ /* BB add check that referral pointer does not fall off end PDU */
++
++ }
++ /* BB add check for name_len bigger than bcc */
++ *targetUNCs =
++ kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
++ /* copy the ref strings */
++ referrals =
++ (struct dfs_referral_level_3 *)
++ (8 /* sizeof data hdr */ +
++ pSMBr->DataOffset +
++ (char *) &pSMBr->hdr.Protocol);
++
++ for(i=0;i<*number_of_UNC_in_array;i++) {
++ temp = ((char *)referrals) + referrals->DfsPathOffset;
++ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
++ cifs_strfromUCS_le(*targetUNCs,
++ (wchar_t *) temp, name_len, nls_codepage);
++ } else {
++ strncpy(*targetUNCs,temp,name_len);
++ }
++ /* BB update target_uncs pointers */
++ referrals++;
++ }
++ temp = *targetUNCs;
++ temp[name_len] = 0;
++ }
++
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ if (rc == -EAGAIN)
++ goto getDFSRetry;
++
++ return rc;
++}
++
++int
++CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
++ struct statfs *FSData, const struct nls_table *nls_codepage)
++{
++/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
++ TRANSACTION2_QFSI_REQ *pSMB = NULL;
++ TRANSACTION2_QFSI_RSP *pSMBr = NULL;
++ FILE_SYSTEM_INFO *response_data;
++ int rc = 0;
++ int bytes_returned = 0;
++
++ cFYI(1, ("In QFSInfo"));
++QFSInfoRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ pSMB->TotalParameterCount = 2; /* level */
++ pSMB->TotalDataCount = 0;
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
++ pSMB->ParameterCount = pSMB->TotalParameterCount;
++ pSMB->ParameterOffset = cpu_to_le16(offsetof(
++ struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
++ pSMB->DataCount = 0;
++ pSMB->DataOffset = 0;
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cERROR(1, ("Send error in QFSInfo = %d", rc));
++ } else { /* decode response */
++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
++ cFYI(1,
++ ("Decoding qfsinfo response. BCC: %d Offset %d",
++ pSMBr->ByteCount, pSMBr->DataOffset));
++ if ((pSMBr->ByteCount < 24) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */
++ rc = -EIO; /* bad smb */
++ else {
++ response_data =
++ (FILE_SYSTEM_INFO
++ *) (((char *) &pSMBr->hdr.Protocol) +
++ pSMBr->DataOffset);
++ FSData->f_bsize =
++ le32_to_cpu(response_data->BytesPerSector) *
++ le32_to_cpu(response_data->
++ SectorsPerAllocationUnit);
++ FSData->f_blocks =
++ le64_to_cpu(response_data->TotalAllocationUnits);
++ FSData->f_bfree = FSData->f_bavail =
++ le64_to_cpu(response_data->FreeAllocationUnits);
++ cFYI(1,
++ ("Blocks: %lld Free: %lld Block size %ld",
++ (unsigned long long)FSData->f_blocks,
++ (unsigned long long)FSData->f_bfree,
++ FSData->f_bsize));
++ }
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ if (rc == -EAGAIN)
++ goto QFSInfoRetry;
++
++ return rc;
++}
++
++int
++CIFSSMBQFSAttributeInfo(int xid, struct cifsTconInfo *tcon,
++ const struct nls_table *nls_codepage)
++{
++/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
++ TRANSACTION2_QFSI_REQ *pSMB = NULL;
++ TRANSACTION2_QFSI_RSP *pSMBr = NULL;
++ FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
++ int rc = 0;
++ int bytes_returned = 0;
++
++ cFYI(1, ("In QFSAttributeInfo"));
++QFSAttributeRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ pSMB->TotalParameterCount = 2; /* level */
++ pSMB->TotalDataCount = 0;
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
++ pSMB->ParameterCount = pSMB->TotalParameterCount;
++ pSMB->ParameterOffset = cpu_to_le16(offsetof(
++ struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
++ pSMB->DataCount = 0;
++ pSMB->DataOffset = 0;
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
++ } else { /* decode response */
++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
++ if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) { /* BB also check enough bytes returned */
++ rc = -EIO; /* bad smb */
++ } else {
++ response_data =
++ (FILE_SYSTEM_ATTRIBUTE_INFO
++ *) (((char *) &pSMBr->hdr.Protocol) +
++ pSMBr->DataOffset);
++ response_data->Attributes = le32_to_cpu(response_data->Attributes);
++ response_data->MaxPathNameComponentLength =
++ le32_to_cpu(response_data->MaxPathNameComponentLength);
++ response_data->FileSystemNameLen =
++ le32_to_cpu(response_data->FileSystemNameLen);
++ memcpy(&tcon->fsAttrInfo, response_data,
++ sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
++ }
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ if (rc == -EAGAIN)
++ goto QFSAttributeRetry;
++
++ return rc;
++}
++
++int
++CIFSSMBQFSDeviceInfo(int xid, struct cifsTconInfo *tcon,
++ const struct nls_table *nls_codepage)
++{
++/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
++ TRANSACTION2_QFSI_REQ *pSMB = NULL;
++ TRANSACTION2_QFSI_RSP *pSMBr = NULL;
++ FILE_SYSTEM_DEVICE_INFO *response_data;
++ int rc = 0;
++ int bytes_returned = 0;
++
++ cFYI(1, ("In QFSDeviceInfo"));
++QFSDeviceRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ pSMB->TotalParameterCount = 2; /* level */
++ pSMB->TotalDataCount = 0;
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
++ pSMB->ParameterCount = pSMB->TotalParameterCount;
++ pSMB->ParameterOffset = cpu_to_le16(offsetof(
++ struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
++
++ pSMB->DataCount = 0;
++ pSMB->DataOffset = 0;
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
++ } else { /* decode response */
++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
++ if ((pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO))
++ || (pSMBr->DataOffset > 512))
++ rc = -EIO; /* bad smb */
++ else {
++ response_data =
++ (FILE_SYSTEM_DEVICE_INFO
++ *) (((char *) &pSMBr->hdr.Protocol) +
++ pSMBr->DataOffset);
++ response_data->DeviceType =
++ le32_to_cpu(response_data->DeviceType);
++ response_data->DeviceCharacteristics =
++ le32_to_cpu(response_data->DeviceCharacteristics);
++ memcpy(&tcon->fsDevInfo, response_data,
++ sizeof (FILE_SYSTEM_DEVICE_INFO));
++ }
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ if (rc == -EAGAIN)
++ goto QFSDeviceRetry;
++
++ return rc;
++}
++
++int
++CIFSSMBQFSUnixInfo(int xid, struct cifsTconInfo *tcon,
++ const struct nls_table *nls_codepage)
++{
++/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
++ TRANSACTION2_QFSI_REQ *pSMB = NULL;
++ TRANSACTION2_QFSI_RSP *pSMBr = NULL;
++ FILE_SYSTEM_UNIX_INFO *response_data;
++ int rc = 0;
++ int bytes_returned = 0;
++
++ cFYI(1, ("In QFSUnixInfo"));
++QFSUnixRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ pSMB->ParameterCount = 2; /* level */
++ pSMB->TotalDataCount = 0;
++ pSMB->DataCount = 0;
++ pSMB->DataOffset = 0;
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ByteCount = pSMB->ParameterCount + 1 /* pad */ ;
++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
++ pSMB->TotalParameterCount = pSMB->ParameterCount;
++ pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
++ smb_com_transaction2_qfsi_req, InformationLevel) - 4);
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
++ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
++ } else { /* decode response */
++ pSMBr->DataOffset = cpu_to_le16(pSMBr->DataOffset);
++ if ((pSMBr->ByteCount < 13) || (pSMBr->DataOffset > 512)) {
++ rc = -EIO; /* bad smb */
++ } else {
++ response_data =
++ (FILE_SYSTEM_UNIX_INFO
++ *) (((char *) &pSMBr->hdr.Protocol) +
++ pSMBr->DataOffset);
++ response_data->MajorVersionNumber =
++ le16_to_cpu(response_data->MajorVersionNumber);
++ response_data->MinorVersionNumber =
++ le16_to_cpu(response_data->MinorVersionNumber);
++ response_data->Capability =
++ le64_to_cpu(response_data->Capability);
++ memcpy(&tcon->fsUnixInfo, response_data,
++ sizeof (FILE_SYSTEM_UNIX_INFO));
++ }
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ if (rc == -EAGAIN)
++ goto QFSUnixRetry;
++
++
++ return rc;
++}
++
++/* We can not use write of zero bytes trick to
++ set file size due to need for large file support. Also note that
++ this SetPathInfo is preferred to SetFileInfo based method in next
++ routine which is only needed to work around a sharing violation bug
++ in Samba which this routine can run into */
++
++int
++CIFSSMBSetEOF(int xid, struct cifsTconInfo *tcon, char *fileName,
++ __u64 size, int SetAllocation, const struct nls_table *nls_codepage)
++{
++ struct smb_com_transaction2_spi_req *pSMB = NULL;
++ struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
++ struct file_end_of_file_info *parm_data;
++ int name_len;
++ int rc = 0;
++ int bytes_returned = 0;
++
++ cFYI(1, ("In SetEOF"));
++SetEOFRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len =
++ cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(fileName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->FileName, fileName, name_len);
++ }
++ pSMB->ParameterCount = 6 + name_len;
++ pSMB->DataCount = sizeof (struct file_end_of_file_info);
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
++ InformationLevel) - 4;
++ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
++ if(SetAllocation) {
++ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
++ pSMB->InformationLevel =
++ cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
++ else
++ pSMB->InformationLevel =
++ cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
++ } else /* Set File Size */ {
++ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
++ pSMB->InformationLevel =
++ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
++ else
++ pSMB->InformationLevel =
++ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
++ }
++
++ parm_data =
++ (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
++ pSMB->DataOffset);
++ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
++ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
++ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount;
++ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
++ pSMB->TotalDataCount = pSMB->DataCount;
++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
++ pSMB->TotalParameterCount = pSMB->ParameterCount;
++ pSMB->Reserved4 = 0;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ parm_data->FileSize = cpu_to_le64(size);
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("SetPathInfo (file size) returned %d", rc));
++ }
++
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ if (rc == -EAGAIN)
++ goto SetEOFRetry;
++
++ return rc;
++}
++
++int
++CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
++ __u16 fid, __u32 pid_of_opener, int SetAllocation)
++{
++ struct smb_com_transaction2_sfi_req *pSMB = NULL;
++ struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
++ char *data_offset;
++ struct file_end_of_file_info *parm_data;
++ int rc = 0;
++ int bytes_returned = 0;
++ __u32 tmp;
++
++ cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
++ (long long)size));
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ tmp = cpu_to_le32(pid_of_opener); /* override pid of current process
++ so network fid will be valid */
++ pSMB->hdr.Pid = tmp & 0xFFFF;
++ tmp >>= 16;
++ pSMB->hdr.PidHigh = tmp & 0xFFFF;
++
++ pSMB->ParameterCount = 6;
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_sfi_req,
++ Fid) - 4;
++ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
++
++ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
++
++ pSMB->DataCount = sizeof(struct file_end_of_file_info);
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
++ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount;
++ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
++ pSMB->TotalDataCount = pSMB->DataCount;
++ pSMB->TotalParameterCount = pSMB->ParameterCount;
++ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
++ parm_data =
++ (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
++ pSMB->DataOffset);
++ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); /* now safe to change to le */
++ parm_data->FileSize = cpu_to_le64(size);
++ pSMB->Fid = fid;
++ if(SetAllocation) {
++ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
++ pSMB->InformationLevel =
++ cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
++ else
++ pSMB->InformationLevel =
++ cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
++ } else /* Set File Size */ {
++ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
++ pSMB->InformationLevel =
++ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
++ else
++ pSMB->InformationLevel =
++ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
++ }
++ pSMB->Reserved4 = 0;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1,
++ ("Send error in SetFileInfo (SetFileSize) = %d",
++ rc));
++ }
++
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ /* Note: On -EAGAIN error only caller can retry on handle based calls
++ since file handle passed in no longer valid */
++
++ return rc;
++}
++
++int
++CIFSSMBSetTimes(int xid, struct cifsTconInfo *tcon, char *fileName,
++ FILE_BASIC_INFO * data, const struct nls_table *nls_codepage)
++{
++ TRANSACTION2_SPI_REQ *pSMB = NULL;
++ TRANSACTION2_SPI_RSP *pSMBr = NULL;
++ int name_len;
++ int rc = 0;
++ int bytes_returned = 0;
++ char *data_offset;
++
++ cFYI(1, ("In SetTimes"));
++
++SetTimesRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len =
++ cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(fileName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->FileName, fileName, name_len);
++ }
++
++ pSMB->ParameterCount = 6 + name_len;
++ pSMB->DataCount = sizeof (FILE_BASIC_INFO);
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
++ InformationLevel) - 4;
++ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
++ data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
++ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
++ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
++ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount;
++
++ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
++ pSMB->TotalDataCount = pSMB->DataCount;
++ pSMB->TotalParameterCount = pSMB->ParameterCount;
++ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
++ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
++ else
++ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
++ pSMB->Reserved4 = 0;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("SetPathInfo (times) returned %d", rc));
++ }
++
++ if (pSMB)
++ cifs_buf_release(pSMB);
++
++ if (rc == -EAGAIN)
++ goto SetTimesRetry;
++
++ return rc;
++}
++
++int
++CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
++ char *fileName, __u64 mode, __u64 uid, __u64 gid,
++ dev_t device, const struct nls_table *nls_codepage)
++{
++ TRANSACTION2_SPI_REQ *pSMB = NULL;
++ TRANSACTION2_SPI_RSP *pSMBr = NULL;
++ int name_len;
++ int rc = 0;
++ int bytes_returned = 0;
++ FILE_UNIX_BASIC_INFO *data_offset;
++
++ cFYI(1, ("In SetUID/GID/Mode"));
++setPermsRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len =
++ cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(fileName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->FileName, fileName, name_len);
++ }
++
++ pSMB->ParameterCount = 6 + name_len;
++ pSMB->DataCount = sizeof (FILE_UNIX_BASIC_INFO);
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
++ InformationLevel) - 4;
++ pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
++ data_offset =
++ (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
++ pSMB->DataOffset);
++ pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
++ pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
++ pSMB->ByteCount = 3 /* pad */ + pSMB->ParameterCount + pSMB->DataCount;
++ pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
++ pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
++ pSMB->TotalParameterCount = pSMB->ParameterCount;
++ pSMB->TotalDataCount = pSMB->DataCount;
++ pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
++ pSMB->Reserved4 = 0;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ data_offset->Uid = cpu_to_le64(uid);
++ data_offset->Gid = cpu_to_le64(gid);
++ /* better to leave device as zero when it is */
++ data_offset->DevMajor = cpu_to_le64(MAJOR(device));
++ data_offset->DevMinor = cpu_to_le64(MINOR(device));
++ data_offset->Permissions = cpu_to_le64(mode);
++
++ if(S_ISREG(mode))
++ data_offset->Type = cpu_to_le32(UNIX_FILE);
++ else if(S_ISDIR(mode))
++ data_offset->Type = cpu_to_le32(UNIX_DIR);
++ else if(S_ISLNK(mode))
++ data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
++ else if(S_ISCHR(mode))
++ data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
++ else if(S_ISBLK(mode))
++ data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
++ else if(S_ISFIFO(mode))
++ data_offset->Type = cpu_to_le32(UNIX_FIFO);
++ else if(S_ISSOCK(mode))
++ data_offset->Type = cpu_to_le32(UNIX_SOCKET);
++
++
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("SetPathInfo (perms) returned %d", rc));
++ }
++
++ if (pSMB)
++ cifs_buf_release(pSMB);
++ if (rc == -EAGAIN)
++ goto setPermsRetry;
++ return rc;
++}
++
++int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
++ const int notify_subdirs, const __u16 netfid,
++ __u32 filter, const struct nls_table *nls_codepage)
++{
++ int rc = 0;
++ struct smb_com_transaction_change_notify_req * pSMB = NULL;
++ struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
++ int bytes_returned;
++
++ cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
++ rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ pSMB->TotalParameterCount = 0 ;
++ pSMB->TotalDataCount = 0;
++ pSMB->MaxParameterCount = cpu_to_le32(2);
++ /* BB find exact data count max from sess structure BB */
++ pSMB->MaxDataCount = 0; /* same in little endian or be */
++ pSMB->MaxSetupCount = 4;
++ pSMB->Reserved = 0;
++ pSMB->ParameterOffset = 0;
++ pSMB->DataCount = 0;
++ pSMB->DataOffset = 0;
++ pSMB->SetupCount = 4; /* single byte does not need le conversion */
++ pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
++ pSMB->ParameterCount = pSMB->TotalParameterCount;
++ if(notify_subdirs)
++ pSMB->WatchTree = 1; /* one byte - no le conversion needed */
++ pSMB->Reserved2 = 0;
++ pSMB->CompletionFilter = cpu_to_le32(filter);
++ pSMB->Fid = netfid; /* file handle always le */
++ pSMB->ByteCount = 0;
++
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Error in Notify = %d", rc));
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++/* if (rc == -EAGAIN)
++ goto NotifyRetry; */
++ return rc;
++}
++#ifdef CONFIG_CIFS_XATTR
++int
++CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
++ const unsigned char *searchName,
++ char * EAData, size_t size,
++ const struct nls_table *nls_codepage)
++{
++ /* BB assumes one setup word */
++ TRANSACTION2_QPI_REQ *pSMB = NULL;
++ TRANSACTION2_QPI_RSP *pSMBr = NULL;
++ int rc = 0;
++ int bytes_returned;
++ int name_len;
++
++ cFYI(1, ("In Query All EAs path %s", searchName));
++QAllEAsRetry:
++ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
++ (void **) &pSMBr);
++ if (rc)
++ return rc;
++
++ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
++ name_len =
++ cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
++ /* find define for this maxpathcomponent */
++ , nls_codepage);
++ name_len++; /* trailing null */
++ name_len *= 2;
++ } else { /* BB improve the check for buffer overruns BB */
++ name_len = strnlen(searchName, 530);
++ name_len++; /* trailing null */
++ strncpy(pSMB->FileName, searchName, name_len);
++ }
++
++ pSMB->TotalParameterCount = 2 /* level */ + 4 /* reserved */ +
++ name_len /* includes null */ ;
++ pSMB->TotalDataCount = 0;
++ pSMB->MaxParameterCount = cpu_to_le16(2);
++ pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
++ pSMB->MaxSetupCount = 0;
++ pSMB->Reserved = 0;
++ pSMB->Flags = 0;
++ pSMB->Timeout = 0;
++ pSMB->Reserved2 = 0;
++ pSMB->ParameterOffset = cpu_to_le16(offsetof(
++ struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
++ pSMB->DataCount = 0;
++ pSMB->DataOffset = 0;
++ pSMB->SetupCount = 1;
++ pSMB->Reserved3 = 0;
++ pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
++ pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
++ pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
++ pSMB->ParameterCount = pSMB->TotalParameterCount;
++ pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
++ pSMB->Reserved4 = 0;
++ pSMB->hdr.smb_buf_length += pSMB->ByteCount;
++ pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
++
++ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
++ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
++ if (rc) {
++ cFYI(1, ("Send error in QueryAllEAs = %d", rc));
++ } else { /* decode response */
++ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
++ /* BB also check enough total bytes returned */
++ /* BB we need to improve the validity checking
++ of these trans2 responses */
++ if ((pSMBr->ByteCount < 4) || (pSMBr->DataOffset > 512))
++ rc = -EIO; /* bad smb */
++ /* else if (pFindData){
++ memcpy((char *) pFindData,
++ (char *) &pSMBr->hdr.Protocol +
++ pSMBr->DataOffset, kl);
++ }*/ else {
++ /* check that length of list is not more than bcc */
++ /* check that each entry does not go beyond length
++ of list */
++ /* check that each element of each entry does not
++ go beyond end of list */
++ struct fealist * ea_response_data;
++ rc = 0;
++ /* validate_trans2_offsets() */
++ /* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/
++ ea_response_data = (struct fealist *)
++ (((char *) &pSMBr->hdr.Protocol) +
++ pSMBr->DataOffset);
++ cFYI(1,("ea length %d",ea_response_data->list_len));
++ }
++ }
++ if (pSMB)
++ cifs_buf_release(pSMB);
++ if (rc == -EAGAIN)
++ goto QAllEAsRetry;
++
++ return rc;
++}
++#endif
+diff -urN linux-2.4.29.old/fs/cifs/cifs_unicode.c linux-2.4.29/fs/cifs/cifs_unicode.c
+--- linux-2.4.29.old/fs/cifs/cifs_unicode.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/cifs_unicode.c 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,87 @@
++/*
++ * fs/cifs/cifs_unicode.c
++ *
++ * Copyright (c) International Business Machines Corp., 2000,2002
++ * Modified by Steve French (sfrench@us.ibm.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
++ * the GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#include <linux/fs.h>
++#include "cifs_unicode.h"
++#include "cifs_uniupr.h"
++#include "cifspdu.h"
++#include "cifs_debug.h"
++
++/*
++ * NAME: cifs_strfromUCS()
++ *
++ * FUNCTION: Convert little-endian unicode string to character string
++ *
++ */
++int
++cifs_strfromUCS_le(char *to, const wchar_t * from, /* LITTLE ENDIAN */
++ int len, const struct nls_table *codepage)
++{
++ int i;
++ int outlen = 0;
++
++ for (i = 0; (i < len) && from[i]; i++) {
++ int charlen;
++ /* 2.4.0 kernel or greater */
++ charlen =
++ codepage->uni2char(le16_to_cpu(from[i]), &to[outlen],
++ NLS_MAX_CHARSET_SIZE);
++ if (charlen > 0) {
++ outlen += charlen;
++ } else {
++ to[outlen++] = '?';
++ }
++ }
++ to[outlen] = 0;
++ return outlen;
++}
++
++/*
++ * NAME: cifs_strtoUCS()
++ *
++ * FUNCTION: Convert character string to unicode string
++ *
++ */
++int
++cifs_strtoUCS(wchar_t * to, const char *from, int len,
++ const struct nls_table *codepage)
++{
++ int charlen;
++ int i;
++
++ for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
++
++ /* works for 2.4.0 kernel or later */
++ charlen = codepage->char2uni(from, len, &to[i]);
++ if (charlen < 1) {
++ cERROR(1,
++ ("cifs_strtoUCS: char2uni returned %d",
++ charlen));
++ to[i] = cpu_to_le16(0x003f); /* a question mark */
++ charlen = 1;
++ }
++ to[i] = cpu_to_le16(to[i]);
++
++ }
++
++ to[i] = 0;
++ return i;
++}
++
+diff -urN linux-2.4.29.old/fs/cifs/cifs_unicode.h linux-2.4.29/fs/cifs/cifs_unicode.h
+--- linux-2.4.29.old/fs/cifs/cifs_unicode.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/cifs_unicode.h 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,353 @@
++/*
++ * cifs_unicode: Unicode kernel case support
++ *
++ * Function:
++ * Convert a unicode character to upper or lower case using
++ * compressed tables.
++ *
++ * Copyright (c) International Business Machines Corp., 2000,2002
++ *
++ * 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
++ *
++ *
++ * Notes:
++ * These APIs are based on the C library functions. The semantics
++ * should match the C functions but with expanded size operands.
++ *
++ * The upper/lower functions are based on a table created by mkupr.
++ * This is a compressed table of upper and lower case conversion.
++ *
++ */
++
++#include <asm/byteorder.h>
++#include <linux/types.h>
++#include <linux/nls.h>
++
++#define UNIUPR_NOLOWER /* Example to not expand lower case tables */
++
++/* Just define what we want from uniupr.h. We don't want to define the tables
++ * in each source file.
++ */
++#ifndef UNICASERANGE_DEFINED
++struct UniCaseRange {
++ wchar_t start;
++ wchar_t end;
++ signed char *table;
++};
++#endif /* UNICASERANGE_DEFINED */
++
++#ifndef UNIUPR_NOUPPER
++extern signed char CifsUniUpperTable[512];
++extern const struct UniCaseRange CifsUniUpperRange[];
++#endif /* UNIUPR_NOUPPER */
++
++#ifndef UNIUPR_NOLOWER
++extern signed char UniLowerTable[512];
++extern struct UniCaseRange UniLowerRange[];
++#endif /* UNIUPR_NOLOWER */
++
++#ifdef __KERNEL__
++int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *);
++int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *);
++#endif
++
++/*
++ * UniStrcat: Concatenate the second string to the first
++ *
++ * Returns:
++ * Address of the first string
++ */
++static inline wchar_t *
++UniStrcat(wchar_t * ucs1, const wchar_t * ucs2)
++{
++ wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */
++
++ while (*ucs1++) ; /* To end of first string */
++ ucs1--; /* Return to the null */
++ while ((*ucs1++ = *ucs2++)) ; /* copy string 2 over */
++ return anchor;
++}
++
++/*
++ * UniStrchr: Find a character in a string
++ *
++ * Returns:
++ * Address of first occurrence of character in string
++ * or NULL if the character is not in the string
++ */
++static inline wchar_t *
++UniStrchr(const wchar_t * ucs, wchar_t uc)
++{
++ while ((*ucs != uc) && *ucs)
++ ucs++;
++
++ if (*ucs == uc)
++ return (wchar_t *) ucs;
++ return NULL;
++}
++
++/*
++ * UniStrcmp: Compare two strings
++ *
++ * Returns:
++ * < 0: First string is less than second
++ * = 0: Strings are equal
++ * > 0: First string is greater than second
++ */
++static inline int
++UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2)
++{
++ while ((*ucs1 == *ucs2) && *ucs1) {
++ ucs1++;
++ ucs2++;
++ }
++ return (int) *ucs1 - (int) *ucs2;
++}
++
++/*
++ * UniStrcpy: Copy a string
++ */
++static inline wchar_t *
++UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2)
++{
++ wchar_t *anchor = ucs1; /* save the start of result string */
++
++ while ((*ucs1++ = *ucs2++)) ;
++ return anchor;
++}
++
++/*
++ * UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes)
++ */
++static inline size_t
++UniStrlen(const wchar_t * ucs1)
++{
++ int i = 0;
++
++ while (*ucs1++)
++ i++;
++ return i;
++}
++
++/*
++ * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a string (length limited)
++ */
++static inline size_t
++UniStrnlen(const wchar_t * ucs1, int maxlen)
++{
++ int i = 0;
++
++ while (*ucs1++) {
++ i++;
++ if (i >= maxlen)
++ break;
++ }
++ return i;
++}
++
++/*
++ * UniStrncat: Concatenate length limited string
++ */
++static inline wchar_t *
++UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
++{
++ wchar_t *anchor = ucs1; /* save pointer to string 1 */
++
++ while (*ucs1++) ;
++ ucs1--; /* point to null terminator of s1 */
++ while (n-- && (*ucs1 = *ucs2)) { /* copy s2 after s1 */
++ ucs1++;
++ ucs2++;
++ }
++ *ucs1 = 0; /* Null terminate the result */
++ return (anchor);
++}
++
++/*
++ * UniStrncmp: Compare length limited string
++ */
++static inline int
++UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
++{
++ if (!n)
++ return 0; /* Null strings are equal */
++ while ((*ucs1 == *ucs2) && *ucs1 && --n) {
++ ucs1++;
++ ucs2++;
++ }
++ return (int) *ucs1 - (int) *ucs2;
++}
++
++/*
++ * UniStrncmp_le: Compare length limited string - native to little-endian
++ */
++static inline int
++UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
++{
++ if (!n)
++ return 0; /* Null strings are equal */
++ while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
++ ucs1++;
++ ucs2++;
++ }
++ return (int) *ucs1 - (int) __le16_to_cpu(*ucs2);
++}
++
++/*
++ * UniStrncpy: Copy length limited string with pad
++ */
++static inline wchar_t *
++UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
++{
++ wchar_t *anchor = ucs1;
++
++ while (n-- && *ucs2) /* Copy the strings */
++ *ucs1++ = *ucs2++;
++
++ n++;
++ while (n--) /* Pad with nulls */
++ *ucs1++ = 0;
++ return anchor;
++}
++
++/*
++ * UniStrncpy_le: Copy length limited string with pad to little-endian
++ */
++static inline wchar_t *
++UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
++{
++ wchar_t *anchor = ucs1;
++
++ while (n-- && *ucs2) /* Copy the strings */
++ *ucs1++ = __le16_to_cpu(*ucs2++);
++
++ n++;
++ while (n--) /* Pad with nulls */
++ *ucs1++ = 0;
++ return anchor;
++}
++
++/*
++ * UniStrstr: Find a string in a string
++ *
++ * Returns:
++ * Address of first match found
++ * NULL if no matching string is found
++ */
++static inline wchar_t *
++UniStrstr(const wchar_t * ucs1, const wchar_t * ucs2)
++{
++ const wchar_t *anchor1 = ucs1;
++ const wchar_t *anchor2 = ucs2;
++
++ while (*ucs1) {
++ if (*ucs1 == *ucs2) { /* Partial match found */
++ ucs1++;
++ ucs2++;
++ } else {
++ if (!*ucs2) /* Match found */
++ return (wchar_t *) anchor1;
++ ucs1 = ++anchor1; /* No match */
++ ucs2 = anchor2;
++ }
++ }
++
++ if (!*ucs2) /* Both end together */
++ return (wchar_t *) anchor1; /* Match found */
++ return NULL; /* No match */
++}
++
++#ifndef UNIUPR_NOUPPER
++/*
++ * UniToupper: Convert a unicode character to upper case
++ */
++static inline wchar_t
++UniToupper(register wchar_t uc)
++{
++ register const struct UniCaseRange *rp;
++
++ if (uc < sizeof (CifsUniUpperTable)) { /* Latin characters */
++ return uc + CifsUniUpperTable[uc]; /* Use base tables */
++ } else {
++ rp = CifsUniUpperRange; /* Use range tables */
++ while (rp->start) {
++ if (uc < rp->start) /* Before start of range */
++ return uc; /* Uppercase = input */
++ if (uc <= rp->end) /* In range */
++ return uc + rp->table[uc - rp->start];
++ rp++; /* Try next range */
++ }
++ }
++ return uc; /* Past last range */
++}
++
++/*
++ * UniStrupr: Upper case a unicode string
++ */
++static inline wchar_t *
++UniStrupr(register wchar_t * upin)
++{
++ register wchar_t *up;
++
++ up = upin;
++ while (*up) { /* For all characters */
++ *up = UniToupper(*up);
++ up++;
++ }
++ return upin; /* Return input pointer */
++}
++#endif /* UNIUPR_NOUPPER */
++
++#ifndef UNIUPR_NOLOWER
++/*
++ * UniTolower: Convert a unicode character to lower case
++ */
++static inline wchar_t
++UniTolower(wchar_t uc)
++{
++ register struct UniCaseRange *rp;
++
++ if (uc < sizeof (UniLowerTable)) { /* Latin characters */
++ return uc + UniLowerTable[uc]; /* Use base tables */
++ } else {
++ rp = UniLowerRange; /* Use range tables */
++ while (rp->start) {
++ if (uc < rp->start) /* Before start of range */
++ return uc; /* Uppercase = input */
++ if (uc <= rp->end) /* In range */
++ return uc + rp->table[uc - rp->start];
++ rp++; /* Try next range */
++ }
++ }
++ return uc; /* Past last range */
++}
++
++/*
++ * UniStrlwr: Lower case a unicode string
++ */
++static inline wchar_t *
++UniStrlwr(register wchar_t * upin)
++{
++ register wchar_t *up;
++
++ up = upin;
++ while (*up) { /* For all characters */
++ *up = UniTolower(*up);
++ up++;
++ }
++ return upin; /* Return input pointer */
++}
++
++#endif
+diff -urN linux-2.4.29.old/fs/cifs/cifs_uniupr.h linux-2.4.29/fs/cifs/cifs_uniupr.h
+--- linux-2.4.29.old/fs/cifs/cifs_uniupr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/cifs_uniupr.h 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,253 @@
++/*
++ * Copyright (c) International Business Machines Corp., 2000,2002
++ *
++ * 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
++ *
++ * uniupr.h - Unicode compressed case ranges
++ *
++*/
++
++#ifndef UNIUPR_NOUPPER
++/*
++ * Latin upper case
++ */
++signed char CifsUniUpperTable[512] = {
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 040-04f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 050-05f */
++ 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 060-06f */
++ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, 0, 0, 0, 0, 0, /* 070-07f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0c0-0cf */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0d0-0df */
++ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 0e0-0ef */
++ -32, -32, -32, -32, -32, -32, -32, 0, -32, -32, -32, -32, -32, -32, -32, 121, /* 0f0-0ff */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 100-10f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 110-11f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 120-12f */
++ 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 130-13f */
++ -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, /* 140-14f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 150-15f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 160-16f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0, /* 170-17f */
++ 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, /* 180-18f */
++ 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, /* 190-19f */
++ 0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */
++ -1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */
++ 0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */
++ -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1, /* 1d0-1df */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */
++ 0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */
++};
++
++/* Upper case range - Greek */
++static signed char UniCaseRangeU03a0[47] = {
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -38, -37, -37, -37, /* 3a0-3af */
++ 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 3b0-3bf */
++ -32, -32, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -64,
++ -63, -63,
++};
++
++/* Upper case range - Cyrillic */
++static signed char UniCaseRangeU0430[48] = {
++ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 430-43f */
++ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* 440-44f */
++ 0, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, 0, -80, -80, /* 450-45f */
++};
++
++/* Upper case range - Extended cyrillic */
++static signed char UniCaseRangeU0490[61] = {
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 490-49f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4a0-4af */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 4b0-4bf */
++ 0, 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1,
++};
++
++/* Upper case range - Extended latin and greek */
++static signed char UniCaseRangeU1e00[509] = {
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e00-1e0f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e10-1e1f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e20-1e2f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e30-1e3f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e40-1e4f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e50-1e5f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e60-1e6f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e70-1e7f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e80-1e8f */
++ 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, -59, 0, -1, 0, -1, /* 1e90-1e9f */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ea0-1eaf */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1eb0-1ebf */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ec0-1ecf */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ed0-1edf */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1ee0-1eef */
++ 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
++ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f00-1f0f */
++ 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f10-1f1f */
++ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f20-1f2f */
++ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f30-1f3f */
++ 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f40-1f4f */
++ 0, 8, 0, 8, 0, 8, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f50-1f5f */
++ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f60-1f6f */
++ 74, 74, 86, 86, 86, 86, 100, 100, 0, 0, 112, 112, 126, 126, 0, 0, /* 1f70-1f7f */
++ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f80-1f8f */
++ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f90-1f9f */
++ 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fa0-1faf */
++ 8, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fb0-1fbf */
++ 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fc0-1fcf */
++ 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fd0-1fdf */
++ 8, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1fe0-1fef */
++ 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++};
++
++/* Upper case range - Wide latin */
++static signed char UniCaseRangeUff40[27] = {
++ 0, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, /* ff40-ff4f */
++ -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32,
++};
++
++/*
++ * Upper Case Range
++ */
++const struct UniCaseRange CifsUniUpperRange[] = {
++ {0x03a0, 0x03ce, UniCaseRangeU03a0},
++ {0x0430, 0x045f, UniCaseRangeU0430},
++ {0x0490, 0x04cc, UniCaseRangeU0490},
++ {0x1e00, 0x1ffc, UniCaseRangeU1e00},
++ {0xff40, 0xff5a, UniCaseRangeUff40},
++ {0, 0, NULL}
++};
++#endif
++
++#ifndef UNIUPR_NOLOWER
++/*
++ * Latin lower case
++ */
++static signed char CifsUniLowerTable[512] = {
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 030-03f */
++ 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 040-04f */
++ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, /* 050-05f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 060-06f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 070-07f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 080-08f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 090-09f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0a0-0af */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0b0-0bf */
++ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 0c0-0cf */
++ 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 0, /* 0d0-0df */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0e0-0ef */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0f0-0ff */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 100-10f */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 110-11f */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 120-12f */
++ 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, /* 130-13f */
++ 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, /* 140-14f */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 150-15f */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 160-16f */
++ 1, 0, 1, 0, 1, 0, 1, 0, -121, 1, 0, 1, 0, 1, 0, 0, /* 170-17f */
++ 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 79, 0, /* 180-18f */
++ 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 190-19f */
++ 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, /* 1a0-1af */
++ 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, /* 1b0-1bf */
++ 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0, 1, 0, 1, /* 1c0-1cf */
++ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, /* 1d0-1df */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e0-1ef */
++ 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1f0-1ff */
++};
++
++/* Lower case range - Greek */
++static signed char UniCaseRangeL0380[44] = {
++ 0, 0, 0, 0, 0, 0, 38, 0, 37, 37, 37, 0, 64, 0, 63, 63, /* 380-38f */
++ 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 390-39f */
++ 32, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32,
++};
++
++/* Lower case range - Cyrillic */
++static signed char UniCaseRangeL0400[48] = {
++ 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 80, 80, /* 400-40f */
++ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 410-41f */
++ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* 420-42f */
++};
++
++/* Lower case range - Extended cyrillic */
++static signed char UniCaseRangeL0490[60] = {
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 490-49f */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4a0-4af */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 4b0-4bf */
++ 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
++};
++
++/* Lower case range - Extended latin and greek */
++static signed char UniCaseRangeL1e00[504] = {
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e00-1e0f */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e10-1e1f */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e20-1e2f */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e30-1e3f */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e40-1e4f */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e50-1e5f */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e60-1e6f */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e70-1e7f */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1e80-1e8f */
++ 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 1e90-1e9f */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ea0-1eaf */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1eb0-1ebf */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ec0-1ecf */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ed0-1edf */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, /* 1ee0-1eef */
++ 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, /* 1ef0-1eff */
++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f00-1f0f */
++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f10-1f1f */
++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f20-1f2f */
++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f30-1f3f */
++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, 0, 0, /* 1f40-1f4f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, -8, 0, -8, 0, -8, 0, -8, /* 1f50-1f5f */
++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f60-1f6f */
++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1f70-1f7f */
++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f80-1f8f */
++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1f90-1f9f */
++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -8, -8, -8, -8, -8, -8, /* 1fa0-1faf */
++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -74, -74, -9, 0, 0, 0, /* 1fb0-1fbf */
++ 0, 0, 0, 0, 0, 0, 0, 0, -86, -86, -86, -86, -9, 0, 0, 0, /* 1fc0-1fcf */
++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -100, -100, 0, 0, 0, 0, /* 1fd0-1fdf */
++ 0, 0, 0, 0, 0, 0, 0, 0, -8, -8, -112, -112, -7, 0, 0, 0, /* 1fe0-1fef */
++ 0, 0, 0, 0, 0, 0, 0, 0,
++};
++
++/* Lower case range - Wide latin */
++static signed char UniCaseRangeLff20[27] = {
++ 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, /* ff20-ff2f */
++ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
++};
++
++/*
++ * Lower Case Range
++ */
++const static struct UniCaseRange CifsUniLowerRange[] = {
++ 0x0380, 0x03ab, UniCaseRangeL0380,
++ 0x0400, 0x042f, UniCaseRangeL0400,
++ 0x0490, 0x04cb, UniCaseRangeL0490,
++ 0x1e00, 0x1ff7, UniCaseRangeL1e00,
++ 0xff20, 0xff3a, UniCaseRangeLff20,
++ 0, 0, 0
++};
++#endif
+diff -urN linux-2.4.29.old/fs/cifs/connect.c linux-2.4.29/fs/cifs/connect.c
+--- linux-2.4.29.old/fs/cifs/connect.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/connect.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,2924 @@
++/*
++ * fs/cifs/connect.c
++ *
++ * Copyright (C) International Business Machines Corp., 2002,2004
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#include <linux/fs.h>
++#include <linux/net.h>
++#include <linux/string.h>
++#include <linux/list.h>
++#include <linux/wait.h>
++#include <linux/version.h>
++#include <linux/ipv6.h>
++#include <linux/pagemap.h>
++#include <linux/ctype.h>
++#include <linux/utsname.h>
++#include <asm/uaccess.h>
++#include <asm/processor.h>
++#include "cifspdu.h"
++#include "cifsglob.h"
++#include "cifsproto.h"
++#include "cifs_unicode.h"
++#include "cifs_debug.h"
++#include "cifs_fs_sb.h"
++#include "ntlmssp.h"
++#include "nterr.h"
++#include "rfc1002pdu.h"
++
++#define CIFS_PORT 445
++#define RFC1001_PORT 139
++
++extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
++ unsigned char *p24);
++extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
++ unsigned char *p24);
++extern int cifs_inet_pton(int, const char *, void *dst);
++
++struct smb_vol {
++ char *username;
++ char *password;
++ char *domainname;
++ char *UNC;
++ char *UNCip;
++ char *iocharset; /* local code page for mapping to and from Unicode */
++ char source_rfc1001_name[16]; /* netbios name of client */
++ uid_t linux_uid;
++ gid_t linux_gid;
++ mode_t file_mode;
++ mode_t dir_mode;
++ int rw:1;
++ int retry:1;
++ int intr:1;
++ unsigned int rsize;
++ unsigned int wsize;
++ unsigned int sockopt;
++ unsigned short int port;
++};
++
++static int ipv4_connect(struct sockaddr_in *psin_server,
++ struct socket **csocket,
++ char * netb_name);
++static int ipv6_connect(struct sockaddr_in6 *psin_server,
++ struct socket **csocket);
++
++
++ /*
++ * cifs tcp session reconnection
++ *
++ * mark tcp session as reconnecting so temporarily locked
++ * mark all smb sessions as reconnecting for tcp session
++ * reconnect tcp session
++ * wake up waiters on reconnection? - (not needed currently)
++ */
++
++int
++cifs_reconnect(struct TCP_Server_Info *server)
++{
++ int rc = 0;
++ struct list_head *tmp;
++ struct cifsSesInfo *ses;
++ struct cifsTconInfo *tcon;
++ struct mid_q_entry * mid_entry;
++
++ spin_lock(&GlobalMid_Lock);
++ if(server->tcpStatus == CifsExiting) {
++ /* the demux thread will exit normally
++ next time through the loop */
++ spin_unlock(&GlobalMid_Lock);
++ return rc;
++ } else
++ server->tcpStatus = CifsNeedReconnect;
++ spin_unlock(&GlobalMid_Lock);
++ server->maxBuf = 0;
++
++ cFYI(1, ("Reconnecting tcp session "));
++
++ /* before reconnecting the tcp session, mark the smb session (uid)
++ and the tid bad so they are not used until reconnected */
++ read_lock(&GlobalSMBSeslock);
++ list_for_each(tmp, &GlobalSMBSessionList) {
++ ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
++ if (ses->server) {
++ if (ses->server == server) {
++ ses->status = CifsNeedReconnect;
++ ses->ipc_tid = 0;
++ }
++ }
++ /* else tcp and smb sessions need reconnection */
++ }
++ list_for_each(tmp, &GlobalTreeConnectionList) {
++ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
++ if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
++ tcon->tidStatus = CifsNeedReconnect;
++ }
++ }
++ read_unlock(&GlobalSMBSeslock);
++ /* do not want to be sending data on a socket we are freeing */
++ down(&server->tcpSem);
++ if(server->ssocket) {
++ cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
++ server->ssocket->flags));
++ server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
++ cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
++ server->ssocket->flags));
++ sock_release(server->ssocket);
++ server->ssocket = NULL;
++ }
++
++ spin_lock(&GlobalMid_Lock);
++ list_for_each(tmp, &server->pending_mid_q) {
++ mid_entry = list_entry(tmp, struct
++ mid_q_entry,
++ qhead);
++ if(mid_entry) {
++ if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
++ /* Mark other intransit requests as needing retry so
++ we do not immediately mark the session bad again
++ (ie after we reconnect below) as they timeout too */
++ mid_entry->midState = MID_RETRY_NEEDED;
++ }
++ }
++ }
++ spin_unlock(&GlobalMid_Lock);
++ up(&server->tcpSem);
++
++ while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
++ {
++ if(server->protocolType == IPV6) {
++ rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
++ } else {
++ rc = ipv4_connect(&server->addr.sockAddr,
++ &server->ssocket,
++ server->workstation_RFC1001_name);
++ }
++ if(rc) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(3 * HZ);
++ } else {
++ atomic_inc(&tcpSesReconnectCount);
++ spin_lock(&GlobalMid_Lock);
++ if(server->tcpStatus != CifsExiting)
++ server->tcpStatus = CifsGood;
++ spin_unlock(&GlobalMid_Lock);
++ /* atomic_set(&server->inFlight,0);*/
++ wake_up(&server->response_q);
++ }
++ }
++ return rc;
++}
++
++static int
++cifs_demultiplex_thread(struct TCP_Server_Info *server)
++{
++ int length;
++ unsigned int pdu_length, total_read;
++ struct smb_hdr *smb_buffer = NULL;
++ struct msghdr smb_msg;
++ mm_segment_t temp_fs;
++ struct iovec iov;
++ struct socket *csocket = server->ssocket;
++ struct list_head *tmp;
++ struct cifsSesInfo *ses;
++ struct task_struct *task_to_wake = NULL;
++ struct mid_q_entry *mid_entry;
++ char *temp;
++
++ daemonize();
++ sprintf(current->comm,"cifsd");
++ /* allow_signal(SIGKILL);*/
++ current->flags |= PF_MEMALLOC;
++ server->tsk = current; /* save process info to wake at shutdown */
++ cFYI(1, ("Demultiplex PID: %d", current->pid));
++
++ temp_fs = get_fs(); /* we must turn off socket api parm checking */
++ set_fs(get_ds());
++
++ while (server->tcpStatus != CifsExiting) {
++ if (smb_buffer == NULL)
++ smb_buffer = cifs_buf_get();
++ else
++ memset(smb_buffer, 0, sizeof (struct smb_hdr));
++
++ if (smb_buffer == NULL) {
++ cERROR(1,("Can not get memory for SMB response"));
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(HZ * 3); /* give system time to free memory */
++ continue;
++ }
++ iov.iov_base = smb_buffer;
++ iov.iov_len = sizeof (struct smb_hdr) - 1;
++ /* 1 byte less above since wct is not always returned in error cases */
++ smb_msg.msg_iov = &iov;
++ smb_msg.msg_iovlen = 1;
++ smb_msg.msg_control = NULL;
++ smb_msg.msg_controllen = 0;
++
++ length =
++ sock_recvmsg(csocket, &smb_msg,
++ sizeof (struct smb_hdr) -
++ 1 /* RFC1001 header and SMB header */ ,
++ MSG_PEEK /* flags see socket.h */ );
++
++ if(server->tcpStatus == CifsExiting) {
++ break;
++ } else if (server->tcpStatus == CifsNeedReconnect) {
++ cFYI(1,("Reconnecting after server stopped responding"));
++ cifs_reconnect(server);
++ cFYI(1,("call to reconnect done"));
++ csocket = server->ssocket;
++ continue;
++ } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(1); /* minimum sleep to prevent looping
++ allowing socket to clear and app threads to set
++ tcpStatus CifsNeedReconnect if server hung */
++ continue;
++ } else if (length <= 0) {
++ if(server->tcpStatus == CifsNew) {
++ cFYI(1,("tcp session abended prematurely (after SMBnegprot)"));
++ /* some servers kill tcp session rather than returning
++ smb negprot error in which case reconnecting here is
++ not going to help - return error to mount */
++ break;
++ }
++ if(length == -EINTR) {
++ cFYI(1,("cifsd thread killed"));
++ break;
++ }
++ cFYI(1,("Reconnecting after unexpected peek error %d",length));
++ cifs_reconnect(server);
++ csocket = server->ssocket;
++ wake_up(&server->response_q);
++ continue;
++ }
++
++ pdu_length = 4 + ntohl(smb_buffer->smb_buf_length);
++ /* Ony read pdu_length after below checks for too short (due
++ to e.g. int overflow) and too long ie beyond end of buf */
++ cFYI(1, ("Peek length rcvd: 0x%x beginning 0x%x)", length, pdu_length));
++
++ temp = (char *) smb_buffer;
++ if (length > 3) {
++ if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) {
++ iov.iov_base = smb_buffer;
++ iov.iov_len = 4;
++ length = sock_recvmsg(csocket, &smb_msg, 4, 0);
++ cFYI(0,("Received 4 byte keep alive packet"));
++ } else if (temp[0] == (char) RFC1002_POSITIVE_SESSION_RESPONSE) {
++ iov.iov_base = smb_buffer;
++ iov.iov_len = 4;
++ length = sock_recvmsg(csocket, &smb_msg, 4, 0);
++ cFYI(1,("Good RFC 1002 session rsp"));
++ } else if ((temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE)
++ && (length == 5)) {
++ /* we get this from Windows 98 instead of error on SMB negprot response */
++ cFYI(1,("Negative RFC 1002 Session Response Error 0x%x)",temp[4]));
++ if(server->tcpStatus == CifsNew) {
++ /* if nack on negprot (rather than
++ ret of smb negprot error) reconnecting
++ not going to help, ret error to mount */
++ break;
++ } else {
++ /* give server a second to
++ clean up before reconnect attempt */
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(HZ);
++ /* always try 445 first on reconnect
++ since we get NACK on some if we ever
++ connected to port 139 (the NACK is
++ since we do not begin with RFC1001
++ session initialize frame) */
++ server->addr.sockAddr.sin_port = CIFS_PORT;
++ cifs_reconnect(server);
++ csocket = server->ssocket;
++ wake_up(&server->response_q);
++ continue;
++ }
++ } else if (temp[0] != (char) 0) {
++ cERROR(1,("Unknown RFC 1002 frame"));
++ cifs_dump_mem(" Received Data: ", temp, length);
++ cifs_reconnect(server);
++ csocket = server->ssocket;
++ continue;
++ } else {
++ if ((length != sizeof (struct smb_hdr) - 1)
++ || (pdu_length >
++ CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)
++ || (pdu_length <
++ sizeof (struct smb_hdr) - 1)
++ ||
++ (checkSMBhdr
++ (smb_buffer, smb_buffer->Mid))) {
++ cERROR(1,
++ ("Invalid size or format for SMB found with length %d and pdu_lenght %d",
++ length, pdu_length));
++ cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
++ /* could we fix this network corruption by finding next
++ smb header (instead of killing the session) and
++ restart reading from next valid SMB found? */
++ cifs_reconnect(server);
++ csocket = server->ssocket;
++ continue;
++ } else { /* length ok */
++
++ length = 0;
++ iov.iov_base = smb_buffer;
++ iov.iov_len = pdu_length;
++ for (total_read = 0;
++ total_read < pdu_length;
++ total_read += length) {
++ length = sock_recvmsg(csocket, &smb_msg,
++ pdu_length - total_read, 0);
++ if (length == 0) {
++ cERROR(1,
++ ("Zero length receive when expecting %d ",
++ pdu_length - total_read));
++ cifs_reconnect(server);
++ csocket = server->ssocket;
++ continue;
++ }
++ }
++ }
++
++ dump_smb(smb_buffer, length);
++ if (checkSMB
++ (smb_buffer, smb_buffer->Mid, total_read)) {
++ cERROR(1, ("Bad SMB Received "));
++ continue;
++ }
++
++ task_to_wake = NULL;
++ spin_lock(&GlobalMid_Lock);
++ list_for_each(tmp, &server->pending_mid_q) {
++ mid_entry = list_entry(tmp, struct
++ mid_q_entry,
++ qhead);
++
++ if ((mid_entry->mid == smb_buffer->Mid) && (mid_entry->midState == MID_REQUEST_SUBMITTED)) {
++ cFYI(1,
++ (" Mid 0x%x matched - waking up ",mid_entry->mid));
++ task_to_wake = mid_entry->tsk;
++ mid_entry->resp_buf =
++ smb_buffer;
++ mid_entry->midState =
++ MID_RESPONSE_RECEIVED;
++ }
++ }
++ spin_unlock(&GlobalMid_Lock);
++ if (task_to_wake) {
++ smb_buffer = NULL; /* will be freed by users thread after he is done */
++ wake_up_process(task_to_wake);
++ } else if (is_valid_oplock_break(smb_buffer) == FALSE) {
++ cERROR(1, ("No task to wake, unknown frame rcvd!"));
++ cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
++ }
++ }
++ } else {
++ cFYI(0,
++ ("Frame less than four bytes received %d bytes long.",
++ length));
++ if (length > 0) {
++ length = sock_recvmsg(csocket, &smb_msg, length, 0); /* throw away junk frame */
++ cFYI(1,
++ (" with junk 0x%x in it ",
++ *(__u32 *) smb_buffer));
++ }
++ }
++ }
++ spin_lock(&GlobalMid_Lock);
++ server->tcpStatus = CifsExiting;
++ server->tsk = NULL;
++ atomic_set(&server->inFlight, 0);
++ spin_unlock(&GlobalMid_Lock);
++ /* Although there should not be any requests blocked on
++ this queue it can not hurt to be paranoid and try to wake up requests
++ that may haven been blocked when more than 50 at time were on the wire
++ to the same server - they now will see the session is in exit state
++ and get out of SendReceive. */
++ wake_up_all(&server->request_q);
++ /* give those requests time to exit */
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(HZ/8);
++
++ if(server->ssocket) {
++ sock_release(csocket);
++ server->ssocket = NULL;
++ }
++ set_fs(temp_fs);
++ if (smb_buffer) /* buffer usually freed in free_mid - need to free it on error or exit */
++ cifs_buf_release(smb_buffer);
++
++ read_lock(&GlobalSMBSeslock);
++ if (list_empty(&server->pending_mid_q)) {
++ /* loop through server session structures attached to this and mark them dead */
++ list_for_each(tmp, &GlobalSMBSessionList) {
++ ses =
++ list_entry(tmp, struct cifsSesInfo,
++ cifsSessionList);
++ if (ses->server == server) {
++ ses->status = CifsExiting;
++ ses->server = NULL;
++ }
++ }
++ read_unlock(&GlobalSMBSeslock);
++ } else {
++ spin_lock(&GlobalMid_Lock);
++ list_for_each(tmp, &server->pending_mid_q) {
++ mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
++ if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
++ cFYI(1,
++ (" Clearing Mid 0x%x - waking up ",mid_entry->mid));
++ task_to_wake = mid_entry->tsk;
++ if(task_to_wake) {
++ wake_up_process(task_to_wake);
++ }
++ }
++ }
++ spin_unlock(&GlobalMid_Lock);
++ read_unlock(&GlobalSMBSeslock);
++ set_current_state(TASK_INTERRUPTIBLE);
++ /* 1/8th of sec is more than enough time for them to exit */
++ schedule_timeout(HZ/8);
++ }
++
++ if (list_empty(&server->pending_mid_q)) {
++ /* mpx threads have not exited yet give them
++ at least the smb send timeout time for long ops */
++ cFYI(1, ("Wait for exit from demultiplex thread"));
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(46 * HZ);
++ /* if threads still have not exited they are probably never
++ coming home not much else we can do but free the memory */
++ }
++ kfree(server);
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(HZ/4);
++ return 0;
++}
++
++static void *
++cifs_kcalloc(size_t size, int type)
++{
++ void *addr;
++ addr = kmalloc(size, type);
++ if (addr)
++ memset(addr, 0, size);
++ return addr;
++}
++
++static int
++cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol)
++{
++ char *value;
++ char *data;
++ unsigned int temp_len, i, j;
++ char separator[2];
++
++ separator[0] = ',';
++ separator[1] = 0;
++
++ memset(vol->source_rfc1001_name,0x20,15);
++ for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
++ /* does not have to be a perfect mapping since the field is
++ informational, only used for servers that do not support
++ port 445 and it can be overridden at mount time */
++ vol->source_rfc1001_name[i] = toupper(system_utsname.nodename[i]);
++ }
++ vol->source_rfc1001_name[15] = 0;
++
++ vol->linux_uid = current->uid; /* current->euid instead? */
++ vol->linux_gid = current->gid;
++ vol->dir_mode = S_IRWXUGO;
++ /* 2767 perms indicate mandatory locking support */
++ vol->file_mode = S_IALLUGO & ~(S_ISUID | S_IXGRP);
++
++ /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
++ vol->rw = TRUE;
++
++ if (!options)
++ return 1;
++
++ if(strncmp(options,"sep=",4) == 0) {
++ if(options[4] != 0) {
++ separator[0] = options[4];
++ options += 5;
++ } else {
++ cFYI(1,("Null separator not allowed"));
++ }
++ }
++
++ while ((data = strsep(&options, separator)) != NULL) {
++ if (!*data)
++ continue;
++ if ((value = strchr(data, '=')) != NULL)
++ *value++ = '\0';
++ if (strnicmp(data, "user", 4) == 0) {
++ if (!value || !*value) {
++ printk(KERN_WARNING
++ "CIFS: invalid or missing username\n");
++ return 1; /* needs_arg; */
++ }
++ if (strnlen(value, 200) < 200) {
++ vol->username = value;
++ } else {
++ printk(KERN_WARNING "CIFS: username too long\n");
++ return 1;
++ }
++ } else if (strnicmp(data, "pass", 4) == 0) {
++ if (!value || !*value) {
++ vol->password = NULL;
++ continue;
++ }
++ temp_len = strlen(value);
++ /* removed password length check, NTLM passwords
++ can be arbitrarily long */
++
++ /* if comma in password, the string will be
++ prematurely null terminated. Commas in password are
++ specified across the cifs mount interface by a double
++ comma ie ,, and a comma used as in other cases ie ','
++ as a parameter delimiter/separator is single and due
++ to the strsep above is temporarily zeroed. */
++
++ /* NB: password legally can have multiple commas and
++ the only illegal character in a password is null */
++
++ if ((value[temp_len] == 0) && (value[temp_len+1] == separator[0])) {
++ /* reinsert comma */
++ value[temp_len] = separator[0];
++ temp_len+=2; /* move after the second comma */
++ while(value[temp_len] != 0) {
++ if((value[temp_len] == separator[0]) && (value[temp_len+1] != separator[0])) {
++ /* single comma indicating start of next parm */
++ break;
++ }
++ temp_len++;
++ }
++ if(value[temp_len] == 0) {
++ options = NULL;
++ } else {
++ value[temp_len] = 0;
++ /* move options to point to start of next parm */
++ options = value + temp_len + 1;
++ }
++ /* go from value to (value + temp_len) condensing double commas to singles */
++ vol->password = cifs_kcalloc(temp_len, GFP_KERNEL);
++ for(i=0,j=0;i<temp_len;i++,j++) {
++ vol->password[j] = value[i];
++ if(value[i] == separator[0] && value[i+1] == separator[0]) {
++ /* skip second comma */
++ i++;
++ }
++ }
++ /* value[temp_len] is zeroed above so
++ vol->password[temp_len] guaranteed to be null */
++ } else {
++ vol->password = cifs_kcalloc(temp_len + 1, GFP_KERNEL);
++ strcpy(vol->password, value);
++ }
++ } else if (strnicmp(data, "ip", 2) == 0) {
++ if (!value || !*value) {
++ vol->UNCip = NULL;
++ } else if (strnlen(value, 35) < 35) {
++ vol->UNCip = value;
++ } else {
++ printk(KERN_WARNING "CIFS: ip address too long\n");
++ return 1;
++ }
++ } else if ((strnicmp(data, "unc", 3) == 0)
++ || (strnicmp(data, "target", 6) == 0)
++ || (strnicmp(data, "path", 4) == 0)) {
++ if (!value || !*value) {
++ printk(KERN_WARNING
++ "CIFS: invalid path to network resource\n");
++ return 1; /* needs_arg; */
++ }
++ if ((temp_len = strnlen(value, 300)) < 300) {
++ vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
++ if(vol->UNC == NULL)
++ return 1;
++ strcpy(vol->UNC,value);
++ if (strncmp(vol->UNC, "//", 2) == 0) {
++ vol->UNC[0] = '\\';
++ vol->UNC[1] = '\\';
++ } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
++ printk(KERN_WARNING
++ "CIFS: UNC Path does not begin with // or \\\\ \n");
++ return 1;
++ }
++ } else {
++ printk(KERN_WARNING "CIFS: UNC name too long\n");
++ return 1;
++ }
++ } else if ((strnicmp(data, "domain", 3) == 0)
++ || (strnicmp(data, "workgroup", 5) == 0)) {
++ if (!value || !*value) {
++ printk(KERN_WARNING "CIFS: invalid domain name\n");
++ return 1; /* needs_arg; */
++ }
++ /* BB are there cases in which a comma can be valid in
++ a domain name and need special handling? */
++ if (strnlen(value, 65) < 65) {
++ vol->domainname = value;
++ cFYI(1, ("Domain name set"));
++ } else {
++ printk(KERN_WARNING "CIFS: domain name too long\n");
++ return 1;
++ }
++ } else if (strnicmp(data, "iocharset", 9) == 0) {
++ if (!value || !*value) {
++ printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
++ return 1; /* needs_arg; */
++ }
++ if (strnlen(value, 65) < 65) {
++ if(strnicmp(value,"default",7))
++ vol->iocharset = value;
++ /* if iocharset not set load_nls_default used by caller */
++ cFYI(1, ("iocharset set to %s",value));
++ } else {
++ printk(KERN_WARNING "CIFS: iocharset name too long.\n");
++ return 1;
++ }
++ } else if (strnicmp(data, "uid", 3) == 0) {
++ if (value && *value) {
++ vol->linux_uid =
++ simple_strtoul(value, &value, 0);
++ }
++ } else if (strnicmp(data, "gid", 3) == 0) {
++ if (value && *value) {
++ vol->linux_gid =
++ simple_strtoul(value, &value, 0);
++ }
++ } else if (strnicmp(data, "file_mode", 4) == 0) {
++ if (value && *value) {
++ vol->file_mode =
++ simple_strtoul(value, &value, 0);
++ }
++ } else if (strnicmp(data, "dir_mode", 3) == 0) {
++ if (value && *value) {
++ vol->dir_mode =
++ simple_strtoul(value, &value, 0);
++ }
++ } else if (strnicmp(data, "port", 4) == 0) {
++ if (value && *value) {
++ vol->port =
++ simple_strtoul(value, &value, 0);
++ }
++ } else if (strnicmp(data, "rsize", 5) == 0) {
++ if (value && *value) {
++ vol->rsize =
++ simple_strtoul(value, &value, 0);
++ }
++ } else if (strnicmp(data, "wsize", 5) == 0) {
++ if (value && *value) {
++ vol->wsize =
++ simple_strtoul(value, &value, 0);
++ }
++ } else if (strnicmp(data, "sockopt", 5) == 0) {
++ if (value && *value) {
++ vol->sockopt =
++ simple_strtoul(value, &value, 0);
++ }
++ } else if (strnicmp(data, "netbiosname", 4) == 0) {
++ if (!value || !*value || (*value == ' ')) {
++ cFYI(1,("invalid (empty) netbiosname specified"));
++ } else {
++ memset(vol->source_rfc1001_name,0x20,15);
++ for(i=0;i<15;i++) {
++ /* BB are there cases in which a comma can be
++ valid in this workstation netbios name (and need
++ special handling)? */
++
++ /* We do not uppercase netbiosname for user */
++ if (value[i]==0)
++ break;
++ else
++ vol->source_rfc1001_name[i] = value[i];
++ }
++ /* The string has 16th byte zero still from
++ set at top of the function */
++ if((i==15) && (value[i] != 0))
++ printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n");
++ }
++ } else if (strnicmp(data, "credentials", 4) == 0) {
++ /* ignore */
++ } else if (strnicmp(data, "version", 3) == 0) {
++ /* ignore */
++ } else if (strnicmp(data, "rw", 2) == 0) {
++ vol->rw = TRUE;
++ } else if ((strnicmp(data, "suid", 4) == 0) ||
++ (strnicmp(data, "nosuid", 6) == 0) ||
++ (strnicmp(data, "exec", 4) == 0) ||
++ (strnicmp(data, "noexec", 6) == 0) ||
++ (strnicmp(data, "nodev", 5) == 0) ||
++ (strnicmp(data, "noauto", 6) == 0) ||
++ (strnicmp(data, "dev", 3) == 0)) {
++ /* The mount tool or mount.cifs helper (if present)
++ uses these opts to set flags, and the flags are read
++ by the kernel vfs layer before we get here (ie
++ before read super) so there is no point trying to
++ parse these options again and set anything and it
++ is ok to just ignore them */
++ continue;
++ } else if (strnicmp(data, "ro", 2) == 0) {
++ vol->rw = FALSE;
++ } else if (strnicmp(data, "hard", 4) == 0) {
++ vol->retry = 1;
++ } else if (strnicmp(data, "soft", 4) == 0) {
++ vol->retry = 0;
++ } else if (strnicmp(data, "nohard", 6) == 0) {
++ vol->retry = 0;
++ } else if (strnicmp(data, "nosoft", 6) == 0) {
++ vol->retry = 1;
++ } else if (strnicmp(data, "nointr", 6) == 0) {
++ vol->intr = 0;
++ } else if (strnicmp(data, "intr", 4) == 0) {
++ vol->intr = 1;
++ } else if (strnicmp(data, "noac", 4) == 0) {
++ printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
++ } else
++ printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
++ }
++ if (vol->UNC == NULL) {
++ if(devname == NULL) {
++ printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
++ return 1;
++ }
++ if ((temp_len = strnlen(devname, 300)) < 300) {
++ vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
++ if(vol->UNC == NULL)
++ return 1;
++ strcpy(vol->UNC,devname);
++ if (strncmp(vol->UNC, "//", 2) == 0) {
++ vol->UNC[0] = '\\';
++ vol->UNC[1] = '\\';
++ } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
++ printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
++ return 1;
++ }
++ } else {
++ printk(KERN_WARNING "CIFS: UNC name too long\n");
++ return 1;
++ }
++ }
++ if(vol->UNCip == 0)
++ vol->UNCip = &vol->UNC[2];
++
++ return 0;
++}
++
++static struct cifsSesInfo *
++cifs_find_tcp_session(__u32 new_target_ip_addr,
++ char *userName, struct TCP_Server_Info **psrvTcp)
++{
++ struct list_head *tmp;
++ struct cifsSesInfo *ses;
++
++ *psrvTcp = NULL;
++ read_lock(&GlobalSMBSeslock);
++ list_for_each(tmp, &GlobalSMBSessionList) {
++ ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
++ if (ses->server) {
++ if (ses->server->addr.sockAddr.sin_addr.s_addr ==
++ new_target_ip_addr) {
++ /* BB lock server and tcp session and increment use count here?? */
++ *psrvTcp = ses->server; /* found a match on the TCP session */
++ /* BB check if reconnection needed */
++ if (strncmp
++ (ses->userName, userName,
++ MAX_USERNAME_SIZE) == 0){
++ read_unlock(&GlobalSMBSeslock);
++ return ses; /* found exact match on both tcp and SMB sessions */
++ }
++ }
++ }
++ /* else tcp and smb sessions need reconnection */
++ }
++ read_unlock(&GlobalSMBSeslock);
++ return NULL;
++}
++
++static struct cifsTconInfo *
++find_unc(__u32 new_target_ip_addr, char *uncName, char *userName)
++{
++ struct list_head *tmp;
++ struct cifsTconInfo *tcon;
++
++ read_lock(&GlobalSMBSeslock);
++ list_for_each(tmp, &GlobalTreeConnectionList) {
++ cFYI(1, ("Next tcon - "));
++ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
++ if (tcon->ses) {
++ if (tcon->ses->server) {
++ cFYI(1,
++ (" old ip addr: %x == new ip %x ?",
++ tcon->ses->server->addr.sockAddr.sin_addr.
++ s_addr, new_target_ip_addr));
++ if (tcon->ses->server->addr.sockAddr.sin_addr.
++ s_addr == new_target_ip_addr) {
++ /* BB lock tcon and server and tcp session and increment use count here? */
++ /* found a match on the TCP session */
++ /* BB check if reconnection needed */
++ cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
++ tcon->treeName, uncName));
++ if (strncmp
++ (tcon->treeName, uncName,
++ MAX_TREE_SIZE) == 0) {
++ cFYI(1,
++ ("Matched UNC, old user: %s == new: %s ?",
++ tcon->treeName, uncName));
++ if (strncmp
++ (tcon->ses->userName,
++ userName,
++ MAX_USERNAME_SIZE) == 0) {
++ read_unlock(&GlobalSMBSeslock);
++ return tcon;/* also matched user (smb session)*/
++ }
++ }
++ }
++ }
++ }
++ }
++ read_unlock(&GlobalSMBSeslock);
++ return NULL;
++}
++
++int
++connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
++ const char *old_path, const struct nls_table *nls_codepage)
++{
++ unsigned char *referrals = NULL;
++ unsigned int num_referrals;
++ int rc = 0;
++
++ rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
++ &num_referrals, &referrals);
++
++ /* BB Add in code to: if valid refrl, if not ip address contact
++ the helper that resolves tcp names, mount to it, try to
++ tcon to it unmount it if fail */
++
++ if(referrals)
++ kfree(referrals);
++
++ return rc;
++}
++
++int
++get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
++ const char *old_path, const struct nls_table *nls_codepage,
++ unsigned int *pnum_referrals, unsigned char ** preferrals)
++{
++ char *temp_unc;
++ int rc = 0;
++
++ *pnum_referrals = 0;
++
++ if (pSesInfo->ipc_tid == 0) {
++ temp_unc = kmalloc(2 /* for slashes */ +
++ strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
++ + 1 + 4 /* slash IPC$ */ + 2,
++ GFP_KERNEL);
++ if (temp_unc == NULL)
++ return -ENOMEM;
++ temp_unc[0] = '\\';
++ temp_unc[1] = '\\';
++ strcpy(temp_unc + 2, pSesInfo->serverName);
++ strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
++ rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
++ cFYI(1,
++ ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
++ kfree(temp_unc);
++ }
++ if (rc == 0)
++ rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
++ pnum_referrals, nls_codepage);
++
++ return rc;
++}
++
++/* See RFC1001 section 14 on representation of Netbios names */
++static void rfc1002mangle(char * target,char * source, unsigned int length)
++{
++ unsigned int i,j;
++
++ for(i=0,j=0;i<(length);i++) {
++ /* mask a nibble at a time and encode */
++ target[j] = 'A' + (0x0F & (source[i] >> 4));
++ target[j+1] = 'A' + (0x0F & source[i]);
++ j+=2;
++ }
++
++}
++
++
++static int
++ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
++ char * netbios_name)
++{
++ int rc = 0;
++ int connected = 0;
++ unsigned short int orig_port = 0;
++
++ if(*csocket == NULL) {
++ rc = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
++ if (rc < 0) {
++ cERROR(1, ("Error %d creating socket",rc));
++ *csocket = NULL;
++ return rc;
++ } else {
++ /* BB other socket options to set KEEPALIVE, NODELAY? */
++ cFYI(1,("Socket created"));
++ (*csocket)->sk->allocation = GFP_NOFS;
++ }
++ }
++
++ psin_server->sin_family = AF_INET;
++ if(psin_server->sin_port) { /* user overrode default port */
++ rc = (*csocket)->ops->connect(*csocket,
++ (struct sockaddr *) psin_server,
++ sizeof (struct sockaddr_in),0);
++ if (rc >= 0)
++ connected = 1;
++ }
++
++ if(!connected) {
++ /* save original port so we can retry user specified port
++ later if fall back ports fail this time */
++ orig_port = psin_server->sin_port;
++
++ /* do not retry on the same port we just failed on */
++ if(psin_server->sin_port != htons(CIFS_PORT)) {
++ psin_server->sin_port = htons(CIFS_PORT);
++
++ rc = (*csocket)->ops->connect(*csocket,
++ (struct sockaddr *) psin_server,
++ sizeof (struct sockaddr_in),0);
++ if (rc >= 0)
++ connected = 1;
++ }
++ }
++ if (!connected) {
++ psin_server->sin_port = htons(RFC1001_PORT);
++ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
++ psin_server, sizeof (struct sockaddr_in),0);
++ if (rc >= 0)
++ connected = 1;
++ }
++
++ /* give up here - unless we want to retry on different
++ protocol families some day */
++ if (!connected) {
++ if(orig_port)
++ psin_server->sin_port = orig_port;
++ cFYI(1,("Error %d connecting to server via ipv4",rc));
++ sock_release(*csocket);
++ *csocket = NULL;
++ return rc;
++ }
++ /* Eventually check for other socket options to change from
++ the default. sock_setsockopt not used because it expects
++ user space buffer */
++ (*csocket)->sk->rcvtimeo = 7 * HZ;
++
++ /* send RFC1001 sessinit */
++
++ if(psin_server->sin_port == htons(139)) {
++ /* some servers require RFC1001 sessinit before sending
++ negprot - BB check reconnection in case where second
++ sessinit is sent but no second negprot */
++ struct rfc1002_session_packet * ses_init_buf;
++ struct smb_hdr * smb_buf;
++ ses_init_buf = cifs_kcalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
++ if(ses_init_buf) {
++ ses_init_buf->trailer.session_req.called_len = 32;
++ rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
++ DEFAULT_CIFS_CALLED_NAME,16);
++ ses_init_buf->trailer.session_req.calling_len = 32;
++ /* calling name ends in null (byte 16) from old smb
++ convention. */
++ if(netbios_name && (netbios_name[0] !=0)) {
++ rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
++ netbios_name,16);
++ } else {
++ rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
++ "LINUX_CIFS_CLNT",16);
++ }
++ ses_init_buf->trailer.session_req.scope1 = 0;
++ ses_init_buf->trailer.session_req.scope2 = 0;
++ smb_buf = (struct smb_hdr *)ses_init_buf;
++ /* sizeof RFC1002_SESSION_REQUEST with no scope */
++ smb_buf->smb_buf_length = 0x81000044;
++ rc = smb_send(*csocket, smb_buf, 0x44,
++ (struct sockaddr *)psin_server);
++ kfree(ses_init_buf);
++ }
++ /* else the negprot may still work without this
++ even though malloc failed */
++
++ }
++
++ return rc;
++}
++
++static int
++ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
++{
++ int rc = 0;
++ int connected = 0;
++
++ if(*csocket == NULL) {
++ rc = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
++ if (rc < 0) {
++ cERROR(1, ("Error %d creating ipv6 socket",rc));
++ *csocket = NULL;
++ return rc;
++ } else {
++ /* BB other socket options to set KEEPALIVE, NODELAY? */
++ cFYI(1,("ipv6 Socket created"));
++ (*csocket)->sk->allocation = GFP_NOFS;
++ }
++ }
++
++ psin_server->sin6_family = AF_INET6;
++
++ if(psin_server->sin6_port) { /* user overrode default port */
++ rc = (*csocket)->ops->connect(*csocket,
++ (struct sockaddr *) psin_server,
++ sizeof (struct sockaddr_in6),0);
++ if (rc >= 0)
++ connected = 1;
++ }
++
++ if(!connected) {
++ /* do not retry on the same port we just failed on */
++ if(psin_server->sin6_port != htons(CIFS_PORT)) {
++ psin_server->sin6_port = htons(CIFS_PORT);
++
++ rc = (*csocket)->ops->connect(*csocket,
++ (struct sockaddr *) psin_server,
++ sizeof (struct sockaddr_in6),0);
++ if (rc >= 0)
++ connected = 1;
++ }
++ }
++ if (!connected) {
++ psin_server->sin6_port = htons(RFC1001_PORT);
++ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
++ psin_server, sizeof (struct sockaddr_in6),0);
++ if (rc >= 0)
++ connected = 1;
++ }
++
++ /* give up here - unless we want to retry on different
++ protocol families some day */
++ if (!connected) {
++ cFYI(1,("Error %d connecting to server via ipv6",rc));
++ sock_release(*csocket);
++ *csocket = NULL;
++ return rc;
++ }
++ /* Eventually check for other socket options to change from
++ the default. sock_setsockopt not used because it expects
++ user space buffer */
++ (*csocket)->sk->rcvtimeo = 7 * HZ;
++
++ return rc;
++}
++
++int
++cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
++ char *mount_data, const char *devname)
++{
++ int rc = 0;
++ int xid;
++ struct socket *csocket = NULL;
++ struct sockaddr_in sin_server;
++ struct sockaddr_in6 sin_server6;
++ struct smb_vol volume_info;
++ struct cifsSesInfo *pSesInfo = NULL;
++ struct cifsSesInfo *existingCifsSes = NULL;
++ struct cifsTconInfo *tcon = NULL;
++ struct TCP_Server_Info *srvTcp = NULL;
++
++ xid = GetXid();
++
++ cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); /* BB removeme BB fixme */
++
++ memset(&volume_info,0,sizeof(struct smb_vol));
++ if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
++ if(volume_info.UNC)
++ kfree(volume_info.UNC);
++ if(volume_info.password)
++ kfree(volume_info.password);
++ FreeXid(xid);
++ return -EINVAL;
++ }
++
++ if (volume_info.username) {
++ cFYI(1, ("Username: %s ", volume_info.username));
++
++ } else {
++ cifserror("No username specified ");
++ /* In userspace mount helper we can get user name from alternate
++ locations such as env variables and files on disk */
++ if(volume_info.UNC)
++ kfree(volume_info.UNC);
++ if(volume_info.password)
++ kfree(volume_info.password);
++ FreeXid(xid);
++ return -EINVAL;
++ }
++
++ if (volume_info.UNCip && volume_info.UNC) {
++ rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
++
++ if(rc == 0) {
++ /* not ipv4 address, try ipv6 */
++ rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
++ }
++
++ if(rc != 1) {
++ /* we failed translating address */
++ if(volume_info.UNC)
++ kfree(volume_info.UNC);
++ if(volume_info.password)
++ kfree(volume_info.password);
++ FreeXid(xid);
++ return -EINVAL;
++ }
++
++ cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
++ /* success */
++ rc = 0;
++ } else if (volume_info.UNCip){
++ /* BB using ip addr as server name connect to the DFS root below */
++ cERROR(1,("Connecting to DFS root not implemented yet"));
++ if(volume_info.UNC)
++ kfree(volume_info.UNC);
++ if(volume_info.password)
++ kfree(volume_info.password);
++ FreeXid(xid);
++ return -EINVAL;
++ } else /* which servers DFS root would we conect to */ {
++ cERROR(1,
++ ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified "));
++ if(volume_info.UNC)
++ kfree(volume_info.UNC);
++ if(volume_info.password)
++ kfree(volume_info.password);
++ FreeXid(xid);
++ return -EINVAL;
++ }
++
++ /* this is needed for ASCII cp to Unicode converts */
++ if(volume_info.iocharset == NULL) {
++ cifs_sb->local_nls = load_nls_default();
++ /* load_nls_default can not return null */
++ } else {
++ cifs_sb->local_nls = load_nls(volume_info.iocharset);
++ if(cifs_sb->local_nls == NULL) {
++ cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
++ if(volume_info.UNC)
++ kfree(volume_info.UNC);
++ if(volume_info.password)
++ kfree(volume_info.password);
++ FreeXid(xid);
++ return -ELIBACC;
++ }
++ }
++
++ existingCifsSes =
++ cifs_find_tcp_session(sin_server.sin_addr.s_addr,
++ volume_info.username, &srvTcp);
++ if (srvTcp) {
++ cFYI(1, ("Existing tcp session with server found "));
++ } else { /* create socket */
++ if(volume_info.port)
++ sin_server.sin_port = htons(volume_info.port);
++ else
++ sin_server.sin_port = 0;
++ rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name);
++ if (rc < 0) {
++ cERROR(1,
++ ("Error connecting to IPv4 socket. Aborting operation"));
++ if(csocket != NULL)
++ sock_release(csocket);
++ if(volume_info.UNC)
++ kfree(volume_info.UNC);
++ if(volume_info.password)
++ kfree(volume_info.password);
++ FreeXid(xid);
++ return rc;
++ }
++
++ srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL);
++ if (srvTcp == NULL) {
++ rc = -ENOMEM;
++ sock_release(csocket);
++ if(volume_info.UNC)
++ kfree(volume_info.UNC);
++ if(volume_info.password)
++ kfree(volume_info.password);
++ FreeXid(xid);
++ return rc;
++ } else {
++ memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
++ memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
++ atomic_set(&srvTcp->inFlight,0);
++ /* BB Add code for ipv6 case too */
++ srvTcp->ssocket = csocket;
++ srvTcp->protocolType = IPV4;
++ init_waitqueue_head(&srvTcp->response_q);
++ init_waitqueue_head(&srvTcp->request_q);
++ INIT_LIST_HEAD(&srvTcp->pending_mid_q);
++ /* at this point we are the only ones with the pointer
++ to the struct since the kernel thread not created yet
++ so no need to spinlock this init of tcpStatus */
++ srvTcp->tcpStatus = CifsNew;
++ init_MUTEX(&srvTcp->tcpSem);
++ kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
++ CLONE_FS | CLONE_FILES | CLONE_VM);
++ memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
++ }
++ }
++
++ if (existingCifsSes) {
++ pSesInfo = existingCifsSes;
++ cFYI(1, ("Existing smb sess found "));
++ if(volume_info.password)
++ kfree(volume_info.password);
++ /* volume_info.UNC freed at end of function */
++ } else if (!rc) {
++ cFYI(1, ("Existing smb sess not found "));
++ pSesInfo = sesInfoAlloc();
++ if (pSesInfo == NULL)
++ rc = -ENOMEM;
++ else {
++ pSesInfo->server = srvTcp;
++ sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
++ NIPQUAD(sin_server.sin_addr.s_addr));
++ }
++
++ if (!rc){
++ /* volume_info.password freed at unmount */
++ if (volume_info.password)
++ pSesInfo->password = volume_info.password;
++ if (volume_info.username)
++ strncpy(pSesInfo->userName,
++ volume_info.username,MAX_USERNAME_SIZE);
++ if (volume_info.domainname)
++ strncpy(pSesInfo->domainName,
++ volume_info.domainname,MAX_USERNAME_SIZE);
++ pSesInfo->linux_uid = volume_info.linux_uid;
++ down(&pSesInfo->sesSem);
++ rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
++ up(&pSesInfo->sesSem);
++ if(!rc)
++ atomic_inc(&srvTcp->socketUseCount);
++ } else
++ if(volume_info.password)
++ kfree(volume_info.password);
++ }
++
++ /* search for existing tcon to this server share */
++ if (!rc) {
++ if((volume_info.rsize) && (volume_info.rsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
++ cifs_sb->rsize = volume_info.rsize;
++ else
++ cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
++ if((volume_info.wsize) && (volume_info.wsize + MAX_CIFS_HDR_SIZE < srvTcp->maxBuf))
++ cifs_sb->wsize = volume_info.wsize;
++ else
++ cifs_sb->wsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */
++ if(cifs_sb->rsize < PAGE_CACHE_SIZE) {
++ cifs_sb->rsize = PAGE_CACHE_SIZE;
++ cERROR(1,("Attempt to set readsize for mount to less than one page (4096)"));
++ }
++ cifs_sb->mnt_uid = volume_info.linux_uid;
++ cifs_sb->mnt_gid = volume_info.linux_gid;
++ cifs_sb->mnt_file_mode = volume_info.file_mode;
++ cifs_sb->mnt_dir_mode = volume_info.dir_mode;
++ cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
++ tcon =
++ find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
++ volume_info.username);
++ if (tcon) {
++ cFYI(1, ("Found match on UNC path "));
++ /* we can have only one retry value for a connection
++ to a share so for resources mounted more than once
++ to the same server share the last value passed in
++ for the retry flag is used */
++ tcon->retry = volume_info.retry;
++ } else {
++ tcon = tconInfoAlloc();
++ if (tcon == NULL)
++ rc = -ENOMEM;
++ else {
++ /* check for null share name ie connect to dfs root */
++
++ /* BB check if this works for exactly length three strings */
++ if ((strchr(volume_info.UNC + 3, '\\') == NULL)
++ && (strchr(volume_info.UNC + 3, '/') ==
++ NULL)) {
++ rc = connect_to_dfs_path(xid,
++ pSesInfo,
++ "",
++ cifs_sb->
++ local_nls);
++ if(volume_info.UNC)
++ kfree(volume_info.UNC);
++ FreeXid(xid);
++ return -ENODEV;
++ } else {
++ rc = CIFSTCon(xid, pSesInfo,
++ volume_info.UNC,
++ tcon, cifs_sb->local_nls);
++ cFYI(1, ("CIFS Tcon rc = %d", rc));
++ }
++ if (!rc) {
++ atomic_inc(&pSesInfo->inUse);
++ tcon->retry = volume_info.retry;
++ }
++ }
++ }
++ }
++ if(pSesInfo) {
++ if (pSesInfo->capabilities & CAP_LARGE_FILES) {
++ sb->s_maxbytes = (u64) 1 << 63;
++ } else
++ sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
++ }
++
++/* on error free sesinfo and tcon struct if needed */
++ if (rc) {
++ /* if session setup failed, use count is zero but
++ we still need to free cifsd thread */
++ if(atomic_read(&srvTcp->socketUseCount) == 0) {
++ spin_lock(&GlobalMid_Lock);
++ srvTcp->tcpStatus = CifsExiting;
++ spin_unlock(&GlobalMid_Lock);
++ if(srvTcp->tsk)
++ send_sig(SIGKILL,srvTcp->tsk,1);
++ }
++ /* If find_unc succeeded then rc == 0 so we can not end */
++ if (tcon) /* up accidently freeing someone elses tcon struct */
++ tconInfoFree(tcon);
++ if (existingCifsSes == 0) {
++ if (pSesInfo) {
++ if ((pSesInfo->server) &&
++ (pSesInfo->status == CifsGood)) {
++ int temp_rc;
++ temp_rc = CIFSSMBLogoff(xid, pSesInfo);
++ /* if the socketUseCount is now zero */
++ if((temp_rc == -ESHUTDOWN) &&
++ (pSesInfo->server->tsk))
++ send_sig(SIGKILL,pSesInfo->server->tsk,1);
++ } else
++ cFYI(1, ("No session or bad tcon"));
++ sesInfoFree(pSesInfo);
++ /* pSesInfo = NULL; */
++ }
++ }
++ } else {
++ atomic_inc(&tcon->useCount);
++ cifs_sb->tcon = tcon;
++ tcon->ses = pSesInfo;
++
++ /* do not care if following two calls succeed - informational only */
++ CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls);
++ CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls);
++ if (tcon->ses->capabilities & CAP_UNIX)
++ CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls);
++ }
++
++ /* volume_info.password is freed above when existing session found
++ (in which case it is not needed anymore) but when new sesion is created
++ the password ptr is put in the new session structure (in which case the
++ password will be freed at unmount time) */
++ if(volume_info.UNC)
++ kfree(volume_info.UNC);
++ FreeXid(xid);
++ return rc;
++}
++
++static int
++CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
++ char session_key[CIFS_SESSION_KEY_SIZE],
++ const struct nls_table *nls_codepage)
++{
++ struct smb_hdr *smb_buffer;
++ struct smb_hdr *smb_buffer_response;
++ SESSION_SETUP_ANDX *pSMB;
++ SESSION_SETUP_ANDX *pSMBr;
++ char *bcc_ptr;
++ char *user = ses->userName;
++ char *domain = ses->domainName;
++ int rc = 0;
++ int remaining_words = 0;
++ int bytes_returned = 0;
++ int len;
++
++ cFYI(1, ("In sesssetup "));
++
++ smb_buffer = cifs_buf_get();
++ if (smb_buffer == 0) {
++ return -ENOMEM;
++ }
++ smb_buffer_response = smb_buffer;
++ pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
++
++ /* send SMBsessionSetup here */
++ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
++ NULL /* no tCon exists yet */ , 13 /* wct */ );
++
++ pSMB->req_no_secext.AndXCommand = 0xFF;
++ pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
++ pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
++
++ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
++ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
++
++ pSMB->req_no_secext.Capabilities =
++ CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS;
++ if (ses->capabilities & CAP_UNICODE) {
++ smb_buffer->Flags2 |= SMBFLG2_UNICODE;
++ pSMB->req_no_secext.Capabilities |= CAP_UNICODE;
++ }
++ if (ses->capabilities & CAP_STATUS32) {
++ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
++ pSMB->req_no_secext.Capabilities |= CAP_STATUS32;
++ }
++ if (ses->capabilities & CAP_DFS) {
++ smb_buffer->Flags2 |= SMBFLG2_DFS;
++ pSMB->req_no_secext.Capabilities |= CAP_DFS;
++ }
++ pSMB->req_no_secext.Capabilities =
++ cpu_to_le32(pSMB->req_no_secext.Capabilities);
++ /* pSMB->req_no_secext.CaseInsensitivePasswordLength =
++ CIFS_SESSION_KEY_SIZE; */
++ pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
++ pSMB->req_no_secext.CaseSensitivePasswordLength =
++ cpu_to_le16(CIFS_SESSION_KEY_SIZE);
++ bcc_ptr = pByteArea(smb_buffer);
++ /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE);
++ bcc_ptr += CIFS_SESSION_KEY_SIZE; */
++ memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
++ bcc_ptr += CIFS_SESSION_KEY_SIZE;
++
++ if (ses->capabilities & CAP_UNICODE) {
++ if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
++ *bcc_ptr = 0;
++ bcc_ptr++;
++ }
++ if(user == NULL)
++ bytes_returned = 0; /* skill null user */
++ else
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100,
++ nls_codepage);
++ bcc_ptr += 2 * bytes_returned; /* convert num 16 bit words to bytes */
++ bcc_ptr += 2; /* trailing null */
++ if (domain == NULL)
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr,
++ "CIFS_LINUX_DOM", 32, nls_codepage);
++ else
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
++ nls_codepage);
++ bcc_ptr += 2 * bytes_returned;
++ bcc_ptr += 2;
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
++ 32, nls_codepage);
++ bcc_ptr += 2 * bytes_returned;
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
++ nls_codepage);
++ bcc_ptr += 2 * bytes_returned;
++ bcc_ptr += 2;
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
++ 64, nls_codepage);
++ bcc_ptr += 2 * bytes_returned;
++ bcc_ptr += 2;
++ } else {
++ if(user != NULL) {
++ strncpy(bcc_ptr, user, 200);
++ bcc_ptr += strnlen(user, 200);
++ }
++ *bcc_ptr = 0;
++ bcc_ptr++;
++ if (domain == NULL) {
++ strcpy(bcc_ptr, "CIFS_LINUX_DOM");
++ bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
++ } else {
++ strncpy(bcc_ptr, domain, 64);
++ bcc_ptr += strnlen(domain, 64);
++ *bcc_ptr = 0;
++ bcc_ptr++;
++ }
++ strcpy(bcc_ptr, "Linux version ");
++ bcc_ptr += strlen("Linux version ");
++ strcpy(bcc_ptr, UTS_RELEASE);
++ bcc_ptr += strlen(UTS_RELEASE) + 1;
++ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
++ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
++ }
++ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
++ smb_buffer->smb_buf_length += BCC(smb_buffer);
++ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
++
++ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
++ &bytes_returned, 1);
++ if (rc) {
++/* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */
++ } else if ((smb_buffer_response->WordCount == 3)
++ || (smb_buffer_response->WordCount == 4)) {
++ pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
++ if (pSMBr->resp.Action & GUEST_LOGIN)
++ cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
++ if (ses) {
++ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
++ cFYI(1, ("UID = %d ", ses->Suid));
++ /* response can have either 3 or 4 word count - Samba sends 3 */
++ bcc_ptr = pByteArea(smb_buffer_response);
++ if ((pSMBr->resp.hdr.WordCount == 3)
++ || ((pSMBr->resp.hdr.WordCount == 4)
++ && (pSMBr->resp.SecurityBlobLength <
++ pSMBr->resp.ByteCount))) {
++ if (pSMBr->resp.hdr.WordCount == 4)
++ bcc_ptr +=
++ pSMBr->resp.SecurityBlobLength;
++
++ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
++ if ((long) (bcc_ptr) % 2) {
++ remaining_words =
++ (BCC(smb_buffer_response)
++ - 1) / 2;
++ bcc_ptr++; /* Unicode strings must be word aligned */
++ } else {
++ remaining_words =
++ BCC
++ (smb_buffer_response) / 2;
++ }
++ len =
++ UniStrnlen((wchar_t *) bcc_ptr,
++ remaining_words - 1);
++/* We look for obvious messed up bcc or strings in response so we do not go off
++ the end since (at least) WIN2K and Windows XP have a major bug in not null
++ terminating last Unicode string in response */
++ ses->serverOS = cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
++ cifs_strfromUCS_le(ses->serverOS,
++ (wchar_t *)bcc_ptr, len,nls_codepage);
++ bcc_ptr += 2 * (len + 1);
++ remaining_words -= len + 1;
++ ses->serverOS[2 * len] = 0;
++ ses->serverOS[1 + (2 * len)] = 0;
++ if (remaining_words > 0) {
++ len = UniStrnlen((wchar_t *)bcc_ptr,
++ remaining_words
++ - 1);
++ ses->serverNOS =cifs_kcalloc(2 * (len + 1),GFP_KERNEL);
++ cifs_strfromUCS_le(ses->serverNOS,
++ (wchar_t *)bcc_ptr,len,nls_codepage);
++ bcc_ptr += 2 * (len + 1);
++ ses->serverNOS[2 * len] = 0;
++ ses->serverNOS[1 + (2 * len)] = 0;
++ remaining_words -= len + 1;
++ if (remaining_words > 0) {
++ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
++ /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
++ ses->serverDomain =
++ cifs_kcalloc(2*(len+1),GFP_KERNEL);
++ cifs_strfromUCS_le(ses->serverDomain,
++ (wchar_t *)bcc_ptr,len,nls_codepage);
++ bcc_ptr += 2 * (len + 1);
++ ses->serverDomain[2*len] = 0;
++ ses->serverDomain[1+(2*len)] = 0;
++ } /* else no more room so create dummy domain string */
++ else
++ ses->serverDomain =
++ cifs_kcalloc(2,
++ GFP_KERNEL);
++ } else { /* no room so create dummy domain and NOS string */
++ ses->serverDomain =
++ cifs_kcalloc(2, GFP_KERNEL);
++ ses->serverNOS =
++ cifs_kcalloc(2, GFP_KERNEL);
++ }
++ } else { /* ASCII */
++ len = strnlen(bcc_ptr, 1024);
++ if (((long) bcc_ptr + len) - (long)
++ pByteArea(smb_buffer_response)
++ <= BCC(smb_buffer_response)) {
++ ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
++ strncpy(ses->serverOS,bcc_ptr, len);
++
++ bcc_ptr += len;
++ bcc_ptr[0] = 0; /* null terminate the string */
++ bcc_ptr++;
++
++ len = strnlen(bcc_ptr, 1024);
++ ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
++ strncpy(ses->serverNOS, bcc_ptr, len);
++ bcc_ptr += len;
++ bcc_ptr[0] = 0;
++ bcc_ptr++;
++
++ len = strnlen(bcc_ptr, 1024);
++ ses->serverDomain = cifs_kcalloc(len + 1,GFP_KERNEL);
++ strncpy(ses->serverDomain, bcc_ptr, len);
++ bcc_ptr += len;
++ bcc_ptr[0] = 0;
++ bcc_ptr++;
++ } else
++ cFYI(1,
++ ("Variable field of length %d extends beyond end of smb ",
++ len));
++ }
++ } else {
++ cERROR(1,
++ (" Security Blob Length extends beyond end of SMB"));
++ }
++ } else {
++ cERROR(1, ("No session structure passed in."));
++ }
++ } else {
++ cERROR(1,
++ (" Invalid Word count %d: ",
++ smb_buffer_response->WordCount));
++ rc = -EIO;
++ }
++
++ if (smb_buffer)
++ cifs_buf_release(smb_buffer);
++
++ return rc;
++}
++
++static int
++CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
++ char *SecurityBlob,int SecurityBlobLength,
++ const struct nls_table *nls_codepage)
++{
++ struct smb_hdr *smb_buffer;
++ struct smb_hdr *smb_buffer_response;
++ SESSION_SETUP_ANDX *pSMB;
++ SESSION_SETUP_ANDX *pSMBr;
++ char *bcc_ptr;
++ char *user = ses->userName;
++ char *domain = ses->domainName;
++ int rc = 0;
++ int remaining_words = 0;
++ int bytes_returned = 0;
++ int len;
++
++ cFYI(1, ("In spnego sesssetup "));
++
++ smb_buffer = cifs_buf_get();
++ if (smb_buffer == 0) {
++ return -ENOMEM;
++ }
++ smb_buffer_response = smb_buffer;
++ pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
++
++ /* send SMBsessionSetup here */
++ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
++ NULL /* no tCon exists yet */ , 12 /* wct */ );
++ pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
++ pSMB->req.AndXCommand = 0xFF;
++ pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
++ pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
++
++ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
++ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
++
++ pSMB->req.Capabilities =
++ CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
++ CAP_EXTENDED_SECURITY;
++ if (ses->capabilities & CAP_UNICODE) {
++ smb_buffer->Flags2 |= SMBFLG2_UNICODE;
++ pSMB->req.Capabilities |= CAP_UNICODE;
++ }
++ if (ses->capabilities & CAP_STATUS32) {
++ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
++ pSMB->req.Capabilities |= CAP_STATUS32;
++ }
++ if (ses->capabilities & CAP_DFS) {
++ smb_buffer->Flags2 |= SMBFLG2_DFS;
++ pSMB->req.Capabilities |= CAP_DFS;
++ }
++ pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
++
++ pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
++ bcc_ptr = pByteArea(smb_buffer);
++ memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
++ bcc_ptr += SecurityBlobLength;
++
++ if (ses->capabilities & CAP_UNICODE) {
++ if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */
++ *bcc_ptr = 0;
++ bcc_ptr++;
++ }
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage);
++ bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */
++ bcc_ptr += 2; /* trailing null */
++ if (domain == NULL)
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr,
++ "CIFS_LINUX_DOM", 32, nls_codepage);
++ else
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
++ nls_codepage);
++ bcc_ptr += 2 * bytes_returned;
++ bcc_ptr += 2;
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
++ 32, nls_codepage);
++ bcc_ptr += 2 * bytes_returned;
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
++ nls_codepage);
++ bcc_ptr += 2 * bytes_returned;
++ bcc_ptr += 2;
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
++ 64, nls_codepage);
++ bcc_ptr += 2 * bytes_returned;
++ bcc_ptr += 2;
++ } else {
++ strncpy(bcc_ptr, user, 200);
++ bcc_ptr += strnlen(user, 200);
++ *bcc_ptr = 0;
++ bcc_ptr++;
++ if (domain == NULL) {
++ strcpy(bcc_ptr, "CIFS_LINUX_DOM");
++ bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
++ } else {
++ strncpy(bcc_ptr, domain, 64);
++ bcc_ptr += strnlen(domain, 64);
++ *bcc_ptr = 0;
++ bcc_ptr++;
++ }
++ strcpy(bcc_ptr, "Linux version ");
++ bcc_ptr += strlen("Linux version ");
++ strcpy(bcc_ptr, UTS_RELEASE);
++ bcc_ptr += strlen(UTS_RELEASE) + 1;
++ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
++ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
++ }
++ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
++ smb_buffer->smb_buf_length += BCC(smb_buffer);
++ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
++
++ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
++ &bytes_returned, 1);
++ if (rc) {
++/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
++ } else if ((smb_buffer_response->WordCount == 3)
++ || (smb_buffer_response->WordCount == 4)) {
++ pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
++ pSMBr->resp.SecurityBlobLength =
++ le16_to_cpu(pSMBr->resp.SecurityBlobLength);
++ if (pSMBr->resp.Action & GUEST_LOGIN)
++ cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
++ if (ses) {
++ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
++ cFYI(1, ("UID = %d ", ses->Suid));
++ bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */
++
++ /* BB Fix below to make endian neutral !! */
++
++ if ((pSMBr->resp.hdr.WordCount == 3)
++ || ((pSMBr->resp.hdr.WordCount == 4)
++ && (pSMBr->resp.SecurityBlobLength <
++ pSMBr->resp.ByteCount))) {
++ if (pSMBr->resp.hdr.WordCount == 4) {
++ bcc_ptr +=
++ pSMBr->resp.SecurityBlobLength;
++ cFYI(1,
++ ("Security Blob Length %d ",
++ pSMBr->resp.SecurityBlobLength));
++ }
++
++ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
++ if ((long) (bcc_ptr) % 2) {
++ remaining_words =
++ (BCC(smb_buffer_response)
++ - 1) / 2;
++ bcc_ptr++; /* Unicode strings must be word aligned */
++ } else {
++ remaining_words =
++ BCC
++ (smb_buffer_response) / 2;
++ }
++ len =
++ UniStrnlen((wchar_t *) bcc_ptr,
++ remaining_words - 1);
++/* We look for obvious messed up bcc or strings in response so we do not go off
++ the end since (at least) WIN2K and Windows XP have a major bug in not null
++ terminating last Unicode string in response */
++ ses->serverOS =
++ cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
++ cifs_strfromUCS_le(ses->serverOS,
++ (wchar_t *)
++ bcc_ptr, len,
++ nls_codepage);
++ bcc_ptr += 2 * (len + 1);
++ remaining_words -= len + 1;
++ ses->serverOS[2 * len] = 0;
++ ses->serverOS[1 + (2 * len)] = 0;
++ if (remaining_words > 0) {
++ len = UniStrnlen((wchar_t *)bcc_ptr,
++ remaining_words
++ - 1);
++ ses->serverNOS =
++ cifs_kcalloc(2 * (len + 1),
++ GFP_KERNEL);
++ cifs_strfromUCS_le(ses->serverNOS,
++ (wchar_t *)bcc_ptr,
++ len,
++ nls_codepage);
++ bcc_ptr += 2 * (len + 1);
++ ses->serverNOS[2 * len] = 0;
++ ses->serverNOS[1 + (2 * len)] = 0;
++ remaining_words -= len + 1;
++ if (remaining_words > 0) {
++ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
++ /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
++ ses->serverDomain = cifs_kcalloc(2*(len+1),GFP_KERNEL);
++ cifs_strfromUCS_le(ses->serverDomain,
++ (wchar_t *)bcc_ptr,
++ len,
++ nls_codepage);
++ bcc_ptr += 2*(len+1);
++ ses->serverDomain[2*len] = 0;
++ ses->serverDomain[1+(2*len)] = 0;
++ } /* else no more room so create dummy domain string */
++ else
++ ses->serverDomain =
++ cifs_kcalloc(2,GFP_KERNEL);
++ } else { /* no room so create dummy domain and NOS string */
++ ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
++ ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
++ }
++ } else { /* ASCII */
++
++ len = strnlen(bcc_ptr, 1024);
++ if (((long) bcc_ptr + len) - (long)
++ pByteArea(smb_buffer_response)
++ <= BCC(smb_buffer_response)) {
++ ses->serverOS = cifs_kcalloc(len + 1, GFP_KERNEL);
++ strncpy(ses->serverOS, bcc_ptr, len);
++
++ bcc_ptr += len;
++ bcc_ptr[0] = 0; /* null terminate the string */
++ bcc_ptr++;
++
++ len = strnlen(bcc_ptr, 1024);
++ ses->serverNOS = cifs_kcalloc(len + 1,GFP_KERNEL);
++ strncpy(ses->serverNOS, bcc_ptr, len);
++ bcc_ptr += len;
++ bcc_ptr[0] = 0;
++ bcc_ptr++;
++
++ len = strnlen(bcc_ptr, 1024);
++ ses->serverDomain = cifs_kcalloc(len + 1, GFP_KERNEL);
++ strncpy(ses->serverDomain, bcc_ptr, len);
++ bcc_ptr += len;
++ bcc_ptr[0] = 0;
++ bcc_ptr++;
++ } else
++ cFYI(1,
++ ("Variable field of length %d extends beyond end of smb ",
++ len));
++ }
++ } else {
++ cERROR(1,
++ (" Security Blob Length extends beyond end of SMB"));
++ }
++ } else {
++ cERROR(1, ("No session structure passed in."));
++ }
++ } else {
++ cERROR(1,
++ (" Invalid Word count %d: ",
++ smb_buffer_response->WordCount));
++ rc = -EIO;
++ }
++
++ if (smb_buffer)
++ cifs_buf_release(smb_buffer);
++
++ return rc;
++}
++
++static int
++CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
++ struct cifsSesInfo *ses, int * pNTLMv2_flag,
++ const struct nls_table *nls_codepage)
++{
++ struct smb_hdr *smb_buffer;
++ struct smb_hdr *smb_buffer_response;
++ SESSION_SETUP_ANDX *pSMB;
++ SESSION_SETUP_ANDX *pSMBr;
++ char *bcc_ptr;
++ char *domain = ses->domainName;
++ int rc = 0;
++ int remaining_words = 0;
++ int bytes_returned = 0;
++ int len;
++ int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE);
++ PNEGOTIATE_MESSAGE SecurityBlob;
++ PCHALLENGE_MESSAGE SecurityBlob2;
++
++ cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
++ *pNTLMv2_flag = FALSE;
++ smb_buffer = cifs_buf_get();
++ if (smb_buffer == 0) {
++ return -ENOMEM;
++ }
++ smb_buffer_response = smb_buffer;
++ pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
++ pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
++
++ /* send SMBsessionSetup here */
++ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
++ NULL /* no tCon exists yet */ , 12 /* wct */ );
++ pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
++ pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
++
++ pSMB->req.AndXCommand = 0xFF;
++ pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
++ pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
++
++ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
++ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
++
++ pSMB->req.Capabilities =
++ CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
++ CAP_EXTENDED_SECURITY;
++ if (ses->capabilities & CAP_UNICODE) {
++ smb_buffer->Flags2 |= SMBFLG2_UNICODE;
++ pSMB->req.Capabilities |= CAP_UNICODE;
++ }
++ if (ses->capabilities & CAP_STATUS32) {
++ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
++ pSMB->req.Capabilities |= CAP_STATUS32;
++ }
++ if (ses->capabilities & CAP_DFS) {
++ smb_buffer->Flags2 |= SMBFLG2_DFS;
++ pSMB->req.Capabilities |= CAP_DFS;
++ }
++ pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
++
++ bcc_ptr = (char *) &pSMB->req.SecurityBlob;
++ SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr;
++ strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
++ SecurityBlob->MessageType = NtLmNegotiate;
++ SecurityBlob->NegotiateFlags =
++ NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
++ NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
++ /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
++ if(sign_CIFS_PDUs)
++ SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
++ if(ntlmv2_support)
++ SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
++ /* setup pointers to domain name and workstation name */
++ bcc_ptr += SecurityBlobLength;
++
++ SecurityBlob->WorkstationName.Buffer = 0;
++ SecurityBlob->WorkstationName.Length = 0;
++ SecurityBlob->WorkstationName.MaximumLength = 0;
++
++ if (domain == NULL) {
++ SecurityBlob->DomainName.Buffer = 0;
++ SecurityBlob->DomainName.Length = 0;
++ SecurityBlob->DomainName.MaximumLength = 0;
++ } else {
++ SecurityBlob->NegotiateFlags |=
++ NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
++ strncpy(bcc_ptr, domain, 63);
++ SecurityBlob->DomainName.Length = strnlen(domain, 64);
++ SecurityBlob->DomainName.MaximumLength =
++ cpu_to_le16(SecurityBlob->DomainName.Length);
++ SecurityBlob->DomainName.Buffer =
++ cpu_to_le32((long) &SecurityBlob->
++ DomainString -
++ (long) &SecurityBlob->Signature);
++ bcc_ptr += SecurityBlob->DomainName.Length;
++ SecurityBlobLength += SecurityBlob->DomainName.Length;
++ SecurityBlob->DomainName.Length =
++ cpu_to_le16(SecurityBlob->DomainName.Length);
++ }
++ if (ses->capabilities & CAP_UNICODE) {
++ if ((long) bcc_ptr % 2) {
++ *bcc_ptr = 0;
++ bcc_ptr++;
++ }
++
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
++ 32, nls_codepage);
++ bcc_ptr += 2 * bytes_returned;
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
++ nls_codepage);
++ bcc_ptr += 2 * bytes_returned;
++ bcc_ptr += 2; /* null terminate Linux version */
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
++ 64, nls_codepage);
++ bcc_ptr += 2 * bytes_returned;
++ *(bcc_ptr + 1) = 0;
++ *(bcc_ptr + 2) = 0;
++ bcc_ptr += 2; /* null terminate network opsys string */
++ *(bcc_ptr + 1) = 0;
++ *(bcc_ptr + 2) = 0;
++ bcc_ptr += 2; /* null domain */
++ } else { /* ASCII */
++ strcpy(bcc_ptr, "Linux version ");
++ bcc_ptr += strlen("Linux version ");
++ strcpy(bcc_ptr, UTS_RELEASE);
++ bcc_ptr += strlen(UTS_RELEASE) + 1;
++ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
++ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
++ bcc_ptr++; /* empty domain field */
++ *bcc_ptr = 0;
++ }
++ SecurityBlob->NegotiateFlags =
++ cpu_to_le32(SecurityBlob->NegotiateFlags);
++ pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
++ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
++ smb_buffer->smb_buf_length += BCC(smb_buffer);
++ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
++
++ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
++ &bytes_returned, 1);
++
++ if (smb_buffer_response->Status.CifsError ==
++ (NT_STATUS_MORE_PROCESSING_REQUIRED))
++ rc = 0;
++
++ if (rc) {
++/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
++ } else if ((smb_buffer_response->WordCount == 3)
++ || (smb_buffer_response->WordCount == 4)) {
++ pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
++ pSMBr->resp.SecurityBlobLength =
++ le16_to_cpu(pSMBr->resp.SecurityBlobLength);
++ if (pSMBr->resp.Action & GUEST_LOGIN)
++ cFYI(1, (" Guest login"));
++ /* Do we want to set anything in SesInfo struct when guest login? */
++
++ bcc_ptr = pByteArea(smb_buffer_response);
++ /* response can have either 3 or 4 word count - Samba sends 3 */
++
++ SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
++ if (SecurityBlob2->MessageType != NtLmChallenge) {
++ cFYI(1,
++ ("Unexpected NTLMSSP message type received %d",
++ SecurityBlob2->MessageType));
++ } else if (ses) {
++ ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
++ cFYI(1, ("UID = %d ", ses->Suid));
++ if ((pSMBr->resp.hdr.WordCount == 3)
++ || ((pSMBr->resp.hdr.WordCount == 4)
++ && (pSMBr->resp.SecurityBlobLength <
++ pSMBr->resp.ByteCount))) {
++ if (pSMBr->resp.hdr.WordCount == 4) {
++ bcc_ptr +=
++ pSMBr->resp.SecurityBlobLength;
++ cFYI(1,
++ ("Security Blob Length %d ",
++ pSMBr->resp.SecurityBlobLength));
++ }
++
++ cFYI(1, ("NTLMSSP Challenge rcvd "));
++
++ memcpy(ses->server->cryptKey,
++ SecurityBlob2->Challenge,
++ CIFS_CRYPTO_KEY_SIZE);
++ if(SecurityBlob2->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLMV2)
++ *pNTLMv2_flag = TRUE;
++
++ if((SecurityBlob2->NegotiateFlags &
++ NTLMSSP_NEGOTIATE_ALWAYS_SIGN)
++ || (sign_CIFS_PDUs > 1))
++ ses->server->secMode |=
++ SECMODE_SIGN_REQUIRED;
++ if ((SecurityBlob2->NegotiateFlags &
++ NTLMSSP_NEGOTIATE_SIGN) && (sign_CIFS_PDUs))
++ ses->server->secMode |=
++ SECMODE_SIGN_ENABLED;
++
++ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
++ if ((long) (bcc_ptr) % 2) {
++ remaining_words =
++ (BCC(smb_buffer_response)
++ - 1) / 2;
++ bcc_ptr++; /* Unicode strings must be word aligned */
++ } else {
++ remaining_words =
++ BCC
++ (smb_buffer_response) / 2;
++ }
++ len =
++ UniStrnlen((wchar_t *) bcc_ptr,
++ remaining_words - 1);
++/* We look for obvious messed up bcc or strings in response so we do not go off
++ the end since (at least) WIN2K and Windows XP have a major bug in not null
++ terminating last Unicode string in response */
++ ses->serverOS =
++ cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
++ cifs_strfromUCS_le(ses->serverOS,
++ (wchar_t *)
++ bcc_ptr, len,
++ nls_codepage);
++ bcc_ptr += 2 * (len + 1);
++ remaining_words -= len + 1;
++ ses->serverOS[2 * len] = 0;
++ ses->serverOS[1 + (2 * len)] = 0;
++ if (remaining_words > 0) {
++ len = UniStrnlen((wchar_t *)
++ bcc_ptr,
++ remaining_words
++ - 1);
++ ses->serverNOS =
++ cifs_kcalloc(2 * (len + 1),
++ GFP_KERNEL);
++ cifs_strfromUCS_le(ses->
++ serverNOS,
++ (wchar_t *)
++ bcc_ptr,
++ len,
++ nls_codepage);
++ bcc_ptr += 2 * (len + 1);
++ ses->serverNOS[2 * len] = 0;
++ ses->serverNOS[1 +
++ (2 * len)] = 0;
++ remaining_words -= len + 1;
++ if (remaining_words > 0) {
++ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
++ /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
++ ses->serverDomain =
++ cifs_kcalloc(2 *
++ (len +
++ 1),
++ GFP_KERNEL);
++ cifs_strfromUCS_le
++ (ses->
++ serverDomain,
++ (wchar_t *)
++ bcc_ptr, len,
++ nls_codepage);
++ bcc_ptr +=
++ 2 * (len + 1);
++ ses->
++ serverDomain[2
++ * len]
++ = 0;
++ ses->
++ serverDomain[1
++ +
++ (2
++ *
++ len)]
++ = 0;
++ } /* else no more room so create dummy domain string */
++ else
++ ses->serverDomain =
++ cifs_kcalloc(2,
++ GFP_KERNEL);
++ } else { /* no room so create dummy domain and NOS string */
++ ses->serverDomain =
++ cifs_kcalloc(2, GFP_KERNEL);
++ ses->serverNOS =
++ cifs_kcalloc(2, GFP_KERNEL);
++ }
++ } else { /* ASCII */
++ len = strnlen(bcc_ptr, 1024);
++ if (((long) bcc_ptr + len) - (long)
++ pByteArea(smb_buffer_response)
++ <= BCC(smb_buffer_response)) {
++ ses->serverOS =
++ cifs_kcalloc(len + 1,
++ GFP_KERNEL);
++ strncpy(ses->serverOS,
++ bcc_ptr, len);
++
++ bcc_ptr += len;
++ bcc_ptr[0] = 0; /* null terminate string */
++ bcc_ptr++;
++
++ len = strnlen(bcc_ptr, 1024);
++ ses->serverNOS =
++ cifs_kcalloc(len + 1,
++ GFP_KERNEL);
++ strncpy(ses->serverNOS, bcc_ptr, len);
++ bcc_ptr += len;
++ bcc_ptr[0] = 0;
++ bcc_ptr++;
++
++ len = strnlen(bcc_ptr, 1024);
++ ses->serverDomain =
++ cifs_kcalloc(len + 1,
++ GFP_KERNEL);
++ strncpy(ses->serverDomain, bcc_ptr, len);
++ bcc_ptr += len;
++ bcc_ptr[0] = 0;
++ bcc_ptr++;
++ } else
++ cFYI(1,
++ ("Variable field of length %d extends beyond end of smb ",
++ len));
++ }
++ } else {
++ cERROR(1,
++ (" Security Blob Length extends beyond end of SMB"));
++ }
++ } else {
++ cERROR(1, ("No session structure passed in."));
++ }
++ } else {
++ cERROR(1,
++ (" Invalid Word count %d: ",
++ smb_buffer_response->WordCount));
++ rc = -EIO;
++ }
++
++ if (smb_buffer)
++ cifs_buf_release(smb_buffer);
++
++ return rc;
++}
++
++static int
++CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
++ char *ntlm_session_key, int ntlmv2_flag,
++ const struct nls_table *nls_codepage)
++{
++ struct smb_hdr *smb_buffer;
++ struct smb_hdr *smb_buffer_response;
++ SESSION_SETUP_ANDX *pSMB;
++ SESSION_SETUP_ANDX *pSMBr;
++ char *bcc_ptr;
++ char *user = ses->userName;
++ char *domain = ses->domainName;
++ int rc = 0;
++ int remaining_words = 0;
++ int bytes_returned = 0;
++ int len;
++ int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE);
++ PAUTHENTICATE_MESSAGE SecurityBlob;
++
++ cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
++
++ smb_buffer = cifs_buf_get();
++ if (smb_buffer == 0) {
++ return -ENOMEM;
++ }
++ smb_buffer_response = smb_buffer;
++ pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
++ pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response;
++
++ /* send SMBsessionSetup here */
++ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
++ NULL /* no tCon exists yet */ , 12 /* wct */ );
++ pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT);
++ pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
++ pSMB->req.AndXCommand = 0xFF;
++ pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
++ pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
++
++ pSMB->req.hdr.Uid = ses->Suid;
++
++ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
++ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
++
++ pSMB->req.Capabilities =
++ CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
++ CAP_EXTENDED_SECURITY;
++ if (ses->capabilities & CAP_UNICODE) {
++ smb_buffer->Flags2 |= SMBFLG2_UNICODE;
++ pSMB->req.Capabilities |= CAP_UNICODE;
++ }
++ if (ses->capabilities & CAP_STATUS32) {
++ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
++ pSMB->req.Capabilities |= CAP_STATUS32;
++ }
++ if (ses->capabilities & CAP_DFS) {
++ smb_buffer->Flags2 |= SMBFLG2_DFS;
++ pSMB->req.Capabilities |= CAP_DFS;
++ }
++ pSMB->req.Capabilities = cpu_to_le32(pSMB->req.Capabilities);
++
++ bcc_ptr = (char *) &pSMB->req.SecurityBlob;
++ SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr;
++ strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
++ SecurityBlob->MessageType = NtLmAuthenticate;
++ bcc_ptr += SecurityBlobLength;
++ SecurityBlob->NegotiateFlags =
++ NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
++ NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
++ 0x80000000 | NTLMSSP_NEGOTIATE_128;
++ if(sign_CIFS_PDUs)
++ SecurityBlob->NegotiateFlags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
++ if(ntlmv2_flag)
++ SecurityBlob->NegotiateFlags |= NTLMSSP_NEGOTIATE_NTLMV2;
++
++/* setup pointers to domain name and workstation name */
++
++ SecurityBlob->WorkstationName.Buffer = 0;
++ SecurityBlob->WorkstationName.Length = 0;
++ SecurityBlob->WorkstationName.MaximumLength = 0;
++ SecurityBlob->SessionKey.Length = 0;
++ SecurityBlob->SessionKey.MaximumLength = 0;
++ SecurityBlob->SessionKey.Buffer = 0;
++
++ SecurityBlob->LmChallengeResponse.Length = 0;
++ SecurityBlob->LmChallengeResponse.MaximumLength = 0;
++ SecurityBlob->LmChallengeResponse.Buffer = 0;
++
++ SecurityBlob->NtChallengeResponse.Length =
++ cpu_to_le16(CIFS_SESSION_KEY_SIZE);
++ SecurityBlob->NtChallengeResponse.MaximumLength =
++ cpu_to_le16(CIFS_SESSION_KEY_SIZE);
++ memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
++ SecurityBlob->NtChallengeResponse.Buffer =
++ cpu_to_le32(SecurityBlobLength);
++ SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
++ bcc_ptr += CIFS_SESSION_KEY_SIZE;
++
++ if (ses->capabilities & CAP_UNICODE) {
++ if (domain == NULL) {
++ SecurityBlob->DomainName.Buffer = 0;
++ SecurityBlob->DomainName.Length = 0;
++ SecurityBlob->DomainName.MaximumLength = 0;
++ } else {
++ SecurityBlob->DomainName.Length =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64,
++ nls_codepage);
++ SecurityBlob->DomainName.Length *= 2;
++ SecurityBlob->DomainName.MaximumLength =
++ cpu_to_le16(SecurityBlob->DomainName.Length);
++ SecurityBlob->DomainName.Buffer =
++ cpu_to_le32(SecurityBlobLength);
++ bcc_ptr += SecurityBlob->DomainName.Length;
++ SecurityBlobLength += SecurityBlob->DomainName.Length;
++ SecurityBlob->DomainName.Length =
++ cpu_to_le16(SecurityBlob->DomainName.Length);
++ }
++ if (user == NULL) {
++ SecurityBlob->UserName.Buffer = 0;
++ SecurityBlob->UserName.Length = 0;
++ SecurityBlob->UserName.MaximumLength = 0;
++ } else {
++ SecurityBlob->UserName.Length =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64,
++ nls_codepage);
++ SecurityBlob->UserName.Length *= 2;
++ SecurityBlob->UserName.MaximumLength =
++ cpu_to_le16(SecurityBlob->UserName.Length);
++ SecurityBlob->UserName.Buffer =
++ cpu_to_le32(SecurityBlobLength);
++ bcc_ptr += SecurityBlob->UserName.Length;
++ SecurityBlobLength += SecurityBlob->UserName.Length;
++ SecurityBlob->UserName.Length =
++ cpu_to_le16(SecurityBlob->UserName.Length);
++ }
++
++ /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage);
++ SecurityBlob->WorkstationName.Length *= 2;
++ SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
++ SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
++ bcc_ptr += SecurityBlob->WorkstationName.Length;
++ SecurityBlobLength += SecurityBlob->WorkstationName.Length;
++ SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
++
++ if ((long) bcc_ptr % 2) {
++ *bcc_ptr = 0;
++ bcc_ptr++;
++ }
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ",
++ 32, nls_codepage);
++ bcc_ptr += 2 * bytes_returned;
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
++ nls_codepage);
++ bcc_ptr += 2 * bytes_returned;
++ bcc_ptr += 2; /* null term version string */
++ bytes_returned =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS,
++ 64, nls_codepage);
++ bcc_ptr += 2 * bytes_returned;
++ *(bcc_ptr + 1) = 0;
++ *(bcc_ptr + 2) = 0;
++ bcc_ptr += 2; /* null terminate network opsys string */
++ *(bcc_ptr + 1) = 0;
++ *(bcc_ptr + 2) = 0;
++ bcc_ptr += 2; /* null domain */
++ } else { /* ASCII */
++ if (domain == NULL) {
++ SecurityBlob->DomainName.Buffer = 0;
++ SecurityBlob->DomainName.Length = 0;
++ SecurityBlob->DomainName.MaximumLength = 0;
++ } else {
++ SecurityBlob->NegotiateFlags |=
++ NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
++ strncpy(bcc_ptr, domain, 63);
++ SecurityBlob->DomainName.Length = strnlen(domain, 64);
++ SecurityBlob->DomainName.MaximumLength =
++ cpu_to_le16(SecurityBlob->DomainName.Length);
++ SecurityBlob->DomainName.Buffer =
++ cpu_to_le32(SecurityBlobLength);
++ bcc_ptr += SecurityBlob->DomainName.Length;
++ SecurityBlobLength += SecurityBlob->DomainName.Length;
++ SecurityBlob->DomainName.Length =
++ cpu_to_le16(SecurityBlob->DomainName.Length);
++ }
++ if (user == NULL) {
++ SecurityBlob->UserName.Buffer = 0;
++ SecurityBlob->UserName.Length = 0;
++ SecurityBlob->UserName.MaximumLength = 0;
++ } else {
++ strncpy(bcc_ptr, user, 63);
++ SecurityBlob->UserName.Length = strnlen(user, 64);
++ SecurityBlob->UserName.MaximumLength =
++ cpu_to_le16(SecurityBlob->UserName.Length);
++ SecurityBlob->UserName.Buffer =
++ cpu_to_le32(SecurityBlobLength);
++ bcc_ptr += SecurityBlob->UserName.Length;
++ SecurityBlobLength += SecurityBlob->UserName.Length;
++ SecurityBlob->UserName.Length =
++ cpu_to_le16(SecurityBlob->UserName.Length);
++ }
++ /* BB fill in our workstation name if known BB */
++
++ strcpy(bcc_ptr, "Linux version ");
++ bcc_ptr += strlen("Linux version ");
++ strcpy(bcc_ptr, UTS_RELEASE);
++ bcc_ptr += strlen(UTS_RELEASE) + 1;
++ strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
++ bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
++ bcc_ptr++; /* null domain */
++ *bcc_ptr = 0;
++ }
++ SecurityBlob->NegotiateFlags =
++ cpu_to_le32(SecurityBlob->NegotiateFlags);
++ pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
++ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
++ smb_buffer->smb_buf_length += BCC(smb_buffer);
++ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
++
++ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
++ &bytes_returned, 1);
++ if (rc) {
++/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */
++ } else if ((smb_buffer_response->WordCount == 3)
++ || (smb_buffer_response->WordCount == 4)) {
++ pSMBr->resp.Action = le16_to_cpu(pSMBr->resp.Action);
++ pSMBr->resp.SecurityBlobLength =
++ le16_to_cpu(pSMBr->resp.SecurityBlobLength);
++ if (pSMBr->resp.Action & GUEST_LOGIN)
++ cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
++/* if(SecurityBlob2->MessageType != NtLm??){
++ cFYI("Unexpected message type on auth response is %d "));
++ } */
++ if (ses) {
++ cFYI(1,
++ ("Does UID on challenge %d match auth response UID %d ",
++ ses->Suid, smb_buffer_response->Uid));
++ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
++ bcc_ptr = pByteArea(smb_buffer_response);
++ /* response can have either 3 or 4 word count - Samba sends 3 */
++ if ((pSMBr->resp.hdr.WordCount == 3)
++ || ((pSMBr->resp.hdr.WordCount == 4)
++ && (pSMBr->resp.SecurityBlobLength <
++ pSMBr->resp.ByteCount))) {
++ if (pSMBr->resp.hdr.WordCount == 4) {
++ bcc_ptr +=
++ pSMBr->resp.SecurityBlobLength;
++ cFYI(1,
++ ("Security Blob Length %d ",
++ pSMBr->resp.SecurityBlobLength));
++ }
++
++ cFYI(1,
++ ("NTLMSSP response to Authenticate "));
++
++ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
++ if ((long) (bcc_ptr) % 2) {
++ remaining_words =
++ (BCC(smb_buffer_response)
++ - 1) / 2;
++ bcc_ptr++; /* Unicode strings must be word aligned */
++ } else {
++ remaining_words = BCC(smb_buffer_response) / 2;
++ }
++ len =
++ UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1);
++/* We look for obvious messed up bcc or strings in response so we do not go off
++ the end since (at least) WIN2K and Windows XP have a major bug in not null
++ terminating last Unicode string in response */
++ ses->serverOS =
++ cifs_kcalloc(2 * (len + 1), GFP_KERNEL);
++ cifs_strfromUCS_le(ses->serverOS,
++ (wchar_t *)
++ bcc_ptr, len,
++ nls_codepage);
++ bcc_ptr += 2 * (len + 1);
++ remaining_words -= len + 1;
++ ses->serverOS[2 * len] = 0;
++ ses->serverOS[1 + (2 * len)] = 0;
++ if (remaining_words > 0) {
++ len = UniStrnlen((wchar_t *)
++ bcc_ptr,
++ remaining_words
++ - 1);
++ ses->serverNOS =
++ cifs_kcalloc(2 * (len + 1),
++ GFP_KERNEL);
++ cifs_strfromUCS_le(ses->
++ serverNOS,
++ (wchar_t *)
++ bcc_ptr,
++ len,
++ nls_codepage);
++ bcc_ptr += 2 * (len + 1);
++ ses->serverNOS[2 * len] = 0;
++ ses->serverNOS[1+(2*len)] = 0;
++ remaining_words -= len + 1;
++ if (remaining_words > 0) {
++ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
++ /* last string not always null terminated (e.g. for Windows XP & 2000) */
++ ses->serverDomain =
++ cifs_kcalloc(2 *
++ (len +
++ 1),
++ GFP_KERNEL);
++ cifs_strfromUCS_le
++ (ses->
++ serverDomain,
++ (wchar_t *)
++ bcc_ptr, len,
++ nls_codepage);
++ bcc_ptr +=
++ 2 * (len + 1);
++ ses->
++ serverDomain[2
++ * len]
++ = 0;
++ ses->
++ serverDomain[1
++ +
++ (2
++ *
++ len)]
++ = 0;
++ } /* else no more room so create dummy domain string */
++ else
++ ses->serverDomain = cifs_kcalloc(2,GFP_KERNEL);
++ } else { /* no room so create dummy domain and NOS string */
++ ses->serverDomain = cifs_kcalloc(2, GFP_KERNEL);
++ ses->serverNOS = cifs_kcalloc(2, GFP_KERNEL);
++ }
++ } else { /* ASCII */
++ len = strnlen(bcc_ptr, 1024);
++ if (((long) bcc_ptr + len) -
++ (long) pByteArea(smb_buffer_response)
++ <= BCC(smb_buffer_response)) {
++ ses->serverOS = cifs_kcalloc(len + 1,GFP_KERNEL);
++ strncpy(ses->serverOS,bcc_ptr, len);
++
++ bcc_ptr += len;
++ bcc_ptr[0] = 0; /* null terminate the string */
++ bcc_ptr++;
++
++ len = strnlen(bcc_ptr, 1024);
++ ses->serverNOS = cifs_kcalloc(len+1,GFP_KERNEL);
++ strncpy(ses->serverNOS, bcc_ptr, len);
++ bcc_ptr += len;
++ bcc_ptr[0] = 0;
++ bcc_ptr++;
++
++ len = strnlen(bcc_ptr, 1024);
++ ses->serverDomain = cifs_kcalloc(len+1,GFP_KERNEL);
++ strncpy(ses->serverDomain, bcc_ptr, len);
++ bcc_ptr += len;
++ bcc_ptr[0] = 0;
++ bcc_ptr++;
++ } else
++ cFYI(1,
++ ("Variable field of length %d extends beyond end of smb ",
++ len));
++ }
++ } else {
++ cERROR(1,
++ (" Security Blob Length extends beyond end of SMB"));
++ }
++ } else {
++ cERROR(1, ("No session structure passed in."));
++ }
++ } else {
++ cERROR(1,
++ (" Invalid Word count %d: ",
++ smb_buffer_response->WordCount));
++ rc = -EIO;
++ }
++
++ if (smb_buffer)
++ cifs_buf_release(smb_buffer);
++
++ return rc;
++}
++
++int
++CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
++ const char *tree, struct cifsTconInfo *tcon,
++ const struct nls_table *nls_codepage)
++{
++ struct smb_hdr *smb_buffer;
++ struct smb_hdr *smb_buffer_response;
++ TCONX_REQ *pSMB;
++ TCONX_RSP *pSMBr;
++ char *bcc_ptr;
++ int rc = 0;
++ int length;
++
++ if (ses == NULL)
++ return -EIO;
++
++ smb_buffer = cifs_buf_get();
++ if (smb_buffer == 0) {
++ return -ENOMEM;
++ }
++ smb_buffer_response = smb_buffer;
++
++ header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX,
++ NULL /*no tid */ , 4 /*wct */ );
++ smb_buffer->Uid = ses->Suid;
++ pSMB = (TCONX_REQ *) smb_buffer;
++ pSMBr = (TCONX_RSP *) smb_buffer_response;
++
++ pSMB->AndXCommand = 0xFF;
++ pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
++ pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
++ bcc_ptr = &(pSMB->Password[0]);
++ bcc_ptr++; /* skip password */
++
++ if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
++ smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
++
++ if (ses->capabilities & CAP_STATUS32) {
++ smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
++ }
++ if (ses->capabilities & CAP_DFS) {
++ smb_buffer->Flags2 |= SMBFLG2_DFS;
++ }
++ if (ses->capabilities & CAP_UNICODE) {
++ smb_buffer->Flags2 |= SMBFLG2_UNICODE;
++ length =
++ cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage);
++ bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */
++ bcc_ptr += 2; /* skip trailing null */
++ } else { /* ASCII */
++
++ strcpy(bcc_ptr, tree);
++ bcc_ptr += strlen(tree) + 1;
++ }
++ strcpy(bcc_ptr, "?????");
++ bcc_ptr += strlen("?????");
++ bcc_ptr += 1;
++ BCC(smb_buffer) = (long) bcc_ptr - (long) pByteArea(smb_buffer);
++ smb_buffer->smb_buf_length += BCC(smb_buffer);
++ BCC(smb_buffer) = cpu_to_le16(BCC(smb_buffer));
++
++ rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, 0);
++
++ /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */
++ /* above now done in SendReceive */
++ if ((rc == 0) && (tcon != NULL)) {
++ tcon->tidStatus = CifsGood;
++ tcon->tid = smb_buffer_response->Tid;
++ bcc_ptr = pByteArea(smb_buffer_response);
++ length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
++ /* skip service field (NB: this field is always ASCII) */
++ bcc_ptr += length + 1;
++ strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
++ if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
++ length = UniStrnlen((wchar_t *) bcc_ptr, 512);
++ if (((long) bcc_ptr + (2 * length)) -
++ (long) pByteArea(smb_buffer_response) <=
++ BCC(smb_buffer_response)) {
++ if(tcon->nativeFileSystem)
++ kfree(tcon->nativeFileSystem);
++ tcon->nativeFileSystem =
++ cifs_kcalloc(length + 2, GFP_KERNEL);
++ cifs_strfromUCS_le(tcon->nativeFileSystem,
++ (wchar_t *) bcc_ptr,
++ length, nls_codepage);
++ bcc_ptr += 2 * length;
++ bcc_ptr[0] = 0; /* null terminate the string */
++ bcc_ptr[1] = 0;
++ bcc_ptr += 2;
++ }
++ /* else do not bother copying these informational fields */
++ } else {
++ length = strnlen(bcc_ptr, 1024);
++ if (((long) bcc_ptr + length) -
++ (long) pByteArea(smb_buffer_response) <=
++ BCC(smb_buffer_response)) {
++ if(tcon->nativeFileSystem)
++ kfree(tcon->nativeFileSystem);
++ tcon->nativeFileSystem =
++ cifs_kcalloc(length + 1, GFP_KERNEL);
++ strncpy(tcon->nativeFileSystem, bcc_ptr,
++ length);
++ }
++ /* else do not bother copying these informational fields */
++ }
++ tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
++ cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
++ } else if ((rc == 0) && tcon == NULL) {
++ /* all we need to save for IPC$ connection */
++ ses->ipc_tid = smb_buffer_response->Tid;
++ }
++
++ if (smb_buffer)
++ cifs_buf_release(smb_buffer);
++ return rc;
++}
++
++int
++cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
++{
++ int rc = 0;
++ int xid;
++ struct cifsSesInfo *ses = NULL;
++ struct task_struct *cifsd_task;
++
++ xid = GetXid();
++
++ if (cifs_sb->tcon) {
++ ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
++ rc = CIFSSMBTDis(xid, cifs_sb->tcon);
++ if (rc == -EBUSY) {
++ FreeXid(xid);
++ return 0;
++ }
++ tconInfoFree(cifs_sb->tcon);
++ if ((ses) && (ses->server)) {
++ /* save off task so we do not refer to ses later */
++ cifsd_task = ses->server->tsk;
++ cFYI(1, ("About to do SMBLogoff "));
++ rc = CIFSSMBLogoff(xid, ses);
++ if (rc == -EBUSY) {
++ FreeXid(xid);
++ return 0;
++ } else if (rc == -ESHUTDOWN) {
++ cFYI(1,("Waking up socket by sending it signal"));
++ send_sig(SIGKILL,cifsd_task,1);
++ rc = 0;
++ } /* else - we have an smb session
++ left on this socket do not kill cifsd */
++ } else
++ cFYI(1, ("No session or bad tcon"));
++ }
++
++ cifs_sb->tcon = NULL;
++ if (ses) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(HZ / 2);
++ }
++ if (ses)
++ sesInfoFree(ses);
++
++ FreeXid(xid);
++ return rc; /* BB check if we should always return zero here */
++}
++
++int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
++ struct nls_table * nls_info)
++{
++ int rc = 0;
++ char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
++ int ntlmv2_flag = FALSE;
++
++ /* what if server changes its buffer size after dropping the session? */
++ if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
++ rc = CIFSSMBNegotiate(xid, pSesInfo);
++ if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
++ rc = CIFSSMBNegotiate(xid, pSesInfo);
++ if(rc == -EAGAIN)
++ rc = -EHOSTDOWN;
++ }
++ if(rc == 0) {
++ spin_lock(&GlobalMid_Lock);
++ if(pSesInfo->server->tcpStatus != CifsExiting)
++ pSesInfo->server->tcpStatus = CifsGood;
++ else
++ rc = -EHOSTDOWN;
++ spin_unlock(&GlobalMid_Lock);
++
++ }
++ }
++ if (!rc) {
++ pSesInfo->capabilities = pSesInfo->server->capabilities;
++ if(linuxExtEnabled == 0)
++ pSesInfo->capabilities &= (~CAP_UNIX);
++ pSesInfo->sequence_number = 0;
++ cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
++ pSesInfo->server->secMode,
++ pSesInfo->server->capabilities,
++ pSesInfo->server->timeZone));
++ if (extended_security
++ && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
++ && (pSesInfo->server->secType == NTLMSSP)) {
++ cFYI(1, ("New style sesssetup "));
++ rc = CIFSSpnegoSessSetup(xid, pSesInfo,
++ NULL /* security blob */,
++ 0 /* blob length */,
++ nls_info);
++ } else if (extended_security
++ && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
++ && (pSesInfo->server->secType == RawNTLMSSP)) {
++ cFYI(1, ("NTLMSSP sesssetup "));
++ rc = CIFSNTLMSSPNegotiateSessSetup(xid,
++ pSesInfo,
++ &ntlmv2_flag,
++ nls_info);
++ if (!rc) {
++ if(ntlmv2_flag) {
++ char * v2_response;
++ cFYI(1,("Can use more secure NTLM version 2 password hash"));
++ CalcNTLMv2_partial_mac_key(pSesInfo,
++ nls_info);
++ v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
++ if(v2_response) {
++ CalcNTLMv2_response(pSesInfo,v2_response);
++/* cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */
++ kfree(v2_response);
++ /* BB Put dummy sig in SessSetup PDU? */
++ } else
++ rc = -ENOMEM;
++
++ } else {
++ SMBNTencrypt(pSesInfo->password,
++ pSesInfo->server->cryptKey,
++ ntlm_session_key);
++
++ cifs_calculate_mac_key(pSesInfo->mac_signing_key,
++ ntlm_session_key,
++ pSesInfo->password);
++ }
++ /* for better security the weaker lanman hash not sent
++ in AuthSessSetup so we no longer calculate it */
++
++ rc = CIFSNTLMSSPAuthSessSetup(xid,
++ pSesInfo,
++ ntlm_session_key,
++ ntlmv2_flag,
++ nls_info);
++ }
++ } else { /* old style NTLM 0.12 session setup */
++ SMBNTencrypt(pSesInfo->password,
++ pSesInfo->server->cryptKey,
++ ntlm_session_key);
++
++ cifs_calculate_mac_key(pSesInfo->mac_signing_key,
++ ntlm_session_key, pSesInfo->password);
++ rc = CIFSSessSetup(xid, pSesInfo,
++ ntlm_session_key, nls_info);
++ }
++ if (rc) {
++ cERROR(1,("Send error in SessSetup = %d",rc));
++ } else {
++ cFYI(1,("CIFS Session Established successfully"));
++ pSesInfo->status = CifsGood;
++ }
++ }
++ return rc;
++}
++
+diff -urN linux-2.4.29.old/fs/cifs/dir.c linux-2.4.29/fs/cifs/dir.c
+--- linux-2.4.29.old/fs/cifs/dir.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/dir.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,425 @@
++/*
++ * fs/cifs/dir.c
++ *
++ * vfs operations that deal with dentries
++ *
++ * Copyright (C) International Business Machines Corp., 2002,2003
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#include <linux/fs.h>
++#include <linux/stat.h>
++#include <linux/slab.h>
++#include "cifsfs.h"
++#include "cifspdu.h"
++#include "cifsglob.h"
++#include "cifsproto.h"
++#include "cifs_debug.h"
++#include "cifs_fs_sb.h"
++
++void
++renew_parental_timestamps(struct dentry *direntry)
++{
++ /* BB check if there is a way to get the kernel to do this or if we really need this */
++ do {
++ direntry->d_time = jiffies;
++ direntry = direntry->d_parent;
++ } while (!IS_ROOT(direntry));
++}
++
++/* Note: caller must free return buffer */
++char *
++build_path_from_dentry(struct dentry *direntry)
++{
++ struct dentry *temp;
++ int namelen = 0;
++ char *full_path;
++
++ if(direntry == NULL)
++ return NULL; /* not much we can do if dentry is freed and
++ we need to reopen the file after it was closed implicitly
++ when the server crashed */
++
++cifs_bp_rename_retry:
++ for (temp = direntry; !IS_ROOT(temp);) {
++ namelen += (1 + temp->d_name.len);
++ temp = temp->d_parent;
++ if(temp == NULL) {
++ cERROR(1,("corrupt dentry"));
++ return NULL;
++ }
++ }
++
++ full_path = kmalloc(namelen+1, GFP_KERNEL);
++ if(full_path == NULL)
++ return full_path;
++ full_path[namelen] = 0; /* trailing null */
++
++ for (temp = direntry; !IS_ROOT(temp);) {
++ namelen -= 1 + temp->d_name.len;
++ if (namelen < 0) {
++ break;
++ } else {
++ full_path[namelen] = '\\';
++ strncpy(full_path + namelen + 1, temp->d_name.name,
++ temp->d_name.len);
++ cFYI(0, (" name: %s ", full_path + namelen));
++ }
++ temp = temp->d_parent;
++ if(temp == NULL) {
++ cERROR(1,("corrupt dentry"));
++ kfree(full_path);
++ return NULL;
++ }
++ }
++ if (namelen != 0) {
++ cERROR(1,
++ ("We did not end path lookup where we expected namelen is %d",
++ namelen));
++ /* presumably this is only possible if we were racing with a rename
++ of one of the parent directories (we can not lock the dentries
++ above us to prevent this, but retrying should be harmless) */
++ kfree(full_path);
++ namelen = 0;
++ goto cifs_bp_rename_retry;
++ }
++
++ return full_path;
++}
++
++/* Note: caller must free return buffer */
++char *
++build_wildcard_path_from_dentry(struct dentry *direntry)
++{
++ struct dentry *temp;
++ int namelen = 0;
++ char *full_path;
++
++ if(direntry == NULL)
++ return NULL; /* not much we can do if dentry is freed and
++ we need to reopen the file after it was closed implicitly
++ when the server crashed */
++
++cifs_bwp_rename_retry:
++ for (temp = direntry; !IS_ROOT(temp);) {
++ namelen += (1 + temp->d_name.len);
++ temp = temp->d_parent;
++ if(temp == NULL) {
++ cERROR(1,("corrupt dentry"));
++ return NULL;
++ }
++ }
++
++ full_path = kmalloc(namelen+3, GFP_KERNEL);
++ if(full_path == NULL)
++ return full_path;
++
++ full_path[namelen] = '\\';
++ full_path[namelen+1] = '*';
++ full_path[namelen+2] = 0; /* trailing null */
++
++ for (temp = direntry; !IS_ROOT(temp);) {
++ namelen -= 1 + temp->d_name.len;
++ if (namelen < 0) {
++ break;
++ } else {
++ full_path[namelen] = '\\';
++ strncpy(full_path + namelen + 1, temp->d_name.name,
++ temp->d_name.len);
++ cFYI(0, (" name: %s ", full_path + namelen));
++ }
++ temp = temp->d_parent;
++ if(temp == NULL) {
++ cERROR(1,("corrupt dentry"));
++ kfree(full_path);
++ return NULL;
++ }
++ }
++ if (namelen != 0) {
++ cERROR(1,
++ ("We did not end path lookup where we expected namelen is %d",
++ namelen));
++ /* presumably this is only possible if we were racing with a rename
++ of one of the parent directories (we can not lock the dentries
++ above us to prevent this, but retrying should be harmless) */
++ kfree(full_path);
++ namelen = 0;
++ goto cifs_bwp_rename_retry;
++ }
++
++ return full_path;
++}
++
++/* Inode operations in similar order to how they appear in the Linux file fs.h */
++
++int
++cifs_create(struct inode *inode, struct dentry *direntry, int mode)
++{
++ int rc = -ENOENT;
++ int xid;
++ int oplock = 0; /* no sense requested oplock if we are just going to
++ immediately close the file */
++ __u16 fileHandle;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ char *full_path = NULL;
++ FILE_ALL_INFO * buf = NULL;
++ struct inode *newinode = NULL;
++
++ xid = GetXid();
++
++ cifs_sb = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb->tcon;
++
++ down(&direntry->d_sb->s_vfs_rename_sem);
++ full_path = build_path_from_dentry(direntry);
++ up(&direntry->d_sb->s_vfs_rename_sem);
++ if(full_path == NULL) {
++ FreeXid(xid);
++ return -ENOMEM;
++ }
++
++ /* BB add processing to set equivalent of mode - e.g. via CreateX with ACLs */
++
++ buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
++ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OVERWRITE_IF,
++ GENERIC_WRITE, CREATE_NOT_DIR,
++ &fileHandle, &oplock, buf, cifs_sb->local_nls);
++ if (rc) {
++ cFYI(1, ("cifs_create returned 0x%x ", rc));
++ } else {
++ /* BB for case of overwriting existing file can we use the inode that was
++ passed in rather than creating new one?? */
++ if (pTcon->ses->capabilities & CAP_UNIX)
++ rc = cifs_get_inode_info_unix(&newinode, full_path,
++ inode->i_sb,xid);
++ else
++ rc = cifs_get_inode_info(&newinode, full_path,
++ buf, inode->i_sb,xid);
++
++ if (rc != 0) {
++ cFYI(1,("Create worked but get_inode_info failed with rc = %d",
++ rc));
++ } else {
++ direntry->d_op = &cifs_dentry_ops;
++ d_instantiate(direntry, newinode);
++ }
++ CIFSSMBClose(xid, pTcon, fileHandle);
++
++ if(newinode) {
++ newinode->i_mode = mode;
++ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
++ CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode,
++ (__u64)-1,
++ (__u64)-1,
++ 0 /* dev */,
++ cifs_sb->local_nls);
++ else { /* BB implement via Windows security descriptors */
++ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
++ /* in the meantime could set r/o dos attribute when perms are eg:
++ mode & 0222 == 0 */
++ }
++ }
++ }
++
++ if (buf)
++ kfree(buf);
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++
++ return rc;
++}
++
++int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, int device_number)
++{
++ int rc = -EPERM;
++ int xid;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ char *full_path = NULL;
++ struct inode * newinode = NULL;
++
++ xid = GetXid();
++
++ cifs_sb = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb->tcon;
++
++ down(&direntry->d_sb->s_vfs_rename_sem);
++ full_path = build_path_from_dentry(direntry);
++ up(&direntry->d_sb->s_vfs_rename_sem);
++ if(full_path == NULL)
++ rc = -ENOMEM;
++
++ if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) {
++ rc = CIFSSMBUnixSetPerms(xid, pTcon,
++ full_path, mode, current->euid, current->egid,
++ device_number, cifs_sb->local_nls);
++ if(!rc) {
++ rc = cifs_get_inode_info_unix(&newinode, full_path,
++ inode->i_sb,xid);
++ direntry->d_op = &cifs_dentry_ops;
++ if(rc == 0)
++ d_instantiate(direntry, newinode);
++ }
++ }
++
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++
++ return rc;
++}
++
++
++struct dentry *
++cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry)
++{
++ int xid;
++ int rc = 0; /* to get around spurious gcc warning, set to zero here */
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ struct inode *newInode = NULL;
++ char *full_path = NULL;
++
++ xid = GetXid();
++
++ cFYI(1,
++ (" parent inode = 0x%p name is: %s and dentry = 0x%p",
++ parent_dir_inode, direntry->d_name.name, direntry));
++
++ /* BB Add check of incoming data - e.g. frame not longer than maximum SMB - let server check the namelen BB */
++
++ /* check whether path exists */
++
++ cifs_sb = CIFS_SB(parent_dir_inode->i_sb);
++ pTcon = cifs_sb->tcon;
++
++ /* can not grab the rename sem here since it would
++ deadlock in the cases (beginning of sys_rename itself)
++ in which we already have the sb rename sem */
++ full_path = build_path_from_dentry(direntry);
++ if(full_path == NULL) {
++ FreeXid(xid);
++ return ERR_PTR(-ENOMEM);
++ }
++
++ if (direntry->d_inode != NULL) {
++ cFYI(1, (" non-NULL inode in lookup"));
++ } else {
++ cFYI(1, (" NULL inode in lookup"));
++ }
++ cFYI(1,
++ (" Full path: %s inode = 0x%p", full_path, direntry->d_inode));
++
++ if (pTcon->ses->capabilities & CAP_UNIX)
++ rc = cifs_get_inode_info_unix(&newInode, full_path,
++ parent_dir_inode->i_sb,xid);
++ else
++ rc = cifs_get_inode_info(&newInode, full_path, NULL,
++ parent_dir_inode->i_sb,xid);
++
++ if ((rc == 0) && (newInode != NULL)) {
++ direntry->d_op = &cifs_dentry_ops;
++ d_add(direntry, newInode);
++
++ /* since paths are not looked up by component - the parent directories are presumed to be good here */
++ renew_parental_timestamps(direntry);
++
++ } else if (rc == -ENOENT) {
++ rc = 0;
++ d_add(direntry, NULL);
++ } else {
++ cERROR(1,("Error 0x%x or on cifs_get_inode_info in lookup",rc));
++ /* BB special case check for Access Denied - watch security
++ exposure of returning dir info implicitly via different rc
++ if file exists or not but no access BB */
++ }
++
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return ERR_PTR(rc);
++}
++
++int
++cifs_dir_open(struct inode *inode, struct file *file)
++{ /* NB: currently unused since searches are opened in readdir */
++ int rc = 0;
++ int xid;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ char *full_path = NULL;
++
++ xid = GetXid();
++
++ cifs_sb = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb->tcon;
++
++ if(file->f_dentry) {
++ down(&file->f_dentry->d_sb->s_vfs_rename_sem);
++ full_path = build_wildcard_path_from_dentry(file->f_dentry);
++ up(&file->f_dentry->d_sb->s_vfs_rename_sem);
++ } else {
++ FreeXid(xid);
++ return -EIO;
++ }
++
++ cFYI(1, ("inode = 0x%p and full path is %s", inode, full_path));
++
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return rc;
++}
++
++static int
++cifs_d_revalidate(struct dentry *direntry, int flags)
++{
++ int isValid = 1;
++
++/* lock_kernel(); *//* surely we do not want to lock the kernel for a whole network round trip which could take seconds */
++
++ if (direntry->d_inode) {
++ if (cifs_revalidate(direntry)) {
++ /* unlock_kernel(); */
++ return 0;
++ }
++ } else {
++ cFYI(1,
++ ("In cifs_d_revalidate with no inode but name = %s and dentry 0x%p",
++ direntry->d_name.name, direntry));
++ }
++
++/* unlock_kernel(); */
++
++ return isValid;
++}
++
++/* static int cifs_d_delete(struct dentry *direntry)
++{
++ int rc = 0;
++
++ cFYI(1, ("In cifs d_delete, name = %s", direntry->d_name.name));
++
++ return rc;
++} */
++
++struct dentry_operations cifs_dentry_ops = {
++ .d_revalidate = cifs_d_revalidate,
++/* d_delete: cifs_d_delete, *//* not needed except for debugging */
++ /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */
++};
+diff -urN linux-2.4.29.old/fs/cifs/file.c linux-2.4.29/fs/cifs/file.c
+--- linux-2.4.29.old/fs/cifs/file.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/file.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,2185 @@
++/*
++ * fs/cifs/file.c
++ *
++ * vfs operations that deal with files
++ *
++ * Copyright (C) International Business Machines Corp., 2002,2003
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#include <linux/fs.h>
++#include <linux/stat.h>
++#include <linux/fcntl.h>
++#include <linux/version.h>
++#include <linux/pagemap.h>
++#include <linux/smp_lock.h>
++#include <linux/list.h>
++#include <asm/div64.h>
++#include <linux/mm.h>
++#include <linux/types.h>
++#include "cifsfs.h"
++#include "cifspdu.h"
++#include "cifsglob.h"
++#include "cifsproto.h"
++#include "cifs_unicode.h"
++#include "cifs_debug.h"
++#include "cifs_fs_sb.h"
++
++int
++cifs_open(struct inode *inode, struct file *file)
++{
++ int rc = -EACCES;
++ int xid, oplock;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ struct cifsFileInfo *pCifsFile;
++ struct cifsInodeInfo *pCifsInode;
++ char *full_path = NULL;
++ int desiredAccess = 0x20197;
++ int disposition;
++ __u16 netfid;
++ FILE_ALL_INFO * buf = NULL;
++ time_t temp;
++
++ xid = GetXid();
++
++ cifs_sb = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb->tcon;
++
++ down(&inode->i_sb->s_vfs_rename_sem);
++ full_path = build_path_from_dentry(file->f_dentry);
++ up(&inode->i_sb->s_vfs_rename_sem);
++ if(full_path == NULL) {
++ FreeXid(xid);
++ return -ENOMEM;
++ }
++
++ cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
++ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
++ desiredAccess = GENERIC_READ;
++ else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
++ desiredAccess = GENERIC_WRITE;
++ else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
++ /* GENERIC_ALL is too much permission to request */
++ /* can cause unnecessary access denied on create */
++ /* desiredAccess = GENERIC_ALL; */
++ desiredAccess = GENERIC_READ | GENERIC_WRITE;
++ }
++
++/*********************************************************************
++ * open flag mapping table:
++ *
++ * POSIX Flag CIFS Disposition
++ * ---------- ----------------
++ * O_CREAT FILE_OPEN_IF
++ * O_CREAT | O_EXCL FILE_CREATE
++ * O_CREAT | O_TRUNC FILE_OVERWRITE_IF
++ * O_TRUNC FILE_OVERWRITE
++ * none of the above FILE_OPEN
++ *
++ * Note that there is not a direct match between disposition
++ * FILE_SUPERSEDE (ie create whether or not file exists although
++ * O_CREAT | O_TRUNC is similar but truncates the existing
++ * file rather than creating a new file as FILE_SUPERSEDE does
++ * (which uses the attributes / metadata passed in on open call)
++ *?
++ *? O_SYNC is a reasonable match to CIFS writethrough flag
++ *? and the read write flags match reasonably. O_LARGEFILE
++ *? is irrelevant because largefile support is always used
++ *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
++ * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation
++ *********************************************************************/
++
++ /* For 2.4 case, file was already checked for existence
++ before create by vfs lookup and created in create
++ entry point, we are now just opening the newly
++ created file with the right desiredAccess flags */
++
++ if((file->f_flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
++ disposition = FILE_OPEN_IF;
++ else if((file->f_flags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
++ disposition = FILE_OVERWRITE_IF;
++ else if((file->f_flags & O_CREAT) == O_CREAT)
++ disposition = FILE_OPEN_IF;
++ else
++ disposition = FILE_OPEN;
++
++ if (oplockEnabled)
++ oplock = REQ_OPLOCK;
++ else
++ oplock = FALSE;
++
++ /* BB pass O_SYNC flag through on file attributes .. BB */
++
++ /* Also refresh inode by passing in file_info buf returned by SMBOpen
++ and calling get_inode_info with returned buf (at least
++ helps non-Unix server case */
++
++ /* BB we can not do this if this is the second open of a file
++ and the first handle has writebehind data, we might be
++ able to simply do a filemap_fdatawrite/filemap_fdatawait first */
++ buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
++ if(buf==0) {
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return -ENOMEM;
++ }
++ rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
++ CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls);
++ if (rc) {
++ cFYI(1, ("cifs_open returned 0x%x ", rc));
++ cFYI(1, ("oplock: %d ", oplock));
++ } else {
++ file->private_data =
++ kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
++ if (file->private_data) {
++ memset(file->private_data, 0, sizeof(struct cifsFileInfo));
++ pCifsFile = (struct cifsFileInfo *) file->private_data;
++ pCifsFile->netfid = netfid;
++ pCifsFile->pid = current->pid;
++ init_MUTEX(&pCifsFile->fh_sem);
++ pCifsFile->pfile = file; /* needed for writepage */
++ pCifsFile->pInode = inode;
++ pCifsFile->invalidHandle = FALSE;
++ pCifsFile->closePend = FALSE;
++ write_lock(&GlobalSMBSeslock);
++ spin_lock(&files_lock);
++ list_add(&pCifsFile->tlist,&pTcon->openFileList);
++ pCifsInode = CIFS_I(file->f_dentry->d_inode);
++ if(pCifsInode) {
++ /* want handles we can use to read with first */
++ /* in the list so we do not have to walk the */
++ /* list to search for one in prepare_write */
++ if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
++ list_add_tail(&pCifsFile->flist,&pCifsInode->openFileList);
++ } else {
++ list_add(&pCifsFile->flist,&pCifsInode->openFileList);
++ }
++ spin_unlock(&files_lock);
++ write_unlock(&GlobalSMBSeslock);
++ if(pCifsInode->clientCanCacheRead) {
++ /* we have the inode open somewhere else
++ no need to discard cache data */
++ } else {
++ if(buf) {
++ /* BB need same check in cifs_create too? */
++
++ /* if not oplocked, invalidate inode pages if mtime
++ or file size changed */
++ temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime));
++ if((file->f_dentry->d_inode->i_mtime == temp) &&
++ (file->f_dentry->d_inode->i_size == (loff_t)le64_to_cpu(buf->EndOfFile))) {
++ cFYI(1,("inode unchanged on server"));
++ } else {
++ if(file->f_dentry->d_inode->i_mapping) {
++ /* BB no need to lock inode until after invalidate*/
++ /* since namei code should already have it locked?*/
++ filemap_fdatasync(file->f_dentry->d_inode->i_mapping);
++ }
++ cFYI(1,("invalidating remote inode since open detected it changed"));
++ invalidate_inode_pages(file->f_dentry->d_inode);
++ }
++ }
++ }
++ if (pTcon->ses->capabilities & CAP_UNIX)
++ rc = cifs_get_inode_info_unix(&file->f_dentry->d_inode,
++ full_path, inode->i_sb,xid);
++ else
++ rc = cifs_get_inode_info(&file->f_dentry->d_inode,
++ full_path, buf, inode->i_sb,xid);
++
++ if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
++ pCifsInode->clientCanCacheAll = TRUE;
++ pCifsInode->clientCanCacheRead = TRUE;
++ cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode));
++ } else if((oplock & 0xF) == OPLOCK_READ)
++ pCifsInode->clientCanCacheRead = TRUE;
++ } else {
++ spin_unlock(&files_lock);
++ write_unlock(&GlobalSMBSeslock);
++ }
++ if(oplock & CIFS_CREATE_ACTION) {
++ /* time to set mode which we can not set earlier due
++ to problems creating new read-only files */
++ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
++ CIFSSMBUnixSetPerms(xid, pTcon, full_path, inode->i_mode,
++ (__u64)-1,
++ (__u64)-1,
++ 0 /* dev */,
++ cifs_sb->local_nls);
++ else {/* BB implement via Windows security descriptors */
++ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
++ /* in the meantime could set r/o dos attribute when perms are eg:
++ mode & 0222 == 0 */
++ }
++ }
++ }
++ }
++
++ if (buf)
++ kfree(buf);
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return rc;
++}
++
++/* Try to reaquire byte range locks that were released when session */
++/* to server was lost */
++static int cifs_relock_file(struct cifsFileInfo * cifsFile)
++{
++ int rc = 0;
++
++/* BB list all locks open on this file and relock */
++
++ return rc;
++}
++
++static int cifs_reopen_file(struct inode *inode, struct file *file, int can_flush)
++{
++ int rc = -EACCES;
++ int xid, oplock;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ struct cifsFileInfo *pCifsFile;
++ struct cifsInodeInfo *pCifsInode;
++ char *full_path = NULL;
++ int desiredAccess = 0x20197;
++ int disposition = FILE_OPEN;
++ __u16 netfid;
++
++ if(inode == NULL)
++ return -EBADF;
++ if (file->private_data) {
++ pCifsFile = (struct cifsFileInfo *) file->private_data;
++ } else
++ return -EBADF;
++
++ xid = GetXid();
++ down(&pCifsFile->fh_sem);
++ if(pCifsFile->invalidHandle == FALSE) {
++ up(&pCifsFile->fh_sem);
++ FreeXid(xid);
++ return 0;
++ }
++
++ if(file->f_dentry == NULL) {
++ up(&pCifsFile->fh_sem);
++ cFYI(1,("failed file reopen, no valid name if dentry freed"));
++ FreeXid(xid);
++ return -EBADF;
++ }
++ cifs_sb = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb->tcon;
++/* can not grab rename sem here because various ops, including
++those that already have the rename sem can end up causing writepage
++to get called and if the server was down that means we end up here,
++and we can never tell if the caller already has the rename_sem */
++ full_path = build_path_from_dentry(file->f_dentry);
++ if(full_path == NULL) {
++ up(&pCifsFile->fh_sem);
++ FreeXid(xid);
++ return -ENOMEM;
++ }
++
++ cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
++ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
++ desiredAccess = GENERIC_READ;
++ else if ((file->f_flags & O_ACCMODE) == O_WRONLY)
++ desiredAccess = GENERIC_WRITE;
++ else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
++ /* GENERIC_ALL is too much permission to request */
++ /* can cause unnecessary access denied on create */
++ /* desiredAccess = GENERIC_ALL; */
++ desiredAccess = GENERIC_READ | GENERIC_WRITE;
++ }
++
++ if (oplockEnabled)
++ oplock = REQ_OPLOCK;
++ else
++ oplock = FALSE;
++
++
++ /* Can not refresh inode by passing in file_info buf to be returned
++ by SMBOpen and then calling get_inode_info with returned buf
++ since file might have write behind data that needs to be flushed
++ and server version of file size can be stale. If we
++ knew for sure that inode was not dirty locally we could do this */
++
++/* buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
++ if(buf==0) {
++ up(&pCifsFile->fh_sem);
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return -ENOMEM;
++ }*/
++ rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
++ CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls);
++ if (rc) {
++ up(&pCifsFile->fh_sem);
++ cFYI(1, ("cifs_open returned 0x%x ", rc));
++ cFYI(1, ("oplock: %d ", oplock));
++ } else {
++ pCifsFile->netfid = netfid;
++ pCifsFile->invalidHandle = FALSE;
++ up(&pCifsFile->fh_sem);
++ pCifsInode = CIFS_I(inode);
++ if(pCifsInode) {
++ if(can_flush) {
++ filemap_fdatasync(inode->i_mapping);
++ filemap_fdatawait(inode->i_mapping);
++ /* temporarily disable caching while we
++ go to server to get inode info */
++ pCifsInode->clientCanCacheAll = FALSE;
++ pCifsInode->clientCanCacheRead = FALSE;
++ if (pTcon->ses->capabilities & CAP_UNIX)
++ rc = cifs_get_inode_info_unix(&inode,
++ full_path, inode->i_sb,xid);
++ else
++ rc = cifs_get_inode_info(&inode,
++ full_path, NULL, inode->i_sb,xid);
++ } /* else we are writing out data to server already
++ and could deadlock if we tried to flush data, and
++ since we do not know if we have data that would
++ invalidate the current end of file on the server
++ we can not go to the server to get the new
++ inod info */
++ if((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
++ pCifsInode->clientCanCacheAll = TRUE;
++ pCifsInode->clientCanCacheRead = TRUE;
++ cFYI(1,("Exclusive Oplock granted on inode %p",file->f_dentry->d_inode));
++ } else if((oplock & 0xF) == OPLOCK_READ) {
++ pCifsInode->clientCanCacheRead = TRUE;
++ pCifsInode->clientCanCacheAll = FALSE;
++ } else {
++ pCifsInode->clientCanCacheRead = FALSE;
++ pCifsInode->clientCanCacheAll = FALSE;
++ }
++ cifs_relock_file(pCifsFile);
++ }
++ }
++
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return rc;
++}
++
++int
++cifs_close(struct inode *inode, struct file *file)
++{
++ int rc = 0;
++ int xid;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ struct cifsFileInfo *pSMBFile =
++ (struct cifsFileInfo *) file->private_data;
++
++ xid = GetXid();
++
++ cifs_sb = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb->tcon;
++ if (pSMBFile) {
++ pSMBFile->closePend = TRUE;
++ spin_lock(&files_lock);
++ if(pTcon) {
++ /* no sense reconnecting to close a file that is
++ already closed */
++ if (pTcon->tidStatus != CifsNeedReconnect) {
++ spin_unlock(&files_lock);
++ rc = CIFSSMBClose(xid,pTcon,pSMBFile->netfid);
++ spin_lock(&files_lock);
++ }
++ }
++ list_del(&pSMBFile->flist);
++ list_del(&pSMBFile->tlist);
++ spin_unlock(&files_lock);
++ if(pSMBFile->search_resume_name)
++ kfree(pSMBFile->search_resume_name);
++ kfree(file->private_data);
++ file->private_data = NULL;
++ } else
++ rc = -EBADF;
++
++ if(list_empty(&(CIFS_I(inode)->openFileList))) {
++ cFYI(1,("closing last open instance for inode %p",inode));
++ /* if the file is not open we do not know if we can cache
++ info on this inode, much less write behind and read ahead */
++ CIFS_I(inode)->clientCanCacheRead = FALSE;
++ CIFS_I(inode)->clientCanCacheAll = FALSE;
++ }
++ if((rc ==0) && CIFS_I(inode)->write_behind_rc)
++ rc = CIFS_I(inode)->write_behind_rc;
++ FreeXid(xid);
++ return rc;
++}
++
++int
++cifs_closedir(struct inode *inode, struct file *file)
++{
++ int rc = 0;
++ int xid;
++ struct cifsFileInfo *pSMBFileStruct =
++ (struct cifsFileInfo *) file->private_data;
++
++ cFYI(1, ("Closedir inode = 0x%p with ", inode));
++
++ xid = GetXid();
++
++ if (pSMBFileStruct) {
++ cFYI(1, ("Freeing private data in close dir"));
++ kfree(file->private_data);
++ file->private_data = NULL;
++ }
++ FreeXid(xid);
++ return rc;
++}
++
++int
++cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
++{
++ int rc, xid;
++ __u32 lockType = LOCKING_ANDX_LARGE_FILES;
++ __u32 numLock = 0;
++ __u32 numUnlock = 0;
++ __u64 length;
++ int wait_flag = FALSE;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ length = 1 + pfLock->fl_end - pfLock->fl_start;
++
++ rc = -EACCES;
++
++ xid = GetXid();
++
++ cFYI(1,
++ ("Lock parm: 0x%x flockflags: 0x%x flocktype: 0x%x start: %lld end: %lld",
++ cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
++ pfLock->fl_end));
++
++ if (pfLock->fl_flags & FL_POSIX)
++ cFYI(1, ("Posix "));
++ if (pfLock->fl_flags & FL_FLOCK)
++ cFYI(1, ("Flock "));
++/* if (pfLock->fl_flags & FL_SLEEP) {
++ cFYI(1, ("Blocking lock "));
++ wait_flag = TRUE;
++ } */
++ if (pfLock->fl_flags & FL_ACCESS)
++ cFYI(1, ("Process suspended by mandatory locking - not implemented yet "));
++ if (pfLock->fl_flags & FL_LEASE)
++ cFYI(1, ("Lease on file - not implemented yet"));
++ if (pfLock->fl_flags & (~(FL_POSIX | FL_FLOCK | FL_ACCESS | FL_LEASE)))
++ cFYI(1, ("Unknown lock flags 0x%x",pfLock->fl_flags));
++
++ if (pfLock->fl_type == F_WRLCK) {
++ cFYI(1, ("F_WRLCK "));
++ numLock = 1;
++ } else if (pfLock->fl_type == F_UNLCK) {
++ cFYI(1, ("F_UNLCK "));
++ numUnlock = 1;
++ } else if (pfLock->fl_type == F_RDLCK) {
++ cFYI(1, ("F_RDLCK "));
++ lockType |= LOCKING_ANDX_SHARED_LOCK;
++ numLock = 1;
++ } else if (pfLock->fl_type == F_EXLCK) {
++ cFYI(1, ("F_EXLCK "));
++ numLock = 1;
++ } else if (pfLock->fl_type == F_SHLCK) {
++ cFYI(1, ("F_SHLCK "));
++ lockType |= LOCKING_ANDX_SHARED_LOCK;
++ numLock = 1;
++ } else
++ cFYI(1, ("Unknown type of lock "));
++
++ cifs_sb = CIFS_SB(file->f_dentry->d_sb);
++ pTcon = cifs_sb->tcon;
++
++ if (file->private_data == NULL) {
++ FreeXid(xid);
++ return -EBADF;
++ }
++
++ if (IS_GETLK(cmd)) {
++ rc = CIFSSMBLock(xid, pTcon,
++ ((struct cifsFileInfo *) file->
++ private_data)->netfid,
++ length,
++ pfLock->fl_start, 0, 1, lockType,
++ 0 /* wait flag */ );
++ if (rc == 0) {
++ rc = CIFSSMBLock(xid, pTcon,
++ ((struct cifsFileInfo *) file->
++ private_data)->netfid,
++ length,
++ pfLock->fl_start, 1 /* numUnlock */ ,
++ 0 /* numLock */ , lockType,
++ 0 /* wait flag */ );
++ pfLock->fl_type = F_UNLCK;
++ if (rc != 0)
++ cERROR(1,
++ ("Error unlocking previously locked range %d during test of lock ",
++ rc));
++ rc = 0;
++
++ } else {
++ /* if rc == ERR_SHARING_VIOLATION ? */
++ rc = 0; /* do not change lock type to unlock since range in use */
++ }
++
++ FreeXid(xid);
++ return rc;
++ }
++
++ rc = CIFSSMBLock(xid, pTcon,
++ ((struct cifsFileInfo *) file->private_data)->
++ netfid, length,
++ pfLock->fl_start, numUnlock, numLock, lockType,
++ wait_flag);
++ FreeXid(xid);
++ return rc;
++}
++
++ssize_t
++cifs_write(struct file * file, const char *write_data,
++ size_t write_size, loff_t * poffset)
++{
++ int rc = 0;
++ unsigned int bytes_written = 0;
++ unsigned int total_written;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ int xid, long_op;
++ struct cifsFileInfo * open_file;
++
++ if(file->f_dentry == NULL)
++ return -EBADF;
++
++ cifs_sb = CIFS_SB(file->f_dentry->d_sb);
++ if(cifs_sb == NULL) {
++ return -EBADF;
++ }
++ pTcon = cifs_sb->tcon;
++
++ /*cFYI(1,
++ (" write %d bytes to offset %lld of %s", write_size,
++ *poffset, file->f_dentry->d_name.name)); */
++
++ if (file->private_data == NULL) {
++ return -EBADF;
++ } else {
++ open_file = (struct cifsFileInfo *) file->private_data;
++ }
++
++ xid = GetXid();
++ if(file->f_dentry->d_inode == NULL) {
++ FreeXid(xid);
++ return -EBADF;
++ }
++
++ if (*poffset > file->f_dentry->d_inode->i_size)
++ long_op = 2; /* writes past end of file can take a long time */
++ else
++ long_op = 1;
++
++ for (total_written = 0; write_size > total_written;
++ total_written += bytes_written) {
++ rc = -EAGAIN;
++ while(rc == -EAGAIN) {
++ if(file->private_data == NULL) {
++ /* file has been closed on us */
++ FreeXid(xid);
++ /* if we have gotten here we have written some data
++ and blocked, and the file has been freed on us
++ while we blocked so return what we managed to write */
++ return total_written;
++ }
++ if(open_file->closePend) {
++ FreeXid(xid);
++ if(total_written)
++ return total_written;
++ else
++ return -EBADF;
++ }
++ if (open_file->invalidHandle) {
++ if((file->f_dentry == NULL) ||
++ (file->f_dentry->d_inode == NULL)) {
++ FreeXid(xid);
++ return total_written;
++ }
++ /* we could deadlock if we called
++ filemap_fdatawait from here so tell
++ reopen_file not to flush data to server now */
++ rc = cifs_reopen_file(file->f_dentry->d_inode,
++ file,FALSE);
++ if(rc != 0)
++ break;
++ }
++
++ rc = CIFSSMBWrite(xid, pTcon,
++ open_file->netfid,
++ write_size - total_written, *poffset,
++ &bytes_written,
++ write_data + total_written, long_op);
++ }
++ if (rc || (bytes_written == 0)) {
++ if (total_written)
++ break;
++ else {
++ FreeXid(xid);
++ return rc;
++ }
++ } else
++ *poffset += bytes_written;
++ long_op = FALSE; /* subsequent writes fast - 15 seconds is plenty */
++ }
++
++#ifdef CONFIG_CIFS_STATS
++ if(total_written > 0) {
++ atomic_inc(&pTcon->num_writes);
++ spin_lock(&pTcon->stat_lock);
++ pTcon->bytes_written += total_written;
++ spin_unlock(&pTcon->stat_lock);
++ }
++#endif
++
++ /* since the write may have blocked check these pointers again */
++ if(file->f_dentry) {
++ if(file->f_dentry->d_inode) {
++ file->f_dentry->d_inode->i_ctime = file->f_dentry->d_inode->i_mtime =
++ CURRENT_TIME;
++ if (total_written > 0) {
++ if (*poffset > file->f_dentry->d_inode->i_size)
++ file->f_dentry->d_inode->i_size = *poffset;
++ }
++ mark_inode_dirty_sync(file->f_dentry->d_inode);
++ }
++ }
++ FreeXid(xid);
++ return total_written;
++}
++
++static int
++cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
++{
++ struct address_space *mapping = page->mapping;
++ loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
++ char * write_data;
++ int rc = -EFAULT;
++ int bytes_written = 0;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ struct inode *inode;
++ struct cifsInodeInfo *cifsInode;
++ struct cifsFileInfo *open_file = NULL;
++ struct list_head *tmp;
++ struct list_head *tmp1;
++
++ if (!mapping) {
++ return -EFAULT;
++ } else if(!mapping->host) {
++ return -EFAULT;
++ }
++
++ inode = page->mapping->host;
++ cifs_sb = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb->tcon;
++
++ offset += (loff_t)from;
++ write_data = kmap(page);
++ write_data += from;
++
++ if((to > PAGE_CACHE_SIZE) || (from > to)) {
++ kunmap(page);
++ return -EIO;
++ }
++
++ /* racing with truncate? */
++ if(offset > mapping->host->i_size) {
++ kunmap(page);
++ return 0; /* don't care */
++ }
++
++ /* check to make sure that we are not extending the file */
++ if(mapping->host->i_size - offset < (loff_t)to)
++ to = (unsigned)(mapping->host->i_size - offset);
++
++
++ cifsInode = CIFS_I(mapping->host);
++ read_lock(&GlobalSMBSeslock);
++ /* BB we should start at the end */
++ list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {
++ open_file = list_entry(tmp,struct cifsFileInfo, flist);
++ if(open_file->closePend)
++ continue;
++ /* We check if file is open for writing first */
++ if((open_file->pfile) &&
++ ((open_file->pfile->f_flags & O_RDWR) ||
++ (open_file->pfile->f_flags & O_WRONLY))) {
++ read_unlock(&GlobalSMBSeslock);
++ bytes_written = cifs_write(open_file->pfile, write_data,
++ to-from, &offset);
++ read_lock(&GlobalSMBSeslock);
++ /* Does mm or vfs already set times? */
++ inode->i_atime = inode->i_mtime = CURRENT_TIME;
++ if ((bytes_written > 0) && (offset)) {
++ rc = 0;
++ } else if(bytes_written < 0) {
++ if(rc == -EBADF) {
++ /* have seen a case in which
++ kernel seemed to have closed/freed a file
++ even with writes active so we might as well
++ see if there are other file structs to try
++ for the same inode before giving up */
++ continue;
++ } else
++ rc = bytes_written;
++ }
++ break; /* now that we found a valid file handle
++ and tried to write to it we are done, no
++ sense continuing to loop looking for another */
++ }
++ if(tmp->next == NULL) {
++ cFYI(1,("File instance %p removed",tmp));
++ break;
++ }
++ }
++ read_unlock(&GlobalSMBSeslock);
++ if(open_file == NULL) {
++ cFYI(1,("No writeable filehandles for inode"));
++ rc = -EIO;
++ }
++
++ kunmap(page);
++ return rc;
++}
++
++#if 0
++static int
++cifs_writepages(struct address_space *mapping, struct writeback_control *wbc)
++{
++ int rc = -EFAULT;
++ int xid;
++
++ xid = GetXid();
++/* call 16K write then Setpageuptodate */
++ FreeXid(xid);
++ return rc;
++}
++#endif
++
++static int
++cifs_writepage(struct page* page)
++{
++ int rc = -EFAULT;
++ int xid;
++
++ xid = GetXid();
++/* BB add check for wbc flags */
++ page_cache_get(page);
++ if (!Page_Uptodate(page)) {
++ cFYI(1,("ppw - page not up to date"));
++ }
++
++ rc = cifs_partialpagewrite(page,0,PAGE_CACHE_SIZE);
++ SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20))
++ unlock_page(page);
++#else
++ UnlockPage(page);
++#endif
++ page_cache_release(page);
++ FreeXid(xid);
++ return rc;
++}
++
++static int
++cifs_commit_write(struct file *file, struct page *page, unsigned offset,
++ unsigned to)
++{
++ int xid;
++ int rc = 0;
++ struct inode *inode = page->mapping->host;
++ loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
++ char * page_data;
++
++ xid = GetXid();
++ cFYI(1,("commit write for page %p up to position %lld for %d",page,position,to));
++ if (position > inode->i_size){
++ inode->i_size = position;
++ /*if (file->private_data == NULL) {
++ rc = -EBADF;
++ } else {
++ open_file = (struct cifsFileInfo *)file->private_data;
++ cifs_sb = CIFS_SB(inode->i_sb);
++ rc = -EAGAIN;
++ while(rc == -EAGAIN) {
++ if((open_file->invalidHandle) &&
++ (!open_file->closePend)) {
++ rc = cifs_reopen_file(file->f_dentry->d_inode,file);
++ if(rc != 0)
++ break;
++ }
++ if(!open_file->closePend) {
++ rc = CIFSSMBSetFileSize(xid, cifs_sb->tcon,
++ position, open_file->netfid,
++ open_file->pid,FALSE);
++ } else {
++ rc = -EBADF;
++ break;
++ }
++ }
++ cFYI(1,(" SetEOF (commit write) rc = %d",rc));
++ }*/
++ }
++ if (!Page_Uptodate(page)) {
++ position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;
++ /* can not rely on (or let) writepage write this data */
++ if(to < offset) {
++ cFYI(1,("Illegal offsets, can not copy from %d to %d",
++ offset,to));
++ FreeXid(xid);
++ return rc;
++ }
++ /* this is probably better than directly calling
++ partialpage_write since in this function
++ the file handle is known which we might as well
++ leverage */
++ /* BB check if anything else missing out of ppw */
++ /* such as updating last write time */
++ page_data = kmap(page);
++ rc = cifs_write(file, page_data+offset,to-offset,
++ &position);
++ if(rc > 0)
++ rc = 0;
++ /* else if rc < 0 should we set writebehind rc? */
++ kunmap(page);
++ } else {
++ set_page_dirty(page);
++ }
++
++ FreeXid(xid);
++ return rc;
++}
++
++int
++cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
++{
++ int xid;
++ int rc = 0;
++ struct inode * inode = file->f_dentry->d_inode;
++
++ xid = GetXid();
++
++ cFYI(1, ("Sync file - name: %s datasync: 0x%x ",
++ dentry->d_name.name, datasync));
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17))
++ rc = filemap_fdatasync(inode->i_mapping);
++#else
++ filemap_fdatasync(inode->i_mapping);
++#endif
++ if(rc == 0)
++ CIFS_I(inode)->write_behind_rc = 0;
++ FreeXid(xid);
++ return rc;
++}
++
++static int
++cifs_sync_page(struct page *page)
++{
++ struct address_space *mapping;
++ struct inode *inode;
++ unsigned long index = page->index;
++ unsigned int rpages = 0;
++ int rc = 0;
++
++ cFYI(1,("sync page %p",page));
++ mapping = page->mapping;
++ if (!mapping)
++ return 0;
++ inode = mapping->host;
++ if (!inode)
++ return 0;
++
++/* fill in rpages then
++ result = cifs_pagein_inode(inode, index, rpages); *//* BB finish */
++
++ cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index));
++
++ if (rc < 0)
++ return rc;
++ return 0;
++}
++
++/*
++ * As file closes, flush all cached write data for this inode checking
++ * for write behind errors.
++ *
++ */
++int cifs_flush(struct file *file)
++{
++ struct inode * inode = file->f_dentry->d_inode;
++ int rc = 0;
++
++ /* Rather than do the steps manually: */
++ /* lock the inode for writing */
++ /* loop through pages looking for write behind data (dirty pages) */
++ /* coalesce into contiguous 16K (or smaller) chunks to write to server */
++ /* send to server (prefer in parallel) */
++ /* deal with writebehind errors */
++ /* unlock inode for writing */
++ /* filemapfdatawrite appears easier for the time being */
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,17))
++ rc = filemap_fdatasync(inode->i_mapping);
++#else
++ filemap_fdatasync(inode->i_mapping);
++#endif
++ if(rc == 0) /* reset wb rc if we were able to write out dirty pages */
++ CIFS_I(inode)->write_behind_rc = 0;
++
++ cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc));
++
++ return rc;
++}
++
++
++ssize_t
++cifs_read(struct file * file, char *read_data, size_t read_size,
++ loff_t * poffset)
++{
++ int rc = -EACCES;
++ unsigned int bytes_read = 0;
++ unsigned int total_read;
++ unsigned int current_read_size;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ int xid;
++ char * current_offset;
++ struct cifsFileInfo * open_file;
++
++ xid = GetXid();
++ cifs_sb = CIFS_SB(file->f_dentry->d_sb);
++ pTcon = cifs_sb->tcon;
++
++ if (file->private_data == NULL) {
++ FreeXid(xid);
++ return -EBADF;
++ }
++ open_file = (struct cifsFileInfo *)file->private_data;
++
++ if((file->f_flags & O_ACCMODE) == O_WRONLY) {
++ cFYI(1,("attempting read on write only file instance"));
++ }
++
++ for (total_read = 0,current_offset=read_data; read_size > total_read;
++ total_read += bytes_read,current_offset+=bytes_read) {
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15))
++ current_read_size = min_t(const int,read_size - total_read,cifs_sb->rsize);
++#else
++ current_read_size = min(read_size - total_read,cifs_sb->rsize);
++#endif
++ rc = -EAGAIN;
++ while(rc == -EAGAIN) {
++ if ((open_file->invalidHandle) && (!open_file->closePend)) {
++ rc = cifs_reopen_file(file->f_dentry->d_inode,
++ file,TRUE);
++ if(rc != 0)
++ break;
++ }
++
++ rc = CIFSSMBRead(xid, pTcon,
++ open_file->netfid,
++ current_read_size, *poffset,
++ &bytes_read, &current_offset);
++ }
++ if (rc || (bytes_read == 0)) {
++ if (total_read) {
++ break;
++ } else {
++ FreeXid(xid);
++ return rc;
++ }
++ } else {
++#ifdef CONFIG_CIFS_STATS
++ atomic_inc(&pTcon->num_reads);
++ spin_lock(&pTcon->stat_lock);
++ pTcon->bytes_read += total_read;
++ spin_unlock(&pTcon->stat_lock);
++#endif
++ *poffset += bytes_read;
++ }
++ }
++ FreeXid(xid);
++ return total_read;
++}
++
++int cifs_file_mmap(struct file * file, struct vm_area_struct * vma)
++{
++ struct dentry * dentry = file->f_dentry;
++ int rc, xid;
++
++ xid = GetXid();
++ rc = cifs_revalidate(dentry);
++ if (rc) {
++ cFYI(1,("Validation prior to mmap failed, error=%d", rc));
++ FreeXid(xid);
++ return rc;
++ }
++ rc = generic_file_mmap(file, vma);
++ FreeXid(xid);
++ return rc;
++}
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
++static void cifs_copy_cache_pages(struct address_space *mapping,
++ struct list_head *pages, int bytes_read,
++ char *data,struct pagevec * plru_pvec)
++{
++ struct page *page;
++ char * target;
++
++ while (bytes_read > 0) {
++ if(list_empty(pages))
++ break;
++
++ page = list_entry(pages->prev, struct page, lru);
++ list_del(&page->lru);
++
++ if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) {
++ page_cache_release(page);
++ cFYI(1,("Add page cache failed"));
++ continue;
++ }
++
++ target = kmap_atomic(page,KM_USER0);
++
++ if(PAGE_CACHE_SIZE > bytes_read) {
++ memcpy(target,data,bytes_read);
++ /* zero the tail end of this partial page */
++ memset(target+bytes_read,0,PAGE_CACHE_SIZE-bytes_read);
++ bytes_read = 0;
++ } else {
++ memcpy(target,data,PAGE_CACHE_SIZE);
++ bytes_read -= PAGE_CACHE_SIZE;
++ }
++ kunmap_atomic(target,KM_USER0);
++
++ flush_dcache_page(page);
++ SetPageUptodate(page);
++ unlock_page(page);
++ if (!pagevec_add(plru_pvec, page))
++ __pagevec_lru_add(plru_pvec);
++ data += PAGE_CACHE_SIZE;
++ }
++ return;
++}
++
++
++static int
++cifs_readpages(struct file *file, struct address_space *mapping,
++ struct list_head *page_list, unsigned num_pages)
++{
++ int rc = -EACCES;
++ int xid;
++ loff_t offset;
++ struct page * page;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ int bytes_read = 0;
++ unsigned int read_size,i;
++ char * smb_read_data = NULL;
++ struct smb_com_read_rsp * pSMBr;
++ struct pagevec lru_pvec;
++ struct cifsFileInfo * open_file;
++
++ xid = GetXid();
++ if (file->private_data == NULL) {
++ FreeXid(xid);
++ return -EBADF;
++ }
++ open_file = (struct cifsFileInfo *)file->private_data;
++ cifs_sb = CIFS_SB(file->f_dentry->d_sb);
++ pTcon = cifs_sb->tcon;
++
++ pagevec_init(&lru_pvec, 0);
++
++ for(i = 0;i<num_pages;) {
++ unsigned contig_pages;
++ struct page * tmp_page;
++ unsigned long expected_index;
++
++ if(list_empty(page_list)) {
++ break;
++ }
++ page = list_entry(page_list->prev, struct page, lru);
++ offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
++
++ /* count adjacent pages that we will read into */
++ contig_pages = 0;
++ expected_index = list_entry(page_list->prev,struct page,lru)->index;
++ list_for_each_entry_reverse(tmp_page,page_list,lru) {
++ if(tmp_page->index == expected_index) {
++ contig_pages++;
++ expected_index++;
++ } else {
++ break;
++ }
++ }
++ if(contig_pages + i > num_pages) {
++ contig_pages = num_pages - i;
++ }
++
++ /* for reads over a certain size could initiate async read ahead */
++
++ read_size = contig_pages * PAGE_CACHE_SIZE;
++ /* Read size needs to be in multiples of one page */
++ read_size = min_t(const unsigned int,read_size,cifs_sb->rsize & PAGE_CACHE_MASK);
++
++ rc = -EAGAIN;
++ while(rc == -EAGAIN) {
++ if ((open_file->invalidHandle) && (!open_file->closePend)) {
++ rc = cifs_reopen_file(file->f_dentry->d_inode,
++ file, TRUE);
++ if(rc != 0)
++ break;
++ }
++
++ rc = CIFSSMBRead(xid, pTcon,
++ open_file->netfid,
++ read_size, offset,
++ &bytes_read, &smb_read_data);
++ /* BB need to check return code here */
++ if(rc== -EAGAIN) {
++ if(smb_read_data) {
++ cifs_buf_release(smb_read_data);
++ smb_read_data = NULL;
++ }
++ }
++ }
++ if ((rc < 0) || (smb_read_data == NULL)) {
++ cFYI(1,("Read error in readpages: %d",rc));
++ /* clean up remaing pages off list */
++ while (!list_empty(page_list) && (i < num_pages)) {
++ page = list_entry(page_list->prev, struct page, lru);
++ list_del(&page->lru);
++ page_cache_release(page);
++ }
++ break;
++ } else if (bytes_read > 0) {
++ pSMBr = (struct smb_com_read_rsp *)smb_read_data;
++ cifs_copy_cache_pages(mapping, page_list, bytes_read,
++ smb_read_data + 4 /* RFC1001 hdr */ +
++ le16_to_cpu(pSMBr->DataOffset), &lru_pvec);
++
++ i += bytes_read >> PAGE_CACHE_SHIFT;
++#ifdef CONFIG_CIFS_STATS
++ atomic_inc(&pTcon->num_reads);
++ spin_lock(&pTcon->stat_lock);
++ pTcon->bytes_read += bytes_read;
++ spin_unlock(&pTcon->stat_lock);
++#endif
++ if((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
++ cFYI(1,("Partial page %d of %d read to cache",i++,num_pages));
++
++ i++; /* account for partial page */
++
++ /* server copy of file can have smaller size than client */
++ /* BB do we need to verify this common case ? this case is ok -
++ if we are at server EOF we will hit it on next read */
++
++ /* while(!list_empty(page_list) && (i < num_pages)) {
++ page = list_entry(page_list->prev,struct page, list);
++ list_del(&page->list);
++ page_cache_release(page);
++ }
++ break; */
++ }
++ } else {
++ cFYI(1,("No bytes read (%d) at offset %lld . Cleaning remaining pages from readahead list",bytes_read,offset));
++ /* BB turn off caching and do new lookup on file size at server? */
++ while (!list_empty(page_list) && (i < num_pages)) {
++ page = list_entry(page_list->prev, struct page, lru);
++ list_del(&page->lru);
++ page_cache_release(page); /* BB removeme - replace with zero of page? */
++ }
++ break;
++ }
++ if(smb_read_data) {
++ cifs_buf_release(smb_read_data);
++ smb_read_data = NULL;
++ }
++ bytes_read = 0;
++ }
++
++ pagevec_lru_add(&lru_pvec);
++
++/* need to free smb_read_data buf before exit */
++ if(smb_read_data) {
++ cifs_buf_release(smb_read_data);
++ smb_read_data = NULL;
++ }
++
++ FreeXid(xid);
++ return rc;
++}
++#endif
++
++static int cifs_readpage_worker(struct file *file, struct page *page, loff_t * poffset)
++{
++ char * read_data;
++ int rc;
++
++ page_cache_get(page);
++ read_data = kmap(page);
++ /* for reads over a certain size could initiate async read ahead */
++
++ rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
++
++ if (rc < 0)
++ goto io_error;
++ else {
++ cFYI(1,("Bytes read %d ",rc));
++ }
++
++ file->f_dentry->d_inode->i_atime = CURRENT_TIME;
++
++ if(PAGE_CACHE_SIZE > rc) {
++ memset(read_data+rc, 0, PAGE_CACHE_SIZE - rc);
++ }
++ flush_dcache_page(page);
++ SetPageUptodate(page);
++ rc = 0;
++
++io_error:
++ kunmap(page);
++ page_cache_release(page);
++ return rc;
++}
++
++static int
++cifs_readpage(struct file *file, struct page *page)
++{
++ loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
++ int rc = -EACCES;
++ int xid;
++
++ xid = GetXid();
++
++ if (file->private_data == NULL) {
++ FreeXid(xid);
++ return -EBADF;
++ }
++
++ cFYI(1,("readpage %p at offset %d 0x%x\n",page,(int)offset,(int)offset));
++
++ rc = cifs_readpage_worker(file,page,&offset);
++
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,20))
++ unlock_page(page);
++#else
++ UnlockPage(page);
++#endif
++
++ FreeXid(xid);
++ return rc;
++}
++
++/* We do not want to update the file size from server for inodes
++ open for write - to avoid races with writepage extending
++ the file - in the future we could consider allowing
++ refreshing the inode only on increases in the file size
++ but this is tricky to do without racing with writebehind
++ page caching in the current Linux kernel design */
++
++int is_size_safe_to_change(struct cifsInodeInfo * cifsInode)
++{
++ struct list_head *tmp;
++ struct list_head *tmp1;
++ struct cifsFileInfo *open_file = NULL;
++ int rc = TRUE;
++
++ if(cifsInode == NULL)
++ return rc;
++
++ read_lock(&GlobalSMBSeslock);
++ list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {
++ open_file = list_entry(tmp,struct cifsFileInfo, flist);
++ if(open_file == NULL)
++ break;
++ if(open_file->closePend)
++ continue;
++ /* We check if file is open for writing,
++ BB we could supplement this with a check to see if file size
++ changes have been flushed to server - ie inode metadata dirty */
++ if((open_file->pfile) &&
++ ((open_file->pfile->f_flags & O_RDWR) ||
++ (open_file->pfile->f_flags & O_WRONLY))) {
++ rc = FALSE;
++ break;
++ }
++ if(tmp->next == NULL) {
++ cFYI(1,("File instance %p removed",tmp));
++ break;
++ }
++ }
++ read_unlock(&GlobalSMBSeslock);
++ return rc;
++}
++
++
++void
++fill_in_inode(struct inode *tmp_inode,
++ FILE_DIRECTORY_INFO * pfindData, int *pobject_type)
++{
++ struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
++ struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
++
++ pfindData->ExtFileAttributes =
++ le32_to_cpu(pfindData->ExtFileAttributes);
++ pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
++ pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile);
++ cifsInfo->cifsAttrs = pfindData->ExtFileAttributes;
++ cifsInfo->time = jiffies;
++
++ /* Linux can not store file creation time unfortunately so ignore it */
++ tmp_inode->i_atime =
++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
++ tmp_inode->i_mtime =
++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
++ tmp_inode->i_ctime =
++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
++ /* treat dos attribute of read-only as read-only mode bit e.g. 555? */
++ /* 2767 perms - indicate mandatory locking */
++ /* BB fill in uid and gid here? with help from winbind?
++ or retrieve from NTFS stream extended attribute */
++ if(atomic_read(&cifsInfo->inUse) == 0) {
++ tmp_inode->i_uid = cifs_sb->mnt_uid;
++ tmp_inode->i_gid = cifs_sb->mnt_gid;
++ /* set default mode. will override for dirs below */
++ tmp_inode->i_mode = cifs_sb->mnt_file_mode;
++ }
++
++ cFYI(0,
++ ("CIFS FFIRST: Attributes came in as 0x%x",
++ pfindData->ExtFileAttributes));
++ if (pfindData->ExtFileAttributes & ATTR_REPARSE) {
++ *pobject_type = DT_LNK;
++ /* BB can this and S_IFREG or S_IFDIR be set as in Windows? */
++ tmp_inode->i_mode |= S_IFLNK;
++ } else if (pfindData->ExtFileAttributes & ATTR_DIRECTORY) {
++ *pobject_type = DT_DIR;
++ /* override default perms since we do not lock dirs */
++ if(atomic_read(&cifsInfo->inUse) == 0) {
++ tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
++ }
++ tmp_inode->i_mode |= S_IFDIR;
++ } else {
++ *pobject_type = DT_REG;
++ tmp_inode->i_mode |= S_IFREG;
++ if(pfindData->ExtFileAttributes & ATTR_READONLY)
++ tmp_inode->i_mode &= ~(S_IWUGO);
++
++ }/* could add code here - to validate if device or weird share type? */
++
++ /* can not fill in nlink here as in qpathinfo version and Unx search */
++ if(atomic_read(&cifsInfo->inUse) == 0) {
++ atomic_set(&cifsInfo->inUse,1);
++ }
++ if(is_size_safe_to_change(cifsInfo)) {
++ /* can not safely change the file size here if the
++ client is writing to it due to potential races */
++ tmp_inode->i_size = pfindData->EndOfFile;
++
++ /* 512 bytes (2**9) is the fake blocksize that must be used */
++ /* for this calculation, even though the reported blocksize is larger */
++ tmp_inode->i_blocks = (512 - 1 + pfindData->AllocationSize) >> 9;
++ }
++
++ if (pfindData->AllocationSize < pfindData->EndOfFile)
++ cFYI(1, ("Possible sparse file: allocation size less than end of file "));
++ cFYI(1,
++ ("File Size %ld and blocks %ld and blocksize %ld",
++ (unsigned long) tmp_inode->i_size, tmp_inode->i_blocks,
++ tmp_inode->i_blksize));
++ if (S_ISREG(tmp_inode->i_mode)) {
++ cFYI(1, (" File inode "));
++ tmp_inode->i_op = &cifs_file_inode_ops;
++ tmp_inode->i_fop = &cifs_file_ops;
++ tmp_inode->i_data.a_ops = &cifs_addr_ops;
++ } else if (S_ISDIR(tmp_inode->i_mode)) {
++ cFYI(1, (" Directory inode"));
++ tmp_inode->i_op = &cifs_dir_inode_ops;
++ tmp_inode->i_fop = &cifs_dir_ops;
++ } else if (S_ISLNK(tmp_inode->i_mode)) {
++ cFYI(1, (" Symbolic Link inode "));
++ tmp_inode->i_op = &cifs_symlink_inode_ops;
++ } else {
++ cFYI(1, (" Init special inode "));
++ init_special_inode(tmp_inode, tmp_inode->i_mode,
++ kdev_t_to_nr(tmp_inode->i_rdev));
++ }
++}
++
++void
++unix_fill_in_inode(struct inode *tmp_inode,
++ FILE_UNIX_INFO * pfindData, int *pobject_type)
++{
++ struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
++ cifsInfo->time = jiffies;
++ atomic_inc(&cifsInfo->inUse);
++
++ tmp_inode->i_atime =
++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
++ tmp_inode->i_mtime =
++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastModificationTime));
++ tmp_inode->i_ctime =
++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange));
++
++ tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
++ pfindData->Type = le32_to_cpu(pfindData->Type);
++ if (pfindData->Type == UNIX_FILE) {
++ *pobject_type = DT_REG;
++ tmp_inode->i_mode |= S_IFREG;
++ } else if (pfindData->Type == UNIX_SYMLINK) {
++ *pobject_type = DT_LNK;
++ tmp_inode->i_mode |= S_IFLNK;
++ } else if (pfindData->Type == UNIX_DIR) {
++ *pobject_type = DT_DIR;
++ tmp_inode->i_mode |= S_IFDIR;
++ } else if (pfindData->Type == UNIX_CHARDEV) {
++ *pobject_type = DT_CHR;
++ tmp_inode->i_mode |= S_IFCHR;
++ tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
++ le64_to_cpu(pfindData->DevMinor) & MINORMASK);
++ } else if (pfindData->Type == UNIX_BLOCKDEV) {
++ *pobject_type = DT_BLK;
++ tmp_inode->i_mode |= S_IFBLK;
++ tmp_inode->i_rdev = MKDEV(le64_to_cpu(pfindData->DevMajor),
++ le64_to_cpu(pfindData->DevMinor) & MINORMASK);
++ } else if (pfindData->Type == UNIX_FIFO) {
++ *pobject_type = DT_FIFO;
++ tmp_inode->i_mode |= S_IFIFO;
++ } else if (pfindData->Type == UNIX_SOCKET) {
++ *pobject_type = DT_SOCK;
++ tmp_inode->i_mode |= S_IFSOCK;
++ }
++
++ tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
++ tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
++ tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
++
++ pfindData->NumOfBytes = le64_to_cpu(pfindData->NumOfBytes);
++ if(is_size_safe_to_change(cifsInfo)) {
++ /* can not safely change the file size here if the
++ client is writing to it due to potential races */
++ pfindData->EndOfFile = le64_to_cpu(pfindData->EndOfFile);
++ tmp_inode->i_size = pfindData->EndOfFile;
++
++ /* 512 bytes (2**9) is the fake blocksize that must be used */
++ /* for this calculation, not the real blocksize */
++ tmp_inode->i_blocks = (512 - 1 + pfindData->NumOfBytes) >> 9;
++ }
++
++ if (S_ISREG(tmp_inode->i_mode)) {
++ cFYI(1, ("File inode"));
++ tmp_inode->i_op = &cifs_file_inode_ops;
++ tmp_inode->i_fop = &cifs_file_ops;
++ tmp_inode->i_data.a_ops = &cifs_addr_ops;
++ } else if (S_ISDIR(tmp_inode->i_mode)) {
++ cFYI(1, ("Directory inode"));
++ tmp_inode->i_op = &cifs_dir_inode_ops;
++ tmp_inode->i_fop = &cifs_dir_ops;
++ } else if (S_ISLNK(tmp_inode->i_mode)) {
++ cFYI(1, ("Symbolic Link inode"));
++ tmp_inode->i_op = &cifs_symlink_inode_ops;
++/* tmp_inode->i_fop = *//* do not need to set to anything */
++ } else {
++ cFYI(1, ("Special inode"));
++ init_special_inode(tmp_inode, tmp_inode->i_mode,
++ kdev_t_to_nr(tmp_inode->i_rdev));
++ }
++}
++
++static void
++construct_dentry(struct qstr *qstring, struct file *file,
++ struct inode **ptmp_inode, struct dentry **pnew_dentry)
++{
++ struct dentry *tmp_dentry;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ struct cifsInodeInfo *pCifsI;
++
++ cFYI(1, ("For %s ", qstring->name));
++ cifs_sb = CIFS_SB(file->f_dentry->d_sb);
++ pTcon = cifs_sb->tcon;
++
++ qstring->hash = full_name_hash(qstring->name, qstring->len);
++ tmp_dentry = d_lookup(file->f_dentry, qstring);
++ if (tmp_dentry) {
++ cFYI(0, (" existing dentry with inode 0x%p", tmp_dentry->d_inode));
++ *ptmp_inode = tmp_dentry->d_inode;
++ /* BB overwrite the old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len ?? */
++ if(*ptmp_inode == NULL) {
++ *ptmp_inode = new_inode(file->f_dentry->d_sb);
++ if(*ptmp_inode == NULL)
++ return;
++ d_instantiate(tmp_dentry, *ptmp_inode);
++ insert_inode_hash(*ptmp_inode);
++ pCifsI = CIFS_I(*ptmp_inode);
++ INIT_LIST_HEAD(&pCifsI->openFileList);
++ /* can not enable caching for this inode
++ until a file instance is open and we
++ can check the oplock flag on the open
++ response */
++ (*ptmp_inode)->i_blksize = CIFS_MAX_MSGSIZE;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15))
++ (*ptmp_inode)->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
++#endif
++ pCifsI->clientCanCacheRead = FALSE;
++ pCifsI->clientCanCacheAll = FALSE;
++ pCifsI->time = 0;
++ /* do not need to set cifs Attrs since
++ they are about to be overwritten
++ in fill_in_inode */
++ atomic_set(&pCifsI->inUse, 0);
++ }
++ } else {
++ tmp_dentry = d_alloc(file->f_dentry, qstring);
++ if(tmp_dentry == NULL) {
++ cERROR(1,("Failed allocating dentry"));
++ return;
++ }
++
++ if(ptmp_inode) {
++ *ptmp_inode = new_inode(file->f_dentry->d_sb);
++ if(*ptmp_inode == NULL)
++ return;
++ pCifsI = CIFS_I(*ptmp_inode);
++ insert_inode_hash(*ptmp_inode);
++ INIT_LIST_HEAD(&pCifsI->openFileList);
++ /* can not enable caching for this inode
++ until a file instance is open and we
++ can check the oplock flag on the open
++ response */
++ (*ptmp_inode)->i_blksize = CIFS_MAX_MSGSIZE;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15))
++ (*ptmp_inode)->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
++#endif
++ pCifsI->clientCanCacheRead = FALSE;
++ pCifsI->clientCanCacheAll = FALSE;
++ pCifsI->time = 0;
++ /* do not need to set cifs Attrs since
++ they are about to be overwritten
++ in fill_in_inode */
++ atomic_set(&pCifsI->inUse, 0);
++ }
++ tmp_dentry->d_op = &cifs_dentry_ops;
++ d_instantiate(tmp_dentry, *ptmp_inode);
++ d_rehash(tmp_dentry);
++ }
++
++ tmp_dentry->d_time = jiffies;
++ *pnew_dentry = tmp_dentry;
++}
++
++static void reset_resume_key(struct file * dir_file,
++ unsigned char * filename,
++ unsigned int len,int Unicode,struct nls_table * nls_tab) {
++ struct cifsFileInfo *cifsFile;
++
++ cifsFile = (struct cifsFileInfo *)dir_file->private_data;
++ if(cifsFile == NULL)
++ return;
++ if(cifsFile->search_resume_name) {
++ kfree(cifsFile->search_resume_name);
++ }
++
++ if(Unicode)
++ len *= 2;
++ cifsFile->resume_name_length = len;
++
++ cifsFile->search_resume_name =
++ kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
++
++ if(cifsFile->search_resume_name == NULL) {
++ cERROR(1,("failed new resume key allocate, length %d",
++ cifsFile->resume_name_length));
++ return;
++ }
++ if(Unicode)
++ cifs_strtoUCS((wchar_t *) cifsFile->search_resume_name,
++ filename, len, nls_tab);
++ else
++ memcpy(cifsFile->search_resume_name, filename,
++ cifsFile->resume_name_length);
++ cFYI(1,("Reset resume key to: %s with len %d",filename,len));
++ return;
++}
++
++
++
++static int
++cifs_filldir(struct qstr *pqstring, FILE_DIRECTORY_INFO * pfindData,
++ struct file *file, filldir_t filldir, void *direntry)
++{
++ struct inode *tmp_inode;
++ struct dentry *tmp_dentry;
++ int object_type,rc;
++
++ pqstring->name = pfindData->FileName;
++ pqstring->len = pfindData->FileNameLength;
++
++ construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
++ if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
++ return -ENOMEM;
++ }
++ fill_in_inode(tmp_inode, pfindData, &object_type);
++ rc = filldir(direntry, pfindData->FileName, pqstring->len, file->f_pos,
++ tmp_inode->i_ino, object_type);
++ if(rc) {
++ /* due to readdir error we need to recalculate resume
++ key so next readdir will restart on right entry */
++ cFYI(1,("Error %d on filldir of %s",rc ,pfindData->FileName));
++ }
++ dput(tmp_dentry);
++ return rc;
++}
++
++static int
++cifs_filldir_unix(struct qstr *pqstring,
++ FILE_UNIX_INFO * pUnixFindData, struct file *file,
++ filldir_t filldir, void *direntry)
++{
++ struct inode *tmp_inode;
++ struct dentry *tmp_dentry;
++ int object_type, rc;
++
++ pqstring->name = pUnixFindData->FileName;
++ pqstring->len = strnlen(pUnixFindData->FileName, MAX_PATHCONF);
++
++ construct_dentry(pqstring, file, &tmp_inode, &tmp_dentry);
++ if((tmp_inode == NULL) || (tmp_dentry == NULL)) {
++ return -ENOMEM;
++ }
++
++ unix_fill_in_inode(tmp_inode, pUnixFindData, &object_type);
++ rc = filldir(direntry, pUnixFindData->FileName, pqstring->len,
++ file->f_pos, tmp_inode->i_ino, object_type);
++ if(rc) {
++ /* due to readdir error we need to recalculate resume
++ key so next readdir will restart on right entry */
++ cFYI(1,("Error %d on filldir of %s",rc ,pUnixFindData->FileName));
++ }
++ dput(tmp_dentry);
++ return rc;
++}
++
++int
++cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
++{
++ int rc = 0;
++ int xid;
++ int Unicode = FALSE;
++ int UnixSearch = FALSE;
++ unsigned int bufsize, i;
++ __u16 searchHandle;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ struct cifsFileInfo *cifsFile = NULL;
++ char *full_path = NULL;
++ char *data;
++ struct qstr qstring;
++ T2_FFIRST_RSP_PARMS findParms;
++ T2_FNEXT_RSP_PARMS findNextParms;
++ FILE_DIRECTORY_INFO *pfindData;
++ FILE_DIRECTORY_INFO *lastFindData;
++ FILE_UNIX_INFO *pfindDataUnix;
++
++ xid = GetXid();
++
++ cifs_sb = CIFS_SB(file->f_dentry->d_sb);
++ pTcon = cifs_sb->tcon;
++ bufsize = pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE;
++ if(bufsize > CIFS_MAX_MSGSIZE) {
++ FreeXid(xid);
++ return -EIO;
++ }
++ data = kmalloc(bufsize, GFP_KERNEL);
++ pfindData = (FILE_DIRECTORY_INFO *) data;
++
++ if(file->f_dentry == NULL) {
++ FreeXid(xid);
++ return -EIO;
++ }
++ down(&file->f_dentry->d_sb->s_vfs_rename_sem);
++ full_path = build_wildcard_path_from_dentry(file->f_dentry);
++ up(&file->f_dentry->d_sb->s_vfs_rename_sem);
++
++
++ cFYI(1, ("Full path: %s start at: %lld ", full_path, file->f_pos));
++
++ switch ((int) file->f_pos) {
++ case 0:
++ if (filldir(direntry, ".", 1, file->f_pos,
++ file->f_dentry->d_inode->i_ino, DT_DIR) < 0) {
++ cERROR(1, ("Filldir for current dir failed "));
++ break;
++ }
++ file->f_pos++;
++ /* fallthrough */
++ case 1:
++ if (filldir(direntry, "..", 2, file->f_pos,
++ file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
++ cERROR(1, ("Filldir for parent dir failed "));
++ break;
++ }
++ file->f_pos++;
++ /* fallthrough */
++ case 2:
++ if (file->private_data != NULL) {
++ cifsFile =
++ (struct cifsFileInfo *) file->private_data;
++ if (cifsFile->endOfSearch) {
++ if(cifsFile->emptyDir) {
++ cFYI(1, ("End of search, empty dir"));
++ rc = 0;
++ break;
++ }
++ } else {
++ cifsFile->invalidHandle = TRUE;
++ CIFSFindClose(xid, pTcon, cifsFile->netfid);
++ }
++ if(cifsFile->search_resume_name) {
++ kfree(cifsFile->search_resume_name);
++ cifsFile->search_resume_name = NULL;
++ }
++ }
++ rc = CIFSFindFirst(xid, pTcon, full_path, pfindData,
++ &findParms, cifs_sb->local_nls,
++ &Unicode, &UnixSearch);
++ cFYI(1, ("Count: %d End: %d ", findParms.SearchCount,
++ findParms.EndofSearch));
++
++ if (rc == 0) {
++ searchHandle = findParms.SearchHandle;
++ if(file->private_data == NULL)
++ file->private_data =
++ kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL);
++ if (file->private_data) {
++ memset(file->private_data, 0,
++ sizeof (struct cifsFileInfo));
++ cifsFile =
++ (struct cifsFileInfo *) file->private_data;
++ cifsFile->netfid = searchHandle;
++ cifsFile->invalidHandle = FALSE;
++ init_MUTEX(&cifsFile->fh_sem);
++ } else {
++ rc = -ENOMEM;
++ break;
++ }
++
++ renew_parental_timestamps(file->f_dentry);
++ lastFindData =
++ (FILE_DIRECTORY_INFO *) ((char *) pfindData +
++ findParms.LastNameOffset);
++ if((char *)lastFindData > (char *)pfindData + bufsize) {
++ cFYI(1,("last search entry past end of packet"));
++ rc = -EIO;
++ break;
++ }
++ /* Offset of resume key same for levels 257 and 514 */
++ cifsFile->resume_key = lastFindData->FileIndex;
++ if(UnixSearch == FALSE) {
++ cifsFile->resume_name_length =
++ le32_to_cpu(lastFindData->FileNameLength);
++ if(cifsFile->resume_name_length > bufsize - 64) {
++ cFYI(1,("Illegal resume file name length %d",
++ cifsFile->resume_name_length));
++ rc = -ENOMEM;
++ break;
++ }
++ cifsFile->search_resume_name =
++ kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
++ cFYI(1,("Last file: %s with name %d bytes long",
++ lastFindData->FileName,
++ cifsFile->resume_name_length));
++ memcpy(cifsFile->search_resume_name,
++ lastFindData->FileName,
++ cifsFile->resume_name_length);
++ } else {
++ pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
++ if (Unicode == TRUE) {
++ for(i=0;(pfindDataUnix->FileName[i]
++ | pfindDataUnix->FileName[i+1]);
++ i+=2) {
++ if(i > bufsize-64)
++ break;
++ }
++ cifsFile->resume_name_length = i + 2;
++ } else {
++ cifsFile->resume_name_length =
++ strnlen(pfindDataUnix->FileName,
++ bufsize-63);
++ }
++ if(cifsFile->resume_name_length > bufsize - 64) {
++ cFYI(1,("Illegal resume file name length %d",
++ cifsFile->resume_name_length));
++ rc = -ENOMEM;
++ break;
++ }
++ cifsFile->search_resume_name =
++ kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
++ cFYI(1,("Last file: %s with name %d bytes long",
++ pfindDataUnix->FileName,
++ cifsFile->resume_name_length));
++ memcpy(cifsFile->search_resume_name,
++ pfindDataUnix->FileName,
++ cifsFile->resume_name_length);
++ }
++ for (i = 2; i < (unsigned int)findParms.SearchCount + 2; i++) {
++ if (UnixSearch == FALSE) {
++ pfindData->FileNameLength =
++ le32_to_cpu(pfindData->FileNameLength);
++ if (Unicode == TRUE)
++ pfindData->FileNameLength =
++ cifs_strfromUCS_le
++ (pfindData->FileName,
++ (wchar_t *)
++ pfindData->FileName,
++ (pfindData->
++ FileNameLength) / 2,
++ cifs_sb->local_nls);
++ qstring.len = pfindData->FileNameLength;
++ if (((qstring.len != 1)
++ || (pfindData->FileName[0] != '.'))
++ && ((qstring.len != 2)
++ || (pfindData->
++ FileName[0] != '.')
++ || (pfindData->
++ FileName[1] != '.'))) {
++ if(cifs_filldir(&qstring,
++ pfindData,
++ file, filldir,
++ direntry)) {
++ /* do not end search if
++ kernel not ready to take
++ remaining entries yet */
++ reset_resume_key(file, pfindData->FileName,qstring.len,
++ Unicode, cifs_sb->local_nls);
++ findParms.EndofSearch = 0;
++ break;
++ }
++ file->f_pos++;
++ }
++ } else { /* UnixSearch */
++ pfindDataUnix =
++ (FILE_UNIX_INFO *) pfindData;
++ if (Unicode == TRUE)
++ qstring.len =
++ cifs_strfromUCS_le
++ (pfindDataUnix->FileName,
++ (wchar_t *)
++ pfindDataUnix->FileName,
++ MAX_PATHCONF,
++ cifs_sb->local_nls);
++ else
++ qstring.len =
++ strnlen(pfindDataUnix->
++ FileName,
++ MAX_PATHCONF);
++ if (((qstring.len != 1)
++ || (pfindDataUnix->
++ FileName[0] != '.'))
++ && ((qstring.len != 2)
++ || (pfindDataUnix->
++ FileName[0] != '.')
++ || (pfindDataUnix->
++ FileName[1] != '.'))) {
++ if(cifs_filldir_unix(&qstring,
++ pfindDataUnix,
++ file,
++ filldir,
++ direntry)) {
++ /* do not end search if
++ kernel not ready to take
++ remaining entries yet */
++ findParms.EndofSearch = 0;
++ reset_resume_key(file, pfindDataUnix->FileName,
++ qstring.len,Unicode,cifs_sb->local_nls);
++ break;
++ }
++ file->f_pos++;
++ }
++ }
++ /* works also for Unix ff struct since first field of both */
++ pfindData =
++ (FILE_DIRECTORY_INFO *) ((char *) pfindData
++ + le32_to_cpu(pfindData->NextEntryOffset));
++ /* BB also should check to make sure that pointer is not beyond the end of the SMB */
++ /* if(pfindData > lastFindData) rc = -EIO; break; */
++ } /* end for loop */
++ if ((findParms.EndofSearch != 0) && cifsFile) {
++ cifsFile->endOfSearch = TRUE;
++ if(findParms.SearchCount == 2)
++ cifsFile->emptyDir = TRUE;
++ }
++ } else {
++ if (cifsFile)
++ cifsFile->endOfSearch = TRUE;
++ /* unless parent directory gone do not return error */
++ rc = 0;
++ }
++ break;
++ default:
++ if (file->private_data == NULL) {
++ rc = -EBADF;
++ cFYI(1,
++ ("Readdir on closed srch, pos = %lld",
++ file->f_pos));
++ } else {
++ cifsFile = (struct cifsFileInfo *) file->private_data;
++ if (cifsFile->endOfSearch) {
++ rc = 0;
++ cFYI(1, ("End of search "));
++ break;
++ }
++ searchHandle = cifsFile->netfid;
++ rc = CIFSFindNext(xid, pTcon, pfindData,
++ &findNextParms, searchHandle,
++ cifsFile->search_resume_name,
++ cifsFile->resume_name_length,
++ cifsFile->resume_key,
++ &Unicode, &UnixSearch);
++ cFYI(1,("Count: %d End: %d ",
++ findNextParms.SearchCount,
++ findNextParms.EndofSearch));
++ if ((rc == 0) && (findNextParms.SearchCount != 0)) {
++ /* BB save off resume key, key name and name length */
++ lastFindData =
++ (FILE_DIRECTORY_INFO *) ((char *) pfindData
++ + findNextParms.LastNameOffset);
++ if((char *)lastFindData > (char *)pfindData + bufsize) {
++ cFYI(1,("last search entry past end of packet"));
++ rc = -EIO;
++ break;
++ }
++ /* Offset of resume key same for levels 257 and 514 */
++ cifsFile->resume_key = lastFindData->FileIndex;
++
++ if(UnixSearch == FALSE) {
++ cifsFile->resume_name_length =
++ le32_to_cpu(lastFindData->FileNameLength);
++ if(cifsFile->resume_name_length > bufsize - 64) {
++ cFYI(1,("Illegal resume file name length %d",
++ cifsFile->resume_name_length));
++ rc = -ENOMEM;
++ break;
++ }
++ /* Free the memory allocated by previous findfirst
++ or findnext call - we can not reuse the memory since
++ the resume name may not be same string length */
++ if(cifsFile->search_resume_name)
++ kfree(cifsFile->search_resume_name);
++ cifsFile->search_resume_name =
++ kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
++ cFYI(1,("Last file: %s with name %d bytes long",
++ lastFindData->FileName,
++ cifsFile->resume_name_length));
++ memcpy(cifsFile->search_resume_name,
++ lastFindData->FileName,
++ cifsFile->resume_name_length);
++ } else {
++ pfindDataUnix = (FILE_UNIX_INFO *)lastFindData;
++ if (Unicode == TRUE) {
++ for(i=0;(pfindDataUnix->FileName[i]
++ | pfindDataUnix->FileName[i+1]);
++ i+=2) {
++ if(i > bufsize-64)
++ break;
++ }
++ cifsFile->resume_name_length = i + 2;
++ } else {
++ cifsFile->resume_name_length =
++ strnlen(pfindDataUnix->
++ FileName,
++ MAX_PATHCONF);
++ }
++ if(cifsFile->resume_name_length > bufsize - 64) {
++ cFYI(1,("Illegal resume file name length %d",
++ cifsFile->resume_name_length));
++ rc = -ENOMEM;
++ break;
++ }
++ /* Free the memory allocated by previous findfirst
++ or findnext call - we can not reuse the memory since
++ the resume name may not be same string length */
++ if(cifsFile->search_resume_name)
++ kfree(cifsFile->search_resume_name);
++ cifsFile->search_resume_name =
++ kmalloc(cifsFile->resume_name_length, GFP_KERNEL);
++ cFYI(1,("fnext last file: %s with name %d bytes long",
++ pfindDataUnix->FileName,
++ cifsFile->resume_name_length));
++ memcpy(cifsFile->search_resume_name,
++ pfindDataUnix->FileName,
++ cifsFile->resume_name_length);
++ }
++
++ for (i = 0; i < findNextParms.SearchCount; i++) {
++ pfindData->FileNameLength =
++ le32_to_cpu(pfindData->
++ FileNameLength);
++ if (UnixSearch == FALSE) {
++ if (Unicode == TRUE)
++ pfindData->FileNameLength =
++ cifs_strfromUCS_le
++ (pfindData->FileName,
++ (wchar_t *)
++ pfindData->FileName,
++ (pfindData->FileNameLength)/ 2,
++ cifs_sb->local_nls);
++ qstring.len =
++ pfindData->FileNameLength;
++ if (((qstring.len != 1)
++ || (pfindData->FileName[0] != '.'))
++ && ((qstring.len != 2)
++ || (pfindData->FileName[0] != '.')
++ || (pfindData->FileName[1] !=
++ '.'))) {
++ if(cifs_filldir
++ (&qstring,
++ pfindData,
++ file, filldir,
++ direntry)) {
++ /* do not end search if
++ kernel not ready to take
++ remaining entries yet */
++ findNextParms.EndofSearch = 0;
++ reset_resume_key(file, pfindData->FileName,qstring.len,
++ Unicode,cifs_sb->local_nls);
++ break;
++ }
++ file->f_pos++;
++ }
++ } else { /* UnixSearch */
++ pfindDataUnix =
++ (FILE_UNIX_INFO *)
++ pfindData;
++ if (Unicode == TRUE)
++ qstring.len =
++ cifs_strfromUCS_le
++ (pfindDataUnix->FileName,
++ (wchar_t *)
++ pfindDataUnix->FileName,
++ MAX_PATHCONF,
++ cifs_sb->local_nls);
++ else
++ qstring.len =
++ strnlen
++ (pfindDataUnix->
++ FileName,
++ MAX_PATHCONF);
++ if (((qstring.len != 1)
++ || (pfindDataUnix->
++ FileName[0] != '.'))
++ && ((qstring.len != 2)
++ || (pfindDataUnix->
++ FileName[0] != '.')
++ || (pfindDataUnix->
++ FileName[1] !=
++ '.'))) {
++ if(cifs_filldir_unix
++ (&qstring,
++ pfindDataUnix,
++ file, filldir,
++ direntry)) {
++ /* do not end search if
++ kernel not ready to take
++ remaining entries yet */
++ findNextParms.EndofSearch = 0;
++ reset_resume_key(file, pfindDataUnix->FileName,qstring.len,
++ Unicode,cifs_sb->local_nls);
++ break;
++ }
++ file->f_pos++;
++ }
++ }
++ pfindData = (FILE_DIRECTORY_INFO *) ((char *) pfindData + le32_to_cpu(pfindData->NextEntryOffset)); /* works also for Unix find struct since this is the first field of both */
++ /* BB also should check to make sure that pointer is not beyond the end of the SMB */
++ } /* end for loop */
++ if (findNextParms.EndofSearch != 0) {
++ cifsFile->endOfSearch = TRUE;
++ }
++ } else {
++ cifsFile->endOfSearch = TRUE;
++ rc = 0; /* unless parent directory disappeared - do not return error here (eg Access Denied or no more files) */
++ }
++ }
++ } /* end switch */
++ if (data)
++ kfree(data);
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++
++ return rc;
++}
++int cifs_prepare_write(struct file *file, struct page *page,
++ unsigned from, unsigned to)
++{
++ int rc = 0;
++ loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
++ cFYI(1,("prepare write for page %p from %d to %d",page,from,to));
++ if (!Page_Uptodate(page)) {
++ /* if (to - from != PAGE_CACHE_SIZE) {
++ void *kaddr = kmap_atomic(page, KM_USER0);
++ memset(kaddr, 0, from);
++ memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
++ flush_dcache_page(page);
++ kunmap_atomic(kaddr, KM_USER0);
++ } */
++ /* If we are writing a full page it will be up to date,
++ no need to read from the server */
++ if((to==PAGE_CACHE_SIZE) && (from == 0))
++ SetPageUptodate(page);
++
++ /* might as well read a page, it is fast enough */
++ if((file->f_flags & O_ACCMODE) != O_WRONLY) {
++ rc = cifs_readpage_worker(file,page,&offset);
++ } else {
++ /* should we try using another
++ file handle if there is one - how would we lock it
++ to prevent close of that handle racing with this read? */
++ /* In any case this will be written out by commit_write */
++ }
++ }
++
++ /* BB should we pass any errors back? e.g. if we do not have read access to the file */
++ return 0;
++}
++
++
++struct address_space_operations cifs_addr_ops = {
++ .readpage = cifs_readpage,
++/* .readpages = cifs_readpages, */
++ .writepage = cifs_writepage,
++ .prepare_write = cifs_prepare_write,
++ .commit_write = cifs_commit_write,
++ .sync_page = cifs_sync_page,
++ /*.direct_IO = */
++};
+diff -urN linux-2.4.29.old/fs/cifs/inode.c linux-2.4.29/fs/cifs/inode.c
+--- linux-2.4.29.old/fs/cifs/inode.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/inode.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,1079 @@
++/*
++ * fs/cifs/inode.c
++ *
++ * Copyright (C) International Business Machines Corp., 2002,2003
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#include <linux/fs.h>
++#include <linux/stat.h>
++#include <linux/pagemap.h>
++#include <linux/version.h>
++#include <asm/div64.h>
++#include "cifsfs.h"
++#include "cifspdu.h"
++#include "cifsglob.h"
++#include "cifsproto.h"
++#include "cifs_debug.h"
++#include "cifs_fs_sb.h"
++
++extern int is_size_safe_to_change(struct cifsInodeInfo *);
++
++struct inode * get_cifs_inode(struct super_block * sb)
++{
++ struct inode * newinode;
++ newinode = new_inode(sb);
++ cFYI(1,("got new inode %p",newinode));
++ if(newinode) {
++ struct cifsInodeInfo * cifsInfo = CIFS_I(newinode);
++ cifsInfo->clientCanCacheRead = FALSE;
++ cifsInfo->clientCanCacheAll = FALSE;
++ INIT_LIST_HEAD(&cifsInfo->openFileList);
++ cifsInfo->cifsAttrs = 0x20; /* default */
++ newinode->i_blksize = CIFS_MAX_MSGSIZE;
++#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,4,15))
++ newinode->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
++#endif
++ atomic_set(&cifsInfo->inUse, 0);
++ cifsInfo->time = 0;
++ insert_inode_hash(newinode);
++ }
++ return newinode;
++
++}
++
++int
++cifs_get_inode_info_unix(struct inode **pinode,
++ const unsigned char *search_path,
++ struct super_block *sb,int xid)
++{
++ int rc = 0;
++ FILE_UNIX_BASIC_INFO findData;
++ struct cifsTconInfo *pTcon;
++ struct inode *inode;
++ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
++ char *tmp_path;
++
++ pTcon = cifs_sb->tcon;
++ cFYI(1, (" Getting info on %s ", search_path));
++ /* we could have done a find first instead but this returns more info */
++ rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
++ cifs_sb->local_nls);
++ /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */
++ if (rc) {
++ if (rc == -EREMOTE) {
++ tmp_path =
++ kmalloc(strnlen
++ (pTcon->treeName,
++ MAX_TREE_SIZE + 1) +
++ strnlen(search_path, MAX_PATHCONF) + 1,
++ GFP_KERNEL);
++ if (tmp_path == NULL) {
++ return -ENOMEM;
++ }
++ /* have to skip first of the double backslash of UNC name */
++ strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
++ strncat(tmp_path, search_path, MAX_PATHCONF);
++ rc = connect_to_dfs_path(xid, pTcon->ses,
++ /* treename + */ tmp_path,
++ cifs_sb->local_nls);
++ kfree(tmp_path);
++
++ /* BB fix up inode etc. */
++ } else if (rc) {
++ return rc;
++ }
++
++ } else {
++ struct cifsInodeInfo *cifsInfo;
++
++ /* get new inode */
++ if (*pinode == NULL) {
++ *pinode = get_cifs_inode(sb);
++ }
++ if(*pinode == NULL) {
++ return -ENOMEM;
++ }
++
++ inode = *pinode;
++ cifsInfo = CIFS_I(inode);
++
++ cFYI(1, (" Old time %ld ", cifsInfo->time));
++ cifsInfo->time = jiffies;
++ cFYI(1, (" New time %ld ", cifsInfo->time));
++ atomic_set(&cifsInfo->inUse,1); /* ok to set on every refresh of inode */
++
++ inode->i_atime =
++ cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
++ inode->i_mtime =
++ cifs_NTtimeToUnix(le64_to_cpu
++ (findData.LastModificationTime));
++ inode->i_ctime =
++ cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
++ inode->i_mode = le64_to_cpu(findData.Permissions);
++ findData.Type = le32_to_cpu(findData.Type);
++ if (findData.Type == UNIX_FILE) {
++ inode->i_mode |= S_IFREG;
++ } else if (findData.Type == UNIX_SYMLINK) {
++ inode->i_mode |= S_IFLNK;
++ } else if (findData.Type == UNIX_DIR) {
++ inode->i_mode |= S_IFDIR;
++ } else if (findData.Type == UNIX_CHARDEV) {
++ inode->i_mode |= S_IFCHR;
++ inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
++ le64_to_cpu(findData.DevMinor) & MINORMASK);
++ } else if (findData.Type == UNIX_BLOCKDEV) {
++ inode->i_mode |= S_IFBLK;
++ inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
++ le64_to_cpu(findData.DevMinor) & MINORMASK);
++ } else if (findData.Type == UNIX_FIFO) {
++ inode->i_mode |= S_IFIFO;
++ } else if (findData.Type == UNIX_SOCKET) {
++ inode->i_mode |= S_IFSOCK;
++ }
++ inode->i_uid = le64_to_cpu(findData.Uid);
++ inode->i_gid = le64_to_cpu(findData.Gid);
++ inode->i_nlink = le64_to_cpu(findData.Nlinks);
++ findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes);
++ findData.EndOfFile = le64_to_cpu(findData.EndOfFile);
++
++ if(is_size_safe_to_change(cifsInfo)) {
++ /* can not safely change the file size here if the
++ client is writing to it due to potential races */
++ inode->i_size = findData.EndOfFile;
++/* blksize needs to be multiple of two. So safer to default to blksize
++ and blkbits set in superblock so 2**blkbits and blksize will match */
++/* inode->i_blksize =
++ (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
++
++ /* This seems incredibly stupid but it turns out that
++ i_blocks is not related to (i_size / i_blksize), instead a
++ size of 512 is required to be used for calculating num blocks */
++
++
++/* inode->i_blocks =
++ (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;*/
++
++ /* 512 bytes (2**9) is the fake blocksize that must be used */
++ /* for this calculation */
++ inode->i_blocks = (512 - 1 + findData.NumOfBytes) >> 9;
++ }
++
++ if (findData.NumOfBytes < findData.EndOfFile)
++ cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));
++ cFYI(1,
++ ("Size %ld and blocks %ld ",
++ (unsigned long) inode->i_size, inode->i_blocks));
++ if (S_ISREG(inode->i_mode)) {
++ cFYI(1, (" File inode "));
++ inode->i_op = &cifs_file_inode_ops;
++ inode->i_fop = &cifs_file_ops;
++ inode->i_data.a_ops = &cifs_addr_ops;
++ } else if (S_ISDIR(inode->i_mode)) {
++ cFYI(1, (" Directory inode"));
++ inode->i_op = &cifs_dir_inode_ops;
++ inode->i_fop = &cifs_dir_ops;
++ } else if (S_ISLNK(inode->i_mode)) {
++ cFYI(1, (" Symbolic Link inode "));
++ inode->i_op = &cifs_symlink_inode_ops;
++/* tmp_inode->i_fop = *//* do not need to set to anything */
++ } else {
++ cFYI(1, (" Init special inode "));
++ init_special_inode(inode, inode->i_mode,
++ kdev_t_to_nr(inode->i_rdev));
++ }
++ }
++ return rc;
++}
++
++int
++cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
++ FILE_ALL_INFO * pfindData, struct super_block *sb, int xid)
++{
++ int rc = 0;
++ struct cifsTconInfo *pTcon;
++ struct inode *inode;
++ struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
++ char *tmp_path;
++ char *buf = NULL;
++
++ pTcon = cifs_sb->tcon;
++ cFYI(1,("Getting info on %s ", search_path));
++
++ if((pfindData == NULL) && (*pinode != NULL)) {
++ if(CIFS_I(*pinode)->clientCanCacheRead) {
++ cFYI(1,("No need to revalidate inode sizes on cached file "));
++ return rc;
++ }
++ }
++
++ /* if file info not passed in then get it from server */
++ if(pfindData == NULL) {
++ buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
++ pfindData = (FILE_ALL_INFO *)buf;
++ /* could do find first instead but this returns more info */
++ rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
++ cifs_sb->local_nls);
++ }
++ /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
++ if (rc) {
++ if (rc == -EREMOTE) {
++ tmp_path =
++ kmalloc(strnlen
++ (pTcon->treeName,
++ MAX_TREE_SIZE + 1) +
++ strnlen(search_path, MAX_PATHCONF) + 1,
++ GFP_KERNEL);
++ if (tmp_path == NULL) {
++ if(buf)
++ kfree(buf);
++ return -ENOMEM;
++ }
++
++ strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
++ strncat(tmp_path, search_path, MAX_PATHCONF);
++ rc = connect_to_dfs_path(xid, pTcon->ses,
++ /* treename + */ tmp_path,
++ cifs_sb->local_nls);
++ kfree(tmp_path);
++ /* BB fix up inode etc. */
++ } else if (rc) {
++ if(buf)
++ kfree(buf);
++ return rc;
++ }
++ } else {
++ struct cifsInodeInfo *cifsInfo;
++
++ /* get new inode */
++ if (*pinode == NULL) {
++ *pinode = get_cifs_inode(sb);
++ }
++ if(*pinode == NULL)
++ return -ENOMEM;
++ inode = *pinode;
++ cifsInfo = CIFS_I(inode);
++ pfindData->Attributes = le32_to_cpu(pfindData->Attributes);
++ cifsInfo->cifsAttrs = pfindData->Attributes;
++ cFYI(1, (" Old time %ld ", cifsInfo->time));
++ cifsInfo->time = jiffies;
++ cFYI(1, (" New time %ld ", cifsInfo->time));
++
++/* blksize needs to be multiple of two. So safer to default to blksize
++ and blkbits set in superblock so 2**blkbits and blksize will match */
++/* inode->i_blksize =
++ (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
++
++ /* Linux can not store file creation time unfortunately so we ignore it */
++ inode->i_atime =
++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
++ inode->i_mtime =
++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
++ inode->i_ctime =
++ cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
++ cFYI(0,
++ (" Attributes came in as 0x%x ", pfindData->Attributes));
++
++ /* set default mode. will override for dirs below */
++ if(atomic_read(&cifsInfo->inUse) == 0)
++ /* new inode, can safely set these fields */
++ inode->i_mode = cifs_sb->mnt_file_mode;
++
++ if (pfindData->Attributes & ATTR_REPARSE) {
++ /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */
++ inode->i_mode |= S_IFLNK;
++ } else if (pfindData->Attributes & ATTR_DIRECTORY) {
++ /* override default perms since we do not do byte range locking on dirs */
++ inode->i_mode = cifs_sb->mnt_dir_mode;
++ inode->i_mode |= S_IFDIR;
++ } else {
++ inode->i_mode |= S_IFREG;
++ /* treat the dos attribute of read-only as read-only mode e.g. 555 */
++ if(cifsInfo->cifsAttrs & ATTR_READONLY)
++ inode->i_mode &= ~(S_IWUGO);
++ /* BB add code here - validate if device or weird share or device type? */
++ }
++ if(is_size_safe_to_change(cifsInfo)) {
++ /* can not safely change the file size here if the
++ client is writing to it due to potential races */
++ inode->i_size = le64_to_cpu(pfindData->EndOfFile);
++
++ /* 512 bytes (2**9) is the fake blocksize that must be used */
++ /* for this calculation */
++ inode->i_blocks = (512 - 1 + pfindData->AllocationSize)
++ >> 9;
++ }
++ pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
++
++ cFYI(1,
++ (" Size %ld and blocks %ld ",
++ (unsigned long) inode->i_size, inode->i_blocks));
++ inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
++
++ /* BB fill in uid and gid here? with help from winbind?
++ or retrieve from NTFS stream extended attribute */
++ if(atomic_read(&cifsInfo->inUse) == 0) {
++ inode->i_uid = cifs_sb->mnt_uid;
++ inode->i_gid = cifs_sb->mnt_gid;
++ /* set so we do not keep refreshing these fields with
++ bad data after user has changed them in memory */
++ atomic_set(&cifsInfo->inUse,1);
++ }
++
++ if (S_ISREG(inode->i_mode)) {
++ cFYI(1, (" File inode "));
++ inode->i_op = &cifs_file_inode_ops;
++ inode->i_fop = &cifs_file_ops;
++ inode->i_data.a_ops = &cifs_addr_ops;
++ } else if (S_ISDIR(inode->i_mode)) {
++ cFYI(1, (" Directory inode "));
++ inode->i_op = &cifs_dir_inode_ops;
++ inode->i_fop = &cifs_dir_ops;
++ } else if (S_ISLNK(inode->i_mode)) {
++ cFYI(1, (" Symbolic Link inode "));
++ inode->i_op = &cifs_symlink_inode_ops;
++ } else {
++ init_special_inode(inode, inode->i_mode,
++ kdev_t_to_nr(inode->i_rdev));
++ }
++ }
++ if(buf)
++ kfree(buf);
++ return rc;
++}
++
++void
++cifs_read_inode(struct inode *inode)
++{ /* gets root inode */
++ int xid;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsInodeInfo *cifs_inode;
++
++ cifs_sb = CIFS_SB(inode->i_sb);
++ xid = GetXid();
++
++ cifs_inode = CIFS_I(inode);
++ cifs_inode->cifsAttrs = ATTR_DIRECTORY;
++ atomic_set(&cifs_inode->inUse, 0);
++ cifs_inode->time = 0;
++ inode->i_blksize = CIFS_MAX_MSGSIZE;
++ inode->i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
++
++ INIT_LIST_HEAD(&cifs_inode->openFileList);
++
++ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
++ cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);
++ else
++ cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);
++ /* can not call macro FreeXid here since in a void func */
++ _FreeXid(xid);
++}
++
++int
++cifs_unlink(struct inode *inode, struct dentry *direntry)
++{
++ int rc = 0;
++ int xid;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ char *full_path = NULL;
++ struct cifsInodeInfo *cifsInode;
++ FILE_BASIC_INFO * pinfo_buf;
++
++ cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
++
++ xid = GetXid();
++
++ cifs_sb = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb->tcon;
++
++/* Unlink can be called from rename so we can not grab
++ the sem here since we deadlock otherwise */
++/* down(&direntry->d_sb->s_vfs_rename_sem);*/
++ full_path = build_path_from_dentry(direntry);
++/* up(&direntry->d_sb->s_vfs_rename_sem);*/
++ if(full_path == NULL) {
++ FreeXid(xid);
++ return -ENOMEM;
++ }
++ rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
++
++ if (!rc) {
++ direntry->d_inode->i_nlink--;
++ } else if (rc == -ENOENT) {
++ d_drop(direntry);
++ } else if (rc == -ETXTBSY) {
++ int oplock = FALSE;
++ __u16 netfid;
++
++ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
++ CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
++ &netfid, &oplock, NULL, cifs_sb->local_nls);
++ if(rc==0) {
++ CIFSSMBRenameOpenFile(xid,pTcon,netfid,
++ NULL, cifs_sb->local_nls);
++ CIFSSMBClose(xid, pTcon, netfid);
++ direntry->d_inode->i_nlink--;
++ }
++ } else if (rc == -EACCES) {
++ /* try only if r/o attribute set in local lookup data? */
++ pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL);
++ if(pinfo_buf) {
++ memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO));
++ /* ATTRS set to normal clears r/o bit */
++ pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
++ rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf,
++ cifs_sb->local_nls);
++ kfree(pinfo_buf);
++ }
++ if(rc==0) {
++ rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
++ if (!rc) {
++ direntry->d_inode->i_nlink--;
++ } else if (rc == -ETXTBSY) {
++ int oplock = FALSE;
++ __u16 netfid;
++
++ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
++ CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
++ &netfid, &oplock, NULL, cifs_sb->local_nls);
++ if(rc==0) {
++ CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls);
++ CIFSSMBClose(xid, pTcon, netfid);
++ direntry->d_inode->i_nlink--;
++ }
++ /* BB if rc = -ETXTBUSY goto the rename logic BB */
++ }
++ }
++ }
++ cifsInode = CIFS_I(direntry->d_inode);
++ cifsInode->time = 0; /* will force revalidate to get info when needed */
++ direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
++ CURRENT_TIME;
++ cifsInode = CIFS_I(inode);
++ cifsInode->time = 0; /* force revalidate of dir as well */
++
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return rc;
++}
++
++int
++cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
++{
++ int rc = 0;
++ int xid;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ char *full_path = NULL;
++ struct inode *newinode = NULL;
++
++ cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));
++
++ xid = GetXid();
++
++ cifs_sb = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb->tcon;
++
++ down(&inode->i_sb->s_vfs_rename_sem);
++ full_path = build_path_from_dentry(direntry);
++ up(&inode->i_sb->s_vfs_rename_sem);
++ if(full_path == NULL) {
++ FreeXid(xid);
++ return -ENOMEM;
++ }
++ /* BB add setting the equivalent of mode via CreateX w/ACLs */
++ rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
++ if (rc) {
++ cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
++ d_drop(direntry);
++ } else {
++ inode->i_nlink++;
++ if (pTcon->ses->capabilities & CAP_UNIX)
++ rc = cifs_get_inode_info_unix(&newinode, full_path,
++ inode->i_sb,xid);
++ else
++ rc = cifs_get_inode_info(&newinode, full_path,NULL,
++ inode->i_sb,xid);
++
++ direntry->d_op = &cifs_dentry_ops;
++ d_instantiate(direntry, newinode);
++ if(direntry->d_inode)
++ direntry->d_inode->i_nlink = 2;
++ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
++ CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
++ (__u64)-1,
++ (__u64)-1,
++ 0 /* dev_t */,
++ cifs_sb->local_nls);
++ else { /* BB to be implemented via Windows secrty descriptors*/
++ /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
++ }
++ }
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++
++ return rc;
++}
++
++int
++cifs_rmdir(struct inode *inode, struct dentry *direntry)
++{
++ int rc = 0;
++ int xid;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ char *full_path = NULL;
++ struct cifsInodeInfo *cifsInode;
++
++ cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
++
++ xid = GetXid();
++
++ cifs_sb = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb->tcon;
++
++ down(&inode->i_sb->s_vfs_rename_sem);
++ full_path = build_path_from_dentry(direntry);
++ up(&inode->i_sb->s_vfs_rename_sem);
++ if(full_path == NULL) {
++ FreeXid(xid);
++ return -ENOMEM;
++ }
++
++ rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
++
++ if (!rc) {
++ inode->i_nlink--;
++ direntry->d_inode->i_size = 0;
++ direntry->d_inode->i_nlink = 0;
++ }
++
++ cifsInode = CIFS_I(direntry->d_inode);
++ cifsInode->time = 0; /* force revalidate to go get info when needed */
++ direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
++ CURRENT_TIME;
++
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return rc;
++}
++
++int
++cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
++ struct inode *target_inode, struct dentry *target_direntry)
++{
++ char *fromName;
++ char *toName;
++ struct cifs_sb_info *cifs_sb_source;
++ struct cifs_sb_info *cifs_sb_target;
++ struct cifsTconInfo *pTcon;
++ int xid;
++ int rc = 0;
++
++ xid = GetXid();
++
++ cifs_sb_target = CIFS_SB(target_inode->i_sb);
++ cifs_sb_source = CIFS_SB(source_inode->i_sb);
++ pTcon = cifs_sb_source->tcon;
++
++ if (pTcon != cifs_sb_target->tcon) {
++ FreeXid(xid);
++ return -EXDEV; /* BB actually could be allowed if same server, but
++ different share. Might eventually add support for this */
++ }
++
++ /* we already have the rename sem so we do not need
++ to grab it again here to protect the path integrity */
++ fromName = build_path_from_dentry(source_direntry);
++ toName = build_path_from_dentry(target_direntry);
++ if((fromName == NULL) || (toName == NULL)) {
++ rc = -ENOMEM;
++ goto cifs_rename_exit;
++ }
++
++ rc = CIFSSMBRename(xid, pTcon, fromName, toName,
++ cifs_sb_source->local_nls);
++ if(rc == -EEXIST) {
++ /* check if they are the same file
++ because rename of hardlinked files is a noop */
++ FILE_UNIX_BASIC_INFO * info_buf_source;
++ FILE_UNIX_BASIC_INFO * info_buf_target;
++
++ info_buf_source =
++ kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),GFP_KERNEL);
++ if(info_buf_source != NULL) {
++ info_buf_target = info_buf_source+1;
++ rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
++ info_buf_source, cifs_sb_source->local_nls);
++ if(rc == 0) {
++ rc = CIFSSMBUnixQPathInfo(xid,pTcon,toName,
++ info_buf_target,
++ cifs_sb_target->local_nls);
++ }
++ if((rc == 0) &&
++ (info_buf_source->UniqueId ==
++ info_buf_target->UniqueId)) {
++ /* do not rename since the files are hardlinked
++ which is a noop */
++ } else {
++ /* we either can not tell the files are hardlinked
++ (as with Windows servers) or files are not hardlinked
++ so delete the target manually before renaming to
++ follow POSIX rather than Windows semantics */
++ cifs_unlink(target_inode, target_direntry);
++ rc = CIFSSMBRename(xid, pTcon, fromName, toName,
++ cifs_sb_source->local_nls);
++ }
++ kfree(info_buf_source);
++ } /* if we can not get memory just leave rc as EEXIST */
++ }
++
++ if((rc == -EIO)||(rc == -EEXIST)) {
++ int oplock = FALSE;
++ __u16 netfid;
++
++ rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
++ CREATE_NOT_DIR,
++ &netfid, &oplock, NULL, cifs_sb_source->local_nls);
++ if(rc==0) {
++ CIFSSMBRenameOpenFile(xid,pTcon,netfid,
++ toName, cifs_sb_source->local_nls);
++ CIFSSMBClose(xid, pTcon, netfid);
++ }
++ }
++
++cifs_rename_exit:
++ if (fromName)
++ kfree(fromName);
++ if (toName)
++ kfree(toName);
++
++ FreeXid(xid);
++ return rc;
++}
++
++int
++cifs_revalidate(struct dentry *direntry)
++{
++ int xid;
++ int rc = 0;
++ char *full_path;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsInodeInfo *cifsInode;
++ loff_t local_size;
++ time_t local_mtime;
++ int invalidate_inode = FALSE;
++
++ if(direntry->d_inode == NULL)
++ return -ENOENT;
++
++ cifsInode = CIFS_I(direntry->d_inode);
++
++ if(cifsInode == NULL)
++ return -ENOENT;
++
++ /* no sense revalidating inode info on file that no one can write */
++ if(CIFS_I(direntry->d_inode)->clientCanCacheRead)
++ return rc;
++
++ xid = GetXid();
++
++ cifs_sb = CIFS_SB(direntry->d_sb);
++
++ /* can not safely grab the rename sem here if
++ rename calls revalidate since that would deadlock */
++ full_path = build_path_from_dentry(direntry);
++ if(full_path == NULL) {
++ FreeXid(xid);
++ return -ENOMEM;
++ }
++ cFYI(1,
++ ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
++ full_path, direntry->d_inode,
++ direntry->d_inode->i_count.counter, direntry,
++ direntry->d_time, jiffies));
++
++ if (cifsInode->time == 0){
++ /* was set to zero previously to force revalidate */
++ } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) {
++ if((S_ISREG(direntry->d_inode->i_mode) == 0) ||
++ (direntry->d_inode->i_nlink == 1)) {
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return rc;
++ } else {
++ cFYI(1,("Have to revalidate file due to hardlinks"));
++ }
++ }
++
++ /* save mtime and size */
++ local_mtime = direntry->d_inode->i_mtime;
++ local_size = direntry->d_inode->i_size;
++
++ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
++ rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
++ direntry->d_sb,xid);
++ if(rc) {
++ cFYI(1,("error on getting revalidate info %d",rc));
++/* if(rc != -ENOENT)
++ rc = 0; */ /* BB should we cache info on certain errors? */
++ }
++ } else {
++ rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
++ direntry->d_sb,xid);
++ if(rc) {
++ cFYI(1,("error on getting revalidate info %d",rc));
++/* if(rc != -ENOENT)
++ rc = 0; */ /* BB should we cache info on certain errors? */
++ }
++ }
++ /* should we remap certain errors, access denied?, to zero */
++
++ /* if not oplocked, we invalidate inode pages if mtime
++ or file size had changed on server */
++
++ if((local_mtime == direntry->d_inode->i_mtime) &&
++ (local_size == direntry->d_inode->i_size)) {
++ cFYI(1,("cifs_revalidate - inode unchanged"));
++ } else {
++ /* file may have changed on server */
++ if(cifsInode->clientCanCacheRead) {
++ /* no need to invalidate inode pages since we were
++ the only ones who could have modified the file and
++ the server copy is staler than ours */
++ } else {
++ invalidate_inode = TRUE;
++ }
++ }
++
++ /* can not grab this sem since kernel filesys locking
++ documentation indicates i_sem may be taken by the kernel
++ on lookup and rename which could deadlock if we grab
++ the i_sem here as well */
++/* down(&direntry->d_inode->i_sem);*/
++ /* need to write out dirty pages here */
++ if(direntry->d_inode->i_mapping) {
++ /* do we need to lock inode until after invalidate completes below? */
++ filemap_fdatasync(direntry->d_inode->i_mapping);
++ }
++ if(invalidate_inode) {
++ filemap_fdatawait(direntry->d_inode->i_mapping);
++ /* may eventually have to do this for open files too */
++ if(list_empty(&(cifsInode->openFileList))) {
++ /* Has changed on server - flush read ahead pages */
++ cFYI(1,("Invalidating read ahead data on closed file"));
++ invalidate_inode_pages(direntry->d_inode);
++ }
++ }
++/* up(&direntry->d_inode->i_sem);*/
++
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++
++ return rc;
++}
++
++/* int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
++{
++ int err = cifs_revalidate(dentry);
++ if (!err)
++ generic_fillattr(dentry->d_inode, stat);
++ return err;
++} */
++
++void
++cifs_truncate_file(struct inode *inode)
++{ /* BB remove - may not need this function after all BB */
++ int xid;
++ int rc = -EIO;
++ int found = FALSE;
++ struct cifsFileInfo *open_file = NULL;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ struct cifsInodeInfo *cifsInode;
++ struct dentry *dirent;
++ struct list_head * tmp;
++ char *full_path = NULL;
++
++ xid = GetXid();
++
++ cifs_sb = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb->tcon;
++
++ /* To avoid spurious oplock breaks from server, in the case
++ of inodes that we already have open, avoid doing path
++ based setting of file size if we can do it by handle.
++ This keeps our caching token (oplock) and avoids
++ timeouts when the local oplock break takes longer to flush
++ writebehind data than the SMB timeout for the SetPathInfo
++ request would allow */
++ read_lock(&GlobalSMBSeslock);
++ cifsInode = CIFS_I(inode);
++ list_for_each(tmp, &cifsInode->openFileList) {
++ open_file = list_entry(tmp,struct cifsFileInfo, flist);
++ /* We check if file is open for writing first */
++ if((open_file->pfile) && (!open_file->invalidHandle) &&
++ ((open_file->pfile->f_flags & O_RDWR) ||
++ (open_file->pfile->f_flags & O_WRONLY))) {
++ read_unlock(&GlobalSMBSeslock);
++ found = TRUE;
++ rc = CIFSSMBSetFileSize(xid, pTcon, inode->i_size,
++ open_file->netfid,open_file->pid,FALSE);
++ if(rc == 0) {
++ FreeXid(xid);
++ return;
++ }
++ /* Do not need reopen and retry on EAGAIN since we will
++ retry by pathname below */
++ if(rc == -EAGAIN)
++ rc = -EHOSTDOWN;
++
++ break; /* now that we found one valid file handle no
++ sense continuing to loop trying others */
++ }
++ }
++ if(found == FALSE)
++ read_unlock(&GlobalSMBSeslock);
++
++ if (list_empty(&inode->i_dentry)) {
++ cERROR(1,
++ ("Can not get pathname from empty dentry in inode 0x%p ",
++ inode));
++ FreeXid(xid);
++ return;
++ }
++
++ dirent = list_entry(inode->i_dentry.next, struct dentry, d_alias);
++ if (dirent) {
++ full_path = build_path_from_dentry(dirent);
++ rc = CIFSSMBSetEOF(xid, pTcon, full_path, inode->i_size,FALSE,
++ cifs_sb->local_nls);
++ cFYI(1,(" SetEOF (truncate) rc = %d",rc));
++ if (!rc)
++ CIFSSMBSetEOF(xid,pTcon,full_path,inode->i_size,TRUE,cifs_sb->local_nls);
++ /* allocation size setting seems optional so ignore return code */
++ }
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return;
++}
++
++static int cifs_truncate_page(struct address_space *mapping, loff_t from)
++{
++ unsigned long index = from >> PAGE_CACHE_SHIFT;
++ unsigned offset = from & (PAGE_CACHE_SIZE-1);
++ struct page *page;
++ char *kaddr;
++ int rc = 0;
++
++ page = grab_cache_page(mapping, index);
++ if (!page)
++ return -ENOMEM;
++
++ kaddr = kmap_atomic(page, KM_USER0);
++ memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
++ flush_dcache_page(page);
++ kunmap_atomic(kaddr, KM_USER0);
++ unlock_page(page);
++ page_cache_release(page);
++ return rc;
++}
++
++int
++cifs_setattr(struct dentry *direntry, struct iattr *attrs)
++{
++ int xid;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ char *full_path = NULL;
++ int rc = -EACCES;
++ int found = FALSE;
++ struct cifsFileInfo *open_file = NULL;
++ FILE_BASIC_INFO time_buf;
++ int set_time = FALSE;
++ __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
++ __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
++ __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
++ struct cifsInodeInfo *cifsInode;
++ struct list_head * tmp;
++
++ xid = GetXid();
++
++ cFYI(1,
++ (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
++ direntry->d_name.name, attrs->ia_valid));
++ cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
++ pTcon = cifs_sb->tcon;
++
++ down(&direntry->d_sb->s_vfs_rename_sem);
++ full_path = build_path_from_dentry(direntry);
++ up(&direntry->d_sb->s_vfs_rename_sem);
++ if(full_path == NULL) {
++ FreeXid(xid);
++ return -ENOMEM;
++ }
++ cifsInode = CIFS_I(direntry->d_inode);
++
++ /* BB check if we need to refresh inode from server now ? BB */
++
++ /* need to flush data before changing file size on server */
++ filemap_fdatasync(direntry->d_inode->i_mapping);
++
++ if (attrs->ia_valid & ATTR_SIZE) {
++ read_lock(&GlobalSMBSeslock);
++ /* To avoid spurious oplock breaks from server, in the case
++ of inodes that we already have open, avoid doing path
++ based setting of file size if we can do it by handle.
++ This keeps our caching token (oplock) and avoids
++ timeouts when the local oplock break takes longer to flush
++ writebehind data than the SMB timeout for the SetPathInfo
++ request would allow */
++ list_for_each(tmp, &cifsInode->openFileList) {
++ open_file = list_entry(tmp,struct cifsFileInfo, flist);
++ /* We check if file is open for writing first */
++ if((open_file->pfile) &&
++ ((open_file->pfile->f_flags & O_RDWR) ||
++ (open_file->pfile->f_flags & O_WRONLY))) {
++ if(open_file->invalidHandle == FALSE) {
++ /* we found a valid, writeable network file
++ handle to use to try to set the file size */
++ __u16 nfid = open_file->netfid;
++ __u32 npid = open_file->pid;
++ read_unlock(&GlobalSMBSeslock);
++ found = TRUE;
++ rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
++ nfid,npid,FALSE);
++ cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc));
++ /* Do not need reopen and retry on EAGAIN since we will
++ retry by pathname below */
++
++ break; /* now that we found one valid file handle no
++ sense continuing to loop trying others */
++ }
++ }
++ }
++ if(found == FALSE) {
++ read_unlock(&GlobalSMBSeslock);
++ }
++
++
++ if(rc != 0) {
++ /* Set file size by pathname rather than by handle either
++ because no valid, writeable file handle for it was found or
++ because there was an error setting it by handle */
++ rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE,
++ cifs_sb->local_nls);
++ cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc));
++ }
++
++ /* Server is ok setting allocation size implicitly - no need to call: */
++ /*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/
++
++ if (rc == 0) {
++ rc = vmtruncate(direntry->d_inode, attrs->ia_size);
++ cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size);
++ }
++ }
++ if (attrs->ia_valid & ATTR_UID) {
++ cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
++ uid = attrs->ia_uid;
++ /* entry->uid = cpu_to_le16(attr->ia_uid); */
++ }
++ if (attrs->ia_valid & ATTR_GID) {
++ cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
++ gid = attrs->ia_gid;
++ /* entry->gid = cpu_to_le16(attr->ia_gid); */
++ }
++
++ time_buf.Attributes = 0;
++ if (attrs->ia_valid & ATTR_MODE) {
++ cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
++ mode = attrs->ia_mode;
++ /* entry->mode = cpu_to_le16(attr->ia_mode); */
++ }
++
++ if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
++ && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
++ rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
++ 0 /* dev_t */, cifs_sb->local_nls);
++ else if (attrs->ia_valid & ATTR_MODE) {
++ if((mode & S_IWUGO) == 0) /* not writeable */ {
++ if((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
++ time_buf.Attributes =
++ cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY);
++ } else if((mode & S_IWUGO) == S_IWUGO) {
++ if(cifsInode->cifsAttrs & ATTR_READONLY)
++ time_buf.Attributes =
++ cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY));
++ }
++ /* BB to be implemented - via Windows security descriptors or streams */
++ /* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/
++ }
++
++ if (attrs->ia_valid & ATTR_ATIME) {
++ set_time = TRUE;
++ time_buf.LastAccessTime =
++ cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
++ } else
++ time_buf.LastAccessTime = 0;
++
++ if (attrs->ia_valid & ATTR_MTIME) {
++ set_time = TRUE;
++ time_buf.LastWriteTime =
++ cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
++ } else
++ time_buf.LastWriteTime = 0;
++
++ if (attrs->ia_valid & ATTR_CTIME) {
++ set_time = TRUE;
++ time_buf.ChangeTime =
++ cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
++ } else
++ time_buf.ChangeTime = 0;
++
++ if (set_time | time_buf.Attributes) {
++ /* BB what if setting one attribute fails
++ (such as size) but time setting works */
++ time_buf.CreationTime = 0; /* do not change */
++ /* In the future we should experiment - try setting timestamps
++ via Handle (SetFileInfo) instead of by path */
++ rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
++ cifs_sb->local_nls);
++ }
++
++ /* do not need local check to inode_check_ok since the server does that */
++ if (!rc)
++ rc = inode_setattr(direntry->d_inode, attrs);
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return rc;
++}
++
++void
++cifs_delete_inode(struct inode *inode)
++{
++ cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
++ /* may have to add back in if and when safe distributed caching of
++ directories added e.g. via FindNotify */
++}
+diff -urN linux-2.4.29.old/fs/cifs/link.c linux-2.4.29/fs/cifs/link.c
+--- linux-2.4.29.old/fs/cifs/link.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/link.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,328 @@
++/*
++ * fs/cifs/link.c
++ *
++ * Copyright (C) International Business Machines Corp., 2002,2003
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#include <linux/fs.h>
++#include <linux/stat.h>
++#include "cifsfs.h"
++#include "cifspdu.h"
++#include "cifsglob.h"
++#include "cifsproto.h"
++#include "cifs_debug.h"
++#include "cifs_fs_sb.h"
++
++int
++cifs_hardlink(struct dentry *old_file, struct inode *inode,
++ struct dentry *direntry)
++{
++ int rc = -EACCES;
++ int xid;
++ char *fromName = NULL;
++ char *toName = NULL;
++ struct cifs_sb_info *cifs_sb_target;
++ struct cifsTconInfo *pTcon;
++ struct cifsInodeInfo *cifsInode;
++
++ xid = GetXid();
++
++ cifs_sb_target = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb_target->tcon;
++
++/* No need to check for cross device links since server will do that
++ BB note DFS case in future though (when we may have to check) */
++
++ down(&inode->i_sb->s_vfs_rename_sem);
++ fromName = build_path_from_dentry(old_file);
++ toName = build_path_from_dentry(direntry);
++ up(&inode->i_sb->s_vfs_rename_sem);
++ if((fromName == NULL) || (toName == NULL)) {
++ rc = -ENOMEM;
++ goto cifs_hl_exit;
++ }
++
++ if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)
++ rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
++ cifs_sb_target->local_nls);
++ else {
++ rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
++ cifs_sb_target->local_nls);
++ if(rc == -EIO)
++ rc = -EOPNOTSUPP;
++ }
++
++/* if (!rc) */
++ {
++ /* renew_parental_timestamps(old_file);
++ inode->i_nlink++;
++ mark_inode_dirty(inode);
++ d_instantiate(direntry, inode); */
++ /* BB add call to either mark inode dirty or refresh its data and timestamp to current time */
++ }
++ d_drop(direntry); /* force new lookup from server */
++ cifsInode = CIFS_I(old_file->d_inode);
++ cifsInode->time = 0; /* will force revalidate to go get info when needed */
++
++cifs_hl_exit:
++ if (fromName)
++ kfree(fromName);
++ if (toName)
++ kfree(toName);
++ FreeXid(xid);
++ return rc;
++}
++
++int
++cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
++{
++ struct inode *inode = direntry->d_inode;
++ int rc = -EACCES;
++ int xid;
++ char *full_path = NULL;
++ char * target_path;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++
++ xid = GetXid();
++
++ down(&direntry->d_sb->s_vfs_rename_sem);
++ full_path = build_path_from_dentry(direntry);
++ up(&direntry->d_sb->s_vfs_rename_sem);
++
++ if(full_path == NULL) {
++ FreeXid(xid);
++ return -ENOMEM;
++ }
++ cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
++ cifs_sb = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb->tcon;
++ target_path = kmalloc(PATH_MAX, GFP_KERNEL);
++ if(target_path == NULL) {
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return -ENOMEM;
++ }
++ /* can not call the following line due to EFAULT in vfs_readlink which is presumably expecting a user space buffer */
++ /* length = cifs_readlink(direntry,target_path, sizeof(target_path) - 1); */
++
++/* BB add read reparse point symlink code and Unix extensions symlink code here BB */
++ if (pTcon->ses->capabilities & CAP_UNIX)
++ rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
++ target_path,
++ PATH_MAX-1,
++ cifs_sb->local_nls);
++ else {
++ /* rc = CIFSSMBQueryReparseLinkInfo */
++ /* BB Add code to Query ReparsePoint info */
++ }
++ /* BB Anything else to do to handle recursive links? */
++ /* BB Should we be using page symlink ops here? */
++
++ if (rc == 0) {
++
++/* BB Add special case check for Samba DFS symlinks */
++
++ target_path[PATH_MAX-1] = 0;
++ rc = vfs_follow_link(nd, target_path);
++ }
++ /* else EACCESS */
++
++ if (target_path)
++ kfree(target_path);
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return rc;
++}
++
++int
++cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
++{
++ int rc = -EOPNOTSUPP;
++ int xid;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ char *full_path = NULL;
++ struct inode *newinode = NULL;
++
++ xid = GetXid();
++
++ cifs_sb = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb->tcon;
++
++ down(&inode->i_sb->s_vfs_rename_sem);
++ full_path = build_path_from_dentry(direntry);
++ up(&inode->i_sb->s_vfs_rename_sem);
++
++ if(full_path == NULL) {
++ FreeXid(xid);
++ return -ENOMEM;
++ }
++
++ cFYI(1, ("Full path: %s ", full_path));
++ cFYI(1, ("symname is %s", symname));
++
++ /* BB what if DFS and this volume is on different share? BB */
++ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
++ rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
++ cifs_sb->local_nls);
++ /* else
++ rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,cifs_sb_target->local_nls); */
++
++ if (rc == 0) {
++ if (pTcon->ses->capabilities & CAP_UNIX)
++ rc = cifs_get_inode_info_unix(&newinode, full_path,
++ inode->i_sb,xid);
++ else
++ rc = cifs_get_inode_info(&newinode, full_path, NULL,
++ inode->i_sb,xid);
++
++ if (rc != 0) {
++ cFYI(1,
++ ("Create symlink worked but get_inode_info failed with rc = %d ",
++ rc));
++ } else {
++ direntry->d_op = &cifs_dentry_ops;
++ d_instantiate(direntry, newinode);
++ }
++ }
++
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return rc;
++}
++
++int
++cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
++{
++ struct inode *inode = direntry->d_inode;
++ int rc = -EACCES;
++ int xid;
++ int oplock = FALSE;
++ struct cifs_sb_info *cifs_sb;
++ struct cifsTconInfo *pTcon;
++ char *full_path = NULL;
++ char *tmp_path = NULL;
++ char * tmpbuffer;
++ unsigned char * referrals = NULL;
++ int num_referrals = 0;
++ int len;
++ __u16 fid;
++
++ xid = GetXid();
++ cifs_sb = CIFS_SB(inode->i_sb);
++ pTcon = cifs_sb->tcon;
++
++/* BB would it be safe against deadlock to grab this sem
++ even though rename itself grabs the sem and calls lookup? */
++/* down(&inode->i_sb->s_vfs_rename_sem);*/
++ full_path = build_path_from_dentry(direntry);
++/* up(&inode->i_sb->s_vfs_rename_sem);*/
++
++ if(full_path == NULL) {
++ FreeXid(xid);
++ return -ENOMEM;
++ }
++
++ cFYI(1,
++ ("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d",
++ full_path, inode, pBuffer, buflen));
++ if(buflen > PATH_MAX)
++ len = PATH_MAX;
++ else
++ len = buflen;
++ tmpbuffer = kmalloc(len,GFP_KERNEL);
++ if(tmpbuffer == NULL) {
++ if (full_path)
++ kfree(full_path);
++ FreeXid(xid);
++ return -ENOMEM;
++ }
++
++/* BB add read reparse point symlink code and Unix extensions symlink code here BB */
++ if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
++ rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
++ tmpbuffer,
++ len - 1,
++ cifs_sb->local_nls);
++ else {
++ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
++ OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls);
++ if(!rc) {
++ rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
++ tmpbuffer,
++ len - 1,
++ fid,
++ cifs_sb->local_nls);
++ if(CIFSSMBClose(xid, pTcon, fid)) {
++ cFYI(1,("Error closing junction point (open for ioctl)"));
++ }
++ if(rc == -EIO) {
++ /* Query if DFS Junction */
++ tmp_path =
++ kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
++ GFP_KERNEL);
++ if (tmp_path) {
++ strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
++ strncat(tmp_path, full_path, MAX_PATHCONF);
++ rc = get_dfs_path(xid, pTcon->ses, tmp_path,
++ cifs_sb->local_nls, &num_referrals, &referrals);
++ cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc));
++ if((num_referrals == 0) && (rc == 0))
++ rc = -EACCES;
++ else {
++ cFYI(1,("num referral: %d",num_referrals));
++ if(referrals) {
++ cFYI(1,("referral string: %s ",referrals));
++ strncpy(tmpbuffer, referrals, len-1);
++ }
++ }
++ if(referrals)
++ kfree(referrals);
++ kfree(tmp_path);
++ if(referrals) {
++ kfree(referrals);
++ }
++ }
++ /* BB add code like else decode referrals then memcpy to
++ tmpbuffer and free referrals string array BB */
++ }
++ }
++ }
++ /* BB Anything else to do to handle recursive links? */
++ /* BB Should we be using page ops here? */
++
++ /* BB null terminate returned string in pBuffer? BB */
++ if (rc == 0) {
++ rc = vfs_readlink(direntry, pBuffer, len, tmpbuffer);
++ cFYI(1,
++ ("vfs_readlink called from cifs_readlink returned %d",
++ rc));
++ }
++
++ if (tmpbuffer) {
++ kfree(tmpbuffer);
++ }
++ if (full_path) {
++ kfree(full_path);
++ }
++ FreeXid(xid);
++ return rc;
++}
+diff -urN linux-2.4.29.old/fs/cifs/Makefile linux-2.4.29/fs/cifs/Makefile
+--- linux-2.4.29.old/fs/cifs/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/Makefile 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,10 @@
++#
++# Makefile for Linux CIFS VFS client
++#
++O_TARGET := cifs.o
++
++obj-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o cifsencrypt.o
++
++obj-m := $(O_TARGET)
++
++include $(TOPDIR)/Rules.make
+diff -urN linux-2.4.29.old/fs/cifs/md4.c linux-2.4.29/fs/cifs/md4.c
+--- linux-2.4.29.old/fs/cifs/md4.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/md4.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,203 @@
++/*
++ Unix SMB/Netbios implementation.
++ Version 1.9.
++ a implementation of MD4 designed for use in the SMB authentication protocol
++ Copyright (C) Andrew Tridgell 1997-1998.
++ Modified by Steve French (sfrench@us.ibm.com) 2002-2003
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++*/
++#include <linux/module.h>
++#include <linux/fs.h>
++/* NOTE: This code makes no attempt to be fast! */
++
++static __u32
++F(__u32 X, __u32 Y, __u32 Z)
++{
++ return (X & Y) | ((~X) & Z);
++}
++
++static __u32
++G(__u32 X, __u32 Y, __u32 Z)
++{
++ return (X & Y) | (X & Z) | (Y & Z);
++}
++
++static __u32
++H(__u32 X, __u32 Y, __u32 Z)
++{
++ return X ^ Y ^ Z;
++}
++
++static __u32
++lshift(__u32 x, int s)
++{
++ x &= 0xFFFFFFFF;
++ return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
++}
++
++#define ROUND1(a,b,c,d,k,s) (*a) = lshift((*a) + F(*b,*c,*d) + X[k], s)
++#define ROUND2(a,b,c,d,k,s) (*a) = lshift((*a) + G(*b,*c,*d) + X[k] + (__u32)0x5A827999,s)
++#define ROUND3(a,b,c,d,k,s) (*a) = lshift((*a) + H(*b,*c,*d) + X[k] + (__u32)0x6ED9EBA1,s)
++
++/* this applies md4 to 64 byte chunks */
++static void
++mdfour64(__u32 * M, __u32 * A, __u32 *B, __u32 * C, __u32 *D)
++{
++ int j;
++ __u32 AA, BB, CC, DD;
++ __u32 X[16];
++
++
++ for (j = 0; j < 16; j++)
++ X[j] = M[j];
++
++ AA = *A;
++ BB = *B;
++ CC = *C;
++ DD = *D;
++
++ ROUND1(A, B, C, D, 0, 3);
++ ROUND1(D, A, B, C, 1, 7);
++ ROUND1(C, D, A, B, 2, 11);
++ ROUND1(B, C, D, A, 3, 19);
++ ROUND1(A, B, C, D, 4, 3);
++ ROUND1(D, A, B, C, 5, 7);
++ ROUND1(C, D, A, B, 6, 11);
++ ROUND1(B, C, D, A, 7, 19);
++ ROUND1(A, B, C, D, 8, 3);
++ ROUND1(D, A, B, C, 9, 7);
++ ROUND1(C, D, A, B, 10, 11);
++ ROUND1(B, C, D, A, 11, 19);
++ ROUND1(A, B, C, D, 12, 3);
++ ROUND1(D, A, B, C, 13, 7);
++ ROUND1(C, D, A, B, 14, 11);
++ ROUND1(B, C, D, A, 15, 19);
++
++ ROUND2(A, B, C, D, 0, 3);
++ ROUND2(D, A, B, C, 4, 5);
++ ROUND2(C, D, A, B, 8, 9);
++ ROUND2(B, C, D, A, 12, 13);
++ ROUND2(A, B, C, D, 1, 3);
++ ROUND2(D, A, B, C, 5, 5);
++ ROUND2(C, D, A, B, 9, 9);
++ ROUND2(B, C, D, A, 13, 13);
++ ROUND2(A, B, C, D, 2, 3);
++ ROUND2(D, A, B, C, 6, 5);
++ ROUND2(C, D, A, B, 10, 9);
++ ROUND2(B, C, D, A, 14, 13);
++ ROUND2(A, B, C, D, 3, 3);
++ ROUND2(D, A, B, C, 7, 5);
++ ROUND2(C, D, A, B, 11, 9);
++ ROUND2(B, C, D, A, 15, 13);
++
++ ROUND3(A, B, C, D, 0, 3);
++ ROUND3(D, A, B, C, 8, 9);
++ ROUND3(C, D, A, B, 4, 11);
++ ROUND3(B, C, D, A, 12, 15);
++ ROUND3(A, B, C, D, 2, 3);
++ ROUND3(D, A, B, C, 10, 9);
++ ROUND3(C, D, A, B, 6, 11);
++ ROUND3(B, C, D, A, 14, 15);
++ ROUND3(A, B, C, D, 1, 3);
++ ROUND3(D, A, B, C, 9, 9);
++ ROUND3(C, D, A, B, 5, 11);
++ ROUND3(B, C, D, A, 13, 15);
++ ROUND3(A, B, C, D, 3, 3);
++ ROUND3(D, A, B, C, 11, 9);
++ ROUND3(C, D, A, B, 7, 11);
++ ROUND3(B, C, D, A, 15, 15);
++
++ *A += AA;
++ *B += BB;
++ *C += CC;
++ *D += DD;
++
++ *A &= 0xFFFFFFFF;
++ *B &= 0xFFFFFFFF;
++ *C &= 0xFFFFFFFF;
++ *D &= 0xFFFFFFFF;
++
++ for (j = 0; j < 16; j++)
++ X[j] = 0;
++}
++
++static void
++copy64(__u32 * M, unsigned char *in)
++{
++ int i;
++
++ for (i = 0; i < 16; i++)
++ M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) |
++ (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0);
++}
++
++static void
++copy4(unsigned char *out, __u32 x)
++{
++ out[0] = x & 0xFF;
++ out[1] = (x >> 8) & 0xFF;
++ out[2] = (x >> 16) & 0xFF;
++ out[3] = (x >> 24) & 0xFF;
++}
++
++/* produce a md4 message digest from data of length n bytes */
++void
++mdfour(unsigned char *out, unsigned char *in, int n)
++{
++ unsigned char buf[128];
++ __u32 M[16];
++ __u32 b = n * 8;
++ int i;
++ __u32 A = 0x67452301;
++ __u32 B = 0xefcdab89;
++ __u32 C = 0x98badcfe;
++ __u32 D = 0x10325476;
++
++ while (n > 64) {
++ copy64(M, in);
++ mdfour64(M,&A,&B, &C, &D);
++ in += 64;
++ n -= 64;
++ }
++
++ for (i = 0; i < 128; i++)
++ buf[i] = 0;
++ memcpy(buf, in, n);
++ buf[n] = 0x80;
++
++ if (n <= 55) {
++ copy4(buf + 56, b);
++ copy64(M, buf);
++ mdfour64(M, &A, &B, &C, &D);
++ } else {
++ copy4(buf + 120, b);
++ copy64(M, buf);
++ mdfour64(M, &A, &B, &C, &D);
++ copy64(M, buf + 64);
++ mdfour64(M, &A, &B, &C, &D);
++ }
++
++ for (i = 0; i < 128; i++)
++ buf[i] = 0;
++ copy64(M, buf);
++
++ copy4(out, A);
++ copy4(out + 4, B);
++ copy4(out + 8, C);
++ copy4(out + 12, D);
++
++ A = B = C = D = 0;
++}
+diff -urN linux-2.4.29.old/fs/cifs/md5.c linux-2.4.29/fs/cifs/md5.c
+--- linux-2.4.29.old/fs/cifs/md5.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/md5.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,363 @@
++/*
++ * This code implements the MD5 message-digest algorithm.
++ * The algorithm is due to Ron Rivest. This code was
++ * written by Colin Plumb in 1993, no copyright is claimed.
++ * This code is in the public domain; do with it what you wish.
++ *
++ * Equivalent code is available from RSA Data Security, Inc.
++ * This code has been tested against that, and is equivalent,
++ * except that you don't need to include two pages of legalese
++ * with every copy.
++ *
++ * To compute the message digest of a chunk of bytes, declare an
++ * MD5Context structure, pass it to MD5Init, call MD5Update as
++ * needed on buffers full of bytes, and then call MD5Final, which
++ * will fill a supplied 16-byte array with the digest.
++ */
++
++/* This code slightly modified to fit into Samba by
++ abartlet@samba.org Jun 2001
++ and to fit the cifs vfs by
++ Steve French sfrench@us.ibm.com */
++
++#include <linux/string.h>
++#include "md5.h"
++
++static void MD5Transform(__u32 buf[4], __u32 const in[16]);
++
++/*
++ * Note: this code is harmless on little-endian machines.
++ */
++static void
++byteReverse(unsigned char *buf, unsigned longs)
++{
++ __u32 t;
++ do {
++ t = (__u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
++ ((unsigned) buf[1] << 8 | buf[0]);
++ *(__u32 *) buf = t;
++ buf += 4;
++ } while (--longs);
++}
++
++/*
++ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
++ * initialization constants.
++ */
++void
++MD5Init(struct MD5Context *ctx)
++{
++ ctx->buf[0] = 0x67452301;
++ ctx->buf[1] = 0xefcdab89;
++ ctx->buf[2] = 0x98badcfe;
++ ctx->buf[3] = 0x10325476;
++
++ ctx->bits[0] = 0;
++ ctx->bits[1] = 0;
++}
++
++/*
++ * Update context to reflect the concatenation of another buffer full
++ * of bytes.
++ */
++void
++MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
++{
++ register __u32 t;
++
++ /* Update bitcount */
++
++ t = ctx->bits[0];
++ if ((ctx->bits[0] = t + ((__u32) len << 3)) < t)
++ ctx->bits[1]++; /* Carry from low to high */
++ ctx->bits[1] += len >> 29;
++
++ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
++
++ /* Handle any leading odd-sized chunks */
++
++ if (t) {
++ unsigned char *p = (unsigned char *) ctx->in + t;
++
++ t = 64 - t;
++ if (len < t) {
++ memmove(p, buf, len);
++ return;
++ }
++ memmove(p, buf, t);
++ byteReverse(ctx->in, 16);
++ MD5Transform(ctx->buf, (__u32 *) ctx->in);
++ buf += t;
++ len -= t;
++ }
++ /* Process data in 64-byte chunks */
++
++ while (len >= 64) {
++ memmove(ctx->in, buf, 64);
++ byteReverse(ctx->in, 16);
++ MD5Transform(ctx->buf, (__u32 *) ctx->in);
++ buf += 64;
++ len -= 64;
++ }
++
++ /* Handle any remaining bytes of data. */
++
++ memmove(ctx->in, buf, len);
++}
++
++/*
++ * Final wrapup - pad to 64-byte boundary with the bit pattern
++ * 1 0* (64-bit count of bits processed, MSB-first)
++ */
++void
++MD5Final(unsigned char digest[16], struct MD5Context *ctx)
++{
++ unsigned int count;
++ unsigned char *p;
++
++ /* Compute number of bytes mod 64 */
++ count = (ctx->bits[0] >> 3) & 0x3F;
++
++ /* Set the first char of padding to 0x80. This is safe since there is
++ always at least one byte free */
++ p = ctx->in + count;
++ *p++ = 0x80;
++
++ /* Bytes of padding needed to make 64 bytes */
++ count = 64 - 1 - count;
++
++ /* Pad out to 56 mod 64 */
++ if (count < 8) {
++ /* Two lots of padding: Pad the first block to 64 bytes */
++ memset(p, 0, count);
++ byteReverse(ctx->in, 16);
++ MD5Transform(ctx->buf, (__u32 *) ctx->in);
++
++ /* Now fill the next block with 56 bytes */
++ memset(ctx->in, 0, 56);
++ } else {
++ /* Pad block to 56 bytes */
++ memset(p, 0, count - 8);
++ }
++ byteReverse(ctx->in, 14);
++
++ /* Append length in bits and transform */
++ ((__u32 *) ctx->in)[14] = ctx->bits[0];
++ ((__u32 *) ctx->in)[15] = ctx->bits[1];
++
++ MD5Transform(ctx->buf, (__u32 *) ctx->in);
++ byteReverse((unsigned char *) ctx->buf, 4);
++ memmove(digest, ctx->buf, 16);
++ memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
++}
++
++/* The four core functions - F1 is optimized somewhat */
++
++/* #define F1(x, y, z) (x & y | ~x & z) */
++#define F1(x, y, z) (z ^ (x & (y ^ z)))
++#define F2(x, y, z) F1(z, x, y)
++#define F3(x, y, z) (x ^ y ^ z)
++#define F4(x, y, z) (y ^ (x | ~z))
++
++/* This is the central step in the MD5 algorithm. */
++#define MD5STEP(f, w, x, y, z, data, s) \
++ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
++
++/*
++ * The core of the MD5 algorithm, this alters an existing MD5 hash to
++ * reflect the addition of 16 longwords of new data. MD5Update blocks
++ * the data and converts bytes into longwords for this routine.
++ */
++static void
++MD5Transform(__u32 buf[4], __u32 const in[16])
++{
++ register __u32 a, b, c, d;
++
++ a = buf[0];
++ b = buf[1];
++ c = buf[2];
++ d = buf[3];
++
++ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
++ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
++ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
++ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
++ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
++ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
++ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
++ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
++ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
++ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
++ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
++ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
++ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
++ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
++ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
++ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
++
++ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
++ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
++ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
++ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
++ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
++ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
++ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
++ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
++ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
++ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
++ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
++ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
++ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
++ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
++ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
++ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
++
++ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
++ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
++ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
++ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
++ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
++ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
++ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
++ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
++ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
++ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
++ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
++ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
++ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
++ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
++ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
++ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
++
++ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
++ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
++ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
++ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
++ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
++ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
++ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
++ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
++ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
++ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
++ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
++ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
++ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
++ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
++ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
++ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
++
++ buf[0] += a;
++ buf[1] += b;
++ buf[2] += c;
++ buf[3] += d;
++}
++
++/***********************************************************************
++ the rfc 2104 version of hmac_md5 initialisation.
++***********************************************************************/
++void
++hmac_md5_init_rfc2104(unsigned char *key, int key_len,
++ struct HMACMD5Context *ctx)
++{
++ int i;
++
++ /* if key is longer than 64 bytes reset it to key=MD5(key) */
++ if (key_len > 64) {
++ unsigned char tk[16];
++ struct MD5Context tctx;
++
++ MD5Init(&tctx);
++ MD5Update(&tctx, key, key_len);
++ MD5Final(tk, &tctx);
++
++ key = tk;
++ key_len = 16;
++ }
++
++ /* start out by storing key in pads */
++ memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad));
++ memset(ctx->k_opad, 0, sizeof (ctx->k_opad));
++ memcpy(ctx->k_ipad, key, key_len);
++ memcpy(ctx->k_opad, key, key_len);
++
++ /* XOR key with ipad and opad values */
++ for (i = 0; i < 64; i++) {
++ ctx->k_ipad[i] ^= 0x36;
++ ctx->k_opad[i] ^= 0x5c;
++ }
++
++ MD5Init(&ctx->ctx);
++ MD5Update(&ctx->ctx, ctx->k_ipad, 64);
++}
++
++/***********************************************************************
++ the microsoft version of hmac_md5 initialisation.
++***********************************************************************/
++void
++hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
++ struct HMACMD5Context *ctx)
++{
++ int i;
++
++ /* if key is longer than 64 bytes truncate it */
++ if (key_len > 64) {
++ key_len = 64;
++ }
++
++ /* start out by storing key in pads */
++ memset(ctx->k_ipad, 0, sizeof (ctx->k_ipad));
++ memset(ctx->k_opad, 0, sizeof (ctx->k_opad));
++ memcpy(ctx->k_ipad, key, key_len);
++ memcpy(ctx->k_opad, key, key_len);
++
++ /* XOR key with ipad and opad values */
++ for (i = 0; i < 64; i++) {
++ ctx->k_ipad[i] ^= 0x36;
++ ctx->k_opad[i] ^= 0x5c;
++ }
++
++ MD5Init(&ctx->ctx);
++ MD5Update(&ctx->ctx, ctx->k_ipad, 64);
++}
++
++/***********************************************************************
++ update hmac_md5 "inner" buffer
++***********************************************************************/
++void
++hmac_md5_update(const unsigned char *text, int text_len,
++ struct HMACMD5Context *ctx)
++{
++ MD5Update(&ctx->ctx, text, text_len); /* then text of datagram */
++}
++
++/***********************************************************************
++ finish off hmac_md5 "inner" buffer and generate outer one.
++***********************************************************************/
++void
++hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx)
++{
++ struct MD5Context ctx_o;
++
++ MD5Final(digest, &ctx->ctx);
++
++ MD5Init(&ctx_o);
++ MD5Update(&ctx_o, ctx->k_opad, 64);
++ MD5Update(&ctx_o, digest, 16);
++ MD5Final(digest, &ctx_o);
++}
++
++/***********************************************************
++ single function to calculate an HMAC MD5 digest from data.
++ use the microsoft hmacmd5 init method because the key is 16 bytes.
++************************************************************/
++void
++hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
++ unsigned char *digest)
++{
++ struct HMACMD5Context ctx;
++ hmac_md5_init_limK_to_64(key, 16, &ctx);
++ if (data_len != 0) {
++ hmac_md5_update(data, data_len, &ctx);
++ }
++ hmac_md5_final(digest, &ctx);
++}
+diff -urN linux-2.4.29.old/fs/cifs/md5.h linux-2.4.29/fs/cifs/md5.h
+--- linux-2.4.29.old/fs/cifs/md5.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/md5.h 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,38 @@
++#ifndef MD5_H
++#define MD5_H
++#ifndef HEADER_MD5_H
++/* Try to avoid clashes with OpenSSL */
++#define HEADER_MD5_H
++#endif
++
++struct MD5Context {
++ __u32 buf[4];
++ __u32 bits[2];
++ unsigned char in[64];
++};
++#endif /* !MD5_H */
++
++#ifndef _HMAC_MD5_H
++struct HMACMD5Context {
++ struct MD5Context ctx;
++ unsigned char k_ipad[65];
++ unsigned char k_opad[65];
++};
++#endif /* _HMAC_MD5_H */
++
++void MD5Init(struct MD5Context *context);
++void MD5Update(struct MD5Context *context, unsigned char const *buf,
++ unsigned len);
++void MD5Final(unsigned char digest[16], struct MD5Context *context);
++
++/* The following definitions come from lib/hmacmd5.c */
++
++void hmac_md5_init_rfc2104(unsigned char *key, int key_len,
++ struct HMACMD5Context *ctx);
++void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
++ struct HMACMD5Context *ctx);
++void hmac_md5_update(const unsigned char *text, int text_len,
++ struct HMACMD5Context *ctx);
++void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx);
++void hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
++ unsigned char *digest);
+diff -urN linux-2.4.29.old/fs/cifs/misc.c linux-2.4.29/fs/cifs/misc.c
+--- linux-2.4.29.old/fs/cifs/misc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/misc.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,463 @@
++/*
++ * fs/cifs/misc.c
++ *
++ * Copyright (C) International Business Machines Corp., 2002,2003
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/slab.h>
++#include <linux/ctype.h>
++#include "cifspdu.h"
++#include "cifsglob.h"
++#include "cifsproto.h"
++#include "cifs_debug.h"
++#include "smberr.h"
++#include "nterr.h"
++
++extern kmem_cache_t *cifs_req_cachep;
++extern struct task_struct * oplockThread;
++
++__u16 GlobalMid; /* multiplex id - rotating counter */
++
++/* The xid serves as a useful identifier for each incoming vfs request,
++ in a similar way to the mid which is useful to track each sent smb,
++ and CurrentXid can also provide a running counter (although it
++ will eventually wrap past zero) of the total vfs operations handled
++ since the cifs fs was mounted */
++
++unsigned int
++_GetXid(void)
++{
++ unsigned int xid;
++
++ spin_lock(&GlobalMid_Lock);
++ GlobalTotalActiveXid++;
++ if (GlobalTotalActiveXid > GlobalMaxActiveXid)
++ GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */
++ xid = GlobalCurrentXid++;
++ spin_unlock(&GlobalMid_Lock);
++ return xid;
++}
++
++void
++_FreeXid(unsigned int xid)
++{
++ spin_lock(&GlobalMid_Lock);
++ /* if(GlobalTotalActiveXid == 0)
++ BUG(); */
++ GlobalTotalActiveXid--;
++ spin_unlock(&GlobalMid_Lock);
++}
++
++struct cifsSesInfo *
++sesInfoAlloc(void)
++{
++ struct cifsSesInfo *ret_buf;
++
++ ret_buf =
++ (struct cifsSesInfo *) kmalloc(sizeof (struct cifsSesInfo),
++ GFP_KERNEL);
++ if (ret_buf) {
++ memset(ret_buf, 0, sizeof (struct cifsSesInfo));
++ write_lock(&GlobalSMBSeslock);
++ atomic_inc(&sesInfoAllocCount);
++ ret_buf->status = CifsNew;
++ list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList);
++ init_MUTEX(&ret_buf->sesSem);
++ write_unlock(&GlobalSMBSeslock);
++ }
++ return ret_buf;
++}
++
++void
++sesInfoFree(struct cifsSesInfo *buf_to_free)
++{
++ if (buf_to_free == NULL) {
++ cFYI(1, ("Null buffer passed to sesInfoFree"));
++ return;
++ }
++
++ write_lock(&GlobalSMBSeslock);
++ atomic_dec(&sesInfoAllocCount);
++ list_del(&buf_to_free->cifsSessionList);
++ write_unlock(&GlobalSMBSeslock);
++ if (buf_to_free->serverOS)
++ kfree(buf_to_free->serverOS);
++ if (buf_to_free->serverDomain)
++ kfree(buf_to_free->serverDomain);
++ if (buf_to_free->serverNOS)
++ kfree(buf_to_free->serverNOS);
++ if (buf_to_free->password)
++ kfree(buf_to_free->password);
++ kfree(buf_to_free);
++}
++
++struct cifsTconInfo *
++tconInfoAlloc(void)
++{
++ struct cifsTconInfo *ret_buf;
++ ret_buf =
++ (struct cifsTconInfo *) kmalloc(sizeof (struct cifsTconInfo),
++ GFP_KERNEL);
++ if (ret_buf) {
++ memset(ret_buf, 0, sizeof (struct cifsTconInfo));
++ write_lock(&GlobalSMBSeslock);
++ atomic_inc(&tconInfoAllocCount);
++ list_add(&ret_buf->cifsConnectionList,
++ &GlobalTreeConnectionList);
++ ret_buf->tidStatus = CifsNew;
++ INIT_LIST_HEAD(&ret_buf->openFileList);
++ init_MUTEX(&ret_buf->tconSem);
++#ifdef CONFIG_CIFS_STATS
++ ret_buf->stat_lock = SPIN_LOCK_UNLOCKED;
++#endif
++ write_unlock(&GlobalSMBSeslock);
++ }
++ return ret_buf;
++}
++
++void
++tconInfoFree(struct cifsTconInfo *buf_to_free)
++{
++ if (buf_to_free == NULL) {
++ cFYI(1, ("Null buffer passed to tconInfoFree"));
++ return;
++ }
++ write_lock(&GlobalSMBSeslock);
++ atomic_dec(&tconInfoAllocCount);
++ list_del(&buf_to_free->cifsConnectionList);
++ write_unlock(&GlobalSMBSeslock);
++ if (buf_to_free->nativeFileSystem)
++ kfree(buf_to_free->nativeFileSystem);
++ kfree(buf_to_free);
++}
++
++struct smb_hdr *
++cifs_buf_get(void)
++{
++ struct smb_hdr *ret_buf = NULL;
++
++/* We could use negotiated size instead of max_msgsize -
++ but it may be more efficient to always alloc same size
++ albeit slightly larger than necessary and maxbuffersize
++ defaults to this and can not be bigger */
++ ret_buf =
++ (struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep, SLAB_KERNEL);
++
++ /* clear the first few header bytes */
++ if (ret_buf) {
++ memset(ret_buf, 0, sizeof (struct smb_hdr));
++ atomic_inc(&bufAllocCount);
++ }
++
++ return ret_buf;
++}
++
++void
++cifs_buf_release(void *buf_to_free)
++{
++
++ if (buf_to_free == NULL) {
++ cFYI(1, ("Null buffer passed to cifs_buf_release"));
++ return;
++ }
++ kmem_cache_free(cifs_req_cachep, buf_to_free);
++
++ atomic_dec(&bufAllocCount);
++ return;
++}
++
++void
++header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
++ const struct cifsTconInfo *treeCon, int word_count
++ /* length of fixed section (word count) in two byte units */
++ )
++{
++ int i;
++ __u32 tmp;
++ struct list_head* temp_item;
++ struct cifsSesInfo * ses;
++ char *temp = (char *) buffer;
++
++ for (i = 0; i < MAX_CIFS_HDR_SIZE; i++) {
++ temp[i] = 0; /* BB is this needed ?? */
++ }
++
++ buffer->smb_buf_length =
++ (2 * word_count) + sizeof (struct smb_hdr) -
++ 4 /* RFC 1001 length field does not count */ +
++ 2 /* for bcc field itself */ ;
++ /* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */
++
++ buffer->Protocol[0] = 0xFF;
++ buffer->Protocol[1] = 'S';
++ buffer->Protocol[2] = 'M';
++ buffer->Protocol[3] = 'B';
++ buffer->Command = smb_command;
++ buffer->Flags = 0x00; /* case sensitive */
++ buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
++ tmp = cpu_to_le32(current->pid);
++ buffer->Pid = tmp & 0xFFFF;
++ tmp >>= 16;
++ buffer->PidHigh = tmp & 0xFFFF;
++ spin_lock(&GlobalMid_Lock);
++ GlobalMid++;
++ buffer->Mid = GlobalMid;
++ spin_unlock(&GlobalMid_Lock);
++ if (treeCon) {
++ buffer->Tid = treeCon->tid;
++ if (treeCon->ses) {
++ if (treeCon->ses->capabilities & CAP_UNICODE)
++ buffer->Flags2 |= SMBFLG2_UNICODE;
++ if (treeCon->ses->capabilities & CAP_STATUS32) {
++ buffer->Flags2 |= SMBFLG2_ERR_STATUS;
++ }
++
++ buffer->Uid = treeCon->ses->Suid; /* always in LE format */
++ if(multiuser_mount != 0) {
++ /* For the multiuser case, there are few obvious technically */
++ /* possible mechanisms to match the local linux user (uid) */
++ /* to a valid remote smb user (smb_uid): */
++ /* 1) Query Winbind (or other local pam/nss daemon */
++ /* for userid/password/logon_domain or credential */
++ /* 2) Query Winbind for uid to sid to username mapping */
++ /* and see if we have a matching password for existing*/
++ /* session for that user perhas getting password by */
++ /* adding a new pam_cifs module that stores passwords */
++ /* so that the cifs vfs can get at that for all logged*/
++ /* on users */
++ /* 3) (Which is the mechanism we have chosen) */
++ /* Search through sessions to the same server for a */
++ /* a match on the uid that was passed in on mount */
++ /* with the current processes uid (or euid?) and use */
++ /* that smb uid. If no existing smb session for */
++ /* that uid found, use the default smb session ie */
++ /* the smb session for the volume mounted which is */
++ /* the same as would be used if the multiuser mount */
++ /* flag were disabled. */
++
++ /* BB Add support for establishing new tCon and SMB Session */
++ /* with userid/password pairs found on the smb session */
++ /* for other target tcp/ip addresses BB */
++ if(current->uid != treeCon->ses->linux_uid) {
++ cFYI(1,("Multiuser mode and UID did not match tcon uid "));
++ read_lock(&GlobalSMBSeslock);
++ list_for_each(temp_item, &GlobalSMBSessionList) {
++ ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList);
++ if(ses->linux_uid == current->uid) {
++ if(ses->server == treeCon->ses->server) {
++ cFYI(1,("found matching uid substitute right smb_uid"));
++ buffer->Uid = ses->Suid;
++ break;
++ } else {
++ /* BB eventually call cifs_setup_session here */
++ cFYI(1,("local UID found but smb sess with this server does not exist"));
++ }
++ }
++ }
++ read_unlock(&GlobalSMBSeslock);
++ }
++ }
++ }
++ if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)
++ buffer->Flags2 |= SMBFLG2_DFS;
++ if(treeCon->ses->server)
++ if(treeCon->ses->server->secMode &
++ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
++ buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
++ }
++
++/* endian conversion of flags is now done just before sending */
++ buffer->WordCount = (char) word_count;
++ return;
++}
++
++int
++checkSMBhdr(struct smb_hdr *smb, __u16 mid)
++{
++ /* Make sure that this really is an SMB, that it is a response,
++ and that the message ids match */
++ if ((*(unsigned int *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
++ (mid == smb->Mid)) {
++ if(smb->Flags & SMBFLG_RESPONSE)
++ return 0;
++ else {
++ /* only one valid case where server sends us request */
++ if(smb->Command == SMB_COM_LOCKING_ANDX)
++ return 0;
++ else
++ cERROR(1, ("Rcvd Request not response "));
++ }
++ } else { /* bad signature or mid */
++ if (*(unsigned int *) smb->Protocol != cpu_to_le32(0x424d53ff))
++ cERROR(1,
++ ("Bad protocol string signature header %x ",
++ *(unsigned int *) smb->Protocol));
++ if (mid != smb->Mid)
++ cERROR(1, ("Mids do not match"));
++ }
++ cERROR(1, ("bad smb detected. The Mid=%d", smb->Mid));
++ return 1;
++}
++
++int
++checkSMB(struct smb_hdr *smb, __u16 mid, int length)
++{
++ cFYI(0,
++ ("Entering checkSMB with Length: %x, smb_buf_length: %x ",
++ length, ntohl(smb->smb_buf_length)));
++ if (((unsigned int)length < 2 + sizeof (struct smb_hdr))
++ || (ntohl(smb->smb_buf_length) >
++ CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4)) {
++ if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) {
++ cERROR(1, ("Length less than 2 + sizeof smb_hdr "));
++ if (((unsigned int)length >= sizeof (struct smb_hdr) - 1)
++ && (smb->Status.CifsError != 0))
++ return 0; /* some error cases do not return wct and bcc */
++
++ }
++ if (ntohl(smb->smb_buf_length) >
++ CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4)
++ cERROR(1,
++ ("smb_buf_length greater than CIFS_MAX_MSGSIZE ... "));
++ cERROR(1,
++ ("bad smb detected. Illegal length. The mid=%d",
++ smb->Mid));
++ return 1;
++ }
++
++ if (checkSMBhdr(smb, mid))
++ return 1;
++
++ if ((4 + ntohl(smb->smb_buf_length) != smbCalcSize(smb))
++ || (4 + ntohl(smb->smb_buf_length) != (unsigned int)length)) {
++ return 0;
++ } else {
++ cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb)));
++ cERROR(1,
++ ("bad smb size detected. The Mid=%d", smb->Mid));
++ return 1;
++ }
++}
++int
++is_valid_oplock_break(struct smb_hdr *buf)
++{
++ struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf;
++ struct list_head *tmp;
++ struct list_head *tmp1;
++ struct cifsTconInfo *tcon;
++ struct cifsFileInfo *netfile;
++
++ /* could add check for smb response flag 0x80 */
++ cFYI(1,("Checking for oplock break"));
++ if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
++ return FALSE;
++ if(pSMB->hdr.Flags & SMBFLG_RESPONSE) {
++ /* no sense logging error on invalid handle on oplock
++ break - harmless race between close request and oplock
++ break response is expected from time to time writing out
++ large dirty files cached on the client */
++ if ((NT_STATUS_INVALID_HANDLE) ==
++ le32_to_cpu(pSMB->hdr.Status.CifsError)) {
++ cFYI(1,("invalid handle on oplock break"));
++ return TRUE;
++ } else if (ERRbadfid ==
++ le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
++ return TRUE;
++ } else {
++ return FALSE; /* on valid oplock brk we get "request" */
++ }
++ }
++ if(pSMB->hdr.WordCount != 8)
++ return FALSE;
++
++ cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel));
++ if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
++ return FALSE;
++
++ /* look up tcon based on tid & uid */
++ read_lock(&GlobalSMBSeslock);
++ list_for_each(tmp, &GlobalTreeConnectionList) {
++ tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
++ if (tcon->tid == buf->Tid) {
++#ifdef CONFIG_CIFS_STATS
++ atomic_inc(&tcon->num_oplock_brks);
++#endif
++ list_for_each(tmp1,&tcon->openFileList){
++ netfile = list_entry(tmp1,struct cifsFileInfo,tlist);
++ if(pSMB->Fid == netfile->netfid) {
++ struct cifsInodeInfo *pCifsInode;
++ read_unlock(&GlobalSMBSeslock);
++ cFYI(1,("Matching file id, processing oplock break"));
++ pCifsInode =
++ CIFS_I(netfile->pInode);
++ pCifsInode->clientCanCacheAll = FALSE;
++ if(pSMB->OplockLevel == 0)
++ pCifsInode->clientCanCacheRead = FALSE;
++ pCifsInode->oplockPending = TRUE;
++ AllocOplockQEntry(netfile->pInode, netfile->netfid, tcon);
++ cFYI(1,("about to wake up oplock thd"));
++ wake_up_process(oplockThread);
++ return TRUE;
++ }
++ }
++ read_unlock(&GlobalSMBSeslock);
++ cFYI(1,("No matching file for oplock break on connection"));
++ return TRUE;
++ }
++ }
++ read_unlock(&GlobalSMBSeslock);
++ cFYI(1,("Can not process oplock break for non-existent connection"));
++ return TRUE;
++}
++
++void
++dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
++{
++ int i, j;
++ char debug_line[17];
++ unsigned char *buffer;
++
++ if (traceSMB == 0)
++ return;
++
++ buffer = (unsigned char *) smb_buf;
++ for (i = 0, j = 0; i < smb_buf_length; i++, j++) {
++ if (i % 8 == 0) { /* we have reached the beginning of line */
++ printk(KERN_DEBUG "| ");
++ j = 0;
++ }
++ printk("%0#4x ", buffer[i]);
++ debug_line[2 * j] = ' ';
++ if (isprint(buffer[i]))
++ debug_line[1 + (2 * j)] = buffer[i];
++ else
++ debug_line[1 + (2 * j)] = '_';
++
++ if (i % 8 == 7) { /* we have reached end of line, time to print ascii */
++ debug_line[16] = 0;
++ printk(" | %s\n", debug_line);
++ }
++ }
++ for (; j < 8; j++) {
++ printk(" ");
++ debug_line[2 * j] = ' ';
++ debug_line[1 + (2 * j)] = ' ';
++ }
++ printk( " | %s\n", debug_line);
++ return;
++}
+diff -urN linux-2.4.29.old/fs/cifs/netmisc.c linux-2.4.29/fs/cifs/netmisc.c
+--- linux-2.4.29.old/fs/cifs/netmisc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/netmisc.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,905 @@
++/*
++ * fs/cifs/netmisc.c
++ *
++ * Copyright (c) International Business Machines Corp., 2002
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * Error mapping routines from Samba libsmb/errormap.c
++ * Copyright (C) Andrew Tridgell 2001
++ *
++ *
++ * 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/net.h>
++#include <linux/string.h>
++#include <linux/in.h>
++#include <linux/ctype.h>
++#include <linux/fs.h>
++#include <asm/div64.h>
++#include <asm/byteorder.h>
++#include "cifsfs.h"
++#include "cifspdu.h"
++#include "cifsglob.h"
++#include "cifsproto.h"
++#include "smberr.h"
++#include "cifs_debug.h"
++#include "nterr.h"
++
++struct smb_to_posix_error {
++ __u16 smb_err;
++ int posix_code;
++};
++
++const struct smb_to_posix_error mapping_table_ERRDOS[] = {
++ {ERRbadfunc, -EINVAL},
++ {ERRbadfile, -ENOENT},
++ {ERRbadpath, -ENOTDIR},
++ {ERRnofids, -EMFILE},
++ {ERRnoaccess, -EACCES},
++ {ERRbadfid, -EBADF},
++ {ERRbadmcb, -EIO},
++ {ERRnomem, -ENOMEM},
++ {ERRbadmem, -EFAULT},
++ {ERRbadenv, -EFAULT},
++ {ERRbadformat, -EINVAL},
++ {ERRbadaccess, -EACCES},
++ {ERRbaddata, -EIO},
++ {ERRbaddrive, -ENXIO},
++ {ERRremcd, -EACCES},
++ {ERRdiffdevice, -EXDEV},
++ {ERRnofiles, -ENOENT},
++ {ERRbadshare, -ETXTBSY},
++ {ERRlock, -EACCES},
++ {ERRunsup, -EINVAL},
++ {ERRnosuchshare,-ENXIO},
++ {ERRfilexists, -EEXIST},
++ {ERRinvparm, -EINVAL},
++ {ERRdiskfull, -ENOSPC},
++ {ERRinvname, -ENOENT},
++ {ERRdirnotempty, -ENOTEMPTY},
++ {ERRnotlocked, -ENOLCK},
++ {ERRalreadyexists, -EEXIST},
++ {ERRmoredata, -EOVERFLOW},
++ {ErrQuota, -EDQUOT},
++ {ErrNotALink, -ENOLINK},
++ {ERRnetlogonNotStarted,-ENOPROTOOPT},
++ {0, 0}
++};
++
++const struct smb_to_posix_error mapping_table_ERRSRV[] = {
++ {ERRerror, -EIO},
++ {ERRbadpw, -EPERM},
++ {ERRbadtype, -EREMOTE},
++ {ERRaccess, -EACCES},
++ {ERRinvtid, -ENXIO},
++ {ERRinvnetname, -ENODEV},
++ {ERRinvdevice, -ENXIO},
++ {ERRqfull, -ENOSPC},
++ {ERRqtoobig, -ENOSPC},
++ {ERRqeof, -EIO},
++ {ERRinvpfid, -EBADF},
++ {ERRsmbcmd, -EBADRQC},
++ {ERRsrverror, -EIO},
++ {ERRbadBID, -EIO},
++ {ERRfilespecs, -EINVAL},
++ {ERRbadLink, -EIO},
++ {ERRbadpermits, -EINVAL},
++ {ERRbadPID, -ESRCH},
++ {ERRsetattrmode, -EINVAL},
++ {ERRpaused, -EHOSTDOWN},
++ {ERRmsgoff, -EHOSTDOWN},
++ {ERRnoroom, -ENOSPC},
++ {ERRrmuns, -EUSERS},
++ {ERRtimeout, -ETIME},
++ {ERRnoresource, -ENOBUFS},
++ {ERRtoomanyuids, -EUSERS},
++ {ERRbaduid, -EACCES},
++ {ERRusempx, -EIO},
++ {ERRusestd, -EIO},
++ {ERR_NOTIFY_ENUM_DIR, -ENOBUFS},
++ {ERRaccountexpired, -EACCES},
++ {ERRbadclient, -EACCES},
++ {ERRbadLogonTime, -EACCES},
++ {ERRpasswordExpired, -EACCES},
++ {ERRnosupport, -EINVAL},
++ {0, 0}
++};
++
++const struct smb_to_posix_error mapping_table_ERRHRD[] = {
++ {0, 0}
++};
++
++/* Convert string containing dotted ip address to binary form */
++/* returns 0 if invalid address */
++
++/* BB add address family, change rc to status flag and return union or for ipv6 */
++/* will need parent to call something like inet_pton to convert ipv6 address BB */
++int
++cifs_inet_pton(int address_family, char *cp,void *dst)
++{
++ struct in_addr address;
++ int value;
++ int digit;
++ int i;
++ char temp;
++ char bytes[4];
++ char *end = bytes;
++ static const int addr_class_max[4] =
++ { 0xffffffff, 0xffffff, 0xffff, 0xff };
++
++ if(address_family != AF_INET)
++ return -EAFNOSUPPORT;
++
++ for (i = 0; i < 4; i++) {
++ bytes[i] = 0;
++ }
++
++ temp = *cp;
++
++ while (TRUE) {
++ if (!isdigit(temp))
++ return 0;
++
++ value = 0;
++ digit = 0;
++ for (;;) {
++ if (isascii(temp) && isdigit(temp)) {
++ value = (value * 10) + temp - '0';
++ temp = *++cp;
++ digit = 1;
++ } else
++ break;
++ }
++
++ if (temp == '.') {
++ if ((end > bytes + 2) || (value > 255))
++ return 0;
++ *end++ = value;
++ temp = *++cp;
++ } else if (temp == ':') {
++ cFYI(1,("IPv6 addresses not supported for CIFS mounts yet"));
++ return -1;
++ } else
++ break;
++ }
++
++ /* check for last characters */
++ if (temp != '\0' && (!isascii(temp) || !isspace(temp)))
++ if (temp != '\\') {
++ if (temp != '/')
++ return 0;
++ else
++ (*cp = '\\'); /* switch the slash the expected way */
++ }
++ if (value > addr_class_max[end - bytes])
++ return 0;
++
++ address.s_addr = *((int *) bytes) | htonl(value);
++ *((int *)dst) = address.s_addr;
++ return 1; /* success */
++}
++
++/*****************************************************************************
++convert a NT status code to a dos class/code
++ *****************************************************************************/
++/* NT status -> dos error map */
++static const struct {
++ __u8 dos_class;
++ __u16 dos_code;
++ __u32 ntstatus;
++} ntstatus_to_dos_map[] = {
++ {
++ ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, {
++ ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, {
++ ERRDOS, 87, NT_STATUS_INVALID_INFO_CLASS}, {
++ ERRDOS, 24, NT_STATUS_INFO_LENGTH_MISMATCH}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ACCESS_VIOLATION}, {
++ ERRHRD, ERRgeneral, NT_STATUS_IN_PAGE_ERROR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA}, {
++ ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_BAD_INITIAL_STACK}, {
++ ERRDOS, 193, NT_STATUS_BAD_INITIAL_PC}, {
++ ERRDOS, 87, NT_STATUS_INVALID_CID}, {
++ ERRHRD, ERRgeneral, NT_STATUS_TIMER_NOT_CANCELED}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER}, {
++ ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_DEVICE}, {
++ ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE}, {
++ ERRDOS, ERRbadfunc, NT_STATUS_INVALID_DEVICE_REQUEST}, {
++ ERRDOS, 38, NT_STATUS_END_OF_FILE}, {
++ ERRDOS, 34, NT_STATUS_WRONG_VOLUME}, {
++ ERRDOS, 21, NT_STATUS_NO_MEDIA_IN_DEVICE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_MEDIA}, {
++ ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR},
++/* { This NT error code was 'sqashed'
++ from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK
++ during the session setup } */
++ {
++ ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY}, {
++ ERRDOS, 487, NT_STATUS_CONFLICTING_ADDRESSES}, {
++ ERRDOS, 487, NT_STATUS_NOT_MAPPED_VIEW}, {
++ ERRDOS, 87, NT_STATUS_UNABLE_TO_FREE_VM}, {
++ ERRDOS, 87, NT_STATUS_UNABLE_TO_DELETE_SECTION}, {
++ ERRDOS, 2142, NT_STATUS_INVALID_SYSTEM_SERVICE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_INSTRUCTION}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_INVALID_LOCK_SEQUENCE}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_INVALID_VIEW_SIZE}, {
++ ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_ALREADY_COMMITTED},
++/* { This NT error code was 'sqashed'
++ from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
++ during the session setup } */
++ {
++ ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED}, {
++ ERRDOS, 111, NT_STATUS_BUFFER_TOO_SMALL}, {
++ ERRDOS, ERRbadfid, NT_STATUS_OBJECT_TYPE_MISMATCH}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NONCONTINUABLE_EXCEPTION}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_DISPOSITION}, {
++ ERRHRD, ERRgeneral, NT_STATUS_UNWIND}, {
++ ERRHRD, ERRgeneral, NT_STATUS_BAD_STACK}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_UNWIND_TARGET}, {
++ ERRDOS, 158, NT_STATUS_NOT_LOCKED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PARITY_ERROR}, {
++ ERRDOS, 487, NT_STATUS_UNABLE_TO_DECOMMIT_VM}, {
++ ERRDOS, 487, NT_STATUS_NOT_COMMITTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_PORT_ATTRIBUTES}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PORT_MESSAGE_TOO_LONG}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_MIX}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_QUOTA_LOWER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DISK_CORRUPT_ERROR}, {
++ ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_INVALID}, { /* mapping changed since shell does lookup on * and expects file not found */
++ ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND}, {
++ ERRDOS, ERRalreadyexists, NT_STATUS_OBJECT_NAME_COLLISION}, {
++ ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE}, {
++ ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED}, {
++ ERRDOS, 161, NT_STATUS_OBJECT_PATH_INVALID}, {
++ ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND}, {
++ ERRDOS, 161, NT_STATUS_OBJECT_PATH_SYNTAX_BAD}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DATA_OVERRUN}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DATA_LATE_ERROR}, {
++ ERRDOS, 23, NT_STATUS_DATA_ERROR}, {
++ ERRDOS, 23, NT_STATUS_CRC_ERROR}, {
++ ERRDOS, ERRnomem, NT_STATUS_SECTION_TOO_BIG}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_PORT_CONNECTION_REFUSED}, {
++ ERRDOS, ERRbadfid, NT_STATUS_INVALID_PORT_HANDLE}, {
++ ERRDOS, ERRbadshare, NT_STATUS_SHARING_VIOLATION}, {
++ ERRHRD, ERRgeneral, NT_STATUS_QUOTA_EXCEEDED}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PAGE_PROTECTION}, {
++ ERRDOS, 288, NT_STATUS_MUTANT_NOT_OWNED}, {
++ ERRDOS, 298, NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED}, {
++ ERRDOS, 87, NT_STATUS_PORT_ALREADY_SET}, {
++ ERRDOS, 87, NT_STATUS_SECTION_NOT_IMAGE}, {
++ ERRDOS, 156, NT_STATUS_SUSPEND_COUNT_EXCEEDED}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_THREAD_IS_TERMINATING}, {
++ ERRDOS, 87, NT_STATUS_BAD_WORKING_SET_LIMIT}, {
++ ERRDOS, 87, NT_STATUS_INCOMPATIBLE_FILE_MAP}, {
++ ERRDOS, 87, NT_STATUS_SECTION_PROTECTION}, {
++ ERRDOS, 282, NT_STATUS_EAS_NOT_SUPPORTED}, {
++ ERRDOS, 255, NT_STATUS_EA_TOO_LARGE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NONEXISTENT_EA_ENTRY}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_EAS_ON_FILE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_EA_CORRUPT_ERROR}, {
++ ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT}, {
++ ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED}, {
++ ERRDOS, ERRbadfile, NT_STATUS_DELETE_PENDING}, {
++ ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_UNKNOWN_REVISION}, {
++ ERRHRD, ERRgeneral, NT_STATUS_REVISION_MISMATCH}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_OWNER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_PRIMARY_GROUP}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_IMPERSONATION_TOKEN}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CANT_DISABLE_MANDATORY}, {
++ ERRDOS, 2215, NT_STATUS_NO_LOGON_SERVERS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_LOGON_SESSION}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PRIVILEGE}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_PRIVILEGE_NOT_HELD}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME}, {
++ ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS},
++/* { This NT error code was 'sqashed'
++ from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE
++ during the session setup } */
++ {
++ ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP}, {
++ ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP}, {
++ ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_GROUP}, {
++ ERRHRD, ERRgeneral, NT_STATUS_LAST_ADMIN},
++/* { This NT error code was 'sqashed'
++ from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE
++ during the session setup } */
++ {
++ ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_PASSWORD}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, {
++ ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, {
++ ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, {
++ ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, {
++ ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_SUB_AUTHORITY}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACL}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_SID}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_SECURITY_DESCR}, {
++ ERRDOS, 127, NT_STATUS_PROCEDURE_NOT_FOUND}, {
++ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_FORMAT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_TOKEN}, {
++ ERRHRD, ERRgeneral, NT_STATUS_BAD_INHERITANCE_ACL}, {
++ ERRDOS, 158, NT_STATUS_RANGE_NOT_LOCKED}, {
++ ERRDOS, 112, NT_STATUS_DISK_FULL}, {
++ ERRHRD, ERRgeneral, NT_STATUS_SERVER_DISABLED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_SERVER_NOT_DISABLED}, {
++ ERRDOS, 68, NT_STATUS_TOO_MANY_GUIDS_REQUESTED}, {
++ ERRDOS, 259, NT_STATUS_GUIDS_EXHAUSTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ID_AUTHORITY}, {
++ ERRDOS, 259, NT_STATUS_AGENTS_EXHAUSTED}, {
++ ERRDOS, 154, NT_STATUS_INVALID_VOLUME_LABEL}, {
++ ERRDOS, 14, NT_STATUS_SECTION_NOT_EXTENDED}, {
++ ERRDOS, 487, NT_STATUS_NOT_MAPPED_DATA}, {
++ ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_DATA_NOT_FOUND}, {
++ ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_TYPE_NOT_FOUND}, {
++ ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_NAME_NOT_FOUND}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ARRAY_BOUNDS_EXCEEDED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DENORMAL_OPERAND}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_DIVIDE_BY_ZERO}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INEXACT_RESULT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_INVALID_OPERATION}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_OVERFLOW}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_STACK_CHECK}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FLOAT_UNDERFLOW}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INTEGER_DIVIDE_BY_ZERO}, {
++ ERRDOS, 534, NT_STATUS_INTEGER_OVERFLOW}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PRIVILEGED_INSTRUCTION}, {
++ ERRDOS, ERRnomem, NT_STATUS_TOO_MANY_PAGING_FILES}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
++/* { This NT error code was 'sqashed'
++ from NT_STATUS_INSUFFICIENT_RESOURCES to NT_STATUS_INSUFF_SERVER_RESOURCES
++ during the session setup } */
++ {
++ ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, {
++ ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, {
++ ERRDOS, 23, NT_STATUS_DEVICE_DATA_ERROR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_CONNECTED}, {
++ ERRDOS, 21, NT_STATUS_DEVICE_POWER_FAILURE}, {
++ ERRDOS, 487, NT_STATUS_FREE_VM_NOT_AT_BASE}, {
++ ERRDOS, 487, NT_STATUS_MEMORY_NOT_ALLOCATED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_WORKING_SET_QUOTA}, {
++ ERRDOS, 19, NT_STATUS_MEDIA_WRITE_PROTECTED}, {
++ ERRDOS, 21, NT_STATUS_DEVICE_NOT_READY}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_GROUP_ATTRIBUTES}, {
++ ERRHRD, ERRgeneral, NT_STATUS_BAD_IMPERSONATION_LEVEL}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CANT_OPEN_ANONYMOUS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_BAD_VALIDATION_CLASS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_BAD_TOKEN_TYPE}, {
++ ERRDOS, 87, NT_STATUS_BAD_MASTER_BOOT_RECORD}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INSTRUCTION_MISALIGNMENT}, {
++ ERRDOS, ERRpipebusy, NT_STATUS_INSTANCE_NOT_AVAILABLE}, {
++ ERRDOS, ERRpipebusy, NT_STATUS_PIPE_NOT_AVAILABLE}, {
++ ERRDOS, ERRbadpipe, NT_STATUS_INVALID_PIPE_STATE}, {
++ ERRDOS, ERRpipebusy, NT_STATUS_PIPE_BUSY}, {
++ ERRDOS, ERRbadfunc, NT_STATUS_ILLEGAL_FUNCTION}, {
++ ERRDOS, ERRnotconnected, NT_STATUS_PIPE_DISCONNECTED}, {
++ ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_CLOSING}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PIPE_CONNECTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PIPE_LISTENING}, {
++ ERRDOS, ERRbadpipe, NT_STATUS_INVALID_READ_MODE}, {
++ ERRDOS, 121, NT_STATUS_IO_TIMEOUT}, {
++ ERRDOS, 38, NT_STATUS_FILE_FORCED_CLOSED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STARTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PROFILING_NOT_STOPPED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_COULD_NOT_INTERPRET}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_FILE_IS_A_DIRECTORY}, {
++ ERRDOS, ERRunsup, NT_STATUS_NOT_SUPPORTED}, {
++ ERRDOS, 51, NT_STATUS_REMOTE_NOT_LISTENING}, {
++ ERRDOS, 52, NT_STATUS_DUPLICATE_NAME}, {
++ ERRDOS, 53, NT_STATUS_BAD_NETWORK_PATH}, {
++ ERRDOS, 54, NT_STATUS_NETWORK_BUSY}, {
++ ERRDOS, 55, NT_STATUS_DEVICE_DOES_NOT_EXIST}, {
++ ERRDOS, 56, NT_STATUS_TOO_MANY_COMMANDS}, {
++ ERRDOS, 57, NT_STATUS_ADAPTER_HARDWARE_ERROR}, {
++ ERRDOS, 58, NT_STATUS_INVALID_NETWORK_RESPONSE}, {
++ ERRDOS, 59, NT_STATUS_UNEXPECTED_NETWORK_ERROR}, {
++ ERRDOS, 60, NT_STATUS_BAD_REMOTE_ADAPTER}, {
++ ERRDOS, 61, NT_STATUS_PRINT_QUEUE_FULL}, {
++ ERRDOS, 62, NT_STATUS_NO_SPOOL_SPACE}, {
++ ERRDOS, 63, NT_STATUS_PRINT_CANCELLED}, {
++ ERRDOS, 64, NT_STATUS_NETWORK_NAME_DELETED}, {
++ ERRDOS, 65, NT_STATUS_NETWORK_ACCESS_DENIED}, {
++ ERRDOS, 66, NT_STATUS_BAD_DEVICE_TYPE}, {
++ ERRDOS, ERRnosuchshare, NT_STATUS_BAD_NETWORK_NAME}, {
++ ERRDOS, 68, NT_STATUS_TOO_MANY_NAMES}, {
++ ERRDOS, 69, NT_STATUS_TOO_MANY_SESSIONS}, {
++ ERRDOS, 70, NT_STATUS_SHARING_PAUSED}, {
++ ERRDOS, 71, NT_STATUS_REQUEST_NOT_ACCEPTED}, {
++ ERRDOS, 72, NT_STATUS_REDIRECTOR_PAUSED}, {
++ ERRDOS, 88, NT_STATUS_NET_WRITE_FAULT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PROFILING_AT_LIMIT}, {
++ ERRDOS, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_FILE_RENAMED}, {
++ ERRDOS, 240, NT_STATUS_VIRTUAL_CIRCUIT_CLOSED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_SECURITY_ON_OBJECT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CANT_WAIT}, {
++ ERRDOS, ERRpipeclosing, NT_STATUS_PIPE_EMPTY}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CANT_ACCESS_DOMAIN_INFO}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CANT_TERMINATE_SELF}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_SERVER_STATE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_STATE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_DOMAIN_ROLE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_DOMAIN}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_EXISTS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_LIMIT_EXCEEDED}, {
++ ERRDOS, 300, NT_STATUS_OPLOCK_NOT_GRANTED}, {
++ ERRDOS, 301, NT_STATUS_INVALID_OPLOCK_PROTOCOL}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_CORRUPTION}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_ERROR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_GENERIC_NOT_MAPPED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_BAD_DESCRIPTOR_FORMAT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_USER_BUFFER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_IO_ERROR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_CREATE_ERR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_MAP_ERROR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_UNEXPECTED_MM_EXTEND_ERR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NOT_LOGON_PROCESS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_EXISTS}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_1}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_2}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_3}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_4}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_5}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_6}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_7}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_8}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_9}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_10}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_11}, {
++ ERRDOS, 87, NT_STATUS_INVALID_PARAMETER_12}, {
++ ERRDOS, ERRbadpath, NT_STATUS_REDIRECTOR_NOT_STARTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_REDIRECTOR_STARTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_PACKAGE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_BAD_FUNCTION_TABLE}, {
++ ERRDOS, 203, 0xc0000100}, {
++ ERRDOS, 145, NT_STATUS_DIRECTORY_NOT_EMPTY}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FILE_CORRUPT_ERROR}, {
++ ERRDOS, 267, NT_STATUS_NOT_A_DIRECTORY}, {
++ ERRHRD, ERRgeneral, NT_STATUS_BAD_LOGON_SESSION_STATE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_LOGON_SESSION_COLLISION}, {
++ ERRDOS, 206, NT_STATUS_NAME_TOO_LONG}, {
++ ERRDOS, 2401, NT_STATUS_FILES_OPEN}, {
++ ERRDOS, 2404, NT_STATUS_CONNECTION_IN_USE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_MESSAGE_NOT_FOUND}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_PROCESS_IS_TERMINATING}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_LOGON_TYPE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_GUID_TRANSLATION}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CANNOT_IMPERSONATE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_IMAGE_ALREADY_LOADED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_PRESENT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_NOT_EXIST}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_LID_ALREADY_OWNED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_NOT_LID_OWNER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_COMMAND}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_LID}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ABIOS_INVALID_SELECTOR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_LDT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_SIZE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_OFFSET}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_LDT_DESCRIPTOR}, {
++ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NE_FORMAT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_RXACT_INVALID_STATE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_RXACT_COMMIT_FAILURE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_MAPPED_FILE_SIZE_ZERO}, {
++ ERRDOS, ERRnofids, NT_STATUS_TOO_MANY_OPENED_FILES}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CANCELLED}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_CANNOT_DELETE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_COMPUTER_NAME}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_FILE_DELETED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_ACCOUNT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_GROUP}, {
++ ERRHRD, ERRgeneral, NT_STATUS_SPECIAL_USER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_MEMBERS_PRIMARY_GROUP}, {
++ ERRDOS, ERRbadfid, NT_STATUS_FILE_CLOSED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_THREADS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_THREAD_NOT_IN_PROCESS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_TOKEN_ALREADY_IN_USE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_QUOTA_EXCEEDED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_COMMITMENT_LIMIT}, {
++ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_LE_FORMAT}, {
++ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_NOT_MZ}, {
++ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_PROTECT}, {
++ ERRDOS, 193, NT_STATUS_INVALID_IMAGE_WIN_16}, {
++ ERRHRD, ERRgeneral, NT_STATUS_LOGON_SERVER_CONFLICT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_TIME_DIFFERENCE_AT_DC}, {
++ ERRHRD, ERRgeneral, NT_STATUS_SYNCHRONIZATION_REQUIRED}, {
++ ERRDOS, 126, NT_STATUS_DLL_NOT_FOUND}, {
++ ERRHRD, ERRgeneral, NT_STATUS_OPEN_FAILED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_IO_PRIVILEGE_FAILED}, {
++ ERRDOS, 182, NT_STATUS_ORDINAL_NOT_FOUND}, {
++ ERRDOS, 127, NT_STATUS_ENTRYPOINT_NOT_FOUND}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CONTROL_C_EXIT}, {
++ ERRDOS, 64, NT_STATUS_LOCAL_DISCONNECT}, {
++ ERRDOS, 64, NT_STATUS_REMOTE_DISCONNECT}, {
++ ERRDOS, 51, NT_STATUS_REMOTE_RESOURCES}, {
++ ERRDOS, 59, NT_STATUS_LINK_FAILED}, {
++ ERRDOS, 59, NT_STATUS_LINK_TIMEOUT}, {
++ ERRDOS, 59, NT_STATUS_INVALID_CONNECTION}, {
++ ERRDOS, 59, NT_STATUS_INVALID_ADDRESS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DLL_INIT_FAILED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_MISSING_SYSTEMFILE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_UNHANDLED_EXCEPTION}, {
++ ERRHRD, ERRgeneral, NT_STATUS_APP_INIT_FAILURE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_CREATE_FAILED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_PAGEFILE}, {
++ ERRDOS, 124, NT_STATUS_INVALID_LEVEL}, {
++ ERRDOS, 86, NT_STATUS_WRONG_PASSWORD_CORE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_FLOAT_CONTEXT}, {
++ ERRDOS, 109, NT_STATUS_PIPE_BROKEN}, {
++ ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_CORRUPT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_IO_FAILED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_EVENT_PAIR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_VOLUME}, {
++ ERRHRD, ERRgeneral, NT_STATUS_SERIAL_NO_DEVICE_INITED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_ALIAS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_ALIAS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_ALIAS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ALIAS_EXISTS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_LOGON_NOT_GRANTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SECRETS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_SECRET_TOO_LONG}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INTERNAL_DB_ERROR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FULLSCREEN_MODE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_CONTEXT_IDS}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_LOGON_TYPE_NOT_GRANTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NOT_REGISTRY_FILE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FT_MISSING_MEMBER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ILL_FORMED_SERVICE_ENTRY}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_CHARACTER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_UNMAPPABLE_CHARACTER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_UNDEFINED_CHARACTER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_VOLUME}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_WRONG_CYLINDER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_UNKNOWN_ERROR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FLOPPY_BAD_REGISTERS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DISK_RECALIBRATE_FAILED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DISK_OPERATION_FAILED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DISK_RESET_FAILED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_SHARED_IRQ_BUSY}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FT_ORPHANING}, {
++ ERRHRD, ERRgeneral, 0xc000016e}, {
++ ERRHRD, ERRgeneral, 0xc000016f}, {
++ ERRHRD, ERRgeneral, 0xc0000170}, {
++ ERRHRD, ERRgeneral, 0xc0000171}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PARTITION_FAILURE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_BLOCK_LENGTH}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DEVICE_NOT_PARTITIONED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_LOCK_MEDIA}, {
++ ERRHRD, ERRgeneral, NT_STATUS_UNABLE_TO_UNLOAD_MEDIA}, {
++ ERRHRD, ERRgeneral, NT_STATUS_EOM_OVERFLOW}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_MEDIA}, {
++ ERRHRD, ERRgeneral, 0xc0000179}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_MEMBER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_MEMBER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_KEY_DELETED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_LOG_SPACE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_SIDS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_KEY_HAS_CHILDREN}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CHILD_MUST_BE_VOLATILE}, {
++ ERRDOS, 87, NT_STATUS_DEVICE_CONFIGURATION_ERROR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DRIVER_INTERNAL_ERROR}, {
++ ERRDOS, 22, NT_STATUS_INVALID_DEVICE_STATE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DEVICE_PROTOCOL_ERROR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_BACKUP_CONTROLLER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_LOG_FILE_FULL}, {
++ ERRDOS, 19, NT_STATUS_TOO_LATE}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET},
++/* { This NT error code was 'sqashed'
++ from NT_STATUS_NO_TRUST_SAM_ACCOUNT to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
++ during the session setup } */
++ {
++ ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CORRUPT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, {
++ ERRDOS, ERRnetlogonNotStarted, NT_STATUS_NETLOGON_NOT_STARTED}, {
++ ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CHANGED}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
++/* { This NT error code was 'sqashed'
++ from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE
++ during the session setup } */
++ {
++ ERRDOS, ERRnoaccess, NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FS_DRIVER_REQUIRED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_USER_SESSION_KEY}, {
++ ERRDOS, 59, NT_STATUS_USER_SESSION_DELETED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_RESOURCE_LANG_NOT_FOUND}, {
++ ERRDOS, ERRnomem, NT_STATUS_INSUFF_SERVER_RESOURCES}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_BUFFER_SIZE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_COMPONENT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_ADDRESS_WILDCARD}, {
++ ERRDOS, 68, NT_STATUS_TOO_MANY_ADDRESSES}, {
++ ERRDOS, 52, NT_STATUS_ADDRESS_ALREADY_EXISTS}, {
++ ERRDOS, 64, NT_STATUS_ADDRESS_CLOSED}, {
++ ERRDOS, 64, NT_STATUS_CONNECTION_DISCONNECTED}, {
++ ERRDOS, 64, NT_STATUS_CONNECTION_RESET}, {
++ ERRDOS, 68, NT_STATUS_TOO_MANY_NODES}, {
++ ERRDOS, 59, NT_STATUS_TRANSACTION_ABORTED}, {
++ ERRDOS, 59, NT_STATUS_TRANSACTION_TIMED_OUT}, {
++ ERRDOS, 59, NT_STATUS_TRANSACTION_NO_RELEASE}, {
++ ERRDOS, 59, NT_STATUS_TRANSACTION_NO_MATCH}, {
++ ERRDOS, 59, NT_STATUS_TRANSACTION_RESPONDED}, {
++ ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_ID}, {
++ ERRDOS, 59, NT_STATUS_TRANSACTION_INVALID_TYPE}, {
++ ERRDOS, ERRunsup, NT_STATUS_NOT_SERVER_SESSION}, {
++ ERRDOS, ERRunsup, NT_STATUS_NOT_CLIENT_SESSION}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CANNOT_LOAD_REGISTRY_FILE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DEBUG_ATTACH_FAILED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_SYSTEM_PROCESS_TERMINATED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DATA_NOT_ACCEPTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_BROWSER_SERVERS_FOUND}, {
++ ERRHRD, ERRgeneral, NT_STATUS_VDM_HARD_ERROR}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DRIVER_CANCEL_TIMEOUT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_REPLY_MESSAGE_MISMATCH}, {
++ ERRHRD, ERRgeneral, NT_STATUS_MAPPED_ALIGNMENT}, {
++ ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, {
++ ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, {
++ ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, {
++ ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_STACK_OVERFLOW_READ}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FAIL_CHECK}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DUPLICATE_OBJECTID}, {
++ ERRHRD, ERRgeneral, NT_STATUS_OBJECTID_EXISTS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CONVERT_TO_LARGE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_RETRY}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FOUND_OUT_OF_SCOPE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ALLOCATE_BUCKET}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PROPSET_NOT_FOUND}, {
++ ERRHRD, ERRgeneral, NT_STATUS_MARSHALL_OVERFLOW}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_VARIANT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND}, {
++ ERRDOS, ERRnoaccess, NT_STATUS_ACCOUNT_LOCKED_OUT}, {
++ ERRDOS, ERRbadfid, NT_STATUS_HANDLE_NOT_CLOSABLE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_REFUSED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_GRACEFUL_DISCONNECT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_ALREADY_ASSOCIATED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_ADDRESS_NOT_ASSOCIATED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_INVALID}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ACTIVE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NETWORK_UNREACHABLE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_HOST_UNREACHABLE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PROTOCOL_UNREACHABLE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PORT_UNREACHABLE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_REQUEST_ABORTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_ABORTED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_BAD_COMPRESSION_BUFFER}, {
++ ERRHRD, ERRgeneral, NT_STATUS_USER_MAPPED_FILE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_AUDIT_FAILED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_TIMER_RESOLUTION_NOT_SET}, {
++ ERRHRD, ERRgeneral, NT_STATUS_CONNECTION_COUNT_LIMIT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_LOGIN_TIME_RESTRICTION}, {
++ ERRHRD, ERRgeneral, NT_STATUS_LOGIN_WKSTA_RESTRICTION}, {
++ ERRDOS, 193, NT_STATUS_IMAGE_MP_UP_MISMATCH}, {
++ ERRHRD, ERRgeneral, 0xc000024a}, {
++ ERRHRD, ERRgeneral, 0xc000024b}, {
++ ERRHRD, ERRgeneral, 0xc000024c}, {
++ ERRHRD, ERRgeneral, 0xc000024d}, {
++ ERRHRD, ERRgeneral, 0xc000024e}, {
++ ERRHRD, ERRgeneral, 0xc000024f}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INSUFFICIENT_LOGON_INFO}, {
++ ERRHRD, ERRgeneral, NT_STATUS_BAD_DLL_ENTRYPOINT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_BAD_SERVICE_ENTRYPOINT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_LPC_REPLY_LOST}, {
++ ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT1}, {
++ ERRHRD, ERRgeneral, NT_STATUS_IP_ADDRESS_CONFLICT2}, {
++ ERRHRD, ERRgeneral, NT_STATUS_REGISTRY_QUOTA_LIMIT}, {
++ ERRSRV, 3, NT_STATUS_PATH_NOT_COVERED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_NO_CALLBACK_ACTIVE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_LICENSE_QUOTA_EXCEEDED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_SHORT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PWD_TOO_RECENT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PWD_HISTORY_CONFLICT}, {
++ ERRHRD, ERRgeneral, 0xc000025d}, {
++ ERRHRD, ERRgeneral, NT_STATUS_PLUGPLAY_NO_DEVICE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_UNSUPPORTED_COMPRESSION}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_HW_PROFILE}, {
++ ERRHRD, ERRgeneral, NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH}, {
++ ERRDOS, 182, NT_STATUS_DRIVER_ORDINAL_NOT_FOUND}, {
++ ERRDOS, 127, NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND}, {
++ ERRDOS, 288, NT_STATUS_RESOURCE_NOT_OWNED}, {
++ ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LINKS}, {
++ ERRHRD, ERRgeneral, NT_STATUS_QUOTA_LIST_INCONSISTENT}, {
++ ERRHRD, ERRgeneral, NT_STATUS_FILE_IS_OFFLINE}, {
++ ERRDOS, 21, 0xc000026e}, {
++ ERRDOS, 161, 0xc0000281}, {
++ ERRDOS, ERRnoaccess, 0xc000028a}, {
++ ERRDOS, ERRnoaccess, 0xc000028b}, {
++ ERRHRD, ERRgeneral, 0xc000028c}, {
++ ERRDOS, ERRnoaccess, 0xc000028d}, {
++ ERRDOS, ERRnoaccess, 0xc000028e}, {
++ ERRDOS, ERRnoaccess, 0xc000028f}, {
++ ERRDOS, ERRnoaccess, 0xc0000290}, {
++ERRDOS, ERRbadfunc, 0xc000029c},};
++
++/*****************************************************************************
++ Print an error message from the status code
++ *****************************************************************************/
++static void
++cifs_print_status(__u32 status_code)
++{
++ int idx = 0;
++
++ while (nt_errs[idx].nt_errstr != NULL) {
++ if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) ==
++ (status_code & 0xFFFFFF)) {
++ printk(KERN_NOTICE "Status code returned 0x%08x %s\n",
++ status_code,nt_errs[idx].nt_errstr);
++ }
++ idx++;
++ }
++ return;
++}
++
++
++static void
++ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode)
++{
++ int i;
++ if (ntstatus == 0) {
++ *eclass = 0;
++ *ecode = 0;
++ return;
++ }
++ for (i = 0; ntstatus_to_dos_map[i].ntstatus; i++) {
++ if (ntstatus == ntstatus_to_dos_map[i].ntstatus) {
++ *eclass = ntstatus_to_dos_map[i].dos_class;
++ *ecode = ntstatus_to_dos_map[i].dos_code;
++ return;
++ }
++ }
++ *eclass = ERRHRD;
++ *ecode = ERRgeneral;
++}
++
++int
++map_smb_to_linux_error(struct smb_hdr *smb)
++{
++ unsigned int i;
++ int rc = -EIO; /* if transport error smb error may not be set */
++ __u8 smberrclass;
++ __u16 smberrcode;
++
++ /* BB if NT Status codes - map NT BB */
++
++ /* old style smb error codes */
++ if (smb->Status.CifsError == 0)
++ return 0;
++
++ if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
++ /* translate the newer STATUS codes to old style errors and then to POSIX errors */
++ smb->Status.CifsError = le32_to_cpu(smb->Status.CifsError);
++ if(cifsFYI)
++ cifs_print_status(smb->Status.CifsError);
++ ntstatus_to_dos(smb->Status.CifsError, &smberrclass,
++ &smberrcode);
++ } else {
++ smberrclass = smb->Status.DosError.ErrorClass;
++ smb->Status.DosError.Error =
++ le16_to_cpu(smb->Status.DosError.Error);
++ smberrcode = smb->Status.DosError.Error;
++ }
++
++ /* old style errors */
++
++ /* DOS class smb error codes - map DOS */
++ if (smberrclass == ERRDOS) { /* one byte field no need to byte reverse */
++ for (i = 0;
++ i <
++ sizeof (mapping_table_ERRDOS) /
++ sizeof (struct smb_to_posix_error); i++) {
++ if (mapping_table_ERRDOS[i].smb_err == 0)
++ break;
++ else if (mapping_table_ERRDOS[i].smb_err == smberrcode) {
++ rc = mapping_table_ERRDOS[i].posix_code;
++ break;
++ }
++ /* else try the next error mapping one to see if it will match */
++ }
++ } else if (smberrclass == ERRSRV) { /* server class of error codes */
++ for (i = 0;
++ i <
++ sizeof (mapping_table_ERRSRV) /
++ sizeof (struct smb_to_posix_error); i++) {
++ if (mapping_table_ERRSRV[i].smb_err == 0)
++ break;
++ else if (mapping_table_ERRSRV[i].smb_err == smberrcode) {
++ rc = mapping_table_ERRSRV[i].posix_code;
++ break;
++ }
++ /* else try the next error mapping one to see if it will match */
++ }
++ }
++ /* else ERRHRD class errors or junk - return EIO */
++
++ cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!", smberrcode,rc));
++
++ /* generic corrective action e.g. reconnect SMB session on ERRbaduid could be added */
++
++ return rc;
++}
++
++/*
++ * calculate the size of the SMB message based on the fixed header
++ * portion, the number of word parameters and the data portion of the message
++ */
++unsigned int
++smbCalcSize(struct smb_hdr *ptr)
++{
++ return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) +
++ BCC(ptr));
++}
++
++/* The following are taken from fs/ntfs/util.c */
++
++#define NTFS_TIME_OFFSET ((u64)(369*365 + 89) * 24 * 3600 * 10000000)
++
++ /*
++ * Convert the NT UTC (based 1601-01-01, in hundred nanosecond units)
++ * into Unix UTC (based 1970-01-01, in seconds).
++ */
++time_t
++cifs_NTtimeToUnix(__u64 ntutc)
++{
++ /* BB what about the timezone? BB */
++
++ /* Subtract the NTFS time offset, then convert to 1s intervals. */
++ u64 t;
++
++ t = ntutc - NTFS_TIME_OFFSET;
++ do_div(t, 10000000);
++ return (time_t)t;
++}
++
++/* Convert the Unix UTC into NT UTC. */
++__u64
++cifs_UnixTimeToNT(time_t t)
++{
++ __u64 dce_time;
++ /* Convert to 100ns intervals and then add the NTFS time offset. */
++ dce_time = (__u64) t * 10000000;
++ dce_time += NTFS_TIME_OFFSET;
++ return dce_time;
++}
+diff -urN linux-2.4.29.old/fs/cifs/nterr.c linux-2.4.29/fs/cifs/nterr.c
+--- linux-2.4.29.old/fs/cifs/nterr.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/nterr.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,687 @@
++/*
++ * Unix SMB/Netbios implementation.
++ * Version 1.9.
++ * RPC Pipe client / server routines
++ * Copyright (C) Luke Kenneth Casson Leighton 1997-2001.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++/* NT error codes - see nterr.h */
++#include <linux/types.h>
++#include <linux/fs.h>
++#include "nterr.h"
++
++const struct nt_err_code_struct nt_errs[] = {
++ {"NT_STATUS_OK", NT_STATUS_OK},
++ {"NT_STATUS_UNSUCCESSFUL", NT_STATUS_UNSUCCESSFUL},
++ {"NT_STATUS_NOT_IMPLEMENTED", NT_STATUS_NOT_IMPLEMENTED},
++ {"NT_STATUS_INVALID_INFO_CLASS", NT_STATUS_INVALID_INFO_CLASS},
++ {"NT_STATUS_INFO_LENGTH_MISMATCH", NT_STATUS_INFO_LENGTH_MISMATCH},
++ {"NT_STATUS_ACCESS_VIOLATION", NT_STATUS_ACCESS_VIOLATION},
++ {"STATUS_BUFFER_OVERFLOW", STATUS_BUFFER_OVERFLOW},
++ {"NT_STATUS_IN_PAGE_ERROR", NT_STATUS_IN_PAGE_ERROR},
++ {"NT_STATUS_PAGEFILE_QUOTA", NT_STATUS_PAGEFILE_QUOTA},
++ {"NT_STATUS_INVALID_HANDLE", NT_STATUS_INVALID_HANDLE},
++ {"NT_STATUS_BAD_INITIAL_STACK", NT_STATUS_BAD_INITIAL_STACK},
++ {"NT_STATUS_BAD_INITIAL_PC", NT_STATUS_BAD_INITIAL_PC},
++ {"NT_STATUS_INVALID_CID", NT_STATUS_INVALID_CID},
++ {"NT_STATUS_TIMER_NOT_CANCELED", NT_STATUS_TIMER_NOT_CANCELED},
++ {"NT_STATUS_INVALID_PARAMETER", NT_STATUS_INVALID_PARAMETER},
++ {"NT_STATUS_NO_SUCH_DEVICE", NT_STATUS_NO_SUCH_DEVICE},
++ {"NT_STATUS_NO_SUCH_FILE", NT_STATUS_NO_SUCH_FILE},
++ {"NT_STATUS_INVALID_DEVICE_REQUEST",
++ NT_STATUS_INVALID_DEVICE_REQUEST},
++ {"NT_STATUS_END_OF_FILE", NT_STATUS_END_OF_FILE},
++ {"NT_STATUS_WRONG_VOLUME", NT_STATUS_WRONG_VOLUME},
++ {"NT_STATUS_NO_MEDIA_IN_DEVICE", NT_STATUS_NO_MEDIA_IN_DEVICE},
++ {"NT_STATUS_UNRECOGNIZED_MEDIA", NT_STATUS_UNRECOGNIZED_MEDIA},
++ {"NT_STATUS_NONEXISTENT_SECTOR", NT_STATUS_NONEXISTENT_SECTOR},
++ {"NT_STATUS_MORE_PROCESSING_REQUIRED",
++ NT_STATUS_MORE_PROCESSING_REQUIRED},
++ {"NT_STATUS_NO_MEMORY", NT_STATUS_NO_MEMORY},
++ {"NT_STATUS_CONFLICTING_ADDRESSES",
++ NT_STATUS_CONFLICTING_ADDRESSES},
++ {"NT_STATUS_NOT_MAPPED_VIEW", NT_STATUS_NOT_MAPPED_VIEW},
++ {"NT_STATUS_UNABLE_TO_FREE_VM", NT_STATUS_UNABLE_TO_FREE_VM},
++ {"NT_STATUS_UNABLE_TO_DELETE_SECTION",
++ NT_STATUS_UNABLE_TO_DELETE_SECTION},
++ {"NT_STATUS_INVALID_SYSTEM_SERVICE",
++ NT_STATUS_INVALID_SYSTEM_SERVICE},
++ {"NT_STATUS_ILLEGAL_INSTRUCTION", NT_STATUS_ILLEGAL_INSTRUCTION},
++ {"NT_STATUS_INVALID_LOCK_SEQUENCE",
++ NT_STATUS_INVALID_LOCK_SEQUENCE},
++ {"NT_STATUS_INVALID_VIEW_SIZE", NT_STATUS_INVALID_VIEW_SIZE},
++ {"NT_STATUS_INVALID_FILE_FOR_SECTION",
++ NT_STATUS_INVALID_FILE_FOR_SECTION},
++ {"NT_STATUS_ALREADY_COMMITTED", NT_STATUS_ALREADY_COMMITTED},
++ {"NT_STATUS_ACCESS_DENIED", NT_STATUS_ACCESS_DENIED},
++ {"NT_STATUS_BUFFER_TOO_SMALL", NT_STATUS_BUFFER_TOO_SMALL},
++ {"NT_STATUS_OBJECT_TYPE_MISMATCH", NT_STATUS_OBJECT_TYPE_MISMATCH},
++ {"NT_STATUS_NONCONTINUABLE_EXCEPTION",
++ NT_STATUS_NONCONTINUABLE_EXCEPTION},
++ {"NT_STATUS_INVALID_DISPOSITION", NT_STATUS_INVALID_DISPOSITION},
++ {"NT_STATUS_UNWIND", NT_STATUS_UNWIND},
++ {"NT_STATUS_BAD_STACK", NT_STATUS_BAD_STACK},
++ {"NT_STATUS_INVALID_UNWIND_TARGET",
++ NT_STATUS_INVALID_UNWIND_TARGET},
++ {"NT_STATUS_NOT_LOCKED", NT_STATUS_NOT_LOCKED},
++ {"NT_STATUS_PARITY_ERROR", NT_STATUS_PARITY_ERROR},
++ {"NT_STATUS_UNABLE_TO_DECOMMIT_VM",
++ NT_STATUS_UNABLE_TO_DECOMMIT_VM},
++ {"NT_STATUS_NOT_COMMITTED", NT_STATUS_NOT_COMMITTED},
++ {"NT_STATUS_INVALID_PORT_ATTRIBUTES",
++ NT_STATUS_INVALID_PORT_ATTRIBUTES},
++ {"NT_STATUS_PORT_MESSAGE_TOO_LONG",
++ NT_STATUS_PORT_MESSAGE_TOO_LONG},
++ {"NT_STATUS_INVALID_PARAMETER_MIX",
++ NT_STATUS_INVALID_PARAMETER_MIX},
++ {"NT_STATUS_INVALID_QUOTA_LOWER", NT_STATUS_INVALID_QUOTA_LOWER},
++ {"NT_STATUS_DISK_CORRUPT_ERROR", NT_STATUS_DISK_CORRUPT_ERROR},
++ {"NT_STATUS_OBJECT_NAME_INVALID", NT_STATUS_OBJECT_NAME_INVALID},
++ {"NT_STATUS_OBJECT_NAME_NOT_FOUND",
++ NT_STATUS_OBJECT_NAME_NOT_FOUND},
++ {"NT_STATUS_OBJECT_NAME_COLLISION",
++ NT_STATUS_OBJECT_NAME_COLLISION},
++ {"NT_STATUS_HANDLE_NOT_WAITABLE", NT_STATUS_HANDLE_NOT_WAITABLE},
++ {"NT_STATUS_PORT_DISCONNECTED", NT_STATUS_PORT_DISCONNECTED},
++ {"NT_STATUS_DEVICE_ALREADY_ATTACHED",
++ NT_STATUS_DEVICE_ALREADY_ATTACHED},
++ {"NT_STATUS_OBJECT_PATH_INVALID", NT_STATUS_OBJECT_PATH_INVALID},
++ {"NT_STATUS_OBJECT_PATH_NOT_FOUND",
++ NT_STATUS_OBJECT_PATH_NOT_FOUND},
++ {"NT_STATUS_OBJECT_PATH_SYNTAX_BAD",
++ NT_STATUS_OBJECT_PATH_SYNTAX_BAD},
++ {"NT_STATUS_DATA_OVERRUN", NT_STATUS_DATA_OVERRUN},
++ {"NT_STATUS_DATA_LATE_ERROR", NT_STATUS_DATA_LATE_ERROR},
++ {"NT_STATUS_DATA_ERROR", NT_STATUS_DATA_ERROR},
++ {"NT_STATUS_CRC_ERROR", NT_STATUS_CRC_ERROR},
++ {"NT_STATUS_SECTION_TOO_BIG", NT_STATUS_SECTION_TOO_BIG},
++ {"NT_STATUS_PORT_CONNECTION_REFUSED",
++ NT_STATUS_PORT_CONNECTION_REFUSED},
++ {"NT_STATUS_INVALID_PORT_HANDLE", NT_STATUS_INVALID_PORT_HANDLE},
++ {"NT_STATUS_SHARING_VIOLATION", NT_STATUS_SHARING_VIOLATION},
++ {"NT_STATUS_QUOTA_EXCEEDED", NT_STATUS_QUOTA_EXCEEDED},
++ {"NT_STATUS_INVALID_PAGE_PROTECTION",
++ NT_STATUS_INVALID_PAGE_PROTECTION},
++ {"NT_STATUS_MUTANT_NOT_OWNED", NT_STATUS_MUTANT_NOT_OWNED},
++ {"NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED",
++ NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
++ {"NT_STATUS_PORT_ALREADY_SET", NT_STATUS_PORT_ALREADY_SET},
++ {"NT_STATUS_SECTION_NOT_IMAGE", NT_STATUS_SECTION_NOT_IMAGE},
++ {"NT_STATUS_SUSPEND_COUNT_EXCEEDED",
++ NT_STATUS_SUSPEND_COUNT_EXCEEDED},
++ {"NT_STATUS_THREAD_IS_TERMINATING",
++ NT_STATUS_THREAD_IS_TERMINATING},
++ {"NT_STATUS_BAD_WORKING_SET_LIMIT",
++ NT_STATUS_BAD_WORKING_SET_LIMIT},
++ {"NT_STATUS_INCOMPATIBLE_FILE_MAP",
++ NT_STATUS_INCOMPATIBLE_FILE_MAP},
++ {"NT_STATUS_SECTION_PROTECTION", NT_STATUS_SECTION_PROTECTION},
++ {"NT_STATUS_EAS_NOT_SUPPORTED", NT_STATUS_EAS_NOT_SUPPORTED},
++ {"NT_STATUS_EA_TOO_LARGE", NT_STATUS_EA_TOO_LARGE},
++ {"NT_STATUS_NONEXISTENT_EA_ENTRY", NT_STATUS_NONEXISTENT_EA_ENTRY},
++ {"NT_STATUS_NO_EAS_ON_FILE", NT_STATUS_NO_EAS_ON_FILE},
++ {"NT_STATUS_EA_CORRUPT_ERROR", NT_STATUS_EA_CORRUPT_ERROR},
++ {"NT_STATUS_FILE_LOCK_CONFLICT", NT_STATUS_FILE_LOCK_CONFLICT},
++ {"NT_STATUS_LOCK_NOT_GRANTED", NT_STATUS_LOCK_NOT_GRANTED},
++ {"NT_STATUS_DELETE_PENDING", NT_STATUS_DELETE_PENDING},
++ {"NT_STATUS_CTL_FILE_NOT_SUPPORTED",
++ NT_STATUS_CTL_FILE_NOT_SUPPORTED},
++ {"NT_STATUS_UNKNOWN_REVISION", NT_STATUS_UNKNOWN_REVISION},
++ {"NT_STATUS_REVISION_MISMATCH", NT_STATUS_REVISION_MISMATCH},
++ {"NT_STATUS_INVALID_OWNER", NT_STATUS_INVALID_OWNER},
++ {"NT_STATUS_INVALID_PRIMARY_GROUP",
++ NT_STATUS_INVALID_PRIMARY_GROUP},
++ {"NT_STATUS_NO_IMPERSONATION_TOKEN",
++ NT_STATUS_NO_IMPERSONATION_TOKEN},
++ {"NT_STATUS_CANT_DISABLE_MANDATORY",
++ NT_STATUS_CANT_DISABLE_MANDATORY},
++ {"NT_STATUS_NO_LOGON_SERVERS", NT_STATUS_NO_LOGON_SERVERS},
++ {"NT_STATUS_NO_SUCH_LOGON_SESSION",
++ NT_STATUS_NO_SUCH_LOGON_SESSION},
++ {"NT_STATUS_NO_SUCH_PRIVILEGE", NT_STATUS_NO_SUCH_PRIVILEGE},
++ {"NT_STATUS_PRIVILEGE_NOT_HELD", NT_STATUS_PRIVILEGE_NOT_HELD},
++ {"NT_STATUS_INVALID_ACCOUNT_NAME", NT_STATUS_INVALID_ACCOUNT_NAME},
++ {"NT_STATUS_USER_EXISTS", NT_STATUS_USER_EXISTS},
++ {"NT_STATUS_NO_SUCH_USER", NT_STATUS_NO_SUCH_USER},
++ {"NT_STATUS_GROUP_EXISTS", NT_STATUS_GROUP_EXISTS},
++ {"NT_STATUS_NO_SUCH_GROUP", NT_STATUS_NO_SUCH_GROUP},
++ {"NT_STATUS_MEMBER_IN_GROUP", NT_STATUS_MEMBER_IN_GROUP},
++ {"NT_STATUS_MEMBER_NOT_IN_GROUP", NT_STATUS_MEMBER_NOT_IN_GROUP},
++ {"NT_STATUS_LAST_ADMIN", NT_STATUS_LAST_ADMIN},
++ {"NT_STATUS_WRONG_PASSWORD", NT_STATUS_WRONG_PASSWORD},
++ {"NT_STATUS_ILL_FORMED_PASSWORD", NT_STATUS_ILL_FORMED_PASSWORD},
++ {"NT_STATUS_PASSWORD_RESTRICTION", NT_STATUS_PASSWORD_RESTRICTION},
++ {"NT_STATUS_LOGON_FAILURE", NT_STATUS_LOGON_FAILURE},
++ {"NT_STATUS_ACCOUNT_RESTRICTION", NT_STATUS_ACCOUNT_RESTRICTION},
++ {"NT_STATUS_INVALID_LOGON_HOURS", NT_STATUS_INVALID_LOGON_HOURS},
++ {"NT_STATUS_INVALID_WORKSTATION", NT_STATUS_INVALID_WORKSTATION},
++ {"NT_STATUS_PASSWORD_EXPIRED", NT_STATUS_PASSWORD_EXPIRED},
++ {"NT_STATUS_ACCOUNT_DISABLED", NT_STATUS_ACCOUNT_DISABLED},
++ {"NT_STATUS_NONE_MAPPED", NT_STATUS_NONE_MAPPED},
++ {"NT_STATUS_TOO_MANY_LUIDS_REQUESTED",
++ NT_STATUS_TOO_MANY_LUIDS_REQUESTED},
++ {"NT_STATUS_LUIDS_EXHAUSTED", NT_STATUS_LUIDS_EXHAUSTED},
++ {"NT_STATUS_INVALID_SUB_AUTHORITY",
++ NT_STATUS_INVALID_SUB_AUTHORITY},
++ {"NT_STATUS_INVALID_ACL", NT_STATUS_INVALID_ACL},
++ {"NT_STATUS_INVALID_SID", NT_STATUS_INVALID_SID},
++ {"NT_STATUS_INVALID_SECURITY_DESCR",
++ NT_STATUS_INVALID_SECURITY_DESCR},
++ {"NT_STATUS_PROCEDURE_NOT_FOUND", NT_STATUS_PROCEDURE_NOT_FOUND},
++ {"NT_STATUS_INVALID_IMAGE_FORMAT", NT_STATUS_INVALID_IMAGE_FORMAT},
++ {"NT_STATUS_NO_TOKEN", NT_STATUS_NO_TOKEN},
++ {"NT_STATUS_BAD_INHERITANCE_ACL", NT_STATUS_BAD_INHERITANCE_ACL},
++ {"NT_STATUS_RANGE_NOT_LOCKED", NT_STATUS_RANGE_NOT_LOCKED},
++ {"NT_STATUS_DISK_FULL", NT_STATUS_DISK_FULL},
++ {"NT_STATUS_SERVER_DISABLED", NT_STATUS_SERVER_DISABLED},
++ {"NT_STATUS_SERVER_NOT_DISABLED", NT_STATUS_SERVER_NOT_DISABLED},
++ {"NT_STATUS_TOO_MANY_GUIDS_REQUESTED",
++ NT_STATUS_TOO_MANY_GUIDS_REQUESTED},
++ {"NT_STATUS_GUIDS_EXHAUSTED", NT_STATUS_GUIDS_EXHAUSTED},
++ {"NT_STATUS_INVALID_ID_AUTHORITY", NT_STATUS_INVALID_ID_AUTHORITY},
++ {"NT_STATUS_AGENTS_EXHAUSTED", NT_STATUS_AGENTS_EXHAUSTED},
++ {"NT_STATUS_INVALID_VOLUME_LABEL", NT_STATUS_INVALID_VOLUME_LABEL},
++ {"NT_STATUS_SECTION_NOT_EXTENDED", NT_STATUS_SECTION_NOT_EXTENDED},
++ {"NT_STATUS_NOT_MAPPED_DATA", NT_STATUS_NOT_MAPPED_DATA},
++ {"NT_STATUS_RESOURCE_DATA_NOT_FOUND",
++ NT_STATUS_RESOURCE_DATA_NOT_FOUND},
++ {"NT_STATUS_RESOURCE_TYPE_NOT_FOUND",
++ NT_STATUS_RESOURCE_TYPE_NOT_FOUND},
++ {"NT_STATUS_RESOURCE_NAME_NOT_FOUND",
++ NT_STATUS_RESOURCE_NAME_NOT_FOUND},
++ {"NT_STATUS_ARRAY_BOUNDS_EXCEEDED",
++ NT_STATUS_ARRAY_BOUNDS_EXCEEDED},
++ {"NT_STATUS_FLOAT_DENORMAL_OPERAND",
++ NT_STATUS_FLOAT_DENORMAL_OPERAND},
++ {"NT_STATUS_FLOAT_DIVIDE_BY_ZERO", NT_STATUS_FLOAT_DIVIDE_BY_ZERO},
++ {"NT_STATUS_FLOAT_INEXACT_RESULT", NT_STATUS_FLOAT_INEXACT_RESULT},
++ {"NT_STATUS_FLOAT_INVALID_OPERATION",
++ NT_STATUS_FLOAT_INVALID_OPERATION},
++ {"NT_STATUS_FLOAT_OVERFLOW", NT_STATUS_FLOAT_OVERFLOW},
++ {"NT_STATUS_FLOAT_STACK_CHECK", NT_STATUS_FLOAT_STACK_CHECK},
++ {"NT_STATUS_FLOAT_UNDERFLOW", NT_STATUS_FLOAT_UNDERFLOW},
++ {"NT_STATUS_INTEGER_DIVIDE_BY_ZERO",
++ NT_STATUS_INTEGER_DIVIDE_BY_ZERO},
++ {"NT_STATUS_INTEGER_OVERFLOW", NT_STATUS_INTEGER_OVERFLOW},
++ {"NT_STATUS_PRIVILEGED_INSTRUCTION",
++ NT_STATUS_PRIVILEGED_INSTRUCTION},
++ {"NT_STATUS_TOO_MANY_PAGING_FILES",
++ NT_STATUS_TOO_MANY_PAGING_FILES},
++ {"NT_STATUS_FILE_INVALID", NT_STATUS_FILE_INVALID},
++ {"NT_STATUS_ALLOTTED_SPACE_EXCEEDED",
++ NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
++ {"NT_STATUS_INSUFFICIENT_RESOURCES",
++ NT_STATUS_INSUFFICIENT_RESOURCES},
++ {"NT_STATUS_DFS_EXIT_PATH_FOUND", NT_STATUS_DFS_EXIT_PATH_FOUND},
++ {"NT_STATUS_DEVICE_DATA_ERROR", NT_STATUS_DEVICE_DATA_ERROR},
++ {"NT_STATUS_DEVICE_NOT_CONNECTED", NT_STATUS_DEVICE_NOT_CONNECTED},
++ {"NT_STATUS_DEVICE_POWER_FAILURE", NT_STATUS_DEVICE_POWER_FAILURE},
++ {"NT_STATUS_FREE_VM_NOT_AT_BASE", NT_STATUS_FREE_VM_NOT_AT_BASE},
++ {"NT_STATUS_MEMORY_NOT_ALLOCATED", NT_STATUS_MEMORY_NOT_ALLOCATED},
++ {"NT_STATUS_WORKING_SET_QUOTA", NT_STATUS_WORKING_SET_QUOTA},
++ {"NT_STATUS_MEDIA_WRITE_PROTECTED",
++ NT_STATUS_MEDIA_WRITE_PROTECTED},
++ {"NT_STATUS_DEVICE_NOT_READY", NT_STATUS_DEVICE_NOT_READY},
++ {"NT_STATUS_INVALID_GROUP_ATTRIBUTES",
++ NT_STATUS_INVALID_GROUP_ATTRIBUTES},
++ {"NT_STATUS_BAD_IMPERSONATION_LEVEL",
++ NT_STATUS_BAD_IMPERSONATION_LEVEL},
++ {"NT_STATUS_CANT_OPEN_ANONYMOUS", NT_STATUS_CANT_OPEN_ANONYMOUS},
++ {"NT_STATUS_BAD_VALIDATION_CLASS", NT_STATUS_BAD_VALIDATION_CLASS},
++ {"NT_STATUS_BAD_TOKEN_TYPE", NT_STATUS_BAD_TOKEN_TYPE},
++ {"NT_STATUS_BAD_MASTER_BOOT_RECORD",
++ NT_STATUS_BAD_MASTER_BOOT_RECORD},
++ {"NT_STATUS_INSTRUCTION_MISALIGNMENT",
++ NT_STATUS_INSTRUCTION_MISALIGNMENT},
++ {"NT_STATUS_INSTANCE_NOT_AVAILABLE",
++ NT_STATUS_INSTANCE_NOT_AVAILABLE},
++ {"NT_STATUS_PIPE_NOT_AVAILABLE", NT_STATUS_PIPE_NOT_AVAILABLE},
++ {"NT_STATUS_INVALID_PIPE_STATE", NT_STATUS_INVALID_PIPE_STATE},
++ {"NT_STATUS_PIPE_BUSY", NT_STATUS_PIPE_BUSY},
++ {"NT_STATUS_ILLEGAL_FUNCTION", NT_STATUS_ILLEGAL_FUNCTION},
++ {"NT_STATUS_PIPE_DISCONNECTED", NT_STATUS_PIPE_DISCONNECTED},
++ {"NT_STATUS_PIPE_CLOSING", NT_STATUS_PIPE_CLOSING},
++ {"NT_STATUS_PIPE_CONNECTED", NT_STATUS_PIPE_CONNECTED},
++ {"NT_STATUS_PIPE_LISTENING", NT_STATUS_PIPE_LISTENING},
++ {"NT_STATUS_INVALID_READ_MODE", NT_STATUS_INVALID_READ_MODE},
++ {"NT_STATUS_IO_TIMEOUT", NT_STATUS_IO_TIMEOUT},
++ {"NT_STATUS_FILE_FORCED_CLOSED", NT_STATUS_FILE_FORCED_CLOSED},
++ {"NT_STATUS_PROFILING_NOT_STARTED",
++ NT_STATUS_PROFILING_NOT_STARTED},
++ {"NT_STATUS_PROFILING_NOT_STOPPED",
++ NT_STATUS_PROFILING_NOT_STOPPED},
++ {"NT_STATUS_COULD_NOT_INTERPRET", NT_STATUS_COULD_NOT_INTERPRET},
++ {"NT_STATUS_FILE_IS_A_DIRECTORY", NT_STATUS_FILE_IS_A_DIRECTORY},
++ {"NT_STATUS_NOT_SUPPORTED", NT_STATUS_NOT_SUPPORTED},
++ {"NT_STATUS_REMOTE_NOT_LISTENING", NT_STATUS_REMOTE_NOT_LISTENING},
++ {"NT_STATUS_DUPLICATE_NAME", NT_STATUS_DUPLICATE_NAME},
++ {"NT_STATUS_BAD_NETWORK_PATH", NT_STATUS_BAD_NETWORK_PATH},
++ {"NT_STATUS_NETWORK_BUSY", NT_STATUS_NETWORK_BUSY},
++ {"NT_STATUS_DEVICE_DOES_NOT_EXIST",
++ NT_STATUS_DEVICE_DOES_NOT_EXIST},
++ {"NT_STATUS_TOO_MANY_COMMANDS", NT_STATUS_TOO_MANY_COMMANDS},
++ {"NT_STATUS_ADAPTER_HARDWARE_ERROR",
++ NT_STATUS_ADAPTER_HARDWARE_ERROR},
++ {"NT_STATUS_INVALID_NETWORK_RESPONSE",
++ NT_STATUS_INVALID_NETWORK_RESPONSE},
++ {"NT_STATUS_UNEXPECTED_NETWORK_ERROR",
++ NT_STATUS_UNEXPECTED_NETWORK_ERROR},
++ {"NT_STATUS_BAD_REMOTE_ADAPTER", NT_STATUS_BAD_REMOTE_ADAPTER},
++ {"NT_STATUS_PRINT_QUEUE_FULL", NT_STATUS_PRINT_QUEUE_FULL},
++ {"NT_STATUS_NO_SPOOL_SPACE", NT_STATUS_NO_SPOOL_SPACE},
++ {"NT_STATUS_PRINT_CANCELLED", NT_STATUS_PRINT_CANCELLED},
++ {"NT_STATUS_NETWORK_NAME_DELETED", NT_STATUS_NETWORK_NAME_DELETED},
++ {"NT_STATUS_NETWORK_ACCESS_DENIED",
++ NT_STATUS_NETWORK_ACCESS_DENIED},
++ {"NT_STATUS_BAD_DEVICE_TYPE", NT_STATUS_BAD_DEVICE_TYPE},
++ {"NT_STATUS_BAD_NETWORK_NAME", NT_STATUS_BAD_NETWORK_NAME},
++ {"NT_STATUS_TOO_MANY_NAMES", NT_STATUS_TOO_MANY_NAMES},
++ {"NT_STATUS_TOO_MANY_SESSIONS", NT_STATUS_TOO_MANY_SESSIONS},
++ {"NT_STATUS_SHARING_PAUSED", NT_STATUS_SHARING_PAUSED},
++ {"NT_STATUS_REQUEST_NOT_ACCEPTED", NT_STATUS_REQUEST_NOT_ACCEPTED},
++ {"NT_STATUS_REDIRECTOR_PAUSED", NT_STATUS_REDIRECTOR_PAUSED},
++ {"NT_STATUS_NET_WRITE_FAULT", NT_STATUS_NET_WRITE_FAULT},
++ {"NT_STATUS_PROFILING_AT_LIMIT", NT_STATUS_PROFILING_AT_LIMIT},
++ {"NT_STATUS_NOT_SAME_DEVICE", NT_STATUS_NOT_SAME_DEVICE},
++ {"NT_STATUS_FILE_RENAMED", NT_STATUS_FILE_RENAMED},
++ {"NT_STATUS_VIRTUAL_CIRCUIT_CLOSED",
++ NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
++ {"NT_STATUS_NO_SECURITY_ON_OBJECT",
++ NT_STATUS_NO_SECURITY_ON_OBJECT},
++ {"NT_STATUS_CANT_WAIT", NT_STATUS_CANT_WAIT},
++ {"NT_STATUS_PIPE_EMPTY", NT_STATUS_PIPE_EMPTY},
++ {"NT_STATUS_CANT_ACCESS_DOMAIN_INFO",
++ NT_STATUS_CANT_ACCESS_DOMAIN_INFO},
++ {"NT_STATUS_CANT_TERMINATE_SELF", NT_STATUS_CANT_TERMINATE_SELF},
++ {"NT_STATUS_INVALID_SERVER_STATE", NT_STATUS_INVALID_SERVER_STATE},
++ {"NT_STATUS_INVALID_DOMAIN_STATE", NT_STATUS_INVALID_DOMAIN_STATE},
++ {"NT_STATUS_INVALID_DOMAIN_ROLE", NT_STATUS_INVALID_DOMAIN_ROLE},
++ {"NT_STATUS_NO_SUCH_DOMAIN", NT_STATUS_NO_SUCH_DOMAIN},
++ {"NT_STATUS_DOMAIN_EXISTS", NT_STATUS_DOMAIN_EXISTS},
++ {"NT_STATUS_DOMAIN_LIMIT_EXCEEDED",
++ NT_STATUS_DOMAIN_LIMIT_EXCEEDED},
++ {"NT_STATUS_OPLOCK_NOT_GRANTED", NT_STATUS_OPLOCK_NOT_GRANTED},
++ {"NT_STATUS_INVALID_OPLOCK_PROTOCOL",
++ NT_STATUS_INVALID_OPLOCK_PROTOCOL},
++ {"NT_STATUS_INTERNAL_DB_CORRUPTION",
++ NT_STATUS_INTERNAL_DB_CORRUPTION},
++ {"NT_STATUS_INTERNAL_ERROR", NT_STATUS_INTERNAL_ERROR},
++ {"NT_STATUS_GENERIC_NOT_MAPPED", NT_STATUS_GENERIC_NOT_MAPPED},
++ {"NT_STATUS_BAD_DESCRIPTOR_FORMAT",
++ NT_STATUS_BAD_DESCRIPTOR_FORMAT},
++ {"NT_STATUS_INVALID_USER_BUFFER", NT_STATUS_INVALID_USER_BUFFER},
++ {"NT_STATUS_UNEXPECTED_IO_ERROR", NT_STATUS_UNEXPECTED_IO_ERROR},
++ {"NT_STATUS_UNEXPECTED_MM_CREATE_ERR",
++ NT_STATUS_UNEXPECTED_MM_CREATE_ERR},
++ {"NT_STATUS_UNEXPECTED_MM_MAP_ERROR",
++ NT_STATUS_UNEXPECTED_MM_MAP_ERROR},
++ {"NT_STATUS_UNEXPECTED_MM_EXTEND_ERR",
++ NT_STATUS_UNEXPECTED_MM_EXTEND_ERR},
++ {"NT_STATUS_NOT_LOGON_PROCESS", NT_STATUS_NOT_LOGON_PROCESS},
++ {"NT_STATUS_LOGON_SESSION_EXISTS", NT_STATUS_LOGON_SESSION_EXISTS},
++ {"NT_STATUS_INVALID_PARAMETER_1", NT_STATUS_INVALID_PARAMETER_1},
++ {"NT_STATUS_INVALID_PARAMETER_2", NT_STATUS_INVALID_PARAMETER_2},
++ {"NT_STATUS_INVALID_PARAMETER_3", NT_STATUS_INVALID_PARAMETER_3},
++ {"NT_STATUS_INVALID_PARAMETER_4", NT_STATUS_INVALID_PARAMETER_4},
++ {"NT_STATUS_INVALID_PARAMETER_5", NT_STATUS_INVALID_PARAMETER_5},
++ {"NT_STATUS_INVALID_PARAMETER_6", NT_STATUS_INVALID_PARAMETER_6},
++ {"NT_STATUS_INVALID_PARAMETER_7", NT_STATUS_INVALID_PARAMETER_7},
++ {"NT_STATUS_INVALID_PARAMETER_8", NT_STATUS_INVALID_PARAMETER_8},
++ {"NT_STATUS_INVALID_PARAMETER_9", NT_STATUS_INVALID_PARAMETER_9},
++ {"NT_STATUS_INVALID_PARAMETER_10", NT_STATUS_INVALID_PARAMETER_10},
++ {"NT_STATUS_INVALID_PARAMETER_11", NT_STATUS_INVALID_PARAMETER_11},
++ {"NT_STATUS_INVALID_PARAMETER_12", NT_STATUS_INVALID_PARAMETER_12},
++ {"NT_STATUS_REDIRECTOR_NOT_STARTED",
++ NT_STATUS_REDIRECTOR_NOT_STARTED},
++ {"NT_STATUS_REDIRECTOR_STARTED", NT_STATUS_REDIRECTOR_STARTED},
++ {"NT_STATUS_STACK_OVERFLOW", NT_STATUS_STACK_OVERFLOW},
++ {"NT_STATUS_NO_SUCH_PACKAGE", NT_STATUS_NO_SUCH_PACKAGE},
++ {"NT_STATUS_BAD_FUNCTION_TABLE", NT_STATUS_BAD_FUNCTION_TABLE},
++ {"NT_STATUS_DIRECTORY_NOT_EMPTY", NT_STATUS_DIRECTORY_NOT_EMPTY},
++ {"NT_STATUS_FILE_CORRUPT_ERROR", NT_STATUS_FILE_CORRUPT_ERROR},
++ {"NT_STATUS_NOT_A_DIRECTORY", NT_STATUS_NOT_A_DIRECTORY},
++ {"NT_STATUS_BAD_LOGON_SESSION_STATE",
++ NT_STATUS_BAD_LOGON_SESSION_STATE},
++ {"NT_STATUS_LOGON_SESSION_COLLISION",
++ NT_STATUS_LOGON_SESSION_COLLISION},
++ {"NT_STATUS_NAME_TOO_LONG", NT_STATUS_NAME_TOO_LONG},
++ {"NT_STATUS_FILES_OPEN", NT_STATUS_FILES_OPEN},
++ {"NT_STATUS_CONNECTION_IN_USE", NT_STATUS_CONNECTION_IN_USE},
++ {"NT_STATUS_MESSAGE_NOT_FOUND", NT_STATUS_MESSAGE_NOT_FOUND},
++ {"NT_STATUS_PROCESS_IS_TERMINATING",
++ NT_STATUS_PROCESS_IS_TERMINATING},
++ {"NT_STATUS_INVALID_LOGON_TYPE", NT_STATUS_INVALID_LOGON_TYPE},
++ {"NT_STATUS_NO_GUID_TRANSLATION", NT_STATUS_NO_GUID_TRANSLATION},
++ {"NT_STATUS_CANNOT_IMPERSONATE", NT_STATUS_CANNOT_IMPERSONATE},
++ {"NT_STATUS_IMAGE_ALREADY_LOADED", NT_STATUS_IMAGE_ALREADY_LOADED},
++ {"NT_STATUS_ABIOS_NOT_PRESENT", NT_STATUS_ABIOS_NOT_PRESENT},
++ {"NT_STATUS_ABIOS_LID_NOT_EXIST", NT_STATUS_ABIOS_LID_NOT_EXIST},
++ {"NT_STATUS_ABIOS_LID_ALREADY_OWNED",
++ NT_STATUS_ABIOS_LID_ALREADY_OWNED},
++ {"NT_STATUS_ABIOS_NOT_LID_OWNER", NT_STATUS_ABIOS_NOT_LID_OWNER},
++ {"NT_STATUS_ABIOS_INVALID_COMMAND",
++ NT_STATUS_ABIOS_INVALID_COMMAND},
++ {"NT_STATUS_ABIOS_INVALID_LID", NT_STATUS_ABIOS_INVALID_LID},
++ {"NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE",
++ NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE},
++ {"NT_STATUS_ABIOS_INVALID_SELECTOR",
++ NT_STATUS_ABIOS_INVALID_SELECTOR},
++ {"NT_STATUS_NO_LDT", NT_STATUS_NO_LDT},
++ {"NT_STATUS_INVALID_LDT_SIZE", NT_STATUS_INVALID_LDT_SIZE},
++ {"NT_STATUS_INVALID_LDT_OFFSET", NT_STATUS_INVALID_LDT_OFFSET},
++ {"NT_STATUS_INVALID_LDT_DESCRIPTOR",
++ NT_STATUS_INVALID_LDT_DESCRIPTOR},
++ {"NT_STATUS_INVALID_IMAGE_NE_FORMAT",
++ NT_STATUS_INVALID_IMAGE_NE_FORMAT},
++ {"NT_STATUS_RXACT_INVALID_STATE", NT_STATUS_RXACT_INVALID_STATE},
++ {"NT_STATUS_RXACT_COMMIT_FAILURE", NT_STATUS_RXACT_COMMIT_FAILURE},
++ {"NT_STATUS_MAPPED_FILE_SIZE_ZERO",
++ NT_STATUS_MAPPED_FILE_SIZE_ZERO},
++ {"NT_STATUS_TOO_MANY_OPENED_FILES",
++ NT_STATUS_TOO_MANY_OPENED_FILES},
++ {"NT_STATUS_CANCELLED", NT_STATUS_CANCELLED},
++ {"NT_STATUS_CANNOT_DELETE", NT_STATUS_CANNOT_DELETE},
++ {"NT_STATUS_INVALID_COMPUTER_NAME",
++ NT_STATUS_INVALID_COMPUTER_NAME},
++ {"NT_STATUS_FILE_DELETED", NT_STATUS_FILE_DELETED},
++ {"NT_STATUS_SPECIAL_ACCOUNT", NT_STATUS_SPECIAL_ACCOUNT},
++ {"NT_STATUS_SPECIAL_GROUP", NT_STATUS_SPECIAL_GROUP},
++ {"NT_STATUS_SPECIAL_USER", NT_STATUS_SPECIAL_USER},
++ {"NT_STATUS_MEMBERS_PRIMARY_GROUP",
++ NT_STATUS_MEMBERS_PRIMARY_GROUP},
++ {"NT_STATUS_FILE_CLOSED", NT_STATUS_FILE_CLOSED},
++ {"NT_STATUS_TOO_MANY_THREADS", NT_STATUS_TOO_MANY_THREADS},
++ {"NT_STATUS_THREAD_NOT_IN_PROCESS",
++ NT_STATUS_THREAD_NOT_IN_PROCESS},
++ {"NT_STATUS_TOKEN_ALREADY_IN_USE", NT_STATUS_TOKEN_ALREADY_IN_USE},
++ {"NT_STATUS_PAGEFILE_QUOTA_EXCEEDED",
++ NT_STATUS_PAGEFILE_QUOTA_EXCEEDED},
++ {"NT_STATUS_COMMITMENT_LIMIT", NT_STATUS_COMMITMENT_LIMIT},
++ {"NT_STATUS_INVALID_IMAGE_LE_FORMAT",
++ NT_STATUS_INVALID_IMAGE_LE_FORMAT},
++ {"NT_STATUS_INVALID_IMAGE_NOT_MZ", NT_STATUS_INVALID_IMAGE_NOT_MZ},
++ {"NT_STATUS_INVALID_IMAGE_PROTECT",
++ NT_STATUS_INVALID_IMAGE_PROTECT},
++ {"NT_STATUS_INVALID_IMAGE_WIN_16", NT_STATUS_INVALID_IMAGE_WIN_16},
++ {"NT_STATUS_LOGON_SERVER_CONFLICT",
++ NT_STATUS_LOGON_SERVER_CONFLICT},
++ {"NT_STATUS_TIME_DIFFERENCE_AT_DC",
++ NT_STATUS_TIME_DIFFERENCE_AT_DC},
++ {"NT_STATUS_SYNCHRONIZATION_REQUIRED",
++ NT_STATUS_SYNCHRONIZATION_REQUIRED},
++ {"NT_STATUS_DLL_NOT_FOUND", NT_STATUS_DLL_NOT_FOUND},
++ {"NT_STATUS_OPEN_FAILED", NT_STATUS_OPEN_FAILED},
++ {"NT_STATUS_IO_PRIVILEGE_FAILED", NT_STATUS_IO_PRIVILEGE_FAILED},
++ {"NT_STATUS_ORDINAL_NOT_FOUND", NT_STATUS_ORDINAL_NOT_FOUND},
++ {"NT_STATUS_ENTRYPOINT_NOT_FOUND", NT_STATUS_ENTRYPOINT_NOT_FOUND},
++ {"NT_STATUS_CONTROL_C_EXIT", NT_STATUS_CONTROL_C_EXIT},
++ {"NT_STATUS_LOCAL_DISCONNECT", NT_STATUS_LOCAL_DISCONNECT},
++ {"NT_STATUS_REMOTE_DISCONNECT", NT_STATUS_REMOTE_DISCONNECT},
++ {"NT_STATUS_REMOTE_RESOURCES", NT_STATUS_REMOTE_RESOURCES},
++ {"NT_STATUS_LINK_FAILED", NT_STATUS_LINK_FAILED},
++ {"NT_STATUS_LINK_TIMEOUT", NT_STATUS_LINK_TIMEOUT},
++ {"NT_STATUS_INVALID_CONNECTION", NT_STATUS_INVALID_CONNECTION},
++ {"NT_STATUS_INVALID_ADDRESS", NT_STATUS_INVALID_ADDRESS},
++ {"NT_STATUS_DLL_INIT_FAILED", NT_STATUS_DLL_INIT_FAILED},
++ {"NT_STATUS_MISSING_SYSTEMFILE", NT_STATUS_MISSING_SYSTEMFILE},
++ {"NT_STATUS_UNHANDLED_EXCEPTION", NT_STATUS_UNHANDLED_EXCEPTION},
++ {"NT_STATUS_APP_INIT_FAILURE", NT_STATUS_APP_INIT_FAILURE},
++ {"NT_STATUS_PAGEFILE_CREATE_FAILED",
++ NT_STATUS_PAGEFILE_CREATE_FAILED},
++ {"NT_STATUS_NO_PAGEFILE", NT_STATUS_NO_PAGEFILE},
++ {"NT_STATUS_INVALID_LEVEL", NT_STATUS_INVALID_LEVEL},
++ {"NT_STATUS_WRONG_PASSWORD_CORE", NT_STATUS_WRONG_PASSWORD_CORE},
++ {"NT_STATUS_ILLEGAL_FLOAT_CONTEXT",
++ NT_STATUS_ILLEGAL_FLOAT_CONTEXT},
++ {"NT_STATUS_PIPE_BROKEN", NT_STATUS_PIPE_BROKEN},
++ {"NT_STATUS_REGISTRY_CORRUPT", NT_STATUS_REGISTRY_CORRUPT},
++ {"NT_STATUS_REGISTRY_IO_FAILED", NT_STATUS_REGISTRY_IO_FAILED},
++ {"NT_STATUS_NO_EVENT_PAIR", NT_STATUS_NO_EVENT_PAIR},
++ {"NT_STATUS_UNRECOGNIZED_VOLUME", NT_STATUS_UNRECOGNIZED_VOLUME},
++ {"NT_STATUS_SERIAL_NO_DEVICE_INITED",
++ NT_STATUS_SERIAL_NO_DEVICE_INITED},
++ {"NT_STATUS_NO_SUCH_ALIAS", NT_STATUS_NO_SUCH_ALIAS},
++ {"NT_STATUS_MEMBER_NOT_IN_ALIAS", NT_STATUS_MEMBER_NOT_IN_ALIAS},
++ {"NT_STATUS_MEMBER_IN_ALIAS", NT_STATUS_MEMBER_IN_ALIAS},
++ {"NT_STATUS_ALIAS_EXISTS", NT_STATUS_ALIAS_EXISTS},
++ {"NT_STATUS_LOGON_NOT_GRANTED", NT_STATUS_LOGON_NOT_GRANTED},
++ {"NT_STATUS_TOO_MANY_SECRETS", NT_STATUS_TOO_MANY_SECRETS},
++ {"NT_STATUS_SECRET_TOO_LONG", NT_STATUS_SECRET_TOO_LONG},
++ {"NT_STATUS_INTERNAL_DB_ERROR", NT_STATUS_INTERNAL_DB_ERROR},
++ {"NT_STATUS_FULLSCREEN_MODE", NT_STATUS_FULLSCREEN_MODE},
++ {"NT_STATUS_TOO_MANY_CONTEXT_IDS", NT_STATUS_TOO_MANY_CONTEXT_IDS},
++ {"NT_STATUS_LOGON_TYPE_NOT_GRANTED",
++ NT_STATUS_LOGON_TYPE_NOT_GRANTED},
++ {"NT_STATUS_NOT_REGISTRY_FILE", NT_STATUS_NOT_REGISTRY_FILE},
++ {"NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED",
++ NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED},
++ {"NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR",
++ NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR},
++ {"NT_STATUS_FT_MISSING_MEMBER", NT_STATUS_FT_MISSING_MEMBER},
++ {"NT_STATUS_ILL_FORMED_SERVICE_ENTRY",
++ NT_STATUS_ILL_FORMED_SERVICE_ENTRY},
++ {"NT_STATUS_ILLEGAL_CHARACTER", NT_STATUS_ILLEGAL_CHARACTER},
++ {"NT_STATUS_UNMAPPABLE_CHARACTER", NT_STATUS_UNMAPPABLE_CHARACTER},
++ {"NT_STATUS_UNDEFINED_CHARACTER", NT_STATUS_UNDEFINED_CHARACTER},
++ {"NT_STATUS_FLOPPY_VOLUME", NT_STATUS_FLOPPY_VOLUME},
++ {"NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND",
++ NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND},
++ {"NT_STATUS_FLOPPY_WRONG_CYLINDER",
++ NT_STATUS_FLOPPY_WRONG_CYLINDER},
++ {"NT_STATUS_FLOPPY_UNKNOWN_ERROR", NT_STATUS_FLOPPY_UNKNOWN_ERROR},
++ {"NT_STATUS_FLOPPY_BAD_REGISTERS", NT_STATUS_FLOPPY_BAD_REGISTERS},
++ {"NT_STATUS_DISK_RECALIBRATE_FAILED",
++ NT_STATUS_DISK_RECALIBRATE_FAILED},
++ {"NT_STATUS_DISK_OPERATION_FAILED",
++ NT_STATUS_DISK_OPERATION_FAILED},
++ {"NT_STATUS_DISK_RESET_FAILED", NT_STATUS_DISK_RESET_FAILED},
++ {"NT_STATUS_SHARED_IRQ_BUSY", NT_STATUS_SHARED_IRQ_BUSY},
++ {"NT_STATUS_FT_ORPHANING", NT_STATUS_FT_ORPHANING},
++ {"NT_STATUS_PARTITION_FAILURE", NT_STATUS_PARTITION_FAILURE},
++ {"NT_STATUS_INVALID_BLOCK_LENGTH", NT_STATUS_INVALID_BLOCK_LENGTH},
++ {"NT_STATUS_DEVICE_NOT_PARTITIONED",
++ NT_STATUS_DEVICE_NOT_PARTITIONED},
++ {"NT_STATUS_UNABLE_TO_LOCK_MEDIA", NT_STATUS_UNABLE_TO_LOCK_MEDIA},
++ {"NT_STATUS_UNABLE_TO_UNLOAD_MEDIA",
++ NT_STATUS_UNABLE_TO_UNLOAD_MEDIA},
++ {"NT_STATUS_EOM_OVERFLOW", NT_STATUS_EOM_OVERFLOW},
++ {"NT_STATUS_NO_MEDIA", NT_STATUS_NO_MEDIA},
++ {"NT_STATUS_NO_SUCH_MEMBER", NT_STATUS_NO_SUCH_MEMBER},
++ {"NT_STATUS_INVALID_MEMBER", NT_STATUS_INVALID_MEMBER},
++ {"NT_STATUS_KEY_DELETED", NT_STATUS_KEY_DELETED},
++ {"NT_STATUS_NO_LOG_SPACE", NT_STATUS_NO_LOG_SPACE},
++ {"NT_STATUS_TOO_MANY_SIDS", NT_STATUS_TOO_MANY_SIDS},
++ {"NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED",
++ NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED},
++ {"NT_STATUS_KEY_HAS_CHILDREN", NT_STATUS_KEY_HAS_CHILDREN},
++ {"NT_STATUS_CHILD_MUST_BE_VOLATILE",
++ NT_STATUS_CHILD_MUST_BE_VOLATILE},
++ {"NT_STATUS_DEVICE_CONFIGURATION_ERROR",
++ NT_STATUS_DEVICE_CONFIGURATION_ERROR},
++ {"NT_STATUS_DRIVER_INTERNAL_ERROR",
++ NT_STATUS_DRIVER_INTERNAL_ERROR},
++ {"NT_STATUS_INVALID_DEVICE_STATE", NT_STATUS_INVALID_DEVICE_STATE},
++ {"NT_STATUS_IO_DEVICE_ERROR", NT_STATUS_IO_DEVICE_ERROR},
++ {"NT_STATUS_DEVICE_PROTOCOL_ERROR",
++ NT_STATUS_DEVICE_PROTOCOL_ERROR},
++ {"NT_STATUS_BACKUP_CONTROLLER", NT_STATUS_BACKUP_CONTROLLER},
++ {"NT_STATUS_LOG_FILE_FULL", NT_STATUS_LOG_FILE_FULL},
++ {"NT_STATUS_TOO_LATE", NT_STATUS_TOO_LATE},
++ {"NT_STATUS_NO_TRUST_LSA_SECRET", NT_STATUS_NO_TRUST_LSA_SECRET},
++ {"NT_STATUS_NO_TRUST_SAM_ACCOUNT", NT_STATUS_NO_TRUST_SAM_ACCOUNT},
++ {"NT_STATUS_TRUSTED_DOMAIN_FAILURE",
++ NT_STATUS_TRUSTED_DOMAIN_FAILURE},
++ {"NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE",
++ NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE},
++ {"NT_STATUS_EVENTLOG_FILE_CORRUPT",
++ NT_STATUS_EVENTLOG_FILE_CORRUPT},
++ {"NT_STATUS_EVENTLOG_CANT_START", NT_STATUS_EVENTLOG_CANT_START},
++ {"NT_STATUS_TRUST_FAILURE", NT_STATUS_TRUST_FAILURE},
++ {"NT_STATUS_MUTANT_LIMIT_EXCEEDED",
++ NT_STATUS_MUTANT_LIMIT_EXCEEDED},
++ {"NT_STATUS_NETLOGON_NOT_STARTED", NT_STATUS_NETLOGON_NOT_STARTED},
++ {"NT_STATUS_ACCOUNT_EXPIRED", NT_STATUS_ACCOUNT_EXPIRED},
++ {"NT_STATUS_POSSIBLE_DEADLOCK", NT_STATUS_POSSIBLE_DEADLOCK},
++ {"NT_STATUS_NETWORK_CREDENTIAL_CONFLICT",
++ NT_STATUS_NETWORK_CREDENTIAL_CONFLICT},
++ {"NT_STATUS_REMOTE_SESSION_LIMIT", NT_STATUS_REMOTE_SESSION_LIMIT},
++ {"NT_STATUS_EVENTLOG_FILE_CHANGED",
++ NT_STATUS_EVENTLOG_FILE_CHANGED},
++ {"NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT",
++ NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT},
++ {"NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT",
++ NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT},
++ {"NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT",
++ NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
++ {"NT_STATUS_DOMAIN_TRUST_INCONSISTENT",
++ NT_STATUS_DOMAIN_TRUST_INCONSISTENT},
++ {"NT_STATUS_FS_DRIVER_REQUIRED", NT_STATUS_FS_DRIVER_REQUIRED},
++ {"NT_STATUS_NO_USER_SESSION_KEY", NT_STATUS_NO_USER_SESSION_KEY},
++ {"NT_STATUS_USER_SESSION_DELETED", NT_STATUS_USER_SESSION_DELETED},
++ {"NT_STATUS_RESOURCE_LANG_NOT_FOUND",
++ NT_STATUS_RESOURCE_LANG_NOT_FOUND},
++ {"NT_STATUS_INSUFF_SERVER_RESOURCES",
++ NT_STATUS_INSUFF_SERVER_RESOURCES},
++ {"NT_STATUS_INVALID_BUFFER_SIZE", NT_STATUS_INVALID_BUFFER_SIZE},
++ {"NT_STATUS_INVALID_ADDRESS_COMPONENT",
++ NT_STATUS_INVALID_ADDRESS_COMPONENT},
++ {"NT_STATUS_INVALID_ADDRESS_WILDCARD",
++ NT_STATUS_INVALID_ADDRESS_WILDCARD},
++ {"NT_STATUS_TOO_MANY_ADDRESSES", NT_STATUS_TOO_MANY_ADDRESSES},
++ {"NT_STATUS_ADDRESS_ALREADY_EXISTS",
++ NT_STATUS_ADDRESS_ALREADY_EXISTS},
++ {"NT_STATUS_ADDRESS_CLOSED", NT_STATUS_ADDRESS_CLOSED},
++ {"NT_STATUS_CONNECTION_DISCONNECTED",
++ NT_STATUS_CONNECTION_DISCONNECTED},
++ {"NT_STATUS_CONNECTION_RESET", NT_STATUS_CONNECTION_RESET},
++ {"NT_STATUS_TOO_MANY_NODES", NT_STATUS_TOO_MANY_NODES},
++ {"NT_STATUS_TRANSACTION_ABORTED", NT_STATUS_TRANSACTION_ABORTED},
++ {"NT_STATUS_TRANSACTION_TIMED_OUT",
++ NT_STATUS_TRANSACTION_TIMED_OUT},
++ {"NT_STATUS_TRANSACTION_NO_RELEASE",
++ NT_STATUS_TRANSACTION_NO_RELEASE},
++ {"NT_STATUS_TRANSACTION_NO_MATCH", NT_STATUS_TRANSACTION_NO_MATCH},
++ {"NT_STATUS_TRANSACTION_RESPONDED",
++ NT_STATUS_TRANSACTION_RESPONDED},
++ {"NT_STATUS_TRANSACTION_INVALID_ID",
++ NT_STATUS_TRANSACTION_INVALID_ID},
++ {"NT_STATUS_TRANSACTION_INVALID_TYPE",
++ NT_STATUS_TRANSACTION_INVALID_TYPE},
++ {"NT_STATUS_NOT_SERVER_SESSION", NT_STATUS_NOT_SERVER_SESSION},
++ {"NT_STATUS_NOT_CLIENT_SESSION", NT_STATUS_NOT_CLIENT_SESSION},
++ {"NT_STATUS_CANNOT_LOAD_REGISTRY_FILE",
++ NT_STATUS_CANNOT_LOAD_REGISTRY_FILE},
++ {"NT_STATUS_DEBUG_ATTACH_FAILED", NT_STATUS_DEBUG_ATTACH_FAILED},
++ {"NT_STATUS_SYSTEM_PROCESS_TERMINATED",
++ NT_STATUS_SYSTEM_PROCESS_TERMINATED},
++ {"NT_STATUS_DATA_NOT_ACCEPTED", NT_STATUS_DATA_NOT_ACCEPTED},
++ {"NT_STATUS_NO_BROWSER_SERVERS_FOUND",
++ NT_STATUS_NO_BROWSER_SERVERS_FOUND},
++ {"NT_STATUS_VDM_HARD_ERROR", NT_STATUS_VDM_HARD_ERROR},
++ {"NT_STATUS_DRIVER_CANCEL_TIMEOUT",
++ NT_STATUS_DRIVER_CANCEL_TIMEOUT},
++ {"NT_STATUS_REPLY_MESSAGE_MISMATCH",
++ NT_STATUS_REPLY_MESSAGE_MISMATCH},
++ {"NT_STATUS_MAPPED_ALIGNMENT", NT_STATUS_MAPPED_ALIGNMENT},
++ {"NT_STATUS_IMAGE_CHECKSUM_MISMATCH",
++ NT_STATUS_IMAGE_CHECKSUM_MISMATCH},
++ {"NT_STATUS_LOST_WRITEBEHIND_DATA",
++ NT_STATUS_LOST_WRITEBEHIND_DATA},
++ {"NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID",
++ NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID},
++ {"NT_STATUS_PASSWORD_MUST_CHANGE", NT_STATUS_PASSWORD_MUST_CHANGE},
++ {"NT_STATUS_NOT_FOUND", NT_STATUS_NOT_FOUND},
++ {"NT_STATUS_NOT_TINY_STREAM", NT_STATUS_NOT_TINY_STREAM},
++ {"NT_STATUS_RECOVERY_FAILURE", NT_STATUS_RECOVERY_FAILURE},
++ {"NT_STATUS_STACK_OVERFLOW_READ", NT_STATUS_STACK_OVERFLOW_READ},
++ {"NT_STATUS_FAIL_CHECK", NT_STATUS_FAIL_CHECK},
++ {"NT_STATUS_DUPLICATE_OBJECTID", NT_STATUS_DUPLICATE_OBJECTID},
++ {"NT_STATUS_OBJECTID_EXISTS", NT_STATUS_OBJECTID_EXISTS},
++ {"NT_STATUS_CONVERT_TO_LARGE", NT_STATUS_CONVERT_TO_LARGE},
++ {"NT_STATUS_RETRY", NT_STATUS_RETRY},
++ {"NT_STATUS_FOUND_OUT_OF_SCOPE", NT_STATUS_FOUND_OUT_OF_SCOPE},
++ {"NT_STATUS_ALLOCATE_BUCKET", NT_STATUS_ALLOCATE_BUCKET},
++ {"NT_STATUS_PROPSET_NOT_FOUND", NT_STATUS_PROPSET_NOT_FOUND},
++ {"NT_STATUS_MARSHALL_OVERFLOW", NT_STATUS_MARSHALL_OVERFLOW},
++ {"NT_STATUS_INVALID_VARIANT", NT_STATUS_INVALID_VARIANT},
++ {"NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND",
++ NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND},
++ {"NT_STATUS_ACCOUNT_LOCKED_OUT", NT_STATUS_ACCOUNT_LOCKED_OUT},
++ {"NT_STATUS_HANDLE_NOT_CLOSABLE", NT_STATUS_HANDLE_NOT_CLOSABLE},
++ {"NT_STATUS_CONNECTION_REFUSED", NT_STATUS_CONNECTION_REFUSED},
++ {"NT_STATUS_GRACEFUL_DISCONNECT", NT_STATUS_GRACEFUL_DISCONNECT},
++ {"NT_STATUS_ADDRESS_ALREADY_ASSOCIATED",
++ NT_STATUS_ADDRESS_ALREADY_ASSOCIATED},
++ {"NT_STATUS_ADDRESS_NOT_ASSOCIATED",
++ NT_STATUS_ADDRESS_NOT_ASSOCIATED},
++ {"NT_STATUS_CONNECTION_INVALID", NT_STATUS_CONNECTION_INVALID},
++ {"NT_STATUS_CONNECTION_ACTIVE", NT_STATUS_CONNECTION_ACTIVE},
++ {"NT_STATUS_NETWORK_UNREACHABLE", NT_STATUS_NETWORK_UNREACHABLE},
++ {"NT_STATUS_HOST_UNREACHABLE", NT_STATUS_HOST_UNREACHABLE},
++ {"NT_STATUS_PROTOCOL_UNREACHABLE", NT_STATUS_PROTOCOL_UNREACHABLE},
++ {"NT_STATUS_PORT_UNREACHABLE", NT_STATUS_PORT_UNREACHABLE},
++ {"NT_STATUS_REQUEST_ABORTED", NT_STATUS_REQUEST_ABORTED},
++ {"NT_STATUS_CONNECTION_ABORTED", NT_STATUS_CONNECTION_ABORTED},
++ {"NT_STATUS_BAD_COMPRESSION_BUFFER",
++ NT_STATUS_BAD_COMPRESSION_BUFFER},
++ {"NT_STATUS_USER_MAPPED_FILE", NT_STATUS_USER_MAPPED_FILE},
++ {"NT_STATUS_AUDIT_FAILED", NT_STATUS_AUDIT_FAILED},
++ {"NT_STATUS_TIMER_RESOLUTION_NOT_SET",
++ NT_STATUS_TIMER_RESOLUTION_NOT_SET},
++ {"NT_STATUS_CONNECTION_COUNT_LIMIT",
++ NT_STATUS_CONNECTION_COUNT_LIMIT},
++ {"NT_STATUS_LOGIN_TIME_RESTRICTION",
++ NT_STATUS_LOGIN_TIME_RESTRICTION},
++ {"NT_STATUS_LOGIN_WKSTA_RESTRICTION",
++ NT_STATUS_LOGIN_WKSTA_RESTRICTION},
++ {"NT_STATUS_IMAGE_MP_UP_MISMATCH", NT_STATUS_IMAGE_MP_UP_MISMATCH},
++ {"NT_STATUS_INSUFFICIENT_LOGON_INFO",
++ NT_STATUS_INSUFFICIENT_LOGON_INFO},
++ {"NT_STATUS_BAD_DLL_ENTRYPOINT", NT_STATUS_BAD_DLL_ENTRYPOINT},
++ {"NT_STATUS_BAD_SERVICE_ENTRYPOINT",
++ NT_STATUS_BAD_SERVICE_ENTRYPOINT},
++ {"NT_STATUS_LPC_REPLY_LOST", NT_STATUS_LPC_REPLY_LOST},
++ {"NT_STATUS_IP_ADDRESS_CONFLICT1", NT_STATUS_IP_ADDRESS_CONFLICT1},
++ {"NT_STATUS_IP_ADDRESS_CONFLICT2", NT_STATUS_IP_ADDRESS_CONFLICT2},
++ {"NT_STATUS_REGISTRY_QUOTA_LIMIT", NT_STATUS_REGISTRY_QUOTA_LIMIT},
++ {"NT_STATUS_PATH_NOT_COVERED", NT_STATUS_PATH_NOT_COVERED},
++ {"NT_STATUS_NO_CALLBACK_ACTIVE", NT_STATUS_NO_CALLBACK_ACTIVE},
++ {"NT_STATUS_LICENSE_QUOTA_EXCEEDED",
++ NT_STATUS_LICENSE_QUOTA_EXCEEDED},
++ {"NT_STATUS_PWD_TOO_SHORT", NT_STATUS_PWD_TOO_SHORT},
++ {"NT_STATUS_PWD_TOO_RECENT", NT_STATUS_PWD_TOO_RECENT},
++ {"NT_STATUS_PWD_HISTORY_CONFLICT", NT_STATUS_PWD_HISTORY_CONFLICT},
++ {"NT_STATUS_PLUGPLAY_NO_DEVICE", NT_STATUS_PLUGPLAY_NO_DEVICE},
++ {"NT_STATUS_UNSUPPORTED_COMPRESSION",
++ NT_STATUS_UNSUPPORTED_COMPRESSION},
++ {"NT_STATUS_INVALID_HW_PROFILE", NT_STATUS_INVALID_HW_PROFILE},
++ {"NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH",
++ NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH},
++ {"NT_STATUS_DRIVER_ORDINAL_NOT_FOUND",
++ NT_STATUS_DRIVER_ORDINAL_NOT_FOUND},
++ {"NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND",
++ NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND},
++ {"NT_STATUS_RESOURCE_NOT_OWNED", NT_STATUS_RESOURCE_NOT_OWNED},
++ {"NT_STATUS_TOO_MANY_LINKS", NT_STATUS_TOO_MANY_LINKS},
++ {"NT_STATUS_QUOTA_LIST_INCONSISTENT",
++ NT_STATUS_QUOTA_LIST_INCONSISTENT},
++ {"NT_STATUS_FILE_IS_OFFLINE", NT_STATUS_FILE_IS_OFFLINE},
++ {"NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES},
++ {"STATUS_MORE_ENTRIES", STATUS_MORE_ENTRIES},
++ {"STATUS_SOME_UNMAPPED", STATUS_SOME_UNMAPPED},
++ {NULL, 0}
++};
+diff -urN linux-2.4.29.old/fs/cifs/nterr.h linux-2.4.29/fs/cifs/nterr.h
+--- linux-2.4.29.old/fs/cifs/nterr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/nterr.h 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,556 @@
++/*
++ Unix SMB/Netbios implementation.
++ Version 1.9.
++ NT error code constants
++ Copyright (C) Andrew Tridgell 1992-2000
++ Copyright (C) John H Terpstra 1996-2000
++ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
++ Copyright (C) Paul Ashton 1998-2000
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++*/
++
++
++
++#ifndef _NTERR_H
++#define _NTERR_H
++
++struct nt_err_code_struct {
++ char *nt_errstr;
++ __u32 nt_errcode;
++};
++
++extern const struct nt_err_code_struct nt_errs[];
++
++/* Win32 Status codes. */
++
++#define STATUS_BUFFER_OVERFLOW 0x80000005
++#define STATUS_MORE_ENTRIES 0x0105
++#define ERROR_INVALID_PARAMETER 0x0057
++#define ERROR_INSUFFICIENT_BUFFER 0x007a
++#define STATUS_1804 0x070c
++#define STATUS_NOTIFY_ENUM_DIR 0x010c
++
++/* Win32 Error codes extracted using a loop in smbclient then printing a
++ netmon sniff to a file. */
++
++#define NT_STATUS_OK 0x0000
++#define STATUS_SOME_UNMAPPED 0x0107
++#define STATUS_BUFFER_OVERFLOW 0x80000005
++#define NT_STATUS_NO_MORE_ENTRIES 0x8000001a
++#define NT_STATUS_UNSUCCESSFUL 0xC0000000 | 0x0001
++#define NT_STATUS_NOT_IMPLEMENTED 0xC0000000 | 0x0002
++#define NT_STATUS_INVALID_INFO_CLASS 0xC0000000 | 0x0003
++#define NT_STATUS_INFO_LENGTH_MISMATCH 0xC0000000 | 0x0004
++#define NT_STATUS_ACCESS_VIOLATION 0xC0000000 | 0x0005
++#define NT_STATUS_IN_PAGE_ERROR 0xC0000000 | 0x0006
++#define NT_STATUS_PAGEFILE_QUOTA 0xC0000000 | 0x0007
++#define NT_STATUS_INVALID_HANDLE 0xC0000000 | 0x0008
++#define NT_STATUS_BAD_INITIAL_STACK 0xC0000000 | 0x0009
++#define NT_STATUS_BAD_INITIAL_PC 0xC0000000 | 0x000a
++#define NT_STATUS_INVALID_CID 0xC0000000 | 0x000b
++#define NT_STATUS_TIMER_NOT_CANCELED 0xC0000000 | 0x000c
++#define NT_STATUS_INVALID_PARAMETER 0xC0000000 | 0x000d
++#define NT_STATUS_NO_SUCH_DEVICE 0xC0000000 | 0x000e
++#define NT_STATUS_NO_SUCH_FILE 0xC0000000 | 0x000f
++#define NT_STATUS_INVALID_DEVICE_REQUEST 0xC0000000 | 0x0010
++#define NT_STATUS_END_OF_FILE 0xC0000000 | 0x0011
++#define NT_STATUS_WRONG_VOLUME 0xC0000000 | 0x0012
++#define NT_STATUS_NO_MEDIA_IN_DEVICE 0xC0000000 | 0x0013
++#define NT_STATUS_UNRECOGNIZED_MEDIA 0xC0000000 | 0x0014
++#define NT_STATUS_NONEXISTENT_SECTOR 0xC0000000 | 0x0015
++#define NT_STATUS_MORE_PROCESSING_REQUIRED 0xC0000000 | 0x0016
++#define NT_STATUS_NO_MEMORY 0xC0000000 | 0x0017
++#define NT_STATUS_CONFLICTING_ADDRESSES 0xC0000000 | 0x0018
++#define NT_STATUS_NOT_MAPPED_VIEW 0xC0000000 | 0x0019
++#define NT_STATUS_UNABLE_TO_FREE_VM 0x80000000 | 0x001a
++#define NT_STATUS_UNABLE_TO_DELETE_SECTION 0xC0000000 | 0x001b
++#define NT_STATUS_INVALID_SYSTEM_SERVICE 0xC0000000 | 0x001c
++#define NT_STATUS_ILLEGAL_INSTRUCTION 0xC0000000 | 0x001d
++#define NT_STATUS_INVALID_LOCK_SEQUENCE 0xC0000000 | 0x001e
++#define NT_STATUS_INVALID_VIEW_SIZE 0xC0000000 | 0x001f
++#define NT_STATUS_INVALID_FILE_FOR_SECTION 0xC0000000 | 0x0020
++#define NT_STATUS_ALREADY_COMMITTED 0xC0000000 | 0x0021
++#define NT_STATUS_ACCESS_DENIED 0xC0000000 | 0x0022
++#define NT_STATUS_BUFFER_TOO_SMALL 0xC0000000 | 0x0023
++#define NT_STATUS_OBJECT_TYPE_MISMATCH 0xC0000000 | 0x0024
++#define NT_STATUS_NONCONTINUABLE_EXCEPTION 0xC0000000 | 0x0025
++#define NT_STATUS_INVALID_DISPOSITION 0xC0000000 | 0x0026
++#define NT_STATUS_UNWIND 0xC0000000 | 0x0027
++#define NT_STATUS_BAD_STACK 0xC0000000 | 0x0028
++#define NT_STATUS_INVALID_UNWIND_TARGET 0xC0000000 | 0x0029
++#define NT_STATUS_NOT_LOCKED 0xC0000000 | 0x002a
++#define NT_STATUS_PARITY_ERROR 0xC0000000 | 0x002b
++#define NT_STATUS_UNABLE_TO_DECOMMIT_VM 0xC0000000 | 0x002c
++#define NT_STATUS_NOT_COMMITTED 0xC0000000 | 0x002d
++#define NT_STATUS_INVALID_PORT_ATTRIBUTES 0xC0000000 | 0x002e
++#define NT_STATUS_PORT_MESSAGE_TOO_LONG 0xC0000000 | 0x002f
++#define NT_STATUS_INVALID_PARAMETER_MIX 0xC0000000 | 0x0030
++#define NT_STATUS_INVALID_QUOTA_LOWER 0xC0000000 | 0x0031
++#define NT_STATUS_DISK_CORRUPT_ERROR 0xC0000000 | 0x0032
++#define NT_STATUS_OBJECT_NAME_INVALID 0xC0000000 | 0x0033
++#define NT_STATUS_OBJECT_NAME_NOT_FOUND 0xC0000000 | 0x0034
++#define NT_STATUS_OBJECT_NAME_COLLISION 0xC0000000 | 0x0035
++#define NT_STATUS_HANDLE_NOT_WAITABLE 0xC0000000 | 0x0036
++#define NT_STATUS_PORT_DISCONNECTED 0xC0000000 | 0x0037
++#define NT_STATUS_DEVICE_ALREADY_ATTACHED 0xC0000000 | 0x0038
++#define NT_STATUS_OBJECT_PATH_INVALID 0xC0000000 | 0x0039
++#define NT_STATUS_OBJECT_PATH_NOT_FOUND 0xC0000000 | 0x003a
++#define NT_STATUS_OBJECT_PATH_SYNTAX_BAD 0xC0000000 | 0x003b
++#define NT_STATUS_DATA_OVERRUN 0xC0000000 | 0x003c
++#define NT_STATUS_DATA_LATE_ERROR 0xC0000000 | 0x003d
++#define NT_STATUS_DATA_ERROR 0xC0000000 | 0x003e
++#define NT_STATUS_CRC_ERROR 0xC0000000 | 0x003f
++#define NT_STATUS_SECTION_TOO_BIG 0xC0000000 | 0x0040
++#define NT_STATUS_PORT_CONNECTION_REFUSED 0xC0000000 | 0x0041
++#define NT_STATUS_INVALID_PORT_HANDLE 0xC0000000 | 0x0042
++#define NT_STATUS_SHARING_VIOLATION 0xC0000000 | 0x0043
++#define NT_STATUS_QUOTA_EXCEEDED 0xC0000000 | 0x0044
++#define NT_STATUS_INVALID_PAGE_PROTECTION 0xC0000000 | 0x0045
++#define NT_STATUS_MUTANT_NOT_OWNED 0xC0000000 | 0x0046
++#define NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED 0xC0000000 | 0x0047
++#define NT_STATUS_PORT_ALREADY_SET 0xC0000000 | 0x0048
++#define NT_STATUS_SECTION_NOT_IMAGE 0xC0000000 | 0x0049
++#define NT_STATUS_SUSPEND_COUNT_EXCEEDED 0xC0000000 | 0x004a
++#define NT_STATUS_THREAD_IS_TERMINATING 0xC0000000 | 0x004b
++#define NT_STATUS_BAD_WORKING_SET_LIMIT 0xC0000000 | 0x004c
++#define NT_STATUS_INCOMPATIBLE_FILE_MAP 0xC0000000 | 0x004d
++#define NT_STATUS_SECTION_PROTECTION 0xC0000000 | 0x004e
++#define NT_STATUS_EAS_NOT_SUPPORTED 0xC0000000 | 0x004f
++#define NT_STATUS_EA_TOO_LARGE 0xC0000000 | 0x0050
++#define NT_STATUS_NONEXISTENT_EA_ENTRY 0xC0000000 | 0x0051
++#define NT_STATUS_NO_EAS_ON_FILE 0xC0000000 | 0x0052
++#define NT_STATUS_EA_CORRUPT_ERROR 0xC0000000 | 0x0053
++#define NT_STATUS_FILE_LOCK_CONFLICT 0xC0000000 | 0x0054
++#define NT_STATUS_LOCK_NOT_GRANTED 0xC0000000 | 0x0055
++#define NT_STATUS_DELETE_PENDING 0xC0000000 | 0x0056
++#define NT_STATUS_CTL_FILE_NOT_SUPPORTED 0xC0000000 | 0x0057
++#define NT_STATUS_UNKNOWN_REVISION 0xC0000000 | 0x0058
++#define NT_STATUS_REVISION_MISMATCH 0xC0000000 | 0x0059
++#define NT_STATUS_INVALID_OWNER 0xC0000000 | 0x005a
++#define NT_STATUS_INVALID_PRIMARY_GROUP 0xC0000000 | 0x005b
++#define NT_STATUS_NO_IMPERSONATION_TOKEN 0xC0000000 | 0x005c
++#define NT_STATUS_CANT_DISABLE_MANDATORY 0xC0000000 | 0x005d
++#define NT_STATUS_NO_LOGON_SERVERS 0xC0000000 | 0x005e
++#define NT_STATUS_NO_SUCH_LOGON_SESSION 0xC0000000 | 0x005f
++#define NT_STATUS_NO_SUCH_PRIVILEGE 0xC0000000 | 0x0060
++#define NT_STATUS_PRIVILEGE_NOT_HELD 0xC0000000 | 0x0061
++#define NT_STATUS_INVALID_ACCOUNT_NAME 0xC0000000 | 0x0062
++#define NT_STATUS_USER_EXISTS 0xC0000000 | 0x0063
++#define NT_STATUS_NO_SUCH_USER 0xC0000000 | 0x0064
++#define NT_STATUS_GROUP_EXISTS 0xC0000000 | 0x0065
++#define NT_STATUS_NO_SUCH_GROUP 0xC0000000 | 0x0066
++#define NT_STATUS_MEMBER_IN_GROUP 0xC0000000 | 0x0067
++#define NT_STATUS_MEMBER_NOT_IN_GROUP 0xC0000000 | 0x0068
++#define NT_STATUS_LAST_ADMIN 0xC0000000 | 0x0069
++#define NT_STATUS_WRONG_PASSWORD 0xC0000000 | 0x006a
++#define NT_STATUS_ILL_FORMED_PASSWORD 0xC0000000 | 0x006b
++#define NT_STATUS_PASSWORD_RESTRICTION 0xC0000000 | 0x006c
++#define NT_STATUS_LOGON_FAILURE 0xC0000000 | 0x006d
++#define NT_STATUS_ACCOUNT_RESTRICTION 0xC0000000 | 0x006e
++#define NT_STATUS_INVALID_LOGON_HOURS 0xC0000000 | 0x006f
++#define NT_STATUS_INVALID_WORKSTATION 0xC0000000 | 0x0070
++#define NT_STATUS_PASSWORD_EXPIRED 0xC0000000 | 0x0071
++#define NT_STATUS_ACCOUNT_DISABLED 0xC0000000 | 0x0072
++#define NT_STATUS_NONE_MAPPED 0xC0000000 | 0x0073
++#define NT_STATUS_TOO_MANY_LUIDS_REQUESTED 0xC0000000 | 0x0074
++#define NT_STATUS_LUIDS_EXHAUSTED 0xC0000000 | 0x0075
++#define NT_STATUS_INVALID_SUB_AUTHORITY 0xC0000000 | 0x0076
++#define NT_STATUS_INVALID_ACL 0xC0000000 | 0x0077
++#define NT_STATUS_INVALID_SID 0xC0000000 | 0x0078
++#define NT_STATUS_INVALID_SECURITY_DESCR 0xC0000000 | 0x0079
++#define NT_STATUS_PROCEDURE_NOT_FOUND 0xC0000000 | 0x007a
++#define NT_STATUS_INVALID_IMAGE_FORMAT 0xC0000000 | 0x007b
++#define NT_STATUS_NO_TOKEN 0xC0000000 | 0x007c
++#define NT_STATUS_BAD_INHERITANCE_ACL 0xC0000000 | 0x007d
++#define NT_STATUS_RANGE_NOT_LOCKED 0xC0000000 | 0x007e
++#define NT_STATUS_DISK_FULL 0xC0000000 | 0x007f
++#define NT_STATUS_SERVER_DISABLED 0xC0000000 | 0x0080
++#define NT_STATUS_SERVER_NOT_DISABLED 0xC0000000 | 0x0081
++#define NT_STATUS_TOO_MANY_GUIDS_REQUESTED 0xC0000000 | 0x0082
++#define NT_STATUS_GUIDS_EXHAUSTED 0xC0000000 | 0x0083
++#define NT_STATUS_INVALID_ID_AUTHORITY 0xC0000000 | 0x0084
++#define NT_STATUS_AGENTS_EXHAUSTED 0xC0000000 | 0x0085
++#define NT_STATUS_INVALID_VOLUME_LABEL 0xC0000000 | 0x0086
++#define NT_STATUS_SECTION_NOT_EXTENDED 0xC0000000 | 0x0087
++#define NT_STATUS_NOT_MAPPED_DATA 0xC0000000 | 0x0088
++#define NT_STATUS_RESOURCE_DATA_NOT_FOUND 0xC0000000 | 0x0089
++#define NT_STATUS_RESOURCE_TYPE_NOT_FOUND 0xC0000000 | 0x008a
++#define NT_STATUS_RESOURCE_NAME_NOT_FOUND 0xC0000000 | 0x008b
++#define NT_STATUS_ARRAY_BOUNDS_EXCEEDED 0xC0000000 | 0x008c
++#define NT_STATUS_FLOAT_DENORMAL_OPERAND 0xC0000000 | 0x008d
++#define NT_STATUS_FLOAT_DIVIDE_BY_ZERO 0xC0000000 | 0x008e
++#define NT_STATUS_FLOAT_INEXACT_RESULT 0xC0000000 | 0x008f
++#define NT_STATUS_FLOAT_INVALID_OPERATION 0xC0000000 | 0x0090
++#define NT_STATUS_FLOAT_OVERFLOW 0xC0000000 | 0x0091
++#define NT_STATUS_FLOAT_STACK_CHECK 0xC0000000 | 0x0092
++#define NT_STATUS_FLOAT_UNDERFLOW 0xC0000000 | 0x0093
++#define NT_STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000000 | 0x0094
++#define NT_STATUS_INTEGER_OVERFLOW 0xC0000000 | 0x0095
++#define NT_STATUS_PRIVILEGED_INSTRUCTION 0xC0000000 | 0x0096
++#define NT_STATUS_TOO_MANY_PAGING_FILES 0xC0000000 | 0x0097
++#define NT_STATUS_FILE_INVALID 0xC0000000 | 0x0098
++#define NT_STATUS_ALLOTTED_SPACE_EXCEEDED 0xC0000000 | 0x0099
++#define NT_STATUS_INSUFFICIENT_RESOURCES 0xC0000000 | 0x009a
++#define NT_STATUS_DFS_EXIT_PATH_FOUND 0xC0000000 | 0x009b
++#define NT_STATUS_DEVICE_DATA_ERROR 0xC0000000 | 0x009c
++#define NT_STATUS_DEVICE_NOT_CONNECTED 0xC0000000 | 0x009d
++#define NT_STATUS_DEVICE_POWER_FAILURE 0xC0000000 | 0x009e
++#define NT_STATUS_FREE_VM_NOT_AT_BASE 0xC0000000 | 0x009f
++#define NT_STATUS_MEMORY_NOT_ALLOCATED 0xC0000000 | 0x00a0
++#define NT_STATUS_WORKING_SET_QUOTA 0xC0000000 | 0x00a1
++#define NT_STATUS_MEDIA_WRITE_PROTECTED 0xC0000000 | 0x00a2
++#define NT_STATUS_DEVICE_NOT_READY 0xC0000000 | 0x00a3
++#define NT_STATUS_INVALID_GROUP_ATTRIBUTES 0xC0000000 | 0x00a4
++#define NT_STATUS_BAD_IMPERSONATION_LEVEL 0xC0000000 | 0x00a5
++#define NT_STATUS_CANT_OPEN_ANONYMOUS 0xC0000000 | 0x00a6
++#define NT_STATUS_BAD_VALIDATION_CLASS 0xC0000000 | 0x00a7
++#define NT_STATUS_BAD_TOKEN_TYPE 0xC0000000 | 0x00a8
++#define NT_STATUS_BAD_MASTER_BOOT_RECORD 0xC0000000 | 0x00a9
++#define NT_STATUS_INSTRUCTION_MISALIGNMENT 0xC0000000 | 0x00aa
++#define NT_STATUS_INSTANCE_NOT_AVAILABLE 0xC0000000 | 0x00ab
++#define NT_STATUS_PIPE_NOT_AVAILABLE 0xC0000000 | 0x00ac
++#define NT_STATUS_INVALID_PIPE_STATE 0xC0000000 | 0x00ad
++#define NT_STATUS_PIPE_BUSY 0xC0000000 | 0x00ae
++#define NT_STATUS_ILLEGAL_FUNCTION 0xC0000000 | 0x00af
++#define NT_STATUS_PIPE_DISCONNECTED 0xC0000000 | 0x00b0
++#define NT_STATUS_PIPE_CLOSING 0xC0000000 | 0x00b1
++#define NT_STATUS_PIPE_CONNECTED 0xC0000000 | 0x00b2
++#define NT_STATUS_PIPE_LISTENING 0xC0000000 | 0x00b3
++#define NT_STATUS_INVALID_READ_MODE 0xC0000000 | 0x00b4
++#define NT_STATUS_IO_TIMEOUT 0xC0000000 | 0x00b5
++#define NT_STATUS_FILE_FORCED_CLOSED 0xC0000000 | 0x00b6
++#define NT_STATUS_PROFILING_NOT_STARTED 0xC0000000 | 0x00b7
++#define NT_STATUS_PROFILING_NOT_STOPPED 0xC0000000 | 0x00b8
++#define NT_STATUS_COULD_NOT_INTERPRET 0xC0000000 | 0x00b9
++#define NT_STATUS_FILE_IS_A_DIRECTORY 0xC0000000 | 0x00ba
++#define NT_STATUS_NOT_SUPPORTED 0xC0000000 | 0x00bb
++#define NT_STATUS_REMOTE_NOT_LISTENING 0xC0000000 | 0x00bc
++#define NT_STATUS_DUPLICATE_NAME 0xC0000000 | 0x00bd
++#define NT_STATUS_BAD_NETWORK_PATH 0xC0000000 | 0x00be
++#define NT_STATUS_NETWORK_BUSY 0xC0000000 | 0x00bf
++#define NT_STATUS_DEVICE_DOES_NOT_EXIST 0xC0000000 | 0x00c0
++#define NT_STATUS_TOO_MANY_COMMANDS 0xC0000000 | 0x00c1
++#define NT_STATUS_ADAPTER_HARDWARE_ERROR 0xC0000000 | 0x00c2
++#define NT_STATUS_INVALID_NETWORK_RESPONSE 0xC0000000 | 0x00c3
++#define NT_STATUS_UNEXPECTED_NETWORK_ERROR 0xC0000000 | 0x00c4
++#define NT_STATUS_BAD_REMOTE_ADAPTER 0xC0000000 | 0x00c5
++#define NT_STATUS_PRINT_QUEUE_FULL 0xC0000000 | 0x00c6
++#define NT_STATUS_NO_SPOOL_SPACE 0xC0000000 | 0x00c7
++#define NT_STATUS_PRINT_CANCELLED 0xC0000000 | 0x00c8
++#define NT_STATUS_NETWORK_NAME_DELETED 0xC0000000 | 0x00c9
++#define NT_STATUS_NETWORK_ACCESS_DENIED 0xC0000000 | 0x00ca
++#define NT_STATUS_BAD_DEVICE_TYPE 0xC0000000 | 0x00cb
++#define NT_STATUS_BAD_NETWORK_NAME 0xC0000000 | 0x00cc
++#define NT_STATUS_TOO_MANY_NAMES 0xC0000000 | 0x00cd
++#define NT_STATUS_TOO_MANY_SESSIONS 0xC0000000 | 0x00ce
++#define NT_STATUS_SHARING_PAUSED 0xC0000000 | 0x00cf
++#define NT_STATUS_REQUEST_NOT_ACCEPTED 0xC0000000 | 0x00d0
++#define NT_STATUS_REDIRECTOR_PAUSED 0xC0000000 | 0x00d1
++#define NT_STATUS_NET_WRITE_FAULT 0xC0000000 | 0x00d2
++#define NT_STATUS_PROFILING_AT_LIMIT 0xC0000000 | 0x00d3
++#define NT_STATUS_NOT_SAME_DEVICE 0xC0000000 | 0x00d4
++#define NT_STATUS_FILE_RENAMED 0xC0000000 | 0x00d5
++#define NT_STATUS_VIRTUAL_CIRCUIT_CLOSED 0xC0000000 | 0x00d6
++#define NT_STATUS_NO_SECURITY_ON_OBJECT 0xC0000000 | 0x00d7
++#define NT_STATUS_CANT_WAIT 0xC0000000 | 0x00d8
++#define NT_STATUS_PIPE_EMPTY 0xC0000000 | 0x00d9
++#define NT_STATUS_CANT_ACCESS_DOMAIN_INFO 0xC0000000 | 0x00da
++#define NT_STATUS_CANT_TERMINATE_SELF 0xC0000000 | 0x00db
++#define NT_STATUS_INVALID_SERVER_STATE 0xC0000000 | 0x00dc
++#define NT_STATUS_INVALID_DOMAIN_STATE 0xC0000000 | 0x00dd
++#define NT_STATUS_INVALID_DOMAIN_ROLE 0xC0000000 | 0x00de
++#define NT_STATUS_NO_SUCH_DOMAIN 0xC0000000 | 0x00df
++#define NT_STATUS_DOMAIN_EXISTS 0xC0000000 | 0x00e0
++#define NT_STATUS_DOMAIN_LIMIT_EXCEEDED 0xC0000000 | 0x00e1
++#define NT_STATUS_OPLOCK_NOT_GRANTED 0xC0000000 | 0x00e2
++#define NT_STATUS_INVALID_OPLOCK_PROTOCOL 0xC0000000 | 0x00e3
++#define NT_STATUS_INTERNAL_DB_CORRUPTION 0xC0000000 | 0x00e4
++#define NT_STATUS_INTERNAL_ERROR 0xC0000000 | 0x00e5
++#define NT_STATUS_GENERIC_NOT_MAPPED 0xC0000000 | 0x00e6
++#define NT_STATUS_BAD_DESCRIPTOR_FORMAT 0xC0000000 | 0x00e7
++#define NT_STATUS_INVALID_USER_BUFFER 0xC0000000 | 0x00e8
++#define NT_STATUS_UNEXPECTED_IO_ERROR 0xC0000000 | 0x00e9
++#define NT_STATUS_UNEXPECTED_MM_CREATE_ERR 0xC0000000 | 0x00ea
++#define NT_STATUS_UNEXPECTED_MM_MAP_ERROR 0xC0000000 | 0x00eb
++#define NT_STATUS_UNEXPECTED_MM_EXTEND_ERR 0xC0000000 | 0x00ec
++#define NT_STATUS_NOT_LOGON_PROCESS 0xC0000000 | 0x00ed
++#define NT_STATUS_LOGON_SESSION_EXISTS 0xC0000000 | 0x00ee
++#define NT_STATUS_INVALID_PARAMETER_1 0xC0000000 | 0x00ef
++#define NT_STATUS_INVALID_PARAMETER_2 0xC0000000 | 0x00f0
++#define NT_STATUS_INVALID_PARAMETER_3 0xC0000000 | 0x00f1
++#define NT_STATUS_INVALID_PARAMETER_4 0xC0000000 | 0x00f2
++#define NT_STATUS_INVALID_PARAMETER_5 0xC0000000 | 0x00f3
++#define NT_STATUS_INVALID_PARAMETER_6 0xC0000000 | 0x00f4
++#define NT_STATUS_INVALID_PARAMETER_7 0xC0000000 | 0x00f5
++#define NT_STATUS_INVALID_PARAMETER_8 0xC0000000 | 0x00f6
++#define NT_STATUS_INVALID_PARAMETER_9 0xC0000000 | 0x00f7
++#define NT_STATUS_INVALID_PARAMETER_10 0xC0000000 | 0x00f8
++#define NT_STATUS_INVALID_PARAMETER_11 0xC0000000 | 0x00f9
++#define NT_STATUS_INVALID_PARAMETER_12 0xC0000000 | 0x00fa
++#define NT_STATUS_REDIRECTOR_NOT_STARTED 0xC0000000 | 0x00fb
++#define NT_STATUS_REDIRECTOR_STARTED 0xC0000000 | 0x00fc
++#define NT_STATUS_STACK_OVERFLOW 0xC0000000 | 0x00fd
++#define NT_STATUS_NO_SUCH_PACKAGE 0xC0000000 | 0x00fe
++#define NT_STATUS_BAD_FUNCTION_TABLE 0xC0000000 | 0x00ff
++#define NT_STATUS_DIRECTORY_NOT_EMPTY 0xC0000000 | 0x0101
++#define NT_STATUS_FILE_CORRUPT_ERROR 0xC0000000 | 0x0102
++#define NT_STATUS_NOT_A_DIRECTORY 0xC0000000 | 0x0103
++#define NT_STATUS_BAD_LOGON_SESSION_STATE 0xC0000000 | 0x0104
++#define NT_STATUS_LOGON_SESSION_COLLISION 0xC0000000 | 0x0105
++#define NT_STATUS_NAME_TOO_LONG 0xC0000000 | 0x0106
++#define NT_STATUS_FILES_OPEN 0xC0000000 | 0x0107
++#define NT_STATUS_CONNECTION_IN_USE 0xC0000000 | 0x0108
++#define NT_STATUS_MESSAGE_NOT_FOUND 0xC0000000 | 0x0109
++#define NT_STATUS_PROCESS_IS_TERMINATING 0xC0000000 | 0x010a
++#define NT_STATUS_INVALID_LOGON_TYPE 0xC0000000 | 0x010b
++#define NT_STATUS_NO_GUID_TRANSLATION 0xC0000000 | 0x010c
++#define NT_STATUS_CANNOT_IMPERSONATE 0xC0000000 | 0x010d
++#define NT_STATUS_IMAGE_ALREADY_LOADED 0xC0000000 | 0x010e
++#define NT_STATUS_ABIOS_NOT_PRESENT 0xC0000000 | 0x010f
++#define NT_STATUS_ABIOS_LID_NOT_EXIST 0xC0000000 | 0x0110
++#define NT_STATUS_ABIOS_LID_ALREADY_OWNED 0xC0000000 | 0x0111
++#define NT_STATUS_ABIOS_NOT_LID_OWNER 0xC0000000 | 0x0112
++#define NT_STATUS_ABIOS_INVALID_COMMAND 0xC0000000 | 0x0113
++#define NT_STATUS_ABIOS_INVALID_LID 0xC0000000 | 0x0114
++#define NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE 0xC0000000 | 0x0115
++#define NT_STATUS_ABIOS_INVALID_SELECTOR 0xC0000000 | 0x0116
++#define NT_STATUS_NO_LDT 0xC0000000 | 0x0117
++#define NT_STATUS_INVALID_LDT_SIZE 0xC0000000 | 0x0118
++#define NT_STATUS_INVALID_LDT_OFFSET 0xC0000000 | 0x0119
++#define NT_STATUS_INVALID_LDT_DESCRIPTOR 0xC0000000 | 0x011a
++#define NT_STATUS_INVALID_IMAGE_NE_FORMAT 0xC0000000 | 0x011b
++#define NT_STATUS_RXACT_INVALID_STATE 0xC0000000 | 0x011c
++#define NT_STATUS_RXACT_COMMIT_FAILURE 0xC0000000 | 0x011d
++#define NT_STATUS_MAPPED_FILE_SIZE_ZERO 0xC0000000 | 0x011e
++#define NT_STATUS_TOO_MANY_OPENED_FILES 0xC0000000 | 0x011f
++#define NT_STATUS_CANCELLED 0xC0000000 | 0x0120
++#define NT_STATUS_CANNOT_DELETE 0xC0000000 | 0x0121
++#define NT_STATUS_INVALID_COMPUTER_NAME 0xC0000000 | 0x0122
++#define NT_STATUS_FILE_DELETED 0xC0000000 | 0x0123
++#define NT_STATUS_SPECIAL_ACCOUNT 0xC0000000 | 0x0124
++#define NT_STATUS_SPECIAL_GROUP 0xC0000000 | 0x0125
++#define NT_STATUS_SPECIAL_USER 0xC0000000 | 0x0126
++#define NT_STATUS_MEMBERS_PRIMARY_GROUP 0xC0000000 | 0x0127
++#define NT_STATUS_FILE_CLOSED 0xC0000000 | 0x0128
++#define NT_STATUS_TOO_MANY_THREADS 0xC0000000 | 0x0129
++#define NT_STATUS_THREAD_NOT_IN_PROCESS 0xC0000000 | 0x012a
++#define NT_STATUS_TOKEN_ALREADY_IN_USE 0xC0000000 | 0x012b
++#define NT_STATUS_PAGEFILE_QUOTA_EXCEEDED 0xC0000000 | 0x012c
++#define NT_STATUS_COMMITMENT_LIMIT 0xC0000000 | 0x012d
++#define NT_STATUS_INVALID_IMAGE_LE_FORMAT 0xC0000000 | 0x012e
++#define NT_STATUS_INVALID_IMAGE_NOT_MZ 0xC0000000 | 0x012f
++#define NT_STATUS_INVALID_IMAGE_PROTECT 0xC0000000 | 0x0130
++#define NT_STATUS_INVALID_IMAGE_WIN_16 0xC0000000 | 0x0131
++#define NT_STATUS_LOGON_SERVER_CONFLICT 0xC0000000 | 0x0132
++#define NT_STATUS_TIME_DIFFERENCE_AT_DC 0xC0000000 | 0x0133
++#define NT_STATUS_SYNCHRONIZATION_REQUIRED 0xC0000000 | 0x0134
++#define NT_STATUS_DLL_NOT_FOUND 0xC0000000 | 0x0135
++#define NT_STATUS_OPEN_FAILED 0xC0000000 | 0x0136
++#define NT_STATUS_IO_PRIVILEGE_FAILED 0xC0000000 | 0x0137
++#define NT_STATUS_ORDINAL_NOT_FOUND 0xC0000000 | 0x0138
++#define NT_STATUS_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0139
++#define NT_STATUS_CONTROL_C_EXIT 0xC0000000 | 0x013a
++#define NT_STATUS_LOCAL_DISCONNECT 0xC0000000 | 0x013b
++#define NT_STATUS_REMOTE_DISCONNECT 0xC0000000 | 0x013c
++#define NT_STATUS_REMOTE_RESOURCES 0xC0000000 | 0x013d
++#define NT_STATUS_LINK_FAILED 0xC0000000 | 0x013e
++#define NT_STATUS_LINK_TIMEOUT 0xC0000000 | 0x013f
++#define NT_STATUS_INVALID_CONNECTION 0xC0000000 | 0x0140
++#define NT_STATUS_INVALID_ADDRESS 0xC0000000 | 0x0141
++#define NT_STATUS_DLL_INIT_FAILED 0xC0000000 | 0x0142
++#define NT_STATUS_MISSING_SYSTEMFILE 0xC0000000 | 0x0143
++#define NT_STATUS_UNHANDLED_EXCEPTION 0xC0000000 | 0x0144
++#define NT_STATUS_APP_INIT_FAILURE 0xC0000000 | 0x0145
++#define NT_STATUS_PAGEFILE_CREATE_FAILED 0xC0000000 | 0x0146
++#define NT_STATUS_NO_PAGEFILE 0xC0000000 | 0x0147
++#define NT_STATUS_INVALID_LEVEL 0xC0000000 | 0x0148
++#define NT_STATUS_WRONG_PASSWORD_CORE 0xC0000000 | 0x0149
++#define NT_STATUS_ILLEGAL_FLOAT_CONTEXT 0xC0000000 | 0x014a
++#define NT_STATUS_PIPE_BROKEN 0xC0000000 | 0x014b
++#define NT_STATUS_REGISTRY_CORRUPT 0xC0000000 | 0x014c
++#define NT_STATUS_REGISTRY_IO_FAILED 0xC0000000 | 0x014d
++#define NT_STATUS_NO_EVENT_PAIR 0xC0000000 | 0x014e
++#define NT_STATUS_UNRECOGNIZED_VOLUME 0xC0000000 | 0x014f
++#define NT_STATUS_SERIAL_NO_DEVICE_INITED 0xC0000000 | 0x0150
++#define NT_STATUS_NO_SUCH_ALIAS 0xC0000000 | 0x0151
++#define NT_STATUS_MEMBER_NOT_IN_ALIAS 0xC0000000 | 0x0152
++#define NT_STATUS_MEMBER_IN_ALIAS 0xC0000000 | 0x0153
++#define NT_STATUS_ALIAS_EXISTS 0xC0000000 | 0x0154
++#define NT_STATUS_LOGON_NOT_GRANTED 0xC0000000 | 0x0155
++#define NT_STATUS_TOO_MANY_SECRETS 0xC0000000 | 0x0156
++#define NT_STATUS_SECRET_TOO_LONG 0xC0000000 | 0x0157
++#define NT_STATUS_INTERNAL_DB_ERROR 0xC0000000 | 0x0158
++#define NT_STATUS_FULLSCREEN_MODE 0xC0000000 | 0x0159
++#define NT_STATUS_TOO_MANY_CONTEXT_IDS 0xC0000000 | 0x015a
++#define NT_STATUS_LOGON_TYPE_NOT_GRANTED 0xC0000000 | 0x015b
++#define NT_STATUS_NOT_REGISTRY_FILE 0xC0000000 | 0x015c
++#define NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x015d
++#define NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR 0xC0000000 | 0x015e
++#define NT_STATUS_FT_MISSING_MEMBER 0xC0000000 | 0x015f
++#define NT_STATUS_ILL_FORMED_SERVICE_ENTRY 0xC0000000 | 0x0160
++#define NT_STATUS_ILLEGAL_CHARACTER 0xC0000000 | 0x0161
++#define NT_STATUS_UNMAPPABLE_CHARACTER 0xC0000000 | 0x0162
++#define NT_STATUS_UNDEFINED_CHARACTER 0xC0000000 | 0x0163
++#define NT_STATUS_FLOPPY_VOLUME 0xC0000000 | 0x0164
++#define NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND 0xC0000000 | 0x0165
++#define NT_STATUS_FLOPPY_WRONG_CYLINDER 0xC0000000 | 0x0166
++#define NT_STATUS_FLOPPY_UNKNOWN_ERROR 0xC0000000 | 0x0167
++#define NT_STATUS_FLOPPY_BAD_REGISTERS 0xC0000000 | 0x0168
++#define NT_STATUS_DISK_RECALIBRATE_FAILED 0xC0000000 | 0x0169
++#define NT_STATUS_DISK_OPERATION_FAILED 0xC0000000 | 0x016a
++#define NT_STATUS_DISK_RESET_FAILED 0xC0000000 | 0x016b
++#define NT_STATUS_SHARED_IRQ_BUSY 0xC0000000 | 0x016c
++#define NT_STATUS_FT_ORPHANING 0xC0000000 | 0x016d
++#define NT_STATUS_PARTITION_FAILURE 0xC0000000 | 0x0172
++#define NT_STATUS_INVALID_BLOCK_LENGTH 0xC0000000 | 0x0173
++#define NT_STATUS_DEVICE_NOT_PARTITIONED 0xC0000000 | 0x0174
++#define NT_STATUS_UNABLE_TO_LOCK_MEDIA 0xC0000000 | 0x0175
++#define NT_STATUS_UNABLE_TO_UNLOAD_MEDIA 0xC0000000 | 0x0176
++#define NT_STATUS_EOM_OVERFLOW 0xC0000000 | 0x0177
++#define NT_STATUS_NO_MEDIA 0xC0000000 | 0x0178
++#define NT_STATUS_NO_SUCH_MEMBER 0xC0000000 | 0x017a
++#define NT_STATUS_INVALID_MEMBER 0xC0000000 | 0x017b
++#define NT_STATUS_KEY_DELETED 0xC0000000 | 0x017c
++#define NT_STATUS_NO_LOG_SPACE 0xC0000000 | 0x017d
++#define NT_STATUS_TOO_MANY_SIDS 0xC0000000 | 0x017e
++#define NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED 0xC0000000 | 0x017f
++#define NT_STATUS_KEY_HAS_CHILDREN 0xC0000000 | 0x0180
++#define NT_STATUS_CHILD_MUST_BE_VOLATILE 0xC0000000 | 0x0181
++#define NT_STATUS_DEVICE_CONFIGURATION_ERROR 0xC0000000 | 0x0182
++#define NT_STATUS_DRIVER_INTERNAL_ERROR 0xC0000000 | 0x0183
++#define NT_STATUS_INVALID_DEVICE_STATE 0xC0000000 | 0x0184
++#define NT_STATUS_IO_DEVICE_ERROR 0xC0000000 | 0x0185
++#define NT_STATUS_DEVICE_PROTOCOL_ERROR 0xC0000000 | 0x0186
++#define NT_STATUS_BACKUP_CONTROLLER 0xC0000000 | 0x0187
++#define NT_STATUS_LOG_FILE_FULL 0xC0000000 | 0x0188
++#define NT_STATUS_TOO_LATE 0xC0000000 | 0x0189
++#define NT_STATUS_NO_TRUST_LSA_SECRET 0xC0000000 | 0x018a
++#define NT_STATUS_NO_TRUST_SAM_ACCOUNT 0xC0000000 | 0x018b
++#define NT_STATUS_TRUSTED_DOMAIN_FAILURE 0xC0000000 | 0x018c
++#define NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE 0xC0000000 | 0x018d
++#define NT_STATUS_EVENTLOG_FILE_CORRUPT 0xC0000000 | 0x018e
++#define NT_STATUS_EVENTLOG_CANT_START 0xC0000000 | 0x018f
++#define NT_STATUS_TRUST_FAILURE 0xC0000000 | 0x0190
++#define NT_STATUS_MUTANT_LIMIT_EXCEEDED 0xC0000000 | 0x0191
++#define NT_STATUS_NETLOGON_NOT_STARTED 0xC0000000 | 0x0192
++#define NT_STATUS_ACCOUNT_EXPIRED 0xC0000000 | 0x0193
++#define NT_STATUS_POSSIBLE_DEADLOCK 0xC0000000 | 0x0194
++#define NT_STATUS_NETWORK_CREDENTIAL_CONFLICT 0xC0000000 | 0x0195
++#define NT_STATUS_REMOTE_SESSION_LIMIT 0xC0000000 | 0x0196
++#define NT_STATUS_EVENTLOG_FILE_CHANGED 0xC0000000 | 0x0197
++#define NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT 0xC0000000 | 0x0198
++#define NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT 0xC0000000 | 0x0199
++#define NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT 0xC0000000 | 0x019a
++#define NT_STATUS_DOMAIN_TRUST_INCONSISTENT 0xC0000000 | 0x019b
++#define NT_STATUS_FS_DRIVER_REQUIRED 0xC0000000 | 0x019c
++#define NT_STATUS_NO_USER_SESSION_KEY 0xC0000000 | 0x0202
++#define NT_STATUS_USER_SESSION_DELETED 0xC0000000 | 0x0203
++#define NT_STATUS_RESOURCE_LANG_NOT_FOUND 0xC0000000 | 0x0204
++#define NT_STATUS_INSUFF_SERVER_RESOURCES 0xC0000000 | 0x0205
++#define NT_STATUS_INVALID_BUFFER_SIZE 0xC0000000 | 0x0206
++#define NT_STATUS_INVALID_ADDRESS_COMPONENT 0xC0000000 | 0x0207
++#define NT_STATUS_INVALID_ADDRESS_WILDCARD 0xC0000000 | 0x0208
++#define NT_STATUS_TOO_MANY_ADDRESSES 0xC0000000 | 0x0209
++#define NT_STATUS_ADDRESS_ALREADY_EXISTS 0xC0000000 | 0x020a
++#define NT_STATUS_ADDRESS_CLOSED 0xC0000000 | 0x020b
++#define NT_STATUS_CONNECTION_DISCONNECTED 0xC0000000 | 0x020c
++#define NT_STATUS_CONNECTION_RESET 0xC0000000 | 0x020d
++#define NT_STATUS_TOO_MANY_NODES 0xC0000000 | 0x020e
++#define NT_STATUS_TRANSACTION_ABORTED 0xC0000000 | 0x020f
++#define NT_STATUS_TRANSACTION_TIMED_OUT 0xC0000000 | 0x0210
++#define NT_STATUS_TRANSACTION_NO_RELEASE 0xC0000000 | 0x0211
++#define NT_STATUS_TRANSACTION_NO_MATCH 0xC0000000 | 0x0212
++#define NT_STATUS_TRANSACTION_RESPONDED 0xC0000000 | 0x0213
++#define NT_STATUS_TRANSACTION_INVALID_ID 0xC0000000 | 0x0214
++#define NT_STATUS_TRANSACTION_INVALID_TYPE 0xC0000000 | 0x0215
++#define NT_STATUS_NOT_SERVER_SESSION 0xC0000000 | 0x0216
++#define NT_STATUS_NOT_CLIENT_SESSION 0xC0000000 | 0x0217
++#define NT_STATUS_CANNOT_LOAD_REGISTRY_FILE 0xC0000000 | 0x0218
++#define NT_STATUS_DEBUG_ATTACH_FAILED 0xC0000000 | 0x0219
++#define NT_STATUS_SYSTEM_PROCESS_TERMINATED 0xC0000000 | 0x021a
++#define NT_STATUS_DATA_NOT_ACCEPTED 0xC0000000 | 0x021b
++#define NT_STATUS_NO_BROWSER_SERVERS_FOUND 0xC0000000 | 0x021c
++#define NT_STATUS_VDM_HARD_ERROR 0xC0000000 | 0x021d
++#define NT_STATUS_DRIVER_CANCEL_TIMEOUT 0xC0000000 | 0x021e
++#define NT_STATUS_REPLY_MESSAGE_MISMATCH 0xC0000000 | 0x021f
++#define NT_STATUS_MAPPED_ALIGNMENT 0xC0000000 | 0x0220
++#define NT_STATUS_IMAGE_CHECKSUM_MISMATCH 0xC0000000 | 0x0221
++#define NT_STATUS_LOST_WRITEBEHIND_DATA 0xC0000000 | 0x0222
++#define NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID 0xC0000000 | 0x0223
++#define NT_STATUS_PASSWORD_MUST_CHANGE 0xC0000000 | 0x0224
++#define NT_STATUS_NOT_FOUND 0xC0000000 | 0x0225
++#define NT_STATUS_NOT_TINY_STREAM 0xC0000000 | 0x0226
++#define NT_STATUS_RECOVERY_FAILURE 0xC0000000 | 0x0227
++#define NT_STATUS_STACK_OVERFLOW_READ 0xC0000000 | 0x0228
++#define NT_STATUS_FAIL_CHECK 0xC0000000 | 0x0229
++#define NT_STATUS_DUPLICATE_OBJECTID 0xC0000000 | 0x022a
++#define NT_STATUS_OBJECTID_EXISTS 0xC0000000 | 0x022b
++#define NT_STATUS_CONVERT_TO_LARGE 0xC0000000 | 0x022c
++#define NT_STATUS_RETRY 0xC0000000 | 0x022d
++#define NT_STATUS_FOUND_OUT_OF_SCOPE 0xC0000000 | 0x022e
++#define NT_STATUS_ALLOCATE_BUCKET 0xC0000000 | 0x022f
++#define NT_STATUS_PROPSET_NOT_FOUND 0xC0000000 | 0x0230
++#define NT_STATUS_MARSHALL_OVERFLOW 0xC0000000 | 0x0231
++#define NT_STATUS_INVALID_VARIANT 0xC0000000 | 0x0232
++#define NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND 0xC0000000 | 0x0233
++#define NT_STATUS_ACCOUNT_LOCKED_OUT 0xC0000000 | 0x0234
++#define NT_STATUS_HANDLE_NOT_CLOSABLE 0xC0000000 | 0x0235
++#define NT_STATUS_CONNECTION_REFUSED 0xC0000000 | 0x0236
++#define NT_STATUS_GRACEFUL_DISCONNECT 0xC0000000 | 0x0237
++#define NT_STATUS_ADDRESS_ALREADY_ASSOCIATED 0xC0000000 | 0x0238
++#define NT_STATUS_ADDRESS_NOT_ASSOCIATED 0xC0000000 | 0x0239
++#define NT_STATUS_CONNECTION_INVALID 0xC0000000 | 0x023a
++#define NT_STATUS_CONNECTION_ACTIVE 0xC0000000 | 0x023b
++#define NT_STATUS_NETWORK_UNREACHABLE 0xC0000000 | 0x023c
++#define NT_STATUS_HOST_UNREACHABLE 0xC0000000 | 0x023d
++#define NT_STATUS_PROTOCOL_UNREACHABLE 0xC0000000 | 0x023e
++#define NT_STATUS_PORT_UNREACHABLE 0xC0000000 | 0x023f
++#define NT_STATUS_REQUEST_ABORTED 0xC0000000 | 0x0240
++#define NT_STATUS_CONNECTION_ABORTED 0xC0000000 | 0x0241
++#define NT_STATUS_BAD_COMPRESSION_BUFFER 0xC0000000 | 0x0242
++#define NT_STATUS_USER_MAPPED_FILE 0xC0000000 | 0x0243
++#define NT_STATUS_AUDIT_FAILED 0xC0000000 | 0x0244
++#define NT_STATUS_TIMER_RESOLUTION_NOT_SET 0xC0000000 | 0x0245
++#define NT_STATUS_CONNECTION_COUNT_LIMIT 0xC0000000 | 0x0246
++#define NT_STATUS_LOGIN_TIME_RESTRICTION 0xC0000000 | 0x0247
++#define NT_STATUS_LOGIN_WKSTA_RESTRICTION 0xC0000000 | 0x0248
++#define NT_STATUS_IMAGE_MP_UP_MISMATCH 0xC0000000 | 0x0249
++#define NT_STATUS_INSUFFICIENT_LOGON_INFO 0xC0000000 | 0x0250
++#define NT_STATUS_BAD_DLL_ENTRYPOINT 0xC0000000 | 0x0251
++#define NT_STATUS_BAD_SERVICE_ENTRYPOINT 0xC0000000 | 0x0252
++#define NT_STATUS_LPC_REPLY_LOST 0xC0000000 | 0x0253
++#define NT_STATUS_IP_ADDRESS_CONFLICT1 0xC0000000 | 0x0254
++#define NT_STATUS_IP_ADDRESS_CONFLICT2 0xC0000000 | 0x0255
++#define NT_STATUS_REGISTRY_QUOTA_LIMIT 0xC0000000 | 0x0256
++#define NT_STATUS_PATH_NOT_COVERED 0xC0000000 | 0x0257
++#define NT_STATUS_NO_CALLBACK_ACTIVE 0xC0000000 | 0x0258
++#define NT_STATUS_LICENSE_QUOTA_EXCEEDED 0xC0000000 | 0x0259
++#define NT_STATUS_PWD_TOO_SHORT 0xC0000000 | 0x025a
++#define NT_STATUS_PWD_TOO_RECENT 0xC0000000 | 0x025b
++#define NT_STATUS_PWD_HISTORY_CONFLICT 0xC0000000 | 0x025c
++#define NT_STATUS_PLUGPLAY_NO_DEVICE 0xC0000000 | 0x025e
++#define NT_STATUS_UNSUPPORTED_COMPRESSION 0xC0000000 | 0x025f
++#define NT_STATUS_INVALID_HW_PROFILE 0xC0000000 | 0x0260
++#define NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH 0xC0000000 | 0x0261
++#define NT_STATUS_DRIVER_ORDINAL_NOT_FOUND 0xC0000000 | 0x0262
++#define NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND 0xC0000000 | 0x0263
++#define NT_STATUS_RESOURCE_NOT_OWNED 0xC0000000 | 0x0264
++#define NT_STATUS_TOO_MANY_LINKS 0xC0000000 | 0x0265
++#define NT_STATUS_QUOTA_LIST_INCONSISTENT 0xC0000000 | 0x0266
++#define NT_STATUS_FILE_IS_OFFLINE 0xC0000000 | 0x0267
++#define NT_STATUS_NO_SUCH_JOB 0xC0000000 | 0xEDE /* scheduler */
++
++#endif /* _NTERR_H */
+diff -urN linux-2.4.29.old/fs/cifs/ntlmssp.h linux-2.4.29/fs/cifs/ntlmssp.h
+--- linux-2.4.29.old/fs/cifs/ntlmssp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/ntlmssp.h 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,101 @@
++/*
++ * fs/cifs/ntlmssp.h
++ *
++ * Copyright (c) International Business Machines Corp., 2002
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#pragma pack(1)
++
++#define NTLMSSP_SIGNATURE "NTLMSSP"
++/* Message Types */
++#define NtLmNegotiate 1
++#define NtLmChallenge 2
++#define NtLmAuthenticate 3
++#define UnknownMessage 8
++
++/* Negotiate Flags */
++#define NTLMSSP_NEGOTIATE_UNICODE 0x01 // Text strings are in unicode
++#define NTLMSSP_NEGOTIATE_OEM 0x02 // Text strings are in OEM
++#define NTLMSSP_REQUEST_TARGET 0x04 // Server return its auth realm
++#define NTLMSSP_NEGOTIATE_SIGN 0x0010 // Request signature capability
++#define NTLMSSP_NEGOTIATE_SEAL 0x0020 // Request confidentiality
++#define NTLMSSP_NEGOTIATE_DGRAM 0x0040
++#define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 // Use LM session key for sign/seal
++#define NTLMSSP_NEGOTIATE_NTLM 0x0200 // NTLM authentication
++#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000
++#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000
++#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 // client/server on same machine
++#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 // Sign for all security levels
++#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000
++#define NTLMSSP_TARGET_TYPE_SERVER 0x20000
++#define NTLMSSP_TARGET_TYPE_SHARE 0x40000
++#define NTLMSSP_NEGOTIATE_NTLMV2 0x80000
++#define NTLMSSP_REQUEST_INIT_RESP 0x100000
++#define NTLMSSP_REQUEST_ACCEPT_RESP 0x200000
++#define NTLMSSP_REQUEST_NOT_NT_KEY 0x400000
++#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x800000
++#define NTLMSSP_NEGOTIATE_128 0x20000000
++#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000
++#define NTLMSSP_NEGOTIATE_56 0x80000000
++
++/* Although typedefs are not commonly used for structure definitions */
++/* in the Linux kernel, in this particular case they are useful */
++/* to more closely match the standards document for NTLMSSP from */
++/* OpenGroup and to make the code more closely match the standard in */
++/* appearance */
++
++typedef struct _SECURITY_BUFFER {
++ __u16 Length;
++ __u16 MaximumLength;
++ __u32 Buffer; /* offset to buffer */
++} SECURITY_BUFFER;
++
++typedef struct _NEGOTIATE_MESSAGE {
++ __u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
++ __u32 MessageType; /* 1 */
++ __u32 NegotiateFlags;
++ SECURITY_BUFFER DomainName; /* RFC 1001 style and ASCII */
++ SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */
++ char DomainString[0];
++ /* followed by WorkstationString */
++} NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE;
++
++typedef struct _CHALLENGE_MESSAGE {
++ __u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
++ __u32 MessageType; /* 2 */
++ SECURITY_BUFFER TargetName;
++ __u32 NegotiateFlags;
++ __u8 Challenge[CIFS_CRYPTO_KEY_SIZE];
++ __u8 Reserved[8];
++ SECURITY_BUFFER TargetInfoArray;
++} CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE;
++
++typedef struct _AUTHENTICATE_MESSAGE {
++ __u8 Signature[sizeof (NTLMSSP_SIGNATURE)];
++ __u32 MessageType; /* 3 */
++ SECURITY_BUFFER LmChallengeResponse;
++ SECURITY_BUFFER NtChallengeResponse;
++ SECURITY_BUFFER DomainName;
++ SECURITY_BUFFER UserName;
++ SECURITY_BUFFER WorkstationName;
++ SECURITY_BUFFER SessionKey;
++ __u32 NegotiateFlags;
++ char UserString[0];
++} AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
++
++#pragma pack() /* resume default structure packing */
+diff -urN linux-2.4.29.old/fs/cifs/README linux-2.4.29/fs/cifs/README
+--- linux-2.4.29.old/fs/cifs/README 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/README 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,356 @@
++The CIFS VFS support for Linux supports many advanced network filesystem
++features such as heirarchical dfs like namespace, hardlinks, locking and more.
++It was designed to comply with the SNIA CIFS Technical Reference (which
++supersedes the 1992 X/Open SMB Standard) as well as to perform best practice
++practical interoperability with Windows 2000, Windows XP, Samba and equivalent
++servers.
++
++For questions or bug reports please contact:
++ sfrench@samba.org (sfrench@us.ibm.com)
++
++Build instructions:
++==================
++For Linux 2.4:
++1) Get the kernel source (e.g.from http://www.kernel.org)
++and download the cifs vfs source (see the project page
++at http://us1.samba.org/samba/Linux_CIFS_client.html)
++and change directory into the top of the kernel directory
++then patch the kernel (e.g. "patch -p1 < cifs_24.patch")
++to add the cifs vfs to your kernel configure options if
++it has not already been added (e.g. current SuSE and UL
++users do not need to apply the cifs_24.patch since the cifs vfs is
++already in the kernel configure menu) and then
++mkdir linux/fs/cifs and then copy the current cifs vfs files from
++the cifs download to your kernel build directory e.g.
++
++ cp <cifs_download_dir>/fs/cifs/* to <kernel_download_dir>/fs/cifs
++
++2) make menuconfig (or make xconfig)
++3) select cifs from within the network filesystem choices
++4) save and exit
++5) make dep
++6) make modules (or "make" if CIFS VFS not to be built as a module)
++
++For Linux 2.5:
++1) Download the kernel (e.g. from http://www.kernel.org or from bitkeeper
++at bk://linux.bkbits.net/linux-2.5) and change directory into the top
++of the kernel directory tree (e.g. /usr/src/linux-2.5.73)
++2) make menuconfig (or make xconfig)
++3) select cifs from within the network filesystem choices
++4) save and exit
++5) make
++
++
++Installation instructions:
++=========================
++If you have built the CIFS vfs as module (successfully) simply
++type "make modules_install" (or if you prefer, manually copy the file to
++the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o).
++
++If you have built the CIFS vfs into the kernel itself, follow the instructions
++for your distribution on how to install a new kernel (usually you
++would simply type "make install").
++
++If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on
++the CIFS VFS web site) copy it to the same directory in which mount.smbfs and
++similar files reside (usually /sbin). Although the helper software is not
++required, mount.cifs is recommended. Eventually the Samba 3.0 utility program
++"net" may also be helpful since it may someday provide easier mount syntax for
++users who are used to Windows e.g. net use <mount point> <UNC name or cifs URL>
++Note that running the Winbind pam/nss module (logon service) on all of your
++Linux clients is useful in mapping Uids and Gids consistently across the
++domain to the proper network user. The mount.cifs mount helper can be
++trivially built from Samba 3.0 or later source e.g. by executing:
++
++ gcc samba/source/client/mount.cifs.c -o mount.cifs
++
++Note that when the mount.cifs utility is run suid (allowing user mounts),
++in order to reduce risks, the "nosuid" mount flag is passed in on mount to
++disallow execution of an suid program mounted on the remote target.
++When mount is executed as root, nosuid is not passed in by default,
++and execution of suid programs on the remote target would be enabled
++by default. This can be changed, as with nfs and other filesystems,
++by simply specifying "nosuid" among the mount options. For user mounts
++though to be able to pass the suid flag to mount requires rebuilding
++mount.cifs with the following flag:
++
++ gcc samba/source/client/mount.cifs.c -DCIFS_ALLOW_USR_SUID -o mount.cifs
++
++There is a corresponding manual page for cifs mounting in the Samba 3.0 and
++later source tree in docs/manpages/mount.cifs.8
++
++Samba Considerations
++====================
++To get the maximum benefit from the CIFS VFS, we recommend using a server that
++supports the SNIA CIFS Unix Extensions standard (e.g. Samba 2.2.5 or later or
++Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers.
++Note that uid, gid and file permissions will display default values if you do
++not have a server that supports the Unix extensions for CIFS (such as Samba
++2.2.5 or later). To enable the Unix CIFS Extensions in the Samba server, add
++the line:
++
++ unix extensions = yes
++
++to your smb.conf file on the server. Note that the following smb.conf settings
++are also useful (on the Samba server) when the majority of clients are Unix or
++Linux:
++
++ case sensitive = yes
++ delete readonly = yes
++ ea support = yes
++
++Note that ea support is required for supporting Linux xattrs.
++Some administrators also change the "map archive" and the "create mask"
++parameters from their default values. Creating special devices (mknod)
++remotely may require specifying a mkdev function to Samba if you are not using
++Samba 3.0.5 or later. For more information on these see the manual pages
++("man smb.conf") on the Samba server system. Note that the cifs vfs,
++unlike the smbfs vfs, does not read the smb.conf on the client system
++(the few optional settings are passed in on mount via -o parameters instead).
++Note that Samba 2.2.7 or later includes a fix that allows the CIFS VFS to delete
++open files (required for strict POSIX compliance). Windows Servers already
++supported this feature. Samba server does not allow symlinks that refer to files
++outside of the share, so in Samba versions prior to 3.0.5, most symlinks to
++files with absolute paths (ie beginning with slash) such as:
++ ln -s /mnt/foo bar
++would be forbidden. Samba 3.0.5 server or later includes the ability to create
++such symlinks safely by converting unsafe symlinks (ie symlinks to server
++files that are outside of the share) to a samba specific format on the server
++that is ignored by local server applications and non-cifs clients and that will
++not be traversed by the Samba server). This is opaque to the Linux client
++application using the cifs vfs. Absolute symlinks will work to Samba 3.0.5 or
++later, but only for remote clients using the CIFS Unix extensions, and will
++be invisbile to Windows clients and typically will not affect local
++applications running on the same server as Samba.
++
++Use instructions:
++================
++Once the CIFS VFS support is built into the kernel or installed as a module
++(cifs.o), you can use mount syntax like the following to access Samba or Windows
++servers:
++
++ mount -t cifs //9.53.216.11/e$ /mnt -o user=myname,pass=mypassword
++
++Before -o the option -v may be specified to make the mount.cifs
++mount helper display the mount steps more verbosely.
++After -o the following commonly used cifs vfs specific options
++are supported:
++
++ user=<username>
++ pass=<password>
++ domain=<domain name>
++
++Other cifs mount options are described below. Use of TCP names (in addition to
++ip addresses) is available if the mount helper (mount.cifs) is installed. If
++you do not trust the server to which are mounted, or if you do not have
++cifs signing enabled (and the physical network is insecure), consider use
++of the standard mount options "noexec" and "nosuid" to reduce the risk of
++running an altered binary on your local system (downloaded from a hostile server
++or altered by a hostile router).
++
++When using the mount helper mount.cifs, passwords may be specified via alternate
++mechanisms, instead of specifying it after -o using the normal "pass=" syntax
++on the command line:
++1) By including it in a credential file. Specify credentials=filename as one
++of the mount options. Credential files contain two lines
++ username=someuser
++ password=your_password
++2) By specifying the password in the PASSWD environment variable (similarly
++the user name can be taken from the USER environment variable).
++3) By specifying the password in a file by name via PASSWD_FILE
++4) By specifying the password in a file by file descriptor via PASSWD_FD
++
++If no password is provided, mount.cifs will prompt for password entry
++
++Restrictions
++============
++Servers must support the NTLM SMB dialect (which is the most recent, supported
++by Samba and Windows NT version 4, 2000 and XP and many other SMB/CIFS servers)
++Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC
++1001/1002 support for "Netbios-Over-TCP/IP." Neither of these is likely to be a
++problem as most servers support this. IPv6 support is planned for the future.
++
++CIFS VFS Mount Options
++======================
++A partial list of the supported mount options follows:
++ user The user name to use when trying to establish
++ the CIFS session.
++ password The user password. If the mount helper is
++ installed, the user will be prompted for password
++ if it is not supplied.
++ ip The ip address of the target server
++ unc The target server Universal Network Name (export) to
++ mount.
++ domain Set the SMB/CIFS workgroup name prepended to the
++ username during CIFS session establishment
++ uid If CIFS Unix extensions are not supported by the server
++ this overrides the default uid for inodes. For mounts to
++ servers which do support the CIFS Unix extensions, such
++ as a properly configured Samba server, the server provides
++ the uid, gid and mode. For servers which do not support
++ the Unix extensions, the default uid (and gid) returned on
++ lookup of existing files is the uid (gid) of the person
++ who executed the mount (root, except when mount.cifs
++ is configured setuid for user mounts) unless the "uid="
++ (gid) mount option is specified. For the uid (gid) of newly
++ created files and directories, ie files created since
++ the last mount of the server share, the expected uid
++ (gid) is cached as as long as the inode remains in
++ memory on the client. Also note that permission
++ checks (authorization checks) on accesses to a file occur
++ at the server, but there are cases in which an administrator
++ may want to restrict at the client as well. For those
++ servers which do not report a uid/gid owner
++ (such as Windows), permissions can also be checked at the
++ client, and a crude form of client side permission checking
++ can be enabled by specifying file_mode and dir_mode on
++ the client
++ gid If CIFS Unix extensions are not supported by the server
++ this overrides the default gid for inodes.
++ file_mode If CIFS Unix extensions are not supported by the server
++ this overrides the default mode for file inodes.
++ dir_mode If CIFS Unix extensions are not supported by the server
++ this overrides the default mode for directory inodes.
++ port attempt to contact the server on this tcp port, before
++ trying the usual ports (port 445, then 139).
++ iocharset Codepage used to convert local path names to and from
++ Unicode. Unicode is used by default for network path
++ names if the server supports it. If iocharset is
++ not specified then the nls_default specified
++ during the local client kernel build will be used.
++ If server does not support Unicode, this parameter is
++ unused.
++ rsize default read size
++ wsize default write size
++ rw mount the network share read-write (note that the
++ server may still consider the share read-only)
++ ro mount network share read-only
++ version used to distinguish different versions of the
++ mount helper utility (not typically needed)
++ sep if first mount option (after the -o), overrides
++ the comma as the separator between the mount
++ parms. e.g.
++ -o user=myname,password=mypassword,domain=mydom
++ could be passed instead with period as the separator by
++ -o sep=.user=myname.password=mypassword.domain=mydom
++ this might be useful when comma is contained within username
++ or password or domain. This option is less important
++ when the cifs mount helper cifs.mount (version 1.1 or later)
++ is used.
++ nosuid Do not allow remote executables with the suid bit
++ program to be executed. This is only meaningful for mounts
++ to servers such as Samba which support the CIFS Unix Extensions.
++ If you do not trust the servers in your network (your mount
++ targets) it is recommended that you specify this option for
++ greater security.
++ suid Allow remote files on this mountpoint with suid enabled to
++ be executed (default for mounts when executed as root,
++ nosuid is default for user mounts).
++ credentials Although ignored by the cifs kernel component, it is used by
++ the mount helper, mount.cifs. When mount.cifs is installed it
++ opens and reads the credential file specified in order
++ to obtain the userid and password arguments which are passed to
++ the cifs vfs.
++ guest Although ignored by the kernel component, the mount.cifs
++ mount helper will not prompt the user for a password
++ if guest is specified on the mount options. If no
++ password is specified a null password will be used.
++
++The mount.cifs mount helper also accepts a few mount options before -o
++including:
++
++ -S take password from stdin (equivalent to setting the environment
++ variable "PASSWD_FD=0"
++ -V print mount.cifs version
++ -? display simple usage information
++
++With recent 2.6 kernel versions of modutils, the version of the cifs kernel
++module can be displayed via modinfo.
++
++Misc /proc/fs/cifs Flags and Debug Info
++=======================================
++Informational pseudo-files:
++DebugData Displays information about active CIFS sessions
++ and shares.
++Stats Lists summary resource usage information as well as per
++ share statistics, if CONFIG_CIFS_STATS in enabled
++ in the kernel configuration.
++
++Configuration pseudo-files:
++MultiuserMount If set to one, more than one CIFS session to
++ the same server ip address can be established
++ if more than one uid accesses the same mount
++ point and if the uids user/password mapping
++ information is available. (default is 0)
++PacketSigningEnabled If set to one, cifs packet signing is enabled
++ and will be used if the server requires
++ it. If set to two, cifs packet signing is
++ required even if the server considers packet
++ signing optional. (default 1)
++cifsFYI If set to one, additional debug information is
++ logged to the system error log. (default 0)
++ExtendedSecurity If set to one, SPNEGO session establishment
++ is allowed which enables more advanced
++ secure CIFS session establishment (default 0)
++NTLMV2Enabled If set to one, more secure password hashes
++ are used when the server supports them and
++ when kerberos is not negotiated (default 0)
++traceSMB If set to one, debug information is logged to the
++ system error log with the start of smb requests
++ and responses (default 0)
++LookupCacheEnable If set to one, inode information is kept cached
++ for one second improving performance of lookups
++ (default 1)
++OplockEnabled If set to one, safe distributed caching enabled.
++ (default 1)
++LinuxExtensionsEnabled If set to one then the client will attempt to
++ use the CIFS "UNIX" extensions which are optional
++ protocol enhancements that allow CIFS servers
++ to return accurate UID/GID information as well
++ as support symbolic links. If you use servers
++ such as Samba that support the CIFS Unix
++ extensions but do not want to use symbolic link
++ support and want to map the uid and gid fields
++ to values supplied at mount (rather than the
++ actual values, then set this to zero. (default 1)
++
++These experimental features and tracing can be enabled by changing flags in
++/proc/fs/cifs (after the cifs module has been installed or built into the
++kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable
++tracing to the kernel message log type:
++
++ echo 1 > /proc/fs/cifs/cifsFYI
++
++and for more extensive tracing including the start of smb requests and responses
++
++ echo 1 > /proc/fs/cifs/traceSMB
++
++Three other experimental features are under development and to test
++require enabling an ifdef (e.g. by adding "#define CIFS_FCNTL" in cifsglob.h)
++
++ CONFIG_CIFS_QUOTA
++
++ CONFIG_CIFS_XATTR
++
++ CONFIG_CIFS_FCNTL (fcntl needed for support of directory change
++ notification and perhaps later for file leases)
++
++Per share (per client mount) statistics are available in /proc/fs/cifs/DebugData
++if the kernel was configured with cifs statistics enabled. The statistics
++represent the number of successful (ie non-zero return code from the server)
++SMB responses to some of the more common commands (open, delete, mkdir etc.).
++Also recorded is the total bytes read and bytes written to the server for
++that share. Note that due to client caching effects this can be less than the
++number of bytes read and written by the application running on the client.
++The statistics for the number of total SMBs and oplock breaks are different in
++that they represent all for that share, not just those for which the server
++returned success.
++
++Also note that "cat /proc/fs/cifs/DebugData" will display information about
++the active sessions and the shares that are mounted. Note: NTLMv2 enablement
++will not work since they its implementation is not quite complete yet.
++Do not alter these configuration values unless you are doing specific testing.
++Enabling extended security works to Windows 2000 Workstations and XP but not to
++Windows 2000 server or Samba since it does not usually send "raw NTLMSSP"
++(instead it sends NTLMSSP encapsulated in SPNEGO/GSSAPI, which support is not
++complete in the CIFS VFS yet).
+diff -urN linux-2.4.29.old/fs/cifs/rfc1002pdu.h linux-2.4.29/fs/cifs/rfc1002pdu.h
+--- linux-2.4.29.old/fs/cifs/rfc1002pdu.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/rfc1002pdu.h 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,79 @@
++/*
++ * fs/cifs/rfc1002pdu.h
++ *
++ * Protocol Data Unit definitions for RFC 1001/1002 support
++ *
++ * Copyright (c) International Business Machines Corp., 2004
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#pragma pack(1)
++
++/* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */
++
++ /* RFC 1002 session packet types */
++#define RFC1002_SESSION_MESASAGE 0x00
++#define RFC1002_SESSION_REQUEST 0x81
++#define RFC1002_POSITIVE_SESSION_RESPONSE 0x82
++#define RFC1002_NEGATIVE_SESSION_RESPONSE 0x83
++#define RFC1002_RETARGET_SESSION_RESPONSE 0x83
++#define RFC1002_SESSION_KEEP_ALIVE 0x85
++
++ /* RFC 1002 flags (only one defined */
++#define RFC1002_LENGTH_EXTEND 0x80 /* high order bit of length (ie +64K) */
++
++struct rfc1002_session_packet {
++ __u8 type;
++ __u8 flags;
++ __u16 length;
++ union {
++ struct {
++ __u8 called_len;
++ __u8 called_name[32];
++ __u8 scope1; /* null */
++ __u8 calling_len;
++ __u8 calling_name[32];
++ __u8 scope2; /* null */
++ } session_req;
++ struct {
++ __u32 retarget_ip_addr;
++ __u16 port;
++ } retarget_resp;
++ __u8 neg_ses_resp_error_code;
++ /* POSITIVE_SESSION_RESPONSE packet does not include trailer.
++ SESSION_KEEP_ALIVE packet also does not include a trailer.
++ Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */
++ } trailer;
++};
++
++/* Negative Session Response error codes */
++#define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */
++#define RFC1002_NOT_LISTENING_CALLING 0x81 /* not listening on calling name */
++#define RFC1002_NOT_PRESENT 0x82 /* called name not present */
++#define RFC1002_INSUFFICIENT_RESOURCE 0x83
++#define RFC1002_UNSPECIFIED_ERROR 0x8F
++
++/* RFC 1002 Datagram service packets are not defined here as they
++are not needed for the network filesystem client unless we plan on
++implementing broadcast resolution of the server ip address (from
++server netbios name). Currently server names are resolved only via DNS
++(tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/
++
++#define DEFAULT_CIFS_CALLED_NAME "*SMBSERVER "
++
++#pragma pack() /* resume default structure packing */
++
+diff -urN linux-2.4.29.old/fs/cifs/smbdes.c linux-2.4.29/fs/cifs/smbdes.c
+--- linux-2.4.29.old/fs/cifs/smbdes.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/smbdes.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,408 @@
++/*
++ Unix SMB/Netbios implementation.
++ Version 1.9.
++
++ a partial implementation of DES designed for use in the
++ SMB authentication protocol
++
++ Copyright (C) Andrew Tridgell 1998
++ Modified by Steve French (sfrench@us.ibm.com) 2002,2004
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++*/
++
++/* NOTES:
++
++ This code makes no attempt to be fast! In fact, it is a very
++ slow implementation
++
++ This code is NOT a complete DES implementation. It implements only
++ the minimum necessary for SMB authentication, as used by all SMB
++ products (including every copy of Microsoft Windows95 ever sold)
++
++ In particular, it can only do a unchained forward DES pass. This
++ means it is not possible to use this code for encryption/decryption
++ of data, instead it is only useful as a "hash" algorithm.
++
++ There is no entry point into this code that allows normal DES operation.
++
++ I believe this means that this code does not come under ITAR
++ regulations but this is NOT a legal opinion. If you are concerned
++ about the applicability of ITAR regulations to this code then you
++ should confirm it for yourself (and maybe let me know if you come
++ up with a different answer to the one above)
++*/
++#include <linux/slab.h>
++#define uchar unsigned char
++
++static uchar perm1[56] = { 57, 49, 41, 33, 25, 17, 9,
++ 1, 58, 50, 42, 34, 26, 18,
++ 10, 2, 59, 51, 43, 35, 27,
++ 19, 11, 3, 60, 52, 44, 36,
++ 63, 55, 47, 39, 31, 23, 15,
++ 7, 62, 54, 46, 38, 30, 22,
++ 14, 6, 61, 53, 45, 37, 29,
++ 21, 13, 5, 28, 20, 12, 4
++};
++
++static uchar perm2[48] = { 14, 17, 11, 24, 1, 5,
++ 3, 28, 15, 6, 21, 10,
++ 23, 19, 12, 4, 26, 8,
++ 16, 7, 27, 20, 13, 2,
++ 41, 52, 31, 37, 47, 55,
++ 30, 40, 51, 45, 33, 48,
++ 44, 49, 39, 56, 34, 53,
++ 46, 42, 50, 36, 29, 32
++};
++
++static uchar perm3[64] = { 58, 50, 42, 34, 26, 18, 10, 2,
++ 60, 52, 44, 36, 28, 20, 12, 4,
++ 62, 54, 46, 38, 30, 22, 14, 6,
++ 64, 56, 48, 40, 32, 24, 16, 8,
++ 57, 49, 41, 33, 25, 17, 9, 1,
++ 59, 51, 43, 35, 27, 19, 11, 3,
++ 61, 53, 45, 37, 29, 21, 13, 5,
++ 63, 55, 47, 39, 31, 23, 15, 7
++};
++
++static uchar perm4[48] = { 32, 1, 2, 3, 4, 5,
++ 4, 5, 6, 7, 8, 9,
++ 8, 9, 10, 11, 12, 13,
++ 12, 13, 14, 15, 16, 17,
++ 16, 17, 18, 19, 20, 21,
++ 20, 21, 22, 23, 24, 25,
++ 24, 25, 26, 27, 28, 29,
++ 28, 29, 30, 31, 32, 1
++};
++
++static uchar perm5[32] = { 16, 7, 20, 21,
++ 29, 12, 28, 17,
++ 1, 15, 23, 26,
++ 5, 18, 31, 10,
++ 2, 8, 24, 14,
++ 32, 27, 3, 9,
++ 19, 13, 30, 6,
++ 22, 11, 4, 25
++};
++
++static uchar perm6[64] = { 40, 8, 48, 16, 56, 24, 64, 32,
++ 39, 7, 47, 15, 55, 23, 63, 31,
++ 38, 6, 46, 14, 54, 22, 62, 30,
++ 37, 5, 45, 13, 53, 21, 61, 29,
++ 36, 4, 44, 12, 52, 20, 60, 28,
++ 35, 3, 43, 11, 51, 19, 59, 27,
++ 34, 2, 42, 10, 50, 18, 58, 26,
++ 33, 1, 41, 9, 49, 17, 57, 25
++};
++
++static uchar sc[16] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
++
++static uchar sbox[8][4][16] = {
++ {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
++ {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
++ {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
++ {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
++
++ {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
++ {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
++ {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
++ {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
++
++ {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
++ {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
++ {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
++ {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
++
++ {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
++ {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
++ {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
++ {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
++
++ {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
++ {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
++ {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
++ {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
++
++ {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
++ {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
++ {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
++ {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
++
++ {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
++ {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
++ {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
++ {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
++
++ {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
++ {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
++ {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
++ {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}
++};
++
++static void
++permute(char *out, char *in, uchar * p, int n)
++{
++ int i;
++ for (i = 0; i < n; i++)
++ out[i] = in[p[i] - 1];
++}
++
++static void
++lshift(char *d, int count, int n)
++{
++ char out[64];
++ int i;
++ for (i = 0; i < n; i++)
++ out[i] = d[(i + count) % n];
++ for (i = 0; i < n; i++)
++ d[i] = out[i];
++}
++
++static void
++concat(char *out, char *in1, char *in2, int l1, int l2)
++{
++ while (l1--)
++ *out++ = *in1++;
++ while (l2--)
++ *out++ = *in2++;
++}
++
++static void
++xor(char *out, char *in1, char *in2, int n)
++{
++ int i;
++ for (i = 0; i < n; i++)
++ out[i] = in1[i] ^ in2[i];
++}
++
++static void
++dohash(char *out, char *in, char *key, int forw)
++{
++ int i, j, k;
++ char *pk1;
++ char c[28];
++ char d[28];
++ char *cd;
++ char ki[16][48];
++ char *pd1;
++ char l[32], r[32];
++ char *rl;
++
++ /* Have to reduce stack usage */
++ pk1 = kmalloc(56+56+64+64,GFP_KERNEL);
++ if(pk1 == NULL)
++ return;
++
++ cd = pk1 + 56;
++ pd1= cd + 56;
++ rl = pd1 + 64;
++
++ permute(pk1, key, perm1, 56);
++
++ for (i = 0; i < 28; i++)
++ c[i] = pk1[i];
++ for (i = 0; i < 28; i++)
++ d[i] = pk1[i + 28];
++
++ for (i = 0; i < 16; i++) {
++ lshift(c, sc[i], 28);
++ lshift(d, sc[i], 28);
++
++ concat(cd, c, d, 28, 28);
++ permute(ki[i], cd, perm2, 48);
++ }
++
++ permute(pd1, in, perm3, 64);
++
++ for (j = 0; j < 32; j++) {
++ l[j] = pd1[j];
++ r[j] = pd1[j + 32];
++ }
++
++ for (i = 0; i < 16; i++) {
++ char *er; /* er[48] */
++ char *erk; /* erk[48] */
++ char b[8][6];
++ char *cb; /* cb[32] */
++ char *pcb; /* pcb[32] */
++ char *r2; /* r2[32] */
++
++ er = kmalloc(48+48+32+32+32, GFP_KERNEL);
++ if(er == NULL) {
++ kfree(pk1);
++ return;
++ }
++ erk = er+48;
++ cb = erk+48;
++ pcb = cb+32;
++ r2 = pcb+32;
++
++ permute(er, r, perm4, 48);
++
++ xor(erk, er, ki[forw ? i : 15 - i], 48);
++
++ for (j = 0; j < 8; j++)
++ for (k = 0; k < 6; k++)
++ b[j][k] = erk[j * 6 + k];
++
++ for (j = 0; j < 8; j++) {
++ int m, n;
++ m = (b[j][0] << 1) | b[j][5];
++
++ n = (b[j][1] << 3) | (b[j][2] << 2) | (b[j][3] <<
++ 1) | b[j][4];
++
++ for (k = 0; k < 4; k++)
++ b[j][k] =
++ (sbox[j][m][n] & (1 << (3 - k))) ? 1 : 0;
++ }
++
++ for (j = 0; j < 8; j++)
++ for (k = 0; k < 4; k++)
++ cb[j * 4 + k] = b[j][k];
++ permute(pcb, cb, perm5, 32);
++
++ xor(r2, l, pcb, 32);
++
++ for (j = 0; j < 32; j++)
++ l[j] = r[j];
++
++ for (j = 0; j < 32; j++)
++ r[j] = r2[j];
++
++ kfree(er);
++ }
++
++ concat(rl, r, l, 32, 32);
++
++ permute(out, rl, perm6, 64);
++ kfree(pk1);
++}
++
++static void
++str_to_key(unsigned char *str, unsigned char *key)
++{
++ int i;
++
++ key[0] = str[0] >> 1;
++ key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2);
++ key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3);
++ key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4);
++ key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5);
++ key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6);
++ key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7);
++ key[7] = str[6] & 0x7F;
++ for (i = 0; i < 8; i++) {
++ key[i] = (key[i] << 1);
++ }
++}
++
++static void
++smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
++{
++ int i;
++ char *outb; /* outb[64] */
++ char *inb; /* inb[64] */
++ char *keyb; /* keyb[64] */
++ unsigned char key2[8];
++
++ outb = kmalloc(64 * 3,GFP_KERNEL);
++ if(outb == NULL)
++ return;
++
++ inb = outb + 64;
++ keyb = inb + 64;
++
++ str_to_key(key, key2);
++
++ for (i = 0; i < 64; i++) {
++ inb[i] = (in[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
++ keyb[i] = (key2[i / 8] & (1 << (7 - (i % 8)))) ? 1 : 0;
++ outb[i] = 0;
++ }
++
++ dohash(outb, inb, keyb, forw);
++
++ for (i = 0; i < 8; i++) {
++ out[i] = 0;
++ }
++
++ for (i = 0; i < 64; i++) {
++ if (outb[i])
++ out[i / 8] |= (1 << (7 - (i % 8)));
++ }
++ kfree(outb);
++}
++
++void
++E_P16(unsigned char *p14, unsigned char *p16)
++{
++ unsigned char sp8[8] =
++ { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 };
++ smbhash(p16, sp8, p14, 1);
++ smbhash(p16 + 8, sp8, p14 + 7, 1);
++}
++
++void
++E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
++{
++ smbhash(p24, c8, p21, 1);
++ smbhash(p24 + 8, c8, p21 + 7, 1);
++ smbhash(p24 + 16, c8, p21 + 14, 1);
++}
++
++void
++D_P16(unsigned char *p14, unsigned char *in, unsigned char *out)
++{
++ smbhash(out, in, p14, 0);
++ smbhash(out + 8, in + 8, p14 + 7, 0);
++}
++
++void
++E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out)
++{
++ smbhash(out, in, p14, 1);
++ smbhash(out + 8, in + 8, p14 + 7, 1);
++}
++
++void
++cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key)
++{
++ unsigned char buf[8];
++
++ smbhash(buf, in, key, 1);
++ smbhash(out, buf, key + 9, 1);
++}
++
++void
++cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key)
++{
++ unsigned char buf[8];
++ static unsigned char key2[8];
++
++ smbhash(buf, in, key, 1);
++ key2[0] = key[7];
++ smbhash(out, buf, key2, 1);
++}
++
++void
++cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
++{
++ static unsigned char key2[8];
++
++ smbhash(out, in, key, forw);
++ key2[0] = key[7];
++ smbhash(out + 8, in + 8, key2, forw);
++}
+diff -urN linux-2.4.29.old/fs/cifs/smbencrypt.c linux-2.4.29/fs/cifs/smbencrypt.c
+--- linux-2.4.29.old/fs/cifs/smbencrypt.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/smbencrypt.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,295 @@
++/*
++ Unix SMB/Netbios implementation.
++ Version 1.9.
++ SMB parameters and setup
++ Copyright (C) Andrew Tridgell 1992-2000
++ Copyright (C) Luke Kenneth Casson Leighton 1996-2000
++ Modified by Jeremy Allison 1995.
++ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
++ Modified by Steve French (sfrench@us.ibm.com) 2002-2003
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++*/
++
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/random.h>
++#include "cifs_unicode.h"
++#include "cifspdu.h"
++#include "md5.h"
++#include "cifs_debug.h"
++
++#ifndef FALSE
++#define FALSE 0
++#endif
++#ifndef TRUE
++#define TRUE 1
++#endif
++
++/* following came from the other byteorder.h to avoid include conflicts */
++#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
++#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
++#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val)))
++
++/*The following definitions come from lib/md4.c */
++
++void mdfour(unsigned char *out, unsigned char *in, int n);
++
++/*The following definitions come from libsmb/smbdes.c */
++
++void E_P16(unsigned char *p14, unsigned char *p16);
++void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
++void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out);
++void E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out);
++void cred_hash1(unsigned char *out, unsigned char *in, unsigned char *key);
++void cred_hash2(unsigned char *out, unsigned char *in, unsigned char *key);
++void cred_hash3(unsigned char *out, unsigned char *in, unsigned char *key,
++ int forw);
++
++/*The following definitions come from libsmb/smbencrypt.c */
++
++void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
++void E_md4hash(const unsigned char *passwd, unsigned char *p16);
++void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]);
++void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
++ unsigned char p24[24]);
++void NTLMSSPOWFencrypt(unsigned char passwd[8],
++ unsigned char *ntlmchalresp, unsigned char p24[24]);
++void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
++int decode_pw_buffer(char in_buffer[516], char *new_pwrd,
++ int new_pwrd_size, __u32 * new_pw_len);
++
++/*
++ This implements the X/Open SMB password encryption
++ It takes a password, a 8 byte "crypt key" and puts 24 bytes of
++ encrypted password into p24 */
++/* Note that password must be uppercased and null terminated */
++void
++SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
++{
++ unsigned char p14[15], p21[21];
++
++ memset(p21, '\0', 21);
++ memset(p14, '\0', 14);
++ strncpy((char *) p14, (char *) passwd, 14);
++
++/* strupper((char *)p14); *//* BB at least uppercase the easy range */
++ E_P16(p14, p21);
++
++ SMBOWFencrypt(p21, c8, p24);
++
++ memset(p14,0,15);
++ memset(p21,0,21);
++}
++
++/* Routines for Windows NT MD4 Hash functions. */
++static int
++_my_wcslen(__u16 * str)
++{
++ int len = 0;
++ while (*str++ != 0)
++ len++;
++ return len;
++}
++
++/*
++ * Convert a string into an NT UNICODE string.
++ * Note that regardless of processor type
++ * this must be in intel (little-endian)
++ * format.
++ */
++
++static int
++_my_mbstowcs(__u16 * dst, const unsigned char *src, int len)
++{ /* not a very good conversion routine - change/fix */
++ int i;
++ __u16 val;
++
++ for (i = 0; i < len; i++) {
++ val = *src;
++ SSVAL(dst, 0, val);
++ dst++;
++ src++;
++ if (val == 0)
++ break;
++ }
++ return i;
++}
++
++/*
++ * Creates the MD4 Hash of the users password in NT UNICODE.
++ */
++
++void
++E_md4hash(const unsigned char *passwd, unsigned char *p16)
++{
++ int len;
++ __u16 wpwd[129];
++
++ /* Password cannot be longer than 128 characters */
++ if(passwd) {
++ len = strlen((char *) passwd);
++ if (len > 128) {
++ len = 128;
++ }
++ /* Password must be converted to NT unicode */
++ _my_mbstowcs(wpwd, passwd, len);
++ } else
++ len = 0;
++
++ wpwd[len] = 0; /* Ensure string is null terminated */
++ /* Calculate length in bytes */
++ len = _my_wcslen(wpwd) * sizeof (__u16);
++
++ mdfour(p16, (unsigned char *) wpwd, len);
++ memset(wpwd,0,129 * 2);
++}
++
++/* Does both the NT and LM owfs of a user's password */
++void
++nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
++{
++ char passwd[514];
++
++ memset(passwd, '\0', 514);
++ if (strlen(pwd) < 513)
++ strcpy(passwd, pwd);
++ else
++ memcpy(passwd, pwd, 512);
++ /* Calculate the MD4 hash (NT compatible) of the password */
++ memset(nt_p16, '\0', 16);
++ E_md4hash(passwd, nt_p16);
++
++ /* Mangle the passwords into Lanman format */
++ passwd[14] = '\0';
++/* strupper(passwd); */
++
++ /* Calculate the SMB (lanman) hash functions of the password */
++
++ memset(p16, '\0', 16);
++ E_P16((unsigned char *) passwd, (unsigned char *) p16);
++
++ /* clear out local copy of user's password (just being paranoid). */
++ memset(passwd, '\0', sizeof (passwd));
++}
++
++/* Does the NTLMv2 owfs of a user's password */
++void
++ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
++ const char *domain_n, unsigned char kr_buf[16],
++ const struct nls_table *nls_codepage)
++{
++ wchar_t * user_u;
++ wchar_t * dom_u;
++ int user_l, domain_l;
++ struct HMACMD5Context ctx;
++
++ /* might as well do one alloc to hold both (user_u and dom_u) */
++ user_u = kmalloc(2048 * sizeof(wchar_t),GFP_KERNEL);
++ if(user_u == NULL)
++ return;
++ dom_u = user_u + 1024;
++
++ /* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
++ push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */
++
++ /* BB user and domain may need to be uppercased */
++ user_l = cifs_strtoUCS(user_u, user_n, 511, nls_codepage);
++ domain_l = cifs_strtoUCS(dom_u, domain_n, 511, nls_codepage);
++
++ user_l++; /* trailing null */
++ domain_l++;
++
++ hmac_md5_init_limK_to_64(owf, 16, &ctx);
++ hmac_md5_update((const unsigned char *) user_u, user_l * 2, &ctx);
++ hmac_md5_update((const unsigned char *) dom_u, domain_l * 2, &ctx);
++ hmac_md5_final(kr_buf, &ctx);
++
++ kfree(user_u);
++}
++
++/* Does the des encryption from the NT or LM MD4 hash. */
++void
++SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
++ unsigned char p24[24])
++{
++ unsigned char p21[21];
++
++ memset(p21, '\0', 21);
++
++ memcpy(p21, passwd, 16);
++ E_P24(p21, c8, p24);
++}
++
++/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
++void
++NTLMSSPOWFencrypt(unsigned char passwd[8],
++ unsigned char *ntlmchalresp, unsigned char p24[24])
++{
++ unsigned char p21[21];
++
++ memset(p21, '\0', 21);
++ memcpy(p21, passwd, 8);
++ memset(p21 + 8, 0xbd, 8);
++
++ E_P24(p21, ntlmchalresp, p24);
++}
++
++/* Does the NT MD4 hash then des encryption. */
++
++void
++SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
++{
++ unsigned char p21[21];
++
++ memset(p21, '\0', 21);
++
++ E_md4hash(passwd, p21);
++ SMBOWFencrypt(p21, c8, p24);
++}
++
++/* Does the md5 encryption from the NT hash for NTLMv2. */
++void
++SMBOWFencrypt_ntv2(const unsigned char kr[16],
++ const struct data_blob * srv_chal,
++ const struct data_blob * cli_chal, unsigned char resp_buf[16])
++{
++ struct HMACMD5Context ctx;
++
++ hmac_md5_init_limK_to_64(kr, 16, &ctx);
++ hmac_md5_update(srv_chal->data, srv_chal->length, &ctx);
++ hmac_md5_update(cli_chal->data, cli_chal->length, &ctx);
++ hmac_md5_final(resp_buf, &ctx);
++}
++
++void
++SMBsesskeygen_ntv2(const unsigned char kr[16],
++ const unsigned char *nt_resp, __u8 sess_key[16])
++{
++ struct HMACMD5Context ctx;
++
++ hmac_md5_init_limK_to_64(kr, 16, &ctx);
++ hmac_md5_update(nt_resp, 16, &ctx);
++ hmac_md5_final((unsigned char *) sess_key, &ctx);
++}
++
++void
++SMBsesskeygen_ntv1(const unsigned char kr[16],
++ const unsigned char *nt_resp, __u8 sess_key[16])
++{
++ mdfour((unsigned char *) sess_key, (unsigned char *) kr, 16);
++}
+diff -urN linux-2.4.29.old/fs/cifs/smberr.c linux-2.4.29/fs/cifs/smberr.c
+--- linux-2.4.29.old/fs/cifs/smberr.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/smberr.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,240 @@
++/*
++ Unix SMB/Netbios implementation.
++ Version 1.9.
++ Copyright (C) Andrew Tridgell 1998
++ Copyright (C) Steve French (sfrench@us.ibm.com) 2002
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++*/
++include "smberr.h"
++#define NO_SYSLOG
++/* error code stuff - put together by Merik Karman
++ merik@blackadder.dsh.oz.au */
++ typedef const struct {
++ char *name;
++ int code;
++ char *message;
++ int posix_code;
++} err_code_struct;
++
++/* Dos Error Messages */
++err_code_struct dos_msgs[] = {
++ {"ERRbadfunc", ERRbadfunc, "Invalid function.", -EINVAL},
++ {"ERRbadfile", ERRbadfile, "File not found.", -ENOENT},
++ {"ERRbadpath", ERRbadpath, "Directory invalid.", -ENOENT},
++ {"ERRnofids", ERRnofids, "No file descriptors available", -EMFILE},
++ {"ERRnoaccess", ERRnoaccess, "Access denied.", -EACCES},
++ {"ERRbadfid", ERRbadfid, "Invalid file handle.", -EBADF},
++ {"ERRbadmcb", 7, "Memory control blocks destroyed.", -EIO},
++ {"ERRnomem", ERRnomem,
++ "Insufficient server memory to perform the requested function.",
++ -ENOMEM},
++ {"ERRbadmem", ERRbadmem, "Invalid memory block address.", -EFAULT},
++ {"ERRbadenv", ERRbadenv, "Invalid environment.", -EFAULT},
++ {"ERRbadformat", 11, "Invalid format.", -EINVAL},
++ {"ERRbadaccess", ERRbadaccess, "Invalid open mode." - EACCES},
++ {"ERRbaddata", ERRbaddata, "Invalid data.", -EIO},
++ {"ERR", ERRres, "reserved.", -EIO},
++ {"ERRbaddrive", ERRbaddrive, "Invalid drive specified.", -ENXIO},
++ {"ERRremcd", ERRremcd,
++ "A Delete Directory request attempted to remove the server's current directory.",
++ -EIO},
++ {"ERRdiffdevice", ERRdiffdevice, "Not same device.", -EXDEV},
++ {"ERRnofiles", ERRnofiles, "A File Search command can find no more files matching the specified criteria.", -ENOENT}, /* Note: must map to zero manually in some places such as readdir */
++ {"ERRbadshare", ERRbadshare,
++ "The sharing mode specified for an Open conflicts with existing FIDs on the file.",
++ -EXTBSY},
++ {"ERRlock", ERRlock,
++ "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process.",
++ -EACCES},
++ {"ERRunsup", ERRunsup, "The operation is unsupported", -EINVAL},
++ {"ERRnosuchshare", ERRnosuchshare,
++ "You specified an invalid share name", -ENXIO},
++ {"ERRfilexists", ERRfilexists,
++ "The file named in a Create Directory, Make New File or Link request already exists.",
++ -EEXIST},
++ {"ERRinvalidname", ERRinvalidname, "Invalid name", -ENOENT},
++ {"ERRdiskfull", ERRdiskfull, "Disk full", -ENOSPC}
++
++ {"ERRmoredata", ERRmoredata,
++ "There is more data to be returned.",},
++ {"ERRinvgroup", 2455, "Invalid workgroup (try the -W option)"},
++ {NULL, -1, NULL, -EIO}
++};
++
++/* Server Error Messages */
++err_code_struct server_msgs[] = {
++ {"ERRerror", 1, "Non-specific error code."},
++ {"ERRbadpw", 2,
++ "Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
++ {"ERRbadtype", 3, "reserved."},
++ {"ERRaccess", 4,
++ "The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."},
++ {"ERRinvnid", 5,
++ "The tree ID (TID) specified in a command was invalid."},
++ {"ERRinvnetname", 6, "Invalid network name in tree connect."},
++ {"ERRinvdevice", 7,
++ "Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."},
++ {"ERRqfull", 49,
++ "Print queue full (files) -- returned by open print file."},
++ {"ERRqtoobig", 50, "Print queue full -- no space."},
++ {"ERRqeof", 51, "EOF on print queue dump."},
++ {"ERRinvpfid", 52, "Invalid print file FID."},
++ {"ERRsmbcmd", 64,
++ "The server did not recognize the command received."},
++ {"ERRsrverror", 65,
++ "The server encountered an internal error, e.g., system file unavailable."},
++ {"ERRfilespecs", 67,
++ "The file handle (FID) and pathname parameters contained an invalid combination of values."},
++ {"ERRreserved", 68, "reserved."},
++ {"ERRbadpermits", 69,
++ "The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."},
++ {"ERRreserved", 70, "reserved."},
++ {"ERRsetattrmode", 71,
++ "The attribute mode in the Set File Attribute request is invalid."},
++ {"ERRpaused", 81, "Server is paused."},
++ {"ERRmsgoff", 82, "Not receiving messages."},
++ {"ERRnoroom", 83, "No room to buffer message."},
++ {"ERRrmuns", 87, "Too many remote user names."},
++ {"ERRtimeout", 88, "Operation timed out."},
++ {"ERRnoresource", 89,
++ "No resources currently available for request."},
++ {"ERRtoomanyuids", 90, "Too many UIDs active on this session."},
++ {"ERRbaduid", 91,
++ "The UID is not known as a valid ID on this session."},
++ {"ERRusempx", 250, "Temp unable to support Raw, use MPX mode."},
++ {"ERRusestd", 251,
++ "Temp unable to support Raw, use standard read/write."},
++ {"ERRcontmpx", 252, "Continue in MPX mode."},
++ {"ERRreserved", 253, "reserved."},
++ {"ERRreserved", 254, "reserved."},
++ {"ERRnosupport", 0xFFFF, "Function not supported."},
++ {NULL, -1, NULL}
++};
++
++/* Hard Error Messages */
++err_code_struct hard_msgs[] = {
++ {"ERRnowrite", 19,
++ "Attempt to write on write-protected diskette."},
++ {"ERRbadunit", 20, "Unknown unit."},
++ {"ERRnotready", 21, "Drive not ready."},
++ {"ERRbadcmd", 22, "Unknown command."},
++ {"ERRdata", 23, "Data error (CRC)."},
++ {"ERRbadreq", 24, "Bad request structure length."},
++ {"ERRseek", 25, "Seek error."},
++ {"ERRbadmedia", 26, "Unknown media type."},
++ {"ERRbadsector", 27, "Sector not found."},
++ {"ERRnopaper", 28, "Printer out of paper."},
++ {"ERRwrite", 29, "Write fault."},
++ {"ERRread", 30, "Read fault."},
++ {"ERRgeneral", 31, "General failure."},
++ {"ERRbadshare", 32, "An open conflicts with an existing open."},
++ {"ERRlock", 33,
++ "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."},
++ {"ERRwrongdisk", 34, "The wrong disk was found in a drive."},
++ {"ERRFCBUnavail", 35, "No FCBs are available to process request."},
++ {"ERRsharebufexc", 36, "A sharing buffer has been exceeded."},
++ {NULL, -1, NULL}
++};
++
++
++const struct {
++ int code;
++ char *class;
++ err_code_struct *err_msgs;
++} err_classes[] = {
++ {
++ 0, "SUCCESS", NULL}, {
++ 0x01, "ERRDOS", dos_msgs}, {
++ 0x02, "ERRSRV", server_msgs}, {
++ 0x03, "ERRHRD", hard_msgs}, {
++ 0x04, "ERRXOS", NULL}, {
++ 0xE1, "ERRRMX1", NULL}, {
++ 0xE2, "ERRRMX2", NULL}, {
++ 0xE3, "ERRRMX3", NULL}, {
++ 0xFF, "ERRCMD", NULL}, {
++-1, NULL, NULL}};
++
++
++/****************************************************************************
++return a SMB error string from a SMB buffer
++****************************************************************************/
++char *smb_dos_errstr(char *inbuf)
++{
++ static pstring ret;
++ int class = CVAL(inbuf, smb_rcls);
++ int num = SVAL(inbuf, smb_err);
++ int i, j;
++
++ for (i = 0; err_classes[i].class; i++)
++ if (err_classes[i].code == class) {
++ if (err_classes[i].err_msgs) {
++ err_code_struct *err =
++ err_classes[i].err_msgs;
++ for (j = 0; err[j].name; j++)
++ if (num == err[j].code) {
++ if (DEBUGLEVEL > 0)
++ slprintf(ret,
++ sizeof
++ (ret) - 1,
++ "%s - %s (%s)",
++ err_classes
++ [i].class,
++ err[j].
++ name,
++ err[j].
++ message);
++ else
++ slprintf(ret,
++ sizeof
++ (ret) - 1,
++ "%s - %s",
++ err_classes
++ [i].class,
++ err[j].
++ name);
++ return ret;
++ }
++ }
++
++ slprintf(ret, sizeof(ret) - 1, "%s - %d",
++ err_classes[i].class, num);
++ return ret;
++ }
++
++ slprintf(ret, sizeof(ret) - 1, "Error: Unknown error (%d,%d)",
++ class, num);
++ return (ret);
++}
++
++
++/*****************************************************************************
++ returns an WERROR error message.
++ *****************************************************************************/
++char *werror_str(WERROR status)
++{
++ static fstring msg;
++ slprintf(msg, sizeof(msg), "WIN32 code 0x%08x", W_ERROR_V(status));
++ return msg;
++}
++
++
++/*****************************************************************************
++map a unix errno to a win32 error
++ *****************************************************************************/
++WERROR map_werror_from_unix(int error)
++{
++ NTSTATUS status = map_nt_error_from_unix(error);
++ return ntstatus_to_werror(status);
++}
+diff -urN linux-2.4.29.old/fs/cifs/smberr.h linux-2.4.29/fs/cifs/smberr.h
+--- linux-2.4.29.old/fs/cifs/smberr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/smberr.h 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,113 @@
++/*
++ * fs/cifs/smberr.h
++ *
++ * Copyright (c) International Business Machines Corp., 2002
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * See Error Codes section of the SNIA CIFS Specification
++ * for more information
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#define SUCCESS 0 /* The request was successful. */
++#define ERRDOS 0x01 /* Error is from the core DOS operating system set */
++#define ERRSRV 0x02 /* Error is generated by the file server daemon */
++#define ERRHRD 0x03 /* Error is a hardware error. */
++#define ERRCMD 0xFF /* Command was not in the "SMB" format. */
++
++/* The following error codes may be generated with the SUCCESS error class.*/
++
++#define SUCCESS 0 /* The request was successful. */
++
++/* The following error codes may be generated with the ERRDOS error class.*/
++
++#define ERRbadfunc 1 /* Invalid function. The server did not recognize or could not perform a system call generated by the server, e.g., set the DIRECTORY attribute on a data file, invalid seek mode. */
++#define ERRbadfile 2 /*File not found. The last component of a file's pathname could not be found. */
++#define ERRbadpath 3 /* Directory invalid. A directory component in a pathname could not be found. */
++#define ERRnofids 4 /* Too many open files. The server has no file handles available. */
++#define ERRnoaccess 5 /* Access denied, the client's context does not permit the requested function. This includes the following conditions: invalid rename command, write to Fid open for read only, read on Fid open for write only, attempt to delete a non-empty directory */
++#define ERRbadfid 6 /* Invalid file handle. The file handle specified was not recognized by the server. */
++#define ERRbadmcb 7 /* Memory control blocks destroyed. */
++#define ERRnomem 8 /* Insufficient server memory to perform the requested function. */
++#define ERRbadmem 9 /* Invalid memory block address. */
++#define ERRbadenv 10 /* Invalid environment. */
++#define ERRbadformat 11 /* Invalid format. */
++#define ERRbadaccess 12 /* Invalid open mode. */
++#define ERRbaddata 13 /* Invalid data (generated only by IOCTL calls within the server). */
++#define ERRbaddrive 15 /* Invalid drive specified. */
++#define ERRremcd 16 /* A Delete Directory request attempted to remove the server's current directory. */
++#define ERRdiffdevice 17 /* Not same device (e.g., a cross volume rename was attempted */
++#define ERRnofiles 18 /* A File Search command can find no more files matching the specified criteria. */
++#define ERRgeneral 31
++#define ERRbadshare 32 /* The sharing mode specified for an Open conflicts with existing FIDs on the file. */
++#define ERRlock 33 /* A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process. */
++#define ERRunsup 50
++#define ERRnosuchshare 67
++#define ERRfilexists 80 /* The file named in the request already exists. */
++#define ERRinvparm 87
++#define ERRdiskfull 112
++#define ERRinvname 123
++#define ERRdirnotempty 145
++#define ERRnotlocked 158
++#define ERRalreadyexists 183
++#define ERRbadpipe 230
++#define ERRpipebusy 231
++#define ERRpipeclosing 232
++#define ERRnotconnected 233
++#define ERRmoredata 234
++#define ErrQuota 0x200 /* The operation would cause a quota limit to be exceeded. */
++#define ErrNotALink 0x201 /* A link operation was performed on a pathname that
++ was not a link. */
++
++/* Following error codes may be generated with the ERRSRV error
++class.*/
++
++#define ERRerror 1 /* Non-specific error code. It is returned under the following conditions: resource other than disk space exhausted (e.g. TIDs), first SMB command was not negotiate, multiple negotiates attempted, and internal server error. */
++#define ERRbadpw 2 /* Bad password - name/password pair in a TreeConnect or Session Setup are invalid. */
++#define ERRbadtype 3 /* used for indicating DFS referral needed */
++#define ERRaccess 4 /* The client does not have the necessary access rights within the specified context for requested function. */
++#define ERRinvtid 5 /* The Tid specified in a command was invalid. */
++#define ERRinvnetname 6 /* Invalid network name in tree connect. */
++#define ERRinvdevice 7 /* Invalid device - printer request made to non-printer connection or non-printer request made to printer connection. */
++#define ERRqfull 49 /* Print queue full (files) -- returned by open print file. */
++#define ERRqtoobig 50 /* Print queue full -- no space. */
++#define ERRqeof 51 /* EOF on print queue dump */
++#define ERRinvpfid 52 /* Invalid print file FID. */
++#define ERRsmbcmd 64 /* The server did not recognize the command received. */
++#define ERRsrverror 65 /* The server encountered an internal error, e.g., system file unavailable. */
++#define ERRbadBID 66 /* (obsolete) */
++#define ERRfilespecs 67 /* The Fid and pathname parameters contained an invalid combination of values. */
++#define ERRbadLink 68 /* (obsolete) */
++#define ERRbadpermits 69 /* The access permissions specified for a file or directory are not a valid combination. */
++#define ERRbadPID 70
++#define ERRsetattrmode 71 /* attribute (mode) is invalid */
++#define ERRpaused 81 /* Server is paused */
++#define ERRmsgoff 82 /* reserved - messaging off */
++#define ERRnoroom 83 /* reserved - no room for message */
++#define ERRrmuns 87 /* reserved - too many remote names */
++#define ERRtimeout 88 /* operation timed out */
++#define ERRnoresource 89 /* No resources available for request */
++#define ERRtoomanyuids 90 /* Too many UIDs active on this session */
++#define ERRbaduid 91 /* The UID is not known as a valid user */
++#define ERRusempx 250 /* temporarily unable to use raw */
++#define ERRusestd 251 /* temporarily unable to use either raw or mpx */
++#define ERR_NOTIFY_ENUM_DIR 1024
++#define ERRaccountexpired 2239
++#define ERRbadclient 2240
++#define ERRbadLogonTime 2241
++#define ERRpasswordExpired 2242
++#define ERRnetlogonNotStarted 2455
++#define ERRnosupport 0xFFFF
+diff -urN linux-2.4.29.old/fs/cifs/TODO linux-2.4.29/fs/cifs/TODO
+--- linux-2.4.29.old/fs/cifs/TODO 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/TODO 2004-07-14 00:25:04.000000000 +0200
+@@ -0,0 +1,106 @@
++version 1.16 May 27, 2004
++
++A Partial List of Missing Features
++==================================
++
++Contributions are welcome. There are plenty of opportunities
++for visible, important contributions to this module. Here
++is a partial list of the known problems and missing features:
++
++a) Support for SecurityDescriptors for chmod/chgrp/chown so
++these can be supported for Windows servers
++
++b) Better pam/winbind integration
++
++c) multi-user mounts - multiplexed sessionsetups over single vc
++(ie tcp session) - prettying up needed
++
++d) Kerberos/SPNEGO session setup support - (started)
++
++e) NTLMv2 authentication (mostly implemented)
++
++f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup
++used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM
++and raw NTLMSSP already. This is important when enabling
++extended security and mounting to Windows 2003 Servers
++
++f) Directory entry caching relies on a 1 second timer, rather than
++using FindNotify or equivalent. - (started)
++
++g) A few byte range testcases fail due to POSIX vs. Windows/CIFS
++style byte range lock differences
++
++h) quota support
++
++i) support for the Linux 2.5 kernel new feature get_xattr and set_xattr
++which will allow us to expose dos attributes as well as real
++ACLs. This support has been started in the current code, but is
++ifdeffed out.
++
++k) finish writepages support (multi-page write behind for improved
++performance) and syncpage
++
++l) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
++extra copy in/out of the socket buffers in some cases.
++
++m) finish support for IPv6. This is mostly complete but
++needs a simple inet_pton like function to convert ipv6
++addresses in string representation.
++
++o) Better optimize open (and pathbased setfilesize) to reduce the
++oplock breaks coming from windows srv. Piggyback identical file
++opens on top of each other by incrementing reference count rather
++than resending (helps reduce server resource utilization and avoid
++spurious oplock breaks).
++
++p) Improve performance of readpages by sending more than one read
++at a time when 8 pages or more are requested. Evaluate whether
++reads larger than 16K would be helpful.
++
++q) For support of Windows9x/98 we need to retry failed mounts
++to *SMBSERVER (default server name) with the uppercase hostname
++in the RFC1001 session_init request.
++
++r) Add Extended Attributed support (for storing UID/GID info
++to Windows servers)
++
++s) Finish fcntl D_NOTIFY support so kde and gnome file list windows
++will autorefresh
++
++t) Add GUI tool to configure /proc/fs/cifs settings and for display of
++the CIFS statistics
++
++KNOWN BUGS (updated May 27, 2004)
++====================================
++1) existing symbolic links (Windows reparse points) are recognized but
++can not be created remotely. They are implemented for Samba and those that
++support the CIFS Unix extensions but Samba has a bug currently handling
++symlink text beginning with slash
++2) follow_link and readdir code does not follow dfs junctions
++but recognizes them
++3) create of new files to FAT partitions on Windows servers can
++succeed but still return access denied (appears to be Windows
++server not cifs client problem) and has not been reproduced recently.
++NTFS partitions do not have this problem.
++4) debug connectathon lock test case 10 which fails against
++Samba (may be unmappable due to POSIX to Windows lock model
++differences but worth investigating). Also debug Samba to
++see why lock test case 7 takes longer to complete to Samba
++than to Windows.
++
++Misc testing to do
++==================
++1) check out max path names and max path name components against various server
++types. Try nested symlinks. Return max path name in stat -f information
++
++2) Modify file portion of ltp so it can run against a mounted network
++share and run it against cifs vfs.
++
++3) Additional performance testing and optimization using iozone and similar -
++there are some easy changes that can be done to parallelize sequential writes,
++and when signing is disabled to request larger read sizes (larger than
++negotiated size) and send larger write sizes to modern servers.
++
++4) More exhaustively test the recently added NT4 support against various
++NT4 service pack levels.
++
+diff -urN linux-2.4.29.old/fs/cifs/transport.c linux-2.4.29/fs/cifs/transport.c
+--- linux-2.4.29.old/fs/cifs/transport.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/fs/cifs/transport.c 2004-07-14 00:25:05.000000000 +0200
+@@ -0,0 +1,434 @@
++/*
++ * fs/cifs/transport.c
++ *
++ * Copyright (C) International Business Machines Corp., 2002,2004
++ * Author(s): Steve French (sfrench@us.ibm.com)
++ *
++ * This library is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License as published
++ * by the Free Software Foundation; either version 2.1 of the License, or
++ * (at your option) any later version.
++ *
++ * This library 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 Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/fs.h>
++#include <linux/list.h>
++#include <linux/wait.h>
++#include <linux/net.h>
++#include <linux/version.h>
++#include <asm/uaccess.h>
++#include <asm/processor.h>
++#include "cifspdu.h"
++#include "cifsglob.h"
++#include "cifsproto.h"
++#include "cifs_debug.h"
++
++extern kmem_cache_t *cifs_mid_cachep;
++extern kmem_cache_t *cifs_oplock_cachep;
++
++struct mid_q_entry *
++AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
++{
++ struct mid_q_entry *temp;
++
++ if (ses == NULL) {
++ cERROR(1, ("Null session passed in to AllocMidQEntry "));
++ return NULL;
++ }
++ if (ses->server == NULL) {
++ cERROR(1, ("Null TCP session in AllocMidQEntry"));
++ return NULL;
++ }
++
++ temp = (struct mid_q_entry *) kmem_cache_alloc(cifs_mid_cachep,
++ SLAB_KERNEL);
++ if (temp == NULL)
++ return temp;
++ else {
++ memset(temp, 0, sizeof (struct mid_q_entry));
++ temp->mid = smb_buffer->Mid; /* always LE */
++ temp->pid = current->pid;
++ temp->command = smb_buffer->Command;
++ cFYI(1, ("For smb_command %d", temp->command));
++ do_gettimeofday(&temp->when_sent);
++ temp->ses = ses;
++ temp->tsk = current;
++ }
++
++ spin_lock(&GlobalMid_Lock);
++ list_add_tail(&temp->qhead, &ses->server->pending_mid_q);
++ atomic_inc(&midCount);
++ temp->midState = MID_REQUEST_ALLOCATED;
++ spin_unlock(&GlobalMid_Lock);
++ return temp;
++}
++
++void
++DeleteMidQEntry(struct mid_q_entry *midEntry)
++{
++ spin_lock(&GlobalMid_Lock);
++ midEntry->midState = MID_FREE;
++ list_del(&midEntry->qhead);
++ atomic_dec(&midCount);
++ spin_unlock(&GlobalMid_Lock);
++ cifs_buf_release(midEntry->resp_buf);
++ kmem_cache_free(cifs_mid_cachep, midEntry);
++}
++
++struct oplock_q_entry *
++AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
++{
++ struct oplock_q_entry *temp;
++ if ((pinode== NULL) || (tcon == NULL)) {
++ cERROR(1, ("Null parms passed to AllocOplockQEntry"));
++ return NULL;
++ }
++ temp = (struct oplock_q_entry *) kmem_cache_alloc(cifs_oplock_cachep,
++ SLAB_KERNEL);
++ if (temp == NULL)
++ return temp;
++ else {
++ temp->pinode = pinode;
++ temp->tcon = tcon;
++ temp->netfid = fid;
++ spin_lock(&GlobalMid_Lock);
++ list_add_tail(&temp->qhead, &GlobalOplock_Q);
++ spin_unlock(&GlobalMid_Lock);
++ }
++ return temp;
++
++}
++
++void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
++{
++ spin_lock(&GlobalMid_Lock);
++ /* should we check if list empty first? */
++ list_del(&oplockEntry->qhead);
++ spin_unlock(&GlobalMid_Lock);
++ kmem_cache_free(cifs_oplock_cachep, oplockEntry);
++}
++
++int
++smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
++ unsigned int smb_buf_length, struct sockaddr *sin)
++{
++ int rc = 0;
++ int i = 0;
++ struct msghdr smb_msg;
++ struct iovec iov;
++ mm_segment_t temp_fs;
++
++ if(ssocket == NULL)
++ return -ENOTSOCK; /* BB eventually add reconnect code here */
++ iov.iov_base = smb_buffer;
++ iov.iov_len = smb_buf_length + 4;
++
++ smb_msg.msg_name = sin;
++ smb_msg.msg_namelen = sizeof (struct sockaddr);
++ smb_msg.msg_iov = &iov;
++ smb_msg.msg_iovlen = 1;
++ smb_msg.msg_control = NULL;
++ smb_msg.msg_controllen = 0;
++ smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
++
++ /* smb header is converted in header_assemble. bcc and rest of SMB word
++ area, and byte area if necessary, is converted to littleendian in
++ cifssmb.c and RFC1001 len is converted to bigendian in smb_send
++ Flags2 is converted in SendReceive */
++
++ smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
++ cFYI(1, ("Sending smb of length %d ", smb_buf_length));
++ dump_smb(smb_buffer, smb_buf_length + 4);
++
++ temp_fs = get_fs(); /* we must turn off socket api parm checking */
++ set_fs(get_ds());
++ while(iov.iov_len > 0) {
++ rc = sock_sendmsg(ssocket, &smb_msg, smb_buf_length + 4);
++ if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
++ i++;
++ if(i > 60) {
++ cERROR(1,
++ ("sends on sock %p stuck for 30 seconds",
++ ssocket));
++ rc = -EAGAIN;
++ break;
++ }
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(HZ/2);
++ continue;
++ }
++ if (rc < 0)
++ break;
++ iov.iov_base += rc;
++ iov.iov_len -= rc;
++ }
++ set_fs(temp_fs);
++
++ if (rc < 0) {
++ cERROR(1,("Error %d sending data on socket to server.", rc));
++ } else {
++ rc = 0;
++ }
++
++ return rc;
++}
++
++int
++SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
++ struct smb_hdr *in_buf, struct smb_hdr *out_buf,
++ int *pbytes_returned, const int long_op)
++{
++ int rc = 0;
++ unsigned int receive_len;
++ long timeout;
++ struct mid_q_entry *midQ;
++
++ if (ses == NULL) {
++ cERROR(1,("Null smb session"));
++ return -EIO;
++ }
++ if(ses->server == NULL) {
++ cERROR(1,("Null tcp session"));
++ return -EIO;
++ }
++
++ /* Ensure that we do not send more than 50 overlapping requests
++ to the same server. We may make this configurable later or
++ use ses->maxReq */
++ if(long_op == -1) {
++ /* oplock breaks must not be held up */
++ atomic_inc(&ses->server->inFlight);
++ } else {
++ spin_lock(&GlobalMid_Lock);
++ while(1) {
++ if(atomic_read(&ses->server->inFlight) >= CIFS_MAX_REQ){
++ spin_unlock(&GlobalMid_Lock);
++ wait_event(ses->server->request_q,
++ atomic_read(&ses->server->inFlight)
++ < CIFS_MAX_REQ);
++ spin_lock(&GlobalMid_Lock);
++ } else {
++ if(ses->server->tcpStatus == CifsExiting) {
++ spin_unlock(&GlobalMid_Lock);
++ return -ENOENT;
++ }
++
++ /* can not count locking commands against total since
++ they are allowed to block on server */
++
++ if(long_op < 3) {
++ /* update # of requests on the wire to server */
++ atomic_inc(&ses->server->inFlight);
++ }
++ spin_unlock(&GlobalMid_Lock);
++ break;
++ }
++ }
++ }
++ /* make sure that we sign in the same order that we send on this socket
++ and avoid races inside tcp sendmsg code that could cause corruption
++ of smb data */
++
++ down(&ses->server->tcpSem);
++
++ if (ses->server->tcpStatus == CifsExiting) {
++ rc = -ENOENT;
++ goto out_unlock;
++ } else if (ses->server->tcpStatus == CifsNeedReconnect) {
++ cFYI(1,("tcp session dead - return to caller to retry"));
++ rc = -EAGAIN;
++ goto out_unlock;
++ } else if (ses->status != CifsGood) {
++ /* check if SMB session is bad because we are setting it up */
++ if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
++ (in_buf->Command != SMB_COM_NEGOTIATE)) {
++ rc = -EAGAIN;
++ goto out_unlock;
++ } /* else ok - we are setting up session */
++ }
++ midQ = AllocMidQEntry(in_buf, ses);
++ if (midQ == NULL) {
++ up(&ses->server->tcpSem);
++ /* If not lock req, update # of requests on wire to server */
++ if(long_op < 3) {
++ atomic_dec(&ses->server->inFlight);
++ wake_up(&ses->server->request_q);
++ }
++ return -ENOMEM;
++ }
++
++ if (in_buf->smb_buf_length > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE - 4) {
++ up(&ses->server->tcpSem);
++ cERROR(1,
++ ("Illegal length, greater than maximum frame, %d ",
++ in_buf->smb_buf_length));
++ DeleteMidQEntry(midQ);
++ /* If not lock req, update # of requests on wire to server */
++ if(long_op < 3) {
++ atomic_dec(&ses->server->inFlight);
++ wake_up(&ses->server->request_q);
++ }
++ return -EIO;
++ }
++
++ if (in_buf->smb_buf_length > 12)
++ in_buf->Flags2 = cpu_to_le16(in_buf->Flags2);
++
++ rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number);
++
++ midQ->midState = MID_REQUEST_SUBMITTED;
++ rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
++ (struct sockaddr *) &(ses->server->addr.sockAddr));
++ if(rc < 0) {
++ DeleteMidQEntry(midQ);
++ up(&ses->server->tcpSem);
++ /* If not lock req, update # of requests on wire to server */
++ if(long_op < 3) {
++ atomic_dec(&ses->server->inFlight);
++ wake_up(&ses->server->request_q);
++ }
++ return rc;
++ } else
++ up(&ses->server->tcpSem);
++ if (long_op == -1)
++ goto cifs_no_response_exit;
++ else if (long_op == 2) /* writes past end of file can take looooong time */
++ timeout = 300 * HZ;
++ else if (long_op == 1)
++ timeout = 45 * HZ; /* should be greater than
++ servers oplock break timeout (about 43 seconds) */
++ else if (long_op > 2) {
++ timeout = MAX_SCHEDULE_TIMEOUT;
++ } else
++ timeout = 15 * HZ;
++ /* wait for 15 seconds or until woken up due to response arriving or
++ due to last connection to this server being unmounted */
++ if (signal_pending(current)) {
++ /* if signal pending do not hold up user for full smb timeout
++ but we still give response a change to complete */
++ if(midQ->midState & MID_REQUEST_SUBMITTED) {
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ timeout = sleep_on_timeout(&ses->server->response_q,2 * HZ);
++ }
++ } else { /* using normal timeout */
++ /* timeout = wait_event_interruptible_timeout(ses->server->response_q,
++ (midQ->midState & MID_RESPONSE_RECEIVED) ||
++ ((ses->server->tcpStatus != CifsGood) &&
++ (ses->server->tcpStatus != CifsNew)),
++ timeout); */
++ /* Can not allow user interrupts- wreaks havoc with performance */
++ if(midQ->midState & MID_REQUEST_SUBMITTED) {
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ timeout = sleep_on_timeout(&ses->server->response_q,timeout);
++ }
++ }
++
++ spin_lock(&GlobalMid_Lock);
++ if (midQ->resp_buf) {
++ spin_unlock(&GlobalMid_Lock);
++ receive_len = be32_to_cpu(midQ->resp_buf->smb_buf_length);
++ } else {
++ cERROR(1,("No response buffer"));
++ if(midQ->midState == MID_REQUEST_SUBMITTED) {
++ if(ses->server->tcpStatus == CifsExiting)
++ rc = -EHOSTDOWN;
++ else {
++ ses->server->tcpStatus = CifsNeedReconnect;
++ midQ->midState = MID_RETRY_NEEDED;
++ }
++ }
++
++ if (rc != -EHOSTDOWN) {
++ if(midQ->midState == MID_RETRY_NEEDED) {
++ rc = -EAGAIN;
++ cFYI(1,("marking request for retry"));
++ } else {
++ rc = -EIO;
++ }
++ }
++ spin_unlock(&GlobalMid_Lock);
++ DeleteMidQEntry(midQ);
++ /* If not lock req, update # of requests on wire to server */
++ if(long_op < 3) {
++ atomic_dec(&ses->server->inFlight);
++ wake_up(&ses->server->request_q);
++ }
++ return rc;
++ }
++
++ if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) {
++ cERROR(1,
++ ("Frame too large received. Length: %d Xid: %d",
++ receive_len, xid));
++ rc = -EIO;
++ } else { /* rcvd frame is ok */
++
++ if (midQ->resp_buf && out_buf
++ && (midQ->midState == MID_RESPONSE_RECEIVED)) {
++ memcpy(out_buf, midQ->resp_buf,
++ receive_len +
++ 4 /* include 4 byte RFC1001 header */ );
++
++ dump_smb(out_buf, 92);
++ /* convert the length into a more usable form */
++ out_buf->smb_buf_length =
++ be32_to_cpu(out_buf->smb_buf_length);
++ if((out_buf->smb_buf_length > 24) &&
++ (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) {
++ rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */
++ if(rc)
++ cFYI(1,("Unexpected signature received from server"));
++ }
++
++ if (out_buf->smb_buf_length > 12)
++ out_buf->Flags2 = le16_to_cpu(out_buf->Flags2);
++ if (out_buf->smb_buf_length > 28)
++ out_buf->Pid = le16_to_cpu(out_buf->Pid);
++ if (out_buf->smb_buf_length > 28)
++ out_buf->PidHigh =
++ le16_to_cpu(out_buf->PidHigh);
++
++ *pbytes_returned = out_buf->smb_buf_length;
++
++ /* BB special case reconnect tid and reconnect uid here? */
++ rc = map_smb_to_linux_error(out_buf);
++
++ /* convert ByteCount if necessary */
++ if (receive_len >=
++ sizeof (struct smb_hdr) -
++ 4 /* do not count RFC1001 header */ +
++ (2 * out_buf->WordCount) + 2 /* bcc */ )
++ BCC(out_buf) = le16_to_cpu(BCC(out_buf));
++ } else {
++ rc = -EIO;
++ cFYI(1,("Bad MID state? "));
++ }
++ }
++cifs_no_response_exit:
++ DeleteMidQEntry(midQ);
++
++ if(long_op < 3) {
++ atomic_dec(&ses->server->inFlight);
++ wake_up(&ses->server->request_q);
++ }
++
++ return rc;
++
++out_unlock:
++ up(&ses->server->tcpSem);
++ /* If not lock req, update # of requests on wire to server */
++ if(long_op < 3) {
++ atomic_dec(&ses->server->inFlight);
++ wake_up(&ses->server->request_q);
++ }
++
++ return rc;
++}
+diff -urN linux-2.4.29.old/fs/Config.in linux-2.4.29/fs/Config.in
+--- linux-2.4.29.old/fs/Config.in 2005-03-21 19:30:22.000000000 +0100
++++ linux-2.4.29/fs/Config.in 2005-03-21 19:36:51.000000000 +0100
+@@ -146,6 +146,10 @@
+ define_bool CONFIG_LOCKD_V4 y
+ fi
+
++ dep_tristate 'CIFS support (advanced network filesystem for Samba, Window and other CIFS compliant servers)' CONFIG_CIFS $CONFIG_INET
++ dep_mbool ' CIFS statistics' CONFIG_CIFS_STATS $CONFIG_CIFS
++ dep_mbool ' CIFS POSIX Protocol Extensions' CONFIG_CIFS_POSIX $CONFIG_CIFS
++
+ dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET
+ if [ "$CONFIG_SMB_FS" != "n" ]; then
+ bool ' Use a default NLS' CONFIG_SMB_NLS_DEFAULT
+diff -urN linux-2.4.29.old/fs/Makefile linux-2.4.29/fs/Makefile
+--- linux-2.4.29.old/fs/Makefile 2005-03-21 19:30:22.000000000 +0100
++++ linux-2.4.29/fs/Makefile 2005-03-21 19:36:51.000000000 +0100
+@@ -37,6 +37,7 @@
+ subdir-$(CONFIG_VFAT_FS) += vfat
+ subdir-$(CONFIG_BFS_FS) += bfs
+ subdir-$(CONFIG_ISO9660_FS) += isofs
++subdir-$(CONFIG_CIFS) += cifs
+ subdir-$(CONFIG_DEVFS_FS) += devfs
+ subdir-$(CONFIG_HFSPLUS_FS) += hfsplus # Before hfs to find wrapped HFS+
+ subdir-$(CONFIG_HFS_FS) += hfs
+diff -urN linux-2.4.29.old/fs/nls/Config.in linux-2.4.29/fs/nls/Config.in
+--- linux-2.4.29.old/fs/nls/Config.in 2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.29/fs/nls/Config.in 2005-03-21 19:36:51.000000000 +0100
+@@ -11,6 +11,7 @@
+
+ # msdos and Joliet want NLS
+ if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \
++ -o "$CONFIG_CIFS" != "n" \
+ -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \
+ -o "$CONFIG_SMB_NLS" = "y" -o "$CONFIG_JFS_FS" != "n" \
+ -o "$CONFIG_BEFS_FS" != "n" -o "$CONFIG_HFSPLUS_FS" != "n" ]; then
diff --git a/target/linux/generic-2.4/patches/108-optional_aout_support.patch b/target/linux/generic-2.4/patches/108-optional_aout_support.patch
new file mode 100644
index 0000000..56dc199
--- /dev/null
+++ b/target/linux/generic-2.4/patches/108-optional_aout_support.patch
@@ -0,0 +1,688 @@
+diff -urPX nopatch linux-2.4.26/Documentation/Configure.help linux/Documentation/Configure.help
+--- linux-2.4.26/Documentation/Configure.help Sat Apr 17 02:10:25 2004
++++ linux/Documentation/Configure.help Sat Apr 17 02:13:54 2004
+@@ -4622,6 +4622,12 @@
+ will be called binfmt_elf.o. Saying M or N here is dangerous because
+ some crucial programs on your system might be in ELF format.
+
++ELF binaries with a.out format interpreters or a.out libraries
++CONFIG_BINFMT_ELF_AOUT
++ The kernel may support ELF executables which use an a.out format
++ interpreter (dynamic linker) and/or a.out shared libraries, in
++ addition to the usual ELF-ELF setups. You shouldn't need this.
++
+ Kernel support for a.out binaries
+ CONFIG_BINFMT_AOUT
+ A.out (Assembler.OUTput) is a set of formats for libraries and
+@@ -4635,13 +4641,11 @@
+ warrant removing support. However its removal is a good idea if you
+ wish to ensure that absolutely none of your programs will use this
+ older executable format. If you don't know what to answer at this
+- point then answer Y. If someone told you "You need a kernel with
++ point then answer N. If someone told you "You need a kernel with
+ QMAGIC support" then you'll have to say Y here. You may answer M to
+ compile a.out support as a module and later load the module when you
+ want to use a program or library in a.out format. The module will be
+- called binfmt_aout.o. Saying M or N here is dangerous though,
+- because some crucial programs on your system might still be in A.OUT
+- format.
++ called binfmt_aout.o.
+
+ OSF/1 v4 readv/writev compatibility
+ CONFIG_OSF4_COMPAT
+diff -urPX nopatch linux-2.4.26/arch/alpha/config.in linux/arch/alpha/config.in
+--- linux-2.4.26/arch/alpha/config.in Fri Feb 20 10:07:20 2004
++++ linux/arch/alpha/config.in Sat Apr 17 02:13:54 2004
+@@ -315,6 +315,9 @@
+ fi
+
+ bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+ tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
+ source drivers/parport/Config.in
+diff -urPX nopatch linux-2.4.26/arch/alpha/defconfig linux/arch/alpha/defconfig
+--- linux-2.4.26/arch/alpha/defconfig Fri Feb 20 10:07:20 2004
++++ linux/arch/alpha/defconfig Sat Apr 17 02:13:54 2004
+@@ -72,6 +72,7 @@
+ # CONFIG_KCORE_AOUT is not set
+ # CONFIG_BINFMT_AOUT is not set
+ CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_ELF_AOUT is not set
+ # CONFIG_BINFMT_MISC is not set
+ # CONFIG_BINFMT_EM86 is not set
+
+diff -urPX nopatch linux-2.4.26/arch/arm/config.in linux/arch/arm/config.in
+--- linux-2.4.26/arch/arm/config.in Fri Feb 20 10:07:20 2004
++++ linux/arch/arm/config.in Sat Apr 17 02:13:54 2004
+@@ -499,6 +499,9 @@
+ A.OUT CONFIG_KCORE_AOUT" ELF
+ tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+ bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+ dep_bool 'Power Management support (experimental)' CONFIG_PM $CONFIG_EXPERIMENTAL
+ dep_tristate 'RISC OS personality' CONFIG_ARTHUR $CONFIG_CPU_32
+diff -urPX nopatch linux-2.4.26/arch/arm/defconfig linux/arch/arm/defconfig
+--- linux-2.4.26/arch/arm/defconfig Fri Feb 20 10:07:21 2004
++++ linux/arch/arm/defconfig Sat Apr 17 02:13:54 2004
+@@ -83,8 +83,9 @@
+ CONFIG_NWFPE=y
+ CONFIG_KCORE_ELF=y
+ # CONFIG_KCORE_AOUT is not set
+-CONFIG_BINFMT_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
+ CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_ELF_AOUT is not set
+ # CONFIG_BINFMT_MISC is not set
+ # CONFIG_PM is not set
+ # CONFIG_ARTHUR is not set
+diff -urPX nopatch linux-2.4.26/arch/cris/config.in linux/arch/cris/config.in
+--- linux-2.4.26/arch/cris/config.in Fri Feb 20 10:07:21 2004
++++ linux/arch/cris/config.in Sat Apr 17 02:13:54 2004
+@@ -31,6 +31,9 @@
+ bool 'Sysctl support' CONFIG_SYSCTL
+
+ bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+
+ string 'Kernel command line' CONFIG_ETRAX_CMDLINE "root=/dev/mtdblock3"
+
+diff -urPX nopatch linux-2.4.26/arch/cris/defconfig linux/arch/cris/defconfig
+--- linux-2.4.26/arch/cris/defconfig Fri Feb 20 10:07:21 2004
++++ linux/arch/cris/defconfig Sat Apr 17 02:13:54 2004
+@@ -18,6 +18,7 @@
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ # CONFIG_SYSCTL is not set
+ CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_ELF_AOUT is not set
+ # CONFIG_ETRAX_KGDB is not set
+ # CONFIG_ETRAX_WATCHDOG is not set
+
+diff -urPX nopatch linux-2.4.26/arch/i386/config.in linux/arch/i386/config.in
+--- linux-2.4.26/arch/i386/config.in Fri Feb 20 10:07:21 2004
++++ linux/arch/i386/config.in Sat Apr 17 02:13:54 2004
+@@ -327,6 +327,9 @@
+ fi
+ tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+ bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+ bool 'Select task to kill on out of memory condition' CONFIG_OOM_KILLER
+
+diff -urPX nopatch linux-2.4.26/arch/i386/defconfig linux/arch/i386/defconfig
+--- linux-2.4.26/arch/i386/defconfig Sat Apr 17 02:10:25 2004
++++ linux/arch/i386/defconfig Sat Apr 17 02:23:27 2004
+@@ -110,9 +110,10 @@
+ CONFIG_SYSCTL=y
+ CONFIG_KCORE_ELF=y
+ # CONFIG_KCORE_AOUT is not set
+-CONFIG_BINFMT_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
+ CONFIG_BINFMT_ELF=y
+-CONFIG_BINFMT_MISC=y
++# CONFIG_BINFMT_ELF_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
+ # CONFIG_OOM_KILLER is not set
+ CONFIG_PM=y
+ # CONFIG_APM is not set
+diff -urPX nopatch linux-2.4.26/arch/ia64/config.in linux/arch/ia64/config.in
+--- linux-2.4.26/arch/ia64/config.in Fri Feb 20 10:07:21 2004
++++ linux/arch/ia64/config.in Sat Apr 17 02:13:54 2004
+@@ -124,6 +124,9 @@
+ bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+ bool 'Sysctl support' CONFIG_SYSCTL
+ bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+
+ if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
+diff -urPX nopatch linux-2.4.26/arch/ia64/defconfig linux/arch/ia64/defconfig
+--- linux-2.4.26/arch/ia64/defconfig Fri Feb 20 10:07:21 2004
++++ linux/arch/ia64/defconfig Sat Apr 17 02:13:54 2004
+@@ -60,6 +60,7 @@
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ CONFIG_SYSCTL=y
+ CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_ELF_AOUT is not set
+ # CONFIG_BINFMT_MISC is not set
+ CONFIG_ACPI=y
+ CONFIG_ACPI_EFI=y
+diff -urPX nopatch linux-2.4.26/arch/m68k/config.in linux/arch/m68k/config.in
+--- linux-2.4.26/arch/m68k/config.in Fri Feb 20 10:07:22 2004
++++ linux/arch/m68k/config.in Sat Apr 17 02:13:55 2004
+@@ -99,6 +99,9 @@
+ fi
+ tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+ bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+
+ if [ "$CONFIG_AMIGA" = "y" ]; then
+diff -urPX nopatch linux-2.4.26/arch/m68k/defconfig linux/arch/m68k/defconfig
+--- linux-2.4.26/arch/m68k/defconfig Fri Feb 20 10:07:22 2004
++++ linux/arch/m68k/defconfig Sat Apr 17 02:13:55 2004
+@@ -44,8 +44,9 @@
+ CONFIG_SYSCTL=y
+ CONFIG_KCORE_ELF=y
+ # CONFIG_KCORE_AOUT is not set
+-CONFIG_BINFMT_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
+ CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_ELF_AOUT is not set
+ # CONFIG_BINFMT_MISC is not set
+ CONFIG_ZORRO=y
+ # CONFIG_AMIGA_PCMCIA is not set
+diff -urPX nopatch linux-2.4.26/arch/mips/config-shared.in linux/arch/mips/config-shared.in
+--- linux-2.4.26/arch/mips/config-shared.in Fri Feb 20 10:07:22 2004
++++ linux/arch/mips/config-shared.in Sat Apr 17 02:13:55 2004
+@@ -944,6 +944,9 @@
+ define_bool CONFIG_KCORE_AOUT n
+ define_bool CONFIG_BINFMT_AOUT n
+ bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+ dep_bool 'Kernel support for Linux/MIPS 32-bit binary compatibility' CONFIG_MIPS32_COMPAT $CONFIG_MIPS64
+ dep_bool 'Kernel support for o32 binaries' CONFIG_MIPS32_O32 $CONFIG_MIPS32_COMPAT
+ dep_bool 'Kernel support for n32 binaries' CONFIG_MIPS32_N32 $CONFIG_MIPS32_COMPAT
+diff -urPX nopatch linux-2.4.26/arch/mips/defconfig linux/arch/mips/defconfig
+--- linux-2.4.26/arch/mips/defconfig Fri Feb 20 10:07:22 2004
++++ linux/arch/mips/defconfig Sat Apr 17 02:13:55 2004
+@@ -139,6 +139,7 @@
+ # CONFIG_KCORE_AOUT is not set
+ # CONFIG_BINFMT_AOUT is not set
+ CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_ELF_AOUT is not set
+ # CONFIG_MIPS32_COMPAT is not set
+ # CONFIG_MIPS32_O32 is not set
+ # CONFIG_MIPS32_N32 is not set
+diff -urPX nopatch linux-2.4.26/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c
+--- linux-2.4.26/arch/mips/kernel/irixelf.c Mon Aug 25 11:44:40 2003
++++ linux/arch/mips/kernel/irixelf.c Sat Apr 17 02:13:55 2004
+@@ -8,6 +8,7 @@
+ * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
+ */
+
++#include <linux/config.h>
+ #include <linux/module.h>
+
+ #include <linux/fs.h>
+@@ -48,7 +49,12 @@
+ extern int dump_fpu (elf_fpregset_t *);
+
+ static struct linux_binfmt irix_format = {
+- NULL, THIS_MODULE, load_irix_binary, load_irix_library,
++ NULL, THIS_MODULE, load_irix_binary,
++#ifdef CONFIG_BINFMT_ELF_AOUT
++ load_irix_library,
++#else
++ NULL,
++#endif
+ irix_core_dump, PAGE_SIZE
+ };
+
+@@ -787,6 +793,7 @@
+ goto out;
+ }
+
++#ifdef CONFIG_BINFMT_ELF_AOUT
+ /* This is really simpleminded and specialized - we are loading an
+ * a.out library that is given an ELF header.
+ */
+@@ -863,6 +870,7 @@
+ kfree(elf_phdata);
+ return 0;
+ }
++#endif
+
+ /* Called through irix_syssgi() to map an elf image given an FD,
+ * a phdr ptr USER_PHDRP in userspace, and a count CNT telling how many
+diff -urPX nopatch linux-2.4.26/arch/mips64/defconfig linux/arch/mips64/defconfig
+--- linux-2.4.26/arch/mips64/defconfig Fri Feb 20 10:07:24 2004
++++ linux/arch/mips64/defconfig Sat Apr 17 02:13:55 2004
+@@ -137,6 +137,7 @@
+ # CONFIG_KCORE_AOUT is not set
+ # CONFIG_BINFMT_AOUT is not set
+ CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_ELF_AOUT is not set
+ CONFIG_MIPS32_COMPAT=y
+ CONFIG_MIPS32_O32=y
+ # CONFIG_MIPS32_N32 is not set
+diff -urPX nopatch linux-2.4.26/arch/parisc/config.in linux/arch/parisc/config.in
+--- linux-2.4.26/arch/parisc/config.in Fri Feb 20 10:07:25 2004
++++ linux/arch/parisc/config.in Sat Apr 17 02:13:55 2004
+@@ -89,6 +89,9 @@
+ bool 'Sysctl support' CONFIG_SYSCTL
+ define_bool CONFIG_KCORE_ELF y
+ bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+ tristate 'Kernel support for SOM binaries' CONFIG_BINFMT_SOM
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+
+diff -urPX nopatch linux-2.4.26/arch/parisc/defconfig linux/arch/parisc/defconfig
+--- linux-2.4.26/arch/parisc/defconfig Fri Feb 20 10:07:25 2004
++++ linux/arch/parisc/defconfig Sat Apr 17 02:13:55 2004
+@@ -56,6 +56,7 @@
+ CONFIG_SYSCTL=y
+ CONFIG_KCORE_ELF=y
+ CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_ELF_AOUT is not set
+ CONFIG_BINFMT_SOM=y
+ # CONFIG_BINFMT_MISC is not set
+ # CONFIG_PM is not set
+diff -urPX nopatch linux-2.4.26/arch/ppc/config.in linux/arch/ppc/config.in
+--- linux-2.4.26/arch/ppc/config.in Sat Apr 17 02:10:25 2004
++++ linux/arch/ppc/config.in Sat Apr 17 02:13:55 2004
+@@ -384,6 +384,7 @@
+ fi
+ define_bool CONFIG_BINFMT_ELF y
+ define_bool CONFIG_KERNEL_ELF y
++bool 'ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+ bool 'Select task to kill on out of memory condition' CONFIG_OOM_KILLER
+
+diff -urPX nopatch linux-2.4.26/arch/ppc/defconfig linux/arch/ppc/defconfig
+--- linux-2.4.26/arch/ppc/defconfig Fri Feb 20 10:07:25 2004
++++ linux/arch/ppc/defconfig Sat Apr 17 02:13:55 2004
+@@ -59,7 +59,8 @@
+ CONFIG_KCORE_ELF=y
+ CONFIG_BINFMT_ELF=y
+ CONFIG_KERNEL_ELF=y
+-CONFIG_BINFMT_MISC=m
++# CONFIG_BINFMT_ELF_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
+ # CONFIG_OOM_KILLER is not set
+ CONFIG_PCI_NAMES=y
+ CONFIG_HOTPLUG=y
+diff -urPX nopatch linux-2.4.26/arch/ppc64/config.in linux/arch/ppc64/config.in
+--- linux-2.4.26/arch/ppc64/config.in Fri Feb 20 10:07:25 2004
++++ linux/arch/ppc64/config.in Sat Apr 17 02:13:55 2004
+@@ -82,6 +82,9 @@
+ fi
+
+ bool 'Kernel support for 64 bit ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+
+ tristate 'Kernel support for 32 bit ELF binaries' CONFIG_BINFMT_ELF32
+
+diff -urPX nopatch linux-2.4.26/arch/ppc64/defconfig linux/arch/ppc64/defconfig
+--- linux-2.4.26/arch/ppc64/defconfig Fri Feb 20 10:07:25 2004
++++ linux/arch/ppc64/defconfig Sat Apr 17 02:13:55 2004
+@@ -56,6 +56,7 @@
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ CONFIG_KCORE_ELF=y
+ CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_ELF_AOUT is not set
+ CONFIG_BINFMT_ELF32=y
+ # CONFIG_BINFMT_MISC is not set
+ CONFIG_PCI_NAMES=y
+diff -urPX nopatch linux-2.4.26/arch/s390/config.in linux/arch/s390/config.in
+--- linux-2.4.26/arch/s390/config.in Fri Nov 28 18:26:19 2003
++++ linux/arch/s390/config.in Sat Apr 17 02:13:55 2004
+@@ -58,6 +58,9 @@
+ bool 'Sysctl support' CONFIG_SYSCTL
+ define_bool CONFIG_KCORE_ELF y
+ bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+ bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
+ bool 'Pseudo page fault support' CONFIG_PFAULT
+diff -urPX nopatch linux-2.4.26/arch/s390/defconfig linux/arch/s390/defconfig
+--- linux-2.4.26/arch/s390/defconfig Fri Feb 20 10:07:26 2004
++++ linux/arch/s390/defconfig Sat Apr 17 02:13:55 2004
+@@ -46,6 +46,7 @@
+ CONFIG_SYSCTL=y
+ CONFIG_KCORE_ELF=y
+ CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_ELF_AOUT is not set
+ # CONFIG_BINFMT_MISC is not set
+ # CONFIG_PROCESS_DEBUG is not set
+ CONFIG_PFAULT=y
+diff -urPX nopatch linux-2.4.26/arch/s390x/config.in linux/arch/s390x/config.in
+--- linux-2.4.26/arch/s390x/config.in Fri Nov 28 18:26:19 2003
++++ linux/arch/s390x/config.in Sat Apr 17 02:13:55 2004
+@@ -61,6 +61,9 @@
+ bool 'Sysctl support' CONFIG_SYSCTL
+ define_bool CONFIG_KCORE_ELF y
+ bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+ bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
+ bool 'Pseudo page fault support' CONFIG_PFAULT
+diff -urPX nopatch linux-2.4.26/arch/s390x/defconfig linux/arch/s390x/defconfig
+--- linux-2.4.26/arch/s390x/defconfig Fri Feb 20 10:07:26 2004
++++ linux/arch/s390x/defconfig Sat Apr 17 02:13:55 2004
+@@ -47,6 +47,7 @@
+ CONFIG_SYSCTL=y
+ CONFIG_KCORE_ELF=y
+ CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_ELF_AOUT is not set
+ # CONFIG_BINFMT_MISC is not set
+ # CONFIG_PROCESS_DEBUG is not set
+ CONFIG_PFAULT=y
+diff -urPX nopatch linux-2.4.26/arch/sh/config.in linux/arch/sh/config.in
+--- linux-2.4.26/arch/sh/config.in Fri Feb 20 10:07:26 2004
++++ linux/arch/sh/config.in Sat Apr 17 02:13:55 2004
+@@ -283,6 +283,9 @@
+ A.OUT CONFIG_KCORE_AOUT" ELF
+ fi
+ bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+
+ bool 'Select task to kill on out of memory condition' CONFIG_OOM_KILLER
+diff -urPX nopatch linux-2.4.26/arch/sh/defconfig linux/arch/sh/defconfig
+--- linux-2.4.26/arch/sh/defconfig Fri Feb 20 10:07:26 2004
++++ linux/arch/sh/defconfig Sat Apr 17 02:13:55 2004
+@@ -48,6 +48,7 @@
+ CONFIG_KCORE_ELF=y
+ # CONFIG_KCORE_AOUT is not set
+ CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_ELF_AOUT is not set
+ # CONFIG_BINFMT_MISC is not set
+
+ #
+diff -urPX nopatch linux-2.4.26/arch/sparc/config.in linux/arch/sparc/config.in
+--- linux-2.4.26/arch/sparc/config.in Fri Feb 20 10:07:26 2004
++++ linux/arch/sparc/config.in Sat Apr 17 02:13:55 2004
+@@ -74,6 +74,9 @@
+ fi
+ tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+ bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+ bool 'SunOS binary emulation' CONFIG_SUNOS_EMUL
+ bool 'Select task to kill on out of memory condition' CONFIG_OOM_KILLER
+diff -urPX nopatch linux-2.4.26/arch/sparc/defconfig linux/arch/sparc/defconfig
+--- linux-2.4.26/arch/sparc/defconfig Sat Apr 17 02:10:25 2004
++++ linux/arch/sparc/defconfig Sat Apr 17 02:13:55 2004
+@@ -49,9 +49,10 @@
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ CONFIG_SYSCTL=y
+ CONFIG_KCORE_ELF=y
+-CONFIG_BINFMT_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
+ CONFIG_BINFMT_ELF=y
+-CONFIG_BINFMT_MISC=m
++# CONFIG_BINFMT_ELF_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
+ CONFIG_SUNOS_EMUL=y
+ # CONFIG_OOM_KILLER is not set
+
+diff -urPX nopatch linux-2.4.26/arch/sparc64/config.in linux/arch/sparc64/config.in
+--- linux-2.4.26/arch/sparc64/config.in Fri Feb 20 10:07:26 2004
++++ linux/arch/sparc64/config.in Sat Apr 17 02:13:55 2004
+@@ -77,6 +77,9 @@
+ bool ' Kernel support for 32-bit (ie. SunOS) a.out binaries' CONFIG_BINFMT_AOUT32
+ fi
+ bool 'Kernel support for 64-bit ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+ bool 'SunOS binary emulation' CONFIG_SUNOS_EMUL
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+diff -urPX nopatch linux-2.4.26/arch/sparc64/defconfig linux/arch/sparc64/defconfig
+--- linux-2.4.26/arch/sparc64/defconfig Sat Apr 17 02:10:26 2004
++++ linux/arch/sparc64/defconfig Sat Apr 17 02:13:55 2004
+@@ -56,7 +56,8 @@
+ CONFIG_BINFMT_ELF32=y
+ # CONFIG_BINFMT_AOUT32 is not set
+ CONFIG_BINFMT_ELF=y
+-CONFIG_BINFMT_MISC=m
++# CONFIG_BINFMT_ELF_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
+ # CONFIG_SUNOS_EMUL is not set
+ CONFIG_SOLARIS_EMUL=m
+ # CONFIG_OOM_KILLER is not set
+diff -urPX nopatch linux-2.4.26/arch/x86_64/config.in linux/arch/x86_64/config.in
+--- linux-2.4.26/arch/x86_64/config.in Sat Apr 17 02:10:26 2004
++++ linux/arch/x86_64/config.in Sat Apr 17 02:13:55 2004
+@@ -118,6 +118,9 @@
+ fi
+ #tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+ bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
++if [ "$CONFIG_BINFMT_ELF" != "n" ]; then
++ bool ' ELF binaries with a.out format interpreters or a.out libraries' CONFIG_BINFMT_ELF_AOUT
++fi
+ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+
+ bool 'Power Management support' CONFIG_PM
+diff -urPX nopatch linux-2.4.26/arch/x86_64/defconfig linux/arch/x86_64/defconfig
+--- linux-2.4.26/arch/x86_64/defconfig Sat Apr 17 02:10:26 2004
++++ linux/arch/x86_64/defconfig Sat Apr 17 02:13:55 2004
+@@ -67,6 +67,7 @@
+ CONFIG_SYSCTL=y
+ CONFIG_KCORE_ELF=y
+ CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_ELF_AOUT is not set
+ # CONFIG_BINFMT_MISC is not set
+ CONFIG_PM=y
+ CONFIG_IA32_EMULATION=y
+diff -urPX nopatch linux-2.4.26/fs/binfmt_elf.c linux/fs/binfmt_elf.c
+--- linux-2.4.26/fs/binfmt_elf.c Sat Apr 17 02:10:31 2004
++++ linux/fs/binfmt_elf.c Sat Apr 17 02:13:55 2004
+@@ -9,6 +9,7 @@
+ * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
+ */
+
++#include <linux/config.h>
+ #include <linux/module.h>
+
+ #include <linux/fs.h>
+@@ -43,7 +44,9 @@
+ #include <linux/elf.h>
+
+ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
++#ifdef CONFIG_BINFMT_ELF_AOUT
+ static int load_elf_library(struct file*);
++#endif
+ static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int);
+ extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
+ extern void dump_thread(struct pt_regs *, struct user *);
+@@ -73,8 +76,14 @@
+ #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1))
+ #define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1))
+
+-static struct linux_binfmt elf_format = {
+- NULL, THIS_MODULE, load_elf_binary, load_elf_library, elf_core_dump, ELF_EXEC_PAGESIZE
++static struct linux_binfmt elf_format = {
++ NULL, THIS_MODULE, load_elf_binary,
++#ifdef CONFIG_BINFMT_ELF_AOUT
++ load_elf_library,
++#else
++ NULL,
++#endif
++ elf_core_dump, ELF_EXEC_PAGESIZE
+ };
+
+ #define BAD_ADDR(x) ((unsigned long)(x) > TASK_SIZE)
+@@ -369,6 +378,7 @@
+ return error;
+ }
+
++#ifdef CONFIG_BINFMT_ELF_AOUT
+ static unsigned long load_aout_interp(struct exec * interp_ex,
+ struct file * interpreter)
+ {
+@@ -413,6 +423,7 @@
+ out:
+ return elf_entry;
+ }
++#endif
+
+ /*
+ * These are the functions used to load ELF style executables and shared
+@@ -420,7 +431,9 @@
+ */
+
+ #define INTERPRETER_NONE 0
++#ifdef CONFIG_BINFMT_ELF_AOUT
+ #define INTERPRETER_AOUT 1
++#endif
+ #define INTERPRETER_ELF 2
+
+
+@@ -444,7 +457,9 @@
+ struct elfhdr elf_ex;
+ struct elfhdr interp_elf_ex;
+ struct exec interp_ex;
++#ifdef CONFIG_BINFMT_ELF_AOUT
+ char passed_fileno[6];
++#endif
+ struct files_struct *files;
+
+ /* Get the exec-header */
+@@ -556,6 +571,7 @@
+
+ /* Some simple consistency checks for the interpreter */
+ if (elf_interpreter) {
++#ifdef CONFIG_BINFMT_ELF_AOUT
+ interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
+
+ /* Now figure out which format our binary is */
+@@ -563,6 +579,9 @@
+ (N_MAGIC(interp_ex) != ZMAGIC) &&
+ (N_MAGIC(interp_ex) != QMAGIC))
+ interpreter_type = INTERPRETER_ELF;
++#else
++ interpreter_type = INTERPRETER_ELF;
++#endif
+
+ if (memcmp(interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
+ interpreter_type &= ~INTERPRETER_ELF;
+@@ -571,6 +590,7 @@
+ if (!interpreter_type)
+ goto out_free_dentry;
+
++#ifdef CONFIG_BINFMT_ELF_AOUT
+ /* Make sure only one type was selected */
+ if ((interpreter_type & INTERPRETER_ELF) &&
+ interpreter_type != INTERPRETER_ELF) {
+@@ -578,6 +598,7 @@
+ // printk(KERN_WARNING "ELF: Ambiguous type, using ELF\n");
+ interpreter_type = INTERPRETER_ELF;
+ }
++#endif
+ /* Verify the interpreter has a valid arch */
+ if ((interpreter_type == INTERPRETER_ELF) &&
+ !elf_check_arch(&interp_elf_ex))
+@@ -590,6 +611,7 @@
+ /* OK, we are done with that, now set up the arg stuff,
+ and then start this sucker up */
+
++#ifdef CONFIG_BINFMT_ELF_AOUT
+ if (!bprm->sh_bang) {
+ char * passed_p;
+
+@@ -605,6 +627,7 @@
+ }
+ }
+ }
++#endif
+
+ /* Flush all traces of the currently running executable */
+ retval = flush_old_exec(bprm);
+@@ -721,10 +744,12 @@
+ end_data += load_bias;
+
+ if (elf_interpreter) {
++#ifdef CONFIG_BINFMT_ELF_AOUT
+ if (interpreter_type == INTERPRETER_AOUT)
+ elf_entry = load_aout_interp(&interp_ex,
+ interpreter);
+ else
++#endif
+ elf_entry = load_elf_interp(&interp_elf_ex,
+ interpreter,
+ &interp_load_addr);
+@@ -743,7 +768,9 @@
+
+ kfree(elf_phdata);
+
++#ifdef CONFIG_BINFMT_ELF_AOUT
+ if (interpreter_type != INTERPRETER_AOUT)
++#endif
+ sys_close(elf_exec_fileno);
+
+ set_binfmt(&elf_format);
+@@ -757,10 +784,14 @@
+ &elf_ex,
+ load_addr, load_bias,
+ interp_load_addr,
++#ifdef CONFIG_BINFMT_ELF_AOUT
+ (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
+ /* N.B. passed_fileno might not be initialized? */
+ if (interpreter_type == INTERPRETER_AOUT)
+ current->mm->arg_start += strlen(passed_fileno) + 1;
++#else
++ 1);
++#endif
+ current->mm->start_brk = current->mm->brk = elf_brk;
+ current->mm->end_code = end_code;
+ current->mm->start_code = start_code;
+@@ -838,9 +869,9 @@
+ goto out;
+ }
+
++#ifdef CONFIG_BINFMT_ELF_AOUT
+ /* This is really simpleminded and specialized - we are loading an
+ a.out library that is given an ELF header. */
+-
+ static int load_elf_library(struct file *file)
+ {
+ struct elf_phdr *elf_phdata;
+@@ -911,6 +942,7 @@
+ out:
+ return error;
+ }
++#endif
+
+ /*
+ * Note that some platforms still use traditional core dumps and not
+diff -urPX nopatch linux-2.4.26/fs/exec.c linux/fs/exec.c
+--- linux-2.4.26/fs/exec.c Fri Feb 20 10:07:36 2004
++++ linux/fs/exec.c Sat Apr 17 02:13:55 2004
+@@ -109,6 +109,7 @@
+ */
+ asmlinkage long sys_uselib(const char * library)
+ {
++#if defined(CONFIG_BINFMT_AOUT) || defined(CONFIG_BINFMT_ELF_AOUT)
+ struct file * file;
+ struct nameidata nd;
+ int error;
+@@ -155,6 +156,9 @@
+ exit:
+ path_release(&nd);
+ goto out;
++#else
++ return -ENOSYS;
++#endif
+ }
+
+ /*
diff --git a/target/linux/generic-2.4/patches/109-ipsec_nat_traversal.patch b/target/linux/generic-2.4/patches/109-ipsec_nat_traversal.patch
new file mode 100644
index 0000000..fc4c29d
--- /dev/null
+++ b/target/linux/generic-2.4/patches/109-ipsec_nat_traversal.patch
@@ -0,0 +1,140 @@
+packaging/utils/nattpatch 2.4
+--- linux/include/net/sock.h 2002/02/06 15:25:10 1.1
++++ linux/include/net/sock.h 2002/05/22 12:14:56
+@@ -488,7 +488,13 @@
+ } bictcp;
+ };
+
+-
++#if 1
++#define UDP_OPT_IN_SOCK 1
++struct udp_opt {
++ __u32 esp_in_udp;
++};
++#endif
++
+ /*
+ * This structure really needs to be cleaned up.
+ * Most of it is for TCP, and not used by any of
+@@ -655,6 +661,9 @@
+ #if defined(CONFIG_SPX) || defined (CONFIG_SPX_MODULE)
+ struct spx_opt af_spx;
+ #endif /* CONFIG_SPX */
++#if 1
++ struct udp_opt af_udp;
++#endif
+
+ } tp_pinfo;
+
+--- linux/net/Config.in.orig Fri Feb 9 14:34:13 2001
++++ linux/net/Config.in Thu Feb 22 19:40:08 2001
+@@ -88,3 +88,5 @@
+ endmenu
+
++bool 'IPSEC NAT-Traversal' CONFIG_IPSEC_NAT_TRAVERSAL
++
+ endmenu
+--- linux/net/ipv4/udp.c.1 Wed Jan 28 15:57:05 2004
++++ linux/net/ipv4/udp.c Wed Jan 28 15:58:56 2004
+@@ -787,6 +787,9 @@
+
+ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
+ {
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++ struct udp_opt *tp = &(sk->tp_pinfo.af_udp);
++#endif
+ /*
+ * Charge it to the socket, dropping if the queue is full.
+ */
+@@ -804,6 +807,40 @@
+ }
+ #endif
+
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++ if (tp->esp_in_udp) {
++ /*
++ * Set skb->sk and xmit packet to ipsec_rcv.
++ *
++ * If ret != 0, ipsec_rcv refused the packet (not ESPinUDP),
++ * restore skb->sk and fall back to sock_queue_rcv_skb
++ */
++ struct inet_protocol *esp = NULL;
++
++#if defined(CONFIG_KLIPS) && !defined(CONFIG_KLIPS_MODULE)
++ /* optomize only when we know it is statically linked */
++ extern struct inet_protocol esp_protocol;
++ esp = &esp_protocol;
++#else
++ for (esp = (struct inet_protocol *)inet_protos[IPPROTO_ESP & (MAX_INET_PROTOS - 1)];
++ (esp) && (esp->protocol != IPPROTO_ESP);
++ esp = esp->next);
++#endif
++
++ if (esp && esp->handler) {
++ struct sock *sav_sk = skb->sk;
++ skb->sk = sk;
++ if (esp->handler(skb) == 0) {
++ skb->sk = sav_sk;
++ /*not sure we might count ESPinUDP as UDP...*/
++ UDP_INC_STATS_BH(UdpInDatagrams);
++ return 0;
++ }
++ skb->sk = sav_sk;
++ }
++ }
++#endif
++
+ if (sock_queue_rcv_skb(sk,skb)<0) {
+ UDP_INC_STATS_BH(UdpInErrors);
+ IP_INC_STATS_BH(IpInDiscards);
+@@ -1027,13 +1064,49 @@
+ return len;
+ }
+
++static int udp_setsockopt(struct sock *sk, int level, int optname,
++ char *optval, int optlen)
++{
++ struct udp_opt *tp = &(sk->tp_pinfo.af_udp);
++ int val;
++ int err = 0;
++
++ if (level != SOL_UDP)
++ return ip_setsockopt(sk, level, optname, optval, optlen);
++
++ if(optlen<sizeof(int))
++ return -EINVAL;
++
++ if (get_user(val, (int *)optval))
++ return -EFAULT;
++
++ lock_sock(sk);
++
++ switch(optname) {
++#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
++#ifndef UDP_ESPINUDP
++#define UDP_ESPINUDP 100
++#endif
++ case UDP_ESPINUDP:
++ tp->esp_in_udp = val;
++ break;
++#endif
++ default:
++ err = -ENOPROTOOPT;
++ break;
++ }
++
++ release_sock(sk);
++ return err;
++}
++
+ struct proto udp_prot = {
+ name: "UDP",
+ close: udp_close,
+ connect: udp_connect,
+ disconnect: udp_disconnect,
+ ioctl: udp_ioctl,
+- setsockopt: ip_setsockopt,
++ setsockopt: udp_setsockopt,
+ getsockopt: ip_getsockopt,
+ sendmsg: udp_sendmsg,
+ recvmsg: udp_recvmsg,
diff --git a/target/linux/generic-2.4/patches/110-netdev_random_core.patch b/target/linux/generic-2.4/patches/110-netdev_random_core.patch
new file mode 100644
index 0000000..784b65e
--- /dev/null
+++ b/target/linux/generic-2.4/patches/110-netdev_random_core.patch
@@ -0,0 +1,296 @@
+diff -urN linux-2.4.26-pre5/Documentation/Configure.help linux-2.4.26-pre5-netdev-core/Documentation/Configure.help
+--- linux-2.4.26-pre5/Documentation/Configure.help Sat Mar 20 10:08:18 2004
++++ linux-2.4.26-pre5-netdev-core/Documentation/Configure.help Sun Mar 21 10:16:14 2004
+@@ -10419,6 +10419,20 @@
+
+ If you don't know what to use this for, you don't need it.
+
++Allow Net Devices to contribute to /dev/random
++CONFIG_NET_RANDOM
++ If you say Y here, network device interrupts will contribute to the
++ kernel entropy pool. Normally, block devices and some other devices
++ feed the pool. Some systems, such as those that are headless or diskless,
++ need additional entropy sources. Some people, however, feel that network
++ devices should not contribute to /dev/random because an external attacker
++ could observe incoming packets in an attempt to learn the entropy pool's
++ state. If you say N, no network device will contribute entropy.
++
++ If you believe there is a chance of your network packets being observed
++ and you doubt the security of the entropy pool's one-way hash, do not
++ enable this. If unsure, say N.
++
+ Ethertap network tap (OBSOLETE)
+ CONFIG_ETHERTAP
+ If you say Y here (and have said Y to "Kernel/User network link
+diff -urN linux-2.4.26-pre5/drivers/net/Config.in linux-2.4.26-pre5-netdev-core/drivers/net/Config.in
+--- linux-2.4.26-pre5/drivers/net/Config.in Sat Mar 20 10:08:18 2004
++++ linux-2.4.26-pre5-netdev-core/drivers/net/Config.in Sun Mar 21 10:16:14 2004
+@@ -8,6 +8,7 @@
+ tristate 'Bonding driver support' CONFIG_BONDING
+ tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
+ tristate 'Universal TUN/TAP device driver support' CONFIG_TUN
++bool 'Allow Net Devices to contribute to /dev/random' CONFIG_NET_RANDOM
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
+ fi
+diff -urN linux-2.4.26-pre5/include/asm-alpha/signal.h linux-2.4.26-pre5-netdev-core/include/asm-alpha/signal.h
+--- linux-2.4.26-pre5/include/asm-alpha/signal.h Sat Dec 1 18:27:14 2001
++++ linux-2.4.26-pre5-netdev-core/include/asm-alpha/signal.h Sun Mar 21 10:16:14 2004
+@@ -121,7 +121,14 @@
+ #define SA_PROBE SA_ONESHOT
+ #define SA_SAMPLE_RANDOM SA_RESTART
+ #define SA_SHIRQ 0x40000000
++
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
+ #endif
++
++#endif /* __KERNEL__ */
+
+ #define SIG_BLOCK 1 /* for blocking signals */
+ #define SIG_UNBLOCK 2 /* for unblocking signals */
+diff -urN linux-2.4.26-pre5/include/asm-arm/signal.h linux-2.4.26-pre5-netdev-core/include/asm-arm/signal.h
+--- linux-2.4.26-pre5/include/asm-arm/signal.h Sat Sep 13 07:57:29 2003
++++ linux-2.4.26-pre5-netdev-core/include/asm-arm/signal.h Sun Mar 21 10:16:14 2004
+@@ -125,7 +125,14 @@
+ #define SA_PROBE 0x80000000
+ #define SA_SAMPLE_RANDOM 0x10000000
+ #define SA_SHIRQ 0x04000000
++
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
+ #endif
++
++#endif /* __KERNEL__ */
+
+ #define SIG_BLOCK 0 /* for blocking signals */
+ #define SIG_UNBLOCK 1 /* for unblocking signals */
+diff -urN linux-2.4.26-pre5/include/asm-cris/signal.h linux-2.4.26-pre5-netdev-core/include/asm-cris/signal.h
+--- linux-2.4.26-pre5/include/asm-cris/signal.h Sat Dec 1 18:27:14 2001
++++ linux-2.4.26-pre5-netdev-core/include/asm-cris/signal.h Sun Mar 21 10:16:14 2004
+@@ -120,7 +120,14 @@
+ #define SA_PROBE SA_ONESHOT
+ #define SA_SAMPLE_RANDOM SA_RESTART
+ #define SA_SHIRQ 0x04000000
++
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
+ #endif
++
++#endif /* __KERNEL__ */
+
+ #define SIG_BLOCK 0 /* for blocking signals */
+ #define SIG_UNBLOCK 1 /* for unblocking signals */
+diff -urN linux-2.4.26-pre5/include/asm-i386/signal.h linux-2.4.26-pre5-netdev-core/include/asm-i386/signal.h
+--- linux-2.4.26-pre5/include/asm-i386/signal.h Sun Mar 21 00:00:43 2004
++++ linux-2.4.26-pre5-netdev-core/include/asm-i386/signal.h Sun Mar 21 10:16:14 2004
+@@ -119,7 +119,14 @@
+ #define SA_PROBE SA_ONESHOT
+ #define SA_SAMPLE_RANDOM SA_RESTART
+ #define SA_SHIRQ 0x04000000
++
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
+ #endif
++
++#endif /* __KERNEL__ */
+
+ #define SIG_BLOCK 0 /* for blocking signals */
+ #define SIG_UNBLOCK 1 /* for unblocking signals */
+diff -urN linux-2.4.26-pre5/include/asm-ia64/signal.h linux-2.4.26-pre5-netdev-core/include/asm-ia64/signal.h
+--- linux-2.4.26-pre5/include/asm-ia64/signal.h Sat Mar 20 10:08:20 2004
++++ linux-2.4.26-pre5-netdev-core/include/asm-ia64/signal.h Sun Mar 21 10:16:14 2004
+@@ -117,6 +117,12 @@
+ #define SA_SHIRQ 0x04000000
+ #define SA_PERCPU_IRQ 0x02000000
+
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
++#endif
++
+ #endif /* __KERNEL__ */
+
+ #define SIG_BLOCK 0 /* for blocking signals */
+diff -urN linux-2.4.26-pre5/include/asm-m68k/signal.h linux-2.4.26-pre5-netdev-core/include/asm-m68k/signal.h
+--- linux-2.4.26-pre5/include/asm-m68k/signal.h Fri Feb 20 07:38:33 2004
++++ linux-2.4.26-pre5-netdev-core/include/asm-m68k/signal.h Sun Mar 21 10:16:14 2004
+@@ -116,7 +116,14 @@
+ #define SA_PROBE SA_ONESHOT
+ #define SA_SAMPLE_RANDOM SA_RESTART
+ #define SA_SHIRQ 0x04000000
++
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
+ #endif
++
++#endif /* __KERNEL__ */
+
+ #define SIG_BLOCK 0 /* for blocking signals */
+ #define SIG_UNBLOCK 1 /* for unblocking signals */
+diff -urN linux-2.4.26-pre5/include/asm-mips/signal.h linux-2.4.26-pre5-netdev-core/include/asm-mips/signal.h
+--- linux-2.4.26-pre5/include/asm-mips/signal.h Sat Sep 13 07:57:31 2003
++++ linux-2.4.26-pre5-netdev-core/include/asm-mips/signal.h Sun Mar 21 10:16:14 2004
+@@ -111,6 +111,12 @@
+ #define SA_SAMPLE_RANDOM SA_RESTART
+ #define SA_SHIRQ 0x02000000
+
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
++#endif
++
+ #endif /* __KERNEL__ */
+
+ #define SIG_BLOCK 1 /* for blocking signals */
+diff -urN linux-2.4.26-pre5/include/asm-mips64/signal.h linux-2.4.26-pre5-netdev-core/include/asm-mips64/signal.h
+--- linux-2.4.26-pre5/include/asm-mips64/signal.h Sat Sep 13 07:57:32 2003
++++ linux-2.4.26-pre5-netdev-core/include/asm-mips64/signal.h Sun Mar 21 10:16:14 2004
+@@ -119,6 +119,12 @@
+ #define SA_SAMPLE_RANDOM SA_RESTART
+ #define SA_SHIRQ 0x02000000
+
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
++#endif
++
+ #endif /* __KERNEL__ */
+
+ #define SIG_BLOCK 1 /* for blocking signals */
+diff -urN linux-2.4.26-pre5/include/asm-parisc/signal.h linux-2.4.26-pre5-netdev-core/include/asm-parisc/signal.h
+--- linux-2.4.26-pre5/include/asm-parisc/signal.h Sun Jan 11 18:48:21 2004
++++ linux-2.4.26-pre5-netdev-core/include/asm-parisc/signal.h Sun Mar 21 10:16:14 2004
+@@ -100,6 +100,12 @@
+ #define SA_SAMPLE_RANDOM SA_RESTART
+ #define SA_SHIRQ 0x04000000
+
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
++#endif
++
+ #endif /* __KERNEL__ */
+
+ #define SIG_BLOCK 0 /* for blocking signals */
+diff -urN linux-2.4.26-pre5/include/asm-ppc/signal.h linux-2.4.26-pre5-netdev-core/include/asm-ppc/signal.h
+--- linux-2.4.26-pre5/include/asm-ppc/signal.h Sat Sep 13 07:57:32 2003
++++ linux-2.4.26-pre5-netdev-core/include/asm-ppc/signal.h Sun Mar 21 10:16:14 2004
+@@ -111,6 +111,13 @@
+ #define SA_PROBE SA_ONESHOT
+ #define SA_SAMPLE_RANDOM SA_RESTART
+ #define SA_SHIRQ 0x04000000
++
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
++#endif
++
+ #endif /* __KERNEL__ */
+
+ #define SIG_BLOCK 0 /* for blocking signals */
+diff -urN linux-2.4.26-pre5/include/asm-s390/signal.h linux-2.4.26-pre5-netdev-core/include/asm-s390/signal.h
+--- linux-2.4.26-pre5/include/asm-s390/signal.h Fri Feb 20 07:38:34 2004
++++ linux-2.4.26-pre5-netdev-core/include/asm-s390/signal.h Sun Mar 21 10:16:14 2004
+@@ -129,7 +129,14 @@
+ #define SA_SHIRQ 0x04000000
+ #define SA_DOPATHGROUP 0x00100000
+ #define SA_FORCE 0x00200000
++
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
+ #endif
++
++#endif /* __KERNEL__ */
+
+ #define SIG_BLOCK 0 /* for blocking signals */
+ #define SIG_UNBLOCK 1 /* for unblocking signals */
+diff -urN linux-2.4.26-pre5/include/asm-s390x/signal.h linux-2.4.26-pre5-netdev-core/include/asm-s390x/signal.h
+--- linux-2.4.26-pre5/include/asm-s390x/signal.h Fri Feb 20 07:38:34 2004
++++ linux-2.4.26-pre5-netdev-core/include/asm-s390x/signal.h Sun Mar 21 10:16:14 2004
+@@ -129,7 +129,14 @@
+ #define SA_SHIRQ 0x04000000
+ #define SA_DOPATHGROUP 0x00100000
+ #define SA_FORCE 0x00200000
++
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
+ #endif
++
++#endif /* __KERNEL__ */
+
+ #define SIG_BLOCK 0 /* for blocking signals */
+ #define SIG_UNBLOCK 1 /* for unblocking signals */
+diff -urN linux-2.4.26-pre5/include/asm-sh/signal.h linux-2.4.26-pre5-netdev-core/include/asm-sh/signal.h
+--- linux-2.4.26-pre5/include/asm-sh/signal.h Sat Dec 1 18:27:13 2001
++++ linux-2.4.26-pre5-netdev-core/include/asm-sh/signal.h Sun Mar 21 10:16:14 2004
+@@ -107,7 +107,14 @@
+ #define SA_PROBE SA_ONESHOT
+ #define SA_SAMPLE_RANDOM SA_RESTART
+ #define SA_SHIRQ 0x04000000
++
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
+ #endif
++
++#endif /* __KERNEL__ */
+
+ #define SIG_BLOCK 0 /* for blocking signals */
+ #define SIG_UNBLOCK 1 /* for unblocking signals */
+diff -urN linux-2.4.26-pre5/include/asm-sparc/signal.h linux-2.4.26-pre5-netdev-core/include/asm-sparc/signal.h
+--- linux-2.4.26-pre5/include/asm-sparc/signal.h Sat Dec 1 18:27:14 2001
++++ linux-2.4.26-pre5-netdev-core/include/asm-sparc/signal.h Sun Mar 21 10:16:14 2004
+@@ -176,7 +176,14 @@
+ #define SA_PROBE SA_ONESHOT
+ #define SA_SAMPLE_RANDOM SA_RESTART
+ #define SA_STATIC_ALLOC 0x80
++
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
+ #endif
++
++#endif /* __KERNEL__ */
+
+ /* Type of a signal handler. */
+ #ifdef __KERNEL__
+diff -urN linux-2.4.26-pre5/include/asm-sparc64/signal.h linux-2.4.26-pre5-netdev-core/include/asm-sparc64/signal.h
+--- linux-2.4.26-pre5/include/asm-sparc64/signal.h Sat Dec 1 18:27:14 2001
++++ linux-2.4.26-pre5-netdev-core/include/asm-sparc64/signal.h Sun Mar 21 10:16:14 2004
+@@ -192,7 +192,14 @@
+ #define SA_PROBE SA_ONESHOT
+ #define SA_SAMPLE_RANDOM SA_RESTART
+ #define SA_STATIC_ALLOC 0x80
++
++#ifdef CONFIG_NET_RANDOM
++#define SA_NET_RANDOM SA_SAMPLE_RANDOM
++#else
++#define SA_NET_RANDOM 0
+ #endif
++
++#endif /* __KERNEL__ */
+
+ /* Type of a signal handler. */
+ #ifdef __KERNEL__
diff --git a/target/linux/generic-2.4/patches/112-bridging_performance.patch b/target/linux/generic-2.4/patches/112-bridging_performance.patch
new file mode 100644
index 0000000..c5d8634
--- /dev/null
+++ b/target/linux/generic-2.4/patches/112-bridging_performance.patch
@@ -0,0 +1,22 @@
+--- linux.old/net/core/dev.c 2005-07-05 16:42:36.000000000 +0200
++++ linux.dev/net/core/dev.c 2005-07-08 19:32:46.000000000 +0200
+@@ -1289,6 +1289,19 @@
+ local_irq_save(flags);
+
+ netdev_rx_stat[this_cpu].total++;
++
++#ifdef CONFIG_BRIDGE
++ /* Optimisation for framebursting (allow interleaving of pkts by
++ * immediately processing the rx pkt instead of Qing the pkt and deferring
++ * the processing). Only optimise for bridging and guard against non
++ * TASKLET based netif_rx calls.
++ */
++ if (!in_irq() && (skb->dev->br_port != NULL) && br_handle_frame_hook != NULL) {
++ local_irq_restore(flags);
++ return netif_receive_skb(skb);
++ }
++#endif
++
+ if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {
+ if (queue->input_pkt_queue.qlen) {
+ if (queue->throttle)
diff --git a/target/linux/generic-2.4/patches/113-even_more_gcc4_stuff.patch b/target/linux/generic-2.4/patches/113-even_more_gcc4_stuff.patch
new file mode 100644
index 0000000..1b98717
--- /dev/null
+++ b/target/linux/generic-2.4/patches/113-even_more_gcc4_stuff.patch
@@ -0,0 +1,367 @@
+diff -Nur linux.old/arch/mips/kernel/mips_ksyms.c linux.dev/arch/mips/kernel/mips_ksyms.c
+--- linux.old/arch/mips/kernel/mips_ksyms.c 2004-02-18 14:36:30.000000000 +0100
++++ linux.dev/arch/mips/kernel/mips_ksyms.c 2005-10-24 14:21:53.702396250 +0200
+@@ -30,6 +30,10 @@
+ #include <asm/floppy.h>
+ #endif
+
++asmlinkage long long __ashldi3 (long long, int);
++asmlinkage long long __ashrdi3 (long long, int);
++asmlinkage long long __lshrdi3 (long long, int);
++asmlinkage long long __muldi3 (long long, long long);
+ extern void *__bzero(void *__s, size_t __count);
+ extern long __strncpy_from_user_nocheck_asm(char *__to,
+ const char *__from, long __len);
+@@ -78,6 +82,13 @@
+ EXPORT_SYMBOL_NOVERS(__strnlen_user_asm);
+
+
++/* Compiler stuff */
++EXPORT_SYMBOL_NOVERS(__ashldi3);
++EXPORT_SYMBOL_NOVERS(__ashrdi3);
++EXPORT_SYMBOL_NOVERS(__lshrdi3);
++EXPORT_SYMBOL_NOVERS(__muldi3);
++
++
+ /* Networking helper routines. */
+ EXPORT_SYMBOL(csum_partial_copy);
+
+diff -Nur linux.old/arch/mips/lib/Makefile linux.dev/arch/mips/lib/Makefile
+--- linux.old/arch/mips/lib/Makefile 2004-02-18 14:36:30.000000000 +0100
++++ linux.dev/arch/mips/lib/Makefile 2005-10-24 14:21:53.774400750 +0200
+@@ -9,7 +9,8 @@
+ obj-y += csum_partial.o csum_partial_copy.o \
+ promlib.o rtc-std.o rtc-no.o memcpy.o \
+ memset.o watch.o strlen_user.o \
+- strncpy_user.o strnlen_user.o
++ strncpy_user.o strnlen_user.o \
++ ashldi3.o ashrdi3.o lshrdi3.o muldi3.o
+
+ export-objs := rtc-std.o rtc-no.o
+
+diff -Nur linux.old/arch/mips/lib/ashldi3.c linux.dev/arch/mips/lib/ashldi3.c
+--- linux.old/arch/mips/lib/ashldi3.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/lib/ashldi3.c 2005-10-24 14:21:53.774400750 +0200
+@@ -0,0 +1,62 @@
++/* ashrdi3.c extracted from gcc-2.95.2/libgcc2.c which is: */
++/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.
++
++This file is part of GNU CC.
++
++GNU CC 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, or (at your option)
++any later version.
++
++GNU CC 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 GNU CC; see the file COPYING. If not, write to
++the Free Software Foundation, 59 Temple Place - Suite 330,
++Boston, MA 02111-1307, USA. */
++
++#define BITS_PER_UNIT 8
++
++typedef int SItype __attribute__ ((mode (SI)));
++typedef unsigned int USItype __attribute__ ((mode (SI)));
++typedef int DItype __attribute__ ((mode (DI)));
++typedef int word_type __attribute__ ((mode (__word__)));
++
++struct DIstruct {SItype high, low;};
++
++typedef union
++{
++ struct DIstruct s;
++ DItype ll;
++} DIunion;
++
++DItype
++__ashldi3 (DItype u, word_type b)
++{
++ DIunion w;
++ word_type bm;
++ DIunion uu;
++
++ if (b == 0)
++ return u;
++
++ uu.ll = u;
++
++ bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
++ if (bm <= 0)
++ {
++ w.s.low = 0;
++ w.s.high = (USItype)uu.s.low << -bm;
++ }
++ else
++ {
++ USItype carries = (USItype)uu.s.low >> bm;
++ w.s.low = (USItype)uu.s.low << b;
++ w.s.high = ((USItype)uu.s.high << b) | carries;
++ }
++
++ return w.ll;
++}
+diff -Nur linux.old/arch/mips/lib/ashrdi3.c linux.dev/arch/mips/lib/ashrdi3.c
+--- linux.old/arch/mips/lib/ashrdi3.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/lib/ashrdi3.c 2005-10-24 14:21:53.774400750 +0200
+@@ -0,0 +1,63 @@
++/* ashrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */
++/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
++
++This file is part of GNU CC.
++
++GNU CC 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, or (at your option)
++any later version.
++
++GNU CC 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 GNU CC; see the file COPYING. If not, write to
++the Free Software Foundation, 59 Temple Place - Suite 330,
++Boston, MA 02111-1307, USA. */
++
++#define BITS_PER_UNIT 8
++
++typedef int SItype __attribute__ ((mode (SI)));
++typedef unsigned int USItype __attribute__ ((mode (SI)));
++typedef int DItype __attribute__ ((mode (DI)));
++typedef int word_type __attribute__ ((mode (__word__)));
++
++struct DIstruct {SItype high, low;};
++
++typedef union
++{
++ struct DIstruct s;
++ DItype ll;
++} DIunion;
++
++DItype
++__ashrdi3 (DItype u, word_type b)
++{
++ DIunion w;
++ word_type bm;
++ DIunion uu;
++
++ if (b == 0)
++ return u;
++
++ uu.ll = u;
++
++ bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
++ if (bm <= 0)
++ {
++ /* w.s.high = 1..1 or 0..0 */
++ w.s.high = uu.s.high >> (sizeof (SItype) * BITS_PER_UNIT - 1);
++ w.s.low = uu.s.high >> -bm;
++ }
++ else
++ {
++ USItype carries = (USItype)uu.s.high << bm;
++ w.s.high = uu.s.high >> b;
++ w.s.low = ((USItype)uu.s.low >> b) | carries;
++ }
++
++ return w.ll;
++}
+diff -Nur linux.old/arch/mips/lib/lshrdi3.c linux.dev/arch/mips/lib/lshrdi3.c
+--- linux.old/arch/mips/lib/lshrdi3.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/lib/lshrdi3.c 2005-10-24 14:21:53.774400750 +0200
+@@ -0,0 +1,62 @@
++/* lshrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */
++/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
++
++This file is part of GNU CC.
++
++GNU CC 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, or (at your option)
++any later version.
++
++GNU CC 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 GNU CC; see the file COPYING. If not, write to
++the Free Software Foundation, 59 Temple Place - Suite 330,
++Boston, MA 02111-1307, USA. */
++
++#define BITS_PER_UNIT 8
++
++typedef int SItype __attribute__ ((mode (SI)));
++typedef unsigned int USItype __attribute__ ((mode (SI)));
++typedef int DItype __attribute__ ((mode (DI)));
++typedef int word_type __attribute__ ((mode (__word__)));
++
++struct DIstruct {SItype high, low;};
++
++typedef union
++{
++ struct DIstruct s;
++ DItype ll;
++} DIunion;
++
++DItype
++__lshrdi3 (DItype u, word_type b)
++{
++ DIunion w;
++ word_type bm;
++ DIunion uu;
++
++ if (b == 0)
++ return u;
++
++ uu.ll = u;
++
++ bm = (sizeof (SItype) * BITS_PER_UNIT) - b;
++ if (bm <= 0)
++ {
++ w.s.high = 0;
++ w.s.low = (USItype)uu.s.high >> -bm;
++ }
++ else
++ {
++ USItype carries = (USItype)uu.s.high << bm;
++ w.s.high = (USItype)uu.s.high >> b;
++ w.s.low = ((USItype)uu.s.low >> b) | carries;
++ }
++
++ return w.ll;
++}
+diff -Nur linux.old/arch/mips/lib/muldi3.c linux.dev/arch/mips/lib/muldi3.c
+--- linux.old/arch/mips/lib/muldi3.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/lib/muldi3.c 2005-10-24 14:21:53.774400750 +0200
+@@ -0,0 +1,63 @@
++/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and
++ gcc-2.7.2.3/longlong.h which is: */
++/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
++
++This file is part of GNU CC.
++
++GNU CC 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, or (at your option)
++any later version.
++
++GNU CC 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 GNU CC; see the file COPYING. If not, write to
++the Free Software Foundation, 59 Temple Place - Suite 330,
++Boston, MA 02111-1307, USA. */
++
++#define BITS_PER_UNIT 8
++
++#define umul_ppmm(w1, w0, u, v) \
++ __asm__ ("multu %2,%3" \
++ : "=l" ((USItype)(w0)), \
++ "=h" ((USItype)(w1)) \
++ : "d" ((USItype)(u)), \
++ "d" ((USItype)(v)))
++
++#define __umulsidi3(u, v) \
++ ({DIunion __w; \
++ umul_ppmm (__w.s.high, __w.s.low, u, v); \
++ __w.ll; })
++
++typedef int SItype __attribute__ ((mode (SI)));
++typedef unsigned int USItype __attribute__ ((mode (SI)));
++typedef int DItype __attribute__ ((mode (DI)));
++typedef int word_type __attribute__ ((mode (__word__)));
++
++struct DIstruct {SItype high, low;};
++
++typedef union
++{
++ struct DIstruct s;
++ DItype ll;
++} DIunion;
++
++DItype
++__muldi3 (DItype u, DItype v)
++{
++ DIunion w;
++ DIunion uu, vv;
++
++ uu.ll = u,
++ vv.ll = v;
++
++ w.ll = __umulsidi3 (uu.s.low, vv.s.low);
++ w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
++ + (USItype) uu.s.high * (USItype) vv.s.low);
++
++ return w.ll;
++}
+diff -Nur linux.old/fs/cifs/cifsfs.c linux.dev/fs/cifs/cifsfs.c
+--- linux.old/fs/cifs/cifsfs.c 2005-10-24 13:48:27.599659000 +0200
++++ linux.dev/fs/cifs/cifsfs.c 2005-10-24 14:25:06.526447000 +0200
+@@ -50,8 +50,6 @@
+ static struct quotactl_ops cifs_quotactl_ops;
+ #endif
+
+-extern struct file_system_type cifs_fs_type;
+-
+ int cifsFYI = 0;
+ int cifsERROR = 1;
+ int traceSMB = 0;
+diff -Nur linux.old/include/asm-mips/uaccess.h linux.dev/include/asm-mips/uaccess.h
+--- linux.old/include/asm-mips/uaccess.h 2005-01-19 15:10:12.000000000 +0100
++++ linux.dev/include/asm-mips/uaccess.h 2005-10-24 14:11:48.563214250 +0200
+@@ -149,7 +149,7 @@
+ * Returns zero on success, or -EFAULT on error.
+ */
+ #define put_user(x,ptr) \
+- __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
++ __put_user_check((x),(ptr),sizeof(*(ptr)))
+
+ /*
+ * get_user: - Get a simple variable from user space.
+@@ -169,7 +169,7 @@
+ * On error, the variable @x is set to zero.
+ */
+ #define get_user(x,ptr) \
+- __get_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
++ __get_user_check((x),(ptr),sizeof(*(ptr)))
+
+ /*
+ * __put_user: - Write a simple value into user space, with less checking.
+@@ -191,7 +191,7 @@
+ * Returns zero on success, or -EFAULT on error.
+ */
+ #define __put_user(x,ptr) \
+- __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
++ __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
+
+ /*
+ * __get_user: - Get a simple variable from user space, with less checking.
+@@ -214,7 +214,7 @@
+ * On error, the variable @x is set to zero.
+ */
+ #define __get_user(x,ptr) \
+- __get_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
++ __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+
+ struct __large_struct { unsigned long buf[100]; };
+ #define __m(x) (*(struct __large_struct *)(x))
+@@ -232,7 +232,7 @@
+ #define __get_user_nocheck(x,ptr,size) \
+ ({ \
+ long __gu_err = 0; \
+- __typeof(*(ptr)) __gu_val = 0; \
++ __typeof(*(ptr)) __gu_val = (__typeof(*(ptr))) 0; \
+ long __gu_addr; \
+ __gu_addr = (long) (ptr); \
+ switch (size) { \
diff --git a/target/linux/generic-2.4/patches/200-i4l.patch b/target/linux/generic-2.4/patches/200-i4l.patch
new file mode 100644
index 0000000..c9833e2
--- /dev/null
+++ b/target/linux/generic-2.4/patches/200-i4l.patch
@@ -0,0 +1,20247 @@
+diff -rNu linux-2.4.29.old/Documentation/isdn/CREDITS linux-2.4.29/Documentation/isdn/CREDITS
+--- linux-2.4.29.old/Documentation/isdn/CREDITS 2005-03-22 14:48:26.000000000 +0100
++++ linux-2.4.29/Documentation/isdn/CREDITS 2005-03-22 15:06:50.246454160 +0100
+@@ -37,7 +37,7 @@
+ Andreas Kool (akool@Kool.f.EUnet.de)
+ For contribution of the isdnlog/isdnrep-tool
+
+-Pedro Roque Marques (pedro_m@yahoo.com)
++Pedro Roque Marques (roque@di.fc.ul.pt)
+ For lot of new ideas and the pcbit driver.
+
+ Eberhard Moenkeberg (emoenke@gwdg.de)
+diff -rNu linux-2.4.29.old/Documentation/isdn/HiSax.cert linux-2.4.29/Documentation/isdn/HiSax.cert
+--- linux-2.4.29.old/Documentation/isdn/HiSax.cert 2005-03-22 14:48:26.000000000 +0100
++++ linux-2.4.29/Documentation/isdn/HiSax.cert 2005-03-22 15:06:50.264451424 +0100
+@@ -68,6 +68,8 @@
+ drivers/isdn/hisax/elsa.c
+ drivers/isdn/hisax/diva.c
+ drivers/isdn/hisax/hfc_pci.c
++drivers/isdn/hisax/hfc_usbr.c
++drivers/isdn/hisax/hfc_usb.c
+
+ Please send any changes, bugfixes and patches to me rather than implementing
+ them directly into the HiSax sources.
+diff -rNu linux-2.4.29.old/Documentation/isdn/INTERFACE linux-2.4.29/Documentation/isdn/INTERFACE
+--- linux-2.4.29.old/Documentation/isdn/INTERFACE 2005-03-22 14:48:26.000000000 +0100
++++ linux-2.4.29/Documentation/isdn/INTERFACE 2005-03-22 15:06:50.288447776 +0100
+@@ -1,4 +1,4 @@
+-$Id: INTERFACE,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
++$Id: INTERFACE,v 1.17 2002/01/31 13:26:35 keil Exp $
+
+ Description of the Interface between Linklevel and Hardwarelevel
+ of isdn4linux:
+@@ -399,7 +399,7 @@
+ protocol-Id is one of the constants ISDN_PROTO_L3...
+ parm.fax = Pointer to T30_s fax struct. (fax usage only)
+
+- ISDN_CMD_GETL2: (currently unused)
++ ISDN_CMD_GETL3: (currently unused)
+
+ With this command, the HL-driver is told to return the current
+ setting of the Layer-3-protocol.
+@@ -781,3 +781,22 @@
+ arg = channel-number, locally to the driver. (starting with 0)
+ parm = unused.
+
++ ISDN_STAT_ALERT:
++
++ With this call, the HL-driver signals the receive of an ALERTING message to the LL.
++
++ Parameter:
++ driver = driver-Id
++ command = ISDN_STAT_ALERT
++ arg = channel-number, locally to the driver. (starting with 0)
++
++ ISDN_STAT_PROCEED:
++
++ With this call, the HL-driver signals the receive of an CALL PROCEEDING message
++ to the LL.
++
++ Parameter:
++ driver = driver-Id
++ command = ISDN_STAT_PROCEED
++ arg = channel-number, locally to the driver. (starting with 0)
++
+diff -rNu linux-2.4.29.old/Documentation/isdn/INTERFACE.fax linux-2.4.29/Documentation/isdn/INTERFACE.fax
+--- linux-2.4.29.old/Documentation/isdn/INTERFACE.fax 2005-03-22 14:48:26.000000000 +0100
++++ linux-2.4.29/Documentation/isdn/INTERFACE.fax 2005-03-22 15:06:50.312444128 +0100
+@@ -1,4 +1,4 @@
+-$Id: INTERFACE.fax,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
++$Id: INTERFACE.fax,v 1.2 2000/08/06 09:22:50 armin Exp $
+
+
+ Description of the fax-subinterface between linklevel and hardwarelevel of
+diff -rNu linux-2.4.29.old/Documentation/isdn/README linux-2.4.29/Documentation/isdn/README
+--- linux-2.4.29.old/Documentation/isdn/README 2005-03-22 14:48:26.000000000 +0100
++++ linux-2.4.29/Documentation/isdn/README 2005-03-22 15:06:50.340439872 +0100
+@@ -278,6 +278,12 @@
+ 1 = Add CPN to FCON message on
+ Bit 2: 0 = Add CDN to RING/FCON message off
+ 1 = Add CDN to RING/FCON message on
++ Bit 3: 0 = Do not signal RINGING
++ 1 = Signal RINGING if ALERT was received
++ Bit 4: 0 = Do not signal PROCEEDING
++ 1 = Signal PROCEEDING if CALL PROCEEDING
++ was received
++
+
+ Last but not least a (at the moment fairly primitive) device to request
+ the line-status (/dev/isdninfo) is made available.
+diff -rNu linux-2.4.29.old/Documentation/isdn/README.HiSax linux-2.4.29/Documentation/isdn/README.HiSax
+--- linux-2.4.29.old/Documentation/isdn/README.HiSax 2005-03-22 14:48:26.000000000 +0100
++++ linux-2.4.29/Documentation/isdn/README.HiSax 2005-03-22 15:06:50.372435008 +0100
+@@ -41,10 +41,9 @@
+ ELSA Quickstep 3000PCI
+ ELSA PCMCIA
+ ITK ix1-micro Rev.2
+-Eicon Diva 2.0 ISA and PCI (S0 and U interface, no PRO version)
+-Eicon Diva 2.01 ISA and PCI
+-Eicon Diva 2.02 PCI
+-Eicon Diva Piccola
++Eicon.Diehl Diva 2.0 ISA and PCI (S0 and U interface, no PRO version)
++Eicon.Diehl Diva 2.01 ISA and PCI
++Eicon.Diehl Diva Piccola
+ ASUSCOM NETWORK INC. ISDNLink 128K PC adapter (order code I-IN100-ST-D)
+ Dynalink IS64PH (OEM version of ASUSCOM NETWORK INC. ISDNLink 128K adapter)
+ PCBIT-DP (OEM version of ASUSCOM NETWORK INC. ISDNLink)
+@@ -53,7 +52,6 @@
+ Sedlbauer Speed Star/Speed Star2 (PCMCIA)
+ Sedlbauer ISDN-Controller PC/104
+ USR Sportster internal TA (compatible Stollmann tina-pp V3)
+-USR internal TA PCI
+ ith Kommunikationstechnik GmbH MIC 16 ISA card
+ Traverse Technologie NETjet PCI S0 card and NETspider U card
+ Ovislink ISDN sc100-p card (NETjet driver)
+@@ -68,14 +66,14 @@
+ HFC-PCI based cards
+ Winbond W6692 based cards
+ HFC-S+, HFC-SP/PCMCIA cards
+-formula-n enternow
+-Gerdes Power ISDN
++HFC-USB ISDN TAs
+
+ Note: PCF, PCF-Pro: up to now, only the ISDN part is supported
+ PCC-8: not tested yet
+ Eicon.Diehl Diva U interface not tested
+
+ If you know other passive cards with the Siemens chipset, please let me know.
++To use the PNP cards you need the isapnptools.
+ You can combine any card, if there is no conflict between the resources
+ (io, mem, irq).
+
+@@ -91,15 +89,8 @@
+ modules. It is included in the normal "make [menu]config" target at the
+ kernel. Don't forget it, especially to select the right D-channel protocol.
+
+-Please note: In older versions of the HiSax driver, all PnP cards
+-needed to be configured with isapnp and worked only with the HiSax
+-driver used as a module.
+-
+-In the current version, HiSax will automatically use the in-kernel
+-ISAPnP support, provided you selected it during kernel configuration
+-(CONFIG_ISAPNP), if you don't give the io=, irq= command line parameters.
+-
+-The affected card types are: 4,7,12,14,19,27-30
++Please note: All PnP cards need to be configured with isapnp and will work
++only with the HiSax driver used as a module.
+
+ a) when built as a module
+ -------------------------
+@@ -200,8 +191,6 @@
+ 37 HFC 2BDS0 S+, SP irq,io
+ 38 NETspider U PCI card none
+ 39 HFC 2BDS0 SP/PCMCIA irq,io (set with cardmgr)
+- 40 hotplug interface
+- 41 Formula-n enter:now PCI none
+
+ At the moment IRQ sharing is only possible with PCI cards. Please make sure
+ that your IRQ is free and enabled for ISA use.
+@@ -227,13 +216,6 @@
+ (IO 1 (BASE 0x0180))
+ modprobe hisax type=4 protocol=2 irq=10 io0=0x580 io1=0x180
+
+- In the current version of HiSax, you can instead simply use
+-
+- modprobe hisax type=4 protocol=2
+-
+- if you configured your kernel for ISAPnP. Don't run isapnp in
+- this case!
+-
+ 6. Teles 16.3, Euro ISDN, I/O base 280 hex, IRQ 12 and
+ Teles 16.0, 1TR6, IRQ 5, Memory d0000 hex
+ modprobe hisax type=3,1 protocol=2,1 io=0x280 mem=0,0xd0000
+@@ -314,9 +296,7 @@
+ 36 W6692 based PCI cards none
+ 37 HFC 2BDS0 S+,SP/PCMCIA ONLY WORKS AS A MODULE !
+ 38 NETspider U PCI card none
+- 39 HFC 2BDS0 SP/PCMCIA ONLY WORKS AS A MODULE !
+- 40 hotplug interface ONLY WORKS AS A MODULE !
+- 41 Formula-n enter:now PCI none
++
+
+ Running the driver
+ ------------------
+diff -rNu linux-2.4.29.old/Documentation/isdn/README.act2000 linux-2.4.29/Documentation/isdn/README.act2000
+--- linux-2.4.29.old/Documentation/isdn/README.act2000 2005-03-22 14:48:26.000000000 +0100
++++ linux-2.4.29/Documentation/isdn/README.act2000 2005-03-22 15:06:50.388432576 +0100
+@@ -1,4 +1,4 @@
+-$Id: README.act2000,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
++$Id: README.act2000,v 1.3 2000/08/06 09:22:51 armin Exp $
+
+ This document describes the ACT2000 driver for the
+ IBM Active 2000 ISDN card.
+diff -rNu linux-2.4.29.old/Documentation/isdn/README.audio linux-2.4.29/Documentation/isdn/README.audio
+--- linux-2.4.29.old/Documentation/isdn/README.audio 2005-03-22 14:48:26.000000000 +0100
++++ linux-2.4.29/Documentation/isdn/README.audio 2005-03-22 15:06:50.404430144 +0100
+@@ -1,4 +1,4 @@
+-$Id: README.audio,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
++$Id: README.audio,v 1.8 1999/07/11 17:17:29 armin Exp $
+
+ ISDN subsystem for Linux.
+ Description of audio mode.
+diff -rNu linux-2.4.29.old/Documentation/isdn/README.eicon linux-2.4.29/Documentation/isdn/README.eicon
+--- linux-2.4.29.old/Documentation/isdn/README.eicon 2005-03-22 14:48:26.000000000 +0100
++++ linux-2.4.29/Documentation/isdn/README.eicon 2005-03-22 15:06:50.479418744 +0100
+@@ -1,4 +1,4 @@
+-$Id: README.eicon,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
++$Id: README.eicon,v 1.10 2000/08/13 12:19:15 armin Exp $
+
+ (c) 1999,2000 Armin Schindler (mac@melware.de)
+ (c) 1999,2000 Cytronics & Melware (info@melware.de)
+diff -rNu linux-2.4.29.old/Documentation/isdn/README.hysdn linux-2.4.29/Documentation/isdn/README.hysdn
+--- linux-2.4.29.old/Documentation/isdn/README.hysdn 2005-03-22 14:48:26.000000000 +0100
++++ linux-2.4.29/Documentation/isdn/README.hysdn 2005-03-22 15:06:50.522412208 +0100
+@@ -1,4 +1,4 @@
+-$Id: README.hysdn,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
++$Id: README.hysdn,v 1.3.6.1 2001/02/10 14:41:19 kai Exp $
+ The hysdn driver has been written by
+ by Werner Cornelius (werner@isdn4linux.de or werner@titro.de)
+ for Hypercope GmbH Aachen Germany. Hypercope agreed to publish this driver
+diff -rNu linux-2.4.29.old/Documentation/isdn/README.icn linux-2.4.29/Documentation/isdn/README.icn
+--- linux-2.4.29.old/Documentation/isdn/README.icn 2005-03-22 14:48:26.000000000 +0100
++++ linux-2.4.29/Documentation/isdn/README.icn 2005-03-22 15:06:50.550407952 +0100
+@@ -1,4 +1,4 @@
+-$Id: README.icn,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
++$Id: README.icn,v 1.7 2000/08/06 09:22:51 armin Exp $
+
+ You can get the ICN-ISDN-card from:
+
+diff -rNu linux-2.4.29.old/Documentation/isdn/README.pcbit linux-2.4.29/Documentation/isdn/README.pcbit
+--- linux-2.4.29.old/Documentation/isdn/README.pcbit 2005-03-22 14:48:26.000000000 +0100
++++ linux-2.4.29/Documentation/isdn/README.pcbit 2005-03-22 15:06:50.567405368 +0100
+@@ -37,4 +37,4 @@
+ regards,
+ Pedro.
+
+-<pedro_m@yahoo.com>
++<roque@di.fc.ul.pt>
+diff -rNu linux-2.4.29.old/Documentation/isdn/abcext_kernel.help linux-2.4.29/Documentation/isdn/abcext_kernel.help
+--- linux-2.4.29.old/Documentation/isdn/abcext_kernel.help 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/Documentation/isdn/abcext_kernel.help 2005-03-22 15:06:50.600400352 +0100
+@@ -0,0 +1,166 @@
++
++ISDN-ABC-DW Extension
++CONFIG_ISDN_WITH_ABC
++ These are many brand new Options and Features for the
++ ISDN SUBSYSTEM. Including Logical Device bindings,
++ Compression and other good stuff for Optimizing your
++ ISDN System.
++
++ To Use this Extensions you MUST HAVE THE NEWEST
++ ISDN4K-UTILS. You must have Version 3.1-Beta6 or
++ higher. Elsewhere you can not configure this Extensions.
++
++ WARNING ! THIS STUF IS NOT PRODUCTION RELEASE THE
++ FUNCTION ARE UNDER DEVELOPMENT. This ist BETA-CODE.
++ You can use it at you Own Risk.
++
++ For more Information on these Extensions take a look at
++ "linux/Documentation/isdn/dw-abc-extension-howto.txt or
++ Online at the Web "http://www.mediatronix.de/i4l/index.html"
++
++ Please Report Bugs to "mario@mediatronix.de" or
++ "delefw@isdn4linux.de"
++
++D-Channel-Callback with Channel in use check
++CONFIG_ISDN_WITH_ABC_CALLB
++ When a Interface is declared as an Callback Interface,
++ the Interface is checking that the other Side is not
++ Calling on the same time before the Interface is Dialing.
++
++ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
++ for more Information
++
++ In most case answer with "Yes" when you have Callback devices,
++ otherwise leave it "No"
++
++Outgoing-EAZ-Support
++CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++ Enables the Feature to Define an other EAZ or MSN for
++ Outgoing calls on an Interface.
++
++ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
++ for more Information
++
++Least Cost Router Support
++CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++ This is the final Kernel Code for configuring an Least
++ Cost Router Softwarebased. The other Job is to do the
++ action in ISDNLOG. You need the ISDNLOG to use this
++ function. Currently the ISDNLOG have not the Support for
++ this Option.
++ So in most situations let the Option off.
++
++TCP keepalive detect and response
++CONFIG_ISDN_WITH_ABC_IPV4_TCP_KEEPALIVE
++ This Option works only with the TCP/IP V4. It enables
++ the Function that ISDN Devices are Answering TCP_KEEPALIVE Pakets
++ localy. So that TCP KEEPALIVE Pakets not longer takes the Line
++ open.
++
++Drop frames Sourceadresse is not Interfaceadress
++CONFIG_ISDN_WITH_ABC_IPV4_DYNADDR
++ This Option works only with the TCP/IP V4. It will allow only
++ the Transmitt of Pakets where the Sourceadresse is the Interface
++ adress. It is usefull when you have Lines with Dynamic IP.
++
++ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
++ for more Information
++
++Receive do not reset the Hanguptimer
++CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
++ When you activate this option than the reiceive of pakets do
++ not reset the Hanguptimer. It is very usefull because if the
++ Paket vor your Network your Network generate an Response and
++ the Transmit is reseting the HUPTIMER. But when the Paket is
++ Rejected at your firewall your network generate no Response
++ and no Sendtraffic is generated. So in this case there is no
++ need to Reset the Huptimer because you have only received Data.
++ With that option only Transmitted Data/Pakets will reset the
++ HUPTIMER.
++
++Support of (device-channel) and Binding Groups
++CONFIG_ISDN_WITH_ABC_ICALL_BIND
++ This Option enables the Feature to Bind logical ISDN Interfaces
++ to an prefered ISDN Card or ISDN Card plus Channel. So you have
++ the Chance to keep Channels exclusively for one (or more)
++ Connection. Very usefull when you have more channels and Use
++ Calling Line Identification, because you can organize that your
++ call is going out over the Line with the right EAZ for the CLI.
++
++Skip channel if used external (Dial Only)
++CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
++ When you have more than One ISDN Card in your System and you
++ will Dialout with an Interface you can become the Situation
++ that an External Device such a Telephone or Fax is Using the
++ B-Channels. Normaly ISDN4Linux does not detect this Situation
++ and dial everytime of the "External Busy" line out. With this
++ Option Enabled the I4L will detect that he can not dialout on
++ This Card and dial over the next Card out.
++
++ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
++ for more Information
++
++Interface autodisable if Config error
++CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ This Option will detect an Device which generate Telephone
++ Cost but does not Function correctly because there are
++ Configerrors on one of the Site. In this Situation the
++ Interface will be marked as Unsuably for some time to do
++ not call every time this Site.
++
++ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
++ for more Information
++
++UDP-Info-Support
++CONFIG_ISDN_WITH_ABC_UDP_CHECK
++ This is the Mainoption to Enable or Disable the UDP
++ Info Support. An Option to Controll ISDN-Interfaces
++ Remotely. For this very Complex thing take a look at
++
++ "linux/Documentation/isdn/dw-abc-extension-howto.txt"
++ for more Information.
++
++UDP Hangup Support
++CONFIG_ISDN_WITH_ABC_UDP_CHECK_HANGUP
++
++ Sorry no more Information!
++
++ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
++ for more Information
++
++UDP Dial Support
++CONFIG_ISDN_WITH_ABC_UDP_CHECK_DIAL
++
++ Sorry no more Information!
++
++ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
++ for more Information
++
++Limit on the line frames to two
++CONFIG_ISDN_WITH_ABC_FRAME_LIMIT
++
++ This Option enables support for sending only 2 Pakets on
++ the Fly to the ISDN Driver. It is very usefull when you
++ will use the new RAW-IP Compression. Because of sending
++ Only 2 Pakets on the Fly makes the risk of overflowing
++ the ISDN Driver very smaller.
++
++ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
++ for more Information
++
++Compression with RAWIP and X75I
++CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS
++
++ With this Option you have the ability to make Datacompression
++ on RAW-IP Lines. It is function on HDLC and X75I Connection,
++ but the Prefered L2-Protocol for Compression is X75I because
++ the HDLC Protocol have no Errorcorrection.
++
++ To Use this Option YOU MUST HAVE ENABLED THE OPTION:
++ Support synchronous PPP
++ and must load after loading the main isdndrivers the
++ Modul "isdn_bsdcomp".
++
++ See "linux/Documentation/isdn/dw-abc-extension-howto.txt"
++ for more Information
++
+diff -rNu linux-2.4.29.old/drivers/isdn/Config.in linux-2.4.29/drivers/isdn/Config.in
+--- linux-2.4.29.old/drivers/isdn/Config.in 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/Config.in 2005-03-22 15:06:44.259364336 +0100
+@@ -4,11 +4,9 @@
+
+ # only included if CONFIG_ISDN != n
+
+-define_bool CONFIG_ISDN_BOOL y
+ if [ "$CONFIG_INET" != "n" ]; then
+ bool ' Support synchronous PPP' CONFIG_ISDN_PPP
+ if [ "$CONFIG_ISDN_PPP" != "n" ]; then
+- dep_bool ' PPP filtering for ISDN' CONFIG_IPPP_FILTER $CONFIG_FILTER
+ bool ' Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
+ bool ' Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
+ dep_tristate ' Support BSD compression' CONFIG_ISDN_PPP_BSDCOMP $CONFIG_ISDN
+@@ -23,6 +21,30 @@
+ fi
+
+ mainmenu_option next_comment
++comment 'ISDN abc-dw-extension'
++bool 'Enable isdn-abc-dw-extension' CONFIG_ISDN_WITH_ABC
++if [ "$CONFIG_ISDN_WITH_ABC" != "n" ]; then
++ bool ' Use D-Channel-Callback with Channel in use check' CONFIG_ISDN_WITH_ABC_CALLB
++ bool ' Enable Outgoing-EAZ-Support' CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++ bool ' Enable LCR-Support (need isdnlog)' CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++ bool ' RX dont reset hanguptimeout' CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
++ if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
++ bool ' Enable UDP-Info-Support' CONFIG_ISDN_WITH_ABC_UDP_CHECK
++ if [ "$CONFIG_ISDN_WITH_ABC_UDP_CHECK" != "n" ]; then
++ bool ' Enable Hangup-Support with UDP-INFO' CONFIG_ISDN_WITH_ABC_UDP_CHECK_HANGUP
++ bool ' Enable Dial-Support with UDP-INFO' CONFIG_ISDN_WITH_ABC_UDP_CHECK_DIAL
++ fi
++ fi
++
++ bool ' Skip channel if used external (dial only)' CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
++ bool ' Support interface-auto-disable if config-error' CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ if [ "$CONFIG_ISDN_PPP" != "n" ]; then
++ bool ' Enable Compression with rawip and x75i' CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS
++ fi
++fi
++endmenu
++
++mainmenu_option next_comment
+ comment 'ISDN feature submodules'
+ dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
+ dep_tristate 'Support isdn diversion services' CONFIG_ISDN_DIVERSION $CONFIG_ISDN
+@@ -34,7 +56,6 @@
+ comment 'Passive ISDN cards'
+ dep_tristate 'HiSax SiemensChipSet driver support' CONFIG_ISDN_DRV_HISAX $CONFIG_ISDN
+ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then
+- define_bool CONFIG_ISDN_HISAX y
+ comment ' D-channel protocol features'
+ bool ' HiSax Support for EURO/DSS1' CONFIG_HISAX_EURO
+ if [ "$CONFIG_HISAX_EURO" != "n" ]; then
+@@ -45,31 +66,28 @@
+ fi
+ bool ' HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
+ bool ' HiSax Support for US NI1' CONFIG_HISAX_NI1
+- int ' Maximum number of cards supported by HiSax' CONFIG_HISAX_MAX_CARDS 8
+ comment ' HiSax supported cards'
+- if [ "$CONFIG_ISA" != "n" ]; then
+- bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0
+- bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+- bool ' AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
+- bool ' ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
+- bool ' ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM
+- bool ' TELEINT cards' CONFIG_HISAX_TELEINT
+- bool ' HFC-S based cards' CONFIG_HISAX_HFCS
+- bool ' USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
+- bool ' MIC card' CONFIG_HISAX_MIC
+- bool ' Siemens I-Surf card' CONFIG_HISAX_ISURF
+- bool ' HST Saphir card' CONFIG_HISAX_HSTSAPHIR
+- fi
++ bool ' Teles 16.0/8.0' CONFIG_HISAX_16_0
++ bool ' Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
+ bool ' Teles PCI' CONFIG_HISAX_TELESPCI
+ bool ' Teles S0Box' CONFIG_HISAX_S0BOX
++ bool ' AVM A1 (Fritz)' CONFIG_HISAX_AVM_A1
+ bool ' AVM PnP/PCI (Fritz!PnP/PCI)' CONFIG_HISAX_FRITZPCI
+ bool ' AVM A1 PCMCIA (Fritz)' CONFIG_HISAX_AVM_A1_PCMCIA
+ bool ' Elsa cards' CONFIG_HISAX_ELSA
++ bool ' ITK ix1-micro Revision 2' CONFIG_HISAX_IX1MICROR2
+ bool ' Eicon.Diehl Diva cards' CONFIG_HISAX_DIEHLDIVA
++ bool ' ASUSCOM ISA cards' CONFIG_HISAX_ASUSCOM
++ bool ' TELEINT cards' CONFIG_HISAX_TELEINT
++ bool ' HFC-S based cards' CONFIG_HISAX_HFCS
+ bool ' Sedlbauer cards' CONFIG_HISAX_SEDLBAUER
++ bool ' USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
++ bool ' MIC card' CONFIG_HISAX_MIC
+ bool ' NETjet card' CONFIG_HISAX_NETJET
+ bool ' NETspider U card' CONFIG_HISAX_NETJET_U
+ bool ' Niccy PnP/PCI card' CONFIG_HISAX_NICCY
++ bool ' Siemens I-Surf card' CONFIG_HISAX_ISURF
++ bool ' HST Saphir card' CONFIG_HISAX_HSTSAPHIR
+ bool ' Telekom A4T card' CONFIG_HISAX_BKM_A4T
+ bool ' Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO
+ bool ' Gazel cards' CONFIG_HISAX_GAZEL
+@@ -78,20 +96,27 @@
+ bool ' HFC-S+, HFC-SP, HFC-PCMCIA cards' CONFIG_HISAX_HFC_SX
+ if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+ # bool ' TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
+- bool ' Formula-n enter:now PCI card' CONFIG_HISAX_ENTERNOW_PCI
+ if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
+ bool ' Am7930' CONFIG_HISAX_AMD7930
+ fi
+ fi
+ bool ' HiSax debugging' CONFIG_HISAX_DEBUG
+
+- dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA
+- dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA
+- dep_tristate 'AVM A1 PCMCIA cards' CONFIG_HISAX_AVM_A1_CS $CONFIG_ISDN_DRV_HISAX $CONFIG_PCMCIA $CONFIG_HISAX_AVM_A1_PCMCIA
+- dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_ISDN_DRV_HISAX $CONFIG_EXPERIMENTAL
+- dep_tristate 'AVM Fritz!Card PCI/PCIv2/PnP support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_ISDN_DRV_HISAX $CONFIG_EXPERIMENTAL
+- dep_tristate 'Auerswald devices ISDN support' CONFIG_USB_AUERISDN $CONFIG_ISDN_DRV_HISAX
++ dep_tristate 'Sedlbauer PCMCIA cards' CONFIG_HISAX_SEDLBAUER_CS $CONFIG_PCMCIA
++ dep_tristate 'ELSA PCMCIA MicroLink cards' CONFIG_HISAX_ELSA_CS $CONFIG_PCMCIA
++ dep_tristate 'Colognechip HFC-USB support' CONFIG_HISAX_HFC_USB_CS $CONFIG_HISAX $CONFIG_USB
++ dep_tristate 'ST5481 USB ISDN modem (EXPERIMENTAL)' CONFIG_HISAX_ST5481 $CONFIG_HISAX $CONFIG_USB $CONFIG_EXPERIMENTAL
++ dep_tristate 'Fritz!PCIv2 support (EXPERIMENTAL)' CONFIG_HISAX_FRITZ_PCIPNP $CONFIG_HISAX $CONFIG_EXPERIMENTAL
+
++ if [ "$CONFIG_HISAX_SEDLBAUER_CS" != "n" ]; then
++ define_bool CONFIG_HISAX_SEDLBAUER y
++ fi
++ if [ "$CONFIG_HISAX_ELSA_CS" != "n" ]; then
++ define_bool CONFIG_HISAX_ELSA y
++ fi
++ if [ "$CONFIG_HISAX_HFC_USB_CS" != "n" ]; then
++ define_bool CONFIG_HISAX_HFC_USB y
++ fi
+ fi
+ endmenu
+
+diff -rNu linux-2.4.29.old/drivers/isdn/Makefile linux-2.4.29/drivers/isdn/Makefile
+--- linux-2.4.29.old/drivers/isdn/Makefile 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/Makefile 2005-03-22 15:06:44.277361600 +0100
+@@ -2,7 +2,7 @@
+
+ # The target object and module list name.
+
+-O_TARGET := vmlinux-obj.o
++O_TARGET := isdn.a
+
+ # Objects that export symbols.
+
+@@ -32,9 +32,9 @@
+
+ # Object files in subdirectories
+
+-mod-subdirs := avmb1 eicon hisax
++mod-subdirs := avmb1 eicon
+ subdir-$(CONFIG_ISDN_DIVERSION) += divert
+-subdir-$(CONFIG_ISDN_HISAX) += hisax
++subdir-$(CONFIG_ISDN_DRV_HISAX) += hisax
+ subdir-$(CONFIG_ISDN_DRV_ICN) += icn
+ subdir-$(CONFIG_ISDN_DRV_PCBIT) += pcbit
+ subdir-$(CONFIG_ISDN_DRV_SC) += sc
+diff -rNu linux-2.4.29.old/drivers/isdn/act2000/act2000.h linux-2.4.29/drivers/isdn/act2000/act2000.h
+--- linux-2.4.29.old/drivers/isdn/act2000/act2000.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/act2000/act2000.h 2005-03-22 15:06:44.103388048 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: act2000.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id$
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ *
+@@ -178,19 +178,19 @@
+ char regname[35]; /* Name used for request_region */
+ } act2000_card;
+
+-static inline void act2000_schedule_tx(act2000_card *card)
++extern __inline__ void act2000_schedule_tx(act2000_card *card)
+ {
+ queue_task(&card->snd_tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+
+-static inline void act2000_schedule_rx(act2000_card *card)
++extern __inline__ void act2000_schedule_rx(act2000_card *card)
+ {
+ queue_task(&card->rcv_tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+
+-static inline void act2000_schedule_poll(act2000_card *card)
++extern __inline__ void act2000_schedule_poll(act2000_card *card)
+ {
+ queue_task(&card->poll_tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+diff -rNu linux-2.4.29.old/drivers/isdn/act2000/act2000_isa.c linux-2.4.29/drivers/isdn/act2000/act2000_isa.c
+--- linux-2.4.29.old/drivers/isdn/act2000/act2000_isa.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/act2000/act2000_isa.c 2005-03-22 15:06:44.135383184 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: act2000_isa.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id$
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
+ *
+@@ -178,8 +178,7 @@
+ card->flags &= ~ACT2000_FLAGS_PVALID;
+ }
+ if (!check_region(portbase, ISA_REGION)) {
+- if (request_region(portbase, ACT2000_PORTLEN, card->regname) == NULL)
+- return -EIO;
++ request_region(portbase, ACT2000_PORTLEN, card->regname);
+ card->port = portbase;
+ card->flags |= ACT2000_FLAGS_PVALID;
+ return 0;
+@@ -341,6 +340,9 @@
+ while (skb->len) {
+ if (act2000_isa_writeb(card, *(skb->data))) {
+ /* Fifo is full, but more data to send */
++#if 0
++ printk(KERN_DEBUG "act2000_isa_send: %d bytes\n", l);
++#endif
+ test_and_clear_bit(ACT2000_LOCK_TX, (void *) &card->ilock);
+ /* Schedule myself */
+ act2000_schedule_tx(card);
+@@ -363,6 +365,9 @@
+ } else
+ dev_kfree_skb(skb);
+ card->sbuf = NULL;
++#if 0
++ printk(KERN_DEBUG "act2000_isa_send: %d bytes\n", l);
++#endif
+ }
+ }
+
+diff -rNu linux-2.4.29.old/drivers/isdn/act2000/act2000_isa.h linux-2.4.29/drivers/isdn/act2000/act2000_isa.h
+--- linux-2.4.29.old/drivers/isdn/act2000/act2000_isa.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/act2000/act2000_isa.h 2005-03-22 15:06:44.152380600 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: act2000_isa.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id$
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/act2000/capi.c linux-2.4.29/drivers/isdn/act2000/capi.c
+--- linux-2.4.29.old/drivers/isdn/act2000/capi.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/act2000/capi.c 2005-03-22 15:06:44.172377560 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: capi.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id$
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ * CAPI encoder/decoder
+@@ -76,6 +76,10 @@
+ {{ 0x84, 0x03}, "DISCONNECT_B3_RESP"},
+ {{ 0x86, 0x03}, "DATA_B3_RESP"},
+ {{ 0xff, 0x03}, "MANUFACTURER_RESP"},
++#if 0
++/* CAPI 2.0 */
++ {{ 0x05, 0x80}, "LISTEN_REQ (CAPI 2.0)"},
++#endif
+ #endif
+ {{ 0x00, 0x00}, NULL},
+ };
+diff -rNu linux-2.4.29.old/drivers/isdn/act2000/capi.h linux-2.4.29/drivers/isdn/act2000/capi.h
+--- linux-2.4.29.old/drivers/isdn/act2000/capi.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/act2000/capi.h 2005-03-22 15:06:44.187375280 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: capi.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id$
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ *
+@@ -294,6 +294,19 @@
+ __u16 plci;
+ __u16 info;
+ } select_b3_protocol_conf;
++#if 0
++ struct listen_req {
++ __u32 controller;
++ __u32 infomask;
++ __u32 cipmask;
++ __u32 cipmask2;
++ __u16 dummy; /* 2 Length-bytes of 2 Structs MUST always be 0!!! */
++ } listen_req;
++ struct listen_conf {
++ __u32 controller;
++ __u16 info;
++ } listen_conf;
++#else
+ struct listen_req {
+ __u8 controller;
+ __u32 infomask __attribute__ ((packed));
+@@ -304,6 +317,7 @@
+ __u8 controller;
+ __u16 info __attribute__ ((packed));
+ } listen_conf;
++#endif
+ struct data_b3_req {
+ __u16 fakencci;
+ __u16 datalen;
+@@ -330,7 +344,7 @@
+ } msg;
+ } actcapi_msg;
+
+-static inline unsigned short
++extern __inline__ unsigned short
+ actcapi_nextsmsg(act2000_card *card)
+ {
+ unsigned long flags;
+diff -rNu linux-2.4.29.old/drivers/isdn/act2000/module.c linux-2.4.29/drivers/isdn/act2000/module.c
+--- linux-2.4.29.old/drivers/isdn/act2000/module.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/act2000/module.c 2005-03-22 15:06:44.202373000 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: module.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id$
+ *
+ * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
+ *
+@@ -630,6 +630,10 @@
+ card->interface.features =
+ ISDN_FEATURE_L2_X75I |
+ ISDN_FEATURE_L2_HDLC |
++#if 0
++/* Not yet! New Firmware is on the way ... */
++ ISDN_FEATURE_L2_TRANS |
++#endif
+ ISDN_FEATURE_L3_TRANS |
+ ISDN_FEATURE_P_UNKNOWN;
+ card->interface.hl_hdrlen = 20;
+@@ -843,6 +847,39 @@
+ }
+ printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
+ }
++#if 0
++#ifndef MODULE
++void
++act2000_setup(char *str, int *ints)
++{
++ int i, j, argc, port, irq, bus;
++
++ argc = ints[0];
++ i = 1;
++ if (argc)
++ while (argc) {
++ port = irq = -1;
++ bus = 0;
++ if (argc) {
++ bus = ints[i];
++ i++;
++ argc--;
++ }
++ if (argc) {
++ port = ints[i];
++ i++;
++ argc--;
++ }
++ if (argc) {
++ irq = ints[i];
++ i++;
++ argc--;
++ }
++ act2000_addcard(bus, port, irq, act_id);
++ }
++}
++#endif
++#endif
+
+ module_init(act2000_init);
+ module_exit(act2000_exit);
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/avm_cs.c linux-2.4.29/drivers/isdn/avmb1/avm_cs.c
+--- linux-2.4.29.old/drivers/isdn/avmb1/avm_cs.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/avm_cs.c 2005-03-22 15:06:44.696297912 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: avm_cs.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: avm_cs.c,v 1.6 2001/09/24 13:22:44 kai Exp $
+ *
+ * A PCMCIA client driver for AVM B1/M1/M2
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/avmcard.h linux-2.4.29/drivers/isdn/avmb1/avmcard.h
+--- linux-2.4.29.old/drivers/isdn/avmb1/avmcard.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/avmcard.h 2005-03-22 15:06:44.711295632 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: avmcard.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: avmcard.h,v 1.12 2001/09/24 13:22:44 kai Exp $
+ *
+ * Copyright 1999 by Carsten Paeth <calle@calle.de>
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/b1.c linux-2.4.29/drivers/isdn/avmb1/b1.c
+--- linux-2.4.29.old/drivers/isdn/avmb1/b1.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/b1.c 2005-03-22 15:06:44.733292288 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: b1.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: b1.c,v 1.26 2001/09/24 13:22:44 kai Exp $
+ *
+ * Common module for AVM B1 cards.
+ *
+@@ -20,6 +20,7 @@
+ #include <linux/kernelcapi.h>
+ #include <asm/io.h>
+ #include <linux/init.h>
++#include <linux/isdn_compat.h>
+ #include <asm/uaccess.h>
+ #include <linux/netdevice.h>
+ #include "capilli.h"
+@@ -27,7 +28,7 @@
+ #include "capicmd.h"
+ #include "capiutil.h"
+
+-static char *revision = "$Revision: 1.1.4.1 $";
++static char *revision = "$Revision: 1.26 $";
+
+ /* ------------------------------------------------------------- */
+
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/b1dma.c linux-2.4.29/drivers/isdn/avmb1/b1dma.c
+--- linux-2.4.29.old/drivers/isdn/avmb1/b1dma.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/b1dma.c 2005-03-22 15:06:44.750289704 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: b1dma.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: b1dma.c,v 1.18 2001/09/24 13:22:44 kai Exp $
+ *
+ * Common module for AVM B1 cards that support dma with AMCC
+ *
+@@ -21,6 +21,7 @@
+ #include <linux/kernelcapi.h>
+ #include <asm/io.h>
+ #include <linux/init.h>
++#include <linux/isdn_compat.h>
+ #include <asm/uaccess.h>
+ #include <linux/netdevice.h>
+ #include "capilli.h"
+@@ -28,7 +29,11 @@
+ #include "capicmd.h"
+ #include "capiutil.h"
+
+-static char *revision = "$Revision: 1.1.4.1 $";
++#if BITS_PER_LONG != 32
++#error FIXME: driver requires 32-bit platform
++#endif
++
++static char *revision = "$Revision: 1.18 $";
+
+ /* ------------------------------------------------------------- */
+
+@@ -851,7 +856,7 @@
+ __u8 flag;
+ int len = 0;
+ char *s;
+- u_long txaddr, txlen, rxaddr, rxlen, csr;
++ __u32 txaddr, txlen, rxaddr, rxlen, csr;
+
+ len += sprintf(page+len, "%-16s %s\n", "name", card->name);
+ len += sprintf(page+len, "%-16s 0x%x\n", "io", card->port);
+@@ -907,12 +912,12 @@
+ save_flags(flags);
+ cli();
+
+- txaddr = (u_long)phys_to_virt(b1dmainmeml(card->mbase+0x2c));
+- txaddr -= (u_long)card->dma->sendbuf;
++ txaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x2c));
++ txaddr -= (__u32)card->dma->sendbuf;
+ txlen = b1dmainmeml(card->mbase+0x30);
+
+- rxaddr = (u_long)phys_to_virt(b1dmainmeml(card->mbase+0x24));
+- rxaddr -= (u_long)card->dma->recvbuf;
++ rxaddr = (__u32)phys_to_virt(b1dmainmeml(card->mbase+0x24));
++ rxaddr -= (__u32)card->dma->recvbuf;
+ rxlen = b1dmainmeml(card->mbase+0x28);
+
+ csr = b1dmainmeml(card->mbase+AMCC_INTCSR);
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/b1isa.c linux-2.4.29/drivers/isdn/avmb1/b1isa.c
+--- linux-2.4.29.old/drivers/isdn/avmb1/b1isa.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/b1isa.c 2005-03-22 15:06:44.766287272 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: b1isa.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: b1isa.c,v 1.14 2001/09/24 13:22:44 kai Exp $
+ *
+ * Module for AVM B1 ISA-card.
+ *
+@@ -19,12 +19,13 @@
+ #include <linux/capi.h>
+ #include <linux/init.h>
+ #include <asm/io.h>
++#include <linux/isdn_compat.h>
+ #include "capicmd.h"
+ #include "capiutil.h"
+ #include "capilli.h"
+ #include "avmcard.h"
+
+-static char *revision = "$Revision: 1.1.4.1 $";
++static char *revision = "$Revision: 1.14 $";
+
+ /* ------------------------------------------------------------- */
+
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/b1pci.c linux-2.4.29/drivers/isdn/avmb1/b1pci.c
+--- linux-2.4.29.old/drivers/isdn/avmb1/b1pci.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/b1pci.c 2005-03-22 15:06:44.781284992 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: b1pci.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: b1pci.c,v 1.40 2001/09/24 13:22:44 kai Exp $
+ *
+ * Module for AVM B1 PCI-card.
+ *
+@@ -21,21 +21,24 @@
+ #include <linux/capi.h>
+ #include <asm/io.h>
+ #include <linux/init.h>
++#include <linux/isdn_compat.h>
+ #include "capicmd.h"
+ #include "capiutil.h"
+ #include "capilli.h"
+ #include "avmcard.h"
+
+-static char *revision = "$Revision: 1.1.4.1 $";
++static char *revision = "$Revision: 1.40 $";
+
+ /* ------------------------------------------------------------- */
+
++#ifndef COMPAT_HAS_2_2_PCI
+ static struct pci_device_id b1pci_pci_tbl[] __initdata = {
+ { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, PCI_ANY_ID, PCI_ANY_ID },
+ { } /* Terminating entry */
+ };
+
+ MODULE_DEVICE_TABLE(pci, b1pci_pci_tbl);
++#endif
+ MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 PCI card");
+ MODULE_AUTHOR("Carsten Paeth");
+ MODULE_LICENSE("GPL");
+@@ -416,14 +419,14 @@
+ }
+ param.irq = dev->irq;
+
+- if (pci_resource_start(dev, 2)) { /* B1 PCI V4 */
++ if (pci_resource_start_io(dev, 2)) { /* B1 PCI V4 */
+ #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+ driver = &b1pciv4_driver;
+
+ pci_set_master(dev);
+ #endif
+- param.membase = pci_resource_start(dev, 0);
+- param.port = pci_resource_start(dev, 2);
++ param.membase = pci_resource_start_mem(dev, 0);
++ param.port = pci_resource_start_io(dev, 2);
+
+ printk(KERN_INFO
+ "%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
+@@ -440,7 +443,7 @@
+ }
+ } else {
+ param.membase = 0;
+- param.port = pci_resource_start(dev, 1);
++ param.port = pci_resource_start_io(dev, 1);
+
+ printk(KERN_INFO
+ "%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/b1pcmcia.c linux-2.4.29/drivers/isdn/avmb1/b1pcmcia.c
+--- linux-2.4.29.old/drivers/isdn/avmb1/b1pcmcia.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/b1pcmcia.c 2005-03-22 15:06:44.796282712 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: b1pcmcia.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: b1pcmcia.c,v 1.17 2001/09/24 13:22:44 kai Exp $
+ *
+ * Module for AVM B1/M1/M2 PCMCIA-card.
+ *
+@@ -25,7 +25,7 @@
+ #include "capilli.h"
+ #include "avmcard.h"
+
+-static char *revision = "$Revision: 1.1.4.1 $";
++static char *revision = "$Revision: 1.17 $";
+
+ /* ------------------------------------------------------------- */
+
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/c4.c linux-2.4.29/drivers/isdn/avmb1/c4.c
+--- linux-2.4.29.old/drivers/isdn/avmb1/c4.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/c4.c 2005-03-22 15:06:44.812280280 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: c4.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: c4.c,v 1.38 2001/09/24 13:22:44 kai Exp $
+ *
+ * Module for AVM C4 & C2 card.
+ *
+@@ -18,6 +18,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/ioport.h>
+ #include <linux/pci.h>
++#include <linux/isdn_compat.h>
+ #include <linux/capi.h>
+ #include <linux/kernelcapi.h>
+ #include <linux/init.h>
+@@ -29,7 +30,7 @@
+ #include "capilli.h"
+ #include "avmcard.h"
+
+-static char *revision = "$Revision: 1.1.4.1 $";
++static char *revision = "$Revision: 1.38 $";
+
+ #undef CONFIG_C4_DEBUG
+ #undef CONFIG_C4_POLLDEBUG
+@@ -38,6 +39,7 @@
+
+ static int suppress_pollack;
+
++#ifndef COMPAT_HAS_2_2_PCI
+ static struct pci_device_id c4_pci_tbl[] __initdata = {
+ { PCI_VENDOR_ID_DEC,PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4 },
+ { PCI_VENDOR_ID_DEC,PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C2 },
+@@ -45,6 +47,7 @@
+ };
+
+ MODULE_DEVICE_TABLE(pci, c4_pci_tbl);
++#endif
+ MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM C2/C4 cards");
+ MODULE_AUTHOR("Carsten Paeth");
+ MODULE_LICENSE("GPL");
+@@ -1328,9 +1331,9 @@
+ }
+ pci_set_master(dev);
+
+- param.port = pci_resource_start(dev, 1);
++ param.port = pci_resource_start_io(dev, 1);
+ param.irq = dev->irq;
+- param.membase = pci_resource_start(dev, 0);
++ param.membase = pci_resource_start_mem(dev, 0);
+
+ printk(KERN_INFO
+ "%s: PCI BIOS reports AVM-C%d at i/o %#x, irq %d, mem %#x\n",
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/capi.c linux-2.4.29/drivers/isdn/avmb1/capi.c
+--- linux-2.4.29.old/drivers/isdn/avmb1/capi.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/capi.c 2005-03-22 15:06:44.849274656 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: capi.c,v 1.1.4.2 2001/12/09 18:45:13 kai Exp $
++/* $Id: capi.c,v 1.59 2001/11/07 22:35:48 kai Exp $
+ *
+ * CAPI 2.0 Interface for Linux
+ *
+@@ -23,6 +23,7 @@
+ #include <linux/smp_lock.h>
+ #include <linux/timer.h>
+ #include <linux/wait.h>
++#include <linux/isdn_compat.h>
+ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ #include <linux/tty.h>
+ #ifdef CONFIG_PPP
+@@ -30,6 +31,9 @@
+ #include <linux/ppp_defs.h>
+ #include <linux/if_ppp.h>
+ #undef CAPI_PPP_ON_RAW_DEVICE
++#ifdef CAPI_PPP_ON_RAW_DEVICE
++#include <linux/ppp_channel.h>
++#endif /* CAPI_PPP_ON_RAW_DEVICE */
+ #endif /* CONFIG_PPP */
+ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ #include <linux/skbuff.h>
+@@ -38,14 +42,16 @@
+ #include <linux/capi.h>
+ #include <linux/kernelcapi.h>
+ #include <linux/init.h>
++#ifdef HAVE_DEVFS_FS
+ #include <linux/devfs_fs_kernel.h>
++#endif /* HAVE_DEVFS_FS */
+ #include "capiutil.h"
+ #include "capicmd.h"
+ #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
+ #include "capifs.h"
+ #endif
+
+-static char *revision = "$Revision: 1.1.4.2 $";
++static char *revision = "$Revision: 1.59 $";
+
+ MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface");
+ MODULE_AUTHOR("Carsten Paeth");
+@@ -87,10 +93,10 @@
+ struct capincci *nccip;
+ unsigned int minor;
+
+- u16 applid;
+- u32 ncci;
+- u16 datahandle;
+- u16 msgid;
++ __u16 applid;
++ __u32 ncci;
++ __u16 datahandle;
++ __u16 msgid;
+
+ struct file *file;
+ struct tty_struct *tty;
+@@ -112,16 +118,22 @@
+ /* transmit path */
+ struct datahandle_queue {
+ struct datahandle_queue *next;
+- u16 datahandle;
++ __u16 datahandle;
+ } *ackqueue;
+ int nack;
+
++#ifdef CAPI_PPP_ON_RAW_DEVICE
++ /* interface to generic ppp layer */
++ struct ppp_channel chan;
++ int chan_connected;
++ int chan_index;
++#endif
+ };
+ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+ struct capincci {
+ struct capincci *next;
+- u32 ncci;
++ __u32 ncci;
+ struct capidev *cdev;
+ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ struct capiminor *minorp;
+@@ -131,8 +143,8 @@
+ struct capidev {
+ struct capidev *next;
+ struct file *file;
+- u16 applid;
+- u16 errcode;
++ __u16 applid;
++ __u16 errcode;
+ unsigned int minor;
+ unsigned userflags;
+
+@@ -156,22 +168,28 @@
+ static struct capiminor *minors = 0;
+ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
++#ifdef COMPAT_HAS_kmem_cache
+ static kmem_cache_t *capidev_cachep = 0;
+ static kmem_cache_t *capincci_cachep = 0;
+ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ static kmem_cache_t *capiminor_cachep = 0;
+ static kmem_cache_t *capidh_cachep = 0;
+ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
++#endif
+
+ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ /* -------- datahandles --------------------------------------------- */
+
+-static int capincci_add_ack(struct capiminor *mp, u16 datahandle)
++int capincci_add_ack(struct capiminor *mp, __u16 datahandle)
+ {
+ struct datahandle_queue *n, **pp;
+
+ n = (struct datahandle_queue *)
++#ifdef COMPAT_HAS_kmem_cache
+ kmem_cache_alloc(capidh_cachep, GFP_ATOMIC);
++#else
++ kmalloc(sizeof(struct datahandle_queue), GFP_ATOMIC);
++#endif
+ if (!n) {
+ printk(KERN_ERR "capi: alloc datahandle failed\n");
+ return -1;
+@@ -184,7 +202,7 @@
+ return 0;
+ }
+
+-static int capiminor_del_ack(struct capiminor *mp, u16 datahandle)
++int capiminor_del_ack(struct capiminor *mp, __u16 datahandle)
+ {
+ struct datahandle_queue **pp, *p;
+
+@@ -192,7 +210,11 @@
+ if ((*pp)->datahandle == datahandle) {
+ p = *pp;
+ *pp = (*pp)->next;
++#ifdef COMPAT_HAS_kmem_cache
+ kmem_cache_free(capidh_cachep, p);
++#else
++ kfree(p);
++#endif
+ mp->nack--;
+ return 0;
+ }
+@@ -200,7 +222,7 @@
+ return -1;
+ }
+
+-static void capiminor_del_all_ack(struct capiminor *mp)
++void capiminor_del_all_ack(struct capiminor *mp)
+ {
+ struct datahandle_queue **pp, *p;
+
+@@ -208,7 +230,11 @@
+ while (*pp) {
+ p = *pp;
+ *pp = (*pp)->next;
++#ifdef COMPAT_HAS_kmem_cache
+ kmem_cache_free(capidh_cachep, p);
++#else
++ kfree(p);
++#endif
+ mp->nack--;
+ }
+ }
+@@ -216,13 +242,17 @@
+
+ /* -------- struct capiminor ---------------------------------------- */
+
+-static struct capiminor *capiminor_alloc(u16 applid, u32 ncci)
++struct capiminor *capiminor_alloc(__u16 applid, __u32 ncci)
+ {
+ struct capiminor *mp, **pp;
+ unsigned int minor = 0;
+
+ MOD_INC_USE_COUNT;
++#ifdef COMPAT_HAS_kmem_cache
+ mp = (struct capiminor *)kmem_cache_alloc(capiminor_cachep, GFP_ATOMIC);
++#else
++ mp = (struct capiminor *)kmalloc(sizeof(struct capiminor), GFP_ATOMIC);
++#endif
+ if (!mp) {
+ MOD_DEC_USE_COUNT;
+ printk(KERN_ERR "capi: can't alloc capiminor\n");
+@@ -257,7 +287,7 @@
+ return mp;
+ }
+
+-static void capiminor_free(struct capiminor *mp)
++void capiminor_free(struct capiminor *mp)
+ {
+ struct capiminor **pp;
+
+@@ -271,7 +301,11 @@
+ skb_queue_purge(&mp->inqueue);
+ skb_queue_purge(&mp->outqueue);
+ capiminor_del_all_ack(mp);
++#ifdef COMPAT_HAS_kmem_cache
+ kmem_cache_free(capiminor_cachep, mp);
++#else
++ kfree(mp);
++#endif
+ MOD_DEC_USE_COUNT;
+ #ifdef _DEBUG_REFCOUNT
+ printk(KERN_DEBUG "capiminor_free %d\n", GET_USE_COUNT(THIS_MODULE));
+@@ -283,7 +317,7 @@
+ }
+ }
+
+-static struct capiminor *capiminor_find(unsigned int minor)
++struct capiminor *capiminor_find(unsigned int minor)
+ {
+ struct capiminor *p;
+ for (p = minors; p && p->minor != minor; p = p->next)
+@@ -294,7 +328,7 @@
+
+ /* -------- struct capincci ----------------------------------------- */
+
+-static struct capincci *capincci_alloc(struct capidev *cdev, u32 ncci)
++static struct capincci *capincci_alloc(struct capidev *cdev, __u32 ncci)
+ {
+ struct capincci *np, **pp;
+ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+@@ -302,7 +336,11 @@
+ kdev_t kdev;
+ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
++#ifdef COMPAT_HAS_kmem_cache
+ np = (struct capincci *)kmem_cache_alloc(capincci_cachep, GFP_ATOMIC);
++#else
++ np = (struct capincci *)kmalloc(sizeof(struct capincci), GFP_ATOMIC);
++#endif
+ if (!np)
+ return 0;
+ memset(np, 0, sizeof(struct capincci));
+@@ -331,7 +369,7 @@
+ return np;
+ }
+
+-static void capincci_free(struct capidev *cdev, u32 ncci)
++static void capincci_free(struct capidev *cdev, __u32 ncci)
+ {
+ struct capincci *np, **pp;
+ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+@@ -367,7 +405,11 @@
+ }
+ }
+ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
++#ifdef COMPAT_HAS_kmem_cache
+ kmem_cache_free(capincci_cachep, np);
++#else
++ kfree(np);
++#endif
+ if (*pp == 0) return;
+ } else {
+ pp = &(*pp)->next;
+@@ -375,7 +417,7 @@
+ }
+ }
+
+-static struct capincci *capincci_find(struct capidev *cdev, u32 ncci)
++struct capincci *capincci_find(struct capidev *cdev, __u32 ncci)
+ {
+ struct capincci *p;
+
+@@ -393,7 +435,11 @@
+ struct capidev *cdev;
+ struct capidev **pp;
+
++#ifdef COMPAT_HAS_kmem_cache
+ cdev = (struct capidev *)kmem_cache_alloc(capidev_cachep, GFP_KERNEL);
++#else
++ cdev = (struct capidev *)kmalloc(sizeof(struct capidev), GFP_KERNEL);
++#endif
+ if (!cdev)
+ return 0;
+ memset(cdev, 0, sizeof(struct capidev));
+@@ -423,10 +469,14 @@
+ if (*pp)
+ *pp = cdev->next;
+
++#ifdef COMPAT_HAS_kmem_cache
+ kmem_cache_free(capidev_cachep, cdev);
++#else
++ kfree(cdev);
++#endif
+ }
+
+-static struct capidev *capidev_find(u16 applid)
++static struct capidev *capidev_find(__u16 applid)
+ {
+ struct capidev *p;
+ for (p=capidev_openlist; p; p = p->next) {
+@@ -439,13 +489,13 @@
+ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ /* -------- handle data queue --------------------------------------- */
+
+-static struct sk_buff *
++struct sk_buff *
+ gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
+ {
+ struct sk_buff *nskb;
+ nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_ATOMIC);
+ if (nskb) {
+- u16 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4+4+2);
++ __u16 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4+4+2);
+ unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN);
+ capimsg_setu16(s, 0, CAPI_DATA_B3_RESP_LEN);
+ capimsg_setu16(s, 2, mp->applid);
+@@ -458,11 +508,11 @@
+ return nskb;
+ }
+
+-static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
++int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
+ {
+ struct sk_buff *nskb;
+ unsigned int datalen;
+- u16 errcode, datahandle;
++ __u16 errcode, datahandle;
+
+ datalen = skb->len - CAPIMSG_LEN(skb->data);
+ if (mp->tty) {
+@@ -504,6 +554,28 @@
+ kfree_skb(skb);
+ return 0;
+
++#ifdef CAPI_PPP_ON_RAW_DEVICE
++ } else if (mp->chan_connected) {
++ if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
++ printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
++ return -1;
++ }
++ datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
++ errcode = (*capifuncs->capi_put_message)(mp->applid, nskb);
++ if (errcode != CAPI_NOERROR) {
++ printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
++ errcode);
++ kfree_skb(nskb);
++ return -1;
++ }
++ (void)skb_pull(skb, CAPIMSG_LEN(skb->data));
++#ifdef _DEBUG_DATAFLOW
++ printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ppp\n",
++ datahandle, skb->len);
++#endif
++ ppp_input(&mp->chan, skb);
++ return 0;
++#endif
+ } else if (mp->file) {
+ if (skb_queue_len(&mp->recvqueue) > CAPINC_MAX_RECVQUEUE) {
+ #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+@@ -538,7 +610,7 @@
+ return -1;
+ }
+
+-static void handle_minor_recv(struct capiminor *mp)
++void handle_minor_recv(struct capiminor *mp)
+ {
+ struct sk_buff *skb;
+ while ((skb = skb_dequeue(&mp->inqueue)) != 0) {
+@@ -552,13 +624,13 @@
+ }
+ }
+
+-static int handle_minor_send(struct capiminor *mp)
++int handle_minor_send(struct capiminor *mp)
+ {
+ struct sk_buff *skb;
+- u16 len;
++ __u16 len;
+ int count = 0;
+- u16 errcode;
+- u16 datahandle;
++ __u16 errcode;
++ __u16 datahandle;
+
+ if (mp->tty && mp->ttyoutstop) {
+ #if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+@@ -569,7 +641,7 @@
+
+ while ((skb = skb_dequeue(&mp->outqueue)) != 0) {
+ datahandle = mp->datahandle;
+- len = (u16)skb->len;
++ len = (__u16)skb->len;
+ skb_push(skb, CAPI_DATA_B3_REQ_LEN);
+ memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
+ capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
+@@ -578,7 +650,7 @@
+ capimsg_setu8 (skb->data, 5, CAPI_REQ);
+ capimsg_setu16(skb->data, 6, mp->msgid++);
+ capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */
+- capimsg_setu32(skb->data, 12, (u32) skb->data); /* Data32 */
++ capimsg_setu32(skb->data, 12, (__u32) skb->data); /* Data32 */
+ capimsg_setu16(skb->data, 16, len); /* Data length */
+ capimsg_setu16(skb->data, 18, datahandle);
+ capimsg_setu16(skb->data, 20, 0); /* Flags */
+@@ -620,16 +692,16 @@
+ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ /* -------- function called by lower level -------------------------- */
+
+-static void capi_signal(u16 applid, void *param)
++static void capi_signal(__u16 applid, void *param)
+ {
+ struct capidev *cdev = (struct capidev *)param;
+ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ struct capiminor *mp;
+- u16 datahandle;
++ __u16 datahandle;
+ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ struct capincci *np;
+ struct sk_buff *skb = 0;
+- u32 ncci;
++ __u32 ncci;
+
+ (void) (*capifuncs->capi_get_message) (applid, &skb);
+ if (!skb) {
+@@ -683,6 +755,12 @@
+ #endif
+ kfree_skb(skb);
+ (void)capiminor_del_ack(mp, datahandle);
++#ifdef CAPI_PPP_ON_RAW_DEVICE
++ if (mp->chan_connected) {
++ ppp_output_wakeup(&mp->chan);
++ return;
++ }
++#endif
+ if (mp->tty) {
+ if (mp->tty->ldisc.write_wakeup)
+ mp->tty->ldisc.write_wakeup(mp->tty);
+@@ -758,7 +836,7 @@
+ struct capidev *cdev = (struct capidev *)file->private_data;
+ struct sk_buff *skb;
+ int retval;
+- u16 mlen;
++ __u16 mlen;
+
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+@@ -998,7 +1076,7 @@
+ sizeof(ncci));
+ if (retval)
+ return -EFAULT;
+- nccip = capincci_find(cdev, (u32) ncci);
++ nccip = capincci_find(cdev, (__u32) ncci);
+ if (!nccip)
+ return 0;
+ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+@@ -1023,7 +1101,7 @@
+ sizeof(ncci));
+ if (retval)
+ return -EFAULT;
+- nccip = capincci_find(cdev, (u32) ncci);
++ nccip = capincci_find(cdev, (__u32) ncci);
+ if (!nccip || (mp = nccip->minorp) == 0)
+ return -ESRCH;
+ return mp->minor;
+@@ -1070,7 +1148,9 @@
+
+ static struct file_operations capi_fops =
+ {
++#ifdef COMPAT_HAS_FILEOP_OWNER
+ owner: THIS_MODULE,
++#endif
+ llseek: no_llseek,
+ read: capi_read,
+ write: capi_write,
+@@ -1233,6 +1313,45 @@
+ return -EINVAL;
+
+ switch (cmd) {
++#ifdef CAPI_PPP_ON_RAW_DEVICE
++ case PPPIOCATTACH:
++ {
++ int retval, val;
++ if (get_user(val, (int *) arg))
++ break;
++ if (mp->chan_connected)
++ return -EALREADY;
++ mp->chan.private = mp;
++#if 1
++ return -EINVAL;
++#else
++ mp->chan.ops = &ppp_ops;
++#endif
++
++ retval = ppp_register_channel(&mp->chan, val);
++ if (retval)
++ return retval;
++ mp->chan_connected = 1;
++ mp->chan_index = val;
++ }
++ return 0;
++ case PPPIOCDETACH:
++ {
++ if (!mp->chan_connected)
++ return -ENXIO;
++ ppp_unregister_channel(&mp->chan);
++ mp->chan_connected = 0;
++ }
++ return 0;
++ case PPPIOCGUNIT:
++ {
++ if (!mp->chan_connected)
++ return -ENXIO;
++ if (put_user(mp->chan_index, (int *) arg))
++ return -EFAULT;
++ }
++ return 0;
++#endif
+ }
+ return -EINVAL;
+ }
+@@ -1260,7 +1379,9 @@
+
+ static struct file_operations capinc_raw_fops =
+ {
++#ifdef COMPAT_HAS_FILEOP_OWNER
+ owner: THIS_MODULE,
++#endif
+ llseek: no_llseek,
+ read: capinc_raw_read,
+ write: capinc_raw_write,
+@@ -1272,7 +1393,7 @@
+
+ /* -------- tty_operations for capincci ----------------------------- */
+
+-static int capinc_tty_open(struct tty_struct * tty, struct file * file)
++int capinc_tty_open(struct tty_struct * tty, struct file * file)
+ {
+ struct capiminor *mp;
+
+@@ -1300,7 +1421,7 @@
+ return 0;
+ }
+
+-static void capinc_tty_close(struct tty_struct * tty, struct file * file)
++void capinc_tty_close(struct tty_struct * tty, struct file * file)
+ {
+ struct capiminor *mp;
+
+@@ -1325,8 +1446,8 @@
+ #endif
+ }
+
+-static int capinc_tty_write(struct tty_struct * tty, int from_user,
+- const unsigned char *buf, int count)
++int capinc_tty_write(struct tty_struct * tty, int from_user,
++ const unsigned char *buf, int count)
+ {
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ struct sk_buff *skb;
+@@ -1377,7 +1498,7 @@
+ return count;
+ }
+
+-static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
++void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
+ {
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ struct sk_buff *skb;
+@@ -1414,7 +1535,7 @@
+ }
+ }
+
+-static void capinc_tty_flush_chars(struct tty_struct *tty)
++void capinc_tty_flush_chars(struct tty_struct *tty)
+ {
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ struct sk_buff *skb;
+@@ -1440,7 +1561,7 @@
+ (void)handle_minor_recv(mp);
+ }
+
+-static int capinc_tty_write_room(struct tty_struct *tty)
++int capinc_tty_write_room(struct tty_struct *tty)
+ {
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ int room;
+@@ -1458,7 +1579,7 @@
+ return room;
+ }
+
+-static int capinc_tty_chars_in_buffer(struct tty_struct *tty)
++int capinc_tty_chars_in_buffer(struct tty_struct *tty)
+ {
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ if (!mp || !mp->nccip) {
+@@ -1476,7 +1597,7 @@
+ return mp->outbytes;
+ }
+
+-static int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
++int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg)
+ {
+ int error = 0;
+@@ -1488,14 +1609,14 @@
+ return error;
+ }
+
+-static void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old)
++void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old)
+ {
+ #ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_set_termios\n");
+ #endif
+ }
+
+-static void capinc_tty_throttle(struct tty_struct * tty)
++void capinc_tty_throttle(struct tty_struct * tty)
+ {
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ #ifdef _DEBUG_TTYFUNCS
+@@ -1505,7 +1626,7 @@
+ mp->ttyinstop = 1;
+ }
+
+-static void capinc_tty_unthrottle(struct tty_struct * tty)
++void capinc_tty_unthrottle(struct tty_struct * tty)
+ {
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ #ifdef _DEBUG_TTYFUNCS
+@@ -1517,7 +1638,7 @@
+ }
+ }
+
+-static void capinc_tty_stop(struct tty_struct *tty)
++void capinc_tty_stop(struct tty_struct *tty)
+ {
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ #ifdef _DEBUG_TTYFUNCS
+@@ -1528,7 +1649,7 @@
+ }
+ }
+
+-static void capinc_tty_start(struct tty_struct *tty)
++void capinc_tty_start(struct tty_struct *tty)
+ {
+ struct capiminor *mp = (struct capiminor *)tty->driver_data;
+ #ifdef _DEBUG_TTYFUNCS
+@@ -1540,43 +1661,49 @@
+ }
+ }
+
+-static void capinc_tty_hangup(struct tty_struct *tty)
++void capinc_tty_hangup(struct tty_struct *tty)
+ {
+ #ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_hangup\n");
+ #endif
+ }
+
+-static void capinc_tty_break_ctl(struct tty_struct *tty, int state)
++void capinc_tty_break_ctl(struct tty_struct *tty, int state)
+ {
+ #ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state);
+ #endif
+ }
+
+-static void capinc_tty_flush_buffer(struct tty_struct *tty)
++void capinc_tty_flush_buffer(struct tty_struct *tty)
+ {
+ #ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_flush_buffer\n");
+ #endif
+ }
+
+-static void capinc_tty_set_ldisc(struct tty_struct *tty)
++void capinc_tty_set_ldisc(struct tty_struct *tty)
+ {
+ #ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_set_ldisc\n");
+ #endif
+ }
+
+-static void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
++void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
+ {
+ #ifdef _DEBUG_TTYFUNCS
+ printk(KERN_DEBUG "capinc_tty_send_xchar(%d)\n", ch);
+ #endif
+ }
+
+-static int capinc_tty_read_proc(char *page, char **start, off_t off,
+- int count, int *eof, void *data)
++int capinc_tty_read_proc(char *page, char **start, off_t off,
++ int count, int *eof, void *data)
++{
++ return 0;
++}
++
++int capinc_write_proc(struct file *file, const char *buffer,
++ unsigned long count, void *data)
+ {
+ return 0;
+ }
+@@ -1588,7 +1715,7 @@
+ static struct termios *capinc_tty_termios[CAPINC_NR_PORTS];
+ static struct termios *capinc_tty_termios_locked[CAPINC_NR_PORTS];
+
+-static int capinc_tty_init(void)
++int capinc_tty_init(void)
+ {
+ struct tty_driver *drv = &capinc_tty_driver;
+
+@@ -1646,7 +1773,7 @@
+ return 0;
+ }
+
+-static void capinc_tty_exit(void)
++void capinc_tty_exit(void)
+ {
+ struct tty_driver *drv = &capinc_tty_driver;
+ int retval;
+@@ -1771,8 +1898,9 @@
+
+ /* -------- init function and module interface ---------------------- */
+
++#ifdef COMPAT_HAS_kmem_cache
+
+-static void alloc_exit(void)
++static void __exit alloc_exit(void)
+ {
+ if (capidev_cachep) {
+ (void)kmem_cache_destroy(capidev_cachep);
+@@ -1837,8 +1965,9 @@
+ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ return 0;
+ }
++#endif
+
+-static void lower_callback(unsigned int cmd, u32 contr, void *data)
++static void lower_callback(unsigned int cmd, __u32 contr, void *data)
+ {
+ struct capi_ncciinfo *np;
+ struct capidev *cdev;
+@@ -1900,15 +2029,19 @@
+ MOD_DEC_USE_COUNT;
+ return -EIO;
+ }
++#ifdef HAVE_DEVFS_FS
+ devfs_register_series (NULL, "capi/r%u", CAPINC_NR_PORTS,
+ DEVFS_FL_DEFAULT,
+ capi_rawmajor, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
+ &capinc_raw_fops, NULL);
++#endif
+ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
++#ifdef HAVE_DEVFS_FS
+ devfs_register (NULL, "isdn/capi20", DEVFS_FL_DEFAULT,
+ capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR,
+ &capi_fops, NULL);
++#endif
+ printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major);
+
+ if ((capifuncs = attach_capi_interface(&cuser)) == 0) {
+@@ -1918,9 +2051,11 @@
+ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ devfs_unregister_chrdev(capi_rawmajor, "capi/r%d");
+ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
++#ifdef HAVE_DEVFS_FS
+ devfs_unregister(devfs_find_handle(NULL, "capi20",
+ capi_major, 0,
+ DEVFS_SPECIAL_CHR, 0));
++#endif
+ return -EIO;
+ }
+
+@@ -1934,8 +2069,10 @@
+ }
+ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
++#ifdef COMPAT_HAS_kmem_cache
+ if (alloc_init() < 0) {
+ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
++#ifdef HAVE_DEVFS_FS
+ unsigned int j;
+ devfs_unregister_chrdev(capi_rawmajor, "capi/r%d");
+ for (j = 0; j < CAPINC_NR_PORTS; j++) {
+@@ -1943,16 +2080,20 @@
+ sprintf(devname, "capi/r%u", j);
+ devfs_unregister(devfs_find_handle(NULL, devname, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0));
+ }
++#endif
+ capinc_tty_exit();
+ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+ (void) detach_capi_interface(&cuser);
+ devfs_unregister_chrdev(capi_major, "capi20");
++#ifdef HAVE_DEVFS_FS
+ devfs_unregister(devfs_find_handle(NULL, "capi20",
+ capi_major, 0,
+ DEVFS_SPECIAL_CHR, 0));
++#endif
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
++#endif /* COMPAT_HAS_kmem_cache */
+
+ (void)proc_init();
+
+@@ -1975,23 +2116,31 @@
+ static void __exit capi_exit(void)
+ {
+ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
++#ifdef HAVE_DEVFS_FS
+ unsigned int j;
+ #endif
++#endif
++#ifdef COMPAT_HAS_kmem_cache
+ alloc_exit();
++#endif
+ (void)proc_exit();
+
+ devfs_unregister_chrdev(capi_major, "capi20");
++#ifdef HAVE_DEVFS_FS
+ devfs_unregister(devfs_find_handle(NULL, "isdn/capi20", capi_major, 0, DEVFS_SPECIAL_CHR, 0));
++#endif
+
+ #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ capinc_tty_exit();
+ devfs_unregister_chrdev(capi_rawmajor, "capi/r%d");
++#ifdef HAVE_DEVFS_FS
+ for (j = 0; j < CAPINC_NR_PORTS; j++) {
+ char devname[32];
+ sprintf(devname, "capi/r%u", j);
+ devfs_unregister(devfs_find_handle(NULL, devname, capi_rawmajor, j, DEVFS_SPECIAL_CHR, 0));
+ }
+ #endif
++#endif
+ (void) detach_capi_interface(&cuser);
+ printk(KERN_NOTICE "capi: Rev %s: unloaded\n", rev);
+ }
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/capicmd.h linux-2.4.29/drivers/isdn/avmb1/capicmd.h
+--- linux-2.4.29.old/drivers/isdn/avmb1/capicmd.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/capicmd.h 2005-03-22 15:06:44.865272224 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: capicmd.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: capicmd.h,v 1.4 2001/09/24 13:22:44 kai Exp $
+ *
+ * CAPI 2.0 Interface for Linux
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/capidev.h linux-2.4.29/drivers/isdn/avmb1/capidev.h
+--- linux-2.4.29.old/drivers/isdn/avmb1/capidev.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/capidev.h 2005-03-22 15:06:44.880269944 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: capidev.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: capidev.h,v 1.8 2001/09/24 13:22:44 kai Exp $
+ *
+ * CAPI 2.0 Interface for Linux
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/capidrv.c linux-2.4.29/drivers/isdn/avmb1/capidrv.c
+--- linux-2.4.29.old/drivers/isdn/avmb1/capidrv.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/capidrv.c 2005-03-22 15:06:44.918264168 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: capidrv.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: capidrv.c,v 1.45 2001/09/24 13:22:44 kai Exp $
+ *
+ * ISDN4Linux Driver, using capi20 interface (kernelcapi)
+ *
+@@ -35,7 +35,7 @@
+ #include "capicmd.h"
+ #include "capidrv.h"
+
+-static char *revision = "$Revision: 1.1.4.1 $";
++static char *revision = "$Revision: 1.45 $";
+ static int debugmode = 0;
+
+ MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux");
+@@ -105,7 +105,6 @@
+ int oldstate;
+ /* */
+ __u16 datahandle;
+- spinlock_t lock;
+ struct ncci_datahandle_queue {
+ struct ncci_datahandle_queue *next;
+ __u16 datahandle;
+@@ -423,7 +422,6 @@
+ nccip->plcip = plcip;
+ nccip->chan = plcip->chan;
+ nccip->datahandle = 0;
+- nccip->lock = SPIN_LOCK_UNLOCKED;
+
+ nccip->next = plcip->ncci_list;
+ plcip->ncci_list = nccip;
+@@ -480,7 +478,6 @@
+ __u16 datahandle, int len)
+ {
+ struct ncci_datahandle_queue *n, **pp;
+- unsigned long flags;
+
+ n = (struct ncci_datahandle_queue *)
+ kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC);
+@@ -491,31 +488,25 @@
+ n->next = 0;
+ n->datahandle = datahandle;
+ n->len = len;
+- spin_lock_irqsave(&nccip->lock, flags);
+ for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) ;
+ *pp = n;
+- spin_unlock_irqrestore(&nccip->lock, flags);
+ return 0;
+ }
+
+ static int capidrv_del_ack(struct capidrv_ncci *nccip, __u16 datahandle)
+ {
+ struct ncci_datahandle_queue **pp, *p;
+- unsigned long flags;
+ int len;
+
+- spin_lock_irqsave(&nccip->lock, flags);
+ for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) {
+ if ((*pp)->datahandle == datahandle) {
+ p = *pp;
+ len = p->len;
+ *pp = (*pp)->next;
+- spin_unlock_irqrestore(&nccip->lock, flags);
+ kfree(p);
+ return len;
+ }
+ }
+- spin_unlock_irqrestore(&nccip->lock, flags);
+ return -1;
+ }
+
+@@ -523,25 +514,13 @@
+
+ static void send_message(capidrv_contr * card, _cmsg * cmsg)
+ {
+- struct sk_buff *skb;
+- size_t len;
+- u16 err;
+-
++ struct sk_buff *skb;
++ size_t len;
+ capi_cmsg2message(cmsg, cmsg->buf);
+ len = CAPIMSG_LEN(cmsg->buf);
+ skb = alloc_skb(len, GFP_ATOMIC);
+- if(!skb) {
+- printk(KERN_ERR "no skb len(%d) memory\n", len);
+- return;
+- }
+ memcpy(skb_put(skb, len), cmsg->buf, len);
+- err = (*capifuncs->capi_put_message) (global.appid, skb);
+- if (err) {
+- printk(KERN_WARNING "%s: capi_put_message error: %04x\n",
+- __FUNCTION__, err);
+- kfree_skb(skb);
+- return;
+- }
++ (*capifuncs->capi_put_message) (global.appid, skb);
+ global.nsentctlpkt++;
+ }
+
+@@ -1932,8 +1911,10 @@
+ (void)capidrv_del_ack(nccip, datahandle);
+ return 0;
+ }
++#if 1
+ printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n",
+ card->contrnr, skb_headroom(skb), msglen);
++#endif
+ memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen);
+ errcode = (*capifuncs->capi_put_message) (global.appid, nskb);
+ if (errcode == CAPI_NOERROR) {
+@@ -2035,6 +2016,52 @@
+ send_message(card, &cmdcmsg);
+ }
+
++#if 0
++static void disable_dchannel_trace(capidrv_contr *card)
++{
++ __u8 manufacturer[CAPI_MANUFACTURER_LEN];
++ capi_version version;
++ __u16 contr = card->contrnr;
++ __u16 errcode;
++ __u16 avmversion[3];
++
++ errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer);
++ if (errcode != CAPI_NOERROR) {
++ printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
++ card->name, errcode);
++ return;
++ }
++ if (strstr(manufacturer, "AVM") == 0) {
++ printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
++ card->name, manufacturer);
++ return;
++ }
++ errcode = (*capifuncs->capi_get_version)(contr, &version);
++ if (errcode != CAPI_NOERROR) {
++ printk(KERN_ERR "%s: can't get version (0x%x)\n",
++ card->name, errcode);
++ return;
++ }
++ avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
++ avmversion[1] = (version.majormanuversion << 4) & 0xf0;
++ avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
++ avmversion[2] |= version.minormanuversion & 0x0f;
++
++ if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
++ printk(KERN_INFO "%s: D2 trace disabled\n", card->name);
++ } else {
++ printk(KERN_INFO "%s: D3 trace disabled\n", card->name);
++ }
++ capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
++ card->msgid++,
++ contr,
++ 0x214D5641, /* ManuID */
++ 0, /* Class */
++ 1, /* Function */
++ (_cstruct)"\004\000\000\000\000");
++ send_message(card, &cmdcmsg);
++}
++#endif
+
+ static void send_listen(capidrv_contr *card)
+ {
+@@ -2200,10 +2227,10 @@
+ free_ncci(card, card->bchans[card->nbchan-1].nccip);
+ if (card->bchans[card->nbchan-1].plcip)
+ free_plci(card, card->bchans[card->nbchan-1].plcip);
++ if (card->plci_list)
++ printk(KERN_ERR "capidrv: bug in free_plci()\n");
+ card->nbchan--;
+ }
+- if (card->plci_list)
+- printk(KERN_ERR "capidrv: bug in free_plci()\n");
+ kfree(card->bchans);
+ card->bchans = 0;
+
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/capidrv.h linux-2.4.29/drivers/isdn/avmb1/capidrv.h
+--- linux-2.4.29.old/drivers/isdn/avmb1/capidrv.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/capidrv.h 2005-03-22 15:06:44.935261584 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: capidrv.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: capidrv.h,v 1.4 2001/09/24 13:22:44 kai Exp $
+ *
+ * ISDN4Linux Driver, using capi20 interface (kernelcapi)
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/capifs.c linux-2.4.29/drivers/isdn/avmb1/capifs.c
+--- linux-2.4.29.old/drivers/isdn/avmb1/capifs.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/capifs.c 2005-03-22 15:06:44.950259304 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: capifs.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: capifs.c,v 1.22 2001/09/24 13:22:44 kai Exp $
+ *
+ * Copyright 2000 by Carsten Paeth <calle@calle.de>
+ *
+@@ -25,6 +25,7 @@
+ #include <linux/major.h>
+ #include <linux/slab.h>
+ #include <linux/ctype.h>
++#include <linux/isdn_compat.h>
+ #include <asm/bitops.h>
+ #include <asm/uaccess.h>
+
+@@ -32,7 +33,7 @@
+ MODULE_AUTHOR("Carsten Paeth");
+ MODULE_LICENSE("GPL");
+
+-static char *revision = "$Revision: 1.1.4.1 $";
++static char *revision = "$Revision: 1.22 $";
+
+ struct capifs_ncci {
+ struct inode *inode;
+@@ -69,14 +70,21 @@
+ static int capifs_root_readdir(struct file *,void *,filldir_t);
+ static struct dentry *capifs_root_lookup(struct inode *,struct dentry *);
+ static int capifs_revalidate(struct dentry *, int);
++#ifdef COMPAT_VFS_2_4
+ static struct inode *capifs_new_inode(struct super_block *sb);
++#endif
+
+ static struct file_operations capifs_root_operations = {
++#ifdef COMPAT_VFS_2_4
+ read: generic_read_dir,
++#endif
+ readdir: capifs_root_readdir,
+ };
+
+ struct inode_operations capifs_root_inode_operations = {
++#ifndef COMPAT_VFS_2_4
++ default_file_ops: &capifs_root_operations, /* file operations */
++#endif
+ lookup: capifs_root_lookup,
+ };
+
+@@ -101,12 +109,20 @@
+ switch(nr)
+ {
+ case 0:
++#ifdef COMPAT_VFS_2_4
+ if (filldir(dirent, ".", 1, nr, inode->i_ino, DT_DIR) < 0)
++#else
++ if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0)
++#endif
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+ case 1:
++#ifdef COMPAT_VFS_2_4
+ if (filldir(dirent, "..", 2, nr, inode->i_ino, DT_DIR) < 0)
++#else
++ if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0)
++#endif
+ return 0;
+ filp->f_pos = ++nr;
+ /* fall through */
+@@ -118,7 +134,11 @@
+ char *p = numbuf;
+ if (np->type) *p++ = np->type;
+ sprintf(p, "%u", np->num);
++#ifdef COMPAT_VFS_2_4
+ if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr, DT_UNKNOWN) < 0 )
++#else
++ if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 )
++#endif
+ return 0;
+ }
+ filp->f_pos = ++nr;
+@@ -180,7 +200,7 @@
+
+ dentry->d_inode = np->inode;
+ if ( dentry->d_inode )
+- atomic_inc(&dentry->d_inode->i_count);
++ i_count_inc(dentry->d_inode->i_count);
+
+ d_add(dentry, dentry->d_inode);
+
+@@ -199,9 +219,9 @@
+
+ for ( i = 0 ; i < sbi->max_ncci ; i++ ) {
+ if ( (inode = sbi->nccis[i].inode) ) {
+- if (atomic_read(&inode->i_count) != 1 )
++ if (i_count_read(inode->i_count) != 1 )
+ printk("capifs_put_super: badness: entry %d count %d\n",
+- i, (unsigned)atomic_read(&inode->i_count));
++ i, (unsigned)i_count_read(inode->i_count));
+ inode->i_nlink--;
+ iput(inode);
+ }
+@@ -213,11 +233,24 @@
+
+ kfree(sbi->nccis);
+ kfree(sbi);
++#ifndef COMPAT_VFS_2_4
++ MOD_DEC_USE_COUNT;
++#endif
+ }
+
++#ifdef COMPAT_VFS_2_4
+ static int capifs_statfs(struct super_block *sb, struct statfs *buf);
++#else
++static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
++static void capifs_write_inode(struct inode *inode) { };
++static void capifs_read_inode(struct inode *inode);
++#endif
+
+ static struct super_operations capifs_sops = {
++#ifndef COMPAT_VFS_2_4
++ read_inode: capifs_read_inode,
++ write_inode: capifs_write_inode,
++#endif
+ put_super: capifs_put_super,
+ statfs: capifs_statfs,
+ };
+@@ -288,6 +321,10 @@
+ struct dentry * root;
+ struct capifs_sb_info *sbi;
+
++#ifndef COMPAT_VFS_2_4
++ MOD_INC_USE_COUNT;
++ lock_super(s);
++#endif
+ /* Super block already completed? */
+ if (s->s_root)
+ goto out;
+@@ -322,6 +359,7 @@
+ /*
+ * Get the root inode and dentry, but defer checking for errors.
+ */
++#ifdef COMPAT_VFS_2_4
+ root_inode = capifs_new_inode(s);
+ if (root_inode) {
+ root_inode->i_ino = 1;
+@@ -331,6 +369,10 @@
+ root_inode->i_nlink = 2;
+ }
+ root = d_alloc_root(root_inode);
++#else
++ root_inode = iget(s, 1); /* inode 1 == root directory */
++ root = d_alloc_root(root_inode, NULL);
++#endif
+
+ /*
+ * Check whether somebody else completed the super block.
+@@ -370,11 +412,34 @@
+ mounts = s;
+
+ out: /* Success ... somebody else completed the super block for us. */
++#ifndef COMPAT_VFS_2_4
++ unlock_super(s);
++#endif
+ return s;
+ fail:
++#ifndef COMPAT_VFS_2_4
++ unlock_super(s);
++ MOD_DEC_USE_COUNT;
++#endif
+ return NULL;
+ }
+
++#ifndef COMPAT_VFS_2_4
++static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
++{
++ struct statfs tmp;
++
++ tmp.f_type = CAPIFS_SUPER_MAGIC;
++ tmp.f_bsize = 1024;
++ tmp.f_blocks = 0;
++ tmp.f_bfree = 0;
++ tmp.f_bavail = 0;
++ tmp.f_files = 0;
++ tmp.f_ffree = 0;
++ tmp.f_namelen = NAME_MAX;
++ return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
++}
++#else
+ static int capifs_statfs(struct super_block *sb, struct statfs *buf)
+ {
+ buf->f_type = CAPIFS_SUPER_MAGIC;
+@@ -387,7 +452,9 @@
+ buf->f_namelen = NAME_MAX;
+ return 0;
+ }
++#endif
+
++#ifdef COMPAT_VFS_2_4
+ static struct inode *capifs_new_inode(struct super_block *sb)
+ {
+ struct inode *inode = new_inode(sb);
+@@ -399,8 +466,51 @@
+ }
+ return inode;
+ }
++#else
++static void capifs_read_inode(struct inode *inode)
++{
++ ino_t ino = inode->i_ino;
++ struct capifs_sb_info *sbi = SBI(inode->i_sb);
++
++ inode->i_mode = 0;
++ inode->i_nlink = 0;
++ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
++ inode->i_blocks = 0;
++ inode->i_blksize = 1024;
++ inode->i_uid = inode->i_gid = 0;
++
++ if ( ino == 1 ) {
++ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
++ inode->i_op = &capifs_root_inode_operations;
++ inode->i_nlink = 2;
++ return;
++ }
+
++ ino -= 2;
++ if ( ino >= sbi->max_ncci )
++ return; /* Bogus */
++
++#ifdef COMPAT_VFS_2_4
++ init_special_inode(inode, S_IFCHR, 0);
++#else
++ inode->i_mode = S_IFCHR;
++ inode->i_op = &chrdev_inode_operations;
++#endif
++
++ return;
++}
++#endif
++
++#ifndef COMPAT_VFS_2_4
++static struct file_system_type capifs_fs_type = {
++ "capifs",
++ 0,
++ capifs_read_super,
++ NULL
++};
++#else
+ static DECLARE_FSTYPE(capifs_fs_type, "capifs", capifs_read_super, 0);
++#endif
+
+ void capifs_new_ncci(char type, unsigned int num, kdev_t device)
+ {
+@@ -421,16 +531,26 @@
+ break;
+ }
+ }
++#ifdef COMPAT_VFS_2_4
+ if ( ino >= sbi->max_ncci )
+ continue;
+
+ if ((np->inode = capifs_new_inode(sb)) != NULL) {
++#else
++ if ((np->inode = iget(sb, ino+2)) != NULL) {
++#endif
+ struct inode *inode = np->inode;
+ inode->i_uid = sbi->setuid ? sbi->uid : current->fsuid;
+ inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid;
++#ifdef COMPAT_VFS_2_4
+ inode->i_nlink = 1;
+ inode->i_ino = ino + 2;
+ init_special_inode(inode, sbi->mode|S_IFCHR, np->kdev);
++#else
++ inode->i_mode = sbi->mode | S_IFCHR;
++ inode->i_rdev = np->kdev;
++ inode->i_nlink++;
++#endif
+ }
+ }
+ }
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/capifs.h linux-2.4.29/drivers/isdn/avmb1/capifs.h
+--- linux-2.4.29.old/drivers/isdn/avmb1/capifs.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/capifs.h 2005-03-22 15:06:44.965257024 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: capifs.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: capifs.h,v 1.4 2001/09/24 13:22:44 kai Exp $
+ *
+ * Copyright 2000 by Carsten Paeth <calle@calle.de>
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/capilli.h linux-2.4.29/drivers/isdn/avmb1/capilli.h
+--- linux-2.4.29.old/drivers/isdn/avmb1/capilli.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/capilli.h 2005-03-22 15:06:44.980254744 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: capilli.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: capilli.h,v 1.5 2001/09/24 13:22:44 kai Exp $
+ *
+ * Kernel CAPI 2.0 Driver Interface for Linux
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/capiutil.c linux-2.4.29/drivers/isdn/avmb1/capiutil.c
+--- linux-2.4.29.old/drivers/isdn/avmb1/capiutil.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/capiutil.c 2005-03-22 15:06:44.997252160 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: capiutil.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: capiutil.c,v 1.16 2001/09/24 13:22:44 kai Exp $
+ *
+ * CAPI 2.0 convert capi message to capi message struct
+ *
+@@ -19,6 +19,7 @@
+ #include <linux/init.h>
+ #include <asm/segment.h>
+ #include <linux/config.h>
++#include <linux/isdn_compat.h>
+ #include "capiutil.h"
+
+ MODULE_DESCRIPTION("CAPI4Linux: CAPI message conversion support");
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/capiutil.h linux-2.4.29/drivers/isdn/avmb1/capiutil.h
+--- linux-2.4.29.old/drivers/isdn/avmb1/capiutil.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/capiutil.h 2005-03-22 15:06:45.040245624 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: capiutil.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: capiutil.h,v 1.7 2001/09/24 13:22:44 kai Exp $
+ *
+ * CAPI 2.0 defines & types
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/kcapi.c linux-2.4.29/drivers/isdn/avmb1/kcapi.c
+--- linux-2.4.29.old/drivers/isdn/avmb1/kcapi.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/kcapi.c 2005-03-22 15:06:45.062242280 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: kcapi.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: kcapi.c,v 1.28 2001/09/24 13:22:44 kai Exp $
+ *
+ * Kernel CAPI 2.0 Module
+ *
+@@ -21,6 +21,7 @@
+ #include <linux/proc_fs.h>
+ #include <linux/skbuff.h>
+ #include <linux/tqueue.h>
++#include <linux/isdn_compat.h>
+ #include <linux/capi.h>
+ #include <linux/kernelcapi.h>
+ #include <linux/locks.h>
+@@ -33,7 +34,7 @@
+ #include <linux/b1lli.h>
+ #endif
+
+-static char *revision = "$Revision: 1.1.4.1 $";
++static char *revision = "$Revision: 1.28 $";
+
+ /* ------------------------------------------------------------- */
+
+@@ -64,7 +65,6 @@
+ __u32 ncci;
+ __u32 winsize;
+ int nmsg;
+- spinlock_t lock;
+ struct msgidqueue *msgidqueue;
+ struct msgidqueue *msgidlast;
+ struct msgidqueue *msgidfree;
+@@ -104,14 +104,14 @@
+ #define APPL(a) (&applications[(a)-1])
+ #define VALID_APPLID(a) ((a) && (a) <= CAPI_MAXAPPL && APPL(a)->applid == a)
+ #define APPL_IS_FREE(a) (APPL(a)->applid == 0)
+-#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0)
+-#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0)
++#define APPL_MARK_FREE(a) do{ APPL(a)->applid=0; MOD_DEC_USE_COUNT; }while(0);
++#define APPL_MARK_USED(a) do{ APPL(a)->applid=(a); MOD_INC_USE_COUNT; }while(0);
+
+ #define NCCI2CTRL(ncci) (((ncci) >> 24) & 0x7f)
+
+ #define VALID_CARD(c) ((c) > 0 && (c) <= CAPI_MAXCONTR)
+ #define CARD(c) (&cards[(c)-1])
+-#define CARDNR(cp) ((((cp)-cards)+1) & 0xff)
++#define CARDNR(cp) (((cp)-cards)+1)
+
+ static struct capi_appl applications[CAPI_MAXAPPL];
+ static struct capi_ctr cards[CAPI_MAXCONTR];
+@@ -535,9 +535,13 @@
+ * of devices. Devices can only removed in
+ * user process, not in bh.
+ */
++#ifdef COMPAT_HAS_SCHEDULE_TASK
+ MOD_INC_USE_COUNT;
+ if (schedule_task(&tq_state_notify) == 0)
+ MOD_DEC_USE_COUNT;
++#else
++ queue_task(&tq_state_notify, &tq_scheduler);
++#endif
+ return 0;
+ }
+
+@@ -546,13 +550,7 @@
+ static void notify_up(__u32 contr)
+ {
+ struct capi_interface_user *p;
+- __u16 appl;
+
+- for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
+- if (!VALID_APPLID(appl)) continue;
+- if (APPL(appl)->releasing) continue;
+- CARD(contr)->driver->register_appl(CARD(contr), appl, &APPL(appl)->rparam);
+- }
+ printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
+ spin_lock(&capi_users_lock);
+ for (p = capi_users; p; p = p->next) {
+@@ -639,7 +637,9 @@
+ kfree(np);
+ MOD_DEC_USE_COUNT;
+ }
++#ifdef COMPAT_HAS_SCHEDULE_TASK
+ MOD_DEC_USE_COUNT;
++#endif
+ }
+
+ /* -------- NCCI Handling ------------------------------------- */
+@@ -647,7 +647,6 @@
+ static inline void mq_init(struct capi_ncci * np)
+ {
+ int i;
+- np->lock = SPIN_LOCK_UNLOCKED;
+ np->msgidqueue = 0;
+ np->msgidlast = 0;
+ np->nmsg = 0;
+@@ -662,11 +661,8 @@
+ static inline int mq_enqueue(struct capi_ncci * np, __u16 msgid)
+ {
+ struct msgidqueue *mq;
+- spin_lock_bh(&np->lock);
+- if ((mq = np->msgidfree) == 0) {
+- spin_unlock_bh(&np->lock);
++ if ((mq = np->msgidfree) == 0)
+ return 0;
+- }
+ np->msgidfree = mq->next;
+ mq->msgid = msgid;
+ mq->next = 0;
+@@ -676,14 +672,12 @@
+ if (!np->msgidqueue)
+ np->msgidqueue = mq;
+ np->nmsg++;
+- spin_unlock_bh(&np->lock);
+ return 1;
+ }
+
+ static inline int mq_dequeue(struct capi_ncci * np, __u16 msgid)
+ {
+ struct msgidqueue **pp;
+- spin_lock_bh(&np->lock);
+ for (pp = &np->msgidqueue; *pp; pp = &(*pp)->next) {
+ if ((*pp)->msgid == msgid) {
+ struct msgidqueue *mq = *pp;
+@@ -693,11 +687,9 @@
+ mq->next = np->msgidfree;
+ np->msgidfree = mq;
+ np->nmsg--;
+- spin_unlock_bh(&np->lock);
+ return 1;
+ }
+ }
+- spin_unlock_bh(&np->lock);
+ return 0;
+ }
+
+@@ -720,16 +712,12 @@
+ nextpp = &(*pp)->next;
+ }
+ }
+- if (APPL(appl)->releasing) { /* only release if the application was marked for release */
+- printk(KERN_DEBUG "kcapi: appl %d releasing(%d)\n", appl, APPL(appl)->releasing);
+- APPL(appl)->releasing--;
+- if (APPL(appl)->releasing <= 0) {
+- APPL(appl)->signal = 0;
+- APPL_MARK_FREE(appl);
+- printk(KERN_INFO "kcapi: appl %d down\n", appl);
+- }
+- } else
+- printk(KERN_WARNING "kcapi: appl %d card%d released without request\n", appl, card->cnr);
++ APPL(appl)->releasing--;
++ if (APPL(appl)->releasing <= 0) {
++ APPL(appl)->signal = 0;
++ APPL_MARK_FREE(appl);
++ printk(KERN_INFO "kcapi: appl %d down\n", appl);
++ }
+ }
+ /*
+ * ncci management
+@@ -882,7 +870,16 @@
+
+ static void controllercb_ready(struct capi_ctr * card)
+ {
++ __u16 appl;
++
+ card->cardstate = CARD_RUNNING;
++
++ for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
++ if (!VALID_APPLID(appl)) continue;
++ if (APPL(appl)->releasing) continue;
++ card->driver->register_appl(card, appl, &APPL(appl)->rparam);
++ }
++
+ printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
+ CARDNR(card), card->name);
+
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/t1isa.c linux-2.4.29/drivers/isdn/avmb1/t1isa.c
+--- linux-2.4.29.old/drivers/isdn/avmb1/t1isa.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/t1isa.c 2005-03-22 15:06:45.078239848 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: t1isa.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: t1isa.c,v 1.22 2001/09/24 13:22:44 kai Exp $
+ *
+ * Module for AVM T1 HEMA-card.
+ *
+@@ -19,13 +19,14 @@
+ #include <linux/capi.h>
+ #include <linux/kernelcapi.h>
+ #include <linux/init.h>
++#include <linux/isdn_compat.h>
+ #include <asm/io.h>
+ #include "capicmd.h"
+ #include "capiutil.h"
+ #include "capilli.h"
+ #include "avmcard.h"
+
+-static char *revision = "$Revision: 1.1.4.1 $";
++static char *revision = "$Revision: 1.22 $";
+
+ /* ------------------------------------------------------------- */
+
+diff -rNu linux-2.4.29.old/drivers/isdn/avmb1/t1pci.c linux-2.4.29/drivers/isdn/avmb1/t1pci.c
+--- linux-2.4.29.old/drivers/isdn/avmb1/t1pci.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/avmb1/t1pci.c 2005-03-22 15:06:45.094237416 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: t1pci.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: t1pci.c,v 1.25 2001/09/24 13:22:44 kai Exp $
+ *
+ * Module for AVM T1 PCI-card.
+ *
+@@ -18,6 +18,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/ioport.h>
+ #include <linux/pci.h>
++#include <linux/isdn_compat.h>
+ #include <linux/capi.h>
+ #include <linux/init.h>
+ #include <asm/io.h>
+@@ -26,19 +27,21 @@
+ #include "capilli.h"
+ #include "avmcard.h"
+
+-static char *revision = "$Revision: 1.1.4.1 $";
++static char *revision = "$Revision: 1.25 $";
+
+ #undef CONFIG_T1PCI_DEBUG
+ #undef CONFIG_T1PCI_POLLDEBUG
+
+ /* ------------------------------------------------------------- */
+
++#ifndef COMPAT_HAS_2_2_PCI
+ static struct pci_device_id t1pci_pci_tbl[] __initdata = {
+ { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, PCI_ANY_ID, PCI_ANY_ID },
+ { } /* Terminating entry */
+ };
+
+ MODULE_DEVICE_TABLE(pci, t1pci_pci_tbl);
++#endif
+ MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 PCI card");
+ MODULE_AUTHOR("Carsten Paeth");
+ MODULE_LICENSE("GPL");
+@@ -264,9 +267,9 @@
+ }
+ pci_set_master(dev);
+
+- param.port = pci_resource_start(dev, 1);
++ param.port = pci_resource_start_io(dev, 1);
+ param.irq = dev->irq;
+- param.membase = pci_resource_start(dev, 0);
++ param.membase = pci_resource_start_mem(dev, 0);
+
+ printk(KERN_INFO
+ "%s: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
+diff -rNu linux-2.4.29.old/drivers/isdn/divert/divert_procfs.c linux-2.4.29/drivers/isdn/divert/divert_procfs.c
+--- linux-2.4.29.old/drivers/isdn/divert/divert_procfs.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/divert/divert_procfs.c 2005-03-22 15:06:45.158227688 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: divert_procfs.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id$
+ *
+ * Filesystem handling for the diversion supplementary services.
+ *
+@@ -14,13 +14,16 @@
+ #include <linux/module.h>
+ #include <linux/version.h>
+ #include <linux/poll.h>
++#ifndef COMPAT_USE_MODCOUNT_LOCK
+ #include <linux/smp_lock.h>
++#endif
+ #ifdef CONFIG_PROC_FS
+ #include <linux/proc_fs.h>
+ #else
+ #include <linux/fs.h>
+ #endif
+ #include <linux/isdnif.h>
++#include <linux/isdn_compat.h>
+ #include "isdn_divert.h"
+
+ /*********************************/
+@@ -80,7 +83,6 @@
+ isdn_divert_read(struct file *file, char *buf, size_t count, loff_t * off)
+ {
+ struct divert_info *inf;
+- loff_t pos = *off;
+ int len;
+
+ if (!*((struct divert_info **) file->private_data)) {
+@@ -92,11 +94,11 @@
+ return (0);
+
+ inf->usage_cnt--; /* new usage count */
+- file->private_data = &inf->next; /* next structure */
++ (struct divert_info **) file->private_data = &inf->next; /* next structure */
+ if ((len = strlen(inf->info_start)) <= count) {
+ if (copy_to_user(buf, inf->info_start, len))
+ return -EFAULT;
+- *off = pos + len;
++ file->f_pos += len;
+ return (len);
+ }
+ return (0);
+@@ -136,17 +138,23 @@
+ {
+ unsigned long flags;
+
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ MOD_INC_USE_COUNT;
++#else
+ lock_kernel();
++#endif
+ save_flags(flags);
+ cli();
+ if_used++;
+ if (divert_info_head)
+- filep->private_data = &(divert_info_tail->next);
++ (struct divert_info **) filep->private_data = &(divert_info_tail->next);
+ else
+- filep->private_data = &divert_info_head;
++ (struct divert_info **) filep->private_data = &divert_info_head;
+ restore_flags(flags);
+ /* start_divert(); */
++#ifndef COMPAT_USE_MODCOUNT_LOCK
+ unlock_kernel();
++#endif
+ return (0);
+ } /* isdn_divert_open */
+
+@@ -159,7 +167,9 @@
+ struct divert_info *inf;
+ unsigned long flags;
+
++#ifndef COMPAT_USE_MODCOUNT_LOCK
+ lock_kernel();
++#endif
+ save_flags(flags);
+ cli();
+ if_used--;
+@@ -175,7 +185,11 @@
+ divert_info_head = divert_info_head->next;
+ kfree(inf);
+ }
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ MOD_DEC_USE_COUNT;
++#else
+ unlock_kernel();
++#endif
+ return (0);
+ } /* isdn_divert_close */
+
+@@ -276,6 +290,9 @@
+ open: isdn_divert_open,
+ release: isdn_divert_close,
+ };
++#ifdef COMPAT_NO_SOFTNET
++struct inode_operations divert_file_inode_operations;
++#endif
+
+ /****************************/
+ /* isdn subdir in /proc/net */
+@@ -302,8 +319,16 @@
+ remove_proc_entry("isdn", proc_net);
+ return (-1);
+ }
++#ifdef COMPAT_NO_SOFTNET
++ memset(&divert_file_inode_operations, 0, sizeof(struct inode_operations));
++ divert_file_inode_operations.default_file_ops = &isdn_fops;
++ isdn_divert_entry->ops = &divert_file_inode_operations;
++#else
+ isdn_divert_entry->proc_fops = &isdn_fops;
++#ifdef COMPAT_HAS_FILEOP_OWNER
+ isdn_divert_entry->owner = THIS_MODULE;
++#endif
++#endif /* COMPAT_NO_SOFTNET */
+ #endif /* CONFIG_PROC_FS */
+
+ return (0);
+diff -rNu linux-2.4.29.old/drivers/isdn/divert/isdn_divert.c linux-2.4.29/drivers/isdn/divert/isdn_divert.c
+--- linux-2.4.29.old/drivers/isdn/divert/isdn_divert.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/divert/isdn_divert.c 2005-03-22 15:06:45.173225408 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_divert.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id$
+ *
+ * DSS1 main diversion supplementary handling for i4l.
+ *
+@@ -84,6 +84,9 @@
+ restore_flags(flags);
+ break;
+
++ case NETWORK_DIAL:
++ divert_if.dial_net_name(cs->deflect_dest);
++
+ case DEFLECT_AUTODEL:
+ default:
+ save_flags(flags);
+@@ -452,6 +455,7 @@
+ case DEFLECT_PROCEED:
+ case DEFLECT_REPORT:
+ case DEFLECT_REJECT:
++ case NETWORK_DIAL:
+ if (dv->rule.action == DEFLECT_PROCEED)
+ if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime)))
+ return(0); /* no external deflection needed */
+@@ -495,6 +499,11 @@
+ else
+ { cs->deflect_dest[0] = '\0';
+ retval = 4; /* only proceed */
++ if (cs->akt_state == NETWORK_DIAL) {
++ strcpy(cs->deflect_dest,dv->rule.to_nr);
++ cs->timer.expires = jiffies + 10;
++ retval = 0;
++ }
+ }
+ sprintf(cs->info,"%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
+ cs->akt_state,
+@@ -739,6 +748,18 @@
+ }
+
+
++#if 0
++ sprintf(st, "0x%lx 0x%lx",ic->arg, ic->parm.dss1_io.ll_id);
++ p = st + strlen(st);
++ p1 = ic->parm.dss1_io.data;
++ i = ic->parm.dss1_io.datalen;
++ while ((i > 0) && (p - st < 530))
++ { p += sprintf(p," %02x",(*p1++) & 0xFF);
++ i--;
++ }
++ sprintf(p, "\n");
++ put_info_buffer(st);
++#endif
+ break;
+
+ default:
+diff -rNu linux-2.4.29.old/drivers/isdn/divert/isdn_divert.h linux-2.4.29/drivers/isdn/divert/isdn_divert.h
+--- linux-2.4.29.old/drivers/isdn/divert/isdn_divert.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/divert/isdn_divert.h 2005-03-22 15:06:45.189222976 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_divert.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id$
+ *
+ * Header for the diversion supplementary ioctl interface.
+ *
+@@ -36,9 +36,10 @@
+ #define DEFLECT_PROCEED 2 /* deflect when externally triggered */
+ #define DEFLECT_ALERT 3 /* alert and deflect after delay */
+ #define DEFLECT_REJECT 4 /* reject immediately */
+-#define DIVERT_ACTIVATE 5 /* diversion activate */
+-#define DIVERT_DEACTIVATE 6 /* diversion deactivate */
+-#define DIVERT_REPORT 7 /* interrogation result */
++#define NETWORK_DIAL 5 /* dial a network interface */
++#define DIVERT_ACTIVATE 16 /* diversion activate */
++#define DIVERT_DEACTIVATE 17 /* diversion deactivate */
++#define DIVERT_REPORT 18 /* interrogation result */
+ #define DEFLECT_AUTODEL 255 /* only for internal use */
+
+ #define DEFLECT_ALL_IDS 0xFFFFFFFF /* all drivers selected */
+@@ -60,6 +61,7 @@
+ 2 = report call, send proceed, wait max waittime secs
+ 3 = report call, alert and deflect after waittime
+ 4 = report call, reject immediately
++ 5 = dial net interface specified in to_nr
+ actions 1-2 only take place if interface is opened
+ */
+ u_char waittime; /* maximum wait time for proceeding */
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/Divas_mod.c linux-2.4.29/drivers/isdn/eicon/Divas_mod.c
+--- linux-2.4.29.old/drivers/isdn/eicon/Divas_mod.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/Divas_mod.c 2005-03-22 15:06:45.229216896 +0100
+@@ -20,6 +20,7 @@
+ #include "adapter.h"
+ #include "uxio.h"
+
++#include <linux/isdn_compat.h>
+
+ MODULE_DESCRIPTION("ISDN4Linux: Driver for Eicon Diva Server cards");
+ MODULE_AUTHOR("Armin Schindler");
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/common.c linux-2.4.29/drivers/isdn/eicon/common.c
+--- linux-2.4.29.old/drivers/isdn/eicon/common.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/common.c 2005-03-22 15:06:45.301205952 +0100
+@@ -808,9 +808,7 @@
+
+ while(i--)
+ {
+- if (card->state == DIA_RUNNING)
+- DivaDoCardDpc(card);
+- card++;
++ DivaDoCardDpc(card++);
+ }
+ }
+
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/eicon.h linux-2.4.29/drivers/isdn/eicon/eicon.h
+--- linux-2.4.29.old/drivers/isdn/eicon/eicon.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/eicon.h 2005-03-22 15:06:45.371195312 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: eicon.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: eicon.h,v 1.26 2001/09/24 13:22:47 kai Exp $
+ *
+ * ISDN low-level module for Eicon active ISDN-Cards.
+ *
+@@ -348,19 +348,19 @@
+ extern char *eicon_ctype_name[];
+
+
+-static inline void eicon_schedule_tx(eicon_card *card)
++extern __inline__ void eicon_schedule_tx(eicon_card *card)
+ {
+ queue_task(&card->snd_tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+
+-static inline void eicon_schedule_rx(eicon_card *card)
++extern __inline__ void eicon_schedule_rx(eicon_card *card)
+ {
+ queue_task(&card->rcv_tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+
+-static inline void eicon_schedule_ack(eicon_card *card)
++extern __inline__ void eicon_schedule_ack(eicon_card *card)
+ {
+ queue_task(&card->ack_tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/eicon_dsp.h linux-2.4.29/drivers/isdn/eicon/eicon_dsp.h
+--- linux-2.4.29.old/drivers/isdn/eicon/eicon_dsp.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/eicon_dsp.h 2005-03-22 15:06:45.386193032 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: eicon_dsp.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: eicon_dsp.h,v 1.8 2001/09/24 13:22:47 kai Exp $
+ *
+ * ISDN lowlevel-module for Eicon active cards.
+ * DSP definitions
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/eicon_idi.c linux-2.4.29/drivers/isdn/eicon/eicon_idi.c
+--- linux-2.4.29.old/drivers/isdn/eicon/eicon_idi.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/eicon_idi.c 2005-03-22 15:06:45.421187712 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: eicon_idi.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: eicon_idi.c,v 1.45 2001/11/07 22:35:48 kai Exp $
+ *
+ * ISDN lowlevel-module for Eicon active cards.
+ * IDI interface
+@@ -25,7 +25,7 @@
+
+ #undef EICON_FULL_SERVICE_OKTETT
+
+-char *eicon_idi_revision = "$Revision: 1.1.4.1 $";
++char *eicon_idi_revision = "$Revision: 1.45 $";
+
+ eicon_manifbuf *manbuf;
+
+@@ -1583,6 +1583,37 @@
+ return;
+ }
+
++#if 0
++ eicon_sff_dochead *doc = (eicon_sff_dochead *)skb->data;
++ eicon_sff_pagehead *page = (eicon_sff_pagehead *)skb->data + sizeof(eicon_sff_dochead);
++
++ printk(KERN_DEBUG"SFF: doc %d / page %d (skb : %d)\n",
++ sizeof(eicon_sff_dochead),
++ sizeof(eicon_sff_pagehead), skb->len);
++
++ if (skb->len >= sizeof(eicon_sff_dochead)) {
++ printk(KERN_DEBUG"SFF: id = 0x%x\n", doc->id);
++ printk(KERN_DEBUG"SFF: version = 0x%x\n", doc->version);
++ printk(KERN_DEBUG"SFF: reserved1 = 0x%x\n", doc->reserved1);
++ printk(KERN_DEBUG"SFF: userinfo = 0x%x\n", doc->userinfo);
++ printk(KERN_DEBUG"SFF: pagecount = 0x%x\n", doc->pagecount);
++ printk(KERN_DEBUG"SFF: off1pagehead = 0x%x\n", doc->off1pagehead);
++ printk(KERN_DEBUG"SFF: offnpagehead = 0x%x\n", doc->offnpagehead);
++ printk(KERN_DEBUG"SFF: offdocend = 0x%x\n", doc->offdocend);
++ }
++ if (skb->len >= (sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead))) {
++ printk(KERN_DEBUG"SFFp: id = 0x%x\n", page->pageheadid);
++ printk(KERN_DEBUG"SFFp: len = 0x%x\n", page->pageheadlen);
++ printk(KERN_DEBUG"SFFp: resvert = 0x%x\n", page->resvert);
++ printk(KERN_DEBUG"SFFp: reshoriz = 0x%x\n", page->reshoriz);
++ printk(KERN_DEBUG"SFFp: coding = 0x%x\n", page->coding);
++ printk(KERN_DEBUG"SFFp: reserved2 = 0x%x\n", page->reserved2);
++ printk(KERN_DEBUG"SFFp: linelength = 0x%x\n", page->linelength);
++ printk(KERN_DEBUG"SFFp: pagelength = 0x%x\n", page->pagelength);
++ printk(KERN_DEBUG"SFFp: offprevpage = 0x%x\n", page->offprevpage);
++ printk(KERN_DEBUG"SFFp: offnextpage = 0x%x\n", page->offnextpage);
++ }
++#endif
+
+
+ if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
+@@ -2054,8 +2085,7 @@
+ OutBuf.Len++;
+ } else {
+ *OutBuf.Next++ = 0;
+- *(__u16 *) OutBuf.Next = (__u16) LineBuf.Len;
+- OutBuf.Next += sizeof(__u16);
++ *((__u16 *) OutBuf.Next)++ = (__u16) LineBuf.Len;
+ OutBuf.Len += 3;
+ }
+ memcpy(OutBuf.Next, LineBuf.Data, LineBuf.Len);
+@@ -2385,6 +2415,12 @@
+ } else {
+ if (chan->e.B2Id)
+ idi_do_req(ccard, chan, REMOVE, 1);
++#if 0
++ if (chan->e.D3Id) {
++ idi_do_req(ccard, chan, REMOVE, 0);
++ idi_do_req(ccard, chan, ASSIGN, 0);
++ }
++#endif
+ chan->statectrl &= ~WAITING_FOR_HANGUP;
+ chan->statectrl &= ~IN_HOLD;
+ if (chan->statectrl & HAVE_CONN_REQ) {
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/eicon_idi.h linux-2.4.29/drivers/isdn/eicon/eicon_idi.h
+--- linux-2.4.29.old/drivers/isdn/eicon/eicon_idi.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/eicon_idi.h 2005-03-22 15:06:45.437185280 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: eicon_idi.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: eicon_idi.h,v 1.12 2001/09/24 13:22:47 kai Exp $
+ *
+ * ISDN lowlevel-module for the Eicon active cards.
+ * IDI-Interface
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/eicon_io.c linux-2.4.29/drivers/isdn/eicon/eicon_io.c
+--- linux-2.4.29.old/drivers/isdn/eicon/eicon_io.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/eicon_io.c 2005-03-22 15:06:45.453182848 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: eicon_io.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: eicon_io.c,v 1.15 2001/09/24 13:22:47 kai Exp $
+ *
+ * ISDN low-level module for Eicon active ISDN-Cards.
+ * Code for communicating with hardware.
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/eicon_isa.c linux-2.4.29/drivers/isdn/eicon/eicon_isa.c
+--- linux-2.4.29.old/drivers/isdn/eicon/eicon_isa.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/eicon_isa.c 2005-03-22 15:06:45.469180416 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: eicon_isa.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: eicon_isa.c,v 1.18 2001/11/07 22:35:48 kai Exp $
+ *
+ * ISDN low-level module for Eicon active ISDN-Cards.
+ * Hardware-specific code for old ISA cards.
+@@ -20,7 +20,7 @@
+ #define release_shmem release_region
+ #define request_shmem request_region
+
+-char *eicon_isa_revision = "$Revision: 1.1.4.1 $";
++char *eicon_isa_revision = "$Revision: 1.18 $";
+
+ #undef EICON_MCA_DEBUG
+
+@@ -38,8 +38,12 @@
+ static void
+ eicon_isa_release_shmem(eicon_isa_card *card) {
+ if (card->mvalid) {
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ iounmap(card->shmem);
+ release_mem_region(card->physmem, card->ramsize);
++#else
++ release_shmem((unsigned long)card->shmem, card->ramsize);
++#endif
+ }
+ card->mvalid = 0;
+ }
+@@ -94,12 +98,20 @@
+ Mem, Id);
+ return -1;
+ }
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ if (check_mem_region(Mem, RAMSIZE)) {
++#else
++ if (check_shmem(Mem, RAMSIZE)) {
++#endif
+ printk(KERN_WARNING "eicon_isa_boot: memory at 0x%x already in use.\n", Mem);
+ return -1;
+ }
+
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ amem = (unsigned long) ioremap(Mem, RAMSIZE);
++#else
++ amem = (unsigned long) Mem;
++#endif
+ writew(0x55aa, amem + 0x402);
+ if (readw(amem + 0x402) != 0x55aa) primary = 0;
+ writew(0, amem + 0x402);
+@@ -109,12 +121,16 @@
+ if (primary) {
+ printk(KERN_INFO "Eicon: assuming pri card at 0x%x\n", Mem);
+ writeb(0, amem + 0x3ffe);
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ iounmap((unsigned char *)amem);
++#endif
+ return EICON_CTYPE_ISAPRI;
+ } else {
+ printk(KERN_INFO "Eicon: assuming bri card at 0x%x\n", Mem);
+ writeb(0, amem + 0x400);
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ iounmap((unsigned char *)amem);
++#endif
+ return EICON_CTYPE_ISABRI;
+ }
+ return -1;
+@@ -151,6 +167,7 @@
+ else
+ card->ramsize = RAMSIZE;
+
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ if (check_mem_region(card->physmem, card->ramsize)) {
+ printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n",
+ card->physmem);
+@@ -159,6 +176,16 @@
+ }
+ request_mem_region(card->physmem, card->ramsize, "Eicon ISA ISDN");
+ card->shmem = (eicon_isa_shmem *) ioremap(card->physmem, card->ramsize);
++#else
++ /* Register shmem */
++ if (check_shmem((unsigned long)card->shmem, card->ramsize)) {
++ printk(KERN_WARNING "eicon_isa_boot: memory at 0x%lx already in use.\n",
++ (unsigned long)card->shmem);
++ kfree(code);
++ return -EBUSY;
++ }
++ request_shmem((unsigned long)card->shmem, card->ramsize, "Eicon ISA ISDN");
++#endif
+ #ifdef EICON_MCA_DEBUG
+ printk(KERN_INFO "eicon_isa_boot: card->ramsize = %d.\n", card->ramsize);
+ #endif
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/eicon_isa.h linux-2.4.29/drivers/isdn/eicon/eicon_isa.h
+--- linux-2.4.29.old/drivers/isdn/eicon/eicon_isa.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/eicon_isa.h 2005-03-22 15:06:45.485177984 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: eicon_isa.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: eicon_isa.h,v 1.11 2001/09/24 13:22:47 kai Exp $
+ *
+ * ISDN low-level module for Eicon active ISDN-Cards.
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/eicon_mod.c linux-2.4.29/drivers/isdn/eicon/eicon_mod.c
+--- linux-2.4.29.old/drivers/isdn/eicon/eicon_mod.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/eicon_mod.c 2005-03-22 15:06:45.505174944 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: eicon_mod.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: eicon_mod.c,v 1.44 2001/11/20 09:48:25 armin Exp $
+ *
+ * ISDN lowlevel-module for Eicon active cards.
+ *
+@@ -44,7 +44,7 @@
+ static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains
+ start of card-list */
+
+-static char *eicon_revision = "$Revision: 1.1.4.1 $";
++static char *eicon_revision = "$Revision: 1.44 $";
+
+ extern char *eicon_pci_revision;
+ extern char *eicon_isa_revision;
+@@ -639,6 +639,18 @@
+ static int
+ if_writecmd(const u_char * buf, int len, int user, int id, int channel)
+ {
++#if 0
++ /* Not yet used */
++ eicon_card *card = eicon_findcard(id);
++
++ if (card) {
++ if (!card->flags & EICON_FLAGS_RUNNING)
++ return (len);
++ return (len);
++ }
++ printk(KERN_ERR
++ "eicon: if_writecmd called with invalid driverId!\n");
++#endif
+ return (len);
+ }
+
+@@ -665,11 +677,8 @@
+ else
+ cnt = skb->len;
+
+- if (user) {
+- spin_unlock_irqrestore(&eicon_lock, flags);
++ if (user)
+ copy_to_user(p, skb->data, cnt);
+- spin_lock_irqsave(&eicon_lock, flags);
+- }
+ else
+ memcpy(p, skb->data, cnt);
+
+@@ -1459,6 +1468,7 @@
+
+ #ifndef MODULE
+
++#ifdef COMPAT_HAS_NEW_SETUP
+ static int __init
+ eicon_setup(char *line)
+ {
+@@ -1467,6 +1477,12 @@
+ char *str;
+
+ str = get_options(line, 4, ints);
++#else
++void
++eicon_setup(char *str, int *ints)
++{
++ int i, argc;
++#endif
+
+ argc = ints[0];
+ i = 1;
+@@ -1494,9 +1510,13 @@
+ #else
+ printk(KERN_INFO "Eicon ISDN active driver setup\n");
+ #endif
++#ifdef COMPAT_HAS_NEW_SETUP
+ return(1);
+ }
+ __setup("eicon=", eicon_setup);
++#else
++}
++#endif
+
+ #endif /* MODULE */
+
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/eicon_pci.c linux-2.4.29/drivers/isdn/eicon/eicon_pci.c
+--- linux-2.4.29.old/drivers/isdn/eicon/eicon_pci.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/eicon_pci.c 2005-03-22 15:06:45.522172360 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: eicon_pci.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: eicon_pci.c,v 1.18 2001/09/24 13:22:47 kai Exp $
+ *
+ * ISDN low-level module for Eicon active ISDN-Cards.
+ * Hardware-specific code for PCI cards.
+@@ -24,7 +24,7 @@
+ #include "adapter.h"
+ #include "uxio.h"
+
+-char *eicon_pci_revision = "$Revision: 1.1.4.1 $";
++char *eicon_pci_revision = "$Revision: 1.18 $";
+
+ #if CONFIG_PCI /* intire stuff is only for PCI */
+ #ifdef CONFIG_ISDN_DRV_EICON_PCI
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/eicon_pci.h linux-2.4.29/drivers/isdn/eicon/eicon_pci.h
+--- linux-2.4.29.old/drivers/isdn/eicon/eicon_pci.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/eicon_pci.h 2005-03-22 15:06:45.538169928 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: eicon_pci.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: eicon_pci.h,v 1.7 2001/09/24 13:22:47 kai Exp $
+ *
+ * ISDN low-level module for Eicon active ISDN-Cards (PCI part).
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/fourbri.c linux-2.4.29/drivers/isdn/eicon/fourbri.c
+--- linux-2.4.29.old/drivers/isdn/eicon/fourbri.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/fourbri.c 2005-03-22 15:06:45.553167648 +0100
+@@ -337,8 +337,7 @@
+ static int diva_server_4bri_start(card_t *card, byte *channels)
+ {
+ byte *ctl;
+- byte *shared;
+- int i;
++ byte *shared, i;
+ int adapter_num;
+
+ DPRINTF(("divas: start Diva Server 4BRI"));
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/kprintf.c linux-2.4.29/drivers/isdn/eicon/kprintf.c
+--- linux-2.4.29.old/drivers/isdn/eicon/kprintf.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/kprintf.c 2005-03-22 15:06:45.601160352 +0100
+@@ -18,6 +18,468 @@
+ #include "divalog.h"
+ #include "uxio.h"
+
++/*
++ * Implementation of printf and sprintf for kernel
++ */
++
++#define MAX_BUFF (80) /* limit size of temporary buffers */
++
++#define WRITE_CHAR(BUFFER, SIZE, C) \
++ if (--(SIZE) < 0) { (BUFFER)--; *(BUFFER) = '\0'; return; } *(BUFFER)++ = (C)
++
++
++/*
++ * convert a number to decimal ASCII
++ */
++
++static
++void do_decimal( char *temp,
++ int temp_len,
++ unsigned int value,
++ char *s)
++
++{
++ int i;
++
++ temp[0] = '\0';
++
++ for (i = 1; i < temp_len; i++)
++ {
++ temp[i] = (char) ((value % 10) + (int) '0');
++ value /= 10;
++ }
++
++ for (i = (temp_len - 1); temp[i] == '0'; i--)
++ {
++ ;
++ }
++
++ if (i == 0)
++ {
++ i++;
++ }
++
++ while (i >= 0)
++ {
++ *s++ = temp[i--];
++ }
++
++ return;
++}
++
++/*
++ * convert a number to octal ASCII
++ */
++
++static
++void do_octal( char *temp,
++ unsigned int value,
++ char *s)
++
++{
++ int i;
++
++ temp[0] = '\0';
++
++ for (i = 1; i <= 11; i++)
++ {
++ temp[i] = (char) ((value & 07) + (int) '0');
++ value >>= 3;
++ }
++ temp[11] &= '3';
++
++ for (i = 11; temp[i] == '0'; i--)
++ {
++ ;
++ }
++
++ if (i == 0)
++ {
++ i++;
++ }
++
++ while (i >= 0)
++ {
++ *s++ = temp[i--];
++ }
++
++ return;
++}
++
++/*
++ * convert a number to hex ASCII
++ */
++
++static
++void do_hex( char *temp,
++ unsigned int value,
++ char *s)
++
++{
++ int i;
++ static
++ char *dec_to_hex = "0123456789abcdef";
++
++ temp[0] = '\0';
++
++ for (i = 1; i <= 8; i++)
++ {
++ temp[i] = dec_to_hex[value & 0x0f];
++ value >>= 4;
++ }
++
++ for (i = 8; temp[i] == '0'; i--)
++ {
++ ;
++ }
++
++ if (i == 0)
++ {
++ i++;
++ }
++
++ while (i >= 0)
++ {
++ *s++ = temp[i--];
++ }
++
++ return;
++}
++
++/*
++ * convert a buffer to ASCII HEX
++ */
++
++static
++void do_buffer( char *buffer,
++ int length,
++ char *s)
++
++{
++ static
++ char hex_char [] = "0123456789abcdef";
++ char *b = buffer;
++ int hex_byte;
++ int nybble;
++
++ length = (length >= ((MAX_BUFF / 3) + 1)) ? (MAX_BUFF / 3) : length;
++
++ while (length)
++ {
++ hex_byte = (int) *b++;
++ nybble = (hex_byte >> 4) & 0xf;
++ *s++ = hex_char[nybble];
++ nybble = hex_byte & 0xf;
++ *s++ = hex_char[nybble];
++ *s++ = ' ';
++ length--;
++ }
++ *s = '\0';
++
++ return;
++}
++
++/*
++ * Body of sprintf function: behaves just like standard sprintf, except we
++ * have an extra argument (buffer size) which we use to ensure we don't
++ * overflow
++ */
++
++void Divas_vsprintf( char *buffer,
++ int size,
++ char *fmt,
++ va_list argptr)
++
++{
++ char c; /* single character buffer */
++ int i; /* handy scratch counter */
++ int f; /* format character (after %) */
++ char *str; /* pointer into string */
++ char temp[20]; /* temp buffer used in printing numbers */
++ char string[MAX_BUFF]; /* output from number conversion */
++ int length; /* length of string "str" */
++ char fill; /* fill character ' ' or '0' */
++ boolean_t leftjust; /* TRUE if left justified, else right justified */
++ int fmax, fmin; /* field specifiers % MIN . MAX s */
++ int leading; /* number of leading/trailing fill characters */
++ char sign; /* set to '-' for negative decimals */
++ int number; /* numeric argument */
++
++ char *buff_ptr; /* pointer to user's buffer of hex data */
++ int buff_len; /* length of hex data */
++
++ /* make sure we have somthing to write into */
++
++ if ((!buffer) || (size <= 0))
++ {
++ return;
++ }
++
++ while (TRUE)
++ {
++ /* echo characters until end or '%' encountered */
++
++ while ((c = *fmt++) != '%')
++ {
++ if (!c)
++ {
++ *buffer = '\0';
++ return;
++ }
++ WRITE_CHAR(buffer, size, c);
++ }
++
++ /* echo %% as % */
++
++ if (*fmt == '%')
++ {
++ WRITE_CHAR(buffer, size, *fmt);
++ continue;
++ }
++
++ /* %- turns on left-justify */
++
++ if ((leftjust = (boolean_t) ((*fmt == '-') ? TRUE : FALSE)))
++ {
++ fmt++;
++ }
++
++ /* %0 turns on zero filling */
++
++ if (*fmt == '0')
++ {
++ fill = '0';
++ }
++ else
++ {
++ fill = ' ';
++ }
++
++ /* minium field width specifier for %d, u, x, c, s */
++
++ fmin = 0;
++
++ if (*fmt == '*')
++ {
++ fmin = va_arg(argptr, int);
++ fmt++;
++ }
++ else
++ {
++ while ('0' <= *fmt && *fmt <= '9')
++ {
++ fmin = (fmin * 10) + (*fmt++ - '0');
++ }
++ }
++
++ /* maximum string width specifier for %s */
++
++ fmax = 0;
++
++ if (*fmt == '.')
++ {
++ if (*(++fmt) == '*')
++ {
++ fmax = va_arg(argptr, int);
++ fmt++;
++ }
++ else
++ {
++ while ('0' <= *fmt && *fmt <= '9')
++ {
++ fmax = (fmax * 10) + (*fmt++ - '0');
++ }
++ }
++ }
++
++ /* skip over 'l' option (ints are assumed same size as longs) */
++
++ if (*fmt == 'l')
++ {
++ fmt++;
++ }
++
++ /* get the format chacater */
++
++ if (!(f = *fmt++))
++ {
++ WRITE_CHAR(buffer, size, '%');
++ *buffer = '\0';
++ return;
++ }
++
++ sign = '\0'; /* sign == '-' for negative decimal */
++
++ str = string;
++
++ switch (f)
++ {
++ case 'c' :
++ string[0] = (char) va_arg(argptr, int);
++ string[1] = '\0';
++ fmax = 0;
++ fill = ' ';
++ break;
++
++ case 's' :
++ str = va_arg(argptr, char *);
++ fill = ' ';
++ break;
++
++ case 'D' :
++ case 'd' :
++ number = va_arg(argptr, int);
++ if (number < 0)
++ {
++ sign = '-';
++ number = -number;
++ }
++ do_decimal(temp, DIM(temp), (unsigned int) number, str);
++ fmax = 0;
++ break;
++
++ case 'U' :
++ case 'u' :
++ number = va_arg(argptr, int);
++ do_decimal(temp, DIM(temp), (unsigned int) number, str);
++ fmax = 0;
++ break;
++
++ case 'O' :
++ case 'o' :
++ number = va_arg(argptr, int);
++ do_octal(temp, (unsigned int) number, str);
++ fmax = 0;
++ break;
++
++ case 'X' :
++ case 'x' :
++ number = va_arg(argptr, int);
++ do_hex(temp, (unsigned int) number, str);
++ fmax = 0;
++ break;
++
++ case 'H' :
++ case 'h' :
++ buff_ptr = va_arg(argptr, char *);
++ buff_len = va_arg(argptr, int);
++ do_buffer(buff_ptr, buff_len, str);
++ fmax = 0;
++ break;
++
++ default :
++ WRITE_CHAR(buffer, size, ((char) f));
++ break;
++ }
++
++ /* get the length of the string */
++
++ length = 0;
++ while (str[length])
++ {
++ length++;
++ }
++
++ /* make sure we have fmax and fmin values that are O.K. */
++
++ if (fmin > DIM(string) || fmin < 0)
++ {
++ fmin = 0;
++ }
++
++ if (fmax > DIM(string) || fmax < 0)
++ {
++ fmax = 0;
++ }
++
++ /* figure out how many leading characters thare are */
++
++ leading = 0;
++
++ if (fmax || fmin)
++ {
++ if (fmax)
++ {
++ if (length > fmax)
++ {
++ length = fmax;
++ }
++ }
++
++ if (fmin)
++ {
++ leading = fmin - length;
++ }
++
++ if (sign == '-')
++ {
++ leading--;
++ }
++ }
++
++ /* output sign now, if fill is numeric */
++
++ if (sign == '-' && fill == '0')
++ {
++ WRITE_CHAR(buffer, size, '-');
++ }
++
++ /* if right justified, output fill characters */
++
++ if (!leftjust)
++ {
++ for (i = 0; i < leading; i++)
++ {
++ WRITE_CHAR(buffer, size, fill);
++ }
++ }
++
++ /* output sign now, if fill is spaces */
++
++ if (sign == '-' && fill == ' ')
++ {
++ WRITE_CHAR(buffer, size, '-');
++ }
++
++ /* now the actual value */
++
++ for (i = 0; i < length; i++)
++ {
++ WRITE_CHAR(buffer, size, str[i]);
++ }
++
++ /* if left justified, fill out with the fill character */
++
++ if (leftjust)
++ {
++ for (i = 0; i < leading; i++)
++ {
++ WRITE_CHAR(buffer, size, fill);
++ }
++ }
++ }
++}
++
++/*
++ * sprintf for kernel
++ *
++ * call our vsprintf assuming user has a big buffer....
++ */
++
++void DivasSprintf(char *buffer, char *fmt, ...)
++
++{
++ va_list argptr; /* pointer to additional args */
++
++ va_start(argptr, fmt);
++
++ Divas_vsprintf(buffer, 1024, fmt, argptr);
++
++ va_end(argptr);
++
++ return;
++}
++
+ void DivasPrintf(char *fmt, ...)
+
+ {
+@@ -40,7 +502,7 @@
+
+ /* call vsprintf to format the user's information */
+
+- vsnprintf(log.buffer, DIM(log.buffer), fmt, argptr);
++ Divas_vsprintf(log.buffer, DIM(log.buffer), fmt, argptr);
+
+ va_end(argptr);
+
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/lincfg.c linux-2.4.29/drivers/isdn/eicon/lincfg.c
+--- linux-2.4.29.old/drivers/isdn/eicon/lincfg.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/lincfg.c 2005-03-22 15:06:45.620157464 +0100
+@@ -26,6 +26,9 @@
+ #include "uxio.h"
+
+ #include <linux/pci.h>
++#ifndef COMPAT_HAS_2_2_PCI
++#include <linux/pci_ids.h>
++#endif
+ #include <linux/kernel.h>
+ #include <linux/ioport.h>
+
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/linchr.c linux-2.4.29/drivers/isdn/eicon/linchr.c
+--- linux-2.4.29.old/drivers/isdn/eicon/linchr.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/linchr.c 2005-03-22 15:06:45.635155184 +0100
+@@ -154,17 +154,17 @@
+ klog_t *pHeadItem;
+
+ if (BufferSize < sizeof(klog_t))
++ {
++ printk(KERN_WARNING "Divas: Divalog buffer specifed a size that is too small (%d - %d required)\n",
++ BufferSize, sizeof(klog_t));
+ return -EIO;
++ }
+
+ pHeadItem = (klog_t *) DivasLogFifoRead();
+
+ if (pHeadItem)
+ {
+- if(copy_to_user(pClientLogBuffer, pHeadItem, sizeof(klog_t)))
+- {
+- kfree(pHeadItem);
+- return -EFAULT;
+- }
++ memcpy(pClientLogBuffer, pHeadItem, sizeof(klog_t));
+ kfree(pHeadItem);
+ return sizeof(klog_t);
+ }
+diff -rNu linux-2.4.29.old/drivers/isdn/eicon/linio.c linux-2.4.29/drivers/isdn/eicon/linio.c
+--- linux-2.4.29.old/drivers/isdn/eicon/linio.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/eicon/linio.c 2005-03-22 15:06:45.651152752 +0100
+@@ -15,6 +15,7 @@
+ #include <linux/slab.h>
+ #include <linux/pci.h>
+ #include <linux/delay.h>
++#include <linux/isdn_compat.h>
+ #undef N_DATA
+
+ #include "uxio.h"
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/Makefile linux-2.4.29/drivers/isdn/hisax/Makefile
+--- linux-2.4.29.old/drivers/isdn/hisax/Makefile 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/Makefile 2005-03-22 15:06:45.819127216 +0100
+@@ -4,20 +4,17 @@
+
+ O_TARGET := vmlinux-obj.o
+
+-# Define maximum number of cards
+-
+-EXTRA_CFLAGS += -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS)
+-
+ # Objects that export symbols.
+
+-export-objs := config.o hisax_isac.o isdnhdlc.o
++export-objs := config.o fsm.o hisax_isac.o
+
+ # Multipart objects.
+
+ list-multi := hisax.o hisax_st5481.o
+ hisax-objs := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
+ lmgr.o q931.o callc.o fsm.o cert.o
+-hisax_st5481-objs := st5481_init.o st5481_usb.o st5481_d.o st5481_b.o
++hisax_st5481-objs := st5481_init.o st5481_usb.o st5481_d.o st5481_b.o \
++ st5481_hdlc.o
+
+ # Optional parts of multipart objects.
+ hisax-objs-$(CONFIG_HISAX_EURO) += l3dss1.o
+@@ -33,7 +30,7 @@
+ hisax-objs-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o
+ hisax-objs-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o
+ hisax-objs-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o
+-hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipacx.o
++hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o
+ hisax-objs-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o
+ hisax-objs-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o
+ hisax-objs-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o isar.o
+@@ -44,6 +41,7 @@
+ hisax-objs-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o
+ hisax-objs-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o
+ hisax-objs-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o
++hisax-objs-$(CONFIG_HISAX_HFC_USB) += hfc_usbr.o
+ hisax-objs-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o
+ hisax-objs-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o
+ hisax-objs-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o
+@@ -51,7 +49,6 @@
+ hisax-objs-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o
+ hisax-objs-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o
+ hisax-objs-$(CONFIG_HISAX_W6692) += w6692.o
+-hisax-objs-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o
+ #hisax-objs-$(CONFIG_HISAX_TESTEMU) += testemu.o
+
+ hisax-objs += $(sort $(hisax-objs-y))
+@@ -61,10 +58,9 @@
+ obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o
+ obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o
+ obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o
+-obj-$(CONFIG_HISAX_AVM_A1_CS) += avma1_cs.o
+-obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o isdnhdlc.o
+-obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o
+-obj-$(CONFIG_USB_AUERISDN) += isdnhdlc.o
++obj-$(CONFIG_HISAX_HFC_USB_CS) += hfc_usb.o
++obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o
++obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_fcpcipnp.o hisax_isac.o
+
+ CERT := $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
+ CFLAGS_cert.o := -DCERTIFICATION=$(CERT)
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/amd7930.c linux-2.4.29/drivers/isdn/hisax/amd7930.c
+--- linux-2.4.29.old/drivers/isdn/hisax/amd7930.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/amd7930.c 2005-03-22 15:06:45.837124480 +0100
+@@ -0,0 +1,755 @@
++/* $Id: amd7930.c,v 1.8 2001/09/24 13:22:55 kai Exp $
++ *
++ * HiSax ISDN driver - chip specific routines for AMD 7930
++ *
++ * Author Brent Baccala
++ * Copyright by Brent Baccala <baccala@FreeSoft.org>
++ *
++ * This software may be used and distributed according to the terms
++ * of the GNU General Public License, incorporated herein by reference.
++ *
++ * - Existing ISDN HiSax driver provides all the smarts
++ * - it compiles, runs, talks to an isolated phone switch, connects
++ * to a Cisco, pings go through
++ * - AMD 7930 support only (no DBRI yet)
++ * - no US NI-1 support (may not work on US phone system - untested)
++ * - periodic packet loss, apparently due to lost interrupts
++ * - ISDN sometimes freezes, requiring reboot before it will work again
++ *
++ * The code is unreliable enough to be consider alpha
++ *
++ * This file is (c) under GNU General Public License
++ *
++ * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the
++ * SparcStation 1+. The chip provides microphone and speaker interfaces
++ * which provide mono-channel audio at 8K samples per second via either
++ * 8-bit A-law or 8-bit mu-law encoding. Also, the chip features an
++ * ISDN BRI Line Interface Unit (LIU), I.430 S/T physical interface,
++ * which performs basic D channel LAPD processing and provides raw
++ * B channel data. The digital audio channel, the two ISDN B channels,
++ * and two 64 Kbps channels to the microprocessor are all interconnected
++ * via a multiplexer.
++ *
++ * This driver interfaces to the Linux HiSax ISDN driver, which performs
++ * all high-level Q.921 and Q.931 ISDN functions. The file is not
++ * itself a hardware driver; rather it uses functions exported by
++ * the AMD7930 driver in the sparcaudio subsystem (drivers/sbus/audio),
++ * allowing the chip to be simultaneously used for both audio and ISDN data.
++ * The hardware driver does _no_ buffering, but provides several callbacks
++ * which are called during interrupt service and should therefore run quickly.
++ *
++ * D channel transmission is performed by passing the hardware driver the
++ * address and size of an skb's data area, then waiting for a callback
++ * to signal successful transmission of the packet. A task is then
++ * queued to notify the HiSax driver that another packet may be transmitted.
++ *
++ * D channel reception is quite simple, mainly because of:
++ * 1) the slow speed of the D channel - 16 kbps, and
++ * 2) the presence of an 8- or 32-byte (depending on chip version) FIFO
++ * to buffer the D channel data on the chip
++ * Worst case scenario of back-to-back packets with the 8 byte buffer
++ * at 16 kbps yields an service time of 4 ms - long enough to preclude
++ * the need for fancy buffering. We queue a background task that copies
++ * data out of the receive buffer into an skb, and the hardware driver
++ * simply does nothing until we're done with the receive buffer and
++ * reset it for a new packet.
++ *
++ * B channel processing is more complex, because of:
++ * 1) the faster speed - 64 kbps,
++ * 2) the lack of any on-chip buffering (it interrupts for every byte), and
++ * 3) the lack of any chip support for HDLC encapsulation
++ *
++ * The HiSax driver can put each B channel into one of three modes -
++ * L1_MODE_NULL (channel disabled), L1_MODE_TRANS (transparent data relay),
++ * and L1_MODE_HDLC (HDLC encapsulation by low-level driver).
++ * L1_MODE_HDLC is the most common, used for almost all "pure" digital
++ * data sessions. L1_MODE_TRANS is used for ISDN audio.
++ *
++ * HDLC B channel transmission is performed via a large buffer into
++ * which the skb is copied while performing HDLC bit-stuffing. A CRC
++ * is computed and attached to the end of the buffer, which is then
++ * passed to the low-level routines for raw transmission. Once
++ * transmission is complete, the hardware driver is set to enter HDLC
++ * idle by successive transmission of mark (all 1) bytes, waiting for
++ * the ISDN driver to prepare another packet for transmission and
++ * deliver it.
++ *
++ * HDLC B channel reception is performed via an X-byte ring buffer
++ * divided into N sections of X/N bytes each. Defaults: X=256 bytes, N=4.
++ * As the hardware driver notifies us that each section is full, we
++ * hand it the next section and schedule a background task to peruse
++ * the received section, bit-by-bit, with an HDLC decoder. As
++ * packets are detected, they are copied into a large buffer while
++ * decoding HDLC bit-stuffing. The ending CRC is verified, and if
++ * it is correct, we alloc a new skb of the correct length (which we
++ * now know), copy the packet into it, and hand it to the upper layers.
++ * Optimization: for large packets, we hand the buffer (which also
++ * happens to be an skb) directly to the upper layer after an skb_trim,
++ * and alloc a new large buffer for future packets, thus avoiding a copy.
++ * Then we return to HDLC processing; state is saved between calls.
++ *
++ */
++
++#define __NO_VERSION__
++#include "hisax.h"
++#include "../../sbus/audio/amd7930.h"
++#include "isac.h"
++#include "isdnl1.h"
++#include "rawhdlc.h"
++#include <linux/interrupt.h>
++
++static const char *amd7930_revision = "$Revision: 1.8 $";
++
++#define RCV_BUFSIZE 1024 /* Size of raw receive buffer in bytes */
++#define RCV_BUFBLKS 4 /* Number of blocks to divide buffer into
++ * (must divide RCV_BUFSIZE) */
++
++static void Bchan_fill_fifo(struct BCState *, struct sk_buff *);
++
++static void
++Bchan_xmt_bh(struct BCState *bcs)
++{
++ struct sk_buff *skb;
++
++ if (bcs->hw.amd7930.tx_skb != NULL) {
++ dev_kfree_skb(bcs->hw.amd7930.tx_skb);
++ bcs->hw.amd7930.tx_skb = NULL;
++ }
++
++ if ((skb = skb_dequeue(&bcs->squeue))) {
++ Bchan_fill_fifo(bcs, skb);
++ } else {
++ clear_bit(BC_FLG_BUSY, &bcs->Flag);
++ bcs->event |= 1 << B_XMTBUFREADY;
++ queue_task(&bcs->tqueue, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ }
++}
++
++static void
++Bchan_xmit_callback(struct BCState *bcs)
++{
++ queue_task(&bcs->hw.amd7930.tq_xmt, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++}
++
++/* B channel transmission: two modes (three, if you count L1_MODE_NULL)
++ *
++ * L1_MODE_HDLC - We need to do HDLC encapsulation before transmiting
++ * the packet (i.e. make_raw_hdlc_data). Since this can be a
++ * time-consuming operation, our completion callback just schedules
++ * a bottom half to do encapsulation for the next packet. In between,
++ * the link will just idle
++ *
++ * L1_MODE_TRANS - Data goes through, well, transparent. No HDLC encap,
++ * and we can't just let the link idle, so the "bottom half" actually
++ * gets called during the top half (it's our callback routine in this case),
++ * but it's a lot faster now since we don't call make_raw_hdlc_data
++ */
++
++static void
++Bchan_fill_fifo(struct BCState *bcs, struct sk_buff *skb)
++{
++ struct IsdnCardState *cs = bcs->cs;
++ int len;
++
++ if ((cs->debug & L1_DEB_HSCX) || (cs->debug & L1_DEB_HSCX_FIFO)) {
++ char tmp[1024];
++ char *t = tmp;
++
++ t += sprintf(t, "amd7930_fill_fifo %c cnt %d",
++ bcs->channel ? 'B' : 'A', skb->len);
++ if (cs->debug & L1_DEB_HSCX_FIFO)
++ QuickHex(t, skb->data, skb->len);
++ debugl1(cs, tmp);
++ }
++
++ if (bcs->mode == L1_MODE_HDLC) {
++ len = make_raw_hdlc_data(skb->data, skb->len,
++ bcs->hw.amd7930.tx_buff, RAW_BUFMAX);
++ if (len > 0)
++ amd7930_bxmit(0, bcs->channel,
++ bcs->hw.amd7930.tx_buff, len,
++ (void *) &Bchan_xmit_callback,
++ (void *) bcs);
++ dev_kfree_skb(skb);
++ } else if (bcs->mode == L1_MODE_TRANS) {
++ amd7930_bxmit(0, bcs->channel,
++ bcs->hw.amd7930.tx_buff, skb->len,
++ (void *) &Bchan_xmt_bh,
++ (void *) bcs);
++ bcs->hw.amd7930.tx_skb = skb;
++ } else {
++ dev_kfree_skb(skb);
++ }
++}
++
++static void
++Bchan_mode(struct BCState *bcs, int mode, int bc)
++{
++ struct IsdnCardState *cs = bcs->cs;
++
++ if (cs->debug & L1_DEB_HSCX) {
++ char tmp[40];
++ sprintf(tmp, "AMD 7930 mode %d bchan %d/%d",
++ mode, bc, bcs->channel);
++ debugl1(cs, tmp);
++ }
++ bcs->mode = mode;
++}
++
++/* Bchan_l2l1 is the entry point for upper layer routines that want to
++ * transmit on the B channel. PH_DATA_REQ is a normal packet that
++ * we either start transmitting (if idle) or queue (if busy).
++ * PH_PULL_REQ can be called to request a callback message (PH_PULL_CNF)
++ * once the link is idle. After a "pull" callback, the upper layer
++ * routines can use PH_PULL_IND to send data.
++ */
++
++static void
++Bchan_l2l1(struct PStack *st, int pr, void *arg)
++{
++ struct sk_buff *skb = arg;
++
++ switch (pr) {
++ case (PH_DATA_REQ):
++ if (test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
++ skb_queue_tail(&st->l1.bcs->squeue, skb);
++ } else {
++ test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
++ Bchan_fill_fifo(st->l1.bcs, skb);
++ }
++ break;
++ case (PH_PULL_IND):
++ if (test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
++ printk(KERN_WARNING "amd7930: this shouldn't happen\n");
++ break;
++ }
++ test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
++ Bchan_fill_fifo(st->l1.bcs, skb);
++ break;
++ case (PH_PULL_REQ):
++ if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag)) {
++ clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
++ st->l1.l1l2(st, PH_PULL_CNF, NULL);
++ } else
++ set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
++ break;
++ }
++}
++
++/* Receiver callback and bottom half - decodes HDLC at leisure (if
++ * L1_MODE_HDLC) and passes newly received skb on via bcs->rqueue. If
++ * a large packet is received, stick rv_skb (the buffer that the
++ * packet has been decoded into) on the receive queue and alloc a new
++ * (large) skb to act as buffer for future receives. If a small
++ * packet is received, leave rv_skb alone, alloc a new skb of the
++ * correct size, and copy the packet into it
++ */
++
++static void
++Bchan_recv_callback(struct BCState *bcs)
++{
++ struct amd7930_hw *hw = &bcs->hw.amd7930;
++
++ hw->rv_buff_in += RCV_BUFSIZE/RCV_BUFBLKS;
++ hw->rv_buff_in %= RCV_BUFSIZE;
++
++ if (hw->rv_buff_in != hw->rv_buff_out) {
++ amd7930_brecv(0, bcs->channel,
++ hw->rv_buff + hw->rv_buff_in,
++ RCV_BUFSIZE/RCV_BUFBLKS,
++ (void *) &Bchan_recv_callback, (void *) bcs);
++ }
++
++ queue_task(&hw->tq_rcv, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++}
++
++static void
++Bchan_rcv_bh(struct BCState *bcs)
++{
++ struct IsdnCardState *cs = bcs->cs;
++ struct amd7930_hw *hw = &bcs->hw.amd7930;
++ struct sk_buff *skb;
++ int len;
++
++ if (cs->debug & L1_DEB_HSCX) {
++ char tmp[1024];
++
++ sprintf(tmp, "amd7930_Bchan_rcv (%d/%d)",
++ hw->rv_buff_in, hw->rv_buff_out);
++ debugl1(cs, tmp);
++ QuickHex(tmp, hw->rv_buff + hw->rv_buff_out,
++ RCV_BUFSIZE/RCV_BUFBLKS);
++ debugl1(cs, tmp);
++ }
++
++ do {
++ if (bcs->mode == L1_MODE_HDLC) {
++ while ((len = read_raw_hdlc_data(hw->hdlc_state,
++ hw->rv_buff + hw->rv_buff_out, RCV_BUFSIZE/RCV_BUFBLKS,
++ hw->rv_skb->tail, HSCX_BUFMAX))) {
++ if (len > 0 && (cs->debug & L1_DEB_HSCX_FIFO)) {
++ char tmp[1024];
++ char *t = tmp;
++
++ t += sprintf(t, "amd7930_Bchan_rcv %c cnt %d", bcs->channel ? 'B' : 'A', len);
++ QuickHex(t, hw->rv_skb->tail, len);
++ debugl1(cs, tmp);
++ }
++
++ if (len > HSCX_BUFMAX/2) {
++ /* Large packet received */
++
++ if (!(skb = dev_alloc_skb(HSCX_BUFMAX))) {
++ printk(KERN_WARNING "amd7930: receive out of memory");
++ } else {
++ skb_put(hw->rv_skb, len);
++ skb_queue_tail(&bcs->rqueue, hw->rv_skb);
++ hw->rv_skb = skb;
++ bcs->event |= 1 << B_RCVBUFREADY;
++ queue_task(&bcs->tqueue, &tq_immediate);
++ }
++ } else if (len > 0) {
++ /* Small packet received */
++
++ if (!(skb = dev_alloc_skb(len))) {
++ printk(KERN_WARNING "amd7930: receive out of memory\n");
++ } else {
++ memcpy(skb_put(skb, len), hw->rv_skb->tail, len);
++ skb_queue_tail(&bcs->rqueue, skb);
++ bcs->event |= 1 << B_RCVBUFREADY;
++ queue_task(&bcs->tqueue, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ }
++ } else {
++ /* Reception Error */
++ /* printk("amd7930: B channel receive error\n"); */
++ }
++ }
++ } else if (bcs->mode == L1_MODE_TRANS) {
++ if (!(skb = dev_alloc_skb(RCV_BUFSIZE/RCV_BUFBLKS))) {
++ printk(KERN_WARNING "amd7930: receive out of memory\n");
++ } else {
++ memcpy(skb_put(skb, RCV_BUFSIZE/RCV_BUFBLKS),
++ hw->rv_buff + hw->rv_buff_out,
++ RCV_BUFSIZE/RCV_BUFBLKS);
++ skb_queue_tail(&bcs->rqueue, skb);
++ bcs->event |= 1 << B_RCVBUFREADY;
++ queue_task(&bcs->tqueue, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ }
++ }
++
++ if (hw->rv_buff_in == hw->rv_buff_out) {
++ /* Buffer was filled up - need to restart receiver */
++ amd7930_brecv(0, bcs->channel,
++ hw->rv_buff + hw->rv_buff_in,
++ RCV_BUFSIZE/RCV_BUFBLKS,
++ (void *) &Bchan_recv_callback,
++ (void *) bcs);
++ }
++
++ hw->rv_buff_out += RCV_BUFSIZE/RCV_BUFBLKS;
++ hw->rv_buff_out %= RCV_BUFSIZE;
++
++ } while (hw->rv_buff_in != hw->rv_buff_out);
++}
++
++static void
++Bchan_close(struct BCState *bcs)
++{
++ struct sk_buff *skb;
++
++ Bchan_mode(bcs, 0, 0);
++ amd7930_bclose(0, bcs->channel);
++
++ if (test_bit(BC_FLG_INIT, &bcs->Flag)) {
++ skb_queue_purge(&bcs->rqueue);
++ skb_queue_purge(&bcs->squeue);
++ }
++ test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
++}
++
++static int
++Bchan_open(struct BCState *bcs)
++{
++ struct amd7930_hw *hw = &bcs->hw.amd7930;
++
++ if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
++ skb_queue_head_init(&bcs->rqueue);
++ skb_queue_head_init(&bcs->squeue);
++ }
++ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
++
++ amd7930_bopen(0, bcs->channel, 0xff);
++ hw->rv_buff_in = 0;
++ hw->rv_buff_out = 0;
++ hw->tx_skb = NULL;
++ init_hdlc_state(hw->hdlc_state, 0);
++ amd7930_brecv(0, bcs->channel,
++ hw->rv_buff + hw->rv_buff_in, RCV_BUFSIZE/RCV_BUFBLKS,
++ (void *) &Bchan_recv_callback, (void *) bcs);
++
++ bcs->event = 0;
++ bcs->tx_cnt = 0;
++ return (0);
++}
++
++static void
++Bchan_init(struct BCState *bcs)
++{
++ if (!(bcs->hw.amd7930.tx_buff = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) {
++ printk(KERN_WARNING
++ "HiSax: No memory for amd7930.tx_buff\n");
++ return;
++ }
++ if (!(bcs->hw.amd7930.rv_buff = kmalloc(RCV_BUFSIZE, GFP_ATOMIC))) {
++ printk(KERN_WARNING
++ "HiSax: No memory for amd7930.rv_buff\n");
++ return;
++ }
++ if (!(bcs->hw.amd7930.rv_skb = dev_alloc_skb(HSCX_BUFMAX))) {
++ printk(KERN_WARNING
++ "HiSax: No memory for amd7930.rv_skb\n");
++ return;
++ }
++ if (!(bcs->hw.amd7930.hdlc_state = kmalloc(sizeof(struct hdlc_state),
++ GFP_ATOMIC))) {
++ printk(KERN_WARNING
++ "HiSax: No memory for amd7930.hdlc_state\n");
++ return;
++ }
++
++ bcs->hw.amd7930.tq_rcv.sync = 0;
++ bcs->hw.amd7930.tq_rcv.routine = (void (*)(void *)) &Bchan_rcv_bh;
++ bcs->hw.amd7930.tq_rcv.data = (void *) bcs;
++
++ bcs->hw.amd7930.tq_xmt.sync = 0;
++ bcs->hw.amd7930.tq_xmt.routine = (void (*)(void *)) &Bchan_xmt_bh;
++ bcs->hw.amd7930.tq_xmt.data = (void *) bcs;
++}
++
++static void
++Bchan_manl1(struct PStack *st, int pr,
++ void *arg)
++{
++ switch (pr) {
++ case (PH_ACTIVATE_REQ):
++ test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
++ Bchan_mode(st->l1.bcs, st->l1.mode, st->l1.bc);
++ st->l1.l1man(st, PH_ACTIVATE_CNF, NULL);
++ break;
++ case (PH_DEACTIVATE_REQ):
++ if (!test_bit(BC_FLG_BUSY, &st->l1.bcs->Flag))
++ Bchan_mode(st->l1.bcs, 0, 0);
++ test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
++ break;
++ }
++}
++
++int
++setstack_amd7930(struct PStack *st, struct BCState *bcs)
++{
++ if (Bchan_open(bcs))
++ return (-1);
++ st->l1.bcs = bcs;
++ st->l2.l2l1 = Bchan_l2l1;
++ st->ma.manl1 = Bchan_manl1;
++ setstack_manager(st);
++ bcs->st = st;
++ return (0);
++}
++
++
++static void
++amd7930_drecv_callback(void *arg, int error, unsigned int count)
++{
++ struct IsdnCardState *cs = (struct IsdnCardState *) arg;
++ static struct tq_struct task;
++ struct sk_buff *skb;
++
++ /* NOTE: This function is called directly from an interrupt handler */
++
++ if (1) {
++ if (!(skb = alloc_skb(count, GFP_ATOMIC)))
++ printk(KERN_WARNING "HiSax: D receive out of memory\n");
++ else {
++ memcpy(skb_put(skb, count), cs->rcvbuf, count);
++ skb_queue_tail(&cs->rq, skb);
++ }
++
++ task.routine = (void *) DChannel_proc_rcv;
++ task.data = (void *) cs;
++ queue_task(&task, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ }
++
++ if (cs->debug & L1_DEB_ISAC_FIFO) {
++ char tmp[128];
++ char *t = tmp;
++
++ t += sprintf(t, "amd7930 Drecv cnt %d", count);
++ if (error) t += sprintf(t, " ERR %x", error);
++ QuickHex(t, cs->rcvbuf, count);
++ debugl1(cs, tmp);
++ }
++
++ amd7930_drecv(0, cs->rcvbuf, MAX_DFRAME_LEN,
++ &amd7930_drecv_callback, cs);
++}
++
++static void
++amd7930_dxmit_callback(void *arg, int error)
++{
++ struct IsdnCardState *cs = (struct IsdnCardState *) arg;
++ static struct tq_struct task;
++
++ /* NOTE: This function is called directly from an interrupt handler */
++
++ /* may wish to do retransmission here, if error indicates collision */
++
++ if (cs->debug & L1_DEB_ISAC_FIFO) {
++ char tmp[128];
++ char *t = tmp;
++
++ t += sprintf(t, "amd7930 Dxmit cnt %d", cs->tx_skb->len);
++ if (error) t += sprintf(t, " ERR %x", error);
++ QuickHex(t, cs->tx_skb->data, cs->tx_skb->len);
++ debugl1(cs, tmp);
++ }
++
++ cs->tx_skb = NULL;
++
++ task.routine = (void *) DChannel_proc_xmt;
++ task.data = (void *) cs;
++ queue_task(&task, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++}
++
++static void
++amd7930_Dchan_l2l1(struct PStack *st, int pr, void *arg)
++{
++ struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
++ struct sk_buff *skb = arg;
++ char str[64];
++
++ switch (pr) {
++ case (PH_DATA_REQ):
++ if (cs->tx_skb) {
++ skb_queue_tail(&cs->sq, skb);
++#ifdef L2FRAME_DEBUG /* psa */
++ if (cs->debug & L1_DEB_LAPD)
++ Logl2Frame(cs, skb, "PH_DATA Queued", 0);
++#endif
++ } else {
++ if ((cs->dlogflag) && (!(skb->data[2] & 1))) {
++ /* I-FRAME */
++ LogFrame(cs, skb->data, skb->len);
++ sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
++ dlogframe(cs, skb->data+4, skb->len-4,
++ str);
++ }
++ cs->tx_skb = skb;
++ cs->tx_cnt = 0;
++#ifdef L2FRAME_DEBUG /* psa */
++ if (cs->debug & L1_DEB_LAPD)
++ Logl2Frame(cs, skb, "PH_DATA", 0);
++#endif
++ amd7930_dxmit(0, skb->data, skb->len,
++ &amd7930_dxmit_callback, cs);
++ }
++ break;
++ case (PH_PULL_IND):
++ if (cs->tx_skb) {
++ if (cs->debug & L1_DEB_WARN)
++ debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
++ skb_queue_tail(&cs->sq, skb);
++ break;
++ }
++ if ((cs->dlogflag) && (!(skb->data[2] & 1))) { /* I-FRAME */
++ LogFrame(cs, skb->data, skb->len);
++ sprintf(str, "Q.931 frame user->network tei %d", st->l2.tei);
++ dlogframe(cs, skb->data + 4, skb->len - 4,
++ str);
++ }
++ cs->tx_skb = skb;
++ cs->tx_cnt = 0;
++#ifdef L2FRAME_DEBUG /* psa */
++ if (cs->debug & L1_DEB_LAPD)
++ Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
++#endif
++ amd7930_dxmit(0, cs->tx_skb->data, cs->tx_skb->len,
++ &amd7930_dxmit_callback, cs);
++ break;
++ case (PH_PULL_REQ):
++#ifdef L2FRAME_DEBUG /* psa */
++ if (cs->debug & L1_DEB_LAPD)
++ debugl1(cs, "-> PH_REQUEST_PULL");
++#endif
++ if (!cs->tx_skb) {
++ test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
++ st->l1.l1l2(st, PH_PULL_CNF, NULL);
++ } else
++ test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
++ break;
++ }
++}
++
++int
++setDstack_amd7930(struct PStack *st, struct IsdnCardState *cs)
++{
++ st->l2.l2l1 = amd7930_Dchan_l2l1;
++ if (! cs->rcvbuf) {
++ printk("setDstack_amd7930: No cs->rcvbuf!\n");
++ } else {
++ amd7930_drecv(0, cs->rcvbuf, MAX_DFRAME_LEN,
++ &amd7930_drecv_callback, cs);
++ }
++ return (0);
++}
++
++static void
++manl1_msg(struct IsdnCardState *cs, int msg, void *arg) {
++ struct PStack *st;
++
++ st = cs->stlist;
++ while (st) {
++ st->ma.manl1(st, msg, arg);
++ st = st->next;
++ }
++}
++
++static void
++amd7930_new_ph(struct IsdnCardState *cs)
++{
++ switch (amd7930_get_liu_state(0)) {
++ case 3:
++ manl1_msg(cs, PH_POWERUP_CNF, NULL);
++ break;
++
++ case 7:
++ manl1_msg(cs, PH_I4_P8_IND, NULL);
++ break;
++
++ case 8:
++ manl1_msg(cs, PH_RSYNC_IND, NULL);
++ break;
++ }
++}
++
++/* amd7930 LIU state change callback */
++
++static void
++amd7930_liu_callback(struct IsdnCardState *cs)
++{
++ static struct tq_struct task;
++
++ if (!cs)
++ return;
++
++ if (cs->debug & L1_DEB_ISAC) {
++ char tmp[32];
++ sprintf(tmp, "amd7930_liu state %d", amd7930_get_liu_state(0));
++ debugl1(cs, tmp);
++ }
++
++ task.sync = 0;
++ task.routine = (void *) &amd7930_new_ph;
++ task.data = (void *) cs;
++ queue_task(&task, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++}
++
++void
++amd7930_l1cmd(struct IsdnCardState *cs, int msg, void *arg)
++{
++ u_char val;
++ char tmp[32];
++
++ if (cs->debug & L1_DEB_ISAC) {
++ char tmp[32];
++ sprintf(tmp, "amd7930_l1cmd msg %x", msg);
++ debugl1(cs, tmp);
++ }
++
++ switch(msg) {
++ case PH_RESET_REQ:
++ if (amd7930_get_liu_state(0) <= 3)
++ amd7930_liu_activate(0,0);
++ else
++ amd7930_liu_deactivate(0);
++ break;
++ case PH_ENABLE_REQ:
++ break;
++ case PH_INFO3_REQ:
++ amd7930_liu_activate(0,0);
++ break;
++ case PH_TESTLOOP_REQ:
++ break;
++ default:
++ if (cs->debug & L1_DEB_WARN) {
++ sprintf(tmp, "amd7930_l1cmd unknown %4x", msg);
++ debugl1(cs, tmp);
++ }
++ break;
++ }
++}
++
++static void init_amd7930(struct IsdnCardState *cs)
++{
++ Bchan_init(&cs->bcs[0]);
++ Bchan_init(&cs->bcs[1]);
++ cs->bcs[0].BC_SetStack = setstack_amd7930;
++ cs->bcs[1].BC_SetStack = setstack_amd7930;
++ cs->bcs[0].BC_Close = Bchan_close;
++ cs->bcs[1].BC_Close = Bchan_close;
++ Bchan_mode(cs->bcs, 0, 0);
++ Bchan_mode(cs->bcs + 1, 0, 0);
++}
++
++void
++release_amd7930(struct IsdnCardState *cs)
++{
++}
++
++static int
++amd7930_card_msg(struct IsdnCardState *cs, int mt, void *arg)
++{
++ switch (mt) {
++ case CARD_RESET:
++ return(0);
++ case CARD_RELEASE:
++ release_amd7930(cs);
++ return(0);
++ case CARD_INIT:
++ cs->l1cmd = amd7930_l1cmd;
++ amd7930_liu_init(0, &amd7930_liu_callback, (void *)cs);
++ init_amd7930(cs);
++ return(0);
++ case CARD_TEST:
++ return(0);
++ }
++ return(0);
++}
++
++int __init
++setup_amd7930(struct IsdnCard *card)
++{
++ struct IsdnCardState *cs = card->cs;
++ char tmp[64];
++
++ strcpy(tmp, amd7930_revision);
++ printk(KERN_INFO "HiSax: AMD7930 driver Rev. %s\n", HiSax_getrev(tmp));
++ if (cs->typ != ISDN_CTYPE_AMD7930)
++ return (0);
++
++ cs->irq = amd7930_get_irqnum(0);
++ if (cs->irq == 0)
++ return (0);
++
++ cs->cardmsg = &amd7930_card_msg;
++
++ return (1);
++}
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/arcofi.c linux-2.4.29/drivers/isdn/hisax/arcofi.c
+--- linux-2.4.29.old/drivers/isdn/hisax/arcofi.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/arcofi.c 2005-03-22 15:06:45.852122200 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: arcofi.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: arcofi.c,v 1.14 2001/09/24 13:22:55 kai Exp $
+ *
+ * Ansteuerung ARCOFI 2165
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/arcofi.h linux-2.4.29/drivers/isdn/hisax/arcofi.h
+--- linux-2.4.29.old/drivers/isdn/hisax/arcofi.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/arcofi.h 2005-03-22 15:06:45.872119160 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: arcofi.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id$
+ *
+ * Ansteuerung ARCOFI 2165
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/asuscom.c linux-2.4.29/drivers/isdn/hisax/asuscom.c
+--- linux-2.4.29.old/drivers/isdn/hisax/asuscom.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/asuscom.c 2005-03-22 15:06:45.889116576 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: asuscom.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: asuscom.c,v 1.14 2001/09/24 13:22:55 kai Exp $
+ *
+ * low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
+ *
+@@ -14,7 +14,6 @@
+
+ #define __NO_VERSION__
+ #include <linux/init.h>
+-#include <linux/isapnp.h>
+ #include "hisax.h"
+ #include "isac.h"
+ #include "ipac.h"
+@@ -23,7 +22,7 @@
+
+ extern const char *CardType[];
+
+-const char *Asuscom_revision = "$Revision: 1.1.4.1 $";
++const char *Asuscom_revision = "$Revision: 1.14 $";
+
+ #define byteout(addr,val) outb(val,addr)
+ #define bytein(addr) inb(addr)
+@@ -310,27 +309,6 @@
+ return(0);
+ }
+
+-#ifdef __ISAPNP__
+-static struct isapnp_device_id asus_ids[] __initdata = {
+- { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
+- ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
+- (unsigned long) "Asus1688 PnP" },
+- { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
+- ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
+- (unsigned long) "Asus1690 PnP" },
+- { ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
+- ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
+- (unsigned long) "Isurf2 PnP" },
+- { ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
+- ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
+- (unsigned long) "Iscas TE320" },
+- { 0, }
+-};
+-
+-static struct isapnp_device_id *adev = &asus_ids[0];
+-static struct pci_bus *pnp_c __devinitdata = NULL;
+-#endif
+-
+ int __init
+ setup_asuscom(struct IsdnCard *card)
+ {
+@@ -343,45 +321,7 @@
+ printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_ASUSCOM)
+ return (0);
+-#ifdef __ISAPNP__
+- if (!card->para[1] && isapnp_present()) {
+- struct pci_bus *pb;
+- struct pci_dev *pd;
+-
+- while(adev->card_vendor) {
+- if ((pb = isapnp_find_card(adev->card_vendor,
+- adev->card_device, pnp_c))) {
+- pnp_c = pb;
+- pd = NULL;
+- if ((pd = isapnp_find_dev(pnp_c,
+- adev->vendor, adev->function, pd))) {
+- printk(KERN_INFO "HiSax: %s detected\n",
+- (char *)adev->driver_data);
+- pd->prepare(pd);
+- pd->deactivate(pd);
+- pd->activate(pd);
+- card->para[1] = pd->resource[0].start;
+- card->para[0] = pd->irq_resource[0].start;
+- if (!card->para[0] || !card->para[1]) {
+- printk(KERN_ERR "AsusPnP:some resources are missing %ld/%lx\n",
+- card->para[0], card->para[1]);
+- pd->deactivate(pd);
+- return(0);
+- }
+- break;
+- } else {
+- printk(KERN_ERR "AsusPnP: PnP error card found, no device\n");
+- }
+- }
+- adev++;
+- pnp_c=NULL;
+- }
+- if (!adev->card_vendor) {
+- printk(KERN_INFO "AsusPnP: no ISAPnP card found\n");
+- return(0);
+- }
+- }
+-#endif
++
+ bytecnt = 8;
+ cs->hw.asus.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/avm_a1.c linux-2.4.29/drivers/isdn/hisax/avm_a1.c
+--- linux-2.4.29.old/drivers/isdn/hisax/avm_a1.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/avm_a1.c 2005-03-22 15:06:45.904114296 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: avm_a1.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: avm_a1.c,v 2.15 2001/09/24 13:22:55 kai Exp $
+ *
+ * low level stuff for AVM A1 (Fritz) isdn cards
+ *
+@@ -18,7 +18,7 @@
+ #include "isdnl1.h"
+
+ extern const char *CardType[];
+-static const char *avm_revision = "$Revision: 1.1.4.1 $";
++static const char *avm_revision = "$Revision: 2.15 $";
+
+ #define AVM_A1_STAT_ISAC 0x01
+ #define AVM_A1_STAT_HSCX 0x02
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/avm_a1p.c linux-2.4.29/drivers/isdn/hisax/avm_a1p.c
+--- linux-2.4.29.old/drivers/isdn/hisax/avm_a1p.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/avm_a1p.c 2005-03-22 15:06:45.919112016 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: avm_a1p.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: avm_a1p.c,v 2.9 2001/09/24 13:22:55 kai Exp $
+ *
+ * low level stuff for the following AVM cards:
+ * A1 PCMCIA
+@@ -57,7 +57,7 @@
+ #define byteout(addr,val) outb(val,addr)
+ #define bytein(addr) inb(addr)
+
+-static const char *avm_revision = "$Revision: 1.1.4.1 $";
++static const char *avm_revision = "$Revision: 2.9 $";
+
+ static inline u_char
+ ReadISAC(struct IsdnCardState *cs, u_char offset)
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/avm_pci.c linux-2.4.29/drivers/isdn/hisax/avm_pci.c
+--- linux-2.4.29.old/drivers/isdn/hisax/avm_pci.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/avm_pci.c 2005-03-22 15:06:45.945108064 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: avm_pci.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: avm_pci.c,v 1.29 2001/09/24 13:22:55 kai Exp $
+ *
+ * low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
+ *
+@@ -19,11 +19,11 @@
+ #include "isac.h"
+ #include "isdnl1.h"
+ #include <linux/pci.h>
+-#include <linux/isapnp.h>
++#include <linux/isdn_compat.h>
+ #include <linux/interrupt.h>
+
+ extern const char *CardType[];
+-static const char *avm_pci_rev = "$Revision: 1.1.4.1 $";
++static const char *avm_pci_rev = "$Revision: 1.29 $";
+
+ #define AVM_FRITZ_PCI 1
+ #define AVM_FRITZ_PNP 2
+@@ -291,8 +291,7 @@
+ debugl1(cs, "hdlc_empty_fifo: incoming packet too large");
+ return;
+ }
+- p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx;
+- ptr = (u_int *)p;
++ ptr = (u_int *) p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx;
+ bcs->hw.hdlc.rcvidx += count;
+ if (cs->subtyp == AVM_FRITZ_PCI) {
+ outl(idx, cs->hw.avm.cfg_reg + 4);
+@@ -353,8 +352,7 @@
+ }
+ if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
+ debugl1(cs, "hdlc_fill_fifo %d/%ld", count, bcs->tx_skb->len);
+- p = bcs->tx_skb->data;
+- ptr = (u_int *)p;
++ ptr = (u_int *) p = bcs->tx_skb->data;
+ skb_pull(bcs->tx_skb, count);
+ bcs->tx_cnt -= count;
+ bcs->hw.hdlc.count += count;
+@@ -766,10 +764,6 @@
+ }
+
+ static struct pci_dev *dev_avm __initdata = NULL;
+-#ifdef __ISAPNP__
+-static struct pci_bus *bus_avm __initdata = NULL;
+-static struct pci_dev *pnp_avm __initdata = NULL;
+-#endif
+
+ int __init
+ setup_avm_pcipnp(struct IsdnCard *card)
+@@ -783,47 +777,10 @@
+ if (cs->typ != ISDN_CTYPE_FRITZPCI)
+ return (0);
+ if (card->para[1]) {
+- /* old manual method */
+ cs->hw.avm.cfg_reg = card->para[1];
+ cs->irq = card->para[0];
+ cs->subtyp = AVM_FRITZ_PNP;
+ } else {
+-#ifdef __ISAPNP__
+- if (isapnp_present()) {
+- struct pci_bus *ba;
+- if ((ba = isapnp_find_card(
+- ISAPNP_VENDOR('A', 'V', 'M'),
+- ISAPNP_FUNCTION(0x0900), bus_avm))) {
+- bus_avm = ba;
+- pnp_avm = NULL;
+- if ((pnp_avm = isapnp_find_dev(bus_avm,
+- ISAPNP_VENDOR('A', 'V', 'M'),
+- ISAPNP_FUNCTION(0x0900), pnp_avm))) {
+- pnp_avm->prepare(pnp_avm);
+- pnp_avm->deactivate(pnp_avm);
+- pnp_avm->activate(pnp_avm);
+- cs->hw.avm.cfg_reg =
+- pnp_avm->resource[0].start;
+- cs->irq =
+- pnp_avm->irq_resource[0].start;
+- if (!cs->irq) {
+- printk(KERN_ERR "FritzPnP:No IRQ\n");
+- pnp_avm->deactivate(pnp_avm);
+- return(0);
+- }
+- if (!cs->hw.avm.cfg_reg) {
+- printk(KERN_ERR "FritzPnP:No IO address\n");
+- pnp_avm->deactivate(pnp_avm);
+- return(0);
+- }
+- cs->subtyp = AVM_FRITZ_PNP;
+- goto ready;
+- }
+- }
+- } else {
+- printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
+- }
+-#endif
+ #if CONFIG_PCI
+ if (!pci_present()) {
+ printk(KERN_ERR "FritzPCI: no PCI bus present\n");
+@@ -838,7 +795,7 @@
+ }
+ if (pci_enable_device(dev_avm))
+ return(0);
+- cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
++ cs->hw.avm.cfg_reg = pci_resource_start_io(dev_avm, 1);
+ if (!cs->hw.avm.cfg_reg) {
+ printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
+ return(0);
+@@ -854,7 +811,6 @@
+ return (0);
+ #endif /* CONFIG_PCI */
+ }
+-ready:
+ cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
+ if (check_region((cs->hw.avm.cfg_reg), 32)) {
+ printk(KERN_WARNING
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/bkm_a4t.c linux-2.4.29/drivers/isdn/hisax/bkm_a4t.c
+--- linux-2.4.29.old/drivers/isdn/hisax/bkm_a4t.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/bkm_a4t.c 2005-03-22 15:06:45.962105480 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: bkm_a4t.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: bkm_a4t.c,v 1.22 2001/09/24 13:22:55 kai Exp $
+ *
+ * low level stuff for T-Berkom A4T
+ *
+@@ -20,11 +20,12 @@
+ #include "jade.h"
+ #include "isdnl1.h"
+ #include <linux/pci.h>
++#include <linux/isdn_compat.h>
+ #include "bkm_ax.h"
+
+ extern const char *CardType[];
+
+-const char *bkm_a4t_revision = "$Revision: 1.1.4.1 $";
++const char *bkm_a4t_revision = "$Revision: 1.22 $";
+
+
+ static inline u_char
+@@ -293,13 +294,13 @@
+ u16 sub_sys;
+ u16 sub_vendor;
+
+- sub_vendor = dev_a4t->subsystem_vendor;
+- sub_sys = dev_a4t->subsystem_device;
++ pci_get_sub_vendor(dev_a4t,sub_vendor);
++ pci_get_sub_system(dev_a4t,sub_sys);
+ if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) {
+ if (pci_enable_device(dev_a4t))
+ return(0);
+ found = 1;
+- pci_memaddr = pci_resource_start(dev_a4t, 0);
++ pci_memaddr = pci_resource_start_mem(dev_a4t, 0);
+ cs->irq = dev_a4t->irq;
+ break;
+ }
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/bkm_a8.c linux-2.4.29/drivers/isdn/hisax/bkm_a8.c
+--- linux-2.4.29.old/drivers/isdn/hisax/bkm_a8.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/bkm_a8.c 2005-03-22 15:06:45.982102440 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: bkm_a8.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: bkm_a8.c,v 1.22 2001/09/24 13:22:55 kai Exp $
+ *
+ * low level stuff for Scitel Quadro (4*S0, passive)
+ *
+@@ -20,6 +20,7 @@
+ #include "hscx.h"
+ #include "isdnl1.h"
+ #include <linux/pci.h>
++#include <linux/isdn_compat.h>
+ #include "bkm_ax.h"
+
+ #if CONFIG_PCI
+@@ -28,7 +29,7 @@
+
+ extern const char *CardType[];
+
+-const char sct_quadro_revision[] = "$Revision: 1.1.4.1 $";
++const char sct_quadro_revision[] = "$Revision: 1.22 $";
+
+ static const char *sct_quadro_subtypes[] =
+ {
+@@ -329,13 +330,13 @@
+ while ((dev_a8 = pci_find_device(PCI_VENDOR_ID_PLX,
+ PCI_DEVICE_ID_PLX_9050, dev_a8))) {
+
+- sub_vendor_id = dev_a8->subsystem_vendor;
+- sub_sys_id = dev_a8->subsystem_device;
++ pci_get_sub_vendor(dev_a8,sub_vendor_id);
++ pci_get_sub_system(dev_a8,sub_sys_id);
+ if ((sub_sys_id == PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) &&
+ (sub_vendor_id == PCI_VENDOR_ID_BERKOM)) {
+ if (pci_enable_device(dev_a8))
+ return(0);
+- pci_ioaddr1 = pci_resource_start(dev_a8, 1);
++ pci_ioaddr1 = pci_resource_start_io(dev_a8, 1);
+ pci_irq = dev_a8->irq;
+ pci_bus = dev_a8->bus->number;
+ pci_device_fn = dev_a8->devfn;
+@@ -365,7 +366,7 @@
+ pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
+ pcibios_write_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_1, pci_ioaddr1);
+- dev_a8->resource[ 1].start = pci_ioaddr1;
++ get_pcibase(dev_a8, 1) = pci_ioaddr1;
+ }
+ #endif /* End HACK */
+ }
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/bkm_ax.h linux-2.4.29/drivers/isdn/hisax/bkm_ax.h
+--- linux-2.4.29.old/drivers/isdn/hisax/bkm_ax.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/bkm_ax.h 2005-03-22 15:06:46.010098184 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: bkm_ax.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id$
+ *
+ * low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive)
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/callc.c linux-2.4.29/drivers/isdn/hisax/callc.c
+--- linux-2.4.29.old/drivers/isdn/hisax/callc.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/callc.c 2005-03-22 15:06:46.027095600 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: callc.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: callc.c,v 2.59 2002/02/09 21:19:11 keil Exp $
+ *
+ * Author Karsten Keil
+ * Copyright by Karsten Keil <keil@isdn4linux.de>
+@@ -26,7 +26,7 @@
+ #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
+ #endif /* MODULE */
+
+-const char *lli_revision = "$Revision: 1.1.4.1 $";
++const char *lli_revision = "$Revision: 2.59 $";
+
+ extern struct IsdnCard cards[];
+ extern int nrcards;
+@@ -145,9 +145,11 @@
+ EV_PROCEED, /* 20 */
+ EV_ALERT, /* 21 */
+ EV_REDIR, /* 22 */
++ EV_ALERTING, /* 23 */
++ EV_PROCEEDING, /* 24 */
+ };
+
+-#define EVENT_COUNT (EV_REDIR + 1)
++#define EVENT_COUNT (EV_PROCEEDING + 1)
+
+ static char *strEvent[] =
+ {
+@@ -174,6 +176,8 @@
+ "EV_PROCEED",
+ "EV_ALERT",
+ "EV_REDIR",
++ "EV_ALERTING",
++ "EV_PROCEEDING",
+ };
+
+
+@@ -286,6 +290,22 @@
+ }
+
+ static void
++lli_alerting(struct FsmInst *fi, int event, void *arg)
++{
++ struct Channel *chanp = fi->userdata;
++
++ HL_LL(chanp, ISDN_STAT_ALERT);
++}
++
++static void
++lli_proceeding(struct FsmInst *fi, int event, void *arg)
++{
++ struct Channel *chanp = fi->userdata;
++
++ HL_LL(chanp, ISDN_STAT_PROCEED);
++}
++
++static void
+ lli_resume(struct FsmInst *fi, int event, void *arg)
+ {
+ struct Channel *chanp = fi->userdata;
+@@ -784,6 +804,8 @@
+ {ST_OUT_DIAL, EV_DISCONNECT_IND, lli_release_req},
+ {ST_OUT_DIAL, EV_RELEASE, lli_dhup_close},
+ {ST_OUT_DIAL, EV_NOSETUP_RSP, lli_no_setup_rsp},
++ {ST_OUT_DIAL, EV_PROCEEDING, lli_proceeding},
++ {ST_OUT_DIAL, EV_ALERTING, lli_alerting},
+ {ST_OUT_DIAL, EV_SETUP_ERR, lli_error},
+ {ST_IN_WAIT_LL, EV_LEASED_REL, lli_failure_l},
+ {ST_IN_WAIT_LL, EV_ACCEPTD, lli_setup_rsp},
+@@ -925,7 +947,7 @@
+ ic.driver = cs->myid;
+ ic.command = ISDN_STAT_REDIR;
+ ic.arg = chan;
+- ic.parm.num[0] = result;
++ (ulong)(ic.parm.num[0]) = result;
+ cs->iif.statcallb(&ic);
+ } /* stat_redir_result */
+
+@@ -997,8 +1019,13 @@
+ FsmEvent(&chanp->fi, EV_RELEASE, NULL);
+ break;
+ case (CC_PROCEED_SEND | INDICATION):
++ break;
+ case (CC_PROCEEDING | INDICATION):
++ FsmEvent(&chanp->fi, EV_PROCEEDING, NULL);
++ break;
+ case (CC_ALERTING | INDICATION):
++ FsmEvent(&chanp->fi, EV_ALERTING, NULL);
++ break;
+ case (CC_PROGRESS | INDICATION):
+ case (CC_NOTIFY | INDICATION):
+ break;
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/cert.c linux-2.4.29/drivers/isdn/hisax/cert.c
+--- linux-2.4.29.old/drivers/isdn/hisax/cert.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/cert.c 2005-03-22 15:06:46.042093320 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: cert.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: cert.c,v 2.6 2001/09/24 13:22:56 kai Exp $
+ *
+ * Author Karsten Keil
+ * Copyright by Karsten Keil <keil@isdn4linux.de>
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/config.c linux-2.4.29/drivers/isdn/hisax/config.c
+--- linux-2.4.29.old/drivers/isdn/hisax/config.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/config.c 2005-03-22 15:06:46.077088000 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: config.c,v 1.1.4.5 2001/12/09 19:19:26 kai Exp $
++/* $Id: config.c,v 2.84 2002/08/13 09:55:29 keil Exp $
+ *
+ * Author Karsten Keil
+ * Copyright by Karsten Keil <keil@isdn4linux.de>
+@@ -24,6 +24,11 @@
+ #include <linux/kernel_stat.h>
+ #include <linux/tqueue.h>
+ #include <linux/interrupt.h>
++
++#ifdef CONFIG_HISAX_HFC_USB
++#include "hisax_loadable.h"
++#endif
++
+ #define HISAX_STATUS_BUFSIZE 4096
+ #define INCLUDE_INLINE_FUNCS
+
+@@ -75,8 +80,7 @@
+ * 37 HFC 2BDS0 S+/SP p0=irq p1=iobase
+ * 38 Travers Technologies NETspider-U PCI card
+ * 39 HFC 2BDS0-SP PCMCIA p0=irq p1=iobase
+- * 40 hotplug interface
+- * 41 Formula-n enter:now ISDN PCI a/b none
++ * 40 HFC-S USB none
+ *
+ * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
+ *
+@@ -95,11 +99,17 @@
+ "Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T",
+ "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
+ "HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA",
+- "Hotplug", "Formula-n enter:now PCI a/b",
++ "HFC-S USB",
+ };
+
+ void HiSax_closecard(int cardnr);
+
++#ifdef CONFIG_HISAX_HFC_USB
++#define DEFAULT_CARD ISDN_CTYPE_HFC_USB
++#define DEFAULT_CFG {0,0,0,0}
++EXPORT_SYMBOL(hisax_register_hfcusb);
++#endif
++
+ #ifdef CONFIG_HISAX_ELSA
+ #define DEFAULT_CARD ISDN_CTYPE_ELSA
+ #define DEFAULT_CFG {0,0,0,0}
+@@ -339,19 +349,27 @@
+ NULL, \
+ }
+
+-struct IsdnCard cards[HISAX_MAX_CARDS] = {
++#define EMPTY_CARD {0, DEFAULT_PROTO, {0, 0, 0, 0}, NULL}
++
++struct IsdnCard cards[] = {
+ FIRST_CARD,
++ EMPTY_CARD,
++ EMPTY_CARD,
++ EMPTY_CARD,
++ EMPTY_CARD,
++ EMPTY_CARD,
++ EMPTY_CARD,
++ EMPTY_CARD,
+ };
+
+-#define HISAX_IDSIZE (HISAX_MAX_CARDS*8)
+-static char HiSaxID[HISAX_IDSIZE] __devinitdata = { 0, };
++static char HiSaxID[64] __devinitdata = { 0, };
+
+ char *HiSax_id __devinitdata = HiSaxID;
+ #ifdef MODULE
+ /* Variables for insmod */
+-static int type[HISAX_MAX_CARDS] __devinitdata = { 0, };
+-static int protocol[HISAX_MAX_CARDS] __devinitdata = { 0, };
+-static int io[HISAX_MAX_CARDS] __devinitdata = { 0, };
++static int type[8] __devinitdata = { 0, };
++static int protocol[8] __devinitdata = { 0, };
++static int io[8] __devinitdata = { 0, };
+ #undef IO0_IO1
+ #ifdef CONFIG_HISAX_16_3
+ #define IO0_IO1
+@@ -361,27 +379,23 @@
+ #define IO0_IO1
+ #endif
+ #ifdef IO0_IO1
+-static int io0[HISAX_MAX_CARDS] __devinitdata = { 0, };
+-static int io1[HISAX_MAX_CARDS] __devinitdata = { 0, };
++static int io0[8] __devinitdata = { 0, };
++static int io1[8] __devinitdata = { 0, };
+ #endif
+-static int irq[HISAX_MAX_CARDS] __devinitdata = { 0, };
+-static int mem[HISAX_MAX_CARDS] __devinitdata = { 0, };
++static int irq[8] __devinitdata = { 0, };
++static int mem[8] __devinitdata = { 0, };
+ static char *id __devinitdata = HiSaxID;
+
+-#define PARM_PARA "1-" __MODULE_STRING(HISAX_MAX_CARDS) "i"
+-
+-MODULE_DESCRIPTION("ISDN4Linux: Driver for passive ISDN cards");
+ MODULE_AUTHOR("Karsten Keil");
+-MODULE_LICENSE("GPL");
+-MODULE_PARM(type, PARM_PARA);
+-MODULE_PARM(protocol, PARM_PARA);
+-MODULE_PARM(io, PARM_PARA);
+-MODULE_PARM(irq, PARM_PARA);
+-MODULE_PARM(mem, PARM_PARA);
++MODULE_PARM(type, "1-8i");
++MODULE_PARM(protocol, "1-8i");
++MODULE_PARM(io, "1-8i");
++MODULE_PARM(irq, "1-8i");
++MODULE_PARM(mem, "1-8i");
+ MODULE_PARM(id, "s");
+ #ifdef IO0_IO1
+-MODULE_PARM(io0, PARM_PARA);
+-MODULE_PARM(io1, PARM_PARA);
++MODULE_PARM(io0, "1-8i");
++MODULE_PARM(io1, "1-8i");
+ #endif
+ #endif /* MODULE */
+
+@@ -432,6 +446,7 @@
+ }
+
+ #ifndef MODULE
++#ifdef COMPAT_HAS_NEW_SETUP
+ #define MAX_ARG (HISAX_MAX_CARDS*5)
+ static int __init HiSax_setup(char *line)
+ {
+@@ -440,12 +455,16 @@
+ char *str;
+
+ str = get_options(line, MAX_ARG, ints);
++#else
++void __init HiSax_setup(char *str, int *ints)
++{
++ int i, j, argc;
++#endif
+ argc = ints[0];
+ printk(KERN_DEBUG "HiSax_setup: argc(%d) str(%s)\n", argc, str);
+ i = 0;
+ j = 1;
+ while (argc && (i < HISAX_MAX_CARDS)) {
+- cards[i].protocol = DEFAULT_PROTO;
+ if (argc) {
+ cards[i].typ = ints[j];
+ j++;
+@@ -473,19 +492,21 @@
+ }
+ i++;
+ }
+- if (str && *str) {
+- if (strlen(str) < HISAX_IDSIZE)
+- strcpy(HiSaxID, str);
+- else
+- printk(KERN_WARNING "HiSax: ID too long!");
+- } else
++ if (str && *str) {
++ strcpy(HiSaxID, str);
++ HiSax_id = HiSaxID;
++ } else {
+ strcpy(HiSaxID, "HiSax");
+-
+- HiSax_id = HiSaxID;
++ HiSax_id = HiSaxID;
++ }
++#ifdef COMPAT_HAS_NEW_SETUP
+ return 1;
+ }
+
+ __setup("hisax=", HiSax_setup);
++#else
++}
++#endif /* COMPAT_HAS_NEW_SETUP */
+ #endif /* MODULES */
+
+ #if CARD_TELES0
+@@ -560,6 +581,10 @@
+ extern int setup_hfcpci(struct IsdnCard *card);
+ #endif
+
++#if CONFIG_HISAX_HFC_USB
++extern int setup_hfc_usb(struct IsdnCard *card);
++#endif
++
+ #if CARD_HFC_SX
+ extern int setup_hfcsx(struct IsdnCard *card);
+ #endif
+@@ -604,10 +629,6 @@
+ extern int setup_netjet_u(struct IsdnCard *card);
+ #endif
+
+-#if CARD_FN_ENTERNOW_PCI
+-extern int setup_enternow_pci(struct IsdnCard *card);
+-#endif
+-
+ /*
+ * Find card with given driverId
+ */
+@@ -899,7 +920,8 @@
+ return 3;
+ }
+
+-static int __devinit checkcard(int cardnr, char *id, int *busy_flag)
++static int __devinit checkcard(int cardnr, char *id, int *busy_flag,
++ void *load_drv)
+ {
+ long flags;
+ int ret = 0;
+@@ -1093,6 +1115,12 @@
+ ret = setup_hfcsx(card);
+ break;
+ #endif
++#if CONFIG_HISAX_HFC_USB
++ case ISDN_CTYPE_HFC_USB:
++ cs->hw.hfcusb.drv = load_drv;
++ ret = setup_hfc_usb(card);
++ break;
++#endif
+ #if CARD_NICCY
+ case ISDN_CTYPE_NICCY:
+ ret = setup_niccy(card);
+@@ -1143,11 +1171,6 @@
+ ret = setup_netjet_u(card);
+ break;
+ #endif
+-#if CARD_FN_ENTERNOW_PCI
+- case ISDN_CTYPE_ENTERNOW:
+- ret = setup_enternow_pci(card);
+- break;
+-#endif
+ case ISDN_CTYPE_DYNAMIC:
+ ret = 2;
+ break;
+@@ -1186,6 +1209,9 @@
+ case ISDN_CTYPE_DYNAMIC:
+ ret = 0;
+ break;
++ case ISDN_CTYPE_HFC_USB:
++ ret = cs->cardmsg(cs, CARD_INIT, NULL);
++ break;
+ default:
+ ret = init_card(cs);
+ break;
+@@ -1257,16 +1283,13 @@
+ else
+ sprintf(ids, "%s%d", id, i);
+ }
+- if (checkcard(i, ids, busy_flag)) {
++ if (checkcard(i, ids, busy_flag, NULL)) {
+ foundcards++;
+ i++;
+ } else {
+- /* make sure we don't oops the module */
+- if (cards[i].typ > 0 && cards[i].typ <= ISDN_CTYPE_COUNT) {
+- printk(KERN_WARNING
+- "HiSax: Card %s not installed !\n",
+- CardType[cards[i].typ]);
+- }
++ printk(KERN_WARNING
++ "HiSax: Card %s not installed !\n",
++ CardType[cards[i].typ]);
+ HiSax_shiftcards(i);
+ nrcards--;
+ }
+@@ -1342,6 +1365,49 @@
+ #endif
+ }
+
++#ifdef CONFIG_HISAX_HFC_USB
++int
++hisax_register_hfcusb(struct hisax_drvreg *l1drv)
++{
++ int i;
++ char ids[30];
++
++ if (l1drv->version != HISAX_LOAD_VERSION)
++ return 1;
++
++ switch (l1drv->cmd) {
++ case HISAX_LOAD_CHKVER:
++ break; /* success */
++
++ case HISAX_LOAD_REGISTER:
++ for (i = 0; i < HISAX_MAX_CARDS; i++) {
++ if (!cards[i].typ)
++ break;
++ }
++ if (i >= HISAX_MAX_CARDS)
++ return 1; /* no space */
++ cards[i].typ = ISDN_CTYPE_HFC_USB; /* setup type */
++ cards[i].protocol = DEFAULT_PROTO;
++ sprintf(ids, "%s%d", l1drv->drvname, i);
++ if (checkcard(i, ids, NULL, (void *) l1drv)) {
++ nrcards++;
++ return 0;
++ }
++ if (cards[i].cs)
++ kfree((void *) cards[i].cs);
++ cards[i].cs = NULL;
++ cards[i].typ = 0; /* no card present */
++ return 1;
++ break;
++
++ default:
++ return 1; /* unknown command */
++ }
++
++ return 0;
++} /* hisax_register_hfcusb */
++#endif
++
+ static int __init HiSax_init(void)
+ {
+ int i, retval;
+@@ -1408,8 +1474,6 @@
+ if (protocol[i]) {
+ cards[j].protocol = protocol[i];
+ nzproto++;
+- } else {
+- cards[j].protocol = DEFAULT_PROTO;
+ }
+ switch (type[i]) {
+ case ISDN_CTYPE_16_0:
+@@ -1487,22 +1551,15 @@
+ } else {
+ /* QUADRO is a 4 BRI card */
+ cards[j++].para[0] = 1;
+- /* we need to check if further cards can be added */
+- if (j < HISAX_MAX_CARDS) {
+- cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+- cards[j].protocol = protocol[i];
+- cards[j++].para[0] = 2;
+- }
+- if (j < HISAX_MAX_CARDS) {
+- cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+- cards[j].protocol = protocol[i];
+- cards[j++].para[0] = 3;
+- }
+- if (j < HISAX_MAX_CARDS) {
+- cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
+- cards[j].protocol = protocol[i];
+- cards[j].para[0] = 4;
+- }
++ cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
++ cards[j].protocol = protocol[i];
++ cards[j++].para[0] = 2;
++ cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
++ cards[j].protocol = protocol[i];
++ cards[j++].para[0] = 3;
++ cards[j].typ = ISDN_CTYPE_SCT_QUADRO;
++ cards[j].protocol = protocol[i];
++ cards[j].para[0] = 4;
+ }
+ break;
+ }
+@@ -1526,10 +1583,15 @@
+ nrcards, (nrcards > 1) ? "s" : "");
+
+ /* Install only, if at least one card found */
+- if (!HiSax_inithardware(NULL))
+- return -ENODEV;
++ if (!HiSax_inithardware(NULL)) {
++ retval = -EIO;
++ goto out_isdnl1;
++ }
++
+ return 0;
+
++ out_isdnl1:
++ Isdnl1Free();
+ out_tei:
+ TeiFree();
+ out_isdnl2:
+@@ -1576,8 +1638,6 @@
+ cards[i].typ = type[i];
+ if (protocol[i]) {
+ cards[i].protocol = protocol[i];
+- } else {
+- cards[i].protocol = DEFAULT_PROTO;
+ }
+ }
+ cards[0].para[0] = pcm_irq;
+@@ -1595,8 +1655,7 @@
+ printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
+ nrcards, (nrcards > 1) ? "s" : "");
+
+- if (!HiSax_inithardware(busy_flag))
+- return -ENODEV;
++ HiSax_inithardware(busy_flag);
+ printk(KERN_NOTICE "HiSax: module installed\n");
+ #endif
+ return 0;
+@@ -1619,8 +1678,6 @@
+ cards[i].typ = type[i];
+ if (protocol[i]) {
+ cards[i].protocol = protocol[i];
+- } else {
+- cards[i].protocol = DEFAULT_PROTO;
+ }
+ }
+ cards[0].para[0] = pcm_irq;
+@@ -1638,8 +1695,7 @@
+ printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
+ nrcards, (nrcards > 1) ? "s" : "");
+
+- if (!HiSax_inithardware(busy_flag))
+- return -ENODEV;
++ HiSax_inithardware(busy_flag);
+ printk(KERN_NOTICE "HiSax: module installed\n");
+ #endif
+ return 0;
+@@ -1662,8 +1718,6 @@
+ cards[i].typ = type[i];
+ if (protocol[i]) {
+ cards[i].protocol = protocol[i];
+- } else {
+- cards[i].protocol = DEFAULT_PROTO;
+ }
+ }
+ cards[0].para[0] = pcm_irq;
+@@ -1681,8 +1735,7 @@
+ printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
+ nrcards, (nrcards > 1) ? "s" : "");
+
+- if (!HiSax_inithardware(busy_flag))
+- return -ENODEV;
++ HiSax_inithardware(busy_flag);
+ printk(KERN_NOTICE "HiSax: module installed\n");
+ #endif
+ return 0;
+@@ -1705,8 +1758,6 @@
+ cards[i].typ = type[i];
+ if (protocol[i]) {
+ cards[i].protocol = protocol[i];
+- } else {
+- cards[i].protocol = DEFAULT_PROTO;
+ }
+ }
+ cards[0].para[0] = pcm_irq;
+@@ -1724,8 +1775,7 @@
+ printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
+ nrcards, (nrcards > 1) ? "s" : "");
+
+- if (!HiSax_inithardware(busy_flag))
+- return -ENODEV;
++ HiSax_inithardware(busy_flag);
+ printk(KERN_NOTICE "HiSax: module installed\n");
+ #endif
+ return 0;
+@@ -1743,7 +1793,7 @@
+ sprintf(ids, "HiSax%d", nrcards);
+ else
+ sprintf(ids, "HiSax");
+- if (!checkcard(nrcards, ids, busy_flag)) {
++ if (!checkcard(nrcards, ids, busy_flag, NULL)) {
+ return -1;
+ }
+ ret = nrcards;
+@@ -1785,7 +1835,7 @@
+ cards[i].protocol = protocol;
+ sprintf(id, "%s%d", name, i);
+ nrcards++;
+- retval = checkcard(i, id, 0);
++ retval = checkcard(i, id, 0, NULL);
+ if (retval == 0) { // yuck
+ cards[i].typ = 0;
+ nrcards--;
+@@ -2117,9 +2167,6 @@
+ {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20, PCI_ANY_ID, PCI_ANY_ID},
+ {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA20_U, PCI_ANY_ID, PCI_ANY_ID},
+ {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA201, PCI_ANY_ID, PCI_ANY_ID},
+-//#########################################################################################
+- {PCI_VENDOR_ID_EICON, PCI_DEVICE_ID_EICON_DIVA202, PCI_ANY_ID, PCI_ANY_ID},
+-//#########################################################################################
+ #endif
+ #ifdef CONFIG_HISAX_ELSA
+ {PCI_VENDOR_ID_ELSA, PCI_DEVICE_ID_ELSA_MICROLINK, PCI_ANY_ID, PCI_ANY_ID},
+@@ -2178,11 +2225,3 @@
+
+ module_init(HiSax_init);
+ module_exit(HiSax_exit);
+-
+-EXPORT_SYMBOL(FsmNew);
+-EXPORT_SYMBOL(FsmFree);
+-EXPORT_SYMBOL(FsmEvent);
+-EXPORT_SYMBOL(FsmChangeState);
+-EXPORT_SYMBOL(FsmInitTimer);
+-EXPORT_SYMBOL(FsmDelTimer);
+-EXPORT_SYMBOL(FsmRestartTimer);
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/diva.c linux-2.4.29/drivers/isdn/hisax/diva.c
+--- linux-2.4.29.old/drivers/isdn/hisax/diva.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/diva.c 2005-03-22 15:06:46.106083592 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: diva.c,v 1.1.4.2 2002/08/30 11:21:00 keil Exp $
++/* $Id: diva.c,v 1.33 2001/09/24 13:22:56 kai Exp $
+ *
+ * low level stuff for Eicon.Diehl Diva Family ISDN cards
+ *
+@@ -22,14 +22,13 @@
+ #include "isac.h"
+ #include "hscx.h"
+ #include "ipac.h"
+-#include "ipacx.h"
+ #include "isdnl1.h"
+ #include <linux/pci.h>
+-#include <linux/isapnp.h>
++#include <linux/isdn_compat.h>
+
+ extern const char *CardType[];
+
+-const char *Diva_revision = "$Revision: 1.1.4.2 $";
++const char *Diva_revision = "$Revision: 1.33 $";
+
+ #define byteout(addr,val) outb(val,addr)
+ #define bytein(addr) inb(addr)
+@@ -51,7 +50,6 @@
+ #define DIVA_PCI 2
+ #define DIVA_IPAC_ISA 3
+ #define DIVA_IPAC_PCI 4
+-#define DIVA_IPACX_PCI 5
+
+ /* CTRL (Read) */
+ #define DIVA_IRQ_STAT 0x01
+@@ -71,12 +69,10 @@
+ #define PITA_MISC_REG 0x1c
+ #ifdef __BIG_ENDIAN
+ #define PITA_PARA_SOFTRESET 0x00000001
+-#define PITA_SER_SOFTRESET 0x00000002
+ #define PITA_PARA_MPX_MODE 0x00000004
+ #define PITA_INT0_ENABLE 0x00000200
+ #else
+ #define PITA_PARA_SOFTRESET 0x01000000
+-#define PITA_SER_SOFTRESET 0x02000000
+ #define PITA_PARA_MPX_MODE 0x04000000
+ #define PITA_INT0_ENABLE 0x00020000
+ #endif
+@@ -244,47 +240,6 @@
+ memwritereg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0), value);
+ }
+
+-/* IO-Functions for IPACX type cards */
+-static u_char
+-MemReadISAC_IPACX(struct IsdnCardState *cs, u_char offset)
+-{
+- return (memreadreg(cs->hw.diva.cfg_reg, offset));
+-}
+-
+-static void
+-MemWriteISAC_IPACX(struct IsdnCardState *cs, u_char offset, u_char value)
+-{
+- memwritereg(cs->hw.diva.cfg_reg, offset, value);
+-}
+-
+-static void
+-MemReadISACfifo_IPACX(struct IsdnCardState *cs, u_char * data, int size)
+-{
+- while(size--)
+- *data++ = memreadreg(cs->hw.diva.cfg_reg, 0);
+-}
+-
+-static void
+-MemWriteISACfifo_IPACX(struct IsdnCardState *cs, u_char * data, int size)
+-{
+- while(size--)
+- memwritereg(cs->hw.diva.cfg_reg, 0, *data++);
+-}
+-
+-static u_char
+-MemReadHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset)
+-{
+- return(memreadreg(cs->hw.diva.cfg_reg, offset +
+- (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1)));
+-}
+-
+-static void
+-MemWriteHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+-{
+- memwritereg(cs->hw.diva.cfg_reg, offset +
+- (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1), value);
+-}
+-
+ /*
+ * fast interrupt HSCX stuff goes here
+ */
+@@ -595,7 +550,7 @@
+ u_char exval;
+ struct BCState *bcs;
+
+- if (val & 0x01) { // EXB
++ if (val & 0x01) {
+ bcs = cs->bcs + 1;
+ exval = MemReadHSCX(cs, 1, HSCX_EXIR);
+ if (exval & 0x40) {
+@@ -622,7 +577,7 @@
+ debugl1(cs, "HSCX B interrupt %x", val);
+ Memhscx_interrupt(cs, val, 1);
+ }
+- if (val & 0x02) { // EXA
++ if (val & 0x02) {
+ bcs = cs->bcs;
+ exval = MemReadHSCX(cs, 0, HSCX_EXIR);
+ if (exval & 0x40) {
+@@ -644,7 +599,7 @@
+ } else if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX A EXIR %x", exval);
+ }
+- if (val & 0x04) { // ICA
++ if (val & 0x04) {
+ exval = MemReadHSCX(cs, 0, HSCX_ISTA);
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "HSCX A interrupt %x", exval);
+@@ -705,31 +660,12 @@
+ memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xC0);
+ }
+
+-static void
+-diva_irq_ipacx_pci(int intno, void *dev_id, struct pt_regs *regs)
+-{
+- struct IsdnCardState *cs = dev_id;
+- u_char val;
+- u_char *cfg;
+-
+- if (!cs) {
+- printk(KERN_WARNING "Diva: Spurious interrupt!\n");
+- return;
+- }
+- cfg = (u_char *) cs->hw.diva.pci_cfg;
+- val = *cfg;
+- if (!(val &PITA_INT0_STATUS)) return; // other shared IRQ
+- interrupt_ipacx(cs); // handler for chip
+- *cfg = PITA_INT0_STATUS; // Reset PLX interrupt
+-}
+-
+ void
+ release_io_diva(struct IsdnCardState *cs)
+ {
+ int bytecnt;
+
+- if ((cs->subtyp == DIVA_IPAC_PCI) ||
+- (cs->subtyp == DIVA_IPACX_PCI) ) {
++ if (cs->subtyp == DIVA_IPAC_PCI) {
+ u_int *cfg = (unsigned int *)cs->hw.diva.pci_cfg;
+
+ *cfg = 0; /* disable INT0/1 */
+@@ -776,16 +712,6 @@
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((10*HZ)/1000);
+ memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0);
+- } else if (cs->subtyp == DIVA_IPACX_PCI) {
+- unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg +
+- PITA_MISC_REG);
+- *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE;
+- set_current_state(TASK_UNINTERRUPTIBLE);
+- schedule_timeout((10*HZ)/1000);
+- *ireg = PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET;
+- set_current_state(TASK_UNINTERRUPTIBLE);
+- schedule_timeout((10*HZ)/1000);
+- MemWriteISAC_IPACX(cs, IPACX_MASK, 0xff); // Interrupts off
+ } else { /* DIVA 2.0 */
+ cs->hw.diva.ctrl_reg = 0; /* Reset On */
+ byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
+@@ -814,9 +740,7 @@
+ {
+ int blink = 0;
+
+- if ((cs->subtyp == DIVA_IPAC_ISA) ||
+- (cs->subtyp == DIVA_IPAC_PCI) ||
+- (cs->subtyp == DIVA_IPACX_PCI) )
++ if ((cs->subtyp == DIVA_IPAC_ISA) || (cs->subtyp == DIVA_IPAC_PCI))
+ return;
+ del_timer(&cs->hw.diva.tl);
+ if (cs->hw.diva.status & DIVA_ASSIGN)
+@@ -859,12 +783,6 @@
+ release_io_diva(cs);
+ return(0);
+ case CARD_INIT:
+- if (cs->subtyp == DIVA_IPACX_PCI) {
+- ireg = (unsigned int *)cs->hw.diva.pci_cfg;
+- *ireg = PITA_INT0_ENABLE;
+- init_ipacx(cs, 3); // init chip and enable interrupts
+- return (0);
+- }
+ if (cs->subtyp == DIVA_IPAC_PCI) {
+ ireg = (unsigned int *)cs->hw.diva.pci_cfg;
+ *ireg = PITA_INT0_ENABLE;
+@@ -901,9 +819,7 @@
+ }
+ break;
+ }
+- if ((cs->subtyp != DIVA_IPAC_ISA) &&
+- (cs->subtyp != DIVA_IPAC_PCI) &&
+- (cs->subtyp != DIVA_IPACX_PCI) )
++ if ((cs->subtyp != DIVA_IPAC_ISA) && (cs->subtyp != DIVA_IPAC_PCI))
+ diva_led_handler(cs);
+ return(0);
+ }
+@@ -911,40 +827,11 @@
+ static struct pci_dev *dev_diva __initdata = NULL;
+ static struct pci_dev *dev_diva_u __initdata = NULL;
+ static struct pci_dev *dev_diva201 __initdata = NULL;
+-static struct pci_dev *dev_diva202 __initdata = NULL;
+-
+-#ifdef __ISAPNP__
+-static struct isapnp_device_id diva_ids[] __initdata = {
+- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+- (unsigned long) "Diva picola" },
+- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51),
+- (unsigned long) "Diva picola" },
+- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+- (unsigned long) "Diva 2.0" },
+- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71),
+- (unsigned long) "Diva 2.0" },
+- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+- ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+- (unsigned long) "Diva 2.01" },
+- { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+- ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1),
+- (unsigned long) "Diva 2.01" },
+- { 0, }
+-};
+-
+-static struct isapnp_device_id *pdev = &diva_ids[0];
+-static struct pci_bus *pnp_c __devinitdata = NULL;
+-#endif
+-
+
+ int __init
+ setup_diva(struct IsdnCard *card)
+ {
+- int bytecnt = 8;
++ int bytecnt;
+ u_char val;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+@@ -977,75 +864,8 @@
+ cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
+ }
+ cs->irq = card->para[0];
++ bytecnt = 8;
+ } else {
+-#ifdef __ISAPNP__
+- if (isapnp_present()) {
+- struct pci_bus *pb;
+- struct pci_dev *pd;
+-
+- while(pdev->card_vendor) {
+- if ((pb = isapnp_find_card(pdev->card_vendor,
+- pdev->card_device, pnp_c))) {
+- pnp_c = pb;
+- pd = NULL;
+- if ((pd = isapnp_find_dev(pnp_c,
+- pdev->vendor, pdev->function, pd))) {
+- printk(KERN_INFO "HiSax: %s detected\n",
+- (char *)pdev->driver_data);
+- pd->prepare(pd);
+- pd->deactivate(pd);
+- pd->activate(pd);
+- card->para[1] =
+- pd->resource[0].start;
+- card->para[0] =
+- pd->irq_resource[0].start;
+- if (!card->para[0] || !card->para[1]) {
+- printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
+- card->para[0], card->para[1]);
+- pd->deactivate(pd);
+- return(0);
+- }
+- cs->hw.diva.cfg_reg = card->para[1];
+- cs->irq = card->para[0];
+- if (pdev->function == ISAPNP_FUNCTION(0xA1)) {
+- cs->subtyp = DIVA_IPAC_ISA;
+- cs->hw.diva.ctrl = 0;
+- cs->hw.diva.isac =
+- card->para[1] + DIVA_IPAC_DATA;
+- cs->hw.diva.hscx =
+- card->para[1] + DIVA_IPAC_DATA;
+- cs->hw.diva.isac_adr =
+- card->para[1] + DIVA_IPAC_ADR;
+- cs->hw.diva.hscx_adr =
+- card->para[1] + DIVA_IPAC_ADR;
+- test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+- } else {
+- cs->subtyp = DIVA_ISA;
+- cs->hw.diva.ctrl =
+- card->para[1] + DIVA_ISA_CTRL;
+- cs->hw.diva.isac =
+- card->para[1] + DIVA_ISA_ISAC_DATA;
+- cs->hw.diva.hscx =
+- card->para[1] + DIVA_HSCX_DATA;
+- cs->hw.diva.isac_adr =
+- card->para[1] + DIVA_ISA_ISAC_ADR;
+- cs->hw.diva.hscx_adr =
+- card->para[1] + DIVA_HSCX_ADR;
+- }
+- goto ready;
+- } else {
+- printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
+- return(0);
+- }
+- }
+- pdev++;
+- pnp_c=NULL;
+- }
+- if (!pdev->card_vendor) {
+- printk(KERN_INFO "Diva PnP: no ISAPnP card found\n");
+- }
+- }
+-#endif
+ #if CONFIG_PCI
+ if (!pci_present()) {
+ printk(KERN_ERR "Diva: no PCI bus present\n");
+@@ -1059,14 +879,14 @@
+ return(0);
+ cs->subtyp = DIVA_PCI;
+ cs->irq = dev_diva->irq;
+- cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
++ cs->hw.diva.cfg_reg = pci_resource_start_io(dev_diva, 2);
+ } else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
+ if (pci_enable_device(dev_diva_u))
+ return(0);
+ cs->subtyp = DIVA_PCI;
+ cs->irq = dev_diva_u->irq;
+- cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
++ cs->hw.diva.cfg_reg = pci_resource_start_io(dev_diva_u, 2);
+ } else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
+ PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
+ if (pci_enable_device(dev_diva201))
+@@ -1074,19 +894,9 @@
+ cs->subtyp = DIVA_IPAC_PCI;
+ cs->irq = dev_diva201->irq;
+ cs->hw.diva.pci_cfg =
+- (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
++ (ulong) ioremap(pci_resource_start_mem(dev_diva201, 0), 4096);
+ cs->hw.diva.cfg_reg =
+- (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
+- } else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
+- PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
+- if (pci_enable_device(dev_diva202))
+- return(0);
+- cs->subtyp = DIVA_IPACX_PCI;
+- cs->irq = dev_diva202->irq;
+- cs->hw.diva.pci_cfg =
+- (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
+- cs->hw.diva.cfg_reg =
+- (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
++ (ulong) ioremap(pci_resource_start_mem(dev_diva201, 1), 4096);
+ } else {
+ printk(KERN_WARNING "Diva: No PCI card found\n");
+ return(0);
+@@ -1107,8 +917,7 @@
+ printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
+ return (0);
+ #endif /* CONFIG_PCI */
+- if ((cs->subtyp == DIVA_IPAC_PCI) ||
+- (cs->subtyp == DIVA_IPACX_PCI) ) {
++ if (cs->subtyp == DIVA_IPAC_PCI) {
+ cs->hw.diva.ctrl = 0;
+ cs->hw.diva.isac = 0;
+ cs->hw.diva.hscx = 0;
+@@ -1125,23 +934,18 @@
+ bytecnt = 32;
+ }
+ }
+-ready:
++
+ printk(KERN_INFO
+ "Diva: %s card configured at %#lx IRQ %d\n",
+ (cs->subtyp == DIVA_PCI) ? "PCI" :
+ (cs->subtyp == DIVA_ISA) ? "ISA" :
+- (cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" :
+- (cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI",
++ (cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" : "IPAC PCI",
+ cs->hw.diva.cfg_reg, cs->irq);
+- if ((cs->subtyp == DIVA_IPAC_PCI) ||
+- (cs->subtyp == DIVA_IPACX_PCI) ||
+- (cs->subtyp == DIVA_PCI) )
+- printk(KERN_INFO "Diva: %s space at %#lx\n",
+- (cs->subtyp == DIVA_PCI) ? "PCI" :
+- (cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI",
++ if ((cs->subtyp == DIVA_IPAC_PCI) || (cs->subtyp == DIVA_PCI))
++ printk(KERN_INFO "Diva: %s PCI space at %#lx\n",
++ (cs->subtyp == DIVA_PCI) ? "PCI" : "IPAC PCI",
+ cs->hw.diva.pci_cfg);
+- if ((cs->subtyp != DIVA_IPAC_PCI) &&
+- (cs->subtyp != DIVA_IPACX_PCI) ) {
++ if (cs->subtyp != DIVA_IPAC_PCI) {
+ if (check_region(cs->hw.diva.cfg_reg, bytecnt)) {
+ printk(KERN_WARNING
+ "HiSax: %s config port %lx-%lx already in use\n",
+@@ -1177,17 +981,6 @@
+ cs->irq_func = &diva_irq_ipac_pci;
+ val = memreadreg(cs->hw.diva.cfg_reg, IPAC_ID);
+ printk(KERN_INFO "Diva: IPAC version %x\n", val);
+- } else if (cs->subtyp == DIVA_IPACX_PCI) {
+- cs->readisac = &MemReadISAC_IPACX;
+- cs->writeisac = &MemWriteISAC_IPACX;
+- cs->readisacfifo = &MemReadISACfifo_IPACX;
+- cs->writeisacfifo = &MemWriteISACfifo_IPACX;
+- cs->BC_Read_Reg = &MemReadHSCX_IPACX;
+- cs->BC_Write_Reg = &MemWriteHSCX_IPACX;
+- cs->BC_Send_Data = 0; // function located in ipacx module
+- cs->irq_func = &diva_irq_ipacx_pci;
+- printk(KERN_INFO "Diva: IPACX Design Id: %x\n",
+- MemReadISAC_IPACX(cs, IPACX_ID) &0x3F);
+ } else { /* DIVA 2.0 */
+ cs->hw.diva.tl.function = (void *) diva_led_handler;
+ cs->hw.diva.tl.data = (long) cs;
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/elsa.c linux-2.4.29/drivers/isdn/hisax/elsa.c
+--- linux-2.4.29.old/drivers/isdn/hisax/elsa.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/elsa.c 2005-03-22 15:06:46.123081008 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: elsa.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: elsa.c,v 2.32 2001/09/24 13:22:56 kai Exp $
+ *
+ * low level stuff for Elsa isdn cards
+ *
+@@ -28,13 +28,13 @@
+ #include "hscx.h"
+ #include "isdnl1.h"
+ #include <linux/pci.h>
+-#include <linux/isapnp.h>
++#include <linux/isdn_compat.h>
+ #include <linux/serial.h>
+ #include <linux/serial_reg.h>
+
+ extern const char *CardType[];
+
+-const char *Elsa_revision = "$Revision: 1.1.4.1 $";
++const char *Elsa_revision = "$Revision: 2.32 $";
+ const char *Elsa_Types[] =
+ {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
+ "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI",
+@@ -864,21 +864,6 @@
+ static struct pci_dev *dev_qs1000 __devinitdata = NULL;
+ static struct pci_dev *dev_qs3000 __devinitdata = NULL;
+
+-#ifdef __ISAPNP__
+-static struct isapnp_device_id elsa_ids[] __initdata = {
+- { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133),
+- ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133),
+- (unsigned long) "Elsa QS1000" },
+- { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134),
+- ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134),
+- (unsigned long) "Elsa QS3000" },
+- { 0, }
+-};
+-
+-static struct isapnp_device_id *pdev = &elsa_ids[0];
+-static struct pci_bus *pnp_c __devinitdata = NULL;
+-#endif
+-
+ int __devinit
+ setup_elsa(struct IsdnCard *card)
+ {
+@@ -893,7 +878,6 @@
+ cs->hw.elsa.ctrl_reg = 0;
+ cs->hw.elsa.status = 0;
+ cs->hw.elsa.MFlag = 0;
+- cs->subtyp = 0;
+ if (cs->typ == ISDN_CTYPE_ELSA) {
+ cs->hw.elsa.base = card->para[0];
+ printk(KERN_INFO "Elsa: Microlink IO probing\n");
+@@ -955,60 +939,9 @@
+ return (0);
+ }
+ } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
+-#ifdef __ISAPNP__
+- if (!card->para[1] && isapnp_present()) {
+- struct pci_bus *pb;
+- struct pci_dev *pd;
+-
+- while(pdev->card_vendor) {
+- if ((pb = isapnp_find_card(pdev->card_vendor,
+- pdev->card_device, pnp_c))) {
+- pnp_c = pb;
+- pd = NULL;
+- if ((pd = isapnp_find_dev(pnp_c,
+- pdev->vendor, pdev->function, pd))) {
+- printk(KERN_INFO "HiSax: %s detected\n",
+- (char *)pdev->driver_data);
+- pd->prepare(pd);
+- pd->deactivate(pd);
+- pd->activate(pd);
+- card->para[1] =
+- pd->resource[0].start;
+- card->para[0] =
+- pd->irq_resource[0].start;
+- if (!card->para[0] || !card->para[1]) {
+- printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
+- card->para[0], card->para[1]);
+- pd->deactivate(pd);
+- return(0);
+- }
+- if (pdev->function == ISAPNP_FUNCTION(0x133))
+- cs->subtyp = ELSA_QS1000;
+- else
+- cs->subtyp = ELSA_QS3000;
+- break;
+- } else {
+- printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
+- return(0);
+- }
+- }
+- pdev++;
+- pnp_c=NULL;
+- }
+- if (!pdev->card_vendor) {
+- printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
+- return(0);
+- }
+- }
+-#endif
+- if (card->para[1] && card->para[0]) {
+- cs->hw.elsa.base = card->para[1];
+- cs->irq = card->para[0];
+- if (!cs->subtyp)
+- cs->subtyp = ELSA_QS1000;
+- } else {
+- printk(KERN_ERR "Elsa PnP: no parameter\n");
+- }
++ cs->hw.elsa.base = card->para[1];
++ cs->irq = card->para[0];
++ cs->subtyp = ELSA_QS1000;
+ cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+ cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+ cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+@@ -1058,16 +991,16 @@
+ return(0);
+ cs->subtyp = ELSA_QS1000PCI;
+ cs->irq = dev_qs1000->irq;
+- cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
+- cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
++ cs->hw.elsa.cfg = pci_resource_start_io(dev_qs1000, 1);
++ cs->hw.elsa.base = pci_resource_start_io(dev_qs1000, 3);
+ } else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+ PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
+ if (pci_enable_device(dev_qs3000))
+ return(0);
+ cs->subtyp = ELSA_QS3000PCI;
+ cs->irq = dev_qs3000->irq;
+- cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
+- cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
++ cs->hw.elsa.cfg = pci_resource_start_io(dev_qs3000, 1);
++ cs->hw.elsa.base = pci_resource_start_io(dev_qs3000, 3);
+ } else {
+ printk(KERN_WARNING "Elsa: No PCI card found\n");
+ return(0);
+@@ -1123,7 +1056,6 @@
+ break;
+ case ELSA_PCFPRO:
+ case ELSA_PCF:
+- case ELSA_QS3000:
+ case ELSA_QS3000PCI:
+ bytecnt = 16;
+ break;
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/elsa_cs.c linux-2.4.29/drivers/isdn/hisax/elsa_cs.c
+--- linux-2.4.29.old/drivers/isdn/hisax/elsa_cs.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/elsa_cs.c 2005-03-22 15:06:46.138078728 +0100
+@@ -72,7 +72,7 @@
+ MODULE_PARM(pc_debug, "i");
+ #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
+ static char *version =
+-"elsa_cs.c $Revision: 1.1.4.1 $ $Date: 2001/11/20 14:19:35 $ (K.Lichtenwalder)";
++"elsa_cs.c $Revision: 1.2 $ $Date: 2001/09/24 13:22:56 $ (K.Lichtenwalder)";
+ #else
+ #define DEBUG(n, args...)
+ #endif
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/elsa_ser.c linux-2.4.29/drivers/isdn/hisax/elsa_ser.c
+--- linux-2.4.29.old/drivers/isdn/hisax/elsa_ser.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/elsa_ser.c 2005-03-22 15:06:46.158075688 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: elsa_ser.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: elsa_ser.c,v 2.14 2001/09/24 13:22:56 kai Exp $
+ *
+ * stuff for the serial modem on ELSA cards
+ *
+@@ -396,6 +396,74 @@
+ }
+ }
+
++#if 0
++static inline void check_modem_status(struct IsdnCardState *cs)
++{
++ int status;
++ struct async_struct *info = cs->hw.elsa.info;
++ struct async_icount *icount;
++
++ status = serial_inp(info, UART_MSR);
++
++ if (status & UART_MSR_ANY_DELTA) {
++ icount = &info->state->icount;
++ /* update input line counters */
++ if (status & UART_MSR_TERI)
++ icount->rng++;
++ if (status & UART_MSR_DDSR)
++ icount->dsr++;
++ if (status & UART_MSR_DDCD) {
++ icount->dcd++;
++ }
++ if (status & UART_MSR_DCTS)
++ icount->cts++;
++// wake_up(&info->delta_msr_wait);
++ }
++
++ if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
++#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
++ printk("ttys%d CD now %s...", info->line,
++ (status & UART_MSR_DCD) ? "on" : "off");
++#endif
++ if (status & UART_MSR_DCD)
++// wake_up(&info->open_wait);
++;
++ else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
++ (info->flags & ASYNC_CALLOUT_NOHUP))) {
++#ifdef SERIAL_DEBUG_OPEN
++ printk("doing serial hangup...");
++#endif
++ if (info->tty)
++ tty_hangup(info->tty);
++ }
++ }
++#if 0
++ if (info->flags & ASYNC_CTS_FLOW) {
++ if (info->tty->hw_stopped) {
++ if (status & UART_MSR_CTS) {
++#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
++ printk("CTS tx start...");
++#endif
++ info->tty->hw_stopped = 0;
++ info->IER |= UART_IER_THRI;
++ serial_outp(info, UART_IER, info->IER);
++// rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
++ return;
++ }
++ } else {
++ if (!(status & UART_MSR_CTS)) {
++#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
++ printk("CTS tx stop...");
++#endif
++ info->tty->hw_stopped = 1;
++ info->IER &= ~UART_IER_THRI;
++ serial_outp(info, UART_IER, info->IER);
++ }
++ }
++ }
++#endif 0
++}
++#endif
+
+ static void rs_interrupt_elsa(int irq, struct IsdnCardState *cs)
+ {
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/fsm.c linux-2.4.29/drivers/isdn/hisax/fsm.c
+--- linux-2.4.29.old/drivers/isdn/hisax/fsm.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/fsm.c 2005-03-22 15:06:46.174073256 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: fsm.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id$
+ *
+ * Finite state machine
+ *
+@@ -21,6 +21,14 @@
+
+ #define FSM_TIMER_DEBUG 0
+
++EXPORT_SYMBOL(FsmNew);
++EXPORT_SYMBOL(FsmFree);
++EXPORT_SYMBOL(FsmEvent);
++EXPORT_SYMBOL(FsmChangeState);
++EXPORT_SYMBOL(FsmInitTimer);
++EXPORT_SYMBOL(FsmDelTimer);
++EXPORT_SYMBOL(FsmRestartTimer);
++
+ int __init
+ FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount)
+ {
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/fsm.h linux-2.4.29/drivers/isdn/hisax/fsm.h
+--- linux-2.4.29.old/drivers/isdn/hisax/fsm.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/fsm.h 2005-03-22 15:06:46.189070976 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: fsm.h,v 1.1.2.1 2001/11/20 14:19:35 kai Exp $
++/* $Id$
+ *
+ * Finite state machine
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/gazel.c linux-2.4.29/drivers/isdn/hisax/gazel.c
+--- linux-2.4.29.old/drivers/isdn/hisax/gazel.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/gazel.c 2005-03-22 15:06:46.205068544 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: gazel.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: gazel.c,v 2.19 2001/09/24 13:22:56 kai Exp $
+ *
+ * low level stuff for Gazel isdn cards
+ *
+@@ -20,9 +20,10 @@
+ #include "isdnl1.h"
+ #include "ipac.h"
+ #include <linux/pci.h>
++#include <linux/isdn_compat.h>
+
+ extern const char *CardType[];
+-const char *gazel_revision = "$Revision: 1.1.4.1 $";
++const char *gazel_revision = "$Revision: 2.19 $";
+
+ #define R647 1
+ #define R685 2
+@@ -563,8 +564,8 @@
+ if (pci_enable_device(dev_tel))
+ return 1;
+ pci_irq = dev_tel->irq;
+- pci_ioaddr0 = pci_resource_start(dev_tel, 1);
+- pci_ioaddr1 = pci_resource_start(dev_tel, 2);
++ pci_ioaddr0 = pci_resource_start_io(dev_tel, 1);
++ pci_ioaddr1 = pci_resource_start_io(dev_tel, 2);
+ found = 1;
+ }
+ if (found)
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hfc_2bds0.c linux-2.4.29/drivers/isdn/hisax/hfc_2bds0.c
+--- linux-2.4.29.old/drivers/isdn/hisax/hfc_2bds0.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hfc_2bds0.c 2005-03-22 15:06:46.221066112 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hfc_2bds0.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: hfc_2bds0.c,v 1.18 2001/09/24 13:22:56 kai Exp $
+ *
+ * specific routines for CCD's HFC 2BDS0
+ *
+@@ -616,6 +616,17 @@
+ */
+ if (!cs)
+ return;
++#if 0
++ if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
++ if (cs->debug)
++ debugl1(cs, "D-Channel Busy cleared");
++ stptr = cs->stlist;
++ while (stptr != NULL) {
++ stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
++ stptr = stptr->next;
++ }
++ }
++#endif
+ if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+ switch (cs->dc.hfcd.ph_state) {
+ case (0):
+@@ -1090,6 +1101,32 @@
+ cs->hw.hfcD.mst_m |= HFCD_MASTER;
+ cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
+ break;
++#if 0
++ case (HW_TESTLOOP | REQUEST):
++ u_char val = 0;
++ if (1 & (int) arg)
++ val |= 0x0c;
++ if (2 & (int) arg)
++ val |= 0x3;
++ if (test_bit(HW_IOM1, &cs->HW_Flags)) {
++ /* IOM 1 Mode */
++ if (!val) {
++ cs->writeisac(cs, ISAC_SPCR, 0xa);
++ cs->writeisac(cs, ISAC_ADF1, 0x2);
++ } else {
++ cs->writeisac(cs, ISAC_SPCR, val);
++ cs->writeisac(cs, ISAC_ADF1, 0xa);
++ }
++ } else {
++ /* IOM 2 Mode */
++ cs->writeisac(cs, ISAC_SPCR, val);
++ if (val)
++ cs->writeisac(cs, ISAC_ADF1, 0x8);
++ else
++ cs->writeisac(cs, ISAC_ADF1, 0x0);
++ }
++ break;
++#endif
+ default:
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "hfcd_l1hw unknown pr %4x", pr);
+@@ -1106,6 +1143,20 @@
+ static void
+ hfc_dbusy_timer(struct IsdnCardState *cs)
+ {
++#if 0
++ struct PStack *stptr;
++ if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
++ if (cs->debug)
++ debugl1(cs, "D-Channel Busy");
++ test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
++ stptr = cs->stlist;
++
++ while (stptr != NULL) {
++ stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
++ stptr = stptr->next;
++ }
++ }
++#endif
+ }
+
+ unsigned int __init
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hfc_2bds0.h linux-2.4.29/drivers/isdn/hisax/hfc_2bds0.h
+--- linux-2.4.29.old/drivers/isdn/hisax/hfc_2bds0.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hfc_2bds0.h 2005-03-22 15:06:46.236063832 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hfc_2bds0.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: hfc_2bds0.h,v 1.6 2001/09/24 13:22:56 kai Exp $
+ *
+ * specific defines for CCD's HFC 2BDS0
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hfc_2bs0.c linux-2.4.29/drivers/isdn/hisax/hfc_2bs0.c
+--- linux-2.4.29.old/drivers/isdn/hisax/hfc_2bs0.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hfc_2bs0.c 2005-03-22 15:06:46.272058360 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hfc_2bs0.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: hfc_2bs0.c,v 1.20 2001/09/24 13:22:56 kai Exp $
+ *
+ * specific routines for CCD's HFC 2BS0
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hfc_2bs0.h linux-2.4.29/drivers/isdn/hisax/hfc_2bs0.h
+--- linux-2.4.29.old/drivers/isdn/hisax/hfc_2bs0.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hfc_2bs0.h 2005-03-22 15:06:46.288055928 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hfc_2bs0.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: hfc_2bs0.h,v 1.5 2001/09/24 13:22:56 kai Exp $
+ *
+ * specific defines for CCD's HFC 2BS0
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hfc_pci.c linux-2.4.29/drivers/isdn/hisax/hfc_pci.c
+--- linux-2.4.29.old/drivers/isdn/hisax/hfc_pci.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hfc_pci.c 2005-03-22 15:06:46.305053344 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hfc_pci.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: hfc_pci.c,v 1.48 2001/09/24 13:22:56 kai Exp $
+ *
+ * low level driver for CCD´s hfc-pci based cards
+ *
+@@ -22,11 +22,12 @@
+ #include "hfc_pci.h"
+ #include "isdnl1.h"
+ #include <linux/pci.h>
++#include <linux/isdn_compat.h>
+ #include <linux/interrupt.h>
+
+ extern const char *CardType[];
+
+-static const char *hfcpci_revision = "$Revision: 1.1.4.1 $";
++static const char *hfcpci_revision = "$Revision: 1.48 $";
+
+ /* table entry in the PCI devices list */
+ typedef struct {
+@@ -76,8 +77,6 @@
+ {
+ unsigned long flags;
+
+- printk(KERN_INFO "HiSax: release hfcpci at %p\n",
+- cs->hw.hfcpci.pci_io);
+ save_flags(flags);
+ cli();
+ cs->hw.hfcpci.int_m2 = 0; /* interrupt output off ! */
+@@ -88,11 +87,13 @@
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */
+ Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */
++#if CONFIG_PCI
+ pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0); /* disable memory mapped ports + busmaster */
++#endif /* CONFIG_PCI */
+ del_timer(&cs->hw.hfcpci.timer);
+ kfree(cs->hw.hfcpci.share_start);
+ cs->hw.hfcpci.share_start = NULL;
+- iounmap((void *)cs->hw.hfcpci.pci_io);
++ vfree(cs->hw.hfcpci.pci_io);
+ }
+
+ /********************************************************************************/
+@@ -687,10 +688,6 @@
+ debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded",
+ bcs->channel, bcs->tx_skb->len);
+
+- if (bcs->st->lli.l1writewakeup &&
+- (PACKET_NOACK != bcs->tx_skb->pkt_type))
+- bcs->st->lli.l1writewakeup(bcs->st, bcs->tx_skb->len);
+-
+ dev_kfree_skb_any(bcs->tx_skb);
+ cli();
+ bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */
+@@ -1146,6 +1143,20 @@
+ static void
+ hfcpci_dbusy_timer(struct IsdnCardState *cs)
+ {
++#if 0
++ struct PStack *stptr;
++ if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
++ if (cs->debug)
++ debugl1(cs, "D-Channel Busy");
++ test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
++ stptr = cs->stlist;
++
++ while (stptr != NULL) {
++ stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
++ stptr = stptr->next;
++ }
++ }
++#endif
+ }
+
+ /*************************************/
+@@ -1550,6 +1561,17 @@
+ */
+ if (!cs)
+ return;
++#if 0
++ if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
++ if (cs->debug)
++ debugl1(cs, "D-Channel Busy cleared");
++ stptr = cs->stlist;
++ while (stptr != NULL) {
++ stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
++ stptr = stptr->next;
++ }
++ }
++#endif
+ if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+ if (!cs->hw.hfcpci.nt_mode)
+ switch (cs->dc.hfcpci.ph_state) {
+@@ -1712,7 +1734,7 @@
+ if (pci_enable_device(tmp_hfcpci))
+ continue;
+ pci_set_master(tmp_hfcpci);
+- if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK)))
++ if ((card->para[0]) && (card->para[0] != (get_pcibase(tmp_hfcpci, 0) & PCI_BASE_ADDRESS_IO_MASK)))
+ continue;
+ else
+ break;
+@@ -1729,7 +1751,7 @@
+ printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
+ return (0);
+ }
+- cs->hw.hfcpci.pci_io = (char *) dev_hfcpci->resource[ 1].start;
++ cs->hw.hfcpci.pci_io = (char *) get_pcibase(dev_hfcpci, 1);
+ printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
+ } else {
+ printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
+@@ -1746,7 +1768,7 @@
+ printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n");
+ return 0;
+ }
+- cs->hw.hfcpci.fifos = (void *)
++ (ulong) cs->hw.hfcpci.fifos =
+ (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000;
+ pcibios_write_config_dword(cs->hw.hfcpci.pci_bus,
+ cs->hw.hfcpci.pci_device_fn, 0x80,
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hfc_pci.h linux-2.4.29/drivers/isdn/hisax/hfc_pci.h
+--- linux-2.4.29.old/drivers/isdn/hisax/hfc_pci.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hfc_pci.h 2005-03-22 15:06:46.320051064 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hfc_pci.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: hfc_pci.h,v 1.10 2001/09/24 13:22:56 kai Exp $
+ *
+ * specific defines for CCD's HFC 2BDS0 PCI chips
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hfc_sx.c linux-2.4.29/drivers/isdn/hisax/hfc_sx.c
+--- linux-2.4.29.old/drivers/isdn/hisax/hfc_sx.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hfc_sx.c 2005-03-22 15:06:46.350046504 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hfc_sx.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: hfc_sx.c,v 1.12 2001/09/24 13:22:56 kai Exp $
+ *
+ * level driver for CCD´s hfc-s+/sp based cards
+ *
+@@ -17,11 +17,10 @@
+ #include "hfc_sx.h"
+ #include "isdnl1.h"
+ #include <linux/interrupt.h>
+-#include <linux/isapnp.h>
+
+ extern const char *CardType[];
+
+-static const char *hfcsx_revision = "$Revision: 1.1.4.1 $";
++static const char *hfcsx_revision = "$Revision: 1.12 $";
+
+ /***************************************/
+ /* IRQ-table for CCDs demo board */
+@@ -940,6 +939,20 @@
+ static void
+ hfcsx_dbusy_timer(struct IsdnCardState *cs)
+ {
++#if 0
++ struct PStack *stptr;
++ if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
++ if (cs->debug)
++ debugl1(cs, "D-Channel Busy");
++ test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
++ stptr = cs->stlist;
++
++ while (stptr != NULL) {
++ stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
++ stptr = stptr->next;
++ }
++ }
++#endif
+ }
+
+ /*************************************/
+@@ -1333,6 +1346,17 @@
+ */
+ if (!cs)
+ return;
++#if 0
++ if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
++ if (cs->debug)
++ debugl1(cs, "D-Channel Busy cleared");
++ stptr = cs->stlist;
++ while (stptr != NULL) {
++ stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
++ stptr = stptr->next;
++ }
++ }
++#endif
+ if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+ if (!cs->hw.hfcsx.nt_mode)
+ switch (cs->dc.hfcsx.ph_state) {
+@@ -1461,17 +1485,7 @@
+ return (0);
+ }
+
+-#ifdef __ISAPNP__
+-static struct isapnp_device_id hfc_ids[] __initdata = {
+- { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620),
+- ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620),
+- (unsigned long) "Teles 16.3c2" },
+- { 0, }
+-};
+
+-static struct isapnp_device_id *hdev = &hfc_ids[0];
+-static struct pci_bus *pnp_c __devinitdata = NULL;
+-#endif
+
+ int __devinit
+ setup_hfcsx(struct IsdnCard *card)
+@@ -1482,45 +1496,6 @@
+
+ strcpy(tmp, hfcsx_revision);
+ printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp));
+-#ifdef __ISAPNP__
+- if (!card->para[1] && isapnp_present()) {
+- struct pci_bus *pb;
+- struct pci_dev *pd;
+-
+- while(hdev->card_vendor) {
+- if ((pb = isapnp_find_card(hdev->card_vendor,
+- hdev->card_device, pnp_c))) {
+- pnp_c = pb;
+- pd = NULL;
+- if ((pd = isapnp_find_dev(pnp_c,
+- hdev->vendor, hdev->function, pd))) {
+- printk(KERN_INFO "HiSax: %s detected\n",
+- (char *)hdev->driver_data);
+- pd->prepare(pd);
+- pd->deactivate(pd);
+- pd->activate(pd);
+- card->para[1] = pd->resource[0].start;
+- card->para[0] = pd->irq_resource[0].start;
+- if (!card->para[0] || !card->para[1]) {
+- printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
+- card->para[0], card->para[1]);
+- pd->deactivate(pd);
+- return(0);
+- }
+- break;
+- } else {
+- printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
+- }
+- }
+- hdev++;
+- pnp_c=NULL;
+- }
+- if (!hdev->card_vendor) {
+- printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
+- return(0);
+- }
+- }
+-#endif
+ cs->hw.hfcsx.base = card->para[1] & 0xfffe;
+ cs->irq = card->para[0];
+ cs->hw.hfcsx.int_s1 = 0;
+@@ -1603,3 +1578,7 @@
+ cs->auxcmd = &hfcsx_auxcmd;
+ return (1);
+ }
++
++
++
++
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hfc_sx.h linux-2.4.29/drivers/isdn/hisax/hfc_sx.h
+--- linux-2.4.29.old/drivers/isdn/hisax/hfc_sx.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hfc_sx.h 2005-03-22 15:06:46.365044224 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hfc_sx.h,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id$
+ *
+ * specific defines for CCD's HFC 2BDS0 S+,SP chips
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hfc_usb.c linux-2.4.29/drivers/isdn/hisax/hfc_usb.c
+--- linux-2.4.29.old/drivers/isdn/hisax/hfc_usb.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hfc_usb.c 2005-03-22 15:06:46.381041792 +0100
+@@ -0,0 +1,1189 @@
++/* $Id: hfc_usb.c,v 2.3 2001/07/06 21:30:11 werner Exp $
++ *
++ *
++ *
++ * Author (C) 2001 Werner Cornelius (werner@isdn-development.de)
++ * modular driver for Colognechip HFC-USB chip
++ * as plugin for HiSax isdn driver
++ * type approval valid for HFC-S USB based TAs
++ *
++ * Copyright 2001 by Werner Cornelius (werner@isdn-development.de)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include <linux/types.h>
++#include <linux/stddef.h>
++#include <linux/timer.h>
++#include <linux/config.h>
++#include <linux/isdn_compat.h>
++#include <linux/init.h>
++#include "hisax.h"
++#include <linux/module.h>
++#include <linux/kernel_stat.h>
++#include <linux/tqueue.h>
++#include <linux/usb.h>
++#include <linux/kernel.h>
++#include <linux/smp_lock.h>
++#include <linux/sched.h>
++#include "hisax_loadable.h"
++
++#define INCLUDE_INLINE_FUNCS
++
++/***********/
++/* defines */
++/***********/
++#define HFC_CTRL_TIMEOUT 5 /* 5ms timeout writing/reading regs */
++#define HFC_TIMER_T3 7000 /* timeout for l1 activation timer */
++
++#define HFCUSB_L1_STATECHANGE 0 /* L1 state changed */
++#define HFCUSB_L1_DRX 1 /* D-frame received */
++#define HFCUSB_L1_ERX 2 /* E-frame received */
++#define HFCUSB_L1_DTX 4 /* D-frames completed */
++
++#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */
++
++#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */
++#define HFCUSB_TX_THRESHOLD 64 /* threshold for fifo report bit tx */
++
++#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */
++#define HFCUSB_CIRM 0x00 /* cirm register index */
++#define HFCUSB_USB_SIZE 0x07 /* int length register */
++#define HFCUSB_USB_SIZE_I 0x06 /* iso length register */
++#define HFCUSB_F_CROSS 0x0b /* bit order register */
++#define HFCUSB_CLKDEL 0x37 /* bit delay register */
++#define HFCUSB_CON_HDLC 0xfa /* channel connect register */
++#define HFCUSB_HDLC_PAR 0xfb
++#define HFCUSB_SCTRL 0x31 /* S-bus control register (tx) */
++#define HFCUSB_SCTRL_E 0x32 /* same for E and special funcs */
++#define HFCUSB_SCTRL_R 0x33 /* S-bus control register (rx) */
++#define HFCUSB_F_THRES 0x0c /* threshold register */
++#define HFCUSB_FIFO 0x0f /* fifo select register */
++#define HFCUSB_F_USAGE 0x1a /* fifo usage register */
++#define HFCUSB_MST_MODE0 0x14
++#define HFCUSB_MST_MODE1 0x15
++#define HFCUSB_P_DATA 0x1f
++#define HFCUSB_INC_RES_F 0x0e
++#define HFCUSB_STATES 0x30
++
++#define HFCUSB_CHIPID 0x40 /* ID value of HFC-USB */
++
++/******************/
++/* fifo registers */
++/******************/
++#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */
++#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */
++#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */
++#define HFCUSB_B2_TX 2
++#define HFCUSB_B2_RX 3
++#define HFCUSB_D_TX 4
++#define HFCUSB_D_RX 5
++#define HFCUSB_PCM_TX 6
++#define HFCUSB_PCM_RX 7
++
++/************/
++/* LED mask */
++/************/
++#define LED_DRIVER 0x1
++#define LED_L1 0x2
++#define LED_BCH 0x4
++
++/**********/
++/* macros */
++/**********/
++#define Write_hfc(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),0,0,HFC_CTRL_TIMEOUT)
++#define Read_hfc(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT)
++
++#ifdef COMPAT_HAS_USB_IDTAB
++/****************************************/
++/* data defining the devices to be used */
++/****************************************/
++static __devinitdata const struct usb_device_id hfc_usb_idtab[3] = {
++ {USB_DEVICE(0x959, 0x2bd0)}, /* Colognechip ROM */
++ {USB_DEVICE(0x7b0, 0x0006)}, /* USB TA 128 */
++ {} /* end with an all-zeroes entry */
++};
++#endif
++
++/*************************************************/
++/* entry and size of output/input control buffer */
++/*************************************************/
++#define HFC_CTRL_BUFSIZE 32
++typedef struct {
++ __u8 hfc_reg; /* register number */
++ __u8 reg_val; /* value to be written (or read) */
++} ctrl_buft;
++
++/***************************************************************/
++/* structure defining input+output fifos (interrupt/bulk mode) */
++/***************************************************************/
++struct hfcusb_data; /* forward definition */
++typedef struct {
++ int fifonum; /* fifo index attached to this structure */
++ __u8 fifo_mask; /* mask for this fifo */
++ int active; /* fifo is currently active */
++ struct hfcusb_data *hfc; /* pointer to main structure */
++ int pipe; /* address of endpoint */
++ __u8 usb_maxlen; /* maximum length for usb transfer */
++ int max_size; /* maximum size of receive/send packet */
++ int transmode; /* transparent mode selected */
++ int framenum; /* number of frame when last tx completed */
++ int rx_offset; /* offset inside rx buffer */
++ int next_complete; /* complete marker */
++ __u8 *act_ptr; /* pointer to next data */
++ __u8 intervall; /* interrupt interval */
++ struct sk_buff *buff; /* actual used buffer */
++ urb_t urb; /* transfer structure for usb routines */
++ __u8 buffer[128]; /* buffer incoming/outgoing data */
++} usb_fifo;
++
++/*********************************************/
++/* structure holding all data for one device */
++/*********************************************/
++typedef struct hfcusb_data {
++ struct hisax_drvreg regd; /* register data and callbacks */
++ struct usb_device *dev; /* our device */
++ int if_used; /* used interface number */
++ int alt_used; /* used alternate config */
++ int ctrl_paksize; /* control pipe packet size */
++ int ctrl_in_pipe, ctrl_out_pipe; /* handles for control pipe */
++
++ /* control pipe background handling */
++ ctrl_buft ctrl_buff[HFC_CTRL_BUFSIZE]; /* buffer holding queued data */
++ volatile int ctrl_in_idx, ctrl_out_idx, ctrl_cnt; /* input/output pointer + count */
++ urb_t ctrl_urb; /* transfer structure for control channel */
++ devrequest ctrl_write; /* buffer for control write request */
++ devrequest ctrl_read; /* same for read request */
++
++ volatile __u8 dfifo_fill; /* value read from tx d-fifo */
++ volatile __u8 active_fifos; /* fifos currently active as bit mask */
++ volatile __u8 threshold_mask; /* threshold actually reported */
++ volatile __u8 service_request; /* fifo needs service from task */
++ volatile __u8 ctrl_fifo; /* last selected fifo */
++ volatile __u8 bch_enables; /* or mask for sctrl_r and sctrl register values */
++ volatile __u8 led_req; /* request status of adapters leds */
++ volatile __u8 led_act; /* active status of adapters leds */
++ usb_fifo fifos[HFCUSB_NUM_FIFOS]; /* structure holding all fifo data */
++
++ /* layer 1 activation/deactivation handling */
++ volatile __u8 l1_state; /* actual l1 state */
++ volatile ulong l1_event; /* event mask */
++ struct tq_struct l1_tq; /* l1 bh structure */
++ struct timer_list t3_timer; /* timer for activation/deactivation */
++ struct timer_list t4_timer; /* timer for activation/deactivation */
++} hfcusb_data;
++
++#if 0
++static void
++usb_dump_urb(purb_t purb)
++{
++ printk("urb :%p\n", purb);
++ printk("next :%p\n", purb->next);
++ printk("dev :%p\n", purb->dev);
++ printk("pipe :%08X\n", purb->pipe);
++ printk("status :%d\n", purb->status);
++ printk("transfer_flags :%08X\n", purb->transfer_flags);
++ printk("transfer_buffer :%p\n", purb->transfer_buffer);
++ printk("transfer_buffer_length:%d\n",
++ purb->transfer_buffer_length);
++ printk("actual_length :%d\n", purb->actual_length);
++ printk("setup_packet :%p\n", purb->setup_packet);
++ printk("start_frame :%d\n", purb->start_frame);
++ printk("number_of_packets :%d\n", purb->number_of_packets);
++ printk("interval :%d\n", purb->interval);
++ printk("error_count :%d\n", purb->error_count);
++ printk("context :%p\n", purb->context);
++ printk("complete :%p\n", purb->complete);
++}
++#endif
++
++/*************************************************************************/
++/* bottom half handler for L1 activation/deactiavtaion + D-chan + E-chan */
++/*************************************************************************/
++static void
++usb_l1d_bh(hfcusb_data * hfc)
++{
++
++ while (hfc->l1_event) {
++ if (test_and_clear_bit
++ (HFCUSB_L1_STATECHANGE, &hfc->l1_event)) {
++ if (hfc->l1_state == 7)
++ hfc->led_req |= LED_L1;
++ else
++ hfc->led_req &= ~LED_L1;
++ if ((hfc->l1_state == 7) ||
++ (hfc->l1_state == 3))
++ hfc->regd.dch_l1l2(hfc->regd.arg_hisax,
++ (hfc->l1_state ==
++ 7) ? (PH_ACTIVATE |
++ INDICATION)
++ : (PH_DEACTIVATE | INDICATION),
++ NULL);
++ }
++ if (test_and_clear_bit(HFCUSB_L1_DRX, &hfc->l1_event)) {
++ hfc->regd.dch_l1l2(hfc->regd.arg_hisax,
++ PH_DATA | INDICATION,
++ (void *) 0);
++ }
++ if (test_and_clear_bit(HFCUSB_L1_ERX, &hfc->l1_event)) {
++ hfc->regd.dch_l1l2(hfc->regd.arg_hisax,
++ PH_DATA | INDICATION,
++ (void *) 1);
++ }
++ if (test_and_clear_bit(HFCUSB_L1_DTX, &hfc->l1_event)) {
++ hfc->regd.dch_l1l2(hfc->regd.arg_hisax,
++ PH_DATA | CONFIRM, NULL);
++ }
++ } /* while */
++} /* usb_l1d_bh */
++
++/******************************************************/
++/* start next background transfer for control channel */
++/******************************************************/
++static void
++ctrl_start_transfer(hfcusb_data * hfc)
++{
++
++ if (hfc->ctrl_cnt) {
++ switch (hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg) {
++ case HFCUSB_F_USAGE:
++ hfc->ctrl_urb.pipe = hfc->ctrl_in_pipe;
++ hfc->ctrl_urb.setup_packet =
++ (u_char *) & hfc->ctrl_read;
++ hfc->ctrl_urb.transfer_buffer_length = 1;
++ hfc->ctrl_read.index =
++ hfc->ctrl_buff[hfc->ctrl_out_idx].
++ hfc_reg;
++ hfc->ctrl_urb.transfer_buffer =
++ (char *) &hfc->dfifo_fill;
++ break;
++
++ default: /* write register */
++ hfc->ctrl_urb.pipe = hfc->ctrl_out_pipe;
++ hfc->ctrl_urb.setup_packet =
++ (u_char *) & hfc->ctrl_write;
++ hfc->ctrl_urb.transfer_buffer = NULL;
++ hfc->ctrl_urb.transfer_buffer_length = 0;
++ hfc->ctrl_write.index =
++ hfc->ctrl_buff[hfc->ctrl_out_idx].
++ hfc_reg;
++ hfc->ctrl_write.value =
++ hfc->ctrl_buff[hfc->ctrl_out_idx].
++ reg_val;
++ break;
++ }
++ usb_submit_urb(&hfc->ctrl_urb); /* start transfer */
++ }
++} /* ctrl_start_transfer */
++
++/************************************/
++/* queue a control transfer request */
++/* return 0 on success. */
++/************************************/
++static int
++queue_control_request(hfcusb_data * hfc, __u8 reg, __u8 val)
++{
++ ctrl_buft *buf;
++
++ if (hfc->ctrl_cnt >= HFC_CTRL_BUFSIZE)
++ return (1); /* no space left */
++ buf = hfc->ctrl_buff + hfc->ctrl_in_idx; /* pointer to new index */
++ buf->hfc_reg = reg;
++ buf->reg_val = val;
++ if (++hfc->ctrl_in_idx >= HFC_CTRL_BUFSIZE)
++ hfc->ctrl_in_idx = 0; /* pointer wrap */
++ if (++hfc->ctrl_cnt == 1)
++ ctrl_start_transfer(hfc);
++ return (0);
++} /* queue_control_request */
++
++/**************************************/
++/* called when timer t3 or t4 expires */
++/**************************************/
++static void
++l1_timer_expire(hfcusb_data * hfc)
++{
++ if (timer_pending(&hfc->t4_timer))
++ del_timer(&hfc->t4_timer);
++ queue_control_request(hfc, HFCUSB_STATES, 0x40);
++ test_and_set_bit(HFCUSB_L1_STATECHANGE,
++ &hfc->l1_event);
++ queue_task(&hfc->l1_tq, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++} /* l1_timer_expire */
++
++/**************************************************/
++/* (re)fills a tx-fifo urb. Queuing is done later */
++/**************************************************/
++static void
++fill_tx_urb(usb_fifo * fifo)
++{
++ struct sk_buff *skb;
++ long flags;
++ int i, ii = 0;
++
++ fifo->urb.dev = fifo->hfc->dev;
++ if ((fifo->buff)
++ && (fifo->urb.transfer_buffer_length < fifo->usb_maxlen)) {
++ switch (fifo->fifonum) {
++ case HFCUSB_B1_TX:
++ case HFCUSB_B2_TX:
++ skb = fifo->buff;
++ fifo->buff = NULL;
++ fifo->hfc->regd.bch_l1l2(fifo->hfc->regd.
++ arg_hisax,
++ (fifo->fifonum ==
++ HFCUSB_B1_TX) ? 0
++ : 1,
++ (PH_DATA |
++ CONFIRM),
++ (void *) skb);
++ fifo->hfc->service_request |=
++ fifo->fifo_mask;
++ return;
++ case HFCUSB_D_TX:
++ dev_kfree_skb_any(fifo->buff);
++ fifo->buff = NULL;
++ save_flags(flags);
++ cli();
++ fifo->hfc->dfifo_fill = 0xff; /* currently invalid data */
++ queue_control_request(fifo->hfc,
++ HFCUSB_FIFO,
++ HFCUSB_D_TX);
++ queue_control_request(fifo->hfc,
++ HFCUSB_F_USAGE, 0);
++ restore_flags(flags);
++ return;
++ default:
++ return; /* error, invalid fifo */
++ }
++ }
++
++ /* check if new buffer needed */
++ if (!fifo->buff) {
++ switch (fifo->fifonum) {
++ case HFCUSB_B1_TX:
++ if (fifo->hfc->regd.bsk[0])
++ fifo->buff = *fifo->hfc->regd.bsk[0]; /* B1-channel tx buffer */
++ break;
++ case HFCUSB_B2_TX:
++ if (fifo->hfc->regd.bsk[1])
++ fifo->buff = *fifo->hfc->regd.bsk[1]; /* B2-channel tx buffer */
++ break;
++ case HFCUSB_D_TX:
++ if (fifo->hfc->regd.dsq)
++ fifo->buff = skb_dequeue(fifo->hfc->regd.dsq); /* D-channel tx queue */
++ break;
++ default:
++ return; /* error, invalid fifo */
++ }
++ if (!fifo->buff) {
++ fifo->active = 0; /* we are inactive now */
++ fifo->hfc->active_fifos &= ~fifo->fifo_mask;
++ if (fifo->fifonum == HFCUSB_D_TX) {
++ test_and_set_bit(HFCUSB_L1_DTX,
++ &fifo->hfc->l1_event);
++ queue_task(&fifo->hfc->l1_tq,
++ &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ }
++ return;
++ }
++ fifo->act_ptr = fifo->buff->data; /* start of data */
++ fifo->active = 1;
++ ii = 1;
++ fifo->hfc->active_fifos |= fifo->fifo_mask;
++ fifo->hfc->service_request &= ~fifo->fifo_mask;
++ }
++ /* fillup the send buffer */
++ i = fifo->buff->len - (fifo->act_ptr - fifo->buff->data); /* remaining length */
++ fifo->buffer[0] = !fifo->transmode; /* not eof */
++ if (i > (fifo->usb_maxlen - ii)) {
++ i = fifo->usb_maxlen - ii;
++ }
++ if (i)
++ memcpy(fifo->buffer + ii, fifo->act_ptr, i);
++ fifo->urb.transfer_buffer_length = i + ii;
++ fifo->rx_offset = ii;
++} /* fill_tx_urb */
++
++/************************************************/
++/* transmit completion routine for all tx fifos */
++/************************************************/
++static void
++tx_complete(purb_t urb)
++{
++ usb_fifo *fifo = (usb_fifo *) urb->context; /* pointer to our fifo */
++
++ fifo->hfc->service_request &= ~fifo->fifo_mask; /* no further handling */
++ fifo->framenum = usb_get_current_frame_number(fifo->hfc->dev);
++
++ /* check for deactivation or error */
++ if ((!fifo->active) || (urb->status)) {
++ fifo->hfc->active_fifos &= ~fifo->fifo_mask; /* we are inactive */
++ fifo->active = 0;
++ if ((fifo->buff) && (fifo->fifonum == HFCUSB_D_TX)) {
++ dev_kfree_skb_any(fifo->buff);
++ }
++ fifo->buff = NULL;
++ return;
++ }
++ fifo->act_ptr += (urb->transfer_buffer_length - fifo->rx_offset); /* adjust pointer */
++ fill_tx_urb(fifo); /* refill the urb */
++ fifo->hfc->threshold_mask |= fifo->fifo_mask; /* assume threshold reached */
++ if (fifo->buff)
++ fifo->hfc->service_request |= fifo->fifo_mask; /* need to restart */
++} /* tx_complete */
++
++/***********************************************/
++/* receive completion routine for all rx fifos */
++/***********************************************/
++static void
++rx_complete(purb_t urb)
++{
++ usb_fifo *fifo = (usb_fifo *) urb->context; /* pointer to our fifo */
++ hfcusb_data *hfc = fifo->hfc;
++ usb_fifo *txfifo;
++ __u8 last_state;
++ int i, ii, currcnt, hdlci;
++ struct sk_buff *skb;
++
++ urb->dev = hfc->dev; /* security init */
++ if ((!fifo->active) || (urb->status)) {
++ hfc->service_request &= ~fifo->fifo_mask; /* no further handling */
++ hfc->active_fifos &= ~fifo->fifo_mask; /* we are inactive */
++ fifo->urb.interval = 0; /* cancel automatic rescheduling */
++ if (fifo->buff) {
++ dev_kfree_skb_any(fifo->buff);
++ fifo->buff = NULL;
++ }
++ return;
++ }
++
++ /* first check for any status changes */
++ if ((urb->actual_length < fifo->rx_offset)
++ || (urb->actual_length > fifo->usb_maxlen))
++ return; /* error condition */
++
++ if (fifo->rx_offset) {
++ hfc->threshold_mask = fifo->buffer[1]; /* update threshold status */
++ fifo->next_complete = fifo->buffer[0] & 1;
++ if ((fifo->fifonum == HFCUSB_D_RX) &&
++ (hfc->led_req != hfc->led_act))
++ queue_control_request(hfc, HFCUSB_P_DATA, hfc->led_req);
++
++ /* check if rescheduling needed */
++ if ((i =
++ hfc->service_request & hfc->active_fifos & ~hfc->
++ threshold_mask)) {
++ currcnt =
++ usb_get_current_frame_number(hfc->dev);
++ txfifo = hfc->fifos + HFCUSB_B1_TX;
++ ii = 3;
++ while (ii--) {
++ if ((i & txfifo->fifo_mask)
++ && (currcnt != txfifo->framenum)) {
++ hfc->service_request &=
++ ~txfifo->fifo_mask;
++ if (!txfifo->buff)
++ fill_tx_urb(txfifo);
++ if (txfifo->buff)
++ usb_submit_urb(&txfifo->
++ urb);
++ }
++ txfifo += 2;
++ }
++ }
++
++ /* handle l1 events */
++ if ((fifo->buffer[0] >> 4) != hfc->l1_state) {
++ last_state = hfc->l1_state;
++ hfc->l1_state = fifo->buffer[0] >> 4; /* update status */
++ if (timer_pending(&hfc->t4_timer))
++ del_timer(&hfc->t4_timer);
++ if (((hfc->l1_state == 3) &&
++ ((last_state == 7) ||
++ (last_state == 8))) ||
++ ((timer_pending(&hfc->t3_timer) &&
++ (hfc->l1_state == 8)))) {
++ hfc->t4_timer.expires = jiffies + 2;
++ add_timer(&hfc->t4_timer);
++ } else {
++ if (timer_pending(&hfc->t3_timer)
++ && (hfc->l1_state == 7))
++ del_timer(&hfc->t3_timer); /* no longer needed */
++ test_and_set_bit(HFCUSB_L1_STATECHANGE,
++ &hfc->l1_event);
++ queue_task(&hfc->l1_tq, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ }
++ }
++ }
++
++ /* check the length for data and move if present */
++ if (fifo->next_complete || (urb->actual_length > fifo->rx_offset)) {
++ i = fifo->buff->len + urb->actual_length - fifo->rx_offset; /* new total length */
++ hdlci = (fifo->transmode) ? 0 : 3;
++ if (i <= (fifo->max_size + hdlci)) {
++ memcpy(fifo->act_ptr,
++ fifo->buffer + fifo->rx_offset,
++ urb->actual_length - fifo->rx_offset);
++ fifo->act_ptr +=
++ (urb->actual_length - fifo->rx_offset);
++ fifo->buff->len +=
++ (urb->actual_length - fifo->rx_offset);
++ } else
++ fifo->buff->len = fifo->max_size + 4; /* mark frame as to long */
++ if (fifo->next_complete && (urb->actual_length < fifo->usb_maxlen)) {
++ /* the frame is complete */
++ fifo->next_complete = 0;
++ if (((!*(fifo->act_ptr - 1)) || fifo->transmode) &&
++ (fifo->buff->len >= (hdlci + 1))
++ && (fifo->buff->len <=
++ (fifo->max_size + hdlci)) &&
++ ((skb = dev_alloc_skb(fifo->max_size + hdlci)) != NULL)) {
++ fifo->buff->len -= hdlci; /* adjust size */
++ switch (fifo->fifonum) {
++ case HFCUSB_D_RX:
++ skb_queue_tail(hfc->regd.
++ drq,
++ fifo->buff);
++ test_and_set_bit
++ (HFCUSB_L1_DRX,
++ &hfc->l1_event);
++ queue_task(&hfc->l1_tq,
++ &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ break;
++
++ case HFCUSB_B1_RX:
++ if (hfc->regd.brq[0]) {
++ skb_queue_tail
++ (hfc->regd.
++ brq[0],
++ fifo->buff);
++ hfc->regd.
++ bch_l1l2(hfc->
++ regd.
++ arg_hisax,
++ 0,
++ PH_DATA
++ |
++ INDICATION,
++ (void *)
++ fifo->
++ buff);
++ } else
++ dev_kfree_skb_any
++ (fifo->buff);
++ break;
++
++ case HFCUSB_B2_RX:
++ if (hfc->regd.brq[1]) {
++ skb_queue_tail
++ (hfc->regd.
++ brq[1],
++ fifo->buff);
++ hfc->regd.
++ bch_l1l2(hfc->
++ regd.
++ arg_hisax,
++ 1,
++ PH_DATA
++ |
++ INDICATION,
++ (void
++ *)
++ fifo->
++ buff);
++ } else
++ dev_kfree_skb_any
++ (fifo->buff);
++ break;
++
++ case HFCUSB_PCM_RX:
++ skb_queue_tail(&hfc->regd.
++ erq,
++ fifo->buff);
++ test_and_set_bit
++ (HFCUSB_L1_ERX,
++ &hfc->l1_event);
++ queue_task(&hfc->l1_tq,
++ &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ break;
++
++ default:
++ dev_kfree_skb_any(fifo->
++ buff);
++ break;
++ }
++ fifo->buff = skb;
++ }
++ fifo->buff->len = 0; /* reset counter */
++ fifo->act_ptr = fifo->buff->data; /* and pointer */
++ }
++ }
++ fifo->rx_offset = (urb->actual_length < fifo->usb_maxlen) ? 2 : 0;
++} /* rx_complete */
++
++/***************************************************/
++/* start the interrupt transfer for the given fifo */
++/***************************************************/
++static void
++start_rx_fifo(usb_fifo * fifo)
++{
++ if (fifo->buff)
++ return; /* still active */
++ if (!
++ (fifo->buff =
++ dev_alloc_skb(fifo->max_size + (fifo->transmode ? 0 : 3))))
++ return;
++ fifo->act_ptr = fifo->buff->data;
++ FILL_INT_URB(&fifo->urb, fifo->hfc->dev, fifo->pipe, fifo->buffer,
++ fifo->usb_maxlen, rx_complete, fifo, fifo->intervall);
++ fifo->next_complete = 0;
++ fifo->rx_offset = 2;
++ fifo->active = 1; /* must be marked active */
++ fifo->hfc->active_fifos |= fifo->fifo_mask;
++ if (usb_submit_urb(&fifo->urb)) {
++ fifo->active = 0;
++ fifo->hfc->active_fifos &= ~fifo->fifo_mask;
++ dev_kfree_skb_any(fifo->buff);
++ fifo->buff = NULL;
++ }
++} /* start_rx_fifo */
++
++/***************************************************************/
++/* control completion routine handling background control cmds */
++/***************************************************************/
++static void
++ctrl_complete(purb_t urb)
++{
++ hfcusb_data *hfc = (hfcusb_data *) urb->context;
++
++ urb->dev = hfc->dev;
++ if (hfc->ctrl_cnt) {
++ switch (hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg) {
++ case HFCUSB_FIFO:
++ hfc->ctrl_fifo =
++ hfc->ctrl_buff[hfc->ctrl_out_idx].
++ reg_val;
++ break;
++ case HFCUSB_F_USAGE:
++ if (!hfc->dfifo_fill) {
++ fill_tx_urb(hfc->fifos +
++ HFCUSB_D_TX);
++ if (hfc->fifos[HFCUSB_D_TX].buff)
++ usb_submit_urb(&hfc->
++ fifos
++ [HFCUSB_D_TX].
++ urb);
++ } else {
++ queue_control_request(hfc,
++ HFCUSB_FIFO,
++ HFCUSB_D_TX);
++ queue_control_request(hfc,
++ HFCUSB_F_USAGE,
++ 0);
++ }
++ break;
++ case HFCUSB_SCTRL_R:
++ switch (hfc->ctrl_fifo) {
++ case HFCUSB_B1_RX:
++ if (hfc->bch_enables & 1)
++ start_rx_fifo(hfc->
++ fifos
++ +
++ HFCUSB_B1_RX);
++ break;
++ case HFCUSB_B2_RX:
++ if (hfc->bch_enables & 2)
++ start_rx_fifo(hfc->
++ fifos
++ +
++ HFCUSB_B2_RX);
++ break;
++ }
++ if (hfc->bch_enables & 3)
++ hfc->led_req |= LED_BCH;
++ else
++ hfc->led_req &= ~LED_BCH;
++ break;
++ case HFCUSB_P_DATA:
++ hfc->led_act =
++ hfc->ctrl_buff[hfc->ctrl_out_idx].
++ reg_val;
++ break;
++ }
++ hfc->ctrl_cnt--; /* decrement actual count */
++ if (++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE)
++ hfc->ctrl_out_idx = 0; /* pointer wrap */
++ ctrl_start_transfer(hfc); /* start next transfer */
++ }
++} /* ctrl_complete */
++
++/*****************************************/
++/* Layer 1 + D channel access from HiSax */
++/*****************************************/
++static void
++hfcusb_l1_access(void *drvarg, int pr, void *arg)
++{
++ hfcusb_data *hfc = (hfcusb_data *) drvarg;
++
++ switch (pr) {
++ case (PH_DATA | REQUEST):
++ case (PH_PULL | INDICATION):
++ skb_queue_tail(hfc->regd.dsq,
++ (struct sk_buff *) arg);
++ if (!hfc->fifos[HFCUSB_D_TX].active
++ && !hfc->dfifo_fill) {
++ fill_tx_urb(hfc->fifos + HFCUSB_D_TX);
++ hfc->active_fifos |=
++ hfc->fifos[HFCUSB_D_TX].fifo_mask;
++ usb_submit_urb(&hfc->fifos[HFCUSB_D_TX].
++ urb);
++ }
++ break;
++ case (PH_ACTIVATE | REQUEST):
++ switch (hfc->l1_state) {
++ case 6:
++ case 8:
++ hfc->regd.dch_l1l2(hfc->regd.arg_hisax,
++ (PH_DEACTIVATE |
++ INDICATION), NULL);
++
++ break;
++ case 7:
++ hfc->regd.dch_l1l2(hfc->regd.arg_hisax,
++ (PH_ACTIVATE |
++ INDICATION), NULL);
++
++ break;
++ default:
++ queue_control_request(hfc, HFCUSB_STATES, 0x60); /* start activation */
++ hfc->t3_timer.expires =
++ jiffies + (HFC_TIMER_T3 * HZ) / 1000;
++ if (!timer_pending(&hfc->t3_timer))
++ add_timer(&hfc->t3_timer);
++ break;
++ }
++ break;
++
++ case (PH_DEACTIVATE | REQUEST):
++ queue_control_request(hfc, HFCUSB_STATES, 0x40); /* start deactivation */
++ break;
++ default:
++ printk(KERN_INFO "unknown hfcusb l1_access 0x%x\n",
++ pr);
++ break;
++ }
++} /* hfcusb_l1_access */
++
++/*******************************/
++/* B channel access from HiSax */
++/*******************************/
++static void
++hfcusb_bch_access(void *drvarg, int chan, int pr, void *arg)
++{
++ hfcusb_data *hfc = (hfcusb_data *) drvarg;
++ usb_fifo *fifo = hfc->fifos + (chan ? HFCUSB_B2_TX : HFCUSB_B1_TX);
++ long flags;
++
++ switch (pr) {
++ case (PH_DATA | REQUEST):
++ case (PH_PULL | INDICATION):
++ save_flags(flags);
++ cli();
++ if (!fifo->active) {
++ fill_tx_urb(fifo);
++ hfc->active_fifos |= fifo->fifo_mask;
++ usb_submit_urb(&fifo->urb);
++ }
++ restore_flags(flags);
++ break;
++ case (PH_ACTIVATE | REQUEST):
++ if (!((int) arg)) {
++ hfc->bch_enables &= ~(1 << chan);
++ if (fifo->active) {
++ fifo->active = 0;
++ usb_unlink_urb(&fifo->urb);
++ }
++ save_flags(flags);
++ cli();
++ queue_control_request(hfc, HFCUSB_FIFO,
++ fifo->fifonum);
++ queue_control_request(hfc,
++ HFCUSB_INC_RES_F, 2);
++ queue_control_request(hfc, HFCUSB_CON_HDLC,
++ 9);
++ queue_control_request(hfc, HFCUSB_SCTRL,
++ 0x40 +
++ hfc->bch_enables);
++ queue_control_request(hfc, HFCUSB_SCTRL_R,
++ hfc->bch_enables);
++ restore_flags(flags);
++ fifo++;
++ if (fifo->active) {
++ fifo->active = 0;
++ usb_unlink_urb(&fifo->urb);
++ }
++ return; /* fifo deactivated */
++ }
++ fifo->transmode = ((int) arg == L1_MODE_TRANS);
++ fifo->max_size =
++ ((fifo->transmode) ? fifo->
++ usb_maxlen : MAX_BCH_SIZE);
++ (fifo + 1)->transmode = fifo->transmode;
++ (fifo + 1)->max_size = fifo->max_size;
++ hfc->bch_enables |= (1 << chan);
++ save_flags(flags);
++ cli();
++ queue_control_request(hfc, HFCUSB_FIFO,
++ fifo->fifonum);
++ queue_control_request(hfc, HFCUSB_CON_HDLC,
++ ((!fifo->
++ transmode) ? 9 : 11));
++ queue_control_request(hfc, HFCUSB_INC_RES_F, 2);
++ queue_control_request(hfc, HFCUSB_SCTRL,
++ 0x40 + hfc->bch_enables);
++ if ((int) arg == L1_MODE_HDLC)
++ queue_control_request(hfc, HFCUSB_CON_HDLC,
++ 8);
++ queue_control_request(hfc, HFCUSB_FIFO,
++ fifo->fifonum + 1);
++ queue_control_request(hfc, HFCUSB_CON_HDLC,
++ ((!fifo->
++ transmode) ? 8 : 10));
++ queue_control_request(hfc, HFCUSB_INC_RES_F, 2);
++ queue_control_request(hfc, HFCUSB_SCTRL_R,
++ hfc->bch_enables);
++ restore_flags(flags);
++
++ break;
++
++ default:
++ printk(KERN_INFO
++ "unknown hfcusb bch_access chan %d 0x%x\n",
++ chan, pr);
++ break;
++ }
++} /* hfcusb_bch_access */
++
++/***************************************************************************/
++/* usb_init is called once when a new matching device is detected to setup */
++/* main parmeters. It registers the driver at the main hisax module. */
++/* on success 0 is returned. */
++/***************************************************************************/
++static int
++usb_init(hfcusb_data * hfc)
++{
++ usb_fifo *fifo;
++ int i;
++ u_char b;
++
++ /* check the chip id */
++ if ((Read_hfc(hfc, HFCUSB_CHIP_ID, &b) != 1) ||
++ (b != HFCUSB_CHIPID)) {
++ printk(KERN_INFO "HFC-USB: Invalid chip id 0x%02x\n", b);
++ return (1);
++ }
++
++ /* first set the needed config, interface and alternate */
++ usb_set_configuration(hfc->dev, 1);
++ usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used);
++
++ /* init the led state request */
++ hfc->led_req = LED_DRIVER;
++
++ /* now we initialise the chip */
++ Write_hfc(hfc, HFCUSB_CIRM, 0x10); /* aux = output, reset off */
++ Write_hfc(hfc, HFCUSB_P_DATA, 0); /* leds = off */
++ Write_hfc(hfc, HFCUSB_USB_SIZE,
++ (hfc->fifos[HFCUSB_B1_TX].usb_maxlen >> 3) |
++ ((hfc->fifos[HFCUSB_B1_RX].usb_maxlen >> 3) << 4));
++
++ /* enable PCM/GCI master mode */
++ Write_hfc(hfc, HFCUSB_MST_MODE1, 0); /* set default values */
++ Write_hfc(hfc, HFCUSB_MST_MODE0, 1); /* enable master mode */
++
++ /* init the fifos */
++ Write_hfc(hfc, HFCUSB_F_THRES, (HFCUSB_TX_THRESHOLD >> 3) |
++ ((HFCUSB_RX_THRESHOLD >> 3) << 4));
++
++ for (i = 0, fifo = hfc->fifos + i; i < HFCUSB_NUM_FIFOS;
++ i++, fifo++) {
++ Write_hfc(hfc, HFCUSB_FIFO, i); /* select the desired fifo */
++
++ fifo->transmode = 0; /* hdlc mode selected */
++ fifo->buff = NULL; /* init buffer pointer */
++ fifo->max_size =
++ (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN;
++ Write_hfc(hfc, HFCUSB_HDLC_PAR, ((i <= HFCUSB_B2_RX) ? 0 : 2)); /* data length */
++ Write_hfc(hfc, HFCUSB_CON_HDLC, ((i & 1) ? 0x08 : 0x09)); /* rx hdlc, tx fill 1 */
++ Write_hfc(hfc, HFCUSB_INC_RES_F, 2); /* reset the fifo */
++ }
++
++ Write_hfc(hfc, HFCUSB_CLKDEL, 0x0f); /* clock delay value */
++ Write_hfc(hfc, HFCUSB_STATES, 3 | 0x10); /* set deactivated mode */
++ Write_hfc(hfc, HFCUSB_STATES, 3); /* enable state machine */
++
++ Write_hfc(hfc, HFCUSB_SCTRL_R, 0); /* disable both B receivers */
++ Write_hfc(hfc, HFCUSB_SCTRL, 0x40); /* disable B transmitters + cap mode */
++
++ /* init the l1 timer */
++ init_timer(&hfc->t3_timer);
++ hfc->t3_timer.data = (long) hfc;
++ hfc->t3_timer.function = (void *) l1_timer_expire;
++ hfc->t4_timer.data = (long) hfc;
++ hfc->t4_timer.function = (void *) l1_timer_expire;
++ hfc->l1_tq.routine = (void *) (void *) usb_l1d_bh;
++ hfc->l1_tq.sync = 0;
++ hfc->l1_tq.data = hfc;
++
++ /* init the background control machinery */
++ hfc->ctrl_read.requesttype = 0xc0;
++ hfc->ctrl_read.request = 1;
++ hfc->ctrl_read.length = 1;
++ hfc->ctrl_write.requesttype = 0x40;
++ hfc->ctrl_write.request = 0;
++ hfc->ctrl_write.length = 0;
++ FILL_CONTROL_URB(&hfc->ctrl_urb, hfc->dev, hfc->ctrl_out_pipe,
++ (u_char *) & hfc->ctrl_write, NULL, 0,
++ ctrl_complete, hfc);
++
++ /* init the TX-urbs */
++ fifo = hfc->fifos + HFCUSB_D_TX;
++ FILL_BULK_URB(&fifo->urb, hfc->dev, fifo->pipe,
++ (u_char *) fifo->buffer, 0, tx_complete, fifo);
++ fifo = hfc->fifos + HFCUSB_B1_TX;
++ FILL_BULK_URB(&fifo->urb, hfc->dev, fifo->pipe,
++ (u_char *) fifo->buffer, 0, tx_complete, fifo);
++ fifo = hfc->fifos + HFCUSB_B2_TX;
++ FILL_BULK_URB(&fifo->urb, hfc->dev, fifo->pipe,
++ (u_char *) fifo->buffer, 0, tx_complete, fifo);
++
++ /* init the E-buffer */
++ skb_queue_head_init(&hfc->regd.erq);
++
++ /* now register ourself at hisax */
++ hfc->regd.version = HISAX_LOAD_VERSION; /* set our version */
++ hfc->regd.cmd = HISAX_LOAD_REGISTER; /* register command */
++ hfc->regd.argl1 = (void *) hfc; /* argument for our local routine */
++ hfc->regd.dch_l2l1 = hfcusb_l1_access;
++ hfc->regd.bch_l2l1 = hfcusb_bch_access;
++ hfc->regd.drvname = "hfc_usb";
++ if (hisax_register_hfcusb(&hfc->regd)) {
++ printk(KERN_INFO "HFC-USB failed to register at hisax\n");
++ Write_hfc(hfc, HFCUSB_CIRM, 0x08); /* aux = input, reset on */
++ return (1);
++ }
++
++ /* startup the D- and E-channel fifos */
++ start_rx_fifo(hfc->fifos + HFCUSB_D_RX); /* D-fifo */
++ if (hfc->fifos[HFCUSB_PCM_RX].pipe)
++ start_rx_fifo(hfc->fifos + HFCUSB_PCM_RX); /* E-fifo */
++
++ return (0);
++} /* usb_init */
++
++/*************************************************/
++/* function called to probe a new plugged device */
++/*************************************************/
++static void *
++hfc_usb_probe(struct usb_device *dev, unsigned int interface
++#ifdef COMPAT_HAS_USB_IDTAB
++ , const struct usb_device_id *id_table)
++#else
++ )
++#endif
++{
++ hfcusb_data *context;
++ struct usb_interface *ifp = dev->actconfig->interface + interface;
++ struct usb_interface_descriptor *ifdp =
++ ifp->altsetting + ifp->act_altsetting;
++ struct usb_endpoint_descriptor *epd;
++ int i, idx, ep_msk;
++
++#ifdef COMPAT_HAS_USB_IDTAB
++ if (id_table && (dev->descriptor.idVendor == id_table->idVendor) &&
++ (dev->descriptor.idProduct == id_table->idProduct) &&
++#else
++ if ((((dev->descriptor.idVendor == 0x959) &&
++ (dev->descriptor.idProduct == 0x2bd0)) ||
++ ((dev->descriptor.idVendor == 0x7b0) &&
++ (dev->descriptor.idProduct == 0x0006))) &&
++#endif
++ (ifdp->bNumEndpoints >= 6) && (ifdp->bNumEndpoints <= 16)) {
++ if (!(context = kmalloc(sizeof(hfcusb_data), GFP_KERNEL))) {
++ return (NULL); /* got no mem */
++ };
++ memset(context, 0, sizeof(hfcusb_data)); /* clear the structure */
++ i = ifdp->bNumEndpoints; /* get number of endpoints */
++ ep_msk = 0; /* none found */
++ epd = ifdp->endpoint; /* first endpoint descriptor */
++ while (i-- && ((ep_msk & 0xcf) != 0xcf)) {
++
++ idx = (((epd->bEndpointAddress & 0x7f) - 1) << 1); /* get endpoint base */
++ if (idx < 7) {
++ switch (epd->bmAttributes) {
++ case USB_ENDPOINT_XFER_INT:
++ if (!
++ (epd->
++ bEndpointAddress &
++ 0x80))
++ break; /* only interrupt in allowed */
++ idx++; /* input index is odd */
++ context->fifos[idx].pipe =
++ usb_rcvintpipe(dev,
++ epd->
++ bEndpointAddress);
++ break;
++
++ case USB_ENDPOINT_XFER_BULK:
++ if (epd->
++ bEndpointAddress &
++ 0x80)
++ break; /* only bulk out allowed */
++ context->fifos[idx].pipe =
++ usb_sndbulkpipe(dev,
++ epd->
++ bEndpointAddress);
++ break;
++ default:
++ context->fifos[idx].pipe = 0; /* reset data */
++ } /* switch attribute */
++
++ if (context->fifos[idx].pipe) {
++ context->fifos[idx].fifonum = idx;
++ context->fifos[idx].fifo_mask =
++ 1 << idx;
++ context->fifos[idx].hfc = context;
++ context->fifos[idx].usb_maxlen =
++ epd->wMaxPacketSize;
++ context->fifos[idx].intervall =
++ epd->bInterval;
++ ep_msk |= (1 << idx);
++ } else
++ ep_msk &= ~(1 << idx);
++ } /* idx < 7 */
++ epd++;
++ }
++
++ if ((ep_msk & 0x3f) != 0x3f) {
++ kfree(context);
++ return (NULL);
++ }
++ MOD_INC_USE_COUNT; /* lock our module */
++ context->dev = dev; /* save device */
++ context->if_used = interface; /* save used interface */
++ context->alt_used = ifp->act_altsetting; /* and alternate config */
++ context->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */
++
++ /* create the control pipes needed for register access */
++ context->ctrl_in_pipe = usb_rcvctrlpipe(context->dev, 0);
++ context->ctrl_out_pipe = usb_sndctrlpipe(context->dev, 0);
++
++ /* init the chip and register the driver */
++ if (usb_init(context)) {
++ kfree(context);
++ MOD_DEC_USE_COUNT;
++ return (NULL);
++ }
++
++ printk(KERN_INFO
++ "HFC-USB: New device if=%d alt=%d registered\n",
++ context->if_used, context->alt_used);
++ return (context);
++ }
++
++ return (NULL); /* no matching entry */
++} /* hfc_usb_probe */
++
++/****************************************************/
++/* function called when an active device is removed */
++/****************************************************/
++static void
++hfc_usb_disconnect(struct usb_device *usbdev, void *drv_context)
++{
++ hfcusb_data *context = drv_context;
++ int i;
++ struct sk_buff *skb;
++
++ /* tell all fifos to terminate */
++ for (i = 0; i < HFCUSB_NUM_FIFOS; i++)
++ if (context->fifos[i].active) {
++ context->fifos[i].active = 0;
++ usb_unlink_urb(&context->fifos[i].urb);
++ }
++ while (context->active_fifos) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ /* Timeout 10ms */
++ schedule_timeout((10 * HZ) / 1000);
++ }
++ if (timer_pending(&context->t3_timer))
++ del_timer(&context->t3_timer);
++ context->regd.release_driver(context->regd.arg_hisax);
++ while ((skb = skb_dequeue(&context->regd.erq)) != NULL)
++ dev_kfree_skb_any(skb);
++
++ kfree(context); /* free our structure again */
++ MOD_DEC_USE_COUNT; /* and decrement the usage counter */
++} /* hfc_usb_disconnect */
++
++/************************************/
++/* our driver information structure */
++/************************************/
++static struct usb_driver hfc_drv = {
++ name:"hfc_usb",
++#ifdef COMPAT_HAS_USB_IDTAB
++ id_table:hfc_usb_idtab,
++#endif
++ probe:hfc_usb_probe,
++ disconnect:hfc_usb_disconnect,
++};
++
++static void __exit
++hfc_usb_exit(void)
++{
++
++ usb_deregister(&hfc_drv); /* release our driver */
++ printk(KERN_INFO "HFC-USB module removed\n");
++}
++
++static int __init
++hfc_usb_init(void)
++{
++ struct hisax_drvreg drv;
++
++ drv.version = HISAX_LOAD_VERSION; /* set our version */
++ drv.cmd = HISAX_LOAD_CHKVER; /* check command only */
++ if (hisax_register_hfcusb(&drv)) {
++ printk(KERN_INFO "HFC-USB <-> hisax version conflict\n");
++ return (-1); /* unable to register */
++ }
++ if (usb_register(&hfc_drv)) {
++ printk(KERN_INFO
++ "Unable to register HFC-USB module at usb stack\n");
++ return (-1); /* unable to register */
++ }
++
++ printk(KERN_INFO "HFC-USB module loaded\n");
++ return (0);
++}
++
++module_init(hfc_usb_init);
++module_exit(hfc_usb_exit);
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hfc_usbr.c linux-2.4.29/drivers/isdn/hisax/hfc_usbr.c
+--- linux-2.4.29.old/drivers/isdn/hisax/hfc_usbr.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hfc_usbr.c 2005-03-22 15:06:46.397039360 +0100
+@@ -0,0 +1,471 @@
++/* $Id: hfc_usbr.c,v 2.5 2001/07/06 21:30:11 werner Exp $
++
++ * hfc_usb.c low level driver for CCD´s hfc-usb single chip controllers
++ * type approval valid for HFC-S USB based TAs
++ *
++ * Author Werner Cornelius (werner@isdn-development.de)
++ *
++ * Copyright 2001 by Werner Cornelius (werner@isdn4linux.de)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#define __NO_VERSION__
++#include <linux/init.h>
++#include "hisax.h"
++#include "isdnl1.h"
++#include "hisax_loadable.h"
++
++extern const char *CardType[];
++
++static const char *hfcusb_revision = "$Revision: 2.5 $";
++
++/*********************************/
++/* schedule a new b_channel task */
++/*********************************/
++static void
++hfcusb_sched_event(struct BCState *bcs, int event)
++{
++ bcs->event |= 1 << event;
++ queue_task(&bcs->tqueue, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++}
++
++/************************************************/
++/* select a b-channel entry matching and active */
++/************************************************/
++static
++struct BCState *
++Sel_BCS(struct IsdnCardState *cs, int channel)
++{
++ if (cs->bcs[0].mode && (cs->bcs[0].channel == channel))
++ return (&cs->bcs[0]);
++ else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel))
++ return (&cs->bcs[1]);
++ else
++ return (NULL);
++}
++
++/**********************************************/
++/* transfer function (D-channel from l2 to l1 */
++/**********************************************/
++static void
++hfcusb_d_l2l1(struct PStack *st, int pr, void *arg)
++{
++ struct IsdnCardState *cs = st->l1.hardware;
++ struct hisax_drvreg *drv = cs->hw.hfcusb.drv;
++
++ if (drv) {
++ switch (pr) {
++ case (PH_DATA | REQUEST):
++ case (PH_PULL | INDICATION):
++ cs->hw.hfcusb.dch_tx_busy = 1;
++ break;
++ case (PH_PULL | REQUEST):
++ if (!cs->hw.hfcusb.dch_tx_busy) {
++ test_and_clear_bit(FLG_L1_PULL_REQ,
++ &st->l1.Flags);
++ st->l1.l1l2(st, PH_PULL | CONFIRM,
++ NULL);
++ } else
++ test_and_set_bit(FLG_L1_PULL_REQ,
++ &st->l1.Flags);
++ return;
++ }
++ drv->dch_l2l1(drv, pr, arg);
++ } else
++ debugl1(cs, "hfcusb l2l1 called without existing driver");
++} /* hfcusb_d_l2l1 */
++
++/*****************************/
++/* E-channel receive routine */
++/*****************************/
++static void
++EChannel_proc_rcv(struct IsdnCardState *cs)
++{
++ u_char *ptr;
++ struct sk_buff *skb;
++ struct hisax_drvreg *usbdrv =
++ (struct hisax_drvreg *) cs->hw.hfcusb.drv;
++
++
++ while ((skb = skb_dequeue(&usbdrv->erq)) != NULL) {
++ if (cs->debug & DEB_DLOG_HEX) {
++ ptr = cs->dlog;
++ if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) {
++ *ptr++ = 'E';
++ *ptr++ = 'C';
++ *ptr++ = 'H';
++ *ptr++ = 'O';
++ *ptr++ = ':';
++ ptr += QuickHex(ptr, skb->data, skb->len);
++ ptr--;
++ *ptr++ = '\n';
++ *ptr = 0;
++ HiSax_putstatus(cs, NULL, cs->dlog);
++ } else
++ HiSax_putstatus(cs, "LogEcho: ",
++ "warning Frame too big (%d)",
++ skb->len);
++ }
++ dev_kfree_skb_any(skb);
++ }
++}
++
++/******************************************/
++/* transfer function called from L1 to L2 */
++/******************************************/
++static void
++hfcusb_d_l1l2(void *cs1, int pr, void *arg)
++{
++ struct IsdnCardState *cs = (struct IsdnCardState *) cs1;
++
++ switch (pr) {
++ case (PH_DATA | INDICATION):
++ if (!((int) arg))
++ DChannel_proc_rcv(cs);
++ else
++ EChannel_proc_rcv(cs);
++ break;
++
++ case (PH_DATA | CONFIRM):
++ cs->hw.hfcusb.dch_tx_busy = 0;
++ DChannel_proc_xmt(cs);
++ break;
++
++ case (PH_ACTIVATE | INDICATION):
++ case (PH_ACTIVATE | CONFIRM):
++ cs->stlist->l1.l1l2(cs->stlist, pr, arg);
++ if (cs->debug & L1_DEB_ISAC)
++ debugl1(cs, "layer 1 activated");
++ break;
++
++ case (PH_DEACTIVATE | INDICATION):
++ case (PH_DEACTIVATE | CONFIRM):
++ cs->stlist->l1.l1l2(cs->stlist, pr, arg);
++ if (cs->debug & L1_DEB_ISAC)
++ debugl1(cs, "layer 1 deactivated");
++ break;
++
++ default:
++ debugl1(cs, "unknown l1 msg 0x%x ", pr);
++ }
++} /* hfcusb_d_l1l2 */
++
++
++/******************************************/
++/* transfer function called from L1 to L2 */
++/******************************************/
++static void
++hfcusb_b_l1l2(void *cs1, int chan, int pr, void *arg)
++{
++ struct IsdnCardState *cs = (struct IsdnCardState *) cs1;
++ struct BCState *bcs = Sel_BCS(cs, chan);
++
++ switch (pr) {
++ case (PH_DATA | INDICATION):
++ if (!bcs)
++ return;
++ hfcusb_sched_event(bcs, B_RCVBUFREADY);
++ break;
++
++ case (PH_DATA | CONFIRM):
++ if (!bcs)
++ return;
++ bcs->tx_cnt -= bcs->tx_skb->len;
++ if (bcs->st->lli.l1writewakeup &&
++ (PACKET_NOACK != bcs->tx_skb->pkt_type))
++ bcs->st->lli.l1writewakeup(bcs->st,
++ bcs->tx_skb->
++ len);
++ dev_kfree_skb_any(bcs->tx_skb);
++ bcs->tx_skb = skb_dequeue(&bcs->squeue);
++ break;
++
++ case (PH_ACTIVATE | INDICATION):
++ case (PH_ACTIVATE | CONFIRM):
++ cs->stlist->l1.l1l2(cs->stlist, pr, arg);
++ if (cs->debug & L1_DEB_ISAC)
++ debugl1(cs, "layer 1 activated");
++ break;
++
++ case (PH_DEACTIVATE | INDICATION):
++ case (PH_DEACTIVATE | CONFIRM):
++ cs->stlist->l1.l1l2(cs->stlist, pr, arg);
++ if (cs->debug & L1_DEB_ISAC)
++ debugl1(cs, "layer 1 deactivated");
++ break;
++
++ default:
++ debugl1(cs, "unknown l1 b msg 0x%x ", pr);
++ }
++} /* hfcusb_b_l1l2 */
++
++
++/***********************************************/
++/* called during init setting l1 stack pointer */
++/***********************************************/
++void
++setstack_hfcusb(struct PStack *st, struct IsdnCardState *cs)
++{
++ st->l2.l2l1 = hfcusb_d_l2l1;
++}
++
++/**************************************/
++/* send B-channel data if not blocked */
++/**************************************/
++static void
++hfcusb_send_data(struct BCState *bcs)
++{
++ struct IsdnCardState *cs = bcs->cs;
++ struct hisax_drvreg *drv =
++ (struct hisax_drvreg *) cs->hw.hfcusb.drv;
++
++ if (!drv)
++ return;
++ drv->bch_l2l1(drv->argl1, bcs->channel, PH_DATA | REQUEST,
++ bcs->tx_skb);
++}
++
++/***************************************************************/
++/* activate/deactivate hardware for selected channels and mode */
++/***************************************************************/
++void
++mode_hfcusb(struct BCState *bcs, int mode, int bc)
++{
++ struct IsdnCardState *cs = bcs->cs;
++ struct hisax_drvreg *drv = cs->hw.hfcusb.drv;
++
++ if (!drv)
++ return;
++ if (cs->debug & L1_DEB_HSCX)
++ debugl1(cs, "HFCUSB bchannel mode %d bchan %d/%d",
++ mode, bc, bcs->channel);
++ bcs->mode = mode;
++ bcs->channel = bc;
++ if (mode) {
++ drv->bsk[bc] = &bcs->tx_skb;
++ drv->brq[bc] = &bcs->rqueue;
++ }
++ drv->bch_l2l1(drv->argl1, bc, PH_ACTIVATE | REQUEST,
++ (void *) mode);
++ if (!mode) {
++ drv->bsk[bc] = NULL;
++ drv->brq[bc] = NULL;
++ }
++}
++
++/******************************/
++/* Layer2 -> Layer 1 Transfer */
++/******************************/
++static void
++hfcusb_b_l2l1(struct PStack *st, int pr, void *arg)
++{
++ struct sk_buff *skb = arg;
++ struct hisax_drvreg *drv = st->l1.bcs->cs->hw.hfcusb.drv;
++ long flags;
++
++ switch (pr) {
++ case (PH_DATA | REQUEST):
++ save_flags(flags);
++ cli();
++ if (st->l1.bcs->tx_skb) {
++ skb_queue_tail(&st->l1.bcs->squeue, skb);
++ restore_flags(flags);
++ } else {
++ st->l1.bcs->tx_skb = skb;
++ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
++ restore_flags(flags);
++ }
++ break;
++ case (PH_PULL | INDICATION):
++ if (st->l1.bcs->tx_skb) {
++ printk(KERN_WARNING
++ "hfc_l2l1: this shouldn't happen\n");
++ break;
++ }
++ save_flags(flags);
++ cli();
++ st->l1.bcs->tx_skb = skb;
++ st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
++ restore_flags(flags);
++ break;
++ case (PH_PULL | REQUEST):
++ if (!st->l1.bcs->tx_skb) {
++ test_and_clear_bit(FLG_L1_PULL_REQ,
++ &st->l1.Flags);
++ st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
++ } else
++ test_and_set_bit(FLG_L1_PULL_REQ,
++ &st->l1.Flags);
++ break;
++ case (PH_ACTIVATE | REQUEST):
++ if (drv) {
++ test_and_set_bit(BC_FLG_ACTIV,
++ &st->l1.bcs->Flag);
++ mode_hfcusb(st->l1.bcs, st->l1.mode,
++ st->l1.bc);
++ l1_msg_b(st, pr, arg);
++ }
++ break;
++ case (PH_DEACTIVATE | REQUEST):
++ l1_msg_b(st, pr, arg);
++ break;
++ case (PH_DEACTIVATE | CONFIRM):
++ test_and_clear_bit(BC_FLG_ACTIV,
++ &st->l1.bcs->Flag);
++ test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
++ mode_hfcusb(st->l1.bcs, 0, st->l1.bc);
++ st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
++ break;
++ }
++}
++
++/******************************************/
++/* deactivate B-channel access and queues */
++/******************************************/
++static void
++close_hfcusb(struct BCState *bcs)
++{
++ mode_hfcusb(bcs, 0, bcs->channel);
++ if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
++ skb_queue_purge(&bcs->rqueue);
++ skb_queue_purge(&bcs->squeue);
++ if (bcs->tx_skb) {
++ dev_kfree_skb_any(bcs->tx_skb);
++ bcs->tx_skb = NULL;
++ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
++ }
++ }
++}
++
++/*************************************/
++/* init B-channel queues and control */
++/*************************************/
++static int
++open_hfcusbstate(struct IsdnCardState *cs, struct BCState *bcs)
++{
++ if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
++ skb_queue_head_init(&bcs->rqueue);
++ skb_queue_head_init(&bcs->squeue);
++ }
++ bcs->tx_skb = NULL;
++ test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
++ bcs->event = 0;
++ bcs->tx_cnt = 0;
++ return (0);
++}
++
++/*********************************/
++/* inits the stack for B-channel */
++/*********************************/
++static int
++setstack_2b(struct PStack *st, struct BCState *bcs)
++{
++ bcs->channel = st->l1.bc;
++ if (open_hfcusbstate(st->l1.hardware, bcs))
++ return (-1);
++ st->l1.bcs = bcs;
++ st->l2.l2l1 = hfcusb_b_l2l1;
++ setstack_manager(st);
++ bcs->st = st;
++ setstack_l1_B(st);
++ return (0);
++}
++
++/********************************/
++/* called for card init message */
++/********************************/
++void __devinit
++inithfcusb(struct IsdnCardState *cs)
++{
++ cs->setstack_d = setstack_hfcusb;
++ cs->BC_Send_Data = &hfcusb_send_data;
++ cs->bcs[0].BC_SetStack = setstack_2b;
++ cs->bcs[1].BC_SetStack = setstack_2b;
++ cs->bcs[0].BC_Close = close_hfcusb;
++ cs->bcs[1].BC_Close = close_hfcusb;
++ mode_hfcusb(cs->bcs, 0, 0);
++ mode_hfcusb(cs->bcs + 1, 0, 1);
++}
++
++
++
++/*******************************************/
++/* handle card messages from control layer */
++/*******************************************/
++static int
++hfcusb_card_msg(struct IsdnCardState *cs, int mt, void *arg)
++{
++ if (cs->debug & L1_DEB_ISAC)
++ debugl1(cs, "HFCUSB: card_msg %x", mt);
++ switch (mt) {
++ case CARD_INIT:
++ inithfcusb(cs);
++ return (0);
++ case CARD_RELEASE:
++ case CARD_RESET:
++ case CARD_TEST:
++ return (0);
++ }
++ return (0);
++}
++
++
++extern void
++ HiSax_closecard(int cardnr);
++/*****************************/
++/* release a driver instance */
++/* called when hardware is */
++/* no longer present. */
++/*****************************/
++static void
++release_hfcdrv(void *arg)
++{
++ struct IsdnCardState *cs = (struct IsdnCardState *) arg;
++
++ cs->hw.hfcusb.drv = NULL; /* disable any further use of driver */
++ HiSax_closecard(cs->cardnr);
++} /* release_hfcdrv */
++
++/*********************************************/
++/* called once when a new device is detected */
++/* initialises local data */
++/*********************************************/
++int
++setup_hfc_usb(struct IsdnCard *card)
++{
++ struct IsdnCardState *cs = card->cs;
++ char tmp[64];
++ struct hisax_drvreg *usbdrv =
++ (struct hisax_drvreg *) cs->hw.hfcusb.drv;
++
++ if (!usbdrv)
++ return (0); /* no driver data present */
++
++ strcpy(tmp, hfcusb_revision);
++ printk(KERN_INFO "HiSax: HFC-USB driver Rev. %s\n",
++ HiSax_getrev(tmp));
++
++ usbdrv->release_driver = &release_hfcdrv; /* release routine */
++ usbdrv->arg_hisax = (void *) cs; /* parameter for calling */
++ usbdrv->dch_l1l2 = &hfcusb_d_l1l2; /* access from L1 to HiSax */
++ usbdrv->bch_l1l2 = &hfcusb_b_l1l2;
++ usbdrv->drq = &cs->rq;
++ usbdrv->dsq = &cs->sq;
++ cs->cardmsg = &hfcusb_card_msg;
++ return (1); /* success */
++}
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hfcscard.c linux-2.4.29/drivers/isdn/hisax/hfcscard.c
+--- linux-2.4.29.old/drivers/isdn/hisax/hfcscard.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hfcscard.c 2005-03-22 15:06:46.412037080 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hfcscard.c,v 1.1.4.1 2001/11/20 14:19:35 kai Exp $
++/* $Id: hfcscard.c,v 1.10 2001/09/24 13:22:56 kai Exp $
+ *
+ * low level stuff for hfcs based cards (Teles3c, ACER P10)
+ *
+@@ -12,14 +12,13 @@
+
+ #define __NO_VERSION__
+ #include <linux/init.h>
+-#include <linux/isapnp.h>
+ #include "hisax.h"
+ #include "hfc_2bds0.h"
+ #include "isdnl1.h"
+
+ extern const char *CardType[];
+
+-static const char *hfcs_revision = "$Revision: 1.1.4.1 $";
++static const char *hfcs_revision = "$Revision: 1.10 $";
+
+ static void
+ hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+@@ -140,36 +139,6 @@
+ return(0);
+ }
+
+-#ifdef __ISAPNP__
+-static struct isapnp_device_id hfc_ids[] __initdata = {
+- { ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
+- ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
+- (unsigned long) "Acer P10" },
+- { ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002),
+- ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002),
+- (unsigned long) "Billion 2" },
+- { ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001),
+- ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001),
+- (unsigned long) "Billion 1" },
+- { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410),
+- ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410),
+- (unsigned long) "IStar PnP" },
+- { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610),
+- ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610),
+- (unsigned long) "Teles 16.3c" },
+- { ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001),
+- ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001),
+- (unsigned long) "Tornado Tipa C" },
+- { ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001),
+- ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001),
+- (unsigned long) "Genius Speed Surfer" },
+- { 0, }
+-};
+-
+-static struct isapnp_device_id *hdev = &hfc_ids[0];
+-static struct pci_bus *pnp_c __devinitdata = NULL;
+-#endif
+-
+ int __init
+ setup_hfcs(struct IsdnCard *card)
+ {
+@@ -178,46 +147,6 @@
+
+ strcpy(tmp, hfcs_revision);
+ printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp));
+-
+-#ifdef __ISAPNP__
+- if (!card->para[1] && isapnp_present()) {
+- struct pci_bus *pb;
+- struct pci_dev *pd;
+-
+- while(hdev->card_vendor) {
+- if ((pb = isapnp_find_card(hdev->card_vendor,
+- hdev->card_device, pnp_c))) {
+- pnp_c = pb;
+- pd = NULL;
+- if ((pd = isapnp_find_dev(pnp_c,
+- hdev->vendor, hdev->function, pd))) {
+- printk(KERN_INFO "HiSax: %s detected\n",
+- (char *)hdev->driver_data);
+- pd->prepare(pd);
+- pd->deactivate(pd);
+- pd->activate(pd);
+- card->para[1] = pd->resource[0].start;
+- card->para[0] = pd->irq_resource[0].start;
+- if (!card->para[0] || !card->para[1]) {
+- printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
+- card->para[0], card->para[1]);
+- pd->deactivate(pd);
+- return(0);
+- }
+- break;
+- } else {
+- printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
+- }
+- }
+- hdev++;
+- pnp_c=NULL;
+- }
+- if (!hdev->card_vendor) {
+- printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
+- return(0);
+- }
+- }
+-#endif
+ cs->hw.hfcD.addr = card->para[1] & 0xfffe;
+ cs->irq = card->para[0];
+ cs->hw.hfcD.cip = 0;
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hisax.h linux-2.4.29/drivers/isdn/hisax/hisax.h
+--- linux-2.4.29.old/drivers/isdn/hisax/hisax.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hisax.h 2005-03-22 15:06:46.431034192 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hisax.h,v 1.1.4.2 2001/12/09 19:15:28 kai Exp $
++/* $Id: hisax.h,v 2.64 2001/09/24 13:22:56 kai Exp $
+ *
+ * Basic declarations, defines and prototypes
+ *
+@@ -24,7 +24,9 @@
+ #include <linux/isdnif.h>
+ #include <linux/tty.h>
+ #include <linux/serial_reg.h>
++#ifndef COMPAT_NO_SOFTNET
+ #include <linux/netdevice.h>
++#endif
+
+ #define ERROR_STATISTIC
+
+@@ -68,9 +70,6 @@
+ #define DL_DATA 0x0220
+ #define DL_FLUSH 0x0224
+ #define DL_UNIT_DATA 0x0230
+-
+-#define MDL_BC_RELEASE 0x0278 // Formula-n enter:now
+-#define MDL_BC_ASSIGN 0x027C // Formula-n enter:now
+ #define MDL_ASSIGN 0x0280
+ #define MDL_REMOVE 0x0284
+ #define MDL_ERROR 0x0288
+@@ -472,8 +471,6 @@
+ #define BC_FLG_FTI_RUN 13
+ #define BC_FLG_LL_OK 14
+ #define BC_FLG_LL_CONN 15
+-#define BC_FLG_FTI_FTS 16
+-#define BC_FLG_FRH_WAIT 17
+
+ #define L1_MODE_NULL 0
+ #define L1_MODE_TRANS 1
+@@ -695,6 +692,13 @@
+ struct timer_list timer;
+ };
+
++#ifdef CONFIG_HISAX_HFC_USB
++struct hfcUSB_hw {
++ void *drv; /* pointer to driver structure */
++ int dch_tx_busy;
++};
++#endif
++
+ struct hfcSX_hw {
+ unsigned long base;
+ unsigned char cirm;
+@@ -838,17 +842,6 @@
+ int ph_state;
+ };
+
+-struct amd7930_chip {
+- u_char lmr1;
+- u_char ph_state;
+- u_char old_state;
+- u_char flg_t3;
+- unsigned int tx_xmtlen;
+- struct timer_list timer3;
+- void (*ph_command) (struct IsdnCardState *, u_char, char *);
+- void (*setIrqMask) (struct IsdnCardState *, u_char);
+-};
+-
+ struct icc_chip {
+ int ph_state;
+ u_char *mon_tx;
+@@ -902,6 +895,9 @@
+ struct njet_hw njet;
+ struct hfcD_hw hfcD;
+ struct hfcPCI_hw hfcpci;
++#ifdef CONFIG_HISAX_HFC_USB
++ struct hfcUSB_hw hfcusb;
++#endif
+ struct hfcSX_hw hfcsx;
+ struct ix1_hw niccy;
+ struct isurf_hw isurf;
+@@ -945,7 +941,6 @@
+ struct hfcpci_chip hfcpci;
+ struct hfcsx_chip hfcsx;
+ struct w6692_chip w6692;
+- struct amd7930_chip amd7930;
+ struct icc_chip icc;
+ } dc;
+ u_char *rcvbuf;
+@@ -967,6 +962,8 @@
+ #define MON0_TX 4
+ #define MON1_TX 8
+
++#define HISAX_MAX_CARDS 8
++
+ #define ISDN_CTYPE_16_0 1
+ #define ISDN_CTYPE_8_0 2
+ #define ISDN_CTYPE_16_3 3
+@@ -1006,8 +1003,8 @@
+ #define ISDN_CTYPE_HFC_SX 37
+ #define ISDN_CTYPE_NETJET_U 38
+ #define ISDN_CTYPE_HFC_SP_PCMCIA 39
+-#define ISDN_CTYPE_DYNAMIC 40
+-#define ISDN_CTYPE_ENTERNOW 41
++#define ISDN_CTYPE_HFC_USB 40
++#define ISDN_CTYPE_DYNAMIC 41
+ #define ISDN_CTYPE_COUNT 41
+
+
+@@ -1267,10 +1264,6 @@
+ #define CARD_NETJET_U 0
+ #endif
+
+-#ifdef CONFIG_HISAX_ENTERNOW_PCI
+-#define CARD_FN_ENTERNOW_PCI 1
+-#endif
+-
+ #define TEI_PER_CARD 1
+
+ /* L1 Debug */
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hisax_debug.h linux-2.4.29/drivers/isdn/hisax/hisax_debug.h
+--- linux-2.4.29.old/drivers/isdn/hisax/hisax_debug.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hisax_debug.h 2005-03-22 15:06:46.452031000 +0100
+@@ -28,7 +28,7 @@
+
+ #define DBG(level, format, arg...) do { \
+ if (level & __debug_variable) \
+-printk(KERN_DEBUG "%s: " format "\n" , __FUNCTION__ , ## arg); \
++printk(KERN_DEBUG __FUNCTION__ ": " format "\n" , ## arg); \
+ } while (0)
+
+ #define DBG_PACKET(level,data,count) \
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hisax_fcpcipnp.c linux-2.4.29/drivers/isdn/hisax/hisax_fcpcipnp.c
+--- linux-2.4.29.old/drivers/isdn/hisax/hisax_fcpcipnp.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hisax_fcpcipnp.c 2005-03-22 15:06:46.468028568 +0100
+@@ -20,22 +20,19 @@
+ *
+ * o POWER PC
+ * o clean up debugging
+- * o tx_skb at PH_DEACTIVATE time
+ */
+
+ #include <linux/version.h>
+ #include <linux/module.h>
+ #include <linux/init.h>
+ #include <linux/pci.h>
+-#include <linux/isapnp.h>
++#include "hisax_isapnp.h"
+ #include <linux/kmod.h>
+ #include <linux/slab.h>
+ #include <linux/skbuff.h>
+ #include <linux/netdevice.h>
+-
+-#include <asm/io.h>
+-
+ #include "hisax_fcpcipnp.h"
++#include "hisax_isac.h"
+
+ // debugging cruft
+ #define __debug_variable debug
+@@ -46,10 +43,14 @@
+ MODULE_PARM(debug, "i");
+ #endif
+
+-MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
++MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>");
+ MODULE_DESCRIPTION("AVM Fritz!PCI/PnP ISDN driver");
+
+-static struct pci_device_id fcpci_ids[] __devinitdata = {
++#ifndef PCI_DEVICE_ID_AVM_A1_V2
++#define PCI_DEVICE_ID_AVM_A1_V2 0x0e00
++#endif
++
++static struct pci_device_id fcpci_ids[] __initdata = {
+ { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1 , PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0, (unsigned long) "Fritz!Card PCI" },
+ { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1_V2, PCI_ANY_ID, PCI_ANY_ID,
+@@ -58,7 +59,7 @@
+ };
+ MODULE_DEVICE_TABLE(pci, fcpci_ids);
+
+-static struct isapnp_device_id fcpnp_ids[] __devinitdata = {
++static struct isapnp_device_id fcpnp_ids[] __initdata = {
+ { ISAPNP_VENDOR('A', 'V', 'M'), ISAPNP_FUNCTION(0x0900),
+ ISAPNP_VENDOR('A', 'V', 'M'), ISAPNP_FUNCTION(0x0900),
+ (unsigned long) "Fritz!Card PnP" },
+@@ -68,7 +69,8 @@
+
+ static int protocol = 2; /* EURO-ISDN Default */
+ MODULE_PARM(protocol, "i");
+-MODULE_LICENSE("GPL");
++
++static LIST_HEAD(adapter_list);
+
+ // ----------------------------------------------------------------------
+
+@@ -147,7 +149,7 @@
+ outb(idx, adapter->io + AVM_INDEX);
+ val = inb(adapter->io + AVM_DATA + (offset & 0xf));
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+- DBG(0x1000, " port %#x, value %#x",
++ DBG(0x1000, __FUNCTION__ " port %#x, value %#x",
+ offset, val);
+ return val;
+ }
+@@ -160,7 +162,7 @@
+ AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW;
+ unsigned long flags;
+
+- DBG(0x1000, " port %#x, value %#x",
++ DBG(0x1000, __FUNCTION__ " port %#x, value %#x",
+ offset, value);
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ outb(idx, adapter->io + AVM_INDEX);
+@@ -240,7 +242,7 @@
+ outl(offset, adapter->io + AVM_ISACSX_INDEX);
+ val = inl(adapter->io + AVM_ISACSX_DATA);
+ spin_unlock_irqrestore(&adapter->hw_lock, flags);
+- DBG(0x1000, " port %#x, value %#x",
++ DBG(0x1000, __FUNCTION__ " port %#x, value %#x",
+ offset, val);
+
+ return val;
+@@ -252,7 +254,7 @@
+ struct fritz_adapter *adapter = isac->priv;
+ unsigned long flags;
+
+- DBG(0x1000, " port %#x, value %#x",
++ DBG(0x1000, __FUNCTION__ " port %#x, value %#x",
+ offset, value);
+ spin_lock_irqsave(&adapter->hw_lock, flags);
+ outl(offset, adapter->io + AVM_ISACSX_INDEX);
+@@ -375,6 +377,9 @@
+
+ DBG(0x40, "hdlc_fill_fifo");
+
++ if (!skb)
++ BUG();
++
+ if (skb->len == 0)
+ BUG();
+
+@@ -515,7 +520,6 @@
+ }
+ skb_push(bcs->tx_skb, bcs->tx_cnt);
+ bcs->tx_cnt = 0;
+- hdlc_fill_fifo(bcs);
+ }
+
+ static inline void hdlc_xpr_irq(struct fritz_bcs *bcs)
+@@ -536,7 +540,7 @@
+ dev_kfree_skb_irq(skb);
+ }
+
+-static void hdlc_irq_one(struct fritz_bcs *bcs, u32 stat)
++static void hdlc_irq(struct fritz_bcs *bcs, u32 stat)
+ {
+ DBG(0x10, "ch%d stat %#x", bcs->channel, stat);
+ if (stat & HDLC_INT_RPR) {
+@@ -553,7 +557,7 @@
+ }
+ }
+
+-static inline void hdlc_irq(struct fritz_adapter *adapter)
++static inline void hdlc_interrupt(struct fritz_adapter *adapter)
+ {
+ int nr;
+ u32 stat;
+@@ -562,7 +566,7 @@
+ stat = adapter->read_hdlc_status(adapter, nr);
+ DBG(0x10, "HDLC %c stat %#x", 'A' + nr, stat);
+ if (stat & HDLC_INT_MASK)
+- hdlc_irq_one(&adapter->bcs[nr], stat);
++ hdlc_irq(&adapter->bcs[nr], stat);
+ }
+ }
+
+@@ -584,14 +588,14 @@
+ adapter->write_ctrl(bcs, 5);
+ break;
+ case L1_MODE_TRANS:
++ bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
++ adapter->write_ctrl(bcs, 5);
++ bcs->ctrl.sr.cmd = HDLC_CMD_XRS;
++ adapter->write_ctrl(bcs, 1);
++ bcs->ctrl.sr.cmd = 0;
++ break;
+ case L1_MODE_HDLC:
+- bcs->rcvidx = 0;
+- bcs->tx_cnt = 0;
+- bcs->tx_skb = NULL;
+- if (mode == L1_MODE_TRANS)
+- bcs->ctrl.sr.mode = HDLC_MODE_TRANS;
+- else
+- bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
++ bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
+ adapter->write_ctrl(bcs, 5);
+ bcs->ctrl.sr.cmd = HDLC_CMD_XRS;
+ adapter->write_ctrl(bcs, 1);
+@@ -645,10 +649,10 @@
+ return;
+ DBG(2, "STATUS0 %#x", val);
+ if (val & AVM_STATUS0_IRQ_ISAC)
+- isacsx_irq(&adapter->isac);
++ isacsx_interrupt(&adapter->isac);
+
+ if (val & AVM_STATUS0_IRQ_HDLC)
+- hdlc_irq(adapter);
++ hdlc_interrupt(adapter);
+ }
+
+ static void fcpci_irq(int intno, void *dev, struct pt_regs *regs)
+@@ -662,10 +666,10 @@
+ return;
+ DBG(2, "sval %#x", sval);
+ if (!(sval & AVM_STATUS0_IRQ_ISAC))
+- isac_irq(&adapter->isac);
++ isac_interrupt(&adapter->isac);
+
+ if (!(sval & AVM_STATUS0_IRQ_HDLC))
+- hdlc_irq(adapter);
++ hdlc_interrupt(adapter);
+ }
+
+ // ----------------------------------------------------------------------
+@@ -681,11 +685,6 @@
+ {
+ outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER |
+ AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0);
+-
+- outb(AVM_STATUS1_ENA_IOM | adapter->irq,
+- adapter->io + AVM_STATUS1);
+- set_current_state(TASK_UNINTERRUPTIBLE);
+- schedule_timeout(50*HZ / 1000); /* Timeout 50ms */
+ }
+
+ // ----------------------------------------------------------------------
+@@ -693,6 +692,7 @@
+ static int __devinit fcpcipnp_setup(struct fritz_adapter *adapter)
+ {
+ u32 val = 0;
++ struct pci_dev *pdev = adapter->pci_dev;
+ int retval;
+
+ DBG(1,"");
+@@ -700,21 +700,21 @@
+ isac_init(&adapter->isac); // FIXME is this okay now
+
+ retval = -EBUSY;
+- if (!request_region(adapter->io, 32, "fcpcipnp"))
++ if (!request_region(adapter->io, 32, "hisax_fcpcipnp"))
+ goto err;
+
+ switch (adapter->type) {
+ case AVM_FRITZ_PCIV2:
+- retval = request_irq(adapter->irq, fcpci2_irq, SA_SHIRQ,
+- "fcpcipnp", adapter);
++ retval = request_irq(pdev->irq, fcpci2_irq, SA_SHIRQ,
++ "hisax_fcpcipnp", adapter);
+ break;
+ case AVM_FRITZ_PCI:
+- retval = request_irq(adapter->irq, fcpci_irq, SA_SHIRQ,
+- "fcpcipnp", adapter);
++ retval = request_irq(pdev->irq, fcpci_irq, SA_SHIRQ,
++ "hisax_fcpcipnp", adapter);
+ break;
+ case AVM_FRITZ_PNP:
+- retval = request_irq(adapter->irq, fcpci_irq, 0,
+- "fcpcipnp", adapter);
++ retval = request_irq(pdev->irq, fcpci_irq, 0,
++ "hisax_fcpcipnp", adapter);
+ break;
+ }
+ if (retval)
+@@ -808,11 +808,23 @@
+
+ static void __devexit fcpcipnp_release(struct fritz_adapter *adapter)
+ {
++ struct pci_dev *pdev = adapter->pci_dev;
++
+ DBG(1,"");
+
+ outb(0, adapter->io + AVM_STATUS0);
+- free_irq(adapter->irq, adapter);
++ free_irq(pdev->irq, adapter);
+ release_region(adapter->io, 32);
++
++ switch (adapter->type) {
++ case AVM_FRITZ_PCI:
++ case AVM_FRITZ_PCIV2:
++ pci_disable_device(pdev);
++ break;
++ case AVM_FRITZ_PNP:
++ pdev->deactivate(pdev);
++ break;
++ }
+ }
+
+ // ----------------------------------------------------------------------
+@@ -830,6 +842,8 @@
+
+ memset(adapter, 0, sizeof(struct fritz_adapter));
+
++ adapter->pci_dev = pdev;
++
+ SET_MODULE_OWNER(&adapter->isac.hisax_d_if);
+ adapter->isac.hisax_d_if.ifc.priv = &adapter->isac;
+ adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1;
+@@ -840,6 +854,7 @@
+ adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i];
+ adapter->bcs[i].b_if.ifc.l2l1 = fritz_b_l2l1;
+ }
++ list_add(&adapter->list, &adapter_list);
+
+ pci_set_drvdata(pdev, adapter);
+
+@@ -854,6 +869,7 @@
+ static void delete_adapter(struct fritz_adapter *adapter)
+ {
+ hisax_unregister(&adapter->isac.hisax_d_if);
++ list_del(&adapter->list);
+ kfree(adapter);
+ }
+
+@@ -863,12 +879,15 @@
+ struct fritz_adapter *adapter;
+ int retval;
+
++ printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at %s\n",
++ (char *) ent->driver_data, pdev->slot_name);
++
+ retval = -ENOMEM;
+ adapter = new_adapter(pdev);
+ if (!adapter)
+ goto err;
+
+- if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2)
++ if (pdev->device == 0x0e00)
+ adapter->type = AVM_FRITZ_PCIV2;
+ else
+ adapter->type = AVM_FRITZ_PCI;
+@@ -876,12 +895,7 @@
+ retval = pci_enable_device(pdev);
+ if (retval)
+ goto err_free;
+-
+ adapter->io = pci_resource_start(pdev, 1);
+- adapter->irq = pdev->irq;
+-
+- printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at %s\n",
+- (char *) ent->driver_data, pdev->slot_name);
+
+ retval = fcpcipnp_setup(adapter);
+ if (retval)
+@@ -901,6 +915,9 @@
+ struct fritz_adapter *adapter;
+ int retval;
+
++ printk(KERN_INFO "hisax_fcpcipnp: found adapter %s\n",
++ (char *) ent->driver_data);
++
+ retval = -ENOMEM;
+ adapter = new_adapter(pdev);
+ if (!adapter)
+@@ -912,11 +929,8 @@
+ pdev->deactivate(pdev); // why?
+ pdev->activate(pdev);
+ adapter->io = pdev->resource[0].start;
+- adapter->irq = pdev->irq_resource[0].start;
+-
+- printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at IO %#x irq %d\n",
+- (char *) ent->driver_data, adapter->io, adapter->irq);
+-
++ pdev->irq = pdev->irq_resource[0].start;
++
+ retval = fcpcipnp_setup(adapter);
+ if (retval)
+ goto err_free;
+@@ -929,43 +943,35 @@
+ return retval;
+ }
+
+-static void __devexit fcpci_remove(struct pci_dev *pdev)
+-{
+- struct fritz_adapter *adapter = pci_get_drvdata(pdev);
+-
+- fcpcipnp_release(adapter);
+- pci_disable_device(pdev);
+- delete_adapter(adapter);
+-}
+-
+-static void __devexit fcpnp_remove(struct pci_dev *pdev)
++static void __devexit fcpcipnp_remove(struct pci_dev *pdev)
+ {
+ struct fritz_adapter *adapter = pci_get_drvdata(pdev);
+
+ fcpcipnp_release(adapter);
+- pdev->deactivate(pdev);
+ delete_adapter(adapter);
+ }
+
+ static struct pci_driver fcpci_driver = {
+- name: "fcpci",
+- probe: fcpci_probe,
+- remove: __devexit_p(fcpci_remove),
++ name: "fcpci",
++ probe: fcpci_probe,
++ remove: fcpcipnp_remove,
+ id_table: fcpci_ids,
+ };
+
+ static struct isapnp_driver fcpnp_driver = {
+- name: "fcpnp",
+- probe: fcpnp_probe,
+- remove: __devexit_p(fcpnp_remove),
++ name: "fcpnp",
++ probe: fcpnp_probe,
++ remove: fcpcipnp_remove,
+ id_table: fcpnp_ids,
+ };
+
+-static int __init hisax_fcpcipnp_init(void)
++static LIST_HEAD(isapnp_drivers);
++
++static int __init hisax_fcpci_init(void)
+ {
+ int retval, pci_nr_found;
+
+- printk(KERN_INFO "hisax_fcpcipnp: Fritz!Card PCI/PCIv2/PnP ISDN driver v0.0.1\n");
++ printk(KERN_INFO "hisax_fcpcipnp: Fritz!PCI/PnP ISDN driver v0.0.1\n");
+
+ retval = pci_register_driver(&fcpci_driver);
+ if (retval < 0)
+@@ -976,15 +982,14 @@
+ if (retval < 0)
+ goto out_unregister_pci;
+
+-#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
++#if !defined(CONFIG_HOTPLUG) && defined(MODULE)
+ if (pci_nr_found + retval == 0) {
+ retval = -ENODEV;
+ goto out_unregister_isapnp;
+- }
+ #endif
+ return 0;
+
+-#if !defined(CONFIG_HOTPLUG) || defined(MODULE)
++#if !defined(CONFIG_HOTPLUG) && defined(MODULE)
+ out_unregister_isapnp:
+ isapnp_unregister_driver(&fcpnp_driver);
+ #endif
+@@ -994,11 +999,15 @@
+ return retval;
+ }
+
+-static void __exit hisax_fcpcipnp_exit(void)
++static void __exit hisax_fcpci_exit(void)
+ {
+ isapnp_unregister_driver(&fcpnp_driver);
+ pci_unregister_driver(&fcpci_driver);
+ }
+
+-module_init(hisax_fcpcipnp_init);
+-module_exit(hisax_fcpcipnp_exit);
++module_init(hisax_fcpci_init);
++module_exit(hisax_fcpci_exit);
++
++#ifdef __ISAPNP__
++#include "hisax_isapnp.c"
++#endif
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hisax_fcpcipnp.h linux-2.4.29/drivers/isdn/hisax/hisax_fcpcipnp.h
+--- linux-2.4.29.old/drivers/isdn/hisax/hisax_fcpcipnp.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hisax_fcpcipnp.h 2005-03-22 15:06:46.484026136 +0100
+@@ -43,10 +43,12 @@
+ };
+
+ struct fritz_adapter {
++ struct list_head list;
++ struct pci_dev *pci_dev;
++
+ int type;
+ spinlock_t hw_lock;
+ unsigned int io;
+- unsigned int irq;
+ struct isac isac;
+
+ struct fritz_bcs bcs[2];
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hisax_isac.c linux-2.4.29/drivers/isdn/hisax/hisax_isac.c
+--- linux-2.4.29.old/drivers/isdn/hisax/hisax_isac.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hisax_isac.c 2005-03-22 15:06:46.543017168 +0100
+@@ -34,7 +34,7 @@
+ static int debug = 1;
+ MODULE_PARM(debug, "i");
+
+-static char *ISACVer[] = {
++static char *ISACVer[] __devinitdata = {
+ "2086/2186 V1.1",
+ "2085 B1",
+ "2085 B2",
+@@ -42,10 +42,6 @@
+ };
+ #endif
+
+-MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>");
+-MODULE_DESCRIPTION("ISAC/ISAC-SX driver");
+-MODULE_LICENSE("GPL");
+-
+ #define DBG_WARN 0x0001
+ #define DBG_IRQ 0x0002
+ #define DBG_L1M 0x0004
+@@ -438,7 +434,7 @@
+ va_end(args);
+ }
+
+-static void isac_version(struct isac *cs)
++static void __devinit isac_version(struct isac *cs)
+ {
+ int val;
+
+@@ -602,7 +598,7 @@
+ }
+ }
+
+-void isac_irq(struct isac *isac)
++void isac_interrupt(struct isac *isac)
+ {
+ unsigned char val;
+
+@@ -635,8 +631,6 @@
+ if (val & ISAC_ISTA_SIN) {
+ DBG(DBG_WARN, "SIN");
+ }
+- isac->write_isac(isac, ISAC_MASK, 0xff);
+- isac->write_isac(isac, ISAC_MASK, 0x00);
+ }
+
+ // ======================================================================
+@@ -742,7 +736,7 @@
+ }
+ }
+
+-void isacsx_irq(struct isac *isac)
++void isacsx_interrupt(struct isac *isac)
+ {
+ unsigned char val;
+
+@@ -755,7 +749,7 @@
+ isacsx_cic_interrupt(isac);
+ }
+
+-void isac_init(struct isac *isac)
++void __devinit isac_init(struct isac *isac)
+ {
+ isac->tx_skb = NULL;
+ isac->l1m.fsm = &l1fsm;
+@@ -770,7 +764,7 @@
+ FsmInitTimer(&isac->l1m, &isac->timer);
+ }
+
+-void isac_setup(struct isac *isac)
++void __devinit isac_setup(struct isac *isac)
+ {
+ int val, eval;
+
+@@ -781,7 +775,7 @@
+
+ isac->write_isac(isac, ISAC_MASK, 0xff);
+ isac->mocr = 0xaa;
+- if (test_bit(ISAC_IOM1, &isac->flags)) {
++ if (test_bit(HW_IOM1, &isac->flags)) {
+ /* IOM 1 Mode */
+ isac->write_isac(isac, ISAC_ADF2, 0x0);
+ isac->write_isac(isac, ISAC_SPCR, 0xa);
+@@ -817,7 +811,7 @@
+ FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL);
+
+ isac->write_isac(isac, ISAC_MASK, 0x0);
+- // RESET Receiver and Transmitter
++ /* RESET Receiver and Transmitter */
+ isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_XRES | ISAC_CMDR_RRES);
+ }
+
+@@ -888,10 +882,10 @@
+ EXPORT_SYMBOL(isac_d_l2l1);
+
+ EXPORT_SYMBOL(isacsx_setup);
+-EXPORT_SYMBOL(isacsx_irq);
++EXPORT_SYMBOL(isacsx_interrupt);
+
+ EXPORT_SYMBOL(isac_setup);
+-EXPORT_SYMBOL(isac_irq);
++EXPORT_SYMBOL(isac_interrupt);
+
+ module_init(hisax_isac_init);
+ module_exit(hisax_isac_exit);
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hisax_isac.h linux-2.4.29/drivers/isdn/hisax/hisax_isac.h
+--- linux-2.4.29.old/drivers/isdn/hisax/hisax_isac.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hisax_isac.h 2005-03-22 15:06:46.559014736 +0100
+@@ -8,7 +8,7 @@
+ #define TIMER3_VALUE 7000
+ #define MAX_DFRAME_LEN_L1 300
+
+-#define ISAC_IOM1 0
++#define HW_IOM1 0
+
+ struct isac {
+ void *priv;
+@@ -37,9 +37,9 @@
+ void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg);
+
+ void isac_setup(struct isac *isac);
+-void isac_irq(struct isac *isac);
++void isac_interrupt(struct isac *isac);
+
+ void isacsx_setup(struct isac *isac);
+-void isacsx_irq(struct isac *isac);
++void isacsx_interrupt(struct isac *isac);
+
+ #endif
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hisax_isapnp.c linux-2.4.29/drivers/isdn/hisax/hisax_isapnp.c
+--- linux-2.4.29.old/drivers/isdn/hisax/hisax_isapnp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hisax_isapnp.c 2005-03-22 15:06:46.576012152 +0100
+@@ -0,0 +1,105 @@
++// FIXME copied
++static const struct isapnp_device_id *
++isapnp_match_device(const struct isapnp_device_id *ids, struct pci_dev *dev)
++{
++ DBG(1,"");
++
++ while (ids->card_vendor || ids->card_device) {
++ if ((ids->card_vendor == ISAPNP_ANY_ID || ids->card_vendor == dev->bus->vendor) &&
++ (ids->card_device == ISAPNP_ANY_ID || ids->card_device == dev->bus->device) &&
++ (ids->vendor == ISAPNP_ANY_ID || ids->vendor == dev->vendor) &&
++ (ids->function == ISAPNP_ANY_ID || ids->function == dev->device))
++ return ids;
++ ids++;
++ }
++ return NULL;
++}
++
++/**
++ * pci_dev_driver - get the pci_driver of a device
++ * @dev: the device to query
++ *
++ * Returns the appropriate pci_driver structure or %NULL if there is no
++ * registered driver for the device.
++ */
++struct pci_driver *isapnp_dev_driver(const struct pci_dev *dev)
++{
++ return dev->driver;
++}
++
++static int isapnp_announce_device(struct isapnp_driver *drv, struct pci_dev *dev)
++{
++ const struct isapnp_device_id *id;
++ int ret = 0;
++
++ DBG(1,"");
++
++ if (drv->id_table) {
++ id = isapnp_match_device(drv->id_table, dev);
++ if (!id) {
++ ret = 0;
++ goto out;
++ }
++ } else
++ id = NULL;
++
++// dev_probe_lock();
++ if (drv->probe(dev, id) >= 0) {
++ dev->driver = (struct pci_driver *) drv;
++ ret = 1;
++ }
++// dev_probe_unlock();
++out:
++ return ret;
++}
++
++/**
++ * FIXME pci_register_driver - register a new pci driver
++ * @drv: the driver structure to register
++ *
++ * Adds the driver structure to the list of registered drivers
++ * Returns the number of pci devices which were claimed by the driver
++ * during registration. The driver remains registered even if the
++ * return value is zero.
++ */
++int isapnp_register_driver(struct isapnp_driver *drv)
++{
++ struct pci_dev *dev;
++ int count = 0;
++
++ DBG(1,"");
++
++ list_add_tail(&drv->node, &isapnp_drivers);
++ isapnp_for_each_dev(dev) {
++ if (!isapnp_dev_driver(dev))
++ count += isapnp_announce_device(drv, dev);
++ }
++ return count;
++}
++
++/**
++ * pci_unregister_driver - unregister a pci driver
++ * @drv: the driver structure to unregister
++ *
++ * Deletes the driver structure from the list of registered PCI drivers,
++ * gives it a chance to clean up by calling its remove() function for
++ * each device it was responsible for, and marks those devices as
++ * driverless.
++ */
++
++void isapnp_unregister_driver(struct isapnp_driver *drv)
++{
++ struct pci_dev *dev;
++
++ DBG(1,"");
++
++ list_del(&drv->node);
++ isapnp_for_each_dev(dev) {
++ if (dev->driver == (struct pci_driver *) drv) {
++ if (drv->remove)
++ drv->remove(dev);
++ dev->driver = NULL;
++ }
++ }
++}
++
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hisax_isapnp.h linux-2.4.29/drivers/isdn/hisax/hisax_isapnp.h
+--- linux-2.4.29.old/drivers/isdn/hisax/hisax_isapnp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hisax_isapnp.h 2005-03-22 15:06:46.590010024 +0100
+@@ -0,0 +1,33 @@
++#ifndef __HISAX_ISAPNP_H__
++#define __HISAX_ISAPNP_H__
++
++#include <linux/isapnp.h>
++
++#ifdef COMPAT_NEED_ISAPNP_DRIVER
++struct isapnp_driver {
++ struct list_head node;
++ char *name;
++ const struct isapnp_device_id *id_table; /* NULL if wants all devices */
++ int (*probe) (struct pci_dev *dev, const struct isapnp_device_id *id); /* New device inserted */
++ void (*remove) (struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */
++};
++#endif
++#ifdef __ISAPNP__
++
++int isapnp_register_driver(struct isapnp_driver *drv);
++void isapnp_unregister_driver(struct isapnp_driver *drv);
++
++#else
++
++static inline int isapnp_register_driver(struct isapnp_driver *drv)
++{
++ return 0;
++}
++
++static inline void isapnp_unregister_driver(struct isapnp_driver *drv)
++{
++}
++
++#endif
++
++#endif
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hisax_loadable.h linux-2.4.29/drivers/isdn/hisax/hisax_loadable.h
+--- linux-2.4.29.old/drivers/isdn/hisax/hisax_loadable.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hisax_loadable.h 2005-03-22 15:06:46.606007592 +0100
+@@ -0,0 +1,74 @@
++/* $Id: hisax_loadable.h,v 2.1 2001/06/08 22:19:16 werner Exp $
++ *
++ *
++ * Author (C) 2001 Werner Cornelius (werner@isdn-development.de)
++ * modular driver for Colognechip HFC-USB chip
++ * as plugin for HiSax isdn driver
++ *
++ * Copyright 2001 by Werner Cornelius (werner@isdn4linux.de)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include <linux/types.h>
++#include <linux/skbuff.h>
++
++/***************************************/
++/* additional defines for l1 constants */
++/***************************************/
++#define B1_DATA 0x1f0
++#define B1_SETMODE 0x1f4
++#define B2_DATA 0x1f8
++#define B2_SETMODE 0x1fc
++
++
++/********************************************************/
++/* structure used for register and release of L1 driver */
++/********************************************************/
++struct hisax_drvreg {
++ int version; /* actual version for check */
++ int cmd; /* command code */
++
++ /* function pointers set by hisax during register call */
++ void (*release_driver) (void *arg_hisax); /* set by hisax, release function for driver */
++ void (*dch_l1l2) (void *arg_hisax, int pr, void *arg); /* set by hisax, notify dch+l1 events */
++ void (*bch_l1l2) (void *arg_hisax, int chan, int pr, void *arg); /* set by hisax, notify bch events */
++ void *arg_hisax; /* argument when calling hisax main */
++ struct sk_buff_head *drq; /* pointer to D-receive queue */
++ struct sk_buff_head *dsq; /* pointer to D-send queue */
++ struct sk_buff_head erq; /* E-receive queue */
++ struct sk_buff_head *brq[2]; /* pointer to B-receive queues */
++ struct sk_buff **bsk[2]; /* pointer to B-transmit buffer */
++
++ /* function pointers set by l1 driver before calling the register function */
++ void (*dch_l2l1) (void *argl1, int pr, void *arg); /* function dch+l1 from hisax -> l1 */
++ void (*bch_l2l1) (void *argl1, int chan, int pr, void *arg); /* function bch from hisax -> l1 */
++ void *argl1; /* pointer to l1 data structure when calling l1 */
++
++ char *drvname; /* driver name for hisax usage */
++};
++
++/**************************/
++/* constants and commands */
++/**************************/
++#define HISAX_LOAD_VERSION 4 /* change when interface changes */
++#define HISAX_LOAD_CHKVER 0 /* check version command (returns 0 on success) */
++#define HISAX_LOAD_REGISTER 1 /* register the L1 driver and return 0 on success */
++
++/***************************************/
++/* definition of the register function */
++/***************************************/
++extern int hisax_register_hfcusb(struct hisax_drvreg *l1drv);
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hscx.c linux-2.4.29/drivers/isdn/hisax/hscx.c
+--- linux-2.4.29.old/drivers/isdn/hisax/hscx.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hscx.c 2005-03-22 15:06:46.621005312 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hscx.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: hscx.c,v 1.24 2001/09/24 13:22:56 kai Exp $
+ *
+ * HSCX specific routines
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hscx.h linux-2.4.29/drivers/isdn/hisax/hscx.h
+--- linux-2.4.29.old/drivers/isdn/hisax/hscx.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hscx.h 2005-03-22 15:06:46.640002424 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hscx.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: hscx.h,v 1.8 2001/09/24 13:22:56 kai Exp $
+ *
+ * HSCX specific defines
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hscx_irq.c linux-2.4.29/drivers/isdn/hisax/hscx_irq.c
+--- linux-2.4.29.old/drivers/isdn/hisax/hscx_irq.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hscx_irq.c 2005-03-22 15:06:46.655999992 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hscx_irq.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: hscx_irq.c,v 1.18 2001/09/24 13:22:56 kai Exp $
+ *
+ * low level b-channel stuff for Siemens HSCX
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/icc.c linux-2.4.29/drivers/isdn/hisax/icc.c
+--- linux-2.4.29.old/drivers/isdn/hisax/icc.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/icc.c 2005-03-22 15:06:46.672997408 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: icc.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: icc.c,v 1.8 2001/09/24 13:22:56 kai Exp $
+ *
+ * ICC specific routines
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/icc.h linux-2.4.29/drivers/isdn/hisax/icc.h
+--- linux-2.4.29.old/drivers/isdn/hisax/icc.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/icc.h 2005-03-22 15:06:46.687995128 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: icc.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: icc.h,v 1.4 2001/09/24 13:22:56 kai Exp $
+ *
+ * ICC specific routines
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/ipac.h linux-2.4.29/drivers/isdn/hisax/ipac.h
+--- linux-2.4.29.old/drivers/isdn/hisax/ipac.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/ipac.h 2005-03-22 15:06:46.702992848 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: ipac.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: ipac.h,v 1.7 2001/09/24 13:22:56 kai Exp $
+ *
+ * IPAC specific defines
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/isac.c linux-2.4.29/drivers/isdn/hisax/isac.c
+--- linux-2.4.29.old/drivers/isdn/hisax/isac.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/isac.c 2005-03-22 15:06:46.844971264 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isac.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: isac.c,v 1.31 2001/09/24 13:22:56 kai Exp $
+ *
+ * ISAC specific routines
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/isac.h linux-2.4.29/drivers/isdn/hisax/isac.h
+--- linux-2.4.29.old/drivers/isdn/hisax/isac.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/isac.h 2005-03-22 15:06:47.111930680 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isac.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: isac.h,v 1.9 2001/09/24 13:22:56 kai Exp $
+ *
+ * ISAC specific defines
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/isar.c linux-2.4.29/drivers/isdn/hisax/isar.c
+--- linux-2.4.29.old/drivers/isdn/hisax/isar.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/isar.c 2005-03-22 15:06:47.302901648 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isar.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: isar.c,v 1.22 2001/09/23 12:00:05 keil Exp $
+ *
+ * isar.c ISAR (Siemens PSB 7110) specific routines
+ *
+@@ -21,12 +21,10 @@
+ #define DLE 0x10
+ #define ETX 0x03
+
+-#define FAXMODCNT 13
+-const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146};
+-static u_int modmask = 0x1fff;
+-static int frm_extra_delay = 2;
+-static int para_TOA = 6;
+-const u_char *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL" };
++
++const u_char faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146";
++const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146};
++#define FAXMODCNT 13
+
+ void isar_setup(struct IsdnCardState *cs);
+ static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para);
+@@ -127,7 +125,7 @@
+ ireg->clsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_L);
+ #if DUMP_MBOXFRAME
+ if (cs->debug & L1_DEB_HSCX)
+- debugl1(cs, "irq_stat(%02x,%02x,%d)", ireg->iis, ireg->cmsb,
++ debugl1(cs, "rcv_mbox(%02x,%02x,%d)", ireg->iis, ireg->cmsb,
+ ireg->clsb);
+ #endif
+ }
+@@ -414,7 +412,6 @@
+ }
+ cs->debug = debug;
+ isar_setup(cs);
+-
+ ret = 0;
+ reterrflg:
+ restore_flags(flags);
+@@ -428,21 +425,6 @@
+ return(ret);
+ }
+
+-static inline void
+-ll_deliver_faxstat(struct BCState *bcs, u_char status)
+-{
+- isdn_ctrl ic;
+- struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata;
+-
+- if (bcs->cs->debug & L1_DEB_HSCX)
+- debugl1(bcs->cs, "HL->LL FAXIND %x", status);
+- ic.driver = bcs->cs->myid;
+- ic.command = ISDN_STAT_FAXIND;
+- ic.arg = chanp->chan;
+- ic.parm.aux.cmd = status;
+- bcs->cs->iif.statcallb(&ic);
+-}
+-
+ extern void BChannel_bh(struct BCState *);
+ #define B_LL_NOCARRIER 8
+ #define B_LL_CONNECT 9
+@@ -599,6 +581,7 @@
+ if (ireg->cmsb & SART_NMD) { /* ABORT */
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_rcv_frame: no more data");
++ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ bcs->hw.isar.rcvidx = 0;
+ send_DLE_ETX(bcs);
+ sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
+@@ -609,6 +592,7 @@
+ }
+ } else {
+ printk(KERN_WARNING "HiSax: skb out of memory\n");
++ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ }
+ break;
+ }
+@@ -633,9 +617,8 @@
+ bcs->hw.isar.rcvidx = 0;
+ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ } else {
+- if (ireg->cmsb & HDLC_FSD) {
++ if (ireg->cmsb & HDLC_FSD)
+ bcs->hw.isar.rcvidx = 0;
+- }
+ ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx;
+ bcs->hw.isar.rcvidx += ireg->clsb;
+ rcv_mbox(cs, ireg, ptr);
+@@ -646,8 +629,6 @@
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar frame to short %d",
+ bcs->hw.isar.rcvidx);
+- printk(KERN_WARNING "ISAR: frame to short %d\n",
+- bcs->hw.isar.rcvidx);
+ } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
+ printk(KERN_WARNING "ISAR: receive out of memory\n");
+ } else {
+@@ -658,7 +639,6 @@
+ isar_sched_event(bcs, B_RCVBUFREADY);
+ send_DLE_ETX(bcs);
+ isar_sched_event(bcs, B_LL_OK);
+- test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
+ }
+ bcs->hw.isar.rcvidx = 0;
+ }
+@@ -666,14 +646,13 @@
+ if (ireg->cmsb & SART_NMD) { /* ABORT */
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar_rcv_frame: no more data");
++ cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+ bcs->hw.isar.rcvidx = 0;
++ send_DLE_ETX(bcs);
+ sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
+ ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
+ bcs->hw.isar.state = STFAX_ESCAPE;
+- if (test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag)) {
+- send_DLE_ETX(bcs);
+- isar_sched_event(bcs, B_LL_NOCARRIER);
+- }
++ isar_sched_event(bcs, B_LL_NOCARRIER);
+ }
+ break;
+ default:
+@@ -977,6 +956,21 @@
+ }
+ }
+
++static inline void
++ll_deliver_faxstat(struct BCState *bcs, u_char status)
++{
++ isdn_ctrl ic;
++ struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata;
++
++ if (bcs->cs->debug & L1_DEB_HSCX)
++ debugl1(bcs->cs, "HL->LL FAXIND %x", status);
++ ic.driver = bcs->cs->myid;
++ ic.command = ISDN_STAT_FAXIND;
++ ic.arg = chanp->chan;
++ ic.parm.aux.cmd = status;
++ bcs->cs->iif.statcallb(&ic);
++}
++
+ static void
+ isar_pump_statev_fax(struct BCState *bcs, u_char devt) {
+ struct IsdnCardState *cs = bcs->cs;
+@@ -1081,22 +1075,19 @@
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "pump stev RSP_DISC");
+ if (bcs->hw.isar.state == STFAX_ESCAPE) {
+- p1 = 5;
+ switch(bcs->hw.isar.newcmd) {
+ case 0:
+ bcs->hw.isar.state = STFAX_READY;
+ break;
+- case PCTRL_CMD_FTM:
+- p1 = 2;
+ case PCTRL_CMD_FTH:
++ case PCTRL_CMD_FTM:
++ p1 = 10;
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
+ PCTRL_CMD_SILON, 1, &p1);
+ bcs->hw.isar.state = STFAX_SILDET;
+ break;
+- case PCTRL_CMD_FRM:
+- if (frm_extra_delay)
+- mdelay(frm_extra_delay);
+ case PCTRL_CMD_FRH:
++ case PCTRL_CMD_FRM:
+ p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod;
+ bcs->hw.isar.newmod = 0;
+ bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
+@@ -1215,9 +1206,6 @@
+ isar_pump_statev_modem(bcs, ireg->cmsb);
+ } else if (bcs->mode == L1_MODE_FAX) {
+ isar_pump_statev_fax(bcs, ireg->cmsb);
+- } else if (ireg->cmsb == PSEV_10MS_TIMER) {
+- if (cs->debug & L1_DEB_HSCX)
+- debugl1(cs, "pump stev TIMER");
+ } else {
+ if (cs->debug & L1_DEB_WARN)
+ debugl1(cs, "isar IIS_PSTEV pmode %d stat %x",
+@@ -1278,9 +1266,6 @@
+ if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) {
+ isar_sched_event(bcs, B_LL_CONNECT);
+ }
+- if (test_and_clear_bit(BC_FLG_FTI_FTS, &bcs->Flag)) {
+- isar_sched_event(bcs, B_LL_OK);
+- }
+ }
+
+ static void
+@@ -1303,7 +1288,7 @@
+ } else {
+ param[5] = PV32P6_ATN;
+ }
+- param[0] = para_TOA; /* 6 db */
++ param[0] = 6; /* 6 db */
+ param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B |
+ PV32P2_V22C | PV32P2_V21 | PV32P2_BEL;
+ param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B;
+@@ -1319,7 +1304,7 @@
+ } else {
+ param[1] = PFAXP2_ATN;
+ }
+- param[0] = para_TOA; /* 6 db */
++ param[0] = 6; /* 6 db */
+ sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param);
+ bcs->hw.isar.state = STFAX_NULL;
+ bcs->hw.isar.newcmd = 0;
+@@ -1348,6 +1333,7 @@
+ "\0\0");
+ break;
+ case L1_MODE_HDLC:
++ case L1_MODE_FAX:
+ param[0] = 0;
+ sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1,
+ param);
+@@ -1359,9 +1345,6 @@
+ sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2,
+ param);
+ break;
+- case L1_MODE_FAX:
+- /* SART must not configured with FAX */
+- break;
+ }
+ udelay(1000);
+ sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL);
+@@ -1465,7 +1448,6 @@
+
+ switch(cmd) {
+ case ISDN_FAX_CLASS1_FTM:
+- test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
+ if (bcs->hw.isar.state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FTM;
+@@ -1489,7 +1471,6 @@
+ }
+ break;
+ case ISDN_FAX_CLASS1_FTH:
+- test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
+ if (bcs->hw.isar.state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FTH;
+@@ -1513,7 +1494,6 @@
+ }
+ break;
+ case ISDN_FAX_CLASS1_FRM:
+- test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
+ if (bcs->hw.isar.state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FRM;
+@@ -1537,7 +1517,6 @@
+ }
+ break;
+ case ISDN_FAX_CLASS1_FRH:
+- test_and_set_bit(BC_FLG_FRH_WAIT, &bcs->Flag);
+ if (bcs->hw.isar.state == STFAX_READY) {
+ p1 = para;
+ ctrl = PCTRL_CMD_FRH;
+@@ -1560,11 +1539,6 @@
+ bcs->hw.isar.state = STFAX_ESCAPE;
+ }
+ break;
+- case ISDN_FAXPUMP_HALT:
+- bcs->hw.isar.state = STFAX_NULL;
+- nom = 0;
+- ctrl = PCTRL_CMD_HALT;
+- break;
+ }
+ if (ctrl)
+ sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
+@@ -1658,15 +1632,6 @@
+ l1_msg_b(st, pr, arg);
+ break;
+ case (PH_DEACTIVATE | CONFIRM):
+- switch(st->l1.mode) {
+- case L1_MODE_TRANS:
+- case L1_MODE_HDLC:
+- case L1_MODE_V32:
+- break;
+- case L1_MODE_FAX:
+- isar_pump_cmd(st->l1.bcs, ISDN_FAXPUMP_HALT, 0);
+- break;
+- }
+ test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+ if (st->l1.bcs->cs->debug & L1_DEB_HSCX)
+@@ -1758,51 +1723,6 @@
+ test_and_set_bit(BC_FLG_DLEETX,
+ &bcs->Flag);
+ break;
+- case ISDN_FAX_CLASS1_FTS:
+- if (ic->parm.aux.subcmd == AT_QUERY) {
+- ic->command = ISDN_STAT_FAXIND;
+- ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK;
+- cs->iif.statcallb(ic);
+- return(0);
+- } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
+- strcpy(ic->parm.aux.para, "0-255");
+- ic->command = ISDN_STAT_FAXIND;
+- ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
+- cs->iif.statcallb(ic);
+- return(0);
+- } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
+- if (cs->debug & L1_DEB_HSCX)
+- debugl1(cs, "isar_auxcmd %s=%d",
+- FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]);
+- if (bcs->hw.isar.state == STFAX_READY) {
+- if (! ic->parm.aux.para[0]) {
+- ic->command = ISDN_STAT_FAXIND;
+- ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK;
+- cs->iif.statcallb(ic);
+- return(0);
+- }
+- if (! test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag)) {
+- /* n*10 ms */
+- bcs->hw.isar.ftimer.expires =
+- jiffies + ((ic->parm.aux.para[0] * 10 * HZ)/1000);
+- test_and_set_bit(BC_FLG_FTI_FTS, &bcs->Flag);
+- add_timer(&bcs->hw.isar.ftimer);
+- return(0);
+- } else {
+- if (cs->debug)
+- debugl1(cs, "isar FTS=%d and FTI busy",
+- ic->parm.aux.para[0]);
+- }
+- } else {
+- if (cs->debug)
+- debugl1(cs, "isar FTS=%d and isar.state not ready(%x)",
+- ic->parm.aux.para[0],bcs->hw.isar.state);
+- }
+- ic->command = ISDN_STAT_FAXIND;
+- ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR;
+- cs->iif.statcallb(ic);
+- }
+- break;
+ case ISDN_FAX_CLASS1_FRM:
+ case ISDN_FAX_CLASS1_FRH:
+ case ISDN_FAX_CLASS1_FTM:
+@@ -1815,24 +1735,16 @@
+ cs->iif.statcallb(ic);
+ return(0);
+ } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) {
+- char *p = ic->parm.aux.para;
+- for(i=0;i<FAXMODCNT;i++)
+- if ((1<<i) & modmask)
+- p += sprintf(p, "%d,", faxmodulation[i]);
+- p--;
+- *p=0;
++ strcpy(ic->parm.aux.para, faxmodulation_s);
+ ic->command = ISDN_STAT_FAXIND;
+ ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY;
+ cs->iif.statcallb(ic);
+ return(0);
+ } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) {
+- if (cs->debug & L1_DEB_HSCX)
+- debugl1(cs, "isar_auxcmd %s=%d",
+- FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]);
+ for(i=0;i<FAXMODCNT;i++)
+ if (faxmodulation[i]==ic->parm.aux.para[0])
+ break;
+- if ((i < FAXMODCNT) && ((1<<i) & modmask) &&
++ if ((FAXMODCNT > i) &&
+ test_bit(BC_FLG_INIT, &bcs->Flag)) {
+ isar_pump_cmd(bcs,
+ ic->parm.aux.cmd,
+@@ -1850,7 +1762,7 @@
+ break;
+ case (ISDN_CMD_IOCTL):
+ switch (ic->arg) {
+- case 9: /* load firmware */
++ case (9): /* load firmware */
+ features = ISDN_FEATURE_L2_MODEM |
+ ISDN_FEATURE_L2_FAX |
+ ISDN_FEATURE_L3_FCLASS1;
+@@ -1860,26 +1772,6 @@
+ else
+ ll_run(cs, features);
+ break;
+- case 20:
+- features = *(unsigned int *) ic->parm.num;
+- printk(KERN_DEBUG "HiSax: max modulation old(%04x) new(%04x)\n",
+- modmask, features);
+- modmask = features;
+- break;
+- case 21:
+- features = *(unsigned int *) ic->parm.num;
+- printk(KERN_DEBUG "HiSax: FRM extra delay old(%d) new(%d) ms\n",
+- frm_extra_delay, features);
+- if (features >= 0)
+- frm_extra_delay = features;
+- break;
+- case 22:
+- features = *(unsigned int *) ic->parm.num;
+- printk(KERN_DEBUG "HiSax: TOA old(%d) new(%d) db\n",
+- para_TOA, features);
+- if (features >= 0 && features < 32)
+- para_TOA = features;
+- break;
+ default:
+ printk(KERN_DEBUG "HiSax: invalid ioctl %d\n",
+ (int) ic->arg);
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/isar.h linux-2.4.29/drivers/isdn/hisax/isar.h
+--- linux-2.4.29.old/drivers/isdn/hisax/isar.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/isar.h 2005-03-22 15:06:47.457878088 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isar.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: isar.h,v 1.11 2001/09/24 13:22:56 kai Exp $
+ *
+ * ISAR (Siemens PSB 7110) specific defines
+ *
+@@ -28,8 +28,6 @@
+ #define ISAR_HIS_FIRM 0x1e
+ #define ISAR_HIS_STDSP 0x08
+ #define ISAR_HIS_DIAG 0x05
+-#define ISAR_HIS_WAITSTATE 0x27
+-#define ISAR_HIS_TIMERIRQ 0x25
+ #define ISAR_HIS_P0CFG 0x3c
+ #define ISAR_HIS_P12CFG 0x24
+ #define ISAR_HIS_SARTCFG 0x25
+@@ -45,10 +43,6 @@
+ #define ISAR_HIS_DPS2 0x80
+ #define SET_DPS(x) ((x<<6) & 0xc0)
+
+-#define ISAR_CMD_TIMERIRQ_OFF 0x20
+-#define ISAR_CMD_TIMERIRQ_ON 0x21
+-
+-
+ #define ISAR_IIS_MSCMSD 0x3f
+ #define ISAR_IIS_VNR 0x15
+ #define ISAR_IIS_DKEY 0x03
+@@ -213,8 +207,6 @@
+ #define STFAX_ESCAPE 5
+ #define STFAX_SILDET 6
+
+-#define ISDN_FAXPUMP_HALT 100
+-
+ extern int ISARVersion(struct IsdnCardState *cs, char *s);
+ extern void isar_int_main(struct IsdnCardState *cs);
+ extern void initisar(struct IsdnCardState *cs);
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/isdnl1.c linux-2.4.29/drivers/isdn/hisax/isdnl1.c
+--- linux-2.4.29.old/drivers/isdn/hisax/isdnl1.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/isdnl1.c 2005-03-22 15:06:47.582859088 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdnl1.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: isdnl1.c,v 2.46 2001/09/24 13:22:56 kai Exp $
+ *
+ * common low level stuff for Siemens Chipsetbased isdn cards
+ *
+@@ -18,7 +18,7 @@
+ *
+ */
+
+-const char *l1_revision = "$Revision: 1.1.4.1 $";
++const char *l1_revision = "$Revision: 2.46 $";
+
+ #define __NO_VERSION__
+ #include <linux/init.h>
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/isdnl1.h linux-2.4.29/drivers/isdn/hisax/isdnl1.h
+--- linux-2.4.29.old/drivers/isdn/hisax/isdnl1.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/isdnl1.h 2005-03-22 15:06:47.615854072 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdnl1.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: isdnl1.h,v 2.12 2001/09/24 13:22:56 kai Exp $
+ *
+ * Layer 1 defines
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/isdnl2.c linux-2.4.29/drivers/isdn/hisax/isdnl2.c
+--- linux-2.4.29.old/drivers/isdn/hisax/isdnl2.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/isdnl2.c 2005-03-22 15:06:47.631851640 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdnl2.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: isdnl2.c,v 2.30 2001/09/24 13:22:56 kai Exp $
+ *
+ * Author Karsten Keil
+ * based on the teles driver from Jan den Ouden
+@@ -20,7 +20,7 @@
+ #include "hisax.h"
+ #include "isdnl2.h"
+
+-const char *l2_revision = "$Revision: 1.1.4.1 $";
++const char *l2_revision = "$Revision: 2.30 $";
+
+ static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
+
+@@ -1418,8 +1418,8 @@
+ freewin(st);
+ st->l2.tei = -1;
+ stop_t200(st, 17);
+- st5_dl_release_l2l3(st);
+ FsmChangeState(fi, ST_L2_1);
++ st5_dl_release_l2l3(st);
+ }
+
+ static void
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/isdnl2.h linux-2.4.29/drivers/isdn/hisax/isdnl2.h
+--- linux-2.4.29.old/drivers/isdn/hisax/isdnl2.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/isdnl2.h 2005-03-22 15:06:47.647849208 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdnl2.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id$
+ *
+ * Layer 2 defines
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/isdnl3.c linux-2.4.29/drivers/isdn/hisax/isdnl3.c
+--- linux-2.4.29.old/drivers/isdn/hisax/isdnl3.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/isdnl3.c 2005-03-22 15:06:47.663846776 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdnl3.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: isdnl3.c,v 2.22 2001/09/24 13:22:56 kai Exp $
+ *
+ * Author Karsten Keil
+ * based on the teles driver from Jan den Ouden
+@@ -21,7 +21,7 @@
+ #include "isdnl3.h"
+ #include <linux/config.h>
+
+-const char *l3_revision = "$Revision: 1.1.4.1 $";
++const char *l3_revision = "$Revision: 2.22 $";
+
+ static struct Fsm l3fsm;
+
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/isdnl3.h linux-2.4.29/drivers/isdn/hisax/isdnl3.h
+--- linux-2.4.29.old/drivers/isdn/hisax/isdnl3.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/isdnl3.h 2005-03-22 15:06:47.679844344 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdnl3.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id$
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/isurf.c linux-2.4.29/drivers/isdn/hisax/isurf.c
+--- linux-2.4.29.old/drivers/isdn/hisax/isurf.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/isurf.c 2005-03-22 15:06:47.699841304 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isurf.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: isurf.c,v 1.12 2001/09/24 13:22:56 kai Exp $
+ *
+ * low level stuff for Siemens I-Surf/I-Talk cards
+ *
+@@ -16,11 +16,10 @@
+ #include "isac.h"
+ #include "isar.h"
+ #include "isdnl1.h"
+-#include <linux/isapnp.h>
+
+ extern const char *CardType[];
+
+-static const char *ISurf_revision = "$Revision: 1.1.4.1 $";
++static const char *ISurf_revision = "$Revision: 1.12 $";
+
+ #define byteout(addr,val) outb(val,addr)
+ #define bytein(addr) inb(addr)
+@@ -128,8 +127,10 @@
+ release_io_isurf(struct IsdnCardState *cs)
+ {
+ release_region(cs->hw.isurf.reset, 1);
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ iounmap((unsigned char *)cs->hw.isurf.isar);
+ release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
++#endif
+ }
+
+ static void
+@@ -194,10 +195,6 @@
+ return(isar_auxcmd(cs, ic));
+ }
+
+-#ifdef __ISAPNP__
+-static struct pci_bus *pnp_surf __devinitdata = NULL;
+-#endif
+-
+ int __init
+ setup_isurf(struct IsdnCard *card)
+ {
+@@ -215,58 +212,9 @@
+ cs->hw.isurf.phymem = card->para[2];
+ cs->irq = card->para[0];
+ } else {
+-#ifdef __ISAPNP__
+- struct pci_bus *pb;
+- struct pci_dev *pd;
+-
+- if (isapnp_present()) {
+- cs->subtyp = 0;
+- if ((pb = isapnp_find_card(
+- ISAPNP_VENDOR('S', 'I', 'E'),
+- ISAPNP_FUNCTION(0x0010), pnp_surf))) {
+- pnp_surf = pb;
+- pd = NULL;
+- if (!(pd = isapnp_find_dev(pnp_surf,
+- ISAPNP_VENDOR('S', 'I', 'E'),
+- ISAPNP_FUNCTION(0x0010), pd))) {
+- printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n");
+- return (0);
+- }
+- pd->prepare(pd);
+- pd->deactivate(pd);
+- pd->activate(pd);
+- /* The ISA-PnP logic apparently
+- * expects upper limit address to be
+- * set. Since the isa-pnp module
+- * doesn't do this, so we have to make
+- * up for it.
+- */
+- isapnp_cfg_begin(pd->bus->number, pd->devfn);
+- isapnp_write_word(ISAPNP_CFG_MEM+3,
+- pd->resource[8].end >> 8);
+- isapnp_cfg_end();
+- cs->hw.isurf.reset = pd->resource[0].start;
+- cs->hw.isurf.phymem = pd->resource[8].start;
+- cs->irq = pd->irq_resource[0].start;
+- if (!cs->irq || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) {
+- printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n",
+- cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem);
+- pd->deactivate(pd);
+- return(0);
+- }
+- } else {
+- printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n");
+- return(0);
+- }
+- } else {
+- printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n");
+- return(0);
+- }
+-#else
+ printk(KERN_WARNING "HiSax: %s port/mem not set\n",
+ CardType[card->typ]);
+ return (0);
+-#endif
+ }
+ if (check_region(cs->hw.isurf.reset, 1)) {
+ printk(KERN_WARNING
+@@ -277,6 +225,7 @@
+ } else {
+ request_region(cs->hw.isurf.reset, 1, "isurf isdn");
+ }
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ if (check_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE)) {
+ printk(KERN_WARNING
+ "HiSax: %s memory region %lx-%lx already in use\n",
+@@ -292,6 +241,10 @@
+ cs->hw.isurf.isar =
+ (unsigned long) ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
+ cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET;
++#else
++ cs->hw.isurf.isar = cs->hw.isurf.phymem + ISURF_ISAR_OFFSET;
++ cs->hw.isurf.isac = cs->hw.isurf.phymem + ISURF_ISAC_OFFSET;
++#endif
+ printk(KERN_INFO
+ "ISurf: defined at 0x%x 0x%lx IRQ %d\n",
+ cs->hw.isurf.reset,
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/ix1_micro.c linux-2.4.29/drivers/isdn/hisax/ix1_micro.c
+--- linux-2.4.29.old/drivers/isdn/hisax/ix1_micro.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/ix1_micro.c 2005-03-22 15:06:47.714839024 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: ix1_micro.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: ix1_micro.c,v 2.12 2001/09/24 13:22:56 kai Exp $
+ *
+ * low level stuff for ITK ix1-micro Rev.2 isdn cards
+ * derived from the original file teles3.c from Karsten Keil
+@@ -19,14 +19,13 @@
+
+ #define __NO_VERSION__
+ #include <linux/init.h>
+-#include <linux/isapnp.h>
+ #include "hisax.h"
+ #include "isac.h"
+ #include "hscx.h"
+ #include "isdnl1.h"
+
+ extern const char *CardType[];
+-const char *ix1_revision = "$Revision: 1.1.4.1 $";
++const char *ix1_revision = "$Revision: 2.12 $";
+
+ #define byteout(addr,val) outb(val,addr)
+ #define bytein(addr) inb(addr)
+@@ -219,21 +218,6 @@
+ return(0);
+ }
+
+-#ifdef __ISAPNP__
+-static struct isapnp_device_id itk_ids[] __initdata = {
+- { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
+- ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
+- (unsigned long) "ITK micro 2" },
+- { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
+- ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
+- (unsigned long) "ITK micro 2." },
+- { 0, }
+-};
+-
+-static struct isapnp_device_id *idev = &itk_ids[0];
+-static struct pci_bus *pnp_c __devinitdata = NULL;
+-#endif
+-
+
+ int __init
+ setup_ix1micro(struct IsdnCard *card)
+@@ -246,45 +230,6 @@
+ if (cs->typ != ISDN_CTYPE_IX1MICROR2)
+ return (0);
+
+-#ifdef __ISAPNP__
+- if (!card->para[1] && isapnp_present()) {
+- struct pci_bus *pb;
+- struct pci_dev *pd;
+-
+- while(idev->card_vendor) {
+- if ((pb = isapnp_find_card(idev->card_vendor,
+- idev->card_device, pnp_c))) {
+- pnp_c = pb;
+- pd = NULL;
+- if ((pd = isapnp_find_dev(pnp_c,
+- idev->vendor, idev->function, pd))) {
+- printk(KERN_INFO "HiSax: %s detected\n",
+- (char *)idev->driver_data);
+- pd->prepare(pd);
+- pd->deactivate(pd);
+- pd->activate(pd);
+- card->para[1] = pd->resource[0].start;
+- card->para[0] = pd->irq_resource[0].start;
+- if (!card->para[0] || !card->para[1]) {
+- printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n",
+- card->para[0], card->para[1]);
+- pd->deactivate(pd);
+- return(0);
+- }
+- break;
+- } else {
+- printk(KERN_ERR "ITK PnP: PnP error card found, no device\n");
+- }
+- }
+- idev++;
+- pnp_c=NULL;
+- }
+- if (!idev->card_vendor) {
+- printk(KERN_INFO "ITK PnP: no ISAPnP card found\n");
+- return(0);
+- }
+- }
+-#endif
+ /* IO-Ports */
+ cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET;
+ cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET;
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/jade.c linux-2.4.29/drivers/isdn/hisax/jade.c
+--- linux-2.4.29.old/drivers/isdn/hisax/jade.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/jade.c 2005-03-22 15:06:47.729836744 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: jade.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: jade.c,v 1.9 2001/09/24 13:22:56 kai Exp $
+ *
+ * JADE stuff (derived from original hscx.c)
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/jade.h linux-2.4.29/drivers/isdn/hisax/jade.h
+--- linux-2.4.29.old/drivers/isdn/hisax/jade.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/jade.h 2005-03-22 15:06:47.745834312 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: jade.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: jade.h,v 1.5 2001/09/24 13:22:56 kai Exp $
+ *
+ * JADE specific defines
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/jade_irq.c linux-2.4.29/drivers/isdn/hisax/jade_irq.c
+--- linux-2.4.29.old/drivers/isdn/hisax/jade_irq.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/jade_irq.c 2005-03-22 15:06:47.760832032 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: jade_irq.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: jade_irq.c,v 1.7 2001/09/24 13:22:56 kai Exp $
+ *
+ * Low level JADE IRQ stuff (derived from original hscx_irq.c)
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/l3_1tr6.c linux-2.4.29/drivers/isdn/hisax/l3_1tr6.c
+--- linux-2.4.29.old/drivers/isdn/hisax/l3_1tr6.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/l3_1tr6.c 2005-03-22 15:06:47.777829448 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: l3_1tr6.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: l3_1tr6.c,v 2.15 2001/09/24 13:22:56 kai Exp $
+ *
+ * German 1TR6 D-channel protocol
+ *
+@@ -20,7 +20,7 @@
+ #include <linux/ctype.h>
+
+ extern char *HiSax_getrev(const char *revision);
+-const char *l3_1tr6_revision = "$Revision: 1.1.4.1 $";
++const char *l3_1tr6_revision = "$Revision: 2.15 $";
+
+ #define MsgHead(ptr, cref, mty, dis) \
+ *ptr++ = dis; \
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/l3_1tr6.h linux-2.4.29/drivers/isdn/hisax/l3_1tr6.h
+--- linux-2.4.29.old/drivers/isdn/hisax/l3_1tr6.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/l3_1tr6.h 2005-03-22 15:06:47.796826560 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: l3_1tr6.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id$
+ *
+ * German 1TR6 D-channel protocol defines
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/l3dss1.c linux-2.4.29/drivers/isdn/hisax/l3dss1.c
+--- linux-2.4.29.old/drivers/isdn/hisax/l3dss1.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/l3dss1.c 2005-03-22 15:06:47.822822608 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: l3dss1.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: l3dss1.c,v 2.32 2001/09/24 13:22:56 kai Exp $
+ *
+ * EURO/DSS1 D-channel protocol
+ *
+@@ -27,7 +27,7 @@
+ #include <linux/config.h>
+
+ extern char *HiSax_getrev(const char *revision);
+-const char *dss1_revision = "$Revision: 1.1.4.1 $";
++const char *dss1_revision = "$Revision: 2.32 $";
+
+ #define EXT_BEARER_CAPS 1
+
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/l3dss1.h linux-2.4.29/drivers/isdn/hisax/l3dss1.h
+--- linux-2.4.29.old/drivers/isdn/hisax/l3dss1.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/l3dss1.h 2005-03-22 15:06:47.842819568 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: l3dss1.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id$
+ *
+ * DSS1 (Euro) D-channel protocol defines
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/l3ni1.c linux-2.4.29/drivers/isdn/hisax/l3ni1.c
+--- linux-2.4.29.old/drivers/isdn/hisax/l3ni1.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/l3ni1.c 2005-03-22 15:06:47.859816984 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: l3ni1.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: l3ni1.c,v 2.8 2001/09/24 13:22:56 kai Exp $
+ *
+ * NI1 D-channel protocol
+ *
+@@ -25,7 +25,7 @@
+ #include <linux/ctype.h>
+
+ extern char *HiSax_getrev(const char *revision);
+-const char *ni1_revision = "$Revision: 1.1.4.1 $";
++const char *ni1_revision = "$Revision: 2.8 $";
+
+ #define EXT_BEARER_CAPS 1
+
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/l3ni1.h linux-2.4.29/drivers/isdn/hisax/l3ni1.h
+--- linux-2.4.29.old/drivers/isdn/hisax/l3ni1.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/l3ni1.h 2005-03-22 15:06:47.877814248 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: l3ni1.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id$
+ *
+ * NI1 D-channel protocol
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/lmgr.c linux-2.4.29/drivers/isdn/hisax/lmgr.c
+--- linux-2.4.29.old/drivers/isdn/hisax/lmgr.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/lmgr.c 2005-03-22 15:06:47.895811512 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: lmgr.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id$
+ *
+ * Layermanagement module
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/md5sums.asc linux-2.4.29/drivers/isdn/hisax/md5sums.asc
+--- linux-2.4.29.old/drivers/isdn/hisax/md5sums.asc 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/md5sums.asc 2005-03-22 15:06:47.910809232 +0100
+@@ -1,33 +1,22 @@
+------BEGIN PGP SIGNED MESSAGE-----
+-Hash: SHA1
+-
+ # This are valid md5sums for certificated HiSax driver.
+ # The certification is valid only if the md5sums of all files match.
+ # The certification is valid only for ELSA Microlink PCI,
+-# Eicon Technology Diva 2.01 PCI, Sedlbauer SpeedFax+,
+-# HFC-S PCI A based cards and HFC-S USB based ISDN
+-# terminal adapters in the moment.
++# Eicon Technology Diva 2.01 PCI, Sedlbauer SpeedFax+,
++# HFC-S PCI A based cards and HFC-S USB based isdn tas
++# in the moment.
+ # Read ../../../Documentation/isdn/HiSax.cert for more informations.
+ #
+-cd4a9917e1147039d5dfc66440d42054 isac.c
+-211840e78b56c9d4753be9c85da21a50 isdnl1.c
+-5ce9b1fff42a02f9c2eb4fb81c701b1f isdnl2.c
+-6948de0c43513dd23c6706feb5fc2209 isdnl3.c
+-3730780b69368218d756024165efea79 tei.c
+-16e72710eb58da01415b877490f5d2ac callc.c
+-6abc55c77e0f3149ae9334f3257a1a1a cert.c
+-27bdb2800d4590e00da20eff241edc47 l3dss1.c
+-df8bb877b854c4302d396b554e4e84ef l3_1tr6.c
+-9d8b4bed15370063d1b16e47080f50e1 elsa.c
+-210f4a3f1eebca70229d786b15cf3e90 diva.c
+-4ddf21079dd77e892380f789bae250a7 sedlbauer.c
+-8200d818771e3cbdef2a3c3e818d25ac hfc_pci.c
++6f9433a8b696076562562d090e3c420f isac.c
++13c3eed869f5139f44c563e3a8fea1f5 isdnl1.c
++addcff863b0ff1e366c0f2ae9fa6e81e isdnl2.c
++7076deb94a363945c21ea27aca4a720a isdnl3.c
++51c603829b6cc4f8421f744ad657ceff tei.c
++669050ab5079f02887ed0239d86e5474 callc.c
++ecacd146b8f8881ef9349935dab3df4a cert.c
++fadeb3b85bb23bc1ac48470c0848d6fa l3dss1.c
++cf7dec9fac6283716904d26b99188476 l3_1tr6.c
++2f75c8765e1be13d114d5f4433cf364b elsa.c
++b4cf8a4dceed9ea6dcba65a85b4eecc7 diva.c
++dee3f8f40c6fe78a4b57729804b7e6cd sedlbauer.c
++0d79fe6dfc5bfaa4826970c41a6d273d hfc_pci.c
+ # end of md5sums
+------BEGIN PGP SIGNATURE-----
+-Version: GnuPG v1.0.6 (GNU/Linux)
+-Comment: For info see http://www.gnupg.org
+-
+-iD8DBQE9rE91DiY0VZsg4ukRAkKfAJ4xWUfqjc0hW+V+JPue5yr7mrt+RwCdGdSf
+-GIKgAEdRLzERmpt/bCCwAbY=
+-=FaHw
+------END PGP SIGNATURE-----
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/mic.c linux-2.4.29/drivers/isdn/hisax/mic.c
+--- linux-2.4.29.old/drivers/isdn/hisax/mic.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/mic.c 2005-03-22 15:06:47.926806800 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: mic.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: mic.c,v 1.12 2001/09/24 13:22:56 kai Exp $
+ *
+ * low level stuff for mic cards
+ *
+@@ -19,7 +19,7 @@
+
+ extern const char *CardType[];
+
+-const char *mic_revision = "$Revision: 1.1.4.1 $";
++const char *mic_revision = "$Revision: 1.12 $";
+
+ #define byteout(addr,val) outb(val,addr)
+ #define bytein(addr) inb(addr)
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/netjet.c linux-2.4.29/drivers/isdn/hisax/netjet.c
+--- linux-2.4.29.old/drivers/isdn/hisax/netjet.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/netjet.c 2005-03-22 15:06:47.941804520 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: netjet.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: netjet.c,v 1.29 2001/09/24 13:22:56 kai Exp $
+ *
+ * low level stuff for Traverse Technologie NETJet ISDN cards
+ *
+@@ -8,9 +8,7 @@
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+- * Thanks to Traverse Technologies Australia for documents and information
+- *
+- * 16-Apr-2002 - led code added - Guy Ellis (guy@traverse.com.au)
++ * Thanks to Traverse Technologie Australia for documents and information
+ *
+ */
+
+@@ -26,7 +24,7 @@
+ #include <asm/io.h>
+ #include "netjet.h"
+
+-const char *NETjet_revision = "$Revision: 1.1.4.1 $";
++const char *NETjet_revision = "$Revision: 1.29 $";
+
+ /* Interface functions */
+
+@@ -135,7 +133,6 @@
+ mode_tiger(struct BCState *bcs, int mode, int bc)
+ {
+ struct IsdnCardState *cs = bcs->cs;
+- u_char led;
+
+ if (cs->debug & L1_DEB_HSCX)
+ debugl1(cs, "Tiger mode %d bchan %d/%d",
+@@ -157,15 +154,6 @@
+ cs->hw.njet.dmactrl);
+ byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
+ }
+- if (cs->typ == ISDN_CTYPE_NETJET_S)
+- {
+- // led off
+- led = bc & 0x01;
+- led = 0x01 << (6 + led); // convert to mask
+- led = ~led;
+- cs->hw.njet.auxd &= led;
+- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+- }
+ break;
+ case (L1_MODE_TRANS):
+ break;
+@@ -191,14 +179,6 @@
+ bcs->hw.tiger.sendp = bcs->hw.tiger.send;
+ bcs->hw.tiger.free = NETJET_DMA_TXSIZE;
+ test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
+- if (cs->typ == ISDN_CTYPE_NETJET_S)
+- {
+- // led on
+- led = bc & 0x01;
+- led = 0x01 << (6 + led); // convert to mask
+- cs->hw.njet.auxd |= led;
+- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+- }
+ break;
+ }
+ if (cs->debug & L1_DEB_HSCX)
+@@ -874,13 +854,9 @@
+ case (PH_ACTIVATE | REQUEST):
+ test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+ mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc);
+- /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
+- st->l1.bcs->cs->cardmsg(st->l1.bcs->cs, MDL_BC_ASSIGN, (void *)(&st->l1.bc));
+ l1_msg_b(st, pr, arg);
+ break;
+ case (PH_DEACTIVATE | REQUEST):
+- /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
+- st->l1.bcs->cs->cardmsg(st->l1.bcs->cs, MDL_BC_RELEASE, (void *)(&st->l1.bc));
+ l1_msg_b(st, pr, arg);
+ break;
+ case (PH_DEACTIVATE | CONFIRM):
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/netjet.h linux-2.4.29/drivers/isdn/hisax/netjet.h
+--- linux-2.4.29.old/drivers/isdn/hisax/netjet.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/netjet.h 2005-03-22 15:06:47.956802240 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: netjet.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: netjet.h,v 2.8 2001/09/24 13:22:56 kai Exp $
+ *
+ * NETjet common header file
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/niccy.c linux-2.4.29/drivers/isdn/hisax/niccy.c
+--- linux-2.4.29.old/drivers/isdn/hisax/niccy.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/niccy.c 2005-03-22 15:06:47.977799048 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: niccy.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: niccy.c,v 1.21 2001/10/20 22:05:00 kai Exp $
+ *
+ * low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
+ * compatible (SAGEM cybermodem)
+@@ -22,10 +22,10 @@
+ #include "hscx.h"
+ #include "isdnl1.h"
+ #include <linux/pci.h>
+-#include <linux/isapnp.h>
++#include <linux/isdn_compat.h>
+
+ extern const char *CardType[];
+-const char *niccy_revision = "$Revision: 1.1.4.1 $";
++const char *niccy_revision = "$Revision: 1.21 $";
+
+ #define byteout(addr,val) outb(val,addr)
+ #define bytein(addr) inb(addr)
+@@ -239,9 +239,6 @@
+ }
+
+ static struct pci_dev *niccy_dev __initdata = NULL;
+-#ifdef __ISAPNP__
+-static struct pci_bus *pnp_c __devinitdata = NULL;
+-#endif
+
+ int __init
+ setup_niccy(struct IsdnCard *card)
+@@ -253,39 +250,7 @@
+ printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_NICCY)
+ return (0);
+-#ifdef __ISAPNP__
+- if (!card->para[1] && isapnp_present()) {
+- struct pci_bus *pb;
+- struct pci_dev *pd;
+-
+- if ((pb = isapnp_find_card(
+- ISAPNP_VENDOR('S', 'D', 'A'),
+- ISAPNP_FUNCTION(0x0150), pnp_c))) {
+- pnp_c = pb;
+- pd = NULL;
+- if (!(pd = isapnp_find_dev(pnp_c,
+- ISAPNP_VENDOR('S', 'D', 'A'),
+- ISAPNP_FUNCTION(0x0150), pd))) {
+- printk(KERN_ERR "NiccyPnP: PnP error card found, no device\n");
+- return (0);
+- }
+- pd->prepare(pd);
+- pd->deactivate(pd);
+- pd->activate(pd);
+- card->para[1] = pd->resource[0].start;
+- card->para[2] = pd->resource[1].start;
+- card->para[0] = pd->irq_resource[0].start;
+- if (!card->para[0] || !card->para[1] || !card->para[2]) {
+- printk(KERN_ERR "NiccyPnP:some resources are missing %ld/%lx/%lx\n",
+- card->para[0], card->para[1], card->para[2]);
+- pd->deactivate(pd);
+- return(0);
+- }
+- } else {
+- printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n");
+- }
+- }
+-#endif
++
+ if (card->para[1]) {
+ cs->hw.niccy.isac = card->para[1] + ISAC_PNP;
+ cs->hw.niccy.hscx = card->para[1] + HSCX_PNP;
+@@ -331,12 +296,12 @@
+ return(0);
+ }
+ cs->irq = niccy_dev->irq;
+- cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0);
++ cs->hw.niccy.cfg_reg = pci_resource_start_io(niccy_dev, 0);
+ if (!cs->hw.niccy.cfg_reg) {
+ printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
+ return(0);
+ }
+- pci_ioaddr = pci_resource_start(niccy_dev, 1);
++ pci_ioaddr = pci_resource_start_io(niccy_dev, 1);
+ if (!pci_ioaddr) {
+ printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
+ return(0);
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/nj_s.c linux-2.4.29/drivers/isdn/hisax/nj_s.c
+--- linux-2.4.29.old/drivers/isdn/hisax/nj_s.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/nj_s.c 2005-03-22 15:06:47.993796616 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: nj_s.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: nj_s.c,v 2.13 2001/09/24 13:22:56 kai Exp $
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+@@ -12,11 +12,12 @@
+ #include "isac.h"
+ #include "isdnl1.h"
+ #include <linux/pci.h>
++#include <linux/isdn_compat.h>
+ #include <linux/interrupt.h>
+ #include <linux/ppp_defs.h>
+ #include "netjet.h"
+
+-const char *NETjet_S_revision = "$Revision: 1.1.4.1 $";
++const char *NETjet_S_revision = "$Revision: 2.13 $";
+
+ static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
+ {
+@@ -130,7 +131,6 @@
+ release_io_netjet(cs);
+ return(0);
+ case CARD_INIT:
+- reset_netjet_s(cs);
+ inittiger(cs);
+ clear_pending_isac_ints(cs);
+ initisac(cs);
+@@ -180,19 +180,11 @@
+ printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n");
+ return(0);
+ }
+- cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
++ cs->hw.njet.base = pci_resource_start_io(dev_netjet, 0);
+ if (!cs->hw.njet.base) {
+ printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+- /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */
+- if ((dev_netjet->subsystem_vendor == 0x55) &&
+- (dev_netjet->subsystem_device == 0x02)) {
+- printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n");
+- printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n");
+- return(0);
+- }
+- /* end new code */
+ } else {
+ printk(KERN_WARNING "NETjet-S: No PCI card found\n");
+ return(0);
+@@ -263,6 +255,7 @@
+ } else {
+ request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn");
+ }
++ reset_netjet_s(cs);
+ cs->readisac = &NETjet_ReadIC;
+ cs->writeisac = &NETjet_WriteIC;
+ cs->readisacfifo = &NETjet_ReadICfifo;
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/nj_u.c linux-2.4.29/drivers/isdn/hisax/nj_u.c
+--- linux-2.4.29.old/drivers/isdn/hisax/nj_u.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/nj_u.c 2005-03-22 15:06:48.008794336 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: nj_u.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: nj_u.c,v 2.14 2001/09/24 13:22:56 kai Exp $
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+@@ -12,11 +12,12 @@
+ #include "icc.h"
+ #include "isdnl1.h"
+ #include <linux/pci.h>
++#include <linux/isdn_compat.h>
+ #include <linux/interrupt.h>
+ #include <linux/ppp_defs.h>
+ #include "netjet.h"
+
+-const char *NETjet_U_revision = "$Revision: 1.1.4.1 $";
++const char *NETjet_U_revision = "$Revision: 2.14 $";
+
+ static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
+ {
+@@ -181,7 +182,7 @@
+ printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n");
+ return(0);
+ }
+- cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
++ cs->hw.njet.base = pci_resource_start_io(dev_netjet, 0);
+ if (!cs->hw.njet.base) {
+ printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n");
+ return(0);
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/q931.c linux-2.4.29/drivers/isdn/hisax/q931.c
+--- linux-2.4.29.old/drivers/isdn/hisax/q931.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/q931.c 2005-03-22 15:06:48.032790688 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: q931.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: q931.c,v 1.12 2001/09/24 13:22:56 kai Exp $
+ *
+ * code to decode ITU Q.931 call control messages
+ *
+@@ -197,6 +197,31 @@
+
+ #define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType))
+
++#if 0
++static struct MessageType fac_1tr6[] =
++{
++ {FAC_Sperre, "Sperre"},
++ {FAC_Forward1, "Forward 1"},
++ {FAC_Forward2, "Forward 2"},
++ {FAC_Konferenz, "Konferenz"},
++ {FAC_GrabBchan, "Grab Bchannel"},
++ {FAC_Reactivate, "Reactivate"},
++ {FAC_Konferenz3, "Dreier Konferenz"},
++ {FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"},
++ {FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"},
++ {FAC_NummernIdent, "Rufnummer-Identifizierung"},
++ {FAC_GBG, "GBG"},
++ {FAC_DisplayUebergeben, "Display Uebergeben"},
++ {FAC_DisplayUmgeleitet, "Display Umgeleitet"},
++ {FAC_Unterdruecke, "Unterdruecke Rufnummer"},
++ {FAC_Deactivate, "Deactivate"},
++ {FAC_Activate, "Activate"},
++ {FAC_SPV, "SPV"},
++ {FAC_Rueckwechsel, "Rueckwechsel"},
++ {FAC_Umleitung, "Umleitung"}
++};
++#define FAC_1TR6_LEN (sizeof(fac_1tr6) / sizeof(struct MessageType))
++#endif
+
+ static int
+ prbits(char *dest, u_char b, int start, int len)
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/rawhdlc.c linux-2.4.29/drivers/isdn/hisax/rawhdlc.c
+--- linux-2.4.29.old/drivers/isdn/hisax/rawhdlc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/rawhdlc.c 2005-03-22 15:06:48.047788408 +0100
+@@ -0,0 +1,543 @@
++/* $Id: rawhdlc.c,v 1.7 2001/09/24 13:22:57 kai Exp $
++ *
++ * support routines for cards that don't support HDLC
++ *
++ * Author Brent Baccala
++ * Copyright by Karsten Keil <keil@isdn4linux.de>
++ * by Brent Baccala <baccala@FreeSoft.org>
++ *
++ * This software may be used and distributed according to the terms
++ * of the GNU General Public License, incorporated herein by reference.
++ *
++ *
++ * Some passive ISDN cards, such as the Traverse NETJet and the AMD 7930,
++ * don't perform HDLC encapsulation over the B channel. Drivers for
++ * such cards use support routines in this file to perform B channel HDLC.
++ *
++ * Bit-synchronous HDLC encapsulation is a means of encapsulating packets
++ * over a continuously transmitting serial communications link.
++ * It looks like this:
++ *
++ * 11111111101111110...........0111111011111111111
++ * iiiiiiiiiffffffffdddddddddddffffffffiiiiiiiiiii
++ *
++ * i = idle f = flag d = data
++ *
++ * When idle, the channel sends a continuous string of ones (mark
++ * idle; illustrated), or a continuous string of flag characters (flag
++ * idle). The beginning of a data frame is marked by a flag character
++ * (01111110), then comes the actual data, followed by another flag
++ * character, after which another frame may be sent immediately (a
++ * single flag may serve as both the end of one frame and the start of
++ * the next), or the link may return to idle. Obviously, the flag
++ * character can not appear anywhere in the data (or a false
++ * end-of-frame would occur), so the transmitter performs
++ * "bit-stuffing" - inserting a zero bit after every five one bits,
++ * irregardless of the original bit after the five ones. Byte
++ * ordering is irrelevent at this point - the data is treated as a
++ * string of bits, not bytes. Since no more than 5 ones may now occur
++ * in a row, the flag sequence, with its 6 ones, is unique.
++ *
++ * Upon reception, a zero bit that occur after 5 one bits is simply
++ * discarded. A series of 6 one bits is end-of-frame, and a series of
++ * 7 one bits is an abort. Once bit-stuffing has been corrected for,
++ * an integer number of bytes should now be present. The last two
++ * of these bytes form the Frame Check Sequence, a CRC that is verified
++ * and then discarded. Note that bit-stuffing is performed on the FCS
++ * just as if it were regular data.
++ *
++ *
++ *
++ * int make_raw_hdlc_data(u_char *src, u_int slen,
++ * u_char *dst, u_int dsize)
++ *
++ * Used for transmission. Copies slen bytes from src to dst, performing
++ * HDLC encapsulation (flag bytes, bit-stuffing, CRC) in the process.
++ * dsize is size of destination buffer, and should be at least
++ * ((6*slen)/5)+5 bytes to ensure adequate space will be available.
++ * Function returns length (in bytes) of valid destination buffer, or
++ * 0 upon destination overflow.
++ *
++ * void init_hdlc_state(struct hdlc_state *stateptr, int mode)
++ *
++ * Initializes hdlc_state structure before first call to read_raw_hdlc_data
++ *
++ * mode = 0: Sane mode
++ * mode = 1/2:
++ * Insane mode; NETJet use a shared unsigned int memory block (
++ * with busmaster DMA), the bit pattern of every word is
++ * <8 B1> <8 B2> <8 Mon> <2 D> <4 C/I> <MX> <MR>
++ * according to Siemens IOM-2 interface, so we have to handle
++ * the src buffer as unsigned int and have to shift/mask the
++ * B-channel bytes.
++ * mode 1 -> B1 mode 2 -> B2 data is used
++ *
++ * int read_raw_hdlc_data(struct hdlc_state *saved_state,
++ * u_char *src, u_int slen,
++ * u_char *dst, u_int dsize)
++ *
++ * Used for reception. Scans source buffer bit-by-bit looking for
++ * valid HDLC frames, which are copied to destination buffer. HDLC
++ * state information is stored in a structure, which allows this
++ * function to process frames spread across several blocks of raw
++ * HDLC data. Part of the state information is bit offsets into
++ * the source and destination buffers.
++ *
++ * A return value >0 indicates the length of a valid frame, now
++ * stored in the destination buffer. In this case, the source
++ * buffer might not be completely processed, so this function should
++ * be called again with the same source buffer, possibly with a
++ * different destination buffer.
++ *
++ * A return value of zero indicates that the source buffer was
++ * completely processed without finding a valid end-of-packet;
++ * however, we might be in the middle of packet reception, so
++ * the function should be called again with the next block of
++ * raw HDLC data and the same destination buffer. It is NOT
++ * permitted to change the destination buffer in this case,
++ * since data may already have begun to be stored there.
++ *
++ * A return value of -1 indicates some kind of error - destination
++ * buffer overflow, CRC check failed, frame not a multiple of 8
++ * bits. Destination buffer probably contains invalid data, which
++ * should be discarded. Call function again with same source buffer
++ * and a new (or same) destination buffer.
++ *
++ * Suggested calling sequence:
++ *
++ * init_hdlc_state(...);
++ * for (EACH_RAW_DATA_BLOCK) {
++ * while (len = read_raw_hdlc_data(...)) {
++ * if (len == -1) DISCARD_FRAME;
++ * else PROCESS_FRAME;
++ * }
++ * }
++ *
++ *
++ * Test the code in this file as follows:
++ * gcc -DDEBUGME -o rawhdlctest rawhdlc.c
++ * ./rawhdlctest < rawdata
++ *
++ * The file "rawdata" can be easily generated from a HISAX B-channel
++ * hex dump (CF CF CF 02 ...) using the following perl script:
++ *
++ * while(<>) {
++ * @hexlist = split ' ';
++ * while ($hexstr = shift(@hexlist)) {
++ * printf "%c", hex($hexstr);
++ * }
++ * }
++ *
++ */
++
++#ifdef DEBUGME
++#include <stdio.h>
++#endif
++
++#include <linux/types.h>
++#include <linux/ppp_defs.h>
++#include "rawhdlc.h"
++
++/* There's actually an identical copy of this table in the PPP code
++ * (ppp_crc16_table), but I don't want this code dependent on PPP
++ */
++
++// static
++__u16 fcstab[256] =
++{
++ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
++ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
++ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
++ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
++ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
++ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
++ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
++ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
++ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
++ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
++ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
++ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
++ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
++ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
++ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
++ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
++ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
++ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
++ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
++ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
++ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
++ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
++ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
++ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
++ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
++ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
++ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
++ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
++ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
++ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
++ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
++ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
++};
++
++#define HDLC_ZERO_SEARCH 0
++#define HDLC_FLAG_SEARCH 1
++#define HDLC_FLAG_FOUND 2
++#define HDLC_FRAME_FOUND 3
++#define HDLC_NULL 4
++#define HDLC_PART 5
++#define HDLC_FULL 6
++
++#define HDLC_FLAG_VALUE 0x7e
++
++
++#define MAKE_RAW_BYTE for (j=0; j<8; j++) { \
++ bitcnt++;\
++ out_val >>= 1;\
++ if (val & 1) {\
++ s_one++;\
++ out_val |= 0x80;\
++ } else {\
++ s_one = 0;\
++ out_val &= 0x7f;\
++ }\
++ if (bitcnt==8) {\
++ if (d_cnt == dsize) return 0;\
++ dst[d_cnt++] = out_val;\
++ bitcnt = 0;\
++ }\
++ if (s_one == 5) {\
++ out_val >>= 1;\
++ out_val &= 0x7f;\
++ bitcnt++;\
++ s_one = 0;\
++ }\
++ if (bitcnt==8) {\
++ if (d_cnt == dsize) return 0;\
++ dst[d_cnt++] = out_val;\
++ bitcnt = 0;\
++ }\
++ val >>= 1;\
++ }
++
++/* Optimization suggestion: If needed, this function could be
++ * dramatically sped up using a state machine. Each state would
++ * correspond to having seen N one bits, and being offset M bits into
++ * the current output byte. N ranges from 0 to 4, M from 0 to 7, so
++ * we need 5*8 = 35 states. Each state would have a table with 256
++ * entries, one for each input character. Each entry would contain
++ * three output characters, an output state, an a byte increment
++ * that's either 1 or 2. All this could fit in four bytes; so we need
++ * 4 bytes * 256 characters = 1 KB for each state (35 KB total). Zero
++ * the output buffer before you start. For each character in your
++ * input, you look it up in the current state's table and get three
++ * bytes to be or'ed into the output at the current byte offset, and
++ * an byte increment to move your pointer forward. A simple Perl
++ * script could generate the tables. Given HDLC semantics, probably
++ * would be better to set output to all 1s, then use ands instead of ors.
++ * A smaller state machine could operate on nibbles instead of bytes.
++ * A state machine for 32-bit architectures could use word offsets
++ * instead of byte offsets, requiring 5*32 = 160 states; probably
++ * best to work on nibbles in such a case.
++ */
++
++
++int make_raw_hdlc_data(u_char *src, u_int slen, u_char *dst, u_int dsize)
++{
++ register u_int i,d_cnt=0;
++ register u_char j;
++ register u_char val;
++ register u_char s_one = 0;
++ register u_char out_val = 0;
++ register u_char bitcnt = 0;
++ u_int fcs;
++
++
++ dst[d_cnt++] = HDLC_FLAG_VALUE;
++ fcs = PPP_INITFCS;
++ for (i=0; i<slen; i++) {
++ val = src[i];
++ fcs = PPP_FCS (fcs, val);
++ MAKE_RAW_BYTE;
++ }
++ fcs ^= 0xffff;
++ val = fcs & 0xff;
++ MAKE_RAW_BYTE;
++ val = (fcs>>8) & 0xff;
++ MAKE_RAW_BYTE;
++ val = HDLC_FLAG_VALUE;
++ for (j=0; j<8; j++) {
++ bitcnt++;
++ out_val >>= 1;
++ if (val & 1)
++ out_val |= 0x80;
++ else
++ out_val &= 0x7f;
++ if (bitcnt==8) {
++ if (d_cnt == dsize) return 0;
++ dst[d_cnt++] = out_val;
++ bitcnt = 0;
++ }
++ val >>= 1;
++ }
++ if (bitcnt) {
++ while (8>bitcnt++) {
++ out_val >>= 1;
++ out_val |= 0x80;
++ }
++ if (d_cnt == dsize) return 0;
++ dst[d_cnt++] = out_val;
++ }
++
++ return d_cnt;
++}
++
++void init_hdlc_state(struct hdlc_state *stateptr, int mode)
++{
++ stateptr->state = HDLC_ZERO_SEARCH;
++ stateptr->r_one = 0;
++ stateptr->r_val = 0;
++ stateptr->o_bitcnt = 0;
++ stateptr->i_bitcnt = 0;
++ stateptr->insane_mode = mode;
++}
++
++/* Optimization suggestion: A similar state machine could surely
++ * be developed for this function as well.
++ */
++
++int read_raw_hdlc_data(struct hdlc_state *saved_state,
++ u_char *src, u_int slen, u_char *dst, u_int dsize)
++{
++ int retval=0;
++ register u_char val;
++ register u_char state = saved_state->state;
++ register u_char r_one = saved_state->r_one;
++ register u_char r_val = saved_state->r_val;
++ register u_int o_bitcnt = saved_state->o_bitcnt;
++ register u_int i_bitcnt = saved_state->i_bitcnt;
++ register u_int fcs = saved_state->fcs;
++ register u_int *isrc = (u_int *) src;
++
++ /* Use i_bitcnt (bit offset into source buffer) to reload "val"
++ * in case we're starting up again partway through a source buffer
++ */
++
++ if ((i_bitcnt >> 3) < slen) {
++ if (saved_state->insane_mode==1) {
++ val = isrc[(i_bitcnt >> 3)] & 0xff;
++ } else if (saved_state->insane_mode==2) {
++ val = (isrc[i_bitcnt >> 3] >>8) & 0xff;
++ } else {
++ val = src[i_bitcnt >> 3];
++ }
++ val >>= i_bitcnt & 7;
++ }
++
++ /* One bit per loop. Keep going until we've got something to
++ * report (retval != 0), or we exhaust the source buffer
++ */
++
++ while ((retval == 0) && ((i_bitcnt >> 3) < slen)) {
++ if ((i_bitcnt & 7) == 0) {
++ if (saved_state->insane_mode==1) {
++ val = isrc[(i_bitcnt >> 3)] & 0xff;
++ } else if (saved_state->insane_mode==2) {
++ val = (isrc[i_bitcnt >> 3] >>8) & 0xff;
++ } else {
++ val = src[i_bitcnt >> 3];
++ }
++#ifdef DEBUGME
++ printf("Input byte %d: 0x%2x\n", i_bitcnt>>3, val);
++#endif
++ if (val == 0xff) {
++ state = HDLC_ZERO_SEARCH;
++ o_bitcnt = 0;
++ r_one = 0;
++ i_bitcnt += 8;
++ continue;
++ }
++ }
++
++#ifdef DEBUGME
++ /* printf("Data bit=%d (%d/%d)\n", val&1, i_bitcnt>>3, i_bitcnt&7);*/
++#endif
++
++ if (state == HDLC_ZERO_SEARCH) {
++ if (val & 1) {
++ r_one++;
++ } else {
++ r_one=0;
++ state= HDLC_FLAG_SEARCH;
++ }
++ } else if (state == HDLC_FLAG_SEARCH) {
++ if (val & 1) {
++ r_one++;
++ if (r_one>6) {
++ state=HDLC_ZERO_SEARCH;
++ }
++ } else {
++ if (r_one==6) {
++ o_bitcnt=0;
++ r_val=0;
++ state=HDLC_FLAG_FOUND;
++ }
++ r_one=0;
++ }
++ } else if (state == HDLC_FLAG_FOUND) {
++ if (val & 1) {
++ r_one++;
++ if (r_one>6) {
++ state=HDLC_ZERO_SEARCH;
++ } else {
++ r_val >>= 1;
++ r_val |= 0x80;
++ o_bitcnt++;
++ }
++ } else {
++ if (r_one==6) {
++ o_bitcnt=0;
++ r_val=0;
++ r_one=0;
++ i_bitcnt++;
++ val >>= 1;
++ continue;
++ } else if (r_one!=5) {
++ r_val >>= 1;
++ r_val &= 0x7f;
++ o_bitcnt++;
++ }
++ r_one=0;
++ }
++ if ((state != HDLC_ZERO_SEARCH) &&
++ !(o_bitcnt & 7)) {
++#ifdef DEBUGME
++ printf("HDLC_FRAME_FOUND at i_bitcnt:%d\n",i_bitcnt);
++#endif
++ state=HDLC_FRAME_FOUND;
++ fcs = PPP_INITFCS;
++ dst[0] = r_val;
++ fcs = PPP_FCS (fcs, r_val);
++ }
++ } else if (state == HDLC_FRAME_FOUND) {
++ if (val & 1) {
++ r_one++;
++ if (r_one>6) {
++ state=HDLC_ZERO_SEARCH;
++ o_bitcnt=0;
++ } else {
++ r_val >>= 1;
++ r_val |= 0x80;
++ o_bitcnt++;
++ }
++ } else {
++ if (r_one==6) {
++ r_val=0;
++ r_one=0;
++ o_bitcnt++;
++ if (o_bitcnt & 7) {
++ /* Alignment error */
++#ifdef DEBUGME
++ printf("Alignment error\n");
++#endif
++ state=HDLC_FLAG_SEARCH;
++ retval = -1;
++ } else if (fcs==PPP_GOODFCS) {
++ /* Valid frame */
++ state=HDLC_FLAG_FOUND;
++ retval = (o_bitcnt>>3)-3;
++ } else {
++ /* CRC error */
++#ifdef DEBUGME
++ printf("CRC error; fcs was 0x%x, should have been 0x%x\n", fcs, PPP_GOODFCS);
++#endif
++ state=HDLC_FLAG_FOUND;
++ retval = -1;
++ }
++ } else if (r_one==5) {
++ r_one=0;
++ i_bitcnt++;
++ val >>= 1;
++ continue;
++ } else {
++ r_val >>= 1;
++ r_val &= 0x7f;
++ o_bitcnt++;
++ }
++ r_one=0;
++ }
++ if ((state == HDLC_FRAME_FOUND) &&
++ !(o_bitcnt & 7)) {
++ if ((o_bitcnt>>3)>=dsize) {
++ /* Buffer overflow error */
++#ifdef DEBUGME
++ printf("Buffer overflow error\n");
++#endif
++ r_val=0;
++ state=HDLC_FLAG_SEARCH;
++ retval = -1;
++ } else {
++ dst[(o_bitcnt>>3)-1] = r_val;
++ fcs = PPP_FCS (fcs, r_val);
++#ifdef DEBUGME
++ printf("Output byte %d: 0x%02x; FCS 0x%04x\n", (o_bitcnt>>3)-1, r_val, fcs);
++#endif
++ }
++ }
++ }
++ i_bitcnt ++;
++ val >>= 1;
++ }
++
++ /* We exhausted the source buffer before anything else happened
++ * (retval==0). Reset i_bitcnt in expectation of a new source
++ * buffer. Other, we either had an error or a valid frame, so
++ * reset o_bitcnt in expectation of a new destination buffer.
++ */
++
++ if (retval == 0) {
++ i_bitcnt = 0;
++ } else {
++ o_bitcnt = 0;
++ }
++
++ saved_state->state = state;
++ saved_state->r_one = r_one;
++ saved_state->r_val = r_val;
++ saved_state->fcs = fcs;
++ saved_state->o_bitcnt = o_bitcnt;
++ saved_state->i_bitcnt = i_bitcnt;
++
++ return (retval);
++}
++
++
++
++#ifdef DEBUGME
++
++char buffer[1024];
++char obuffer[1024];
++
++main()
++{
++ int buflen=0;
++ int len;
++ struct hdlc_state hdlc_state;
++
++ while((buffer[buflen] = getc(stdin)) != EOF && buflen<1024) buflen++;
++
++ printf("buflen = %d\n", buflen);
++
++ init_hdlc_state(&hdlc_state, 0);
++
++ while (len = read_raw_hdlc_data(&hdlc_state,buffer,buflen,obuffer,1024)) {
++ if (len == -1) printf("Error @ byte %d/bit %d\n",
++ hdlc_state.i_bitcnt>>3, hdlc_state.i_bitcnt & 7);
++ else {
++ printf("Frame received: len %d\n", len);
++ }
++ }
++
++ printf("Done\n");
++}
++
++#endif
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/rawhdlc.h linux-2.4.29/drivers/isdn/hisax/rawhdlc.h
+--- linux-2.4.29.old/drivers/isdn/hisax/rawhdlc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/rawhdlc.h 2005-03-22 15:06:48.076784000 +0100
+@@ -0,0 +1,28 @@
++/* $Id: rawhdlc.h,v 1.5 2001/09/24 13:22:57 kai Exp $
++ *
++ * Author Brent Baccala
++ * Copyright by Brent Baccala <baccala@FreeSoft.org>
++ *
++ * This software may be used and distributed according to the terms
++ * of the GNU General Public License, incorporated herein by reference.
++ *
++ */
++
++#ifndef RAWHDLC_H
++struct hdlc_state {
++ char insane_mode;
++ u_char state;
++ u_char r_one;
++ u_char r_val;
++ u_int o_bitcnt;
++ u_int i_bitcnt;
++ u_int fcs;
++};
++
++
++int make_raw_hdlc_data(u_char *src, u_int slen, u_char *dst, u_int dsize);
++void init_hdlc_state(struct hdlc_state *stateptr, int mode);
++int read_raw_hdlc_data(struct hdlc_state *saved_state,
++ u_char *src, u_int slen, u_char *dst, u_int dsize);
++#define RAWHDLC_H
++#endif
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/s0box.c linux-2.4.29/drivers/isdn/hisax/s0box.c
+--- linux-2.4.29.old/drivers/isdn/hisax/s0box.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/s0box.c 2005-03-22 15:06:48.092781568 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: s0box.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: s0box.c,v 2.6 2001/09/24 13:22:57 kai Exp $
+ *
+ * low level stuff for Creatix S0BOX
+ *
+@@ -18,7 +18,7 @@
+ #include "isdnl1.h"
+
+ extern const char *CardType[];
+-const char *s0box_revision = "$Revision: 1.1.4.1 $";
++const char *s0box_revision = "$Revision: 2.6 $";
+
+ static inline void
+ writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/saphir.c linux-2.4.29/drivers/isdn/hisax/saphir.c
+--- linux-2.4.29.old/drivers/isdn/hisax/saphir.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/saphir.c 2005-03-22 15:06:48.107779288 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: saphir.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: saphir.c,v 1.10 2001/09/24 13:22:57 kai Exp $
+ *
+ * low level stuff for HST Saphir 1
+ *
+@@ -20,7 +20,7 @@
+ #include "isdnl1.h"
+
+ extern const char *CardType[];
+-static char *saphir_rev = "$Revision: 1.1.4.1 $";
++static char *saphir_rev = "$Revision: 1.10 $";
+
+ #define byteout(addr,val) outb(val,addr)
+ #define bytein(addr) inb(addr)
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/sedlbauer.c linux-2.4.29/drivers/isdn/hisax/sedlbauer.c
+--- linux-2.4.29.old/drivers/isdn/hisax/sedlbauer.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/sedlbauer.c 2005-03-22 15:06:48.123776856 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: sedlbauer.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: sedlbauer.c,v 1.34 2002/02/09 21:00:57 keil Exp $
+ *
+ * low level stuff for Sedlbauer cards
+ * includes support for the Sedlbauer speed star (speed star II),
+@@ -48,18 +48,19 @@
+ #include "isar.h"
+ #include "isdnl1.h"
+ #include <linux/pci.h>
+-#include <linux/isapnp.h>
++#include <linux/isdn_compat.h>
+
+ extern const char *CardType[];
+
+-const char *Sedlbauer_revision = "$Revision: 1.1.4.1 $";
++const char *Sedlbauer_revision = "$Revision: 1.34 $";
+
+ const char *Sedlbauer_Types[] =
+ {"None", "speed card/win", "speed star", "speed fax+",
+ "speed win II / ISDN PC/104", "speed star II", "speed pci",
+- "speed fax+ pyramid", "speed fax+ pci"};
++ "speed fax+ pyramid", "speed fax+ pci", "HST Saphir III"};
+
+ #define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51
++#define PCI_SUBVENDOR_HST_SAPHIR3 0x52
+ #define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53
+ #define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54
+ #define PCI_SUB_ID_SEDLBAUER 0x01
+@@ -72,6 +73,7 @@
+ #define SEDL_SPEED_PCI 6
+ #define SEDL_SPEEDFAX_PYRAMID 7
+ #define SEDL_SPEEDFAX_PCI 8
++#define HST_SAPHIR3 9
+
+ #define SEDL_CHIP_TEST 0
+ #define SEDL_CHIP_ISAC_HSCX 1
+@@ -531,21 +533,6 @@
+
+ static struct pci_dev *dev_sedl __devinitdata = NULL;
+
+-#ifdef __ISAPNP__
+-static struct isapnp_device_id sedl_ids[] __initdata = {
+- { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
+- ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
+- (unsigned long) "Speed win" },
+- { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02),
+- ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02),
+- (unsigned long) "Speed Fax+" },
+- { 0, }
+-};
+-
+-static struct isapnp_device_id *pdev = &sedl_ids[0];
+-static struct pci_bus *pnp_c __devinitdata = NULL;
+-#endif
+-
+ int __devinit
+ setup_sedlbauer(struct IsdnCard *card)
+ {
+@@ -581,57 +568,6 @@
+ bytecnt = 16;
+ }
+ } else {
+-#ifdef __ISAPNP__
+- if (isapnp_present()) {
+- struct pci_bus *pb;
+- struct pci_dev *pd;
+-
+- while(pdev->card_vendor) {
+- if ((pb = isapnp_find_card(pdev->card_vendor,
+- pdev->card_device, pnp_c))) {
+- pnp_c = pb;
+- pd = NULL;
+- if ((pd = isapnp_find_dev(pnp_c,
+- pdev->vendor, pdev->function, pd))) {
+- printk(KERN_INFO "HiSax: %s detected\n",
+- (char *)pdev->driver_data);
+- pd->prepare(pd);
+- pd->deactivate(pd);
+- pd->activate(pd);
+- card->para[1] =
+- pd->resource[0].start;
+- card->para[0] =
+- pd->irq_resource[0].start;
+- if (!card->para[0] || !card->para[1]) {
+- printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
+- card->para[0], card->para[1]);
+- pd->deactivate(pd);
+- return(0);
+- }
+- cs->hw.sedl.cfg_reg = card->para[1];
+- cs->irq = card->para[0];
+- if (pdev->function == ISAPNP_FUNCTION(0x2)) {
+- cs->subtyp = SEDL_SPEED_FAX;
+- cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+- bytecnt = 16;
+- } else {
+- cs->subtyp = SEDL_SPEED_CARD_WIN;
+- cs->hw.sedl.chip = SEDL_CHIP_TEST;
+- }
+- goto ready;
+- } else {
+- printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
+- return(0);
+- }
+- }
+- pdev++;
+- pnp_c=NULL;
+- }
+- if (!pdev->card_vendor) {
+- printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
+- }
+- }
+-#endif
+ /* Probe for Sedlbauer speed pci */
+ #if CONFIG_PCI
+ if (!pci_present()) {
+@@ -647,15 +583,15 @@
+ printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
+ return(0);
+ }
+- cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
++ cs->hw.sedl.cfg_reg = pci_resource_start_io(dev_sedl, 0);
+ } else {
+ printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
+ return(0);
+ }
+ cs->irq_flags |= SA_SHIRQ;
+ cs->hw.sedl.bus = SEDL_BUS_PCI;
+- sub_vendor_id = dev_sedl->subsystem_vendor;
+- sub_id = dev_sedl->subsystem_device;
++ pci_get_sub_vendor(dev_sedl,sub_vendor_id);
++ pci_get_sub_system(dev_sedl,sub_id);
+ printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
+ sub_vendor_id, sub_id);
+ printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
+@@ -670,6 +606,9 @@
+ } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
+ cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+ cs->subtyp = SEDL_SPEEDFAX_PCI;
++ } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
++ cs->hw.sedl.chip = SEDL_CHIP_IPAC;
++ cs->subtyp = HST_SAPHIR3;
+ } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
+ cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+ cs->subtyp = SEDL_SPEED_PCI;
+@@ -683,8 +622,8 @@
+ cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
+ byteout(cs->hw.sedl.cfg_reg, 0xff);
+ byteout(cs->hw.sedl.cfg_reg, 0x00);
+- byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
+- byteout(cs->hw.sedl.cfg_reg+ 5, 0x02);
++ byteout(cs->hw.sedl.cfg_reg +2, 0xdd);
++ byteout(cs->hw.sedl.cfg_reg +5, 0x02);
+ byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
+ save_flags(flags);
+ sti();
+@@ -697,7 +636,7 @@
+ return (0);
+ #endif /* CONFIG_PCI */
+ }
+-ready:
++
+ /* In case of the sedlbauer pcmcia card, this region is in use,
+ * reserved for us by the card manager. So we do not check it
+ * here, it would fail.
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/sportster.c linux-2.4.29/drivers/isdn/hisax/sportster.c
+--- linux-2.4.29.old/drivers/isdn/hisax/sportster.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/sportster.c 2005-03-22 15:06:48.169769864 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: sportster.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: sportster.c,v 1.16 2001/09/24 13:22:57 kai Exp $
+ *
+ * low level stuff for USR Sportster internal TA
+ *
+@@ -20,7 +20,7 @@
+ #include "isdnl1.h"
+
+ extern const char *CardType[];
+-const char *sportster_revision = "$Revision: 1.1.4.1 $";
++const char *sportster_revision = "$Revision: 1.16 $";
+
+ #define byteout(addr,val) outb(val,addr)
+ #define bytein(addr) inb(addr)
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/st5481-debug.h linux-2.4.29/drivers/isdn/hisax/st5481-debug.h
+--- linux-2.4.29.old/drivers/isdn/hisax/st5481-debug.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/st5481-debug.h 2005-03-22 15:06:48.184767584 +0100
+@@ -0,0 +1,103 @@
++#define ST5481_DEBUG 0x0
++
++#if ST5481_DEBUG
++
++
++/*
++ DEBUG flags. Set compile option ST5481_DEBUG with the following bits set to trace
++ the given subsections:
++
++ 0x01: USB
++ 0x02: D
++ 0x04: B
++ 0x08: PH
++ 0x10: PACKET_DUMP D out
++ 0x20: ISO_DUMP D out
++ 0x40: PACKET_DUMP D in
++ 0x80: ISO_DUMP in
++ 0x100: PACKET_DUMP B out
++ 0x200: ISO_DUMP B out
++ 0x400: PACKET_DUMP B in
++*/
++
++#define DBG(level, format, arg...) \
++if (level & ST5481_DEBUG) \
++printk(KERN_DEBUG __FUNCTION__ ": " format "\n" , ## arg) \
++
++static inline void
++dump_packet(const char *name,const u_char *data,int pkt_len)
++{
++#define DUMP_HDR_SIZE 200
++#define DUMP_TLR_SIZE 8
++ if (pkt_len) {
++ int i,len1,len2;
++
++ printk(KERN_DEBUG "%s: length=%d,data=",name,pkt_len);
++
++ if (pkt_len > DUMP_HDR_SIZE+ DUMP_TLR_SIZE) {
++ len1 = DUMP_HDR_SIZE;
++ len2 = DUMP_TLR_SIZE;
++ } else {
++ len1 = pkt_len > DUMP_HDR_SIZE ? DUMP_HDR_SIZE : pkt_len;
++ len2 = 0;
++ }
++ for (i = 0; i < len1; ++i) {
++ printk ("%.2x", data[i]);
++ }
++ if (len2) {
++ printk ("..");
++ for (i = pkt_len-DUMP_TLR_SIZE; i < pkt_len; ++i) {
++ printk ("%.2x", data[i]);
++ }
++ }
++ printk ("\n");
++ }
++#undef DUMP_HDR_SIZE
++#undef DUMP_TLR_SIZE
++}
++
++static inline void
++dump_iso_packet(const char *name,urb_t *urb)
++{
++ int i,j;
++ int len,ofs;
++ u_char *data;
++
++ printk(KERN_DEBUG "%s: packets=%d,errors=%d\n",
++ name,urb->number_of_packets,urb->error_count);
++ for (i = 0; i < urb->number_of_packets; ++i) {
++ if (urb->pipe & USB_DIR_IN) {
++ len = urb->iso_frame_desc[i].actual_length;
++ } else {
++ len = urb->iso_frame_desc[i].length;
++ }
++ ofs = urb->iso_frame_desc[i].offset;
++ printk(KERN_DEBUG "len=%.2d,ofs=%.3d ",len,ofs);
++ if (len) {
++ data = urb->transfer_buffer+ofs;
++ for (j=0; j < len; j++) {
++ printk ("%.2x", data[j]);
++ }
++ }
++ printk("\n");
++ }
++}
++
++#define DUMP_PACKET(level,data,count) \
++ if (level & ST5481_DEBUG) dump_packet(__FUNCTION__,data,count)
++#define DUMP_SKB(level,skb) \
++ if ((level & ST5481_DEBUG) && skb) dump_packet(__FUNCTION__,skb->data,skb->len)
++#define DUMP_ISO_PACKET(level,urb) \
++ if (level & ST5481_DEBUG) dump_iso_packet(__FUNCTION__,urb)
++
++#else
++
++#define DBG(level,format, arg...) do {} while (0)
++#define DUMP_PACKET(level,data,count) do {} while (0)
++#define DUMP_SKB(level,skb) do {} while (0)
++#define DUMP_ISO_PACKET(level,urb) do {} while (0)
++
++#endif
++
++
++
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/st5481.h linux-2.4.29/drivers/isdn/hisax/st5481.h
+--- linux-2.4.29.old/drivers/isdn/hisax/st5481.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/st5481.h 2005-03-22 15:06:48.201765000 +0100
+@@ -219,15 +219,15 @@
+ #define L1_EVENT_COUNT (EV_TIMER3 + 1)
+
+ #define ERR(format, arg...) \
+-printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg)
++printk(KERN_ERR __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
+
+ #define WARN(format, arg...) \
+-printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg)
++printk(KERN_WARNING __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
+
+ #define INFO(format, arg...) \
+-printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __FUNCTION__ , ## arg)
++printk(KERN_INFO __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
+
+-#include "isdnhdlc.h"
++#include "st5481_hdlc.h"
+ #include "fsm.h"
+ #include "hisax_if.h"
+ #include <linux/skbuff.h>
+@@ -236,7 +236,7 @@
+ * FIFO handling
+ */
+
+-/* Generic FIFO structure */
++/* Generic FIFO structure */
+ struct fifo {
+ u_char r,w,count,size;
+ spinlock_t lock;
+@@ -270,7 +270,7 @@
+ index = -1;
+ } else {
+ // Return index where to get the next data to add to the FIFO
+- index = fifo->w++ & (fifo->size-1);
++ index = fifo->w++ & (fifo->size-1);
+ fifo->count++;
+ }
+ spin_unlock_irqrestore(&fifo->lock, flags);
+@@ -289,13 +289,13 @@
+ return -1;
+ }
+
+- spin_lock_irqsave(&fifo->lock, flags);
++ spin_lock_irqsave(&fifo->lock, flags);
+ if (!fifo->count) {
+ // FIFO empty
+ index = -1;
+ } else {
+ // Return index where to get the next data from the FIFO
+- index = fifo->r++ & (fifo->size-1);
++ index = fifo->r++ & (fifo->size-1);
+ fifo->count--;
+ }
+ spin_unlock_irqrestore(&fifo->lock, flags);
+@@ -309,7 +309,7 @@
+ typedef void (*ctrl_complete_t)(void *);
+
+ typedef struct ctrl_msg {
+- struct usb_ctrlrequest dr;
++ devrequest dr;
+ ctrl_complete_t complete;
+ void *context;
+ } ctrl_msg;
+@@ -336,7 +336,7 @@
+ };
+
+ struct st5481_d_out {
+- struct isdnhdlc_vars hdlc_state;
++ struct hdlc_vars hdlc_state;
+ struct urb *urb[2]; /* double buffering */
+ unsigned long busy;
+ struct sk_buff *tx_skb;
+@@ -344,7 +344,7 @@
+ };
+
+ struct st5481_b_out {
+- struct isdnhdlc_vars hdlc_state;
++ struct hdlc_vars hdlc_state;
+ struct urb *urb[2]; /* double buffering */
+ u_char flow_event;
+ u_long busy;
+@@ -352,7 +352,7 @@
+ };
+
+ struct st5481_in {
+- struct isdnhdlc_vars hdlc_state;
++ struct hdlc_vars hdlc_state;
+ struct urb *urb[2]; /* double buffering */
+ int mode;
+ int bufsize;
+@@ -478,7 +478,7 @@
+ if (level & __debug_variable) dump_iso_packet(__FUNCTION__,urb)
+
+ static void __attribute__((unused))
+-dump_iso_packet(const char *name,struct urb *urb)
++dump_iso_packet(const char *name,urb_t *urb)
+ {
+ int i,j;
+ int len,ofs;
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/st5481_b.c linux-2.4.29/drivers/isdn/hisax/st5481_b.c
+--- linux-2.4.29.old/drivers/isdn/hisax/st5481_b.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/st5481_b.c 2005-03-22 15:06:48.216762720 +0100
+@@ -67,28 +67,24 @@
+ bytes_sent = buf_size - len;
+ if (skb->len < bytes_sent)
+ bytes_sent = skb->len;
+- { /* swap tx bytes to get hearable audio data */
+- register unsigned char *src = skb->data;
+- register unsigned char *dest = urb->transfer_buffer+len;
+- register unsigned int count;
+- for (count = 0; count < bytes_sent; count++)
+- *dest++ = isdnhdlc_bit_rev_tab[*src++];
+- }
++
++ memcpy(urb->transfer_buffer+len, skb->data, bytes_sent);
++
+ len += bytes_sent;
+ } else {
+- len += isdnhdlc_encode(&b_out->hdlc_state,
+- skb->data, skb->len, &bytes_sent,
+- urb->transfer_buffer+len, buf_size-len);
++ len += hdlc_encode(&b_out->hdlc_state,
++ skb->data, skb->len, &bytes_sent,
++ urb->transfer_buffer+len, buf_size-len);
+ }
+
+ skb_pull(skb, bytes_sent);
+-
++
+ if (!skb->len) {
+ // Frame sent
+ b_out->tx_skb = NULL;
+ B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
+ dev_kfree_skb_any(skb);
+-
++
+ /* if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */
+ /* st5481B_sched_event(bcs, B_XMTBUFREADY); */
+ /* } */
+@@ -99,9 +95,9 @@
+ len = buf_size;
+ } else {
+ // Send flags
+- len += isdnhdlc_encode(&b_out->hdlc_state,
+- NULL, 0, &bytes_sent,
+- urb->transfer_buffer+len, buf_size-len);
++ len += hdlc_encode(&b_out->hdlc_state,
++ NULL, 0, &bytes_sent,
++ urb->transfer_buffer+len, buf_size-len);
+ }
+ }
+ }
+@@ -213,7 +209,7 @@
+ if (bcs->mode != L1_MODE_NULL) {
+ // Open the B channel
+ if (bcs->mode != L1_MODE_TRANS) {
+- isdnhdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K);
++ hdlc_out_init(&b_out->hdlc_state, 0, bcs->mode == L1_MODE_HDLC_56K);
+ }
+ st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2, NULL, NULL);
+
+@@ -279,7 +275,7 @@
+ usb_b_out_complete, bcs);
+ }
+
+-static void st5481_release_b_out(struct st5481_bcs *bcs)
++static void __devexit st5481_release_b_out(struct st5481_bcs *bcs)
+ {
+ struct st5481_b_out *b_out = &bcs->b_out;
+
+@@ -320,7 +316,7 @@
+ /*
+ * Release buffers and URBs for the B channels
+ */
+-void st5481_release_b(struct st5481_bcs *bcs)
++void __devexit st5481_release_b(struct st5481_bcs *bcs)
+ {
+ DBG(4,"");
+
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/st5481_d.c linux-2.4.29/drivers/isdn/hisax/st5481_d.c
+--- linux-2.4.29.old/drivers/isdn/hisax/st5481_d.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/st5481_d.c 2005-03-22 15:06:48.231760440 +0100
+@@ -162,8 +162,8 @@
+ {ST_L1_F8, EV_TIMER3, l1_timer3},
+ {ST_L1_F8, EV_IND_DP, l1_go_f3},
+ {ST_L1_F8, EV_IND_AP, l1_go_f6},
+- {ST_L1_F8, EV_IND_AI8, l1_go_f7},
+- {ST_L1_F8, EV_IND_AI10, l1_go_f7},
++ {ST_L1_F8, EV_IND_AI8, l1_go_f8},
++ {ST_L1_F8, EV_IND_AI10, l1_go_f8},
+ {ST_L1_F8, EV_IND_RSY, l1_ignore},
+ };
+
+@@ -297,7 +297,7 @@
+ unsigned int num_packets, packet_offset;
+ int len, buf_size, bytes_sent;
+ struct sk_buff *skb;
+- struct iso_packet_descriptor *desc;
++ iso_packet_descriptor_t *desc;
+
+ if (d_out->fsm.state != ST_DOUT_NORMAL)
+ return;
+@@ -313,15 +313,15 @@
+ buf_size = NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT;
+
+ if (skb) {
+- len = isdnhdlc_encode(&d_out->hdlc_state,
+- skb->data, skb->len, &bytes_sent,
+- urb->transfer_buffer, buf_size);
++ len = hdlc_encode(&d_out->hdlc_state,
++ skb->data, skb->len, &bytes_sent,
++ urb->transfer_buffer, buf_size);
+ skb_pull(skb,bytes_sent);
+ } else {
+ // Send flags or idle
+- len = isdnhdlc_encode(&d_out->hdlc_state,
+- NULL, 0, &bytes_sent,
+- urb->transfer_buffer, buf_size);
++ len = hdlc_encode(&d_out->hdlc_state,
++ NULL, 0, &bytes_sent,
++ urb->transfer_buffer, buf_size);
+ }
+
+ if (len < buf_size) {
+@@ -413,7 +413,7 @@
+
+ DBG(2,"len=%d",skb->len);
+
+- isdnhdlc_out_init(&d_out->hdlc_state, 1, 0);
++ hdlc_out_init(&d_out->hdlc_state, 1, 0);
+
+ if (test_and_set_bit(buf_nr, &d_out->busy)) {
+ WARN("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy);
+@@ -422,9 +422,9 @@
+ urb = d_out->urb[buf_nr];
+
+ DBG_SKB(0x10, skb);
+- len = isdnhdlc_encode(&d_out->hdlc_state,
+- skb->data, skb->len, &bytes_sent,
+- urb->transfer_buffer, 16);
++ len = hdlc_encode(&d_out->hdlc_state,
++ skb->data, skb->len, &bytes_sent,
++ urb->transfer_buffer, 16);
+ skb_pull(skb, bytes_sent);
+
+ if(len < 16)
+@@ -673,7 +673,7 @@
+ usb_d_out_complete, adapter);
+ }
+
+-static void st5481_release_d_out(struct st5481_adapter *adapter)
++static void __devexit st5481_release_d_out(struct st5481_adapter *adapter)
+ {
+ struct st5481_d_out *d_out = &adapter->d_out;
+
+@@ -723,7 +723,7 @@
+ return retval;
+ }
+
+-void st5481_release_d(struct st5481_adapter *adapter)
++void __devexit st5481_release_d(struct st5481_adapter *adapter)
+ {
+ DBG(2,"");
+
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/st5481_init.c linux-2.4.29/drivers/isdn/hisax/st5481_init.c
+--- linux-2.4.29.old/drivers/isdn/hisax/st5481_init.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/st5481_init.c 2005-03-22 15:06:48.268754816 +0100
+@@ -14,6 +14,7 @@
+ * TODO:
+ *
+ * b layer1 delay?
++ * hdlc as module
+ * hotplug / unregister issues
+ * mod_inc/dec_use_count
+ * unify parts of d/b channel usb handling
+@@ -177,7 +178,7 @@
+ static struct usb_driver st5481_usb_driver = {
+ name: "st5481_usb",
+ probe: probe_st5481,
+- disconnect: __devexit_p(disconnect_st5481),
++ disconnect: disconnect_st5481,
+ id_table: st5481_ids,
+ };
+
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/st5481_usb.c linux-2.4.29/drivers/isdn/hisax/st5481_usb.c
+--- linux-2.4.29.old/drivers/isdn/hisax/st5481_usb.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/st5481_usb.c 2005-03-22 15:06:48.284752384 +0100
+@@ -41,9 +41,9 @@
+ (unsigned char *)&ctrl->msg_fifo.data[r_index];
+
+ DBG(1,"request=0x%02x,value=0x%04x,index=%x",
+- ((struct ctrl_msg *)urb->setup_packet)->dr.bRequest,
+- ((struct ctrl_msg *)urb->setup_packet)->dr.wValue,
+- ((struct ctrl_msg *)urb->setup_packet)->dr.wIndex);
++ ((struct ctrl_msg *)urb->setup_packet)->dr.request,
++ ((struct ctrl_msg *)urb->setup_packet)->dr.value,
++ ((struct ctrl_msg *)urb->setup_packet)->dr.index);
+
+ // Prepare the URB
+ urb->dev = adapter->usb_dev;
+@@ -69,11 +69,11 @@
+ }
+ ctrl_msg = &ctrl->msg_fifo.data[w_index];
+
+- ctrl_msg->dr.bRequestType = requesttype;
+- ctrl_msg->dr.bRequest = request;
+- ctrl_msg->dr.wValue = cpu_to_le16p(&value);
+- ctrl_msg->dr.wIndex = cpu_to_le16p(&index);
+- ctrl_msg->dr.wLength = 0;
++ ctrl_msg->dr.requesttype = requesttype;
++ ctrl_msg->dr.request = request;
++ ctrl_msg->dr.value = cpu_to_le16p(&value);
++ ctrl_msg->dr.index = cpu_to_le16p(&index);
++ ctrl_msg->dr.length = 0;
+ ctrl_msg->complete = complete;
+ ctrl_msg->context = context;
+
+@@ -140,17 +140,17 @@
+
+ ctrl_msg = (struct ctrl_msg *)urb->setup_packet;
+
+- if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) {
++ if (ctrl_msg->dr.request == USB_REQ_CLEAR_FEATURE) {
+ /* Special case handling for pipe reset */
+- le16_to_cpus(&ctrl_msg->dr.wIndex);
++ le16_to_cpus(&ctrl_msg->dr.index);
+ usb_endpoint_running(adapter->usb_dev,
+- ctrl_msg->dr.wIndex & ~USB_DIR_IN,
+- (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0);
++ ctrl_msg->dr.index & ~USB_DIR_IN,
++ (ctrl_msg->dr.index & USB_DIR_IN) == 0);
+
+ /* toggle is reset on clear */
+ usb_settoggle(adapter->usb_dev,
+- ctrl_msg->dr.wIndex & ~USB_DIR_IN,
+- (ctrl_msg->dr.wIndex & USB_DIR_IN) == 0,
++ ctrl_msg->dr.index & ~USB_DIR_IN,
++ (ctrl_msg->dr.index & USB_DIR_IN) == 0,
+ 0);
+
+
+@@ -235,7 +235,7 @@
+ struct usb_interface_descriptor *altsetting;
+ struct usb_endpoint_descriptor *endpoint;
+ int status;
+- struct urb *urb;
++ urb_t *urb;
+ u_char *buf;
+
+ DBG(1,"");
+@@ -307,7 +307,7 @@
+ * Release buffers and URBs for the interrupt and control
+ * endpoint.
+ */
+-void st5481_release_usb(struct st5481_adapter *adapter)
++void __devexit st5481_release_usb(struct st5481_adapter *adapter)
+ {
+ struct st5481_intr *intr = &adapter->intr;
+ struct st5481_ctrl *ctrl = &adapter->ctrl;
+@@ -443,7 +443,7 @@
+ return retval;
+ }
+
+-void st5481_release_isocpipes(struct urb* urb[2])
++void __devexit st5481_release_isocpipes(struct urb* urb[2])
+ {
+ int j;
+
+@@ -484,18 +484,16 @@
+ ptr = urb->transfer_buffer;
+ while (len > 0) {
+ if (in->mode == L1_MODE_TRANS) {
+- /* swap rx bytes to get hearable audio */
+- register unsigned char *dest = in->rcvbuf;
++ memcpy(in->rcvbuf, ptr, len);
+ status = len;
+- for (; len; len--)
+- *dest++ = isdnhdlc_bit_rev_tab[*ptr++];
++ len = 0;
+ } else {
+- status = isdnhdlc_decode(&in->hdlc_state, ptr, len, &count,
+- in->rcvbuf, in->bufsize);
++ status = hdlc_decode(&in->hdlc_state, ptr, len, &count,
++ in->rcvbuf, in->bufsize);
+ ptr += count;
+ len -= count;
+ }
+-
++
+ if (status > 0) {
+ // Good frame received
+ DBG(4,"count=%d",status);
+@@ -549,7 +547,7 @@
+ return retval;
+ }
+
+-void st5481_release_in(struct st5481_in *in)
++void __devexit st5481_release_in(struct st5481_in *in)
+ {
+ DBG(2,"");
+
+@@ -562,8 +560,7 @@
+ */
+ int st5481_isoc_flatten(struct urb *urb)
+ {
+- struct iso_packet_descriptor *pipd;
+- struct iso_packet_descriptor *pend;
++ piso_packet_descriptor_t pipd,pend;
+ unsigned char *src,*dst;
+ unsigned int len;
+
+@@ -624,10 +621,15 @@
+
+ if (in->mode != L1_MODE_NULL) {
+ if (in->mode != L1_MODE_TRANS)
+- isdnhdlc_rcv_init(&in->hdlc_state,
+- in->mode == L1_MODE_HDLC_56K);
++ hdlc_rcv_init(&in->hdlc_state,
++ in->mode == L1_MODE_HDLC_56K);
+
+ st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL);
++#if 0
++ st5481_usb_device_ctrl_msg(in->adapter, in->counter,
++ in->packet_size,
++ st5481_start_rcv, in);
++#endif
+ st5481_usb_device_ctrl_msg(in->adapter, in->counter,
+ in->packet_size,
+ NULL, NULL);
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/tei.c linux-2.4.29/drivers/isdn/hisax/tei.c
+--- linux-2.4.29.old/drivers/isdn/hisax/tei.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/tei.c 2005-03-22 15:06:48.316747520 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: tei.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: tei.c,v 2.20 2001/09/24 13:22:57 kai Exp $
+ *
+ * Author Karsten Keil
+ * based on the teles driver from Jan den Ouden
+@@ -21,7 +21,7 @@
+ #include <linux/init.h>
+ #include <linux/random.h>
+
+-const char *tei_revision = "$Revision: 1.1.4.1 $";
++const char *tei_revision = "$Revision: 2.20 $";
+
+ #define ID_REQUEST 1
+ #define ID_ASSIGNED 2
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/teleint.c linux-2.4.29/drivers/isdn/hisax/teleint.c
+--- linux-2.4.29.old/drivers/isdn/hisax/teleint.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/teleint.c 2005-03-22 15:06:48.330745392 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: teleint.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: teleint.c,v 1.16 2001/09/24 13:22:57 kai Exp $
+ *
+ * low level stuff for TeleInt isdn cards
+ *
+@@ -19,7 +19,7 @@
+
+ extern const char *CardType[];
+
+-const char *TeleInt_revision = "$Revision: 1.1.4.1 $";
++const char *TeleInt_revision = "$Revision: 1.16 $";
+
+ #define byteout(addr,val) outb(val,addr)
+ #define bytein(addr) inb(addr)
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/teles0.c linux-2.4.29/drivers/isdn/hisax/teles0.c
+--- linux-2.4.29.old/drivers/isdn/hisax/teles0.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/teles0.c 2005-03-22 15:06:48.348742656 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: teles0.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: teles0.c,v 2.15 2001/09/24 13:22:57 kai Exp $
+ *
+ * low level stuff for Teles Memory IO isdn cards
+ *
+@@ -24,7 +24,7 @@
+
+ extern const char *CardType[];
+
+-const char *teles0_revision = "$Revision: 1.1.4.1 $";
++const char *teles0_revision = "$Revision: 2.15 $";
+
+ #define TELES_IOMEM_SIZE 0x400
+ #define byteout(addr,val) outb(val,addr)
+@@ -189,8 +189,10 @@
+ {
+ if (cs->hw.teles0.cfg_reg)
+ release_region(cs->hw.teles0.cfg_reg, 8);
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ iounmap((unsigned char *)cs->hw.teles0.membase);
+ release_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
++#endif
+ }
+
+ static int
+@@ -327,6 +329,7 @@
+ /* 16.0 and 8.0 designed for IOM1 */
+ test_and_set_bit(HW_IOM1, &cs->HW_Flags);
+ cs->hw.teles0.phymem = card->para[1];
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ if (check_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE)) {
+ printk(KERN_WARNING
+ "HiSax: %s memory region %lx-%lx already in use\n",
+@@ -342,6 +345,9 @@
+ }
+ cs->hw.teles0.membase =
+ (unsigned long) ioremap(cs->hw.teles0.phymem, TELES_IOMEM_SIZE);
++#else
++ cs->hw.teles0.membase = cs->hw.teles0.phymem;
++#endif
+ printk(KERN_INFO
+ "HiSax: %s config irq:%d mem:0x%lX cfg:0x%X\n",
+ CardType[cs->typ], cs->irq,
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/teles3.c linux-2.4.29/drivers/isdn/hisax/teles3.c
+--- linux-2.4.29.old/drivers/isdn/hisax/teles3.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/teles3.c 2005-03-22 15:06:48.367739768 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: teles3.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: teles3.c,v 2.19 2001/09/24 13:22:57 kai Exp $
+ *
+ * low level stuff for Teles 16.3 & PNP isdn cards
+ *
+@@ -15,14 +15,13 @@
+ */
+ #define __NO_VERSION__
+ #include <linux/init.h>
+-#include <linux/isapnp.h>
+ #include "hisax.h"
+ #include "isac.h"
+ #include "hscx.h"
+ #include "isdnl1.h"
+
+ extern const char *CardType[];
+-const char *teles3_revision = "$Revision: 1.1.4.1 $";
++const char *teles3_revision = "$Revision: 2.19 $";
+
+ #define byteout(addr,val) outb(val,addr)
+ #define bytein(addr) inb(addr)
+@@ -255,24 +254,6 @@
+ return(0);
+ }
+
+-#ifdef __ISAPNP__
+-static struct isapnp_device_id teles_ids[] __initdata = {
+- { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
+- ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
+- (unsigned long) "Teles 16.3 PnP" },
+- { ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
+- ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
+- (unsigned long) "Creatix 16.3 PnP" },
+- { ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
+- ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
+- (unsigned long) "Compaq ISDN S0" },
+- { 0, }
+-};
+-
+-static struct isapnp_device_id *tdev = &teles_ids[0];
+-static struct pci_bus *pnp_c __devinitdata = NULL;
+-#endif
+-
+ int __devinit
+ setup_teles3(struct IsdnCard *card)
+ {
+@@ -286,47 +267,6 @@
+ && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA))
+ return (0);
+
+-#ifdef __ISAPNP__
+- if (!card->para[1] && isapnp_present()) {
+- struct pci_bus *pb;
+- struct pci_dev *pd;
+-
+- while(tdev->card_vendor) {
+- if ((pb = isapnp_find_card(tdev->card_vendor,
+- tdev->card_device, pnp_c))) {
+- pnp_c = pb;
+- pd = NULL;
+- if ((pd = isapnp_find_dev(pnp_c,
+- tdev->vendor, tdev->function, pd))) {
+- printk(KERN_INFO "HiSax: %s detected\n",
+- (char *)tdev->driver_data);
+- pd->prepare(pd);
+- pd->deactivate(pd);
+- pd->activate(pd);
+- card->para[3] = pd->resource[2].start;
+- card->para[2] = pd->resource[1].start;
+- card->para[1] = pd->resource[0].start;
+- card->para[0] = pd->irq_resource[0].start;
+- if (!card->para[0] || !card->para[1] || !card->para[2]) {
+- printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n",
+- card->para[0], card->para[1], card->para[2]);
+- pd->deactivate(pd);
+- return(0);
+- }
+- break;
+- } else {
+- printk(KERN_ERR "Teles PnP: PnP error card found, no device\n");
+- }
+- }
+- tdev++;
+- pnp_c=NULL;
+- }
+- if (!tdev->card_vendor) {
+- printk(KERN_INFO "Teles PnP: no ISAPnP card found\n");
+- return(0);
+- }
+- }
+-#endif
+ if (cs->typ == ISDN_CTYPE_16_3) {
+ cs->hw.teles3.cfg_reg = card->para[1];
+ switch (cs->hw.teles3.cfg_reg) {
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/telespci.c linux-2.4.29/drivers/isdn/hisax/telespci.c
+--- linux-2.4.29.old/drivers/isdn/hisax/telespci.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/telespci.c 2005-03-22 15:06:48.382737488 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: telespci.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: telespci.c,v 2.23 2001/09/24 13:22:57 kai Exp $
+ *
+ * low level stuff for Teles PCI isdn cards
+ *
+@@ -20,9 +20,10 @@
+ #include "hscx.h"
+ #include "isdnl1.h"
+ #include <linux/pci.h>
++#include <linux/isdn_compat.h>
+
+ extern const char *CardType[];
+-const char *telespci_revision = "$Revision: 1.1.4.1 $";
++const char *telespci_revision = "$Revision: 2.23 $";
+
+ #define ZORAN_PO_RQ_PEN 0x02000000
+ #define ZORAN_PO_WR 0x00800000
+@@ -307,10 +308,10 @@
+ printk(KERN_WARNING "Teles: No IRQ for PCI card found\n");
+ return(0);
+ }
+- cs->hw.teles0.membase = (u_long) ioremap(pci_resource_start(dev_tel, 0),
++ cs->hw.teles0.membase = (u_long) ioremap(pci_resource_start_mem(dev_tel, 0),
+ PAGE_SIZE);
+ printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n",
+- pci_resource_start(dev_tel, 0), dev_tel->irq);
++ pci_resource_start_mem(dev_tel, 0), dev_tel->irq);
+ } else {
+ printk(KERN_WARNING "TelesPCI: No PCI card found\n");
+ return(0);
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/w6692.c linux-2.4.29/drivers/isdn/hisax/w6692.c
+--- linux-2.4.29.old/drivers/isdn/hisax/w6692.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/w6692.c 2005-03-22 15:06:48.398735056 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: w6692.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: w6692.c,v 1.18 2001/09/24 13:22:57 kai Exp $
+ *
+ * Winbond W6692 specific routines
+ *
+@@ -18,6 +18,7 @@
+ #include "isdnl1.h"
+ #include <linux/interrupt.h>
+ #include <linux/pci.h>
++#include <linux/isdn_compat.h>
+
+ /* table entry in the PCI devices list */
+ typedef struct {
+@@ -29,20 +30,14 @@
+
+ static const PCI_ENTRY id_list[] =
+ {
+- {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, "Winbond", "W6692"},
+ {PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"},
+- {0, 0, "U.S.Robotics", "ISDN PCI Card TA"}
++ {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, "Winbond", "W6692"},
++ {0, 0, NULL, NULL}
+ };
+
+-#define W6692_SV_USR 0x16ec
+-#define W6692_SD_USR 0x3409
+-#define W6692_WINBOND 0
+-#define W6692_DYNALINK 1
+-#define W6692_USR 2
+-
+ extern const char *CardType[];
+
+-const char *w6692_revision = "$Revision: 1.1.4.1 $";
++const char *w6692_revision = "$Revision: 1.18 $";
+
+ #define DBUSY_TIMER_VALUE 80
+
+@@ -675,6 +670,16 @@
+ static void
+ DC_Close_W6692(struct IsdnCardState *cs)
+ {
++#if 0
++ if (cs->dc.w6692.mon_rx) {
++ kfree(cs->dc.w6692.mon_rx);
++ cs->dc.w6692.mon_rx = NULL;
++ }
++ if (cs->dc.w6692.mon_tx) {
++ kfree(cs->dc.w6692.mon_tx);
++ cs->dc.w6692.mon_tx = NULL;
++ }
++#endif
+ }
+
+ static void
+@@ -865,38 +870,31 @@
+ return (0);
+ }
+
+-void resetW6692(struct IsdnCardState *cs)
+-{
+- cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST);
+- schedule_timeout((10*HZ)/1000);
+- cs->writeW6692(cs, W_D_CTL, 0x00);
+- schedule_timeout((10*HZ)/1000);
+- cs->writeW6692(cs, W_IMASK, 0xff);
+- cs->writeW6692(cs, W_D_SAM, 0xff);
+- cs->writeW6692(cs, W_D_TAM, 0xff);
+- cs->writeW6692(cs, W_D_EXIM, 0x00);
+- cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT);
+- cs->writeW6692(cs, W_IMASK, 0x18);
+- if (cs->subtyp == W6692_USR) {
+- /* seems that USR implemented some power control features
+- * Pin 79 is connected to the oscilator circuit so we
+- * have to handle it here
+- */
+- cs->writeW6692(cs, W_PCTL, 0x80);
+- cs->writeW6692(cs, W_XDATA, 0x00);
+- }
+-}
+-
+ void __init initW6692(struct IsdnCardState *cs, int part)
+ {
+ if (part & 1) {
+ cs->tqueue.routine = (void *) (void *) W6692_bh;
+ cs->setstack_d = setstack_W6692;
+ cs->DC_Close = DC_Close_W6692;
++#if 0
++ cs->dc.w6692.mon_tx = NULL;
++ cs->dc.w6692.mon_rx = NULL;
++#endif
+ cs->dbusytimer.function = (void *) dbusy_timer_handler;
+ cs->dbusytimer.data = (long) cs;
+ init_timer(&cs->dbusytimer);
+- resetW6692(cs);
++
++ cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST);
++ cs->writeW6692(cs, W_D_CTL, 0x00);
++ cs->writeW6692(cs, W_IMASK, 0xff);
++#if 0
++ cs->dc.w6692.mocr = 0xaa;
++#endif
++ cs->writeW6692(cs, W_D_SAM, 0xff);
++ cs->writeW6692(cs, W_D_TAM, 0xff);
++ cs->writeW6692(cs, W_D_EXIM, 0x00);
++ cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT);
++ cs->writeW6692(cs, W_IMASK, 0x18);
+ ph_command(cs, W_L1CMD_RST);
+ cs->dc.w6692.ph_state = W_L1CMD_RST;
+ W6692_new_ph(cs);
+@@ -963,14 +961,9 @@
+ {
+ switch (mt) {
+ case CARD_RESET:
+- resetW6692(cs);
+ return (0);
+ case CARD_RELEASE:
+- cs->writeW6692(cs, W_IMASK, 0xff);
+ release_region(cs->hw.w6692.iobase, 256);
+- if (cs->subtyp == W6692_USR) {
+- cs->writeW6692(cs, W_XDATA, 0x04);
+- }
+ return (0);
+ case CARD_INIT:
+ initW6692(cs, 3);
+@@ -1013,7 +1006,6 @@
+ if (dev_w6692) {
+ if (pci_enable_device(dev_w6692))
+ continue;
+- cs->subtyp = id_idx;
+ break;
+ }
+ id_idx++;
+@@ -1023,14 +1015,7 @@
+ pci_irq = dev_w6692->irq;
+ /* I think address 0 is allways the configuration area */
+ /* and address 1 is the real IO space KKe 03.09.99 */
+- pci_ioaddr = pci_resource_start(dev_w6692, 1);
+- /* USR ISDN PCI card TA need some special handling */
+- if (cs->subtyp == W6692_WINBOND) {
+- if ((W6692_SV_USR == dev_w6692->subsystem_vendor) &&
+- (W6692_SD_USR == dev_w6692->subsystem_device)) {
+- cs->subtyp = W6692_USR;
+- }
+- }
++ pci_ioaddr = pci_resource_start_io(dev_w6692, 1);
+ }
+ if (!found) {
+ printk(KERN_WARNING "W6692: No PCI card found\n");
+@@ -1047,18 +1032,18 @@
+ }
+ cs->hw.w6692.iobase = pci_ioaddr;
+ printk(KERN_INFO "Found: %s %s, I/O base: 0x%x, irq: %d\n",
+- id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name,
+- pci_ioaddr, pci_irq);
++ id_list[id_idx].vendor_name, id_list[id_idx].card_name,
++ pci_ioaddr, dev_w6692->irq);
+ if (check_region((cs->hw.w6692.iobase), 256)) {
+ printk(KERN_WARNING
+ "HiSax: %s I/O ports %x-%x already in use\n",
+- id_list[cs->subtyp].card_name,
++ id_list[id_idx].card_name,
+ cs->hw.w6692.iobase,
+ cs->hw.w6692.iobase + 255);
+ return (0);
+ } else {
+ request_region(cs->hw.w6692.iobase, 256,
+- id_list[cs->subtyp].card_name);
++ id_list[id_idx].card_name);
+ }
+ #else
+ printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n");
+@@ -1068,7 +1053,7 @@
+
+ printk(KERN_INFO
+ "HiSax: %s config irq:%d I/O:%x\n",
+- id_list[cs->subtyp].card_name, cs->irq,
++ id_list[id_idx].card_name, cs->irq,
+ cs->hw.w6692.iobase);
+
+ cs->readW6692 = &ReadW6692;
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/w6692.h linux-2.4.29/drivers/isdn/hisax/w6692.h
+--- linux-2.4.29.old/drivers/isdn/hisax/w6692.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hisax/w6692.h 2005-03-22 15:06:48.414732624 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: w6692.h,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
++/* $Id: w6692.h,v 1.4 2001/09/24 13:22:57 kai Exp $
+ *
+ * Winbond W6692 specific defines
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hysdn/boardergo.c linux-2.4.29/drivers/isdn/hysdn/boardergo.c
+--- linux-2.4.29.old/drivers/isdn/hysdn/boardergo.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hysdn/boardergo.c 2005-03-22 15:06:48.468724416 +0100
+@@ -1,27 +1,41 @@
+-/* $Id: boardergo.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
+- *
++/* $Id: boardergo.c,v 1.9 2001/07/19 20:39:51 kai Exp $
++
+ * Linux driver for HYSDN cards, specific routines for ergo type boards.
+ *
+- * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH
+- * Copyright 1999 by Werner Cornelius (werner@titro.de)
+- *
+- * This software may be used and distributed according to the terms
+- * of the GNU General Public License, incorporated herein by reference.
+- *
+ * As all Linux supported cards Champ2, Ergo and Metro2/4 use the same
+ * DPRAM interface and layout with only minor differences all related
+ * stuff is done here, not in separate modules.
+ *
++ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
++ *
++ * Copyright 1999 by Werner Cornelius (werner@titro.de)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
+ */
+
++#define __NO_VERSION__
+ #include <linux/config.h>
+-#include <linux/sched.h>
++#include <linux/module.h>
++#include <linux/version.h>
++#include <asm/io.h>
+ #include <linux/signal.h>
+ #include <linux/kernel.h>
+ #include <linux/ioport.h>
+ #include <linux/interrupt.h>
+ #include <linux/vmalloc.h>
+-#include <asm/io.h>
+
+ #include "hysdn_defs.h"
+ #include "boardergo.h"
+@@ -45,11 +59,10 @@
+ if (!card->irq_enabled)
+ return; /* other device interrupting or irq switched off */
+
+- save_flags(flags);
+- cli(); /* no further irqs allowed */
++ HYSDN_SPIN_LOCK(&card->irq_lock, flags);
+
+ if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) {
+- restore_flags(flags); /* restore old state */
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ return; /* no interrupt requested by E1 */
+ }
+ /* clear any pending ints on the board */
+@@ -63,7 +76,7 @@
+ queue_task(&card->irq_queue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+- restore_flags(flags);
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ } /* ergo_interrupt */
+
+ /******************************************************************************/
+@@ -83,17 +96,15 @@
+ return; /* invalid call */
+
+ dpr = card->dpram; /* point to DPRAM */
++ HYSDN_SPIN_LOCK(&card->irq_lock, flags);
+
+- save_flags(flags);
+- cli();
+ if (card->hw_lock) {
+- restore_flags(flags); /* hardware currently unavailable */
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ return;
+ }
+ card->hw_lock = 1; /* we now lock the hardware */
+
+ do {
+- sti(); /* reenable other ints */
+ again = 0; /* assume loop not to be repeated */
+
+ if (!dpr->ToHyFlag) {
+@@ -113,15 +124,13 @@
+ again = 1; /* restart loop */
+ }
+ } /* a message has arrived for us */
+- cli(); /* no further ints */
+ if (again) {
+ dpr->ToHyInt = 1;
+ dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
+ } else
+ card->hw_lock = 0; /* free hardware again */
+ } while (again); /* until nothing more to do */
+-
+- restore_flags(flags);
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ } /* ergo_irq_bh */
+
+
+@@ -138,8 +147,7 @@
+ #ifdef CONFIG_HYSDN_CAPI
+ hycapi_capi_stop(card);
+ #endif /* CONFIG_HYSDN_CAPI */
+- save_flags(flags);
+- cli();
++ HYSDN_SPIN_LOCK(&card->irq_lock, flags);
+ val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */
+ val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1); /* mask irq */
+ byteout(card->iobase + PCI9050_INTR_REG, val);
+@@ -147,8 +155,7 @@
+ byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RESET); /* reset E1 processor */
+ card->state = CARD_STATE_UNUSED;
+ card->err_log_state = ERRLOG_STATE_OFF; /* currently no log active */
+-
+- restore_flags(flags);
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ } /* ergo_stopcard */
+
+ /**************************************************************************/
+@@ -163,20 +170,17 @@
+ card->err_log_state = ERRLOG_STATE_OFF; /* must be off */
+ return;
+ }
+- save_flags(flags);
+- cli();
+-
++ HYSDN_SPIN_LOCK(&card->irq_lock, flags);
+ if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) ||
+ ((card->err_log_state == ERRLOG_STATE_ON) && on)) {
+- restore_flags(flags);
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ return; /* nothing to do */
+ }
+ if (on)
+ card->err_log_state = ERRLOG_STATE_START; /* request start */
+ else
+ card->err_log_state = ERRLOG_STATE_STOP; /* request stop */
+-
+- restore_flags(flags);
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ queue_task(&card->irq_queue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ } /* ergo_set_errlog_state */
+@@ -245,9 +249,6 @@
+ while (!dpram->ToHyNoDpramErrLog); /* reread volatile register to flush PCI */
+
+ byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RUN); /* start E1 processor */
+- /* the interrupts are still masked */
+-
+- sti();
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
+
+@@ -282,7 +283,6 @@
+ dst = sp->Data; /* point to data in spool structure */
+ buflen = sp->Len; /* maximum len of spooled data */
+ wr_mirror = sp->WrPtr; /* only once read */
+- sti();
+
+ /* try until all bytes written or error */
+ i = 0x1000; /* timeout value */
+@@ -358,9 +358,7 @@
+
+ if (card->debug_flags & LOG_POF_RECORD)
+ hysdn_addlog(card, "ERGO: pof boot success");
+- save_flags(flags);
+- cli();
+-
++ HYSDN_SPIN_LOCK(&card->irq_lock, flags);
+ card->state = CARD_STATE_RUN; /* now card is running */
+ /* enable the cards interrupt */
+ byteout(card->iobase + PCI9050_INTR_REG,
+@@ -371,8 +369,7 @@
+ dpr->ToPcFlag = 0; /* reset data indicator */
+ dpr->ToHyInt = 1;
+ dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
+-
+- restore_flags(flags);
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ if ((hynet_enable & (1 << card->myid))
+ && (i = hysdn_net_create(card)))
+ {
+@@ -387,7 +384,6 @@
+ #endif /* CONFIG_HYSDN_CAPI */
+ return (0); /* success */
+ } /* data has arrived */
+- sti();
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout((50 * HZ) / 1000); /* Timeout 50ms */
+ } /* wait until timeout */
+diff -rNu linux-2.4.29.old/drivers/isdn/hysdn/boardergo.h linux-2.4.29/drivers/isdn/hysdn/boardergo.h
+--- linux-2.4.29.old/drivers/isdn/hysdn/boardergo.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hysdn/boardergo.h 2005-03-22 15:06:48.485721832 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: boardergo.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Linux driver for HYSDN cards, definitions for ergo type boards (buffers..).
+ *
+@@ -10,6 +10,7 @@
+ *
+ */
+
++#include <linux/isdn_compat.h>
+
+ /************************************************/
+ /* defines for the dual port memory of the card */
+diff -rNu linux-2.4.29.old/drivers/isdn/hysdn/hycapi.c linux-2.4.29/drivers/isdn/hysdn/hycapi.c
+--- linux-2.4.29.old/drivers/isdn/hysdn/hycapi.c 2005-03-22 14:47:57.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hysdn/hycapi.c 2005-03-22 15:06:48.500719552 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hycapi.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Linux driver for HYSDN cards, CAPI2.0-Interface.
+ *
+@@ -29,7 +29,7 @@
+ #include "hysdn_defs.h"
+ #include <linux/kernelcapi.h>
+
+-static char hycapi_revision[]="$Revision: 1.1.4.1 $";
++static char hycapi_revision[]="$Revision$";
+
+ unsigned int hycapi_enable = 0xffffffff;
+ MODULE_PARM(hycapi_enable, "i");
+diff -rNu linux-2.4.29.old/drivers/isdn/hysdn/hysdn_boot.c linux-2.4.29/drivers/isdn/hysdn/hysdn_boot.c
+--- linux-2.4.29.old/drivers/isdn/hysdn/hysdn_boot.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hysdn/hysdn_boot.c 2005-03-22 15:06:48.516717120 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hysdn_boot.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Linux driver for HYSDN cards
+ * specific routines for booting and pof handling
+@@ -143,7 +143,7 @@
+ (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA",
+ datlen, boot->pof_recoffset);
+
+- if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen)) < 0)
++ if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen) < 0))
+ return (boot->last_error); /* error writing data */
+
+ if (boot->pof_recoffset + datlen >= boot->pof_reclen)
+diff -rNu linux-2.4.29.old/drivers/isdn/hysdn/hysdn_defs.h linux-2.4.29/drivers/isdn/hysdn/hysdn_defs.h
+--- linux-2.4.29.old/drivers/isdn/hysdn/hysdn_defs.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hysdn/hysdn_defs.h 2005-03-22 15:06:48.533714536 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hysdn_defs.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id: hysdn_defs.h,v 1.10 2001/09/24 13:23:03 kai Exp $
+ *
+ * Linux driver for HYSDN cards
+ * global definitions and exported vars and functions.
+@@ -19,6 +19,11 @@
+ #include <linux/interrupt.h>
+ #include <linux/tqueue.h>
+ #include <linux/skbuff.h>
++#include <linux/isdn_compat.h>
++#include <linux/spinlock.h>
++
++#define HYSDN_SPIN_LOCK(a,b) spin_lock(a)
++#define HYSDN_SPIN_UNLOCK(a,b) spin_unlock(a)
+
+ /****************************/
+ /* storage type definitions */
+@@ -176,6 +181,7 @@
+ struct tq_struct irq_queue; /* interrupt task queue */
+ uchar volatile irq_enabled; /* interrupt enabled if != 0 */
+ uchar volatile hw_lock; /* hardware is currently locked -> no access */
++ spinlock_t irq_lock;
+
+ /* boot process */
+ void *boot; /* pointer to boot private data */
+diff -rNu linux-2.4.29.old/drivers/isdn/hysdn/hysdn_init.c linux-2.4.29/drivers/isdn/hysdn/hysdn_init.c
+--- linux-2.4.29.old/drivers/isdn/hysdn/hysdn_init.c 2005-03-22 14:47:57.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hysdn/hysdn_init.c 2005-03-22 15:06:48.551711800 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hysdn_init.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Linux driver for HYSDN cards, init functions.
+ *
+@@ -21,6 +21,7 @@
+
+ #include "hysdn_defs.h"
+
++#ifndef COMPAT_HAS_2_2_PCI
+ static struct pci_device_id hysdn_pci_tbl[] __initdata = {
+ {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO},
+ {PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2},
+@@ -29,11 +30,12 @@
+ { } /* Terminating entry */
+ };
+ MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl);
++#endif
+ MODULE_DESCRIPTION("ISDN4Linux: Driver for HYSDN cards");
+ MODULE_AUTHOR("Werner Cornelius");
+ MODULE_LICENSE("GPL");
+
+-static char *hysdn_init_revision = "$Revision: 1.1.4.1 $";
++static char *hysdn_init_revision = "$Revision$";
+ int cardmax; /* number of found cards */
+ hysdn_card *card_root = NULL; /* pointer to first card */
+
+@@ -91,11 +93,11 @@
+ card->myid = cardmax; /* set own id */
+ card->bus = akt_pcidev->bus->number;
+ card->devfn = akt_pcidev->devfn; /* slot + function */
+- card->subsysid = akt_pcidev->subsystem_device;
++ pci_get_sub_system(akt_pcidev,card->subsysid);
+ card->irq = akt_pcidev->irq;
+- card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
+- card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
+- card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
++ card->iobase = pci_resource_start_io(akt_pcidev, PCI_REG_PLX_IO_BASE);
++ card->plxbase = pci_resource_start_mem(akt_pcidev, PCI_REG_PLX_MEM_BASE);
++ card->membase = pci_resource_start_mem(akt_pcidev, PCI_REG_MEMORY_BASE);
+ card->brdtype = BD_NONE; /* unknown */
+ card->debug_flags = DEF_DEB_FLAGS; /* set default debug */
+ card->faxchans = 0; /* default no fax channels */
+diff -rNu linux-2.4.29.old/drivers/isdn/hysdn/hysdn_net.c linux-2.4.29/drivers/isdn/hysdn/hysdn_net.c
+--- linux-2.4.29.old/drivers/isdn/hysdn/hysdn_net.c 2005-03-22 14:47:57.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hysdn/hysdn_net.c 2005-03-22 15:06:48.567709368 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hysdn_net.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Linux driver for HYSDN cards, net (ethernet type) handling routines.
+ *
+@@ -29,7 +29,7 @@
+ MODULE_PARM(hynet_enable, "i");
+
+ /* store the actual version for log reporting */
+-char *hysdn_net_revision = "$Revision: 1.1.4.1 $";
++char *hysdn_net_revision = "$Revision$";
+
+ #define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */
+
+@@ -45,6 +45,10 @@
+ /* additional vars may be added here */
+ char dev_name[9]; /* our own device name */
+
++#ifdef COMPAT_NO_SOFTNET
++ struct sk_buff *tx_skb; /* buffer for tx operation */
++
++#else
+ /* Tx control lock. This protects the transmit buffer ring
+ * state along with the "tx full" state of the driver. This
+ * means all netif_queue flow control actions are protected
+@@ -56,6 +60,7 @@
+ int sk_count; /* number of buffers currently in ring */
+
+ int is_open; /* flag controlling module locking */
++#endif
+ }; /* net_local */
+
+
+@@ -83,11 +88,19 @@
+ hysdn_card *card = dev->priv;
+ int i;
+
++#ifdef COMPAT_NO_SOFTNET
++ dev->tbusy = 0; /* non busy state */
++ dev->interrupt = 0;
++ if (!dev->start)
++ MOD_INC_USE_COUNT; /* increment only if device is down */
++ dev->start = 1; /* and started */
++#else
+ if (!((struct net_local *) dev)->is_open)
+ MOD_INC_USE_COUNT; /* increment only if interface is actually down */
+ ((struct net_local *) dev)->is_open = 1; /* device actually open */
+
+ netif_start_queue(dev); /* start tx-queueing */
++#endif
+
+ /* Fill in the MAC-level header (if not already set) */
+ if (!card->mac_addr[0]) {
+@@ -104,6 +117,7 @@
+ return (0);
+ } /* net_open */
+
++#ifndef COMPAT_NO_SOFTNET
+ /*******************************************/
+ /* flush the currently occupied tx-buffers */
+ /* must only be called when device closed */
+@@ -119,6 +133,7 @@
+ nl->sk_count--;
+ }
+ } /* flush_tx_buffers */
++#endif
+
+
+ /*********************************************************************/
+@@ -129,6 +144,15 @@
+ net_close(struct net_device *dev)
+ {
+
++#ifdef COMPAT_NO_SOFTNET
++ dev->tbusy = 1; /* we are busy */
++
++ if (dev->start)
++ MOD_DEC_USE_COUNT; /* dec only if device has been active */
++
++ dev->start = 0; /* and not started */
++
++#else
+ netif_stop_queue(dev); /* disable queueing */
+
+ if (((struct net_local *) dev)->is_open)
+@@ -136,9 +160,52 @@
+ ((struct net_local *) dev)->is_open = 0;
+ flush_tx_buffers((struct net_local *) dev);
+
++#endif
+ return (0); /* success */
+ } /* net_close */
+
++#ifdef COMPAT_NO_SOFTNET
++/************************************/
++/* send a packet on this interface. */
++/* only for kernel versions < 2.3.33 */
++/************************************/
++static int
++net_send_packet(struct sk_buff *skb, struct net_device *dev)
++{
++ struct net_local *lp = (struct net_local *) dev;
++
++ if (dev->tbusy) {
++ /*
++ * If we get here, some higher level has decided we are broken.
++ * There should really be a "kick me" function call instead.
++ * As ISDN may have higher timeouts than real ethernet 10s timeout
++ */
++ int tickssofar = jiffies - dev->trans_start;
++ if (tickssofar < (10000 * HZ) / 1000)
++ return 1;
++ printk(KERN_WARNING "%s: transmit timed out. \n", dev->name);
++ dev->tbusy = 0;
++ dev->trans_start = jiffies;
++ }
++ /*
++ * Block a timer-based transmit from overlapping. This could better be
++ * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
++ */
++ if (test_and_set_bit(0, (void *) &dev->tbusy) != 0)
++ printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
++
++ else {
++ lp->stats.tx_bytes += skb->len;
++ dev->trans_start = jiffies;
++ lp->tx_skb = skb; /* remember skb pointer */
++ queue_task(&((hysdn_card *) dev->priv)->irq_queue, &tq_immediate);
++ mark_bh(IMMEDIATE_BH);
++ }
++
++ return (0); /* success */
++} /* net_send_packet */
++
++#else
+ /************************************/
+ /* send a packet on this interface. */
+ /* new style for kernel >= 2.3.33 */
+@@ -176,6 +243,7 @@
+ return (0); /* success */
+ } /* net_send_packet */
+
++#endif
+
+
+ /***********************************************************************/
+@@ -190,6 +258,15 @@
+ if (!lp)
+ return; /* non existing device */
+
++#ifdef COMPAT_NO_SOFTNET
++ if (lp->tx_skb)
++ dev_kfree_skb(lp->tx_skb); /* free tx pointer */
++ lp->tx_skb = NULL; /* reset pointer */
++
++ lp->stats.tx_packets++;
++ lp->netdev.tbusy = 0;
++ mark_bh(NET_BH); /* Inform upper layers. */
++#else
+
+ if (!lp->sk_count)
+ return; /* error condition */
+@@ -203,6 +280,7 @@
+
+ if (lp->sk_count-- == MAX_SKB_BUFFERS) /* dec usage count */
+ netif_start_queue((struct net_device *) lp);
++#endif
+ } /* hysdn_tx_netack */
+
+ /*****************************************************/
+@@ -250,10 +328,15 @@
+ if (!lp)
+ return (NULL); /* non existing device */
+
++#ifdef COMPAT_NO_SOFTNET
++ return (lp->tx_skb); /* return packet pointer */
++
++#else
+ if (!lp->sk_count)
+ return (NULL); /* nothing available */
+
+ return (lp->skbs[lp->out_idx]); /* next packet to send */
++#endif
+ } /* hysdn_tx_netget */
+
+
+@@ -296,15 +379,21 @@
+ }
+ memset(dev, 0, sizeof(struct net_local)); /* clean the structure */
+
++#ifndef COMPAT_NO_SOFTNET
+ spin_lock_init(&((struct net_local *) dev)->lock);
++#endif
+
+ /* initialise necessary or informing fields */
+ dev->base_addr = card->iobase; /* IO address */
+ dev->irq = card->irq; /* irq */
+ dev->init = net_init; /* the init function of the device */
++#ifdef COMPAT_NO_SOFTNET
++ dev->name = ((struct net_local *) dev)->dev_name; /* device name */
++#else
+ if(dev->name) {
+ strcpy(dev->name, ((struct net_local *) dev)->dev_name);
+ }
++#endif
+ if ((i = register_netdev(dev))) {
+ printk(KERN_WARNING "HYSDN: unable to create network device\n");
+ kfree(dev);
+@@ -333,7 +422,9 @@
+ card->netif = NULL; /* clear out pointer */
+ dev->stop(dev); /* close the device */
+
++#ifndef COMPAT_NO_SOFTNET
+ flush_tx_buffers((struct net_local *) dev); /* empty buffers */
++#endif
+
+ unregister_netdev(dev); /* release the device */
+ kfree(dev); /* release the memory allocated */
+diff -rNu linux-2.4.29.old/drivers/isdn/hysdn/hysdn_pof.h linux-2.4.29/drivers/isdn/hysdn/hysdn_pof.h
+--- linux-2.4.29.old/drivers/isdn/hysdn/hysdn_pof.h 2005-03-22 14:47:57.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hysdn/hysdn_pof.h 2005-03-22 15:06:48.583706936 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hysdn_pof.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Linux driver for HYSDN cards, definitions used for handling pof-files.
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/hysdn/hysdn_procconf.c linux-2.4.29/drivers/isdn/hysdn/hysdn_procconf.c
+--- linux-2.4.29.old/drivers/isdn/hysdn/hysdn_procconf.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hysdn/hysdn_procconf.c 2005-03-22 15:06:48.598704656 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hysdn_procconf.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions.
+ *
+@@ -17,11 +17,13 @@
+ #include <linux/poll.h>
+ #include <linux/proc_fs.h>
+ #include <linux/pci.h>
++#ifndef COMPAT_USE_MODCOUNT_LOCK
+ #include <linux/smp_lock.h>
++#endif
+
+ #include "hysdn_defs.h"
+
+-static char *hysdn_procconf_revision = "$Revision: 1.1.4.1 $";
++static char *hysdn_procconf_revision = "$Revision$";
+
+ #define INFO_OUT_LEN 80 /* length of info line including lf */
+
+@@ -212,32 +214,29 @@
+ static ssize_t
+ hysdn_conf_read(struct file *file, char *buf, size_t count, loff_t * off)
+ {
+- loff_t pos = *off;
+ char *cp;
+ int i;
+
+ if (off != &file->f_pos) /* fs error check */
+ return -ESPIPE;
+
+- if (!(file->f_mode & FMODE_READ))
+- return -EPERM;
+-
+- if (!(cp = file->private_data))
+- return (-EFAULT); /* should never happen */
+-
+- i = strlen(cp); /* get total string length */
+-
+- if (pos != (unsigned)pos || pos >= i)
+- return 0;
+-
+- /* still bytes to transfer */
+- cp += pos; /* point to desired data offset */
+- i -= pos; /* remaining length */
+- if (i > count)
+- i = count; /* limit length to transfer */
+- if (copy_to_user(buf, cp, i))
+- return (-EFAULT); /* copy error */
+- *off = pos + i; /* adjust offset */
++ if (file->f_mode & FMODE_READ) {
++ if (!(cp = file->private_data))
++ return (-EFAULT); /* should never happen */
++ i = strlen(cp); /* get total string length */
++ if (*off < i) {
++ /* still bytes to transfer */
++ cp += *off; /* point to desired data offset */
++ i -= *off; /* remaining length */
++ if (i > count)
++ i = count; /* limit length to transfer */
++ if (copy_to_user(buf, cp, i))
++ return (-EFAULT); /* copy error */
++ *off += i; /* adjust offset */
++ } else
++ return (0);
++ } else
++ return (-EPERM); /* no permission to read */
+
+ return (i);
+ } /* hysdn_conf_read */
+@@ -254,7 +253,11 @@
+ char *cp, *tmp;
+
+ /* now search the addressed card */
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ MOD_INC_USE_COUNT;
++#else
+ lock_kernel();
++#endif
+ card = card_root;
+ while (card) {
+ pd = card->procconf;
+@@ -263,7 +266,11 @@
+ card = card->next; /* search next entry */
+ }
+ if (!card) {
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ MOD_DEC_USE_COUNT;
++#else
+ unlock_kernel();
++#endif
+ return (-ENODEV); /* device is unknown/invalid */
+ }
+ if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
+@@ -274,7 +281,11 @@
+ /* write only access -> write boot file or conf line */
+
+ if (!(cnf = kmalloc(sizeof(struct conf_writedata), GFP_KERNEL))) {
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ MOD_DEC_USE_COUNT;
++#else
+ unlock_kernel();
++#endif
+ return (-EFAULT);
+ }
+ cnf->card = card;
+@@ -286,7 +297,11 @@
+ /* read access -> output card info data */
+
+ if (!(tmp = (char *) kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) {
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ MOD_DEC_USE_COUNT;
++#else
+ unlock_kernel();
++#endif
+ return (-EFAULT); /* out of memory */
+ }
+ filep->private_data = tmp; /* start of string */
+@@ -320,10 +335,16 @@
+ *cp++ = '\n';
+ *cp = 0; /* end of string */
+ } else { /* simultaneous read/write access forbidden ! */
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ MOD_DEC_USE_COUNT;
++#else
+ unlock_kernel();
++#endif
+ return (-EPERM); /* no permission this time */
+ }
++#ifndef COMPAT_USE_MODCOUNT_LOCK
+ unlock_kernel();
++#endif
+ return (0);
+ } /* hysdn_conf_open */
+
+@@ -338,7 +359,9 @@
+ int retval = 0;
+ struct proc_dir_entry *pd;
+
++#ifndef COMPAT_USE_MODCOUNT_LOCK
+ lock_kernel();
++#endif
+ /* search the addressed card */
+ card = card_root;
+ while (card) {
+@@ -348,7 +371,9 @@
+ card = card->next; /* search next entry */
+ }
+ if (!card) {
++#ifndef COMPAT_USE_MODCOUNT_LOCK
+ unlock_kernel();
++#endif
+ return (-ENODEV); /* device is unknown/invalid */
+ }
+ if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
+@@ -371,7 +396,11 @@
+ if (filep->private_data)
+ kfree(filep->private_data); /* release memory */
+ }
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ MOD_DEC_USE_COUNT;
++#else
+ unlock_kernel();
++#endif
+ return (retval);
+ } /* hysdn_conf_close */
+
+@@ -387,6 +416,9 @@
+ release: hysdn_conf_close,
+ };
+
++#ifdef COMPAT_NO_SOFTNET
++static struct inode_operations conf_inode_operations;
++#endif
+ /*****************************/
+ /* hysdn subdir in /proc/net */
+ /*****************************/
+@@ -415,8 +447,17 @@
+ if ((card->procconf = (void *) create_proc_entry(conf_name,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ hysdn_proc_entry)) != NULL) {
++#ifdef COMPAT_NO_SOFTNET
++ memset(&conf_inode_operations, 0, sizeof(struct inode_operations));
++ conf_inode_operations.default_file_ops = &conf_fops;
++
++ ((struct proc_dir_entry *) card->procconf)->ops = &conf_inode_operations;
++#else
+ ((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops;
++#ifdef COMPAT_HAS_FILEOP_OWNER
+ ((struct proc_dir_entry *) card->procconf)->owner = THIS_MODULE;
++#endif
++#endif
+ hysdn_proclog_init(card); /* init the log file entry */
+ }
+ card = card->next; /* next entry */
+diff -rNu linux-2.4.29.old/drivers/isdn/hysdn/hysdn_proclog.c linux-2.4.29/drivers/isdn/hysdn/hysdn_proclog.c
+--- linux-2.4.29.old/drivers/isdn/hysdn/hysdn_proclog.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hysdn/hysdn_proclog.c 2005-03-22 15:06:48.613702376 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hysdn_proclog.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Linux driver for HYSDN cards, /proc/net filesystem log functions.
+ *
+@@ -16,7 +16,9 @@
+ #include <linux/poll.h>
+ #include <linux/proc_fs.h>
+ #include <linux/pci.h>
++#ifndef COMPAT_USE_MODCOUNT_LOCK
+ #include <linux/smp_lock.h>
++#endif
+
+ #include "hysdn_defs.h"
+
+@@ -115,8 +117,7 @@
+ strcpy(ib->log_start, cp); /* set output string */
+ ib->next = NULL;
+ ib->proc_ctrl = pd; /* point to own control structure */
+- save_flags(flags);
+- cli();
++ HYSDN_SPIN_LOCK(&card->irq_lock, flags);
+ ib->usage_cnt = pd->if_used;
+ if (!pd->log_head)
+ pd->log_head = ib; /* new head */
+@@ -124,7 +125,7 @@
+ pd->log_tail->next = ib; /* follows existing messages */
+ pd->log_tail = ib; /* new tail */
+ i = pd->del_lock++; /* get lock state */
+- restore_flags(flags);
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+
+ /* delete old entrys */
+ if (!i)
+@@ -210,7 +211,6 @@
+ word ino;
+ struct procdata *pd = NULL;
+ hysdn_card *card;
+- loff_t pos = *off;
+
+ if (!*((struct log_data **) file->private_data)) {
+ if (file->f_flags & O_NONBLOCK)
+@@ -235,11 +235,11 @@
+ return (0);
+
+ inf->usage_cnt--; /* new usage count */
+- file->private_data = &inf->next; /* next structure */
++ (struct log_data **) file->private_data = &inf->next; /* next structure */
+ if ((len = strlen(inf->log_start)) <= count) {
+ if (copy_to_user(buf, inf->log_start, len))
+ return -EFAULT;
+- *off = pos + len;
++ file->f_pos += len;
+ return (len);
+ }
+ return (0);
+@@ -255,7 +255,11 @@
+ struct procdata *pd = NULL;
+ ulong flags;
+
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ MOD_INC_USE_COUNT;
++#else
+ lock_kernel();
++#endif
+ card = card_root;
+ while (card) {
+ pd = card->proclog;
+@@ -264,7 +268,11 @@
+ card = card->next; /* search next entry */
+ }
+ if (!card) {
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ MOD_DEC_USE_COUNT;
++#else
+ unlock_kernel();
++#endif
+ return (-ENODEV); /* device is unknown/invalid */
+ }
+ filep->private_data = card; /* remember our own card */
+@@ -274,19 +282,24 @@
+ } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+
+ /* read access -> log/debug read */
+- save_flags(flags);
+- cli();
++ HYSDN_SPIN_LOCK(&card->irq_lock, flags);
+ pd->if_used++;
+ if (pd->log_head)
+- filep->private_data = &(pd->log_tail->next);
++ (struct log_data **) filep->private_data = &(pd->log_tail->next);
+ else
+- filep->private_data = &(pd->log_head);
+- restore_flags(flags);
++ (struct log_data **) filep->private_data = &(pd->log_head);
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ } else { /* simultaneous read/write access forbidden ! */
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ MOD_DEC_USE_COUNT;
++#else
+ unlock_kernel();
++#endif
+ return (-EPERM); /* no permission this time */
+ }
++#ifndef COMPAT_USE_MODCOUNT_LOCK
+ unlock_kernel();
++#endif
+ return (0);
+ } /* hysdn_log_open */
+
+@@ -306,7 +319,9 @@
+ int flags, retval = 0;
+
+
++#ifndef COMPAT_USE_MODCOUNT_LOCK
+ lock_kernel();
++#endif
+ if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+ /* write only access -> write debug level written */
+ retval = 0; /* success */
+@@ -314,8 +329,7 @@
+ /* read access -> log/debug read, mark one further file as closed */
+
+ pd = NULL;
+- save_flags(flags);
+- cli();
++ HYSDN_SPIN_LOCK(&card->irq_lock, flags);
+ inf = *((struct log_data **) filep->private_data); /* get first log entry */
+ if (inf)
+ pd = (struct procdata *) inf->proc_ctrl; /* still entries there */
+@@ -338,7 +352,7 @@
+ inf->usage_cnt--; /* decrement usage count for buffers */
+ inf = inf->next;
+ }
+- restore_flags(flags);
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+
+ if (pd)
+ if (pd->if_used <= 0) /* delete buffers if last file closed */
+@@ -348,7 +362,11 @@
+ kfree(inf);
+ }
+ } /* read access */
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ MOD_DEC_USE_COUNT;
++#else
+ unlock_kernel();
++#endif
+
+ return (retval);
+ } /* hysdn_log_close */
+@@ -400,6 +418,9 @@
+ release: hysdn_log_close,
+ };
+
++#ifdef COMPAT_NO_SOFTNET
++struct inode_operations log_inode_operations;
++#endif
+
+ /***********************************************************************************/
+ /* hysdn_proclog_init is called when the module is loaded after creating the cards */
+@@ -414,10 +435,20 @@
+
+ if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
+ memset(pd, 0, sizeof(struct procdata));
++#ifdef COMPAT_NO_SOFTNET
++ memset(&log_inode_operations, 0, sizeof(struct inode_operations));
++ log_inode_operations.default_file_ops = &log_fops;
++#endif
+ sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
+ if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) {
++#ifdef COMPAT_NO_SOFTNET
++ pd->log->ops = &log_inode_operations; /* set new operations table */
++#else
+ pd->log->proc_fops = &log_fops;
++#ifdef COMPAT_HAS_FILEOP_OWNER
+ pd->log->owner = THIS_MODULE;
++#endif
++#endif
+ }
+
+ init_waitqueue_head(&(pd->rd_queue));
+diff -rNu linux-2.4.29.old/drivers/isdn/hysdn/hysdn_sched.c linux-2.4.29/drivers/isdn/hysdn/hysdn_sched.c
+--- linux-2.4.29.old/drivers/isdn/hysdn/hysdn_sched.c 2005-03-22 14:47:57.000000000 +0100
++++ linux-2.4.29/drivers/isdn/hysdn/hysdn_sched.c 2005-03-22 15:06:48.630699792 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hysdn_sched.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id: hysdn_sched.c,v 1.9 2001/09/24 13:23:03 kai Exp $
+ *
+ * Linux driver for HYSDN cards
+ * scheduler routines for handling exchange card <-> pc.
+@@ -12,11 +12,9 @@
+ */
+
+ #include <linux/config.h>
+-#include <linux/sched.h>
+ #include <linux/signal.h>
+ #include <linux/kernel.h>
+ #include <linux/ioport.h>
+-#include <linux/interrupt.h>
+ #include <asm/io.h>
+
+ #include "hysdn_defs.h"
+@@ -151,22 +149,19 @@
+
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1);
+-
+- save_flags(flags);
+- cli();
++ HYSDN_SPIN_LOCK(&card->irq_lock, flags);
+ while (card->async_busy) {
+- sti();
+-
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg delayed");
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
+ if (!--cnt) {
+- restore_flags(flags);
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ return (-ERR_ASYNC_TIME); /* timed out */
+ }
+- cli();
++ HYSDN_SPIN_LOCK(&card->irq_lock, flags);
+ } /* wait for buffer to become free */
+
+ strcpy(card->async_data, line);
+@@ -177,31 +172,26 @@
+ /* now queue the task */
+ queue_task(&card->irq_queue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+- sti();
+-
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg data queued");
+
+ cnt++; /* short delay */
+- cli();
+-
++ HYSDN_SPIN_LOCK(&card->irq_lock, flags);
+ while (card->async_busy) {
+- sti();
+-
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg waiting for tx-ready");
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout((20 * HZ) / 1000); /* Timeout 20ms */
+ if (!--cnt) {
+- restore_flags(flags);
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ return (-ERR_ASYNC_TIME); /* timed out */
+ }
+- cli();
++ HYSDN_SPIN_LOCK(&card->irq_lock, flags);
+ } /* wait for buffer to become free again */
+-
+- restore_flags(flags);
+-
++ HYSDN_SPIN_UNLOCK(&card->irq_lock, flags);
+ if (card->debug_flags & LOG_SCHED_ASYN)
+ hysdn_addlog(card, "async tx-cfg data send");
+
+diff -rNu linux-2.4.29.old/drivers/isdn/icn/icn.c linux-2.4.29/drivers/isdn/icn/icn.c
+--- linux-2.4.29.old/drivers/isdn/icn/icn.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/icn/icn.c 2005-03-22 15:06:48.722685808 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: icn.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * ISDN low-level module for the ICN active ISDN-Card.
+ *
+@@ -41,7 +41,7 @@
+ #undef MAP_DEBUG
+
+ static char
+-*revision = "$Revision: 1.1.4.1 $";
++*revision = "$Revision$";
+
+ static int icn_addcard(int, char *, char *);
+
+@@ -1634,6 +1634,7 @@
+ }
+
+ #ifndef MODULE
++#ifdef COMPAT_HAS_NEW_SETUP
+ static int __init
+ icn_setup(char *line)
+ {
+@@ -1643,6 +1644,14 @@
+ static char sid2[20];
+
+ str = get_options(line, 2, ints);
++#else
++void
++icn_setup(char *str, int *ints)
++{
++ char *p;
++ static char sid[20];
++ static char sid2[20];
++#endif
+ if (ints[0])
+ portbase = ints[1];
+ if (ints[0] > 1)
+@@ -1656,9 +1665,13 @@
+ icn_id2 = sid2;
+ }
+ }
++#ifdef COMPAT_HAS_NEW_SETUP
+ return(1);
+ }
+ __setup("icn=", icn_setup);
++#else
++}
++#endif
+ #endif /* MODULE */
+
+ static int __init icn_init(void)
+diff -rNu linux-2.4.29.old/drivers/isdn/icn/icn.h linux-2.4.29/drivers/isdn/icn/icn.h
+--- linux-2.4.29.old/drivers/isdn/icn/icn.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/icn/icn.h 2005-03-22 15:06:48.752681248 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: icn.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * ISDN lowlevel-module for the ICN active ISDN-Card.
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_audio.c linux-2.4.29/drivers/isdn/isdn_audio.c
+--- linux-2.4.29.old/drivers/isdn/isdn_audio.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_audio.c 2005-03-22 15:06:44.306357192 +0100
+@@ -1,9 +1,9 @@
+-/* $Id: isdn_audio.c,v 1.1.4.1 2001/11/20 14:19:33 kai Exp $
++/* $Id: isdn_audio.c,v 1.24 2002/08/13 09:57:26 keil Exp $
+ *
+ * Linux ISDN subsystem, audio conversion and compression (linklevel).
+ *
+ * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
+- * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at)
++ * DTMF code (c) 1996 by Christian Mock (cm@tahina.priv.at)
+ * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de)
+ *
+ * This software may be used and distributed according to the terms
+@@ -15,7 +15,7 @@
+ #include "isdn_audio.h"
+ #include "isdn_common.h"
+
+-char *isdn_audio_revision = "$Revision: 1.1.4.1 $";
++char *isdn_audio_revision = "$Revision: 1.24 $";
+
+ /*
+ * Misc. lookup-tables.
+@@ -169,19 +169,39 @@
+ 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a
+ };
+
+-#define NCOEFF 8 /* number of frequencies to be analyzed */
+-#define DTMF_TRESH 4000 /* above this is dtmf */
++#define NCOEFF 16 /* number of frequencies to be analyzed */
++#define DTMF_TRESH 25000 /* above this is dtmf */
+ #define SILENCE_TRESH 200 /* below this is silence */
++#define H2_TRESH 20000 /* 2nd harmonic */
+ #define AMP_BITS 9 /* bits per sample, reduced to avoid overflow */
+ #define LOGRP 0
+ #define HIGRP 1
+
++typedef struct {
++ int grp; /* low/high group */
++ int k; /* k */
++ int k2; /* k fuer 2. harmonic */
++} dtmf_t;
++
+ /* For DTMF recognition:
+ * 2 * cos(2 * PI * k / N) precalculated for all k
+ */
+ static int cos2pik[NCOEFF] =
+ {
+- 55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332
++ 55812, 29528, 53603, 24032, 51193, 14443, 48590, 6517,
++ 38113, -21204, 33057, -32186, 25889, -45081, 18332, -55279
++};
++
++static dtmf_t dtmf_tones[8] =
++{
++ {LOGRP, 0, 1}, /* 697 Hz */
++ {LOGRP, 2, 3}, /* 770 Hz */
++ {LOGRP, 4, 5}, /* 852 Hz */
++ {LOGRP, 6, 7}, /* 941 Hz */
++ {HIGRP, 8, 9}, /* 1209 Hz */
++ {HIGRP, 10, 11}, /* 1336 Hz */
++ {HIGRP, 12, 13}, /* 1477 Hz */
++ {HIGRP, 14, 15} /* 1633 Hz */
+ };
+
+ static char dtmf_matrix[4][4] =
+@@ -208,7 +228,7 @@
+ : "memory", "ax");
+ #else
+ while (n--)
+- *buff = table[*(unsigned char *)buff], buff++;
++ *buff++ = table[*(unsigned char *)buff];
+ #endif
+ }
+
+@@ -479,18 +499,6 @@
+ sk2 = sk1;
+ sk1 = sk;
+ }
+- /* Avoid overflows */
+- sk >>= 1;
+- sk2 >>= 1;
+- /* compute |X(k)|**2 */
+- /* report overflows. This should not happen. */
+- /* Comment this out if desired */
+- if (sk < -32768 || sk > 32767)
+- printk(KERN_DEBUG
+- "isdn_audio: dtmf goertzel overflow, sk=%d\n", sk);
+- if (sk2 < -32768 || sk2 > 32767)
+- printk(KERN_DEBUG
+- "isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2);
+ result[k] =
+ ((sk * sk) >> AMP_BITS) -
+ ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) +
+@@ -514,58 +522,28 @@
+ int grp[2];
+ char what;
+ char *p;
+- int thresh;
+
+ while ((skb = skb_dequeue(&info->dtmf_queue))) {
+ result = (int *) skb->data;
+ s = info->dtmf_state;
+- grp[LOGRP] = grp[HIGRP] = -1;
++ grp[LOGRP] = grp[HIGRP] = -2;
+ silence = 0;
+- thresh = 0;
+- for (i = 0; i < NCOEFF; i++) {
+- if (result[i] > DTMF_TRESH) {
+- if (result[i] > thresh)
+- thresh = result[i];
+- }
+- else if (result[i] < SILENCE_TRESH)
++ for (i = 0; i < 8; i++) {
++ if ((result[dtmf_tones[i].k] > DTMF_TRESH) &&
++ (result[dtmf_tones[i].k2] < H2_TRESH))
++ grp[dtmf_tones[i].grp] = (grp[dtmf_tones[i].grp] == -2) ? i : -1;
++ else if ((result[dtmf_tones[i].k] < SILENCE_TRESH) &&
++ (result[dtmf_tones[i].k2] < SILENCE_TRESH))
+ silence++;
+ }
+- if (silence == NCOEFF)
++ if (silence == 8)
+ what = ' ';
+ else {
+- if (thresh > 0) {
+- thresh = thresh >> 4; /* touchtones must match within 12 dB */
+- for (i = 0; i < NCOEFF; i++) {
+- if (result[i] < thresh)
+- continue; /* ignore */
+- /* good level found. This is allowed only one time per group */
+- if (i < NCOEFF / 2) {
+- /* lowgroup*/
+- if (grp[LOGRP] >= 0) {
+- // Bad. Another tone found. */
+- grp[LOGRP] = -1;
+- break;
+- }
+- else
+- grp[LOGRP] = i;
+- }
+- else { /* higroup */
+- if (grp[HIGRP] >= 0) { // Bad. Another tone found. */
+- grp[HIGRP] = -1;
+- break;
+- }
+- else
+- grp[HIGRP] = i - NCOEFF/2;
+- }
+- }
+- if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
+- what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]];
+- if (s->last != ' ' && s->last != '.')
+- s->last = what; /* min. 1 non-DTMF between DTMF */
+- } else
+- what = '.';
+- }
+- else
++ if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) {
++ what = dtmf_matrix[grp[LOGRP]][grp[HIGRP] - 4];
++ if (s->last != ' ' && s->last != '.')
++ s->last = what; /* min. 1 non-DTMF between DTMF */
++ } else
+ what = '.';
+ }
+ if ((what != s->last) && (what != ' ') && (what != '.')) {
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_audio.h linux-2.4.29/drivers/isdn/isdn_audio.h
+--- linux-2.4.29.old/drivers/isdn/isdn_audio.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_audio.h 2005-03-22 15:06:44.321354912 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_audio.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_audio.h,v 1.10 2001/09/24 13:22:42 kai Exp $
+ *
+ * Linux ISDN subsystem, audio conversion and compression (linklevel).
+ *
+@@ -20,7 +20,6 @@
+
+ typedef struct dtmf_state {
+ char last;
+- char llast;
+ int idx;
+ int buf[DTMF_NPOINTS];
+ } dtmf_state;
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_bsdcomp.c linux-2.4.29/drivers/isdn/isdn_bsdcomp.c
+--- linux-2.4.29.old/drivers/isdn/isdn_bsdcomp.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_bsdcomp.c 2005-03-22 15:06:44.339352176 +0100
+@@ -105,6 +105,14 @@
+
+ #define DEBUG 1
+
++#ifdef CONFIG_ISDN_WITH_ABC
++#define BSD_C_MALLOC(x) kmalloc((x),GFP_ATOMIC)
++#define BSD_C_FREE(x) kfree(x)
++#else
++#define BSD_C_MALLOC(x) vmalloc(x)
++#define BSD_C_FREE(x) vfree(x)
++#endif
++
+ /*
+ * A dictionary for doing BSD compress.
+ */
+@@ -285,7 +293,7 @@
+ * Release the dictionary
+ */
+ if (db->dict) {
+- vfree (db->dict);
++ BSD_C_FREE (db->dict);
+ db->dict = NULL;
+ }
+
+@@ -293,7 +301,7 @@
+ * Release the string buffer
+ */
+ if (db->lens) {
+- vfree (db->lens);
++ BSD_C_FREE (db->lens);
+ db->lens = NULL;
+ }
+
+@@ -350,14 +358,19 @@
+ * Allocate space for the dictionary. This may be more than one page in
+ * length.
+ */
+- db->dict = (struct bsd_dict *) vmalloc (hsize * sizeof (struct bsd_dict));
++ db->dict = (struct bsd_dict *) BSD_C_MALLOC (hsize * sizeof (struct bsd_dict));
++
++ MOD_INC_USE_COUNT;
++ /*
++ ** MOD_INC_USE_COUNT must be before bsd_free
++ ** bsd_free make MOD_DEC_USE_COUNT if db != NULL
++ */
++
+ if (!db->dict) {
+ bsd_free (db);
+ return NULL;
+ }
+
+- MOD_INC_USE_COUNT;
+-
+ /*
+ * If this is the compression buffer then there is no length data.
+ * For decompression, the length information is needed as well.
+@@ -365,7 +378,7 @@
+ if (!decomp)
+ db->lens = NULL;
+ else {
+- db->lens = (unsigned short *) vmalloc ((maxmaxcode + 1) *
++ db->lens = (unsigned short *) BSD_C_MALLOC ((maxmaxcode + 1) *
+ sizeof (db->lens[0]));
+ if (!db->lens) {
+ bsd_free (db); /* calls MOD_DEC_USE_COUNT; */
+@@ -478,7 +491,11 @@
+ int hval,disp,ilen,mxcode;
+ unsigned char *rptr = skb_in->data;
+ int isize = skb_in->len;
++#ifdef CONFIG_ISDN_WITH_ABC
++ long secure = 0;
++#endif
+
++#ifndef CONFIG_ISDN_WITH_ABC
+ #define OUTPUT(ent) \
+ { \
+ bitno -= n_bits; \
+@@ -490,17 +507,45 @@
+ bitno += 8; \
+ } while (bitno <= 24); \
+ }
++#else
++#define OUTPUT(ent) \
++ { \
++ secure = 0; \
++ bitno -= n_bits; \
++ accm |= ((ent) << bitno); \
++ do { \
++ if(skb_out && skb_tailroom(skb_out) > 0) \
++ *(skb_put(skb_out,1)) = (unsigned char) (accm>>24); \
++ accm <<= 8; \
++ bitno += 8; \
++ } while (bitno <= 24 && ++secure < 10000); \
++ if(secure >= 10000) { \
++ printk(KERN_DEBUG "BSD in OUTPUT secure counter reached\n"); \
++ return 0; \
++ } \
++ }
++#endif
+
+ /*
+ * If the protocol is not in the range we're interested in,
+ * just return without compressing the packet. If it is,
+ * the protocol becomes the first byte to compress.
+ */
++#ifdef CONFIG_ISDN_WITH_ABC
++ ent = proto;
++
++ if (proto < 0x21 || proto > 0xf9 || !(proto & 0x1) ) {
++
++ printk(KERN_DEBUG "bsd_compress called with %x\n",proto);
++ return 0;
++ }
++#else
+ printk(KERN_DEBUG "bsd_compress called with %x\n",proto);
+
+ ent = proto;
+ if (proto < 0x21 || proto > 0xf9 || !(proto & 0x1) )
+ return 0;
++#endif
+
+ db = (struct bsd_db *) state;
+ hshift = db->hshift;
+@@ -538,6 +583,9 @@
+
+ /* continue probing until a match or invalid entry */
+ disp = (hval == 0) ? 1 : hval;
++#ifdef CONFIG_ISDN_WITH_ABC
++ secure = 0;
++#endif
+
+ do {
+ hval += disp;
+@@ -546,7 +594,15 @@
+ dictp = dict_ptr (db, hval);
+ if (dictp->codem1 >= max_ent)
+ goto nomatch;
++#ifndef CONFIG_ISDN_WITH_ABC
+ } while (dictp->fcode != fcode);
++#else
++ } while (dictp->fcode != fcode && ++secure < 100000);
++ if(secure >= 100000) {
++ printk(KERN_DEBUG "BSD: compress while dictp->fcode != fcode secure-counter reached\n");
++ return 0;
++ }
++#endif
+
+ ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */
+ continue;
+@@ -669,6 +725,9 @@
+ int ilen;
+ int codelen;
+ int extra;
++#ifdef CONFIG_ISDN_WITH_ABC
++ unsigned long secure = 0;
++#endif
+
+ db = (struct bsd_db *) state;
+ max_ent = db->max_ent;
+@@ -677,7 +736,9 @@
+ n_bits = db->n_bits;
+ tgtbitno = 32 - n_bits; /* bitno when we have a code */
+
++#ifndef CONFIG_ISDN_WITH_ABC
+ printk(KERN_DEBUG "bsd_decompress called\n");
++#endif
+
+ if(!skb_in || !skb_out) {
+ printk(KERN_ERR "bsd_decompress called with NULL parameter\n");
+@@ -795,7 +856,11 @@
+
+ p = skb_put(skb_out,codelen);
+ p += codelen;
++#ifdef CONFIG_ISDN_WITH_ABC
++ for(secure = 0; finchar > LAST && secure < 50000;secure++) {
++#else
+ while (finchar > LAST) {
++#endif
+ struct bsd_dict *dictp2 = dict_ptr (db, finchar);
+
+ dictp = dict_ptr (db, dictp2->cptr);
+@@ -822,6 +887,12 @@
+ }
+ }
+ *--p = finchar;
++#ifdef CONFIG_ISDN_WITH_ABC
++ if(secure >= 50000) {
++ printk(KERN_DEBUG "BSD: decompress secure-counter reached\n");
++ return DECOMP_FATALERROR;
++ }
++#endif
+
+ #ifdef DEBUG
+ if (--codelen != 0)
+@@ -851,12 +922,23 @@
+ /* look for a free hash table entry */
+ if (dictp->codem1 < max_ent) {
+ disp = (hval == 0) ? 1 : hval;
++#ifdef CONFIG_ISDN_WITH_ABC
++ secure = 0;
++#endif
+ do {
+ hval += disp;
+ if (hval >= db->hsize)
+ hval -= db->hsize;
+ dictp = dict_ptr (db, hval);
++#ifndef CONFIG_ISDN_WITH_ABC
+ } while (dictp->codem1 < max_ent);
++#else
++ } while (dictp->codem1 < max_ent && ++secure < 50000);
++ if(secure >= 50000) {
++ printk(KERN_DEBUG "BSD: decomp while (dictp->codem1 < max_ent) secure-counter reached\n");
++ return DECOMP_FATALERROR;
++ }
++#endif
+ }
+
+ /*
+@@ -895,11 +977,21 @@
+ db->comp_bytes += skb_in->len - BSD_OVHD;
+ db->uncomp_bytes += skb_out->len;
+
++#ifdef CONFIG_ISDN_WITH_ABC
++ /*
++ ** bsd_check will call bsd_clear
++ ** and so on the internal tables will be cleared.
++ **
++ ** I think that's not what we will at this point ?????
++ ** For me at works without bsd_check.
++ */
++#else
+ if (bsd_check(db)) {
+ if (db->debug)
+ printk(KERN_DEBUG "bsd_decomp%d: peer should have cleared dictionary on %d\n",
+ db->unit, db->seqno - 1);
+ }
++#endif
+ return skb_out->len;
+ }
+
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_common.c linux-2.4.29/drivers/isdn/isdn_common.c
+--- linux-2.4.29.old/drivers/isdn/isdn_common.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_common.c 2005-03-22 15:06:44.359349136 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_common.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_common.c,v 1.137 2002/02/09 21:19:11 keil Exp $
+ *
+ * Linux ISDN subsystem, common used functions (linklevel).
+ *
+@@ -19,6 +19,7 @@
+ #include <linux/vmalloc.h>
+ #include <linux/isdn.h>
+ #include <linux/smp_lock.h>
++#include <linux/list.h>
+ #include "isdn_common.h"
+ #include "isdn_tty.h"
+ #include "isdn_net.h"
+@@ -33,7 +34,9 @@
+ #include <linux/isdn_divertif.h>
+ #endif /* CONFIG_ISDN_DIVERSION */
+ #include "isdn_v110.h"
++#ifdef HAVE_DEVFS_FS
+ #include <linux/devfs_fs_kernel.h>
++#endif /* HAVE_DEVFS_FS */
+
+ /* Debugflags */
+ #undef ISDN_DEBUG_STATCALLB
+@@ -44,7 +47,7 @@
+
+ isdn_dev *dev;
+
+-static char *isdn_revision = "$Revision: 1.1.4.1 $";
++static char *isdn_revision = "$Revision: 1.137 $";
+
+ extern char *isdn_net_revision;
+ extern char *isdn_tty_revision;
+@@ -67,19 +70,19 @@
+
+ static int isdn_writebuf_stub(int, int, const u_char *, int, int);
+ static void set_global_features(void);
++#ifdef HAVE_DEVFS_FS
+ static void isdn_register_devfs(int);
+ static void isdn_unregister_devfs(int);
++#endif /* HAVE_DEVFS_FS */
+ static int isdn_wildmat(char *s, char *p);
+
+ void
+ isdn_lock_drivers(void)
+ {
+ int i;
+- isdn_ctrl cmd;
+
+- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
+- if (!dev->drv[i])
+- continue;
++ for (i = 0; i < dev->drivers; i++) {
++ isdn_ctrl cmd;
+
+ cmd.driver = i;
+ cmd.arg = 0;
+@@ -101,10 +104,7 @@
+ {
+ int i;
+
+- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
+- if (!dev->drv[i])
+- continue;
+-
++ for (i = 0; i < dev->drivers; i++)
+ if (dev->drv[i]->locks > 0) {
+ isdn_ctrl cmd;
+
+@@ -114,7 +114,6 @@
+ isdn_command(&cmd);
+ dev->drv[i]->locks--;
+ }
+- }
+ }
+
+ void
+@@ -473,6 +472,7 @@
+ dev->drv[di]->flags &= ~DRV_FLAG_RUNNING;
+ break;
+ case ISDN_STAT_ICALL:
++ case ISDN_STAT_ICALLW:
+ if (i < 0)
+ return -1;
+ #ifdef ISDN_DEBUG_STATCALLB
+@@ -718,7 +718,9 @@
+ dev->drvmap[i] = -1;
+ dev->chanmap[i] = -1;
+ dev->usage[i] &= ~ISDN_USAGE_DISABLED;
++#ifdef HAVE_DEVFS_FS
+ isdn_unregister_devfs(i);
++#endif /* HAVE_DEVFS_FS */
+ }
+ dev->drivers--;
+ dev->channels -= dev->drv[di]->channels;
+@@ -755,6 +757,10 @@
+ if (divert_if)
+ return(divert_if->stat_callback(c));
+ #endif /* CONFIG_ISDN_DIVERSION */
++ case ISDN_STAT_ALERT:
++ case ISDN_STAT_PROCEED:
++ isdn_tty_stat_callback(i, c);
++ break;
+ default:
+ return -1;
+ }
+@@ -900,72 +906,239 @@
+ return (dev->chanmap[minor]);
+ }
+
+-static char *
+-isdn_statstr(void)
++// ----------------------------------------------------------------------
++// /dev/isdninfo
++//
++// This device has somewhat insane semantics, but we need to support
++// them for the sake of compatibility.
++//
++// After opening, the first read will succeed and return the current state
++// Then, unless O_NONBLOCK is set, it will block until a state change happens
++// and then return the new state.
++// Also, if the buffer size for the read is too small, we'll just return
++// EOF
++
++struct isdnstatus_dev {
++ struct list_head list;
++ int update;
++};
++
++static DECLARE_WAIT_QUEUE_HEAD(isdnstatus_waitq);
++static LIST_HEAD(isdnstatus_devs);
++static spinlock_t isdnstatus_devs_lock = SPIN_LOCK_UNLOCKED;
++
++void
++isdn_info_update(void)
++{
++ struct list_head *p;
++ struct isdnstatus_dev *idev;
++
++ spin_lock(&isdnstatus_devs_lock);
++ list_for_each(p, &isdnstatus_devs) {
++ idev = list_entry(p, struct isdnstatus_dev, list);
++ idev->update = 1;
++ }
++ spin_unlock(&isdnstatus_devs_lock);
++ wake_up_interruptible(&isdnstatus_waitq);
++}
++
++static int
++isdnstatus_open(struct inode *ino, struct file *filep)
++{
++ struct isdnstatus_dev *p;
++
++ p = kmalloc(sizeof(struct isdnstatus_dev), GFP_USER);
++ if (!p)
++ return -ENOMEM;
++
++ /* At opening time we allow a single update */
++ p->update = 1;
++ spin_lock(&isdnstatus_devs_lock);
++ list_add(&p->list, &isdnstatus_devs);
++ spin_unlock(&isdnstatus_devs_lock);
++ filep->private_data = p;
++
++ return 0;
++}
++
++static void
++isdnstatus_close(struct inode *ino, struct file *filep)
++{
++ struct isdnstatus_dev *p = filep->private_data;
++
++ spin_lock(&isdnstatus_devs_lock);
++ list_del(&p->list);
++ spin_unlock(&isdnstatus_devs_lock);
++ kfree(p);
++}
++
++// FIXME we don't lock against the state changing whilst being
++// printed
++
++void
++isdn_statstr(char *buf)
+ {
+- static char istatbuf[2048];
+ char *p;
+ int i;
+
+- sprintf(istatbuf, "idmap:\t");
+- p = istatbuf + strlen(istatbuf);
++ p = buf;
++ p += sprintf(p, "idmap:\t");
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+- sprintf(p, "%s ", (dev->drvmap[i] < 0) ? "-" : dev->drvid[dev->drvmap[i]]);
+- p = istatbuf + strlen(istatbuf);
++ p += sprintf(p, "%s ", (dev->drvmap[i] < 0) ? "-" : dev->drvid[dev->drvmap[i]]);
+ }
+- sprintf(p, "\nchmap:\t");
+- p = istatbuf + strlen(istatbuf);
++ p += sprintf(p, "\nchmap:\t");
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+- sprintf(p, "%d ", dev->chanmap[i]);
+- p = istatbuf + strlen(istatbuf);
++ p += sprintf(p, "%d ", dev->chanmap[i]);
+ }
+- sprintf(p, "\ndrmap:\t");
+- p = istatbuf + strlen(istatbuf);
++ p += sprintf(p, "\ndrmap:\t");
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+- sprintf(p, "%d ", dev->drvmap[i]);
+- p = istatbuf + strlen(istatbuf);
++ p += sprintf(p, "%d ", dev->drvmap[i]);
+ }
+- sprintf(p, "\nusage:\t");
+- p = istatbuf + strlen(istatbuf);
++ p += sprintf(p, "\nusage:\t");
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+- sprintf(p, "%d ", dev->usage[i]);
+- p = istatbuf + strlen(istatbuf);
++ p += sprintf(p, "%d ", dev->usage[i]);
+ }
+- sprintf(p, "\nflags:\t");
+- p = istatbuf + strlen(istatbuf);
++ p += sprintf(p, "\nflags:\t");
+ for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
+ if (dev->drv[i]) {
+- sprintf(p, "%ld ", dev->drv[i]->online);
+- p = istatbuf + strlen(istatbuf);
++ p += sprintf(p, "%ld ", dev->drv[i]->online);
+ } else {
+- sprintf(p, "? ");
+- p = istatbuf + strlen(istatbuf);
++ p += sprintf(p, "? ");
+ }
+ }
+- sprintf(p, "\nphone:\t");
+- p = istatbuf + strlen(istatbuf);
++ p += sprintf(p, "\nphone:\t");
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+- sprintf(p, "%s ", dev->num[i]);
+- p = istatbuf + strlen(istatbuf);
++ p += sprintf(p, "%s ", dev->num[i]);
+ }
+- sprintf(p, "\n");
+- return istatbuf;
++ p += sprintf(p, "\n");
+ }
+
+-/* Module interface-code */
++static ssize_t
++isdnstatus_read(struct file *file, char *buf, size_t count, loff_t * off)
++{
++ static DECLARE_MUTEX(istatbuf_mutex);
++ static char istatbuf[2048];
+
+-void
+-isdn_info_update(void)
++ DECLARE_WAITQUEUE(wait, current);
++ struct isdnstatus_dev *idev;
++ int retval = 0;
++ unsigned int len;
++
++ idev = file->private_data;
++
++ if (off != &file->f_pos)
++ return -ESPIPE;
++
++ add_wait_queue(&isdnstatus_waitq, &wait);
++ for (;;) {
++ set_current_state(TASK_INTERRUPTIBLE);
++
++ if (idev->update)
++ break;
++
++ retval = -EAGAIN;
++ if (file->f_flags & O_NONBLOCK)
++ break;
++
++ retval = -ERESTARTSYS;
++ if (signal_pending(current))
++ break;
++
++ schedule();
++ }
++ __set_current_state(TASK_RUNNING);
++ remove_wait_queue(&isdnstatus_waitq, &wait);
++
++ if (!idev->update)
++ goto out;
++
++ idev->update = 0;
++ down(&istatbuf_mutex);
++ isdn_statstr(istatbuf);
++ len = strlen(istatbuf);
++ if (len > count) {
++ retval = 0;
++ goto out_unlock;
++ }
++ if (copy_to_user(buf, istatbuf, len)) {
++ retval = -EFAULT;
++ goto out_unlock;
++ }
++ *off += len;
++ retval = len;
++
++ out_unlock:
++ up(&istatbuf_mutex);
++ out:
++ return retval;
++}
++
++static ssize_t
++isdnstatus_write(struct file *file, const char *buf, size_t count, loff_t * off)
+ {
+- infostruct *p = dev->infochain;
++ return -EINVAL;
++}
++
++static unsigned int
++isdnstatus_poll(struct file *file, poll_table * wait)
++{
++ struct isdnstatus_dev *idev;
++ unsigned int mask = 0;
++
++ idev = file->private_data;
+
+- while (p) {
+- *(p->private) = 1;
+- p = (infostruct *) p->next;
++ poll_wait(file, &isdnstatus_waitq, wait);
++ if (idev->update) {
++ mask |= POLLIN | POLLRDNORM;
+ }
+- wake_up_interruptible(&(dev->info_waitq));
++ return mask;
+ }
+
++static int
++isdnstatus_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
++{
++ int retval;
++ isdn_net_ioctl_phone phone;
++
++ switch (cmd) {
++ case IIOCGETDVR:
++ return (TTY_DV +
++ (NET_DV << 8) +
++ (INF_DV << 16));
++ case IIOCGETCPS:
++ if (arg) {
++ ulong *p = (ulong *) arg;
++ int i;
++ if ((retval = verify_area(VERIFY_WRITE, (void *) arg,
++ sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
++ return retval;
++ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
++ put_user(dev->ibytes[i], p++);
++ put_user(dev->obytes[i], p++);
++ }
++ return 0;
++ } else
++ return -EINVAL;
++ break;
++#ifdef CONFIG_NETDEVICES
++ case IIOCNETGPN:
++ /* Get peer phone number of a connected
++ * isdn network interface */
++ if (arg) {
++ if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
++ return -EFAULT;
++ return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
++ } else
++ return -EINVAL;
++#endif
++ default:
++ return -EINVAL;
++ }
++}
++
++// ----------------------------------------------------------------------
++
++
+ static ssize_t
+ isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
+ {
+@@ -976,37 +1149,16 @@
+ int chidx;
+ int retval;
+ char *p;
+- loff_t pos = *off;
+
+ if (off != &file->f_pos)
+ return -ESPIPE;
+
+- if (pos != (unsigned) pos)
+- return -EINVAL;
+-
++#ifndef COMPAT_HAVE_READ_LOCK_KERNEL
+ lock_kernel();
+- if (minor == ISDN_MINOR_STATUS) {
+- if (!file->private_data) {
+- if (file->f_flags & O_NONBLOCK) {
+- retval = -EAGAIN;
+- goto out;
+- }
+- interruptible_sleep_on(&(dev->info_waitq));
+- }
+- p = isdn_statstr();
+- file->private_data = 0;
+- if ((len = strlen(p)) <= count) {
+- if (copy_to_user(buf, p, len)) {
+- retval = -EFAULT;
+- goto out;
+- }
+- *off = pos + len;
+- retval = len;
+- goto out;
+- }
+- retval = 0;
+- goto out;
+- }
++#endif
++ if (minor == ISDN_MINOR_STATUS)
++ return isdnstatus_read(file, buf, count, off);
++
+ if (!dev->drivers) {
+ retval = -ENODEV;
+ goto out;
+@@ -1031,7 +1183,7 @@
+ cli();
+ len = isdn_readbchan(drvidx, chidx, p, 0, count,
+ &dev->drv[drvidx]->rcv_waitq[chidx]);
+- *off = pos + len;
++ *off += len;
+ restore_flags(flags);
+ if (copy_to_user(buf,p,len))
+ len = -EFAULT;
+@@ -1052,6 +1204,9 @@
+ }
+ interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
+ }
++#ifdef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++ if(drvidx || (len = isdn_dw_abc_lcr_readstat(buf,count)) < 1) {
++#endif
+ if (dev->drv[drvidx]->interface->readstat) {
+ if (count > dev->drv[drvidx]->stavail)
+ count = dev->drv[drvidx]->stavail;
+@@ -1061,6 +1216,9 @@
+ } else {
+ len = 0;
+ }
++#ifdef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++ }
++#endif
+ save_flags(flags);
+ cli();
+ if (len)
+@@ -1068,7 +1226,7 @@
+ else
+ dev->drv[drvidx]->stavail = 0;
+ restore_flags(flags);
+- *off = pos + len;
++ *off += len;
+ retval = len;
+ goto out;
+ }
+@@ -1080,7 +1238,9 @@
+ #endif
+ retval = -ENODEV;
+ out:
++#ifndef COMPAT_HAVE_READ_LOCK_KERNEL
+ unlock_kernel();
++#endif
+ return retval;
+ }
+
+@@ -1092,15 +1252,18 @@
+ int chidx;
+ int retval;
+
++ if (minor == ISDN_MINOR_STATUS)
++ return isdnstatus_write(file, buf, count, off);
++
+ if (off != &file->f_pos)
+ return -ESPIPE;
+
+- if (minor == ISDN_MINOR_STATUS)
+- return -EPERM;
+ if (!dev->drivers)
+ return -ENODEV;
+
++#ifndef COMPAT_HAVE_WRITE_LOCK_KERNEL
+ lock_kernel();
++#endif
+ if (minor <= ISDN_MINOR_BMAX) {
+ printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
+ drvidx = isdn_minor2drv(minor);
+@@ -1145,7 +1308,9 @@
+ #endif
+ retval = -ENODEV;
+ out:
++#ifndef COMPAT_HAVE_WRITE_LOCK_KERNEL
+ unlock_kernel();
++#endif
+ return retval;
+ }
+
+@@ -1156,15 +1321,12 @@
+ unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+
++#ifndef COMPAT_HAVE_POLL_LOCK_KERNEL
+ lock_kernel();
+- if (minor == ISDN_MINOR_STATUS) {
+- poll_wait(file, &(dev->info_waitq), wait);
+- /* mask = POLLOUT | POLLWRNORM; */
+- if (file->private_data) {
+- mask |= POLLIN | POLLRDNORM;
+- }
+- goto out;
+- }
++#endif
++ if (minor == ISDN_MINOR_STATUS)
++ return isdnstatus_poll(file, wait);
++
+ if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
+ if (drvidx < 0) {
+ /* driver deregistered while file open */
+@@ -1186,7 +1348,9 @@
+ #endif
+ mask = POLLERR;
+ out:
++#ifndef COMPAT_HAVE_POLL_LOCK_KERNEL
+ unlock_kernel();
++#endif
+ return mask;
+ }
+
+@@ -1216,42 +1380,9 @@
+ #define phone iocpar.phone
+ #define cfg iocpar.cfg
+
+- if (minor == ISDN_MINOR_STATUS) {
+- switch (cmd) {
+- case IIOCGETDVR:
+- return (TTY_DV +
+- (NET_DV << 8) +
+- (INF_DV << 16));
+- case IIOCGETCPS:
+- if (arg) {
+- ulong *p = (ulong *) arg;
+- int i;
+- if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+- sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
+- return ret;
+- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+- put_user(dev->ibytes[i], p++);
+- put_user(dev->obytes[i], p++);
+- }
+- return 0;
+- } else
+- return -EINVAL;
+- break;
+-#ifdef CONFIG_NETDEVICES
+- case IIOCNETGPN:
+- /* Get peer phone number of a connected
+- * isdn network interface */
+- if (arg) {
+- if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+- return -EFAULT;
+- return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
+- } else
+- return -EINVAL;
+-#endif
+- default:
+- return -EINVAL;
+- }
+- }
++ if (minor == ISDN_MINOR_STATUS)
++ return isdnstatus_ioctl(inode, file, cmd, arg);
++
+ if (!dev->drivers)
+ return -ENODEV;
+ if (minor <= ISDN_MINOR_BMAX) {
+@@ -1273,11 +1404,34 @@
+ */
+ switch (cmd) {
+ case IIOCNETDWRSET:
++#ifdef CONFIG_ISDN_WITH_ABC
++ if (arg) {
++
++ if (copy_from_user(name, (char *) arg, sizeof(name))) {
++
++ return(-EFAULT);
++
++ } else {
++
++ isdn_net_dev *p = isdn_net_findif(name);
++
++ if(p == NULL)
++ return(-EINVAL);
++
++ return(isdn_dw_abc_reset_interface(p->local,1));
++ }
++ }
++#else
+ printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
++#endif
+ return(-EINVAL);
+ case IIOCNETLCR:
++#ifdef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++ return(isdn_dw_abc_lcr_ioctl(arg));
++#else
+ printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
+ return -ENODEV;
++#endif
+ #ifdef CONFIG_NETDEVICES
+ case IIOCNETAIF:
+ /* Add a network-interface */
+@@ -1650,22 +1804,12 @@
+ int chidx;
+ int retval = -ENODEV;
+
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ MOD_INC_USE_COUNT;
++#endif
+
+ if (minor == ISDN_MINOR_STATUS) {
+- infostruct *p;
+-
+- if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) {
+- p->next = (char *) dev->infochain;
+- p->private = (char *) &(filep->private_data);
+- dev->infochain = p;
+- /* At opening we allow a single update */
+- filep->private_data = (char *) 1;
+- retval = 0;
+- goto out;
+- } else {
+- retval = -ENOMEM;
+- goto out;
+- }
++ return isdnstatus_open(ino, filep);
+ }
+ if (!dev->channels)
+ goto out;
+@@ -1688,6 +1832,9 @@
+ if (drvidx < 0)
+ goto out;
+ isdn_lock_drivers();
++#ifdef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++ if(!drvidx) isdn_dw_abc_lcr_open();
++#endif
+ retval = 0;
+ goto out;
+ }
+@@ -1700,6 +1847,10 @@
+ }
+ #endif
+ out:
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ if (retval)
++ MOD_DEC_USE_COUNT;
++#endif
+ return retval;
+ }
+
+@@ -1708,25 +1859,11 @@
+ {
+ uint minor = MINOR(ino->i_rdev);
+
++#ifndef COMPAT_USE_MODCOUNT_LOCK
+ lock_kernel();
++#endif
+ if (minor == ISDN_MINOR_STATUS) {
+- infostruct *p = dev->infochain;
+- infostruct *q = NULL;
+-
+- while (p) {
+- if (p->private == (char *) &(filep->private_data)) {
+- if (q)
+- q->next = p->next;
+- else
+- dev->infochain = (infostruct *) (p->next);
+- kfree(p);
+- goto out;
+- }
+- q = p;
+- p = (infostruct *) (p->next);
+- }
+- printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
+- goto out;
++ isdnstatus_close(ino, filep);
+ }
+ isdn_unlock_drivers();
+ if (minor <= ISDN_MINOR_BMAX)
+@@ -1734,6 +1871,12 @@
+ if (minor <= ISDN_MINOR_CTRLMAX) {
+ if (dev->profd == current)
+ dev->profd = NULL;
++#ifdef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++ {
++ int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
++ if(!drvidx) isdn_dw_abc_lcr_close();
++ }
++#endif
+ goto out;
+ }
+ #ifdef CONFIG_ISDN_PPP
+@@ -1742,13 +1885,19 @@
+ #endif
+
+ out:
++#ifdef COMPAT_USE_MODCOUNT_LOCK
++ MOD_DEC_USE_COUNT;
++#else
+ unlock_kernel();
++#endif
+ return 0;
+ }
+
+ static struct file_operations isdn_fops =
+ {
++#ifdef COMPAT_HAS_FILEOP_OWNER
+ owner: THIS_MODULE,
++#endif
+ llseek: no_llseek,
+ read: isdn_read,
+ write: isdn_write,
+@@ -1801,6 +1950,15 @@
+ if (USG_NONE(dev->usage[i]) &&
+ (dev->drvmap[i] != -1)) {
+ int d = dev->drvmap[i];
++#ifdef CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
++ if(jiffies < dev->dwabc_chan_external_inuse[i]) {
++
++ if((dev->dwabc_chan_external_inuse[i] - jiffies) > (HZ * 120))
++ dev->dwabc_chan_external_inuse[i] = 0;
++ else
++ continue;
++ }
++#endif
+ if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) &&
+ ((pre_dev != d) || (pre_chan != dev->chanmap[i])))
+ continue;
+@@ -1819,7 +1977,11 @@
+ restore_flags(flags);
+ return i;
+ } else {
++#ifdef CONFIG_ISDN_WITH_ABC
++ if ((pre_dev == d) && ((pre_chan == dev->chanmap[i]) || pre_chan > 1000)) {
++#else
+ if ((pre_dev == d) && (pre_chan == dev->chanmap[i])) {
++#endif
+ dev->usage[i] &= ISDN_USAGE_EXCLUSIVE;
+ dev->usage[i] |= usage;
+ isdn_info_update();
+@@ -2006,7 +2168,7 @@
+
+ if ((adding) && (d->rcverr))
+ kfree(d->rcverr);
+- if (!(d->rcverr = kmalloc(sizeof(int) * m, GFP_KERNEL))) {
++ if (!(d->rcverr = (int *) kmalloc(sizeof(int) * m, GFP_KERNEL))) {
+ printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n");
+ return -1;
+ }
+@@ -2014,7 +2176,7 @@
+
+ if ((adding) && (d->rcvcount))
+ kfree(d->rcvcount);
+- if (!(d->rcvcount = kmalloc(sizeof(int) * m, GFP_KERNEL))) {
++ if (!(d->rcvcount = (int *) kmalloc(sizeof(int) * m, GFP_KERNEL))) {
+ printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n");
+ if (!adding) kfree(d->rcverr);
+ return -1;
+@@ -2026,7 +2188,8 @@
+ skb_queue_purge(&d->rpqueue[j]);
+ kfree(d->rpqueue);
+ }
+- if (!(d->rpqueue = kmalloc(sizeof(struct sk_buff_head) * m, GFP_KERNEL))) {
++ if (!(d->rpqueue =
++ (struct sk_buff_head *) kmalloc(sizeof(struct sk_buff_head) * m, GFP_KERNEL))) {
+ printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
+ if (!adding) {
+ kfree(d->rcvcount);
+@@ -2040,7 +2203,8 @@
+
+ if ((adding) && (d->rcv_waitq))
+ kfree(d->rcv_waitq);
+- d->rcv_waitq = kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL);
++ d->rcv_waitq = (wait_queue_head_t *)
++ kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL);
+ if (!d->rcv_waitq) {
+ printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
+ if (!adding) {
+@@ -2064,7 +2228,9 @@
+ if (dev->chanmap[k] < 0) {
+ dev->chanmap[k] = j;
+ dev->drvmap[k] = drvidx;
++#ifdef HAVE_DEVFS_FS
+ isdn_register_devfs(k);
++#endif /* HAVE_DEVFS_FS */
+ break;
+ }
+ restore_flags(flags);
+@@ -2128,6 +2294,7 @@
+ i_div->ll_cmd = isdn_command; /* set command function */
+ i_div->drv_to_name = map_drvname;
+ i_div->name_to_drv = map_namedrv;
++ i_div->dial_net_name = isdn_net_force_dial;
+ MOD_INC_USE_COUNT;
+ divert_if = i_div; /* remember interface */
+ return(DIVERT_NO_ERR);
+@@ -2165,7 +2332,7 @@
+ printk(KERN_WARNING "register_isdn: No write routine given.\n");
+ return 0;
+ }
+- if (!(d = kmalloc(sizeof(driver), GFP_KERNEL))) {
++ if (!(d = (driver *) kmalloc(sizeof(driver), GFP_KERNEL))) {
+ printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n");
+ return 0;
+ }
+@@ -2225,6 +2392,7 @@
+ return rev;
+ }
+
++#ifdef HAVE_DEVFS_FS
+ #ifdef CONFIG_DEVFS_FS
+
+ static devfs_handle_t devfs_handle;
+@@ -2314,6 +2482,7 @@
+ }
+
+ #endif /* CONFIG_DEVFS_FS */
++#endif /* HAVE_DEVFS_FS */
+
+ /*
+ * Allocate and initialize all data, register modem-devices
+@@ -2331,7 +2500,6 @@
+ init_timer(&dev->timer);
+ dev->timer.function = isdn_timer_funct;
+ init_MUTEX(&dev->sem);
+- init_waitqueue_head(&dev->info_waitq);
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ dev->drvmap[i] = -1;
+ dev->chanmap[i] = -1;
+@@ -2345,7 +2513,9 @@
+ vfree(dev);
+ return -EIO;
+ }
++#ifdef HAVE_DEVFS_FS
+ isdn_init_devfs();
++#endif /* HAVE_DEVFS_FS */
+ if ((i = isdn_tty_modem_init()) < 0) {
+ printk(KERN_WARNING "isdn: Could not register tty devices\n");
+ if (i == -3)
+@@ -2353,7 +2523,9 @@
+ if (i <= -2)
+ tty_unregister_driver(&dev->mdm.tty_modem);
+ vfree(dev);
++#ifdef HAVE_DEVFS_FS
+ isdn_cleanup_devfs();
++#endif /* HAVE_DEVFS_FS */
+ devfs_unregister_chrdev(ISDN_MAJOR, "isdn");
+ return -EIO;
+ }
+@@ -2364,7 +2536,9 @@
+ tty_unregister_driver(&dev->mdm.cua_modem);
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+ kfree(dev->mdm.info[i].xmit_buf - 4);
++#ifdef HAVE_DEVFS_FS
+ isdn_cleanup_devfs();
++#endif /* HAVE_DEVFS_FS */
+ devfs_unregister_chrdev(ISDN_MAJOR, "isdn");
+ vfree(dev);
+ return -EIO;
+@@ -2390,6 +2564,9 @@
+ printk("\n");
+ #endif
+ isdn_info_update();
++#ifdef CONFIG_ISDN_WITH_ABC
++ isdn_dw_abc_init_func();
++#endif
+ return 0;
+ }
+
+@@ -2398,7 +2575,7 @@
+ */
+ static void __exit isdn_exit(void)
+ {
+- unsigned long flags;
++ int flags;
+ int i;
+
+ #ifdef CONFIG_ISDN_PPP
+@@ -2432,13 +2609,18 @@
+ printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
+ restore_flags(flags);
+ } else {
++#ifdef HAVE_DEVFS_FS
+ isdn_cleanup_devfs();
++#endif /* HAVE_DEVFS_FS */
+ del_timer(&dev->timer);
+ restore_flags(flags);
+ /* call vfree with interrupts enabled, else it will hang */
+ vfree(dev);
+ printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
+ }
++#ifdef CONFIG_ISDN_WITH_ABC
++ isdn_dw_abc_release_func();
++#endif
+ }
+
+ module_init(isdn_init);
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_common.h linux-2.4.29/drivers/isdn/isdn_common.h
+--- linux-2.4.29.old/drivers/isdn/isdn_common.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_common.h 2005-03-22 15:06:44.374346856 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_common.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_common.h,v 1.22 2001/09/24 13:22:42 kai Exp $
+ *
+ * header for Linux ISDN subsystem
+ * common used functions and debugging-switches (linklevel).
+@@ -24,6 +24,9 @@
+ #undef ISDN_DEBUG_NET_DIAL
+ #undef ISDN_DEBUG_NET_ICALL
+
++#ifdef CONFIG_ISDN_WITH_ABC
++int isdn_net_force_dial_lp(isdn_net_local *);
++#endif
+ /* Prototypes */
+ extern void isdn_MOD_INC_USE_COUNT(void);
+ extern void isdn_MOD_DEC_USE_COUNT(void);
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_concap.c linux-2.4.29/drivers/isdn/isdn_concap.c
+--- linux-2.4.29.old/drivers/isdn/isdn_concap.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_concap.c 2005-03-22 15:06:44.389344576 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_concap.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_concap.c,v 1.9 2001/09/24 13:22:42 kai Exp $
+ *
+ * Linux ISDN subsystem, protocol encapsulation
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_concap.h linux-2.4.29/drivers/isdn/isdn_concap.h
+--- linux-2.4.29.old/drivers/isdn/isdn_concap.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_concap.h 2005-03-22 15:06:44.405342144 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_concap.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_concap.h,v 1.4 2001/09/24 13:22:42 kai Exp $
+ *
+ * Linux ISDN subsystem, protocol encapsulation
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_dwabc.c linux-2.4.29/drivers/isdn/isdn_dwabc.c
+--- linux-2.4.29.old/drivers/isdn/isdn_dwabc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_dwabc.c 2005-03-22 15:06:44.421339712 +0100
+@@ -0,0 +1,1053 @@
++
++/* $Id: isdn_dwabc.c,v 1.27 2001/12/01 23:18:21 detabc Exp $
++
++ * Linux ISDN subsystem, abc-extension releated funktions.
++ *
++ * Copyright by abc GmbH
++ * written by Detlef Wengorz <detlefw@isdn4linux.de>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2, or (at your option)
++ * any later version.
++ *
++ */
++
++#include <linux/config.h>
++#define __NO_VERSION__
++
++#ifdef CONFIG_ISDN_WITH_ABC
++
++static char *dwabcrevison = "$Revision: 1.27 $";
++
++#include <asm/semaphore.h>
++#define CONFIG_ISDN_WITH_ABC_NEED_DWSJIFFIES 1
++#include <linux/list.h>
++#include <linux/isdn.h>
++#include "isdn_common.h"
++#include "isdn_net.h"
++
++#include <linux/skbuff.h>
++
++#include <net/udp.h>
++#include <net/checksum.h>
++#include <linux/isdn_dwabc.h>
++
++
++#if CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS && CONFIG_ISDN_PPP
++#include <linux/isdn_ppp.h>
++extern struct isdn_ppp_compressor *isdn_ippp_comp_head;
++#define ipc_head isdn_ippp_comp_head
++#ifndef CI_BSD_COMPRESS
++#define CI_BSD_COMPRESS 21
++#endif
++#endif
++
++#define NBYTEORDER_30BYTES 0x1e00
++#define DWABC_TMRES (HZ / 10)
++
++#define VERBLEVEL (dev->net_verbose > 2)
++
++static struct timer_list dw_abc_timer;
++
++
++#ifdef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++static ISDN_DWSPINLOCK lcr_spin = ISDN_DWSPIN_UNLOCKED;
++#define LCR_LOCK() isdn_dwspin_trylock(&lcr_spin)
++#define LCR_ULOCK() isdn_dwspin_unlock(&lcr_spin)
++
++typedef struct ISDN_DW_ABC_LCR {
++
++ struct list_head dll;
++ char lcr_printbuf[64 + ISDN_MSNLEN + ISDN_MSNLEN];
++ char *lcr_poin;
++ char *lcr_epoin;
++
++} ISDN_DW_ABC_LCR;
++
++static LIST_HEAD(lcr_dll);
++static atomic_t lcr_open_count = ATOMIC_INIT(0);
++static volatile ulong lcr_call_counter = 0;
++
++
++static int myjiftime(char *p,u_long nj)
++{
++ sprintf(p,"%02ld:%02ld.%02ld",
++ ((nj / 100) / 60) % 100, (nj / 100) % 60,nj % 100);
++
++ return(8);
++}
++
++
++static void dw_lcr_clear_all(void)
++{
++ struct list_head *lh;
++
++ if(!LCR_LOCK()) {
++
++ while((lh = lcr_dll.next) != &lcr_dll) {
++
++ ISDN_DW_ABC_LCR *p = list_entry(lh,ISDN_DW_ABC_LCR,dll);
++ list_del(&p->dll);
++ kfree(p);
++ }
++
++ LCR_ULOCK();
++ }
++}
++
++void isdn_dw_abc_lcr_open(void)
++{ atomic_inc(&lcr_open_count); }
++
++void isdn_dw_abc_lcr_close(void)
++{
++ if(atomic_dec_and_test(&lcr_open_count))
++ dw_lcr_clear_all();
++}
++
++int isdn_dw_abc_lcr_lock(void)
++{ return(LCR_LOCK()); }
++
++void isdn_dw_abc_lcr_ulock(void)
++{ LCR_ULOCK(); }
++
++
++size_t isdn_dw_abc_lcr_readstat(char *buf,size_t count)
++{
++ size_t retw = 0;
++
++ while(buf != NULL && count > 0) {
++
++ struct list_head *lh = NULL;
++ ISDN_DW_ABC_LCR *p = NULL;
++ char *dp = NULL;
++ size_t n;
++
++ if((n = LCR_LOCK())) {
++
++ if(!retw)
++ retw = n;
++
++ break;
++ }
++
++
++ while((lh = lcr_dll.next) != &lcr_dll) {
++
++ p = list_entry(lh,ISDN_DW_ABC_LCR,dll);
++
++ if(p->lcr_poin >= p->lcr_epoin) {
++
++ list_del(&p->dll);
++ kfree(p);
++ p = NULL;
++
++ } else break;
++ }
++
++ if(p == NULL) {
++
++ LCR_ULOCK();
++ break;
++ }
++
++ n = p->lcr_epoin - p->lcr_poin;
++
++ if(n > count)
++ n = count;
++
++ dp = p->lcr_poin;
++ p->lcr_poin += n;
++ retw += n;
++ LCR_ULOCK();
++ copy_to_user(buf,dp,n);
++ buf += n;
++ }
++
++ return(retw);
++}
++
++
++static void isdn_dw_abc_lcr_clear_helper(isdn_net_local *lp)
++{
++ if(lp != NULL) {
++
++ void *a,*b;
++
++ a = lp->dw_abc_lcr_cmd;
++ b = lp->dw_abc_lcr_io;
++ lp->dw_abc_lcr_io = NULL;
++ lp->dw_abc_lcr_cmd = NULL;
++ lp->dw_abc_lcr_callid =
++ lp->dw_abc_lcr_start_request =
++ lp->dw_abc_lcr_end_request = 0;
++
++ if(a) kfree(a);
++ if(b) kfree(b);
++ }
++}
++
++void isdn_dw_abc_lcr_clear(isdn_net_local *lp)
++{
++ if(!LCR_LOCK()) {
++ isdn_dw_abc_lcr_clear_helper(lp);
++ LCR_ULOCK();
++ }
++}
++
++
++u_long isdn_dw_abc_lcr_call_number( isdn_net_local *lp,isdn_ctrl *call_cmd)
++{
++ u_long mid = 0;
++
++ if(LCR_LOCK())
++ return(0);
++
++ isdn_dw_abc_lcr_clear_helper(lp);
++
++ if( atomic_read(&lcr_open_count) > 0 &&
++ lp != NULL &&
++ call_cmd != NULL) {
++
++ ISDN_DW_ABC_LCR *lc = NULL;
++ int ab = 0;
++
++ if((lp->dw_abc_lcr_cmd =
++ ( isdn_ctrl *)kmalloc(sizeof(isdn_ctrl),GFP_ATOMIC)) == NULL) {
++
++no_mem_out:;
++ isdn_dw_abc_lcr_clear_helper(lp);
++ LCR_ULOCK();
++ printk(KERN_DEBUG "%s %d : LCR no memory\n",__FILE__,__LINE__);
++ return(0);
++ }
++
++ memcpy(lp->dw_abc_lcr_cmd,call_cmd,sizeof(*call_cmd));
++ while(!(lp->dw_abc_lcr_callid = mid = lcr_call_counter++));
++
++ lp->dw_abc_lcr_end_request = lp->dw_abc_lcr_start_request = jiffies;
++ lp->dw_abc_lcr_end_request += HZ * 3;
++
++ if((lc = (ISDN_DW_ABC_LCR *)kmalloc(sizeof(*lc),GFP_KERNEL)) == NULL)
++ goto no_mem_out;
++
++ lc->lcr_poin = lc->lcr_epoin = lc->lcr_printbuf;
++ lc->lcr_epoin += myjiftime(lc->lcr_epoin,jiffies);
++
++ sprintf(lc->lcr_epoin," DW_ABC_LCR\t%lu\t%.*s\t%.*s\n",
++ mid,
++ (int)ISDN_MSNLEN,
++ call_cmd->parm.setup.eazmsn,
++ (int)ISDN_MSNLEN,
++ call_cmd->parm.setup.phone);
++
++ lc->lcr_epoin += strlen(lc->lcr_epoin);
++ ab = lc->lcr_epoin - lc->lcr_poin;
++
++ list_add_tail(&lc->dll,&lcr_dll);
++ LCR_ULOCK();
++
++ if(ab > 0) {
++
++ if(dev->drv[0] != NULL ) {
++
++ dev->drv[0]->stavail += ab;
++ wake_up_interruptible(&dev->drv[0]->st_waitq);
++ }
++ }
++
++ } else LCR_ULOCK();
++
++ return(mid);
++}
++
++
++int isdn_dw_abc_lcr_ioctl(u_long arg)
++{
++ struct ISDN_DWABC_LCR_IOCTL i;
++ int need = sizeof(struct ISDN_DWABC_LCR_IOCTL);
++ isdn_net_dev *p;
++
++ memset(&i,0,sizeof(struct ISDN_DWABC_LCR_IOCTL));
++ copy_from_user(&i,(char *)arg,sizeof(int));
++
++ if(i.lcr_ioctl_sizeof < need)
++ need = i.lcr_ioctl_sizeof;
++
++ if(need > 0)
++ copy_from_user(&i,(char *)arg,need);
++
++ if(LCR_LOCK())
++ return(-EAGAIN);
++
++ p = dev->netdev;
++
++ for(;p ; p = p->next) {
++
++ isdn_net_local *lp = p->local;
++
++ if( lp->dw_abc_lcr_callid != i.lcr_ioctl_callid)
++ continue;
++
++ if(lp->dw_abc_lcr_cmd == NULL)
++ continue;
++
++ if(lp->dw_abc_lcr_io == NULL)
++ lp->dw_abc_lcr_io = (struct ISDN_DWABC_LCR_IOCTL *)
++ kmalloc(sizeof(struct ISDN_DWABC_LCR_IOCTL),GFP_ATOMIC);
++
++ if(lp->dw_abc_lcr_io == NULL) {
++
++ printk(KERN_DEBUG "%s %d : no memory\n",__FILE__,__LINE__);
++ continue;
++ }
++
++ memcpy(lp->dw_abc_lcr_io,&i,sizeof(struct ISDN_DWABC_LCR_IOCTL));
++
++ if(i.lcr_ioctl_flags & DWABC_LCR_FLG_NEWNUMBER) {
++
++ char *xx = i.lcr_ioctl_nr;
++ char *exx = xx + sizeof(i.lcr_ioctl_nr);
++ char *d = lp->dw_abc_lcr_cmd->parm.setup.phone;
++ char *ed = d + sizeof(lp->dw_abc_lcr_cmd->parm.setup.phone) - 1;
++
++ while(d < ed && xx < exx && *xx) *(d++) = *(xx++);
++ while(d < ed) *(d++) = 0;
++ *d = 0;
++ }
++ }
++
++ LCR_ULOCK();
++ return(0);
++}
++
++#endif
++
++
++#ifdef CONFIG_ISDN_WITH_ABC_UDP_CHECK
++int dw_abc_udp_test(struct sk_buff *skb,struct net_device *ndev)
++{
++ if(ndev != NULL && skb != NULL && skb->protocol == htons(ETH_P_IP)) {
++
++ struct iphdr *iph = (struct iphdr *)skb->data;
++ isdn_net_local *lp = (isdn_net_local *) ndev->priv;
++ int rklen = skb->len;
++
++ if (skb->nh.raw > skb->data && skb->nh.raw < skb->tail) {
++
++ rklen -= (char *)skb->nh.raw - (char *)skb->data;
++ iph = (struct iphdr *)skb->nh.raw;
++ }
++
++ if(rklen >= 20 && iph->version == 4 &&
++ !(lp->dw_abc_flags & ISDN_DW_ABC_FLAG_NO_UDP_CHECK)) {
++
++ if( iph->tot_len == NBYTEORDER_30BYTES &&
++ iph->protocol == IPPROTO_UDP) {
++
++ struct udphdr *udp =
++ (struct udphdr *)((char *)iph + (iph->ihl << 2));
++
++ ushort usrc = ntohs(udp->source);
++
++ if( udp->dest == htons(25001) &&
++ usrc >= 20000 && usrc < 25000) {
++
++ char *p = (char *)(udp + 1);
++
++ if(p[0] == p[1]) {
++
++ char mc = 0;
++
++ switch(*p) {
++ case 0x30:
++
++ mc = *p;
++
++ if((lp->flags & ISDN_NET_CONNECTED) && (!lp->dialstate))
++ mc++;
++
++ break;
++
++ case 0x32:
++
++ mc = *p;
++#ifdef CONFIG_ISDN_WITH_ABC_UDP_CHECK_DIAL
++ if((lp->flags & ISDN_NET_CONNECTED) && (!lp->dialstate)) {
++
++ mc++;
++ break;
++ }
++
++ if(!isdn_net_force_dial_lp(lp)) mc++;
++#endif
++ break;
++
++ case 0x11:
++ mc = *p + 1;
++ isdn_dw_abc_reset_interface(lp,1);
++ break;
++
++ case 0x28: mc = *p + 1; break;
++ case 0x2a:
++ case 0x2c:
++
++ mc = *p;
++#ifdef CONFIG_ISDN_WITH_ABC_UDP_CHECK_HANGUP
++ if(!(lp->dw_abc_flags & ISDN_DW_ABC_FLAG_NO_UDP_HANGUP)) {
++
++ if(lp->isdn_device >= 0) {
++
++ isdn_net_hangup(ndev);
++ mc = *p + 1;
++ }
++ }
++#endif
++ break;
++ }
++
++ if(mc) {
++
++ struct sk_buff *nskb;
++ int need = 2+sizeof(struct iphdr)+sizeof(struct udphdr);
++ int hneed = need + ndev->hard_header_len;
++
++ if((nskb = (struct sk_buff *)dev_alloc_skb(hneed)) != NULL) {
++
++ ushort n = sizeof(struct udphdr) + 2;
++ struct iphdr *niph;
++ struct udphdr *nup;
++ skb_reserve(nskb,ndev->hard_header_len);
++
++ if((niph = (struct iphdr *)skb_put(nskb,need))==NULL){
++
++ printk(KERN_DEBUG "%s: skb_put failt (%d bytes)\n", lp->name,hneed);
++ dev_kfree_skb(nskb);
++ return(0);
++ }
++
++ nup = (struct udphdr *)(niph + 1);
++ ((char *)(nup + 1))[0] = mc;
++ ((char *)(nup + 1))[1] = mc;
++ nup->source=udp->dest;
++ nup->dest=udp->source;
++ nup->len=htons(n);
++ nup->check=0; /* dont need checksum */
++ memset((void *)niph,0,sizeof(*niph));
++ niph->version=4;
++ niph->ihl=5;
++ niph->tot_len=NBYTEORDER_30BYTES;
++ niph->ttl = 32;
++ niph->protocol = IPPROTO_UDP;
++ niph->saddr=iph->daddr;
++ niph->daddr=iph->saddr;
++ niph->id=iph->id;
++ niph->check=ip_fast_csum((unsigned char *)niph,niph->ihl);
++ nskb->dev = ndev;
++ nskb->pkt_type = PACKET_HOST;
++ nskb->protocol = htons(ETH_P_IP);
++ nskb->mac.raw = nskb->data;
++ netif_rx(nskb);
++ }
++
++ return(1);
++ }
++ }
++ }
++ }
++ }
++ }
++
++ return(0);
++}
++#endif
++
++
++void isdn_dw_clear_if(ulong pm,isdn_net_local *lp)
++{
++ if(lp != NULL) {
++#ifdef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++ isdn_dw_abc_lcr_clear(lp);
++#endif
++ }
++}
++
++
++
++static void dw_abc_timer_func(u_long dont_need_yet)
++{
++ register u_long t;
++
++ if(!((t = ++isdn_dwabc_jiffies.msec_100) & 1))
++ if(isdn_dwabc_jiffies.msec_200++ & 1)
++ isdn_dwabc_jiffies.msec_400++;
++
++ if(!(t % 5))
++ if(isdn_dwabc_jiffies.msec_500++ & 1)
++ isdn_dwabc_jiffies.msec_1000++;
++
++ dw_abc_timer.expires = jiffies + DWABC_TMRES;
++ add_timer(&dw_abc_timer);
++}
++
++
++void isdn_dw_abc_init_func(void)
++{
++
++ init_timer(&dw_abc_timer);
++ dw_abc_timer.function = dw_abc_timer_func;
++
++
++ printk( KERN_INFO
++ "abc-extension %s Kernel 0x%06X\n"
++ "written by\nDetlef Wengorz <detlefw@isdn4linux.de>\n"
++ "Installed options:\n"
++#ifdef CONFIG_ISDN_WITH_ABC_CALLB
++ "CONFIG_ISDN_WITH_ABC_CALLB\n"
++#endif
++#ifdef CONFIG_ISDN_WITH_ABC_UDP_CHECK
++ "CONFIG_ISDN_WITH_ABC_UDP_CHECK\n"
++#endif
++#ifdef CONFIG_ISDN_WITH_ABC_UDP_CHECK_HANGUP
++ "CONFIG_ISDN_WITH_ABC_UDP_CHECK_HANGUP\n"
++#endif
++#ifdef CONFIG_ISDN_WITH_ABC_UDP_CHECK_DIAL
++ "CONFIG_ISDN_WITH_ABC_UDP_CHECK_DIAL\n"
++#endif
++#ifdef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++ "CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ\n"
++#endif
++#ifdef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++ "CONFIG_ISDN_WITH_ABC_LCR_SUPPORT\n"
++#endif
++#ifdef CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
++ "CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER\n"
++#endif
++#ifdef CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
++ "CONFIG_ISDN_WITH_ABC_CH_EXTINUSE\n"
++#endif
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ "CONFIG_ISDN_WITH_ABC_CONN_ERROR\n"
++#endif
++#ifdef CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS
++ "CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS\n"
++#endif
++ "loaded\n",
++ dwabcrevison,LINUX_VERSION_CODE);
++ dwsjiffies = 0;
++ dw_abc_timer.expires = jiffies + DWABC_TMRES;
++ add_timer(&dw_abc_timer);
++}
++
++void isdn_dw_abc_release_func(void)
++{
++ del_timer(&dw_abc_timer);
++#ifdef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++ dw_lcr_clear_all();
++#endif
++ printk( KERN_INFO
++ "abc-extension %s Kernel 0x%06X\n"
++ "written by\n"
++ "Detlef Wengorz <detlefw@isdn4linux.de>\n"
++ "unloaded\n",
++ dwabcrevison,LINUX_VERSION_CODE);
++}
++
++
++void isdn_dwabc_test_phone(isdn_net_local *lp)
++{
++ if(lp != NULL) {
++
++ isdn_net_phone *h = lp->phone[0];
++ ulong oflags = lp->dw_abc_flags;
++ int secure = 0;
++
++ lp->dw_abc_flags = 0;
++#ifdef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++ *lp->dw_out_msn = 0;
++#endif
++
++ for(;h != NULL && secure < 1000;secure++,h = h->next) {
++
++ char *p = h->num;
++ char *ep = p + ISDN_MSNLEN;
++
++ for(;p < ep && *p && (*p <= ' ' || *p == '"' || *p == '\'');p++);
++
++ if(p >= ep)
++ continue;
++
++#ifdef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++ if(*p == '>') {
++
++ if(++p < ep && *p != '<' && *p != '>') {
++
++ char *d = lp->dw_out_msn;
++
++ for(;*p && (p < ep) && (*p == ' ' || *p == '\t');p++);
++ for(ep--;*p && (p < ep);) *(d++) = *(p++);
++ *d = 0;
++ continue;
++ }
++ }
++#endif
++
++ if(*p == '~') {
++
++ /* abc switch's */
++
++ for(p++;p < ep && *p;p++) switch(*p) {
++ case 'u': lp->dw_abc_flags |= ISDN_DW_ABC_FLAG_NO_UDP_CHECK; break;
++ case 'h': lp->dw_abc_flags |= ISDN_DW_ABC_FLAG_NO_UDP_HANGUP; break;
++ case 'd': lp->dw_abc_flags |= ISDN_DW_ABC_FLAG_NO_UDP_DIAL; break;
++ case 'c': lp->dw_abc_flags |= ISDN_DW_ABC_FLAG_NO_CH_EXTINUSE; break;
++ case 'e': lp->dw_abc_flags |= ISDN_DW_ABC_FLAG_NO_CONN_ERROR; break;
++ case 'l': lp->dw_abc_flags |= ISDN_DW_ABC_FLAG_NO_LCR; break;
++
++ case 'x':
++ case 'X': lp->dw_abc_flags |= ISDN_DW_ABC_FLAG_RCV_NO_HUPTIMER; break;
++
++ case 'B': lp->dw_abc_flags |= ISDN_DW_ABC_FLAG_BSD_COMPRESS; break;
++ case 'L': lp->dw_abc_flags |= ISDN_DW_ABC_FLAG_LEASED_LINE; break;
++
++ case '"':
++ case ' ':
++ case '\t':
++ case '\'': break;
++
++ default:
++ printk(KERN_DEBUG"isdn_net: %s abc-switch <~%c> unknown\n",lp->name,*p);
++ break;
++ }
++ }
++ }
++
++ if(lp->dw_abc_flags & ISDN_DW_ABC_FLAG_LEASED_LINE) {
++
++ lp->dw_abc_flags |=
++ ISDN_DW_ABC_FLAG_NO_UDP_CHECK |
++ ISDN_DW_ABC_FLAG_NO_UDP_HANGUP |
++ ISDN_DW_ABC_FLAG_NO_UDP_DIAL |
++ ISDN_DW_ABC_FLAG_NO_CH_EXTINUSE |
++ ISDN_DW_ABC_FLAG_NO_CONN_ERROR |
++ ISDN_DW_ABC_FLAG_NO_LCR;
++ }
++
++ if(dev->net_verbose && (lp->dw_abc_flags != oflags || dev->net_verbose > 4))
++ printk(KERN_DEBUG "isdn_net %s abc-flags 0x%lx\n",lp->name,lp->dw_abc_flags);
++
++ }
++}
++
++
++int isdn_dw_abc_reset_interface(isdn_net_local *lp,int with_message)
++{
++ int r = -EINVAL;
++
++ if(lp != NULL) {
++
++ r = 0;
++
++ lp->dw_abc_bchan_last_connect = 0;
++ lp->dw_abc_dialstart = 0;
++ lp->dw_abc_inuse_secure = 0;
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ lp->dw_abc_bchan_errcnt = 0;
++#endif
++
++ if(with_message && dev->net_verbose > 0)
++ printk(KERN_INFO
++ "%s: NOTE: reset (clear) abc-interface-secure-counter\n",
++ lp->name);
++ }
++
++ return(r);
++}
++
++
++#if CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS && CONFIG_ISDN_PPP
++
++#define DWBSD_PKT_FIRST_LEN 16
++#define DWBSD_PKT_SWITCH 165
++#define DWBSD_PKT_BSD 189
++
++#define DWBSD_VERSION 0x2
++
++void dwabc_bsd_first_gen(isdn_net_local *lp)
++{
++ if(lp != NULL && lp->p_encap == ISDN_NET_ENCAP_RAWIP &&
++ (lp->dw_abc_flags & ISDN_DW_ABC_FLAG_BSD_COMPRESS)) {
++
++ struct sk_buff *skb = NULL;
++ char *p = NULL;
++ char *ep = NULL;
++
++ if((skb =(struct sk_buff *)dev_alloc_skb(128)) == NULL) {
++
++ printk(KERN_INFO "%s: dwabc: alloc-skb failed for 128 bytes\n",lp->name);
++ return;
++ }
++
++ skb_reserve(skb,64);
++ p = skb_put(skb,DWBSD_PKT_FIRST_LEN);
++ ep = p + DWBSD_PKT_FIRST_LEN;
++
++ *(p++) = DWBSD_PKT_SWITCH;
++ *(p++) = DWBSD_VERSION;
++ for(;p < ep;p++) *(p++) = 0;
++
++ isdn_net_write_super(lp, skb);
++
++ if(dev->net_verbose > 2)
++ printk(KERN_INFO "%s: dwabc: sending comm-header version 0x%x\n",lp->name,DWBSD_VERSION);
++ }
++}
++
++
++void dwabc_bsd_free(isdn_net_local *lp)
++{
++ if(lp != NULL) {
++
++ if(lp->dw_abc_bsd_stat_rx || lp->dw_abc_bsd_stat_tx) {
++
++ struct isdn_ppp_compressor *c = NULL;
++
++ if(!(c = (struct isdn_ppp_compressor *)lp->dw_abc_bsd_compressor)) {
++
++ printk(KERN_WARNING
++ "%s: PANIC: freeing bsd compressmemory without compressor\n",
++ lp->name);
++
++ } else {
++
++ if(lp->dw_abc_bsd_stat_rx) (*c->free)(lp->dw_abc_bsd_stat_rx);
++ if(lp->dw_abc_bsd_stat_tx) (*c->free)(lp->dw_abc_bsd_stat_tx);
++
++ if(dev->net_verbose > 2)
++ printk(KERN_INFO
++ "%s: free bsd compress-memory\n",
++ lp->name);
++ }
++ }
++
++ lp->dw_abc_bsd_compressor = NULL;
++ lp->dw_abc_bsd_stat_rx = NULL;
++ lp->dw_abc_bsd_stat_tx = NULL;
++ lp->dw_abc_if_flags &= ~ISDN_DW_ABC_IFFLAG_BSDAKTIV;
++
++ if(dev->net_verbose > 0) {
++
++ if(lp->dw_abc_bsd_rcv != lp->dw_abc_bsd_bsd_rcv) {
++
++ printk(KERN_INFO "%s: Receive %lu<-%lu kb\n",lp->name,
++ lp->dw_abc_bsd_rcv >> 10 , lp->dw_abc_bsd_bsd_rcv >> 10);
++ }
++
++
++ if(lp->dw_abc_bsd_snd != lp->dw_abc_bsd_bsd_snd) {
++
++ printk(KERN_INFO "%s: Send %lu->%lu kb\n",lp->name,
++ lp->dw_abc_bsd_snd >> 10 , lp->dw_abc_bsd_bsd_snd >> 10);
++ }
++ }
++
++ lp->dw_abc_bsd_rcv =
++ lp->dw_abc_bsd_bsd_rcv =
++ lp->dw_abc_bsd_snd =
++ lp->dw_abc_bsd_bsd_snd = 0;
++ }
++}
++
++
++int dwabc_bsd_init(isdn_net_local *lp)
++{
++ int r = 1;
++
++ if(lp != NULL) {
++
++ dwabc_bsd_free(lp);
++
++ if(lp->p_encap == ISDN_NET_ENCAP_RAWIP) {
++
++ void *rx = NULL;
++ void *tx = NULL;
++ struct isdn_ppp_comp_data *cp = NULL;
++ struct isdn_ppp_compressor *c = NULL;
++
++ if(lp->dw_abc_flags & ISDN_DW_ABC_FLAG_BSD_COMPRESS) do {
++
++ for(c = ipc_head ;
++ c != NULL && c->num != CI_BSD_COMPRESS; c = c->next);
++
++ if(c == NULL) {
++
++ printk(KERN_INFO
++ "%s: Module isdn_bsdcompress not loaded\n",
++ lp->name);
++
++ break;
++ }
++
++ cp = (struct isdn_ppp_comp_data *)
++ kmalloc(sizeof(struct isdn_ppp_comp_data),GFP_ATOMIC);
++
++ if(cp == NULL) {
++
++ printk(KERN_INFO
++ "%s: allocation of isdn_ppp_comp_data failed\n",
++ lp->name);
++
++ break;
++ }
++
++ memset(cp,0,sizeof(*cp));
++ cp->num = CI_BSD_COMPRESS;
++ cp->optlen = 1;
++
++ /*
++ ** set BSD_VERSION 1 and 12 bits compressmode
++ */
++ *cp->options = (1 << 5) | 12;
++
++ if((rx = (*c->alloc)(cp)) == NULL) {
++
++ printk(KERN_INFO
++ "%s: allocation of bsd rx-memory failed\n",
++ lp->name);
++
++ break;
++ }
++
++ if(!(*c->init)(rx,cp,0,1)) {
++
++ printk(KERN_INFO
++ "%s: init of bsd rx-stream failed\n",lp->name);
++
++ break;
++ }
++
++ cp->flags = IPPP_COMP_FLAG_XMIT;
++
++ if((tx = (*c->alloc)(cp)) == NULL) {
++
++ printk(KERN_INFO
++ "%s: allocation of bsd tx-memory failed\n",
++ lp->name);
++
++ break;
++ }
++
++ if(!(*c->init)(tx,cp,0,1)) {
++
++ printk(KERN_INFO
++ "%s: init of bsd tx-stream failed\n",
++ lp->name);
++
++ break;
++ }
++
++ lp->dw_abc_bsd_compressor = (void *)c;
++ lp->dw_abc_bsd_stat_rx = rx;
++ lp->dw_abc_bsd_stat_tx = tx;
++ rx = tx = NULL;
++ r = 0;
++
++ if(dev->net_verbose > 2)
++ printk(KERN_INFO
++ "%s: bsd compress-memory and init ok\n",
++ lp->name);
++
++ } while(0);
++
++ if(cp != NULL)
++ kfree(cp);
++
++ if(c != NULL) {
++
++ if(tx != NULL) (*c->free)(tx);
++ if(rx != NULL) (*c->free)(rx);
++ }
++
++ } else if(lp->dw_abc_flags & ISDN_DW_ABC_FLAG_BSD_COMPRESS) {
++
++ printk(KERN_INFO
++ "%s: bsd-compress only with encapsulation rawip allowed\n",
++ lp->name);
++ }
++ }
++
++ return(r);
++}
++
++struct sk_buff *dwabc_bsd_compress( isdn_net_local *lp,
++ struct sk_buff *skb,
++ struct net_device *ndev)
++{
++ if(lp != NULL && lp->p_encap == ISDN_NET_ENCAP_RAWIP &&
++ (lp->dw_abc_flags & ISDN_DW_ABC_FLAG_BSD_COMPRESS) &&
++ (lp->dw_abc_if_flags & ISDN_DW_ABC_IFFLAG_BSDAKTIV)) {
++
++ if(lp->dw_abc_bsd_stat_tx != NULL && lp->dw_abc_bsd_compressor) {
++
++ struct isdn_ppp_compressor *cp =
++ (struct isdn_ppp_compressor *)lp->dw_abc_bsd_compressor;
++
++ struct sk_buff *nskb = (struct sk_buff *)
++ dev_alloc_skb(skb->len * 2 + ndev->hard_header_len);
++
++ int l = 0;
++
++ if(nskb == NULL) {
++
++ (void)(*cp->reset)(lp->dw_abc_bsd_stat_tx,0,0,NULL,0,NULL);
++ printk(KERN_INFO "%s: dwabc-compress no memory\n",lp->name);
++
++ } else {
++
++ skb_reserve(nskb,ndev->hard_header_len);
++ *(unsigned char *)skb_put(nskb,1) = DWBSD_PKT_BSD;
++ l = (*cp->compress)(lp->dw_abc_bsd_stat_tx,skb,nskb,0x21);
++
++ if(l < 1 || l > skb->len) {
++
++ (void)(*cp->reset)(lp->dw_abc_bsd_stat_tx,0,0,NULL,0,NULL);
++ dev_kfree_skb(nskb);
++
++ } else {
++
++ u_short sqnr;
++
++ dev_kfree_skb(skb);
++ skb = nskb;
++ sqnr = ((*(u_char *)skb->data) << 8) +
++ ((u_char)skb->data[1]);
++
++ if(sqnr > 65500)
++ (void)(*cp->reset)
++ (lp->dw_abc_bsd_stat_tx,0,0,NULL,0,NULL);
++ }
++ }
++ }
++ }
++
++ return(skb);
++}
++
++struct sk_buff *dwabc_bsd_rx_pkt( isdn_net_local *lp,
++ struct sk_buff *skb,
++ struct net_device *ndev)
++{
++ struct sk_buff *r = skb;
++
++ if(lp != NULL && lp->p_encap == ISDN_NET_ENCAP_RAWIP &&
++ (lp->dw_abc_flags & ISDN_DW_ABC_FLAG_BSD_COMPRESS)) {
++
++ unsigned char *p = (unsigned char *)skb->data;
++ struct isdn_ppp_compressor *cp =
++ (struct isdn_ppp_compressor *)lp->dw_abc_bsd_compressor;
++
++ if(*p == DWBSD_PKT_SWITCH) {
++
++ if(skb->len == DWBSD_PKT_FIRST_LEN) {
++
++ if((lp->dw_abc_remote_version = p[1]) < 0x2) {
++
++ printk(KERN_INFO
++ "%s: I can't really talk with remote version 0x%x\n"
++ "Please upgrade remote or disable rawip-compression\n",
++ lp->name,
++ p[1]);
++ }
++
++ lp->dw_abc_if_flags |= ISDN_DW_ABC_IFFLAG_BSDAKTIV;
++ dev_kfree_skb(skb);
++
++ if(cp && lp->dw_abc_bsd_stat_tx)
++ (void)(*cp->reset)(lp->dw_abc_bsd_stat_tx,0,0,NULL,0,NULL);
++
++ if(dev->net_verbose > 2)
++ printk(KERN_INFO
++ "%s: receive comm-header rem-version 0x%02x\n",
++ lp->name,
++ lp->dw_abc_remote_version);
++
++ return(NULL);
++ }
++
++ } else if(*p == DWBSD_PKT_BSD && lp->dw_abc_bsd_stat_rx != NULL && cp) {
++
++ struct sk_buff *nskb = NULL;
++
++ if(test_and_set_bit(ISDN_DW_ABC_BITLOCK_RECEIVE,
++ &lp->dw_abc_bitlocks)) {
++
++ printk(KERN_INFO "%s: bsd-decomp called recursivly\n",lp->name);
++ dev_kfree_skb(skb);
++ dwabc_bsd_first_gen(lp);
++ return(NULL);
++ }
++
++ nskb = (struct sk_buff *)
++ dev_alloc_skb(2048 + ndev->hard_header_len);
++
++ if(nskb != NULL) {
++
++ int l = 0;
++ u_short sqnr;
++
++ skb_reserve(nskb,ndev->hard_header_len);
++ skb_pull(skb, 1);
++ sqnr = ((*(u_char *)skb->data) << 8) | ((u_char)skb->data[1]);
++
++ if(!sqnr && cp && lp->dw_abc_bsd_stat_rx)
++ (void)(*cp->reset)(lp->dw_abc_bsd_stat_rx,0,0,NULL,0,NULL);
++
++ if((l = (*cp->decompress)
++ (lp->dw_abc_bsd_stat_rx,skb,nskb,NULL)) < 1 || l>8000) {
++
++ printk(KERN_INFO "%s: abc-decomp failed\n",lp->name);
++ dev_kfree_skb(nskb);
++ dev_kfree_skb(skb);
++ nskb = NULL;
++ dwabc_bsd_first_gen(lp);
++
++ } else {
++
++ if (nskb->data[0] & 0x1)
++ skb_pull(nskb, 1); /* protocol ID is only 8 bit */
++ else
++ skb_pull(nskb, 2);
++
++ nskb->dev = skb->dev;
++ nskb->pkt_type = skb->pkt_type;
++ nskb->mac.raw = nskb->data;
++ dev_kfree_skb(skb);
++ }
++
++ } else {
++
++ printk(KERN_INFO "%s: PANIC abc-decomp no memory\n",lp->name);
++ dev_kfree_skb(skb);
++ dwabc_bsd_first_gen(lp);
++ }
++
++ clear_bit(ISDN_DW_ABC_BITLOCK_RECEIVE,&lp->dw_abc_bitlocks);
++ r = nskb;
++ }
++ }
++
++ return(r);
++}
++
++#else
++int dwabc_bsd_init(isdn_net_local *lp) { return(1); }
++void dwabc_bsd_free(isdn_net_local *lp) { return; }
++void dwabc_bsd_first_gen(isdn_net_local *lp) { return ; }
++
++struct sk_buff *dwabc_bsd_compress(isdn_net_local *lp,struct sk_buff *skb,struct net_device *ndev)
++{ return(skb); }
++
++struct sk_buff *dwabc_bsd_rx_pkt(isdn_net_local *lp,struct sk_buff *skb,struct net_device *ndev)
++{ return(skb); }
++#endif
++#endif
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_net.c linux-2.4.29/drivers/isdn/isdn_net.c
+--- linux-2.4.29.old/drivers/isdn/isdn_net.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_net.c 2005-03-22 15:06:44.447335760 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_net.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_net.c,v 1.153 2002/08/17 18:35:23 detabc Exp $
+ *
+ * Linux ISDN subsystem, network interfaces and related functions (linklevel).
+ *
+@@ -9,14 +9,6 @@
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+- * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02
+- * guy@traverse.com.au
+- * Outgoing calls - looks for a 'V' in first char of dialed number
+- * Incoming calls - checks first character of eaz as follows:
+- * Numeric - accept DATA only - original functionality
+- * 'V' - accept VOICE (DOV) only
+- * 'B' - accept BOTH DATA and DOV types
+- *
+ * Jan 2001: fix CISCO HDLC Bjoern A. Zeeb <i4l@zabbadoz.net>
+ * for info on the protocol, see
+ * http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
+@@ -38,6 +30,10 @@
+ #include "isdn_concap.h"
+ #endif
+
++#ifdef CONFIG_ISDN_WITH_ABC
++#include <linux/isdn_dwabc.h>
++#define isdn_net_log_skb(skb,lp) isdn_net_log_skb_dwabc(skb,lp,NULL)
++#endif
+
+ /*
+ * Outline of new tbusy handling:
+@@ -79,7 +75,11 @@
+ dev = lp->master;
+ else
+ dev = &n->dev;
++#ifdef COMPAT_NO_SOFTNET
++ return dev->start;
++#else
+ return netif_running(dev);
++#endif
+ }
+
+ /*
+@@ -143,6 +143,10 @@
+ atomic_inc(&lp->frame_cnt);
+ if (isdn_net_device_busy(lp))
+ isdn_net_device_stop_queue(lp);
++#if 0
++ printk(KERN_DEBUG "%s: inc_frame_cnt now %d\n", lp->name,
++ atomic_read(&lp->frame_cnt));
++#endif
+ }
+
+ static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp)
+@@ -157,11 +161,19 @@
+ isdn_net_device_wake_queue(lp);
+ }
+ }
++#if 0
++ printk(KERN_DEBUG "%s: dec_frame_cnt now %d\n", lp->name,
++ atomic_read(&lp->frame_cnt));
++#endif
+ }
+
+ static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
+ {
+ atomic_set(&lp->frame_cnt, 0);
++#if 0
++ printk(KERN_DEBUG "%s: zero_frame_cnt now %d\n", lp->name,
++ atomic_read(&lp->frame_cnt));
++#endif
+ }
+
+ /* For 2.2.x we leave the transmitter busy timeout at 2 secs, just
+@@ -173,23 +185,101 @@
+ * which might rely on the tx timeout. If so, we'll find out this way...
+ */
+
++#ifdef COMPAT_NO_SOFTNET
++#define ISDN_NET_TX_TIMEOUT (2*HZ)
++#else
+ #define ISDN_NET_TX_TIMEOUT (20*HZ)
++#endif
+
+ /* Prototypes */
+
++#ifndef CONFIG_ISDN_WITH_ABC
+ int isdn_net_force_dial_lp(isdn_net_local *);
++#endif
+ static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
+
+ static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
+ static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp);
+
+-char *isdn_net_revision = "$Revision: 1.1.4.1 $";
++char *isdn_net_revision = "$Revision: 1.153 $";
+
+ /*
+ * Code for raw-networking over ISDN
+ */
++#ifdef CONFIG_ISDN_WITH_ABC
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++static int isdn_dwabc_encap_with_conerr(isdn_net_local *lp)
++{
++ if(lp->dw_abc_flags & ISDN_DW_ABC_FLAG_NO_CONN_ERROR)
++ return(0);
++
++ return(
++ lp->p_encap == ISDN_NET_ENCAP_SYNCPPP ||
++ lp->p_encap == ISDN_NET_ENCAP_RAWIP ||
++ lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK ||
++ lp->p_encap == ISDN_NET_ENCAP_UIHDLC );
++}
++
++static int isdn_dwabc_conerr_ippktok(struct sk_buff *skb)
++{
++ struct iphdr *iph = (struct iphdr *)skb->data;
++ return(iph->version == 6 || (skb->len >= 20 && iph->version == 4));
++}
++
++#endif
++
++static int isdn_dwabc_is_interface_disabled(isdn_net_local *lp)
++{
++ if(lp == NULL)
++ return(0);
++
++ lp->dw_abc_inuse_secure = 0;
++ lp->dw_abc_dialstart = 0;
++
++ /*
++ ** check for jiffies overflow
++ */
++ if(lp->dw_abc_bchan_last_connect > jiffies) {
++
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ lp->dw_abc_bchan_errcnt = 0;
++#endif
++ lp->dw_abc_bchan_last_connect = 0;
++ }
++
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ if(!(lp->dw_abc_flags & ISDN_DW_ABC_FLAG_NO_CONN_ERROR) && isdn_dwabc_encap_with_conerr(lp)) {
++
++ if(lp->dw_abc_bchan_errcnt > 3 && !(lp->dw_abc_bchan_errcnt & 3)) {
+
++ ulong nj = jiffies;
++ ulong delay = lp->dw_abc_bchan_errcnt *
++ lp->dw_abc_bchan_errcnt *
++ lp->dw_abc_bchan_errcnt;
++
++ if(delay > 86400) delay = 86400;
++ delay = (lp->dw_abc_bchan_last_connect + delay * HZ);
++
++ if(delay > nj) {
++
++ printk(KERN_INFO
++ "%s: interface auto-disabled (bchannel connect-error %lu seconds left)\n",
++ lp->name,(delay - nj) / HZ);
++
++ return(1);
++ }
++ }
++ }
++#endif
++ return(0);
++}
++#endif
++
++#ifdef CONFIG_ISDN_WITH_ABC
++void
++#else
+ static void
++#endif
+ isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason)
+ {
+ if(skb) {
+@@ -297,6 +387,12 @@
+
+ save_flags(flags);
+ cli();
++#ifdef CONFIG_ISDN_WITH_ABC
++ isdn_dw_clear_if(0l,lp);
++ lp->dw_abc_if_flags &= ~ISDN_DW_ABC_IFFLAG_NODCHAN;
++ lp->dw_abc_inuse_secure = 0;
++ dwabc_bsd_free(lp);
++#endif
+ skb_queue_purge(&lp->super_tx_queue);
+
+ if (!lp->master) { /* reset only master device */
+@@ -351,6 +447,26 @@
+ if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
+ anymore = 1;
+ l->huptimer++;
++#ifdef CONFIG_ISDN_WITH_ABC
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ if( isdn_dwabc_encap_with_conerr(l) && l->dw_abc_bchan_errcnt > 0) {
++
++ int n = 180;
++
++ if(l->dw_abc_bchan_errcnt > 3) n = 120;
++ if(l->dw_abc_bchan_errcnt > 6) n = 90;
++ if(l->dw_abc_bchan_errcnt > 9) n = 60;
++
++ if(l->huptimer > n) {
++
++ printk(KERN_INFO "%s: bchan conf-error auto-secure-hangup\n",l->name);
++ isdn_net_hangup(&p->dev);
++ p = (isdn_net_dev *) p->next;
++ continue;
++ }
++ }
++#endif
++#endif
+ /*
+ * if there is some dialmode where timeout-hangup
+ * should _not_ be done, check for that here
+@@ -465,8 +581,32 @@
+ printk(KERN_INFO "%s: Chargesum is %d\n", lp->name,
+ lp->charge);
+ isdn_net_unbind_channel(lp);
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ if(lp->dw_abc_bchan_errcnt) {
++
++ printk(KERN_INFO
++ "%s: Note: bchannel-error-counter is %hd\n",
++ lp->name,
++ lp->dw_abc_bchan_errcnt);
++ }
++#endif
+ return 1;
+ }
++#ifdef CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
++ if(!(lp->dw_abc_flags & ISDN_DW_ABC_FLAG_NO_CH_EXTINUSE)) {
++ if((lp->dialstate == 4 || lp->dialstate == 12) &&
++ lp->dw_abc_dialstart && (idx < ISDN_MAX_CHANNELS)) {
++
++ if((jiffies - lp->dw_abc_dialstart) < (HZ >>2)) {
++
++ lp->dw_abc_if_flags |= ISDN_DW_ABC_IFFLAG_NODCHAN;
++ lp->dialstate = 1;
++ dev->dwabc_chan_external_inuse[idx] = jiffies + HZ * 30;
++ printk(KERN_INFO "%s: Channel %d look like external in use\n",lp->name,idx);
++ }
++ }
++ }
++#endif
+ break;
+ #ifdef CONFIG_ISDN_X25
+ case ISDN_STAT_BHUP:
+@@ -507,6 +647,19 @@
+ }
+ }
+ printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
++#ifdef CONFIG_ISDN_WITH_ABC
++ if(!dwabc_bsd_init(lp)) dwabc_bsd_first_gen(lp);
++ lp->dw_abc_bchan_last_connect = jiffies;
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ if(!(lp->dw_abc_flags & ISDN_DW_ABC_FLAG_NO_CONN_ERROR)) {
++
++ lp->dw_abc_bchan_errcnt += isdn_dwabc_encap_with_conerr(lp);
++
++ if(lp->dw_abc_bchan_errcnt > 32000)
++ lp->dw_abc_bchan_errcnt = 32000;
++ }
++#endif
++#endif
+ /* If first Chargeinfo comes before B-Channel connect,
+ * we correct the timestamp here.
+ */
+@@ -578,7 +731,6 @@
+ int i;
+ unsigned long flags;
+ isdn_ctrl cmd;
+- u_char *phone_number;
+
+ while (p) {
+ isdn_net_local *lp = p->local;
+@@ -597,6 +749,47 @@
+ */
+ save_flags(flags);
+ cli();
++#ifdef CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
++ if(!(lp->dw_abc_flags & ISDN_DW_ABC_FLAG_NO_CH_EXTINUSE) &&
++ (lp->dw_abc_if_flags & ISDN_DW_ABC_IFFLAG_NODCHAN)) {
++
++ int chi = 0;
++ short lsecure = 0;
++
++ lsecure = lp->dw_abc_inuse_secure;
++ isdn_net_unbind_channel(lp);
++ lp->dw_abc_inuse_secure = lsecure + 1;
++
++ /* Grab a free ISDN-Channel */
++ if ((lsecure >= ISDN_MAX_CHANNELS ) || (chi =
++ isdn_get_free_channel(
++ ISDN_USAGE_NET,
++ lp->l2_proto,
++ lp->l3_proto,
++ lp->pre_device,
++ lp->pre_channel,
++#ifdef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++ (*lp->dw_out_msn) ? lp->dw_out_msn : lp->msn)
++#else
++ lp->msn)
++#endif
++ ) < 0) {
++
++ restore_flags(flags);
++ isdn_net_unreachable(&p->dev, NULL,
++ "DWABC: redial-external-inuse NO FREE CHANNEL\n");
++ isdn_net_hangup(&p->dev);
++ break;
++ }
++
++ isdn_net_bind_channel(lp, chi);
++ lp->dialstate = 1;
++ lp->dialstarted = 0;
++ lp->dialwait_timer = 0;
++ }
++
++ lp->dw_abc_if_flags &= ~ISDN_DW_ABC_IFFLAG_NODCHAN;
++#endif
+ lp->dial = lp->phone[1];
+ restore_flags(flags);
+ if (!lp->dial) {
+@@ -621,18 +814,69 @@
+ cmd.arg = lp->isdn_channel;
+ cmd.command = ISDN_CMD_CLREAZ;
+ isdn_command(&cmd);
++#ifdef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++ sprintf(cmd.parm.num, "%s",
++ isdn_map_eaz2msn((*lp->dw_out_msn) ? lp->dw_out_msn : lp->msn, cmd.driver));
++#else
+ sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver));
++#endif
+ cmd.command = ISDN_CMD_SETEAZ;
+ isdn_command(&cmd);
+ lp->dialretry = 0;
+ anymore = 1;
+ lp->dialstate++;
++#ifdef CONFIG_ISDN_WITH_ABC
++ lp->onhtime = lp->dw_abc_old_onhtime;
++#ifdef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++ isdn_dw_abc_lcr_clear(lp);
++#endif
++#endif
+ /* Fall through */
+ case 3:
+ /* Setup interface, dial current phone-number, switch to next number.
+ * If list of phone-numbers is exhausted, increment
+ * retry-counter.
+ */
++#ifdef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++ if(!isdn_dw_abc_lcr_lock()) {
++
++ if( lp->dw_abc_lcr_cmd != NULL &&
++ lp->dw_abc_lcr_start_request !=
++ lp->dw_abc_lcr_end_request) {
++
++ if( lp->dw_abc_lcr_io == NULL &&
++ lp->dw_abc_lcr_start_request <= jiffies &&
++ lp->dw_abc_lcr_end_request > jiffies) {
++
++ isdn_dw_abc_lcr_ulock();
++ anymore = 1;
++ break;
++ }
++
++ if(lp->dw_abc_lcr_io != NULL) {
++
++ if(lp->dw_abc_lcr_io->lcr_ioctl_flags &
++ DWABC_LCR_FLG_DISABLE) {
++
++ isdn_dw_abc_lcr_ulock();
++ isdn_net_hangup(&p->dev);
++ break;
++ }
++
++ if(lp->dw_abc_lcr_io->lcr_ioctl_flags &
++ DWABC_LCR_FLG_NEWHUPTIME) {
++ lp->onhtime = lp->dw_abc_lcr_io->lcr_ioctl_onhtime;
++ }
++ }
++
++ memcpy(&cmd,lp->dw_abc_lcr_cmd,sizeof(cmd));
++ isdn_dw_abc_lcr_ulock();
++ goto dw_abc_lcr_next_click;
++ }
++
++ isdn_dw_abc_lcr_ulock();
++ }
++#endif
+ if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) {
+ char *s;
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+@@ -677,20 +921,7 @@
+ break;
+ }
+
+- cmd.driver = lp->isdn_device;
+- cmd.command = ISDN_CMD_DIAL;
+- cmd.parm.setup.si2 = 0;
+-
+- /* check for DOV */
+- phone_number = lp->dial->num;
+- if ((*phone_number == 'v') ||
+- (*phone_number == 'V')) { /* DOV call */
+- cmd.parm.setup.si1 = 1;
+- } else { /* DATA call */
+- cmd.parm.setup.si1 = 7;
+- }
+-
+- strcpy(cmd.parm.setup.phone, phone_number);
++ sprintf(cmd.parm.setup.phone, "%s", lp->dial->num);
+ /*
+ * Switch to next number or back to start if at end of list.
+ */
+@@ -710,17 +941,70 @@
+ }
+ }
+ restore_flags(flags);
++ cmd.driver = lp->isdn_device;
++ cmd.command = ISDN_CMD_DIAL;
++ cmd.parm.setup.si1 = 7;
++ cmd.parm.setup.si2 = 0;
++#ifdef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++ sprintf(cmd.parm.setup.eazmsn, "%s",
++ isdn_map_eaz2msn((*lp->dw_out_msn) ? lp->dw_out_msn : lp->msn, cmd.driver));
++#else
+ sprintf(cmd.parm.setup.eazmsn, "%s",
+ isdn_map_eaz2msn(lp->msn, cmd.driver));
++#endif
++#ifdef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++ /*
++ ** if callback-out we dont need
++ ** low-cost-routing LCR
++ */
++ if(!(lp->flags & ISDN_NET_CBOUT) &&
++ !(lp->dw_abc_flags & ISDN_DW_ABC_FLAG_NO_LCR)) {
++
++ isdn_dw_abc_lcr_call_number(lp,&cmd);
++
++ if(lp->dw_abc_lcr_start_request != lp->dw_abc_lcr_end_request) {
++
++ if(dev->net_verbose > 2) {
++
++ printk(KERN_INFO
++ "%s: Waiting for LCR-response from isdnlog %s -> %s...\n",
++ lp->name,
++ cmd.parm.setup.eazmsn,
++ cmd.parm.setup.phone);
++ }
++
++ anymore = 1;
++ break;
++ }
++ }
++
++dw_abc_lcr_next_click:;
++ isdn_dw_abc_lcr_clear(lp);
++#endif
+ i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel);
+ if (i >= 0) {
+ strcpy(dev->num[i], cmd.parm.setup.phone);
+ dev->usage[i] |= ISDN_USAGE_OUTGOING;
+ isdn_info_update();
+ }
+- printk(KERN_INFO "%s: dialing %d %s... %s\n", lp->name,
+- lp->dialretry, cmd.parm.setup.phone,
+- (cmd.parm.setup.si1 == 1) ? "DOV" : "");
++#ifdef CONFIG_ISDN_WITH_ABC
++ printk(KERN_INFO "%s: dialing %d %s -> %s...\n", lp->name,
++ lp->dialretry,
++ cmd.parm.setup.eazmsn,
++ cmd.parm.setup.phone);
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ if(lp->dw_abc_bchan_errcnt) {
++
++ printk(KERN_INFO
++ "%s: Note: bchannel-error-counter is %hd\n",
++ lp->name,
++ lp->dw_abc_bchan_errcnt);
++ }
++#endif
++#else
++ printk(KERN_INFO "%s: dialing %d %s...\n", lp->name,
++ lp->dialretry, cmd.parm.setup.phone);
++#endif
+ lp->dtimer = 0;
+ #ifdef ISDN_DEBUG_NET_DIAL
+ printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device,
+@@ -741,6 +1025,10 @@
+ lp->dialstate =
+ (lp->cbdelay &&
+ (lp->flags & ISDN_NET_CBOUT)) ? 12 : 4;
++#ifdef CONFIG_ISDN_WITH_ABC
++ lp->dw_abc_if_flags &= ~ISDN_DW_ABC_IFFLAG_NODCHAN;
++ lp->dw_abc_dialstart = jiffies;
++#endif
+ break;
+ case 4:
+ /* Wait for D-Channel-connect.
+@@ -890,6 +1178,15 @@
+ isdn_command(&cmd);
+ printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge);
+ isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ if(lp->dw_abc_bchan_errcnt) {
++
++ printk(KERN_INFO
++ "%s: Note: bchannel-error-counter is %hd\n",
++ lp->name,
++ lp->dw_abc_bchan_errcnt);
++ }
++#endif
+ }
+ isdn_net_unbind_channel(lp);
+ }
+@@ -899,8 +1196,13 @@
+ unsigned short dest;
+ } ip_ports;
+
++#ifdef CONFIG_ISDN_WITH_ABC
++void
++isdn_net_log_skb_dwabc(struct sk_buff * skb, isdn_net_local * lp,char *reason)
++#else
+ static void
+ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp)
++#endif
+ {
+ u_char *p = skb->nh.raw; /* hopefully, this was set correctly */
+ unsigned short proto = ntohs(skb->protocol);
+@@ -972,7 +1274,13 @@
+ break;
+ }
+ printk(KERN_INFO
++#ifdef CONFIG_ISDN_WITH_ABC
++ "%s %s: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
++ (reason == NULL) ? "OPEN" : reason,
++ (lp != NULL) ? lp->name : "",
++#else
+ "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n",
++#endif
+
+ p[12], p[13], p[14], p[15],
+ p[16], p[17], p[18], p[19],
+@@ -980,7 +1288,13 @@
+ break;
+ case ETH_P_ARP:
+ printk(KERN_INFO
++#ifdef CONFIG_ISDN_WITH_ABC
++ "%s %s: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
++ (reason == NULL) ? "OPEN" : reason,
++ (lp != NULL) ? lp->name : "",
++#else
+ "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n",
++#endif
+ p[14], p[15], p[16], p[17],
+ p[24], p[25], p[26], p[27]);
+ break;
+@@ -1004,11 +1318,22 @@
+ }
+
+ spin_lock_bh(&lp->xmit_lock);
++
+ if (!isdn_net_lp_busy(lp)) {
++#ifdef CONFIG_ISDN_WITH_ABC
++ if(!skb_queue_empty(&lp->super_tx_queue)) {
++ /*
++ ** don't reverse the frame flow
++ ** compression need frames in order and maybe other's too
++ */
++ skb_queue_tail(&lp->super_tx_queue, skb);
++ skb = skb_dequeue(&lp->super_tx_queue);
++ }
++#endif
+ isdn_net_writebuf_skb(lp, skb);
+- } else {
+- skb_queue_tail(&lp->super_tx_queue, skb);
+- }
++
++ } else skb_queue_tail(&lp->super_tx_queue, skb);
++
+ spin_unlock_bh(&lp->xmit_lock);
+ }
+
+@@ -1056,7 +1381,6 @@
+ printk(KERN_WARNING "%s: HL driver queue full\n", lp->name);
+ goto error;
+ }
+-
+ lp->transcount += len;
+ isdn_net_inc_frame_cnt(lp);
+ return;
+@@ -1064,9 +1388,19 @@
+ error:
+ dev_kfree_skb(skb);
+ lp->stats.tx_errors++;
+-
+ }
+
++#if 0
++int isdn_net_send_skb(struct net_device *ndev, isdn_net_local * lp,struct sk_buff *skb)
++{
++ if (isdn_net_lp_busy(lp)) {
++ printk(KERN_WARNING "isdn_net_send_skb: HL channel busy\n");
++ return 1;
++ }
++ isdn_net_writebuf_skb(lp, skb);
++ return 0;
++}
++#endif
+
+ /*
+ * Helper function for isdn_net_start_xmit.
+@@ -1109,7 +1443,54 @@
+
+ /* Reset hangup-timeout */
+ lp->huptimer = 0; // FIXME?
++#ifdef CONFIG_ISDN_WITH_ABC
++
++ if(test_and_set_bit(ISDN_DW_ABC_BITLOCK_SEND,&lp->dw_abc_bitlocks)) {
++
++ if(dev->net_verbose > 2)
++ printk(KERN_INFO "%s: isdn_net_xmit called recursivly\n",lp->name);
++
++ spin_unlock_bh(&lp->xmit_lock);
++ return(1);
++ }
++
++ if(skb != NULL) {
++
++ int l = skb->len;
++ int nl = l;
++
++ if( lp->p_encap == ISDN_NET_ENCAP_RAWIP &&
++ (lp->dw_abc_if_flags & ISDN_DW_ABC_IFFLAG_BSDAKTIV)) {
++
++ if((skb = dwabc_bsd_compress(lp,skb,ndev)) != NULL) {
++
++ int r = 0;
++ nl = skb->len;
++ skb_queue_tail(&lp->super_tx_queue,skb);
++
++ if(l != nl && (r = isdn_dc2minor(lp->isdn_device,lp->isdn_channel)) >= 0) {
++
++ dev->obytes[r] += l - nl;
++ lp->stats.tx_bytes += l - nl;
++ }
++ }
++
++ } else skb_queue_tail(&lp->super_tx_queue,skb);
++
++ if(lp->p_encap == ISDN_NET_ENCAP_RAWIP) {
++
++ lp->dw_abc_bsd_snd += l;
++ lp->dw_abc_bsd_bsd_snd += nl;
++ }
++ }
++ clear_bit(ISDN_DW_ABC_BITLOCK_SEND,&lp->dw_abc_bitlocks);
++
++ while(!isdn_net_lp_busy(lp) && (skb = skb_dequeue(&lp->super_tx_queue)))
++ isdn_net_writebuf_skb(lp, skb);
++
++#else
+ isdn_net_writebuf_skb(lp, skb);
++#endif
+ spin_unlock_bh(&lp->xmit_lock);
+
+ /* the following stuff is here for backwards compatibility.
+@@ -1143,6 +1524,69 @@
+
+ return retv;
+
++#if 0
++ if (lp->cps > lp->triggercps) {
++ /* Device overloaded */
++
++ /*
++ * Packet-delivery via round-robin over master
++ * and all connected slaves.
++ */
++ if (lp->master) {
++ /* Slaves always deliver themselves */
++ spin_lock_bh(&lp->xmit_lock);
++ if (!isdn_net_lp_busy(lp)) {
++ isdn_net_writebuf_skb(lp, skb);
++ ret = 0;
++ } else {
++ isdn_net_device_stop_queue(lp);
++ ret = 1;
++ }
++ ret = isdn_net_send_skb(ndev, lp, skb);
++ spin_unlock_bh(&lp->xmit_lock);
++ } else {
++ isdn_net_local *slp = (isdn_net_local *) (lp->srobin->priv);
++ /* Master delivers via srobin and maintains srobin */
++ if (lp->srobin == ndev) {
++ spin_lock_bh(&lp->xmit_lock);
++ ret = isdn_net_send_skb(ndev, lp, skb);
++ spin_unlock_bh(&lp->xmit_lock);
++ } else {
++ ret = isdn_net_start_xmit(skb, lp->srobin);
++ }
++ lp->srobin = (slp->slave) ? slp->slave : ndev;
++ slp = (isdn_net_local *) (lp->srobin->priv);
++ if (!((slp->flags & ISDN_NET_CONNECTED) && (slp->dialstate == 0)))
++ lp->srobin = ndev;
++ }
++ /* Slave-startup using delay-variable */
++ if (lp->slave) {
++ if (!lp->sqfull) {
++ /* First time overload: set timestamp only */
++ lp->sqfull = 1;
++ lp->sqfull_stamp = jiffies;
++ } else {
++ /* subsequent overload: if slavedelay exceeded, start dialing */
++ if ((jiffies - lp->sqfull_stamp) > lp->slavedelay)
++ isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
++ }
++ }
++ } else {
++ /* Not overloaded, deliver locally */
++ spin_lock_bh(&lp->xmit_lock);
++ if (!isdn_net_lp_busy(lp)) {
++ isdn_net_writebuf_skb(lp, skb);
++ ret = 0;
++ } else {
++ isdn_net_device_stop_queue(lp);
++ ret = 1;
++ }
++ spin_unlock_bh(&lp->xmit_lock);
++ if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ))))
++ lp->sqfull = 0;
++ }
++ return ret;
++#endif
+ }
+
+ static void
+@@ -1161,6 +1605,7 @@
+ }
+
+
++#ifndef COMPAT_NO_SOFTNET
+ void isdn_net_tx_timeout(struct net_device * ndev)
+ {
+ isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+@@ -1188,19 +1633,206 @@
+ ndev->trans_start = jiffies;
+ netif_wake_queue(ndev);
+ }
++#endif
+
+ /*
+ * Try sending a packet.
+ * If this interface isn't connected to a ISDN-Channel, find a free channel,
+ * and start dialing.
+ */
++#ifdef CONFIG_ISDN_WITH_ABC
++static int dwabc_isdn_net_start_xmit(struct sk_buff *,struct net_device *);
++
++static int isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
++{
++ if(skb == NULL || ndev == NULL)
++ return(dwabc_isdn_net_start_xmit(skb,ndev));
++#ifdef CONFIG_ISDN_WITH_ABC_UDP_CHECK
++ if(!(((isdn_net_local *)ndev->priv)->dw_abc_flags &
++ ISDN_DW_ABC_FLAG_NO_UDP_CHECK)) {
++
++ if(dw_abc_udp_test(skb,ndev)) {
++ dev_kfree_skb(skb);
++ return(0);
++ }
++ }
++#endif
++ return(dwabc_isdn_net_start_xmit(skb,ndev));
++}
++
++
++#ifdef CONFIG_ISDN_WITH_ABC
++int isdn_auto_dial_helper( isdn_net_local *lp,
++ struct sk_buff *skb,
++ int dm_manual_allowed)
++/**********************************************************************
++ return's:
++ -1 dial not allowed or impossible
++ 0 interface is connected
++ 1 dial is started
++***********************************************************************/
++{
++ int retw = -1;
++ int chi;
++ ulong flags;
++ char *errmsg = NULL;
++
++#ifdef ISDN_DEBUG_NET_DUMP
++ {
++ char *buf = skb->data;
++ isdn_dumppkt("S:", buf, skb->len, 40);
++ }
++#endif
++ if (lp->flags & ISDN_NET_CONNECTED)
++ return(0);
++
++ save_flags(flags);
++ cli();
++
++ do {
++
++ /* Log packet, which triggered dialing */
++ if (dev->net_verbose)
++ isdn_net_log_skb(skb, lp);
++ /* only do autodial if allowed by config */
++ if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) {
++ errmsg = "dial rejected: interface not in dialmode `auto'";
++
++ if(dm_manual_allowed &&
++ !(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_MANUAL)) {
++
++ errmsg =
++ "dial rejected: interface not in dialmode `auto or manual'";
++ }
++ break;
++ }
++
++ if (!lp->phone[1]) {
++
++ errmsg = "No phone number";
++ break;
++ }
++
++ if(lp->dialwait_timer <= 0) {
++
++ if( lp->dialstarted > 0 &&
++ lp->dialtimeout > 0 &&
++ jiffies < (lp->dialstarted + lp->dialtimeout + lp->dialwait)) {
++
++ lp->dialwait_timer =
++ lp->dialstarted + lp->dialtimeout + lp->dialwait;
++ }
++ }
++
++ if(lp->dialwait_timer > 0) {
++
++ if(jiffies < lp->dialwait_timer) {
++
++ errmsg = "dial rejected: retry-time not reached";
++ break;
++
++ } else lp->dialwait_timer = 0;
++ }
++#ifdef CONFIG_ISDN_WITH_ABC
++ if(isdn_dwabc_is_interface_disabled(lp))
++ break;
++#endif
++ /* Grab a free ISDN-Channel */
++ if (((chi =
++ isdn_get_free_channel(
++ ISDN_USAGE_NET,
++ lp->l2_proto,
++ lp->l3_proto,
++ lp->pre_device,
++ lp->pre_channel,
++#ifdef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++ (*lp->dw_out_msn) ? lp->dw_out_msn :
++#endif
++ lp->msn)
++ ) < 0) &&
++ ((chi =
++ isdn_get_free_channel(
++ ISDN_USAGE_NET,
++ lp->l2_proto,
++ lp->l3_proto,
++ lp->pre_device,
++ lp->pre_channel^1,
++#ifdef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++ (*lp->dw_out_msn) ? lp->dw_out_msn :
++#endif
++ lp->msn)
++ ) < 0)) {
++
++ errmsg = "No channel";
++ break;
++ }
++
++ lp->dialstate = 1;
++ /* Connect interface with channel */
++ isdn_net_bind_channel(lp, chi);
++#ifdef CONFIG_ISDN_PPP
++ if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) {
++ /* no 'first_skb' handling for syncPPP */
++ if (isdn_ppp_bind(lp) < 0) {
++ isdn_net_unbind_channel(lp);
++ break;
++ }
++
++ isdn_net_dial(); /* Initiate dialing */
++ netif_stop_queue(&lp->netdev->dev);
++ retw = 1;
++ break;
++ /* let upper layer requeue skb packet */
++ }
++#endif
++ /* Initiate dialing */
++ isdn_net_dial();
++ isdn_net_device_stop_queue(lp);
++ retw = 1;
++
++ } while(0);
++
++ if(retw < 0 && errmsg != NULL)
++ isdn_net_unreachable(&lp->netdev->dev, skb, errmsg);
++
++ restore_flags(flags);
++ return(retw);
++}
++#endif
++
++
++
++static int
++dwabc_isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
++#else
+ static int
+ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
++#endif
+ {
+ isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+ #ifdef CONFIG_ISDN_X25
+ struct concap_proto * cprot = lp -> netdev -> cprot;
+ #endif
++#ifdef COMPAT_NO_SOFTNET
++ /* some comment as with the softnet TX timeout
++ when this happens, it's a bug in the HL card driver
++ and should be fixed there, so we can supposedly get rid of
++ this here at all.
++ I added a debugging message to find out if it ever occurs --KG
++ */
++
++ if (ndev->tbusy) {
++ if (jiffies - ndev->trans_start < ISDN_NET_TX_TIMEOUT)
++ return 1;
++ if (!lp->dialstate){
++ lp->stats.tx_errors++;
++ printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n",
++ ndev->name, lp->dialstate);
++ }
++ ndev->trans_start = jiffies;
++ netif_wake_queue(ndev);
++ }
++#endif
+ #ifdef CONFIG_ISDN_X25
+ /* At this point hard_start_xmit() passes control to the encapsulation
+ protocol (if present).
+@@ -1220,6 +1852,40 @@
+ } else
+ #endif
+ /* auto-dialing xmit function */
++#ifdef CONFIG_ISDN_WITH_ABC
++ {
++ int r;
++
++ isdn_net_adjust_hdr(skb, ndev);
++
++ if(!(r = isdn_auto_dial_helper(lp,skb,0))) {
++
++ /*
++ ** Device is connected to an ISDN channel
++ */
++ ndev->trans_start = jiffies;
++
++ if (!lp->dialstate) {
++
++ /*
++ ** ISDN connection is established, try sending
++ */
++ r = isdn_net_xmit(ndev, skb);
++
++ } else r = 1;
++
++ if(r)
++ netif_stop_queue(ndev);
++
++ } else if(r < 0) {
++
++ dev_kfree_skb(skb);
++ r = 0;
++ }
++
++ return(r);
++ }
++#else
+ {
+ #ifdef ISDN_DEBUG_NET_DUMP
+ u_char *buf;
+@@ -1256,6 +1922,14 @@
+ } else
+ lp->dialwait_timer = 0;
+ }
++#ifdef CONFIG_ISDN_WITH_ABC
++ if(isdn_dwabc_is_interface_disabled(lp)) {
++
++ dev_kfree_skb(skb);
++ restore_flags(flags);
++ return(0);
++ }
++#endif
+ /* Grab a free ISDN-Channel */
+ if (((chi =
+ isdn_get_free_channel(
+@@ -1264,6 +1938,9 @@
+ lp->l3_proto,
+ lp->pre_device,
+ lp->pre_channel,
++#ifdef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++ (*lp->dw_out_msn) ? lp->dw_out_msn :
++#endif
+ lp->msn)
+ ) < 0) &&
+ ((chi =
+@@ -1273,6 +1950,9 @@
+ lp->l3_proto,
+ lp->pre_device,
+ lp->pre_channel^1,
++#ifdef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++ (*lp->dw_out_msn) ? lp->dw_out_msn :
++#endif
+ lp->msn)
+ ) < 0)) {
+ restore_flags(flags);
+@@ -1296,16 +1976,6 @@
+ restore_flags(flags);
+ return 0; /* STN (skb to nirvana) ;) */
+ }
+-#ifdef CONFIG_IPPP_FILTER
+- if (isdn_ppp_autodial_filter(skb, lp)) {
+- isdn_ppp_free(lp);
+- isdn_net_unbind_channel(lp);
+- restore_flags(flags);
+- isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered");
+- dev_kfree_skb(skb);
+- return 0;
+- }
+-#endif
+ restore_flags(flags);
+ isdn_net_dial(); /* Initiate dialing */
+ netif_stop_queue(ndev);
+@@ -1337,6 +2007,7 @@
+ }
+ }
+ return 1;
++#endif
+ }
+
+ /*
+@@ -1356,6 +2027,9 @@
+ if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
+ #endif
+ netif_stop_queue(dev);
++#ifdef COMPAT_NO_SOFTNET
++ dev->start = 0;
++#endif
+ if ((p = (((isdn_net_local *) dev->priv)->slave))) {
+ /* If this interface has slaves, stop them also */
+ while (p) {
+@@ -1776,6 +2450,10 @@
+ }
+
+ switch (type) {
++ case CISCO_TYPE_INET:
++ skb->protocol = htons(ETH_P_IP);
++ netif_rx(skb);
++ break;
+ case CISCO_TYPE_SLARP:
+ isdn_net_ciscohdlck_slarp_in(lp, skb);
+ goto out_free;
+@@ -1785,11 +2463,11 @@
+ "\"no cdp enable\" on cisco.\n", lp->name);
+ goto out_free;
+ default:
+- /* no special cisco protocol */
+- skb->protocol = htons(type);
+- netif_rx(skb);
+- return;
++ printk(KERN_WARNING "%s: Unknown Cisco type 0x%04x\n",
++ lp->name, type);
++ goto out_free;
+ }
++ return;
+
+ out_free:
+ kfree_skb(skb);
+@@ -1803,9 +2481,19 @@
+ {
+ isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+ isdn_net_local *olp = lp; /* original 'lp' */
++#ifdef CONFIG_ISDN_PPP
++ int proto = PPP_PROTOCOL(skb->data);
++#endif
+ #ifdef CONFIG_ISDN_X25
+ struct concap_proto *cprot = lp -> netdev -> cprot;
+ #endif
++#ifdef CONFIG_ISDN_WITH_ABC
++ struct net_device *ondev = ndev;
++#ifdef CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
++ ulong lp_huptimer = 0;
++ ulong olp_huptimer = 0;
++#endif
++#endif
+ lp->transcount += skb->len;
+
+ lp->stats.rx_packets++;
+@@ -1819,6 +2507,10 @@
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes += skb->len;
+ }
++#ifdef CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
++ lp_huptimer = lp->huptimer;
++ olp_huptimer = olp->huptimer;
++#endif
+ skb->dev = ndev;
+ skb->pkt_type = PACKET_HOST;
+ skb->mac.raw = skb->data;
+@@ -1840,9 +2532,40 @@
+ /* Fall through */
+ case ISDN_NET_ENCAP_RAWIP:
+ /* RAW-IP without MAC-Header */
++#ifdef CONFIG_ISDN_WITH_ABC
++ if(olp->p_encap == ISDN_NET_ENCAP_RAWIP) {
++
++ ushort l = skb->len;
++ short r = 0;
++
++ olp->dw_abc_bsd_bsd_rcv += l;
++
++ if((skb = dwabc_bsd_rx_pkt(olp,skb,ondev)) == NULL) {
++
++ olp->dw_abc_bsd_rcv += l;
++ return;
++ }
++
++ olp->dw_abc_bsd_rcv += skb->len;
++
++ if( l != skb->len &&
++ (r=isdn_dc2minor(olp->isdn_device,olp->isdn_channel))>=0) {
++
++ dev->ibytes[r] += skb->len - l;
++ olp->stats.rx_bytes += skb->len - l;
++
++ if(olp != lp)
++ lp->stats.rx_bytes += skb->len - l;
++ }
++ }
++#endif
+ olp->huptimer = 0;
+ lp->huptimer = 0;
+ skb->protocol = htons(ETH_P_IP);
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ if(isdn_dwabc_conerr_ippktok(skb))
++ lp->dw_abc_bchan_errcnt = 0;
++#endif
+ break;
+ case ISDN_NET_ENCAP_CISCOHDLCK:
+ isdn_net_ciscohdlck_receive(lp, skb);
+@@ -1862,8 +2585,22 @@
+ break;
+ #ifdef CONFIG_ISDN_PPP
+ case ISDN_NET_ENCAP_SYNCPPP:
+- /* huptimer is done in isdn_ppp_push_higher */
++ /*
++ * If encapsulation is syncppp, don't reset
++ * huptimer on LCP packets.
++ */
++ if (proto != PPP_LCP) {
++ olp->huptimer = 0;
++ lp->huptimer = 0;
++ }
+ isdn_ppp_receive(lp->netdev, olp, skb);
++#ifdef CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
++ if(olp->dw_abc_flags & ISDN_DW_ABC_FLAG_RCV_NO_HUPTIMER) {
++
++ lp->huptimer = lp_huptimer + 1;
++ olp->huptimer = olp_huptimer+ 1;
++ }
++#endif
+ return;
+ #endif
+
+@@ -1873,6 +2610,15 @@
+ if(cprot) if(cprot -> pops)
+ if( cprot -> pops -> data_ind){
+ cprot -> pops -> data_ind(cprot,skb);
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ lp->dw_abc_bchan_errcnt = 0;
++#ifdef CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
++ if(olp->dw_abc_flags & ISDN_DW_ABC_FLAG_RCV_NO_HUPTIMER) {
++ lp->huptimer = lp_huptimer;
++ olp->huptimer = olp_huptimer;
++ }
++#endif
++#endif
+ return;
+ };
+ #endif /* CONFIG_ISDN_X25 */
+@@ -1882,6 +2628,15 @@
+ return;
+ }
+
++#ifdef CONFIG_ISDN_WITH_ABC
++#ifdef CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
++ if(olp->dw_abc_flags & ISDN_DW_ABC_FLAG_RCV_NO_HUPTIMER) {
++
++ lp->huptimer = lp_huptimer;
++ olp->huptimer = olp_huptimer;
++ }
++#endif
++#endif
+ netif_rx(skb);
+ return;
+ }
+@@ -2160,8 +2915,10 @@
+ isdn_net_phone *n;
+ ulong flags;
+ char nr[32];
+- char *my_eaz;
+-
++#ifdef CONFIG_ISDN_WITH_ABC
++ if(dev->net_verbose > 2)
++ printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=0x%04X\n", di, ch, idx,dev->usage[idx]);
++#endif
+ /* Search name in netdev-chain */
+ save_flags(flags);
+ cli();
+@@ -2180,17 +2937,15 @@
+ eaz = setup->eazmsn;
+ if (dev->net_verbose > 1)
+ printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
+- /* Accept DATA and VOICE calls at this stage
+- local eaz is checked later for allowed call types */
+- if ((si1 != 7) && (si1 != 1)) {
+- restore_flags(flags);
+- if (dev->net_verbose > 1)
+- printk(KERN_INFO "isdn_net: Service-Indicator not 1 or 7, ignored\n");
+- return 0;
+- }
+-
+-n = (isdn_net_phone *) 0;
+-p = dev->netdev;
++ /* Accept only calls with Si1 = 7 (Data-Transmission) */
++ if (si1 != 7) {
++ restore_flags(flags);
++ if (dev->net_verbose > 1)
++ printk(KERN_INFO "isdn_net: Service-Indicator not 7, ignored\n");
++ return 0;
++ }
++ n = (isdn_net_phone *) 0;
++ p = dev->netdev;
+ ematch = wret = swapped = 0;
+ #ifdef ISDN_DEBUG_NET_ICALL
+ printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
+@@ -2210,25 +2965,8 @@
+ break;
+ }
+ swapped = 0;
+- /* check acceptable call types for DOV */
+- my_eaz = isdn_map_eaz2msn(lp->msn, di);
+- if (si1 == 1) { /* it's a DOV call, check if we allow it */
+- if (*my_eaz == 'v' || *my_eaz == 'V' ||
+- *my_eaz == 'b' || *my_eaz == 'B')
+- my_eaz++; /* skip to allow a match */
+- else
+- my_eaz = 0; /* force non match */
+- } else { /* it's a DATA call, check if we allow it */
+- if (*my_eaz == 'b' || *my_eaz == 'B')
+- my_eaz++; /* skip to allow a match */
+- }
+- if (my_eaz)
+- matchret = isdn_msncmp(eaz, my_eaz);
+- else
+- matchret = 1;
+- if (!matchret)
+- ematch = 1;
+-
++ if (!(matchret = isdn_msncmp(eaz, isdn_map_eaz2msn(lp->msn, di))))
++ ematch = 1;
+ /* Remember if more numbers eventually can match */
+ if (matchret > wret)
+ wret = matchret;
+@@ -2236,17 +2974,122 @@
+ printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n",
+ lp->name, lp->msn, lp->flags, lp->dialstate);
+ #endif
++#ifdef CONFIG_ISDN_WITH_ABC_CALLB
++ if ((!matchret) && /* EAZ is matching */
++ (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */
++ (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */
++ (lp->dialstate == 4) || (lp->dialstate == 12) || /* if dialing */
++ ((lp->flags & ISDN_NET_CBOUT) != 0 && /* init a callback */
++ lp->outgoing != 0 )))
++
++ /*
++ ** we dont stop call's anymore (both sides call's syncron)
++ ** it will be problem in any case.
++ ** both sides will make the same.
++ ** i try later to make a switch (check the phon-numbers)
++ ** to detect with side must be stop the call.
++ */
++#else
+ if ((!matchret) && /* EAZ is matching */
+ (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */
+ (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */
+ ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */
+ (!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */
+ )))
++#endif
+ {
+ #ifdef ISDN_DEBUG_NET_ICALL
+ printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n",
+ lp->pre_device, lp->pre_channel);
+ #endif
++#ifdef CONFIG_ISDN_WITH_ABC
++#ifdef CONFIG_ISDN_WITH_ABC_CALLB
++ {
++ int use_this_call = 0;
++
++ if(!(lp->flags & ISDN_NET_CBOUT) && ((lp->dialstate == 4) || (lp->dialstate == 12))) {
++
++ /*
++ ** searching for a diff. in the calling-number and the EAZ
++ ** the remote will make the same
++ */
++
++ char *pnr = nr;
++ char *pea = eaz;
++
++ for(;*pnr;pnr++);
++ for(;*pea;pea++);
++ for(pnr--,pea--;pnr >= nr && pea >= eaz && *pea != *pnr;pnr--,pea--);
++
++ if(pnr < nr || pea < eaz || *pea > *pnr) {
++
++ p = (isdn_net_dev *) p->next;
++ continue;
++ }
++
++ use_this_call = 1;
++ }
++
++ if( use_this_call ||
++ ((lp->flags & ISDN_NET_CBOUT) && (lp->flags & ISDN_NET_CONNECTED))) {
++
++ /*
++ ** the incoming call was to quick.
++ ** the callback-delay-time ist not reached.
++ ** in that case we can stop the call
++ */
++
++ if(lp->isdn_device > -1 && lp->isdn_channel > -1) {
++
++ int minor = isdn_dc2minor(lp->isdn_device,lp->isdn_channel);
++
++ if(lp->isdn_device != di || lp->isdn_channel != ch) {
++
++ isdn_ctrl cmd;
++
++ memset((void *)&cmd,0,sizeof(cmd));
++ cmd.driver = lp->isdn_device;
++ cmd.command = ISDN_CMD_HANGUP;
++ cmd.arg = lp->isdn_channel;
++ (void) dev->drv[cmd.driver]->interface->command(&cmd);
++ isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
++
++ if(dev->net_verbose > 1) {
++
++ printk(KERN_INFO
++ "%s: found outgoing call hangup old call on di %d ch %d\n",
++ lp->name,lp->isdn_device,lp->isdn_channel);
++ }
++
++ } else if (dev->net_verbose > 1) {
++
++ printk(KERN_INFO "%s: found outgoing call on same di %d ch %d\n",
++ lp->name,lp->isdn_device,lp->isdn_channel);
++ }
++
++ if(minor >= 0) {
++
++ dev->rx_netdev[minor] = NULL;
++ dev->st_netdev[minor] = NULL;
++ }
++
++ isdn_free_channel(lp->isdn_device,
++ lp->isdn_channel, ISDN_USAGE_NET);
++
++ } else if (dev->net_verbose > 1) {
++
++ printk(KERN_INFO "%s: found outgoing call reset callstate \n",lp->name);
++ }
++
++ lp->flags &= ~ISDN_NET_CONNECTED;
++ lp->isdn_device = -1;
++ lp->isdn_channel = -1;
++ lp->dtimer = 0;
++ lp->dialstate = 0;
++ }
++ }
++#endif
++#endif
+ if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) {
+ if ((lp->pre_channel != ch) ||
+ (lp->pre_device != di)) {
+@@ -2375,6 +3218,12 @@
+ continue;
+ }
+ }
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ if(isdn_dwabc_is_interface_disabled(lp)) {
++ restore_flags(flags);
++ return 3;
++ }
++#endif
+ if (lp->flags & ISDN_NET_CALLBACK) {
+ int chi;
+ /*
+@@ -2427,6 +3276,47 @@
+ restore_flags(flags);
+ return 0;
+ } else {
++#ifdef CONFIG_ISDN_WITH_ABC_CALLB
++ {
++ /*
++ ** this is a sanity-check.
++ ** check for double use (device and channel)
++ ** will be very near to a kernel-crash in that case
++ */
++ isdn_net_dev *sp = dev->netdev;
++ int s_shl;
++ isdn_net_local *ml;
++
++ for(s_shl=0; s_shl < 2048 && sp != NULL; sp = (isdn_net_dev *)sp->next, s_shl++) {
++
++ if(sp == p || (ml = sp->local) == NULL)
++ continue;
++
++ if(ml->isdn_device != di || ml->isdn_channel != ch)
++ continue;
++
++ if(ml->dialstate != 4 && ml->dialstate != 12) {
++
++ /*
++ ** wrong situation
++ */
++ break;
++ }
++
++ isdn_net_unbind_channel(ml);
++ }
++
++ if(sp != NULL) {
++
++ printk(KERN_DEBUG
++"%s: call from %s -> %s (drv %d chan %d duplicated with %s) \n",
++ lp->name, nr, eaz,di,ch,
++ sp->local->name );
++
++ restore_flags(flags);
++ return 3;
++ }}
++#endif
+ printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", lp->name, nr,
+ eaz);
+ /* if this interface is dialing, it does it probably on a different
+@@ -2516,7 +3406,11 @@
+ lp->l3_proto,
+ lp->pre_device,
+ lp->pre_channel,
++#ifdef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++ (*lp->dw_out_msn) ? lp->dw_out_msn : lp->msn)
++#else
+ lp->msn)
++#endif
+ ) < 0) {
+ printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", lp->name);
+ restore_flags(flags);
+@@ -2599,7 +3493,11 @@
+ strcpy(netdev->local->name, " ");
+ else
+ strcpy(netdev->local->name, name);
++#ifdef COMPAT_NO_SOFTNET
++ netdev->dev.name = netdev->local->name;
++#else
+ strcpy(netdev->dev.name, netdev->local->name);
++#endif
+ netdev->dev.priv = netdev->local;
+ netdev->dev.init = isdn_net_init;
+ netdev->local->p_encap = ISDN_NET_ENCAP_RAWIP;
+@@ -2617,11 +3515,13 @@
+ ((isdn_net_local *) q->priv)->slave = &(netdev->dev);
+ } else {
+ /* Device shall be a master */
++#ifndef COMPAT_NO_SOFTNET
+ /*
+ * Watchdog timer (currently) for master only.
+ */
+ netdev->dev.tx_timeout = isdn_net_tx_timeout;
+ netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
++#endif
+ if (register_netdev(&netdev->dev) != 0) {
+ printk(KERN_WARNING "isdn_net: Could not register net-device\n");
+ kfree(netdev->local);
+@@ -2658,6 +3558,9 @@
+ netdev->local->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */
+ netdev->local->onhtime = 10; /* Default hangup-time for saving costs
+ of those who forget configuring this */
++#ifdef CONFIG_ISDN_WITH_ABC
++ netdev->local->dw_abc_old_onhtime = netdev->local->onhtime;
++#endif
+ netdev->local->dialmax = 1;
+ netdev->local->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; /* Hangup before Callback, manual dial */
+ netdev->local->cbdelay = 25; /* Wait 5 secs before Callback */
+@@ -2831,7 +3734,6 @@
+
+ /* If binding is exclusive, try to grab the channel */
+ save_flags(flags);
+- cli();
+ if ((i = isdn_get_free_channel(ISDN_USAGE_NET,
+ lp->l2_proto, lp->l3_proto, drvidx,
+ chidx, lp->msn)) < 0) {
+@@ -2859,6 +3761,9 @@
+ lp->pre_device = drvidx;
+ lp->pre_channel = chidx;
+ lp->onhtime = cfg->onhtime;
++#ifdef CONFIG_ISDN_WITH_ABC
++ lp->dw_abc_old_onhtime = lp->onhtime;
++#endif
+ lp->charge = cfg->charge;
+ lp->l2_proto = cfg->l2_proto;
+ lp->l3_proto = cfg->l3_proto;
+@@ -2932,6 +3837,9 @@
+ }
+ }
+ lp->p_encap = cfg->p_encap;
++#ifdef CONFIG_ISDN_WITH_ABC
++ isdn_dw_abc_reset_interface(lp,0);
++#endif
+ return 0;
+ }
+ return -ENODEV;
+@@ -3007,6 +3915,9 @@
+ strcpy(n->num, phone->phone);
+ n->next = p->local->phone[phone->outgoing & 1];
+ p->local->phone[phone->outgoing & 1] = n;
++#ifdef CONFIG_ISDN_WITH_ABC
++ isdn_dwabc_test_phone(p->local);
++#endif
+ return 0;
+ }
+ return -ENODEV;
+@@ -3100,6 +4011,9 @@
+ else
+ p->local->phone[inout] = n->next;
+ kfree(n);
++#ifdef CONFIG_ISDN_WITH_ABC
++ isdn_dwabc_test_phone(p->local);
++#endif
+ restore_flags(flags);
+ return 0;
+ }
+@@ -3135,6 +4049,9 @@
+ p->local->phone[i] = NULL;
+ }
+ p->local->dial = NULL;
++#ifdef CONFIG_ISDN_WITH_ABC
++ isdn_dwabc_test_phone(p->local);
++#endif
+ restore_flags(flags);
+ return 0;
+ }
+@@ -3218,6 +4135,10 @@
+ /* If no more net-devices remain, disable auto-hangup timer */
+ if (dev->netdev == NULL)
+ isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
++#ifdef CONFIG_ISDN_WITH_ABC
++ isdn_dw_clear_if(~0l,p->local);
++ dwabc_bsd_free(p->local);
++#endif
+ restore_flags(flags);
+ kfree(p->local);
+ kfree(p);
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_net.h linux-2.4.29/drivers/isdn/isdn_net.h
+--- linux-2.4.29.old/drivers/isdn/isdn_net.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_net.h 2005-03-22 15:06:44.463333328 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_net.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_net.h,v 1.23 2001/11/07 22:35:48 kai Exp $
+ *
+ * header for Linux ISDN subsystem, network related functions (linklevel).
+ *
+@@ -26,6 +26,7 @@
+ #define CISCO_ADDR_BROADCAST 0x8f
+ #define CISCO_CTRL 0x00
+ #define CISCO_TYPE_CDP 0x2000
++#define CISCO_TYPE_INET 0x0800
+ #define CISCO_TYPE_SLARP 0x8035
+ #define CISCO_SLARP_REQUEST 0
+ #define CISCO_SLARP_REPLY 1
+@@ -106,8 +107,6 @@
+ spin_lock_irqsave(&nd->queue_lock, flags);
+
+ lp = nd->queue;
+-// printk(KERN_DEBUG __FUNCTION__": lp:%s(%p) nlp:%s(%p) last(%p)\n",
+-// lp->name, lp, nlp->name, nlp, lp->last);
+ nlp->last = lp->last;
+ lp->last->next = nlp;
+ lp->last = nlp;
+@@ -127,20 +126,12 @@
+ if (lp->master)
+ master_lp = (isdn_net_local *) lp->master->priv;
+
+-// printk(KERN_DEBUG __FUNCTION__": lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n",
+-// lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue);
+ spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
+ lp->last->next = lp->next;
+ lp->next->last = lp->last;
+- if (master_lp->netdev->queue == lp) {
++ if (master_lp->netdev->queue == lp)
+ master_lp->netdev->queue = lp->next;
+- if (lp->next == lp) { /* last in queue */
+- master_lp->netdev->queue = master_lp->netdev->local;
+- }
+- }
+ lp->next = lp->last = lp; /* (re)set own pointers */
+-// printk(KERN_DEBUG __FUNCTION__": mndq(%p)\n",
+-// master_lp->netdev->queue);
+ spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
+ }
+
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_ppp.c linux-2.4.29/drivers/isdn/isdn_ppp.c
+--- linux-2.4.29.old/drivers/isdn/isdn_ppp.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_ppp.c 2005-03-22 15:06:44.481330592 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_ppp.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_ppp.c,v 1.94 2001/11/07 22:35:48 kai Exp $
+ *
+ * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
+ *
+@@ -13,9 +13,6 @@
+ #include <linux/isdn.h>
+ #include <linux/poll.h>
+ #include <linux/ppp-comp.h>
+-#ifdef CONFIG_IPPP_FILTER
+-#include <linux/filter.h>
+-#endif
+
+ #include "isdn_common.h"
+ #include "isdn_ppp.h"
+@@ -72,11 +69,19 @@
+ static int isdn_ppp_bundle(struct ippp_struct *, int unit);
+ #endif /* CONFIG_ISDN_MPP */
+
+-char *isdn_ppp_revision = "$Revision: 1.1.4.1 $";
++char *isdn_ppp_revision = "$Revision: 1.94 $";
+
+ static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
+
++#ifndef CONFIG_ISDN_WITH_ABC
+ static struct isdn_ppp_compressor *ipc_head = NULL;
++#else
++ /*
++ ** make compressor's common usable
++ */
++struct isdn_ppp_compressor *isdn_ippp_comp_head = NULL;
++#define ipc_head isdn_ippp_comp_head
++#endif
+
+ /*
+ * frame log (debug)
+@@ -110,11 +115,8 @@
+ unsigned long flags;
+ struct ippp_struct *is;
+
+- if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
+- __FUNCTION__, lp->ppp_slot);
++ if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS)
+ return 0;
+- }
+
+ save_flags(flags);
+ cli();
+@@ -130,12 +132,7 @@
+ lp->netdev->pb->ref_ct--;
+ spin_unlock(&lp->netdev->pb->lock);
+ #endif /* CONFIG_ISDN_MPP */
+- if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n",
+- __FUNCTION__, lp->ppp_slot);
+- restore_flags(flags);
+- return 0;
+- }
++
+ is = ippp_table[lp->ppp_slot];
+ if ((is->state & IPPP_CONNECT))
+ isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */
+@@ -231,13 +228,12 @@
+ void
+ isdn_ppp_wakeup_daemon(isdn_net_local * lp)
+ {
+- if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
+- __FUNCTION__, lp->ppp_slot);
++ if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS)
+ return;
+- }
++
+ ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
+- wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
++
++ wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
+ }
+
+ /*
+@@ -250,14 +246,13 @@
+ {
+ struct ippp_struct *is;
+
+- if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "%s: slot(%d) out of range\n",
+- __FUNCTION__, slot);
++ if (slot < 0 || slot >= ISDN_MAX_CHANNELS)
+ return 0;
+- }
+ is = ippp_table[slot];
++
+ if (is->state)
+ wake_up_interruptible(&is->wq);
++
+ is->state = IPPP_CLOSEWAIT;
+ return 1;
+ }
+@@ -295,9 +290,11 @@
+ return -EBUSY;
+ }
+ is = file->private_data = ippp_table[slot];
+-
+- printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n",
+- slot, min, is->state);
++
++#if 0
++ if (is->debug & 0x1)
++#endif
++ printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state);
+
+ /* compression stuff */
+ is->link_compressor = is->compressor = NULL;
+@@ -327,10 +324,7 @@
+ */
+ is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */
+ #endif
+-#ifdef CONFIG_IPPP_FILTER
+- is->pass_filter.filter = NULL;
+- is->active_filter.filter = NULL;
+-#endif
++
+ is->state = IPPP_OPEN;
+
+ return 0;
+@@ -349,20 +343,12 @@
+ return;
+ is = file->private_data;
+
+- if (!is) {
+- printk(KERN_ERR "%s: no file->private_data\n", __FUNCTION__);
+- return;
+- }
+ if (is->debug & 0x1)
+ printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
+
+ if (is->lp) { /* a lp address says: this link is still up */
+ isdn_net_dev *p = is->lp->netdev;
+
+- if (!p) {
+- printk(KERN_ERR "%s: no lp->netdev\n", __FUNCTION__);
+- return;
+- }
+ is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */
+ /*
+ * isdn_net_hangup() calls isdn_ppp_free()
+@@ -385,18 +371,8 @@
+ slhc_free(is->slcomp);
+ is->slcomp = NULL;
+ #endif
+-#ifdef CONFIG_IPPP_FILTER
+- if (is->pass_filter.filter) {
+- kfree(is->pass_filter.filter);
+- is->pass_filter.filter = NULL;
+- }
+- if (is->active_filter.filter) {
+- kfree(is->active_filter.filter);
+- is->active_filter.filter = NULL;
+- }
+-#endif
+
+-/* TODO: if this was the previous master: link the stuff to the new master */
++/* TODO: if this was the previous master: link the the stuff to the new master */
+ if(is->comp_stat)
+ is->compressor->free(is->comp_stat);
+ if(is->link_comp_stat)
+@@ -509,13 +485,15 @@
+ if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) {
+ if (lp) {
+ /* OK .. we are ready to send buffers */
+- is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */
+ netif_wake_queue(&lp->netdev->dev);
+- break;
+ }
+ }
+ is->pppcfg = val;
+ break;
++#if 0
++ case PPPIOCGSTAT: /* read PPP statistic information */
++ break;
++#endif
+ case PPPIOCGIDLE: /* get idle time information */
+ if (lp) {
+ struct ppp_idle pidle;
+@@ -604,39 +582,6 @@
+ }
+ return set_arg((void *)arg,&pci,sizeof(struct pppcallinfo));
+ }
+-#ifdef CONFIG_IPPP_FILTER
+- case PPPIOCSPASS:
+- case PPPIOCSACTIVE:
+- {
+- struct sock_fprog uprog, *filtp;
+- struct sock_filter *code = NULL;
+- int len, err;
+-
+- if (copy_from_user(&uprog, (void *) arg, sizeof(uprog)))
+- return -EFAULT;
+- if (uprog.len > 0 && uprog.len < 65536) {
+- len = uprog.len * sizeof(struct sock_filter);
+- code = kmalloc(len, GFP_KERNEL);
+- if (code == NULL)
+- return -ENOMEM;
+- if (copy_from_user(code, uprog.filter, len)) {
+- kfree(code);
+- return -EFAULT;
+- }
+- err = sk_chk_filter(code, uprog.len);
+- if (err) {
+- kfree(code);
+- return err;
+- }
+- }
+- filtp = (cmd == PPPIOCSPASS) ? &is->pass_filter : &is->active_filter;
+- if (filtp->filter)
+- kfree(filtp->filter);
+- filtp->filter = code;
+- filtp->len = uprog.len;
+- break;
+- }
+-#endif /* CONFIG_IPPP_FILTER */
+ default:
+ break;
+ }
+@@ -699,7 +644,7 @@
+ struct ippp_struct *is;
+
+ if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
+- printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot);
++ printk(KERN_WARNING "ippp: illegal slot.\n");
+ return 0;
+ }
+ is = ippp_table[slot];
+@@ -976,8 +921,7 @@
+
+ slot = lp->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
+- lp->ppp_slot);
++ printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
+ kfree_skb(skb);
+ return;
+ }
+@@ -1026,23 +970,19 @@
+ {
+ struct net_device *dev = &net_dev->dev;
+ struct ippp_struct *is, *mis;
+- isdn_net_local *mlp = NULL;
+ int slot;
+
+ slot = lp->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
+- lp->ppp_slot);
++ printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot %d\n", lp->ppp_slot);
+ goto drop_packet;
+ }
+ is = ippp_table[slot];
+
+ if (lp->master) { // FIXME?
+- mlp = (isdn_net_local *) lp->master->priv;
+- slot = mlp->ppp_slot;
++ slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
+- lp->ppp_slot);
++ printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot %d\n", lp->ppp_slot);
+ goto drop_packet;
+ }
+ }
+@@ -1076,11 +1016,6 @@
+ case PPP_VJC_UNCOMP:
+ if (is->debug & 0x20)
+ printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
+- if (net_dev->local->ppp_slot < 0) {
+- printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
+- __FUNCTION__, net_dev->local->ppp_slot);
+- goto drop_packet;
+- }
+ if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
+ printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
+ goto drop_packet;
+@@ -1102,11 +1037,6 @@
+ }
+ skb_put(skb, skb_old->len + 128);
+ memcpy(skb->data, skb_old->data, skb_old->len);
+- if (net_dev->local->ppp_slot < 0) {
+- printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n",
+- __FUNCTION__, net_dev->local->ppp_slot);
+- goto drop_packet;
+- }
+ pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
+ skb->data, skb_old->len);
+ kfree_skb(skb_old);
+@@ -1133,36 +1063,12 @@
+ return;
+ }
+
+-#ifdef CONFIG_IPPP_FILTER
+- /* check if the packet passes the pass and active filters
+- * the filter instructions are constructed assuming
+- * a four-byte PPP header on each packet (which is still present) */
+- skb_push(skb, 4);
+- skb->data[0] = 0; /* indicate inbound */
+-
+- if (is->pass_filter.filter
+- && sk_run_filter(skb, is->pass_filter.filter,
+- is->pass_filter.len) == 0) {
+- if (is->debug & 0x2)
+- printk(KERN_DEBUG "IPPP: inbound frame filtered.\n");
+- kfree_skb(skb);
+- return;
+- }
+- if (!(is->active_filter.filter
+- && sk_run_filter(skb, is->active_filter.filter,
+- is->active_filter.len) == 0)) {
+- if (is->debug & 0x2)
+- printk(KERN_DEBUG "IPPP: link-active filter: reseting huptimer.\n");
+- lp->huptimer = 0;
+- if (mlp)
+- mlp->huptimer = 0;
+- }
+- skb_pull(skb, 4);
+-#else /* CONFIG_IPPP_FILTER */
+- lp->huptimer = 0;
+- if (mlp)
+- mlp->huptimer = 0;
+-#endif /* CONFIG_IPPP_FILTER */
++ /* Reset hangup-timer */
++ lp->huptimer = 0;
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ lp->dw_abc_bchan_errcnt = 0;
++#endif
++
+ skb->dev = dev;
+ skb->mac.raw = skb->data;
+ netif_rx(skb);
+@@ -1199,6 +1105,7 @@
+ return skb_push(skb,len);
+ }
+
++
+ /*
+ * send ppp frame .. we expect a PIDCOMPressable proto --
+ * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP)
+@@ -1214,25 +1121,23 @@
+ isdn_net_dev *nd;
+ unsigned int proto = PPP_IP; /* 0x21 */
+ struct ippp_struct *ipt,*ipts;
+- int slot, retval = 0;
++ int slot;
+
+ mlp = (isdn_net_local *) (netdev->priv);
+ nd = mlp->netdev; /* get master lp */
+
+ slot = mlp->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
+- mlp->ppp_slot);
++ printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", mlp->ppp_slot);
+ kfree_skb(skb);
+- goto out;
++ return 0;
+ }
+ ipts = ippp_table[slot];
+
+ if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
+ if (ipts->debug & 0x1)
+ printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name);
+- retval = 1;
+- goto out;
++ return 1;
+ }
+
+ switch (ntohs(skb->protocol)) {
+@@ -1246,25 +1151,24 @@
+ printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
+ skb->protocol);
+ dev_kfree_skb(skb);
+- goto out;
++ return 0;
+ }
+
+ lp = isdn_net_get_locked_lp(nd);
+ if (!lp) {
+ printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
+- retval = 1;
+- goto out;
++ return 1;
+ }
+ /* we have our lp locked from now on */
+
+ slot = lp->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
+- lp->ppp_slot);
++ printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", lp->ppp_slot);
+ kfree_skb(skb);
+- goto unlock;
++ return 0;
+ }
+ ipt = ippp_table[slot];
++ lp->huptimer = 0;
+
+ /*
+ * after this line .. requeueing in the device queue is no longer allowed!!!
+@@ -1275,34 +1179,6 @@
+ */
+ skb_pull(skb,IPPP_MAX_HEADER);
+
+-#ifdef CONFIG_IPPP_FILTER
+- /* check if we should pass this packet
+- * the filter instructions are constructed assuming
+- * a four-byte PPP header on each packet */
+- skb_push(skb, 4);
+- skb->data[0] = 1; /* indicate outbound */
+- *(u_int16_t *)(skb->data + 2) = htons(proto);
+-
+- if (ipt->pass_filter.filter
+- && sk_run_filter(skb, ipt->pass_filter.filter,
+- ipt->pass_filter.len) == 0) {
+- if (ipt->debug & 0x4)
+- printk(KERN_DEBUG "IPPP: outbound frame filtered.\n");
+- kfree_skb(skb);
+- goto unlock;
+- }
+- if (!(ipt->active_filter.filter
+- && sk_run_filter(skb, ipt->active_filter.filter,
+- ipt->active_filter.len) == 0)) {
+- if (ipt->debug & 0x4)
+- printk(KERN_DEBUG "IPPP: link-active filter: reseting huptimer.\n");
+- lp->huptimer = 0;
+- }
+- skb_pull(skb, 4);
+-#else /* CONFIG_IPPP_FILTER */
+- lp->huptimer = 0;
+-#endif /* CONFIG_IPPP_FILTER */
+-
+ if (ipt->debug & 0x4)
+ printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
+ if (ipts->debug & 0x40)
+@@ -1440,54 +1316,9 @@
+
+ unlock:
+ spin_unlock_bh(&lp->xmit_lock);
+- out:
+- return retval;
++ return 0;
+ }
+
+-#ifdef CONFIG_IPPP_FILTER
+-/*
+- * check if this packet may trigger auto-dial.
+- */
+-
+-int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp)
+-{
+- struct ippp_struct *is = ippp_table[lp->ppp_slot];
+- u_int16_t proto;
+- int drop = 0;
+-
+- switch (ntohs(skb->protocol)) {
+- case ETH_P_IP:
+- proto = PPP_IP;
+- break;
+- case ETH_P_IPX:
+- proto = PPP_IPX;
+- break;
+- default:
+- printk(KERN_ERR "isdn_ppp_autodial_filter: unsupported protocol 0x%x.\n",
+- skb->protocol);
+- return 1;
+- }
+-
+- /* the filter instructions are constructed assuming
+- * a four-byte PPP header on each packet. we have to
+- * temporarily remove part of the fake header stuck on
+- * earlier.
+- */
+- skb_pull(skb, IPPP_MAX_HEADER - 4);
+- skb->data[0] = 1; /* indicate outbound */
+- *(u_int16_t *)(skb->data + 2) = htons(proto);
+-
+- drop |= is->pass_filter.filter
+- && sk_run_filter(skb, is->pass_filter.filter,
+- is->pass_filter.len) == 0;
+- drop |= is->active_filter.filter
+- && sk_run_filter(skb, is->active_filter.filter,
+- is->active_filter.len) == 0;
+-
+- skb_push(skb, IPPP_MAX_HEADER - 4);
+- return drop;
+-}
+-#endif
+ #ifdef CONFIG_ISDN_MPP
+
+ /* this is _not_ rfc1990 header, but something we convert both short and long
+@@ -1537,15 +1368,8 @@
+
+ static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
+ {
+- struct ippp_struct * is;
+-
+- if (lp->ppp_slot < 0) {
+- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
+- __FUNCTION__, lp->ppp_slot);
+- return(-EINVAL);
+- }
+-
+- is = ippp_table[lp->ppp_slot];
++ struct ippp_struct * is = ippp_table[lp->ppp_slot];
++
+ if (add_to) {
+ if( lp->netdev->pb )
+ lp->netdev->pb->ref_ct--;
+@@ -1591,8 +1415,7 @@
+ stats = &mp->stats;
+ slot = lp->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "%s: lp->ppp_slot(%d)\n",
+- __FUNCTION__, lp->ppp_slot);
++ printk(KERN_ERR "isdn_ppp_mp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
+ stats->frame_drops++;
+ dev_kfree_skb(skb);
+ spin_unlock_irqrestore(&mp->lock, flags);
+@@ -1628,8 +1451,7 @@
+ for (lpq = net_dev->queue;;) {
+ slot = lpq->ppp_slot;
+ if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
+- __FUNCTION__, lpq->ppp_slot);
++ printk(KERN_ERR "isdn_ppp_mp_receive: lpq->ppp_slot %d\n", lpq->ppp_slot);
+ } else {
+ u32 lls = ippp_table[slot]->last_link_seqno;
+ if (MP_LT(lls, minseq))
+@@ -1861,14 +1683,9 @@
+ struct sk_buff * skb;
+ unsigned int tot_len;
+
+- if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
+- __FUNCTION__, lp->ppp_slot);
+- return;
+- }
+ if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {
+ if( ippp_table[lp->ppp_slot]->debug & 0x40 )
+- printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
++ printk(KERN_DEBUG"isdn_mppp: reassembly: frame %d, "
+ "len %d\n", MP_SEQ(from), from->len );
+ skb = from;
+ skb_pull(skb, MP_HEADER_LEN);
+@@ -1987,10 +1804,8 @@
+ memset(&t, 0, sizeof(struct ppp_stats));
+ if (dev->flags & IFF_UP) {
+ t.p.ppp_ipackets = lp->stats.rx_packets;
+- t.p.ppp_ibytes = lp->stats.rx_bytes;
+ t.p.ppp_ierrors = lp->stats.rx_errors;
+ t.p.ppp_opackets = lp->stats.tx_packets;
+- t.p.ppp_obytes = lp->stats.tx_bytes;
+ t.p.ppp_oerrors = lp->stats.tx_errors;
+ #ifdef CONFIG_ISDN_PPP_VJ
+ if (slot >= 0 && ippp_table[slot]->slcomp) {
+@@ -2018,6 +1833,9 @@
+ int len;
+ isdn_net_local *lp = (isdn_net_local *) dev->priv;
+
++#if 0
++ printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n", cmd, lp->ppp_slot);
++#endif
+
+ if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
+ return -EINVAL;
+@@ -2431,7 +2249,7 @@
+ return;
+ }
+ rs->state = CCPResetSentReq;
+- /* We always expect an Ack if the decompressor doesn't
++ /* We always expect an Ack if the decompressor doesnt
+ know better */
+ rs->expra = 1;
+ rs->dlen = 0;
+@@ -2582,7 +2400,13 @@
+ }
+
+ if(type) { /* type=1 => Link compression */
++#if 0
++ compressor = is->link_compressor;
++ stat = is->link_comp_stat;
++ new_proto = PPP_LINK_COMP;
++#else
+ return skb_in;
++#endif
+ }
+ else {
+ if(!master) {
+@@ -2630,31 +2454,18 @@
+ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
+ struct sk_buff *skb,int proto)
+ {
+- struct ippp_struct *is;
++ struct ippp_struct *is = ippp_table[lp->ppp_slot];
+ struct ippp_struct *mis;
+ int len;
+ struct isdn_ppp_resetparams rsparm;
+ unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
+
+- printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
+- lp->ppp_slot);
+- if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
+- __FUNCTION__, lp->ppp_slot);
+- return;
+- }
+- is = ippp_table[lp->ppp_slot];
++ printk(KERN_DEBUG "Received CCP frame from peer\n");
+ isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
+
+- if(lp->master) {
+- int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+- if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "%s: slot(%d) out of range\n",
+- __FUNCTION__, slot);
+- return;
+- }
+- mis = ippp_table[slot];
+- } else
++ if(lp->master)
++ mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot];
++ else
+ mis = is;
+
+ switch(skb->data[0]) {
+@@ -2806,18 +2617,13 @@
+
+ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
+ {
+- struct ippp_struct *mis,*is;
+- int proto, slot = lp->ppp_slot;
++ struct ippp_struct *mis,*is = ippp_table[lp->ppp_slot];
++ int proto;
+ unsigned char *data;
+
+ if(!skb || skb->len < 3)
+ return;
+- if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n",
+- __FUNCTION__, slot);
+- return;
+- }
+- is = ippp_table[slot];
++
+ /* Daemon may send with or without address and control field comp */
+ data = skb->data;
+ if(!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
+@@ -2833,17 +2639,12 @@
+ printk(KERN_DEBUG "Received CCP frame from daemon:\n");
+ isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
+
+- if (lp->master) {
+- slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+- if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+- printk(KERN_ERR "%s: slot(%d) out of range\n",
+- __FUNCTION__, slot);
+- return;
+- }
+- mis = ippp_table[slot];
+- } else
+- mis = is;
+- if (mis != is)
++ if(lp->master)
++ mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot];
++ else
++ mis = is;
++
++ if(mis != is)
+ printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
+
+ switch(data[2]) {
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_ppp.h linux-2.4.29/drivers/isdn/isdn_ppp.h
+--- linux-2.4.29.old/drivers/isdn/isdn_ppp.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_ppp.h 2005-03-22 15:06:44.497328160 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_ppp.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_ppp.h,v 1.18 2001/09/24 13:22:42 kai Exp $
+ *
+ * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
+ *
+@@ -19,7 +19,6 @@
+ extern void isdn_ppp_cleanup(void);
+ extern int isdn_ppp_free(isdn_net_local *);
+ extern int isdn_ppp_bind(isdn_net_local *);
+-extern int isdn_ppp_autodial_filter(struct sk_buff *, isdn_net_local *);
+ extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
+ extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
+ extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_tty.c linux-2.4.29/drivers/isdn/isdn_tty.c
+--- linux-2.4.29.old/drivers/isdn/isdn_tty.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_tty.c 2005-03-22 15:06:44.524324056 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_tty.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_tty.c,v 1.104 2002/02/09 21:19:11 keil Exp $
+ *
+ * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
+ *
+@@ -53,7 +53,7 @@
+ static int si2bit[8] =
+ {4, 1, 4, 4, 4, 4, 4, 4};
+
+-char *isdn_tty_revision = "$Revision: 1.1.4.1 $";
++char *isdn_tty_revision = "$Revision: 1.104 $";
+
+
+ /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
+@@ -321,7 +321,10 @@
+ info->send_outstanding++;
+ info->msr &= ~UART_MSR_CTS;
+ info->lsr &= ~UART_LSR_TEMT;
+- tty_wakeup(tty);
++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++ tty->ldisc.write_wakeup)
++ (tty->ldisc.write_wakeup) (tty);
++ wake_up_interruptible(&tty->write_wait);
+ return;
+ }
+ if (slen < 0) {
+@@ -1211,7 +1214,10 @@
+ /* If DLE decoding results in zero-transmit, but
+ * c originally was non-zero, do a wakeup.
+ */
+- tty_wakeup(tty);
++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++ tty->ldisc.write_wakeup)
++ (tty->ldisc.write_wakeup) (tty);
++ wake_up_interruptible(&tty->write_wait);
+ info->msr |= UART_MSR_CTS;
+ info->lsr |= UART_LSR_TEMT;
+ }
+@@ -1232,6 +1238,7 @@
+ }
+ }
+ } else
++#ifdef ISDN_TTY_FCLASS1
+ if (TTY_IS_FCLASS1(info)) {
+ int cc = isdn_tty_handleDLEdown(info, m, c);
+
+@@ -1252,6 +1259,7 @@
+ info->xmit_count += cc;
+ } else
+ #endif
++#endif
+ info->xmit_count += c;
+ } else {
+ info->msr |= UART_MSR_CTS;
+@@ -1329,7 +1337,10 @@
+ isdn_tty_cleanup_xmit(info);
+ info->xmit_count = 0;
+ restore_flags(flags);
+- tty_wakeup(tty);
++ wake_up_interruptible(&tty->write_wait);
++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++ tty->ldisc.write_wakeup)
++ (tty->ldisc.write_wakeup) (tty);
+ }
+
+ static void
+@@ -1858,7 +1869,8 @@
+ isdn_tty_shutdown(info);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+- tty_ldisc_flush(tty);
++ if (tty->ldisc.flush_buffer)
++ tty->ldisc.flush_buffer(tty);
+ info->tty = 0;
+ info->ncarrier = 0;
+ tty->closing = 0;
+@@ -2306,6 +2318,22 @@
+ isdn_tty_at_cout("\r\n", info);
+ }
+ return 1;
++ case ISDN_STAT_ALERT:
++#ifdef ISDN_TTY_STAT_DEBUG
++ printk(KERN_DEBUG "tty_STAT_ALERT ttyI%d\n", info->line);
++#endif
++ /* Signal RINGING to tty-device if requested */
++ if (info->emu.mdmreg[REG_ALERT] & BIT_ALERT)
++ isdn_tty_modem_result(RESULT_RINGING, info);
++ return 1;
++ case ISDN_STAT_PROCEED:
++#ifdef ISDN_TTY_STAT_DEBUG
++ printk(KERN_DEBUG "tty_STAT_PROCEED ttyI%d\n", info->line);
++#endif
++ /* Signal PROCEEDING to tty-device if requested */
++ if (info->emu.mdmreg[REG_PROCEED] & BIT_PROCEED)
++ isdn_tty_modem_result(RESULT_PROCEEDING, info);
++ return 1;
+ case ISDN_STAT_DCONN:
+ #ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
+@@ -2618,7 +2646,7 @@
+ static char *msg[] =
+ {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR",
+ "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
+- "RINGING", "NO MSN/EAZ", "VCON", "RUNG"};
++ "RINGING", "NO MSN/EAZ", "VCON", "RUNG", "PROCEEDING"};
+ ulong flags;
+ char s[ISDN_MSNLEN+10];
+
+@@ -2781,7 +2809,8 @@
+ restore_flags(flags);
+ return;
+ }
+- tty_ldisc_flush(info->tty);
++ if (info->tty->ldisc.flush_buffer)
++ info->tty->ldisc.flush_buffer(info->tty);
+ if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
+ (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
+@@ -3296,9 +3325,11 @@
+ #ifdef CONFIG_ISDN_TTY_FAX
+ if (TTY_IS_FCLASS2(info))
+ sprintf(rs, "\r\n2");
++#ifdef ISDN_TTY_FCLASS1
+ else if (TTY_IS_FCLASS1(info))
+ sprintf(rs, "\r\n1");
+ #endif
++#endif
+ isdn_tty_at_cout(rs, info);
+ break;
+ case '=':
+@@ -3313,6 +3344,7 @@
+ m->mdmreg[REG_PSIZE] * 16;
+ break;
+ #ifdef CONFIG_ISDN_TTY_FAX
++#ifdef ISDN_TTY_FCLASS1
+ case '1':
+ p[0]++;
+ if (!(dev->global_features &
+@@ -3324,6 +3356,7 @@
+ info->xmit_size =
+ m->mdmreg[REG_PSIZE] * 16;
+ break;
++#endif
+ case '2':
+ p[0]++;
+ if (!(dev->global_features &
+@@ -3348,9 +3381,11 @@
+ p[0]++;
+ strcpy(rs, "\r\n0,");
+ #ifdef CONFIG_ISDN_TTY_FAX
++#ifdef ISDN_TTY_FCLASS1
+ if (dev->global_features &
+ ISDN_FEATURE_L3_FCLASS1)
+ strcat(rs, "1,");
++#endif
+ if (dev->global_features &
+ ISDN_FEATURE_L3_FCLASS2)
+ strcat(rs, "2,");
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_tty.h linux-2.4.29/drivers/isdn/isdn_tty.h
+--- linux-2.4.29.old/drivers/isdn/isdn_tty.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_tty.h 2005-03-22 15:06:44.545320864 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_tty.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_tty.h,v 1.25 2002/02/09 21:19:11 keil Exp $
+ *
+ * header for Linux ISDN subsystem, tty related functions (linklevel).
+ *
+@@ -78,6 +78,10 @@
+ #define BIT_CPNFCON 2
+ #define REG_CDN 23
+ #define BIT_CDN 4
++#define REG_ALERT 23
++#define BIT_ALERT 8
++#define REG_PROCEED 23
++#define BIT_PROCEED 16
+
+ /* defines for result codes */
+ #define RESULT_OK 0
+@@ -93,10 +97,13 @@
+ #define RESULT_NO_MSN_EAZ 10
+ #define RESULT_VCON 11
+ #define RESULT_RUNG 12
++#define RESULT_PROCEEDING 13
+
++#ifdef ISDN_TTY_FCLASS1
+ #define TTY_IS_FCLASS1(info) \
+ ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
+ (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1))
++#endif
+ #define TTY_IS_FCLASS2(info) \
+ ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
+ (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2))
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_ttyfax.c linux-2.4.29/drivers/isdn/isdn_ttyfax.c
+--- linux-2.4.29.old/drivers/isdn/isdn_ttyfax.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_ttyfax.c 2005-03-22 15:06:44.561318432 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_ttyfax.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_ttyfax.c,v 1.9 2001/09/24 13:22:43 kai Exp $
+ *
+ * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel).
+ *
+@@ -20,7 +20,7 @@
+ #include "isdn_ttyfax.h"
+
+
+-static char *isdn_tty_fax_revision = "$Revision: 1.1.4.1 $";
++static char *isdn_tty_fax_revision = "$Revision: 1.9 $";
+
+ #define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; }
+
+@@ -148,6 +148,7 @@
+ }
+ }
+
++#ifdef ISDN_TTY_FCLASS1
+ int
+ isdn_tty_fax_command1(modem_info * info, isdn_ctrl * c)
+ {
+@@ -186,6 +187,7 @@
+ }
+ return (0);
+ }
++#endif
+
+ int
+ isdn_tty_fax_command(modem_info * info, isdn_ctrl * c)
+@@ -193,8 +195,10 @@
+ T30_s *f = info->fax;
+ char rs[10];
+
++#ifdef ISDN_TTY_FCLASS1
+ if (TTY_IS_FCLASS1(info))
+ return (isdn_tty_fax_command1(info, c));
++#endif
+
+ #ifdef ISDN_TTY_FAX_CMD_DEBUG
+ printk(KERN_DEBUG "isdn_tty: Fax cmd %d on ttyI%d\n",
+@@ -312,6 +316,7 @@
+ }
+ }
+
++#ifdef ISDN_TTY_FCLASS1
+ /*
+ * Parse AT+F.. FAX class 1 commands
+ */
+@@ -403,6 +408,7 @@
+ }
+ return 1;
+ }
++#endif
+
+ /*
+ * Parse AT+F.. FAX class 2 commands
+@@ -970,6 +976,70 @@
+ }
+ return 0;
+ }
++#if 0
++ /* LO=n - Flow control opts */
++ if (!strncmp(p[0], "LO", 2)) { /* TODO */
++ p[0] += 2;
++ switch (*p[0]) {
++ case '?':
++ p[0]++;
++ sprintf(rs, "\r\n%d", f->lo);
++ isdn_tty_at_cout(rs, info);
++ break;
++ case '=':
++ p[0]++;
++ if (*p[0] == '?') {
++ p[0]++;
++ sprintf(rs, "\r\n0,1,2");
++ isdn_tty_at_cout(rs, info);
++ } else {
++ par = isdn_getnum(p);
++ if ((par < 0) || (par > 2))
++ PARSE_ERROR1;
++ f->lo = par;
++#ifdef ISDN_TTY_FAX_STAT_DEBUG
++ printk(KERN_DEBUG "isdn_tty: Fax FLO=%d\n", par);
++#endif
++ }
++ break;
++ default:
++ PARSE_ERROR1;
++ }
++ return 0;
++ }
++#endif
++#if 0
++ /* LPL=n - Doc for polling cmd */
++ if (!strncmp(p[0], "LPL", 3)) { /* TODO */
++ p[0] += 3;
++ switch (*p[0]) {
++ case '?':
++ p[0]++;
++ sprintf(rs, "\r\n%d", f->lpl);
++ isdn_tty_at_cout(rs, info);
++ break;
++ case '=':
++ p[0]++;
++ if (*p[0] == '?') {
++ p[0]++;
++ sprintf(rs, "\r\n0,1");
++ isdn_tty_at_cout(rs, info);
++ } else {
++ par = isdn_getnum(p);
++ if ((par < 0) || (par > 1))
++ PARSE_ERROR1;
++ f->lpl = par;
++#ifdef ISDN_TTY_FAX_STAT_DEBUG
++ printk(KERN_DEBUG "isdn_tty: Fax FLPL=%d\n", par);
++#endif
++ }
++ break;
++ default:
++ PARSE_ERROR1;
++ }
++ return 0;
++ }
++#endif
+
+ /* MDL? - DCE Model */
+ if (!strncmp(p[0], "MDL?", 4)) {
+@@ -1049,6 +1119,38 @@
+ }
+ return 0;
+ }
++#if 0
++ /* PTS=n - Page transfer status */
++ if (!strncmp(p[0], "PTS", 3)) { /* TODO */
++ p[0] += 3;
++ switch (*p[0]) {
++ case '?':
++ p[0]++;
++ sprintf(rs, "\r\n%d", f->pts);
++ isdn_tty_at_cout(rs, info);
++ break;
++ case '=':
++ p[0]++;
++ if (*p[0] == '?') {
++ p[0]++;
++ sprintf(rs, "\r\n0-5");
++ isdn_tty_at_cout(rs, info);
++ } else {
++ par = isdn_getnum(p);
++ if ((par < 0) || (par > 5))
++ PARSE_ERROR1;
++ f->pts = par;
++#ifdef ISDN_TTY_FAX_STAT_DEBUG
++ printk(KERN_DEBUG "isdn_tty: Fax FPTS=%d\n", par);
++#endif
++ }
++ break;
++ default:
++ PARSE_ERROR1;
++ }
++ return 0;
++ }
++#endif
+
+ /* REL=n - Phase C received EOL alignment */
+ if (!strncmp(p[0], "REL", 3)) {
+@@ -1091,6 +1193,38 @@
+ isdn_tty_at_cout(rs, info);
+ return 0;
+ }
++#if 0
++ /* SPL=n - Enable polling */
++ if (!strncmp(p[0], "SPL", 3)) { /* TODO */
++ p[0] += 3;
++ switch (*p[0]) {
++ case '?':
++ p[0]++;
++ sprintf(rs, "\r\n%d", f->spl);
++ isdn_tty_at_cout(rs, info);
++ break;
++ case '=':
++ p[0]++;
++ if (*p[0] == '?') {
++ p[0]++;
++ sprintf(rs, "\r\n0,1");
++ isdn_tty_at_cout(rs, info);
++ } else {
++ par = isdn_getnum(p);
++ if ((par < 0) || (par > 1))
++ PARSE_ERROR1;
++ f->spl = par;
++#ifdef ISDN_TTY_FAX_STAT_DEBUG
++ printk(KERN_DEBUG "isdn_tty: Fax FSPL=%d\n", par);
++#endif
++ }
++ break;
++ default:
++ PARSE_ERROR1;
++ }
++ return 0;
++ }
++#endif
+
+ /* Phase C Transmit Data Block Size */
+ if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */
+@@ -1116,7 +1250,9 @@
+ {
+ if (TTY_IS_FCLASS2(info))
+ return (isdn_tty_cmd_FCLASS2(p, info));
++#ifdef ISDN_TTY_FCLASS1
+ else if (TTY_IS_FCLASS1(info))
+ return (isdn_tty_cmd_FCLASS1(p, info));
++#endif
+ PARSE_ERROR1;
+ }
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_ttyfax.h linux-2.4.29/drivers/isdn/isdn_ttyfax.h
+--- linux-2.4.29.old/drivers/isdn/isdn_ttyfax.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_ttyfax.h 2005-03-22 15:06:44.576316152 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_ttyfax.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_ttyfax.h,v 1.3 2001/09/24 13:22:43 kai Exp $
+ *
+ * header for Linux ISDN subsystem, tty_fax related functions (linklevel).
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_v110.c linux-2.4.29/drivers/isdn/isdn_v110.c
+--- linux-2.4.29.old/drivers/isdn/isdn_v110.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_v110.c 2005-03-22 15:06:44.593313568 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_v110.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_v110.c,v 1.8 2001/09/24 13:22:43 kai Exp $
+ *
+ * Linux ISDN subsystem, V.110 related functions (linklevel).
+ *
+@@ -19,7 +19,7 @@
+
+ #undef ISDN_V110_DEBUG
+
+-char *isdn_v110_revision = "$Revision: 1.1.4.1 $";
++char *isdn_v110_revision = "$Revision: 1.8 $";
+
+ #define V110_38400 255
+ #define V110_19200 15
+@@ -138,6 +138,14 @@
+ return;
+ #ifdef ISDN_V110_DEBUG
+ printk(KERN_DEBUG "v110 close\n");
++#if 0
++ printk(KERN_DEBUG "isdn_v110_close: nbytes=%d\n", v->nbytes);
++ printk(KERN_DEBUG "isdn_v110_close: nbits=%d\n", v->nbits);
++ printk(KERN_DEBUG "isdn_v110_close: key=%d\n", v->key);
++ printk(KERN_DEBUG "isdn_v110_close: SyncInit=%d\n", v->SyncInit);
++ printk(KERN_DEBUG "isdn_v110:close: decodelen=%d\n", v->decodelen);
++ printk(KERN_DEBUG "isdn_v110_close: framelen=%d\n", v->framelen);
++#endif
+ #endif
+ kfree(v->encodebuf);
+ kfree(v);
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_v110.h linux-2.4.29/drivers/isdn/isdn_v110.h
+--- linux-2.4.29.old/drivers/isdn/isdn_v110.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_v110.h 2005-03-22 15:06:44.608311288 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_v110.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_v110.h,v 1.5 2001/09/24 13:22:43 kai Exp $
+ *
+ * Linux ISDN subsystem, V.110 related functions (linklevel).
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_x25iface.c linux-2.4.29/drivers/isdn/isdn_x25iface.c
+--- linux-2.4.29.old/drivers/isdn/isdn_x25iface.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_x25iface.c 2005-03-22 15:06:44.626308552 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_x25iface.c,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_x25iface.c,v 1.10 2001/09/24 13:22:43 kai Exp $
+ *
+ * Linux ISDN subsystem, X.25 related functions
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/isdn_x25iface.h linux-2.4.29/drivers/isdn/isdn_x25iface.h
+--- linux-2.4.29.old/drivers/isdn/isdn_x25iface.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdn_x25iface.h 2005-03-22 15:06:44.645305664 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_x25iface.h,v 1.1.4.1 2001/11/20 14:19:34 kai Exp $
++/* $Id: isdn_x25iface.h,v 1.4 2001/09/24 13:22:43 kai Exp $
+ *
+ * header for Linux ISDN subsystem, x.25 related functions
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/isdnloop/isdnloop.c linux-2.4.29/drivers/isdn/isdnloop/isdnloop.c
+--- linux-2.4.29.old/drivers/isdn/isdnloop/isdnloop.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdnloop/isdnloop.c 2005-03-22 15:06:48.813671976 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdnloop.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id: isdnloop.c,v 1.17 2001/08/30 10:45:42 kai Exp $
+ *
+ * ISDN low-level module implementing a dummy loop driver.
+ *
+@@ -14,7 +14,7 @@
+ #include <linux/init.h>
+ #include "isdnloop.h"
+
+-static char *revision = "$Revision: 1.1.4.1 $";
++static char *revision = "$Revision$";
+ static char *isdnloop_id;
+
+ MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card");
+@@ -22,8 +22,8 @@
+ MODULE_LICENSE("GPL");
+ MODULE_PARM(isdnloop_id, "s");
+ MODULE_PARM_DESC(isdnloop_id, "ID-String of first card");
+-
+-static int isdnloop_addcard(char *);
++
++ static int isdnloop_addcard(char *);
+
+ /*
+ * Free queue completely.
+@@ -1542,11 +1542,7 @@
+ } else
+ strcpy(rev, " ??? ");
+ printk(KERN_NOTICE "isdnloop-ISDN-driver Rev%s\n", rev);
+-
+- if (isdnloop_id)
+- return (isdnloop_addcard(isdnloop_id));
+-
+- return 0;
++ return (isdnloop_addcard(isdnloop_id));
+ }
+
+ static void __exit
+diff -rNu linux-2.4.29.old/drivers/isdn/isdnloop/isdnloop.h linux-2.4.29/drivers/isdn/isdnloop/isdnloop.h
+--- linux-2.4.29.old/drivers/isdn/isdnloop/isdnloop.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/isdnloop/isdnloop.h 2005-03-22 15:06:48.834668784 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdnloop.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Loopback lowlevel module for testing of linklevel.
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/pcbit/callbacks.c linux-2.4.29/drivers/isdn/pcbit/callbacks.c
+--- linux-2.4.29.old/drivers/isdn/pcbit/callbacks.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/pcbit/callbacks.c 2005-03-22 15:06:48.909657384 +0100
+@@ -3,7 +3,7 @@
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+- * Written by Pedro Roque Marques (pedro_m@yahoo.com)
++ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+diff -rNu linux-2.4.29.old/drivers/isdn/pcbit/callbacks.h linux-2.4.29/drivers/isdn/pcbit/callbacks.h
+--- linux-2.4.29.old/drivers/isdn/pcbit/callbacks.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/pcbit/callbacks.h 2005-03-22 15:06:48.953650696 +0100
+@@ -3,7 +3,7 @@
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+- * Written by Pedro Roque Marques (pedro_m@yahoo.com)
++ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+diff -rNu linux-2.4.29.old/drivers/isdn/pcbit/capi.c linux-2.4.29/drivers/isdn/pcbit/capi.c
+--- linux-2.4.29.old/drivers/isdn/pcbit/capi.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/pcbit/capi.c 2005-03-22 15:06:49.042637168 +0100
+@@ -4,7 +4,7 @@
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+- * Written by Pedro Roque Marques (pedro_m@yahoo.com)
++ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+diff -rNu linux-2.4.29.old/drivers/isdn/pcbit/capi.h linux-2.4.29/drivers/isdn/pcbit/capi.h
+--- linux-2.4.29.old/drivers/isdn/pcbit/capi.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/pcbit/capi.h 2005-03-22 15:06:49.071632760 +0100
+@@ -3,7 +3,7 @@
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+- * Written by Pedro Roque Marques (pedro_m@yahoo.com)
++ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+@@ -63,7 +63,8 @@
+ extern int capi_decode_debug_188(u_char *hdr, ushort hdrlen);
+ #endif
+
+-static inline struct pcbit_chan *
++extern __inline__
++struct pcbit_chan *
+ capi_channel(struct pcbit_dev *dev, struct sk_buff *skb)
+ {
+ ushort callref;
+diff -rNu linux-2.4.29.old/drivers/isdn/pcbit/drv.c linux-2.4.29/drivers/isdn/pcbit/drv.c
+--- linux-2.4.29.old/drivers/isdn/pcbit/drv.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/pcbit/drv.c 2005-03-22 15:06:49.091629720 +0100
+@@ -3,7 +3,7 @@
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+- * Written by Pedro Roque Marques (pedro_m@yahoo.com)
++ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+@@ -35,7 +35,9 @@
+ #include <linux/isdnif.h>
+ #include <asm/string.h>
+ #include <asm/io.h>
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ #include <linux/ioport.h>
++#endif
+
+ #include "pcbit.h"
+ #include "edss1.h"
+@@ -89,6 +91,7 @@
+
+ if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF ) {
+ dev->ph_mem = mem_base;
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ if (check_mem_region(dev->ph_mem, 4096)) {
+ printk(KERN_WARNING
+ "PCBIT: memory region %lx-%lx already in use\n",
+@@ -100,6 +103,9 @@
+ request_mem_region(dev->ph_mem, 4096, "PCBIT mem");
+ }
+ dev->sh_mem = (unsigned char*)ioremap(dev->ph_mem, 4096);
++#else
++ dev->sh_mem = (unsigned char*) mem_base;
++#endif
+ }
+ else
+ {
+@@ -112,8 +118,10 @@
+ dev->b1 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
+ if (!dev->b1) {
+ printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ iounmap((unsigned char*)dev->sh_mem);
+ release_mem_region(dev->ph_mem, 4096);
++#endif
+ kfree(dev);
+ return -ENOMEM;
+ }
+@@ -122,8 +130,10 @@
+ if (!dev->b2) {
+ printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
+ kfree(dev->b1);
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ iounmap((unsigned char*)dev->sh_mem);
+ release_mem_region(dev->ph_mem, 4096);
++#endif
+ kfree(dev);
+ return -ENOMEM;
+ }
+@@ -144,8 +154,10 @@
+ {
+ kfree(dev->b1);
+ kfree(dev->b2);
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ iounmap((unsigned char*)dev->sh_mem);
+ release_mem_region(dev->ph_mem, 4096);
++#endif
+ kfree(dev);
+ dev_pcbit[board] = NULL;
+ return -EIO;
+@@ -166,8 +178,10 @@
+ free_irq(irq, dev);
+ kfree(dev->b1);
+ kfree(dev->b2);
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ iounmap((unsigned char*)dev->sh_mem);
+ release_mem_region(dev->ph_mem, 4096);
++#endif
+ kfree(dev);
+ dev_pcbit[board] = NULL;
+ return -EIO;
+@@ -197,8 +211,10 @@
+ free_irq(irq, dev);
+ kfree(dev->b1);
+ kfree(dev->b2);
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ iounmap((unsigned char*)dev->sh_mem);
+ release_mem_region(dev->ph_mem, 4096);
++#endif
+ kfree(dev);
+ dev_pcbit[board] = NULL;
+ return -EIO;
+@@ -235,8 +251,10 @@
+ del_timer(&dev->b2->fsm_timer);
+ kfree(dev->b1);
+ kfree(dev->b2);
++#ifdef COMPAT_HAS_ISA_IOREMAP
+ iounmap((unsigned char*)dev->sh_mem);
+ release_mem_region(dev->ph_mem, 4096);
++#endif
+ kfree(dev);
+ }
+ }
+@@ -430,7 +448,7 @@
+ switch(dev->l2_state) {
+ case L2_LWMODE:
+ /* check (size <= rdp_size); write buf into board */
+- if (len < 0 || len > BANK4 + 1)
++ if (len > BANK4 + 1)
+ {
+ printk("pcbit_writecmd: invalid length %d\n", len);
+ return -EINVAL;
+@@ -609,6 +627,20 @@
+ dev->b1->s_refnum,
+ dev->b2->s_refnum);
+ #endif
++#if 0
++ if (dev->b1->s_refnum == refnum)
++ chan = dev->b1;
++ else {
++
++ if (dev->b2->s_refnum == refnum)
++ chan = dev->b2;
++ else {
++ chan = NULL;
++ printk(KERN_WARNING "Connection Confirm - refnum doesn't match chan\n");
++ break;
++ }
++ }
++#else
+ /* We just try to find a channel in the right state */
+
+ if (dev->b1->fsm_state == ST_CALL_INIT)
+@@ -622,6 +654,7 @@
+ break;
+ }
+ }
++#endif
+ if (capi_decode_conn_conf(chan, skb, &complete)) {
+ printk(KERN_DEBUG "conn_conf indicates error\n");
+ pcbit_fsm_event(dev, chan, EV_ERROR, NULL);
+diff -rNu linux-2.4.29.old/drivers/isdn/pcbit/edss1.c linux-2.4.29/drivers/isdn/pcbit/edss1.c
+--- linux-2.4.29.old/drivers/isdn/pcbit/edss1.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/pcbit/edss1.c 2005-03-22 15:06:49.119625464 +0100
+@@ -4,7 +4,7 @@
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+- * Written by Pedro Roque Marques (pedro_m@yahoo.com)
++ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+diff -rNu linux-2.4.29.old/drivers/isdn/pcbit/edss1.h linux-2.4.29/drivers/isdn/pcbit/edss1.h
+--- linux-2.4.29.old/drivers/isdn/pcbit/edss1.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/pcbit/edss1.h 2005-03-22 15:06:49.161619080 +0100
+@@ -3,7 +3,7 @@
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+- * Written by Pedro Roque Marques (pedro_m@yahoo.com)
++ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+diff -rNu linux-2.4.29.old/drivers/isdn/pcbit/layer2.c linux-2.4.29/drivers/isdn/pcbit/layer2.c
+--- linux-2.4.29.old/drivers/isdn/pcbit/layer2.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/pcbit/layer2.c 2005-03-22 15:06:49.195613912 +0100
+@@ -3,7 +3,7 @@
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+- * Written by Pedro Roque Marques (pedro_m@yahoo.com)
++ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+@@ -369,11 +369,16 @@
+
+ if (dev->read_frame) {
+ printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n");
++#if 0
++ pcbit_l2_error(dev);
++ return;
++#else
+ /* discard previous queued frame */
+ if (dev->read_frame->skb)
+ kfree_skb(dev->read_frame->skb);
+ kfree(dev->read_frame);
+ dev->read_frame = NULL;
++#endif
+ }
+ frame = kmalloc(sizeof(struct frame_buf), GFP_ATOMIC);
+
+@@ -449,10 +454,14 @@
+
+ if (!(frame = dev->read_frame)) {
+ printk("Type 1 frame and no frame queued\n");
++#if 1
+ /* usually after an error: toss frame */
+ dev->readptr += tt;
+ if (dev->readptr > dev->sh_mem + BANK2 + BANKLEN)
+ dev->readptr -= BANKLEN;
++#else
++ pcbit_l2_error(dev);
++#endif
+ return;
+
+ }
+diff -rNu linux-2.4.29.old/drivers/isdn/pcbit/layer2.h linux-2.4.29/drivers/isdn/pcbit/layer2.h
+--- linux-2.4.29.old/drivers/isdn/pcbit/layer2.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/pcbit/layer2.h 2005-03-22 15:06:49.228608896 +0100
+@@ -3,7 +3,7 @@
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+- * Written by Pedro Roque Marques (pedro_m@yahoo.com)
++ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+diff -rNu linux-2.4.29.old/drivers/isdn/pcbit/module.c linux-2.4.29/drivers/isdn/pcbit/module.c
+--- linux-2.4.29.old/drivers/isdn/pcbit/module.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/pcbit/module.c 2005-03-22 15:06:49.251605400 +0100
+@@ -3,7 +3,7 @@
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+- * Written by Pedro Roque Marques (pedro_m@yahoo.com)
++ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+@@ -92,6 +92,7 @@
+ }
+
+ #ifndef MODULE
++#ifdef COMPAT_HAS_NEW_SETUP
+ #define MAX_PARA (MAX_PCBIT_CARDS * 2)
+ static int __init pcbit_setup(char *line)
+ {
+@@ -100,6 +101,11 @@
+ int ints[MAX_PARA+1];
+
+ str = get_options(line, MAX_PARA, ints);
++#else
++void pcbit_setup(char *str, int *ints)
++{
++ int i, j, argc;
++#endif
+ argc = ints[0];
+ i = 0;
+ j = 1;
+@@ -118,9 +124,13 @@
+
+ i++;
+ }
++#ifdef COMPAT_HAS_NEW_SETUP
+ return(1);
+ }
+ __setup("pcbit=", pcbit_setup);
++#else
++}
++#endif
+ #endif
+
+ module_init(pcbit_init);
+diff -rNu linux-2.4.29.old/drivers/isdn/pcbit/pcbit.h linux-2.4.29/drivers/isdn/pcbit/pcbit.h
+--- linux-2.4.29.old/drivers/isdn/pcbit/pcbit.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/pcbit/pcbit.h 2005-03-22 15:06:49.284600384 +0100
+@@ -3,7 +3,7 @@
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+- * Written by Pedro Roque Marques (pedro_m@yahoo.com)
++ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+diff -rNu linux-2.4.29.old/drivers/isdn/sc/card.h linux-2.4.29/drivers/isdn/sc/card.h
+--- linux-2.4.29.old/drivers/isdn/sc/card.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/sc/card.h 2005-03-22 15:06:49.333592936 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: card.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Driver parameters for SpellCaster ISA ISDN adapters
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/sc/command.c linux-2.4.29/drivers/isdn/sc/command.c
+--- linux-2.4.29.old/drivers/isdn/sc/command.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/sc/command.c 2005-03-22 15:06:49.348590656 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: command.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+@@ -95,7 +95,7 @@
+ if(adapter[i]->driverId == driver)
+ return i;
+ }
+- return -ENODEV;
++ return -NODEV;
+ }
+
+ /*
+diff -rNu linux-2.4.29.old/drivers/isdn/sc/debug.c linux-2.4.29/drivers/isdn/sc/debug.c
+--- linux-2.4.29.old/drivers/isdn/sc/debug.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/sc/debug.c 2005-03-22 15:06:49.363588376 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: debug.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/sc/debug.h linux-2.4.29/drivers/isdn/sc/debug.h
+--- linux-2.4.29.old/drivers/isdn/sc/debug.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/sc/debug.h 2005-03-22 15:06:49.378586096 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: debug.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/sc/event.c linux-2.4.29/drivers/isdn/sc/event.c
+--- linux-2.4.29.old/drivers/isdn/sc/event.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/sc/event.c 2005-03-22 15:06:49.394583664 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: event.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/sc/init.c linux-2.4.29/drivers/isdn/sc/init.c
+--- linux-2.4.29.old/drivers/isdn/sc/init.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/sc/init.c 2005-03-22 15:06:49.432577888 +0100
+@@ -514,6 +514,15 @@
+ schedule_timeout(HZ);
+ sig = readl(rambase + SIG_OFFSET);
+ pr_debug("Looking for a signature, got 0x%x\n", sig);
++#if 0
++/*
++ * For Gary:
++ * If it's a timing problem, it should be gone with the above schedule()
++ * Another possible reason may be the missing volatile in the original
++ * code. readl() does this for us.
++ */
++ printk(""); /* Hack! Doesn't work without this !!!??? */
++#endif
+ if(sig == SIGNATURE)
+ return PRI_BOARD;
+
+@@ -525,6 +534,9 @@
+ schedule_timeout(HZ);
+ sig = readl(rambase + SIG_OFFSET);
+ pr_debug("Looking for a signature, got 0x%x\n", sig);
++#if 0
++ printk(""); /* Hack! Doesn't work without this !!!??? */
++#endif
+ if(sig == SIGNATURE)
+ return BRI_BOARD;
+
+diff -rNu linux-2.4.29.old/drivers/isdn/sc/interrupt.c linux-2.4.29/drivers/isdn/sc/interrupt.c
+--- linux-2.4.29.old/drivers/isdn/sc/interrupt.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/sc/interrupt.c 2005-03-22 15:06:49.447575608 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: interrupt.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/sc/ioctl.c linux-2.4.29/drivers/isdn/sc/ioctl.c
+--- linux-2.4.29.old/drivers/isdn/sc/ioctl.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/sc/ioctl.c 2005-03-22 15:06:49.463573176 +0100
+@@ -23,6 +23,9 @@
+
+ extern board *adapter[];
+
++#if 0
++static char *ChannelStates[] = { "Idle", "Ready", "Connecting", "Connected", "Disconnecting" };
++#endif
+
+ int GetStatus(int card, boardInfo *);
+
+diff -rNu linux-2.4.29.old/drivers/isdn/sc/message.c linux-2.4.29/drivers/isdn/sc/message.c
+--- linux-2.4.29.old/drivers/isdn/sc/message.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/sc/message.c 2005-03-22 15:06:49.478570896 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: message.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * functions for sending and receiving control messages
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/sc/message.h linux-2.4.29/drivers/isdn/sc/message.h
+--- linux-2.4.29.old/drivers/isdn/sc/message.h 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/sc/message.h 2005-03-22 15:06:49.495568312 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: message.h,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/sc/packet.c linux-2.4.29/drivers/isdn/sc/packet.c
+--- linux-2.4.29.old/drivers/isdn/sc/packet.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/sc/packet.c 2005-03-22 15:06:49.514565424 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: packet.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/sc/shmem.c linux-2.4.29/drivers/isdn/sc/shmem.c
+--- linux-2.4.29.old/drivers/isdn/sc/shmem.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/sc/shmem.c 2005-03-22 15:06:49.560558432 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: shmem.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/sc/timer.c linux-2.4.29/drivers/isdn/sc/timer.c
+--- linux-2.4.29.old/drivers/isdn/sc/timer.c 2005-03-22 14:47:56.000000000 +0100
++++ linux-2.4.29/drivers/isdn/sc/timer.c 2005-03-22 15:06:49.575556152 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: timer.c,v 1.1.4.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Copyright (C) 1996 SpellCaster Telecommunications Inc.
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/tpam/tpam.h linux-2.4.29/drivers/isdn/tpam/tpam.h
+--- linux-2.4.29.old/drivers/isdn/tpam/tpam.h 2005-03-22 14:47:57.000000000 +0100
++++ linux-2.4.29/drivers/isdn/tpam/tpam.h 2005-03-22 15:06:49.648545056 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: tpam.h,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
++/* $Id: tpam.h,v 1.3 2001/09/24 13:23:12 kai Exp $
+ *
+ * Turbo PAM ISDN driver for Linux. (Kernel Driver)
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/tpam/tpam_commands.c linux-2.4.29/drivers/isdn/tpam/tpam_commands.c
+--- linux-2.4.29.old/drivers/isdn/tpam/tpam_commands.c 2005-03-22 14:47:57.000000000 +0100
++++ linux-2.4.29/drivers/isdn/tpam/tpam_commands.c 2005-03-22 15:06:49.664542624 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: tpam_commands.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
++/* $Id: tpam_commands.c,v 1.3 2001/09/24 13:23:12 kai Exp $
+ *
+ * Turbo PAM ISDN driver for Linux. (Kernel Driver - ISDN commands)
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/tpam/tpam_crcpc.c linux-2.4.29/drivers/isdn/tpam/tpam_crcpc.c
+--- linux-2.4.29.old/drivers/isdn/tpam/tpam_crcpc.c 2005-03-22 14:47:57.000000000 +0100
++++ linux-2.4.29/drivers/isdn/tpam/tpam_crcpc.c 2005-03-22 15:06:49.681540040 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: tpam_crcpc.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Turbo PAM ISDN driver for Linux. (Kernel Driver - CRC encoding)
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/tpam/tpam_hdlc.c linux-2.4.29/drivers/isdn/tpam/tpam_hdlc.c
+--- linux-2.4.29.old/drivers/isdn/tpam/tpam_hdlc.c 2005-03-22 14:47:57.000000000 +0100
++++ linux-2.4.29/drivers/isdn/tpam/tpam_hdlc.c 2005-03-22 15:06:49.702536848 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: tpam_hdlc.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
++/* $Id: tpam_hdlc.c,v 1.3 2001/09/24 13:23:12 kai Exp $
+ *
+ * Turbo PAM ISDN driver for Linux. (Kernel Driver - HDLC encoding)
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/tpam/tpam_main.c linux-2.4.29/drivers/isdn/tpam/tpam_main.c
+--- linux-2.4.29.old/drivers/isdn/tpam/tpam_main.c 2005-03-22 14:47:57.000000000 +0100
++++ linux-2.4.29/drivers/isdn/tpam/tpam_main.c 2005-03-22 15:06:49.717534568 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: tpam_main.c,v 1.1.2.2 2001/12/09 18:45:14 kai Exp $
++/* $Id$
+ *
+ * Turbo PAM ISDN driver for Linux. (Kernel Driver - main routines)
+ *
+@@ -254,7 +254,7 @@
+ name: "tpam",
+ id_table: tpam_pci_tbl,
+ probe: tpam_probe,
+- remove: __devexit_p(tpam_remove),
++ remove: tpam_remove,
+ };
+
+ static int __init tpam_init(void) {
+diff -rNu linux-2.4.29.old/drivers/isdn/tpam/tpam_memory.c linux-2.4.29/drivers/isdn/tpam/tpam_memory.c
+--- linux-2.4.29.old/drivers/isdn/tpam/tpam_memory.c 2005-03-22 14:47:57.000000000 +0100
++++ linux-2.4.29/drivers/isdn/tpam/tpam_memory.c 2005-03-22 15:06:49.734531984 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: tpam_memory.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Turbo PAM ISDN driver for Linux. (Kernel Driver - Board Memory Access)
+ *
+diff -rNu linux-2.4.29.old/drivers/isdn/tpam/tpam_nco.c linux-2.4.29/drivers/isdn/tpam/tpam_nco.c
+--- linux-2.4.29.old/drivers/isdn/tpam/tpam_nco.c 2005-03-22 14:47:57.000000000 +0100
++++ linux-2.4.29/drivers/isdn/tpam/tpam_nco.c 2005-03-22 15:06:49.749529704 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: tpam_nco.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Turbo PAM ISDN driver for Linux.
+ * (Kernel Driver - Low Level NCO Manipulation)
+diff -rNu linux-2.4.29.old/drivers/isdn/tpam/tpam_queues.c linux-2.4.29/drivers/isdn/tpam/tpam_queues.c
+--- linux-2.4.29.old/drivers/isdn/tpam/tpam_queues.c 2005-03-22 14:47:57.000000000 +0100
++++ linux-2.4.29/drivers/isdn/tpam/tpam_queues.c 2005-03-22 15:06:49.764527424 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: tpam_queues.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
++/* $Id$
+ *
+ * Turbo PAM ISDN driver for Linux. (Kernel Driver)
+ *
+@@ -146,7 +146,6 @@
+ do {
+ hpic = readl(card->bar0 + TPAM_HPIC_REGISTER);
+ if (waiting_too_long++ > 0xfffffff) {
+- kfree_skb(skb);
+ spin_unlock(&card->lock);
+ printk(KERN_ERR "TurboPAM(tpam_irq): "
+ "waiting too long...\n");
+diff -rNu linux-2.4.29.old/include/linux/b1lli.h linux-2.4.29/include/linux/b1lli.h
+--- linux-2.4.29.old/include/linux/b1lli.h 2005-03-22 14:47:32.000000000 +0100
++++ linux-2.4.29/include/linux/b1lli.h 2005-03-22 15:06:49.881509640 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: b1lli.h,v 1.8.8.3 2001/09/23 22:25:05 kai Exp $
++/* $Id$
+ *
+ * ISDN lowlevel-module for AVM B1-card.
+ *
+diff -rNu linux-2.4.29.old/include/linux/b1pcmcia.h linux-2.4.29/include/linux/b1pcmcia.h
+--- linux-2.4.29.old/include/linux/b1pcmcia.h 2005-03-22 14:47:32.000000000 +0100
++++ linux-2.4.29/include/linux/b1pcmcia.h 2005-03-22 15:06:49.862512528 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: b1pcmcia.h,v 1.1.8.2 2001/09/23 22:25:05 kai Exp $
++/* $Id$
+ *
+ * Exported functions of module b1pcmcia to be called by
+ * avm_cs card services module.
+diff -rNu linux-2.4.29.old/include/linux/capi.h linux-2.4.29/include/linux/capi.h
+--- linux-2.4.29.old/include/linux/capi.h 2005-03-22 14:47:32.000000000 +0100
++++ linux-2.4.29/include/linux/capi.h 2005-03-22 15:06:49.922503408 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: capi.h,v 1.1.4.1 2001/11/20 14:19:38 kai Exp $
++/* $Id$
+ *
+ * CAPI 2.0 Interface for Linux
+ *
+diff -rNu linux-2.4.29.old/include/linux/concap.h linux-2.4.29/include/linux/concap.h
+--- linux-2.4.29.old/include/linux/concap.h 2005-03-22 14:47:32.000000000 +0100
++++ linux-2.4.29/include/linux/concap.h 2005-03-22 15:06:49.906505840 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: concap.h,v 1.2.8.1 2001/09/23 22:25:05 kai Exp $
++/* $Id: concap.h,v 1.3 2001/09/24 13:23:13 kai Exp $
+ *
+ * Copyright 1997 by Henner Eisen <eis@baty.hanse.de>
+ *
+@@ -11,6 +11,7 @@
+ #ifdef __KERNEL__
+ #include <linux/skbuff.h>
+ #include <linux/netdevice.h>
++#include <linux/isdn_compat.h>
+
+ /* Stuff to support encapsulation protocols genericly. The encapsulation
+ protocol is processed at the uppermost layer of the network interface.
+diff -rNu linux-2.4.29.old/include/linux/hysdn_if.h linux-2.4.29/include/linux/hysdn_if.h
+--- linux-2.4.29.old/include/linux/hysdn_if.h 2005-03-22 14:47:32.000000000 +0100
++++ linux-2.4.29/include/linux/hysdn_if.h 2005-03-22 15:06:49.974495504 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: hysdn_if.h,v 1.1.8.3 2001/09/23 22:25:05 kai Exp $
++/* $Id$
+ *
+ * Linux driver for HYSDN cards
+ * ioctl definitions shared by hynetmgr and driver.
+diff -rNu linux-2.4.29.old/include/linux/isdn/tpam.h linux-2.4.29/include/linux/isdn/tpam.h
+--- linux-2.4.29.old/include/linux/isdn/tpam.h 2005-03-22 14:47:32.000000000 +0100
++++ linux-2.4.29/include/linux/isdn/tpam.h 2005-03-22 15:06:49.947499608 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: tpam.h,v 1.1.2.1 2001/11/20 14:19:38 kai Exp $
++/* $Id$
+ *
+ * Turbo PAM ISDN driver for Linux. (Kernel Driver)
+ *
+diff -rNu linux-2.4.29.old/include/linux/isdn.h linux-2.4.29/include/linux/isdn.h
+--- linux-2.4.29.old/include/linux/isdn.h 2005-03-22 14:47:31.000000000 +0100
++++ linux-2.4.29/include/linux/isdn.h 2005-03-22 15:06:50.001491400 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn.h,v 1.1.4.1 2001/11/20 14:19:38 kai Exp $
++/* $Id: isdn.h,v 1.125 2001/12/01 23:18:21 detabc Exp $
+ *
+ * Main header for the Linux ISDN subsystem (linklevel).
+ *
+@@ -14,6 +14,7 @@
+ #ifndef __ISDN_H__
+ #define __ISDN_H__
+
++#include <linux/isdn_compat.h>
+ #include <linux/ioctl.h>
+
+ #ifdef CONFIG_COBALT_MICRO_SERVER
+@@ -93,9 +94,15 @@
+ #define ISDN_LMSNLEN 255 /* Length of tty's Listen-MSN string */
+ #define ISDN_CMSGLEN 50 /* Length of CONNECT-Message to add for Modem */
+
++#ifdef BIG_PHONE_NUMBERS
+ #define ISDN_MSNLEN 32
+ #define NET_DV 0x06 /* Data version for isdn_net_ioctl_cfg */
+ #define TTY_DV 0x06 /* Data version for iprofd etc. */
++#else
++#define ISDN_MSNLEN 20
++#define NET_DV 0x05 /* Data version for isdn_net_ioctl_cfg */
++#define TTY_DV 0x05 /* Data version for iprofd etc. */
++#endif
+
+ #define INF_DV 0x01 /* Data version for /dev/isdninfo */
+
+@@ -187,6 +194,61 @@
+ #define ISDN_MINOR_PPPMAX (128 + (ISDN_MAX_CHANNELS-1))
+ #define ISDN_MINOR_STATUS 255
+
++#ifndef CONFIG_ISDN_WITH_ABC
++#undef CONFIG_ISDN_WITH_ABC_CALLB
++#undef CONFIG_ISDN_WITH_ABC_UDP_CHECK
++#undef CONFIG_ISDN_WITH_ABC_UDP_CHECK_HANGUP
++#undef CONFIG_ISDN_WITH_ABC_UDP_CHECK_DIAL
++#undef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++#undef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++#undef CONFIG_ISDN_WITH_ABC_RCV_NO_HUPTIMER
++#undef CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
++#undef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++#undef CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS
++#else /* CONFIG_ISDN_WITH_ABC */
++#include <linux/isdn_dwabc.h>
++
++
++typedef struct DWABCJIFFIES {
++
++ u_long msec_1000;
++ u_long msec_500;
++ u_long msec_400;
++ u_long msec_200;
++ u_long msec_100;
++
++} DWABCJIFFIES;
++
++
++#ifdef CONFIG_ISDN_WITH_ABC_NEED_DWSJIFFIES
++DWABCJIFFIES isdn_dwabc_jiffies;
++#else
++extern DWABCJIFFIES isdn_dwabc_jiffies;
++#endif
++#define dwsjiffies (isdn_dwabc_jiffies.msec_1000)
++
++#define ISDN_DW_ABC_FLAG_UNUSED00001 0x00000001L
++#define ISDN_DW_ABC_FLAG_NO_UDP_CHECK 0x00000002L
++#define ISDN_DW_ABC_FLAG_NO_UDP_HANGUP 0x00000004L
++#define ISDN_DW_ABC_FLAG_NO_UDP_DIAL 0x00000008L
++#define ISDN_DW_ABC_FLAG_UNUSED00010 0x00000010L
++#define ISDN_DW_ABC_FLAG_RCV_NO_HUPTIMER 0x00000020L
++#define ISDN_DW_ABC_FLAG_NO_CH_EXTINUSE 0x00000040L
++#define ISDN_DW_ABC_FLAG_NO_CONN_ERROR 0x00000080L
++#define ISDN_DW_ABC_FLAG_BSD_COMPRESS 0x00000100L
++#define ISDN_DW_ABC_FLAG_NO_LCR 0x00000200L
++#define ISDN_DW_ABC_FLAG_LEASED_LINE 0x00001000L
++
++#define ISDN_DW_ABC_IFFLAG_NODCHAN 0x00000001L
++#define ISDN_DW_ABC_IFFLAG_BSDAKTIV 0x00000002L
++
++#define ISDN_DW_ABC_BITLOCK_SEND 0
++#define ISDN_DW_ABC_BITLOCK_RECEIVE 1
++
++#endif /* CONFIG_ISDN_WITH_ABC */
++
++
++
+ #ifdef CONFIG_ISDN_PPP
+
+ #ifdef CONFIG_ISDN_PPP_VJ
+@@ -204,9 +266,11 @@
+ # include <linux/concap.h>
+ #endif
+
++#ifdef HAVE_DEVFS_FS
+ #ifdef CONFIG_DEVFS_FS
+ # include <linux/devfs_fs_kernel.h>
+ #endif
++#endif /* HAVE_DEVFS_FS */
+
+ #include <linux/isdnif.h>
+
+@@ -272,6 +336,12 @@
+ #define ISDN_NET_CALLBACK 0x04 /* activate callback */
+ #define ISDN_NET_CBHUP 0x08 /* hangup before callback */
+ #define ISDN_NET_CBOUT 0x10 /* remote machine does callback */
++#if 0
++/* Unused??? */
++#define ISDN_NET_CLONE 0x08 /* clone a tmp interface when called */
++#define ISDN_NET_TMP 0x10 /* tmp interface until getting an IP */
++#define ISDN_NET_DYNAMIC 0x20 /* this link is dynamically allocated */
++#endif
+
+ #define ISDN_NET_MAGIC 0x49344C02 /* for paranoia-checking */
+
+@@ -386,6 +456,38 @@
+ char cisco_debserint; /* debugging flag of cisco hdlc with slarp */
+ struct timer_list cisco_timer;
+ struct tq_struct tqueue;
++#ifdef CONFIG_ISDN_WITH_ABC
++ ulong dw_abc_flags;
++ ulong dw_abc_if_flags;
++ int dw_abc_inuse_secure;
++ ulong dw_abc_dialstart;
++ int dw_abc_old_onhtime;
++ int dw_abc_remote_version;
++ int dw_abc_bitlocks;
++#ifdef CONFIG_ISDN_WITH_ABC_OUTGOING_EAZ
++ char dw_out_msn[ISDN_MSNLEN]; /* eaz for outgoing call if *out_msn != 0 */
++#endif
++#ifdef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++ ulong dw_abc_lcr_callid;
++ ulong dw_abc_lcr_start_request;
++ ulong dw_abc_lcr_end_request;
++ isdn_ctrl *dw_abc_lcr_cmd;
++ struct ISDN_DWABC_LCR_IOCTL *dw_abc_lcr_io;
++#endif
++ ulong dw_abc_bchan_last_connect;
++#ifdef CONFIG_ISDN_WITH_ABC_CONN_ERROR
++ short dw_abc_bchan_errcnt;
++#endif
++#ifdef CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS
++ void *dw_abc_bsd_compressor;
++ void *dw_abc_bsd_stat_rx;
++ void *dw_abc_bsd_stat_tx;
++#endif
++ ulong dw_abc_bsd_snd;
++ ulong dw_abc_bsd_bsd_snd;
++ ulong dw_abc_bsd_rcv;
++ ulong dw_abc_bsd_bsd_rcv;
++#endif
+ } isdn_net_local;
+
+ /* the interface itself */
+@@ -608,12 +710,13 @@
+ int tflags; /* Timer-Flags: */
+ /* see ISDN_TIMER_..defines */
+ int global_flags;
+- infostruct *infochain; /* List of open info-devs. */
+- wait_queue_head_t info_waitq; /* Wait-Queue for isdninfo */
+ struct timer_list timer; /* Misc.-function Timer */
+ int chanmap[ISDN_MAX_CHANNELS];/* Map minor->device-channel */
+ int drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index */
+ int usage[ISDN_MAX_CHANNELS]; /* Used by tty/ip/voice */
++#ifdef CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
++ ulong dwabc_chan_external_inuse[ISDN_MAX_CHANNELS];
++#endif
+ char num[ISDN_MAX_CHANNELS][ISDN_MSNLEN];
+ /* Remote number of active ch.*/
+ int m_idx[ISDN_MAX_CHANNELS]; /* Index for mdm.... */
+@@ -631,6 +734,7 @@
+ isdn_v110_stream *v110[ISDN_MAX_CHANNELS]; /* V.110 private data */
+ struct semaphore sem; /* serialize list access*/
+ unsigned long global_features;
++#ifdef HAVE_DEVFS_FS
+ #ifdef CONFIG_DEVFS_FS
+ devfs_handle_t devfs_handle_isdninfo;
+ devfs_handle_t devfs_handle_isdnctrl;
+@@ -640,10 +744,41 @@
+ devfs_handle_t devfs_handle_ipppX[ISDN_MAX_CHANNELS];
+ #endif
+ #endif /* CONFIG_DEVFS_FS */
++#endif /* HAVE_DEVFS_FS */
+ } isdn_dev;
+
+ extern isdn_dev *dev;
+
++#ifdef CONFIG_ISDN_WITH_ABC
++extern int isdn_auto_dial_helper(isdn_net_local *,struct sk_buff *,int);
++extern void dwisdn_nfw_send(isdn_net_local *lp,int drop_only);
++extern void isdn_net_unreachable(struct net_device *,struct sk_buff *,char *);
++extern void isdn_net_log_skb_dwabc(struct sk_buff *,isdn_net_local *,char *);
++extern void isdn_net_hangup(struct net_device *d);
++extern void isdn_dw_clear_if(ulong pm,isdn_net_local *);
++extern void isdn_dwabc_test_phone(isdn_net_local *);
++extern void isdn_dw_abc_init_func(void);
++extern void isdn_dw_abc_release_func(void);
++extern int isdn_dw_abc_reset_interface(isdn_net_local *,int);
++extern int dwabc_bsd_init(isdn_net_local *lp);
++extern void dwabc_bsd_free(isdn_net_local *lp);
++extern struct sk_buff *dwabc_bsd_compress(isdn_net_local *,struct sk_buff *,struct net_device *);
++extern void dwabc_bsd_first_gen(isdn_net_local *);
++extern struct sk_buff *dwabc_bsd_rx_pkt(isdn_net_local *,struct sk_buff *,struct net_device *);
++#ifdef CONFIG_ISDN_WITH_ABC_LCR_SUPPORT
++extern size_t isdn_dw_abc_lcr_readstat(char *,size_t);
++extern ulong isdn_dw_abc_lcr_call_number(isdn_net_local *,isdn_ctrl *);
++extern void isdn_dw_abc_lcr_open(void);
++extern void isdn_dw_abc_lcr_close(void);
++extern int isdn_dw_abc_lcr_ioctl(ulong);
++extern void isdn_dw_abc_lcr_clear(isdn_net_local *);
++extern int isdn_dw_abc_lcr_lock(void);
++extern void isdn_dw_abc_lcr_ulock(void);
++#endif
++#ifdef CONFIG_ISDN_WITH_ABC_UDP_CHECK
++extern int dw_abc_udp_test(struct sk_buff *skb,struct net_device *ndev);
++#endif
++#endif
+
+ #endif /* __KERNEL__ */
+
+diff -rNu linux-2.4.29.old/include/linux/isdn_compat.h linux-2.4.29/include/linux/isdn_compat.h
+--- linux-2.4.29.old/include/linux/isdn_compat.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/include/linux/isdn_compat.h 2005-03-22 15:06:50.017488968 +0100
+@@ -0,0 +1,261 @@
++/* $Id: isdn_compat.h,v 1.53 2001/09/24 13:23:13 kai Exp $
++ *
++ * Linux ISDN subsystem
++ * Compatibility for various Linux kernel versions
++ *
++ * This software may be used and distributed according to the terms
++ * of the GNU General Public License, incorporated herein by reference.
++ *
++ */
++
++#ifndef _LINUX_ISDN_COMPAT_H
++#define _LINUX_ISDN_COMPAT_H
++
++#ifdef __KERNEL__
++
++#ifndef ISDN_COMPAT_NOT_GENERIC
++/* when using std2kern -u, this part is left out and instead provided
++ by the .ctrl files */
++
++#include <linux/version.h>
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)
++
++#define set_current_state(sta) (current->state = sta)
++#define module_init(x) int init_module(void) { return x(); }
++#define module_exit(x) void cleanup_module(void) { x(); }
++#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0 = 0; } while (0)
++#define init_MUTEX(x) *(x)=MUTEX
++#define init_MUTEX_LOCKED(x) *(x)=MUTEX_LOCKED
++#define __devinit
++#define __devinitdata
++
++#else /* 2.2.18 and later */
++
++#define COMPAT_HAS_NEW_SETUP
++#define COMPAT_HAS_NEW_WAITQ
++
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
++
++#define dev_kfree_skb_irq(a) dev_kfree_skb(a)
++#define dev_kfree_skb_any(a) dev_kfree_skb(a)
++#define COMPAT_HAS_2_2_PCI
++#define get_pcibase(ps, nr) ps->base_address[nr]
++#define pci_resource_start_io(pdev, nr) ((pdev)->base_address[nr] & PCI_BASE_ADDRESS_IO_MASK)
++#define pci_resource_start_mem(pdev, nr) ((pdev)->base_address[nr] & PCI_BASE_ADDRESS_MEM_MASK)
++#define pci_get_sub_vendor(pdev, id) pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &id)
++#define pci_get_sub_system(pdev, id) pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &id)
++
++#define __exit
++#define __devinit
++#define __devinitdata
++
++#define net_device device
++#define COMPAT_NO_SOFTNET
++#define netif_running(d) test_bit(LINK_STATE_START, &d->state)
++#define COMPAT_NEED_MPPP_DEFS
++#define spin_lock_bh(lock)
++#define spin_unlock_bh(lock)
++#define COMPAT_NEED_SPIN_LOCK_BH
++#define i_count_read(ic) ic
++#define i_count_inc(ic) ic++
++#define COMPAT_USE_MODCOUNT_LOCK
++#define devfs_register_chrdev(m,n,f) register_chrdev(m,n,f)
++#define devfs_unregister_chrdev(m,n) unregister_chrdev(m,n)
++#define COMPAT_NEED_PCI_IDS
++#define in_irq() (local_irq_count[smp_processor_id()] != 0)
++
++#else /* 2.4.0 and later */
++
++#define pci_resource_start_io(pdev, nr) pci_resource_start(pdev, nr)
++#define pci_resource_start_mem(pdev, nr) pci_resource_start(pdev, nr)
++#define get_pcibase(ps, nr) ps->resource[nr].start
++#define pci_get_sub_system(pdev, id) id = pdev->subsystem_device
++#define pci_get_sub_vendor(pdev, id) id = pdev->subsystem_vendor
++
++#define BIG_PHONE_NUMBERS
++#define COMPAT_HAS_ISA_IOREMAP
++#define i_count_read(ic) atomic_read(&ic)
++#define i_count_inc(ic) atomic_inc(&ic)
++#define COMPAT_HAS_FILEOP_OWNER
++#define COMPAT_HAVE_NEW_FILLDIR
++#define COMPAT_has_fileops_in_inode
++#define COMPAT_HAS_init_special_inode
++#define COMPAT_d_alloc_root_one_parameter
++#define HAVE_DEVFS_FS
++#define COMPAT_HAS_SCHEDULE_TASK
++#define COMPAT_HAS_USB_IDTAB
++
++#endif
++
++#endif /* ISDN_COMPAT_GENERIC */
++
++#ifdef COMPAT_HAS_2_2_PCI
++#include <linux/pci.h>
++#ifdef __powerpc__
++static inline int pci_enable_device(struct pci_dev *dev)
++{
++ u16 cmd;
++ pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO | PCI_COMMAND_SERR;
++ cmd &= ~PCI_COMMAND_FAST_BACK;
++ pci_write_config_word(dev, PCI_COMMAND, cmd);
++ return(0);
++}
++#else
++static inline int pci_enable_device(struct pci_dev *dev)
++{
++ return 0;
++}
++#endif /* __powerpc__ */
++
++#define PCI_ANY_ID (~0)
++
++/* as this is included multiple times, we make it inline */
++
++static inline struct pci_dev * pci_find_subsys(unsigned int vendor, unsigned int device,
++ unsigned int ss_vendor, unsigned int ss_device,
++ struct pci_dev *from)
++{
++ unsigned short subsystem_vendor, subsystem_device;
++
++ while ((from = pci_find_device(vendor, device, from))) {
++ pci_read_config_word(from, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
++ pci_read_config_word(from, PCI_SUBSYSTEM_ID, &subsystem_device);
++ if ((ss_vendor == PCI_ANY_ID || subsystem_vendor == ss_vendor) &&
++ (ss_device == PCI_ANY_ID || subsystem_device == ss_device))
++ return from;
++ }
++ return NULL;
++}
++#endif
++
++#ifdef COMPAT_NO_SOFTNET
++#include <linux/netdevice.h>
++
++/*
++ * Tell upper layers that the network device is ready to xmit more frames.
++ */
++static void __inline__ netif_wake_queue(struct net_device * dev)
++{
++ dev->tbusy = 0;
++ mark_bh(NET_BH);
++}
++
++/*
++ * called during net_device open()
++ */
++static void __inline__ netif_start_queue(struct net_device * dev)
++{
++ dev->tbusy = 0;
++ /* actually, we never use the interrupt flag at all */
++ dev->interrupt = 0;
++ dev->start = 1;
++}
++
++/*
++ * Ask upper layers to temporarily cease passing us more xmit frames.
++ */
++static void __inline__ netif_stop_queue(struct net_device * dev)
++{
++ dev->tbusy = 1;
++}
++
++#endif /* COMPAT_NO_SOFTNET */
++
++#ifndef COMPAT_HAS_NEW_WAITQ
++typedef struct wait_queue wait_queue_t;
++typedef struct wait_queue *wait_queue_head_t;
++
++#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL }
++#define DECLARE_WAIT_QUEUE_HEAD(wait) wait_queue_head_t wait
++#define init_waitqueue_head(x) *(x)=NULL
++#define init_waitqueue_entry(q,p) ((q)->task)=(p)
++#endif /* COMPAT_HAS_NEW_WAITQ */
++
++#ifdef COMPAT_NEED_PCI_IDS
++
++#define PCI_ANY_ID (~0)
++
++#define PCI_VENDOR_ID_DYNALINK 0x0675
++#define PCI_DEVICE_ID_DYNALINK_IS64PH 0x1702
++
++#define PCI_DEVICE_ID_WINBOND2_6692 0x6692
++
++#define PCI_DEVICE_ID_PLX_R685 0x1030
++#define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151
++#define PCI_DEVICE_ID_PLX_R753 0x1152
++
++#define PCI_VENDOR_ID_ELSA 0x1048
++#define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000
++#define PCI_DEVICE_ID_ELSA_QS3000 0x3000
++
++#define PCI_VENDOR_ID_EICON 0x1133
++#define PCI_DEVICE_ID_EICON_DIVA20PRO 0xe001
++#define PCI_DEVICE_ID_EICON_DIVA20 0xe002
++#define PCI_DEVICE_ID_EICON_DIVA20PRO_U 0xe003
++#define PCI_DEVICE_ID_EICON_DIVA20_U 0xe004
++#define PCI_DEVICE_ID_EICON_DIVA201 0xe005
++#define PCI_DEVICE_ID_EICON_MAESTRA 0xe010
++#define PCI_DEVICE_ID_EICON_MAESTRAQ 0xe012
++#define PCI_DEVICE_ID_EICON_MAESTRAQ_U 0xe013
++#define PCI_DEVICE_ID_EICON_MAESTRAP 0xe014
++
++#define PCI_VENDOR_ID_CCD 0x1397
++#define PCI_DEVICE_ID_CCD_2BD0 0x2BD0
++#define PCI_DEVICE_ID_CCD_B000 0xB000
++#define PCI_DEVICE_ID_CCD_B006 0xB006
++#define PCI_DEVICE_ID_CCD_B007 0xB007
++#define PCI_DEVICE_ID_CCD_B008 0xB008
++#define PCI_DEVICE_ID_CCD_B009 0xB009
++#define PCI_DEVICE_ID_CCD_B00A 0xB00A
++#define PCI_DEVICE_ID_CCD_B00B 0xB00B
++#define PCI_DEVICE_ID_CCD_B00C 0xB00C
++#define PCI_DEVICE_ID_CCD_B100 0xB100
++
++#define PCI_VENDOR_ID_ASUSTEK 0x1043
++#define PCI_DEVICE_ID_ASUSTEK_0675 0x0675
++
++#define PCI_VENDOR_ID_BERKOM 0x0871
++#define PCI_DEVICE_ID_BERKOM_A1T 0xFFA1
++#define PCI_DEVICE_ID_BERKOM_T_CONCEPT 0xFFA2
++#define PCI_DEVICE_ID_BERKOM_A4T 0xFFA4
++#define PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO 0xFFA8
++
++#define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016
++
++#define PCI_DEVICE_ID_TIGERJET_100 0x0002
++
++#define PCI_VENDOR_ID_ANIGMA 0x1051
++#define PCI_DEVICE_ID_ANIGMA_MC145575 0x0100
++
++#define PCI_VENDOR_ID_ZOLTRIX 0x15b0
++#define PCI_DEVICE_ID_ZOLTRIX_2BD0 0x2BD0
++
++#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_E 0x0070
++#define PCI_DEVICE_ID_DIGI_DF_M_E 0x0071
++#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A 0x0072
++#define PCI_DEVICE_ID_DIGI_DF_M_A 0x0073
++
++#define PCI_DEVICE_ID_AVM_B1 0x0700
++#define PCI_DEVICE_ID_AVM_C4 0x0800
++#define PCI_DEVICE_ID_AVM_C2 0x1100
++#define PCI_DEVICE_ID_AVM_T1 0x1200
++
++#define PCI_VENDOR_ID_HYPERCOPE 0x1365
++#define PCI_DEVICE_ID_HYPERCOPE_PLX 0x9050
++#define PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO 0x0104
++#define PCI_SUBDEVICE_ID_HYPERCOPE_ERGO 0x0106
++#define PCI_SUBDEVICE_ID_HYPERCOPE_METRO 0x0107
++#define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2 0x0108
++#define PCI_SUBDEVICE_ID_HYPERCOPE_PLEXUS 0x0109
++
++#define PCI_VENDOR_ID_ABOCOM 0x13D1
++#define PCI_DEVICE_ID_ABOCOM_2BD1 0x2BD1
++
++#endif /* COMPAT_NEED_PCI_IDS */
++
++#endif /* __KERNEL__ */
++#endif /* _LINUX_ISDN_COMPAT_H */
+diff -rNu linux-2.4.29.old/include/linux/isdn_divertif.h linux-2.4.29/include/linux/isdn_divertif.h
+--- linux-2.4.29.old/include/linux/isdn_divertif.h 2005-03-22 14:47:32.000000000 +0100
++++ linux-2.4.29/include/linux/isdn_divertif.h 2005-03-22 15:06:50.032486688 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_divertif.h,v 1.1.4.1 2001/11/20 14:19:38 kai Exp $
++/* $Id$
+ *
+ * Header for the diversion supplementary interface for i4l.
+ *
+@@ -14,7 +14,7 @@
+ /***********************************************************/
+ /* magic value is also used to control version information */
+ /***********************************************************/
+-#define DIVERT_IF_MAGIC 0x25873401
++#define DIVERT_IF_MAGIC 0x25873402
+ #define DIVERT_CMD_REG 0x00 /* register command */
+ #define DIVERT_CMD_REL 0x01 /* release command */
+ #define DIVERT_NO_ERR 0x00 /* return value no error */
+@@ -34,6 +34,7 @@
+ int (*ll_cmd)(isdn_ctrl *); /* supplied by hl on return */
+ char * (*drv_to_name)(int); /* map a driver id to name, supplied by hl */
+ int (*name_to_drv)(char *); /* map a driver id to name, supplied by hl */
++ int (*dial_net_name)(char *); /* force dial of a ll net interface */
+ } isdn_divert_if;
+
+ /*********************/
+diff -rNu linux-2.4.29.old/include/linux/isdn_dwabc.h linux-2.4.29/include/linux/isdn_dwabc.h
+--- linux-2.4.29.old/include/linux/isdn_dwabc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29/include/linux/isdn_dwabc.h 2005-03-22 15:06:50.048484256 +0100
+@@ -0,0 +1,84 @@
++/* $Id: isdn_dwabc.h,v 1.9 2001/09/26 20:32:08 detabc Exp $
++ *
++ * Header for the Linux ISDN abc-extension.
++ *
++ * Copyright by abc GmbH
++ * written by Detlef Wengorz <detlefw@isdn4linux.de>
++ *
++ * This software may be used and distributed according to the terms
++ * of the GNU General Public License, incorporated herein by reference.
++ *
++ */
++
++#ifndef ISDN_DWABC_H
++#define ISDN_DWABC_H
++
++#ifdef __KERNEL__
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/smp.h>
++#include <linux/spinlock.h>
++#include <linux/errno.h>
++
++
++typedef struct ISDN_DWSPINLOCK {
++
++ spinlock_t spin;
++ short owner;
++ short my_flags;
++ ulong irq_flags;
++
++} ISDN_DWSPINLOCK;
++
++#define ISDN_DWSPIN_UNLOCKED \
++ (ISDN_DWSPINLOCK) { \
++ spin: SPIN_LOCK_UNLOCKED, \
++ owner: -1, \
++ my_flags: 0, \
++ irq_flags: 0, \
++ }
++
++#define ISDN_DWSPIN_INIT(x) \
++ do { *(x) = ISDN_DWSPIN_UNLOCKED; } while(0);
++
++static __inline__ int isdn_dwspin_trylock(ISDN_DWSPINLOCK *spin)
++{
++ if(!spin_trylock(&spin->spin)) {
++
++ if(spin->owner == smp_processor_id())
++ return(-EAGAIN);
++
++ spin_lock(&spin->spin);
++ }
++
++ spin->owner = smp_processor_id();
++ return(0);
++}
++
++static __inline__ void isdn_dwspin_unlock(ISDN_DWSPINLOCK *spin)
++{
++ spin->owner = -1;
++ spin_unlock(&spin->spin);
++}
++
++
++#else
++#include <sys/types.h>
++#endif
++
++#define DWABC_LCR_FLG_NEWNUMBER 0x00000001L
++#define DWABC_LCR_FLG_DISABLE 0x00000002L
++#define DWABC_LCR_FLG_NEWHUPTIME 0x00000004L
++
++
++struct ISDN_DWABC_LCR_IOCTL {
++
++ int lcr_ioctl_sizeof; /* mustbe sizeof(ISDN_DWABC_LCR_IOCTL) */
++ u_short lcr_ioctl_onhtime; /* new hanguptime */
++ u_long lcr_ioctl_callid; /* callid from lcr-subsystem */
++ u_long lcr_ioctl_flags; /* see above */
++ char lcr_ioctl_nr[32]; /* new destination phonenumber */
++};
++
++#endif
+diff -rNu linux-2.4.29.old/include/linux/isdn_lzscomp.h linux-2.4.29/include/linux/isdn_lzscomp.h
+--- linux-2.4.29.old/include/linux/isdn_lzscomp.h 2005-03-22 14:47:32.000000000 +0100
++++ linux-2.4.29/include/linux/isdn_lzscomp.h 2005-03-22 15:06:50.089478024 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdn_lzscomp.h,v 1.1.4.1 2001/11/20 14:19:38 kai Exp $
++/* $Id$
+ *
+ * Header for isdn_lzscomp.c
+ * Concentrated here to not mess up half a dozen kernel headers with code
+diff -rNu linux-2.4.29.old/include/linux/isdn_ppp.h linux-2.4.29/include/linux/isdn_ppp.h
+--- linux-2.4.29.old/include/linux/isdn_ppp.h 2005-03-22 14:47:31.000000000 +0100
++++ linux-2.4.29/include/linux/isdn_ppp.h 2005-03-22 15:06:50.116473920 +0100
+@@ -8,6 +8,7 @@
+ #ifndef _LINUX_ISDN_PPP_H
+ #define _LINUX_ISDN_PPP_H
+
++#include <linux/isdn_compat.h>
+
+ #define CALLTYPE_INCOMING 0x1
+ #define CALLTYPE_OUTGOING 0x2
+@@ -33,6 +34,11 @@
+ #define PPPIOCSCOMPRESSOR _IOW('t',135,int)
+ #define PPPIOCGIFNAME _IOR('t',136, char [IFNAMSIZ] )
+
++#ifdef COMPAT_NEED_MPPP_DEFS
++#define PPP_MP 0x003d
++#define PPP_COMPFRAG 0x00fb
++#define PPP_CCPFRAG 0x80fb
++#endif
+
+ #define SC_MP_PROT 0x00000200
+ #define SC_REJ_MP_PROT 0x00000400
+@@ -65,9 +71,6 @@
+
+ #include <linux/config.h>
+
+-#ifdef CONFIG_IPPP_FILTER
+-#include <linux/filter.h>
+-#endif
+
+ #define DECOMP_ERR_NOMEM (-10)
+
+@@ -226,10 +229,6 @@
+ unsigned char *cbuf;
+ struct slcompress *slcomp;
+ #endif
+-#ifdef CONFIG_IPPP_FILTER
+- struct sock_fprog pass_filter; /* filter for packets to pass */
+- struct sock_fprog active_filter; /* filter for pkts to reset idle */
+-#endif
+ unsigned long debug;
+ struct isdn_ppp_compressor *compressor,*decompressor;
+ struct isdn_ppp_compressor *link_compressor,*link_decompressor;
+diff -rNu linux-2.4.29.old/include/linux/isdnif.h linux-2.4.29/include/linux/isdnif.h
+--- linux-2.4.29.old/include/linux/isdnif.h 2005-03-22 14:47:31.000000000 +0100
++++ linux-2.4.29/include/linux/isdnif.h 2005-03-22 15:06:50.132471488 +0100
+@@ -1,4 +1,4 @@
+-/* $Id: isdnif.h,v 1.1.4.1 2001/11/20 14:19:38 kai Exp $
++/* $Id: isdnif.h,v 1.43 2002/02/09 21:19:11 keil Exp $
+ *
+ * Linux ISDN subsystem
+ * Definition of the interface between the subsystem and its low-level drivers.
+@@ -14,6 +14,7 @@
+ #ifndef __ISDNIF_H__
+ #define __ISDNIF_H__
+
++#include <linux/isdn_compat.h>
+
+ /*
+ * Values for general protocol-selection
+@@ -213,6 +214,8 @@
+ #define ISDN_STAT_FAXIND 276 /* FAX indications from HL-driver */
+ #define ISDN_STAT_AUDIO 277 /* DTMF, DSP indications */
+ #define ISDN_STAT_DISCH 278 /* Disable/Enable channel usage */
++#define ISDN_STAT_ALERT 279 /* Signal alerting */
++#define ISDN_STAT_PROCEED 280 /* Signal proceeding */
+
+ /*
+ * Audio commands
+diff -rNu linux-2.4.29.old/include/linux/kernelcapi.h linux-2.4.29/include/linux/kernelcapi.h
+--- linux-2.4.29.old/include/linux/kernelcapi.h 2005-03-22 14:47:32.000000000 +0100
++++ linux-2.4.29/include/linux/kernelcapi.h 2005-03-22 15:06:50.147469208 +0100
+@@ -1,12 +1,10 @@
+-/* $Id: kernelcapi.h,v 1.1.4.2 2002/01/28 18:25:10 kai Exp $
++/*
++ * $Id: kernelcapi.h,v 1.9 2000/11/28 09:34:02 kai Exp $
+ *
+ * Kernel CAPI 2.0 Interface for Linux
+ *
+ * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
+ *
+- * This software may be used and distributed according to the terms
+- * of the GNU General Public License, incorporated herein by reference.
+- *
+ */
+
+ #ifndef __KERNELCAPI_H__
diff --git a/target/linux/generic-2.4/patches/201-hfc_usb_backport.patch b/target/linux/generic-2.4/patches/201-hfc_usb_backport.patch
new file mode 100644
index 0000000..4ef20fa
--- /dev/null
+++ b/target/linux/generic-2.4/patches/201-hfc_usb_backport.patch
@@ -0,0 +1,2663 @@
+diff -rNu linux-2.4.29.old/drivers/Makefile linux-2.4.29/drivers/Makefile
+--- linux-2.4.29.old/drivers/Makefile 2005-03-22 14:47:41.000000000 +0100
++++ linux-2.4.29/drivers/Makefile 2005-03-22 15:15:20.012957872 +0100
+@@ -38,7 +38,7 @@
+ subdir-$(CONFIG_MD) += md
+ subdir-$(CONFIG_IEEE1394) += ieee1394
+ subdir-$(CONFIG_PNP) += pnp
+-subdir-$(CONFIG_ISDN_BOOL) += isdn
++subdir-$(CONFIG_ISDN) += isdn
+ subdir-$(CONFIG_ATM) += atm
+ subdir-$(CONFIG_FC4) += fc4
+
+diff -rNu linux-2.4.29.old/drivers/isdn/hisax/hfc_usb.c linux-2.4.29/drivers/isdn/hisax/hfc_usb.c
+--- linux-2.4.29.old/drivers/isdn/hisax/hfc_usb.c 2005-03-22 15:13:58.233390256 +0100
++++ linux-2.4.29/drivers/isdn/hisax/hfc_usb.c 2005-03-22 15:14:57.475384104 +0100
+@@ -1,13 +1,11 @@
+-/* $Id: hfc_usb.c,v 2.3 2001/07/06 21:30:11 werner Exp $
++/*
++ * hfc_usb.c
+ *
++ * modular HiSax ISDN driver for Colognechip HFC-USB chip
+ *
+- *
+- * Author (C) 2001 Werner Cornelius (werner@isdn-development.de)
+- * modular driver for Colognechip HFC-USB chip
+- * as plugin for HiSax isdn driver
+- * type approval valid for HFC-S USB based TAs
+- *
+- * Copyright 2001 by Werner Cornelius (werner@isdn-development.de)
++ * Authors : Peter Sprenger (sprenger@moving-byters.de)
++ * Martin Bachem (info@colognechip.com)
++ * based on the first hfc_usb driver of Werner Cornelius (werner@isdn-development.de)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -23,70 +21,90 @@
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+- */
++ * 2005_Mar_16 grsch
++ * ported 2.6.8 hfc_usb.c to 2.4.20 format
++ * Gregor Schaffrath <gschaff@ran-dom.org>
++*/
++
+
+ #include <linux/types.h>
+ #include <linux/stddef.h>
+ #include <linux/timer.h>
+ #include <linux/config.h>
+-#include <linux/isdn_compat.h>
+ #include <linux/init.h>
+ #include "hisax.h"
+ #include <linux/module.h>
+ #include <linux/kernel_stat.h>
+-#include <linux/tqueue.h>
+ #include <linux/usb.h>
+ #include <linux/kernel.h>
+ #include <linux/smp_lock.h>
+ #include <linux/sched.h>
++#include "hisax_if.h"
+ #include "hisax_loadable.h"
+
++static const char *hfcusb_revision = "4.0";
++
++/*
++ to enable much mire debug messages in this driver, define
++ VERBOSE_USB_DEBUG and VERBOSE_ISDN_DEBUG
++ below
++*/
++
++#define VERBOSE_USB_DEBUG
++#define VERBOSE_ISDN_DEBUG
++
+ #define INCLUDE_INLINE_FUNCS
+
++#define TRUE 1
++#define FALSE 0
++
++
+ /***********/
+ /* defines */
+ /***********/
+-#define HFC_CTRL_TIMEOUT 5 /* 5ms timeout writing/reading regs */
+-#define HFC_TIMER_T3 7000 /* timeout for l1 activation timer */
+-
+-#define HFCUSB_L1_STATECHANGE 0 /* L1 state changed */
+-#define HFCUSB_L1_DRX 1 /* D-frame received */
+-#define HFCUSB_L1_ERX 2 /* E-frame received */
+-#define HFCUSB_L1_DTX 4 /* D-frames completed */
+-
+-#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */
+-
+-#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */
+-#define HFCUSB_TX_THRESHOLD 64 /* threshold for fifo report bit tx */
+-
+-#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */
+-#define HFCUSB_CIRM 0x00 /* cirm register index */
+-#define HFCUSB_USB_SIZE 0x07 /* int length register */
+-#define HFCUSB_USB_SIZE_I 0x06 /* iso length register */
+-#define HFCUSB_F_CROSS 0x0b /* bit order register */
+-#define HFCUSB_CLKDEL 0x37 /* bit delay register */
+-#define HFCUSB_CON_HDLC 0xfa /* channel connect register */
++#define HFC_CTRL_TIMEOUT 20 //(HZ * USB_CTRL_GET_TIMEOUT)
++/* 5ms timeout writing/reading regs */
++#define HFC_TIMER_T3 8000 /* timeout for l1 activation timer */
++#define HFC_TIMER_T4 500 /* time for state change interval */
++
++#define HFCUSB_L1_STATECHANGE 0 /* L1 state changed */
++#define HFCUSB_L1_DRX 1 /* D-frame received */
++#define HFCUSB_L1_ERX 2 /* E-frame received */
++#define HFCUSB_L1_DTX 4 /* D-frames completed */
++
++#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */
++
++#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */
++#define HFCUSB_TX_THRESHOLD 64 /* threshold for fifo report bit tx */
++
++#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */
++#define HFCUSB_CIRM 0x00 /* cirm register index */
++#define HFCUSB_USB_SIZE 0x07 /* int length register */
++#define HFCUSB_USB_SIZE_I 0x06 /* iso length register */
++#define HFCUSB_F_CROSS 0x0b /* bit order register */
++#define HFCUSB_CLKDEL 0x37 /* bit delay register */
++#define HFCUSB_CON_HDLC 0xfa /* channel connect register */
+ #define HFCUSB_HDLC_PAR 0xfb
+-#define HFCUSB_SCTRL 0x31 /* S-bus control register (tx) */
+-#define HFCUSB_SCTRL_E 0x32 /* same for E and special funcs */
+-#define HFCUSB_SCTRL_R 0x33 /* S-bus control register (rx) */
+-#define HFCUSB_F_THRES 0x0c /* threshold register */
+-#define HFCUSB_FIFO 0x0f /* fifo select register */
+-#define HFCUSB_F_USAGE 0x1a /* fifo usage register */
++#define HFCUSB_SCTRL 0x31 /* S-bus control register (tx) */
++#define HFCUSB_SCTRL_E 0x32 /* same for E and special funcs */
++#define HFCUSB_SCTRL_R 0x33 /* S-bus control register (rx) */
++#define HFCUSB_F_THRES 0x0c /* threshold register */
++#define HFCUSB_FIFO 0x0f /* fifo select register */
++#define HFCUSB_F_USAGE 0x1a /* fifo usage register */
+ #define HFCUSB_MST_MODE0 0x14
+ #define HFCUSB_MST_MODE1 0x15
+ #define HFCUSB_P_DATA 0x1f
+ #define HFCUSB_INC_RES_F 0x0e
+ #define HFCUSB_STATES 0x30
+
+-#define HFCUSB_CHIPID 0x40 /* ID value of HFC-USB */
++#define HFCUSB_CHIPID 0x40 /* ID value of HFC-USB */
+
+ /******************/
+ /* fifo registers */
+ /******************/
+-#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */
+-#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */
+-#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */
++#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */
++#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */
++#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */
+ #define HFCUSB_B2_TX 2
+ #define HFCUSB_B2_RX 3
+ #define HFCUSB_D_TX 4
+@@ -94,198 +112,162 @@
+ #define HFCUSB_PCM_TX 6
+ #define HFCUSB_PCM_RX 7
+
+-/************/
+-/* LED mask */
+-/************/
+-#define LED_DRIVER 0x1
+-#define LED_L1 0x2
+-#define LED_BCH 0x4
++/*
++* used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
++* supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
++*/
++#define USB_INT 0
++#define USB_BULK 1
++#define USB_ISOC 2
++
++#define ISOC_PACKETS_D 8
++#define ISOC_PACKETS_B 8
++#define ISO_BUFFER_SIZE 128
++
++// ISO send definitions
++#define SINK_MAX 68
++#define SINK_MIN 48
++#define SINK_DMIN 12
++#define SINK_DMAX 18
++#define BITLINE_INF (-64*8)
++
++
++
+
+ /**********/
+ /* macros */
+ /**********/
+-#define Write_hfc(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),0,0,HFC_CTRL_TIMEOUT)
+-#define Read_hfc(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT)
+-
+-#ifdef COMPAT_HAS_USB_IDTAB
+-/****************************************/
+-/* data defining the devices to be used */
+-/****************************************/
+-static __devinitdata const struct usb_device_id hfc_usb_idtab[3] = {
+- {USB_DEVICE(0x959, 0x2bd0)}, /* Colognechip ROM */
+- {USB_DEVICE(0x7b0, 0x0006)}, /* USB TA 128 */
+- {} /* end with an all-zeroes entry */
+-};
+-#endif
++#define write_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),NULL,0,HFC_CTRL_TIMEOUT)
++#define read_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT)
+
+ /*************************************************/
+ /* entry and size of output/input control buffer */
+ /*************************************************/
+ #define HFC_CTRL_BUFSIZE 32
+-typedef struct {
++typedef struct
++{
+ __u8 hfc_reg; /* register number */
+ __u8 reg_val; /* value to be written (or read) */
++ int action; /* data for action handler */
++
+ } ctrl_buft;
+
++typedef struct
++{
++ int vendor; // vendor id
++ int prod_id; // product id
++ char *vend_name; // vendor string
++ __u8 led_scheme; // led display scheme
++ __u8 led_invert; // invert led aux port settings
++ __u8 led_bits[8]; // array of 8 possible LED bitmask settings
++
++} vendor_data;
++
+ /***************************************************************/
+ /* structure defining input+output fifos (interrupt/bulk mode) */
+ /***************************************************************/
+-struct hfcusb_data; /* forward definition */
+-typedef struct {
+- int fifonum; /* fifo index attached to this structure */
+- __u8 fifo_mask; /* mask for this fifo */
+- int active; /* fifo is currently active */
++
++struct usb_fifo; /* forward definition */
++typedef struct iso_urb_struct
++{
++ struct urb *purb;
++ __u8 buffer[ISO_BUFFER_SIZE]; /* buffer incoming/outgoing data */
++ struct usb_fifo *owner_fifo; // pointer to owner fifo
++} iso_urb_struct;
++
++
++struct hfcusb_data; /* forward definition */
++typedef struct usb_fifo
++{
++ int fifonum; /* fifo index attached to this structure */
++ int active; /* fifo is currently active */
+ struct hfcusb_data *hfc; /* pointer to main structure */
+- int pipe; /* address of endpoint */
+- __u8 usb_maxlen; /* maximum length for usb transfer */
+- int max_size; /* maximum size of receive/send packet */
+- int transmode; /* transparent mode selected */
+- int framenum; /* number of frame when last tx completed */
+- int rx_offset; /* offset inside rx buffer */
+- int next_complete; /* complete marker */
+- __u8 *act_ptr; /* pointer to next data */
+- __u8 intervall; /* interrupt interval */
+- struct sk_buff *buff; /* actual used buffer */
+- urb_t urb; /* transfer structure for usb routines */
+- __u8 buffer[128]; /* buffer incoming/outgoing data */
++ int pipe; /* address of endpoint */
++ __u8 usb_packet_maxlen; /* maximum length for usb transfer */
++ unsigned int max_size; /* maximum size of receive/send packet */
++ __u8 intervall; /* interrupt interval */
++ struct sk_buff *skbuff; /* actual used buffer */
++ struct urb *urb; /* transfer structure for usb routines */
++ __u8 buffer[128]; /* buffer incoming/outgoing data */
++ int bit_line; /* how much bits are in the fifo? */
++
++ volatile __u8 usb_transfer_mode;/* switched between ISO and INT */
++ iso_urb_struct iso[2]; /* need two urbs to have one always for pending */
++ struct hisax_if *hif; /* hisax interface */
++ int delete_flg; /* only delete skbuff once */
++ int last_urblen; /* remember length of last packet */
++
+ } usb_fifo;
+
++
+ /*********************************************/
+ /* structure holding all data for one device */
+ /*********************************************/
+-typedef struct hfcusb_data {
+- struct hisax_drvreg regd; /* register data and callbacks */
+- struct usb_device *dev; /* our device */
+- int if_used; /* used interface number */
+- int alt_used; /* used alternate config */
+- int ctrl_paksize; /* control pipe packet size */
++typedef struct hfcusb_data
++{
++ // HiSax Interface for loadable Layer1 drivers
++ struct hisax_d_if d_if; /* see hisax_if.h */
++ struct hisax_b_if b_if[2]; /* see hisax_if.h */
++ int protocol;
++
++ struct usb_device *dev; /* our device */
++ int if_used; /* used interface number */
++ int alt_used; /* used alternate config */
++ int ctrl_paksize; /* control pipe packet size */
+ int ctrl_in_pipe, ctrl_out_pipe; /* handles for control pipe */
++ int cfg_used; /* configuration index used */
++ int vend_idx; // vendor found
++
++ int b_mode[2]; // B-channel mode
++
++ int l1_activated; // layer 1 activated
++
++ int packet_size,iso_packet_size;
+
+ /* control pipe background handling */
+ ctrl_buft ctrl_buff[HFC_CTRL_BUFSIZE]; /* buffer holding queued data */
+- volatile int ctrl_in_idx, ctrl_out_idx, ctrl_cnt; /* input/output pointer + count */
+- urb_t ctrl_urb; /* transfer structure for control channel */
+- devrequest ctrl_write; /* buffer for control write request */
+- devrequest ctrl_read; /* same for read request */
+-
+- volatile __u8 dfifo_fill; /* value read from tx d-fifo */
+- volatile __u8 active_fifos; /* fifos currently active as bit mask */
+- volatile __u8 threshold_mask; /* threshold actually reported */
+- volatile __u8 service_request; /* fifo needs service from task */
+- volatile __u8 ctrl_fifo; /* last selected fifo */
+- volatile __u8 bch_enables; /* or mask for sctrl_r and sctrl register values */
+- volatile __u8 led_req; /* request status of adapters leds */
+- volatile __u8 led_act; /* active status of adapters leds */
++ volatile int ctrl_in_idx, ctrl_out_idx,
++ ctrl_cnt; /* input/output pointer + count */
++ struct urb *ctrl_urb; /* transfer structure for control channel */
++
++ struct usb_ctrlrequest ctrl_write; /* buffer for control write request */
++ struct usb_ctrlrequest ctrl_read; /* same for read request */
++
++ __u8 led_state,led_new_data,led_b_active;
++
++ volatile __u8 threshold_mask; /* threshold actually reported */
++ volatile __u8 bch_enables; /* or mask for sctrl_r and sctrl register values */
++
+ usb_fifo fifos[HFCUSB_NUM_FIFOS]; /* structure holding all fifo data */
+
+- /* layer 1 activation/deactivation handling */
+- volatile __u8 l1_state; /* actual l1 state */
+- volatile ulong l1_event; /* event mask */
+- struct tq_struct l1_tq; /* l1 bh structure */
+- struct timer_list t3_timer; /* timer for activation/deactivation */
+- struct timer_list t4_timer; /* timer for activation/deactivation */
++ volatile __u8 l1_state; /* actual l1 state */
++ struct timer_list t3_timer; /* timer 3 for activation/deactivation */
++ struct timer_list t4_timer; /* timer 4 for activation/deactivation */
++ struct timer_list led_timer; /* timer flashing leds */
++
+ } hfcusb_data;
+
+-#if 0
+-static void
+-usb_dump_urb(purb_t purb)
+-{
+- printk("urb :%p\n", purb);
+- printk("next :%p\n", purb->next);
+- printk("dev :%p\n", purb->dev);
+- printk("pipe :%08X\n", purb->pipe);
+- printk("status :%d\n", purb->status);
+- printk("transfer_flags :%08X\n", purb->transfer_flags);
+- printk("transfer_buffer :%p\n", purb->transfer_buffer);
+- printk("transfer_buffer_length:%d\n",
+- purb->transfer_buffer_length);
+- printk("actual_length :%d\n", purb->actual_length);
+- printk("setup_packet :%p\n", purb->setup_packet);
+- printk("start_frame :%d\n", purb->start_frame);
+- printk("number_of_packets :%d\n", purb->number_of_packets);
+- printk("interval :%d\n", purb->interval);
+- printk("error_count :%d\n", purb->error_count);
+- printk("context :%p\n", purb->context);
+- printk("complete :%p\n", purb->complete);
+-}
+-#endif
+
+-/*************************************************************************/
+-/* bottom half handler for L1 activation/deactiavtaion + D-chan + E-chan */
+-/*************************************************************************/
+-static void
+-usb_l1d_bh(hfcusb_data * hfc)
+-{
++static void collect_rx_frame(usb_fifo *fifo,__u8 *data,int len,int finish);
++
+
+- while (hfc->l1_event) {
+- if (test_and_clear_bit
+- (HFCUSB_L1_STATECHANGE, &hfc->l1_event)) {
+- if (hfc->l1_state == 7)
+- hfc->led_req |= LED_L1;
+- else
+- hfc->led_req &= ~LED_L1;
+- if ((hfc->l1_state == 7) ||
+- (hfc->l1_state == 3))
+- hfc->regd.dch_l1l2(hfc->regd.arg_hisax,
+- (hfc->l1_state ==
+- 7) ? (PH_ACTIVATE |
+- INDICATION)
+- : (PH_DEACTIVATE | INDICATION),
+- NULL);
+- }
+- if (test_and_clear_bit(HFCUSB_L1_DRX, &hfc->l1_event)) {
+- hfc->regd.dch_l1l2(hfc->regd.arg_hisax,
+- PH_DATA | INDICATION,
+- (void *) 0);
+- }
+- if (test_and_clear_bit(HFCUSB_L1_ERX, &hfc->l1_event)) {
+- hfc->regd.dch_l1l2(hfc->regd.arg_hisax,
+- PH_DATA | INDICATION,
+- (void *) 1);
+- }
+- if (test_and_clear_bit(HFCUSB_L1_DTX, &hfc->l1_event)) {
+- hfc->regd.dch_l1l2(hfc->regd.arg_hisax,
+- PH_DATA | CONFIRM, NULL);
+- }
+- } /* while */
+-} /* usb_l1d_bh */
+
+ /******************************************************/
+ /* start next background transfer for control channel */
+ /******************************************************/
+-static void
+-ctrl_start_transfer(hfcusb_data * hfc)
++static void ctrl_start_transfer(hfcusb_data * hfc)
+ {
+-
+- if (hfc->ctrl_cnt) {
+- switch (hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg) {
+- case HFCUSB_F_USAGE:
+- hfc->ctrl_urb.pipe = hfc->ctrl_in_pipe;
+- hfc->ctrl_urb.setup_packet =
+- (u_char *) & hfc->ctrl_read;
+- hfc->ctrl_urb.transfer_buffer_length = 1;
+- hfc->ctrl_read.index =
+- hfc->ctrl_buff[hfc->ctrl_out_idx].
+- hfc_reg;
+- hfc->ctrl_urb.transfer_buffer =
+- (char *) &hfc->dfifo_fill;
+- break;
+-
+- default: /* write register */
+- hfc->ctrl_urb.pipe = hfc->ctrl_out_pipe;
+- hfc->ctrl_urb.setup_packet =
+- (u_char *) & hfc->ctrl_write;
+- hfc->ctrl_urb.transfer_buffer = NULL;
+- hfc->ctrl_urb.transfer_buffer_length = 0;
+- hfc->ctrl_write.index =
+- hfc->ctrl_buff[hfc->ctrl_out_idx].
+- hfc_reg;
+- hfc->ctrl_write.value =
+- hfc->ctrl_buff[hfc->ctrl_out_idx].
+- reg_val;
+- break;
+- }
+- usb_submit_urb(&hfc->ctrl_urb); /* start transfer */
++ int err;
++ if(hfc->ctrl_cnt)
++ {
++ hfc->ctrl_urb->pipe = hfc->ctrl_out_pipe;
++ hfc->ctrl_urb->setup_packet = (u_char *) & hfc->ctrl_write;
++ hfc->ctrl_urb->transfer_buffer = NULL;
++ hfc->ctrl_urb->transfer_buffer_length = 0;
++ hfc->ctrl_write.wIndex = hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg;
++ hfc->ctrl_write.wValue = hfc->ctrl_buff[hfc->ctrl_out_idx].reg_val;
++ err = usb_submit_urb(hfc->ctrl_urb); /* start transfer */
++ printk(KERN_DEBUG "ctrl_start_transfer: submit %d\n", err);
+ }
+ } /* ctrl_start_transfer */
+
+@@ -293,897 +275,1418 @@
+ /* queue a control transfer request */
+ /* return 0 on success. */
+ /************************************/
+-static int
+-queue_control_request(hfcusb_data * hfc, __u8 reg, __u8 val)
++static int queue_control_request(hfcusb_data * hfc, __u8 reg, __u8 val,int action)
+ {
+ ctrl_buft *buf;
+
+- if (hfc->ctrl_cnt >= HFC_CTRL_BUFSIZE)
+- return (1); /* no space left */
+- buf = hfc->ctrl_buff + hfc->ctrl_in_idx; /* pointer to new index */
++#ifdef VERBOSE_USB_DEBUG
++ printk ("HFC_USB: queue_control_request reg: %x, val: %x\n", reg, val);
++#endif
++
++ if(hfc->ctrl_cnt >= HFC_CTRL_BUFSIZE) return(1); /* no space left */
++ buf = &hfc->ctrl_buff[hfc->ctrl_in_idx]; /* pointer to new index */
+ buf->hfc_reg = reg;
+ buf->reg_val = val;
++ buf->action=action;
+ if (++hfc->ctrl_in_idx >= HFC_CTRL_BUFSIZE)
+ hfc->ctrl_in_idx = 0; /* pointer wrap */
+ if (++hfc->ctrl_cnt == 1)
+ ctrl_start_transfer(hfc);
+- return (0);
+-} /* queue_control_request */
++ return(0);
++} /* queue_control_request */
+
+-/**************************************/
+-/* called when timer t3 or t4 expires */
+-/**************************************/
+-static void
+-l1_timer_expire(hfcusb_data * hfc)
+-{
+- if (timer_pending(&hfc->t4_timer))
+- del_timer(&hfc->t4_timer);
+- queue_control_request(hfc, HFCUSB_STATES, 0x40);
+- test_and_set_bit(HFCUSB_L1_STATECHANGE,
+- &hfc->l1_event);
+- queue_task(&hfc->l1_tq, &tq_immediate);
+- mark_bh(IMMEDIATE_BH);
+-} /* l1_timer_expire */
+-
+-/**************************************************/
+-/* (re)fills a tx-fifo urb. Queuing is done later */
+-/**************************************************/
+-static void
+-fill_tx_urb(usb_fifo * fifo)
+-{
+- struct sk_buff *skb;
+- long flags;
+- int i, ii = 0;
+-
+- fifo->urb.dev = fifo->hfc->dev;
+- if ((fifo->buff)
+- && (fifo->urb.transfer_buffer_length < fifo->usb_maxlen)) {
+- switch (fifo->fifonum) {
+- case HFCUSB_B1_TX:
+- case HFCUSB_B2_TX:
+- skb = fifo->buff;
+- fifo->buff = NULL;
+- fifo->hfc->regd.bch_l1l2(fifo->hfc->regd.
+- arg_hisax,
+- (fifo->fifonum ==
+- HFCUSB_B1_TX) ? 0
+- : 1,
+- (PH_DATA |
+- CONFIRM),
+- (void *) skb);
+- fifo->hfc->service_request |=
+- fifo->fifo_mask;
+- return;
+- case HFCUSB_D_TX:
+- dev_kfree_skb_any(fifo->buff);
+- fifo->buff = NULL;
+- save_flags(flags);
+- cli();
+- fifo->hfc->dfifo_fill = 0xff; /* currently invalid data */
+- queue_control_request(fifo->hfc,
+- HFCUSB_FIFO,
+- HFCUSB_D_TX);
+- queue_control_request(fifo->hfc,
+- HFCUSB_F_USAGE, 0);
+- restore_flags(flags);
+- return;
+- default:
+- return; /* error, invalid fifo */
+- }
++
++static int control_action_handler(hfcusb_data *hfc,int reg,int val,int action)
++{
++ if(!action) return(1); // no action defined
++
++ return(0);
++}
++
++
++/***************************************************************/
++/* control completion routine handling background control cmds */
++/***************************************************************/
++static void ctrl_complete(struct urb *urb)
++{
++ hfcusb_data *hfc = (hfcusb_data *) urb->context;
++ ctrl_buft *buf;
++
++ printk(KERN_DEBUG "ctrl_complete cnt %d\n", hfc->ctrl_cnt);
++ urb->dev = hfc->dev;
++ if(hfc->ctrl_cnt)
++ {
++ buf=&hfc->ctrl_buff[hfc->ctrl_out_idx];
++ control_action_handler(hfc,buf->hfc_reg,buf->reg_val,buf->action);
++
++ hfc->ctrl_cnt--; /* decrement actual count */
++ if(++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE) hfc->ctrl_out_idx = 0; /* pointer wrap */
++
++ ctrl_start_transfer(hfc); /* start next transfer */
++ }
++} /* ctrl_complete */
++
++
++
++#define LED_OFF 0 // no LED support
++#define LED_SCHEME1 1 // LED standard scheme
++#define LED_SCHEME2 2 // not used yet...
++
++#define LED_POWER_ON 1
++#define LED_POWER_OFF 2
++#define LED_S0_ON 3
++#define LED_S0_OFF 4
++#define LED_B1_ON 5
++#define LED_B1_OFF 6
++#define LED_B1_DATA 7
++#define LED_B2_ON 8
++#define LED_B2_OFF 9
++#define LED_B2_DATA 10
++
++#define LED_NORMAL 0 // LEDs are normal
++#define LED_INVERTED 1 // LEDs are inverted
++
++// time for LED flashing
++#define LED_TIME 250
++
++vendor_data vdata[]=
++{
++ {0x959, 0x2bd0, "ISDN USB TA (Cologne Chip HFC-S USB based)", LED_OFF,LED_NORMAL,{4,0,2,1}}, /* CologneChip Eval TA */
++ {0x7b0, 0x0007, "Billion tiny USB ISDN TA 128", LED_SCHEME1, LED_INVERTED, {8,0x40,0x20,0x10}}, /* Billion TA */
++ {0x742, 0x2008, "Stollmann USB TA", LED_SCHEME1, LED_NORMAL, {4,0,2,1}}, /* Stollmann TA */
++ {0x8e3, 0x0301, "Olitec USB RNIS", LED_SCHEME1, LED_NORMAL, {2,0,1,4}}, /* Olitec TA */
++ {0x675, 0x1688, "DrayTec USB ISDN TA", LED_SCHEME1, LED_NORMAL, {4,0,2,1}}, /* Draytec TA */
++ {0x7fa, 0x0846, "Bewan Modem RNIS USB", LED_SCHEME1, LED_INVERTED, {8,0x40,0x20,0x10}}, /* Bewan TA */
++ {0} // EOL element
++};
++
++/***************************************************/
++/* write led data to auxport & invert if necessary */
++/***************************************************/
++static void write_led(hfcusb_data * hfc,__u8 led_state)
++{
++ if(led_state!=hfc->led_state)
++ {
++ hfc->led_state=led_state;
++ queue_control_request(hfc, HFCUSB_P_DATA,(vdata[hfc->vend_idx].led_invert) ? ~led_state : led_state,1);
++ }
++}
++
++/******************************************/
++/* invert B-channel LEDs if data is sent */
++/******************************************/
++static void led_timer(hfcusb_data * hfc)
++{
++ static int cnt=0;
++ __u8 led_state=hfc->led_state;
++
++ if(cnt)
++ {
++ if(hfc->led_b_active&1) led_state|=vdata[hfc->vend_idx].led_bits[2];
++ if(hfc->led_b_active&2) led_state|=vdata[hfc->vend_idx].led_bits[3];
++ }
++ else
++ {
++ if(!(hfc->led_b_active&1) || hfc->led_new_data&1) led_state&=~vdata[hfc->vend_idx].led_bits[2];
++ if(!(hfc->led_b_active&2) || hfc->led_new_data&2) led_state&=~vdata[hfc->vend_idx].led_bits[3];
+ }
+
+- /* check if new buffer needed */
+- if (!fifo->buff) {
+- switch (fifo->fifonum) {
+- case HFCUSB_B1_TX:
+- if (fifo->hfc->regd.bsk[0])
+- fifo->buff = *fifo->hfc->regd.bsk[0]; /* B1-channel tx buffer */
++ write_led(hfc,led_state);
++ hfc->led_new_data=0;
++
++ cnt=!cnt;
++ // restart 4 hz timer
++ hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000;
++ if(!timer_pending(&hfc->led_timer)) add_timer(&hfc->led_timer);
++}
++
++/**************************/
++/* handle LED requests */
++/**************************/
++static void handle_led(hfcusb_data * hfc,int event)
++{
++ __u8 led_state=hfc->led_state;
++
++ // if no scheme -> no LED action
++ if(vdata[hfc->vend_idx].led_scheme==LED_OFF) return;
++
++ switch(event)
++ {
++ case LED_POWER_ON:
++ led_state|=vdata[hfc->vend_idx].led_bits[0];
++ break;
++ case LED_POWER_OFF: // no Power off handling
++ break;
++ case LED_S0_ON:
++ led_state|=vdata[hfc->vend_idx].led_bits[1];
++ break;
++ case LED_S0_OFF:
++ led_state&=~vdata[hfc->vend_idx].led_bits[1];
+ break;
+- case HFCUSB_B2_TX:
+- if (fifo->hfc->regd.bsk[1])
+- fifo->buff = *fifo->hfc->regd.bsk[1]; /* B2-channel tx buffer */
++ case LED_B1_ON:
++ hfc->led_b_active|=1;
+ break;
+- case HFCUSB_D_TX:
+- if (fifo->hfc->regd.dsq)
+- fifo->buff = skb_dequeue(fifo->hfc->regd.dsq); /* D-channel tx queue */
++ case LED_B1_OFF:
++ hfc->led_b_active&=~1;
+ break;
+- default:
+- return; /* error, invalid fifo */
++ case LED_B1_DATA:
++ hfc->led_new_data|=1;
++ break;
++ case LED_B2_ON:
++ hfc->led_b_active|=2;
++ break;
++ case LED_B2_OFF:
++ hfc->led_b_active&=~2;
++ break;
++ case LED_B2_DATA:
++ hfc->led_new_data|=2;
++ break;
++ }
++
++ write_led(hfc,led_state);
++}
++
++/********************************/
++/* called when timer t3 expires */
++/********************************/
++static void l1_timer_expire_t3(hfcusb_data * hfc)
++{
++ //printk (KERN_INFO "HFC-USB: l1_timer_expire_t3\n");
++
++ hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL);
++#ifdef VERBOSE_USB_DEBUG
++ printk(KERN_INFO "PH_DEACTIVATE | INDICATION sent\n");
++#endif
++ hfc->l1_activated=FALSE;
++ handle_led(hfc,LED_S0_OFF);
++}
++
++/********************************/
++/* called when timer t4 expires */
++/********************************/
++static void l1_timer_expire_t4(hfcusb_data * hfc)
++{
++ //printk (KERN_INFO "HFC-USB: l1_timer_expire_t4\n");
++
++ hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL);
++#ifdef VERBOSE_USB_DEBUG
++ printk(KERN_INFO "PH_DEACTIVATE | INDICATION sent\n");
++#endif
++ hfc->l1_activated=FALSE;
++ handle_led(hfc,LED_S0_OFF);
++}
++
++/*****************************/
++/* handle S0 state changes */
++/*****************************/
++static void state_handler(hfcusb_data * hfc,__u8 state)
++{
++ __u8 old_state;
++
++ old_state=hfc->l1_state;
++
++ // range check
++ if(state==old_state || state<1 || state>8) return;
++
++#ifdef VERBOSE_ISDN_DEBUG
++ printk(KERN_INFO "HFC-USB: new S0 state:%d old_state:%d\n",state,old_state);
++#endif
++
++ if(state<4 || state==7 || state==8)
++ {
++ if(timer_pending(&hfc->t3_timer)) del_timer(&hfc->t3_timer);
++ //printk(KERN_INFO "HFC-USB: T3 deactivated\n");
++ }
++
++ if(state>=7)
++ {
++ if(timer_pending(&hfc->t4_timer)) del_timer(&hfc->t4_timer);
++ //printk(KERN_INFO "HFC-USB: T4 deactivated\n");
++ }
++
++ if(state==7 && !hfc->l1_activated)
++ {
++ hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_ACTIVATE | INDICATION,NULL);
++ //printk(KERN_INFO "HFC-USB: PH_ACTIVATE | INDICATION sent\n");
++ hfc->l1_activated=TRUE;
++ handle_led(hfc,LED_S0_ON);
++ }
++ else
++ if(state<=3 /* && activated*/)
++ {
++ if(old_state==7 || old_state==8)
++ {
++ //printk(KERN_INFO "HFC-USB: T4 activated\n");
++ hfc->t4_timer.expires = jiffies + (HFC_TIMER_T4 * HZ) / 1000;
++ if(!timer_pending(&hfc->t4_timer)) add_timer(&hfc->t4_timer);
+ }
+- if (!fifo->buff) {
+- fifo->active = 0; /* we are inactive now */
+- fifo->hfc->active_fifos &= ~fifo->fifo_mask;
+- if (fifo->fifonum == HFCUSB_D_TX) {
+- test_and_set_bit(HFCUSB_L1_DTX,
+- &fifo->hfc->l1_event);
+- queue_task(&fifo->hfc->l1_tq,
+- &tq_immediate);
+- mark_bh(IMMEDIATE_BH);
+- }
+- return;
++ else
++ {
++ hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,PH_DEACTIVATE | INDICATION,NULL);
++ //printk(KERN_INFO "HFC-USB: PH_DEACTIVATE | INDICATION sent\n");
++ hfc->l1_activated=FALSE;
++ handle_led(hfc,LED_S0_OFF);
+ }
+- fifo->act_ptr = fifo->buff->data; /* start of data */
+- fifo->active = 1;
+- ii = 1;
+- fifo->hfc->active_fifos |= fifo->fifo_mask;
+- fifo->hfc->service_request &= ~fifo->fifo_mask;
+- }
+- /* fillup the send buffer */
+- i = fifo->buff->len - (fifo->act_ptr - fifo->buff->data); /* remaining length */
+- fifo->buffer[0] = !fifo->transmode; /* not eof */
+- if (i > (fifo->usb_maxlen - ii)) {
+- i = fifo->usb_maxlen - ii;
+- }
+- if (i)
+- memcpy(fifo->buffer + ii, fifo->act_ptr, i);
+- fifo->urb.transfer_buffer_length = i + ii;
+- fifo->rx_offset = ii;
+-} /* fill_tx_urb */
+-
+-/************************************************/
+-/* transmit completion routine for all tx fifos */
+-/************************************************/
+-static void
+-tx_complete(purb_t urb)
++ }
++
++ hfc->l1_state=state;
++}
++
++
++/* prepare iso urb */
++static void fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *buf,
++ int num_packets, int packet_size, int interval, usb_complete_t complete, void *context)
+ {
+- usb_fifo *fifo = (usb_fifo *) urb->context; /* pointer to our fifo */
++ int k;
+
+- fifo->hfc->service_request &= ~fifo->fifo_mask; /* no further handling */
+- fifo->framenum = usb_get_current_frame_number(fifo->hfc->dev);
++ spin_lock_init(&urb->lock); // do we really need spin_lock_init ?
++ urb->dev = dev;
++ urb->pipe = pipe;
++ urb->complete = complete;
++ urb->number_of_packets = num_packets;
++ urb->transfer_buffer_length = packet_size * num_packets;
++ urb->context = context;
++ urb->transfer_buffer = buf;
++ urb->transfer_flags = 0;
++ urb->transfer_flags = USB_ISO_ASAP;
++ urb->actual_length = 0;
++ urb->interval = interval;
++ for (k = 0; k < num_packets; k++) {
++ urb->iso_frame_desc[k].offset = packet_size * k;
++ urb->iso_frame_desc[k].length = packet_size;
++ urb->iso_frame_desc[k].actual_length = 0;
++ }
++}
+
+- /* check for deactivation or error */
+- if ((!fifo->active) || (urb->status)) {
+- fifo->hfc->active_fifos &= ~fifo->fifo_mask; /* we are inactive */
+- fifo->active = 0;
+- if ((fifo->buff) && (fifo->fifonum == HFCUSB_D_TX)) {
+- dev_kfree_skb_any(fifo->buff);
++/* allocs urbs and start isoc transfer with two pending urbs to avoid gaps in the transfer chain */
++static int start_isoc_chain(usb_fifo * fifo, int num_packets_per_urb,usb_complete_t complete,int packet_size)
++{
++ int i, k, errcode;
++
++#ifdef VERBOSE_USB_DEBUG
++ printk(KERN_INFO "HFC-USB: starting ISO-chain for Fifo %i\n", fifo->fifonum);
++#endif
++
++
++ // allocate Memory for Iso out Urbs
++ for (i = 0; i < 2; i++) {
++ if (!(fifo->iso[i].purb)) {
++ fifo->iso[i].purb = usb_alloc_urb(num_packets_per_urb);
++ fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo;
++
++ // Init the first iso
++ if (ISO_BUFFER_SIZE >= (fifo->usb_packet_maxlen * num_packets_per_urb))
++ {
++
++ fill_isoc_urb(fifo->iso[i].purb, fifo->hfc->dev, fifo->pipe, fifo->iso[i].buffer,
++ num_packets_per_urb, fifo->usb_packet_maxlen, fifo->intervall,
++ complete, &fifo->iso[i]);
++
++ memset(fifo->iso[i].buffer, 0, sizeof(fifo->iso[i].buffer));
++
++ // defining packet delimeters in fifo->buffer
++ for(k = 0; k < num_packets_per_urb; k++)
++ {
++ fifo->iso[i].purb->iso_frame_desc[k].offset = k*packet_size;
++ fifo->iso[i].purb->iso_frame_desc[k].length = packet_size;
++ }
++ }
+ }
+- fifo->buff = NULL;
+- return;
++
++ fifo->bit_line = BITLINE_INF;
++
++ errcode = usb_submit_urb(fifo->iso[i].purb);
++ fifo->active = (errcode >= 0) ? 1 : 0;
++ if(errcode < 0)
++ {
++ printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i.%i \n", errcode, i);
++ };
++
+ }
+- fifo->act_ptr += (urb->transfer_buffer_length - fifo->rx_offset); /* adjust pointer */
+- fill_tx_urb(fifo); /* refill the urb */
+- fifo->hfc->threshold_mask |= fifo->fifo_mask; /* assume threshold reached */
+- if (fifo->buff)
+- fifo->hfc->service_request |= fifo->fifo_mask; /* need to restart */
+-} /* tx_complete */
+
+-/***********************************************/
+-/* receive completion routine for all rx fifos */
+-/***********************************************/
+-static void
+-rx_complete(purb_t urb)
++ // errcode = (usb_submit_urb(fifo->iso[0].purb, GFP_KERNEL));
++ return(fifo->active);
++}
++
++/* stops running iso chain and frees their pending urbs */
++static void stop_isoc_chain(usb_fifo * fifo)
+ {
+- usb_fifo *fifo = (usb_fifo *) urb->context; /* pointer to our fifo */
+- hfcusb_data *hfc = fifo->hfc;
+- usb_fifo *txfifo;
+- __u8 last_state;
+- int i, ii, currcnt, hdlci;
+- struct sk_buff *skb;
+-
+- urb->dev = hfc->dev; /* security init */
+- if ((!fifo->active) || (urb->status)) {
+- hfc->service_request &= ~fifo->fifo_mask; /* no further handling */
+- hfc->active_fifos &= ~fifo->fifo_mask; /* we are inactive */
+- fifo->urb.interval = 0; /* cancel automatic rescheduling */
+- if (fifo->buff) {
+- dev_kfree_skb_any(fifo->buff);
+- fifo->buff = NULL;
++ int i;
++
++ for(i = 0; i < 2; i++)
++ {
++ if(fifo->iso[i].purb)
++ {
++#ifdef VERBOSE_USB_DEBUG
++ printk(KERN_INFO "HFC-USB: Stopping iso chain for fifo %i.%i\n", fifo->fifonum, i);
++#endif
++ usb_unlink_urb(fifo->iso[i].purb);
++ usb_free_urb(fifo->iso[i].purb);
++ fifo->iso[i].purb = NULL;
+ }
+- return;
+ }
++ if (fifo->urb) {
++ usb_unlink_urb(fifo->urb);
++ usb_free_urb(fifo->urb);
++ fifo->urb = NULL;
++ }
++ fifo->active = 0;
++}
+
+- /* first check for any status changes */
+- if ((urb->actual_length < fifo->rx_offset)
+- || (urb->actual_length > fifo->usb_maxlen))
+- return; /* error condition */
+-
+- if (fifo->rx_offset) {
+- hfc->threshold_mask = fifo->buffer[1]; /* update threshold status */
+- fifo->next_complete = fifo->buffer[0] & 1;
+- if ((fifo->fifonum == HFCUSB_D_RX) &&
+- (hfc->led_req != hfc->led_act))
+- queue_control_request(hfc, HFCUSB_P_DATA, hfc->led_req);
+-
+- /* check if rescheduling needed */
+- if ((i =
+- hfc->service_request & hfc->active_fifos & ~hfc->
+- threshold_mask)) {
+- currcnt =
+- usb_get_current_frame_number(hfc->dev);
+- txfifo = hfc->fifos + HFCUSB_B1_TX;
+- ii = 3;
+- while (ii--) {
+- if ((i & txfifo->fifo_mask)
+- && (currcnt != txfifo->framenum)) {
+- hfc->service_request &=
+- ~txfifo->fifo_mask;
+- if (!txfifo->buff)
+- fill_tx_urb(txfifo);
+- if (txfifo->buff)
+- usb_submit_urb(&txfifo->
+- urb);
++// defines how much ISO packets are handled in one URB
++static int iso_packets[8]={ISOC_PACKETS_B,ISOC_PACKETS_B,ISOC_PACKETS_B,ISOC_PACKETS_B,
++ ISOC_PACKETS_D,ISOC_PACKETS_D,ISOC_PACKETS_D,ISOC_PACKETS_D};
++
++/*****************************************************/
++/* transmit completion routine for all ISO tx fifos */
++/*****************************************************/
++static void tx_iso_complete(struct urb *urb)
++{
++ iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
++ usb_fifo *fifo = context_iso_urb->owner_fifo;
++ hfcusb_data *hfc = fifo->hfc;
++ int k, tx_offset, num_isoc_packets, sink, len, current_len,errcode,frame_complete,transp_mode,fifon;
++ __u8 threshbit;
++ __u8 threshtable[8] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
++
++ fifon=fifo->fifonum;
++ tx_offset=0;
++ // very weird error code when using ohci drivers, for now : ignore this error ... (MB)
++ if(urb->status == -EOVERFLOW)
++ {
++ urb->status = 0;
++#ifdef VERBOSE_USB_DEBUG
++ printk(KERN_INFO "HFC-USB: ignoring USB DATAOVERRUN for fifo %i \n",fifon);
++#endif
++ }
++
++ if(fifo->active && !urb->status)
++ {
++ transp_mode=0;
++ if(fifon<4 && hfc->b_mode[fifon/2]==L1_MODE_TRANS) transp_mode=TRUE;
++
++ threshbit = threshtable[fifon] & hfc->threshold_mask; // is threshold set for our channel?
++ num_isoc_packets=iso_packets[fifon];
++
++ if(fifon >= HFCUSB_D_TX)
++ {
++ sink = (threshbit) ? SINK_DMIN : SINK_DMAX; // how much bit go to the sink for D-channel?
++ }
++ else
++ {
++ sink = (threshbit) ? SINK_MIN : SINK_MAX; // how much bit go to the sink for B-channel?
++ }
++
++ // prepare ISO Urb
++ fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,context_iso_urb->buffer, num_isoc_packets,
++ fifo->usb_packet_maxlen, fifo->intervall, tx_iso_complete, urb->context);
++ memset(context_iso_urb->buffer, 0, sizeof(context_iso_urb->buffer));
++
++ frame_complete=FALSE;
++
++ // Generate Iso Packets
++ for(k = 0; k < num_isoc_packets; ++k)
++ {
++ if(fifo->skbuff)
++ {
++ len = fifo->skbuff->len; // remaining length
++
++ fifo->bit_line -= sink; // we lower data margin every msec
++ current_len = (0 - fifo->bit_line) / 8;
++ if(current_len > 14) current_len = 14; // maximum 15 byte for every ISO packet makes our life easier
++ current_len = (len <= current_len) ? len : current_len;
++ fifo->bit_line += current_len * 8; // how much bit do we put on the line?
++
++ context_iso_urb->buffer[tx_offset] = 0;
++ if(current_len == len)
++ {
++ if(!transp_mode)
++ {
++ context_iso_urb->buffer[tx_offset] = 1; // here frame completion
++ fifo->bit_line += 32; // add 2 byte flags and 16bit CRC at end of ISDN frame
++ }
++ frame_complete = TRUE;
++ }
++
++ // copy bytes from buffer into ISO_URB
++ memcpy(context_iso_urb->buffer+tx_offset+1,fifo->skbuff->data,current_len);
++ skb_pull(fifo->skbuff,current_len);
++
++ // define packet delimeters within the URB buffer
++ urb->iso_frame_desc[k].offset = tx_offset;
++ urb->iso_frame_desc[k].length = current_len + 1;
++
++ tx_offset += (current_len + 1);
++ // printk(KERN_INFO "HFC-USB: fifonum:%d,%d bytes to send, %d bytes ISO packet,bitline:%d,sink:%d,threshbit:%d,threshmask:%x\n",fifon,len,current_len,fifo->bit_line,sink,threshbit,hfc->threshold_mask);
++ if(!transp_mode)
++ {
++ if(fifon==HFCUSB_B1_TX) handle_led(hfc,LED_B1_DATA);
++ if(fifon==HFCUSB_B2_TX) handle_led(hfc,LED_B2_DATA);
++ }
++ }
++ else
++ {
++ // we have no more data - generate 1 byte ISO packets
++ urb->iso_frame_desc[k].offset = tx_offset++;
++
++ urb->iso_frame_desc[k].length = 1;
++ fifo->bit_line -= sink; // we lower data margin every msec
++
++ if(fifo->bit_line < BITLINE_INF)
++ {
++ fifo->bit_line = BITLINE_INF;
++ //printk (KERN_INFO "HFC-USB: BITLINE_INF underrun\n");
+ }
+- txfifo += 2;
+ }
+- }
+
+- /* handle l1 events */
+- if ((fifo->buffer[0] >> 4) != hfc->l1_state) {
+- last_state = hfc->l1_state;
+- hfc->l1_state = fifo->buffer[0] >> 4; /* update status */
+- if (timer_pending(&hfc->t4_timer))
+- del_timer(&hfc->t4_timer);
+- if (((hfc->l1_state == 3) &&
+- ((last_state == 7) ||
+- (last_state == 8))) ||
+- ((timer_pending(&hfc->t3_timer) &&
+- (hfc->l1_state == 8)))) {
+- hfc->t4_timer.expires = jiffies + 2;
+- add_timer(&hfc->t4_timer);
+- } else {
+- if (timer_pending(&hfc->t3_timer)
+- && (hfc->l1_state == 7))
+- del_timer(&hfc->t3_timer); /* no longer needed */
+- test_and_set_bit(HFCUSB_L1_STATECHANGE,
+- &hfc->l1_event);
+- queue_task(&hfc->l1_tq, &tq_immediate);
+- mark_bh(IMMEDIATE_BH);
++ if(frame_complete)
++ {
++ // delete the buffer only once, here or in hfc_usb_l2l1() in a PH_DATA|REQUEST
++ fifo->delete_flg=TRUE;
++
++ fifo->hif->l1l2(fifo->hif,PH_DATA|CONFIRM,(void*)fifo->skbuff->truesize);
++
++ if(fifo->skbuff && fifo->delete_flg)
++ {
++ dev_kfree_skb_any(fifo->skbuff);
++ //printk(KERN_INFO "HFC-USB: skbuff=NULL on fifo:%d\n",fifo->fifonum);
++ fifo->skbuff = NULL;
++ fifo->delete_flg=FALSE;
++ }
++
++ frame_complete=FALSE;
+ }
++ }
++
++ errcode = usb_submit_urb(urb);
++ if(errcode < 0)
++ {
++ printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n", errcode);
++ }
++ }
++ else
++ {
++ if(urb->status)
++ {
++ printk(KERN_INFO "HFC-USB: tx_iso_complete : urb->status %i, fifonum %i\n", urb->status,fifon);
+ }
+ }
+
+- /* check the length for data and move if present */
+- if (fifo->next_complete || (urb->actual_length > fifo->rx_offset)) {
+- i = fifo->buff->len + urb->actual_length - fifo->rx_offset; /* new total length */
+- hdlci = (fifo->transmode) ? 0 : 3;
+- if (i <= (fifo->max_size + hdlci)) {
+- memcpy(fifo->act_ptr,
+- fifo->buffer + fifo->rx_offset,
+- urb->actual_length - fifo->rx_offset);
+- fifo->act_ptr +=
+- (urb->actual_length - fifo->rx_offset);
+- fifo->buff->len +=
+- (urb->actual_length - fifo->rx_offset);
+- } else
+- fifo->buff->len = fifo->max_size + 4; /* mark frame as to long */
+- if (fifo->next_complete && (urb->actual_length < fifo->usb_maxlen)) {
+- /* the frame is complete */
+- fifo->next_complete = 0;
+- if (((!*(fifo->act_ptr - 1)) || fifo->transmode) &&
+- (fifo->buff->len >= (hdlci + 1))
+- && (fifo->buff->len <=
+- (fifo->max_size + hdlci)) &&
+- ((skb = dev_alloc_skb(fifo->max_size + hdlci)) != NULL)) {
+- fifo->buff->len -= hdlci; /* adjust size */
+- switch (fifo->fifonum) {
+- case HFCUSB_D_RX:
+- skb_queue_tail(hfc->regd.
+- drq,
+- fifo->buff);
+- test_and_set_bit
+- (HFCUSB_L1_DRX,
+- &hfc->l1_event);
+- queue_task(&hfc->l1_tq,
+- &tq_immediate);
+- mark_bh(IMMEDIATE_BH);
+- break;
++} /* tx_iso_complete */
+
+- case HFCUSB_B1_RX:
+- if (hfc->regd.brq[0]) {
+- skb_queue_tail
+- (hfc->regd.
+- brq[0],
+- fifo->buff);
+- hfc->regd.
+- bch_l1l2(hfc->
+- regd.
+- arg_hisax,
+- 0,
+- PH_DATA
+- |
+- INDICATION,
+- (void *)
+- fifo->
+- buff);
+- } else
+- dev_kfree_skb_any
+- (fifo->buff);
+- break;
+-
+- case HFCUSB_B2_RX:
+- if (hfc->regd.brq[1]) {
+- skb_queue_tail
+- (hfc->regd.
+- brq[1],
+- fifo->buff);
+- hfc->regd.
+- bch_l1l2(hfc->
+- regd.
+- arg_hisax,
+- 1,
+- PH_DATA
+- |
+- INDICATION,
+- (void
+- *)
+- fifo->
+- buff);
+- } else
+- dev_kfree_skb_any
+- (fifo->buff);
+- break;
++/*****************************************************/
++/* receive completion routine for all ISO tx fifos */
++/*****************************************************/
++static void rx_iso_complete(struct urb *urb)
++{
++ iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
++ usb_fifo *fifo = context_iso_urb->owner_fifo;
++ hfcusb_data *hfc = fifo->hfc;
++ int k, len, errcode, offset, num_isoc_packets,fifon;
++ __u8 *buf;
+
+- case HFCUSB_PCM_RX:
+- skb_queue_tail(&hfc->regd.
+- erq,
+- fifo->buff);
+- test_and_set_bit
+- (HFCUSB_L1_ERX,
+- &hfc->l1_event);
+- queue_task(&hfc->l1_tq,
+- &tq_immediate);
+- mark_bh(IMMEDIATE_BH);
+- break;
++ fifon=fifo->fifonum;
++ // very weird error code when using ohci drivers, for now : ignore this error ... (MB)
++ if(urb->status == -EOVERFLOW)
++ {
++ urb->status = 0;
++#ifdef VERBOSE_USB_DEBUG
++ printk(KERN_INFO "HFC-USB: ignoring USB DATAOVERRUN for fifo %i \n",fifon);
++#endif
++ }
+
+- default:
+- dev_kfree_skb_any(fifo->
+- buff);
+- break;
++ if(fifo->active && !urb->status)
++ {
++ num_isoc_packets=iso_packets[fifon];
++
++ // Generate D-Channel Iso Packets
++ for(k = 0; k < num_isoc_packets; ++k)
++ {
++ len=urb->iso_frame_desc[k].actual_length;
++ offset=urb->iso_frame_desc[k].offset;
++ buf=context_iso_urb->buffer+offset;
++
++ if(fifo->last_urblen!=fifo->usb_packet_maxlen)
++ {
++ // the threshold mask is in the 2nd status byte
++ hfc->threshold_mask=buf[1];
++ // the S0 state is in the upper half of the 1st status byte
++ state_handler(hfc,buf[0] >> 4);
++ // if we have more than the 2 status bytes -> collect data
++ if(len>2) collect_rx_frame(fifo,buf+2,len-2,buf[0]&1);
+ }
+- fifo->buff = skb;
+- }
+- fifo->buff->len = 0; /* reset counter */
+- fifo->act_ptr = fifo->buff->data; /* and pointer */
++ else collect_rx_frame(fifo,buf,len,0);
++
++ fifo->last_urblen=len;
++
++ }
++
++ // prepare ISO Urb
++ fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe,context_iso_urb->buffer, num_isoc_packets,
++ fifo->usb_packet_maxlen, fifo->intervall, rx_iso_complete, urb->context);
++
++ errcode = usb_submit_urb(urb);
++ if(errcode < 0)
++ {
++ printk(KERN_INFO "HFC-USB: error submitting ISO URB: %i \n", errcode);
++ }
++ }
++ else
++ {
++ if(urb->status)
++ {
++ printk(KERN_INFO "HFC-USB: rx_iso_complete : urb->status %i, fifonum %i\n", urb->status,fifon);
++ }
++ }
++} /* rx_iso_complete */
++
++
++/*****************************************************/
++/* collect data from interrupt or isochron in */
++/*****************************************************/
++static void collect_rx_frame(usb_fifo *fifo,__u8 *data,int len,int finish)
++{
++ hfcusb_data *hfc = fifo->hfc;
++ int transp_mode,fifon;
++
++ fifon=fifo->fifonum;
++ transp_mode=0;
++ if(fifon<4 && hfc->b_mode[fifon/2]==L1_MODE_TRANS) transp_mode=TRUE;
++
++ //printk(KERN_INFO "HFC-USB: got %d bytes finish:%d max_size:%d fifo:%d\n",len,finish,fifo->max_size,fifon);
++ if(!fifo->skbuff)
++ {
++ // allocate sk buffer
++ fifo->skbuff=dev_alloc_skb(fifo->max_size + 3);
++ if(!fifo->skbuff)
++ {
++ printk(KERN_INFO "HFC-USB: cannot allocate buffer (dev_alloc_skb) fifo:%d\n",fifon);
++ return;
++ }
++
++ }
++
++ if(len && fifo->skbuff->len+len<fifo->max_size)
++ {
++ memcpy(skb_put(fifo->skbuff,len),data,len);
++ }
++ else printk(KERN_INFO "HCF-USB: got frame exceeded fifo->max_size:%d\n",fifo->max_size);
++
++ // give transparent data up, when 128 byte are available
++ if(transp_mode && fifo->skbuff->len>=128)
++ {
++ fifo->hif->l1l2(fifo->hif,PH_DATA | INDICATION,fifo->skbuff);
++ fifo->skbuff = NULL; // buffer was freed from upper layer
++ return;
++ }
++
++ // we have a complete hdlc packet
++ if(finish)
++ {
++ if(!fifo->skbuff->data[fifo->skbuff->len-1])
++ {
++ skb_trim(fifo->skbuff,fifo->skbuff->len-3); // remove CRC & status
++
++ //printk(KERN_INFO "HFC-USB: got frame %d bytes on fifo:%d\n",fifo->skbuff->len,fifon);
++
++ if(fifon==HFCUSB_PCM_RX) fifo->hif->l1l2(fifo->hif,PH_DATA_E | INDICATION,fifo->skbuff);
++ else fifo->hif->l1l2(fifo->hif,PH_DATA | INDICATION,fifo->skbuff);
++
++ fifo->skbuff = NULL; // buffer was freed from upper layer
++ }
++ else
++ {
++ printk(KERN_INFO "HFC-USB: got frame %d bytes but CRC ERROR!!!\n",fifo->skbuff->len);
++
++ skb_trim(fifo->skbuff,0); // clear whole buffer
++ }
++ }
++
++ // LED flashing only in HDLC mode
++ if(!transp_mode)
++ {
++ if(fifon==HFCUSB_B1_RX) handle_led(hfc,LED_B1_DATA);
++ if(fifon==HFCUSB_B2_RX) handle_led(hfc,LED_B2_DATA);
++ }
++}
++
++/***********************************************/
++/* receive completion routine for all rx fifos */
++/***********************************************/
++static void rx_complete(struct urb *urb)
++{
++ int len;
++ __u8 *buf;
++ usb_fifo *fifo = (usb_fifo *) urb->context; /* pointer to our fifo */
++ hfcusb_data *hfc = fifo->hfc;
++
++ urb->dev = hfc->dev; /* security init */
++
++ if((!fifo->active) || (urb->status)) {
++#ifdef VERBOSE_USB_DEBUG
++ printk(KERN_INFO "HFC-USB: RX-Fifo %i is going down (%i)\n", fifo->fifonum, urb->status);
++#endif
++ fifo->urb->interval = 0; /* cancel automatic rescheduling */
++ if(fifo->skbuff) {
++ dev_kfree_skb_any(fifo->skbuff);
++ fifo->skbuff = NULL;
+ }
++ return;
+ }
+- fifo->rx_offset = (urb->actual_length < fifo->usb_maxlen) ? 2 : 0;
+-} /* rx_complete */
++
++ len=urb->actual_length;
++ buf=fifo->buffer;
++
++ if(fifo->last_urblen!=fifo->usb_packet_maxlen) {
++ // the threshold mask is in the 2nd status byte
++ hfc->threshold_mask=buf[1];
++ // the S0 state is in the upper half of the 1st status byte
++ state_handler(hfc,buf[0] >> 4);
++ // if we have more than the 2 status bytes -> collect data
++ if(len>2) collect_rx_frame(fifo,buf+2,urb->actual_length-2,buf[0]&1);
++ } else
++ collect_rx_frame(fifo,buf,urb->actual_length,0);
++
++ fifo->last_urblen=urb->actual_length;
++
++
++} /* rx_complete */
++
++
+
+ /***************************************************/
+ /* start the interrupt transfer for the given fifo */
+ /***************************************************/
+-static void
+-start_rx_fifo(usb_fifo * fifo)
++static void start_int_fifo(usb_fifo * fifo)
+ {
+- if (fifo->buff)
+- return; /* still active */
+- if (!
+- (fifo->buff =
+- dev_alloc_skb(fifo->max_size + (fifo->transmode ? 0 : 3))))
+- return;
+- fifo->act_ptr = fifo->buff->data;
+- FILL_INT_URB(&fifo->urb, fifo->hfc->dev, fifo->pipe, fifo->buffer,
+- fifo->usb_maxlen, rx_complete, fifo, fifo->intervall);
+- fifo->next_complete = 0;
+- fifo->rx_offset = 2;
+- fifo->active = 1; /* must be marked active */
+- fifo->hfc->active_fifos |= fifo->fifo_mask;
+- if (usb_submit_urb(&fifo->urb)) {
++ int errcode;
++
++#ifdef VERBOSE_USB_DEBUG
++ printk(KERN_INFO "HFC-USB: starting intr IN fifo:%d\n", fifo->fifonum);
++#endif
++ if (!fifo->urb) {
++ fifo->urb = usb_alloc_urb(0);
++ if (!fifo->urb)
++ return;
++ }
++ usb_fill_int_urb(fifo->urb, fifo->hfc->dev, fifo->pipe, fifo->buffer,
++ fifo->usb_packet_maxlen, rx_complete, fifo, fifo->intervall);
++ fifo->active = 1; /* must be marked active */
++ errcode = usb_submit_urb(fifo->urb);
++
++ if(errcode)
++ {
++ printk(KERN_INFO "HFC-USB: submit URB error(start_int_info): status:%i\n", errcode);
+ fifo->active = 0;
+- fifo->hfc->active_fifos &= ~fifo->fifo_mask;
+- dev_kfree_skb_any(fifo->buff);
+- fifo->buff = NULL;
++ fifo->skbuff = NULL;
+ }
+-} /* start_rx_fifo */
++} /* start_int_fifo */
+
+-/***************************************************************/
+-/* control completion routine handling background control cmds */
+-/***************************************************************/
+-static void
+-ctrl_complete(purb_t urb)
++/*****************************/
++/* set the B-channel mode */
++/*****************************/
++static void set_hfcmode(hfcusb_data *hfc,int channel,int mode)
+ {
+- hfcusb_data *hfc = (hfcusb_data *) urb->context;
++ __u8 val,idx_table[2]={0,2};
+
+- urb->dev = hfc->dev;
+- if (hfc->ctrl_cnt) {
+- switch (hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg) {
+- case HFCUSB_FIFO:
+- hfc->ctrl_fifo =
+- hfc->ctrl_buff[hfc->ctrl_out_idx].
+- reg_val;
+- break;
+- case HFCUSB_F_USAGE:
+- if (!hfc->dfifo_fill) {
+- fill_tx_urb(hfc->fifos +
+- HFCUSB_D_TX);
+- if (hfc->fifos[HFCUSB_D_TX].buff)
+- usb_submit_urb(&hfc->
+- fifos
+- [HFCUSB_D_TX].
+- urb);
+- } else {
+- queue_control_request(hfc,
+- HFCUSB_FIFO,
+- HFCUSB_D_TX);
+- queue_control_request(hfc,
+- HFCUSB_F_USAGE,
+- 0);
+- }
+- break;
+- case HFCUSB_SCTRL_R:
+- switch (hfc->ctrl_fifo) {
+- case HFCUSB_B1_RX:
+- if (hfc->bch_enables & 1)
+- start_rx_fifo(hfc->
+- fifos
+- +
+- HFCUSB_B1_RX);
+- break;
+- case HFCUSB_B2_RX:
+- if (hfc->bch_enables & 2)
+- start_rx_fifo(hfc->
+- fifos
+- +
+- HFCUSB_B2_RX);
+- break;
+- }
+- if (hfc->bch_enables & 3)
+- hfc->led_req |= LED_BCH;
+- else
+- hfc->led_req &= ~LED_BCH;
+- break;
+- case HFCUSB_P_DATA:
+- hfc->led_act =
+- hfc->ctrl_buff[hfc->ctrl_out_idx].
+- reg_val;
+- break;
+- }
+- hfc->ctrl_cnt--; /* decrement actual count */
+- if (++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE)
+- hfc->ctrl_out_idx = 0; /* pointer wrap */
+- ctrl_start_transfer(hfc); /* start next transfer */
++#ifdef VERBOSE_ISDN_DEBUG
++ printk (KERN_INFO "HFC-USB: setting channel %d to mode %d\n",channel,mode);
++#endif
++
++ hfc->b_mode[channel]=mode;
++
++ // setup CON_HDLC
++ val=0;
++ if(mode!=L1_MODE_NULL) val=8; // enable fifo?
++ if(mode==L1_MODE_TRANS) val|=2; // set transparent bit
++
++ queue_control_request(hfc,HFCUSB_FIFO,idx_table[channel],1); // set FIFO to transmit register
++ queue_control_request(hfc,HFCUSB_CON_HDLC,val,1);
++ queue_control_request(hfc,HFCUSB_INC_RES_F,2,1); // reset fifo
++
++ queue_control_request(hfc,HFCUSB_FIFO,idx_table[channel]+1,1); // set FIFO to receive register
++ queue_control_request(hfc,HFCUSB_CON_HDLC,val,1);
++ queue_control_request(hfc,HFCUSB_INC_RES_F,2,1); // reset fifo
++
++ val=0x40;
++ if(hfc->b_mode[0]) val|=1;
++ if(hfc->b_mode[1]) val|=2;
++ queue_control_request(hfc,HFCUSB_SCTRL,val,1);
++
++ val=0;
++ if(hfc->b_mode[0]) val|=1;
++ if(hfc->b_mode[1]) val|=2;
++ queue_control_request(hfc,HFCUSB_SCTRL_R,val,1);
++
++ if(mode==L1_MODE_NULL)
++ {
++ if(channel) handle_led(hfc,LED_B2_OFF);
++ else handle_led(hfc,LED_B1_OFF);
+ }
+-} /* ctrl_complete */
++ else
++ {
++ if(channel) handle_led(hfc,LED_B2_ON);
++ else handle_led(hfc,LED_B1_ON);
++ }
++}
+
+-/*****************************************/
+-/* Layer 1 + D channel access from HiSax */
+-/*****************************************/
+-static void
+-hfcusb_l1_access(void *drvarg, int pr, void *arg)
+-{
+- hfcusb_data *hfc = (hfcusb_data *) drvarg;
+-
+- switch (pr) {
+- case (PH_DATA | REQUEST):
+- case (PH_PULL | INDICATION):
+- skb_queue_tail(hfc->regd.dsq,
+- (struct sk_buff *) arg);
+- if (!hfc->fifos[HFCUSB_D_TX].active
+- && !hfc->dfifo_fill) {
+- fill_tx_urb(hfc->fifos + HFCUSB_D_TX);
+- hfc->active_fifos |=
+- hfc->fifos[HFCUSB_D_TX].fifo_mask;
+- usb_submit_urb(&hfc->fifos[HFCUSB_D_TX].
+- urb);
+- }
+- break;
+- case (PH_ACTIVATE | REQUEST):
+- switch (hfc->l1_state) {
+- case 6:
+- case 8:
+- hfc->regd.dch_l1l2(hfc->regd.arg_hisax,
+- (PH_DEACTIVATE |
+- INDICATION), NULL);
++/*
++ --------------------------------------------------------------------------------------
++ from here : hisax_if callback routines :
++ - void hfc_usb_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg) {
+
+- break;
+- case 7:
+- hfc->regd.dch_l1l2(hfc->regd.arg_hisax,
+- (PH_ACTIVATE |
+- INDICATION), NULL);
++ l1 to l2 routines :
++ - static void hfc_usb_l1l2(hfcusb_data * hfc)
+
+- break;
+- default:
+- queue_control_request(hfc, HFCUSB_STATES, 0x60); /* start activation */
+- hfc->t3_timer.expires =
+- jiffies + (HFC_TIMER_T3 * HZ) / 1000;
+- if (!timer_pending(&hfc->t3_timer))
+- add_timer(&hfc->t3_timer);
+- break;
+- }
+- break;
++*/
+
+- case (PH_DEACTIVATE | REQUEST):
+- queue_control_request(hfc, HFCUSB_STATES, 0x40); /* start deactivation */
+- break;
+- default:
+- printk(KERN_INFO "unknown hfcusb l1_access 0x%x\n",
+- pr);
+- break;
+- }
+-} /* hfcusb_l1_access */
+-
+-/*******************************/
+-/* B channel access from HiSax */
+-/*******************************/
+-static void
+-hfcusb_bch_access(void *drvarg, int chan, int pr, void *arg)
+-{
+- hfcusb_data *hfc = (hfcusb_data *) drvarg;
+- usb_fifo *fifo = hfc->fifos + (chan ? HFCUSB_B2_TX : HFCUSB_B1_TX);
+- long flags;
+-
+- switch (pr) {
+- case (PH_DATA | REQUEST):
+- case (PH_PULL | INDICATION):
+- save_flags(flags);
+- cli();
+- if (!fifo->active) {
+- fill_tx_urb(fifo);
+- hfc->active_fifos |= fifo->fifo_mask;
+- usb_submit_urb(&fifo->urb);
+- }
+- restore_flags(flags);
+- break;
+- case (PH_ACTIVATE | REQUEST):
+- if (!((int) arg)) {
+- hfc->bch_enables &= ~(1 << chan);
+- if (fifo->active) {
+- fifo->active = 0;
+- usb_unlink_urb(&fifo->urb);
++void hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
++{
++ usb_fifo *fifo = my_hisax_if->priv;
++ hfcusb_data *hfc = fifo->hfc;
++
++ switch (pr) {
++ case PH_ACTIVATE | REQUEST:
++ if(fifo->fifonum==HFCUSB_D_TX)
++ {
++#ifdef VERBOSE_ISDN_DEBUG
++ printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_ACTIVATE | REQUEST\n");
++#endif
++ queue_control_request(hfc, HFCUSB_STATES,0x60,1); /* make activation */
++ hfc->t3_timer.expires = jiffies + (HFC_TIMER_T3 * HZ) / 1000;
++ if(!timer_pending(&hfc->t3_timer)) add_timer(&hfc->t3_timer);
+ }
+- save_flags(flags);
+- cli();
+- queue_control_request(hfc, HFCUSB_FIFO,
+- fifo->fifonum);
+- queue_control_request(hfc,
+- HFCUSB_INC_RES_F, 2);
+- queue_control_request(hfc, HFCUSB_CON_HDLC,
+- 9);
+- queue_control_request(hfc, HFCUSB_SCTRL,
+- 0x40 +
+- hfc->bch_enables);
+- queue_control_request(hfc, HFCUSB_SCTRL_R,
+- hfc->bch_enables);
+- restore_flags(flags);
+- fifo++;
+- if (fifo->active) {
+- fifo->active = 0;
+- usb_unlink_urb(&fifo->urb);
++ else
++ {
++#ifdef VERBOSE_ISDN_DEBUG
++ printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_ACTIVATE | REQUEST\n");
++#endif
++ set_hfcmode(hfc,(fifo->fifonum==HFCUSB_B1_TX) ? 0 : 1 ,(int)arg);
++ fifo->hif->l1l2(fifo->hif,PH_ACTIVATE | INDICATION, NULL);
+ }
+- return; /* fifo deactivated */
+- }
+- fifo->transmode = ((int) arg == L1_MODE_TRANS);
+- fifo->max_size =
+- ((fifo->transmode) ? fifo->
+- usb_maxlen : MAX_BCH_SIZE);
+- (fifo + 1)->transmode = fifo->transmode;
+- (fifo + 1)->max_size = fifo->max_size;
+- hfc->bch_enables |= (1 << chan);
+- save_flags(flags);
+- cli();
+- queue_control_request(hfc, HFCUSB_FIFO,
+- fifo->fifonum);
+- queue_control_request(hfc, HFCUSB_CON_HDLC,
+- ((!fifo->
+- transmode) ? 9 : 11));
+- queue_control_request(hfc, HFCUSB_INC_RES_F, 2);
+- queue_control_request(hfc, HFCUSB_SCTRL,
+- 0x40 + hfc->bch_enables);
+- if ((int) arg == L1_MODE_HDLC)
+- queue_control_request(hfc, HFCUSB_CON_HDLC,
+- 8);
+- queue_control_request(hfc, HFCUSB_FIFO,
+- fifo->fifonum + 1);
+- queue_control_request(hfc, HFCUSB_CON_HDLC,
+- ((!fifo->
+- transmode) ? 8 : 10));
+- queue_control_request(hfc, HFCUSB_INC_RES_F, 2);
+- queue_control_request(hfc, HFCUSB_SCTRL_R,
+- hfc->bch_enables);
+- restore_flags(flags);
+-
+- break;
+-
+- default:
+- printk(KERN_INFO
+- "unknown hfcusb bch_access chan %d 0x%x\n",
+- chan, pr);
+- break;
+- }
+-} /* hfcusb_bch_access */
++ break;
++ case PH_DEACTIVATE | REQUEST:
++ if(fifo->fifonum==HFCUSB_D_TX)
++ {
++#ifdef VERBOSE_ISDN_DEBUG
++ printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DEACTIVATE | REQUEST\n");
++#endif
++ printk (KERN_INFO "HFC-USB: ISDN TE device should not deativate...\n");
++ }
++ else
++ {
++#ifdef VERBOSE_ISDN_DEBUG
++ printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DEACTIVATE | REQUEST\n");
++#endif
++ set_hfcmode(hfc,(fifo->fifonum==HFCUSB_B1_TX) ? 0 : 1 ,(int)L1_MODE_NULL);
++ fifo->hif->l1l2(fifo->hif,PH_DEACTIVATE | INDICATION, NULL);
++ }
++ break;
++ case PH_DATA | REQUEST:
++ if(fifo->skbuff && fifo->delete_flg)
++ {
++ dev_kfree_skb_any(fifo->skbuff);
++ //printk(KERN_INFO "skbuff=NULL on fifo:%d\n",fifo->fifonum);
++ fifo->skbuff = NULL;
++ fifo->delete_flg=FALSE;
++ }
++
++ fifo->skbuff=arg; // we have a new buffer
++
++ //if(fifo->fifonum==HFCUSB_D_TX) printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DATA | REQUEST\n");
++ //else printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DATA | REQUEST\n");
++ break;
++ default:
++ printk (KERN_INFO "HFC_USB: hfc_usb_d_l2l1: unkown state : %#x\n", pr);
++ break;
++ }
++}
++
++// valid configurations
++#define CNF_4INT3ISO 1 // 4 INT IN, 3 ISO OUT
++#define CNF_3INT3ISO 2 // 3 INT IN, 3 ISO OUT
++#define CNF_4ISO3ISO 3 // 4 ISO IN, 3 ISO OUT
++#define CNF_3ISO3ISO 4 // 3 ISO IN, 3 ISO OUT
++
++
++/*
++ --------------------------------------------------------------------------------------
++ From here on USB initialization and deactivation related routines are implemented :
++
++ - hfc_usb_init :
++ is the main Entry Point for the USB Subsystem when the device get plugged
++ in. This function calls usb_register with usb_driver as parameter.
++ Here, further entry points for probing (hfc_usb_probe) and disconnecting
++ the device (hfc_usb_disconnect) are published, as the id_table
++
++ - hfc_usb_probe
++ this function is called by the usb subsystem, and steps through the alternate
++ settings of the currently plugged in device to detect all Endpoints needed to
++ run an ISDN TA.
++ Needed EndPoints are
++ 3 (+1) IntIn EndPoints (D-in, E-in, B1-in, B2-in, (E-in)) or
++ 3 (+1) Isochron In Endpoints (D-out, B1-out, B2-out) and 3 IsoOut Endpoints
++ The currently used transfer mode of on the Out-Endpoints will be stored in
++ hfc->usb_transfer_mode and is either USB_INT or USB_ISO
++ When a valid alternate setting could be found, the usb_init (see blow)
++ function is called
++
++ - usb_init
++ Here, the HFC_USB Chip itself gets initialized and the USB framework to send/receive
++ Data to/from the several EndPoints are initialized:
++ The E- and D-Channel Int-In chain gets started
++ The IsoChain for the Iso-Out traffic get started
++
++ - hfc_usb_disconnect
++ this function is called by the usb subsystem and has to free all resources
++ and stop all usb traffic to allow a proper hotplugging disconnect.
++
++*/
+
+ /***************************************************************************/
+ /* usb_init is called once when a new matching device is detected to setup */
+-/* main parmeters. It registers the driver at the main hisax module. */
++/* main parameters. It registers the driver at the main hisax module. */
+ /* on success 0 is returned. */
+ /***************************************************************************/
+-static int
+-usb_init(hfcusb_data * hfc)
++static int usb_init(hfcusb_data * hfc)
+ {
+ usb_fifo *fifo;
+- int i;
++ int i, err;
+ u_char b;
+-
++ struct hisax_b_if *p_b_if[2];
++
+ /* check the chip id */
+- if ((Read_hfc(hfc, HFCUSB_CHIP_ID, &b) != 1) ||
+- (b != HFCUSB_CHIPID)) {
++ printk(KERN_INFO "HFCUSB_CHIP_ID begin\n");
++ if (read_usb(hfc, HFCUSB_CHIP_ID, &b) != 1) {
++ printk(KERN_INFO "HFC-USB: cannot read chip id\n");
++ return(1);
++ }
++ printk(KERN_INFO "HFCUSB_CHIP_ID %x\n", b);
++ if (b != HFCUSB_CHIPID) {
+ printk(KERN_INFO "HFC-USB: Invalid chip id 0x%02x\n", b);
+- return (1);
++ return(1);
+ }
+
+ /* first set the needed config, interface and alternate */
+- usb_set_configuration(hfc->dev, 1);
+- usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used);
++ printk(KERN_INFO "usb_init 1\n");
++// usb_set_configuration(hfc->dev, 1);
++ printk(KERN_INFO "usb_init 2\n");
++ err = usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used);
++ printk(KERN_INFO "usb_init usb_set_interface return %d\n", err);
++ /* now we initialize the chip */
++ write_usb(hfc, HFCUSB_CIRM, 8); // do reset
++ write_usb(hfc, HFCUSB_CIRM, 0x10); // aux = output, reset off
+
+- /* init the led state request */
+- hfc->led_req = LED_DRIVER;
++ // set USB_SIZE to match the the wMaxPacketSize for INT or BULK transfers
++ write_usb(hfc, HFCUSB_USB_SIZE,(hfc->packet_size/8) | ((hfc->packet_size/8) << 4));
+
+- /* now we initialise the chip */
+- Write_hfc(hfc, HFCUSB_CIRM, 0x10); /* aux = output, reset off */
+- Write_hfc(hfc, HFCUSB_P_DATA, 0); /* leds = off */
+- Write_hfc(hfc, HFCUSB_USB_SIZE,
+- (hfc->fifos[HFCUSB_B1_TX].usb_maxlen >> 3) |
+- ((hfc->fifos[HFCUSB_B1_RX].usb_maxlen >> 3) << 4));
++ // set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers
++ write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size);
+
+ /* enable PCM/GCI master mode */
+- Write_hfc(hfc, HFCUSB_MST_MODE1, 0); /* set default values */
+- Write_hfc(hfc, HFCUSB_MST_MODE0, 1); /* enable master mode */
++ write_usb(hfc, HFCUSB_MST_MODE1, 0); /* set default values */
++ write_usb(hfc, HFCUSB_MST_MODE0, 1); /* enable master mode */
+
+ /* init the fifos */
+- Write_hfc(hfc, HFCUSB_F_THRES, (HFCUSB_TX_THRESHOLD >> 3) |
+- ((HFCUSB_RX_THRESHOLD >> 3) << 4));
++ write_usb(hfc, HFCUSB_F_THRES, (HFCUSB_TX_THRESHOLD/8) |((HFCUSB_RX_THRESHOLD/8) << 4));
+
+- for (i = 0, fifo = hfc->fifos + i; i < HFCUSB_NUM_FIFOS;
+- i++, fifo++) {
+- Write_hfc(hfc, HFCUSB_FIFO, i); /* select the desired fifo */
+-
+- fifo->transmode = 0; /* hdlc mode selected */
+- fifo->buff = NULL; /* init buffer pointer */
+- fifo->max_size =
+- (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN;
+- Write_hfc(hfc, HFCUSB_HDLC_PAR, ((i <= HFCUSB_B2_RX) ? 0 : 2)); /* data length */
+- Write_hfc(hfc, HFCUSB_CON_HDLC, ((i & 1) ? 0x08 : 0x09)); /* rx hdlc, tx fill 1 */
+- Write_hfc(hfc, HFCUSB_INC_RES_F, 2); /* reset the fifo */
+- }
+-
+- Write_hfc(hfc, HFCUSB_CLKDEL, 0x0f); /* clock delay value */
+- Write_hfc(hfc, HFCUSB_STATES, 3 | 0x10); /* set deactivated mode */
+- Write_hfc(hfc, HFCUSB_STATES, 3); /* enable state machine */
++ fifo = hfc->fifos;
++ for(i = 0; i < HFCUSB_NUM_FIFOS; i++)
++ {
++ write_usb(hfc, HFCUSB_FIFO, i); /* select the desired fifo */
++ fifo[i].skbuff = NULL; /* init buffer pointer */
++ fifo[i].max_size = (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN;
++ fifo[i].last_urblen=0;
++ write_usb(hfc, HFCUSB_HDLC_PAR, ((i <= HFCUSB_B2_RX) ? 0 : 2)); // set 2 bit for D- & E-channel
++ write_usb(hfc, HFCUSB_CON_HDLC, ((i==HFCUSB_D_TX) ? 0x09 : 0x08)); // rx hdlc, enable IFF for D-channel
++ write_usb(hfc, HFCUSB_INC_RES_F, 2); /* reset the fifo */
++ }
+
+- Write_hfc(hfc, HFCUSB_SCTRL_R, 0); /* disable both B receivers */
+- Write_hfc(hfc, HFCUSB_SCTRL, 0x40); /* disable B transmitters + cap mode */
++ write_usb(hfc, HFCUSB_CLKDEL, 0x0f); /* clock delay value */
++ write_usb(hfc, HFCUSB_STATES, 3 | 0x10); /* set deactivated mode */
++ write_usb(hfc, HFCUSB_STATES, 3); /* enable state machine */
++
++ write_usb(hfc, HFCUSB_SCTRL_R, 0); /* disable both B receivers */
++ write_usb(hfc, HFCUSB_SCTRL, 0x40); /* disable B transmitters + capacitive mode */
++
++ // set both B-channel to not connected
++ hfc->b_mode[0]=L1_MODE_NULL;
++ hfc->b_mode[1]=L1_MODE_NULL;
++
++ hfc->l1_activated=FALSE;
++ hfc->led_state=0;
++ hfc->led_new_data=0;
+
+- /* init the l1 timer */
++ /* init the t3 timer */
+ init_timer(&hfc->t3_timer);
+ hfc->t3_timer.data = (long) hfc;
+- hfc->t3_timer.function = (void *) l1_timer_expire;
++ hfc->t3_timer.function = (void *) l1_timer_expire_t3;
++ /* init the t4 timer */
++ init_timer(&hfc->t4_timer);
+ hfc->t4_timer.data = (long) hfc;
+- hfc->t4_timer.function = (void *) l1_timer_expire;
+- hfc->l1_tq.routine = (void *) (void *) usb_l1d_bh;
+- hfc->l1_tq.sync = 0;
+- hfc->l1_tq.data = hfc;
+-
+- /* init the background control machinery */
+- hfc->ctrl_read.requesttype = 0xc0;
+- hfc->ctrl_read.request = 1;
+- hfc->ctrl_read.length = 1;
+- hfc->ctrl_write.requesttype = 0x40;
+- hfc->ctrl_write.request = 0;
+- hfc->ctrl_write.length = 0;
+- FILL_CONTROL_URB(&hfc->ctrl_urb, hfc->dev, hfc->ctrl_out_pipe,
+- (u_char *) & hfc->ctrl_write, NULL, 0,
+- ctrl_complete, hfc);
+-
+- /* init the TX-urbs */
+- fifo = hfc->fifos + HFCUSB_D_TX;
+- FILL_BULK_URB(&fifo->urb, hfc->dev, fifo->pipe,
+- (u_char *) fifo->buffer, 0, tx_complete, fifo);
+- fifo = hfc->fifos + HFCUSB_B1_TX;
+- FILL_BULK_URB(&fifo->urb, hfc->dev, fifo->pipe,
+- (u_char *) fifo->buffer, 0, tx_complete, fifo);
+- fifo = hfc->fifos + HFCUSB_B2_TX;
+- FILL_BULK_URB(&fifo->urb, hfc->dev, fifo->pipe,
+- (u_char *) fifo->buffer, 0, tx_complete, fifo);
+-
+- /* init the E-buffer */
+- skb_queue_head_init(&hfc->regd.erq);
+-
+- /* now register ourself at hisax */
+- hfc->regd.version = HISAX_LOAD_VERSION; /* set our version */
+- hfc->regd.cmd = HISAX_LOAD_REGISTER; /* register command */
+- hfc->regd.argl1 = (void *) hfc; /* argument for our local routine */
+- hfc->regd.dch_l2l1 = hfcusb_l1_access;
+- hfc->regd.bch_l2l1 = hfcusb_bch_access;
+- hfc->regd.drvname = "hfc_usb";
+- if (hisax_register_hfcusb(&hfc->regd)) {
+- printk(KERN_INFO "HFC-USB failed to register at hisax\n");
+- Write_hfc(hfc, HFCUSB_CIRM, 0x08); /* aux = input, reset on */
+- return (1);
+- }
+-
+- /* startup the D- and E-channel fifos */
+- start_rx_fifo(hfc->fifos + HFCUSB_D_RX); /* D-fifo */
+- if (hfc->fifos[HFCUSB_PCM_RX].pipe)
+- start_rx_fifo(hfc->fifos + HFCUSB_PCM_RX); /* E-fifo */
++ hfc->t4_timer.function = (void *) l1_timer_expire_t4;
++ /* init the led timer */
++ init_timer(&hfc->led_timer);
++ hfc->led_timer.data = (long) hfc;
++ hfc->led_timer.function = (void *) led_timer;
++ // trigger 4 hz led timer
++ hfc->led_timer.expires = jiffies + (LED_TIME * HZ) / 1000;
++ if(!timer_pending(&hfc->led_timer)) add_timer(&hfc->led_timer);
++
++ // init the background machinery for control requests
++ hfc->ctrl_read.bRequestType = 0xc0;
++ hfc->ctrl_read.bRequest = 1;
++ hfc->ctrl_read.wLength = 1;
++ hfc->ctrl_write.bRequestType = 0x40;
++ hfc->ctrl_write.bRequest = 0;
++ hfc->ctrl_write.wLength = 0;
++ usb_fill_control_urb(hfc->ctrl_urb, hfc->dev, hfc->ctrl_out_pipe,(u_char *) & hfc->ctrl_write, NULL, 0, ctrl_complete, hfc);
++
++ /* Init All Fifos */
++ for(i = 0; i < HFCUSB_NUM_FIFOS; i++)
++ {
++ hfc->fifos[i].iso[0].purb = NULL;
++ hfc->fifos[i].iso[1].purb = NULL;
++ hfc->fifos[i].active = 0;
++ }
++
++ // register like Germaschewski :
++ hfc->d_if.owner = THIS_MODULE;
++ hfc->d_if.ifc.priv = &hfc->fifos[HFCUSB_D_TX];
++ hfc->d_if.ifc.l2l1 = hfc_usb_l2l1;
++
++ for (i=0; i<2; i++)
++ {
++ hfc->b_if[i].ifc.priv = &hfc->fifos[HFCUSB_B1_TX+i*2];
++ hfc->b_if[i].ifc.l2l1 = hfc_usb_l2l1;
++ p_b_if[i] = &hfc->b_if[i];
++ }
++
++ hfc->protocol = 2; /* default EURO ISDN, should be a module_param */
++ hisax_register(&hfc->d_if, p_b_if, "hfc_usb", hfc->protocol);
++
++ for (i=0; i<4; i++)
++ hfc->fifos[i].hif=&p_b_if[i/2]->ifc;
++ for (i=4; i<8; i++)
++ hfc->fifos[i].hif=&hfc->d_if.ifc;
++
++ // 3 (+1) INT IN + 3 ISO OUT
++ if(hfc->cfg_used == CNF_3INT3ISO || hfc->cfg_used == CNF_4INT3ISO)
++ {
++ start_int_fifo(hfc->fifos + HFCUSB_D_RX); // Int IN D-fifo
++ if(hfc->fifos[HFCUSB_PCM_RX].pipe) start_int_fifo(hfc->fifos + HFCUSB_PCM_RX); // E-fifo
++ start_int_fifo(hfc->fifos + HFCUSB_B1_RX); // Int IN B1-fifo
++ start_int_fifo(hfc->fifos + HFCUSB_B2_RX); // Int IN B2-fifo
++ }
++
++ // 3 (+1) ISO IN + 3 ISO OUT
++ if(hfc->cfg_used==CNF_3ISO3ISO || hfc->cfg_used==CNF_4ISO3ISO)
++ {
++ start_isoc_chain(hfc->fifos + HFCUSB_D_RX, ISOC_PACKETS_D, rx_iso_complete,16);
++ if(hfc->fifos[HFCUSB_PCM_RX].pipe) start_isoc_chain(hfc->fifos + HFCUSB_PCM_RX, ISOC_PACKETS_D, rx_iso_complete,16);
++ start_isoc_chain(hfc->fifos + HFCUSB_B1_RX, ISOC_PACKETS_B, rx_iso_complete,16);
++ start_isoc_chain(hfc->fifos + HFCUSB_B2_RX, ISOC_PACKETS_B, rx_iso_complete,16);
++ }
++
++ start_isoc_chain(hfc->fifos + HFCUSB_D_TX, ISOC_PACKETS_D, tx_iso_complete,1);
++ start_isoc_chain(hfc->fifos + HFCUSB_B1_TX, ISOC_PACKETS_B, tx_iso_complete,1);
++ start_isoc_chain(hfc->fifos + HFCUSB_B2_TX, ISOC_PACKETS_B, tx_iso_complete,1);
++
++ handle_led(hfc,LED_POWER_ON);
++
++ return(0);
++} /* usb_init */
++
++
++/****************************************/
++/* data defining the devices to be used */
++/****************************************/
++// static __devinitdata const struct usb_device_id hfc_usb_idtab[3] = {
++static struct usb_device_id hfc_usb_idtab[] = {
++ {USB_DEVICE(0x7b0, 0x0007)}, /* Billion USB TA 2 */
++ {USB_DEVICE(0x742, 0x2008)}, /* Stollmann USB TA */
++ {USB_DEVICE(0x959, 0x2bd0)}, /* Colognechip USB eval TA */
++ {USB_DEVICE(0x8e3, 0x0301)}, /* OliTec ISDN USB */
++ {USB_DEVICE(0x675, 0x1688)}, /* DrayTec ISDN USB */
++ {USB_DEVICE(0x7fa, 0x0846)}, /* Bewan ISDN USB TA */
++ {} /* end with an all-zeroes entry */
++};
++
++MODULE_AUTHOR("Peter Sprenger (sprenger@moving-byters.de)/Martin Bachem (info@colognechip.com)");
++MODULE_DESCRIPTION("HFC I4L USB driver");
++MODULE_DEVICE_TABLE(usb, hfc_usb_idtab);
++MODULE_LICENSE("GPL");
++
++#define EP_NUL 1 // Endpoint at this position not allowed
++#define EP_NOP 2 // all type of endpoints allowed at this position
++#define EP_ISO 3 // Isochron endpoint mandatory at this position
++#define EP_BLK 4 // Bulk endpoint mandatory at this position
++#define EP_INT 5 // Interrupt endpoint mandatory at this position
++
++// this array represents all endpoints possible in the HCF-USB
++// the last 2 entries are the configuration number and the minimum interval for Interrupt endpoints
++int validconf[][18]=
++{
++ // INT in, ISO out config
++ {EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NOP,EP_INT,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_NUL,EP_NUL,CNF_4INT3ISO,2},
++ {EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_INT,EP_NUL,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_ISO,EP_NUL,EP_NUL,EP_NUL,CNF_3INT3ISO,2},
++ // ISO in, ISO out config
++ {EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_NOP,EP_ISO,CNF_4ISO3ISO,2},
++ {EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_NUL,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_ISO,EP_NUL,EP_NUL,CNF_3ISO3ISO,2},
++ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} // EOL element
++};
++
++// string description of chosen config
++char *conf_str[]=
++{
++ "4 Interrupt IN + 3 Isochron OUT",
++ "3 Interrupt IN + 3 Isochron OUT",
++ "4 Isochron IN + 3 Isochron OUT",
++ "3 Isochron IN + 3 Isochron OUT"
++};
+
+- return (0);
+-} /* usb_init */
+
+ /*************************************************/
+ /* function called to probe a new plugged device */
+ /*************************************************/
+-static void *
+-hfc_usb_probe(struct usb_device *dev, unsigned int interface
+-#ifdef COMPAT_HAS_USB_IDTAB
+- , const struct usb_device_id *id_table)
+-#else
+- )
+-#endif
++//static int hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
++static void* hfc_usb_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id)
+ {
++ //struct usb_device *dev= interface_to_usbdev(intf);
++ struct usb_interface* intf = dev->actconfig->interface + ifnum;
+ hfcusb_data *context;
+- struct usb_interface *ifp = dev->actconfig->interface + interface;
+- struct usb_interface_descriptor *ifdp =
+- ifp->altsetting + ifp->act_altsetting;
+- struct usb_endpoint_descriptor *epd;
+- int i, idx, ep_msk;
+-
+-#ifdef COMPAT_HAS_USB_IDTAB
+- if (id_table && (dev->descriptor.idVendor == id_table->idVendor) &&
+- (dev->descriptor.idProduct == id_table->idProduct) &&
+-#else
+- if ((((dev->descriptor.idVendor == 0x959) &&
+- (dev->descriptor.idProduct == 0x2bd0)) ||
+- ((dev->descriptor.idVendor == 0x7b0) &&
+- (dev->descriptor.idProduct == 0x0006))) &&
+-#endif
+- (ifdp->bNumEndpoints >= 6) && (ifdp->bNumEndpoints <= 16)) {
+- if (!(context = kmalloc(sizeof(hfcusb_data), GFP_KERNEL))) {
+- return (NULL); /* got no mem */
+- };
+- memset(context, 0, sizeof(hfcusb_data)); /* clear the structure */
+- i = ifdp->bNumEndpoints; /* get number of endpoints */
+- ep_msk = 0; /* none found */
+- epd = ifdp->endpoint; /* first endpoint descriptor */
+- while (i-- && ((ep_msk & 0xcf) != 0xcf)) {
+-
+- idx = (((epd->bEndpointAddress & 0x7f) - 1) << 1); /* get endpoint base */
+- if (idx < 7) {
+- switch (epd->bmAttributes) {
+- case USB_ENDPOINT_XFER_INT:
+- if (!
+- (epd->
+- bEndpointAddress &
+- 0x80))
+- break; /* only interrupt in allowed */
+- idx++; /* input index is odd */
+- context->fifos[idx].pipe =
+- usb_rcvintpipe(dev,
+- epd->
+- bEndpointAddress);
+- break;
+-
+- case USB_ENDPOINT_XFER_BULK:
+- if (epd->
+- bEndpointAddress &
+- 0x80)
+- break; /* only bulk out allowed */
+- context->fifos[idx].pipe =
+- usb_sndbulkpipe(dev,
+- epd->
+- bEndpointAddress);
+- break;
+- default:
+- context->fifos[idx].pipe = 0; /* reset data */
+- } /* switch attribute */
+-
+- if (context->fifos[idx].pipe) {
+- context->fifos[idx].fifonum = idx;
+- context->fifos[idx].fifo_mask =
+- 1 << idx;
+- context->fifos[idx].hfc = context;
+- context->fifos[idx].usb_maxlen =
+- epd->wMaxPacketSize;
+- context->fifos[idx].intervall =
+- epd->bInterval;
+- ep_msk |= (1 << idx);
+- } else
+- ep_msk &= ~(1 << idx);
+- } /* idx < 7 */
+- epd++;
+- }
++ //struct usb_host_interface *iface = intf->cur_altsetting;
++ //struct usb_host_interface *iface_used = NULL;
++ //struct usb_host_endpoint *ep;
++ struct usb_endpoint_descriptor* ep;
++ //int ifnum = iface->desc.bInterfaceNumber;
++ struct usb_interface_descriptor* intfdesc = intf->altsetting + intf->act_altsetting;
++ struct usb_interface_descriptor* intfdesc_used = NULL;
++ int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf, attr, cfg_found, cidx, ep_addr;
++ int cmptbl[16],small_match,iso_packet_size,packet_size,alt_used=0;
++
++// usb_show_device(dev);
++// usb_show_device_descriptor(&dev->descriptor);
++// usb_show_interface_descriptor(&iface->desc);
++ vend_idx=0xffff;
++ for(i=0;vdata[i].vendor;i++)
++ {
++ if(dev->descriptor.idVendor==vdata[i].vendor && dev->descriptor.idProduct==vdata[i].prod_id) vend_idx=i;
++ }
++
+
+- if ((ep_msk & 0x3f) != 0x3f) {
+- kfree(context);
+- return (NULL);
+- }
+- MOD_INC_USE_COUNT; /* lock our module */
+- context->dev = dev; /* save device */
+- context->if_used = interface; /* save used interface */
+- context->alt_used = ifp->act_altsetting; /* and alternate config */
+- context->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */
+-
+- /* create the control pipes needed for register access */
+- context->ctrl_in_pipe = usb_rcvctrlpipe(context->dev, 0);
+- context->ctrl_out_pipe = usb_sndctrlpipe(context->dev, 0);
+-
+- /* init the chip and register the driver */
+- if (usb_init(context)) {
+- kfree(context);
+- MOD_DEC_USE_COUNT;
+- return (NULL);
+- }
++#ifdef VERBOSE_USB_DEBUG
++ printk(KERN_INFO "HFC-USB: probing interface(%d) actalt(%d)\n",
++ ifnum, intfdesc->bAlternateSetting);
++ /* printk(KERN_INFO "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n",
++ ifnum, intfdesc->bAlternateSetting, intf->driver->minor); */
++#endif
+
+- printk(KERN_INFO
+- "HFC-USB: New device if=%d alt=%d registered\n",
+- context->if_used, context->alt_used);
+- return (context);
+- }
++ if (vend_idx != 0xffff) {
++#ifdef VERBOSE_USB_DEBUG
++ printk(KERN_INFO "HFC-USB: found vendor idx:%d name:%s\n",vend_idx,vdata[vend_idx].vend_name);
++#endif
++ /* if vendor and product ID is OK, start probing a matching alternate setting ... */
++ alt_idx = 0;
++ small_match=0xffff;
++ // default settings
++ iso_packet_size=16;
++ packet_size=64;
++
++ while (alt_idx < intf->num_altsetting) {
++ //iface = intf->altsetting + alt_idx;
++ intfdesc = intf->altsetting + alt_idx;
++ probe_alt_setting = intfdesc->bAlternateSetting;
++ cfg_used=0;
+
+- return (NULL); /* no matching entry */
+-} /* hfc_usb_probe */
++#ifdef VERBOSE_USB_DEBUG
++ printk(KERN_INFO "HFC-USB: test alt_setting %d\n", probe_alt_setting);
++#endif
++ // check for config EOL element
++ while (validconf[cfg_used][0]) {
++ cfg_found=TRUE;
++ vcf=validconf[cfg_used];
++ ep = intfdesc->endpoint; /* first endpoint descriptor */
++
++#ifdef VERBOSE_USB_DEBUG
++ printk(KERN_INFO "HFC-USB: (if=%d alt=%d cfg_used=%d)\n",
++ ifnum, probe_alt_setting, cfg_used);
++#endif
++ // copy table
++ memcpy(cmptbl,vcf,16*sizeof(int));
++
++ // check for all endpoints in this alternate setting
++ for (i=0; i < intfdesc->bNumEndpoints; i++) {
++ ep_addr = ep->bEndpointAddress;
++ idx = ((ep_addr & 0x7f)-1)*2; /* get endpoint base */
++ if (ep_addr & 0x80)
++ idx++;
++ attr = ep->bmAttributes;
++
++ if (cmptbl[idx] == EP_NUL) {
++ printk(KERN_INFO "HFC-USB: cfg_found=FALSE in idx:%d attr:%d cmptbl[%d]:%d\n",
++ idx, attr, idx, cmptbl[idx]);
++ cfg_found = FALSE;
++ }
++
++ if (attr == USB_ENDPOINT_XFER_INT && cmptbl[idx] == EP_INT)
++ cmptbl[idx] = EP_NUL;
++ if (attr == USB_ENDPOINT_XFER_BULK && cmptbl[idx] == EP_BLK)
++ cmptbl[idx] = EP_NUL;
++ if (attr == USB_ENDPOINT_XFER_ISOC && cmptbl[idx] == EP_ISO)
++ cmptbl[idx] = EP_NUL;
++
++ // check if all INT endpoints match minimum interval
++ if (attr == USB_ENDPOINT_XFER_INT && ep->bInterval < vcf[17]) {
++#ifdef VERBOSE_USB_DEBUG
++ if (cfg_found)
++ printk(KERN_INFO "HFC-USB: Interrupt Endpoint interval < %d found - skipping config\n",
++ vcf[17]);
++#endif
++ cfg_found = FALSE;
++ }
++
++ ep++;
++ }
++
++ for (i = 0; i < 16; i++) {
++ // printk(KERN_INFO "HFC-USB: cmptbl[%d]:%d\n", i, cmptbl[i]);
++
++ // all entries must be EP_NOP or EP_NUL for a valid config
++ if (cmptbl[i] != EP_NOP && cmptbl[i] != EP_NUL)
++ cfg_found = FALSE;
++ }
++
++ // we check for smallest match, to provide configuration priority
++ // configurations with smaller index have higher priority
++ if (cfg_found) {
++ if (cfg_used < small_match) {
++ small_match = cfg_used;
++ alt_used = probe_alt_setting;
++ //iface_used = iface;
++ intfdesc_used = intfdesc;
++ }
++#ifdef VERBOSE_USB_DEBUG
++ printk(KERN_INFO "HFC-USB: small_match=%x %x\n", small_match, alt_used);
++#endif
++ }
++
++ cfg_used++;
++ }
++
++ alt_idx++;
++ } /* (alt_idx < intf->num_altsetting) */
++#ifdef VERBOSE_USB_DEBUG
++ printk(KERN_INFO "HFC-USB: final small_match=%x alt_used=%x\n",small_match, alt_used);
++#endif
++ // yiipiee, we found a valid config
++ if (small_match != 0xffff) {
++ //iface = iface_used;
++ intfdesc = intfdesc_used;
++
++ if (!(context = kmalloc(sizeof(hfcusb_data), GFP_KERNEL)))
++ return(NULL); /* got no mem */
++ memset(context, 0, sizeof(hfcusb_data)); /* clear the structure */
++
++ ep = intfdesc->endpoint; /* first endpoint descriptor */
++ vcf = validconf[small_match];
++
++ for (i = 0; i < intfdesc->bNumEndpoints; i++) {
++ ep_addr = ep->bEndpointAddress;
++ idx = ((ep_addr & 0x7f)-1)*2; /* get endpoint base */
++ if (ep_addr & 0x80)
++ idx++;
++ cidx = idx & 7;
++ attr = ep->bmAttributes;
++
++ // only initialize used endpoints
++ if (vcf[idx] != EP_NOP && vcf[idx] != EP_NUL) {
++ switch (attr) {
++ case USB_ENDPOINT_XFER_INT:
++ context->fifos[cidx].pipe = usb_rcvintpipe(dev, ep->bEndpointAddress);
++ context->fifos[cidx].usb_transfer_mode = USB_INT;
++ packet_size = ep->wMaxPacketSize; // remember max packet size
++#ifdef VERBOSE_USB_DEBUG
++ printk (KERN_INFO "HFC-USB: Interrupt-In Endpoint found %d ms(idx:%d cidx:%d)!\n",
++ ep->bInterval, idx, cidx);
++#endif
++ break;
++ case USB_ENDPOINT_XFER_BULK:
++ if (ep_addr & 0x80)
++ context->fifos[cidx].pipe = usb_rcvbulkpipe(dev, ep->bEndpointAddress);
++ else
++ context->fifos[cidx].pipe = usb_sndbulkpipe(dev, ep->bEndpointAddress);
++ context->fifos[cidx].usb_transfer_mode = USB_BULK;
++ packet_size = ep->wMaxPacketSize; // remember max packet size
++#ifdef VERBOSE_USB_DEBUG
++ printk (KERN_INFO "HFC-USB: Bulk Endpoint found (idx:%d cidx:%d)!\n",
++ idx, cidx);
++#endif
++ break;
++ case USB_ENDPOINT_XFER_ISOC:
++ if (ep_addr & 0x80)
++ context->fifos[cidx].pipe = usb_rcvisocpipe(dev, ep->bEndpointAddress);
++ else
++ context->fifos[cidx].pipe = usb_sndisocpipe(dev, ep->bEndpointAddress);
++ context->fifos[cidx].usb_transfer_mode = USB_ISOC;
++ iso_packet_size = ep->wMaxPacketSize; // remember max packet size
++#ifdef VERBOSE_USB_DEBUG
++ printk (KERN_INFO "HFC-USB: ISO Endpoint found (idx:%d cidx:%d)!\n",
++ idx, cidx);
++#endif
++ break;
++ default:
++ context->fifos[cidx].pipe = 0; /* reset data */
++ } /* switch attribute */
++
++ if (context->fifos[cidx].pipe) {
++ context->fifos[cidx].fifonum = cidx;
++ context->fifos[cidx].hfc = context;
++ context->fifos[cidx].usb_packet_maxlen = ep->wMaxPacketSize;
++ context->fifos[cidx].intervall = ep->bInterval;
++ context->fifos[cidx].skbuff = NULL;
++#ifdef VERBOSE_USB_DEBUG
++ printk (KERN_INFO "HFC-USB: fifo%d pktlen %d interval %d\n",
++ context->fifos[cidx].fifonum,
++ context->fifos[cidx].usb_packet_maxlen,
++ context->fifos[cidx].intervall);
++#endif
++ }
++ }
++
++ ep++;
++ }
++
++ // now share our luck
++ context->dev = dev; /* save device */
++ context->if_used = ifnum; /* save used interface */
++ context->alt_used = alt_used; /* and alternate config */
++ context->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */
++ context->cfg_used=vcf[16]; // store used config
++ context->vend_idx=vend_idx; // store found vendor
++ context->packet_size=packet_size;
++ context->iso_packet_size=iso_packet_size;
++
++ /* create the control pipes needed for register access */
++ context->ctrl_in_pipe = usb_rcvctrlpipe(context->dev, 0);
++ context->ctrl_out_pipe = usb_sndctrlpipe(context->dev, 0);
++ context->ctrl_urb = usb_alloc_urb(0);
++
++ printk(KERN_INFO "HFC-USB: detected \"%s\" configuration: %s (if=%d alt=%d)\n",
++ vdata[vend_idx].vend_name, conf_str[small_match], context->if_used, context->alt_used);
++
++ /* init the chip and register the driver */
++ if (usb_init(context))
++ {
++ if (context->ctrl_urb) {
++ usb_unlink_urb(context->ctrl_urb);
++ usb_free_urb(context->ctrl_urb);
++ context->ctrl_urb = NULL;
++ }
++ kfree(context);
++ return(NULL);
++ }
++ //usb_set_intfdata(intf, context);
++ //intf->private_data = context;
++ return(context);
++ }
++ }
++ return(NULL);
++}
+
+ /****************************************************/
+ /* function called when an active device is removed */
+ /****************************************************/
+-static void
+-hfc_usb_disconnect(struct usb_device *usbdev, void *drv_context)
++//static void hfc_usb_disconnect(struct usb_interface *intf)
++static void hfc_usb_disconnect(struct usb_device *usbdev, void* drv_context)
+ {
+- hfcusb_data *context = drv_context;
++ //hfcusb_data *context = intf->private_data;
++ hfcusb_data* context = drv_context;
+ int i;
+- struct sk_buff *skb;
+
+- /* tell all fifos to terminate */
+- for (i = 0; i < HFCUSB_NUM_FIFOS; i++)
+- if (context->fifos[i].active) {
+- context->fifos[i].active = 0;
+- usb_unlink_urb(&context->fifos[i].urb);
+- }
+- while (context->active_fifos) {
+- set_current_state(TASK_INTERRUPTIBLE);
+- /* Timeout 10ms */
+- schedule_timeout((10 * HZ) / 1000);
+- }
++ printk(KERN_INFO "HFC-USB: device disconnect\n");
++
++ //intf->private_data = NULL;
++ if (!context)
++ return;
+ if (timer_pending(&context->t3_timer))
+ del_timer(&context->t3_timer);
+- context->regd.release_driver(context->regd.arg_hisax);
+- while ((skb = skb_dequeue(&context->regd.erq)) != NULL)
+- dev_kfree_skb_any(skb);
++ if (timer_pending(&context->t4_timer))
++ del_timer(&context->t4_timer);
++ if (timer_pending(&context->led_timer))
++ del_timer(&context->led_timer);
++
++ hisax_unregister(&context->d_if);
+
++ /* tell all fifos to terminate */
++ for(i = 0; i < HFCUSB_NUM_FIFOS; i++) {
++ if(context->fifos[i].usb_transfer_mode == USB_ISOC) {
++ if(context->fifos[i].active > 0) {
++ stop_isoc_chain(&context->fifos[i]);
++#ifdef VERBOSE_USB_DEBUG
++ printk (KERN_INFO "HFC-USB: hfc_usb_disconnect: stopping ISOC chain Fifo no %i\n", i);
++#endif
++ }
++ } else {
++ if(context->fifos[i].active > 0) {
++ context->fifos[i].active = 0;
++#ifdef VERBOSE_USB_DEBUG
++ printk (KERN_INFO "HFC-USB: hfc_usb_disconnect: unlinking URB for Fifo no %i\n", i);
++#endif
++ }
++ if (context->fifos[i].urb) {
++ usb_unlink_urb(context->fifos[i].urb);
++ usb_free_urb(context->fifos[i].urb);
++ context->fifos[i].urb = NULL;
++ }
++ }
++ context->fifos[i].active = 0;
++ }
++ if (context->ctrl_urb) {
++ usb_unlink_urb(context->ctrl_urb);
++ usb_free_urb(context->ctrl_urb);
++ context->ctrl_urb = NULL;
++ }
+ kfree(context); /* free our structure again */
+- MOD_DEC_USE_COUNT; /* and decrement the usage counter */
+ } /* hfc_usb_disconnect */
+
++
+ /************************************/
+ /* our driver information structure */
+ /************************************/
+ static struct usb_driver hfc_drv = {
+ name:"hfc_usb",
+-#ifdef COMPAT_HAS_USB_IDTAB
+ id_table:hfc_usb_idtab,
+-#endif
+ probe:hfc_usb_probe,
+ disconnect:hfc_usb_disconnect,
+ };
+
+-static void __exit
+-hfc_usb_exit(void)
+-{
+
++static void __exit hfc_usb_exit(void)
++{
++#ifdef VERBOSE_USB_DEBUG
++ printk ("HFC-USB: calling \"hfc_usb_exit\" ...\n");
++#endif
+ usb_deregister(&hfc_drv); /* release our driver */
+ printk(KERN_INFO "HFC-USB module removed\n");
+ }
+
+-static int __init
+-hfc_usb_init(void)
++static int __init hfc_usb_init(void)
+ {
+- struct hisax_drvreg drv;
++ printk ("HFC-USB: driver module revision %s loaded\n", hfcusb_revision);
+
+- drv.version = HISAX_LOAD_VERSION; /* set our version */
+- drv.cmd = HISAX_LOAD_CHKVER; /* check command only */
+- if (hisax_register_hfcusb(&drv)) {
+- printk(KERN_INFO "HFC-USB <-> hisax version conflict\n");
+- return (-1); /* unable to register */
+- }
+- if (usb_register(&hfc_drv)) {
+- printk(KERN_INFO
+- "Unable to register HFC-USB module at usb stack\n");
+- return (-1); /* unable to register */
++ if(usb_register(&hfc_drv))
++ {
++ printk(KERN_INFO "HFC-USB: Unable to register HFC-USB module at usb stack\n");
++ return(-1); /* unable to register */
+ }
+-
+- printk(KERN_INFO "HFC-USB module loaded\n");
+- return (0);
++ return(0);
+ }
+
++
++
++
++
+ module_init(hfc_usb_init);
+ module_exit(hfc_usb_exit);
++
diff --git a/target/linux/generic-2.4/patches/202-pl2303_backport.patch b/target/linux/generic-2.4/patches/202-pl2303_backport.patch
new file mode 100644
index 0000000..f889ad2
--- /dev/null
+++ b/target/linux/generic-2.4/patches/202-pl2303_backport.patch
@@ -0,0 +1,40 @@
+diff -ur linux-2.4.32/drivers/usb/serial/pl2303.c linux-2.4.32.openwrt/drivers/usb/serial/pl2303.c
+--- linux-2.4.32/drivers/usb/serial/pl2303.c 2005-06-01 02:56:56.000000000 +0200
++++ linux-2.4.32.openwrt/drivers/usb/serial/pl2303.c 2005-11-18 12:22:23.000000000 +0100
+@@ -78,6 +78,11 @@
+ { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
+ { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
+ { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
++ { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
++ { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
++ { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
++ { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
++ { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
+ { } /* Terminating entry */
+ };
+
+diff -ur linux-2.4.32/drivers/usb/serial/pl2303.h linux-2.4.32.openwrt/drivers/usb/serial/pl2303.h
+--- linux-2.4.32/drivers/usb/serial/pl2303.h 2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.32.openwrt/drivers/usb/serial/pl2303.h 2005-11-18 12:23:38.000000000 +0100
+@@ -41,3 +41,21 @@
+
+ #define SITECOM_VENDOR_ID 0x6189
+ #define SITECOM_PRODUCT_ID 0x2068
++
++/* Alcatel OT535/735 USB cable */
++#define ALCATEL_VENDOR_ID 0x11f7
++#define ALCATEL_PRODUCT_ID 0x02df
++
++/* Samsung I330 phone cradle */
++#define SAMSUNG_VENDOR_ID 0x04e8
++#define SAMSUNG_PRODUCT_ID 0x8001
++
++#define SIEMENS_VENDOR_ID 0x11f5
++#define SIEMENS_PRODUCT_ID_X65 0x0003
++
++#define SYNTECH_VENDOR_ID 0x0745
++#define SYNTECH_PRODUCT_ID 0x0001
++
++/* Nokia CA-42 Cable */
++#define NOKIA_CA42_VENDOR_ID 0x078b
++#define NOKIA_CA42_PRODUCT_ID 0x1234
diff --git a/target/linux/generic-2.4/patches/203-hfsplus_fix.patch b/target/linux/generic-2.4/patches/203-hfsplus_fix.patch
new file mode 100644
index 0000000..695a2d3
--- /dev/null
+++ b/target/linux/generic-2.4/patches/203-hfsplus_fix.patch
@@ -0,0 +1,23 @@
+diff -urN linux-2.4.30.old/fs/hfsplus/super.c linux-2.4.30.dev/fs/hfsplus/super.c
+--- linux-2.4.30.old/fs/hfsplus/super.c 2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.30.dev/fs/hfsplus/super.c 2005-04-27 19:54:40.000000000 +0200
+@@ -240,8 +240,7 @@
+ if (!(*flags & MS_RDONLY)) {
+ struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr;
+
+- if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_INCNSTNT)) ||
+- !(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
++ if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
+ printk("HFS+-fs warning: Filesystem was not cleanly unmounted, "
+ "running fsck.hfsplus is recommended. leaving read-only.\n");
+ sb->s_flags |= MS_RDONLY;
+@@ -343,8 +342,7 @@
+ /* Set up operations so we can load metadata */
+ sb->s_op = &hfsplus_sops;
+
+- if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_INCNSTNT)) ||
+- !(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
++ if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) {
+ if (!silent)
+ printk("HFS+-fs warning: Filesystem was not cleanly unmounted, "
+ "running fsck.hfsplus is recommended. mounting read-only.\n");
diff --git a/target/linux/generic-2.4/patches/206-gcc_3.4_fixes.patch b/target/linux/generic-2.4/patches/206-gcc_3.4_fixes.patch
new file mode 100644
index 0000000..9cf0553
--- /dev/null
+++ b/target/linux/generic-2.4/patches/206-gcc_3.4_fixes.patch
@@ -0,0 +1,225 @@
+diff -Nur linux-2.4.30/arch/mips/kernel/signal.c linux-2.4.30.openwrt/arch/mips/kernel/signal.c
+--- linux-2.4.30/arch/mips/kernel/signal.c 2005-07-02 13:00:13.000000000 +0200
++++ linux-2.4.30.openwrt/arch/mips/kernel/signal.c 2005-07-02 13:00:49.000000000 +0200
+@@ -6,8 +6,10 @@
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1994 - 1999 Ralf Baechle
+ * Copyright (C) 1999 Silicon Graphics, Inc.
++ * Copyright (C) 2004 Maciej W. Rozycki
+ */
+ #include <linux/config.h>
++#include <linux/compiler.h>
+ #include <linux/sched.h>
+ #include <linux/mm.h>
+ #include <linux/smp.h>
+@@ -76,7 +78,9 @@
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+ save_static_function(sys_sigsuspend);
+-static_unused int _sys_sigsuspend(struct pt_regs regs)
++static int _sys_sigsuspend(struct pt_regs regs)
++ __asm__("_sys_sigsuspend") __attribute_used__;
++static int _sys_sigsuspend(struct pt_regs regs)
+ {
+ sigset_t *uset, saveset, newset;
+
+@@ -102,7 +106,9 @@
+ }
+
+ save_static_function(sys_rt_sigsuspend);
+-static_unused int _sys_rt_sigsuspend(struct pt_regs regs)
++static int _sys_rt_sigsuspend(struct pt_regs regs)
++ __asm__("_sys_rt_sigsuspend") __attribute_used__;
++static int _sys_rt_sigsuspend(struct pt_regs regs)
+ {
+ sigset_t *unewset, saveset, newset;
+ size_t sigsetsize;
+diff -Nur linux-2.4.30/arch/mips/kernel/syscall.c linux-2.4.30.openwrt/arch/mips/kernel/syscall.c
+--- linux-2.4.30/arch/mips/kernel/syscall.c 2005-07-02 13:00:13.000000000 +0200
++++ linux-2.4.30.openwrt/arch/mips/kernel/syscall.c 2005-07-02 13:00:49.000000000 +0200
+@@ -5,6 +5,7 @@
+ *
+ * Copyright (C) 1995 - 2000 by Ralf Baechle
+ * Copyright (C) 2000 Silicon Graphics, Inc.
++ * Copyright (C) 2004 Maciej W. Rozycki
+ *
+ * TODO: Implement the compatibility syscalls.
+ * Don't waste that much memory for empty entries in the syscall
+@@ -158,7 +159,9 @@
+ }
+
+ save_static_function(sys_fork);
+-static_unused int _sys_fork(struct pt_regs regs)
++static int _sys_fork(struct pt_regs regs)
++ __asm__("_sys_fork") __attribute_used__;
++static int _sys_fork(struct pt_regs regs)
+ {
+ int res;
+
+@@ -168,7 +171,9 @@
+
+
+ save_static_function(sys_clone);
+-static_unused int _sys_clone(struct pt_regs regs)
++static int _sys_clone(struct pt_regs regs)
++ __asm__("_sys_clone") __attribute_used__;
++static int _sys_clone(struct pt_regs regs)
+ {
+ unsigned long clone_flags;
+ unsigned long newsp;
+diff -Nur linux-2.4.30/arch/mips/ld.script.in linux-2.4.30.openwrt/arch/mips/ld.script.in
+--- linux-2.4.30/arch/mips/ld.script.in 2005-07-02 13:00:22.000000000 +0200
++++ linux-2.4.30.openwrt/arch/mips/ld.script.in 2005-07-02 13:00:42.000000000 +0200
+@@ -9,6 +9,7 @@
+ {
+ _ftext = . ;
+ *(.text)
++ *(.fixup)
+ *(.rodata)
+ *(.rodata.*)
+ *(.rodata1)
+diff -Nur linux-2.4.30/arch/mips64/kernel/signal.c linux-2.4.30.openwrt/arch/mips64/kernel/signal.c
+--- linux-2.4.30/arch/mips64/kernel/signal.c 2005-07-02 13:00:13.000000000 +0200
++++ linux-2.4.30.openwrt/arch/mips64/kernel/signal.c 2005-07-02 13:00:49.000000000 +0200
+@@ -6,8 +6,10 @@
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1994 - 2000 Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
++ * Copyright (C) 2004 Maciej W. Rozycki
+ */
+ #include <linux/config.h>
++#include <linux/compiler.h>
+ #include <linux/sched.h>
+ #include <linux/mm.h>
+ #include <linux/smp.h>
+@@ -75,7 +77,9 @@
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+ save_static_function(sys_rt_sigsuspend);
+-static_unused int _sys_rt_sigsuspend(abi64_no_regargs, struct pt_regs regs)
++static int _sys_rt_sigsuspend(abi64_no_regargs, struct pt_regs regs)
++ __asm__("_sys_rt_sigsuspend") __attribute_used__;
++static int _sys_rt_sigsuspend(abi64_no_regargs, struct pt_regs regs)
+ {
+ sigset_t *unewset, saveset, newset;
+ size_t sigsetsize;
+diff -Nur linux-2.4.30/arch/mips64/kernel/signal32.c linux-2.4.30.openwrt/arch/mips64/kernel/signal32.c
+--- linux-2.4.30/arch/mips64/kernel/signal32.c 2005-07-02 13:00:13.000000000 +0200
++++ linux-2.4.30.openwrt/arch/mips64/kernel/signal32.c 2005-07-02 13:00:49.000000000 +0200
+@@ -6,7 +6,9 @@
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1994 - 2000 Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
++ * Copyright (C) 2004 Maciej W. Rozycki
+ */
++#include <linux/compiler.h>
+ #include <linux/sched.h>
+ #include <linux/mm.h>
+ #include <linux/smp.h>
+@@ -192,7 +194,9 @@
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+ save_static_function(sys32_sigsuspend);
+-static_unused int _sys32_sigsuspend(abi64_no_regargs, struct pt_regs regs)
++static int _sys32_sigsuspend(abi64_no_regargs, struct pt_regs regs)
++ __asm__("_sys32_sigsuspend") __attribute_used__;
++static int _sys32_sigsuspend(abi64_no_regargs, struct pt_regs regs)
+ {
+ sigset32_t *uset;
+ sigset_t newset, saveset;
+@@ -219,7 +223,9 @@
+ }
+
+ save_static_function(sys32_rt_sigsuspend);
+-static_unused int _sys32_rt_sigsuspend(abi64_no_regargs, struct pt_regs regs)
++static int _sys32_rt_sigsuspend(abi64_no_regargs, struct pt_regs regs)
++ __asm__("_sys32_rt_sigsuspend") __attribute_used__;
++static int _sys32_rt_sigsuspend(abi64_no_regargs, struct pt_regs regs)
+ {
+ sigset32_t *uset;
+ sigset_t newset, saveset;
+diff -Nur linux-2.4.30/arch/mips64/kernel/syscall.c linux-2.4.30.openwrt/arch/mips64/kernel/syscall.c
+--- linux-2.4.30/arch/mips64/kernel/syscall.c 2005-07-02 13:00:13.000000000 +0200
++++ linux-2.4.30.openwrt/arch/mips64/kernel/syscall.c 2005-07-02 13:00:49.000000000 +0200
+@@ -6,7 +6,9 @@
+ * Copyright (C) 1995 - 2000, 2001 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2001 MIPS Technologies, Inc.
++ * Copyright (C) 2004 Maciej W. Rozycki
+ */
++#include <linux/compiler.h>
+ #include <linux/errno.h>
+ #include <linux/linkage.h>
+ #include <linux/mm.h>
+@@ -151,7 +153,9 @@
+ }
+
+ save_static_function(sys_fork);
+-static_unused int _sys_fork(abi64_no_regargs, struct pt_regs regs)
++static int _sys_fork(abi64_no_regargs, struct pt_regs regs)
++ __asm__("_sys_fork") __attribute_used__;
++static int _sys_fork(abi64_no_regargs, struct pt_regs regs)
+ {
+ int res;
+
+@@ -160,7 +164,9 @@
+ }
+
+ save_static_function(sys_clone);
+-static_unused int _sys_clone(abi64_no_regargs, struct pt_regs regs)
++static int _sys_clone(abi64_no_regargs, struct pt_regs regs)
++ __asm__("_sys_clone") __attribute_used__;
++static int _sys_clone(abi64_no_regargs, struct pt_regs regs)
+ {
+ unsigned long clone_flags;
+ unsigned long newsp;
+diff -Nur linux-2.4.30/include/asm-mips/ptrace.h linux-2.4.30.openwrt/include/asm-mips/ptrace.h
+--- linux-2.4.30/include/asm-mips/ptrace.h 2005-07-02 13:00:13.000000000 +0200
++++ linux-2.4.30.openwrt/include/asm-mips/ptrace.h 2005-07-02 13:00:49.000000000 +0200
+@@ -4,6 +4,7 @@
+ * for more details.
+ *
+ * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000 by Ralf Baechle
++ * Copyright (C) 2004 Maciej W. Rozycki
+ *
+ * Machine dependent structs and defines to help the user use
+ * the ptrace system call.
+@@ -64,12 +65,10 @@
+ "sw\t$22,"__str(PT_R22)"($29)\n\t" \
+ "sw\t$23,"__str(PT_R23)"($29)\n\t" \
+ "sw\t$30,"__str(PT_R30)"($29)\n\t" \
++ "j\t_" #symbol "\n\t" \
+ ".end\t" #symbol "\n\t" \
+ ".size\t" #symbol",. - " #symbol)
+
+-/* Used in declaration of save_static functions. */
+-#define static_unused static __attribute__((unused))
+-
+ #endif /* !__ASSEMBLY__ */
+
+ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+diff -Nur linux-2.4.30/include/asm-mips64/ptrace.h linux-2.4.30.openwrt/include/asm-mips64/ptrace.h
+--- linux-2.4.30/include/asm-mips64/ptrace.h 2005-07-02 13:00:13.000000000 +0200
++++ linux-2.4.30.openwrt/include/asm-mips64/ptrace.h 2005-07-02 13:00:49.000000000 +0200
+@@ -5,6 +5,7 @@
+ *
+ * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
++ * Copyright (C) 2004 Maciej W. Rozycki
+ */
+ #ifndef _ASM_PTRACE_H
+ #define _ASM_PTRACE_H
+@@ -61,12 +62,10 @@
+ "sd\t$22,"__str(PT_R22)"($29)\n\t" \
+ "sd\t$23,"__str(PT_R23)"($29)\n\t" \
+ "sd\t$30,"__str(PT_R30)"($29)\n\t" \
++ "j\t_" #symbol "\n\t" \
+ ".end\t" #symbol "\n\t" \
+ ".size\t" #symbol",. - " #symbol)
+
+-/* Used in declaration of save_static functions. */
+-#define static_unused static __attribute__((unused))
+-
+ #define abi64_no_regargs \
+ unsigned long __dummy0, \
+ unsigned long __dummy1, \
diff --git a/target/linux/generic-2.4/patches/208-usb2_fix.patch b/target/linux/generic-2.4/patches/208-usb2_fix.patch
new file mode 100644
index 0000000..f8e5be1
--- /dev/null
+++ b/target/linux/generic-2.4/patches/208-usb2_fix.patch
@@ -0,0 +1,15 @@
+diff -ur linux-2.4.30.dev/drivers/usb/host/ehci-q.c linux-tmp/drivers/usb/host/ehci-q.c
+--- linux-2.4.30.dev/drivers/usb/host/ehci-q.c 2005-01-19 15:10:07.000000000 +0100
++++ linux-tmp/drivers/usb/host/ehci-q.c 2005-03-30 05:11:12.000000000 +0200
+@@ -783,6 +765,11 @@
+ if (!(cmd & CMD_ASE)) {
+ /* in case a clear of CMD_ASE didn't take yet */
+ (void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
++
++ /* force async head to be valid */
++ writel ((u32)ehci->async->qh_dma,
++ &ehci->regs->async_next);
++
+ cmd |= CMD_ASE | CMD_RUN;
+ writel (cmd, &ehci->regs->command);
+ ehci->hcd.state = USB_STATE_RUNNING;
diff --git a/target/linux/generic-2.4/patches/209-build_fixes.patch b/target/linux/generic-2.4/patches/209-build_fixes.patch
new file mode 100644
index 0000000..235ee04
--- /dev/null
+++ b/target/linux/generic-2.4/patches/209-build_fixes.patch
@@ -0,0 +1,48 @@
+diff -urN linux.old/Makefile linux.dev/Makefile
+--- linux.old/Makefile 2005-08-26 13:41:41.689634168 +0200
++++ linux.dev/Makefile 2005-08-26 13:44:34.233403528 +0200
+@@ -354,7 +354,7 @@
+ @rm -f .ver1
+
+ include/linux/version.h: ./Makefile
+- @expr length "$(KERNELRELEASE)" \<= $(uts_len) > /dev/null || \
++ @-expr length "$(KERNELRELEASE)" \<= $(uts_len) > /dev/null || \
+ (echo KERNELRELEASE \"$(KERNELRELEASE)\" exceeds $(uts_len) characters >&2; false)
+ @echo \#define UTS_RELEASE \"$(KERNELRELEASE)\" > .ver
+ @echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver
+@@ -509,7 +509,7 @@
+ ifdef CONFIG_MODVERSIONS
+ $(MAKE) update-modverfile
+ endif
+- scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
++ find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print | xargs scripts/mkdep -- > .hdepend
+ scripts/mkdep -- init/*.c > .depend
+
+ ifdef CONFIG_MODVERSIONS
+--- linux.old/Rules.make 2005-08-31 00:37:34.363109288 +0200
++++ linux.dev/Rules.make 2005-08-31 13:59:20.140676296 +0200
+@@ -126,7 +126,7 @@
+ # This make dependencies quickly
+ #
+ fastdep: dummy
+- $(TOPDIR)/scripts/mkdep $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -- $(wildcard *.[chS]) > .depend
++ find -name '*.[chS]' | xargs $(TOPDIR)/scripts/mkdep $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -- > .depend
+ ifdef ALL_SUB_DIRS
+ $(MAKE) $(patsubst %,_sfdep_%,$(ALL_SUB_DIRS)) _FASTDEP_ALL_SUB_DIRS="$(ALL_SUB_DIRS)"
+ endif
+@@ -176,7 +176,14 @@
+ _modinst__: dummy
+ ifneq "$(strip $(ALL_MOBJS))" ""
+ mkdir -p $(MODLIB)/kernel/$(MOD_DESTDIR)
+- cp $(sort $(ALL_MOBJS)) $(MODLIB)/kernel/$(MOD_DESTDIR)
++ #@cp $(sort $(ALL_MOBJS)) $(MODLIB)/kernel/$(MOD_DESTDIR)
++ for f in $(ALL_MOBJS) ; do \
++ $(OBJCOPY) -R __ksymtab -R .comment -R .note -x \
++ `$(NM) $$f | cut -f3- -d' ' | sed -n \
++ -e 's/__module_parm_\(.*\)/-K \1/p' \
++ -e 's/__ks..tab_\(.*\)/-K \1/p'` \
++ $$f $(MODLIB)/kernel/$(MOD_DESTDIR)$(MOD_TARGET)`basename $$f`; \
++ done
+ endif
+
+ .PHONY: modules_install
diff --git a/target/linux/generic-2.4/patches/210-fix-irq-serial.patch b/target/linux/generic-2.4/patches/210-fix-irq-serial.patch
new file mode 100644
index 0000000..630dc04
--- /dev/null
+++ b/target/linux/generic-2.4/patches/210-fix-irq-serial.patch
@@ -0,0 +1,21 @@
+--- linux-2.4.30/drivers/char/serial.c 2005-06-29 20:44:46.000000000 +0200
++++ linux-2.4.30.serial/drivers/char/serial.c 2005-06-29 21:15:12.000000000 +0200
+@@ -5455,18 +5455,6 @@
+ sizeof(struct rs_multiport_struct));
+ #endif
+ }
+-#ifdef CONFIG_SERIAL_CONSOLE
+- /*
+- * The interrupt of the serial console port
+- * can't be shared.
+- */
+- if (sercons.flags & CON_CONSDEV) {
+- for(i = 0; i < NR_PORTS; i++)
+- if (i != sercons.index &&
+- rs_table[i].irq == rs_table[sercons.index].irq)
+- rs_table[i].irq = 0;
+- }
+-#endif
+ show_serial_version();
+
+ /* Initialize the tty_driver structure */
diff --git a/target/linux/generic-2.4/patches/212-htb_time_fix.patch b/target/linux/generic-2.4/patches/212-htb_time_fix.patch
new file mode 100644
index 0000000..7281093
--- /dev/null
+++ b/target/linux/generic-2.4/patches/212-htb_time_fix.patch
@@ -0,0 +1,75 @@
+--- linux.old/net/sched/sch_htb.c 2005-11-15 14:09:41.548066000 +0100
++++ linux.dev/net/sched/sch_htb.c 2005-11-15 14:08:34.000000000 +0100
+@@ -369,7 +369,7 @@
+ struct list_head *l;
+ list_for_each (l,q->hash+i) {
+ struct htb_class *cl = list_entry(l,struct htb_class,hlist);
+- long diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer, 0);
++ long long diff = PSCHED_TDIFF_SAFE(q->now, cl->t_c, (u32)cl->mbuffer, 0);
+ printk(KERN_DEBUG "htb*c%x m=%d t=%ld c=%ld pq=%lu df=%ld ql=%d "
+ "pa=%x f:",
+ cl->classid,cl->cmode,cl->tokens,cl->ctokens,
+@@ -617,7 +617,7 @@
+ * mode transitions per time unit. The speed gain is about 1/6.
+ */
+ static __inline__ enum htb_cmode
+-htb_class_mode(struct htb_class *cl,long *diff)
++htb_class_mode(struct htb_class *cl,long long *diff)
+ {
+ long toks;
+
+@@ -650,7 +650,7 @@
+ * to mode other than HTB_CAN_SEND (see htb_add_to_wait_tree).
+ */
+ static void
+-htb_change_class_mode(struct htb_sched *q, struct htb_class *cl, long *diff)
++htb_change_class_mode(struct htb_sched *q, struct htb_class *cl, long long *diff)
+ {
+ enum htb_cmode new_mode = htb_class_mode(cl,diff);
+
+@@ -815,7 +815,8 @@
+ static void htb_charge_class(struct htb_sched *q,struct htb_class *cl,
+ int level,int bytes)
+ {
+- long toks,diff;
++ long long diff;
++ long toks;
+ enum htb_cmode old_mode;
+ HTB_DBG(5,1,"htb_chrg_cl cl=%X lev=%d len=%d\n",cl->classid,level,bytes);
+
+@@ -831,7 +832,7 @@
+ #ifdef HTB_DEBUG
+ if (diff > cl->mbuffer || diff < 0 || PSCHED_TLESS(q->now, cl->t_c)) {
+ if (net_ratelimit())
+- printk(KERN_ERR "HTB: bad diff in charge, cl=%X diff=%lX now=%Lu then=%Lu j=%lu\n",
++ printk(KERN_ERR "HTB: bad diff in charge, cl=%X diff=%Ld now=%Lu then=%Lu j=%lu\n",
+ cl->classid, diff,
+ (unsigned long long) q->now,
+ (unsigned long long) cl->t_c,
+@@ -848,7 +849,7 @@
+ }
+ HTB_ACCNT (ctokens,cbuffer,ceil);
+ cl->t_c = q->now;
+- HTB_DBG(5,2,"htb_chrg_clp cl=%X diff=%ld tok=%ld ctok=%ld\n",cl->classid,diff,cl->tokens,cl->ctokens);
++ HTB_DBG(5,2,"htb_chrg_clp cl=%X diff=%Ld tok=%ld ctok=%ld\n",cl->classid,diff,cl->tokens,cl->ctokens);
+
+ old_mode = cl->cmode; diff = 0;
+ htb_change_class_mode(q,cl,&diff);
+@@ -887,7 +888,7 @@
+ level,q->wait_pq[level].rb_node,q->row_mask[level]);
+ for (i = 0; i < 500; i++) {
+ struct htb_class *cl;
+- long diff;
++ long long diff;
+ rb_node_t *p = q->wait_pq[level].rb_node;
+ if (!p) return 0;
+ while (p->rb_left) p = p->rb_left;
+@@ -902,7 +903,7 @@
+ #ifdef HTB_DEBUG
+ if (diff > cl->mbuffer || diff < 0 || PSCHED_TLESS(q->now, cl->t_c)) {
+ if (net_ratelimit())
+- printk(KERN_ERR "HTB: bad diff in events, cl=%X diff=%lX now=%Lu then=%Lu j=%lu\n",
++ printk(KERN_ERR "HTB: bad diff in events, cl=%X diff=%Ld now=%Lu then=%Lu j=%lu\n",
+ cl->classid, diff,
+ (unsigned long long) q->now,
+ (unsigned long long) cl->t_c,
diff --git a/target/linux/generic-2.4/patches/213-htb_disable_hysteresis.patch b/target/linux/generic-2.4/patches/213-htb_disable_hysteresis.patch
new file mode 100644
index 0000000..5d0ff92
--- /dev/null
+++ b/target/linux/generic-2.4/patches/213-htb_disable_hysteresis.patch
@@ -0,0 +1,11 @@
+--- linux.old/net/sched/sch_htb.c 2005-11-15 14:09:41.548066000 +0100
++++ linux.dev/net/sched/sch_htb.c 2005-11-15 14:08:34.000000000 +0100
+@@ -74,7 +74,7 @@
+ #define HTB_EWMAC 2 /* rate average over HTB_EWMAC*HTB_HSIZE sec */
+ #define HTB_DEBUG 1 /* compile debugging support (activated by tc tool) */
+ #define HTB_RATECM 1 /* whether to use rate computer */
+-#define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */
++#define HTB_HYSTERESIS 0/* whether to use mode hysteresis for speedup */
+ #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock)
+ #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock)
+ #define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */
diff --git a/target/linux/generic-2.4/patches/222-sound.patch b/target/linux/generic-2.4/patches/222-sound.patch
new file mode 100644
index 0000000..351e8c2
--- /dev/null
+++ b/target/linux/generic-2.4/patches/222-sound.patch
@@ -0,0 +1,27 @@
+diff -rNu linux-2.4.30/drivers/sound/sound_core.c linux-2.4.30.new/drivers/sound/sound_core.c
+--- linux-2.4.30/drivers/sound/sound_core.c 2001-10-01 05:26:08.000000000 +1000
++++ linux-2.4.30.new/drivers/sound/sound_core.c 2005-08-27 22:52:55.061719968 +1000
+@@ -174,9 +174,9 @@
+ }
+
+ if (r == low)
+- sprintf (name_buf, "%s", name);
++ snprintf (name_buf, sizeof(name_buf), "%s", name);
+ else
+- sprintf (name_buf, "%s%d", name, (r - low) / SOUND_STEP);
++ snprintf (name_buf, sizeof(name_buf), "%s%d", name, (r - low) / SOUND_STEP);
+ s->de = devfs_register (devfs_handle, name_buf,
+ DEVFS_FL_NONE, SOUND_MAJOR, s->unit_minor,
+ S_IFCHR | mode, fops, NULL);
+@@ -507,9 +507,9 @@
+ * ALSA toplevel modules for soundcards, thus we need
+ * load them at first. [Jaroslav Kysela <perex@jcu.cz>]
+ */
+- sprintf(mod, "sound-slot-%i", unit>>4);
++ snprintf(mod, sizeof(mod), "sound-slot-%i", unit>>4);
+ request_module(mod);
+- sprintf(mod, "sound-service-%i-%i", unit>>4, chain);
++ snprintf(mod, sizeof(mod), "sound-service-%i-%i", unit>>4, chain);
+ request_module(mod);
+ spin_lock(&sound_loader_lock);
+ s = __look_for_unit(chain, unit);
diff --git a/target/linux/generic-2.4/patches/224-atm_hotplug.patch b/target/linux/generic-2.4/patches/224-atm_hotplug.patch
new file mode 100644
index 0000000..c431d8c
--- /dev/null
+++ b/target/linux/generic-2.4/patches/224-atm_hotplug.patch
@@ -0,0 +1,98 @@
+diff -urN linux.old/include/linux/atmdev.h linux.dev/include/linux/atmdev.h
+--- linux.old/include/linux/atmdev.h 2005-11-17 12:51:55.883585000 +0100
++++ linux.dev/include/linux/atmdev.h 2005-11-17 13:49:22.012671000 +0100
+@@ -408,6 +408,7 @@
+ struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
+ int number,atm_dev_flags_t *flags); /* number == -1: pick first available */
+ struct atm_dev *atm_dev_lookup(int number);
++void atm_dev_set_link_status(struct atm_dev *dev, int status);
+ void atm_dev_deregister(struct atm_dev *dev);
+ void shutdown_atm_dev(struct atm_dev *dev);
+ void vcc_insert_socket(struct sock *sk);
+diff -urN linux.old/net/atm/resources.c linux.dev/net/atm/resources.c
+--- linux.old/net/atm/resources.c 2003-11-28 19:26:21.000000000 +0100
++++ linux.dev/net/atm/resources.c 2005-11-17 14:27:26.514267750 +0100
+@@ -10,6 +10,7 @@
+ #include <linux/sonet.h>
+ #include <linux/kernel.h> /* for barrier */
+ #include <linux/module.h>
++#include <linux/kmod.h>
+ #include <linux/bitops.h>
+ #include <net/sock.h> /* for struct sock */
+ #include <asm/segment.h> /* for get_fs_long and put_fs_long */
+@@ -70,6 +71,44 @@
+ return dev;
+ }
+
++#ifdef CONFIG_HOTPLUG
++static void atm_run_sbin_hotplug(struct atm_dev *dev, char *action)
++{
++ char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], atmname[255], action_str[32];
++ int i;
++
++ sprintf(ifname, "INTERFACE=atm%d", dev->number);
++ sprintf(atmname, "ATMDRIVER=%s", dev->type);
++ sprintf(action_str, "ACTION=%s", action);
++
++ i = 0;
++ argv[i++] = hotplug_path;
++ argv[i++] = "net";
++ argv[i] = 0;
++
++ i = 0;
++ /* minimal command environment */
++ envp [i++] = "HOME=/";
++ envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
++ envp [i++] = ifname;
++ envp [i++] = atmname;
++ envp [i++] = action_str;
++ envp [i] = 0;
++
++ return call_usermodehelper(argv [0], argv, envp);
++}
++#endif
++
++void atm_dev_set_link_status(struct atm_dev *dev, int status)
++{
++#ifdef CONFIG_HOTPLUG
++ if (status)
++ atm_run_sbin_hotplug(dev, "up");
++ else
++ atm_run_sbin_hotplug(dev, "down");
++#endif
++}
++
+ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
+ int number, atm_dev_flags_t *flags)
+ {
+@@ -123,7 +162,10 @@
+ }
+ }
+ #endif
+-
++#ifdef CONFIG_HOTPLUG
++ atm_run_sbin_hotplug(dev, "register");
++#endif
++
+ return dev;
+ }
+
+@@ -131,6 +173,10 @@
+ void atm_dev_deregister(struct atm_dev *dev)
+ {
+ unsigned long warning_time;
++
++#ifdef CONFIG_HOTPLUG
++ atm_run_sbin_hotplug(dev, "unregister");
++#endif
+
+ #ifdef CONFIG_PROC_FS
+ if (dev->ops->proc_read)
+@@ -399,6 +445,7 @@
+ }
+
+
++EXPORT_SYMBOL(atm_dev_set_link_status);
+ EXPORT_SYMBOL(atm_dev_register);
+ EXPORT_SYMBOL(atm_dev_deregister);
+ EXPORT_SYMBOL(atm_dev_lookup);
diff --git a/target/linux/generic-2.4/patches/225-string_lib_useful_exports.patch b/target/linux/generic-2.4/patches/225-string_lib_useful_exports.patch
new file mode 100644
index 0000000..b89f765
--- /dev/null
+++ b/target/linux/generic-2.4/patches/225-string_lib_useful_exports.patch
@@ -0,0 +1,170 @@
+diff -ruN linux-2.4.32-old/lib/string.c linux-2.4.32-new/lib/string.c
+--- linux-2.4.32-old/lib/string.c 2004-11-17 12:54:22.000000000 +0100
++++ linux-2.4.32-new/lib/string.c 2006-01-17 14:41:17.000000000 +0100
+@@ -50,6 +50,7 @@
+ }
+ return (int)c1 - (int)c2;
+ }
++EXPORT_SYMBOL(strnicmp);
+ #endif
+
+ char * ___strtok;
+@@ -68,6 +69,7 @@
+ /* nothing */;
+ return tmp;
+ }
++EXPORT_SYMBOL(strcpy);
+ #endif
+
+ #ifndef __HAVE_ARCH_STRNCPY
+@@ -90,6 +92,7 @@
+
+ return tmp;
+ }
++EXPORT_SYMBOL(strncpy);
+ #endif
+
+ #ifndef __HAVE_ARCH_STRCAT
+@@ -109,6 +112,7 @@
+
+ return tmp;
+ }
++EXPORT_SYMBOL(strcat);
+ #endif
+
+ #ifndef __HAVE_ARCH_STRNCAT
+@@ -138,6 +142,7 @@
+
+ return tmp;
+ }
++EXPORT_SYMBOL(strncat);
+ #endif
+
+ #ifndef __HAVE_ARCH_STRCMP
+@@ -157,6 +162,7 @@
+
+ return __res;
+ }
++EXPORT_SYMBOL(strcmp);
+ #endif
+
+ #ifndef __HAVE_ARCH_STRNCMP
+@@ -178,6 +184,7 @@
+
+ return __res;
+ }
++EXPORT_SYMBOL(strncmp);
+ #endif
+
+ #ifndef __HAVE_ARCH_STRCHR
+@@ -193,6 +200,7 @@
+ return NULL;
+ return (char *) s;
+ }
++EXPORT_SYMBOL(strchr);
+ #endif
+
+ #ifndef __HAVE_ARCH_STRRCHR
+@@ -210,6 +218,7 @@
+ } while (--p >= s);
+ return NULL;
+ }
++EXPORT_SYMBOL(strrchr);
+ #endif
+
+ #ifndef __HAVE_ARCH_STRLEN
+@@ -225,6 +234,7 @@
+ /* nothing */;
+ return sc - s;
+ }
++EXPORT_SYMBOL(strlen);
+ #endif
+
+ #ifndef __HAVE_ARCH_STRNLEN
+@@ -241,6 +251,7 @@
+ /* nothing */;
+ return sc - s;
+ }
++EXPORT_SYMBOL(strnlen);
+ #endif
+
+ #ifndef __HAVE_ARCH_STRSPN
+@@ -268,6 +279,7 @@
+
+ return count;
+ }
++EXPORT_SYMBOL(strspn);
+ #endif
+
+ #ifndef __HAVE_ARCH_STRPBRK
+@@ -288,6 +300,7 @@
+ }
+ return NULL;
+ }
++EXPORT_SYMBOL(strpbrk);
+ #endif
+
+ #ifndef __HAVE_ARCH_STRTOK
+@@ -345,6 +358,7 @@
+
+ return sbegin;
+ }
++EXPORT_SYMBOL(strsep);
+ #endif
+
+ #ifndef __HAVE_ARCH_MEMSET
+@@ -365,6 +379,7 @@
+
+ return s;
+ }
++EXPORT_SYMBOL(memset);
+ #endif
+
+ #ifndef __HAVE_ARCH_BCOPY
+@@ -409,6 +424,7 @@
+
+ return dest;
+ }
++EXPORT_SYMBOL(memcpy);
+ #endif
+
+ #ifndef __HAVE_ARCH_MEMMOVE
+@@ -439,6 +455,7 @@
+
+ return dest;
+ }
++EXPORT_SYMBOL(memmove);
+ #endif
+
+ #ifndef __HAVE_ARCH_MEMCMP
+@@ -458,6 +475,7 @@
+ break;
+ return res;
+ }
++EXPORT_SYMBOL(memcmp);
+ #endif
+
+ #ifndef __HAVE_ARCH_MEMSCAN
+@@ -482,6 +500,7 @@
+ }
+ return (void *) p;
+ }
++EXPORT_SYMBOL(memscan);
+ #endif
+
+ #ifndef __HAVE_ARCH_STRSTR
+@@ -506,6 +525,7 @@
+ }
+ return NULL;
+ }
++EXPORT_SYMBOL(strstr);
+ #endif
+
+ #ifndef __HAVE_ARCH_MEMCHR
+@@ -528,5 +548,5 @@
+ }
+ return NULL;
+ }
+-
++EXPORT_SYMBOL(memchr);
+ #endif
diff --git a/target/linux/generic-2.4/patches/226-atm_br2684.patch b/target/linux/generic-2.4/patches/226-atm_br2684.patch
new file mode 100644
index 0000000..56f0015
--- /dev/null
+++ b/target/linux/generic-2.4/patches/226-atm_br2684.patch
@@ -0,0 +1,578 @@
+diff -urN linux-2.4.32/net/atm/br2684.c linux-2.4.32.new/net/atm/br2684.c
+--- linux-2.4.32/net/atm/br2684.c 2004-08-08 01:26:06.000000000 +0200
++++ linux-2.4.32.new/net/atm/br2684.c 2006-02-06 18:59:40.000000000 +0100
+@@ -55,36 +55,55 @@
+ #define skb_debug(skb) do {} while (0)
+ #endif
+
++#define BR2684_LLC_LEN 3
++#define BR2684_SNAP_LEN 3
++#define BR2684_ETHERTYPE_LEN 2
++#define BR2684_PID_LEN 2
++#define BR2684_PAD_LEN 2
++
++static unsigned char llc_common[] = { 0xaa, 0xaa, 0x03 };
++static unsigned char snap_bridged[] = { 0x00, 0x80, 0xc2 };
++static unsigned char snap_routed[] = { 0x00, 0x00, 0x00 };
++static unsigned char pid_ipv4[] = { 0x00, 0x07 };
++static unsigned char ethertype_ipv4[] = { 0x08, 0x00 };
++static unsigned char ethertype_ipv6[] = { 0x86, 0xdd };
++static unsigned char pad_bridged[] = { 0x00, 0x00 };
++
+ static unsigned char llc_oui_pid_pad[] =
+ { 0xAA, 0xAA, 0x03, 0x00, 0x80, 0xC2, 0x00, 0x07, 0x00, 0x00 };
++static unsigned char llc_oui_ipv6[] =
++ { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x86, 0xdd };
++static unsigned char llc_oui_ipv4[] =
++ { 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00 };
+ #define PADLEN (2)
+
+ enum br2684_encaps {
+- e_vc = BR2684_ENCAPS_VC,
++ e_vc = BR2684_ENCAPS_VC,
+ e_llc = BR2684_ENCAPS_LLC,
+ };
+
+ struct br2684_vcc {
+- struct atm_vcc *atmvcc;
++ struct atm_vcc *atmvcc;
+ struct br2684_dev *brdev;
+ /* keep old push,pop functions for chaining */
+- void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb);
++ void (*old_push) (struct atm_vcc * vcc, struct sk_buff * skb);
+ /* void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); */
+ enum br2684_encaps encaps;
++ enum br2684_payload payload;
+ struct list_head brvccs;
+ #ifdef CONFIG_ATM_BR2684_IPFILTER
+ struct br2684_filter filter;
+-#endif /* CONFIG_ATM_BR2684_IPFILTER */
++#endif /* CONFIG_ATM_BR2684_IPFILTER */
+ #ifndef FASTER_VERSION
+ unsigned copies_needed, copies_failed;
+-#endif /* FASTER_VERSION */
++#endif /* FASTER_VERSION */
+ };
+
+ struct br2684_dev {
+ struct net_device net_dev;
+ struct list_head br2684_devs;
+ int number;
+- struct list_head brvccs; /* one device <=> one vcc (before xmas) */
++ struct list_head brvccs; /* one device <=> one vcc (before xmas) */
+ struct net_device_stats stats;
+ int mac_was_set;
+ };
+@@ -173,24 +192,84 @@
+ }
+ skb = skb2;
+ }
+- skb_push(skb, minheadroom);
+- if (brvcc->encaps == e_llc)
+- memcpy(skb->data, llc_oui_pid_pad, 10);
+- else
+- memset(skb->data, 0, 2);
+-#endif /* FASTER_VERSION */
++
++ /* This skb_push is a problem: routed packets need less headroom than
++ * bridged packets.
++ */
++
++/* skb_push(skb, minheadroom); */
++ if (brvcc->encaps == e_llc) {
++ int offset = 0;
++ int actual_headroom;
++
++ actual_headroom =
++ BR2684_LLC_LEN +
++ BR2684_SNAP_LEN +
++ ((brvcc->payload == p_bridged) ?
++ (BR2684_PID_LEN + BR2684_PAD_LEN) :
++ BR2684_ETHERTYPE_LEN);
++
++ skb_push(skb, actual_headroom);
++ memcpy(skb->data, llc_common, BR2684_LLC_LEN);
++ offset += BR2684_LLC_LEN;
++
++ if (brvcc->payload == p_bridged) {
++ memcpy(skb->data + offset, snap_bridged,
++ BR2684_SNAP_LEN);
++ offset += BR2684_SNAP_LEN;
++ /* pid_ipv4 is poorly named. should probably be
++ * pid_ethernet
++ */
++ memcpy(skb->data + offset, pid_ipv4,
++ BR2684_PID_LEN);
++ offset += BR2684_PID_LEN;
++ memcpy(skb->data + offset, pad_bridged,
++ BR2684_PAD_LEN);
++ offset += BR2684_PAD_LEN;
++ } else if (brvcc->payload == p_routed) {
++ unsigned short prot =
++ __constant_ntohs(skb->protocol);
++ memcpy(skb->data + offset, snap_routed,
++ BR2684_SNAP_LEN);
++ offset += BR2684_SNAP_LEN;
++
++ switch (prot) {
++ case ETH_P_IP:
++ memcpy(skb->data + offset,
++ ethertype_ipv4,
++ BR2684_ETHERTYPE_LEN);
++ break;
++ case ETH_P_IPV6:
++ memcpy(skb->data + offset,
++ ethertype_ipv6,
++ BR2684_ETHERTYPE_LEN);
++ break;
++ default:
++ dev_kfree_skb(skb);
++ return 0;
++ }
++ offset += BR2684_ETHERTYPE_LEN;
++
++ }
++ } else {
++ skb_push(skb, 2);
++ if (brvcc->payload == p_bridged)
++ memset(skb->data, 0, 2);
++ }
++#endif /* FASTER_VERSION */
+ skb_debug(skb);
+
+ ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
+- DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev);
++ DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc,
++ atmvcc->dev);
+ if (!atm_may_send(atmvcc, skb->truesize)) {
+ /* we free this here for now, because we cannot know in a higher
+- layer whether the skb point it supplied wasn't freed yet.
+- now, it always is.
+- */
++ layer whether the skb point it supplied wasn't freed yet.
++ now, it always is.
++ */
+ dev_kfree_skb(skb);
+ return 0;
+- }
++ }
+ atomic_add(skb->truesize, &atmvcc->sk->wmem_alloc);
+ ATM_SKB(skb)->atm_options = atmvcc->atm_options;
+ brdev->stats.tx_packets++;
+@@ -428,18 +507,39 @@
+ atm_return(atmvcc, skb->truesize);
+ DPRINTK("skb from brdev %p\n", brdev);
+ if (brvcc->encaps == e_llc) {
++ /* accept packets that have "ipv[46]" in the snap header */
++ /* 8 - 2 == sizeof(llc_oui_ipv6) - BR2684_ETHERTYPE_LEN */
++ if (memcmp(skb->data, llc_oui_ipv6, 8 - 2) == 0) {
++ plen = sizeof(llc_oui_ipv6);
++
++ if (memcmp(skb->data + 6, ethertype_ipv6, 2) == 0)
++ skb->protocol =
++ __constant_htons(ETH_P_IPV6);
++ else if (memcmp(skb->data + 6, ethertype_ipv4, 2)
++ == 0)
++ skb->protocol = __constant_htons(ETH_P_IP);
++ else {
++ brdev->stats.rx_errors++;
++ dev_kfree_skb(skb);
++ return;
++ }
++ skb_pull(skb, plen);
++ skb->nh.raw = skb->data;
++ skb->pkt_type = PACKET_HOST;
++ }
++
+ /* let us waste some time for checking the encapsulation.
+ Note, that only 7 char is checked so frames with a valid FCS
+ are also accepted (but FCS is not checked of course) */
+- if (memcmp(skb->data, llc_oui_pid_pad, 7)) {
++ else if (memcmp(skb->data, llc_oui_pid_pad, 7) == 0) {
++ skb_pull(skb, plen - ETH_HLEN);
++ skb->protocol =
++ eth_type_trans(skb, &brdev->net_dev);
++ } else {
+ brdev->stats.rx_errors++;
+ dev_kfree_skb(skb);
+ return;
+ }
+-
+- /* Strip FCS if present */
+- if (skb->len > 7 && skb->data[7] == 0x01)
+- __skb_trim(skb, skb->len - 4);
+ } else {
+ plen = PADLEN + ETH_HLEN; /* pad, dstmac,srcmac, ethtype */
+ /* first 2 chars should be 0 */
+@@ -448,13 +548,14 @@
+ dev_kfree_skb(skb);
+ return;
+ }
++ skb_pull(skb, plen - ETH_HLEN);
++ skb->protocol = eth_type_trans(skb, &brdev->net_dev);
+ }
+ if (skb->len < plen) {
+ brdev->stats.rx_errors++;
+ dev_kfree_skb(skb); /* dev_ not needed? */
+ return;
+ }
+-
+ #ifdef FASTER_VERSION
+ /* FIXME: tcpdump shows that pointer to mac header is 2 bytes earlier,
+ than should be. What else should I set? */
+@@ -465,30 +566,29 @@
+ skb->protocol = ((u16 *) skb->data)[-1];
+ #else /* some protocols might require this: */
+ skb->protocol = br_type_trans(skb, &brdev->net_dev);
+-#endif /* CONFIG_BR2684_FAST_TRANS */
++#endif /* CONFIG_BR2684_FAST_TRANS */
+ #else
+- skb_pull(skb, plen - ETH_HLEN);
+- skb->protocol = eth_type_trans(skb, &brdev->net_dev);
+-#endif /* FASTER_VERSION */
++ /* skb_pull(skb, plen - ETH_HLEN); */
++ /* skb->protocol = eth_type_trans(skb, &brdev->net_dev); */
++#endif /* FASTER_VERSION */
+ #ifdef CONFIG_ATM_BR2684_IPFILTER
+ if (packet_fails_filter(skb->protocol, brvcc, skb)) {
+ brdev->stats.rx_dropped++;
+ dev_kfree_skb(skb);
+ return;
+ }
+-#endif /* CONFIG_ATM_BR2684_IPFILTER */
++#endif /* CONFIG_ATM_BR2684_IPFILTER */
+ skb->dev = &brdev->net_dev;
+- ATM_SKB(skb)->vcc = atmvcc; /* needed ? */
++ /* ATM_SKB(skb)->vcc = atmvcc; *//* needed ? */
+ DPRINTK("received packet's protocol: %x\n", ntohs(skb->protocol));
+ skb_debug(skb);
+- if (!(brdev->net_dev.flags & IFF_UP)) { /* sigh, interface is down */
++ if (!(brdev->net_dev.flags & IFF_UP)) { /* sigh, interface is down */
+ brdev->stats.rx_dropped++;
+ dev_kfree_skb(skb);
+ return;
+ }
+ brdev->stats.rx_packets++;
+ brdev->stats.rx_bytes += skb->len;
+- memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
+ netif_rx(skb);
+ }
+
+@@ -525,10 +625,10 @@
+ err = -EEXIST;
+ goto error;
+ }
+- if (be.fcs_in != BR2684_FCSIN_NO || be.fcs_out != BR2684_FCSOUT_NO ||
+- be.fcs_auto || be.has_vpiid || be.send_padding || (be.encaps !=
+- BR2684_ENCAPS_VC && be.encaps != BR2684_ENCAPS_LLC) ||
+- be.min_size != 0) {
++ if (be.fcs_in != BR2684_FCSIN_NO || be.fcs_out != BR2684_FCSOUT_NO
++ || be.fcs_auto || be.has_vpiid || be.send_padding
++ || (be.encaps != BR2684_ENCAPS_VC
++ && be.encaps != BR2684_ENCAPS_LLC) || be.min_size != 0) {
+ err = -EINVAL;
+ goto error;
+ }
+@@ -554,18 +654,21 @@
+ brvcc->atmvcc = atmvcc;
+ atmvcc->user_back = brvcc;
+ brvcc->encaps = (enum br2684_encaps) be.encaps;
++ brvcc->payload = (enum br2684_payload) be.payload;
+ brvcc->old_push = atmvcc->push;
+ barrier();
+ atmvcc->push = br2684_push;
+ skb_queue_head_init(&copy);
+ skb_migrate(&atmvcc->sk->receive_queue, &copy);
+ while ((skb = skb_dequeue(&copy))) {
++#ifdef notdef
+ BRPRIV(skb->dev)->stats.rx_bytes -= skb->len;
+ BRPRIV(skb->dev)->stats.rx_packets--;
++#endif
+ br2684_push(atmvcc, skb);
+ }
+ return 0;
+- error:
++ error:
+ write_unlock_irq(&devs_lock);
+ MOD_DEC_USE_COUNT;
+ return err;
+@@ -608,12 +711,25 @@
+
+ if (ni.ifname[0] != '\0') {
+ memcpy(brdev->net_dev.name, ni.ifname,
+- sizeof(brdev->net_dev.name));
+- brdev->net_dev.name[sizeof(brdev->net_dev.name) - 1] = '\0';
++ sizeof(brdev->net_dev.name));
++ brdev->net_dev.name[sizeof(brdev->net_dev.name) - 1] =
++ '\0';
+ } else
+ sprintf(brdev->net_dev.name, "nas%d", brdev->number);
+ DPRINTK("registered netdev %s\n", brdev->net_dev.name);
+- ether_setup(&brdev->net_dev);
++ if (ni.payload == p_routed) {
++ brdev->net_dev.hard_header_len = 0;
++ brdev->net_dev.addr_len = 0;
++ brdev->net_dev.mtu = 1500;
++
++ /* Type PPP seems most suitable */
++ brdev->net_dev.type = ARPHRD_PPP;
++ brdev->net_dev.flags =
++ IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
++ brdev->net_dev.tx_queue_len = 100;
++ } else {
++ ether_setup(&brdev->net_dev);
++ }
+ brdev->mac_was_set = 0;
+ #ifdef FASTER_VERSION
+ my_eth_header = brdev->net_dev.hard_header;
+@@ -677,12 +793,11 @@
+ err = br2684_setfilt(atmvcc, arg);
+ MOD_DEC_USE_COUNT;
+ return err;
+-#endif /* CONFIG_ATM_BR2684_IPFILTER */
++#endif /* CONFIG_ATM_BR2684_IPFILTER */
+ }
+ return -ENOIOCTLCMD;
+ }
+
+-#ifdef CONFIG_PROC_FS
+ /* Never put more than 256 bytes in at once */
+ static int br2684_proc_engine(loff_t pos, char *buf)
+ {
+@@ -692,52 +807,62 @@
+ list_for_each(lhd, &br2684_devs) {
+ brdev = list_entry_brdev(lhd);
+ if (pos-- == 0)
+- return sprintf(buf, "dev %.16s: num=%d, mac=%02X:%02X:"
+- "%02X:%02X:%02X:%02X (%s)\n", brdev->net_dev.name,
+- brdev->number,
+- brdev->net_dev.dev_addr[0],
+- brdev->net_dev.dev_addr[1],
+- brdev->net_dev.dev_addr[2],
+- brdev->net_dev.dev_addr[3],
+- brdev->net_dev.dev_addr[4],
+- brdev->net_dev.dev_addr[5],
+- brdev->mac_was_set ? "set" : "auto");
++ return sprintf(buf,
++ "dev %.16s: num=%d, mac=%02X:%02X:"
++ "%02X:%02X:%02X:%02X (%s)\n",
++ brdev->net_dev.name, brdev->number,
++ brdev->net_dev.dev_addr[0],
++ brdev->net_dev.dev_addr[1],
++ brdev->net_dev.dev_addr[2],
++ brdev->net_dev.dev_addr[3],
++ brdev->net_dev.dev_addr[4],
++ brdev->net_dev.dev_addr[5],
++ brdev->
++ mac_was_set ? "set" : "auto");
+ list_for_each(lhc, &brdev->brvccs) {
+ brvcc = list_entry_brvcc(lhc);
+ if (pos-- == 0)
+- return sprintf(buf, " vcc %d.%d.%d: encaps=%s"
++ return sprintf(buf,
++ " vcc %d.%d.%d: encaps=%s"
++ ", payload=%s"
+ #ifndef FASTER_VERSION
+- ", failed copies %u/%u"
+-#endif /* FASTER_VERSION */
+- "\n", brvcc->atmvcc->dev->number,
+- brvcc->atmvcc->vpi, brvcc->atmvcc->vci,
+- (brvcc->encaps == e_llc) ? "LLC" : "VC"
++ ", failed copies %u/%u"
++#endif /* FASTER_VERSION */
++ "\n",
++ brvcc->atmvcc->dev->number,
++ brvcc->atmvcc->vpi,
++ brvcc->atmvcc->vci,
++ (brvcc->encaps ==
++ e_llc) ? "LLC" : "VC",
++ (brvcc->payload ==
++ p_bridged) ? "bridged" :
++ "routed"
+ #ifndef FASTER_VERSION
+- , brvcc->copies_failed
+- , brvcc->copies_needed
+-#endif /* FASTER_VERSION */
++ , brvcc->copies_failed,
++ brvcc->copies_needed
++#endif /* FASTER_VERSION */
+ );
+ #ifdef CONFIG_ATM_BR2684_IPFILTER
+ #define b1(var, byte) ((u8 *) &brvcc->filter.var)[byte]
+ #define bs(var) b1(var, 0), b1(var, 1), b1(var, 2), b1(var, 3)
+ if (brvcc->filter.netmask != 0 && pos-- == 0)
+- return sprintf(buf, " filter=%d.%d.%d.%d/"
+- "%d.%d.%d.%d\n", bs(prefix), bs(netmask));
++ return sprintf(buf,
++ " filter=%d.%d.%d.%d/"
++ "%d.%d.%d.%d\n", bs(prefix),
++ bs(netmask));
+ #undef bs
+ #undef b1
+-#endif /* CONFIG_ATM_BR2684_IPFILTER */
++#endif /* CONFIG_ATM_BR2684_IPFILTER */
+ }
+ }
+ return 0;
+ }
+
+ static ssize_t br2684_proc_read(struct file *file, char *buf, size_t count,
+- loff_t *pos)
++ loff_t * pos)
+ {
+ unsigned long page;
+ int len = 0, x, left;
+- loff_t n = *pos;
+-
+ page = get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+@@ -746,7 +871,7 @@
+ left = count;
+ read_lock(&devs_lock);
+ for (;;) {
+- x = br2684_proc_engine(n, &((char *) page)[len]);
++ x = br2684_proc_engine(*pos, &((char *) page)[len]);
+ if (x == 0)
+ break;
+ if (x > left)
+@@ -761,12 +886,11 @@
+ }
+ len += x;
+ left -= x;
+- n++;
++ (*pos)++;
+ if (left < 256)
+ break;
+ }
+ read_unlock(&devs_lock);
+- *pos = n;
+ if (len > 0 && copy_to_user(buf, (char *) page, len))
+ len = -EFAULT;
+ free_page(page);
+@@ -774,23 +898,20 @@
+ }
+
+ static struct file_operations br2684_proc_operations = {
+- read: br2684_proc_read,
++ read:br2684_proc_read,
+ };
+
+ extern struct proc_dir_entry *atm_proc_root; /* from proc.c */
+-#endif /* CONFIG_PROC_FS */
+
+ /* the following avoids some spurious warnings from the compiler */
+ #define UNUSED __attribute__((unused))
+
+ static int __init UNUSED br2684_init(void)
+ {
+-#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *p;
+ if ((p = create_proc_entry("br2684", 0, atm_proc_root)) == NULL)
+ return -ENOMEM;
+ p->proc_fops = &br2684_proc_operations;
+-#endif /* CONFIG_PROC_FS */
+ br2684_ioctl_set(br2684_ioctl);
+ return 0;
+ }
+@@ -799,9 +920,7 @@
+ {
+ struct br2684_dev *brdev;
+ br2684_ioctl_set(NULL);
+-#ifdef CONFIG_PROC_FS
+ remove_proc_entry("br2684", atm_proc_root);
+-#endif /* CONFIG_PROC_FS */
+ while (!list_empty(&br2684_devs)) {
+ brdev = list_entry_brdev(br2684_devs.next);
+ unregister_netdev(&brdev->net_dev);
+diff -urN linux-2.4.32/net/atm/common.c linux-2.4.32.new/net/atm/common.c
+--- linux-2.4.32/net/atm/common.c 2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.32.new/net/atm/common.c 2006-02-06 17:26:52.000000000 +0100
+@@ -158,6 +158,7 @@
+ }
+ #ifdef CONFIG_ATM_BR2684_MODULE
+ EXPORT_SYMBOL(br2684_ioctl_set);
++EXPORT_SYMBOL(br2684_ioctl_hook);
+ #endif
+ #endif
+
+--- linux-2.4.32/include/linux/atmbr2684.h 2002-08-03 02:39:45.000000000 +0200
++++ linux-2.4.32.new/include/linux/atmbr2684.h 2006-02-06 19:01:24.000000000 +0100
+@@ -3,6 +3,7 @@
+
+ #include <linux/atm.h>
+ #include <linux/if.h> /* For IFNAMSIZ */
++#include <linux/if_ether.h> /* ETH_P_* */
+
+ /*
+ * Type of media we're bridging (ethernet, token ring, etc) Currently only
+@@ -36,15 +37,24 @@
+ #define BR2684_ENCAPS_AUTODETECT (2) /* Unsuported */
+
+ /*
++ * Is this VC bridged or routed?
++ */
++
++#define BR2684_PAYLOAD_ROUTED (0)
++#define BR2684_PAYLOAD_BRIDGED (1)
++
++
++/*
+ * This is for the ATM_NEWBACKENDIF call - these are like socket families:
+ * the first element of the structure is the backend number and the rest
+ * is per-backend specific
+ */
+ struct atm_newif_br2684 {
+- atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */
+- int media; /* BR2684_MEDIA_* */
+- char ifname[IFNAMSIZ];
+- int mtu;
++ atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */
++ int media; /* BR2684_MEDIA_* */
++ char ifname[IFNAMSIZ];
++ int mtu;
++ int payload; /* bridged or routed */
+ };
+
+ /*
+@@ -68,16 +78,17 @@
+ * is per-backend specific
+ */
+ struct atm_backend_br2684 {
+- atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */
++ atm_backend_t backend_num; /* ATM_BACKEND_BR2684 */
+ struct br2684_if_spec ifspec;
+- int fcs_in; /* BR2684_FCSIN_* */
+- int fcs_out; /* BR2684_FCSOUT_* */
+- int fcs_auto; /* 1: fcs_{in,out} disabled if no FCS rx'ed */
+- int encaps; /* BR2684_ENCAPS_* */
+- int has_vpiid; /* 1: use vpn_id - Unsupported */
+- __u8 vpn_id[7];
+- int send_padding; /* unsupported */
+- int min_size; /* we will pad smaller packets than this */
++ int fcs_in; /* BR2684_FCSIN_* */
++ int fcs_out; /* BR2684_FCSOUT_* */
++ int fcs_auto; /* 1: fcs_{in,out} disabled if no FCS rx'ed */
++ int encaps; /* BR2684_ENCAPS_* */
++ int payload; /* BR2684_PAYLOAD_* */
++ int has_vpiid; /* 1: use vpn_id - Unsupported */
++ __u8 vpn_id[7];
++ int send_padding; /* unsupported */
++ int min_size; /* we will pad smaller packets than this */
+ };
+
+ /*
+@@ -95,7 +106,12 @@
+ struct br2684_filter filter;
+ };
+
++enum br2684_payload {
++ p_routed = BR2684_PAYLOAD_ROUTED,
++ p_bridged = BR2684_PAYLOAD_BRIDGED,
++};
++
+ #define BR2684_SETFILT _IOW( 'a', ATMIOC_BACKEND + 0, \
+ struct br2684_filter_set)
+
+-#endif /* _LINUX_ATMBR2684_H */
++#endif /* _LINUX_ATMBR2684_H */
diff --git a/target/linux/generic-2.4/patches/227-jffs2_eofdetect.patch b/target/linux/generic-2.4/patches/227-jffs2_eofdetect.patch
new file mode 100644
index 0000000..fe97be5
--- /dev/null
+++ b/target/linux/generic-2.4/patches/227-jffs2_eofdetect.patch
@@ -0,0 +1,97 @@
+diff -ur linux.old/fs/jffs2/build.c linux.dev/fs/jffs2/build.c
+--- linux.old/fs/jffs2/build.c 2003-06-13 16:51:37.000000000 +0200
++++ linux.dev/fs/jffs2/build.c 2006-06-23 22:15:21.000000000 +0200
+@@ -31,6 +31,10 @@
+ * provisions above, a recipient may use your version of this file
+ * under either the RHEPL or the GPL.
+ *
++ * Modification for automatically cleaning the filesystem after
++ * a specially marked block
++ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
++ *
+ * $Id: build.c,v 1.16.2.3 2003/04/30 09:43:32 dwmw2 Exp $
+ *
+ */
+@@ -38,6 +42,7 @@
+ #include <linux/kernel.h>
+ #include <linux/jffs2.h>
+ #include <linux/slab.h>
++#include <linux/mtd/mtd.h>
+ #include "nodelist.h"
+
+ int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *);
+@@ -89,6 +94,18 @@
+ if (ret)
+ return ret;
+
++ if (c->flags & (1 << 7)) {
++ printk("%s(): unlocking the mtd device... ", __func__);
++ if (c->mtd->unlock)
++ c->mtd->unlock(c->mtd, 0, c->mtd->size);
++ printk("done.\n");
++
++ printk("%s(): erasing all blocks after the end marker... ", __func__);
++ jffs2_erase_pending_blocks(c);
++ jffs2_mark_erased_blocks(c);
++ printk("done.\n");
++ }
++
+ D1(printk(KERN_DEBUG "Scanned flash completely\n"));
+ /* Now build the data map for each inode, marking obsoleted nodes
+ as such, and also increase nlink of any children. */
+diff -ur linux.old/fs/jffs2/scan.c linux.dev/fs/jffs2/scan.c
+--- linux.old/fs/jffs2/scan.c 2006-06-23 21:57:32.000000000 +0200
++++ linux.dev/fs/jffs2/scan.c 2006-06-23 22:01:35.000000000 +0200
+@@ -31,6 +31,10 @@
+ * provisions above, a recipient may use your version of this file
+ * under either the RHEPL or the GPL.
+ *
++ * Modification for automatically cleaning the filesystem after
++ * a specially marked block
++ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
++ *
+ * $Id: scan.c,v 1.51.2.4 2003/11/02 13:51:18 dwmw2 Exp $
+ *
+ */
+@@ -88,7 +92,12 @@
+ for (i=0; i<c->nr_blocks; i++) {
+ struct jffs2_eraseblock *jeb = &c->blocks[i];
+
+- ret = jffs2_scan_eraseblock(c, jeb);
++
++ if (c->flags & (1 << 7))
++ ret = 1;
++ else
++ ret = jffs2_scan_eraseblock(c, jeb);
++
+ if (ret < 0)
+ return ret;
+
+@@ -181,6 +190,7 @@
+
+ while(ofs < jeb->offset + c->sector_size) {
+ ssize_t retlen;
++ unsigned char *buf = (unsigned char *) &node;
+ ACCT_PARANOIA_CHECK(jeb);
+
+ if (ofs & 3) {
+@@ -202,8 +212,18 @@
+ break;
+ }
+
+- err = c->mtd->read(c->mtd, ofs, sizeof(node), &retlen, (char *)&node);
++ err = c->mtd->read(c->mtd, ofs, sizeof(node), &retlen, buf);
++ if ((buf[0] == 0xde) &&
++ (buf[1] == 0xad) &&
++ (buf[2] == 0xc0) &&
++ (buf[3] == 0xde)) {
++
++ /* end of filesystem. erase everything after this point */
++ c->flags |= (1 << 7);
++ printk("jffs2_scan_eraseblock(): End of filesystem marker found at 0x%x\n", jeb->offset);
+
++ return 1;
++ }
+ if (err) {
+ D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", sizeof(node), ofs, err));
+ return err;
diff --git a/target/linux/generic-2.4/patches/228-more_usb_fixes.patch b/target/linux/generic-2.4/patches/228-more_usb_fixes.patch
new file mode 100644
index 0000000..40b24ca
--- /dev/null
+++ b/target/linux/generic-2.4/patches/228-more_usb_fixes.patch
@@ -0,0 +1,861 @@
+diff -ur linux.old/drivers/scsi/hosts.c linux.dev/drivers/scsi/hosts.c
+--- linux.old/drivers/scsi/hosts.c 2003-06-13 16:51:36.000000000 +0200
++++ linux.dev/drivers/scsi/hosts.c 2006-07-30 12:34:30.000000000 +0200
+@@ -107,8 +107,21 @@
+ if (shn) shn->host_registered = 0;
+ /* else {} : This should not happen, we should panic here... */
+
++ /* If we are removing the last host registered, it is safe to reuse
++ * its host number (this avoids "holes" at boot time) (DB)
++ * It is also safe to reuse those of numbers directly below which have
++ * been released earlier (to avoid some holes in numbering).
++ */
++ if(sh->host_no == max_scsi_hosts - 1) {
++ while(--max_scsi_hosts >= next_scsi_host) {
++ shpnt = scsi_hostlist;
++ while(shpnt && shpnt->host_no != max_scsi_hosts - 1)
++ shpnt = shpnt->next;
++ if(shpnt)
++ break;
++ }
++ }
+ next_scsi_host--;
+-
+ kfree((char *) sh);
+ }
+
+diff -ur linux.old/drivers/usb/hcd.c linux.dev/drivers/usb/hcd.c
+--- linux.old/drivers/usb/hcd.c 2004-04-14 15:05:32.000000000 +0200
++++ linux.dev/drivers/usb/hcd.c 2006-07-30 11:49:06.000000000 +0200
+@@ -1105,7 +1105,8 @@
+ break;
+ case PIPE_BULK:
+ allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK
+- | USB_ZERO_PACKET | URB_NO_INTERRUPT;
++ | USB_ZERO_PACKET | URB_NO_INTERRUPT
++ | URB_NO_TRANSFER_DMA_MAP;
+ break;
+ case PIPE_INTERRUPT:
+ allowed |= USB_DISABLE_SPD;
+@@ -1212,7 +1213,8 @@
+ urb->setup_packet,
+ sizeof (struct usb_ctrlrequest),
+ PCI_DMA_TODEVICE);
+- if (urb->transfer_buffer_length != 0)
++ if (urb->transfer_buffer_length != 0
++ && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+ urb->transfer_dma = pci_map_single (
+ hcd->pdev,
+ urb->transfer_buffer,
+diff -ur linux.old/drivers/usb/host/ehci-hcd.c linux.dev/drivers/usb/host/ehci-hcd.c
+--- linux.old/drivers/usb/host/ehci-hcd.c 2006-07-30 11:31:57.000000000 +0200
++++ linux.dev/drivers/usb/host/ehci-hcd.c 2006-07-30 11:48:14.000000000 +0200
+@@ -399,6 +399,27 @@
+ ehci_mem_cleanup (ehci);
+ return retval;
+ }
++
++{
++ int misc_reg;
++ u32 vendor_id;
++
++ pci_read_config_dword (ehci->hcd.pdev, PCI_VENDOR_ID, &vendor_id);
++ if (vendor_id == 0x31041106) {
++ /* VIA 6212 */
++ printk(KERN_INFO "EHCI: Enabling VIA 6212 workarounds\n", misc_reg);
++ pci_read_config_byte(ehci->hcd.pdev, 0x49, &misc_reg);
++ misc_reg &= ~0x20;
++ pci_write_config_byte(ehci->hcd.pdev, 0x49, misc_reg);
++ pci_read_config_byte(ehci->hcd.pdev, 0x49, &misc_reg);
++
++ pci_read_config_byte(ehci->hcd.pdev, 0x4b, &misc_reg);
++ misc_reg |= 0x20;
++ pci_write_config_byte(ehci->hcd.pdev, 0x4b, misc_reg);
++ pci_read_config_byte(ehci->hcd.pdev, 0x4b, &misc_reg);
++ }
++}
++
+ writel (INTR_MASK, &ehci->regs->intr_enable);
+ writel (ehci->periodic_dma, &ehci->regs->frame_list);
+
+diff -ur linux.old/drivers/usb/host/ehci-q.c linux.dev/drivers/usb/host/ehci-q.c
+--- linux.old/drivers/usb/host/ehci-q.c 2006-07-30 11:31:57.000000000 +0200
++++ linux.dev/drivers/usb/host/ehci-q.c 2006-07-30 12:10:15.000000000 +0200
+@@ -791,6 +791,8 @@
+ writel (cmd, &ehci->regs->command);
+ ehci->hcd.state = USB_STATE_RUNNING;
+ /* posted write need not be known to HC yet ... */
++
++ timer_action (ehci, TIMER_IO_WATCHDOG);
+ }
+ }
+
+diff -ur linux.old/drivers/usb/host/usb-uhci.c linux.dev/drivers/usb/host/usb-uhci.c
+--- linux.old/drivers/usb/host/usb-uhci.c 2004-11-17 12:54:21.000000000 +0100
++++ linux.dev/drivers/usb/host/usb-uhci.c 2006-07-30 12:10:16.000000000 +0200
+@@ -2491,7 +2491,7 @@
+ ((urb_priv_t*)urb->hcpriv)->flags=0;
+ }
+
+- if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) &&
++ if ((urb->status != -ECONNABORTED) && (urb->status != -ECONNRESET) &&
+ (urb->status != -ENOENT)) {
+
+ urb->status = -EINPROGRESS;
+@@ -3034,6 +3034,21 @@
+
+ pci_set_master(dev);
+
++ {
++ u8 misc_reg;
++ u32 vendor_id;
++
++ pci_read_config_dword (dev, PCI_VENDOR_ID, &vendor_id);
++ if (vendor_id == 0x30381106) {
++ /* VIA 6212 */
++ printk(KERN_INFO "UHCI: Enabling VIA 6212 workarounds\n");
++ pci_read_config_byte(dev, 0x41, &misc_reg);
++ misc_reg &= ~0x10;
++ pci_write_config_byte(dev, 0x41, misc_reg);
++ pci_read_config_byte(dev, 0x41, &misc_reg);
++ }
++ }
++
+ /* Search for the IO base address.. */
+ for (i = 0; i < 6; i++) {
+
+diff -ur linux.old/drivers/usb/storage/transport.c linux.dev/drivers/usb/storage/transport.c
+--- linux.old/drivers/usb/storage/transport.c 2005-04-04 03:42:19.000000000 +0200
++++ linux.dev/drivers/usb/storage/transport.c 2006-07-30 12:22:56.000000000 +0200
+@@ -54,6 +54,22 @@
+ #include <linux/sched.h>
+ #include <linux/errno.h>
+ #include <linux/slab.h>
++#include <linux/pci.h>
++#include "../hcd.h"
++
++/* These definitions mirror those in pci.h, so they can be used
++ * interchangeably with their PCI_ counterparts */
++enum dma_data_direction {
++ DMA_BIDIRECTIONAL = 0,
++ DMA_TO_DEVICE = 1,
++ DMA_FROM_DEVICE = 2,
++ DMA_NONE = 3,
++};
++
++#define dma_map_sg(d,s,n,dir) pci_map_sg(d,s,n,dir)
++#define dma_unmap_sg(d,s,n,dir) pci_unmap_sg(d,s,n,dir)
++
++
+
+ /***********************************************************************
+ * Helper routines
+@@ -554,6 +570,543 @@
+ return US_BULK_TRANSFER_SHORT;
+ }
+
++/*-------------------------------------------------------------------*/
++/**
++ * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
++ * @dev: device to which the scatterlist will be mapped
++ * @pipe: endpoint defining the mapping direction
++ * @sg: the scatterlist to unmap
++ * @n_hw_ents: the positive return value from usb_buffer_map_sg
++ *
++ * Reverses the effect of usb_buffer_map_sg().
++ */
++static void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
++ struct scatterlist *sg, int n_hw_ents)
++{
++ struct usb_bus *bus;
++ struct usb_hcd *hcd;
++ struct pci_dev *pdev;
++
++ if (!dev
++ || !(bus = dev->bus)
++ || !(hcd = bus->hcpriv)
++ || !(pdev = hcd->pdev)
++ || !pdev->dma_mask)
++ return;
++
++ dma_unmap_sg (pdev, sg, n_hw_ents,
++ usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
++}
++
++/**
++ * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
++ * @dev: device to which the scatterlist will be mapped
++ * @pipe: endpoint defining the mapping direction
++ * @sg: the scatterlist to map
++ * @nents: the number of entries in the scatterlist
++ *
++ * Return value is either < 0 (indicating no buffers could be mapped), or
++ * the number of DMA mapping array entries in the scatterlist.
++ *
++ * The caller is responsible for placing the resulting DMA addresses from
++ * the scatterlist into URB transfer buffer pointers, and for setting the
++ * URB_NO_TRANSFER_DMA_MAP transfer flag in each of those URBs.
++ *
++ * Top I/O rates come from queuing URBs, instead of waiting for each one
++ * to complete before starting the next I/O. This is particularly easy
++ * to do with scatterlists. Just allocate and submit one URB for each DMA
++ * mapping entry returned, stopping on the first error or when all succeed.
++ * Better yet, use the usb_sg_*() calls, which do that (and more) for you.
++ *
++ * This call would normally be used when translating scatterlist requests,
++ * rather than usb_buffer_map(), since on some hardware (with IOMMUs) it
++ * may be able to coalesce mappings for improved I/O efficiency.
++ *
++ * Reverse the effect of this call with usb_buffer_unmap_sg().
++ */
++static int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
++ struct scatterlist *sg, int nents)
++{
++ struct usb_bus *bus;
++ struct usb_hcd *hcd;
++ struct pci_dev *pdev;
++
++ if (!dev
++ || usb_pipecontrol (pipe)
++ || !(bus = dev->bus)
++ || !(hcd = bus->hcpriv)
++ || !(pdev = hcd->pdev)
++ || !pdev->dma_mask)
++ return -1;
++
++ // FIXME generic api broken like pci, can't report errors
++ return dma_map_sg (pdev, sg, nents,
++ usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
++}
++
++static void sg_clean (struct usb_sg_request *io)
++{
++ struct usb_hcd *hcd = io->dev->bus->hcpriv;
++ struct pci_dev *pdev = hcd->pdev;
++
++ if (io->urbs) {
++ while (io->entries--)
++ usb_free_urb (io->urbs [io->entries]);
++ kfree (io->urbs);
++ io->urbs = 0;
++ }
++ if (pdev->dma_mask != 0)
++ usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
++ io->dev = 0;
++}
++
++static void sg_complete (struct urb *urb)
++{
++ struct usb_sg_request *io = (struct usb_sg_request *) urb->context;
++
++ spin_lock (&io->lock);
++
++ /* In 2.5 we require hcds' endpoint queues not to progress after fault
++ * reports, until the completion callback (this!) returns. That lets
++ * device driver code (like this routine) unlink queued urbs first,
++ * if it needs to, since the HC won't work on them at all. So it's
++ * not possible for page N+1 to overwrite page N, and so on.
++ *
++ * That's only for "hard" faults; "soft" faults (unlinks) sometimes
++ * complete before the HCD can get requests away from hardware,
++ * though never during cleanup after a hard fault.
++ */
++ if (io->status
++ && (io->status != -ECONNRESET
++ || urb->status != -ECONNRESET)
++ && urb->actual_length) {
++ US_DEBUGP("Error: %s ep%d%s scatterlist error %d/%d\n",
++ io->dev->devpath,
++ usb_pipeendpoint (urb->pipe),
++ usb_pipein (urb->pipe) ? "in" : "out",
++ urb->status, io->status);
++ // BUG ();
++ }
++
++ if (urb->status && urb->status != -ECONNRESET) {
++ int i, found, status;
++
++ io->status = urb->status;
++
++ /* the previous urbs, and this one, completed already.
++ * unlink pending urbs so they won't rx/tx bad data.
++ */
++ for (i = 0, found = 0; i < io->entries; i++) {
++ if (!io->urbs [i])
++ continue;
++ if (found) {
++ status = usb_unlink_urb (io->urbs [i]);
++ if (status != -EINPROGRESS && status != -EBUSY)
++ US_DEBUGP("Error: %s, unlink --> %d\n", __FUNCTION__, status);
++ } else if (urb == io->urbs [i])
++ found = 1;
++ }
++ }
++ urb->dev = 0;
++
++ /* on the last completion, signal usb_sg_wait() */
++ io->bytes += urb->actual_length;
++ io->count--;
++ if (!io->count)
++ complete (&io->complete);
++
++ spin_unlock (&io->lock);
++}
++
++/**
++ * usb_sg_init - initializes scatterlist-based bulk/interrupt I/O request
++ * @io: request block being initialized. until usb_sg_wait() returns,
++ * treat this as a pointer to an opaque block of memory,
++ * @dev: the usb device that will send or receive the data
++ * @pipe: endpoint "pipe" used to transfer the data
++ * @period: polling rate for interrupt endpoints, in frames or
++ * (for high speed endpoints) microframes; ignored for bulk
++ * @sg: scatterlist entries
++ * @nents: how many entries in the scatterlist
++ * @length: how many bytes to send from the scatterlist, or zero to
++ * send every byte identified in the list.
++ * @mem_flags: SLAB_* flags affecting memory allocations in this call
++ *
++ * Returns zero for success, else a negative errno value. This initializes a
++ * scatter/gather request, allocating resources such as I/O mappings and urb
++ * memory (except maybe memory used by USB controller drivers).
++ *
++ * The request must be issued using usb_sg_wait(), which waits for the I/O to
++ * complete (or to be canceled) and then cleans up all resources allocated by
++ * usb_sg_init().
++ *
++ * The request may be canceled with usb_sg_cancel(), either before or after
++ * usb_sg_wait() is called.
++ */
++int usb_sg_init (
++ struct usb_sg_request *io,
++ struct usb_device *dev,
++ unsigned pipe,
++ unsigned period,
++ struct scatterlist *sg,
++ int nents,
++ size_t length,
++ int mem_flags
++)
++{
++ int i;
++ int urb_flags;
++ int dma;
++ struct usb_hcd *hcd;
++
++ hcd = dev->bus->hcpriv;
++
++ if (!io || !dev || !sg
++ || usb_pipecontrol (pipe)
++ || usb_pipeisoc (pipe)
++ || nents <= 0)
++ return -EINVAL;
++
++ spin_lock_init (&io->lock);
++ io->dev = dev;
++ io->pipe = pipe;
++ io->sg = sg;
++ io->nents = nents;
++
++ /* not all host controllers use DMA (like the mainstream pci ones);
++ * they can use PIO (sl811) or be software over another transport.
++ */
++ dma = (hcd->pdev->dma_mask != 0);
++ if (dma)
++ io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
++ else
++ io->entries = nents;
++
++ /* initialize all the urbs we'll use */
++ if (io->entries <= 0)
++ return io->entries;
++
++ io->count = 0;
++ io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags);
++ if (!io->urbs)
++ goto nomem;
++
++ urb_flags = USB_ASYNC_UNLINK | URB_NO_INTERRUPT | URB_NO_TRANSFER_DMA_MAP;
++ if (usb_pipein (pipe))
++ urb_flags |= URB_SHORT_NOT_OK;
++
++ for (i = 0; i < io->entries; i++, io->count = i) {
++ unsigned len;
++
++ io->urbs [i] = usb_alloc_urb (0);
++ if (!io->urbs [i]) {
++ io->entries = i;
++ goto nomem;
++ }
++
++ io->urbs [i]->dev = 0;
++ io->urbs [i]->pipe = pipe;
++ io->urbs [i]->interval = period;
++ io->urbs [i]->transfer_flags = urb_flags;
++
++ io->urbs [i]->complete = sg_complete;
++ io->urbs [i]->context = io;
++ io->urbs [i]->status = -EINPROGRESS;
++ io->urbs [i]->actual_length = 0;
++
++ if (dma) {
++ /* hc may use _only_ transfer_dma */
++ io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
++ len = sg_dma_len (sg + i);
++ } else {
++ /* hc may use _only_ transfer_buffer */
++ io->urbs [i]->transfer_buffer =
++ page_address (sg [i].page) + sg [i].offset;
++ len = sg [i].length;
++ }
++
++ if (length) {
++ len = min_t (unsigned, len, length);
++ length -= len;
++ if (length == 0)
++ io->entries = i + 1;
++ }
++ io->urbs [i]->transfer_buffer_length = len;
++ }
++ io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT;
++
++ /* transaction state */
++ io->status = 0;
++ io->bytes = 0;
++ init_completion (&io->complete);
++ return 0;
++
++nomem:
++ sg_clean (io);
++ return -ENOMEM;
++}
++
++/**
++ * usb_sg_cancel - stop scatter/gather i/o issued by usb_sg_wait()
++ * @io: request block, initialized with usb_sg_init()
++ *
++ * This stops a request after it has been started by usb_sg_wait().
++ * It can also prevents one initialized by usb_sg_init() from starting,
++ * so that call just frees resources allocated to the request.
++ */
++void usb_sg_cancel (struct usb_sg_request *io)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave (&io->lock, flags);
++
++ /* shut everything down, if it didn't already */
++ if (!io->status) {
++ int i;
++
++ io->status = -ECONNRESET;
++ for (i = 0; i < io->entries; i++) {
++ int retval;
++
++ if (!io->urbs [i]->dev)
++ continue;
++ retval = usb_unlink_urb (io->urbs [i]);
++ if (retval != -EINPROGRESS && retval != -EBUSY)
++ US_DEBUGP("WARNING: %s, unlink --> %d\n", __FUNCTION__, retval);
++ }
++ }
++ spin_unlock_irqrestore (&io->lock, flags);
++}
++
++/**
++ * usb_sg_wait - synchronously execute scatter/gather request
++ * @io: request block handle, as initialized with usb_sg_init().
++ * some fields become accessible when this call returns.
++ * Context: !in_interrupt ()
++ *
++ * This function blocks until the specified I/O operation completes. It
++ * leverages the grouping of the related I/O requests to get good transfer
++ * rates, by queueing the requests. At higher speeds, such queuing can
++ * significantly improve USB throughput.
++ *
++ * There are three kinds of completion for this function.
++ * (1) success, where io->status is zero. The number of io->bytes
++ * transferred is as requested.
++ * (2) error, where io->status is a negative errno value. The number
++ * of io->bytes transferred before the error is usually less
++ * than requested, and can be nonzero.
++ * (3) cancelation, a type of error with status -ECONNRESET that
++ * is initiated by usb_sg_cancel().
++ *
++ * When this function returns, all memory allocated through usb_sg_init() or
++ * this call will have been freed. The request block parameter may still be
++ * passed to usb_sg_cancel(), or it may be freed. It could also be
++ * reinitialized and then reused.
++ *
++ * Data Transfer Rates:
++ *
++ * Bulk transfers are valid for full or high speed endpoints.
++ * The best full speed data rate is 19 packets of 64 bytes each
++ * per frame, or 1216 bytes per millisecond.
++ * The best high speed data rate is 13 packets of 512 bytes each
++ * per microframe, or 52 KBytes per millisecond.
++ *
++ * The reason to use interrupt transfers through this API would most likely
++ * be to reserve high speed bandwidth, where up to 24 KBytes per millisecond
++ * could be transferred. That capability is less useful for low or full
++ * speed interrupt endpoints, which allow at most one packet per millisecond,
++ * of at most 8 or 64 bytes (respectively).
++ */
++void usb_sg_wait (struct usb_sg_request *io)
++{
++ int i, entries = io->entries;
++
++ /* queue the urbs. */
++ spin_lock_irq (&io->lock);
++ for (i = 0; i < entries && !io->status; i++) {
++ int retval;
++
++ io->urbs [i]->dev = io->dev;
++ retval = usb_submit_urb (io->urbs [i]);
++
++ /* after we submit, let completions or cancelations fire;
++ * we handshake using io->status.
++ */
++ spin_unlock_irq (&io->lock);
++ switch (retval) {
++ /* maybe we retrying will recover */
++ case -ENXIO: // hc didn't queue this one
++ case -EAGAIN:
++ case -ENOMEM:
++ io->urbs [i]->dev = 0;
++ retval = 0;
++ i--;
++ yield ();
++ break;
++
++ /* no error? continue immediately.
++ *
++ * NOTE: to work better with UHCI (4K I/O buffer may
++ * need 3K of TDs) it may be good to limit how many
++ * URBs are queued at once; N milliseconds?
++ */
++ case 0:
++ cpu_relax ();
++ break;
++
++ /* fail any uncompleted urbs */
++ default:
++ spin_lock_irq (&io->lock);
++ io->count -= entries - i;
++ if (io->status == -EINPROGRESS)
++ io->status = retval;
++ if (io->count == 0)
++ complete (&io->complete);
++ spin_unlock_irq (&io->lock);
++
++ io->urbs [i]->dev = 0;
++ io->urbs [i]->status = retval;
++
++ US_DEBUGP("%s, submit --> %d\n", __FUNCTION__, retval);
++ usb_sg_cancel (io);
++ }
++ spin_lock_irq (&io->lock);
++ if (retval && io->status == -ECONNRESET)
++ io->status = retval;
++ }
++ spin_unlock_irq (&io->lock);
++
++ /* OK, yes, this could be packaged as non-blocking.
++ * So could the submit loop above ... but it's easier to
++ * solve neither problem than to solve both!
++ */
++ wait_for_completion (&io->complete);
++
++ sg_clean (io);
++}
++
++/*
++ * Interpret the results of a URB transfer
++ *
++ * This function prints appropriate debugging messages, clears halts on
++ * non-control endpoints, and translates the status to the corresponding
++ * USB_STOR_XFER_xxx return code.
++ */
++static int interpret_urb_result(struct us_data *us, unsigned int pipe,
++ unsigned int length, int result, unsigned int partial)
++{
++ US_DEBUGP("Status code %d; transferred %u/%u\n",
++ result, partial, length);
++ switch (result) {
++
++ /* no error code; did we send all the data? */
++ case 0:
++ if (partial != length) {
++ US_DEBUGP("-- short transfer\n");
++ return USB_STOR_XFER_SHORT;
++ }
++
++ US_DEBUGP("-- transfer complete\n");
++ return USB_STOR_XFER_GOOD;
++
++ /* stalled */
++ case -EPIPE:
++ /* for control endpoints, (used by CB[I]) a stall indicates
++ * a failed command */
++ if (usb_pipecontrol(pipe)) {
++ US_DEBUGP("-- stall on control pipe\n");
++ return USB_STOR_XFER_STALLED;
++ }
++
++ /* for other sorts of endpoint, clear the stall */
++ US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
++ if (usb_stor_clear_halt(us, pipe) < 0)
++ return USB_STOR_XFER_ERROR;
++ return USB_STOR_XFER_STALLED;
++
++ /* timeout or excessively long NAK */
++ case -ETIMEDOUT:
++ US_DEBUGP("-- timeout or NAK\n");
++ return USB_STOR_XFER_ERROR;
++
++ /* babble - the device tried to send more than we wanted to read */
++ case -EOVERFLOW:
++ US_DEBUGP("-- babble\n");
++ return USB_STOR_XFER_LONG;
++
++ /* the transfer was cancelled by abort, disconnect, or timeout */
++ case -ECONNRESET:
++ US_DEBUGP("-- transfer cancelled\n");
++ return USB_STOR_XFER_ERROR;
++
++ /* short scatter-gather read transfer */
++ case -EREMOTEIO:
++ US_DEBUGP("-- short read transfer\n");
++ return USB_STOR_XFER_SHORT;
++
++ /* abort or disconnect in progress */
++ case -EIO:
++ US_DEBUGP("-- abort or disconnect in progress\n");
++ return USB_STOR_XFER_ERROR;
++
++ /* the catch-all error case */
++ default:
++ US_DEBUGP("-- unknown error\n");
++ return USB_STOR_XFER_ERROR;
++ }
++}
++
++/*
++ * Transfer a scatter-gather list via bulk transfer
++ *
++ * This function does basically the same thing as usb_stor_bulk_msg()
++ * above, but it uses the usbcore scatter-gather library.
++ */
++int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
++ struct scatterlist *sg, int num_sg, unsigned int length,
++ unsigned int *act_len)
++{
++ int result;
++
++ /* don't submit s-g requests during abort/disconnect processing */
++ if (us->flags & ABORTING_OR_DISCONNECTING)
++ return USB_STOR_XFER_ERROR;
++
++ /* initialize the scatter-gather request block */
++ US_DEBUGP("%s: xfer %u bytes, %d entries\n", __FUNCTION__,
++ length, num_sg);
++ result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0,
++ sg, num_sg, length, SLAB_NOIO);
++ if (result) {
++ US_DEBUGP("usb_sg_init returned %d\n", result);
++ return USB_STOR_XFER_ERROR;
++ }
++
++ /* since the block has been initialized successfully, it's now
++ * okay to cancel it */
++ set_bit(US_FLIDX_SG_ACTIVE, &us->flags);
++
++ /* did an abort/disconnect occur during the submission? */
++ if (us->flags & ABORTING_OR_DISCONNECTING) {
++
++ /* cancel the request, if it hasn't been cancelled already */
++ if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) {
++ US_DEBUGP("-- cancelling sg request\n");
++ usb_sg_cancel(&us->current_sg);
++ }
++ }
++
++ /* wait for the completion of the transfer */
++ usb_sg_wait(&us->current_sg);
++ clear_bit(US_FLIDX_SG_ACTIVE, &us->flags);
++
++ result = us->current_sg.status;
++ if (act_len)
++ *act_len = us->current_sg.bytes;
++ return interpret_urb_result(us, pipe, length, result,
++ us->current_sg.bytes);
++}
++
+ /*
+ * Transfer an entire SCSI command's worth of data payload over the bulk
+ * pipe.
+@@ -569,6 +1122,8 @@
+ struct scatterlist *sg;
+ unsigned int total_transferred = 0;
+ unsigned int transfer_amount;
++ unsigned int partial;
++ unsigned int pipe;
+
+ /* calculate how much we want to transfer */
+ transfer_amount = usb_stor_transfer_length(srb);
+@@ -585,23 +1140,34 @@
+ * make the appropriate requests for each, until done
+ */
+ sg = (struct scatterlist *) srb->request_buffer;
+- for (i = 0; i < srb->use_sg; i++) {
+-
+- /* transfer the lesser of the next buffer or the
+- * remaining data */
+- if (transfer_amount - total_transferred >=
+- sg[i].length) {
+- result = usb_stor_transfer_partial(us,
+- sg[i].address, sg[i].length);
+- total_transferred += sg[i].length;
+- } else
+- result = usb_stor_transfer_partial(us,
+- sg[i].address,
+- transfer_amount - total_transferred);
+-
+- /* if we get an error, end the loop here */
+- if (result)
+- break;
++ if (us->pusb_dev->speed == USB_SPEED_HIGH) {
++ /* calculate the appropriate pipe information */
++ if (us->srb->sc_data_direction == SCSI_DATA_READ)
++ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
++ else
++ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
++ /* use the usb core scatter-gather primitives */
++ result = usb_stor_bulk_transfer_sglist(us, pipe,
++ sg, srb->use_sg, transfer_amount, &partial);
++ } else {
++ for (i = 0; i < srb->use_sg; i++) {
++
++ /* transfer the lesser of the next buffer or the
++ * remaining data */
++ if (transfer_amount - total_transferred >=
++ sg[i].length) {
++ result = usb_stor_transfer_partial(us,
++ sg[i].address, sg[i].length);
++ total_transferred += sg[i].length;
++ } else
++ result = usb_stor_transfer_partial(us,
++ sg[i].address,
++ transfer_amount - total_transferred);
++
++ /* if we get an error, end the loop here */
++ if (result)
++ break;
++ }
+ }
+ }
+ else
+diff -ur linux.old/drivers/usb/storage/transport.h linux.dev/drivers/usb/storage/transport.h
+--- linux.old/drivers/usb/storage/transport.h 2003-08-25 13:44:42.000000000 +0200
++++ linux.dev/drivers/usb/storage/transport.h 2006-07-30 12:10:16.000000000 +0200
+@@ -127,6 +127,16 @@
+ #define US_BULK_TRANSFER_ABORTED 3 /* transfer canceled */
+
+ /*
++ * usb_stor_bulk_transfer_xxx() return codes, in order of severity
++ */
++
++#define USB_STOR_XFER_GOOD 0 /* good transfer */
++#define USB_STOR_XFER_SHORT 1 /* transferred less than expected */
++#define USB_STOR_XFER_STALLED 2 /* endpoint stalled */
++#define USB_STOR_XFER_LONG 3 /* device tried to send too much */
++#define USB_STOR_XFER_ERROR 4 /* transfer died in the middle */
++
++/*
+ * Transport return codes
+ */
+
+diff -ur linux.old/drivers/usb/storage/usb.h linux.dev/drivers/usb/storage/usb.h
+--- linux.old/drivers/usb/storage/usb.h 2005-04-04 03:42:20.000000000 +0200
++++ linux.dev/drivers/usb/storage/usb.h 2006-07-30 12:11:06.000000000 +0200
+@@ -111,6 +111,60 @@
+ typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*);
+ typedef void (*extra_data_destructor)(void *); /* extra data destructor */
+
++/* Dynamic flag definitions: used in set_bit() etc. */
++#define US_FLIDX_URB_ACTIVE 18 /* 0x00040000 current_urb is in use */
++#define US_FLIDX_SG_ACTIVE 19 /* 0x00080000 current_sg is in use */
++#define US_FLIDX_ABORTING 20 /* 0x00100000 abort is in progress */
++#define US_FLIDX_DISCONNECTING 21 /* 0x00200000 disconnect in progress */
++#define ABORTING_OR_DISCONNECTING ((1UL << US_FLIDX_ABORTING) | \
++ (1UL << US_FLIDX_DISCONNECTING))
++#define US_FLIDX_RESETTING 22 /* 0x00400000 device reset in progress */
++
++/* processing state machine states */
++#define US_STATE_IDLE 1
++#define US_STATE_RUNNING 2
++#define US_STATE_RESETTING 3
++#define US_STATE_ABORTING 4
++
++/**
++ * struct usb_sg_request - support for scatter/gather I/O
++ * @status: zero indicates success, else negative errno
++ * @bytes: counts bytes transferred.
++ *
++ * These requests are initialized using usb_sg_init(), and then are used
++ * as request handles passed to usb_sg_wait() or usb_sg_cancel(). Most
++ * members of the request object aren't for driver access.
++ *
++ * The status and bytecount values are valid only after usb_sg_wait()
++ * returns. If the status is zero, then the bytecount matches the total
++ * from the request.
++ *
++ * After an error completion, drivers may need to clear a halt condition
++ * on the endpoint.
++ */
++struct usb_sg_request {
++ int status;
++ size_t bytes;
++
++ /*
++ * members below are private to usbcore,
++ * and are not provided for driver access!
++ */
++ spinlock_t lock;
++
++ struct usb_device *dev;
++ int pipe;
++ struct scatterlist *sg;
++ int nents;
++
++ int entries;
++ struct urb **urbs;
++
++ int count;
++ struct completion complete;
++};
++
++
+ /* we allocate one of these for every device that we remember */
+ struct us_data {
+ struct us_data *next; /* next device */
+@@ -171,6 +225,7 @@
+ struct urb *current_urb; /* non-int USB requests */
+ struct completion current_done; /* the done flag */
+ unsigned int tag; /* tag for bulk CBW/CSW */
++ struct usb_sg_request current_sg; /* scatter-gather req. */
+
+ /* the semaphore for sleeping the control thread */
+ struct semaphore sema; /* to sleep thread on */
+diff -ur linux.old/include/linux/usb.h linux.dev/include/linux/usb.h
+--- linux.old/include/linux/usb.h 2004-11-17 12:54:22.000000000 +0100
++++ linux.dev/include/linux/usb.h 2006-07-30 12:19:19.000000000 +0200
+@@ -483,6 +483,8 @@
+ #define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt needed */
+ /* ... less overhead for QUEUE_BULK */
+ #define USB_TIMEOUT_KILLED 0x1000 // only set by HCD!
++#define URB_NO_TRANSFER_DMA_MAP 0x0400 /* urb->transfer_dma valid on submit */
++#define URB_NO_SETUP_DMA_MAP 0x0800 /* urb->setup_dma valid on submit */
+
+ struct iso_packet_descriptor
+ {
diff --git a/target/linux/generic-2.4/patches/229-pppoe_mtu_fix.patch b/target/linux/generic-2.4/patches/229-pppoe_mtu_fix.patch
new file mode 100644
index 0000000..c2e4f06
--- /dev/null
+++ b/target/linux/generic-2.4/patches/229-pppoe_mtu_fix.patch
@@ -0,0 +1,12 @@
+--- linux-2.4.30/drivers/net/pppoe.c.old 2006-10-10 13:49:12.000000000 +0200
++++ linux-2.4.30/drivers/net/pppoe.c 2006-10-10 13:50:02.000000000 +0200
+@@ -639,6 +639,9 @@
+ po->chan.hdrlen = (sizeof(struct pppoe_hdr) +
+ dev->hard_header_len);
+
++ if (po->chan.mtu > dev->mtu - sizeof(struct pppoe_hdr))
++ po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr);
++
+ po->chan.private = sk;
+ po->chan.ops = &pppoe_chan_ops;
+
diff --git a/target/linux/generic-2.4/patches/601-netfilter_ipp2p_0.8.1rc1.patch b/target/linux/generic-2.4/patches/601-netfilter_ipp2p_0.8.1rc1.patch
new file mode 100644
index 0000000..bfaa6e4
--- /dev/null
+++ b/target/linux/generic-2.4/patches/601-netfilter_ipp2p_0.8.1rc1.patch
@@ -0,0 +1,929 @@
+diff -urN linux.old/include/linux/netfilter_ipv4/ipt_ipp2p.h linux.dev/include/linux/netfilter_ipv4/ipt_ipp2p.h
+--- linux.old/include/linux/netfilter_ipv4/ipt_ipp2p.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/linux/netfilter_ipv4/ipt_ipp2p.h 2006-03-23 14:37:56.000000000 +0100
+@@ -0,0 +1,31 @@
++#ifndef __IPT_IPP2P_H
++#define __IPT_IPP2P_H
++#define IPP2P_VERSION "0.8.1_rc1"
++
++struct ipt_p2p_info {
++ int cmd;
++ int debug;
++};
++
++#endif //__IPT_IPP2P_H
++
++#define SHORT_HAND_IPP2P 1 /* --ipp2p switch*/
++//#define SHORT_HAND_DATA 4 /* --ipp2p-data switch*/
++#define SHORT_HAND_NONE 5 /* no short hand*/
++
++#define IPP2P_EDK (1 << 1)
++#define IPP2P_DATA_KAZAA (1 << 2)
++#define IPP2P_DATA_EDK (1 << 3)
++#define IPP2P_DATA_DC (1 << 4)
++#define IPP2P_DC (1 << 5)
++#define IPP2P_DATA_GNU (1 << 6)
++#define IPP2P_GNU (1 << 7)
++#define IPP2P_KAZAA (1 << 8)
++#define IPP2P_BIT (1 << 9)
++#define IPP2P_APPLE (1 << 10)
++#define IPP2P_SOUL (1 << 11)
++#define IPP2P_WINMX (1 << 12)
++#define IPP2P_ARES (1 << 13)
++#define IPP2P_MUTE (1 << 14)
++#define IPP2P_WASTE (1 << 15)
++#define IPP2P_XDCC (1 << 16)
+diff -urN linux.old/net/ipv4/netfilter/Config.in linux.dev/net/ipv4/netfilter/Config.in
+--- linux.old/net/ipv4/netfilter/Config.in 2006-03-23 14:35:20.000000000 +0100
++++ linux.dev/net/ipv4/netfilter/Config.in 2006-03-23 14:35:58.000000000 +0100
+@@ -29,6 +29,7 @@
+ dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES
++ dep_tristate ' peer to peer traffic match support' CONFIG_IP_NF_MATCH_IPP2P $CONFIG_IP_NF_IPTABLES
+
+ dep_tristate ' DSCP match support' CONFIG_IP_NF_MATCH_DSCP $CONFIG_IP_NF_IPTABLES
+
+diff -urN linux.old/net/ipv4/netfilter/Makefile linux.dev/net/ipv4/netfilter/Makefile
+--- linux.old/net/ipv4/netfilter/Makefile 2006-03-23 14:35:20.000000000 +0100
++++ linux.dev/net/ipv4/netfilter/Makefile 2006-03-23 14:35:58.000000000 +0100
+@@ -76,6 +76,7 @@
+ obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
+ obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
+ obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
++obj-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p.o
+
+ obj-$(CONFIG_IP_NF_MATCH_PKTTYPE) += ipt_pkttype.o
+ obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
+diff -urN linux.old/net/ipv4/netfilter/ipt_ipp2p.c linux.dev/net/ipv4/netfilter/ipt_ipp2p.c
+--- linux.old/net/ipv4/netfilter/ipt_ipp2p.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/net/ipv4/netfilter/ipt_ipp2p.c 2006-03-23 14:37:18.000000000 +0100
+@@ -0,0 +1,868 @@
++#if defined(MODVERSIONS)
++#include <linux/modversions.h>
++#endif
++#include <linux/module.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/version.h>
++#include <linux/netfilter_ipv4/ipt_ipp2p.h>
++#include <net/tcp.h>
++#include <net/udp.h>
++
++#define get_u8(X,O) (*(__u8 *)(X + O))
++#define get_u16(X,O) (*(__u16 *)(X + O))
++#define get_u32(X,O) (*(__u32 *)(X + O))
++
++MODULE_AUTHOR("Eicke Friedrich/Klaus Degner <ipp2p@ipp2p.org>");
++MODULE_DESCRIPTION("An extension to iptables to identify P2P traffic.");
++MODULE_LICENSE("GPL");
++
++
++/*Search for UDP eDonkey/eMule/Kad commands*/
++int
++udp_search_edk (unsigned char *haystack, int packet_len)
++{
++ unsigned char *t = haystack;
++ t += 8;
++
++ switch (t[0]) {
++ case 0xe3:
++ { /*edonkey*/
++ switch (t[1])
++ {
++ /* client -> server status request */
++ case 0x96:
++ if (packet_len == 14) return ((IPP2P_EDK * 100) + 50);
++ break;
++ /* server -> client status request */
++ case 0x97: if (packet_len == 42) return ((IPP2P_EDK * 100) + 51);
++ break;
++ /* server description request */
++ /* e3 2a ff f0 .. | size == 6 */
++ case 0xa2: if ( (packet_len == 14) && ( get_u16(t,2) == __constant_htons(0xfff0) ) ) return ((IPP2P_EDK * 100) + 52);
++ break;
++ /* server description response */
++ /* e3 a3 ff f0 .. | size > 40 && size < 200 */
++ //case 0xa3: return ((IPP2P_EDK * 100) + 53);
++ // break;
++ case 0x9a: if (packet_len==26) return ((IPP2P_EDK * 100) + 54);
++ break;
++
++ case 0x92: if (packet_len==18) return ((IPP2P_EDK * 100) + 55);
++ break;
++ }
++ break;
++ }
++ case 0xe4:
++ {
++ switch (t[1])
++ {
++ /* e4 20 .. | size == 43 */
++ case 0x20: if ((packet_len == 43) && (t[2] != 0x00) && (t[34] != 0x00)) return ((IPP2P_EDK * 100) + 60);
++ break;
++ /* e4 00 .. 00 | size == 35 ? */
++ case 0x00: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 61);
++ break;
++ /* e4 10 .. 00 | size == 35 ? */
++ case 0x10: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 62);
++ break;
++ /* e4 18 .. 00 | size == 35 ? */
++ case 0x18: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 63);
++ break;
++ /* e4 52 .. | size = 44 */
++ case 0x52: if (packet_len == 44 ) return ((IPP2P_EDK * 100) + 64);
++ break;
++ /* e4 58 .. | size == 6 */
++ case 0x58: if (packet_len == 14 ) return ((IPP2P_EDK * 100) + 65);
++ break;
++ /* e4 59 .. | size == 2 */
++ case 0x59: if (packet_len == 10 )return ((IPP2P_EDK * 100) + 66);
++ break;
++ /* e4 28 .. | packet_len == 52,77,102,127... */
++ case 0x28: if (((packet_len-52) % 25) == 0) return ((IPP2P_EDK * 100) + 67);
++ break;
++ /* e4 50 xx xx | size == 4 */
++ case 0x50: if (packet_len == 12) return ((IPP2P_EDK * 100) + 68);
++ break;
++ /* e4 40 xx xx | size == 48 */
++ case 0x40: if (packet_len == 56) return ((IPP2P_EDK * 100) + 69);
++ break;
++ }
++ break;
++ }
++ } /* end of switch (t[0]) */
++ return 0;
++}/*udp_search_edk*/
++
++
++/*Search for UDP Gnutella commands*/
++int
++udp_search_gnu (unsigned char *haystack, int packet_len)
++{
++ unsigned char *t = haystack;
++ t += 8;
++
++ if (memcmp(t, "GND", 3) == 0) return ((IPP2P_GNU * 100) + 51);
++ if (memcmp(t, "GNUTELLA ", 9) == 0) return ((IPP2P_GNU * 100) + 52);
++ return 0;
++}/*udp_search_gnu*/
++
++
++/*Search for UDP KaZaA commands*/
++int
++udp_search_kazaa (unsigned char *haystack, int packet_len)
++{
++ unsigned char *t = haystack;
++
++ if (t[packet_len-1] == 0x00){
++ t += (packet_len - 6);
++ if (memcmp(t, "KaZaA", 5) == 0) return (IPP2P_KAZAA * 100 +50);
++ }
++
++ return 0;
++}/*udp_search_kazaa*/
++
++/*Search for UDP DirectConnect commands*/
++int
++udp_search_directconnect (unsigned char *haystack, int packet_len)
++{
++ unsigned char *t = haystack;
++ if ((*(t + 8) == 0x24) && (*(t + packet_len - 1) == 0x7c)) {
++ t+=8;
++ if (memcmp(t, "SR ", 3) == 0) return ((IPP2P_DC * 100) + 60);
++ if (memcmp(t, "Ping ", 5) == 0) return ((IPP2P_DC * 100) + 61);
++ }
++ return 0;
++}/*udp_search_directconnect*/
++
++
++
++/*Search for UDP BitTorrent commands*/
++int
++udp_search_bit (unsigned char *haystack, int packet_len)
++{
++ switch(packet_len)
++ {
++ case 24:
++ /* ^ 00 00 04 17 27 10 19 80 */
++ if ((ntohl(get_u32(haystack, 8)) == 0x00000417) && (ntohl(get_u32(haystack, 12)) == 0x27101980))
++ return (IPP2P_BIT * 100 + 50);
++ break;
++ case 44:
++ if (get_u32(haystack, 16) == __constant_htonl(0x00000400) && get_u32(haystack, 36) == __constant_htonl(0x00000104))
++ return (IPP2P_BIT * 100 + 51);
++ if (get_u32(haystack, 16) == __constant_htonl(0x00000400))
++ return (IPP2P_BIT * 100 + 61);
++ break;
++ case 65:
++ if (get_u32(haystack, 16) == __constant_htonl(0x00000404) && get_u32(haystack, 36) == __constant_htonl(0x00000104))
++ return (IPP2P_BIT * 100 + 52);
++ if (get_u32(haystack, 16) == __constant_htonl(0x00000404))
++ return (IPP2P_BIT * 100 + 62);
++ break;
++ case 67:
++ if (get_u32(haystack, 16) == __constant_htonl(0x00000406) && get_u32(haystack, 36) == __constant_htonl(0x00000104))
++ return (IPP2P_BIT * 100 + 53);
++ if (get_u32(haystack, 16) == __constant_htonl(0x00000406))
++ return (IPP2P_BIT * 100 + 63);
++ break;
++ case 211:
++ if (get_u32(haystack, 8) == __constant_htonl(0x00000405))
++ return (IPP2P_BIT * 100 + 54);
++ break;
++ case 29:
++ if ((get_u32(haystack, 8) == __constant_htonl(0x00000401)))
++ return (IPP2P_BIT * 100 + 55);
++ break;
++ case 52:
++ if (get_u32(haystack,8) == __constant_htonl(0x00000827) &&
++ get_u32(haystack,12) == __constant_htonl(0x37502950))
++ return (IPP2P_BIT * 100 + 80);
++ break;
++ default:
++ /* this packet does not have a constant size */
++ if (packet_len >= 40 && get_u32(haystack, 16) == __constant_htonl(0x00000402) && get_u32(haystack, 36) == __constant_htonl(0x00000104))
++ return (IPP2P_BIT * 100 + 56);
++ break;
++ }
++
++ /* some extra-bitcomet rules:
++ * "d1:" [a|r] "d2:id20:"
++ */
++ if (packet_len > 30 && get_u8(haystack, 8) == 'd' && get_u8(haystack, 9) == '1' && get_u8(haystack, 10) == ':' )
++ {
++ if (get_u8(haystack, 11) == 'a' || get_u8(haystack, 11) == 'r')
++ {
++ if (memcmp(haystack+12,"d2:id20:",8)==0)
++ return (IPP2P_BIT * 100 + 57);
++ }
++ }
++
++#if 0
++ /* bitlord rules */
++ /* packetlen must be bigger than 40 */
++ /* first 4 bytes are zero */
++ if (packet_len > 40 && get_u32(haystack, 8) == 0x00000000)
++ {
++ /* first rule: 00 00 00 00 01 00 00 xx xx xx xx 00 00 00 00*/
++ if (get_u32(haystack, 12) == 0x00000000 &&
++ get_u32(haystack, 16) == 0x00010000 &&
++ get_u32(haystack, 24) == 0x00000000 )
++ return (IPP2P_BIT * 100 + 71);
++
++ /* 00 01 00 00 0d 00 00 xx xx xx xx 00 00 00 00*/
++ if (get_u32(haystack, 12) == 0x00000001 &&
++ get_u32(haystack, 16) == 0x000d0000 &&
++ get_u32(haystack, 24) == 0x00000000 )
++ return (IPP2P_BIT * 100 + 71);
++
++
++ }
++#endif
++
++ return 0;
++}/*udp_search_bit*/
++
++
++
++/*Search for Ares commands*/
++//#define IPP2P_DEBUG_ARES
++int
++search_ares (const unsigned char *payload, const u16 plen)
++//int search_ares (unsigned char *haystack, int packet_len, int head_len)
++{
++// const unsigned char *t = haystack + head_len;
++
++ /* all ares packets start with */
++ if (payload[1] == 0 && (plen - payload[0]) == 3)
++ {
++ switch (payload[2])
++ {
++ case 0x5a:
++ /* ares connect */
++ if ( plen == 6 && payload[5] == 0x05 ) return ((IPP2P_ARES * 100) + 1);
++ break;
++ case 0x09:
++ /* ares search, min 3 chars --> 14 bytes
++ * lets define a search can be up to 30 chars --> max 34 bytes
++ */
++ if ( plen >= 14 && plen <= 34 ) return ((IPP2P_ARES * 100) + 1);
++ break;
++#ifdef IPP2P_DEBUG_ARES
++ default:
++ printk(KERN_DEBUG "Unknown Ares command %x recognized, len: %u \n", (unsigned int) payload[2],plen);
++#endif /* IPP2P_DEBUG_ARES */
++ }
++ }
++
++#if 0
++ /* found connect packet: 03 00 5a 04 03 05 */
++ /* new version ares 1.8: 03 00 5a xx xx 05 */
++ if ((plen) == 6){ /* possible connect command*/
++ if ((payload[0] == 0x03) && (payload[1] == 0x00) && (payload[2] == 0x5a) && (payload[5] == 0x05))
++ return ((IPP2P_ARES * 100) + 1);
++ }
++ if ((plen) == 60){ /* possible download command*/
++ if ((payload[59] == 0x0a) && (payload[58] == 0x0a)){
++ if (memcmp(t, "PUSH SHA1:", 10) == 0) /* found download command */
++ return ((IPP2P_ARES * 100) + 2);
++ }
++ }
++#endif
++
++ return 0;
++} /*search_ares*/
++
++/*Search for SoulSeek commands*/
++int
++search_soul (const unsigned char *payload, const u16 plen)
++{
++//#define IPP2P_DEBUG_SOUL
++ /* match: xx xx xx xx | xx = sizeof(payload) - 4 */
++ if (get_u32(payload, 0) == (plen - 4)){
++ const __u32 m=get_u32(payload, 4);
++ /* match 00 yy yy 00, yy can be everything */
++ if ( get_u8(payload, 4) == 0x00 && get_u8(payload, 7) == 0x00 )
++ {
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "0: Soulseek command 0x%x recognized\n",get_u32(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 1);
++ }
++
++ /* next match: 01 yy 00 00 | yy can be everything */
++ if ( get_u8(payload, 4) == 0x01 && get_u16(payload, 6) == 0x0000 )
++ {
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "1: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 2);
++ }
++
++ /* other soulseek commandos are: 1-5,7,9,13-18,22,23,26,28,35-37,40-46,50,51,60,62-69,91,92,1001 */
++ /* try to do this in an intelligent way */
++ /* get all small commandos */
++ switch(m)
++ {
++ case 7:
++ case 9:
++ case 22:
++ case 23:
++ case 26:
++ case 28:
++ case 50:
++ case 51:
++ case 60:
++ case 91:
++ case 92:
++ case 1001:
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "2: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 3);
++ }
++
++ if (m > 0 && m < 6 )
++ {
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "3: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 4);
++ }
++ if (m > 12 && m < 19 )
++ {
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "4: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 5);
++ }
++
++ if (m > 34 && m < 38 )
++ {
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "5: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 6);
++ }
++
++ if (m > 39 && m < 47 )
++ {
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "6: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 7);
++ }
++
++ if (m > 61 && m < 70 )
++ {
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "7: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 8);
++ }
++
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "unknown SOULSEEK command: 0x%x, first 16 bit: 0x%x, first 8 bit: 0x%x ,soulseek ???\n",get_u32(payload, 4),get_u16(payload, 4) >> 16,get_u8(payload, 4) >> 24);
++#endif /* IPP2P_DEBUG_SOUL */
++ }
++
++ /* match 14 00 00 00 01 yy 00 00 00 STRING(YY) 01 00 00 00 00 46|50 00 00 00 00 */
++ /* without size at the beginning !!! */
++ if ( get_u32(payload, 0) == 0x14 && get_u8(payload, 4) == 0x01 )
++ {
++ __u32 y=get_u32(payload, 5);
++ /* we need 19 chars + string */
++ if ( (y + 19) <= (plen) )
++ {
++ const unsigned char *w=payload+9+y;
++ if (get_u32(w, 0) == 0x01 && ( get_u16(w, 4) == 0x4600 || get_u16(w, 4) == 0x5000) && get_u32(w, 6) == 0x00);
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "Soulssek special client command recognized\n");
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 9);
++ }
++ }
++ return 0;
++}
++
++
++/*Search for WinMX commands*/
++int
++search_winmx (const unsigned char *payload, const u16 plen)
++{
++//#define IPP2P_DEBUG_WINMX
++ if (((plen) == 4) && (memcmp(payload, "SEND", 4) == 0)) return ((IPP2P_WINMX * 100) + 1);
++ if (((plen) == 3) && (memcmp(payload, "GET", 3) == 0)) return ((IPP2P_WINMX * 100) + 2);
++ //if (packet_len < (head_len + 10)) return 0;
++ if (plen < 10) return 0;
++
++ if ((memcmp(payload, "SEND", 4) == 0) || (memcmp(payload, "GET", 3) == 0)){
++ u16 c=4;
++ const u16 end=plen-2;
++ u8 count=0;
++ while (c < end)
++ {
++ if (payload[c]== 0x20 && payload[c+1] == 0x22)
++ {
++ c++;
++ count++;
++ if (count>=2) return ((IPP2P_WINMX * 100) + 3);
++ }
++ c++;
++ }
++ }
++
++ if ( plen == 149 && payload[0] == '8' )
++ {
++#ifdef IPP2P_DEBUG_WINMX
++ printk(KERN_INFO "maybe WinMX\n");
++#endif
++ if (get_u32(payload,17) == 0 && get_u32(payload,21) == 0 && get_u32(payload,25) == 0 &&
++// get_u32(payload,33) == __constant_htonl(0x71182b1a) && get_u32(payload,37) == __constant_htonl(0x05050000) &&
++// get_u32(payload,133) == __constant_htonl(0x31097edf) && get_u32(payload,145) == __constant_htonl(0xdcb8f792))
++ get_u16(payload,39) == 0 && get_u16(payload,135) == __constant_htons(0x7edf) && get_u16(payload,147) == __constant_htons(0xf792))
++
++ {
++#ifdef IPP2P_DEBUG_WINMX
++ printk(KERN_INFO "got WinMX\n");
++#endif
++ return ((IPP2P_WINMX * 100) + 4);
++ }
++ }
++ return 0;
++} /*search_winmx*/
++
++
++/*Search for appleJuice commands*/
++int
++search_apple (const unsigned char *payload, const u16 plen)
++{
++ if ( (plen > 7) && (payload[6] == 0x0d) && (payload[7] == 0x0a) && (memcmp(payload, "ajprot", 6) == 0)) return (IPP2P_APPLE * 100);
++
++ return 0;
++}
++
++
++/*Search for BitTorrent commands*/
++int
++search_bittorrent (const unsigned char *payload, const u16 plen)
++{
++ if (plen > 20)
++ {
++ /* test for match 0x13+"BitTorrent protocol" */
++ if (payload[0] == 0x13)
++ {
++ if (memcmp(payload+1, "BitTorrent protocol", 19) == 0) return (IPP2P_BIT * 100);
++ }
++
++ /* get tracker commandos, all starts with GET /
++ * then it can follow: scrape| announce
++ * and then ?hash_info=
++ */
++ if (memcmp(payload,"GET /",5) == 0)
++ {
++ /* message scrape */
++ if ( memcmp(payload+5,"scrape?info_hash=",17)==0 ) return (IPP2P_BIT * 100 + 1);
++ /* message announce */
++ if ( memcmp(payload+5,"announce?info_hash=",19)==0 ) return (IPP2P_BIT * 100 + 2);
++ }
++ }
++ else
++ {
++ /* bitcomet encryptes the first packet, so we have to detect another
++ * one later in the flow */
++ /* first try failed, too many missdetections */
++ //if ( size == 5 && get_u32(t,0) == __constant_htonl(1) && t[4] < 3) return (IPP2P_BIT * 100 + 3);
++
++ /* second try: block request packets */
++ if ( plen == 17 && get_u32(payload,0) == __constant_htonl(0x0d) && payload[4] == 0x06 && get_u32(payload,13) == __constant_htonl(0x4000) ) return (IPP2P_BIT * 100 + 3);
++ }
++
++ return 0;
++}
++
++
++
++/*check for Kazaa get command*/
++int
++search_kazaa (const unsigned char *payload, const u16 plen)
++
++{
++ if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a) && memcmp(payload, "GET /.hash=", 11) == 0)
++ return (IPP2P_DATA_KAZAA * 100);
++
++ return 0;
++}
++
++
++/*check for gnutella get command*/
++int
++search_gnu (const unsigned char *payload, const u16 plen)
++{
++ if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a))
++ {
++ if (memcmp(payload, "GET /get/", 9) == 0) return ((IPP2P_DATA_GNU * 100) + 1);
++ if (memcmp(payload, "GET /uri-res/", 13) == 0) return ((IPP2P_DATA_GNU * 100) + 2);
++ }
++ return 0;
++}
++
++
++/*check for gnutella get commands and other typical data*/
++int
++search_all_gnu (const unsigned char *payload, const u16 plen)
++{
++
++ if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a))
++ {
++
++ if (memcmp(payload, "GNUTELLA CONNECT/", 17) == 0) return ((IPP2P_GNU * 100) + 1);
++ if (memcmp(payload, "GNUTELLA/", 9) == 0) return ((IPP2P_GNU * 100) + 2);
++
++
++ if ((memcmp(payload, "GET /get/", 9) == 0) || (memcmp(payload, "GET /uri-res/", 13) == 0))
++ {
++ u16 c=8;
++ const u16 end=plen-22;
++ while (c < end) {
++ if ( payload[c] == 0x0a && payload[c+1] == 0x0d && ((memcmp(&payload[c+2], "X-Gnutella-", 11) == 0) || (memcmp(&payload[c+2], "X-Queue:", 8) == 0)))
++ return ((IPP2P_GNU * 100) + 3);
++ c++;
++ }
++ }
++ }
++ return 0;
++}
++
++
++/*check for KaZaA download commands and other typical data*/
++int
++search_all_kazaa (const unsigned char *payload, const u16 plen)
++{
++ if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a))
++ {
++
++ if (memcmp(payload, "GIVE ", 5) == 0) return ((IPP2P_KAZAA * 100) + 1);
++
++ if (memcmp(payload, "GET /", 5) == 0) {
++ u16 c = 8;
++ const u16 end=plen-22;
++ while (c < end) {
++ if ( payload[c] == 0x0a && payload[c+1] == 0x0d && ((memcmp(&payload[c+2], "X-Kazaa-Username: ", 18) == 0) || (memcmp(&payload[c+2], "User-Agent: PeerEnabler/", 24) == 0)))
++ return ((IPP2P_KAZAA * 100) + 2);
++ c++;
++ }
++ }
++ }
++ return 0;
++}
++
++/*fast check for edonkey file segment transfer command*/
++int
++search_edk (const unsigned char *payload, const u16 plen)
++{
++ if (payload[0] != 0xe3)
++ return 0;
++ else {
++ if (payload[5] == 0x47)
++ return (IPP2P_DATA_EDK * 100);
++ else
++ return 0;
++ }
++}
++
++
++
++/*intensive but slower search for some edonkey packets including size-check*/
++int
++search_all_edk (const unsigned char *payload, const u16 plen)
++{
++ if (payload[0] != 0xe3)
++ return 0;
++ else {
++ //t += head_len;
++ const u16 cmd = get_u16(payload, 1);
++ if (cmd == (plen - 5)) {
++ switch (payload[5]) {
++ case 0x01: return ((IPP2P_EDK * 100) + 1); /*Client: hello or Server:hello*/
++ case 0x4c: return ((IPP2P_EDK * 100) + 9); /*Client: Hello-Answer*/
++ }
++ }
++ return 0;
++ }
++}
++
++
++/*fast check for Direct Connect send command*/
++int
++search_dc (const unsigned char *payload, const u16 plen)
++{
++
++ if (payload[0] != 0x24 )
++ return 0;
++ else {
++ if (memcmp(&payload[1], "Send|", 5) == 0)
++ return (IPP2P_DATA_DC * 100);
++ else
++ return 0;
++ }
++
++}
++
++
++/*intensive but slower check for all direct connect packets*/
++int
++search_all_dc (const unsigned char *payload, const u16 plen)
++{
++// unsigned char *t = haystack;
++
++ if (payload[0] == 0x24 && payload[plen-1] == 0x7c)
++ {
++ const unsigned char *t=&payload[1];
++ /* Client-Hub-Protocol */
++ if (memcmp(t, "Lock ", 5) == 0) return ((IPP2P_DC * 100) + 1);
++ /* Client-Client-Protocol, some are already recognized by client-hub (like lock) */
++ if (memcmp(t, "MyNick ", 7) == 0) return ((IPP2P_DC * 100) + 38);
++ }
++ return 0;
++}
++
++/*check for mute*/
++int
++search_mute (const unsigned char *payload, const u16 plen)
++{
++ if ( plen == 209 || plen == 345 || plen == 473 || plen == 609 || plen == 1121 )
++ {
++ //printk(KERN_DEBUG "size hit: %u",size);
++ if (memcmp(payload,"PublicKey: ",11) == 0 )
++ {
++ return ((IPP2P_MUTE * 100) + 0);
++
++/* if (memcmp(t+size-14,"\x0aEndPublicKey\x0a",14) == 0)
++ {
++ printk(KERN_DEBUG "end pubic key hit: %u",size);
++
++ }*/
++ }
++ }
++ return 0;
++}
++
++
++/* check for xdcc */
++int
++search_xdcc (const unsigned char *payload, const u16 plen)
++{
++ /* search in small packets only */
++ if (plen > 20 && plen < 200 && payload[plen-1] == 0x0a && payload[plen-2] == 0x0d && memcmp(payload,"PRIVMSG ",8) == 0)
++ {
++
++ u16 x=10;
++ const u16 end=plen - 13;
++
++ /* is seems to be a irc private massage, chedck for xdcc command */
++ while (x < end)
++ {
++ if (payload[x] == ':')
++ {
++ if ( memcmp(&payload[x+1],"xdcc send #",11) == 0 )
++ return ((IPP2P_XDCC * 100) + 0);
++ }
++ x++;
++ }
++ }
++ return 0;
++}
++
++/* search for waste */
++int search_waste(const unsigned char *payload, const u16 plen)
++{
++ if ( plen >= 8 && memcmp(payload,"GET.sha1:",9) == 0)
++ return ((IPP2P_WASTE * 100) + 0);
++
++ return 0;
++}
++
++
++static struct {
++ int command;
++ __u8 short_hand; /*for fucntions included in short hands*/
++ int packet_len;
++ int (*function_name) (const unsigned char *, const u16);
++} matchlist[] = {
++ {IPP2P_EDK,SHORT_HAND_IPP2P,20, &search_all_edk},
++// {IPP2P_DATA_KAZAA,SHORT_HAND_DATA,200, &search_kazaa},
++// {IPP2P_DATA_EDK,SHORT_HAND_DATA,60, &search_edk},
++// {IPP2P_DATA_DC,SHORT_HAND_DATA,26, &search_dc},
++ {IPP2P_DC,SHORT_HAND_IPP2P,5, search_all_dc},
++// {IPP2P_DATA_GNU,SHORT_HAND_DATA,40, &search_gnu},
++ {IPP2P_GNU,SHORT_HAND_IPP2P,5, &search_all_gnu},
++ {IPP2P_KAZAA,SHORT_HAND_IPP2P,5, &search_all_kazaa},
++ {IPP2P_BIT,SHORT_HAND_IPP2P,20, &search_bittorrent},
++ {IPP2P_APPLE,SHORT_HAND_IPP2P,5, &search_apple},
++ {IPP2P_SOUL,SHORT_HAND_IPP2P,5, &search_soul},
++ {IPP2P_WINMX,SHORT_HAND_IPP2P,2, &search_winmx},
++ {IPP2P_ARES,SHORT_HAND_IPP2P,5, &search_ares},
++ {IPP2P_MUTE,SHORT_HAND_NONE,200, &search_mute},
++ {IPP2P_WASTE,SHORT_HAND_NONE,5, &search_waste},
++ {IPP2P_XDCC,SHORT_HAND_NONE,5, &search_xdcc},
++ {0,0,0,NULL}
++};
++
++
++static struct {
++ int command;
++ __u8 short_hand; /*for fucntions included in short hands*/
++ int packet_len;
++ int (*function_name) (unsigned char *, int);
++} udp_list[] = {
++ {IPP2P_KAZAA,SHORT_HAND_IPP2P,14, &udp_search_kazaa},
++ {IPP2P_BIT,SHORT_HAND_IPP2P,23, &udp_search_bit},
++ {IPP2P_GNU,SHORT_HAND_IPP2P,11, &udp_search_gnu},
++ {IPP2P_EDK,SHORT_HAND_IPP2P,9, &udp_search_edk},
++ {IPP2P_DC,SHORT_HAND_IPP2P,12, &udp_search_directconnect},
++ {0,0,0,NULL}
++};
++
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++ const void *hdr,
++ u_int16_t datalen,
++#endif
++
++ int *hotdrop)
++{
++ const struct ipt_p2p_info *info = matchinfo;
++ unsigned char *haystack;
++ struct iphdr *ip = skb->nh.iph;
++ int p2p_result = 0, i = 0;
++// int head_len;
++ int hlen = ntohs(ip->tot_len)-(ip->ihl*4); /*hlen = packet-data length*/
++
++ /*must not be a fragment*/
++ if (offset) {
++ if (info->debug) printk("IPP2P.match: offset found %i \n",offset);
++ return 0;
++ }
++
++ /*make sure that skb is linear*/
++ if(skb_is_nonlinear(skb)){
++ if (info->debug) printk("IPP2P.match: nonlinear skb found\n");
++ return 0;
++ }
++
++
++ haystack=(char *)ip+(ip->ihl*4); /*haystack = packet data*/
++
++ switch (ip->protocol){
++ case IPPROTO_TCP: /*what to do with a TCP packet*/
++ {
++ struct tcphdr *tcph = (void *) ip + ip->ihl * 4;
++
++ if (tcph->fin) return 0; /*if FIN bit is set bail out*/
++ if (tcph->syn) return 0; /*if SYN bit is set bail out*/
++ if (tcph->rst) return 0; /*if RST bit is set bail out*/
++
++ haystack += tcph->doff * 4; /*get TCP-Header-Size*/
++ hlen -= tcph->doff * 4;
++ while (matchlist[i].command) {
++ if ((((info->cmd & matchlist[i].command) == matchlist[i].command) ||
++ ((info->cmd & matchlist[i].short_hand) == matchlist[i].short_hand)) &&
++ (hlen > matchlist[i].packet_len)) {
++ p2p_result = matchlist[i].function_name(haystack, hlen);
++ if (p2p_result)
++ {
++ if (info->debug) printk("IPP2P.debug:TCP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
++ p2p_result, NIPQUAD(ip->saddr),ntohs(tcph->source), NIPQUAD(ip->daddr),ntohs(tcph->dest),hlen);
++ return p2p_result;
++ }
++ }
++ i++;
++ }
++ return p2p_result;
++ }
++
++ case IPPROTO_UDP: /*what to do with an UDP packet*/
++ {
++ struct udphdr *udph = (void *) ip + ip->ihl * 4;
++
++ while (udp_list[i].command){
++ if ((((info->cmd & udp_list[i].command) == udp_list[i].command) ||
++ ((info->cmd & udp_list[i].short_hand) == udp_list[i].short_hand)) &&
++ (hlen > udp_list[i].packet_len)) {
++ p2p_result = udp_list[i].function_name(haystack, hlen);
++ if (p2p_result){
++ if (info->debug) printk("IPP2P.debug:UDP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
++ p2p_result, NIPQUAD(ip->saddr),ntohs(udph->source), NIPQUAD(ip->daddr),ntohs(udph->dest),hlen);
++ return p2p_result;
++ }
++ }
++ i++;
++ }
++ return p2p_result;
++ }
++
++ default: return 0;
++ }
++}
++
++
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ /* Must specify -p tcp */
++/* if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) {
++ * printk("ipp2p: Only works on TCP packets, use -p tcp\n");
++ * return 0;
++ * }*/
++ return 1;
++}
++
++
++
++
++static struct ipt_match ipp2p_match = {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++ { NULL, NULL },
++ "ipp2p",
++ &match,
++ &checkentry,
++ NULL,
++ THIS_MODULE
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
++ .name = "ipp2p",
++ .match = &match,
++ .checkentry = &checkentry,
++ .me = THIS_MODULE,
++#endif
++};
++
++
++static int __init init(void)
++{
++ printk(KERN_INFO "IPP2P v%s loading\n", IPP2P_VERSION);
++ return ipt_register_match(&ipp2p_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&ipp2p_match);
++ printk(KERN_INFO "IPP2P v%s unloaded\n", IPP2P_VERSION);
++}
++
++module_init(init);
++module_exit(fini);
++
++
diff --git a/target/linux/generic-2.4/patches/602-netfilter_layer7_2.1nbd.patch b/target/linux/generic-2.4/patches/602-netfilter_layer7_2.1nbd.patch
new file mode 100644
index 0000000..d67725d
--- /dev/null
+++ b/target/linux/generic-2.4/patches/602-netfilter_layer7_2.1nbd.patch
@@ -0,0 +1,2083 @@
+diff -urN linux.old/Documentation/Configure.help linux.dev/Documentation/Configure.help
+--- linux.old/Documentation/Configure.help 2006-01-31 16:55:22.467939000 +0100
++++ linux.dev/Documentation/Configure.help 2006-01-31 16:58:24.751331500 +0100
+@@ -29151,6 +29151,18 @@
+
+ If unsure, say N.
+
++CONFIG_IP_NF_MATCH_LAYER7
++ Say Y if you want to be able to classify connections (and their
++ packets) based on regular expression matching of their application
++ layer data. This is one way to classify applications such as
++ peer-to-peer filesharing systems that do not always use the same
++ port.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
++CONFIG_IP_NF_MATCH_LAYER7_DEBUG
++ Say Y to get lots of debugging output.
++
+ #
+ # A couple of things I keep forgetting:
+ # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet,
+diff -urN linux.old/include/linux/netfilter_ipv4/ip_conntrack.h linux.dev/include/linux/netfilter_ipv4/ip_conntrack.h
+--- linux.old/include/linux/netfilter_ipv4/ip_conntrack.h 2005-11-16 20:12:54.000000000 +0100
++++ linux.dev/include/linux/netfilter_ipv4/ip_conntrack.h 2006-01-31 16:58:24.775333000 +0100
+@@ -207,6 +207,17 @@
+ } nat;
+ #endif /* CONFIG_IP_NF_NAT_NEEDED */
+
++#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE)
++ struct {
++ unsigned int numpackets; /* surely this is kept track of somewhere else, right? I can't find it... */
++ char * app_proto; /* "http", "ftp", etc. NULL if unclassifed */
++
++ /* the application layer data so far. NULL if ->numpackets > numpackets */
++ char * app_data;
++
++ unsigned int app_data_len;
++ } layer7;
++#endif
+ };
+
+ /* get master conntrack via master expectation */
+diff -urN linux.old/include/linux/netfilter_ipv4/ipt_layer7.h linux.dev/include/linux/netfilter_ipv4/ipt_layer7.h
+--- linux.old/include/linux/netfilter_ipv4/ipt_layer7.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/linux/netfilter_ipv4/ipt_layer7.h 2006-01-31 19:29:03.774017500 +0100
+@@ -0,0 +1,27 @@
++/*
++ By Matthew Strait <quadong@users.sf.net>, Dec 2003.
++ http://l7-filter.sf.net
++
++ 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.
++ http://www.gnu.org/licenses/gpl.txt
++*/
++
++#ifndef _IPT_LAYER7_H
++#define _IPT_LAYER7_H
++
++#define MAX_PATTERN_LEN 8192
++#define MAX_PROTOCOL_LEN 256
++
++typedef char *(*proc_ipt_search) (char *, char, char *);
++
++struct ipt_layer7_info {
++ char protocol[MAX_PROTOCOL_LEN];
++ char invert:1;
++ char pattern[MAX_PATTERN_LEN];
++ char pkt;
++};
++
++#endif /* _IPT_LAYER7_H */
+diff -urN linux.old/net/ipv4/netfilter/Config.in linux.dev/net/ipv4/netfilter/Config.in
+--- linux.old/net/ipv4/netfilter/Config.in 2006-01-31 16:55:32.364558000 +0100
++++ linux.dev/net/ipv4/netfilter/Config.in 2006-01-31 16:58:24.803334750 +0100
+@@ -44,6 +44,9 @@
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' Owner match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OWNER $CONFIG_IP_NF_IPTABLES
++ dep_tristate ' Layer 7 match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_LAYER7 $CONFIG_IP_NF_CONNTRACK
++ dep_mbool ' Layer 7 debugging output (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_LAYER7_DEBUG $CONFIG_IP_NF_MATCH_LAYER7
++
+ fi
+ # The targets
+ dep_tristate ' Packet filtering' CONFIG_IP_NF_FILTER $CONFIG_IP_NF_IPTABLES
+diff -urN linux.old/net/ipv4/netfilter/Makefile linux.dev/net/ipv4/netfilter/Makefile
+--- linux.old/net/ipv4/netfilter/Makefile 2006-01-31 16:55:32.372558000 +0100
++++ linux.dev/net/ipv4/netfilter/Makefile 2006-01-31 16:58:24.803334750 +0100
+@@ -87,6 +87,7 @@
+ obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
+ obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
+ obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
++obj-$(CONFIG_IP_NF_MATCH_LAYER7) += ipt_layer7.o
+
+ # targets
+ obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
+diff -urN linux.old/net/ipv4/netfilter/ip_conntrack_core.c linux.dev/net/ipv4/netfilter/ip_conntrack_core.c
+--- linux.old/net/ipv4/netfilter/ip_conntrack_core.c 2005-04-04 03:42:20.000000000 +0200
++++ linux.dev/net/ipv4/netfilter/ip_conntrack_core.c 2006-01-31 16:58:24.811335250 +0100
+@@ -346,6 +346,14 @@
+ }
+ kfree(ct->master);
+ }
++
++ #if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE)
++ if(ct->layer7.app_proto)
++ kfree(ct->layer7.app_proto);
++ if(ct->layer7.app_data)
++ kfree(ct->layer7.app_data);
++ #endif
++
+ WRITE_UNLOCK(&ip_conntrack_lock);
+
+ if (master)
+diff -urN linux.old/net/ipv4/netfilter/ip_conntrack_standalone.c linux.dev/net/ipv4/netfilter/ip_conntrack_standalone.c
+--- linux.old/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-04-04 03:42:20.000000000 +0200
++++ linux.dev/net/ipv4/netfilter/ip_conntrack_standalone.c 2006-01-31 16:58:24.815335500 +0100
+@@ -107,6 +107,13 @@
+ len += sprintf(buffer + len, "[ASSURED] ");
+ len += sprintf(buffer + len, "use=%u ",
+ atomic_read(&conntrack->ct_general.use));
++
++ #if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE)
++ if(conntrack->layer7.app_proto)
++ len += sprintf(buffer + len, "l7proto=%s ",
++ conntrack->layer7.app_proto);
++ #endif
++
+ len += sprintf(buffer + len, "\n");
+
+ return len;
+diff -urN linux.old/net/ipv4/netfilter/ipt_layer7.c linux.dev/net/ipv4/netfilter/ipt_layer7.c
+--- linux.old/net/ipv4/netfilter/ipt_layer7.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/net/ipv4/netfilter/ipt_layer7.c 2006-01-31 19:31:38.591693000 +0100
+@@ -0,0 +1,595 @@
++/*
++ Kernel module to match application layer (OSI layer 7)
++ data in connections.
++
++ http://l7-filter.sf.net
++
++ By Matthew Strait and Ethan Sommer, 2003-2005.
++
++ 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.
++ http://www.gnu.org/licenses/gpl.txt
++
++ Based on ipt_string.c (C) 2000 Emmanuel Roger <winfield@freegates.be>
++ and cls_layer7.c (C) 2003 Matthew Strait, Ethan Sommer, Justin Levandoski
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/proc_fs.h>
++#include <linux/ctype.h>
++#include <net/ip.h>
++#include <net/tcp.h>
++#include <linux/netfilter_ipv4/lockhelp.h>
++
++#include "regexp/regexp.c"
++
++#include <linux/netfilter_ipv4/ipt_layer7.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++MODULE_AUTHOR("Matthew Strait <quadong@users.sf.net>, Ethan Sommer <sommere@users.sf.net>");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("iptables application layer match module");
++
++static int maxdatalen = 2048; // this is the default
++MODULE_PARM(maxdatalen,"i");
++MODULE_PARM_DESC(maxdatalen,"maximum bytes of data looked at by l7-filter");
++
++#if defined(CONFIG_IP_NF_MATCH_LAYER7_DEBUG)
++ #define DPRINTK(format,args...) printk(format,##args)
++#else
++ #define DPRINTK(format,args...)
++#endif
++
++#define TOTAL_PACKETS master_conntrack->layer7.numpackets
++
++/* Number of packets whose data we look at.
++This can be modified through /proc/net/layer7_numpackets */
++static int num_packets = 10;
++
++static struct pattern_cache {
++ char * regex_string;
++ regexp * pattern;
++ struct pattern_cache * next;
++} * first_pattern_cache = NULL;
++
++/* I'm new to locking. Here are my assumptions:
++
++- No one will write to /proc/net/layer7_numpackets over and over very fast;
++ if they did, nothing awful would happen.
++
++- This code will never be processing the same packet twice at the same time,
++ because iptables rules are traversed in order.
++
++- It doesn't matter if two packets from different connections are in here at
++ the same time, because they don't share any data.
++
++- It _does_ matter if two packets from the same connection are here at the same
++ time. In this case, we have to protect the conntracks and the list of
++ compiled patterns.
++*/
++DECLARE_RWLOCK(ct_lock);
++DECLARE_LOCK(list_lock);
++
++#if CONFIG_IP_NF_MATCH_LAYER7_DEBUG
++/* Converts an unfriendly string into a friendly one by
++replacing unprintables with periods and all whitespace with " ". */
++static char * friendly_print(unsigned char * s)
++{
++ char * f = kmalloc(strlen(s) + 1, GFP_ATOMIC);
++ int i;
++
++ if(!f) {
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in friendly_print, bailing.\n");
++ return NULL;
++ }
++
++ for(i = 0; i < strlen(s); i++){
++ if(isprint(s[i]) && s[i] < 128) f[i] = s[i];
++ else if(isspace(s[i])) f[i] = ' ';
++ else f[i] = '.';
++ }
++ f[i] = '\0';
++ return f;
++}
++
++static char dec2hex(int i)
++{
++ switch (i) {
++ case 0 ... 9:
++ return (char)(i + '0');
++ break;
++ case 10 ... 15:
++ return (char)(i - 10 + 'a');
++ break;
++ default:
++ if (net_ratelimit())
++ printk("Problem in dec2hex\n");
++ return '\0';
++ }
++}
++
++static char * hex_print(unsigned char * s)
++{
++ char * g = kmalloc(strlen(s)*3 + 1, GFP_ATOMIC);
++ int i;
++
++ if(!g) {
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in hex_print, bailing.\n");
++ return NULL;
++ }
++
++ for(i = 0; i < strlen(s); i++) {
++ g[i*3 ] = dec2hex(s[i]/16);
++ g[i*3 + 1] = dec2hex(s[i]%16);
++ g[i*3 + 2] = ' ';
++ }
++ g[i*3] = '\0';
++
++ return g;
++}
++#endif // DEBUG
++
++/* Use instead of regcomp. As we expect to be seeing the same regexps over and
++over again, it make sense to cache the results. */
++static regexp * compile_and_cache(char * regex_string, char * protocol)
++{
++ struct pattern_cache * node = first_pattern_cache;
++ struct pattern_cache * last_pattern_cache = first_pattern_cache;
++ struct pattern_cache * tmp;
++ unsigned int len;
++
++ while (node != NULL) {
++ if (!strcmp(node->regex_string, regex_string))
++ return node->pattern;
++
++ last_pattern_cache = node;/* points at the last non-NULL node */
++ node = node->next;
++ }
++
++ /* If we reach the end of the list, then we have not yet cached
++ the pattern for this regex. Let's do that now.
++ Be paranoid about running out of memory to avoid list corruption. */
++ tmp = kmalloc(sizeof(struct pattern_cache), GFP_ATOMIC);
++
++ if(!tmp) {
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n");
++ return NULL;
++ }
++
++ tmp->regex_string = kmalloc(strlen(regex_string) + 1, GFP_ATOMIC);
++ tmp->pattern = kmalloc(sizeof(struct regexp), GFP_ATOMIC);
++ tmp->next = NULL;
++
++ if(!tmp->regex_string || !tmp->pattern) {
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n");
++ kfree(tmp->regex_string);
++ kfree(tmp->pattern);
++ kfree(tmp);
++ return NULL;
++ }
++
++ /* Ok. The new node is all ready now. */
++ node = tmp;
++
++ if(first_pattern_cache == NULL) /* list is empty */
++ first_pattern_cache = node; /* make node the beginning */
++ else
++ last_pattern_cache->next = node; /* attach node to the end */
++
++ /* copy the string and compile the regex */
++ len = strlen(regex_string);
++ DPRINTK("About to compile this: \"%s\"\n", regex_string);
++ node->pattern = regcomp(regex_string, &len);
++ if ( !node->pattern ) {
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: Error compiling regexp \"%s\" (%s)\n", regex_string, protocol);
++ /* pattern is now cached as NULL, so we won't try again. */
++ }
++
++ strcpy(node->regex_string, regex_string);
++ return node->pattern;
++}
++
++static int can_handle(const struct sk_buff *skb)
++{
++ if(!skb->nh.iph) /* not IP */
++ return 0;
++ if(skb->nh.iph->protocol != IPPROTO_TCP &&
++ skb->nh.iph->protocol != IPPROTO_UDP &&
++ skb->nh.iph->protocol != IPPROTO_ICMP)
++ return 0;
++ return 1;
++}
++
++/* Returns offset the into the skb->data that the application data starts */
++static int app_data_offset(const struct sk_buff *skb)
++{
++ /* In case we are ported somewhere (ebtables?) where skb->nh.iph
++ isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */
++ int ip_hl = 4*skb->nh.iph->ihl;
++
++ if( skb->nh.iph->protocol == IPPROTO_TCP ) {
++ /* 12 == offset into TCP header for the header length field.
++ Can't get this with skb->h.th->doff because the tcphdr
++ struct doesn't get set when routing (this is confirmed to be
++ true in Netfilter as well as QoS.) */
++ int tcp_hl = 4*(skb->data[ip_hl + 12] >> 4);
++
++ return ip_hl + tcp_hl;
++ } else if( skb->nh.iph->protocol == IPPROTO_UDP ) {
++ return ip_hl + 8; /* UDP header is always 8 bytes */
++ } else if( skb->nh.iph->protocol == IPPROTO_ICMP ) {
++ return ip_hl + 8; /* ICMP header is 8 bytes */
++ } else {
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: tried to handle unknown protocol!\n");
++ return ip_hl + 8; /* something reasonable */
++ }
++}
++
++/* handles whether there's a match when we aren't appending data anymore */
++static int match_no_append(struct ip_conntrack * conntrack, struct ip_conntrack * master_conntrack,
++ enum ip_conntrack_info ctinfo, enum ip_conntrack_info master_ctinfo,
++ struct ipt_layer7_info * info)
++{
++ /* If we're in here, throw the app data away */
++ WRITE_LOCK(&ct_lock);
++ if(master_conntrack->layer7.app_data != NULL) {
++
++ #ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG
++ if(!master_conntrack->layer7.app_proto) {
++ char * f = friendly_print(master_conntrack->layer7.app_data);
++ char * g = hex_print(master_conntrack->layer7.app_data);
++ DPRINTK("\nl7-filter gave up after %d bytes (%d packets):\n%s\n",
++ strlen(f),
++ TOTAL_PACKETS, f);
++ kfree(f);
++ DPRINTK("In hex: %s\n", g);
++ kfree(g);
++ }
++ #endif
++
++ kfree(master_conntrack->layer7.app_data);
++ master_conntrack->layer7.app_data = NULL; /* don't free again */
++ }
++ WRITE_UNLOCK(&ct_lock);
++
++ if(master_conntrack->layer7.app_proto){
++ /* Here child connections set their .app_proto (for /proc/net/ip_conntrack) */
++ WRITE_LOCK(&ct_lock);
++ if(!conntrack->layer7.app_proto) {
++ conntrack->layer7.app_proto = kmalloc(strlen(master_conntrack->layer7.app_proto)+1, GFP_ATOMIC);
++ if(!conntrack->layer7.app_proto){
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n");
++ WRITE_UNLOCK(&ct_lock);
++ return 1;
++ }
++ strcpy(conntrack->layer7.app_proto, master_conntrack->layer7.app_proto);
++ }
++ WRITE_UNLOCK(&ct_lock);
++
++ return (!strcmp(master_conntrack->layer7.app_proto, info->protocol));
++ }
++ else {
++ /* If not classified, set to "unknown" to distinguish from
++ connections that are still being tested. */
++ WRITE_LOCK(&ct_lock);
++ master_conntrack->layer7.app_proto = kmalloc(strlen("unknown")+1, GFP_ATOMIC);
++ if(!master_conntrack->layer7.app_proto){
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n");
++ WRITE_UNLOCK(&ct_lock);
++ return 1;
++ }
++ strcpy(master_conntrack->layer7.app_proto, "unknown");
++ WRITE_UNLOCK(&ct_lock);
++ return 0;
++ }
++}
++
++static int add_datastr(char *target, int offset, char *app_data, int len)
++{
++ int length = 0, i;
++
++ /* Strip nulls. Make everything lower case (our regex lib doesn't
++ do case insensitivity). Add it to the end of the current data. */
++ for(i = 0; i < maxdatalen-offset-1 && i < len; i++) {
++ if(app_data[i] != '\0') {
++ target[length+offset] =
++ /* the kernel version of tolower mungs 'upper ascii' */
++ isascii(app_data[i])? tolower(app_data[i]) : app_data[i];
++ length++;
++ }
++ }
++
++ target[length+offset] = '\0';
++
++ return length;
++}
++
++/* add the new app data to the conntrack. Return number of bytes added. */
++static int add_data(struct ip_conntrack * master_conntrack,
++ char * app_data, int appdatalen)
++{
++ int length;
++
++ length = add_datastr(master_conntrack->layer7.app_data, master_conntrack->layer7.app_data_len, app_data, appdatalen);
++ master_conntrack->layer7.app_data_len += length;
++
++ return length;
++}
++
++/* Returns true on match and false otherwise. */
++static int match(/* const */struct sk_buff *skb, const struct net_device *in,
++ const struct net_device *out, const void *matchinfo,
++ int offset, int *hotdrop)
++{
++ struct ipt_layer7_info * info = (struct ipt_layer7_info *)matchinfo;
++ enum ip_conntrack_info master_ctinfo, ctinfo;
++ struct ip_conntrack *master_conntrack, *conntrack;
++ unsigned char *app_data, *tmp_data;
++ unsigned int pattern_result, appdatalen;
++ regexp * comppattern;
++
++ if(!can_handle(skb)){
++ DPRINTK("layer7: This is some protocol I can't handle.\n");
++ return info->invert;
++ }
++
++ /* Treat the parent and all its children together as one connection,
++ except for the purpose of setting conntrack->layer7.app_proto in the
++ actual connection. This makes /proc/net/ip_conntrack somewhat more
++ satisfying. */
++ if(!(conntrack = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) ||
++ !(master_conntrack = ip_conntrack_get((struct sk_buff *)skb, &master_ctinfo))) {
++ DPRINTK("layer7: packet is not from a known connection, giving up.\n");
++ return info->invert;
++ }
++
++ /* Try to get a master conntrack (and its master etc) for FTP, etc. */
++ while (master_ct(master_conntrack) != NULL)
++ master_conntrack = master_ct(master_conntrack);
++
++ if(!skb->cb[0]){
++ WRITE_LOCK(&ct_lock);
++ master_conntrack->layer7.numpackets++;/*starts at 0 via memset*/
++ WRITE_UNLOCK(&ct_lock);
++ }
++
++ /* if we've classified it or seen too many packets */
++ if(!info->pkt && (TOTAL_PACKETS > num_packets ||
++ master_conntrack->layer7.app_proto)) {
++
++ pattern_result = match_no_append(conntrack, master_conntrack, ctinfo, master_ctinfo, info);
++
++ /* skb->cb[0] == seen. Avoid doing things twice if there are two l7
++ rules. I'm not sure that using cb for this purpose is correct, although
++ it says "put your private variables there". But it doesn't look like it
++ is being used for anything else in the skbs that make it here. How can
++ I write to cb without making the compiler angry? */
++ skb->cb[0] = 1; /* marking it seen here is probably irrelevant, but consistant */
++
++ return (pattern_result ^ info->invert);
++ }
++
++ if(skb_is_nonlinear(skb)){
++ if(skb_linearize(skb, GFP_ATOMIC) != 0){
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: failed to linearize packet, bailing.\n");
++ return info->invert;
++ }
++ }
++
++ /* now that the skb is linearized, it's safe to set these. */
++ app_data = skb->data + app_data_offset(skb);
++ appdatalen = skb->tail - app_data;
++
++ LOCK_BH(&list_lock);
++ /* the return value gets checked later, when we're ready to use it */
++ comppattern = compile_and_cache(info->pattern, info->protocol);
++ UNLOCK_BH(&list_lock);
++
++ if (info->pkt) {
++ tmp_data = kmalloc(maxdatalen, GFP_ATOMIC);
++ if(!tmp_data){
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in match, bailing.\n");
++ return info->invert;
++ }
++
++ tmp_data[0] = '\0';
++ add_datastr(tmp_data, 0, app_data, appdatalen);
++ pattern_result = ((comppattern && regexec(comppattern, tmp_data)) ? 1 : 0);
++ kfree(tmp_data);
++ tmp_data = NULL;
++
++ return (pattern_result ^ info->invert);
++ }
++
++ /* On the first packet of a connection, allocate space for app data */
++ WRITE_LOCK(&ct_lock);
++ if(TOTAL_PACKETS == 1 && !skb->cb[0] && !master_conntrack->layer7.app_data) {
++ master_conntrack->layer7.app_data = kmalloc(maxdatalen, GFP_ATOMIC);
++ if(!master_conntrack->layer7.app_data){
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in match, bailing.\n");
++ WRITE_UNLOCK(&ct_lock);
++ return info->invert;
++ }
++
++ master_conntrack->layer7.app_data[0] = '\0';
++ }
++ WRITE_UNLOCK(&ct_lock);
++
++ /* Can be here, but unallocated, if numpackets is increased near
++ the beginning of a connection */
++ if(master_conntrack->layer7.app_data == NULL)
++ return (info->invert); /* unmatched */
++
++ if(!skb->cb[0]){
++ int newbytes;
++ WRITE_LOCK(&ct_lock);
++ newbytes = add_data(master_conntrack, app_data, appdatalen);
++ WRITE_UNLOCK(&ct_lock);
++
++ if(newbytes == 0) { /* didn't add any data */
++ skb->cb[0] = 1;
++ /* Didn't match before, not going to match now */
++ return info->invert;
++ }
++ }
++
++ /* If looking for "unknown", then never match. "Unknown" means that
++ we've given up; we're still trying with these packets. */
++ if(!strcmp(info->protocol, "unknown")) {
++ pattern_result = 0;
++ /* If the regexp failed to compile, don't bother running it */
++ } else if(comppattern && regexec(comppattern, master_conntrack->layer7.app_data)) {
++ DPRINTK("layer7: regexec positive: %s!\n", info->protocol);
++ pattern_result = 1;
++ } else pattern_result = 0;
++
++ if(pattern_result) {
++ WRITE_LOCK(&ct_lock);
++ master_conntrack->layer7.app_proto = kmalloc(strlen(info->protocol)+1, GFP_ATOMIC);
++ if(!master_conntrack->layer7.app_proto){
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in match, bailing.\n");
++ WRITE_UNLOCK(&ct_lock);
++ return (pattern_result ^ info->invert);
++ }
++ strcpy(master_conntrack->layer7.app_proto, info->protocol);
++ WRITE_UNLOCK(&ct_lock);
++ }
++
++ /* mark the packet seen */
++ skb->cb[0] = 1;
++
++ return (pattern_result ^ info->invert);
++}
++
++static int checkentry(const char *tablename, const struct ipt_ip *ip,
++ void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
++{
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_layer7_info)))
++ return 0;
++ return 1;
++}
++
++static struct ipt_match layer7_match = {
++ .name = "layer7",
++ .match = &match,
++ .checkentry = &checkentry,
++ .me = THIS_MODULE
++};
++
++/* taken from drivers/video/modedb.c */
++static int my_atoi(const char *s)
++{
++ int val = 0;
++
++ for (;; s++) {
++ switch (*s) {
++ case '0'...'9':
++ val = 10*val+(*s-'0');
++ break;
++ default:
++ return val;
++ }
++ }
++}
++
++/* write out num_packets to userland. */
++static int layer7_read_proc(char* page, char ** start, off_t off, int count,
++ int* eof, void * data)
++{
++ if(num_packets > 99 && net_ratelimit())
++ printk(KERN_ERR "layer7: NOT REACHED. num_packets too big\n");
++
++ page[0] = num_packets/10 + '0';
++ page[1] = num_packets%10 + '0';
++ page[2] = '\n';
++ page[3] = '\0';
++
++ *eof=1;
++
++ return 3;
++}
++
++/* Read in num_packets from userland */
++static int layer7_write_proc(struct file* file, const char* buffer,
++ unsigned long count, void *data)
++{
++ char * foo = kmalloc(count, GFP_ATOMIC);
++
++ if(!foo){
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory, bailing. num_packets unchanged.\n");
++ return count;
++ }
++
++ copy_from_user(foo, buffer, count);
++
++ num_packets = my_atoi(foo);
++ kfree (foo);
++
++ /* This has an arbitrary limit to make the math easier. I'm lazy.
++ But anyway, 99 is a LOT! If you want more, you're doing it wrong! */
++ if(num_packets > 99) {
++ printk(KERN_WARNING "layer7: num_packets can't be > 99.\n");
++ num_packets = 99;
++ } else if(num_packets < 1) {
++ printk(KERN_WARNING "layer7: num_packets can't be < 1.\n");
++ num_packets = 1;
++ }
++
++ return count;
++}
++
++/* register the proc file */
++static void layer7_init_proc(void)
++{
++ struct proc_dir_entry* entry;
++ entry = create_proc_entry("layer7_numpackets", 0644, proc_net);
++ entry->read_proc = layer7_read_proc;
++ entry->write_proc = layer7_write_proc;
++}
++
++static void layer7_cleanup_proc(void)
++{
++ remove_proc_entry("layer7_numpackets", proc_net);
++}
++
++static int __init init(void)
++{
++ layer7_init_proc();
++ if(maxdatalen < 1) {
++ printk(KERN_WARNING "layer7: maxdatalen can't be < 1, using 1\n");
++ maxdatalen = 1;
++ }
++ /* This is not a hard limit. It's just here to prevent people from
++ bringing their slow machines to a grinding halt. */
++ else if(maxdatalen > 65536) {
++ printk(KERN_WARNING "layer7: maxdatalen can't be > 65536, using 65536\n");
++ maxdatalen = 65536;
++ }
++ return ipt_register_match(&layer7_match);
++}
++
++static void __exit fini(void)
++{
++ layer7_cleanup_proc();
++ ipt_unregister_match(&layer7_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -urN linux.old/net/ipv4/netfilter/regexp/regexp.c linux.dev/net/ipv4/netfilter/regexp/regexp.c
+--- linux.old/net/ipv4/netfilter/regexp/regexp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/net/ipv4/netfilter/regexp/regexp.c 2006-01-31 16:58:24.819335750 +0100
+@@ -0,0 +1,1195 @@
++/*
++ * regcomp and regexec -- regsub and regerror are elsewhere
++ * @(#)regexp.c 1.3 of 18 April 87
++ *
++ * Copyright (c) 1986 by University of Toronto.
++ * Written by Henry Spencer. Not derived from licensed software.
++ *
++ * Permission is granted to anyone to use this software for any
++ * purpose on any computer system, and to redistribute it freely,
++ * subject to the following restrictions:
++ *
++ * 1. The author is not responsible for the consequences of use of
++ * this software, no matter how awful, even if they arise
++ * from defects in it.
++ *
++ * 2. The origin of this software must not be misrepresented, either
++ * by explicit claim or by omission.
++ *
++ * 3. Altered versions must be plainly marked as such, and must not
++ * be misrepresented as being the original software.
++ *
++ * Beware that some of this code is subtly aware of the way operator
++ * precedence is structured in regular expressions. Serious changes in
++ * regular-expression syntax might require a total rethink.
++ *
++ * This code was modified by Ethan Sommer to work within the kernel
++ * (it now uses kmalloc etc..)
++ *
++ * Modified slightly by Matthew Strait to use more modern C.
++ */
++
++#include "regexp.h"
++#include "regmagic.h"
++
++/* added by ethan and matt. Lets it work in both kernel and user space.
++(So iptables can use it, for instance.) Yea, it goes both ways... */
++#if __KERNEL__
++ #define malloc(foo) kmalloc(foo,GFP_ATOMIC)
++#else
++ #define printk(format,args...) printf(format,##args)
++#endif
++
++void regerror(char * s)
++{
++ printk("<3>Regexp: %s\n", s);
++ /* NOTREACHED */
++}
++
++/*
++ * The "internal use only" fields in regexp.h are present to pass info from
++ * compile to execute that permits the execute phase to run lots faster on
++ * simple cases. They are:
++ *
++ * regstart char that must begin a match; '\0' if none obvious
++ * reganch is the match anchored (at beginning-of-line only)?
++ * regmust string (pointer into program) that match must include, or NULL
++ * regmlen length of regmust string
++ *
++ * Regstart and reganch permit very fast decisions on suitable starting points
++ * for a match, cutting down the work a lot. Regmust permits fast rejection
++ * of lines that cannot possibly match. The regmust tests are costly enough
++ * that regcomp() supplies a regmust only if the r.e. contains something
++ * potentially expensive (at present, the only such thing detected is * or +
++ * at the start of the r.e., which can involve a lot of backup). Regmlen is
++ * supplied because the test in regexec() needs it and regcomp() is computing
++ * it anyway.
++ */
++
++/*
++ * Structure for regexp "program". This is essentially a linear encoding
++ * of a nondeterministic finite-state machine (aka syntax charts or
++ * "railroad normal form" in parsing technology). Each node is an opcode
++ * plus a "next" pointer, possibly plus an operand. "Next" pointers of
++ * all nodes except BRANCH implement concatenation; a "next" pointer with
++ * a BRANCH on both ends of it is connecting two alternatives. (Here we
++ * have one of the subtle syntax dependencies: an individual BRANCH (as
++ * opposed to a collection of them) is never concatenated with anything
++ * because of operator precedence.) The operand of some types of node is
++ * a literal string; for others, it is a node leading into a sub-FSM. In
++ * particular, the operand of a BRANCH node is the first node of the branch.
++ * (NB this is *not* a tree structure: the tail of the branch connects
++ * to the thing following the set of BRANCHes.) The opcodes are:
++ */
++
++/* definition number opnd? meaning */
++#define END 0 /* no End of program. */
++#define BOL 1 /* no Match "" at beginning of line. */
++#define EOL 2 /* no Match "" at end of line. */
++#define ANY 3 /* no Match any one character. */
++#define ANYOF 4 /* str Match any character in this string. */
++#define ANYBUT 5 /* str Match any character not in this string. */
++#define BRANCH 6 /* node Match this alternative, or the next... */
++#define BACK 7 /* no Match "", "next" ptr points backward. */
++#define EXACTLY 8 /* str Match this string. */
++#define NOTHING 9 /* no Match empty string. */
++#define STAR 10 /* node Match this (simple) thing 0 or more times. */
++#define PLUS 11 /* node Match this (simple) thing 1 or more times. */
++#define OPEN 20 /* no Mark this point in input as start of #n. */
++ /* OPEN+1 is number 1, etc. */
++#define CLOSE 30 /* no Analogous to OPEN. */
++
++/*
++ * Opcode notes:
++ *
++ * BRANCH The set of branches constituting a single choice are hooked
++ * together with their "next" pointers, since precedence prevents
++ * anything being concatenated to any individual branch. The
++ * "next" pointer of the last BRANCH in a choice points to the
++ * thing following the whole choice. This is also where the
++ * final "next" pointer of each individual branch points; each
++ * branch starts with the operand node of a BRANCH node.
++ *
++ * BACK Normal "next" pointers all implicitly point forward; BACK
++ * exists to make loop structures possible.
++ *
++ * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
++ * BRANCH structures using BACK. Simple cases (one character
++ * per match) are implemented with STAR and PLUS for speed
++ * and to minimize recursive plunges.
++ *
++ * OPEN,CLOSE ...are numbered at compile time.
++ */
++
++/*
++ * A node is one char of opcode followed by two chars of "next" pointer.
++ * "Next" pointers are stored as two 8-bit pieces, high order first. The
++ * value is a positive offset from the opcode of the node containing it.
++ * An operand, if any, simply follows the node. (Note that much of the
++ * code generation knows about this implicit relationship.)
++ *
++ * Using two bytes for the "next" pointer is vast overkill for most things,
++ * but allows patterns to get big without disasters.
++ */
++#define OP(p) (*(p))
++#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
++#define OPERAND(p) ((p) + 3)
++
++/*
++ * See regmagic.h for one further detail of program structure.
++ */
++
++
++/*
++ * Utility definitions.
++ */
++#ifndef CHARBITS
++#define UCHARAT(p) ((int)*(unsigned char *)(p))
++#else
++#define UCHARAT(p) ((int)*(p)&CHARBITS)
++#endif
++
++#define FAIL(m) { regerror(m); return(NULL); }
++#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
++#define META "^$.[()|?+*\\"
++
++/*
++ * Flags to be passed up and down.
++ */
++#define HASWIDTH 01 /* Known never to match null string. */
++#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
++#define SPSTART 04 /* Starts with * or +. */
++#define WORST 0 /* Worst case. */
++
++/*
++ * Global work variables for regcomp().
++ */
++static char *regparse; /* Input-scan pointer. */
++static int regnpar; /* () count. */
++static char regdummy;
++static char *regcode; /* Code-emit pointer; &regdummy = don't. */
++static long regsize; /* Code size. */
++
++/*
++ * Forward declarations for regcomp()'s friends.
++ */
++#ifndef STATIC
++#define STATIC static
++#endif
++STATIC char *reg(int paren,int *flagp);
++STATIC char *regbranch(int *flagp);
++STATIC char *regpiece(int *flagp);
++STATIC char *regatom(int *flagp);
++STATIC char *regnode(char op);
++STATIC char *regnext(char *p);
++STATIC void regc(char b);
++STATIC void reginsert(char op, char *opnd);
++STATIC void regtail(char *p, char *val);
++STATIC void regoptail(char *p, char *val);
++
++
++__kernel_size_t my_strcspn(const char *s1,const char *s2)
++{
++ char *scan1;
++ char *scan2;
++ int count;
++
++ count = 0;
++ for (scan1 = (char *)s1; *scan1 != '\0'; scan1++) {
++ for (scan2 = (char *)s2; *scan2 != '\0';) /* ++ moved down. */
++ if (*scan1 == *scan2++)
++ return(count);
++ count++;
++ }
++ return(count);
++}
++
++/*
++ - regcomp - compile a regular expression into internal code
++ *
++ * We can't allocate space until we know how big the compiled form will be,
++ * but we can't compile it (and thus know how big it is) until we've got a
++ * place to put the code. So we cheat: we compile it twice, once with code
++ * generation turned off and size counting turned on, and once "for real".
++ * This also means that we don't allocate space until we are sure that the
++ * thing really will compile successfully, and we never have to move the
++ * code and thus invalidate pointers into it. (Note that it has to be in
++ * one piece because free() must be able to free it all.)
++ *
++ * Beware that the optimization-preparation code in here knows about some
++ * of the structure of the compiled regexp.
++ */
++regexp *
++regcomp(char *exp,int *patternsize)
++{
++ register regexp *r;
++ register char *scan;
++ register char *longest;
++ register int len;
++ int flags;
++ /* commented out by ethan
++ extern char *malloc();
++ */
++
++ if (exp == NULL)
++ FAIL("NULL argument");
++
++ /* First pass: determine size, legality. */
++ regparse = exp;
++ regnpar = 1;
++ regsize = 0L;
++ regcode = &regdummy;
++ regc(MAGIC);
++ if (reg(0, &flags) == NULL)
++ return(NULL);
++
++ /* Small enough for pointer-storage convention? */
++ if (regsize >= 32767L) /* Probably could be 65535L. */
++ FAIL("regexp too big");
++
++ /* Allocate space. */
++ *patternsize=sizeof(regexp) + (unsigned)regsize;
++ r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
++ if (r == NULL)
++ FAIL("out of space");
++
++ /* Second pass: emit code. */
++ regparse = exp;
++ regnpar = 1;
++ regcode = r->program;
++ regc(MAGIC);
++ if (reg(0, &flags) == NULL)
++ return(NULL);
++
++ /* Dig out information for optimizations. */
++ r->regstart = '\0'; /* Worst-case defaults. */
++ r->reganch = 0;
++ r->regmust = NULL;
++ r->regmlen = 0;
++ scan = r->program+1; /* First BRANCH. */
++ if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
++ scan = OPERAND(scan);
++
++ /* Starting-point info. */
++ if (OP(scan) == EXACTLY)
++ r->regstart = *OPERAND(scan);
++ else if (OP(scan) == BOL)
++ r->reganch++;
++
++ /*
++ * If there's something expensive in the r.e., find the
++ * longest literal string that must appear and make it the
++ * regmust. Resolve ties in favor of later strings, since
++ * the regstart check works with the beginning of the r.e.
++ * and avoiding duplication strengthens checking. Not a
++ * strong reason, but sufficient in the absence of others.
++ */
++ if (flags&SPSTART) {
++ longest = NULL;
++ len = 0;
++ for (; scan != NULL; scan = regnext(scan))
++ if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
++ longest = OPERAND(scan);
++ len = strlen(OPERAND(scan));
++ }
++ r->regmust = longest;
++ r->regmlen = len;
++ }
++ }
++
++ return(r);
++}
++
++/*
++ - reg - regular expression, i.e. main body or parenthesized thing
++ *
++ * Caller must absorb opening parenthesis.
++ *
++ * Combining parenthesis handling with the base level of regular expression
++ * is a trifle forced, but the need to tie the tails of the branches to what
++ * follows makes it hard to avoid.
++ */
++static char *
++reg(int paren, int *flagp /* Parenthesized? */ )
++{
++ register char *ret;
++ register char *br;
++ register char *ender;
++ register int parno = 0; /* 0 makes gcc happy */
++ int flags;
++
++ *flagp = HASWIDTH; /* Tentatively. */
++
++ /* Make an OPEN node, if parenthesized. */
++ if (paren) {
++ if (regnpar >= NSUBEXP)
++ FAIL("too many ()");
++ parno = regnpar;
++ regnpar++;
++ ret = regnode(OPEN+parno);
++ } else
++ ret = NULL;
++
++ /* Pick up the branches, linking them together. */
++ br = regbranch(&flags);
++ if (br == NULL)
++ return(NULL);
++ if (ret != NULL)
++ regtail(ret, br); /* OPEN -> first. */
++ else
++ ret = br;
++ if (!(flags&HASWIDTH))
++ *flagp &= ~HASWIDTH;
++ *flagp |= flags&SPSTART;
++ while (*regparse == '|') {
++ regparse++;
++ br = regbranch(&flags);
++ if (br == NULL)
++ return(NULL);
++ regtail(ret, br); /* BRANCH -> BRANCH. */
++ if (!(flags&HASWIDTH))
++ *flagp &= ~HASWIDTH;
++ *flagp |= flags&SPSTART;
++ }
++
++ /* Make a closing node, and hook it on the end. */
++ ender = regnode((paren) ? CLOSE+parno : END);
++ regtail(ret, ender);
++
++ /* Hook the tails of the branches to the closing node. */
++ for (br = ret; br != NULL; br = regnext(br))
++ regoptail(br, ender);
++
++ /* Check for proper termination. */
++ if (paren && *regparse++ != ')') {
++ FAIL("unmatched ()");
++ } else if (!paren && *regparse != '\0') {
++ if (*regparse == ')') {
++ FAIL("unmatched ()");
++ } else
++ FAIL("junk on end"); /* "Can't happen". */
++ /* NOTREACHED */
++ }
++
++ return(ret);
++}
++
++/*
++ - regbranch - one alternative of an | operator
++ *
++ * Implements the concatenation operator.
++ */
++static char *
++regbranch(int *flagp)
++{
++ register char *ret;
++ register char *chain;
++ register char *latest;
++ int flags;
++
++ *flagp = WORST; /* Tentatively. */
++
++ ret = regnode(BRANCH);
++ chain = NULL;
++ while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
++ latest = regpiece(&flags);
++ if (latest == NULL)
++ return(NULL);
++ *flagp |= flags&HASWIDTH;
++ if (chain == NULL) /* First piece. */
++ *flagp |= flags&SPSTART;
++ else
++ regtail(chain, latest);
++ chain = latest;
++ }
++ if (chain == NULL) /* Loop ran zero times. */
++ (void) regnode(NOTHING);
++
++ return(ret);
++}
++
++/*
++ - regpiece - something followed by possible [*+?]
++ *
++ * Note that the branching code sequences used for ? and the general cases
++ * of * and + are somewhat optimized: they use the same NOTHING node as
++ * both the endmarker for their branch list and the body of the last branch.
++ * It might seem that this node could be dispensed with entirely, but the
++ * endmarker role is not redundant.
++ */
++static char *
++regpiece(int *flagp)
++{
++ register char *ret;
++ register char op;
++ register char *next;
++ int flags;
++
++ ret = regatom(&flags);
++ if (ret == NULL)
++ return(NULL);
++
++ op = *regparse;
++ if (!ISMULT(op)) {
++ *flagp = flags;
++ return(ret);
++ }
++
++ if (!(flags&HASWIDTH) && op != '?')
++ FAIL("*+ operand could be empty");
++ *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
++
++ if (op == '*' && (flags&SIMPLE))
++ reginsert(STAR, ret);
++ else if (op == '*') {
++ /* Emit x* as (x&|), where & means "self". */
++ reginsert(BRANCH, ret); /* Either x */
++ regoptail(ret, regnode(BACK)); /* and loop */
++ regoptail(ret, ret); /* back */
++ regtail(ret, regnode(BRANCH)); /* or */
++ regtail(ret, regnode(NOTHING)); /* null. */
++ } else if (op == '+' && (flags&SIMPLE))
++ reginsert(PLUS, ret);
++ else if (op == '+') {
++ /* Emit x+ as x(&|), where & means "self". */
++ next = regnode(BRANCH); /* Either */
++ regtail(ret, next);
++ regtail(regnode(BACK), ret); /* loop back */
++ regtail(next, regnode(BRANCH)); /* or */
++ regtail(ret, regnode(NOTHING)); /* null. */
++ } else if (op == '?') {
++ /* Emit x? as (x|) */
++ reginsert(BRANCH, ret); /* Either x */
++ regtail(ret, regnode(BRANCH)); /* or */
++ next = regnode(NOTHING); /* null. */
++ regtail(ret, next);
++ regoptail(ret, next);
++ }
++ regparse++;
++ if (ISMULT(*regparse))
++ FAIL("nested *?+");
++
++ return(ret);
++}
++
++/*
++ - regatom - the lowest level
++ *
++ * Optimization: gobbles an entire sequence of ordinary characters so that
++ * it can turn them into a single node, which is smaller to store and
++ * faster to run. Backslashed characters are exceptions, each becoming a
++ * separate node; the code is simpler that way and it's not worth fixing.
++ */
++static char *
++regatom(int *flagp)
++{
++ register char *ret;
++ int flags;
++
++ *flagp = WORST; /* Tentatively. */
++
++ switch (*regparse++) {
++ case '^':
++ ret = regnode(BOL);
++ break;
++ case '$':
++ ret = regnode(EOL);
++ break;
++ case '.':
++ ret = regnode(ANY);
++ *flagp |= HASWIDTH|SIMPLE;
++ break;
++ case '[': {
++ register int class;
++ register int classend;
++
++ if (*regparse == '^') { /* Complement of range. */
++ ret = regnode(ANYBUT);
++ regparse++;
++ } else
++ ret = regnode(ANYOF);
++ if (*regparse == ']' || *regparse == '-')
++ regc(*regparse++);
++ while (*regparse != '\0' && *regparse != ']') {
++ if (*regparse == '-') {
++ regparse++;
++ if (*regparse == ']' || *regparse == '\0')
++ regc('-');
++ else {
++ class = UCHARAT(regparse-2)+1;
++ classend = UCHARAT(regparse);
++ if (class > classend+1)
++ FAIL("invalid [] range");
++ for (; class <= classend; class++)
++ regc(class);
++ regparse++;
++ }
++ } else
++ regc(*regparse++);
++ }
++ regc('\0');
++ if (*regparse != ']')
++ FAIL("unmatched []");
++ regparse++;
++ *flagp |= HASWIDTH|SIMPLE;
++ }
++ break;
++ case '(':
++ ret = reg(1, &flags);
++ if (ret == NULL)
++ return(NULL);
++ *flagp |= flags&(HASWIDTH|SPSTART);
++ break;
++ case '\0':
++ case '|':
++ case ')':
++ FAIL("internal urp"); /* Supposed to be caught earlier. */
++ break;
++ case '?':
++ case '+':
++ case '*':
++ FAIL("?+* follows nothing");
++ break;
++ case '\\':
++ if (*regparse == '\0')
++ FAIL("trailing \\");
++ ret = regnode(EXACTLY);
++ regc(*regparse++);
++ regc('\0');
++ *flagp |= HASWIDTH|SIMPLE;
++ break;
++ default: {
++ register int len;
++ register char ender;
++
++ regparse--;
++ len = my_strcspn((const char *)regparse, (const char *)META);
++ if (len <= 0)
++ FAIL("internal disaster");
++ ender = *(regparse+len);
++ if (len > 1 && ISMULT(ender))
++ len--; /* Back off clear of ?+* operand. */
++ *flagp |= HASWIDTH;
++ if (len == 1)
++ *flagp |= SIMPLE;
++ ret = regnode(EXACTLY);
++ while (len > 0) {
++ regc(*regparse++);
++ len--;
++ }
++ regc('\0');
++ }
++ break;
++ }
++
++ return(ret);
++}
++
++/*
++ - regnode - emit a node
++ */
++static char * /* Location. */
++regnode(char op)
++{
++ register char *ret;
++ register char *ptr;
++
++ ret = regcode;
++ if (ret == &regdummy) {
++ regsize += 3;
++ return(ret);
++ }
++
++ ptr = ret;
++ *ptr++ = op;
++ *ptr++ = '\0'; /* Null "next" pointer. */
++ *ptr++ = '\0';
++ regcode = ptr;
++
++ return(ret);
++}
++
++/*
++ - regc - emit (if appropriate) a byte of code
++ */
++static void
++regc(char b)
++{
++ if (regcode != &regdummy)
++ *regcode++ = b;
++ else
++ regsize++;
++}
++
++/*
++ - reginsert - insert an operator in front of already-emitted operand
++ *
++ * Means relocating the operand.
++ */
++static void
++reginsert(char op, char* opnd)
++{
++ register char *src;
++ register char *dst;
++ register char *place;
++
++ if (regcode == &regdummy) {
++ regsize += 3;
++ return;
++ }
++
++ src = regcode;
++ regcode += 3;
++ dst = regcode;
++ while (src > opnd)
++ *--dst = *--src;
++
++ place = opnd; /* Op node, where operand used to be. */
++ *place++ = op;
++ *place++ = '\0';
++ *place++ = '\0';
++}
++
++/*
++ - regtail - set the next-pointer at the end of a node chain
++ */
++static void
++regtail(char *p, char *val)
++{
++ register char *scan;
++ register char *temp;
++ register int offset;
++
++ if (p == &regdummy)
++ return;
++
++ /* Find last node. */
++ scan = p;
++ for (;;) {
++ temp = regnext(scan);
++ if (temp == NULL)
++ break;
++ scan = temp;
++ }
++
++ if (OP(scan) == BACK)
++ offset = scan - val;
++ else
++ offset = val - scan;
++ *(scan+1) = (offset>>8)&0377;
++ *(scan+2) = offset&0377;
++}
++
++/*
++ - regoptail - regtail on operand of first argument; nop if operandless
++ */
++static void
++regoptail(char *p, char *val)
++{
++ /* "Operandless" and "op != BRANCH" are synonymous in practice. */
++ if (p == NULL || p == &regdummy || OP(p) != BRANCH)
++ return;
++ regtail(OPERAND(p), val);
++}
++
++/*
++ * regexec and friends
++ */
++
++/*
++ * Global work variables for regexec().
++ */
++static char *reginput; /* String-input pointer. */
++static char *regbol; /* Beginning of input, for ^ check. */
++static char **regstartp; /* Pointer to startp array. */
++static char **regendp; /* Ditto for endp. */
++
++/*
++ * Forwards.
++ */
++STATIC int regtry(regexp *prog, char *string);
++STATIC int regmatch(char *prog);
++STATIC int regrepeat(char *p);
++
++#ifdef DEBUG
++int regnarrate = 0;
++void regdump();
++STATIC char *regprop(char *op);
++#endif
++
++/*
++ - regexec - match a regexp against a string
++ */
++int
++regexec(regexp *prog, char *string)
++{
++ register char *s;
++
++ /* Be paranoid... */
++ if (prog == NULL || string == NULL) {
++ printk("<3>Regexp: NULL parameter\n");
++ return(0);
++ }
++
++ /* Check validity of program. */
++ if (UCHARAT(prog->program) != MAGIC) {
++ printk("<3>Regexp: corrupted program\n");
++ return(0);
++ }
++
++ /* If there is a "must appear" string, look for it. */
++ if (prog->regmust != NULL) {
++ s = string;
++ while ((s = strchr(s, prog->regmust[0])) != NULL) {
++ if (strncmp(s, prog->regmust, prog->regmlen) == 0)
++ break; /* Found it. */
++ s++;
++ }
++ if (s == NULL) /* Not present. */
++ return(0);
++ }
++
++ /* Mark beginning of line for ^ . */
++ regbol = string;
++
++ /* Simplest case: anchored match need be tried only once. */
++ if (prog->reganch)
++ return(regtry(prog, string));
++
++ /* Messy cases: unanchored match. */
++ s = string;
++ if (prog->regstart != '\0')
++ /* We know what char it must start with. */
++ while ((s = strchr(s, prog->regstart)) != NULL) {
++ if (regtry(prog, s))
++ return(1);
++ s++;
++ }
++ else
++ /* We don't -- general case. */
++ do {
++ if (regtry(prog, s))
++ return(1);
++ } while (*s++ != '\0');
++
++ /* Failure. */
++ return(0);
++}
++
++/*
++ - regtry - try match at specific point
++ */
++static int /* 0 failure, 1 success */
++regtry(regexp *prog, char *string)
++{
++ register int i;
++ register char **sp;
++ register char **ep;
++
++ reginput = string;
++ regstartp = prog->startp;
++ regendp = prog->endp;
++
++ sp = prog->startp;
++ ep = prog->endp;
++ for (i = NSUBEXP; i > 0; i--) {
++ *sp++ = NULL;
++ *ep++ = NULL;
++ }
++ if (regmatch(prog->program + 1)) {
++ prog->startp[0] = string;
++ prog->endp[0] = reginput;
++ return(1);
++ } else
++ return(0);
++}
++
++/*
++ - regmatch - main matching routine
++ *
++ * Conceptually the strategy is simple: check to see whether the current
++ * node matches, call self recursively to see whether the rest matches,
++ * and then act accordingly. In practice we make some effort to avoid
++ * recursion, in particular by going through "ordinary" nodes (that don't
++ * need to know whether the rest of the match failed) by a loop instead of
++ * by recursion.
++ */
++static int /* 0 failure, 1 success */
++regmatch(char *prog)
++{
++ register char *scan = prog; /* Current node. */
++ char *next; /* Next node. */
++
++#ifdef DEBUG
++ if (scan != NULL && regnarrate)
++ fprintf(stderr, "%s(\n", regprop(scan));
++#endif
++ while (scan != NULL) {
++#ifdef DEBUG
++ if (regnarrate)
++ fprintf(stderr, "%s...\n", regprop(scan));
++#endif
++ next = regnext(scan);
++
++ switch (OP(scan)) {
++ case BOL:
++ if (reginput != regbol)
++ return(0);
++ break;
++ case EOL:
++ if (*reginput != '\0')
++ return(0);
++ break;
++ case ANY:
++ if (*reginput == '\0')
++ return(0);
++ reginput++;
++ break;
++ case EXACTLY: {
++ register int len;
++ register char *opnd;
++
++ opnd = OPERAND(scan);
++ /* Inline the first character, for speed. */
++ if (*opnd != *reginput)
++ return(0);
++ len = strlen(opnd);
++ if (len > 1 && strncmp(opnd, reginput, len) != 0)
++ return(0);
++ reginput += len;
++ }
++ break;
++ case ANYOF:
++ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
++ return(0);
++ reginput++;
++ break;
++ case ANYBUT:
++ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
++ return(0);
++ reginput++;
++ break;
++ case NOTHING:
++ case BACK:
++ break;
++ case OPEN+1:
++ case OPEN+2:
++ case OPEN+3:
++ case OPEN+4:
++ case OPEN+5:
++ case OPEN+6:
++ case OPEN+7:
++ case OPEN+8:
++ case OPEN+9: {
++ register int no;
++ register char *save;
++
++ no = OP(scan) - OPEN;
++ save = reginput;
++
++ if (regmatch(next)) {
++ /*
++ * Don't set startp if some later
++ * invocation of the same parentheses
++ * already has.
++ */
++ if (regstartp[no] == NULL)
++ regstartp[no] = save;
++ return(1);
++ } else
++ return(0);
++ }
++ break;
++ case CLOSE+1:
++ case CLOSE+2:
++ case CLOSE+3:
++ case CLOSE+4:
++ case CLOSE+5:
++ case CLOSE+6:
++ case CLOSE+7:
++ case CLOSE+8:
++ case CLOSE+9:
++ {
++ register int no;
++ register char *save;
++
++ no = OP(scan) - CLOSE;
++ save = reginput;
++
++ if (regmatch(next)) {
++ /*
++ * Don't set endp if some later
++ * invocation of the same parentheses
++ * already has.
++ */
++ if (regendp[no] == NULL)
++ regendp[no] = save;
++ return(1);
++ } else
++ return(0);
++ }
++ break;
++ case BRANCH: {
++ register char *save;
++
++ if (OP(next) != BRANCH) /* No choice. */
++ next = OPERAND(scan); /* Avoid recursion. */
++ else {
++ do {
++ save = reginput;
++ if (regmatch(OPERAND(scan)))
++ return(1);
++ reginput = save;
++ scan = regnext(scan);
++ } while (scan != NULL && OP(scan) == BRANCH);
++ return(0);
++ /* NOTREACHED */
++ }
++ }
++ break;
++ case STAR:
++ case PLUS: {
++ register char nextch;
++ register int no;
++ register char *save;
++ register int min;
++
++ /*
++ * Lookahead to avoid useless match attempts
++ * when we know what character comes next.
++ */
++ nextch = '\0';
++ if (OP(next) == EXACTLY)
++ nextch = *OPERAND(next);
++ min = (OP(scan) == STAR) ? 0 : 1;
++ save = reginput;
++ no = regrepeat(OPERAND(scan));
++ while (no >= min) {
++ /* If it could work, try it. */
++ if (nextch == '\0' || *reginput == nextch)
++ if (regmatch(next))
++ return(1);
++ /* Couldn't or didn't -- back up. */
++ no--;
++ reginput = save + no;
++ }
++ return(0);
++ }
++ break;
++ case END:
++ return(1); /* Success! */
++ break;
++ default:
++ printk("<3>Regexp: memory corruption\n");
++ return(0);
++ break;
++ }
++
++ scan = next;
++ }
++
++ /*
++ * We get here only if there's trouble -- normally "case END" is
++ * the terminating point.
++ */
++ printk("<3>Regexp: corrupted pointers\n");
++ return(0);
++}
++
++/*
++ - regrepeat - repeatedly match something simple, report how many
++ */
++static int
++regrepeat(char *p)
++{
++ register int count = 0;
++ register char *scan;
++ register char *opnd;
++
++ scan = reginput;
++ opnd = OPERAND(p);
++ switch (OP(p)) {
++ case ANY:
++ count = strlen(scan);
++ scan += count;
++ break;
++ case EXACTLY:
++ while (*opnd == *scan) {
++ count++;
++ scan++;
++ }
++ break;
++ case ANYOF:
++ while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
++ count++;
++ scan++;
++ }
++ break;
++ case ANYBUT:
++ while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
++ count++;
++ scan++;
++ }
++ break;
++ default: /* Oh dear. Called inappropriately. */
++ printk("<3>Regexp: internal foulup\n");
++ count = 0; /* Best compromise. */
++ break;
++ }
++ reginput = scan;
++
++ return(count);
++}
++
++/*
++ - regnext - dig the "next" pointer out of a node
++ */
++static char*
++regnext(char *p)
++{
++ register int offset;
++
++ if (p == &regdummy)
++ return(NULL);
++
++ offset = NEXT(p);
++ if (offset == 0)
++ return(NULL);
++
++ if (OP(p) == BACK)
++ return(p-offset);
++ else
++ return(p+offset);
++}
++
++#ifdef DEBUG
++
++STATIC char *regprop();
++
++/*
++ - regdump - dump a regexp onto stdout in vaguely comprehensible form
++ */
++void
++regdump(regexp *r)
++{
++ register char *s;
++ register char op = EXACTLY; /* Arbitrary non-END op. */
++ register char *next;
++ /* extern char *strchr(); */
++
++
++ s = r->program + 1;
++ while (op != END) { /* While that wasn't END last time... */
++ op = OP(s);
++ printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
++ next = regnext(s);
++ if (next == NULL) /* Next ptr. */
++ printf("(0)");
++ else
++ printf("(%d)", (s-r->program)+(next-s));
++ s += 3;
++ if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
++ /* Literal string, where present. */
++ while (*s != '\0') {
++ putchar(*s);
++ s++;
++ }
++ s++;
++ }
++ putchar('\n');
++ }
++
++ /* Header fields of interest. */
++ if (r->regstart != '\0')
++ printf("start `%c' ", r->regstart);
++ if (r->reganch)
++ printf("anchored ");
++ if (r->regmust != NULL)
++ printf("must have \"%s\"", r->regmust);
++ printf("\n");
++}
++
++/*
++ - regprop - printable representation of opcode
++ */
++static char *
++regprop(char *op)
++{
++#define BUFLEN 50
++ register char *p;
++ static char buf[BUFLEN];
++
++ strcpy(buf, ":");
++
++ switch (OP(op)) {
++ case BOL:
++ p = "BOL";
++ break;
++ case EOL:
++ p = "EOL";
++ break;
++ case ANY:
++ p = "ANY";
++ break;
++ case ANYOF:
++ p = "ANYOF";
++ break;
++ case ANYBUT:
++ p = "ANYBUT";
++ break;
++ case BRANCH:
++ p = "BRANCH";
++ break;
++ case EXACTLY:
++ p = "EXACTLY";
++ break;
++ case NOTHING:
++ p = "NOTHING";
++ break;
++ case BACK:
++ p = "BACK";
++ break;
++ case END:
++ p = "END";
++ break;
++ case OPEN+1:
++ case OPEN+2:
++ case OPEN+3:
++ case OPEN+4:
++ case OPEN+5:
++ case OPEN+6:
++ case OPEN+7:
++ case OPEN+8:
++ case OPEN+9:
++ snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "OPEN%d", OP(op)-OPEN);
++ p = NULL;
++ break;
++ case CLOSE+1:
++ case CLOSE+2:
++ case CLOSE+3:
++ case CLOSE+4:
++ case CLOSE+5:
++ case CLOSE+6:
++ case CLOSE+7:
++ case CLOSE+8:
++ case CLOSE+9:
++ snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "CLOSE%d", OP(op)-CLOSE);
++ p = NULL;
++ break;
++ case STAR:
++ p = "STAR";
++ break;
++ case PLUS:
++ p = "PLUS";
++ break;
++ default:
++ printk("<3>Regexp: corrupted opcode\n");
++ break;
++ }
++ if (p != NULL)
++ strncat(buf, p, BUFLEN-strlen(buf));
++ return(buf);
++}
++#endif
++
++
+diff -urN linux.old/net/ipv4/netfilter/regexp/regexp.h linux.dev/net/ipv4/netfilter/regexp/regexp.h
+--- linux.old/net/ipv4/netfilter/regexp/regexp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/net/ipv4/netfilter/regexp/regexp.h 2006-01-31 16:58:24.819335750 +0100
+@@ -0,0 +1,40 @@
++/*
++ * Definitions etc. for regexp(3) routines.
++ *
++ * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
++ * not the System V one.
++ */
++
++#ifndef REGEXP_H
++#define REGEXP_H
++
++/*
++http://www.opensource.apple.com/darwinsource/10.3/expect-1/expect/expect.h ,
++which contains a version of this library, says:
++
++ *
++ * NSUBEXP must be at least 10, and no greater than 117 or the parser
++ * will not work properly.
++ *
++
++However, it looks rather like this library is limited to 10. If you think
++otherwise, let us know.
++*/
++
++#define NSUBEXP 10
++typedef struct regexp {
++ char *startp[NSUBEXP];
++ char *endp[NSUBEXP];
++ char regstart; /* Internal use only. */
++ char reganch; /* Internal use only. */
++ char *regmust; /* Internal use only. */
++ int regmlen; /* Internal use only. */
++ char program[1]; /* Unwarranted chumminess with compiler. */
++} regexp;
++
++regexp * regcomp(char *exp, int *patternsize);
++int regexec(regexp *prog, char *string);
++void regsub(regexp *prog, char *source, char *dest);
++void regerror(char *s);
++
++#endif
+diff -urN linux.old/net/ipv4/netfilter/regexp/regmagic.h linux.dev/net/ipv4/netfilter/regexp/regmagic.h
+--- linux.old/net/ipv4/netfilter/regexp/regmagic.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/net/ipv4/netfilter/regexp/regmagic.h 2006-01-31 16:58:24.823336000 +0100
+@@ -0,0 +1,5 @@
++/*
++ * The first byte of the regexp internal "program" is actually this magic
++ * number; the start node begins in the second byte.
++ */
++#define MAGIC 0234
+diff -urN linux.old/net/ipv4/netfilter/regexp/regsub.c linux.dev/net/ipv4/netfilter/regexp/regsub.c
+--- linux.old/net/ipv4/netfilter/regexp/regsub.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/net/ipv4/netfilter/regexp/regsub.c 2006-01-31 16:58:24.823336000 +0100
+@@ -0,0 +1,95 @@
++/*
++ * regsub
++ * @(#)regsub.c 1.3 of 2 April 86
++ *
++ * Copyright (c) 1986 by University of Toronto.
++ * Written by Henry Spencer. Not derived from licensed software.
++ *
++ * Permission is granted to anyone to use this software for any
++ * purpose on any computer system, and to redistribute it freely,
++ * subject to the following restrictions:
++ *
++ * 1. The author is not responsible for the consequences of use of
++ * this software, no matter how awful, even if they arise
++ * from defects in it.
++ *
++ * 2. The origin of this software must not be misrepresented, either
++ * by explicit claim or by omission.
++ *
++ * 3. Altered versions must be plainly marked as such, and must not
++ * be misrepresented as being the original software.
++ *
++ *
++ * This code was modified by Ethan Sommer to work within the kernel
++ * (it now uses kmalloc etc..)
++ *
++ */
++#include "regexp.h"
++#include "regmagic.h"
++#include <linux/string.h>
++
++
++#ifndef CHARBITS
++#define UCHARAT(p) ((int)*(unsigned char *)(p))
++#else
++#define UCHARAT(p) ((int)*(p)&CHARBITS)
++#endif
++
++#if 0
++//void regerror(char * s)
++//{
++// printk("regexp(3): %s", s);
++// /* NOTREACHED */
++//}
++#endif
++
++/*
++ - regsub - perform substitutions after a regexp match
++ */
++void
++regsub(regexp * prog, char * source, char * dest)
++{
++ register char *src;
++ register char *dst;
++ register char c;
++ register int no;
++ register int len;
++
++ /* Not necessary and gcc doesn't like it -MLS */
++ /*extern char *strncpy();*/
++
++ if (prog == NULL || source == NULL || dest == NULL) {
++ regerror("NULL parm to regsub");
++ return;
++ }
++ if (UCHARAT(prog->program) != MAGIC) {
++ regerror("damaged regexp fed to regsub");
++ return;
++ }
++
++ src = source;
++ dst = dest;
++ while ((c = *src++) != '\0') {
++ if (c == '&')
++ no = 0;
++ else if (c == '\\' && '0' <= *src && *src <= '9')
++ no = *src++ - '0';
++ else
++ no = -1;
++
++ if (no < 0) { /* Ordinary character. */
++ if (c == '\\' && (*src == '\\' || *src == '&'))
++ c = *src++;
++ *dst++ = c;
++ } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
++ len = prog->endp[no] - prog->startp[no];
++ (void) strncpy(dst, prog->startp[no], len);
++ dst += len;
++ if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */
++ regerror("damaged match string");
++ return;
++ }
++ }
++ }
++ *dst++ = '\0';
++}
diff --git a/target/linux/generic-2.4/patches/603-netfilter_nat_pptp.patch b/target/linux/generic-2.4/patches/603-netfilter_nat_pptp.patch
new file mode 100644
index 0000000..6a7a16f
--- /dev/null
+++ b/target/linux/generic-2.4/patches/603-netfilter_nat_pptp.patch
@@ -0,0 +1,2412 @@
+diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack.h
+--- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack.h 2005-04-02 19:04:11.000000000 +0200
++++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack.h 2005-04-02 19:41:05.000000000 +0200
+@@ -50,16 +50,19 @@
+
+ #include <linux/netfilter_ipv4/ip_conntrack_tcp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_icmp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
+
+ /* per conntrack: protocol private data */
+ union ip_conntrack_proto {
+ /* insert conntrack proto private data here */
+ struct ip_ct_tcp tcp;
+ struct ip_ct_icmp icmp;
++ struct ip_ct_gre gre;
+ };
+
+ union ip_conntrack_expect_proto {
+ /* insert expect proto private data here */
++ struct ip_ct_gre_expect gre;
+ };
+
+ /* Add protocol helper include file here */
+@@ -67,6 +70,7 @@
+
+ #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
++#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
+
+ /* per expectation: application helper private data */
+ union ip_conntrack_expect_help {
+@@ -74,6 +78,7 @@
+ struct ip_ct_amanda_expect exp_amanda_info;
+ struct ip_ct_ftp_expect exp_ftp_info;
+ struct ip_ct_irc_expect exp_irc_info;
++ struct ip_ct_pptp_expect exp_pptp_info;
+
+ #ifdef CONFIG_IP_NF_NAT_NEEDED
+ union {
+@@ -87,14 +92,17 @@
+ /* insert conntrack helper private data (master) here */
+ struct ip_ct_ftp_master ct_ftp_info;
+ struct ip_ct_irc_master ct_irc_info;
++ struct ip_ct_pptp_master ct_pptp_info;
+ };
+
+ #ifdef CONFIG_IP_NF_NAT_NEEDED
+ #include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_pptp.h>
+
+ /* per conntrack: nat application helper private data */
+ union ip_conntrack_nat_help {
+ /* insert nat helper private data here */
++ struct ip_nat_pptp nat_pptp_info;
+ };
+ #endif
+
+diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_pptp.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_pptp.h
+--- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_pptp.h 2005-04-02 19:09:07.000000000 +0200
+@@ -0,0 +1,313 @@
++/* PPTP constants and structs */
++#ifndef _CONNTRACK_PPTP_H
++#define _CONNTRACK_PPTP_H
++
++/* state of the control session */
++enum pptp_ctrlsess_state {
++ PPTP_SESSION_NONE, /* no session present */
++ PPTP_SESSION_ERROR, /* some session error */
++ PPTP_SESSION_STOPREQ, /* stop_sess request seen */
++ PPTP_SESSION_REQUESTED, /* start_sess request seen */
++ PPTP_SESSION_CONFIRMED, /* session established */
++};
++
++/* state of the call inside the control session */
++enum pptp_ctrlcall_state {
++ PPTP_CALL_NONE,
++ PPTP_CALL_ERROR,
++ PPTP_CALL_OUT_REQ,
++ PPTP_CALL_OUT_CONF,
++ PPTP_CALL_IN_REQ,
++ PPTP_CALL_IN_REP,
++ PPTP_CALL_IN_CONF,
++ PPTP_CALL_CLEAR_REQ,
++};
++
++
++/* conntrack private data */
++struct ip_ct_pptp_master {
++ enum pptp_ctrlsess_state sstate; /* session state */
++
++ /* everything below is going to be per-expectation in newnat,
++ * since there could be more than one call within one session */
++ enum pptp_ctrlcall_state cstate; /* call state */
++ u_int16_t pac_call_id; /* call id of PAC, host byte order */
++ u_int16_t pns_call_id; /* call id of PNS, host byte order */
++};
++
++/* conntrack_expect private member */
++struct ip_ct_pptp_expect {
++ enum pptp_ctrlcall_state cstate; /* call state */
++ u_int16_t pac_call_id; /* call id of PAC */
++ u_int16_t pns_call_id; /* call id of PNS */
++};
++
++
++#ifdef __KERNEL__
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++DECLARE_LOCK_EXTERN(ip_pptp_lock);
++
++#define IP_CONNTR_PPTP PPTP_CONTROL_PORT
++
++union pptp_ctrl_union {
++ void *rawreq;
++ struct PptpStartSessionRequest *sreq;
++ struct PptpStartSessionReply *srep;
++ struct PptpStopSessionRequest *streq;
++ struct PptpStopSessionReply *strep;
++ struct PptpOutCallRequest *ocreq;
++ struct PptpOutCallReply *ocack;
++ struct PptpInCallRequest *icreq;
++ struct PptpInCallReply *icack;
++ struct PptpInCallConnected *iccon;
++ struct PptpClearCallRequest *clrreq;
++ struct PptpCallDisconnectNotify *disc;
++ struct PptpWanErrorNotify *wanerr;
++ struct PptpSetLinkInfo *setlink;
++};
++
++
++
++#define PPTP_CONTROL_PORT 1723
++
++#define PPTP_PACKET_CONTROL 1
++#define PPTP_PACKET_MGMT 2
++
++#define PPTP_MAGIC_COOKIE 0x1a2b3c4d
++
++struct pptp_pkt_hdr {
++ __u16 packetLength;
++ __u16 packetType;
++ __u32 magicCookie;
++};
++
++/* PptpControlMessageType values */
++#define PPTP_START_SESSION_REQUEST 1
++#define PPTP_START_SESSION_REPLY 2
++#define PPTP_STOP_SESSION_REQUEST 3
++#define PPTP_STOP_SESSION_REPLY 4
++#define PPTP_ECHO_REQUEST 5
++#define PPTP_ECHO_REPLY 6
++#define PPTP_OUT_CALL_REQUEST 7
++#define PPTP_OUT_CALL_REPLY 8
++#define PPTP_IN_CALL_REQUEST 9
++#define PPTP_IN_CALL_REPLY 10
++#define PPTP_IN_CALL_CONNECT 11
++#define PPTP_CALL_CLEAR_REQUEST 12
++#define PPTP_CALL_DISCONNECT_NOTIFY 13
++#define PPTP_WAN_ERROR_NOTIFY 14
++#define PPTP_SET_LINK_INFO 15
++
++#define PPTP_MSG_MAX 15
++
++/* PptpGeneralError values */
++#define PPTP_ERROR_CODE_NONE 0
++#define PPTP_NOT_CONNECTED 1
++#define PPTP_BAD_FORMAT 2
++#define PPTP_BAD_VALUE 3
++#define PPTP_NO_RESOURCE 4
++#define PPTP_BAD_CALLID 5
++#define PPTP_REMOVE_DEVICE_ERROR 6
++
++struct PptpControlHeader {
++ __u16 messageType;
++ __u16 reserved;
++};
++
++/* FramingCapability Bitmap Values */
++#define PPTP_FRAME_CAP_ASYNC 0x1
++#define PPTP_FRAME_CAP_SYNC 0x2
++
++/* BearerCapability Bitmap Values */
++#define PPTP_BEARER_CAP_ANALOG 0x1
++#define PPTP_BEARER_CAP_DIGITAL 0x2
++
++struct PptpStartSessionRequest {
++ __u16 protocolVersion;
++ __u8 reserved1;
++ __u8 reserved2;
++ __u32 framingCapability;
++ __u32 bearerCapability;
++ __u16 maxChannels;
++ __u16 firmwareRevision;
++ __u8 hostName[64];
++ __u8 vendorString[64];
++};
++
++/* PptpStartSessionResultCode Values */
++#define PPTP_START_OK 1
++#define PPTP_START_GENERAL_ERROR 2
++#define PPTP_START_ALREADY_CONNECTED 3
++#define PPTP_START_NOT_AUTHORIZED 4
++#define PPTP_START_UNKNOWN_PROTOCOL 5
++
++struct PptpStartSessionReply {
++ __u16 protocolVersion;
++ __u8 resultCode;
++ __u8 generalErrorCode;
++ __u32 framingCapability;
++ __u32 bearerCapability;
++ __u16 maxChannels;
++ __u16 firmwareRevision;
++ __u8 hostName[64];
++ __u8 vendorString[64];
++};
++
++/* PptpStopReasons */
++#define PPTP_STOP_NONE 1
++#define PPTP_STOP_PROTOCOL 2
++#define PPTP_STOP_LOCAL_SHUTDOWN 3
++
++struct PptpStopSessionRequest {
++ __u8 reason;
++};
++
++/* PptpStopSessionResultCode */
++#define PPTP_STOP_OK 1
++#define PPTP_STOP_GENERAL_ERROR 2
++
++struct PptpStopSessionReply {
++ __u8 resultCode;
++ __u8 generalErrorCode;
++};
++
++struct PptpEchoRequest {
++ __u32 identNumber;
++};
++
++/* PptpEchoReplyResultCode */
++#define PPTP_ECHO_OK 1
++#define PPTP_ECHO_GENERAL_ERROR 2
++
++struct PptpEchoReply {
++ __u32 identNumber;
++ __u8 resultCode;
++ __u8 generalErrorCode;
++ __u16 reserved;
++};
++
++/* PptpFramingType */
++#define PPTP_ASYNC_FRAMING 1
++#define PPTP_SYNC_FRAMING 2
++#define PPTP_DONT_CARE_FRAMING 3
++
++/* PptpCallBearerType */
++#define PPTP_ANALOG_TYPE 1
++#define PPTP_DIGITAL_TYPE 2
++#define PPTP_DONT_CARE_BEARER_TYPE 3
++
++struct PptpOutCallRequest {
++ __u16 callID;
++ __u16 callSerialNumber;
++ __u32 minBPS;
++ __u32 maxBPS;
++ __u32 bearerType;
++ __u32 framingType;
++ __u16 packetWindow;
++ __u16 packetProcDelay;
++ __u16 reserved1;
++ __u16 phoneNumberLength;
++ __u16 reserved2;
++ __u8 phoneNumber[64];
++ __u8 subAddress[64];
++};
++
++/* PptpCallResultCode */
++#define PPTP_OUTCALL_CONNECT 1
++#define PPTP_OUTCALL_GENERAL_ERROR 2
++#define PPTP_OUTCALL_NO_CARRIER 3
++#define PPTP_OUTCALL_BUSY 4
++#define PPTP_OUTCALL_NO_DIAL_TONE 5
++#define PPTP_OUTCALL_TIMEOUT 6
++#define PPTP_OUTCALL_DONT_ACCEPT 7
++
++struct PptpOutCallReply {
++ __u16 callID;
++ __u16 peersCallID;
++ __u8 resultCode;
++ __u8 generalErrorCode;
++ __u16 causeCode;
++ __u32 connectSpeed;
++ __u16 packetWindow;
++ __u16 packetProcDelay;
++ __u32 physChannelID;
++};
++
++struct PptpInCallRequest {
++ __u16 callID;
++ __u16 callSerialNumber;
++ __u32 callBearerType;
++ __u32 physChannelID;
++ __u16 dialedNumberLength;
++ __u16 dialingNumberLength;
++ __u8 dialedNumber[64];
++ __u8 dialingNumber[64];
++ __u8 subAddress[64];
++};
++
++/* PptpInCallResultCode */
++#define PPTP_INCALL_ACCEPT 1
++#define PPTP_INCALL_GENERAL_ERROR 2
++#define PPTP_INCALL_DONT_ACCEPT 3
++
++struct PptpInCallReply {
++ __u16 callID;
++ __u16 peersCallID;
++ __u8 resultCode;
++ __u8 generalErrorCode;
++ __u16 packetWindow;
++ __u16 packetProcDelay;
++ __u16 reserved;
++};
++
++struct PptpInCallConnected {
++ __u16 peersCallID;
++ __u16 reserved;
++ __u32 connectSpeed;
++ __u16 packetWindow;
++ __u16 packetProcDelay;
++ __u32 callFramingType;
++};
++
++struct PptpClearCallRequest {
++ __u16 callID;
++ __u16 reserved;
++};
++
++struct PptpCallDisconnectNotify {
++ __u16 callID;
++ __u8 resultCode;
++ __u8 generalErrorCode;
++ __u16 causeCode;
++ __u16 reserved;
++ __u8 callStatistics[128];
++};
++
++struct PptpWanErrorNotify {
++ __u16 peersCallID;
++ __u16 reserved;
++ __u32 crcErrors;
++ __u32 framingErrors;
++ __u32 hardwareOverRuns;
++ __u32 bufferOverRuns;
++ __u32 timeoutErrors;
++ __u32 alignmentErrors;
++};
++
++struct PptpSetLinkInfo {
++ __u16 peersCallID;
++ __u16 reserved;
++ __u32 sendAccm;
++ __u32 recvAccm;
++};
++
++
++struct pptp_priv_data {
++ __u16 call_id;
++ __u16 mcall_id;
++ __u16 pcall_id;
++};
++
++#endif /* __KERNEL__ */
++#endif /* _CONNTRACK_PPTP_H */
+diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h
+--- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h 2005-04-02 19:10:45.000000000 +0200
+@@ -0,0 +1,123 @@
++#ifndef _CONNTRACK_PROTO_GRE_H
++#define _CONNTRACK_PROTO_GRE_H
++#include <asm/byteorder.h>
++
++/* GRE PROTOCOL HEADER */
++
++/* GRE Version field */
++#define GRE_VERSION_1701 0x0
++#define GRE_VERSION_PPTP 0x1
++
++/* GRE Protocol field */
++#define GRE_PROTOCOL_PPTP 0x880B
++
++/* GRE Flags */
++#define GRE_FLAG_C 0x80
++#define GRE_FLAG_R 0x40
++#define GRE_FLAG_K 0x20
++#define GRE_FLAG_S 0x10
++#define GRE_FLAG_A 0x80
++
++#define GRE_IS_C(f) ((f)&GRE_FLAG_C)
++#define GRE_IS_R(f) ((f)&GRE_FLAG_R)
++#define GRE_IS_K(f) ((f)&GRE_FLAG_K)
++#define GRE_IS_S(f) ((f)&GRE_FLAG_S)
++#define GRE_IS_A(f) ((f)&GRE_FLAG_A)
++
++/* GRE is a mess: Four different standards */
++struct gre_hdr {
++#if defined(__LITTLE_ENDIAN_BITFIELD)
++ __u16 rec:3,
++ srr:1,
++ seq:1,
++ key:1,
++ routing:1,
++ csum:1,
++ version:3,
++ reserved:4,
++ ack:1;
++#elif defined(__BIG_ENDIAN_BITFIELD)
++ __u16 csum:1,
++ routing:1,
++ key:1,
++ seq:1,
++ srr:1,
++ rec:3,
++ ack:1,
++ reserved:4,
++ version:3;
++#else
++#error "Adjust your <asm/byteorder.h> defines"
++#endif
++ __u16 protocol;
++};
++
++/* modified GRE header for PPTP */
++struct gre_hdr_pptp {
++ __u8 flags; /* bitfield */
++ __u8 version; /* should be GRE_VERSION_PPTP */
++ __u16 protocol; /* should be GRE_PROTOCOL_PPTP */
++ __u16 payload_len; /* size of ppp payload, not inc. gre header */
++ __u16 call_id; /* peer's call_id for this session */
++ __u32 seq; /* sequence number. Present if S==1 */
++ __u32 ack; /* seq number of highest packet recieved by */
++ /* sender in this session */
++};
++
++
++/* this is part of ip_conntrack */
++struct ip_ct_gre {
++ unsigned int stream_timeout;
++ unsigned int timeout;
++};
++
++/* this is part of ip_conntrack_expect */
++struct ip_ct_gre_expect {
++ struct ip_ct_gre_keymap *keymap_orig, *keymap_reply;
++};
++
++#ifdef __KERNEL__
++struct ip_conntrack_expect;
++
++/* structure for original <-> reply keymap */
++struct ip_ct_gre_keymap {
++ struct list_head list;
++
++ struct ip_conntrack_tuple tuple;
++};
++
++
++/* add new tuple->key_reply pair to keymap */
++int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
++ struct ip_conntrack_tuple *t,
++ int reply);
++
++/* change an existing keymap entry */
++void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
++ struct ip_conntrack_tuple *t);
++
++/* delete keymap entries */
++void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp);
++
++
++/* get pointer to gre key, if present */
++static inline u_int32_t *gre_key(struct gre_hdr *greh)
++{
++ if (!greh->key)
++ return NULL;
++ if (greh->csum || greh->routing)
++ return (u_int32_t *) (greh+sizeof(*greh)+4);
++ return (u_int32_t *) (greh+sizeof(*greh));
++}
++
++/* get pointer ot gre csum, if present */
++static inline u_int16_t *gre_csum(struct gre_hdr *greh)
++{
++ if (!greh->csum)
++ return NULL;
++ return (u_int16_t *) (greh+sizeof(*greh));
++}
++
++#endif /* __KERNEL__ */
++
++#endif /* _CONNTRACK_PROTO_GRE_H */
+diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
+--- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_conntrack_tuple.h 2005-04-02 19:07:18.000000000 +0200
+@@ -14,7 +14,7 @@
+ union ip_conntrack_manip_proto
+ {
+ /* Add other protocols here. */
+- u_int16_t all;
++ u_int32_t all;
+
+ struct {
+ u_int16_t port;
+@@ -25,6 +25,9 @@
+ struct {
+ u_int16_t id;
+ } icmp;
++ struct {
++ u_int32_t key;
++ } gre;
+ };
+
+ /* The manipulable part of the tuple. */
+@@ -44,7 +47,7 @@
+ u_int32_t ip;
+ union {
+ /* Add other protocols here. */
+- u_int16_t all;
++ u_int32_t all;
+
+ struct {
+ u_int16_t port;
+@@ -55,6 +58,9 @@
+ struct {
+ u_int8_t type, code;
+ } icmp;
++ struct {
++ u_int32_t key;
++ } gre;
+ } u;
+
+ /* The protocol. */
+@@ -80,10 +86,16 @@
+ #ifdef __KERNEL__
+
+ #define DUMP_TUPLE(tp) \
+-DEBUGP("tuple %p: %u %u.%u.%u.%u:%hu -> %u.%u.%u.%u:%hu\n", \
++DEBUGP("tuple %p: %u %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", \
+ (tp), (tp)->dst.protonum, \
+- NIPQUAD((tp)->src.ip), ntohs((tp)->src.u.all), \
+- NIPQUAD((tp)->dst.ip), ntohs((tp)->dst.u.all))
++ NIPQUAD((tp)->src.ip), ntohl((tp)->src.u.all), \
++ NIPQUAD((tp)->dst.ip), ntohl((tp)->dst.u.all))
++
++#define DUMP_TUPLE_RAW(x) \
++ DEBUGP("tuple %p: %u %u.%u.%u.%u:0x%08x -> %u.%u.%u.%u:0x%08x\n",\
++ (x), (x)->dst.protonum, \
++ NIPQUAD((x)->src.ip), ntohl((x)->src.u.all), \
++ NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.all))
+
+ #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
+
+diff -urN linux-2.4.29-old/include/linux/netfilter_ipv4/ip_nat_pptp.h linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_nat_pptp.h
+--- linux-2.4.29-old/include/linux/netfilter_ipv4/ip_nat_pptp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29-dev/include/linux/netfilter_ipv4/ip_nat_pptp.h 2005-04-02 19:07:18.000000000 +0200
+@@ -0,0 +1,11 @@
++/* PPTP constants and structs */
++#ifndef _NAT_PPTP_H
++#define _NAT_PPTP_H
++
++/* conntrack private data */
++struct ip_nat_pptp {
++ u_int16_t pns_call_id; /* NAT'ed PNS call id */
++ u_int16_t pac_call_id; /* NAT'ed PAC call id */
++};
++
++#endif /* _NAT_PPTP_H */
+diff -urN linux-2.4.29-old/net/ipv4/netfilter/Config.in linux-2.4.29-dev/net/ipv4/netfilter/Config.in
+--- linux-2.4.29-old/net/ipv4/netfilter/Config.in 2005-04-02 19:04:11.000000000 +0200
++++ linux-2.4.29-dev/net/ipv4/netfilter/Config.in 2005-04-02 19:07:18.000000000 +0200
+@@ -10,6 +10,8 @@
+ dep_tristate ' Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK
+ dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK
+ dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
++ dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK
++ dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE
+ fi
+
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+@@ -67,6 +69,20 @@
+ define_bool CONFIG_IP_NF_NAT_NEEDED y
+ dep_tristate ' MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT
+ dep_tristate ' REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT
++ if [ "$CONFIG_IP_NF_PPTP" = "m" ]; then
++ define_tristate CONFIG_IP_NF_NAT_PPTP m
++ else
++ if [ "$CONFIG_IP_NF_PPTP" = "y" ]; then
++ define_tristate CONFIG_IP_NF_NAT_PPTP $CONFIG_IP_NF_NAT
++ fi
++ fi
++ if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "m" ]; then
++ define_tristate CONFIG_IP_NF_NAT_PROTO_GRE m
++ else
++ if [ "$CONFIG_IP_NF_CT_PROTO_GRE" = "y" ]; then
++ define_tristate CONFIG_IP_NF_NAT_PROTO_GRE $CONFIG_IP_NF_NAT
++ fi
++ fi
+ if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then
+ define_tristate CONFIG_IP_NF_NAT_AMANDA m
+ else
+diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_core.c
+--- linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_core.c 2005-04-02 19:04:11.000000000 +0200
++++ linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_core.c 2005-04-02 19:07:18.000000000 +0200
+@@ -142,6 +142,8 @@
+ tuple->dst.ip = iph->daddr;
+ tuple->dst.protonum = iph->protocol;
+
++ tuple->src.u.all = tuple->dst.u.all = 0;
++
+ ret = protocol->pkt_to_tuple((u_int32_t *)iph + iph->ihl,
+ len - 4*iph->ihl,
+ tuple);
+@@ -157,6 +159,8 @@
+ inverse->dst.ip = orig->src.ip;
+ inverse->dst.protonum = orig->dst.protonum;
+
++ inverse->src.u.all = inverse->dst.u.all = 0;
++
+ return protocol->invert_tuple(inverse, orig);
+ }
+
+@@ -954,8 +958,8 @@
+ * so there is no need to use the tuple lock too */
+
+ DEBUGP("ip_conntrack_expect_related %p\n", related_to);
+- DEBUGP("tuple: "); DUMP_TUPLE(&expect->tuple);
+- DEBUGP("mask: "); DUMP_TUPLE(&expect->mask);
++ DEBUGP("tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
++ DEBUGP("mask: "); DUMP_TUPLE_RAW(&expect->mask);
+
+ old = LIST_FIND(&ip_conntrack_expect_list, resent_expect,
+ struct ip_conntrack_expect *, &expect->tuple,
+@@ -1072,15 +1076,14 @@
+
+ MUST_BE_READ_LOCKED(&ip_conntrack_lock);
+ WRITE_LOCK(&ip_conntrack_expect_tuple_lock);
+-
+ DEBUGP("change_expect:\n");
+- DEBUGP("exp tuple: "); DUMP_TUPLE(&expect->tuple);
+- DEBUGP("exp mask: "); DUMP_TUPLE(&expect->mask);
+- DEBUGP("newtuple: "); DUMP_TUPLE(newtuple);
++ DEBUGP("exp tuple: "); DUMP_TUPLE_RAW(&expect->tuple);
++ DEBUGP("exp mask: "); DUMP_TUPLE_RAW(&expect->mask);
++ DEBUGP("newtuple: "); DUMP_TUPLE_RAW(newtuple);
+ if (expect->ct_tuple.dst.protonum == 0) {
+ /* Never seen before */
+ DEBUGP("change expect: never seen before\n");
+- if (!ip_ct_tuple_equal(&expect->tuple, newtuple)
++ if (!ip_ct_tuple_mask_cmp(&expect->tuple, newtuple, &expect->mask)
+ && LIST_FIND(&ip_conntrack_expect_list, expect_clash,
+ struct ip_conntrack_expect *, newtuple, &expect->mask)) {
+ /* Force NAT to find an unused tuple */
+diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_pptp_priv.h linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_pptp_priv.h
+--- linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_pptp_priv.h 2005-04-02 19:14:10.000000000 +0200
+@@ -0,0 +1,24 @@
++#ifndef _IP_CT_PPTP_PRIV_H
++#define _IP_CT_PPTP_PRIV_H
++
++/* PptpControlMessageType names */
++static const char *strMName[] = {
++ "UNKNOWN_MESSAGE",
++ "START_SESSION_REQUEST",
++ "START_SESSION_REPLY",
++ "STOP_SESSION_REQUEST",
++ "STOP_SESSION_REPLY",
++ "ECHO_REQUEST",
++ "ECHO_REPLY",
++ "OUT_CALL_REQUEST",
++ "OUT_CALL_REPLY",
++ "IN_CALL_REQUEST",
++ "IN_CALL_REPLY",
++ "IN_CALL_CONNECT",
++ "CALL_CLEAR_REQUEST",
++ "CALL_DISCONNECT_NOTIFY",
++ "WAN_ERROR_NOTIFY",
++ "SET_LINK_INFO"
++};
++
++#endif
+diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_proto_gre.c linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_proto_gre.c
+--- linux-2.4.29-old/net/ipv4/netfilter/ip_conntrack_proto_gre.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29-dev/net/ipv4/netfilter/ip_conntrack_proto_gre.c 2005-04-02 19:14:31.000000000 +0200
+@@ -0,0 +1,333 @@
++/*
++ * ip_conntrack_proto_gre.c - Version 1.2
++ *
++ * Connection tracking protocol helper module for GRE.
++ *
++ * GRE is a generic encapsulation protocol, which is generally not very
++ * suited for NAT, as it has no protocol-specific part as port numbers.
++ *
++ * It has an optional key field, which may help us distinguishing two
++ * connections between the same two hosts.
++ *
++ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
++ *
++ * PPTP is built on top of a modified version of GRE, and has a mandatory
++ * field called "CallID", which serves us for the same purpose as the key
++ * field in plain GRE.
++ *
++ * Documentation about PPTP can be found in RFC 2637
++ *
++ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
++ *
++ * Development of this code funded by Astaro AG (http://www.astaro.com/)
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/timer.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <linux/in.h>
++#include <linux/list.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++
++DECLARE_RWLOCK(ip_ct_gre_lock);
++#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_ct_gre_lock)
++#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_ct_gre_lock)
++
++#include <linux/netfilter_ipv4/listhelp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_core.h>
++
++#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
++#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
++MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE");
++
++/* shamelessly stolen from ip_conntrack_proto_udp.c */
++#define GRE_TIMEOUT (30*HZ)
++#define GRE_STREAM_TIMEOUT (180*HZ)
++
++#if 0
++#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
++ ": " format, ## args)
++#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x:%u:0x%x\n", \
++ NIPQUAD((x)->src.ip), ntohl((x)->src.u.gre.key), \
++ NIPQUAD((x)->dst.ip), ntohl((x)->dst.u.gre.key))
++#else
++#define DEBUGP(x, args...)
++#define DUMP_TUPLE_GRE(x)
++#endif
++
++/* GRE KEYMAP HANDLING FUNCTIONS */
++static LIST_HEAD(gre_keymap_list);
++
++static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km,
++ const struct ip_conntrack_tuple *t)
++{
++ return ((km->tuple.src.ip == t->src.ip) &&
++ (km->tuple.dst.ip == t->dst.ip) &&
++ (km->tuple.dst.protonum == t->dst.protonum) &&
++ (km->tuple.dst.u.all == t->dst.u.all));
++}
++
++/* look up the source key for a given tuple */
++static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t)
++{
++ struct ip_ct_gre_keymap *km;
++ u_int32_t key;
++
++ READ_LOCK(&ip_ct_gre_lock);
++ km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn,
++ struct ip_ct_gre_keymap *, t);
++ if (!km) {
++ READ_UNLOCK(&ip_ct_gre_lock);
++ return 0;
++ }
++
++ key = km->tuple.src.u.gre.key;
++ READ_UNLOCK(&ip_ct_gre_lock);
++
++ return key;
++}
++
++/* add a single keymap entry, associate with specified expect */
++int ip_ct_gre_keymap_add(struct ip_conntrack_expect *exp,
++ struct ip_conntrack_tuple *t, int reply)
++{
++ struct ip_ct_gre_keymap *km;
++
++ km = kmalloc(sizeof(*km), GFP_ATOMIC);
++ if (!km)
++ return -1;
++
++ /* initializing list head should be sufficient */
++ memset(km, 0, sizeof(*km));
++
++ memcpy(&km->tuple, t, sizeof(*t));
++
++ if (!reply)
++ exp->proto.gre.keymap_orig = km;
++ else
++ exp->proto.gre.keymap_reply = km;
++
++ DEBUGP("adding new entry %p: ", km);
++ DUMP_TUPLE_GRE(&km->tuple);
++
++ WRITE_LOCK(&ip_ct_gre_lock);
++ list_append(&gre_keymap_list, km);
++ WRITE_UNLOCK(&ip_ct_gre_lock);
++
++ return 0;
++}
++
++/* change the tuple of a keymap entry (used by nat helper) */
++void ip_ct_gre_keymap_change(struct ip_ct_gre_keymap *km,
++ struct ip_conntrack_tuple *t)
++{
++ DEBUGP("changing entry %p to: ", km);
++ DUMP_TUPLE_GRE(t);
++
++ WRITE_LOCK(&ip_ct_gre_lock);
++ memcpy(&km->tuple, t, sizeof(km->tuple));
++ WRITE_UNLOCK(&ip_ct_gre_lock);
++}
++
++/* destroy the keymap entries associated with specified expect */
++void ip_ct_gre_keymap_destroy(struct ip_conntrack_expect *exp)
++{
++ DEBUGP("entering for exp %p\n", exp);
++ WRITE_LOCK(&ip_ct_gre_lock);
++ if (exp->proto.gre.keymap_orig) {
++ DEBUGP("removing %p from list\n", exp->proto.gre.keymap_orig);
++ list_del(&exp->proto.gre.keymap_orig->list);
++ kfree(exp->proto.gre.keymap_orig);
++ exp->proto.gre.keymap_orig = NULL;
++ }
++ if (exp->proto.gre.keymap_reply) {
++ DEBUGP("removing %p from list\n", exp->proto.gre.keymap_reply);
++ list_del(&exp->proto.gre.keymap_reply->list);
++ kfree(exp->proto.gre.keymap_reply);
++ exp->proto.gre.keymap_reply = NULL;
++ }
++ WRITE_UNLOCK(&ip_ct_gre_lock);
++}
++
++
++/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */
++
++/* invert gre part of tuple */
++static int gre_invert_tuple(struct ip_conntrack_tuple *tuple,
++ const struct ip_conntrack_tuple *orig)
++{
++ tuple->dst.u.gre.key = orig->src.u.gre.key;
++ tuple->src.u.gre.key = orig->dst.u.gre.key;
++
++ return 1;
++}
++
++/* gre hdr info to tuple */
++static int gre_pkt_to_tuple(const void *datah, size_t datalen,
++ struct ip_conntrack_tuple *tuple)
++{
++ struct gre_hdr *grehdr = (struct gre_hdr *) datah;
++ struct gre_hdr_pptp *pgrehdr = (struct gre_hdr_pptp *) datah;
++ u_int32_t srckey;
++
++ /* core guarantees 8 protocol bytes, no need for size check */
++
++ switch (grehdr->version) {
++ case GRE_VERSION_1701:
++ if (!grehdr->key) {
++ DEBUGP("Can't track GRE without key\n");
++ return 0;
++ }
++ tuple->dst.u.gre.key = *(gre_key(grehdr));
++ break;
++
++ case GRE_VERSION_PPTP:
++ if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
++ DEBUGP("GRE_VERSION_PPTP but unknown proto\n");
++ return 0;
++ }
++ tuple->dst.u.gre.key = htonl(ntohs(pgrehdr->call_id));
++ break;
++
++ default:
++ printk(KERN_WARNING "unknown GRE version %hu\n",
++ grehdr->version);
++ return 0;
++ }
++
++ srckey = gre_keymap_lookup(tuple);
++
++#if 0
++ DEBUGP("found src key %x for tuple ", ntohl(srckey));
++ DUMP_TUPLE_GRE(tuple);
++#endif
++ tuple->src.u.gre.key = srckey;
++
++ return 1;
++}
++
++/* print gre part of tuple */
++static unsigned int gre_print_tuple(char *buffer,
++ const struct ip_conntrack_tuple *tuple)
++{
++ return sprintf(buffer, "srckey=0x%x dstkey=0x%x ",
++ ntohl(tuple->src.u.gre.key),
++ ntohl(tuple->dst.u.gre.key));
++}
++
++/* print private data for conntrack */
++static unsigned int gre_print_conntrack(char *buffer,
++ const struct ip_conntrack *ct)
++{
++ return sprintf(buffer, "timeout=%u, stream_timeout=%u ",
++ (ct->proto.gre.timeout / HZ),
++ (ct->proto.gre.stream_timeout / HZ));
++}
++
++/* Returns verdict for packet, and may modify conntrack */
++static int gre_packet(struct ip_conntrack *ct,
++ struct iphdr *iph, size_t len,
++ enum ip_conntrack_info conntrackinfo)
++{
++ /* If we've seen traffic both ways, this is a GRE connection.
++ * Extend timeout. */
++ if (ct->status & IPS_SEEN_REPLY) {
++ ip_ct_refresh_acct(ct, ct->proto.gre.stream_timeout);
++ /* Also, more likely to be important, and not a probe. */
++ set_bit(IPS_ASSURED_BIT, &ct->status);
++ } else
++ ip_ct_refresh_acct(ct, ct->proto.gre.timeout);
++
++ return NF_ACCEPT;
++}
++
++/* Called when a new connection for this protocol found. */
++static int gre_new(struct ip_conntrack *ct,
++ struct iphdr *iph, size_t len)
++{
++ DEBUGP(": ");
++ DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++
++ /* initialize to sane value. Ideally a conntrack helper
++ * (e.g. in case of pptp) is increasing them */
++ ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT;
++ ct->proto.gre.timeout = GRE_TIMEOUT;
++
++ return 1;
++}
++
++/* Called when a conntrack entry has already been removed from the hashes
++ * and is about to be deleted from memory */
++static void gre_destroy(struct ip_conntrack *ct)
++{
++ struct ip_conntrack_expect *master = ct->master;
++
++ DEBUGP(" entering\n");
++
++ if (!master) {
++ DEBUGP("no master exp for ct %p\n", ct);
++ return;
++ }
++
++ ip_ct_gre_keymap_destroy(master);
++}
++
++/* protocol helper struct */
++static struct ip_conntrack_protocol gre = { { NULL, NULL }, IPPROTO_GRE,
++ "gre",
++ gre_pkt_to_tuple,
++ gre_invert_tuple,
++ gre_print_tuple,
++ gre_print_conntrack,
++ gre_packet,
++ gre_new,
++ gre_destroy,
++ NULL,
++ THIS_MODULE };
++
++/* ip_conntrack_proto_gre initialization */
++static int __init init(void)
++{
++ int retcode;
++
++ if ((retcode = ip_conntrack_protocol_register(&gre))) {
++ printk(KERN_ERR "Unable to register conntrack protocol "
++ "helper for gre: %d\n", retcode);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ struct list_head *pos, *n;
++
++ /* delete all keymap entries */
++ WRITE_LOCK(&ip_ct_gre_lock);
++ list_for_each_safe(pos, n, &gre_keymap_list) {
++ DEBUGP("deleting keymap %p at module unload time\n", pos);
++ list_del(pos);
++ kfree(pos);
++ }
++ WRITE_UNLOCK(&ip_ct_gre_lock);
++
++ ip_conntrack_protocol_unregister(&gre);
++}
++
++EXPORT_SYMBOL(ip_ct_gre_keymap_add);
++EXPORT_SYMBOL(ip_ct_gre_keymap_change);
++EXPORT_SYMBOL(ip_ct_gre_keymap_destroy);
++
++module_init(init);
++module_exit(fini);
+diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_nat_core.c linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_core.c
+--- linux-2.4.29-old/net/ipv4/netfilter/ip_nat_core.c 2005-01-19 15:10:13.000000000 +0100
++++ linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_core.c 2005-04-02 19:07:18.000000000 +0200
+@@ -424,7 +424,7 @@
+ *tuple = *orig_tuple;
+ while ((rptr = find_best_ips_proto_fast(tuple, mr, conntrack, hooknum))
+ != NULL) {
+- DEBUGP("Found best for "); DUMP_TUPLE(tuple);
++ DEBUGP("Found best for "); DUMP_TUPLE_RAW(tuple);
+ /* 3) The per-protocol part of the manip is made to
+ map into the range to make a unique tuple. */
+
+@@ -564,9 +564,9 @@
+ HOOK2MANIP(hooknum)==IP_NAT_MANIP_SRC ? "SRC" : "DST",
+ conntrack);
+ DEBUGP("Original: ");
+- DUMP_TUPLE(&orig_tp);
++ DUMP_TUPLE_RAW(&orig_tp);
+ DEBUGP("New: ");
+- DUMP_TUPLE(&new_tuple);
++ DUMP_TUPLE_RAW(&new_tuple);
+ #endif
+
+ /* We now have two tuples (SRCIP/SRCPT/DSTIP/DSTPT):
+diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_nat_pptp.c linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_pptp.c
+--- linux-2.4.29-old/net/ipv4/netfilter/ip_nat_pptp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_pptp.c 2005-04-02 19:14:52.000000000 +0200
+@@ -0,0 +1,475 @@
++/*
++ * ip_nat_pptp.c - Version 1.5
++ *
++ * NAT support for PPTP (Point to Point Tunneling Protocol).
++ * PPTP is a a protocol for creating virtual private networks.
++ * It is a specification defined by Microsoft and some vendors
++ * working with Microsoft. PPTP is built on top of a modified
++ * version of the Internet Generic Routing Encapsulation Protocol.
++ * GRE is defined in RFC 1701 and RFC 1702. Documentation of
++ * PPTP can be found in RFC 2637
++ *
++ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
++ *
++ * Development of this code funded by Astaro AG (http://www.astaro.com/)
++ *
++ * TODO: - Support for multiple calls within one session
++ * (needs netfilter newnat code)
++ * - NAT to a unique tuple, not to TCP source port
++ * (needs netfilter tuple reservation)
++ *
++ * Changes:
++ * 2002-02-10 - Version 1.3
++ * - Use ip_nat_mangle_tcp_packet() because of cloned skb's
++ * in local connections (Philip Craig <philipc@snapgear.com>)
++ * - add checks for magicCookie and pptp version
++ * - make argument list of pptp_{out,in}bound_packet() shorter
++ * - move to C99 style initializers
++ * - print version number at module loadtime
++ * 2003-09-22 - Version 1.5
++ * - use SNATed tcp sourceport as callid, since we get called before
++ * TCP header is mangled (Philip Craig <philipc@snapgear.com>)
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <net/tcp.h>
++#include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ip_nat_helper.h>
++#include <linux/netfilter_ipv4/ip_nat_pptp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
++#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
++
++#define IP_NAT_PPTP_VERSION "1.5"
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
++MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
++
++
++#if 0
++#include "ip_conntrack_pptp_priv.h"
++#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
++ ": " format, ## args)
++#else
++#define DEBUGP(format, args...)
++#endif
++
++static unsigned int
++pptp_nat_expected(struct sk_buff **pskb,
++ unsigned int hooknum,
++ struct ip_conntrack *ct,
++ struct ip_nat_info *info)
++{
++ struct ip_conntrack *master = master_ct(ct);
++ struct ip_nat_multi_range mr;
++ struct ip_ct_pptp_master *ct_pptp_info;
++ struct ip_nat_pptp *nat_pptp_info;
++ u_int32_t newip, newcid;
++ int ret;
++
++ IP_NF_ASSERT(info);
++ IP_NF_ASSERT(master);
++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
++
++ DEBUGP("we have a connection!\n");
++
++ LOCK_BH(&ip_pptp_lock);
++ ct_pptp_info = &master->help.ct_pptp_info;
++ nat_pptp_info = &master->nat.help.nat_pptp_info;
++
++ /* need to alter GRE tuple because conntrack expectfn() used 'wrong'
++ * (unmanipulated) values */
++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
++ DEBUGP("completing tuples with NAT info \n");
++ /* we can do this, since we're unconfirmed */
++ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
++ htonl(ct_pptp_info->pac_call_id)) {
++ /* assume PNS->PAC */
++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
++ htonl(nat_pptp_info->pns_call_id);
++ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
++ htonl(nat_pptp_info->pns_call_id);
++ newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
++ newcid = htonl(nat_pptp_info->pac_call_id);
++ } else {
++ /* assume PAC->PNS */
++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
++ htonl(nat_pptp_info->pac_call_id);
++ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
++ htonl(nat_pptp_info->pac_call_id);
++ newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ newcid = htonl(nat_pptp_info->pns_call_id);
++ }
++ } else {
++ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
++ htonl(ct_pptp_info->pac_call_id)) {
++ /* assume PNS->PAC */
++ newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ newcid = htonl(ct_pptp_info->pns_call_id);
++ }
++ else {
++ /* assume PAC->PNS */
++ newip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
++ newcid = htonl(ct_pptp_info->pac_call_id);
++ }
++ }
++
++ mr.rangesize = 1;
++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED;
++ mr.range[0].min_ip = mr.range[0].max_ip = newip;
++ mr.range[0].min = mr.range[0].max =
++ ((union ip_conntrack_manip_proto ) { newcid });
++ DEBUGP("change ip to %u.%u.%u.%u\n",
++ NIPQUAD(newip));
++ DEBUGP("change key to 0x%x\n", ntohl(newcid));
++ ret = ip_nat_setup_info(ct, &mr, hooknum);
++
++ UNLOCK_BH(&ip_pptp_lock);
++
++ return ret;
++
++}
++
++/* outbound packets == from PNS to PAC */
++static inline unsigned int
++pptp_outbound_pkt(struct sk_buff **pskb,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect *exp)
++
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *) iph + iph->ihl*4;
++ struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *)
++ ((void *)tcph + tcph->doff*4);
++
++ struct PptpControlHeader *ctlh;
++ union pptp_ctrl_union pptpReq;
++ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
++ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
++
++ u_int16_t msg, *cid = NULL, new_callid;
++
++ /* FIXME: size checks !!! */
++ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
++ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
++
++ new_callid = htons(ct_pptp_info->pns_call_id);
++
++ switch (msg = ntohs(ctlh->messageType)) {
++ case PPTP_OUT_CALL_REQUEST:
++ cid = &pptpReq.ocreq->callID;
++ /* FIXME: ideally we would want to reserve a call ID
++ * here. current netfilter NAT core is not able to do
++ * this :( For now we use TCP source port. This breaks
++ * multiple calls within one control session */
++
++ /* save original call ID in nat_info */
++ nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id;
++
++ /* don't use tcph->source since we are at a DSTmanip
++ * hook (e.g. PREROUTING) and pkt is not mangled yet */
++ new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port;
++
++ /* save new call ID in ct info */
++ ct_pptp_info->pns_call_id = ntohs(new_callid);
++ break;
++ case PPTP_IN_CALL_REPLY:
++ cid = &pptpReq.icreq->callID;
++ break;
++ case PPTP_CALL_CLEAR_REQUEST:
++ cid = &pptpReq.clrreq->callID;
++ break;
++ default:
++ DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,
++ (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
++ /* fall through */
++
++ case PPTP_SET_LINK_INFO:
++ /* only need to NAT in case PAC is behind NAT box */
++ case PPTP_START_SESSION_REQUEST:
++ case PPTP_START_SESSION_REPLY:
++ case PPTP_STOP_SESSION_REQUEST:
++ case PPTP_STOP_SESSION_REPLY:
++ case PPTP_ECHO_REQUEST:
++ case PPTP_ECHO_REPLY:
++ /* no need to alter packet */
++ return NF_ACCEPT;
++ }
++
++ IP_NF_ASSERT(cid);
++
++ DEBUGP("altering call id from 0x%04x to 0x%04x\n",
++ ntohs(*cid), ntohs(new_callid));
++
++ /* mangle packet */
++ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)cid - (void *)pptph,
++ sizeof(new_callid), (char *)&new_callid,
++ sizeof(new_callid));
++
++ return NF_ACCEPT;
++}
++
++/* inbound packets == from PAC to PNS */
++static inline unsigned int
++pptp_inbound_pkt(struct sk_buff **pskb,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect *oldexp)
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *) iph + iph->ihl*4;
++ struct pptp_pkt_hdr *pptph = (struct pptp_pkt_hdr *)
++ ((void *)tcph + tcph->doff*4);
++
++ struct PptpControlHeader *ctlh;
++ union pptp_ctrl_union pptpReq;
++ struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info;
++ struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info;
++
++ u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL;
++ u_int32_t old_dst_ip;
++
++ struct ip_conntrack_tuple t, inv_t;
++ struct ip_conntrack_tuple *orig_t, *reply_t;
++
++ /* FIXME: size checks !!! */
++ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
++ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
++
++ new_pcid = htons(nat_pptp_info->pns_call_id);
++
++ switch (msg = ntohs(ctlh->messageType)) {
++ case PPTP_OUT_CALL_REPLY:
++ pcid = &pptpReq.ocack->peersCallID;
++ cid = &pptpReq.ocack->callID;
++ if (!oldexp) {
++ DEBUGP("outcall but no expectation\n");
++ break;
++ }
++ old_dst_ip = oldexp->tuple.dst.ip;
++ t = oldexp->tuple;
++ invert_tuplepr(&inv_t, &t);
++
++ /* save original PAC call ID in nat_info */
++ nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id;
++
++ /* alter expectation */
++ orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
++ reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
++ if (t.src.ip == orig_t->src.ip && t.dst.ip == orig_t->dst.ip) {
++ /* expectation for PNS->PAC direction */
++ t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
++ t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
++ inv_t.src.ip = reply_t->src.ip;
++ inv_t.dst.ip = reply_t->dst.ip;
++ inv_t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
++ inv_t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
++ } else {
++ /* expectation for PAC->PNS direction */
++ t.src.u.gre.key = htonl(nat_pptp_info->pac_call_id);
++ t.dst.u.gre.key = htonl(ct_pptp_info->pns_call_id);
++ inv_t.src.ip = orig_t->src.ip;
++ inv_t.dst.ip = orig_t->dst.ip;
++ inv_t.src.u.gre.key = htonl(nat_pptp_info->pns_call_id);
++ inv_t.dst.u.gre.key = htonl(ct_pptp_info->pac_call_id);
++ }
++
++ if (!ip_conntrack_change_expect(oldexp, &t)) {
++ DEBUGP("successfully changed expect\n");
++ } else {
++ DEBUGP("can't change expect\n");
++ }
++ ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_orig, &t);
++ ip_ct_gre_keymap_change(oldexp->proto.gre.keymap_reply, &inv_t);
++ break;
++ case PPTP_IN_CALL_CONNECT:
++ pcid = &pptpReq.iccon->peersCallID;
++ if (!oldexp)
++ break;
++ old_dst_ip = oldexp->tuple.dst.ip;
++ t = oldexp->tuple;
++
++ /* alter expectation, no need for callID */
++ if (t.dst.ip == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip) {
++ /* expectation for PNS->PAC direction */
++ t.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ } else {
++ /* expectation for PAC->PNS direction */
++ t.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ }
++
++ if (!ip_conntrack_change_expect(oldexp, &t)) {
++ DEBUGP("successfully changed expect\n");
++ } else {
++ DEBUGP("can't change expect\n");
++ }
++ break;
++ case PPTP_IN_CALL_REQUEST:
++ /* only need to nat in case PAC is behind NAT box */
++ break;
++ case PPTP_WAN_ERROR_NOTIFY:
++ pcid = &pptpReq.wanerr->peersCallID;
++ break;
++ case PPTP_CALL_DISCONNECT_NOTIFY:
++ pcid = &pptpReq.disc->callID;
++ break;
++
++ default:
++ DEBUGP("unknown inbound packet %s\n",
++ (msg <= PPTP_MSG_MAX)? strMName[msg]:strMName[0]);
++ /* fall through */
++
++ case PPTP_START_SESSION_REQUEST:
++ case PPTP_START_SESSION_REPLY:
++ case PPTP_STOP_SESSION_REQUEST:
++ case PPTP_STOP_SESSION_REPLY:
++ case PPTP_ECHO_REQUEST:
++ case PPTP_ECHO_REPLY:
++ /* no need to alter packet */
++ return NF_ACCEPT;
++ }
++
++ /* mangle packet */
++ IP_NF_ASSERT(pcid);
++ DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
++ ntohs(*pcid), ntohs(new_pcid));
++ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, (void *)pcid - (void *)pptph,
++ sizeof(new_pcid), (char *)&new_pcid,
++ sizeof(new_pcid));
++
++ if (new_cid) {
++ IP_NF_ASSERT(cid);
++ DEBUGP("altering call id from 0x%04x to 0x%04x\n",
++ ntohs(*cid), ntohs(new_cid));
++ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
++ (void *)cid - (void *)pptph,
++ sizeof(new_cid), (char *)&new_cid,
++ sizeof(new_cid));
++ }
++
++ /* great, at least we don't need to resize packets */
++ return NF_ACCEPT;
++}
++
++
++static unsigned int tcp_help(struct ip_conntrack *ct,
++ struct ip_conntrack_expect *exp,
++ struct ip_nat_info *info,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum, struct sk_buff **pskb)
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *) iph + iph->ihl*4;
++ unsigned int datalen = (*pskb)->len - iph->ihl*4 - tcph->doff*4;
++ struct pptp_pkt_hdr *pptph;
++
++ int dir;
++
++ DEBUGP("entering\n");
++
++ /* Only mangle things once: DST for original direction
++ and SRC for reply direction. */
++ dir = CTINFO2DIR(ctinfo);
++ if (!((HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
++ && dir == IP_CT_DIR_ORIGINAL)
++ || (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST
++ && dir == IP_CT_DIR_REPLY))) {
++ DEBUGP("Not touching dir %s at hook %s\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT"
++ : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???");
++ return NF_ACCEPT;
++ }
++
++ /* if packet is too small, just skip it */
++ if (datalen < sizeof(struct pptp_pkt_hdr)+
++ sizeof(struct PptpControlHeader)) {
++ DEBUGP("pptp packet too short\n");
++ return NF_ACCEPT;
++ }
++
++ pptph = (struct pptp_pkt_hdr *) ((void *)tcph + tcph->doff*4);
++
++ /* if it's not a control message, we can't handle it */
++ if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
++ ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
++ DEBUGP("not a pptp control packet\n");
++ return NF_ACCEPT;
++ }
++
++ LOCK_BH(&ip_pptp_lock);
++
++ if (dir == IP_CT_DIR_ORIGINAL) {
++ /* reuqests sent by client to server (PNS->PAC) */
++ pptp_outbound_pkt(pskb, ct, ctinfo, exp);
++ } else {
++ /* response from the server to the client (PAC->PNS) */
++ pptp_inbound_pkt(pskb, ct, ctinfo, exp);
++ }
++
++ UNLOCK_BH(&ip_pptp_lock);
++
++ return NF_ACCEPT;
++}
++
++/* nat helper struct for control connection */
++static struct ip_nat_helper pptp_tcp_helper = {
++ .list = { NULL, NULL },
++ .name = "pptp",
++ .flags = IP_NAT_HELPER_F_ALWAYS,
++ .me = THIS_MODULE,
++ .tuple = { .src = { .ip = 0,
++ .u = { .tcp = { .port =
++ __constant_htons(PPTP_CONTROL_PORT) }
++ }
++ },
++ .dst = { .ip = 0,
++ .u = { .all = 0 },
++ .protonum = IPPROTO_TCP
++ }
++ },
++
++ .mask = { .src = { .ip = 0,
++ .u = { .tcp = { .port = 0xFFFF } }
++ },
++ .dst = { .ip = 0,
++ .u = { .all = 0 },
++ .protonum = 0xFFFF
++ }
++ },
++ .help = tcp_help,
++ .expect = pptp_nat_expected
++};
++
++
++static int __init init(void)
++{
++ DEBUGP("%s: registering NAT helper\n", __FILE__);
++ if (ip_nat_helper_register(&pptp_tcp_helper)) {
++ printk(KERN_ERR "Unable to register NAT application helper "
++ "for pptp\n");
++ return -EIO;
++ }
++
++ printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION);
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ DEBUGP("cleanup_module\n" );
++ ip_nat_helper_unregister(&pptp_tcp_helper);
++ printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION);
++}
++
++module_init(init);
++module_exit(fini);
+diff -urN linux-2.4.29-old/net/ipv4/netfilter/ip_nat_proto_gre.c linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_proto_gre.c
+--- linux-2.4.29-old/net/ipv4/netfilter/ip_nat_proto_gre.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.29-dev/net/ipv4/netfilter/ip_nat_proto_gre.c 2005-04-02 19:15:10.000000000 +0200
+@@ -0,0 +1,202 @@
++/*
++ * ip_nat_proto_gre.c - Version 1.2
++ *
++ * NAT protocol helper module for GRE.
++ *
++ * GRE is a generic encapsulation protocol, which is generally not very
++ * suited for NAT, as it has no protocol-specific part as port numbers.
++ *
++ * It has an optional key field, which may help us distinguishing two
++ * connections between the same two hosts.
++ *
++ * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784
++ *
++ * PPTP is built on top of a modified version of GRE, and has a mandatory
++ * field called "CallID", which serves us for the same purpose as the key
++ * field in plain GRE.
++ *
++ * Documentation about PPTP can be found in RFC 2637
++ *
++ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
++ *
++ * Development of this code funded by Astaro AG (http://www.astaro.com/)
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ip_nat_protocol.h>
++#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
++MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
++
++#if 0
++#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
++ ": " format, ## args)
++#else
++#define DEBUGP(x, args...)
++#endif
++
++/* is key in given range between min and max */
++static int
++gre_in_range(const struct ip_conntrack_tuple *tuple,
++ enum ip_nat_manip_type maniptype,
++ const union ip_conntrack_manip_proto *min,
++ const union ip_conntrack_manip_proto *max)
++{
++ u_int32_t key;
++
++ if (maniptype == IP_NAT_MANIP_SRC)
++ key = tuple->src.u.gre.key;
++ else
++ key = tuple->dst.u.gre.key;
++
++ return ntohl(key) >= ntohl(min->gre.key)
++ && ntohl(key) <= ntohl(max->gre.key);
++}
++
++/* generate unique tuple ... */
++static int
++gre_unique_tuple(struct ip_conntrack_tuple *tuple,
++ const struct ip_nat_range *range,
++ enum ip_nat_manip_type maniptype,
++ const struct ip_conntrack *conntrack)
++{
++ u_int32_t min, i, range_size;
++ u_int32_t key = 0, *keyptr;
++
++ if (maniptype == IP_NAT_MANIP_SRC)
++ keyptr = &tuple->src.u.gre.key;
++ else
++ keyptr = &tuple->dst.u.gre.key;
++
++ if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
++
++ DEBUGP("%p: NATing GRE PPTP\n", conntrack);
++ min = 1;
++ range_size = 0xffff;
++
++ } else {
++ min = ntohl(range->min.gre.key);
++ range_size = ntohl(range->max.gre.key) - min + 1;
++ }
++
++ DEBUGP("min = %u, range_size = %u\n", min, range_size);
++
++ for (i = 0; i < range_size; i++, key++) {
++ *keyptr = htonl(min + key % range_size);
++ if (!ip_nat_used_tuple(tuple, conntrack))
++ return 1;
++ }
++
++ DEBUGP("%p: no NAT mapping\n", conntrack);
++
++ return 0;
++}
++
++/* manipulate a GRE packet according to maniptype */
++static void
++gre_manip_pkt(struct iphdr *iph, size_t len,
++ const struct ip_conntrack_manip *manip,
++ enum ip_nat_manip_type maniptype)
++{
++ struct gre_hdr *greh = (struct gre_hdr *)((u_int32_t *)iph+iph->ihl);
++ struct gre_hdr_pptp *pgreh = (struct gre_hdr_pptp *) greh;
++
++ /* we only have destination manip of a packet, since 'source key'
++ * is not present in the packet itself */
++ if (maniptype == IP_NAT_MANIP_DST) {
++ /* key manipulation is always dest */
++ switch (greh->version) {
++ case 0:
++ if (!greh->key) {
++ DEBUGP("can't nat GRE w/o key\n");
++ break;
++ }
++ if (greh->csum) {
++ /* FIXME: Never tested this code... */
++ *(gre_csum(greh)) =
++ ip_nat_cheat_check(~*(gre_key(greh)),
++ manip->u.gre.key,
++ *(gre_csum(greh)));
++ }
++ *(gre_key(greh)) = manip->u.gre.key;
++ break;
++ case GRE_VERSION_PPTP:
++ DEBUGP("call_id -> 0x%04x\n",
++ ntohl(manip->u.gre.key));
++ pgreh->call_id = htons(ntohl(manip->u.gre.key));
++ break;
++ default:
++ DEBUGP("can't nat unknown GRE version\n");
++ break;
++ }
++ }
++}
++
++/* print out a nat tuple */
++static unsigned int
++gre_print(char *buffer,
++ const struct ip_conntrack_tuple *match,
++ const struct ip_conntrack_tuple *mask)
++{
++ unsigned int len = 0;
++
++ if (mask->src.u.gre.key)
++ len += sprintf(buffer + len, "srckey=0x%x ",
++ ntohl(match->src.u.gre.key));
++
++ if (mask->dst.u.gre.key)
++ len += sprintf(buffer + len, "dstkey=0x%x ",
++ ntohl(match->src.u.gre.key));
++
++ return len;
++}
++
++/* print a range of keys */
++static unsigned int
++gre_print_range(char *buffer, const struct ip_nat_range *range)
++{
++ if (range->min.gre.key != 0
++ || range->max.gre.key != 0xFFFF) {
++ if (range->min.gre.key == range->max.gre.key)
++ return sprintf(buffer, "key 0x%x ",
++ ntohl(range->min.gre.key));
++ else
++ return sprintf(buffer, "keys 0x%u-0x%u ",
++ ntohl(range->min.gre.key),
++ ntohl(range->max.gre.key));
++ } else
++ return 0;
++}
++
++/* nat helper struct */
++static struct ip_nat_protocol gre =
++ { { NULL, NULL }, "GRE", IPPROTO_GRE,
++ gre_manip_pkt,
++ gre_in_range,
++ gre_unique_tuple,
++ gre_print,
++ gre_print_range
++ };
++
++static int __init init(void)
++{
++ if (ip_nat_protocol_register(&gre))
++ return -EIO;
++
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ip_nat_protocol_unregister(&gre);
++}
++
++module_init(init);
++module_exit(fini);
+diff -urN linux-2.4.29-old/net/ipv4/netfilter/Makefile linux-2.4.29-dev/net/ipv4/netfilter/Makefile
+--- linux-2.4.29-old/net/ipv4/netfilter/Makefile 2005-04-02 19:04:11.000000000 +0200
++++ linux-2.4.29-dev/net/ipv4/netfilter/Makefile 2005-04-02 19:07:18.000000000 +0200
+@@ -36,23 +36,32 @@
+ ifdef CONFIG_IP_NF_AMANDA
+ export-objs += ip_conntrack_amanda.o
+ endif
+-
+ obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
+ obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
+ ifdef CONFIG_IP_NF_FTP
+ export-objs += ip_conntrack_ftp.o
+ endif
+-
+ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
+ ifdef CONFIG_IP_NF_IRC
+ export-objs += ip_conntrack_irc.o
+ endif
++obj-$(CONFIG_IP_NF_CT_PROTO_GRE) += ip_conntrack_proto_gre.o
++ifdef CONFIG_IP_NF_CT_PROTO_GRE
++ export-objs += ip_conntrack_proto_gre.o
++endif
++obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o
++ifdef CONFIG_IP_NF_NAT_PPTP
++ export-objs += ip_conntrack_pptp.o
++endif
++
+
+ # NAT helpers
+ obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
+ obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
+ obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
+ obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
++obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o
++obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
+
+ # generic IP tables
+ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
+--- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_pptp.c 1970-01-01 01:00:00.000000000 +0100
++++ /home/florian//openwrt/trunk/openwrt/build_mipsel/linux/net/ipv4/netfilter/ip_conntrack_pptp.c 2006-02-04 18:23:27.000000000 +0100
+@@ -0,0 +1,635 @@
++/*
++ * ip_conntrack_pptp.c - Version 1.9
++ *
++ * Connection tracking support for PPTP (Point to Point Tunneling Protocol).
++ * PPTP is a a protocol for creating virtual private networks.
++ * It is a specification defined by Microsoft and some vendors
++ * working with Microsoft. PPTP is built on top of a modified
++ * version of the Internet Generic Routing Encapsulation Protocol.
++ * GRE is defined in RFC 1701 and RFC 1702. Documentation of
++ * PPTP can be found in RFC 2637
++ *
++ * (C) 2000-2003 by Harald Welte <laforge@gnumonks.org>
++ *
++ * Development of this code funded by Astaro AG (http://www.astaro.com/)
++ *
++ * Limitations:
++ * - We blindly assume that control connections are always
++ * established in PNS->PAC direction. This is a violation
++ * of RFFC2673
++ *
++ * TODO: - finish support for multiple calls within one session
++ * (needs expect reservations in newnat)
++ * - testing of incoming PPTP calls
++ *
++ * Changes:
++ * 2002-02-05 - Version 1.3
++ * - Call ip_conntrack_unexpect_related() from
++ * pptp_timeout_related() to destroy expectations in case
++ * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen
++ * (Philip Craig <philipc@snapgear.com>)
++ * - Add Version information at module loadtime
++ * 2002-02-10 - Version 1.6
++ * - move to C99 style initializers
++ * - remove second expectation if first arrives
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <net/tcp.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h>
++#include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
++
++#define IP_CT_PPTP_VERSION "1.9"
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
++MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
++
++DECLARE_LOCK(ip_pptp_lock);
++
++#if 0
++#include "ip_conntrack_pptp_priv.h"
++#define DEBUGP(format, args...) printk(KERN_DEBUG __FILE__ ":" __FUNCTION__ \
++ ": " format, ## args)
++#else
++#define DEBUGP(format, args...)
++#endif
++
++#define SECS *HZ
++#define MINS * 60 SECS
++#define HOURS * 60 MINS
++#define DAYS * 24 HOURS
++
++#define PPTP_GRE_TIMEOUT (10 MINS)
++#define PPTP_GRE_STREAM_TIMEOUT (5 DAYS)
++
++static int pptp_expectfn(struct ip_conntrack *ct)
++{
++ struct ip_conntrack *master;
++ struct ip_conntrack_expect *exp;
++
++ DEBUGP("increasing timeouts\n");
++ /* increase timeout of GRE data channel conntrack entry */
++ ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
++ ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT;
++
++ master = master_ct(ct);
++ if (!master) {
++ DEBUGP(" no master!!!\n");
++ return 0;
++ }
++
++ exp = ct->master;
++ if (!exp) {
++ DEBUGP("no expectation!!\n");
++ return 0;
++ }
++
++ DEBUGP("completing tuples with ct info\n");
++ /* we can do this, since we're unconfirmed */
++ if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.gre.key ==
++ htonl(master->help.ct_pptp_info.pac_call_id)) {
++ /* assume PNS->PAC */
++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
++ htonl(master->help.ct_pptp_info.pns_call_id);
++ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
++ htonl(master->help.ct_pptp_info.pns_call_id);
++ } else {
++ /* assume PAC->PNS */
++ ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.gre.key =
++ htonl(master->help.ct_pptp_info.pac_call_id);
++ ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.gre.key =
++ htonl(master->help.ct_pptp_info.pac_call_id);
++ }
++
++ /* delete other expectation */
++ if (exp->expected_list.next != &exp->expected_list) {
++ struct ip_conntrack_expect *other_exp;
++ struct list_head *cur_item, *next;
++
++ for (cur_item = master->sibling_list.next;
++ cur_item != &master->sibling_list; cur_item = next) {
++ next = cur_item->next;
++ other_exp = list_entry(cur_item,
++ struct ip_conntrack_expect,
++ expected_list);
++ /* remove only if occurred at same sequence number */
++ if (other_exp != exp && other_exp->seq == exp->seq) {
++ DEBUGP("unexpecting other direction\n");
++ ip_ct_gre_keymap_destroy(other_exp);
++ ip_conntrack_unexpect_related(other_exp);
++ }
++ }
++ }
++
++ return 0;
++}
++
++/* timeout GRE data connections */
++static int pptp_timeout_related(struct ip_conntrack *ct)
++{
++ struct list_head *cur_item, *next;
++ struct ip_conntrack_expect *exp;
++ enum ip_conntrack_info ctinfo;
++ struct iphdr *iph;
++
++ /* FIXME: do we have to lock something ? */
++ for (cur_item = ct->sibling_list.next;
++ cur_item != &ct->sibling_list; cur_item = next) {
++ next = cur_item->next;
++ exp = list_entry(cur_item, struct ip_conntrack_expect,
++ expected_list);
++
++ ip_ct_gre_keymap_destroy(exp);
++ if (!exp->sibling) {
++ ip_conntrack_unexpect_related(exp);
++ continue;
++ }
++
++ DEBUGP("setting timeout of conntrack %p to 0\n",
++ exp->sibling);
++ exp->sibling->proto.gre.timeout = 0;
++ exp->sibling->proto.gre.stream_timeout = 0;
++ ip_ct_refresh_acct(exp->sibling, ctinfo, iph, 0);
++ }
++
++ return 0;
++}
++
++/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
++static inline int
++exp_gre(struct ip_conntrack *master,
++ u_int32_t seq,
++ u_int16_t callid,
++ u_int16_t peer_callid)
++{
++ struct ip_conntrack_expect exp;
++ struct ip_conntrack_tuple inv_tuple;
++
++ memset(&exp, 0, sizeof(exp));
++ /* tuple in original direction, PNS->PAC */
++ exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ exp.tuple.src.u.gre.key = htonl(ntohs(peer_callid));
++ exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
++ exp.tuple.dst.u.gre.key = htonl(ntohs(callid));
++ exp.tuple.dst.protonum = IPPROTO_GRE;
++
++ exp.mask.src.ip = 0xffffffff;
++ exp.mask.src.u.all = 0;
++ exp.mask.dst.u.all = 0;
++ exp.mask.dst.u.gre.key = 0xffffffff;
++ exp.mask.dst.ip = 0xffffffff;
++ exp.mask.dst.protonum = 0xffff;
++
++ exp.seq = seq;
++ exp.expectfn = pptp_expectfn;
++
++ exp.help.exp_pptp_info.pac_call_id = ntohs(callid);
++ exp.help.exp_pptp_info.pns_call_id = ntohs(peer_callid);
++
++ DEBUGP("calling expect_related ");
++ DUMP_TUPLE_RAW(&exp.tuple);
++
++ /* Add GRE keymap entries */
++ if (ip_ct_gre_keymap_add(&exp, &exp.tuple, 0) != 0)
++ return 1;
++
++ invert_tuplepr(&inv_tuple, &exp.tuple);
++ if (ip_ct_gre_keymap_add(&exp, &inv_tuple, 1) != 0) {
++ ip_ct_gre_keymap_destroy(&exp);
++ return 1;
++ }
++
++ if (ip_conntrack_expect_related(master, &exp) != 0) {
++ ip_ct_gre_keymap_destroy(&exp);
++ DEBUGP("cannot expect_related()\n");
++ return 1;
++ }
++
++ /* tuple in reply direction, PAC->PNS */
++ exp.tuple.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
++ exp.tuple.src.u.gre.key = htonl(ntohs(callid));
++ exp.tuple.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ exp.tuple.dst.u.gre.key = htonl(ntohs(peer_callid));
++
++ DEBUGP("calling expect_related ");
++ DUMP_TUPLE_RAW(&exp.tuple);
++
++ /* Add GRE keymap entries */
++ ip_ct_gre_keymap_add(&exp, &exp.tuple, 0);
++ invert_tuplepr(&inv_tuple, &exp.tuple);
++ ip_ct_gre_keymap_add(&exp, &inv_tuple, 1);
++ /* FIXME: cannot handle error correctly, since we need to free
++ * the above keymap :( */
++
++ if (ip_conntrack_expect_related(master, &exp) != 0) {
++ /* free the second pair of keypmaps */
++ ip_ct_gre_keymap_destroy(&exp);
++ DEBUGP("cannot expect_related():\n");
++ return 1;
++ }
++
++ return 0;
++}
++
++static inline int
++pptp_inbound_pkt(struct tcphdr *tcph,
++ struct pptp_pkt_hdr *pptph,
++ size_t datalen,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo)
++{
++ struct PptpControlHeader *ctlh;
++ union pptp_ctrl_union pptpReq;
++
++ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
++ u_int16_t msg, *cid, *pcid;
++ u_int32_t seq;
++
++ ctlh = (struct PptpControlHeader *)
++ ((char *) pptph + sizeof(struct pptp_pkt_hdr));
++ pptpReq.rawreq = (void *)
++ ((char *) ctlh + sizeof(struct PptpControlHeader));
++
++ msg = ntohs(ctlh->messageType);
++ DEBUGP("inbound control message %s\n", strMName[msg]);
++
++ switch (msg) {
++ case PPTP_START_SESSION_REPLY:
++ /* server confirms new control session */
++ if (info->sstate < PPTP_SESSION_REQUESTED) {
++ DEBUGP("%s without START_SESS_REQUEST\n",
++ strMName[msg]);
++ break;
++ }
++ if (pptpReq.srep->resultCode == PPTP_START_OK)
++ info->sstate = PPTP_SESSION_CONFIRMED;
++ else
++ info->sstate = PPTP_SESSION_ERROR;
++ break;
++
++ case PPTP_STOP_SESSION_REPLY:
++ /* server confirms end of control session */
++ if (info->sstate > PPTP_SESSION_STOPREQ) {
++ DEBUGP("%s without STOP_SESS_REQUEST\n",
++ strMName[msg]);
++ break;
++ }
++ if (pptpReq.strep->resultCode == PPTP_STOP_OK)
++ info->sstate = PPTP_SESSION_NONE;
++ else
++ info->sstate = PPTP_SESSION_ERROR;
++ break;
++
++ case PPTP_OUT_CALL_REPLY:
++ /* server accepted call, we now expect GRE frames */
++ if (info->sstate != PPTP_SESSION_CONFIRMED) {
++ DEBUGP("%s but no session\n", strMName[msg]);
++ break;
++ }
++ if (info->cstate != PPTP_CALL_OUT_REQ &&
++ info->cstate != PPTP_CALL_OUT_CONF) {
++ DEBUGP("%s without OUTCALL_REQ\n", strMName[msg]);
++ break;
++ }
++ if (pptpReq.ocack->resultCode != PPTP_OUTCALL_CONNECT) {
++ info->cstate = PPTP_CALL_NONE;
++ break;
++ }
++
++ cid = &pptpReq.ocack->callID;
++ pcid = &pptpReq.ocack->peersCallID;
++
++ info->pac_call_id = ntohs(*cid);
++
++ if (htons(info->pns_call_id) != *pcid) {
++ DEBUGP("%s for unknown callid %u\n",
++ strMName[msg], ntohs(*pcid));
++ break;
++ }
++
++ DEBUGP("%s, CID=%X, PCID=%X\n", strMName[msg],
++ ntohs(*cid), ntohs(*pcid));
++
++ info->cstate = PPTP_CALL_OUT_CONF;
++
++ seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
++ if (exp_gre(ct, seq, *cid, *pcid) != 0)
++ printk("ip_conntrack_pptp: error during exp_gre\n");
++ break;
++
++ case PPTP_IN_CALL_REQUEST:
++ /* server tells us about incoming call request */
++ if (info->sstate != PPTP_SESSION_CONFIRMED) {
++ DEBUGP("%s but no session\n", strMName[msg]);
++ break;
++ }
++ pcid = &pptpReq.icack->peersCallID;
++ DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
++ info->cstate = PPTP_CALL_IN_REQ;
++ info->pac_call_id= ntohs(*pcid);
++ break;
++
++ case PPTP_IN_CALL_CONNECT:
++ /* server tells us about incoming call established */
++ if (info->sstate != PPTP_SESSION_CONFIRMED) {
++ DEBUGP("%s but no session\n", strMName[msg]);
++ break;
++ }
++ if (info->sstate != PPTP_CALL_IN_REP
++ && info->sstate != PPTP_CALL_IN_CONF) {
++ DEBUGP("%s but never sent IN_CALL_REPLY\n",
++ strMName[msg]);
++ break;
++ }
++
++ pcid = &pptpReq.iccon->peersCallID;
++ cid = &info->pac_call_id;
++
++ if (info->pns_call_id != ntohs(*pcid)) {
++ DEBUGP("%s for unknown CallID %u\n",
++ strMName[msg], ntohs(*cid));
++ break;
++ }
++
++ DEBUGP("%s, PCID=%X\n", strMName[msg], ntohs(*pcid));
++ info->cstate = PPTP_CALL_IN_CONF;
++
++ /* we expect a GRE connection from PAC to PNS */
++ seq = ntohl(tcph->seq) + ((void *)pcid - (void *)pptph);
++ if (exp_gre(ct, seq, *cid, *pcid) != 0)
++ printk("ip_conntrack_pptp: error during exp_gre\n");
++
++ break;
++
++ case PPTP_CALL_DISCONNECT_NOTIFY:
++ /* server confirms disconnect */
++ cid = &pptpReq.disc->callID;
++ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
++ info->cstate = PPTP_CALL_NONE;
++
++ /* untrack this call id, unexpect GRE packets */
++ pptp_timeout_related(ct);
++ break;
++
++ case PPTP_WAN_ERROR_NOTIFY:
++ break;
++
++ case PPTP_ECHO_REQUEST:
++ case PPTP_ECHO_REPLY:
++ /* I don't have to explain these ;) */
++ break;
++ default:
++ DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)
++ ? strMName[msg]:strMName[0], msg);
++ break;
++ }
++
++ return NF_ACCEPT;
++
++}
++
++static inline int
++pptp_outbound_pkt(struct tcphdr *tcph,
++ struct pptp_pkt_hdr *pptph,
++ size_t datalen,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo)
++{
++ struct PptpControlHeader *ctlh;
++ union pptp_ctrl_union pptpReq;
++ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
++ u_int16_t msg, *cid, *pcid;
++
++ ctlh = (struct PptpControlHeader *) ((void *) pptph + sizeof(*pptph));
++ pptpReq.rawreq = (void *) ((void *) ctlh + sizeof(*ctlh));
++
++ msg = ntohs(ctlh->messageType);
++ DEBUGP("outbound control message %s\n", strMName[msg]);
++
++ switch (msg) {
++ case PPTP_START_SESSION_REQUEST:
++ /* client requests for new control session */
++ if (info->sstate != PPTP_SESSION_NONE) {
++ DEBUGP("%s but we already have one",
++ strMName[msg]);
++ }
++ info->sstate = PPTP_SESSION_REQUESTED;
++ break;
++ case PPTP_STOP_SESSION_REQUEST:
++ /* client requests end of control session */
++ info->sstate = PPTP_SESSION_STOPREQ;
++ break;
++
++ case PPTP_OUT_CALL_REQUEST:
++ /* client initiating connection to server */
++ if (info->sstate != PPTP_SESSION_CONFIRMED) {
++ DEBUGP("%s but no session\n",
++ strMName[msg]);
++ break;
++ }
++ info->cstate = PPTP_CALL_OUT_REQ;
++ /* track PNS call id */
++ cid = &pptpReq.ocreq->callID;
++ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*cid));
++ info->pns_call_id = ntohs(*cid);
++ break;
++ case PPTP_IN_CALL_REPLY:
++ /* client answers incoming call */
++ if (info->cstate != PPTP_CALL_IN_REQ
++ && info->cstate != PPTP_CALL_IN_REP) {
++ DEBUGP("%s without incall_req\n",
++ strMName[msg]);
++ break;
++ }
++ if (pptpReq.icack->resultCode != PPTP_INCALL_ACCEPT) {
++ info->cstate = PPTP_CALL_NONE;
++ break;
++ }
++ pcid = &pptpReq.icack->peersCallID;
++ if (info->pac_call_id != ntohs(*pcid)) {
++ DEBUGP("%s for unknown call %u\n",
++ strMName[msg], ntohs(*pcid));
++ break;
++ }
++ DEBUGP("%s, CID=%X\n", strMName[msg], ntohs(*pcid));
++ /* part two of the three-way handshake */
++ info->cstate = PPTP_CALL_IN_REP;
++ info->pns_call_id = ntohs(pptpReq.icack->callID);
++ break;
++
++ case PPTP_CALL_CLEAR_REQUEST:
++ /* client requests hangup of call */
++ if (info->sstate != PPTP_SESSION_CONFIRMED) {
++ DEBUGP("CLEAR_CALL but no session\n");
++ break;
++ }
++ /* FUTURE: iterate over all calls and check if
++ * call ID is valid. We don't do this without newnat,
++ * because we only know about last call */
++ info->cstate = PPTP_CALL_CLEAR_REQ;
++ break;
++ case PPTP_SET_LINK_INFO:
++ break;
++ case PPTP_ECHO_REQUEST:
++ case PPTP_ECHO_REPLY:
++ /* I don't have to explain these ;) */
++ break;
++ default:
++ DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)?
++ strMName[msg]:strMName[0], msg);
++ /* unknown: no need to create GRE masq table entry */
++ break;
++ }
++
++ return NF_ACCEPT;
++}
++
++
++/* track caller id inside control connection, call expect_related */
++static int
++conntrack_pptp_help(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
++
++{
++ struct pptp_pkt_hdr *pptph;
++
++ struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
++ u_int32_t tcplen = len - iph->ihl * 4;
++ u_int32_t datalen = tcplen - tcph->doff * 4;
++ void *datalimit;
++ int dir = CTINFO2DIR(ctinfo);
++ struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info;
++
++ int oldsstate, oldcstate;
++ int ret;
++
++ /* don't do any tracking before tcp handshake complete */
++ if (ctinfo != IP_CT_ESTABLISHED
++ && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
++ DEBUGP("ctinfo = %u, skipping\n", ctinfo);
++ return NF_ACCEPT;
++ }
++
++ /* not a complete TCP header? */
++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) {
++ DEBUGP("tcplen = %u\n", tcplen);
++ return NF_ACCEPT;
++ }
++
++ /* checksum invalid? */
++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++ csum_partial((char *) tcph, tcplen, 0))) {
++ printk(KERN_NOTICE __FILE__ ": bad csum\n");
++ /* W2K PPTP server sends TCP packets with wrong checksum :(( */
++ //return NF_ACCEPT;
++ }
++
++ if (tcph->fin || tcph->rst) {
++ DEBUGP("RST/FIN received, timeouting GRE\n");
++ /* can't do this after real newnat */
++ info->cstate = PPTP_CALL_NONE;
++
++ /* untrack this call id, unexpect GRE packets */
++ pptp_timeout_related(ct);
++ }
++
++
++ pptph = (struct pptp_pkt_hdr *) ((void *) tcph + tcph->doff * 4);
++ datalimit = (void *) pptph + datalen;
++
++ /* not a full pptp packet header? */
++ if ((void *) pptph+sizeof(*pptph) >= datalimit) {
++ DEBUGP("no full PPTP header, can't track\n");
++ return NF_ACCEPT;
++ }
++
++ /* if it's not a control message we can't do anything with it */
++ if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
++ ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
++ DEBUGP("not a control packet\n");
++ return NF_ACCEPT;
++ }
++
++ oldsstate = info->sstate;
++ oldcstate = info->cstate;
++
++ LOCK_BH(&ip_pptp_lock);
++
++ /* FIXME: We just blindly assume that the control connection is always
++ * established from PNS->PAC. However, RFC makes no guarantee */
++ if (dir == IP_CT_DIR_ORIGINAL)
++ /* client -> server (PNS -> PAC) */
++ ret = pptp_outbound_pkt(tcph, pptph, datalen, ct, ctinfo);
++ else
++ /* server -> client (PAC -> PNS) */
++ ret = pptp_inbound_pkt(tcph, pptph, datalen, ct, ctinfo);
++ DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
++ oldsstate, info->sstate, oldcstate, info->cstate);
++ UNLOCK_BH(&ip_pptp_lock);
++
++ return ret;
++}
++
++/* control protocol helper */
++static struct ip_conntrack_helper pptp = {
++ .list = { NULL, NULL },
++ .name = "pptp",
++ .flags = IP_CT_HELPER_F_REUSE_EXPECT,
++ .me = THIS_MODULE,
++ .max_expected = 2,
++ .timeout = 0,
++ .tuple = { .src = { .ip = 0,
++ .u = { .tcp = { .port =
++ __constant_htons(PPTP_CONTROL_PORT) } }
++ },
++ .dst = { .ip = 0,
++ .u = { .all = 0 },
++ .protonum = IPPROTO_TCP
++ }
++ },
++ .mask = { .src = { .ip = 0,
++ .u = { .tcp = { .port = 0xffff } }
++ },
++ .dst = { .ip = 0,
++ .u = { .all = 0 },
++ .protonum = 0xffff
++ }
++ },
++ .help = conntrack_pptp_help
++};
++
++/* ip_conntrack_pptp initialization */
++static int __init init(void)
++{
++ int retcode;
++
++ DEBUGP(__FILE__ ": registering helper\n");
++ if ((retcode = ip_conntrack_helper_register(&pptp))) {
++ printk(KERN_ERR "Unable to register conntrack application "
++ "helper for pptp: %d\n", retcode);
++ return -EIO;
++ }
++
++ printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION);
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ip_conntrack_helper_unregister(&pptp);
++ printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION);
++}
++
++module_init(init);
++module_exit(fini);
++
++EXPORT_SYMBOL(ip_pptp_lock);
diff --git a/target/linux/generic-2.4/patches/604-netfilter_maxconn.patch b/target/linux/generic-2.4/patches/604-netfilter_maxconn.patch
new file mode 100644
index 0000000..001ed67
--- /dev/null
+++ b/target/linux/generic-2.4/patches/604-netfilter_maxconn.patch
@@ -0,0 +1,20 @@
+--- ../../buildroot-unpacked/build_mipsel/linux/net/ipv4/netfilter/ip_conntrack_core.c 2004-11-28 22:59:36.000000000 -0500
++++ linux/net/ipv4/netfilter/ip_conntrack_core.c 2004-11-30 05:05:32.000000000 -0500
+@@ -1386,7 +1386,7 @@
+ nf_unregister_sockopt(&so_getorigdst);
+ }
+
+-static int hashsize = 0;
++static int hashsize = 5953;
+ MODULE_PARM(hashsize, "i");
+
+ int __init ip_conntrack_init(void)
+@@ -1407,7 +1407,7 @@
+ if (ip_conntrack_htable_size < 16)
+ ip_conntrack_htable_size = 16;
+ }
+- ip_conntrack_max = 8 * ip_conntrack_htable_size;
++ ip_conntrack_max = ip_conntrack_htable_size;
+
+ printk("ip_conntrack version %s (%u buckets, %d max)"
+ " - %Zd bytes per conntrack\n", IP_CONNTRACK_VERSION,
diff --git a/target/linux/generic-2.4/patches/605-netfilter_TTL.patch b/target/linux/generic-2.4/patches/605-netfilter_TTL.patch
new file mode 100644
index 0000000..0aa3c80
--- /dev/null
+++ b/target/linux/generic-2.4/patches/605-netfilter_TTL.patch
@@ -0,0 +1,180 @@
+diff -urN linux-2.4.30.old/Documentation/Configure.help linux-2.4.30.dev/Documentation/Configure.help
+--- linux-2.4.30.old/Documentation/Configure.help 2005-04-27 11:35:46.000000000 +0200
++++ linux-2.4.30.dev/Documentation/Configure.help 2005-04-27 11:43:49.000000000 +0200
+@@ -3209,6 +3209,15 @@
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
++TTL target support
++CONFIG_IP_NF_TARGET_TTL
++ This option adds a `TTL' target, which enables the user to set
++ the TTL value or increment / decrement the TTL value by a given
++ amount.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
+ ipchains (2.2-style) support
+ CONFIG_IP_NF_COMPAT_IPCHAINS
+ This option places ipchains (with masquerading and redirection
+diff -urN linux-2.4.30.old/include/linux/netfilter_ipv4/ipt_TTL.h linux-2.4.30.dev/include/linux/netfilter_ipv4/ipt_TTL.h
+--- linux-2.4.30.old/include/linux/netfilter_ipv4/ipt_TTL.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.30.dev/include/linux/netfilter_ipv4/ipt_TTL.h 2005-04-27 11:43:49.000000000 +0200
+@@ -0,0 +1,21 @@
++/* TTL modification module for IP tables
++ * (C) 2000 by Harald Welte <laforge@gnumonks.org> */
++
++#ifndef _IPT_TTL_H
++#define _IPT_TTL_H
++
++enum {
++ IPT_TTL_SET = 0,
++ IPT_TTL_INC,
++ IPT_TTL_DEC
++};
++
++#define IPT_TTL_MAXMODE IPT_TTL_DEC
++
++struct ipt_TTL_info {
++ u_int8_t mode;
++ u_int8_t ttl;
++};
++
++
++#endif
+diff -urN linux-2.4.30.old/net/ipv4/netfilter/Config.in linux-2.4.30.dev/net/ipv4/netfilter/Config.in
+--- linux-2.4.30.old/net/ipv4/netfilter/Config.in 2005-04-27 11:35:45.000000000 +0200
++++ linux-2.4.30.dev/net/ipv4/netfilter/Config.in 2005-04-27 11:43:49.000000000 +0200
+@@ -129,6 +129,7 @@
+ dep_tristate ' MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
+ fi
+ dep_tristate ' LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
++ dep_tristate ' TTL target support' CONFIG_IP_NF_TARGET_TTL $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' TCPMSS target support' CONFIG_IP_NF_TARGET_TCPMSS $CONFIG_IP_NF_IPTABLES
+ fi
+diff -urN linux-2.4.30.old/net/ipv4/netfilter/ipt_TTL.c linux-2.4.30.dev/net/ipv4/netfilter/ipt_TTL.c
+--- linux-2.4.30.old/net/ipv4/netfilter/ipt_TTL.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.30.dev/net/ipv4/netfilter/ipt_TTL.c 2005-04-27 11:43:49.000000000 +0200
+@@ -0,0 +1,110 @@
++/* TTL modification target for IP tables
++ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
++ *
++ * Version: $Revision: 1.1 $
++ *
++ * This software is distributed under the terms of GNU GPL
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_TTL.h>
++
++MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
++MODULE_DESCRIPTION("IP tables TTL modification module");
++MODULE_LICENSE("GPL");
++
++static unsigned int ipt_ttl_target(struct sk_buff **pskb, unsigned int hooknum,
++ const struct net_device *in, const struct net_device *out,
++ const void *targinfo, void *userinfo)
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ const struct ipt_TTL_info *info = targinfo;
++ u_int16_t diffs[2];
++ int new_ttl;
++
++ switch (info->mode) {
++ case IPT_TTL_SET:
++ new_ttl = info->ttl;
++ break;
++ case IPT_TTL_INC:
++ new_ttl = iph->ttl + info->ttl;
++ if (new_ttl > 255)
++ new_ttl = 255;
++ break;
++ case IPT_TTL_DEC:
++ new_ttl = iph->ttl - info->ttl;
++ if (new_ttl < 0)
++ new_ttl = 0;
++ break;
++ default:
++ new_ttl = iph->ttl;
++ break;
++ }
++
++ if (new_ttl != iph->ttl) {
++ diffs[0] = htons(((unsigned)iph->ttl) << 8) ^ 0xFFFF;
++ iph->ttl = new_ttl;
++ diffs[1] = htons(((unsigned)iph->ttl) << 8);
++ iph->check = csum_fold(csum_partial((char *)diffs,
++ sizeof(diffs),
++ iph->check^0xFFFF));
++ (*pskb)->nfcache |= NFC_ALTERED;
++ }
++
++ return IPT_CONTINUE;
++}
++
++static int ipt_ttl_checkentry(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ struct ipt_TTL_info *info = targinfo;
++
++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_TTL_info))) {
++ printk(KERN_WARNING "TTL: targinfosize %u != %Zu\n",
++ targinfosize,
++ IPT_ALIGN(sizeof(struct ipt_TTL_info)));
++ return 0;
++ }
++
++ if (strcmp(tablename, "mangle")) {
++ printk(KERN_WARNING "TTL: can only be called from \"mangle\" table, not \"%s\"\n", tablename);
++ return 0;
++ }
++
++ if (info->mode > IPT_TTL_MAXMODE) {
++ printk(KERN_WARNING "TTL: invalid or unknown Mode %u\n",
++ info->mode);
++ return 0;
++ }
++
++ if ((info->mode != IPT_TTL_SET) && (info->ttl == 0)) {
++ printk(KERN_WARNING "TTL: increment/decrement doesn't make sense with value 0\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_target ipt_TTL = { { NULL, NULL }, "TTL",
++ ipt_ttl_target, ipt_ttl_checkentry, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++ return ipt_register_target(&ipt_TTL);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&ipt_TTL);
++}
++
++module_init(init);
++module_exit(fini);
+diff -urN linux-2.4.30.old/net/ipv4/netfilter/Makefile linux-2.4.30.dev/net/ipv4/netfilter/Makefile
+--- linux-2.4.30.old/net/ipv4/netfilter/Makefile 2005-04-27 11:35:45.000000000 +0200
++++ linux-2.4.30.dev/net/ipv4/netfilter/Makefile 2005-04-27 11:43:49.000000000 +0200
+@@ -112,6 +112,7 @@
+ obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+ obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
+ obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
++obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
+ obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
+ obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
+
diff --git a/target/linux/generic-2.4/patches/606-netfilter_NETMAP.patch b/target/linux/generic-2.4/patches/606-netfilter_NETMAP.patch
new file mode 100644
index 0000000..ccd6391
--- /dev/null
+++ b/target/linux/generic-2.4/patches/606-netfilter_NETMAP.patch
@@ -0,0 +1,159 @@
+diff -urN linux-2.4.30.orig/Documentation/Configure.help linux-2.4.30/Documentation/Configure.help
+--- linux-2.4.30.orig/Documentation/Configure.help 2005-07-01 02:06:36.000000000 +0200
++++ linux-2.4.30/Documentation/Configure.help 2005-07-01 00:41:09.000000000 +0200
+@@ -3086,6 +3086,17 @@
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
++NETMAP target support
++CONFIG_IP_NF_TARGET_NETMAP
++ NETMAP is an implementation of static 1:1 NAT mapping of network
++ addresses. It maps the network address part, while keeping the
++ host address part intact. It is similar to Fast NAT, except that
++ Netfilter's connection tracking doesn't work well with Fast NAT.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. The module will be called
++ ipt_NETMAP.o. If unsure, say `N'.
++
+ Packet mangling
+ CONFIG_IP_NF_MANGLE
+ This option adds a `mangle' table to iptables: see the man page for
+diff -urN linux-2.4.30.orig/net/ipv4/netfilter/Config.in linux-2.4.30/net/ipv4/netfilter/Config.in
+--- linux-2.4.30.orig/net/ipv4/netfilter/Config.in 2005-07-01 02:06:35.000000000 +0200
++++ linux-2.4.30/net/ipv4/netfilter/Config.in 2005-07-01 00:41:09.000000000 +0200
+@@ -69,6 +69,7 @@
+ define_bool CONFIG_IP_NF_NAT_NEEDED y
+ dep_tristate ' MASQUERADE target support' CONFIG_IP_NF_TARGET_MASQUERADE $CONFIG_IP_NF_NAT
+ dep_tristate ' REDIRECT target support' CONFIG_IP_NF_TARGET_REDIRECT $CONFIG_IP_NF_NAT
++ dep_tristate ' NETMAP target support' CONFIG_IP_NF_TARGET_NETMAP $CONFIG_IP_NF_NAT
+ if [ "$CONFIG_IP_NF_PPTP" = "m" ]; then
+ define_tristate CONFIG_IP_NF_NAT_PPTP m
+ else
+diff -urN linux-2.4.30.orig/net/ipv4/netfilter/ipt_NETMAP.c linux-2.4.30/net/ipv4/netfilter/ipt_NETMAP.c
+--- linux-2.4.30.orig/net/ipv4/netfilter/ipt_NETMAP.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.30/net/ipv4/netfilter/ipt_NETMAP.c 2005-07-01 00:41:09.000000000 +0200
+@@ -0,0 +1,112 @@
++/* NETMAP - static NAT mapping of IP network addresses (1:1).
++ The mapping can be applied to source (POSTROUTING),
++ destination (PREROUTING), or both (with separate rules).
++
++ Author: Svenning Soerensen <svenning@post5.tele.dk>
++*/
++
++#include <linux/config.h>
++#include <linux/ip.h>
++#include <linux/module.h>
++#include <linux/netdevice.h>
++#include <linux/netfilter.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++
++#define MODULENAME "NETMAP"
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>");
++MODULE_DESCRIPTION("iptables 1:1 NAT mapping of IP networks target");
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++static int
++check(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ const struct ip_nat_multi_range *mr = targinfo;
++
++ if (strcmp(tablename, "nat") != 0) {
++ DEBUGP(MODULENAME":check: bad table `%s'.\n", tablename);
++ return 0;
++ }
++ if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
++ DEBUGP(MODULENAME":check: size %u.\n", targinfosize);
++ return 0;
++ }
++ if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING))) {
++ DEBUGP(MODULENAME":check: bad hooks %x.\n", hook_mask);
++ return 0;
++ }
++ if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) {
++ DEBUGP(MODULENAME":check: bad MAP_IPS.\n");
++ return 0;
++ }
++ if (mr->rangesize != 1) {
++ DEBUGP(MODULENAME":check: bad rangesize %u.\n", mr->rangesize);
++ return 0;
++ }
++ return 1;
++}
++
++static unsigned int
++target(struct sk_buff **pskb,
++ unsigned int hooknum,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *targinfo,
++ void *userinfo)
++{
++ struct ip_conntrack *ct;
++ enum ip_conntrack_info ctinfo;
++ u_int32_t new_ip, netmask;
++ const struct ip_nat_multi_range *mr = targinfo;
++ struct ip_nat_multi_range newrange;
++
++ IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
++ || hooknum == NF_IP_POST_ROUTING);
++ ct = ip_conntrack_get(*pskb, &ctinfo);
++
++ netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip);
++
++ if (hooknum == NF_IP_PRE_ROUTING)
++ new_ip = (*pskb)->nh.iph->daddr & ~netmask;
++ else
++ new_ip = (*pskb)->nh.iph->saddr & ~netmask;
++ new_ip |= mr->range[0].min_ip & netmask;
++
++ newrange = ((struct ip_nat_multi_range)
++ { 1, { { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS,
++ new_ip, new_ip,
++ mr->range[0].min, mr->range[0].max } } });
++
++ /* Hand modified range to generic setup. */
++ return ip_nat_setup_info(ct, &newrange, hooknum);
++}
++
++static struct ipt_target target_module = {
++ .name = MODULENAME,
++ .target = target,
++ .checkentry = check,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_target(&target_module);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&target_module);
++}
++
++module_init(init);
++module_exit(fini);
+diff -urN linux-2.4.30.orig/net/ipv4/netfilter/Makefile linux-2.4.30/net/ipv4/netfilter/Makefile
+--- linux-2.4.30.orig/net/ipv4/netfilter/Makefile 2005-07-01 02:06:35.000000000 +0200
++++ linux-2.4.30/net/ipv4/netfilter/Makefile 2005-07-01 00:41:09.000000000 +0200
+@@ -110,6 +110,7 @@
+ obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
+ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
+ obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
++obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
+ obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
+ obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
+ obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
diff --git a/target/linux/generic-2.4/patches/607-netfilter_connmark.patch b/target/linux/generic-2.4/patches/607-netfilter_connmark.patch
new file mode 100644
index 0000000..154314d
--- /dev/null
+++ b/target/linux/generic-2.4/patches/607-netfilter_connmark.patch
@@ -0,0 +1,351 @@
+diff -urN linux.old/include/linux/netfilter_ipv4/ip_conntrack.h linux.dev/include/linux/netfilter_ipv4/ip_conntrack.h
+--- linux.old/include/linux/netfilter_ipv4/ip_conntrack.h 2005-08-20 20:02:06.619827000 +0200
++++ linux.dev/include/linux/netfilter_ipv4/ip_conntrack.h 2005-08-20 20:19:23.302029232 +0200
+@@ -226,6 +226,9 @@
+ unsigned int app_data_len;
+ } layer7;
+ #endif
++#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
++ unsigned long mark;
++#endif
+ };
+
+ /* get master conntrack via master expectation */
+diff -urN linux.old/include/linux/netfilter_ipv4/ipt_CONNMARK.h linux.dev/include/linux/netfilter_ipv4/ipt_CONNMARK.h
+--- linux.old/include/linux/netfilter_ipv4/ipt_CONNMARK.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/linux/netfilter_ipv4/ipt_CONNMARK.h 2005-08-20 20:19:41.058329864 +0200
+@@ -0,0 +1,25 @@
++#ifndef _IPT_CONNMARK_H_target
++#define _IPT_CONNMARK_H_target
++
++/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
++ * by Henrik Nordstrom <hno@marasystems.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++enum {
++ IPT_CONNMARK_SET = 0,
++ IPT_CONNMARK_SAVE,
++ IPT_CONNMARK_RESTORE
++};
++
++struct ipt_connmark_target_info {
++ unsigned long mark;
++ unsigned long mask;
++ u_int8_t mode;
++};
++
++#endif /*_IPT_CONNMARK_H_target*/
+diff -urN linux.old/include/linux/netfilter_ipv4/ipt_connmark.h linux.dev/include/linux/netfilter_ipv4/ipt_connmark.h
+--- linux.old/include/linux/netfilter_ipv4/ipt_connmark.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/linux/netfilter_ipv4/ipt_connmark.h 2005-08-20 20:19:41.058329864 +0200
+@@ -0,0 +1,18 @@
++#ifndef _IPT_CONNMARK_H
++#define _IPT_CONNMARK_H
++
++/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
++ * by Henrik Nordstrom <hno@marasystems.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++struct ipt_connmark_info {
++ unsigned long mark, mask;
++ u_int8_t invert;
++};
++
++#endif /*_IPT_CONNMARK_H*/
+diff -urN linux.old/net/ipv4/netfilter/Config.in linux.dev/net/ipv4/netfilter/Config.in
+--- linux.old/net/ipv4/netfilter/Config.in 2005-08-20 20:02:09.325416000 +0200
++++ linux.dev/net/ipv4/netfilter/Config.in 2005-08-20 20:29:11.546602464 +0200
+@@ -6,7 +6,8 @@
+
+ tristate 'Connection tracking (required for masq/NAT)' CONFIG_IP_NF_CONNTRACK
+ if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
+- dep_tristate ' FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACK
++ bool ' Connection mark tracking support' CONFIG_IP_NF_CONNTRACK_MARK
++ dep_tristate ' FTP protocol support' CONFIG_IP_NF_FTP $CONFIG_IP_NF_CONNTRACKa
+ dep_tristate ' Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK
+ dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK
+ dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
+@@ -42,6 +43,9 @@
+ if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; then
+ dep_tristate ' Connection state match support' CONFIG_IP_NF_MATCH_STATE $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' Connection tracking match support' CONFIG_IP_NF_MATCH_CONNTRACK $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES
++ if [ "$CONFIG_IP_NF_CONNTRACK_MARK" != "n" ]; then
++ dep_tristate ' Connection mark match support' CONFIG_IP_NF_MATCH_CONNMARK $CONFIG_IP_NF_IPTABLES
++ fi
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES
+@@ -125,6 +129,9 @@
+
+ dep_tristate ' MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
+ fi
++ if [ "$CONFIG_IP_NF_CONNTRACK_MARK" != "n" ]; then
++ dep_tristate ' CONNMARK target support' CONFIG_IP_NF_TARGET_CONNMARK $CONFIG_IP_NF_IPTABLES
++ fi
+ dep_tristate ' LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' TTL target support' CONFIG_IP_NF_TARGET_TTL $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_IP_NF_IPTABLES
+diff -urN linux.old/net/ipv4/netfilter/Makefile linux.dev/net/ipv4/netfilter/Makefile
+--- linux.old/net/ipv4/netfilter/Makefile 2005-08-20 20:02:09.326416000 +0200
++++ linux.dev/net/ipv4/netfilter/Makefile 2005-08-20 20:29:54.081136232 +0200
+@@ -93,6 +93,7 @@
+
+ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
+ obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
++obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o
+ obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
+ obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
+ obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
+@@ -110,6 +111,7 @@
+ obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+ obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
+ obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
++obj-$(CONFIG_IP_NF_TARGET_CONNMARK) += ipt_CONNMARK.o
+ obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
+ obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
+ obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
+diff -urN linux.old/net/ipv4/netfilter/ip_conntrack_core.c linux.dev/net/ipv4/netfilter/ip_conntrack_core.c
+--- linux.old/net/ipv4/netfilter/ip_conntrack_core.c 2005-08-20 20:02:06.828795000 +0200
++++ linux.dev/net/ipv4/netfilter/ip_conntrack_core.c 2005-08-20 20:33:23.308328864 +0200
+@@ -755,6 +755,9 @@
+ __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
+ conntrack->master = expected;
+ expected->sibling = conntrack;
++#ifdef CONFIG_IP_NF_CONNTRACK_MARK
++ conntrack->mark = expected->expectant->mark;
++#endif
+ LIST_DELETE(&ip_conntrack_expect_list, expected);
+ expected->expectant->expecting--;
+ nf_conntrack_get(&master_ct(conntrack)->infos[0]);
+diff -urN linux.old/net/ipv4/netfilter/ip_conntrack_standalone.c linux.dev/net/ipv4/netfilter/ip_conntrack_standalone.c
+--- linux.old/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-08-20 20:02:06.583833000 +0200
++++ linux.dev/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-08-20 20:32:15.364657872 +0200
+@@ -107,6 +107,9 @@
+ len += sprintf(buffer + len, "[ASSURED] ");
+ len += sprintf(buffer + len, "use=%u ",
+ atomic_read(&conntrack->ct_general.use));
++ #if defined(CONFIG_IP_NF_CONNTRACK_MARK)
++ len += sprintf(buffer + len, "mark=%ld ", conntrack->mark);
++ #endif
+
+ #if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE)
+ if(conntrack->layer7.app_proto)
+diff -urN linux.old/net/ipv4/netfilter/ipt_CONNMARK.c linux.dev/net/ipv4/netfilter/ipt_CONNMARK.c
+--- linux.old/net/ipv4/netfilter/ipt_CONNMARK.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/net/ipv4/netfilter/ipt_CONNMARK.c 2005-08-20 20:21:28.666970864 +0200
+@@ -0,0 +1,118 @@
++/* This kernel module is used to modify the connection mark values, or
++ * to optionally restore the skb nfmark from the connection mark
++ *
++ * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
++ * by Henrik Nordstrom <hno@marasystems.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++
++MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
++MODULE_DESCRIPTION("IP tables CONNMARK matching module");
++MODULE_LICENSE("GPL");
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_CONNMARK.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++
++static unsigned int
++target(struct sk_buff **pskb,
++ unsigned int hooknum,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *targinfo,
++ void *userinfo)
++{
++ const struct ipt_connmark_target_info *markinfo = targinfo;
++ unsigned long diff;
++ unsigned long nfmark;
++ unsigned long newmark;
++
++ enum ip_conntrack_info ctinfo;
++ struct ip_conntrack *ct = ip_conntrack_get((*pskb), &ctinfo);
++ if (ct) {
++ switch(markinfo->mode) {
++ case IPT_CONNMARK_SET:
++ newmark = (ct->mark & ~markinfo->mask) | markinfo->mark;
++ if (newmark != ct->mark)
++ ct->mark = newmark;
++ break;
++ case IPT_CONNMARK_SAVE:
++ newmark = (ct->mark & ~markinfo->mask) | ((*pskb)->nfmark & markinfo->mask);
++ if (ct->mark != newmark)
++ ct->mark = newmark;
++ break;
++ case IPT_CONNMARK_RESTORE:
++ nfmark = (*pskb)->nfmark;
++ diff = (ct->mark ^ nfmark & markinfo->mask);
++ if (diff != 0) {
++ (*pskb)->nfmark = nfmark ^ diff;
++ (*pskb)->nfcache |= NFC_ALTERED;
++ }
++ break;
++ }
++ }
++
++ return IPT_CONTINUE;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ struct ipt_connmark_target_info *matchinfo = targinfo;
++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_connmark_target_info))) {
++ printk(KERN_WARNING "CONNMARK: targinfosize %u != %Zu\n",
++ targinfosize,
++ IPT_ALIGN(sizeof(struct ipt_connmark_target_info)));
++ return 0;
++ }
++
++ if (matchinfo->mode == IPT_CONNMARK_RESTORE) {
++ if (strcmp(tablename, "mangle") != 0) {
++ printk(KERN_WARNING "CONNMARK: restore can only be called from \"mangle\" table, not \"%s\"\n", tablename);
++ return 0;
++ }
++ }
++
++ return 1;
++}
++
++static struct ipt_target ipt_connmark_reg = {
++ .name = "CONNMARK",
++ .target = &target,
++ .checkentry = &checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_target(&ipt_connmark_reg);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&ipt_connmark_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -urN linux.old/net/ipv4/netfilter/ipt_connmark.c linux.dev/net/ipv4/netfilter/ipt_connmark.c
+--- linux.old/net/ipv4/netfilter/ipt_connmark.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/net/ipv4/netfilter/ipt_connmark.c 2005-08-20 20:21:28.666970864 +0200
+@@ -0,0 +1,83 @@
++/* This kernel module matches connection mark values set by the
++ * CONNMARK target
++ *
++ * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
++ * by Henrik Nordstrom <hno@marasystems.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++
++MODULE_AUTHOR("Henrik Nordstrom <hno@marasytems.com>");
++MODULE_DESCRIPTION("IP tables connmark match module");
++MODULE_LICENSE("GPL");
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_connmark.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ const void *hdr,
++ u_int16_t datalen,
++ int *hotdrop)
++{
++ const struct ipt_connmark_info *info = matchinfo;
++ enum ip_conntrack_info ctinfo;
++ struct ip_conntrack *ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
++ if (!ct)
++ return 0;
++
++ return ((ct->mark & info->mask) == info->mark) ^ info->invert;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_connmark_info)))
++ return 0;
++
++ return 1;
++}
++
++static struct ipt_match connmark_match = {
++ .name = "connmark",
++ .match = &match,
++ .checkentry = &checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_match(&connmark_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&connmark_match);
++}
++
++module_init(init);
++module_exit(fini);
diff --git a/target/linux/generic-2.4/patches/608-netfilter_ipset.patch b/target/linux/generic-2.4/patches/608-netfilter_ipset.patch
new file mode 100644
index 0000000..8cf5c69
--- /dev/null
+++ b/target/linux/generic-2.4/patches/608-netfilter_ipset.patch
@@ -0,0 +1,5725 @@
+diff -Naur linux-old/Documentation/Configure.help linux-new/Documentation/Configure.help
+--- linux-old/Documentation/Configure.help 2005-07-23 23:34:46.000000000 +0200
++++ linux-new/Documentation/Configure.help 2005-08-10 22:13:01.000000000 +0200
+@@ -3209,6 +3209,75 @@
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
++IP set support
++CONFIG_IP_NF_SET
++ This option adds IP set support to the kernel.
++
++ In order to define and use sets, you need userlevel utilities: an
++ iptables binary which knows about IP sets and the program ipset(8),
++ by which you can define and setup the sets themselves.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
++set match support
++CONFIG_IP_NF_MATCH_SET
++ This option adds IP set match support.
++ You need the ipset utility to create and set up the sets.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
++SET target support
++CONFIG_IP_NF_TARGET_SET
++ This option adds IP set target support.
++ You need the ipset utility to create and set up the sets.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
++ipmap set type support
++CONFIG_IP_NF_SET_IPMAP
++ This option adds the ipmap set type support.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
++macipmap set type support
++CONFIG_IP_NF_SET_MACIPMAP
++ This option adds the macipmap set type support.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
++portmap set type support
++CONFIG_IP_NF_SET_PORTMAP
++ This option adds the portmap set type support.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
++iphash set type support
++CONFIG_IP_NF_SET_IPHASH
++ This option adds the iphash set type support.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
++nethash set type support
++CONFIG_IP_NF_SET_NETHASH
++ This option adds the nethash set type support.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
++iptree set type support
++CONFIG_IP_NF_SET_IPTREE
++ This option adds the iptree set type support.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
+ TTL target support
+ CONFIG_IP_NF_TARGET_TTL
+ This option adds a `TTL' target, which enables the user to set
+diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set.h linux-new/include/linux/netfilter_ipv4/ip_set.h
+--- linux-old/include/linux/netfilter_ipv4/ip_set.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/include/linux/netfilter_ipv4/ip_set.h 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,489 @@
++#ifndef _IP_SET_H
++#define _IP_SET_H
++
++/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
++ * Patrick Schaaf <bof@bof.de>
++ * Martin Josefsson <gandalf@wlug.westbo.se>
++ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * A sockopt of such quality has hardly ever been seen before on the open
++ * market! This little beauty, hardly ever used: above 64, so it's
++ * traditionally used for firewalling, not touched (even once!) by the
++ * 2.0, 2.2 and 2.4 kernels!
++ *
++ * Comes with its own certificate of authenticity, valid anywhere in the
++ * Free world!
++ *
++ * Rusty, 19.4.2000
++ */
++#define SO_IP_SET 83
++
++/*
++ * Heavily modify by Joakim Axelsson 08.03.2002
++ * - Made it more modulebased
++ *
++ * Additional heavy modifications by Jozsef Kadlecsik 22.02.2004
++ * - bindings added
++ * - in order to "deal with" backward compatibility, renamed to ipset
++ */
++
++/*
++ * Used so that the kernel module and ipset-binary can match their versions
++ */
++#define IP_SET_PROTOCOL_VERSION 2
++
++#define IP_SET_MAXNAMELEN 32 /* set names and set typenames */
++
++/* Lets work with our own typedef for representing an IP address.
++ * We hope to make the code more portable, possibly to IPv6...
++ *
++ * The representation works in HOST byte order, because most set types
++ * will perform arithmetic operations and compare operations.
++ *
++ * For now the type is an uint32_t.
++ *
++ * Make sure to ONLY use the functions when translating and parsing
++ * in order to keep the host byte order and make it more portable:
++ * parse_ip()
++ * parse_mask()
++ * parse_ipandmask()
++ * ip_tostring()
++ * (Joakim: where are they???)
++ */
++
++typedef uint32_t ip_set_ip_t;
++
++/* Sets are identified by an id in kernel space. Tweak with ip_set_id_t
++ * and IP_SET_INVALID_ID if you want to increase the max number of sets.
++ */
++typedef uint16_t ip_set_id_t;
++
++#define IP_SET_INVALID_ID 65535
++
++/* How deep we follow bindings */
++#define IP_SET_MAX_BINDINGS 6
++
++/*
++ * Option flags for kernel operations (ipt_set_info)
++ */
++#define IPSET_SRC 0x01 /* Source match/add */
++#define IPSET_DST 0x02 /* Destination match/add */
++#define IPSET_MATCH_INV 0x04 /* Inverse matching */
++
++/*
++ * Set types (flavours)
++ */
++#define IPSET_TYPE_IP 0 /* IP address type of set */
++#define IPSET_TYPE_PORT 1 /* Port type of set */
++
++/* Reserved keywords */
++#define IPSET_TOKEN_DEFAULT ":default:"
++#define IPSET_TOKEN_ALL ":all:"
++
++/* SO_IP_SET operation constants, and their request struct types.
++ *
++ * Operation ids:
++ * 0-99: commands with version checking
++ * 100-199: add/del/test/bind/unbind
++ * 200-299: list, save, restore
++ */
++
++/* Single shot operations:
++ * version, create, destroy, flush, rename and swap
++ *
++ * Sets are identified by name.
++ */
++
++#define IP_SET_REQ_STD \
++ unsigned op; \
++ unsigned version; \
++ char name[IP_SET_MAXNAMELEN]
++
++#define IP_SET_OP_CREATE 0x00000001 /* Create a new (empty) set */
++struct ip_set_req_create {
++ IP_SET_REQ_STD;
++ char typename[IP_SET_MAXNAMELEN];
++};
++
++#define IP_SET_OP_DESTROY 0x00000002 /* Remove a (empty) set */
++struct ip_set_req_std {
++ IP_SET_REQ_STD;
++};
++
++#define IP_SET_OP_FLUSH 0x00000003 /* Remove all IPs in a set */
++/* Uses ip_set_req_std */
++
++#define IP_SET_OP_RENAME 0x00000004 /* Rename a set */
++/* Uses ip_set_req_create */
++
++#define IP_SET_OP_SWAP 0x00000005 /* Swap two sets */
++/* Uses ip_set_req_create */
++
++union ip_set_name_index {
++ char name[IP_SET_MAXNAMELEN];
++ ip_set_id_t index;
++};
++
++#define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */
++struct ip_set_req_get_set {
++ unsigned op;
++ unsigned version;
++ union ip_set_name_index set;
++};
++
++#define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */
++/* Uses ip_set_req_get_set */
++
++#define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */
++struct ip_set_req_version {
++ unsigned op;
++ unsigned version;
++};
++
++/* Double shots operations:
++ * add, del, test, bind and unbind.
++ *
++ * First we query the kernel to get the index and type of the target set,
++ * then issue the command. Validity of IP is checked in kernel in order
++ * to minimalize sockopt operations.
++ */
++
++/* Get minimal set data for add/del/test/bind/unbind IP */
++#define IP_SET_OP_ADT_GET 0x00000010 /* Get set and type */
++struct ip_set_req_adt_get {
++ unsigned op;
++ unsigned version;
++ union ip_set_name_index set;
++ char typename[IP_SET_MAXNAMELEN];
++};
++
++#define IP_SET_REQ_BYINDEX \
++ unsigned op; \
++ ip_set_id_t index;
++
++struct ip_set_req_adt {
++ IP_SET_REQ_BYINDEX;
++};
++
++#define IP_SET_OP_ADD_IP 0x00000101 /* Add an IP to a set */
++/* Uses ip_set_req_adt, with type specific addage */
++
++#define IP_SET_OP_DEL_IP 0x00000102 /* Remove an IP from a set */
++/* Uses ip_set_req_adt, with type specific addage */
++
++#define IP_SET_OP_TEST_IP 0x00000103 /* Test an IP in a set */
++/* Uses ip_set_req_adt, with type specific addage */
++
++#define IP_SET_OP_BIND_SET 0x00000104 /* Bind an IP to a set */
++/* Uses ip_set_req_bind, with type specific addage */
++struct ip_set_req_bind {
++ IP_SET_REQ_BYINDEX;
++ char binding[IP_SET_MAXNAMELEN];
++};
++
++#define IP_SET_OP_UNBIND_SET 0x00000105 /* Unbind an IP from a set */
++/* Uses ip_set_req_bind, with type speficic addage
++ * index = 0 means unbinding for all sets */
++
++#define IP_SET_OP_TEST_BIND_SET 0x00000106 /* Test binding an IP to a set */
++/* Uses ip_set_req_bind, with type specific addage */
++
++/* Multiple shots operations: list, save, restore.
++ *
++ * - check kernel version and query the max number of sets
++ * - get the basic information on all sets
++ * and size required for the next step
++ * - get actual set data: header, data, bindings
++ */
++
++/* Get max_sets and the index of a queried set
++ */
++#define IP_SET_OP_MAX_SETS 0x00000020
++struct ip_set_req_max_sets {
++ unsigned op;
++ unsigned version;
++ ip_set_id_t max_sets; /* max_sets */
++ ip_set_id_t sets; /* real number of sets */
++ union ip_set_name_index set; /* index of set if name used */
++};
++
++/* Get the id and name of the sets plus size for next step */
++#define IP_SET_OP_LIST_SIZE 0x00000201
++#define IP_SET_OP_SAVE_SIZE 0x00000202
++struct ip_set_req_setnames {
++ unsigned op;
++ ip_set_id_t index; /* set to list/save */
++ size_t size; /* size to get setdata/bindings */
++ /* followed by sets number of struct ip_set_name_list */
++};
++
++struct ip_set_name_list {
++ char name[IP_SET_MAXNAMELEN];
++ char typename[IP_SET_MAXNAMELEN];
++ ip_set_id_t index;
++ ip_set_id_t id;
++};
++
++/* The actual list operation */
++#define IP_SET_OP_LIST 0x00000203
++struct ip_set_req_list {
++ IP_SET_REQ_BYINDEX;
++ /* sets number of struct ip_set_list in reply */
++};
++
++struct ip_set_list {
++ ip_set_id_t index;
++ ip_set_id_t binding;
++ u_int32_t ref;
++ size_t header_size; /* Set header data of header_size */
++ size_t members_size; /* Set members data of members_size */
++ size_t bindings_size; /* Set bindings data of bindings_size */
++};
++
++struct ip_set_hash_list {
++ ip_set_ip_t ip;
++ ip_set_id_t binding;
++};
++
++/* The save operation */
++#define IP_SET_OP_SAVE 0x00000204
++/* Uses ip_set_req_list, in the reply replaced by
++ * sets number of struct ip_set_save plus a marker
++ * ip_set_save followed by ip_set_hash_save structures.
++ */
++struct ip_set_save {
++ ip_set_id_t index;
++ ip_set_id_t binding;
++ size_t header_size; /* Set header data of header_size */
++ size_t members_size; /* Set members data of members_size */
++};
++
++/* At restoring, ip == 0 means default binding for the given set: */
++struct ip_set_hash_save {
++ ip_set_ip_t ip;
++ ip_set_id_t id;
++ ip_set_id_t binding;
++};
++
++/* The restore operation */
++#define IP_SET_OP_RESTORE 0x00000205
++/* Uses ip_set_req_setnames followed by ip_set_restore structures
++ * plus a marker ip_set_restore, followed by ip_set_hash_save
++ * structures.
++ */
++struct ip_set_restore {
++ char name[IP_SET_MAXNAMELEN];
++ char typename[IP_SET_MAXNAMELEN];
++ ip_set_id_t index;
++ size_t header_size; /* Create data of header_size */
++ size_t members_size; /* Set members data of members_size */
++};
++
++static inline int bitmap_bytes(ip_set_ip_t a, ip_set_ip_t b)
++{
++ return 4 * ((((b - a + 8) / 8) + 3) / 4);
++}
++
++#ifdef __KERNEL__
++
++#define ip_set_printk(format, args...) \
++ do { \
++ printk("%s: %s: ", __FILE__, __FUNCTION__); \
++ printk(format "\n" , ## args); \
++ } while (0)
++
++#if defined(IP_SET_DEBUG)
++#define DP(format, args...) \
++ do { \
++ printk("%s: %s (DBG): ", __FILE__, __FUNCTION__);\
++ printk(format "\n" , ## args); \
++ } while (0)
++#define IP_SET_ASSERT(x) \
++ do { \
++ if (!(x)) \
++ printk("IP_SET_ASSERT: %s:%i(%s)\n", \
++ __FILE__, __LINE__, __FUNCTION__); \
++ } while (0)
++#else
++#define DP(format, args...)
++#define IP_SET_ASSERT(x)
++#endif
++
++struct ip_set;
++
++/*
++ * The ip_set_type definition - one per set type, e.g. "ipmap".
++ *
++ * Each individual set has a pointer, set->type, going to one
++ * of these structures. Function pointers inside the structure implement
++ * the real behaviour of the sets.
++ *
++ * If not mentioned differently, the implementation behind the function
++ * pointers of a set_type, is expected to return 0 if ok, and a negative
++ * errno (e.g. -EINVAL) on error.
++ */
++struct ip_set_type {
++ struct list_head list; /* next in list of set types */
++
++ /* test for IP in set (kernel: iptables -m set src|dst)
++ * return 0 if not in set, 1 if in set.
++ */
++ int (*testip_kernel) (struct ip_set *set,
++ const struct sk_buff * skb,
++ u_int32_t flags,
++ ip_set_ip_t *ip);
++
++ /* test for IP in set (userspace: ipset -T set IP)
++ * return 0 if not in set, 1 if in set.
++ */
++ int (*testip) (struct ip_set *set,
++ const void *data, size_t size,
++ ip_set_ip_t *ip);
++
++ /*
++ * Size of the data structure passed by when
++ * adding/deletin/testing an entry.
++ */
++ size_t reqsize;
++
++ /* Add IP into set (userspace: ipset -A set IP)
++ * Return -EEXIST if the address is already in the set,
++ * and -ERANGE if the address lies outside the set bounds.
++ * If the address was not already in the set, 0 is returned.
++ */
++ int (*addip) (struct ip_set *set,
++ const void *data, size_t size,
++ ip_set_ip_t *ip);
++
++ /* Add IP into set (kernel: iptables ... -j SET set src|dst)
++ * Return -EEXIST if the address is already in the set,
++ * and -ERANGE if the address lies outside the set bounds.
++ * If the address was not already in the set, 0 is returned.
++ */
++ int (*addip_kernel) (struct ip_set *set,
++ const struct sk_buff * skb,
++ u_int32_t flags,
++ ip_set_ip_t *ip);
++
++ /* remove IP from set (userspace: ipset -D set --entry x)
++ * Return -EEXIST if the address is NOT in the set,
++ * and -ERANGE if the address lies outside the set bounds.
++ * If the address really was in the set, 0 is returned.
++ */
++ int (*delip) (struct ip_set *set,
++ const void *data, size_t size,
++ ip_set_ip_t *ip);
++
++ /* remove IP from set (kernel: iptables ... -j SET --entry x)
++ * Return -EEXIST if the address is NOT in the set,
++ * and -ERANGE if the address lies outside the set bounds.
++ * If the address really was in the set, 0 is returned.
++ */
++ int (*delip_kernel) (struct ip_set *set,
++ const struct sk_buff * skb,
++ u_int32_t flags,
++ ip_set_ip_t *ip);
++
++ /* new set creation - allocated type specific items
++ */
++ int (*create) (struct ip_set *set,
++ const void *data, size_t size);
++
++ /* retry the operation after successfully tweaking the set
++ */
++ int (*retry) (struct ip_set *set);
++
++ /* set destruction - free type specific items
++ * There is no return value.
++ * Can be called only when child sets are destroyed.
++ */
++ void (*destroy) (struct ip_set *set);
++
++ /* set flushing - reset all bits in the set, or something similar.
++ * There is no return value.
++ */
++ void (*flush) (struct ip_set *set);
++
++ /* Listing: size needed for header
++ */
++ size_t header_size;
++
++ /* Listing: Get the header
++ *
++ * Fill in the information in "data".
++ * This function is always run after list_header_size() under a
++ * writelock on the set. Therefor is the length of "data" always
++ * correct.
++ */
++ void (*list_header) (const struct ip_set *set,
++ void *data);
++
++ /* Listing: Get the size for the set members
++ */
++ int (*list_members_size) (const struct ip_set *set);
++
++ /* Listing: Get the set members
++ *
++ * Fill in the information in "data".
++ * This function is always run after list_member_size() under a
++ * writelock on the set. Therefor is the length of "data" always
++ * correct.
++ */
++ void (*list_members) (const struct ip_set *set,
++ void *data);
++
++ char typename[IP_SET_MAXNAMELEN];
++ char typecode;
++ int protocol_version;
++
++ /* Set this to THIS_MODULE if you are a module, otherwise NULL */
++ struct module *me;
++};
++
++extern int ip_set_register_set_type(struct ip_set_type *set_type);
++extern void ip_set_unregister_set_type(struct ip_set_type *set_type);
++
++/* A generic ipset */
++struct ip_set {
++ char name[IP_SET_MAXNAMELEN]; /* the name of the set */
++ rwlock_t lock; /* lock for concurrency control */
++ ip_set_id_t id; /* set id for swapping */
++ ip_set_id_t binding; /* default binding for the set */
++ atomic_t ref; /* in kernel and in hash references */
++ struct ip_set_type *type; /* the set types */
++ void *data; /* pooltype specific data */
++};
++
++/* Structure to bind set elements to sets */
++struct ip_set_hash {
++ struct list_head list; /* list of clashing entries in hash */
++ ip_set_ip_t ip; /* ip from set */
++ ip_set_id_t id; /* set id */
++ ip_set_id_t binding; /* set we bind the element to */
++};
++
++/* register and unregister set references */
++extern ip_set_id_t ip_set_get_byname(const char name[IP_SET_MAXNAMELEN]);
++extern ip_set_id_t ip_set_get_byindex(ip_set_id_t id);
++extern void ip_set_put(ip_set_id_t id);
++
++/* API for iptables set match, and SET target */
++extern void ip_set_addip_kernel(ip_set_id_t id,
++ const struct sk_buff *skb,
++ const u_int32_t *flags);
++extern void ip_set_delip_kernel(ip_set_id_t id,
++ const struct sk_buff *skb,
++ const u_int32_t *flags);
++extern int ip_set_testip_kernel(ip_set_id_t id,
++ const struct sk_buff *skb,
++ const u_int32_t *flags);
++
++#endif /* __KERNEL__ */
++
++#endif /*_IP_SET_H*/
+diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_iphash.h linux-new/include/linux/netfilter_ipv4/ip_set_iphash.h
+--- linux-old/include/linux/netfilter_ipv4/ip_set_iphash.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/include/linux/netfilter_ipv4/ip_set_iphash.h 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,30 @@
++#ifndef __IP_SET_IPHASH_H
++#define __IP_SET_IPHASH_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++#define SETTYPE_NAME "iphash"
++#define MAX_RANGE 0x0000FFFF
++
++struct ip_set_iphash {
++ ip_set_ip_t *members; /* the iphash proper */
++ uint32_t initval; /* initval for jhash_1word */
++ uint32_t prime; /* prime for double hashing */
++ uint32_t hashsize; /* hash size */
++ uint16_t probes; /* max number of probes */
++ uint16_t resize; /* resize factor in percent */
++ ip_set_ip_t netmask; /* netmask */
++};
++
++struct ip_set_req_iphash_create {
++ uint32_t hashsize;
++ uint16_t probes;
++ uint16_t resize;
++ ip_set_ip_t netmask;
++};
++
++struct ip_set_req_iphash {
++ ip_set_ip_t ip;
++};
++
++#endif /* __IP_SET_IPHASH_H */
+diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_ipmap.h linux-new/include/linux/netfilter_ipv4/ip_set_ipmap.h
+--- linux-old/include/linux/netfilter_ipv4/ip_set_ipmap.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/include/linux/netfilter_ipv4/ip_set_ipmap.h 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,56 @@
++#ifndef __IP_SET_IPMAP_H
++#define __IP_SET_IPMAP_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++#define SETTYPE_NAME "ipmap"
++#define MAX_RANGE 0x0000FFFF
++
++struct ip_set_ipmap {
++ void *members; /* the ipmap proper */
++ ip_set_ip_t first_ip; /* host byte order, included in range */
++ ip_set_ip_t last_ip; /* host byte order, included in range */
++ ip_set_ip_t netmask; /* subnet netmask */
++ ip_set_ip_t sizeid; /* size of set in IPs */
++ u_int16_t hosts; /* number of hosts in a subnet */
++};
++
++struct ip_set_req_ipmap_create {
++ ip_set_ip_t from;
++ ip_set_ip_t to;
++ ip_set_ip_t netmask;
++};
++
++struct ip_set_req_ipmap {
++ ip_set_ip_t ip;
++};
++
++unsigned int
++mask_to_bits(ip_set_ip_t mask)
++{
++ unsigned int bits = 32;
++ ip_set_ip_t maskaddr;
++
++ if (mask == 0xFFFFFFFF)
++ return bits;
++
++ maskaddr = 0xFFFFFFFE;
++ while (--bits >= 0 && maskaddr != mask)
++ maskaddr <<= 1;
++
++ return bits;
++}
++
++ip_set_ip_t
++range_to_mask(ip_set_ip_t from, ip_set_ip_t to, unsigned int *bits)
++{
++ ip_set_ip_t mask = 0xFFFFFFFE;
++
++ *bits = 32;
++ while (--(*bits) >= 0 && mask && (to & mask) != from)
++ mask <<= 1;
++
++ return mask;
++}
++
++#endif /* __IP_SET_IPMAP_H */
+diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_iptree.h linux-new/include/linux/netfilter_ipv4/ip_set_iptree.h
+--- linux-old/include/linux/netfilter_ipv4/ip_set_iptree.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/include/linux/netfilter_ipv4/ip_set_iptree.h 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,39 @@
++#ifndef __IP_SET_IPTREE_H
++#define __IP_SET_IPTREE_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++#define SETTYPE_NAME "iptree"
++#define MAX_RANGE 0x0000FFFF
++
++struct ip_set_iptreed {
++ unsigned long expires[255]; /* x.x.x.ADDR */
++};
++
++struct ip_set_iptreec {
++ struct ip_set_iptreed *tree[255]; /* x.x.ADDR.* */
++};
++
++struct ip_set_iptreeb {
++ struct ip_set_iptreec *tree[255]; /* x.ADDR.*.* */
++};
++
++struct ip_set_iptree {
++ unsigned int timeout;
++ unsigned int gc_interval;
++#ifdef __KERNEL__
++ struct timer_list gc;
++ struct ip_set_iptreeb *tree[255]; /* ADDR.*.*.* */
++#endif
++};
++
++struct ip_set_req_iptree_create {
++ unsigned int timeout;
++};
++
++struct ip_set_req_iptree {
++ ip_set_ip_t ip;
++ unsigned int timeout;
++};
++
++#endif /* __IP_SET_IPTREE_H */
+diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_jhash.h linux-new/include/linux/netfilter_ipv4/ip_set_jhash.h
+--- linux-old/include/linux/netfilter_ipv4/ip_set_jhash.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/include/linux/netfilter_ipv4/ip_set_jhash.h 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,148 @@
++#ifndef _LINUX_IPSET_JHASH_H
++#define _LINUX_IPSET_JHASH_H
++
++/* This is a copy of linux/jhash.h but the types u32/u8 are changed
++ * to __u32/__u8 so that the header file can be included into
++ * userspace code as well. Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
++ */
++
++/* jhash.h: Jenkins hash support.
++ *
++ * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
++ *
++ * http://burtleburtle.net/bob/hash/
++ *
++ * These are the credits from Bob's sources:
++ *
++ * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
++ * hash(), hash2(), hash3, and mix() are externally useful functions.
++ * Routines to test the hash are included if SELF_TEST is defined.
++ * You can use this free for any purpose. It has no warranty.
++ *
++ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
++ *
++ * I've modified Bob's hash to be useful in the Linux kernel, and
++ * any bugs present are surely my fault. -DaveM
++ */
++
++/* NOTE: Arguments are modified. */
++#define __jhash_mix(a, b, c) \
++{ \
++ a -= b; a -= c; a ^= (c>>13); \
++ b -= c; b -= a; b ^= (a<<8); \
++ c -= a; c -= b; c ^= (b>>13); \
++ a -= b; a -= c; a ^= (c>>12); \
++ b -= c; b -= a; b ^= (a<<16); \
++ c -= a; c -= b; c ^= (b>>5); \
++ a -= b; a -= c; a ^= (c>>3); \
++ b -= c; b -= a; b ^= (a<<10); \
++ c -= a; c -= b; c ^= (b>>15); \
++}
++
++/* The golden ration: an arbitrary value */
++#define JHASH_GOLDEN_RATIO 0x9e3779b9
++
++/* The most generic version, hashes an arbitrary sequence
++ * of bytes. No alignment or length assumptions are made about
++ * the input key.
++ */
++static inline __u32 jhash(void *key, __u32 length, __u32 initval)
++{
++ __u32 a, b, c, len;
++ __u8 *k = key;
++
++ len = length;
++ a = b = JHASH_GOLDEN_RATIO;
++ c = initval;
++
++ while (len >= 12) {
++ a += (k[0] +((__u32)k[1]<<8) +((__u32)k[2]<<16) +((__u32)k[3]<<24));
++ b += (k[4] +((__u32)k[5]<<8) +((__u32)k[6]<<16) +((__u32)k[7]<<24));
++ c += (k[8] +((__u32)k[9]<<8) +((__u32)k[10]<<16)+((__u32)k[11]<<24));
++
++ __jhash_mix(a,b,c);
++
++ k += 12;
++ len -= 12;
++ }
++
++ c += length;
++ switch (len) {
++ case 11: c += ((__u32)k[10]<<24);
++ case 10: c += ((__u32)k[9]<<16);
++ case 9 : c += ((__u32)k[8]<<8);
++ case 8 : b += ((__u32)k[7]<<24);
++ case 7 : b += ((__u32)k[6]<<16);
++ case 6 : b += ((__u32)k[5]<<8);
++ case 5 : b += k[4];
++ case 4 : a += ((__u32)k[3]<<24);
++ case 3 : a += ((__u32)k[2]<<16);
++ case 2 : a += ((__u32)k[1]<<8);
++ case 1 : a += k[0];
++ };
++
++ __jhash_mix(a,b,c);
++
++ return c;
++}
++
++/* A special optimized version that handles 1 or more of __u32s.
++ * The length parameter here is the number of __u32s in the key.
++ */
++static inline __u32 jhash2(__u32 *k, __u32 length, __u32 initval)
++{
++ __u32 a, b, c, len;
++
++ a = b = JHASH_GOLDEN_RATIO;
++ c = initval;
++ len = length;
++
++ while (len >= 3) {
++ a += k[0];
++ b += k[1];
++ c += k[2];
++ __jhash_mix(a, b, c);
++ k += 3; len -= 3;
++ }
++
++ c += length * 4;
++
++ switch (len) {
++ case 2 : b += k[1];
++ case 1 : a += k[0];
++ };
++
++ __jhash_mix(a,b,c);
++
++ return c;
++}
++
++
++/* A special ultra-optimized versions that knows they are hashing exactly
++ * 3, 2 or 1 word(s).
++ *
++ * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
++ * done at the end is not done here.
++ */
++static inline __u32 jhash_3words(__u32 a, __u32 b, __u32 c, __u32 initval)
++{
++ a += JHASH_GOLDEN_RATIO;
++ b += JHASH_GOLDEN_RATIO;
++ c += initval;
++
++ __jhash_mix(a, b, c);
++
++ return c;
++}
++
++static inline __u32 jhash_2words(__u32 a, __u32 b, __u32 initval)
++{
++ return jhash_3words(a, b, 0, initval);
++}
++
++static inline __u32 jhash_1word(__u32 a, __u32 initval)
++{
++ return jhash_3words(a, 0, 0, initval);
++}
++
++#endif /* _LINUX_IPSET_JHASH_H */
+diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_macipmap.h linux-new/include/linux/netfilter_ipv4/ip_set_macipmap.h
+--- linux-old/include/linux/netfilter_ipv4/ip_set_macipmap.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/include/linux/netfilter_ipv4/ip_set_macipmap.h 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,38 @@
++#ifndef __IP_SET_MACIPMAP_H
++#define __IP_SET_MACIPMAP_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++#define SETTYPE_NAME "macipmap"
++#define MAX_RANGE 0x0000FFFF
++
++/* general flags */
++#define IPSET_MACIP_MATCHUNSET 1
++
++/* per ip flags */
++#define IPSET_MACIP_ISSET 1
++
++struct ip_set_macipmap {
++ void *members; /* the macipmap proper */
++ ip_set_ip_t first_ip; /* host byte order, included in range */
++ ip_set_ip_t last_ip; /* host byte order, included in range */
++ u_int32_t flags;
++};
++
++struct ip_set_req_macipmap_create {
++ ip_set_ip_t from;
++ ip_set_ip_t to;
++ u_int32_t flags;
++};
++
++struct ip_set_req_macipmap {
++ ip_set_ip_t ip;
++ unsigned char ethernet[ETH_ALEN];
++};
++
++struct ip_set_macip {
++ unsigned short flags;
++ unsigned char ethernet[ETH_ALEN];
++};
++
++#endif /* __IP_SET_MACIPMAP_H */
+diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_malloc.h linux-new/include/linux/netfilter_ipv4/ip_set_malloc.h
+--- linux-old/include/linux/netfilter_ipv4/ip_set_malloc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/include/linux/netfilter_ipv4/ip_set_malloc.h 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,27 @@
++#ifndef _IP_SET_MALLOC_H
++#define _IP_SET_MALLOC_H
++
++#ifdef __KERNEL__
++
++/* Memory allocation and deallocation */
++static size_t max_malloc_size = 131072; /* Guaranteed: slab.c */
++
++static inline void * ip_set_malloc(size_t bytes)
++{
++ if (bytes > max_malloc_size)
++ return vmalloc(bytes);
++ else
++ return kmalloc(bytes, GFP_KERNEL);
++}
++
++static inline void ip_set_free(void * data, size_t bytes)
++{
++ if (bytes > max_malloc_size)
++ vfree(data);
++ else
++ kfree(data);
++}
++
++#endif /* __KERNEL__ */
++
++#endif /*_IP_SET_MALLOC_H*/
+diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_nethash.h linux-new/include/linux/netfilter_ipv4/ip_set_nethash.h
+--- linux-old/include/linux/netfilter_ipv4/ip_set_nethash.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/include/linux/netfilter_ipv4/ip_set_nethash.h 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,55 @@
++#ifndef __IP_SET_NETHASH_H
++#define __IP_SET_NETHASH_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++#define SETTYPE_NAME "nethash"
++#define MAX_RANGE 0x0000FFFF
++
++struct ip_set_nethash {
++ ip_set_ip_t *members; /* the nethash proper */
++ uint32_t initval; /* initval for jhash_1word */
++ uint32_t prime; /* prime for double hashing */
++ uint32_t hashsize; /* hash size */
++ uint16_t probes; /* max number of probes */
++ uint16_t resize; /* resize factor in percent */
++ unsigned char cidr[30]; /* CIDR sizes */
++};
++
++struct ip_set_req_nethash_create {
++ uint32_t hashsize;
++ uint16_t probes;
++ uint16_t resize;
++};
++
++struct ip_set_req_nethash {
++ ip_set_ip_t ip;
++ unsigned char cidr;
++};
++
++static unsigned char shifts[] = {255, 253, 249, 241, 225, 193, 129, 1};
++
++static inline ip_set_ip_t
++pack(ip_set_ip_t ip, unsigned char cidr)
++{
++ ip_set_ip_t addr, *paddr = &addr;
++ unsigned char n, t, *a;
++
++ addr = htonl(ip & (0xFFFFFFFF << (32 - (cidr))));
++#ifdef __KERNEL__
++ DP("ip:%u.%u.%u.%u/%u", NIPQUAD(addr), cidr);
++#endif
++ n = cidr / 8;
++ t = cidr % 8;
++ a = &((unsigned char *)paddr)[n];
++ *a = *a /(1 << (8 - t)) + shifts[t];
++#ifdef __KERNEL__
++ DP("n: %u, t: %u, a: %u", n, t, *a);
++ DP("ip:%u.%u.%u.%u/%u, %u.%u.%u.%u",
++ HIPQUAD(ip), cidr, NIPQUAD(addr));
++#endif
++
++ return ntohl(addr);
++}
++
++#endif /* __IP_SET_NETHASH_H */
+diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_portmap.h linux-new/include/linux/netfilter_ipv4/ip_set_portmap.h
+--- linux-old/include/linux/netfilter_ipv4/ip_set_portmap.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/include/linux/netfilter_ipv4/ip_set_portmap.h 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,25 @@
++#ifndef __IP_SET_PORTMAP_H
++#define __IP_SET_PORTMAP_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++#define SETTYPE_NAME "portmap"
++#define MAX_RANGE 0x0000FFFF
++#define INVALID_PORT (MAX_RANGE + 1)
++
++struct ip_set_portmap {
++ void *members; /* the portmap proper */
++ ip_set_ip_t first_port; /* host byte order, included in range */
++ ip_set_ip_t last_port; /* host byte order, included in range */
++};
++
++struct ip_set_req_portmap_create {
++ ip_set_ip_t from;
++ ip_set_ip_t to;
++};
++
++struct ip_set_req_portmap {
++ ip_set_ip_t port;
++};
++
++#endif /* __IP_SET_PORTMAP_H */
+diff -Naur linux-old/include/linux/netfilter_ipv4/ip_set_prime.h linux-new/include/linux/netfilter_ipv4/ip_set_prime.h
+--- linux-old/include/linux/netfilter_ipv4/ip_set_prime.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/include/linux/netfilter_ipv4/ip_set_prime.h 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,34 @@
++#ifndef __IP_SET_PRIME_H
++#define __IP_SET_PRIME_H
++
++static inline unsigned make_prime_bound(unsigned nr)
++{
++ unsigned long long nr64 = nr;
++ unsigned long long x = 1;
++ nr = 1;
++ while (x <= nr64) { x <<= 2; nr <<= 1; }
++ return nr;
++}
++
++static inline int make_prime_check(unsigned nr)
++{
++ unsigned x = 3;
++ unsigned b = make_prime_bound(nr);
++ while (x <= b) {
++ if (0 == (nr % x)) return 0;
++ x += 2;
++ }
++ return 1;
++}
++
++static unsigned make_prime(unsigned nr)
++{
++ if (0 == (nr & 1)) nr--;
++ while (nr > 1) {
++ if (make_prime_check(nr)) return nr;
++ nr -= 2;
++ }
++ return 2;
++}
++
++#endif /* __IP_SET_PRIME_H */
+diff -Naur linux-old/include/linux/netfilter_ipv4/ipt_set.h linux-new/include/linux/netfilter_ipv4/ipt_set.h
+--- linux-old/include/linux/netfilter_ipv4/ipt_set.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/include/linux/netfilter_ipv4/ipt_set.h 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,21 @@
++#ifndef _IPT_SET_H
++#define _IPT_SET_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++struct ipt_set_info {
++ ip_set_id_t index;
++ u_int32_t flags[IP_SET_MAX_BINDINGS + 1];
++};
++
++/* match info */
++struct ipt_set_info_match {
++ struct ipt_set_info match_set;
++};
++
++struct ipt_set_info_target {
++ struct ipt_set_info add_set;
++ struct ipt_set_info del_set;
++};
++
++#endif /*_IPT_SET_H*/
+diff -Naur linux-old/net/ipv4/netfilter/Config.in linux-new/net/ipv4/netfilter/Config.in
+--- linux-old/net/ipv4/netfilter/Config.in 2005-07-23 23:34:46.000000000 +0200
++++ linux-new/net/ipv4/netfilter/Config.in 2005-08-10 22:13:01.000000000 +0200
+@@ -21,6 +21,20 @@
+ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then
+ # The simple matches.
+ dep_tristate ' limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES
++
++ dep_tristate ' IP set support' CONFIG_IP_NF_SET $CONFIG_IP_NF_IPTABLES
++ if [ "$CONFIG_IP_NF_SET" != "n" ]; then
++ int ' Maximum number of sets' CONFIG_IP_NF_SET_MAX 256
++ int ' Hash size for bindings of IP sets' CONFIG_IP_NF_SET_HASHSIZE 1024
++ dep_tristate ' set match support' CONFIG_IP_NF_MATCH_SET $CONFIG_IP_NF_SET
++ dep_tristate ' SET target support' CONFIG_IP_NF_TARGET_SET $CONFIG_IP_NF_SET
++ dep_tristate ' ipmap set type support' CONFIG_IP_NF_SET_IPMAP $CONFIG_IP_NF_SET
++ dep_tristate ' portmap set type support' CONFIG_IP_NF_SET_PORTMAP $CONFIG_IP_NF_SET
++ dep_tristate ' macipmap set type support' CONFIG_IP_NF_SET_MACIPMAP $CONFIG_IP_NF_SET
++ dep_tristate ' iphash set type support' CONFIG_IP_NF_SET_IPHASH $CONFIG_IP_NF_SET
++ dep_tristate ' nethash set type support' CONFIG_IP_NF_SET_NETHASH $CONFIG_IP_NF_SET
++ dep_tristate ' iptree set type support' CONFIG_IP_NF_SET_IPTREE $CONFIG_IP_NF_SET
++ fi
+ dep_tristate ' MAC address match support' CONFIG_IP_NF_MATCH_MAC $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' Packet type match support' CONFIG_IP_NF_MATCH_PKTTYPE $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
+diff -Naur linux-old/net/ipv4/netfilter/ip_set.c linux-new/net/ipv4/netfilter/ip_set.c
+--- linux-old/net/ipv4/netfilter/ip_set.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/net/ipv4/netfilter/ip_set.c 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,2002 @@
++/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
++ * Patrick Schaaf <bof@bof.de>
++ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module for IP set management */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kmod.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/random.h>
++#include <linux/jhash.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <asm/softirq.h>
++#include <asm/semaphore.h>
++#include <linux/spinlock.h>
++#include <linux/vmalloc.h>
++
++#define ASSERT_READ_LOCK(x) /* dont use that */
++#define ASSERT_WRITE_LOCK(x)
++#include <linux/netfilter_ipv4/listhelp.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++
++static struct list_head set_type_list; /* all registered sets */
++static struct ip_set **ip_set_list; /* all individual sets */
++static DECLARE_RWLOCK(ip_set_lock); /* protects the lists and the hash */
++static DECLARE_MUTEX(ip_set_app_mutex); /* serializes user access */
++static ip_set_id_t ip_set_max = CONFIG_IP_NF_SET_MAX;
++static ip_set_id_t ip_set_bindings_hash_size = CONFIG_IP_NF_SET_HASHSIZE;
++static struct list_head *ip_set_hash; /* hash of bindings */
++static unsigned int ip_set_hash_random; /* random seed */
++
++/* Arrgh */
++#ifdef MODULE
++#define __MOD_INC(foo) __MOD_INC_USE_COUNT(foo)
++#define __MOD_DEC(foo) __MOD_DEC_USE_COUNT(foo)
++#define __MOD_INC_SELF MOD_INC_USE_COUNT
++#define __MOD_DEC_SELF MOD_DEC_USE_COUNT
++#else
++#define __MOD_INC(foo)
++#define __MOD_DEC(foo)
++#define __MOD_INC_SELF
++#define __MOD_DEC_SELF
++#endif
++
++/*
++ * Sets are identified either by the index in ip_set_list or by id.
++ * The id never changes and is used to find a key in the hash.
++ * The index may change by swapping and used at all other places
++ * (set/SET netfilter modules, binding value, etc.)
++ *
++ * Userspace requests are serialized by ip_set_mutex and sets can
++ * be deleted only from userspace. Therefore ip_set_list locking
++ * must obey the following rules:
++ *
++ * - kernel requests: read and write locking mandatory
++ * - user requests: read locking optional, write locking mandatory
++ */
++
++static inline void
++__ip_set_get(ip_set_id_t index)
++{
++ atomic_inc(&ip_set_list[index]->ref);
++}
++
++static inline void
++__ip_set_put(ip_set_id_t index)
++{
++ atomic_dec(&ip_set_list[index]->ref);
++}
++
++/*
++ * Binding routines
++ */
++
++static inline int
++ip_hash_cmp(const struct ip_set_hash *set_hash,
++ ip_set_id_t id, ip_set_ip_t ip)
++{
++ return set_hash->id == id && set_hash->ip == ip;
++}
++
++static ip_set_id_t
++ip_set_find_in_hash(ip_set_id_t id, ip_set_ip_t ip)
++{
++ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
++ % ip_set_bindings_hash_size;
++ struct ip_set_hash *set_hash;
++
++ MUST_BE_READ_LOCKED(&ip_set_lock);
++ IP_SET_ASSERT(ip_set_list[id]);
++ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
++
++ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp,
++ struct ip_set_hash *, id, ip);
++
++ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
++ HIPQUAD(ip),
++ set_hash != NULL ? ip_set_list[set_hash->binding]->name : "");
++
++ return (set_hash != NULL ? set_hash->binding : IP_SET_INVALID_ID);
++}
++
++static inline void
++__set_hash_del(struct ip_set_hash *set_hash)
++{
++ MUST_BE_WRITE_LOCKED(&ip_set_lock);
++ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
++
++ __ip_set_put(set_hash->binding);
++ list_del(&set_hash->list);
++ kfree(set_hash);
++}
++
++static int
++ip_set_hash_del(ip_set_id_t id, ip_set_ip_t ip)
++{
++ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
++ % ip_set_bindings_hash_size;
++ struct ip_set_hash *set_hash;
++
++ IP_SET_ASSERT(ip_set_list[id]);
++ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
++ WRITE_LOCK(&ip_set_lock);
++ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp,
++ struct ip_set_hash *, id, ip);
++ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
++ HIPQUAD(ip),
++ set_hash != NULL ? ip_set_list[set_hash->binding]->name : "");
++
++ if (set_hash != NULL)
++ __set_hash_del(set_hash);
++ WRITE_UNLOCK(&ip_set_lock);
++ return 0;
++}
++
++static int
++ip_set_hash_add(ip_set_id_t id, ip_set_ip_t ip, ip_set_id_t binding)
++{
++ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
++ % ip_set_bindings_hash_size;
++ struct ip_set_hash *set_hash;
++ int ret = 0;
++
++ IP_SET_ASSERT(ip_set_list[id]);
++ IP_SET_ASSERT(ip_set_list[binding]);
++ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
++ HIPQUAD(ip), ip_set_list[binding]->name);
++ WRITE_LOCK(&ip_set_lock);
++ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp,
++ struct ip_set_hash *, id, ip);
++ if (!set_hash) {
++ set_hash = kmalloc(sizeof(struct ip_set_hash), GFP_KERNEL);
++ if (!set_hash) {
++ ret = -ENOMEM;
++ goto unlock;
++ }
++ INIT_LIST_HEAD(&set_hash->list);
++ set_hash->id = id;
++ set_hash->ip = ip;
++ list_add(&ip_set_hash[key], &set_hash->list);
++ } else {
++ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
++ DP("overwrite binding: %s",
++ ip_set_list[set_hash->binding]->name);
++ __ip_set_put(set_hash->binding);
++ }
++ set_hash->binding = binding;
++ __ip_set_get(set_hash->binding);
++ unlock:
++ WRITE_UNLOCK(&ip_set_lock);
++ return ret;
++}
++
++#define FOREACH_HASH_DO(fn, args...) \
++({ \
++ ip_set_id_t __key; \
++ struct ip_set_hash *__set_hash; \
++ \
++ for (__key = 0; __key < ip_set_bindings_hash_size; __key++) { \
++ list_for_each_entry(__set_hash, &ip_set_hash[__key], list) \
++ fn(__set_hash , ## args); \
++ } \
++})
++
++#define FOREACH_HASH_RW_DO(fn, args...) \
++({ \
++ ip_set_id_t __key; \
++ struct ip_set_hash *__set_hash, *__n; \
++ \
++ MUST_BE_WRITE_LOCKED(&ip_set_lock); \
++ for (__key = 0; __key < ip_set_bindings_hash_size; __key++) { \
++ list_for_each_entry_safe(__set_hash, __n, &ip_set_hash[__key], list)\
++ fn(__set_hash , ## args); \
++ } \
++})
++
++/* Add, del and test set entries from kernel */
++
++#define follow_bindings(index, set, ip) \
++((index = ip_set_find_in_hash((set)->id, ip)) != IP_SET_INVALID_ID \
++ || (index = (set)->binding) != IP_SET_INVALID_ID)
++
++int
++ip_set_testip_kernel(ip_set_id_t index,
++ const struct sk_buff *skb,
++ const u_int32_t *flags)
++{
++ struct ip_set *set;
++ ip_set_ip_t ip;
++ int res, i = 0;
++
++ IP_SET_ASSERT(flags[i]);
++ READ_LOCK(&ip_set_lock);
++ do {
++ set = ip_set_list[index];
++ IP_SET_ASSERT(set);
++ DP("set %s, index %u", set->name, index);
++ read_lock_bh(&set->lock);
++ res = set->type->testip_kernel(set, skb, flags[i], &ip);
++ read_unlock_bh(&set->lock);
++ } while (res > 0
++ && flags[++i]
++ && follow_bindings(index, set, ip));
++ READ_UNLOCK(&ip_set_lock);
++
++ return res;
++}
++
++void
++ip_set_addip_kernel(ip_set_id_t index,
++ const struct sk_buff *skb,
++ const u_int32_t *flags)
++{
++ struct ip_set *set;
++ ip_set_ip_t ip;
++ int res, i= 0;
++
++ IP_SET_ASSERT(flags[i]);
++ retry:
++ READ_LOCK(&ip_set_lock);
++ do {
++ set = ip_set_list[index];
++ IP_SET_ASSERT(set);
++ DP("set %s, index %u", set->name, index);
++ write_lock_bh(&set->lock);
++ res = set->type->addip_kernel(set, skb, flags[i], &ip);
++ write_unlock_bh(&set->lock);
++ } while ((res == 0 || res == -EEXIST)
++ && flags[++i]
++ && follow_bindings(index, set, ip));
++ READ_UNLOCK(&ip_set_lock);
++
++ if (res == -EAGAIN
++ && set->type->retry
++ && (res = set->type->retry(set)) == 0)
++ goto retry;
++}
++
++void
++ip_set_delip_kernel(ip_set_id_t index,
++ const struct sk_buff *skb,
++ const u_int32_t *flags)
++{
++ struct ip_set *set;
++ ip_set_ip_t ip;
++ int res, i = 0;
++
++ IP_SET_ASSERT(flags[i]);
++ READ_LOCK(&ip_set_lock);
++ do {
++ set = ip_set_list[index];
++ IP_SET_ASSERT(set);
++ DP("set %s, index %u", set->name, index);
++ write_lock_bh(&set->lock);
++ res = set->type->delip_kernel(set, skb, flags[i], &ip);
++ write_unlock_bh(&set->lock);
++ } while ((res == 0 || res == -EEXIST)
++ && flags[++i]
++ && follow_bindings(index, set, ip));
++ READ_UNLOCK(&ip_set_lock);
++}
++
++/* Register and deregister settype */
++
++static inline int
++set_type_equal(const struct ip_set_type *set_type, const char *str2)
++{
++ return !strncmp(set_type->typename, str2, IP_SET_MAXNAMELEN - 1);
++}
++
++static inline struct ip_set_type *
++find_set_type(const char *name)
++{
++ return LIST_FIND(&set_type_list,
++ set_type_equal,
++ struct ip_set_type *,
++ name);
++}
++
++int
++ip_set_register_set_type(struct ip_set_type *set_type)
++{
++ int ret = 0;
++
++ if (set_type->protocol_version != IP_SET_PROTOCOL_VERSION) {
++ ip_set_printk("'%s' uses wrong protocol version %u (want %u)",
++ set_type->typename,
++ set_type->protocol_version,
++ IP_SET_PROTOCOL_VERSION);
++ return -EINVAL;
++ }
++
++ WRITE_LOCK(&ip_set_lock);
++ if (find_set_type(set_type->typename)) {
++ /* Duplicate! */
++ ip_set_printk("'%s' already registered!",
++ set_type->typename);
++ ret = -EINVAL;
++ goto unlock;
++ }
++ __MOD_INC_SELF;
++ list_append(&set_type_list, set_type);
++ DP("'%s' registered.", set_type->typename);
++ unlock:
++ WRITE_UNLOCK(&ip_set_lock);
++ return ret;
++}
++
++void
++ip_set_unregister_set_type(struct ip_set_type *set_type)
++{
++ WRITE_LOCK(&ip_set_lock);
++ if (!find_set_type(set_type->typename)) {
++ ip_set_printk("'%s' not registered?",
++ set_type->typename);
++ goto unlock;
++ }
++ LIST_DELETE(&set_type_list, set_type);
++ __MOD_DEC_SELF;
++ DP("'%s' unregistered.", set_type->typename);
++ unlock:
++ WRITE_UNLOCK(&ip_set_lock);
++
++}
++
++/*
++ * Userspace routines
++ */
++
++/*
++ * Find set by name, reference it once. The reference makes sure the
++ * thing pointed to, does not go away under our feet. Drop the reference
++ * later, using ip_set_put().
++ */
++ip_set_id_t
++ip_set_get_byname(const char *name)
++{
++ ip_set_id_t i, index = IP_SET_INVALID_ID;
++
++ down(&ip_set_app_mutex);
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] != NULL
++ && strcmp(ip_set_list[i]->name, name) == 0) {
++ __ip_set_get(i);
++ index = i;
++ break;
++ }
++ }
++ up(&ip_set_app_mutex);
++ return index;
++}
++
++/*
++ * Find set by index, reference it once. The reference makes sure the
++ * thing pointed to, does not go away under our feet. Drop the reference
++ * later, using ip_set_put().
++ */
++ip_set_id_t
++ip_set_get_byindex(ip_set_id_t index)
++{
++ down(&ip_set_app_mutex);
++
++ if (index >= ip_set_max)
++ return IP_SET_INVALID_ID;
++
++ if (ip_set_list[index])
++ __ip_set_get(index);
++ else
++ index = IP_SET_INVALID_ID;
++
++ up(&ip_set_app_mutex);
++ return index;
++}
++
++/*
++ * If the given set pointer points to a valid set, decrement
++ * reference count by 1. The caller shall not assume the index
++ * to be valid, after calling this function.
++ */
++void ip_set_put(ip_set_id_t index)
++{
++ down(&ip_set_app_mutex);
++ if (ip_set_list[index])
++ __ip_set_put(index);
++ up(&ip_set_app_mutex);
++}
++
++/* Find a set by name or index */
++static ip_set_id_t
++ip_set_find_byname(const char *name)
++{
++ ip_set_id_t i, index = IP_SET_INVALID_ID;
++
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] != NULL
++ && strcmp(ip_set_list[i]->name, name) == 0) {
++ index = i;
++ break;
++ }
++ }
++ return index;
++}
++
++static ip_set_id_t
++ip_set_find_byindex(ip_set_id_t index)
++{
++ if (index >= ip_set_max || ip_set_list[index] == NULL)
++ index = IP_SET_INVALID_ID;
++
++ return index;
++}
++
++/*
++ * Add, del, test, bind and unbind
++ */
++
++static inline int
++__ip_set_testip(struct ip_set *set,
++ const void *data,
++ size_t size,
++ ip_set_ip_t *ip)
++{
++ int res;
++
++ read_lock_bh(&set->lock);
++ res = set->type->testip(set, data, size, ip);
++ read_unlock_bh(&set->lock);
++
++ return res;
++}
++
++static int
++__ip_set_addip(ip_set_id_t index,
++ const void *data,
++ size_t size)
++{
++ struct ip_set *set = ip_set_list[index];
++ ip_set_ip_t ip;
++ int res;
++
++ IP_SET_ASSERT(set);
++ do {
++ write_lock_bh(&set->lock);
++ res = set->type->addip(set, data, size, &ip);
++ write_unlock_bh(&set->lock);
++ } while (res == -EAGAIN
++ && set->type->retry
++ && (res = set->type->retry(set)) == 0);
++
++ return res;
++}
++
++static int
++ip_set_addip(ip_set_id_t index,
++ const void *data,
++ size_t size)
++{
++
++ return __ip_set_addip(index,
++ data + sizeof(struct ip_set_req_adt),
++ size - sizeof(struct ip_set_req_adt));
++}
++
++static int
++ip_set_delip(ip_set_id_t index,
++ const void *data,
++ size_t size)
++{
++ struct ip_set *set = ip_set_list[index];
++ ip_set_ip_t ip;
++ int res;
++
++ IP_SET_ASSERT(set);
++ write_lock_bh(&set->lock);
++ res = set->type->delip(set,
++ data + sizeof(struct ip_set_req_adt),
++ size - sizeof(struct ip_set_req_adt),
++ &ip);
++ write_unlock_bh(&set->lock);
++
++ return res;
++}
++
++static int
++ip_set_testip(ip_set_id_t index,
++ const void *data,
++ size_t size)
++{
++ struct ip_set *set = ip_set_list[index];
++ ip_set_ip_t ip;
++ int res;
++
++ IP_SET_ASSERT(set);
++ res = __ip_set_testip(set,
++ data + sizeof(struct ip_set_req_adt),
++ size - sizeof(struct ip_set_req_adt),
++ &ip);
++
++ return (res > 0 ? -EEXIST : res);
++}
++
++static int
++ip_set_bindip(ip_set_id_t index,
++ const void *data,
++ size_t size)
++{
++ struct ip_set *set = ip_set_list[index];
++ struct ip_set_req_bind *req_bind;
++ ip_set_id_t binding;
++ ip_set_ip_t ip;
++ int res;
++
++ IP_SET_ASSERT(set);
++ if (size < sizeof(struct ip_set_req_bind))
++ return -EINVAL;
++
++ req_bind = (struct ip_set_req_bind *) data;
++ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
++
++ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
++ /* Default binding of a set */
++ char *binding_name;
++
++ if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN)
++ return -EINVAL;
++
++ binding_name = (char *)(data + sizeof(struct ip_set_req_bind));
++ binding_name[IP_SET_MAXNAMELEN - 1] = '\0';
++
++ binding = ip_set_find_byname(binding_name);
++ if (binding == IP_SET_INVALID_ID)
++ return -ENOENT;
++
++ WRITE_LOCK(&ip_set_lock);
++ /* Sets as binding values are referenced */
++ if (set->binding != IP_SET_INVALID_ID)
++ __ip_set_put(set->binding);
++ set->binding = binding;
++ __ip_set_get(set->binding);
++ WRITE_UNLOCK(&ip_set_lock);
++
++ return 0;
++ }
++ binding = ip_set_find_byname(req_bind->binding);
++ if (binding == IP_SET_INVALID_ID)
++ return -ENOENT;
++
++ res = __ip_set_testip(set,
++ data + sizeof(struct ip_set_req_bind),
++ size - sizeof(struct ip_set_req_bind),
++ &ip);
++ DP("set %s, ip: %u.%u.%u.%u, binding %s",
++ set->name, HIPQUAD(ip), ip_set_list[binding]->name);
++
++ if (res >= 0)
++ res = ip_set_hash_add(set->id, ip, binding);
++
++ return res;
++}
++
++#define FOREACH_SET_DO(fn, args...) \
++({ \
++ ip_set_id_t __i; \
++ struct ip_set *__set; \
++ \
++ for (__i = 0; __i < ip_set_max; __i++) { \
++ __set = ip_set_list[__i]; \
++ if (__set != NULL) \
++ fn(__set , ##args); \
++ } \
++})
++
++static inline void
++__set_hash_del_byid(struct ip_set_hash *set_hash, ip_set_id_t id)
++{
++ if (set_hash->id == id)
++ __set_hash_del(set_hash);
++}
++
++static inline void
++__unbind_default(struct ip_set *set)
++{
++ if (set->binding != IP_SET_INVALID_ID) {
++ /* Sets as binding values are referenced */
++ __ip_set_put(set->binding);
++ set->binding = IP_SET_INVALID_ID;
++ }
++}
++
++static int
++ip_set_unbindip(ip_set_id_t index,
++ const void *data,
++ size_t size)
++{
++ struct ip_set *set;
++ struct ip_set_req_bind *req_bind;
++ ip_set_ip_t ip;
++ int res;
++
++ DP("");
++ if (size < sizeof(struct ip_set_req_bind))
++ return -EINVAL;
++
++ req_bind = (struct ip_set_req_bind *) data;
++ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
++
++ DP("%u %s", index, req_bind->binding);
++ if (index == IP_SET_INVALID_ID) {
++ /* unbind :all: */
++ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
++ /* Default binding of sets */
++ WRITE_LOCK(&ip_set_lock);
++ FOREACH_SET_DO(__unbind_default);
++ WRITE_UNLOCK(&ip_set_lock);
++ return 0;
++ } else if (strcmp(req_bind->binding, IPSET_TOKEN_ALL) == 0) {
++ /* Flush all bindings of all sets*/
++ WRITE_LOCK(&ip_set_lock);
++ FOREACH_HASH_RW_DO(__set_hash_del);
++ WRITE_UNLOCK(&ip_set_lock);
++ return 0;
++ }
++ DP("unreachable reached!");
++ return -EINVAL;
++ }
++
++ set = ip_set_list[index];
++ IP_SET_ASSERT(set);
++ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
++ /* Default binding of set */
++ ip_set_id_t binding = ip_set_find_byindex(set->binding);
++
++ if (binding == IP_SET_INVALID_ID)
++ return -ENOENT;
++
++ WRITE_LOCK(&ip_set_lock);
++ /* Sets in hash values are referenced */
++ __ip_set_put(set->binding);
++ set->binding = IP_SET_INVALID_ID;
++ WRITE_UNLOCK(&ip_set_lock);
++
++ return 0;
++ } else if (strcmp(req_bind->binding, IPSET_TOKEN_ALL) == 0) {
++ /* Flush all bindings */
++
++ WRITE_LOCK(&ip_set_lock);
++ FOREACH_HASH_RW_DO(__set_hash_del_byid, set->id);
++ WRITE_UNLOCK(&ip_set_lock);
++ return 0;
++ }
++
++ res = __ip_set_testip(set,
++ data + sizeof(struct ip_set_req_bind),
++ size - sizeof(struct ip_set_req_bind),
++ &ip);
++
++ DP("set %s, ip: %u.%u.%u.%u", set->name, HIPQUAD(ip));
++ if (res >= 0)
++ res = ip_set_hash_del(set->id, ip);
++
++ return res;
++}
++
++static int
++ip_set_testbind(ip_set_id_t index,
++ const void *data,
++ size_t size)
++{
++ struct ip_set *set = ip_set_list[index];
++ struct ip_set_req_bind *req_bind;
++ ip_set_id_t binding;
++ ip_set_ip_t ip;
++ int res;
++
++ IP_SET_ASSERT(set);
++ if (size < sizeof(struct ip_set_req_bind))
++ return -EINVAL;
++
++ req_bind = (struct ip_set_req_bind *) data;
++ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
++
++ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
++ /* Default binding of set */
++ char *binding_name;
++
++ if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN)
++ return -EINVAL;
++
++ binding_name = (char *)(data + sizeof(struct ip_set_req_bind));
++ binding_name[IP_SET_MAXNAMELEN - 1] = '\0';
++
++ binding = ip_set_find_byname(binding_name);
++ if (binding == IP_SET_INVALID_ID)
++ return -ENOENT;
++
++ res = (set->binding == binding) ? -EEXIST : 0;
++
++ return res;
++ }
++ binding = ip_set_find_byname(req_bind->binding);
++ if (binding == IP_SET_INVALID_ID)
++ return -ENOENT;
++
++
++ res = __ip_set_testip(set,
++ data + sizeof(struct ip_set_req_bind),
++ size - sizeof(struct ip_set_req_bind),
++ &ip);
++ DP("set %s, ip: %u.%u.%u.%u, binding %s",
++ set->name, HIPQUAD(ip), ip_set_list[binding]->name);
++
++ if (res >= 0)
++ res = (ip_set_find_in_hash(set->id, ip) == binding)
++ ? -EEXIST : 0;
++
++ return res;
++}
++
++static struct ip_set_type *
++find_set_type_rlock(const char *typename)
++{
++ struct ip_set_type *type;
++
++ READ_LOCK(&ip_set_lock);
++ type = find_set_type(typename);
++ if (type == NULL)
++ READ_UNLOCK(&ip_set_lock);
++
++ return type;
++}
++
++static int
++find_free_id(const char *name,
++ ip_set_id_t *index,
++ ip_set_id_t *id)
++{
++ ip_set_id_t i;
++
++ *id = IP_SET_INVALID_ID;
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] == NULL) {
++ if (*id == IP_SET_INVALID_ID)
++ *id = *index = i;
++ } else if (strcmp(name, ip_set_list[i]->name) == 0)
++ /* Name clash */
++ return -EEXIST;
++ }
++ if (*id == IP_SET_INVALID_ID)
++ /* No free slot remained */
++ return -ERANGE;
++ /* Check that index is usable as id (swapping) */
++ check:
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] != NULL
++ && ip_set_list[i]->id == *id) {
++ *id = i;
++ goto check;
++ }
++ }
++ return 0;
++}
++
++/*
++ * Create a set
++ */
++static int
++ip_set_create(const char *name,
++ const char *typename,
++ ip_set_id_t restore,
++ const void *data,
++ size_t size)
++{
++ struct ip_set *set;
++ ip_set_id_t index, id;
++ int res = 0;
++
++ DP("setname: %s, typename: %s, id: %u", name, typename, restore);
++ /*
++ * First, and without any locks, allocate and initialize
++ * a normal base set structure.
++ */
++ set = kmalloc(sizeof(struct ip_set), GFP_KERNEL);
++ if (!set)
++ return -ENOMEM;
++ set->lock = RW_LOCK_UNLOCKED;
++ strncpy(set->name, name, IP_SET_MAXNAMELEN);
++ set->binding = IP_SET_INVALID_ID;
++ atomic_set(&set->ref, 0);
++
++ /*
++ * Next, take the &ip_set_lock, check that we know the type,
++ * and take a reference on the type, to make sure it
++ * stays available while constructing our new set.
++ *
++ * After referencing the type, we drop the &ip_set_lock,
++ * and let the new set construction run without locks.
++ */
++ set->type = find_set_type_rlock(typename);
++ if (set->type == NULL) {
++ /* Try loading the module */
++ char modulename[IP_SET_MAXNAMELEN + strlen("ip_set_") + 1];
++ strcpy(modulename, "ip_set_");
++ strcat(modulename, typename);
++ DP("try to load %s", modulename);
++ request_module(modulename);
++ set->type = find_set_type_rlock(typename);
++ }
++ if (set->type == NULL) {
++ ip_set_printk("no set type '%s', set '%s' not created",
++ typename, name);
++ kfree(set);
++ return -ENOENT;
++ }
++ __MOD_INC(set->type->me);
++ READ_UNLOCK(&ip_set_lock);
++
++ /*
++ * Without holding any locks, create private part.
++ */
++ res = set->type->create(set, data, size);
++ if (res != 0) {
++ __MOD_DEC(set->type->me);
++ kfree(set);
++ return res;
++ }
++
++ /* BTW, res==0 here. */
++
++ /*
++ * Here, we have a valid, constructed set. &ip_set_lock again,
++ * find free id/index and check that it is not already in
++ * ip_set_list.
++ */
++ WRITE_LOCK(&ip_set_lock);
++ if ((res = find_free_id(set->name, &index, &id)) != 0) {
++ DP("no free id!");
++ goto cleanup;
++ }
++
++ /* Make sure restore gets the same index */
++ if (restore != IP_SET_INVALID_ID && index != restore) {
++ DP("Can't restore, sets are screwed up");
++ res = -ERANGE;
++ goto cleanup;
++ }
++
++ /*
++ * Finally! Add our shiny new set to the list, and be done.
++ */
++ DP("create: '%s' created with index %u, id %u!", set->name, index, id);
++ set->id = id;
++ ip_set_list[index] = set;
++ WRITE_UNLOCK(&ip_set_lock);
++ return res;
++
++ cleanup:
++ WRITE_UNLOCK(&ip_set_lock);
++ set->type->destroy(set);
++ __MOD_DEC(set->type->me);
++ kfree(set);
++ return res;
++}
++
++/*
++ * Destroy a given existing set
++ */
++static void
++ip_set_destroy_set(ip_set_id_t index)
++{
++ struct ip_set *set = ip_set_list[index];
++
++ IP_SET_ASSERT(set);
++ DP("set: %s", set->name);
++ WRITE_LOCK(&ip_set_lock);
++ FOREACH_HASH_RW_DO(__set_hash_del_byid, set->id);
++ if (set->binding != IP_SET_INVALID_ID)
++ __ip_set_put(set->binding);
++ ip_set_list[index] = NULL;
++ WRITE_UNLOCK(&ip_set_lock);
++
++ /* Must call it without holding any lock */
++ set->type->destroy(set);
++ __MOD_DEC(set->type->me);
++ kfree(set);
++}
++
++/*
++ * Destroy a set - or all sets
++ * Sets must not be referenced/used.
++ */
++static int
++ip_set_destroy(ip_set_id_t index)
++{
++ ip_set_id_t i;
++
++ /* ref modification always protected by the mutex */
++ if (index != IP_SET_INVALID_ID) {
++ if (atomic_read(&ip_set_list[index]->ref))
++ return -EBUSY;
++ ip_set_destroy_set(index);
++ } else {
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] != NULL
++ && (atomic_read(&ip_set_list[i]->ref)))
++ return -EBUSY;
++ }
++
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] != NULL)
++ ip_set_destroy_set(i);
++ }
++ }
++ return 0;
++}
++
++static void
++ip_set_flush_set(struct ip_set *set)
++{
++ DP("set: %s %u", set->name, set->id);
++
++ write_lock_bh(&set->lock);
++ set->type->flush(set);
++ write_unlock_bh(&set->lock);
++}
++
++/*
++ * Flush data in a set - or in all sets
++ */
++static int
++ip_set_flush(ip_set_id_t index)
++{
++ if (index != IP_SET_INVALID_ID) {
++ IP_SET_ASSERT(ip_set_list[index]);
++ ip_set_flush_set(ip_set_list[index]);
++ } else
++ FOREACH_SET_DO(ip_set_flush_set);
++
++ return 0;
++}
++
++/* Rename a set */
++static int
++ip_set_rename(ip_set_id_t index, const char *name)
++{
++ struct ip_set *set = ip_set_list[index];
++ ip_set_id_t i;
++ int res = 0;
++
++ DP("set: %s to %s", set->name, name);
++ WRITE_LOCK(&ip_set_lock);
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] != NULL
++ && strncmp(ip_set_list[i]->name,
++ name,
++ IP_SET_MAXNAMELEN - 1) == 0) {
++ res = -EEXIST;
++ goto unlock;
++ }
++ }
++ strncpy(set->name, name, IP_SET_MAXNAMELEN);
++ unlock:
++ WRITE_UNLOCK(&ip_set_lock);
++ return res;
++}
++
++/*
++ * Swap two sets so that name/index points to the other.
++ * References are also swapped.
++ */
++static int
++ip_set_swap(ip_set_id_t from_index, ip_set_id_t to_index)
++{
++ struct ip_set *from = ip_set_list[from_index];
++ struct ip_set *to = ip_set_list[to_index];
++ char from_name[IP_SET_MAXNAMELEN];
++ u_int32_t from_ref;
++
++ DP("set: %s to %s", from->name, to->name);
++ /* Type can't be changed. Artifical restriction. */
++ if (from->type->typecode != to->type->typecode)
++ return -ENOEXEC;
++
++ /* No magic here: ref munging protected by the mutex */
++ WRITE_LOCK(&ip_set_lock);
++ strncpy(from_name, from->name, IP_SET_MAXNAMELEN);
++ from_ref = atomic_read(&from->ref);
++
++ strncpy(from->name, to->name, IP_SET_MAXNAMELEN);
++ atomic_set(&from->ref, atomic_read(&to->ref));
++ strncpy(to->name, from_name, IP_SET_MAXNAMELEN);
++ atomic_set(&to->ref, from_ref);
++
++ ip_set_list[from_index] = to;
++ ip_set_list[to_index] = from;
++
++ WRITE_UNLOCK(&ip_set_lock);
++ return 0;
++}
++
++/*
++ * List set data
++ */
++
++static inline void
++__set_hash_bindings_size_list(struct ip_set_hash *set_hash,
++ ip_set_id_t id, size_t *size)
++{
++ if (set_hash->id == id)
++ *size += sizeof(struct ip_set_hash_list);
++}
++
++static inline void
++__set_hash_bindings_size_save(struct ip_set_hash *set_hash,
++ ip_set_id_t id, size_t *size)
++{
++ if (set_hash->id == id)
++ *size += sizeof(struct ip_set_hash_save);
++}
++
++static inline void
++__set_hash_bindings(struct ip_set_hash *set_hash,
++ ip_set_id_t id, void *data, int *used)
++{
++ if (set_hash->id == id) {
++ struct ip_set_hash_list *hash_list =
++ (struct ip_set_hash_list *)(data + *used);
++
++ hash_list->ip = set_hash->ip;
++ hash_list->binding = set_hash->binding;
++ *used += sizeof(struct ip_set_hash_list);
++ }
++}
++
++static int ip_set_list_set(ip_set_id_t index,
++ void *data,
++ int *used,
++ int len)
++{
++ struct ip_set *set = ip_set_list[index];
++ struct ip_set_list *set_list;
++
++ /* Pointer to our header */
++ set_list = (struct ip_set_list *) (data + *used);
++
++ DP("set: %s, used: %d %p %p", set->name, *used, data, data + *used);
++
++ /* Get and ensure header size */
++ if (*used + sizeof(struct ip_set_list) > len)
++ goto not_enough_mem;
++ *used += sizeof(struct ip_set_list);
++
++ read_lock_bh(&set->lock);
++ /* Get and ensure set specific header size */
++ set_list->header_size = set->type->header_size;
++ if (*used + set_list->header_size > len)
++ goto unlock_set;
++
++ /* Fill in the header */
++ set_list->index = index;
++ set_list->binding = set->binding;
++ set_list->ref = atomic_read(&set->ref);
++
++ /* Fill in set spefific header data */
++ DP("call list_header");
++ set->type->list_header(set, data + *used);
++ DP("call list_header, done");
++ *used += set_list->header_size;
++
++ /* Get and ensure set specific members size */
++ DP("call list_members_size");
++ set_list->members_size = set->type->list_members_size(set);
++ DP("call list_members_size, done");
++ if (*used + set_list->members_size > len)
++ goto unlock_set;
++
++ /* Fill in set spefific members data */
++ DP("call list_members");
++ set->type->list_members(set, data + *used);
++ DP("call list_members, done");
++ *used += set_list->members_size;
++ read_unlock_bh(&set->lock);
++
++ /* Bindings */
++
++ /* Get and ensure set specific bindings size */
++ set_list->bindings_size = 0;
++ FOREACH_HASH_DO(__set_hash_bindings_size_list,
++ set->id, &set_list->bindings_size);
++ if (*used + set_list->bindings_size > len)
++ goto not_enough_mem;
++
++ /* Fill in set spefific bindings data */
++ FOREACH_HASH_DO(__set_hash_bindings, set->id, data, used);
++
++ return 0;
++
++ unlock_set:
++ read_unlock_bh(&set->lock);
++ not_enough_mem:
++ DP("not enough mem, try again");
++ return -EAGAIN;
++}
++
++/*
++ * Save sets
++ */
++static int ip_set_save_set(ip_set_id_t index,
++ void *data,
++ int *used,
++ int len)
++{
++ struct ip_set *set;
++ struct ip_set_save *set_save;
++
++ /* Pointer to our header */
++ set_save = (struct ip_set_save *) (data + *used);
++
++ /* Get and ensure header size */
++ if (*used + sizeof(struct ip_set_save) > len)
++ goto not_enough_mem;
++ *used += sizeof(struct ip_set_save);
++
++ set = ip_set_list[index];
++ DP("set: %s, used: %u(%u) %p %p", set->name, *used, len,
++ data, data + *used);
++
++ read_lock_bh(&set->lock);
++ /* Get and ensure set specific header size */
++ set_save->header_size = set->type->header_size;
++ if (*used + set_save->header_size > len)
++ goto unlock_set;
++
++ /* Fill in the header */
++ set_save->index = index;
++ set_save->binding = set->binding;
++
++ /* Fill in set spefific header data */
++ set->type->list_header(set, data + *used);
++ *used += set_save->header_size;
++
++ DP("set header filled: %s, used: %u %p %p", set->name, *used,
++ data, data + *used);
++ /* Get and ensure set specific members size */
++ set_save->members_size = set->type->list_members_size(set);
++ if (*used + set_save->members_size > len)
++ goto unlock_set;
++
++ /* Fill in set spefific members data */
++ set->type->list_members(set, data + *used);
++ *used += set_save->members_size;
++ read_unlock_bh(&set->lock);
++ DP("set members filled: %s, used: %u %p %p", set->name, *used,
++ data, data + *used);
++ return 0;
++
++ unlock_set:
++ read_unlock_bh(&set->lock);
++ not_enough_mem:
++ DP("not enough mem, try again");
++ return -EAGAIN;
++}
++
++static inline void
++__set_hash_save_bindings(struct ip_set_hash *set_hash,
++ ip_set_id_t id,
++ void *data,
++ int *used,
++ int len,
++ int *res)
++{
++ if (*res == 0
++ && (id == IP_SET_INVALID_ID || set_hash->id == id)) {
++ struct ip_set_hash_save *hash_save =
++ (struct ip_set_hash_save *)(data + *used);
++ /* Ensure bindings size */
++ if (*used + sizeof(struct ip_set_hash_save) > len) {
++ *res = -ENOMEM;
++ return;
++ }
++ hash_save->id = set_hash->id;
++ hash_save->ip = set_hash->ip;
++ hash_save->binding = set_hash->binding;
++ *used += sizeof(struct ip_set_hash_save);
++ }
++}
++
++static int ip_set_save_bindings(ip_set_id_t index,
++ void *data,
++ int *used,
++ int len)
++{
++ int res = 0;
++ struct ip_set_save *set_save;
++
++ DP("used %u, len %u", *used, len);
++ /* Get and ensure header size */
++ if (*used + sizeof(struct ip_set_save) > len)
++ return -ENOMEM;
++
++ /* Marker */
++ set_save = (struct ip_set_save *) (data + *used);
++ set_save->index = IP_SET_INVALID_ID;
++ *used += sizeof(struct ip_set_save);
++
++ DP("marker added used %u, len %u", *used, len);
++ /* Fill in bindings data */
++ if (index != IP_SET_INVALID_ID)
++ /* Sets are identified by id in hash */
++ index = ip_set_list[index]->id;
++ FOREACH_HASH_DO(__set_hash_save_bindings, index, data, used, len, &res);
++
++ return res;
++}
++
++/*
++ * Restore sets
++ */
++static int ip_set_restore(void *data,
++ int len)
++{
++ int res = 0;
++ int line = 0, used = 0, members_size;
++ struct ip_set *set;
++ struct ip_set_hash_save *hash_save;
++ struct ip_set_restore *set_restore;
++ ip_set_id_t index;
++
++ /* Loop to restore sets */
++ while (1) {
++ line++;
++
++ DP("%u %u %u", used, sizeof(struct ip_set_restore), len);
++ /* Get and ensure header size */
++ if (used + sizeof(struct ip_set_restore) > len)
++ return line;
++ set_restore = (struct ip_set_restore *) (data + used);
++ used += sizeof(struct ip_set_restore);
++
++ /* Ensure data size */
++ if (used
++ + set_restore->header_size
++ + set_restore->members_size > len)
++ return line;
++
++ /* Check marker */
++ if (set_restore->index == IP_SET_INVALID_ID) {
++ line--;
++ goto bindings;
++ }
++
++ /* Try to create the set */
++ DP("restore %s %s", set_restore->name, set_restore->typename);
++ res = ip_set_create(set_restore->name,
++ set_restore->typename,
++ set_restore->index,
++ data + used,
++ set_restore->header_size);
++
++ if (res != 0)
++ return line;
++ used += set_restore->header_size;
++
++ index = ip_set_find_byindex(set_restore->index);
++ DP("index %u, restore_index %u", index, set_restore->index);
++ if (index != set_restore->index)
++ return line;
++ /* Try to restore members data */
++ set = ip_set_list[index];
++ members_size = 0;
++ DP("members_size %u reqsize %u",
++ set_restore->members_size, set->type->reqsize);
++ while (members_size + set->type->reqsize <=
++ set_restore->members_size) {
++ line++;
++ DP("members: %u, line %u", members_size, line);
++ res = __ip_set_addip(index,
++ data + used + members_size,
++ set->type->reqsize);
++ if (!(res == 0 || res == -EEXIST))
++ return line;
++ members_size += set->type->reqsize;
++ }
++
++ DP("members_size %u %u",
++ set_restore->members_size, members_size);
++ if (members_size != set_restore->members_size)
++ return line++;
++ used += set_restore->members_size;
++ }
++
++ bindings:
++ /* Loop to restore bindings */
++ while (used < len) {
++ line++;
++
++ DP("restore binding, line %u", line);
++ /* Get and ensure size */
++ if (used + sizeof(struct ip_set_hash_save) > len)
++ return line;
++ hash_save = (struct ip_set_hash_save *) (data + used);
++ used += sizeof(struct ip_set_hash_save);
++
++ /* hash_save->id is used to store the index */
++ index = ip_set_find_byindex(hash_save->id);
++ DP("restore binding index %u, id %u, %u -> %u",
++ index, hash_save->id, hash_save->ip, hash_save->binding);
++ if (index != hash_save->id)
++ return line;
++
++ set = ip_set_list[hash_save->id];
++ /* Null valued IP means default binding */
++ if (hash_save->ip)
++ res = ip_set_hash_add(set->id,
++ hash_save->ip,
++ hash_save->binding);
++ else {
++ IP_SET_ASSERT(set->binding == IP_SET_INVALID_ID);
++ WRITE_LOCK(&ip_set_lock);
++ set->binding = hash_save->binding;
++ __ip_set_get(set->binding);
++ WRITE_UNLOCK(&ip_set_lock);
++ DP("default binding: %u", set->binding);
++ }
++ if (res != 0)
++ return line;
++ }
++ if (used != len)
++ return line;
++
++ return 0;
++}
++
++static int
++ip_set_sockfn_set(struct sock *sk, int optval, void *user, unsigned int len)
++{
++ void *data;
++ int res = 0; /* Assume OK */
++ unsigned *op;
++ struct ip_set_req_adt *req_adt;
++ ip_set_id_t index = IP_SET_INVALID_ID;
++ int (*adtfn)(ip_set_id_t index,
++ const void *data, size_t size);
++ struct fn_table {
++ int (*fn)(ip_set_id_t index,
++ const void *data, size_t size);
++ } adtfn_table[] =
++ { { ip_set_addip }, { ip_set_delip }, { ip_set_testip},
++ { ip_set_bindip}, { ip_set_unbindip }, { ip_set_testbind },
++ };
++
++ DP("optval=%d, user=%p, len=%d", optval, user, len);
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++ if (optval != SO_IP_SET)
++ return -EBADF;
++ if (len <= sizeof(unsigned)) {
++ ip_set_printk("short userdata (want >%zu, got %u)",
++ sizeof(unsigned), len);
++ return -EINVAL;
++ }
++ data = vmalloc(len);
++ if (!data) {
++ DP("out of mem for %u bytes", len);
++ return -ENOMEM;
++ }
++ if (copy_from_user(data, user, len) != 0) {
++ res = -EFAULT;
++ goto done;
++ }
++ if (down_interruptible(&ip_set_app_mutex)) {
++ res = -EINTR;
++ goto done;
++ }
++
++ op = (unsigned *)data;
++ DP("op=%x", *op);
++
++ if (*op < IP_SET_OP_VERSION) {
++ /* Check the version at the beginning of operations */
++ struct ip_set_req_version *req_version =
++ (struct ip_set_req_version *) data;
++ if (req_version->version != IP_SET_PROTOCOL_VERSION) {
++ res = -EPROTO;
++ goto done;
++ }
++ }
++
++ switch (*op) {
++ case IP_SET_OP_CREATE:{
++ struct ip_set_req_create *req_create
++ = (struct ip_set_req_create *) data;
++
++ if (len <= sizeof(struct ip_set_req_create)) {
++ ip_set_printk("short CREATE data (want >%zu, got %u)",
++ sizeof(struct ip_set_req_create), len);
++ res = -EINVAL;
++ goto done;
++ }
++ req_create->name[IP_SET_MAXNAMELEN - 1] = '\0';
++ req_create->typename[IP_SET_MAXNAMELEN - 1] = '\0';
++ res = ip_set_create(req_create->name,
++ req_create->typename,
++ IP_SET_INVALID_ID,
++ data + sizeof(struct ip_set_req_create),
++ len - sizeof(struct ip_set_req_create));
++ goto done;
++ }
++ case IP_SET_OP_DESTROY:{
++ struct ip_set_req_std *req_destroy
++ = (struct ip_set_req_std *) data;
++
++ if (len != sizeof(struct ip_set_req_std)) {
++ ip_set_printk("invalid DESTROY data (want %zu, got %u)",
++ sizeof(struct ip_set_req_std), len);
++ res = -EINVAL;
++ goto done;
++ }
++ if (strcmp(req_destroy->name, IPSET_TOKEN_ALL) == 0) {
++ /* Destroy all sets */
++ index = IP_SET_INVALID_ID;
++ } else {
++ req_destroy->name[IP_SET_MAXNAMELEN - 1] = '\0';
++ index = ip_set_find_byname(req_destroy->name);
++
++ if (index == IP_SET_INVALID_ID) {
++ res = -ENOENT;
++ goto done;
++ }
++ }
++
++ res = ip_set_destroy(index);
++ goto done;
++ }
++ case IP_SET_OP_FLUSH:{
++ struct ip_set_req_std *req_flush =
++ (struct ip_set_req_std *) data;
++
++ if (len != sizeof(struct ip_set_req_std)) {
++ ip_set_printk("invalid FLUSH data (want %zu, got %u)",
++ sizeof(struct ip_set_req_std), len);
++ res = -EINVAL;
++ goto done;
++ }
++ if (strcmp(req_flush->name, IPSET_TOKEN_ALL) == 0) {
++ /* Flush all sets */
++ index = IP_SET_INVALID_ID;
++ } else {
++ req_flush->name[IP_SET_MAXNAMELEN - 1] = '\0';
++ index = ip_set_find_byname(req_flush->name);
++
++ if (index == IP_SET_INVALID_ID) {
++ res = -ENOENT;
++ goto done;
++ }
++ }
++ res = ip_set_flush(index);
++ goto done;
++ }
++ case IP_SET_OP_RENAME:{
++ struct ip_set_req_create *req_rename
++ = (struct ip_set_req_create *) data;
++
++ if (len != sizeof(struct ip_set_req_create)) {
++ ip_set_printk("invalid RENAME data (want %zu, got %u)",
++ sizeof(struct ip_set_req_create), len);
++ res = -EINVAL;
++ goto done;
++ }
++
++ req_rename->name[IP_SET_MAXNAMELEN - 1] = '\0';
++ req_rename->typename[IP_SET_MAXNAMELEN - 1] = '\0';
++
++ index = ip_set_find_byname(req_rename->name);
++ if (index == IP_SET_INVALID_ID) {
++ res = -ENOENT;
++ goto done;
++ }
++ res = ip_set_rename(index, req_rename->typename);
++ goto done;
++ }
++ case IP_SET_OP_SWAP:{
++ struct ip_set_req_create *req_swap
++ = (struct ip_set_req_create *) data;
++ ip_set_id_t to_index;
++
++ if (len != sizeof(struct ip_set_req_create)) {
++ ip_set_printk("invalid SWAP data (want %zu, got %u)",
++ sizeof(struct ip_set_req_create), len);
++ res = -EINVAL;
++ goto done;
++ }
++
++ req_swap->name[IP_SET_MAXNAMELEN - 1] = '\0';
++ req_swap->typename[IP_SET_MAXNAMELEN - 1] = '\0';
++
++ index = ip_set_find_byname(req_swap->name);
++ if (index == IP_SET_INVALID_ID) {
++ res = -ENOENT;
++ goto done;
++ }
++ to_index = ip_set_find_byname(req_swap->typename);
++ if (to_index == IP_SET_INVALID_ID) {
++ res = -ENOENT;
++ goto done;
++ }
++ res = ip_set_swap(index, to_index);
++ goto done;
++ }
++ default:
++ break; /* Set identified by id */
++ }
++
++ /* There we may have add/del/test/bind/unbind/test_bind operations */
++ if (*op < IP_SET_OP_ADD_IP || *op > IP_SET_OP_TEST_BIND_SET) {
++ res = -EBADMSG;
++ goto done;
++ }
++ adtfn = adtfn_table[*op - IP_SET_OP_ADD_IP].fn;
++
++ if (len < sizeof(struct ip_set_req_adt)) {
++ ip_set_printk("short data in adt request (want >=%zu, got %u)",
++ sizeof(struct ip_set_req_adt), len);
++ res = -EINVAL;
++ goto done;
++ }
++ req_adt = (struct ip_set_req_adt *) data;
++
++ /* -U :all: :all:|:default: uses IP_SET_INVALID_ID */
++ if (!(*op == IP_SET_OP_UNBIND_SET
++ && req_adt->index == IP_SET_INVALID_ID)) {
++ index = ip_set_find_byindex(req_adt->index);
++ if (index == IP_SET_INVALID_ID) {
++ res = -ENOENT;
++ goto done;
++ }
++ }
++ res = adtfn(index, data, len);
++
++ done:
++ up(&ip_set_app_mutex);
++ vfree(data);
++ if (res > 0)
++ res = 0;
++ DP("final result %d", res);
++ return res;
++}
++
++static int
++ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len)
++{
++ int res = 0;
++ unsigned *op;
++ ip_set_id_t index = IP_SET_INVALID_ID;
++ void *data;
++ int copylen = *len;
++
++ DP("optval=%d, user=%p, len=%d", optval, user, *len);
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++ if (optval != SO_IP_SET)
++ return -EBADF;
++ if (*len < sizeof(unsigned)) {
++ ip_set_printk("short userdata (want >=%zu, got %d)",
++ sizeof(unsigned), *len);
++ return -EINVAL;
++ }
++ data = vmalloc(*len);
++ if (!data) {
++ DP("out of mem for %d bytes", *len);
++ return -ENOMEM;
++ }
++ if (copy_from_user(data, user, *len) != 0) {
++ res = -EFAULT;
++ goto done;
++ }
++ if (down_interruptible(&ip_set_app_mutex)) {
++ res = -EINTR;
++ goto done;
++ }
++
++ op = (unsigned *) data;
++ DP("op=%x", *op);
++
++ if (*op < IP_SET_OP_VERSION) {
++ /* Check the version at the beginning of operations */
++ struct ip_set_req_version *req_version =
++ (struct ip_set_req_version *) data;
++ if (req_version->version != IP_SET_PROTOCOL_VERSION) {
++ res = -EPROTO;
++ goto done;
++ }
++ }
++
++ switch (*op) {
++ case IP_SET_OP_VERSION: {
++ struct ip_set_req_version *req_version =
++ (struct ip_set_req_version *) data;
++
++ if (*len != sizeof(struct ip_set_req_version)) {
++ ip_set_printk("invalid VERSION (want %zu, got %d)",
++ sizeof(struct ip_set_req_version),
++ *len);
++ res = -EINVAL;
++ goto done;
++ }
++
++ req_version->version = IP_SET_PROTOCOL_VERSION;
++ res = copy_to_user(user, req_version,
++ sizeof(struct ip_set_req_version));
++ goto done;
++ }
++ case IP_SET_OP_GET_BYNAME: {
++ struct ip_set_req_get_set *req_get
++ = (struct ip_set_req_get_set *) data;
++
++ if (*len != sizeof(struct ip_set_req_get_set)) {
++ ip_set_printk("invalid GET_BYNAME (want %zu, got %d)",
++ sizeof(struct ip_set_req_get_set), *len);
++ res = -EINVAL;
++ goto done;
++ }
++ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
++ index = ip_set_find_byname(req_get->set.name);
++ req_get->set.index = index;
++ goto copy;
++ }
++ case IP_SET_OP_GET_BYINDEX: {
++ struct ip_set_req_get_set *req_get
++ = (struct ip_set_req_get_set *) data;
++
++ if (*len != sizeof(struct ip_set_req_get_set)) {
++ ip_set_printk("invalid GET_BYINDEX (want %zu, got %d)",
++ sizeof(struct ip_set_req_get_set), *len);
++ res = -EINVAL;
++ goto done;
++ }
++ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
++ index = ip_set_find_byindex(req_get->set.index);
++ strncpy(req_get->set.name,
++ index == IP_SET_INVALID_ID ? ""
++ : ip_set_list[index]->name, IP_SET_MAXNAMELEN);
++ goto copy;
++ }
++ case IP_SET_OP_ADT_GET: {
++ struct ip_set_req_adt_get *req_get
++ = (struct ip_set_req_adt_get *) data;
++
++ if (*len != sizeof(struct ip_set_req_adt_get)) {
++ ip_set_printk("invalid ADT_GET (want %zu, got %d)",
++ sizeof(struct ip_set_req_adt_get), *len);
++ res = -EINVAL;
++ goto done;
++ }
++ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
++ index = ip_set_find_byname(req_get->set.name);
++ if (index != IP_SET_INVALID_ID) {
++ req_get->set.index = index;
++ strncpy(req_get->typename,
++ ip_set_list[index]->type->typename,
++ IP_SET_MAXNAMELEN - 1);
++ } else {
++ res = -ENOENT;
++ goto done;
++ }
++ goto copy;
++ }
++ case IP_SET_OP_MAX_SETS: {
++ struct ip_set_req_max_sets *req_max_sets
++ = (struct ip_set_req_max_sets *) data;
++ ip_set_id_t i;
++
++ if (*len != sizeof(struct ip_set_req_max_sets)) {
++ ip_set_printk("invalid MAX_SETS (want %zu, got %d)",
++ sizeof(struct ip_set_req_max_sets), *len);
++ res = -EINVAL;
++ goto done;
++ }
++
++ if (strcmp(req_max_sets->set.name, IPSET_TOKEN_ALL) == 0) {
++ req_max_sets->set.index = IP_SET_INVALID_ID;
++ } else {
++ req_max_sets->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
++ req_max_sets->set.index =
++ ip_set_find_byname(req_max_sets->set.name);
++ if (req_max_sets->set.index == IP_SET_INVALID_ID) {
++ res = -ENOENT;
++ goto done;
++ }
++ }
++ req_max_sets->max_sets = ip_set_max;
++ req_max_sets->sets = 0;
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] != NULL)
++ req_max_sets->sets++;
++ }
++ goto copy;
++ }
++ case IP_SET_OP_LIST_SIZE:
++ case IP_SET_OP_SAVE_SIZE: {
++ struct ip_set_req_setnames *req_setnames
++ = (struct ip_set_req_setnames *) data;
++ struct ip_set_name_list *name_list;
++ struct ip_set *set;
++ ip_set_id_t i;
++ int used;
++
++ if (*len < sizeof(struct ip_set_req_setnames)) {
++ ip_set_printk("short LIST_SIZE (want >=%zu, got %d)",
++ sizeof(struct ip_set_req_setnames), *len);
++ res = -EINVAL;
++ goto done;
++ }
++
++ req_setnames->size = 0;
++ used = sizeof(struct ip_set_req_setnames);
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] == NULL)
++ continue;
++ name_list = (struct ip_set_name_list *)
++ (data + used);
++ used += sizeof(struct ip_set_name_list);
++ if (used > copylen) {
++ res = -EAGAIN;
++ goto done;
++ }
++ set = ip_set_list[i];
++ /* Fill in index, name, etc. */
++ name_list->index = i;
++ name_list->id = set->id;
++ strncpy(name_list->name,
++ set->name,
++ IP_SET_MAXNAMELEN - 1);
++ strncpy(name_list->typename,
++ set->type->typename,
++ IP_SET_MAXNAMELEN - 1);
++ DP("filled %s of type %s, index %u\n",
++ name_list->name, name_list->typename,
++ name_list->index);
++ if (!(req_setnames->index == IP_SET_INVALID_ID
++ || req_setnames->index == i))
++ continue;
++ /* Update size */
++ switch (*op) {
++ case IP_SET_OP_LIST_SIZE: {
++ req_setnames->size += sizeof(struct ip_set_list)
++ + set->type->header_size
++ + set->type->list_members_size(set);
++ FOREACH_HASH_DO(__set_hash_bindings_size_list,
++ i, &req_setnames->size);
++ break;
++ }
++ case IP_SET_OP_SAVE_SIZE: {
++ req_setnames->size += sizeof(struct ip_set_save)
++ + set->type->header_size
++ + set->type->list_members_size(set);
++ FOREACH_HASH_DO(__set_hash_bindings_size_save,
++ i, &req_setnames->size);
++ break;
++ }
++ default:
++ break;
++ }
++ }
++ if (copylen != used) {
++ res = -EAGAIN;
++ goto done;
++ }
++ goto copy;
++ }
++ case IP_SET_OP_LIST: {
++ struct ip_set_req_list *req_list
++ = (struct ip_set_req_list *) data;
++ ip_set_id_t i;
++ int used;
++
++ if (*len < sizeof(struct ip_set_req_list)) {
++ ip_set_printk("short LIST (want >=%zu, got %d)",
++ sizeof(struct ip_set_req_list), *len);
++ res = -EINVAL;
++ goto done;
++ }
++ index = req_list->index;
++ if (index != IP_SET_INVALID_ID
++ && ip_set_find_byindex(index) != index) {
++ res = -ENOENT;
++ goto done;
++ }
++ used = 0;
++ if (index == IP_SET_INVALID_ID) {
++ /* List all sets */
++ for (i = 0; i < ip_set_max && res == 0; i++) {
++ if (ip_set_list[i] != NULL)
++ res = ip_set_list_set(i, data, &used, *len);
++ }
++ } else {
++ /* List an individual set */
++ res = ip_set_list_set(index, data, &used, *len);
++ }
++ if (res != 0)
++ goto done;
++ else if (copylen != used) {
++ res = -EAGAIN;
++ goto done;
++ }
++ goto copy;
++ }
++ case IP_SET_OP_SAVE: {
++ struct ip_set_req_list *req_save
++ = (struct ip_set_req_list *) data;
++ ip_set_id_t i;
++ int used;
++
++ if (*len < sizeof(struct ip_set_req_list)) {
++ ip_set_printk("short SAVE (want >=%zu, got %d)",
++ sizeof(struct ip_set_req_list), *len);
++ res = -EINVAL;
++ goto done;
++ }
++ index = req_save->index;
++ if (index != IP_SET_INVALID_ID
++ && ip_set_find_byindex(index) != index) {
++ res = -ENOENT;
++ goto done;
++ }
++ used = 0;
++ if (index == IP_SET_INVALID_ID) {
++ /* Save all sets */
++ for (i = 0; i < ip_set_max && res == 0; i++) {
++ if (ip_set_list[i] != NULL)
++ res = ip_set_save_set(i, data, &used, *len);
++ }
++ } else {
++ /* Save an individual set */
++ res = ip_set_save_set(index, data, &used, *len);
++ }
++ if (res == 0)
++ res = ip_set_save_bindings(index, data, &used, *len);
++
++ if (res != 0)
++ goto done;
++ else if (copylen != used) {
++ res = -EAGAIN;
++ goto done;
++ }
++ goto copy;
++ }
++ case IP_SET_OP_RESTORE: {
++ struct ip_set_req_setnames *req_restore
++ = (struct ip_set_req_setnames *) data;
++ int line;
++
++ if (*len < sizeof(struct ip_set_req_setnames)
++ || *len != req_restore->size) {
++ ip_set_printk("invalid RESTORE (want =%zu, got %d)",
++ req_restore->size, *len);
++ res = -EINVAL;
++ goto done;
++ }
++ line = ip_set_restore(data + sizeof(struct ip_set_req_setnames),
++ req_restore->size - sizeof(struct ip_set_req_setnames));
++ DP("ip_set_restore: %u", line);
++ if (line != 0) {
++ res = -EAGAIN;
++ req_restore->size = line;
++ copylen = sizeof(struct ip_set_req_setnames);
++ goto copy;
++ }
++ goto done;
++ }
++ default:
++ res = -EBADMSG;
++ goto done;
++ } /* end of switch(op) */
++
++ copy:
++ DP("set %s, copylen %u", index != IP_SET_INVALID_ID
++ && ip_set_list[index]
++ ? ip_set_list[index]->name
++ : ":all:", copylen);
++ if (res == 0)
++ res = copy_to_user(user, data, copylen);
++ else
++ copy_to_user(user, data, copylen);
++
++ done:
++ up(&ip_set_app_mutex);
++ vfree(data);
++ if (res > 0)
++ res = 0;
++ DP("final result %d", res);
++ return res;
++}
++
++static struct nf_sockopt_ops so_set = {
++ .pf = PF_INET,
++ .set_optmin = SO_IP_SET,
++ .set_optmax = SO_IP_SET + 1,
++ .set = &ip_set_sockfn_set,
++ .get_optmin = SO_IP_SET,
++ .get_optmax = SO_IP_SET + 1,
++ .get = &ip_set_sockfn_get,
++ .use = 0
++};
++
++static int max_sets, hash_size;
++MODULE_PARM(max_sets, "i");
++MODULE_PARM_DESC(max_sets, "maximal number of sets");
++MODULE_PARM(hash_size, "i");
++MODULE_PARM_DESC(hash_size, "hash size for bindings");
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("module implementing core IP set support");
++
++static int __init init(void)
++{
++ int res;
++ ip_set_id_t i;
++
++ get_random_bytes(&ip_set_hash_random, 4);
++ if (max_sets)
++ ip_set_max = max_sets;
++ ip_set_list = vmalloc(sizeof(struct ip_set *) * ip_set_max);
++ if (!ip_set_list) {
++ printk(KERN_ERR "Unable to create ip_set_list\n");
++ return -ENOMEM;
++ }
++ memset(ip_set_list, 0, sizeof(struct ip_set *) * ip_set_max);
++ if (hash_size)
++ ip_set_bindings_hash_size = hash_size;
++ ip_set_hash = vmalloc(sizeof(struct list_head) * ip_set_bindings_hash_size);
++ if (!ip_set_hash) {
++ printk(KERN_ERR "Unable to create ip_set_hash\n");
++ vfree(ip_set_list);
++ return -ENOMEM;
++ }
++ for (i = 0; i < ip_set_bindings_hash_size; i++)
++ INIT_LIST_HEAD(&ip_set_hash[i]);
++
++ INIT_LIST_HEAD(&set_type_list);
++
++ res = nf_register_sockopt(&so_set);
++ if (res != 0) {
++ ip_set_printk("SO_SET registry failed: %d", res);
++ vfree(ip_set_list);
++ vfree(ip_set_hash);
++ return res;
++ }
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ /* There can't be any existing set or binding. Racy. */
++ nf_unregister_sockopt(&so_set);
++ vfree(ip_set_list);
++ vfree(ip_set_hash);
++ DP("these are the famous last words");
++}
++
++EXPORT_SYMBOL(ip_set_register_set_type);
++EXPORT_SYMBOL(ip_set_unregister_set_type);
++
++EXPORT_SYMBOL(ip_set_get_byname);
++EXPORT_SYMBOL(ip_set_get_byindex);
++EXPORT_SYMBOL(ip_set_put);
++
++EXPORT_SYMBOL(ip_set_addip_kernel);
++EXPORT_SYMBOL(ip_set_delip_kernel);
++EXPORT_SYMBOL(ip_set_testip_kernel);
++
++module_init(init);
++module_exit(fini);
+diff -Naur linux-old/net/ipv4/netfilter/ip_set_iphash.c linux-new/net/ipv4/netfilter/ip_set_iphash.c
+--- linux-old/net/ipv4/netfilter/ip_set_iphash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/net/ipv4/netfilter/ip_set_iphash.c 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,379 @@
++/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module implementing an ip hash set */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <asm/softirq.h>
++#include <linux/spinlock.h>
++#include <linux/vmalloc.h>
++#include <linux/random.h>
++
++#include <net/ip.h>
++
++#include <linux/netfilter_ipv4/ip_set_malloc.h>
++#include <linux/netfilter_ipv4/ip_set_iphash.h>
++#include <linux/netfilter_ipv4/ip_set_jhash.h>
++#include <linux/netfilter_ipv4/ip_set_prime.h>
++
++static inline __u32
++jhash_ip(const struct ip_set_iphash *map, ip_set_ip_t ip)
++{
++ return jhash_1word(ip, map->initval);
++}
++
++static inline __u32
++randhash_ip(const struct ip_set_iphash *map, ip_set_ip_t ip)
++{
++ return (1 + ip % map->prime);
++}
++
++static inline __u32
++hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++ __u32 jhash, randhash, id;
++ u_int16_t i;
++
++ *hash_ip = ip & map->netmask;
++ jhash = jhash_ip(map, *hash_ip);
++ randhash = randhash_ip(map, *hash_ip);
++ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u, %u.%u.%u.%u",
++ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip), HIPQUAD(map->netmask));
++
++ for (i = 0; i < map->probes; i++) {
++ id = (jhash + i * randhash) % map->hashsize;
++ DP("hash key: %u", id);
++ if (map->members[id] == *hash_ip)
++ return id;
++ /* No shortcut at testing - there can be deleted
++ * entries. */
++ }
++ return UINT_MAX;
++}
++
++static inline int
++__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ return (hash_id(set, ip, hash_ip) != UINT_MAX);
++}
++
++static int
++testip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_iphash *req =
++ (struct ip_set_req_iphash *) data;
++
++ if (size != sizeof(struct ip_set_req_iphash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iphash),
++ size);
++ return -EINVAL;
++ }
++ return __testip(set, req->ip, hash_ip);
++}
++
++static int
++testip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __testip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++static inline int
++__addip(struct ip_set_iphash *map, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ __u32 jhash, randhash, probe;
++ u_int16_t i;
++
++ *hash_ip = ip & map->netmask;
++ jhash = jhash_ip(map, *hash_ip);
++ randhash = randhash_ip(map, *hash_ip);
++
++ for (i = 0; i < map->probes; i++) {
++ probe = (jhash + i * randhash) % map->hashsize;
++ if (map->members[probe] == *hash_ip)
++ return -EEXIST;
++ if (!map->members[probe]) {
++ map->members[probe] = *hash_ip;
++ return 0;
++ }
++ }
++ /* Trigger rehashing */
++ return -EAGAIN;
++}
++
++static int
++addip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_iphash *req =
++ (struct ip_set_req_iphash *) data;
++
++ if (size != sizeof(struct ip_set_req_iphash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iphash),
++ size);
++ return -EINVAL;
++ }
++ return __addip((struct ip_set_iphash *) set->data, req->ip, hash_ip);
++}
++
++static int
++addip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __addip((struct ip_set_iphash *) set->data,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++static int retry(struct ip_set *set)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++ ip_set_ip_t hash_ip, *members;
++ u_int32_t i, hashsize;
++ unsigned newbytes;
++ int res;
++ struct ip_set_iphash tmp = {
++ .hashsize = map->hashsize,
++ .probes = map->probes,
++ .resize = map->resize,
++ .netmask = map->netmask,
++ };
++
++ if (map->resize == 0)
++ return -ERANGE;
++
++ again:
++ res = 0;
++
++ /* Calculate new parameters */
++ get_random_bytes(&tmp.initval, 4);
++ hashsize = tmp.hashsize + (tmp.hashsize * map->resize)/100;
++ if (hashsize == tmp.hashsize)
++ hashsize++;
++ tmp.prime = make_prime(hashsize);
++
++ ip_set_printk("rehashing of set %s triggered: "
++ "hashsize grows from %u to %u",
++ set->name, tmp.hashsize, hashsize);
++ tmp.hashsize = hashsize;
++
++ newbytes = hashsize * sizeof(ip_set_ip_t);
++ tmp.members = ip_set_malloc(newbytes);
++ if (!tmp.members) {
++ DP("out of memory for %d bytes", newbytes);
++ return -ENOMEM;
++ }
++ memset(tmp.members, 0, newbytes);
++
++ write_lock_bh(&set->lock);
++ map = (struct ip_set_iphash *) set->data; /* Play safe */
++ for (i = 0; i < map->hashsize && res == 0; i++) {
++ if (map->members[i])
++ res = __addip(&tmp, map->members[i], &hash_ip);
++ }
++ if (res) {
++ /* Failure, try again */
++ write_unlock_bh(&set->lock);
++ ip_set_free(tmp.members, newbytes);
++ goto again;
++ }
++
++ /* Success at resizing! */
++ members = map->members;
++ hashsize = map->hashsize;
++
++ map->initval = tmp.initval;
++ map->prime = tmp.prime;
++ map->hashsize = tmp.hashsize;
++ map->members = tmp.members;
++ write_unlock_bh(&set->lock);
++
++ ip_set_free(members, hashsize * sizeof(ip_set_ip_t));
++
++ return 0;
++}
++
++static inline int
++__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++ ip_set_ip_t id = hash_id(set, ip, hash_ip);
++
++ if (id == UINT_MAX)
++ return -EEXIST;
++
++ map->members[id] = 0;
++ return 0;
++}
++
++static int
++delip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_iphash *req =
++ (struct ip_set_req_iphash *) data;
++
++ if (size != sizeof(struct ip_set_req_iphash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iphash),
++ size);
++ return -EINVAL;
++ }
++ return __delip(set, req->ip, hash_ip);
++}
++
++static int
++delip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __delip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++static int create(struct ip_set *set, const void *data, size_t size)
++{
++ unsigned newbytes;
++ struct ip_set_req_iphash_create *req =
++ (struct ip_set_req_iphash_create *) data;
++ struct ip_set_iphash *map;
++
++ if (size != sizeof(struct ip_set_req_iphash_create)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iphash_create),
++ size);
++ return -EINVAL;
++ }
++
++ if (req->hashsize < 1) {
++ ip_set_printk("hashsize too small");
++ return -ENOEXEC;
++ }
++
++ map = kmalloc(sizeof(struct ip_set_iphash), GFP_KERNEL);
++ if (!map) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_iphash));
++ return -ENOMEM;
++ }
++ get_random_bytes(&map->initval, 4);
++ map->prime = make_prime(req->hashsize);
++ map->hashsize = req->hashsize;
++ map->probes = req->probes;
++ map->resize = req->resize;
++ map->netmask = req->netmask;
++ newbytes = map->hashsize * sizeof(ip_set_ip_t);
++ map->members = ip_set_malloc(newbytes);
++ if (!map->members) {
++ DP("out of memory for %d bytes", newbytes);
++ kfree(map);
++ return -ENOMEM;
++ }
++ memset(map->members, 0, newbytes);
++
++ set->data = map;
++ return 0;
++}
++
++static void destroy(struct ip_set *set)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++
++ ip_set_free(map->members, map->hashsize * sizeof(ip_set_ip_t));
++ kfree(map);
++
++ set->data = NULL;
++}
++
++static void flush(struct ip_set *set)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++ memset(map->members, 0, map->hashsize * sizeof(ip_set_ip_t));
++}
++
++static void list_header(const struct ip_set *set, void *data)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++ struct ip_set_req_iphash_create *header =
++ (struct ip_set_req_iphash_create *) data;
++
++ header->hashsize = map->hashsize;
++ header->probes = map->probes;
++ header->resize = map->resize;
++ header->netmask = map->netmask;
++}
++
++static int list_members_size(const struct ip_set *set)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++
++ return (map->hashsize * sizeof(ip_set_ip_t));
++}
++
++static void list_members(const struct ip_set *set, void *data)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++ int bytes = map->hashsize * sizeof(ip_set_ip_t);
++
++ memcpy(data, map->members, bytes);
++}
++
++static struct ip_set_type ip_set_iphash = {
++ .typename = SETTYPE_NAME,
++ .typecode = IPSET_TYPE_IP,
++ .protocol_version = IP_SET_PROTOCOL_VERSION,
++ .create = &create,
++ .destroy = &destroy,
++ .flush = &flush,
++ .reqsize = sizeof(struct ip_set_req_iphash),
++ .addip = &addip,
++ .addip_kernel = &addip_kernel,
++ .retry = &retry,
++ .delip = &delip,
++ .delip_kernel = &delip_kernel,
++ .testip = &testip,
++ .testip_kernel = &testip_kernel,
++ .header_size = sizeof(struct ip_set_req_iphash_create),
++ .list_header = &list_header,
++ .list_members_size = &list_members_size,
++ .list_members = &list_members,
++ .me = THIS_MODULE,
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("iphash type of IP sets");
++
++static int __init init(void)
++{
++ return ip_set_register_set_type(&ip_set_iphash);
++}
++
++static void __exit fini(void)
++{
++ /* FIXME: possible race with ip_set_create() */
++ ip_set_unregister_set_type(&ip_set_iphash);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Naur linux-old/net/ipv4/netfilter/ip_set_ipmap.c linux-new/net/ipv4/netfilter/ip_set_ipmap.c
+--- linux-old/net/ipv4/netfilter/ip_set_ipmap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/net/ipv4/netfilter/ip_set_ipmap.c 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,314 @@
++/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
++ * Patrick Schaaf <bof@bof.de>
++ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module implementing an IP set type: the single bitmap type */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <asm/softirq.h>
++#include <linux/spinlock.h>
++
++#include <linux/netfilter_ipv4/ip_set_ipmap.h>
++
++static inline ip_set_ip_t
++ip_to_id(const struct ip_set_ipmap *map, ip_set_ip_t ip)
++{
++ return (ip - map->first_ip)/map->hosts;
++}
++
++static inline int
++__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++
++ if (ip < map->first_ip || ip > map->last_ip)
++ return -ERANGE;
++
++ *hash_ip = ip & map->netmask;
++ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
++ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
++ return !!test_bit(ip_to_id(map, *hash_ip), map->members);
++}
++
++static int
++testip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_ipmap *req =
++ (struct ip_set_req_ipmap *) data;
++
++ if (size != sizeof(struct ip_set_req_ipmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_ipmap),
++ size);
++ return -EINVAL;
++ }
++ return __testip(set, req->ip, hash_ip);
++}
++
++static int
++testip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ u_int32_t flags,
++ ip_set_ip_t *hash_ip)
++{
++ int res;
++
++ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
++ flags & IPSET_SRC ? "SRC" : "DST",
++ NIPQUAD(skb->nh.iph->saddr),
++ NIPQUAD(skb->nh.iph->daddr));
++
++ res = __testip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++ return (res < 0 ? 0 : res);
++}
++
++static inline int
++__addip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++
++ if (ip < map->first_ip || ip > map->last_ip)
++ return -ERANGE;
++
++ *hash_ip = ip & map->netmask;
++ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
++ if (test_and_set_bit(ip_to_id(map, *hash_ip), map->members))
++ return -EEXIST;
++
++ return 0;
++}
++
++static int
++addip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_ipmap *req =
++ (struct ip_set_req_ipmap *) data;
++
++ if (size != sizeof(struct ip_set_req_ipmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_ipmap),
++ size);
++ return -EINVAL;
++ }
++ DP("%u.%u.%u.%u", HIPQUAD(req->ip));
++ return __addip(set, req->ip, hash_ip);
++}
++
++static int
++addip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __addip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++static inline int
++__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++
++ if (ip < map->first_ip || ip > map->last_ip)
++ return -ERANGE;
++
++ *hash_ip = ip & map->netmask;
++ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
++ if (!test_and_clear_bit(ip_to_id(map, *hash_ip), map->members))
++ return -EEXIST;
++
++ return 0;
++}
++
++static int
++delip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_ipmap *req =
++ (struct ip_set_req_ipmap *) data;
++
++ if (size != sizeof(struct ip_set_req_ipmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_ipmap),
++ size);
++ return -EINVAL;
++ }
++ return __delip(set, req->ip, hash_ip);
++}
++
++static int
++delip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __delip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++static int create(struct ip_set *set, const void *data, size_t size)
++{
++ int newbytes;
++ struct ip_set_req_ipmap_create *req =
++ (struct ip_set_req_ipmap_create *) data;
++ struct ip_set_ipmap *map;
++
++ if (size != sizeof(struct ip_set_req_ipmap_create)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_ipmap_create),
++ size);
++ return -EINVAL;
++ }
++
++ DP("from %u.%u.%u.%u to %u.%u.%u.%u",
++ HIPQUAD(req->from), HIPQUAD(req->to));
++
++ if (req->from > req->to) {
++ DP("bad ip range");
++ return -ENOEXEC;
++ }
++
++ if (req->to - req->from > MAX_RANGE) {
++ ip_set_printk("range too big (max %d addresses)",
++ MAX_RANGE);
++ return -ENOEXEC;
++ }
++
++ map = kmalloc(sizeof(struct ip_set_ipmap), GFP_KERNEL);
++ if (!map) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_ipmap));
++ return -ENOMEM;
++ }
++ map->first_ip = req->from;
++ map->last_ip = req->to;
++ map->netmask = req->netmask;
++
++ if (req->netmask == 0xFFFFFFFF) {
++ map->hosts = 1;
++ map->sizeid = map->last_ip - map->first_ip + 1;
++ } else {
++ unsigned int mask_bits, netmask_bits;
++ ip_set_ip_t mask;
++
++ map->first_ip &= map->netmask; /* Should we better bark? */
++
++ mask = range_to_mask(map->first_ip, map->last_ip, &mask_bits);
++ netmask_bits = mask_to_bits(map->netmask);
++
++ if (!mask || netmask_bits <= mask_bits)
++ return -ENOEXEC;
++
++ map->hosts = 2 << (32 - netmask_bits - 1);
++ map->sizeid = 2 << (netmask_bits - mask_bits - 1);
++ }
++ newbytes = bitmap_bytes(0, map->sizeid - 1);
++ map->members = kmalloc(newbytes, GFP_KERNEL);
++ if (!map->members) {
++ DP("out of memory for %d bytes", newbytes);
++ kfree(map);
++ return -ENOMEM;
++ }
++ memset(map->members, 0, newbytes);
++
++ set->data = map;
++ return 0;
++}
++
++static void destroy(struct ip_set *set)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++
++ kfree(map->members);
++ kfree(map);
++
++ set->data = NULL;
++}
++
++static void flush(struct ip_set *set)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++ memset(map->members, 0, bitmap_bytes(0, map->sizeid - 1));
++}
++
++static void list_header(const struct ip_set *set, void *data)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++ struct ip_set_req_ipmap_create *header =
++ (struct ip_set_req_ipmap_create *) data;
++
++ header->from = map->first_ip;
++ header->to = map->last_ip;
++ header->netmask = map->netmask;
++}
++
++static int list_members_size(const struct ip_set *set)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++
++ return bitmap_bytes(0, map->sizeid - 1);
++}
++
++static void list_members(const struct ip_set *set, void *data)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++ int bytes = bitmap_bytes(0, map->sizeid - 1);
++
++ memcpy(data, map->members, bytes);
++}
++
++static struct ip_set_type ip_set_ipmap = {
++ .typename = SETTYPE_NAME,
++ .typecode = IPSET_TYPE_IP,
++ .protocol_version = IP_SET_PROTOCOL_VERSION,
++ .create = &create,
++ .destroy = &destroy,
++ .flush = &flush,
++ .reqsize = sizeof(struct ip_set_req_ipmap),
++ .addip = &addip,
++ .addip_kernel = &addip_kernel,
++ .delip = &delip,
++ .delip_kernel = &delip_kernel,
++ .testip = &testip,
++ .testip_kernel = &testip_kernel,
++ .header_size = sizeof(struct ip_set_req_ipmap_create),
++ .list_header = &list_header,
++ .list_members_size = &list_members_size,
++ .list_members = &list_members,
++ .me = THIS_MODULE,
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("ipmap type of IP sets");
++
++static int __init init(void)
++{
++ return ip_set_register_set_type(&ip_set_ipmap);
++}
++
++static void __exit fini(void)
++{
++ /* FIXME: possible race with ip_set_create() */
++ ip_set_unregister_set_type(&ip_set_ipmap);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Naur linux-old/net/ipv4/netfilter/ip_set_iptree.c linux-new/net/ipv4/netfilter/ip_set_iptree.c
+--- linux-old/net/ipv4/netfilter/ip_set_iptree.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/net/ipv4/netfilter/ip_set_iptree.c 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,511 @@
++/* Copyright (C) 2005 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module implementing an IP set type: the iptree type */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++
++#include <linux/netfilter_ipv4/ip_set_iptree.h>
++
++/* Garbage collection interval in seconds: */
++#define IPTREE_GC_TIME 5*60
++/* Sleep so many milliseconds before trying again
++ * to delete the gc timer at destroying a set */
++#define IPTREE_DESTROY_SLEEP 100
++
++static kmem_cache_t *branch_cachep;
++static kmem_cache_t *leaf_cachep;
++
++#define ABCD(a,b,c,d,addrp) do { \
++ a = ((unsigned char *)addrp)[3]; \
++ b = ((unsigned char *)addrp)[2]; \
++ c = ((unsigned char *)addrp)[1]; \
++ d = ((unsigned char *)addrp)[0]; \
++} while (0)
++
++#define TESTIP_WALK(map, elem, branch) do { \
++ if ((map)->tree[elem]) { \
++ branch = (map)->tree[elem]; \
++ } else \
++ return 0; \
++} while (0)
++
++static inline int
++__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_iptreeb *btree;
++ struct ip_set_iptreec *ctree;
++ struct ip_set_iptreed *dtree;
++ unsigned char a,b,c,d;
++
++ *hash_ip = ip;
++ ABCD(a, b, c, d, hash_ip);
++ DP("%u %u %u %u timeout %u", a, b, c, d, map->timeout);
++ TESTIP_WALK(map, a, btree);
++ TESTIP_WALK(btree, b, ctree);
++ TESTIP_WALK(ctree, c, dtree);
++ DP("%lu %lu", dtree->expires[d], jiffies);
++ return !!(map->timeout ? (time_after(dtree->expires[d], jiffies))
++ : dtree->expires[d]);
++}
++
++static int
++testip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_iptree *req =
++ (struct ip_set_req_iptree *) data;
++
++ if (size != sizeof(struct ip_set_req_iptree)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iptree),
++ size);
++ return -EINVAL;
++ }
++ return __testip(set, req->ip, hash_ip);
++}
++
++static int
++testip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ u_int32_t flags,
++ ip_set_ip_t *hash_ip)
++{
++ int res;
++
++ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
++ flags & IPSET_SRC ? "SRC" : "DST",
++ NIPQUAD(skb->nh.iph->saddr),
++ NIPQUAD(skb->nh.iph->daddr));
++
++ res = __testip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++ return (res < 0 ? 0 : res);
++}
++
++#define ADDIP_WALK(map, elem, branch, type, cachep) do { \
++ if ((map)->tree[elem]) { \
++ DP("found %u", elem); \
++ branch = (map)->tree[elem]; \
++ } else { \
++ branch = (type *) \
++ kmem_cache_alloc(cachep, GFP_KERNEL); \
++ if (branch == NULL) \
++ return -ENOMEM; \
++ memset(branch, 0, sizeof(*branch)); \
++ (map)->tree[elem] = branch; \
++ DP("alloc %u", elem); \
++ } \
++} while (0)
++
++static inline int
++__addip(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_iptreeb *btree;
++ struct ip_set_iptreec *ctree;
++ struct ip_set_iptreed *dtree;
++ unsigned char a,b,c,d;
++ int ret = 0;
++
++ *hash_ip = ip;
++ ABCD(a, b, c, d, hash_ip);
++ DP("%u %u %u %u timeout %u", a, b, c, d, timeout);
++ ADDIP_WALK(map, a, btree, struct ip_set_iptreeb, branch_cachep);
++ ADDIP_WALK(btree, b, ctree, struct ip_set_iptreec, branch_cachep);
++ ADDIP_WALK(ctree, c, dtree, struct ip_set_iptreed, leaf_cachep);
++ if (dtree->expires[d]
++ && (!map->timeout || time_after(dtree->expires[d], jiffies)))
++ ret = -EEXIST;
++ dtree->expires[d] = map->timeout ? (timeout * HZ + jiffies) : 1;
++ DP("%u %lu", d, dtree->expires[d]);
++ return ret;
++}
++
++static int
++addip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_req_iptree *req =
++ (struct ip_set_req_iptree *) data;
++
++ if (size != sizeof(struct ip_set_req_iptree)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iptree),
++ size);
++ return -EINVAL;
++ }
++ DP("%u.%u.%u.%u %u", HIPQUAD(req->ip), req->timeout);
++ return __addip(set, req->ip,
++ req->timeout ? req->timeout : map->timeout,
++ hash_ip);
++}
++
++static int
++addip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++
++ return __addip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ map->timeout,
++ hash_ip);
++}
++
++#define DELIP_WALK(map, elem, branch) do { \
++ if ((map)->tree[elem]) { \
++ branch = (map)->tree[elem]; \
++ } else \
++ return -EEXIST; \
++} while (0)
++
++static inline int
++__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_iptreeb *btree;
++ struct ip_set_iptreec *ctree;
++ struct ip_set_iptreed *dtree;
++ unsigned char a,b,c,d;
++
++ *hash_ip = ip;
++ ABCD(a, b, c, d, hash_ip);
++ DELIP_WALK(map, a, btree);
++ DELIP_WALK(btree, b, ctree);
++ DELIP_WALK(ctree, c, dtree);
++
++ if (dtree->expires[d]) {
++ dtree->expires[d] = 0;
++ return 0;
++ }
++ return -EEXIST;
++}
++
++static int
++delip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_iptree *req =
++ (struct ip_set_req_iptree *) data;
++
++ if (size != sizeof(struct ip_set_req_iptree)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iptree),
++ size);
++ return -EINVAL;
++ }
++ return __delip(set, req->ip, hash_ip);
++}
++
++static int
++delip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __delip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++#define LOOP_WALK_BEGIN(map, i, branch) \
++ for (i = 0; i < 255; i++) { \
++ if (!(map)->tree[i]) \
++ continue; \
++ branch = (map)->tree[i]
++
++#define LOOP_WALK_END }
++
++static void ip_tree_gc(unsigned long ul_set)
++{
++ struct ip_set *set = (void *) ul_set;
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_iptreeb *btree;
++ struct ip_set_iptreec *ctree;
++ struct ip_set_iptreed *dtree;
++ unsigned char a,b,c,d;
++ unsigned char i,j,k;
++
++ i = j = k = 0;
++ DP("gc: %s", set->name);
++ write_lock_bh(&set->lock);
++ LOOP_WALK_BEGIN(map, a, btree);
++ LOOP_WALK_BEGIN(btree, b, ctree);
++ LOOP_WALK_BEGIN(ctree, c, dtree);
++ for (d = 0; d < 255; d++) {
++ if (dtree->expires[d]) {
++ DP("gc: %u %u %u %u: expires %lu jiffies %lu",
++ a, b, c, d,
++ dtree->expires[d], jiffies);
++ if (map->timeout
++ && time_before(dtree->expires[d], jiffies))
++ dtree->expires[d] = 0;
++ else
++ k = 1;
++ }
++ }
++ if (k == 0) {
++ DP("gc: %s: leaf %u %u %u empty",
++ set->name, a, b, c);
++ kmem_cache_free(leaf_cachep, dtree);
++ ctree->tree[c] = NULL;
++ } else {
++ DP("gc: %s: leaf %u %u %u not empty",
++ set->name, a, b, c);
++ j = 1;
++ k = 0;
++ }
++ LOOP_WALK_END;
++ if (j == 0) {
++ DP("gc: %s: branch %u %u empty",
++ set->name, a, b);
++ kmem_cache_free(branch_cachep, ctree);
++ btree->tree[b] = NULL;
++ } else {
++ DP("gc: %s: branch %u %u not empty",
++ set->name, a, b);
++ i = 1;
++ j = k = 0;
++ }
++ LOOP_WALK_END;
++ if (i == 0) {
++ DP("gc: %s: branch %u empty",
++ set->name, a);
++ kmem_cache_free(branch_cachep, btree);
++ map->tree[a] = NULL;
++ } else {
++ DP("gc: %s: branch %u not empty",
++ set->name, a);
++ i = j = k = 0;
++ }
++ LOOP_WALK_END;
++ write_unlock_bh(&set->lock);
++
++ map->gc.expires = jiffies + map->gc_interval * HZ;
++ add_timer(&map->gc);
++}
++
++static int create(struct ip_set *set, const void *data, size_t size)
++{
++ struct ip_set_req_iptree_create *req =
++ (struct ip_set_req_iptree_create *) data;
++ struct ip_set_iptree *map;
++
++ if (size != sizeof(struct ip_set_req_iptree_create)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iptree_create),
++ size);
++ return -EINVAL;
++ }
++
++ map = kmalloc(sizeof(struct ip_set_iptree), GFP_KERNEL);
++ if (!map) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_iptree));
++ return -ENOMEM;
++ }
++ memset(map, 0, sizeof(*map));
++ map->timeout = req->timeout;
++ set->data = map;
++
++ /* If there is no timeout for the entries,
++ * we still have to call gc because delete
++ * do not clean up empty branches */
++ map->gc_interval = IPTREE_GC_TIME;
++ init_timer(&map->gc);
++ map->gc.data = (unsigned long) set;
++ map->gc.function = ip_tree_gc;
++ map->gc.expires = jiffies + map->gc_interval * HZ;
++ add_timer(&map->gc);
++
++ return 0;
++}
++
++static void __flush(struct ip_set_iptree *map)
++{
++ struct ip_set_iptreeb *btree;
++ struct ip_set_iptreec *ctree;
++ struct ip_set_iptreed *dtree;
++ unsigned int a,b,c;
++
++ LOOP_WALK_BEGIN(map, a, btree);
++ LOOP_WALK_BEGIN(btree, b, ctree);
++ LOOP_WALK_BEGIN(ctree, c, dtree);
++ kmem_cache_free(leaf_cachep, dtree);
++ LOOP_WALK_END;
++ kmem_cache_free(branch_cachep, ctree);
++ LOOP_WALK_END;
++ kmem_cache_free(branch_cachep, btree);
++ LOOP_WALK_END;
++}
++
++static void destroy(struct ip_set *set)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++
++ while (!del_timer(&map->gc))
++ msleep(IPTREE_DESTROY_SLEEP);
++ __flush(map);
++ kfree(map);
++ set->data = NULL;
++}
++
++static void flush(struct ip_set *set)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ unsigned int timeout = map->timeout;
++
++ __flush(map);
++ memset(map, 0, sizeof(*map));
++ map->timeout = timeout;
++}
++
++static void list_header(const struct ip_set *set, void *data)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_req_iptree_create *header =
++ (struct ip_set_req_iptree_create *) data;
++
++ header->timeout = map->timeout;
++}
++
++static int list_members_size(const struct ip_set *set)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_iptreeb *btree;
++ struct ip_set_iptreec *ctree;
++ struct ip_set_iptreed *dtree;
++ unsigned char a,b,c,d;
++ unsigned int count = 0;
++
++ LOOP_WALK_BEGIN(map, a, btree);
++ LOOP_WALK_BEGIN(btree, b, ctree);
++ LOOP_WALK_BEGIN(ctree, c, dtree);
++ for (d = 0; d < 255; d++) {
++ if (dtree->expires[d]
++ && (!map->timeout || time_after(dtree->expires[d], jiffies)))
++ count++;
++ }
++ LOOP_WALK_END;
++ LOOP_WALK_END;
++ LOOP_WALK_END;
++
++ DP("members %u", count);
++ return (count * sizeof(struct ip_set_req_iptree));
++}
++
++static void list_members(const struct ip_set *set, void *data)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_iptreeb *btree;
++ struct ip_set_iptreec *ctree;
++ struct ip_set_iptreed *dtree;
++ unsigned char a,b,c,d;
++ size_t offset = 0;
++ struct ip_set_req_iptree *entry;
++
++ LOOP_WALK_BEGIN(map, a, btree);
++ LOOP_WALK_BEGIN(btree, b, ctree);
++ LOOP_WALK_BEGIN(ctree, c, dtree);
++ for (d = 0; d < 255; d++) {
++ if (dtree->expires[d]
++ && (!map->timeout || time_after(dtree->expires[d], jiffies))) {
++ entry = (struct ip_set_req_iptree *)(data + offset);
++ entry->ip = ((a << 24) | (b << 16) | (c << 8) | d);
++ entry->timeout = !map->timeout ? 0
++ : (dtree->expires[d] - jiffies)/HZ;
++ offset += sizeof(struct ip_set_req_iptree);
++ }
++ }
++ LOOP_WALK_END;
++ LOOP_WALK_END;
++ LOOP_WALK_END;
++}
++
++static struct ip_set_type ip_set_iptree = {
++ .typename = SETTYPE_NAME,
++ .typecode = IPSET_TYPE_IP,
++ .protocol_version = IP_SET_PROTOCOL_VERSION,
++ .create = &create,
++ .destroy = &destroy,
++ .flush = &flush,
++ .reqsize = sizeof(struct ip_set_req_iptree),
++ .addip = &addip,
++ .addip_kernel = &addip_kernel,
++ .delip = &delip,
++ .delip_kernel = &delip_kernel,
++ .testip = &testip,
++ .testip_kernel = &testip_kernel,
++ .header_size = sizeof(struct ip_set_req_iptree_create),
++ .list_header = &list_header,
++ .list_members_size = &list_members_size,
++ .list_members = &list_members,
++ .me = THIS_MODULE,
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("iptree type of IP sets");
++
++static int __init init(void)
++{
++ int ret;
++
++ branch_cachep = kmem_cache_create("ip_set_iptreeb",
++ sizeof(struct ip_set_iptreeb),
++ 0, 0, NULL, NULL);
++ if (!branch_cachep) {
++ printk(KERN_ERR "Unable to create ip_set_iptreeb slab cache\n");
++ ret = -ENOMEM;
++ goto out;
++ }
++ leaf_cachep = kmem_cache_create("ip_set_iptreed",
++ sizeof(struct ip_set_iptreed),
++ 0, 0, NULL, NULL);
++ if (!leaf_cachep) {
++ printk(KERN_ERR "Unable to create ip_set_iptreed slab cache\n");
++ ret = -ENOMEM;
++ goto free_branch;
++ }
++ ret = ip_set_register_set_type(&ip_set_iptree);
++ if (ret == 0)
++ goto out;
++
++ kmem_cache_destroy(leaf_cachep);
++ free_branch:
++ kmem_cache_destroy(branch_cachep);
++ out:
++ return ret;
++}
++
++static void __exit fini(void)
++{
++ /* FIXME: possible race with ip_set_create() */
++ ip_set_unregister_set_type(&ip_set_iptree);
++ kmem_cache_destroy(leaf_cachep);
++ kmem_cache_destroy(branch_cachep);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Naur linux-old/net/ipv4/netfilter/ip_set_macipmap.c linux-new/net/ipv4/netfilter/ip_set_macipmap.c
+--- linux-old/net/ipv4/netfilter/ip_set_macipmap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/net/ipv4/netfilter/ip_set_macipmap.c 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,340 @@
++/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
++ * Patrick Schaaf <bof@bof.de>
++ * Martin Josefsson <gandalf@wlug.westbo.se>
++ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module implementing an IP set type: the macipmap type */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <asm/softirq.h>
++#include <linux/spinlock.h>
++#include <linux/if_ether.h>
++#include <linux/vmalloc.h>
++
++#include <linux/netfilter_ipv4/ip_set_malloc.h>
++#include <linux/netfilter_ipv4/ip_set_macipmap.h>
++
++static int
++testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_macipmap *map = (struct ip_set_macipmap *) set->data;
++ struct ip_set_macip *table = (struct ip_set_macip *) map->members;
++ struct ip_set_req_macipmap *req = (struct ip_set_req_macipmap *) data;
++
++ if (size != sizeof(struct ip_set_req_macipmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_macipmap),
++ size);
++ return -EINVAL;
++ }
++
++ if (req->ip < map->first_ip || req->ip > map->last_ip)
++ return -ERANGE;
++
++ *hash_ip = req->ip;
++ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
++ set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip));
++ if (test_bit(IPSET_MACIP_ISSET,
++ &table[req->ip - map->first_ip].flags)) {
++ return (memcmp(req->ethernet,
++ &table[req->ip - map->first_ip].ethernet,
++ ETH_ALEN) == 0);
++ } else {
++ return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
++ }
++}
++
++static int
++testip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++ struct ip_set_macip *table =
++ (struct ip_set_macip *) map->members;
++ ip_set_ip_t ip;
++
++ ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr);
++ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
++ flags & IPSET_SRC ? "SRC" : "DST",
++ NIPQUAD(skb->nh.iph->saddr),
++ NIPQUAD(skb->nh.iph->daddr));
++
++ if (ip < map->first_ip || ip > map->last_ip)
++ return 0;
++
++ *hash_ip = ip;
++ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
++ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
++ if (test_bit(IPSET_MACIP_ISSET, &table[ip - map->first_ip].flags)) {
++ /* Is mac pointer valid?
++ * If so, compare... */
++ return (skb->mac.raw >= skb->head
++ && (skb->mac.raw + ETH_HLEN) <= skb->data
++ && (memcmp(skb->mac.ethernet->h_source,
++ &table[ip - map->first_ip].ethernet,
++ ETH_ALEN) == 0));
++ } else {
++ return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
++ }
++}
++
++/* returns 0 on success */
++static inline int
++__addip(struct ip_set *set,
++ ip_set_ip_t ip, unsigned char *ethernet, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++ struct ip_set_macip *table =
++ (struct ip_set_macip *) map->members;
++
++ if (ip < map->first_ip || ip > map->last_ip)
++ return -ERANGE;
++ if (test_and_set_bit(IPSET_MACIP_ISSET,
++ &table[ip - map->first_ip].flags))
++ return -EEXIST;
++
++ *hash_ip = ip;
++ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
++ memcpy(&table[ip - map->first_ip].ethernet, ethernet, ETH_ALEN);
++ return 0;
++}
++
++static int
++addip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_macipmap *req =
++ (struct ip_set_req_macipmap *) data;
++
++ if (size != sizeof(struct ip_set_req_macipmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_macipmap),
++ size);
++ return -EINVAL;
++ }
++ return __addip(set, req->ip, req->ethernet, hash_ip);
++}
++
++static int
++addip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ ip_set_ip_t ip;
++
++ ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr);
++
++ if (!(skb->mac.raw >= skb->head
++ && (skb->mac.raw + ETH_HLEN) <= skb->data))
++ return -EINVAL;
++
++ return __addip(set, ip, skb->mac.ethernet->h_source, hash_ip);
++}
++
++static inline int
++__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++ struct ip_set_macip *table =
++ (struct ip_set_macip *) map->members;
++
++ if (ip < map->first_ip || ip > map->last_ip)
++ return -ERANGE;
++ if (!test_and_clear_bit(IPSET_MACIP_ISSET,
++ &table[ip - map->first_ip].flags))
++ return -EEXIST;
++
++ *hash_ip = ip;
++ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
++ return 0;
++}
++
++static int
++delip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_macipmap *req =
++ (struct ip_set_req_macipmap *) data;
++
++ if (size != sizeof(struct ip_set_req_macipmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_macipmap),
++ size);
++ return -EINVAL;
++ }
++ return __delip(set, req->ip, hash_ip);
++}
++
++static int
++delip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __delip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++static inline size_t members_size(ip_set_id_t from, ip_set_id_t to)
++{
++ return (size_t)((to - from + 1) * sizeof(struct ip_set_macip));
++}
++
++static int create(struct ip_set *set, const void *data, size_t size)
++{
++ int newbytes;
++ struct ip_set_req_macipmap_create *req =
++ (struct ip_set_req_macipmap_create *) data;
++ struct ip_set_macipmap *map;
++
++ if (size != sizeof(struct ip_set_req_macipmap_create)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_macipmap_create),
++ size);
++ return -EINVAL;
++ }
++
++ DP("from %u.%u.%u.%u to %u.%u.%u.%u",
++ HIPQUAD(req->from), HIPQUAD(req->to));
++
++ if (req->from > req->to) {
++ DP("bad ip range");
++ return -ENOEXEC;
++ }
++
++ if (req->to - req->from > MAX_RANGE) {
++ ip_set_printk("range too big (max %d addresses)",
++ MAX_RANGE);
++ return -ENOEXEC;
++ }
++
++ map = kmalloc(sizeof(struct ip_set_macipmap), GFP_KERNEL);
++ if (!map) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_macipmap));
++ return -ENOMEM;
++ }
++ map->flags = req->flags;
++ map->first_ip = req->from;
++ map->last_ip = req->to;
++ newbytes = members_size(map->first_ip, map->last_ip);
++ map->members = ip_set_malloc(newbytes);
++ DP("members: %u %p", newbytes, map->members);
++ if (!map->members) {
++ DP("out of memory for %d bytes", newbytes);
++ kfree(map);
++ return -ENOMEM;
++ }
++ memset(map->members, 0, newbytes);
++
++ set->data = map;
++ return 0;
++}
++
++static void destroy(struct ip_set *set)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++
++ ip_set_free(map->members, members_size(map->first_ip, map->last_ip));
++ kfree(map);
++
++ set->data = NULL;
++}
++
++static void flush(struct ip_set *set)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++ memset(map->members, 0, members_size(map->first_ip, map->last_ip));
++}
++
++static void list_header(const struct ip_set *set, void *data)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++ struct ip_set_req_macipmap_create *header =
++ (struct ip_set_req_macipmap_create *) data;
++
++ DP("list_header %x %x %u", map->first_ip, map->last_ip,
++ map->flags);
++
++ header->from = map->first_ip;
++ header->to = map->last_ip;
++ header->flags = map->flags;
++}
++
++static int list_members_size(const struct ip_set *set)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++
++ DP("%u", members_size(map->first_ip, map->last_ip));
++ return members_size(map->first_ip, map->last_ip);
++}
++
++static void list_members(const struct ip_set *set, void *data)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++
++ int bytes = members_size(map->first_ip, map->last_ip);
++
++ DP("members: %u %p", bytes, map->members);
++ memcpy(data, map->members, bytes);
++}
++
++static struct ip_set_type ip_set_macipmap = {
++ .typename = SETTYPE_NAME,
++ .typecode = IPSET_TYPE_IP,
++ .protocol_version = IP_SET_PROTOCOL_VERSION,
++ .create = &create,
++ .destroy = &destroy,
++ .flush = &flush,
++ .reqsize = sizeof(struct ip_set_req_macipmap),
++ .addip = &addip,
++ .addip_kernel = &addip_kernel,
++ .delip = &delip,
++ .delip_kernel = &delip_kernel,
++ .testip = &testip,
++ .testip_kernel = &testip_kernel,
++ .header_size = sizeof(struct ip_set_req_macipmap_create),
++ .list_header = &list_header,
++ .list_members_size = &list_members_size,
++ .list_members = &list_members,
++ .me = THIS_MODULE,
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("macipmap type of IP sets");
++
++static int __init init(void)
++{
++ return ip_set_register_set_type(&ip_set_macipmap);
++}
++
++static void __exit fini(void)
++{
++ /* FIXME: possible race with ip_set_create() */
++ ip_set_unregister_set_type(&ip_set_macipmap);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Naur linux-old/net/ipv4/netfilter/ip_set_nethash.c linux-new/net/ipv4/netfilter/ip_set_nethash.c
+--- linux-old/net/ipv4/netfilter/ip_set_nethash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/net/ipv4/netfilter/ip_set_nethash.c 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,450 @@
++/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module implementing a cidr nethash set */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <asm/softirq.h>
++#include <linux/spinlock.h>
++#include <linux/vmalloc.h>
++#include <linux/random.h>
++
++#include <net/ip.h>
++
++#include <linux/netfilter_ipv4/ip_set_malloc.h>
++#include <linux/netfilter_ipv4/ip_set_nethash.h>
++#include <linux/netfilter_ipv4/ip_set_jhash.h>
++#include <linux/netfilter_ipv4/ip_set_prime.h>
++
++static inline __u32
++jhash_ip(const struct ip_set_nethash *map, ip_set_ip_t ip)
++{
++ return jhash_1word(ip, map->initval);
++}
++
++static inline __u32
++randhash_ip(const struct ip_set_nethash *map, ip_set_ip_t ip)
++{
++ return (1 + ip % map->prime);
++}
++
++static inline __u32
++hash_id_cidr(struct ip_set_nethash *map,
++ ip_set_ip_t ip,
++ unsigned char cidr,
++ ip_set_ip_t *hash_ip)
++{
++ __u32 jhash, randhash, id;
++ u_int16_t i;
++
++ *hash_ip = pack(ip, cidr);
++ jhash = jhash_ip(map, *hash_ip);
++ randhash = randhash_ip(map, *hash_ip);
++
++ for (i = 0; i < map->probes; i++) {
++ id = (jhash + i * randhash) % map->hashsize;
++ DP("hash key: %u", id);
++ if (map->members[id] == *hash_ip)
++ return id;
++ }
++ return UINT_MAX;
++}
++
++static inline __u32
++hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++ __u32 id = UINT_MAX;
++ int i;
++
++ for (i = 0; i < 30 && map->cidr[i]; i++) {
++ id = hash_id_cidr(map, ip, map->cidr[i], hash_ip);
++ if (id != UINT_MAX)
++ break;
++ }
++ return id;
++}
++
++static inline int
++__testip_cidr(struct ip_set *set, ip_set_ip_t ip, unsigned char cidr,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++
++ return (hash_id_cidr(map, ip, cidr, hash_ip) != UINT_MAX);
++}
++
++static inline int
++__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ return (hash_id(set, ip, hash_ip) != UINT_MAX);
++}
++
++static int
++testip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_nethash *req =
++ (struct ip_set_req_nethash *) data;
++
++ if (size != sizeof(struct ip_set_req_nethash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_nethash),
++ size);
++ return -EINVAL;
++ }
++ return (req->cidr == 32 ? __testip(set, req->ip, hash_ip)
++ : __testip_cidr(set, req->ip, req->cidr, hash_ip));
++}
++
++static int
++testip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __testip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++static inline int
++__addip_base(struct ip_set_nethash *map, ip_set_ip_t ip)
++{
++ __u32 jhash, randhash, probe;
++ u_int16_t i;
++
++ jhash = jhash_ip(map, ip);
++ randhash = randhash_ip(map, ip);
++
++ for (i = 0; i < map->probes; i++) {
++ probe = (jhash + i * randhash) % map->hashsize;
++ if (map->members[probe] == ip)
++ return -EEXIST;
++ if (!map->members[probe]) {
++ map->members[probe] = ip;
++ return 0;
++ }
++ }
++ /* Trigger rehashing */
++ return -EAGAIN;
++}
++
++static inline int
++__addip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
++ ip_set_ip_t *hash_ip)
++{
++ *hash_ip = pack(ip, cidr);
++ DP("%u.%u.%u.%u/%u, %u.%u.%u.%u", HIPQUAD(ip), cidr, HIPQUAD(*hash_ip));
++
++ return __addip_base(map, *hash_ip);
++}
++
++static void
++update_cidr_sizes(struct ip_set_nethash *map, unsigned char cidr)
++{
++ unsigned char next;
++ int i;
++
++ for (i = 0; i < 30 && map->cidr[i]; i++) {
++ if (map->cidr[i] == cidr) {
++ return;
++ } else if (map->cidr[i] < cidr) {
++ next = map->cidr[i];
++ map->cidr[i] = cidr;
++ cidr = next;
++ }
++ }
++ if (i < 30)
++ map->cidr[i] = cidr;
++}
++
++static int
++addip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_nethash *req =
++ (struct ip_set_req_nethash *) data;
++ int ret;
++
++ if (size != sizeof(struct ip_set_req_nethash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_nethash),
++ size);
++ return -EINVAL;
++ }
++ ret = __addip((struct ip_set_nethash *) set->data,
++ req->ip, req->cidr, hash_ip);
++
++ if (ret == 0)
++ update_cidr_sizes((struct ip_set_nethash *) set->data,
++ req->cidr);
++
++ return ret;
++}
++
++static int
++addip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++ int ret = -ERANGE;
++ ip_set_ip_t ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr);
++
++ if (map->cidr[0])
++ ret = __addip(map, ip, map->cidr[0], hash_ip);
++
++ return ret;
++}
++
++static int retry(struct ip_set *set)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++ ip_set_ip_t *members;
++ u_int32_t i, hashsize;
++ unsigned newbytes;
++ int res;
++ struct ip_set_nethash tmp = {
++ .hashsize = map->hashsize,
++ .probes = map->probes,
++ .resize = map->resize
++ };
++
++ if (map->resize == 0)
++ return -ERANGE;
++
++ memcpy(tmp.cidr, map->cidr, 30 * sizeof(unsigned char));
++ again:
++ res = 0;
++
++ /* Calculate new parameters */
++ get_random_bytes(&tmp.initval, 4);
++ hashsize = tmp.hashsize + (tmp.hashsize * map->resize)/100;
++ if (hashsize == tmp.hashsize)
++ hashsize++;
++ tmp.prime = make_prime(hashsize);
++
++ ip_set_printk("rehashing of set %s triggered: "
++ "hashsize grows from %u to %u",
++ set->name, tmp.hashsize, hashsize);
++ tmp.hashsize = hashsize;
++
++ newbytes = hashsize * sizeof(ip_set_ip_t);
++ tmp.members = ip_set_malloc(newbytes);
++ if (!tmp.members) {
++ DP("out of memory for %d bytes", newbytes);
++ return -ENOMEM;
++ }
++ memset(tmp.members, 0, newbytes);
++
++ write_lock_bh(&set->lock);
++ map = (struct ip_set_nethash *) set->data; /* Play safe */
++ for (i = 0; i < map->hashsize && res == 0; i++) {
++ if (map->members[i])
++ res = __addip_base(&tmp, map->members[i]);
++ }
++ if (res) {
++ /* Failure, try again */
++ write_unlock_bh(&set->lock);
++ ip_set_free(tmp.members, newbytes);
++ goto again;
++ }
++
++ /* Success at resizing! */
++ members = map->members;
++ hashsize = map->hashsize;
++
++ map->initval = tmp.initval;
++ map->prime = tmp.prime;
++ map->hashsize = tmp.hashsize;
++ map->members = tmp.members;
++ write_unlock_bh(&set->lock);
++
++ ip_set_free(members, hashsize * sizeof(ip_set_ip_t));
++
++ return 0;
++}
++
++static inline int
++__delip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
++ ip_set_ip_t *hash_ip)
++{
++ ip_set_ip_t id = hash_id_cidr(map, ip, cidr, hash_ip);
++
++ if (id == UINT_MAX)
++ return -EEXIST;
++
++ map->members[id] = 0;
++ return 0;
++}
++
++static int
++delip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_nethash *req =
++ (struct ip_set_req_nethash *) data;
++
++ if (size != sizeof(struct ip_set_req_nethash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_nethash),
++ size);
++ return -EINVAL;
++ }
++ /* TODO: no garbage collection in map->cidr */
++ return __delip((struct ip_set_nethash *) set->data,
++ req->ip, req->cidr, hash_ip);
++}
++
++static int
++delip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++ int ret = -ERANGE;
++ ip_set_ip_t ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr);
++
++ if (map->cidr[0])
++ ret = __delip(map, ip, map->cidr[0], hash_ip);
++
++ return ret;
++}
++
++static int create(struct ip_set *set, const void *data, size_t size)
++{
++ unsigned newbytes;
++ struct ip_set_req_nethash_create *req =
++ (struct ip_set_req_nethash_create *) data;
++ struct ip_set_nethash *map;
++
++ if (size != sizeof(struct ip_set_req_nethash_create)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_nethash_create),
++ size);
++ return -EINVAL;
++ }
++
++ if (req->hashsize < 1) {
++ ip_set_printk("hashsize too small");
++ return -ENOEXEC;
++ }
++
++ map = kmalloc(sizeof(struct ip_set_nethash), GFP_KERNEL);
++ if (!map) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_nethash));
++ return -ENOMEM;
++ }
++ get_random_bytes(&map->initval, 4);
++ map->prime = make_prime(req->hashsize);
++ map->hashsize = req->hashsize;
++ map->probes = req->probes;
++ map->resize = req->resize;
++ memset(map->cidr, 0, 30 * sizeof(unsigned char));
++ newbytes = map->hashsize * sizeof(ip_set_ip_t);
++ map->members = ip_set_malloc(newbytes);
++ if (!map->members) {
++ DP("out of memory for %d bytes", newbytes);
++ kfree(map);
++ return -ENOMEM;
++ }
++ memset(map->members, 0, newbytes);
++
++ set->data = map;
++ return 0;
++}
++
++static void destroy(struct ip_set *set)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++
++ ip_set_free(map->members, map->hashsize * sizeof(ip_set_ip_t));
++ kfree(map);
++
++ set->data = NULL;
++}
++
++static void flush(struct ip_set *set)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++ memset(map->members, 0, map->hashsize * sizeof(ip_set_ip_t));
++ memset(map->cidr, 0, 30 * sizeof(unsigned char));
++}
++
++static void list_header(const struct ip_set *set, void *data)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++ struct ip_set_req_nethash_create *header =
++ (struct ip_set_req_nethash_create *) data;
++
++ header->hashsize = map->hashsize;
++ header->probes = map->probes;
++ header->resize = map->resize;
++}
++
++static int list_members_size(const struct ip_set *set)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++
++ return (map->hashsize * sizeof(ip_set_ip_t));
++}
++
++static void list_members(const struct ip_set *set, void *data)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++ int bytes = map->hashsize * sizeof(ip_set_ip_t);
++
++ memcpy(data, map->members, bytes);
++}
++
++static struct ip_set_type ip_set_nethash = {
++ .typename = SETTYPE_NAME,
++ .typecode = IPSET_TYPE_IP,
++ .protocol_version = IP_SET_PROTOCOL_VERSION,
++ .create = &create,
++ .destroy = &destroy,
++ .flush = &flush,
++ .reqsize = sizeof(struct ip_set_req_nethash),
++ .addip = &addip,
++ .addip_kernel = &addip_kernel,
++ .retry = &retry,
++ .delip = &delip,
++ .delip_kernel = &delip_kernel,
++ .testip = &testip,
++ .testip_kernel = &testip_kernel,
++ .header_size = sizeof(struct ip_set_req_nethash_create),
++ .list_header = &list_header,
++ .list_members_size = &list_members_size,
++ .list_members = &list_members,
++ .me = THIS_MODULE,
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("nethash type of IP sets");
++
++static int __init init(void)
++{
++ return ip_set_register_set_type(&ip_set_nethash);
++}
++
++static void __exit fini(void)
++{
++ /* FIXME: possible race with ip_set_create() */
++ ip_set_unregister_set_type(&ip_set_nethash);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Naur linux-old/net/ipv4/netfilter/ip_set_portmap.c linux-new/net/ipv4/netfilter/ip_set_portmap.c
+--- linux-old/net/ipv4/netfilter/ip_set_portmap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/net/ipv4/netfilter/ip_set_portmap.c 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,321 @@
++/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module implementing a port set type as a bitmap */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <asm/softirq.h>
++#include <linux/spinlock.h>
++
++#include <net/ip.h>
++
++#include <linux/netfilter_ipv4/ip_set_portmap.h>
++
++static inline ip_set_ip_t
++get_port(const struct sk_buff *skb, u_int32_t flags)
++{
++ struct iphdr *iph = skb->nh.iph;
++ u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
++
++ switch (iph->protocol) {
++ case IPPROTO_TCP: {
++ struct tcphdr *tcph = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
++
++ /* See comments at tcp_match in ip_tables.c */
++ if (offset != 0
++ || (offset == 0
++ && (skb->len - iph->ihl * 4) < sizeof(struct tcphdr)))
++ return INVALID_PORT;
++
++ return ntohs(flags & IPSET_SRC ?
++ tcph->source : tcph->dest);
++ }
++ case IPPROTO_UDP: {
++ struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
++
++ if (offset != 0
++ || (offset == 0
++ && (skb->len - iph->ihl * 4) < sizeof(struct udphdr)))
++ return INVALID_PORT;
++
++ return ntohs(flags & IPSET_SRC ?
++ udph->source : udph->dest);
++ }
++ default:
++ return INVALID_PORT;
++ }
++}
++
++static inline int
++__testport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++
++ if (port < map->first_port || port > map->last_port)
++ return -ERANGE;
++
++ *hash_port = port;
++ DP("set: %s, port:%u, %u", set->name, port, *hash_port);
++ return !!test_bit(port - map->first_port, map->members);
++}
++
++static int
++testport(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_port)
++{
++ struct ip_set_req_portmap *req =
++ (struct ip_set_req_portmap *) data;
++
++ if (size != sizeof(struct ip_set_req_portmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_portmap),
++ size);
++ return -EINVAL;
++ }
++ return __testport(set, req->port, hash_port);
++}
++
++static int
++testport_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_port)
++{
++ int res;
++ ip_set_ip_t port = get_port(skb, flags);
++
++ DP("flag %s port %u", flags & IPSET_SRC ? "SRC" : "DST", port);
++ if (port == INVALID_PORT)
++ return 0;
++
++ res = __testport(set, port, hash_port);
++
++ return (res < 0 ? 0 : res);
++}
++
++static inline int
++__addport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++
++ if (port < map->first_port || port > map->last_port)
++ return -ERANGE;
++ if (test_and_set_bit(port - map->first_port, map->members))
++ return -EEXIST;
++
++ *hash_port = port;
++ DP("port %u", port);
++ return 0;
++}
++
++static int
++addport(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_port)
++{
++ struct ip_set_req_portmap *req =
++ (struct ip_set_req_portmap *) data;
++
++ if (size != sizeof(struct ip_set_req_portmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_portmap),
++ size);
++ return -EINVAL;
++ }
++ return __addport(set, req->port, hash_port);
++}
++
++static int
++addport_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_port)
++{
++ ip_set_ip_t port = get_port(skb, flags);
++
++ if (port == INVALID_PORT)
++ return -EINVAL;
++
++ return __addport(set, port, hash_port);
++}
++
++static inline int
++__delport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++
++ if (port < map->first_port || port > map->last_port)
++ return -ERANGE;
++ if (!test_and_clear_bit(port - map->first_port, map->members))
++ return -EEXIST;
++
++ *hash_port = port;
++ DP("port %u", port);
++ return 0;
++}
++
++static int
++delport(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_port)
++{
++ struct ip_set_req_portmap *req =
++ (struct ip_set_req_portmap *) data;
++
++ if (size != sizeof(struct ip_set_req_portmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_portmap),
++ size);
++ return -EINVAL;
++ }
++ return __delport(set, req->port, hash_port);
++}
++
++static int
++delport_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_port)
++{
++ ip_set_ip_t port = get_port(skb, flags);
++
++ if (port == INVALID_PORT)
++ return -EINVAL;
++
++ return __delport(set, port, hash_port);
++}
++
++static int create(struct ip_set *set, const void *data, size_t size)
++{
++ int newbytes;
++ struct ip_set_req_portmap_create *req =
++ (struct ip_set_req_portmap_create *) data;
++ struct ip_set_portmap *map;
++
++ if (size != sizeof(struct ip_set_req_portmap_create)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_portmap_create),
++ size);
++ return -EINVAL;
++ }
++
++ DP("from %u to %u", req->from, req->to);
++
++ if (req->from > req->to) {
++ DP("bad port range");
++ return -ENOEXEC;
++ }
++
++ if (req->to - req->from > MAX_RANGE) {
++ ip_set_printk("range too big (max %d ports)",
++ MAX_RANGE);
++ return -ENOEXEC;
++ }
++
++ map = kmalloc(sizeof(struct ip_set_portmap), GFP_KERNEL);
++ if (!map) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_portmap));
++ return -ENOMEM;
++ }
++ map->first_port = req->from;
++ map->last_port = req->to;
++ newbytes = bitmap_bytes(req->from, req->to);
++ map->members = kmalloc(newbytes, GFP_KERNEL);
++ if (!map->members) {
++ DP("out of memory for %d bytes", newbytes);
++ kfree(map);
++ return -ENOMEM;
++ }
++ memset(map->members, 0, newbytes);
++
++ set->data = map;
++ return 0;
++}
++
++static void destroy(struct ip_set *set)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++
++ kfree(map->members);
++ kfree(map);
++
++ set->data = NULL;
++}
++
++static void flush(struct ip_set *set)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++ memset(map->members, 0, bitmap_bytes(map->first_port, map->last_port));
++}
++
++static void list_header(const struct ip_set *set, void *data)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++ struct ip_set_req_portmap_create *header =
++ (struct ip_set_req_portmap_create *) data;
++
++ DP("list_header %u %u", map->first_port, map->last_port);
++
++ header->from = map->first_port;
++ header->to = map->last_port;
++}
++
++static int list_members_size(const struct ip_set *set)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++
++ return bitmap_bytes(map->first_port, map->last_port);
++}
++
++static void list_members(const struct ip_set *set, void *data)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++ int bytes = bitmap_bytes(map->first_port, map->last_port);
++
++ memcpy(data, map->members, bytes);
++}
++
++static struct ip_set_type ip_set_portmap = {
++ .typename = SETTYPE_NAME,
++ .typecode = IPSET_TYPE_PORT,
++ .protocol_version = IP_SET_PROTOCOL_VERSION,
++ .create = &create,
++ .destroy = &destroy,
++ .flush = &flush,
++ .reqsize = sizeof(struct ip_set_req_portmap),
++ .addip = &addport,
++ .addip_kernel = &addport_kernel,
++ .delip = &delport,
++ .delip_kernel = &delport_kernel,
++ .testip = &testport,
++ .testip_kernel = &testport_kernel,
++ .header_size = sizeof(struct ip_set_req_portmap_create),
++ .list_header = &list_header,
++ .list_members_size = &list_members_size,
++ .list_members = &list_members,
++ .me = THIS_MODULE,
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("portmap type of IP sets");
++
++static int __init init(void)
++{
++ return ip_set_register_set_type(&ip_set_portmap);
++}
++
++static void __exit fini(void)
++{
++ /* FIXME: possible race with ip_set_create() */
++ ip_set_unregister_set_type(&ip_set_portmap);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Naur linux-old/net/ipv4/netfilter/ipt_set.c linux-new/net/ipv4/netfilter/ipt_set.c
+--- linux-old/net/ipv4/netfilter/ipt_set.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/net/ipv4/netfilter/ipt_set.c 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,114 @@
++/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
++ * Patrick Schaaf <bof@bof.de>
++ * Martin Josefsson <gandalf@wlug.westbo.se>
++ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module to match an IP set. */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/netfilter_ipv4/ipt_set.h>
++
++static inline int
++match_set(const struct ipt_set_info *info,
++ const struct sk_buff *skb,
++ int inv)
++{
++ if (ip_set_testip_kernel(info->index, skb, info->flags))
++ inv = !inv;
++ return inv;
++}
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ const void *hdr,
++ u_int16_t datalen,
++ int *hotdrop)
++{
++ const struct ipt_set_info_match *info = matchinfo;
++
++ return match_set(&info->match_set,
++ skb,
++ info->match_set.flags[0] & IPSET_MATCH_INV);
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ struct ipt_set_info_match *info =
++ (struct ipt_set_info_match *) matchinfo;
++ ip_set_id_t index;
++
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
++ ip_set_printk("invalid matchsize %d", matchsize);
++ return 0;
++ }
++
++ index = ip_set_get_byindex(info->match_set.index);
++
++ if (index == IP_SET_INVALID_ID) {
++ ip_set_printk("Cannot find set indentified by id %u to match",
++ info->match_set.index);
++ return 0; /* error */
++ }
++ if (info->match_set.flags[IP_SET_MAX_BINDINGS] != 0) {
++ ip_set_printk("That's nasty!");
++ return 0; /* error */
++ }
++
++ return 1;
++}
++
++static void destroy(void *matchinfo, unsigned int matchsize)
++{
++ struct ipt_set_info_match *info = matchinfo;
++
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
++ ip_set_printk("invalid matchsize %d", matchsize);
++ return;
++ }
++
++ ip_set_put(info->match_set.index);
++}
++
++static struct ipt_match set_match = {
++ .name = "set",
++ .match = &match,
++ .checkentry = &checkentry,
++ .destroy = &destroy,
++ .me = THIS_MODULE
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("iptables IP set match module");
++
++static int __init init(void)
++{
++ return ipt_register_match(&set_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&set_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Naur linux-old/net/ipv4/netfilter/ipt_SET.c linux-new/net/ipv4/netfilter/ipt_SET.c
+--- linux-old/net/ipv4/netfilter/ipt_SET.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-new/net/ipv4/netfilter/ipt_SET.c 2005-08-10 22:13:00.000000000 +0200
+@@ -0,0 +1,127 @@
++/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
++ * Patrick Schaaf <bof@bof.de>
++ * Martin Josefsson <gandalf@wlug.westbo.se>
++ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* ipt_SET.c - netfilter target to manipulate IP sets */
++
++#include <linux/types.h>
++#include <linux/ip.h>
++#include <linux/timer.h>
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/netdevice.h>
++#include <linux/if.h>
++#include <linux/inetdevice.h>
++#include <net/protocol.h>
++#include <net/checksum.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ipt_set.h>
++
++static unsigned int
++target(struct sk_buff **pskb,
++ unsigned int hooknum,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *targinfo,
++ void *userinfo)
++{
++ const struct ipt_set_info_target *info = targinfo;
++
++ if (info->add_set.index != IP_SET_INVALID_ID)
++ ip_set_addip_kernel(info->add_set.index,
++ *pskb,
++ info->add_set.flags);
++ if (info->del_set.index != IP_SET_INVALID_ID)
++ ip_set_delip_kernel(info->del_set.index,
++ *pskb,
++ info->del_set.flags);
++
++ return IPT_CONTINUE;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize, unsigned int hook_mask)
++{
++ struct ipt_set_info_target *info =
++ (struct ipt_set_info_target *) targinfo;
++ ip_set_id_t index;
++
++ if (targinfosize != IPT_ALIGN(sizeof(*info))) {
++ DP("bad target info size %u", targinfosize);
++ return 0;
++ }
++
++ if (info->add_set.index != IP_SET_INVALID_ID) {
++ index = ip_set_get_byindex(info->add_set.index);
++ if (index == IP_SET_INVALID_ID) {
++ ip_set_printk("cannot find add_set index %u as target",
++ info->add_set.index);
++ return 0; /* error */
++ }
++ }
++
++ if (info->del_set.index != IP_SET_INVALID_ID) {
++ index = ip_set_get_byindex(info->del_set.index);
++ if (index == IP_SET_INVALID_ID) {
++ ip_set_printk("cannot find del_set index %u as target",
++ info->del_set.index);
++ return 0; /* error */
++ }
++ }
++ if (info->add_set.flags[IP_SET_MAX_BINDINGS] != 0
++ || info->del_set.flags[IP_SET_MAX_BINDINGS] != 0) {
++ ip_set_printk("That's nasty!");
++ return 0; /* error */
++ }
++ return 1;
++}
++
++static void destroy(void *targetinfo, unsigned int targetsize)
++{
++ struct ipt_set_info_target *info = targetinfo;
++
++ if (targetsize != IPT_ALIGN(sizeof(struct ipt_set_info_target))) {
++ ip_set_printk("invalid targetsize %d", targetsize);
++ return;
++ }
++
++ if (info->add_set.index != IP_SET_INVALID_ID)
++ ip_set_put(info->add_set.index);
++ if (info->del_set.index != IP_SET_INVALID_ID)
++ ip_set_put(info->del_set.index);
++}
++
++static struct ipt_target SET_target = {
++ .name = "SET",
++ .target = target,
++ .checkentry = checkentry,
++ .destroy = destroy,
++ .me = THIS_MODULE
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("iptables IP set target module");
++
++static int __init init(void)
++{
++ return ipt_register_target(&SET_target);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&SET_target);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Naur linux-old/net/ipv4/netfilter/Makefile linux-new/net/ipv4/netfilter/Makefile
+--- linux-old/net/ipv4/netfilter/Makefile 2005-07-23 23:34:46.000000000 +0200
++++ linux-new/net/ipv4/netfilter/Makefile 2005-08-10 22:13:01.000000000 +0200
+@@ -75,6 +75,18 @@
+ obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
+ obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
+ obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
++obj-$(CONFIG_IP_NF_MATCH_SET) += ipt_set.o
++obj-$(CONFIG_IP_NF_TARGET_SET) += ipt_SET.o
++ifdef CONFIG_IP_NF_SET
++ obj-$(CONFIG_IP_NF_SET) += ip_set.o
++ export-objs += ip_set.o
++endif
++obj-$(CONFIG_IP_NF_SET_IPMAP) += ip_set_ipmap.o
++obj-$(CONFIG_IP_NF_SET_PORTMAP) += ip_set_portmap.o
++obj-$(CONFIG_IP_NF_SET_MACIPMAP) += ip_set_macipmap.o
++obj-$(CONFIG_IP_NF_SET_IPHASH) += ip_set_iphash.o
++obj-$(CONFIG_IP_NF_SET_NETHASH) += ip_set_nethash.o
++obj-$(CONFIG_IP_NF_SET_IPTREE) += ip_set_iptree.o
+ obj-$(CONFIG_IP_NF_MATCH_MAC) += ipt_mac.o
+ obj-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p.o
+
diff --git a/target/linux/generic-2.4/patches/609-netfilter_string.patch b/target/linux/generic-2.4/patches/609-netfilter_string.patch
new file mode 100644
index 0000000..c8e1a2d
--- /dev/null
+++ b/target/linux/generic-2.4/patches/609-netfilter_string.patch
@@ -0,0 +1,348 @@
+diff -Nur linux-2.4.32/include/linux/netfilter_ipv4/ipt_string.h linux-2.4.32.patch/include/linux/netfilter_ipv4/ipt_string.h
+--- linux-2.4.32/include/linux/netfilter_ipv4/ipt_string.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32.patch/include/linux/netfilter_ipv4/ipt_string.h 2005-12-16 00:40:19.082509250 +0100
+@@ -0,0 +1,18 @@
++#ifndef _IPT_STRING_H
++#define _IPT_STRING_H
++
++#define IPT_STRING_MAX_PATTERN_SIZE 128
++#define IPT_STRING_MAX_ALGO_NAME_SIZE 16
++
++struct ipt_string_info
++{
++ u_int16_t from_offset;
++ u_int16_t to_offset;
++ char algo[IPT_STRING_MAX_ALGO_NAME_SIZE];
++ char pattern[IPT_STRING_MAX_PATTERN_SIZE];
++ u_int8_t patlen;
++ u_int8_t invert;
++ struct ts_config __attribute__((aligned(8))) *config;
++};
++
++#endif /*_IPT_STRING_H*/
+diff -Nur linux-2.4.32/include/linux/textsearch.h linux-2.4.32.patch/include/linux/textsearch.h
+--- linux-2.4.32/include/linux/textsearch.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32.patch/include/linux/textsearch.h 2005-12-16 11:15:34.838073000 +0100
+@@ -0,0 +1,205 @@
++#ifndef __LINUX_TEXTSEARCH_H
++#define __LINUX_TEXTSEARCH_H
++
++#ifdef __KERNEL__
++
++#include <linux/types.h>
++#include <linux/list.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++
++#ifdef __CHECKER__
++#define __bitwise__ __attribute__((bitwise))
++#else
++#define __bitwise__
++#endif
++#ifdef __CHECK_ENDIAN__
++#define __bitwise __bitwise__
++#else
++#define __bitwise
++#endif
++
++typedef __u16 __bitwise __le16;
++typedef __u16 __bitwise __be16;
++typedef __u32 __bitwise __le32;
++typedef __u32 __bitwise __be32;
++#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
++typedef __u64 __bitwise __le64;
++typedef __u64 __bitwise __be64;
++#endif
++
++#ifdef __KERNEL__
++typedef unsigned __bitwise__ gfp_t;
++#endif
++
++struct ts_config;
++
++/**
++ * TS_AUTOLOAD - Automatically load textsearch modules when needed
++ */
++#define TS_AUTOLOAD 1
++
++/**
++ * struct ts_state - search state
++ * @offset: offset for next match
++ * @cb: control buffer, for persistant variables of get_next_block()
++ */
++struct ts_state
++{
++ unsigned int offset;
++ char cb[40];
++};
++
++/**
++ * struct ts_ops - search module operations
++ * @name: name of search algorithm
++ * @init: initialization function to prepare a search
++ * @find: find the next occurrence of the pattern
++ * @destroy: destroy algorithm specific parts of a search configuration
++ * @get_pattern: return head of pattern
++ * @get_pattern_len: return length of pattern
++ * @owner: module reference to algorithm
++ */
++struct ts_ops
++{
++ const char *name;
++ struct ts_config * (*init)(const void *, unsigned int, gfp_t);
++ unsigned int (*find)(struct ts_config *,
++ struct ts_state *);
++ void (*destroy)(struct ts_config *);
++ void * (*get_pattern)(struct ts_config *);
++ unsigned int (*get_pattern_len)(struct ts_config *);
++ struct module *owner;
++ struct list_head list;
++};
++
++/**
++ * struct ts_config - search configuration
++ * @ops: operations of chosen algorithm
++ * @get_next_block: callback to fetch the next block to search in
++ * @finish: callback to finalize a search
++ */
++struct ts_config
++{
++ struct ts_ops *ops;
++
++ /**
++ * get_next_block - fetch next block of data
++ * @consumed: number of bytes consumed by the caller
++ * @dst: destination buffer
++ * @conf: search configuration
++ * @state: search state
++ *
++ * Called repeatedly until 0 is returned. Must assign the
++ * head of the next block of data to &*dst and return the length
++ * of the block or 0 if at the end. consumed == 0 indicates
++ * a new search. May store/read persistant values in state->cb.
++ */
++ unsigned int (*get_next_block)(unsigned int consumed,
++ const u8 **dst,
++ struct ts_config *conf,
++ struct ts_state *state);
++
++ /**
++ * finish - finalize/clean a series of get_next_block() calls
++ * @conf: search configuration
++ * @state: search state
++ *
++ * Called after the last use of get_next_block(), may be used
++ * to cleanup any leftovers.
++ */
++ void (*finish)(struct ts_config *conf,
++ struct ts_state *state);
++};
++
++/**
++ * textsearch_next - continue searching for a pattern
++ * @conf: search configuration
++ * @state: search state
++ *
++ * Continues a search looking for more occurrences of the pattern.
++ * textsearch_find() must be called to find the first occurrence
++ * in order to reset the state.
++ *
++ * Returns the position of the next occurrence of the pattern or
++ * UINT_MAX if not match was found.
++ */
++static inline unsigned int textsearch_next(struct ts_config *conf,
++ struct ts_state *state)
++{
++ unsigned int ret = conf->ops->find(conf, state);
++
++ if (conf->finish)
++ conf->finish(conf, state);
++
++ return ret;
++}
++
++/**
++ * textsearch_find - start searching for a pattern
++ * @conf: search configuration
++ * @state: search state
++ *
++ * Returns the position of first occurrence of the pattern or
++ * UINT_MAX if no match was found.
++ */
++static inline unsigned int textsearch_find(struct ts_config *conf,
++ struct ts_state *state)
++{
++ state->offset = 0;
++ return textsearch_next(conf, state);
++}
++
++/**
++ * textsearch_get_pattern - return head of the pattern
++ * @conf: search configuration
++ */
++static inline void *textsearch_get_pattern(struct ts_config *conf)
++{
++ return conf->ops->get_pattern(conf);
++}
++
++/**
++ * textsearch_get_pattern_len - return length of the pattern
++ * @conf: search configuration
++ */
++static inline unsigned int textsearch_get_pattern_len(struct ts_config *conf)
++{
++ return conf->ops->get_pattern_len(conf);
++}
++
++extern int textsearch_register(struct ts_ops *);
++extern int textsearch_unregister(struct ts_ops *);
++extern struct ts_config *textsearch_prepare(const char *, const void *,
++ unsigned int, gfp_t, int);
++extern void textsearch_destroy(struct ts_config *conf);
++extern unsigned int textsearch_find_continuous(struct ts_config *,
++ struct ts_state *,
++ const void *, unsigned int);
++
++
++#define TS_PRIV_ALIGNTO 8
++#define TS_PRIV_ALIGN(len) (((len) + TS_PRIV_ALIGNTO-1) & ~(TS_PRIV_ALIGNTO-1))
++
++static inline struct ts_config *alloc_ts_config(size_t payload,
++ gfp_t gfp_mask)
++{
++ struct ts_config *conf;
++
++ conf = kmalloc(TS_PRIV_ALIGN(sizeof(*conf)) + payload, gfp_mask);
++ if (conf == NULL)
++ return -ENOMEM;
++
++ memset(conf, 0, TS_PRIV_ALIGN(sizeof(*conf)) + payload);
++ return conf;
++}
++
++static inline void *ts_config_priv(struct ts_config *conf)
++{
++ return ((u8 *) conf + TS_PRIV_ALIGN(sizeof(struct ts_config)));
++}
++
++#endif /* __KERNEL__ */
++
++#endif
+diff -Nur linux-2.4.32/net/ipv4/netfilter/Config.in linux-2.4.32.patch/net/ipv4/netfilter/Config.in
+--- linux-2.4.32/net/ipv4/netfilter/Config.in 2005-01-19 15:10:13.000000000 +0100
++++ linux-2.4.32.patch/net/ipv4/netfilter/Config.in 2005-12-16 00:41:43.023755250 +0100
+@@ -42,6 +42,7 @@
+ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' Unclean match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_UNCLEAN $CONFIG_IP_NF_IPTABLES
++ dep_tristate ' String match support (EXPERIMENTAL) ' CONFIG_IP_NF_MATCH_STRING $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' Owner match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_OWNER $CONFIG_IP_NF_IPTABLES
+ fi
+ # The targets
+diff -Nur linux-2.4.32/net/ipv4/netfilter/ipt_string.c linux-2.4.32.patch/net/ipv4/netfilter/ipt_string.c
+--- linux-2.4.32/net/ipv4/netfilter/ipt_string.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32.patch/net/ipv4/netfilter/ipt_string.c 2005-12-16 00:40:48.436343750 +0100
+@@ -0,0 +1,91 @@
++/* String matching match for iptables
++ *
++ * (C) 2005 Pablo Neira Ayuso <pablo@eurodev.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_string.h>
++#include <linux/textsearch.h>
++
++MODULE_AUTHOR("Pablo Neira Ayuso <pablo@eurodev.net>");
++MODULE_DESCRIPTION("IP tables string match module");
++MODULE_LICENSE("GPL");
++
++static int match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ struct ts_state state;
++ struct ipt_string_info *conf = (struct ipt_string_info *) matchinfo;
++
++ memset(&state, 0, sizeof(struct ts_state));
++
++ return (skb_find_text((struct sk_buff *)skb, conf->from_offset,
++ conf->to_offset, conf->config, &state)
++ != UINT_MAX) && !conf->invert;
++}
++
++#define STRING_TEXT_PRIV(m) ((struct ipt_string_info *) m)
++
++static int checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ struct ipt_string_info *conf = matchinfo;
++ struct ts_config *ts_conf;
++
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_string_info)))
++ return 0;
++
++ /* Damn, can't handle this case properly with iptables... */
++ if (conf->from_offset > conf->to_offset)
++ return 0;
++
++ ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen,
++ GFP_KERNEL, TS_AUTOLOAD);
++ if (IS_ERR(ts_conf))
++ return 0;
++
++ conf->config = ts_conf;
++
++ return 1;
++}
++
++static void destroy(void *matchinfo, unsigned int matchsize)
++{
++ textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config);
++}
++
++static struct ipt_match string_match = {
++ .name = "string",
++ .match = match,
++ .checkentry = checkentry,
++ .destroy = destroy,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ return ipt_register_match(&string_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&string_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur linux-2.4.32/net/ipv4/netfilter/Makefile linux-2.4.32.patch/net/ipv4/netfilter/Makefile
+--- linux-2.4.32/net/ipv4/netfilter/Makefile 2003-08-25 13:44:44.000000000 +0200
++++ linux-2.4.32.patch/net/ipv4/netfilter/Makefile 2005-12-16 00:42:10.929499250 +0100
+@@ -85,6 +85,7 @@
+ obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
+ obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
+ obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
++obj-$(CONFIG_IP_NF_MATCH_STRING) += ipt_string.o
+ obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
+
+ # targets
diff --git a/target/linux/generic-2.4/patches/610-netfilter_connbytes.patch b/target/linux/generic-2.4/patches/610-netfilter_connbytes.patch
new file mode 100644
index 0000000..95bc10f
--- /dev/null
+++ b/target/linux/generic-2.4/patches/610-netfilter_connbytes.patch
@@ -0,0 +1,439 @@
+--- linux/net/ipv4/netfilter/Config.in.org 2005-11-13 15:53:59.457222512 +0100
++++ linux/net/ipv4/netfilter/Config.in 2005-11-13 15:56:25.241060000 +0100
+@@ -11,6 +11,8 @@
+ dep_tristate ' Amanda protocol support' CONFIG_IP_NF_AMANDA $CONFIG_IP_NF_CONNTRACK
+ dep_tristate ' TFTP protocol support' CONFIG_IP_NF_TFTP $CONFIG_IP_NF_CONNTRACK
+ dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK
++ dep_tristate ' Connection tracking flow accounting' CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK
++ dep_tristate ' Connection byte counter support' CONFIG_IP_NF_MATCH_CONNBYTES $CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK
+ dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE
+ fi
+--- linux/net/ipv4/netfilter/Makefile.org 2005-11-12 16:48:38.000000000 +0100
++++ linux/net/ipv4/netfilter/Makefile 2005-11-13 15:56:38.663019552 +0100
+@@ -94,6 +94,7 @@
+ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
+ obj-$(CONFIG_IP_NF_MATCH_STATE) += ipt_state.o
+ obj-$(CONFIG_IP_NF_MATCH_CONNMARK) += ipt_connmark.o
++obj-$(CONFIG_IP_NF_MATCH_CONNBYTES) += ipt_connbytes.o
+ obj-$(CONFIG_IP_NF_MATCH_CONNTRACK) += ipt_conntrack.o
+ obj-$(CONFIG_IP_NF_MATCH_UNCLEAN) += ipt_unclean.o
+ obj-$(CONFIG_IP_NF_MATCH_TCPMSS) += ipt_tcpmss.o
+--- linux/net/ipv4/netfilter/ip_conntrack_amanda.c.org 2004-02-18 14:36:32.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_conntrack_amanda.c 2005-11-13 15:40:00.000000000 +0100
+@@ -75,7 +75,7 @@
+
+ /* increase the UDP timeout of the master connection as replies from
+ * Amanda clients to the server can be quite delayed */
+- ip_ct_refresh(ct, master_timeout * HZ);
++ ip_ct_refresh_acct(ct,ctinfo,NULL, master_timeout * HZ);
+
+ /* Search for "CONNECT " string */
+ do {
+--- linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c.org 2003-11-28 19:26:21.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2005-11-13 15:45:41.045992536 +0100
+@@ -211,7 +211,7 @@
+ set_bit(IPS_ASSURED_BIT, &conntrack->status);
+
+ WRITE_UNLOCK(&tcp_lock);
+- ip_ct_refresh(conntrack, *tcp_timeouts[newconntrack]);
++ ip_ct_refresh_acct(conntrack,ctinfo,iph, *tcp_timeouts[newconntrack]);
+ }
+
+ return NF_ACCEPT;
+--- linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c.org 2003-11-28 19:26:21.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_conntrack_proto_udp.c 2005-11-13 15:47:38.348159896 +0100
+@@ -47,16 +47,16 @@
+ /* Returns verdict for packet, and may modify conntracktype */
+ static int udp_packet(struct ip_conntrack *conntrack,
+ struct iphdr *iph, size_t len,
+- enum ip_conntrack_info conntrackinfo)
++ enum ip_conntrack_info ctinfo)
+ {
+ /* If we've seen traffic both ways, this is some kind of UDP
+ stream. Extend timeout. */
+ if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
+- ip_ct_refresh(conntrack, ip_ct_udp_timeout_stream);
++ ip_ct_refresh_acct(conntrack,ctinfo,iph,ip_ct_udp_timeout_stream);
+ /* Also, more likely to be important, and not a probe */
+ set_bit(IPS_ASSURED_BIT, &conntrack->status);
+ } else
+- ip_ct_refresh(conntrack, ip_ct_udp_timeout);
++ ip_ct_refresh_acct(conntrack,ctinfo,iph, ip_ct_udp_timeout);
+
+ return NF_ACCEPT;
+ }
+--- linux/net/ipv4/netfilter/ip_conntrack_standalone.c.org 2005-11-12 16:48:38.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_conntrack_standalone.c 2005-11-13 15:51:07.608347512 +0100
+@@ -79,6 +79,18 @@
+ return len;
+ }
+
++#if defined(CONFIG_IP_NF_CT_ACCT) || \
++ defined(CONFIG_IP_NF_CT_ACCT_MODULE)
++static unsigned int
++print_counters(char *buffer, struct ip_conntrack_counter *counter)
++{
++ return sprintf(buffer, "packets=%llu bytes=%llu ",
++ counter->packets, counter->bytes);
++}
++#else
++#define print_counters(x, y) 0
++#endif
++
+ static unsigned int
+ print_conntrack(char *buffer, struct ip_conntrack *conntrack)
+ {
+@@ -98,11 +110,15 @@
+ len += print_tuple(buffer + len,
+ &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
+ proto);
++ len += print_counters(buffer + len,
++ &conntrack->counters[IP_CT_DIR_ORIGINAL]);
+ if (!(test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)))
+ len += sprintf(buffer + len, "[UNREPLIED] ");
+ len += print_tuple(buffer + len,
+ &conntrack->tuplehash[IP_CT_DIR_REPLY].tuple,
+ proto);
++ len += print_counters(buffer + len,
++ &conntrack->counters[IP_CT_DIR_REPLY]);
+ if (test_bit(IPS_ASSURED_BIT, &conntrack->status))
+ len += sprintf(buffer + len, "[ASSURED] ");
+ len += sprintf(buffer + len, "use=%u ",
+@@ -478,7 +494,7 @@
+ EXPORT_SYMBOL(ip_conntrack_helper_register);
+ EXPORT_SYMBOL(ip_conntrack_helper_unregister);
+ EXPORT_SYMBOL(ip_ct_iterate_cleanup);
+-EXPORT_SYMBOL(ip_ct_refresh);
++EXPORT_SYMBOL(ip_ct_refresh_acct);
+ EXPORT_SYMBOL(ip_ct_find_proto);
+ EXPORT_SYMBOL(__ip_ct_find_proto);
+ EXPORT_SYMBOL(ip_ct_find_helper);
+--- linux/net/ipv4/netfilter/ip_conntrack_proto_generic.c.org 2003-11-28 19:26:21.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_conntrack_proto_generic.c 2005-11-13 15:44:20.734201784 +0100
+@@ -41,9 +41,9 @@
+ /* Returns verdict for packet, or -1 for invalid. */
+ static int established(struct ip_conntrack *conntrack,
+ struct iphdr *iph, size_t len,
+- enum ip_conntrack_info conntrackinfo)
++ enum ip_conntrack_info ctinfo)
+ {
+- ip_ct_refresh(conntrack, ip_ct_generic_timeout);
++ ip_ct_refresh_acct(conntrack, ctinfo,iph,ip_ct_generic_timeout);
+ return NF_ACCEPT;
+ }
+
+--- linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c.org 2003-11-28 19:26:21.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_conntrack_proto_icmp.c 2005-11-13 15:44:50.733641176 +0100
+@@ -82,7 +82,7 @@
+ ct->timeout.function((unsigned long)ct);
+ } else {
+ atomic_inc(&ct->proto.icmp.count);
+- ip_ct_refresh(ct, ip_ct_icmp_timeout);
++ ip_ct_refresh_acct(ct,ctinfo,iph, ip_ct_icmp_timeout);
+ }
+
+ return NF_ACCEPT;
+--- linux/net/ipv4/netfilter/ip_conntrack_core.c.org 2005-11-12 16:48:38.000000000 +0100
++++ linux/net/ipv4/netfilter/ip_conntrack_core.c 2005-11-13 15:43:23.882844504 +0100
+@@ -1196,22 +1196,40 @@
+
+ MOD_DEC_USE_COUNT;
+ }
++static inline void ct_add_counters(struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo,
++ const struct iphdr *iph)
++{
++#if defined(CONFIG_IP_NF_CT_ACCT) || \
++ defined(CONFIG_IP_NF_CT_ACCT_MODULE)
++ if (iph) {
++ ct->counters[CTINFO2DIR(ctinfo)].packets++;
++ ct->counters[CTINFO2DIR(ctinfo)].bytes +=
++ ntohs(iph->tot_len);
++ }
++#endif
++}
+
+ /* Refresh conntrack for this many jiffies. */
+-void ip_ct_refresh(struct ip_conntrack *ct, unsigned long extra_jiffies)
++void ip_ct_refresh_acct(struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo,
++ const struct iphdr *iph,
++ unsigned long extra_jiffies)
+ {
+ IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct);
+
+ WRITE_LOCK(&ip_conntrack_lock);
+ /* If not in hash table, timer will not be active yet */
+- if (!is_confirmed(ct))
++ if (!is_confirmed(ct)) {
+ ct->timeout.expires = extra_jiffies;
+- else {
++ ct_add_counters(ct, ctinfo,iph);
++ } else {
+ /* Need del_timer for race avoidance (may already be dying). */
+ if (del_timer(&ct->timeout)) {
+ ct->timeout.expires = jiffies + extra_jiffies;
+ add_timer(&ct->timeout);
+ }
++ ct_add_counters(ct, ctinfo, iph);
+ }
+ WRITE_UNLOCK(&ip_conntrack_lock);
+ }
+--- linux/include/linux/netfilter_ipv4/ip_conntrack.h.org 2005-11-12 16:48:38.000000000 +0100
++++ linux/include/linux/netfilter_ipv4/ip_conntrack.h 2005-11-13 15:39:04.000000000 +0100
+@@ -164,6 +164,12 @@
+ union ip_conntrack_expect_help help;
+ };
+
++struct ip_conntrack_counter
++{
++ u_int64_t packets;
++ u_int64_t bytes;
++};
++
+ struct ip_conntrack_helper;
+
+ struct ip_conntrack
+@@ -181,6 +187,12 @@
+ /* Timer function; drops refcnt when it goes off. */
+ struct timer_list timeout;
+
++#if defined(CONFIG_IP_NF_CT_ACCT) || \
++ defined(CONFIG_IP_NF_CT_ACCT_MODULE)
++ /* Accounting Information (same cache line as other written members) */
++ struct ip_conntrack_counter counters[IP_CT_DIR_MAX];
++#endif
++
+ /* If we're expecting another related connection, this will be
+ in expected linked list */
+ struct list_head sibling_list;
+@@ -264,8 +276,10 @@
+ const struct ip_conntrack_tuple *orig);
+
+ /* Refresh conntrack for this many jiffies */
+-extern void ip_ct_refresh(struct ip_conntrack *ct,
+- unsigned long extra_jiffies);
++extern void ip_ct_refresh_acct(struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo,
++ const struct iphdr *iph,
++ unsigned long extra_jiffies);
+
+ /* These are for NAT. Icky. */
+ /* Call me when a conntrack is destroyed. */
+--- linux/net/ipv4/netfilter/ipt_connbytes.c.org 1970-01-01 01:00:00.000000000 +0100
++++ linux/net/ipv4/netfilter/ipt_connbytes.c 2005-11-13 16:22:02.021433872 +0100
+@@ -0,0 +1,163 @@
++/* Kernel module to match connection tracking byte counter.
++ * GPL (C) 2002 Martin Devera (devik@cdi.cz).
++ *
++ * 2004-07-20 Harald Welte <laforge at netfilter.org>
++ * - reimplemented to use per-connection accounting counters
++ * - add functionality to match number of packets
++ * - add functionality to match average packet size
++ * - add support to match directions seperately
++ *
++ * 2004-10-24 Piotr Chytla <pch at fouk.org>
++ * - Connbytes with per-connection accouting backported to 2.4
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/types.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_connbytes.h>
++
++#include <asm/div64.h>
++
++static u_int64_t mydiv(u_int64_t arg1,u_int32_t arg2)
++{
++ do_div(arg1,arg2);
++ return arg1;
++}
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ const void *hdr,
++ u_int16_t datalen,
++ int *hotdrop)
++{
++ static u_int64_t what;
++ const struct ipt_connbytes_info *sinfo = matchinfo;
++ enum ip_conntrack_info ctinfo;
++ struct ip_conntrack *ct;
++
++ if (!(ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)))
++ return 0; /* no match */
++ switch (sinfo->what) {
++ case IPT_CONNBYTES_PKTS:
++ switch (sinfo->direction) {
++ case IPT_CONNBYTES_DIR_ORIGINAL:
++ what = ct->counters[IP_CT_DIR_ORIGINAL].packets;
++ break;
++ case IPT_CONNBYTES_DIR_REPLY:
++ what = ct->counters[IP_CT_DIR_REPLY].packets;
++ break;
++ case IPT_CONNBYTES_DIR_BOTH:
++ what = ct->counters[IP_CT_DIR_ORIGINAL].packets;
++ what += ct->counters[IP_CT_DIR_REPLY].packets;
++ break;
++ }
++ break;
++ case IPT_CONNBYTES_BYTES:
++ switch (sinfo->direction) {
++ case IPT_CONNBYTES_DIR_ORIGINAL:
++ what = ct->counters[IP_CT_DIR_ORIGINAL].bytes;
++ break;
++ case IPT_CONNBYTES_DIR_REPLY:
++ what = ct->counters[IP_CT_DIR_REPLY].bytes;
++ break;
++ case IPT_CONNBYTES_DIR_BOTH:
++ what = ct->counters[IP_CT_DIR_ORIGINAL].bytes;
++ what += ct->counters[IP_CT_DIR_REPLY].bytes;
++ break;
++ }
++ break;
++ case IPT_CONNBYTES_AVGPKT:
++ switch (sinfo->direction) {
++ case IPT_CONNBYTES_DIR_ORIGINAL:
++ {
++ u_int32_t pkts32;
++
++ if (ct->counters[IP_CT_DIR_ORIGINAL].packets > 0xfffffffff)
++ pkts32 = 0xffffffff;
++ else
++ pkts32 = ct->counters[IP_CT_DIR_ORIGINAL].packets;
++ what = mydiv(ct->counters[IP_CT_DIR_ORIGINAL].bytes,pkts32);
++ }
++ break;
++ case IPT_CONNBYTES_DIR_REPLY:
++ {
++ u_int32_t pkts32;
++
++ if (ct->counters[IP_CT_DIR_REPLY].packets > 0xffffffff)
++ pkts32 = 0xffffffff;
++ else
++ pkts32 = ct->counters[IP_CT_DIR_REPLY].packets;
++ what = mydiv(ct->counters[IP_CT_DIR_REPLY].bytes,pkts32);
++ }
++ break;
++ case IPT_CONNBYTES_DIR_BOTH:
++ {
++ u_int64_t bytes;
++ u_int64_t pkts;
++ u_int32_t pkts32;
++ bytes = ct->counters[IP_CT_DIR_ORIGINAL].bytes +
++ ct->counters[IP_CT_DIR_REPLY].bytes;
++ pkts = ct->counters[IP_CT_DIR_ORIGINAL].packets +
++ ct->counters[IP_CT_DIR_REPLY].packets;
++ if (pkts > 0xffffffff)
++ pkts32 = 0xffffffff;
++ else
++ pkts32 = pkts;
++ what = mydiv(bytes,pkts);
++ }
++ break;
++ }
++ break;
++ }
++ if (sinfo->count.to)
++ return (what <= sinfo->count.to && what >= sinfo->count.from);
++ else
++ return (what >= sinfo->count.from);
++}
++
++static int check(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ const struct ipt_connbytes_info *sinfo = matchinfo;
++
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_connbytes_info)))
++ return 0;
++ if (sinfo->what != IPT_CONNBYTES_PKTS &&
++ sinfo->what != IPT_CONNBYTES_BYTES &&
++ sinfo->what != IPT_CONNBYTES_AVGPKT)
++ return 0;
++
++ if (sinfo->direction != IPT_CONNBYTES_DIR_ORIGINAL &&
++ sinfo->direction != IPT_CONNBYTES_DIR_REPLY &&
++ sinfo->direction != IPT_CONNBYTES_DIR_BOTH)
++ return 0;
++
++ return 1;
++}
++
++static struct ipt_match state_match
++= { { NULL, NULL }, "connbytes", &match, &check, NULL, THIS_MODULE };
++
++static int __init init(void)
++{
++ return ipt_register_match(&state_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&state_match);
++}
++
++module_init(init);
++module_exit(fini);
++MODULE_LICENSE("GPL");
+--- linux/include/linux/netfilter_ipv4/ipt_connbytes.h.org 1970-01-01 01:00:00.000000000 +0100
++++ linux/include/linux/netfilter_ipv4/ipt_connbytes.h 2005-11-13 16:11:24.567341624 +0100
+@@ -0,0 +1,25 @@
++#ifndef _IPT_CONNBYTES_H
++#define _IPT_CONNBYTES_H
++enum ipt_connbytes_what {
++ IPT_CONNBYTES_PKTS,
++ IPT_CONNBYTES_BYTES,
++ IPT_CONNBYTES_AVGPKT,
++};
++
++enum ipt_connbytes_direction {
++ IPT_CONNBYTES_DIR_ORIGINAL,
++ IPT_CONNBYTES_DIR_REPLY,
++ IPT_CONNBYTES_DIR_BOTH,
++};
++
++struct ipt_connbytes_info
++{
++ struct {
++ u_int64_t from; /* count to be matched */
++ u_int64_t to; /* count to be matched */
++ } count;
++ u_int8_t what; /* ipt_connbytes_what */
++ u_int8_t direction; /* ipt_connbytes_direction */
++};
++
++#endif
+--- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_proto_gre.c 2006-02-04 19:16:25.000000000 +0100
++++ /home/florian//openwrt/trunk/openwrt/build_mipsel/linux/net/ipv4/netfilter/ip_conntrack_proto_gre.c 2006-02-04 18:19:08.000000000 +0100
+@@ -237,16 +237,16 @@
+ /* Returns verdict for packet, and may modify conntrack */
+ static int gre_packet(struct ip_conntrack *ct,
+ struct iphdr *iph, size_t len,
+- enum ip_conntrack_info conntrackinfo)
++ enum ip_conntrack_info ctinfo)
+ {
+ /* If we've seen traffic both ways, this is a GRE connection.
+ * Extend timeout. */
+ if (ct->status & IPS_SEEN_REPLY) {
+- ip_ct_refresh_acct(ct, ct->proto.gre.stream_timeout);
++ ip_ct_refresh_acct(ct, ctinfo, iph, ct->proto.gre.stream_timeout);
+ /* Also, more likely to be important, and not a probe. */
+ set_bit(IPS_ASSURED_BIT, &ct->status);
+ } else
+- ip_ct_refresh_acct(ct, ct->proto.gre.timeout);
++ ip_ct_refresh_acct(ct, ctinfo, iph, ct->proto.gre.timeout);
+
+ return NF_ACCEPT;
+ }
diff --git a/target/linux/generic-2.4/patches/611-netfilter_condition.patch b/target/linux/generic-2.4/patches/611-netfilter_condition.patch
new file mode 100644
index 0000000..6c16c29
--- /dev/null
+++ b/target/linux/generic-2.4/patches/611-netfilter_condition.patch
@@ -0,0 +1,625 @@
+diff -ruN linux-2.4.30-old/Documentation/Configure.help linux-2.4.30-new/Documentation/Configure.help
+--- linux-2.4.30-old/Documentation/Configure.help 2005-11-13 21:52:27.000000000 +0100
++++ linux-2.4.30-new/Documentation/Configure.help 2005-11-13 22:20:15.000000000 +0100
+@@ -2979,6 +2979,14 @@
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
++Condition variable match support
++CONFIG_IP_NF_MATCH_CONDITION
++ This option allows you to match firewall rules against condition
++ variables stored in the /proc/net/ipt_condition directory.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
+ conntrack match support
+ CONFIG_IP_NF_MATCH_CONNTRACK
+ This is a general conntrack match module, a superset of the state match.
+@@ -3354,6 +3362,14 @@
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
++Condition variable match support
++CONFIG_IP6_NF_MATCH_CONDITION
++ This option allows you to match firewall rules against condition
++ variables stored in the /proc/net/ipt_condition directory.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
+ Multiple port match support
+ CONFIG_IP6_NF_MATCH_MULTIPORT
+ Multiport matching allows you to match TCP or UDP packets based on
+diff -ruN linux-2.4.30-old/include/linux/netfilter_ipv4/ipt_condition.h linux-2.4.30-new/include/linux/netfilter_ipv4/ipt_condition.h
+--- linux-2.4.30-old/include/linux/netfilter_ipv4/ipt_condition.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.30-new/include/linux/netfilter_ipv4/ipt_condition.h 2005-11-13 22:20:14.000000000 +0100
+@@ -0,0 +1,11 @@
++#ifndef __IPT_CONDITION_MATCH__
++#define __IPT_CONDITION_MATCH__
++
++#define CONDITION_NAME_LEN 32
++
++struct condition_info {
++ char name[CONDITION_NAME_LEN];
++ int invert;
++};
++
++#endif
+diff -ruN linux-2.4.30-old/include/linux/netfilter_ipv6/ip6t_condition.h linux-2.4.30-new/include/linux/netfilter_ipv6/ip6t_condition.h
+--- linux-2.4.30-old/include/linux/netfilter_ipv6/ip6t_condition.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.30-new/include/linux/netfilter_ipv6/ip6t_condition.h 2005-11-13 22:20:14.000000000 +0100
+@@ -0,0 +1,11 @@
++#ifndef __IP6T_CONDITION_MATCH__
++#define __IP6T_CONDITION_MATCH__
++
++#define CONDITION6_NAME_LEN 32
++
++struct condition6_info {
++ char name[CONDITION6_NAME_LEN];
++ int invert;
++};
++
++#endif
+diff -ruN linux-2.4.30-old/net/ipv4/netfilter/Config.in linux-2.4.30-new/net/ipv4/netfilter/Config.in
+--- linux-2.4.30-old/net/ipv4/netfilter/Config.in 2005-11-13 21:52:27.000000000 +0100
++++ linux-2.4.30-new/net/ipv4/netfilter/Config.in 2005-11-13 22:20:15.000000000 +0100
+@@ -43,6 +43,7 @@
+ dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
++ dep_tristate ' condition match support' CONFIG_IP_NF_MATCH_CONDITION $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' peer to peer traffic match support' CONFIG_IP_NF_MATCH_IPP2P $CONFIG_IP_NF_IPTABLES
+diff -ruN linux-2.4.30-old/net/ipv4/netfilter/Makefile linux-2.4.30-new/net/ipv4/netfilter/Makefile
+--- linux-2.4.30-old/net/ipv4/netfilter/Makefile 2005-11-13 21:52:27.000000000 +0100
++++ linux-2.4.30-new/net/ipv4/netfilter/Makefile 2005-11-13 22:20:15.000000000 +0100
+@@ -94,6 +94,7 @@
+ obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
+ obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
+ obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
++obj-$(CONFIG_IP_NF_MATCH_CONDITION) += ipt_condition.o
+
+ obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
+
+diff -ruN linux-2.4.30-old/net/ipv4/netfilter/ipt_condition.c linux-2.4.30-new/net/ipv4/netfilter/ipt_condition.c
+--- linux-2.4.30-old/net/ipv4/netfilter/ipt_condition.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.30-new/net/ipv4/netfilter/ipt_condition.c 2005-11-13 22:20:14.000000000 +0100
+@@ -0,0 +1,256 @@
++/*-------------------------------------------*\
++| Netfilter Condition Module |
++| |
++| Description: This module allows firewall |
++| rules to match using condition variables |
++| stored in /proc files. |
++| |
++| Author: Stephane Ouellette 2002-10-22 |
++| <ouellettes@videotron.ca> |
++| |
++| History: |
++| 2003-02-10 Second version with improved |
++| locking and simplified code. |
++| |
++| This software is distributed under the |
++| terms of the GNU GPL. |
++\*-------------------------------------------*/
++
++#include<linux/module.h>
++#include<linux/proc_fs.h>
++#include<linux/spinlock.h>
++#include<linux/string.h>
++#include<asm/atomic.h>
++#include<linux/netfilter_ipv4/ip_tables.h>
++#include<linux/netfilter_ipv4/ipt_condition.h>
++
++
++#ifndef CONFIG_PROC_FS
++#error "Proc file system support is required for this module"
++#endif
++
++
++MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca>");
++MODULE_DESCRIPTION("Allows rules to match against condition variables");
++MODULE_LICENSE("GPL");
++
++
++struct condition_variable {
++ struct condition_variable *next;
++ struct proc_dir_entry *status_proc;
++ atomic_t refcount;
++ int enabled; /* TRUE == 1, FALSE == 0 */
++};
++
++
++static rwlock_t list_lock;
++static struct condition_variable *head = NULL;
++static struct proc_dir_entry *proc_net_condition = NULL;
++
++
++static int
++ipt_condition_read_info(char *buffer, char **start, off_t offset,
++ int length, int *eof, void *data)
++{
++ struct condition_variable *var =
++ (struct condition_variable *) data;
++
++ if (offset == 0) {
++ *start = buffer;
++ buffer[0] = (var->enabled) ? '1' : '0';
++ buffer[1] = '\n';
++ return 2;
++ }
++
++ *eof = 1;
++ return 0;
++}
++
++
++static int
++ipt_condition_write_info(struct file *file, const char *buffer,
++ unsigned long length, void *data)
++{
++ struct condition_variable *var =
++ (struct condition_variable *) data;
++
++ if (length) {
++ /* Match only on the first character */
++ switch (buffer[0]) {
++ case '0':
++ var->enabled = 0;
++ break;
++ case '1':
++ var->enabled = 1;
++ }
++ }
++
++ return (int) length;
++}
++
++
++static int
++match(const struct sk_buff *skb, const struct net_device *in,
++ const struct net_device *out, const void *matchinfo, int offset,
++ const void *hdr, u_int16_t datalen, int *hotdrop)
++{
++ const struct condition_info *info =
++ (const struct condition_info *) matchinfo;
++ struct condition_variable *var;
++ int condition_status = 0;
++
++ read_lock(&list_lock);
++
++ for (var = head; var; var = var->next) {
++ if (strcmp(info->name, var->status_proc->name) == 0) {
++ condition_status = var->enabled;
++ break;
++ }
++ }
++
++ read_unlock(&list_lock);
++
++ return condition_status ^ info->invert;
++}
++
++
++
++static int
++checkentry(const char *tablename, const struct ipt_ip *ip,
++ void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
++{
++ struct condition_info *info = (struct condition_info *) matchinfo;
++ struct condition_variable *var, *newvar;
++
++ if (matchsize != IPT_ALIGN(sizeof(struct condition_info)))
++ return 0;
++
++ /* The first step is to check if the condition variable already exists. */
++ /* Here, a read lock is sufficient because we won't change the list */
++ read_lock(&list_lock);
++
++ for (var = head; var; var = var->next) {
++ if (strcmp(info->name, var->status_proc->name) == 0) {
++ atomic_inc(&var->refcount);
++ read_unlock(&list_lock);
++ return 1;
++ }
++ }
++
++ read_unlock(&list_lock);
++
++ /* At this point, we need to allocate a new condition variable */
++ newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL);
++
++ if (!newvar)
++ return -ENOMEM;
++
++ /* Create the condition variable's proc file entry */
++ newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition);
++
++ if (!newvar->status_proc) {
++ /*
++ * There are two possibilities:
++ * 1- Another condition variable with the same name has been created, which is valid.
++ * 2- There was a memory allocation error.
++ */
++ kfree(newvar);
++ read_lock(&list_lock);
++
++ for (var = head; var; var = var->next) {
++ if (strcmp(info->name, var->status_proc->name) == 0) {
++ atomic_inc(&var->refcount);
++ read_unlock(&list_lock);
++ return 1;
++ }
++ }
++
++ read_unlock(&list_lock);
++ return -ENOMEM;
++ }
++
++ atomic_set(&newvar->refcount, 1);
++ newvar->enabled = 0;
++ newvar->status_proc->owner = THIS_MODULE;
++ newvar->status_proc->data = newvar;
++ wmb();
++ newvar->status_proc->read_proc = ipt_condition_read_info;
++ newvar->status_proc->write_proc = ipt_condition_write_info;
++
++ write_lock(&list_lock);
++
++ newvar->next = head;
++ head = newvar;
++
++ write_unlock(&list_lock);
++
++ return 1;
++}
++
++
++static void
++destroy(void *matchinfo, unsigned int matchsize)
++{
++ struct condition_info *info = (struct condition_info *) matchinfo;
++ struct condition_variable *var, *prev = NULL;
++
++ if (matchsize != IPT_ALIGN(sizeof(struct condition_info)))
++ return;
++
++ write_lock(&list_lock);
++
++ for (var = head; var && strcmp(info->name, var->status_proc->name);
++ prev = var, var = var->next);
++
++ if (var && atomic_dec_and_test(&var->refcount)) {
++ if (prev)
++ prev->next = var->next;
++ else
++ head = var->next;
++
++ write_unlock(&list_lock);
++ remove_proc_entry(var->status_proc->name, proc_net_condition);
++ kfree(var);
++ } else
++ write_unlock(&list_lock);
++}
++
++
++static struct ipt_match condition_match = {
++ .name = "condition",
++ .match = &match,
++ .checkentry = &checkentry,
++ .destroy = &destroy,
++ .me = THIS_MODULE
++};
++
++
++static int __init
++init(void)
++{
++ int errorcode;
++
++ rwlock_init(&list_lock);
++ proc_net_condition = proc_mkdir("ipt_condition", proc_net);
++
++ if (proc_net_condition) {
++ errorcode = ipt_register_match(&condition_match);
++
++ if (errorcode)
++ remove_proc_entry("ipt_condition", proc_net);
++ } else
++ errorcode = -EACCES;
++
++ return errorcode;
++}
++
++
++static void __exit
++fini(void)
++{
++ ipt_unregister_match(&condition_match);
++ remove_proc_entry("ipt_condition", proc_net);
++}
++
++module_init(init);
++module_exit(fini);
+diff -ruN linux-2.4.30-old/net/ipv6/netfilter/Config.in linux-2.4.30-new/net/ipv6/netfilter/Config.in
+--- linux-2.4.30-old/net/ipv6/netfilter/Config.in 2003-06-13 16:51:39.000000000 +0200
++++ linux-2.4.30-new/net/ipv6/netfilter/Config.in 2005-11-13 22:20:15.000000000 +0100
+@@ -17,6 +17,7 @@
+ if [ "$CONFIG_IP6_NF_IPTABLES" != "n" ]; then
+ # The simple matches.
+ dep_tristate ' limit match support' CONFIG_IP6_NF_MATCH_LIMIT $CONFIG_IP6_NF_IPTABLES
++ dep_tristate ' condition match support' CONFIG_IP6_NF_MATCH_CONDITION $CONFIG_IP6_NF_IPTABLES
+ dep_tristate ' MAC address match support' CONFIG_IP6_NF_MATCH_MAC $CONFIG_IP6_NF_IPTABLES
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' Routing header match support (EXPERIMENTAL)' CONFIG_IP6_NF_MATCH_RT $CONFIG_IP6_NF_IPTABLES
+diff -ruN linux-2.4.30-old/net/ipv6/netfilter/Makefile linux-2.4.30-new/net/ipv6/netfilter/Makefile
+--- linux-2.4.30-old/net/ipv6/netfilter/Makefile 2003-06-13 16:51:39.000000000 +0200
++++ linux-2.4.30-new/net/ipv6/netfilter/Makefile 2005-11-13 22:20:15.000000000 +0100
+@@ -14,6 +14,7 @@
+ # Link order matters here.
+ obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
+ obj-$(CONFIG_IP6_NF_MATCH_LIMIT) += ip6t_limit.o
++obj-$(CONFIG_IP6_NF_MATCH_CONDITION) += ip6t_condition.o
+ obj-$(CONFIG_IP6_NF_MATCH_MARK) += ip6t_mark.o
+ obj-$(CONFIG_IP6_NF_MATCH_LENGTH) += ip6t_length.o
+ obj-$(CONFIG_IP6_NF_MATCH_MAC) += ip6t_mac.o
+diff -ruN linux-2.4.30-old/net/ipv6/netfilter/ip6t_condition.c linux-2.4.30-new/net/ipv6/netfilter/ip6t_condition.c
+--- linux-2.4.30-old/net/ipv6/netfilter/ip6t_condition.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.30-new/net/ipv6/netfilter/ip6t_condition.c 2005-11-13 22:20:14.000000000 +0100
+@@ -0,0 +1,254 @@
++/*-------------------------------------------*\
++| Netfilter Condition Module for IPv6 |
++| |
++| Description: This module allows firewall |
++| rules to match using condition variables |
++| stored in /proc files. |
++| |
++| Author: Stephane Ouellette 2003-02-10 |
++| <ouellettes@videotron.ca> |
++| |
++| This software is distributed under the |
++| terms of the GNU GPL. |
++\*-------------------------------------------*/
++
++#include<linux/module.h>
++#include<linux/proc_fs.h>
++#include<linux/spinlock.h>
++#include<linux/string.h>
++#include<asm/atomic.h>
++#include<linux/netfilter_ipv6/ip6_tables.h>
++#include<linux/netfilter_ipv6/ip6t_condition.h>
++
++
++#ifndef CONFIG_PROC_FS
++#error "Proc file system support is required for this module"
++#endif
++
++
++MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca>");
++MODULE_DESCRIPTION("Allows rules to match against condition variables");
++MODULE_LICENSE("GPL");
++
++
++struct condition_variable {
++ struct condition_variable *next;
++ struct proc_dir_entry *status_proc;
++ atomic_t refcount;
++ int enabled; /* TRUE == 1, FALSE == 0 */
++};
++
++
++static rwlock_t list_lock;
++static struct condition_variable *head = NULL;
++static struct proc_dir_entry *proc_net_condition = NULL;
++
++
++static int
++ipt_condition_read_info(char *buffer, char **start, off_t offset,
++ int length, int *eof, void *data)
++{
++ struct condition_variable *var =
++ (struct condition_variable *) data;
++
++ if (offset == 0) {
++ *start = buffer;
++ buffer[0] = (var->enabled) ? '1' : '0';
++ buffer[1] = '\n';
++ return 2;
++ }
++
++ *eof = 1;
++ return 0;
++}
++
++
++static int
++ipt_condition_write_info(struct file *file, const char *buffer,
++ unsigned long length, void *data)
++{
++ struct condition_variable *var =
++ (struct condition_variable *) data;
++
++ if (length) {
++ /* Match only on the first character */
++ switch (buffer[0]) {
++ case '0':
++ var->enabled = 0;
++ break;
++ case '1':
++ var->enabled = 1;
++ }
++ }
++
++ return (int) length;
++}
++
++
++static int
++match(const struct sk_buff *skb, const struct net_device *in,
++ const struct net_device *out, const void *matchinfo, int offset,
++ const void *hdr, u_int16_t datalen, int *hotdrop)
++{
++ const struct condition6_info *info =
++ (const struct condition6_info *) matchinfo;
++ struct condition_variable *var;
++ int condition_status = 0;
++
++ read_lock(&list_lock);
++
++ for (var = head; var; var = var->next) {
++ if (strcmp(info->name, var->status_proc->name) == 0) {
++ condition_status = var->enabled;
++ break;
++ }
++ }
++
++ read_unlock(&list_lock);
++
++ return condition_status ^ info->invert;
++}
++
++
++
++static int
++checkentry(const char *tablename, const struct ip6t_ip6 *ip,
++ void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
++{
++ struct condition6_info *info =
++ (struct condition6_info *) matchinfo;
++ struct condition_variable *var, *newvar;
++
++ if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info)))
++ return 0;
++
++ /* The first step is to check if the condition variable already exists. */
++ /* Here, a read lock is sufficient because we won't change the list */
++ read_lock(&list_lock);
++
++ for (var = head; var; var = var->next) {
++ if (strcmp(info->name, var->status_proc->name) == 0) {
++ atomic_inc(&var->refcount);
++ read_unlock(&list_lock);
++ return 1;
++ }
++ }
++
++ read_unlock(&list_lock);
++
++ /* At this point, we need to allocate a new condition variable */
++ newvar = kmalloc(sizeof(struct condition_variable), GFP_KERNEL);
++
++ if (!newvar)
++ return -ENOMEM;
++
++ /* Create the condition variable's proc file entry */
++ newvar->status_proc = create_proc_entry(info->name, 0644, proc_net_condition);
++
++ if (!newvar->status_proc) {
++ /*
++ * There are two possibilities:
++ * 1- Another condition variable with the same name has been created, which is valid.
++ * 2- There was a memory allocation error.
++ */
++ kfree(newvar);
++ read_lock(&list_lock);
++
++ for (var = head; var; var = var->next) {
++ if (strcmp(info->name, var->status_proc->name) == 0) {
++ atomic_inc(&var->refcount);
++ read_unlock(&list_lock);
++ return 1;
++ }
++ }
++
++ read_unlock(&list_lock);
++ return -ENOMEM;
++ }
++
++ atomic_set(&newvar->refcount, 1);
++ newvar->enabled = 0;
++ newvar->status_proc->owner = THIS_MODULE;
++ newvar->status_proc->data = newvar;
++ wmb();
++ newvar->status_proc->read_proc = ipt_condition_read_info;
++ newvar->status_proc->write_proc = ipt_condition_write_info;
++
++ write_lock(&list_lock);
++
++ newvar->next = head;
++ head = newvar;
++
++ write_unlock(&list_lock);
++
++ return 1;
++}
++
++
++static void
++destroy(void *matchinfo, unsigned int matchsize)
++{
++ struct condition6_info *info =
++ (struct condition6_info *) matchinfo;
++ struct condition_variable *var, *prev = NULL;
++
++ if (matchsize != IP6T_ALIGN(sizeof(struct condition6_info)))
++ return;
++
++ write_lock(&list_lock);
++
++ for (var = head; var && strcmp(info->name, var->status_proc->name);
++ prev = var, var = var->next);
++
++ if (var && atomic_dec_and_test(&var->refcount)) {
++ if (prev)
++ prev->next = var->next;
++ else
++ head = var->next;
++
++ write_unlock(&list_lock);
++ remove_proc_entry(var->status_proc->name, proc_net_condition);
++ kfree(var);
++ } else
++ write_unlock(&list_lock);
++}
++
++
++static struct ip6t_match condition_match = {
++ .name = "condition",
++ .match = &match,
++ .checkentry = &checkentry,
++ .destroy = &destroy,
++ .me = THIS_MODULE
++};
++
++
++static int __init
++init(void)
++{
++ int errorcode;
++
++ rwlock_init(&list_lock);
++ proc_net_condition = proc_mkdir("ip6t_condition", proc_net);
++
++ if (proc_net_condition) {
++ errorcode = ipt_register_match(&condition_match);
++
++ if (errorcode)
++ remove_proc_entry("ip6t_condition", proc_net);
++ } else
++ errorcode = -EACCES;
++
++ return errorcode;
++}
++
++
++static void __exit
++fini(void)
++{
++ ipt_unregister_match(&condition_match);
++ remove_proc_entry("ip6t_condition", proc_net);
++}
++
++module_init(init);
++module_exit(fini);
diff --git a/target/linux/generic-2.4/patches/612-netfilter_quota.patch b/target/linux/generic-2.4/patches/612-netfilter_quota.patch
new file mode 100644
index 0000000..a0a019c
--- /dev/null
+++ b/target/linux/generic-2.4/patches/612-netfilter_quota.patch
@@ -0,0 +1,147 @@
+diff -ruN linux-2.4.30-old/Documentation/Configure.help linux-2.4.30-new/Documentation/Configure.help
+--- linux-2.4.30-old/Documentation/Configure.help 2005-11-13 22:30:42.000000000 +0100
++++ linux-2.4.30-new/Documentation/Configure.help 2005-11-13 22:31:17.000000000 +0100
+@@ -2888,6 +2888,13 @@
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
++quota match support
++CONFIG_IP_NF_MATCH_QUOTA
++ This match implements network quotas.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. If unsure, say `N'.
++
+ skb->pkt_type packet match support
+ CONFIG_IP_NF_MATCH_PKTTYPE
+ This patch allows you to match packet in accrodance
+diff -ruN linux-2.4.30-old/include/linux/netfilter_ipv4/ipt_quota.h linux-2.4.30-new/include/linux/netfilter_ipv4/ipt_quota.h
+--- linux-2.4.30-old/include/linux/netfilter_ipv4/ipt_quota.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.30-new/include/linux/netfilter_ipv4/ipt_quota.h 2005-11-13 22:31:17.000000000 +0100
+@@ -0,0 +1,12 @@
++#ifndef _IPT_QUOTA_H
++#define _IPT_QUOTA_H
++
++/* print debug info in both kernel/netfilter module & iptable library */
++//#define DEBUG_IPT_QUOTA
++
++struct ipt_quota_info {
++ u_int64_t quota;
++ struct ipt_quota_info *master;
++};
++
++#endif /*_IPT_QUOTA_H*/
+diff -ruN linux-2.4.30-old/net/ipv4/netfilter/Config.in linux-2.4.30-new/net/ipv4/netfilter/Config.in
+--- linux-2.4.30-old/net/ipv4/netfilter/Config.in 2005-11-13 22:30:42.000000000 +0100
++++ linux-2.4.30-new/net/ipv4/netfilter/Config.in 2005-11-13 22:31:17.000000000 +0100
+@@ -24,6 +24,7 @@
+ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; then
+ # The simple matches.
+ dep_tristate ' limit match support' CONFIG_IP_NF_MATCH_LIMIT $CONFIG_IP_NF_IPTABLES
++ dep_tristate ' quota match support' CONFIG_IP_NF_MATCH_QUOTA $CONFIG_IP_NF_IPTABLES
+
+ dep_tristate ' IP set support' CONFIG_IP_NF_SET $CONFIG_IP_NF_IPTABLES
+ if [ "$CONFIG_IP_NF_SET" != "n" ]; then
+diff -ruN linux-2.4.30-old/net/ipv4/netfilter/Makefile linux-2.4.30-new/net/ipv4/netfilter/Makefile
+--- linux-2.4.30-old/net/ipv4/netfilter/Makefile 2005-11-13 22:30:42.000000000 +0100
++++ linux-2.4.30-new/net/ipv4/netfilter/Makefile 2005-11-13 22:31:17.000000000 +0100
+@@ -74,6 +74,7 @@
+ # matches
+ obj-$(CONFIG_IP_NF_MATCH_HELPER) += ipt_helper.o
+ obj-$(CONFIG_IP_NF_MATCH_LIMIT) += ipt_limit.o
++obj-$(CONFIG_IP_NF_MATCH_QUOTA) += ipt_quota.o
+ obj-$(CONFIG_IP_NF_MATCH_MARK) += ipt_mark.o
+ obj-$(CONFIG_IP_NF_MATCH_SET) += ipt_set.o
+ obj-$(CONFIG_IP_NF_TARGET_SET) += ipt_SET.o
+diff -ruN linux-2.4.30-old/net/ipv4/netfilter/ipt_quota.c linux-2.4.30-new/net/ipv4/netfilter/ipt_quota.c
+--- linux-2.4.30-old/net/ipv4/netfilter/ipt_quota.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.30-new/net/ipv4/netfilter/ipt_quota.c 2005-11-13 22:31:17.000000000 +0100
+@@ -0,0 +1,88 @@
++/*
++ * netfilter module to enforce network quotas
++ *
++ * Sam Johnston <samj@samj.net>
++ *
++ * 30/01/05: Fixed on SMP --Pablo Neira <pablo@eurodev.net>
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_quota.h>
++
++MODULE_LICENSE("GPL");
++
++static spinlock_t quota_lock = SPIN_LOCK_UNLOCKED;
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset, const void *hdr, u_int16_t datalen, int *hotdrop)
++{
++ struct ipt_quota_info *q =
++ ((struct ipt_quota_info *) matchinfo)->master;
++
++ spin_lock_bh(&quota_lock);
++
++ if (q->quota >= datalen) {
++ /* we can afford this one */
++ q->quota -= datalen;
++ spin_unlock_bh(&quota_lock);
++
++#ifdef DEBUG_IPT_QUOTA
++ printk("IPT Quota OK: %llu datlen %d \n", q->quota, datalen);
++#endif
++ return 1;
++ }
++
++ /* so we do not allow even small packets from now on */
++ q->quota = 0;
++
++#ifdef DEBUG_IPT_QUOTA
++ printk("IPT Quota Failed: %llu datlen %d \n", q->quota, datalen);
++#endif
++
++ spin_unlock_bh(&quota_lock);
++ return 0;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
++{
++ /* TODO: spinlocks? sanity checks? */
++ struct ipt_quota_info *q = (struct ipt_quota_info *) matchinfo;
++
++ if (matchsize != IPT_ALIGN(sizeof (struct ipt_quota_info)))
++ return 0;
++
++ /* For SMP, we only want to use one set of counters. */
++ q->master = q;
++
++ return 1;
++}
++
++static struct ipt_match quota_match
++ = { {NULL, NULL}, "quota", &match, &checkentry, NULL, THIS_MODULE };
++
++static int __init
++init(void)
++{
++ return ipt_register_match(&quota_match);
++}
++
++static void __exit
++fini(void)
++{
++ ipt_unregister_match(&quota_match);
++}
++
++module_init(init);
++module_exit(fini);
++
diff --git a/target/linux/generic-2.4/patches/613-netfilter_nat_h323.patch b/target/linux/generic-2.4/patches/613-netfilter_nat_h323.patch
new file mode 100644
index 0000000..983d4fe
--- /dev/null
+++ b/target/linux/generic-2.4/patches/613-netfilter_nat_h323.patch
@@ -0,0 +1,821 @@
+diff -urN linux-2.4.32/net/ipv4/netfilter/Config.in linux-2.4.32.new/net/ipv4/netfilter/Config.in
+--- linux-2.4.32/net/ipv4/netfilter/Config.in 2006-03-01 00:49:36.652505800 +0100
++++ linux-2.4.32.new/net/ipv4/netfilter/Config.in 2006-03-01 00:50:18.692114808 +0100
+@@ -15,6 +15,7 @@
+ dep_tristate ' Connection byte counter support' CONFIG_IP_NF_MATCH_CONNBYTES $CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK
+ dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE
++ dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK
+ fi
+
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+@@ -111,6 +112,13 @@
+ define_tristate CONFIG_IP_NF_NAT_AMANDA $CONFIG_IP_NF_NAT
+ fi
+ fi
++ if [ "$CONFIG_IP_NF_H323" = "m" ]; then
++ define_tristate CONFIG_IP_NF_NAT_H323 m
++ else
++ if [ "$CONFIG_IP_NF_H323" = "y" ]; then
++ define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT
++ fi
++ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
+ fi
+diff -urN linux-2.4.32/net/ipv4/netfilter/Makefile linux-2.4.32.new/net/ipv4/netfilter/Makefile
+--- linux-2.4.32/net/ipv4/netfilter/Makefile 2006-03-01 00:49:36.654505496 +0100
++++ linux-2.4.32.new/net/ipv4/netfilter/Makefile 2006-03-01 00:50:18.693114656 +0100
+@@ -53,6 +53,10 @@
+ ifdef CONFIG_IP_NF_NAT_PPTP
+ export-objs += ip_conntrack_pptp.o
+ endif
++obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o
++ifdef CONFIG_IP_NF_NAT_H323
++ export-objs += ip_conntrack_h323.o
++endif
+
+
+ # NAT helpers
+@@ -62,6 +66,7 @@
+ obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
+ obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o
+ obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
++obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
+
+ # generic IP tables
+ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
+diff -urN linux-2.4.32/net/ipv4/netfilter/ip_conntrack_h323.c linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_h323.c
+--- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_h323.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_h323.c 2006-03-01 00:50:18.694114504 +0100
+@@ -0,0 +1,302 @@
++/*
++ * H.323 'brute force' extension for H.323 connection tracking.
++ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
++ * (http://www.coritel.it/projects/sofia/nat/)
++ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind'
++ * the unregistered helpers to the conntrack entries.
++ */
++
++
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <net/tcp.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ip_conntrack_core.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
++#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
++
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
++MODULE_LICENSE("GPL");
++
++DECLARE_LOCK(ip_h323_lock);
++struct module *ip_conntrack_h323 = THIS_MODULE;
++
++#define DEBUGP(format, args...)
++
++static int h245_help(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo)
++{
++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
++ unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
++ unsigned char *data_limit;
++ u_int32_t tcplen = len - iph->ihl * 4;
++ u_int32_t datalen = tcplen - tcph->doff * 4;
++ int dir = CTINFO2DIR(ctinfo);
++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
++ struct ip_conntrack_expect expect, *exp = &expect;
++ struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
++ u_int16_t data_port;
++ u_int32_t data_ip;
++ unsigned int i;
++
++ DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
++ NIPQUAD(iph->saddr), ntohs(tcph->source),
++ NIPQUAD(iph->daddr), ntohs(tcph->dest));
++
++ /* Can't track connections formed before we registered */
++ if (!info)
++ return NF_ACCEPT;
++
++ /* Until there's been traffic both ways, don't look in packets. */
++ if (ctinfo != IP_CT_ESTABLISHED
++ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
++ DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo);
++ return NF_ACCEPT;
++ }
++
++ /* Not whole TCP header or too short packet? */
++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
++ DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen);
++ return NF_ACCEPT;
++ }
++
++ /* Checksum invalid? Ignore. */
++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++ csum_partial((char *)tcph, tcplen, 0))) {
++ DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
++ tcph, tcplen, NIPQUAD(iph->saddr),
++ NIPQUAD(iph->daddr));
++ return NF_ACCEPT;
++ }
++
++ data_limit = (unsigned char *) data + datalen;
++ /* bytes: 0123 45
++ ipadrr port */
++ for (i = 0; data < (data_limit - 5); data++, i++) {
++ memcpy(&data_ip, data, sizeof(u_int32_t));
++ if (data_ip == iph->saddr) {
++ memcpy(&data_port, data + 4, sizeof(u_int16_t));
++ memset(&expect, 0, sizeof(expect));
++ /* update the H.225 info */
++ DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n",
++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
++ NIPQUAD(iph->saddr), ntohs(data_port));
++ LOCK_BH(&ip_h323_lock);
++ info->is_h225 = H225_PORT + 1;
++ exp_info->port = data_port;
++ exp_info->dir = dir;
++ exp_info->offset = i;
++
++ exp->seq = ntohl(tcph->seq) + i;
++
++ exp->tuple = ((struct ip_conntrack_tuple)
++ { { ct->tuplehash[!dir].tuple.src.ip,
++ { 0 } },
++ { data_ip,
++ { data_port },
++ IPPROTO_UDP }});
++ exp->mask = ((struct ip_conntrack_tuple)
++ { { 0xFFFFFFFF, { 0 } },
++ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
++
++ exp->expectfn = NULL;
++
++ /* Ignore failure; should only happen with NAT */
++ ip_conntrack_expect_related(ct, exp);
++
++ UNLOCK_BH(&ip_h323_lock);
++ }
++ }
++
++ return NF_ACCEPT;
++
++}
++
++/* H.245 helper is not registered! */
++static struct ip_conntrack_helper h245 =
++ { { NULL, NULL },
++ "H.245", /* name */
++ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
++ NULL, /* module */
++ 8, /* max_ expected */
++ 240, /* timeout */
++ { { 0, { 0 } }, /* tuple */
++ { 0, { 0 }, IPPROTO_TCP } },
++ { { 0, { 0xFFFF } }, /* mask */
++ { 0, { 0 }, 0xFFFF } },
++ h245_help /* helper */
++ };
++
++static int h225_expect(struct ip_conntrack *ct)
++{
++ WRITE_LOCK(&ip_conntrack_lock);
++ ct->helper = &h245;
++ DEBUGP("h225_expect: helper for %p added\n", ct);
++ WRITE_UNLOCK(&ip_conntrack_lock);
++
++ return NF_ACCEPT; /* unused */
++}
++
++static int h225_help(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo)
++{
++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
++ unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
++ unsigned char *data_limit;
++ u_int32_t tcplen = len - iph->ihl * 4;
++ u_int32_t datalen = tcplen - tcph->doff * 4;
++ int dir = CTINFO2DIR(ctinfo);
++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
++ struct ip_conntrack_expect expect, *exp = &expect;
++ struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info;
++ u_int16_t data_port;
++ u_int32_t data_ip;
++ unsigned int i;
++
++ DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
++ NIPQUAD(iph->saddr), ntohs(tcph->source),
++ NIPQUAD(iph->daddr), ntohs(tcph->dest));
++
++ /* Can't track connections formed before we registered */
++ if (!info)
++ return NF_ACCEPT;
++
++ /* Until there's been traffic both ways, don't look in packets. */
++ if (ctinfo != IP_CT_ESTABLISHED
++ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
++ DEBUGP("ct_h225_help: Conntrackinfo = %u\n", ctinfo);
++ return NF_ACCEPT;
++ }
++
++ /* Not whole TCP header or too short packet? */
++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) {
++ DEBUGP("ct_h225_help: tcplen = %u\n", (unsigned)tcplen);
++ return NF_ACCEPT;
++ }
++
++ /* Checksum invalid? Ignore. */
++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++ csum_partial((char *)tcph, tcplen, 0))) {
++ DEBUGP("ct_h225_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
++ tcph, tcplen, NIPQUAD(iph->saddr),
++ NIPQUAD(iph->daddr));
++ return NF_ACCEPT;
++ }
++
++ data_limit = (unsigned char *) data + datalen;
++ /* bytes: 0123 45
++ ipadrr port */
++ for (i = 0; data < (data_limit - 5); data++, i++) {
++ memcpy(&data_ip, data, sizeof(u_int32_t));
++ if (data_ip == iph->saddr) {
++ memcpy(&data_port, data + 4, sizeof(u_int16_t));
++ if (data_port == tcph->source) {
++ /* Signal address */
++ DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n",
++ NIPQUAD(iph->saddr));
++ /* Update the H.225 info so that NAT can mangle the address/port
++ even when we have no expected connection! */
++#ifdef CONFIG_IP_NF_NAT_NEEDED
++ LOCK_BH(&ip_h323_lock);
++ info->dir = dir;
++ info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i;
++ info->offset[IP_CT_DIR_ORIGINAL] = i;
++ UNLOCK_BH(&ip_h323_lock);
++#endif
++ } else {
++ memset(&expect, 0, sizeof(expect));
++
++ /* update the H.225 info */
++ LOCK_BH(&ip_h323_lock);
++ info->is_h225 = H225_PORT;
++ exp_info->port = data_port;
++ exp_info->dir = dir;
++ exp_info->offset = i;
++
++ exp->seq = ntohl(tcph->seq) + i;
++
++ exp->tuple = ((struct ip_conntrack_tuple)
++ { { ct->tuplehash[!dir].tuple.src.ip,
++ { 0 } },
++ { data_ip,
++ { data_port },
++ IPPROTO_TCP }});
++ exp->mask = ((struct ip_conntrack_tuple)
++ { { 0xFFFFFFFF, { 0 } },
++ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
++
++ exp->expectfn = h225_expect;
++
++ /* Ignore failure */
++ ip_conntrack_expect_related(ct, exp);
++
++ DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n",
++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
++ NIPQUAD(iph->saddr), ntohs(data_port));
++
++ UNLOCK_BH(&ip_h323_lock);
++ }
++#ifdef CONFIG_IP_NF_NAT_NEEDED
++ } else if (data_ip == iph->daddr) {
++ memcpy(&data_port, data + 4, sizeof(u_int16_t));
++ if (data_port == tcph->dest) {
++ /* Signal address */
++ DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n",
++ NIPQUAD(iph->daddr));
++ /* Update the H.225 info so that NAT can mangle the address/port
++ even when we have no expected connection! */
++ LOCK_BH(&ip_h323_lock);
++ info->dir = dir;
++ info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i;
++ info->offset[IP_CT_DIR_REPLY] = i;
++ UNLOCK_BH(&ip_h323_lock);
++ }
++#endif
++ }
++ }
++
++ return NF_ACCEPT;
++
++}
++
++static struct ip_conntrack_helper h225 =
++ { { NULL, NULL },
++ "H.225", /* name */
++ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
++ THIS_MODULE, /* module */
++ 2, /* max_expected */
++ 240, /* timeout */
++ { { 0, { __constant_htons(H225_PORT) } }, /* tuple */
++ { 0, { 0 }, IPPROTO_TCP } },
++ { { 0, { 0xFFFF } }, /* mask */
++ { 0, { 0 }, 0xFFFF } },
++ h225_help /* helper */
++ };
++
++static int __init init(void)
++{
++ return ip_conntrack_helper_register(&h225);
++}
++
++static void __exit fini(void)
++{
++ /* Unregister H.225 helper */
++ ip_conntrack_helper_unregister(&h225);
++}
++
++#ifdef CONFIG_IP_NF_NAT_NEEDED
++EXPORT_SYMBOL(ip_h323_lock);
++#endif
++
++module_init(init);
++module_exit(fini);
+diff -urN linux-2.4.32/net/ipv4/netfilter/ip_nat_h323.c linux-2.4.32.new/net/ipv4/netfilter/ip_nat_h323.c
+--- linux-2.4.32/net/ipv4/netfilter/ip_nat_h323.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32.new/net/ipv4/netfilter/ip_nat_h323.c 2006-03-01 00:50:18.698113896 +0100
+@@ -0,0 +1,403 @@
++/*
++ * H.323 'brute force' extension for NAT alteration.
++ * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
++ * (http://www.coritel.it/projects/sofia/nat.html)
++ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind'
++ * the unregistered helpers to the conntrack entries.
++ */
++
++
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <net/tcp.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_helper.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
++
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
++MODULE_LICENSE("GPL");
++
++DECLARE_LOCK_EXTERN(ip_h323_lock);
++struct module *ip_nat_h323 = THIS_MODULE;
++
++#define DEBUGP(format, args...)
++
++
++static unsigned int
++h225_nat_expected(struct sk_buff **pskb,
++ unsigned int hooknum,
++ struct ip_conntrack *ct,
++ struct ip_nat_info *info);
++
++static unsigned int h225_nat_help(struct ip_conntrack *ct,
++ struct ip_conntrack_expect *exp,
++ struct ip_nat_info *info,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum,
++ struct sk_buff **pskb);
++
++static struct ip_nat_helper h245 =
++ { { NULL, NULL },
++ "H.245", /* name */
++ 0, /* flags */
++ NULL, /* module */
++ { { 0, { 0 } }, /* tuple */
++ { 0, { 0 }, IPPROTO_TCP } },
++ { { 0, { 0xFFFF } }, /* mask */
++ { 0, { 0 }, 0xFFFF } },
++ h225_nat_help, /* helper */
++ h225_nat_expected /* expectfn */
++ };
++
++static unsigned int
++h225_nat_expected(struct sk_buff **pskb,
++ unsigned int hooknum,
++ struct ip_conntrack *ct,
++ struct ip_nat_info *info)
++{
++ struct ip_nat_multi_range mr;
++ u_int32_t newdstip, newsrcip, newip;
++ u_int16_t port;
++ struct ip_ct_h225_expect *exp_info;
++ struct ip_ct_h225_master *master_info;
++ struct ip_conntrack *master = master_ct(ct);
++ unsigned int is_h225, ret;
++
++ IP_NF_ASSERT(info);
++ IP_NF_ASSERT(master);
++
++ IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
++
++ DEBUGP("h225_nat_expected: We have a connection!\n");
++ master_info = &ct->master->expectant->help.ct_h225_info;
++ exp_info = &ct->master->help.exp_h225_info;
++
++ LOCK_BH(&ip_h323_lock);
++
++ DEBUGP("master: ");
++ DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++ DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple);
++ DEBUGP("conntrack: ");
++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++ if (exp_info->dir == IP_CT_DIR_ORIGINAL) {
++ /* Make connection go to the client. */
++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
++ DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n",
++ NIPQUAD(newsrcip), NIPQUAD(newdstip));
++ } else {
++ /* Make the connection go to the server */
++ newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
++ newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n",
++ NIPQUAD(newsrcip), NIPQUAD(newdstip));
++ }
++ port = exp_info->port;
++ is_h225 = master_info->is_h225 == H225_PORT;
++ UNLOCK_BH(&ip_h323_lock);
++
++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
++ newip = newsrcip;
++ else
++ newip = newdstip;
++
++ DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
++
++ mr.rangesize = 1;
++ /* We don't want to manip the per-protocol, just the IPs... */
++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
++ mr.range[0].min_ip = mr.range[0].max_ip = newip;
++
++ /* ... unless we're doing a MANIP_DST, in which case, make
++ sure we map to the correct port */
++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
++ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
++ mr.range[0].min = mr.range[0].max
++ = ((union ip_conntrack_manip_proto)
++ { port });
++ }
++
++ ret = ip_nat_setup_info(ct, &mr, hooknum);
++
++ if (is_h225) {
++ DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct);
++ /* NAT expectfn called with ip_nat_lock write-locked */
++ info->helper = &h245;
++ }
++ return ret;
++}
++
++static int h323_signal_address_fixup(struct ip_conntrack *ct,
++ struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo)
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *)iph + iph->ihl*4;
++ unsigned char *data;
++ u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
++ u_int32_t datalen = tcplen - tcph->doff*4;
++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info;
++ u_int32_t newip;
++ u_int16_t port;
++ u_int8_t buffer[6];
++ int i;
++
++ MUST_BE_LOCKED(&ip_h323_lock);
++
++ DEBUGP("h323_signal_address_fixup: %s %s\n",
++ between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
++ ? "yes" : "no",
++ between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
++ ? "yes" : "no");
++ if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)
++ || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen)))
++ return 1;
++
++ DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n",
++ info->offset[IP_CT_DIR_ORIGINAL],
++ info->offset[IP_CT_DIR_REPLY],
++ tcplen);
++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
++
++ for (i = 0; i < IP_CT_DIR_MAX; i++) {
++ DEBUGP("h323_signal_address_fixup: %s %s\n",
++ info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply",
++ i == IP_CT_DIR_ORIGINAL ? "caller" : "callee");
++ if (!between(info->seq[i], ntohl(tcph->seq),
++ ntohl(tcph->seq) + datalen))
++ continue;
++ if (!between(info->seq[i] + 6, ntohl(tcph->seq),
++ ntohl(tcph->seq) + datalen)) {
++ /* Partial retransmisison. It's a cracker being funky. */
++ if (net_ratelimit()) {
++ printk("H.323_NAT: partial packet %u/6 in %u/%u\n",
++ info->seq[i],
++ ntohl(tcph->seq),
++ ntohl(tcph->seq) + datalen);
++ }
++ return 0;
++ }
++
++ /* Change address inside packet to match way we're mapping
++ this connection. */
++ if (i == IP_CT_DIR_ORIGINAL) {
++ newip = ct->tuplehash[!info->dir].tuple.dst.ip;
++ port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port;
++ } else {
++ newip = ct->tuplehash[!info->dir].tuple.src.ip;
++ port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port;
++ }
++
++ data = (char *) tcph + tcph->doff * 4 + info->offset[i];
++
++ DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n",
++ i == IP_CT_DIR_ORIGINAL ? "source" : "dest ",
++ data[0], data[1], data[2], data[3],
++ (data[4] << 8 | data[5]));
++
++ /* Modify the packet */
++ memcpy(buffer, &newip, 4);
++ memcpy(buffer + 4, &port, 2);
++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset[i],
++ 6, buffer, 6))
++ return 0;
++
++ DEBUGP("h323_signal_address_fixup: new %s IP:port %u.%u.%u.%u:%u\n",
++ i == IP_CT_DIR_ORIGINAL ? "source" : "dest ",
++ data[0], data[1], data[2], data[3],
++ (data[4] << 8 | data[5]));
++ }
++
++ return 1;
++}
++
++static int h323_data_fixup(struct ip_ct_h225_expect *info,
++ struct ip_conntrack *ct,
++ struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect *expect)
++{
++ u_int32_t newip;
++ u_int16_t port;
++ u_int8_t buffer[6];
++ struct ip_conntrack_tuple newtuple;
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *)iph + iph->ihl*4;
++ unsigned char *data;
++ u_int32_t tcplen = (*pskb)->len - iph->ihl*4;
++ struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info;
++ int is_h225;
++
++ MUST_BE_LOCKED(&ip_h323_lock);
++ DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen);
++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
++
++ if (!between(expect->seq + 6, ntohl(tcph->seq),
++ ntohl(tcph->seq) + tcplen - tcph->doff * 4)) {
++ /* Partial retransmisison. It's a cracker being funky. */
++ if (net_ratelimit()) {
++ printk("H.323_NAT: partial packet %u/6 in %u/%u\n",
++ expect->seq,
++ ntohl(tcph->seq),
++ ntohl(tcph->seq) + tcplen - tcph->doff * 4);
++ }
++ return 0;
++ }
++
++ /* Change address inside packet to match way we're mapping
++ this connection. */
++ if (info->dir == IP_CT_DIR_REPLY) {
++ /* Must be where client thinks server is */
++ newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
++ /* Expect something from client->server */
++ newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
++ } else {
++ /* Must be where server thinks client is */
++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ /* Expect something from server->client */
++ newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
++ newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ }
++
++ is_h225 = (master_info->is_h225 == H225_PORT);
++
++ if (is_h225) {
++ newtuple.dst.protonum = IPPROTO_TCP;
++ newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port;
++ } else {
++ newtuple.dst.protonum = IPPROTO_UDP;
++ newtuple.src.u.udp.port = expect->tuple.src.u.udp.port;
++ }
++
++ /* Try to get same port: if not, try to change it. */
++ for (port = ntohs(info->port); port != 0; port++) {
++ if (is_h225)
++ newtuple.dst.u.tcp.port = htons(port);
++ else
++ newtuple.dst.u.udp.port = htons(port);
++
++ if (ip_conntrack_change_expect(expect, &newtuple) == 0)
++ break;
++ }
++ if (port == 0) {
++ DEBUGP("h323_data_fixup: no free port found!\n");
++ return 0;
++ }
++
++ port = htons(port);
++
++ data = (char *) tcph + tcph->doff * 4 + info->offset;
++
++ DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n",
++ data[0], data[1], data[2], data[3],
++ (data[4] << 8 | data[5]));
++
++ /* Modify the packet */
++ memcpy(buffer, &newip, 4);
++ memcpy(buffer + 4, &port, 2);
++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset,
++ 6, buffer, 6))
++ return 0;
++
++ DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n",
++ data[0], data[1], data[2], data[3],
++ (data[4] << 8 | data[5]));
++
++ return 1;
++}
++
++static unsigned int h225_nat_help(struct ip_conntrack *ct,
++ struct ip_conntrack_expect *exp,
++ struct ip_nat_info *info,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum,
++ struct sk_buff **pskb)
++{
++ int dir;
++ struct ip_ct_h225_expect *exp_info;
++
++ /* Only mangle things once: original direction in POST_ROUTING
++ and reply direction on PRE_ROUTING. */
++ dir = CTINFO2DIR(ctinfo);
++ DEBUGP("nat_h323: dir %s at hook %s\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
++ DEBUGP("nat_h323: Not touching dir %s at hook %s\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
++ return NF_ACCEPT;
++ }
++
++ if (!exp) {
++ LOCK_BH(&ip_h323_lock);
++ if (!h323_signal_address_fixup(ct, pskb, ctinfo)) {
++ UNLOCK_BH(&ip_h323_lock);
++ return NF_DROP;
++ }
++ UNLOCK_BH(&ip_h323_lock);
++ return NF_ACCEPT;
++ }
++
++ exp_info = &exp->help.exp_h225_info;
++
++ LOCK_BH(&ip_h323_lock);
++ if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) {
++ UNLOCK_BH(&ip_h323_lock);
++ return NF_DROP;
++ }
++ UNLOCK_BH(&ip_h323_lock);
++
++ return NF_ACCEPT;
++}
++
++static struct ip_nat_helper h225 =
++ { { NULL, NULL },
++ "H.225", /* name */
++ IP_NAT_HELPER_F_ALWAYS, /* flags */
++ THIS_MODULE, /* module */
++ { { 0, { __constant_htons(H225_PORT) } }, /* tuple */
++ { 0, { 0 }, IPPROTO_TCP } },
++ { { 0, { 0xFFFF } }, /* mask */
++ { 0, { 0 }, 0xFFFF } },
++ h225_nat_help, /* helper */
++ h225_nat_expected /* expectfn */
++ };
++
++static int __init init(void)
++{
++ int ret;
++
++ ret = ip_nat_helper_register(&h225);
++
++ if (ret != 0)
++ printk("ip_nat_h323: cannot initialize the module!\n");
++
++ return ret;
++}
++
++static void __exit fini(void)
++{
++ ip_nat_helper_unregister(&h225);
++}
++
++module_init(init);
++module_exit(fini);
+diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack.h
+--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h 2006-03-01 00:49:36.474532856 +0100
++++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-03-01 00:50:18.699113744 +0100
+@@ -71,6 +71,7 @@
+ #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_h323.h>
+
+ /* per expectation: application helper private data */
+ union ip_conntrack_expect_help {
+@@ -79,6 +80,7 @@
+ struct ip_ct_ftp_expect exp_ftp_info;
+ struct ip_ct_irc_expect exp_irc_info;
+ struct ip_ct_pptp_expect exp_pptp_info;
++ struct ip_ct_h225_expect exp_h225_info;
+
+ #ifdef CONFIG_IP_NF_NAT_NEEDED
+ union {
+@@ -93,6 +95,7 @@
+ struct ip_ct_ftp_master ct_ftp_info;
+ struct ip_ct_irc_master ct_irc_info;
+ struct ip_ct_pptp_master ct_pptp_info;
++ struct ip_ct_h225_master ct_h225_info;
+ };
+
+ #ifdef CONFIG_IP_NF_NAT_NEEDED
+diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_h323.h linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_h323.h
+--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_h323.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_h323.h 2006-03-01 00:50:18.700113592 +0100
+@@ -0,0 +1,30 @@
++#ifndef _IP_CONNTRACK_H323_H
++#define _IP_CONNTRACK_H323_H
++/* H.323 connection tracking. */
++
++#ifdef __KERNEL__
++/* Protects H.323 related data */
++DECLARE_LOCK_EXTERN(ip_h323_lock);
++#endif
++
++/* Default H.225 port */
++#define H225_PORT 1720
++
++/* This structure is per expected connection */
++struct ip_ct_h225_expect {
++ u_int16_t port; /* Port of the H.225 helper/RTCP/RTP channel */
++ enum ip_conntrack_dir dir; /* Direction of the original connection */
++ unsigned int offset; /* offset of the address in the payload */
++};
++
++/* This structure exists only once per master */
++struct ip_ct_h225_master {
++ int is_h225; /* H.225 or H.245 connection */
++#ifdef CONFIG_IP_NF_NAT_NEEDED
++ enum ip_conntrack_dir dir; /* Direction of the original connection */
++ u_int32_t seq[IP_CT_DIR_MAX]; /* Exceptional packet mangling for signal addressess... */
++ unsigned int offset[IP_CT_DIR_MAX]; /* ...and the offset of the addresses in the payload */
++#endif
++};
++
++#endif /* _IP_CONNTRACK_H323_H */
diff --git a/target/linux/generic-2.4/patches/614-netfilter_nat_rtsp.patch b/target/linux/generic-2.4/patches/614-netfilter_nat_rtsp.patch
new file mode 100644
index 0000000..6ae3e7b
--- /dev/null
+++ b/target/linux/generic-2.4/patches/614-netfilter_nat_rtsp.patch
@@ -0,0 +1,1523 @@
+diff -urN linux-2.4.32/net/ipv4/netfilter/Config.in linux-2.4.32.new/net/ipv4/netfilter/Config.in
+--- linux-2.4.32/net/ipv4/netfilter/Config.in 2006-03-01 00:53:57.884792456 +0100
++++ linux-2.4.32.new/net/ipv4/netfilter/Config.in 2006-03-01 00:55:14.462150928 +0100
+@@ -16,6 +16,7 @@
+ dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK
+ dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE
+ dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK
++ dep_tristate ' RTSP protocol support' CONFIG_IP_NF_RTSP $CONFIG_IP_NF_CONNTRACK
+ fi
+
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+@@ -119,6 +120,13 @@
+ define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT
+ fi
+ fi
++ if [ "$CONFIG_IP_NF_RTSP" = "m" ]; then
++ define_tristate CONFIG_IP_NF_NAT_RTSP m
++ else
++ if [ "$CONFIG_IP_NF_RTSP" = "y" ]; then
++ define_tristate CONFIG_IP_NF_NAT_RTSP $CONFIG_IP_NF_NAT
++ fi
++ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
+ fi
+diff -urN linux-2.4.32/net/ipv4/netfilter/Makefile linux-2.4.32.new/net/ipv4/netfilter/Makefile
+--- linux-2.4.32/net/ipv4/netfilter/Makefile 2006-03-01 00:53:57.886792152 +0100
++++ linux-2.4.32.new/net/ipv4/netfilter/Makefile 2006-03-01 00:55:14.463150776 +0100
+@@ -57,6 +57,11 @@
+ ifdef CONFIG_IP_NF_NAT_H323
+ export-objs += ip_conntrack_h323.o
+ endif
++obj-$(CONFIG_IP_NF_RTSP) += ip_conntrack_rtsp.o
++ifdef CONFIG_IP_NF_NAT_RTSP
++ export-objs += ip_conntrack_rtsp.o
++endif
++
+
+
+ # NAT helpers
+@@ -67,6 +72,7 @@
+ obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o
+ obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
+ obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
++obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.o
+
+ # generic IP tables
+ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
+diff -urN linux-2.4.32/net/ipv4/netfilter/ip_conntrack_rtsp.c linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_rtsp.c
+--- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_rtsp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_rtsp.c 2006-03-01 00:55:14.465150472 +0100
+@@ -0,0 +1,507 @@
++/*
++ * RTSP extension for IP connection tracking
++ * (C) 2003 by Tom Marshall <tmarshall@real.com>
++ * based on ip_conntrack_irc.c
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Module load syntax:
++ * insmod ip_conntrack_rtsp.o ports=port1,port2,...port<MAX_PORTS>
++ * max_outstanding=n setup_timeout=secs
++ *
++ * If no ports are specified, the default will be port 554.
++ *
++ * With max_outstanding you can define the maximum number of not yet
++ * answered SETUP requests per RTSP session (default 8).
++ * With setup_timeout you can specify how long the system waits for
++ * an expected data channel (default 300 seconds).
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <net/tcp.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
++
++#include <linux/ctype.h>
++#define NF_NEED_STRNCASECMP
++#define NF_NEED_STRTOU16
++#define NF_NEED_STRTOU32
++#define NF_NEED_NEXTLINE
++#include <linux/netfilter_helpers.h>
++#define NF_NEED_MIME_NEXTLINE
++#include <linux/netfilter_mime.h>
++
++#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */
++
++#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
++#ifdef IP_NF_RTSP_DEBUG
++#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
++#else
++#define DEBUGP(fmt, args...)
++#endif
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int num_ports = 0;
++static int max_outstanding = 8;
++static unsigned int setup_timeout = 300;
++
++MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>");
++MODULE_DESCRIPTION("RTSP connection tracking module");
++MODULE_LICENSE("GPL");
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++MODULE_PARM_DESC(ports, "port numbers of RTSP servers");
++MODULE_PARM(max_outstanding, "i");
++MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session");
++MODULE_PARM(setup_timeout, "i");
++MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels");
++#endif
++
++DECLARE_LOCK(ip_rtsp_lock);
++struct module* ip_conntrack_rtsp = THIS_MODULE;
++
++/*
++ * Max mappings we will allow for one RTSP connection (for RTP, the number
++ * of allocated ports is twice this value). Note that SMIL burns a lot of
++ * ports so keep this reasonably high. If this is too low, you will see a
++ * lot of "no free client map entries" messages.
++ */
++#define MAX_PORT_MAPS 16
++
++/*** default port list was here in the masq code: 554, 3030, 4040 ***/
++
++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
++
++/*
++ * Parse an RTSP packet.
++ *
++ * Returns zero if parsing failed.
++ *
++ * Parameters:
++ * IN ptcp tcp data pointer
++ * IN tcplen tcp data len
++ * IN/OUT ptcpoff points to current tcp offset
++ * OUT phdrsoff set to offset of rtsp headers
++ * OUT phdrslen set to length of rtsp headers
++ * OUT pcseqoff set to offset of CSeq header
++ * OUT pcseqlen set to length of CSeq header
++ */
++static int
++rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff,
++ uint* phdrsoff, uint* phdrslen,
++ uint* pcseqoff, uint* pcseqlen)
++{
++ uint entitylen = 0;
++ uint lineoff;
++ uint linelen;
++
++ if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
++ {
++ return 0;
++ }
++
++ *phdrsoff = *ptcpoff;
++ while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
++ {
++ if (linelen == 0)
++ {
++ if (entitylen > 0)
++ {
++ *ptcpoff += min(entitylen, tcplen - *ptcpoff);
++ }
++ break;
++ }
++ if (lineoff+linelen > tcplen)
++ {
++ INFOP("!! overrun !!\n");
++ break;
++ }
++
++ if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0)
++ {
++ *pcseqoff = lineoff;
++ *pcseqlen = linelen;
++ }
++ if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0)
++ {
++ uint off = lineoff+15;
++ SKIP_WSPACE(ptcp+lineoff, linelen, off);
++ nf_strtou32(ptcp+off, &entitylen);
++ }
++ }
++ *phdrslen = (*ptcpoff) - (*phdrsoff);
++
++ return 1;
++}
++
++/*
++ * Find lo/hi client ports (if any) in transport header
++ * In:
++ * ptcp, tcplen = packet
++ * tranoff, tranlen = buffer to search
++ *
++ * Out:
++ * pport_lo, pport_hi = lo/hi ports (host endian)
++ *
++ * Returns nonzero if any client ports found
++ *
++ * Note: it is valid (and expected) for the client to request multiple
++ * transports, so we need to parse the entire line.
++ */
++static int
++rtsp_parse_transport(char* ptran, uint tranlen,
++ struct ip_ct_rtsp_expect* prtspexp)
++{
++ int rc = 0;
++ uint off = 0;
++
++ if (tranlen < 10 || !iseol(ptran[tranlen-1]) ||
++ nf_strncasecmp(ptran, "Transport:", 10) != 0)
++ {
++ INFOP("sanity check failed\n");
++ return 0;
++ }
++ DEBUGP("tran='%.*s'\n", (int)tranlen, ptran);
++ off += 10;
++ SKIP_WSPACE(ptran, tranlen, off);
++
++ /* Transport: tran;field;field=val,tran;field;field=val,... */
++ while (off < tranlen)
++ {
++ const char* pparamend;
++ uint nextparamoff;
++
++ pparamend = memchr(ptran+off, ',', tranlen-off);
++ pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
++ nextparamoff = pparamend-ptran;
++
++ while (off < nextparamoff)
++ {
++ const char* pfieldend;
++ uint nextfieldoff;
++
++ pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++
++ if (strncmp(ptran+off, "client_port=", 12) == 0)
++ {
++ u_int16_t port;
++ uint numlen;
++
++ off += 12;
++ numlen = nf_strtou16(ptran+off, &port);
++ off += numlen;
++ if (prtspexp->loport != 0 && prtspexp->loport != port)
++ {
++ DEBUGP("multiple ports found, port %hu ignored\n", port);
++ }
++ else
++ {
++ prtspexp->loport = prtspexp->hiport = port;
++ if (ptran[off] == '-')
++ {
++ off++;
++ numlen = nf_strtou16(ptran+off, &port);
++ off += numlen;
++ prtspexp->pbtype = pb_range;
++ prtspexp->hiport = port;
++
++ // If we have a range, assume rtp:
++ // loport must be even, hiport must be loport+1
++ if ((prtspexp->loport & 0x0001) != 0 ||
++ prtspexp->hiport != prtspexp->loport+1)
++ {
++ DEBUGP("incorrect range: %hu-%hu, correcting\n",
++ prtspexp->loport, prtspexp->hiport);
++ prtspexp->loport &= 0xfffe;
++ prtspexp->hiport = prtspexp->loport+1;
++ }
++ }
++ else if (ptran[off] == '/')
++ {
++ off++;
++ numlen = nf_strtou16(ptran+off, &port);
++ off += numlen;
++ prtspexp->pbtype = pb_discon;
++ prtspexp->hiport = port;
++ }
++ rc = 1;
++ }
++ }
++
++ /*
++ * Note we don't look for the destination parameter here.
++ * If we are using NAT, the NAT module will handle it. If not,
++ * and the client is sending packets elsewhere, the expectation
++ * will quietly time out.
++ */
++
++ off = nextfieldoff;
++ }
++
++ off = nextparamoff;
++ }
++
++ return rc;
++}
++
++/*** conntrack functions ***/
++
++/* outbound packet: client->server */
++static int
++help_out(const struct iphdr* iph, size_t pktlen,
++ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
++{
++ int dir = CTINFO2DIR(ctinfo); /* = IP_CT_DIR_ORIGINAL */
++ struct tcphdr* tcph = (void*)iph + iph->ihl * 4;
++ uint tcplen = pktlen - iph->ihl * 4;
++ char* pdata = (char*)tcph + tcph->doff * 4;
++ uint datalen = tcplen - tcph->doff * 4;
++ uint dataoff = 0;
++
++ struct ip_conntrack_expect exp;
++
++ while (dataoff < datalen)
++ {
++ uint cmdoff = dataoff;
++ uint hdrsoff = 0;
++ uint hdrslen = 0;
++ uint cseqoff = 0;
++ uint cseqlen = 0;
++ uint lineoff = 0;
++ uint linelen = 0;
++ uint off;
++ int rc;
++
++ if (!rtsp_parse_message(pdata, datalen, &dataoff,
++ &hdrsoff, &hdrslen,
++ &cseqoff, &cseqlen))
++ {
++ break; /* not a valid message */
++ }
++
++ if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
++ {
++ continue; /* not a SETUP message */
++ }
++ DEBUGP("found a setup message\n");
++
++ memset(&exp, 0, sizeof(exp));
++
++ off = 0;
++ while (nf_mime_nextline(pdata+hdrsoff, hdrslen, &off,
++ &lineoff, &linelen))
++ {
++ if (linelen == 0)
++ {
++ break;
++ }
++ if (off > hdrsoff+hdrslen)
++ {
++ INFOP("!! overrun !!");
++ break;
++ }
++
++ if (nf_strncasecmp(pdata+hdrsoff+lineoff, "Transport:", 10) == 0)
++ {
++ rtsp_parse_transport(pdata+hdrsoff+lineoff, linelen,
++ &exp.help.exp_rtsp_info);
++ }
++ }
++
++ if (exp.help.exp_rtsp_info.loport == 0)
++ {
++ DEBUGP("no udp transports found\n");
++ continue; /* no udp transports found */
++ }
++
++ DEBUGP("udp transport found, ports=(%d,%hu,%hu)\n",
++ (int)exp.help.exp_rtsp_info.pbtype,
++ exp.help.exp_rtsp_info.loport,
++ exp.help.exp_rtsp_info.hiport);
++
++ LOCK_BH(&ip_rtsp_lock);
++ exp.seq = ntohl(tcph->seq) + hdrsoff; /* mark all the headers */
++ exp.help.exp_rtsp_info.len = hdrslen;
++
++ exp.tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
++ exp.mask.src.ip = 0xffffffff;
++ exp.tuple.dst.ip = ct->tuplehash[dir].tuple.src.ip;
++ exp.mask.dst.ip = 0xffffffff;
++ exp.tuple.dst.u.udp.port = exp.help.exp_rtsp_info.loport;
++ exp.mask.dst.u.udp.port = (exp.help.exp_rtsp_info.pbtype == pb_range) ? 0xfffe : 0xffff;
++ exp.tuple.dst.protonum = IPPROTO_UDP;
++ exp.mask.dst.protonum = 0xffff;
++
++ DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
++ NIPQUAD(exp.tuple.src.ip),
++ ntohs(exp.tuple.src.u.tcp.port),
++ NIPQUAD(exp.tuple.dst.ip),
++ ntohs(exp.tuple.dst.u.tcp.port));
++
++ /* pass the request off to the nat helper */
++ rc = ip_conntrack_expect_related(ct, &exp);
++ UNLOCK_BH(&ip_rtsp_lock);
++ if (rc == 0)
++ {
++ DEBUGP("ip_conntrack_expect_related succeeded\n");
++ }
++ else
++ {
++ INFOP("ip_conntrack_expect_related failed (%d)\n", rc);
++ }
++ }
++
++ return NF_ACCEPT;
++}
++
++/* inbound packet: server->client */
++static int
++help_in(const struct iphdr* iph, size_t pktlen,
++ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
++{
++ return NF_ACCEPT;
++}
++
++static int
++help(const struct iphdr* iph, size_t pktlen,
++ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
++{
++ /* tcplen not negative guarenteed by ip_conntrack_tcp.c */
++ struct tcphdr* tcph = (void*)iph + iph->ihl * 4;
++ u_int32_t tcplen = pktlen - iph->ihl * 4;
++
++ /* Until there's been traffic both ways, don't look in packets. */
++ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY)
++ {
++ DEBUGP("conntrackinfo = %u\n", ctinfo);
++ return NF_ACCEPT;
++ }
++
++ /* Not whole TCP header? */
++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4)
++ {
++ DEBUGP("tcplen = %u\n", (unsigned)tcplen);
++ return NF_ACCEPT;
++ }
++
++ /* Checksum invalid? Ignore. */
++ /* FIXME: Source route IP option packets --RR */
++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++ csum_partial((char*)tcph, tcplen, 0)))
++ {
++ DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
++ tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
++ return NF_ACCEPT;
++ }
++
++ switch (CTINFO2DIR(ctinfo))
++ {
++ case IP_CT_DIR_ORIGINAL:
++ help_out(iph, pktlen, ct, ctinfo);
++ break;
++ case IP_CT_DIR_REPLY:
++ help_in(iph, pktlen, ct, ctinfo);
++ break;
++ }
++
++ return NF_ACCEPT;
++}
++
++static struct ip_conntrack_helper rtsp_helpers[MAX_PORTS];
++static char rtsp_names[MAX_PORTS][10];
++
++/* This function is intentionally _NOT_ defined as __exit */
++static void
++fini(void)
++{
++ int i;
++ for (i = 0; i < num_ports; i++)
++ {
++ DEBUGP("unregistering port %d\n", ports[i]);
++ ip_conntrack_helper_unregister(&rtsp_helpers[i]);
++ }
++}
++
++static int __init
++init(void)
++{
++ int i, ret;
++ struct ip_conntrack_helper *hlpr;
++ char *tmpname;
++
++ printk("ip_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n");
++
++ if (max_outstanding < 1)
++ {
++ printk("ip_conntrack_rtsp: max_outstanding must be a positive integer\n");
++ return -EBUSY;
++ }
++ if (setup_timeout < 0)
++ {
++ printk("ip_conntrack_rtsp: setup_timeout must be a positive integer\n");
++ return -EBUSY;
++ }
++
++ /* If no port given, default to standard rtsp port */
++ if (ports[0] == 0)
++ {
++ ports[0] = RTSP_PORT;
++ }
++
++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++)
++ {
++ hlpr = &rtsp_helpers[i];
++ memset(hlpr, 0, sizeof(struct ip_conntrack_helper));
++ hlpr->tuple.src.u.tcp.port = htons(ports[i]);
++ hlpr->tuple.dst.protonum = IPPROTO_TCP;
++ hlpr->mask.src.u.tcp.port = 0xFFFF;
++ hlpr->mask.dst.protonum = 0xFFFF;
++ hlpr->max_expected = max_outstanding;
++ hlpr->timeout = setup_timeout;
++ hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT;
++ hlpr->me = ip_conntrack_rtsp;
++ hlpr->help = help;
++
++ tmpname = &rtsp_names[i][0];
++ if (ports[i] == RTSP_PORT)
++ {
++ sprintf(tmpname, "rtsp");
++ }
++ else
++ {
++ sprintf(tmpname, "rtsp-%d", i);
++ }
++ hlpr->name = tmpname;
++
++ DEBUGP("port #%d: %d\n", i, ports[i]);
++
++ ret = ip_conntrack_helper_register(hlpr);
++
++ if (ret)
++ {
++ printk("ip_conntrack_rtsp: ERROR registering port %d\n", ports[i]);
++ fini();
++ return -EBUSY;
++ }
++ num_ports++;
++ }
++ return 0;
++}
++
++#ifdef CONFIG_IP_NF_NAT_NEEDED
++EXPORT_SYMBOL(ip_rtsp_lock);
++#endif
++
++module_init(init);
++module_exit(fini);
+diff -urN linux-2.4.32/net/ipv4/netfilter/ip_nat_rtsp.c linux-2.4.32.new/net/ipv4/netfilter/ip_nat_rtsp.c
+--- linux-2.4.32/net/ipv4/netfilter/ip_nat_rtsp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32.new/net/ipv4/netfilter/ip_nat_rtsp.c 2006-03-01 00:55:14.467150168 +0100
+@@ -0,0 +1,621 @@
++/*
++ * RTSP extension for TCP NAT alteration
++ * (C) 2003 by Tom Marshall <tmarshall@real.com>
++ * based on ip_nat_irc.c
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Module load syntax:
++ * insmod ip_nat_rtsp.o ports=port1,port2,...port<MAX_PORTS>
++ * stunaddr=<address>
++ * destaction=[auto|strip|none]
++ *
++ * If no ports are specified, the default will be port 554 only.
++ *
++ * stunaddr specifies the address used to detect that a client is using STUN.
++ * If this address is seen in the destination parameter, it is assumed that
++ * the client has already punched a UDP hole in the firewall, so we don't
++ * mangle the client_port. If none is specified, it is autodetected. It
++ * only needs to be set if you have multiple levels of NAT. It should be
++ * set to the external address that the STUN clients detect. Note that in
++ * this case, it will not be possible for clients to use UDP with servers
++ * between the NATs.
++ *
++ * If no destaction is specified, auto is used.
++ * destaction=auto: strip destination parameter if it is not stunaddr.
++ * destaction=strip: always strip destination parameter (not recommended).
++ * destaction=none: do not touch destination parameter (not recommended).
++ */
++
++#include <linux/module.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/kernel.h>
++#include <net/tcp.h>
++#include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_helper.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++
++#include <linux/inet.h>
++#include <linux/ctype.h>
++#define NF_NEED_STRNCASECMP
++#define NF_NEED_STRTOU16
++#include <linux/netfilter_helpers.h>
++#define NF_NEED_MIME_NEXTLINE
++#include <linux/netfilter_mime.h>
++
++#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
++#ifdef IP_NF_RTSP_DEBUG
++#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
++#else
++#define DEBUGP(fmt, args...)
++#endif
++
++#define MAX_PORTS 8
++#define DSTACT_AUTO 0
++#define DSTACT_STRIP 1
++#define DSTACT_NONE 2
++
++static int ports[MAX_PORTS];
++static char* stunaddr = NULL;
++static char* destaction = NULL;
++
++static int num_ports = 0;
++static u_int32_t extip = 0;
++static int dstact = 0;
++
++MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>");
++MODULE_DESCRIPTION("RTSP network address translation module");
++MODULE_LICENSE("GPL");
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++MODULE_PARM_DESC(ports, "port numbers of RTSP servers");
++MODULE_PARM(stunaddr, "s");
++MODULE_PARM_DESC(stunaddr, "Address for detecting STUN");
++MODULE_PARM(destaction, "s");
++MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)");
++#endif
++
++/* protects rtsp part of conntracks */
++DECLARE_LOCK_EXTERN(ip_rtsp_lock);
++
++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
++
++/*** helper functions ***/
++
++static void
++get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen)
++{
++ struct iphdr* iph = (struct iphdr*)skb->nh.iph;
++ struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl*4);
++
++ *pptcpdata = (char*)tcph + tcph->doff*4;
++ *ptcpdatalen = ((char*)skb->h.raw + skb->len) - *pptcpdata;
++}
++
++/*** nat functions ***/
++
++/*
++ * Mangle the "Transport:" header:
++ * - Replace all occurences of "client_port=<spec>"
++ * - Handle destination parameter
++ *
++ * In:
++ * ct, ctinfo = conntrack context
++ * pskb = packet
++ * tranoff = Transport header offset from TCP data
++ * tranlen = Transport header length (incl. CRLF)
++ * rport_lo = replacement low port (host endian)
++ * rport_hi = replacement high port (host endian)
++ *
++ * Returns packet size difference.
++ *
++ * Assumes that a complete transport header is present, ending with CR or LF
++ */
++static int
++rtsp_mangle_tran(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect* exp,
++ struct sk_buff** pskb, uint tranoff, uint tranlen)
++{
++ char* ptcp;
++ uint tcplen;
++ char* ptran;
++ char rbuf1[16]; /* Replacement buffer (one port) */
++ uint rbuf1len; /* Replacement len (one port) */
++ char rbufa[16]; /* Replacement buffer (all ports) */
++ uint rbufalen; /* Replacement len (all ports) */
++ u_int32_t newip;
++ u_int16_t loport, hiport;
++ uint off = 0;
++ uint diff; /* Number of bytes we removed */
++
++ struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info;
++ struct ip_conntrack_tuple t;
++
++ char szextaddr[15+1];
++ uint extaddrlen;
++ int is_stun;
++
++ get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++ ptran = ptcp+tranoff;
++
++ if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen ||
++ tranlen < 10 || !iseol(ptran[tranlen-1]) ||
++ nf_strncasecmp(ptran, "Transport:", 10) != 0)
++ {
++ INFOP("sanity check failed\n");
++ return 0;
++ }
++ off += 10;
++ SKIP_WSPACE(ptcp+tranoff, tranlen, off);
++
++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ t = exp->tuple;
++ t.dst.ip = newip;
++
++ extaddrlen = extip ? sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(extip))
++ : sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(newip));
++ DEBUGP("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto"));
++
++ rbuf1len = rbufalen = 0;
++ switch (prtspexp->pbtype)
++ {
++ case pb_single:
++ for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
++ {
++ t.dst.u.udp.port = htons(loport);
++ if (ip_conntrack_change_expect(exp, &t) == 0)
++ {
++ DEBUGP("using port %hu\n", loport);
++ break;
++ }
++ }
++ if (loport != 0)
++ {
++ rbuf1len = sprintf(rbuf1, "%hu", loport);
++ rbufalen = sprintf(rbufa, "%hu", loport);
++ }
++ break;
++ case pb_range:
++ for (loport = prtspexp->loport; loport != 0; loport += 2) /* XXX: improper wrap? */
++ {
++ t.dst.u.udp.port = htons(loport);
++ if (ip_conntrack_change_expect(exp, &t) == 0)
++ {
++ hiport = loport + ~exp->mask.dst.u.udp.port;
++ DEBUGP("using ports %hu-%hu\n", loport, hiport);
++ break;
++ }
++ }
++ if (loport != 0)
++ {
++ rbuf1len = sprintf(rbuf1, "%hu", loport);
++ rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1);
++ }
++ break;
++ case pb_discon:
++ for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
++ {
++ t.dst.u.udp.port = htons(loport);
++ if (ip_conntrack_change_expect(exp, &t) == 0)
++ {
++ DEBUGP("using port %hu (1 of 2)\n", loport);
++ break;
++ }
++ }
++ for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */
++ {
++ t.dst.u.udp.port = htons(hiport);
++ if (ip_conntrack_change_expect(exp, &t) == 0)
++ {
++ DEBUGP("using port %hu (2 of 2)\n", hiport);
++ break;
++ }
++ }
++ if (loport != 0 && hiport != 0)
++ {
++ rbuf1len = sprintf(rbuf1, "%hu", loport);
++ if (hiport == loport+1)
++ {
++ rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport);
++ }
++ else
++ {
++ rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport);
++ }
++ }
++ break;
++ }
++
++ if (rbuf1len == 0)
++ {
++ return 0; /* cannot get replacement port(s) */
++ }
++
++ /* Transport: tran;field;field=val,tran;field;field=val,... */
++ while (off < tranlen)
++ {
++ uint saveoff;
++ const char* pparamend;
++ uint nextparamoff;
++
++ pparamend = memchr(ptran+off, ',', tranlen-off);
++ pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
++ nextparamoff = pparamend-ptcp;
++
++ /*
++ * We pass over each param twice. On the first pass, we look for a
++ * destination= field. It is handled by the security policy. If it
++ * is present, allowed, and equal to our external address, we assume
++ * that STUN is being used and we leave the client_port= field alone.
++ */
++ is_stun = 0;
++ saveoff = off;
++ while (off < nextparamoff)
++ {
++ const char* pfieldend;
++ uint nextfieldoff;
++
++ pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++
++ if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0)
++ {
++ if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0)
++ {
++ is_stun = 1;
++ }
++ if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun))
++ {
++ diff = nextfieldoff-off;
++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
++ off, diff, NULL, 0))
++ {
++ /* mangle failed, all we can do is bail */
++ return 0;
++ }
++ get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++ ptran = ptcp+tranoff;
++ tranlen -= diff;
++ nextparamoff -= diff;
++ nextfieldoff -= diff;
++ }
++ }
++
++ off = nextfieldoff;
++ }
++ if (is_stun)
++ {
++ continue;
++ }
++ off = saveoff;
++ while (off < nextparamoff)
++ {
++ const char* pfieldend;
++ uint nextfieldoff;
++
++ pfieldend = memchr(ptran+off, ';', nextparamoff-off);
++ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++
++ if (strncmp(ptran+off, "client_port=", 12) == 0)
++ {
++ u_int16_t port;
++ uint numlen;
++ uint origoff;
++ uint origlen;
++ char* rbuf = rbuf1;
++ uint rbuflen = rbuf1len;
++
++ off += 12;
++ origoff = (ptran-ptcp)+off;
++ origlen = 0;
++ numlen = nf_strtou16(ptran+off, &port);
++ off += numlen;
++ origlen += numlen;
++ if (port != prtspexp->loport)
++ {
++ DEBUGP("multiple ports found, port %hu ignored\n", port);
++ }
++ else
++ {
++ if (ptran[off] == '-' || ptran[off] == '/')
++ {
++ off++;
++ origlen++;
++ numlen = nf_strtou16(ptran+off, &port);
++ off += numlen;
++ origlen += numlen;
++ rbuf = rbufa;
++ rbuflen = rbufalen;
++ }
++
++ /*
++ * note we cannot just memcpy() if the sizes are the same.
++ * the mangle function does skb resizing, checks for a
++ * cloned skb, and updates the checksums.
++ *
++ * parameter 4 below is offset from start of tcp data.
++ */
++ diff = origlen-rbuflen;
++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
++ origoff, origlen, rbuf, rbuflen))
++ {
++ /* mangle failed, all we can do is bail */
++ return 0;
++ }
++ get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++ ptran = ptcp+tranoff;
++ tranlen -= diff;
++ nextparamoff -= diff;
++ nextfieldoff -= diff;
++ }
++ }
++
++ off = nextfieldoff;
++ }
++
++ off = nextparamoff;
++ }
++
++ return 1;
++}
++
++static unsigned int
++expected(struct sk_buff **pskb, uint hooknum, struct ip_conntrack* ct, struct ip_nat_info* info)
++{
++ struct ip_nat_multi_range mr;
++ u_int32_t newdstip, newsrcip, newip;
++
++ struct ip_conntrack *master = master_ct(ct);
++
++ IP_NF_ASSERT(info);
++ IP_NF_ASSERT(master);
++
++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
++
++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ newip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ? newsrcip : newdstip;
++
++ DEBUGP("newsrcip=%u.%u.%u.%u, newdstip=%u.%u.%u.%u, newip=%u.%u.%u.%u\n",
++ NIPQUAD(newsrcip), NIPQUAD(newdstip), NIPQUAD(newip));
++
++ mr.rangesize = 1;
++ /* We don't want to manip the per-protocol, just the IPs. */
++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
++ mr.range[0].min_ip = mr.range[0].max_ip = newip;
++
++ return ip_nat_setup_info(ct, &mr, hooknum);
++}
++
++static uint
++help_out(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect* exp, struct sk_buff** pskb)
++{
++ char* ptcp;
++ uint tcplen;
++ uint hdrsoff;
++ uint hdrslen;
++ uint lineoff;
++ uint linelen;
++ uint off;
++
++ struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph;
++ struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4);
++
++ struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info;
++
++ get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++
++ hdrsoff = exp->seq - ntohl(tcph->seq);
++ hdrslen = prtspexp->len;
++ off = hdrsoff;
++
++ while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen))
++ {
++ if (linelen == 0)
++ {
++ break;
++ }
++ if (off > hdrsoff+hdrslen)
++ {
++ INFOP("!! overrun !!");
++ break;
++ }
++ DEBUGP("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
++
++ if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0)
++ {
++ uint oldtcplen = tcplen;
++ if (!rtsp_mangle_tran(ct, ctinfo, exp, pskb, lineoff, linelen))
++ {
++ break;
++ }
++ get_skb_tcpdata(*pskb, &ptcp, &tcplen);
++ hdrslen -= (oldtcplen-tcplen);
++ off -= (oldtcplen-tcplen);
++ lineoff -= (oldtcplen-tcplen);
++ linelen -= (oldtcplen-tcplen);
++ DEBUGP("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
++ }
++ }
++
++ return NF_ACCEPT;
++}
++
++static uint
++help_in(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect* exp, struct sk_buff** pskb)
++{
++ /* XXX: unmangle */
++ return NF_ACCEPT;
++}
++
++static uint
++help(struct ip_conntrack* ct,
++ struct ip_conntrack_expect* exp,
++ struct ip_nat_info* info,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum,
++ struct sk_buff** pskb)
++{
++ struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph;
++ struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl * 4);
++ uint datalen;
++ int dir;
++ struct ip_ct_rtsp_expect* ct_rtsp_info;
++ int rc = NF_ACCEPT;
++
++ if (ct == NULL || exp == NULL || info == NULL || pskb == NULL)
++ {
++ DEBUGP("!! null ptr (%p,%p,%p,%p) !!\n", ct, exp, info, pskb);
++ return NF_ACCEPT;
++ }
++
++ ct_rtsp_info = &exp->help.exp_rtsp_info;
++
++ /*
++ * Only mangle things once: original direction in POST_ROUTING
++ * and reply direction on PRE_ROUTING.
++ */
++ dir = CTINFO2DIR(ctinfo);
++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY)))
++ {
++ DEBUGP("Not touching dir %s at hook %s\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
++ return NF_ACCEPT;
++ }
++ DEBUGP("got beyond not touching\n");
++
++ datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
++
++ LOCK_BH(&ip_rtsp_lock);
++ /* Ensure the packet contains all of the marked data */
++ if (!between(exp->seq + ct_rtsp_info->len,
++ ntohl(tcph->seq), ntohl(tcph->seq) + datalen))
++ {
++ /* Partial retransmission? Probably a hacker. */
++ if (net_ratelimit())
++ {
++ INFOP("partial packet %u/%u in %u/%u\n",
++ exp->seq, ct_rtsp_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen);
++ }
++ UNLOCK_BH(&ip_rtsp_lock);
++ return NF_DROP;
++ }
++
++ switch (dir)
++ {
++ case IP_CT_DIR_ORIGINAL:
++ rc = help_out(ct, ctinfo, exp, pskb);
++ break;
++ case IP_CT_DIR_REPLY:
++ rc = help_in(ct, ctinfo, exp, pskb);
++ break;
++ }
++ UNLOCK_BH(&ip_rtsp_lock);
++
++ return rc;
++}
++
++static struct ip_nat_helper ip_nat_rtsp_helpers[MAX_PORTS];
++static char rtsp_names[MAX_PORTS][10];
++
++/* This function is intentionally _NOT_ defined as __exit */
++static void
++fini(void)
++{
++ int i;
++
++ for (i = 0; i < num_ports; i++)
++ {
++ DEBUGP("unregistering helper for port %d\n", ports[i]);
++ ip_nat_helper_unregister(&ip_nat_rtsp_helpers[i]);
++ }
++}
++
++static int __init
++init(void)
++{
++ int ret = 0;
++ int i;
++ struct ip_nat_helper* hlpr;
++ char* tmpname;
++
++ printk("ip_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n");
++
++ if (ports[0] == 0)
++ {
++ ports[0] = RTSP_PORT;
++ }
++
++ for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++)
++ {
++ hlpr = &ip_nat_rtsp_helpers[i];
++ memset(hlpr, 0, sizeof(struct ip_nat_helper));
++
++ hlpr->tuple.dst.protonum = IPPROTO_TCP;
++ hlpr->tuple.src.u.tcp.port = htons(ports[i]);
++ hlpr->mask.src.u.tcp.port = 0xFFFF;
++ hlpr->mask.dst.protonum = 0xFFFF;
++ hlpr->help = help;
++ hlpr->flags = 0;
++ hlpr->me = THIS_MODULE;
++ hlpr->expect = expected;
++
++ tmpname = &rtsp_names[i][0];
++ if (ports[i] == RTSP_PORT)
++ {
++ sprintf(tmpname, "rtsp");
++ }
++ else
++ {
++ sprintf(tmpname, "rtsp-%d", i);
++ }
++ hlpr->name = tmpname;
++
++ DEBUGP("registering helper for port %d: name %s\n", ports[i], hlpr->name);
++ ret = ip_nat_helper_register(hlpr);
++
++ if (ret)
++ {
++ printk("ip_nat_rtsp: error registering helper for port %d\n", ports[i]);
++ fini();
++ return 1;
++ }
++ num_ports++;
++ }
++ if (stunaddr != NULL)
++ {
++ extip = in_aton(stunaddr);
++ }
++ if (destaction != NULL)
++ {
++ if (strcmp(destaction, "auto") == 0)
++ {
++ dstact = DSTACT_AUTO;
++ }
++ if (strcmp(destaction, "strip") == 0)
++ {
++ dstact = DSTACT_STRIP;
++ }
++ if (strcmp(destaction, "none") == 0)
++ {
++ dstact = DSTACT_NONE;
++ }
++ }
++ return ret;
++}
++
++module_init(init);
++module_exit(fini);
+--- linux-2.4.32/arch/mips/kernel/mips_ksyms.c 2006-03-01 00:49:34.142887320 +0100
++++ linux-2.4.32.new/arch/mips/kernel/mips_ksyms.c 2006-03-01 00:55:14.469149864 +0100
+@@ -52,6 +52,7 @@
+ /*
+ * String functions
+ */
++EXPORT_SYMBOL_NOVERS(memchr);
+ EXPORT_SYMBOL_NOVERS(memcmp);
+ EXPORT_SYMBOL_NOVERS(memset);
+ EXPORT_SYMBOL_NOVERS(memcpy);
+diff -urN linux-2.4.32/include/linux/netfilter_helpers.h linux-2.4.32.new/include/linux/netfilter_helpers.h
+--- linux-2.4.32/include/linux/netfilter_helpers.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32.new/include/linux/netfilter_helpers.h 2006-03-01 00:55:14.470149712 +0100
+@@ -0,0 +1,133 @@
++/*
++ * Helpers for netfiler modules. This file provides implementations for basic
++ * functions such as strncasecmp(), etc.
++ *
++ * gcc will warn for defined but unused functions, so we only include the
++ * functions requested. The following macros are used:
++ * NF_NEED_STRNCASECMP nf_strncasecmp()
++ * NF_NEED_STRTOU16 nf_strtou16()
++ * NF_NEED_STRTOU32 nf_strtou32()
++ */
++#ifndef _NETFILTER_HELPERS_H
++#define _NETFILTER_HELPERS_H
++
++/* Only include these functions for kernel code. */
++#ifdef __KERNEL__
++
++#include <linux/ctype.h>
++#define iseol(c) ( (c) == '\r' || (c) == '\n' )
++
++/*
++ * The standard strncasecmp()
++ */
++#ifdef NF_NEED_STRNCASECMP
++static int
++nf_strncasecmp(const char* s1, const char* s2, u_int32_t len)
++{
++ if (s1 == NULL || s2 == NULL)
++ {
++ if (s1 == NULL && s2 == NULL)
++ {
++ return 0;
++ }
++ return (s1 == NULL) ? -1 : 1;
++ }
++ while (len > 0 && tolower(*s1) == tolower(*s2))
++ {
++ len--;
++ s1++;
++ s2++;
++ }
++ return ( (len == 0) ? 0 : (tolower(*s1) - tolower(*s2)) );
++}
++#endif /* NF_NEED_STRNCASECMP */
++
++/*
++ * Parse a string containing a 16-bit unsigned integer.
++ * Returns the number of chars used, or zero if no number is found.
++ */
++#ifdef NF_NEED_STRTOU16
++static int
++nf_strtou16(const char* pbuf, u_int16_t* pval)
++{
++ int n = 0;
++
++ *pval = 0;
++ while (isdigit(pbuf[n]))
++ {
++ *pval = (*pval * 10) + (pbuf[n] - '0');
++ n++;
++ }
++
++ return n;
++}
++#endif /* NF_NEED_STRTOU16 */
++
++/*
++ * Parse a string containing a 32-bit unsigned integer.
++ * Returns the number of chars used, or zero if no number is found.
++ */
++#ifdef NF_NEED_STRTOU32
++static int
++nf_strtou32(const char* pbuf, u_int32_t* pval)
++{
++ int n = 0;
++
++ *pval = 0;
++ while (pbuf[n] >= '0' && pbuf[n] <= '9')
++ {
++ *pval = (*pval * 10) + (pbuf[n] - '0');
++ n++;
++ }
++
++ return n;
++}
++#endif /* NF_NEED_STRTOU32 */
++
++/*
++ * Given a buffer and length, advance to the next line and mark the current
++ * line.
++ */
++#ifdef NF_NEED_NEXTLINE
++static int
++nf_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen)
++{
++ uint off = *poff;
++ uint physlen = 0;
++
++ if (off >= len)
++ {
++ return 0;
++ }
++
++ while (p[off] != '\n')
++ {
++ if (len-off <= 1)
++ {
++ return 0;
++ }
++
++ physlen++;
++ off++;
++ }
++
++ /* if we saw a crlf, physlen needs adjusted */
++ if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r')
++ {
++ physlen--;
++ }
++
++ /* advance past the newline */
++ off++;
++
++ *plineoff = *poff;
++ *plinelen = physlen;
++ *poff = off;
++
++ return 1;
++}
++#endif /* NF_NEED_NEXTLINE */
++
++#endif /* __KERNEL__ */
++
++#endif /* _NETFILTER_HELPERS_H */
+diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h
+--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 2006-03-01 00:55:14.472149408 +0100
+@@ -0,0 +1,68 @@
++/*
++ * RTSP extension for IP connection tracking.
++ * (C) 2003 by Tom Marshall <tmarshall@real.com>
++ * based on ip_conntrack_irc.h
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++#ifndef _IP_CONNTRACK_RTSP_H
++#define _IP_CONNTRACK_RTSP_H
++
++/* #define IP_NF_RTSP_DEBUG */
++#define IP_NF_RTSP_VERSION "0.01"
++
++/* port block types */
++typedef enum {
++ pb_single, /* client_port=x */
++ pb_range, /* client_port=x-y */
++ pb_discon /* client_port=x/y (rtspbis) */
++} portblock_t;
++
++/* We record seq number and length of rtsp headers here, all in host order. */
++
++/*
++ * This structure is per expected connection. It is a member of struct
++ * ip_conntrack_expect. The TCP SEQ for the conntrack expect is stored
++ * there and we are expected to only store the length of the data which
++ * needs replaced. If a packet contains multiple RTSP messages, we create
++ * one expected connection per message.
++ *
++ * We use these variables to mark the entire header block. This may seem
++ * like overkill, but the nature of RTSP requires it. A header may appear
++ * multiple times in a message. We must treat two Transport headers the
++ * same as one Transport header with two entries.
++ */
++struct ip_ct_rtsp_expect
++{
++ u_int32_t len; /* length of header block */
++ portblock_t pbtype; /* Type of port block that was requested */
++ u_int16_t loport; /* Port that was requested, low or first */
++ u_int16_t hiport; /* Port that was requested, high or second */
++#if 0
++ uint method; /* RTSP method */
++ uint cseq; /* CSeq from request */
++#endif
++};
++
++/* This structure exists only once per master */
++struct ip_ct_rtsp_master
++{
++ /* Empty (?) */
++};
++
++
++#ifdef __KERNEL__
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++
++#define RTSP_PORT 554
++
++/* Protects rtsp part of conntracks */
++DECLARE_LOCK_EXTERN(ip_rtsp_lock);
++
++#endif /* __KERNEL__ */
++
++#endif /* _IP_CONNTRACK_RTSP_H */
+diff -urN linux-2.4.32/include/linux/netfilter_mime.h linux-2.4.32.new/include/linux/netfilter_mime.h
+--- linux-2.4.32/include/linux/netfilter_mime.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32.new/include/linux/netfilter_mime.h 2006-03-01 00:55:14.473149256 +0100
+@@ -0,0 +1,90 @@
++/*
++ * MIME functions for netfilter modules. This file provides implementations
++ * for basic MIME parsing. MIME headers are used in many protocols, such as
++ * HTTP, RTSP, SIP, etc.
++ *
++ * gcc will warn for defined but unused functions, so we only include the
++ * functions requested. The following macros are used:
++ * NF_NEED_MIME_NEXTLINE nf_mime_nextline()
++ */
++#ifndef _NETFILTER_MIME_H
++#define _NETFILTER_MIME_H
++
++/* Only include these functions for kernel code. */
++#ifdef __KERNEL__
++
++#include <linux/kernel.h>
++#include <linux/ctype.h>
++
++/*
++ * Given a buffer and length, advance to the next line and mark the current
++ * line. If the current line is empty, *plinelen will be set to zero. If
++ * not, it will be set to the actual line length (including CRLF).
++ *
++ * 'line' in this context means logical line (includes LWS continuations).
++ * Returns 1 on success, 0 on failure.
++ */
++#ifdef NF_NEED_MIME_NEXTLINE
++static int
++nf_mime_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen)
++{
++ uint off = *poff;
++ uint physlen = 0;
++ int is_first_line = 1;
++
++ if (off >= len)
++ {
++ return 0;
++ }
++
++ do
++ {
++ while (p[off] != '\n')
++ {
++ if (len-off <= 1)
++ {
++ return 0;
++ }
++
++ physlen++;
++ off++;
++ }
++
++ /* if we saw a crlf, physlen needs adjusted */
++ if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r')
++ {
++ physlen--;
++ }
++
++ /* advance past the newline */
++ off++;
++
++ /* check for an empty line */
++ if (physlen == 0)
++ {
++ break;
++ }
++
++ /* check for colon on the first physical line */
++ if (is_first_line)
++ {
++ is_first_line = 0;
++ if (memchr(p+(*poff), ':', physlen) == NULL)
++ {
++ return 0;
++ }
++ }
++ }
++ while (p[off] == ' ' || p[off] == '\t');
++
++ *plineoff = *poff;
++ *plinelen = (physlen == 0) ? 0 : (off - *poff);
++ *poff = off;
++
++ return 1;
++}
++#endif /* NF_NEED_MIME_NEXTLINE */
++
++#endif /* __KERNEL__ */
++
++#endif /* _NETFILTER_MIME_H */
+--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h 2006-03-01 00:53:57.889791696 +0100
++++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-03-01 01:06:32.178122440 +0100
+@@ -72,6 +72,7 @@
+ #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_h323.h>
++#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
+
+ /* per expectation: application helper private data */
+ union ip_conntrack_expect_help {
+@@ -81,6 +82,7 @@
+ struct ip_ct_irc_expect exp_irc_info;
+ struct ip_ct_pptp_expect exp_pptp_info;
+ struct ip_ct_h225_expect exp_h225_info;
++ struct ip_ct_rtsp_expect exp_rtsp_info;
+
+ #ifdef CONFIG_IP_NF_NAT_NEEDED
+ union {
+@@ -96,6 +98,7 @@
+ struct ip_ct_irc_master ct_irc_info;
+ struct ip_ct_pptp_master ct_pptp_info;
+ struct ip_ct_h225_master ct_h225_info;
++ struct ip_ct_rtsp_master ct_rtsp_info;
+ };
+
+ #ifdef CONFIG_IP_NF_NAT_NEEDED
diff --git a/target/linux/generic-2.4/patches/615-netfilter_nat_mms.patch b/target/linux/generic-2.4/patches/615-netfilter_nat_mms.patch
new file mode 100644
index 0000000..3871d59
--- /dev/null
+++ b/target/linux/generic-2.4/patches/615-netfilter_nat_mms.patch
@@ -0,0 +1,739 @@
+diff -urN linux-2.4.32/net/ipv4/netfilter/Config.in linux-2.4.32.new/net/ipv4/netfilter/Config.in
+--- linux-2.4.32/net/ipv4/netfilter/Config.in 2006-03-01 01:12:48.268947944 +0100
++++ linux-2.4.32.new/net/ipv4/netfilter/Config.in 2006-03-01 01:14:53.455916632 +0100
+@@ -17,6 +17,7 @@
+ dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE
+ dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK
+ dep_tristate ' RTSP protocol support' CONFIG_IP_NF_RTSP $CONFIG_IP_NF_CONNTRACK
++ dep_tristate ' MMS protocol support' CONFIG_IP_NF_MMS $CONFIG_IP_NF_CONNTRACK
+ fi
+
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+@@ -127,6 +128,13 @@
+ define_tristate CONFIG_IP_NF_NAT_RTSP $CONFIG_IP_NF_NAT
+ fi
+ fi
++ if [ "$CONFIG_IP_NF_MMS" = "m" ]; then
++ define_tristate CONFIG_IP_NF_NAT_MMS m
++ else
++ if [ "$CONFIG_IP_NF_MMS" = "y" ]; then
++ define_tristate CONFIG_IP_NF_NAT_MMS $CONFIG_IP_NF_NAT
++ fi
++ fi
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT
+ fi
+diff -urN linux-2.4.32/net/ipv4/netfilter/Makefile linux-2.4.32.new/net/ipv4/netfilter/Makefile
+--- linux-2.4.32/net/ipv4/netfilter/Makefile 2006-03-01 01:12:48.270947640 +0100
++++ linux-2.4.32.new/net/ipv4/netfilter/Makefile 2006-03-01 01:15:25.263081208 +0100
+@@ -61,6 +61,10 @@
+ ifdef CONFIG_IP_NF_NAT_RTSP
+ export-objs += ip_conntrack_rtsp.o
+ endif
++obj-$(CONFIG_IP_NF_MMS) += ip_conntrack_mms.o
++ifdef CONFIG_IP_NF_NAT_MMS
++ export-objs += ip_conntrack_mms.o
++endif
+
+
+
+@@ -73,6 +77,7 @@
+ obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
+ obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
+ obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.o
++obj-$(CONFIG_IP_NF_NAT_MMS) += ip_nat_mms.o
+
+ # generic IP tables
+ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
+diff -urN linux-2.4.32/net/ipv4/netfilter/ip_conntrack_mms.c linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_mms.c
+--- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_mms.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_mms.c 2006-03-01 01:13:32.991149136 +0100
+@@ -0,0 +1,292 @@
++/* MMS extension for IP connection tracking
++ * (C) 2002 by Filip Sneppe <filip.sneppe@cronos.be>
++ * based on ip_conntrack_ftp.c and ip_conntrack_irc.c
++ *
++ * ip_conntrack_mms.c v0.3 2002-09-22
++ *
++ * 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.
++ *
++ * Module load syntax:
++ * insmod ip_conntrack_mms.o ports=port1,port2,...port<MAX_PORTS>
++ *
++ * Please give the ports of all MMS servers You wish to connect to.
++ * If you don't specify ports, the default will be TCP port 1755.
++ *
++ * More info on MMS protocol, firewalls and NAT:
++ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp
++ * http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp
++ *
++ * The SDP project people are reverse-engineering MMS:
++ * http://get.to/sdp
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <linux/ctype.h>
++#include <net/checksum.h>
++#include <net/tcp.h>
++
++#include <linux/netfilter_ipv4/lockhelp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_mms.h>
++
++DECLARE_LOCK(ip_mms_lock);
++struct module *ip_conntrack_mms = THIS_MODULE;
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int ports_c;
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++#endif
++
++#define DEBUGP(format, args...)
++
++#ifdef CONFIG_IP_NF_NAT_NEEDED
++EXPORT_SYMBOL(ip_mms_lock);
++#endif
++
++MODULE_AUTHOR("Filip Sneppe <filip.sneppe@cronos.be>");
++MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) connection tracking module");
++MODULE_LICENSE("GPL");
++
++/* #define isdigit(c) (c >= '0' && c <= '9') */
++
++/* copied from drivers/usb/serial/io_edgeport.c - not perfect but will do the trick */
++static void unicode_to_ascii (char *string, short *unicode, int unicode_size)
++{
++ int i;
++ for (i = 0; i < unicode_size; ++i) {
++ string[i] = (char)(unicode[i]);
++ }
++ string[unicode_size] = 0x00;
++}
++
++__inline static int atoi(char *s)
++{
++ int i=0;
++ while (isdigit(*s)) {
++ i = i*10 + *(s++) - '0';
++ }
++ return i;
++}
++
++/* convert ip address string like "192.168.0.10" to unsigned int */
++__inline static u_int32_t asciiiptoi(char *s)
++{
++ unsigned int i, j, k;
++
++ for(i=k=0; k<3; ++k, ++s, i<<=8) {
++ i+=atoi(s);
++ for(j=0; (*(++s) != '.') && (j<3); ++j)
++ ;
++ }
++ i+=atoi(s);
++ return ntohl(i);
++}
++
++int parse_mms(const char *data,
++ const unsigned int datalen,
++ u_int32_t *mms_ip,
++ u_int16_t *mms_proto,
++ u_int16_t *mms_port,
++ char **mms_string_b,
++ char **mms_string_e,
++ char **mms_padding_e)
++{
++ int unicode_size, i;
++ char tempstring[28]; /* "\\255.255.255.255\UDP\65535" */
++ char getlengthstring[28];
++
++ for(unicode_size=0;
++ (char) *(data+(MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2)) != (char)0;
++ unicode_size++)
++ if ((unicode_size == 28) || (MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2 >= datalen))
++ return -1; /* out of bounds - incomplete packet */
++
++ unicode_to_ascii(tempstring, (short *)(data+MMS_SRV_UNICODE_STRING_OFFSET), unicode_size);
++ DEBUGP("ip_conntrack_mms: offset 60: %s\n", (const char *)(tempstring));
++
++ /* IP address ? */
++ *mms_ip = asciiiptoi(tempstring+2);
++
++ i=sprintf(getlengthstring, "%u.%u.%u.%u", HIPQUAD(*mms_ip));
++
++ /* protocol ? */
++ if(strncmp(tempstring+3+i, "TCP", 3)==0)
++ *mms_proto = IPPROTO_TCP;
++ else if(strncmp(tempstring+3+i, "UDP", 3)==0)
++ *mms_proto = IPPROTO_UDP;
++
++ /* port ? */
++ *mms_port = atoi(tempstring+7+i);
++
++ /* we store a pointer to the beginning of the "\\a.b.c.d\proto\port"
++ unicode string, one to the end of the string, and one to the end
++ of the packet, since we must keep track of the number of bytes
++ between end of the unicode string and the end of packet (padding) */
++ *mms_string_b = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET);
++ *mms_string_e = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET + unicode_size * 2);
++ *mms_padding_e = (char *)(data + datalen); /* looks funny, doesn't it */
++ return 0;
++}
++
++
++static int help(const struct iphdr *iph, size_t len,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo)
++{
++ /* tcplen not negative guaranteed by ip_conntrack_tcp.c */
++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4;
++ const char *data = (const char *)tcph + tcph->doff * 4;
++ unsigned int tcplen = len - iph->ihl * 4;
++ unsigned int datalen = tcplen - tcph->doff * 4;
++ int dir = CTINFO2DIR(ctinfo);
++ struct ip_conntrack_expect expect, *exp = &expect;
++ struct ip_ct_mms_expect *exp_mms_info = &exp->help.exp_mms_info;
++
++ u_int32_t mms_ip;
++ u_int16_t mms_proto;
++ char mms_proto_string[8];
++ u_int16_t mms_port;
++ char *mms_string_b, *mms_string_e, *mms_padding_e;
++
++ /* Until there's been traffic both ways, don't look in packets. */
++ if (ctinfo != IP_CT_ESTABLISHED
++ && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
++ DEBUGP("ip_conntrack_mms: Conntrackinfo = %u\n", ctinfo);
++ return NF_ACCEPT;
++ }
++
++ /* Not whole TCP header? */
++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff*4) {
++ DEBUGP("ip_conntrack_mms: tcplen = %u\n", (unsigned)tcplen);
++ return NF_ACCEPT;
++ }
++
++ /* Checksum invalid? Ignore. */
++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
++ csum_partial((char *)tcph, tcplen, 0))) {
++ DEBUGP("mms_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
++ tcph, tcplen, NIPQUAD(iph->saddr),
++ NIPQUAD(iph->daddr));
++ return NF_ACCEPT;
++ }
++
++ /* Only look at packets with 0x00030002/196610 on bytes 36->39 of TCP payload */
++ if( (MMS_SRV_MSG_OFFSET < datalen) &&
++ ((*(u32 *)(data+MMS_SRV_MSG_OFFSET)) == MMS_SRV_MSG_ID)) {
++ DEBUGP("ip_conntrack_mms: offset 37: %u %u %u %u, datalen:%u\n",
++ (u8)*(data+36), (u8)*(data+37),
++ (u8)*(data+38), (u8)*(data+39),
++ datalen);
++ if(parse_mms(data, datalen, &mms_ip, &mms_proto, &mms_port,
++ &mms_string_b, &mms_string_e, &mms_padding_e))
++ if(net_ratelimit())
++ printk(KERN_WARNING
++ "ip_conntrack_mms: Unable to parse data payload\n");
++
++ memset(&expect, 0, sizeof(expect));
++
++ sprintf(mms_proto_string, "(%u)", mms_proto);
++ DEBUGP("ip_conntrack_mms: adding %s expectation %u.%u.%u.%u -> %u.%u.%u.%u:%u\n",
++ mms_proto == IPPROTO_TCP ? "TCP"
++ : mms_proto == IPPROTO_UDP ? "UDP":mms_proto_string,
++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
++ NIPQUAD(mms_ip),
++ mms_port);
++
++ /* it's possible that the client will just ask the server to tunnel
++ the stream over the same TCP session (from port 1755): there's
++ shouldn't be a need to add an expectation in that case, but it
++ makes NAT packet mangling so much easier */
++ LOCK_BH(&ip_mms_lock);
++
++ DEBUGP("ip_conntrack_mms: tcph->seq = %u\n", tcph->seq);
++
++ exp->seq = ntohl(tcph->seq) + (mms_string_b - data);
++ exp_mms_info->len = (mms_string_e - mms_string_b);
++ exp_mms_info->padding = (mms_padding_e - mms_string_e);
++ exp_mms_info->port = mms_port;
++
++ DEBUGP("ip_conntrack_mms: wrote info seq=%u (ofs=%u), len=%d, padding=%u\n",
++ exp->seq, (mms_string_e - data), exp_mms_info->len, exp_mms_info->padding);
++
++ exp->tuple = ((struct ip_conntrack_tuple)
++ { { ct->tuplehash[!dir].tuple.src.ip, { 0 } },
++ { mms_ip,
++ { (__u16) ntohs(mms_port) },
++ mms_proto } }
++ );
++ exp->mask = ((struct ip_conntrack_tuple)
++ { { 0xFFFFFFFF, { 0 } },
++ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
++ exp->expectfn = NULL;
++ ip_conntrack_expect_related(ct, &expect);
++ UNLOCK_BH(&ip_mms_lock);
++ }
++
++ return NF_ACCEPT;
++}
++
++static struct ip_conntrack_helper mms[MAX_PORTS];
++static char mms_names[MAX_PORTS][10];
++
++/* Not __exit: called from init() */
++static void fini(void)
++{
++ int i;
++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
++ DEBUGP("ip_conntrack_mms: unregistering helper for port %d\n",
++ ports[i]);
++ ip_conntrack_helper_unregister(&mms[i]);
++ }
++}
++
++static int __init init(void)
++{
++ int i, ret;
++ char *tmpname;
++
++ if (ports[0] == 0)
++ ports[0] = MMS_PORT;
++
++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
++ memset(&mms[i], 0, sizeof(struct ip_conntrack_helper));
++ mms[i].tuple.src.u.tcp.port = htons(ports[i]);
++ mms[i].tuple.dst.protonum = IPPROTO_TCP;
++ mms[i].mask.src.u.tcp.port = 0xFFFF;
++ mms[i].mask.dst.protonum = 0xFFFF;
++ mms[i].max_expected = 1;
++ mms[i].timeout = 0;
++ mms[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
++ mms[i].me = THIS_MODULE;
++ mms[i].help = help;
++
++ tmpname = &mms_names[i][0];
++ if (ports[i] == MMS_PORT)
++ sprintf(tmpname, "mms");
++ else
++ sprintf(tmpname, "mms-%d", ports[i]);
++ mms[i].name = tmpname;
++
++ DEBUGP("ip_conntrack_mms: registering helper for port %d\n",
++ ports[i]);
++ ret = ip_conntrack_helper_register(&mms[i]);
++
++ if (ret) {
++ fini();
++ return ret;
++ }
++ ports_c++;
++ }
++ return 0;
++}
++
++module_init(init);
++module_exit(fini);
+diff -urN linux-2.4.32/net/ipv4/netfilter/ip_nat_mms.c linux-2.4.32.new/net/ipv4/netfilter/ip_nat_mms.c
+--- linux-2.4.32/net/ipv4/netfilter/ip_nat_mms.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32.new/net/ipv4/netfilter/ip_nat_mms.c 2006-03-01 01:13:32.992148984 +0100
+@@ -0,0 +1,330 @@
++/* MMS extension for TCP NAT alteration.
++ * (C) 2002 by Filip Sneppe <filip.sneppe@cronos.be>
++ * based on ip_nat_ftp.c and ip_nat_irc.c
++ *
++ * ip_nat_mms.c v0.3 2002-09-22
++ *
++ * 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.
++ *
++ * Module load syntax:
++ * insmod ip_nat_mms.o ports=port1,port2,...port<MAX_PORTS>
++ *
++ * Please give the ports of all MMS servers You wish to connect to.
++ * If you don't specify ports, the default will be TCP port 1755.
++ *
++ * More info on MMS protocol, firewalls and NAT:
++ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp
++ * http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp
++ *
++ * The SDP project people are reverse-engineering MMS:
++ * http://get.to/sdp
++ */
++
++
++#include <linux/module.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <net/tcp.h>
++#include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_helper.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ip_conntrack_mms.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++
++#define DEBUGP(format, args...)
++#define DUMP_BYTES(address, counter)
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int ports_c = 0;
++
++#ifdef MODULE_PARM
++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
++#endif
++
++MODULE_AUTHOR("Filip Sneppe <filip.sneppe@cronos.be>");
++MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) NAT module");
++MODULE_LICENSE("GPL");
++
++DECLARE_LOCK_EXTERN(ip_mms_lock);
++
++
++static int mms_data_fixup(const struct ip_ct_mms_expect *ct_mms_info,
++ struct ip_conntrack *ct,
++ struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect *expect)
++{
++ u_int32_t newip;
++ struct ip_conntrack_tuple t;
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
++ char *data = (char *)tcph + tcph->doff * 4;
++ int i, j, k, port;
++ u_int16_t mms_proto;
++
++ u_int32_t *mms_chunkLenLV = (u_int32_t *)(data + MMS_SRV_CHUNKLENLV_OFFSET);
++ u_int32_t *mms_chunkLenLM = (u_int32_t *)(data + MMS_SRV_CHUNKLENLM_OFFSET);
++ u_int32_t *mms_messageLength = (u_int32_t *)(data + MMS_SRV_MESSAGELENGTH_OFFSET);
++
++ int zero_padding;
++
++ char buffer[28]; /* "\\255.255.255.255\UDP\65635" * 2 (for unicode) */
++ char unicode_buffer[75]; /* 27*2 (unicode) + 20 + 1 */
++ char proto_string[6];
++
++ MUST_BE_LOCKED(&ip_mms_lock);
++
++ /* what was the protocol again ? */
++ mms_proto = expect->tuple.dst.protonum;
++ sprintf(proto_string, "%u", mms_proto);
++
++ DEBUGP("ip_nat_mms: mms_data_fixup: info (seq %u + %u) in %u, proto %s\n",
++ expect->seq, ct_mms_info->len, ntohl(tcph->seq),
++ mms_proto == IPPROTO_UDP ? "UDP"
++ : mms_proto == IPPROTO_TCP ? "TCP":proto_string);
++
++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++
++ /* Alter conntrack's expectations. */
++ t = expect->tuple;
++ t.dst.ip = newip;
++ for (port = ct_mms_info->port; port != 0; port++) {
++ t.dst.u.tcp.port = htons(port);
++ if (ip_conntrack_change_expect(expect, &t) == 0) {
++ DEBUGP("ip_nat_mms: mms_data_fixup: using port %d\n", port);
++ break;
++ }
++ }
++
++ if(port == 0)
++ return 0;
++
++ sprintf(buffer, "\\\\%u.%u.%u.%u\\%s\\%u",
++ NIPQUAD(newip),
++ expect->tuple.dst.protonum == IPPROTO_UDP ? "UDP"
++ : expect->tuple.dst.protonum == IPPROTO_TCP ? "TCP":proto_string,
++ port);
++ DEBUGP("ip_nat_mms: new unicode string=%s\n", buffer);
++
++ memset(unicode_buffer, 0, sizeof(char)*75);
++
++ for (i=0; i<strlen(buffer); ++i)
++ *(unicode_buffer+i*2)=*(buffer+i);
++
++ DEBUGP("ip_nat_mms: mms_data_fixup: padding: %u len: %u\n", ct_mms_info->padding, ct_mms_info->len);
++ DEBUGP("ip_nat_mms: mms_data_fixup: offset: %u\n", MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len);
++ DUMP_BYTES(data+MMS_SRV_UNICODE_STRING_OFFSET, 60);
++
++ /* add end of packet to it */
++ for (j=0; j<ct_mms_info->padding; ++j) {
++ DEBUGP("ip_nat_mms: mms_data_fixup: i=%u j=%u byte=%u\n",
++ i, j, (u8)*(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j));
++ *(unicode_buffer+i*2+j) = *(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j);
++ }
++
++ /* pad with zeroes at the end ? see explanation of weird math below */
++ zero_padding = (8-(strlen(buffer)*2 + ct_mms_info->padding + 4)%8)%8;
++ for (k=0; k<zero_padding; ++k)
++ *(unicode_buffer+i*2+j+k)= (char)0;
++
++ DEBUGP("ip_nat_mms: mms_data_fixup: zero_padding = %u\n", zero_padding);
++ DEBUGP("ip_nat_mms: original=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n",
++ *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength);
++
++ /* explanation, before I forget what I did:
++ strlen(buffer)*2 + ct_mms_info->padding + 4 must be divisable by 8;
++ divide by 8 and add 3 to compute the mms_chunkLenLM field,
++ but note that things may have to be padded with zeroes to align by 8
++ bytes, hence we add 7 and divide by 8 to get the correct length */
++ *mms_chunkLenLM = (u_int32_t) (3+(strlen(buffer)*2+ct_mms_info->padding+11)/8);
++ *mms_chunkLenLV = *mms_chunkLenLM+2;
++ *mms_messageLength = *mms_chunkLenLV*8;
++
++ DEBUGP("ip_nat_mms: modified=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n",
++ *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength);
++
++ ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
++ expect->seq - ntohl(tcph->seq),
++ ct_mms_info->len + ct_mms_info->padding, unicode_buffer,
++ strlen(buffer)*2 + ct_mms_info->padding + zero_padding);
++ DUMP_BYTES(unicode_buffer, 60);
++
++ return 1;
++}
++
++static unsigned int
++mms_nat_expected(struct sk_buff **pskb,
++ unsigned int hooknum,
++ struct ip_conntrack *ct,
++ struct ip_nat_info *info)
++{
++ struct ip_nat_multi_range mr;
++ u_int32_t newdstip, newsrcip, newip;
++
++ struct ip_conntrack *master = master_ct(ct);
++
++ IP_NF_ASSERT(info);
++ IP_NF_ASSERT(master);
++
++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
++
++ DEBUGP("ip_nat_mms: mms_nat_expected: We have a connection!\n");
++
++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ DEBUGP("ip_nat_mms: mms_nat_expected: hook %s: newsrc->newdst %u.%u.%u.%u->%u.%u.%u.%u\n",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???",
++ NIPQUAD(newsrcip), NIPQUAD(newdstip));
++
++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
++ newip = newsrcip;
++ else
++ newip = newdstip;
++
++ DEBUGP("ip_nat_mms: mms_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
++
++ mr.rangesize = 1;
++ /* We don't want to manip the per-protocol, just the IPs. */
++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
++ mr.range[0].min_ip = mr.range[0].max_ip = newip;
++
++ return ip_nat_setup_info(ct, &mr, hooknum);
++}
++
++
++static unsigned int mms_nat_help(struct ip_conntrack *ct,
++ struct ip_conntrack_expect *exp,
++ struct ip_nat_info *info,
++ enum ip_conntrack_info ctinfo,
++ unsigned int hooknum,
++ struct sk_buff **pskb)
++{
++ struct iphdr *iph = (*pskb)->nh.iph;
++ struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
++ unsigned int datalen;
++ int dir;
++ struct ip_ct_mms_expect *ct_mms_info;
++
++ if (!exp)
++ DEBUGP("ip_nat_mms: no exp!!");
++
++ ct_mms_info = &exp->help.exp_mms_info;
++
++ /* Only mangle things once: original direction in POST_ROUTING
++ and reply direction on PRE_ROUTING. */
++ dir = CTINFO2DIR(ctinfo);
++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
++ ||(hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
++ DEBUGP("ip_nat_mms: mms_nat_help: not touching dir %s at hook %s\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
++ return NF_ACCEPT;
++ }
++ DEBUGP("ip_nat_mms: mms_nat_help: beyond not touching (dir %s at hook %s)\n",
++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
++
++ datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
++
++ DEBUGP("ip_nat_mms: mms_nat_help: %u+%u=%u %u %u\n", exp->seq, ct_mms_info->len,
++ exp->seq + ct_mms_info->len,
++ ntohl(tcph->seq),
++ ntohl(tcph->seq) + datalen);
++
++ LOCK_BH(&ip_mms_lock);
++ /* Check wether the whole IP/proto/port pattern is carried in the payload */
++ if (between(exp->seq + ct_mms_info->len,
++ ntohl(tcph->seq),
++ ntohl(tcph->seq) + datalen)) {
++ if (!mms_data_fixup(ct_mms_info, ct, pskb, ctinfo, exp)) {
++ UNLOCK_BH(&ip_mms_lock);
++ return NF_DROP;
++ }
++ } else {
++ /* Half a match? This means a partial retransmisison.
++ It's a cracker being funky. */
++ if (net_ratelimit()) {
++ printk("ip_nat_mms: partial packet %u/%u in %u/%u\n",
++ exp->seq, ct_mms_info->len,
++ ntohl(tcph->seq),
++ ntohl(tcph->seq) + datalen);
++ }
++ UNLOCK_BH(&ip_mms_lock);
++ return NF_DROP;
++ }
++ UNLOCK_BH(&ip_mms_lock);
++
++ return NF_ACCEPT;
++}
++
++static struct ip_nat_helper mms[MAX_PORTS];
++static char mms_names[MAX_PORTS][10];
++
++/* Not __exit: called from init() */
++static void fini(void)
++{
++ int i;
++
++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
++ DEBUGP("ip_nat_mms: unregistering helper for port %d\n", ports[i]);
++ ip_nat_helper_unregister(&mms[i]);
++ }
++}
++
++static int __init init(void)
++{
++ int i, ret = 0;
++ char *tmpname;
++
++ if (ports[0] == 0)
++ ports[0] = MMS_PORT;
++
++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
++
++ memset(&mms[i], 0, sizeof(struct ip_nat_helper));
++
++ mms[i].tuple.dst.protonum = IPPROTO_TCP;
++ mms[i].tuple.src.u.tcp.port = htons(ports[i]);
++ mms[i].mask.dst.protonum = 0xFFFF;
++ mms[i].mask.src.u.tcp.port = 0xFFFF;
++ mms[i].help = mms_nat_help;
++ mms[i].me = THIS_MODULE;
++ mms[i].flags = 0;
++ mms[i].expect = mms_nat_expected;
++
++ tmpname = &mms_names[i][0];
++ if (ports[i] == MMS_PORT)
++ sprintf(tmpname, "mms");
++ else
++ sprintf(tmpname, "mms-%d", i);
++ mms[i].name = tmpname;
++
++ DEBUGP("ip_nat_mms: register helper for port %d\n",
++ ports[i]);
++ ret = ip_nat_helper_register(&mms[i]);
++
++ if (ret) {
++ printk("ip_nat_mms: error registering "
++ "helper for port %d\n", ports[i]);
++ fini();
++ return ret;
++ }
++ ports_c++;
++ }
++
++ return ret;
++}
++
++module_init(init);
++module_exit(fini);
+diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack.h
+--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h 2006-03-01 01:12:47.910002512 +0100
++++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-03-01 01:16:16.710260048 +0100
+@@ -73,6 +73,7 @@
+ #include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_h323.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
++#include <linux/netfilter_ipv4/ip_conntrack_mms.h>
+
+ /* per expectation: application helper private data */
+ union ip_conntrack_expect_help {
+@@ -83,6 +84,7 @@
+ struct ip_ct_pptp_expect exp_pptp_info;
+ struct ip_ct_h225_expect exp_h225_info;
+ struct ip_ct_rtsp_expect exp_rtsp_info;
++ struct ip_ct_mms_expect exp_mms_info;
+
+ #ifdef CONFIG_IP_NF_NAT_NEEDED
+ union {
+@@ -99,6 +101,7 @@
+ struct ip_ct_pptp_master ct_pptp_info;
+ struct ip_ct_h225_master ct_h225_info;
+ struct ip_ct_rtsp_master ct_rtsp_info;
++ struct ip_ct_mms_master ct_mms_info;
+ };
+
+ #ifdef CONFIG_IP_NF_NAT_NEEDED
+diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_mms.h linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_mms.h
+--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_mms.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_mms.h 2006-03-01 01:13:32.993148832 +0100
+@@ -0,0 +1,31 @@
++#ifndef _IP_CONNTRACK_MMS_H
++#define _IP_CONNTRACK_MMS_H
++/* MMS tracking. */
++
++#ifdef __KERNEL__
++#include <linux/netfilter_ipv4/lockhelp.h>
++
++DECLARE_LOCK_EXTERN(ip_mms_lock);
++
++#define MMS_PORT 1755
++#define MMS_SRV_MSG_ID 196610
++
++#define MMS_SRV_MSG_OFFSET 36
++#define MMS_SRV_UNICODE_STRING_OFFSET 60
++#define MMS_SRV_CHUNKLENLV_OFFSET 16
++#define MMS_SRV_CHUNKLENLM_OFFSET 32
++#define MMS_SRV_MESSAGELENGTH_OFFSET 8
++#endif
++
++/* This structure is per expected connection */
++struct ip_ct_mms_expect {
++ u_int32_t len;
++ u_int32_t padding;
++ u_int16_t port;
++};
++
++/* This structure exists only once per master */
++struct ip_ct_mms_master {
++};
++
++#endif /* _IP_CONNTRACK_MMS_H */
diff --git a/target/linux/generic-2.4/patches/616-netfilter_imq.patch b/target/linux/generic-2.4/patches/616-netfilter_imq.patch
new file mode 100644
index 0000000..e2e45af
--- /dev/null
+++ b/target/linux/generic-2.4/patches/616-netfilter_imq.patch
@@ -0,0 +1,748 @@
+diff -aurN linux-2.4.28-orig/Documentation/Configure.help linux-2.4.28/Documentation/Configure.help
+--- linux-2.4.28-orig/Documentation/Configure.help 2004-11-17 11:54:20.000000000 +0000
++++ linux-2.4.28/Documentation/Configure.help 2004-12-14 11:43:42.000000000 +0000
+@@ -3147,6 +3147,22 @@
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
++IMQ target support
++CONFIG_IP_NF_TARGET_IMQ
++ This option adds a `IMQ' target which is used to specify if and
++ to which imq device packets should get enqueued/dequeued.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
++IMQ target support
++CONFIG_IP6_NF_TARGET_IMQ
++ This option adds a `IMQ' target which is used to specify if and
++ to which imq device packets should get enqueued/dequeued.
++
++ If you want to compile it as a module, say M here and read
++ <file:Documentation/modules.txt>. If unsure, say `N'.
++
+ MARK target support
+ CONFIG_IP_NF_TARGET_MARK
+ This option adds a `MARK' target, which allows you to create rules
+@@ -9799,6 +9815,20 @@
+ say M here and read <file:Documentation/modules.txt>. The module
+ will be called bonding.o.
+
++Intermediate queueing device support
++CONFIG_IMQ
++ The imq device(s) is used as placeholder for QoS queueing disciplines.
++ Every packet entering/leaving the ip stack can be directed through
++ the imq device where it's enqueued/dequeued to the attached qdisc.
++ This allows you to treat network devices as classes and distribute
++ bandwidth among them. Iptables is used to specify through which imq
++ device, if any, packets travel.
++
++ If you want to compile this as a module ( = code which ca be
++ inserted in and removed from the running kernel whenever you want),
++ say M here and read <file:Documentation/modules.txt>. The module
++ will be called imq.o
++
+ SLIP (serial line) support
+ CONFIG_SLIP
+ Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
+diff -aurN linux-2.4.28-orig/drivers/net/Config.in linux-2.4.28/drivers/net/Config.in
+--- linux-2.4.28-orig/drivers/net/Config.in 2004-08-07 23:26:04.000000000 +0000
++++ linux-2.4.28/drivers/net/Config.in 2004-12-14 11:43:42.000000000 +0000
+@@ -7,6 +7,11 @@
+ tristate 'Dummy net driver support' CONFIG_DUMMY
+ tristate 'Bonding driver support' CONFIG_BONDING
+ tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
++if [ "$CONFIG_NETFILTER" = "y" ]; then
++ tristate 'IMQ (intermediate queueing device) support' CONFIG_IMQ
++else
++ comment 'IMQ needs CONFIG_NETFILTER enabled'
++fi
+ tristate 'Universal TUN/TAP device driver support' CONFIG_TUN
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP
+diff -aurN linux-2.4.28-orig/drivers/net/Makefile linux-2.4.28/drivers/net/Makefile
+--- linux-2.4.28-orig/drivers/net/Makefile 2004-08-07 23:26:04.000000000 +0000
++++ linux-2.4.28/drivers/net/Makefile 2004-12-14 11:43:42.000000000 +0000
+@@ -170,6 +170,7 @@
+
+ obj-$(CONFIG_STRIP) += strip.o
+ obj-$(CONFIG_DUMMY) += dummy.o
++obj-$(CONFIG_IMQ) += imq.o
+ obj-$(CONFIG_DE600) += de600.o
+ obj-$(CONFIG_DE620) += de620.o
+ obj-$(CONFIG_AT1500) += lance.o
+diff -aurN linux-2.4.28-orig/drivers/net/imq.c linux-2.4.28/drivers/net/imq.c
+--- linux-2.4.28-orig/drivers/net/imq.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.4.28/drivers/net/imq.c 2004-12-14 11:43:42.000000000 +0000
+@@ -0,0 +1,321 @@
++/*
++ * Pseudo-driver for the intermediate queue device.
++ *
++ * 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.
++ *
++ * Authors: Patrick McHardy, <kaber@trash.net>
++ *
++ * The first version was written by Martin Devera, <devik@cdi.cz>
++ *
++ * Credits: Jan Rafaj <imq2t@cedric.vabo.cz>
++ * - Update patch to 2.4.21
++ * Sebastian Strollo <sstrollo@nortelnetworks.com>
++ * - Fix "Dead-loop on netdevice imq"-issue
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/if_arp.h>
++#include <linux/netfilter.h>
++#include <linux/netfilter_ipv4.h>
++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
++#include <linux/netfilter_ipv6.h>
++#endif
++#include <linux/imq.h>
++#include <net/pkt_sched.h>
++
++static nf_hookfn imq_nf_hook;
++
++static struct nf_hook_ops imq_ingress_ipv4 = {
++ { NULL, NULL},
++ imq_nf_hook,
++ PF_INET,
++ NF_IP_PRE_ROUTING,
++ NF_IP_PRI_MANGLE + 1
++};
++
++static struct nf_hook_ops imq_egress_ipv4 = {
++ { NULL, NULL},
++ imq_nf_hook,
++ PF_INET,
++ NF_IP_POST_ROUTING,
++ NF_IP_PRI_LAST
++};
++
++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
++static struct nf_hook_ops imq_ingress_ipv6 = {
++ { NULL, NULL},
++ imq_nf_hook,
++ PF_INET6,
++ NF_IP6_PRE_ROUTING,
++ NF_IP6_PRI_MANGLE + 1
++};
++
++static struct nf_hook_ops imq_egress_ipv6 = {
++ { NULL, NULL},
++ imq_nf_hook,
++ PF_INET6,
++ NF_IP6_POST_ROUTING,
++ NF_IP6_PRI_LAST
++};
++#endif
++
++static unsigned int numdevs = 2;
++
++MODULE_PARM(numdevs, "i");
++MODULE_PARM_DESC(numdevs, "number of imq devices");
++
++static struct net_device *imq_devs;
++
++
++static struct net_device_stats *imq_get_stats(struct net_device *dev)
++{
++ return (struct net_device_stats *)dev->priv;
++}
++
++/* called for packets kfree'd in qdiscs at places other than enqueue */
++static void imq_skb_destructor(struct sk_buff *skb)
++{
++ struct nf_info *info = skb->nf_info;
++
++ if (info) {
++ if (info->indev)
++ dev_put(info->indev);
++ if (info->outdev)
++ dev_put(info->outdev);
++ kfree(info);
++ }
++}
++
++static int imq_dev_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct net_device_stats *stats = (struct net_device_stats*) dev->priv;
++
++ stats->tx_bytes += skb->len;
++ stats->tx_packets++;
++
++ skb->imq_flags = 0;
++ skb->destructor = NULL;
++
++ dev->trans_start = jiffies;
++ nf_reinject(skb, skb->nf_info, NF_ACCEPT);
++ return 0;
++}
++
++static int imq_nf_queue(struct sk_buff *skb, struct nf_info *info,
++ void *data)
++{
++ struct net_device *dev;
++ struct net_device_stats *stats;
++ struct sk_buff *skb2 = NULL;
++ struct Qdisc *q;
++ unsigned int index = skb->imq_flags&IMQ_F_IFMASK;
++ int ret = -1;
++
++ if (index > numdevs)
++ return -1;
++
++ dev = imq_devs + index;
++ if (!(dev->flags & IFF_UP)) {
++ skb->imq_flags = 0;
++ nf_reinject(skb, info, NF_ACCEPT);
++ return 0;
++ }
++ dev->last_rx = jiffies;
++
++ if (skb->destructor) {
++ skb2 = skb;
++ skb = skb_clone(skb, GFP_ATOMIC);
++ if (!skb)
++ return -1;
++ }
++ skb->nf_info = info;
++
++ stats = (struct net_device_stats *)dev->priv;
++ stats->rx_bytes+= skb->len;
++ stats->rx_packets++;
++
++ spin_lock_bh(&dev->queue_lock);
++ q = dev->qdisc;
++ if (q->enqueue) {
++ q->enqueue(skb_get(skb), q);
++ if (skb_shared(skb)) {
++ skb->destructor = imq_skb_destructor;
++ kfree_skb(skb);
++ ret = 0;
++ }
++ }
++ if (spin_is_locked(&dev->xmit_lock))
++ netif_schedule(dev);
++ else
++ qdisc_run(dev);
++ spin_unlock_bh(&dev->queue_lock);
++
++ if (skb2)
++ kfree_skb(ret ? skb : skb2);
++
++ return ret;
++}
++
++static unsigned int imq_nf_hook(unsigned int hook, struct sk_buff **pskb,
++ const struct net_device *indev,
++ const struct net_device *outdev,
++ int (*okfn)(struct sk_buff *))
++{
++ if ((*pskb)->imq_flags & IMQ_F_ENQUEUE)
++ return NF_QUEUE;
++
++ return NF_ACCEPT;
++}
++
++
++static int __init imq_init_hooks(void)
++{
++ int err;
++
++ if ((err = nf_register_queue_handler(PF_INET, imq_nf_queue, NULL)))
++ goto err1;
++ if ((err = nf_register_hook(&imq_ingress_ipv4)))
++ goto err2;
++ if ((err = nf_register_hook(&imq_egress_ipv4)))
++ goto err3;
++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
++ if ((err = nf_register_queue_handler(PF_INET6, imq_nf_queue, NULL)))
++ goto err4;
++ if ((err = nf_register_hook(&imq_ingress_ipv6)))
++ goto err5;
++ if ((err = nf_register_hook(&imq_egress_ipv6)))
++ goto err6;
++#endif
++
++ return 0;
++
++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
++err6:
++ nf_unregister_hook(&imq_ingress_ipv6);
++err5:
++ nf_unregister_queue_handler(PF_INET6);
++err4:
++ nf_unregister_hook(&imq_egress_ipv4);
++#endif
++err3:
++ nf_unregister_hook(&imq_ingress_ipv4);
++err2:
++ nf_unregister_queue_handler(PF_INET);
++err1:
++ return err;
++}
++
++static void __exit imq_unhook(void)
++{
++ nf_unregister_hook(&imq_ingress_ipv4);
++ nf_unregister_hook(&imq_egress_ipv4);
++ nf_unregister_queue_handler(PF_INET);
++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
++ nf_unregister_hook(&imq_ingress_ipv6);
++ nf_unregister_hook(&imq_egress_ipv6);
++ nf_unregister_queue_handler(PF_INET6);
++#endif
++}
++
++static int __init imq_dev_init(struct net_device *dev)
++{
++ dev->hard_start_xmit = imq_dev_xmit;
++ dev->type = ARPHRD_VOID;
++ dev->mtu = 1500;
++ dev->tx_queue_len = 30;
++ dev->flags = IFF_NOARP;
++ dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
++ if (dev->priv == NULL)
++ return -ENOMEM;
++ memset(dev->priv, 0, sizeof(struct net_device_stats));
++ dev->get_stats = imq_get_stats;
++
++ return 0;
++}
++
++static void imq_dev_uninit(struct net_device *dev)
++{
++ kfree(dev->priv);
++}
++
++static int __init imq_init_devs(void)
++{
++ struct net_device *dev;
++ int i;
++
++ if (!numdevs || numdevs > IMQ_MAX_DEVS) {
++ printk(KERN_ERR "numdevs has to be betweed 1 and %u\n",
++ IMQ_MAX_DEVS);
++ return -EINVAL;
++ }
++
++ imq_devs = kmalloc(sizeof(struct net_device) * numdevs, GFP_KERNEL);
++ if (!imq_devs)
++ return -ENOMEM;
++ memset(imq_devs, 0, sizeof(struct net_device) * numdevs);
++
++ /* we start counting at zero */
++ numdevs--;
++
++ for (i = 0, dev = imq_devs; i <= numdevs; i++, dev++) {
++ SET_MODULE_OWNER(dev);
++ strcpy(dev->name, "imq%d");
++ dev->init = imq_dev_init;
++ dev->uninit = imq_dev_uninit;
++
++ if (register_netdev(dev) < 0)
++ goto err_register;
++ }
++ return 0;
++
++err_register:
++ for (; i; i--)
++ unregister_netdev(--dev);
++ kfree(imq_devs);
++ return -EIO;
++}
++
++static void imq_cleanup_devs(void)
++{
++ int i;
++ struct net_device *dev = imq_devs;
++
++ for (i = 0; i <= numdevs; i++)
++ unregister_netdev(dev++);
++
++ kfree(imq_devs);
++}
++
++static int __init imq_init_module(void)
++{
++ int err;
++
++ if ((err = imq_init_devs()))
++ return err;
++ if ((err = imq_init_hooks())) {
++ imq_cleanup_devs();
++ return err;
++ }
++
++ printk(KERN_INFO "imq driver loaded.\n");
++
++ return 0;
++}
++
++static void __exit imq_cleanup_module(void)
++{
++ imq_unhook();
++ imq_cleanup_devs();
++}
++
++module_init(imq_init_module);
++module_exit(imq_cleanup_module);
++MODULE_LICENSE("GPL");
+diff -aurN linux-2.4.28-orig/include/linux/imq.h linux-2.4.28/include/linux/imq.h
+--- linux-2.4.28-orig/include/linux/imq.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.4.28/include/linux/imq.h 2004-12-14 11:43:42.000000000 +0000
+@@ -0,0 +1,9 @@
++#ifndef _IMQ_H
++#define _IMQ_H
++
++#define IMQ_MAX_DEVS 16
++
++#define IMQ_F_IFMASK 0x7f
++#define IMQ_F_ENQUEUE 0x80
++
++#endif /* _IMQ_H */
+diff -aurN linux-2.4.28-orig/include/linux/netfilter_ipv4/ipt_IMQ.h linux-2.4.28/include/linux/netfilter_ipv4/ipt_IMQ.h
+--- linux-2.4.28-orig/include/linux/netfilter_ipv4/ipt_IMQ.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.4.28/include/linux/netfilter_ipv4/ipt_IMQ.h 2004-12-14 11:43:42.000000000 +0000
+@@ -0,0 +1,8 @@
++#ifndef _IPT_IMQ_H
++#define _IPT_IMQ_H
++
++struct ipt_imq_info {
++ unsigned int todev; /* target imq device */
++};
++
++#endif /* _IPT_IMQ_H */
+diff -aurN linux-2.4.28-orig/include/linux/netfilter_ipv6/ip6t_IMQ.h linux-2.4.28/include/linux/netfilter_ipv6/ip6t_IMQ.h
+--- linux-2.4.28-orig/include/linux/netfilter_ipv6/ip6t_IMQ.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.4.28/include/linux/netfilter_ipv6/ip6t_IMQ.h 2004-12-14 11:43:42.000000000 +0000
+@@ -0,0 +1,8 @@
++#ifndef _IP6T_IMQ_H
++#define _IP6T_IMQ_H
++
++struct ip6t_imq_info {
++ unsigned int todev; /* target imq device */
++};
++
++#endif /* _IP6T_IMQ_H */
+diff -aurN linux-2.4.28-orig/include/linux/skbuff.h linux-2.4.28/include/linux/skbuff.h
+--- linux-2.4.28-orig/include/linux/skbuff.h 2004-08-07 23:26:06.000000000 +0000
++++ linux-2.4.28/include/linux/skbuff.h 2004-12-14 11:43:42.000000000 +0000
+@@ -93,6 +93,9 @@
+ struct nf_conntrack *master;
+ };
+ #endif
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++struct nf_info;
++#endif
+
+ struct sk_buff_head {
+ /* These two members must be first. */
+@@ -182,7 +185,7 @@
+ unsigned int len; /* Length of actual data */
+ unsigned int data_len;
+ unsigned int csum; /* Checksum */
+- unsigned char __unused, /* Dead field, may be reused */
++ unsigned char imq_flags, /* intermediate queueing device */
+ cloned, /* head may be cloned (check refcnt to be sure). */
+ pkt_type, /* Packet class */
+ ip_summed; /* Driver fed us an IP checksum */
+@@ -219,6 +222,9 @@
+ #ifdef CONFIG_NET_SCHED
+ __u32 tc_index; /* traffic control index */
+ #endif
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++ struct nf_info *nf_info;
++#endif
+ };
+
+ #ifdef __KERNEL__
+diff -aurN linux-2.4.28-orig/net/core/skbuff.c linux-2.4.28/net/core/skbuff.c
+--- linux-2.4.28-orig/net/core/skbuff.c 2003-08-25 11:44:44.000000000 +0000
++++ linux-2.4.28/net/core/skbuff.c 2004-12-14 11:43:42.000000000 +0000
+@@ -202,6 +202,10 @@
+ /* Set up other state */
+ skb->len = 0;
+ skb->cloned = 0;
++#if defined(CONFIG_IMQ) || defined (CONFIG_IMQ_MODULE)
++ skb->imq_flags = 0;
++ skb->nf_info = NULL;
++#endif
+ skb->data_len = 0;
+
+ atomic_set(&skb->users, 1);
+@@ -250,6 +254,10 @@
+ #ifdef CONFIG_NET_SCHED
+ skb->tc_index = 0;
+ #endif
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++ skb->imq_flags = 0;
++ skb->nf_info = NULL;
++#endif
+ }
+
+ static void skb_drop_fraglist(struct sk_buff *skb)
+@@ -400,6 +408,10 @@
+ #ifdef CONFIG_NET_SCHED
+ C(tc_index);
+ #endif
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++ C(imq_flags);
++ C(nf_info);
++#endif
+
+ atomic_inc(&(skb_shinfo(skb)->dataref));
+ skb->cloned = 1;
+@@ -444,6 +456,10 @@
+ #ifdef CONFIG_NET_SCHED
+ new->tc_index = old->tc_index;
+ #endif
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++ new->imq_flags=old->imq_flags;
++ new->nf_info=old->nf_info;
++#endif
+ }
+
+ /**
+diff -aurN linux-2.4.28-orig/net/ipv4/netfilter/Config.in linux-2.4.28/net/ipv4/netfilter/Config.in
+--- linux-2.4.28-orig/net/ipv4/netfilter/Config.in 2003-08-25 11:44:44.000000000 +0000
++++ linux-2.4.28/net/ipv4/netfilter/Config.in 2004-12-14 11:43:43.000000000 +0000
+@@ -104,6 +104,7 @@
+ dep_tristate ' DSCP target support' CONFIG_IP_NF_TARGET_DSCP $CONFIG_IP_NF_MANGLE
+
+ dep_tristate ' MARK target support' CONFIG_IP_NF_TARGET_MARK $CONFIG_IP_NF_MANGLE
++ dep_tristate ' IMQ target support' CONFIG_IP_NF_TARGET_IMQ $CONFIG_IP_NF_MANGLE
+ fi
+ dep_tristate ' LOG target support' CONFIG_IP_NF_TARGET_LOG $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' ULOG target support' CONFIG_IP_NF_TARGET_ULOG $CONFIG_IP_NF_IPTABLES
+diff -aurN linux-2.4.28-orig/net/ipv4/netfilter/Makefile linux-2.4.28/net/ipv4/netfilter/Makefile
+--- linux-2.4.28-orig/net/ipv4/netfilter/Makefile 2003-08-25 11:44:44.000000000 +0000
++++ linux-2.4.28/net/ipv4/netfilter/Makefile 2004-12-14 11:43:43.000000000 +0000
+@@ -94,6 +94,7 @@
+ obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
+ obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
+ obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
++obj-$(CONFIG_IP_NF_TARGET_IMQ) += ipt_IMQ.o
+ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
+ obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+ obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
+diff -aurN linux-2.4.28-orig/net/ipv4/netfilter/ipt_IMQ.c linux-2.4.28/net/ipv4/netfilter/ipt_IMQ.c
+--- linux-2.4.28-orig/net/ipv4/netfilter/ipt_IMQ.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.4.28/net/ipv4/netfilter/ipt_IMQ.c 2004-12-14 11:43:43.000000000 +0000
+@@ -0,0 +1,78 @@
++/* This target marks packets to be enqueued to an imq device */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_IMQ.h>
++#include <linux/imq.h>
++
++static unsigned int imq_target(struct sk_buff **pskb,
++ unsigned int hooknum,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *targinfo,
++ void *userinfo)
++{
++ struct ipt_imq_info *mr = (struct ipt_imq_info*)targinfo;
++
++ (*pskb)->imq_flags = mr->todev | IMQ_F_ENQUEUE;
++ (*pskb)->nfcache |= NFC_ALTERED;
++
++ return IPT_CONTINUE;
++}
++
++static int imq_checkentry(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ struct ipt_imq_info *mr;
++
++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_imq_info))) {
++ printk(KERN_WARNING "IMQ: invalid targinfosize\n");
++ return 0;
++ }
++ mr = (struct ipt_imq_info*)targinfo;
++
++ if (strcmp(tablename, "mangle") != 0) {
++ printk(KERN_WARNING
++ "IMQ: IMQ can only be called from \"mangle\" table, not \"%s\"\n",
++ tablename);
++ return 0;
++ }
++
++ if (mr->todev > IMQ_MAX_DEVS) {
++ printk(KERN_WARNING
++ "IMQ: invalid device specified, highest is %u\n",
++ IMQ_MAX_DEVS);
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_target ipt_imq_reg = {
++ { NULL, NULL},
++ "IMQ",
++ imq_target,
++ imq_checkentry,
++ NULL,
++ THIS_MODULE
++};
++
++static int __init init(void)
++{
++ if (ipt_register_target(&ipt_imq_reg))
++ return -EINVAL;
++
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&ipt_imq_reg);
++}
++
++module_init(init);
++module_exit(fini);
++MODULE_LICENSE("GPL");
+diff -aurN linux-2.4.28-orig/net/ipv6/netfilter/Config.in linux-2.4.28/net/ipv6/netfilter/Config.in
+--- linux-2.4.28-orig/net/ipv6/netfilter/Config.in 2003-06-13 14:51:39.000000000 +0000
++++ linux-2.4.28/net/ipv6/netfilter/Config.in 2004-12-14 11:43:43.000000000 +0000
+@@ -71,6 +71,7 @@
+ if [ "$CONFIG_IP6_NF_MANGLE" != "n" ]; then
+ # dep_tristate ' TOS target support' CONFIG_IP6_NF_TARGET_TOS $CONFIG_IP_NF_MANGLE
+ dep_tristate ' MARK target support' CONFIG_IP6_NF_TARGET_MARK $CONFIG_IP6_NF_MANGLE
++ dep_tristate ' IMQ target support' CONFIG_IP6_NF_TARGET_IMQ $CONFIG_IP6_NF_MANGLE
+ fi
+ #dep_tristate ' LOG target support' CONFIG_IP6_NF_TARGET_LOG $CONFIG_IP6_NF_IPTABLES
+ fi
+diff -aurN linux-2.4.28-orig/net/ipv6/netfilter/Makefile linux-2.4.28/net/ipv6/netfilter/Makefile
+--- linux-2.4.28-orig/net/ipv6/netfilter/Makefile 2003-06-13 14:51:39.000000000 +0000
++++ linux-2.4.28/net/ipv6/netfilter/Makefile 2004-12-14 11:43:43.000000000 +0000
+@@ -28,6 +28,7 @@
+ obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
+ obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
+ obj-$(CONFIG_IP6_NF_TARGET_MARK) += ip6t_MARK.o
++obj-$(CONFIG_IP6_NF_TARGET_IMQ) += ip6t_IMQ.o
+ obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
+ obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o
+ obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
+diff -aurN linux-2.4.28-orig/net/ipv6/netfilter/ip6t_IMQ.c linux-2.4.28/net/ipv6/netfilter/ip6t_IMQ.c
+--- linux-2.4.28-orig/net/ipv6/netfilter/ip6t_IMQ.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.4.28/net/ipv6/netfilter/ip6t_IMQ.c 2004-12-14 11:43:43.000000000 +0000
+@@ -0,0 +1,78 @@
++/* This target marks packets to be enqueued to an imq device */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_IMQ.h>
++#include <linux/imq.h>
++
++static unsigned int imq_target(struct sk_buff **pskb,
++ unsigned int hooknum,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *targinfo,
++ void *userinfo)
++{
++ struct ip6t_imq_info *mr = (struct ip6t_imq_info*)targinfo;
++
++ (*pskb)->imq_flags = mr->todev | IMQ_F_ENQUEUE;
++ (*pskb)->nfcache |= NFC_ALTERED;
++
++ return IP6T_CONTINUE;
++}
++
++static int imq_checkentry(const char *tablename,
++ const struct ip6t_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ struct ip6t_imq_info *mr;
++
++ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_imq_info))) {
++ printk(KERN_WARNING "IMQ: invalid targinfosize\n");
++ return 0;
++ }
++ mr = (struct ip6t_imq_info*)targinfo;
++
++ if (strcmp(tablename, "mangle") != 0) {
++ printk(KERN_WARNING
++ "IMQ: IMQ can only be called from \"mangle\" table, not \"%s\"\n",
++ tablename);
++ return 0;
++ }
++
++ if (mr->todev > IMQ_MAX_DEVS) {
++ printk(KERN_WARNING
++ "IMQ: invalid device specified, highest is %u\n",
++ IMQ_MAX_DEVS);
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ip6t_target ip6t_imq_reg = {
++ { NULL, NULL},
++ "IMQ",
++ imq_target,
++ imq_checkentry,
++ NULL,
++ THIS_MODULE
++};
++
++static int __init init(void)
++{
++ if (ip6t_register_target(&ip6t_imq_reg))
++ return -EINVAL;
++
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ip6t_unregister_target(&ip6t_imq_reg);
++}
++
++module_init(init);
++module_exit(fini);
++MODULE_LICENSE("GPL");
+diff -aurN linux-2.4.28-orig/net/sched/sch_generic.c linux-2.4.28/net/sched/sch_generic.c
+--- linux-2.4.28-orig/net/sched/sch_generic.c 2004-11-17 11:54:22.000000000 +0000
++++ linux-2.4.28/net/sched/sch_generic.c 2004-12-14 11:44:27.000000000 +0000
+@@ -29,6 +29,9 @@
+ #include <linux/skbuff.h>
+ #include <linux/rtnetlink.h>
+ #include <linux/init.h>
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++#include <linux/imq.h>
++#endif
+ #include <linux/list.h>
+ #include <net/sock.h>
+ #include <net/pkt_sched.h>
+@@ -90,7 +93,11 @@
+ spin_unlock(&dev->queue_lock);
+
+ if (!netif_queue_stopped(dev)) {
+- if (netdev_nit)
++ if (netdev_nit
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++ && !(skb->imq_flags & IMQ_F_ENQUEUE)
++#endif
++ )
+ dev_queue_xmit_nit(skb, dev);
+
+ if (dev->hard_start_xmit(skb, dev) == 0) {
diff --git a/target/linux/generic-2.4/patches/617-netfilter_time.patch b/target/linux/generic-2.4/patches/617-netfilter_time.patch
new file mode 100644
index 0000000..3593571
--- /dev/null
+++ b/target/linux/generic-2.4/patches/617-netfilter_time.patch
@@ -0,0 +1,238 @@
+diff -urN linux-2.4.32.orig/net/ipv4/netfilter/Config.in linux-2.4.32/net/ipv4/netfilter/Config.in
+--- linux-2.4.32.orig/net/ipv4/netfilter/Config.in 2006-01-07 12:11:37.000000000 +0100
++++ linux-2.4.32/net/ipv4/netfilter/Config.in 2006-01-07 12:15:45.000000000 +0100
+@@ -48,6 +48,7 @@
+ dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES
++ dep_tristate ' TIME match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_TIME $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' condition match support' CONFIG_IP_NF_MATCH_CONDITION $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES
+ dep_tristate ' ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES
+diff -urN linux-2.4.32.orig/net/ipv4/netfilter/ipt_time.c linux-2.4.32/net/ipv4/netfilter/ipt_time.c
+--- linux-2.4.32.orig/net/ipv4/netfilter/ipt_time.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32/net/ipv4/netfilter/ipt_time.c 2006-01-07 12:14:32.000000000 +0100
+@@ -0,0 +1,193 @@
++/*
++ This is a module which is used for time matching
++ It is using some modified code from dietlibc (localtime() function)
++ that you can find at http://www.fefe.de/dietlibc/
++ This file is distributed under the terms of the GNU General Public
++ License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL
++ 2001-05-04 Fabrice MARIE <fabrice@netfilter.org> : initial development.
++ 2001-21-05 Fabrice MARIE <fabrice@netfilter.org> : bug fix in the match code,
++ thanks to "Zeng Yu" <zengy@capitel.com.cn> for bug report.
++ 2001-26-09 Fabrice MARIE <fabrice@netfilter.org> : force the match to be in LOCAL_IN or PRE_ROUTING only.
++ 2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack,
++ added Nguyen Dang Phuoc Dong <dongnd@tlnet.com.vn> patch to support timezones.
++ 2004-05-02 Fabrice : added support for date matching, from an idea of Fabien COELHO.
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_time.h>
++#include <linux/time.h>
++
++MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
++MODULE_DESCRIPTION("Match arrival timestamp/date");
++MODULE_LICENSE("GPL");
++
++struct tm
++{
++ int tm_sec; /* Seconds. [0-60] (1 leap second) */
++ int tm_min; /* Minutes. [0-59] */
++ int tm_hour; /* Hours. [0-23] */
++ int tm_mday; /* Day. [1-31] */
++ int tm_mon; /* Month. [0-11] */
++ int tm_year; /* Year - 1900. */
++ int tm_wday; /* Day of week. [0-6] */
++ int tm_yday; /* Days in year.[0-365] */
++ int tm_isdst; /* DST. [-1/0/1]*/
++
++ long int tm_gmtoff; /* we don't care, we count from GMT */
++ const char *tm_zone; /* we don't care, we count from GMT */
++};
++
++void
++localtime(const time_t *timepr, struct tm *r);
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ const void *hdr,
++ u_int16_t datalen,
++ int *hotdrop)
++{
++ const struct ipt_time_info *info = matchinfo; /* match info for rule */
++ struct tm currenttime; /* time human readable */
++ u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1};
++ u_int16_t packet_time;
++ struct timeval kerneltimeval;
++ time_t packet_local_time;
++
++ /* if kerneltime=1, we don't read the skb->timestamp but kernel time instead */
++ if (info->kerneltime)
++ {
++ do_gettimeofday(&kerneltimeval);
++ packet_local_time = kerneltimeval.tv_sec;
++ }
++ else
++ packet_local_time = skb->stamp.tv_sec;
++
++ /* First we make sure we are in the date start-stop boundaries */
++ if ((packet_local_time < info->date_start) || (packet_local_time > info->date_stop))
++ return 0; /* We are outside the date boundaries */
++
++ /* Transform the timestamp of the packet, in a human readable form */
++ localtime(&packet_local_time, &currenttime);
++
++ /* check if we match this timestamp, we start by the days... */
++ if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday])
++ return 0; /* the day doesn't match */
++
++ /* ... check the time now */
++ packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min;
++ if ((packet_time < info->time_start) || (packet_time > info->time_stop))
++ return 0;
++
++ /* here we match ! */
++ return 1;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ struct ipt_time_info *info = matchinfo; /* match info for rule */
++
++ /* First, check that we are in the correct hooks */
++ if (hook_mask
++ & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT)))
++ {
++ printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n");
++ return 0;
++ }
++ /* we use the kerneltime if we are in forward or output */
++ info->kerneltime = 1;
++ if (hook_mask & ~((1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT)))
++ /* we use the skb time */
++ info->kerneltime = 0;
++
++ /* Check the size */
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_time_info)))
++ return 0;
++ /* Now check the coherence of the data ... */
++ if ((info->time_start > 1439) || /* 23*60+59 = 1439*/
++ (info->time_stop > 1439))
++ {
++ printk(KERN_WARNING "ipt_time: invalid argument\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_match time_match = {
++ .name = "time",
++ .match = match,
++ .checkentry = checkentry,
++ .me = THIS_MODULE,
++};
++
++static int __init init(void)
++{
++ printk("ipt_time loading\n");
++ return ipt_register_match(&time_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&time_match);
++ printk("ipt_time unloaded\n");
++}
++
++module_init(init);
++module_exit(fini);
++
++
++/* The part below is borowed and modified from dietlibc */
++
++/* seconds per day */
++#define SPD 24*60*60
++
++void
++localtime(const time_t *timepr, struct tm *r) {
++ time_t i;
++ time_t timep;
++ extern struct timezone sys_tz;
++ const unsigned int __spm[12] =
++ { 0,
++ (31),
++ (31+28),
++ (31+28+31),
++ (31+28+31+30),
++ (31+28+31+30+31),
++ (31+28+31+30+31+30),
++ (31+28+31+30+31+30+31),
++ (31+28+31+30+31+30+31+31),
++ (31+28+31+30+31+30+31+31+30),
++ (31+28+31+30+31+30+31+31+30+31),
++ (31+28+31+30+31+30+31+31+30+31+30),
++ };
++ register time_t work;
++
++ timep = (*timepr) - (sys_tz.tz_minuteswest * 60);
++ work=timep%(SPD);
++ r->tm_sec=work%60; work/=60;
++ r->tm_min=work%60; r->tm_hour=work/60;
++ work=timep/(SPD);
++ r->tm_wday=(4+work)%7;
++ for (i=1970; ; ++i) {
++ register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365;
++ if (work>k)
++ work-=k;
++ else
++ break;
++ }
++ r->tm_year=i-1900;
++ for (i=11; i && __spm[i]>work; --i) ;
++ r->tm_mon=i;
++ r->tm_mday=work-__spm[i]+1;
++}
+diff -urN linux-2.4.32.orig/net/ipv4/netfilter/Makefile linux-2.4.32/net/ipv4/netfilter/Makefile
+--- linux-2.4.32.orig/net/ipv4/netfilter/Makefile 2006-01-07 12:11:37.000000000 +0100
++++ linux-2.4.32/net/ipv4/netfilter/Makefile 2006-01-07 12:16:07.000000000 +0100
+@@ -118,6 +118,7 @@
+ obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
+ obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
+ obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
++obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o
+ obj-$(CONFIG_IP_NF_MATCH_CONDITION) += ipt_condition.o
+
+ obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
+diff -urN linux-2.4.32.orig/include/linux/netfilter_ipv4/ipt_time.h linux-2.4.32/include/linux/netfilter_ipv4/ipt_time.h
+--- linux-2.4.32.orig/include/linux/netfilter_ipv4/ipt_time.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.32/include/linux/netfilter_ipv4/ipt_time.h 2006-01-07 12:16:42.000000000 +0100
+@@ -0,0 +1,15 @@
++#ifndef __ipt_time_h_included__
++#define __ipt_time_h_included__
++
++
++struct ipt_time_info {
++ u_int8_t days_match; /* 1 bit per day. -SMTWTFS */
++ u_int16_t time_start; /* 0 < time_start < 23*60+59 = 1439 */
++ u_int16_t time_stop; /* 0:0 < time_stat < 23:59 */
++ u_int8_t kerneltime; /* ignore skb time (and use kerneltime) or not. */
++ time_t date_start;
++ time_t date_stop;
++};
++
++
++#endif /* __ipt_time_h_included__ */
diff --git a/target/linux/generic-2.4/patches/618-netfilter_multiport_backport.patch b/target/linux/generic-2.4/patches/618-netfilter_multiport_backport.patch
new file mode 100644
index 0000000..c34f9ec
--- /dev/null
+++ b/target/linux/generic-2.4/patches/618-netfilter_multiport_backport.patch
@@ -0,0 +1,231 @@
+diff -urN linux.old/include/linux/netfilter_ipv4/ipt_multiport.h linux.dev/include/linux/netfilter_ipv4/ipt_multiport.h
+--- linux.old/include/linux/netfilter_ipv4/ipt_multiport.h 2000-12-11 22:31:30.000000000 +0100
++++ linux.dev/include/linux/netfilter_ipv4/ipt_multiport.h 2006-02-04 05:23:54.318518250 +0100
+@@ -11,11 +11,12 @@
+
+ #define IPT_MULTI_PORTS 15
+
+-/* Must fit inside union ipt_matchinfo: 16 bytes */
+-struct ipt_multiport
++struct ipt_multiport_v1
+ {
+ u_int8_t flags; /* Type of comparison */
+ u_int8_t count; /* Number of ports */
+ u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */
++ u_int8_t pflags[IPT_MULTI_PORTS]; /* Port flags */
++ u_int8_t invert; /* Invert flag */
+ };
+ #endif /*_IPT_MULTIPORT_H*/
+diff -urN linux.old/net/ipv4/netfilter/ipt_multiport.c linux.dev/net/ipv4/netfilter/ipt_multiport.c
+--- linux.old/net/ipv4/netfilter/ipt_multiport.c 2003-06-13 16:51:39.000000000 +0200
++++ linux.dev/net/ipv4/netfilter/ipt_multiport.c 2006-02-04 05:34:27.362081000 +0100
+@@ -1,5 +1,14 @@
+ /* Kernel module to match one of a list of TCP/UDP ports: ports are in
+ the same place so we can treat them as equal. */
++
++/* (C) 1999-2001 Paul `Rusty' Russell
++ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
+ #include <linux/module.h>
+ #include <linux/types.h>
+ #include <linux/udp.h>
+@@ -8,97 +17,136 @@
+ #include <linux/netfilter_ipv4/ipt_multiport.h>
+ #include <linux/netfilter_ipv4/ip_tables.h>
+
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
++MODULE_DESCRIPTION("iptables multiple port match module");
++
+ #if 0
+ #define duprintf(format, args...) printk(format , ## args)
+ #else
+ #define duprintf(format, args...)
+ #endif
+
++/* from linux 2.6 skbuff.h */
++static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
++ int len, void *buffer)
++{
++ int hlen = skb_headlen(skb);
++
++ if (hlen - offset >= len)
++ return skb->data + offset;
++
++ if (skb_copy_bits(skb, offset, buffer, len) < 0)
++ return NULL;
++
++ return buffer;
++}
++
++
+ /* Returns 1 if the port is matched by the test, 0 otherwise. */
+ static inline int
+-ports_match(const u_int16_t *portlist, enum ipt_multiport_flags flags,
+- u_int8_t count, u_int16_t src, u_int16_t dst)
++ports_match_v1(const struct ipt_multiport_v1 *minfo,
++ u_int16_t src, u_int16_t dst)
+ {
+ unsigned int i;
+- for (i=0; i<count; i++) {
+- if (flags != IPT_MULTIPORT_DESTINATION
+- && portlist[i] == src)
+- return 1;
+-
+- if (flags != IPT_MULTIPORT_SOURCE
+- && portlist[i] == dst)
+- return 1;
+- }
++ u_int16_t s, e;
+
+- return 0;
++ for (i=0; i < minfo->count; i++) {
++ s = minfo->ports[i];
++
++ if (minfo->pflags[i]) {
++ /* range port matching */
++ e = minfo->ports[++i];
++ duprintf("src or dst matches with %d-%d?\n", s, e);
++
++ if (minfo->flags == IPT_MULTIPORT_SOURCE
++ && src >= s && src <= e)
++ return 1 ^ minfo->invert;
++ if (minfo->flags == IPT_MULTIPORT_DESTINATION
++ && dst >= s && dst <= e)
++ return 1 ^ minfo->invert;
++ if (minfo->flags == IPT_MULTIPORT_EITHER
++ && ((dst >= s && dst <= e)
++ || (src >= s && src <= e)))
++ return 1 ^ minfo->invert;
++ } else {
++ /* exact port matching */
++ duprintf("src or dst matches with %d?\n", s);
++
++ if (minfo->flags == IPT_MULTIPORT_SOURCE
++ && src == s)
++ return 1 ^ minfo->invert;
++ if (minfo->flags == IPT_MULTIPORT_DESTINATION
++ && dst == s)
++ return 1 ^ minfo->invert;
++ if (minfo->flags == IPT_MULTIPORT_EITHER
++ && (src == s || dst == s))
++ return 1 ^ minfo->invert;
++ }
++ }
++
++ return minfo->invert;
+ }
+
+ static int
+-match(const struct sk_buff *skb,
+- const struct net_device *in,
+- const struct net_device *out,
+- const void *matchinfo,
+- int offset,
+- const void *hdr,
+- u_int16_t datalen,
+- int *hotdrop)
++match_v1(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
+ {
+- const struct udphdr *udp = hdr;
+- const struct ipt_multiport *multiinfo = matchinfo;
++ u16 _ports[2], *pptr;
++ const struct ipt_multiport_v1 *multiinfo = matchinfo;
++
++ if (offset)
++ return 0;
+
+- /* Must be big enough to read ports. */
+- if (offset == 0 && datalen < sizeof(struct udphdr)) {
++ pptr = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
++ sizeof(_ports), _ports);
++ if (pptr == NULL) {
+ /* We've been asked to examine this packet, and we
+- can't. Hence, no choice but to drop. */
+- duprintf("ipt_multiport:"
+- " Dropping evil offset=0 tinygram.\n");
+- *hotdrop = 1;
+- return 0;
++ * can't. Hence, no choice but to drop.
++ */
++ duprintf("ipt_multiport:"
++ " Dropping evil offset=0 tinygram.\n");
++ *hotdrop = 1;
++ return 0;
+ }
+
+- /* Must not be a fragment. */
+- return !offset
+- && ports_match(multiinfo->ports,
+- multiinfo->flags, multiinfo->count,
+- ntohs(udp->source), ntohs(udp->dest));
++ return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1]));
+ }
+
+-/* Called when user tries to insert an entry of this type. */
+ static int
+-checkentry(const char *tablename,
+- const struct ipt_ip *ip,
+- void *matchinfo,
+- unsigned int matchsize,
+- unsigned int hook_mask)
++checkentry_v1(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
+ {
+- const struct ipt_multiport *multiinfo = matchinfo;
+-
+- if (matchsize != IPT_ALIGN(sizeof(struct ipt_multiport)))
+- return 0;
+-
+- /* Must specify proto == TCP/UDP, no unknown flags or bad count */
+- return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP)
+- && !(ip->invflags & IPT_INV_PROTO)
+- && matchsize == IPT_ALIGN(sizeof(struct ipt_multiport))
+- && (multiinfo->flags == IPT_MULTIPORT_SOURCE
+- || multiinfo->flags == IPT_MULTIPORT_DESTINATION
+- || multiinfo->flags == IPT_MULTIPORT_EITHER)
+- && multiinfo->count <= IPT_MULTI_PORTS;
++ return (matchsize == IPT_ALIGN(sizeof(struct ipt_multiport_v1)));
+ }
+
+-static struct ipt_match multiport_match
+-= { { NULL, NULL }, "multiport", &match, &checkentry, NULL, THIS_MODULE };
++static struct ipt_match multiport_match_v1 = {
++ .name = "multiport",
++ .match = &match_v1,
++ .checkentry = &checkentry_v1,
++ .me = THIS_MODULE,
++};
+
+ static int __init init(void)
+ {
+- return ipt_register_match(&multiport_match);
++ int err;
++
++ err = ipt_register_match(&multiport_match_v1);
++
++ return err;
+ }
+
+ static void __exit fini(void)
+ {
+- ipt_unregister_match(&multiport_match);
++ ipt_unregister_match(&multiport_match_v1);
+ }
+
+ module_init(init);
+ module_exit(fini);
+-MODULE_LICENSE("GPL");
diff --git a/target/linux/generic-2.4/patches/700-multiple_default_gateways.patch b/target/linux/generic-2.4/patches/700-multiple_default_gateways.patch
new file mode 100644
index 0000000..46407c8
--- /dev/null
+++ b/target/linux/generic-2.4/patches/700-multiple_default_gateways.patch
@@ -0,0 +1,1299 @@
+diff -ur v2.4.29/linux/include/linux/netfilter_ipv4/ip_nat.h linux/include/linux/netfilter_ipv4/ip_nat.h
+--- v2.4.29/linux/include/linux/netfilter_ipv4/ip_nat.h 2005-01-20 09:25:34.000000000 +0200
++++ linux/include/linux/netfilter_ipv4/ip_nat.h 2005-01-20 09:55:46.998651976 +0200
+@@ -121,5 +121,13 @@
+ extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv,
+ u_int32_t newval,
+ u_int16_t oldcheck);
++
++/* Call input routing for SNAT-ed traffic */
++extern unsigned int ip_nat_route_input(unsigned int hooknum,
++ struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ int (*okfn)(struct sk_buff *));
++
+ #endif /*__KERNEL__*/
+ #endif
+diff -ur v2.4.29/linux/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h
+--- v2.4.29/linux/include/linux/rtnetlink.h 2004-08-08 10:56:48.000000000 +0300
++++ linux/include/linux/rtnetlink.h 2005-01-20 09:55:33.431714464 +0200
+@@ -234,6 +234,8 @@
+ #define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */
+ #define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */
+ #define RTNH_F_ONLINK 4 /* Gateway is forced on link */
++#define RTNH_F_SUSPECT 8 /* We don't know the real state */
++#define RTNH_F_BADSTATE (RTNH_F_DEAD | RTNH_F_SUSPECT)
+
+ /* Macros to handle hexthops */
+
+diff -ur v2.4.29/linux/include/net/ip_fib.h linux/include/net/ip_fib.h
+--- v2.4.29/linux/include/net/ip_fib.h 2001-11-13 03:24:05.000000000 +0200
++++ linux/include/net/ip_fib.h 2005-01-20 09:55:33.432714312 +0200
+@@ -162,7 +162,8 @@
+
+ static inline void fib_select_default(const struct rt_key *key, struct fib_result *res)
+ {
+- if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
++ if ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
++ FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)
+ main_table->tb_select_default(main_table, key, res);
+ }
+
+@@ -174,6 +175,7 @@
+ extern int fib_lookup(const struct rt_key *key, struct fib_result *res);
+ extern struct fib_table *__fib_new_table(int id);
+ extern void fib_rule_put(struct fib_rule *r);
++extern int fib_result_table(struct fib_result *res);
+
+ static inline struct fib_table *fib_get_table(int id)
+ {
+@@ -275,5 +277,6 @@
+ #endif
+ }
+
++extern rwlock_t fib_nhflags_lock;
+
+ #endif /* _NET_FIB_H */
+diff -ur v2.4.29/linux/include/net/route.h linux/include/net/route.h
+--- v2.4.29/linux/include/net/route.h 2003-08-25 22:06:13.000000000 +0300
++++ linux/include/net/route.h 2005-01-20 09:55:46.999651824 +0200
+@@ -49,6 +49,8 @@
+ {
+ __u32 dst;
+ __u32 src;
++ __u32 lsrc;
++ __u32 gw;
+ int iif;
+ int oif;
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+@@ -128,6 +130,7 @@
+ extern void rt_cache_flush(int how);
+ extern int ip_route_output_key(struct rtable **, const struct rt_key *key);
+ extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin);
++extern int ip_route_input_lookup(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin, u32 lsrc);
+ extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
+ extern void ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu);
+ extern void ip_rt_send_redirect(struct sk_buff *skb);
+@@ -148,6 +151,15 @@
+ }
+
+
++static inline int
++ip_route_output_lookup(struct rtable **rp,
++ u32 daddr, u32 saddr, u32 tos, int oif, u32 gw)
++{
++ struct rt_key key = { dst:daddr, src:saddr, gw:gw, oif:oif, tos:tos };
++
++ return ip_route_output_key(rp, &key);
++}
++
+ static inline void ip_rt_put(struct rtable * rt)
+ {
+ if (rt)
+diff -ur v2.4.29/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
+--- v2.4.29/linux/net/ipv4/fib_frontend.c 2003-08-25 22:06:13.000000000 +0300
++++ linux/net/ipv4/fib_frontend.c 2005-01-20 09:55:46.999651824 +0200
+@@ -54,6 +54,8 @@
+ struct fib_table *local_table;
+ struct fib_table *main_table;
+
++#define FIB_RES_TABLE(r) (RT_TABLE_MAIN)
++
+ #else
+
+ #define RT_TABLE_MIN 1
+@@ -71,6 +73,7 @@
+ return tb;
+ }
+
++#define FIB_RES_TABLE(r) (fib_result_table(r))
+
+ #endif /* CONFIG_IP_MULTIPLE_TABLES */
+
+@@ -209,6 +212,9 @@
+ struct in_device *in_dev;
+ struct rt_key key;
+ struct fib_result res;
++ int table;
++ unsigned char prefixlen;
++ unsigned char scope;
+ int no_addr, rpf;
+ int ret;
+
+@@ -216,6 +222,7 @@
+ key.src = dst;
+ key.tos = tos;
+ key.oif = 0;
++ key.gw = 0;
+ key.iif = oif;
+ key.scope = RT_SCOPE_UNIVERSE;
+
+@@ -237,31 +244,35 @@
+ goto e_inval_res;
+ *spec_dst = FIB_RES_PREFSRC(res);
+ fib_combine_itag(itag, &res);
+-#ifdef CONFIG_IP_ROUTE_MULTIPATH
+- if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
+-#else
+ if (FIB_RES_DEV(res) == dev)
+-#endif
+ {
+ ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
+ fib_res_put(&res);
+ return ret;
+ }
++ table = FIB_RES_TABLE(&res);
++ prefixlen = res.prefixlen;
++ scope = res.scope;
+ fib_res_put(&res);
+ if (no_addr)
+ goto last_resort;
+- if (rpf)
+- goto e_inval;
+ key.oif = dev->ifindex;
+
+ ret = 0;
+ if (fib_lookup(&key, &res) == 0) {
+- if (res.type == RTN_UNICAST) {
++ if (res.type == RTN_UNICAST &&
++ ((table == FIB_RES_TABLE(&res) &&
++ res.prefixlen >= prefixlen && res.scope >= scope) ||
++ !rpf)) {
+ *spec_dst = FIB_RES_PREFSRC(res);
+ ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
++ fib_res_put(&res);
++ return ret;
+ }
+ fib_res_put(&res);
+ }
++ if (rpf)
++ goto e_inval;
+ return ret;
+
+ last_resort:
+@@ -579,9 +590,7 @@
+ switch (event) {
+ case NETDEV_UP:
+ fib_add_ifaddr(ifa);
+-#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ fib_sync_up(ifa->ifa_dev->dev);
+-#endif
+ rt_cache_flush(-1);
+ break;
+ case NETDEV_DOWN:
+@@ -617,9 +626,7 @@
+ for_ifa(in_dev) {
+ fib_add_ifaddr(ifa);
+ } endfor_ifa(in_dev);
+-#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ fib_sync_up(dev);
+-#endif
+ rt_cache_flush(-1);
+ break;
+ case NETDEV_DOWN:
+diff -ur v2.4.29/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c
+--- v2.4.29/linux/net/ipv4/fib_hash.c 2003-08-25 22:06:13.000000000 +0300
++++ linux/net/ipv4/fib_hash.c 2005-01-20 09:55:47.000651672 +0200
+@@ -71,6 +71,7 @@
+ struct fib_info *fn_info;
+ #define FIB_INFO(f) ((f)->fn_info)
+ fn_key_t fn_key;
++ int fn_last_dflt;
+ u8 fn_tos;
+ u8 fn_type;
+ u8 fn_scope;
+@@ -336,72 +337,123 @@
+ return err;
+ }
+
+-static int fn_hash_last_dflt=-1;
+-
+-static int fib_detect_death(struct fib_info *fi, int order,
+- struct fib_info **last_resort, int *last_idx)
++static int fib_detect_death(struct fib_info *fi, int order, int last_dflt,
++ struct fib_info **last_resort, int *last_idx,
++ int *last_nhsel, const struct rt_key *key)
+ {
+ struct neighbour *n;
+- int state = NUD_NONE;
++ int nhsel;
++ int state;
++ struct fib_nh * nh;
++ u32 dst;
++ int flag, dead = 1;
++
++ /* change_nexthops(fi) { */
++ for (nhsel = 0, nh = fi->fib_nh; nhsel < fi->fib_nhs; nh++, nhsel++) {
++ if (key->oif && key->oif != nh->nh_oif)
++ continue;
++ if (key->gw && key->gw != nh->nh_gw && nh->nh_gw &&
++ nh->nh_scope == RT_SCOPE_LINK)
++ continue;
++ if (nh->nh_flags & RTNH_F_DEAD)
++ continue;
+
+- n = neigh_lookup(&arp_tbl, &fi->fib_nh[0].nh_gw, fi->fib_dev);
+- if (n) {
+- state = n->nud_state;
+- neigh_release(n);
++ flag = 0;
++ if (nh->nh_dev->flags & IFF_NOARP) {
++ dead = 0;
++ goto setfl;
++ }
++
++ dst = nh->nh_gw;
++ if (!nh->nh_gw || nh->nh_scope != RT_SCOPE_LINK)
++ dst = key->dst;
++
++ state = NUD_NONE;
++ n = neigh_lookup(&arp_tbl, &dst, nh->nh_dev);
++ if (n) {
++ state = n->nud_state;
++ neigh_release(n);
++ }
++ if (state==NUD_REACHABLE ||
++ ((state&NUD_VALID) && order != last_dflt)) {
++ dead = 0;
++ goto setfl;
++ }
++ if (!(state&NUD_VALID))
++ flag = 1;
++ if (!dead)
++ goto setfl;
++ if ((state&NUD_VALID) ||
++ (*last_idx<0 && order >= last_dflt)) {
++ *last_resort = fi;
++ *last_idx = order;
++ *last_nhsel = nhsel;
++ }
++
++ setfl:
++
++ read_lock_bh(&fib_nhflags_lock);
++ if (flag)
++ nh->nh_flags |= RTNH_F_SUSPECT;
++ else
++ nh->nh_flags &= ~RTNH_F_SUSPECT;
++ read_unlock_bh(&fib_nhflags_lock);
+ }
+- if (state==NUD_REACHABLE)
+- return 0;
+- if ((state&NUD_VALID) && order != fn_hash_last_dflt)
+- return 0;
+- if ((state&NUD_VALID) ||
+- (*last_idx<0 && order > fn_hash_last_dflt)) {
+- *last_resort = fi;
+- *last_idx = order;
+- }
+- return 1;
++ /* } endfor_nexthops(fi) */
++
++ return dead;
+ }
+
+ static void
+ fn_hash_select_default(struct fib_table *tb, const struct rt_key *key, struct fib_result *res)
+ {
+- int order, last_idx;
+- struct fib_node *f;
++ int order, last_idx, last_dflt, last_nhsel;
++ struct fib_node *f, *first_node;
+ struct fib_info *fi = NULL;
+ struct fib_info *last_resort;
+ struct fn_hash *t = (struct fn_hash*)tb->tb_data;
+- struct fn_zone *fz = t->fn_zones[0];
++ struct fn_zone *fz = t->fn_zones[res->prefixlen];
++ fn_key_t k;
+
+ if (fz == NULL)
+ return;
+
++ k = fz_key(key->dst, fz);
++ last_dflt = -2;
++ first_node = NULL;
+ last_idx = -1;
+ last_resort = NULL;
++ last_nhsel = 0;
+ order = -1;
+
+ read_lock(&fib_hash_lock);
+- for (f = fz->fz_hash[0]; f; f = f->fn_next) {
++ for (f = fz_chain(k, fz); f; f = f->fn_next) {
+ struct fib_info *next_fi = FIB_INFO(f);
+
+- if ((f->fn_state&FN_S_ZOMBIE) ||
++ if (!fn_key_eq(k, f->fn_key) ||
++ (f->fn_state&FN_S_ZOMBIE) ||
+ f->fn_scope != res->scope ||
++#ifdef CONFIG_IP_ROUTE_TOS
++ (f->fn_tos && f->fn_tos != key->tos) ||
++#endif
+ f->fn_type != RTN_UNICAST)
+ continue;
+
+ if (next_fi->fib_priority > res->fi->fib_priority)
+ break;
+- if (!next_fi->fib_nh[0].nh_gw || next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
+- continue;
+ f->fn_state |= FN_S_ACCESSED;
+
+- if (fi == NULL) {
+- if (next_fi != res->fi)
+- break;
+- } else if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
++ if (!first_node) {
++ last_dflt = f->fn_last_dflt;
++ first_node = f;
++ }
++ if (fi && !fib_detect_death(fi, order, last_dflt,
++ &last_resort, &last_idx, &last_nhsel, key)) {
+ if (res->fi)
+ fib_info_put(res->fi);
+ res->fi = fi;
+ atomic_inc(&fi->fib_clntref);
+- fn_hash_last_dflt = order;
++ first_node->fn_last_dflt = order;
+ goto out;
+ }
+ fi = next_fi;
+@@ -409,16 +461,25 @@
+ }
+
+ if (order<=0 || fi==NULL) {
+- fn_hash_last_dflt = -1;
++ if (fi && fi->fib_nhs > 1 &&
++ fib_detect_death(fi, order, last_dflt,
++ &last_resort, &last_idx, &last_nhsel, key) &&
++ last_resort == fi) {
++ read_lock_bh(&fib_nhflags_lock);
++ fi->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
++ read_unlock_bh(&fib_nhflags_lock);
++ }
++ if (first_node) first_node->fn_last_dflt = -1;
+ goto out;
+ }
+
+- if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
++ if (!fib_detect_death(fi, order, last_dflt, &last_resort, &last_idx,
++ &last_nhsel, key)) {
+ if (res->fi)
+ fib_info_put(res->fi);
+ res->fi = fi;
+ atomic_inc(&fi->fib_clntref);
+- fn_hash_last_dflt = order;
++ first_node->fn_last_dflt = order;
+ goto out;
+ }
+
+@@ -428,8 +489,11 @@
+ res->fi = last_resort;
+ if (last_resort)
+ atomic_inc(&last_resort->fib_clntref);
++ read_lock_bh(&fib_nhflags_lock);
++ last_resort->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
++ read_unlock_bh(&fib_nhflags_lock);
++ first_node->fn_last_dflt = last_idx;
+ }
+- fn_hash_last_dflt = last_idx;
+ out:
+ read_unlock(&fib_hash_lock);
+ }
+@@ -589,6 +653,7 @@
+
+ memset(new_f, 0, sizeof(struct fib_node));
+
++ new_f->fn_last_dflt = -1;
+ new_f->fn_key = key;
+ #ifdef CONFIG_IP_ROUTE_TOS
+ new_f->fn_tos = tos;
+diff -ur v2.4.29/linux/net/ipv4/fib_rules.c linux/net/ipv4/fib_rules.c
+--- v2.4.29/linux/net/ipv4/fib_rules.c 2004-02-19 00:23:39.000000000 +0200
++++ linux/net/ipv4/fib_rules.c 2005-01-20 09:55:33.433714160 +0200
+@@ -307,6 +307,11 @@
+ }
+ }
+
++int fib_result_table(struct fib_result *res)
++{
++ return res->r->r_table;
++}
++
+ int fib_lookup(const struct rt_key *key, struct fib_result *res)
+ {
+ int err;
+@@ -371,8 +376,10 @@
+
+ void fib_select_default(const struct rt_key *key, struct fib_result *res)
+ {
+- if (res->r && res->r->r_action == RTN_UNICAST &&
+- FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
++ if (res->r &&
++ (res->r->r_action == RTN_UNICAST || res->r->r_action == RTN_NAT) &&
++ ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
++ FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)) {
+ struct fib_table *tb;
+ if ((tb = fib_get_table(res->r->r_table)) != NULL)
+ tb->tb_select_default(tb, key, res);
+diff -ur v2.4.29/linux/net/ipv4/fib_semantics.c linux/net/ipv4/fib_semantics.c
+--- v2.4.29/linux/net/ipv4/fib_semantics.c 2003-08-25 22:06:13.000000000 +0300
++++ linux/net/ipv4/fib_semantics.c 2005-01-20 09:55:47.000651672 +0200
+@@ -48,6 +48,7 @@
+ static struct fib_info *fib_info_list;
+ static rwlock_t fib_info_lock = RW_LOCK_UNLOCKED;
+ int fib_info_cnt;
++rwlock_t fib_nhflags_lock = RW_LOCK_UNLOCKED;
+
+ #define for_fib_info() { struct fib_info *fi; \
+ for (fi = fib_info_list; fi; fi = fi->fib_next)
+@@ -150,7 +151,7 @@
+ #ifdef CONFIG_NET_CLS_ROUTE
+ nh->nh_tclassid != onh->nh_tclassid ||
+ #endif
+- ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
++ ((nh->nh_flags^onh->nh_flags)&~RTNH_F_BADSTATE))
+ return -1;
+ onh++;
+ } endfor_nexthops(fi);
+@@ -166,7 +167,7 @@
+ nfi->fib_prefsrc == fi->fib_prefsrc &&
+ nfi->fib_priority == fi->fib_priority &&
+ memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(fi->fib_metrics)) == 0 &&
+- ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
++ ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_BADSTATE) == 0 &&
+ (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0))
+ return fi;
+ } endfor_fib_info();
+@@ -365,8 +366,11 @@
+ return -EINVAL;
+ if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL)
+ return -ENODEV;
+- if (!(dev->flags&IFF_UP))
+- return -ENETDOWN;
++ if (!(dev->flags&IFF_UP)) {
++ if (fi->fib_protocol != RTPROT_STATIC)
++ return -ENETDOWN;
++ nh->nh_flags |= RTNH_F_DEAD;
++ }
+ nh->nh_dev = dev;
+ dev_hold(dev);
+ nh->nh_scope = RT_SCOPE_LINK;
+@@ -380,23 +384,48 @@
+ /* It is not necessary, but requires a bit of thinking */
+ if (key.scope < RT_SCOPE_LINK)
+ key.scope = RT_SCOPE_LINK;
+- if ((err = fib_lookup(&key, &res)) != 0)
+- return err;
+- err = -EINVAL;
+- if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
+- goto out;
+- nh->nh_scope = res.scope;
+- nh->nh_oif = FIB_RES_OIF(res);
+- if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
+- goto out;
+- dev_hold(nh->nh_dev);
+- err = -ENETDOWN;
+- if (!(nh->nh_dev->flags & IFF_UP))
+- goto out;
+- err = 0;
++
++ err = fib_lookup(&key, &res);
++ if (err) {
++ struct in_device *in_dev;
++
++ if (err != -ENETUNREACH ||
++ fi->fib_protocol != RTPROT_STATIC)
++ return err;
++
++ in_dev = inetdev_by_index(nh->nh_oif);
++ if (in_dev == NULL ||
++ in_dev->dev->flags & IFF_UP) {
++ if (in_dev)
++ in_dev_put(in_dev);
++ return err;
++ }
++ nh->nh_flags |= RTNH_F_DEAD;
++ nh->nh_scope = RT_SCOPE_LINK;
++ nh->nh_dev = in_dev->dev;
++ dev_hold(nh->nh_dev);
++ in_dev_put(in_dev);
++ } else {
++ err = -EINVAL;
++ if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
++ goto out;
++ nh->nh_scope = res.scope;
++ nh->nh_oif = FIB_RES_OIF(res);
++ if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
++ goto out;
++ dev_hold(nh->nh_dev);
++ if (!(nh->nh_dev->flags & IFF_UP)) {
++ if (fi->fib_protocol != RTPROT_STATIC) {
++ err = -ENETDOWN;
++ goto out;
++ }
++ nh->nh_flags |= RTNH_F_DEAD;
++ }
++ err = 0;
+ out:
+- fib_res_put(&res);
+- return err;
++ fib_res_put(&res);
++ return err;
++ }
+ } else {
+ struct in_device *in_dev;
+
+@@ -407,8 +436,11 @@
+ if (in_dev == NULL)
+ return -ENODEV;
+ if (!(in_dev->dev->flags&IFF_UP)) {
+- in_dev_put(in_dev);
+- return -ENETDOWN;
++ if (fi->fib_protocol != RTPROT_STATIC) {
++ in_dev_put(in_dev);
++ return -ENETDOWN;
++ }
++ nh->nh_flags |= RTNH_F_DEAD;
+ }
+ nh->nh_dev = in_dev->dev;
+ dev_hold(nh->nh_dev);
+@@ -603,8 +635,12 @@
+ for_nexthops(fi) {
+ if (nh->nh_flags&RTNH_F_DEAD)
+ continue;
+- if (!key->oif || key->oif == nh->nh_oif)
+- break;
++ if (key->oif && key->oif != nh->nh_oif)
++ continue;
++ if (key->gw && key->gw != nh->nh_gw &&
++ nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
++ continue;
++ break;
+ }
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (nhsel < fi->fib_nhs) {
+@@ -870,22 +906,35 @@
+ if (local && fi->fib_prefsrc == local) {
+ fi->fib_flags |= RTNH_F_DEAD;
+ ret++;
+- } else if (dev && fi->fib_nhs) {
++ } else if (fi->fib_nhs) {
+ int dead = 0;
+
+ change_nexthops(fi) {
+- if (nh->nh_flags&RTNH_F_DEAD)
+- dead++;
+- else if (nh->nh_dev == dev &&
+- nh->nh_scope != scope) {
+- nh->nh_flags |= RTNH_F_DEAD;
++ if (nh->nh_flags&RTNH_F_DEAD) {
++ if (fi->fib_protocol!=RTPROT_STATIC ||
++ nh->nh_dev == NULL ||
++ !__in_dev_get(nh->nh_dev) ||
++ nh->nh_dev->flags&IFF_UP)
++ dead++;
++ } else if ((nh->nh_dev == dev && dev &&
++ nh->nh_scope != scope) ||
++ (local == nh->nh_gw && local &&
++ nh->nh_oif)) {
++ write_lock_bh(&fib_nhflags_lock);
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+- spin_lock_bh(&fib_multipath_lock);
++ spin_lock(&fib_multipath_lock);
++ nh->nh_flags |= RTNH_F_DEAD;
+ fi->fib_power -= nh->nh_power;
+ nh->nh_power = 0;
+- spin_unlock_bh(&fib_multipath_lock);
++ spin_unlock(&fib_multipath_lock);
++#else
++ nh->nh_flags |= RTNH_F_DEAD;
+ #endif
+- dead++;
++ write_unlock_bh(&fib_nhflags_lock);
++ if (fi->fib_protocol!=RTPROT_STATIC ||
++ force ||
++ (dev && __in_dev_get(dev) == NULL))
++ dead++;
+ }
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (force > 1 && nh->nh_dev == dev) {
+@@ -903,37 +952,55 @@
+ return ret;
+ }
+
+-#ifdef CONFIG_IP_ROUTE_MULTIPATH
+-
+ /*
+- Dead device goes up. We wake up dead nexthops.
+- It takes sense only on multipath routes.
++ Dead device goes up or new address is added. We wake up dead nexthops.
+ */
+
+ int fib_sync_up(struct net_device *dev)
+ {
+- int ret = 0;
++ struct rt_key key;
++ struct fib_result res;
++ int ret, rep;
+
++repeat:
+ if (!(dev->flags&IFF_UP))
+ return 0;
+
++ ret = 0;
++ rep = 0;
+ for_fib_info() {
+ int alive = 0;
+
+ change_nexthops(fi) {
+- if (!(nh->nh_flags&RTNH_F_DEAD)) {
+- alive++;
++ if (!(nh->nh_flags&RTNH_F_DEAD))
+ continue;
+- }
+ if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
+ continue;
+ if (nh->nh_dev != dev || __in_dev_get(dev) == NULL)
+ continue;
++ if (nh->nh_gw && fi->fib_protocol == RTPROT_STATIC) {
++ memset(&key, 0, sizeof(key));
++ key.dst = nh->nh_gw;
++ key.oif = nh->nh_oif;
++ key.scope = nh->nh_scope;
++ if (fib_lookup(&key, &res) != 0)
++ continue;
++ if (res.type != RTN_UNICAST &&
++ res.type != RTN_LOCAL) {
++ fib_res_put(&res);
++ continue;
++ }
++ nh->nh_scope = res.scope;
++ fib_res_put(&res);
++ rep = 1;
++ }
+ alive++;
++#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ spin_lock_bh(&fib_multipath_lock);
+ nh->nh_power = 0;
+ nh->nh_flags &= ~RTNH_F_DEAD;
+ spin_unlock_bh(&fib_multipath_lock);
++#endif
+ } endfor_nexthops(fi)
+
+ if (alive > 0) {
+@@ -941,9 +1008,13 @@
+ ret++;
+ }
+ } endfor_fib_info();
++ if (rep)
++ goto repeat;
+ return ret;
+ }
+
++#ifdef CONFIG_IP_ROUTE_MULTIPATH
++
+ /*
+ The algorithm is suboptimal, but it provides really
+ fair weighted route distribution.
+@@ -952,24 +1023,45 @@
+ void fib_select_multipath(const struct rt_key *key, struct fib_result *res)
+ {
+ struct fib_info *fi = res->fi;
+- int w;
++ int w, alive;
+
+ spin_lock_bh(&fib_multipath_lock);
++ if (key->oif) {
++ int sel = -1;
++ w = -1;
++ change_nexthops(fi) {
++ if (key->oif != nh->nh_oif)
++ continue;
++ if (key->gw && key->gw != nh->nh_gw &&
++ nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
++ continue;
++ if (!(nh->nh_flags&RTNH_F_BADSTATE)) {
++ if (nh->nh_power > w) {
++ w = nh->nh_power;
++ sel = nhsel;
++ }
++ }
++ } endfor_nexthops(fi);
++ if (sel >= 0) {
++ spin_unlock_bh(&fib_multipath_lock);
++ res->nh_sel = sel;
++ return;
++ }
++ goto last_resort;
++ }
++
++repeat:
+ if (fi->fib_power <= 0) {
+ int power = 0;
+ change_nexthops(fi) {
+- if (!(nh->nh_flags&RTNH_F_DEAD)) {
++ if (!(nh->nh_flags&RTNH_F_BADSTATE)) {
+ power += nh->nh_weight;
+ nh->nh_power = nh->nh_weight;
+ }
+ } endfor_nexthops(fi);
+ fi->fib_power = power;
+- if (power <= 0) {
+- spin_unlock_bh(&fib_multipath_lock);
+- /* Race condition: route has just become dead. */
+- res->nh_sel = 0;
+- return;
+- }
++ if (power <= 0)
++ goto last_resort;
+ }
+
+
+@@ -979,20 +1071,40 @@
+
+ w = jiffies % fi->fib_power;
+
++ alive = 0;
+ change_nexthops(fi) {
+- if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
++ if (!(nh->nh_flags&RTNH_F_BADSTATE) && nh->nh_power) {
+ if ((w -= nh->nh_power) <= 0) {
+ nh->nh_power--;
+ fi->fib_power--;
+- res->nh_sel = nhsel;
+ spin_unlock_bh(&fib_multipath_lock);
++ res->nh_sel = nhsel;
+ return;
+ }
++ alive = 1;
++ }
++ } endfor_nexthops(fi);
++ if (alive) {
++ fi->fib_power = 0;
++ goto repeat;
++ }
++
++last_resort:
++
++ for_nexthops(fi) {
++ if (!(nh->nh_flags&RTNH_F_DEAD)) {
++ if (key->oif && key->oif != nh->nh_oif)
++ continue;
++ if (key->gw && key->gw != nh->nh_gw &&
++ nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
++ continue;
++ spin_unlock_bh(&fib_multipath_lock);
++ res->nh_sel = nhsel;
++ return;
+ }
+ } endfor_nexthops(fi);
+
+ /* Race condition: route has just become dead. */
+- res->nh_sel = 0;
+ spin_unlock_bh(&fib_multipath_lock);
+ }
+ #endif
+diff -ur v2.4.29/linux/net/ipv4/ip_nat_dumb.c linux/net/ipv4/ip_nat_dumb.c
+--- v2.4.29/linux/net/ipv4/ip_nat_dumb.c 2001-11-13 03:25:26.000000000 +0200
++++ linux/net/ipv4/ip_nat_dumb.c 2005-01-20 09:55:47.001651520 +0200
+@@ -124,6 +124,7 @@
+ key.dst = ciph->saddr;
+ key.iif = skb->dev->ifindex;
+ key.oif = 0;
++ key.gw = 0;
+ #ifdef CONFIG_IP_ROUTE_TOS
+ key.tos = RT_TOS(ciph->tos);
+ #endif
+diff -ur v2.4.29/linux/net/ipv4/netfilter/ip_fw_compat_masq.c linux/net/ipv4/netfilter/ip_fw_compat_masq.c
+--- v2.4.29/linux/net/ipv4/netfilter/ip_fw_compat_masq.c 2005-01-20 09:25:34.000000000 +0200
++++ linux/net/ipv4/netfilter/ip_fw_compat_masq.c 2005-01-20 09:55:47.001651520 +0200
+@@ -41,6 +41,10 @@
+ enum ip_conntrack_info ctinfo;
+ struct ip_conntrack *ct;
+ unsigned int ret;
++ struct rtable *rt, *skb_rt;
++ struct net_device *skb_dev;
++ __u32 saddr;
++ int new;
+
+ /* Sorry, only ICMP, TCP and UDP. */
+ if (iph->protocol != IPPROTO_ICMP
+@@ -64,22 +68,28 @@
+ }
+
+ info = &ct->nat.info;
++ iph = (*pskb)->nh.iph;
++ saddr = iph->saddr;
++ new = 0;
+
+ WRITE_LOCK(&ip_nat_lock);
+ /* Setup the masquerade, if not already */
+ if (!info->initialized) {
+ u_int32_t newsrc;
+- struct rtable *rt;
+ struct ip_nat_multi_range range;
+
++ skb_rt = (struct rtable *) (*pskb)->dst;
++ skb_dev = skb_rt->u.dst.dev;
+ /* Pass 0 instead of saddr, since it's going to be changed
+ anyway. */
+- if (ip_route_output(&rt, iph->daddr, 0, 0, 0) != 0) {
++ if (ip_route_output_lookup(&rt, iph->daddr, 0, RT_TOS(iph->tos),
++ skb_dev? skb_dev->ifindex : 0,
++ skb_dev? skb_rt->rt_gateway : 0) != 0) {
++ WRITE_UNLOCK(&ip_nat_lock);
+ DEBUGP("ipnat_rule_masquerade: Can't reroute.\n");
+ return NF_DROP;
+ }
+- newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway,
+- RT_SCOPE_UNIVERSE);
++ newsrc = rt->rt_src;
+ ip_rt_put(rt);
+ range = ((struct ip_nat_multi_range)
+ { 1,
+@@ -92,11 +102,31 @@
+ WRITE_UNLOCK(&ip_nat_lock);
+ return ret;
+ }
++ new = 1;
+ } else
+ DEBUGP("Masquerading already done on this conn.\n");
+ WRITE_UNLOCK(&ip_nat_lock);
+
+- return do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb);
++ ret = do_bindings(ct, ctinfo, info, NF_IP_POST_ROUTING, pskb);
++ if (ret != NF_ACCEPT || saddr == (*pskb)->nh.iph->saddr || new)
++ return ret;
++
++ iph = (*pskb)->nh.iph;
++ if (ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), 0) != 0)
++ return NF_DROP;
++
++ skb_rt = (struct rtable *) (*pskb)->dst;
++ skb_dev = skb_rt->u.dst.dev;
++ if (skb_dev != rt->u.dst.dev || rt->rt_gateway != skb_rt->rt_gateway) {
++ if (skb_dev != rt->u.dst.dev) {
++ /* TODO: check the new mtu and reply FRAG_NEEDED */
++ }
++ dst_release((*pskb)->dst);
++ (*pskb)->dst = &rt->u.dst;
++ } else {
++ ip_rt_put(rt);
++ }
++ return NF_ACCEPT;
+ }
+
+ void
+diff -ur v2.4.29/linux/net/ipv4/netfilter/ip_nat_core.c linux/net/ipv4/netfilter/ip_nat_core.c
+--- v2.4.29/linux/net/ipv4/netfilter/ip_nat_core.c 2005-01-20 09:25:34.000000000 +0200
++++ linux/net/ipv4/netfilter/ip_nat_core.c 2005-01-20 09:55:47.002651368 +0200
+@@ -994,6 +994,60 @@
+ return NF_ACCEPT;
+ }
+
++unsigned int
++ip_nat_route_input(unsigned int hooknum,
++ struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ int (*okfn)(struct sk_buff *))
++{
++ struct sk_buff *skb = *pskb;
++ struct iphdr *iph;
++ struct ip_conntrack *ct;
++ enum ip_conntrack_info ctinfo;
++ struct ip_nat_info *info;
++ enum ip_conntrack_dir dir;
++ __u32 saddr;
++ int i;
++
++ if (!(ct = ip_conntrack_get(skb, &ctinfo)))
++ return NF_ACCEPT;
++
++ info = &ct->nat.info;
++ if (!info->initialized)
++ return NF_ACCEPT;
++
++ if (skb->dst)
++ return NF_ACCEPT;
++
++ if (skb->len < sizeof(struct iphdr))
++ return NF_ACCEPT;
++
++ iph = skb->nh.iph;
++ saddr = iph->saddr;
++ hooknum = NF_IP_POST_ROUTING;
++ dir = CTINFO2DIR(ctinfo);
++
++ READ_LOCK(&ip_nat_lock);
++ for (i = 0; i < info->num_manips; i++) {
++ if (info->manips[i].direction == dir
++ && info->manips[i].hooknum == hooknum
++ && info->manips[i].maniptype == IP_NAT_MANIP_SRC) {
++ saddr = info->manips[i].manip.ip;
++ }
++ }
++ READ_UNLOCK(&ip_nat_lock);
++
++ if (saddr == iph->saddr)
++ return NF_ACCEPT;
++
++ if (ip_route_input_lookup(skb, iph->daddr, iph->saddr, iph->tos,
++ skb->dev, saddr))
++ return NF_DROP;
++
++ return NF_ACCEPT;
++}
++
+ int __init ip_nat_init(void)
+ {
+ size_t i;
+diff -ur v2.4.29/linux/net/ipv4/netfilter/ip_nat_standalone.c linux/net/ipv4/netfilter/ip_nat_standalone.c
+--- v2.4.29/linux/net/ipv4/netfilter/ip_nat_standalone.c 2005-01-20 09:25:34.000000000 +0200
++++ linux/net/ipv4/netfilter/ip_nat_standalone.c 2005-01-20 09:55:47.002651368 +0200
+@@ -241,6 +241,9 @@
+ /* Before packet filtering, change destination */
+ static struct nf_hook_ops ip_nat_in_ops
+ = { { NULL, NULL }, ip_nat_in, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_NAT_DST };
++/* Before routing, route before mangling */
++static struct nf_hook_ops ip_nat_inr_ops
++= { { NULL, NULL }, ip_nat_route_input, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_LAST-1 };
+ /* After packet filtering, change source */
+ static struct nf_hook_ops ip_nat_out_ops
+ = { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC};
+@@ -309,10 +312,15 @@
+ printk("ip_nat_init: can't register in hook.\n");
+ goto cleanup_nat;
+ }
++ ret = nf_register_hook(&ip_nat_inr_ops);
++ if (ret < 0) {
++ printk("ip_nat_init: can't register inr hook.\n");
++ goto cleanup_inops;
++ }
+ ret = nf_register_hook(&ip_nat_out_ops);
+ if (ret < 0) {
+ printk("ip_nat_init: can't register out hook.\n");
+- goto cleanup_inops;
++ goto cleanup_inrops;
+ }
+ ret = nf_register_hook(&ip_nat_local_out_ops);
+ if (ret < 0) {
+@@ -332,6 +340,8 @@
+ nf_unregister_hook(&ip_nat_local_out_ops);
+ cleanup_outops:
+ nf_unregister_hook(&ip_nat_out_ops);
++ cleanup_inrops:
++ nf_unregister_hook(&ip_nat_inr_ops);
+ cleanup_inops:
+ nf_unregister_hook(&ip_nat_in_ops);
+ cleanup_nat:
+diff -ur v2.4.29/linux/net/ipv4/netfilter/ipt_MASQUERADE.c linux/net/ipv4/netfilter/ipt_MASQUERADE.c
+--- v2.4.29/linux/net/ipv4/netfilter/ipt_MASQUERADE.c 2005-01-20 09:25:34.000000000 +0200
++++ linux/net/ipv4/netfilter/ipt_MASQUERADE.c 2005-01-20 09:55:47.003651216 +0200
+@@ -87,7 +87,8 @@
+ key.dst = (*pskb)->nh.iph->daddr;
+ key.src = 0; /* Unknown: that's what we're trying to establish */
+ key.tos = RT_TOS((*pskb)->nh.iph->tos)|RTO_CONN;
+- key.oif = 0;
++ key.oif = out->ifindex;
++ key.gw = ((struct rtable *) (*pskb)->dst)->rt_gateway;
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+ key.fwmark = (*pskb)->nfmark;
+ #endif
+@@ -98,13 +99,6 @@
+ " No route: Rusty's brain broke!\n");
+ return NF_DROP;
+ }
+- if (rt->u.dst.dev != out) {
+- if (net_ratelimit())
+- printk("MASQUERADE:"
+- " Route sent us somewhere else.\n");
+- ip_rt_put(rt);
+- return NF_DROP;
+- }
+
+ newsrc = rt->rt_src;
+ DEBUGP("newsrc = %u.%u.%u.%u\n", NIPQUAD(newsrc));
+diff -ur v2.4.29/linux/net/ipv4/route.c linux/net/ipv4/route.c
+--- v2.4.29/linux/net/ipv4/route.c 2004-11-18 08:30:33.000000000 +0200
++++ linux/net/ipv4/route.c 2005-01-20 09:55:47.004651064 +0200
+@@ -919,6 +919,7 @@
+
+ /* Gateway is different ... */
+ rt->rt_gateway = new_gw;
++ if (rt->key.gw) rt->key.gw = new_gw;
+
+ /* Redirect received -> path was valid */
+ dst_confirm(&rth->u.dst);
+@@ -1343,6 +1344,7 @@
+ rth->key.fwmark = skb->nfmark;
+ #endif
+ rth->key.src = saddr;
++ rth->key.lsrc = 0;
+ rth->rt_src = saddr;
+ #ifdef CONFIG_IP_ROUTE_NAT
+ rth->rt_dst_map = daddr;
+@@ -1356,6 +1358,7 @@
+ rth->u.dst.dev = &loopback_dev;
+ dev_hold(rth->u.dst.dev);
+ rth->key.oif = 0;
++ rth->key.gw = 0;
+ rth->rt_gateway = daddr;
+ rth->rt_spec_dst= spec_dst;
+ rth->rt_type = RTN_MULTICAST;
+@@ -1395,7 +1398,7 @@
+ */
+
+ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
+- u8 tos, struct net_device *dev)
++ u8 tos, struct net_device *dev, u32 lsrc)
+ {
+ struct rt_key key;
+ struct fib_result res;
+@@ -1415,16 +1418,17 @@
+ goto out;
+
+ key.dst = daddr;
+- key.src = saddr;
++ key.src = lsrc? : saddr;
+ key.tos = tos;
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+ key.fwmark = skb->nfmark;
+ #endif
+- key.iif = dev->ifindex;
++ key.iif = lsrc? loopback_dev.ifindex : dev->ifindex;
+ key.oif = 0;
++ key.gw = 0;
+ key.scope = RT_SCOPE_UNIVERSE;
+
+- hash = rt_hash_code(daddr, saddr ^ (key.iif << 5), tos);
++ hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5), tos);
+
+ /* Check for the most weird martians, which can be not detected
+ by fib_lookup.
+@@ -1445,6 +1449,12 @@
+ if (BADCLASS(daddr) || ZERONET(daddr) || LOOPBACK(daddr))
+ goto martian_destination;
+
++ if (lsrc) {
++ if (MULTICAST(lsrc) || BADCLASS(lsrc) ||
++ ZERONET(lsrc) || LOOPBACK(lsrc))
++ goto e_inval;
++ }
++
+ /*
+ * Now we are ready to route packet.
+ */
+@@ -1454,6 +1464,10 @@
+ goto no_route;
+ }
+ free_res = 1;
++ if (lsrc && res.type != RTN_UNICAST && res.type != RTN_NAT)
++ goto e_inval;
++ key.iif = dev->ifindex;
++ key.src = saddr;
+
+ rt_cache_stat[smp_processor_id()].in_slow_tot++;
+
+@@ -1464,7 +1478,7 @@
+
+ if (1) {
+ u32 src_map = saddr;
+- if (res.r)
++ if (res.r && !lsrc)
+ src_map = fib_rules_policy(saddr, &res, &flags);
+
+ if (res.type == RTN_NAT) {
+@@ -1503,8 +1517,9 @@
+ if (res.type != RTN_UNICAST)
+ goto martian_destination;
+
++ fib_select_default(&key, &res);
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+- if (res.fi->fib_nhs > 1 && key.oif == 0)
++ if (res.fi->fib_nhs > 1)
+ fib_select_multipath(&key, &res);
+ #endif
+ out_dev = in_dev_get(FIB_RES_DEV(res));
+@@ -1524,6 +1539,7 @@
+ flags |= RTCF_DIRECTSRC;
+
+ if (out_dev == in_dev && err && !(flags & (RTCF_NAT | RTCF_MASQ)) &&
++ !lsrc &&
+ (IN_DEV_SHARED_MEDIA(out_dev) ||
+ inet_addr_onlink(out_dev, saddr, FIB_RES_GW(res))))
+ flags |= RTCF_DOREDIRECT;
+@@ -1550,6 +1566,7 @@
+ #endif
+ rth->key.src = saddr;
+ rth->rt_src = saddr;
++ rth->key.lsrc = lsrc;
+ rth->rt_gateway = daddr;
+ #ifdef CONFIG_IP_ROUTE_NAT
+ rth->rt_src_map = key.src;
+@@ -1562,6 +1579,7 @@
+ rth->u.dst.dev = out_dev->dev;
+ dev_hold(rth->u.dst.dev);
+ rth->key.oif = 0;
++ rth->key.gw = 0;
+ rth->rt_spec_dst= spec_dst;
+
+ rth->u.dst.input = ip_forward;
+@@ -1572,7 +1590,8 @@
+ rth->rt_flags = flags;
+
+ #ifdef CONFIG_NET_FASTROUTE
+- if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT))) {
++ if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT)) &&
++ !lsrc) {
+ struct net_device *odev = rth->u.dst.dev;
+ if (odev != dev &&
+ dev->accept_fastpath &&
+@@ -1595,6 +1614,8 @@
+ brd_input:
+ if (skb->protocol != htons(ETH_P_IP))
+ goto e_inval;
++ if (lsrc)
++ goto e_inval;
+
+ if (ZERONET(saddr))
+ spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
+@@ -1627,6 +1648,7 @@
+ #endif
+ rth->key.src = saddr;
+ rth->rt_src = saddr;
++ rth->key.lsrc = 0;
+ #ifdef CONFIG_IP_ROUTE_NAT
+ rth->rt_dst_map = key.dst;
+ rth->rt_src_map = key.src;
+@@ -1639,6 +1661,7 @@
+ rth->u.dst.dev = &loopback_dev;
+ dev_hold(rth->u.dst.dev);
+ rth->key.oif = 0;
++ rth->key.gw = 0;
+ rth->rt_gateway = daddr;
+ rth->rt_spec_dst= spec_dst;
+ rth->u.dst.input= ip_local_deliver;
+@@ -1704,8 +1727,9 @@
+ goto e_inval;
+ }
+
+-int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
+- u8 tos, struct net_device *dev)
++static inline int
++ip_route_input_cached(struct sk_buff *skb, u32 daddr, u32 saddr,
++ u8 tos, struct net_device *dev, u32 lsrc)
+ {
+ struct rtable * rth;
+ unsigned hash;
+@@ -1719,6 +1743,7 @@
+ if (rth->key.dst == daddr &&
+ rth->key.src == saddr &&
+ rth->key.iif == iif &&
++ rth->key.lsrc == lsrc &&
+ rth->key.oif == 0 &&
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+ rth->key.fwmark == skb->nfmark &&
+@@ -1766,9 +1791,21 @@
+ read_unlock(&inetdev_lock);
+ return -EINVAL;
+ }
+- return ip_route_input_slow(skb, daddr, saddr, tos, dev);
++ return ip_route_input_slow(skb, daddr, saddr, tos, dev, lsrc);
++}
++
++int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
++ u8 tos, struct net_device *dev)
++{
++ return ip_route_input_cached(skb, daddr, saddr, tos, dev, 0);
+ }
+
++int ip_route_input_lookup(struct sk_buff *skb, u32 daddr, u32 saddr,
++ u8 tos, struct net_device *dev, u32 lsrc)
++{
++ return ip_route_input_cached(skb, daddr, saddr, tos, dev, lsrc);
++}
++
+ /*
+ * Major route resolver routine.
+ */
+@@ -1791,6 +1828,7 @@
+ key.tos = tos & IPTOS_RT_MASK;
+ key.iif = loopback_dev.ifindex;
+ key.oif = oldkey->oif;
++ key.gw = oldkey->gw;
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+ key.fwmark = oldkey->fwmark;
+ #endif
+@@ -1880,6 +1918,7 @@
+ dev_out = &loopback_dev;
+ dev_hold(dev_out);
+ key.oif = loopback_dev.ifindex;
++ key.gw = 0;
+ res.type = RTN_LOCAL;
+ flags |= RTCF_LOCAL;
+ goto make_route;
+@@ -1887,7 +1926,7 @@
+
+ if (fib_lookup(&key, &res)) {
+ res.fi = NULL;
+- if (oldkey->oif) {
++ if (oldkey->oif && dev_out->flags&IFF_UP) {
+ /* Apparently, routing tables are wrong. Assume,
+ that the destination is on link.
+
+@@ -1930,6 +1969,7 @@
+ dev_out = &loopback_dev;
+ dev_hold(dev_out);
+ key.oif = dev_out->ifindex;
++ key.gw = 0;
+ if (res.fi)
+ fib_info_put(res.fi);
+ res.fi = NULL;
+@@ -1937,13 +1977,12 @@
+ goto make_route;
+ }
+
++ if (res.type == RTN_UNICAST)
++ fib_select_default(&key, &res);
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+- if (res.fi->fib_nhs > 1 && key.oif == 0)
++ if (res.fi->fib_nhs > 1)
+ fib_select_multipath(&key, &res);
+- else
+ #endif
+- if (!res.prefixlen && res.type == RTN_UNICAST && !key.oif)
+- fib_select_default(&key, &res);
+
+ if (!key.src)
+ key.src = FIB_RES_PREFSRC(res);
+@@ -2001,7 +2040,9 @@
+ rth->key.tos = tos;
+ rth->key.src = oldkey->src;
+ rth->key.iif = 0;
++ rth->key.lsrc = 0;
+ rth->key.oif = oldkey->oif;
++ rth->key.gw = oldkey->gw;
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+ rth->key.fwmark = oldkey->fwmark;
+ #endif
+@@ -2080,6 +2121,7 @@
+ rth->key.src == key->src &&
+ rth->key.iif == 0 &&
+ rth->key.oif == key->oif &&
++ rth->key.gw == key->gw &&
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+ rth->key.fwmark == key->fwmark &&
+ #endif
+diff -ur v2.4.29/linux/net/netsyms.c linux/net/netsyms.c
+--- v2.4.29/linux/net/netsyms.c 2005-01-20 09:25:34.000000000 +0200
++++ linux/net/netsyms.c 2005-01-20 09:55:47.005650912 +0200
+@@ -260,6 +260,7 @@
+ EXPORT_SYMBOL(inet_unregister_protosw);
+ EXPORT_SYMBOL(ip_route_output_key);
+ EXPORT_SYMBOL(ip_route_input);
++EXPORT_SYMBOL(ip_route_input_lookup);
+ EXPORT_SYMBOL(icmp_send);
+ EXPORT_SYMBOL(icmp_statistics);
+ EXPORT_SYMBOL(icmp_err_convert);
diff --git a/target/linux/generic-2.6/files/init b/target/linux/generic-2.6/files/init
new file mode 100755
index 0000000..1fa6a7f
--- /dev/null
+++ b/target/linux/generic-2.6/files/init
@@ -0,0 +1,82 @@
+#!/bin/sh
+# Copyright (C) 2006 OpenWrt.org
+
+export PATH=/bin:/sbin:/usr/bin:/usr/sbin
+mount none /proc -t proc
+mount none /dev -t devfs
+mount non /dev/pts -t devpts
+
+# the root mount point can come from the kernel command line
+# or it can be overridden in the preinit.arch file
+[ -f /etc/preinit.arch ] && . /etc/preinit.arch
+
+# if we have no root parameter, just go to running from ramfs
+[ -z $rootfs ] && {
+ export NOMOUNT="No Root"
+ exec /sbin/init
+}
+
+#if we have a failsafe boot selected, dont bother
+#trying to find or wait for a root mount point
+[ -z "$FAILSAFE" ] || {
+ exec /bin/busybox init
+}
+
+# Load the modules we have in initramfs, this should
+# make the media accessible, but, it may take some time
+. /etc/functions.sh
+load_modules /etc/modules /etc/modules.d/*
+
+#wait 10 seconds for the disc to show up
+#usb stick typically takes 4 to 6 seconds
+#till it's readable
+#it's quite possible the disc never shows up
+#if we netbooted this kernel
+COUNTER=0
+while [ $COUNTER -lt 10 ]; do
+ sleep 1
+ [ -e $rootfs ] && let COUNTER=10;
+ let COUNTER=COUNTER+1
+done
+[ -e $rootfs ] || {
+ export FAILSAFE="NoDisc"
+ exec /bin/busybox init
+}
+
+# now we'll try mount it, again with a timeout
+# This will fail if the inserted stick is formatted
+# in a manner we dont understand
+COUNTER=0
+while [ $COUNTER -lt 10 ]; do
+ sleep 1
+ mount $rootfs /mnt
+ [ $? -eq "0" ] && let COUNTER=100;
+ let COUNTER=COUNTER+1
+done
+[ $? -ne "0" ] && {
+ export FAILSAFE="MountFail"
+ exec /bin/busybox init
+}
+
+#It mounted, lets look for a postinit file, again, give it time
+#I've seen this take 6 seconds to actually complete
+COUNTER=0
+while [ $COUNTER -lt 10 ]; do
+ sleep 1
+ [ -e /mnt/etc/banner ] && let COUNTER=10;
+ let COUNTER=COUNTER+1
+done
+[ -e /mnt/etc/banner ] || {
+ export FAILSAFE="No Openwrt FS"
+ exec /bin/busybox init
+}
+
+unset rootfs
+
+mount -o move /proc /mnt/proc
+mount -o move /dev /mnt/dev
+mount -o move /dev/pts /mnt/dev/pts
+mount -o move /tmp /mnt/tmp
+mount -o move /sys /mnt/sys
+mount none /tmp -t tmpfs
+exec switch_root -c /dev/console /mnt /sbin/init
diff --git a/target/linux/generic-2.6/patches/000-reenable_devfs.patch b/target/linux/generic-2.6/patches/000-reenable_devfs.patch
new file mode 100644
index 0000000..7871c4c
--- /dev/null
+++ b/target/linux/generic-2.6/patches/000-reenable_devfs.patch
@@ -0,0 +1,718 @@
+diff -ur linux-2.6.15-rc5/drivers/mtd/mtd_blkdevs.c linux-2.6.15-rc5-openwrt/drivers/mtd/mtd_blkdevs.c
+--- linux-2.6.15-rc5/drivers/mtd/mtd_blkdevs.c 2005-12-04 06:10:42.000000000 +0100
++++ linux-2.6.15-rc5-openwrt/drivers/mtd/mtd_blkdevs.c 2005-12-15 07:53:20.000000000 +0100
+@@ -21,6 +21,9 @@
+ #include <linux/init.h>
+ #include <asm/semaphore.h>
+ #include <asm/uaccess.h>
++#ifdef CONFIG_DEVFS_FS
++#include <linux/devfs_fs_kernel.h>
++#endif
+
+ static LIST_HEAD(blktrans_majors);
+
+@@ -302,6 +305,11 @@
+ snprintf(gd->disk_name, sizeof(gd->disk_name),
+ "%s%d", tr->name, new->devnum);
+
++#ifdef CONFIG_DEVFS_FS
++ snprintf(gd->devfs_name, sizeof(gd->devfs_name),
++ "%s/%c", tr->name, (tr->part_bits?'a':'0') + new->devnum);
++#endif
++
+ /* 2.5 has capacity in units of 512 bytes while still
+ having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */
+ set_capacity(gd, (new->size * new->blksize) >> 9);
+@@ -418,6 +426,10 @@
+ return ret;
+ }
+
++#ifdef CONFIG_DEVFS_FS
++ devfs_mk_dir(tr->name);
++#endif
++
+ INIT_LIST_HEAD(&tr->devs);
+ list_add(&tr->list, &blktrans_majors);
+
+@@ -450,6 +462,10 @@
+ tr->remove_dev(dev);
+ }
+
++#ifdef CONFIG_DEVFS_FS
++ devfs_remove(tr->name);
++#endif
++
+ blk_cleanup_queue(tr->blkcore_priv->rq);
+ unregister_blkdev(tr->major, tr->name);
+
+diff -ur linux-2.6.15-rc5/drivers/mtd/mtdchar.c linux-2.6.15-rc5-openwrt/drivers/mtd/mtdchar.c
+--- linux-2.6.15-rc5/drivers/mtd/mtdchar.c 2005-12-04 06:10:42.000000000 +0100
++++ linux-2.6.15-rc5-openwrt/drivers/mtd/mtdchar.c 2005-12-15 07:49:15.000000000 +0100
+@@ -19,19 +18,33 @@
+
+ #include <asm/uaccess.h>
+
++#ifdef CONFIG_DEVFS_FS
++#include <linux/devfs_fs_kernel.h>
++#else
++#include <linux/device.h>
++
+ static struct class *mtd_class;
++#endif
+
+ static void mtd_notify_add(struct mtd_info* mtd)
+ {
+ if (!mtd)
+ return;
+
++#ifdef CONFIG_DEVFS_FS
++ devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
++ S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index);
++
++ devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
++ S_IFCHR | S_IRUGO, "mtd/%dro", mtd->index);
++#else
+ class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
+ NULL, "mtd%d", mtd->index);
+
+ class_device_create(mtd_class, NULL,
+ MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
+ NULL, "mtd%dro", mtd->index);
++#endif
+ }
+
+ static void mtd_notify_remove(struct mtd_info* mtd)
+@@ -39,8 +52,13 @@
+ if (!mtd)
+ return;
+
++#ifdef CONFIG_DEVFS_FS
++ devfs_remove("mtd/%d", mtd->index);
++ devfs_remove("mtd/%dro", mtd->index);
++#else
+ class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
+ class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
++#endif
+ }
+
+ static struct mtd_notifier notifier = {
+@@ -48,6 +66,22 @@
+ .remove = mtd_notify_remove,
+ };
+
++#ifdef CONFIG_DEVFS_FS
++ static inline void mtdchar_devfs_init(void)
++ {
++ devfs_mk_dir("mtd");
++ register_mtd_user(&notifier);
++ }
++ static inline void mtdchar_devfs_exit(void)
++ {
++ unregister_mtd_user(&notifier);
++ devfs_remove("mtd");
++ }
++ #else /* !DEVFS */
++ #define mtdchar_devfs_init() do { } while(0)
++ #define mtdchar_devfs_exit() do { } while(0)
++#endif
++
+ /*
+ * We use file->private_data to store a pointer to the MTDdevice.
+ * Since alighment is at least 32 bits, we have 2 bits free for OTP
+@@ -643,6 +677,9 @@
+ return -EAGAIN;
+ }
+
++#ifdef CONFIG_DEVFS_FS
++ mtdchar_devfs_init();
++#else
+ mtd_class = class_create(THIS_MODULE, "mtd");
+
+ if (IS_ERR(mtd_class)) {
+@@ -652,13 +689,19 @@
+ }
+
+ register_mtd_user(&notifier);
++#endif
+ return 0;
+ }
+
+ static void __exit cleanup_mtdchar(void)
+ {
++
++#ifdef CONFIG_DEVFS_FS
++ mtdchar_devfs_exit();
++#else
+ unregister_mtd_user(&notifier);
+ class_destroy(mtd_class);
++#endif
+ unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
+ }
+
+diff -ur linux-2.6.15-rc5/fs/Kconfig linux-2.6.15-rc5-openwrt/fs/Kconfig
+--- linux-2.6.15-rc5/fs/Kconfig 2005-12-04 06:10:42.000000000 +0100
++++ linux-2.6.15-rc5-openwrt/fs/Kconfig 2005-12-15 07:44:01.000000000 +0100
+@@ -772,6 +772,56 @@
+ help
+ Exports the dump image of crashed kernel in ELF format.
+
++config DEVFS_FS
++ bool "/dev file system support (OBSOLETE)"
++ depends on EXPERIMENTAL
++ help
++ This is support for devfs, a virtual file system (like /proc) which
++ provides the file system interface to device drivers, normally found
++ in /dev. Devfs does not depend on major and minor number
++ allocations. Device drivers register entries in /dev which then
++ appear automatically, which means that the system administrator does
++ not have to create character and block special device files in the
++ /dev directory using the mknod command (or MAKEDEV script) anymore.
++
++ This is work in progress. If you want to use this, you *must* read
++ the material in <file:Documentation/filesystems/devfs/>, especially
++ the file README there.
++
++ Note that devfs no longer manages /dev/pts! If you are using UNIX98
++ ptys, you will also need to mount the /dev/pts filesystem (devpts).
++
++ Note that devfs has been obsoleted by udev,
++ <http://www.kernel.org/pub/linux/utils/kernel/hotplug/>.
++ It has been stripped down to a bare minimum and is only provided for
++ legacy installations that use its naming scheme which is
++ unfortunately different from the names normal Linux installations
++ use.
++
++ If unsure, say N.
++
++config DEVFS_MOUNT
++ bool "Automatically mount at boot"
++ depends on DEVFS_FS
++ help
++ This option appears if you have CONFIG_DEVFS_FS enabled. Setting
++ this to 'Y' will make the kernel automatically mount devfs onto /dev
++ when the system is booted, before the init thread is started.
++ You can override this with the "devfs=nomount" boot option.
++
++ If unsure, say N.
++
++config DEVFS_DEBUG
++ bool "Debug devfs"
++ depends on DEVFS_FS
++ help
++ If you say Y here, then the /dev file system code will generate
++ debugging messages. See the file
++ <file:Documentation/filesystems/devfs/boot-options> for more
++ details.
++
++ If unsure, say N.
++
+ config SYSFS
+ bool "sysfs file system support" if EMBEDDED
+ default y
+diff -ur linux-2.6.17/drivers/ieee1394/dv1394.c linux-2.6.17-devfs/drivers/ieee1394/dv1394.c
+--- linux-2.6.17/drivers/ieee1394/dv1394.c 2006-06-17 18:49:35.000000000 -0700
++++ linux-2.6.17-devfs/drivers/ieee1394/dv1394.c 2006-08-25 11:06:18.000000000 -0700
+@@ -73,7 +73,7 @@
+ - fix all XXX showstoppers
+ - disable IR/IT DMA interrupts on shutdown
+ - flush pci writes to the card by issuing a read
+- - character device dispatching
++ - devfs and character device dispatching (* needs testing with Linux 2.2.x)
+ - switch over to the new kernel DMA API (pci_map_*()) (* needs testing on platforms with IOMMU!)
+ - keep all video_cards in a list (for open() via chardev), set file->private_data = video
+ - dv1394_poll should indicate POLLIN when receiving buffers are available
+@@ -1096,6 +1096,7 @@
+
+ init.api_version = DV1394_API_VERSION;
+ init.n_frames = DV1394_MAX_FRAMES / 4;
++ /* the following are now set via devfs */
+ init.channel = video->channel;
+ init.format = video->pal_or_ntsc;
+ init.cip_n = video->cip_n;
+@@ -1790,6 +1791,8 @@
+ {
+ struct video_card *video = NULL;
+
++ /* if the device was opened through devfs, then file->private_data
++ has already been set to video by devfs */
+ if (file->private_data) {
+ video = (struct video_card*) file->private_data;
+
+@@ -2208,7 +2211,7 @@
+ video = kzalloc(sizeof(*video), GFP_KERNEL);
+ if (!video) {
+ printk(KERN_ERR "dv1394: cannot allocate video_card\n");
+- return -1;
++ goto err;
+ }
+
+ video->ohci = ohci;
+@@ -2263,14 +2266,37 @@
+ list_add_tail(&video->list, &dv1394_cards);
+ spin_unlock_irqrestore(&dv1394_cards_lock, flags);
+
++ if (devfs_mk_cdev(MKDEV(IEEE1394_MAJOR,
++ IEEE1394_MINOR_BLOCK_DV1394*16 + video->id),
++ S_IFCHR|S_IRUGO|S_IWUGO,
++ "ieee1394/dv/host%d/%s/%s",
++ (video->id>>2),
++ (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
++ (video->mode == MODE_RECEIVE ? "in" : "out")) < 0)
++ goto err_free;
++
+ debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id);
++
+ return 0;
++
++ err_free:
++ kfree(video);
++ err:
++ return -1;
+ }
+
+ static void dv1394_un_init(struct video_card *video)
+ {
++ char buf[32];
++
+ /* obviously nobody has the driver open at this point */
+ do_dv1394_shutdown(video, 1);
++ snprintf(buf, sizeof(buf), "dv/host%d/%s/%s", (video->id >> 2),
++ (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
++ (video->mode == MODE_RECEIVE ? "in" : "out")
++ );
++
++ devfs_remove("ieee1394/%s", buf);
+ kfree(video);
+ }
+
+@@ -2307,6 +2333,9 @@
+
+ class_device_destroy(hpsb_protocol_class,
+ MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)));
++ devfs_remove("ieee1394/dv/host%d/NTSC", id);
++ devfs_remove("ieee1394/dv/host%d/PAL", id);
++ devfs_remove("ieee1394/dv/host%d", id);
+ }
+
+ static void dv1394_add_host (struct hpsb_host *host)
+@@ -2323,6 +2352,9 @@
+ class_device_create(hpsb_protocol_class, NULL, MKDEV(
+ IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16 + (id<<2)),
+ NULL, "dv1394-%d", id);
++ devfs_mk_dir("ieee1394/dv/host%d", id);
++ devfs_mk_dir("ieee1394/dv/host%d/NTSC", id);
++ devfs_mk_dir("ieee1394/dv/host%d/PAL", id);
+
+ dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
+ dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT);
+@@ -2579,8 +2611,10 @@
+ static void __exit dv1394_exit_module(void)
+ {
+ hpsb_unregister_protocol(&dv1394_driver);
++
+ hpsb_unregister_highlevel(&dv1394_highlevel);
+ cdev_del(&dv1394_cdev);
++ devfs_remove("ieee1394/dv");
+ }
+
+ static int __init dv1394_init_module(void)
+@@ -2596,12 +2630,15 @@
+ return ret;
+ }
+
++ devfs_mk_dir("ieee1394/dv");
++
+ hpsb_register_highlevel(&dv1394_highlevel);
+
+ ret = hpsb_register_protocol(&dv1394_driver);
+ if (ret) {
+ printk(KERN_ERR "dv1394: failed to register protocol\n");
+ hpsb_unregister_highlevel(&dv1394_highlevel);
++ devfs_remove("ieee1394/dv");
+ cdev_del(&dv1394_cdev);
+ return ret;
+ }
+diff -ur linux-2.6.17/drivers/ieee1394/ieee1394_core.c linux-2.6.17-devfs/drivers/ieee1394/ieee1394_core.c
+--- linux-2.6.17/drivers/ieee1394/ieee1394_core.c 2006-06-17 18:49:35.000000000 -0700
++++ linux-2.6.17-devfs/drivers/ieee1394/ieee1394_core.c 2006-08-25 11:06:18.000000000 -0700
+@@ -1078,10 +1078,17 @@
+ goto exit_release_kernel_thread;
+ }
+
++ /* actually this is a non-fatal error */
++ ret = devfs_mk_dir("ieee1394");
++ if (ret < 0) {
++ HPSB_ERR("unable to make devfs dir for device major %d!\n", IEEE1394_MAJOR);
++ goto release_chrdev;
++ }
++
+ ret = bus_register(&ieee1394_bus_type);
+ if (ret < 0) {
+ HPSB_INFO("bus register failed");
+- goto release_chrdev;
++ goto release_devfs;
+ }
+
+ for (i = 0; fw_bus_attrs[i]; i++) {
+@@ -1092,7 +1099,7 @@
+ fw_bus_attrs[i--]);
+ }
+ bus_unregister(&ieee1394_bus_type);
+- goto release_chrdev;
++ goto release_devfs;
+ }
+ }
+
+@@ -1145,6 +1152,8 @@
+ for (i = 0; fw_bus_attrs[i]; i++)
+ bus_remove_file(&ieee1394_bus_type, fw_bus_attrs[i]);
+ bus_unregister(&ieee1394_bus_type);
++release_devfs:
++ devfs_remove("ieee1394");
+ release_chrdev:
+ unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
+ exit_release_kernel_thread:
+@@ -1182,6 +1191,7 @@
+ hpsb_cleanup_config_roms();
+
+ unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
++ devfs_remove("ieee1394");
+ }
+
+ module_init(ieee1394_init);
+diff -ur linux-2.6.17/drivers/ieee1394/ieee1394_core.h linux-2.6.17-devfs/drivers/ieee1394/ieee1394_core.h
+--- linux-2.6.17/drivers/ieee1394/ieee1394_core.h 2006-06-17 18:49:35.000000000 -0700
++++ linux-2.6.17-devfs/drivers/ieee1394/ieee1394_core.h 2006-08-25 11:06:18.000000000 -0700
+@@ -3,6 +3,7 @@
+ #define _IEEE1394_CORE_H
+
+ #include <linux/slab.h>
++#include <linux/devfs_fs_kernel.h>
+ #include <asm/atomic.h>
+ #include <asm/semaphore.h>
+ #include "hosts.h"
+diff -ur linux-2.6.17/drivers/ieee1394/raw1394.c linux-2.6.17-devfs/drivers/ieee1394/raw1394.c
+--- linux-2.6.17/drivers/ieee1394/raw1394.c 2006-06-17 18:49:35.000000000 -0700
++++ linux-2.6.17-devfs/drivers/ieee1394/raw1394.c 2006-08-25 11:06:18.000000000 -0700
+@@ -41,6 +41,7 @@
+ #include <linux/cdev.h>
+ #include <asm/uaccess.h>
+ #include <asm/atomic.h>
++#include <linux/devfs_fs_kernel.h>
+ #include <linux/compat.h>
+
+ #include "csr1212.h"
+@@ -2998,6 +2999,9 @@
+ goto out_unreg;
+ }
+
++ devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16),
++ S_IFCHR | S_IRUSR | S_IWUSR, RAW1394_DEVICE_NAME);
++
+ cdev_init(&raw1394_cdev, &raw1394_fops);
+ raw1394_cdev.owner = THIS_MODULE;
+ kobject_set_name(&raw1394_cdev.kobj, RAW1394_DEVICE_NAME);
+@@ -3019,6 +3023,7 @@
+ goto out;
+
+ out_dev:
++ devfs_remove(RAW1394_DEVICE_NAME);
+ class_device_destroy(hpsb_protocol_class,
+ MKDEV(IEEE1394_MAJOR,
+ IEEE1394_MINOR_BLOCK_RAW1394 * 16));
+@@ -3034,6 +3039,7 @@
+ MKDEV(IEEE1394_MAJOR,
+ IEEE1394_MINOR_BLOCK_RAW1394 * 16));
+ cdev_del(&raw1394_cdev);
++ devfs_remove(RAW1394_DEVICE_NAME);
+ hpsb_unregister_highlevel(&raw1394_highlevel);
+ hpsb_unregister_protocol(&raw1394_driver);
+ }
+diff -ur linux-2.6.17/drivers/ieee1394/video1394.c linux-2.6.17-devfs/drivers/ieee1394/video1394.c
+--- linux-2.6.17/drivers/ieee1394/video1394.c 2006-06-17 18:49:35.000000000 -0700
++++ linux-2.6.17-devfs/drivers/ieee1394/video1394.c 2006-08-25 11:06:18.000000000 -0700
+@@ -42,6 +42,7 @@
+ #include <linux/poll.h>
+ #include <linux/smp_lock.h>
+ #include <linux/delay.h>
++#include <linux/devfs_fs_kernel.h>
+ #include <linux/bitops.h>
+ #include <linux/types.h>
+ #include <linux/vmalloc.h>
+@@ -1321,6 +1322,9 @@
+ class_device_create(hpsb_protocol_class, NULL, MKDEV(
+ IEEE1394_MAJOR, minor),
+ NULL, "%s-%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
++ devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, minor),
++ S_IFCHR | S_IRUSR | S_IWUSR,
++ "%s/%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
+ }
+
+
+@@ -1328,9 +1332,12 @@
+ {
+ struct ti_ohci *ohci = hpsb_get_hostinfo(&video1394_highlevel, host);
+
+- if (ohci)
++ if (ohci) {
+ class_device_destroy(hpsb_protocol_class, MKDEV(IEEE1394_MAJOR,
+ IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->host->id));
++ devfs_remove("%s/%d", VIDEO1394_DRIVER_NAME, ohci->host->id);
++ }
++
+ return;
+ }
+
+@@ -1471,8 +1478,12 @@
+ static void __exit video1394_exit_module (void)
+ {
+ hpsb_unregister_protocol(&video1394_driver);
++
+ hpsb_unregister_highlevel(&video1394_highlevel);
++
++ devfs_remove(VIDEO1394_DRIVER_NAME);
+ cdev_del(&video1394_cdev);
++
+ PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
+ }
+
+@@ -1489,12 +1500,15 @@
+ return ret;
+ }
+
++ devfs_mk_dir(VIDEO1394_DRIVER_NAME);
++
+ hpsb_register_highlevel(&video1394_highlevel);
+
+ ret = hpsb_register_protocol(&video1394_driver);
+ if (ret) {
+ PRINT_G(KERN_ERR, "video1394: failed to register protocol");
+ hpsb_unregister_highlevel(&video1394_highlevel);
++ devfs_remove(VIDEO1394_DRIVER_NAME);
+ cdev_del(&video1394_cdev);
+ return ret;
+ }
+diff -ur linux-2.6.17/drivers/scsi/osst.c linux-2.6.17-devfs/drivers/scsi/osst.c
+--- linux-2.6.17/drivers/scsi/osst.c 2006-06-17 18:49:35.000000000 -0700
++++ linux-2.6.17-devfs/drivers/scsi/osst.c 2006-08-25 11:06:18.000000000 -0700
+@@ -48,6 +48,7 @@
+ #include <linux/vmalloc.h>
+ #include <linux/blkdev.h>
+ #include <linux/moduleparam.h>
++#include <linux/devfs_fs_kernel.h>
+ #include <linux/delay.h>
+ #include <linux/jiffies.h>
+ #include <asm/uaccess.h>
+@@ -5721,7 +5722,7 @@
+ struct st_partstat * STps;
+ struct osst_buffer * buffer;
+ struct gendisk * drive;
+- int i, dev_num;
++ int i, mode, dev_num;
+
+ if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
+ return -ENODEV;
+@@ -5857,6 +5858,18 @@
+ snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
+ osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
+ }
++ for (mode = 0; mode < ST_NBR_MODES; ++mode) {
++ /* Rewind entry */
++ devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5)),
++ S_IFCHR | S_IRUGO | S_IWUGO,
++ "%s/ot%s", SDp->devfs_name, osst_formats[mode]);
++
++ /* No-rewind entry */
++ devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5) + 128),
++ S_IFCHR | S_IRUGO | S_IWUGO,
++ "%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
++ }
++ drive->number = devfs_register_tape(SDp->devfs_name);
+
+ sdev_printk(KERN_INFO, SDp,
+ "osst :I: Attached OnStream %.5s tape as %s\n",
+@@ -5873,7 +5886,7 @@
+ {
+ struct scsi_device * SDp = to_scsi_device(dev);
+ struct osst_tape * tpnt;
+- int i;
++ int i, mode;
+
+ if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
+ return 0;
+@@ -5884,6 +5897,11 @@
+ osst_sysfs_destroy(MKDEV(OSST_MAJOR, i));
+ osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128));
+ tpnt->device = NULL;
++ for (mode = 0; mode < ST_NBR_MODES; ++mode) {
++ devfs_remove("%s/ot%s", SDp->devfs_name, osst_formats[mode]);
++ devfs_remove("%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
++ }
++ devfs_unregister_tape(tpnt->drive->number);
+ put_disk(tpnt->drive);
+ os_scsi_tapes[i] = NULL;
+ osst_nr_dev--;
+diff -ur linux-2.6.17/drivers/scsi/scsi.c linux-2.6.17-devfs/drivers/scsi/scsi.c
+--- linux-2.6.17/drivers/scsi/scsi.c 2006-06-17 18:49:35.000000000 -0700
++++ linux-2.6.17-devfs/drivers/scsi/scsi.c 2006-08-25 11:07:42.000000000 -0700
+@@ -48,6 +48,7 @@
+ #include <linux/delay.h>
+ #include <linux/init.h>
+ #include <linux/completion.h>
++#include <linux/devfs_fs_kernel.h>
+ #include <linux/unistd.h>
+ #include <linux/spinlock.h>
+ #include <linux/kmod.h>
+@@ -1247,6 +1248,7 @@
+ for_each_possible_cpu(i)
+ INIT_LIST_HEAD(&per_cpu(scsi_done_q, i));
+
++ devfs_mk_dir("scsi");
+ printk(KERN_NOTICE "SCSI subsystem initialized\n");
+ return 0;
+
+@@ -1271,6 +1273,7 @@
+ scsi_exit_sysctl();
+ scsi_exit_hosts();
+ scsi_exit_devinfo();
++ devfs_remove("scsi");
+ scsi_exit_procfs();
+ scsi_exit_queue();
+ }
+diff -ur linux-2.6.17/drivers/scsi/scsi_scan.c linux-2.6.17-devfs/drivers/scsi/scsi_scan.c
+--- linux-2.6.17/drivers/scsi/scsi_scan.c 2006-06-17 18:49:35.000000000 -0700
++++ linux-2.6.17-devfs/drivers/scsi/scsi_scan.c 2006-08-25 11:06:18.000000000 -0700
+@@ -716,8 +716,12 @@
+ if (inq_result[7] & 0x10)
+ sdev->sdtr = 1;
+
++ sprintf(sdev->devfs_name, "scsi/host%d/bus%d/target%d/lun%d",
++ sdev->host->host_no, sdev->channel,
++ sdev->id, sdev->lun);
++
+ /*
+- * End sysfs code.
++ * End driverfs/devfs code.
+ */
+
+ if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) &&
+diff -ur linux-2.6.17/drivers/scsi/sd.c linux-2.6.17-devfs/drivers/scsi/sd.c
+--- linux-2.6.17/drivers/scsi/sd.c 2006-06-17 18:49:35.000000000 -0700
++++ linux-2.6.17-devfs/drivers/scsi/sd.c 2006-08-25 11:06:18.000000000 -0700
+@@ -1683,6 +1683,8 @@
+ 'a' + m1, 'a' + m2, 'a' + m3);
+ }
+
++ strcpy(gd->devfs_name, sdp->devfs_name);
++
+ gd->private_data = &sdkp->driver;
+ gd->queue = sdkp->device->request_queue;
+
+diff -ur linux-2.6.17/drivers/scsi/sg.c linux-2.6.17-devfs/drivers/scsi/sg.c
+--- linux-2.6.17/drivers/scsi/sg.c 2006-06-17 18:49:35.000000000 -0700
++++ linux-2.6.17-devfs/drivers/scsi/sg.c 2006-08-25 11:06:18.000000000 -0700
+@@ -44,6 +44,7 @@
+ #include <linux/poll.h>
+ #include <linux/smp_lock.h>
+ #include <linux/moduleparam.h>
++#include <linux/devfs_fs_kernel.h>
+ #include <linux/cdev.h>
+ #include <linux/seq_file.h>
+ #include <linux/blkdev.h>
+@@ -1427,10 +1428,14 @@
+ k = error;
+ sdp = sg_dev_arr[k];
+
++ devfs_mk_cdev(MKDEV(SCSI_GENERIC_MAJOR, k),
++ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
++ "%s/generic", scsidp->devfs_name);
+ error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1);
+- if (error)
++ if (error) {
++ devfs_remove("%s/generic", scsidp->devfs_name);
+ goto out;
+-
++ }
+ sdp->cdev = cdev;
+ if (sg_sysfs_valid) {
+ struct class_device * sg_class_member;
+@@ -1520,6 +1525,7 @@
+ class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, k));
+ cdev_del(sdp->cdev);
+ sdp->cdev = NULL;
++ devfs_remove("%s/generic", scsidp->devfs_name);
+ put_disk(sdp->disk);
+ sdp->disk = NULL;
+ if (NULL == sdp->headfp)
+diff -ur linux-2.6.17/drivers/scsi/sr.c linux-2.6.17-devfs/drivers/scsi/sr.c
+--- linux-2.6.17/drivers/scsi/sr.c 2006-06-17 18:49:35.000000000 -0700
++++ linux-2.6.17-devfs/drivers/scsi/sr.c 2006-08-25 11:06:18.000000000 -0700
+@@ -592,6 +592,8 @@
+ get_capabilities(cd);
+ sr_vendor_init(cd);
+
++ snprintf(disk->devfs_name, sizeof(disk->devfs_name),
++ "%s/cd", sdev->devfs_name);
+ disk->driverfs_dev = &sdev->sdev_gendev;
+ set_capacity(disk, cd->capacity);
+ disk->private_data = &cd->driver;
+diff -ur linux-2.6.17/drivers/scsi/st.c linux-2.6.17-devfs/drivers/scsi/st.c
+--- linux-2.6.17/drivers/scsi/st.c 2006-06-17 18:49:35.000000000 -0700
++++ linux-2.6.17-devfs/drivers/scsi/st.c 2006-08-25 11:06:18.000000000 -0700
+@@ -35,6 +35,7 @@
+ #include <linux/spinlock.h>
+ #include <linux/blkdev.h>
+ #include <linux/moduleparam.h>
++#include <linux/devfs_fs_kernel.h>
+ #include <linux/cdev.h>
+ #include <linux/delay.h>
+ #include <linux/mutex.h>
+@@ -4053,8 +4054,23 @@
+ do_create_class_files(tpnt, dev_num, mode);
+ }
+
++ for (mode = 0; mode < ST_NBR_MODES; ++mode) {
++ /* Make sure that the minor numbers corresponding to the four
++ first modes always get the same names */
++ i = mode << (4 - ST_NBR_MODE_BITS);
++ /* Rewind entry */
++ devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 0)),
++ S_IFCHR | S_IRUGO | S_IWUGO,
++ "%s/mt%s", SDp->devfs_name, st_formats[i]);
++ /* No-rewind entry */
++ devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 1)),
++ S_IFCHR | S_IRUGO | S_IWUGO,
++ "%s/mt%sn", SDp->devfs_name, st_formats[i]);
++ }
++ disk->number = devfs_register_tape(SDp->devfs_name);
++
+ sdev_printk(KERN_WARNING, SDp,
+ "Attached scsi tape %s\n", tape_name(tpnt));
+ printk(KERN_WARNING "%s: try direct i/o: %s (alignment %d B)\n",
+ tape_name(tpnt), tpnt->try_dio ? "yes" : "no",
+ queue_dma_alignment(SDp->request_queue) + 1);
+@@ -4106,9 +4122,13 @@
+ scsi_tapes[i] = NULL;
+ st_nr_dev--;
+ write_unlock(&st_dev_arr_lock);
++ devfs_unregister_tape(tpnt->disk->number);
+ sysfs_remove_link(&tpnt->device->sdev_gendev.kobj,
+ "tape");
+ for (mode = 0; mode < ST_NBR_MODES; ++mode) {
++ j = mode << (4 - ST_NBR_MODE_BITS);
++ devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[j]);
++ devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[j]);
+ for (j=0; j < 2; j++) {
+ class_device_destroy(st_sysfs_class,
+ MKDEV(SCSI_TAPE_MAJOR,
+diff -ur linux-2.6.17/include/scsi/scsi_device.h linux-2.6.17-devfs/include/scsi/scsi_device.h
+--- linux-2.6.17/include/scsi/scsi_device.h 2006-06-17 18:49:35.000000000 -0700
++++ linux-2.6.17-devfs/include/scsi/scsi_device.h 2006-08-25 11:06:18.000000000 -0700
+@@ -74,6 +74,7 @@
+ unsigned sector_size; /* size in bytes */
+
+ void *hostdata; /* available to low-level driver */
++ char devfs_name[256]; /* devfs junk */
+ char type;
+ char scsi_level;
+ char inq_periph_qual; /* PQ from INQUIRY data */
diff --git a/target/linux/generic-2.6/patches/001-squashfs.patch b/target/linux/generic-2.6/patches/001-squashfs.patch
new file mode 100644
index 0000000..f88dbba
--- /dev/null
+++ b/target/linux/generic-2.6/patches/001-squashfs.patch
@@ -0,0 +1,4173 @@
+diff --new-file -urp linux-2.6.15/fs/Kconfig linux-2.6.15-squashfs3.0/fs/Kconfig
+--- linux-2.6.15/fs/Kconfig 2006-03-01 22:37:27.000000000 +0000
++++ linux-2.6.15-squashfs3.0/fs/Kconfig 2006-03-07 21:12:37.000000000 +0000
+@@ -1151,6 +1151,71 @@ config CRAMFS
+
+ If unsure, say N.
+
++config SQUASHFS
++ tristate "SquashFS 3.0 - Squashed file system support"
++ select ZLIB_INFLATE
++ help
++ Saying Y here includes support for SquashFS 3.0 (a Compressed Read-Only File
++ System). Squashfs is a highly compressed read-only filesystem for Linux.
++ It uses zlib compression to compress both files, inodes and directories.
++ Inodes in the system are very small and all blocks are packed to minimise
++ data overhead. Block sizes greater than 4K are supported up to a maximum of 64K.
++ SquashFS 3.0 supports 64 bit filesystems and files (larger than 4GB), full
++ uid/gid information, hard links and timestamps.
++
++ Squashfs is intended for general read-only filesystem use, for archival
++ use (i.e. in cases where a .tar.gz file may be used), and in embedded
++ systems where low overhead is needed. Further information and filesystem tools
++ are available from http://squashfs.sourceforge.net.
++
++ If you want to compile this as a module ( = code which can be
++ inserted in and removed from the running kernel whenever you want),
++ say M here and read <file:Documentation/modules.txt>. The module
++ will be called squashfs. Note that the root file system (the one
++ containing the directory /) cannot be compiled as a module.
++
++ If unsure, say N.
++
++config SQUASHFS_EMBEDDED
++
++ bool "Additional options for memory-constrained systems"
++ depends on SQUASHFS
++ default n
++ help
++ Saying Y here allows you to specify cache sizes and how Squashfs
++ allocates memory. This is only intended for memory constrained
++ systems.
++
++ If unsure, say N.
++
++config SQUASHFS_FRAGMENT_CACHE_SIZE
++ int "Number of fragments cached" if SQUASHFS_EMBEDDED
++ depends on SQUASHFS
++ default "3"
++ help
++ By default SquashFS caches the last 3 fragments read from
++ the filesystem. Increasing this amount may mean SquashFS
++ has to re-read fragments less often from disk, at the expense
++ of extra system memory. Decreasing this amount will mean
++ SquashFS uses less memory at the expense of extra reads from disk.
++
++ Note there must be at least one cached fragment. Anything
++ much more than three will probably not make much difference.
++
++config SQUASHFS_VMALLOC
++ bool "Use Vmalloc rather than Kmalloc" if SQUASHFS_EMBEDDED
++ depends on SQUASHFS
++ default n
++ help
++ By default SquashFS uses kmalloc to obtain fragment cache memory.
++ Kmalloc memory is the standard kernel allocator, but it can fail
++ on memory constrained systems. Because of the way Vmalloc works,
++ Vmalloc can succeed when kmalloc fails. Specifying this option
++ will make SquashFS always use Vmalloc to allocate the
++ fragment cache memory.
++
++ If unsure, say N.
++
+ config VXFS_FS
+ tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
+ help
+diff --new-file -urp linux-2.6.15/fs/Makefile linux-2.6.15-squashfs3.0/fs/Makefile
+--- linux-2.6.15/fs/Makefile 2006-03-01 22:37:27.000000000 +0000
++++ linux-2.6.15-squashfs3.0/fs/Makefile 2006-03-07 21:12:37.000000000 +0000
+@@ -55,6 +55,7 @@ obj-$(CONFIG_EXT3_FS) += ext3/ # Before
+ obj-$(CONFIG_JBD) += jbd/
+ obj-$(CONFIG_EXT2_FS) += ext2/
+ obj-$(CONFIG_CRAMFS) += cramfs/
++obj-$(CONFIG_SQUASHFS) += squashfs/
+ obj-$(CONFIG_RAMFS) += ramfs/
+ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/
+ obj-$(CONFIG_CODA_FS) += coda/
+diff --new-file -urp linux-2.6.15/fs/squashfs/inode.c linux-2.6.15-squashfs3.0/fs/squashfs/inode.c
+--- linux-2.6.15/fs/squashfs/inode.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-squashfs3.0/fs/squashfs/inode.c 2006-03-07 21:12:37.000000000 +0000
+@@ -0,0 +1,2127 @@
++/*
++ * Squashfs - a compressed read only filesystem for Linux
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.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,
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * inode.c
++ */
++
++#include <linux/types.h>
++#include <linux/squashfs_fs.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/smp_lock.h>
++#include <linux/slab.h>
++#include <linux/squashfs_fs_sb.h>
++#include <linux/squashfs_fs_i.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include <linux/init.h>
++#include <linux/dcache.h>
++#include <linux/wait.h>
++#include <linux/zlib.h>
++#include <linux/blkdev.h>
++#include <linux/vmalloc.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++
++#include "squashfs.h"
++
++static void squashfs_put_super(struct super_block *);
++static int squashfs_statfs(struct super_block *, struct kstatfs *);
++static int squashfs_symlink_readpage(struct file *file, struct page *page);
++static int squashfs_readpage(struct file *file, struct page *page);
++static int squashfs_readpage4K(struct file *file, struct page *page);
++static int squashfs_readdir(struct file *, void *, filldir_t);
++static struct inode *squashfs_alloc_inode(struct super_block *sb);
++static void squashfs_destroy_inode(struct inode *inode);
++static int init_inodecache(void);
++static void destroy_inodecache(void);
++static struct dentry *squashfs_lookup(struct inode *, struct dentry *,
++ struct nameidata *);
++static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode);
++static long long read_blocklist(struct inode *inode, int index,
++ int readahead_blks, char *block_list,
++ unsigned short **block_p, unsigned int *bsize);
++static struct super_block *squashfs_get_sb(struct file_system_type *, int,
++ const char *, void *);
++
++
++static z_stream stream;
++
++static struct file_system_type squashfs_fs_type = {
++ .owner = THIS_MODULE,
++ .name = "squashfs",
++ .get_sb = squashfs_get_sb,
++ .kill_sb = kill_block_super,
++ .fs_flags = FS_REQUIRES_DEV
++};
++
++static unsigned char squashfs_filetype_table[] = {
++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
++};
++
++static struct super_operations squashfs_ops = {
++ .alloc_inode = squashfs_alloc_inode,
++ .destroy_inode = squashfs_destroy_inode,
++ .statfs = squashfs_statfs,
++ .put_super = squashfs_put_super,
++};
++
++SQSH_EXTERN struct address_space_operations squashfs_symlink_aops = {
++ .readpage = squashfs_symlink_readpage
++};
++
++SQSH_EXTERN struct address_space_operations squashfs_aops = {
++ .readpage = squashfs_readpage
++};
++
++SQSH_EXTERN struct address_space_operations squashfs_aops_4K = {
++ .readpage = squashfs_readpage4K
++};
++
++static struct file_operations squashfs_dir_ops = {
++ .read = generic_read_dir,
++ .readdir = squashfs_readdir
++};
++
++SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = {
++ .lookup = squashfs_lookup
++};
++
++
++static struct buffer_head *get_block_length(struct super_block *s,
++ int *cur_index, int *offset, int *c_byte)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ unsigned short temp;
++ struct buffer_head *bh;
++
++ if (!(bh = sb_bread(s, *cur_index)))
++ goto out;
++
++ if (msblk->devblksize - *offset == 1) {
++ if (msblk->swap)
++ ((unsigned char *) &temp)[1] = *((unsigned char *)
++ (bh->b_data + *offset));
++ else
++ ((unsigned char *) &temp)[0] = *((unsigned char *)
++ (bh->b_data + *offset));
++ brelse(bh);
++ if (!(bh = sb_bread(s, ++(*cur_index))))
++ goto out;
++ if (msblk->swap)
++ ((unsigned char *) &temp)[0] = *((unsigned char *)
++ bh->b_data);
++ else
++ ((unsigned char *) &temp)[1] = *((unsigned char *)
++ bh->b_data);
++ *c_byte = temp;
++ *offset = 1;
++ } else {
++ if (msblk->swap) {
++ ((unsigned char *) &temp)[1] = *((unsigned char *)
++ (bh->b_data + *offset));
++ ((unsigned char *) &temp)[0] = *((unsigned char *)
++ (bh->b_data + *offset + 1));
++ } else {
++ ((unsigned char *) &temp)[0] = *((unsigned char *)
++ (bh->b_data + *offset));
++ ((unsigned char *) &temp)[1] = *((unsigned char *)
++ (bh->b_data + *offset + 1));
++ }
++ *c_byte = temp;
++ *offset += 2;
++ }
++
++ if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
++ if (*offset == msblk->devblksize) {
++ brelse(bh);
++ if (!(bh = sb_bread(s, ++(*cur_index))))
++ goto out;
++ *offset = 0;
++ }
++ if (*((unsigned char *) (bh->b_data + *offset)) !=
++ SQUASHFS_MARKER_BYTE) {
++ ERROR("Metadata block marker corrupt @ %x\n",
++ *cur_index);
++ brelse(bh);
++ goto out;
++ }
++ (*offset)++;
++ }
++ return bh;
++
++out:
++ return NULL;
++}
++
++
++SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
++ long long index, unsigned int length,
++ long long *next_index)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >>
++ msblk->devblksize_log2) + 2];
++ unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
++ unsigned int cur_index = index >> msblk->devblksize_log2;
++ int bytes, avail_bytes, b = 0, k;
++ char *c_buffer;
++ unsigned int compressed;
++ unsigned int c_byte = length;
++
++ if (c_byte) {
++ bytes = msblk->devblksize - offset;
++ compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
++ c_buffer = compressed ? msblk->read_data : buffer;
++ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
++
++ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
++ ? "" : "un", (unsigned int) c_byte);
++
++ if (!(bh[0] = sb_getblk(s, cur_index)))
++ goto block_release;
++
++ for (b = 1; bytes < c_byte; b++) {
++ if (!(bh[b] = sb_getblk(s, ++cur_index)))
++ goto block_release;
++ bytes += msblk->devblksize;
++ }
++ ll_rw_block(READ, b, bh);
++ } else {
++ if (!(bh[0] = get_block_length(s, &cur_index, &offset,
++ &c_byte)))
++ goto read_failure;
++
++ bytes = msblk->devblksize - offset;
++ compressed = SQUASHFS_COMPRESSED(c_byte);
++ c_buffer = compressed ? msblk->read_data : buffer;
++ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
++
++ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
++ ? "" : "un", (unsigned int) c_byte);
++
++ for (b = 1; bytes < c_byte; b++) {
++ if (!(bh[b] = sb_getblk(s, ++cur_index)))
++ goto block_release;
++ bytes += msblk->devblksize;
++ }
++ ll_rw_block(READ, b - 1, bh + 1);
++ }
++
++ if (compressed)
++ down(&msblk->read_data_mutex);
++
++ for (bytes = 0, k = 0; k < b; k++) {
++ avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
++ msblk->devblksize - offset :
++ c_byte - bytes;
++ wait_on_buffer(bh[k]);
++ if (!buffer_uptodate(bh[k]))
++ goto block_release;
++ memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes);
++ bytes += avail_bytes;
++ offset = 0;
++ brelse(bh[k]);
++ }
++
++ /*
++ * uncompress block
++ */
++ if (compressed) {
++ int zlib_err;
++
++ stream.next_in = c_buffer;
++ stream.avail_in = c_byte;
++ stream.next_out = buffer;
++ stream.avail_out = msblk->read_size;
++
++ if (((zlib_err = zlib_inflateInit(&stream)) != Z_OK) ||
++ ((zlib_err = zlib_inflate(&stream, Z_FINISH))
++ != Z_STREAM_END) || ((zlib_err =
++ zlib_inflateEnd(&stream)) != Z_OK)) {
++ ERROR("zlib_fs returned unexpected result 0x%x\n",
++ zlib_err);
++ bytes = 0;
++ } else
++ bytes = stream.total_out;
++
++ up(&msblk->read_data_mutex);
++ }
++
++ if (next_index)
++ *next_index = index + c_byte + (length ? 0 :
++ (SQUASHFS_CHECK_DATA(msblk->sblk.flags)
++ ? 3 : 2));
++ return bytes;
++
++block_release:
++ while (--b >= 0)
++ brelse(bh[b]);
++
++read_failure:
++ ERROR("sb_bread failed reading block 0x%x\n", cur_index);
++ return 0;
++}
++
++
++SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer,
++ long long block, unsigned int offset,
++ int length, long long *next_block,
++ unsigned int *next_offset)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ int n, i, bytes, return_length = length;
++ long long next_index;
++
++ TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
++
++ while ( 1 ) {
++ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
++ if (msblk->block_cache[i].block == block)
++ break;
++
++ down(&msblk->block_cache_mutex);
++
++ if (i == SQUASHFS_CACHED_BLKS) {
++ /* read inode header block */
++ for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS;
++ n ; n --, i = (i + 1) %
++ SQUASHFS_CACHED_BLKS)
++ if (msblk->block_cache[i].block !=
++ SQUASHFS_USED_BLK)
++ break;
++
++ if (n == 0) {
++ wait_queue_t wait;
++
++ init_waitqueue_entry(&wait, current);
++ add_wait_queue(&msblk->waitq, &wait);
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ up(&msblk->block_cache_mutex);
++ schedule();
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&msblk->waitq, &wait);
++ continue;
++ }
++ msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
++
++ if (msblk->block_cache[i].block ==
++ SQUASHFS_INVALID_BLK) {
++ if (!(msblk->block_cache[i].data =
++ kmalloc(SQUASHFS_METADATA_SIZE,
++ GFP_KERNEL))) {
++ ERROR("Failed to allocate cache"
++ "block\n");
++ up(&msblk->block_cache_mutex);
++ goto out;
++ }
++ }
++
++ msblk->block_cache[i].block = SQUASHFS_USED_BLK;
++ up(&msblk->block_cache_mutex);
++
++ if (!(msblk->block_cache[i].length =
++ squashfs_read_data(s,
++ msblk->block_cache[i].data,
++ block, 0, &next_index))) {
++ ERROR("Unable to read cache block [%llx:%x]\n",
++ block, offset);
++ goto out;
++ }
++
++ down(&msblk->block_cache_mutex);
++ wake_up(&msblk->waitq);
++ msblk->block_cache[i].block = block;
++ msblk->block_cache[i].next_index = next_index;
++ TRACE("Read cache block [%llx:%x]\n", block, offset);
++ }
++
++ if (msblk->block_cache[i].block != block) {
++ up(&msblk->block_cache_mutex);
++ continue;
++ }
++
++ if ((bytes = msblk->block_cache[i].length - offset) >= length) {
++ if (buffer)
++ memcpy(buffer, msblk->block_cache[i].data +
++ offset, length);
++ if (msblk->block_cache[i].length - offset == length) {
++ *next_block = msblk->block_cache[i].next_index;
++ *next_offset = 0;
++ } else {
++ *next_block = block;
++ *next_offset = offset + length;
++ }
++ up(&msblk->block_cache_mutex);
++ goto finish;
++ } else {
++ if (buffer) {
++ memcpy(buffer, msblk->block_cache[i].data +
++ offset, bytes);
++ buffer += bytes;
++ }
++ block = msblk->block_cache[i].next_index;
++ up(&msblk->block_cache_mutex);
++ length -= bytes;
++ offset = 0;
++ }
++ }
++
++finish:
++ return return_length;
++out:
++ return 0;
++}
++
++
++static int get_fragment_location(struct super_block *s, unsigned int fragment,
++ long long *fragment_start_block,
++ unsigned int *fragment_size)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ long long start_block =
++ msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
++ struct squashfs_fragment_entry fragment_entry;
++
++ if (msblk->swap) {
++ struct squashfs_fragment_entry sfragment_entry;
++
++ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
++ start_block, offset,
++ sizeof(sfragment_entry), &start_block,
++ &offset))
++ goto out;
++ SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
++ } else
++ if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
++ start_block, offset,
++ sizeof(fragment_entry), &start_block,
++ &offset))
++ goto out;
++
++ *fragment_start_block = fragment_entry.start_block;
++ *fragment_size = fragment_entry.size;
++
++ return 1;
++
++out:
++ return 0;
++}
++
++
++SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct
++ squashfs_fragment_cache *fragment)
++{
++ down(&msblk->fragment_mutex);
++ fragment->locked --;
++ wake_up(&msblk->fragment_wait_queue);
++ up(&msblk->fragment_mutex);
++}
++
++
++SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block
++ *s, long long start_block,
++ int length)
++{
++ int i, n;
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++
++ while ( 1 ) {
++ down(&msblk->fragment_mutex);
++
++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
++ msblk->fragment[i].block != start_block; i++);
++
++ if (i == SQUASHFS_CACHED_FRAGMENTS) {
++ for (i = msblk->next_fragment, n =
++ SQUASHFS_CACHED_FRAGMENTS; n &&
++ msblk->fragment[i].locked; n--, i = (i + 1) %
++ SQUASHFS_CACHED_FRAGMENTS);
++
++ if (n == 0) {
++ wait_queue_t wait;
++
++ init_waitqueue_entry(&wait, current);
++ add_wait_queue(&msblk->fragment_wait_queue,
++ &wait);
++ set_current_state(TASK_UNINTERRUPTIBLE);
++ up(&msblk->fragment_mutex);
++ schedule();
++ set_current_state(TASK_RUNNING);
++ remove_wait_queue(&msblk->fragment_wait_queue,
++ &wait);
++ continue;
++ }
++ msblk->next_fragment = (msblk->next_fragment + 1) %
++ SQUASHFS_CACHED_FRAGMENTS;
++
++ if (msblk->fragment[i].data == NULL)
++ if (!(msblk->fragment[i].data = SQUASHFS_ALLOC
++ (SQUASHFS_FILE_MAX_SIZE))) {
++ ERROR("Failed to allocate fragment "
++ "cache block\n");
++ up(&msblk->fragment_mutex);
++ goto out;
++ }
++
++ msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
++ msblk->fragment[i].locked = 1;
++ up(&msblk->fragment_mutex);
++
++ if (!(msblk->fragment[i].length = squashfs_read_data(s,
++ msblk->fragment[i].data,
++ start_block, length, NULL))) {
++ ERROR("Unable to read fragment cache block "
++ "[%llx]\n", start_block);
++ msblk->fragment[i].locked = 0;
++ goto out;
++ }
++
++ msblk->fragment[i].block = start_block;
++ TRACE("New fragment %d, start block %lld, locked %d\n",
++ i, msblk->fragment[i].block,
++ msblk->fragment[i].locked);
++ break;
++ }
++
++ msblk->fragment[i].locked++;
++ up(&msblk->fragment_mutex);
++ TRACE("Got fragment %d, start block %lld, locked %d\n", i,
++ msblk->fragment[i].block,
++ msblk->fragment[i].locked);
++ break;
++ }
++
++ return &msblk->fragment[i];
++
++out:
++ return NULL;
++}
++
++
++static struct inode *squashfs_new_inode(struct super_block *s,
++ struct squashfs_base_inode_header *inodeb)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ struct inode *i = new_inode(s);
++
++ if (i) {
++ i->i_ino = inodeb->inode_number;
++ i->i_mtime.tv_sec = inodeb->mtime;
++ i->i_atime.tv_sec = inodeb->mtime;
++ i->i_ctime.tv_sec = inodeb->mtime;
++ i->i_uid = msblk->uid[inodeb->uid];
++ i->i_mode = inodeb->mode;
++ i->i_size = 0;
++ if (inodeb->guid == SQUASHFS_GUIDS)
++ i->i_gid = i->i_uid;
++ else
++ i->i_gid = msblk->guid[inodeb->guid];
++ }
++
++ return i;
++}
++
++
++static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode)
++{
++ struct inode *i;
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ long long block = SQUASHFS_INODE_BLK(inode) +
++ sblk->inode_table_start;
++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
++ long long next_block;
++ unsigned int next_offset;
++ union squashfs_inode_header id, sid;
++ struct squashfs_base_inode_header *inodeb = &id.base,
++ *sinodeb = &sid.base;
++
++ TRACE("Entered squashfs_iget\n");
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
++ offset, sizeof(*sinodeb), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb,
++ sizeof(*sinodeb));
++ } else
++ if (!squashfs_get_cached_block(s, (char *) inodeb, block,
++ offset, sizeof(*inodeb), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ switch(inodeb->inode_type) {
++ case SQUASHFS_FILE_TYPE: {
++ unsigned int frag_size;
++ long long frag_blk;
++ struct squashfs_reg_inode_header *inodep = &id.reg;
++ struct squashfs_reg_inode_header *sinodep = &sid.reg;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ frag_blk = SQUASHFS_INVALID_BLK;
++ if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
++ !get_fragment_location(s,
++ inodep->fragment, &frag_blk, &frag_size))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb)) == NULL)
++ goto failed_read1;
++
++ i->i_nlink = 1;
++ i->i_size = inodep->file_size;
++ i->i_fop = &generic_ro_fops;
++ i->i_mode |= S_IFREG;
++ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
++ i->i_blksize = PAGE_CACHE_SIZE;
++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
++ SQUASHFS_I(i)->start_block = inodep->start_block;
++ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
++ SQUASHFS_I(i)->offset = next_offset;
++ if (sblk->block_size > 4096)
++ i->i_data.a_ops = &squashfs_aops;
++ else
++ i->i_data.a_ops = &squashfs_aops_4K;
++
++ TRACE("File inode %x:%x, start_block %llx, "
++ "block_list_start %llx, offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ inodep->start_block, next_block,
++ next_offset);
++ break;
++ }
++ case SQUASHFS_LREG_TYPE: {
++ unsigned int frag_size;
++ long long frag_blk;
++ struct squashfs_lreg_inode_header *inodep = &id.lreg;
++ struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ frag_blk = SQUASHFS_INVALID_BLK;
++ if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
++ !get_fragment_location(s,
++ inodep->fragment, &frag_blk, &frag_size))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb)) == NULL)
++ goto failed_read1;
++
++ i->i_nlink = inodep->nlink;
++ i->i_size = inodep->file_size;
++ i->i_fop = &generic_ro_fops;
++ i->i_mode |= S_IFREG;
++ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
++ i->i_blksize = PAGE_CACHE_SIZE;
++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
++ SQUASHFS_I(i)->start_block = inodep->start_block;
++ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
++ SQUASHFS_I(i)->offset = next_offset;
++ if (sblk->block_size > 4096)
++ i->i_data.a_ops = &squashfs_aops;
++ else
++ i->i_data.a_ops = &squashfs_aops_4K;
++
++ TRACE("File inode %x:%x, start_block %llx, "
++ "block_list_start %llx, offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ inodep->start_block, next_block,
++ next_offset);
++ break;
++ }
++ case SQUASHFS_DIR_TYPE: {
++ struct squashfs_dir_inode_header *inodep = &id.dir;
++ struct squashfs_dir_inode_header *sinodep = &sid.dir;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb)) == NULL)
++ goto failed_read1;
++
++ i->i_nlink = inodep->nlink;
++ i->i_size = inodep->file_size;
++ i->i_op = &squashfs_dir_inode_ops;
++ i->i_fop = &squashfs_dir_ops;
++ i->i_mode |= S_IFDIR;
++ SQUASHFS_I(i)->start_block = inodep->start_block;
++ SQUASHFS_I(i)->offset = inodep->offset;
++ SQUASHFS_I(i)->u.s2.directory_index_count = 0;
++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
++
++ TRACE("Directory inode %x:%x, start_block %x, offset "
++ "%x\n", SQUASHFS_INODE_BLK(inode),
++ offset, inodep->start_block,
++ inodep->offset);
++ break;
++ }
++ case SQUASHFS_LDIR_TYPE: {
++ struct squashfs_ldir_inode_header *inodep = &id.ldir;
++ struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep,
++ sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb)) == NULL)
++ goto failed_read1;
++
++ i->i_nlink = inodep->nlink;
++ i->i_size = inodep->file_size;
++ i->i_op = &squashfs_dir_inode_ops;
++ i->i_fop = &squashfs_dir_ops;
++ i->i_mode |= S_IFDIR;
++ SQUASHFS_I(i)->start_block = inodep->start_block;
++ SQUASHFS_I(i)->offset = inodep->offset;
++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
++ SQUASHFS_I(i)->u.s2.directory_index_offset =
++ next_offset;
++ SQUASHFS_I(i)->u.s2.directory_index_count =
++ inodep->i_count;
++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
++
++ TRACE("Long directory inode %x:%x, start_block %x, "
++ "offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ inodep->start_block, inodep->offset);
++ break;
++ }
++ case SQUASHFS_SYMLINK_TYPE: {
++ struct squashfs_symlink_inode_header *inodep =
++ &id.symlink;
++ struct squashfs_symlink_inode_header *sinodep =
++ &sid.symlink;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep,
++ sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb)) == NULL)
++ goto failed_read1;
++
++ i->i_nlink = inodep->nlink;
++ i->i_size = inodep->symlink_size;
++ i->i_op = &page_symlink_inode_operations;
++ i->i_data.a_ops = &squashfs_symlink_aops;
++ i->i_mode |= S_IFLNK;
++ SQUASHFS_I(i)->start_block = next_block;
++ SQUASHFS_I(i)->offset = next_offset;
++
++ TRACE("Symbolic link inode %x:%x, start_block %llx, "
++ "offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ next_block, next_offset);
++ break;
++ }
++ case SQUASHFS_BLKDEV_TYPE:
++ case SQUASHFS_CHRDEV_TYPE: {
++ struct squashfs_dev_inode_header *inodep = &id.dev;
++ struct squashfs_dev_inode_header *sinodep = &sid.dev;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if ((i = squashfs_new_inode(s, inodeb)) == NULL)
++ goto failed_read1;
++
++ i->i_nlink = inodep->nlink;
++ i->i_mode |= (inodeb->inode_type ==
++ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR :
++ S_IFBLK;
++ init_special_inode(i, i->i_mode,
++ old_decode_dev(inodep->rdev));
++
++ TRACE("Device inode %x:%x, rdev %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ inodep->rdev);
++ break;
++ }
++ case SQUASHFS_FIFO_TYPE:
++ case SQUASHFS_SOCKET_TYPE: {
++ struct squashfs_ipc_inode_header *inodep = &id.ipc;
++ struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if ((i = squashfs_new_inode(s, inodeb)) == NULL)
++ goto failed_read1;
++
++ i->i_nlink = inodep->nlink;
++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
++ ? S_IFIFO : S_IFSOCK;
++ init_special_inode(i, i->i_mode, 0);
++ break;
++ }
++ default:
++ ERROR("Unknown inode type %d in squashfs_iget!\n",
++ inodeb->inode_type);
++ goto failed_read1;
++ }
++
++ insert_inode_hash(i);
++ return i;
++
++failed_read:
++ ERROR("Unable to read inode [%llx:%x]\n", block, offset);
++
++failed_read1:
++ return NULL;
++}
++
++
++static int read_fragment_index_table(struct super_block *s)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++
++ /* Allocate fragment index table */
++ if (!(msblk->fragment_index = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES
++ (sblk->fragments), GFP_KERNEL))) {
++ ERROR("Failed to allocate uid/gid table\n");
++ return 0;
++ }
++
++ if (SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments) &&
++ !squashfs_read_data(s, (char *)
++ msblk->fragment_index,
++ sblk->fragment_table_start,
++ SQUASHFS_FRAGMENT_INDEX_BYTES
++ (sblk->fragments) |
++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++ ERROR("unable to read fragment index table\n");
++ return 0;
++ }
++
++ if (msblk->swap) {
++ int i;
++ long long fragment;
++
++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments);
++ i++) {
++ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
++ &msblk->fragment_index[i], 1);
++ msblk->fragment_index[i] = fragment;
++ }
++ }
++
++ return 1;
++}
++
++
++static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
++{
++ struct squashfs_super_block *sblk = &msblk->sblk;
++
++ msblk->iget = squashfs_iget;
++ msblk->read_blocklist = read_blocklist;
++ msblk->read_fragment_index_table = read_fragment_index_table;
++
++ if (sblk->s_major == 1) {
++ if (!squashfs_1_0_supported(msblk)) {
++ SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
++ "are unsupported\n");
++ SERROR("Please recompile with "
++ "Squashfs 1.0 support enabled\n");
++ return 0;
++ }
++ } else if (sblk->s_major == 2) {
++ if (!squashfs_2_0_supported(msblk)) {
++ SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
++ "are unsupported\n");
++ SERROR("Please recompile with "
++ "Squashfs 2.0 support enabled\n");
++ return 0;
++ }
++ } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
++ SQUASHFS_MINOR) {
++ SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
++ "filesystem\n", sblk->s_major, sblk->s_minor);
++ SERROR("Please update your kernel\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++
++static int squashfs_fill_super(struct super_block *s, void *data, int silent)
++{
++ struct squashfs_sb_info *msblk;
++ struct squashfs_super_block *sblk;
++ int i;
++ char b[BDEVNAME_SIZE];
++ struct inode *root;
++
++ TRACE("Entered squashfs_read_superblock\n");
++
++ if (!(s->s_fs_info = kmalloc(sizeof(struct squashfs_sb_info),
++ GFP_KERNEL))) {
++ ERROR("Failed to allocate superblock\n");
++ goto failure;
++ }
++ memset(s->s_fs_info, 0, sizeof(struct squashfs_sb_info));
++ msblk = s->s_fs_info;
++ sblk = &msblk->sblk;
++
++ msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE);
++ msblk->devblksize_log2 = ffz(~msblk->devblksize);
++
++ init_MUTEX(&msblk->read_data_mutex);
++ init_MUTEX(&msblk->read_page_mutex);
++ init_MUTEX(&msblk->block_cache_mutex);
++ init_MUTEX(&msblk->fragment_mutex);
++ init_MUTEX(&msblk->meta_index_mutex);
++
++ init_waitqueue_head(&msblk->waitq);
++ init_waitqueue_head(&msblk->fragment_wait_queue);
++
++ if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
++ sizeof(struct squashfs_super_block) |
++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++ SERROR("unable to read superblock\n");
++ goto failed_mount;
++ }
++
++ /* Check it is a SQUASHFS superblock */
++ msblk->swap = 0;
++ if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
++ if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
++ struct squashfs_super_block ssblk;
++
++ WARNING("Mounting a different endian SQUASHFS "
++ "filesystem on %s\n", bdevname(s->s_bdev, b));
++
++ SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
++ memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
++ msblk->swap = 1;
++ } else {
++ SERROR("Can't find a SQUASHFS superblock on %s\n",
++ bdevname(s->s_bdev, b));
++ goto failed_mount;
++ }
++ }
++
++ /* Check the MAJOR & MINOR versions */
++ if(!supported_squashfs_filesystem(msblk, silent))
++ goto failed_mount;
++
++ TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b));
++ TRACE("Inodes are %scompressed\n",
++ SQUASHFS_UNCOMPRESSED_INODES
++ (sblk->flags) ? "un" : "");
++ TRACE("Data is %scompressed\n",
++ SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
++ ? "un" : "");
++ TRACE("Check data is %s present in the filesystem\n",
++ SQUASHFS_CHECK_DATA(sblk->flags) ?
++ "" : "not");
++ TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
++ TRACE("Block size %d\n", sblk->block_size);
++ TRACE("Number of inodes %d\n", sblk->inodes);
++ if (sblk->s_major > 1)
++ TRACE("Number of fragments %d\n", sblk->fragments);
++ TRACE("Number of uids %d\n", sblk->no_uids);
++ TRACE("Number of gids %d\n", sblk->no_guids);
++ TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
++ TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
++ if (sblk->s_major > 1)
++ TRACE("sblk->fragment_table_start %llx\n",
++ sblk->fragment_table_start);
++ TRACE("sblk->uid_start %llx\n", sblk->uid_start);
++
++ s->s_flags |= MS_RDONLY;
++ s->s_op = &squashfs_ops;
++
++ /* Init inode_table block pointer array */
++ if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
++ SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
++ ERROR("Failed to allocate block cache\n");
++ goto failed_mount;
++ }
++
++ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
++ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
++
++ msblk->next_cache = 0;
++
++ /* Allocate read_data block */
++ msblk->read_size = (sblk->block_size < SQUASHFS_METADATA_SIZE) ?
++ SQUASHFS_METADATA_SIZE :
++ sblk->block_size;
++
++ if (!(msblk->read_data = kmalloc(msblk->read_size, GFP_KERNEL))) {
++ ERROR("Failed to allocate read_data block\n");
++ goto failed_mount;
++ }
++
++ /* Allocate read_page block */
++ if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) {
++ ERROR("Failed to allocate read_page block\n");
++ goto failed_mount;
++ }
++
++ /* Allocate uid and gid tables */
++ if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
++ sizeof(unsigned int), GFP_KERNEL))) {
++ ERROR("Failed to allocate uid/gid table\n");
++ goto failed_mount;
++ }
++ msblk->guid = msblk->uid + sblk->no_uids;
++
++ if (msblk->swap) {
++ unsigned int suid[sblk->no_uids + sblk->no_guids];
++
++ if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
++ ((sblk->no_uids + sblk->no_guids) *
++ sizeof(unsigned int)) |
++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++ ERROR("unable to read uid/gid table\n");
++ goto failed_mount;
++ }
++
++ SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
++ sblk->no_guids), (sizeof(unsigned int) * 8));
++ } else
++ if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
++ ((sblk->no_uids + sblk->no_guids) *
++ sizeof(unsigned int)) |
++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++ ERROR("unable to read uid/gid table\n");
++ goto failed_mount;
++ }
++
++
++ if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
++ goto allocate_root;
++
++ if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) *
++ SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) {
++ ERROR("Failed to allocate fragment block cache\n");
++ goto failed_mount;
++ }
++
++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
++ msblk->fragment[i].locked = 0;
++ msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
++ msblk->fragment[i].data = NULL;
++ }
++
++ msblk->next_fragment = 0;
++
++ /* Allocate fragment index table */
++ if (msblk->read_fragment_index_table(s) == 0)
++ goto failed_mount;
++
++allocate_root:
++ if ((root = (msblk->iget)(s, sblk->root_inode)) == NULL)
++ goto failed_mount;
++
++ if ((s->s_root = d_alloc_root(root)) == NULL) {
++ ERROR("Root inode create failed\n");
++ iput(root);
++ goto failed_mount;
++ }
++
++ TRACE("Leaving squashfs_read_super\n");
++ return 0;
++
++failed_mount:
++ kfree(msblk->fragment_index);
++ kfree(msblk->fragment);
++ kfree(msblk->uid);
++ kfree(msblk->read_page);
++ kfree(msblk->read_data);
++ kfree(msblk->block_cache);
++ kfree(msblk->fragment_index_2);
++ kfree(s->s_fs_info);
++ s->s_fs_info = NULL;
++ return -EINVAL;
++
++failure:
++ return -ENOMEM;
++}
++
++
++static int squashfs_statfs(struct super_block *s, struct kstatfs *buf)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++
++ TRACE("Entered squashfs_statfs\n");
++
++ buf->f_type = SQUASHFS_MAGIC;
++ buf->f_bsize = sblk->block_size;
++ buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
++ buf->f_bfree = buf->f_bavail = 0;
++ buf->f_files = sblk->inodes;
++ buf->f_ffree = 0;
++ buf->f_namelen = SQUASHFS_NAME_LEN;
++
++ return 0;
++}
++
++
++static int squashfs_symlink_readpage(struct file *file, struct page *page)
++{
++ struct inode *inode = page->mapping->host;
++ int index = page->index << PAGE_CACHE_SHIFT, length, bytes;
++ long long block = SQUASHFS_I(inode)->start_block;
++ int offset = SQUASHFS_I(inode)->offset;
++ void *pageaddr = kmap(page);
++
++ TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
++ "%llx, offset %x\n", page->index,
++ SQUASHFS_I(inode)->start_block,
++ SQUASHFS_I(inode)->offset);
++
++ for (length = 0; length < index; length += bytes) {
++ if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL,
++ block, offset, PAGE_CACHE_SIZE, &block,
++ &offset))) {
++ ERROR("Unable to read symbolic link [%llx:%x]\n", block,
++ offset);
++ goto skip_read;
++ }
++ }
++
++ if (length != index) {
++ ERROR("(squashfs_symlink_readpage) length != index\n");
++ bytes = 0;
++ goto skip_read;
++ }
++
++ bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE :
++ i_size_read(inode) - length;
++
++ if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block,
++ offset, bytes, &block, &offset)))
++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
++
++skip_read:
++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
++ kunmap(page);
++ SetPageUptodate(page);
++ unlock_page(page);
++
++ return 0;
++}
++
++
++struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
++{
++ struct meta_index *meta = NULL;
++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++ int i;
++
++ down(&msblk->meta_index_mutex);
++
++ TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
++
++ if(msblk->meta_index == NULL)
++ goto not_allocated;
++
++ for (i = 0; i < SQUASHFS_META_NUMBER; i ++)
++ if (msblk->meta_index[i].inode_number == inode->i_ino &&
++ msblk->meta_index[i].offset >= offset &&
++ msblk->meta_index[i].offset <= index &&
++ msblk->meta_index[i].locked == 0) {
++ TRACE("locate_meta_index: entry %d, offset %d\n", i,
++ msblk->meta_index[i].offset);
++ meta = &msblk->meta_index[i];
++ offset = meta->offset;
++ }
++
++ if (meta)
++ meta->locked = 1;
++
++not_allocated:
++ up(&msblk->meta_index_mutex);
++
++ return meta;
++}
++
++
++struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
++{
++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++ struct meta_index *meta = NULL;
++ int i;
++
++ down(&msblk->meta_index_mutex);
++
++ TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
++
++ if(msblk->meta_index == NULL) {
++ if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) *
++ SQUASHFS_META_NUMBER, GFP_KERNEL))) {
++ ERROR("Failed to allocate meta_index\n");
++ goto failed;
++ }
++ for(i = 0; i < SQUASHFS_META_NUMBER; i++) {
++ msblk->meta_index[i].inode_number = 0;
++ msblk->meta_index[i].locked = 0;
++ }
++ msblk->next_meta_index = 0;
++ }
++
++ for(i = SQUASHFS_META_NUMBER; i &&
++ msblk->meta_index[msblk->next_meta_index].locked; i --)
++ msblk->next_meta_index = (msblk->next_meta_index + 1) %
++ SQUASHFS_META_NUMBER;
++
++ if(i == 0) {
++ TRACE("empty_meta_index: failed!\n");
++ goto failed;
++ }
++
++ TRACE("empty_meta_index: returned meta entry %d, %p\n",
++ msblk->next_meta_index,
++ &msblk->meta_index[msblk->next_meta_index]);
++
++ meta = &msblk->meta_index[msblk->next_meta_index];
++ msblk->next_meta_index = (msblk->next_meta_index + 1) %
++ SQUASHFS_META_NUMBER;
++
++ meta->inode_number = inode->i_ino;
++ meta->offset = offset;
++ meta->skip = skip;
++ meta->entries = 0;
++ meta->locked = 1;
++
++failed:
++ up(&msblk->meta_index_mutex);
++ return meta;
++}
++
++
++void release_meta_index(struct inode *inode, struct meta_index *meta)
++{
++ meta->locked = 0;
++}
++
++
++static int read_block_index(struct super_block *s, int blocks, char *block_list,
++ long long *start_block, int *offset)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ unsigned int *block_listp;
++ int block = 0;
++
++ if (msblk->swap) {
++ char sblock_list[blocks << 2];
++
++ if (!squashfs_get_cached_block(s, sblock_list, *start_block,
++ *offset, blocks << 2, start_block, offset)) {
++ ERROR("Unable to read block list [%llx:%x]\n",
++ *start_block, *offset);
++ goto failure;
++ }
++ SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
++ ((unsigned int *)sblock_list), blocks);
++ } else
++ if (!squashfs_get_cached_block(s, block_list, *start_block,
++ *offset, blocks << 2, start_block, offset)) {
++ ERROR("Unable to read block list [%llx:%x]\n",
++ *start_block, *offset);
++ goto failure;
++ }
++
++ for (block_listp = (unsigned int *) block_list; blocks;
++ block_listp++, blocks --)
++ block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
++
++ return block;
++
++failure:
++ return -1;
++}
++
++
++#define SIZE 256
++
++static inline int calculate_skip(int blocks) {
++ int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
++ return skip >= 7 ? 7 : skip + 1;
++}
++
++
++static int get_meta_index(struct inode *inode, int index,
++ long long *index_block, int *index_offset,
++ long long *data_block, char *block_list)
++{
++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
++ int offset = 0;
++ struct meta_index *meta;
++ struct meta_entry *meta_entry;
++ long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
++ int cur_offset = SQUASHFS_I(inode)->offset;
++ long long cur_data_block = SQUASHFS_I(inode)->start_block;
++ int i;
++
++ index /= SQUASHFS_META_INDEXES * skip;
++
++ while ( offset < index ) {
++ meta = locate_meta_index(inode, index, offset + 1);
++
++ if (meta == NULL) {
++ if ((meta = empty_meta_index(inode, offset + 1,
++ skip)) == NULL)
++ goto all_done;
++ } else {
++ offset = index < meta->offset + meta->entries ? index :
++ meta->offset + meta->entries - 1;
++ meta_entry = &meta->meta_entry[offset - meta->offset];
++ cur_index_block = meta_entry->index_block + sblk->inode_table_start;
++ cur_offset = meta_entry->offset;
++ cur_data_block = meta_entry->data_block;
++ TRACE("get_meta_index: offset %d, meta->offset %d, "
++ "meta->entries %d\n", offset, meta->offset,
++ meta->entries);
++ TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
++ " data_block 0x%llx\n", cur_index_block,
++ cur_offset, cur_data_block);
++ }
++
++ for (i = meta->offset + meta->entries; i <= index &&
++ i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
++ int blocks = skip * SQUASHFS_META_INDEXES;
++
++ while (blocks) {
++ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) :
++ blocks;
++ int res = read_block_index(inode->i_sb, block,
++ block_list, &cur_index_block,
++ &cur_offset);
++
++ if (res == -1)
++ goto failed;
++
++ cur_data_block += res;
++ blocks -= block;
++ }
++
++ meta_entry = &meta->meta_entry[i - meta->offset];
++ meta_entry->index_block = cur_index_block - sblk->inode_table_start;
++ meta_entry->offset = cur_offset;
++ meta_entry->data_block = cur_data_block;
++ meta->entries ++;
++ offset ++;
++ }
++
++ TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
++ meta->offset, meta->entries);
++
++ release_meta_index(inode, meta);
++ }
++
++all_done:
++ *index_block = cur_index_block;
++ *index_offset = cur_offset;
++ *data_block = cur_data_block;
++
++ return offset * SQUASHFS_META_INDEXES * skip;
++
++failed:
++ release_meta_index(inode, meta);
++ return -1;
++}
++
++
++static long long read_blocklist(struct inode *inode, int index,
++ int readahead_blks, char *block_list,
++ unsigned short **block_p, unsigned int *bsize)
++{
++ long long block_ptr;
++ int offset;
++ long long block;
++ int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
++ block_list);
++
++ TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
++ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset,
++ block);
++
++ if(res == -1)
++ goto failure;
++
++ index -= res;
++
++ while ( index ) {
++ int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
++ int res = read_block_index(inode->i_sb, blocks, block_list,
++ &block_ptr, &offset);
++ if (res == -1)
++ goto failure;
++ block += res;
++ index -= blocks;
++ }
++
++ if (read_block_index(inode->i_sb, 1, block_list,
++ &block_ptr, &offset) == -1)
++ goto failure;
++ *bsize = *((unsigned int *) block_list);
++
++ return block;
++
++failure:
++ return 0;
++}
++
++
++static int squashfs_readpage(struct file *file, struct page *page)
++{
++ struct inode *inode = page->mapping->host;
++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ unsigned char block_list[SIZE];
++ long long block;
++ unsigned int bsize, i = 0, bytes = 0, byte_offset = 0;
++ int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
++ void *pageaddr;
++ struct squashfs_fragment_cache *fragment = NULL;
++ char *data_ptr = msblk->read_page;
++
++ int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
++ int start_index = page->index & ~mask;
++ int end_index = start_index | mask;
++
++ TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
++ page->index,
++ SQUASHFS_I(inode)->start_block);
++
++ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
++ PAGE_CACHE_SHIFT))
++ goto skip_read;
++
++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
++ || index < (i_size_read(inode) >>
++ sblk->block_log)) {
++ if ((block = (msblk->read_blocklist)(inode, index, 1,
++ block_list, NULL, &bsize)) == 0)
++ goto skip_read;
++
++ down(&msblk->read_page_mutex);
++
++ if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page,
++ block, bsize, NULL))) {
++ ERROR("Unable to read page, block %llx, size %x\n", block,
++ bsize);
++ up(&msblk->read_page_mutex);
++ goto skip_read;
++ }
++ } else {
++ if ((fragment = get_cached_fragment(inode->i_sb,
++ SQUASHFS_I(inode)->
++ u.s1.fragment_start_block,
++ SQUASHFS_I(inode)->u.s1.fragment_size))
++ == NULL) {
++ ERROR("Unable to read page, block %llx, size %x\n",
++ SQUASHFS_I(inode)->
++ u.s1.fragment_start_block,
++ (int) SQUASHFS_I(inode)->
++ u.s1.fragment_size);
++ goto skip_read;
++ }
++ bytes = SQUASHFS_I(inode)->u.s1.fragment_offset +
++ (i_size_read(inode) & (sblk->block_size
++ - 1));
++ byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset;
++ data_ptr = fragment->data;
++ }
++
++ for (i = start_index; i <= end_index && byte_offset < bytes;
++ i++, byte_offset += PAGE_CACHE_SIZE) {
++ struct page *push_page;
++ int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ?
++ PAGE_CACHE_SIZE : bytes - byte_offset;
++
++ TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n",
++ bytes, i, byte_offset, available_bytes);
++
++ if (i == page->index) {
++ pageaddr = kmap_atomic(page, KM_USER0);
++ memcpy(pageaddr, data_ptr + byte_offset,
++ available_bytes);
++ memset(pageaddr + available_bytes, 0,
++ PAGE_CACHE_SIZE - available_bytes);
++ kunmap_atomic(pageaddr, KM_USER0);
++ flush_dcache_page(page);
++ SetPageUptodate(page);
++ unlock_page(page);
++ } else if ((push_page =
++ grab_cache_page_nowait(page->mapping, i))) {
++ pageaddr = kmap_atomic(push_page, KM_USER0);
++
++ memcpy(pageaddr, data_ptr + byte_offset,
++ available_bytes);
++ memset(pageaddr + available_bytes, 0,
++ PAGE_CACHE_SIZE - available_bytes);
++ kunmap_atomic(pageaddr, KM_USER0);
++ flush_dcache_page(push_page);
++ SetPageUptodate(push_page);
++ unlock_page(push_page);
++ page_cache_release(push_page);
++ }
++ }
++
++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
++ || index < (i_size_read(inode) >>
++ sblk->block_log))
++ up(&msblk->read_page_mutex);
++ else
++ release_cached_fragment(msblk, fragment);
++
++ return 0;
++
++skip_read:
++ pageaddr = kmap_atomic(page, KM_USER0);
++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
++ kunmap_atomic(pageaddr, KM_USER0);
++ flush_dcache_page(page);
++ SetPageUptodate(page);
++ unlock_page(page);
++
++ return 0;
++}
++
++
++static int squashfs_readpage4K(struct file *file, struct page *page)
++{
++ struct inode *inode = page->mapping->host;
++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ unsigned char block_list[SIZE];
++ long long block;
++ unsigned int bsize, bytes = 0;
++ void *pageaddr;
++
++ TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n",
++ page->index,
++ SQUASHFS_I(inode)->start_block);
++
++ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
++ PAGE_CACHE_SHIFT)) {
++ pageaddr = kmap_atomic(page, KM_USER0);
++ goto skip_read;
++ }
++
++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
++ || page->index < (i_size_read(inode) >>
++ sblk->block_log)) {
++ block = (msblk->read_blocklist)(inode, page->index, 1,
++ block_list, NULL, &bsize);
++
++ down(&msblk->read_page_mutex);
++ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
++ bsize, NULL);
++ pageaddr = kmap_atomic(page, KM_USER0);
++ if (bytes)
++ memcpy(pageaddr, msblk->read_page, bytes);
++ else
++ ERROR("Unable to read page, block %llx, size %x\n",
++ block, bsize);
++ up(&msblk->read_page_mutex);
++ } else {
++ struct squashfs_fragment_cache *fragment =
++ get_cached_fragment(inode->i_sb,
++ SQUASHFS_I(inode)->
++ u.s1.fragment_start_block,
++ SQUASHFS_I(inode)-> u.s1.fragment_size);
++ pageaddr = kmap_atomic(page, KM_USER0);
++ if (fragment) {
++ bytes = i_size_read(inode) & (sblk->block_size - 1);
++ memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
++ u.s1.fragment_offset, bytes);
++ release_cached_fragment(msblk, fragment);
++ } else
++ ERROR("Unable to read page, block %llx, size %x\n",
++ SQUASHFS_I(inode)->
++ u.s1.fragment_start_block, (int)
++ SQUASHFS_I(inode)-> u.s1.fragment_size);
++ }
++
++skip_read:
++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
++ kunmap_atomic(pageaddr, KM_USER0);
++ flush_dcache_page(page);
++ SetPageUptodate(page);
++ unlock_page(page);
++
++ return 0;
++}
++
++
++static int get_dir_index_using_offset(struct super_block *s, long long
++ *next_block, unsigned int *next_offset,
++ long long index_start,
++ unsigned int index_offset, int i_count,
++ long long f_pos)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ int i, length = 0;
++ struct squashfs_dir_index index;
++
++ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
++ i_count, (unsigned int) f_pos);
++
++ f_pos =- 3;
++ if (f_pos == 0)
++ goto finish;
++
++ for (i = 0; i < i_count; i++) {
++ if (msblk->swap) {
++ struct squashfs_dir_index sindex;
++ squashfs_get_cached_block(s, (char *) &sindex,
++ index_start, index_offset,
++ sizeof(sindex), &index_start,
++ &index_offset);
++ SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
++ } else
++ squashfs_get_cached_block(s, (char *) &index,
++ index_start, index_offset,
++ sizeof(index), &index_start,
++ &index_offset);
++
++ if (index.index > f_pos)
++ break;
++
++ squashfs_get_cached_block(s, NULL, index_start, index_offset,
++ index.size + 1, &index_start,
++ &index_offset);
++
++ length = index.index;
++ *next_block = index.start_block + sblk->directory_table_start;
++ }
++
++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++
++finish:
++ return length + 3;
++}
++
++
++static int get_dir_index_using_name(struct super_block *s, long long
++ *next_block, unsigned int *next_offset,
++ long long index_start,
++ unsigned int index_offset, int i_count,
++ const char *name, int size)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ int i, length = 0;
++ char buffer[sizeof(struct squashfs_dir_index) + SQUASHFS_NAME_LEN + 1];
++ struct squashfs_dir_index *index = (struct squashfs_dir_index *) buffer;
++ char str[SQUASHFS_NAME_LEN + 1];
++
++ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
++
++ strncpy(str, name, size);
++ str[size] = '\0';
++
++ for (i = 0; i < i_count; i++) {
++ if (msblk->swap) {
++ struct squashfs_dir_index sindex;
++ squashfs_get_cached_block(s, (char *) &sindex,
++ index_start, index_offset,
++ sizeof(sindex), &index_start,
++ &index_offset);
++ SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
++ } else
++ squashfs_get_cached_block(s, (char *) index,
++ index_start, index_offset,
++ sizeof(struct squashfs_dir_index),
++ &index_start, &index_offset);
++
++ squashfs_get_cached_block(s, index->name, index_start,
++ index_offset, index->size + 1,
++ &index_start, &index_offset);
++
++ index->name[index->size + 1] = '\0';
++
++ if (strcmp(index->name, str) > 0)
++ break;
++
++ length = index->index;
++ *next_block = index->start_block + sblk->directory_table_start;
++ }
++
++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++ return length + 3;
++}
++
++
++static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
++{
++ struct inode *i = file->f_dentry->d_inode;
++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ long long next_block = SQUASHFS_I(i)->start_block +
++ sblk->directory_table_start;
++ int next_offset = SQUASHFS_I(i)->offset, length = 0, dirs_read = 0,
++ dir_count;
++ struct squashfs_dir_header dirh;
++ char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
++ struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
++
++ TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
++
++ while(file->f_pos < 3) {
++ char *name;
++ int size, i_ino;
++
++ if(file->f_pos == 0) {
++ name = ".";
++ size = 1;
++ i_ino = i->i_ino;
++ } else {
++ name = "..";
++ size = 2;
++ i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
++ }
++ TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
++ (unsigned int) dirent, name, size, (int)
++ file->f_pos, i_ino,
++ squashfs_filetype_table[1]);
++
++ if (filldir(dirent, name, size,
++ file->f_pos, i_ino,
++ squashfs_filetype_table[1]) < 0) {
++ TRACE("Filldir returned less than 0\n");
++ goto finish;
++ }
++ file->f_pos += size;
++ dirs_read++;
++ }
++
++ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_start,
++ SQUASHFS_I(i)->u.s2.directory_index_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_count,
++ file->f_pos);
++
++ while (length < i_size_read(i)) {
++ /* read directory header */
++ if (msblk->swap) {
++ struct squashfs_dir_header sdirh;
++
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++ next_block, next_offset, sizeof(sdirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdirh);
++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++ next_block, next_offset, sizeof(dirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(dirh);
++ }
++
++ dir_count = dirh.count + 1;
++ while (dir_count--) {
++ if (msblk->swap) {
++ struct squashfs_dir_entry sdire;
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ &sdire, next_block, next_offset,
++ sizeof(sdire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdire);
++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ dire, next_block, next_offset,
++ sizeof(*dire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(*dire);
++ }
++
++ if (!squashfs_get_cached_block(i->i_sb, dire->name,
++ next_block, next_offset,
++ dire->size + 1, &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += dire->size + 1;
++
++ if (file->f_pos >= length)
++ continue;
++
++ dire->name[dire->size + 1] = '\0';
++
++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
++ (unsigned int) dirent, dire->name,
++ dire->size + 1, (int) file->f_pos,
++ dirh.start_block, dire->offset,
++ dirh.inode_number + dire->inode_number,
++ squashfs_filetype_table[dire->type]);
++
++ if (filldir(dirent, dire->name, dire->size + 1,
++ file->f_pos,
++ dirh.inode_number + dire->inode_number,
++ squashfs_filetype_table[dire->type])
++ < 0) {
++ TRACE("Filldir returned less than 0\n");
++ goto finish;
++ }
++ file->f_pos = length;
++ dirs_read++;
++ }
++ }
++
++finish:
++ return dirs_read;
++
++failed_read:
++ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++ next_offset);
++ return 0;
++}
++
++
++static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry,
++ struct nameidata *nd)
++{
++ const unsigned char *name = dentry->d_name.name;
++ int len = dentry->d_name.len;
++ struct inode *inode = NULL;
++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ long long next_block = SQUASHFS_I(i)->start_block +
++ sblk->directory_table_start;
++ int next_offset = SQUASHFS_I(i)->offset, length = 0,
++ dir_count;
++ struct squashfs_dir_header dirh;
++ char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN];
++ struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
++
++ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
++
++ if (len > SQUASHFS_NAME_LEN)
++ goto exit_loop;
++
++ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_start,
++ SQUASHFS_I(i)->u.s2.directory_index_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_count, name,
++ len);
++
++ while (length < i_size_read(i)) {
++ /* read directory header */
++ if (msblk->swap) {
++ struct squashfs_dir_header sdirh;
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++ next_block, next_offset, sizeof(sdirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdirh);
++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++ next_block, next_offset, sizeof(dirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(dirh);
++ }
++
++ dir_count = dirh.count + 1;
++ while (dir_count--) {
++ if (msblk->swap) {
++ struct squashfs_dir_entry sdire;
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ &sdire, next_block,next_offset,
++ sizeof(sdire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdire);
++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ dire, next_block,next_offset,
++ sizeof(*dire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(*dire);
++ }
++
++ if (!squashfs_get_cached_block(i->i_sb, dire->name,
++ next_block, next_offset, dire->size + 1,
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += dire->size + 1;
++
++ if (name[0] < dire->name[0])
++ goto exit_loop;
++
++ if ((len == dire->size + 1) && !strncmp(name,
++ dire->name, len)) {
++ squashfs_inode_t ino =
++ SQUASHFS_MKINODE(dirh.start_block,
++ dire->offset);
++
++ TRACE("calling squashfs_iget for directory "
++ "entry %s, inode %x:%x, %d\n", name,
++ dirh.start_block, dire->offset,
++ dirh.inode_number + dire->inode_number);
++
++ inode = (msblk->iget)(i->i_sb, ino);
++
++ goto exit_loop;
++ }
++ }
++ }
++
++exit_loop:
++ d_add(dentry, inode);
++ return ERR_PTR(0);
++
++failed_read:
++ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++ next_offset);
++ goto exit_loop;
++}
++
++
++static void squashfs_put_super(struct super_block *s)
++{
++ int i;
++
++ if (s->s_fs_info) {
++ struct squashfs_sb_info *sbi = s->s_fs_info;
++ if (sbi->block_cache)
++ for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
++ if (sbi->block_cache[i].block !=
++ SQUASHFS_INVALID_BLK)
++ kfree(sbi->block_cache[i].data);
++ if (sbi->fragment)
++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++)
++ SQUASHFS_FREE(sbi->fragment[i].data);
++ kfree(sbi->fragment);
++ kfree(sbi->block_cache);
++ kfree(sbi->read_data);
++ kfree(sbi->read_page);
++ kfree(sbi->uid);
++ kfree(sbi->fragment_index);
++ kfree(sbi->fragment_index_2);
++ kfree(sbi->meta_index);
++ kfree(s->s_fs_info);
++ s->s_fs_info = NULL;
++ }
++}
++
++
++static struct super_block *squashfs_get_sb(struct file_system_type *fs_type,
++ int flags, const char *dev_name, void *data)
++{
++ return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super);
++}
++
++
++static int __init init_squashfs_fs(void)
++{
++ int err = init_inodecache();
++ if (err)
++ goto out;
++
++ printk(KERN_INFO "squashfs: version 3.0 (2006/03/15) "
++ "Phillip Lougher\n");
++
++ if (!(stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
++ ERROR("Failed to allocate zlib workspace\n");
++ destroy_inodecache();
++ err = -ENOMEM;
++ goto out;
++ }
++
++ if ((err = register_filesystem(&squashfs_fs_type))) {
++ vfree(stream.workspace);
++ destroy_inodecache();
++ }
++
++out:
++ return err;
++}
++
++
++static void __exit exit_squashfs_fs(void)
++{
++ vfree(stream.workspace);
++ unregister_filesystem(&squashfs_fs_type);
++ destroy_inodecache();
++}
++
++
++static kmem_cache_t * squashfs_inode_cachep;
++
++
++static struct inode *squashfs_alloc_inode(struct super_block *sb)
++{
++ struct squashfs_inode_info *ei;
++ ei = kmem_cache_alloc(squashfs_inode_cachep, SLAB_KERNEL);
++ if (!ei)
++ return NULL;
++ return &ei->vfs_inode;
++}
++
++
++static void squashfs_destroy_inode(struct inode *inode)
++{
++ kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode));
++}
++
++
++static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
++{
++ struct squashfs_inode_info *ei = foo;
++
++ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
++ SLAB_CTOR_CONSTRUCTOR)
++ inode_init_once(&ei->vfs_inode);
++}
++
++
++static int __init init_inodecache(void)
++{
++ squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",
++ sizeof(struct squashfs_inode_info),
++ 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
++ init_once, NULL);
++ if (squashfs_inode_cachep == NULL)
++ return -ENOMEM;
++ return 0;
++}
++
++
++static void destroy_inodecache(void)
++{
++ if (kmem_cache_destroy(squashfs_inode_cachep))
++ printk(KERN_INFO "squashfs_inode_cache: not all structures "
++ "were freed\n");
++}
++
++
++module_init(init_squashfs_fs);
++module_exit(exit_squashfs_fs);
++MODULE_DESCRIPTION("squashfs, a compressed read-only filesystem");
++MODULE_AUTHOR("Phillip Lougher <phillip@lougher.org.uk>");
++MODULE_LICENSE("GPL");
+diff --new-file -urp linux-2.6.15/fs/squashfs/Makefile linux-2.6.15-squashfs3.0/fs/squashfs/Makefile
+--- linux-2.6.15/fs/squashfs/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-squashfs3.0/fs/squashfs/Makefile 2006-03-07 21:12:37.000000000 +0000
+@@ -0,0 +1,7 @@
++#
++# Makefile for the linux squashfs routines.
++#
++
++obj-$(CONFIG_SQUASHFS) += squashfs.o
++squashfs-y += inode.o
++squashfs-y += squashfs2_0.o
+diff --new-file -urp linux-2.6.15/fs/squashfs/squashfs2_0.c linux-2.6.15-squashfs3.0/fs/squashfs/squashfs2_0.c
+--- linux-2.6.15/fs/squashfs/squashfs2_0.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-squashfs3.0/fs/squashfs/squashfs2_0.c 2006-03-07 21:12:37.000000000 +0000
+@@ -0,0 +1,758 @@
++/*
++ * Squashfs - a compressed read only filesystem for Linux
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.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,
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs2_0.c
++ */
++
++#include <linux/types.h>
++#include <linux/squashfs_fs.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/fs.h>
++#include <linux/smp_lock.h>
++#include <linux/slab.h>
++#include <linux/squashfs_fs_sb.h>
++#include <linux/squashfs_fs_i.h>
++#include <linux/buffer_head.h>
++#include <linux/vfs.h>
++#include <linux/init.h>
++#include <linux/dcache.h>
++#include <linux/wait.h>
++#include <linux/zlib.h>
++#include <linux/blkdev.h>
++#include <linux/vmalloc.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++
++#include "squashfs.h"
++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
++static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *,
++ struct nameidata *);
++
++static struct file_operations squashfs_dir_ops_2 = {
++ .read = generic_read_dir,
++ .readdir = squashfs_readdir_2
++};
++
++static struct inode_operations squashfs_dir_inode_ops_2 = {
++ .lookup = squashfs_lookup_2
++};
++
++static unsigned char squashfs_filetype_table[] = {
++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
++};
++
++static int read_fragment_index_table_2(struct super_block *s)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++
++ if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2
++ (sblk->fragments), GFP_KERNEL))) {
++ ERROR("Failed to allocate uid/gid table\n");
++ return 0;
++ }
++
++ if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) &&
++ !squashfs_read_data(s, (char *)
++ msblk->fragment_index_2,
++ sblk->fragment_table_start,
++ SQUASHFS_FRAGMENT_INDEX_BYTES_2
++ (sblk->fragments) |
++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
++ ERROR("unable to read fragment index table\n");
++ return 0;
++ }
++
++ if (msblk->swap) {
++ int i;
++ unsigned int fragment;
++
++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments);
++ i++) {
++ SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment),
++ &msblk->fragment_index_2[i], 1);
++ msblk->fragment_index_2[i] = fragment;
++ }
++ }
++
++ return 1;
++}
++
++
++static int get_fragment_location_2(struct super_block *s, unsigned int fragment,
++ long long *fragment_start_block,
++ unsigned int *fragment_size)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ long long start_block =
++ msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)];
++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment);
++ struct squashfs_fragment_entry_2 fragment_entry;
++
++ if (msblk->swap) {
++ struct squashfs_fragment_entry_2 sfragment_entry;
++
++ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
++ start_block, offset,
++ sizeof(sfragment_entry), &start_block,
++ &offset))
++ goto out;
++ SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry);
++ } else
++ if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
++ start_block, offset,
++ sizeof(fragment_entry), &start_block,
++ &offset))
++ goto out;
++
++ *fragment_start_block = fragment_entry.start_block;
++ *fragment_size = fragment_entry.size;
++
++ return 1;
++
++out:
++ return 0;
++}
++
++
++static struct inode *squashfs_new_inode(struct super_block *s,
++ struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ struct inode *i = new_inode(s);
++
++ if (i) {
++ i->i_ino = ino;
++ i->i_mtime.tv_sec = sblk->mkfs_time;
++ i->i_atime.tv_sec = sblk->mkfs_time;
++ i->i_ctime.tv_sec = sblk->mkfs_time;
++ i->i_uid = msblk->uid[inodeb->uid];
++ i->i_mode = inodeb->mode;
++ i->i_nlink = 1;
++ i->i_size = 0;
++ if (inodeb->guid == SQUASHFS_GUIDS)
++ i->i_gid = i->i_uid;
++ else
++ i->i_gid = msblk->guid[inodeb->guid];
++ }
++
++ return i;
++}
++
++
++static struct inode *squashfs_iget_2(struct super_block *s, squashfs_inode_t inode)
++{
++ struct inode *i;
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ unsigned int block = SQUASHFS_INODE_BLK(inode) +
++ sblk->inode_table_start;
++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
++ unsigned int ino = SQUASHFS_MK_VFS_INODE(block
++ - sblk->inode_table_start, offset);
++ long long next_block;
++ unsigned int next_offset;
++ union squashfs_inode_header_2 id, sid;
++ struct squashfs_base_inode_header_2 *inodeb = &id.base,
++ *sinodeb = &sid.base;
++
++ TRACE("Entered squashfs_iget\n");
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
++ offset, sizeof(*sinodeb), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
++ sizeof(*sinodeb));
++ } else
++ if (!squashfs_get_cached_block(s, (char *) inodeb, block,
++ offset, sizeof(*inodeb), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ switch(inodeb->inode_type) {
++ case SQUASHFS_FILE_TYPE: {
++ struct squashfs_reg_inode_header_2 *inodep = &id.reg;
++ struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
++ long long frag_blk;
++ unsigned int frag_size;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ frag_blk = SQUASHFS_INVALID_BLK;
++ if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
++ !get_fragment_location_2(s,
++ inodep->fragment, &frag_blk, &frag_size))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++ goto failed_read1;
++
++ i->i_size = inodep->file_size;
++ i->i_fop = &generic_ro_fops;
++ i->i_mode |= S_IFREG;
++ i->i_mtime.tv_sec = inodep->mtime;
++ i->i_atime.tv_sec = inodep->mtime;
++ i->i_ctime.tv_sec = inodep->mtime;
++ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
++ i->i_blksize = PAGE_CACHE_SIZE;
++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
++ SQUASHFS_I(i)->start_block = inodep->start_block;
++ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
++ SQUASHFS_I(i)->offset = next_offset;
++ if (sblk->block_size > 4096)
++ i->i_data.a_ops = &squashfs_aops;
++ else
++ i->i_data.a_ops = &squashfs_aops_4K;
++
++ TRACE("File inode %x:%x, start_block %x, "
++ "block_list_start %llx, offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ inodep->start_block, next_block,
++ next_offset);
++ break;
++ }
++ case SQUASHFS_DIR_TYPE: {
++ struct squashfs_dir_inode_header_2 *inodep = &id.dir;
++ struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++ goto failed_read1;
++
++ i->i_size = inodep->file_size;
++ i->i_op = &squashfs_dir_inode_ops_2;
++ i->i_fop = &squashfs_dir_ops_2;
++ i->i_mode |= S_IFDIR;
++ i->i_mtime.tv_sec = inodep->mtime;
++ i->i_atime.tv_sec = inodep->mtime;
++ i->i_ctime.tv_sec = inodep->mtime;
++ SQUASHFS_I(i)->start_block = inodep->start_block;
++ SQUASHFS_I(i)->offset = inodep->offset;
++ SQUASHFS_I(i)->u.s2.directory_index_count = 0;
++ SQUASHFS_I(i)->u.s2.parent_inode = 0;
++
++ TRACE("Directory inode %x:%x, start_block %x, offset "
++ "%x\n", SQUASHFS_INODE_BLK(inode),
++ offset, inodep->start_block,
++ inodep->offset);
++ break;
++ }
++ case SQUASHFS_LDIR_TYPE: {
++ struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
++ struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
++ sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++ goto failed_read1;
++
++ i->i_size = inodep->file_size;
++ i->i_op = &squashfs_dir_inode_ops_2;
++ i->i_fop = &squashfs_dir_ops_2;
++ i->i_mode |= S_IFDIR;
++ i->i_mtime.tv_sec = inodep->mtime;
++ i->i_atime.tv_sec = inodep->mtime;
++ i->i_ctime.tv_sec = inodep->mtime;
++ SQUASHFS_I(i)->start_block = inodep->start_block;
++ SQUASHFS_I(i)->offset = inodep->offset;
++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
++ SQUASHFS_I(i)->u.s2.directory_index_offset =
++ next_offset;
++ SQUASHFS_I(i)->u.s2.directory_index_count =
++ inodep->i_count;
++ SQUASHFS_I(i)->u.s2.parent_inode = 0;
++
++ TRACE("Long directory inode %x:%x, start_block %x, "
++ "offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ inodep->start_block, inodep->offset);
++ break;
++ }
++ case SQUASHFS_SYMLINK_TYPE: {
++ struct squashfs_symlink_inode_header_2 *inodep =
++ &id.symlink;
++ struct squashfs_symlink_inode_header_2 *sinodep =
++ &sid.symlink;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
++ sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++ goto failed_read1;
++
++ i->i_size = inodep->symlink_size;
++ i->i_op = &page_symlink_inode_operations;
++ i->i_data.a_ops = &squashfs_symlink_aops;
++ i->i_mode |= S_IFLNK;
++ SQUASHFS_I(i)->start_block = next_block;
++ SQUASHFS_I(i)->offset = next_offset;
++
++ TRACE("Symbolic link inode %x:%x, start_block %llx, "
++ "offset %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ next_block, next_offset);
++ break;
++ }
++ case SQUASHFS_BLKDEV_TYPE:
++ case SQUASHFS_CHRDEV_TYPE: {
++ struct squashfs_dev_inode_header_2 *inodep = &id.dev;
++ struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;
++
++ if (msblk->swap) {
++ if (!squashfs_get_cached_block(s, (char *)
++ sinodep, block, offset,
++ sizeof(*sinodep), &next_block,
++ &next_offset))
++ goto failed_read;
++ SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
++ } else
++ if (!squashfs_get_cached_block(s, (char *)
++ inodep, block, offset,
++ sizeof(*inodep), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++ goto failed_read1;
++
++ i->i_mode |= (inodeb->inode_type ==
++ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR :
++ S_IFBLK;
++ init_special_inode(i, i->i_mode,
++ old_decode_dev(inodep->rdev));
++
++ TRACE("Device inode %x:%x, rdev %x\n",
++ SQUASHFS_INODE_BLK(inode), offset,
++ inodep->rdev);
++ break;
++ }
++ case SQUASHFS_FIFO_TYPE:
++ case SQUASHFS_SOCKET_TYPE: {
++ if ((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
++ goto failed_read1;
++
++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
++ ? S_IFIFO : S_IFSOCK;
++ init_special_inode(i, i->i_mode, 0);
++ break;
++ }
++ default:
++ ERROR("Unknown inode type %d in squashfs_iget!\n",
++ inodeb->inode_type);
++ goto failed_read1;
++ }
++
++ insert_inode_hash(i);
++ return i;
++
++failed_read:
++ ERROR("Unable to read inode [%x:%x]\n", block, offset);
++
++failed_read1:
++ return NULL;
++}
++
++
++static int get_dir_index_using_offset(struct super_block *s, long long
++ *next_block, unsigned int *next_offset,
++ long long index_start,
++ unsigned int index_offset, int i_count,
++ long long f_pos)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ int i, length = 0;
++ struct squashfs_dir_index_2 index;
++
++ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
++ i_count, (unsigned int) f_pos);
++
++ if (f_pos == 0)
++ goto finish;
++
++ for (i = 0; i < i_count; i++) {
++ if (msblk->swap) {
++ struct squashfs_dir_index_2 sindex;
++ squashfs_get_cached_block(s, (char *) &sindex,
++ index_start, index_offset,
++ sizeof(sindex), &index_start,
++ &index_offset);
++ SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex);
++ } else
++ squashfs_get_cached_block(s, (char *) &index,
++ index_start, index_offset,
++ sizeof(index), &index_start,
++ &index_offset);
++
++ if (index.index > f_pos)
++ break;
++
++ squashfs_get_cached_block(s, NULL, index_start, index_offset,
++ index.size + 1, &index_start,
++ &index_offset);
++
++ length = index.index;
++ *next_block = index.start_block + sblk->directory_table_start;
++ }
++
++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++
++finish:
++ return length;
++}
++
++
++static int get_dir_index_using_name(struct super_block *s, long long
++ *next_block, unsigned int *next_offset,
++ long long index_start,
++ unsigned int index_offset, int i_count,
++ const char *name, int size)
++{
++ struct squashfs_sb_info *msblk = s->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ int i, length = 0;
++ char buffer[sizeof(struct squashfs_dir_index_2) + SQUASHFS_NAME_LEN + 1];
++ struct squashfs_dir_index_2 *index = (struct squashfs_dir_index_2 *) buffer;
++ char str[SQUASHFS_NAME_LEN + 1];
++
++ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
++
++ strncpy(str, name, size);
++ str[size] = '\0';
++
++ for (i = 0; i < i_count; i++) {
++ if (msblk->swap) {
++ struct squashfs_dir_index_2 sindex;
++ squashfs_get_cached_block(s, (char *) &sindex,
++ index_start, index_offset,
++ sizeof(sindex), &index_start,
++ &index_offset);
++ SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex);
++ } else
++ squashfs_get_cached_block(s, (char *) index,
++ index_start, index_offset,
++ sizeof(struct squashfs_dir_index_2),
++ &index_start, &index_offset);
++
++ squashfs_get_cached_block(s, index->name, index_start,
++ index_offset, index->size + 1,
++ &index_start, &index_offset);
++
++ index->name[index->size + 1] = '\0';
++
++ if (strcmp(index->name, str) > 0)
++ break;
++
++ length = index->index;
++ *next_block = index->start_block + sblk->directory_table_start;
++ }
++
++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
++ return length;
++}
++
++
++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
++{
++ struct inode *i = file->f_dentry->d_inode;
++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ long long next_block = SQUASHFS_I(i)->start_block +
++ sblk->directory_table_start;
++ int next_offset = SQUASHFS_I(i)->offset, length = 0, dirs_read = 0,
++ dir_count;
++ struct squashfs_dir_header_2 dirh;
++ char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1];
++ struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer;
++
++ TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
++
++ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_start,
++ SQUASHFS_I(i)->u.s2.directory_index_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_count,
++ file->f_pos);
++
++ while (length < i_size_read(i)) {
++ /* read directory header */
++ if (msblk->swap) {
++ struct squashfs_dir_header_2 sdirh;
++
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++ next_block, next_offset, sizeof(sdirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdirh);
++ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++ next_block, next_offset, sizeof(dirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(dirh);
++ }
++
++ dir_count = dirh.count + 1;
++ while (dir_count--) {
++ if (msblk->swap) {
++ struct squashfs_dir_entry_2 sdire;
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ &sdire, next_block, next_offset,
++ sizeof(sdire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdire);
++ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ dire, next_block, next_offset,
++ sizeof(*dire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(*dire);
++ }
++
++ if (!squashfs_get_cached_block(i->i_sb, dire->name,
++ next_block, next_offset,
++ dire->size + 1, &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += dire->size + 1;
++
++ if (file->f_pos >= length)
++ continue;
++
++ dire->name[dire->size + 1] = '\0';
++
++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
++ (unsigned int) dirent, dire->name,
++ dire->size + 1, (int) file->f_pos,
++ dirh.start_block, dire->offset,
++ squashfs_filetype_table[dire->type]);
++
++ if (filldir(dirent, dire->name, dire->size + 1,
++ file->f_pos, SQUASHFS_MK_VFS_INODE(
++ dirh.start_block, dire->offset),
++ squashfs_filetype_table[dire->type])
++ < 0) {
++ TRACE("Filldir returned less than 0\n");
++ goto finish;
++ }
++ file->f_pos = length;
++ dirs_read++;
++ }
++ }
++
++finish:
++ return dirs_read;
++
++failed_read:
++ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++ next_offset);
++ return 0;
++}
++
++
++static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry,
++ struct nameidata *nd)
++{
++ const unsigned char *name = dentry->d_name.name;
++ int len = dentry->d_name.len;
++ struct inode *inode = NULL;
++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
++ struct squashfs_super_block *sblk = &msblk->sblk;
++ long long next_block = SQUASHFS_I(i)->start_block +
++ sblk->directory_table_start;
++ int next_offset = SQUASHFS_I(i)->offset, length = 0,
++ dir_count;
++ struct squashfs_dir_header_2 dirh;
++ char buffer[sizeof(struct squashfs_dir_entry_2) + SQUASHFS_NAME_LEN];
++ struct squashfs_dir_entry_2 *dire = (struct squashfs_dir_entry_2 *) buffer;
++ int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
++
++ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
++
++ if (len > SQUASHFS_NAME_LEN)
++ goto exit_loop;
++
++ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_start,
++ SQUASHFS_I(i)->u.s2.directory_index_offset,
++ SQUASHFS_I(i)->u.s2.directory_index_count, name,
++ len);
++
++ while (length < i_size_read(i)) {
++ /* read directory header */
++ if (msblk->swap) {
++ struct squashfs_dir_header_2 sdirh;
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
++ next_block, next_offset, sizeof(sdirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdirh);
++ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
++ next_block, next_offset, sizeof(dirh),
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += sizeof(dirh);
++ }
++
++ dir_count = dirh.count + 1;
++ while (dir_count--) {
++ if (msblk->swap) {
++ struct squashfs_dir_entry_2 sdire;
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ &sdire, next_block,next_offset,
++ sizeof(sdire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(sdire);
++ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
++ } else {
++ if (!squashfs_get_cached_block(i->i_sb, (char *)
++ dire, next_block,next_offset,
++ sizeof(*dire), &next_block,
++ &next_offset))
++ goto failed_read;
++
++ length += sizeof(*dire);
++ }
++
++ if (!squashfs_get_cached_block(i->i_sb, dire->name,
++ next_block, next_offset, dire->size + 1,
++ &next_block, &next_offset))
++ goto failed_read;
++
++ length += dire->size + 1;
++
++ if (sorted && name[0] < dire->name[0])
++ goto exit_loop;
++
++ if ((len == dire->size + 1) && !strncmp(name,
++ dire->name, len)) {
++ squashfs_inode_t ino =
++ SQUASHFS_MKINODE(dirh.start_block,
++ dire->offset);
++
++ TRACE("calling squashfs_iget for directory "
++ "entry %s, inode %x:%x, %lld\n", name,
++ dirh.start_block, dire->offset, ino);
++
++ inode = (msblk->iget)(i->i_sb, ino);
++
++ goto exit_loop;
++ }
++ }
++ }
++
++exit_loop:
++ d_add(dentry, inode);
++ return ERR_PTR(0);
++
++failed_read:
++ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
++ next_offset);
++ goto exit_loop;
++}
++
++
++int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
++{
++ struct squashfs_super_block *sblk = &msblk->sblk;
++
++ msblk->iget = squashfs_iget_2;
++ msblk->read_fragment_index_table = read_fragment_index_table_2;
++
++ sblk->bytes_used = sblk->bytes_used_2;
++ sblk->uid_start = sblk->uid_start_2;
++ sblk->guid_start = sblk->guid_start_2;
++ sblk->inode_table_start = sblk->inode_table_start_2;
++ sblk->directory_table_start = sblk->directory_table_start_2;
++ sblk->fragment_table_start = sblk->fragment_table_start_2;
++
++ return 1;
++}
+diff --new-file -urp linux-2.6.15/fs/squashfs/squashfs.h linux-2.6.15-squashfs3.0/fs/squashfs/squashfs.h
+--- linux-2.6.15/fs/squashfs/squashfs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-squashfs3.0/fs/squashfs/squashfs.h 2006-03-07 21:12:37.000000000 +0000
+@@ -0,0 +1,86 @@
++/*
++ * Squashfs - a compressed read only filesystem for Linux
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.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,
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs.h
++ */
++
++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++#endif
++
++#ifdef SQUASHFS_TRACE
++#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args)
++#else
++#define TRACE(s, args...) {}
++#endif
++
++#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args)
++
++#define SERROR(s, args...) do { \
++ if (!silent) \
++ printk(KERN_ERR "SQUASHFS error: "s, ## args);\
++ } while(0)
++
++#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args)
++
++static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode)
++{
++ return list_entry(inode, struct squashfs_inode_info, vfs_inode);
++}
++
++#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY)
++#define SQSH_EXTERN
++extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
++ long long index, unsigned int length,
++ long long *next_index);
++extern int squashfs_get_cached_block(struct super_block *s, char *buffer,
++ long long block, unsigned int offset,
++ int length, long long *next_block,
++ unsigned int *next_offset);
++extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct
++ squashfs_fragment_cache *fragment);
++extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block
++ *s, long long start_block,
++ int length);
++extern struct address_space_operations squashfs_symlink_aops;
++extern struct address_space_operations squashfs_aops;
++extern struct address_space_operations squashfs_aops_4K;
++extern struct inode_operations squashfs_dir_inode_ops;
++#else
++#define SQSH_EXTERN static
++#endif
++
++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk);
++#else
++static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk)
++{
++ return 0;
++}
++#endif
++
++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk);
++#else
++static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
++{
++ return 0;
++}
++#endif
+diff --new-file -urp linux-2.6.15/include/linux/squashfs_fs.h linux-2.6.15-squashfs3.0/include/linux/squashfs_fs.h
+--- linux-2.6.15/include/linux/squashfs_fs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-squashfs3.0/include/linux/squashfs_fs.h 2006-03-07 21:12:37.000000000 +0000
+@@ -0,0 +1,911 @@
++#ifndef SQUASHFS_FS
++#define SQUASHFS_FS
++
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.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,
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs_fs.h
++ */
++
++#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
++#endif
++
++#ifdef CONFIG_SQUASHFS_VMALLOC
++#define SQUASHFS_ALLOC(a) vmalloc(a)
++#define SQUASHFS_FREE(a) vfree(a)
++#else
++#define SQUASHFS_ALLOC(a) kmalloc(a, GFP_KERNEL)
++#define SQUASHFS_FREE(a) kfree(a)
++#endif
++#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
++#define SQUASHFS_MAJOR 3
++#define SQUASHFS_MINOR 0
++#define SQUASHFS_MAGIC 0x73717368
++#define SQUASHFS_MAGIC_SWAP 0x68737173
++#define SQUASHFS_START 0
++
++/* size of metadata (inode and directory) blocks */
++#define SQUASHFS_METADATA_SIZE 8192
++#define SQUASHFS_METADATA_LOG 13
++
++/* default size of data blocks */
++#define SQUASHFS_FILE_SIZE 65536
++#define SQUASHFS_FILE_LOG 16
++
++#define SQUASHFS_FILE_MAX_SIZE 65536
++
++/* Max number of uids and gids */
++#define SQUASHFS_UIDS 256
++#define SQUASHFS_GUIDS 255
++
++/* Max length of filename (not 255) */
++#define SQUASHFS_NAME_LEN 256
++
++#define SQUASHFS_INVALID ((long long) 0xffffffffffff)
++#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff)
++#define SQUASHFS_INVALID_BLK ((long long) -1)
++#define SQUASHFS_USED_BLK ((long long) -2)
++
++/* Filesystem flags */
++#define SQUASHFS_NOI 0
++#define SQUASHFS_NOD 1
++#define SQUASHFS_CHECK 2
++#define SQUASHFS_NOF 3
++#define SQUASHFS_NO_FRAG 4
++#define SQUASHFS_ALWAYS_FRAG 5
++#define SQUASHFS_DUPLICATE 6
++
++#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1)
++
++#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \
++ SQUASHFS_NOI)
++
++#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \
++ SQUASHFS_NOD)
++
++#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
++ SQUASHFS_NOF)
++
++#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
++ SQUASHFS_NO_FRAG)
++
++#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
++ SQUASHFS_ALWAYS_FRAG)
++
++#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \
++ SQUASHFS_DUPLICATE)
++
++#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \
++ SQUASHFS_CHECK)
++
++#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
++ duplicate_checking) (noi | (nod << 1) | (check_data << 2) \
++ | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
++ (duplicate_checking << 6))
++
++/* Max number of types and file types */
++#define SQUASHFS_DIR_TYPE 1
++#define SQUASHFS_FILE_TYPE 2
++#define SQUASHFS_SYMLINK_TYPE 3
++#define SQUASHFS_BLKDEV_TYPE 4
++#define SQUASHFS_CHRDEV_TYPE 5
++#define SQUASHFS_FIFO_TYPE 6
++#define SQUASHFS_SOCKET_TYPE 7
++#define SQUASHFS_LDIR_TYPE 8
++#define SQUASHFS_LREG_TYPE 9
++
++/* 1.0 filesystem type definitions */
++#define SQUASHFS_TYPES 5
++#define SQUASHFS_IPC_TYPE 0
++
++/* Flag whether block is compressed or uncompressed, bit is set if block is
++ * uncompressed */
++#define SQUASHFS_COMPRESSED_BIT (1 << 15)
++
++#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
++ (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT)
++
++#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT))
++
++#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
++
++#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) (((B) & \
++ ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \
++ ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK)
++
++#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
++
++/*
++ * Inode number ops. Inodes consist of a compressed block number, and an
++ * uncompressed offset within that block
++ */
++#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16))
++
++#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff))
++
++#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\
++ << 16) + (B)))
++
++/* Compute 32 bit VFS inode number from squashfs inode number */
++#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \
++ ((b) >> 2) + 1))
++/* XXX */
++
++/* Translate between VFS mode and squashfs mode */
++#define SQUASHFS_MODE(a) ((a) & 0xfff)
++
++/* fragment and fragment table defines */
++#define SQUASHFS_FRAGMENT_BYTES(A) (A * sizeof(struct squashfs_fragment_entry))
++
++#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \
++ SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \
++ SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \
++ SQUASHFS_METADATA_SIZE - 1) / \
++ SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\
++ sizeof(long long))
++
++/* cached data constants for filesystem */
++#define SQUASHFS_CACHED_BLKS 8
++
++#define SQUASHFS_MAX_FILE_SIZE_LOG 64
++
++#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \
++ (SQUASHFS_MAX_FILE_SIZE_LOG - 2))
++
++#define SQUASHFS_MARKER_BYTE 0xff
++
++/* meta index cache */
++#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
++#define SQUASHFS_META_ENTRIES 31
++#define SQUASHFS_META_NUMBER 8
++#define SQUASHFS_SLOTS 4
++
++struct meta_entry {
++ long long data_block;
++ unsigned int index_block;
++ unsigned short offset;
++ unsigned short pad;
++};
++
++struct meta_index {
++ unsigned int inode_number;
++ unsigned int offset;
++ unsigned short entries;
++ unsigned short skip;
++ unsigned short locked;
++ unsigned short pad;
++ struct meta_entry meta_entry[SQUASHFS_META_ENTRIES];
++};
++
++
++/*
++ * definitions for structures on disk
++ */
++
++typedef long long squashfs_block_t;
++typedef long long squashfs_inode_t;
++
++struct squashfs_super_block {
++ unsigned int s_magic;
++ unsigned int inodes;
++ unsigned int bytes_used_2;
++ unsigned int uid_start_2;
++ unsigned int guid_start_2;
++ unsigned int inode_table_start_2;
++ unsigned int directory_table_start_2;
++ unsigned int s_major:16;
++ unsigned int s_minor:16;
++ unsigned int block_size_1:16;
++ unsigned int block_log:16;
++ unsigned int flags:8;
++ unsigned int no_uids:8;
++ unsigned int no_guids:8;
++ unsigned int mkfs_time /* time of filesystem creation */;
++ squashfs_inode_t root_inode;
++ unsigned int block_size;
++ unsigned int fragments;
++ unsigned int fragment_table_start_2;
++ long long bytes_used;
++ long long uid_start;
++ long long guid_start;
++ long long inode_table_start;
++ long long directory_table_start;
++ long long fragment_table_start;
++ long long unused;
++} __attribute__ ((packed));
++
++struct squashfs_dir_index {
++ unsigned int index;
++ unsigned int start_block;
++ unsigned char size;
++ unsigned char name[0];
++} __attribute__ ((packed));
++
++#define SQUASHFS_BASE_INODE_HEADER \
++ unsigned int inode_type:4; \
++ unsigned int mode:12; \
++ unsigned int uid:8; \
++ unsigned int guid:8; \
++ unsigned int mtime; \
++ unsigned int inode_number;
++
++struct squashfs_base_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++} __attribute__ ((packed));
++
++struct squashfs_ipc_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++ unsigned int nlink;
++} __attribute__ ((packed));
++
++struct squashfs_dev_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++ unsigned int nlink;
++ unsigned short rdev;
++} __attribute__ ((packed));
++
++struct squashfs_symlink_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++ unsigned int nlink;
++ unsigned short symlink_size;
++ char symlink[0];
++} __attribute__ ((packed));
++
++struct squashfs_reg_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++ squashfs_block_t start_block;
++ unsigned int fragment;
++ unsigned int offset;
++ unsigned int file_size;
++ unsigned short block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_lreg_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++ unsigned int nlink;
++ squashfs_block_t start_block;
++ unsigned int fragment;
++ unsigned int offset;
++ long long file_size;
++ unsigned short block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++ unsigned int nlink;
++ unsigned int file_size:19;
++ unsigned int offset:13;
++ unsigned int start_block;
++ unsigned int parent_inode;
++} __attribute__ ((packed));
++
++struct squashfs_ldir_inode_header {
++ SQUASHFS_BASE_INODE_HEADER;
++ unsigned int nlink;
++ unsigned int file_size:27;
++ unsigned int offset:13;
++ unsigned int start_block;
++ unsigned int i_count:16;
++ unsigned int parent_inode;
++ struct squashfs_dir_index index[0];
++} __attribute__ ((packed));
++
++union squashfs_inode_header {
++ struct squashfs_base_inode_header base;
++ struct squashfs_dev_inode_header dev;
++ struct squashfs_symlink_inode_header symlink;
++ struct squashfs_reg_inode_header reg;
++ struct squashfs_lreg_inode_header lreg;
++ struct squashfs_dir_inode_header dir;
++ struct squashfs_ldir_inode_header ldir;
++ struct squashfs_ipc_inode_header ipc;
++};
++
++struct squashfs_dir_entry {
++ unsigned int offset:13;
++ unsigned int type:3;
++ unsigned int size:8;
++ int inode_number:16;
++ char name[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_header {
++ unsigned int count:8;
++ unsigned int start_block;
++ unsigned int inode_number;
++} __attribute__ ((packed));
++
++struct squashfs_fragment_entry {
++ long long start_block;
++ unsigned int size;
++ unsigned int unused;
++} __attribute__ ((packed));
++
++extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
++extern int squashfs_uncompress_init(void);
++extern int squashfs_uncompress_exit(void);
++
++/*
++ * macros to convert each packed bitfield structure from little endian to big
++ * endian and vice versa. These are needed when creating or using a filesystem
++ * on a machine with different byte ordering to the target architecture.
++ *
++ */
++
++#define SQUASHFS_SWAP_START \
++ int bits;\
++ int b_pos;\
++ unsigned long long val;\
++ unsigned char *s;\
++ unsigned char *d;
++
++#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
++ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
++ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
++ SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
++ SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
++ SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
++ SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
++ SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
++ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
++ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
++ SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
++ SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
++ SQUASHFS_SWAP((s)->flags, d, 288, 8);\
++ SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
++ SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
++ SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
++ SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
++ SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
++ SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
++ SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
++ SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
++ SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
++ SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
++ SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
++ SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
++ SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
++ SQUASHFS_SWAP((s)->unused, d, 888, 64);\
++}
++
++#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
++ SQUASHFS_MEMSET(s, d, n);\
++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\
++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\
++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
++ SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
++
++#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
++}
++
++#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++ sizeof(struct squashfs_ipc_inode_header))\
++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++}
++
++#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++ sizeof(struct squashfs_dev_inode_header)); \
++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++ SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
++}
++
++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++ sizeof(struct squashfs_symlink_inode_header));\
++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++ SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
++}
++
++#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++ sizeof(struct squashfs_reg_inode_header));\
++ SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
++ SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
++ SQUASHFS_SWAP((s)->offset, d, 192, 32);\
++ SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
++}
++
++#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++ sizeof(struct squashfs_lreg_inode_header));\
++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
++ SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
++ SQUASHFS_SWAP((s)->offset, d, 224, 32);\
++ SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
++}
++
++#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++ sizeof(struct squashfs_dir_inode_header));\
++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++ SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
++ SQUASHFS_SWAP((s)->offset, d, 147, 13);\
++ SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
++ SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
++}
++
++#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
++ sizeof(struct squashfs_ldir_inode_header));\
++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
++ SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
++ SQUASHFS_SWAP((s)->offset, d, 155, 13);\
++ SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
++ SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
++ SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
++ SQUASHFS_SWAP((s)->index, d, 0, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
++ SQUASHFS_SWAP((s)->size, d, 64, 8);\
++}
++
++#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
++ SQUASHFS_SWAP((s)->count, d, 0, 8);\
++ SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
++ SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\
++ SQUASHFS_SWAP((s)->type, d, 13, 3);\
++ SQUASHFS_SWAP((s)->size, d, 16, 8);\
++ SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
++ SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
++ SQUASHFS_SWAP((s)->size, d, 64, 32);\
++}
++
++#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
++ int entry;\
++ int bit_position;\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, n * 2);\
++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++ 16)\
++ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
++}
++
++#define SQUASHFS_SWAP_INTS(s, d, n) {\
++ int entry;\
++ int bit_position;\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, n * 4);\
++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++ 32)\
++ SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
++}
++
++#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
++ int entry;\
++ int bit_position;\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, n * 8);\
++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++ 64)\
++ SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
++}
++
++#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
++ int entry;\
++ int bit_position;\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, n * bits / 8);\
++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
++ bits)\
++ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
++
++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
++
++struct squashfs_base_inode_header_1 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:4; /* index into uid table */
++ unsigned int guid:4; /* index into guid table */
++} __attribute__ ((packed));
++
++struct squashfs_ipc_inode_header_1 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:4; /* index into uid table */
++ unsigned int guid:4; /* index into guid table */
++ unsigned int type:4;
++ unsigned int offset:4;
++} __attribute__ ((packed));
++
++struct squashfs_dev_inode_header_1 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:4; /* index into uid table */
++ unsigned int guid:4; /* index into guid table */
++ unsigned short rdev;
++} __attribute__ ((packed));
++
++struct squashfs_symlink_inode_header_1 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:4; /* index into uid table */
++ unsigned int guid:4; /* index into guid table */
++ unsigned short symlink_size;
++ char symlink[0];
++} __attribute__ ((packed));
++
++struct squashfs_reg_inode_header_1 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:4; /* index into uid table */
++ unsigned int guid:4; /* index into guid table */
++ unsigned int mtime;
++ unsigned int start_block;
++ unsigned int file_size:32;
++ unsigned short block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_inode_header_1 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:4; /* index into uid table */
++ unsigned int guid:4; /* index into guid table */
++ unsigned int file_size:19;
++ unsigned int offset:13;
++ unsigned int mtime;
++ unsigned int start_block:24;
++} __attribute__ ((packed));
++
++#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
++ SQUASHFS_MEMSET(s, d, n);\
++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
++ SQUASHFS_SWAP((s)->uid, d, 16, 4);\
++ SQUASHFS_SWAP((s)->guid, d, 20, 4);
++
++#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
++}
++
++#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++ sizeof(struct squashfs_ipc_inode_header_1));\
++ SQUASHFS_SWAP((s)->type, d, 24, 4);\
++ SQUASHFS_SWAP((s)->offset, d, 28, 4);\
++}
++
++#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++ sizeof(struct squashfs_dev_inode_header_1));\
++ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
++}
++
++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++ sizeof(struct squashfs_symlink_inode_header_1));\
++ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
++}
++
++#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++ sizeof(struct squashfs_reg_inode_header_1));\
++ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
++ SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
++ sizeof(struct squashfs_dir_inode_header_1));\
++ SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
++ SQUASHFS_SWAP((s)->offset, d, 43, 13);\
++ SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
++}
++
++#endif
++
++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++
++struct squashfs_dir_index_2 {
++ unsigned int index:27;
++ unsigned int start_block:29;
++ unsigned char size;
++ unsigned char name[0];
++} __attribute__ ((packed));
++
++struct squashfs_base_inode_header_2 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:8; /* index into uid table */
++ unsigned int guid:8; /* index into guid table */
++} __attribute__ ((packed));
++
++struct squashfs_ipc_inode_header_2 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:8; /* index into uid table */
++ unsigned int guid:8; /* index into guid table */
++} __attribute__ ((packed));
++
++struct squashfs_dev_inode_header_2 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:8; /* index into uid table */
++ unsigned int guid:8; /* index into guid table */
++ unsigned short rdev;
++} __attribute__ ((packed));
++
++struct squashfs_symlink_inode_header_2 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:8; /* index into uid table */
++ unsigned int guid:8; /* index into guid table */
++ unsigned short symlink_size;
++ char symlink[0];
++} __attribute__ ((packed));
++
++struct squashfs_reg_inode_header_2 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:8; /* index into uid table */
++ unsigned int guid:8; /* index into guid table */
++ unsigned int mtime;
++ unsigned int start_block;
++ unsigned int fragment;
++ unsigned int offset;
++ unsigned int file_size:32;
++ unsigned short block_list[0];
++} __attribute__ ((packed));
++
++struct squashfs_dir_inode_header_2 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:8; /* index into uid table */
++ unsigned int guid:8; /* index into guid table */
++ unsigned int file_size:19;
++ unsigned int offset:13;
++ unsigned int mtime;
++ unsigned int start_block:24;
++} __attribute__ ((packed));
++
++struct squashfs_ldir_inode_header_2 {
++ unsigned int inode_type:4;
++ unsigned int mode:12; /* protection */
++ unsigned int uid:8; /* index into uid table */
++ unsigned int guid:8; /* index into guid table */
++ unsigned int file_size:27;
++ unsigned int offset:13;
++ unsigned int mtime;
++ unsigned int start_block:24;
++ unsigned int i_count:16;
++ struct squashfs_dir_index_2 index[0];
++} __attribute__ ((packed));
++
++union squashfs_inode_header_2 {
++ struct squashfs_base_inode_header_2 base;
++ struct squashfs_dev_inode_header_2 dev;
++ struct squashfs_symlink_inode_header_2 symlink;
++ struct squashfs_reg_inode_header_2 reg;
++ struct squashfs_dir_inode_header_2 dir;
++ struct squashfs_ldir_inode_header_2 ldir;
++ struct squashfs_ipc_inode_header_2 ipc;
++};
++
++struct squashfs_dir_header_2 {
++ unsigned int count:8;
++ unsigned int start_block:24;
++} __attribute__ ((packed));
++
++struct squashfs_dir_entry_2 {
++ unsigned int offset:13;
++ unsigned int type:3;
++ unsigned int size:8;
++ char name[0];
++} __attribute__ ((packed));
++
++struct squashfs_fragment_entry_2 {
++ unsigned int start_block;
++ unsigned int size;
++} __attribute__ ((packed));
++
++#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
++ SQUASHFS_MEMSET(s, d, n);\
++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\
++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\
++
++#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
++}
++
++#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
++ SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
++
++#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++ sizeof(struct squashfs_dev_inode_header_2)); \
++ SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
++}
++
++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++ sizeof(struct squashfs_symlink_inode_header_2));\
++ SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
++}
++
++#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++ sizeof(struct squashfs_reg_inode_header_2));\
++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
++ SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
++ SQUASHFS_SWAP((s)->offset, d, 128, 32);\
++ SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
++}
++
++#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++ sizeof(struct squashfs_dir_inode_header_2));\
++ SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
++ SQUASHFS_SWAP((s)->offset, d, 51, 13);\
++ SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
++}
++
++#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
++ sizeof(struct squashfs_ldir_inode_header_2));\
++ SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
++ SQUASHFS_SWAP((s)->offset, d, 59, 13);\
++ SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
++ SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
++ SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
++}
++
++#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
++ SQUASHFS_SWAP((s)->index, d, 0, 27);\
++ SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
++ SQUASHFS_SWAP((s)->size, d, 56, 8);\
++}
++#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
++ SQUASHFS_SWAP((s)->count, d, 0, 8);\
++ SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
++}
++
++#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\
++ SQUASHFS_SWAP((s)->type, d, 13, 3);\
++ SQUASHFS_SWAP((s)->size, d, 16, 8);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
++ SQUASHFS_SWAP_START\
++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
++ SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
++ SQUASHFS_SWAP((s)->size, d, 32, 32);\
++}
++
++#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
++
++/* fragment and fragment table defines */
++#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2))
++
++#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \
++ SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \
++ SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \
++ SQUASHFS_METADATA_SIZE - 1) / \
++ SQUASHFS_METADATA_SIZE)
++
++#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\
++ sizeof(int))
++
++#endif
++
++#ifdef __KERNEL__
++
++/*
++ * macros used to swap each structure entry, taking into account
++ * bitfields and different bitfield placing conventions on differing
++ * architectures
++ */
++
++#include <asm/byteorder.h>
++
++#ifdef __BIG_ENDIAN
++ /* convert from little endian to big endian */
++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
++ tbits, b_pos)
++#else
++ /* convert from big endian to little endian */
++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
++ tbits, 64 - tbits - b_pos)
++#endif
++
++#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
++ b_pos = pos % 8;\
++ val = 0;\
++ s = (unsigned char *)p + (pos / 8);\
++ d = ((unsigned char *) &val) + 7;\
++ for(bits = 0; bits < (tbits + b_pos); bits += 8) \
++ *d-- = *s++;\
++ value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
++}
++
++#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n);
++
++#endif
++#endif
+diff --new-file -urp linux-2.6.15/include/linux/squashfs_fs_i.h linux-2.6.15-squashfs3.0/include/linux/squashfs_fs_i.h
+--- linux-2.6.15/include/linux/squashfs_fs_i.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-squashfs3.0/include/linux/squashfs_fs_i.h 2006-03-07 21:12:37.000000000 +0000
+@@ -0,0 +1,45 @@
++#ifndef SQUASHFS_FS_I
++#define SQUASHFS_FS_I
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.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,
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs_fs_i.h
++ */
++
++struct squashfs_inode_info {
++ long long start_block;
++ unsigned int offset;
++ union {
++ struct {
++ long long fragment_start_block;
++ unsigned int fragment_size;
++ unsigned int fragment_offset;
++ long long block_list_start;
++ } s1;
++ struct {
++ long long directory_index_start;
++ unsigned int directory_index_offset;
++ unsigned int directory_index_count;
++ unsigned int parent_inode;
++ } s2;
++ } u;
++ struct inode vfs_inode;
++};
++#endif
+diff --new-file -urp linux-2.6.15/include/linux/squashfs_fs_sb.h linux-2.6.15-squashfs3.0/include/linux/squashfs_fs_sb.h
+--- linux-2.6.15/include/linux/squashfs_fs_sb.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-squashfs3.0/include/linux/squashfs_fs_sb.h 2006-03-07 21:12:37.000000000 +0000
+@@ -0,0 +1,74 @@
++#ifndef SQUASHFS_FS_SB
++#define SQUASHFS_FS_SB
++/*
++ * Squashfs
++ *
++ * Copyright (c) 2002, 2003, 2004, 2005, 2006
++ * Phillip Lougher <phillip@lougher.org.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,
++ * 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * squashfs_fs_sb.h
++ */
++
++#include <linux/squashfs_fs.h>
++
++struct squashfs_cache {
++ long long block;
++ int length;
++ long long next_index;
++ char *data;
++};
++
++struct squashfs_fragment_cache {
++ long long block;
++ int length;
++ unsigned int locked;
++ char *data;
++};
++
++struct squashfs_sb_info {
++ struct squashfs_super_block sblk;
++ int devblksize;
++ int devblksize_log2;
++ int swap;
++ struct squashfs_cache *block_cache;
++ struct squashfs_fragment_cache *fragment;
++ int next_cache;
++ int next_fragment;
++ int next_meta_index;
++ unsigned int *uid;
++ unsigned int *guid;
++ long long *fragment_index;
++ unsigned int *fragment_index_2;
++ unsigned int read_size;
++ char *read_data;
++ char *read_page;
++ struct semaphore read_data_mutex;
++ struct semaphore read_page_mutex;
++ struct semaphore block_cache_mutex;
++ struct semaphore fragment_mutex;
++ struct semaphore meta_index_mutex;
++ wait_queue_head_t waitq;
++ wait_queue_head_t fragment_wait_queue;
++ struct meta_index *meta_index;
++ struct inode *(*iget)(struct super_block *s, squashfs_inode_t \
++ inode);
++ long long (*read_blocklist)(struct inode *inode, int \
++ index, int readahead_blks, char *block_list, \
++ unsigned short **block_p, unsigned int *bsize);
++ int (*read_fragment_index_table)(struct super_block *s);
++};
++#endif
+diff --new-file -urp linux-2.6.15/init/do_mounts_rd.c linux-2.6.15-squashfs3.0/init/do_mounts_rd.c
+--- linux-2.6.15/init/do_mounts_rd.c 2006-03-01 22:37:27.000000000 +0000
++++ linux-2.6.15-squashfs3.0/init/do_mounts_rd.c 2006-03-07 21:12:37.000000000 +0000
+@@ -5,6 +5,7 @@
+ #include <linux/ext2_fs.h>
+ #include <linux/romfs_fs.h>
+ #include <linux/cramfs_fs.h>
++#include <linux/squashfs_fs.h>
+ #include <linux/initrd.h>
+ #include <linux/string.h>
+
+@@ -39,6 +40,7 @@ static int __init crd_load(int in_fd, in
+ * numbers could not be found.
+ *
+ * We currently check for the following magic numbers:
++ * squashfs
+ * minix
+ * ext2
+ * romfs
+@@ -53,6 +55,7 @@ identify_ramdisk_image(int fd, int start
+ struct ext2_super_block *ext2sb;
+ struct romfs_super_block *romfsb;
+ struct cramfs_super *cramfsb;
++ struct squashfs_super_block *squashfsb;
+ int nblocks = -1;
+ unsigned char *buf;
+
+@@ -64,6 +67,7 @@ identify_ramdisk_image(int fd, int start
+ ext2sb = (struct ext2_super_block *) buf;
+ romfsb = (struct romfs_super_block *) buf;
+ cramfsb = (struct cramfs_super *) buf;
++ squashfsb = (struct squashfs_super_block *) buf;
+ memset(buf, 0xe5, size);
+
+ /*
+@@ -101,6 +105,15 @@ identify_ramdisk_image(int fd, int start
+ goto done;
+ }
+
++ /* squashfs is at block zero too */
++ if (squashfsb->s_magic == SQUASHFS_MAGIC) {
++ printk(KERN_NOTICE
++ "RAMDISK: squashfs filesystem found at block %d\n",
++ start_block);
++ nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
++ goto done;
++ }
++
+ /*
+ * Read block 1 to test for minix and ext2 superblock
+ */
diff --git a/target/linux/generic-2.6/patches/002-squashfs_lzma.patch b/target/linux/generic-2.6/patches/002-squashfs_lzma.patch
new file mode 100644
index 0000000..a166e84
--- /dev/null
+++ b/target/linux/generic-2.6/patches/002-squashfs_lzma.patch
@@ -0,0 +1,886 @@
+diff -Nur linux-2.6.16/fs/squashfs/inode.c linux-2.6.16-owrt/fs/squashfs/inode.c
+--- linux-2.6.16/fs/squashfs/inode.c 2006-03-21 10:55:59.000000000 +0100
++++ linux-2.6.16-owrt/fs/squashfs/inode.c 2006-03-21 12:24:37.000000000 +0100
+@@ -4,6 +4,9 @@
+ * Copyright (c) 2002, 2003, 2004, 2005, 2006
+ * Phillip Lougher <phillip@lougher.org.uk>
+ *
++ * LZMA decompressor support added by Oleg I. Vdovikin
++ * Copyright (c) 2005 Oleg I.Vdovikin <oleg@cs.msu.su>
++ *
+ * 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,
+@@ -21,6 +24,7 @@
+ * inode.c
+ */
+
++#define SQUASHFS_LZMA
+ #include <linux/types.h>
+ #include <linux/squashfs_fs.h>
+ #include <linux/module.h>
+@@ -44,6 +48,19 @@
+
+ #include "squashfs.h"
+
++#ifdef SQUASHFS_LZMA
++#include "LzmaDecode.h"
++
++/* default LZMA settings, should be in sync with mksquashfs */
++#define LZMA_LC 3
++#define LZMA_LP 0
++#define LZMA_PB 2
++
++#define LZMA_WORKSPACE_SIZE ((LZMA_BASE_SIZE + \
++ (LZMA_LIT_SIZE << (LZMA_LC + LZMA_LP))) * sizeof(CProb))
++
++#endif
++
+ static void squashfs_put_super(struct super_block *);
+ static int squashfs_statfs(struct super_block *, struct kstatfs *);
+ static int squashfs_symlink_readpage(struct file *file, struct page *page);
+@@ -64,7 +81,11 @@
+ const char *, void *);
+
+
++#ifdef SQUASHFS_LZMA
++static unsigned char lzma_workspace[LZMA_WORKSPACE_SIZE];
++#else
+ static z_stream stream;
++#endif
+
+ static struct file_system_type squashfs_fs_type = {
+ .owner = THIS_MODULE,
+@@ -249,6 +270,15 @@
+ if (compressed) {
+ int zlib_err;
+
++#ifdef SQUASHFS_LZMA
++ if ((zlib_err = LzmaDecode(lzma_workspace,
++ LZMA_WORKSPACE_SIZE, LZMA_LC, LZMA_LP, LZMA_PB,
++ c_buffer, c_byte, buffer, msblk->read_size, &bytes)) != LZMA_RESULT_OK)
++ {
++ ERROR("lzma returned unexpected result 0x%x\n", zlib_err);
++ bytes = 0;
++ }
++#else
+ stream.next_in = c_buffer;
+ stream.avail_in = c_byte;
+ stream.next_out = buffer;
+@@ -263,6 +293,7 @@
+ bytes = 0;
+ } else
+ bytes = stream.total_out;
++#endif
+
+ up(&msblk->read_data_mutex);
+ }
+@@ -2046,15 +2077,19 @@
+ printk(KERN_INFO "squashfs: version 3.0 (2006/03/15) "
+ "Phillip Lougher\n");
+
++#ifndef SQUASHFS_LZMA
+ if (!(stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
+ ERROR("Failed to allocate zlib workspace\n");
+ destroy_inodecache();
+ err = -ENOMEM;
+ goto out;
+ }
++#endif
+
+ if ((err = register_filesystem(&squashfs_fs_type))) {
++#ifndef SQUASHFS_LZMA
+ vfree(stream.workspace);
++#endif
+ destroy_inodecache();
+ }
+
+@@ -2065,7 +2100,9 @@
+
+ static void __exit exit_squashfs_fs(void)
+ {
++#ifndef SQUASHFS_LZMA
+ vfree(stream.workspace);
++#endif
+ unregister_filesystem(&squashfs_fs_type);
+ destroy_inodecache();
+ }
+diff -Nur linux-2.6.16/fs/squashfs/LzmaDecode.c linux-2.6.16-owrt/fs/squashfs/LzmaDecode.c
+--- linux-2.6.16/fs/squashfs/LzmaDecode.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/fs/squashfs/LzmaDecode.c 2006-03-21 10:56:57.000000000 +0100
+@@ -0,0 +1,663 @@
++/*
++ LzmaDecode.c
++ LZMA Decoder
++
++ LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
++ http://www.7-zip.org/
++
++ LZMA SDK is licensed under two licenses:
++ 1) GNU Lesser General Public License (GNU LGPL)
++ 2) Common Public License (CPL)
++ It means that you can select one of these two licenses and
++ follow rules of that license.
++
++ SPECIAL EXCEPTION:
++ Igor Pavlov, as the author of this code, expressly permits you to
++ statically or dynamically link your code (or bind by name) to the
++ interfaces of this file without subjecting your linked code to the
++ terms of the CPL or GNU LGPL. Any modifications or additions
++ to this file, however, are subject to the LGPL or CPL terms.
++*/
++
++#include "LzmaDecode.h"
++
++#ifndef Byte
++#define Byte unsigned char
++#endif
++
++#define kNumTopBits 24
++#define kTopValue ((UInt32)1 << kNumTopBits)
++
++#define kNumBitModelTotalBits 11
++#define kBitModelTotal (1 << kNumBitModelTotalBits)
++#define kNumMoveBits 5
++
++typedef struct _CRangeDecoder
++{
++ Byte *Buffer;
++ Byte *BufferLim;
++ UInt32 Range;
++ UInt32 Code;
++ #ifdef _LZMA_IN_CB
++ ILzmaInCallback *InCallback;
++ int Result;
++ #endif
++ int ExtraBytes;
++} CRangeDecoder;
++
++Byte RangeDecoderReadByte(CRangeDecoder *rd)
++{
++ if (rd->Buffer == rd->BufferLim)
++ {
++ #ifdef _LZMA_IN_CB
++ UInt32 size;
++ rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size);
++ rd->BufferLim = rd->Buffer + size;
++ if (size == 0)
++ #endif
++ {
++ rd->ExtraBytes = 1;
++ return 0xFF;
++ }
++ }
++ return (*rd->Buffer++);
++}
++
++/* #define ReadByte (*rd->Buffer++) */
++#define ReadByte (RangeDecoderReadByte(rd))
++
++void RangeDecoderInit(CRangeDecoder *rd,
++ #ifdef _LZMA_IN_CB
++ ILzmaInCallback *inCallback
++ #else
++ Byte *stream, UInt32 bufferSize
++ #endif
++ )
++{
++ int i;
++ #ifdef _LZMA_IN_CB
++ rd->InCallback = inCallback;
++ rd->Buffer = rd->BufferLim = 0;
++ #else
++ rd->Buffer = stream;
++ rd->BufferLim = stream + bufferSize;
++ #endif
++ rd->ExtraBytes = 0;
++ rd->Code = 0;
++ rd->Range = (0xFFFFFFFF);
++ for(i = 0; i < 5; i++)
++ rd->Code = (rd->Code << 8) | ReadByte;
++}
++
++#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code;
++#define RC_FLUSH_VAR rd->Range = range; rd->Code = code;
++#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; }
++
++UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits)
++{
++ RC_INIT_VAR
++ UInt32 result = 0;
++ int i;
++ for (i = numTotalBits; i > 0; i--)
++ {
++ /* UInt32 t; */
++ range >>= 1;
++
++ result <<= 1;
++ if (code >= range)
++ {
++ code -= range;
++ result |= 1;
++ }
++ /*
++ t = (code - range) >> 31;
++ t &= 1;
++ code -= range & (t - 1);
++ result = (result + result) | (1 - t);
++ */
++ RC_NORMALIZE
++ }
++ RC_FLUSH_VAR
++ return result;
++}
++
++int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd)
++{
++ UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob;
++ if (rd->Code < bound)
++ {
++ rd->Range = bound;
++ *prob += (kBitModelTotal - *prob) >> kNumMoveBits;
++ if (rd->Range < kTopValue)
++ {
++ rd->Code = (rd->Code << 8) | ReadByte;
++ rd->Range <<= 8;
++ }
++ return 0;
++ }
++ else
++ {
++ rd->Range -= bound;
++ rd->Code -= bound;
++ *prob -= (*prob) >> kNumMoveBits;
++ if (rd->Range < kTopValue)
++ {
++ rd->Code = (rd->Code << 8) | ReadByte;
++ rd->Range <<= 8;
++ }
++ return 1;
++ }
++}
++
++#define RC_GET_BIT2(prob, mi, A0, A1) \
++ UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \
++ if (code < bound) \
++ { A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \
++ else \
++ { A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \
++ RC_NORMALIZE
++
++#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;)
++
++int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
++{
++ int mi = 1;
++ int i;
++ #ifdef _LZMA_LOC_OPT
++ RC_INIT_VAR
++ #endif
++ for(i = numLevels; i > 0; i--)
++ {
++ #ifdef _LZMA_LOC_OPT
++ CProb *prob = probs + mi;
++ RC_GET_BIT(prob, mi)
++ #else
++ mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd);
++ #endif
++ }
++ #ifdef _LZMA_LOC_OPT
++ RC_FLUSH_VAR
++ #endif
++ return mi - (1 << numLevels);
++}
++
++int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
++{
++ int mi = 1;
++ int i;
++ int symbol = 0;
++ #ifdef _LZMA_LOC_OPT
++ RC_INIT_VAR
++ #endif
++ for(i = 0; i < numLevels; i++)
++ {
++ #ifdef _LZMA_LOC_OPT
++ CProb *prob = probs + mi;
++ RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i))
++ #else
++ int bit = RangeDecoderBitDecode(probs + mi, rd);
++ mi = mi + mi + bit;
++ symbol |= (bit << i);
++ #endif
++ }
++ #ifdef _LZMA_LOC_OPT
++ RC_FLUSH_VAR
++ #endif
++ return symbol;
++}
++
++Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd)
++{
++ int symbol = 1;
++ #ifdef _LZMA_LOC_OPT
++ RC_INIT_VAR
++ #endif
++ do
++ {
++ #ifdef _LZMA_LOC_OPT
++ CProb *prob = probs + symbol;
++ RC_GET_BIT(prob, symbol)
++ #else
++ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
++ #endif
++ }
++ while (symbol < 0x100);
++ #ifdef _LZMA_LOC_OPT
++ RC_FLUSH_VAR
++ #endif
++ return symbol;
++}
++
++Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte)
++{
++ int symbol = 1;
++ #ifdef _LZMA_LOC_OPT
++ RC_INIT_VAR
++ #endif
++ do
++ {
++ int bit;
++ int matchBit = (matchByte >> 7) & 1;
++ matchByte <<= 1;
++ #ifdef _LZMA_LOC_OPT
++ {
++ CProb *prob = probs + ((1 + matchBit) << 8) + symbol;
++ RC_GET_BIT2(prob, symbol, bit = 0, bit = 1)
++ }
++ #else
++ bit = RangeDecoderBitDecode(probs + ((1 + matchBit) << 8) + symbol, rd);
++ symbol = (symbol << 1) | bit;
++ #endif
++ if (matchBit != bit)
++ {
++ while (symbol < 0x100)
++ {
++ #ifdef _LZMA_LOC_OPT
++ CProb *prob = probs + symbol;
++ RC_GET_BIT(prob, symbol)
++ #else
++ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
++ #endif
++ }
++ break;
++ }
++ }
++ while (symbol < 0x100);
++ #ifdef _LZMA_LOC_OPT
++ RC_FLUSH_VAR
++ #endif
++ return symbol;
++}
++
++#define kNumPosBitsMax 4
++#define kNumPosStatesMax (1 << kNumPosBitsMax)
++
++#define kLenNumLowBits 3
++#define kLenNumLowSymbols (1 << kLenNumLowBits)
++#define kLenNumMidBits 3
++#define kLenNumMidSymbols (1 << kLenNumMidBits)
++#define kLenNumHighBits 8
++#define kLenNumHighSymbols (1 << kLenNumHighBits)
++
++#define LenChoice 0
++#define LenChoice2 (LenChoice + 1)
++#define LenLow (LenChoice2 + 1)
++#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
++#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
++#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
++
++int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState)
++{
++ if(RangeDecoderBitDecode(p + LenChoice, rd) == 0)
++ return RangeDecoderBitTreeDecode(p + LenLow +
++ (posState << kLenNumLowBits), kLenNumLowBits, rd);
++ if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0)
++ return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid +
++ (posState << kLenNumMidBits), kLenNumMidBits, rd);
++ return kLenNumLowSymbols + kLenNumMidSymbols +
++ RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd);
++}
++
++#define kNumStates 12
++
++#define kStartPosModelIndex 4
++#define kEndPosModelIndex 14
++#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
++
++#define kNumPosSlotBits 6
++#define kNumLenToPosStates 4
++
++#define kNumAlignBits 4
++#define kAlignTableSize (1 << kNumAlignBits)
++
++#define kMatchMinLen 2
++
++#define IsMatch 0
++#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
++#define IsRepG0 (IsRep + kNumStates)
++#define IsRepG1 (IsRepG0 + kNumStates)
++#define IsRepG2 (IsRepG1 + kNumStates)
++#define IsRep0Long (IsRepG2 + kNumStates)
++#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
++#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
++#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
++#define LenCoder (Align + kAlignTableSize)
++#define RepLenCoder (LenCoder + kNumLenProbs)
++#define Literal (RepLenCoder + kNumLenProbs)
++
++#if Literal != LZMA_BASE_SIZE
++StopCompilingDueBUG
++#endif
++
++#ifdef _LZMA_OUT_READ
++
++typedef struct _LzmaVarState
++{
++ CRangeDecoder RangeDecoder;
++ Byte *Dictionary;
++ UInt32 DictionarySize;
++ UInt32 DictionaryPos;
++ UInt32 GlobalPos;
++ UInt32 Reps[4];
++ int lc;
++ int lp;
++ int pb;
++ int State;
++ int PreviousIsMatch;
++ int RemainLen;
++} LzmaVarState;
++
++int LzmaDecoderInit(
++ unsigned char *buffer, UInt32 bufferSize,
++ int lc, int lp, int pb,
++ unsigned char *dictionary, UInt32 dictionarySize,
++ #ifdef _LZMA_IN_CB
++ ILzmaInCallback *inCallback
++ #else
++ unsigned char *inStream, UInt32 inSize
++ #endif
++ )
++{
++ LzmaVarState *vs = (LzmaVarState *)buffer;
++ CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
++ UInt32 i;
++ if (bufferSize < numProbs * sizeof(CProb) + sizeof(LzmaVarState))
++ return LZMA_RESULT_NOT_ENOUGH_MEM;
++ vs->Dictionary = dictionary;
++ vs->DictionarySize = dictionarySize;
++ vs->DictionaryPos = 0;
++ vs->GlobalPos = 0;
++ vs->Reps[0] = vs->Reps[1] = vs->Reps[2] = vs->Reps[3] = 1;
++ vs->lc = lc;
++ vs->lp = lp;
++ vs->pb = pb;
++ vs->State = 0;
++ vs->PreviousIsMatch = 0;
++ vs->RemainLen = 0;
++ dictionary[dictionarySize - 1] = 0;
++ for (i = 0; i < numProbs; i++)
++ p[i] = kBitModelTotal >> 1;
++ RangeDecoderInit(&vs->RangeDecoder,
++ #ifdef _LZMA_IN_CB
++ inCallback
++ #else
++ inStream, inSize
++ #endif
++ );
++ return LZMA_RESULT_OK;
++}
++
++int LzmaDecode(unsigned char *buffer,
++ unsigned char *outStream, UInt32 outSize,
++ UInt32 *outSizeProcessed)
++{
++ LzmaVarState *vs = (LzmaVarState *)buffer;
++ CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
++ CRangeDecoder rd = vs->RangeDecoder;
++ int state = vs->State;
++ int previousIsMatch = vs->PreviousIsMatch;
++ Byte previousByte;
++ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
++ UInt32 nowPos = 0;
++ UInt32 posStateMask = (1 << (vs->pb)) - 1;
++ UInt32 literalPosMask = (1 << (vs->lp)) - 1;
++ int lc = vs->lc;
++ int len = vs->RemainLen;
++ UInt32 globalPos = vs->GlobalPos;
++
++ Byte *dictionary = vs->Dictionary;
++ UInt32 dictionarySize = vs->DictionarySize;
++ UInt32 dictionaryPos = vs->DictionaryPos;
++
++ if (len == -1)
++ {
++ *outSizeProcessed = 0;
++ return LZMA_RESULT_OK;
++ }
++
++ while(len > 0 && nowPos < outSize)
++ {
++ UInt32 pos = dictionaryPos - rep0;
++ if (pos >= dictionarySize)
++ pos += dictionarySize;
++ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
++ if (++dictionaryPos == dictionarySize)
++ dictionaryPos = 0;
++ len--;
++ }
++ if (dictionaryPos == 0)
++ previousByte = dictionary[dictionarySize - 1];
++ else
++ previousByte = dictionary[dictionaryPos - 1];
++#else
++
++int LzmaDecode(
++ Byte *buffer, UInt32 bufferSize,
++ int lc, int lp, int pb,
++ #ifdef _LZMA_IN_CB
++ ILzmaInCallback *inCallback,
++ #else
++ unsigned char *inStream, UInt32 inSize,
++ #endif
++ unsigned char *outStream, UInt32 outSize,
++ UInt32 *outSizeProcessed)
++{
++ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
++ CProb *p = (CProb *)buffer;
++ CRangeDecoder rd;
++ UInt32 i;
++ int state = 0;
++ int previousIsMatch = 0;
++ Byte previousByte = 0;
++ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
++ UInt32 nowPos = 0;
++ UInt32 posStateMask = (1 << pb) - 1;
++ UInt32 literalPosMask = (1 << lp) - 1;
++ int len = 0;
++ if (bufferSize < numProbs * sizeof(CProb))
++ return LZMA_RESULT_NOT_ENOUGH_MEM;
++ for (i = 0; i < numProbs; i++)
++ p[i] = kBitModelTotal >> 1;
++ RangeDecoderInit(&rd,
++ #ifdef _LZMA_IN_CB
++ inCallback
++ #else
++ inStream, inSize
++ #endif
++ );
++#endif
++
++ *outSizeProcessed = 0;
++ while(nowPos < outSize)
++ {
++ int posState = (int)(
++ (nowPos
++ #ifdef _LZMA_OUT_READ
++ + globalPos
++ #endif
++ )
++ & posStateMask);
++ #ifdef _LZMA_IN_CB
++ if (rd.Result != LZMA_RESULT_OK)
++ return rd.Result;
++ #endif
++ if (rd.ExtraBytes != 0)
++ return LZMA_RESULT_DATA_ERROR;
++ if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0)
++ {
++ CProb *probs = p + Literal + (LZMA_LIT_SIZE *
++ (((
++ (nowPos
++ #ifdef _LZMA_OUT_READ
++ + globalPos
++ #endif
++ )
++ & literalPosMask) << lc) + (previousByte >> (8 - lc))));
++
++ if (state < 4) state = 0;
++ else if (state < 10) state -= 3;
++ else state -= 6;
++ if (previousIsMatch)
++ {
++ Byte matchByte;
++ #ifdef _LZMA_OUT_READ
++ UInt32 pos = dictionaryPos - rep0;
++ if (pos >= dictionarySize)
++ pos += dictionarySize;
++ matchByte = dictionary[pos];
++ #else
++ matchByte = outStream[nowPos - rep0];
++ #endif
++ previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte);
++ previousIsMatch = 0;
++ }
++ else
++ previousByte = LzmaLiteralDecode(probs, &rd);
++ outStream[nowPos++] = previousByte;
++ #ifdef _LZMA_OUT_READ
++ dictionary[dictionaryPos] = previousByte;
++ if (++dictionaryPos == dictionarySize)
++ dictionaryPos = 0;
++ #endif
++ }
++ else
++ {
++ previousIsMatch = 1;
++ if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1)
++ {
++ if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0)
++ {
++ if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0)
++ {
++ #ifdef _LZMA_OUT_READ
++ UInt32 pos;
++ #endif
++ if (
++ (nowPos
++ #ifdef _LZMA_OUT_READ
++ + globalPos
++ #endif
++ )
++ == 0)
++ return LZMA_RESULT_DATA_ERROR;
++ state = state < 7 ? 9 : 11;
++ #ifdef _LZMA_OUT_READ
++ pos = dictionaryPos - rep0;
++ if (pos >= dictionarySize)
++ pos += dictionarySize;
++ previousByte = dictionary[pos];
++ dictionary[dictionaryPos] = previousByte;
++ if (++dictionaryPos == dictionarySize)
++ dictionaryPos = 0;
++ #else
++ previousByte = outStream[nowPos - rep0];
++ #endif
++ outStream[nowPos++] = previousByte;
++ continue;
++ }
++ }
++ else
++ {
++ UInt32 distance;
++ if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0)
++ distance = rep1;
++ else
++ {
++ if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0)
++ distance = rep2;
++ else
++ {
++ distance = rep3;
++ rep3 = rep2;
++ }
++ rep2 = rep1;
++ }
++ rep1 = rep0;
++ rep0 = distance;
++ }
++ len = LzmaLenDecode(p + RepLenCoder, &rd, posState);
++ state = state < 7 ? 8 : 11;
++ }
++ else
++ {
++ int posSlot;
++ rep3 = rep2;
++ rep2 = rep1;
++ rep1 = rep0;
++ state = state < 7 ? 7 : 10;
++ len = LzmaLenDecode(p + LenCoder, &rd, posState);
++ posSlot = RangeDecoderBitTreeDecode(p + PosSlot +
++ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
++ kNumPosSlotBits), kNumPosSlotBits, &rd);
++ if (posSlot >= kStartPosModelIndex)
++ {
++ int numDirectBits = ((posSlot >> 1) - 1);
++ rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits);
++ if (posSlot < kEndPosModelIndex)
++ {
++ rep0 += RangeDecoderReverseBitTreeDecode(
++ p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd);
++ }
++ else
++ {
++ rep0 += RangeDecoderDecodeDirectBits(&rd,
++ numDirectBits - kNumAlignBits) << kNumAlignBits;
++ rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd);
++ }
++ }
++ else
++ rep0 = posSlot;
++ rep0++;
++ }
++ if (rep0 == (UInt32)(0))
++ {
++ /* it's for stream version */
++ len = -1;
++ break;
++ }
++ if (rep0 > nowPos
++ #ifdef _LZMA_OUT_READ
++ + globalPos
++ #endif
++ )
++ {
++ return LZMA_RESULT_DATA_ERROR;
++ }
++ len += kMatchMinLen;
++ do
++ {
++ #ifdef _LZMA_OUT_READ
++ UInt32 pos = dictionaryPos - rep0;
++ if (pos >= dictionarySize)
++ pos += dictionarySize;
++ previousByte = dictionary[pos];
++ dictionary[dictionaryPos] = previousByte;
++ if (++dictionaryPos == dictionarySize)
++ dictionaryPos = 0;
++ #else
++ previousByte = outStream[nowPos - rep0];
++ #endif
++ outStream[nowPos++] = previousByte;
++ len--;
++ }
++ while(len > 0 && nowPos < outSize);
++ }
++ }
++
++ #ifdef _LZMA_OUT_READ
++ vs->RangeDecoder = rd;
++ vs->DictionaryPos = dictionaryPos;
++ vs->GlobalPos = globalPos + nowPos;
++ vs->Reps[0] = rep0;
++ vs->Reps[1] = rep1;
++ vs->Reps[2] = rep2;
++ vs->Reps[3] = rep3;
++ vs->State = state;
++ vs->PreviousIsMatch = previousIsMatch;
++ vs->RemainLen = len;
++ #endif
++
++ *outSizeProcessed = nowPos;
++ return LZMA_RESULT_OK;
++}
+diff -Nur linux-2.6.16/fs/squashfs/LzmaDecode.h linux-2.6.16-owrt/fs/squashfs/LzmaDecode.h
+--- linux-2.6.16/fs/squashfs/LzmaDecode.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/fs/squashfs/LzmaDecode.h 2006-03-21 10:56:57.000000000 +0100
+@@ -0,0 +1,100 @@
++/*
++ LzmaDecode.h
++ LZMA Decoder interface
++
++ LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
++ http://www.7-zip.org/
++
++ LZMA SDK is licensed under two licenses:
++ 1) GNU Lesser General Public License (GNU LGPL)
++ 2) Common Public License (CPL)
++ It means that you can select one of these two licenses and
++ follow rules of that license.
++
++ SPECIAL EXCEPTION:
++ Igor Pavlov, as the author of this code, expressly permits you to
++ statically or dynamically link your code (or bind by name) to the
++ interfaces of this file without subjecting your linked code to the
++ terms of the CPL or GNU LGPL. Any modifications or additions
++ to this file, however, are subject to the LGPL or CPL terms.
++*/
++
++#ifndef __LZMADECODE_H
++#define __LZMADECODE_H
++
++/* #define _LZMA_IN_CB */
++/* Use callback for input data */
++
++/* #define _LZMA_OUT_READ */
++/* Use read function for output data */
++
++/* #define _LZMA_PROB32 */
++/* It can increase speed on some 32-bit CPUs,
++ but memory usage will be doubled in that case */
++
++/* #define _LZMA_LOC_OPT */
++/* Enable local speed optimizations inside code */
++
++#ifndef UInt32
++#ifdef _LZMA_UINT32_IS_ULONG
++#define UInt32 unsigned long
++#else
++#define UInt32 unsigned int
++#endif
++#endif
++
++#ifdef _LZMA_PROB32
++#define CProb UInt32
++#else
++#define CProb unsigned short
++#endif
++
++#define LZMA_RESULT_OK 0
++#define LZMA_RESULT_DATA_ERROR 1
++#define LZMA_RESULT_NOT_ENOUGH_MEM 2
++
++#ifdef _LZMA_IN_CB
++typedef struct _ILzmaInCallback
++{
++ int (*Read)(void *object, unsigned char **buffer, UInt32 *bufferSize);
++} ILzmaInCallback;
++#endif
++
++#define LZMA_BASE_SIZE 1846
++#define LZMA_LIT_SIZE 768
++
++/*
++bufferSize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb)
++bufferSize += 100 in case of _LZMA_OUT_READ
++by default CProb is unsigned short,
++but if specify _LZMA_PROB_32, CProb will be UInt32(unsigned int)
++*/
++
++#ifdef _LZMA_OUT_READ
++int LzmaDecoderInit(
++ unsigned char *buffer, UInt32 bufferSize,
++ int lc, int lp, int pb,
++ unsigned char *dictionary, UInt32 dictionarySize,
++ #ifdef _LZMA_IN_CB
++ ILzmaInCallback *inCallback
++ #else
++ unsigned char *inStream, UInt32 inSize
++ #endif
++);
++#endif
++
++int LzmaDecode(
++ unsigned char *buffer,
++ #ifndef _LZMA_OUT_READ
++ UInt32 bufferSize,
++ int lc, int lp, int pb,
++ #ifdef _LZMA_IN_CB
++ ILzmaInCallback *inCallback,
++ #else
++ unsigned char *inStream, UInt32 inSize,
++ #endif
++ #endif
++ unsigned char *outStream, UInt32 outSize,
++ UInt32 *outSizeProcessed);
++
++#endif
+diff -Nur linux-2.6.16/fs/squashfs/Makefile linux-2.6.16-owrt/fs/squashfs/Makefile
+--- linux-2.6.16/fs/squashfs/Makefile 2006-03-21 10:55:59.000000000 +0100
++++ linux-2.6.16-owrt/fs/squashfs/Makefile 2006-03-21 10:57:08.000000000 +0100
+@@ -5,3 +5,4 @@
+ obj-$(CONFIG_SQUASHFS) += squashfs.o
+ squashfs-y += inode.o
+ squashfs-y += squashfs2_0.o
++squashfs-y += LzmaDecode.o
diff --git a/target/linux/generic-2.6/patches/004-extra_optimization.patch b/target/linux/generic-2.6/patches/004-extra_optimization.patch
new file mode 100644
index 0000000..805d2f0
--- /dev/null
+++ b/target/linux/generic-2.6/patches/004-extra_optimization.patch
@@ -0,0 +1,12 @@
+--- linux-2.6.12.5/Makefile.old 2005-10-23 22:56:29.017270000 +0200
++++ linux-2.6.12.5/Makefile 2005-10-23 22:57:23.226138500 +0200
+@@ -533,6 +533,9 @@
+ NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
+ CHECKFLAGS += $(NOSTDINC_FLAGS)
+
++# improve gcc optimization
++CFLAGS += $(call cc-option,-funit-at-a-time,)
++
+ # warn about C99 declaration after statement
+ CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
+
diff --git a/target/linux/generic-2.6/patches/005-gcc4_fix.patch b/target/linux/generic-2.6/patches/005-gcc4_fix.patch
new file mode 100644
index 0000000..99489b9
--- /dev/null
+++ b/target/linux/generic-2.6/patches/005-gcc4_fix.patch
@@ -0,0 +1,221 @@
+diff -ruN linux-2.6.15.1/include/asm-ppc/libgcc.h linux-2.6.15.1-openwrt/include/asm-ppc/libgcc.h
+--- linux-2.6.15.1/include/asm-ppc/libgcc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15.1-openwrt/include/asm-ppc/libgcc.h 2006-02-01 15:47:53.000000000 +0100
+@@ -0,0 +1,8 @@
++#ifndef __ASM_LIBGCC_H
++#define __ASM_LIBGCC_H
++
++#undef ARCH_NEEDS_ashldi3
++#undef ARCH_NEEDS_ashrdi3
++#undef ARCH_NEEDS_lshrdi3
++
++#endif /* __ASM_LIBGCC_H */
+diff -ruN linux-2.6.15.1/include/asm-i386/libgcc.h linux-2.6.15.1-openwrt/include/asm-i386/libgcc.h
+--- linux-2.6.15.1/include/asm-i386/libgcc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15.1-openwrt/include/asm-i386/libgcc.h 2006-02-01 15:47:53.000000000 +0100
+@@ -0,0 +1,8 @@
++#ifndef __ASM_LIBGCC_H
++#define __ASM_LIBGCC_H
++
++#undef ARCH_NEEDS_ashldi3
++#undef ARCH_NEEDS_ashrdi3
++#undef ARCH_NEEDS_lshrdi3
++
++#endif /* __ASM_LIBGCC_H */
+diff -ruN linux-2.6.15.1/include/asm-um/libgcc.h linux-2.6.15.1-openwrt/include/asm-i386/libgcc.h
+--- linux-2.6.15.1/include/asm-um/libgcc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15.1-openwrt/include/asm-um/libgcc.h 2006-02-01 15:47:53.000000000 +0100
+@@ -0,0 +1,8 @@
++#ifndef __ASM_LIBGCC_H
++#define __ASM_LIBGCC_H
++
++#undef ARCH_NEEDS_ashldi3
++#undef ARCH_NEEDS_ashrdi3
++#undef ARCH_NEEDS_lshrdi3
++
++#endif /* __ASM_LIBGCC_H */
+diff -Nur linux-2.6.15.1/include/asm-mips/libgcc.h linux-2.6.15.1-openwrt/include/asm-mips/libgcc.h
+--- linux-2.6.15.1/include/asm-mips/libgcc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15.1-openwrt/include/asm-mips/libgcc.h 2006-01-20 10:32:28.000000000 +0100
+@@ -0,0 +1,8 @@
++#ifndef __ASM_LIBGCC_H
++#define __ASM_LIBGCC_H
++
++#define ARCH_NEEDS_ashldi3
++#define ARCH_NEEDS_ashrdi3
++#define ARCH_NEEDS_lshrdi3
++
++#endif /* __ASM_LIBGCC_H */
+diff -Nur linux-2.6.15.1/include/linux/libgcc.h linux-2.6.15.1-openwrt/include/linux/libgcc.h
+--- linux-2.6.15.1/include/linux/libgcc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15.1-openwrt/include/linux/libgcc.h 2006-01-20 10:33:38.000000000 +0100
+@@ -0,0 +1,32 @@
++#ifndef __LINUX_LIBGCC_H
++#define __LINUX_LIBGCC_H
++
++#include <asm/byteorder.h>
++#include <asm/libgcc.h>
++
++typedef long long DWtype;
++typedef int Wtype;
++typedef unsigned int UWtype;
++typedef int word_type __attribute__ ((mode (__word__)));
++
++#define BITS_PER_UNIT 8
++
++#ifdef __BIG_ENDIAN
++struct DWstruct {
++ Wtype high, low;
++};
++#elif defined(__LITTLE_ENDIAN)
++struct DWstruct {
++ Wtype low, high;
++};
++#else
++#error I feel sick.
++#endif
++
++typedef union
++{
++ struct DWstruct s;
++ DWtype ll;
++} DWunion;
++
++#endif /* __LINUX_LIBGCC_H */
+diff -Nur linux-2.6.15.1/lib/ashldi3.c linux-2.6.15.1-openwrt/lib/ashldi3.c
+--- linux-2.6.15.1/lib/ashldi3.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15.1-openwrt/lib/ashldi3.c 2006-01-20 10:38:41.000000000 +0100
+@@ -0,0 +1,32 @@
++#include <linux/libgcc.h>
++#include <linux/module.h>
++
++#ifdef ARCH_NEEDS_ashldi3
++
++DWtype __ashldi3(DWtype u, word_type b)
++{
++ DWunion uu, w;
++ word_type bm;
++
++ if (b == 0)
++ return u;
++
++ uu.ll = u;
++ bm = (sizeof(Wtype) * BITS_PER_UNIT) - b;
++
++ if (bm <= 0) {
++ w.s.low = 0;
++ w.s.high = (UWtype) uu.s.low << -bm;
++ } else {
++ const UWtype carries = (UWtype) uu.s.low >> bm;
++
++ w.s.low = (UWtype) uu.s.low << b;
++ w.s.high = ((UWtype) uu.s.high << b) | carries;
++ }
++
++ return w.ll;
++}
++
++EXPORT_SYMBOL(__ashldi3);
++
++#endif /* ARCH_NEEDS_ashldi3 */
+diff -Nur linux-2.6.15.1/lib/ashrdi3.c linux-2.6.15.1-openwrt/lib/ashrdi3.c
+--- linux-2.6.15.1/lib/ashrdi3.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15.1-openwrt/lib/ashrdi3.c 2006-01-20 10:39:29.000000000 +0100
+@@ -0,0 +1,36 @@
++#include <linux/libgcc.h>
++#include <linux/module.h>
++
++/* Unless shift functions are defined with full ANSI prototypes,
++ parameter b will be promoted to int if word_type is smaller than an int. */
++#ifdef ARCH_NEEDS_ashrdi3
++
++DWtype __ashrdi3(DWtype u, word_type b)
++{
++ DWunion uu, w;
++ word_type bm;
++
++ if (b == 0)
++ return u;
++
++ uu.ll = u;
++ bm = (sizeof(Wtype) * BITS_PER_UNIT) - b;
++
++ if (bm <= 0) {
++ /* w.s.high = 1..1 or 0..0 */
++ w.s.high =
++ uu.s.high >> (sizeof(Wtype) * BITS_PER_UNIT - 1);
++ w.s.low = uu.s.high >> -bm;
++ } else {
++ const UWtype carries = (UWtype) uu.s.high << bm;
++
++ w.s.high = uu.s.high >> b;
++ w.s.low = ((UWtype) uu.s.low >> b) | carries;
++ }
++
++ return w.ll;
++}
++
++EXPORT_SYMBOL(__ashrdi3);
++
++#endif /* ARCH_NEEDS_ashrdi3 */
+diff -Nur linux-2.6.15.1/lib/lshrdi3.c linux-2.6.15.1-openwrt/lib/lshrdi3.c
+--- linux-2.6.15.1/lib/lshrdi3.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15.1-openwrt/lib/lshrdi3.c 2006-01-20 10:40:10.000000000 +0100
+@@ -0,0 +1,34 @@
++#include <linux/libgcc.h>
++#include <linux/module.h>
++
++/* Unless shift functions are defined with full ANSI prototypes,
++ parameter b will be promoted to int if word_type is smaller than an int. */
++#ifdef ARCH_NEEDS_lshrdi3
++
++DWtype __lshrdi3(DWtype u, word_type b)
++{
++ DWunion uu, w;
++ word_type bm;
++
++ if (b == 0)
++ return u;
++
++ uu.ll = u;
++ bm = (sizeof(Wtype) * BITS_PER_UNIT) - b;
++
++ if (bm <= 0) {
++ w.s.high = 0;
++ w.s.low = (UWtype) uu.s.high >> -bm;
++ } else {
++ const UWtype carries = (UWtype) uu.s.high << bm;
++
++ w.s.high = (UWtype) uu.s.high >> b;
++ w.s.low = ((UWtype) uu.s.low >> b) | carries;
++ }
++
++ return w.ll;
++}
++
++EXPORT_SYMBOL(__lshrdi3);
++
++#endif /* ARCH_NEEDS_lshrdi3 */
+diff -Nur linux-2.6.15.1/lib/Makefile linux-2.6.15.1-openwrt/lib/Makefile
+--- linux-2.6.15.1/lib/Makefile 2006-01-15 07:16:02.000000000 +0100
++++ linux-2.6.15.1-openwrt/lib/Makefile 2006-01-20 10:34:19.000000000 +0100
+@@ -8,6 +8,7 @@
+ sha1.o
+
+ lib-y += kobject.o kref.o kobject_uevent.o klist.o
++obj-y += ashldi3.o ashrdi3.o lshrdi3.o
+
+ obj-y += sort.o parser.o halfmd4.o
+
+diff -Nur linux-2.6.15.1/include/asm-arm/libgcc.h linux-2.6.15.1-openwrt/include/asm-arm/libgcc.h
+--- linux-2.6.15.1/include/asm-arm/libgcc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15.1-openwrt/include/asm-arm/libgcc.h 2006-04-12 23:01:18.000000000 +0200
+@@ -0,0 +1,8 @@
++#ifndef __ASM_LIBGCC_H
++#define __ASM_LIBGCC_H
++
++#undef ARCH_NEEDS_ashldi3
++#undef ARCH_NEEDS_ashrdi3
++#undef ARCH_NEEDS_lshrdi3
++
++#endif /* __ASM_LIBGCC_H */
diff --git a/target/linux/generic-2.6/patches/006-gcc4_inline_fix.patch b/target/linux/generic-2.6/patches/006-gcc4_inline_fix.patch
new file mode 100644
index 0000000..e95663e
--- /dev/null
+++ b/target/linux/generic-2.6/patches/006-gcc4_inline_fix.patch
@@ -0,0 +1,11 @@
+--- linux-2.6.15.1.old/include/asm-mips/system.h 2006-01-28 15:02:54.481032280 +0100
++++ linux-2.6.15.1.dev/include/asm-mips/system.h 2006-01-28 14:47:51.634285848 +0100
+@@ -273,7 +273,7 @@
+ if something tries to do an invalid xchg(). */
+ extern void __xchg_called_with_bad_pointer(void);
+
+-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
++static __always_inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+ {
+ switch (size) {
+ case 4:
diff --git a/target/linux/generic-2.6/patches/010-disable_old_squashfs_compatibility.patch b/target/linux/generic-2.6/patches/010-disable_old_squashfs_compatibility.patch
new file mode 100644
index 0000000..1b8b61a
--- /dev/null
+++ b/target/linux/generic-2.6/patches/010-disable_old_squashfs_compatibility.patch
@@ -0,0 +1,22 @@
+diff -Nur linux-2.6.16/fs/squashfs/Makefile linux-2.6.16-owrt/fs/squashfs/Makefile
+--- linux-2.6.16/fs/squashfs/Makefile 2006-03-21 13:50:31.000000000 +0100
++++ linux-2.6.16-owrt/fs/squashfs/Makefile 2006-03-21 13:51:09.000000000 +0100
+@@ -4,5 +4,4 @@
+
+ obj-$(CONFIG_SQUASHFS) += squashfs.o
+ squashfs-y += inode.o
+-squashfs-y += squashfs2_0.o
+ squashfs-y += LzmaDecode.o
+diff -Nur linux-2.6.16/fs/squashfs/squashfs.h linux-2.6.16-owrt/fs/squashfs/squashfs.h
+--- linux-2.6.16/fs/squashfs/squashfs.h 2006-03-21 10:55:59.000000000 +0100
++++ linux-2.6.16-owrt/fs/squashfs/squashfs.h 2006-03-21 13:50:58.000000000 +0100
+@@ -24,6 +24,9 @@
+ #ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+ #undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
+ #endif
++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++#undef CONFIG_SQUASHFS_2_0_COMPATIBILITY
++#endif
+
+ #ifdef SQUASHFS_TRACE
+ #define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args)
diff --git a/target/linux/generic-2.6/patches/011-mips_boot.patch b/target/linux/generic-2.6/patches/011-mips_boot.patch
new file mode 100644
index 0000000..611c70d
--- /dev/null
+++ b/target/linux/generic-2.6/patches/011-mips_boot.patch
@@ -0,0 +1,15 @@
+diff -Nur linux-cvs/arch/mips/kernel/head.S linux-aruba/arch/mips/kernel/head.S
+--- linux-cvs/arch/mips/kernel/head.S 2004-12-23 00:21:39.000000000 -0800
++++ linux-aruba/arch/mips/kernel/head.S 2005-10-20 09:16:08.000000000 -0700
+@@ -122,6 +122,10 @@
+ #endif
+ .endm
+
++
++ j kernel_entry
++ nop
++
+ /*
+ * Reserved space for exception handlers.
+ * Necessary for machines which link their kernels at KSEG0.
+
diff --git a/target/linux/generic-2.6/patches/100-netfilter_layer7_2.1nbd.patch b/target/linux/generic-2.6/patches/100-netfilter_layer7_2.1nbd.patch
new file mode 100644
index 0000000..ec3929b
--- /dev/null
+++ b/target/linux/generic-2.6/patches/100-netfilter_layer7_2.1nbd.patch
@@ -0,0 +1,2071 @@
+diff -Nur linux-2.6.17/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.17-owrt/include/linux/netfilter_ipv4/ip_conntrack.h
+--- linux-2.6.17/include/linux/netfilter_ipv4/ip_conntrack.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/linux/netfilter_ipv4/ip_conntrack.h 2006-06-18 12:29:04.000000000 +0200
+@@ -124,6 +124,15 @@
+ /* Traversed often, so hopefully in different cacheline to top */
+ /* These are my tuples; original and reply */
+ struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
++
++#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE)
++ struct {
++ char * app_proto; /* e.g. "http". NULL before decision. "unknown" after decision if no match */
++ char * app_data; /* application layer data so far. NULL after match decision */
++ unsigned int app_data_len;
++ } layer7;
++#endif
++
+ };
+
+ struct ip_conntrack_expect
+diff -Nur linux-2.6.17/include/linux/netfilter_ipv4/ipt_layer7.h linux-2.6.17-owrt/include/linux/netfilter_ipv4/ipt_layer7.h
+--- linux-2.6.17/include/linux/netfilter_ipv4/ipt_layer7.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/linux/netfilter_ipv4/ipt_layer7.h 2006-06-18 12:29:04.000000000 +0200
+@@ -0,0 +1,27 @@
++/*
++ By Matthew Strait <quadong@users.sf.net>, Dec 2003.
++ http://l7-filter.sf.net
++
++ 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.
++ http://www.gnu.org/licenses/gpl.txt
++*/
++
++#ifndef _IPT_LAYER7_H
++#define _IPT_LAYER7_H
++
++#define MAX_PATTERN_LEN 8192
++#define MAX_PROTOCOL_LEN 256
++
++typedef char *(*proc_ipt_search) (char *, char, char *);
++
++struct ipt_layer7_info {
++ char protocol[MAX_PROTOCOL_LEN];
++ char invert:1;
++ char pattern[MAX_PATTERN_LEN];
++ char pkt;
++};
++
++#endif /* _IPT_LAYER7_H */
+diff -Nur linux-2.6.17/net/ipv4/netfilter/ip_conntrack_core.c linux-2.6.17-owrt/net/ipv4/netfilter/ip_conntrack_core.c
+--- linux-2.6.17/net/ipv4/netfilter/ip_conntrack_core.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/netfilter/ip_conntrack_core.c 2006-06-18 12:29:04.000000000 +0200
+@@ -339,6 +339,13 @@
+ * too. */
+ ip_ct_remove_expectations(ct);
+
++ #if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE)
++ if(ct->layer7.app_proto)
++ kfree(ct->layer7.app_proto);
++ if(ct->layer7.app_data)
++ kfree(ct->layer7.app_data);
++ #endif
++
+ /* We overload first tuple to link into unconfirmed list. */
+ if (!is_confirmed(ct)) {
+ BUG_ON(list_empty(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list));
+diff -Nur linux-2.6.17/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.6.17-owrt/net/ipv4/netfilter/ip_conntrack_standalone.c
+--- linux-2.6.17/net/ipv4/netfilter/ip_conntrack_standalone.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/netfilter/ip_conntrack_standalone.c 2006-06-18 12:29:04.000000000 +0200
+@@ -189,6 +189,12 @@
+ return -ENOSPC;
+ #endif
+
++#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE)
++ if(conntrack->layer7.app_proto)
++ if (seq_printf(s, "l7proto=%s ",conntrack->layer7.app_proto))
++ return 1;
++#endif
++
+ if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
+ return -ENOSPC;
+
+diff -Nur linux-2.6.17/net/ipv4/netfilter/ipt_layer7.c linux-2.6.17-owrt/net/ipv4/netfilter/ipt_layer7.c
+--- linux-2.6.17/net/ipv4/netfilter/ipt_layer7.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/net/ipv4/netfilter/ipt_layer7.c 2006-06-18 12:29:04.000000000 +0200
+@@ -0,0 +1,592 @@
++/*
++ Kernel module to match application layer (OSI layer 7)
++ data in connections.
++
++ http://l7-filter.sf.net
++
++ By Matthew Strait and Ethan Sommer, 2003-2005.
++
++ 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.
++ http://www.gnu.org/licenses/gpl.txt
++
++ Based on ipt_string.c (C) 2000 Emmanuel Roger <winfield@freegates.be>
++ and cls_layer7.c (C) 2003 Matthew Strait, Ethan Sommer, Justin Levandoski
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/proc_fs.h>
++#include <linux/ctype.h>
++#include <net/ip.h>
++#include <net/tcp.h>
++#include <linux/spinlock.h>
++
++#include "regexp/regexp.c"
++
++#include <linux/netfilter_ipv4/ipt_layer7.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++
++MODULE_AUTHOR("Matthew Strait <quadong@users.sf.net>, Ethan Sommer <sommere@users.sf.net>");
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("iptables application layer match module");
++MODULE_VERSION("2.0");
++
++static int maxdatalen = 2048; // this is the default
++module_param(maxdatalen, int, 0444);
++MODULE_PARM_DESC(maxdatalen, "maximum bytes of data looked at by l7-filter");
++
++#ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG
++ #define DPRINTK(format,args...) printk(format,##args)
++#else
++ #define DPRINTK(format,args...)
++#endif
++
++#define TOTAL_PACKETS master_conntrack->counters[IP_CT_DIR_ORIGINAL].packets + \
++ master_conntrack->counters[IP_CT_DIR_REPLY].packets
++
++/* Number of packets whose data we look at.
++This can be modified through /proc/net/layer7_numpackets */
++static int num_packets = 10;
++
++static struct pattern_cache {
++ char * regex_string;
++ regexp * pattern;
++ struct pattern_cache * next;
++} * first_pattern_cache = NULL;
++
++/* I'm new to locking. Here are my assumptions:
++
++- No one will write to /proc/net/layer7_numpackets over and over very fast;
++ if they did, nothing awful would happen.
++
++- This code will never be processing the same packet twice at the same time,
++ because iptables rules are traversed in order.
++
++- It doesn't matter if two packets from different connections are in here at
++ the same time, because they don't share any data.
++
++- It _does_ matter if two packets from the same connection are here at the same
++ time. In this case, we have to protect the conntracks and the list of
++ compiled patterns.
++*/
++DEFINE_RWLOCK(ct_lock);
++DEFINE_SPINLOCK(list_lock);
++
++#ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG
++/* Converts an unfriendly string into a friendly one by
++replacing unprintables with periods and all whitespace with " ". */
++static char * friendly_print(unsigned char * s)
++{
++ char * f = kmalloc(strlen(s) + 1, GFP_ATOMIC);
++ int i;
++
++ if(!f) {
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in friendly_print, bailing.\n");
++ return NULL;
++ }
++
++ for(i = 0; i < strlen(s); i++){
++ if(isprint(s[i]) && s[i] < 128) f[i] = s[i];
++ else if(isspace(s[i])) f[i] = ' ';
++ else f[i] = '.';
++ }
++ f[i] = '\0';
++ return f;
++}
++
++static char dec2hex(int i)
++{
++ switch (i) {
++ case 0 ... 9:
++ return (char)(i + '0');
++ break;
++ case 10 ... 15:
++ return (char)(i - 10 + 'a');
++ break;
++ default:
++ if (net_ratelimit())
++ printk("Problem in dec2hex\n");
++ return '\0';
++ }
++}
++
++static char * hex_print(unsigned char * s)
++{
++ char * g = kmalloc(strlen(s)*3 + 1, GFP_ATOMIC);
++ int i;
++
++ if(!g) {
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in hex_print, bailing.\n");
++ return NULL;
++ }
++
++ for(i = 0; i < strlen(s); i++) {
++ g[i*3 ] = dec2hex(s[i]/16);
++ g[i*3 + 1] = dec2hex(s[i]%16);
++ g[i*3 + 2] = ' ';
++ }
++ g[i*3] = '\0';
++
++ return g;
++}
++#endif // DEBUG
++
++/* Use instead of regcomp. As we expect to be seeing the same regexps over and
++over again, it make sense to cache the results. */
++static regexp * compile_and_cache(char * regex_string, char * protocol)
++{
++ struct pattern_cache * node = first_pattern_cache;
++ struct pattern_cache * last_pattern_cache = first_pattern_cache;
++ struct pattern_cache * tmp;
++ unsigned int len;
++
++ while (node != NULL) {
++ if (!strcmp(node->regex_string, regex_string))
++ return node->pattern;
++
++ last_pattern_cache = node;/* points at the last non-NULL node */
++ node = node->next;
++ }
++
++ /* If we reach the end of the list, then we have not yet cached
++ the pattern for this regex. Let's do that now.
++ Be paranoid about running out of memory to avoid list corruption. */
++ tmp = kmalloc(sizeof(struct pattern_cache), GFP_ATOMIC);
++
++ if(!tmp) {
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n");
++ return NULL;
++ }
++
++ tmp->regex_string = kmalloc(strlen(regex_string) + 1, GFP_ATOMIC);
++ tmp->pattern = kmalloc(sizeof(struct regexp), GFP_ATOMIC);
++ tmp->next = NULL;
++
++ if(!tmp->regex_string || !tmp->pattern) {
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in compile_and_cache, bailing.\n");
++ kfree(tmp->regex_string);
++ kfree(tmp->pattern);
++ kfree(tmp);
++ return NULL;
++ }
++
++ /* Ok. The new node is all ready now. */
++ node = tmp;
++
++ if(first_pattern_cache == NULL) /* list is empty */
++ first_pattern_cache = node; /* make node the beginning */
++ else
++ last_pattern_cache->next = node; /* attach node to the end */
++
++ /* copy the string and compile the regex */
++ len = strlen(regex_string);
++ DPRINTK("About to compile this: \"%s\"\n", regex_string);
++ node->pattern = regcomp(regex_string, &len);
++ if ( !node->pattern ) {
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: Error compiling regexp \"%s\" (%s)\n", regex_string, protocol);
++ /* pattern is now cached as NULL, so we won't try again. */
++ }
++
++ strcpy(node->regex_string, regex_string);
++ return node->pattern;
++}
++
++static int can_handle(const struct sk_buff *skb)
++{
++ if(!skb->nh.iph) /* not IP */
++ return 0;
++ if(skb->nh.iph->protocol != IPPROTO_TCP &&
++ skb->nh.iph->protocol != IPPROTO_UDP &&
++ skb->nh.iph->protocol != IPPROTO_ICMP)
++ return 0;
++ return 1;
++}
++
++/* Returns offset the into the skb->data that the application data starts */
++static int app_data_offset(const struct sk_buff *skb)
++{
++ /* In case we are ported somewhere (ebtables?) where skb->nh.iph
++ isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */
++ int ip_hl = 4*skb->nh.iph->ihl;
++
++ if( skb->nh.iph->protocol == IPPROTO_TCP ) {
++ /* 12 == offset into TCP header for the header length field.
++ Can't get this with skb->h.th->doff because the tcphdr
++ struct doesn't get set when routing (this is confirmed to be
++ true in Netfilter as well as QoS.) */
++ int tcp_hl = 4*(skb->data[ip_hl + 12] >> 4);
++
++ return ip_hl + tcp_hl;
++ } else if( skb->nh.iph->protocol == IPPROTO_UDP ) {
++ return ip_hl + 8; /* UDP header is always 8 bytes */
++ } else if( skb->nh.iph->protocol == IPPROTO_ICMP ) {
++ return ip_hl + 8; /* ICMP header is 8 bytes */
++ } else {
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: tried to handle unknown protocol!\n");
++ return ip_hl + 8; /* something reasonable */
++ }
++}
++
++/* handles whether there's a match when we aren't appending data anymore */
++static int match_no_append(struct ip_conntrack * conntrack, struct ip_conntrack * master_conntrack,
++ enum ip_conntrack_info ctinfo, enum ip_conntrack_info master_ctinfo,
++ struct ipt_layer7_info * info)
++{
++ /* If we're in here, throw the app data away */
++ write_lock(&ct_lock);
++ if(master_conntrack->layer7.app_data != NULL) {
++
++ #ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG
++ if(!master_conntrack->layer7.app_proto) {
++ char * f = friendly_print(master_conntrack->layer7.app_data);
++ char * g = hex_print(master_conntrack->layer7.app_data);
++ DPRINTK("\nl7-filter gave up after %d bytes (%llu packets):\n%s\n",
++ strlen(f),
++ TOTAL_PACKETS, f);
++ kfree(f);
++ DPRINTK("In hex: %s\n", g);
++ kfree(g);
++ }
++ #endif
++
++ kfree(master_conntrack->layer7.app_data);
++ master_conntrack->layer7.app_data = NULL; /* don't free again */
++ }
++ write_unlock(&ct_lock);
++
++ if(master_conntrack->layer7.app_proto){
++ /* Here child connections set their .app_proto (for /proc/net/ip_conntrack) */
++ write_lock(&ct_lock);
++ if(!conntrack->layer7.app_proto) {
++ conntrack->layer7.app_proto = kmalloc(strlen(master_conntrack->layer7.app_proto)+1, GFP_ATOMIC);
++ if(!conntrack->layer7.app_proto){
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n");
++ write_unlock(&ct_lock);
++ return 1;
++ }
++ strcpy(conntrack->layer7.app_proto, master_conntrack->layer7.app_proto);
++ }
++ write_unlock(&ct_lock);
++
++ return (!strcmp(master_conntrack->layer7.app_proto, info->protocol));
++ }
++ else {
++ /* If not classified, set to "unknown" to distinguish from
++ connections that are still being tested. */
++ write_lock(&ct_lock);
++ master_conntrack->layer7.app_proto = kmalloc(strlen("unknown")+1, GFP_ATOMIC);
++ if(!master_conntrack->layer7.app_proto){
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in match_no_append, bailing.\n");
++ write_unlock(&ct_lock);
++ return 1;
++ }
++ strcpy(master_conntrack->layer7.app_proto, "unknown");
++ write_unlock(&ct_lock);
++ return 0;
++ }
++}
++
++static int add_datastr(char *target, int offset, char *app_data, int len)
++{
++ int length = 0, i;
++
++ /* Strip nulls. Make everything lower case (our regex lib doesn't
++ do case insensitivity). Add it to the end of the current data. */
++ for(i = 0; i < maxdatalen-offset-1 && i < len; i++) {
++ if(app_data[i] != '\0') {
++ target[length+offset] =
++ /* the kernel version of tolower mungs 'upper ascii' */
++ isascii(app_data[i])? tolower(app_data[i]) : app_data[i];
++ length++;
++ }
++ }
++ target[length+offset] = '\0';
++
++ return length;
++}
++
++/* add the new app data to the conntrack. Return number of bytes added. */
++static int add_data(struct ip_conntrack * master_conntrack,
++ char * app_data, int appdatalen)
++{
++ int length;
++
++ length = add_datastr(master_conntrack->layer7.app_data, master_conntrack->layer7.app_data_len, app_data, appdatalen);
++ master_conntrack->layer7.app_data_len += length;
++
++ return length;
++}
++
++/* Returns true on match and false otherwise. */
++static int match(/* const */struct sk_buff *skb, const struct net_device *in,
++ const struct net_device *out, const void *matchinfo,
++ int offset, int *hotdrop)
++{
++ struct ipt_layer7_info * info = (struct ipt_layer7_info *)matchinfo;
++ enum ip_conntrack_info master_ctinfo, ctinfo;
++ struct ip_conntrack *master_conntrack, *conntrack;
++ unsigned char *app_data, *tmp_data;
++ unsigned int pattern_result, appdatalen;
++ regexp * comppattern;
++
++ if(!can_handle(skb)){
++ DPRINTK("layer7: This is some protocol I can't handle.\n");
++ return info->invert;
++ }
++
++ /* Treat parent & all its children together as one connection, except
++ for the purpose of setting conntrack->layer7.app_proto in the actual
++ connection. This makes /proc/net/ip_conntrack more satisfying. */
++ if(!(conntrack = ip_conntrack_get((struct sk_buff *)skb, &ctinfo)) ||
++ !(master_conntrack = ip_conntrack_get((struct sk_buff *)skb, &master_ctinfo))) {
++ //DPRINTK("layer7: packet is not from a known connection, giving up.\n");
++ return info->invert;
++ }
++
++ /* Try to get a master conntrack (and its master etc) for FTP, etc. */
++ while (master_ct(master_conntrack) != NULL)
++ master_conntrack = master_ct(master_conntrack);
++
++ /* if we've classified it or seen too many packets */
++ if(!info->pkt && (TOTAL_PACKETS > num_packets ||
++ master_conntrack->layer7.app_proto)) {
++
++ pattern_result = match_no_append(conntrack, master_conntrack, ctinfo, master_ctinfo, info);
++
++ /* skb->cb[0] == seen. Avoid doing things twice if there are two l7
++ rules. I'm not sure that using cb for this purpose is correct, although
++ it says "put your private variables there". But it doesn't look like it
++ is being used for anything else in the skbs that make it here. How can
++ I write to cb without making the compiler angry? */
++ skb->cb[0] = 1; /* marking it seen here is probably irrelevant, but consistant */
++
++ return (pattern_result ^ info->invert);
++ }
++
++ if(skb_is_nonlinear(skb)){
++ if(skb_linearize(skb, GFP_ATOMIC) != 0){
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: failed to linearize packet, bailing.\n");
++ return info->invert;
++ }
++ }
++
++ /* now that the skb is linearized, it's safe to set these. */
++ app_data = skb->data + app_data_offset(skb);
++ appdatalen = skb->tail - app_data;
++
++ spin_lock_bh(&list_lock);
++ /* the return value gets checked later, when we're ready to use it */
++ comppattern = compile_and_cache(info->pattern, info->protocol);
++ spin_unlock_bh(&list_lock);
++
++ if (info->pkt) {
++ tmp_data = kmalloc(maxdatalen, GFP_ATOMIC);
++ if(!tmp_data){
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in match, bailing.\n");
++ return info->invert;
++ }
++
++ tmp_data[0] = '\0';
++ add_datastr(tmp_data, 0, app_data, appdatalen);
++ pattern_result = ((comppattern && regexec(comppattern, tmp_data)) ? 1 : 0);
++ kfree(tmp_data);
++ tmp_data = NULL;
++
++ return (pattern_result ^ info->invert);
++ }
++
++ /* On the first packet of a connection, allocate space for app data */
++ write_lock(&ct_lock);
++ if(TOTAL_PACKETS == 1 && !skb->cb[0] && !master_conntrack->layer7.app_data) {
++ master_conntrack->layer7.app_data = kmalloc(maxdatalen, GFP_ATOMIC);
++ if(!master_conntrack->layer7.app_data){
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in match, bailing.\n");
++ write_unlock(&ct_lock);
++ return info->invert;
++ }
++
++ master_conntrack->layer7.app_data[0] = '\0';
++ }
++ write_unlock(&ct_lock);
++
++ /* Can be here, but unallocated, if numpackets is increased near
++ the beginning of a connection */
++ if(master_conntrack->layer7.app_data == NULL)
++ return (info->invert); /* unmatched */
++
++ if(!skb->cb[0]){
++ int newbytes;
++ write_lock(&ct_lock);
++ newbytes = add_data(master_conntrack, app_data, appdatalen);
++ write_unlock(&ct_lock);
++
++ if(newbytes == 0) { /* didn't add any data */
++ skb->cb[0] = 1;
++ /* Didn't match before, not going to match now */
++ return info->invert;
++ }
++ }
++
++ /* If looking for "unknown", then never match. "Unknown" means that
++ we've given up; we're still trying with these packets. */
++ if(!strcmp(info->protocol, "unknown")) {
++ pattern_result = 0;
++ /* If the regexp failed to compile, don't bother running it */
++ } else if(comppattern && regexec(comppattern, master_conntrack->layer7.app_data)) {
++ DPRINTK("layer7: matched %s\n", info->protocol);
++ pattern_result = 1;
++ } else pattern_result = 0;
++
++ if(pattern_result) {
++ write_lock(&ct_lock);
++ master_conntrack->layer7.app_proto = kmalloc(strlen(info->protocol)+1, GFP_ATOMIC);
++ if(!master_conntrack->layer7.app_proto){
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory in match, bailing.\n");
++ write_unlock(&ct_lock);
++ return (pattern_result ^ info->invert);
++ }
++ strcpy(master_conntrack->layer7.app_proto, info->protocol);
++ write_unlock(&ct_lock);
++ }
++
++ /* mark the packet seen */
++ skb->cb[0] = 1;
++
++ return (pattern_result ^ info->invert);
++}
++
++static int checkentry(const char *tablename, const struct ipt_ip *ip,
++ void *matchinfo, unsigned int matchsize, unsigned int hook_mask)
++{
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_layer7_info)))
++ return 0;
++ return 1;
++}
++
++static struct ipt_match layer7_match = {
++ .name = "layer7",
++ .match = &match,
++ .checkentry = &checkentry,
++ .me = THIS_MODULE
++};
++
++/* taken from drivers/video/modedb.c */
++static int my_atoi(const char *s)
++{
++ int val = 0;
++
++ for (;; s++) {
++ switch (*s) {
++ case '0'...'9':
++ val = 10*val+(*s-'0');
++ break;
++ default:
++ return val;
++ }
++ }
++}
++
++/* write out num_packets to userland. */
++static int layer7_read_proc(char* page, char ** start, off_t off, int count,
++ int* eof, void * data)
++{
++ if(num_packets > 99 && net_ratelimit())
++ printk(KERN_ERR "layer7: NOT REACHED. num_packets too big\n");
++
++ page[0] = num_packets/10 + '0';
++ page[1] = num_packets%10 + '0';
++ page[2] = '\n';
++ page[3] = '\0';
++
++ *eof=1;
++
++ return 3;
++}
++
++/* Read in num_packets from userland */
++static int layer7_write_proc(struct file* file, const char* buffer,
++ unsigned long count, void *data)
++{
++ char * foo = kmalloc(count, GFP_ATOMIC);
++
++ if(!foo){
++ if (net_ratelimit())
++ printk(KERN_ERR "layer7: out of memory, bailing. num_packets unchanged.\n");
++ return count;
++ }
++
++ if(copy_from_user(foo, buffer, count)) {
++ return -EFAULT;
++ }
++
++
++ num_packets = my_atoi(foo);
++ kfree (foo);
++
++ /* This has an arbitrary limit to make the math easier. I'm lazy.
++ But anyway, 99 is a LOT! If you want more, you're doing it wrong! */
++ if(num_packets > 99) {
++ printk(KERN_WARNING "layer7: num_packets can't be > 99.\n");
++ num_packets = 99;
++ } else if(num_packets < 1) {
++ printk(KERN_WARNING "layer7: num_packets can't be < 1.\n");
++ num_packets = 1;
++ }
++
++ return count;
++}
++
++/* register the proc file */
++static void layer7_init_proc(void)
++{
++ struct proc_dir_entry* entry;
++ entry = create_proc_entry("layer7_numpackets", 0644, proc_net);
++ entry->read_proc = layer7_read_proc;
++ entry->write_proc = layer7_write_proc;
++}
++
++static void layer7_cleanup_proc(void)
++{
++ remove_proc_entry("layer7_numpackets", proc_net);
++}
++
++static int __init init(void)
++{
++ layer7_init_proc();
++ if(maxdatalen < 1) {
++ printk(KERN_WARNING "layer7: maxdatalen can't be < 1, using 1\n");
++ maxdatalen = 1;
++ }
++ /* This is not a hard limit. It's just here to prevent people from
++ bringing their slow machines to a grinding halt. */
++ else if(maxdatalen > 65536) {
++ printk(KERN_WARNING "layer7: maxdatalen can't be > 65536, using 65536\n");
++ maxdatalen = 65536;
++ }
++ return ipt_register_match(&layer7_match);
++}
++
++static void __exit fini(void)
++{
++ layer7_cleanup_proc();
++ ipt_unregister_match(&layer7_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur linux-2.6.17/net/ipv4/netfilter/Kconfig linux-2.6.17-owrt/net/ipv4/netfilter/Kconfig
+--- linux-2.6.17/net/ipv4/netfilter/Kconfig 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/netfilter/Kconfig 2006-06-18 12:32:58.000000000 +0200
+@@ -314,6 +314,24 @@
+ destination IP' or `500pps from any given source IP' with a single
+ IPtables rule.
+
++config IP_NF_MATCH_LAYER7
++ tristate "Layer 7 match support (EXPERIMENTAL)"
++ depends on IP_NF_IPTABLES && IP_NF_CT_ACCT && IP_NF_CONNTRACK && EXPERIMENTAL
++ help
++ Say Y if you want to be able to classify connections (and their
++ packets) based on regular expression matching of their application
++ layer data. This is one way to classify applications such as
++ peer-to-peer filesharing systems that do not always use the same
++ port.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
++config IP_NF_MATCH_LAYER7_DEBUG
++ bool "Layer 7 debugging output"
++ depends on IP_NF_MATCH_LAYER7
++ help
++ Say Y to get lots of debugging output.
++
+ # `filter', generic and specific targets
+ config IP_NF_FILTER
+ tristate "Packet filtering"
+diff -Nur linux-2.6.17/net/ipv4/netfilter/Makefile linux-2.6.17-owrt/net/ipv4/netfilter/Makefile
+--- linux-2.6.17/net/ipv4/netfilter/Makefile 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/netfilter/Makefile 2006-06-18 12:29:04.000000000 +0200
+@@ -62,6 +62,8 @@
+ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
+ obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
+
++obj-$(CONFIG_IP_NF_MATCH_LAYER7) += ipt_layer7.o
++
+ # targets
+ obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
+ obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o
+diff -Nur linux-2.6.17/net/ipv4/netfilter/regexp/regexp.c linux-2.6.17-owrt/net/ipv4/netfilter/regexp/regexp.c
+--- linux-2.6.17/net/ipv4/netfilter/regexp/regexp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/net/ipv4/netfilter/regexp/regexp.c 2006-06-18 12:29:04.000000000 +0200
+@@ -0,0 +1,1195 @@
++/*
++ * regcomp and regexec -- regsub and regerror are elsewhere
++ * @(#)regexp.c 1.3 of 18 April 87
++ *
++ * Copyright (c) 1986 by University of Toronto.
++ * Written by Henry Spencer. Not derived from licensed software.
++ *
++ * Permission is granted to anyone to use this software for any
++ * purpose on any computer system, and to redistribute it freely,
++ * subject to the following restrictions:
++ *
++ * 1. The author is not responsible for the consequences of use of
++ * this software, no matter how awful, even if they arise
++ * from defects in it.
++ *
++ * 2. The origin of this software must not be misrepresented, either
++ * by explicit claim or by omission.
++ *
++ * 3. Altered versions must be plainly marked as such, and must not
++ * be misrepresented as being the original software.
++ *
++ * Beware that some of this code is subtly aware of the way operator
++ * precedence is structured in regular expressions. Serious changes in
++ * regular-expression syntax might require a total rethink.
++ *
++ * This code was modified by Ethan Sommer to work within the kernel
++ * (it now uses kmalloc etc..)
++ *
++ * Modified slightly by Matthew Strait to use more modern C.
++ */
++
++#include "regexp.h"
++#include "regmagic.h"
++
++/* added by ethan and matt. Lets it work in both kernel and user space.
++(So iptables can use it, for instance.) Yea, it goes both ways... */
++#if __KERNEL__
++ #define malloc(foo) kmalloc(foo,GFP_ATOMIC)
++#else
++ #define printk(format,args...) printf(format,##args)
++#endif
++
++void regerror(char * s)
++{
++ printk("<3>Regexp: %s\n", s);
++ /* NOTREACHED */
++}
++
++/*
++ * The "internal use only" fields in regexp.h are present to pass info from
++ * compile to execute that permits the execute phase to run lots faster on
++ * simple cases. They are:
++ *
++ * regstart char that must begin a match; '\0' if none obvious
++ * reganch is the match anchored (at beginning-of-line only)?
++ * regmust string (pointer into program) that match must include, or NULL
++ * regmlen length of regmust string
++ *
++ * Regstart and reganch permit very fast decisions on suitable starting points
++ * for a match, cutting down the work a lot. Regmust permits fast rejection
++ * of lines that cannot possibly match. The regmust tests are costly enough
++ * that regcomp() supplies a regmust only if the r.e. contains something
++ * potentially expensive (at present, the only such thing detected is * or +
++ * at the start of the r.e., which can involve a lot of backup). Regmlen is
++ * supplied because the test in regexec() needs it and regcomp() is computing
++ * it anyway.
++ */
++
++/*
++ * Structure for regexp "program". This is essentially a linear encoding
++ * of a nondeterministic finite-state machine (aka syntax charts or
++ * "railroad normal form" in parsing technology). Each node is an opcode
++ * plus a "next" pointer, possibly plus an operand. "Next" pointers of
++ * all nodes except BRANCH implement concatenation; a "next" pointer with
++ * a BRANCH on both ends of it is connecting two alternatives. (Here we
++ * have one of the subtle syntax dependencies: an individual BRANCH (as
++ * opposed to a collection of them) is never concatenated with anything
++ * because of operator precedence.) The operand of some types of node is
++ * a literal string; for others, it is a node leading into a sub-FSM. In
++ * particular, the operand of a BRANCH node is the first node of the branch.
++ * (NB this is *not* a tree structure: the tail of the branch connects
++ * to the thing following the set of BRANCHes.) The opcodes are:
++ */
++
++/* definition number opnd? meaning */
++#define END 0 /* no End of program. */
++#define BOL 1 /* no Match "" at beginning of line. */
++#define EOL 2 /* no Match "" at end of line. */
++#define ANY 3 /* no Match any one character. */
++#define ANYOF 4 /* str Match any character in this string. */
++#define ANYBUT 5 /* str Match any character not in this string. */
++#define BRANCH 6 /* node Match this alternative, or the next... */
++#define BACK 7 /* no Match "", "next" ptr points backward. */
++#define EXACTLY 8 /* str Match this string. */
++#define NOTHING 9 /* no Match empty string. */
++#define STAR 10 /* node Match this (simple) thing 0 or more times. */
++#define PLUS 11 /* node Match this (simple) thing 1 or more times. */
++#define OPEN 20 /* no Mark this point in input as start of #n. */
++ /* OPEN+1 is number 1, etc. */
++#define CLOSE 30 /* no Analogous to OPEN. */
++
++/*
++ * Opcode notes:
++ *
++ * BRANCH The set of branches constituting a single choice are hooked
++ * together with their "next" pointers, since precedence prevents
++ * anything being concatenated to any individual branch. The
++ * "next" pointer of the last BRANCH in a choice points to the
++ * thing following the whole choice. This is also where the
++ * final "next" pointer of each individual branch points; each
++ * branch starts with the operand node of a BRANCH node.
++ *
++ * BACK Normal "next" pointers all implicitly point forward; BACK
++ * exists to make loop structures possible.
++ *
++ * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
++ * BRANCH structures using BACK. Simple cases (one character
++ * per match) are implemented with STAR and PLUS for speed
++ * and to minimize recursive plunges.
++ *
++ * OPEN,CLOSE ...are numbered at compile time.
++ */
++
++/*
++ * A node is one char of opcode followed by two chars of "next" pointer.
++ * "Next" pointers are stored as two 8-bit pieces, high order first. The
++ * value is a positive offset from the opcode of the node containing it.
++ * An operand, if any, simply follows the node. (Note that much of the
++ * code generation knows about this implicit relationship.)
++ *
++ * Using two bytes for the "next" pointer is vast overkill for most things,
++ * but allows patterns to get big without disasters.
++ */
++#define OP(p) (*(p))
++#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
++#define OPERAND(p) ((p) + 3)
++
++/*
++ * See regmagic.h for one further detail of program structure.
++ */
++
++
++/*
++ * Utility definitions.
++ */
++#ifndef CHARBITS
++#define UCHARAT(p) ((int)*(unsigned char *)(p))
++#else
++#define UCHARAT(p) ((int)*(p)&CHARBITS)
++#endif
++
++#define FAIL(m) { regerror(m); return(NULL); }
++#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
++#define META "^$.[()|?+*\\"
++
++/*
++ * Flags to be passed up and down.
++ */
++#define HASWIDTH 01 /* Known never to match null string. */
++#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
++#define SPSTART 04 /* Starts with * or +. */
++#define WORST 0 /* Worst case. */
++
++/*
++ * Global work variables for regcomp().
++ */
++static char *regparse; /* Input-scan pointer. */
++static int regnpar; /* () count. */
++static char regdummy;
++static char *regcode; /* Code-emit pointer; &regdummy = don't. */
++static long regsize; /* Code size. */
++
++/*
++ * Forward declarations for regcomp()'s friends.
++ */
++#ifndef STATIC
++#define STATIC static
++#endif
++STATIC char *reg(int paren,int *flagp);
++STATIC char *regbranch(int *flagp);
++STATIC char *regpiece(int *flagp);
++STATIC char *regatom(int *flagp);
++STATIC char *regnode(char op);
++STATIC char *regnext(char *p);
++STATIC void regc(char b);
++STATIC void reginsert(char op, char *opnd);
++STATIC void regtail(char *p, char *val);
++STATIC void regoptail(char *p, char *val);
++
++
++__kernel_size_t my_strcspn(const char *s1,const char *s2)
++{
++ char *scan1;
++ char *scan2;
++ int count;
++
++ count = 0;
++ for (scan1 = (char *)s1; *scan1 != '\0'; scan1++) {
++ for (scan2 = (char *)s2; *scan2 != '\0';) /* ++ moved down. */
++ if (*scan1 == *scan2++)
++ return(count);
++ count++;
++ }
++ return(count);
++}
++
++/*
++ - regcomp - compile a regular expression into internal code
++ *
++ * We can't allocate space until we know how big the compiled form will be,
++ * but we can't compile it (and thus know how big it is) until we've got a
++ * place to put the code. So we cheat: we compile it twice, once with code
++ * generation turned off and size counting turned on, and once "for real".
++ * This also means that we don't allocate space until we are sure that the
++ * thing really will compile successfully, and we never have to move the
++ * code and thus invalidate pointers into it. (Note that it has to be in
++ * one piece because free() must be able to free it all.)
++ *
++ * Beware that the optimization-preparation code in here knows about some
++ * of the structure of the compiled regexp.
++ */
++regexp *
++regcomp(char *exp,int *patternsize)
++{
++ register regexp *r;
++ register char *scan;
++ register char *longest;
++ register int len;
++ int flags;
++ /* commented out by ethan
++ extern char *malloc();
++ */
++
++ if (exp == NULL)
++ FAIL("NULL argument");
++
++ /* First pass: determine size, legality. */
++ regparse = exp;
++ regnpar = 1;
++ regsize = 0L;
++ regcode = &regdummy;
++ regc(MAGIC);
++ if (reg(0, &flags) == NULL)
++ return(NULL);
++
++ /* Small enough for pointer-storage convention? */
++ if (regsize >= 32767L) /* Probably could be 65535L. */
++ FAIL("regexp too big");
++
++ /* Allocate space. */
++ *patternsize=sizeof(regexp) + (unsigned)regsize;
++ r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
++ if (r == NULL)
++ FAIL("out of space");
++
++ /* Second pass: emit code. */
++ regparse = exp;
++ regnpar = 1;
++ regcode = r->program;
++ regc(MAGIC);
++ if (reg(0, &flags) == NULL)
++ return(NULL);
++
++ /* Dig out information for optimizations. */
++ r->regstart = '\0'; /* Worst-case defaults. */
++ r->reganch = 0;
++ r->regmust = NULL;
++ r->regmlen = 0;
++ scan = r->program+1; /* First BRANCH. */
++ if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
++ scan = OPERAND(scan);
++
++ /* Starting-point info. */
++ if (OP(scan) == EXACTLY)
++ r->regstart = *OPERAND(scan);
++ else if (OP(scan) == BOL)
++ r->reganch++;
++
++ /*
++ * If there's something expensive in the r.e., find the
++ * longest literal string that must appear and make it the
++ * regmust. Resolve ties in favor of later strings, since
++ * the regstart check works with the beginning of the r.e.
++ * and avoiding duplication strengthens checking. Not a
++ * strong reason, but sufficient in the absence of others.
++ */
++ if (flags&SPSTART) {
++ longest = NULL;
++ len = 0;
++ for (; scan != NULL; scan = regnext(scan))
++ if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
++ longest = OPERAND(scan);
++ len = strlen(OPERAND(scan));
++ }
++ r->regmust = longest;
++ r->regmlen = len;
++ }
++ }
++
++ return(r);
++}
++
++/*
++ - reg - regular expression, i.e. main body or parenthesized thing
++ *
++ * Caller must absorb opening parenthesis.
++ *
++ * Combining parenthesis handling with the base level of regular expression
++ * is a trifle forced, but the need to tie the tails of the branches to what
++ * follows makes it hard to avoid.
++ */
++static char *
++reg(int paren, int *flagp /* Parenthesized? */ )
++{
++ register char *ret;
++ register char *br;
++ register char *ender;
++ register int parno = 0; /* 0 makes gcc happy */
++ int flags;
++
++ *flagp = HASWIDTH; /* Tentatively. */
++
++ /* Make an OPEN node, if parenthesized. */
++ if (paren) {
++ if (regnpar >= NSUBEXP)
++ FAIL("too many ()");
++ parno = regnpar;
++ regnpar++;
++ ret = regnode(OPEN+parno);
++ } else
++ ret = NULL;
++
++ /* Pick up the branches, linking them together. */
++ br = regbranch(&flags);
++ if (br == NULL)
++ return(NULL);
++ if (ret != NULL)
++ regtail(ret, br); /* OPEN -> first. */
++ else
++ ret = br;
++ if (!(flags&HASWIDTH))
++ *flagp &= ~HASWIDTH;
++ *flagp |= flags&SPSTART;
++ while (*regparse == '|') {
++ regparse++;
++ br = regbranch(&flags);
++ if (br == NULL)
++ return(NULL);
++ regtail(ret, br); /* BRANCH -> BRANCH. */
++ if (!(flags&HASWIDTH))
++ *flagp &= ~HASWIDTH;
++ *flagp |= flags&SPSTART;
++ }
++
++ /* Make a closing node, and hook it on the end. */
++ ender = regnode((paren) ? CLOSE+parno : END);
++ regtail(ret, ender);
++
++ /* Hook the tails of the branches to the closing node. */
++ for (br = ret; br != NULL; br = regnext(br))
++ regoptail(br, ender);
++
++ /* Check for proper termination. */
++ if (paren && *regparse++ != ')') {
++ FAIL("unmatched ()");
++ } else if (!paren && *regparse != '\0') {
++ if (*regparse == ')') {
++ FAIL("unmatched ()");
++ } else
++ FAIL("junk on end"); /* "Can't happen". */
++ /* NOTREACHED */
++ }
++
++ return(ret);
++}
++
++/*
++ - regbranch - one alternative of an | operator
++ *
++ * Implements the concatenation operator.
++ */
++static char *
++regbranch(int *flagp)
++{
++ register char *ret;
++ register char *chain;
++ register char *latest;
++ int flags;
++
++ *flagp = WORST; /* Tentatively. */
++
++ ret = regnode(BRANCH);
++ chain = NULL;
++ while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
++ latest = regpiece(&flags);
++ if (latest == NULL)
++ return(NULL);
++ *flagp |= flags&HASWIDTH;
++ if (chain == NULL) /* First piece. */
++ *flagp |= flags&SPSTART;
++ else
++ regtail(chain, latest);
++ chain = latest;
++ }
++ if (chain == NULL) /* Loop ran zero times. */
++ (void) regnode(NOTHING);
++
++ return(ret);
++}
++
++/*
++ - regpiece - something followed by possible [*+?]
++ *
++ * Note that the branching code sequences used for ? and the general cases
++ * of * and + are somewhat optimized: they use the same NOTHING node as
++ * both the endmarker for their branch list and the body of the last branch.
++ * It might seem that this node could be dispensed with entirely, but the
++ * endmarker role is not redundant.
++ */
++static char *
++regpiece(int *flagp)
++{
++ register char *ret;
++ register char op;
++ register char *next;
++ int flags;
++
++ ret = regatom(&flags);
++ if (ret == NULL)
++ return(NULL);
++
++ op = *regparse;
++ if (!ISMULT(op)) {
++ *flagp = flags;
++ return(ret);
++ }
++
++ if (!(flags&HASWIDTH) && op != '?')
++ FAIL("*+ operand could be empty");
++ *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
++
++ if (op == '*' && (flags&SIMPLE))
++ reginsert(STAR, ret);
++ else if (op == '*') {
++ /* Emit x* as (x&|), where & means "self". */
++ reginsert(BRANCH, ret); /* Either x */
++ regoptail(ret, regnode(BACK)); /* and loop */
++ regoptail(ret, ret); /* back */
++ regtail(ret, regnode(BRANCH)); /* or */
++ regtail(ret, regnode(NOTHING)); /* null. */
++ } else if (op == '+' && (flags&SIMPLE))
++ reginsert(PLUS, ret);
++ else if (op == '+') {
++ /* Emit x+ as x(&|), where & means "self". */
++ next = regnode(BRANCH); /* Either */
++ regtail(ret, next);
++ regtail(regnode(BACK), ret); /* loop back */
++ regtail(next, regnode(BRANCH)); /* or */
++ regtail(ret, regnode(NOTHING)); /* null. */
++ } else if (op == '?') {
++ /* Emit x? as (x|) */
++ reginsert(BRANCH, ret); /* Either x */
++ regtail(ret, regnode(BRANCH)); /* or */
++ next = regnode(NOTHING); /* null. */
++ regtail(ret, next);
++ regoptail(ret, next);
++ }
++ regparse++;
++ if (ISMULT(*regparse))
++ FAIL("nested *?+");
++
++ return(ret);
++}
++
++/*
++ - regatom - the lowest level
++ *
++ * Optimization: gobbles an entire sequence of ordinary characters so that
++ * it can turn them into a single node, which is smaller to store and
++ * faster to run. Backslashed characters are exceptions, each becoming a
++ * separate node; the code is simpler that way and it's not worth fixing.
++ */
++static char *
++regatom(int *flagp)
++{
++ register char *ret;
++ int flags;
++
++ *flagp = WORST; /* Tentatively. */
++
++ switch (*regparse++) {
++ case '^':
++ ret = regnode(BOL);
++ break;
++ case '$':
++ ret = regnode(EOL);
++ break;
++ case '.':
++ ret = regnode(ANY);
++ *flagp |= HASWIDTH|SIMPLE;
++ break;
++ case '[': {
++ register int class;
++ register int classend;
++
++ if (*regparse == '^') { /* Complement of range. */
++ ret = regnode(ANYBUT);
++ regparse++;
++ } else
++ ret = regnode(ANYOF);
++ if (*regparse == ']' || *regparse == '-')
++ regc(*regparse++);
++ while (*regparse != '\0' && *regparse != ']') {
++ if (*regparse == '-') {
++ regparse++;
++ if (*regparse == ']' || *regparse == '\0')
++ regc('-');
++ else {
++ class = UCHARAT(regparse-2)+1;
++ classend = UCHARAT(regparse);
++ if (class > classend+1)
++ FAIL("invalid [] range");
++ for (; class <= classend; class++)
++ regc(class);
++ regparse++;
++ }
++ } else
++ regc(*regparse++);
++ }
++ regc('\0');
++ if (*regparse != ']')
++ FAIL("unmatched []");
++ regparse++;
++ *flagp |= HASWIDTH|SIMPLE;
++ }
++ break;
++ case '(':
++ ret = reg(1, &flags);
++ if (ret == NULL)
++ return(NULL);
++ *flagp |= flags&(HASWIDTH|SPSTART);
++ break;
++ case '\0':
++ case '|':
++ case ')':
++ FAIL("internal urp"); /* Supposed to be caught earlier. */
++ break;
++ case '?':
++ case '+':
++ case '*':
++ FAIL("?+* follows nothing");
++ break;
++ case '\\':
++ if (*regparse == '\0')
++ FAIL("trailing \\");
++ ret = regnode(EXACTLY);
++ regc(*regparse++);
++ regc('\0');
++ *flagp |= HASWIDTH|SIMPLE;
++ break;
++ default: {
++ register int len;
++ register char ender;
++
++ regparse--;
++ len = my_strcspn((const char *)regparse, (const char *)META);
++ if (len <= 0)
++ FAIL("internal disaster");
++ ender = *(regparse+len);
++ if (len > 1 && ISMULT(ender))
++ len--; /* Back off clear of ?+* operand. */
++ *flagp |= HASWIDTH;
++ if (len == 1)
++ *flagp |= SIMPLE;
++ ret = regnode(EXACTLY);
++ while (len > 0) {
++ regc(*regparse++);
++ len--;
++ }
++ regc('\0');
++ }
++ break;
++ }
++
++ return(ret);
++}
++
++/*
++ - regnode - emit a node
++ */
++static char * /* Location. */
++regnode(char op)
++{
++ register char *ret;
++ register char *ptr;
++
++ ret = regcode;
++ if (ret == &regdummy) {
++ regsize += 3;
++ return(ret);
++ }
++
++ ptr = ret;
++ *ptr++ = op;
++ *ptr++ = '\0'; /* Null "next" pointer. */
++ *ptr++ = '\0';
++ regcode = ptr;
++
++ return(ret);
++}
++
++/*
++ - regc - emit (if appropriate) a byte of code
++ */
++static void
++regc(char b)
++{
++ if (regcode != &regdummy)
++ *regcode++ = b;
++ else
++ regsize++;
++}
++
++/*
++ - reginsert - insert an operator in front of already-emitted operand
++ *
++ * Means relocating the operand.
++ */
++static void
++reginsert(char op, char* opnd)
++{
++ register char *src;
++ register char *dst;
++ register char *place;
++
++ if (regcode == &regdummy) {
++ regsize += 3;
++ return;
++ }
++
++ src = regcode;
++ regcode += 3;
++ dst = regcode;
++ while (src > opnd)
++ *--dst = *--src;
++
++ place = opnd; /* Op node, where operand used to be. */
++ *place++ = op;
++ *place++ = '\0';
++ *place++ = '\0';
++}
++
++/*
++ - regtail - set the next-pointer at the end of a node chain
++ */
++static void
++regtail(char *p, char *val)
++{
++ register char *scan;
++ register char *temp;
++ register int offset;
++
++ if (p == &regdummy)
++ return;
++
++ /* Find last node. */
++ scan = p;
++ for (;;) {
++ temp = regnext(scan);
++ if (temp == NULL)
++ break;
++ scan = temp;
++ }
++
++ if (OP(scan) == BACK)
++ offset = scan - val;
++ else
++ offset = val - scan;
++ *(scan+1) = (offset>>8)&0377;
++ *(scan+2) = offset&0377;
++}
++
++/*
++ - regoptail - regtail on operand of first argument; nop if operandless
++ */
++static void
++regoptail(char *p, char *val)
++{
++ /* "Operandless" and "op != BRANCH" are synonymous in practice. */
++ if (p == NULL || p == &regdummy || OP(p) != BRANCH)
++ return;
++ regtail(OPERAND(p), val);
++}
++
++/*
++ * regexec and friends
++ */
++
++/*
++ * Global work variables for regexec().
++ */
++static char *reginput; /* String-input pointer. */
++static char *regbol; /* Beginning of input, for ^ check. */
++static char **regstartp; /* Pointer to startp array. */
++static char **regendp; /* Ditto for endp. */
++
++/*
++ * Forwards.
++ */
++STATIC int regtry(regexp *prog, char *string);
++STATIC int regmatch(char *prog);
++STATIC int regrepeat(char *p);
++
++#ifdef DEBUG
++int regnarrate = 0;
++void regdump();
++STATIC char *regprop(char *op);
++#endif
++
++/*
++ - regexec - match a regexp against a string
++ */
++int
++regexec(regexp *prog, char *string)
++{
++ register char *s;
++
++ /* Be paranoid... */
++ if (prog == NULL || string == NULL) {
++ printk("<3>Regexp: NULL parameter\n");
++ return(0);
++ }
++
++ /* Check validity of program. */
++ if (UCHARAT(prog->program) != MAGIC) {
++ printk("<3>Regexp: corrupted program\n");
++ return(0);
++ }
++
++ /* If there is a "must appear" string, look for it. */
++ if (prog->regmust != NULL) {
++ s = string;
++ while ((s = strchr(s, prog->regmust[0])) != NULL) {
++ if (strncmp(s, prog->regmust, prog->regmlen) == 0)
++ break; /* Found it. */
++ s++;
++ }
++ if (s == NULL) /* Not present. */
++ return(0);
++ }
++
++ /* Mark beginning of line for ^ . */
++ regbol = string;
++
++ /* Simplest case: anchored match need be tried only once. */
++ if (prog->reganch)
++ return(regtry(prog, string));
++
++ /* Messy cases: unanchored match. */
++ s = string;
++ if (prog->regstart != '\0')
++ /* We know what char it must start with. */
++ while ((s = strchr(s, prog->regstart)) != NULL) {
++ if (regtry(prog, s))
++ return(1);
++ s++;
++ }
++ else
++ /* We don't -- general case. */
++ do {
++ if (regtry(prog, s))
++ return(1);
++ } while (*s++ != '\0');
++
++ /* Failure. */
++ return(0);
++}
++
++/*
++ - regtry - try match at specific point
++ */
++static int /* 0 failure, 1 success */
++regtry(regexp *prog, char *string)
++{
++ register int i;
++ register char **sp;
++ register char **ep;
++
++ reginput = string;
++ regstartp = prog->startp;
++ regendp = prog->endp;
++
++ sp = prog->startp;
++ ep = prog->endp;
++ for (i = NSUBEXP; i > 0; i--) {
++ *sp++ = NULL;
++ *ep++ = NULL;
++ }
++ if (regmatch(prog->program + 1)) {
++ prog->startp[0] = string;
++ prog->endp[0] = reginput;
++ return(1);
++ } else
++ return(0);
++}
++
++/*
++ - regmatch - main matching routine
++ *
++ * Conceptually the strategy is simple: check to see whether the current
++ * node matches, call self recursively to see whether the rest matches,
++ * and then act accordingly. In practice we make some effort to avoid
++ * recursion, in particular by going through "ordinary" nodes (that don't
++ * need to know whether the rest of the match failed) by a loop instead of
++ * by recursion.
++ */
++static int /* 0 failure, 1 success */
++regmatch(char *prog)
++{
++ register char *scan = prog; /* Current node. */
++ char *next; /* Next node. */
++
++#ifdef DEBUG
++ if (scan != NULL && regnarrate)
++ fprintf(stderr, "%s(\n", regprop(scan));
++#endif
++ while (scan != NULL) {
++#ifdef DEBUG
++ if (regnarrate)
++ fprintf(stderr, "%s...\n", regprop(scan));
++#endif
++ next = regnext(scan);
++
++ switch (OP(scan)) {
++ case BOL:
++ if (reginput != regbol)
++ return(0);
++ break;
++ case EOL:
++ if (*reginput != '\0')
++ return(0);
++ break;
++ case ANY:
++ if (*reginput == '\0')
++ return(0);
++ reginput++;
++ break;
++ case EXACTLY: {
++ register int len;
++ register char *opnd;
++
++ opnd = OPERAND(scan);
++ /* Inline the first character, for speed. */
++ if (*opnd != *reginput)
++ return(0);
++ len = strlen(opnd);
++ if (len > 1 && strncmp(opnd, reginput, len) != 0)
++ return(0);
++ reginput += len;
++ }
++ break;
++ case ANYOF:
++ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
++ return(0);
++ reginput++;
++ break;
++ case ANYBUT:
++ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
++ return(0);
++ reginput++;
++ break;
++ case NOTHING:
++ case BACK:
++ break;
++ case OPEN+1:
++ case OPEN+2:
++ case OPEN+3:
++ case OPEN+4:
++ case OPEN+5:
++ case OPEN+6:
++ case OPEN+7:
++ case OPEN+8:
++ case OPEN+9: {
++ register int no;
++ register char *save;
++
++ no = OP(scan) - OPEN;
++ save = reginput;
++
++ if (regmatch(next)) {
++ /*
++ * Don't set startp if some later
++ * invocation of the same parentheses
++ * already has.
++ */
++ if (regstartp[no] == NULL)
++ regstartp[no] = save;
++ return(1);
++ } else
++ return(0);
++ }
++ break;
++ case CLOSE+1:
++ case CLOSE+2:
++ case CLOSE+3:
++ case CLOSE+4:
++ case CLOSE+5:
++ case CLOSE+6:
++ case CLOSE+7:
++ case CLOSE+8:
++ case CLOSE+9:
++ {
++ register int no;
++ register char *save;
++
++ no = OP(scan) - CLOSE;
++ save = reginput;
++
++ if (regmatch(next)) {
++ /*
++ * Don't set endp if some later
++ * invocation of the same parentheses
++ * already has.
++ */
++ if (regendp[no] == NULL)
++ regendp[no] = save;
++ return(1);
++ } else
++ return(0);
++ }
++ break;
++ case BRANCH: {
++ register char *save;
++
++ if (OP(next) != BRANCH) /* No choice. */
++ next = OPERAND(scan); /* Avoid recursion. */
++ else {
++ do {
++ save = reginput;
++ if (regmatch(OPERAND(scan)))
++ return(1);
++ reginput = save;
++ scan = regnext(scan);
++ } while (scan != NULL && OP(scan) == BRANCH);
++ return(0);
++ /* NOTREACHED */
++ }
++ }
++ break;
++ case STAR:
++ case PLUS: {
++ register char nextch;
++ register int no;
++ register char *save;
++ register int min;
++
++ /*
++ * Lookahead to avoid useless match attempts
++ * when we know what character comes next.
++ */
++ nextch = '\0';
++ if (OP(next) == EXACTLY)
++ nextch = *OPERAND(next);
++ min = (OP(scan) == STAR) ? 0 : 1;
++ save = reginput;
++ no = regrepeat(OPERAND(scan));
++ while (no >= min) {
++ /* If it could work, try it. */
++ if (nextch == '\0' || *reginput == nextch)
++ if (regmatch(next))
++ return(1);
++ /* Couldn't or didn't -- back up. */
++ no--;
++ reginput = save + no;
++ }
++ return(0);
++ }
++ break;
++ case END:
++ return(1); /* Success! */
++ break;
++ default:
++ printk("<3>Regexp: memory corruption\n");
++ return(0);
++ break;
++ }
++
++ scan = next;
++ }
++
++ /*
++ * We get here only if there's trouble -- normally "case END" is
++ * the terminating point.
++ */
++ printk("<3>Regexp: corrupted pointers\n");
++ return(0);
++}
++
++/*
++ - regrepeat - repeatedly match something simple, report how many
++ */
++static int
++regrepeat(char *p)
++{
++ register int count = 0;
++ register char *scan;
++ register char *opnd;
++
++ scan = reginput;
++ opnd = OPERAND(p);
++ switch (OP(p)) {
++ case ANY:
++ count = strlen(scan);
++ scan += count;
++ break;
++ case EXACTLY:
++ while (*opnd == *scan) {
++ count++;
++ scan++;
++ }
++ break;
++ case ANYOF:
++ while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
++ count++;
++ scan++;
++ }
++ break;
++ case ANYBUT:
++ while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
++ count++;
++ scan++;
++ }
++ break;
++ default: /* Oh dear. Called inappropriately. */
++ printk("<3>Regexp: internal foulup\n");
++ count = 0; /* Best compromise. */
++ break;
++ }
++ reginput = scan;
++
++ return(count);
++}
++
++/*
++ - regnext - dig the "next" pointer out of a node
++ */
++static char*
++regnext(char *p)
++{
++ register int offset;
++
++ if (p == &regdummy)
++ return(NULL);
++
++ offset = NEXT(p);
++ if (offset == 0)
++ return(NULL);
++
++ if (OP(p) == BACK)
++ return(p-offset);
++ else
++ return(p+offset);
++}
++
++#ifdef DEBUG
++
++STATIC char *regprop();
++
++/*
++ - regdump - dump a regexp onto stdout in vaguely comprehensible form
++ */
++void
++regdump(regexp *r)
++{
++ register char *s;
++ register char op = EXACTLY; /* Arbitrary non-END op. */
++ register char *next;
++ /* extern char *strchr(); */
++
++
++ s = r->program + 1;
++ while (op != END) { /* While that wasn't END last time... */
++ op = OP(s);
++ printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
++ next = regnext(s);
++ if (next == NULL) /* Next ptr. */
++ printf("(0)");
++ else
++ printf("(%d)", (s-r->program)+(next-s));
++ s += 3;
++ if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
++ /* Literal string, where present. */
++ while (*s != '\0') {
++ putchar(*s);
++ s++;
++ }
++ s++;
++ }
++ putchar('\n');
++ }
++
++ /* Header fields of interest. */
++ if (r->regstart != '\0')
++ printf("start `%c' ", r->regstart);
++ if (r->reganch)
++ printf("anchored ");
++ if (r->regmust != NULL)
++ printf("must have \"%s\"", r->regmust);
++ printf("\n");
++}
++
++/*
++ - regprop - printable representation of opcode
++ */
++static char *
++regprop(char *op)
++{
++#define BUFLEN 50
++ register char *p;
++ static char buf[BUFLEN];
++
++ strcpy(buf, ":");
++
++ switch (OP(op)) {
++ case BOL:
++ p = "BOL";
++ break;
++ case EOL:
++ p = "EOL";
++ break;
++ case ANY:
++ p = "ANY";
++ break;
++ case ANYOF:
++ p = "ANYOF";
++ break;
++ case ANYBUT:
++ p = "ANYBUT";
++ break;
++ case BRANCH:
++ p = "BRANCH";
++ break;
++ case EXACTLY:
++ p = "EXACTLY";
++ break;
++ case NOTHING:
++ p = "NOTHING";
++ break;
++ case BACK:
++ p = "BACK";
++ break;
++ case END:
++ p = "END";
++ break;
++ case OPEN+1:
++ case OPEN+2:
++ case OPEN+3:
++ case OPEN+4:
++ case OPEN+5:
++ case OPEN+6:
++ case OPEN+7:
++ case OPEN+8:
++ case OPEN+9:
++ snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "OPEN%d", OP(op)-OPEN);
++ p = NULL;
++ break;
++ case CLOSE+1:
++ case CLOSE+2:
++ case CLOSE+3:
++ case CLOSE+4:
++ case CLOSE+5:
++ case CLOSE+6:
++ case CLOSE+7:
++ case CLOSE+8:
++ case CLOSE+9:
++ snprintf(buf+strlen(buf),BUFLEN-strlen(buf), "CLOSE%d", OP(op)-CLOSE);
++ p = NULL;
++ break;
++ case STAR:
++ p = "STAR";
++ break;
++ case PLUS:
++ p = "PLUS";
++ break;
++ default:
++ printk("<3>Regexp: corrupted opcode\n");
++ break;
++ }
++ if (p != NULL)
++ strncat(buf, p, BUFLEN-strlen(buf));
++ return(buf);
++}
++#endif
++
++
+diff -Nur linux-2.6.17/net/ipv4/netfilter/regexp/regexp.h linux-2.6.17-owrt/net/ipv4/netfilter/regexp/regexp.h
+--- linux-2.6.17/net/ipv4/netfilter/regexp/regexp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/net/ipv4/netfilter/regexp/regexp.h 2006-06-18 12:29:04.000000000 +0200
+@@ -0,0 +1,41 @@
++/*
++ * Definitions etc. for regexp(3) routines.
++ *
++ * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
++ * not the System V one.
++ */
++
++#ifndef REGEXP_H
++#define REGEXP_H
++
++
++/*
++http://www.opensource.apple.com/darwinsource/10.3/expect-1/expect/expect.h ,
++which contains a version of this library, says:
++
++ *
++ * NSUBEXP must be at least 10, and no greater than 117 or the parser
++ * will not work properly.
++ *
++
++However, it looks rather like this library is limited to 10. If you think
++otherwise, let us know.
++*/
++
++#define NSUBEXP 10
++typedef struct regexp {
++ char *startp[NSUBEXP];
++ char *endp[NSUBEXP];
++ char regstart; /* Internal use only. */
++ char reganch; /* Internal use only. */
++ char *regmust; /* Internal use only. */
++ int regmlen; /* Internal use only. */
++ char program[1]; /* Unwarranted chumminess with compiler. */
++} regexp;
++
++regexp * regcomp(char *exp, int *patternsize);
++int regexec(regexp *prog, char *string);
++void regsub(regexp *prog, char *source, char *dest);
++void regerror(char *s);
++
++#endif
+diff -Nur linux-2.6.17/net/ipv4/netfilter/regexp/regmagic.h linux-2.6.17-owrt/net/ipv4/netfilter/regexp/regmagic.h
+--- linux-2.6.17/net/ipv4/netfilter/regexp/regmagic.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/net/ipv4/netfilter/regexp/regmagic.h 2006-06-18 12:29:04.000000000 +0200
+@@ -0,0 +1,5 @@
++/*
++ * The first byte of the regexp internal "program" is actually this magic
++ * number; the start node begins in the second byte.
++ */
++#define MAGIC 0234
+diff -Nur linux-2.6.17/net/ipv4/netfilter/regexp/regsub.c linux-2.6.17-owrt/net/ipv4/netfilter/regexp/regsub.c
+--- linux-2.6.17/net/ipv4/netfilter/regexp/regsub.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/net/ipv4/netfilter/regexp/regsub.c 2006-06-18 12:29:04.000000000 +0200
+@@ -0,0 +1,95 @@
++/*
++ * regsub
++ * @(#)regsub.c 1.3 of 2 April 86
++ *
++ * Copyright (c) 1986 by University of Toronto.
++ * Written by Henry Spencer. Not derived from licensed software.
++ *
++ * Permission is granted to anyone to use this software for any
++ * purpose on any computer system, and to redistribute it freely,
++ * subject to the following restrictions:
++ *
++ * 1. The author is not responsible for the consequences of use of
++ * this software, no matter how awful, even if they arise
++ * from defects in it.
++ *
++ * 2. The origin of this software must not be misrepresented, either
++ * by explicit claim or by omission.
++ *
++ * 3. Altered versions must be plainly marked as such, and must not
++ * be misrepresented as being the original software.
++ *
++ *
++ * This code was modified by Ethan Sommer to work within the kernel
++ * (it now uses kmalloc etc..)
++ *
++ */
++#include "regexp.h"
++#include "regmagic.h"
++#include <linux/string.h>
++
++
++#ifndef CHARBITS
++#define UCHARAT(p) ((int)*(unsigned char *)(p))
++#else
++#define UCHARAT(p) ((int)*(p)&CHARBITS)
++#endif
++
++#if 0
++//void regerror(char * s)
++//{
++// printk("regexp(3): %s", s);
++// /* NOTREACHED */
++//}
++#endif
++
++/*
++ - regsub - perform substitutions after a regexp match
++ */
++void
++regsub(regexp * prog, char * source, char * dest)
++{
++ register char *src;
++ register char *dst;
++ register char c;
++ register int no;
++ register int len;
++
++ /* Not necessary and gcc doesn't like it -MLS */
++ /*extern char *strncpy();*/
++
++ if (prog == NULL || source == NULL || dest == NULL) {
++ regerror("NULL parm to regsub");
++ return;
++ }
++ if (UCHARAT(prog->program) != MAGIC) {
++ regerror("damaged regexp fed to regsub");
++ return;
++ }
++
++ src = source;
++ dst = dest;
++ while ((c = *src++) != '\0') {
++ if (c == '&')
++ no = 0;
++ else if (c == '\\' && '0' <= *src && *src <= '9')
++ no = *src++ - '0';
++ else
++ no = -1;
++
++ if (no < 0) { /* Ordinary character. */
++ if (c == '\\' && (*src == '\\' || *src == '&'))
++ c = *src++;
++ *dst++ = c;
++ } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
++ len = prog->endp[no] - prog->startp[no];
++ (void) strncpy(dst, prog->startp[no], len);
++ dst += len;
++ if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */
++ regerror("damaged match string");
++ return;
++ }
++ }
++ }
++ *dst++ = '\0';
++}
diff --git a/target/linux/generic-2.6/patches/101-ipp2p_0.8.1rc1.patch b/target/linux/generic-2.6/patches/101-ipp2p_0.8.1rc1.patch
new file mode 100644
index 0000000..9841db9
--- /dev/null
+++ b/target/linux/generic-2.6/patches/101-ipp2p_0.8.1rc1.patch
@@ -0,0 +1,935 @@
+diff -Nur linux-2.6.17/include/linux/netfilter_ipv4/ipt_ipp2p.h linux-2.6.17-owrt/include/linux/netfilter_ipv4/ipt_ipp2p.h
+--- linux-2.6.17/include/linux/netfilter_ipv4/ipt_ipp2p.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/include/linux/netfilter_ipv4/ipt_ipp2p.h 2006-06-18 12:37:14.000000000 +0200
+@@ -0,0 +1,31 @@
++#ifndef __IPT_IPP2P_H
++#define __IPT_IPP2P_H
++#define IPP2P_VERSION "0.8.1_rc1"
++
++struct ipt_p2p_info {
++ int cmd;
++ int debug;
++};
++
++#endif //__IPT_IPP2P_H
++
++#define SHORT_HAND_IPP2P 1 /* --ipp2p switch*/
++//#define SHORT_HAND_DATA 4 /* --ipp2p-data switch*/
++#define SHORT_HAND_NONE 5 /* no short hand*/
++
++#define IPP2P_EDK (1 << 1)
++#define IPP2P_DATA_KAZAA (1 << 2)
++#define IPP2P_DATA_EDK (1 << 3)
++#define IPP2P_DATA_DC (1 << 4)
++#define IPP2P_DC (1 << 5)
++#define IPP2P_DATA_GNU (1 << 6)
++#define IPP2P_GNU (1 << 7)
++#define IPP2P_KAZAA (1 << 8)
++#define IPP2P_BIT (1 << 9)
++#define IPP2P_APPLE (1 << 10)
++#define IPP2P_SOUL (1 << 11)
++#define IPP2P_WINMX (1 << 12)
++#define IPP2P_ARES (1 << 13)
++#define IPP2P_MUTE (1 << 14)
++#define IPP2P_WASTE (1 << 15)
++#define IPP2P_XDCC (1 << 16)
+diff -Nur linux-2.6.17/net/ipv4/netfilter/ipt_ipp2p.c linux-2.6.17-owrt/net/ipv4/netfilter/ipt_ipp2p.c
+--- linux-2.6.17/net/ipv4/netfilter/ipt_ipp2p.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/net/ipv4/netfilter/ipt_ipp2p.c 2006-06-18 12:37:14.000000000 +0200
+@@ -0,0 +1,868 @@
++#if defined(MODVERSIONS)
++#include <linux/modversions.h>
++#endif
++#include <linux/module.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/version.h>
++#include <linux/netfilter_ipv4/ipt_ipp2p.h>
++#include <net/tcp.h>
++#include <net/udp.h>
++
++#define get_u8(X,O) (*(__u8 *)(X + O))
++#define get_u16(X,O) (*(__u16 *)(X + O))
++#define get_u32(X,O) (*(__u32 *)(X + O))
++
++MODULE_AUTHOR("Eicke Friedrich/Klaus Degner <ipp2p@ipp2p.org>");
++MODULE_DESCRIPTION("An extension to iptables to identify P2P traffic.");
++MODULE_LICENSE("GPL");
++
++
++/*Search for UDP eDonkey/eMule/Kad commands*/
++int
++udp_search_edk (unsigned char *haystack, int packet_len)
++{
++ unsigned char *t = haystack;
++ t += 8;
++
++ switch (t[0]) {
++ case 0xe3:
++ { /*edonkey*/
++ switch (t[1])
++ {
++ /* client -> server status request */
++ case 0x96:
++ if (packet_len == 14) return ((IPP2P_EDK * 100) + 50);
++ break;
++ /* server -> client status request */
++ case 0x97: if (packet_len == 42) return ((IPP2P_EDK * 100) + 51);
++ break;
++ /* server description request */
++ /* e3 2a ff f0 .. | size == 6 */
++ case 0xa2: if ( (packet_len == 14) && ( get_u16(t,2) == __constant_htons(0xfff0) ) ) return ((IPP2P_EDK * 100) + 52);
++ break;
++ /* server description response */
++ /* e3 a3 ff f0 .. | size > 40 && size < 200 */
++ //case 0xa3: return ((IPP2P_EDK * 100) + 53);
++ // break;
++ case 0x9a: if (packet_len==26) return ((IPP2P_EDK * 100) + 54);
++ break;
++
++ case 0x92: if (packet_len==18) return ((IPP2P_EDK * 100) + 55);
++ break;
++ }
++ break;
++ }
++ case 0xe4:
++ {
++ switch (t[1])
++ {
++ /* e4 20 .. | size == 43 */
++ case 0x20: if ((packet_len == 43) && (t[2] != 0x00) && (t[34] != 0x00)) return ((IPP2P_EDK * 100) + 60);
++ break;
++ /* e4 00 .. 00 | size == 35 ? */
++ case 0x00: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 61);
++ break;
++ /* e4 10 .. 00 | size == 35 ? */
++ case 0x10: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 62);
++ break;
++ /* e4 18 .. 00 | size == 35 ? */
++ case 0x18: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 63);
++ break;
++ /* e4 52 .. | size = 44 */
++ case 0x52: if (packet_len == 44 ) return ((IPP2P_EDK * 100) + 64);
++ break;
++ /* e4 58 .. | size == 6 */
++ case 0x58: if (packet_len == 14 ) return ((IPP2P_EDK * 100) + 65);
++ break;
++ /* e4 59 .. | size == 2 */
++ case 0x59: if (packet_len == 10 )return ((IPP2P_EDK * 100) + 66);
++ break;
++ /* e4 28 .. | packet_len == 52,77,102,127... */
++ case 0x28: if (((packet_len-52) % 25) == 0) return ((IPP2P_EDK * 100) + 67);
++ break;
++ /* e4 50 xx xx | size == 4 */
++ case 0x50: if (packet_len == 12) return ((IPP2P_EDK * 100) + 68);
++ break;
++ /* e4 40 xx xx | size == 48 */
++ case 0x40: if (packet_len == 56) return ((IPP2P_EDK * 100) + 69);
++ break;
++ }
++ break;
++ }
++ } /* end of switch (t[0]) */
++ return 0;
++}/*udp_search_edk*/
++
++
++/*Search for UDP Gnutella commands*/
++int
++udp_search_gnu (unsigned char *haystack, int packet_len)
++{
++ unsigned char *t = haystack;
++ t += 8;
++
++ if (memcmp(t, "GND", 3) == 0) return ((IPP2P_GNU * 100) + 51);
++ if (memcmp(t, "GNUTELLA ", 9) == 0) return ((IPP2P_GNU * 100) + 52);
++ return 0;
++}/*udp_search_gnu*/
++
++
++/*Search for UDP KaZaA commands*/
++int
++udp_search_kazaa (unsigned char *haystack, int packet_len)
++{
++ unsigned char *t = haystack;
++
++ if (t[packet_len-1] == 0x00){
++ t += (packet_len - 6);
++ if (memcmp(t, "KaZaA", 5) == 0) return (IPP2P_KAZAA * 100 +50);
++ }
++
++ return 0;
++}/*udp_search_kazaa*/
++
++/*Search for UDP DirectConnect commands*/
++int
++udp_search_directconnect (unsigned char *haystack, int packet_len)
++{
++ unsigned char *t = haystack;
++ if ((*(t + 8) == 0x24) && (*(t + packet_len - 1) == 0x7c)) {
++ t+=8;
++ if (memcmp(t, "SR ", 3) == 0) return ((IPP2P_DC * 100) + 60);
++ if (memcmp(t, "Ping ", 5) == 0) return ((IPP2P_DC * 100) + 61);
++ }
++ return 0;
++}/*udp_search_directconnect*/
++
++
++
++/*Search for UDP BitTorrent commands*/
++int
++udp_search_bit (unsigned char *haystack, int packet_len)
++{
++ switch(packet_len)
++ {
++ case 24:
++ /* ^ 00 00 04 17 27 10 19 80 */
++ if ((ntohl(get_u32(haystack, 8)) == 0x00000417) && (ntohl(get_u32(haystack, 12)) == 0x27101980))
++ return (IPP2P_BIT * 100 + 50);
++ break;
++ case 44:
++ if (get_u32(haystack, 16) == __constant_htonl(0x00000400) && get_u32(haystack, 36) == __constant_htonl(0x00000104))
++ return (IPP2P_BIT * 100 + 51);
++ if (get_u32(haystack, 16) == __constant_htonl(0x00000400))
++ return (IPP2P_BIT * 100 + 61);
++ break;
++ case 65:
++ if (get_u32(haystack, 16) == __constant_htonl(0x00000404) && get_u32(haystack, 36) == __constant_htonl(0x00000104))
++ return (IPP2P_BIT * 100 + 52);
++ if (get_u32(haystack, 16) == __constant_htonl(0x00000404))
++ return (IPP2P_BIT * 100 + 62);
++ break;
++ case 67:
++ if (get_u32(haystack, 16) == __constant_htonl(0x00000406) && get_u32(haystack, 36) == __constant_htonl(0x00000104))
++ return (IPP2P_BIT * 100 + 53);
++ if (get_u32(haystack, 16) == __constant_htonl(0x00000406))
++ return (IPP2P_BIT * 100 + 63);
++ break;
++ case 211:
++ if (get_u32(haystack, 8) == __constant_htonl(0x00000405))
++ return (IPP2P_BIT * 100 + 54);
++ break;
++ case 29:
++ if ((get_u32(haystack, 8) == __constant_htonl(0x00000401)))
++ return (IPP2P_BIT * 100 + 55);
++ break;
++ case 52:
++ if (get_u32(haystack,8) == __constant_htonl(0x00000827) &&
++ get_u32(haystack,12) == __constant_htonl(0x37502950))
++ return (IPP2P_BIT * 100 + 80);
++ break;
++ default:
++ /* this packet does not have a constant size */
++ if (packet_len >= 40 && get_u32(haystack, 16) == __constant_htonl(0x00000402) && get_u32(haystack, 36) == __constant_htonl(0x00000104))
++ return (IPP2P_BIT * 100 + 56);
++ break;
++ }
++
++ /* some extra-bitcomet rules:
++ * "d1:" [a|r] "d2:id20:"
++ */
++ if (packet_len > 30 && get_u8(haystack, 8) == 'd' && get_u8(haystack, 9) == '1' && get_u8(haystack, 10) == ':' )
++ {
++ if (get_u8(haystack, 11) == 'a' || get_u8(haystack, 11) == 'r')
++ {
++ if (memcmp(haystack+12,"d2:id20:",8)==0)
++ return (IPP2P_BIT * 100 + 57);
++ }
++ }
++
++#if 0
++ /* bitlord rules */
++ /* packetlen must be bigger than 40 */
++ /* first 4 bytes are zero */
++ if (packet_len > 40 && get_u32(haystack, 8) == 0x00000000)
++ {
++ /* first rule: 00 00 00 00 01 00 00 xx xx xx xx 00 00 00 00*/
++ if (get_u32(haystack, 12) == 0x00000000 &&
++ get_u32(haystack, 16) == 0x00010000 &&
++ get_u32(haystack, 24) == 0x00000000 )
++ return (IPP2P_BIT * 100 + 71);
++
++ /* 00 01 00 00 0d 00 00 xx xx xx xx 00 00 00 00*/
++ if (get_u32(haystack, 12) == 0x00000001 &&
++ get_u32(haystack, 16) == 0x000d0000 &&
++ get_u32(haystack, 24) == 0x00000000 )
++ return (IPP2P_BIT * 100 + 71);
++
++
++ }
++#endif
++
++ return 0;
++}/*udp_search_bit*/
++
++
++
++/*Search for Ares commands*/
++//#define IPP2P_DEBUG_ARES
++int
++search_ares (const unsigned char *payload, const u16 plen)
++//int search_ares (unsigned char *haystack, int packet_len, int head_len)
++{
++// const unsigned char *t = haystack + head_len;
++
++ /* all ares packets start with */
++ if (payload[1] == 0 && (plen - payload[0]) == 3)
++ {
++ switch (payload[2])
++ {
++ case 0x5a:
++ /* ares connect */
++ if ( plen == 6 && payload[5] == 0x05 ) return ((IPP2P_ARES * 100) + 1);
++ break;
++ case 0x09:
++ /* ares search, min 3 chars --> 14 bytes
++ * lets define a search can be up to 30 chars --> max 34 bytes
++ */
++ if ( plen >= 14 && plen <= 34 ) return ((IPP2P_ARES * 100) + 1);
++ break;
++#ifdef IPP2P_DEBUG_ARES
++ default:
++ printk(KERN_DEBUG "Unknown Ares command %x recognized, len: %u \n", (unsigned int) payload[2],plen);
++#endif /* IPP2P_DEBUG_ARES */
++ }
++ }
++
++#if 0
++ /* found connect packet: 03 00 5a 04 03 05 */
++ /* new version ares 1.8: 03 00 5a xx xx 05 */
++ if ((plen) == 6){ /* possible connect command*/
++ if ((payload[0] == 0x03) && (payload[1] == 0x00) && (payload[2] == 0x5a) && (payload[5] == 0x05))
++ return ((IPP2P_ARES * 100) + 1);
++ }
++ if ((plen) == 60){ /* possible download command*/
++ if ((payload[59] == 0x0a) && (payload[58] == 0x0a)){
++ if (memcmp(t, "PUSH SHA1:", 10) == 0) /* found download command */
++ return ((IPP2P_ARES * 100) + 2);
++ }
++ }
++#endif
++
++ return 0;
++} /*search_ares*/
++
++/*Search for SoulSeek commands*/
++int
++search_soul (const unsigned char *payload, const u16 plen)
++{
++//#define IPP2P_DEBUG_SOUL
++ /* match: xx xx xx xx | xx = sizeof(payload) - 4 */
++ if (get_u32(payload, 0) == (plen - 4)){
++ const __u32 m=get_u32(payload, 4);
++ /* match 00 yy yy 00, yy can be everything */
++ if ( get_u8(payload, 4) == 0x00 && get_u8(payload, 7) == 0x00 )
++ {
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "0: Soulseek command 0x%x recognized\n",get_u32(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 1);
++ }
++
++ /* next match: 01 yy 00 00 | yy can be everything */
++ if ( get_u8(payload, 4) == 0x01 && get_u16(payload, 6) == 0x0000 )
++ {
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "1: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 2);
++ }
++
++ /* other soulseek commandos are: 1-5,7,9,13-18,22,23,26,28,35-37,40-46,50,51,60,62-69,91,92,1001 */
++ /* try to do this in an intelligent way */
++ /* get all small commandos */
++ switch(m)
++ {
++ case 7:
++ case 9:
++ case 22:
++ case 23:
++ case 26:
++ case 28:
++ case 50:
++ case 51:
++ case 60:
++ case 91:
++ case 92:
++ case 1001:
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "2: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 3);
++ }
++
++ if (m > 0 && m < 6 )
++ {
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "3: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 4);
++ }
++ if (m > 12 && m < 19 )
++ {
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "4: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 5);
++ }
++
++ if (m > 34 && m < 38 )
++ {
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "5: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 6);
++ }
++
++ if (m > 39 && m < 47 )
++ {
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "6: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 7);
++ }
++
++ if (m > 61 && m < 70 )
++ {
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "7: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 8);
++ }
++
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "unknown SOULSEEK command: 0x%x, first 16 bit: 0x%x, first 8 bit: 0x%x ,soulseek ???\n",get_u32(payload, 4),get_u16(payload, 4) >> 16,get_u8(payload, 4) >> 24);
++#endif /* IPP2P_DEBUG_SOUL */
++ }
++
++ /* match 14 00 00 00 01 yy 00 00 00 STRING(YY) 01 00 00 00 00 46|50 00 00 00 00 */
++ /* without size at the beginning !!! */
++ if ( get_u32(payload, 0) == 0x14 && get_u8(payload, 4) == 0x01 )
++ {
++ __u32 y=get_u32(payload, 5);
++ /* we need 19 chars + string */
++ if ( (y + 19) <= (plen) )
++ {
++ const unsigned char *w=payload+9+y;
++ if (get_u32(w, 0) == 0x01 && ( get_u16(w, 4) == 0x4600 || get_u16(w, 4) == 0x5000) && get_u32(w, 6) == 0x00);
++#ifdef IPP2P_DEBUG_SOUL
++ printk(KERN_DEBUG "Soulssek special client command recognized\n");
++#endif /* IPP2P_DEBUG_SOUL */
++ return ((IPP2P_SOUL * 100) + 9);
++ }
++ }
++ return 0;
++}
++
++
++/*Search for WinMX commands*/
++int
++search_winmx (const unsigned char *payload, const u16 plen)
++{
++//#define IPP2P_DEBUG_WINMX
++ if (((plen) == 4) && (memcmp(payload, "SEND", 4) == 0)) return ((IPP2P_WINMX * 100) + 1);
++ if (((plen) == 3) && (memcmp(payload, "GET", 3) == 0)) return ((IPP2P_WINMX * 100) + 2);
++ //if (packet_len < (head_len + 10)) return 0;
++ if (plen < 10) return 0;
++
++ if ((memcmp(payload, "SEND", 4) == 0) || (memcmp(payload, "GET", 3) == 0)){
++ u16 c=4;
++ const u16 end=plen-2;
++ u8 count=0;
++ while (c < end)
++ {
++ if (payload[c]== 0x20 && payload[c+1] == 0x22)
++ {
++ c++;
++ count++;
++ if (count>=2) return ((IPP2P_WINMX * 100) + 3);
++ }
++ c++;
++ }
++ }
++
++ if ( plen == 149 && payload[0] == '8' )
++ {
++#ifdef IPP2P_DEBUG_WINMX
++ printk(KERN_INFO "maybe WinMX\n");
++#endif
++ if (get_u32(payload,17) == 0 && get_u32(payload,21) == 0 && get_u32(payload,25) == 0 &&
++// get_u32(payload,33) == __constant_htonl(0x71182b1a) && get_u32(payload,37) == __constant_htonl(0x05050000) &&
++// get_u32(payload,133) == __constant_htonl(0x31097edf) && get_u32(payload,145) == __constant_htonl(0xdcb8f792))
++ get_u16(payload,39) == 0 && get_u16(payload,135) == __constant_htons(0x7edf) && get_u16(payload,147) == __constant_htons(0xf792))
++
++ {
++#ifdef IPP2P_DEBUG_WINMX
++ printk(KERN_INFO "got WinMX\n");
++#endif
++ return ((IPP2P_WINMX * 100) + 4);
++ }
++ }
++ return 0;
++} /*search_winmx*/
++
++
++/*Search for appleJuice commands*/
++int
++search_apple (const unsigned char *payload, const u16 plen)
++{
++ if ( (plen > 7) && (payload[6] == 0x0d) && (payload[7] == 0x0a) && (memcmp(payload, "ajprot", 6) == 0)) return (IPP2P_APPLE * 100);
++
++ return 0;
++}
++
++
++/*Search for BitTorrent commands*/
++int
++search_bittorrent (const unsigned char *payload, const u16 plen)
++{
++ if (plen > 20)
++ {
++ /* test for match 0x13+"BitTorrent protocol" */
++ if (payload[0] == 0x13)
++ {
++ if (memcmp(payload+1, "BitTorrent protocol", 19) == 0) return (IPP2P_BIT * 100);
++ }
++
++ /* get tracker commandos, all starts with GET /
++ * then it can follow: scrape| announce
++ * and then ?hash_info=
++ */
++ if (memcmp(payload,"GET /",5) == 0)
++ {
++ /* message scrape */
++ if ( memcmp(payload+5,"scrape?info_hash=",17)==0 ) return (IPP2P_BIT * 100 + 1);
++ /* message announce */
++ if ( memcmp(payload+5,"announce?info_hash=",19)==0 ) return (IPP2P_BIT * 100 + 2);
++ }
++ }
++ else
++ {
++ /* bitcomet encryptes the first packet, so we have to detect another
++ * one later in the flow */
++ /* first try failed, too many missdetections */
++ //if ( size == 5 && get_u32(t,0) == __constant_htonl(1) && t[4] < 3) return (IPP2P_BIT * 100 + 3);
++
++ /* second try: block request packets */
++ if ( plen == 17 && get_u32(payload,0) == __constant_htonl(0x0d) && payload[4] == 0x06 && get_u32(payload,13) == __constant_htonl(0x4000) ) return (IPP2P_BIT * 100 + 3);
++ }
++
++ return 0;
++}
++
++
++
++/*check for Kazaa get command*/
++int
++search_kazaa (const unsigned char *payload, const u16 plen)
++
++{
++ if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a) && memcmp(payload, "GET /.hash=", 11) == 0)
++ return (IPP2P_DATA_KAZAA * 100);
++
++ return 0;
++}
++
++
++/*check for gnutella get command*/
++int
++search_gnu (const unsigned char *payload, const u16 plen)
++{
++ if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a))
++ {
++ if (memcmp(payload, "GET /get/", 9) == 0) return ((IPP2P_DATA_GNU * 100) + 1);
++ if (memcmp(payload, "GET /uri-res/", 13) == 0) return ((IPP2P_DATA_GNU * 100) + 2);
++ }
++ return 0;
++}
++
++
++/*check for gnutella get commands and other typical data*/
++int
++search_all_gnu (const unsigned char *payload, const u16 plen)
++{
++
++ if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a))
++ {
++
++ if (memcmp(payload, "GNUTELLA CONNECT/", 17) == 0) return ((IPP2P_GNU * 100) + 1);
++ if (memcmp(payload, "GNUTELLA/", 9) == 0) return ((IPP2P_GNU * 100) + 2);
++
++
++ if ((memcmp(payload, "GET /get/", 9) == 0) || (memcmp(payload, "GET /uri-res/", 13) == 0))
++ {
++ u16 c=8;
++ const u16 end=plen-22;
++ while (c < end) {
++ if ( payload[c] == 0x0a && payload[c+1] == 0x0d && ((memcmp(&payload[c+2], "X-Gnutella-", 11) == 0) || (memcmp(&payload[c+2], "X-Queue:", 8) == 0)))
++ return ((IPP2P_GNU * 100) + 3);
++ c++;
++ }
++ }
++ }
++ return 0;
++}
++
++
++/*check for KaZaA download commands and other typical data*/
++int
++search_all_kazaa (const unsigned char *payload, const u16 plen)
++{
++ if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a))
++ {
++
++ if (memcmp(payload, "GIVE ", 5) == 0) return ((IPP2P_KAZAA * 100) + 1);
++
++ if (memcmp(payload, "GET /", 5) == 0) {
++ u16 c = 8;
++ const u16 end=plen-22;
++ while (c < end) {
++ if ( payload[c] == 0x0a && payload[c+1] == 0x0d && ((memcmp(&payload[c+2], "X-Kazaa-Username: ", 18) == 0) || (memcmp(&payload[c+2], "User-Agent: PeerEnabler/", 24) == 0)))
++ return ((IPP2P_KAZAA * 100) + 2);
++ c++;
++ }
++ }
++ }
++ return 0;
++}
++
++/*fast check for edonkey file segment transfer command*/
++int
++search_edk (const unsigned char *payload, const u16 plen)
++{
++ if (payload[0] != 0xe3)
++ return 0;
++ else {
++ if (payload[5] == 0x47)
++ return (IPP2P_DATA_EDK * 100);
++ else
++ return 0;
++ }
++}
++
++
++
++/*intensive but slower search for some edonkey packets including size-check*/
++int
++search_all_edk (const unsigned char *payload, const u16 plen)
++{
++ if (payload[0] != 0xe3)
++ return 0;
++ else {
++ //t += head_len;
++ const u16 cmd = get_u16(payload, 1);
++ if (cmd == (plen - 5)) {
++ switch (payload[5]) {
++ case 0x01: return ((IPP2P_EDK * 100) + 1); /*Client: hello or Server:hello*/
++ case 0x4c: return ((IPP2P_EDK * 100) + 9); /*Client: Hello-Answer*/
++ }
++ }
++ return 0;
++ }
++}
++
++
++/*fast check for Direct Connect send command*/
++int
++search_dc (const unsigned char *payload, const u16 plen)
++{
++
++ if (payload[0] != 0x24 )
++ return 0;
++ else {
++ if (memcmp(&payload[1], "Send|", 5) == 0)
++ return (IPP2P_DATA_DC * 100);
++ else
++ return 0;
++ }
++
++}
++
++
++/*intensive but slower check for all direct connect packets*/
++int
++search_all_dc (const unsigned char *payload, const u16 plen)
++{
++// unsigned char *t = haystack;
++
++ if (payload[0] == 0x24 && payload[plen-1] == 0x7c)
++ {
++ const unsigned char *t=&payload[1];
++ /* Client-Hub-Protocol */
++ if (memcmp(t, "Lock ", 5) == 0) return ((IPP2P_DC * 100) + 1);
++ /* Client-Client-Protocol, some are already recognized by client-hub (like lock) */
++ if (memcmp(t, "MyNick ", 7) == 0) return ((IPP2P_DC * 100) + 38);
++ }
++ return 0;
++}
++
++/*check for mute*/
++int
++search_mute (const unsigned char *payload, const u16 plen)
++{
++ if ( plen == 209 || plen == 345 || plen == 473 || plen == 609 || plen == 1121 )
++ {
++ //printk(KERN_DEBUG "size hit: %u",size);
++ if (memcmp(payload,"PublicKey: ",11) == 0 )
++ {
++ return ((IPP2P_MUTE * 100) + 0);
++
++/* if (memcmp(t+size-14,"\x0aEndPublicKey\x0a",14) == 0)
++ {
++ printk(KERN_DEBUG "end pubic key hit: %u",size);
++
++ }*/
++ }
++ }
++ return 0;
++}
++
++
++/* check for xdcc */
++int
++search_xdcc (const unsigned char *payload, const u16 plen)
++{
++ /* search in small packets only */
++ if (plen > 20 && plen < 200 && payload[plen-1] == 0x0a && payload[plen-2] == 0x0d && memcmp(payload,"PRIVMSG ",8) == 0)
++ {
++
++ u16 x=10;
++ const u16 end=plen - 13;
++
++ /* is seems to be a irc private massage, chedck for xdcc command */
++ while (x < end)
++ {
++ if (payload[x] == ':')
++ {
++ if ( memcmp(&payload[x+1],"xdcc send #",11) == 0 )
++ return ((IPP2P_XDCC * 100) + 0);
++ }
++ x++;
++ }
++ }
++ return 0;
++}
++
++/* search for waste */
++int search_waste(const unsigned char *payload, const u16 plen)
++{
++ if ( plen >= 8 && memcmp(payload,"GET.sha1:",9) == 0)
++ return ((IPP2P_WASTE * 100) + 0);
++
++ return 0;
++}
++
++
++static struct {
++ int command;
++ __u8 short_hand; /*for fucntions included in short hands*/
++ int packet_len;
++ int (*function_name) (const unsigned char *, const u16);
++} matchlist[] = {
++ {IPP2P_EDK,SHORT_HAND_IPP2P,20, &search_all_edk},
++// {IPP2P_DATA_KAZAA,SHORT_HAND_DATA,200, &search_kazaa},
++// {IPP2P_DATA_EDK,SHORT_HAND_DATA,60, &search_edk},
++// {IPP2P_DATA_DC,SHORT_HAND_DATA,26, &search_dc},
++ {IPP2P_DC,SHORT_HAND_IPP2P,5, search_all_dc},
++// {IPP2P_DATA_GNU,SHORT_HAND_DATA,40, &search_gnu},
++ {IPP2P_GNU,SHORT_HAND_IPP2P,5, &search_all_gnu},
++ {IPP2P_KAZAA,SHORT_HAND_IPP2P,5, &search_all_kazaa},
++ {IPP2P_BIT,SHORT_HAND_IPP2P,20, &search_bittorrent},
++ {IPP2P_APPLE,SHORT_HAND_IPP2P,5, &search_apple},
++ {IPP2P_SOUL,SHORT_HAND_IPP2P,5, &search_soul},
++ {IPP2P_WINMX,SHORT_HAND_IPP2P,2, &search_winmx},
++ {IPP2P_ARES,SHORT_HAND_IPP2P,5, &search_ares},
++ {IPP2P_MUTE,SHORT_HAND_NONE,200, &search_mute},
++ {IPP2P_WASTE,SHORT_HAND_NONE,5, &search_waste},
++ {IPP2P_XDCC,SHORT_HAND_NONE,5, &search_xdcc},
++ {0,0,0,NULL}
++};
++
++
++static struct {
++ int command;
++ __u8 short_hand; /*for fucntions included in short hands*/
++ int packet_len;
++ int (*function_name) (unsigned char *, int);
++} udp_list[] = {
++ {IPP2P_KAZAA,SHORT_HAND_IPP2P,14, &udp_search_kazaa},
++ {IPP2P_BIT,SHORT_HAND_IPP2P,23, &udp_search_bit},
++ {IPP2P_GNU,SHORT_HAND_IPP2P,11, &udp_search_gnu},
++ {IPP2P_EDK,SHORT_HAND_IPP2P,9, &udp_search_edk},
++ {IPP2P_DC,SHORT_HAND_IPP2P,12, &udp_search_directconnect},
++ {0,0,0,NULL}
++};
++
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++ const void *hdr,
++ u_int16_t datalen,
++#endif
++
++ int *hotdrop)
++{
++ const struct ipt_p2p_info *info = matchinfo;
++ unsigned char *haystack;
++ struct iphdr *ip = skb->nh.iph;
++ int p2p_result = 0, i = 0;
++// int head_len;
++ int hlen = ntohs(ip->tot_len)-(ip->ihl*4); /*hlen = packet-data length*/
++
++ /*must not be a fragment*/
++ if (offset) {
++ if (info->debug) printk("IPP2P.match: offset found %i \n",offset);
++ return 0;
++ }
++
++ /*make sure that skb is linear*/
++ if(skb_is_nonlinear(skb)){
++ if (info->debug) printk("IPP2P.match: nonlinear skb found\n");
++ return 0;
++ }
++
++
++ haystack=(char *)ip+(ip->ihl*4); /*haystack = packet data*/
++
++ switch (ip->protocol){
++ case IPPROTO_TCP: /*what to do with a TCP packet*/
++ {
++ struct tcphdr *tcph = (void *) ip + ip->ihl * 4;
++
++ if (tcph->fin) return 0; /*if FIN bit is set bail out*/
++ if (tcph->syn) return 0; /*if SYN bit is set bail out*/
++ if (tcph->rst) return 0; /*if RST bit is set bail out*/
++
++ haystack += tcph->doff * 4; /*get TCP-Header-Size*/
++ hlen -= tcph->doff * 4;
++ while (matchlist[i].command) {
++ if ((((info->cmd & matchlist[i].command) == matchlist[i].command) ||
++ ((info->cmd & matchlist[i].short_hand) == matchlist[i].short_hand)) &&
++ (hlen > matchlist[i].packet_len)) {
++ p2p_result = matchlist[i].function_name(haystack, hlen);
++ if (p2p_result)
++ {
++ if (info->debug) printk("IPP2P.debug:TCP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
++ p2p_result, NIPQUAD(ip->saddr),ntohs(tcph->source), NIPQUAD(ip->daddr),ntohs(tcph->dest),hlen);
++ return p2p_result;
++ }
++ }
++ i++;
++ }
++ return p2p_result;
++ }
++
++ case IPPROTO_UDP: /*what to do with an UDP packet*/
++ {
++ struct udphdr *udph = (void *) ip + ip->ihl * 4;
++
++ while (udp_list[i].command){
++ if ((((info->cmd & udp_list[i].command) == udp_list[i].command) ||
++ ((info->cmd & udp_list[i].short_hand) == udp_list[i].short_hand)) &&
++ (hlen > udp_list[i].packet_len)) {
++ p2p_result = udp_list[i].function_name(haystack, hlen);
++ if (p2p_result){
++ if (info->debug) printk("IPP2P.debug:UDP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
++ p2p_result, NIPQUAD(ip->saddr),ntohs(udph->source), NIPQUAD(ip->daddr),ntohs(udph->dest),hlen);
++ return p2p_result;
++ }
++ }
++ i++;
++ }
++ return p2p_result;
++ }
++
++ default: return 0;
++ }
++}
++
++
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ /* Must specify -p tcp */
++/* if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) {
++ * printk("ipp2p: Only works on TCP packets, use -p tcp\n");
++ * return 0;
++ * }*/
++ return 1;
++}
++
++
++
++
++static struct ipt_match ipp2p_match = {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
++ { NULL, NULL },
++ "ipp2p",
++ &match,
++ &checkentry,
++ NULL,
++ THIS_MODULE
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
++ .name = "ipp2p",
++ .match = &match,
++ .checkentry = &checkentry,
++ .me = THIS_MODULE,
++#endif
++};
++
++
++static int __init init(void)
++{
++ printk(KERN_INFO "IPP2P v%s loading\n", IPP2P_VERSION);
++ return ipt_register_match(&ipp2p_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&ipp2p_match);
++ printk(KERN_INFO "IPP2P v%s unloaded\n", IPP2P_VERSION);
++}
++
++module_init(init);
++module_exit(fini);
++
++
+diff -Nur linux-2.6.17/net/ipv4/netfilter/Kconfig linux-2.6.17-owrt/net/ipv4/netfilter/Kconfig
+--- linux-2.6.17/net/ipv4/netfilter/Kconfig 2006-06-18 12:36:55.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/netfilter/Kconfig 2006-06-18 12:37:14.000000000 +0200
+@@ -222,6 +222,12 @@
+
+ To compile it as a module, choose M here. If unsure, say N.
+
++config IP_NF_MATCH_IPP2P
++ tristate "IPP2P"
++ depends on IP_NF_IPTABLES
++ help
++ Module for matching traffic of various Peer-to-Peer applications
++
+ config IP_NF_MATCH_TOS
+ tristate "TOS match support"
+ depends on IP_NF_IPTABLES
+diff -Nur linux-2.6.17/net/ipv4/netfilter/Makefile linux-2.6.17-owrt/net/ipv4/netfilter/Makefile
+--- linux-2.6.17/net/ipv4/netfilter/Makefile 2006-06-18 12:36:55.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/netfilter/Makefile 2006-06-18 12:38:11.000000000 +0200
+@@ -61,7 +61,7 @@
+ obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
+ obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
+ obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
+-
++obj-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p.o
+ obj-$(CONFIG_IP_NF_MATCH_LAYER7) += ipt_layer7.o
+
+ # targets
diff --git a/target/linux/generic-2.6/patches/102-openswan-2.4.0.kernel-2.6-natt.patch b/target/linux/generic-2.6/patches/102-openswan-2.4.0.kernel-2.6-natt.patch
new file mode 100644
index 0000000..6d6939b
--- /dev/null
+++ b/target/linux/generic-2.6/patches/102-openswan-2.4.0.kernel-2.6-natt.patch
@@ -0,0 +1,171 @@
+diff -Nur linux-2.6.16/include/net/xfrmudp.h linux-2.6.16-owrt/include/net/xfrmudp.h
+--- linux-2.6.16/include/net/xfrmudp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/net/xfrmudp.h 2006-03-22 21:39:54.000000000 +0100
+@@ -0,0 +1,10 @@
++/*
++ * pointer to function for type that xfrm4_input wants, to permit
++ * decoupling of XFRM from udp.c
++ */
++#define HAVE_XFRM4_UDP_REGISTER
++
++typedef int (*xfrm4_rcv_encap_t)(struct sk_buff *skb, __u16 encap_type);
++extern int udp4_register_esp_rcvencap(xfrm4_rcv_encap_t func
++ , xfrm4_rcv_encap_t *oldfunc);
++extern int udp4_unregister_esp_rcvencap(xfrm4_rcv_encap_t func);
+diff -Nur linux-2.6.16/net/ipv4/Kconfig linux-2.6.16-owrt/net/ipv4/Kconfig
+--- linux-2.6.16/net/ipv4/Kconfig 2006-03-20 06:53:29.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/Kconfig 2006-03-22 21:49:04.000000000 +0100
+@@ -271,6 +271,12 @@
+ Network), but can be distributed all over the Internet. If you want
+ to do that, say Y here and to "IP multicast routing" below.
+
++config IPSEC_NAT_TRAVERSAL
++ bool "IPSEC NAT-Traversal (KLIPS compatible)"
++ depends on INET
++ ---help---
++ Includes support for RFC3947/RFC3948 NAT-Traversal of ESP over UDP.
++
+ config IP_MROUTE
+ bool "IP: multicast routing"
+ depends on IP_MULTICAST
+diff -Nur linux-2.6.16/net/ipv4/udp.c linux-2.6.16-owrt/net/ipv4/udp.c
+--- linux-2.6.16/net/ipv4/udp.c 2006-03-20 06:53:29.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/udp.c 2006-03-22 21:39:54.000000000 +0100
+@@ -109,11 +109,14 @@
+ #include <net/inet_common.h>
+ #include <net/checksum.h>
+ #include <net/xfrm.h>
++#include <net/xfrmudp.h>
+
+ /*
+ * Snmp MIB for the UDP layer
+ */
+
++static xfrm4_rcv_encap_t xfrm4_rcv_encap_func;
++
+ DEFINE_SNMP_STAT(struct udp_mib, udp_statistics) __read_mostly;
+
+ struct hlist_head udp_hash[UDP_HTABLE_SIZE];
+@@ -882,6 +885,42 @@
+ sk_common_release(sk);
+ }
+
++#if defined(CONFIG_XFRM) || defined(CONFIG_IPSEC_NAT_TRAVERSAL)
++
++/* if XFRM isn't a module, then register it directly. */
++#if 0 && !defined(CONFIG_XFRM_MODULE) && !defined(CONFIG_IPSEC_NAT_TRAVERSAL)
++static xfrm4_rcv_encap_t xfrm4_rcv_encap_func = xfrm4_rcv_encap;
++#else
++static xfrm4_rcv_encap_t xfrm4_rcv_encap_func = NULL;
++#endif
++
++int udp4_register_esp_rcvencap(xfrm4_rcv_encap_t func
++ , xfrm4_rcv_encap_t *oldfunc)
++{
++ if(oldfunc != NULL) {
++ *oldfunc = xfrm4_rcv_encap_func;
++ }
++
++#if 0
++ if(xfrm4_rcv_encap_func != NULL)
++ return -1;
++#endif
++
++ xfrm4_rcv_encap_func = func;
++ return 0;
++}
++
++int udp4_unregister_esp_rcvencap(xfrm4_rcv_encap_t func)
++{
++ if(xfrm4_rcv_encap_func != func)
++ return -1;
++
++ xfrm4_rcv_encap_func = NULL;
++ return 0;
++}
++#endif /* CONFIG_XFRM_MODULE || CONFIG_IPSEC_NAT_TRAVERSAL */
++
++
+ /* return:
+ * 1 if the the UDP system should process it
+ * 0 if we should drop this packet
+@@ -889,9 +928,9 @@
+ */
+ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb)
+ {
+-#ifndef CONFIG_XFRM
++#if !defined(CONFIG_XFRM) && !defined(CONFIG_IPSEC_NAT_TRAVERSAL)
+ return 1;
+-#else
++#else /* either CONFIG_XFRM or CONFIG_IPSEC_NAT_TRAVERSAL */
+ struct udp_sock *up = udp_sk(sk);
+ struct udphdr *uh = skb->h.uh;
+ struct iphdr *iph;
+@@ -903,11 +942,11 @@
+
+ /* if we're overly short, let UDP handle it */
+ if (udpdata > skb->tail)
+- return 1;
++ return 2;
+
+ /* if this is not encapsulated socket, then just return now */
+ if (!encap_type)
+- return 1;
++ return 3;
+
+ len = skb->tail - udpdata;
+
+@@ -922,7 +961,7 @@
+ len = sizeof(struct udphdr);
+ } else
+ /* Must be an IKE packet.. pass it through */
+- return 1;
++ return 4;
+ break;
+ case UDP_ENCAP_ESPINUDP_NON_IKE:
+ /* Check if this is a keepalive packet. If so, eat it. */
+@@ -935,7 +974,7 @@
+ len = sizeof(struct udphdr) + 2 * sizeof(u32);
+ } else
+ /* Must be an IKE packet.. pass it through */
+- return 1;
++ return 5;
+ break;
+ }
+
+@@ -946,6 +985,8 @@
+ */
+ if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ return 0;
++ if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
++ return 0;
+
+ /* Now we can update and verify the packet length... */
+ iph = skb->nh.iph;
+@@ -1010,9 +1051,13 @@
+ return 0;
+ }
+ if (ret < 0) {
+- /* process the ESP packet */
+- ret = xfrm4_rcv_encap(skb, up->encap_type);
+- UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS);
++ if(xfrm4_rcv_encap_func != NULL) {
++ ret = (*xfrm4_rcv_encap_func)(skb, up->encap_type);
++ UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS);
++ } else {
++ UDP_INC_STATS_BH(UDP_MIB_INERRORS);
++ ret = 1;
++ }
+ return -ret;
+ }
+ /* FALLTHROUGH -- it's a UDP Packet */
+@@ -1559,3 +1604,9 @@
+ EXPORT_SYMBOL(udp_proc_register);
+ EXPORT_SYMBOL(udp_proc_unregister);
+ #endif
++
++#if defined(CONFIG_IPSEC_NAT_TRAVERSAL)
++EXPORT_SYMBOL(udp4_register_esp_rcvencap);
++EXPORT_SYMBOL(udp4_unregister_esp_rcvencap);
++#endif
++
diff --git a/target/linux/generic-2.6/patches/103-netfilter-ipset.patch b/target/linux/generic-2.6/patches/103-netfilter-ipset.patch
new file mode 100644
index 0000000..fb75c8b
--- /dev/null
+++ b/target/linux/generic-2.6/patches/103-netfilter-ipset.patch
@@ -0,0 +1,5739 @@
+diff -Nur linux-2.6.16/include/linux/netfilter_ipv4/ip_set.h linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set.h
+--- linux-2.6.16/include/linux/netfilter_ipv4/ip_set.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set.h 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,489 @@
++#ifndef _IP_SET_H
++#define _IP_SET_H
++
++/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
++ * Patrick Schaaf <bof@bof.de>
++ * Martin Josefsson <gandalf@wlug.westbo.se>
++ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * A sockopt of such quality has hardly ever been seen before on the open
++ * market! This little beauty, hardly ever used: above 64, so it's
++ * traditionally used for firewalling, not touched (even once!) by the
++ * 2.0, 2.2 and 2.4 kernels!
++ *
++ * Comes with its own certificate of authenticity, valid anywhere in the
++ * Free world!
++ *
++ * Rusty, 19.4.2000
++ */
++#define SO_IP_SET 83
++
++/*
++ * Heavily modify by Joakim Axelsson 08.03.2002
++ * - Made it more modulebased
++ *
++ * Additional heavy modifications by Jozsef Kadlecsik 22.02.2004
++ * - bindings added
++ * - in order to "deal with" backward compatibility, renamed to ipset
++ */
++
++/*
++ * Used so that the kernel module and ipset-binary can match their versions
++ */
++#define IP_SET_PROTOCOL_VERSION 2
++
++#define IP_SET_MAXNAMELEN 32 /* set names and set typenames */
++
++/* Lets work with our own typedef for representing an IP address.
++ * We hope to make the code more portable, possibly to IPv6...
++ *
++ * The representation works in HOST byte order, because most set types
++ * will perform arithmetic operations and compare operations.
++ *
++ * For now the type is an uint32_t.
++ *
++ * Make sure to ONLY use the functions when translating and parsing
++ * in order to keep the host byte order and make it more portable:
++ * parse_ip()
++ * parse_mask()
++ * parse_ipandmask()
++ * ip_tostring()
++ * (Joakim: where are they???)
++ */
++
++typedef uint32_t ip_set_ip_t;
++
++/* Sets are identified by an id in kernel space. Tweak with ip_set_id_t
++ * and IP_SET_INVALID_ID if you want to increase the max number of sets.
++ */
++typedef uint16_t ip_set_id_t;
++
++#define IP_SET_INVALID_ID 65535
++
++/* How deep we follow bindings */
++#define IP_SET_MAX_BINDINGS 6
++
++/*
++ * Option flags for kernel operations (ipt_set_info)
++ */
++#define IPSET_SRC 0x01 /* Source match/add */
++#define IPSET_DST 0x02 /* Destination match/add */
++#define IPSET_MATCH_INV 0x04 /* Inverse matching */
++
++/*
++ * Set types (flavours)
++ */
++#define IPSET_TYPE_IP 0 /* IP address type of set */
++#define IPSET_TYPE_PORT 1 /* Port type of set */
++
++/* Reserved keywords */
++#define IPSET_TOKEN_DEFAULT ":default:"
++#define IPSET_TOKEN_ALL ":all:"
++
++/* SO_IP_SET operation constants, and their request struct types.
++ *
++ * Operation ids:
++ * 0-99: commands with version checking
++ * 100-199: add/del/test/bind/unbind
++ * 200-299: list, save, restore
++ */
++
++/* Single shot operations:
++ * version, create, destroy, flush, rename and swap
++ *
++ * Sets are identified by name.
++ */
++
++#define IP_SET_REQ_STD \
++ unsigned op; \
++ unsigned version; \
++ char name[IP_SET_MAXNAMELEN]
++
++#define IP_SET_OP_CREATE 0x00000001 /* Create a new (empty) set */
++struct ip_set_req_create {
++ IP_SET_REQ_STD;
++ char typename[IP_SET_MAXNAMELEN];
++};
++
++#define IP_SET_OP_DESTROY 0x00000002 /* Remove a (empty) set */
++struct ip_set_req_std {
++ IP_SET_REQ_STD;
++};
++
++#define IP_SET_OP_FLUSH 0x00000003 /* Remove all IPs in a set */
++/* Uses ip_set_req_std */
++
++#define IP_SET_OP_RENAME 0x00000004 /* Rename a set */
++/* Uses ip_set_req_create */
++
++#define IP_SET_OP_SWAP 0x00000005 /* Swap two sets */
++/* Uses ip_set_req_create */
++
++union ip_set_name_index {
++ char name[IP_SET_MAXNAMELEN];
++ ip_set_id_t index;
++};
++
++#define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */
++struct ip_set_req_get_set {
++ unsigned op;
++ unsigned version;
++ union ip_set_name_index set;
++};
++
++#define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */
++/* Uses ip_set_req_get_set */
++
++#define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */
++struct ip_set_req_version {
++ unsigned op;
++ unsigned version;
++};
++
++/* Double shots operations:
++ * add, del, test, bind and unbind.
++ *
++ * First we query the kernel to get the index and type of the target set,
++ * then issue the command. Validity of IP is checked in kernel in order
++ * to minimalize sockopt operations.
++ */
++
++/* Get minimal set data for add/del/test/bind/unbind IP */
++#define IP_SET_OP_ADT_GET 0x00000010 /* Get set and type */
++struct ip_set_req_adt_get {
++ unsigned op;
++ unsigned version;
++ union ip_set_name_index set;
++ char typename[IP_SET_MAXNAMELEN];
++};
++
++#define IP_SET_REQ_BYINDEX \
++ unsigned op; \
++ ip_set_id_t index;
++
++struct ip_set_req_adt {
++ IP_SET_REQ_BYINDEX;
++};
++
++#define IP_SET_OP_ADD_IP 0x00000101 /* Add an IP to a set */
++/* Uses ip_set_req_adt, with type specific addage */
++
++#define IP_SET_OP_DEL_IP 0x00000102 /* Remove an IP from a set */
++/* Uses ip_set_req_adt, with type specific addage */
++
++#define IP_SET_OP_TEST_IP 0x00000103 /* Test an IP in a set */
++/* Uses ip_set_req_adt, with type specific addage */
++
++#define IP_SET_OP_BIND_SET 0x00000104 /* Bind an IP to a set */
++/* Uses ip_set_req_bind, with type specific addage */
++struct ip_set_req_bind {
++ IP_SET_REQ_BYINDEX;
++ char binding[IP_SET_MAXNAMELEN];
++};
++
++#define IP_SET_OP_UNBIND_SET 0x00000105 /* Unbind an IP from a set */
++/* Uses ip_set_req_bind, with type speficic addage
++ * index = 0 means unbinding for all sets */
++
++#define IP_SET_OP_TEST_BIND_SET 0x00000106 /* Test binding an IP to a set */
++/* Uses ip_set_req_bind, with type specific addage */
++
++/* Multiple shots operations: list, save, restore.
++ *
++ * - check kernel version and query the max number of sets
++ * - get the basic information on all sets
++ * and size required for the next step
++ * - get actual set data: header, data, bindings
++ */
++
++/* Get max_sets and the index of a queried set
++ */
++#define IP_SET_OP_MAX_SETS 0x00000020
++struct ip_set_req_max_sets {
++ unsigned op;
++ unsigned version;
++ ip_set_id_t max_sets; /* max_sets */
++ ip_set_id_t sets; /* real number of sets */
++ union ip_set_name_index set; /* index of set if name used */
++};
++
++/* Get the id and name of the sets plus size for next step */
++#define IP_SET_OP_LIST_SIZE 0x00000201
++#define IP_SET_OP_SAVE_SIZE 0x00000202
++struct ip_set_req_setnames {
++ unsigned op;
++ ip_set_id_t index; /* set to list/save */
++ size_t size; /* size to get setdata/bindings */
++ /* followed by sets number of struct ip_set_name_list */
++};
++
++struct ip_set_name_list {
++ char name[IP_SET_MAXNAMELEN];
++ char typename[IP_SET_MAXNAMELEN];
++ ip_set_id_t index;
++ ip_set_id_t id;
++};
++
++/* The actual list operation */
++#define IP_SET_OP_LIST 0x00000203
++struct ip_set_req_list {
++ IP_SET_REQ_BYINDEX;
++ /* sets number of struct ip_set_list in reply */
++};
++
++struct ip_set_list {
++ ip_set_id_t index;
++ ip_set_id_t binding;
++ u_int32_t ref;
++ size_t header_size; /* Set header data of header_size */
++ size_t members_size; /* Set members data of members_size */
++ size_t bindings_size; /* Set bindings data of bindings_size */
++};
++
++struct ip_set_hash_list {
++ ip_set_ip_t ip;
++ ip_set_id_t binding;
++};
++
++/* The save operation */
++#define IP_SET_OP_SAVE 0x00000204
++/* Uses ip_set_req_list, in the reply replaced by
++ * sets number of struct ip_set_save plus a marker
++ * ip_set_save followed by ip_set_hash_save structures.
++ */
++struct ip_set_save {
++ ip_set_id_t index;
++ ip_set_id_t binding;
++ size_t header_size; /* Set header data of header_size */
++ size_t members_size; /* Set members data of members_size */
++};
++
++/* At restoring, ip == 0 means default binding for the given set: */
++struct ip_set_hash_save {
++ ip_set_ip_t ip;
++ ip_set_id_t id;
++ ip_set_id_t binding;
++};
++
++/* The restore operation */
++#define IP_SET_OP_RESTORE 0x00000205
++/* Uses ip_set_req_setnames followed by ip_set_restore structures
++ * plus a marker ip_set_restore, followed by ip_set_hash_save
++ * structures.
++ */
++struct ip_set_restore {
++ char name[IP_SET_MAXNAMELEN];
++ char typename[IP_SET_MAXNAMELEN];
++ ip_set_id_t index;
++ size_t header_size; /* Create data of header_size */
++ size_t members_size; /* Set members data of members_size */
++};
++
++static inline int bitmap_bytes(ip_set_ip_t a, ip_set_ip_t b)
++{
++ return 4 * ((((b - a + 8) / 8) + 3) / 4);
++}
++
++#ifdef __KERNEL__
++
++#define ip_set_printk(format, args...) \
++ do { \
++ printk("%s: %s: ", __FILE__, __FUNCTION__); \
++ printk(format "\n" , ## args); \
++ } while (0)
++
++#if defined(IP_SET_DEBUG)
++#define DP(format, args...) \
++ do { \
++ printk("%s: %s (DBG): ", __FILE__, __FUNCTION__);\
++ printk(format "\n" , ## args); \
++ } while (0)
++#define IP_SET_ASSERT(x) \
++ do { \
++ if (!(x)) \
++ printk("IP_SET_ASSERT: %s:%i(%s)\n", \
++ __FILE__, __LINE__, __FUNCTION__); \
++ } while (0)
++#else
++#define DP(format, args...)
++#define IP_SET_ASSERT(x)
++#endif
++
++struct ip_set;
++
++/*
++ * The ip_set_type definition - one per set type, e.g. "ipmap".
++ *
++ * Each individual set has a pointer, set->type, going to one
++ * of these structures. Function pointers inside the structure implement
++ * the real behaviour of the sets.
++ *
++ * If not mentioned differently, the implementation behind the function
++ * pointers of a set_type, is expected to return 0 if ok, and a negative
++ * errno (e.g. -EINVAL) on error.
++ */
++struct ip_set_type {
++ struct list_head list; /* next in list of set types */
++
++ /* test for IP in set (kernel: iptables -m set src|dst)
++ * return 0 if not in set, 1 if in set.
++ */
++ int (*testip_kernel) (struct ip_set *set,
++ const struct sk_buff * skb,
++ u_int32_t flags,
++ ip_set_ip_t *ip);
++
++ /* test for IP in set (userspace: ipset -T set IP)
++ * return 0 if not in set, 1 if in set.
++ */
++ int (*testip) (struct ip_set *set,
++ const void *data, size_t size,
++ ip_set_ip_t *ip);
++
++ /*
++ * Size of the data structure passed by when
++ * adding/deletin/testing an entry.
++ */
++ size_t reqsize;
++
++ /* Add IP into set (userspace: ipset -A set IP)
++ * Return -EEXIST if the address is already in the set,
++ * and -ERANGE if the address lies outside the set bounds.
++ * If the address was not already in the set, 0 is returned.
++ */
++ int (*addip) (struct ip_set *set,
++ const void *data, size_t size,
++ ip_set_ip_t *ip);
++
++ /* Add IP into set (kernel: iptables ... -j SET set src|dst)
++ * Return -EEXIST if the address is already in the set,
++ * and -ERANGE if the address lies outside the set bounds.
++ * If the address was not already in the set, 0 is returned.
++ */
++ int (*addip_kernel) (struct ip_set *set,
++ const struct sk_buff * skb,
++ u_int32_t flags,
++ ip_set_ip_t *ip);
++
++ /* remove IP from set (userspace: ipset -D set --entry x)
++ * Return -EEXIST if the address is NOT in the set,
++ * and -ERANGE if the address lies outside the set bounds.
++ * If the address really was in the set, 0 is returned.
++ */
++ int (*delip) (struct ip_set *set,
++ const void *data, size_t size,
++ ip_set_ip_t *ip);
++
++ /* remove IP from set (kernel: iptables ... -j SET --entry x)
++ * Return -EEXIST if the address is NOT in the set,
++ * and -ERANGE if the address lies outside the set bounds.
++ * If the address really was in the set, 0 is returned.
++ */
++ int (*delip_kernel) (struct ip_set *set,
++ const struct sk_buff * skb,
++ u_int32_t flags,
++ ip_set_ip_t *ip);
++
++ /* new set creation - allocated type specific items
++ */
++ int (*create) (struct ip_set *set,
++ const void *data, size_t size);
++
++ /* retry the operation after successfully tweaking the set
++ */
++ int (*retry) (struct ip_set *set);
++
++ /* set destruction - free type specific items
++ * There is no return value.
++ * Can be called only when child sets are destroyed.
++ */
++ void (*destroy) (struct ip_set *set);
++
++ /* set flushing - reset all bits in the set, or something similar.
++ * There is no return value.
++ */
++ void (*flush) (struct ip_set *set);
++
++ /* Listing: size needed for header
++ */
++ size_t header_size;
++
++ /* Listing: Get the header
++ *
++ * Fill in the information in "data".
++ * This function is always run after list_header_size() under a
++ * writelock on the set. Therefor is the length of "data" always
++ * correct.
++ */
++ void (*list_header) (const struct ip_set *set,
++ void *data);
++
++ /* Listing: Get the size for the set members
++ */
++ int (*list_members_size) (const struct ip_set *set);
++
++ /* Listing: Get the set members
++ *
++ * Fill in the information in "data".
++ * This function is always run after list_member_size() under a
++ * writelock on the set. Therefor is the length of "data" always
++ * correct.
++ */
++ void (*list_members) (const struct ip_set *set,
++ void *data);
++
++ char typename[IP_SET_MAXNAMELEN];
++ char typecode;
++ int protocol_version;
++
++ /* Set this to THIS_MODULE if you are a module, otherwise NULL */
++ struct module *me;
++};
++
++extern int ip_set_register_set_type(struct ip_set_type *set_type);
++extern void ip_set_unregister_set_type(struct ip_set_type *set_type);
++
++/* A generic ipset */
++struct ip_set {
++ char name[IP_SET_MAXNAMELEN]; /* the name of the set */
++ rwlock_t lock; /* lock for concurrency control */
++ ip_set_id_t id; /* set id for swapping */
++ ip_set_id_t binding; /* default binding for the set */
++ atomic_t ref; /* in kernel and in hash references */
++ struct ip_set_type *type; /* the set types */
++ void *data; /* pooltype specific data */
++};
++
++/* Structure to bind set elements to sets */
++struct ip_set_hash {
++ struct list_head list; /* list of clashing entries in hash */
++ ip_set_ip_t ip; /* ip from set */
++ ip_set_id_t id; /* set id */
++ ip_set_id_t binding; /* set we bind the element to */
++};
++
++/* register and unregister set references */
++extern ip_set_id_t ip_set_get_byname(const char name[IP_SET_MAXNAMELEN]);
++extern ip_set_id_t ip_set_get_byindex(ip_set_id_t id);
++extern void ip_set_put(ip_set_id_t id);
++
++/* API for iptables set match, and SET target */
++extern void ip_set_addip_kernel(ip_set_id_t id,
++ const struct sk_buff *skb,
++ const u_int32_t *flags);
++extern void ip_set_delip_kernel(ip_set_id_t id,
++ const struct sk_buff *skb,
++ const u_int32_t *flags);
++extern int ip_set_testip_kernel(ip_set_id_t id,
++ const struct sk_buff *skb,
++ const u_int32_t *flags);
++
++#endif /* __KERNEL__ */
++
++#endif /*_IP_SET_H*/
+diff -Nur linux-2.6.16/include/linux/netfilter_ipv4/ip_set_iphash.h linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_iphash.h
+--- linux-2.6.16/include/linux/netfilter_ipv4/ip_set_iphash.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_iphash.h 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,30 @@
++#ifndef __IP_SET_IPHASH_H
++#define __IP_SET_IPHASH_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++#define SETTYPE_NAME "iphash"
++#define MAX_RANGE 0x0000FFFF
++
++struct ip_set_iphash {
++ ip_set_ip_t *members; /* the iphash proper */
++ uint32_t initval; /* initval for jhash_1word */
++ uint32_t prime; /* prime for double hashing */
++ uint32_t hashsize; /* hash size */
++ uint16_t probes; /* max number of probes */
++ uint16_t resize; /* resize factor in percent */
++ ip_set_ip_t netmask; /* netmask */
++};
++
++struct ip_set_req_iphash_create {
++ uint32_t hashsize;
++ uint16_t probes;
++ uint16_t resize;
++ ip_set_ip_t netmask;
++};
++
++struct ip_set_req_iphash {
++ ip_set_ip_t ip;
++};
++
++#endif /* __IP_SET_IPHASH_H */
+diff -Nur linux-2.6.16/include/linux/netfilter_ipv4/ip_set_ipmap.h linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_ipmap.h
+--- linux-2.6.16/include/linux/netfilter_ipv4/ip_set_ipmap.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_ipmap.h 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,56 @@
++#ifndef __IP_SET_IPMAP_H
++#define __IP_SET_IPMAP_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++#define SETTYPE_NAME "ipmap"
++#define MAX_RANGE 0x0000FFFF
++
++struct ip_set_ipmap {
++ void *members; /* the ipmap proper */
++ ip_set_ip_t first_ip; /* host byte order, included in range */
++ ip_set_ip_t last_ip; /* host byte order, included in range */
++ ip_set_ip_t netmask; /* subnet netmask */
++ ip_set_ip_t sizeid; /* size of set in IPs */
++ u_int16_t hosts; /* number of hosts in a subnet */
++};
++
++struct ip_set_req_ipmap_create {
++ ip_set_ip_t from;
++ ip_set_ip_t to;
++ ip_set_ip_t netmask;
++};
++
++struct ip_set_req_ipmap {
++ ip_set_ip_t ip;
++};
++
++unsigned int
++mask_to_bits(ip_set_ip_t mask)
++{
++ unsigned int bits = 32;
++ ip_set_ip_t maskaddr;
++
++ if (mask == 0xFFFFFFFF)
++ return bits;
++
++ maskaddr = 0xFFFFFFFE;
++ while (--bits >= 0 && maskaddr != mask)
++ maskaddr <<= 1;
++
++ return bits;
++}
++
++ip_set_ip_t
++range_to_mask(ip_set_ip_t from, ip_set_ip_t to, unsigned int *bits)
++{
++ ip_set_ip_t mask = 0xFFFFFFFE;
++
++ *bits = 32;
++ while (--(*bits) >= 0 && mask && (to & mask) != from)
++ mask <<= 1;
++
++ return mask;
++}
++
++#endif /* __IP_SET_IPMAP_H */
+diff -Nur linux-2.6.16/include/linux/netfilter_ipv4/ip_set_iptree.h linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_iptree.h
+--- linux-2.6.16/include/linux/netfilter_ipv4/ip_set_iptree.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_iptree.h 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,39 @@
++#ifndef __IP_SET_IPTREE_H
++#define __IP_SET_IPTREE_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++#define SETTYPE_NAME "iptree"
++#define MAX_RANGE 0x0000FFFF
++
++struct ip_set_iptreed {
++ unsigned long expires[255]; /* x.x.x.ADDR */
++};
++
++struct ip_set_iptreec {
++ struct ip_set_iptreed *tree[255]; /* x.x.ADDR.* */
++};
++
++struct ip_set_iptreeb {
++ struct ip_set_iptreec *tree[255]; /* x.ADDR.*.* */
++};
++
++struct ip_set_iptree {
++ unsigned int timeout;
++ unsigned int gc_interval;
++#ifdef __KERNEL__
++ struct timer_list gc;
++ struct ip_set_iptreeb *tree[255]; /* ADDR.*.*.* */
++#endif
++};
++
++struct ip_set_req_iptree_create {
++ unsigned int timeout;
++};
++
++struct ip_set_req_iptree {
++ ip_set_ip_t ip;
++ unsigned int timeout;
++};
++
++#endif /* __IP_SET_IPTREE_H */
+diff -Nur linux-2.6.16/include/linux/netfilter_ipv4/ip_set_jhash.h linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_jhash.h
+--- linux-2.6.16/include/linux/netfilter_ipv4/ip_set_jhash.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_jhash.h 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,148 @@
++#ifndef _LINUX_IPSET_JHASH_H
++#define _LINUX_IPSET_JHASH_H
++
++/* This is a copy of linux/jhash.h but the types u32/u8 are changed
++ * to __u32/__u8 so that the header file can be included into
++ * userspace code as well. Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
++ */
++
++/* jhash.h: Jenkins hash support.
++ *
++ * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
++ *
++ * http://burtleburtle.net/bob/hash/
++ *
++ * These are the credits from Bob's sources:
++ *
++ * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
++ * hash(), hash2(), hash3, and mix() are externally useful functions.
++ * Routines to test the hash are included if SELF_TEST is defined.
++ * You can use this free for any purpose. It has no warranty.
++ *
++ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
++ *
++ * I've modified Bob's hash to be useful in the Linux kernel, and
++ * any bugs present are surely my fault. -DaveM
++ */
++
++/* NOTE: Arguments are modified. */
++#define __jhash_mix(a, b, c) \
++{ \
++ a -= b; a -= c; a ^= (c>>13); \
++ b -= c; b -= a; b ^= (a<<8); \
++ c -= a; c -= b; c ^= (b>>13); \
++ a -= b; a -= c; a ^= (c>>12); \
++ b -= c; b -= a; b ^= (a<<16); \
++ c -= a; c -= b; c ^= (b>>5); \
++ a -= b; a -= c; a ^= (c>>3); \
++ b -= c; b -= a; b ^= (a<<10); \
++ c -= a; c -= b; c ^= (b>>15); \
++}
++
++/* The golden ration: an arbitrary value */
++#define JHASH_GOLDEN_RATIO 0x9e3779b9
++
++/* The most generic version, hashes an arbitrary sequence
++ * of bytes. No alignment or length assumptions are made about
++ * the input key.
++ */
++static inline __u32 jhash(void *key, __u32 length, __u32 initval)
++{
++ __u32 a, b, c, len;
++ __u8 *k = key;
++
++ len = length;
++ a = b = JHASH_GOLDEN_RATIO;
++ c = initval;
++
++ while (len >= 12) {
++ a += (k[0] +((__u32)k[1]<<8) +((__u32)k[2]<<16) +((__u32)k[3]<<24));
++ b += (k[4] +((__u32)k[5]<<8) +((__u32)k[6]<<16) +((__u32)k[7]<<24));
++ c += (k[8] +((__u32)k[9]<<8) +((__u32)k[10]<<16)+((__u32)k[11]<<24));
++
++ __jhash_mix(a,b,c);
++
++ k += 12;
++ len -= 12;
++ }
++
++ c += length;
++ switch (len) {
++ case 11: c += ((__u32)k[10]<<24);
++ case 10: c += ((__u32)k[9]<<16);
++ case 9 : c += ((__u32)k[8]<<8);
++ case 8 : b += ((__u32)k[7]<<24);
++ case 7 : b += ((__u32)k[6]<<16);
++ case 6 : b += ((__u32)k[5]<<8);
++ case 5 : b += k[4];
++ case 4 : a += ((__u32)k[3]<<24);
++ case 3 : a += ((__u32)k[2]<<16);
++ case 2 : a += ((__u32)k[1]<<8);
++ case 1 : a += k[0];
++ };
++
++ __jhash_mix(a,b,c);
++
++ return c;
++}
++
++/* A special optimized version that handles 1 or more of __u32s.
++ * The length parameter here is the number of __u32s in the key.
++ */
++static inline __u32 jhash2(__u32 *k, __u32 length, __u32 initval)
++{
++ __u32 a, b, c, len;
++
++ a = b = JHASH_GOLDEN_RATIO;
++ c = initval;
++ len = length;
++
++ while (len >= 3) {
++ a += k[0];
++ b += k[1];
++ c += k[2];
++ __jhash_mix(a, b, c);
++ k += 3; len -= 3;
++ }
++
++ c += length * 4;
++
++ switch (len) {
++ case 2 : b += k[1];
++ case 1 : a += k[0];
++ };
++
++ __jhash_mix(a,b,c);
++
++ return c;
++}
++
++
++/* A special ultra-optimized versions that knows they are hashing exactly
++ * 3, 2 or 1 word(s).
++ *
++ * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
++ * done at the end is not done here.
++ */
++static inline __u32 jhash_3words(__u32 a, __u32 b, __u32 c, __u32 initval)
++{
++ a += JHASH_GOLDEN_RATIO;
++ b += JHASH_GOLDEN_RATIO;
++ c += initval;
++
++ __jhash_mix(a, b, c);
++
++ return c;
++}
++
++static inline __u32 jhash_2words(__u32 a, __u32 b, __u32 initval)
++{
++ return jhash_3words(a, b, 0, initval);
++}
++
++static inline __u32 jhash_1word(__u32 a, __u32 initval)
++{
++ return jhash_3words(a, 0, 0, initval);
++}
++
++#endif /* _LINUX_IPSET_JHASH_H */
+diff -Nur linux-2.6.16/include/linux/netfilter_ipv4/ip_set_macipmap.h linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_macipmap.h
+--- linux-2.6.16/include/linux/netfilter_ipv4/ip_set_macipmap.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_macipmap.h 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,38 @@
++#ifndef __IP_SET_MACIPMAP_H
++#define __IP_SET_MACIPMAP_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++#define SETTYPE_NAME "macipmap"
++#define MAX_RANGE 0x0000FFFF
++
++/* general flags */
++#define IPSET_MACIP_MATCHUNSET 1
++
++/* per ip flags */
++#define IPSET_MACIP_ISSET 1
++
++struct ip_set_macipmap {
++ void *members; /* the macipmap proper */
++ ip_set_ip_t first_ip; /* host byte order, included in range */
++ ip_set_ip_t last_ip; /* host byte order, included in range */
++ u_int32_t flags;
++};
++
++struct ip_set_req_macipmap_create {
++ ip_set_ip_t from;
++ ip_set_ip_t to;
++ u_int32_t flags;
++};
++
++struct ip_set_req_macipmap {
++ ip_set_ip_t ip;
++ unsigned char ethernet[ETH_ALEN];
++};
++
++struct ip_set_macip {
++ unsigned short flags;
++ unsigned char ethernet[ETH_ALEN];
++};
++
++#endif /* __IP_SET_MACIPMAP_H */
+diff -Nur linux-2.6.16/include/linux/netfilter_ipv4/ip_set_malloc.h linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_malloc.h
+--- linux-2.6.16/include/linux/netfilter_ipv4/ip_set_malloc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_malloc.h 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,42 @@
++#ifndef _IP_SET_MALLOC_H
++#define _IP_SET_MALLOC_H
++
++#ifdef __KERNEL__
++
++/* Memory allocation and deallocation */
++static size_t max_malloc_size = 0;
++
++static inline void init_max_malloc_size(void)
++{
++#define CACHE(x) max_malloc_size = x;
++#include <linux/kmalloc_sizes.h>
++#undef CACHE
++}
++
++static inline void * ip_set_malloc_atomic(size_t bytes)
++{
++ if (bytes > max_malloc_size)
++ return __vmalloc(bytes, GFP_ATOMIC, PAGE_KERNEL);
++ else
++ return kmalloc(bytes, GFP_ATOMIC);
++}
++
++static inline void * ip_set_malloc(size_t bytes)
++{
++ if (bytes > max_malloc_size)
++ return vmalloc(bytes);
++ else
++ return kmalloc(bytes, GFP_KERNEL);
++}
++
++static inline void ip_set_free(void * data, size_t bytes)
++{
++ if (bytes > max_malloc_size)
++ vfree(data);
++ else
++ kfree(data);
++}
++
++#endif /* __KERNEL__ */
++
++#endif /*_IP_SET_MALLOC_H*/
+diff -Nur linux-2.6.16/include/linux/netfilter_ipv4/ip_set_nethash.h linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_nethash.h
+--- linux-2.6.16/include/linux/netfilter_ipv4/ip_set_nethash.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_nethash.h 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,55 @@
++#ifndef __IP_SET_NETHASH_H
++#define __IP_SET_NETHASH_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++#define SETTYPE_NAME "nethash"
++#define MAX_RANGE 0x0000FFFF
++
++struct ip_set_nethash {
++ ip_set_ip_t *members; /* the nethash proper */
++ uint32_t initval; /* initval for jhash_1word */
++ uint32_t prime; /* prime for double hashing */
++ uint32_t hashsize; /* hash size */
++ uint16_t probes; /* max number of probes */
++ uint16_t resize; /* resize factor in percent */
++ unsigned char cidr[30]; /* CIDR sizes */
++};
++
++struct ip_set_req_nethash_create {
++ uint32_t hashsize;
++ uint16_t probes;
++ uint16_t resize;
++};
++
++struct ip_set_req_nethash {
++ ip_set_ip_t ip;
++ unsigned char cidr;
++};
++
++static unsigned char shifts[] = {255, 253, 249, 241, 225, 193, 129, 1};
++
++static inline ip_set_ip_t
++pack(ip_set_ip_t ip, unsigned char cidr)
++{
++ ip_set_ip_t addr, *paddr = &addr;
++ unsigned char n, t, *a;
++
++ addr = htonl(ip & (0xFFFFFFFF << (32 - (cidr))));
++#ifdef __KERNEL__
++ DP("ip:%u.%u.%u.%u/%u", NIPQUAD(addr), cidr);
++#endif
++ n = cidr / 8;
++ t = cidr % 8;
++ a = &((unsigned char *)paddr)[n];
++ *a = *a /(1 << (8 - t)) + shifts[t];
++#ifdef __KERNEL__
++ DP("n: %u, t: %u, a: %u", n, t, *a);
++ DP("ip:%u.%u.%u.%u/%u, %u.%u.%u.%u",
++ HIPQUAD(ip), cidr, NIPQUAD(addr));
++#endif
++
++ return ntohl(addr);
++}
++
++#endif /* __IP_SET_NETHASH_H */
+diff -Nur linux-2.6.16/include/linux/netfilter_ipv4/ip_set_portmap.h linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_portmap.h
+--- linux-2.6.16/include/linux/netfilter_ipv4/ip_set_portmap.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_portmap.h 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,25 @@
++#ifndef __IP_SET_PORTMAP_H
++#define __IP_SET_PORTMAP_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++#define SETTYPE_NAME "portmap"
++#define MAX_RANGE 0x0000FFFF
++#define INVALID_PORT (MAX_RANGE + 1)
++
++struct ip_set_portmap {
++ void *members; /* the portmap proper */
++ ip_set_ip_t first_port; /* host byte order, included in range */
++ ip_set_ip_t last_port; /* host byte order, included in range */
++};
++
++struct ip_set_req_portmap_create {
++ ip_set_ip_t from;
++ ip_set_ip_t to;
++};
++
++struct ip_set_req_portmap {
++ ip_set_ip_t port;
++};
++
++#endif /* __IP_SET_PORTMAP_H */
+diff -Nur linux-2.6.16/include/linux/netfilter_ipv4/ip_set_prime.h linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_prime.h
+--- linux-2.6.16/include/linux/netfilter_ipv4/ip_set_prime.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/netfilter_ipv4/ip_set_prime.h 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,34 @@
++#ifndef __IP_SET_PRIME_H
++#define __IP_SET_PRIME_H
++
++static inline unsigned make_prime_bound(unsigned nr)
++{
++ unsigned long long nr64 = nr;
++ unsigned long long x = 1;
++ nr = 1;
++ while (x <= nr64) { x <<= 2; nr <<= 1; }
++ return nr;
++}
++
++static inline int make_prime_check(unsigned nr)
++{
++ unsigned x = 3;
++ unsigned b = make_prime_bound(nr);
++ while (x <= b) {
++ if (0 == (nr % x)) return 0;
++ x += 2;
++ }
++ return 1;
++}
++
++static unsigned make_prime(unsigned nr)
++{
++ if (0 == (nr & 1)) nr--;
++ while (nr > 1) {
++ if (make_prime_check(nr)) return nr;
++ nr -= 2;
++ }
++ return 2;
++}
++
++#endif /* __IP_SET_PRIME_H */
+diff -Nur linux-2.6.16/include/linux/netfilter_ipv4/ipt_set.h linux-2.6.16-owrt/include/linux/netfilter_ipv4/ipt_set.h
+--- linux-2.6.16/include/linux/netfilter_ipv4/ipt_set.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/netfilter_ipv4/ipt_set.h 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,21 @@
++#ifndef _IPT_SET_H
++#define _IPT_SET_H
++
++#include <linux/netfilter_ipv4/ip_set.h>
++
++struct ipt_set_info {
++ ip_set_id_t index;
++ u_int32_t flags[IP_SET_MAX_BINDINGS + 1];
++};
++
++/* match info */
++struct ipt_set_info_match {
++ struct ipt_set_info match_set;
++};
++
++struct ipt_set_info_target {
++ struct ipt_set_info add_set;
++ struct ipt_set_info del_set;
++};
++
++#endif /*_IPT_SET_H*/
+diff -Nur linux-2.6.16/net/ipv4/netfilter/ip_set.c linux-2.6.16-owrt/net/ipv4/netfilter/ip_set.c
+--- linux-2.6.16/net/ipv4/netfilter/ip_set.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/netfilter/ip_set.c 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,1989 @@
++/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
++ * Patrick Schaaf <bof@bof.de>
++ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module for IP set management */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/kmod.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/random.h>
++#include <linux/jhash.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <asm/semaphore.h>
++#include <linux/spinlock.h>
++#include <linux/vmalloc.h>
++
++#define ASSERT_READ_LOCK(x) /* dont use that */
++#define ASSERT_WRITE_LOCK(x)
++#include <linux/netfilter_ipv4/listhelp.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++
++static struct list_head set_type_list; /* all registered sets */
++static struct ip_set **ip_set_list; /* all individual sets */
++static DEFINE_RWLOCK(ip_set_lock); /* protects the lists and the hash */
++static DECLARE_MUTEX(ip_set_app_mutex); /* serializes user access */
++static ip_set_id_t ip_set_max = CONFIG_IP_NF_SET_MAX;
++static ip_set_id_t ip_set_bindings_hash_size = CONFIG_IP_NF_SET_HASHSIZE;
++static struct list_head *ip_set_hash; /* hash of bindings */
++static unsigned int ip_set_hash_random; /* random seed */
++
++/*
++ * Sets are identified either by the index in ip_set_list or by id.
++ * The id never changes and is used to find a key in the hash.
++ * The index may change by swapping and used at all other places
++ * (set/SET netfilter modules, binding value, etc.)
++ *
++ * Userspace requests are serialized by ip_set_mutex and sets can
++ * be deleted only from userspace. Therefore ip_set_list locking
++ * must obey the following rules:
++ *
++ * - kernel requests: read and write locking mandatory
++ * - user requests: read locking optional, write locking mandatory
++ */
++
++static inline void
++__ip_set_get(ip_set_id_t index)
++{
++ atomic_inc(&ip_set_list[index]->ref);
++}
++
++static inline void
++__ip_set_put(ip_set_id_t index)
++{
++ atomic_dec(&ip_set_list[index]->ref);
++}
++
++/*
++ * Binding routines
++ */
++
++static inline int
++ip_hash_cmp(const struct ip_set_hash *set_hash,
++ ip_set_id_t id, ip_set_ip_t ip)
++{
++ return set_hash->id == id && set_hash->ip == ip;
++}
++
++static ip_set_id_t
++ip_set_find_in_hash(ip_set_id_t id, ip_set_ip_t ip)
++{
++ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
++ % ip_set_bindings_hash_size;
++ struct ip_set_hash *set_hash;
++
++ ASSERT_READ_LOCK(&ip_set_lock);
++ IP_SET_ASSERT(ip_set_list[id]);
++ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
++
++ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp,
++ struct ip_set_hash *, id, ip);
++
++ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
++ HIPQUAD(ip),
++ set_hash != NULL ? ip_set_list[set_hash->binding]->name : "");
++
++ return (set_hash != NULL ? set_hash->binding : IP_SET_INVALID_ID);
++}
++
++static inline void
++__set_hash_del(struct ip_set_hash *set_hash)
++{
++ ASSERT_WRITE_LOCK(&ip_set_lock);
++ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
++
++ __ip_set_put(set_hash->binding);
++ list_del(&set_hash->list);
++ kfree(set_hash);
++}
++
++static int
++ip_set_hash_del(ip_set_id_t id, ip_set_ip_t ip)
++{
++ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
++ % ip_set_bindings_hash_size;
++ struct ip_set_hash *set_hash;
++
++ IP_SET_ASSERT(ip_set_list[id]);
++ DP("set: %s, ip: %u.%u.%u.%u", ip_set_list[id]->name, HIPQUAD(ip));
++ write_lock_bh(&ip_set_lock);
++ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp,
++ struct ip_set_hash *, id, ip);
++ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
++ HIPQUAD(ip),
++ set_hash != NULL ? ip_set_list[set_hash->binding]->name : "");
++
++ if (set_hash != NULL)
++ __set_hash_del(set_hash);
++ write_unlock_bh(&ip_set_lock);
++ return 0;
++}
++
++static int
++ip_set_hash_add(ip_set_id_t id, ip_set_ip_t ip, ip_set_id_t binding)
++{
++ u_int32_t key = jhash_2words(id, ip, ip_set_hash_random)
++ % ip_set_bindings_hash_size;
++ struct ip_set_hash *set_hash;
++ int ret = 0;
++
++ IP_SET_ASSERT(ip_set_list[id]);
++ IP_SET_ASSERT(ip_set_list[binding]);
++ DP("set: %s, ip: %u.%u.%u.%u, binding: %s", ip_set_list[id]->name,
++ HIPQUAD(ip), ip_set_list[binding]->name);
++ write_lock_bh(&ip_set_lock);
++ set_hash = LIST_FIND(&ip_set_hash[key], ip_hash_cmp,
++ struct ip_set_hash *, id, ip);
++ if (!set_hash) {
++ set_hash = kmalloc(sizeof(struct ip_set_hash), GFP_KERNEL);
++ if (!set_hash) {
++ ret = -ENOMEM;
++ goto unlock;
++ }
++ INIT_LIST_HEAD(&set_hash->list);
++ set_hash->id = id;
++ set_hash->ip = ip;
++ list_add(&ip_set_hash[key], &set_hash->list);
++ } else {
++ IP_SET_ASSERT(ip_set_list[set_hash->binding]);
++ DP("overwrite binding: %s",
++ ip_set_list[set_hash->binding]->name);
++ __ip_set_put(set_hash->binding);
++ }
++ set_hash->binding = binding;
++ __ip_set_get(set_hash->binding);
++ unlock:
++ write_unlock_bh(&ip_set_lock);
++ return ret;
++}
++
++#define FOREACH_HASH_DO(fn, args...) \
++({ \
++ ip_set_id_t __key; \
++ struct ip_set_hash *__set_hash; \
++ \
++ for (__key = 0; __key < ip_set_bindings_hash_size; __key++) { \
++ list_for_each_entry(__set_hash, &ip_set_hash[__key], list) \
++ fn(__set_hash , ## args); \
++ } \
++})
++
++#define FOREACH_HASH_RW_DO(fn, args...) \
++({ \
++ ip_set_id_t __key; \
++ struct ip_set_hash *__set_hash, *__n; \
++ \
++ ASSERT_WRITE_LOCK(&ip_set_lock); \
++ for (__key = 0; __key < ip_set_bindings_hash_size; __key++) { \
++ list_for_each_entry_safe(__set_hash, __n, &ip_set_hash[__key], list)\
++ fn(__set_hash , ## args); \
++ } \
++})
++
++/* Add, del and test set entries from kernel */
++
++#define follow_bindings(index, set, ip) \
++((index = ip_set_find_in_hash((set)->id, ip)) != IP_SET_INVALID_ID \
++ || (index = (set)->binding) != IP_SET_INVALID_ID)
++
++int
++ip_set_testip_kernel(ip_set_id_t index,
++ const struct sk_buff *skb,
++ const u_int32_t *flags)
++{
++ struct ip_set *set;
++ ip_set_ip_t ip;
++ int res, i = 0;
++
++ IP_SET_ASSERT(flags[i]);
++ read_lock_bh(&ip_set_lock);
++ do {
++ set = ip_set_list[index];
++ IP_SET_ASSERT(set);
++ DP("set %s, index %u", set->name, index);
++ read_lock_bh(&set->lock);
++ res = set->type->testip_kernel(set, skb, flags[i], &ip);
++ read_unlock_bh(&set->lock);
++ } while (res > 0
++ && flags[++i]
++ && follow_bindings(index, set, ip));
++ read_unlock_bh(&ip_set_lock);
++
++ return res;
++}
++
++void
++ip_set_addip_kernel(ip_set_id_t index,
++ const struct sk_buff *skb,
++ const u_int32_t *flags)
++{
++ struct ip_set *set;
++ ip_set_ip_t ip;
++ int res, i= 0;
++
++ IP_SET_ASSERT(flags[i]);
++ retry:
++ read_lock_bh(&ip_set_lock);
++ do {
++ set = ip_set_list[index];
++ IP_SET_ASSERT(set);
++ DP("set %s, index %u", set->name, index);
++ write_lock_bh(&set->lock);
++ res = set->type->addip_kernel(set, skb, flags[i], &ip);
++ write_unlock_bh(&set->lock);
++ } while ((res == 0 || res == -EEXIST)
++ && flags[++i]
++ && follow_bindings(index, set, ip));
++ read_unlock_bh(&ip_set_lock);
++
++ if (res == -EAGAIN
++ && set->type->retry
++ && (res = set->type->retry(set)) == 0)
++ goto retry;
++}
++
++void
++ip_set_delip_kernel(ip_set_id_t index,
++ const struct sk_buff *skb,
++ const u_int32_t *flags)
++{
++ struct ip_set *set;
++ ip_set_ip_t ip;
++ int res, i = 0;
++
++ IP_SET_ASSERT(flags[i]);
++ read_lock_bh(&ip_set_lock);
++ do {
++ set = ip_set_list[index];
++ IP_SET_ASSERT(set);
++ DP("set %s, index %u", set->name, index);
++ write_lock_bh(&set->lock);
++ res = set->type->delip_kernel(set, skb, flags[i], &ip);
++ write_unlock_bh(&set->lock);
++ } while ((res == 0 || res == -EEXIST)
++ && flags[++i]
++ && follow_bindings(index, set, ip));
++ read_unlock_bh(&ip_set_lock);
++}
++
++/* Register and deregister settype */
++
++static inline int
++set_type_equal(const struct ip_set_type *set_type, const char *str2)
++{
++ return !strncmp(set_type->typename, str2, IP_SET_MAXNAMELEN - 1);
++}
++
++static inline struct ip_set_type *
++find_set_type(const char *name)
++{
++ return LIST_FIND(&set_type_list,
++ set_type_equal,
++ struct ip_set_type *,
++ name);
++}
++
++int
++ip_set_register_set_type(struct ip_set_type *set_type)
++{
++ int ret = 0;
++
++ if (set_type->protocol_version != IP_SET_PROTOCOL_VERSION) {
++ ip_set_printk("'%s' uses wrong protocol version %u (want %u)",
++ set_type->typename,
++ set_type->protocol_version,
++ IP_SET_PROTOCOL_VERSION);
++ return -EINVAL;
++ }
++
++ write_lock_bh(&ip_set_lock);
++ if (find_set_type(set_type->typename)) {
++ /* Duplicate! */
++ ip_set_printk("'%s' already registered!",
++ set_type->typename);
++ ret = -EINVAL;
++ goto unlock;
++ }
++ if (!try_module_get(THIS_MODULE)) {
++ ret = -EFAULT;
++ goto unlock;
++ }
++ list_append(&set_type_list, set_type);
++ DP("'%s' registered.", set_type->typename);
++ unlock:
++ write_unlock_bh(&ip_set_lock);
++ return ret;
++}
++
++void
++ip_set_unregister_set_type(struct ip_set_type *set_type)
++{
++ write_lock_bh(&ip_set_lock);
++ if (!find_set_type(set_type->typename)) {
++ ip_set_printk("'%s' not registered?",
++ set_type->typename);
++ goto unlock;
++ }
++ LIST_DELETE(&set_type_list, set_type);
++ module_put(THIS_MODULE);
++ DP("'%s' unregistered.", set_type->typename);
++ unlock:
++ write_unlock_bh(&ip_set_lock);
++
++}
++
++/*
++ * Userspace routines
++ */
++
++/*
++ * Find set by name, reference it once. The reference makes sure the
++ * thing pointed to, does not go away under our feet. Drop the reference
++ * later, using ip_set_put().
++ */
++ip_set_id_t
++ip_set_get_byname(const char *name)
++{
++ ip_set_id_t i, index = IP_SET_INVALID_ID;
++
++ down(&ip_set_app_mutex);
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] != NULL
++ && strcmp(ip_set_list[i]->name, name) == 0) {
++ __ip_set_get(i);
++ index = i;
++ break;
++ }
++ }
++ up(&ip_set_app_mutex);
++ return index;
++}
++
++/*
++ * Find set by index, reference it once. The reference makes sure the
++ * thing pointed to, does not go away under our feet. Drop the reference
++ * later, using ip_set_put().
++ */
++ip_set_id_t
++ip_set_get_byindex(ip_set_id_t index)
++{
++ down(&ip_set_app_mutex);
++
++ if (index >= ip_set_max)
++ return IP_SET_INVALID_ID;
++
++ if (ip_set_list[index])
++ __ip_set_get(index);
++ else
++ index = IP_SET_INVALID_ID;
++
++ up(&ip_set_app_mutex);
++ return index;
++}
++
++/*
++ * If the given set pointer points to a valid set, decrement
++ * reference count by 1. The caller shall not assume the index
++ * to be valid, after calling this function.
++ */
++void ip_set_put(ip_set_id_t index)
++{
++ down(&ip_set_app_mutex);
++ if (ip_set_list[index])
++ __ip_set_put(index);
++ up(&ip_set_app_mutex);
++}
++
++/* Find a set by name or index */
++static ip_set_id_t
++ip_set_find_byname(const char *name)
++{
++ ip_set_id_t i, index = IP_SET_INVALID_ID;
++
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] != NULL
++ && strcmp(ip_set_list[i]->name, name) == 0) {
++ index = i;
++ break;
++ }
++ }
++ return index;
++}
++
++static ip_set_id_t
++ip_set_find_byindex(ip_set_id_t index)
++{
++ if (index >= ip_set_max || ip_set_list[index] == NULL)
++ index = IP_SET_INVALID_ID;
++
++ return index;
++}
++
++/*
++ * Add, del, test, bind and unbind
++ */
++
++static inline int
++__ip_set_testip(struct ip_set *set,
++ const void *data,
++ size_t size,
++ ip_set_ip_t *ip)
++{
++ int res;
++
++ read_lock_bh(&set->lock);
++ res = set->type->testip(set, data, size, ip);
++ read_unlock_bh(&set->lock);
++
++ return res;
++}
++
++static int
++__ip_set_addip(ip_set_id_t index,
++ const void *data,
++ size_t size)
++{
++ struct ip_set *set = ip_set_list[index];
++ ip_set_ip_t ip;
++ int res;
++
++ IP_SET_ASSERT(set);
++ do {
++ write_lock_bh(&set->lock);
++ res = set->type->addip(set, data, size, &ip);
++ write_unlock_bh(&set->lock);
++ } while (res == -EAGAIN
++ && set->type->retry
++ && (res = set->type->retry(set)) == 0);
++
++ return res;
++}
++
++static int
++ip_set_addip(ip_set_id_t index,
++ const void *data,
++ size_t size)
++{
++
++ return __ip_set_addip(index,
++ data + sizeof(struct ip_set_req_adt),
++ size - sizeof(struct ip_set_req_adt));
++}
++
++static int
++ip_set_delip(ip_set_id_t index,
++ const void *data,
++ size_t size)
++{
++ struct ip_set *set = ip_set_list[index];
++ ip_set_ip_t ip;
++ int res;
++
++ IP_SET_ASSERT(set);
++ write_lock_bh(&set->lock);
++ res = set->type->delip(set,
++ data + sizeof(struct ip_set_req_adt),
++ size - sizeof(struct ip_set_req_adt),
++ &ip);
++ write_unlock_bh(&set->lock);
++
++ return res;
++}
++
++static int
++ip_set_testip(ip_set_id_t index,
++ const void *data,
++ size_t size)
++{
++ struct ip_set *set = ip_set_list[index];
++ ip_set_ip_t ip;
++ int res;
++
++ IP_SET_ASSERT(set);
++ res = __ip_set_testip(set,
++ data + sizeof(struct ip_set_req_adt),
++ size - sizeof(struct ip_set_req_adt),
++ &ip);
++
++ return (res > 0 ? -EEXIST : res);
++}
++
++static int
++ip_set_bindip(ip_set_id_t index,
++ const void *data,
++ size_t size)
++{
++ struct ip_set *set = ip_set_list[index];
++ struct ip_set_req_bind *req_bind;
++ ip_set_id_t binding;
++ ip_set_ip_t ip;
++ int res;
++
++ IP_SET_ASSERT(set);
++ if (size < sizeof(struct ip_set_req_bind))
++ return -EINVAL;
++
++ req_bind = (struct ip_set_req_bind *) data;
++ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
++
++ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
++ /* Default binding of a set */
++ char *binding_name;
++
++ if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN)
++ return -EINVAL;
++
++ binding_name = (char *)(data + sizeof(struct ip_set_req_bind));
++ binding_name[IP_SET_MAXNAMELEN - 1] = '\0';
++
++ binding = ip_set_find_byname(binding_name);
++ if (binding == IP_SET_INVALID_ID)
++ return -ENOENT;
++
++ write_lock_bh(&ip_set_lock);
++ /* Sets as binding values are referenced */
++ if (set->binding != IP_SET_INVALID_ID)
++ __ip_set_put(set->binding);
++ set->binding = binding;
++ __ip_set_get(set->binding);
++ write_unlock_bh(&ip_set_lock);
++
++ return 0;
++ }
++ binding = ip_set_find_byname(req_bind->binding);
++ if (binding == IP_SET_INVALID_ID)
++ return -ENOENT;
++
++ res = __ip_set_testip(set,
++ data + sizeof(struct ip_set_req_bind),
++ size - sizeof(struct ip_set_req_bind),
++ &ip);
++ DP("set %s, ip: %u.%u.%u.%u, binding %s",
++ set->name, HIPQUAD(ip), ip_set_list[binding]->name);
++
++ if (res >= 0)
++ res = ip_set_hash_add(set->id, ip, binding);
++
++ return res;
++}
++
++#define FOREACH_SET_DO(fn, args...) \
++({ \
++ ip_set_id_t __i; \
++ struct ip_set *__set; \
++ \
++ for (__i = 0; __i < ip_set_max; __i++) { \
++ __set = ip_set_list[__i]; \
++ if (__set != NULL) \
++ fn(__set , ##args); \
++ } \
++})
++
++static inline void
++__set_hash_del_byid(struct ip_set_hash *set_hash, ip_set_id_t id)
++{
++ if (set_hash->id == id)
++ __set_hash_del(set_hash);
++}
++
++static inline void
++__unbind_default(struct ip_set *set)
++{
++ if (set->binding != IP_SET_INVALID_ID) {
++ /* Sets as binding values are referenced */
++ __ip_set_put(set->binding);
++ set->binding = IP_SET_INVALID_ID;
++ }
++}
++
++static int
++ip_set_unbindip(ip_set_id_t index,
++ const void *data,
++ size_t size)
++{
++ struct ip_set *set;
++ struct ip_set_req_bind *req_bind;
++ ip_set_ip_t ip;
++ int res;
++
++ DP("");
++ if (size < sizeof(struct ip_set_req_bind))
++ return -EINVAL;
++
++ req_bind = (struct ip_set_req_bind *) data;
++ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
++
++ DP("%u %s", index, req_bind->binding);
++ if (index == IP_SET_INVALID_ID) {
++ /* unbind :all: */
++ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
++ /* Default binding of sets */
++ write_lock_bh(&ip_set_lock);
++ FOREACH_SET_DO(__unbind_default);
++ write_unlock_bh(&ip_set_lock);
++ return 0;
++ } else if (strcmp(req_bind->binding, IPSET_TOKEN_ALL) == 0) {
++ /* Flush all bindings of all sets*/
++ write_lock_bh(&ip_set_lock);
++ FOREACH_HASH_RW_DO(__set_hash_del);
++ write_unlock_bh(&ip_set_lock);
++ return 0;
++ }
++ DP("unreachable reached!");
++ return -EINVAL;
++ }
++
++ set = ip_set_list[index];
++ IP_SET_ASSERT(set);
++ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
++ /* Default binding of set */
++ ip_set_id_t binding = ip_set_find_byindex(set->binding);
++
++ if (binding == IP_SET_INVALID_ID)
++ return -ENOENT;
++
++ write_lock_bh(&ip_set_lock);
++ /* Sets in hash values are referenced */
++ __ip_set_put(set->binding);
++ set->binding = IP_SET_INVALID_ID;
++ write_unlock_bh(&ip_set_lock);
++
++ return 0;
++ } else if (strcmp(req_bind->binding, IPSET_TOKEN_ALL) == 0) {
++ /* Flush all bindings */
++
++ write_lock_bh(&ip_set_lock);
++ FOREACH_HASH_RW_DO(__set_hash_del_byid, set->id);
++ write_unlock_bh(&ip_set_lock);
++ return 0;
++ }
++
++ res = __ip_set_testip(set,
++ data + sizeof(struct ip_set_req_bind),
++ size - sizeof(struct ip_set_req_bind),
++ &ip);
++
++ DP("set %s, ip: %u.%u.%u.%u", set->name, HIPQUAD(ip));
++ if (res >= 0)
++ res = ip_set_hash_del(set->id, ip);
++
++ return res;
++}
++
++static int
++ip_set_testbind(ip_set_id_t index,
++ const void *data,
++ size_t size)
++{
++ struct ip_set *set = ip_set_list[index];
++ struct ip_set_req_bind *req_bind;
++ ip_set_id_t binding;
++ ip_set_ip_t ip;
++ int res;
++
++ IP_SET_ASSERT(set);
++ if (size < sizeof(struct ip_set_req_bind))
++ return -EINVAL;
++
++ req_bind = (struct ip_set_req_bind *) data;
++ req_bind->binding[IP_SET_MAXNAMELEN - 1] = '\0';
++
++ if (strcmp(req_bind->binding, IPSET_TOKEN_DEFAULT) == 0) {
++ /* Default binding of set */
++ char *binding_name;
++
++ if (size != sizeof(struct ip_set_req_bind) + IP_SET_MAXNAMELEN)
++ return -EINVAL;
++
++ binding_name = (char *)(data + sizeof(struct ip_set_req_bind));
++ binding_name[IP_SET_MAXNAMELEN - 1] = '\0';
++
++ binding = ip_set_find_byname(binding_name);
++ if (binding == IP_SET_INVALID_ID)
++ return -ENOENT;
++
++ res = (set->binding == binding) ? -EEXIST : 0;
++
++ return res;
++ }
++ binding = ip_set_find_byname(req_bind->binding);
++ if (binding == IP_SET_INVALID_ID)
++ return -ENOENT;
++
++
++ res = __ip_set_testip(set,
++ data + sizeof(struct ip_set_req_bind),
++ size - sizeof(struct ip_set_req_bind),
++ &ip);
++ DP("set %s, ip: %u.%u.%u.%u, binding %s",
++ set->name, HIPQUAD(ip), ip_set_list[binding]->name);
++
++ if (res >= 0)
++ res = (ip_set_find_in_hash(set->id, ip) == binding)
++ ? -EEXIST : 0;
++
++ return res;
++}
++
++static struct ip_set_type *
++find_set_type_rlock(const char *typename)
++{
++ struct ip_set_type *type;
++
++ read_lock_bh(&ip_set_lock);
++ type = find_set_type(typename);
++ if (type == NULL)
++ read_unlock_bh(&ip_set_lock);
++
++ return type;
++}
++
++static int
++find_free_id(const char *name,
++ ip_set_id_t *index,
++ ip_set_id_t *id)
++{
++ ip_set_id_t i;
++
++ *id = IP_SET_INVALID_ID;
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] == NULL) {
++ if (*id == IP_SET_INVALID_ID)
++ *id = *index = i;
++ } else if (strcmp(name, ip_set_list[i]->name) == 0)
++ /* Name clash */
++ return -EEXIST;
++ }
++ if (*id == IP_SET_INVALID_ID)
++ /* No free slot remained */
++ return -ERANGE;
++ /* Check that index is usable as id (swapping) */
++ check:
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] != NULL
++ && ip_set_list[i]->id == *id) {
++ *id = i;
++ goto check;
++ }
++ }
++ return 0;
++}
++
++/*
++ * Create a set
++ */
++static int
++ip_set_create(const char *name,
++ const char *typename,
++ ip_set_id_t restore,
++ const void *data,
++ size_t size)
++{
++ struct ip_set *set;
++ ip_set_id_t index, id;
++ int res = 0;
++
++ DP("setname: %s, typename: %s, id: %u", name, typename, restore);
++ /*
++ * First, and without any locks, allocate and initialize
++ * a normal base set structure.
++ */
++ set = kmalloc(sizeof(struct ip_set), GFP_KERNEL);
++ if (!set)
++ return -ENOMEM;
++ set->lock = RW_LOCK_UNLOCKED;
++ strncpy(set->name, name, IP_SET_MAXNAMELEN);
++ set->binding = IP_SET_INVALID_ID;
++ atomic_set(&set->ref, 0);
++
++ /*
++ * Next, take the &ip_set_lock, check that we know the type,
++ * and take a reference on the type, to make sure it
++ * stays available while constructing our new set.
++ *
++ * After referencing the type, we drop the &ip_set_lock,
++ * and let the new set construction run without locks.
++ */
++ set->type = find_set_type_rlock(typename);
++ if (set->type == NULL) {
++ /* Try loading the module */
++ char modulename[IP_SET_MAXNAMELEN + strlen("ip_set_") + 1];
++ strcpy(modulename, "ip_set_");
++ strcat(modulename, typename);
++ DP("try to load %s", modulename);
++ request_module(modulename);
++ set->type = find_set_type_rlock(typename);
++ }
++ if (set->type == NULL) {
++ ip_set_printk("no set type '%s', set '%s' not created",
++ typename, name);
++ res = -ENOENT;
++ goto out;
++ }
++ if (!try_module_get(set->type->me)) {
++ read_unlock_bh(&ip_set_lock);
++ res = -EFAULT;
++ goto out;
++ }
++ read_unlock_bh(&ip_set_lock);
++
++ /*
++ * Without holding any locks, create private part.
++ */
++ res = set->type->create(set, data, size);
++ if (res != 0)
++ goto put_out;
++
++ /* BTW, res==0 here. */
++
++ /*
++ * Here, we have a valid, constructed set. &ip_set_lock again,
++ * find free id/index and check that it is not already in
++ * ip_set_list.
++ */
++ write_lock_bh(&ip_set_lock);
++ if ((res = find_free_id(set->name, &index, &id)) != 0) {
++ DP("no free id!");
++ goto cleanup;
++ }
++
++ /* Make sure restore gets the same index */
++ if (restore != IP_SET_INVALID_ID && index != restore) {
++ DP("Can't restore, sets are screwed up");
++ res = -ERANGE;
++ goto cleanup;
++ }
++
++ /*
++ * Finally! Add our shiny new set to the list, and be done.
++ */
++ DP("create: '%s' created with index %u, id %u!", set->name, index, id);
++ set->id = id;
++ ip_set_list[index] = set;
++ write_unlock_bh(&ip_set_lock);
++ return res;
++
++ cleanup:
++ write_unlock_bh(&ip_set_lock);
++ set->type->destroy(set);
++ put_out:
++ module_put(set->type->me);
++ out:
++ kfree(set);
++ return res;
++}
++
++/*
++ * Destroy a given existing set
++ */
++static void
++ip_set_destroy_set(ip_set_id_t index)
++{
++ struct ip_set *set = ip_set_list[index];
++
++ IP_SET_ASSERT(set);
++ DP("set: %s", set->name);
++ write_lock_bh(&ip_set_lock);
++ FOREACH_HASH_RW_DO(__set_hash_del_byid, set->id);
++ if (set->binding != IP_SET_INVALID_ID)
++ __ip_set_put(set->binding);
++ ip_set_list[index] = NULL;
++ write_unlock_bh(&ip_set_lock);
++
++ /* Must call it without holding any lock */
++ set->type->destroy(set);
++ module_put(set->type->me);
++ kfree(set);
++}
++
++/*
++ * Destroy a set - or all sets
++ * Sets must not be referenced/used.
++ */
++static int
++ip_set_destroy(ip_set_id_t index)
++{
++ ip_set_id_t i;
++
++ /* ref modification always protected by the mutex */
++ if (index != IP_SET_INVALID_ID) {
++ if (atomic_read(&ip_set_list[index]->ref))
++ return -EBUSY;
++ ip_set_destroy_set(index);
++ } else {
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] != NULL
++ && (atomic_read(&ip_set_list[i]->ref)))
++ return -EBUSY;
++ }
++
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] != NULL)
++ ip_set_destroy_set(i);
++ }
++ }
++ return 0;
++}
++
++static void
++ip_set_flush_set(struct ip_set *set)
++{
++ DP("set: %s %u", set->name, set->id);
++
++ write_lock_bh(&set->lock);
++ set->type->flush(set);
++ write_unlock_bh(&set->lock);
++}
++
++/*
++ * Flush data in a set - or in all sets
++ */
++static int
++ip_set_flush(ip_set_id_t index)
++{
++ if (index != IP_SET_INVALID_ID) {
++ IP_SET_ASSERT(ip_set_list[index]);
++ ip_set_flush_set(ip_set_list[index]);
++ } else
++ FOREACH_SET_DO(ip_set_flush_set);
++
++ return 0;
++}
++
++/* Rename a set */
++static int
++ip_set_rename(ip_set_id_t index, const char *name)
++{
++ struct ip_set *set = ip_set_list[index];
++ ip_set_id_t i;
++ int res = 0;
++
++ DP("set: %s to %s", set->name, name);
++ write_lock_bh(&ip_set_lock);
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] != NULL
++ && strncmp(ip_set_list[i]->name,
++ name,
++ IP_SET_MAXNAMELEN - 1) == 0) {
++ res = -EEXIST;
++ goto unlock;
++ }
++ }
++ strncpy(set->name, name, IP_SET_MAXNAMELEN);
++ unlock:
++ write_unlock_bh(&ip_set_lock);
++ return res;
++}
++
++/*
++ * Swap two sets so that name/index points to the other.
++ * References are also swapped.
++ */
++static int
++ip_set_swap(ip_set_id_t from_index, ip_set_id_t to_index)
++{
++ struct ip_set *from = ip_set_list[from_index];
++ struct ip_set *to = ip_set_list[to_index];
++ char from_name[IP_SET_MAXNAMELEN];
++ u_int32_t from_ref;
++
++ DP("set: %s to %s", from->name, to->name);
++ /* Type can't be changed. Artifical restriction. */
++ if (from->type->typecode != to->type->typecode)
++ return -ENOEXEC;
++
++ /* No magic here: ref munging protected by the mutex */
++ write_lock_bh(&ip_set_lock);
++ strncpy(from_name, from->name, IP_SET_MAXNAMELEN);
++ from_ref = atomic_read(&from->ref);
++
++ strncpy(from->name, to->name, IP_SET_MAXNAMELEN);
++ atomic_set(&from->ref, atomic_read(&to->ref));
++ strncpy(to->name, from_name, IP_SET_MAXNAMELEN);
++ atomic_set(&to->ref, from_ref);
++
++ ip_set_list[from_index] = to;
++ ip_set_list[to_index] = from;
++
++ write_unlock_bh(&ip_set_lock);
++ return 0;
++}
++
++/*
++ * List set data
++ */
++
++static inline void
++__set_hash_bindings_size_list(struct ip_set_hash *set_hash,
++ ip_set_id_t id, size_t *size)
++{
++ if (set_hash->id == id)
++ *size += sizeof(struct ip_set_hash_list);
++}
++
++static inline void
++__set_hash_bindings_size_save(struct ip_set_hash *set_hash,
++ ip_set_id_t id, size_t *size)
++{
++ if (set_hash->id == id)
++ *size += sizeof(struct ip_set_hash_save);
++}
++
++static inline void
++__set_hash_bindings(struct ip_set_hash *set_hash,
++ ip_set_id_t id, void *data, int *used)
++{
++ if (set_hash->id == id) {
++ struct ip_set_hash_list *hash_list =
++ (struct ip_set_hash_list *)(data + *used);
++
++ hash_list->ip = set_hash->ip;
++ hash_list->binding = set_hash->binding;
++ *used += sizeof(struct ip_set_hash_list);
++ }
++}
++
++static int ip_set_list_set(ip_set_id_t index,
++ void *data,
++ int *used,
++ int len)
++{
++ struct ip_set *set = ip_set_list[index];
++ struct ip_set_list *set_list;
++
++ /* Pointer to our header */
++ set_list = (struct ip_set_list *) (data + *used);
++
++ DP("set: %s, used: %d %p %p", set->name, *used, data, data + *used);
++
++ /* Get and ensure header size */
++ if (*used + sizeof(struct ip_set_list) > len)
++ goto not_enough_mem;
++ *used += sizeof(struct ip_set_list);
++
++ read_lock_bh(&set->lock);
++ /* Get and ensure set specific header size */
++ set_list->header_size = set->type->header_size;
++ if (*used + set_list->header_size > len)
++ goto unlock_set;
++
++ /* Fill in the header */
++ set_list->index = index;
++ set_list->binding = set->binding;
++ set_list->ref = atomic_read(&set->ref);
++
++ /* Fill in set spefific header data */
++ set->type->list_header(set, data + *used);
++ *used += set_list->header_size;
++
++ /* Get and ensure set specific members size */
++ set_list->members_size = set->type->list_members_size(set);
++ if (*used + set_list->members_size > len)
++ goto unlock_set;
++
++ /* Fill in set spefific members data */
++ set->type->list_members(set, data + *used);
++ *used += set_list->members_size;
++ read_unlock_bh(&set->lock);
++
++ /* Bindings */
++
++ /* Get and ensure set specific bindings size */
++ set_list->bindings_size = 0;
++ FOREACH_HASH_DO(__set_hash_bindings_size_list,
++ set->id, &set_list->bindings_size);
++ if (*used + set_list->bindings_size > len)
++ goto not_enough_mem;
++
++ /* Fill in set spefific bindings data */
++ FOREACH_HASH_DO(__set_hash_bindings, set->id, data, used);
++
++ return 0;
++
++ unlock_set:
++ read_unlock_bh(&set->lock);
++ not_enough_mem:
++ DP("not enough mem, try again");
++ return -EAGAIN;
++}
++
++/*
++ * Save sets
++ */
++static int ip_set_save_set(ip_set_id_t index,
++ void *data,
++ int *used,
++ int len)
++{
++ struct ip_set *set;
++ struct ip_set_save *set_save;
++
++ /* Pointer to our header */
++ set_save = (struct ip_set_save *) (data + *used);
++
++ /* Get and ensure header size */
++ if (*used + sizeof(struct ip_set_save) > len)
++ goto not_enough_mem;
++ *used += sizeof(struct ip_set_save);
++
++ set = ip_set_list[index];
++ DP("set: %s, used: %u(%u) %p %p", set->name, *used, len,
++ data, data + *used);
++
++ read_lock_bh(&set->lock);
++ /* Get and ensure set specific header size */
++ set_save->header_size = set->type->header_size;
++ if (*used + set_save->header_size > len)
++ goto unlock_set;
++
++ /* Fill in the header */
++ set_save->index = index;
++ set_save->binding = set->binding;
++
++ /* Fill in set spefific header data */
++ set->type->list_header(set, data + *used);
++ *used += set_save->header_size;
++
++ DP("set header filled: %s, used: %u %p %p", set->name, *used,
++ data, data + *used);
++ /* Get and ensure set specific members size */
++ set_save->members_size = set->type->list_members_size(set);
++ if (*used + set_save->members_size > len)
++ goto unlock_set;
++
++ /* Fill in set spefific members data */
++ set->type->list_members(set, data + *used);
++ *used += set_save->members_size;
++ read_unlock_bh(&set->lock);
++ DP("set members filled: %s, used: %u %p %p", set->name, *used,
++ data, data + *used);
++ return 0;
++
++ unlock_set:
++ read_unlock_bh(&set->lock);
++ not_enough_mem:
++ DP("not enough mem, try again");
++ return -EAGAIN;
++}
++
++static inline void
++__set_hash_save_bindings(struct ip_set_hash *set_hash,
++ ip_set_id_t id,
++ void *data,
++ int *used,
++ int len,
++ int *res)
++{
++ if (*res == 0
++ && (id == IP_SET_INVALID_ID || set_hash->id == id)) {
++ struct ip_set_hash_save *hash_save =
++ (struct ip_set_hash_save *)(data + *used);
++ /* Ensure bindings size */
++ if (*used + sizeof(struct ip_set_hash_save) > len) {
++ *res = -ENOMEM;
++ return;
++ }
++ hash_save->id = set_hash->id;
++ hash_save->ip = set_hash->ip;
++ hash_save->binding = set_hash->binding;
++ *used += sizeof(struct ip_set_hash_save);
++ }
++}
++
++static int ip_set_save_bindings(ip_set_id_t index,
++ void *data,
++ int *used,
++ int len)
++{
++ int res = 0;
++ struct ip_set_save *set_save;
++
++ DP("used %u, len %u", *used, len);
++ /* Get and ensure header size */
++ if (*used + sizeof(struct ip_set_save) > len)
++ return -ENOMEM;
++
++ /* Marker */
++ set_save = (struct ip_set_save *) (data + *used);
++ set_save->index = IP_SET_INVALID_ID;
++ *used += sizeof(struct ip_set_save);
++
++ DP("marker added used %u, len %u", *used, len);
++ /* Fill in bindings data */
++ if (index != IP_SET_INVALID_ID)
++ /* Sets are identified by id in hash */
++ index = ip_set_list[index]->id;
++ FOREACH_HASH_DO(__set_hash_save_bindings, index, data, used, len, &res);
++
++ return res;
++}
++
++/*
++ * Restore sets
++ */
++static int ip_set_restore(void *data,
++ int len)
++{
++ int res = 0;
++ int line = 0, used = 0, members_size;
++ struct ip_set *set;
++ struct ip_set_hash_save *hash_save;
++ struct ip_set_restore *set_restore;
++ ip_set_id_t index;
++
++ /* Loop to restore sets */
++ while (1) {
++ line++;
++
++ DP("%u %u %u", used, sizeof(struct ip_set_restore), len);
++ /* Get and ensure header size */
++ if (used + sizeof(struct ip_set_restore) > len)
++ return line;
++ set_restore = (struct ip_set_restore *) (data + used);
++ used += sizeof(struct ip_set_restore);
++
++ /* Ensure data size */
++ if (used
++ + set_restore->header_size
++ + set_restore->members_size > len)
++ return line;
++
++ /* Check marker */
++ if (set_restore->index == IP_SET_INVALID_ID) {
++ line--;
++ goto bindings;
++ }
++
++ /* Try to create the set */
++ DP("restore %s %s", set_restore->name, set_restore->typename);
++ res = ip_set_create(set_restore->name,
++ set_restore->typename,
++ set_restore->index,
++ data + used,
++ set_restore->header_size);
++
++ if (res != 0)
++ return line;
++ used += set_restore->header_size;
++
++ index = ip_set_find_byindex(set_restore->index);
++ DP("index %u, restore_index %u", index, set_restore->index);
++ if (index != set_restore->index)
++ return line;
++ /* Try to restore members data */
++ set = ip_set_list[index];
++ members_size = 0;
++ DP("members_size %u reqsize %u",
++ set_restore->members_size, set->type->reqsize);
++ while (members_size + set->type->reqsize <=
++ set_restore->members_size) {
++ line++;
++ DP("members: %u, line %u", members_size, line);
++ res = __ip_set_addip(index,
++ data + used + members_size,
++ set->type->reqsize);
++ if (!(res == 0 || res == -EEXIST))
++ return line;
++ members_size += set->type->reqsize;
++ }
++
++ DP("members_size %u %u",
++ set_restore->members_size, members_size);
++ if (members_size != set_restore->members_size)
++ return line++;
++ used += set_restore->members_size;
++ }
++
++ bindings:
++ /* Loop to restore bindings */
++ while (used < len) {
++ line++;
++
++ DP("restore binding, line %u", line);
++ /* Get and ensure size */
++ if (used + sizeof(struct ip_set_hash_save) > len)
++ return line;
++ hash_save = (struct ip_set_hash_save *) (data + used);
++ used += sizeof(struct ip_set_hash_save);
++
++ /* hash_save->id is used to store the index */
++ index = ip_set_find_byindex(hash_save->id);
++ DP("restore binding index %u, id %u, %u -> %u",
++ index, hash_save->id, hash_save->ip, hash_save->binding);
++ if (index != hash_save->id)
++ return line;
++
++ set = ip_set_list[hash_save->id];
++ /* Null valued IP means default binding */
++ if (hash_save->ip)
++ res = ip_set_hash_add(set->id,
++ hash_save->ip,
++ hash_save->binding);
++ else {
++ IP_SET_ASSERT(set->binding == IP_SET_INVALID_ID);
++ write_lock_bh(&ip_set_lock);
++ set->binding = hash_save->binding;
++ __ip_set_get(set->binding);
++ write_unlock_bh(&ip_set_lock);
++ DP("default binding: %u", set->binding);
++ }
++ if (res != 0)
++ return line;
++ }
++ if (used != len)
++ return line;
++
++ return 0;
++}
++
++static int
++ip_set_sockfn_set(struct sock *sk, int optval, void *user, unsigned int len)
++{
++ void *data;
++ int res = 0; /* Assume OK */
++ unsigned *op;
++ struct ip_set_req_adt *req_adt;
++ ip_set_id_t index = IP_SET_INVALID_ID;
++ int (*adtfn)(ip_set_id_t index,
++ const void *data, size_t size);
++ struct fn_table {
++ int (*fn)(ip_set_id_t index,
++ const void *data, size_t size);
++ } adtfn_table[] =
++ { { ip_set_addip }, { ip_set_delip }, { ip_set_testip},
++ { ip_set_bindip}, { ip_set_unbindip }, { ip_set_testbind },
++ };
++
++ DP("optval=%d, user=%p, len=%d", optval, user, len);
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++ if (optval != SO_IP_SET)
++ return -EBADF;
++ if (len <= sizeof(unsigned)) {
++ ip_set_printk("short userdata (want >%zu, got %u)",
++ sizeof(unsigned), len);
++ return -EINVAL;
++ }
++ data = vmalloc(len);
++ if (!data) {
++ DP("out of mem for %u bytes", len);
++ return -ENOMEM;
++ }
++ if (copy_from_user(data, user, len) != 0) {
++ res = -EFAULT;
++ goto done;
++ }
++ if (down_interruptible(&ip_set_app_mutex)) {
++ res = -EINTR;
++ goto done;
++ }
++
++ op = (unsigned *)data;
++ DP("op=%x", *op);
++
++ if (*op < IP_SET_OP_VERSION) {
++ /* Check the version at the beginning of operations */
++ struct ip_set_req_version *req_version =
++ (struct ip_set_req_version *) data;
++ if (req_version->version != IP_SET_PROTOCOL_VERSION) {
++ res = -EPROTO;
++ goto done;
++ }
++ }
++
++ switch (*op) {
++ case IP_SET_OP_CREATE:{
++ struct ip_set_req_create *req_create
++ = (struct ip_set_req_create *) data;
++
++ if (len <= sizeof(struct ip_set_req_create)) {
++ ip_set_printk("short CREATE data (want >%zu, got %u)",
++ sizeof(struct ip_set_req_create), len);
++ res = -EINVAL;
++ goto done;
++ }
++ req_create->name[IP_SET_MAXNAMELEN - 1] = '\0';
++ req_create->typename[IP_SET_MAXNAMELEN - 1] = '\0';
++ res = ip_set_create(req_create->name,
++ req_create->typename,
++ IP_SET_INVALID_ID,
++ data + sizeof(struct ip_set_req_create),
++ len - sizeof(struct ip_set_req_create));
++ goto done;
++ }
++ case IP_SET_OP_DESTROY:{
++ struct ip_set_req_std *req_destroy
++ = (struct ip_set_req_std *) data;
++
++ if (len != sizeof(struct ip_set_req_std)) {
++ ip_set_printk("invalid DESTROY data (want %zu, got %u)",
++ sizeof(struct ip_set_req_std), len);
++ res = -EINVAL;
++ goto done;
++ }
++ if (strcmp(req_destroy->name, IPSET_TOKEN_ALL) == 0) {
++ /* Destroy all sets */
++ index = IP_SET_INVALID_ID;
++ } else {
++ req_destroy->name[IP_SET_MAXNAMELEN - 1] = '\0';
++ index = ip_set_find_byname(req_destroy->name);
++
++ if (index == IP_SET_INVALID_ID) {
++ res = -ENOENT;
++ goto done;
++ }
++ }
++
++ res = ip_set_destroy(index);
++ goto done;
++ }
++ case IP_SET_OP_FLUSH:{
++ struct ip_set_req_std *req_flush =
++ (struct ip_set_req_std *) data;
++
++ if (len != sizeof(struct ip_set_req_std)) {
++ ip_set_printk("invalid FLUSH data (want %zu, got %u)",
++ sizeof(struct ip_set_req_std), len);
++ res = -EINVAL;
++ goto done;
++ }
++ if (strcmp(req_flush->name, IPSET_TOKEN_ALL) == 0) {
++ /* Flush all sets */
++ index = IP_SET_INVALID_ID;
++ } else {
++ req_flush->name[IP_SET_MAXNAMELEN - 1] = '\0';
++ index = ip_set_find_byname(req_flush->name);
++
++ if (index == IP_SET_INVALID_ID) {
++ res = -ENOENT;
++ goto done;
++ }
++ }
++ res = ip_set_flush(index);
++ goto done;
++ }
++ case IP_SET_OP_RENAME:{
++ struct ip_set_req_create *req_rename
++ = (struct ip_set_req_create *) data;
++
++ if (len != sizeof(struct ip_set_req_create)) {
++ ip_set_printk("invalid RENAME data (want %zu, got %u)",
++ sizeof(struct ip_set_req_create), len);
++ res = -EINVAL;
++ goto done;
++ }
++
++ req_rename->name[IP_SET_MAXNAMELEN - 1] = '\0';
++ req_rename->typename[IP_SET_MAXNAMELEN - 1] = '\0';
++
++ index = ip_set_find_byname(req_rename->name);
++ if (index == IP_SET_INVALID_ID) {
++ res = -ENOENT;
++ goto done;
++ }
++ res = ip_set_rename(index, req_rename->typename);
++ goto done;
++ }
++ case IP_SET_OP_SWAP:{
++ struct ip_set_req_create *req_swap
++ = (struct ip_set_req_create *) data;
++ ip_set_id_t to_index;
++
++ if (len != sizeof(struct ip_set_req_create)) {
++ ip_set_printk("invalid SWAP data (want %zu, got %u)",
++ sizeof(struct ip_set_req_create), len);
++ res = -EINVAL;
++ goto done;
++ }
++
++ req_swap->name[IP_SET_MAXNAMELEN - 1] = '\0';
++ req_swap->typename[IP_SET_MAXNAMELEN - 1] = '\0';
++
++ index = ip_set_find_byname(req_swap->name);
++ if (index == IP_SET_INVALID_ID) {
++ res = -ENOENT;
++ goto done;
++ }
++ to_index = ip_set_find_byname(req_swap->typename);
++ if (to_index == IP_SET_INVALID_ID) {
++ res = -ENOENT;
++ goto done;
++ }
++ res = ip_set_swap(index, to_index);
++ goto done;
++ }
++ default:
++ break; /* Set identified by id */
++ }
++
++ /* There we may have add/del/test/bind/unbind/test_bind operations */
++ if (*op < IP_SET_OP_ADD_IP || *op > IP_SET_OP_TEST_BIND_SET) {
++ res = -EBADMSG;
++ goto done;
++ }
++ adtfn = adtfn_table[*op - IP_SET_OP_ADD_IP].fn;
++
++ if (len < sizeof(struct ip_set_req_adt)) {
++ ip_set_printk("short data in adt request (want >=%zu, got %u)",
++ sizeof(struct ip_set_req_adt), len);
++ res = -EINVAL;
++ goto done;
++ }
++ req_adt = (struct ip_set_req_adt *) data;
++
++ /* -U :all: :all:|:default: uses IP_SET_INVALID_ID */
++ if (!(*op == IP_SET_OP_UNBIND_SET
++ && req_adt->index == IP_SET_INVALID_ID)) {
++ index = ip_set_find_byindex(req_adt->index);
++ if (index == IP_SET_INVALID_ID) {
++ res = -ENOENT;
++ goto done;
++ }
++ }
++ res = adtfn(index, data, len);
++
++ done:
++ up(&ip_set_app_mutex);
++ vfree(data);
++ if (res > 0)
++ res = 0;
++ DP("final result %d", res);
++ return res;
++}
++
++static int
++ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len)
++{
++ int res = 0;
++ unsigned *op;
++ ip_set_id_t index = IP_SET_INVALID_ID;
++ void *data;
++ int copylen = *len;
++
++ DP("optval=%d, user=%p, len=%d", optval, user, *len);
++ if (!capable(CAP_NET_ADMIN))
++ return -EPERM;
++ if (optval != SO_IP_SET)
++ return -EBADF;
++ if (*len < sizeof(unsigned)) {
++ ip_set_printk("short userdata (want >=%zu, got %d)",
++ sizeof(unsigned), *len);
++ return -EINVAL;
++ }
++ data = vmalloc(*len);
++ if (!data) {
++ DP("out of mem for %d bytes", *len);
++ return -ENOMEM;
++ }
++ if (copy_from_user(data, user, *len) != 0) {
++ res = -EFAULT;
++ goto done;
++ }
++ if (down_interruptible(&ip_set_app_mutex)) {
++ res = -EINTR;
++ goto done;
++ }
++
++ op = (unsigned *) data;
++ DP("op=%x", *op);
++
++ if (*op < IP_SET_OP_VERSION) {
++ /* Check the version at the beginning of operations */
++ struct ip_set_req_version *req_version =
++ (struct ip_set_req_version *) data;
++ if (req_version->version != IP_SET_PROTOCOL_VERSION) {
++ res = -EPROTO;
++ goto done;
++ }
++ }
++
++ switch (*op) {
++ case IP_SET_OP_VERSION: {
++ struct ip_set_req_version *req_version =
++ (struct ip_set_req_version *) data;
++
++ if (*len != sizeof(struct ip_set_req_version)) {
++ ip_set_printk("invalid VERSION (want %zu, got %d)",
++ sizeof(struct ip_set_req_version),
++ *len);
++ res = -EINVAL;
++ goto done;
++ }
++
++ req_version->version = IP_SET_PROTOCOL_VERSION;
++ res = copy_to_user(user, req_version,
++ sizeof(struct ip_set_req_version));
++ goto done;
++ }
++ case IP_SET_OP_GET_BYNAME: {
++ struct ip_set_req_get_set *req_get
++ = (struct ip_set_req_get_set *) data;
++
++ if (*len != sizeof(struct ip_set_req_get_set)) {
++ ip_set_printk("invalid GET_BYNAME (want %zu, got %d)",
++ sizeof(struct ip_set_req_get_set), *len);
++ res = -EINVAL;
++ goto done;
++ }
++ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
++ index = ip_set_find_byname(req_get->set.name);
++ req_get->set.index = index;
++ goto copy;
++ }
++ case IP_SET_OP_GET_BYINDEX: {
++ struct ip_set_req_get_set *req_get
++ = (struct ip_set_req_get_set *) data;
++
++ if (*len != sizeof(struct ip_set_req_get_set)) {
++ ip_set_printk("invalid GET_BYINDEX (want %zu, got %d)",
++ sizeof(struct ip_set_req_get_set), *len);
++ res = -EINVAL;
++ goto done;
++ }
++ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
++ index = ip_set_find_byindex(req_get->set.index);
++ strncpy(req_get->set.name,
++ index == IP_SET_INVALID_ID ? ""
++ : ip_set_list[index]->name, IP_SET_MAXNAMELEN);
++ goto copy;
++ }
++ case IP_SET_OP_ADT_GET: {
++ struct ip_set_req_adt_get *req_get
++ = (struct ip_set_req_adt_get *) data;
++
++ if (*len != sizeof(struct ip_set_req_adt_get)) {
++ ip_set_printk("invalid ADT_GET (want %zu, got %d)",
++ sizeof(struct ip_set_req_adt_get), *len);
++ res = -EINVAL;
++ goto done;
++ }
++ req_get->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
++ index = ip_set_find_byname(req_get->set.name);
++ if (index != IP_SET_INVALID_ID) {
++ req_get->set.index = index;
++ strncpy(req_get->typename,
++ ip_set_list[index]->type->typename,
++ IP_SET_MAXNAMELEN - 1);
++ } else {
++ res = -ENOENT;
++ goto done;
++ }
++ goto copy;
++ }
++ case IP_SET_OP_MAX_SETS: {
++ struct ip_set_req_max_sets *req_max_sets
++ = (struct ip_set_req_max_sets *) data;
++ ip_set_id_t i;
++
++ if (*len != sizeof(struct ip_set_req_max_sets)) {
++ ip_set_printk("invalid MAX_SETS (want %zu, got %d)",
++ sizeof(struct ip_set_req_max_sets), *len);
++ res = -EINVAL;
++ goto done;
++ }
++
++ if (strcmp(req_max_sets->set.name, IPSET_TOKEN_ALL) == 0) {
++ req_max_sets->set.index = IP_SET_INVALID_ID;
++ } else {
++ req_max_sets->set.name[IP_SET_MAXNAMELEN - 1] = '\0';
++ req_max_sets->set.index =
++ ip_set_find_byname(req_max_sets->set.name);
++ if (req_max_sets->set.index == IP_SET_INVALID_ID) {
++ res = -ENOENT;
++ goto done;
++ }
++ }
++ req_max_sets->max_sets = ip_set_max;
++ req_max_sets->sets = 0;
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] != NULL)
++ req_max_sets->sets++;
++ }
++ goto copy;
++ }
++ case IP_SET_OP_LIST_SIZE:
++ case IP_SET_OP_SAVE_SIZE: {
++ struct ip_set_req_setnames *req_setnames
++ = (struct ip_set_req_setnames *) data;
++ struct ip_set_name_list *name_list;
++ struct ip_set *set;
++ ip_set_id_t i;
++ int used;
++
++ if (*len < sizeof(struct ip_set_req_setnames)) {
++ ip_set_printk("short LIST_SIZE (want >=%zu, got %d)",
++ sizeof(struct ip_set_req_setnames), *len);
++ res = -EINVAL;
++ goto done;
++ }
++
++ req_setnames->size = 0;
++ used = sizeof(struct ip_set_req_setnames);
++ for (i = 0; i < ip_set_max; i++) {
++ if (ip_set_list[i] == NULL)
++ continue;
++ name_list = (struct ip_set_name_list *)
++ (data + used);
++ used += sizeof(struct ip_set_name_list);
++ if (used > copylen) {
++ res = -EAGAIN;
++ goto done;
++ }
++ set = ip_set_list[i];
++ /* Fill in index, name, etc. */
++ name_list->index = i;
++ name_list->id = set->id;
++ strncpy(name_list->name,
++ set->name,
++ IP_SET_MAXNAMELEN - 1);
++ strncpy(name_list->typename,
++ set->type->typename,
++ IP_SET_MAXNAMELEN - 1);
++ DP("filled %s of type %s, index %u\n",
++ name_list->name, name_list->typename,
++ name_list->index);
++ if (!(req_setnames->index == IP_SET_INVALID_ID
++ || req_setnames->index == i))
++ continue;
++ /* Update size */
++ switch (*op) {
++ case IP_SET_OP_LIST_SIZE: {
++ req_setnames->size += sizeof(struct ip_set_list)
++ + set->type->header_size
++ + set->type->list_members_size(set);
++ FOREACH_HASH_DO(__set_hash_bindings_size_list,
++ i, &req_setnames->size);
++ break;
++ }
++ case IP_SET_OP_SAVE_SIZE: {
++ req_setnames->size += sizeof(struct ip_set_save)
++ + set->type->header_size
++ + set->type->list_members_size(set);
++ FOREACH_HASH_DO(__set_hash_bindings_size_save,
++ i, &req_setnames->size);
++ break;
++ }
++ default:
++ break;
++ }
++ }
++ if (copylen != used) {
++ res = -EAGAIN;
++ goto done;
++ }
++ goto copy;
++ }
++ case IP_SET_OP_LIST: {
++ struct ip_set_req_list *req_list
++ = (struct ip_set_req_list *) data;
++ ip_set_id_t i;
++ int used;
++
++ if (*len < sizeof(struct ip_set_req_list)) {
++ ip_set_printk("short LIST (want >=%zu, got %d)",
++ sizeof(struct ip_set_req_list), *len);
++ res = -EINVAL;
++ goto done;
++ }
++ index = req_list->index;
++ if (index != IP_SET_INVALID_ID
++ && ip_set_find_byindex(index) != index) {
++ res = -ENOENT;
++ goto done;
++ }
++ used = 0;
++ if (index == IP_SET_INVALID_ID) {
++ /* List all sets */
++ for (i = 0; i < ip_set_max && res == 0; i++) {
++ if (ip_set_list[i] != NULL)
++ res = ip_set_list_set(i, data, &used, *len);
++ }
++ } else {
++ /* List an individual set */
++ res = ip_set_list_set(index, data, &used, *len);
++ }
++ if (res != 0)
++ goto done;
++ else if (copylen != used) {
++ res = -EAGAIN;
++ goto done;
++ }
++ goto copy;
++ }
++ case IP_SET_OP_SAVE: {
++ struct ip_set_req_list *req_save
++ = (struct ip_set_req_list *) data;
++ ip_set_id_t i;
++ int used;
++
++ if (*len < sizeof(struct ip_set_req_list)) {
++ ip_set_printk("short SAVE (want >=%zu, got %d)",
++ sizeof(struct ip_set_req_list), *len);
++ res = -EINVAL;
++ goto done;
++ }
++ index = req_save->index;
++ if (index != IP_SET_INVALID_ID
++ && ip_set_find_byindex(index) != index) {
++ res = -ENOENT;
++ goto done;
++ }
++ used = 0;
++ if (index == IP_SET_INVALID_ID) {
++ /* Save all sets */
++ for (i = 0; i < ip_set_max && res == 0; i++) {
++ if (ip_set_list[i] != NULL)
++ res = ip_set_save_set(i, data, &used, *len);
++ }
++ } else {
++ /* Save an individual set */
++ res = ip_set_save_set(index, data, &used, *len);
++ }
++ if (res == 0)
++ res = ip_set_save_bindings(index, data, &used, *len);
++
++ if (res != 0)
++ goto done;
++ else if (copylen != used) {
++ res = -EAGAIN;
++ goto done;
++ }
++ goto copy;
++ }
++ case IP_SET_OP_RESTORE: {
++ struct ip_set_req_setnames *req_restore
++ = (struct ip_set_req_setnames *) data;
++ int line;
++
++ if (*len < sizeof(struct ip_set_req_setnames)
++ || *len != req_restore->size) {
++ ip_set_printk("invalid RESTORE (want =%zu, got %d)",
++ req_restore->size, *len);
++ res = -EINVAL;
++ goto done;
++ }
++ line = ip_set_restore(data + sizeof(struct ip_set_req_setnames),
++ req_restore->size - sizeof(struct ip_set_req_setnames));
++ DP("ip_set_restore: %u", line);
++ if (line != 0) {
++ res = -EAGAIN;
++ req_restore->size = line;
++ copylen = sizeof(struct ip_set_req_setnames);
++ goto copy;
++ }
++ goto done;
++ }
++ default:
++ res = -EBADMSG;
++ goto done;
++ } /* end of switch(op) */
++
++ copy:
++ DP("set %s, copylen %u", index != IP_SET_INVALID_ID
++ && ip_set_list[index]
++ ? ip_set_list[index]->name
++ : ":all:", copylen);
++ if (res == 0)
++ res = copy_to_user(user, data, copylen);
++ else
++ copy_to_user(user, data, copylen);
++
++ done:
++ up(&ip_set_app_mutex);
++ vfree(data);
++ if (res > 0)
++ res = 0;
++ DP("final result %d", res);
++ return res;
++}
++
++static struct nf_sockopt_ops so_set = {
++ .pf = PF_INET,
++ .set_optmin = SO_IP_SET,
++ .set_optmax = SO_IP_SET + 1,
++ .set = &ip_set_sockfn_set,
++ .get_optmin = SO_IP_SET,
++ .get_optmax = SO_IP_SET + 1,
++ .get = &ip_set_sockfn_get,
++ .use = 0
++};
++
++static int max_sets, hash_size;
++module_param(max_sets, int, 0600);
++MODULE_PARM_DESC(max_sets, "maximal number of sets");
++module_param(hash_size, int, 0600);
++MODULE_PARM_DESC(hash_size, "hash size for bindings");
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("module implementing core IP set support");
++
++static int __init init(void)
++{
++ int res;
++ ip_set_id_t i;
++
++ get_random_bytes(&ip_set_hash_random, 4);
++ if (max_sets)
++ ip_set_max = max_sets;
++ ip_set_list = vmalloc(sizeof(struct ip_set *) * ip_set_max);
++ if (!ip_set_list) {
++ printk(KERN_ERR "Unable to create ip_set_list\n");
++ return -ENOMEM;
++ }
++ memset(ip_set_list, 0, sizeof(struct ip_set *) * ip_set_max);
++ if (hash_size)
++ ip_set_bindings_hash_size = hash_size;
++ ip_set_hash = vmalloc(sizeof(struct list_head) * ip_set_bindings_hash_size);
++ if (!ip_set_hash) {
++ printk(KERN_ERR "Unable to create ip_set_hash\n");
++ vfree(ip_set_list);
++ return -ENOMEM;
++ }
++ for (i = 0; i < ip_set_bindings_hash_size; i++)
++ INIT_LIST_HEAD(&ip_set_hash[i]);
++
++ INIT_LIST_HEAD(&set_type_list);
++
++ res = nf_register_sockopt(&so_set);
++ if (res != 0) {
++ ip_set_printk("SO_SET registry failed: %d", res);
++ vfree(ip_set_list);
++ vfree(ip_set_hash);
++ return res;
++ }
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ /* There can't be any existing set or binding */
++ nf_unregister_sockopt(&so_set);
++ vfree(ip_set_list);
++ vfree(ip_set_hash);
++ DP("these are the famous last words");
++}
++
++EXPORT_SYMBOL(ip_set_register_set_type);
++EXPORT_SYMBOL(ip_set_unregister_set_type);
++
++EXPORT_SYMBOL(ip_set_get_byname);
++EXPORT_SYMBOL(ip_set_get_byindex);
++EXPORT_SYMBOL(ip_set_put);
++
++EXPORT_SYMBOL(ip_set_addip_kernel);
++EXPORT_SYMBOL(ip_set_delip_kernel);
++EXPORT_SYMBOL(ip_set_testip_kernel);
++
++module_init(init);
++module_exit(fini);
+diff -Nur linux-2.6.16/net/ipv4/netfilter/ip_set_iphash.c linux-2.6.16-owrt/net/ipv4/netfilter/ip_set_iphash.c
+--- linux-2.6.16/net/ipv4/netfilter/ip_set_iphash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/netfilter/ip_set_iphash.c 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,379 @@
++/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module implementing an ip hash set */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <linux/spinlock.h>
++#include <linux/vmalloc.h>
++#include <linux/random.h>
++
++#include <net/ip.h>
++
++#include <linux/netfilter_ipv4/ip_set_malloc.h>
++#include <linux/netfilter_ipv4/ip_set_iphash.h>
++#include <linux/netfilter_ipv4/ip_set_jhash.h>
++#include <linux/netfilter_ipv4/ip_set_prime.h>
++
++static inline __u32
++jhash_ip(const struct ip_set_iphash *map, ip_set_ip_t ip)
++{
++ return jhash_1word(ip, map->initval);
++}
++
++static inline __u32
++randhash_ip(const struct ip_set_iphash *map, ip_set_ip_t ip)
++{
++ return (1 + ip % map->prime);
++}
++
++static inline __u32
++hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++ __u32 jhash, randhash, id;
++ u_int16_t i;
++
++ *hash_ip = ip & map->netmask;
++ jhash = jhash_ip(map, *hash_ip);
++ randhash = randhash_ip(map, *hash_ip);
++ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u, %u.%u.%u.%u",
++ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip), HIPQUAD(map->netmask));
++
++ for (i = 0; i < map->probes; i++) {
++ id = (jhash + i * randhash) % map->hashsize;
++ DP("hash key: %u", id);
++ if (map->members[id] == *hash_ip)
++ return id;
++ /* No shortcut at testing - there can be deleted
++ * entries. */
++ }
++ return UINT_MAX;
++}
++
++static inline int
++__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ return (hash_id(set, ip, hash_ip) != UINT_MAX);
++}
++
++static int
++testip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_iphash *req =
++ (struct ip_set_req_iphash *) data;
++
++ if (size != sizeof(struct ip_set_req_iphash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iphash),
++ size);
++ return -EINVAL;
++ }
++ return __testip(set, req->ip, hash_ip);
++}
++
++static int
++testip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __testip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++static inline int
++__addip(struct ip_set_iphash *map, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ __u32 jhash, randhash, probe;
++ u_int16_t i;
++
++ *hash_ip = ip & map->netmask;
++ jhash = jhash_ip(map, *hash_ip);
++ randhash = randhash_ip(map, *hash_ip);
++
++ for (i = 0; i < map->probes; i++) {
++ probe = (jhash + i * randhash) % map->hashsize;
++ if (map->members[probe] == *hash_ip)
++ return -EEXIST;
++ if (!map->members[probe]) {
++ map->members[probe] = *hash_ip;
++ return 0;
++ }
++ }
++ /* Trigger rehashing */
++ return -EAGAIN;
++}
++
++static int
++addip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_iphash *req =
++ (struct ip_set_req_iphash *) data;
++
++ if (size != sizeof(struct ip_set_req_iphash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iphash),
++ size);
++ return -EINVAL;
++ }
++ return __addip((struct ip_set_iphash *) set->data, req->ip, hash_ip);
++}
++
++static int
++addip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __addip((struct ip_set_iphash *) set->data,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++static int retry(struct ip_set *set)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++ ip_set_ip_t hash_ip, *members;
++ u_int32_t i, hashsize;
++ unsigned newbytes;
++ int res;
++ struct ip_set_iphash tmp = {
++ .hashsize = map->hashsize,
++ .probes = map->probes,
++ .resize = map->resize,
++ .netmask = map->netmask,
++ };
++
++ if (map->resize == 0)
++ return -ERANGE;
++
++ again:
++ res = 0;
++
++ /* Calculate new parameters */
++ get_random_bytes(&tmp.initval, 4);
++ hashsize = tmp.hashsize + (tmp.hashsize * map->resize)/100;
++ if (hashsize == tmp.hashsize)
++ hashsize++;
++ tmp.prime = make_prime(hashsize);
++
++ ip_set_printk("rehashing of set %s triggered: "
++ "hashsize grows from %u to %u",
++ set->name, tmp.hashsize, hashsize);
++ tmp.hashsize = hashsize;
++
++ newbytes = hashsize * sizeof(ip_set_ip_t);
++ tmp.members = ip_set_malloc_atomic(newbytes);
++ if (!tmp.members) {
++ DP("out of memory for %d bytes", newbytes);
++ return -ENOMEM;
++ }
++ memset(tmp.members, 0, newbytes);
++
++ write_lock_bh(&set->lock);
++ map = (struct ip_set_iphash *) set->data; /* Play safe */
++ for (i = 0; i < map->hashsize && res == 0; i++) {
++ if (map->members[i])
++ res = __addip(&tmp, map->members[i], &hash_ip);
++ }
++ if (res) {
++ /* Failure, try again */
++ write_unlock_bh(&set->lock);
++ ip_set_free(tmp.members, newbytes);
++ goto again;
++ }
++
++ /* Success at resizing! */
++ members = map->members;
++ hashsize = map->hashsize;
++
++ map->initval = tmp.initval;
++ map->prime = tmp.prime;
++ map->hashsize = tmp.hashsize;
++ map->members = tmp.members;
++ write_unlock_bh(&set->lock);
++
++ ip_set_free(members, hashsize * sizeof(ip_set_ip_t));
++
++ return 0;
++}
++
++static inline int
++__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++ ip_set_ip_t id = hash_id(set, ip, hash_ip);
++
++ if (id == UINT_MAX)
++ return -EEXIST;
++
++ map->members[id] = 0;
++ return 0;
++}
++
++static int
++delip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_iphash *req =
++ (struct ip_set_req_iphash *) data;
++
++ if (size != sizeof(struct ip_set_req_iphash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iphash),
++ size);
++ return -EINVAL;
++ }
++ return __delip(set, req->ip, hash_ip);
++}
++
++static int
++delip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __delip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++static int create(struct ip_set *set, const void *data, size_t size)
++{
++ unsigned newbytes;
++ struct ip_set_req_iphash_create *req =
++ (struct ip_set_req_iphash_create *) data;
++ struct ip_set_iphash *map;
++
++ if (size != sizeof(struct ip_set_req_iphash_create)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iphash_create),
++ size);
++ return -EINVAL;
++ }
++
++ if (req->hashsize < 1) {
++ ip_set_printk("hashsize too small");
++ return -ENOEXEC;
++ }
++
++ map = kmalloc(sizeof(struct ip_set_iphash), GFP_KERNEL);
++ if (!map) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_iphash));
++ return -ENOMEM;
++ }
++ get_random_bytes(&map->initval, 4);
++ map->prime = make_prime(req->hashsize);
++ map->hashsize = req->hashsize;
++ map->probes = req->probes;
++ map->resize = req->resize;
++ map->netmask = req->netmask;
++ newbytes = map->hashsize * sizeof(ip_set_ip_t);
++ map->members = ip_set_malloc(newbytes);
++ if (!map->members) {
++ DP("out of memory for %d bytes", newbytes);
++ kfree(map);
++ return -ENOMEM;
++ }
++ memset(map->members, 0, newbytes);
++
++ set->data = map;
++ return 0;
++}
++
++static void destroy(struct ip_set *set)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++
++ ip_set_free(map->members, map->hashsize * sizeof(ip_set_ip_t));
++ kfree(map);
++
++ set->data = NULL;
++}
++
++static void flush(struct ip_set *set)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++ memset(map->members, 0, map->hashsize * sizeof(ip_set_ip_t));
++}
++
++static void list_header(const struct ip_set *set, void *data)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++ struct ip_set_req_iphash_create *header =
++ (struct ip_set_req_iphash_create *) data;
++
++ header->hashsize = map->hashsize;
++ header->probes = map->probes;
++ header->resize = map->resize;
++ header->netmask = map->netmask;
++}
++
++static int list_members_size(const struct ip_set *set)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++
++ return (map->hashsize * sizeof(ip_set_ip_t));
++}
++
++static void list_members(const struct ip_set *set, void *data)
++{
++ struct ip_set_iphash *map = (struct ip_set_iphash *) set->data;
++ int bytes = map->hashsize * sizeof(ip_set_ip_t);
++
++ memcpy(data, map->members, bytes);
++}
++
++static struct ip_set_type ip_set_iphash = {
++ .typename = SETTYPE_NAME,
++ .typecode = IPSET_TYPE_IP,
++ .protocol_version = IP_SET_PROTOCOL_VERSION,
++ .create = &create,
++ .destroy = &destroy,
++ .flush = &flush,
++ .reqsize = sizeof(struct ip_set_req_iphash),
++ .addip = &addip,
++ .addip_kernel = &addip_kernel,
++ .retry = &retry,
++ .delip = &delip,
++ .delip_kernel = &delip_kernel,
++ .testip = &testip,
++ .testip_kernel = &testip_kernel,
++ .header_size = sizeof(struct ip_set_req_iphash_create),
++ .list_header = &list_header,
++ .list_members_size = &list_members_size,
++ .list_members = &list_members,
++ .me = THIS_MODULE,
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("iphash type of IP sets");
++
++static int __init init(void)
++{
++ init_max_malloc_size();
++ return ip_set_register_set_type(&ip_set_iphash);
++}
++
++static void __exit fini(void)
++{
++ /* FIXME: possible race with ip_set_create() */
++ ip_set_unregister_set_type(&ip_set_iphash);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur linux-2.6.16/net/ipv4/netfilter/ip_set_ipmap.c linux-2.6.16-owrt/net/ipv4/netfilter/ip_set_ipmap.c
+--- linux-2.6.16/net/ipv4/netfilter/ip_set_ipmap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/netfilter/ip_set_ipmap.c 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,313 @@
++/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
++ * Patrick Schaaf <bof@bof.de>
++ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module implementing an IP set type: the single bitmap type */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <linux/spinlock.h>
++
++#include <linux/netfilter_ipv4/ip_set_ipmap.h>
++
++static inline ip_set_ip_t
++ip_to_id(const struct ip_set_ipmap *map, ip_set_ip_t ip)
++{
++ return (ip - map->first_ip)/map->hosts;
++}
++
++static inline int
++__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++
++ if (ip < map->first_ip || ip > map->last_ip)
++ return -ERANGE;
++
++ *hash_ip = ip & map->netmask;
++ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
++ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
++ return !!test_bit(ip_to_id(map, *hash_ip), map->members);
++}
++
++static int
++testip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_ipmap *req =
++ (struct ip_set_req_ipmap *) data;
++
++ if (size != sizeof(struct ip_set_req_ipmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_ipmap),
++ size);
++ return -EINVAL;
++ }
++ return __testip(set, req->ip, hash_ip);
++}
++
++static int
++testip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ u_int32_t flags,
++ ip_set_ip_t *hash_ip)
++{
++ int res;
++
++ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
++ flags & IPSET_SRC ? "SRC" : "DST",
++ NIPQUAD(skb->nh.iph->saddr),
++ NIPQUAD(skb->nh.iph->daddr));
++
++ res = __testip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++ return (res < 0 ? 0 : res);
++}
++
++static inline int
++__addip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++
++ if (ip < map->first_ip || ip > map->last_ip)
++ return -ERANGE;
++
++ *hash_ip = ip & map->netmask;
++ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
++ if (test_and_set_bit(ip_to_id(map, *hash_ip), map->members))
++ return -EEXIST;
++
++ return 0;
++}
++
++static int
++addip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_ipmap *req =
++ (struct ip_set_req_ipmap *) data;
++
++ if (size != sizeof(struct ip_set_req_ipmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_ipmap),
++ size);
++ return -EINVAL;
++ }
++ DP("%u.%u.%u.%u", HIPQUAD(req->ip));
++ return __addip(set, req->ip, hash_ip);
++}
++
++static int
++addip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __addip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++static inline int
++__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++
++ if (ip < map->first_ip || ip > map->last_ip)
++ return -ERANGE;
++
++ *hash_ip = ip & map->netmask;
++ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
++ if (!test_and_clear_bit(ip_to_id(map, *hash_ip), map->members))
++ return -EEXIST;
++
++ return 0;
++}
++
++static int
++delip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_ipmap *req =
++ (struct ip_set_req_ipmap *) data;
++
++ if (size != sizeof(struct ip_set_req_ipmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_ipmap),
++ size);
++ return -EINVAL;
++ }
++ return __delip(set, req->ip, hash_ip);
++}
++
++static int
++delip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __delip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++static int create(struct ip_set *set, const void *data, size_t size)
++{
++ int newbytes;
++ struct ip_set_req_ipmap_create *req =
++ (struct ip_set_req_ipmap_create *) data;
++ struct ip_set_ipmap *map;
++
++ if (size != sizeof(struct ip_set_req_ipmap_create)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_ipmap_create),
++ size);
++ return -EINVAL;
++ }
++
++ DP("from %u.%u.%u.%u to %u.%u.%u.%u",
++ HIPQUAD(req->from), HIPQUAD(req->to));
++
++ if (req->from > req->to) {
++ DP("bad ip range");
++ return -ENOEXEC;
++ }
++
++ if (req->to - req->from > MAX_RANGE) {
++ ip_set_printk("range too big (max %d addresses)",
++ MAX_RANGE);
++ return -ENOEXEC;
++ }
++
++ map = kmalloc(sizeof(struct ip_set_ipmap), GFP_KERNEL);
++ if (!map) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_ipmap));
++ return -ENOMEM;
++ }
++ map->first_ip = req->from;
++ map->last_ip = req->to;
++ map->netmask = req->netmask;
++
++ if (req->netmask == 0xFFFFFFFF) {
++ map->hosts = 1;
++ map->sizeid = map->last_ip - map->first_ip + 1;
++ } else {
++ unsigned int mask_bits, netmask_bits;
++ ip_set_ip_t mask;
++
++ map->first_ip &= map->netmask; /* Should we better bark? */
++
++ mask = range_to_mask(map->first_ip, map->last_ip, &mask_bits);
++ netmask_bits = mask_to_bits(map->netmask);
++
++ if (!mask || netmask_bits <= mask_bits)
++ return -ENOEXEC;
++
++ map->hosts = 2 << (32 - netmask_bits - 1);
++ map->sizeid = 2 << (netmask_bits - mask_bits - 1);
++ }
++ newbytes = bitmap_bytes(0, map->sizeid - 1);
++ map->members = kmalloc(newbytes, GFP_KERNEL);
++ if (!map->members) {
++ DP("out of memory for %d bytes", newbytes);
++ kfree(map);
++ return -ENOMEM;
++ }
++ memset(map->members, 0, newbytes);
++
++ set->data = map;
++ return 0;
++}
++
++static void destroy(struct ip_set *set)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++
++ kfree(map->members);
++ kfree(map);
++
++ set->data = NULL;
++}
++
++static void flush(struct ip_set *set)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++ memset(map->members, 0, bitmap_bytes(0, map->sizeid - 1));
++}
++
++static void list_header(const struct ip_set *set, void *data)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++ struct ip_set_req_ipmap_create *header =
++ (struct ip_set_req_ipmap_create *) data;
++
++ header->from = map->first_ip;
++ header->to = map->last_ip;
++ header->netmask = map->netmask;
++}
++
++static int list_members_size(const struct ip_set *set)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++
++ return bitmap_bytes(0, map->sizeid - 1);
++}
++
++static void list_members(const struct ip_set *set, void *data)
++{
++ struct ip_set_ipmap *map = (struct ip_set_ipmap *) set->data;
++ int bytes = bitmap_bytes(0, map->sizeid - 1);
++
++ memcpy(data, map->members, bytes);
++}
++
++static struct ip_set_type ip_set_ipmap = {
++ .typename = SETTYPE_NAME,
++ .typecode = IPSET_TYPE_IP,
++ .protocol_version = IP_SET_PROTOCOL_VERSION,
++ .create = &create,
++ .destroy = &destroy,
++ .flush = &flush,
++ .reqsize = sizeof(struct ip_set_req_ipmap),
++ .addip = &addip,
++ .addip_kernel = &addip_kernel,
++ .delip = &delip,
++ .delip_kernel = &delip_kernel,
++ .testip = &testip,
++ .testip_kernel = &testip_kernel,
++ .header_size = sizeof(struct ip_set_req_ipmap_create),
++ .list_header = &list_header,
++ .list_members_size = &list_members_size,
++ .list_members = &list_members,
++ .me = THIS_MODULE,
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("ipmap type of IP sets");
++
++static int __init init(void)
++{
++ return ip_set_register_set_type(&ip_set_ipmap);
++}
++
++static void __exit fini(void)
++{
++ /* FIXME: possible race with ip_set_create() */
++ ip_set_unregister_set_type(&ip_set_ipmap);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur linux-2.6.16/net/ipv4/netfilter/ip_set_iptree.c linux-2.6.16-owrt/net/ipv4/netfilter/ip_set_iptree.c
+--- linux-2.6.16/net/ipv4/netfilter/ip_set_iptree.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/netfilter/ip_set_iptree.c 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,510 @@
++/* Copyright (C) 2005 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module implementing an IP set type: the iptree type */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <linux/spinlock.h>
++
++#include <linux/netfilter_ipv4/ip_set_iptree.h>
++
++/* Garbage collection interval in seconds: */
++#define IPTREE_GC_TIME 5*60
++/* Sleep so many milliseconds before trying again
++ * to delete the gc timer at destroying a set */
++#define IPTREE_DESTROY_SLEEP 100
++
++static kmem_cache_t *branch_cachep;
++static kmem_cache_t *leaf_cachep;
++
++#define ABCD(a,b,c,d,addrp) do { \
++ a = ((unsigned char *)addrp)[3]; \
++ b = ((unsigned char *)addrp)[2]; \
++ c = ((unsigned char *)addrp)[1]; \
++ d = ((unsigned char *)addrp)[0]; \
++} while (0)
++
++#define TESTIP_WALK(map, elem, branch) do { \
++ if ((map)->tree[elem]) { \
++ branch = (map)->tree[elem]; \
++ } else \
++ return 0; \
++} while (0)
++
++static inline int
++__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_iptreeb *btree;
++ struct ip_set_iptreec *ctree;
++ struct ip_set_iptreed *dtree;
++ unsigned char a,b,c,d;
++
++ *hash_ip = ip;
++ ABCD(a, b, c, d, hash_ip);
++ DP("%u %u %u %u timeout %u", a, b, c, d, map->timeout);
++ TESTIP_WALK(map, a, btree);
++ TESTIP_WALK(btree, b, ctree);
++ TESTIP_WALK(ctree, c, dtree);
++ DP("%lu %lu", dtree->expires[d], jiffies);
++ return !!(map->timeout ? (time_after(dtree->expires[d], jiffies))
++ : dtree->expires[d]);
++}
++
++static int
++testip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_iptree *req =
++ (struct ip_set_req_iptree *) data;
++
++ if (size != sizeof(struct ip_set_req_iptree)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iptree),
++ size);
++ return -EINVAL;
++ }
++ return __testip(set, req->ip, hash_ip);
++}
++
++static int
++testip_kernel(struct ip_set *set,
++ const struct sk_buff *skb,
++ u_int32_t flags,
++ ip_set_ip_t *hash_ip)
++{
++ int res;
++
++ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
++ flags & IPSET_SRC ? "SRC" : "DST",
++ NIPQUAD(skb->nh.iph->saddr),
++ NIPQUAD(skb->nh.iph->daddr));
++
++ res = __testip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++ return (res < 0 ? 0 : res);
++}
++
++#define ADDIP_WALK(map, elem, branch, type, cachep) do { \
++ if ((map)->tree[elem]) { \
++ DP("found %u", elem); \
++ branch = (map)->tree[elem]; \
++ } else { \
++ branch = (type *) \
++ kmem_cache_alloc(cachep, GFP_KERNEL); \
++ if (branch == NULL) \
++ return -ENOMEM; \
++ memset(branch, 0, sizeof(*branch)); \
++ (map)->tree[elem] = branch; \
++ DP("alloc %u", elem); \
++ } \
++} while (0)
++
++static inline int
++__addip(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_iptreeb *btree;
++ struct ip_set_iptreec *ctree;
++ struct ip_set_iptreed *dtree;
++ unsigned char a,b,c,d;
++ int ret = 0;
++
++ *hash_ip = ip;
++ ABCD(a, b, c, d, hash_ip);
++ DP("%u %u %u %u timeout %u", a, b, c, d, timeout);
++ ADDIP_WALK(map, a, btree, struct ip_set_iptreeb, branch_cachep);
++ ADDIP_WALK(btree, b, ctree, struct ip_set_iptreec, branch_cachep);
++ ADDIP_WALK(ctree, c, dtree, struct ip_set_iptreed, leaf_cachep);
++ if (dtree->expires[d]
++ && (!map->timeout || time_after(dtree->expires[d], jiffies)))
++ ret = -EEXIST;
++ dtree->expires[d] = map->timeout ? (timeout * HZ + jiffies) : 1;
++ DP("%u %lu", d, dtree->expires[d]);
++ return ret;
++}
++
++static int
++addip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_req_iptree *req =
++ (struct ip_set_req_iptree *) data;
++
++ if (size != sizeof(struct ip_set_req_iptree)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iptree),
++ size);
++ return -EINVAL;
++ }
++ DP("%u.%u.%u.%u %u", HIPQUAD(req->ip), req->timeout);
++ return __addip(set, req->ip,
++ req->timeout ? req->timeout : map->timeout,
++ hash_ip);
++}
++
++static int
++addip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++
++ return __addip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ map->timeout,
++ hash_ip);
++}
++
++#define DELIP_WALK(map, elem, branch) do { \
++ if ((map)->tree[elem]) { \
++ branch = (map)->tree[elem]; \
++ } else \
++ return -EEXIST; \
++} while (0)
++
++static inline int
++__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_iptreeb *btree;
++ struct ip_set_iptreec *ctree;
++ struct ip_set_iptreed *dtree;
++ unsigned char a,b,c,d;
++
++ *hash_ip = ip;
++ ABCD(a, b, c, d, hash_ip);
++ DELIP_WALK(map, a, btree);
++ DELIP_WALK(btree, b, ctree);
++ DELIP_WALK(ctree, c, dtree);
++
++ if (dtree->expires[d]) {
++ dtree->expires[d] = 0;
++ return 0;
++ }
++ return -EEXIST;
++}
++
++static int
++delip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_iptree *req =
++ (struct ip_set_req_iptree *) data;
++
++ if (size != sizeof(struct ip_set_req_iptree)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iptree),
++ size);
++ return -EINVAL;
++ }
++ return __delip(set, req->ip, hash_ip);
++}
++
++static int
++delip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __delip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++#define LOOP_WALK_BEGIN(map, i, branch) \
++ for (i = 0; i < 255; i++) { \
++ if (!(map)->tree[i]) \
++ continue; \
++ branch = (map)->tree[i]
++
++#define LOOP_WALK_END }
++
++static void ip_tree_gc(unsigned long ul_set)
++{
++ struct ip_set *set = (void *) ul_set;
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_iptreeb *btree;
++ struct ip_set_iptreec *ctree;
++ struct ip_set_iptreed *dtree;
++ unsigned char a,b,c,d;
++ unsigned char i,j,k;
++
++ i = j = k = 0;
++ DP("gc: %s", set->name);
++ write_lock_bh(&set->lock);
++ LOOP_WALK_BEGIN(map, a, btree);
++ LOOP_WALK_BEGIN(btree, b, ctree);
++ LOOP_WALK_BEGIN(ctree, c, dtree);
++ for (d = 0; d < 255; d++) {
++ if (dtree->expires[d]) {
++ DP("gc: %u %u %u %u: expires %lu jiffies %lu",
++ a, b, c, d,
++ dtree->expires[d], jiffies);
++ if (map->timeout
++ && time_before(dtree->expires[d], jiffies))
++ dtree->expires[d] = 0;
++ else
++ k = 1;
++ }
++ }
++ if (k == 0) {
++ DP("gc: %s: leaf %u %u %u empty",
++ set->name, a, b, c);
++ kmem_cache_free(leaf_cachep, dtree);
++ ctree->tree[c] = NULL;
++ } else {
++ DP("gc: %s: leaf %u %u %u not empty",
++ set->name, a, b, c);
++ j = 1;
++ k = 0;
++ }
++ LOOP_WALK_END;
++ if (j == 0) {
++ DP("gc: %s: branch %u %u empty",
++ set->name, a, b);
++ kmem_cache_free(branch_cachep, ctree);
++ btree->tree[b] = NULL;
++ } else {
++ DP("gc: %s: branch %u %u not empty",
++ set->name, a, b);
++ i = 1;
++ j = k = 0;
++ }
++ LOOP_WALK_END;
++ if (i == 0) {
++ DP("gc: %s: branch %u empty",
++ set->name, a);
++ kmem_cache_free(branch_cachep, btree);
++ map->tree[a] = NULL;
++ } else {
++ DP("gc: %s: branch %u not empty",
++ set->name, a);
++ i = j = k = 0;
++ }
++ LOOP_WALK_END;
++ write_unlock_bh(&set->lock);
++
++ map->gc.expires = jiffies + map->gc_interval * HZ;
++ add_timer(&map->gc);
++}
++
++static int create(struct ip_set *set, const void *data, size_t size)
++{
++ struct ip_set_req_iptree_create *req =
++ (struct ip_set_req_iptree_create *) data;
++ struct ip_set_iptree *map;
++
++ if (size != sizeof(struct ip_set_req_iptree_create)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_iptree_create),
++ size);
++ return -EINVAL;
++ }
++
++ map = kmalloc(sizeof(struct ip_set_iptree), GFP_KERNEL);
++ if (!map) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_iptree));
++ return -ENOMEM;
++ }
++ memset(map, 0, sizeof(*map));
++ map->timeout = req->timeout;
++ set->data = map;
++
++ /* If there is no timeout for the entries,
++ * we still have to call gc because delete
++ * do not clean up empty branches */
++ map->gc_interval = IPTREE_GC_TIME;
++ init_timer(&map->gc);
++ map->gc.data = (unsigned long) set;
++ map->gc.function = ip_tree_gc;
++ map->gc.expires = jiffies + map->gc_interval * HZ;
++ add_timer(&map->gc);
++
++ return 0;
++}
++
++static void __flush(struct ip_set_iptree *map)
++{
++ struct ip_set_iptreeb *btree;
++ struct ip_set_iptreec *ctree;
++ struct ip_set_iptreed *dtree;
++ unsigned int a,b,c;
++
++ LOOP_WALK_BEGIN(map, a, btree);
++ LOOP_WALK_BEGIN(btree, b, ctree);
++ LOOP_WALK_BEGIN(ctree, c, dtree);
++ kmem_cache_free(leaf_cachep, dtree);
++ LOOP_WALK_END;
++ kmem_cache_free(branch_cachep, ctree);
++ LOOP_WALK_END;
++ kmem_cache_free(branch_cachep, btree);
++ LOOP_WALK_END;
++}
++
++static void destroy(struct ip_set *set)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++
++ while (!del_timer(&map->gc))
++ msleep(IPTREE_DESTROY_SLEEP);
++ __flush(map);
++ kfree(map);
++ set->data = NULL;
++}
++
++static void flush(struct ip_set *set)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ unsigned int timeout = map->timeout;
++
++ __flush(map);
++ memset(map, 0, sizeof(*map));
++ map->timeout = timeout;
++}
++
++static void list_header(const struct ip_set *set, void *data)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_req_iptree_create *header =
++ (struct ip_set_req_iptree_create *) data;
++
++ header->timeout = map->timeout;
++}
++
++static int list_members_size(const struct ip_set *set)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_iptreeb *btree;
++ struct ip_set_iptreec *ctree;
++ struct ip_set_iptreed *dtree;
++ unsigned char a,b,c,d;
++ unsigned int count = 0;
++
++ LOOP_WALK_BEGIN(map, a, btree);
++ LOOP_WALK_BEGIN(btree, b, ctree);
++ LOOP_WALK_BEGIN(ctree, c, dtree);
++ for (d = 0; d < 255; d++) {
++ if (dtree->expires[d]
++ && (!map->timeout || time_after(dtree->expires[d], jiffies)))
++ count++;
++ }
++ LOOP_WALK_END;
++ LOOP_WALK_END;
++ LOOP_WALK_END;
++
++ DP("members %u", count);
++ return (count * sizeof(struct ip_set_req_iptree));
++}
++
++static void list_members(const struct ip_set *set, void *data)
++{
++ struct ip_set_iptree *map = (struct ip_set_iptree *) set->data;
++ struct ip_set_iptreeb *btree;
++ struct ip_set_iptreec *ctree;
++ struct ip_set_iptreed *dtree;
++ unsigned char a,b,c,d;
++ size_t offset = 0;
++ struct ip_set_req_iptree *entry;
++
++ LOOP_WALK_BEGIN(map, a, btree);
++ LOOP_WALK_BEGIN(btree, b, ctree);
++ LOOP_WALK_BEGIN(ctree, c, dtree);
++ for (d = 0; d < 255; d++) {
++ if (dtree->expires[d]
++ && (!map->timeout || time_after(dtree->expires[d], jiffies))) {
++ entry = (struct ip_set_req_iptree *)(data + offset);
++ entry->ip = ((a << 24) | (b << 16) | (c << 8) | d);
++ entry->timeout = !map->timeout ? 0
++ : (dtree->expires[d] - jiffies)/HZ;
++ offset += sizeof(struct ip_set_req_iptree);
++ }
++ }
++ LOOP_WALK_END;
++ LOOP_WALK_END;
++ LOOP_WALK_END;
++}
++
++static struct ip_set_type ip_set_iptree = {
++ .typename = SETTYPE_NAME,
++ .typecode = IPSET_TYPE_IP,
++ .protocol_version = IP_SET_PROTOCOL_VERSION,
++ .create = &create,
++ .destroy = &destroy,
++ .flush = &flush,
++ .reqsize = sizeof(struct ip_set_req_iptree),
++ .addip = &addip,
++ .addip_kernel = &addip_kernel,
++ .delip = &delip,
++ .delip_kernel = &delip_kernel,
++ .testip = &testip,
++ .testip_kernel = &testip_kernel,
++ .header_size = sizeof(struct ip_set_req_iptree_create),
++ .list_header = &list_header,
++ .list_members_size = &list_members_size,
++ .list_members = &list_members,
++ .me = THIS_MODULE,
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("iptree type of IP sets");
++
++static int __init init(void)
++{
++ int ret;
++
++ branch_cachep = kmem_cache_create("ip_set_iptreeb",
++ sizeof(struct ip_set_iptreeb),
++ 0, 0, NULL, NULL);
++ if (!branch_cachep) {
++ printk(KERN_ERR "Unable to create ip_set_iptreeb slab cache\n");
++ ret = -ENOMEM;
++ goto out;
++ }
++ leaf_cachep = kmem_cache_create("ip_set_iptreed",
++ sizeof(struct ip_set_iptreed),
++ 0, 0, NULL, NULL);
++ if (!leaf_cachep) {
++ printk(KERN_ERR "Unable to create ip_set_iptreed slab cache\n");
++ ret = -ENOMEM;
++ goto free_branch;
++ }
++ ret = ip_set_register_set_type(&ip_set_iptree);
++ if (ret == 0)
++ goto out;
++
++ kmem_cache_destroy(leaf_cachep);
++ free_branch:
++ kmem_cache_destroy(branch_cachep);
++ out:
++ return ret;
++}
++
++static void __exit fini(void)
++{
++ /* FIXME: possible race with ip_set_create() */
++ ip_set_unregister_set_type(&ip_set_iptree);
++ kmem_cache_destroy(leaf_cachep);
++ kmem_cache_destroy(branch_cachep);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur linux-2.6.16/net/ipv4/netfilter/ip_set_macipmap.c linux-2.6.16-owrt/net/ipv4/netfilter/ip_set_macipmap.c
+--- linux-2.6.16/net/ipv4/netfilter/ip_set_macipmap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/netfilter/ip_set_macipmap.c 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,338 @@
++/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
++ * Patrick Schaaf <bof@bof.de>
++ * Martin Josefsson <gandalf@wlug.westbo.se>
++ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module implementing an IP set type: the macipmap type */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <linux/spinlock.h>
++#include <linux/if_ether.h>
++#include <linux/vmalloc.h>
++
++#include <linux/netfilter_ipv4/ip_set_malloc.h>
++#include <linux/netfilter_ipv4/ip_set_macipmap.h>
++
++static int
++testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_macipmap *map = (struct ip_set_macipmap *) set->data;
++ struct ip_set_macip *table = (struct ip_set_macip *) map->members;
++ struct ip_set_req_macipmap *req = (struct ip_set_req_macipmap *) data;
++
++ if (size != sizeof(struct ip_set_req_macipmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_macipmap),
++ size);
++ return -EINVAL;
++ }
++
++ if (req->ip < map->first_ip || req->ip > map->last_ip)
++ return -ERANGE;
++
++ *hash_ip = req->ip;
++ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
++ set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip));
++ if (test_bit(IPSET_MACIP_ISSET,
++ (void *) &table[req->ip - map->first_ip].flags)) {
++ return (memcmp(req->ethernet,
++ &table[req->ip - map->first_ip].ethernet,
++ ETH_ALEN) == 0);
++ } else {
++ return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
++ }
++}
++
++static int
++testip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++ struct ip_set_macip *table =
++ (struct ip_set_macip *) map->members;
++ ip_set_ip_t ip;
++
++ ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr);
++ DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
++ flags & IPSET_SRC ? "SRC" : "DST",
++ NIPQUAD(skb->nh.iph->saddr),
++ NIPQUAD(skb->nh.iph->daddr));
++
++ if (ip < map->first_ip || ip > map->last_ip)
++ return 0;
++
++ *hash_ip = ip;
++ DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
++ set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
++ if (test_bit(IPSET_MACIP_ISSET,
++ (void *) &table[ip - map->first_ip].flags)) {
++ /* Is mac pointer valid?
++ * If so, compare... */
++ return (skb->mac.raw >= skb->head
++ && (skb->mac.raw + ETH_HLEN) <= skb->data
++ && (memcmp(eth_hdr(skb)->h_source,
++ &table[ip - map->first_ip].ethernet,
++ ETH_ALEN) == 0));
++ } else {
++ return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
++ }
++}
++
++/* returns 0 on success */
++static inline int
++__addip(struct ip_set *set,
++ ip_set_ip_t ip, unsigned char *ethernet, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++ struct ip_set_macip *table =
++ (struct ip_set_macip *) map->members;
++
++ if (ip < map->first_ip || ip > map->last_ip)
++ return -ERANGE;
++ if (test_and_set_bit(IPSET_MACIP_ISSET,
++ (void *) &table[ip - map->first_ip].flags))
++ return -EEXIST;
++
++ *hash_ip = ip;
++ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
++ memcpy(&table[ip - map->first_ip].ethernet, ethernet, ETH_ALEN);
++ return 0;
++}
++
++static int
++addip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_macipmap *req =
++ (struct ip_set_req_macipmap *) data;
++
++ if (size != sizeof(struct ip_set_req_macipmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_macipmap),
++ size);
++ return -EINVAL;
++ }
++ return __addip(set, req->ip, req->ethernet, hash_ip);
++}
++
++static int
++addip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ ip_set_ip_t ip;
++
++ ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr);
++
++ if (!(skb->mac.raw >= skb->head
++ && (skb->mac.raw + ETH_HLEN) <= skb->data))
++ return -EINVAL;
++
++ return __addip(set, ip, eth_hdr(skb)->h_source, hash_ip);
++}
++
++static inline int
++__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++ struct ip_set_macip *table =
++ (struct ip_set_macip *) map->members;
++
++ if (ip < map->first_ip || ip > map->last_ip)
++ return -ERANGE;
++ if (!test_and_clear_bit(IPSET_MACIP_ISSET,
++ (void *)&table[ip - map->first_ip].flags))
++ return -EEXIST;
++
++ *hash_ip = ip;
++ DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
++ return 0;
++}
++
++static int
++delip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_macipmap *req =
++ (struct ip_set_req_macipmap *) data;
++
++ if (size != sizeof(struct ip_set_req_macipmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_macipmap),
++ size);
++ return -EINVAL;
++ }
++ return __delip(set, req->ip, hash_ip);
++}
++
++static int
++delip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __delip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++static inline size_t members_size(ip_set_id_t from, ip_set_id_t to)
++{
++ return (size_t)((to - from + 1) * sizeof(struct ip_set_macip));
++}
++
++static int create(struct ip_set *set, const void *data, size_t size)
++{
++ int newbytes;
++ struct ip_set_req_macipmap_create *req =
++ (struct ip_set_req_macipmap_create *) data;
++ struct ip_set_macipmap *map;
++
++ if (size != sizeof(struct ip_set_req_macipmap_create)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_macipmap_create),
++ size);
++ return -EINVAL;
++ }
++
++ DP("from %u.%u.%u.%u to %u.%u.%u.%u",
++ HIPQUAD(req->from), HIPQUAD(req->to));
++
++ if (req->from > req->to) {
++ DP("bad ip range");
++ return -ENOEXEC;
++ }
++
++ if (req->to - req->from > MAX_RANGE) {
++ ip_set_printk("range too big (max %d addresses)",
++ MAX_RANGE);
++ return -ENOEXEC;
++ }
++
++ map = kmalloc(sizeof(struct ip_set_macipmap), GFP_KERNEL);
++ if (!map) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_macipmap));
++ return -ENOMEM;
++ }
++ map->flags = req->flags;
++ map->first_ip = req->from;
++ map->last_ip = req->to;
++ newbytes = members_size(map->first_ip, map->last_ip);
++ map->members = ip_set_malloc(newbytes);
++ if (!map->members) {
++ DP("out of memory for %d bytes", newbytes);
++ kfree(map);
++ return -ENOMEM;
++ }
++ memset(map->members, 0, newbytes);
++
++ set->data = map;
++ return 0;
++}
++
++static void destroy(struct ip_set *set)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++
++ ip_set_free(map->members, members_size(map->first_ip, map->last_ip));
++ kfree(map);
++
++ set->data = NULL;
++}
++
++static void flush(struct ip_set *set)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++ memset(map->members, 0, members_size(map->first_ip, map->last_ip));
++}
++
++static void list_header(const struct ip_set *set, void *data)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++ struct ip_set_req_macipmap_create *header =
++ (struct ip_set_req_macipmap_create *) data;
++
++ DP("list_header %x %x %u", map->first_ip, map->last_ip,
++ map->flags);
++
++ header->from = map->first_ip;
++ header->to = map->last_ip;
++ header->flags = map->flags;
++}
++
++static int list_members_size(const struct ip_set *set)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++
++ return members_size(map->first_ip, map->last_ip);
++}
++
++static void list_members(const struct ip_set *set, void *data)
++{
++ struct ip_set_macipmap *map =
++ (struct ip_set_macipmap *) set->data;
++
++ int bytes = members_size(map->first_ip, map->last_ip);
++
++ memcpy(data, map->members, bytes);
++}
++
++static struct ip_set_type ip_set_macipmap = {
++ .typename = SETTYPE_NAME,
++ .typecode = IPSET_TYPE_IP,
++ .protocol_version = IP_SET_PROTOCOL_VERSION,
++ .create = &create,
++ .destroy = &destroy,
++ .flush = &flush,
++ .reqsize = sizeof(struct ip_set_req_macipmap),
++ .addip = &addip,
++ .addip_kernel = &addip_kernel,
++ .delip = &delip,
++ .delip_kernel = &delip_kernel,
++ .testip = &testip,
++ .testip_kernel = &testip_kernel,
++ .header_size = sizeof(struct ip_set_req_macipmap_create),
++ .list_header = &list_header,
++ .list_members_size = &list_members_size,
++ .list_members = &list_members,
++ .me = THIS_MODULE,
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("macipmap type of IP sets");
++
++static int __init init(void)
++{
++ init_max_malloc_size();
++ return ip_set_register_set_type(&ip_set_macipmap);
++}
++
++static void __exit fini(void)
++{
++ /* FIXME: possible race with ip_set_create() */
++ ip_set_unregister_set_type(&ip_set_macipmap);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur linux-2.6.16/net/ipv4/netfilter/ip_set_nethash.c linux-2.6.16-owrt/net/ipv4/netfilter/ip_set_nethash.c
+--- linux-2.6.16/net/ipv4/netfilter/ip_set_nethash.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/netfilter/ip_set_nethash.c 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,449 @@
++/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module implementing a cidr nethash set */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <linux/spinlock.h>
++#include <linux/vmalloc.h>
++#include <linux/random.h>
++
++#include <net/ip.h>
++
++#include <linux/netfilter_ipv4/ip_set_malloc.h>
++#include <linux/netfilter_ipv4/ip_set_nethash.h>
++#include <linux/netfilter_ipv4/ip_set_jhash.h>
++#include <linux/netfilter_ipv4/ip_set_prime.h>
++
++static inline __u32
++jhash_ip(const struct ip_set_nethash *map, ip_set_ip_t ip)
++{
++ return jhash_1word(ip, map->initval);
++}
++
++static inline __u32
++randhash_ip(const struct ip_set_nethash *map, ip_set_ip_t ip)
++{
++ return (1 + ip % map->prime);
++}
++
++static inline __u32
++hash_id_cidr(struct ip_set_nethash *map,
++ ip_set_ip_t ip,
++ unsigned char cidr,
++ ip_set_ip_t *hash_ip)
++{
++ __u32 jhash, randhash, id;
++ u_int16_t i;
++
++ *hash_ip = pack(ip, cidr);
++ jhash = jhash_ip(map, *hash_ip);
++ randhash = randhash_ip(map, *hash_ip);
++
++ for (i = 0; i < map->probes; i++) {
++ id = (jhash + i * randhash) % map->hashsize;
++ DP("hash key: %u", id);
++ if (map->members[id] == *hash_ip)
++ return id;
++ }
++ return UINT_MAX;
++}
++
++static inline __u32
++hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++ __u32 id = UINT_MAX;
++ int i;
++
++ for (i = 0; i < 30 && map->cidr[i]; i++) {
++ id = hash_id_cidr(map, ip, map->cidr[i], hash_ip);
++ if (id != UINT_MAX)
++ break;
++ }
++ return id;
++}
++
++static inline int
++__testip_cidr(struct ip_set *set, ip_set_ip_t ip, unsigned char cidr,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++
++ return (hash_id_cidr(map, ip, cidr, hash_ip) != UINT_MAX);
++}
++
++static inline int
++__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
++{
++ return (hash_id(set, ip, hash_ip) != UINT_MAX);
++}
++
++static int
++testip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_nethash *req =
++ (struct ip_set_req_nethash *) data;
++
++ if (size != sizeof(struct ip_set_req_nethash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_nethash),
++ size);
++ return -EINVAL;
++ }
++ return (req->cidr == 32 ? __testip(set, req->ip, hash_ip)
++ : __testip_cidr(set, req->ip, req->cidr, hash_ip));
++}
++
++static int
++testip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ return __testip(set,
++ ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr),
++ hash_ip);
++}
++
++static inline int
++__addip_base(struct ip_set_nethash *map, ip_set_ip_t ip)
++{
++ __u32 jhash, randhash, probe;
++ u_int16_t i;
++
++ jhash = jhash_ip(map, ip);
++ randhash = randhash_ip(map, ip);
++
++ for (i = 0; i < map->probes; i++) {
++ probe = (jhash + i * randhash) % map->hashsize;
++ if (map->members[probe] == ip)
++ return -EEXIST;
++ if (!map->members[probe]) {
++ map->members[probe] = ip;
++ return 0;
++ }
++ }
++ /* Trigger rehashing */
++ return -EAGAIN;
++}
++
++static inline int
++__addip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
++ ip_set_ip_t *hash_ip)
++{
++ *hash_ip = pack(ip, cidr);
++ DP("%u.%u.%u.%u/%u, %u.%u.%u.%u", HIPQUAD(ip), cidr, HIPQUAD(*hash_ip));
++
++ return __addip_base(map, *hash_ip);
++}
++
++static void
++update_cidr_sizes(struct ip_set_nethash *map, unsigned char cidr)
++{
++ unsigned char next;
++ int i;
++
++ for (i = 0; i < 30 && map->cidr[i]; i++) {
++ if (map->cidr[i] == cidr) {
++ return;
++ } else if (map->cidr[i] < cidr) {
++ next = map->cidr[i];
++ map->cidr[i] = cidr;
++ cidr = next;
++ }
++ }
++ if (i < 30)
++ map->cidr[i] = cidr;
++}
++
++static int
++addip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_nethash *req =
++ (struct ip_set_req_nethash *) data;
++ int ret;
++
++ if (size != sizeof(struct ip_set_req_nethash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_nethash),
++ size);
++ return -EINVAL;
++ }
++ ret = __addip((struct ip_set_nethash *) set->data,
++ req->ip, req->cidr, hash_ip);
++
++ if (ret == 0)
++ update_cidr_sizes((struct ip_set_nethash *) set->data,
++ req->cidr);
++
++ return ret;
++}
++
++static int
++addip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++ int ret = -ERANGE;
++ ip_set_ip_t ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr);
++
++ if (map->cidr[0])
++ ret = __addip(map, ip, map->cidr[0], hash_ip);
++
++ return ret;
++}
++
++static int retry(struct ip_set *set)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++ ip_set_ip_t *members;
++ u_int32_t i, hashsize;
++ unsigned newbytes;
++ int res;
++ struct ip_set_nethash tmp = {
++ .hashsize = map->hashsize,
++ .probes = map->probes,
++ .resize = map->resize
++ };
++
++ if (map->resize == 0)
++ return -ERANGE;
++
++ memcpy(tmp.cidr, map->cidr, 30 * sizeof(unsigned char));
++ again:
++ res = 0;
++
++ /* Calculate new parameters */
++ get_random_bytes(&tmp.initval, 4);
++ hashsize = tmp.hashsize + (tmp.hashsize * map->resize)/100;
++ if (hashsize == tmp.hashsize)
++ hashsize++;
++ tmp.prime = make_prime(hashsize);
++
++ ip_set_printk("rehashing of set %s triggered: "
++ "hashsize grows from %u to %u",
++ set->name, tmp.hashsize, hashsize);
++ tmp.hashsize = hashsize;
++
++ newbytes = hashsize * sizeof(ip_set_ip_t);
++ tmp.members = ip_set_malloc_atomic(newbytes);
++ if (!tmp.members) {
++ DP("out of memory for %d bytes", newbytes);
++ return -ENOMEM;
++ }
++ memset(tmp.members, 0, newbytes);
++
++ write_lock_bh(&set->lock);
++ map = (struct ip_set_nethash *) set->data; /* Play safe */
++ for (i = 0; i < map->hashsize && res == 0; i++) {
++ if (map->members[i])
++ res = __addip_base(&tmp, map->members[i]);
++ }
++ if (res) {
++ /* Failure, try again */
++ write_unlock_bh(&set->lock);
++ ip_set_free(tmp.members, newbytes);
++ goto again;
++ }
++
++ /* Success at resizing! */
++ members = map->members;
++ hashsize = map->hashsize;
++
++ map->initval = tmp.initval;
++ map->prime = tmp.prime;
++ map->hashsize = tmp.hashsize;
++ map->members = tmp.members;
++ write_unlock_bh(&set->lock);
++
++ ip_set_free(members, hashsize * sizeof(ip_set_ip_t));
++
++ return 0;
++}
++
++static inline int
++__delip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
++ ip_set_ip_t *hash_ip)
++{
++ ip_set_ip_t id = hash_id_cidr(map, ip, cidr, hash_ip);
++
++ if (id == UINT_MAX)
++ return -EEXIST;
++
++ map->members[id] = 0;
++ return 0;
++}
++
++static int
++delip(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_ip)
++{
++ struct ip_set_req_nethash *req =
++ (struct ip_set_req_nethash *) data;
++
++ if (size != sizeof(struct ip_set_req_nethash)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_nethash),
++ size);
++ return -EINVAL;
++ }
++ /* TODO: no garbage collection in map->cidr */
++ return __delip((struct ip_set_nethash *) set->data,
++ req->ip, req->cidr, hash_ip);
++}
++
++static int
++delip_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_ip)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++ int ret = -ERANGE;
++ ip_set_ip_t ip = ntohl(flags & IPSET_SRC ? skb->nh.iph->saddr
++ : skb->nh.iph->daddr);
++
++ if (map->cidr[0])
++ ret = __delip(map, ip, map->cidr[0], hash_ip);
++
++ return ret;
++}
++
++static int create(struct ip_set *set, const void *data, size_t size)
++{
++ unsigned newbytes;
++ struct ip_set_req_nethash_create *req =
++ (struct ip_set_req_nethash_create *) data;
++ struct ip_set_nethash *map;
++
++ if (size != sizeof(struct ip_set_req_nethash_create)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_nethash_create),
++ size);
++ return -EINVAL;
++ }
++
++ if (req->hashsize < 1) {
++ ip_set_printk("hashsize too small");
++ return -ENOEXEC;
++ }
++
++ map = kmalloc(sizeof(struct ip_set_nethash), GFP_KERNEL);
++ if (!map) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_nethash));
++ return -ENOMEM;
++ }
++ get_random_bytes(&map->initval, 4);
++ map->prime = make_prime(req->hashsize);
++ map->hashsize = req->hashsize;
++ map->probes = req->probes;
++ map->resize = req->resize;
++ memset(map->cidr, 0, 30 * sizeof(unsigned char));
++ newbytes = map->hashsize * sizeof(ip_set_ip_t);
++ map->members = ip_set_malloc(newbytes);
++ if (!map->members) {
++ DP("out of memory for %d bytes", newbytes);
++ kfree(map);
++ return -ENOMEM;
++ }
++ memset(map->members, 0, newbytes);
++
++ set->data = map;
++ return 0;
++}
++
++static void destroy(struct ip_set *set)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++
++ ip_set_free(map->members, map->hashsize * sizeof(ip_set_ip_t));
++ kfree(map);
++
++ set->data = NULL;
++}
++
++static void flush(struct ip_set *set)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++ memset(map->members, 0, map->hashsize * sizeof(ip_set_ip_t));
++ memset(map->cidr, 0, 30 * sizeof(unsigned char));
++}
++
++static void list_header(const struct ip_set *set, void *data)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++ struct ip_set_req_nethash_create *header =
++ (struct ip_set_req_nethash_create *) data;
++
++ header->hashsize = map->hashsize;
++ header->probes = map->probes;
++ header->resize = map->resize;
++}
++
++static int list_members_size(const struct ip_set *set)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++
++ return (map->hashsize * sizeof(ip_set_ip_t));
++}
++
++static void list_members(const struct ip_set *set, void *data)
++{
++ struct ip_set_nethash *map = (struct ip_set_nethash *) set->data;
++ int bytes = map->hashsize * sizeof(ip_set_ip_t);
++
++ memcpy(data, map->members, bytes);
++}
++
++static struct ip_set_type ip_set_nethash = {
++ .typename = SETTYPE_NAME,
++ .typecode = IPSET_TYPE_IP,
++ .protocol_version = IP_SET_PROTOCOL_VERSION,
++ .create = &create,
++ .destroy = &destroy,
++ .flush = &flush,
++ .reqsize = sizeof(struct ip_set_req_nethash),
++ .addip = &addip,
++ .addip_kernel = &addip_kernel,
++ .retry = &retry,
++ .delip = &delip,
++ .delip_kernel = &delip_kernel,
++ .testip = &testip,
++ .testip_kernel = &testip_kernel,
++ .header_size = sizeof(struct ip_set_req_nethash_create),
++ .list_header = &list_header,
++ .list_members_size = &list_members_size,
++ .list_members = &list_members,
++ .me = THIS_MODULE,
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("nethash type of IP sets");
++
++static int __init init(void)
++{
++ return ip_set_register_set_type(&ip_set_nethash);
++}
++
++static void __exit fini(void)
++{
++ /* FIXME: possible race with ip_set_create() */
++ ip_set_unregister_set_type(&ip_set_nethash);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur linux-2.6.16/net/ipv4/netfilter/ip_set_portmap.c linux-2.6.16-owrt/net/ipv4/netfilter/ip_set_portmap.c
+--- linux-2.6.16/net/ipv4/netfilter/ip_set_portmap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/netfilter/ip_set_portmap.c 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,325 @@
++/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module implementing a port set type as a bitmap */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <linux/spinlock.h>
++
++#include <net/ip.h>
++
++#include <linux/netfilter_ipv4/ip_set_portmap.h>
++
++/* We must handle non-linear skbs */
++static inline ip_set_ip_t
++get_port(const struct sk_buff *skb, u_int32_t flags)
++{
++ struct iphdr *iph = skb->nh.iph;
++ u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
++
++ switch (iph->protocol) {
++ case IPPROTO_TCP: {
++ struct tcphdr tcph;
++
++ /* See comments at tcp_match in ip_tables.c */
++ if (offset)
++ return INVALID_PORT;
++
++ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0)
++ /* No choice either */
++ return INVALID_PORT;
++
++ return ntohs(flags & IPSET_SRC ?
++ tcph.source : tcph.dest);
++ }
++ case IPPROTO_UDP: {
++ struct udphdr udph;
++
++ if (offset)
++ return INVALID_PORT;
++
++ if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0)
++ /* No choice either */
++ return INVALID_PORT;
++
++ return ntohs(flags & IPSET_SRC ?
++ udph.source : udph.dest);
++ }
++ default:
++ return INVALID_PORT;
++ }
++}
++
++static inline int
++__testport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++
++ if (port < map->first_port || port > map->last_port)
++ return -ERANGE;
++
++ *hash_port = port;
++ DP("set: %s, port:%u, %u", set->name, port, *hash_port);
++ return !!test_bit(port - map->first_port, map->members);
++}
++
++static int
++testport(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_port)
++{
++ struct ip_set_req_portmap *req =
++ (struct ip_set_req_portmap *) data;
++
++ if (size != sizeof(struct ip_set_req_portmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_portmap),
++ size);
++ return -EINVAL;
++ }
++ return __testport(set, req->port, hash_port);
++}
++
++static int
++testport_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_port)
++{
++ int res;
++ ip_set_ip_t port = get_port(skb, flags);
++
++ DP("flag %s port %u", flags & IPSET_SRC ? "SRC" : "DST", port);
++ if (port == INVALID_PORT)
++ return 0;
++
++ res = __testport(set, port, hash_port);
++
++ return (res < 0 ? 0 : res);
++}
++
++static inline int
++__addport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++
++ if (port < map->first_port || port > map->last_port)
++ return -ERANGE;
++ if (test_and_set_bit(port - map->first_port, map->members))
++ return -EEXIST;
++
++ *hash_port = port;
++ DP("port %u", port);
++ return 0;
++}
++
++static int
++addport(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_port)
++{
++ struct ip_set_req_portmap *req =
++ (struct ip_set_req_portmap *) data;
++
++ if (size != sizeof(struct ip_set_req_portmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_portmap),
++ size);
++ return -EINVAL;
++ }
++ return __addport(set, req->port, hash_port);
++}
++
++static int
++addport_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_port)
++{
++ ip_set_ip_t port = get_port(skb, flags);
++
++ if (port == INVALID_PORT)
++ return -EINVAL;
++
++ return __addport(set, port, hash_port);
++}
++
++static inline int
++__delport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++
++ if (port < map->first_port || port > map->last_port)
++ return -ERANGE;
++ if (!test_and_clear_bit(port - map->first_port, map->members))
++ return -EEXIST;
++
++ *hash_port = port;
++ DP("port %u", port);
++ return 0;
++}
++
++static int
++delport(struct ip_set *set, const void *data, size_t size,
++ ip_set_ip_t *hash_port)
++{
++ struct ip_set_req_portmap *req =
++ (struct ip_set_req_portmap *) data;
++
++ if (size != sizeof(struct ip_set_req_portmap)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_portmap),
++ size);
++ return -EINVAL;
++ }
++ return __delport(set, req->port, hash_port);
++}
++
++static int
++delport_kernel(struct ip_set *set, const struct sk_buff *skb,
++ u_int32_t flags, ip_set_ip_t *hash_port)
++{
++ ip_set_ip_t port = get_port(skb, flags);
++
++ if (port == INVALID_PORT)
++ return -EINVAL;
++
++ return __delport(set, port, hash_port);
++}
++
++static int create(struct ip_set *set, const void *data, size_t size)
++{
++ int newbytes;
++ struct ip_set_req_portmap_create *req =
++ (struct ip_set_req_portmap_create *) data;
++ struct ip_set_portmap *map;
++
++ if (size != sizeof(struct ip_set_req_portmap_create)) {
++ ip_set_printk("data length wrong (want %zu, have %zu)",
++ sizeof(struct ip_set_req_portmap_create),
++ size);
++ return -EINVAL;
++ }
++
++ DP("from %u to %u", req->from, req->to);
++
++ if (req->from > req->to) {
++ DP("bad port range");
++ return -ENOEXEC;
++ }
++
++ if (req->to - req->from > MAX_RANGE) {
++ ip_set_printk("range too big (max %d ports)",
++ MAX_RANGE);
++ return -ENOEXEC;
++ }
++
++ map = kmalloc(sizeof(struct ip_set_portmap), GFP_KERNEL);
++ if (!map) {
++ DP("out of memory for %d bytes",
++ sizeof(struct ip_set_portmap));
++ return -ENOMEM;
++ }
++ map->first_port = req->from;
++ map->last_port = req->to;
++ newbytes = bitmap_bytes(req->from, req->to);
++ map->members = kmalloc(newbytes, GFP_KERNEL);
++ if (!map->members) {
++ DP("out of memory for %d bytes", newbytes);
++ kfree(map);
++ return -ENOMEM;
++ }
++ memset(map->members, 0, newbytes);
++
++ set->data = map;
++ return 0;
++}
++
++static void destroy(struct ip_set *set)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++
++ kfree(map->members);
++ kfree(map);
++
++ set->data = NULL;
++}
++
++static void flush(struct ip_set *set)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++ memset(map->members, 0, bitmap_bytes(map->first_port, map->last_port));
++}
++
++static void list_header(const struct ip_set *set, void *data)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++ struct ip_set_req_portmap_create *header =
++ (struct ip_set_req_portmap_create *) data;
++
++ DP("list_header %u %u", map->first_port, map->last_port);
++
++ header->from = map->first_port;
++ header->to = map->last_port;
++}
++
++static int list_members_size(const struct ip_set *set)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++
++ return bitmap_bytes(map->first_port, map->last_port);
++}
++
++static void list_members(const struct ip_set *set, void *data)
++{
++ struct ip_set_portmap *map = (struct ip_set_portmap *) set->data;
++ int bytes = bitmap_bytes(map->first_port, map->last_port);
++
++ memcpy(data, map->members, bytes);
++}
++
++static struct ip_set_type ip_set_portmap = {
++ .typename = SETTYPE_NAME,
++ .typecode = IPSET_TYPE_PORT,
++ .protocol_version = IP_SET_PROTOCOL_VERSION,
++ .create = &create,
++ .destroy = &destroy,
++ .flush = &flush,
++ .reqsize = sizeof(struct ip_set_req_portmap),
++ .addip = &addport,
++ .addip_kernel = &addport_kernel,
++ .delip = &delport,
++ .delip_kernel = &delport_kernel,
++ .testip = &testport,
++ .testip_kernel = &testport_kernel,
++ .header_size = sizeof(struct ip_set_req_portmap_create),
++ .list_header = &list_header,
++ .list_members_size = &list_members_size,
++ .list_members = &list_members,
++ .me = THIS_MODULE,
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("portmap type of IP sets");
++
++static int __init init(void)
++{
++ return ip_set_register_set_type(&ip_set_portmap);
++}
++
++static void __exit fini(void)
++{
++ /* FIXME: possible race with ip_set_create() */
++ ip_set_unregister_set_type(&ip_set_portmap);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur linux-2.6.16/net/ipv4/netfilter/ipt_set.c linux-2.6.16-owrt/net/ipv4/netfilter/ipt_set.c
+--- linux-2.6.16/net/ipv4/netfilter/ipt_set.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/netfilter/ipt_set.c 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,112 @@
++/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
++ * Patrick Schaaf <bof@bof.de>
++ * Martin Josefsson <gandalf@wlug.westbo.se>
++ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* Kernel module to match an IP set. */
++
++#include <linux/module.h>
++#include <linux/ip.h>
++#include <linux/skbuff.h>
++
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_set.h>
++#include <linux/netfilter_ipv4/ipt_set.h>
++
++static inline int
++match_set(const struct ipt_set_info *info,
++ const struct sk_buff *skb,
++ int inv)
++{
++ if (ip_set_testip_kernel(info->index, skb, info->flags))
++ inv = !inv;
++ return inv;
++}
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ const struct ipt_set_info_match *info = matchinfo;
++
++ return match_set(&info->match_set,
++ skb,
++ info->match_set.flags[0] & IPSET_MATCH_INV);
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ struct ipt_set_info_match *info =
++ (struct ipt_set_info_match *) matchinfo;
++ ip_set_id_t index;
++
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
++ ip_set_printk("invalid matchsize %d", matchsize);
++ return 0;
++ }
++
++ index = ip_set_get_byindex(info->match_set.index);
++
++ if (index == IP_SET_INVALID_ID) {
++ ip_set_printk("Cannot find set indentified by id %u to match",
++ info->match_set.index);
++ return 0; /* error */
++ }
++ if (info->match_set.flags[IP_SET_MAX_BINDINGS] != 0) {
++ ip_set_printk("That's nasty!");
++ return 0; /* error */
++ }
++
++ return 1;
++}
++
++static void destroy(void *matchinfo, unsigned int matchsize)
++{
++ struct ipt_set_info_match *info = matchinfo;
++
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
++ ip_set_printk("invalid matchsize %d", matchsize);
++ return;
++ }
++
++ ip_set_put(info->match_set.index);
++}
++
++static struct ipt_match set_match = {
++ .name = "set",
++ .match = &match,
++ .checkentry = &checkentry,
++ .destroy = &destroy,
++ .me = THIS_MODULE
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("iptables IP set match module");
++
++static int __init init(void)
++{
++ return ipt_register_match(&set_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&set_match);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur linux-2.6.16/net/ipv4/netfilter/ipt_SET.c linux-2.6.16-owrt/net/ipv4/netfilter/ipt_SET.c
+--- linux-2.6.16/net/ipv4/netfilter/ipt_SET.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/netfilter/ipt_SET.c 2006-03-20 12:53:59.000000000 +0100
+@@ -0,0 +1,128 @@
++/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
++ * Patrick Schaaf <bof@bof.de>
++ * Martin Josefsson <gandalf@wlug.westbo.se>
++ * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
++ *
++ * 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.
++ */
++
++/* ipt_SET.c - netfilter target to manipulate IP sets */
++
++#include <linux/types.h>
++#include <linux/ip.h>
++#include <linux/timer.h>
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/netdevice.h>
++#include <linux/if.h>
++#include <linux/inetdevice.h>
++#include <net/protocol.h>
++#include <net/checksum.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/netfilter_ipv4/ip_nat_rule.h>
++#include <linux/netfilter_ipv4/ipt_set.h>
++
++static unsigned int
++target(struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ unsigned int hooknum,
++ const void *targinfo,
++ void *userinfo)
++{
++ const struct ipt_set_info_target *info = targinfo;
++
++ if (info->add_set.index != IP_SET_INVALID_ID)
++ ip_set_addip_kernel(info->add_set.index,
++ *pskb,
++ info->add_set.flags);
++ if (info->del_set.index != IP_SET_INVALID_ID)
++ ip_set_delip_kernel(info->del_set.index,
++ *pskb,
++ info->del_set.flags);
++
++ return IPT_CONTINUE;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize, unsigned int hook_mask)
++{
++ struct ipt_set_info_target *info =
++ (struct ipt_set_info_target *) targinfo;
++ ip_set_id_t index;
++
++ if (targinfosize != IPT_ALIGN(sizeof(*info))) {
++ DP("bad target info size %u", targinfosize);
++ return 0;
++ }
++
++ if (info->add_set.index != IP_SET_INVALID_ID) {
++ index = ip_set_get_byindex(info->add_set.index);
++ if (index == IP_SET_INVALID_ID) {
++ ip_set_printk("cannot find add_set index %u as target",
++ info->add_set.index);
++ return 0; /* error */
++ }
++ }
++
++ if (info->del_set.index != IP_SET_INVALID_ID) {
++ index = ip_set_get_byindex(info->del_set.index);
++ if (index == IP_SET_INVALID_ID) {
++ ip_set_printk("cannot find del_set index %u as target",
++ info->del_set.index);
++ return 0; /* error */
++ }
++ }
++ if (info->add_set.flags[IP_SET_MAX_BINDINGS] != 0
++ || info->del_set.flags[IP_SET_MAX_BINDINGS] != 0) {
++ ip_set_printk("That's nasty!");
++ return 0; /* error */
++ }
++
++ return 1;
++}
++
++static void destroy(void *targetinfo, unsigned int targetsize)
++{
++ struct ipt_set_info_target *info = targetinfo;
++
++ if (targetsize != IPT_ALIGN(sizeof(struct ipt_set_info_target))) {
++ ip_set_printk("invalid targetsize %d", targetsize);
++ return;
++ }
++
++ if (info->add_set.index != IP_SET_INVALID_ID)
++ ip_set_put(info->add_set.index);
++ if (info->del_set.index != IP_SET_INVALID_ID)
++ ip_set_put(info->del_set.index);
++}
++
++static struct ipt_target SET_target = {
++ .name = "SET",
++ .target = target,
++ .checkentry = checkentry,
++ .destroy = destroy,
++ .me = THIS_MODULE
++};
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
++MODULE_DESCRIPTION("iptables IP set target module");
++
++static int __init init(void)
++{
++ return ipt_register_target(&SET_target);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&SET_target);
++}
++
++module_init(init);
++module_exit(fini);
+diff -Nur linux-2.6.16/net/ipv4/netfilter/Kconfig linux-2.6.16-owrt/net/ipv4/netfilter/Kconfig
+--- linux-2.6.16/net/ipv4/netfilter/Kconfig 2006-03-20 12:52:42.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/netfilter/Kconfig 2006-03-20 12:53:59.000000000 +0100
+@@ -623,5 +623,106 @@
+ Allows altering the ARP packet payload: source and destination
+ hardware and network addresses.
+
++config IP_NF_SET
++ tristate "IP set support"
++ depends on INET && NETFILTER
++ help
++ This option adds IP set support to the kernel.
++ In order to define and use sets, you need the userspace utility
++ ipset(8).
++
++ To compile it as a module, choose M here. If unsure, say N.
++
++config IP_NF_SET_MAX
++ int "Maximum number of IP sets"
++ default 256
++ range 2 65534
++ depends on IP_NF_SET
++ help
++ You can define here default value of the maximum number
++ of IP sets for the kernel.
++
++ The value can be overriden by the 'max_sets' module
++ parameter of the 'ip_set' module.
++
++config IP_NF_SET_HASHSIZE
++ int "Hash size for bindings of IP sets"
++ default 1024
++ depends on IP_NF_SET
++ help
++ You can define here default value of the hash size for
++ bindings of IP sets.
++
++ The value can be overriden by the 'hash_size' module
++ parameter of the 'ip_set' module.
++
++config IP_NF_SET_IPMAP
++ tristate "ipmap set support"
++ depends on IP_NF_SET
++ help
++ This option adds the ipmap set type support.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
++config IP_NF_SET_MACIPMAP
++ tristate "macipmap set support"
++ depends on IP_NF_SET
++ help
++ This option adds the macipmap set type support.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
++config IP_NF_SET_PORTMAP
++ tristate "portmap set support"
++ depends on IP_NF_SET
++ help
++ This option adds the portmap set type support.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
++config IP_NF_SET_IPHASH
++ tristate "iphash set support"
++ depends on IP_NF_SET
++ help
++ This option adds the iphash set type support.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
++config IP_NF_SET_NETHASH
++ tristate "nethash set support"
++ depends on IP_NF_SET
++ help
++ This option adds the nethash set type support.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
++config IP_NF_SET_IPTREE
++ tristate "iptree set support"
++ depends on IP_NF_SET
++ help
++ This option adds the iptree set type support.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
++config IP_NF_MATCH_SET
++ tristate "set match support"
++ depends on IP_NF_SET
++ help
++ Set matching matches against given IP sets.
++ You need the ipset utility to create and set up the sets.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
++config IP_NF_TARGET_SET
++ tristate "SET target support"
++ depends on IP_NF_SET
++ help
++ The SET target makes possible to add/delete entries
++ in IP sets.
++ You need the ipset utility to create and set up the sets.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
++
+ endmenu
+
+diff -Nur linux-2.6.16/net/ipv4/netfilter/Makefile linux-2.6.16-owrt/net/ipv4/netfilter/Makefile
+--- linux-2.6.16/net/ipv4/netfilter/Makefile 2006-03-20 12:52:42.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/netfilter/Makefile 2006-03-20 12:56:30.000000000 +0100
+@@ -47,6 +47,7 @@
+
+ # matches
+ obj-$(CONFIG_IP_NF_MATCH_HASHLIMIT) += ipt_hashlimit.o
++obj-$(CONFIG_IP_NF_MATCH_SET) += ipt_set.o
+ obj-$(CONFIG_IP_NF_MATCH_IPRANGE) += ipt_iprange.o
+ obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
+ obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
+@@ -74,6 +75,17 @@
+ obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
+ obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
+ obj-$(CONFIG_IP_NF_TARGET_TCPMSS) += ipt_TCPMSS.o
++obj-$(CONFIG_IP_NF_TARGET_SET) += ipt_SET.o
++
++# sets
++obj-$(CONFIG_IP_NF_SET) += ip_set.o
++obj-$(CONFIG_IP_NF_SET_IPMAP) += ip_set_ipmap.o
++obj-$(CONFIG_IP_NF_SET_PORTMAP) += ip_set_portmap.o
++obj-$(CONFIG_IP_NF_SET_MACIPMAP) += ip_set_macipmap.o
++obj-$(CONFIG_IP_NF_SET_IPHASH) += ip_set_iphash.o
++obj-$(CONFIG_IP_NF_SET_NETHASH) += ip_set_nethash.o
++obj-$(CONFIG_IP_NF_SET_IPTREE) += ip_set_iptree.o
++
+ obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
+ obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
+
diff --git a/target/linux/generic-2.6/patches/105-netfilter_time.patch b/target/linux/generic-2.6/patches/105-netfilter_time.patch
new file mode 100644
index 0000000..34257ee
--- /dev/null
+++ b/target/linux/generic-2.6/patches/105-netfilter_time.patch
@@ -0,0 +1,241 @@
+diff -urN linux-2.6.15-rc6.orig/net/ipv4/netfilter/ipt_time.c linux-2.6.15-rc6/net/ipv4/netfilter/ipt_time.c
+--- linux-2.6.15-rc6.orig/net/ipv4/netfilter/ipt_time.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-rc6/net/ipv4/netfilter/ipt_time.c 2006-01-07 13:02:59.000000000 +0100
+@@ -0,0 +1,178 @@
++/*
++ This is a module which is used for time matching
++ It is using some modified code from dietlibc (localtime() function)
++ that you can find at http://www.fefe.de/dietlibc/
++ This file is distributed under the terms of the GNU General Public
++ License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL
++ 2001-05-04 Fabrice MARIE <fabrice@netfilter.org> : initial development.
++ 2001-21-05 Fabrice MARIE <fabrice@netfilter.org> : bug fix in the match code,
++ thanks to "Zeng Yu" <zengy@capitel.com.cn> for bug report.
++ 2001-26-09 Fabrice MARIE <fabrice@netfilter.org> : force the match to be in LOCAL_IN or PRE_ROUTING only.
++ 2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack,
++ added Nguyen Dang Phuoc Dong <dongnd@tlnet.com.vn> patch to support timezones.
++ 2004-05-02 Fabrice : added support for date matching, from an idea of Fabien COELHO.
++*/
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_time.h>
++#include <linux/time.h>
++
++MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
++MODULE_DESCRIPTION("Match arrival timestamp/date");
++MODULE_LICENSE("GPL");
++
++struct tm
++{
++ int tm_sec; /* Seconds. [0-60] (1 leap second) */
++ int tm_min; /* Minutes. [0-59] */
++ int tm_hour; /* Hours. [0-23] */
++ int tm_mday; /* Day. [1-31] */
++ int tm_mon; /* Month. [0-11] */
++ int tm_year; /* Year - 1900. */
++ int tm_wday; /* Day of week. [0-6] */
++ int tm_yday; /* Days in year.[0-365] */
++ int tm_isdst; /* DST. [-1/0/1]*/
++
++ long int tm_gmtoff; /* we don't care, we count from GMT */
++ const char *tm_zone; /* we don't care, we count from GMT */
++};
++
++void
++localtime(const u32 time, struct tm *r);
++
++static int
++match(const struct sk_buff *skb,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *matchinfo,
++ int offset,
++ int *hotdrop)
++{
++ const struct ipt_time_info *info = matchinfo; /* match info for rule */
++ struct tm currenttime; /* time human readable */
++ u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1};
++ u_int16_t packet_time;
++
++ /* We might not have a timestamp, get one */
++ if (skb->tstamp.off_sec == 0)
++ __net_timestamp((struct sk_buff *)skb);
++
++ /* First we make sure we are in the date start-stop boundaries */
++ if ((skb->tstamp.off_sec < info->date_start) || (skb->tstamp.off_sec > info->date_stop))
++ return 0; /* We are outside the date boundaries */
++
++ /* Transform the timestamp of the packet, in a human readable form */
++ localtime(skb->tstamp.off_sec, &currenttime);
++
++ /* check if we match this timestamp, we start by the days... */
++ if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday])
++ return 0; /* the day doesn't match */
++
++ /* ... check the time now */
++ packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min;
++ if ((packet_time < info->time_start) || (packet_time > info->time_stop))
++ return 0;
++
++ /* here we match ! */
++ return 1;
++}
++
++static int
++checkentry(const char *tablename,
++ const struct ipt_ip *ip,
++ void *matchinfo,
++ unsigned int matchsize,
++ unsigned int hook_mask)
++{
++ struct ipt_time_info *info = matchinfo; /* match info for rule */
++
++ /* First, check that we are in the correct hooks */
++ if (hook_mask
++ & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT)))
++ {
++ printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n");
++ return 0;
++ }
++
++ /* Check the size */
++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_time_info)))
++ return 0;
++ /* Now check the coherence of the data ... */
++ if ((info->time_start > 1439) || /* 23*60+59 = 1439*/
++ (info->time_stop > 1439))
++ {
++ printk(KERN_WARNING "ipt_time: invalid argument\n");
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_match time_match = {
++ .name = "time",
++ .match = &match,
++ .checkentry = &checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ printk("ipt_time loading\n");
++ return ipt_register_match(&time_match);
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_match(&time_match);
++ printk("ipt_time unloaded\n");
++}
++
++module_init(init);
++module_exit(fini);
++
++
++/* The part below is borowed and modified from dietlibc */
++
++/* seconds per day */
++#define SPD 24*60*60
++
++void
++localtime(const u32 time, struct tm *r) {
++ u32 i, timep;
++ extern struct timezone sys_tz;
++ const unsigned int __spm[12] =
++ { 0,
++ (31),
++ (31+28),
++ (31+28+31),
++ (31+28+31+30),
++ (31+28+31+30+31),
++ (31+28+31+30+31+30),
++ (31+28+31+30+31+30+31),
++ (31+28+31+30+31+30+31+31),
++ (31+28+31+30+31+30+31+31+30),
++ (31+28+31+30+31+30+31+31+30+31),
++ (31+28+31+30+31+30+31+31+30+31+30),
++ };
++ register u32 work;
++
++ timep = time - (sys_tz.tz_minuteswest * 60);
++ work=timep%(SPD);
++ r->tm_sec=work%60; work/=60;
++ r->tm_min=work%60; r->tm_hour=work/60;
++ work=timep/(SPD);
++ r->tm_wday=(4+work)%7;
++ for (i=1970; ; ++i) {
++ register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365;
++ if (work>k)
++ work-=k;
++ else
++ break;
++ }
++ r->tm_year=i-1900;
++ for (i=11; i && __spm[i]>work; --i) ;
++ r->tm_mon=i;
++ r->tm_mday=work-__spm[i]+1;
++}
+diff -urN linux-2.6.15-rc6.orig/net/ipv4/netfilter/Kconfig linux-2.6.15-rc6/net/ipv4/netfilter/Kconfig
+--- linux-2.6.15-rc6.orig/net/ipv4/netfilter/Kconfig 2006-01-07 13:00:21.000000000 +0100
++++ linux-2.6.15-rc6/net/ipv4/netfilter/Kconfig 2006-01-07 13:05:07.000000000 +0100
+@@ -278,6 +278,22 @@
+
+ To compile it as a module, choose M here. If unsure, say N.
+
++
++config IP_NF_MATCH_TIME
++ tristate 'TIME match support'
++ depends on IP_NF_IPTABLES
++ help
++ This option adds a `time' match, which allows you
++ to match based on the packet arrival time/date
++ (arrival time/date at the machine which netfilter is running on) or
++ departure time/date (for locally generated packets).
++
++ If you say Y here, try iptables -m time --help for more information.
++ If you want to compile it as a module, say M here and read
++
++ Documentation/modules.txt. If unsure, say `N'.
++
++
+ config IP_NF_MATCH_RECENT
+ tristate "recent match support"
+ depends on IP_NF_IPTABLES
+diff -urN linux-2.6.15-rc6.orig/net/ipv4/netfilter/Makefile linux-2.6.15-rc6/net/ipv4/netfilter/Makefile
+--- linux-2.6.15-rc6.orig/net/ipv4/netfilter/Makefile 2006-01-07 13:00:21.000000000 +0100
++++ linux-2.6.15-rc6/net/ipv4/netfilter/Makefile 2006-01-07 13:03:50.000000000 +0100
+@@ -58,6 +58,7 @@
+ obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o
+ obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o
+ obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
++obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o
+ obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o
+ obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
+ obj-$(CONFIG_IP_NF_MATCH_DSCP) += ipt_dscp.o
+diff -urN linux-2.6.15-rc6.orig/include/linux/netfilter_ipv4/ipt_time.h linux-2.6.15-rc6/include/linux/netfilter_ipv4/ipt_time.h
+--- linux-2.6.15-rc6.orig/include/linux/netfilter_ipv4/ipt_time.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.15-rc6/include/linux/netfilter_ipv4/ipt_time.h 2006-01-07 13:02:14.000000000 +0100
+@@ -0,0 +1,18 @@
++#ifndef __ipt_time_h_included__
++#define __ipt_time_h_included__
++
++
++struct ipt_time_info {
++ u_int8_t days_match; /* 1 bit per day. -SMTWTFS */
++ u_int16_t time_start; /* 0 < time_start < 23*60+59 = 1439 */
++ u_int16_t time_stop; /* 0:0 < time_stat < 23:59 */
++
++ /* FIXME: Keep this one for userspace iptables binary compability: */
++ u_int8_t kerneltime; /* ignore skb time (and use kerneltime) or not. */
++
++ time_t date_start;
++ time_t date_stop;
++};
++
++
++#endif /* __ipt_time_h_included__ */
diff --git a/target/linux/generic-2.6/patches/106-netfilter_imq.patch b/target/linux/generic-2.6/patches/106-netfilter_imq.patch
new file mode 100644
index 0000000..8114db6
--- /dev/null
+++ b/target/linux/generic-2.6/patches/106-netfilter_imq.patch
@@ -0,0 +1,885 @@
+diff -Nur linux-2.6.16/drivers/net/imq.c linux-2.6.16-owrt/drivers/net/imq.c
+--- linux-2.6.16/drivers/net/imq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/drivers/net/imq.c 2006-03-20 12:59:23.000000000 +0100
+@@ -0,0 +1,403 @@
++/*
++ * Pseudo-driver for the intermediate queue device.
++ *
++ * 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.
++ *
++ * Authors: Patrick McHardy, <kaber@trash.net>
++ *
++ * The first version was written by Martin Devera, <devik@cdi.cz>
++ *
++ * Credits: Jan Rafaj <imq2t@cedric.vabo.cz>
++ * - Update patch to 2.4.21
++ * Sebastian Strollo <sstrollo@nortelnetworks.com>
++ * - Fix "Dead-loop on netdevice imq"-issue
++ * Marcel Sebek <sebek64@post.cz>
++ * - Update to 2.6.2-rc1
++ *
++ * After some time of inactivity there is a group taking care
++ * of IMQ again: http://www.linuximq.net
++ *
++ *
++ * 2004/06/30 - New version of IMQ patch to kernels <=2.6.7 including
++ * the following changes:
++ *
++ * - Correction of ipv6 support "+"s issue (Hasso Tepper)
++ * - Correction of imq_init_devs() issue that resulted in
++ * kernel OOPS unloading IMQ as module (Norbert Buchmuller)
++ * - Addition of functionality to choose number of IMQ devices
++ * during kernel config (Andre Correa)
++ * - Addition of functionality to choose how IMQ hooks on
++ * PRE and POSTROUTING (after or before NAT) (Andre Correa)
++ * - Cosmetic corrections (Norbert Buchmuller) (Andre Correa)
++ *
++ *
++ * 2005/12/16 - IMQ versions between 2.6.7 and 2.6.13 were
++ * released with almost no problems. 2.6.14-x was released
++ * with some important changes: nfcache was removed; After
++ * some weeks of trouble we figured out that some IMQ fields
++ * in skb were missing in skbuff.c - skb_clone and copy_skb_header.
++ * These functions are correctly patched by this new patch version.
++ *
++ * Thanks for all who helped to figure out all the problems with
++ * 2.6.14.x: Patrick McHardy, Rune Kock, VeNoMouS, Max CtRiX,
++ * Kevin Shanahan, Richard Lucassen, Valery Dachev (hopefully
++ * I didn't forget anybody). I apologize again for my lack of time.
++ *
++ * More info at: http://www.linuximq.net/ (Andre Correa)
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/moduleparam.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/if_arp.h>
++#include <linux/netfilter.h>
++#include <linux/netfilter_ipv4.h>
++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
++ #include <linux/netfilter_ipv6.h>
++#endif
++#include <linux/imq.h>
++#include <net/pkt_sched.h>
++
++static nf_hookfn imq_nf_hook;
++
++static struct nf_hook_ops imq_ingress_ipv4 = {
++ .hook = imq_nf_hook,
++ .owner = THIS_MODULE,
++ .pf = PF_INET,
++ .hooknum = NF_IP_PRE_ROUTING,
++#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
++ .priority = NF_IP_PRI_MANGLE + 1
++#else
++ .priority = NF_IP_PRI_NAT_DST + 1
++#endif
++};
++
++static struct nf_hook_ops imq_egress_ipv4 = {
++ .hook = imq_nf_hook,
++ .owner = THIS_MODULE,
++ .pf = PF_INET,
++ .hooknum = NF_IP_POST_ROUTING,
++#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
++ .priority = NF_IP_PRI_LAST
++#else
++ .priority = NF_IP_PRI_NAT_SRC - 1
++#endif
++};
++
++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
++static struct nf_hook_ops imq_ingress_ipv6 = {
++ .hook = imq_nf_hook,
++ .owner = THIS_MODULE,
++ .pf = PF_INET6,
++ .hooknum = NF_IP6_PRE_ROUTING,
++#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
++ .priority = NF_IP6_PRI_MANGLE + 1
++#else
++ .priority = NF_IP6_PRI_NAT_DST + 1
++#endif
++};
++
++static struct nf_hook_ops imq_egress_ipv6 = {
++ .hook = imq_nf_hook,
++ .owner = THIS_MODULE,
++ .pf = PF_INET6,
++ .hooknum = NF_IP6_POST_ROUTING,
++#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
++ .priority = NF_IP6_PRI_LAST
++#else
++ .priority = NF_IP6_PRI_NAT_SRC - 1
++#endif
++};
++#endif
++
++#if defined(CONFIG_IMQ_NUM_DEVS)
++static unsigned int numdevs = CONFIG_IMQ_NUM_DEVS;
++#else
++static unsigned int numdevs = 2;
++#endif
++
++static struct net_device *imq_devs;
++
++static struct net_device_stats *imq_get_stats(struct net_device *dev)
++{
++ return (struct net_device_stats *)dev->priv;
++}
++
++/* called for packets kfree'd in qdiscs at places other than enqueue */
++static void imq_skb_destructor(struct sk_buff *skb)
++{
++ struct nf_info *info = skb->nf_info;
++
++ if (info) {
++ if (info->indev)
++ dev_put(info->indev);
++ if (info->outdev)
++ dev_put(info->outdev);
++ kfree(info);
++ }
++}
++
++static int imq_dev_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ struct net_device_stats *stats = (struct net_device_stats*) dev->priv;
++
++ stats->tx_bytes += skb->len;
++ stats->tx_packets++;
++
++ skb->imq_flags = 0;
++ skb->destructor = NULL;
++
++ dev->trans_start = jiffies;
++ nf_reinject(skb, skb->nf_info, NF_ACCEPT);
++ return 0;
++}
++
++static int imq_nf_queue(struct sk_buff *skb, struct nf_info *info, unsigned queue_num, void *data)
++{
++ struct net_device *dev;
++ struct net_device_stats *stats;
++ struct sk_buff *skb2 = NULL;
++ struct Qdisc *q;
++ unsigned int index = skb->imq_flags&IMQ_F_IFMASK;
++ int ret = -1;
++
++ if (index > numdevs)
++ return -1;
++
++ dev = imq_devs + index;
++ if (!(dev->flags & IFF_UP)) {
++ skb->imq_flags = 0;
++ nf_reinject(skb, info, NF_ACCEPT);
++ return 0;
++ }
++ dev->last_rx = jiffies;
++
++ if (skb->destructor) {
++ skb2 = skb;
++ skb = skb_clone(skb, GFP_ATOMIC);
++ if (!skb)
++ return -1;
++ }
++ skb->nf_info = info;
++
++ stats = (struct net_device_stats *)dev->priv;
++ stats->rx_bytes+= skb->len;
++ stats->rx_packets++;
++
++ spin_lock_bh(&dev->queue_lock);
++ q = dev->qdisc;
++ if (q->enqueue) {
++ q->enqueue(skb_get(skb), q);
++ if (skb_shared(skb)) {
++ skb->destructor = imq_skb_destructor;
++ kfree_skb(skb);
++ ret = 0;
++ }
++ }
++ if (spin_is_locked(&dev->xmit_lock))
++ netif_schedule(dev);
++ else
++
++ while (!netif_queue_stopped(dev) &&
++ qdisc_restart(dev)<0)
++ /* NOTHING */;
++
++ spin_unlock_bh(&dev->queue_lock);
++
++ if (skb2)
++ kfree_skb(ret ? skb : skb2);
++
++ return ret;
++}
++
++static struct nf_queue_handler nfqh = {
++ .name = "imq",
++ .outfn = imq_nf_queue,
++};
++
++static unsigned int imq_nf_hook(unsigned int hook, struct sk_buff **pskb,
++ const struct net_device *indev,
++ const struct net_device *outdev,
++ int (*okfn)(struct sk_buff *))
++{
++ if ((*pskb)->imq_flags & IMQ_F_ENQUEUE)
++ return NF_QUEUE;
++
++ return NF_ACCEPT;
++}
++
++
++static int __init imq_init_hooks(void)
++{
++ int err;
++
++ err = nf_register_queue_handler(PF_INET, &nfqh);
++ if (err > 0)
++ goto err1;
++ if ((err = nf_register_hook(&imq_ingress_ipv4)))
++ goto err2;
++ if ((err = nf_register_hook(&imq_egress_ipv4)))
++ goto err3;
++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
++ if ((err = nf_register_queue_handler(PF_INET6, &nfqh)))
++ goto err4;
++ if ((err = nf_register_hook(&imq_ingress_ipv6)))
++ goto err5;
++ if ((err = nf_register_hook(&imq_egress_ipv6)))
++ goto err6;
++#endif
++
++ return 0;
++
++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
++err6:
++ nf_unregister_hook(&imq_ingress_ipv6);
++err5:
++ nf_unregister_queue_handler(PF_INET6);
++err4:
++ nf_unregister_hook(&imq_egress_ipv6);
++#endif
++err3:
++ nf_unregister_hook(&imq_ingress_ipv4);
++err2:
++ nf_unregister_queue_handler(PF_INET);
++err1:
++ return err;
++}
++
++static void __exit imq_unhook(void)
++{
++ nf_unregister_hook(&imq_ingress_ipv4);
++ nf_unregister_hook(&imq_egress_ipv4);
++ nf_unregister_queue_handler(PF_INET);
++#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
++ nf_unregister_hook(&imq_ingress_ipv6);
++ nf_unregister_hook(&imq_egress_ipv6);
++ nf_unregister_queue_handler(PF_INET6);
++#endif
++}
++
++static int __init imq_dev_init(struct net_device *dev)
++{
++ dev->hard_start_xmit = imq_dev_xmit;
++ dev->type = ARPHRD_VOID;
++ dev->mtu = 1500;
++ dev->tx_queue_len = 30;
++ dev->flags = IFF_NOARP;
++ dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
++ if (dev->priv == NULL)
++ return -ENOMEM;
++ memset(dev->priv, 0, sizeof(struct net_device_stats));
++ dev->get_stats = imq_get_stats;
++
++ return 0;
++}
++
++static void imq_dev_uninit(struct net_device *dev)
++{
++ kfree(dev->priv);
++}
++
++static int __init imq_init_devs(void)
++{
++ struct net_device *dev;
++ int i,j;
++ j = numdevs;
++
++ if (!numdevs || numdevs > IMQ_MAX_DEVS) {
++ printk(KERN_ERR "IMQ: numdevs has to be betweed 1 and %u\n",
++ IMQ_MAX_DEVS);
++ return -EINVAL;
++ }
++
++ imq_devs = kmalloc(sizeof(struct net_device) * numdevs, GFP_KERNEL);
++ if (!imq_devs)
++ return -ENOMEM;
++ memset(imq_devs, 0, sizeof(struct net_device) * numdevs);
++
++ /* we start counting at zero */
++ numdevs--;
++
++ for (i = 0, dev = imq_devs; i <= numdevs; i++, dev++) {
++ SET_MODULE_OWNER(dev);
++ strcpy(dev->name, "imq%d");
++ dev->init = imq_dev_init;
++ dev->uninit = imq_dev_uninit;
++
++ if (register_netdev(dev) < 0)
++ goto err_register;
++ }
++ printk(KERN_INFO "IMQ starting with %u devices...\n", j);
++ return 0;
++
++err_register:
++ for (; i; i--)
++ unregister_netdev(--dev);
++ kfree(imq_devs);
++ return -EIO;
++}
++
++static void imq_cleanup_devs(void)
++{
++ int i;
++ struct net_device *dev = imq_devs;
++
++ for (i = 0; i <= numdevs; i++)
++ unregister_netdev(dev++);
++
++ kfree(imq_devs);
++}
++
++static int __init imq_init_module(void)
++{
++ int err;
++
++ if ((err = imq_init_devs())) {
++ printk(KERN_ERR "IMQ: Error trying imq_init_devs()\n");
++ return err;
++ }
++ if ((err = imq_init_hooks())) {
++ printk(KERN_ERR "IMQ: Error trying imq_init_hooks()\n");
++ imq_cleanup_devs();
++ return err;
++ }
++
++ printk(KERN_INFO "IMQ driver loaded successfully.\n");
++
++#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
++ printk(KERN_INFO "\tHooking IMQ before NAT on PREROUTING.\n");
++#else
++ printk(KERN_INFO "\tHooking IMQ after NAT on PREROUTING.\n");
++#endif
++#if defined(CONFIG_IMQ_BEHAVIOR_AB) || defined(CONFIG_IMQ_BEHAVIOR_BB)
++ printk(KERN_INFO "\tHooking IMQ before NAT on POSTROUTING.\n");
++#else
++ printk(KERN_INFO "\tHooking IMQ after NAT on POSTROUTING.\n");
++#endif
++
++ return 0;
++}
++
++static void __exit imq_cleanup_module(void)
++{
++ imq_unhook();
++ imq_cleanup_devs();
++ printk(KERN_INFO "IMQ driver unloaded successfully.\n");
++}
++
++
++module_init(imq_init_module);
++module_exit(imq_cleanup_module);
++
++module_param(numdevs, int, 0);
++MODULE_PARM_DESC(numdevs, "number of IMQ devices (how many imq* devices will be created)");
++MODULE_AUTHOR("http://www.linuximq.net");
++MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See http://www.linuximq.net/ for more information.");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.6.16/drivers/net/Kconfig linux-2.6.16-owrt/drivers/net/Kconfig
+--- linux-2.6.16/drivers/net/Kconfig 2006-03-20 06:53:29.000000000 +0100
++++ linux-2.6.16-owrt/drivers/net/Kconfig 2006-03-20 12:59:23.000000000 +0100
+@@ -93,6 +93,129 @@
+ To compile this driver as a module, choose M here: the module
+ will be called eql. If unsure, say N.
+
++config IMQ
++ tristate "IMQ (intermediate queueing device) support"
++ depends on NETDEVICES && NETFILTER
++ ---help---
++ The IMQ device(s) is used as placeholder for QoS queueing disciplines.
++ Every packet entering/leaving the IP stack can be directed through
++ the IMQ device where it's enqueued/dequeued to the attached qdisc.
++ This allows you to treat network devices as classes and distribute
++ bandwidth among them. Iptables is used to specify through which IMQ
++ device, if any, packets travel.
++
++ More information at: http://www.linuximq.net/
++
++ To compile this driver as a module, choose M here: the module
++ will be called imq. If unsure, say N.
++
++choice
++ prompt "IMQ behavior (PRE/POSTROUTING)"
++ depends on IMQ
++ default IMQ_BEHAVIOR_BA
++ help
++
++ This settings defines how IMQ behaves in respect to its
++ hooking in PREROUTING and POSTROUTING.
++
++ IMQ can work in any of the following ways:
++
++ PREROUTING | POSTROUTING
++ -----------------|-------------------
++ #1 After NAT | After NAT
++ #2 After NAT | Before NAT
++ #3 Before NAT | After NAT
++ #4 Before NAT | Before NAT
++
++ The default behavior is to hook before NAT on PREROUTING
++ and after NAT on POSTROUTING (#3).
++
++ This settings are specially usefull when trying to use IMQ
++ to shape NATed clients.
++
++ More information can be found at: www.linuximq.net
++
++ If not sure leave the default settings alone.
++
++config IMQ_BEHAVIOR_AA
++ bool "IMQ AA"
++ help
++ This settings defines how IMQ behaves in respect to its
++ hooking in PREROUTING and POSTROUTING.
++
++ Choosing this option will make IMQ hook like this:
++
++ PREROUTING: After NAT
++ POSTROUTING: After NAT
++
++ More information can be found at: www.linuximq.net
++
++ If not sure leave the default settings alone.
++
++config IMQ_BEHAVIOR_AB
++ bool "IMQ AB"
++ help
++ This settings defines how IMQ behaves in respect to its
++ hooking in PREROUTING and POSTROUTING.
++
++ Choosing this option will make IMQ hook like this:
++
++ PREROUTING: After NAT
++ POSTROUTING: Before NAT
++
++ More information can be found at: www.linuximq.net
++
++ If not sure leave the default settings alone.
++
++config IMQ_BEHAVIOR_BA
++ bool "IMQ BA"
++ help
++ This settings defines how IMQ behaves in respect to its
++ hooking in PREROUTING and POSTROUTING.
++
++ Choosing this option will make IMQ hook like this:
++
++ PREROUTING: Before NAT
++ POSTROUTING: After NAT
++
++ More information can be found at: www.linuximq.net
++
++ If not sure leave the default settings alone.
++
++config IMQ_BEHAVIOR_BB
++ bool "IMQ BB"
++ help
++ This settings defines how IMQ behaves in respect to its
++ hooking in PREROUTING and POSTROUTING.
++
++ Choosing this option will make IMQ hook like this:
++
++ PREROUTING: Before NAT
++ POSTROUTING: Before NAT
++
++ More information can be found at: www.linuximq.net
++
++ If not sure leave the default settings alone.
++
++endchoice
++
++config IMQ_NUM_DEVS
++
++ int "Number of IMQ devices"
++ range 2 8
++ depends on IMQ
++ default "2"
++ help
++
++ This settings defines how many IMQ devices will be
++ created.
++
++ The default value is 2.
++
++ More information can be found at: www.linuximq.net
++
++ If not sure leave the default settings alone.
++
+ config TUN
+ tristate "Universal TUN/TAP device driver support"
+ select CRC32
+diff -Nur linux-2.6.16/drivers/net/Makefile linux-2.6.16-owrt/drivers/net/Makefile
+--- linux-2.6.16/drivers/net/Makefile 2006-03-20 06:53:29.000000000 +0100
++++ linux-2.6.16-owrt/drivers/net/Makefile 2006-03-20 13:00:13.000000000 +0100
+@@ -125,6 +125,7 @@
+ endif
+
+ obj-$(CONFIG_DUMMY) += dummy.o
++obj-$(CONFIG_IMQ) += imq.o
+ obj-$(CONFIG_IFB) += ifb.o
+ obj-$(CONFIG_DE600) += de600.o
+ obj-$(CONFIG_DE620) += de620.o
+diff -Nur linux-2.6.16/include/linux/imq.h linux-2.6.16-owrt/include/linux/imq.h
+--- linux-2.6.16/include/linux/imq.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/imq.h 2006-03-20 12:59:23.000000000 +0100
+@@ -0,0 +1,9 @@
++#ifndef _IMQ_H
++#define _IMQ_H
++
++#define IMQ_MAX_DEVS 16
++
++#define IMQ_F_IFMASK 0x7f
++#define IMQ_F_ENQUEUE 0x80
++
++#endif /* _IMQ_H */
+diff -Nur linux-2.6.16/include/linux/netfilter_ipv4/ipt_IMQ.h linux-2.6.16-owrt/include/linux/netfilter_ipv4/ipt_IMQ.h
+--- linux-2.6.16/include/linux/netfilter_ipv4/ipt_IMQ.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/netfilter_ipv4/ipt_IMQ.h 2006-03-20 12:59:23.000000000 +0100
+@@ -0,0 +1,8 @@
++#ifndef _IPT_IMQ_H
++#define _IPT_IMQ_H
++
++struct ipt_imq_info {
++ unsigned int todev; /* target imq device */
++};
++
++#endif /* _IPT_IMQ_H */
+diff -Nur linux-2.6.16/include/linux/netfilter_ipv6/ip6t_IMQ.h linux-2.6.16-owrt/include/linux/netfilter_ipv6/ip6t_IMQ.h
+--- linux-2.6.16/include/linux/netfilter_ipv6/ip6t_IMQ.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/netfilter_ipv6/ip6t_IMQ.h 2006-03-20 12:59:23.000000000 +0100
+@@ -0,0 +1,8 @@
++#ifndef _IP6T_IMQ_H
++#define _IP6T_IMQ_H
++
++struct ip6t_imq_info {
++ unsigned int todev; /* target imq device */
++};
++
++#endif /* _IP6T_IMQ_H */
+diff -Nur linux-2.6.16/include/linux/skbuff.h linux-2.6.16-owrt/include/linux/skbuff.h
+--- linux-2.6.16/include/linux/skbuff.h 2006-03-20 06:53:29.000000000 +0100
++++ linux-2.6.16-owrt/include/linux/skbuff.h 2006-03-20 12:59:23.000000000 +0100
+@@ -275,6 +275,10 @@
+ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+ struct sk_buff *nfct_reasm;
+ #endif
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++ unsigned char imq_flags;
++ struct nf_info *nf_info;
++#endif
+ #ifdef CONFIG_BRIDGE_NETFILTER
+ struct nf_bridge_info *nf_bridge;
+ #endif
+diff -Nur linux-2.6.16/net/core/skbuff.c linux-2.6.16-owrt/net/core/skbuff.c
+--- linux-2.6.16/net/core/skbuff.c 2006-03-20 06:53:29.000000000 +0100
++++ linux-2.6.16-owrt/net/core/skbuff.c 2006-03-20 12:59:23.000000000 +0100
+@@ -425,6 +425,10 @@
+ C(nfct_reasm);
+ nf_conntrack_get_reasm(skb->nfct_reasm);
+ #endif
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++ C(imq_flags);
++ C(nf_info);
++#endif /*CONFIG_IMQ*/
+ #ifdef CONFIG_BRIDGE_NETFILTER
+ C(nf_bridge);
+ nf_bridge_get(skb->nf_bridge);
+@@ -489,6 +493,10 @@
+ #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
+ new->ipvs_property = old->ipvs_property;
+ #endif
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++ new->imq_flags = old->imq_flags;
++ new->nf_info = old->nf_info;
++#endif /*CONFIG_IMQ*/
+ #ifdef CONFIG_BRIDGE_NETFILTER
+ new->nf_bridge = old->nf_bridge;
+ nf_bridge_get(old->nf_bridge);
+diff -Nur linux-2.6.16/net/ipv4/netfilter/ipt_IMQ.c linux-2.6.16-owrt/net/ipv4/netfilter/ipt_IMQ.c
+--- linux-2.6.16/net/ipv4/netfilter/ipt_IMQ.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/netfilter/ipt_IMQ.c 2006-03-20 12:59:23.000000000 +0100
+@@ -0,0 +1,80 @@
++/*
++ * This target marks packets to be enqueued to an imq device
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ipt_IMQ.h>
++#include <linux/imq.h>
++
++static unsigned int imq_target(struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ unsigned int hooknum,
++ const void *targinfo,
++ void *userdata)
++{
++ struct ipt_imq_info *mr = (struct ipt_imq_info*)targinfo;
++
++ (*pskb)->imq_flags = mr->todev | IMQ_F_ENQUEUE;
++
++ return IPT_CONTINUE;
++}
++
++static int imq_checkentry(const char *tablename,
++ const struct ipt_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ struct ipt_imq_info *mr;
++
++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_imq_info))) {
++ printk(KERN_WARNING "IMQ: invalid targinfosize\n");
++ return 0;
++ }
++ mr = (struct ipt_imq_info*)targinfo;
++
++ if (strcmp(tablename, "mangle") != 0) {
++ printk(KERN_WARNING
++ "IMQ: IMQ can only be called from \"mangle\" table, not \"%s\"\n",
++ tablename);
++ return 0;
++ }
++
++ if (mr->todev > IMQ_MAX_DEVS) {
++ printk(KERN_WARNING
++ "IMQ: invalid device specified, highest is %u\n",
++ IMQ_MAX_DEVS);
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ipt_target ipt_imq_reg = {
++ .name = "IMQ",
++ .target = imq_target,
++ .checkentry = imq_checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ if (ipt_register_target(&ipt_imq_reg))
++ return -EINVAL;
++
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&ipt_imq_reg);
++}
++
++module_init(init);
++module_exit(fini);
++
++MODULE_AUTHOR("http://www.linuximq.net");
++MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See http://www.linuximq.net/ for more information.");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.6.16/net/ipv4/netfilter/Kconfig linux-2.6.16-owrt/net/ipv4/netfilter/Kconfig
+--- linux-2.6.16/net/ipv4/netfilter/Kconfig 2006-03-20 12:58:53.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/netfilter/Kconfig 2006-03-20 12:59:23.000000000 +0100
+@@ -351,6 +351,17 @@
+
+ To compile it as a module, choose M here. If unsure, say N.
+
++config IP_NF_TARGET_IMQ
++ tristate "IMQ target support"
++ depends on IP_NF_MANGLE
++ help
++ This option adds a `IMQ' target which is used to specify if and
++ to which IMQ device packets should get enqueued/dequeued.
++
++ For more information visit: http://www.linuximq.net/
++
++ To compile it as a module, choose M here. If unsure, say N.
++
+ config IP_NF_TARGET_LOG
+ tristate "LOG target support"
+ depends on IP_NF_IPTABLES
+diff -Nur linux-2.6.16/net/ipv4/netfilter/Makefile linux-2.6.16-owrt/net/ipv4/netfilter/Makefile
+--- linux-2.6.16/net/ipv4/netfilter/Makefile 2006-03-20 12:58:53.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv4/netfilter/Makefile 2006-03-20 13:01:12.000000000 +0100
+@@ -67,6 +67,7 @@
+ obj-$(CONFIG_IP_NF_TARGET_TOS) += ipt_TOS.o
+ obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
+ obj-$(CONFIG_IP_NF_TARGET_DSCP) += ipt_DSCP.o
++obj-$(CONFIG_IP_NF_TARGET_IMQ) += ipt_IMQ.o
+ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
+ obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+ obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
+diff -Nur linux-2.6.16/net/ipv6/netfilter/ip6t_IMQ.c linux-2.6.16-owrt/net/ipv6/netfilter/ip6t_IMQ.c
+--- linux-2.6.16/net/ipv6/netfilter/ip6t_IMQ.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv6/netfilter/ip6t_IMQ.c 2006-03-20 12:59:23.000000000 +0100
+@@ -0,0 +1,80 @@
++/*
++ * This target marks packets to be enqueued to an imq device
++ */
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_IMQ.h>
++#include <linux/imq.h>
++
++static unsigned int imq_target(struct sk_buff **pskb,
++ unsigned int hooknum,
++ const struct net_device *in,
++ const struct net_device *out,
++ const void *targinfo,
++ void *userdata)
++{
++ struct ip6t_imq_info *mr = (struct ip6t_imq_info*)targinfo;
++
++ (*pskb)->imq_flags = mr->todev | IMQ_F_ENQUEUE;
++
++ return IP6T_CONTINUE;
++}
++
++static int imq_checkentry(const char *tablename,
++ const struct ip6t_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ struct ip6t_imq_info *mr;
++
++ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_imq_info))) {
++ printk(KERN_WARNING "IMQ: invalid targinfosize\n");
++ return 0;
++ }
++ mr = (struct ip6t_imq_info*)targinfo;
++
++ if (strcmp(tablename, "mangle") != 0) {
++ printk(KERN_WARNING
++ "IMQ: IMQ can only be called from \"mangle\" table, not \"%s\"\n",
++ tablename);
++ return 0;
++ }
++
++ if (mr->todev > IMQ_MAX_DEVS) {
++ printk(KERN_WARNING
++ "IMQ: invalid device specified, highest is %u\n",
++ IMQ_MAX_DEVS);
++ return 0;
++ }
++
++ return 1;
++}
++
++static struct ip6t_target ip6t_imq_reg = {
++ .name = "IMQ",
++ .target = imq_target,
++ .checkentry = imq_checkentry,
++ .me = THIS_MODULE
++};
++
++static int __init init(void)
++{
++ if (ip6t_register_target(&ip6t_imq_reg))
++ return -EINVAL;
++
++ return 0;
++}
++
++static void __exit fini(void)
++{
++ ip6t_unregister_target(&ip6t_imq_reg);
++}
++
++module_init(init);
++module_exit(fini);
++
++MODULE_AUTHOR("http://www.linuximq.net");
++MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See http://www.linuximq.net/ for more information.");
++MODULE_LICENSE("GPL");
+diff -Nur linux-2.6.16/net/ipv6/netfilter/Kconfig linux-2.6.16-owrt/net/ipv6/netfilter/Kconfig
+--- linux-2.6.16/net/ipv6/netfilter/Kconfig 2006-03-20 06:53:29.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv6/netfilter/Kconfig 2006-03-20 12:59:23.000000000 +0100
+@@ -154,6 +154,15 @@
+
+ To compile it as a module, choose M here. If unsure, say N.
+
++config IP6_NF_TARGET_IMQ
++ tristate "IMQ target support"
++ depends on IP6_NF_MANGLE
++ help
++ This option adds a `IMQ' target which is used to specify if and
++ to which imq device packets should get enqueued/dequeued.
++
++ To compile it as a module, choose M here. If unsure, say N.
++
+ config IP6_NF_TARGET_LOG
+ tristate "LOG target support"
+ depends on IP6_NF_FILTER
+diff -Nur linux-2.6.16/net/ipv6/netfilter/Makefile linux-2.6.16-owrt/net/ipv6/netfilter/Makefile
+--- linux-2.6.16/net/ipv6/netfilter/Makefile 2006-03-20 06:53:29.000000000 +0100
++++ linux-2.6.16-owrt/net/ipv6/netfilter/Makefile 2006-03-20 13:02:14.000000000 +0100
+@@ -4,6 +4,7 @@
+
+ # Link order matters here.
+ obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
++obj-$(CONFIG_IP6_NF_TARGET_IMQ) += ip6t_IMQ.o
+ obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
+ obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o ip6t_dst.o
+ obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
+diff -Nur linux-2.6.16/net/sched/sch_generic.c linux-2.6.16-owrt/net/sched/sch_generic.c
+--- linux-2.6.16/net/sched/sch_generic.c 2006-03-20 06:53:29.000000000 +0100
++++ linux-2.6.16-owrt/net/sched/sch_generic.c 2006-03-20 12:59:23.000000000 +0100
+@@ -29,6 +29,9 @@
+ #include <linux/netdevice.h>
+ #include <linux/skbuff.h>
+ #include <linux/rtnetlink.h>
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++#include <linux/imq.h>
++#endif
+ #include <linux/init.h>
+ #include <linux/rcupdate.h>
+ #include <linux/list.h>
+@@ -136,7 +139,13 @@
+
+ if (!netif_queue_stopped(dev)) {
+ int ret;
+- if (netdev_nit)
++
++ if (netdev_nit
++#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
++ && !(skb->imq_flags & IMQ_F_ENQUEUE)
++#endif
++ )
++
+ dev_queue_xmit_nit(skb, dev);
+
+ ret = dev->hard_start_xmit(skb, dev);
diff --git a/target/linux/generic-2.6/patches/107-netfilter_nat_sip.patch b/target/linux/generic-2.6/patches/107-netfilter_nat_sip.patch
new file mode 100644
index 0000000..6640118
--- /dev/null
+++ b/target/linux/generic-2.6/patches/107-netfilter_nat_sip.patch
@@ -0,0 +1,830 @@
+diff -urN linux-2.6.16.4/net/ipv4/netfilter/ip_conntrack_sip.c linux-2.6.16.4.new/net/ipv4/netfilter/ip_conntrack_sip.c
+--- linux-2.6.16.4/net/ipv4/netfilter/ip_conntrack_sip.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.4.new/net/ipv4/netfilter/ip_conntrack_sip.c 2006-04-12 17:31:44.000000000 +0200
+@@ -0,0 +1,414 @@
++/* SIP extension for IP connection tracking.
++ *
++ * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
++ * based on RR's ip_conntrack_ftp.c and other modules.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/netfilter.h>
++#include <linux/ip.h>
++#include <linux/ctype.h>
++#include <linux/in.h>
++#include <linux/udp.h>
++#include <net/checksum.h>
++#include <net/udp.h>
++
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_sip.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
++MODULE_DESCRIPTION("SIP connection tracking helper");
++
++static DEFINE_SPINLOCK(sipbf_lock);
++
++
++#define MAX_PORTS 8
++static int ports[MAX_PORTS];
++static int ports_c;
++module_param_array(ports, int, &ports_c, 0400);
++MODULE_PARM_DESC(ports, " port numbers of sip servers");
++
++static unsigned int sip_timeout = SIP_TIMEOUT;
++
++module_param(sip_timeout, int, 0600);
++MODULE_PARM_DESC(sip_timeout, "timeout for the master sip session");
++
++unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack *ct,
++ const char **dptr);
++EXPORT_SYMBOL_GPL(ip_nat_sip_hook);
++
++unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect *exp,
++ const char *dptr);
++EXPORT_SYMBOL_GPL(ip_nat_sdp_hook);
++
++int ct_sip_get_info(const char *dptr, size_t dlen,
++ unsigned int *matchoff,
++ unsigned int *matchlen,
++ struct sip_header_nfo *hnfo);
++EXPORT_SYMBOL(ct_sip_get_info);
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++static int digits_len(const char *dptr, const char *limit, int *shift);
++static int epaddr_len(const char *dptr, const char *limit, int *shift);
++static int skp_digits_len(const char *dptr, const char *limit, int *shift);
++static int skp_epaddr_len(const char *dptr, const char *limit, int *shift);
++
++struct sip_header_nfo ct_sip_hdrs[] = {
++ { /* Via header */
++ "Via:", sizeof("Via:") - 1,
++ "\r\nv:", sizeof("\r\nv:") - 1, /* rfc3261 "\r\n" */
++ "UDP ", sizeof("UDP ") - 1,
++ epaddr_len
++ },
++ { /* Contact header */
++ "Contact:", sizeof("Contact:") - 1,
++ "\r\nm:", sizeof("\r\nm:") - 1,
++ "sip:", sizeof("sip:") - 1,
++ skp_epaddr_len
++ },
++ { /* Content length header */
++ "Content-Length:", sizeof("Content-Length:") - 1,
++ "\r\nl:", sizeof("\r\nl:") - 1,
++ ":", sizeof(":") - 1,
++ skp_digits_len
++ },
++ { /* SDP media info */
++ "\nm=", sizeof("\nm=") - 1,
++ "\rm=", sizeof("\rm=") - 1,
++ "audio ", sizeof("audio ") - 1,
++ digits_len
++ },
++ { /* SDP owner address*/
++ "\no=", sizeof("\no=") - 1,
++ "\ro=", sizeof("\ro=") - 1,
++ "IN IP4 ", sizeof("IN IP4 ") - 1,
++ epaddr_len
++ },
++ { /* SDP connection info */
++ "\nc=", sizeof("\nc=") - 1,
++ "\rc=", sizeof("\rc=") - 1,
++ "IN IP4 ", sizeof("IN IP4 ") - 1,
++ epaddr_len
++ },
++ { /* Requests headers */
++ "sip:", sizeof("sip:") - 1,
++ "sip:", sizeof("sip:") - 1, /* yes, i know.. ;) */
++ "@", sizeof("@") - 1,
++ epaddr_len
++ },
++ { /* SDP version header */
++ "\nv=", sizeof("\nv=") - 1,
++ "\rv=", sizeof("\rv=") - 1,
++ "=", sizeof("=") - 1,
++ digits_len
++ }
++};
++EXPORT_SYMBOL(ct_sip_hdrs);
++
++
++static int digits_len(const char *dptr, const char *limit, int *shift)
++{
++ int len = 0;
++ while (dptr <= limit && isdigit(*dptr)) {
++ dptr++;
++ len++;
++ }
++ return len;
++}
++
++/* get digits lenght, skiping blank spaces. */
++static int skp_digits_len(const char *dptr, const char *limit, int *shift)
++{
++ for (; dptr <= limit && *dptr == ' '; dptr++)
++ (*shift)++;
++
++ return digits_len(dptr, limit, shift);
++}
++
++/* Simple ipaddr parser.. */
++static int parse_ipaddr(const char *cp, const char **endp,
++ uint32_t *ipaddr, const char *limit)
++{
++ unsigned long int val;
++ int i, digit = 0;
++
++ for (i = 0, *ipaddr = 0; cp <= limit && i < 4; i++) {
++ digit = 0;
++ if (!isdigit(*cp))
++ break;
++
++ val = simple_strtoul(cp, (char **)&cp, 10);
++ if (val > 0xFF)
++ return -1;
++
++ ((uint8_t *)ipaddr)[i] = val;
++ digit = 1;
++
++ if (*cp != '.')
++ break;
++ cp++;
++ }
++ if (!digit)
++ return -1;
++
++ if (endp)
++ *endp = cp;
++
++ return 0;
++}
++
++/* skip ip address. returns it lenght. */
++static int epaddr_len(const char *dptr, const char *limit, int *shift)
++{
++ const char *aux = dptr;
++ uint32_t ip;
++
++ if (parse_ipaddr(dptr, &dptr, &ip, limit) < 0) {
++ DEBUGP("ip: %s parse failed.!\n", dptr);
++ return 0;
++ }
++
++ /* Port number */
++ if (*dptr == ':') {
++ dptr++;
++ dptr += digits_len(dptr, limit, shift);
++ }
++ return dptr - aux;
++}
++
++/* get address lenght, skiping user info. */
++static int skp_epaddr_len(const char *dptr, const char *limit, int *shift)
++{
++ for (; dptr <= limit && *dptr != '@'; dptr++)
++ (*shift)++;
++
++ if (*dptr == '@') {
++ dptr++;
++ (*shift)++;
++ return epaddr_len(dptr, limit, shift);
++ }
++ return 0;
++}
++
++/* Returns 0 if not found, -1 error parsing. */
++int ct_sip_get_info(const char *dptr, size_t dlen,
++ unsigned int *matchoff,
++ unsigned int *matchlen,
++ struct sip_header_nfo *hnfo)
++{
++ const char *limit, *aux, *k = dptr;
++ int shift = 0;
++
++ limit = dptr + (dlen - hnfo->lnlen);
++
++ while (dptr <= limit) {
++ if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) &&
++ (strncmp(dptr, hnfo->sname, hnfo->snlen) != 0))
++ {
++ dptr++;
++ continue;
++ }
++ aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen,
++ ct_sip_lnlen(dptr, limit));
++ if (!aux) {
++ DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str, hnfo->lname);
++ return -1;
++ }
++ aux += hnfo->ln_strlen;
++
++ *matchlen = hnfo->match_len(aux, limit, &shift);
++ if (!*matchlen)
++ return -1;
++
++ *matchoff = (aux - k) + shift;
++
++ DEBUGP("%s match succeeded! - len: %u\n", hnfo->lname, *matchlen);
++ return 1;
++ }
++ DEBUGP("%s header not found.\n", hnfo->lname);
++ return 0;
++}
++
++static int set_expected_rtp(struct sk_buff **pskb,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo,
++ uint32_t ipaddr, uint16_t port,
++ const char *dptr)
++{
++ struct ip_conntrack_expect *exp;
++ int ret;
++
++ exp = ip_conntrack_expect_alloc(ct);
++ if (exp == NULL)
++ return NF_DROP;
++
++ exp->tuple = ((struct ip_conntrack_tuple)
++ { { ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip, { 0 } },
++ { ipaddr, { .udp = { htons(port) } }, IPPROTO_UDP }});
++
++ exp->mask = ((struct ip_conntrack_tuple)
++ { { 0xFFFFFFFF, { 0 } },
++ { 0xFFFFFFFF, { .udp = { 0xFFFF } }, 0xFF }});
++
++ exp->expectfn = NULL;
++
++ if (ip_nat_sdp_hook)
++ ret = ip_nat_sdp_hook(pskb, ctinfo, exp, dptr);
++ else {
++ if (ip_conntrack_expect_related(exp) != 0)
++ ret = NF_DROP;
++ else
++ ret = NF_ACCEPT;
++ }
++ ip_conntrack_expect_put(exp);
++
++ return ret;
++}
++
++static int sip_help(struct sk_buff **pskb,
++ struct ip_conntrack *ct,
++ enum ip_conntrack_info ctinfo)
++{
++ unsigned int dataoff, datalen;
++ const char *dptr;
++ int ret = NF_ACCEPT;
++ int matchoff, matchlen;
++ uint32_t ipaddr;
++ uint16_t port;
++
++ /* No Data ? */
++ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
++ if (dataoff >= (*pskb)->len) {
++ DEBUGP("skb->len = %u\n", (*pskb)->len);
++ return NF_ACCEPT;
++ }
++
++ ip_ct_refresh(ct, *pskb, sip_timeout * HZ);
++
++ spin_lock_bh(&sipbf_lock);
++
++ if ((dataoff + (*pskb)->len - dataoff) <= skb_headlen(*pskb))
++ dptr = (*pskb)->data + dataoff;
++ else {
++ DEBUGP("Copy of skbuff not supported yet.\n");
++ goto out;
++ }
++
++ if (ip_nat_sip_hook) {
++ if (!ip_nat_sip_hook(pskb, ctinfo, ct, &dptr)) {
++ ret = NF_DROP;
++ goto out;
++ }
++ }
++
++ if ((ctinfo) >= IP_CT_IS_REPLY)
++ goto out;
++
++ /* After this point NAT, could have mangled skb, so
++ we need to recalculate payload lenght. */
++ datalen = (*pskb)->len - dataoff;
++
++ if (datalen < (sizeof("SIP/2.0 200") - 1))
++ goto out;
++
++ /* RTP info only in some SDP pkts */
++ if (memcmp(dptr, "INVITE", sizeof("INVITE") - 1) != 0 &&
++ memcmp(dptr, "SIP/2.0 200", sizeof("SIP/2.0 200") - 1) != 0) {
++ goto out;
++ }
++ /* Get ip and port address from SDP packet. */
++ if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen,
++ &ct_sip_hdrs[POS_CONECTION]) > 0) {
++
++ /* We'll drop only if there are parse problems. */
++ if (parse_ipaddr(dptr + matchoff, NULL, &ipaddr,
++ dptr + datalen) < 0) {
++ ret = NF_DROP;
++ goto out;
++ }
++ if (ct_sip_get_info(dptr, datalen, &matchoff, &matchlen,
++ &ct_sip_hdrs[POS_MEDIA]) > 0) {
++
++ port = simple_strtoul(dptr + matchoff, NULL, 10);
++ if (port < 1024) {
++ ret = NF_DROP;
++ goto out;
++ }
++ ret = set_expected_rtp(pskb, ct, ctinfo,
++ ipaddr, port, dptr);
++ }
++ }
++out: spin_unlock_bh(&sipbf_lock);
++ return ret;
++}
++
++static struct ip_conntrack_helper sip[MAX_PORTS];
++static char sip_names[MAX_PORTS][10];
++
++static void fini(void)
++{
++ int i = 0;
++ for (; i < ports_c; i++) {
++ DEBUGP("unregistering helper for port %d\n", ports[i]);
++ ip_conntrack_helper_unregister(&sip[i]);
++ }
++}
++
++static int __init init(void)
++{
++ int i, ret;
++ char *tmpname;
++
++ if (ports_c == 0)
++ ports[ports_c++] = SIP_PORT;
++
++ for (i = 0; i < ports_c; i++) {
++ /* Create helper structure */
++ memset(&sip[i], 0, sizeof(struct ip_conntrack_helper));
++
++ sip[i].tuple.dst.protonum = IPPROTO_UDP;
++ sip[i].tuple.src.u.udp.port = htons(ports[i]);
++ sip[i].mask.src.u.udp.port = 0xFFFF;
++ sip[i].mask.dst.protonum = 0xFF;
++ sip[i].max_expected = 1;
++ sip[i].timeout = 3 * 60; /* 3 minutes */
++ sip[i].me = THIS_MODULE;
++ sip[i].help = sip_help;
++
++ tmpname = &sip_names[i][0];
++ if (ports[i] == SIP_PORT)
++ sprintf(tmpname, "sip");
++ else
++ sprintf(tmpname, "sip-%d", i);
++ sip[i].name = tmpname;
++
++ DEBUGP("port #%d: %d\n", i, ports[i]);
++
++ ret=ip_conntrack_helper_register(&sip[i]);
++ if (ret) {
++ printk("ERROR registering helper for port %d\n",
++ ports[i]);
++ fini();
++ return(ret);
++ }
++ }
++ return(0);
++}
++
++module_init(init);
++module_exit(fini);
+diff -urN linux-2.6.16.4/net/ipv4/netfilter/ip_nat_sip.c linux-2.6.16.4.new/net/ipv4/netfilter/ip_nat_sip.c
+--- linux-2.6.16.4/net/ipv4/netfilter/ip_nat_sip.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.4.new/net/ipv4/netfilter/ip_nat_sip.c 2006-04-12 17:31:53.000000000 +0200
+@@ -0,0 +1,249 @@
++/* SIP extension for UDP NAT alteration.
++ *
++ * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
++ * based on RR's ip_nat_ftp.c and other modules.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/ip.h>
++#include <linux/udp.h>
++#include <net/udp.h>
++
++#include <linux/netfilter_ipv4/ip_nat.h>
++#include <linux/netfilter_ipv4/ip_nat_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
++#include <linux/netfilter_ipv4/ip_conntrack_sip.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
++MODULE_DESCRIPTION("SIP NAT helper");
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++extern struct sip_header_nfo ct_sip_hdrs[];
++
++static unsigned int mangle_sip_packet(struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack *ct,
++ const char **dptr, size_t dlen,
++ char *buffer, int bufflen,
++ struct sip_header_nfo *hnfo)
++{
++ unsigned int matchlen, matchoff;
++
++ if (ct_sip_get_info(*dptr, dlen, &matchoff, &matchlen, hnfo) <= 0)
++ return 0;
++
++ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
++ matchoff, matchlen, buffer, bufflen)) {
++ return 0;
++ }
++ /* We need to reload this. Thanks Patrick. */
++ *dptr = (*pskb)->data + (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
++ return 1;
++}
++
++static unsigned int ip_nat_sip(struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack *ct,
++ const char **dptr)
++{
++ char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
++ unsigned int bufflen, dataoff;
++ uint32_t ip;
++ uint16_t port;
++
++ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
++
++ if ((ctinfo) >= IP_CT_IS_REPLY) {
++ ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
++ port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
++ } else {
++ ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++ port = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port;
++ }
++ bufflen = sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(ip), ntohs(port));
++
++ /* short packet ? */
++ if (((*pskb)->len - dataoff) < (sizeof("SIP/2.0") - 1))
++ return 0;
++
++ /* Basic rules: requests and responses. */
++ if (memcmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) == 0) {
++
++ if ((ctinfo) < IP_CT_IS_REPLY) {
++ mangle_sip_packet(pskb, ctinfo, ct, dptr,
++ (*pskb)->len - dataoff, buffer, bufflen,
++ &ct_sip_hdrs[POS_CONTACT]);
++ return 1;
++ }
++
++ if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff,
++ buffer, bufflen, &ct_sip_hdrs[POS_VIA])) {
++ return 0;
++ }
++
++ /* This search should ignore case, but later.. */
++ const char *aux = ct_sip_search("CSeq:", *dptr, sizeof("CSeq:") - 1,
++ (*pskb)->len - dataoff);
++ if (!aux)
++ return 0;
++
++ if (!ct_sip_search("REGISTER", aux, sizeof("REGISTER"),
++ ct_sip_lnlen(aux, *dptr + (*pskb)->len - dataoff))) {
++ return 1;
++ }
++ return mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff,
++ buffer, bufflen, &ct_sip_hdrs[POS_CONTACT]);
++ }
++ if ((ctinfo) < IP_CT_IS_REPLY) {
++ if (!mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff,
++ buffer, bufflen, &ct_sip_hdrs[POS_VIA])) {
++ return 0;
++ }
++
++ /* Mangle Contact if exists only. - watch udp_nat_mangle()! */
++ mangle_sip_packet(pskb, ctinfo, ct, dptr, (*pskb)->len - dataoff,
++ buffer, bufflen, &ct_sip_hdrs[POS_CONTACT]);
++ return 1;
++ }
++ /* This mangle requests headers. */
++ return mangle_sip_packet(pskb, ctinfo, ct, dptr,
++ ct_sip_lnlen(*dptr, *dptr + (*pskb)->len - dataoff),
++ buffer, bufflen, &ct_sip_hdrs[POS_REQ_HEADER]);
++}
++
++static int mangle_content_len(struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack *ct,
++ const char *dptr)
++{
++ unsigned int dataoff, matchoff, matchlen;
++ char buffer[sizeof("65536")];
++ int bufflen;
++
++ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
++
++ /* Get actual SDP lenght */
++ if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff,
++ &matchlen, &ct_sip_hdrs[POS_SDP_HEADER]) > 0) {
++
++ /* since ct_sip_get_info() give us a pointer passing 'v='
++ we need to add 2 bytes in this count. */
++ int c_len = (*pskb)->len - dataoff - matchoff + 2;
++
++ /* Now, update SDP lenght */
++ if (ct_sip_get_info(dptr, (*pskb)->len - dataoff, &matchoff,
++ &matchlen, &ct_sip_hdrs[POS_CONTENT]) > 0) {
++
++ bufflen = sprintf(buffer, "%u", c_len);
++
++ return ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff,
++ matchlen, buffer, bufflen);
++ }
++ }
++ return 0;
++}
++
++static unsigned int mangle_sdp(struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack *ct,
++ uint32_t newip, uint16_t port,
++ const char *dptr)
++{
++ char buffer[sizeof("nnn.nnn.nnn.nnn")];
++ unsigned int dataoff, bufflen;
++
++ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
++
++ /* Mangle owner and contact info. */
++ bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
++ if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
++ buffer, bufflen, &ct_sip_hdrs[POS_OWNER])) {
++ return 0;
++ }
++
++ if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
++ buffer, bufflen, &ct_sip_hdrs[POS_CONECTION])) {
++ return 0;
++ }
++
++ /* Mangle media port. */
++ bufflen = sprintf(buffer, "%u", port);
++ if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
++ buffer, bufflen, &ct_sip_hdrs[POS_MEDIA])) {
++ return 0;
++ }
++
++ return mangle_content_len(pskb, ctinfo, ct, dptr);
++}
++
++/* So, this packet has hit the connection tracking matching code.
++ Mangle it, and change the expectation to match the new version. */
++static unsigned int ip_nat_sdp(struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect *exp,
++ const char *dptr)
++{
++ struct ip_conntrack *ct = exp->master;
++ uint32_t newip;
++ uint16_t port;
++
++ DEBUGP("ip_nat_sdp():\n");
++
++ /* Connection will come from reply */
++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
++
++ exp->tuple.dst.ip = newip;
++ exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
++ exp->dir = IP_CT_DIR_REPLY;
++
++ /* When you see the packet, we need to NAT it the same as the
++ this one. */
++ exp->expectfn = ip_nat_follow_master;
++
++ /* Try to get same port: if not, try to change it. */
++ for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {
++ exp->tuple.dst.u.udp.port = htons(port);
++ if (ip_conntrack_expect_related(exp) == 0)
++ break;
++ }
++
++ if (port == 0)
++ return NF_DROP;
++
++ if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) {
++ ip_conntrack_unexpect_related(exp);
++ return NF_DROP;
++ }
++ return NF_ACCEPT;
++}
++
++static void __exit fini(void)
++{
++ ip_nat_sip_hook = NULL;
++ ip_nat_sdp_hook = NULL;
++ /* Make sure noone calls it, meanwhile. */
++ synchronize_net();
++}
++
++static int __init init(void)
++{
++ BUG_ON(ip_nat_sip_hook);
++ BUG_ON(ip_nat_sdp_hook);
++ ip_nat_sip_hook = ip_nat_sip;
++ ip_nat_sdp_hook = ip_nat_sdp;
++ return 0;
++}
++
++module_init(init);
++module_exit(fini);
+diff -urN linux-2.6.16.4/net/ipv4/netfilter/Kconfig linux-2.6.16.4.new/net/ipv4/netfilter/Kconfig
+--- linux-2.6.16.4/net/ipv4/netfilter/Kconfig 2006-04-12 17:29:19.000000000 +0200
++++ linux-2.6.16.4.new/net/ipv4/netfilter/Kconfig 2006-04-12 17:32:53.000000000 +0200
+@@ -168,6 +168,19 @@
+ If you want to compile it as a module, say M here and read
+ Documentation/modules.txt. If unsure, say `N'.
+
++config IP_NF_SIP
++ tristate 'SIP support'
++ depends on IP_NF_CONNTRACK
++ help
++ SIP is an application-layer control protocol that can establish,
++ modify, and terminate multimedia sessions (conferences) such as
++ Internet telephony calls. With the ip_conntrack_sip and
++ the ip_nat_sip modules you can support the protocol on a connection
++ tracking/NATing firewall.
++
++ If you want to compile it as a module, say 'M' here and read
++ Documentation/modules.txt. If unsure, say 'N'.
++
+ config IP_NF_QUEUE
+ tristate "IP Userspace queueing via NETLINK (OBSOLETE)"
+ help
+@@ -545,6 +558,12 @@
+ default IP_NF_NAT if IP_NF_PPTP=y
+ default m if IP_NF_PPTP=m
+
++config IP_NF_NAT_SIP
++ tristate
++ depends on IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
++ default IP_NF_NAT if IP_NF_SIP=y
++ default m if IP_NF_SIP=m
++
+ # mangle + specific targets
+ config IP_NF_MANGLE
+ tristate "Packet mangling"
+diff -urN linux-2.6.16.4/net/ipv4/netfilter/Makefile linux-2.6.16.4.new/net/ipv4/netfilter/Makefile
+--- linux-2.6.16.4/net/ipv4/netfilter/Makefile 2006-04-12 17:29:19.000000000 +0200
++++ linux-2.6.16.4.new/net/ipv4/netfilter/Makefile 2006-04-12 17:33:39.000000000 +0200
+@@ -28,6 +28,7 @@
+ obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
+ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
+ obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o
++obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o
+
+ # NAT helpers
+ obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
+@@ -35,6 +36,7 @@
+ obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
+ obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
+ obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
++obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o
+
+ # generic IP tables
+ obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
+diff -urN linux-2.6.16.4/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.6.16.4.new/include/linux/netfilter_ipv4/ip_conntrack.h
+--- linux-2.6.16.4/include/linux/netfilter_ipv4/ip_conntrack.h 2006-04-12 17:29:19.000000000 +0200
++++ linux-2.6.16.4.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-04-12 17:30:38.000000000 +0200
+@@ -33,6 +33,7 @@
+ #include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
+ #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
++#include <linux/netfilter_ipv4/ip_conntrack_sip.h>
+
+ /* per conntrack: application helper private data */
+ union ip_conntrack_help {
+@@ -40,6 +41,7 @@
+ struct ip_ct_pptp_master ct_pptp_info;
+ struct ip_ct_ftp_master ct_ftp_info;
+ struct ip_ct_irc_master ct_irc_info;
++ struct ip_ct_sip_master ct_sip_info;
+ };
+
+ #ifdef CONFIG_IP_NF_NAT_NEEDED
+diff -urN linux-2.6.16.4/include/linux/netfilter_ipv4/ip_conntrack_sip.h linux-2.6.16.4.new/include/linux/netfilter_ipv4/ip_conntrack_sip.h
+--- linux-2.6.16.4/include/linux/netfilter_ipv4/ip_conntrack_sip.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.4.new/include/linux/netfilter_ipv4/ip_conntrack_sip.h 2006-04-12 17:31:12.000000000 +0200
+@@ -0,0 +1,81 @@
++#ifndef __IP_CONNTRACK_SIP_H__
++#define __IP_CONNTRACK_SIP_H__
++/* SIP tracking. */
++
++#ifdef __KERNEL__
++
++#define SIP_PORT 5060
++#define SIP_TIMEOUT 3600
++
++#define POS_VIA 0
++#define POS_CONTACT 1
++#define POS_CONTENT 2
++#define POS_MEDIA 3
++#define POS_OWNER 4
++#define POS_CONECTION 5
++#define POS_REQ_HEADER 6
++#define POS_SDP_HEADER 7
++
++struct ip_ct_sip_master {
++};
++
++struct sip_header_nfo {
++ const char *lname;
++ size_t lnlen;
++ const char *sname;
++ size_t snlen;
++ const char *ln_str;
++ size_t ln_strlen;
++ int (*match_len)(const char *, const char *, int *);
++
++};
++
++extern unsigned int (*ip_nat_sip_hook)(struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack *ct,
++ const char **dptr);
++
++/* For NAT to hook in when on expect. */
++extern unsigned int (*ip_nat_sdp_hook)(struct sk_buff **pskb,
++ enum ip_conntrack_info ctinfo,
++ struct ip_conntrack_expect *exp,
++ const char *dptr);
++
++extern int ct_sip_get_info(const char *dptr, size_t dlen,
++ unsigned int *matchoff,
++ unsigned int *matchlen,
++ struct sip_header_nfo *hnfo);
++
++/* get line lenght until first CR or LF seen. */
++static __inline__ int ct_sip_lnlen(const char *line, const char *limit)
++{
++ const char *k = line;
++
++ while ((line <= limit) && (*line == '\r' || *line == '\n'))
++ line++;
++
++ while (line <= limit) {
++ if (*line == '\r' || *line == '\n')
++ break;
++ line++;
++ }
++ return line - k;
++}
++
++/* Linear string search, case sensitive. */
++static __inline__
++const char *ct_sip_search(const char *needle, const char *haystack,
++ size_t needle_len, size_t haystack_len)
++{
++ const char *limit = haystack + (haystack_len - needle_len);
++
++ while (haystack <= limit) {
++ if (memcmp(haystack, needle, needle_len) == 0)
++ return haystack;
++ haystack++;
++ }
++ return NULL;
++}
++#endif /* __KERNEL__ */
++
++#endif /* __IP_CONNTRACK_SIP_H__ */
diff --git a/target/linux/generic-2.6/patches/108-netfilter_route.patch b/target/linux/generic-2.6/patches/108-netfilter_route.patch
new file mode 100644
index 0000000..571d6a3
--- /dev/null
+++ b/target/linux/generic-2.6/patches/108-netfilter_route.patch
@@ -0,0 +1,914 @@
+diff -u'rNF^function' linux-2.6.16.7/include/linux/netfilter_ipv4/ipt_ROUTE.h linux-2.6.16.7-ROUTE/include/linux/netfilter_ipv4/ipt_ROUTE.h
+--- linux-2.6.16.7/include/linux/netfilter_ipv4/ipt_ROUTE.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7-ROUTE/include/linux/netfilter_ipv4/ipt_ROUTE.h 2006-06-14 16:40:49.000000000 +0200
+@@ -0,0 +1,23 @@
++/* Header file for iptables ipt_ROUTE target
++ *
++ * (C) 2002 by Cédric de Launois <delaunois@info.ucl.ac.be>
++ *
++ * This software is distributed under GNU GPL v2, 1991
++ */
++#ifndef _IPT_ROUTE_H_target
++#define _IPT_ROUTE_H_target
++
++#define IPT_ROUTE_IFNAMSIZ 16
++
++struct ipt_route_target_info {
++ char oif[IPT_ROUTE_IFNAMSIZ]; /* Output Interface Name */
++ char iif[IPT_ROUTE_IFNAMSIZ]; /* Input Interface Name */
++ u_int32_t gw; /* IP address of gateway */
++ u_int8_t flags;
++};
++
++/* Values for "flags" field */
++#define IPT_ROUTE_CONTINUE 0x01
++#define IPT_ROUTE_TEE 0x02
++
++#endif /*_IPT_ROUTE_H_target*/
+diff -u'rNF^function' linux-2.6.16.7/include/linux/netfilter_ipv6/ip6t_ROUTE.h linux-2.6.16.7-ROUTE/include/linux/netfilter_ipv6/ip6t_ROUTE.h
+--- linux-2.6.16.7/include/linux/netfilter_ipv6/ip6t_ROUTE.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7-ROUTE/include/linux/netfilter_ipv6/ip6t_ROUTE.h 2006-06-14 16:41:08.000000000 +0200
+@@ -0,0 +1,23 @@
++/* Header file for iptables ip6t_ROUTE target
++ *
++ * (C) 2003 by Cédric de Launois <delaunois@info.ucl.ac.be>
++ *
++ * This software is distributed under GNU GPL v2, 1991
++ */
++#ifndef _IPT_ROUTE_H_target
++#define _IPT_ROUTE_H_target
++
++#define IP6T_ROUTE_IFNAMSIZ 16
++
++struct ip6t_route_target_info {
++ char oif[IP6T_ROUTE_IFNAMSIZ]; /* Output Interface Name */
++ char iif[IP6T_ROUTE_IFNAMSIZ]; /* Input Interface Name */
++ u_int32_t gw[4]; /* IPv6 address of gateway */
++ u_int8_t flags;
++};
++
++/* Values for "flags" field */
++#define IP6T_ROUTE_CONTINUE 0x01
++#define IP6T_ROUTE_TEE 0x02
++
++#endif /*_IP6T_ROUTE_H_target*/
+diff -u'rNF^function' linux-2.6.16.7/net/ipv4/netfilter/Kconfig linux-2.6.16.7-ROUTE/net/ipv4/netfilter/Kconfig
+--- linux-2.6.16.7/net/ipv4/netfilter/Kconfig 2006-06-14 16:05:44.000000000 +0200
++++ linux-2.6.16.7-ROUTE/net/ipv4/netfilter/Kconfig 2006-06-14 16:46:40.000000000 +0200
+@@ -491,6 +491,23 @@
+
+ To compile it as a module, choose M here. If unsure, say N.
+
++config IP_NF_TARGET_ROUTE
++ tristate 'ROUTE target support'
++ depends on IP_NF_MANGLE
++ help
++ This option adds a `ROUTE' target, which enables you to setup unusual
++ routes. For example, the ROUTE lets you route a received packet through
++ an interface or towards a host, even if the regular destination of the
++ packet is the router itself. The ROUTE target is also able to change the
++ incoming interface of a packet.
++
++ The target can be or not a final target. It has to be used inside the
++ mangle table.
++
++ If you want to compile it as a module, say M here and read
++ Documentation/modules.txt. The module will be called ipt_ROUTE.o.
++ If unsure, say `N'.
++
+ config IP_NF_TARGET_NETMAP
+ tristate "NETMAP target support"
+ depends on IP_NF_NAT
+diff -u'rNF^function' linux-2.6.16.7/net/ipv4/netfilter/Makefile linux-2.6.16.7-ROUTE/net/ipv4/netfilter/Makefile
+--- linux-2.6.16.7/net/ipv4/netfilter/Makefile 2006-06-14 16:05:44.000000000 +0200
++++ linux-2.6.16.7-ROUTE/net/ipv4/netfilter/Makefile 2006-06-14 16:44:02.000000000 +0200
+@@ -74,6 +74,7 @@
+ obj-$(CONFIG_IP_NF_TARGET_IMQ) += ipt_IMQ.o
+ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
+ obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
++obj-$(CONFIG_IP_NF_TARGET_ROUTE) += ipt_ROUTE.o
+ obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
+ obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
+ obj-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic.o
+diff -u'rNF^function' linux-2.6.16.7/net/ipv4/netfilter/ipt_ROUTE.c linux-2.6.16.7-ROUTE/net/ipv4/netfilter/ipt_ROUTE.c
+--- linux-2.6.16.7/net/ipv4/netfilter/ipt_ROUTE.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7-ROUTE/net/ipv4/netfilter/ipt_ROUTE.c 2006-06-14 16:42:23.000000000 +0200
+@@ -0,0 +1,461 @@
++/*
++ * This implements the ROUTE target, which enables you to setup unusual
++ * routes not supported by the standard kernel routing table.
++ *
++ * Copyright (C) 2002 Cedric de Launois <delaunois@info.ucl.ac.be>
++ *
++ * v 1.11 2004/11/23
++ *
++ * This software is distributed under GNU GPL v2, 1991
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/netfilter_ipv4/ip_tables.h>
++#include <linux/netfilter_ipv4/ip_conntrack.h>
++#include <linux/netfilter_ipv4/ipt_ROUTE.h>
++#include <linux/netdevice.h>
++#include <linux/route.h>
++#include <linux/if_arp.h>
++#include <net/ip.h>
++#include <net/route.h>
++#include <net/icmp.h>
++#include <net/checksum.h>
++
++#if 0
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Cedric de Launois <delaunois@info.ucl.ac.be>");
++MODULE_DESCRIPTION("iptables ROUTE target module");
++
++/* Try to route the packet according to the routing keys specified in
++ * route_info. Keys are :
++ * - ifindex :
++ * 0 if no oif preferred,
++ * otherwise set to the index of the desired oif
++ * - route_info->gw :
++ * 0 if no gateway specified,
++ * otherwise set to the next host to which the pkt must be routed
++ * If success, skb->dev is the output device to which the packet must
++ * be sent and skb->dst is not NULL
++ *
++ * RETURN: -1 if an error occured
++ * 1 if the packet was succesfully routed to the
++ * destination desired
++ * 0 if the kernel routing table could not route the packet
++ * according to the keys specified
++ */
++static int route(struct sk_buff *skb,
++ unsigned int ifindex,
++ const struct ipt_route_target_info *route_info)
++{
++ int err;
++ struct rtable *rt;
++ struct iphdr *iph = skb->nh.iph;
++ struct flowi fl = {
++ .oif = ifindex,
++ .nl_u = {
++ .ip4_u = {
++ .daddr = iph->daddr,
++ .saddr = 0,
++ .tos = RT_TOS(iph->tos),
++ .scope = RT_SCOPE_UNIVERSE,
++ }
++ }
++ };
++
++ /* The destination address may be overloaded by the target */
++ if (route_info->gw)
++ fl.fl4_dst = route_info->gw;
++
++ /* Trying to route the packet using the standard routing table. */
++ if ((err = ip_route_output_key(&rt, &fl))) {
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: couldn't route pkt (err: %i)",err);
++ return -1;
++ }
++
++ /* Drop old route. */
++ dst_release(skb->dst);
++ skb->dst = NULL;
++
++ /* Success if no oif specified or if the oif correspond to the
++ * one desired */
++ if (!ifindex || rt->u.dst.dev->ifindex == ifindex) {
++ skb->dst = &rt->u.dst;
++ skb->dev = skb->dst->dev;
++ skb->protocol = htons(ETH_P_IP);
++ return 1;
++ }
++
++ /* The interface selected by the routing table is not the one
++ * specified by the user. This may happen because the dst address
++ * is one of our own addresses.
++ */
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: failed to route as desired gw=%u.%u.%u.%u oif=%i (got oif=%i)\n",
++ NIPQUAD(route_info->gw), ifindex, rt->u.dst.dev->ifindex);
++
++ return 0;
++}
++
++
++/* Stolen from ip_finish_output2
++ * PRE : skb->dev is set to the device we are leaving by
++ * skb->dst is not NULL
++ * POST: the packet is sent with the link layer header pushed
++ * the packet is destroyed
++ */
++static void ip_direct_send(struct sk_buff *skb)
++{
++ struct dst_entry *dst = skb->dst;
++ struct hh_cache *hh = dst->hh;
++ struct net_device *dev = dst->dev;
++ int hh_len = LL_RESERVED_SPACE(dev);
++
++ /* Be paranoid, rather than too clever. */
++ if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
++ struct sk_buff *skb2;
++
++ skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
++ if (skb2 == NULL) {
++ kfree_skb(skb);
++ return;
++ }
++ if (skb->sk)
++ skb_set_owner_w(skb2, skb->sk);
++ kfree_skb(skb);
++ skb = skb2;
++ }
++
++ if (hh) {
++ int hh_alen;
++
++ read_lock_bh(&hh->hh_lock);
++ hh_alen = HH_DATA_ALIGN(hh->hh_len);
++ memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
++ read_unlock_bh(&hh->hh_lock);
++ skb_push(skb, hh->hh_len);
++ hh->hh_output(skb);
++ } else if (dst->neighbour)
++ dst->neighbour->output(skb);
++ else {
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ipt_ROUTE: no hdr & no neighbour cache!\n");
++ kfree_skb(skb);
++ }
++}
++
++
++/* PRE : skb->dev is set to the device we are leaving by
++ * POST: - the packet is directly sent to the skb->dev device, without
++ * pushing the link layer header.
++ * - the packet is destroyed
++ */
++static inline int dev_direct_send(struct sk_buff *skb)
++{
++ return dev_queue_xmit(skb);
++}
++
++
++static unsigned int route_oif(const struct ipt_route_target_info *route_info,
++ struct sk_buff *skb)
++{
++ unsigned int ifindex = 0;
++ struct net_device *dev_out = NULL;
++
++ /* The user set the interface name to use.
++ * Getting the current interface index.
++ */
++ if ((dev_out = dev_get_by_name(route_info->oif))) {
++ ifindex = dev_out->ifindex;
++ } else {
++ /* Unknown interface name : packet dropped */
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: oif interface %s not found\n", route_info->oif);
++ return NF_DROP;
++ }
++
++ /* Trying the standard way of routing packets */
++ switch (route(skb, ifindex, route_info)) {
++ case 1:
++ dev_put(dev_out);
++ if (route_info->flags & IPT_ROUTE_CONTINUE)
++ return IPT_CONTINUE;
++
++ ip_direct_send(skb);
++ return NF_STOLEN;
++
++ case 0:
++ /* Failed to send to oif. Trying the hard way */
++ if (route_info->flags & IPT_ROUTE_CONTINUE)
++ return NF_DROP;
++
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: forcing the use of %i\n",
++ ifindex);
++
++ /* We have to force the use of an interface.
++ * This interface must be a tunnel interface since
++ * otherwise we can't guess the hw address for
++ * the packet. For a tunnel interface, no hw address
++ * is needed.
++ */
++ if ((dev_out->type != ARPHRD_TUNNEL)
++ && (dev_out->type != ARPHRD_IPGRE)) {
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: can't guess the hw addr !\n");
++ dev_put(dev_out);
++ return NF_DROP;
++ }
++
++ /* Send the packet. This will also free skb
++ * Do not go through the POST_ROUTING hook because
++ * skb->dst is not set and because it will probably
++ * get confused by the destination IP address.
++ */
++ skb->dev = dev_out;
++ dev_direct_send(skb);
++ dev_put(dev_out);
++ return NF_STOLEN;
++
++ default:
++ /* Unexpected error */
++ dev_put(dev_out);
++ return NF_DROP;
++ }
++}
++
++
++static unsigned int route_iif(const struct ipt_route_target_info *route_info,
++ struct sk_buff *skb)
++{
++ struct net_device *dev_in = NULL;
++
++ /* Getting the current interface index. */
++ if (!(dev_in = dev_get_by_name(route_info->iif))) {
++ if (net_ratelimit())
++ DEBUGP("ipt_ROUTE: iif interface %s not found\n", route_info->iif);
++ return NF_DROP;
++ }
++
++ skb->dev = dev_in;
++ dst_release(skb->dst);
++ skb->dst = NULL;
++
++ netif_rx(skb);
++ dev_put(dev_in);
++ return NF_STOLEN;
++}
++
++
++static unsigned int route_gw(const struct ipt_route_target_info *route_info,
++ struct sk_buff *skb)
++{
++ if (route(skb, 0, route_info)!=1)
++ return NF_DROP;
++
++ if (route_info->flags & IPT_ROUTE_CONTINUE)
++ return IPT_CONTINUE;
++
++ ip_direct_send(skb);
++ return NF_STOLEN;
++}
++
++
++/* To detect and deter routed packet loopback when using the --tee option,
++ * we take a page out of the raw.patch book: on the copied skb, we set up
++ * a fake ->nfct entry, pointing to the local &route_tee_track. We skip
++ * routing packets when we see they already have that ->nfct.
++ */
++
++static struct ip_conntrack route_tee_track;
++
++static unsigned int ipt_route_target(struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ unsigned int hooknum,
++ const void *targinfo,
++ void *userinfo)
++{
++ const struct ipt_route_target_info *route_info = targinfo;
++ struct sk_buff *skb = *pskb;
++ unsigned int res;
++
++ if (skb->nfct == &route_tee_track.ct_general) {
++ /* Loopback - a packet we already routed, is to be
++ * routed another time. Avoid that, now.
++ */
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ipt_ROUTE: loopback - DROP!\n");
++ return NF_DROP;
++ }
++
++ /* If we are at PREROUTING or INPUT hook
++ * the TTL isn't decreased by the IP stack
++ */
++ if (hooknum == NF_IP_PRE_ROUTING ||
++ hooknum == NF_IP_LOCAL_IN) {
++
++ struct iphdr *iph = skb->nh.iph;
++
++ if (iph->ttl <= 1) {
++ struct rtable *rt;
++ struct flowi fl = {
++ .oif = 0,
++ .nl_u = {
++ .ip4_u = {
++ .daddr = iph->daddr,
++ .saddr = iph->saddr,
++ .tos = RT_TOS(iph->tos),
++ .scope = ((iph->tos & RTO_ONLINK) ?
++ RT_SCOPE_LINK :
++ RT_SCOPE_UNIVERSE)
++ }
++ }
++ };
++
++ if (ip_route_output_key(&rt, &fl)) {
++ return NF_DROP;
++ }
++
++ if (skb->dev == rt->u.dst.dev) {
++ /* Drop old route. */
++ dst_release(skb->dst);
++ skb->dst = &rt->u.dst;
++
++ /* this will traverse normal stack, and
++ * thus call conntrack on the icmp packet */
++ icmp_send(skb, ICMP_TIME_EXCEEDED,
++ ICMP_EXC_TTL, 0);
++ }
++
++ return NF_DROP;
++ }
++
++ /*
++ * If we are at INPUT the checksum must be recalculated since
++ * the length could change as the result of a defragmentation.
++ */
++ if(hooknum == NF_IP_LOCAL_IN) {
++ iph->ttl = iph->ttl - 1;
++ iph->check = 0;
++ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
++ } else {
++ ip_decrease_ttl(iph);
++ }
++ }
++
++ if ((route_info->flags & IPT_ROUTE_TEE)) {
++ /*
++ * Copy the *pskb, and route the copy. Will later return
++ * IPT_CONTINUE for the original skb, which should continue
++ * on its way as if nothing happened. The copy should be
++ * independantly delivered to the ROUTE --gw.
++ */
++ skb = skb_copy(*pskb, GFP_ATOMIC);
++ if (!skb) {
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ipt_ROUTE: copy failed!\n");
++ return IPT_CONTINUE;
++ }
++ }
++
++ /* Tell conntrack to forget this packet since it may get confused
++ * when a packet is leaving with dst address == our address.
++ * Good idea ? Dunno. Need advice.
++ *
++ * NEW: mark the skb with our &route_tee_track, so we avoid looping
++ * on any already routed packet.
++ */
++ if (!(route_info->flags & IPT_ROUTE_CONTINUE)) {
++ nf_conntrack_put(skb->nfct);
++ skb->nfct = &route_tee_track.ct_general;
++ skb->nfctinfo = IP_CT_NEW;
++ nf_conntrack_get(skb->nfct);
++ }
++
++ if (route_info->oif[0] != '\0') {
++ res = route_oif(route_info, skb);
++ } else if (route_info->iif[0] != '\0') {
++ res = route_iif(route_info, skb);
++ } else if (route_info->gw) {
++ res = route_gw(route_info, skb);
++ } else {
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ipt_ROUTE: no parameter !\n");
++ res = IPT_CONTINUE;
++ }
++
++ if ((route_info->flags & IPT_ROUTE_TEE))
++ res = IPT_CONTINUE;
++
++ return res;
++}
++
++
++static int ipt_route_checkentry(const char *tablename,
++ const void *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ if (strcmp(tablename, "mangle") != 0) {
++ printk("ipt_ROUTE: bad table `%s', use the `mangle' table.\n",
++ tablename);
++ return 0;
++ }
++
++ if (hook_mask & ~( (1 << NF_IP_PRE_ROUTING)
++ | (1 << NF_IP_LOCAL_IN)
++ | (1 << NF_IP_FORWARD)
++ | (1 << NF_IP_LOCAL_OUT)
++ | (1 << NF_IP_POST_ROUTING))) {
++ printk("ipt_ROUTE: bad hook\n");
++ return 0;
++ }
++
++ if (targinfosize != IPT_ALIGN(sizeof(struct ipt_route_target_info))) {
++ printk(KERN_WARNING "ipt_ROUTE: targinfosize %u != %Zu\n",
++ targinfosize,
++ IPT_ALIGN(sizeof(struct ipt_route_target_info)));
++ return 0;
++ }
++
++ return 1;
++}
++
++
++static struct ipt_target ipt_route_reg = {
++ .name = "ROUTE",
++ .target = ipt_route_target,
++ .checkentry = ipt_route_checkentry,
++ .me = THIS_MODULE,
++};
++
++static int __init init(void)
++{
++ /* Set up fake conntrack (stolen from raw.patch):
++ - to never be deleted, not in any hashes */
++ atomic_set(&route_tee_track.ct_general.use, 1);
++ /* - and look it like as a confirmed connection */
++ set_bit(IPS_CONFIRMED_BIT, &route_tee_track.status);
++ /* Initialize fake conntrack so that NAT will skip it */
++ route_tee_track.status |= IPS_NAT_DONE_MASK;
++
++ return ipt_register_target(&ipt_route_reg);
++}
++
++
++static void __exit fini(void)
++{
++ ipt_unregister_target(&ipt_route_reg);
++}
++
++module_init(init);
++module_exit(fini);
+diff -u'rNF^function' linux-2.6.16.7/net/ipv6/ipv6_syms.c linux-2.6.16.7-ROUTE/net/ipv6/ipv6_syms.c
+--- linux-2.6.16.7/net/ipv6/ipv6_syms.c 2006-04-17 23:53:25.000000000 +0200
++++ linux-2.6.16.7-ROUTE/net/ipv6/ipv6_syms.c 2006-06-14 17:02:32.000000000 +0200
+@@ -12,6 +12,7 @@
+ EXPORT_SYMBOL(icmpv6_statistics);
+ EXPORT_SYMBOL(icmpv6_err_convert);
+ EXPORT_SYMBOL(ndisc_mc_map);
++EXPORT_SYMBOL(nd_tbl);
+ EXPORT_SYMBOL(register_inet6addr_notifier);
+ EXPORT_SYMBOL(unregister_inet6addr_notifier);
+ EXPORT_SYMBOL(ip6_route_output);
+diff -u'rNF^function' linux-2.6.16.7/net/ipv6/netfilter/Kconfig linux-2.6.16.7-ROUTE/net/ipv6/netfilter/Kconfig
+--- linux-2.6.16.7/net/ipv6/netfilter/Kconfig 2006-06-14 16:05:44.000000000 +0200
++++ linux-2.6.16.7-ROUTE/net/ipv6/netfilter/Kconfig 2006-06-14 16:45:45.000000000 +0200
+@@ -182,6 +182,19 @@
+
+ To compile it as a module, choose M here. If unsure, say N.
+
++config IP6_NF_TARGET_ROUTE
++ tristate ' ROUTE target support'
++ depends on IP6_NF_MANGLE
++ help
++ This option adds a `ROUTE' target, which enables you to setup unusual
++ routes. The ROUTE target is also able to change the incoming interface
++ of a packet.
++
++ The target can be or not a final target. It has to be used inside the
++ mangle table.
++
++ Not working as a module.
++
+ config IP6_NF_MANGLE
+ tristate "Packet mangling"
+ depends on IP6_NF_IPTABLES
+diff -u'rNF^function' linux-2.6.16.7/net/ipv6/netfilter/Makefile linux-2.6.16.7-ROUTE/net/ipv6/netfilter/Makefile
+--- linux-2.6.16.7/net/ipv6/netfilter/Makefile 2006-06-14 16:05:44.000000000 +0200
++++ linux-2.6.16.7-ROUTE/net/ipv6/netfilter/Makefile 2006-06-14 16:45:00.000000000 +0200
+@@ -22,6 +22,7 @@
+ obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
+ obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o
+ obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
++obj-$(CONFIG_IP6_NF_TARGET_ROUTE) += ip6t_ROUTE.o
+
+ # objects for l3 independent conntrack
+ nf_conntrack_ipv6-objs := nf_conntrack_l3proto_ipv6.o nf_conntrack_proto_icmpv6.o nf_conntrack_reasm.o
+diff -u'rNF^function' linux-2.6.16.7/net/ipv6/netfilter/ip6t_ROUTE.c linux-2.6.16.7-ROUTE/net/ipv6/netfilter/ip6t_ROUTE.c
+--- linux-2.6.16.7/net/ipv6/netfilter/ip6t_ROUTE.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.16.7-ROUTE/net/ipv6/netfilter/ip6t_ROUTE.c 2006-06-14 16:42:44.000000000 +0200
+@@ -0,0 +1,308 @@
++/*
++ * This implements the ROUTE v6 target, which enables you to setup unusual
++ * routes not supported by the standard kernel routing table.
++ *
++ * Copyright (C) 2003 Cedric de Launois <delaunois@info.ucl.ac.be>
++ *
++ * v 1.1 2004/11/23
++ *
++ * This software is distributed under GNU GPL v2, 1991
++ */
++
++#include <linux/module.h>
++#include <linux/skbuff.h>
++#include <linux/ipv6.h>
++#include <linux/netfilter_ipv6/ip6_tables.h>
++#include <linux/netfilter_ipv6/ip6t_ROUTE.h>
++#include <linux/netdevice.h>
++#include <net/ipv6.h>
++#include <net/ndisc.h>
++#include <net/ip6_route.h>
++#include <linux/icmpv6.h>
++
++#if 1
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++#define NIP6(addr) \
++ ntohs((addr).s6_addr16[0]), \
++ ntohs((addr).s6_addr16[1]), \
++ ntohs((addr).s6_addr16[2]), \
++ ntohs((addr).s6_addr16[3]), \
++ ntohs((addr).s6_addr16[4]), \
++ ntohs((addr).s6_addr16[5]), \
++ ntohs((addr).s6_addr16[6]), \
++ ntohs((addr).s6_addr16[7])
++
++/* Route the packet according to the routing keys specified in
++ * route_info. Keys are :
++ * - ifindex :
++ * 0 if no oif preferred,
++ * otherwise set to the index of the desired oif
++ * - route_info->gw :
++ * 0 if no gateway specified,
++ * otherwise set to the next host to which the pkt must be routed
++ * If success, skb->dev is the output device to which the packet must
++ * be sent and skb->dst is not NULL
++ *
++ * RETURN: 1 if the packet was succesfully routed to the
++ * destination desired
++ * 0 if the kernel routing table could not route the packet
++ * according to the keys specified
++ */
++static int
++route6(struct sk_buff *skb,
++ unsigned int ifindex,
++ const struct ip6t_route_target_info *route_info)
++{
++ struct rt6_info *rt = NULL;
++ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
++ struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
++
++ DEBUGP("ip6t_ROUTE: called with: ");
++ DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr));
++ DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw));
++ DEBUGP("OUT=%s\n", route_info->oif);
++
++ if (ipv6_addr_any(gw))
++ rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1);
++ else
++ rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1);
++
++ if (!rt)
++ goto no_route;
++
++ DEBUGP("ip6t_ROUTE: routing gives: ");
++ DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr));
++ DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway));
++ DEBUGP("OUT=%s\n", rt->rt6i_dev->name);
++
++ if (ifindex && rt->rt6i_dev->ifindex!=ifindex)
++ goto wrong_route;
++
++ if (!rt->rt6i_nexthop) {
++ DEBUGP("ip6t_ROUTE: discovering neighbour\n");
++ rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr);
++ }
++
++ /* Drop old route. */
++ dst_release(skb->dst);
++ skb->dst = &rt->u.dst;
++ skb->dev = rt->rt6i_dev;
++ return 1;
++
++ wrong_route:
++ dst_release(&rt->u.dst);
++ no_route:
++ if (!net_ratelimit())
++ return 0;
++
++ printk("ip6t_ROUTE: no explicit route found ");
++ if (ifindex)
++ printk("via interface %s ", route_info->oif);
++ if (!ipv6_addr_any(gw))
++ printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw));
++ printk("\n");
++ return 0;
++}
++
++
++/* Stolen from ip6_output_finish
++ * PRE : skb->dev is set to the device we are leaving by
++ * skb->dst is not NULL
++ * POST: the packet is sent with the link layer header pushed
++ * the packet is destroyed
++ */
++static void ip_direct_send(struct sk_buff *skb)
++{
++ struct dst_entry *dst = skb->dst;
++ struct hh_cache *hh = dst->hh;
++
++ if (hh) {
++ read_lock_bh(&hh->hh_lock);
++ memcpy(skb->data - 16, hh->hh_data, 16);
++ read_unlock_bh(&hh->hh_lock);
++ skb_push(skb, hh->hh_len);
++ hh->hh_output(skb);
++ } else if (dst->neighbour)
++ dst->neighbour->output(skb);
++ else {
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ip6t_ROUTE: no hdr & no neighbour cache!\n");
++ kfree_skb(skb);
++ }
++}
++
++
++static unsigned int
++route6_oif(const struct ip6t_route_target_info *route_info,
++ struct sk_buff *skb)
++{
++ unsigned int ifindex = 0;
++ struct net_device *dev_out = NULL;
++
++ /* The user set the interface name to use.
++ * Getting the current interface index.
++ */
++ if ((dev_out = dev_get_by_name(route_info->oif))) {
++ ifindex = dev_out->ifindex;
++ } else {
++ /* Unknown interface name : packet dropped */
++ if (net_ratelimit())
++ DEBUGP("ip6t_ROUTE: oif interface %s not found\n", route_info->oif);
++
++ if (route_info->flags & IP6T_ROUTE_CONTINUE)
++ return IP6T_CONTINUE;
++ else
++ return NF_DROP;
++ }
++
++ /* Trying the standard way of routing packets */
++ if (route6(skb, ifindex, route_info)) {
++ dev_put(dev_out);
++ if (route_info->flags & IP6T_ROUTE_CONTINUE)
++ return IP6T_CONTINUE;
++
++ ip_direct_send(skb);
++ return NF_STOLEN;
++ } else
++ return NF_DROP;
++}
++
++
++static unsigned int
++route6_gw(const struct ip6t_route_target_info *route_info,
++ struct sk_buff *skb)
++{
++ if (route6(skb, 0, route_info)) {
++ if (route_info->flags & IP6T_ROUTE_CONTINUE)
++ return IP6T_CONTINUE;
++
++ ip_direct_send(skb);
++ return NF_STOLEN;
++ } else
++ return NF_DROP;
++}
++
++
++static unsigned int
++ip6t_route_target(struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ unsigned int hooknum,
++ const void *targinfo,
++ void *userinfo)
++{
++ const struct ip6t_route_target_info *route_info = targinfo;
++ struct sk_buff *skb = *pskb;
++ struct in6_addr *gw = (struct in6_addr*)&route_info->gw;
++ unsigned int res;
++
++ if (route_info->flags & IP6T_ROUTE_CONTINUE)
++ goto do_it;
++
++ /* If we are at PREROUTING or INPUT hook
++ * the TTL isn't decreased by the IP stack
++ */
++ if (hooknum == NF_IP6_PRE_ROUTING ||
++ hooknum == NF_IP6_LOCAL_IN) {
++
++ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
++
++ if (ipv6h->hop_limit <= 1) {
++ /* Force OUTPUT device used as source address */
++ skb->dev = skb->dst->dev;
++
++ icmpv6_send(skb, ICMPV6_TIME_EXCEED,
++ ICMPV6_EXC_HOPLIMIT, 0, skb->dev);
++
++ return NF_DROP;
++ }
++
++ ipv6h->hop_limit--;
++ }
++
++ if ((route_info->flags & IP6T_ROUTE_TEE)) {
++ /*
++ * Copy the *pskb, and route the copy. Will later return
++ * IP6T_CONTINUE for the original skb, which should continue
++ * on its way as if nothing happened. The copy should be
++ * independantly delivered to the ROUTE --gw.
++ */
++ skb = skb_copy(*pskb, GFP_ATOMIC);
++ if (!skb) {
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ip6t_ROUTE: copy failed!\n");
++ return IP6T_CONTINUE;
++ }
++ }
++
++do_it:
++ if (route_info->oif[0]) {
++ res = route6_oif(route_info, skb);
++ } else if (!ipv6_addr_any(gw)) {
++ res = route6_gw(route_info, skb);
++ } else {
++ if (net_ratelimit())
++ DEBUGP(KERN_DEBUG "ip6t_ROUTE: no parameter !\n");
++ res = IP6T_CONTINUE;
++ }
++
++ if ((route_info->flags & IP6T_ROUTE_TEE))
++ res = IP6T_CONTINUE;
++
++ return res;
++}
++
++
++static int
++ip6t_route_checkentry(const char *tablename,
++ const struct ip6t_entry *e,
++ void *targinfo,
++ unsigned int targinfosize,
++ unsigned int hook_mask)
++{
++ if (strcmp(tablename, "mangle") != 0) {
++ printk("ip6t_ROUTE: can only be called from \"mangle\" table.\n");
++ return 0;
++ }
++
++ if (targinfosize != IP6T_ALIGN(sizeof(struct ip6t_route_target_info))) {
++ printk(KERN_WARNING "ip6t_ROUTE: targinfosize %u != %Zu\n",
++ targinfosize,
++ IP6T_ALIGN(sizeof(struct ip6t_route_target_info)));
++ return 0;
++ }
++
++ return 1;
++}
++
++
++static struct ip6t_target ip6t_route_reg = {
++ .name = "ROUTE",
++ .target = ip6t_route_target,
++ .checkentry = ip6t_route_checkentry,
++ .me = THIS_MODULE
++};
++
++
++static int __init init(void)
++{
++ printk(KERN_DEBUG "registering ipv6 ROUTE target\n");
++ if (ip6t_register_target(&ip6t_route_reg))
++ return -EINVAL;
++
++ return 0;
++}
++
++
++static void __exit fini(void)
++{
++ ip6t_unregister_target(&ip6t_route_reg);
++}
++
++module_init(init);
++module_exit(fini);
++MODULE_LICENSE("GPL");
diff --git a/target/linux/generic-2.6/patches/200-sched_esfq.patch b/target/linux/generic-2.6/patches/200-sched_esfq.patch
new file mode 100644
index 0000000..8790bad
--- /dev/null
+++ b/target/linux/generic-2.6/patches/200-sched_esfq.patch
@@ -0,0 +1,730 @@
+diff -Naur linux-2.6.15.1.orig/include/linux/pkt_sched.h linux-2.6.15.1/include/linux/pkt_sched.h
+--- linux-2.6.15.1.orig/include/linux/pkt_sched.h 2006-01-14 22:16:02.000000000 -0800
++++ linux-2.6.15.1/include/linux/pkt_sched.h 2006-01-30 16:02:32.000000000 -0800
+@@ -146,8 +146,35 @@
+ *
+ * The only reason for this is efficiency, it is possible
+ * to change these parameters in compile time.
++ *
++ * If you need to play with these values use esfq instead.
+ */
+
++/* ESFQ section */
++
++enum
++{
++ /* traditional */
++ TCA_SFQ_HASH_CLASSIC,
++ TCA_SFQ_HASH_DST,
++ TCA_SFQ_HASH_SRC,
++ TCA_SFQ_HASH_FWMARK,
++ /* direct */
++ TCA_SFQ_HASH_DSTDIR,
++ TCA_SFQ_HASH_SRCDIR,
++ TCA_SFQ_HASH_FWMARKDIR,
++};
++
++struct tc_esfq_qopt
++{
++ unsigned quantum; /* Bytes per round allocated to flow */
++ int perturb_period; /* Period of hash perturbation */
++ __u32 limit; /* Maximal packets in queue */
++ unsigned divisor; /* Hash divisor */
++ unsigned flows; /* Maximal number of flows */
++ unsigned hash_kind; /* Hash function to use for flow identification */
++};
++
+ /* RED section */
+
+ enum
+diff -Naur linux-2.6.15.1.orig/net/sched/Kconfig linux-2.6.15.1/net/sched/Kconfig
+--- linux-2.6.15.1.orig/net/sched/Kconfig 2006-01-14 22:16:02.000000000 -0800
++++ linux-2.6.15.1/net/sched/Kconfig 2006-01-30 16:02:32.000000000 -0800
+@@ -185,6 +185,28 @@
+ To compile this code as a module, choose M here: the
+ module will be called sch_sfq.
+
++config NET_SCH_ESFQ
++ tristate "ESFQ queue"
++ depends on NET_SCHED
++ ---help---
++ Say Y here if you want to use the Enhanced Stochastic Fairness
++ Queueing (ESFQ) packet scheduling algorithm for some of your network
++ devices or as a leaf discipline for a classful qdisc such as HTB or
++ CBQ (see the top of <file:net/sched/sch_esfq.c> for details and
++ references to the SFQ algorithm).
++
++ This is an enchanced SFQ version which allows you to control some
++ hardcoded values in the SFQ scheduler: queue depth, hash table size,
++ and queues limit.
++
++ ESFQ also adds control to the hash function used to identify packet
++ flows. The original SFQ hashes by individual flow (TCP session or UDP
++ stream); ESFQ can hash by src or dst IP as well, which can be more
++ fair to users in some networking situations.
++
++ To compile this code as a module, choose M here: the
++ module will be called sch_esfq.
++
+ config NET_SCH_TEQL
+ tristate "True Link Equalizer (TEQL)"
+ ---help---
+diff -Naur linux-2.6.15.1.orig/net/sched/Makefile linux-2.6.15.1/net/sched/Makefile
+--- linux-2.6.15.1.orig/net/sched/Makefile 2006-01-14 22:16:02.000000000 -0800
++++ linux-2.6.15.1/net/sched/Makefile 2006-01-30 16:02:32.000000000 -0800
+@@ -23,6 +23,7 @@
+ obj-$(CONFIG_NET_SCH_INGRESS) += sch_ingress.o
+ obj-$(CONFIG_NET_SCH_DSMARK) += sch_dsmark.o
+ obj-$(CONFIG_NET_SCH_SFQ) += sch_sfq.o
++obj-$(CONFIG_NET_SCH_ESFQ) += sch_esfq.o
+ obj-$(CONFIG_NET_SCH_TBF) += sch_tbf.o
+ obj-$(CONFIG_NET_SCH_TEQL) += sch_teql.o
+ obj-$(CONFIG_NET_SCH_PRIO) += sch_prio.o
+diff -Naur linux-2.6.15.1.orig/net/sched/sch_esfq.c linux-2.6.15.1/net/sched/sch_esfq.c
+--- linux-2.6.15.1.orig/net/sched/sch_esfq.c 1969-12-31 16:00:00.000000000 -0800
++++ linux-2.6.15.1/net/sched/sch_esfq.c 2006-01-30 16:12:29.000000000 -0800
+@@ -0,0 +1,644 @@
++/*
++ * net/sched/sch_esfq.c Extended Stochastic Fairness Queueing discipline.
++ *
++ * 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.
++ *
++ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
++ *
++ * Changes: Alexander Atanasov, <alex@ssi.bg>
++ * Added dynamic depth,limit,divisor,hash_kind options.
++ * Added dst and src hashes.
++ *
++ * Alexander Clouter, <alex@digriz.org.uk>
++ * Ported ESFQ to Linux 2.6.
++ *
++ * Corey Hickey, <bugfood-c@fatooh.org>
++ * Maintenance of the Linux 2.6 port.
++ * Added fwmark hash (thanks to Robert Kurjata)
++ * Added direct hashing for src, dst, and fwmark.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <asm/uaccess.h>
++#include <asm/system.h>
++#include <linux/bitops.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/jiffies.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/socket.h>
++#include <linux/sockios.h>
++#include <linux/in.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/if_ether.h>
++#include <linux/inet.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/notifier.h>
++#include <linux/init.h>
++#include <net/ip.h>
++#include <linux/ipv6.h>
++#include <net/route.h>
++#include <linux/skbuff.h>
++#include <net/sock.h>
++#include <net/pkt_sched.h>
++
++
++/* Stochastic Fairness Queuing algorithm.
++ For more comments look at sch_sfq.c.
++ The difference is that you can change limit, depth,
++ hash table size and choose 7 hash types.
++
++ classic: same as in sch_sfq.c
++ dst: destination IP address
++ src: source IP address
++ fwmark: netfilter mark value
++ dst_direct:
++ src_direct:
++ fwmark_direct: direct hashing of the above sources
++
++ TODO:
++ make sfq_change work.
++*/
++
++
++/* This type should contain at least SFQ_DEPTH*2 values */
++typedef unsigned int esfq_index;
++
++struct esfq_head
++{
++ esfq_index next;
++ esfq_index prev;
++};
++
++struct esfq_sched_data
++{
++/* Parameters */
++ int perturb_period;
++ unsigned quantum; /* Allotment per round: MUST BE >= MTU */
++ int limit;
++ unsigned depth;
++ unsigned hash_divisor;
++ unsigned hash_kind;
++/* Variables */
++ struct timer_list perturb_timer;
++ int perturbation;
++ esfq_index tail; /* Index of current slot in round */
++ esfq_index max_depth; /* Maximal depth */
++
++ esfq_index *ht; /* Hash table */
++ esfq_index *next; /* Active slots link */
++ short *allot; /* Current allotment per slot */
++ unsigned short *hash; /* Hash value indexed by slots */
++ struct sk_buff_head *qs; /* Slot queue */
++ struct esfq_head *dep; /* Linked list of slots, indexed by depth */
++ unsigned dyn_min; /* For dynamic divisor adjustment; minimum value seen */
++ unsigned dyn_max; /* maximum value seen */
++ unsigned dyn_range; /* saved range */
++};
++
++static __inline__ unsigned esfq_hash_u32(struct esfq_sched_data *q,u32 h)
++{
++ int pert = q->perturbation;
++
++ if (pert)
++ h = (h<<pert) ^ (h>>(0x1F - pert));
++
++ h = ntohl(h) * 2654435761UL;
++ return h & (q->hash_divisor-1);
++}
++
++/* Hash input values directly into the "nearest" slot, taking into account the
++ * range of input values seen. This is most useful when the hash table is at
++ * least as large as the range of possible values. */
++static __inline__ unsigned esfq_hash_direct(struct esfq_sched_data *q, u32 h)
++{
++ /* adjust minimum and maximum */
++ if (h < q->dyn_min || h > q->dyn_max) {
++ q->dyn_min = h < q->dyn_min ? h : q->dyn_min;
++ q->dyn_max = h > q->dyn_max ? h : q->dyn_max;
++
++ /* find new range */
++ if ((q->dyn_range = q->dyn_max - q->dyn_min) >= q->hash_divisor)
++ printk(KERN_WARNING "ESFQ: (direct hash) Input range %u is larger than hash "
++ "table. See ESFQ README for details.\n", q->dyn_range);
++ }
++
++ /* hash input values into slot numbers */
++ if (q->dyn_min == q->dyn_max)
++ return 0; /* only one value seen; avoid division by 0 */
++ else
++ return (h - q->dyn_min) * (q->hash_divisor - 1) / q->dyn_range;
++}
++
++static __inline__ unsigned esfq_fold_hash_classic(struct esfq_sched_data *q, u32 h, u32 h1)
++{
++ int pert = q->perturbation;
++
++ /* Have we any rotation primitives? If not, WHY? */
++ h ^= (h1<<pert) ^ (h1>>(0x1F - pert));
++ h ^= h>>10;
++ return h & (q->hash_divisor-1);
++}
++
++static unsigned esfq_hash(struct esfq_sched_data *q, struct sk_buff *skb)
++{
++ u32 h, h2;
++ u32 hs;
++ u32 nfm;
++
++ switch (skb->protocol) {
++ case __constant_htons(ETH_P_IP):
++ {
++ struct iphdr *iph = skb->nh.iph;
++ h = iph->daddr;
++ hs = iph->saddr;
++ nfm = skb->nfmark;
++ h2 = hs^iph->protocol;
++ if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
++ (iph->protocol == IPPROTO_TCP ||
++ iph->protocol == IPPROTO_UDP ||
++ iph->protocol == IPPROTO_SCTP ||
++ iph->protocol == IPPROTO_DCCP ||
++ iph->protocol == IPPROTO_ESP))
++ h2 ^= *(((u32*)iph) + iph->ihl);
++ break;
++ }
++ case __constant_htons(ETH_P_IPV6):
++ {
++ struct ipv6hdr *iph = skb->nh.ipv6h;
++ h = iph->daddr.s6_addr32[3];
++ hs = iph->saddr.s6_addr32[3];
++ nfm = skb->nfmark;
++ h2 = hs^iph->nexthdr;
++ if (iph->nexthdr == IPPROTO_TCP ||
++ iph->nexthdr == IPPROTO_UDP ||
++ iph->nexthdr == IPPROTO_SCTP ||
++ iph->nexthdr == IPPROTO_DCCP ||
++ iph->nexthdr == IPPROTO_ESP)
++ h2 ^= *(u32*)&iph[1];
++ break;
++ }
++ default:
++ h = (u32)(unsigned long)skb->dst;
++ hs = (u32)(unsigned long)skb->sk;
++ nfm = skb->nfmark;
++ h2 = hs^skb->protocol;
++ }
++ switch(q->hash_kind)
++ {
++ case TCA_SFQ_HASH_CLASSIC:
++ return esfq_fold_hash_classic(q, h, h2);
++ case TCA_SFQ_HASH_DST:
++ return esfq_hash_u32(q,h);
++ case TCA_SFQ_HASH_DSTDIR:
++ return esfq_hash_direct(q, ntohl(h));
++ case TCA_SFQ_HASH_SRC:
++ return esfq_hash_u32(q,hs);
++ case TCA_SFQ_HASH_SRCDIR:
++ return esfq_hash_direct(q, ntohl(hs));
++#ifdef CONFIG_NETFILTER
++ case TCA_SFQ_HASH_FWMARK:
++ return esfq_hash_u32(q,nfm);
++ case TCA_SFQ_HASH_FWMARKDIR:
++ return esfq_hash_direct(q,nfm);
++#endif
++ default:
++ if (net_ratelimit())
++ printk(KERN_WARNING "ESFQ: Unknown hash method. Falling back to classic.\n");
++ }
++ return esfq_fold_hash_classic(q, h, h2);
++}
++
++static inline void esfq_link(struct esfq_sched_data *q, esfq_index x)
++{
++ esfq_index p, n;
++ int d = q->qs[x].qlen + q->depth;
++
++ p = d;
++ n = q->dep[d].next;
++ q->dep[x].next = n;
++ q->dep[x].prev = p;
++ q->dep[p].next = q->dep[n].prev = x;
++}
++
++static inline void esfq_dec(struct esfq_sched_data *q, esfq_index x)
++{
++ esfq_index p, n;
++
++ n = q->dep[x].next;
++ p = q->dep[x].prev;
++ q->dep[p].next = n;
++ q->dep[n].prev = p;
++
++ if (n == p && q->max_depth == q->qs[x].qlen + 1)
++ q->max_depth--;
++
++ esfq_link(q, x);
++}
++
++static inline void esfq_inc(struct esfq_sched_data *q, esfq_index x)
++{
++ esfq_index p, n;
++ int d;
++
++ n = q->dep[x].next;
++ p = q->dep[x].prev;
++ q->dep[p].next = n;
++ q->dep[n].prev = p;
++ d = q->qs[x].qlen;
++ if (q->max_depth < d)
++ q->max_depth = d;
++
++ esfq_link(q, x);
++}
++
++static unsigned int esfq_drop(struct Qdisc *sch)
++{
++ struct esfq_sched_data *q = qdisc_priv(sch);
++ esfq_index d = q->max_depth;
++ struct sk_buff *skb;
++ unsigned int len;
++
++ /* Queue is full! Find the longest slot and
++ drop a packet from it */
++
++ if (d > 1) {
++ esfq_index x = q->dep[d+q->depth].next;
++ skb = q->qs[x].prev;
++ len = skb->len;
++ __skb_unlink(skb, &q->qs[x]);
++ kfree_skb(skb);
++ esfq_dec(q, x);
++ sch->q.qlen--;
++ sch->qstats.drops++;
++ return len;
++ }
++
++ if (d == 1) {
++ /* It is difficult to believe, but ALL THE SLOTS HAVE LENGTH 1. */
++ d = q->next[q->tail];
++ q->next[q->tail] = q->next[d];
++ q->allot[q->next[d]] += q->quantum;
++ skb = q->qs[d].prev;
++ len = skb->len;
++ __skb_unlink(skb, &q->qs[d]);
++ kfree_skb(skb);
++ esfq_dec(q, d);
++ sch->q.qlen--;
++ q->ht[q->hash[d]] = q->depth;
++ sch->qstats.drops++;
++ return len;
++ }
++
++ return 0;
++}
++
++static int
++esfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
++{
++ struct esfq_sched_data *q = qdisc_priv(sch);
++ unsigned hash = esfq_hash(q, skb);
++ unsigned depth = q->depth;
++ esfq_index x;
++
++ x = q->ht[hash];
++ if (x == depth) {
++ q->ht[hash] = x = q->dep[depth].next;
++ q->hash[x] = hash;
++ }
++ __skb_queue_tail(&q->qs[x], skb);
++ esfq_inc(q, x);
++ if (q->qs[x].qlen == 1) { /* The flow is new */
++ if (q->tail == depth) { /* It is the first flow */
++ q->tail = x;
++ q->next[x] = x;
++ q->allot[x] = q->quantum;
++ } else {
++ q->next[x] = q->next[q->tail];
++ q->next[q->tail] = x;
++ q->tail = x;
++ }
++ }
++ if (++sch->q.qlen < q->limit-1) {
++ sch->bstats.bytes += skb->len;
++ sch->bstats.packets++;
++ return 0;
++ }
++
++ esfq_drop(sch);
++ return NET_XMIT_CN;
++}
++
++static int
++esfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
++{
++ struct esfq_sched_data *q = qdisc_priv(sch);
++ unsigned hash = esfq_hash(q, skb);
++ unsigned depth = q->depth;
++ esfq_index x;
++
++ x = q->ht[hash];
++ if (x == depth) {
++ q->ht[hash] = x = q->dep[depth].next;
++ q->hash[x] = hash;
++ }
++ __skb_queue_head(&q->qs[x], skb);
++ esfq_inc(q, x);
++ if (q->qs[x].qlen == 1) { /* The flow is new */
++ if (q->tail == depth) { /* It is the first flow */
++ q->tail = x;
++ q->next[x] = x;
++ q->allot[x] = q->quantum;
++ } else {
++ q->next[x] = q->next[q->tail];
++ q->next[q->tail] = x;
++ q->tail = x;
++ }
++ }
++ if (++sch->q.qlen < q->limit - 1) {
++ sch->qstats.requeues++;
++ return 0;
++ }
++
++ sch->qstats.drops++;
++ esfq_drop(sch);
++ return NET_XMIT_CN;
++}
++
++
++
++
++static struct sk_buff *
++esfq_dequeue(struct Qdisc* sch)
++{
++ struct esfq_sched_data *q = qdisc_priv(sch);
++ struct sk_buff *skb;
++ unsigned depth = q->depth;
++ esfq_index a, old_a;
++
++ /* No active slots */
++ if (q->tail == depth)
++ return NULL;
++
++ a = old_a = q->next[q->tail];
++
++ /* Grab packet */
++ skb = __skb_dequeue(&q->qs[a]);
++ esfq_dec(q, a);
++ sch->q.qlen--;
++
++ /* Is the slot empty? */
++ if (q->qs[a].qlen == 0) {
++ q->ht[q->hash[a]] = depth;
++ a = q->next[a];
++ if (a == old_a) {
++ q->tail = depth;
++ return skb;
++ }
++ q->next[q->tail] = a;
++ q->allot[a] += q->quantum;
++ } else if ((q->allot[a] -= skb->len) <= 0) {
++ q->tail = a;
++ a = q->next[a];
++ q->allot[a] += q->quantum;
++ }
++
++ return skb;
++}
++
++static void
++esfq_reset(struct Qdisc* sch)
++{
++ struct sk_buff *skb;
++
++ while ((skb = esfq_dequeue(sch)) != NULL)
++ kfree_skb(skb);
++}
++
++static void esfq_perturbation(unsigned long arg)
++{
++ struct Qdisc *sch = (struct Qdisc*)arg;
++ struct esfq_sched_data *q = qdisc_priv(sch);
++
++ q->perturbation = net_random()&0x1F;
++
++ if (q->perturb_period) {
++ q->perturb_timer.expires = jiffies + q->perturb_period;
++ add_timer(&q->perturb_timer);
++ }
++}
++
++static int esfq_change(struct Qdisc *sch, struct rtattr *opt)
++{
++ struct esfq_sched_data *q = qdisc_priv(sch);
++ struct tc_esfq_qopt *ctl = RTA_DATA(opt);
++ int old_perturb = q->perturb_period;
++
++ if (opt->rta_len < RTA_LENGTH(sizeof(*ctl)))
++ return -EINVAL;
++
++ sch_tree_lock(sch);
++ q->quantum = ctl->quantum ? : psched_mtu(sch->dev);
++ q->perturb_period = ctl->perturb_period*HZ;
++// q->hash_divisor = ctl->divisor;
++// q->tail = q->limit = q->depth = ctl->flows;
++
++ if (ctl->limit)
++ q->limit = min_t(u32, ctl->limit, q->depth);
++
++ if (ctl->hash_kind) {
++ q->hash_kind = ctl->hash_kind;
++ if (q->hash_kind != TCA_SFQ_HASH_CLASSIC)
++ q->perturb_period = 0;
++ }
++
++ // is sch_tree_lock enough to do this ?
++ while (sch->q.qlen >= q->limit-1)
++ esfq_drop(sch);
++
++ if (old_perturb)
++ del_timer(&q->perturb_timer);
++ if (q->perturb_period) {
++ q->perturb_timer.expires = jiffies + q->perturb_period;
++ add_timer(&q->perturb_timer);
++ } else {
++ q->perturbation = 0;
++ }
++ sch_tree_unlock(sch);
++ return 0;
++}
++
++static int esfq_init(struct Qdisc *sch, struct rtattr *opt)
++{
++ struct esfq_sched_data *q = qdisc_priv(sch);
++ struct tc_esfq_qopt *ctl;
++ esfq_index p = ~0UL/2;
++ int i;
++
++ if (opt && opt->rta_len < RTA_LENGTH(sizeof(*ctl)))
++ return -EINVAL;
++
++ init_timer(&q->perturb_timer);
++ q->perturb_timer.data = (unsigned long)sch;
++ q->perturb_timer.function = esfq_perturbation;
++ q->perturbation = 0;
++ q->hash_kind = TCA_SFQ_HASH_CLASSIC;
++ q->max_depth = 0;
++ q->dyn_min = ~0U; /* maximum value for this type */
++ q->dyn_max = 0; /* dyn_min/dyn_max will be set properly upon first packet */
++ if (opt == NULL) {
++ q->quantum = psched_mtu(sch->dev);
++ q->perturb_period = 0;
++ q->hash_divisor = 1024;
++ q->tail = q->limit = q->depth = 128;
++
++ } else {
++ ctl = RTA_DATA(opt);
++ q->quantum = ctl->quantum ? : psched_mtu(sch->dev);
++ q->perturb_period = ctl->perturb_period*HZ;
++ q->hash_divisor = ctl->divisor ? : 1024;
++ q->tail = q->limit = q->depth = ctl->flows ? : 128;
++
++ if ( q->depth > p - 1 )
++ return -EINVAL;
++
++ if (ctl->limit)
++ q->limit = min_t(u32, ctl->limit, q->depth);
++
++ if (ctl->hash_kind) {
++ q->hash_kind = ctl->hash_kind;
++ }
++
++ if (q->perturb_period) {
++ q->perturb_timer.expires = jiffies + q->perturb_period;
++ add_timer(&q->perturb_timer);
++ }
++ }
++
++ q->ht = kmalloc(q->hash_divisor*sizeof(esfq_index), GFP_KERNEL);
++ if (!q->ht)
++ goto err_case;
++
++ q->dep = kmalloc((1+q->depth*2)*sizeof(struct esfq_head), GFP_KERNEL);
++ if (!q->dep)
++ goto err_case;
++ q->next = kmalloc(q->depth*sizeof(esfq_index), GFP_KERNEL);
++ if (!q->next)
++ goto err_case;
++
++ q->allot = kmalloc(q->depth*sizeof(short), GFP_KERNEL);
++ if (!q->allot)
++ goto err_case;
++ q->hash = kmalloc(q->depth*sizeof(unsigned short), GFP_KERNEL);
++ if (!q->hash)
++ goto err_case;
++ q->qs = kmalloc(q->depth*sizeof(struct sk_buff_head), GFP_KERNEL);
++ if (!q->qs)
++ goto err_case;
++
++ for (i=0; i< q->hash_divisor; i++)
++ q->ht[i] = q->depth;
++ for (i=0; i<q->depth; i++) {
++ skb_queue_head_init(&q->qs[i]);
++ q->dep[i+q->depth].next = i+q->depth;
++ q->dep[i+q->depth].prev = i+q->depth;
++ }
++
++ for (i=0; i<q->depth; i++)
++ esfq_link(q, i);
++ return 0;
++err_case:
++ del_timer(&q->perturb_timer);
++ if (q->ht)
++ kfree(q->ht);
++ if (q->dep)
++ kfree(q->dep);
++ if (q->next)
++ kfree(q->next);
++ if (q->allot)
++ kfree(q->allot);
++ if (q->hash)
++ kfree(q->hash);
++ if (q->qs)
++ kfree(q->qs);
++ return -ENOBUFS;
++}
++
++static void esfq_destroy(struct Qdisc *sch)
++{
++ struct esfq_sched_data *q = qdisc_priv(sch);
++ del_timer(&q->perturb_timer);
++ if(q->ht)
++ kfree(q->ht);
++ if(q->dep)
++ kfree(q->dep);
++ if(q->next)
++ kfree(q->next);
++ if(q->allot)
++ kfree(q->allot);
++ if(q->hash)
++ kfree(q->hash);
++ if(q->qs)
++ kfree(q->qs);
++}
++
++static int esfq_dump(struct Qdisc *sch, struct sk_buff *skb)
++{
++ struct esfq_sched_data *q = qdisc_priv(sch);
++ unsigned char *b = skb->tail;
++ struct tc_esfq_qopt opt;
++
++ opt.quantum = q->quantum;
++ opt.perturb_period = q->perturb_period/HZ;
++
++ opt.limit = q->limit;
++ opt.divisor = q->hash_divisor;
++ opt.flows = q->depth;
++ opt.hash_kind = q->hash_kind;
++
++ RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
++
++ return skb->len;
++
++rtattr_failure:
++ skb_trim(skb, b - skb->data);
++ return -1;
++}
++
++static struct Qdisc_ops esfq_qdisc_ops =
++{
++ .next = NULL,
++ .cl_ops = NULL,
++ .id = "esfq",
++ .priv_size = sizeof(struct esfq_sched_data),
++ .enqueue = esfq_enqueue,
++ .dequeue = esfq_dequeue,
++ .requeue = esfq_requeue,
++ .drop = esfq_drop,
++ .init = esfq_init,
++ .reset = esfq_reset,
++ .destroy = esfq_destroy,
++ .change = NULL, /* esfq_change - needs more work */
++ .dump = esfq_dump,
++ .owner = THIS_MODULE,
++};
++
++static int __init esfq_module_init(void)
++{
++ return register_qdisc(&esfq_qdisc_ops);
++}
++static void __exit esfq_module_exit(void)
++{
++ unregister_qdisc(&esfq_qdisc_ops);
++}
++module_init(esfq_module_init)
++module_exit(esfq_module_exit)
++MODULE_LICENSE("GPL");
diff --git a/target/linux/generic-2.6/patches/201-multiple_default_gateways.patch b/target/linux/generic-2.6/patches/201-multiple_default_gateways.patch
new file mode 100644
index 0000000..3be34d7
--- /dev/null
+++ b/target/linux/generic-2.6/patches/201-multiple_default_gateways.patch
@@ -0,0 +1,1238 @@
+diff -Nur linux-2.6.17/include/linux/netfilter_ipv4/ip_nat.h linux-2.6.17-owrt/include/linux/netfilter_ipv4/ip_nat.h
+--- linux-2.6.17/include/linux/netfilter_ipv4/ip_nat.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/linux/netfilter_ipv4/ip_nat.h 2006-06-18 16:53:21.000000000 +0200
+@@ -63,6 +63,13 @@
+
+ struct ip_conntrack;
+
++/* Call input routing for SNAT-ed traffic */
++extern unsigned int ip_nat_route_input(unsigned int hooknum,
++ struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ int (*okfn)(struct sk_buff *));
++
+ /* Set up the info structure to map into this range. */
+ extern unsigned int ip_nat_setup_info(struct ip_conntrack *conntrack,
+ const struct ip_nat_range *range,
+diff -Nur linux-2.6.17/include/linux/rtnetlink.h linux-2.6.17-owrt/include/linux/rtnetlink.h
+--- linux-2.6.17/include/linux/rtnetlink.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/linux/rtnetlink.h 2006-06-18 16:53:21.000000000 +0200
+@@ -293,6 +293,8 @@
+ #define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */
+ #define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */
+ #define RTNH_F_ONLINK 4 /* Gateway is forced on link */
++#define RTNH_F_SUSPECT 8 /* We don't know the real state */
++#define RTNH_F_BADSTATE (RTNH_F_DEAD | RTNH_F_SUSPECT)
+
+ /* Macros to handle hexthops */
+
+diff -Nur linux-2.6.17/include/net/flow.h linux-2.6.17-owrt/include/net/flow.h
+--- linux-2.6.17/include/net/flow.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/net/flow.h 2006-06-18 16:53:21.000000000 +0200
+@@ -19,6 +19,8 @@
+ __u32 daddr;
+ __u32 saddr;
+ __u32 fwmark;
++ __u32 lsrc;
++ __u32 gw;
+ __u8 tos;
+ __u8 scope;
+ } ip4_u;
+@@ -46,6 +48,8 @@
+ #define fl4_dst nl_u.ip4_u.daddr
+ #define fl4_src nl_u.ip4_u.saddr
+ #define fl4_fwmark nl_u.ip4_u.fwmark
++#define fl4_lsrc nl_u.ip4_u.lsrc
++#define fl4_gw nl_u.ip4_u.gw
+ #define fl4_tos nl_u.ip4_u.tos
+ #define fl4_scope nl_u.ip4_u.scope
+
+diff -Nur linux-2.6.17/include/net/ip_fib.h linux-2.6.17-owrt/include/net/ip_fib.h
+--- linux-2.6.17/include/net/ip_fib.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/net/ip_fib.h 2006-06-18 16:53:21.000000000 +0200
+@@ -195,7 +195,8 @@
+
+ static inline void fib_select_default(const struct flowi *flp, struct fib_result *res)
+ {
+- if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
++ if ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
++ FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)
+ ip_fib_main_table->tb_select_default(ip_fib_main_table, flp, res);
+ }
+
+@@ -207,6 +208,7 @@
+ extern int fib_lookup(const struct flowi *flp, struct fib_result *res);
+ extern struct fib_table *__fib_new_table(int id);
+ extern void fib_rule_put(struct fib_rule *r);
++extern int fib_result_table(struct fib_result *res);
+
+ static inline struct fib_table *fib_get_table(int id)
+ {
+@@ -302,4 +304,6 @@
+ extern void fib_proc_exit(void);
+ #endif
+
++extern rwlock_t fib_nhflags_lock;
++
+ #endif /* _NET_FIB_H */
+diff -Nur linux-2.6.17/include/net/route.h linux-2.6.17-owrt/include/net/route.h
+--- linux-2.6.17/include/net/route.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/net/route.h 2006-06-18 16:53:21.000000000 +0200
+@@ -117,6 +117,7 @@
+ extern int ip_route_output_key(struct rtable **, struct flowi *flp);
+ extern int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
+ extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin);
++extern int ip_route_input_lookup(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin, u32 lsrc);
+ extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
+ extern void ip_rt_send_redirect(struct sk_buff *skb);
+
+diff -Nur linux-2.6.17/net/ipv4/fib_frontend.c linux-2.6.17-owrt/net/ipv4/fib_frontend.c
+--- linux-2.6.17/net/ipv4/fib_frontend.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/fib_frontend.c 2006-06-18 16:53:21.000000000 +0200
+@@ -56,6 +56,8 @@
+ struct fib_table *ip_fib_local_table;
+ struct fib_table *ip_fib_main_table;
+
++#define FIB_RES_TABLE(r) (RT_TABLE_MAIN)
++
+ #else
+
+ #define RT_TABLE_MIN 1
+@@ -73,6 +75,7 @@
+ return tb;
+ }
+
++#define FIB_RES_TABLE(r) (fib_result_table(r))
+
+ #endif /* CONFIG_IP_MULTIPLE_TABLES */
+
+@@ -170,6 +173,9 @@
+ .tos = tos } },
+ .iif = oif };
+ struct fib_result res;
++ int table;
++ unsigned char prefixlen;
++ unsigned char scope;
+ int no_addr, rpf;
+ int ret;
+
+@@ -191,31 +197,35 @@
+ goto e_inval_res;
+ *spec_dst = FIB_RES_PREFSRC(res);
+ fib_combine_itag(itag, &res);
+-#ifdef CONFIG_IP_ROUTE_MULTIPATH
+- if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)
+-#else
+ if (FIB_RES_DEV(res) == dev)
+-#endif
+ {
+ ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
+ fib_res_put(&res);
+ return ret;
+ }
++ table = FIB_RES_TABLE(&res);
++ prefixlen = res.prefixlen;
++ scope = res.scope;
+ fib_res_put(&res);
+ if (no_addr)
+ goto last_resort;
+- if (rpf)
+- goto e_inval;
+ fl.oif = dev->ifindex;
+
+ ret = 0;
+ if (fib_lookup(&fl, &res) == 0) {
+- if (res.type == RTN_UNICAST) {
++ if (res.type == RTN_UNICAST &&
++ ((table == FIB_RES_TABLE(&res) &&
++ res.prefixlen >= prefixlen && res.scope >= scope) ||
++ !rpf)) {
+ *spec_dst = FIB_RES_PREFSRC(res);
+ ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;
++ fib_res_put(&res);
++ return ret;
+ }
+ fib_res_put(&res);
+ }
++ if (rpf)
++ goto e_inval;
+ return ret;
+
+ last_resort:
+@@ -589,9 +599,7 @@
+ switch (event) {
+ case NETDEV_UP:
+ fib_add_ifaddr(ifa);
+-#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ fib_sync_up(ifa->ifa_dev->dev);
+-#endif
+ rt_cache_flush(-1);
+ break;
+ case NETDEV_DOWN:
+@@ -627,9 +635,7 @@
+ for_ifa(in_dev) {
+ fib_add_ifaddr(ifa);
+ } endfor_ifa(in_dev);
+-#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ fib_sync_up(dev);
+-#endif
+ rt_cache_flush(-1);
+ break;
+ case NETDEV_DOWN:
+diff -Nur linux-2.6.17/net/ipv4/fib_hash.c linux-2.6.17-owrt/net/ipv4/fib_hash.c
+--- linux-2.6.17/net/ipv4/fib_hash.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/fib_hash.c 2006-06-18 16:53:21.000000000 +0200
+@@ -277,30 +277,38 @@
+ return err;
+ }
+
+-static int fn_hash_last_dflt=-1;
+-
+ static void
+ fn_hash_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
+ {
+- int order, last_idx;
++ int order, last_idx, last_dflt, last_nhsel;
++ struct fib_alias *first_fa = NULL;
++ struct hlist_head *head;
+ struct hlist_node *node;
+ struct fib_node *f;
+ struct fib_info *fi = NULL;
+ struct fib_info *last_resort;
+ struct fn_hash *t = (struct fn_hash*)tb->tb_data;
+- struct fn_zone *fz = t->fn_zones[0];
++ struct fn_zone *fz = t->fn_zones[res->prefixlen];
++ u32 k;
+
+ if (fz == NULL)
+ return;
+
++ k = fz_key(flp->fl4_dst, fz);
++ last_dflt = -2;
++ last_nhsel = 0;
+ last_idx = -1;
+ last_resort = NULL;
+ order = -1;
+
+ read_lock(&fib_hash_lock);
+- hlist_for_each_entry(f, node, &fz->fz_hash[0], fn_hash) {
++ head = &fz->fz_hash[fn_hash(k, fz)];
++ hlist_for_each_entry(f, node, head, fn_hash) {
+ struct fib_alias *fa;
+
++ if (f->fn_key != k)
++ continue;
++
+ list_for_each_entry(fa, &f->fn_alias, fa_list) {
+ struct fib_info *next_fi = fa->fa_info;
+
+@@ -308,41 +316,52 @@
+ fa->fa_type != RTN_UNICAST)
+ continue;
+
++ if (fa->fa_tos &&
++ fa->fa_tos != flp->fl4_tos)
++ continue;
+ if (next_fi->fib_priority > res->fi->fib_priority)
+ break;
+- if (!next_fi->fib_nh[0].nh_gw ||
+- next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
+- continue;
+ fa->fa_state |= FA_S_ACCESSED;
+
+- if (fi == NULL) {
+- if (next_fi != res->fi)
+- break;
+- } else if (!fib_detect_death(fi, order, &last_resort,
+- &last_idx, &fn_hash_last_dflt)) {
++ if (!first_fa) {
++ last_dflt = fa->fa_last_dflt;
++ first_fa = fa;
++ }
++ if (fi && !fib_detect_death(fi, order, &last_resort,
++ &last_idx, &last_dflt, &last_nhsel, flp)) {
+ if (res->fi)
+ fib_info_put(res->fi);
+ res->fi = fi;
+ atomic_inc(&fi->fib_clntref);
+- fn_hash_last_dflt = order;
++ first_fa->fa_last_dflt = order;
+ goto out;
+ }
+ fi = next_fi;
+ order++;
+ }
++ break;
+ }
+
+ if (order <= 0 || fi == NULL) {
+- fn_hash_last_dflt = -1;
++ if (fi && fi->fib_nhs > 1 &&
++ fib_detect_death(fi, order, &last_resort, &last_idx,
++ &last_dflt, &last_nhsel, flp) &&
++ last_resort == fi) {
++ read_lock_bh(&fib_nhflags_lock);
++ fi->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
++ read_unlock_bh(&fib_nhflags_lock);
++ }
++ if (first_fa) first_fa->fa_last_dflt = -1;
+ goto out;
+ }
+
+- if (!fib_detect_death(fi, order, &last_resort, &last_idx, &fn_hash_last_dflt)) {
++ if (!fib_detect_death(fi, order, &last_resort, &last_idx,
++ &last_dflt, &last_nhsel, flp)) {
+ if (res->fi)
+ fib_info_put(res->fi);
+ res->fi = fi;
+ atomic_inc(&fi->fib_clntref);
+- fn_hash_last_dflt = order;
++ first_fa->fa_last_dflt = order;
+ goto out;
+ }
+
+@@ -352,8 +371,11 @@
+ res->fi = last_resort;
+ if (last_resort)
+ atomic_inc(&last_resort->fib_clntref);
++ read_lock_bh(&fib_nhflags_lock);
++ last_resort->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT;
++ read_unlock_bh(&fib_nhflags_lock);
++ first_fa->fa_last_dflt = last_idx;
+ }
+- fn_hash_last_dflt = last_idx;
+ out:
+ read_unlock(&fib_hash_lock);
+ }
+@@ -452,6 +474,7 @@
+ write_lock_bh(&fib_hash_lock);
+ fi_drop = fa->fa_info;
+ fa->fa_info = fi;
++ fa->fa_last_dflt = -1;
+ fa->fa_type = type;
+ fa->fa_scope = r->rtm_scope;
+ state = fa->fa_state;
+@@ -511,6 +534,7 @@
+ new_fa->fa_type = type;
+ new_fa->fa_scope = r->rtm_scope;
+ new_fa->fa_state = 0;
++ new_fa->fa_last_dflt = -1;
+
+ /*
+ * Insert new entry to the list.
+diff -Nur linux-2.6.17/net/ipv4/fib_lookup.h linux-2.6.17-owrt/net/ipv4/fib_lookup.h
+--- linux-2.6.17/net/ipv4/fib_lookup.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/fib_lookup.h 2006-06-18 16:53:21.000000000 +0200
+@@ -9,6 +9,7 @@
+ struct list_head fa_list;
+ struct rcu_head rcu;
+ struct fib_info *fa_info;
++ int fa_last_dflt;
+ u8 fa_tos;
+ u8 fa_type;
+ u8 fa_scope;
+@@ -40,6 +41,7 @@
+ u8 tos, u32 prio);
+ extern int fib_detect_death(struct fib_info *fi, int order,
+ struct fib_info **last_resort,
+- int *last_idx, int *dflt);
++ int *last_idx, int *dflt, int *last_nhsel,
++ const struct flowi *flp);
+
+ #endif /* _FIB_LOOKUP_H */
+diff -Nur linux-2.6.17/net/ipv4/fib_rules.c linux-2.6.17-owrt/net/ipv4/fib_rules.c
+--- linux-2.6.17/net/ipv4/fib_rules.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/fib_rules.c 2006-06-18 16:53:21.000000000 +0200
+@@ -296,6 +296,11 @@
+ }
+ }
+
++int fib_result_table(struct fib_result *res)
++{
++ return res->r->r_table;
++}
++
+ int fib_lookup(const struct flowi *flp, struct fib_result *res)
+ {
+ int err;
+@@ -361,7 +366,8 @@
+ void fib_select_default(const struct flowi *flp, struct fib_result *res)
+ {
+ if (res->r && res->r->r_action == RTN_UNICAST &&
+- FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) {
++ ((FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) ||
++ FIB_RES_NH(*res).nh_scope == RT_SCOPE_HOST)) {
+ struct fib_table *tb;
+ if ((tb = fib_get_table(res->r->r_table)) != NULL)
+ tb->tb_select_default(tb, flp, res);
+diff -Nur linux-2.6.17/net/ipv4/fib_semantics.c linux-2.6.17-owrt/net/ipv4/fib_semantics.c
+--- linux-2.6.17/net/ipv4/fib_semantics.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/fib_semantics.c 2006-06-18 16:53:21.000000000 +0200
+@@ -55,6 +55,7 @@
+ static struct hlist_head *fib_info_laddrhash;
+ static unsigned int fib_hash_size;
+ static unsigned int fib_info_cnt;
++rwlock_t fib_nhflags_lock = RW_LOCK_UNLOCKED;
+
+ #define DEVINDEX_HASHBITS 8
+ #define DEVINDEX_HASHSIZE (1U << DEVINDEX_HASHBITS)
+@@ -190,7 +191,7 @@
+ #ifdef CONFIG_NET_CLS_ROUTE
+ nh->nh_tclassid != onh->nh_tclassid ||
+ #endif
+- ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
++ ((nh->nh_flags^onh->nh_flags)&~RTNH_F_BADSTATE))
+ return -1;
+ onh++;
+ } endfor_nexthops(fi);
+@@ -227,7 +228,7 @@
+ nfi->fib_priority == fi->fib_priority &&
+ memcmp(nfi->fib_metrics, fi->fib_metrics,
+ sizeof(fi->fib_metrics)) == 0 &&
+- ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
++ ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_BADSTATE) == 0 &&
+ (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0))
+ return fi;
+ }
+@@ -319,26 +320,70 @@
+ }
+
+ int fib_detect_death(struct fib_info *fi, int order,
+- struct fib_info **last_resort, int *last_idx, int *dflt)
++ struct fib_info **last_resort, int *last_idx, int *dflt,
++ int *last_nhsel, const struct flowi *flp)
+ {
+ struct neighbour *n;
+- int state = NUD_NONE;
++ int nhsel;
++ int state;
++ struct fib_nh * nh;
++ u32 dst;
++ int flag, dead = 1;
++
++ /* change_nexthops(fi) { */
++ for (nhsel = 0, nh = fi->fib_nh; nhsel < fi->fib_nhs; nh++, nhsel++) {
++ if (flp->oif && flp->oif != nh->nh_oif)
++ continue;
++ if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw && nh->nh_gw &&
++ nh->nh_scope == RT_SCOPE_LINK)
++ continue;
++ if (nh->nh_flags & RTNH_F_DEAD)
++ continue;
+
+- n = neigh_lookup(&arp_tbl, &fi->fib_nh[0].nh_gw, fi->fib_dev);
+- if (n) {
+- state = n->nud_state;
+- neigh_release(n);
+- }
+- if (state==NUD_REACHABLE)
+- return 0;
+- if ((state&NUD_VALID) && order != *dflt)
+- return 0;
+- if ((state&NUD_VALID) ||
+- (*last_idx<0 && order > *dflt)) {
+- *last_resort = fi;
+- *last_idx = order;
++ flag = 0;
++ if (nh->nh_dev->flags & IFF_NOARP) {
++ dead = 0;
++ goto setfl;
++ }
++
++ dst = nh->nh_gw;
++ if (!nh->nh_gw || nh->nh_scope != RT_SCOPE_LINK)
++ dst = flp->fl4_dst;
++
++ state = NUD_NONE;
++ n = neigh_lookup(&arp_tbl, &dst, nh->nh_dev);
++ if (n) {
++ state = n->nud_state;
++ neigh_release(n);
++ }
++ if (state==NUD_REACHABLE ||
++ ((state&NUD_VALID) && order != *dflt)) {
++ dead = 0;
++ goto setfl;
++ }
++ if (!(state&NUD_VALID))
++ flag = 1;
++ if (!dead)
++ goto setfl;
++ if ((state&NUD_VALID) ||
++ (*last_idx<0 && order >= *dflt)) {
++ *last_resort = fi;
++ *last_idx = order;
++ *last_nhsel = nhsel;
++ }
++
++ setfl:
++
++ read_lock_bh(&fib_nhflags_lock);
++ if (flag)
++ nh->nh_flags |= RTNH_F_SUSPECT;
++ else
++ nh->nh_flags &= ~RTNH_F_SUSPECT;
++ read_unlock_bh(&fib_nhflags_lock);
+ }
+- return 1;
++ /* } endfor_nexthops(fi) */
++
++ return dead;
+ }
+
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+@@ -509,8 +554,11 @@
+ return -EINVAL;
+ if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL)
+ return -ENODEV;
+- if (!(dev->flags&IFF_UP))
+- return -ENETDOWN;
++ if (!(dev->flags&IFF_UP)) {
++ if (fi->fib_protocol != RTPROT_STATIC)
++ return -ENETDOWN;
++ nh->nh_flags |= RTNH_F_DEAD;
++ }
+ nh->nh_dev = dev;
+ dev_hold(dev);
+ nh->nh_scope = RT_SCOPE_LINK;
+@@ -525,24 +573,48 @@
+ /* It is not necessary, but requires a bit of thinking */
+ if (fl.fl4_scope < RT_SCOPE_LINK)
+ fl.fl4_scope = RT_SCOPE_LINK;
+- if ((err = fib_lookup(&fl, &res)) != 0)
+- return err;
++ err = fib_lookup(&fl, &res);
+ }
+- err = -EINVAL;
+- if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
+- goto out;
+- nh->nh_scope = res.scope;
+- nh->nh_oif = FIB_RES_OIF(res);
+- if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
+- goto out;
+- dev_hold(nh->nh_dev);
+- err = -ENETDOWN;
+- if (!(nh->nh_dev->flags & IFF_UP))
+- goto out;
+- err = 0;
++ if (err) {
++ struct in_device *in_dev;
++
++ if (err != -ENETUNREACH ||
++ fi->fib_protocol != RTPROT_STATIC)
++ return err;
++
++ in_dev = inetdev_by_index(nh->nh_oif);
++ if (in_dev == NULL ||
++ in_dev->dev->flags & IFF_UP) {
++ if (in_dev)
++ in_dev_put(in_dev);
++ return err;
++ }
++ nh->nh_flags |= RTNH_F_DEAD;
++ nh->nh_scope = RT_SCOPE_LINK;
++ nh->nh_dev = in_dev->dev;
++ dev_hold(nh->nh_dev);
++ in_dev_put(in_dev);
++ } else {
++ err = -EINVAL;
++ if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
++ goto out;
++ nh->nh_scope = res.scope;
++ nh->nh_oif = FIB_RES_OIF(res);
++ if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
++ goto out;
++ dev_hold(nh->nh_dev);
++ if (!(nh->nh_dev->flags & IFF_UP)) {
++ if (fi->fib_protocol != RTPROT_STATIC) {
++ err = -ENETDOWN;
++ goto out;
++ }
++ nh->nh_flags |= RTNH_F_DEAD;
++ }
++ err = 0;
+ out:
+- fib_res_put(&res);
+- return err;
++ fib_res_put(&res);
++ return err;
++ }
+ } else {
+ struct in_device *in_dev;
+
+@@ -553,8 +625,11 @@
+ if (in_dev == NULL)
+ return -ENODEV;
+ if (!(in_dev->dev->flags&IFF_UP)) {
+- in_dev_put(in_dev);
+- return -ENETDOWN;
++ if (fi->fib_protocol != RTPROT_STATIC) {
++ in_dev_put(in_dev);
++ return -ENETDOWN;
++ }
++ nh->nh_flags |= RTNH_F_DEAD;
+ }
+ nh->nh_dev = in_dev->dev;
+ dev_hold(nh->nh_dev);
+@@ -892,8 +967,12 @@
+ for_nexthops(fi) {
+ if (nh->nh_flags&RTNH_F_DEAD)
+ continue;
+- if (!flp->oif || flp->oif == nh->nh_oif)
+- break;
++ if (flp->oif && flp->oif != nh->nh_oif)
++ continue;
++ if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw &&
++ nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
++ continue;
++ break;
+ }
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (nhsel < fi->fib_nhs) {
+@@ -1199,18 +1278,29 @@
+ prev_fi = fi;
+ dead = 0;
+ change_nexthops(fi) {
+- if (nh->nh_flags&RTNH_F_DEAD)
+- dead++;
+- else if (nh->nh_dev == dev &&
+- nh->nh_scope != scope) {
+- nh->nh_flags |= RTNH_F_DEAD;
++ if (nh->nh_flags&RTNH_F_DEAD) {
++ if (fi->fib_protocol!=RTPROT_STATIC ||
++ nh->nh_dev == NULL ||
++ __in_dev_get_rtnl(nh->nh_dev) == NULL ||
++ nh->nh_dev->flags&IFF_UP)
++ dead++;
++ } else if (nh->nh_dev == dev &&
++ nh->nh_scope != scope) {
++ write_lock_bh(&fib_nhflags_lock);
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+- spin_lock_bh(&fib_multipath_lock);
++ spin_lock(&fib_multipath_lock);
++ nh->nh_flags |= RTNH_F_DEAD;
+ fi->fib_power -= nh->nh_power;
+ nh->nh_power = 0;
+- spin_unlock_bh(&fib_multipath_lock);
++ spin_unlock(&fib_multipath_lock);
++#else
++ nh->nh_flags |= RTNH_F_DEAD;
+ #endif
+- dead++;
++ write_unlock_bh(&fib_nhflags_lock);
++ if (fi->fib_protocol!=RTPROT_STATIC ||
++ force ||
++ __in_dev_get_rtnl(dev) == NULL)
++ dead++;
+ }
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+ if (force > 1 && nh->nh_dev == dev) {
+@@ -1229,11 +1319,8 @@
+ return ret;
+ }
+
+-#ifdef CONFIG_IP_ROUTE_MULTIPATH
+-
+ /*
+- Dead device goes up. We wake up dead nexthops.
+- It takes sense only on multipath routes.
++ Dead device goes up or new address is added. We wake up dead nexthops.
+ */
+
+ int fib_sync_up(struct net_device *dev)
+@@ -1243,8 +1330,10 @@
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct fib_nh *nh;
+- int ret;
++ struct fib_result res;
++ int ret, rep;
+
++repeat:
+ if (!(dev->flags&IFF_UP))
+ return 0;
+
+@@ -1252,6 +1341,7 @@
+ hash = fib_devindex_hashfn(dev->ifindex);
+ head = &fib_info_devhash[hash];
+ ret = 0;
++ rep = 0;
+
+ hlist_for_each_entry(nh, node, head, nh_hash) {
+ struct fib_info *fi = nh->nh_parent;
+@@ -1264,19 +1354,37 @@
+ prev_fi = fi;
+ alive = 0;
+ change_nexthops(fi) {
+- if (!(nh->nh_flags&RTNH_F_DEAD)) {
+- alive++;
++ if (!(nh->nh_flags&RTNH_F_DEAD))
+ continue;
+- }
+ if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
+ continue;
+ if (nh->nh_dev != dev || !__in_dev_get_rtnl(dev))
+ continue;
++ if (nh->nh_gw && fi->fib_protocol == RTPROT_STATIC) {
++ struct flowi fl = {
++ .nl_u = { .ip4_u =
++ { .daddr = nh->nh_gw,
++ .scope = nh->nh_scope } },
++ .oif = nh->nh_oif,
++ };
++ if (fib_lookup(&fl, &res) != 0)
++ continue;
++ if (res.type != RTN_UNICAST &&
++ res.type != RTN_LOCAL) {
++ fib_res_put(&res);
++ continue;
++ }
++ nh->nh_scope = res.scope;
++ fib_res_put(&res);
++ rep = 1;
++ }
+ alive++;
++#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ spin_lock_bh(&fib_multipath_lock);
+ nh->nh_power = 0;
+ nh->nh_flags &= ~RTNH_F_DEAD;
+ spin_unlock_bh(&fib_multipath_lock);
++#endif
+ } endfor_nexthops(fi)
+
+ if (alive > 0) {
+@@ -1284,10 +1392,14 @@
+ ret++;
+ }
+ }
++ if (rep)
++ goto repeat;
+
+ return ret;
+ }
+
++#ifdef CONFIG_IP_ROUTE_MULTIPATH
++
+ /*
+ The algorithm is suboptimal, but it provides really
+ fair weighted route distribution.
+@@ -1296,24 +1408,45 @@
+ void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
+ {
+ struct fib_info *fi = res->fi;
+- int w;
++ int w, alive;
+
+ spin_lock_bh(&fib_multipath_lock);
++ if (flp->oif) {
++ int sel = -1;
++ w = -1;
++ change_nexthops(fi) {
++ if (flp->oif != nh->nh_oif)
++ continue;
++ if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw &&
++ nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
++ continue;
++ if (!(nh->nh_flags&RTNH_F_BADSTATE)) {
++ if (nh->nh_power > w) {
++ w = nh->nh_power;
++ sel = nhsel;
++ }
++ }
++ } endfor_nexthops(fi);
++ if (sel >= 0) {
++ spin_unlock_bh(&fib_multipath_lock);
++ res->nh_sel = sel;
++ return;
++ }
++ goto last_resort;
++ }
++
++repeat:
+ if (fi->fib_power <= 0) {
+ int power = 0;
+ change_nexthops(fi) {
+- if (!(nh->nh_flags&RTNH_F_DEAD)) {
++ if (!(nh->nh_flags&RTNH_F_BADSTATE)) {
+ power += nh->nh_weight;
+ nh->nh_power = nh->nh_weight;
+ }
+ } endfor_nexthops(fi);
+ fi->fib_power = power;
+- if (power <= 0) {
+- spin_unlock_bh(&fib_multipath_lock);
+- /* Race condition: route has just become dead. */
+- res->nh_sel = 0;
+- return;
+- }
++ if (power <= 0)
++ goto last_resort;
+ }
+
+
+@@ -1323,20 +1456,40 @@
+
+ w = jiffies % fi->fib_power;
+
++ alive = 0;
+ change_nexthops(fi) {
+- if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
++ if (!(nh->nh_flags&RTNH_F_BADSTATE) && nh->nh_power) {
+ if ((w -= nh->nh_power) <= 0) {
+ nh->nh_power--;
+ fi->fib_power--;
+- res->nh_sel = nhsel;
+ spin_unlock_bh(&fib_multipath_lock);
++ res->nh_sel = nhsel;
+ return;
+ }
++ alive = 1;
++ }
++ } endfor_nexthops(fi);
++ if (alive) {
++ fi->fib_power = 0;
++ goto repeat;
++ }
++
++last_resort:
++
++ for_nexthops(fi) {
++ if (!(nh->nh_flags&RTNH_F_DEAD)) {
++ if (flp->oif && flp->oif != nh->nh_oif)
++ continue;
++ if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw &&
++ nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK)
++ continue;
++ spin_unlock_bh(&fib_multipath_lock);
++ res->nh_sel = nhsel;
++ return;
+ }
+ } endfor_nexthops(fi);
+
+ /* Race condition: route has just become dead. */
+- res->nh_sel = 0;
+ spin_unlock_bh(&fib_multipath_lock);
+ }
+ #endif
+diff -Nur linux-2.6.17/net/ipv4/netfilter/ip_nat_core.c linux-2.6.17-owrt/net/ipv4/netfilter/ip_nat_core.c
+--- linux-2.6.17/net/ipv4/netfilter/ip_nat_core.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/netfilter/ip_nat_core.c 2006-06-18 16:53:21.000000000 +0200
+@@ -589,6 +589,53 @@
+ EXPORT_SYMBOL_GPL(ip_nat_port_range_to_nfattr);
+ #endif
+
++unsigned int
++ip_nat_route_input(unsigned int hooknum,
++ struct sk_buff **pskb,
++ const struct net_device *in,
++ const struct net_device *out,
++ int (*okfn)(struct sk_buff *))
++{
++ struct sk_buff *skb = *pskb;
++ struct iphdr *iph;
++ struct ip_conntrack *conn;
++ enum ip_conntrack_info ctinfo;
++ enum ip_conntrack_dir dir;
++ unsigned long statusbit;
++ u32 saddr;
++
++ if (!(conn = ip_conntrack_get(skb, &ctinfo)))
++ return NF_ACCEPT;
++
++ if (!(conn->status & IPS_NAT_DONE_MASK))
++ return NF_ACCEPT;
++ dir = CTINFO2DIR(ctinfo);
++ statusbit = IPS_SRC_NAT;
++ if (dir == IP_CT_DIR_REPLY)
++ statusbit ^= IPS_NAT_MASK;
++ if (!(conn->status & statusbit))
++ return NF_ACCEPT;
++
++ if (skb->dst)
++ return NF_ACCEPT;
++
++ if (skb->len < sizeof(struct iphdr))
++ return NF_ACCEPT;
++
++ /* use daddr in other direction as masquerade address (lsrc) */
++ iph = skb->nh.iph;
++ saddr = conn->tuplehash[!dir].tuple.dst.ip;
++ if (saddr == iph->saddr)
++ return NF_ACCEPT;
++
++ if (ip_route_input_lookup(skb, iph->daddr, iph->saddr, iph->tos,
++ skb->dev, saddr))
++ return NF_DROP;
++
++ return NF_ACCEPT;
++}
++EXPORT_SYMBOL_GPL(ip_nat_route_input);
++
+ static int __init ip_nat_init(void)
+ {
+ size_t i;
+diff -Nur linux-2.6.17/net/ipv4/netfilter/ip_nat_standalone.c linux-2.6.17-owrt/net/ipv4/netfilter/ip_nat_standalone.c
+--- linux-2.6.17/net/ipv4/netfilter/ip_nat_standalone.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/netfilter/ip_nat_standalone.c 2006-06-18 17:12:03.000000000 +0200
+@@ -334,6 +334,14 @@
+ .hooknum = NF_IP_LOCAL_OUT,
+ .priority = NF_IP_PRI_NAT_DST,
+ },
++ /* Before routing, route before mangling */
++ {
++ .hook = ip_nat_route_input,
++ .owner = THIS_MODULE,
++ .pf = PF_INET,
++ .hooknum = NF_IP_PRE_ROUTING,
++ .priority = NF_IP_PRI_LAST-1,
++ },
+ /* After packet filtering, change source */
+ {
+ .hook = ip_nat_fn,
+diff -Nur linux-2.6.17/net/ipv4/netfilter/ipt_MASQUERADE.c linux-2.6.17-owrt/net/ipv4/netfilter/ipt_MASQUERADE.c
+--- linux-2.6.17/net/ipv4/netfilter/ipt_MASQUERADE.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/netfilter/ipt_MASQUERADE.c 2006-06-18 16:53:21.000000000 +0200
+@@ -88,13 +88,31 @@
+ return NF_ACCEPT;
+
+ mr = targinfo;
+- rt = (struct rtable *)(*pskb)->dst;
+- newsrc = inet_select_addr(out, rt->rt_gateway, RT_SCOPE_UNIVERSE);
+- if (!newsrc) {
+- printk("MASQUERADE: %s ate my IP address\n", out->name);
+- return NF_DROP;
++
++ {
++ struct flowi fl = { .nl_u = { .ip4_u =
++ { .daddr = (*pskb)->nh.iph->daddr,
++ .tos = (RT_TOS((*pskb)->nh.iph->tos) |
++ RTO_CONN),
++ .gw = ((struct rtable *) (*pskb)->dst)->rt_gateway,
++#ifdef CONFIG_IP_ROUTE_FWMARK
++ .fwmark = (*pskb)->nfmark
++#endif
++ } },
++ .oif = out->ifindex };
++ if (ip_route_output_key(&rt, &fl) != 0) {
++ /* Funky routing can do this. */
++ if (net_ratelimit())
++ printk("MASQUERADE:"
++ " No route: Rusty's brain broke!\n");
++ return NF_DROP;
++ }
+ }
+
++ newsrc = rt->rt_src;
++ DEBUGP("newsrc = %u.%u.%u.%u\n", NIPQUAD(newsrc));
++ ip_rt_put(rt);
++
+ write_lock_bh(&masq_lock);
+ ct->nat.masq_index = out->ifindex;
+ write_unlock_bh(&masq_lock);
+diff -Nur linux-2.6.17/net/ipv4/route.c linux-2.6.17-owrt/net/ipv4/route.c
+--- linux-2.6.17/net/ipv4/route.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/net/ipv4/route.c 2006-06-18 16:53:21.000000000 +0200
+@@ -1195,6 +1195,7 @@
+
+ /* Gateway is different ... */
+ rt->rt_gateway = new_gw;
++ if (rt->fl.fl4_gw) rt->fl.fl4_gw = new_gw;
+
+ /* Redirect received -> path was valid */
+ dst_confirm(&rth->u.dst);
+@@ -1626,6 +1627,7 @@
+ rth->fl.fl4_fwmark= skb->nfmark;
+ #endif
+ rth->fl.fl4_src = saddr;
++ rth->fl.fl4_lsrc = 0;
+ rth->rt_src = saddr;
+ #ifdef CONFIG_NET_CLS_ROUTE
+ rth->u.dst.tclassid = itag;
+@@ -1636,6 +1638,7 @@
+ dev_hold(rth->u.dst.dev);
+ rth->idev = in_dev_get(rth->u.dst.dev);
+ rth->fl.oif = 0;
++ rth->fl.fl4_gw = 0;
+ rth->rt_gateway = daddr;
+ rth->rt_spec_dst= spec_dst;
+ rth->rt_type = RTN_MULTICAST;
+@@ -1700,7 +1703,7 @@
+ struct fib_result* res,
+ struct in_device *in_dev,
+ u32 daddr, u32 saddr, u32 tos,
+- struct rtable **result)
++ u32 lsrc, struct rtable **result)
+ {
+
+ struct rtable *rth;
+@@ -1733,6 +1736,7 @@
+ flags |= RTCF_DIRECTSRC;
+
+ if (out_dev == in_dev && err && !(flags & (RTCF_NAT | RTCF_MASQ)) &&
++ !lsrc &&
+ (IN_DEV_SHARED_MEDIA(out_dev) ||
+ inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res))))
+ flags |= RTCF_DOREDIRECT;
+@@ -1772,6 +1776,7 @@
+ #endif
+ rth->fl.fl4_src = saddr;
+ rth->rt_src = saddr;
++ rth->fl.fl4_lsrc = lsrc;
+ rth->rt_gateway = daddr;
+ rth->rt_iif =
+ rth->fl.iif = in_dev->dev->ifindex;
+@@ -1779,6 +1784,7 @@
+ dev_hold(rth->u.dst.dev);
+ rth->idev = in_dev_get(rth->u.dst.dev);
+ rth->fl.oif = 0;
++ rth->fl.fl4_gw = 0;
+ rth->rt_spec_dst= spec_dst;
+
+ rth->u.dst.input = ip_forward;
+@@ -1800,19 +1806,20 @@
+ struct fib_result* res,
+ const struct flowi *fl,
+ struct in_device *in_dev,
+- u32 daddr, u32 saddr, u32 tos)
++ u32 daddr, u32 saddr, u32 tos, u32 lsrc)
+ {
+ struct rtable* rth = NULL;
+ int err;
+ unsigned hash;
+
++ fib_select_default(fl, res);
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+- if (res->fi && res->fi->fib_nhs > 1 && fl->oif == 0)
++ if (res->fi && res->fi->fib_nhs > 1)
+ fib_select_multipath(fl, res);
+ #endif
+
+ /* create a routing cache entry */
+- err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth);
++ err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, lsrc, &rth);
+ if (err)
+ return err;
+
+@@ -1825,7 +1832,7 @@
+ struct fib_result* res,
+ const struct flowi *fl,
+ struct in_device *in_dev,
+- u32 daddr, u32 saddr, u32 tos)
++ u32 daddr, u32 saddr, u32 tos, u32 lsrc)
+ {
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
+ struct rtable* rth = NULL, *rtres;
+@@ -1841,7 +1848,7 @@
+ /* distinguish between multipath and singlepath */
+ if (hopcount < 2)
+ return ip_mkroute_input_def(skb, res, fl, in_dev, daddr,
+- saddr, tos);
++ saddr, tos, 0);
+
+ /* add all alternatives to the routing cache */
+ for (hop = 0; hop < hopcount; hop++) {
+@@ -1853,7 +1860,7 @@
+
+ /* create a routing cache entry */
+ err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos,
+- &rth);
++ 0, &rth);
+ if (err)
+ return err;
+
+@@ -1873,7 +1880,7 @@
+ skb->dst = &rtres->u.dst;
+ return err;
+ #else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
+- return ip_mkroute_input_def(skb, res, fl, in_dev, daddr, saddr, tos);
++ return ip_mkroute_input_def(skb, res, fl, in_dev, daddr, saddr, tos, lsrc);
+ #endif /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
+ }
+
+@@ -1889,20 +1896,20 @@
+ */
+
+ static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
+- u8 tos, struct net_device *dev)
++ u8 tos, struct net_device *dev, u32 lsrc)
+ {
+ struct fib_result res;
+ struct in_device *in_dev = in_dev_get(dev);
+ struct flowi fl = { .nl_u = { .ip4_u =
+ { .daddr = daddr,
+- .saddr = saddr,
++ .saddr = lsrc? : saddr,
+ .tos = tos,
+ .scope = RT_SCOPE_UNIVERSE,
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+ .fwmark = skb->nfmark
+ #endif
+ } },
+- .iif = dev->ifindex };
++ .iif = lsrc? loopback_dev.ifindex : dev->ifindex };
+ unsigned flags = 0;
+ u32 itag = 0;
+ struct rtable * rth;
+@@ -1935,6 +1942,12 @@
+ if (BADCLASS(daddr) || ZERONET(daddr) || LOOPBACK(daddr))
+ goto martian_destination;
+
++ if (lsrc) {
++ if (MULTICAST(lsrc) || BADCLASS(lsrc) ||
++ ZERONET(lsrc) || LOOPBACK(lsrc))
++ goto e_inval;
++ }
++
+ /*
+ * Now we are ready to route packet.
+ */
+@@ -1944,6 +1957,10 @@
+ goto no_route;
+ }
+ free_res = 1;
++ if (lsrc && res.type != RTN_UNICAST && res.type != RTN_NAT)
++ goto e_inval;
++ fl.iif = dev->ifindex;
++ fl.fl4_src = saddr;
+
+ RT_CACHE_STAT_INC(in_slow_tot);
+
+@@ -1968,7 +1985,7 @@
+ if (res.type != RTN_UNICAST)
+ goto martian_destination;
+
+- err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);
++ err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos, lsrc);
+ if (err == -ENOBUFS)
+ goto e_nobufs;
+ if (err == -EINVAL)
+@@ -1983,6 +2000,8 @@
+ brd_input:
+ if (skb->protocol != htons(ETH_P_IP))
+ goto e_inval;
++ if (lsrc)
++ goto e_inval;
+
+ if (ZERONET(saddr))
+ spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
+@@ -2025,6 +2044,7 @@
+ rth->u.dst.dev = &loopback_dev;
+ dev_hold(rth->u.dst.dev);
+ rth->idev = in_dev_get(rth->u.dst.dev);
++ rth->fl.fl4_gw = 0;
+ rth->rt_gateway = daddr;
+ rth->rt_spec_dst= spec_dst;
+ rth->u.dst.input= ip_local_deliver;
+@@ -2074,8 +2094,9 @@
+ goto e_inval;
+ }
+
+-int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
+- u8 tos, struct net_device *dev)
++static inline int
++ip_route_input_cached(struct sk_buff *skb, u32 daddr, u32 saddr,
++ u8 tos, struct net_device *dev, u32 lsrc)
+ {
+ struct rtable * rth;
+ unsigned hash;
+@@ -2090,6 +2111,7 @@
+ if (rth->fl.fl4_dst == daddr &&
+ rth->fl.fl4_src == saddr &&
+ rth->fl.iif == iif &&
++ rth->fl.fl4_lsrc == lsrc &&
+ rth->fl.oif == 0 &&
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+ rth->fl.fl4_fwmark == skb->nfmark &&
+@@ -2138,7 +2160,19 @@
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+- return ip_route_input_slow(skb, daddr, saddr, tos, dev);
++ return ip_route_input_slow(skb, daddr, saddr, tos, dev, lsrc);
++}
++
++int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
++ u8 tos, struct net_device *dev)
++{
++ return ip_route_input_cached(skb, daddr, saddr, tos, dev, 0);
++}
++
++int ip_route_input_lookup(struct sk_buff *skb, u32 daddr, u32 saddr,
++ u8 tos, struct net_device *dev, u32 lsrc)
++{
++ return ip_route_input_cached(skb, daddr, saddr, tos, dev, lsrc);
+ }
+
+ static inline int __mkroute_output(struct rtable **result,
+@@ -2217,6 +2251,7 @@
+ rth->fl.fl4_tos = tos;
+ rth->fl.fl4_src = oldflp->fl4_src;
+ rth->fl.oif = oldflp->oif;
++ rth->fl.fl4_gw = oldflp->fl4_gw;
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+ rth->fl.fl4_fwmark= oldflp->fl4_fwmark;
+ #endif
+@@ -2361,6 +2396,7 @@
+ struct flowi fl = { .nl_u = { .ip4_u =
+ { .daddr = oldflp->fl4_dst,
+ .saddr = oldflp->fl4_src,
++ .gw = oldflp->fl4_gw,
+ .tos = tos & IPTOS_RT_MASK,
+ .scope = ((tos & RTO_ONLINK) ?
+ RT_SCOPE_LINK :
+@@ -2466,6 +2502,7 @@
+ dev_out = &loopback_dev;
+ dev_hold(dev_out);
+ fl.oif = loopback_dev.ifindex;
++ fl.fl4_gw = 0;
+ res.type = RTN_LOCAL;
+ flags |= RTCF_LOCAL;
+ goto make_route;
+@@ -2473,7 +2510,7 @@
+
+ if (fib_lookup(&fl, &res)) {
+ res.fi = NULL;
+- if (oldflp->oif) {
++ if (oldflp->oif && dev_out->flags & IFF_UP) {
+ /* Apparently, routing tables are wrong. Assume,
+ that the destination is on link.
+
+@@ -2513,6 +2550,7 @@
+ dev_out = &loopback_dev;
+ dev_hold(dev_out);
+ fl.oif = dev_out->ifindex;
++ fl.fl4_gw = 0;
+ if (res.fi)
+ fib_info_put(res.fi);
+ res.fi = NULL;
+@@ -2520,13 +2558,12 @@
+ goto make_route;
+ }
+
++ if (res.type == RTN_UNICAST)
++ fib_select_default(&fl, &res);
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH
+- if (res.fi->fib_nhs > 1 && fl.oif == 0)
++ if (res.fi->fib_nhs > 1)
+ fib_select_multipath(&fl, &res);
+- else
+ #endif
+- if (!res.prefixlen && res.type == RTN_UNICAST && !fl.oif)
+- fib_select_default(&fl, &res);
+
+ if (!fl.fl4_src)
+ fl.fl4_src = FIB_RES_PREFSRC(res);
+@@ -2563,6 +2600,7 @@
+ rth->fl.fl4_src == flp->fl4_src &&
+ rth->fl.iif == 0 &&
+ rth->fl.oif == flp->oif &&
++ rth->fl.fl4_gw == flp->fl4_gw &&
+ #ifdef CONFIG_IP_ROUTE_FWMARK
+ rth->fl.fl4_fwmark == flp->fl4_fwmark &&
+ #endif
+@@ -3199,3 +3237,4 @@
+ EXPORT_SYMBOL(__ip_select_ident);
+ EXPORT_SYMBOL(ip_route_input);
+ EXPORT_SYMBOL(ip_route_output_key);
++EXPORT_SYMBOL(ip_route_input_lookup);
diff --git a/target/linux/generic-2.6/patches/202-mips-freestanding.patch b/target/linux/generic-2.6/patches/202-mips-freestanding.patch
new file mode 100644
index 0000000..0441261
--- /dev/null
+++ b/target/linux/generic-2.6/patches/202-mips-freestanding.patch
@@ -0,0 +1,12 @@
+--- linux-2.6.17/arch/mips/Makefile 2006-06-19 15:12:09.000000000 -0700
++++ linux-2.6.17/arch/mips/Makefile 2006-06-19 15:11:59.000000000 -0700
+@@ -602,6 +602,9 @@
+ core-$(CONFIG_TOSHIBA_RBTX4938) += arch/mips/tx4938/common/
+ load-$(CONFIG_TOSHIBA_RBTX4938) += 0xffffffff80100000
+
++# temporary until string.h is fixed
++cflags-y += -ffreestanding
++
+ cflags-y += -Iinclude/asm-mips/mach-generic
+ drivers-$(CONFIG_PCI) += arch/mips/pci/
+
diff --git a/target/linux/generic-2.6/patches/203-fix_initrd_duplication.patch b/target/linux/generic-2.6/patches/203-fix_initrd_duplication.patch
new file mode 100644
index 0000000..4cef893
--- /dev/null
+++ b/target/linux/generic-2.6/patches/203-fix_initrd_duplication.patch
@@ -0,0 +1,13 @@
+diff -Nurb linux-2.6.17/usr/Makefile linux-2.6.17/usr/Makefile
+--- linux-2.6.17/usr/Makefile 2006-06-20 11:51:27.000000000 -0700
++++ linux-2.6.17/usr/Makefile 2006-06-20 11:51:34.000000000 -0700
+@@ -21,8 +21,7 @@
+ $(CONFIG_INITRAMFS_SOURCE),-d)
+ ramfs-args := \
+ $(if $(CONFIG_INITRAMFS_ROOT_UID), -u $(CONFIG_INITRAMFS_ROOT_UID)) \
+- $(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID)) \
+- $(ramfs-input)
++ $(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID))
+
+ # .initramfs_data.cpio.gz.d is used to identify all files included
+ # in initramfs and to detect if any files are added/removed.
diff --git a/target/linux/generic-2.6/patches/204-jffs2_eofdetect.patch b/target/linux/generic-2.6/patches/204-jffs2_eofdetect.patch
new file mode 100644
index 0000000..9f248c9
--- /dev/null
+++ b/target/linux/generic-2.6/patches/204-jffs2_eofdetect.patch
@@ -0,0 +1,58 @@
+diff -urN linux.old/fs/jffs2/build.c linux.dev/fs/jffs2/build.c
+--- linux.old/fs/jffs2/build.c 2006-06-18 03:49:35.000000000 +0200
++++ linux.dev/fs/jffs2/build.c 2006-06-23 21:46:48.000000000 +0200
+@@ -107,6 +107,17 @@
+ dbg_fsbuild("scanned flash completely\n");
+ jffs2_dbg_dump_block_lists_nolock(c);
+
++ if (c->flags & (1 << 7)) {
++ printk("%s(): unlocking the mtd device... ", __func__);
++ if (c->mtd->unlock)
++ c->mtd->unlock(c->mtd, 0, c->mtd->size);
++ printk("done.\n");
++
++ printk("%s(): erasing all blocks after the end marker... ", __func__);
++ jffs2_erase_pending_blocks(c, -1);
++ printk("done.\n");
++ }
++
+ dbg_fsbuild("pass 1 starting\n");
+ c->flags |= JFFS2_SB_FLAG_BUILDING;
+ /* Now scan the directory tree, increasing nlink according to every dirent found. */
+diff -urN linux.old/fs/jffs2/scan.c linux.dev/fs/jffs2/scan.c
+--- linux.old/fs/jffs2/scan.c 2006-06-23 21:39:38.000000000 +0200
++++ linux.dev/fs/jffs2/scan.c 2006-06-23 21:42:18.000000000 +0200
+@@ -119,9 +119,12 @@
+
+ /* reset summary info for next eraseblock scan */
+ jffs2_sum_reset_collected(s);
+-
+- ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
+- buf_size, s);
++
++ if (c->flags & (1 << 7))
++ ret = BLK_STATE_ALLFF;
++ else
++ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
++ buf_size, s);
+
+ if (ret < 0)
+ goto out;
+@@ -389,6 +392,17 @@
+ return err;
+ }
+
++ if ((buf[0] == 0xde) &&
++ (buf[1] == 0xad) &&
++ (buf[2] == 0xc0) &&
++ (buf[3] == 0xde)) {
++ /* end of filesystem. erase everything after this point */
++ printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset);
++ c->flags |= (1 << 7);
++
++ return BLK_STATE_ALLFF;
++ }
++
+ /* We temporarily use 'ofs' as a pointer into the buffer/jeb */
+ ofs = 0;
+
diff --git a/target/linux/generic-2.6/patches/205-block2mtd_fix.patch b/target/linux/generic-2.6/patches/205-block2mtd_fix.patch
new file mode 100644
index 0000000..9aaffc5
--- /dev/null
+++ b/target/linux/generic-2.6/patches/205-block2mtd_fix.patch
@@ -0,0 +1,235 @@
+diff -urN linux.old/drivers/mtd/devices/block2mtd.c linux.dev/drivers/mtd/devices/block2mtd.c
+--- linux.old/drivers/mtd/devices/block2mtd.c 2006-07-29 19:53:54.000000000 +0200
++++ linux.dev/drivers/mtd/devices/block2mtd.c 2006-07-29 19:47:03.000000000 +0200
+@@ -4,11 +4,10 @@
+ * block2mtd.c - create an mtd from a block device
+ *
+ * Copyright (C) 2001,2002 Simon Evans <spse@secret.org.uk>
+- * Copyright (C) 2004,2005 Jörn Engel <joern@wh.fh-wedel.de>
++ * Copyright (C) 2004-2006 Jörn Engel <joern@wh.fh-wedel.de>
+ *
+ * Licence: GPL
+ */
+-#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/fs.h>
+ #include <linux/blkdev.h>
+@@ -19,6 +18,7 @@ #include <linux/init.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/buffer_head.h>
+ #include <linux/mutex.h>
++#include <linux/mount.h>
+
+ #define VERSION "$Revision: 1.30 $"
+
+@@ -62,10 +61,8 @@
+ read_lock_irq(&mapping->tree_lock);
+ for (i = 0; i < PAGE_READAHEAD; i++) {
+ pagei = index + i;
+- if (pagei > end_index) {
+- INFO("Overrun end of disk in cache readahead\n");
++ if (pagei > end_index)
+ break;
+- }
+ page = radix_tree_lookup(&mapping->page_tree, pagei);
+ if (page && (!i))
+ break;
+@@ -237,6 +237,8 @@ static int _block2mtd_write(struct block
+ }
+ return 0;
+ }
++
++
+ static int block2mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+ {
+@@ -300,6 +302,19 @@ static struct block2mtd_dev *add_device(
+
+ /* Get a handle on the device */
+ bdev = open_bdev_excl(devname, O_RDWR, NULL);
++#ifndef MODULE
++ if (IS_ERR(bdev)) {
++
++ /* We might not have rootfs mounted at this point. Try
++ to resolve the device name by other means. */
++
++ dev_t dev = name_to_dev_t(devname);
++ if (dev != 0) {
++ bdev = open_by_devnum(dev, FMODE_WRITE | FMODE_READ);
++ }
++ }
++#endif
++
+ if (IS_ERR(bdev)) {
+ ERROR("error: cannot open device %s", devname);
+ goto devinit_err;
+@@ -331,7 +347,6 @@ static struct block2mtd_dev *add_device(
+ dev->mtd.writev = default_mtd_writev;
+ dev->mtd.sync = block2mtd_sync;
+ dev->mtd.read = block2mtd_read;
+- dev->mtd.readv = default_mtd_readv;
+ dev->mtd.priv = dev;
+ dev->mtd.owner = THIS_MODULE;
+
+@@ -351,6 +366,12 @@ devinit_err:
+ }
+
+
++/* This function works similar to reguler strtoul. In addition, it
++ * allows some suffixes for a more human-readable number format:
++ * ki, Ki, kiB, KiB - multiply result with 1024
++ * Mi, MiB - multiply result with 1024^2
++ * Gi, GiB - multiply result with 1024^3
++ */
+ static int ustrtoul(const char *cp, char **endp, unsigned int base)
+ {
+ unsigned long result = simple_strtoul(cp, endp, base);
+@@ -359,11 +380,16 @@ static int ustrtoul(const char *cp, char
+ result *= 1024;
+ case 'M':
+ result *= 1024;
++ case 'K':
+ case 'k':
+ result *= 1024;
+ /* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */
+- if ((*endp)[1] == 'i')
+- (*endp) += 2;
++ if ((*endp)[1] == 'i') {
++ if ((*endp)[2] == 'B')
++ (*endp) += 3;
++ else
++ (*endp) += 2;
++ }
+ }
+ return result;
+ }
+@@ -383,26 +409,6 @@ static int parse_num(size_t *num, const
+ }
+
+
+-static int parse_name(char **pname, const char *token, size_t limit)
+-{
+- size_t len;
+- char *name;
+-
+- len = strlen(token) + 1;
+- if (len > limit)
+- return -ENOSPC;
+-
+- name = kmalloc(len, GFP_KERNEL);
+- if (!name)
+- return -ENOMEM;
+-
+- strcpy(name, token);
+-
+- *pname = name;
+- return 0;
+-}
+-
+-
+ static inline void kill_final_newline(char *str)
+ {
+ char *newline = strrchr(str, '\n');
+@@ -416,9 +422,16 @@ #define parse_err(fmt, args...) do { \
+ return 0; \
+ } while (0)
+
+-static int block2mtd_setup(const char *val, struct kernel_param *kp)
++#ifndef MODULE
++static int block2mtd_init_called = 0;
++static __initdata char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
++#endif
++
++
++static int block2mtd_setup2(const char *val)
+ {
+- char buf[80+12], *str=buf; /* 80 for device, 12 for erase size */
++ char buf[80 + 12]; /* 80 for device, 12 for erase size */
++ char *str = buf;
+ char *token[2];
+ char *name;
+ size_t erase_size = PAGE_SIZE;
+@@ -430,7 +443,7 @@ static int block2mtd_setup(const char *v
+ strcpy(str, val);
+ kill_final_newline(str);
+
+- for (i=0; i<2; i++)
++ for (i = 0; i < 2; i++)
+ token[i] = strsep(&str, ",");
+
+ if (str)
+@@ -439,18 +452,16 @@ static int block2mtd_setup(const char *v
+ if (!token[0])
+ parse_err("no argument");
+
+- ret = parse_name(&name, token[0], 80);
+- if (ret == -ENOMEM)
+- parse_err("out of memory");
+- if (ret == -ENOSPC)
+- parse_err("name too long");
+- if (ret)
+- return 0;
++ name = token[0];
++ if (strlen(name) + 1 > 80)
++ parse_err("device name too long");
+
+ if (token[1]) {
+ ret = parse_num(&erase_size, token[1]);
+- if (ret)
++ if (ret) {
++ kfree(name);
+ parse_err("illegal erase size");
++ }
+ }
+
+ add_device(name, erase_size);
+@@ -459,13 +470,48 @@ static int block2mtd_setup(const char *v
+ }
+
+
++static int block2mtd_setup(const char *val, struct kernel_param *kp)
++{
++#ifdef MODULE
++ return block2mtd_setup2(val);
++#else
++ /* If more parameters are later passed in via
++ /sys/module/block2mtd/parameters/block2mtd
++ and block2mtd_init() has already been called,
++ we can parse the argument now. */
++
++ if (block2mtd_init_called)
++ return block2mtd_setup2(val);
++
++ /* During early boot stage, we only save the parameters
++ here. We must parse them later: if the param passed
++ from kernel boot command line, block2mtd_setup() is
++ called so early that it is not possible to resolve
++ the device (even kmalloc() fails). Deter that work to
++ block2mtd_setup2(). */
++
++ strlcpy(block2mtd_paramline, val, sizeof(block2mtd_paramline));
++
++ return 0;
++#endif
++}
++
++
+ module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
+ MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>]\"");
+
+ static int __init block2mtd_init(void)
+ {
++ int ret = 0;
+ INFO("version " VERSION);
+- return 0;
++
++#ifndef MODULE
++ if (strlen(block2mtd_paramline))
++ ret = block2mtd_setup2(block2mtd_paramline);
++ block2mtd_init_called = 1;
++#endif
++
++ return ret;
+ }
+
+
diff --git a/target/linux/generic-2.6/patches/206-pppoe_mtu_fix.patch b/target/linux/generic-2.6/patches/206-pppoe_mtu_fix.patch
new file mode 100644
index 0000000..1ad8220
--- /dev/null
+++ b/target/linux/generic-2.6/patches/206-pppoe_mtu_fix.patch
@@ -0,0 +1,12 @@
+--- linux-2.6.17/drivers/net/pppoe.c.old 2006-10-10 13:47:56.000000000 +0200
++++ linux-2.6.17/drivers/net/pppoe.c 2006-10-10 13:52:02.000000000 +0200
+@@ -600,6 +600,9 @@
+ po->chan.hdrlen = (sizeof(struct pppoe_hdr) +
+ dev->hard_header_len);
+
++ if (po->chan.mtu > dev->mtu - sizeof(struct pppoe_hdr))
++ po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr);
++
+ po->chan.private = sk;
+ po->chan.ops = &pppoe_chan_ops;
+
diff --git a/target/linux/magicbox-2.6/Makefile b/target/linux/magicbox-2.6/Makefile
new file mode 100644
index 0000000..7ffd11c
--- /dev/null
+++ b/target/linux/magicbox-2.6/Makefile
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+LINUX_VERSION:=2.6.17
+LINUX_RELEASE:=1
+LINUX_KERNEL_MD5SUM:=37ddefe96625502161f075b9d907f21e
+
+include ./config
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/kernel-build.mk
+
+$(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked
+ [ -d ../generic-$(KERNEL)/patches ] && $(PATCH) $(LINUX_DIR) ../generic-$(KERNEL)/patches $(MAKE_TRACE)
+ [ -d ./patches ] && $(PATCH) $(LINUX_DIR) ./patches $(MAKE_TRACE)
+ @$(CP) config $(LINUX_DIR)/.config
+ touch $@
+
diff --git a/target/linux/magicbox-2.6/config b/target/linux/magicbox-2.6/config
new file mode 100644
index 0000000..1f7f591
--- /dev/null
+++ b/target/linux/magicbox-2.6/config
@@ -0,0 +1,1161 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17
+# Wed Aug 30 06:45:18 2006
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+CONFIG_40x=y
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+# CONFIG_E500 is not set
+CONFIG_MATH_EMULATION=y
+# CONFIG_KEXEC is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_4xx=y
+CONFIG_WANT_EARLY_SERIAL=y
+
+#
+# IBM 4xx options
+#
+# CONFIG_BUBINGA is not set
+# CONFIG_CPCI405 is not set
+# CONFIG_EP405 is not set
+# CONFIG_REDWOOD_5 is not set
+# CONFIG_REDWOOD_6 is not set
+# CONFIG_SYCAMORE is not set
+# CONFIG_WALNUT is not set
+CONFIG_MAGICBOX=y
+# CONFIG_XILINX_ML300 is not set
+# CONFIG_XILINX_ML403 is not set
+CONFIG_IBM_OCP=y
+CONFIG_BIOS_FIXUP=y
+CONFIG_405EP=y
+CONFIG_PPC4xx_DMA=y
+CONFIG_PPC4xx_EDMA=y
+CONFIG_PPC_GEN550=y
+CONFIG_UART0_TTYS0=y
+# CONFIG_UART0_TTYS1 is not set
+CONFIG_NOT_COHERENT_CACHE=y
+
+#
+# Platform options
+#
+# CONFIG_PC_KEYBOARD is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200"
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IPSEC_NAT_TRAVERSAL is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_BRIDGE_NETFILTER is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_CT_ACCT=y
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=y
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+CONFIG_IP_NF_SIP=m
+CONFIG_IP_NF_QUEUE=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_IPP2P=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_TIME=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_IMQ=m
+# CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_ROUTE=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=y
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_SET=m
+CONFIG_IP_NF_SET_MAX=256
+CONFIG_IP_NF_SET_HASHSIZE=1024
+CONFIG_IP_NF_SET_IPMAP=m
+CONFIG_IP_NF_SET_MACIPMAP=m
+CONFIG_IP_NF_SET_PORTMAP=m
+CONFIG_IP_NF_SET_IPHASH=m
+CONFIG_IP_NF_SET_NETHASH=m
+CONFIG_IP_NF_SET_IPTREE=m
+CONFIG_IP_NF_MATCH_SET=m
+CONFIG_IP_NF_TARGET_SET=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_ESFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_PEDIT=m
+# CONFIG_NET_ACT_SIMP is not set
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+CONFIG_IEEE80211_SOFTMAC=m
+# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=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
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_GEOMETRY 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_OTP is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_MAGICMAP=y
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_IFB is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_IMQ=m
+# CONFIG_IMQ_BEHAVIOR_AA is not set
+# CONFIG_IMQ_BEHAVIOR_AB is not set
+CONFIG_IMQ_BEHAVIOR_BA=y
+# CONFIG_IMQ_BEHAVIOR_BB is not set
+CONFIG_IMQ_NUM_DEVS=2
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_IBM_EMAC=y
+CONFIG_IBM_EMAC_RXB=64
+CONFIG_IBM_EMAC_TXB=8
+CONFIG_IBM_EMAC_POLL_WEIGHT=32
+CONFIG_IBM_EMAC_RX_COPY_THRESHOLD=256
+CONFIG_IBM_EMAC_RX_SKB_HEADROOM=0
+# CONFIG_IBM_EMAC_PHY_RX_CLK_FIX is not set
+# CONFIG_IBM_EMAC_DEBUG is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+CONFIG_NET_WIRELESS_RTNETLINK=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_IPW2100=m
+CONFIG_IPW2100_MONITOR=y
+# CONFIG_IPW2100_DEBUG is not set
+CONFIG_IPW2200=m
+CONFIG_IPW2200_MONITOR=y
+# CONFIG_IPW_QOS is not set
+# CONFIG_IPW2200_DEBUG is not set
+# CONFIG_AIRO is not set
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_PRISM54=m
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+# CONFIG_HOSTAP_PLX is not set
+CONFIG_HOSTAP_PCI=m
+# CONFIG_BCM43XX is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_BOOKE_WDT is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=m
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY 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 is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_SQUASHFS_VMALLOC is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# IBM 40x options
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_FS is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+CONFIG_PPC_OCP=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/target/linux/magicbox-2.6/patches/001-magicbox_support.patch b/target/linux/magicbox-2.6/patches/001-magicbox_support.patch
new file mode 100644
index 0000000..b7806da
--- /dev/null
+++ b/target/linux/magicbox-2.6/patches/001-magicbox_support.patch
@@ -0,0 +1,372 @@
+diff -Nur linux-2.6.17/arch/ppc/platforms/4xx/Kconfig linux-2.6.17-owrt/arch/ppc/platforms/4xx/Kconfig
+--- linux-2.6.17/arch/ppc/platforms/4xx/Kconfig 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/ppc/platforms/4xx/Kconfig 2006-08-25 23:33:05.000000000 +0200
+@@ -52,6 +52,12 @@
+ help
+ This option enables support for the IBM PPC405GP evaluation board.
+
++config MAGICBOX
++ bool "MagicBox"
++ select WANT_EARLY_SERIAL
++ help
++ This option enables support for the IBM PPC405EP evaluation board.
++
+ config XILINX_ML300
+ bool "Xilinx-ML300"
+ help
+@@ -173,7 +179,7 @@
+
+ config IBM_OCP
+ bool
+- depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || YUCCA || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
++ depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || YUCCA || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT || MAGICBOX
+ default y
+
+ config IBM_EMAC4
+@@ -183,7 +189,7 @@
+
+ config BIOS_FIXUP
+ bool
+- depends on BUBINGA || EP405 || SYCAMORE || WALNUT
++ depends on BUBINGA || EP405 || SYCAMORE || WALNUT || MAGICBOX
+ default y
+
+ # OAK doesn't exist but wanted to keep this around for any future 403GCX boards
+@@ -194,7 +200,7 @@
+
+ config 405EP
+ bool
+- depends on BUBINGA
++ depends on BUBINGA || MAGICBOX
+ default y
+
+ config 405GP
+diff -Nur linux-2.6.17/arch/ppc/platforms/4xx/magicbox.c linux-2.6.17-owrt/arch/ppc/platforms/4xx/magicbox.c
+--- linux-2.6.17/arch/ppc/platforms/4xx/magicbox.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/ppc/platforms/4xx/magicbox.c 2006-08-25 23:33:05.000000000 +0200
+@@ -0,0 +1,249 @@
++/*
++ * Support for IBM PPC 405EP-based MagicBox board
++ * Copyright (C) 2006 Karol Lewandowski
++ *
++ * Heavily based on bubinga.c
++ *
++ * Author: SAW (IBM), derived from walnut.c.
++ * Maintained by MontaVista Software <source@mvista.com>
++ *
++ * 2003 (c) MontaVista Softare Inc. This file is licensed under the
++ * terms of the GNU General Public License version 2. This program is
++ * licensed "as is" without any warranty of any kind, whether express
++ * or implied.
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/smp.h>
++#include <linux/threads.h>
++#include <linux/param.h>
++#include <linux/string.h>
++#include <linux/blkdev.h>
++#include <linux/pci.h>
++#include <linux/tty.h>
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++
++#include <asm/system.h>
++#include <asm/pci-bridge.h>
++#include <asm/processor.h>
++#include <asm/machdep.h>
++#include <asm/page.h>
++#include <asm/time.h>
++#include <asm/io.h>
++#include <asm/kgdb.h>
++#include <asm/ocp.h>
++#include <asm/ibm_ocp_pci.h>
++
++#include <platforms/4xx/ibm405ep.h>
++
++#undef DEBUG
++
++#ifdef DEBUG
++#define DBG(x...) printk(x)
++#else
++#define DBG(x...)
++#endif
++
++extern bd_t __res;
++
++/* Some IRQs unique to board
++ * Used by the generic 405 PCI setup functions in ppc4xx_pci.c
++ */
++int __init
++ppc405_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
++{
++ static char pci_irq_table[][4] =
++ /*
++ * PCI IDSEL/INTPIN->INTLINE
++ * A B C D
++ */
++ {
++ {28, 28, 28, 28}, /* IDSEL 1 - PCI slot 1 */
++ {29, 29, 29, 29}, /* IDSEL 2 - PCI slot 2 */
++ {30, 30, 30, 30}, /* IDSEL 3 - PCI slot 3 */
++ {31, 31, 31, 31}, /* IDSEL 4 - PCI slot 4 */
++ };
++
++ const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
++ return PCI_IRQ_TABLE_LOOKUP;
++};
++
++
++/* The serial clock for the chip is an internal clock determined by
++ * different clock speeds/dividers.
++ * Calculate the proper input baud rate and setup the serial driver.
++ */
++static void __init
++magicbox_early_serial_map(void)
++{
++ u32 uart_div;
++ int uart_clock;
++ struct uart_port port;
++
++ /* Calculate the serial clock input frequency
++ *
++ * The base baud is the PLL OUTA (provided in the board info
++ * structure) divided by the external UART Divisor, divided
++ * by 16.
++ */
++ uart_div = (mfdcr(DCRN_CPC0_UCR_BASE) & DCRN_CPC0_UCR_U0DIV);
++ uart_clock = __res.bi_procfreq / uart_div;
++
++ /* Setup serial port access */
++ memset(&port, 0, sizeof(port));
++ port.membase = (void*)ACTING_UART0_IO_BASE;
++ port.irq = ACTING_UART0_INT;
++ port.uartclk = uart_clock;
++ port.regshift = 0;
++ port.iotype = SERIAL_IO_MEM;
++ port.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
++ port.line = 0;
++
++ if (early_serial_setup(&port) != 0) {
++ printk("Early serial init of port 0 failed\n");
++ }
++
++ port.membase = (void*)ACTING_UART1_IO_BASE;
++ port.irq = ACTING_UART1_INT;
++ port.line = 1;
++
++ if (early_serial_setup(&port) != 0) {
++ printk("Early serial init of port 1 failed\n");
++ }
++}
++
++void __init
++bios_fixup(struct pci_controller *hose, struct pcil0_regs *pcip)
++{
++ unsigned int bar_response, bar;
++ /*
++ * Expected PCI mapping:
++ *
++ * PLB addr PCI memory addr
++ * --------------------- ---------------------
++ * 0000'0000 - 7fff'ffff <--- 0000'0000 - 7fff'ffff
++ * 8000'0000 - Bfff'ffff ---> 8000'0000 - Bfff'ffff
++ *
++ * PLB addr PCI io addr
++ * --------------------- ---------------------
++ * e800'0000 - e800'ffff ---> 0000'0000 - 0001'0000
++ *
++ * The following code is simplified by assuming that the bootrom
++ * has been well behaved in following this mapping.
++ */
++
++#ifdef DEBUG
++ int i;
++
++ printk("ioremap PCLIO_BASE = 0x%x\n", pcip);
++ printk("PCI bridge regs before fixup \n");
++ for (i = 0; i <= 3; i++) {
++ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
++ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
++ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
++ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
++ }
++ printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
++ printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
++ printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
++ printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
++
++#endif
++
++ /* added for IBM boot rom version 1.15 bios bar changes -AK */
++
++ /* Disable region first */
++ out_le32((void *) &(pcip->pmm[0].ma), 0x00000000);
++ /* PLB starting addr, PCI: 0x80000000 */
++ out_le32((void *) &(pcip->pmm[0].la), 0x80000000);
++ /* PCI start addr, 0x80000000 */
++ out_le32((void *) &(pcip->pmm[0].pcila), PPC405_PCI_MEM_BASE);
++ /* 512MB range of PLB to PCI */
++ out_le32((void *) &(pcip->pmm[0].pciha), 0x00000000);
++ /* Enable no pre-fetch, enable region */
++ out_le32((void *) &(pcip->pmm[0].ma), ((0xffffffff -
++ (PPC405_PCI_UPPER_MEM -
++ PPC405_PCI_MEM_BASE)) | 0x01));
++
++ /* Disable region one */
++ out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
++ out_le32((void *) &(pcip->pmm[1].la), 0x00000000);
++ out_le32((void *) &(pcip->pmm[1].pcila), 0x00000000);
++ out_le32((void *) &(pcip->pmm[1].pciha), 0x00000000);
++ out_le32((void *) &(pcip->pmm[1].ma), 0x00000000);
++ out_le32((void *) &(pcip->ptm1ms), 0x00000001);
++
++ /* Disable region two */
++ out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
++ out_le32((void *) &(pcip->pmm[2].la), 0x00000000);
++ out_le32((void *) &(pcip->pmm[2].pcila), 0x00000000);
++ out_le32((void *) &(pcip->pmm[2].pciha), 0x00000000);
++ out_le32((void *) &(pcip->pmm[2].ma), 0x00000000);
++ out_le32((void *) &(pcip->ptm2ms), 0x00000000);
++ out_le32((void *) &(pcip->ptm2la), 0x00000000);
++
++ /* Zero config bars */
++ for (bar = PCI_BASE_ADDRESS_1; bar <= PCI_BASE_ADDRESS_2; bar += 4) {
++ early_write_config_dword(hose, hose->first_busno,
++ PCI_FUNC(hose->first_busno), bar,
++ 0x00000000);
++ early_read_config_dword(hose, hose->first_busno,
++ PCI_FUNC(hose->first_busno), bar,
++ &bar_response);
++ DBG("BUS %d, device %d, Function %d bar 0x%8.8x is 0x%8.8x\n",
++ hose->first_busno, PCI_SLOT(hose->first_busno),
++ PCI_FUNC(hose->first_busno), bar, bar_response);
++ }
++ /* end work arround */
++
++#ifdef DEBUG
++ printk("PCI bridge regs after fixup \n");
++ for (i = 0; i <= 3; i++) {
++ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].ma)));
++ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].la)));
++ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pcila)));
++ printk(" pmm%dma\t0x%x\n", i, in_le32(&(pcip->pmm[i].pciha)));
++ }
++ printk(" ptm1ms\t0x%x\n", in_le32(&(pcip->ptm1ms)));
++ printk(" ptm1la\t0x%x\n", in_le32(&(pcip->ptm1la)));
++ printk(" ptm2ms\t0x%x\n", in_le32(&(pcip->ptm2ms)));
++ printk(" ptm2la\t0x%x\n", in_le32(&(pcip->ptm2la)));
++
++#endif /* DEBUG */
++}
++
++void __init
++magicbox_setup_arch(void)
++{
++ ppc4xx_setup_arch();
++
++ ibm_ocp_set_emac(0, 1);
++
++ magicbox_early_serial_map();
++
++ /* Identify the system */
++ printk("MagicBox port (C) 2005 Karol Lewandowski <kl@jasmine.eu.org>\n");
++}
++
++void __init
++magicbox_map_io(void)
++{
++ ppc4xx_map_io();
++}
++
++void __init
++platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
++ unsigned long r6, unsigned long r7)
++{
++ ppc4xx_init(r3, r4, r5, r6, r7);
++
++ ppc_md.setup_arch = magicbox_setup_arch;
++ ppc_md.setup_io_mappings = magicbox_map_io;
++
++#ifdef CONFIG_KGDB
++ ppc_md.early_serial_map = bubinga_early_serial_map;
++#endif
++
++}
+diff -Nur linux-2.6.17/arch/ppc/platforms/4xx/magicbox.h linux-2.6.17-owrt/arch/ppc/platforms/4xx/magicbox.h
+--- linux-2.6.17/arch/ppc/platforms/4xx/magicbox.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/ppc/platforms/4xx/magicbox.h 2006-08-25 23:33:05.000000000 +0200
+@@ -0,0 +1,47 @@
++/*
++ * Support for IBM PPC 405EP-based MagicBox board
++ *
++ * Heavily based on bubinga.h
++ *
++ *
++ * Author: SAW (IBM), derived from walnut.h.
++ * Maintained by MontaVista Software <source@mvista.com>
++ *
++ * 2003 (c) MontaVista Softare Inc. This file is licensed under the
++ * terms of the GNU General Public License version 2. This program is
++ * licensed "as is" without any warranty of any kind, whether express
++ * or implied.
++ */
++
++#ifdef __KERNEL__
++#ifndef __MAGICBOX_H__
++#define __MAGICBOX_H__
++
++#include <linux/config.h>
++#include <platforms/4xx/ibm405ep.h>
++#include <asm/ppcboot.h>
++
++/* Memory map for the "MagicBox" 405EP evaluation board -- generic 4xx. */
++
++/* The UART clock is based off an internal clock -
++ * define BASE_BAUD based on the internal clock and divider(s).
++ * Since BASE_BAUD must be a constant, we will initialize it
++ * using clock/divider values which OpenBIOS initializes
++ * for typical configurations at various CPU speeds.
++ * The base baud is calculated as (FWDA / EXT UART DIV / 16)
++ */
++#define BASE_BAUD 0
++
++/* Flash */
++#define PPC40x_FPGA_BASE 0xF0300000
++#define PPC40x_FPGA_REG_OFFS 1 /* offset to flash map reg */
++#define PPC40x_FLASH_ONBD_N(x) (x & 0x02)
++#define PPC40x_FLASH_SRAM_SEL(x) (x & 0x01)
++#define PPC40x_FLASH_LOW 0xFFF00000
++#define PPC40x_FLASH_HIGH 0xFFF80000
++#define PPC40x_FLASH_SIZE 0x80000
++
++#define PPC4xx_MACHINE_NAME "MagicBox"
++
++#endif /* __MAGICBOX_H__ */
++#endif /* __KERNEL__ */
+diff -Nur linux-2.6.17/arch/ppc/platforms/4xx/Makefile linux-2.6.17-owrt/arch/ppc/platforms/4xx/Makefile
+--- linux-2.6.17/arch/ppc/platforms/4xx/Makefile 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/ppc/platforms/4xx/Makefile 2006-08-25 23:33:05.000000000 +0200
+@@ -13,6 +13,7 @@
+ obj-$(CONFIG_REDWOOD_6) += redwood6.o
+ obj-$(CONFIG_SYCAMORE) += sycamore.o
+ obj-$(CONFIG_WALNUT) += walnut.o
++obj-$(CONFIG_MAGICBOX) += magicbox.o
+ obj-$(CONFIG_XILINX_ML300) += xilinx_ml300.o
+ obj-$(CONFIG_XILINX_ML403) += xilinx_ml403.o
+
+diff -Nur linux-2.6.17/include/asm-ppc/ibm4xx.h linux-2.6.17-owrt/include/asm-ppc/ibm4xx.h
+--- linux-2.6.17/include/asm-ppc/ibm4xx.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/asm-ppc/ibm4xx.h 2006-08-25 23:33:05.000000000 +0200
+@@ -19,6 +19,10 @@
+
+ #ifdef CONFIG_40x
+
++#if defined(CONFIG_MAGICBOX)
++#include <platforms/4xx/magicbox.h>
++#endif
++
+ #if defined(CONFIG_BUBINGA)
+ #include <platforms/4xx/bubinga.h>
+ #endif
diff --git a/target/linux/magicbox-2.6/patches/002-flash_map.patch b/target/linux/magicbox-2.6/patches/002-flash_map.patch
new file mode 100644
index 0000000..e5f803a
--- /dev/null
+++ b/target/linux/magicbox-2.6/patches/002-flash_map.patch
@@ -0,0 +1,147 @@
+diff -urN linux.old/drivers/mtd/maps/Kconfig linux.dev/drivers/mtd/maps/Kconfig
+--- linux.old/drivers/mtd/maps/Kconfig 2006-08-30 06:30:59.000000000 +0200
++++ linux.dev/drivers/mtd/maps/Kconfig 2006-08-30 06:11:51.000000000 +0200
+@@ -323,6 +323,15 @@
+ Walnut board. If you have one of these boards and would like to
+ use the flash chips on it, say 'Y'.
+
++config MTD_MAGICMAP
++ tristate "Flash device mapped on IBM 405EP MagicBox"
++ depends on MTD_CFI && MTD_PARTITIONS && 40x && MAGICBOX
++ help
++ This enables access routines for the flash chips on the IBM 405EP
++ MagicBox board. If you have one of these boards and would like to
++ use the flash chips on it, say 'Y'.
++
++
+ config MTD_EBONY
+ tristate "Flash devices mapped on IBM 440GP Ebony"
+ depends on MTD_JEDECPROBE && EBONY
+diff -urN linux.old/drivers/mtd/maps/magicmap.c linux.dev/drivers/mtd/maps/magicmap.c
+--- linux.old/drivers/mtd/maps/magicmap.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/mtd/maps/magicmap.c 2006-08-30 06:52:34.000000000 +0200
+@@ -0,0 +1,113 @@
++/*
++ * magicmap.c: Copyleft 2005 Karol Lewandowski
++ *
++ * Mapping for MagicBox flash.
++ * Based on walnut.c.
++ *
++ * Heikki Lindholm <holindho@infradead.org>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <linux/config.h>
++#include <asm/io.h>
++
++static struct mtd_info *flash;
++
++static struct map_info magic_map = {
++ .name = "Magically mapped flash",
++ .phys = 0xffc00000,
++ .size = 0x400000,
++ .bankwidth = 2,
++};
++
++static struct mtd_partition magic_partitions[] = {
++ {
++ .name = "linux",
++ .offset = 0x0,
++ .size = 0x3c0000,
++ },
++ {
++ .name = "rootfs",
++ .offset = 0x100000,
++ .size = 0x2c0000,
++ },
++ {
++ .name = "bootloader",
++ .offset = 0x3c0000,
++ .size = 0x040000,
++ .mask_flags = MTD_WRITEABLE,
++ },
++};
++
++int __init init_magic(void)
++{
++ u32 size, len;
++
++ magic_map.virt =
++ (void __iomem *)ioremap(magic_map.phys, magic_map.size);
++
++ if (!magic_map.virt) {
++ printk("Failed to ioremap flash.\n");
++ return -EIO;
++ }
++
++ simple_map_init(&magic_map);
++
++ flash = do_map_probe("cfi_probe", &magic_map);
++ if (flash) {
++ flash->owner = THIS_MODULE;
++ if (MTD_READ(flash, 12, sizeof(u32), &len, (char *) &size) ||
++ len != 4)
++ return -ENXIO;
++ size += 0x40; /* header size of the uImage */
++ if (size < 0x400000) {
++ /* skip to next erase block */
++ if (size & (flash->erasesize - 1)) {
++ size |= (flash->erasesize - 1);
++ size += 1;
++ }
++ magic_partitions[1].offset = size;
++ magic_partitions[1].size = magic_partitions[2].offset - size;
++ }
++
++ add_mtd_partitions(flash, magic_partitions,
++ ARRAY_SIZE(magic_partitions));
++ } else {
++ printk("map probe failed for flash\n");
++ return -ENXIO;
++ }
++
++ return 0;
++}
++
++static void __exit cleanup_magic(void)
++{
++ if (flash) {
++ del_mtd_partitions(flash);
++ map_destroy(flash);
++ }
++
++ if (magic_map.virt) {
++ iounmap((void *)magic_map.virt);
++ magic_map.virt = NULL;
++ }
++}
++
++module_init(init_magic);
++module_exit(cleanup_magic);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Karol Lewandowski");
++MODULE_DESCRIPTION("MTD map and partitions for IBM 405EP MagicBox boards");
+diff -urN linux.old/drivers/mtd/maps/Makefile linux.dev/drivers/mtd/maps/Makefile
+--- linux.old/drivers/mtd/maps/Makefile 2006-08-30 06:30:59.000000000 +0200
++++ linux.dev/drivers/mtd/maps/Makefile 2006-08-30 06:11:51.000000000 +0200
+@@ -58,6 +58,7 @@
+ obj-$(CONFIG_MTD_BEECH) += beech-mtd.o
+ obj-$(CONFIG_MTD_ARCTIC) += arctic-mtd.o
+ obj-$(CONFIG_MTD_WALNUT) += walnut.o
++obj-$(CONFIG_MTD_MAGICMAP) += magicmap.o
+ obj-$(CONFIG_MTD_H720X) += h720x-flash.o
+ obj-$(CONFIG_MTD_SBC8240) += sbc8240.o
+ obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o
diff --git a/target/linux/package/Config.in b/target/linux/package/Config.in
new file mode 100644
index 0000000..4d97a57
--- /dev/null
+++ b/target/linux/package/Config.in
@@ -0,0 +1 @@
+source "target/linux/package/*/Config.in"
diff --git a/target/linux/package/Makefile b/target/linux/package/Makefile
new file mode 100644
index 0000000..d6ce862
--- /dev/null
+++ b/target/linux/package/Makefile
@@ -0,0 +1,54 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+# Main makefile for the packages
+include $(TOPDIR)/rules.mk
+include ../rules.mk
+
+package-$(CONFIG_PACKAGE_KMOD_ALSA) += alsa
+package-$(CONFIG_PACKAGE_KMOD_FUSE) += fuse
+package-$(CONFIG_PACKAGE_KMOD_HOSTAP) += hostap
+package-$(CONFIG_PACKAGE_KMOD_MADWIFI) += madwifi
+package-$(CONFIG_PACKAGE_KMOD_MINI_FO) += mini_fo
+package-$(CONFIG_PACKAGE_KMOD_OPENSWAN) += openswan
+package-$(CONFIG_PACKAGE_KMOD_SHFS) += shfs
+package-$(CONFIG_PACKAGE_KMOD_SPCA5XX) += spca5xx
+package-$(CONFIG_PACKAGE_KMOD_SWITCH) += switch
+package-$(CONFIG_PACKAGE_KMOD_UEAGLE_ATM) += ueagle-atm
+package-$(CONFIG_PACKAGE_KMOD_DIAG) += diag
+package-$(CONFIG_PACKAGE_KMOD_WLCOMPAT) += wlcompat
+package-$(CONFIG_PACKAGE_KMOD_ZD1211) += zd1211
+
+wlcompat-compile: base-files-compile
+
+all: compile install
+clean: $(patsubst %,%-clean,$(package-) $(package-y) $(package-m))
+prepare: $(patsubst %,%-prepare,$(package-y) $(package-m))
+compile: $(patsubst %,%-compile,$(package-y) $(package-m))
+install: $(patsubst %,%-install,$(package-y))
+
+KPKG_MAKEOPTS += BUILD_DIR="$(LINUX_BUILD_DIR)"
+
+%-prepare: FORCE
+ $(MAKE) -C $(patsubst %-prepare,%,$@) \
+ $(KPKG_MAKEOPTS) \
+ prepare
+
+%-compile: FORCE
+ $(MAKE) -C $(patsubst %-compile,%,$@) \
+ $(KPKG_MAKEOPTS) \
+ compile
+
+%-install: FORCE
+ $(MAKE) -C $(patsubst %-install,%,$@) \
+ $(KPKG_MAKEOPTS) \
+ install
+
+%-clean: FORCE
+ @$(MAKE) -C $(patsubst %-clean,%,$@) \
+ $(KPKG_MAKEOPTS) \
+ clean
+
diff --git a/target/linux/rb532-2.6/Makefile b/target/linux/rb532-2.6/Makefile
new file mode 100644
index 0000000..30fa1a8
--- /dev/null
+++ b/target/linux/rb532-2.6/Makefile
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+LINUX_VERSION:=2.6.17
+LINUX_RELEASE:=1
+LINUX_KERNEL_MD5SUM:=37ddefe96625502161f075b9d907f21e
+
+include ./config
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/kernel-build.mk
+
+$(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked
+ [ -d ../generic-$(KERNEL)/patches ] && $(PATCH) $(LINUX_DIR) ../generic-$(KERNEL)/patches
+ [ -d ./patches ] && $(PATCH) $(LINUX_DIR) ./patches
+ @$(CP) config $(LINUX_DIR)/.config
+ touch $@
+
diff --git a/target/linux/rb532-2.6/config b/target/linux/rb532-2.6/config
new file mode 100644
index 0000000..eaa3771
--- /dev/null
+++ b/target/linux/rb532-2.6/config
@@ -0,0 +1,1335 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17
+# Sun Jun 18 17:29:23 2006
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+CONFIG_MIKROTIK_RB500=y
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_IRQ_CPU=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_MIPS_L1_CACHE_SHIFT=4
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32_R1=y
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_MIPS_MT is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+# CONFIG_PCMCIA_LOAD_CIS is not set
+# CONFIG_PCMCIA_IOCTL is not set
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+# CONFIG_YENTA is not set
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+CONFIG_IPSEC_NAT_TRAVERSAL=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=y
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+CONFIG_IPV6_ROUTER_PREF=y
+# CONFIG_IPV6_ROUTE_INFO is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_BRIDGE_NETFILTER is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=y
+CONFIG_IP_NF_IRC=y
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+CONFIG_IP_NF_SIP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_IPP2P=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_TIME=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_IMQ=m
+# CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_ROUTE=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=y
+CONFIG_IP_NF_NAT_FTP=y
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_SET=m
+CONFIG_IP_NF_SET_MAX=256
+CONFIG_IP_NF_SET_HASHSIZE=1024
+CONFIG_IP_NF_SET_IPMAP=m
+CONFIG_IP_NF_SET_MACIPMAP=m
+CONFIG_IP_NF_SET_PORTMAP=m
+CONFIG_IP_NF_SET_IPHASH=m
+CONFIG_IP_NF_SET_NETHASH=m
+CONFIG_IP_NF_SET_IPTREE=m
+CONFIG_IP_NF_MATCH_SET=m
+CONFIG_IP_NF_TARGET_SET=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_OWNER=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_IMQ=m
+# CONFIG_IP6_NF_TARGET_LOG is not set
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_HL is not set
+# CONFIG_IP6_NF_RAW is not set
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_ESFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CLS_U32_MARK is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_HAMRADIO=y
+
+#
+# Packet Radio protocols
+#
+CONFIG_AX25=m
+# CONFIG_AX25_DAMA_SLAVE is not set
+# CONFIG_NETROM is not set
+# CONFIG_ROSE is not set
+
+#
+# AX.25 network device drivers
+#
+CONFIG_MKISS=m
+# CONFIG_6PACK is not set
+# CONFIG_BPQETHER is not set
+# CONFIG_BAYCOM_SER_FDX is not set
+# CONFIG_BAYCOM_SER_HDX is not set
+# CONFIG_YAM is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+CONFIG_IEEE80211_SOFTMAC=m
+# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=m
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=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
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE 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_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLOCK2MTD=y
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_BLK_DEV_CF_MIPS=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_IMQ=m
+# CONFIG_IMQ_BEHAVIOR_AA is not set
+# CONFIG_IMQ_BEHAVIOR_AB is not set
+CONFIG_IMQ_BEHAVIOR_BA=y
+# CONFIG_IMQ_BEHAVIOR_BB is not set
+CONFIG_IMQ_NUM_DEVS=2
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_KORINA=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+CONFIG_VIA_RHINE=y
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_LAN_SAA9730 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 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)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+CONFIG_NET_WIRELESS_RTNETLINK=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_PCMCIA_WAVELAN is not set
+# CONFIG_PCMCIA_NETWAVE is not set
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+# CONFIG_AIRO_CS is not set
+# CONFIG_PCMCIA_WL3501 is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+# CONFIG_PRISM54 is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+# CONFIG_HOSTAP_PLX is not set
+# CONFIG_HOSTAP_PCI is not set
+CONFIG_HOSTAP_CS=m
+# CONFIG_BCM43XX is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=m
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_SQUASHFS_VMALLOC is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_OPENWRT_PARTITION=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=m
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_FS is not set
+CONFIG_CROSSCOMPILE=y
+CONFIG_CMDLINE="root=/dev/mtdblock1 rootfstype=squashfs,jffs2 noinitrd console=ttyS0,115200"
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
diff --git a/target/linux/rb532-2.6/patches/100-rb5xx_support.patch b/target/linux/rb532-2.6/patches/100-rb5xx_support.patch
new file mode 100644
index 0000000..f846c78
--- /dev/null
+++ b/target/linux/rb532-2.6/patches/100-rb5xx_support.patch
@@ -0,0 +1,5606 @@
+diff -urN linux.old/arch/mips/Kconfig linux.dev/arch/mips/Kconfig
+--- linux.old/arch/mips/Kconfig 2006-06-18 03:49:35.000000000 +0200
++++ linux.dev/arch/mips/Kconfig 2006-10-11 21:56:38.000000000 +0200
+@@ -742,6 +742,19 @@
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select TOSHIBA_BOARDS
+
++config MIKROTIK_RB500
++ bool "Support for RB5xx boards"
++ select HW_HAS_PCI
++ select IRQ_CPU
++ select SYS_HAS_CPU_MIPS32_R1
++ select SYS_SUPPORTS_LITTLE_ENDIAN
++ select SYS_SUPPORTS_32BIT_KERNEL
++ select SWAP_IO_SPACE
++ select DMA_NONCOHERENT
++ help
++ Support the Mikrotik(tm) Routerboard 500 series,
++ such as the RB532.
++
+ config TOSHIBA_RBTX4927
+ bool "Toshiba TBTX49[23]7 board"
+ select DMA_NONCOHERENT
+@@ -1028,7 +1041,7 @@
+
+ config MIPS_L1_CACHE_SHIFT
+ int
+- default "4" if MACH_DECSTATION
++ default "4" if MACH_DECSTATION || MIKROTIK_RB500
+ default "7" if SGI_IP27
+ default "5"
+
+diff -urN linux.old/arch/mips/Makefile linux.dev/arch/mips/Makefile
+--- linux.old/arch/mips/Makefile 2006-10-11 21:55:59.000000000 +0200
++++ linux.dev/arch/mips/Makefile 2006-10-11 21:56:38.000000000 +0200
+@@ -580,6 +580,13 @@
+ load-$(CONFIG_TOSHIBA_JMR3927) += 0xffffffff80050000
+
+ #
++# Routerboard 532 board
++#
++core-$(CONFIG_MIKROTIK_RB500) += arch/mips/rb500/
++cflags-$(CONFIG_MIKROTIK_RB500) += -Iinclude/asm-mips/rc32434
++load-$(CONFIG_MIKROTIK_RB500) += 0xffffffff80101000
++
++#
+ # Toshiba RBTX4927 board or
+ # Toshiba RBTX4937 board
+ #
+diff -urN linux.old/arch/mips/mm/tlbex.c linux.dev/arch/mips/mm/tlbex.c
+--- linux.old/arch/mips/mm/tlbex.c 2006-06-18 03:49:35.000000000 +0200
++++ linux.dev/arch/mips/mm/tlbex.c 2006-10-11 21:56:38.000000000 +0200
+@@ -876,7 +876,6 @@
+ case CPU_R10000:
+ case CPU_R12000:
+ case CPU_R14000:
+- case CPU_4KC:
+ case CPU_SB1:
+ case CPU_SB1A:
+ case CPU_4KSC:
+@@ -904,6 +903,7 @@
+ tlbw(p);
+ break;
+
++ case CPU_4KC:
+ case CPU_4KEC:
+ case CPU_24K:
+ case CPU_34K:
+diff -urN linux.old/arch/mips/pci/fixup-rb500.c linux.dev/arch/mips/pci/fixup-rb500.c
+--- linux.old/arch/mips/pci/fixup-rb500.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/pci/fixup-rb500.c 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,49 @@
++/*
++ * Copyright 2001 MontaVista Software Inc.
++ * Author: MontaVista Software, Inc.
++ * stevel@mvista.com or source@mvista.com
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++
++#include <asm/rc32434/rc32434.h>
++
++static int __devinitdata irq_map[2][12] = {
++ { 0, 0, 2, 3, 2, 3, 0, 0, 0, 0, 0, 1 },
++ { 0, 0, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3 }
++};
++
++int __devinit pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++ int irq = 0;
++
++ if (dev->bus->number < 2 && PCI_SLOT(dev->devfn) < 12) {
++ irq = irq_map[dev->bus->number][PCI_SLOT(dev->devfn)];
++ }
++ return irq + GROUP4_IRQ_BASE + 4;
++}
++
+diff -urN linux.old/arch/mips/pci/Makefile linux.dev/arch/mips/pci/Makefile
+--- linux.old/arch/mips/pci/Makefile 2006-06-18 03:49:35.000000000 +0200
++++ linux.dev/arch/mips/pci/Makefile 2006-10-11 21:56:38.000000000 +0200
+@@ -57,3 +57,4 @@
+ obj-$(CONFIG_TOSHIBA_RBTX4938) += fixup-tx4938.o ops-tx4938.o
+ obj-$(CONFIG_VICTOR_MPC30X) += fixup-mpc30x.o
+ obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capcella.o
++obj-$(CONFIG_MIKROTIK_RB500) += pci-rc32434.o ops-rc32434.o fixup-rb500.o
+diff -urN linux.old/arch/mips/pci/ops-rc32434.c linux.dev/arch/mips/pci/ops-rc32434.c
+--- linux.old/arch/mips/pci/ops-rc32434.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/pci/ops-rc32434.c 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,195 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * pci_ops for IDT EB434 board
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++
++#include <asm/cpu.h>
++#include <asm/io.h>
++
++#include <asm/rc32434/rc32434.h>
++#include <asm/rc32434/pci.h>
++
++#define PCI_ACCESS_READ 0
++#define PCI_ACCESS_WRITE 1
++
++
++#define PCI_CFG_SET(bus,slot,func,off) \
++ (rc32434_pci->pcicfga = (0x80000000 | \
++ ((bus) << 16) | ((slot)<<11) | \
++ ((func)<<8) | (off)))
++
++static inline int config_access(unsigned char access_type, struct pci_bus *bus,
++ unsigned int devfn, unsigned char where,
++ u32 * data)
++{
++ unsigned int slot = PCI_SLOT(devfn);
++ u8 func = PCI_FUNC(devfn);
++
++ /* Setup address */
++ PCI_CFG_SET(bus->number, slot, func, where);
++ rc32434_sync();
++
++ if (access_type == PCI_ACCESS_WRITE)
++ rc32434_pci->pcicfgd = *data;
++ else
++ *data = rc32434_pci->pcicfgd;
++
++ rc32434_sync();
++
++ return 0;
++}
++
++
++/*
++ * We can't address 8 and 16 bit words directly. Instead we have to
++ * read/write a 32bit word and mask/modify the data we actually want.
++ */
++static int read_config_byte(struct pci_bus *bus, unsigned int devfn,
++ int where, u8 * val)
++{
++ u32 data;
++ int ret;
++
++ ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data);
++ *val = (data >> ((where & 3) << 3)) & 0xff;
++ return ret;
++}
++
++static int read_config_word(struct pci_bus *bus, unsigned int devfn,
++ int where, u16 * val)
++{
++ u32 data;
++ int ret;
++
++ ret = config_access(PCI_ACCESS_READ, bus, devfn, where, &data);
++ *val = (data >> ((where & 3) << 3)) & 0xffff;
++ return ret;
++}
++
++static int read_config_dword(struct pci_bus *bus, unsigned int devfn,
++ int where, u32 * val)
++{
++ int ret;
++
++ ret = config_access(PCI_ACCESS_READ, bus, devfn, where, val);
++ return ret;
++}
++
++static int
++write_config_byte(struct pci_bus *bus, unsigned int devfn, int where,
++ u8 val)
++{
++ u32 data = 0;
++
++ if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
++ return -1;
++
++ data = (data & ~(0xff << ((where & 3) << 3))) |
++ (val << ((where & 3) << 3));
++
++ if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
++ return -1;
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++
++static int
++write_config_word(struct pci_bus *bus, unsigned int devfn, int where,
++ u16 val)
++{
++ u32 data = 0;
++
++ if (config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
++ return -1;
++
++ data = (data & ~(0xffff << ((where & 3) << 3))) |
++ (val << ((where & 3) << 3));
++
++ if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
++ return -1;
++
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++
++static int
++write_config_dword(struct pci_bus *bus, unsigned int devfn, int where,
++ u32 val)
++{
++ if (config_access(PCI_ACCESS_WRITE, bus, devfn, where, &val))
++ return -1;
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++static int pci_config_read(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 * val)
++{
++ switch (size) {
++ case 1:
++ return read_config_byte(bus, devfn, where, (u8 *) val);
++ case 2:
++ return read_config_word(bus, devfn, where, (u16 *) val);
++ default:
++ return read_config_dword(bus, devfn, where, val);
++ }
++}
++
++static int pci_config_write(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 val)
++{
++ switch (size) {
++ case 1:
++ return write_config_byte(bus, devfn, where, (u8) val);
++ case 2:
++ return write_config_word(bus, devfn, where, (u16) val);
++ default:
++ return write_config_dword(bus, devfn, where, val);
++ }
++}
++
++struct pci_ops rc32434_pci_ops = {
++ .read = pci_config_read,
++ .write = pci_config_write,
++};
+diff -urN linux.old/arch/mips/pci/pci-rc32434.c linux.dev/arch/mips/pci/pci-rc32434.c
+--- linux.old/arch/mips/pci/pci-rc32434.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/pci/pci-rc32434.c 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,234 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * PCI initialization for IDT EB434 board
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++
++#include <asm/rc32434/rc32434.h>
++#include <asm/rc32434/pci.h>
++
++#define PCI_ACCESS_READ 0
++#define PCI_ACCESS_WRITE 1
++
++/* define an unsigned array for the PCI registers */
++unsigned int korinaCnfgRegs[25] = {
++ KORINA_CNFG1, KORINA_CNFG2, KORINA_CNFG3, KORINA_CNFG4,
++ KORINA_CNFG5, KORINA_CNFG6, KORINA_CNFG7, KORINA_CNFG8,
++ KORINA_CNFG9, KORINA_CNFG10, KORINA_CNFG11, KORINA_CNFG12,
++ KORINA_CNFG13, KORINA_CNFG14, KORINA_CNFG15, KORINA_CNFG16,
++ KORINA_CNFG17, KORINA_CNFG18, KORINA_CNFG19, KORINA_CNFG20,
++ KORINA_CNFG21, KORINA_CNFG22, KORINA_CNFG23, KORINA_CNFG24
++};
++static struct resource rc32434_res_pci_mem1;
++static struct resource rc32434_res_pci_mem2;
++
++static struct resource rc32434_res_pci_mem1 = {
++ .name = "PCI MEM1",
++ .start = 0x50000000,
++ .end = 0x5FFFFFFF,
++ .flags = IORESOURCE_MEM,
++ .parent = &rc32434_res_pci_mem1,
++ .sibling = NULL,
++ .child = &rc32434_res_pci_mem2
++};
++
++static struct resource rc32434_res_pci_mem2 = {
++ .name = "PCI Mem2",
++ .start = 0x60000000,
++ .end = 0x6FFFFFFF,
++ .flags = IORESOURCE_MEM,
++ .parent = &rc32434_res_pci_mem1,
++ .sibling = NULL,
++ .child = NULL
++};
++
++static struct resource rc32434_res_pci_io1 = {
++ .name = "PCI I/O1",
++ .start = 0x18800000,
++ .end = 0x188FFFFF,
++ .flags = IORESOURCE_IO,
++};
++
++extern struct pci_ops rc32434_pci_ops;
++
++#define PCI_MEM1_START PCI_ADDR_START
++#define PCI_MEM1_END PCI_ADDR_START + CPUTOPCI_MEM_WIN - 1
++#define PCI_MEM2_START PCI_ADDR_START + CPUTOPCI_MEM_WIN
++#define PCI_MEM2_END PCI_ADDR_START + ( 2* CPUTOPCI_MEM_WIN) - 1
++#define PCI_IO1_START PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN)
++#define PCI_IO1_END PCI_ADDR_START + (2* CPUTOPCI_MEM_WIN) + CPUTOPCI_IO_WIN -1
++#define PCI_IO2_START PCI_ADDR_START + (2 * CPUTOPCI_MEM_WIN) + CPUTOPCI_IO_WIN
++#define PCI_IO2_END PCI_ADDR_START + (2* CPUTOPCI_MEM_WIN) + (2 * CPUTOPCI_IO_WIN) -1
++
++
++struct pci_controller rc32434_controller2;
++
++struct pci_controller rc32434_controller = {
++ .pci_ops = &rc32434_pci_ops,
++ .mem_resource = &rc32434_res_pci_mem1,
++ .io_resource = &rc32434_res_pci_io1,
++ .mem_offset = 0,
++ .io_offset = 0,
++
++};
++
++#ifdef __MIPSEB__
++#define PCI_ENDIAN_FLAG PCILBAC_sb_m
++#else
++#define PCI_ENDIAN_FLAG 0
++#endif
++
++static int __init rc32434_pcibridge_init(void)
++{
++ unsigned int pcicValue, pcicData = 0;
++ unsigned int dummyRead, pciCntlVal;
++ int loopCount;
++ unsigned int pciConfigAddr;
++
++ pcicValue = rc32434_pci->pcic;
++ pcicValue = (pcicValue >> PCIM_SHFT) & PCIM_BIT_LEN;
++ if (!((pcicValue == PCIM_H_EA) ||
++ (pcicValue == PCIM_H_IA_FIX) ||
++ (pcicValue == PCIM_H_IA_RR))) {
++ printk("PCI init error!!!\n");
++ /* Not in Host Mode, return ERROR */
++ return -1;
++ }
++ /* Enables the Idle Grant mode, Arbiter Parking */
++ pcicData |=(PCIC_igm_m|PCIC_eap_m|PCIC_en_m);
++ rc32434_pci->pcic = pcicData; /* Enable the PCI bus Interface */
++ /* Zero out the PCI status & PCI Status Mask */
++ for(;;)
++ {
++ pcicData = rc32434_pci->pcis;
++ if (!(pcicData & PCIS_rip_m))
++ break;
++ }
++
++ rc32434_pci->pcis = 0;
++ rc32434_pci->pcism = 0xFFFFFFFF;
++ /* Zero out the PCI decoupled registers */
++ rc32434_pci->pcidac=0; /* disable PCI decoupled accesses at initialization */
++ rc32434_pci->pcidas=0; /* clear the status */
++ rc32434_pci->pcidasm=0x0000007F; /* Mask all the interrupts */
++ /* Mask PCI Messaging Interrupts */
++ rc32434_pci_msg->pciiic = 0;
++ rc32434_pci_msg->pciiim = 0xFFFFFFFF;
++ rc32434_pci_msg->pciioic = 0;
++ rc32434_pci_msg->pciioim = 0;
++
++
++ /* Setup PCILB0 as Memory Window */
++ rc32434_pci->pcilba[0].a = (unsigned int) (PCI_ADDR_START);
++
++ /* setup the PCI map address as same as the local address */
++
++ rc32434_pci->pcilba[0].m = (unsigned int) (PCI_ADDR_START);
++
++
++ /* Setup PCILBA1 as MEM */
++ rc32434_pci->pcilba[0].c = ( ((SIZE_256MB & 0x1f) << PCILBAC_size_b) | PCI_ENDIAN_FLAG);
++ dummyRead = rc32434_pci->pcilba[0].c; /* flush the CPU write Buffers */
++ rc32434_pci->pcilba[1].a = 0x60000000;
++ rc32434_pci->pcilba[1].m = 0x60000000;
++
++ /* setup PCILBA2 as IO Window*/
++ rc32434_pci->pcilba[1].c = (((SIZE_256MB & 0x1f) << PCILBAC_size_b )| PCI_ENDIAN_FLAG);
++ dummyRead = rc32434_pci->pcilba[1].c; /* flush the CPU write Buffers */
++ rc32434_pci->pcilba[2].a = 0x18C00000;
++ rc32434_pci->pcilba[2].m = 0x18FFFFFF;
++
++ /* setup PCILBA2 as IO Window*/
++ rc32434_pci->pcilba[2].c = (((SIZE_4MB & 0x1f) << PCILBAC_size_b) | PCI_ENDIAN_FLAG );
++ dummyRead = rc32434_pci->pcilba[2].c; /* flush the CPU write Buffers */
++
++ /* Setup PCILBA3 as IO Window */
++ rc32434_pci->pcilba[3].a = 0x18800000;
++ rc32434_pci->pcilba[3].m = 0x18800000;
++ rc32434_pci->pcilba[3].c = ( (((SIZE_1MB & 0x1ff) << PCILBAC_size_b) | PCILBAC_msi_m) | PCI_ENDIAN_FLAG);
++ dummyRead = rc32434_pci->pcilba[3].c; /* flush the CPU write Buffers */
++
++ pciConfigAddr=(unsigned int)(0x80000004);
++ for(loopCount=0;loopCount<24;loopCount++){
++ rc32434_pci->pcicfga=pciConfigAddr;
++ dummyRead=rc32434_pci->pcicfga;
++ rc32434_pci->pcicfgd = korinaCnfgRegs[loopCount];
++ dummyRead=rc32434_pci->pcicfgd;
++ pciConfigAddr += 4;
++ }
++ rc32434_pci->pcitc = (unsigned int)((PCITC_RTIMER_VAL&0xff) << PCITC_rtimer_b)
++ | ((PCITC_DTIMER_VAL&0xff) << PCITC_dtimer_b);
++
++ pciCntlVal=rc32434_pci->pcic;
++ pciCntlVal &=~(PCIC_tnr_m);
++ rc32434_pci->pcic = pciCntlVal;
++ pciCntlVal=rc32434_pci->pcic;
++ return 0;
++}
++
++/* Do platform specific device initialization at pci_enable_device() time */
++int pcibios_plat_dev_init(struct pci_dev *dev)
++{
++ if (PCI_SLOT(dev->devfn) == 6 && dev->bus->number == 0) {
++ /* disable prefetched memory range */
++ pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, 0);
++ pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, 0x10);
++
++ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 4);
++ }
++ return 0;
++}
++
++static int __init rc32434_pci_init(void)
++{
++ printk("PCI: Initializing PCI\n");
++
++ ioport_resource.start = rc32434_res_pci_io1.start;
++ ioport_resource.end = rc32434_res_pci_io1.end;
++
++ rc32434_pcibridge_init();
++
++ register_pci_controller(&rc32434_controller);
++ rc32434_sync();
++}
++
++arch_initcall(rc32434_pci_init);
++
+diff -urN linux.old/arch/mips/rb500/devices.c linux.dev/arch/mips/rb500/devices.c
+--- linux.old/arch/mips/rb500/devices.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/rb500/devices.c 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,211 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/ctype.h>
++#include <linux/string.h>
++#include <linux/platform_device.h>
++#include <asm/unaligned.h>
++#include <asm/io.h>
++
++#include <asm/rc32434/rc32434.h>
++#include <asm/rc32434/dma.h>
++#include <asm/rc32434/dma_v.h>
++#include <asm/rc32434/eth.h>
++#include <asm/rc32434/rb.h>
++
++#define ETH0_DMA_RX_IRQ GROUP1_IRQ_BASE + 0
++#define ETH0_DMA_TX_IRQ GROUP1_IRQ_BASE + 1
++#define ETH0_RX_OVR_IRQ GROUP3_IRQ_BASE + 9
++#define ETH0_TX_UND_IRQ GROUP3_IRQ_BASE + 10
++
++#define ETH0_RX_DMA_ADDR (DMA0_PhysicalAddress + 0*DMA_CHAN_OFFSET)
++#define ETH0_TX_DMA_ADDR (DMA0_PhysicalAddress + 1*DMA_CHAN_OFFSET)
++
++static struct resource korina_dev0_res[] = {
++ {
++ .name = "korina_regs",
++ .start = ETH0_PhysicalAddress,
++ .end = ETH0_PhysicalAddress + sizeof(ETH_t),
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .name = "korina_rx",
++ .start = ETH0_DMA_RX_IRQ,
++ .end = ETH0_DMA_RX_IRQ,
++ .flags = IORESOURCE_IRQ
++ },
++ {
++ .name = "korina_tx",
++ .start = ETH0_DMA_TX_IRQ,
++ .end = ETH0_DMA_TX_IRQ,
++ .flags = IORESOURCE_IRQ
++ },
++ {
++ .name = "korina_ovr",
++ .start = ETH0_RX_OVR_IRQ,
++ .end = ETH0_RX_OVR_IRQ,
++ .flags = IORESOURCE_IRQ
++ },
++ {
++ .name = "korina_und",
++ .start = ETH0_TX_UND_IRQ,
++ .end = ETH0_TX_UND_IRQ,
++ .flags = IORESOURCE_IRQ
++ },
++ {
++ .name = "korina_dma_rx",
++ .start = ETH0_RX_DMA_ADDR,
++ .end = ETH0_RX_DMA_ADDR + DMA_CHAN_OFFSET - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .name = "korina_dma_tx",
++ .start = ETH0_TX_DMA_ADDR,
++ .end = ETH0_TX_DMA_ADDR + DMA_CHAN_OFFSET - 1,
++ .flags = IORESOURCE_MEM,
++ }
++};
++
++static struct korina_device korina_dev0_data = {
++ .name = "korina0",
++ .mac = { 0xde, 0xca, 0xff, 0xc0, 0xff, 0xee }
++};
++
++static struct platform_device korina_dev0 = {
++ .id = 0,
++ .name = "korina",
++ .dev.platform_data = &korina_dev0_data,
++ .resource = korina_dev0_res,
++ .num_resources = ARRAY_SIZE(korina_dev0_res),
++};
++
++
++#define CF_GPIO_NUM 13
++
++static struct resource cf_slot0_res[] = {
++ {
++ .name = "cf_membase",
++ .flags = IORESOURCE_MEM
++ },
++ {
++ .name = "cf_irq",
++ .start = (8 + 4 * 32 + CF_GPIO_NUM), /* 149 */
++ .end = (8 + 4 * 32 + CF_GPIO_NUM),
++ .flags = IORESOURCE_IRQ
++ }
++};
++
++static struct cf_device cf_slot0_data = {
++ .gpio_pin = 13
++};
++
++static struct platform_device cf_slot0 = {
++ .id = 0,
++ .name = "rb500-cf",
++ .dev.platform_data = &cf_slot0_data,
++ .resource = cf_slot0_res,
++ .num_resources = ARRAY_SIZE(cf_slot0_res),
++};
++
++
++
++static struct platform_device *rb500_devs[] = {
++ &korina_dev0,
++ &cf_slot0
++};
++
++static void __init parse_mac_addr(char* macstr)
++{
++ int i, j;
++ unsigned char result, value;
++
++ for (i=0; i<6; i++) {
++ result = 0;
++ if (i != 5 && *(macstr+2) != ':') {
++ return;
++ }
++ for (j=0; j<2; j++) {
++ if (isxdigit(*macstr) && (value = isdigit(*macstr) ? *macstr-'0' :
++ toupper(*macstr)-'A'+10) < 16) {
++ result = result*16 + value;
++ macstr++;
++ }
++ else return;
++ }
++
++ macstr++;
++ korina_dev0_data.mac[i] = result;
++ }
++}
++
++
++/* DEVICE CONTROLLER 1 */
++#define CFG_DC_DEV1 (void*)0xb8010010
++#define CFG_DC_DEVBASE 0x0
++#define CFG_DC_DEVMASK 0x4
++#define CFG_DC_DEVC 0x8
++#define CFG_DC_DEVTC 0xC
++
++
++static int __init plat_setup_devices(void)
++{
++ /* Look for the CF card reader */
++ if (!readl(CFG_DC_DEV1 + CFG_DC_DEVMASK))
++ rb500_devs[1] = NULL;
++ else {
++ cf_slot0_res[0].start = readl(CFG_DC_DEV1 + CFG_DC_DEVBASE);
++ cf_slot0_res[0].end = cf_slot0_res[0].start + 0x1000;
++ }
++
++ return platform_add_devices(rb500_devs, ARRAY_SIZE(rb500_devs));
++}
++
++static int __init setup_kmac(char *s)
++{
++ printk("korina mac = %s\n",s);
++ parse_mac_addr(s);
++ return 0;
++}
++
++__setup("kmac=", setup_kmac);
++arch_initcall(plat_setup_devices);
++
++
++#if defined(CONFIG_MTD_BLOCK2MTD) && defined(CONFIG_BLK_DEV_CF_MIPS)
++extern void block2mtd_setup(char *initstr);
++extern void mount_devfs_fs(void);
++
++static int __init setup_mtd(void)
++{
++ struct hd_struct **part;
++ int num = 0, i;
++ char initstr[64];
++
++ if (cf_slot0_data.gd == NULL)
++ return 0;
++
++ /* count partitions */
++ part = cf_slot0_data.gd->part;
++ while (part[num] != NULL) {
++ num++;
++ }
++
++ if (num < 2)
++ return 0;
++
++ mount_devfs_fs();
++ printk("Setting up block2mtd devices\n");
++
++ block2mtd_setup("/dev/cf/card0/part1,131072,kernel");
++ block2mtd_setup("/dev/cf/card0/part2,131072,rootfs");
++
++ for (i = 2; part[i]; i++) {
++ sprintf(initstr, "/dev/cf/card0/part%d,131072,part%d", i + 1, i + 1);
++ block2mtd_setup(initstr);
++ }
++
++ return 0;
++}
++
++late_initcall(setup_mtd);
++#endif
+diff -urN linux.old/arch/mips/rb500/early_serial.c linux.dev/arch/mips/rb500/early_serial.c
+--- linux.old/arch/mips/rb500/early_serial.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/rb500/early_serial.c 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,199 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * EB434 specific polling driver for 16550 UART.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * Copyright (C) 2000 by Lineo, Inc.
++ * Written by Quinn Jensen (jensenq@lineo.com)
++ **************************************************************************
++ * P. Sadik Oct 20, 2003
++ *
++ * DIVISOR is made a function of idt_cpu_freq
++ **************************************************************************
++ * P. Sadik Oct 30, 2003
++ *
++ * added reset_cons_port
++ **************************************************************************
++ */
++
++#include <linux/serial_reg.h>
++
++/* turn this on to watch the debug protocol echoed on the console port */
++#define DEBUG_REMOTE_DEBUG
++
++#define CONS_BAUD 115200
++
++extern unsigned int idt_cpu_freq;
++
++#define EXT_FREQ 24000000
++#define INT_FREQ idt_cpu_freq
++
++#define EXT_PORT 0xb9800000u
++#define EXT_SHIFT 0
++
++#ifdef __MIPSEB__
++#define INT_PORT 0xb8058003u
++#else
++#define INT_PORT 0xb8058000u
++#endif
++#define INT_SHIFT 2
++
++#define INT_FCR UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_14
++#define EXT_FCR UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT
++
++typedef struct
++{
++ volatile unsigned char *base;
++ unsigned int shift;
++ unsigned int freq;
++ unsigned int fcr;
++} ser_port;
++
++ser_port ports[2] =
++{
++ { (volatile unsigned char *)INT_PORT, INT_SHIFT, 0, INT_FCR},
++ { (volatile unsigned char *)EXT_PORT, EXT_SHIFT, EXT_FREQ, EXT_FCR}
++};
++
++#define CONS_PORT 0
++
++void cons_putc(char c);
++int port_getc(int port);
++void port_putc(int port, char c);
++
++int cons_getc(void)
++{
++ return port_getc(CONS_PORT);
++}
++
++void cons_putc(char c)
++{
++ port_putc(CONS_PORT, c);
++}
++
++void cons_puts(char *s)
++{
++ while(*s) {
++ if(*s == '\n') cons_putc('\r');
++ cons_putc(*s);
++ s++;
++ }
++}
++
++void cons_do_putn(int n)
++{
++ if(n) {
++ cons_do_putn(n / 10);
++ cons_putc(n % 10 + '0');
++ }
++}
++
++void cons_putn(int n)
++{
++ if(n < 0) {
++ cons_putc('-');
++ n = -n;
++ }
++
++ if (n == 0) {
++ cons_putc('0');
++ } else {
++ cons_do_putn(n);
++ }
++}
++
++int port_getc(int p)
++{
++ volatile unsigned char *port = ports[p].base;
++ int s = ports[p].shift;
++ int c;
++
++ while((*(port + (UART_LSR << s)) & UART_LSR_DR) == 0) {
++ continue;
++ }
++
++ c = *(port + (UART_RX << s));
++
++ return c;
++}
++
++int port_getc_ready(int p)
++{
++ volatile unsigned char *port = ports[p].base;
++ int s = ports[p].shift;
++
++ return *(port + (UART_LSR << s)) & UART_LSR_DR;
++}
++
++#define OK_TO_XMT (UART_LSR_TEMT | UART_LSR_THRE)
++
++void port_putc(int p, char c)
++{
++ volatile unsigned char *port = ports[p].base;
++ int s = ports[p].shift;
++ volatile unsigned char *lsr = port + (UART_LSR << s);
++
++ while((*lsr & OK_TO_XMT) != OK_TO_XMT) {
++ continue;
++ }
++
++ *(port + (UART_TX << s)) = c;
++}
++
++void reset_cons_port(void)
++{
++ volatile unsigned char *port = ports[CONS_PORT].base;
++ unsigned int s = ports[CONS_PORT].shift;
++ unsigned int DIVISOR;
++
++ if (ports[CONS_PORT].freq)
++ DIVISOR = (ports[CONS_PORT].freq / 16 / CONS_BAUD);
++ else
++ DIVISOR = (idt_cpu_freq / 16 / CONS_BAUD);
++
++ /* reset the port */
++ *(port + (UART_CSR << s)) = 0;
++
++ /* clear and enable the FIFOs */
++ *(port + (UART_FCR << s)) = ports[CONS_PORT].fcr;
++
++ /* set the baud rate */
++ *(port + (UART_LCR << s)) = UART_LCR_DLAB; /* enable DLL, DLM registers */
++
++ *(port + (UART_DLL << s)) = DIVISOR;
++ *(port + (UART_DLM << s)) = DIVISOR >> 8;
++ /* set the line control stuff and disable DLL, DLM regs */
++
++ *(port + (UART_LCR << s)) = UART_LCR_STOP | /* 2 stop bits */
++ UART_LCR_WLEN8; /* 8 bit word length */
++
++ /* leave interrupts off */
++ *(port + (UART_IER << s)) = 0;
++
++ /* the modem controls don't leave the chip on this port, so leave them alone */
++ *(port + (UART_MCR << s)) = 0;
++}
+diff -urN linux.old/arch/mips/rb500/irq.c linux.dev/arch/mips/rb500/irq.c
+--- linux.old/arch/mips/rb500/irq.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/rb500/irq.c 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,264 @@
++/*
++ * BRIEF MODULE DESCRIPTION
++ * RC32434 interrupt routines.
++ *
++ * Copyright 2002 MontaVista Software Inc.
++ * Author: MontaVista Software, Inc.
++ * stevel@mvista.com or source@mvista.com
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ */
++
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/kernel_stat.h>
++#include <linux/module.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/timex.h>
++#include <linux/slab.h>
++#include <linux/random.h>
++#include <linux/delay.h>
++
++#include <asm/bitops.h>
++#include <asm/bootinfo.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/time.h>
++#include <asm/mipsregs.h>
++#include <asm/system.h>
++#include <asm/rc32434/rc32434.h>
++#include <asm/rc32434/gpio.h>
++
++extern void set_debug_traps(void);
++extern irq_cpustat_t irq_stat [NR_CPUS];
++unsigned int local_bh_count[NR_CPUS];
++unsigned int local_irq_count[NR_CPUS];
++
++static unsigned int startup_irq(unsigned int irq);
++static void rb500_end_irq(unsigned int irq_nr);
++static void mask_and_ack_irq(unsigned int irq_nr);
++static void rb500_enable_irq(unsigned int irq_nr);
++static void rb500_disable_irq(unsigned int irq_nr);
++
++extern void __init init_generic_irq(void);
++
++typedef struct {
++ u32 mask; /* mask of valid bits in pending/mask registers */
++ volatile u32 *base_addr;
++} intr_group_t;
++
++#define RC32434_NR_IRQS (GROUP4_IRQ_BASE + 32)
++
++#if (NR_IRQS < RC32434_NR_IRQS)
++#error Too little irqs defined. Did you override <asm/irq.h> ?
++#endif
++
++static const intr_group_t intr_group[NUM_INTR_GROUPS] = {
++ { 0x0000efff, (u32 *)KSEG1ADDR(IC_GROUP0_PEND + 0 * IC_GROUP_OFFSET) },
++ { 0x00001fff, (u32 *)KSEG1ADDR(IC_GROUP0_PEND + 1 * IC_GROUP_OFFSET) },
++ { 0x00000007, (u32 *)KSEG1ADDR(IC_GROUP0_PEND + 2 * IC_GROUP_OFFSET) },
++ { 0x0003ffff, (u32 *)KSEG1ADDR(IC_GROUP0_PEND + 3 * IC_GROUP_OFFSET) },
++ { 0xffffffff, (u32 *)KSEG1ADDR(IC_GROUP0_PEND + 4 * IC_GROUP_OFFSET) }
++};
++
++#define READ_PEND(base) (*(base))
++#define READ_MASK(base) (*(base + 2))
++#define WRITE_MASK(base, val) (*(base + 2) = (val))
++
++static inline int irq_to_group(unsigned int irq_nr)
++{
++ return ((irq_nr - GROUP0_IRQ_BASE) >> 5);
++}
++
++static inline int group_to_ip(unsigned int group)
++{
++ return group + 2;
++}
++
++static inline void enable_local_irq(unsigned int ip)
++{
++ int ipnum = 0x100 << ip;
++ clear_c0_cause(ipnum);
++ set_c0_status(ipnum);
++}
++
++static inline void disable_local_irq(unsigned int ip)
++{
++ int ipnum = 0x100 << ip;
++ clear_c0_status(ipnum);
++}
++
++static inline void ack_local_irq(unsigned int ip)
++{
++ int ipnum = 0x100 << ip;
++ clear_c0_cause(ipnum);
++}
++
++static void rb500_enable_irq(unsigned int irq_nr)
++{
++ int ip = irq_nr - GROUP0_IRQ_BASE;
++ unsigned int group, intr_bit;
++ volatile unsigned int *addr;
++
++
++ if (ip < 0)
++ enable_local_irq(irq_nr);
++ else {
++ group = ip >> 5;
++
++ ip &= (1<<5)-1;
++ intr_bit = 1 << ip;
++
++ enable_local_irq(group_to_ip(group));
++
++ addr = intr_group[group].base_addr;
++ WRITE_MASK(addr, READ_MASK(addr) & ~intr_bit);
++ }
++}
++
++static void rb500_disable_irq(unsigned int irq_nr)
++{
++ int ip = irq_nr - GROUP0_IRQ_BASE;
++ unsigned int group, intr_bit, mask;
++ volatile unsigned int *addr;
++
++ if (ip < 0) {
++ disable_local_irq(irq_nr);
++ }else{
++ group = ip >> 5;
++
++ ip &= (1<<5) -1;
++ intr_bit = 1 << ip;
++ addr = intr_group[group].base_addr;
++ mask = READ_MASK(addr);
++ mask |= intr_bit;
++ WRITE_MASK(addr,mask);
++
++ /*
++ * if there are no more interrupts enabled in this
++ * group, disable corresponding IP
++ */
++ if (mask == intr_group[group].mask)
++ disable_local_irq(group_to_ip(group));
++ }
++}
++
++static unsigned int startup_irq(unsigned int irq_nr)
++{
++ rb500_enable_irq(irq_nr);
++ return 0;
++}
++
++static void shutdown_irq(unsigned int irq_nr)
++{
++ rb500_disable_irq(irq_nr);
++ return;
++}
++
++static void mask_and_ack_irq(unsigned int irq_nr)
++{
++ rb500_disable_irq(irq_nr);
++ ack_local_irq(group_to_ip(irq_to_group(irq_nr)));
++}
++
++static void rb500_end_irq(unsigned int irq_nr)
++{
++
++ int ip = irq_nr - GROUP0_IRQ_BASE;
++ unsigned int intr_bit, group;
++ volatile unsigned int *addr;
++
++ if ((irq_desc[irq_nr].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
++ printk("warning: end_irq %d did not enable (%x)\n",
++ irq_nr, irq_desc[irq_nr].status);
++ return;
++ }
++
++ if (ip < 0) {
++ enable_local_irq(irq_nr);
++ } else {
++ group = ip >> 5;
++
++ ip &= (1 << 5) - 1;
++ intr_bit = 1 << ip;
++
++ if (irq_nr >= GROUP4_IRQ_BASE && irq_nr <= (GROUP4_IRQ_BASE + 13)) {
++ gpio->gpioistat = gpio->gpioistat & ~intr_bit;
++ }
++
++ enable_local_irq(group_to_ip(group));
++
++ addr = intr_group[group].base_addr;
++ WRITE_MASK(addr, READ_MASK(addr) & ~intr_bit);
++ }
++}
++
++static struct hw_interrupt_type rc32434_irq_type = {
++ .typename = "RB500",
++ .startup = startup_irq,
++ .shutdown = shutdown_irq,
++ .enable = rb500_enable_irq,
++ .disable = rb500_disable_irq,
++ .ack = mask_and_ack_irq,
++ .end = rb500_end_irq,
++};
++
++
++void __init arch_init_irq(void)
++{
++ int i;
++
++ printk("Initializing IRQ's: %d out of %d\n", RC32434_NR_IRQS, NR_IRQS);
++ memset(irq_desc, 0, sizeof(irq_desc));
++
++ for (i = 0; i < RC32434_NR_IRQS; i++) {
++ irq_desc[i].status = IRQ_DISABLED;
++ irq_desc[i].action = NULL;
++ irq_desc[i].depth = 1;
++ irq_desc[i].handler = &rc32434_irq_type;
++ spin_lock_init(&irq_desc[i].lock);
++ }
++}
++
++/* Main Interrupt dispatcher */
++asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
++{
++ unsigned int ip, pend, group;
++ volatile unsigned int *addr;
++ unsigned int cp0_cause = read_c0_cause() & read_c0_status();
++
++ if (cp0_cause & CAUSEF_IP7) {
++ ll_timer_interrupt(7, regs);
++ } else if ((ip = (cp0_cause & 0x7c00))) {
++ group = 21 - rc32434_clz(ip);
++
++ addr = intr_group[group].base_addr;
++
++ pend = READ_PEND(addr);
++ pend &= ~READ_MASK(addr); // only unmasked interrupts
++ pend = 39 - rc32434_clz(pend);
++ do_IRQ((group << 5) + pend, regs);
++ }
++}
+diff -urN linux.old/arch/mips/rb500/Makefile linux.dev/arch/mips/rb500/Makefile
+--- linux.old/arch/mips/rb500/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/rb500/Makefile 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,5 @@
++#
++# Makefile for the RB500 board specific parts of the kernel
++#
++
++obj-y += irq.o time.o setup.o serial.o early_serial.o prom.o misc.o devices.o
+diff -urN linux.old/arch/mips/rb500/misc.c linux.dev/arch/mips/rb500/misc.c
+--- linux.old/arch/mips/rb500/misc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/rb500/misc.c 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,54 @@
++#include <linux/module.h>
++#include <linux/kernel.h> /* printk() */
++#include <linux/types.h> /* size_t */
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include <asm/rc32434/rb.h>
++
++#define GPIO_BADDR 0xb8050000
++
++
++static unsigned char *devCtl3Base = (unsigned char *) KSEG1ADDR(0x18010030);
++static unsigned char latchU5State = 0;
++static spinlock_t clu5Lock = SPIN_LOCK_UNLOCKED;
++
++void set434Reg(unsigned regOffs, unsigned bit, unsigned len, unsigned val) {
++ unsigned flags, data;
++ unsigned i = 0;
++ spin_lock_irqsave(&clu5Lock, flags);
++ data = *(volatile unsigned *) (IDT434_REG_BASE + regOffs);
++ for (i = 0; i != len; ++i) {
++ if (val & (1 << i)) data |= (1 << (i + bit));
++ else data &= ~(1 << (i + bit));
++ }
++ *(volatile unsigned *) (IDT434_REG_BASE + regOffs) = data;
++ spin_unlock_irqrestore(&clu5Lock, flags);
++}
++
++void changeLatchU5(unsigned char orMask, unsigned char nandMask) {
++ unsigned flags;
++ spin_lock_irqsave(&clu5Lock, flags);
++ latchU5State = (latchU5State | orMask) & ~nandMask;
++ *devCtl3Base = latchU5State;
++ spin_unlock_irqrestore(&clu5Lock, flags);
++}
++
++u32 gpio_get(gpio_func func)
++{
++ return readl((void *) GPIO_BADDR + func);
++}
++
++void gpio_set(gpio_func func, u32 mask, u32 value)
++{
++ u32 val = readl((void *) GPIO_BADDR + func);
++
++ val &= ~mask;
++ val |= value & mask;
++
++ writel(val, (void *) GPIO_BADDR + func);
++}
++
++EXPORT_SYMBOL(gpio_set);
++EXPORT_SYMBOL(gpio_get);
++EXPORT_SYMBOL(set434Reg);
++EXPORT_SYMBOL(changeLatchU5);
+diff -urN linux.old/arch/mips/rb500/prom.c linux.dev/arch/mips/rb500/prom.c
+--- linux.old/arch/mips/rb500/prom.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/rb500/prom.c 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,181 @@
++/*
++* prom.c
++**********************************************************************
++* P . Sadik Oct 10, 2003
++*
++* Started change log
++* idt_cpu_freq is make a kernel configuration parameter
++* idt_cpu_freq is exported so that other modules can use it.
++* Code cleanup
++**********************************************************************
++* P. Sadik Oct 20, 2003
++*
++* Removed NVRAM code from here, since they are already available under
++* nvram directory.
++* Added serial port initialisation.
++**********************************************************************
++**********************************************************************
++* P. Sadik Oct 30, 2003
++*
++* Added reset_cons_port
++**********************************************************************
++
++ P.Christeas, 2005-2006
++ Port to 2.6, add 2.6 cmdline parsing
++
++*/
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/console.h>
++#include <asm/bootinfo.h>
++#include <linux/bootmem.h>
++#include <linux/ioport.h>
++#include <linux/blkdev.h>
++#include <asm/rc32434/ddr.h>
++
++#define PROM_ENTRY(x) (0xbfc00000+((x)*8))
++extern void __init setup_serial_port(void);
++extern void cons_putc(char c);
++extern void cons_puts(char *s);
++
++unsigned int idt_cpu_freq = 132000000;
++EXPORT_SYMBOL(idt_cpu_freq);
++unsigned int board_type = 500;
++EXPORT_SYMBOL(board_type);
++unsigned int gpio_bootup_state = 0;
++EXPORT_SYMBOL(gpio_bootup_state);
++
++
++char mips_mac_address[18] = "08:00:06:05:40:01";
++EXPORT_SYMBOL(mips_mac_address);
++
++/* what to append to cmdline when button is [not] pressed */
++#define GPIO_INIT_NOBUTTON ""
++#define GPIO_INIT_BUTTON " 2"
++
++#ifdef CONFIG_MIKROTIK_RB500
++unsigned soft_reboot = 0;
++EXPORT_SYMBOL(soft_reboot);
++#endif
++
++#define SR_NMI 0x00180000 /* NMI */
++#define SERIAL_SPEED_ENTRY 0x00000001
++
++#ifdef CONFIG_REMOTE_DEBUG
++extern int remote_debug;
++#endif
++
++extern unsigned long mips_machgroup;
++extern unsigned long mips_machtype;
++
++#define FREQ_TAG "HZ="
++#define GPIO_TAG "gpio="
++#define KMAC_TAG "kmac="
++#define MEM_TAG "mem="
++#define BOARD_TAG "board="
++#define IGNORE_CMDLINE_MEM 1
++#define DEBUG_DDR
++
++void parse_soft_settings(unsigned *ptr, unsigned size);
++void parse_hard_settings(unsigned *ptr, unsigned size);
++
++void __init prom_setup_cmdline(void);
++
++#ifdef DEBUG_DDR
++void cons_puthex4(u32 h){
++ h&=0x0f;
++ if (h>=10)
++ cons_putc((h-10)+'a');
++ else
++ cons_putc(h+'0');
++}
++
++void cons_putreg32(u32 reg){
++ char c;
++ cons_putc('0');
++ cons_putc('x');
++ for (c=28;c>=0;c-=4)
++ cons_puthex4(reg>>c);
++}
++#endif
++
++void __init prom_init(void)
++{
++ DDR_t ddr = (DDR_t) DDR_VirtualAddress; /* define the pointer to the DDR registers */
++ phys_t memsize = 0-ddr->ddrmask;
++
++ /* this should be the very first message, even before serial is properly initialized */
++ prom_setup_cmdline();
++ setup_serial_port();
++
++ mips_machgroup = MACH_GROUP_MIKROTIK;
++ soft_reboot = read_c0_status() & SR_NMI;
++ pm_power_off = NULL;
++
++ /*
++ * give all RAM to boot allocator,
++ * except for the first 0x400 and the last 0x200 bytes
++ */
++ add_memory_region(ddr->ddrbase + 0x400, memsize - 0x600, BOOT_MEM_RAM);
++}
++
++void prom_free_prom_memory(void)
++{
++ /* FIXME: STUB */
++}
++
++void __init prom_setup_cmdline(void){
++ char cmd_line[CL_SIZE];
++ char *cp;
++ int prom_argc;
++ char **prom_argv, **prom_envp;
++ int i;
++
++ prom_argc = fw_arg0;
++ prom_argv = (char **) fw_arg1;
++ prom_envp = (char **) fw_arg2;
++
++ cp=cmd_line;
++ /* Note: it is common that parameters start at argv[1] and not argv[0],
++ however, our elf loader starts at [0] */
++ for(i=0;i<prom_argc;i++){
++ if (strncmp(prom_argv[i], FREQ_TAG, sizeof(FREQ_TAG) - 1) == 0) {
++ idt_cpu_freq = simple_strtoul(prom_argv[i] + sizeof(FREQ_TAG) - 1, 0, 10);
++ continue;
++ }
++#ifdef IGNORE_CMDLINE_MEM
++ /* parses out the "mem=xx" arg */
++ if (strncmp(prom_argv[i], MEM_TAG, sizeof(MEM_TAG) - 1) == 0) {
++ continue;
++ }
++#endif
++ if (i>0) *(cp++) = ' ';
++ if (strncmp(prom_argv[i], BOARD_TAG, sizeof(BOARD_TAG) - 1) == 0) {
++ board_type = simple_strtoul(prom_argv[i] + sizeof(BOARD_TAG) - 1, 0, 10);
++ }
++ if (strncmp(prom_argv[i], GPIO_TAG, sizeof(GPIO_TAG) - 1) == 0) {
++ gpio_bootup_state = simple_strtoul(prom_argv[i] + sizeof(GPIO_TAG) - 1, 0, 10);
++ }
++ strcpy(cp,prom_argv[i]);
++ cp+=strlen(prom_argv[i]);
++ }
++
++ i=strlen(arcs_cmdline);
++ if (i>0){
++ *(cp++) = ' ';
++ strcpy(cp,arcs_cmdline);
++ cp+=strlen(arcs_cmdline);
++ }
++ if (gpio_bootup_state&0x02)
++ strcpy(cp,GPIO_INIT_NOBUTTON);
++ else
++ strcpy(cp,GPIO_INIT_BUTTON);
++ cmd_line[CL_SIZE-1] = '\0';
++
++ strcpy(arcs_cmdline,cmd_line);
++}
++
+diff -urN linux.old/arch/mips/rb500/serial.c linux.dev/arch/mips/rb500/serial.c
+--- linux.old/arch/mips/rb500/serial.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/rb500/serial.c 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,79 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Serial port initialisation.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/pci.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/serial.h>
++#include <linux/serial_core.h>
++
++#include <asm/time.h>
++#include <asm/cpu.h>
++#include <asm/bootinfo.h>
++#include <asm/irq.h>
++#include <asm/serial.h>
++#include <asm/rc32434/rc32434.h>
++
++extern unsigned int idt_cpu_freq;
++
++static struct uart_port serial_req = {
++ .type = PORT_16550A,
++ .line = 0,
++ .irq = RC32434_UART0_IRQ,
++ .flags = STD_COM_FLAGS,
++ .iotype = UPIO_MEM,
++ .membase = (char *) KSEG1ADDR(RC32434_UART0_BASE),
++// .fifosize = 14
++ .regshift = 2
++};
++
++int __init setup_serial_port(void)
++{
++ serial_req.uartclk = idt_cpu_freq;
++
++ if (early_serial_setup(&serial_req)){
++ cons_puts("Serial setup failed!\n");
++ return -ENODEV;
++ }
++
++ return(0);
++}
+diff -urN linux.old/arch/mips/rb500/setup.c linux.dev/arch/mips/rb500/setup.c
+--- linux.old/arch/mips/rb500/setup.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/rb500/setup.c 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,84 @@
++/*
++ * setup.c - boot time setup code
++ */
++
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/irq.h>
++#include <asm/bootinfo.h>
++#include <asm/io.h>
++#include <linux/ioport.h>
++#include <asm/mipsregs.h>
++#include <asm/pgtable.h>
++#include <asm/reboot.h>
++#include <asm/addrspace.h> /* for KSEG1ADDR() */
++#include <asm/rc32434/rc32434.h>
++#include <linux/pm.h>
++#include <asm/rc32434/pci.h>
++
++extern void (*board_time_init)(void);
++extern void (*board_timer_setup)(struct irqaction *irq);
++extern void rc32434_time_init(void);
++extern void rc32434_timer_setup(struct irqaction *irq);
++#ifdef CONFIG_PCI
++extern int __init rc32434_pcibridge_init(void);
++#endif
++
++#define epldMask ((volatile unsigned char *)0xB900000d)
++
++static void rb_machine_restart(char *command)
++{
++ /* just jump to the reset vector */
++ * (volatile unsigned *) KSEG1ADDR(0x18008000) = 0x80000001;
++ ((void (*)(void))KSEG1ADDR(0x1FC00000u))();
++}
++
++static void rb_machine_halt(void)
++{
++ for(;;) continue;
++}
++
++#ifdef CONFIG_CPU_HAS_WB
++void (*__wbflush) (void);
++
++static void rb_write_buffer_flush(void)
++{
++ __asm__ __volatile__
++ ("sync\n\t" "nop\n\t" "loop: bc0f loop\n\t" "nop\n\t");
++}
++#endif
++
++void __init plat_setup(void)
++{
++ unsigned int pciCntlVal;
++
++ board_time_init = rc32434_time_init;
++ board_timer_setup = rc32434_timer_setup;
++
++#ifdef CONFIG_CPU_HAS_WB
++ __wbflush = rb_write_buffer_flush;
++#endif
++ _machine_restart = rb_machine_restart;
++ _machine_halt = rb_machine_halt;
++ /*_machine_power_off = rb_machine_power_halt;*/
++ pm_power_off = rb_machine_halt;
++
++ set_io_port_base(KSEG1);
++
++ pciCntlVal=rc32434_pci->pcic;
++ pciCntlVal &= 0xFFFFFF7;
++ rc32434_pci->pcic = pciCntlVal;
++
++#ifdef CONFIG_PCI
++ /* Enable PCI interrupts in EPLD Mask register */
++ *epldMask = 0x0;
++ *(epldMask + 1) = 0x0;
++#endif
++ write_c0_wired(0);
++}
++
++const char *get_system_type(void)
++{
++ return "MIPS RB500";
++}
+diff -urN linux.old/arch/mips/rb500/time.c linux.dev/arch/mips/rb500/time.c
+--- linux.old/arch/mips/rb500/time.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/arch/mips/rb500/time.c 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,94 @@
++/*
++****************************************************************************
++* Carsten Langgaard, carstenl@mips.com
++* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
++*
++***************************************************************************
++*
++* This program is free software; you can distribute it and/or modify it
++* under the terms of the GNU General Public License (Version 2) as
++* published by the Free Software Foundation.
++*
++* This program is distributed in the hope 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.
++*
++****************************************************************************
++*
++* Setting up the clock on the MIPS boards.
++*
++****************************************************************************
++* P. Sadik Oct 10, 2003
++*
++* Started change log.
++* mips_counter_frequency is now calculated at run time, based on idt_cpu_freq.
++* Code cleanup
++****************************************************************************
++*/
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/kernel_stat.h>
++#include <linux/sched.h>
++#include <linux/spinlock.h>
++#include <linux/mc146818rtc.h>
++#include <linux/irq.h>
++#include <linux/timex.h>
++
++#include <asm/mipsregs.h>
++#include <asm/ptrace.h>
++#include <asm/debug.h>
++#include <asm/rc32434/rc32434.h>
++
++static unsigned long r4k_offset; /* Amount to incr compare reg each time */
++static unsigned long r4k_cur; /* What counter should be at next timer irq */
++extern void ll_timer_interrupt(int irq, struct pt_regs *regs);
++extern unsigned int mips_hpt_frequency;
++extern unsigned int idt_cpu_freq;
++
++/*
++ * Figure out the r4k offset, the amount to increment the compare
++ * register for each time tick. There is no RTC available.
++ *
++ * The RC32434 counts at half the CPU *core* speed.
++ */
++static unsigned long __init cal_r4koff(void)
++{
++ mips_hpt_frequency = idt_cpu_freq * IDT_CLOCK_MULT / 2;
++ return (mips_hpt_frequency / HZ);
++}
++
++
++void __init rc32434_time_init(void)
++{
++ unsigned int est_freq, flags;
++
++ local_irq_save(flags);
++
++ printk("calculating r4koff... ");
++ r4k_offset = cal_r4koff();
++ printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
++
++ est_freq = 2*r4k_offset*HZ;
++ est_freq += 5000; /* round */
++ est_freq -= est_freq%10000;
++ printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
++ (est_freq%1000000)*100/1000000);
++ local_irq_restore(flags);
++}
++
++void __init rc32434_timer_setup(struct irqaction *irq)
++{
++ /* we are using the cpu counter for timer interrupts */
++ setup_irq(MIPS_CPU_TIMER_IRQ, irq);
++
++ /* to generate the first timer interrupt */
++ r4k_cur = (read_c0_count() + r4k_offset);
++ write_c0_compare(r4k_cur);
++}
++
+diff -urN linux.old/drivers/mtd/devices/block2mtd.c linux.dev/drivers/mtd/devices/block2mtd.c
+--- linux.old/drivers/mtd/devices/block2mtd.c 2006-10-11 21:55:59.000000000 +0200
++++ linux.dev/drivers/mtd/devices/block2mtd.c 2006-10-11 22:24:51.000000000 +0200
+@@ -26,7 +26,6 @@
+ #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args)
+ #define INFO(fmt, args...) printk(KERN_INFO "block2mtd: " fmt "\n" , ## args)
+
+-
+ /* Info for the block device */
+ struct block2mtd_dev {
+ struct list_head list;
+@@ -104,7 +103,7 @@
+
+ while (pages) {
+ page = page_readahead(mapping, index);
+- if (!page)
++ if (!page || !page_address(page))
+ return -ENOMEM;
+ if (IS_ERR(page))
+ return PTR_ERR(page);
+@@ -285,7 +284,7 @@
+
+
+ /* FIXME: ensure that mtd->size % erase_size == 0 */
+-static struct block2mtd_dev *add_device(char *devname, int erase_size)
++static struct block2mtd_dev *add_device(char *devname, int erase_size, char *alias)
+ {
+ struct block_device *bdev;
+ struct block2mtd_dev *dev;
+@@ -328,14 +327,15 @@
+
+ /* Setup the MTD structure */
+ /* make the name contain the block device in */
+- dev->mtd.name = kmalloc(sizeof("block2mtd: ") + strlen(devname),
++ dev->mtd.name = kmalloc(strlen((alias ?: devname)),
+ GFP_KERNEL);
+ if (!dev->mtd.name)
+ goto devinit_err;
+
+- sprintf(dev->mtd.name, "block2mtd: %s", devname);
++ strcpy(dev->mtd.name, (alias ?: devname));
+
+ dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
++ dev->mtd.size -= dev->mtd.size % erase_size;
+ dev->mtd.erasesize = erase_size;
+ dev->mtd.type = MTD_RAM;
+ dev->mtd.flags = MTD_CAP_RAM;
+@@ -353,7 +353,7 @@
+ }
+ list_add(&dev->list, &blkmtd_device_list);
+ INFO("mtd%d: [%s] erase_size = %dKiB [%d]", dev->mtd.index,
+- dev->mtd.name + strlen("blkmtd: "),
++ dev->mtd.name,
+ dev->mtd.erasesize >> 10, dev->mtd.erasesize);
+ return dev;
+
+@@ -429,7 +429,7 @@
+ {
+ char buf[80 + 12]; /* 80 for device, 12 for erase size */
+ char *str = buf;
+- char *token[2];
++ char *token[3];
+ char *name;
+ size_t erase_size = PAGE_SIZE;
+ int i, ret;
+@@ -440,7 +440,7 @@
+ strcpy(str, val);
+ kill_final_newline(str);
+
+- for (i = 0; i < 2; i++)
++ for (i = 0; i < 3; i++)
+ token[i] = strsep(&str, ",");
+
+ if (str)
+@@ -461,13 +461,13 @@
+ }
+ }
+
+- add_device(name, erase_size);
++ add_device(name, erase_size, token[2]);
+
+ return 0;
+ }
+
+
+-static int block2mtd_setup(const char *val, struct kernel_param *kp)
++int block2mtd_setup(const char *val, struct kernel_param *kp)
+ {
+ #ifdef MODULE
+ return block2mtd_setup2(val);
+@@ -496,6 +496,7 @@
+
+ module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
+ MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>]\"");
++EXPORT_SYMBOL(block2mtd_setup);
+
+ static int __init block2mtd_init(void)
+ {
+diff -urN linux.old/drivers/pci/Makefile linux.dev/drivers/pci/Makefile
+--- linux.old/drivers/pci/Makefile 2006-06-18 03:49:35.000000000 +0200
++++ linux.dev/drivers/pci/Makefile 2006-10-11 21:56:38.000000000 +0200
+@@ -27,6 +27,7 @@
+ obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
+ obj-$(CONFIG_X86_VISWS) += setup-irq.o
+ obj-$(CONFIG_PCI_MSI) += msi.o
++obj-$(CONFIG_MIKROTIK_RB500) += setup-irq.o
+
+ #
+ # ACPI Related PCI FW Functions
+diff -urN linux.old/include/asm-mips/bootinfo.h linux.dev/include/asm-mips/bootinfo.h
+--- linux.old/include/asm-mips/bootinfo.h 2006-06-18 03:49:35.000000000 +0200
++++ linux.dev/include/asm-mips/bootinfo.h 2006-10-11 21:56:38.000000000 +0200
+@@ -218,6 +218,8 @@
+ #define MACH_GROUP_TITAN 22 /* PMC-Sierra Titan */
+ #define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */
+
++#define MACH_GROUP_MIKROTIK 24 /* Mikrotik Boards */
++
+ #define CL_SIZE COMMAND_LINE_SIZE
+
+ const char *get_system_type(void);
+diff -urN linux.old/include/asm-mips/cpu.h linux.dev/include/asm-mips/cpu.h
+--- linux.old/include/asm-mips/cpu.h 2006-06-18 03:49:35.000000000 +0200
++++ linux.dev/include/asm-mips/cpu.h 2006-10-11 21:56:38.000000000 +0200
+@@ -200,7 +200,8 @@
+ #define CPU_SB1A 62
+ #define CPU_74K 63
+ #define CPU_R14000 64
+-#define CPU_LAST 64
++#define CPU_RC32300 65
++#define CPU_LAST 65
+
+ /*
+ * ISA Level encodings
+diff -urN linux.old/include/asm-mips/rc32434/crom.h linux.dev/include/asm-mips/rc32434/crom.h
+--- linux.old/include/asm-mips/rc32434/crom.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/crom.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,98 @@
++#ifndef __IDT_CROM_H__
++#define __IDT_CROM_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * Configuration ROM register definitions.
++ *
++ * File : $Id: crom.h,v 1.2 2002/06/06 18:34:03 astichte Exp $
++ *
++ * Author : Allen.Stichter@idt.com
++ * Date : 20020118
++ * Update :
++ * $Log: crom.h,v $
++ * Revision 1.2 2002/06/06 18:34:03 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.1 2002/05/29 17:33:21 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ *
++ ******************************************************************************/
++
++#include <asm/rc32434/types.h>
++
++enum
++{
++ CROM0_PhysicalAddress = 0x100b8000,
++ CROM_PhysicalAddress = CROM0_PhysicalAddress,
++
++ CROM0_VirtualAddress = 0xb00b8000,
++ CROM_VirtualAddress = CROM0_VirtualAddress,
++} ;
++
++typedef struct CROM_s
++{
++ U32 cromw0 ; // use CROMW0_
++ U32 cromw1 ; // use CROMW1_
++ U32 cromw2 ; // use CROMW2_
++} volatile * CROM_t ;
++
++enum
++{
++ CROMW0_xloc_b = 0,
++ CROMW0_xloc_m = 0x0000003f,
++ CROMW0_yloc_b = 8,
++ CROMW0_yloc_m = 0x00003f00,
++ CROMW0_speed_b = 16,
++ CROMW0_speed_m = 0x01ff0000,
++ CROMW1_wafer_b = 0,
++ CROMW1_wafer_m = 0x0000001f,
++ CROMW1_lot_b = 8,
++ CROMW1_lot_m = 0x0fffff00,
++ CROMW1_fab_b = 28,
++ CROMW1_fab_m = 0xf0000000,
++ CROMW2_pci_b = 0,
++ CROMW2_pci_m = 0x00000001,
++ CROMW2_eth0_b = 1,
++ CROMW2_eth0_m = 0x00000002,
++ CROMW2_eth1_b = 2,
++ CROMW2_eth1_m = 0x00000004
++ CROMW2_i2c_b = 3,
++ CROMW2_i2c_m = 0x00000008,
++ CROMW2_rng_b = 4,
++ CROMW2_rng_m = 0x00000010,
++ CROMW2_se_b = 5,
++ CROMW2_se_m = 0x00000020,
++ CROMW2_des_b = 6,
++ CROMW2_des_m = 0x00000040,
++ CROMW2_tdes_b = 7,
++ CROMW2_tdes_m = 0x00000080,
++ CROMW2_a128_b = 8,
++ CROMW2_a128_m = 0x00000100,
++ CROMW2_a192_b = 9,
++ CROMW2_a192_m = 0x00000200,
++ CROMW2_a256_b = 10,
++ CROMW2_a256_m = 0x00000400,
++ CROMW2_md5_b = 11,
++ CROMW2_md5_m = 0x00000800,
++ CROMW2_s1_b = 12,
++ CROMW2_s1_m = 0x00001000,
++ CROMW2_s256_b = 13,
++ CROMW2_s256_m = 0x00002000,
++ CROMW2_pka_b = 14,
++ CROMW2_pka_m = 0x00004000,
++ CROMW2_exp_b = 15,
++ CROMW2_exp_m = 0x00018000,
++ CROMW2_exp_8192_v = 0,
++ CROMW2_exp_1536_v = 1,
++ CROMW2_exp_1024_v = 2,
++ CROMW2_exp_512_v = 3,
++ CROMW2_rocfg_b = 17,
++ CROMW2_rocfg_m = 0x000e0000,
++} ;
++
++#endif // __IDT_CROM_H__
+diff -urN linux.old/include/asm-mips/rc32434/ddr.h linux.dev/include/asm-mips/rc32434/ddr.h
+--- linux.old/include/asm-mips/rc32434/ddr.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/ddr.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,175 @@
++#ifndef __IDT_DDR_H__
++#define __IDT_DDR_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * DDR register definition.
++ *
++ * File : $Id: ddr.h,v 1.2 2002/06/06 18:34:03 astichte Exp $
++ *
++ * Author : ryan.holmQVist@idt.com
++ * Date : 20011005
++ * Update :
++ * $Log: ddr.h,v $
++ * Revision 1.2 2002/06/06 18:34:03 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.1 2002/05/29 17:33:21 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ *
++ ******************************************************************************/
++
++#include <asm/rc32434/types.h>
++
++enum
++{
++ DDR0_PhysicalAddress = 0x18018000,
++ DDR_PhysicalAddress = DDR0_PhysicalAddress, // Default
++
++ DDR0_VirtualAddress = 0xb8018000,
++ DDR_VirtualAddress = DDR0_VirtualAddress, // Default
++} ;
++
++typedef struct DDR_s
++{
++ U32 ddrbase ;
++ U32 ddrmask ;
++ U32 res1;
++ U32 res2;
++ U32 ddrc ;
++ U32 ddrabase ;
++ U32 ddramask ;
++ U32 ddramap ;
++ U32 ddrcust;
++ U32 ddrrdc;
++ U32 ddrspare;
++} volatile *DDR_t ;
++
++enum
++{
++ DDR0BASE_baseaddr_b = 16,
++ DDR0BASE_baseaddr_m = 0xffff0000,
++
++ DDR0MASK_mask_b = 16,
++ DDR0MASK_mask_m = 0xffff0000,
++
++ DDR1BASE_baseaddr_b = 16,
++ DDR1BASE_baseaddr_m = 0xffff0000,
++
++ DDR1MASK_mask_b = 16,
++ DDR1MASK_mask_m = 0xffff0000,
++
++ DDRC_ata_b = 5,
++ DDRC_ata_m = 0x000000E0,
++ DDRC_dbw_b = 8,
++ DDRC_dbw_m = 0x00000100,
++ DDRC_wr_b = 9,
++ DDRC_wr_m = 0x00000600,
++ DDRC_ps_b = 11,
++ DDRC_ps_m = 0x00001800,
++ DDRC_dtype_b = 13,
++ DDRC_dtype_m = 0x0000e000,
++ DDRC_rfc_b = 16,
++ DDRC_rfc_m = 0x000f0000,
++ DDRC_rp_b = 20,
++ DDRC_rp_m = 0x00300000,
++ DDRC_ap_b = 22,
++ DDRC_ap_m = 0x00400000,
++ DDRC_rcd_b = 23,
++ DDRC_rcd_m = 0x01800000,
++ DDRC_cl_b = 25,
++ DDRC_cl_m = 0x06000000,
++ DDRC_dbm_b = 27,
++ DDRC_dbm_m = 0x08000000,
++ DDRC_sds_b = 28,
++ DDRC_sds_m = 0x10000000,
++ DDRC_atp_b = 29,
++ DDRC_atp_m = 0x60000000,
++ DDRC_re_b = 31,
++ DDRC_re_m = 0x80000000,
++
++ DDRRDC_ces_b = 0,
++ DDRRDC_ces_m = 0x00000001,
++ DDRRDC_ace_b = 1,
++ DDRRDC_ace_m = 0x00000002,
++
++ DDRABASE_baseaddr_b = 16,
++ DDRABASE_baseaddr_m = 0xffff0000,
++
++ DDRAMASK_mask_b = 16,
++ DDRAMASK_mask_m = 0xffff0000,
++
++ DDRAMAP_map_b = 16,
++ DDRAMAP_map_m = 0xffff0000,
++
++ DDRCUST_cs_b = 0,
++ DDRCUST_cs_m = 0x00000003,
++ DDRCUST_we_b = 2,
++ DDRCUST_we_m = 0x00000004,
++ DDRCUST_ras_b = 3,
++ DDRCUST_ras_m = 0x00000008,
++ DDRCUST_cas_b = 4,
++ DDRCUST_cas_m = 0x00000010,
++ DDRCUST_cke_b = 5,
++ DDRCUST_cke_m = 0x00000020,
++ DDRCUST_ba_b = 6,
++ DDRCUST_ba_m = 0x000000c0,
++
++ RCOUNT_rcount_b = 0,
++ RCOUNT_rcount_m = 0x0000ffff,
++
++ RCOMPARE_rcompare_b = 0,
++ RCOMPARE_rcompare_m = 0x0000ffff,
++
++ RTC_ce_b = 0,
++ RTC_ce_m = 0x00000001,
++ RTC_to_b = 1,
++ RTC_to_m = 0x00000002,
++ RTC_rqe_b = 2,
++ RTC_rqe_m = 0x00000004,
++
++ DDRDQSC_dm_b = 0,
++ DDRDQSC_dm_m = 0x00000003,
++ DDRDQSC_dqsbs_b = 2,
++ DDRDQSC_dqsbs_m = 0x000000fc,
++ DDRDQSC_db_b = 8,
++ DDRDQSC_db_m = 0x00000100,
++ DDRDQSC_dbsp_b = 9,
++ DDRDQSC_dbsp_m = 0x01fffe00,
++ DDRDQSC_bdp_b = 25,
++ DDRDQSC_bdp_m = 0x7e000000,
++
++ DDRDLLC_eao_b = 0,
++ DDRDLLC_eao_m = 0x00000001,
++ DDRDLLC_eo_b = 1,
++ DDRDLLC_eo_m = 0x0000003e,
++ DDRDLLC_fs_b = 6,
++ DDRDLLC_fs_m = 0x000000c0,
++ DDRDLLC_as_b = 8,
++ DDRDLLC_as_m = 0x00000700,
++ DDRDLLC_sp_b = 11,
++ DDRDLLC_sp_m = 0x001ff800,
++
++ DDRDLLFC_men_b = 0,
++ DDRDLLFC_men_m = 0x00000001,
++ DDRDLLFC_aen_b = 1,
++ DDRDLLFC_aen_m = 0x00000002,
++ DDRDLLFC_ff_b = 2,
++ DDRDLLFC_ff_m = 0x00000004,
++
++ DDRDLLTA_addr_b = 2,
++ DDRDLLTA_addr_m = 0xfffffffc,
++
++ DDRDLLED_dbe_b = 0,
++ DDRDLLED_dbe_m = 0x00000001,
++ DDRDLLED_dte_b = 1,
++ DDRDLLED_dte_m = 0x00000002,
++
++
++} ;
++
++#endif // __IDT_DDR_H__
+diff -urN linux.old/include/asm-mips/rc32434/dev.h linux.dev/include/asm-mips/rc32434/dev.h
+--- linux.old/include/asm-mips/rc32434/dev.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/dev.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,134 @@
++#ifndef __IDT_DEV_H__
++#define __IDT_DEV_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * Device Controller register definition.
++ *
++ * File : $Id: dev.h,v 1.2 2002/06/06 18:34:03 astichte Exp $
++ *
++ * Author : John.Ahrens@idt.com
++ * Date : 200112013
++ * Update :
++ * $Log: dev.h,v $
++ * Revision 1.2 2002/06/06 18:34:03 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.1 2002/05/29 17:33:21 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ *
++ ******************************************************************************/
++
++#include <asm/rc32434/types.h>
++
++enum
++{
++ DEV0_PhysicalAddress = 0x18010000,
++ DEV_PhysicalAddress = DEV0_PhysicalAddress, // Default
++
++ DEV0_VirtualAddress = 0xb8010000,
++ DEV_VirtualAddress = DEV0_VirtualAddress, // Default
++} ;
++
++typedef struct DEVICE_s
++{
++ U32 devbase ; // Device Base
++ U32 devmask ; // Device Mask
++ U32 devc ; // Device Control
++ U32 devtc ; // Device Timing Control
++} volatile *DEVICE_t ;
++
++enum
++{
++ DEV_Count = 3,
++} ;
++
++typedef struct DEV_s
++{
++ struct DEVICE_s dev [DEV_Count] ;
++ U32 btcs ; // Bus timeout control / status
++ U32 btcompare ; // Compare
++ U32 btaddr ; // Timeout address.
++ U32 devdacs ; // Decoupled access control.
++ U32 devdaa ; // Decoupled access address.
++ U32 devdad ; // Decoupled access address.
++ U32 devspare ; // spare.
++} volatile *DEV_t ;
++
++enum
++{
++ DEVBASE_baseaddr_b = 16,
++ DEVBASE_baseaddr_m = 0xffff0000,
++ DEVMASK_mask_b = 16,
++ DEVMASK_mask_m = 0xffff0000,
++
++ DEVC_ds_b = 0,
++ DEVC_ds_m = 0x00000003,
++ DEVC_ds_8_v = 0, // 8-bit device.
++ DEVC_ds_16_v = 1, // reserved
++ DEVC_ds_res_v = 2, // reserved.
++ DEVC_ds_res2_v = 3, // reserved.
++ DEVC_be_b = 2,
++ DEVC_be_m = 0x00000004,
++ DEVC_wp_b = 3,
++ DEVC_wp_m = 0x00000008,
++ DEVC_csd_b = 4,
++ DEVC_csd_m = 0x000000f0,
++ DEVC_oed_b = 8,
++ DEVC_oed_m = 0x00000f00,
++ DEVC_bwd_b = 12,
++ DEVC_bwd_m = 0x0000f000,
++ DEVC_rws_b = 16,
++ DEVC_rws_m = 0x003f0000,
++ DEVC_wws_b = 22,
++ DEVC_wws_m = 0x0fc00000,
++ DEVC_bre_b = 28,
++ DEVC_bre_m = 0x10000000,
++ DEVC_bwe_b = 29,
++ DEVC_bwe_m = 0x20000000,
++ DEVC_wam_b = 30,
++ DEVC_wam_m = 0x40000000,
++
++ DEVTC_prd_b = 0,
++ DEVTC_prd_m = 0x0000000f,
++ DEVTC_pwd_b = 4,
++ DEVTC_pwd_m = 0x000000f0,
++ DEVTC_wdh_b = 8,
++ DEVTC_wdh_m = 0x00000700,
++ DEVTC_csh_b = 11,
++ DEVTC_csh_m = 0x00001800,
++
++ BTCS_tt_b = 0,
++ BTCS_tt_m = 0x00000001,
++ BTCS_tt_write = 0,
++ BTCS_tt_read = 1,
++ BTCS_bto_b = 1, // In btcs
++ BTCS_bto_m = 0x00000002, // In btcs
++ BTCS_bte_b = 2, // In btcs
++ BTCS_bte_m = 0x00000004, // In btcs
++
++ BTCOMPARE_compare_b = 0, // In btcompare
++ BTCOMPARE_compare_m = 0x0000ffff, // In btcompare
++
++ DEVDACS_op_b = 0, // In devdacs
++ DEVDACS_op_m = 0x00000001, // In devdacs
++ DEVDACS_op_write_v = 0,
++ DEVDACS_op_read_v = 1,
++ DEVDACS_size_b = 1, // In devdacs
++ DEVDACS_size_m = 0x00000006, // In devdacs
++ DEVDACS_size_byte_v = 0,
++ DEVDACS_size_halfword = 1,
++ DEVDACS_size_triplebyte = 2,
++ DEVDACS_size_word = 3,
++ DEVDACS_err_b = 3, // In devdacs
++ DEVDACS_err_m = 0x00000008, // In devdacs
++ DEVDACS_f_b = 4, // In devdacs
++ DEVDACS_f_m = 0x00000010, // In devdacs
++} ;
++
++#endif //__IDT_DEV_H__
++
+diff -urN linux.old/include/asm-mips/rc32434/dma.h linux.dev/include/asm-mips/rc32434/dma.h
+--- linux.old/include/asm-mips/rc32434/dma.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/dma.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,202 @@
++#ifndef __IDT_DMA_H__
++#define __IDT_DMA_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * DMA register definition.
++ *
++ * File : $Id: dma.h,v 1.3 2002/06/06 18:34:03 astichte Exp $
++ *
++ * Author : ryan.holmQVist@idt.com
++ * Date : 20011005
++ * Update :
++ * $Log: dma.h,v $
++ * Revision 1.3 2002/06/06 18:34:03 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.2 2002/06/05 18:30:46 astichte
++ * Removed IDTField
++ *
++ * Revision 1.1 2002/05/29 17:33:21 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ *
++ ******************************************************************************/
++
++#include <asm/rc32434/types.h>
++enum
++{
++ DMA0_PhysicalAddress = 0x18040000,
++ DMA_PhysicalAddress = DMA0_PhysicalAddress, // Default
++
++ DMA0_VirtualAddress = 0xb8040000,
++ DMA_VirtualAddress = DMA0_VirtualAddress, // Default
++} ;
++
++/*
++ * DMA descriptor (in physical memory).
++ */
++
++typedef struct DMAD_s
++{
++ U32 control ; // Control. use DMAD_*
++ U32 ca ; // Current Address.
++ U32 devcs ; // Device control and status.
++ U32 link ; // Next descriptor in chain.
++} volatile *DMAD_t ;
++
++enum
++{
++ DMAD_size = sizeof (struct DMAD_s),
++ DMAD_count_b = 0, // in DMAD_t -> control
++ DMAD_count_m = 0x0003ffff, // in DMAD_t -> control
++ DMAD_ds_b = 20, // in DMAD_t -> control
++ DMAD_ds_m = 0x00300000, // in DMAD_t -> control
++ DMAD_ds_ethRcv_v = 0,
++ DMAD_ds_ethXmt_v = 0,
++ DMAD_ds_memToFifo_v = 0,
++ DMAD_ds_fifoToMem_v = 0,
++ DMAD_ds_pciToMem_v = 0,
++ DMAD_ds_memToPci_v = 0,
++
++ DMAD_devcmd_b = 22, // in DMAD_t -> control
++ DMAD_devcmd_m = 0x01c00000, // in DMAD_t -> control
++ DMAD_devcmd_byte_v = 0, //memory-to-memory
++ DMAD_devcmd_halfword_v = 1, //memory-to-memory
++ DMAD_devcmd_word_v = 2, //memory-to-memory
++ DMAD_devcmd_2words_v = 3, //memory-to-memory
++ DMAD_devcmd_4words_v = 4, //memory-to-memory
++ DMAD_devcmd_6words_v = 5, //memory-to-memory
++ DMAD_devcmd_8words_v = 6, //memory-to-memory
++ DMAD_devcmd_16words_v = 7, //memory-to-memory
++ DMAD_cof_b = 25, // chain on finished
++ DMAD_cof_m = 0x02000000, //
++ DMAD_cod_b = 26, // chain on done
++ DMAD_cod_m = 0x04000000, //
++ DMAD_iof_b = 27, // interrupt on finished
++ DMAD_iof_m = 0x08000000, //
++ DMAD_iod_b = 28, // interrupt on done
++ DMAD_iod_m = 0x10000000, //
++ DMAD_t_b = 29, // terminated
++ DMAD_t_m = 0x20000000, //
++ DMAD_d_b = 30, // done
++ DMAD_d_m = 0x40000000, //
++ DMAD_f_b = 31, // finished
++ DMAD_f_m = 0x80000000, //
++} ;
++
++/*
++ * DMA register (within Internal Register Map).
++ */
++
++struct DMA_Chan_s
++{
++ U32 dmac ; // Control.
++ U32 dmas ; // Status.
++ U32 dmasm ; // Mask.
++ U32 dmadptr ; // Descriptor pointer.
++ U32 dmandptr ; // Next descriptor pointer.
++};
++
++typedef struct DMA_Chan_s volatile *DMA_Chan_t ;
++
++//DMA_Channels use DMACH_count instead
++
++enum
++{
++ DMAC_run_b = 0, //
++ DMAC_run_m = 0x00000001, //
++ DMAC_dm_b = 1, // done mask
++ DMAC_dm_m = 0x00000002, //
++ DMAC_mode_b = 2, //
++ DMAC_mode_m = 0x0000000c, //
++ DMAC_mode_auto_v = 0,
++ DMAC_mode_burst_v = 1,
++ DMAC_mode_transfer_v = 2, //usually used
++ DMAC_mode_reserved_v = 3,
++ DMAC_a_b = 4, //
++ DMAC_a_m = 0x00000010, //
++
++ DMAS_f_b = 0, // finished (sticky)
++ DMAS_f_m = 0x00000001, //
++ DMAS_d_b = 1, // done (sticky)
++ DMAS_d_m = 0x00000002, //
++ DMAS_c_b = 2, // chain (sticky)
++ DMAS_c_m = 0x00000004, //
++ DMAS_e_b = 3, // error (sticky)
++ DMAS_e_m = 0x00000008, //
++ DMAS_h_b = 4, // halt (sticky)
++ DMAS_h_m = 0x00000010, //
++
++ DMASM_f_b = 0, // finished (1=mask)
++ DMASM_f_m = 0x00000001, //
++ DMASM_d_b = 1, // done (1=mask)
++ DMASM_d_m = 0x00000002, //
++ DMASM_c_b = 2, // chain (1=mask)
++ DMASM_c_m = 0x00000004, //
++ DMASM_e_b = 3, // error (1=mask)
++ DMASM_e_m = 0x00000008, //
++ DMASM_h_b = 4, // halt (1=mask)
++ DMASM_h_m = 0x00000010, //
++} ;
++
++/*
++ * DMA channel definitions
++ */
++
++enum
++{
++ DMACH_ethRcv = 0,
++ DMACH_ethXmt = 1,
++ DMACH_memToFifo = 2,
++ DMACH_fifoToMem = 3,
++ DMACH_pciToMem = 4,
++ DMACH_memToPci = 5,
++
++ DMACH_count //must be last
++};
++
++
++typedef struct DMAC_s
++{
++ struct DMA_Chan_s ch [DMACH_count] ; //use ch[DMACH_]
++} volatile *DMA_t ;
++
++
++/*
++ * External DMA parameters
++*/
++#if 0
++enum
++{
++ DMADEVCMD_ts_b = 0, // ts field in devcmd
++ DMADEVCMD_ts_m = 0x00000007, // ts field in devcmd
++ DMADEVCMD_ts_byte_v = 0,
++ DMADEVCMD_ts_halfword_v = 1,
++ DMADEVCMD_ts_word_v = 2,
++ DMADEVCMD_ts_2word_v = 3,
++ DMADEVCMD_ts_4word_v = 4,
++ DMADEVCMD_ts_6word_v = 5,
++ DMADEVCMD_ts_8word_v = 6,
++ DMADEVCMD_ts_16word_v = 7
++};
++#endif
++
++#if 1 // aws - Compatibility.
++# define EXTDMA_ts_b DMADEVCMD_ts_b
++# define EXTDMA_ts_m DMADEVCMD_ts_m
++# define EXTDMA_ts_byte_v DMADEVCMD_ts_byte_v
++# define EXTDMA_ts_halfword_v DMADEVCMD_ts_halfword_v
++# define EXTDMA_ts_word_v DMADEVCMD_ts_word_v
++# define EXTDMA_ts_2word_v DMADEVCMD_ts_2word_v
++# define EXTDMA_ts_4word_v DMADEVCMD_ts_4word_v
++# define EXTDMA_ts_6word_v DMADEVCMD_ts_6word_v
++# define EXTDMA_ts_8word_v DMADEVCMD_ts_8word_v
++# define EXTDMA_ts_16word_v DMADEVCMD_ts_16word_v
++#endif // aws - Compatibility.
++
++#endif // __IDT_DMA_H__
++
+diff -urN linux.old/include/asm-mips/rc32434/dma_v.h linux.dev/include/asm-mips/rc32434/dma_v.h
+--- linux.old/include/asm-mips/rc32434/dma_v.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/dma_v.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,73 @@
++#ifndef __IDT_DMA_V_H__
++#define __IDT_DMA_V_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * DMA register definition.
++ *
++ * File : $Id: dma.h,v 1.3 2002/06/06 18:34:03 astichte Exp $
++ *
++ * Author : ryan.holmQVist@idt.com
++ * Date : 20011005
++ * Update :
++ * $Log: dma.h,v $
++ * Revision 1.3 2002/06/06 18:34:03 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.2 2002/06/05 18:30:46 astichte
++ * Removed IDTField
++ *
++ * Revision 1.1 2002/05/29 17:33:21 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ *
++ ******************************************************************************/
++#include <asm/rc32434/types.h>
++#include <asm/rc32434/dma.h>
++#include <asm/rc32434/rc32434.h>
++#define DMA_CHAN_OFFSET 0x14
++#define IS_DMA_USED(X) (((X) & (DMAD_f_m | DMAD_d_m | DMAD_t_m)) != 0)
++#define DMA_COUNT(count) \
++ ((count) & DMAD_count_m)
++
++#define DMA_HALT_TIMEOUT 500
++
++
++static inline int rc32434_halt_dma(DMA_Chan_t ch)
++{
++ int timeout=1;
++ if (local_readl(&ch->dmac) & DMAC_run_m) {
++ local_writel(0, &ch->dmac);
++ for (timeout = DMA_HALT_TIMEOUT; timeout > 0; timeout--) {
++ if (local_readl(&ch->dmas) & DMAS_h_m) {
++ local_writel(0, &ch->dmas);
++ break;
++ }
++ }
++ }
++
++ return timeout ? 0 : 1;
++}
++
++static inline void rc32434_start_dma(DMA_Chan_t ch, u32 dma_addr)
++{
++ local_writel(0, &ch->dmandptr);
++ local_writel(dma_addr, &ch->dmadptr);
++}
++
++static inline void rc32434_chain_dma(DMA_Chan_t ch, u32 dma_addr)
++{
++ local_writel(dma_addr, &ch->dmandptr);
++}
++
++#endif // __IDT_DMA_V_H__
++
++
++
++
++
++
++
+diff -urN linux.old/include/asm-mips/rc32434/eth.h linux.dev/include/asm-mips/rc32434/eth.h
+--- linux.old/include/asm-mips/rc32434/eth.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/eth.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,322 @@
++#ifndef __IDT_ETH_H__
++#define __IDT_ETH_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * Ethernet register definition.
++ *
++ * File : $Id: eth.h,v 1.3 2002/06/06 18:34:04 astichte Exp $
++ *
++ * Author : Allen.Stichter@idt.com
++ * Date : 20020605
++ * Update :
++ * $Log: eth.h,v $
++ * Revision 1.3 2002/06/06 18:34:04 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.2 2002/06/05 18:19:46 astichte
++ * Added
++ *
++ * Revision 1.1 2002/05/29 17:33:22 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ ******************************************************************************/
++
++#include <asm/rc32434/types.h>
++
++enum
++{
++ ETH0_PhysicalAddress = 0x18060000,
++ ETH_PhysicalAddress = ETH0_PhysicalAddress, // Default
++
++ ETH0_VirtualAddress = 0xb8060000,
++ ETH_VirtualAddress = ETH0_VirtualAddress, // Default
++} ;
++
++typedef struct
++{
++ U32 ethintfc ;
++ U32 ethfifott ;
++ U32 etharc ;
++ U32 ethhash0 ;
++ U32 ethhash1 ;
++ U32 ethu0 [4] ; // Reserved.
++ U32 ethpfs ;
++ U32 ethmcp ;
++ U32 eth_u1 [10] ; // Reserved.
++ U32 ethspare ;
++ U32 eth_u2 [42] ; // Reserved.
++ U32 ethsal0 ;
++ U32 ethsah0 ;
++ U32 ethsal1 ;
++ U32 ethsah1 ;
++ U32 ethsal2 ;
++ U32 ethsah2 ;
++ U32 ethsal3 ;
++ U32 ethsah3 ;
++ U32 ethrbc ;
++ U32 ethrpc ;
++ U32 ethrupc ;
++ U32 ethrfc ;
++ U32 ethtbc ;
++ U32 ethgpf ;
++ U32 eth_u9 [50] ; // Reserved.
++ U32 ethmac1 ;
++ U32 ethmac2 ;
++ U32 ethipgt ;
++ U32 ethipgr ;
++ U32 ethclrt ;
++ U32 ethmaxf ;
++ U32 eth_u10 ; // Reserved.
++ U32 ethmtest ;
++ U32 miimcfg ;
++ U32 miimcmd ;
++ U32 miimaddr ;
++ U32 miimwtd ;
++ U32 miimrdd ;
++ U32 miimind ;
++ U32 eth_u11 ; // Reserved.
++ U32 eth_u12 ; // Reserved.
++ U32 ethcfsa0 ;
++ U32 ethcfsa1 ;
++ U32 ethcfsa2 ;
++} volatile *ETH_t;
++
++enum
++{
++ ETHINTFC_en_b = 0,
++ ETHINTFC_en_m = 0x00000001,
++ ETHINTFC_its_b = 1,
++ ETHINTFC_its_m = 0x00000002,
++ ETHINTFC_rip_b = 2,
++ ETHINTFC_rip_m = 0x00000004,
++ ETHINTFC_jam_b = 3,
++ ETHINTFC_jam_m = 0x00000008,
++ ETHINTFC_ovr_b = 4,
++ ETHINTFC_ovr_m = 0x00000010,
++ ETHINTFC_und_b = 5,
++ ETHINTFC_und_m = 0x00000020,
++ ETHINTFC_iom_b = 6,
++ ETHINTFC_iom_m = 0x000000c0,
++
++ ETHFIFOTT_tth_b = 0,
++ ETHFIFOTT_tth_m = 0x0000007f,
++
++ ETHARC_pro_b = 0,
++ ETHARC_pro_m = 0x00000001,
++ ETHARC_am_b = 1,
++ ETHARC_am_m = 0x00000002,
++ ETHARC_afm_b = 2,
++ ETHARC_afm_m = 0x00000004,
++ ETHARC_ab_b = 3,
++ ETHARC_ab_m = 0x00000008,
++
++ ETHSAL_byte5_b = 0,
++ ETHSAL_byte5_m = 0x000000ff,
++ ETHSAL_byte4_b = 8,
++ ETHSAL_byte4_m = 0x0000ff00,
++ ETHSAL_byte3_b = 16,
++ ETHSAL_byte3_m = 0x00ff0000,
++ ETHSAL_byte2_b = 24,
++ ETHSAL_byte2_m = 0xff000000,
++
++ ETHSAH_byte1_b = 0,
++ ETHSAH_byte1_m = 0x000000ff,
++ ETHSAH_byte0_b = 8,
++ ETHSAH_byte0_m = 0x0000ff00,
++
++ ETHGPF_ptv_b = 0,
++ ETHGPF_ptv_m = 0x0000ffff,
++
++ ETHPFS_pfd_b = 0,
++ ETHPFS_pfd_m = 0x00000001,
++
++ ETHCFSA0_cfsa4_b = 0,
++ ETHCFSA0_cfsa4_m = 0x000000ff,
++ ETHCFSA0_cfsa5_b = 8,
++ ETHCFSA0_cfsa5_m = 0x0000ff00,
++
++ ETHCFSA1_cfsa2_b = 0,
++ ETHCFSA1_cfsa2_m = 0x000000ff,
++ ETHCFSA1_cfsa3_b = 8,
++ ETHCFSA1_cfsa3_m = 0x0000ff00,
++
++ ETHCFSA2_cfsa0_b = 0,
++ ETHCFSA2_cfsa0_m = 0x000000ff,
++ ETHCFSA2_cfsa1_b = 8,
++ ETHCFSA2_cfsa1_m = 0x0000ff00,
++
++ ETHMAC1_re_b = 0,
++ ETHMAC1_re_m = 0x00000001,
++ ETHMAC1_paf_b = 1,
++ ETHMAC1_paf_m = 0x00000002,
++ ETHMAC1_rfc_b = 2,
++ ETHMAC1_rfc_m = 0x00000004,
++ ETHMAC1_tfc_b = 3,
++ ETHMAC1_tfc_m = 0x00000008,
++ ETHMAC1_lb_b = 4,
++ ETHMAC1_lb_m = 0x00000010,
++ ETHMAC1_mr_b = 31,
++ ETHMAC1_mr_m = 0x80000000,
++
++ ETHMAC2_fd_b = 0,
++ ETHMAC2_fd_m = 0x00000001,
++ ETHMAC2_flc_b = 1,
++ ETHMAC2_flc_m = 0x00000002,
++ ETHMAC2_hfe_b = 2,
++ ETHMAC2_hfe_m = 0x00000004,
++ ETHMAC2_dc_b = 3,
++ ETHMAC2_dc_m = 0x00000008,
++ ETHMAC2_cen_b = 4,
++ ETHMAC2_cen_m = 0x00000010,
++ ETHMAC2_pe_b = 5,
++ ETHMAC2_pe_m = 0x00000020,
++ ETHMAC2_vpe_b = 6,
++ ETHMAC2_vpe_m = 0x00000040,
++ ETHMAC2_ape_b = 7,
++ ETHMAC2_ape_m = 0x00000080,
++ ETHMAC2_ppe_b = 8,
++ ETHMAC2_ppe_m = 0x00000100,
++ ETHMAC2_lpe_b = 9,
++ ETHMAC2_lpe_m = 0x00000200,
++ ETHMAC2_nb_b = 12,
++ ETHMAC2_nb_m = 0x00001000,
++ ETHMAC2_bp_b = 13,
++ ETHMAC2_bp_m = 0x00002000,
++ ETHMAC2_ed_b = 14,
++ ETHMAC2_ed_m = 0x00004000,
++
++ ETHIPGT_ipgt_b = 0,
++ ETHIPGT_ipgt_m = 0x0000007f,
++
++ ETHIPGR_ipgr2_b = 0,
++ ETHIPGR_ipgr2_m = 0x0000007f,
++ ETHIPGR_ipgr1_b = 8,
++ ETHIPGR_ipgr1_m = 0x00007f00,
++
++ ETHCLRT_maxret_b = 0,
++ ETHCLRT_maxret_m = 0x0000000f,
++ ETHCLRT_colwin_b = 8,
++ ETHCLRT_colwin_m = 0x00003f00,
++
++ ETHMAXF_maxf_b = 0,
++ ETHMAXF_maxf_m = 0x0000ffff,
++
++ ETHMTEST_tb_b = 2,
++ ETHMTEST_tb_m = 0x00000004,
++
++ ETHMCP_div_b = 0,
++ ETHMCP_div_m = 0x000000ff,
++
++ MIIMCFG_rsv_b = 0,
++ MIIMCFG_rsv_m = 0x0000000c,
++
++ MIIMCMD_rd_b = 0,
++ MIIMCMD_rd_m = 0x00000001,
++ MIIMCMD_scn_b = 1,
++ MIIMCMD_scn_m = 0x00000002,
++
++ MIIMADDR_regaddr_b = 0,
++ MIIMADDR_regaddr_m = 0x0000001f,
++ MIIMADDR_phyaddr_b = 8,
++ MIIMADDR_phyaddr_m = 0x00001f00,
++
++ MIIMWTD_wdata_b = 0,
++ MIIMWTD_wdata_m = 0x0000ffff,
++
++ MIIMRDD_rdata_b = 0,
++ MIIMRDD_rdata_m = 0x0000ffff,
++
++ MIIMIND_bsy_b = 0,
++ MIIMIND_bsy_m = 0x00000001,
++ MIIMIND_scn_b = 1,
++ MIIMIND_scn_m = 0x00000002,
++ MIIMIND_nv_b = 2,
++ MIIMIND_nv_m = 0x00000004,
++
++} ;
++
++/*
++ * Values for the DEVCS field of the Ethernet DMA Rx and Tx descriptors.
++ */
++enum
++{
++ ETHRX_fd_b = 0,
++ ETHRX_fd_m = 0x00000001,
++ ETHRX_ld_b = 1,
++ ETHRX_ld_m = 0x00000002,
++ ETHRX_rok_b = 2,
++ ETHRX_rok_m = 0x00000004,
++ ETHRX_fm_b = 3,
++ ETHRX_fm_m = 0x00000008,
++ ETHRX_mp_b = 4,
++ ETHRX_mp_m = 0x00000010,
++ ETHRX_bp_b = 5,
++ ETHRX_bp_m = 0x00000020,
++ ETHRX_vlt_b = 6,
++ ETHRX_vlt_m = 0x00000040,
++ ETHRX_cf_b = 7,
++ ETHRX_cf_m = 0x00000080,
++ ETHRX_ovr_b = 8,
++ ETHRX_ovr_m = 0x00000100,
++ ETHRX_crc_b = 9,
++ ETHRX_crc_m = 0x00000200,
++ ETHRX_cv_b = 10,
++ ETHRX_cv_m = 0x00000400,
++ ETHRX_db_b = 11,
++ ETHRX_db_m = 0x00000800,
++ ETHRX_le_b = 12,
++ ETHRX_le_m = 0x00001000,
++ ETHRX_lor_b = 13,
++ ETHRX_lor_m = 0x00002000,
++ ETHRX_ces_b = 14,
++ ETHRX_ces_m = 0x00004000,
++ ETHRX_length_b = 16,
++ ETHRX_length_m = 0xffff0000,
++
++ ETHTX_fd_b = 0,
++ ETHTX_fd_m = 0x00000001,
++ ETHTX_ld_b = 1,
++ ETHTX_ld_m = 0x00000002,
++ ETHTX_oen_b = 2,
++ ETHTX_oen_m = 0x00000004,
++ ETHTX_pen_b = 3,
++ ETHTX_pen_m = 0x00000008,
++ ETHTX_cen_b = 4,
++ ETHTX_cen_m = 0x00000010,
++ ETHTX_hen_b = 5,
++ ETHTX_hen_m = 0x00000020,
++ ETHTX_tok_b = 6,
++ ETHTX_tok_m = 0x00000040,
++ ETHTX_mp_b = 7,
++ ETHTX_mp_m = 0x00000080,
++ ETHTX_bp_b = 8,
++ ETHTX_bp_m = 0x00000100,
++ ETHTX_und_b = 9,
++ ETHTX_und_m = 0x00000200,
++ ETHTX_of_b = 10,
++ ETHTX_of_m = 0x00000400,
++ ETHTX_ed_b = 11,
++ ETHTX_ed_m = 0x00000800,
++ ETHTX_ec_b = 12,
++ ETHTX_ec_m = 0x00001000,
++ ETHTX_lc_b = 13,
++ ETHTX_lc_m = 0x00002000,
++ ETHTX_td_b = 14,
++ ETHTX_td_m = 0x00004000,
++ ETHTX_crc_b = 15,
++ ETHTX_crc_m = 0x00008000,
++ ETHTX_le_b = 16,
++ ETHTX_le_m = 0x00010000,
++ ETHTX_cc_b = 17,
++ ETHTX_cc_m = 0x001E0000,
++} ;
++
++#endif // __IDT_ETH_H__
++
++
++
++
+diff -urN linux.old/include/asm-mips/rc32434/eth_v.h linux.dev/include/asm-mips/rc32434/eth_v.h
+--- linux.old/include/asm-mips/rc32434/eth_v.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/eth_v.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,64 @@
++#ifndef __IDT_ETH_V_H__
++#define __IDT_ETH_V_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * Ethernet register definition.
++ *
++ * File : $Id: eth.h,v 1.3 2002/06/06 18:34:04 astichte Exp $
++ *
++ * Author : Allen.Stichter@idt.com
++ * Date : 20020605
++ * Update :
++ * $Log: eth.h,v $
++ * Revision 1.3 2002/06/06 18:34:04 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.2 2002/06/05 18:19:46 astichte
++ * Added
++ *
++ * Revision 1.1 2002/05/29 17:33:22 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ ******************************************************************************/
++
++#include <asm/rc32434/types.h>
++#include <asm/rc32434/eth.h>
++
++#define IS_TX_TOK(X) (((X) & (1<<ETHTX_tok_b)) >> ETHTX_tok_b ) /* Transmit Okay */
++#define IS_TX_MP(X) (((X) & (1<<ETHTX_mp_b)) >> ETHTX_mp_b ) /* Multicast */
++#define IS_TX_BP(X) (((X) & (1<<ETHTX_bp_b)) >> ETHTX_bp_b ) /* Broadcast */
++#define IS_TX_UND_ERR(X) (((X) & (1<<ETHTX_und_b)) >> ETHTX_und_b ) /* Transmit FIFO Underflow */
++#define IS_TX_OF_ERR(X) (((X) & (1<<ETHTX_of_b)) >> ETHTX_of_b ) /* Oversized frame */
++#define IS_TX_ED_ERR(X) (((X) & (1<<ETHTX_ed_b)) >> ETHTX_ed_b ) /* Excessive deferral */
++#define IS_TX_EC_ERR(X) (((X) & (1<<ETHTX_ec_b)) >> ETHTX_ec_b) /* Excessive collisions */
++#define IS_TX_LC_ERR(X) (((X) & (1<<ETHTX_lc_b)) >> ETHTX_lc_b ) /* Late Collision */
++#define IS_TX_TD_ERR(X) (((X) & (1<<ETHTX_td_b)) >> ETHTX_td_b ) /* Transmit deferred*/
++#define IS_TX_CRC_ERR(X) (((X) & (1<<ETHTX_crc_b)) >> ETHTX_crc_b ) /* CRC Error */
++#define IS_TX_LE_ERR(X) (((X) & (1<<ETHTX_le_b)) >> ETHTX_le_b ) /* Length Error */
++
++#define TX_COLLISION_COUNT(X) (((X) & ETHTX_cc_m)>>ETHTX_cc_b) /* Collision Count */
++
++#define IS_RCV_ROK(X) (((X) & (1<<ETHRX_rok_b)) >> ETHRX_rok_b) /* Receive Okay */
++#define IS_RCV_FM(X) (((X) & (1<<ETHRX_fm_b)) >> ETHRX_fm_b) /* Is Filter Match */
++#define IS_RCV_MP(X) (((X) & (1<<ETHRX_mp_b)) >> ETHRX_mp_b) /* Is it MP */
++#define IS_RCV_BP(X) (((X) & (1<<ETHRX_bp_b)) >> ETHRX_bp_b) /* Is it BP */
++#define IS_RCV_VLT(X) (((X) & (1<<ETHRX_vlt_b)) >> ETHRX_vlt_b) /* VLAN Tag Detect */
++#define IS_RCV_CF(X) (((X) & (1<<ETHRX_cf_b)) >> ETHRX_cf_b) /* Control Frame */
++#define IS_RCV_OVR_ERR(X) (((X) & (1<<ETHRX_ovr_b)) >> ETHRX_ovr_b) /* Receive Overflow */
++#define IS_RCV_CRC_ERR(X) (((X) & (1<<ETHRX_crc_b)) >> ETHRX_crc_b) /* CRC Error */
++#define IS_RCV_CV_ERR(X) (((X) & (1<<ETHRX_cv_b)) >> ETHRX_cv_b) /* Code Violation */
++#define IS_RCV_DB_ERR(X) (((X) & (1<<ETHRX_db_b)) >> ETHRX_db_b) /* Dribble Bits */
++#define IS_RCV_LE_ERR(X) (((X) & (1<<ETHRX_le_b)) >> ETHRX_le_b) /* Length error */
++#define IS_RCV_LOR_ERR(X) (((X) & (1<<ETHRX_lor_b)) >> ETHRX_lor_b) /* Length Out of Range */
++#define IS_RCV_CES_ERR(X) (((X) & (1<<ETHRX_ces_b)) >> ETHRX_ces_b) /* Preamble error */
++#define RCVPKT_LENGTH(X) (((X) & ETHRX_length_m) >> ETHRX_length_b) /* Length of the received packet */
++#endif // __IDT_ETH_V_H__
++
++
++
++
++
+diff -urN linux.old/include/asm-mips/rc32434/gpio.h linux.dev/include/asm-mips/rc32434/gpio.h
+--- linux.old/include/asm-mips/rc32434/gpio.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/gpio.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,182 @@
++#ifndef __IDT_GPIO_H__
++#define __IDT_GPIO_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * GPIO register definition.
++ *
++ * File : $Id: gpio.h,v 1.2 2002/06/06 18:34:04 astichte Exp $
++ *
++ * Author : ryan.holmQVist@idt.com
++ * Date : 20011005
++ * Update :
++ * $Log: gpio.h,v $
++ * Revision 1.2 2002/06/06 18:34:04 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.1 2002/05/29 17:33:22 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ *
++ ******************************************************************************/
++
++#include <asm/rc32434/types.h>
++enum
++{
++ GPIO0_PhysicalAddress = 0x18050000,
++ GPIO_PhysicalAddress = GPIO0_PhysicalAddress, // Default
++
++ GPIO0_VirtualAddress = 0xb8050000,
++ GPIO_VirtualAddress = GPIO0_VirtualAddress, // Default
++} ;
++
++typedef struct
++{
++ U32 gpiofunc; /* GPIO Function Register
++ * gpiofunc[x]==0 bit = gpio
++ * func[x]==1 bit = altfunc
++ */
++ U32 gpiocfg; /* GPIO Configuration Register
++ * gpiocfg[x]==0 bit = input
++ * gpiocfg[x]==1 bit = output
++ */
++ U32 gpiod; /* GPIO Data Register
++ * gpiod[x] read/write gpio pinX status
++ */
++ U32 gpioilevel; /* GPIO Interrupt Status Register
++ * interrupt level (see gpioistat)
++ */
++ U32 gpioistat; /* Gpio Interrupt Status Register
++ * istat[x] = (gpiod[x] == level[x])
++ * cleared in ISR (STICKY bits)
++ */
++ U32 gpionmien; /* GPIO Non-maskable Interrupt Enable Register */
++} volatile * GPIO_t ;
++
++typedef enum
++{
++ GPIO_gpio_v = 0, // gpiofunc use pin as GPIO.
++ GPIO_alt_v = 1, // gpiofunc use pin as alt.
++ GPIO_input_v = 0, // gpiocfg use pin as input.
++ GPIO_output_v = 1, // gpiocfg use pin as output.
++ GPIO_pin0_b = 0,
++ GPIO_pin0_m = 0x00000001,
++ GPIO_pin1_b = 1,
++ GPIO_pin1_m = 0x00000002,
++ GPIO_pin2_b = 2,
++ GPIO_pin2_m = 0x00000004,
++ GPIO_pin3_b = 3,
++ GPIO_pin3_m = 0x00000008,
++ GPIO_pin4_b = 4,
++ GPIO_pin4_m = 0x00000010,
++ GPIO_pin5_b = 5,
++ GPIO_pin5_m = 0x00000020,
++ GPIO_pin6_b = 6,
++ GPIO_pin6_m = 0x00000040,
++ GPIO_pin7_b = 7,
++ GPIO_pin7_m = 0x00000080,
++ GPIO_pin8_b = 8,
++ GPIO_pin8_m = 0x00000100,
++ GPIO_pin9_b = 9,
++ GPIO_pin9_m = 0x00000200,
++ GPIO_pin10_b = 10,
++ GPIO_pin10_m = 0x00000400,
++ GPIO_pin11_b = 11,
++ GPIO_pin11_m = 0x00000800,
++ GPIO_pin12_b = 12,
++ GPIO_pin12_m = 0x00001000,
++ GPIO_pin13_b = 13,
++ GPIO_pin13_m = 0x00002000,
++ GPIO_pin14_b = 14,
++ GPIO_pin14_m = 0x00004000,
++ GPIO_pin15_b = 15,
++ GPIO_pin15_m = 0x00008000,
++ GPIO_pin16_b = 16,
++ GPIO_pin16_m = 0x00010000,
++ GPIO_pin17_b = 17,
++ GPIO_pin17_m = 0x00020000,
++ GPIO_pin18_b = 18,
++ GPIO_pin18_m = 0x00040000,
++ GPIO_pin19_b = 19,
++ GPIO_pin19_m = 0x00080000,
++ GPIO_pin20_b = 20,
++ GPIO_pin20_m = 0x00100000,
++ GPIO_pin21_b = 21,
++ GPIO_pin21_m = 0x00200000,
++ GPIO_pin22_b = 22,
++ GPIO_pin22_m = 0x00400000,
++ GPIO_pin23_b = 23,
++ GPIO_pin23_m = 0x00800000,
++ GPIO_pin24_b = 24,
++ GPIO_pin24_m = 0x01000000,
++ GPIO_pin25_b = 25,
++ GPIO_pin25_m = 0x02000000,
++ GPIO_pin26_b = 26,
++ GPIO_pin26_m = 0x04000000,
++ GPIO_pin27_b = 27,
++ GPIO_pin27_m = 0x08000000,
++ GPIO_pin28_b = 28,
++ GPIO_pin28_m = 0x10000000,
++ GPIO_pin29_b = 29,
++ GPIO_pin29_m = 0x20000000,
++ GPIO_pin30_b = 30,
++ GPIO_pin30_m = 0x40000000,
++ GPIO_pin31_b = 31,
++ GPIO_pin31_m = 0x80000000,
++
++// Alternate function pins. Corrsponding gpiofunc bit set to GPIO_alt_v.
++
++ GPIO_u0sout_b = GPIO_pin0_b, // UART 0 serial out.
++ GPIO_u0sout_m = GPIO_pin0_m,
++ GPIO_u0sout_cfg_v = GPIO_output_v,
++ GPIO_u0sinp_b = GPIO_pin1_b, // UART 0 serial in.
++ GPIO_u0sinp_m = GPIO_pin1_m,
++ GPIO_u0sinp_cfg_v = GPIO_input_v,
++ GPIO_u0rtsn_b = GPIO_pin2_b, // UART 0 req. to send.
++ GPIO_u0rtsn_m = GPIO_pin2_m,
++ GPIO_u0rtsn_cfg_v = GPIO_output_v,
++ GPIO_u0ctsn_b = GPIO_pin3_b, // UART 0 clear to send.
++ GPIO_u0ctsn_m = GPIO_pin3_m,
++ GPIO_u0ctsn_cfg_v = GPIO_input_v,
++ GPIO_maddr22_b = GPIO_pin4_b, // M&P bus bit 22.
++ GPIO_maddr22_m = GPIO_pin4_m,
++ GPIO_maddr22_cfg_v = GPIO_output_v,
++
++ GPIO_maddr23_b = GPIO_pin5_b, // M&P bus bit 23.
++ GPIO_maddr23_m = GPIO_pin5_m,
++ GPIO_maddr23_cfg_v = GPIO_output_v,
++
++ GPIO_maddr24_b = GPIO_pin6_b, // M&P bus bit 24.
++ GPIO_maddr24_m = GPIO_pin6_m,
++ GPIO_maddr24_cfg_v = GPIO_output_v,
++
++ GPIO_maddr25_b = GPIO_pin7_b, // M&P bus bit 25.
++ GPIO_maddr25_m = GPIO_pin7_m,
++ GPIO_maddr25_cfg_v = GPIO_output_v,
++
++ GPIO_cpu_b = GPIO_pin8_b, // M&P bus bit 25.
++ GPIO_cpu_m = GPIO_pin8_m,
++ GPIO_cpu_cfg_v = GPIO_output_v,
++ GPIO_afspare6_b = GPIO_pin9_b, // reserved.
++ GPIO_afspare6_m = GPIO_pin9_m,
++ GPIO_afspare6_cfg_v = GPIO_input_v,
++ GPIO_afspare4_b = GPIO_pin10_b, // reserved.
++ GPIO_afspare4_m = GPIO_pin10_m,
++ GPIO_afspare4_cfg_v = GPIO_input_v,
++ GPIO_afspare3_b = GPIO_pin11_b, // reserved.
++ GPIO_afspare3_m = GPIO_pin11_m,
++ GPIO_afspare3_cfg_v = GPIO_input_v,
++ GPIO_afspare2_b = GPIO_pin12_b, // reserved.
++ GPIO_afspare2_m = GPIO_pin12_m,
++ GPIO_afspare2_cfg_v = GPIO_input_v,
++ GPIO_pcimuintn_b = GPIO_pin13_b, // PCI messaging int.
++ GPIO_pcimuintn_m = GPIO_pin13_m,
++ GPIO_pcimuintn_cfg_v = GPIO_output_v,
++
++} GPIO_DEFS_t;
++
++#endif // __IDT_GPIO_H__
++
+diff -urN linux.old/include/asm-mips/rc32434/i2c.h linux.dev/include/asm-mips/rc32434/i2c.h
+--- linux.old/include/asm-mips/rc32434/i2c.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/i2c.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,147 @@
++#ifndef __IDT_I2C_H__
++#define __IDT_I2C_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * I2C register definitions.
++ *
++ * File : $Id: i2c.h,v 1.2 2002/06/06 18:34:04 astichte Exp $
++ *
++ * Author : Allen.Stichter@idt.com
++ * Date : 20020120
++ * Update :
++ * $Log: i2c.h,v $
++ * Revision 1.2 2002/06/06 18:34:04 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.1 2002/05/29 17:33:22 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ *
++ ******************************************************************************/
++
++#include <asm/rc32434/types.h>
++
++enum
++{
++ I2C0_PhysicalAddress = 0x18068000,
++ I2C_PhysicalAddress = I2C0_PhysicalAddress,
++
++ I2C0_VirtualAddress = 0xb8068000,
++ I2C_VirtualAddress = I2C0_VirtualAddress,
++} ;
++
++typedef struct
++{
++ U32 i2cc ;
++ U32 i2cdi ;
++ U32 i2cdo ;
++ U32 i2ccp ; // I2C clk = ICLK / div / 8
++ U32 i2cmcmd ;
++ U32 i2cms ;
++ U32 i2cmsm ;
++ U32 i2css ;
++ U32 i2cssm ;
++ U32 i2csaddr ;
++ U32 i2csack ;
++} volatile * I2C_t ;
++enum
++{
++ I2CC_men_b = 0, // In I2C-> i2cc
++ I2CC_men_m = 0x00000001,
++ I2CC_sen_b = 1, // In I2C-> i2cc
++ I2CC_sen_m = 0x00000002,
++ I2CC_iom_b = 2, // In I2C-> i2cc
++ I2CC_iom_m = 0x00000004,
++
++ I2CDI_data_b = 0, // In I2C-> i2cdi
++ I2CDI_data_m = 0x000000ff,
++
++ I2CDO_data_b = 0, // In I2C-> i2cdo
++ I2CDO_data_m = 0x000000ff,
++
++ I2CCP_div_b = 0, // In I2C-> i2ccp
++ I2CCP_div_m = 0x0000ffff,
++
++ I2CMCMD_cmd_b = 0, // In I2C-> i2cmcmd
++ I2CMCMD_cmd_m = 0x0000000f,
++ I2CMCMD_cmd_nop_v = 0,
++ I2CMCMD_cmd_start_v = 1,
++ I2CMCMD_cmd_stop_v = 2,
++ I2CMCMD_cmd_res3_v = 3,
++ I2CMCMD_cmd_rd_v = 4,
++ I2CMCMD_cmd_rdack_v = 5,
++ I2CMCMD_cmd_wd_v = 6,
++ I2CMCMD_cmd_wdack_v = 7,
++ I2CMCMD_cmd_res8_v = 8,
++ I2CMCMD_cmd_res9_v = 9,
++ I2CMCMD_cmd_res10_v = 10,
++ I2CMCMD_cmd_res11_v = 11,
++ I2CMCMD_cmd_res12_v = 12,
++ I2CMCMD_cmd_res13_v = 13,
++ I2CMCMD_cmd_res14_v = 14,
++ I2CMCMD_cmd_res15_v = 15,
++
++ I2CMS_d_b = 0, // In I2C-> i2cms
++ I2CMS_d_m = 0x00000001,
++ I2CMS_na_b = 1, // In I2C-> i2cms
++ I2CMS_na_m = 0x00000002,
++ I2CMS_la_b = 2, // In I2C-> i2cms
++ I2CMS_la_m = 0x00000004,
++ I2CMS_err_b = 3, // In I2C-> i2cms
++ I2CMS_err_m = 0x00000008,
++
++ I2CMSM_d_b = 0, // In I2C-> i2cmsm
++ I2CMSM_d_m = 0x00000001,
++ I2CMSM_na_b = 1, // In I2C-> i2cmsm
++ I2CMSM_na_m = 0x00000002,
++ I2CMSM_la_b = 2, // In I2C-> i2cmsm
++ I2CMSM_la_m = 0x00000004,
++ I2CMSM_err_b = 3, // In I2C-> i2cmsm
++ I2CMSM_err_m = 0x00000008,
++
++ I2CSS_rr_b = 0, // In I2C-> i2css
++ I2CSS_rr_m = 0x00000001,
++ I2CSS_wr_b = 1, // In I2C-> i2css
++ I2CSS_wr_m = 0x00000002,
++ I2CSS_sa_b = 2, // In I2C-> i2css
++ I2CSS_sa_m = 0x00000004,
++ I2CSS_tf_b = 3, // In I2C-> i2css
++ I2CSS_tf_m = 0x00000008,
++ I2CSS_gc_b = 4, // In I2C-> i2css
++ I2CSS_gc_m = 0x00000010,
++ I2CSS_na_b = 5, // In I2C-> i2css
++ I2CSS_na_m = 0x00000020,
++ I2CSS_err_b = 6, // In I2C-> i2css
++ I2CSS_err_m = 0x00000040,
++
++ I2CSSM_rr_b = 0, // In I2C-> i2cssm
++ I2CSSM_rr_m = 0x00000001,
++ I2CSSM_wr_b = 1, // In I2C-> i2cssm
++ I2CSSM_wr_m = 0x00000002,
++ I2CSSM_sa_b = 2, // In I2C-> i2cssm
++ I2CSSM_sa_m = 0x00000004,
++ I2CSSM_tf_b = 3, // In I2C-> i2cssm
++ I2CSSM_tf_m = 0x00000008,
++ I2CSSM_gc_b = 4, // In I2C-> i2cssm
++ I2CSSM_gc_m = 0x00000010,
++ I2CSSM_na_b = 5, // In I2C-> i2cssm
++ I2CSSM_na_m = 0x00000020,
++ I2CSSM_err_b = 6, // In I2C-> i2cssm
++ I2CSSM_err_m = 0x00000040,
++
++ I2CSADDR_addr_b = 0, // In I2C-> i2csaddr
++ I2CSADDR_addr_m = 0x000003ff,
++ I2CSADDR_a_gc_b = 10, // In I2C-> i2csaddr
++ I2CSADDR_a_gc_m = 0x00000400,
++ I2CSADDR_a10_b = 11, // In I2C-> i2csaddr
++ I2CSADDR_a10_m = 0x00000800,
++
++ I2CSACK_ack_b = 0, // In I2C-> i2csack
++ I2CSACK_ack_m = 0x00000001,
++
++} ;
++#endif // __IDT_I2C_H__
+diff -urN linux.old/include/asm-mips/rc32434/integ.h linux.dev/include/asm-mips/rc32434/integ.h
+--- linux.old/include/asm-mips/rc32434/integ.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/integ.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,78 @@
++#ifndef __IDT_INTEG_H__
++#define __IDT_INTEG_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * System Integrity register definition.
++ *
++ * File : $Id: integ.h,v 1.3 2002/06/06 18:34:04 astichte Exp $
++ *
++ * Author : ryan.holmQVist@idt.com
++ * Date : 20011005
++ * Update :
++ * $Log: integ.h,v $
++ * Revision 1.3 2002/06/06 18:34:04 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.2 2002/06/05 18:32:33 astichte
++ * Removed IDTField
++ *
++ * Revision 1.1 2002/05/29 17:33:22 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ ******************************************************************************/
++
++#include <asm/rc32434/types.h>
++
++enum
++{
++ INTEG0_PhysicalAddress = 0x18030000,
++ INTEG_PhysicalAddress = INTEG0_PhysicalAddress, // Default
++
++ INTEG0_VirtualAddress = 0xb8030000,
++ INTEG_VirtualAddress = INTEG0_VirtualAddress, // Default
++} ;
++
++// if you are looing for CEA, try rst.h
++typedef struct
++{
++ U32 filler [0xc] ; // 0x30 bytes unused.
++ U32 errcs ; // sticky use ERRCS_
++ U32 wtcount ; // Watchdog timer count reg.
++ U32 wtcompare ; // Watchdog timer timeout value.
++ U32 wtc ; // Watchdog timer control. use WTC_
++} volatile *INTEG_t ;
++
++enum
++{
++ ERRCS_wto_b = 0, // In INTEG_t -> errcs
++ ERRCS_wto_m = 0x00000001,
++ ERRCS_wne_b = 1, // In INTEG_t -> errcs
++ ERRCS_wne_m = 0x00000002,
++ ERRCS_ucw_b = 2, // In INTEG_t -> errcs
++ ERRCS_ucw_m = 0x00000004,
++ ERRCS_ucr_b = 3, // In INTEG_t -> errcs
++ ERRCS_ucr_m = 0x00000008,
++ ERRCS_upw_b = 4, // In INTEG_t -> errcs
++ ERRCS_upw_m = 0x00000010,
++ ERRCS_upr_b = 5, // In INTEG_t -> errcs
++ ERRCS_upr_m = 0x00000020,
++ ERRCS_udw_b = 6, // In INTEG_t -> errcs
++ ERRCS_udw_m = 0x00000040,
++ ERRCS_udr_b = 7, // In INTEG_t -> errcs
++ ERRCS_udr_m = 0x00000080,
++ ERRCS_sae_b = 8, // In INTEG_t -> errcs
++ ERRCS_sae_m = 0x00000100,
++ ERRCS_wre_b = 9, // In INTEG_t -> errcs
++ ERRCS_wre_m = 0x00000200,
++
++ WTC_en_b = 0, // In INTEG_t -> wtc
++ WTC_en_m = 0x00000001,
++ WTC_to_b = 1, // In INTEG_t -> wtc
++ WTC_to_m = 0x00000002,
++} ;
++
++#endif // __IDT_INTEG_H__
+diff -urN linux.old/include/asm-mips/rc32434/int.h linux.dev/include/asm-mips/rc32434/int.h
+--- linux.old/include/asm-mips/rc32434/int.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/int.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,167 @@
++#ifndef __IDT_INT_H__
++#define __IDT_INT_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * Interrupt Controller register definition.
++ *
++ * File : $Id: int.h,v 1.3 2002/06/06 18:34:04 astichte Exp $
++ *
++ * Author : ryan.holmqvist@idt.com
++ * Date : 20011005
++ * Update :
++ * $Log: int.h,v $
++ * Revision 1.3 2002/06/06 18:34:04 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.2 2002/06/05 18:47:33 astichte
++ * Removed IDTField
++ *
++ * Revision 1.1 2002/05/29 17:33:22 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ *
++ ******************************************************************************/
++
++#include <asm/rc32434/types.h>
++
++enum
++{
++ INT0_PhysicalAddress = 0x18038000,
++ INT_PhysicalAddress = INT0_PhysicalAddress, // Default
++
++ INT0_VirtualAddress = 0xb8038000,
++ INT_VirtualAddress = INT0_VirtualAddress, // Default
++} ;
++
++struct INT_s
++{
++ U32 ipend ; //Pending interrupts. use INT?_
++ U32 itest ; //Test bits. use INT?_
++ U32 imask ; //Interrupt disabled when set. use INT?_
++} ;
++
++enum
++{
++ IPEND2 = 0, // HW 2 interrupt to core. use INT2_
++ IPEND3 = 1, // HW 3 interrupt to core. use INT3_
++ IPEND4 = 2, // HW 4 interrupt to core. use INT4_
++ IPEND5 = 3, // HW 5 interrupt to core. use INT5_
++ IPEND6 = 4, // HW 6 interrupt to core. use INT6_
++
++ IPEND_count, // must be last (used in loops)
++ IPEND_min = IPEND2 // min IPEND (used in loops)
++};
++
++typedef struct INTC_s
++{
++ struct INT_s i [IPEND_count] ;// use i[IPEND?] = INT?_
++ U32 nmips ; // use NMIPS_
++} volatile *INT_t ;
++
++enum
++{
++ INT2_timer0_b = 0,
++ INT2_timer0_m = 0x00000001,
++ INT2_timer1_b = 1,
++ INT2_timer1_m = 0x00000002,
++ INT2_timer2_b = 2,
++ INT2_timer2_m = 0x00000004,
++ INT2_refresh_b = 3,
++ INT2_refresh_m = 0x00000008,
++ INT2_watchdogTimeout_b = 4,
++ INT2_watchdogTimeout_m = 0x00000010,
++ INT2_undecodedCpuWrite_b = 5,
++ INT2_undecodedCpuWrite_m = 0x00000020,
++ INT2_undecodedCpuRead_b = 6,
++ INT2_undecodedCpuRead_m = 0x00000040,
++ INT2_undecodedPciWrite_b = 7,
++ INT2_undecodedPciWrite_m = 0x00000080,
++ INT2_undecodedPciRead_b = 8,
++ INT2_undecodedPciRead_m = 0x00000100,
++ INT2_undecodedDmaWrite_b = 9,
++ INT2_undecodedDmaWrite_m = 0x00000200,
++ INT2_undecodedDmaRead_b = 10,
++ INT2_undecodedDmaRead_m = 0x00000400,
++ INT2_ipBusSlaveAckError_b = 11,
++ INT2_ipBusSlaveAckError_m = 0x00000800,
++
++ INT3_dmaChannel0_b = 0,
++ INT3_dmaChannel0_m = 0x00000001,
++ INT3_dmaChannel1_b = 1,
++ INT3_dmaChannel1_m = 0x00000002,
++ INT3_dmaChannel2_b = 2,
++ INT3_dmaChannel2_m = 0x00000004,
++ INT3_dmaChannel3_b = 3,
++ INT3_dmaChannel3_m = 0x00000008,
++ INT3_dmaChannel4_b = 4,
++ INT3_dmaChannel4_m = 0x00000010,
++ INT3_dmaChannel5_b = 5,
++ INT3_dmaChannel5_m = 0x00000020,
++
++ INT5_uartGeneral0_b = 0,
++ INT5_uartGeneral0_m = 0x00000001,
++ INT5_uartTxrdy0_b = 1,
++ INT5_uartTxrdy0_m = 0x00000002,
++ INT5_uartRxrdy0_b = 2,
++ INT5_uartRxrdy0_m = 0x00000004,
++ INT5_pci_b = 3,
++ INT5_pci_m = 0x00000008,
++ INT5_pciDecoupled_b = 4,
++ INT5_pciDecoupled_m = 0x00000010,
++ INT5_spi_b = 5,
++ INT5_spi_m = 0x00000020,
++ INT5_deviceDecoupled_b = 6,
++ INT5_deviceDecoupled_m = 0x00000040,
++ INT5_i2cMaster_b = 7,
++ INT5_i2cMaster_m = 0x00000080,
++ INT5_i2cSlave_b = 8,
++ INT5_i2cSlave_m = 0x00000100,
++ INT5_ethOvr_b = 9,
++ INT5_ethOvr_m = 0x00000200,
++ INT5_ethUnd_b = 10,
++ INT5_ethUnd_m = 0x00000400,
++ INT5_ethPfd_b = 11,
++ INT5_ethPfd_m = 0x00000800,
++ INT5_nvram_b = 12,
++ INT5_nvram_m = 0x00001000,
++
++ INT6_gpio0_b = 0,
++ INT6_gpio0_m = 0x00000001,
++ INT6_gpio1_b = 1,
++ INT6_gpio1_m = 0x00000002,
++ INT6_gpio2_b = 2,
++ INT6_gpio2_m = 0x00000004,
++ INT6_gpio3_b = 3,
++ INT6_gpio3_m = 0x00000008,
++ INT6_gpio4_b = 4,
++ INT6_gpio4_m = 0x00000010,
++ INT6_gpio5_b = 5,
++ INT6_gpio5_m = 0x00000020,
++ INT6_gpio6_b = 6,
++ INT6_gpio6_m = 0x00000040,
++ INT6_gpio7_b = 7,
++ INT6_gpio7_m = 0x00000080,
++ INT6_gpio8_b = 8,
++ INT6_gpio8_m = 0x00000100,
++ INT6_gpio9_b = 9,
++ INT6_gpio9_m = 0x00000200,
++ INT6_gpio10_b = 10,
++ INT6_gpio10_m = 0x00000400,
++ INT6_gpio11_b = 11,
++ INT6_gpio11_m = 0x00000800,
++ INT6_gpio12_b = 12,
++ INT6_gpio12_m = 0x00001000,
++ INT6_gpio13_b = 13,
++ INT6_gpio13_m = 0x00002000,
++
++ NMIPS_gpio_b = 0,
++ NMIPS_gpio_m = 0x00000001,
++} ;
++
++#endif // __IDT_INT_H__
++
++
+diff -urN linux.old/include/asm-mips/rc32434/iparb.h linux.dev/include/asm-mips/rc32434/iparb.h
+--- linux.old/include/asm-mips/rc32434/iparb.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/iparb.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,95 @@
++#ifndef __IDT_IPARB_H__
++#define __IDT_IPARB_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * IP Arbiter register definitions.
++ *
++ * File : $Id: iparb.h,v 1.3 2002/06/06 18:34:04 astichte Exp $
++ *
++ * Author : Allen.Stichter@idt.com
++ * Date : 20020120
++ * Update :
++ * $Log: iparb.h,v $
++ * Revision 1.3 2002/06/06 18:34:04 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.2 2002/06/05 19:01:42 astichte
++ * Removed IDTField
++ *
++ * Revision 1.1 2002/05/29 17:33:23 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ ******************************************************************************/
++
++#include <asm/rc32434/types.h>
++
++enum
++{
++ IPARB0_PhysicalAddress = 0x18048000,
++ IPARB_PhysicalAddress = IPARB0_PhysicalAddress, // Default
++
++ IPARB0_VirtualAddress = 0xb8048000,
++ IPARB_VirtualAddress = IPARB0_VirtualAddress, // Default
++} ;
++
++enum
++{
++ IPABMXC_ethernetReceive = 0,
++ IPABMXC_ethernetTransmit = 1,
++ IPABMXC_memoryToHoldFifo = 2,
++ IPABMXC_holdFifoToMemory = 3,
++ IPABMXC_pciToMemory = 4,
++ IPABMXC_memoryToPci = 5,
++ IPABMXC_pciTarget = 6,
++ IPABMXC_pciTargetStart = 7,
++ IPABMXC_cpuToIpBus = 8,
++
++ IPABMXC_Count, // Must be last in list !
++ IPABMXC_Min = IPABMXC_ethernetReceive,
++
++ IPAPXC_PriorityCount = 4, // 3-highest, 0-lowest.
++} ;
++
++typedef struct
++{
++ U32 ipapc [IPAPXC_PriorityCount] ; // ipapc[IPAPXC_] = IPAPC_
++ U32 ipabmc [IPABMXC_Count] ; // ipabmc[IPABMXC_] = IPABMC_
++ U32 ipac ; // use IPAC_
++ U32 ipaitcc; // use IPAITCC_
++ U32 ipaspare ;
++} volatile * IPARB_t ;
++
++enum
++{
++ IPAC_dwm_b = 2,
++ IPAC_dwm_m = 0x00000004,
++ IPAC_drm_b = 3,
++ IPAC_drm_m = 0x00000008,
++ IPAC_msk_b = 4,
++ IPAC_msk_m = 0x00000010,
++
++ IPAPC_ptc_b = 0,
++ IPAPC_ptc_m = 0x00003fff,
++ IPAPC_mf_b = 14,
++ IPAPC_mf_m = 0x00004000,
++ IPAPC_cptc_b = 16,
++ IPAPC_cptc_m = 0x3fff0000,
++
++ IPAITCC_itcc = 0,
++ IPAITCC_itcc, = 0x000001ff,
++
++ IPABMC_mtc_b = 0,
++ IPABMC_mtc_m = 0x00000fff,
++ IPABMC_p_b = 12,
++ IPABMC_p_m = 0x00003000,
++ IPABMC_msk_b = 14,
++ IPABMC_msk_m = 0x00004000,
++ IPABMC_cmtc_b = 16,
++ IPABMC_cmtc_m = 0x0fff0000,
++};
++
++#endif // __IDT_IPARB_H__
+diff -urN linux.old/include/asm-mips/rc32434/irm.h linux.dev/include/asm-mips/rc32434/irm.h
+--- linux.old/include/asm-mips/rc32434/irm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/irm.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,55 @@
++#ifndef __IDT_IRM_H__
++#define __IDT_IRM_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * Internal Register Map
++ *
++ * File : $Id: irm.h,v 1.2 2002/06/05 14:51:06 astichte Exp $
++ *
++ * Author : Allen.Stichter@idt.com
++ * Date : 20020605
++ * Update :
++ * $Log: irm.h,v $
++ * Revision 1.2 2002/06/05 14:51:06 astichte
++ * *** empty log message ***
++ *
++ * Revision 1.1 2002/05/29 17:33:23 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ ******************************************************************************/
++
++/*
++ * NOTE --
++ * This file is here for backwards compatibility.
++ * DO NOT USE !!!!
++ */
++
++typedef enum
++{
++ IRM_Physical = 0x18000000, // Internal Reg. map physical.
++ RST_Offset = 0x00000000, // Includes sysid and RST.
++ DEV_Offset = 0x00010000, // Device Controller 0.
++ DDR_Offset = 0x00018000, // Double-Data-Rate mem. controller.
++ PMARB_Offset = 0x00020000, // PM bus arbiter.
++ TIM_Offset = 0x00028000, // Counter / timer.
++ INTEG_Offset = 0x00030000, // System Integrity.
++ INT_Offset = 0x00038000, // Interrupt controller.
++ DMA_Offset = 0x00040000, // DMA.
++ IPARB_Offset = 0x00044000, // IP bus arbiter.
++ GPIO_Offset = 0x00050000, // GPIO.
++ UART_Offset = 0x00058000, // UART
++ ETH_Offset = 0x00060000, // Ethernet 1.
++ I2C_Offset = 0x00068000, // I2C interface.
++ SPI_Offset = 0x00070000, // Serial Peripheral Interface.
++ NVRAM_Offset = 0x00078000, // NVRAM interface
++ AUTH_Offset = 0x0007c000, // Authorization unit
++ PCI_Offset = 0x00080000,
++ CROM_Offset = 0x000b8000, // Configuration ROM.
++ IRM_Size = 0x00200000, // Internal Reg. map size.
++} IRM_Offset_t ;
++
++#endif // __IDT_IRM_H__
+diff -urN linux.old/include/asm-mips/rc32434/irq.h linux.dev/include/asm-mips/rc32434/irq.h
+--- linux.old/include/asm-mips/rc32434/irq.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/irq.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,8 @@
++#ifndef __ASM_MACH_MIPS_IRQ_H
++#define __ASM_MACH_MIPS_IRQ_H
++
++#include <linux/config.h>
++
++#define NR_IRQS 256
++
++#endif /* __ASM_MACH_MIPS_IRQ_H */
+diff -urN linux.old/include/asm-mips/rc32434/nvram.h linux.dev/include/asm-mips/rc32434/nvram.h
+--- linux.old/include/asm-mips/rc32434/nvram.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/nvram.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,97 @@
++#ifndef __IDT_NVRAM_H
++#define __IDT_NVRAM_H
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * IP Arbiter register definitions.
++ *
++ * File : $Id: nvram.h,v 1.3 2003/07/24 18:34:04 astichte Exp $
++ *
++ * Author : kiran.rao@idt.com
++ * Date : 20030724
++ * Update :
++ * $Log: nvram.h,v $
++ *
++ *
++ ******************************************************************************/
++#include <asm/rc32434/tpes.h>
++
++
++enum
++{
++ NVRAM0_PhysicalAddress = 0xba000000,
++ NVRAM_PhysicalAddress = NVRAM0_PhysicalAddress, // Default
++
++ NVRAM0_VirtualAddress = 0xba000000,
++ NVRAM_VirtualAddress = NVRAM0_VirtualAddress, // Default
++} ;
++
++enum
++{
++ NVRCMD_cmd_b = 0,
++ NVRCMD_cmd_m = 0x0000007f,
++
++ NVRS_r_b = 0,
++ NVRS_r_m = 0x00000001,
++ NVRS_e_b = 1,
++ NVRS_e_m = 0x00000002,
++ NVRS_k_b = 2,
++ NVRS_k_m = 0x00000004,
++
++ NVRSM_r_b = 0,
++ NVRSM_r_m = 0x00000001,
++ NVRSM_e_b = 1,
++ NVRSM_e_m = 0x00000002,
++ NVRSM_k_b = 2,
++ NVRSM_k_m = 0x00000004,
++
++ NVRCFG0_pwidth_b = 0,
++ NVRCFG0_pwidth_m = 0x00000003,
++ NVRCFG0_nmax_b = 2,
++ NVRCFG0_nmax_m = 0x0000000C,
++ NVRCFG0_vppl_b = 4,
++ NVRCFG0_vppl_m = 0x000000f0,
++ NVRCFG0_vppm_b = 8,
++ NVRCFG0_vppm_m = 0x00000300,
++ NVRCFG0_dvpp_b = 10,
++ NVRCFG0_dvpp_m = 0x00000c00,
++ NVRCFG0_x_b = 12,
++ NVRCFG0_x_m = 0x00007000,
++
++ NVRCFG1_t1tecc_b = 0,
++ NVRCFG1_t1tecc_m = 0x00000003,
++ NVRCFG1_t1mrcl_b = 2,
++ NVRCFG1_t1mrcl_m = 0x0000000c,
++ NVRCFG1_t1bias_b = 4,
++ NVRCFG1_t1bias_m = 0x00000030,
++ NVRCFG1_t2tecc_b = 6,
++ NVRCFG1_t2tecc_m = 0x000000c0,
++ NVRCFG1_t2mrcl_b = 8,
++ NVRCFG1_t2mrcl_m = 0x00000300,
++ NVRCFG1_t2bias_b = 10,
++ NVRCFG1_t2bias_m = 0x00000c00,
++ NVRCFG1_t3tecc_b = 12,
++ NVRCFG1_t3tecc_m = 0x00003000,
++ NVRCFG1_t3mrcl_b = 14,
++ NVRCFG1_t3mrcl_m = 0x0000c000,
++ NVRCFG1_t3bias_b = 16,
++ NVRCFG1_t3bias_m = 0x00030000,
++ NVRCFG1_t4tecc_b = 18,
++ NVRCFG1_t4tecc_m = 0x000c0000,
++ NVRCFG1_t4mrcl_b = 20,
++ NVRCFG1_t4mrcl_m = 0x00300000,
++ NVRCFG1_t4bias_b = 22,
++ NVRCFG1_t4bias_m = 0x00c00000,
++ NVRCFG1_t5tecc_b = 24,
++ NVRCFG1_t5tecc_m = 0x03000000,
++ NVRCFG1_t5mrcl_b = 26,
++ NVRCFG1_t5mrcl_m = 0x0c000000,
++ NVRCFG1_t5bias_b = 28,
++ NVRCFG1_t5bias_m = 0x30000000,
++}
++
++#endif // __IDT_NVRAM_H__
++
+diff -urN linux.old/include/asm-mips/rc32434/pci.h linux.dev/include/asm-mips/rc32434/pci.h
+--- linux.old/include/asm-mips/rc32434/pci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/pci.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,695 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * PCI register definitio
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_PCI_H__
++#define __IDT_PCI_H__
++
++enum
++{
++ PCI0_PhysicalAddress = 0x18080000,
++ PCI_PhysicalAddress = PCI0_PhysicalAddress,
++
++ PCI0_VirtualAddress = 0xB8080000,
++ PCI_VirtualAddress = PCI0_VirtualAddress,
++} ;
++
++enum
++{
++ PCI_LbaCount = 4, // Local base addresses.
++} ;
++
++typedef struct
++{
++ u32 a ; // Address.
++ u32 c ; // Control.
++ u32 m ; // mapping.
++} PCI_Map_s ;
++
++typedef struct
++{
++ u32 pcic ;
++ u32 pcis ;
++ u32 pcism ;
++ u32 pcicfga ;
++ u32 pcicfgd ;
++ PCI_Map_s pcilba [PCI_LbaCount] ;
++ u32 pcidac ;
++ u32 pcidas ;
++ u32 pcidasm ;
++ u32 pcidad ;
++ u32 pcidma8c ;
++ u32 pcidma9c ;
++ u32 pcitc ;
++} volatile *PCI_t ;
++
++// PCI messaging unit.
++enum
++{
++ PCIM_Count = 2,
++} ;
++typedef struct
++{
++ u32 pciim [PCIM_Count] ;
++ u32 pciom [PCIM_Count] ;
++ u32 pciid ;
++ u32 pciiic ;
++ u32 pciiim ;
++ u32 pciiod ;
++ u32 pciioic ;
++ u32 pciioim ;
++} volatile *PCIM_t ;
++
++/*******************************************************************************
++ *
++ * PCI Control Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCIC_en_b = 0,
++ PCIC_en_m = 0x00000001,
++ PCIC_tnr_b = 1,
++ PCIC_tnr_m = 0x00000002,
++ PCIC_sce_b = 2,
++ PCIC_sce_m = 0x00000004,
++ PCIC_ien_b = 3,
++ PCIC_ien_m = 0x00000008,
++ PCIC_aaa_b = 4,
++ PCIC_aaa_m = 0x00000010,
++ PCIC_eap_b = 5,
++ PCIC_eap_m = 0x00000020,
++ PCIC_pcim_b = 6,
++ PCIC_pcim_m = 0x000001c0,
++ PCIC_pcim_disabled_v = 0,
++ PCIC_pcim_tnr_v = 1, // Satellite - target not ready
++ PCIC_pcim_suspend_v = 2, // Satellite - suspended CPU.
++ PCIC_pcim_extern_v = 3, // Host - external arbiter.
++ PCIC_pcim_fixed_v = 4, // Host - fixed priority arb.
++ PCIC_pcim_roundrobin_v = 5, // Host - round robin priority.
++ PCIC_pcim_reserved6_v = 6,
++ PCIC_pcim_reserved7_v = 7,
++ PCIC_igm_b = 9,
++ PCIC_igm_m = 0x00000200,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Status Register
++ *
++ ******************************************************************************/
++enum {
++ PCIS_eed_b = 0,
++ PCIS_eed_m = 0x00000001,
++ PCIS_wr_b = 1,
++ PCIS_wr_m = 0x00000002,
++ PCIS_nmi_b = 2,
++ PCIS_nmi_m = 0x00000004,
++ PCIS_ii_b = 3,
++ PCIS_ii_m = 0x00000008,
++ PCIS_cwe_b = 4,
++ PCIS_cwe_m = 0x00000010,
++ PCIS_cre_b = 5,
++ PCIS_cre_m = 0x00000020,
++ PCIS_mdpe_b = 6,
++ PCIS_mdpe_m = 0x00000040,
++ PCIS_sta_b = 7,
++ PCIS_sta_m = 0x00000080,
++ PCIS_rta_b = 8,
++ PCIS_rta_m = 0x00000100,
++ PCIS_rma_b = 9,
++ PCIS_rma_m = 0x00000200,
++ PCIS_sse_b = 10,
++ PCIS_sse_m = 0x00000400,
++ PCIS_ose_b = 11,
++ PCIS_ose_m = 0x00000800,
++ PCIS_pe_b = 12,
++ PCIS_pe_m = 0x00001000,
++ PCIS_tae_b = 13,
++ PCIS_tae_m = 0x00002000,
++ PCIS_rle_b = 14,
++ PCIS_rle_m = 0x00004000,
++ PCIS_bme_b = 15,
++ PCIS_bme_m = 0x00008000,
++ PCIS_prd_b = 16,
++ PCIS_prd_m = 0x00010000,
++ PCIS_rip_b = 17,
++ PCIS_rip_m = 0x00020000,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Status Mask Register
++ *
++ ******************************************************************************/
++enum {
++ PCISM_eed_b = 0,
++ PCISM_eed_m = 0x00000001,
++ PCISM_wr_b = 1,
++ PCISM_wr_m = 0x00000002,
++ PCISM_nmi_b = 2,
++ PCISM_nmi_m = 0x00000004,
++ PCISM_ii_b = 3,
++ PCISM_ii_m = 0x00000008,
++ PCISM_cwe_b = 4,
++ PCISM_cwe_m = 0x00000010,
++ PCISM_cre_b = 5,
++ PCISM_cre_m = 0x00000020,
++ PCISM_mdpe_b = 6,
++ PCISM_mdpe_m = 0x00000040,
++ PCISM_sta_b = 7,
++ PCISM_sta_m = 0x00000080,
++ PCISM_rta_b = 8,
++ PCISM_rta_m = 0x00000100,
++ PCISM_rma_b = 9,
++ PCISM_rma_m = 0x00000200,
++ PCISM_sse_b = 10,
++ PCISM_sse_m = 0x00000400,
++ PCISM_ose_b = 11,
++ PCISM_ose_m = 0x00000800,
++ PCISM_pe_b = 12,
++ PCISM_pe_m = 0x00001000,
++ PCISM_tae_b = 13,
++ PCISM_tae_m = 0x00002000,
++ PCISM_rle_b = 14,
++ PCISM_rle_m = 0x00004000,
++ PCISM_bme_b = 15,
++ PCISM_bme_m = 0x00008000,
++ PCISM_prd_b = 16,
++ PCISM_prd_m = 0x00010000,
++ PCISM_rip_b = 17,
++ PCISM_rip_m = 0x00020000,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Configuration Address Register
++ *
++ ******************************************************************************/
++enum {
++ PCICFGA_reg_b = 2,
++ PCICFGA_reg_m = 0x000000fc,
++ PCICFGA_reg_id_v = 0x00>>2, //use PCFGID_
++ PCICFGA_reg_04_v = 0x04>>2, //use PCFG04_
++ PCICFGA_reg_08_v = 0x08>>2, //use PCFG08_
++ PCICFGA_reg_0C_v = 0x0C>>2, //use PCFG0C_
++ PCICFGA_reg_pba0_v = 0x10>>2, //use PCIPBA_
++ PCICFGA_reg_pba1_v = 0x14>>2, //use PCIPBA_
++ PCICFGA_reg_pba2_v = 0x18>>2, //use PCIPBA_
++ PCICFGA_reg_pba3_v = 0x1c>>2, //use PCIPBA_
++ PCICFGA_reg_subsystem_v = 0x2c>>2, //use PCFGSS_
++ PCICFGA_reg_3C_v = 0x3C>>2, //use PCFG3C_
++ PCICFGA_reg_pba0c_v = 0x44>>2, //use PCIPBAC_
++ PCICFGA_reg_pba0m_v = 0x48>>2,
++ PCICFGA_reg_pba1c_v = 0x4c>>2, //use PCIPBAC_
++ PCICFGA_reg_pba1m_v = 0x50>>2,
++ PCICFGA_reg_pba2c_v = 0x54>>2, //use PCIPBAC_
++ PCICFGA_reg_pba2m_v = 0x58>>2,
++ PCICFGA_reg_pba3c_v = 0x5c>>2, //use PCIPBAC_
++ PCICFGA_reg_pba3m_v = 0x60>>2,
++ PCICFGA_reg_pmgt_v = 0x64>>2,
++ PCICFGA_func_b = 8,
++ PCICFGA_func_m = 0x00000700,
++ PCICFGA_dev_b = 11,
++ PCICFGA_dev_m = 0x0000f800,
++ PCICFGA_dev_internal_v = 0,
++ PCICFGA_bus_b = 16,
++ PCICFGA_bus_m = 0x00ff0000,
++ PCICFGA_bus_type0_v = 0, //local bus
++ PCICFGA_en_b = 31, // read only
++ PCICFGA_en_m = 0x80000000,
++} ;
++
++enum {
++ PCFGID_vendor_b = 0,
++ PCFGID_vendor_m = 0x0000ffff,
++ PCFGID_vendor_IDT_v = 0x111d,
++ PCFGID_device_b = 16,
++ PCFGID_device_m = 0xffff0000,
++ PCFGID_device_Korinade_v = 0x0214,
++
++ PCFG04_command_ioena_b = 1,
++ PCFG04_command_ioena_m = 0x00000001,
++ PCFG04_command_memena_b = 2,
++ PCFG04_command_memena_m = 0x00000002,
++ PCFG04_command_bmena_b = 3,
++ PCFG04_command_bmena_m = 0x00000004,
++ PCFG04_command_mwinv_b = 5,
++ PCFG04_command_mwinv_m = 0x00000010,
++ PCFG04_command_parena_b = 7,
++ PCFG04_command_parena_m = 0x00000040,
++ PCFG04_command_serrena_b = 9,
++ PCFG04_command_serrena_m = 0x00000100,
++ PCFG04_command_fastbbena_b = 10,
++ PCFG04_command_fastbbena_m = 0x00000200,
++ PCFG04_status_b = 16,
++ PCFG04_status_m = 0xffff0000,
++ PCFG04_status_66MHz_b = 21, // 66 MHz enable
++ PCFG04_status_66MHz_m = 0x00200000,
++ PCFG04_status_fbb_b = 23,
++ PCFG04_status_fbb_m = 0x00800000,
++ PCFG04_status_mdpe_b = 24,
++ PCFG04_status_mdpe_m = 0x01000000,
++ PCFG04_status_dst_b = 25,
++ PCFG04_status_dst_m = 0x06000000,
++ PCFG04_status_sta_b = 27,
++ PCFG04_status_sta_m = 0x08000000,
++ PCFG04_status_rta_b = 28,
++ PCFG04_status_rta_m = 0x10000000,
++ PCFG04_status_rma_b = 29,
++ PCFG04_status_rma_m = 0x20000000,
++ PCFG04_status_sse_b = 30,
++ PCFG04_status_sse_m = 0x40000000,
++ PCFG04_status_pe_b = 31,
++ PCFG04_status_pe_m = 0x40000000,
++
++ PCFG08_revId_b = 0,
++ PCFG08_revId_m = 0x000000ff,
++ PCFG08_classCode_b = 0,
++ PCFG08_classCode_m = 0xffffff00,
++ PCFG08_classCode_bridge_v = 06,
++ PCFG08_classCode_proc_v = 0x0b3000, // processor-MIPS
++ PCFG0C_cacheline_b = 0,
++ PCFG0C_cacheline_m = 0x000000ff,
++ PCFG0C_masterLatency_b = 8,
++ PCFG0C_masterLatency_m = 0x0000ff00,
++ PCFG0C_headerType_b = 16,
++ PCFG0C_headerType_m = 0x00ff0000,
++ PCFG0C_bist_b = 24,
++ PCFG0C_bist_m = 0xff000000,
++
++ PCIPBA_msi_b = 0,
++ PCIPBA_msi_m = 0x00000001,
++ PCIPBA_p_b = 3,
++ PCIPBA_p_m = 0x00000004,
++ PCIPBA_baddr_b = 8,
++ PCIPBA_baddr_m = 0xffffff00,
++
++ PCFGSS_vendorId_b = 0,
++ PCFGSS_vendorId_m = 0x0000ffff,
++ PCFGSS_id_b = 16,
++ PCFGSS_id_m = 0xffff0000,
++
++ PCFG3C_interruptLine_b = 0,
++ PCFG3C_interruptLine_m = 0x000000ff,
++ PCFG3C_interruptPin_b = 8,
++ PCFG3C_interruptPin_m = 0x0000ff00,
++ PCFG3C_minGrant_b = 16,
++ PCFG3C_minGrant_m = 0x00ff0000,
++ PCFG3C_maxLat_b = 24,
++ PCFG3C_maxLat_m = 0xff000000,
++
++ PCIPBAC_msi_b = 0,
++ PCIPBAC_msi_m = 0x00000001,
++ PCIPBAC_p_b = 1,
++ PCIPBAC_p_m = 0x00000002,
++ PCIPBAC_size_b = 2,
++ PCIPBAC_size_m = 0x0000007c,
++ PCIPBAC_sb_b = 7,
++ PCIPBAC_sb_m = 0x00000080,
++ PCIPBAC_pp_b = 8,
++ PCIPBAC_pp_m = 0x00000100,
++ PCIPBAC_mr_b = 9,
++ PCIPBAC_mr_m = 0x00000600,
++ PCIPBAC_mr_read_v =0, //no prefetching
++ PCIPBAC_mr_readLine_v =1,
++ PCIPBAC_mr_readMult_v =2,
++ PCIPBAC_mrl_b = 11,
++ PCIPBAC_mrl_m = 0x00000800,
++ PCIPBAC_mrm_b = 12,
++ PCIPBAC_mrm_m = 0x00001000,
++ PCIPBAC_trp_b = 13,
++ PCIPBAC_trp_m = 0x00002000,
++
++ PCFG40_trdyTimeout_b = 0,
++ PCFG40_trdyTimeout_m = 0x000000ff,
++ PCFG40_retryLim_b = 8,
++ PCFG40_retryLim_m = 0x0000ff00,
++};
++
++/*******************************************************************************
++ *
++ * PCI Local Base Address [0|1|2|3] Register
++ *
++ ******************************************************************************/
++enum {
++ PCILBA_baddr_b = 0, // In PCI_t -> pcilba [] .a
++ PCILBA_baddr_m = 0xffffff00,
++} ;
++/*******************************************************************************
++ *
++ * PCI Local Base Address Control Register
++ *
++ ******************************************************************************/
++enum {
++ PCILBAC_msi_b = 0, // In pPci->pcilba[i].c
++ PCILBAC_msi_m = 0x00000001,
++ PCILBAC_msi_mem_v = 0,
++ PCILBAC_msi_io_v = 1,
++ PCILBAC_size_b = 2, // In pPci->pcilba[i].c
++ PCILBAC_size_m = 0x0000007c,
++ PCILBAC_sb_b = 7, // In pPci->pcilba[i].c
++ PCILBAC_sb_m = 0x00000080,
++ PCILBAC_rt_b = 8, // In pPci->pcilba[i].c
++ PCILBAC_rt_m = 0x00000100,
++ PCILBAC_rt_noprefetch_v = 0, // mem read
++ PCILBAC_rt_prefetch_v = 1, // mem readline
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Local Base Address [0|1|2|3] Mapping Register
++ *
++ ******************************************************************************/
++enum {
++ PCILBAM_maddr_b = 8,
++ PCILBAM_maddr_m = 0xffffff00,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Decoupled Access Control Register
++ *
++ ******************************************************************************/
++enum {
++ PCIDAC_den_b = 0,
++ PCIDAC_den_m = 0x00000001,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI Decoupled Access Status Register
++ *
++ ******************************************************************************/
++enum {
++ PCIDAS_d_b = 0,
++ PCIDAS_d_m = 0x00000001,
++ PCIDAS_b_b = 1,
++ PCIDAS_b_m = 0x00000002,
++ PCIDAS_e_b = 2,
++ PCIDAS_e_m = 0x00000004,
++ PCIDAS_ofe_b = 3,
++ PCIDAS_ofe_m = 0x00000008,
++ PCIDAS_off_b = 4,
++ PCIDAS_off_m = 0x00000010,
++ PCIDAS_ife_b = 5,
++ PCIDAS_ife_m = 0x00000020,
++ PCIDAS_iff_b = 6,
++ PCIDAS_iff_m = 0x00000040,
++} ;
++
++/*******************************************************************************
++ *
++ * PCI DMA Channel 8 Configuration Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCIDMA8C_mbs_b = 0, // Maximum Burst Size.
++ PCIDMA8C_mbs_m = 0x00000fff, // { pcidma8c }
++ PCIDMA8C_our_b = 12, // Optimize Unaligned Burst Reads.
++ PCIDMA8C_our_m = 0x00001000, // { pcidma8c }
++} ;
++
++/*******************************************************************************
++ *
++ * PCI DMA Channel 9 Configuration Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCIDMA9C_mbs_b = 0, // Maximum Burst Size.
++ PCIDMA9C_mbs_m = 0x00000fff, // { pcidma9c }
++} ;
++
++/*******************************************************************************
++ *
++ * PCI to Memory(DMA Channel 8) AND Memory to PCI DMA(DMA Channel 9)Descriptors
++ *
++ ******************************************************************************/
++enum {
++ PCIDMAD_pt_b = 22, // in DEVCMD field (descriptor)
++ PCIDMAD_pt_m = 0x00c00000, // preferred transaction field
++ // These are for reads (DMA channel 8)
++ PCIDMAD_devcmd_mr_v = 0, //memory read
++ PCIDMAD_devcmd_mrl_v = 1, //memory read line
++ PCIDMAD_devcmd_mrm_v = 2, //memory read multiple
++ PCIDMAD_devcmd_ior_v = 3, //I/O read
++ // These are for writes (DMA channel 9)
++ PCIDMAD_devcmd_mw_v = 0, //memory write
++ PCIDMAD_devcmd_mwi_v = 1, //memory write invalidate
++ PCIDMAD_devcmd_iow_v = 3, //I/O write
++
++ // Swap byte field applies to both DMA channel 8 and 9
++ PCIDMAD_sb_b = 24, // in DEVCMD field (descriptor)
++ PCIDMAD_sb_m = 0x01000000, // swap byte field
++} ;
++
++
++/*******************************************************************************
++ *
++ * PCI Target Control Register
++ *
++ ******************************************************************************/
++enum
++{
++ PCITC_rtimer_b = 0, // In PCITC_t -> pcitc
++ PCITC_rtimer_m = 0x000000ff,
++ PCITC_dtimer_b = 8, // In PCITC_t -> pcitc
++ PCITC_dtimer_m = 0x0000ff00,
++ PCITC_rdr_b = 18, // In PCITC_t -> pcitc
++ PCITC_rdr_m = 0x00040000,
++ PCITC_ddt_b = 19, // In PCITC_t -> pcitc
++ PCITC_ddt_m = 0x00080000,
++} ;
++/*******************************************************************************
++ *
++ * PCI messaging unit [applies to both inbound and outbound registers ]
++ *
++ ******************************************************************************/
++enum
++{
++ PCIM_m0_b = 0, // In PCIM_t -> {pci{iic,iim,ioic,ioim}}
++ PCIM_m0_m = 0x00000001, // inbound or outbound message 0
++ PCIM_m1_b = 1, // In PCIM_t -> {pci{iic,iim,ioic,ioim}}
++ PCIM_m1_m = 0x00000002, // inbound or outbound message 1
++ PCIM_db_b = 2, // In PCIM_t -> {pci{iic,iim,ioic,ioim}}
++ PCIM_db_m = 0x00000004, // inbound or outbound doorbell
++};
++
++
++
++
++
++
++#define PCI_MSG_VirtualAddress 0xB8088010
++#define rc32434_pci ((volatile PCI_t) PCI0_VirtualAddress)
++#define rc32434_pci_msg ((volatile PCIM_t) PCI_MSG_VirtualAddress)
++
++#define PCIM_SHFT 0x6
++#define PCIM_BIT_LEN 0x7
++#define PCIM_H_EA 0x3
++#define PCIM_H_IA_FIX 0x4
++#define PCIM_H_IA_RR 0x5
++#if 0
++#define PCI_ADDR_START 0x13000000
++#endif
++
++#define PCI_ADDR_START 0x50000000
++
++#define CPUTOPCI_MEM_WIN 0x02000000
++#define CPUTOPCI_IO_WIN 0x00100000
++#define PCILBA_SIZE_SHFT 2
++#define PCILBA_SIZE_MASK 0x1F
++#define SIZE_256MB 0x1C
++#define SIZE_128MB 0x1B
++#define SIZE_64MB 0x1A
++#define SIZE_32MB 0x19
++#define SIZE_16MB 0x18
++#define SIZE_4MB 0x16
++#define SIZE_2MB 0x15
++#define SIZE_1MB 0x14
++#define KORINA_CONFIG0_ADDR 0x80000000
++#define KORINA_CONFIG1_ADDR 0x80000004
++#define KORINA_CONFIG2_ADDR 0x80000008
++#define KORINA_CONFIG3_ADDR 0x8000000C
++#define KORINA_CONFIG4_ADDR 0x80000010
++#define KORINA_CONFIG5_ADDR 0x80000014
++#define KORINA_CONFIG6_ADDR 0x80000018
++#define KORINA_CONFIG7_ADDR 0x8000001C
++#define KORINA_CONFIG8_ADDR 0x80000020
++#define KORINA_CONFIG9_ADDR 0x80000024
++#define KORINA_CONFIG10_ADDR 0x80000028
++#define KORINA_CONFIG11_ADDR 0x8000002C
++#define KORINA_CONFIG12_ADDR 0x80000030
++#define KORINA_CONFIG13_ADDR 0x80000034
++#define KORINA_CONFIG14_ADDR 0x80000038
++#define KORINA_CONFIG15_ADDR 0x8000003C
++#define KORINA_CONFIG16_ADDR 0x80000040
++#define KORINA_CONFIG17_ADDR 0x80000044
++#define KORINA_CONFIG18_ADDR 0x80000048
++#define KORINA_CONFIG19_ADDR 0x8000004C
++#define KORINA_CONFIG20_ADDR 0x80000050
++#define KORINA_CONFIG21_ADDR 0x80000054
++#define KORINA_CONFIG22_ADDR 0x80000058
++#define KORINA_CONFIG23_ADDR 0x8000005C
++#define KORINA_CONFIG24_ADDR 0x80000060
++#define KORINA_CONFIG25_ADDR 0x80000064
++#define KORINA_CMD (PCFG04_command_ioena_m | \
++ PCFG04_command_memena_m | \
++ PCFG04_command_bmena_m | \
++ PCFG04_command_mwinv_m | \
++ PCFG04_command_parena_m | \
++ PCFG04_command_serrena_m )
++
++#define KORINA_STAT (PCFG04_status_mdpe_m | \
++ PCFG04_status_sta_m | \
++ PCFG04_status_rta_m | \
++ PCFG04_status_rma_m | \
++ PCFG04_status_sse_m | \
++ PCFG04_status_pe_m)
++
++#define KORINA_CNFG1 ((KORINA_STAT<<16)|KORINA_CMD)
++
++#define KORINA_REVID 0
++#define KORINA_CLASS_CODE 0
++#define KORINA_CNFG2 ((KORINA_CLASS_CODE<<8) | \
++ KORINA_REVID)
++
++#define KORINA_CACHE_LINE_SIZE 4
++#define KORINA_MASTER_LAT 0x3c
++#define KORINA_HEADER_TYPE 0
++#define KORINA_BIST 0
++
++#define KORINA_CNFG3 ((KORINA_BIST << 24) | \
++ (KORINA_HEADER_TYPE<<16) | \
++ (KORINA_MASTER_LAT<<8) | \
++ KORINA_CACHE_LINE_SIZE )
++
++#define KORINA_BAR0 0x00000008 /* 128 MB Memory */
++#define KORINA_BAR1 0x18800001 /* 1 MB IO */
++#define KORINA_BAR2 0x18000001 /* 2 MB IO window for Korina
++ internal Registers */
++#define KORINA_BAR3 0x48000008 /* Spare 128 MB Memory */
++
++#define KORINA_CNFG4 KORINA_BAR0
++#define KORINA_CNFG5 KORINA_BAR1
++#define KORINA_CNFG6 KORINA_BAR2
++#define KORINA_CNFG7 KORINA_BAR3
++
++#define KORINA_SUBSYS_VENDOR_ID 0x011d
++#define KORINA_SUBSYSTEM_ID 0x0214
++#define KORINA_CNFG8 0
++#define KORINA_CNFG9 0
++#define KORINA_CNFG10 0
++#define KORINA_CNFG11 ((KORINA_SUBSYS_VENDOR_ID<<16) | \
++ KORINA_SUBSYSTEM_ID)
++#define KORINA_INT_LINE 1
++#define KORINA_INT_PIN 1
++#define KORINA_MIN_GNT 8
++#define KORINA_MAX_LAT 0x38
++#define KORINA_CNFG12 0
++#define KORINA_CNFG13 0
++#define KORINA_CNFG14 0
++#define KORINA_CNFG15 ((KORINA_MAX_LAT<<24) | \
++ (KORINA_MIN_GNT<<16) | \
++ (KORINA_INT_PIN<<8) | \
++ KORINA_INT_LINE)
++#define KORINA_RETRY_LIMIT 0x80
++#define KORINA_TRDY_LIMIT 0x80
++#define KORINA_CNFG16 ((KORINA_RETRY_LIMIT<<8) | \
++ KORINA_TRDY_LIMIT)
++#define PCI_PBAxC_R 0x0
++#define PCI_PBAxC_RL 0x1
++#define PCI_PBAxC_RM 0x2
++#define SIZE_SHFT 2
++
++#if defined(__MIPSEB__)
++#define KORINA_PBA0C ( PCIPBAC_mrl_m | PCIPBAC_sb_m | \
++ ((PCI_PBAxC_RM &0x3) << PCIPBAC_mr_b) | \
++ PCIPBAC_pp_m | \
++ (SIZE_128MB<<SIZE_SHFT) | \
++ PCIPBAC_p_m)
++#else
++#define KORINA_PBA0C ( PCIPBAC_mrl_m | \
++ ((PCI_PBAxC_RM &0x3) << PCIPBAC_mr_b) | \
++ PCIPBAC_pp_m | \
++ (SIZE_128MB<<SIZE_SHFT) | \
++ PCIPBAC_p_m)
++#endif
++#define KORINA_CNFG17 KORINA_PBA0C
++#define KORINA_PBA0M 0x0
++#define KORINA_CNFG18 KORINA_PBA0M
++
++#if defined(__MIPSEB__)
++#define KORINA_PBA1C ((SIZE_1MB<<SIZE_SHFT) | PCIPBAC_sb_m | \
++ PCIPBAC_msi_m)
++#else
++#define KORINA_PBA1C ((SIZE_1MB<<SIZE_SHFT) | \
++ PCIPBAC_msi_m)
++#endif
++#define KORINA_CNFG19 KORINA_PBA1C
++#define KORINA_PBA1M 0x0
++#define KORINA_CNFG20 KORINA_PBA1M
++
++#if defined(__MIPSEB__)
++#define KORINA_PBA2C ((SIZE_2MB<<SIZE_SHFT) | PCIPBAC_sb_m | \
++ PCIPBAC_msi_m)
++#else
++#define KORINA_PBA2C ((SIZE_2MB<<SIZE_SHFT) | \
++ PCIPBAC_msi_m)
++#endif
++#define KORINA_CNFG21 KORINA_PBA2C
++#define KORINA_PBA2M 0x18000000
++#define KORINA_CNFG22 KORINA_PBA2M
++#define KORINA_PBA3C 0
++#define KORINA_CNFG23 KORINA_PBA3C
++#define KORINA_PBA3M 0
++#define KORINA_CNFG24 KORINA_PBA3M
++
++
++
++#define PCITC_DTIMER_VAL 8
++#define PCITC_RTIMER_VAL 0x10
++
++
++
++
++#endif // __IDT_PCI_H__
++
++
++
+diff -urN linux.old/include/asm-mips/rc32434/pcikorina.h linux.dev/include/asm-mips/rc32434/pcikorina.h
+--- linux.old/include/asm-mips/rc32434/pcikorina.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/pcikorina.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,209 @@
++/* $Id: pciacacia.h,v 1.5 2001/05/01 10:09:17 carstenl Exp $
++ *
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ */
++#ifndef _PCIKORINA_H
++#define _PCIKORINA_H
++
++
++#define PCI_MSG_VirtualAddress 0xB8088010
++#define rc32434_pci ((volatile PCI_t) PCI0_VirtualAddress)
++#define rc32434_pci_msg ((volatile PCIM_t) PCI_MSG_VirtualAddress)
++
++#define PCIM_SHFT 0x6
++#define PCIM_BIT_LEN 0x7
++#define PCIM_H_EA 0x3
++#define PCIM_H_IA_FIX 0x4
++#define PCIM_H_IA_RR 0x5
++#if 0
++#define PCI_ADDR_START 0x13000000
++#endif
++
++#define PCI_ADDR_START 0x50000000
++
++#define CPUTOPCI_MEM_WIN 0x02000000
++#define CPUTOPCI_IO_WIN 0x00100000
++#define PCILBA_SIZE_SHFT 2
++#define PCILBA_SIZE_MASK 0x1F
++#define SIZE_256MB 0x1C
++#define SIZE_128MB 0x1B
++#define SIZE_64MB 0x1A
++#define SIZE_32MB 0x19
++#define SIZE_16MB 0x18
++#define SIZE_4MB 0x16
++#define SIZE_2MB 0x15
++#define SIZE_1MB 0x14
++#define KORINA_CONFIG0_ADDR 0x80000000
++#define KORINA_CONFIG1_ADDR 0x80000004
++#define KORINA_CONFIG2_ADDR 0x80000008
++#define KORINA_CONFIG3_ADDR 0x8000000C
++#define KORINA_CONFIG4_ADDR 0x80000010
++#define KORINA_CONFIG5_ADDR 0x80000014
++#define KORINA_CONFIG6_ADDR 0x80000018
++#define KORINA_CONFIG7_ADDR 0x8000001C
++#define KORINA_CONFIG8_ADDR 0x80000020
++#define KORINA_CONFIG9_ADDR 0x80000024
++#define KORINA_CONFIG10_ADDR 0x80000028
++#define KORINA_CONFIG11_ADDR 0x8000002C
++#define KORINA_CONFIG12_ADDR 0x80000030
++#define KORINA_CONFIG13_ADDR 0x80000034
++#define KORINA_CONFIG14_ADDR 0x80000038
++#define KORINA_CONFIG15_ADDR 0x8000003C
++#define KORINA_CONFIG16_ADDR 0x80000040
++#define KORINA_CONFIG17_ADDR 0x80000044
++#define KORINA_CONFIG18_ADDR 0x80000048
++#define KORINA_CONFIG19_ADDR 0x8000004C
++#define KORINA_CONFIG20_ADDR 0x80000050
++#define KORINA_CONFIG21_ADDR 0x80000054
++#define KORINA_CONFIG22_ADDR 0x80000058
++#define KORINA_CONFIG23_ADDR 0x8000005C
++#define KORINA_CONFIG24_ADDR 0x80000060
++#define KORINA_CONFIG25_ADDR 0x80000064
++#define KORINA_CMD (PCFG04_command_ioena_m | \
++ PCFG04_command_memena_m | \
++ PCFG04_command_bmena_m | \
++ PCFG04_command_mwinv_m | \
++ PCFG04_command_parena_m | \
++ PCFG04_command_serrena_m )
++
++#define KORINA_STAT (PCFG04_status_mdpe_m | \
++ PCFG04_status_sta_m | \
++ PCFG04_status_rta_m | \
++ PCFG04_status_rma_m | \
++ PCFG04_status_sse_m | \
++ PCFG04_status_pe_m)
++
++#define KORINA_CNFG1 ((KORINA_STAT<<16)|KORINA_CMD)
++
++#define KORINA_REVID 0
++#define KORINA_CLASS_CODE 0
++#define KORINA_CNFG2 ((KORINA_CLASS_CODE<<8) | \
++ KORINA_REVID)
++
++#define KORINA_CACHE_LINE_SIZE 4
++#define KORINA_MASTER_LAT 0x3c
++#define KORINA_HEADER_TYPE 0
++#define KORINA_BIST 0
++
++#define KORINA_CNFG3 ((KORINA_BIST << 24) | \
++ (KORINA_HEADER_TYPE<<16) | \
++ (KORINA_MASTER_LAT<<8) | \
++ KORINA_CACHE_LINE_SIZE )
++
++#define KORINA_BAR0 0x00000008 /* 128 MB Memory */
++#define KORINA_BAR1 0x18800001 /* 1 MB IO */
++#define KORINA_BAR2 0x18000001 /* 2 MB IO window for Acacia
++ internal Registers */
++#define KORINA_BAR3 0x48000008 /* Spare 128 MB Memory */
++
++#define KORINA_CNFG4 KORINA_BAR0
++#define KORINA_CNFG5 KORINA_BAR1
++#define KORINA_CNFG6 KORINA_BAR2
++#define KORINA_CNFG7 KORINA_BAR3
++
++#define KORINA_SUBSYS_VENDOR_ID 0
++#define KORINA_SUBSYSTEM_ID 0
++#define KORINA_CNFG8 0
++#define KORINA_CNFG9 0
++#define KORINA_CNFG10 0
++#define KORINA_CNFG11 ((KORINA_SUBSYS_VENDOR_ID<<16) | \
++ KORINA_SUBSYSTEM_ID)
++#define KORINA_INT_LINE 1
++#define KORINA_INT_PIN 1
++#define KORINA_MIN_GNT 8
++#define KORINA_MAX_LAT 0x38
++#define KORINA_CNFG12 0
++#define KORINA_CNFG13 0
++#define KORINA_CNFG14 0
++#define KORINA_CNFG15 ((KORINA_MAX_LAT<<24) | \
++ (KORINA_MIN_GNT<<16) | \
++ (KORINA_INT_PIN<<8) | \
++ KORINA_INT_LINE)
++#define KORINA_RETRY_LIMIT 0x80
++#define KORINA_TRDY_LIMIT 0x80
++#define KORINA_CNFG16 ((KORINA_RETRY_LIMIT<<8) | \
++ KORINA_TRDY_LIMIT)
++#define PCI_PBAxC_R 0x0
++#define PCI_PBAxC_RL 0x1
++#define PCI_PBAxC_RM 0x2
++#define SIZE_SHFT 2
++
++#ifdef __MIPSEB__
++#define KORINA_PBA0C ( PCIPBAC_mrl_m | PCIPBAC_sb_m | \
++ ((PCI_PBAxC_RM &0x3) << PCIPBAC_mr_b) | \
++ PCIPBAC_pp_m | \
++ (SIZE_32MB<<SIZE_SHFT) | \
++ PCIPBAC_p_m)
++#else
++#define KORINA_PBA0C ( PCIPBAC_mrl_m | \
++ ((PCI_PBAxC_RM &0x3) << PCIPBAC_mr_b) | \
++ PCIPBAC_pp_m | \
++ (SIZE_32MB<<SIZE_SHFT) | \
++ PCIPBAC_p_m)
++#endif
++
++#if 0
++
++#define KORINA_PBA0C ( PCIPBAC_sb_m | PCIPBAC_pp_m | \
++ ((PCI_PBAxC_R &0x3) << PCIPBAC_mr_b) | \
++ (SIZE_128MB<<SIZE_SHFT))
++#endif
++#define KORINA_CNFG17 KORINA_PBA0C
++#define KORINA_PBA0M 0x0
++#define KORINA_CNFG18 KORINA_PBA0M
++
++#ifdef __MIPSEB__
++#define KORINA_PBA1C ((SIZE_1MB<<SIZE_SHFT) | PCIPBAC_sb_m | \
++ PCIPBAC_msi_m)
++#else
++#define KORINA_PBA1C ((SIZE_1MB<<SIZE_SHFT) | \
++ PCIPBAC_msi_m)
++
++#endif
++
++#define KORINA_CNFG19 KORINA_PBA1C
++#define KORINA_PBA1M 0x0
++#define KORINA_CNFG20 KORINA_PBA1M
++
++#ifdef __MIPSEB__
++#define KORINA_PBA2C ((SIZE_2MB<<SIZE_SHFT) | PCIPBAC_sb_m | \
++ PCIPBAC_msi_m)
++#else
++#define KORINA_PBA2C ((SIZE_2MB<<SIZE_SHFT) | \
++ PCIPBAC_msi_m)
++
++#endif
++#define KORINA_CNFG21 KORINA_PBA2C
++#define KORINA_PBA2M 0x18000000
++#define KORINA_CNFG22 KORINA_PBA2M
++#define KORINA_PBA3C 0
++#define KORINA_CNFG23 KORINA_PBA3C
++#define KORINA_PBA3M 0
++#define KORINA_CNFG24 KORINA_PBA3M
++
++
++
++#define PCITC_DTIMER_VAL 8
++#define PCITC_RTIMER_VAL 0x10
++
++
++#endif /* _PCIKORINA_H */
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+diff -urN linux.old/include/asm-mips/rc32434/pci_regs.h linux.dev/include/asm-mips/rc32434/pci_regs.h
+--- linux.old/include/asm-mips/rc32434/pci_regs.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/pci_regs.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,8 @@
++/* Override the default address space for this arch
++*/
++
++#include <linux/pci_regs.h>
++
++//#undef PCI_BASE_ADDRESS_SPACE
++//#define PCI_BASE_ADDRESS_SPACE PCI_BASE_ADDRESS_SPACE_MEMORY
++
+diff -urN linux.old/include/asm-mips/rc32434/rb.h linux.dev/include/asm-mips/rc32434/rb.h
+--- linux.old/include/asm-mips/rc32434/rb.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/rb.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,69 @@
++#ifndef __MIPS_RB_H__
++#define __MIPS_RB_H__
++#include <linux/genhd.h>
++
++#define IDT434_REG_BASE ((volatile void *) KSEG1ADDR(0x18000000))
++#define DEV0BASE 0x010000
++#define DEV0MASK 0x010004
++#define DEV0C 0x010008
++#define DEV0TC 0x01000C
++#define DEV1BASE 0x010010
++#define DEV1MASK 0x010014
++#define DEV1C 0x010018
++#define DEV1TC 0x01001C
++#define DEV2BASE 0x010020
++#define DEV2MASK 0x010024
++#define DEV2C 0x010028
++#define DEV2TC 0x01002C
++#define DEV3BASE 0x010030
++#define DEV3MASK 0x010034
++#define DEV3C 0x010038
++#define DEV3TC 0x01003C
++#define BTCS 0x010040
++#define BTCOMPARE 0x010044
++#define GPIOFUNC 0x050000
++#define GPIOCFG 0x050004
++#define GPIOD 0x050008
++#define GPIOILEVEL 0x05000C
++#define GPIOISTAT 0x050010
++#define GPIONMIEN 0x050014
++#define IMASK6 0x038038
++
++#define LO_WPX (1 << 0)
++#define LO_ALE (1 << 1)
++#define LO_CLE (1 << 2)
++#define LO_CEX (1 << 3)
++#define LO_FOFF (1 << 5)
++#define LO_SPICS (1 << 6)
++#define LO_ULED (1 << 7)
++
++typedef enum {
++ FUNC = 0x00,
++ CFG = 0x04,
++ DATA = 0x08,
++ ILEVEL = 0x0c,
++ ISTAT = 0x10,
++ NMIEN = 0x14
++} gpio_func;
++
++extern void changeLatchU5(unsigned char orMask, unsigned char nandMask);
++extern unsigned get434Reg(unsigned regOffs);
++extern void set434Reg(unsigned regOffs, unsigned bit, unsigned len, unsigned val);
++extern void gpio_set(gpio_func func, u32 mask, u32 value);
++extern u32 gpio_get(gpio_func func);
++
++#define get434Reg(x) (*(volatile unsigned *) (IDT434_REG_BASE + (x)))
++
++struct korina_device {
++ char *name;
++ unsigned char mac[6];
++ struct net_device *dev;
++};
++
++struct cf_device {
++ int gpio_pin;
++ void *dev;
++ struct gendisk *gd;
++};
++
++#endif
+diff -urN linux.old/include/asm-mips/rc32434/rc32434.h linux.dev/include/asm-mips/rc32434/rc32434.h
+--- linux.old/include/asm-mips/rc32434/rc32434.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/rc32434.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,126 @@
++/*
++ ***************************************************************************
++ * Definitions for IDT RC323434 CPU.
++ *
++ ****************************************************************************
++ * Kiran Rao
++ *
++ * Original form
++ ****************************************************************************
++ * P. Sadik Oct 08, 2003
++ *
++ * Started revision history
++ * Made IDT_BUS_FREQ a kernel configuration parameter
++ ****************************************************************************
++ * P. Sadik Oct 10, 2003
++ *
++ * Removed IDT_BUS_FREQ, since this parameter is no longer required. Instead
++ * idt_cpu_freq is used everywhere
++ ****************************************************************************
++ * P. Sadik Oct 20, 2003
++ *
++ * Removed RC32434_BASE_BAUD
++ ****************************************************************************
++*/
++#ifndef _RC32434_H_
++#define _RC32434_H_
++
++#include <linux/config.h>
++#include <linux/delay.h>
++#include <asm/io.h>
++#include <asm/rc32434/timer.h>
++
++#define RC32434_REG_BASE 0x18000000
++
++#define interrupt ((volatile INT_t ) INT0_VirtualAddress)
++#define timer ((volatile TIM_t) TIM0_VirtualAddress)
++#define gpio ((volatile GPIO_t) GPIO0_VirtualAddress)
++
++#define IDT_CLOCK_MULT 2
++#define MIPS_CPU_TIMER_IRQ 7
++/* Interrupt Controller */
++#define IC_GROUP0_PEND (RC32434_REG_BASE + 0x38000)
++#define IC_GROUP0_MASK (RC32434_REG_BASE + 0x38008)
++#define IC_GROUP_OFFSET 0x0C
++
++#define NUM_INTR_GROUPS 5
++/* 16550 UARTs */
++
++#define GROUP0_IRQ_BASE 8 /* GRP2 IRQ numbers start here */
++#define GROUP1_IRQ_BASE (GROUP0_IRQ_BASE + 32) /* GRP3 IRQ numbers start here */
++#define GROUP2_IRQ_BASE (GROUP1_IRQ_BASE + 32) /* GRP4 IRQ numbers start here */
++#define GROUP3_IRQ_BASE (GROUP2_IRQ_BASE + 32) /* GRP5 IRQ numbers start here */
++#define GROUP4_IRQ_BASE (GROUP3_IRQ_BASE + 32)
++
++
++#ifdef __MIPSEB__
++#define RC32434_UART0_BASE (RC32434_REG_BASE + 0x58003)
++#else
++#define RC32434_UART0_BASE (RC32434_REG_BASE + 0x58000)
++#endif
++
++#define RC32434_UART0_IRQ GROUP3_IRQ_BASE + 0
++// #define EB434_UART1_IRQ GROUP4_IRQ_BASE + 11
++
++#define local_readl(addr) __raw_readl(addr)
++#define local_writel(l,addr) __raw_writel(l,addr)
++
++/* cpu pipeline flush */
++static inline void rc32434_sync(void)
++{
++ __asm__ volatile ("sync");
++}
++
++static inline void rc32434_sync_udelay(int us)
++{
++ __asm__ volatile ("sync");
++ udelay(us);
++}
++
++static inline void rc32434_sync_delay(int ms)
++{
++ __asm__ volatile ("sync");
++ mdelay(ms);
++}
++
++/*
++ * C access to CLZ and CLO instructions
++ * (count leading zeroes/ones).
++ */
++static inline int rc32434_clz(unsigned long val)
++{
++ int ret;
++ __asm__ volatile (
++ ".set\tnoreorder\n\t"
++ ".set\tnoat\n\t"
++ ".set\tmips32\n\t"
++ "clz\t%0,%1\n\t"
++ ".set\tmips0\n\t"
++ ".set\tat\n\t"
++ ".set\treorder"
++ : "=r" (ret)
++ : "r" (val));
++
++ return ret;
++}
++static inline int rc32434_clo(unsigned long val)
++{
++ int ret;
++ __asm__ volatile (
++ ".set\tnoreorder\n\t"
++ ".set\tnoat\n\t"
++ ".set\tmips32\n\t"
++ "clo\t%0,%1\n\t"
++ ".set\tmips0\n\t"
++ ".set\tat\n\t"
++ ".set\treorder"
++ : "=r" (ret)
++ : "r" (val));
++
++ return ret;
++}
++
++extern void cons_putc(char c);
++extern void cons_puts(char *s);
++
++#endif /* _RC32434_H_ */
+diff -urN linux.old/include/asm-mips/rc32434/rst.h linux.dev/include/asm-mips/rc32434/rst.h
+--- linux.old/include/asm-mips/rc32434/rst.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/rst.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,105 @@
++#ifndef __IDT_RST_H__
++#define __IDT_RST_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * Reset register definitions.
++ *
++ * File : $Id: rst.h,v 1.2 2002/06/06 18:34:05 astichte Exp $
++ *
++ * Author : Allen.Stichter@idt.com
++ * Date : 20020118
++ * Update :
++ * $Log: rst.h,v $
++ * Revision 1.2 2002/06/06 18:34:05 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.1 2002/05/29 17:33:24 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ *
++ ******************************************************************************/
++
++#include <asm/rc32434/types.h>
++
++enum
++{
++ RST0_PhysicalAddress = 0x18000000,
++ RST_PhysicalAddress = RST0_PhysicalAddress, // Default
++
++ RST0_VirtualAddress = 0xb8000000,
++ RST_VirtualAddress = RST0_VirtualAddress, // Default
++} ;
++
++typedef struct RST_s
++{
++ U32 filler [0x0006] ;
++ U32 sysid ;
++ U32 filler2 [0x2000-8] ; // Pad out to offset 0x8000
++ U32 reset ;
++ U32 bcv ;
++ U32 cea ;
++} volatile * RST_t ;
++
++enum
++{
++ SYSID_rev_b = 0,
++ SYSID_rev_m = 0x000000ff,
++ SYSID_imp_b = 8,
++ SYSID_imp_m = 0x000fff00,
++ SYSID_vendor_b = 20,
++ SYSID_vendor_m = 0xfff00000,
++
++ BCV_pll_b = 0,
++ BCV_pll_m = 0x0000000f,
++ BCV_pll_PLLBypass_v = 0x0, // PCLK=1*CLK.
++ BCV_pll_Mul3_v = 0x1, // PCLK=3*CLK.
++ BCV_pll_Mul4_v = 0x2, // PCLK=4*CLK.
++ BCV_pll_SlowMul5_v = 0x3, // PCLK=4*CLK.
++ BCV_pll_Mul5_v = 0x4, // PCLK=6*CLK.
++ BCV_pll_SlowMul6_v = 0x5, // PCLK=8*CLK.
++ BCV_pll_Mul6_v = 0x6, // PCLK=8*CLK.
++ BCV_pll_Mul8_v = 0x7, // PCLK=8*CLK.
++ BCV_pll_Mul10_v = 0x8, // PCLK=8*CLK.
++ BCV_pll_Res5_v = 0x9,
++ BCV_pll_Res6_v = 0xa,
++ BCV_pll_Res7_v = 0xb,
++ BCV_pll_Res8_v = 0xc,
++ BCV_pll_Res13_v = 0xd,
++ BCV_pll_Res14_v = 0xe,
++ BCV_pll_Res15_v = 0xf,
++ BCV_clkDiv_b = 4,
++ BCV_clkDiv_m = 0x00000030,
++ BCV_clkDiv_Div1_v = 0x0,
++ BCV_clkDiv_Div2_v = 0x1,
++ BCV_clkDiv_Div4_v = 0x2,
++ BCV_clkDiv_Res3_v = 0x3,
++ BCV_bigEndian_b = 6,
++ BCV_bigEndian_m = 0x00000040,
++ BCV_resetFast_b = 7,
++ BCV_resetFast_m = 0x00000080,
++ BCV_pciMode_b = 8,
++ BCV_pciMode_m = 0x00000100,
++ BCV_pciMode_disabled_v = 0, // PCI is disabled.
++ BCV_pciMode_tnr_v = 1, // satellite Target Not Ready.
++ BCV_pciMode_suspended_v = 2, // satellite with suspended CPU.
++ BCV_pciMode_external_v = 3, // host, external arbiter.
++ BCV_pciMode_fixed_v = 4, // host, fixed priority arbiter.
++ BCV_pciMode_roundRobin_v= 5, // host, round robin arbiter.
++ BCV_pciMode_res6_v = 6,
++ BCV_pciMode_res7_v = 7,
++ BCV_watchDisable_b = 11,
++ BCV_watchDisable_m = 0x00000800,
++ BCV_pllTest_b = 12,
++ BCV_pllTest_m = 0x00001000,
++ BCV_nvramInit_b = 13,
++ BCV_nvramInit_m = 0x00002000,
++ BCV_clksyncTstMd_b = 14,
++ BCV_clksyncTstMd_m = 0x00004000,
++ BCV_delayBypass_b = 15,
++ BCV_delayByPass_m = 0x00008000,
++} ;
++#endif // __IDT_RST_H__
+diff -urN linux.old/include/asm-mips/rc32434/spi.h linux.dev/include/asm-mips/rc32434/spi.h
+--- linux.old/include/asm-mips/rc32434/spi.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/spi.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,100 @@
++#ifndef __IDT_SPI_H__
++#define __IDT_SPI_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * Serial Peripheral Interface register definitions.
++ *
++ * File : $Id: spi.h,v 1.2 2002/06/06 18:34:05 astichte Exp $
++ *
++ * Author : ryan.holmQVist@idt.com
++ * Date : 20011005
++ * Update :
++ * $Log: spi.h,v $
++ * Revision 1.2 2002/06/06 18:34:05 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.1 2002/05/29 17:33:25 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ *
++ ******************************************************************************/
++
++#include <asm/rc32434/types.h>
++
++enum
++{
++ SPI0_PhysicalAddress = 0x18070000,
++ SPI_PhysicalAddress = SPI0_PhysicalAddress,
++
++ SPI0_VirtualAddress = 0xb8070000,
++ SPI_VirtualAddress = SPI0_VirtualAddress,
++} ;
++
++typedef struct
++{
++ U32 spcp ; // prescalar. 0=off, * spiClk = sysClk/(2*(spcp+1)*SPR)
++ U32 spc ; // spi control reg use SPC_
++ U32 sps ; // spi status reg use SPS_
++ U32 spd ; // spi data reg use SPD_
++ U32 siofunc ; // serial IO function use SIOFUNC_
++ U32 siocfg ; // serial IO config use SIOCFG_
++ U32 siod; // serial IO data use SIOD_
++} volatile *SPI_t ;
++
++enum
++{
++ SPCP_div_b = 0,
++ SPCP_div_m = 0x000000ff,
++ SPC_spr_b = 0,
++ SPC_spr_m = 0x00000003,
++ SPC_spr_div2_v = 0,
++ SPC_spr_div4_v = 1,
++ SPC_spr_div16_v = 2,
++ SPC_spr_div32_v = 3,
++ SPC_cpha_b = 2,
++ SPC_cpha_m = 0x00000004,
++ SPC_cpol_b = 3,
++ SPC_cpol_m = 0x00000008,
++ SPC_mstr_b = 4,
++ SPC_mstr_m = 0x00000010,
++ SPC_spe_b = 6,
++ SPC_spe_m = 0x00000040,
++ SPC_spie_b = 7,
++ SPC_spie_m = 0x00000080,
++
++ SPS_modf_b = 4,
++ SPS_modf_m = 0x00000010,
++ SPS_wcol_b = 6,
++ SPS_wcol_m = 0x00000040,
++ SPS_spif_b = 7,
++ SPS_spif_m = 0x00000070,
++
++ SPD_data_b = 0,
++ SPD_data_m = 0x000000ff,
++
++ SIOFUNC_sdo_b = 0,
++ SIOFUNC_sdo_m = 0x00000001,
++ SIOFUNC_sdi_b = 1,
++ SIOFUNC_sdi_m = 0x00000002,
++ SIOFUNC_sck_b = 2,
++ SIOFUNC_sck_m = 0x00000004,
++
++ SIOCFG_sdo_b = 0,
++ SIOCFG_sdo_m = 0x00000001,
++ SIOCFG_sdi_b = 1,
++ SIOCFG_sdi_m = 0x00000002,
++ SIOCFG_sck_b = 2,
++ SIOCFG_sck_m = 0x00000004,
++
++ SIOD_sdo_b = 0,
++ SIOD_sdo_m = 0x00000001,
++ SIOD_sdi_b = 1,
++ SIOD_sdi_m = 0x00000002,
++ SIOD_sck_b = 2,
++ SIOD_sck_m = 0x00000004,
++} ;
++#endif // __IDT_SPI_H__
+diff -urN linux.old/include/asm-mips/rc32434/timer.h linux.dev/include/asm-mips/rc32434/timer.h
+--- linux.old/include/asm-mips/rc32434/timer.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/timer.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,91 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Definitions for timer registers
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt,neb.
++ *
++ * Initial Release
++ *
++ *
++ *
++ **************************************************************************
++ */
++
++#ifndef __IDT_TIM_H__
++#define __IDT_TIM_H__
++
++enum
++{
++ TIM0_PhysicalAddress = 0x18028000,
++ TIM_PhysicalAddress = TIM0_PhysicalAddress, // Default
++
++ TIM0_VirtualAddress = 0xb8028000,
++ TIM_VirtualAddress = TIM0_VirtualAddress, // Default
++} ;
++
++enum
++{
++ TIM_Count = 3,
++} ;
++
++struct TIM_CNTR_s
++{
++ u32 count ;
++ u32 compare ;
++ u32 ctc ; //use CTC_
++} ;
++
++typedef struct TIM_s
++{
++ struct TIM_CNTR_s tim [TIM_Count] ;
++ u32 rcount ; //use RCOUNT_
++ u32 rcompare ; //use RCOMPARE_
++ u32 rtc ; //use RTC_
++} volatile * TIM_t ;
++
++enum
++{
++ CTC_en_b = 0,
++ CTC_en_m = 0x00000001,
++ CTC_to_b = 1,
++ CTC_to_m = 0x00000002,
++
++ RCOUNT_count_b = 0,
++ RCOUNT_count_m = 0x0000ffff,
++ RCOMPARE_compare_b = 0,
++ RCOMPARE_compare_m = 0x0000ffff,
++ RTC_ce_b = 0,
++ RTC_ce_m = 0x00000001,
++ RTC_to_b = 1,
++ RTC_to_m = 0x00000002,
++ RTC_rqe_b = 2,
++ RTC_rqe_m = 0x00000004,
++
++} ;
++#endif // __IDT_TIM_H__
++
+diff -urN linux.old/include/asm-mips/rc32434/tim.h linux.dev/include/asm-mips/rc32434/tim.h
+--- linux.old/include/asm-mips/rc32434/tim.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/tim.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,78 @@
++#ifndef __IDT_TIM_H__
++#define __IDT_TIM_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * Timer register definition.
++ *
++ * File : $Id: tim.h,v 1.2 2002/06/06 18:34:05 astichte Exp $
++ *
++ * Author : ryan.holmQVist@idt.com
++ * Date : 20011005
++ * Update :
++ * $Log: tim.h,v $
++ * Revision 1.2 2002/06/06 18:34:05 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.1 2002/05/29 17:33:25 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ *
++ ******************************************************************************/
++
++
++#include <asm/rc32434/types.h>
++
++enum
++{
++ TIM0_PhysicalAddress = 0x18028000,
++ TIM_PhysicalAddress = TIM0_PhysicalAddress, // Default
++
++ TIM0_VirtualAddress = 0xb8028000,
++ TIM_VirtualAddress = TIM0_VirtualAddress, // Default
++} ;
++
++enum
++{
++ TIM_Count = 3,
++} ;
++
++struct TIM_CNTR_s
++{
++ U32 count ;
++ U32 compare ;
++ U32 ctc ; //use CTC_
++} ;
++
++typedef struct TIM_s
++{
++ struct TIM_CNTR_s tim [TIM_Count] ;
++ U32 rcount ; //use RCOUNT_
++ U32 rcompare ; //use RCOMPARE_
++ U32 rtc ; //use RTC_
++} volatile * TIM_t ;
++
++enum
++{
++ CTC_en_b = 0,
++ CTC_en_m = 0x00000001,
++ CTC_to_b = 1,
++ CTC_to_m = 0x00000002,
++
++ RCOUNT_count_b = 0,
++ RCOUNT_count_m = 0x0000ffff,
++ RCOMPARE_compare_b = 0,
++ RCOMPARE_compare_m = 0x0000ffff,
++ RTC_ce_b = 0,
++ RTC_ce_m = 0x00000001,
++ RTC_to_b = 1,
++ RTC_to_m = 0x00000002,
++ RTC_rqe_b = 2,
++ RTC_rqe_m = 0x00000004,
++
++} ;
++#endif // __IDT_TIM_H__
++
+diff -urN linux.old/include/asm-mips/rc32434/types.h linux.dev/include/asm-mips/rc32434/types.h
+--- linux.old/include/asm-mips/rc32434/types.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/types.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,39 @@
++#ifndef __IDT_TYPES_H__
++#define __IDT_TYPES_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * Common typedefs used in IDT-generated code.
++ *
++ * File : $Id: types.h,v 1.1 2002/06/06 16:16:56 astichte Exp $
++ *
++ * Author : Allen.Stichter@idt.com
++ * Date : 20020606
++ * Update :
++ * $Log: types.h,v $
++ * Revision 1.1 2002/06/06 16:16:56 astichte
++ * Added
++ *
++ *
++ ******************************************************************************/
++
++typedef unsigned char U8 ;
++typedef signed char S8 ;
++
++typedef unsigned short U16 ;
++typedef signed short S16 ;
++
++typedef unsigned int U32 ;
++typedef signed int S32 ;
++
++typedef unsigned long long U64 ;
++typedef signed long long S64 ;
++
++#ifndef __cplusplus
++ typedef U32 bool ; // (false == 0), (true is != false)
++#endif // __cplusplus
++
++#endif // __IDT_TYPES_H__
+diff -urN linux.old/include/asm-mips/rc32434/uart.h linux.dev/include/asm-mips/rc32434/uart.h
+--- linux.old/include/asm-mips/rc32434/uart.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/include/asm-mips/rc32434/uart.h 2006-10-11 21:56:38.000000000 +0200
+@@ -0,0 +1,178 @@
++#ifndef __IDT_UART_H__
++#define __IDT_UART_H__
++
++/*******************************************************************************
++ *
++ * Copyright 2002 Integrated Device Technology, Inc.
++ * All rights reserved.
++ *
++ * UART register definitions.
++ *
++ * File : $Id: uart.h,v 1.3 2002/06/06 18:34:05 astichte Exp $
++ *
++ * Author : Allen.Stichter@idt.com
++ * Date : 20020118
++ * Update :
++ * $Log: uart.h,v $
++ * Revision 1.3 2002/06/06 18:34:05 astichte
++ * Added XXX_PhysicalAddress and XXX_VirtualAddress
++ *
++ * Revision 1.2 2002/06/04 17:37:52 astichte
++ * Updated register definitions.
++ *
++ * Revision 1.1 2002/05/29 17:33:25 sysarch
++ * jba File moved from vcode/include/idt/acacia
++ *
++ *
++ ******************************************************************************/
++
++#include <asm/rc32434/types.h>
++
++enum
++{
++ UART_PhysicalAddress = 0x18058000,
++ UART_PhysicalAddress = UART_PhysicalAddress, // Default
++
++ UART_VirtualAddress = 0xb8058000,
++ UART_VirtualAddress = UART_VirtualAddress, // Default
++} ;
++
++/*
++ * Register definitions are in bytes so we can handle endian problems.
++ */
++
++typedef struct UART_s
++{
++ union
++ {
++ U32 const uartrb ; // 0x00 - DLAB=0, read.
++ U32 uartth ; // 0x00 - DLAB=0, write.
++ U32 uartdll ; // 0x00 - DLAB=1, read/write.
++ } ;
++
++ union
++ {
++ U32 uartie ; // 0x04 - DLAB=0, read/write.
++ U32 uartdlh ; // 0x04 - DLAB=1, read/write.
++ } ;
++ union
++ {
++ U32 const uartii ; // 0x08 - DLAB=0, read.
++ U32 uartfc ; // 0x08 - DLAB=0, write.
++ } ;
++
++ U32 uartlc ; // 0x0c
++ U32 uartmc ; // 0x10
++ U32 uartls ; // 0x14
++ U32 uartms ; // 0x18
++ U32 uarts ; // 0x1c
++} volatile *UART_t ;
++
++// Reset registers.
++typedef U32 volatile *UARTRR_t ;
++
++enum
++{
++ UARTIE_rda_b = 0,
++ UARTIE_rda_m = 0x00000001,
++ UARTIE_the_b = 1,
++ UARTIE_the_m = 0x00000002,
++ UARTIE_rls_b = 2,
++ UARTIE_rls_m = 0x00000004,
++ UARTIE_ems_b = 3,
++ UARTIE_ems_m = 0x00000008,
++
++ UARTII_pi_b = 0,
++ UARTII_pi_m = 0x00000001,
++ UARTII_iid_b = 1,
++ UARTII_iid_m = 0x0000000e,
++ UARTII_iid_ms_v = 0, // Modem stat-CTS,DSR,RI or DCD.
++ UARTII_iid_thre_v = 1, // Trans. Holding Reg. empty.
++ UARTII_iid_rda_v = 2, // Receive data available
++ UARTII_iid_rls_v = 3, // Overrun, parity, etc, error.
++ UARTII_iid_res4_v = 4, // reserved.
++ UARTII_iid_res5_v = 5, // reserved.
++ UARTII_iid_cto_v = 6, // Character timeout.
++ UARTII_iid_res7_v = 7, // reserved.
++
++ UARTFC_en_b = 0,
++ UARTFC_en_m = 0x00000001,
++ UARTFC_rr_b = 1,
++ UARTFC_rr_m = 0x00000002,
++ UARTFC_tr_b = 2,
++ UARTFC_tr_m = 0x00000004,
++ UARTFC_dms_b = 3,
++ UARTFC_dms_m = 0x00000008,
++ UARTFC_rt_b = 6,
++ UARTFC_rt_m = 0x000000c0,
++ UARTFC_rt_1Byte_v = 0,
++ UARTFC_rt_4Byte_v = 1,
++ UARTFC_rt_8Byte_v = 2,
++ UARTFC_rt_14Byte_v = 3,
++
++ UARTLC_wls_b = 0,
++ UARTLC_wls_m = 0x00000003,
++ UARTLC_wls_5Bits_v = 0,
++ UARTLC_wls_6Bits_v = 1,
++ UARTLC_wls_7Bits_v = 2,
++ UARTLC_wls_8Bits_v = 3,
++ UARTLC_stb_b = 2,
++ UARTLC_stb_m = 0x00000004,
++ UARTLC_pen_b = 3,
++ UARTLC_pen_m = 0x00000008,
++ UARTLC_eps_b = 4,
++ UARTLC_eps_m = 0x00000010,
++ UARTLC_sp_b = 5,
++ UARTLC_sp_m = 0x00000020,
++ UARTLC_sb_b = 6,
++ UARTLC_sb_m = 0x00000040,
++ UARTLC_dlab_b = 7,
++ UARTLC_dlab_m = 0x00000080,
++
++ UARTMC_dtr_b = 0,
++ UARTMC_dtr_m = 0x00000001,
++ UARTMC_rts_b = 1,
++ UARTMC_rts_m = 0x00000002,
++ UARTMC_o1_b = 2,
++ UARTMC_o1_m = 0x00000004,
++ UARTMC_o2_b = 3,
++ UARTMC_o2_m = 0x00000008,
++ UARTMC_lp_b = 4,
++ UARTMC_lp_m = 0x00000010,
++
++ UARTLS_dr_b = 0,
++ UARTLS_dr_m = 0x00000001,
++ UARTLS_oe_b = 1,
++ UARTLS_oe_m = 0x00000002,
++ UARTLS_pe_b = 2,
++ UARTLS_pe_m = 0x00000004,
++ UARTLS_fe_b = 3,
++ UARTLS_fe_m = 0x00000008,
++ UARTLS_bi_b = 4,
++ UARTLS_bi_m = 0x00000010,
++ UARTLS_thr_b = 5,
++ UARTLS_thr_m = 0x00000020,
++ UARTLS_te_b = 6,
++ UARTLS_te_m = 0x00000040,
++ UARTLS_rfe_b = 7,
++ UARTLS_rfe_m = 0x00000080,
++
++ UARTMS_dcts_b = 0,
++ UARTMS_dcts_m = 0x00000001,
++ UARTMS_ddsr_b = 1,
++ UARTMS_ddsr_m = 0x00000002,
++ UARTMS_teri_b = 2,
++ UARTMS_teri_m = 0x00000004,
++ UARTMS_ddcd_b = 3,
++ UARTMS_ddcd_m = 0x00000008,
++ UARTMS_cts_b = 4,
++ UARTMS_cts_m = 0x00000010,
++ UARTMS_dsr_b = 5,
++ UARTMS_dsr_m = 0x00000020,
++ UARTMS_ri_b = 6,
++ UARTMS_ri_m = 0x00000040,
++ UARTMS_dcd_b = 7,
++ UARTMS_dcd_m = 0x00000080,
++} ;
++
++#endif // __IDT_UART_H__
diff --git a/target/linux/rb532-2.6/patches/110-korina_ethernet.patch b/target/linux/rb532-2.6/patches/110-korina_ethernet.patch
new file mode 100644
index 0000000..723bc4f
--- /dev/null
+++ b/target/linux/rb532-2.6/patches/110-korina_ethernet.patch
@@ -0,0 +1,1375 @@
+diff -urN linux.old/drivers/net/Kconfig linux.dev/drivers/net/Kconfig
+--- linux.old/drivers/net/Kconfig 2006-06-08 20:21:20.000000000 +0200
++++ linux.dev/drivers/net/Kconfig 2006-06-08 20:19:40.000000000 +0200
+@@ -310,6 +310,13 @@
+
+ source "drivers/net/arm/Kconfig"
+
++config KORINA
++ tristate "Korina Local Ethernet support"
++ depends on NET_ETHERNET && ( IDT_EB434 || MIKROTIK_RB500)
++ help
++ IDT RC32434 has one local ethernet port. Say Y here to enable it.
++ To compile this driver as a module, choose M here.
++
+ config MACE
+ tristate "MACE (Power Mac ethernet) support"
+ depends on NET_ETHERNET && PPC_PMAC && PPC32
+diff -urN linux.old/drivers/net/korina.c linux.dev/drivers/net/korina.c
+--- linux.old/drivers/net/korina.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/korina.c 2006-06-09 00:48:40.000000000 +0200
+@@ -0,0 +1,1159 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Driver for the IDT RC32434 on-chip ethernet controller.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Based on the driver developed by B. Maruthanayakam, H. Kou and others.
++ *
++ * Aug 2004 Sadik
++ *
++ * Added NAPI
++ *
++ **************************************************************************
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/moduleparam.h>
++#include <linux/sched.h>
++#include <linux/ctype.h>
++#include <linux/types.h>
++#include <linux/fcntl.h>
++#include <linux/interrupt.h>
++#include <linux/ptrace.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/proc_fs.h>
++#include <linux/in.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/delay.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/errno.h>
++#include <linux/platform_device.h>
++#include <asm/bootinfo.h>
++#include <asm/system.h>
++#include <asm/bitops.h>
++#include <asm/pgtable.h>
++#include <asm/segment.h>
++#include <asm/io.h>
++#include <asm/dma.h>
++
++#include <asm/rc32434/rb.h>
++#include "rc32434_eth.h"
++
++#define DRIVER_VERSION "(mar2904)"
++
++#define DRIVER_NAME "rc32434 Ethernet driver. " DRIVER_VERSION
++
++#define STATION_ADDRESS_HIGH(dev) (((dev)->dev_addr[0] << 8) | \
++ ((dev)->dev_addr[1]))
++#define STATION_ADDRESS_LOW(dev) (((dev)->dev_addr[2] << 24) | \
++ ((dev)->dev_addr[3] << 16) | \
++ ((dev)->dev_addr[4] << 8) | \
++ ((dev)->dev_addr[5]))
++
++#define MII_CLOCK 1250000 /* no more than 2.5MHz */
++#define CONFIG_IDT_USE_NAPI 1
++
++
++static inline void rc32434_abort_tx(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ rc32434_abort_dma(dev, lp->tx_dma_regs);
++
++}
++
++static inline void rc32434_abort_rx(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ rc32434_abort_dma(dev, lp->rx_dma_regs);
++
++}
++
++static inline void rc32434_start_tx(struct rc32434_local *lp, volatile DMAD_t td)
++{
++ rc32434_start_dma(lp->tx_dma_regs, CPHYSADDR(td));
++}
++
++static inline void rc32434_start_rx(struct rc32434_local *lp, volatile DMAD_t rd)
++{
++ rc32434_start_dma(lp->rx_dma_regs, CPHYSADDR(rd));
++}
++
++static inline void rc32434_chain_tx(struct rc32434_local *lp, volatile DMAD_t td)
++{
++ rc32434_chain_dma(lp->tx_dma_regs, CPHYSADDR(td));
++}
++
++static inline void rc32434_chain_rx(struct rc32434_local *lp, volatile DMAD_t rd)
++{
++ rc32434_chain_dma(lp->rx_dma_regs, CPHYSADDR(rd));
++}
++
++#ifdef RC32434_PROC_DEBUG
++static int rc32434_read_proc(char *buf, char **start, off_t fpos,
++ int length, int *eof, void *data)
++{
++ struct net_device *dev = (struct net_device *)data;
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ int len = 0;
++
++ /* print out header */
++ len += sprintf(buf + len, "\n\tKorina Ethernet Debug\n\n");
++ len += sprintf (buf + len,
++ "DMA halt count = %10d, DMA run count = %10d\n",
++ lp->dma_halt_cnt, lp->dma_run_cnt);
++
++ if (fpos >= len) {
++ *start = buf;
++ *eof = 1;
++ return 0;
++ }
++ *start = buf + fpos;
++
++ if ((len -= fpos) > length)
++ return length;
++ *eof = 1;
++
++ return len;
++
++}
++#endif
++
++
++/*
++ * Restart the RC32434 ethernet controller.
++ */
++static int rc32434_restart(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++
++ /*
++ * Disable interrupts
++ */
++ disable_irq(lp->rx_irq);
++ disable_irq(lp->tx_irq);
++#ifdef RC32434_REVISION
++ disable_irq(lp->ovr_irq);
++#endif
++ disable_irq(lp->und_irq);
++
++ /* Mask F E bit in Tx DMA */
++ __raw_writel(__raw_readl(&lp->tx_dma_regs->dmasm) | DMASM_f_m | DMASM_e_m, &lp->tx_dma_regs->dmasm);
++ /* Mask D H E bit in Rx DMA */
++ __raw_writel(__raw_readl(&lp->rx_dma_regs->dmasm) | DMASM_d_m | DMASM_h_m | DMASM_e_m, &lp->rx_dma_regs->dmasm);
++
++ rc32434_init(dev);
++ rc32434_multicast_list(dev);
++
++ enable_irq(lp->und_irq);
++#ifdef RC32434_REVISION
++ enable_irq(lp->ovr_irq);
++#endif
++ enable_irq(lp->tx_irq);
++ enable_irq(lp->rx_irq);
++
++ return 0;
++}
++
++static int rc32434_probe(struct platform_device *pdev)
++{
++ struct korina_device *bif = (struct korina_device *) pdev->dev.platform_data;
++ struct rc32434_local *lp = NULL;
++ struct net_device *dev = NULL;
++ struct resource *r;
++ int i, retval,err;
++
++ dev = alloc_etherdev(sizeof(struct rc32434_local));
++ if(!dev) {
++ ERR("Korina_eth: alloc_etherdev failed\n");
++ return -1;
++ }
++
++ platform_set_drvdata(pdev, dev);
++ SET_MODULE_OWNER(dev);
++ bif->dev = dev;
++
++ memcpy(dev->dev_addr, bif->mac, 6);
++
++ /* Initialize the device structure. */
++ if (dev->priv == NULL) {
++ lp = (struct rc32434_local *)kmalloc(sizeof(*lp), GFP_KERNEL);
++ memset(lp, 0, sizeof(struct rc32434_local));
++ }
++ else {
++ lp = (struct rc32434_local *)dev->priv;
++ }
++
++ lp->rx_irq = platform_get_irq_byname(pdev, "korina_rx");
++ lp->tx_irq = platform_get_irq_byname(pdev, "korina_tx");
++ lp->ovr_irq = platform_get_irq_byname(pdev, "korina_ovr");
++ lp->und_irq = platform_get_irq_byname(pdev, "korina_und");
++
++ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "korina_regs");
++ dev->base_addr = r->start;
++ lp->eth_regs = ioremap_nocache(r->start, r->end - r->start);
++ if (!lp->eth_regs) {
++ ERR("Can't remap eth registers\n");
++ retval = -ENXIO;
++ goto probe_err_out;
++ }
++
++ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "korina_dma_rx");
++ lp->rx_dma_regs = ioremap_nocache(r->start, r->end - r->start);
++ if (!lp->rx_dma_regs) {
++ ERR("Can't remap Rx DMA registers\n");
++ retval = -ENXIO;
++ goto probe_err_out;
++ }
++
++ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "korina_dma_tx");
++ lp->tx_dma_regs = ioremap_nocache(r->start, r->end - r->start);
++ if (!lp->tx_dma_regs) {
++ ERR("Can't remap Tx DMA registers\n");
++ retval = -ENXIO;
++ goto probe_err_out;
++ }
++
++#ifdef RC32434_PROC_DEBUG
++ lp->ps = create_proc_read_entry (bif->name, 0, proc_net,
++ rc32434_read_proc, dev);
++#endif
++
++ lp->td_ring = (DMAD_t)kmalloc(TD_RING_SIZE + RD_RING_SIZE, GFP_KERNEL);
++ if (!lp->td_ring) {
++ ERR("Can't allocate descriptors\n");
++ retval = -ENOMEM;
++ goto probe_err_out;
++ }
++
++ dma_cache_inv((unsigned long)(lp->td_ring), TD_RING_SIZE + RD_RING_SIZE);
++
++ /* now convert TD_RING pointer to KSEG1 */
++ lp->td_ring = (DMAD_t )KSEG1ADDR(lp->td_ring);
++ lp->rd_ring = &lp->td_ring[RC32434_NUM_TDS];
++
++
++ spin_lock_init(&lp->lock);
++
++ /* just use the rx dma irq */
++ dev->irq = lp->rx_irq;
++
++ dev->priv = lp;
++
++ dev->open = rc32434_open;
++ dev->stop = rc32434_close;
++ dev->hard_start_xmit = rc32434_send_packet;
++ dev->get_stats = rc32434_get_stats;
++ dev->set_multicast_list = &rc32434_multicast_list;
++ dev->tx_timeout = rc32434_tx_timeout;
++ dev->watchdog_timeo = RC32434_TX_TIMEOUT;
++
++#ifdef CONFIG_IDT_USE_NAPI
++ dev->poll = rc32434_poll;
++ dev->weight = 64;
++ printk("Using NAPI with weight %d\n",dev->weight);
++#else
++ lp->rx_tasklet = kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
++ tasklet_init(lp->rx_tasklet, rc32434_rx_tasklet, (unsigned long)dev);
++#endif
++ lp->tx_tasklet = kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
++ tasklet_init(lp->tx_tasklet, rc32434_tx_tasklet, (unsigned long)dev);
++
++ if ((err = register_netdev(dev))) {
++ printk(KERN_ERR "rc32434 ethernet. Cannot register net device %d\n", err);
++ free_netdev(dev);
++ retval = -EINVAL;
++ goto probe_err_out;
++ }
++
++ INFO("Rx IRQ %d, Tx IRQ %d, ", lp->rx_irq, lp->tx_irq);
++ for (i = 0; i < 6; i++) {
++ printk("%2.2x", dev->dev_addr[i]);
++ if (i<5)
++ printk(":");
++ }
++ printk("\n");
++
++ return 0;
++
++ probe_err_out:
++ rc32434_cleanup_module();
++ ERR(" failed. Returns %d\n", retval);
++ return retval;
++
++}
++
++static int rc32434_remove(struct platform_device *pdev)
++{
++ struct korina_device *bif = (struct korina_device *) pdev->dev.platform_data;
++
++ if (bif->dev != NULL) {
++ struct rc32434_local *lp = (struct rc32434_local *)bif->dev->priv;
++ if (lp != NULL) {
++ if (lp->eth_regs)
++ iounmap((void*)lp->eth_regs);
++ if (lp->rx_dma_regs)
++ iounmap((void*)lp->rx_dma_regs);
++ if (lp->tx_dma_regs)
++ iounmap((void*)lp->tx_dma_regs);
++ if (lp->td_ring)
++ kfree((void*)KSEG0ADDR(lp->td_ring));
++
++#ifdef RC32434_PROC_DEBUG
++ if (lp->ps) {
++ remove_proc_entry(bif->name, proc_net);
++ }
++#endif
++ kfree(lp);
++ }
++
++ platform_set_drvdata(pdev, NULL);
++ unregister_netdev(bif->dev);
++ free_netdev(bif->dev);
++ kfree(bif->dev);
++ }
++ return 0;
++}
++
++
++static int rc32434_open(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++
++ /* Initialize */
++ if (rc32434_init(dev)) {
++ ERR("Error: cannot open the Ethernet device\n");
++ return -EAGAIN;
++ }
++
++ /* Install the interrupt handler that handles the Done Finished Ovr and Und Events */
++ if (request_irq(lp->rx_irq, &rc32434_rx_dma_interrupt,
++ SA_SHIRQ | SA_INTERRUPT,
++ "Korina ethernet Rx", dev)) {
++ ERR(": unable to get Rx DMA IRQ %d\n",
++ lp->rx_irq);
++ return -EAGAIN;
++ }
++ if (request_irq(lp->tx_irq, &rc32434_tx_dma_interrupt,
++ SA_SHIRQ | SA_INTERRUPT,
++ "Korina ethernet Tx", dev)) {
++ ERR(": unable to get Tx DMA IRQ %d\n",
++ lp->tx_irq);
++ free_irq(lp->rx_irq, dev);
++ return -EAGAIN;
++ }
++
++#ifdef RC32434_REVISION
++ /* Install handler for overrun error. */
++ if (request_irq(lp->ovr_irq, &rc32434_ovr_interrupt,
++ SA_SHIRQ | SA_INTERRUPT,
++ "Ethernet Overflow", dev)) {
++ ERR(": unable to get OVR IRQ %d\n",
++ lp->ovr_irq);
++ free_irq(lp->rx_irq, dev);
++ free_irq(lp->tx_irq, dev);
++ return -EAGAIN;
++ }
++#endif
++
++ /* Install handler for underflow error. */
++ if (request_irq(lp->und_irq, &rc32434_und_interrupt,
++ SA_SHIRQ | SA_INTERRUPT,
++ "Ethernet Underflow", dev)) {
++ ERR(": unable to get UND IRQ %d\n",
++ lp->und_irq);
++ free_irq(lp->rx_irq, dev);
++ free_irq(lp->tx_irq, dev);
++#ifdef RC32434_REVISION
++ free_irq(lp->ovr_irq, dev);
++#endif
++ return -EAGAIN;
++ }
++
++
++ return 0;
++}
++
++
++
++
++static int rc32434_close(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ u32 tmp;
++
++ /* Disable interrupts */
++ disable_irq(lp->rx_irq);
++ disable_irq(lp->tx_irq);
++#ifdef RC32434_REVISION
++ disable_irq(lp->ovr_irq);
++#endif
++ disable_irq(lp->und_irq);
++
++ tmp = __raw_readl(&lp->tx_dma_regs->dmasm);
++ tmp = tmp | DMASM_f_m | DMASM_e_m;
++ __raw_writel(tmp, &lp->tx_dma_regs->dmasm);
++
++ tmp = __raw_readl(&lp->rx_dma_regs->dmasm);
++ tmp = tmp | DMASM_d_m | DMASM_h_m | DMASM_e_m;
++ __raw_writel(tmp, &lp->rx_dma_regs->dmasm);
++
++ free_irq(lp->rx_irq, dev);
++ free_irq(lp->tx_irq, dev);
++#ifdef RC32434_REVISION
++ free_irq(lp->ovr_irq, dev);
++#endif
++ free_irq(lp->und_irq, dev);
++ return 0;
++}
++
++
++/* transmit packet */
++static int rc32434_send_packet(struct sk_buff *skb, struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ unsigned long flags;
++ u32 length;
++ DMAD_t td;
++
++
++ spin_lock_irqsave(&lp->lock, flags);
++
++ td = &lp->td_ring[lp->tx_chain_tail];
++
++ /* stop queue when full, drop pkts if queue already full */
++ if(lp->tx_count >= (RC32434_NUM_TDS - 2)) {
++ lp->tx_full = 1;
++
++ if(lp->tx_count == (RC32434_NUM_TDS - 2)) {
++ netif_stop_queue(dev);
++ }
++ else {
++ lp->stats.tx_dropped++;
++ dev_kfree_skb_any(skb);
++ spin_unlock_irqrestore(&lp->lock, flags);
++ return 1;
++ }
++ }
++
++ lp->tx_count ++;
++
++ lp->tx_skb[lp->tx_chain_tail] = skb;
++
++ length = skb->len;
++
++ /* Setup the transmit descriptor. */
++ td->ca = CPHYSADDR(skb->data);
++
++ if(__raw_readl(&(lp->tx_dma_regs->dmandptr)) == 0) {
++ if( lp->tx_chain_status == empty ) {
++ td->control = DMA_COUNT(length) |DMAD_cof_m |DMAD_iof_m; /* Update tail */
++ lp->tx_chain_tail = (lp->tx_chain_tail + 1) & RC32434_TDS_MASK; /* Move tail */
++ __raw_writel(CPHYSADDR(&lp->td_ring[lp->tx_chain_head]), &(lp->tx_dma_regs->dmandptr)); /* Write to NDPTR */
++ lp->tx_chain_head = lp->tx_chain_tail; /* Move head to tail */
++ }
++ else {
++ td->control = DMA_COUNT(length) |DMAD_cof_m|DMAD_iof_m; /* Update tail */
++ lp->td_ring[(lp->tx_chain_tail-1)& RC32434_TDS_MASK].control &= ~(DMAD_cof_m); /* Link to prev */
++ lp->td_ring[(lp->tx_chain_tail-1)& RC32434_TDS_MASK].link = CPHYSADDR(td); /* Link to prev */
++ lp->tx_chain_tail = (lp->tx_chain_tail + 1) & RC32434_TDS_MASK; /* Move tail */
++ __raw_writel(CPHYSADDR(&lp->td_ring[lp->tx_chain_head]), &(lp->tx_dma_regs->dmandptr)); /* Write to NDPTR */
++ lp->tx_chain_head = lp->tx_chain_tail; /* Move head to tail */
++ lp->tx_chain_status = empty;
++ }
++ }
++ else {
++ if( lp->tx_chain_status == empty ) {
++ td->control = DMA_COUNT(length) |DMAD_cof_m |DMAD_iof_m; /* Update tail */
++ lp->tx_chain_tail = (lp->tx_chain_tail + 1) & RC32434_TDS_MASK; /* Move tail */
++ lp->tx_chain_status = filled;
++ }
++ else {
++ td->control = DMA_COUNT(length) |DMAD_cof_m |DMAD_iof_m; /* Update tail */
++ lp->td_ring[(lp->tx_chain_tail-1)& RC32434_TDS_MASK].control &= ~(DMAD_cof_m); /* Link to prev */
++ lp->td_ring[(lp->tx_chain_tail-1)& RC32434_TDS_MASK].link = CPHYSADDR(td); /* Link to prev */
++ lp->tx_chain_tail = (lp->tx_chain_tail + 1) & RC32434_TDS_MASK; /* Move tail */
++ }
++ }
++
++ dev->trans_start = jiffies;
++
++ spin_unlock_irqrestore(&lp->lock, flags);
++
++ return 0;
++}
++
++
++/* Ethernet MII-PHY Handler */
++static void rc32434_mii_handler(unsigned long data)
++{
++ struct net_device *dev = (struct net_device *)data;
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ unsigned long flags;
++ unsigned long duplex_status;
++ int port_addr = (lp->rx_irq == 0x2c? 1:0) << 8;
++
++ spin_lock_irqsave(&lp->lock, flags);
++
++ /* Two ports are using the same MII, the difference is the PHY address */
++ __raw_writel(0, &rc32434_eth0_regs->miimcfg);
++ __raw_writel(0, &rc32434_eth0_regs->miimcmd);
++ __raw_writel(port_addr |0x05, &rc32434_eth0_regs->miimaddr);
++ __raw_writel(MIIMCMD_scn_m, &rc32434_eth0_regs->miimcmd);
++ while(__raw_readl(&rc32434_eth0_regs->miimind) & MIIMIND_nv_m);
++
++ ERR("irq:%x port_addr:%x RDD:%x\n",
++ lp->rx_irq, port_addr, __raw_readl(&rc32434_eth0_regs->miimrdd));
++ duplex_status = (__raw_readl(&rc32434_eth0_regs->miimrdd) & 0x140)? ETHMAC2_fd_m: 0;
++ if(duplex_status != lp->duplex_mode) {
++ ERR("The MII-PHY is Auto-negotiated to %s-Duplex mode for Eth-%x\n", duplex_status? "Full":"Half", lp->rx_irq == 0x2c? 1:0);
++ lp->duplex_mode = duplex_status;
++ rc32434_restart(dev);
++ }
++
++ lp->mii_phy_timer.expires = jiffies + 10 * HZ;
++ add_timer(&lp->mii_phy_timer);
++
++ spin_unlock_irqrestore(&lp->lock, flags);
++
++}
++
++#ifdef RC32434_REVISION
++/* Ethernet Rx Overflow interrupt */
++static irqreturn_t
++rc32434_ovr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++{
++ struct net_device *dev = (struct net_device *)dev_id;
++ struct rc32434_local *lp;
++ unsigned int ovr;
++ irqreturn_t retval = IRQ_NONE;
++
++ ASSERT(dev != NULL);
++
++ lp = (struct rc32434_local *)dev->priv;
++ spin_lock(&lp->lock);
++ ovr = __raw_readl(&lp->eth_regs->ethintfc);
++
++ if(ovr & ETHINTFC_ovr_m) {
++ netif_stop_queue(dev);
++
++ /* clear OVR bit */
++ __raw_writel((ovr & ~ETHINTFC_ovr_m), &lp->eth_regs->ethintfc);
++
++ /* Restart interface */
++ rc32434_restart(dev);
++ retval = IRQ_HANDLED;
++ }
++ spin_unlock(&lp->lock);
++
++ return retval;
++}
++
++#endif
++
++
++/* Ethernet Tx Underflow interrupt */
++static irqreturn_t
++rc32434_und_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++{
++ struct net_device *dev = (struct net_device *)dev_id;
++ struct rc32434_local *lp;
++ unsigned int und;
++ irqreturn_t retval = IRQ_NONE;
++
++ ASSERT(dev != NULL);
++
++ lp = (struct rc32434_local *)dev->priv;
++
++ spin_lock(&lp->lock);
++
++ und = __raw_readl(&lp->eth_regs->ethintfc);
++
++ if(und & ETHINTFC_und_m) {
++ netif_stop_queue(dev);
++
++ __raw_writel((und & ~ETHINTFC_und_m), &lp->eth_regs->ethintfc);
++
++ /* Restart interface */
++ rc32434_restart(dev);
++ retval = IRQ_HANDLED;
++ }
++
++ spin_unlock(&lp->lock);
++
++ return retval;
++}
++
++
++/* Ethernet Rx DMA interrupt */
++static irqreturn_t
++rc32434_rx_dma_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++{
++ struct net_device *dev = (struct net_device *)dev_id;
++ struct rc32434_local* lp;
++ volatile u32 dmas,dmasm;
++ irqreturn_t retval;
++
++ ASSERT(dev != NULL);
++
++ lp = (struct rc32434_local *)dev->priv;
++
++ spin_lock(&lp->lock);
++ dmas = __raw_readl(&lp->rx_dma_regs->dmas);
++ if(dmas & (DMAS_d_m|DMAS_h_m|DMAS_e_m)) {
++ /* Mask D H E bit in Rx DMA */
++ dmasm = __raw_readl(&lp->rx_dma_regs->dmasm);
++ __raw_writel(dmasm | (DMASM_d_m | DMASM_h_m | DMASM_e_m), &lp->rx_dma_regs->dmasm);
++#ifdef CONFIG_IDT_USE_NAPI
++ if(netif_rx_schedule_prep(dev))
++ __netif_rx_schedule(dev);
++#else
++ tasklet_hi_schedule(lp->rx_tasklet);
++#endif
++
++ if (dmas & DMAS_e_m)
++ ERR(": DMA error\n");
++
++ retval = IRQ_HANDLED;
++ }
++ else
++ retval = IRQ_NONE;
++
++ spin_unlock(&lp->lock);
++ return retval;
++}
++
++#ifdef CONFIG_IDT_USE_NAPI
++static int rc32434_poll(struct net_device *rx_data_dev, int *budget)
++#else
++static void rc32434_rx_tasklet(unsigned long rx_data_dev)
++#endif
++{
++ struct net_device *dev = (struct net_device *)rx_data_dev;
++ struct rc32434_local* lp = netdev_priv(dev);
++ volatile DMAD_t rd = &lp->rd_ring[lp->rx_next_done];
++ struct sk_buff *skb, *skb_new;
++ u8* pkt_buf;
++ u32 devcs, count, pkt_len, pktuncrc_len;
++ volatile u32 dmas;
++#ifdef CONFIG_IDT_USE_NAPI
++ u32 received = 0;
++ int rx_work_limit = min(*budget,dev->quota);
++#else
++ unsigned long flags;
++ spin_lock_irqsave(&lp->lock, flags);
++#endif
++
++ while ( (count = RC32434_RBSIZE - (u32)DMA_COUNT(rd->control)) != 0) {
++#ifdef CONFIG_IDT_USE_NAPI
++ if(--rx_work_limit <0)
++ {
++ break;
++ }
++#endif
++ /* init the var. used for the later operations within the while loop */
++ skb_new = NULL;
++ devcs = rd->devcs;
++ pkt_len = RCVPKT_LENGTH(devcs);
++ skb = lp->rx_skb[lp->rx_next_done];
++
++ if (count < 64) {
++ lp->stats.rx_errors++;
++ lp->stats.rx_dropped++;
++ }
++ else if ((devcs & ( ETHRX_ld_m)) != ETHRX_ld_m) {
++ /* check that this is a whole packet */
++ /* WARNING: DMA_FD bit incorrectly set in Rc32434 (errata ref #077) */
++ lp->stats.rx_errors++;
++ lp->stats.rx_dropped++;
++ }
++ else if ( (devcs & ETHRX_rok_m) ) {
++
++ {
++ /* must be the (first and) last descriptor then */
++ pkt_buf = (u8*)lp->rx_skb[lp->rx_next_done]->data;
++
++ pktuncrc_len = pkt_len - 4;
++ /* invalidate the cache */
++ dma_cache_inv((unsigned long)pkt_buf, pktuncrc_len);
++
++ /* Malloc up new buffer. */
++ skb_new = dev_alloc_skb(RC32434_RBSIZE + 2);
++
++ if (skb_new != NULL){
++ /* Make room */
++ skb_put(skb, pktuncrc_len);
++
++ skb->protocol = eth_type_trans(skb, dev);
++
++ /* pass the packet to upper layers */
++#ifdef CONFIG_IDT_USE_NAPI
++ netif_receive_skb(skb);
++#else
++ netif_rx(skb);
++#endif
++
++ dev->last_rx = jiffies;
++ lp->stats.rx_packets++;
++ lp->stats.rx_bytes += pktuncrc_len;
++
++ if (IS_RCV_MP(devcs))
++ lp->stats.multicast++;
++
++ /* 16 bit align */
++ skb_reserve(skb_new, 2);
++
++ skb_new->dev = dev;
++ lp->rx_skb[lp->rx_next_done] = skb_new;
++ }
++ else {
++ ERR("no memory, dropping rx packet.\n");
++ lp->stats.rx_errors++;
++ lp->stats.rx_dropped++;
++ }
++ }
++
++ }
++ else {
++ /* This should only happen if we enable accepting broken packets */
++ lp->stats.rx_errors++;
++ lp->stats.rx_dropped++;
++
++ /* add statistics counters */
++ if (IS_RCV_CRC_ERR(devcs)) {
++ DBG(2, "RX CRC error\n");
++ lp->stats.rx_crc_errors++;
++ }
++ else if (IS_RCV_LOR_ERR(devcs)) {
++ DBG(2, "RX LOR error\n");
++ lp->stats.rx_length_errors++;
++ }
++ else if (IS_RCV_LE_ERR(devcs)) {
++ DBG(2, "RX LE error\n");
++ lp->stats.rx_length_errors++;
++ }
++ else if (IS_RCV_OVR_ERR(devcs)) {
++ lp->stats.rx_over_errors++;
++ }
++ else if (IS_RCV_CV_ERR(devcs)) {
++ /* code violation */
++ DBG(2, "RX CV error\n");
++ lp->stats.rx_frame_errors++;
++ }
++ else if (IS_RCV_CES_ERR(devcs)) {
++ DBG(2, "RX Preamble error\n");
++ }
++ }
++
++ rd->devcs = 0;
++
++ /* restore descriptor's curr_addr */
++ if(skb_new)
++ rd->ca = CPHYSADDR(skb_new->data);
++ else
++ rd->ca = CPHYSADDR(skb->data);
++
++ rd->control = DMA_COUNT(RC32434_RBSIZE) |DMAD_cod_m |DMAD_iod_m;
++ lp->rd_ring[(lp->rx_next_done-1)& RC32434_RDS_MASK].control &= ~(DMAD_cod_m);
++
++ lp->rx_next_done = (lp->rx_next_done + 1) & RC32434_RDS_MASK;
++ rd = &lp->rd_ring[lp->rx_next_done];
++ __raw_writel( ~DMAS_d_m, &lp->rx_dma_regs->dmas);
++ }
++#ifdef CONFIG_IDT_USE_NAPI
++ dev->quota -= received;
++ *budget =- received;
++ if(rx_work_limit < 0)
++ goto not_done;
++#endif
++
++ dmas = __raw_readl(&lp->rx_dma_regs->dmas);
++
++ if(dmas & DMAS_h_m) {
++ __raw_writel( ~(DMAS_h_m | DMAS_e_m), &lp->rx_dma_regs->dmas);
++#ifdef RC32434_PROC_DEBUG
++ lp->dma_halt_cnt++;
++#endif
++ rd->devcs = 0;
++ skb = lp->rx_skb[lp->rx_next_done];
++ rd->ca = CPHYSADDR(skb->data);
++ rc32434_chain_rx(lp,rd);
++ }
++
++#ifdef CONFIG_IDT_USE_NAPI
++ netif_rx_complete(dev);
++#endif
++ /* Enable D H E bit in Rx DMA */
++ __raw_writel(__raw_readl(&lp->rx_dma_regs->dmasm) & ~(DMASM_d_m | DMASM_h_m |DMASM_e_m), &lp->rx_dma_regs->dmasm);
++#ifdef CONFIG_IDT_USE_NAPI
++ return 0;
++ not_done:
++ return 1;
++#else
++ spin_unlock_irqrestore(&lp->lock, flags);
++ return;
++#endif
++
++
++}
++
++
++
++/* Ethernet Tx DMA interrupt */
++static irqreturn_t
++rc32434_tx_dma_interrupt(int irq, void *dev_id, struct pt_regs * regs)
++{
++ struct net_device *dev = (struct net_device *)dev_id;
++ struct rc32434_local *lp;
++ volatile u32 dmas,dmasm;
++ irqreturn_t retval;
++
++ ASSERT(dev != NULL);
++
++ lp = (struct rc32434_local *)dev->priv;
++
++ spin_lock(&lp->lock);
++
++ dmas = __raw_readl(&lp->tx_dma_regs->dmas);
++
++ if (dmas & (DMAS_f_m | DMAS_e_m)) {
++ dmasm = __raw_readl(&lp->tx_dma_regs->dmasm);
++ /* Mask F E bit in Tx DMA */
++ __raw_writel(dmasm | (DMASM_f_m | DMASM_e_m), &lp->tx_dma_regs->dmasm);
++
++ tasklet_hi_schedule(lp->tx_tasklet);
++
++ if(lp->tx_chain_status == filled && (__raw_readl(&(lp->tx_dma_regs->dmandptr)) == 0)) {
++ __raw_writel(CPHYSADDR(&lp->td_ring[lp->tx_chain_head]), &(lp->tx_dma_regs->dmandptr));
++ lp->tx_chain_status = empty;
++ lp->tx_chain_head = lp->tx_chain_tail;
++ dev->trans_start = jiffies;
++ }
++
++ if (dmas & DMAS_e_m)
++ ERR(": DMA error\n");
++
++ retval = IRQ_HANDLED;
++ }
++ else
++ retval = IRQ_NONE;
++
++ spin_unlock(&lp->lock);
++
++ return retval;
++}
++
++
++static void rc32434_tx_tasklet(unsigned long tx_data_dev)
++{
++ struct net_device *dev = (struct net_device *)tx_data_dev;
++ struct rc32434_local* lp = (struct rc32434_local *)dev->priv;
++ volatile DMAD_t td = &lp->td_ring[lp->tx_next_done];
++ u32 devcs;
++ unsigned long flags;
++ volatile u32 dmas;
++
++ spin_lock_irqsave(&lp->lock, flags);
++
++ /* process all desc that are done */
++ while(IS_DMA_FINISHED(td->control)) {
++ if(lp->tx_full == 1) {
++ netif_wake_queue(dev);
++ lp->tx_full = 0;
++ }
++
++ devcs = lp->td_ring[lp->tx_next_done].devcs;
++ if ((devcs & (ETHTX_fd_m | ETHTX_ld_m)) != (ETHTX_fd_m | ETHTX_ld_m)) {
++ lp->stats.tx_errors++;
++ lp->stats.tx_dropped++;
++
++ /* should never happen */
++ DBG(1, __FUNCTION__ ": split tx ignored\n");
++ }
++ else if (IS_TX_TOK(devcs)) {
++ lp->stats.tx_packets++;
++ }
++ else {
++ lp->stats.tx_errors++;
++ lp->stats.tx_dropped++;
++
++ /* underflow */
++ if (IS_TX_UND_ERR(devcs))
++ lp->stats.tx_fifo_errors++;
++
++ /* oversized frame */
++ if (IS_TX_OF_ERR(devcs))
++ lp->stats.tx_aborted_errors++;
++
++ /* excessive deferrals */
++ if (IS_TX_ED_ERR(devcs))
++ lp->stats.tx_carrier_errors++;
++
++ /* collisions: medium busy */
++ if (IS_TX_EC_ERR(devcs))
++ lp->stats.collisions++;
++
++ /* late collision */
++ if (IS_TX_LC_ERR(devcs))
++ lp->stats.tx_window_errors++;
++
++ }
++
++ /* We must always free the original skb */
++ if (lp->tx_skb[lp->tx_next_done] != NULL) {
++ dev_kfree_skb_any(lp->tx_skb[lp->tx_next_done]);
++ lp->tx_skb[lp->tx_next_done] = NULL;
++ }
++
++ lp->td_ring[lp->tx_next_done].control = DMAD_iof_m;
++ lp->td_ring[lp->tx_next_done].devcs = ETHTX_fd_m | ETHTX_ld_m;
++ lp->td_ring[lp->tx_next_done].link = 0;
++ lp->td_ring[lp->tx_next_done].ca = 0;
++ lp->tx_count --;
++
++ /* go on to next transmission */
++ lp->tx_next_done = (lp->tx_next_done + 1) & RC32434_TDS_MASK;
++ td = &lp->td_ring[lp->tx_next_done];
++
++ }
++
++ dmas = __raw_readl(&lp->tx_dma_regs->dmas);
++ __raw_writel( ~dmas, &lp->tx_dma_regs->dmas);
++
++ /* Enable F E bit in Tx DMA */
++ __raw_writel(__raw_readl(&lp->tx_dma_regs->dmasm) & ~(DMASM_f_m | DMASM_e_m), &lp->tx_dma_regs->dmasm);
++ spin_unlock_irqrestore(&lp->lock, flags);
++
++}
++
++
++static struct net_device_stats * rc32434_get_stats(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ return &lp->stats;
++}
++
++
++/*
++ * Set or clear the multicast filter for this adaptor.
++ */
++static void rc32434_multicast_list(struct net_device *dev)
++{
++ /* listen to broadcasts always and to treat */
++ /* IFF bits independantly */
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ unsigned long flags;
++ u32 recognise = ETHARC_ab_m; /* always accept broadcasts */
++
++ if (dev->flags & IFF_PROMISC) /* set promiscuous mode */
++ recognise |= ETHARC_pro_m;
++
++ if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 15))
++ recognise |= ETHARC_am_m; /* all multicast & bcast */
++ else if (dev->mc_count > 0) {
++ DBG(2, __FUNCTION__ ": mc_count %d\n", dev->mc_count);
++ recognise |= ETHARC_am_m; /* for the time being */
++ }
++
++ spin_lock_irqsave(&lp->lock, flags);
++ __raw_writel(recognise, &lp->eth_regs->etharc);
++ spin_unlock_irqrestore(&lp->lock, flags);
++}
++
++
++static void rc32434_tx_timeout(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ unsigned long flags;
++
++ spin_lock_irqsave(&lp->lock, flags);
++ rc32434_restart(dev);
++ spin_unlock_irqrestore(&lp->lock, flags);
++
++}
++
++
++/*
++ * Initialize the RC32434 ethernet controller.
++ */
++static int rc32434_init(struct net_device *dev)
++{
++ struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
++ int i, j;
++
++ /* Disable DMA */
++ rc32434_abort_tx(dev);
++ rc32434_abort_rx(dev);
++
++ /* reset ethernet logic */
++ __raw_writel(0, &lp->eth_regs->ethintfc);
++ while((__raw_readl(&lp->eth_regs->ethintfc) & ETHINTFC_rip_m))
++ dev->trans_start = jiffies;
++
++ /* Enable Ethernet Interface */
++ __raw_writel(ETHINTFC_en_m, &lp->eth_regs->ethintfc);
++
++#ifndef CONFIG_IDT_USE_NAPI
++ tasklet_disable(lp->rx_tasklet);
++#endif
++ tasklet_disable(lp->tx_tasklet);
++
++ /* Initialize the transmit Descriptors */
++ for (i = 0; i < RC32434_NUM_TDS; i++) {
++ lp->td_ring[i].control = DMAD_iof_m;
++ lp->td_ring[i].devcs = ETHTX_fd_m | ETHTX_ld_m;
++ lp->td_ring[i].ca = 0;
++ lp->td_ring[i].link = 0;
++ if (lp->tx_skb[i] != NULL) {
++ dev_kfree_skb_any(lp->tx_skb[i]);
++ lp->tx_skb[i] = NULL;
++ }
++ }
++ lp->tx_next_done = lp->tx_chain_head = lp->tx_chain_tail = lp->tx_full = lp->tx_count = 0;
++ lp-> tx_chain_status = empty;
++
++ /*
++ * Initialize the receive descriptors so that they
++ * become a circular linked list, ie. let the last
++ * descriptor point to the first again.
++ */
++ for (i=0; i<RC32434_NUM_RDS; i++) {
++ struct sk_buff *skb = lp->rx_skb[i];
++
++ if (lp->rx_skb[i] == NULL) {
++ skb = dev_alloc_skb(RC32434_RBSIZE + 2);
++ if (skb == NULL) {
++ ERR("No memory in the system\n");
++ for (j = 0; j < RC32434_NUM_RDS; j ++)
++ if (lp->rx_skb[j] != NULL)
++ dev_kfree_skb_any(lp->rx_skb[j]);
++
++ return 1;
++ }
++ else {
++ skb->dev = dev;
++ skb_reserve(skb, 2);
++ lp->rx_skb[i] = skb;
++ lp->rd_ring[i].ca = CPHYSADDR(skb->data);
++
++ }
++ }
++ lp->rd_ring[i].control = DMAD_iod_m | DMA_COUNT(RC32434_RBSIZE);
++ lp->rd_ring[i].devcs = 0;
++ lp->rd_ring[i].ca = CPHYSADDR(skb->data);
++ lp->rd_ring[i].link = CPHYSADDR(&lp->rd_ring[i+1]);
++
++ }
++ /* loop back */
++ lp->rd_ring[RC32434_NUM_RDS-1].link = CPHYSADDR(&lp->rd_ring[0]);
++ lp->rx_next_done = 0;
++
++ lp->rd_ring[RC32434_NUM_RDS-1].control |= DMAD_cod_m;
++ lp->rx_chain_head = 0;
++ lp->rx_chain_tail = 0;
++ lp->rx_chain_status = empty;
++
++ __raw_writel(0, &lp->rx_dma_regs->dmas);
++ /* Start Rx DMA */
++ rc32434_start_rx(lp, &lp->rd_ring[0]);
++
++ /* Enable F E bit in Tx DMA */
++ __raw_writel(__raw_readl(&lp->tx_dma_regs->dmasm) & ~(DMASM_f_m | DMASM_e_m), &lp->tx_dma_regs->dmasm);
++ /* Enable D H E bit in Rx DMA */
++ __raw_writel(__raw_readl(&lp->rx_dma_regs->dmasm) & ~(DMASM_d_m | DMASM_h_m | DMASM_e_m), &lp->rx_dma_regs->dmasm);
++
++ /* Accept only packets destined for this Ethernet device address */
++ __raw_writel(ETHARC_ab_m, &lp->eth_regs->etharc);
++
++ /* Set all Ether station address registers to their initial values */
++ __raw_writel(STATION_ADDRESS_LOW(dev), &lp->eth_regs->ethsal0);
++ __raw_writel(STATION_ADDRESS_HIGH(dev), &lp->eth_regs->ethsah0);
++
++ __raw_writel(STATION_ADDRESS_LOW(dev), &lp->eth_regs->ethsal1);
++ __raw_writel(STATION_ADDRESS_HIGH(dev), &lp->eth_regs->ethsah1);
++
++ __raw_writel(STATION_ADDRESS_LOW(dev), &lp->eth_regs->ethsal2);
++ __raw_writel(STATION_ADDRESS_HIGH(dev), &lp->eth_regs->ethsah2);
++
++ __raw_writel(STATION_ADDRESS_LOW(dev), &lp->eth_regs->ethsal3);
++ __raw_writel(STATION_ADDRESS_HIGH(dev), &lp->eth_regs->ethsah3);
++
++
++ /* Frame Length Checking, Pad Enable, CRC Enable, Full Duplex set */
++ __raw_writel(ETHMAC2_pe_m | ETHMAC2_cen_m | ETHMAC2_fd_m, &lp->eth_regs->ethmac2);
++ //ETHMAC2_flc_m ETHMAC2_fd_m lp->duplex_mode
++
++ /* Back to back inter-packet-gap */
++ __raw_writel(0x15, &lp->eth_regs->ethipgt);
++ /* Non - Back to back inter-packet-gap */
++ __raw_writel(0x12, &lp->eth_regs->ethipgr);
++
++ /* Management Clock Prescaler Divisor */
++ /* Clock independent setting */
++ __raw_writel(((idt_cpu_freq)/MII_CLOCK+1) & ~1,
++ &lp->eth_regs->ethmcp);
++
++ /* don't transmit until fifo contains 48b */
++ __raw_writel(48, &lp->eth_regs->ethfifott);
++
++ __raw_writel(ETHMAC1_re_m, &lp->eth_regs->ethmac1);
++
++#ifndef CONFIG_IDT_USE_NAPI
++ tasklet_enable(lp->rx_tasklet);
++#endif
++ tasklet_enable(lp->tx_tasklet);
++
++ netif_start_queue(dev);
++
++ return 0;
++}
++
++static struct platform_driver korina_driver = {
++ .driver.name = "korina",
++ .probe = rc32434_probe,
++ .remove = rc32434_remove,
++};
++
++static int __init rc32434_init_module(void)
++{
++ return platform_driver_register(&korina_driver);
++}
++
++static void rc32434_cleanup_module(void)
++{
++ return platform_driver_unregister(&korina_driver);
++}
++
++module_init(rc32434_init_module);
++module_exit(rc32434_cleanup_module);
+diff -urN linux.old/drivers/net/Makefile linux.dev/drivers/net/Makefile
+--- linux.old/drivers/net/Makefile 2006-06-08 20:21:20.000000000 +0200
++++ linux.dev/drivers/net/Makefile 2006-06-08 20:19:40.000000000 +0200
+@@ -23,6 +23,8 @@
+ #
+ obj-$(CONFIG_PLIP) += plip.o
+
++obj-$(CONFIG_KORINA) += korina.o
++
+ obj-$(CONFIG_ROADRUNNER) += rrunner.o
+
+ obj-$(CONFIG_HAPPYMEAL) += sunhme.o
+diff -urN linux.old/drivers/net/rc32434_eth.h linux.dev/drivers/net/rc32434_eth.h
+--- linux.old/drivers/net/rc32434_eth.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/net/rc32434_eth.h 2006-06-08 21:57:12.000000000 +0200
+@@ -0,0 +1,178 @@
++/**************************************************************************
++ *
++ * BRIEF MODULE DESCRIPTION
++ * Definitions for IDT RC32434 on-chip ethernet controller.
++ *
++ * Copyright 2004 IDT Inc. (rischelp@idt.com)
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ **************************************************************************
++ * May 2004 rkt, neb
++ *
++ * Initial Release
++ *
++ * Aug 2004
++ *
++ * Added NAPI
++ *
++ **************************************************************************
++ */
++
++
++#include <asm/rc32434/rc32434.h>
++#include <asm/rc32434/dma_v.h>
++#include <asm/rc32434/eth_v.h>
++
++#define CONFIG_IDT_USE_NAPI 1
++#define RC32434_DEBUG 2
++//#define RC32434_PROC_DEBUG
++#undef RC32434_DEBUG
++
++#ifdef RC32434_DEBUG
++
++/* use 0 for production, 1 for verification, >2 for debug */
++static int rc32434_debug = RC32434_DEBUG;
++#define ASSERT(expr) \
++ if(!(expr)) { \
++ printk( "Assertion failed! %s,%s,%s,line=%d\n", \
++ #expr,__FILE__,__FUNCTION__,__LINE__); }
++#define DBG(lvl, format, arg...) if (rc32434_debug > lvl) printk(KERN_INFO "%s: " format, dev->name , ## arg)
++#else
++#define ASSERT(expr) do {} while (0)
++#define DBG(lvl, format, arg...) do {} while (0)
++#endif
++
++#define INFO(format, arg...) printk(KERN_INFO "%s: " format, dev->name , ## arg)
++#define ERR(format, arg...) printk(KERN_ERR "%s: " format, dev->name , ## arg)
++#define WARN(format, arg...) printk(KERN_WARNING "%s: " format, dev->name , ## arg)
++
++/* the following must be powers of two */
++#ifdef CONFIG_IDT_USE_NAPI
++#define RC32434_NUM_RDS 64 /* number of receive descriptors */
++#define RC32434_NUM_TDS 64 /* number of transmit descriptors */
++#else
++#define RC32434_NUM_RDS 128 /* number of receive descriptors */
++#define RC32434_NUM_TDS 128 /* number of transmit descriptors */
++#endif
++
++#define RC32434_RBSIZE 1536 /* size of one resource buffer = Ether MTU */
++#define RC32434_RDS_MASK (RC32434_NUM_RDS-1)
++#define RC32434_TDS_MASK (RC32434_NUM_TDS-1)
++#define RD_RING_SIZE (RC32434_NUM_RDS * sizeof(struct DMAD_s))
++#define TD_RING_SIZE (RC32434_NUM_TDS * sizeof(struct DMAD_s))
++
++#define RC32434_TX_TIMEOUT HZ * 100
++
++#define rc32434_eth0_regs ((ETH_t)(ETH0_VirtualAddress))
++#define rc32434_eth1_regs ((ETH_t)(ETH1_VirtualAddress))
++
++enum status { filled, empty};
++#define IS_DMA_FINISHED(X) (((X) & (DMAD_f_m)) != 0)
++#define IS_DMA_DONE(X) (((X) & (DMAD_d_m)) != 0)
++
++
++/* Information that need to be kept for each board. */
++struct rc32434_local {
++ ETH_t eth_regs;
++ DMA_Chan_t rx_dma_regs;
++ DMA_Chan_t tx_dma_regs;
++ volatile DMAD_t td_ring; /* transmit descriptor ring */
++ volatile DMAD_t rd_ring; /* receive descriptor ring */
++
++ struct sk_buff* tx_skb[RC32434_NUM_TDS]; /* skbuffs for pkt to trans */
++ struct sk_buff* rx_skb[RC32434_NUM_RDS]; /* skbuffs for pkt to trans */
++
++#ifndef CONFIG_IDT_USE_NAPI
++ struct tasklet_struct * rx_tasklet;
++#endif
++ struct tasklet_struct * tx_tasklet;
++
++ int rx_next_done;
++ int rx_chain_head;
++ int rx_chain_tail;
++ enum status rx_chain_status;
++
++ int tx_next_done;
++ int tx_chain_head;
++ int tx_chain_tail;
++ enum status tx_chain_status;
++ int tx_count;
++ int tx_full;
++
++ struct timer_list mii_phy_timer;
++ unsigned long duplex_mode;
++
++ int rx_irq;
++ int tx_irq;
++ int ovr_irq;
++ int und_irq;
++
++ struct net_device_stats stats;
++ spinlock_t lock;
++
++ /* debug /proc entry */
++ struct proc_dir_entry *ps;
++ int dma_halt_cnt; int dma_run_cnt;
++};
++
++extern unsigned int idt_cpu_freq;
++
++/* Index to functions, as function prototypes. */
++static int rc32434_open(struct net_device *dev);
++static int rc32434_send_packet(struct sk_buff *skb, struct net_device *dev);
++static void rc32434_mii_handler(unsigned long data);
++static irqreturn_t rc32434_und_interrupt(int irq, void *dev_id, struct pt_regs * regs);
++static irqreturn_t rc32434_rx_dma_interrupt(int irq, void *dev_id, struct pt_regs * regs);
++static irqreturn_t rc32434_tx_dma_interrupt(int irq, void *dev_id, struct pt_regs * regs);
++#ifdef RC32434_REVISION
++static irqreturn_t rc32434_ovr_interrupt(int irq, void *dev_id, struct pt_regs * regs);
++#endif
++static int rc32434_close(struct net_device *dev);
++static struct net_device_stats *rc32434_get_stats(struct net_device *dev);
++static void rc32434_multicast_list(struct net_device *dev);
++static int rc32434_init(struct net_device *dev);
++static void rc32434_tx_timeout(struct net_device *dev);
++
++static void rc32434_tx_tasklet(unsigned long tx_data_dev);
++#ifdef CONFIG_IDT_USE_NAPI
++static int rc32434_poll(struct net_device *rx_data_dev, int *budget);
++#else
++static void rc32434_rx_tasklet(unsigned long rx_data_dev);
++#endif
++static void rc32434_cleanup_module(void);
++
++
++static inline void rc32434_abort_dma(struct net_device *dev, DMA_Chan_t ch)
++{
++ if (__raw_readl(&ch->dmac) & DMAC_run_m) {
++ __raw_writel(0x10, &ch->dmac);
++
++ while (!(__raw_readl(&ch->dmas) & DMAS_h_m))
++ dev->trans_start = jiffies;
++
++ __raw_writel(0, &ch->dmas);
++ }
++
++ __raw_writel(0, &ch->dmadptr);
++ __raw_writel(0, &ch->dmandptr);
++}
+
diff --git a/target/linux/rb532-2.6/patches/120-cf.patch b/target/linux/rb532-2.6/patches/120-cf.patch
new file mode 100644
index 0000000..657d815
--- /dev/null
+++ b/target/linux/rb532-2.6/patches/120-cf.patch
@@ -0,0 +1,990 @@
+diff -urN linux.old/drivers/block/Kconfig linux.dev/drivers/block/Kconfig
+--- linux.old/drivers/block/Kconfig 2006-06-08 20:20:52.000000000 +0200
++++ linux.dev/drivers/block/Kconfig 2006-06-08 22:14:58.000000000 +0200
+@@ -453,4 +453,12 @@
+ This driver provides Support for ATA over Ethernet block
+ devices like the Coraid EtherDrive (R) Storage Blade.
+
++config BLK_DEV_CF_MIPS
++ bool "CF slot of RB532 board"
++ depends on MIKROTIK_RB500
++ default y
++ help
++ The Routerboard 532 has a CF slot on it. Enable the special block
++ device driver for it.
++
+ endmenu
+diff -urN linux.old/drivers/block/rb500/ata.c linux.dev/drivers/block/rb500/ata.c
+--- linux.old/drivers/block/rb500/ata.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/block/rb500/ata.c 2006-06-09 01:58:40.000000000 +0200
+@@ -0,0 +1,474 @@
++#include <linux/kernel.h> /* printk() */
++#include <linux/module.h> /* module to be loadable */
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/pci.h>
++#include <linux/ioport.h> /* request_mem_region() */
++#include <asm/unaligned.h> /* ioremap() */
++#include <asm/io.h> /* ioremap() */
++#include <asm/rc32434/rb.h>
++
++#include "ata.h"
++
++#define REQUEST_MEM_REGION 0
++#define DEBUG 1
++
++#if DEBUG
++#define DEBUGP printk
++#else
++#define DEBUGP(format, args...)
++#endif
++
++#define SECS 1000000 /* unit for wait_not_busy() is 1us */
++
++unsigned cf_head = 0;
++unsigned cf_cyl = 0;
++unsigned cf_spt = 0;
++unsigned cf_sectors = 0;
++static unsigned cf_block_size = 1;
++static void *baddr = 0;
++
++#define DBUF32 ((volatile u32 *)((unsigned long)dev->baddr | ATA_DBUF_OFFSET))
++
++
++static void cf_do_tasklet(unsigned long dev_l);
++
++
++static inline void wareg(u8 val, unsigned reg, struct cf_mips_dev* dev)
++{
++ writeb(val, dev->baddr + ATA_REG_OFFSET + reg);
++}
++
++static inline u8 rareg(unsigned reg, struct cf_mips_dev* dev)
++{
++ return readb(dev->baddr + ATA_REG_OFFSET + reg);
++}
++
++static inline int get_gpio_bit(gpio_func ofs, struct cf_mips_dev *dev)
++{
++ return (gpio_get(ofs) >> dev->pin) & 1;
++}
++
++static inline void set_gpio_bit(int bit, gpio_func ofs, struct cf_mips_dev *dev)
++{
++ gpio_set(ofs, (1 << dev->pin), ((bit & 1) << dev->pin));
++}
++
++static inline int cfrdy(struct cf_mips_dev *dev)
++{
++ return get_gpio_bit(DATA, dev);
++}
++
++static inline void prepare_cf_irq(struct cf_mips_dev *dev)
++{
++ set_gpio_bit(1, ILEVEL, dev); /* interrupt on cf ready (not busy) */
++ set_gpio_bit(0, ISTAT, dev); /* clear interrupt status */
++}
++
++static inline int cf_present(struct cf_mips_dev* dev)
++{
++ /* TODO: read and configure CIS into memory mapped mode
++ * TODO: parse CISTPL_CONFIG on CF+ cards to get base address (0x200)
++ * TODO: maybe adjust power saving setting for Hitachi Microdrive
++ */
++ int i;
++
++ /* setup CFRDY GPIO as input */
++ set_gpio_bit(0, FUNC, dev);
++ set_gpio_bit(0, CFG, dev);
++
++ for (i = 0; i < 0x10; ++i) {
++ if (rareg(i,dev) != 0xff)
++ return 1;
++ }
++ return 0;
++}
++
++static inline int is_busy(struct cf_mips_dev *dev)
++{
++ return !cfrdy(dev);
++}
++
++static int wait_not_busy(int to_us, int wait_for_busy,struct cf_mips_dev *dev)
++{
++ int us_passed = 0;
++ if (wait_for_busy && !is_busy(dev)) {
++ /* busy must appear within 400ns,
++ * but it may dissapear before we see it
++ * => must not wait for busy in a loop
++ */
++ ndelay(400);
++ }
++
++ do {
++ if (us_passed)
++ udelay(1); /* never reached in async mode */
++ if (!is_busy(dev)) {
++ if (us_passed > 1 * SECS) {
++ printk(KERN_WARNING "cf-mips: not busy ok (after %dus)"
++ ", status 0x%02x\n", us_passed, (unsigned) rareg(ATA_REG_ST,dev));
++ }
++ return CF_TRANS_OK;
++ }
++ if (us_passed == 1 * SECS) {
++ printk(KERN_WARNING "cf-mips: wait not busy %dus..\n", to_us);
++ }
++ if (dev->async_mode) {
++ dev->to_timer.expires = jiffies + (to_us * HZ / SECS);
++ dev->irq_enable_time = jiffies;
++ prepare_cf_irq(dev);
++ if (is_busy(dev)) {
++ add_timer(&dev->to_timer);
++ enable_irq(dev->irq);
++ return CF_TRANS_IN_PROGRESS;
++ }
++ continue;
++ }
++ ++us_passed;
++ } while (us_passed < to_us);
++
++ printk(KERN_ERR "cf-mips: wait not busy timeout (%dus)"
++ ", status 0x%02x, state %d\n",
++ to_us, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate);
++ return CF_TRANS_FAILED;
++}
++
++static irqreturn_t cf_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
++{
++ /* While tasklet has not disabled irq, irq will be retried all the time
++ * because of ILEVEL matching GPIO pin status => deadlock.
++ * To avoid this, we change ILEVEL to 0.
++ */
++ struct cf_mips_dev *dev=dev_id;
++
++ set_gpio_bit(0, ILEVEL, dev);
++ set_gpio_bit(0, ISTAT, dev);
++
++ del_timer(&dev->to_timer);
++ tasklet_schedule(&dev->tasklet);
++ return IRQ_HANDLED;
++}
++
++static int do_reset(struct cf_mips_dev *dev)
++{
++ printk(KERN_INFO "cf-mips: resetting..\n");
++
++ wareg(ATA_REG_DC_SRST, ATA_REG_DC,dev);
++ udelay(1); /* FIXME: how long should we wait here? */
++ wareg(0, ATA_REG_DC,dev);
++
++ return wait_not_busy(30 * SECS, 1,dev);
++}
++
++static int set_multiple(struct cf_mips_dev *dev)
++{
++ if (dev->block_size <= 1)
++ return CF_TRANS_OK;
++
++ wareg(dev->block_size, ATA_REG_SC,dev);
++ wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev);
++ wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev);
++
++ return wait_not_busy(10 * SECS, 1,dev);
++}
++
++static int set_cmd(struct cf_mips_dev *dev)
++{
++ //DEBUGP(KERN_INFO "cf-mips: ata cmd 0x%02x\n", dev->tcmd);
++ // sector_count should be <=24 bits..
++ BUG_ON(dev->tsect_start>=0x10000000);
++ // This way, it addresses 2^24 * 512 = 128G
++
++ if (dev->tsector_count) {
++ wareg(dev->tsector_count & 0xff, ATA_REG_SC,dev);
++ wareg(dev->tsect_start & 0xff, ATA_REG_SN,dev);
++ wareg((dev->tsect_start >> 8) & 0xff, ATA_REG_CL,dev);
++ wareg((dev->tsect_start >> 16) & 0xff, ATA_REG_CH,dev);
++ }
++ wareg(((dev->tsect_start >> 24) & 0x0f) | ATA_REG_DH_BASE | ATA_REG_DH_LBA,
++ ATA_REG_DH,dev); /* select drive on all commands */
++ wareg(dev->tcmd, ATA_REG_CMD,dev);
++ return wait_not_busy(10 * SECS, 1,dev);
++}
++
++static int do_trans(struct cf_mips_dev *dev)
++{
++ int res;
++ unsigned st;
++ int transfered;
++
++ //printk("do_trans: %d sectors left\n",dev->tsectors_left);
++ while (dev->tsectors_left) {
++ transfered = 0;
++
++ st = rareg(ATA_REG_ST,dev);
++ if (!(st & ATA_REG_ST_DRQ)) {
++ printk(KERN_ERR "cf-mips: do_trans without DRQ (status 0x%x)!\n", st);
++ if (st & ATA_REG_ST_ERR) {
++ int errId = rareg(ATA_REG_ERR,dev);
++ printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n",
++ (dev->tread ? "read" : "write"), st, errId);
++ }
++ return CF_TRANS_FAILED;
++ }
++ do { /* Fill/read the buffer one block */
++ u32 *qbuf, *qend;
++ qbuf = (u32 *)dev->tbuf;
++ qend = qbuf + CF_SECT_SIZE / sizeof(u32);
++ if (dev->tread) {
++ while (qbuf!=qend)
++ put_unaligned(*DBUF32,qbuf++);
++ //*(qbuf++) = *DBUF32;
++ }
++ else {
++ while(qbuf!=qend)
++ *DBUF32 = get_unaligned(qbuf++);
++ }
++
++ dev->tsectors_left--;
++ dev->tbuf += CF_SECT_SIZE;
++ dev->tbuf_size -= CF_SECT_SIZE;
++ transfered++;
++ } while (transfered != dev->block_size && dev->tsectors_left > 0);
++
++ res = wait_not_busy(10 * SECS, 1,dev);
++ if (res != CF_TRANS_OK)
++ return res;
++ };
++
++ st = rareg(ATA_REG_ST,dev);
++ if (st & (ATA_REG_ST_DRQ | ATA_REG_ST_DWF | ATA_REG_ST_ERR)) {
++ if (st & ATA_REG_ST_DRQ) {
++ printk(KERN_ERR "cf-mips: DRQ after all %d sectors are %s"
++ ", status 0x%x\n", dev->tsector_count, (dev->tread ? "read" : "written"), st);
++ } else if (st & ATA_REG_ST_DWF) {
++ printk(KERN_ERR "cf-mips: write fault, status 0x%x\n", st);
++ } else {
++ int errId = rareg(ATA_REG_ERR,dev);
++ printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n",
++ (dev->tread ? "read" : "write"), st, errId);
++ }
++ return CF_TRANS_FAILED;
++ }
++ return CF_TRANS_OK;
++}
++
++static int cf_do_state(struct cf_mips_dev *dev)
++{
++ int res;
++ switch (dev->tstate) { /* fall through everywhere */
++ case TS_IDLE:
++ dev->tstate = TS_READY;
++ if (is_busy(dev)) {
++ dev->tstate = TS_AFTER_RESET;
++ res = do_reset(dev);
++ if (res != CF_TRANS_OK)
++ break;
++ }
++ case TS_AFTER_RESET:
++ if (dev->tstate == TS_AFTER_RESET) {
++ dev->tstate = TS_READY;
++ res = set_multiple(dev);
++ if (res != CF_TRANS_OK)
++ break;
++ }
++ case TS_READY:
++ dev->tstate = TS_CMD;
++ res = set_cmd(dev);
++ if (res != CF_TRANS_OK)
++ break;;
++ case TS_CMD:
++ dev->tstate = TS_TRANS;
++ case TS_TRANS:
++ res = do_trans(dev);
++ break;
++ default:
++ printk(KERN_ERR "cf-mips: BUG: unknown tstate %d\n", dev->tstate);
++ return CF_TRANS_FAILED;
++ }
++ if (res != CF_TRANS_IN_PROGRESS)
++ dev->tstate = TS_IDLE;
++ return res;
++}
++
++static void cf_do_tasklet(unsigned long dev_l)
++{
++ struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l;
++ int res;
++
++ disable_irq(dev->irq);
++
++ if (dev->tstate == TS_IDLE)
++ return; /* can happen when irq is first registered */
++
++#if 0
++ DEBUGP(KERN_WARNING "cf-mips: not busy ok (tasklet) status 0x%02x\n",
++ (unsigned) rareg(ATA_REG_ST,dev));
++#endif
++
++ res = cf_do_state(dev);
++ if (res == CF_TRANS_IN_PROGRESS)
++ return;
++ cf_async_trans_done(dev,res);
++}
++
++static void cf_async_timeout(unsigned long dev_l)
++{
++ struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l;
++ disable_irq(dev->irq);
++ /* Perhaps send abort to the device? */
++ printk(KERN_ERR "cf-mips: wait not busy timeout (%lus)"
++ ", status 0x%02x, state %d\n",
++ jiffies - dev->irq_enable_time, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate);
++ dev->tstate = TS_IDLE;
++ cf_async_trans_done(dev,CF_TRANS_FAILED);
++}
++
++int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect,
++ char* buffer, int is_write)
++{
++ BUG_ON(dev->tstate!=TS_IDLE);
++ if (nsect > ATA_MAX_SECT_PER_CMD) {
++ printk(KERN_WARNING "cf-mips: sector count %lu out of range\n",nsect);
++ return CF_TRANS_FAILED;
++ }
++ if (sector + nsect > dev->sectors) {
++ printk(KERN_WARNING "cf-mips: sector %lu out of range\n",sector);
++ return CF_TRANS_FAILED;
++ }
++ dev->tbuf = buffer;
++ dev->tbuf_size = nsect*512;
++ dev->tsect_start = sector;
++ dev->tsector_count = nsect;
++ dev->tsectors_left = dev->tsector_count;
++ dev->tread = (is_write)?0:1;
++
++ dev->tcmd = (dev->block_size == 1 ?
++ (is_write ? ATA_CMD_WRITE_SECTORS : ATA_CMD_READ_SECTORS) :
++ (is_write ? ATA_CMD_WRITE_MULTIPLE : ATA_CMD_READ_MULTIPLE));
++
++ return cf_do_state(dev);
++}
++
++static int do_identify(struct cf_mips_dev *dev)
++{
++ u16 sbuf[CF_SECT_SIZE >> 1];
++ int res;
++ char tstr[17]; //serial
++ BUG_ON(dev->tstate!=TS_IDLE);
++ dev->tbuf = (char *) sbuf;
++ dev->tbuf_size = CF_SECT_SIZE;
++ dev->tsect_start = 0;
++ dev->tsector_count = 0;
++ dev->tsectors_left = 1;
++ dev->tread = 1;
++ dev->tcmd = ATA_CMD_IDENTIFY_DRIVE;
++
++ DEBUGP(KERN_INFO "cf-mips: identify drive..\n");
++ res = cf_do_state(dev);
++ if (res == CF_TRANS_IN_PROGRESS) {
++ printk(KERN_ERR "cf-mips: BUG: async identify cmd\n");
++ return CF_TRANS_FAILED;
++ }
++ if (res != CF_TRANS_OK)
++ return 0;
++
++ dev->head = sbuf[3];
++ dev->cyl = sbuf[1];
++ dev->spt = sbuf[6];
++ dev->sectors = ((unsigned long) sbuf[7] << 16) | sbuf[8];
++ dev->dtype=sbuf[0];
++ memcpy(tstr,&sbuf[12],16);
++ tstr[16]=0;
++ printk(KERN_INFO "cf-mips: %s detected, C/H/S=%d/%d/%d sectors=%u (%uMB) Serial=%s\n",
++ (sbuf[0] == 0x848A ? "CF card" : "ATA drive"), dev->cyl, dev->head,
++ dev->spt, dev->sectors, dev->sectors >> 11,tstr);
++ return 1;
++}
++
++static void init_multiple(struct cf_mips_dev * dev)
++{
++ int res;
++ DEBUGP(KERN_INFO "cf-mips: detecting block size\n");
++
++ dev->block_size = 128; /* max block size = 128 sectors (64KB) */
++ do {
++ wareg(dev->block_size, ATA_REG_SC,dev);
++ wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev);
++ wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev);
++
++ res = wait_not_busy(10 * SECS, 1,dev);
++ if (res != CF_TRANS_OK) {
++ printk(KERN_ERR "cf-mips: failed to detect block size: busy!\n");
++ dev->block_size = 1;
++ return;
++ }
++ if ((rareg(ATA_REG_ST,dev) & ATA_REG_ST_ERR) == 0)
++ break;
++ dev->block_size /= 2;
++ } while (dev->block_size > 1);
++
++ printk(KERN_INFO "cf-mips: multiple sectors = %d\n", dev->block_size);
++}
++
++int cf_init(struct cf_mips_dev *dev)
++{
++ tasklet_init(&dev->tasklet,cf_do_tasklet,(unsigned long)dev);
++ dev->baddr = ioremap_nocache((unsigned long)dev->base, CFDEV_BUF_SIZE);
++ if (!dev->baddr) {
++ printk(KERN_ERR "cf-mips: cf_init: ioremap for (%lx,%x) failed\n",
++ (unsigned long) dev->base, CFDEV_BUF_SIZE);
++ return -EBUSY;
++ }
++
++ if (!cf_present(dev)) {
++ printk(KERN_WARNING "cf-mips: cf card not present\n");
++ iounmap(dev->baddr);
++ return -ENODEV;
++ }
++
++ if (do_reset(dev) != CF_TRANS_OK) {
++ printk(KERN_ERR "cf-mips: cf reset failed\n");
++ iounmap(dev->baddr);
++ return -EBUSY;
++ }
++
++ if (!do_identify(dev)) {
++ printk(KERN_ERR "cf-mips: cf identify failed\n");
++ iounmap(dev->baddr);
++ return -EBUSY;
++ }
++
++/* set_apm_level(ATA_APM_WITH_STANDBY); */
++ init_multiple(dev);
++
++ init_timer(&dev->to_timer);
++ dev->to_timer.function = cf_async_timeout;
++ dev->to_timer.data = (unsigned long)dev;
++
++ prepare_cf_irq(dev);
++ if (request_irq(dev->irq, cf_irq_handler, 0, "CF Mips", dev)) {
++ printk(KERN_ERR "cf-mips: failed to get irq\n");
++ iounmap(dev->baddr);
++ return -EBUSY;
++ }
++ /* Disable below would be odd, because request will enable, and the tasklet
++ will disable it itself */
++ //disable_irq(dev->irq);
++
++ dev->async_mode = 1;
++
++ return 0;
++}
++
++void cf_cleanup(struct cf_mips_dev *dev)
++{
++ iounmap(dev->baddr);
++ free_irq(dev->irq, NULL);
++#if REQUEST_MEM_REGION
++ release_mem_region((unsigned long)dev->base, CFDEV_BUF_SIZE);
++#endif
++}
++
++
++/*eof*/
+diff -urN linux.old/drivers/block/rb500/ata.h linux.dev/drivers/block/rb500/ata.h
+--- linux.old/drivers/block/rb500/ata.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/block/rb500/ata.h 2006-06-09 00:15:23.000000000 +0200
+@@ -0,0 +1,132 @@
++#ifndef __CFMIPS_ATA_H__
++#define __CFMIPS_ATA_H__
++
++#include <linux/interrupt.h>
++
++#define CFG_DC_DEV1 (void*)0xb8010010
++#define CFG_DC_DEVBASE 0x0
++#define CFG_DC_DEVMASK 0x4
++#define CFG_DC_DEVC 0x8
++#define CFG_DC_DEVTC 0xC
++
++#define CFDEV_BUF_SIZE 0x1000
++#define ATA_CIS_OFFSET 0x200
++#define ATA_REG_OFFSET 0x800
++#define ATA_DBUF_OFFSET 0xC00
++
++#define ATA_REG_FEAT 0x1
++#define ATA_REG_SC 0x2
++#define ATA_REG_SN 0x3
++#define ATA_REG_CL 0x4
++#define ATA_REG_CH 0x5
++#define ATA_REG_DH 0x6
++#define ATA_REG_DH_BASE 0xa0
++#define ATA_REG_DH_LBA 0x40
++#define ATA_REG_DH_DRV 0x10
++#define ATA_REG_CMD 0x7
++#define ATA_REG_ST 0x7
++#define ATA_REG_ST_BUSY 0x80
++#define ATA_REG_ST_RDY 0x40
++#define ATA_REG_ST_DWF 0x20
++#define ATA_REG_ST_DSC 0x10
++#define ATA_REG_ST_DRQ 0x08
++#define ATA_REG_ST_CORR 0x04
++#define ATA_REG_ST_ERR 0x01
++#define ATA_REG_ERR 0xd
++#define ATA_REG_DC 0xe
++#define ATA_REG_DC_IEN 0x02
++#define ATA_REG_DC_SRST 0x04
++
++#define ATA_CMD_READ_SECTORS 0x20
++#define ATA_CMD_WRITE_SECTORS 0x30
++#define ATA_CMD_EXEC_DRIVE_DIAG 0x90
++#define ATA_CMD_READ_MULTIPLE 0xC4
++#define ATA_CMD_WRITE_MULTIPLE 0xC5
++#define ATA_CMD_SET_MULTIPLE 0xC6
++#define ATA_CMD_IDENTIFY_DRIVE 0xEC
++#define ATA_CMD_SET_FEATURES 0xEF
++
++#define ATA_FEATURE_ENABLE_APM 0x05
++#define ATA_FEATURE_DISABLE_APM 0x85
++#define ATA_APM_DISABLED 0x00
++#define ATA_APM_MIN_POWER 0x01
++#define ATA_APM_WITH_STANDBY 0x7f
++#define ATA_APM_WITHOUT_STANDBY 0x80
++#define ATA_APM_MAX_PERFORMANCE 0xfe
++
++#define CF_SECT_SIZE 0x200
++/* That is the ratio CF_SECT_SIZE/512 (the kernel sector size) */
++#define CF_KERNEL_MUL 1
++#define ATA_MAX_SECT_PER_CMD 0x100
++
++#define CF_TRANS_FAILED 0
++#define CF_TRANS_OK 1
++#define CF_TRANS_IN_PROGRESS 2
++
++
++enum trans_state {
++ TS_IDLE = 0,
++ TS_AFTER_RESET,
++ TS_READY,
++ TS_CMD,
++ TS_TRANS
++};
++
++//
++// #if DEBUG
++// static unsigned long busy_time;
++// #endif
++
++/** Struct to hold the cfdev
++Actually, all the data here only has one instance. However, for
++reasons of programming conformity, it is passed around as a pointer
++*/
++struct cf_mips_dev {
++ void *base; /* base address for I/O */
++ void *baddr; /* remapped address */
++
++ int pin; /* gpio pin */
++ int irq; /* gpio irq */
++
++ unsigned head;
++ unsigned cyl;
++ unsigned spt;
++ unsigned sectors;
++
++ unsigned short block_size;
++ unsigned dtype ; // ATA or CF
++ struct request_queue *queue;
++ struct gendisk *gd;
++
++ /* Transaction state */
++ enum trans_state tstate;
++ char *tbuf;
++ unsigned long tbuf_size;
++ sector_t tsect_start;
++ unsigned tsector_count;
++ unsigned tsectors_left;
++ int tread;
++ unsigned tcmd;
++ int async_mode;
++ unsigned long irq_enable_time;
++
++ struct request *active_req; /* A request is being carried out. Is that different from tstate? */
++ int users;
++ struct timer_list to_timer;
++ struct tasklet_struct tasklet;
++
++ /** This lock ensures that the requests to this device are all done
++ atomically. Transfers can run in parallel, requests are all queued
++ one-by-one */
++ spinlock_t lock;
++};
++
++int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect,
++ char* buffer, int is_write);
++int cf_init(struct cf_mips_dev* dev);
++void cf_cleanup(struct cf_mips_dev* dev);
++
++void cf_async_trans_done(struct cf_mips_dev* dev, int result);
++// void *cf_get_next_buf(unsigned long *buf_size);
++
++#endif
+diff -urN linux.old/drivers/block/rb500/bdev.c linux.dev/drivers/block/rb500/bdev.c
+--- linux.old/drivers/block/rb500/bdev.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/block/rb500/bdev.c 2006-06-15 16:29:04.000000000 +0200
+@@ -0,0 +1,340 @@
++/* CF-mips driver
++ This is a block driver for the direct (mmaped) interface to the CF-slot,
++ found in Routerboard.com's RB532 board
++ See SDK provided from routerboard.com.
++
++ Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6.
++ Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org>
++
++ This work is redistributed under the terms of the GNU General Public License.
++*/
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/time.h>
++#include <linux/wait.h>
++#include <linux/fs.h>
++#include <linux/genhd.h>
++#include <linux/blkdev.h>
++#include <linux/blkpg.h>
++#include <linux/hdreg.h>
++#include <linux/platform_device.h>
++
++#include <asm/uaccess.h>
++#include <asm/io.h>
++
++#include <asm/rc32434/rb.h>
++
++#ifdef DEBUG
++#define DEBUGP printk
++#define DLEVEL 1
++#else
++#define DEBUGP(format, args...)
++#define DLEVEL 0
++#endif
++
++#define CF_MIPS_MAJOR 13
++#define MAJOR_NR CF_MIPS_MAJOR
++#define CF_MAX_PART 16 /* max 15 partitions */
++
++#include "ata.h"
++
++//extern struct block_device_operations cf_bdops;
++
++// static struct hd_struct cf_parts[CF_MAX_PART];
++// static int cf_part_sizes[CF_MAX_PART];
++// static int cf_hsect_sizes[CF_MAX_PART];
++// static int cf_max_sectors[CF_MAX_PART];
++// static int cf_blksize_sizes[CF_MAX_PART];
++
++// static spinlock_t lock = SPIN_LOCK_UNLOCKED;
++
++// volatile int cf_busy = 0;
++
++static struct request *active_req = NULL;
++
++static int cf_open (struct inode *, struct file *);
++static int cf_release (struct inode *, struct file *);
++static int cf_ioctl (struct inode *, struct file *, unsigned, unsigned long);
++
++static void cf_request(request_queue_t * q);
++static int cf_transfer(const struct request *req);
++
++/*long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
++long (*compat_ioctl) (struct file *, unsigned, unsigned long);*/
++// int (*direct_access) (struct block_device *, sector_t, unsigned long *);
++// int (*media_changed) (struct gendisk *);
++// int (*revalidate_disk) (struct gendisk *);
++
++static struct block_device_operations cf_bdops = {
++ .owner = THIS_MODULE,
++ .open = cf_open,
++ .release = cf_release,
++ .ioctl = cf_ioctl,
++ .media_changed = NULL,
++ .unlocked_ioctl = NULL,
++ .revalidate_disk = NULL,
++ .compat_ioctl = NULL,
++ .direct_access = NULL
++};
++
++
++int cf_mips_probe(struct platform_device *pdev)
++{
++ struct gendisk* cf_gendisk=NULL;
++ struct cf_device *cdev = (struct cf_device *) pdev->dev.platform_data;
++ struct cf_mips_dev *dev;
++ struct resource *r;
++ int reg_result;
++
++ reg_result = register_blkdev(MAJOR_NR, "cf-mips");
++ if (reg_result < 0) {
++ printk(KERN_WARNING "cf-mips: can't get major %d\n", MAJOR_NR);
++ return reg_result;
++ }
++
++ dev = (struct cf_mips_dev *)kmalloc(sizeof(struct cf_mips_dev),GFP_KERNEL);
++ if (!dev)
++ goto out_err;
++ memset(dev, 0, sizeof(struct cf_mips_dev));
++ cdev->dev = dev;
++
++ dev->pin = cdev->gpio_pin;
++ dev->irq = platform_get_irq_byname(pdev, "cf_irq");
++ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cf_membase");
++ dev->base = (void *) r->start;
++
++ if (cf_init(dev)) goto out_err;
++ printk("init done");
++
++ spin_lock_init(&dev->lock);
++ dev->queue = blk_init_queue(cf_request,&dev->lock);
++ if (!dev->queue){
++ printk(KERN_ERR "cf-mips: no mem for queue\n");
++ goto out_err;
++ }
++ blk_queue_max_sectors(dev->queue,ATA_MAX_SECT_PER_CMD);
++
++ /* For memory devices, it is always better to avoid crossing segments
++ inside the same request. */
++/* if (dev->dtype==0x848A){
++ printk(KERN_INFO "Setting boundary for cf to 0x%x",(dev->block_size*512)-1);
++ blk_queue_segment_boundary(dev->queue, (dev->block_size*512)-1);
++ }*/
++
++ dev->gd = alloc_disk(CF_MAX_PART);
++ cf_gendisk = dev->gd;
++ cdev->gd = dev->gd;
++ if (!cf_gendisk) goto out_err; /* Last of these goto's */
++
++ cf_gendisk->major = MAJOR_NR;
++ cf_gendisk->first_minor = 0;
++ cf_gendisk->queue=dev->queue;
++ BUG_ON(cf_gendisk->minors != CF_MAX_PART);
++ strcpy(cf_gendisk->disk_name,"cfa");
++ strcpy(cf_gendisk->devfs_name,"cf/card0");
++ cf_gendisk->fops = &cf_bdops;
++ cf_gendisk->flags = 0 ; /* is not yet GENHD_FL_REMOVABLE */
++ cf_gendisk->private_data=dev;
++
++ set_capacity(cf_gendisk,dev->sectors * CF_KERNEL_MUL);
++
++ /* Let the disk go live */
++ add_disk(cf_gendisk);
++#if 0
++ result = cf_init();
++
++ /* default cfg for all partitions */
++ memset(cf_parts, 0, sizeof (cf_parts[0]) * CF_MAX_PART);
++ memset(cf_part_sizes, 0, sizeof (cf_part_sizes[0]) * CF_MAX_PART);
++ for (i = 0; i < CF_MAX_PART; ++i) {
++ cf_hsect_sizes[i] = CF_SECT_SIZE;
++ cf_max_sectors[i] = ATA_MAX_SECT_PER_CMD;
++ cf_blksize_sizes[i] = BLOCK_SIZE;
++ }
++
++ /* setup info for whole disk (partition 0) */
++ cf_part_sizes[0] = cf_sectors / 2;
++ cf_parts[0].nr_sects = cf_sectors;
++
++ blk_size[MAJOR_NR] = cf_part_sizes;
++ blksize_size[MAJOR_NR] = cf_blksize_sizes;
++ max_sectors[MAJOR_NR] = cf_max_sectors;
++ hardsect_size[MAJOR_NR] = cf_hsect_sizes;
++ read_ahead[MAJOR_NR] = 8; /* (4kB) */
++
++ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
++
++ add_gendisk(&cf_gendisk);
++#endif
++// printk(KERN_INFO "cf-mips partition check: \n");
++// register_disk(cf_gendisk, MKDEV(MAJOR_NR, 0), CF_MAX_PART,
++// &cf_bdops, dev->sectors);
++ return 0;
++
++out_err:
++ if (dev->queue){
++ blk_cleanup_queue(dev->queue);
++ }
++ if (reg_result) {
++ unregister_blkdev(MAJOR_NR, "cf-mips");
++ return reg_result;
++ }
++ if (dev){
++ cf_cleanup(dev);
++ kfree(dev);
++ }
++ return 1;
++}
++
++static int
++cf_mips_remove(struct platform_device *pdev)
++{
++ struct cf_device *cdev = (struct cf_device *) pdev->dev.platform_data;
++ struct cf_mips_dev *dev = (struct cf_mips_dev *) cdev->dev;
++
++ unregister_blkdev(MAJOR_NR, "cf-mips");
++ blk_cleanup_queue(dev->queue);
++
++ del_gendisk(dev->gd);
++ cf_cleanup(dev);
++ return 0;
++}
++
++
++static struct platform_driver cf_driver = {
++ .driver.name = "rb500-cf",
++ .probe = cf_mips_probe,
++ .remove = cf_mips_remove,
++};
++
++static int __init cf_mips_init(void)
++{
++ printk(KERN_INFO "cf-mips module loaded\n");
++ return platform_driver_register(&cf_driver);
++}
++
++static void cf_mips_cleanup(void)
++{
++ platform_driver_unregister(&cf_driver);
++ printk(KERN_INFO "cf-mips module removed\n");
++}
++
++module_init(cf_mips_init);
++module_exit(cf_mips_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_ALIAS_BLOCKDEV_MAJOR(CF_MIPS_MAJOR);
++
++
++static int cf_open(struct inode *inode, struct file *filp)
++{
++ struct cf_mips_dev *dev=inode->i_bdev->bd_disk->private_data;
++ int minor = MINOR(inode->i_rdev);
++
++ if (minor >= CF_MAX_PART)
++ return -ENODEV;
++ //DEBUGP(KERN_INFO "cf-mips module opened, minor %d\n", minor);
++ spin_lock(&dev->lock);
++ dev->users++;
++ spin_unlock(&dev->lock);
++ filp->private_data=dev;
++
++ /* dirty workaround to set CFRDY GPIO as an input when some other
++ program sets it as an output */
++ gpio_set(CFG, (1 << dev->pin), 0);
++ return 0; /* success */
++}
++
++static int cf_release(struct inode *inode, struct file *filp)
++{
++ int minor = MINOR(inode->i_rdev);
++ struct cf_mips_dev *dev=inode->i_bdev->bd_disk->private_data;
++ spin_lock(&dev->lock);
++ dev->users--;
++ spin_unlock(&dev->lock);
++ return 0;
++}
++
++static int cf_ioctl(struct inode *inode, struct file *filp,
++ unsigned int cmd, unsigned long arg)
++{
++ unsigned minor = MINOR(inode->i_rdev);
++ struct cf_mips_dev *dev=inode->i_bdev->bd_disk->private_data;
++
++ DEBUGP(KERN_INFO "cf_ioctl cmd %u\n", cmd);
++ switch (cmd) {
++ case BLKRRPART: /* re-read partition table */
++ if (!capable(CAP_SYS_ADMIN))
++ return -EACCES;
++ printk(KERN_INFO "cf-mips partition check: \n");
++ register_disk(dev->gd);
++ return 0;
++
++ case HDIO_GETGEO:
++ {
++ struct hd_geometry geo;
++ geo.cylinders = dev->cyl;
++ geo.heads = dev->head;
++ geo.sectors = dev->spt;
++ geo.start = (*dev->gd->part)[minor].start_sect;
++ if (copy_to_user((void *) arg, &geo, sizeof (geo)))
++ return -EFAULT;
++ }
++ return 0;
++ }
++
++ return -EINVAL; /* unknown command */
++}
++
++static void cf_request(request_queue_t * q)
++{
++ struct cf_mips_dev* dev;
++
++ struct request * req;
++ int status;
++
++ /* We could have q->queuedata = dev , but haven't yet. */
++ if (active_req)
++ return;
++
++ while ((req=elv_next_request(q))!=NULL){
++ dev=req->rq_disk->private_data;
++ status=cf_transfer(req);
++ if (status==CF_TRANS_IN_PROGRESS){
++ active_req=req;
++ return;
++ }
++ end_request(req,status);
++ }
++}
++
++static int cf_transfer(const struct request *req)
++{
++ struct cf_mips_dev* dev=req->rq_disk->private_data;
++
++ if (!blk_fs_request(req)){
++ if (printk_ratelimit())
++ printk(KERN_WARNING "cf-mips: skipping non-fs request 0x%x\n",req->cmd[0]);
++ return CF_TRANS_FAILED;
++ }
++
++ return cf_do_transfer(dev,req->sector,req->current_nr_sectors,req->buffer,rq_data_dir(req));
++}
++
++void cf_async_trans_done(struct cf_mips_dev * dev,int result)
++{
++ struct request *req;
++
++ spin_lock(&dev->lock);
++ req=active_req;
++ active_req=NULL;
++ end_request(req,result);
++ spin_unlock(&dev->lock);
++
++ spin_lock(&dev->lock);
++ cf_request(dev->queue);
++ spin_unlock(&dev->lock);
++}
++
+diff -urN linux.old/drivers/block/rb500/Makefile linux.dev/drivers/block/rb500/Makefile
+--- linux.old/drivers/block/rb500/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/drivers/block/rb500/Makefile 2006-06-08 22:14:58.000000000 +0200
+@@ -0,0 +1,3 @@
++## Makefile for the RB532 CF port
++
++obj-y += bdev.o ata.o
+diff -urN linux.old/drivers/Makefile linux.dev/drivers/Makefile
+--- linux.old/drivers/Makefile 2006-06-08 20:20:52.000000000 +0200
++++ linux.dev/drivers/Makefile 2006-06-08 22:14:58.000000000 +0200
+@@ -73,3 +73,4 @@
+ obj-y += firmware/
+ obj-$(CONFIG_CRYPTO) += crypto/
+ obj-$(CONFIG_SUPERH) += sh/
++obj-$(CONFIG_BLK_DEV_CF_MIPS) += block/rb500/
+\ No newline at end of file
diff --git a/target/linux/rb532-2.6/patches/130-custom_partitions.patch b/target/linux/rb532-2.6/patches/130-custom_partitions.patch
new file mode 100644
index 0000000..e4b3327
--- /dev/null
+++ b/target/linux/rb532-2.6/patches/130-custom_partitions.patch
@@ -0,0 +1,311 @@
+diff -urN linux.old/fs/partitions/check.c linux.dev/fs/partitions/check.c
+--- linux.old/fs/partitions/check.c 2006-05-31 02:31:44.000000000 +0200
++++ linux.dev/fs/partitions/check.c 2006-06-15 01:27:17.000000000 +0200
+@@ -29,6 +29,7 @@
+ #include "ldm.h"
+ #include "mac.h"
+ #include "msdos.h"
++#include "openwrt.h"
+ #include "osf.h"
+ #include "sgi.h"
+ #include "sun.h"
+@@ -48,6 +49,9 @@
+ * Probe partition formats with tables at disk address 0
+ * that also have an ADFS boot block at 0xdc0.
+ */
++#ifdef CONFIG_OPENWRT_PARTITION
++ openwrt_partition,
++#endif
+ #ifdef CONFIG_ACORN_PARTITION_ICS
+ adfspart_check_ICS,
+ #endif
+diff -urN linux.old/fs/partitions/Kconfig linux.dev/fs/partitions/Kconfig
+--- linux.old/fs/partitions/Kconfig 2006-05-31 02:31:44.000000000 +0200
++++ linux.dev/fs/partitions/Kconfig 2006-06-15 01:27:17.000000000 +0200
+@@ -14,6 +14,12 @@
+
+ If unsure, say N.
+
++config OPENWRT_PARTITION
++ bool "OpenWrt partition support" if PARTITION_ADVANCED
++ default y
++ help
++ Support the custom OpenWrt partition map
++
+ config ACORN_PARTITION
+ bool "Acorn partition support" if PARTITION_ADVANCED
+ default y if ARCH_ACORN
+diff -urN linux.old/fs/partitions/Makefile linux.dev/fs/partitions/Makefile
+--- linux.old/fs/partitions/Makefile 2006-05-31 02:31:44.000000000 +0200
++++ linux.dev/fs/partitions/Makefile 2006-06-15 01:27:17.000000000 +0200
+@@ -11,6 +11,7 @@
+ obj-$(CONFIG_MAC_PARTITION) += mac.o
+ obj-$(CONFIG_LDM_PARTITION) += ldm.o
+ obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
++obj-$(CONFIG_OPENWRT_PARTITION) += openwrt.o
+ obj-$(CONFIG_OSF_PARTITION) += osf.o
+ obj-$(CONFIG_SGI_PARTITION) += sgi.o
+ obj-$(CONFIG_SUN_PARTITION) += sun.o
+diff -urN linux.old/fs/partitions/openwrt.c linux.dev/fs/partitions/openwrt.c
+--- linux.old/fs/partitions/openwrt.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/fs/partitions/openwrt.c 2006-06-15 01:27:17.000000000 +0200
+@@ -0,0 +1,249 @@
++/*
++ * fs/partitions/openwrt.c
++ *
++ * Code extracted from drivers/block/genhd.c
++ * and fs/partitions/msdos.c
++ *
++ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 1991-1998 Linus Torvalds
++ *
++ * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
++ * in the early extended-partition checks and added DM partitions
++ *
++ * Support for DiskManager v6.0x added by Mark Lord,
++ * with information provided by OnTrack. This now works for linux fdisk
++ * and LILO, as well as loadlin and bootln. Note that disks other than
++ * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
++ *
++ * More flexible handling of extended partitions - aeb, 950831
++ *
++ * Check partition table on IDE disks for common CHS translations
++ *
++ * Re-organised Feb 1998 Russell King
++ */
++
++#include <linux/config.h>
++
++#include "check.h"
++#include "openwrt.h"
++
++/*
++ * Many architectures don't like unaligned accesses, while
++ * the nr_sects and start_sect partition table entries are
++ * at a 2 (mod 4) address.
++ */
++#include <asm/unaligned.h>
++
++#define SYS_IND(p) (get_unaligned(&p->sys_ind))
++#define NR_SECTS(p) ({ __typeof__(p->nr_sects) __a = \
++ get_unaligned(&p->nr_sects); \
++ le32_to_cpu(__a); \
++ })
++
++#define START_SECT(p) ({ __typeof__(p->start_sect) __a = \
++ get_unaligned(&p->start_sect); \
++ le32_to_cpu(__a); \
++ })
++
++static inline int is_extended_partition(struct partition *p)
++{
++ return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
++ SYS_IND(p) == WIN98_EXTENDED_PARTITION ||
++ SYS_IND(p) == LINUX_EXTENDED_PARTITION);
++}
++
++#define MSDOS_LABEL_MAGIC1 0x55
++#define MSDOS_LABEL_MAGIC2 0xAA
++
++static inline int
++msdos_magic_present(unsigned char *p)
++{
++ return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
++}
++
++static inline int
++openwrt_magic_present(unsigned char *p)
++{
++ return (p[0] == 'O' &&
++ p[1] == 'W' &&
++ p[2] == 'R' &&
++ p[3] == 'T');
++}
++
++/*
++ * Create devices for each logical partition in an extended partition.
++ * The logical partitions form a linked list, with each entry being
++ * a partition table with two entries. The first entry
++ * is the real data partition (with a start relative to the partition
++ * table start). The second is a pointer to the next logical partition
++ * (with a start relative to the entire extended partition).
++ * We do not create a Linux partition for the partition tables, but
++ * only for the actual data partitions.
++ */
++
++static void
++parse_extended(struct parsed_partitions *state, struct block_device *bdev,
++ u32 first_sector, u32 first_size)
++{
++ struct partition *p;
++ Sector sect;
++ unsigned char *data;
++ u32 this_sector, this_size;
++ int sector_size = bdev_hardsect_size(bdev) / 512;
++ int loopct = 0; /* number of links followed
++ without finding a data partition */
++ int i;
++
++ this_sector = first_sector;
++ this_size = first_size;
++
++ while (1) {
++ if (++loopct > 100)
++ return;
++ if (state->next == state->limit)
++ return;
++ data = read_dev_sector(bdev, this_sector, &sect);
++ if (!data)
++ return;
++
++ if (!msdos_magic_present(data + 510))
++ goto done;
++
++ p = (struct partition *) (data + 0x1be);
++
++ /*
++ * Usually, the first entry is the real data partition,
++ * the 2nd entry is the next extended partition, or empty,
++ * and the 3rd and 4th entries are unused.
++ * However, DRDOS sometimes has the extended partition as
++ * the first entry (when the data partition is empty),
++ * and OS/2 seems to use all four entries.
++ */
++
++ /*
++ * First process the data partition(s)
++ */
++ for (i=0; i<4; i++, p++) {
++ u32 offs, size, next;
++ if (!NR_SECTS(p) || is_extended_partition(p))
++ continue;
++
++ /* Check the 3rd and 4th entries -
++ these sometimes contain random garbage */
++ offs = START_SECT(p)*sector_size;
++ size = NR_SECTS(p)*sector_size;
++ next = this_sector + offs;
++ if (i >= 2) {
++ if (offs + size > this_size)
++ continue;
++ if (next < first_sector)
++ continue;
++ if (next + size > first_sector + first_size)
++ continue;
++ }
++
++ put_partition(state, state->next, next, size);
++ if (SYS_IND(p) == LINUX_RAID_PARTITION)
++ state->parts[state->next].flags = 1;
++ loopct = 0;
++ if (++state->next == state->limit)
++ goto done;
++ }
++ /*
++ * Next, process the (first) extended partition, if present.
++ * (So far, there seems to be no reason to make
++ * parse_extended() recursive and allow a tree
++ * of extended partitions.)
++ * It should be a link to the next logical partition.
++ */
++ p -= 4;
++ for (i=0; i<4; i++, p++)
++ if (NR_SECTS(p) && is_extended_partition(p))
++ break;
++ if (i == 4)
++ goto done; /* nothing left to do */
++
++ this_sector = first_sector + START_SECT(p) * sector_size;
++ this_size = NR_SECTS(p) * sector_size;
++ put_dev_sector(sect);
++ }
++done:
++ put_dev_sector(sect);
++}
++
++
++int openwrt_partition(struct parsed_partitions *state, struct block_device *bdev)
++{
++ int sector_size = bdev_hardsect_size(bdev) / 512;
++ Sector sect;
++ unsigned char *data;
++ struct partition *p;
++ int slot;
++ u32 last_block = 0;
++ u32 size = 0;
++ int firstfree = 5;
++
++ data = read_dev_sector(bdev, 0, &sect);
++ if (!data)
++ return -1;
++ if (!openwrt_magic_present(data)) {
++ printk("No OpenWrt partition table detected\n");
++ put_dev_sector(sect);
++ return 0;
++ }
++
++ /*
++ * Now that the 55aa signature is present, this is probably
++ * either the boot sector of a FAT filesystem or a DOS-type
++ * partition table. Reject this in case the boot indicator
++ * is not 0 or 0x80.
++ */
++ p = (struct partition *) (data + 0x1be);
++ for (slot = 1; slot <= 4; slot++, p++) {
++ if (p->boot_ind != 0 && p->boot_ind != 0x80) {
++ put_dev_sector(sect);
++ return 0;
++ }
++ }
++
++ p = (struct partition *) (data + 0x1be);
++
++ /*
++ * Look for partitions in two passes:
++ * First find the primary and DOS-type extended partitions.
++ */
++
++ state->next = 6;
++ for (slot = 1 ; slot <= 4 ; slot++, p++) {
++ u32 start = START_SECT(p)*sector_size;
++ size = NR_SECTS(p)*sector_size;
++ if (!size) {
++ if (firstfree > slot)
++ firstfree = slot;
++
++ continue;
++ }
++ if (is_extended_partition(p)) {
++ /* prevent someone doing mkfs or mkswap on an
++ extended partition, but leave room for LILO */
++ last_block = start + size;
++ put_partition(state, slot, start, size == 1 ? 1 : 2);
++ printk(" <");
++ parse_extended(state, bdev, start, size);
++ printk(" >");
++ continue;
++ }
++ if ((start + size) > get_capacity(bdev->bd_disk))
++ size = get_capacity(bdev->bd_disk) - start;
++ last_block = start + size;
++ put_partition(state, slot, start, size);
++ }
++ if (last_block + 1024 < (size = get_capacity(bdev->bd_disk)))
++ put_partition(state, firstfree, last_block, size - last_block);
++
++ printk("\n");
++
++ put_dev_sector(sect);
++ return 1;
++}
++
+diff -urN linux.old/fs/partitions/openwrt.h linux.dev/fs/partitions/openwrt.h
+--- linux.old/fs/partitions/openwrt.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.dev/fs/partitions/openwrt.h 2006-06-15 01:27:17.000000000 +0200
+@@ -0,0 +1,6 @@
++/*
++ * fs/partitions/openwrt.h
++ */
++
++int openwrt_partition(struct parsed_partitions *state, struct block_device *bdev);
++
diff --git a/target/linux/rb532-2.6/patches/200-bridge_resource_hack.patch b/target/linux/rb532-2.6/patches/200-bridge_resource_hack.patch
new file mode 100644
index 0000000..3017f5d
--- /dev/null
+++ b/target/linux/rb532-2.6/patches/200-bridge_resource_hack.patch
@@ -0,0 +1,13 @@
+--- linux.old/arch/mips/pci/pci.c 2006-04-19 08:10:14.000000000 +0200
++++ linux.dev/arch/mips/pci/pci.c 2006-06-14 20:23:18.000000000 +0200
+@@ -65,8 +65,10 @@
+ /*
+ * Put everything into 0x00-0xff region modulo 0x400
+ */
++#ifndef CONFIG_MIKROTIK_RB500
+ if (start & 0x300)
+ start = (start + 0x3ff) & ~0x3ff;
++#endif
+ } else if (res->flags & IORESOURCE_MEM) {
+ /* Make sure we start at our min on all hoses */
+ if (start < PCIBIOS_MIN_MEM + hose->mem_resource->start)
diff --git a/target/linux/rb532-2.6/patches/210-pci_fixes.patch b/target/linux/rb532-2.6/patches/210-pci_fixes.patch
new file mode 100644
index 0000000..02cd2f0
--- /dev/null
+++ b/target/linux/rb532-2.6/patches/210-pci_fixes.patch
@@ -0,0 +1,46 @@
+diff -urN linux.old/drivers/pci/probe.c linux.dev/drivers/pci/probe.c
+--- linux.old/drivers/pci/probe.c 2006-06-08 20:21:20.000000000 +0200
++++ linux.dev/drivers/pci/probe.c 2006-06-08 20:19:40.000000000 +0200
+@@ -760,15 +760,22 @@
+ u32 l;
+ u8 hdr_type;
+ int delay = 1;
+-
+- if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
+- return NULL;
+-
+- /* some broken boards return 0 or ~0 if a slot is empty: */
+- if (l == 0xffffffff || l == 0x00000000 ||
+- l == 0x0000ffff || l == 0xffff0000)
+- return NULL;
+-
++ do {
++ if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l))
++ return NULL;
++ /* some broken boards return 0 or ~0 if a slot is empty: */
++ if (l == 0xffffffff || l == 0x00000000 ||
++ l == 0x0000ffff || l == 0xffff0000){
++ if (delay > 4)
++ return NULL;
++ /* But that could also be the previous dev not settled */
++ pr_debug("PCI: retrying scan at 0x%x, because config is 0x%x\n",devfn,l);
++ msleep(delay);
++ delay *=2;
++ l=0;
++ }
++ }while (l==0);
++
+ /* Configuration request Retry Status */
+ while (l == 0xffff0001) {
+ msleep(delay);
+@@ -903,7 +910,10 @@
+
+ /* Go find them, Rover! */
+ for (devfn = 0; devfn < 0x100; devfn += 8)
++ {
++ if (bus->number == 0 && (devfn >> 3) > 21) break;
+ pci_scan_slot(bus, devfn);
++ }
+
+ /*
+ * After performing arch-dependent fixup of the bus, look behind
diff --git a/target/linux/rb532-2.6/patches/220-serial_fix.patch b/target/linux/rb532-2.6/patches/220-serial_fix.patch
new file mode 100644
index 0000000..d36f263
--- /dev/null
+++ b/target/linux/rb532-2.6/patches/220-serial_fix.patch
@@ -0,0 +1,18 @@
+diff -urN linux.old/drivers/serial/8250.c linux.dev/drivers/serial/8250.c
+--- linux.old/drivers/serial/8250.c 2006-06-08 20:21:20.000000000 +0200
++++ linux.dev/drivers/serial/8250.c 2006-06-08 20:19:40.000000000 +0200
+@@ -351,6 +351,13 @@
+ default:
+ outb(value, up->port.iobase + offset);
+ }
++
++#if defined(CONFIG_IDT_EB434) || defined(CONFIG_MIKROTIK_RB500)
++ __SLOW_DOWN_IO;
++ __SLOW_DOWN_IO;
++ __SLOW_DOWN_IO;
++ __SLOW_DOWN_IO;
++#endif
+ }
+
+ /*
+
diff --git a/target/linux/rb532-2.6/patches/230-dma_limit.patch b/target/linux/rb532-2.6/patches/230-dma_limit.patch
new file mode 100644
index 0000000..ca87115
--- /dev/null
+++ b/target/linux/rb532-2.6/patches/230-dma_limit.patch
@@ -0,0 +1,13 @@
+diff -urN linux.old/arch/mips/mm/init.c linux.dev/arch/mips/mm/init.c
+--- linux.old/arch/mips/mm/init.c 2006-06-08 20:21:20.000000000 +0200
++++ linux.dev/arch/mips/mm/init.c 2006-06-08 20:19:40.000000000 +0200
+@@ -149,7 +149,7 @@
+ kmap_init();
+ #endif
+
+- max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
++ max_dma = virt_to_phys((char *) (256 * 1024 * 1024)) >> PAGE_SHIFT;
+ low = max_low_pfn;
+ high = highend_pfn;
+
+
diff --git a/target/linux/rb532-2.6/patches/240-via_rhine_performance.patch b/target/linux/rb532-2.6/patches/240-via_rhine_performance.patch
new file mode 100644
index 0000000..56c1fb5
--- /dev/null
+++ b/target/linux/rb532-2.6/patches/240-via_rhine_performance.patch
@@ -0,0 +1,461 @@
+diff -urN linux.old/drivers/net/via-rhine.c linux.dev/drivers/net/via-rhine.c
+--- linux.old/drivers/net/via-rhine.c 2006-06-08 20:21:20.000000000 +0200
++++ linux.dev/drivers/net/via-rhine.c 2006-06-08 20:19:40.000000000 +0200
+@@ -131,6 +131,10 @@
+ - Fix Tx engine race for good
+ - Craig Brind: Zero padded aligned buffers for short packets.
+
++ OpenWrt Version (Felix Fietkau <nbd@openwrt.org>)
++ - Performance improvements
++ - NAPI polling
++
+ */
+
+ #define DRV_NAME "via-rhine"
+@@ -142,7 +146,6 @@
+ These may be modified when a driver module is loaded. */
+
+ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
+-static int max_interrupt_work = 20;
+
+ /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+ Setting to > 1518 effectively disables this feature. */
+@@ -165,9 +168,9 @@
+ Making the Tx ring too large decreases the effectiveness of channel
+ bonding and packet priority.
+ There are no ill effects from too-large receive rings. */
+-#define TX_RING_SIZE 16
+-#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */
+-#define RX_RING_SIZE 16
++#define TX_RING_SIZE 128
++#define TX_QUEUE_LEN 120 /* Limit ring entries actually used. */
++#define RX_RING_SIZE 128
+
+
+ /* Operational parameters that usually are not changed. */
+@@ -201,6 +204,7 @@
+ #include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/uaccess.h>
++#include <asm/unaligned.h>
+
+ /* These identify the driver base version and may not be removed. */
+ static char version[] __devinitdata =
+@@ -217,10 +221,8 @@
+ MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver");
+ MODULE_LICENSE("GPL");
+
+-module_param(max_interrupt_work, int, 0);
+ module_param(debug, int, 0);
+ module_param(rx_copybreak, int, 0);
+-MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt");
+ MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)");
+ MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames");
+
+@@ -461,6 +463,8 @@
+ struct tx_desc *tx_ring;
+ dma_addr_t rx_ring_dma;
+ dma_addr_t tx_ring_dma;
++ u32 istat;
++ u32 imask;
+
+ /* The addresses of receive-in-place skbuffs. */
+ struct sk_buff *rx_skbuff[RX_RING_SIZE];
+@@ -504,9 +508,10 @@
+ static void rhine_check_media_task(struct net_device *dev);
+ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev);
+ static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+-static void rhine_tx(struct net_device *dev);
+-static void rhine_rx(struct net_device *dev);
+-static void rhine_error(struct net_device *dev, int intr_status);
++static int rhine_poll(struct net_device *dev, int *budget);
++static int rhine_tx(struct net_device *dev);
++static int rhine_rx(struct net_device *dev);
++static void rhine_error(struct net_device *dev);
+ static void rhine_set_rx_mode(struct net_device *dev);
+ static struct net_device_stats *rhine_get_stats(struct net_device *dev);
+ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+@@ -601,6 +606,8 @@
+ struct rhine_private *rp = netdev_priv(dev);
+ void __iomem *ioaddr = rp->base;
+
++ pci_enable_device(rp->pdev);
++
+ iowrite8(Cmd1Reset, ioaddr + ChipCmd1);
+ IOSYNC;
+
+@@ -622,6 +629,28 @@
+ "failed" : "succeeded");
+ }
+
++static inline void rhine_intr_enable(struct net_device *dev)
++{
++ struct rhine_private *rp = netdev_priv(dev);
++ void __iomem *ioaddr = rp->base;
++
++ iowrite16(rp->imask = (IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
++ IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
++ IntrTxDone | IntrTxError | IntrTxUnderrun |
++ IntrPCIErr | IntrStatsMax | IntrLinkChange),
++ ioaddr + IntrEnable);
++}
++
++static inline void rhine_intr_disable(struct net_device *dev)
++{
++ struct rhine_private *rp = netdev_priv(dev);
++ void __iomem *ioaddr = rp->base;
++
++ iowrite16(rp->imask = (IntrRxOverflow | IntrRxNoBuf | IntrTxAborted |
++ IntrTxError | IntrTxUnderrun | IntrPCIErr | IntrStatsMax | IntrLinkChange),
++ ioaddr + IntrEnable);
++}
++
+ #ifdef USE_MMIO
+ static void enable_mmio(long pioaddr, u32 quirks)
+ {
+@@ -664,14 +693,26 @@
+
+ }
+
+-#ifdef CONFIG_NET_POLL_CONTROLLER
+-static void rhine_poll(struct net_device *dev)
++static int rhine_poll(struct net_device *dev, int *budget)
+ {
+- disable_irq(dev->irq);
+- rhine_interrupt(dev->irq, (void *)dev, NULL);
+- enable_irq(dev->irq);
++ unsigned int work_done, work_to_do = min(*budget, dev->quota);
++ struct rhine_private *rp = netdev_priv(dev);
++
++ work_done = rhine_rx(dev);
++
++ if (rp->istat & (IntrTxErrSummary | IntrTxDone))
++ rhine_tx(dev);
++
++ *budget -= work_done;
++ dev->quota -= work_done;
++
++ if (work_done < work_to_do) {
++ netif_rx_complete(dev);
++ rhine_intr_enable(dev);
++ }
++
++ return (work_done >= work_to_do);
+ }
+-#endif
+
+ static void rhine_hw_init(struct net_device *dev, long pioaddr)
+ {
+@@ -850,11 +891,10 @@
+ dev->ethtool_ops = &netdev_ethtool_ops;
+ dev->tx_timeout = rhine_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+-#ifdef CONFIG_NET_POLL_CONTROLLER
+- dev->poll_controller = rhine_poll;
+-#endif
+- if (rp->quirks & rqRhineI)
+- dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
++ dev->poll = rhine_poll;
++ dev->weight = 64;
++
++ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
+
+ INIT_WORK(&rp->tx_timeout_task,
+ (void (*)(void *))rhine_tx_timeout_task, dev);
+@@ -904,6 +944,10 @@
+ }
+ }
+ rp->mii_if.phy_id = phy_id;
++
++ // shut down until somebody really needs it
++ iowrite8(0x80, ioaddr + 0xa1);
++ pci_set_power_state(rp->pdev, 3);
+
+ return 0;
+
+@@ -995,7 +1039,7 @@
+
+ /* Fill in the Rx buffers. Handle allocation failure gracefully. */
+ for (i = 0; i < RX_RING_SIZE; i++) {
+- struct sk_buff *skb = dev_alloc_skb(rp->rx_buf_sz);
++ struct sk_buff *skb = dev_alloc_skb(rp->rx_buf_sz + 4);
+ rp->rx_skbuff[i] = skb;
+ if (skb == NULL)
+ break;
+@@ -1115,11 +1159,7 @@
+ rhine_set_rx_mode(dev);
+
+ /* Enable interrupts by setting the interrupt mask. */
+- iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
+- IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
+- IntrTxDone | IntrTxError | IntrTxUnderrun |
+- IntrPCIErr | IntrStatsMax | IntrLinkChange,
+- ioaddr + IntrEnable);
++ rhine_intr_enable(dev);
+
+ iowrite16(CmdStart | CmdTxOn | CmdRxOn | (Cmd1NoTxPoll << 8),
+ ioaddr + ChipCmd);
+@@ -1230,6 +1270,7 @@
+ mdio_read(dev, rp->mii_if.phy_id, MII_BMSR));
+
+ netif_start_queue(dev);
++ netif_poll_enable(dev);
+
+ return 0;
+ }
+@@ -1268,8 +1309,8 @@
+ /* Reinitialize the hardware. */
+ rhine_chip_reset(dev);
+ init_registers(dev);
+-
+ spin_unlock(&rp->lock);
++
+ enable_irq(rp->pdev->irq);
+
+ dev->trans_start = jiffies;
+@@ -1363,69 +1404,56 @@
+ struct net_device *dev = dev_instance;
+ struct rhine_private *rp = netdev_priv(dev);
+ void __iomem *ioaddr = rp->base;
+- u32 intr_status;
+- int boguscnt = max_interrupt_work;
+ int handled = 0;
+
+- while ((intr_status = get_intr_status(dev))) {
++ if ((rp->istat = (get_intr_status(dev) & rp->imask))) {
+ handled = 1;
+
+ /* Acknowledge all of the current interrupt sources ASAP. */
+- if (intr_status & IntrTxDescRace)
++ if (rp->istat & IntrTxDescRace)
+ iowrite8(0x08, ioaddr + IntrStatus2);
+- iowrite16(intr_status & 0xffff, ioaddr + IntrStatus);
++ iowrite16(rp->istat & 0xffff, ioaddr + IntrStatus);
+ IOSYNC;
+
+- if (debug > 4)
+- printk(KERN_DEBUG "%s: Interrupt, status %8.8x.\n",
+- dev->name, intr_status);
++ if (likely(rp->istat & ((IntrRxDone | IntrRxErr | IntrRxDropped |
++ IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf |
++ IntrTxErrSummary | IntrTxDone)))) {
++
++ rhine_intr_disable(dev);
+
+- if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped |
+- IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf))
+- rhine_rx(dev);
+-
+- if (intr_status & (IntrTxErrSummary | IntrTxDone)) {
+- if (intr_status & IntrTxErrSummary) {
+- /* Avoid scavenging before Tx engine turned off */
+- RHINE_WAIT_FOR(!(ioread8(ioaddr+ChipCmd) & CmdTxOn));
+- if (debug > 2 &&
+- ioread8(ioaddr+ChipCmd) & CmdTxOn)
+- printk(KERN_WARNING "%s: "
+- "rhine_interrupt() Tx engine"
+- "still on.\n", dev->name);
+- }
+- rhine_tx(dev);
++ if (likely(netif_rx_schedule_prep(dev)))
++ __netif_rx_schedule(dev);
+ }
+
+ /* Abnormal error summary/uncommon events handlers. */
+- if (intr_status & (IntrPCIErr | IntrLinkChange |
++ if (unlikely(rp->istat & (IntrPCIErr | IntrLinkChange |
+ IntrStatsMax | IntrTxError | IntrTxAborted |
+- IntrTxUnderrun | IntrTxDescRace))
+- rhine_error(dev, intr_status);
+-
+- if (--boguscnt < 0) {
+- printk(KERN_WARNING "%s: Too much work at interrupt, "
+- "status=%#8.8x.\n",
+- dev->name, intr_status);
+- break;
+- }
++ IntrTxUnderrun | IntrTxDescRace)))
++ rhine_error(dev);
+ }
+
+- if (debug > 3)
+- printk(KERN_DEBUG "%s: exiting interrupt, status=%8.8x.\n",
+- dev->name, ioread16(ioaddr + IntrStatus));
+ return IRQ_RETVAL(handled);
+ }
+
+ /* This routine is logically part of the interrupt handler, but isolated
+ for clarity. */
+-static void rhine_tx(struct net_device *dev)
++static int rhine_tx(struct net_device *dev)
+ {
+ struct rhine_private *rp = netdev_priv(dev);
+ int txstatus = 0, entry = rp->dirty_tx % TX_RING_SIZE;
++ void __iomem *ioaddr = rp->base;
++ int done = 0;
+
+- spin_lock(&rp->lock);
++ /* Avoid scavenging before Tx engine turned off */
++ RHINE_WAIT_FOR(!(ioread8(ioaddr+ChipCmd) & CmdTxOn));
++ if (debug > 2 &&
++ ioread8(ioaddr+ChipCmd) & CmdTxOn)
++ printk(KERN_WARNING "%s: "
++ "rhine_interrupt() Tx engine"
++ "still on.\n", dev->name);
+
++
++ spin_lock_irq(&rp->lock);
+ /* find and cleanup dirty tx descriptors */
+ while (rp->dirty_tx != rp->cur_tx) {
+ txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status);
+@@ -1462,6 +1490,7 @@
+ txstatus & 0xF);
+ rp->stats.tx_bytes += rp->tx_skbuff[entry]->len;
+ rp->stats.tx_packets++;
++ done++;
+ }
+ /* Free the original skb. */
+ if (rp->tx_skbuff_dma[entry]) {
+@@ -1470,23 +1499,25 @@
+ rp->tx_skbuff[entry]->len,
+ PCI_DMA_TODEVICE);
+ }
+- dev_kfree_skb_irq(rp->tx_skbuff[entry]);
++ dev_kfree_skb_any(rp->tx_skbuff[entry]);
+ rp->tx_skbuff[entry] = NULL;
+ entry = (++rp->dirty_tx) % TX_RING_SIZE;
+ }
++ spin_unlock_irq(&rp->lock);
++
+ if ((rp->cur_tx - rp->dirty_tx) < TX_QUEUE_LEN - 4)
+ netif_wake_queue(dev);
+
+- spin_unlock(&rp->lock);
++ return done;
+ }
+
+ /* This routine is logically part of the interrupt handler, but isolated
+ for clarity and better register allocation. */
+-static void rhine_rx(struct net_device *dev)
++static int rhine_rx(struct net_device *dev)
+ {
+ struct rhine_private *rp = netdev_priv(dev);
+ int entry = rp->cur_rx % RX_RING_SIZE;
+- int boguscnt = rp->dirty_rx + RX_RING_SIZE - rp->cur_rx;
++ int done = 0;
+
+ if (debug > 4) {
+ printk(KERN_DEBUG "%s: rhine_rx(), entry %d status %8.8x.\n",
+@@ -1503,8 +1534,6 @@
+ if (debug > 4)
+ printk(KERN_DEBUG "rhine_rx() status is %8.8x.\n",
+ desc_status);
+- if (--boguscnt < 0)
+- break;
+ if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) {
+ if ((desc_status & RxWholePkt) != RxWholePkt) {
+ printk(KERN_WARNING "%s: Oversized Ethernet "
+@@ -1528,9 +1557,7 @@
+ if (desc_status & 0x0004) rp->stats.rx_frame_errors++;
+ if (desc_status & 0x0002) {
+ /* this can also be updated outside the interrupt handler */
+- spin_lock(&rp->lock);
+ rp->stats.rx_crc_errors++;
+- spin_unlock(&rp->lock);
+ }
+ }
+ } else {
+@@ -1558,6 +1585,7 @@
+ rp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+ } else {
++ int i;
+ skb = rp->rx_skbuff[entry];
+ if (skb == NULL) {
+ printk(KERN_ERR "%s: Inconsistent Rx "
+@@ -1566,6 +1594,14 @@
+ break;
+ }
+ rp->rx_skbuff[entry] = NULL;
++
++ /* align the data to the ip header - should be faster than using rx_copybreak */
++ for (i = pkt_len - (pkt_len % 4); i >= 0; i -= 4) {
++ put_unaligned(*((u32 *) (skb->data + i)), (u32 *) (skb->data + i + 2));
++ }
++ skb->data += 2;
++ skb->tail += 2;
++
+ skb_put(skb, pkt_len);
+ pci_unmap_single(rp->pdev,
+ rp->rx_skbuff_dma[entry],
+@@ -1573,10 +1609,11 @@
+ PCI_DMA_FROMDEVICE);
+ }
+ skb->protocol = eth_type_trans(skb, dev);
+- netif_rx(skb);
++ netif_receive_skb(skb);
+ dev->last_rx = jiffies;
+ rp->stats.rx_bytes += pkt_len;
+ rp->stats.rx_packets++;
++ done++;
+ }
+ entry = (++rp->cur_rx) % RX_RING_SIZE;
+ rp->rx_head_desc = &rp->rx_ring[entry];
+@@ -1587,7 +1624,7 @@
+ struct sk_buff *skb;
+ entry = rp->dirty_rx % RX_RING_SIZE;
+ if (rp->rx_skbuff[entry] == NULL) {
+- skb = dev_alloc_skb(rp->rx_buf_sz);
++ skb = dev_alloc_skb(rp->rx_buf_sz + 4);
+ rp->rx_skbuff[entry] = skb;
+ if (skb == NULL)
+ break; /* Better luck next round. */
+@@ -1600,6 +1637,8 @@
+ }
+ rp->rx_ring[entry].rx_status = cpu_to_le32(DescOwn);
+ }
++
++ return done;
+ }
+
+ /*
+@@ -1649,11 +1688,11 @@
+
+ }
+
+-static void rhine_error(struct net_device *dev, int intr_status)
++static void rhine_error(struct net_device *dev)
+ {
+ struct rhine_private *rp = netdev_priv(dev);
+ void __iomem *ioaddr = rp->base;
+-
++ u32 intr_status = rp->istat;
+ spin_lock(&rp->lock);
+
+ if (intr_status & IntrLinkChange)
+@@ -1898,6 +1937,7 @@
+
+ /* Disable interrupts by clearing the interrupt mask. */
+ iowrite16(0x0000, ioaddr + IntrEnable);
++ rp->imask = 0;
+
+ /* Stop the chip's Tx and Rx processes. */
+ iowrite16(CmdStop, ioaddr + ChipCmd);
+@@ -1912,6 +1952,9 @@
+ free_tbufs(dev);
+ free_ring(dev);
+
++ writeb(0x80, ioaddr + 0xa1);
++ pci_set_power_state(rp->pdev, 3);
++
+ return 0;
+ }
+
+@@ -1941,6 +1984,7 @@
+ return; /* Nothing to do for non-WOL adapters */
+
+ rhine_power_init(dev);
++ netif_poll_disable(dev);
+
+ /* Make sure we use pattern 0, 1 and not 4, 5 */
+ if (rp->quirks & rq6patterns)
diff --git a/target/linux/sibyte-2.6/Makefile b/target/linux/sibyte-2.6/Makefile
new file mode 100644
index 0000000..30fa1a8
--- /dev/null
+++ b/target/linux/sibyte-2.6/Makefile
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+LINUX_VERSION:=2.6.17
+LINUX_RELEASE:=1
+LINUX_KERNEL_MD5SUM:=37ddefe96625502161f075b9d907f21e
+
+include ./config
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/kernel-build.mk
+
+$(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked
+ [ -d ../generic-$(KERNEL)/patches ] && $(PATCH) $(LINUX_DIR) ../generic-$(KERNEL)/patches
+ [ -d ./patches ] && $(PATCH) $(LINUX_DIR) ./patches
+ @$(CP) config $(LINUX_DIR)/.config
+ touch $@
+
diff --git a/target/linux/sibyte-2.6/config b/target/linux/sibyte-2.6/config
new file mode 100644
index 0000000..79c4c72
--- /dev/null
+++ b/target/linux/sibyte-2.6/config
@@ -0,0 +1,1313 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.16.4
+# Fri Apr 21 16:08:33 2006
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MACH_JAZZ is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+CONFIG_SIBYTE_SWARM=y
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+CONFIG_SIBYTE_SB1250=y
+CONFIG_SIBYTE_SB1xxx_SOC=y
+# CONFIG_CPU_SB1_PASS_1 is not set
+# CONFIG_CPU_SB1_PASS_2_1250 is not set
+# CONFIG_CPU_SB1_PASS_2_2 is not set
+CONFIG_CPU_SB1_PASS_4=y
+# CONFIG_CPU_SB1_PASS_2_112x is not set
+# CONFIG_CPU_SB1_PASS_3 is not set
+CONFIG_SIBYTE_HAS_LDT=y
+# CONFIG_SIMULATION is not set
+# CONFIG_SB1_CEX_ALWAYS_FATAL is not set
+# CONFIG_SB1_CERR_STALL is not set
+CONFIG_SIBYTE_CFE=y
+CONFIG_SIBYTE_CFE_CONSOLE=y
+# CONFIG_SIBYTE_BUS_WATCHER is not set
+# CONFIG_SIBYTE_SB1250_PROF is not set
+# CONFIG_SIBYTE_TBPROF is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DMA_COHERENT=y
+CONFIG_CPU_BIG_ENDIAN=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_BOOT_ELF32=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32_R1 is not set
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+CONFIG_CPU_SB1=y
+CONFIG_SYS_HAS_CPU_SB1=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+#
+# Kernel type
+#
+# CONFIG_32BIT is not set
+CONFIG_64BIT=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_SIBYTE_DMA_PAGEOPS is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_MIPS_MT is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_HIGHMEM=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_PREEMPT_BKL is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_CPUSETS=y
+CONFIG_INITRAMFS_SOURCE="../root"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+CONFIG_STOP_MACHINE=y
+
+#
+# Block layer
+#
+
+#
+# IO Schedulers
+#
+# CONFIG_IOSCHED_NOOP is not set
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is noet set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_MMU=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_BUILD_ELF64=y
+CONFIG_MIPS32_COMPAT=y
+CONFIG_COMPAT=y
+CONFIG_MIPS32_O32=y
+# CONFIG_MIPS32_N32 is not set
+CONFIG_BINFMT_ELF32=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+CONFIG_IPSEC_NAT_TRAVERSAL=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=y
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_BRIDGE_NETFILTER is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=y
+CONFIG_IP_NF_IRC=y
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_SIP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_IPP2P=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_TIME=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+# CONFIG_IP_NF_MATCH_POLICY is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_IMQ=m
+# CONFIG_IP_NF_TARGET_LOG is not set
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_ROUTE=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=y
+CONFIG_IP_NF_NAT_FTP=y
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_SET=m
+CONFIG_IP_NF_SET_MAX=256
+CONFIG_IP_NF_SET_HASHSIZE=1024
+CONFIG_IP_NF_SET_IPMAP=m
+CONFIG_IP_NF_SET_MACIPMAP=m
+CONFIG_IP_NF_SET_PORTMAP=m
+CONFIG_IP_NF_SET_IPHASH=m
+CONFIG_IP_NF_SET_NETHASH=m
+CONFIG_IP_NF_SET_IPTREE=m
+CONFIG_IP_NF_MATCH_SET=m
+CONFIG_IP_NF_TARGET_SET=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_AHESP is not set
+CONFIG_IP6_NF_MATCH_EUI64=m
+# CONFIG_IP6_NF_MATCH_POLICY is not set
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_IMQ=m
+# CONFIG_IP6_NF_TARGET_LOG is not set
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_HL is not set
+# CONFIG_IP6_NF_RAW is not set
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_CLIP_NO_ICMP=y
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_ATM_BR2684_IPFILTER=y
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_ESFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CLS_U32_MARK is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_HAMRADIO=y
+
+#
+# Packet Radio protocols
+#
+CONFIG_AX25=m
+# CONFIG_AX25_DAMA_SLAVE is not set
+# CONFIG_NETROM is not set
+# CONFIG_ROSE is not set
+
+#
+# AX.25 network device drivers
+#
+CONFIG_MKISS=m
+# CONFIG_6PACK is not set
+# CONFIG_BPQETHER is not set
+# CONFIG_BAYCOM_SER_FDX is not set
+# CONFIG_BAYCOM_SER_HDX is not set
+# CONFIG_YAM is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=m
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=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
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=0
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_IMQ=m
+# CONFIG_IMQ_BEHAVIOR_AA is not set
+# CONFIG_IMQ_BEHAVIOR_AB is not set
+CONFIG_IMQ_BEHAVIOR_BA=y
+# CONFIG_IMQ_BEHAVIOR_BB is not set
+CONFIG_IMQ_NUM_DEVS=2
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_NET_SB1250_MAC=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_DM9000 is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+# CONFIG_PRISM54 is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+# CONFIG_HOSTAP_PLX is not set
+# CONFIG_HOSTAP_PCI is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ATM drivers
+#
+CONFIG_ATM_DUMMY=m
+CONFIG_ATM_TCP=m
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_FORE200E_MAYBE is not set
+# CONFIG_ATM_HE is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=m
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=m
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_STALDRV is not set
+CONFIG_SIBYTE_SB1250_DUART=y
+CONFIG_SIBYTE_SB1250_DUART_CONSOLE=y
+# CONFIG_AU1000_UART is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=m
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_SQUASHFS_VMALLOC is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=m
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=15
+CONFIG_CROSSCOMPILE=y
+CONFIG_CMDLINE=""
+# CONFIG_SB1XXX_CORELIS is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/target/linux/sibyte-2.6/patches/000-DUART.patch b/target/linux/sibyte-2.6/patches/000-DUART.patch
new file mode 100644
index 0000000..fe899f1
--- /dev/null
+++ b/target/linux/sibyte-2.6/patches/000-DUART.patch
@@ -0,0 +1,957 @@
+diff -Nur linux-2.6.17/drivers/char/Kconfig linux-2.6.17-owrt/drivers/char/Kconfig
+--- linux-2.6.17/drivers/char/Kconfig 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/drivers/char/Kconfig 2006-06-18 12:41:36.000000000 +0200
+@@ -340,6 +340,14 @@
+ To compile this driver as a module, choose M here: the
+ module will be called istallion.
+
++config SIBYTE_SB1250_DUART
++ bool "Support for BCM1xxx onchip DUART"
++ depends on MIPS && SIBYTE_SB1xxx_SOC=y
++
++config SIBYTE_SB1250_DUART_CONSOLE
++ bool "Console on BCM1xxx DUART"
++ depends on SIBYTE_SB1250_DUART
++
+ config AU1000_UART
+ bool "Enable Au1000 UART Support"
+ depends on SERIAL_NONSTANDARD && MIPS
+diff -Nur linux-2.6.17/drivers/char/Makefile linux-2.6.17-owrt/drivers/char/Makefile
+--- linux-2.6.17/drivers/char/Makefile 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/drivers/char/Makefile 2006-06-18 12:42:57.000000000 +0200
+@@ -31,6 +31,7 @@
+ obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o
+ obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
+ obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
++obj-$(CONFIG_SIBYTE_SB1250_DUART) += sb1250_duart.o
+ obj-$(CONFIG_COMPUTONE) += ip2/
+ obj-$(CONFIG_RISCOM8) += riscom8.o
+ obj-$(CONFIG_ISI) += isicom.o
+diff -Nur linux-2.6.17/drivers/char/sb1250_duart.c linux-2.6.17-owrt/drivers/char/sb1250_duart.c
+--- linux-2.6.17/drivers/char/sb1250_duart.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/drivers/char/sb1250_duart.c 2006-06-18 12:41:36.000000000 +0200
+@@ -0,0 +1,911 @@
++/*
++ * Copyright (C) 2000,2001,2002,2003,2004 Broadcom Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++/*
++ * Driver support for the on-chip sb1250 dual-channel serial port,
++ * running in asynchronous mode. Also, support for doing a serial console
++ * on one of those ports
++ */
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/serial.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/console.h>
++#include <linux/kdev_t.h>
++#include <linux/major.h>
++#include <linux/termios.h>
++#include <linux/spinlock.h>
++#include <linux/irq.h>
++#include <linux/errno.h>
++#include <linux/tty.h>
++#include <linux/sched.h>
++#include <linux/tty_flip.h>
++#include <linux/timer.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <asm/delay.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/sibyte/swarm.h>
++#include <asm/sibyte/sb1250.h>
++#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
++#include <asm/sibyte/bcm1480_regs.h>
++#include <asm/sibyte/bcm1480_int.h>
++#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
++#include <asm/sibyte/sb1250_regs.h>
++#include <asm/sibyte/sb1250_int.h>
++#else
++#error invalid SiByte UART configuation
++#endif
++#include <asm/sibyte/sb1250_uart.h>
++#include <asm/war.h>
++
++#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
++#define UNIT_CHANREG(n,reg) A_BCM1480_DUART_CHANREG((n),(reg))
++#define UNIT_IMRREG(n) A_BCM1480_DUART_IMRREG(n)
++#define UNIT_INT(n) (K_BCM1480_INT_UART_0 + (n))
++#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
++#define UNIT_CHANREG(n,reg) A_DUART_CHANREG((n),(reg))
++#define UNIT_IMRREG(n) A_DUART_IMRREG(n)
++#define UNIT_INT(n) (K_INT_UART_0 + (n))
++#else
++#error invalid SiByte UART configuation
++#endif
++
++/* Toggle spewing of debugging output */
++#undef DEBUG
++
++#define DEFAULT_CFLAGS (CS8 | B115200)
++
++#define TX_INTEN 1
++#define DUART_INITIALIZED 2
++
++#define DUART_MAX_LINE 4
++char sb1250_duart_present[DUART_MAX_LINE];
++EXPORT_SYMBOL(sb1250_duart_present);
++
++/*
++ * Still not sure what the termios structures set up here are for,
++ * but we have to supply pointers to them to register the tty driver
++ */
++static struct tty_driver *sb1250_duart_driver; //, sb1250_duart_callout_driver;
++
++/*
++ * This lock protects both the open flags for all the uart states as
++ * well as the reference count for the module
++ */
++static DEFINE_SPINLOCK(open_lock);
++
++typedef struct {
++ unsigned char outp_buf[SERIAL_XMIT_SIZE];
++ unsigned int outp_head;
++ unsigned int outp_tail;
++ unsigned int outp_count;
++ spinlock_t outp_lock;
++ unsigned int open;
++ unsigned int line;
++ unsigned int last_cflags;
++ unsigned long flags;
++ struct tty_struct *tty;
++ /* CSR addresses */
++ volatile u32 *status;
++ volatile u32 *imr;
++ volatile u32 *tx_hold;
++ volatile u32 *rx_hold;
++ volatile u32 *mode_1;
++ volatile u32 *mode_2;
++ volatile u32 *clk_sel;
++ volatile u32 *cmd;
++} uart_state_t;
++
++static uart_state_t uart_states[DUART_MAX_LINE];
++
++/*
++ * Inline functions local to this module
++ */
++
++/*
++ * In bug 1956, we get glitches that can mess up uart registers. This
++ * "write-mode-1 after any register access" is the accepted
++ * workaround.
++ */
++#if SIBYTE_1956_WAR
++static unsigned int last_mode1[DUART_MAX_LINE];
++#endif
++
++static inline u32 READ_SERCSR(volatile u32 *addr, int line)
++{
++ u32 val = csr_in32(addr);
++#if SIBYTE_1956_WAR
++ csr_out32(last_mode1[line], uart_states[line].mode_1);
++#endif
++ return val;
++}
++
++static inline void WRITE_SERCSR(u32 val, volatile u32 *addr, int line)
++{
++ csr_out32(val, addr);
++#if SIBYTE_1956_WAR
++ csr_out32(last_mode1[line], uart_states[line].mode_1);
++#endif
++}
++
++static void init_duart_port(uart_state_t *port, int line)
++{
++ if (!(port->flags & DUART_INITIALIZED)) {
++ port->line = line;
++ port->status = IOADDR(UNIT_CHANREG(line, R_DUART_STATUS));
++ port->imr = IOADDR(UNIT_IMRREG(line));
++ port->tx_hold = IOADDR(UNIT_CHANREG(line, R_DUART_TX_HOLD));
++ port->rx_hold = IOADDR(UNIT_CHANREG(line, R_DUART_RX_HOLD));
++ port->mode_1 = IOADDR(UNIT_CHANREG(line, R_DUART_MODE_REG_1));
++ port->mode_2 = IOADDR(UNIT_CHANREG(line, R_DUART_MODE_REG_2));
++ port->clk_sel = IOADDR(UNIT_CHANREG(line, R_DUART_CLK_SEL));
++ port->cmd = IOADDR(UNIT_CHANREG(line, R_DUART_CMD));
++ port->flags |= DUART_INITIALIZED;
++ }
++}
++
++/*
++ * Mask out the passed interrupt lines at the duart level. This should be
++ * called while holding the associated outp_lock.
++ */
++static inline void duart_mask_ints(unsigned int line, unsigned int mask)
++{
++ uart_state_t *port = uart_states + line;
++ u64 tmp = READ_SERCSR(port->imr, line);
++ WRITE_SERCSR(tmp & ~mask, port->imr, line);
++}
++
++
++/* Unmask the passed interrupt lines at the duart level */
++static inline void duart_unmask_ints(unsigned int line, unsigned int mask)
++{
++ uart_state_t *port = uart_states + line;
++ u64 tmp = READ_SERCSR(port->imr, line);
++ WRITE_SERCSR(tmp | mask, port->imr, line);
++}
++
++static inline void transmit_char_pio(uart_state_t *us)
++{
++ struct tty_struct *tty = us->tty;
++ int blocked = 0;
++
++ if (spin_trylock(&us->outp_lock)) {
++ for (;;) {
++ if (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_RDY))
++ break;
++ if (us->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
++ break;
++ } else {
++ WRITE_SERCSR(us->outp_buf[us->outp_head],
++ us->tx_hold, us->line);
++ us->outp_head = (us->outp_head + 1) & (SERIAL_XMIT_SIZE-1);
++ if (--us->outp_count <= 0)
++ break;
++ }
++ udelay(10);
++ }
++ spin_unlock(&us->outp_lock);
++ } else {
++ blocked = 1;
++ }
++
++ if (!us->outp_count || tty->stopped ||
++ tty->hw_stopped || blocked) {
++ us->flags &= ~TX_INTEN;
++ duart_mask_ints(us->line, M_DUART_IMR_TX);
++ }
++
++ if (us->open &&
++ (us->outp_count < (SERIAL_XMIT_SIZE/2))) {
++ /*
++ * We told the discipline at one point that we had no
++ * space, so it went to sleep. Wake it up when we hit
++ * half empty
++ */
++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++ tty->ldisc.write_wakeup)
++ tty->ldisc.write_wakeup(tty);
++ wake_up_interruptible(&tty->write_wait);
++ }
++}
++
++/*
++ * Generic interrupt handler for both channels. dev_id is a pointer
++ * to the proper uart_states structure, so from that we can derive
++ * which port interrupted
++ */
++
++static irqreturn_t duart_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++ uart_state_t *us = (uart_state_t *)dev_id;
++ struct tty_struct *tty = us->tty;
++ unsigned int status = READ_SERCSR(us->status, us->line);
++
++ pr_debug("DUART INT\n");
++
++ if (status & M_DUART_RX_RDY) {
++ int counter = 2048;
++ unsigned int ch;
++
++ if (status & M_DUART_OVRUN_ERR)
++ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
++ if (status & M_DUART_PARITY_ERR) {
++ printk("Parity error!\n");
++ } else if (status & M_DUART_FRM_ERR) {
++ printk("Frame error!\n");
++ }
++
++ while (counter > 0) {
++ if (!(READ_SERCSR(us->status, us->line) & M_DUART_RX_RDY))
++ break;
++ ch = READ_SERCSR(us->rx_hold, us->line);
++ tty_insert_flip_char(tty, ch, 0);
++ udelay(1);
++ counter--;
++ }
++ tty_flip_buffer_push(tty);
++ }
++
++ if (status & M_DUART_TX_RDY) {
++ transmit_char_pio(us);
++ }
++
++ return IRQ_HANDLED;
++}
++
++/*
++ * Actual driver functions
++ */
++
++/* Return the number of characters we can accomodate in a write at this instant */
++static int duart_write_room(struct tty_struct *tty)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++ int retval;
++
++ retval = SERIAL_XMIT_SIZE - us->outp_count;
++
++ pr_debug("duart_write_room called, returning %i\n", retval);
++
++ return retval;
++}
++
++/* memcpy the data from src to destination, but take extra care if the
++ data is coming from user space */
++static inline int copy_buf(char *dest, const char *src, int size, int from_user)
++{
++ if (from_user) {
++ (void) copy_from_user(dest, src, size);
++ } else {
++ memcpy(dest, src, size);
++ }
++ return size;
++}
++
++/*
++ * Buffer up to count characters from buf to be written. If we don't have
++ * other characters buffered, enable the tx interrupt to start sending
++ */
++static int duart_write(struct tty_struct *tty, const unsigned char *buf,
++ int count)
++{
++ uart_state_t *us;
++ int c, t, total = 0;
++ unsigned long flags;
++
++ if (!tty) return 0;
++
++ us = tty->driver_data;
++ if (!us) return 0;
++
++ pr_debug("duart_write called for %i chars by %i (%s)\n", count, current->pid, current->comm);
++
++ spin_lock_irqsave(&us->outp_lock, flags);
++
++ for (;;) {
++ c = count;
++
++ t = SERIAL_XMIT_SIZE - us->outp_tail;
++ if (t < c) c = t;
++
++ t = SERIAL_XMIT_SIZE - 1 - us->outp_count;
++ if (t < c) c = t;
++
++ if (c <= 0) break;
++
++ memcpy(us->outp_buf + us->outp_tail, buf, c);
++
++ us->outp_count += c;
++ us->outp_tail = (us->outp_tail + c) & (SERIAL_XMIT_SIZE - 1);
++ buf += c;
++ count -= c;
++ total += c;
++ }
++
++ spin_unlock_irqrestore(&us->outp_lock, flags);
++
++ if (us->outp_count && !tty->stopped &&
++ !tty->hw_stopped && !(us->flags & TX_INTEN)) {
++ us->flags |= TX_INTEN;
++ duart_unmask_ints(us->line, M_DUART_IMR_TX);
++ }
++
++ return total;
++}
++
++
++/* Buffer one character to be written. If there's not room for it, just drop
++ it on the floor. This is used for echo, among other things */
++static void duart_put_char(struct tty_struct *tty, u_char ch)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++ unsigned long flags;
++
++ pr_debug("duart_put_char called. Char is %x (%c)\n", (int)ch, ch);
++
++ spin_lock_irqsave(&us->outp_lock, flags);
++
++ if (us->outp_count == SERIAL_XMIT_SIZE) {
++ spin_unlock_irqrestore(&us->outp_lock, flags);
++ return;
++ }
++
++ us->outp_buf[us->outp_tail] = ch;
++ us->outp_tail = (us->outp_tail + 1) &(SERIAL_XMIT_SIZE-1);
++ us->outp_count++;
++
++ spin_unlock_irqrestore(&us->outp_lock, flags);
++}
++
++static void duart_flush_chars(struct tty_struct * tty)
++{
++ uart_state_t *port;
++
++ if (!tty) return;
++
++ port = tty->driver_data;
++
++ if (!port) return;
++
++ if (port->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
++ return;
++ }
++
++ port->flags |= TX_INTEN;
++ duart_unmask_ints(port->line, M_DUART_IMR_TX);
++}
++
++/* Return the number of characters in the output buffer that have yet to be
++ written */
++static int duart_chars_in_buffer(struct tty_struct *tty)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++ int retval;
++
++ retval = us->outp_count;
++
++ pr_debug("duart_chars_in_buffer returning %i\n", retval);
++
++ return retval;
++}
++
++/* Kill everything we haven't yet shoved into the FIFO. Turn off the
++ transmit interrupt since we've nothing more to transmit */
++static void duart_flush_buffer(struct tty_struct *tty)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++ unsigned long flags;
++
++ pr_debug("duart_flush_buffer called\n");
++ spin_lock_irqsave(&us->outp_lock, flags);
++ us->outp_head = us->outp_tail = us->outp_count = 0;
++ spin_unlock_irqrestore(&us->outp_lock, flags);
++
++ wake_up_interruptible(&us->tty->write_wait);
++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++ tty->ldisc.write_wakeup)
++ tty->ldisc.write_wakeup(tty);
++}
++
++
++/* See sb1250 user manual for details on these registers */
++static inline void duart_set_cflag(unsigned int line, unsigned int cflag)
++{
++ unsigned int mode_reg1 = 0, mode_reg2 = 0;
++ unsigned int clk_divisor;
++ uart_state_t *port = uart_states + line;
++
++ switch (cflag & CSIZE) {
++ case CS7:
++ mode_reg1 |= V_DUART_BITS_PER_CHAR_7;
++
++ default:
++ /* We don't handle CS5 or CS6...is there a way we're supposed to flag this?
++ right now we just force them to CS8 */
++ mode_reg1 |= 0x0;
++ break;
++ }
++ if (cflag & CSTOPB) {
++ mode_reg2 |= M_DUART_STOP_BIT_LEN_2;
++ }
++ if (!(cflag & PARENB)) {
++ mode_reg1 |= V_DUART_PARITY_MODE_NONE;
++ }
++ if (cflag & PARODD) {
++ mode_reg1 |= M_DUART_PARITY_TYPE_ODD;
++ }
++
++ /* Formula for this is (5000000/baud)-1, but we saturate
++ at 12 bits, which means we can't actually do anything less
++ that 1200 baud */
++ switch (cflag & CBAUD) {
++ case B200:
++ case B300:
++ case B1200: clk_divisor = 4095; break;
++ case B1800: clk_divisor = 2776; break;
++ case B2400: clk_divisor = 2082; break;
++ case B4800: clk_divisor = 1040; break;
++ default:
++ case B9600: clk_divisor = 519; break;
++ case B19200: clk_divisor = 259; break;
++ case B38400: clk_divisor = 129; break;
++ case B57600: clk_divisor = 85; break;
++ case B115200: clk_divisor = 42; break;
++ }
++ WRITE_SERCSR(mode_reg1, port->mode_1, port->line);
++ WRITE_SERCSR(mode_reg2, port->mode_2, port->line);
++ WRITE_SERCSR(clk_divisor, port->clk_sel, port->line);
++ port->last_cflags = cflag;
++}
++
++
++/* Handle notification of a termios change. */
++static void duart_set_termios(struct tty_struct *tty, struct termios *old)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++ pr_debug("duart_set_termios called by %i (%s)\n", current->pid, current->comm);
++ if (old && tty->termios->c_cflag == old->c_cflag)
++ return;
++ duart_set_cflag(us->line, tty->termios->c_cflag);
++}
++
++static int get_serial_info(uart_state_t *us, struct serial_struct * retinfo) {
++
++ struct serial_struct tmp;
++
++ memset(&tmp, 0, sizeof(tmp));
++
++ tmp.type=PORT_SB1250;
++ tmp.line=us->line;
++ tmp.port=UNIT_CHANREG(tmp.line,0);
++ tmp.irq=UNIT_INT(tmp.line);
++ tmp.xmit_fifo_size=16; /* fixed by hw */
++ tmp.baud_base=5000000;
++ tmp.io_type=SERIAL_IO_MEM;
++
++ if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
++ return -EFAULT;
++
++ return 0;
++}
++
++static int duart_ioctl(struct tty_struct *tty, struct file * file,
++ unsigned int cmd, unsigned long arg)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++/* if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
++ return -ENODEV;*/
++ switch (cmd) {
++ case TIOCMGET:
++ printk("Ignoring TIOCMGET\n");
++ break;
++ case TIOCMBIS:
++ printk("Ignoring TIOCMBIS\n");
++ break;
++ case TIOCMBIC:
++ printk("Ignoring TIOCMBIC\n");
++ break;
++ case TIOCMSET:
++ printk("Ignoring TIOCMSET\n");
++ break;
++ case TIOCGSERIAL:
++ return get_serial_info(us,(struct serial_struct *) arg);
++ case TIOCSSERIAL:
++ printk("Ignoring TIOCSSERIAL\n");
++ break;
++ case TIOCSERCONFIG:
++ printk("Ignoring TIOCSERCONFIG\n");
++ break;
++ case TIOCSERGETLSR: /* Get line status register */
++ printk("Ignoring TIOCSERGETLSR\n");
++ break;
++ case TIOCSERGSTRUCT:
++ printk("Ignoring TIOCSERGSTRUCT\n");
++ break;
++ case TIOCMIWAIT:
++ printk("Ignoring TIOCMIWAIT\n");
++ break;
++ case TIOCGICOUNT:
++ printk("Ignoring TIOCGICOUNT\n");
++ break;
++ case TIOCSERGWILD:
++ printk("Ignoring TIOCSERGWILD\n");
++ break;
++ case TIOCSERSWILD:
++ printk("Ignoring TIOCSERSWILD\n");
++ break;
++ default:
++ break;
++ }
++// printk("Ignoring IOCTL %x from pid %i (%s)\n", cmd, current->pid, current->comm);
++ return -ENOIOCTLCMD;
++}
++
++/* XXXKW locking? */
++static void duart_start(struct tty_struct *tty)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++ pr_debug("duart_start called\n");
++
++ if (us->outp_count && !(us->flags & TX_INTEN)) {
++ us->flags |= TX_INTEN;
++ duart_unmask_ints(us->line, M_DUART_IMR_TX);
++ }
++}
++
++/* XXXKW locking? */
++static void duart_stop(struct tty_struct *tty)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++ pr_debug("duart_stop called\n");
++
++ if (us->outp_count && (us->flags & TX_INTEN)) {
++ us->flags &= ~TX_INTEN;
++ duart_mask_ints(us->line, M_DUART_IMR_TX);
++ }
++}
++
++/* Not sure on the semantics of this; are we supposed to wait until the stuff
++ already in the hardware FIFO drains, or are we supposed to wait until
++ we've drained the output buffer, too? I'm assuming the former, 'cause thats
++ what the other drivers seem to assume
++*/
++
++static void duart_wait_until_sent(struct tty_struct *tty, int timeout)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++ unsigned long orig_jiffies;
++
++ orig_jiffies = jiffies;
++ pr_debug("duart_wait_until_sent(%d)+\n", timeout);
++ while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT)) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(1);
++ if (signal_pending(current))
++ break;
++ if (timeout && time_after(jiffies, orig_jiffies + timeout))
++ break;
++ }
++ pr_debug("duart_wait_until_sent()-\n");
++}
++
++/*
++ * duart_hangup() --- called by tty_hangup() when a hangup is signaled.
++ */
++static void duart_hangup(struct tty_struct *tty)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++
++ duart_flush_buffer(tty);
++ us->open = 0;
++ us->tty = 0;
++}
++
++/*
++ * Open a tty line. Note that this can be called multiple times, so ->open can
++ * be >1. Only set up the tty struct if this is a "new" open, e.g. ->open was
++ * zero
++ */
++static int duart_open(struct tty_struct *tty, struct file *filp)
++{
++ uart_state_t *us;
++ unsigned int line = tty->index;
++ unsigned long flags;
++
++ if ((line >= tty->driver->num) || !sb1250_duart_present[line])
++ return -ENODEV;
++
++ pr_debug("duart_open called by %i (%s), tty is %p, rw is %p, ww is %p\n",
++ current->pid, current->comm, tty, tty->read_wait,
++ tty->write_wait);
++
++ us = uart_states + line;
++ tty->driver_data = us;
++
++ spin_lock_irqsave(&open_lock, flags);
++ if (!us->open) {
++ us->tty = tty;
++ us->tty->termios->c_cflag = us->last_cflags;
++ }
++ us->open++;
++ us->flags &= ~TX_INTEN;
++ duart_unmask_ints(line, M_DUART_IMR_RX);
++ spin_unlock_irqrestore(&open_lock, flags);
++
++ return 0;
++}
++
++
++/*
++ * Close a reference count out. If reference count hits zero, null the
++ * tty, kill the interrupts. The tty_io driver is responsible for making
++ * sure we've cleared out our internal buffers before calling close()
++ */
++static void duart_close(struct tty_struct *tty, struct file *filp)
++{
++ uart_state_t *us = (uart_state_t *) tty->driver_data;
++ unsigned long flags;
++
++ pr_debug("duart_close called by %i (%s)\n", current->pid, current->comm);
++
++ if (!us || !us->open)
++ return;
++
++ spin_lock_irqsave(&open_lock, flags);
++ if (tty_hung_up_p(filp)) {
++ spin_unlock_irqrestore(&open_lock, flags);
++ return;
++ }
++
++ if (--us->open < 0) {
++ us->open = 0;
++ printk(KERN_ERR "duart: bad open count: %d\n", us->open);
++ }
++ if (us->open) {
++ spin_unlock_irqrestore(&open_lock, flags);
++ return;
++ }
++
++ spin_unlock_irqrestore(&open_lock, flags);
++
++ tty->closing = 1;
++
++ /* Stop accepting input */
++ duart_mask_ints(us->line, M_DUART_IMR_RX);
++ /* Wait for FIFO to drain */
++ while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT))
++ ;
++
++ if (tty->driver->flush_buffer)
++ tty->driver->flush_buffer(tty);
++ if (tty->ldisc.flush_buffer)
++ tty->ldisc.flush_buffer(tty);
++ tty->closing = 0;
++}
++
++
++static struct tty_operations duart_ops = {
++ .open = duart_open,
++ .close = duart_close,
++ .write = duart_write,
++ .put_char = duart_put_char,
++ .flush_chars = duart_flush_chars,
++ .write_room = duart_write_room,
++ .chars_in_buffer = duart_chars_in_buffer,
++ .flush_buffer = duart_flush_buffer,
++ .ioctl = duart_ioctl,
++// .throttle = duart_throttle,
++// .unthrottle = duart_unthrottle,
++ .set_termios = duart_set_termios,
++ .stop = duart_stop,
++ .start = duart_start,
++ .hangup = duart_hangup,
++ .wait_until_sent = duart_wait_until_sent,
++};
++
++/* Initialize the sb1250_duart_present array based on SOC type. */
++static void __init sb1250_duart_init_present_lines(void)
++{
++ int i, max_lines;
++
++ /* Set the number of available units based on the SOC type. */
++ switch (soc_type) {
++ case K_SYS_SOC_TYPE_BCM1x55:
++ case K_SYS_SOC_TYPE_BCM1x80:
++ max_lines = 4;
++ break;
++ default:
++ /* Assume at least two serial ports at the normal address. */
++ max_lines = 2;
++ break;
++ }
++ if (max_lines > DUART_MAX_LINE)
++ max_lines = DUART_MAX_LINE;
++
++ for (i = 0; i < max_lines; i++)
++ sb1250_duart_present[i] = 1;
++}
++
++/* Set up the driver and register it, register the UART interrupts. This
++ is called from tty_init, or as a part of the module init */
++static int __init sb1250_duart_init(void)
++{
++ int i;
++
++ sb1250_duart_init_present_lines();
++
++ sb1250_duart_driver = alloc_tty_driver(DUART_MAX_LINE);
++ if (!sb1250_duart_driver)
++ return -ENOMEM;
++
++ sb1250_duart_driver->owner = THIS_MODULE;
++ sb1250_duart_driver->name = "duart";
++ sb1250_duart_driver->devfs_name = "duart/";
++ sb1250_duart_driver->major = TTY_MAJOR;
++ sb1250_duart_driver->minor_start = SB1250_DUART_MINOR_BASE;
++ sb1250_duart_driver->type = TTY_DRIVER_TYPE_SERIAL;
++ sb1250_duart_driver->subtype = SERIAL_TYPE_NORMAL;
++ sb1250_duart_driver->init_termios = tty_std_termios;
++ sb1250_duart_driver->flags = TTY_DRIVER_REAL_RAW;
++ tty_set_operations(sb1250_duart_driver, &duart_ops);
++
++ for (i=0; i<DUART_MAX_LINE; i++) {
++ uart_state_t *port = uart_states + i;
++
++ if (!sb1250_duart_present[i])
++ continue;
++
++ init_duart_port(port, i);
++ spin_lock_init(&port->outp_lock);
++ duart_mask_ints(i, M_DUART_IMR_ALL);
++ if (request_irq(UNIT_INT(i), duart_int, 0, "uart", port)) {
++ panic("Couldn't get uart0 interrupt line");
++ }
++ __raw_writeq(M_DUART_RX_EN|M_DUART_TX_EN,
++ IOADDR(UNIT_CHANREG(i, R_DUART_CMD)));
++ duart_set_cflag(i, DEFAULT_CFLAGS);
++ }
++
++ /* Interrupts are now active, our ISR can be called. */
++
++ if (tty_register_driver(sb1250_duart_driver)) {
++ printk(KERN_ERR "Couldn't register sb1250 duart serial driver\n");
++ put_tty_driver(sb1250_duart_driver);
++ return 1;
++ }
++ return 0;
++}
++
++/* Unload the driver. Unregister stuff, get ready to go away */
++static void __exit sb1250_duart_fini(void)
++{
++ unsigned long flags;
++ int i;
++
++ local_irq_save(flags);
++ tty_unregister_driver(sb1250_duart_driver);
++ put_tty_driver(sb1250_duart_driver);
++
++ for (i=0; i<DUART_MAX_LINE; i++) {
++ if (!sb1250_duart_present[i])
++ continue;
++ free_irq(UNIT_INT(i), &uart_states[i]);
++ disable_irq(UNIT_INT(i));
++ }
++ local_irq_restore(flags);
++}
++
++module_init(sb1250_duart_init);
++module_exit(sb1250_duart_fini);
++MODULE_DESCRIPTION("SB1250 Duart serial driver");
++MODULE_AUTHOR("Broadcom Corp.");
++
++#ifdef CONFIG_SIBYTE_SB1250_DUART_CONSOLE
++
++/*
++ * Serial console stuff. Very basic, polling driver for doing serial
++ * console output. The console_sem is held by the caller, so we
++ * shouldn't be interrupted for more console activity.
++ * XXXKW What about getting interrupted by uart driver activity?
++ */
++
++void serial_outc(unsigned char c, int line)
++{
++ uart_state_t *port = uart_states + line;
++ while (!(READ_SERCSR(port->status, line) & M_DUART_TX_RDY)) ;
++ WRITE_SERCSR(c, port->tx_hold, line);
++ while (!(READ_SERCSR(port->status, port->line) & M_DUART_TX_EMT)) ;
++}
++
++static void ser_console_write(struct console *cons, const char *s,
++ unsigned int count)
++{
++ int line = cons->index;
++ uart_state_t *port = uart_states + line;
++ u32 imr;
++
++ imr = READ_SERCSR(port->imr, line);
++ WRITE_SERCSR(0, port->imr, line);
++ while (count--) {
++ if (*s == '\n')
++ serial_outc('\r', line);
++ serial_outc(*s++, line);
++ }
++ WRITE_SERCSR(imr, port->imr, line);
++}
++
++static struct tty_driver *ser_console_device(struct console *c, int *index)
++{
++ *index = c->index;
++ return sb1250_duart_driver;
++}
++
++static int ser_console_setup(struct console *cons, char *str)
++{
++ int i;
++
++ sb1250_duart_init_present_lines();
++
++ for (i=0; i<DUART_MAX_LINE; i++) {
++ uart_state_t *port = uart_states + i;
++
++ if (!sb1250_duart_present[i])
++ continue;
++
++ init_duart_port(port, i);
++#if SIBYTE_1956_WAR
++ last_mode1[i] = V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8;
++#endif
++ WRITE_SERCSR(V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8,
++ port->mode_1, i);
++ WRITE_SERCSR(M_DUART_STOP_BIT_LEN_1,
++ port->mode_2, i);
++ WRITE_SERCSR(V_DUART_BAUD_RATE(115200),
++ port->clk_sel, i);
++ WRITE_SERCSR(M_DUART_RX_EN|M_DUART_TX_EN,
++ port->cmd, i);
++ }
++ return 0;
++}
++
++static struct console sb1250_ser_cons = {
++ .name = "duart",
++ .write = ser_console_write,
++ .device = ser_console_device,
++ .setup = ser_console_setup,
++ .flags = CON_PRINTBUFFER,
++ .index = -1,
++};
++
++static int __init sb1250_serial_console_init(void)
++{
++ register_console(&sb1250_ser_cons);
++ return 0;
++}
++
++console_initcall(sb1250_serial_console_init);
++
++#endif /* CONFIG_SIBYTE_SB1250_DUART_CONSOLE */
+diff -Nur linux-2.6.17/include/linux/serial.h linux-2.6.17-owrt/include/linux/serial.h
+--- linux-2.6.17/include/linux/serial.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/linux/serial.h 2006-06-18 12:41:36.000000000 +0200
+@@ -76,7 +76,8 @@
+ #define PORT_16654 11
+ #define PORT_16850 12
+ #define PORT_RSA 13 /* RSA-DV II/S card */
+-#define PORT_MAX 13
++#define PORT_SB1250 14
++#define PORT_MAX 14
+
+ #define SERIAL_IO_PORT 0
+ #define SERIAL_IO_HUB6 1
diff --git a/target/linux/sibyte-2.6/patches/001-bcm112x_ax.patch b/target/linux/sibyte-2.6/patches/001-bcm112x_ax.patch
new file mode 100644
index 0000000..c80d4ae
--- /dev/null
+++ b/target/linux/sibyte-2.6/patches/001-bcm112x_ax.patch
@@ -0,0 +1,17 @@
+--- linux-2.6.16.4/arch/mips/sibyte/sb1250/setup.c 2006-04-21 16:16:18.000000000 -0700
++++ linux-2.6.16.4/arch/mips/sibyte/sb1250/setup.c 2006-04-21 16:15:22.000000000 -0700
+@@ -140,6 +140,14 @@
+ periph_rev = 3;
+ pass_str = "A2";
+ break;
++ case K_SYS_REVISION_BCM112x_A3:
++ periph_rev = 3;
++ pass_str = "A3";
++ break;
++ case K_SYS_REVISION_BCM112x_A4:
++ periph_rev = 3;
++ pass_str = "A4";
++ break;
+ default:
+ prom_printf("Unknown %s rev %x\n", soc_str, soc_pass);
+ ret = 1;
diff --git a/target/linux/uml-2.6/Makefile b/target/linux/uml-2.6/Makefile
new file mode 100644
index 0000000..59f02b3
--- /dev/null
+++ b/target/linux/uml-2.6/Makefile
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+LINUX_VERSION:=2.6.17
+LINUX_RELEASE:=1
+LINUX_KERNEL_MD5SUM:=37ddefe96625502161f075b9d907f21e
+
+include ./config
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/kernel-build.mk
+
+$(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked
+ [ -d ../generic-$(KERNEL)/patches ] && $(PATCH) $(LINUX_DIR) ../generic-$(KERNEL)/patches
+ [ -d ./patches ] && $(PATCH) $(LINUX_DIR) ./patches
+ @$(CP) config $(LINUX_DIR)/.config
+ touch $@
diff --git a/target/linux/uml-2.6/README b/target/linux/uml-2.6/README
new file mode 100644
index 0000000..84bf114
--- /dev/null
+++ b/target/linux/uml-2.6/README
@@ -0,0 +1,45 @@
+Openwrt inside a user mode linux. Why would we even want this many ask?
+
+There are potentially a lot of reasons, one obvious one to me, it allows
+folks to 'kick the tires' without actually flashing up any hardware. It's
+also a great environment for porting over packages, you can get a package
+fully functional in the uclibc root environment inside a uml without actually
+disturbing your 'real router', and then rebuild for a specific target once
+it's fully tested.
+
+This is a first stab at a build that 'just works' and there will be more
+cleanup to come. The simple directions are:-
+
+Configure for uml target
+Configure with an ext2 root file system
+build it all
+
+In your bin directory you will find a kernel and an ext2 root file system
+when it's finished. Just run it like this:-
+
+bin/openwrt-uml-2.6-vmlinux ubd0=bin/openwrt-uml-2.6-ext2.img con=null ssl=null ssl0=fd:0,fd:1 con0=null,fd:1
+
+The uml will start, and eventually the serial console of the uml will be at your
+console prompt. If you would like it in xterms, substitute con=xterm and con0=xterm.
+No networking is configured, but, it's a starting point. The resulting file system
+has just enough free space to start kicking the tires and playing in the world of
+'embedded routers' along with all the resource restrictions that come with that
+world.
+
+To configure networking and more, refer to the user mode linux documentation online.
+A quick start goes along this line. install the uml-utilities packages so you have
+the uml switch in and running, then add a command param to your uml start like this
+
+eth0=daemon,00:01:01:01:01:01,unix,/<your uml switch control socket here>
+
+With that in, and uml networking actually functional (can be a challenge at times),
+you should be able to ifconfig the interface and talk to the host side, or, if you
+bridged the uml switch to your host network, you should be able to run udhcp and be
+away with networking off to the world. Again, if you are unfamiliar with uml and
+uml networking, please read the docs and how-to stuff available on the net. It does
+take some fiddling to get it started and working right the first time, but after that,
+it opens up a whole new world of virtual machines.
+
+
+
+http://user-mode-linux.sourceforge.net/
diff --git a/target/linux/uml-2.6/config b/target/linux/uml-2.6/config
new file mode 100644
index 0000000..0866558
--- /dev/null
+++ b/target/linux/uml-2.6/config
@@ -0,0 +1,904 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17
+# Tue Aug 22 17:19:49 2006
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_UML=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_IRQ_RELEASE_METHOD=y
+
+#
+# UML-specific options
+#
+# CONFIG_MODE_TT is not set
+# CONFIG_STATIC_LINK is not set
+CONFIG_MODE_SKAS=y
+
+#
+# Host processor type and features
+#
+# CONFIG_M386 is not set
+CONFIG_M486=y
+# CONFIG_M586 is not set
+# CONFIG_M586TSC is not set
+# CONFIG_M586MMX is not set
+# CONFIG_M686 is not set
+# CONFIG_MPENTIUMII is not set
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUMM is not set
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
+# CONFIG_MK8 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MEFFICEON is not set
+# CONFIG_MWINCHIPC6 is not set
+# CONFIG_MWINCHIP2 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_MGEODEGX1 is not set
+# CONFIG_MGEODE_LX is not set
+# CONFIG_MCYRIXIII is not set
+# CONFIG_MVIAC3_2 is not set
+CONFIG_X86_GENERIC=y
+CONFIG_X86_CMPXCHG=y
+CONFIG_X86_XADD=y
+CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_X86_PPRO_FENCE=y
+CONFIG_X86_F00F_BUG=y
+CONFIG_X86_WP_WORKS_OK=y
+CONFIG_X86_INVLPG=y
+CONFIG_X86_BSWAP=y
+CONFIG_X86_POPAD_OK=y
+CONFIG_X86_ALIGNMENT_16=y
+CONFIG_X86_INTEL_USERCOPY=y
+CONFIG_UML_X86=y
+# CONFIG_64BIT is not set
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_HOST_2G_2G=y
+CONFIG_TOP_ADDR=0x80000000
+# CONFIG_3_LEVEL_PGTABLES is not set
+CONFIG_STUB_CODE=0x7fffe000
+CONFIG_STUB_DATA=0x7ffff000
+CONFIG_STUB_START=0x7fffe000
+CONFIG_ARCH_HAS_SC_SIGNALS=y
+CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_LD_SCRIPT_DYN=y
+CONFIG_NET=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_HOSTFS=y
+# CONFIG_HPPFS is not set
+CONFIG_MCONSOLE=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_NEST_LEVEL=0
+# CONFIG_HIGHMEM is not set
+CONFIG_KERNEL_STACK_ORDER=2
+CONFIG_UML_REAL_TIME_CLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_RELAY=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_UBD=y
+CONFIG_BLK_DEV_UBD_SYNC=y
+CONFIG_BLK_DEV_COW_COMMON=y
+# CONFIG_MMAPPER is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=y
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Character Devices
+#
+CONFIG_STDERR_CONSOLE=y
+CONFIG_STDIO_CONSOLE=y
+CONFIG_SSL=y
+CONFIG_NULL_CHAN=y
+CONFIG_PORT_CHAN=y
+CONFIG_PTY_CHAN=y
+CONFIG_TTY_CHAN=y
+CONFIG_XTERM_CHAN=y
+# CONFIG_NOCONFIG_CHAN is not set
+CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
+CONFIG_CON_CHAN="xterm"
+CONFIG_SSL_CHAN="pty"
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_UML_WATCHDOG=m
+CONFIG_UML_SOUND=m
+CONFIG_SOUND=m
+CONFIG_HOSTAUDIO=m
+CONFIG_UML_RANDOM=y
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Networking
+#
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_IP_ROUTE_FWMARK is not set
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_MULTIPATH_CACHED=y
+CONFIG_IP_ROUTE_MULTIPATH_RR=y
+CONFIG_IP_ROUTE_MULTIPATH_RANDOM=y
+CONFIG_IP_ROUTE_MULTIPATH_WRANDOM=y
+CONFIG_IP_ROUTE_MULTIPATH_DRR=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IPSEC_NAT_TRAVERSAL=y
+# CONFIG_IP_MROUTE is not set
+CONFIG_ARPD=y
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+CONFIG_IPV6_ROUTER_PREF=y
+# CONFIG_IPV6_ROUTE_INFO is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+CONFIG_IP_NF_SIP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_IPP2P=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_TIME=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_IMQ=y
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_ROUTE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_NF_SET=m
+CONFIG_IP_NF_SET_MAX=256
+CONFIG_IP_NF_SET_HASHSIZE=1024
+CONFIG_IP_NF_SET_IPMAP=m
+CONFIG_IP_NF_SET_MACIPMAP=m
+CONFIG_IP_NF_SET_PORTMAP=m
+CONFIG_IP_NF_SET_IPHASH=m
+CONFIG_IP_NF_SET_NETHASH=m
+CONFIG_IP_NF_SET_IPTREE=m
+CONFIG_IP_NF_MATCH_SET=m
+CONFIG_IP_NF_TARGET_SET=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_IMQ=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+# CONFIG_NET_SCH_CLK_JIFFIES is not set
+CONFIG_NET_SCH_CLK_GETTIMEOFDAY=y
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_ESFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=m
+CONFIG_IEEE80211_DEBUG=y
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_SOFTMAC=m
+# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# UML Network Devices
+#
+CONFIG_UML_NET=y
+CONFIG_UML_NET_ETHERTAP=y
+CONFIG_UML_NET_TUNTAP=y
+CONFIG_UML_NET_SLIP=y
+CONFIG_UML_NET_DAEMON=y
+CONFIG_UML_NET_MCAST=y
+# CONFIG_UML_NET_PCAP is not set
+CONFIG_UML_NET_SLIRP=y
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_IFB is not set
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_IMQ=m
+# CONFIG_IMQ_BEHAVIOR_AA is not set
+# CONFIG_IMQ_BEHAVIOR_AB is not set
+CONFIG_IMQ_BEHAVIOR_BA=y
+# CONFIG_IMQ_BEHAVIOR_BB is not set
+CONFIG_IMQ_NUM_DEVS=2
+CONFIG_TUN=m
+
+#
+# PHY device support
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+CONFIG_WAN=y
+# CONFIG_SYNCLINK_SYNCPPP is not set
+# CONFIG_HDLC is not set
+# CONFIG_DLCI is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+# CONFIG_SLIP_COMPRESSED is not set
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=y
+# CONFIG_REISERFS_CHECK is not set
+CONFIG_REISERFS_PROC_INFO=y
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_EXPORT=y
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+CONFIG_HFSPLUS_FS=m
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_EMBEDDED=y
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_SQUASHFS_VMALLOC is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+CONFIG_9P_FS=m
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_AES_586 is not set
+# CONFIG_CRYPTO_AES_X86_64 is not set
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=m
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID5=m
+# CONFIG_MD_RAID5_RESHAPE is not set
+CONFIG_MD_RAID6=m
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
+# CONFIG_INPUT is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+CONFIG_DEBUG_SLAB=y
+# CONFIG_DEBUG_SLAB_LEAK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_UNWIND_INFO=y
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_GPROF is not set
+# CONFIG_GCOV is not set
+# CONFIG_SYSCALL_DEBUG is not set
diff --git a/target/linux/x86-2.6/Makefile b/target/linux/x86-2.6/Makefile
new file mode 100644
index 0000000..59f02b3
--- /dev/null
+++ b/target/linux/x86-2.6/Makefile
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+LINUX_VERSION:=2.6.17
+LINUX_RELEASE:=1
+LINUX_KERNEL_MD5SUM:=37ddefe96625502161f075b9d907f21e
+
+include ./config
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/kernel-build.mk
+
+$(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked
+ [ -d ../generic-$(KERNEL)/patches ] && $(PATCH) $(LINUX_DIR) ../generic-$(KERNEL)/patches
+ [ -d ./patches ] && $(PATCH) $(LINUX_DIR) ./patches
+ @$(CP) config $(LINUX_DIR)/.config
+ touch $@
diff --git a/target/linux/x86-2.6/config b/target/linux/x86-2.6/config
new file mode 100644
index 0000000..d43bd80
--- /dev/null
+++ b/target/linux/x86-2.6/config
@@ -0,0 +1,2077 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17
+# Mon Oct 9 15:42:06 2006
+#
+CONFIG_X86_32=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_X86=y
+CONFIG_MMU=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_DMI=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE="../../root"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_UID16=y
+# CONFIG_VM86 is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+
+#
+# Processor type and features
+#
+CONFIG_SCx200HR_TIMER=y
+# CONFIG_SMP is not set
+CONFIG_X86_PC=y
+# CONFIG_X86_ELAN is not set
+# CONFIG_X86_VOYAGER is not set
+# CONFIG_X86_NUMAQ is not set
+# CONFIG_X86_SUMMIT is not set
+# CONFIG_X86_BIGSMP is not set
+# CONFIG_X86_VISWS is not set
+# CONFIG_X86_GENERICARCH is not set
+# CONFIG_X86_ES7000 is not set
+# CONFIG_M386 is not set
+CONFIG_M486=y
+# CONFIG_M586 is not set
+# CONFIG_M586TSC is not set
+# CONFIG_M586MMX is not set
+# CONFIG_M686 is not set
+# CONFIG_MPENTIUMII is not set
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUMM is not set
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
+# CONFIG_MK8 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MEFFICEON is not set
+# CONFIG_MWINCHIPC6 is not set
+# CONFIG_MWINCHIP2 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_MGEODEGX1 is not set
+# CONFIG_MGEODE_LX is not set
+# CONFIG_MCYRIXIII is not set
+# CONFIG_MVIAC3_2 is not set
+# CONFIG_X86_GENERIC is not set
+CONFIG_X86_CMPXCHG=y
+CONFIG_X86_XADD=y
+CONFIG_X86_L1_CACHE_SHIFT=4
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_X86_PPRO_FENCE=y
+CONFIG_X86_F00F_BUG=y
+CONFIG_X86_WP_WORKS_OK=y
+CONFIG_X86_INVLPG=y
+CONFIG_X86_BSWAP=y
+CONFIG_X86_POPAD_OK=y
+CONFIG_X86_ALIGNMENT_16=y
+# CONFIG_HPET_TIMER is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_X86_UP_APIC is not set
+# CONFIG_X86_MCE is not set
+# CONFIG_TOSHIBA is not set
+# CONFIG_I8K is not set
+# CONFIG_X86_REBOOTFIXUPS is not set
+# CONFIG_MICROCODE is not set
+# CONFIG_X86_MSR is not set
+# CONFIG_X86_CPUID is not set
+
+#
+# Firmware Drivers
+#
+# CONFIG_EDD is not set
+# CONFIG_DELL_RBU is not set
+# CONFIG_DCDBAS is not set
+CONFIG_NOHIGHMEM=y
+# CONFIG_HIGHMEM4G is not set
+# CONFIG_HIGHMEM64G is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_3G_OPT is not set
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_MTRR is not set
+# CONFIG_REGPARM is not set
+# CONFIG_SECCOMP is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+# CONFIG_KEXEC is not set
+CONFIG_PHYSICAL_START=0x100000
+
+#
+# Power management options (ACPI, APM)
+#
+# CONFIG_PM is not set
+
+#
+# ACPI (Advanced Configuration and Power Interface) Support
+#
+# CONFIG_ACPI is not set
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+
+#
+# CPUFreq processor drivers
+#
+# CONFIG_X86_POWERNOW_K6 is not set
+# CONFIG_X86_POWERNOW_K7 is not set
+# CONFIG_X86_POWERNOW_K8 is not set
+CONFIG_X86_GX_SUSPMOD=m
+# CONFIG_X86_SPEEDSTEP_CENTRINO is not set
+# CONFIG_X86_SPEEDSTEP_ICH is not set
+# CONFIG_X86_SPEEDSTEP_SMI is not set
+# CONFIG_X86_P4_CLOCKMOD is not set
+# CONFIG_X86_CPUFREQ_NFORCE2 is not set
+# CONFIG_X86_LONGRUN is not set
+
+#
+# shared options
+#
+# CONFIG_X86_SPEEDSTEP_LIB is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+CONFIG_PCI=y
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GOMMCONFIG is not set
+# CONFIG_PCI_GODIRECT is not set
+CONFIG_PCI_GOANY=y
+CONFIG_PCI_BIOS=y
+CONFIG_PCI_DIRECT=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_ISA_DMA_API=y
+CONFIG_ISA=y
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+CONFIG_SCx200=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=m
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=m
+# CONFIG_PCMCIA_LOAD_CIS is not set
+# CONFIG_PCMCIA_IOCTL is not set
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+CONFIG_YENTA=m
+# CONFIG_YENTA_O2 is not set
+# CONFIG_YENTA_RICOH is not set
+# CONFIG_YENTA_TI is not set
+# CONFIG_YENTA_TOSHIBA is not set
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_PROBE=y
+CONFIG_PCCARD_NONSTATIC=m
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+CONFIG_IPSEC_NAT_TRAVERSAL=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=y
+CONFIG_TCP_CONG_SCALABLE=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+CONFIG_IPV6_ROUTER_PREF=y
+# CONFIG_IPV6_ROUTE_INFO is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+# CONFIG_BRIDGE_NETFILTER is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=y
+CONFIG_IP_NF_IRC=y
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+CONFIG_IP_NF_SIP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_IPP2P=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_TIME=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_IMQ=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_ROUTE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=y
+CONFIG_IP_NF_NAT_FTP=y
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_TTL=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_IP_NF_SET=m
+CONFIG_IP_NF_SET_MAX=256
+CONFIG_IP_NF_SET_HASHSIZE=1024
+CONFIG_IP_NF_SET_IPMAP=m
+CONFIG_IP_NF_SET_MACIPMAP=m
+CONFIG_IP_NF_SET_PORTMAP=m
+CONFIG_IP_NF_SET_IPHASH=m
+CONFIG_IP_NF_SET_NETHASH=m
+CONFIG_IP_NF_SET_IPTREE=m
+CONFIG_IP_NF_MATCH_SET=m
+CONFIG_IP_NF_TARGET_SET=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_IMQ=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_CLIP_NO_ICMP=y
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_ATM_BR2684_IPFILTER=y
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_ESFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CLS_U32_MARK is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_HAMRADIO=y
+
+#
+# Packet Radio protocols
+#
+CONFIG_AX25=m
+# CONFIG_AX25_DAMA_SLAVE is not set
+# CONFIG_NETROM is not set
+# CONFIG_ROSE is not set
+
+#
+# AX.25 network device drivers
+#
+CONFIG_MKISS=m
+# CONFIG_6PACK is not set
+# CONFIG_BPQETHER is not set
+# CONFIG_DMASCC is not set
+# CONFIG_SCC is not set
+# CONFIG_BAYCOM_SER_FDX is not set
+# CONFIG_BAYCOM_SER_HDX is not set
+# CONFIG_YAM is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBTUART is not set
+# CONFIG_BT_HCIVHCI is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+# CONFIG_IEEE80211_SOFTMAC is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=m
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=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
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE 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_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_TS5500 is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLOCK2MTD=y
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG is not set
+
+#
+# Protocols
+#
+CONFIG_ISAPNP=y
+# CONFIG_PNPBIOS is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# 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_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_IDEPNP is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_ATIIXP is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_CS5535 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+CONFIG_BLK_DEV_SC1200=y
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC 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
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_IMQ=m
+# CONFIG_IMQ_BEHAVIOR_AA is not set
+# CONFIG_IMQ_BEHAVIOR_AB is not set
+CONFIG_IMQ_BEHAVIOR_BA=y
+# CONFIG_IMQ_BEHAVIOR_BB is not set
+CONFIG_IMQ_NUM_DEVS=2
+CONFIG_TUN=m
+# CONFIG_NET_SB1000 is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=m
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_CICADA_PHY=m
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+# CONFIG_EL3 is not set
+# CONFIG_3C515 is not set
+CONFIG_VORTEX=m
+# CONFIG_TYPHOON is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_B44 is not set
+CONFIG_FORCEDETH=m
+# CONFIG_CS89x0 is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=m
+# CONFIG_FEALNX is not set
+CONFIG_NATSEMI=m
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+CONFIG_8139TOO=m
+CONFIG_8139TOO_PIO=y
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+CONFIG_SIS900=m
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+CONFIG_VIA_RHINE=m
+# CONFIG_VIA_RHINE_MMIO is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+CONFIG_SIS190=m
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 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)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+CONFIG_NET_WIRELESS_RTNETLINK=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_ARLAN is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_PCMCIA_WAVELAN is not set
+# CONFIG_PCMCIA_NETWAVE is not set
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_IPW2100=m
+CONFIG_IPW2100_MONITOR=y
+# CONFIG_IPW2100_DEBUG is not set
+CONFIG_IPW2200=m
+CONFIG_IPW2200_MONITOR=y
+CONFIG_IPW_QOS=y
+# CONFIG_IPW2200_DEBUG is not set
+CONFIG_AIRO=m
+CONFIG_HERMES=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+# CONFIG_NORTEL_HERMES is not set
+CONFIG_PCI_HERMES=m
+CONFIG_ATMEL=m
+CONFIG_PCI_ATMEL=m
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_PCMCIA_SPECTRUM is not set
+CONFIG_AIRO_CS=m
+CONFIG_PCMCIA_ATMEL=m
+# CONFIG_PCMCIA_WL3501 is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_PRISM54=m
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+CONFIG_HOSTAP_PLX=m
+CONFIG_HOSTAP_PCI=m
+CONFIG_HOSTAP_CS=m
+CONFIG_NET_WIRELESS=y
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# ATM drivers
+#
+CONFIG_ATM_DUMMY=m
+CONFIG_ATM_TCP=m
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+# CONFIG_ATM_FORE200E_MAYBE is not set
+# CONFIG_ATM_HE is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=m
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=m
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+# CONFIG_SERIAL_8250_PNP is not set
+CONFIG_SERIAL_8250_CS=m
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=m
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_IBMASR is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I6300ESB_WDT is not set
+# CONFIG_I8XX_TCO is not set
+CONFIG_SC1200_WDT=m
+CONFIG_SCx200_WDT=m
+# CONFIG_60XX_WDT is not set
+# CONFIG_SBC8360_WDT is not set
+# CONFIG_CPU5_WDT is not set
+# CONFIG_W83627HF_WDT is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_W83977F_WDT is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_SBC_EPX_C3_WATCHDOG is not set
+
+#
+# ISA-based Watchdog Cards
+#
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_WDT is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_NVRAM=y
+CONFIG_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_SONYPI is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_MWAVE is not set
+CONFIG_SCx200_GPIO=m
+# CONFIG_CS5535_GPIO is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ELEKTOR is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+CONFIG_SCx200_I2C=m
+CONFIG_SCx200_I2C_SCL=12
+CONFIG_SCx200_I2C_SDA=13
+CONFIG_SCx200_ACB=m
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+# CONFIG_IBM_ASM is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+# CONFIG_VIDEO_V4L1 is not set
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=y
+
+#
+# Video Capture Adapters
+#
+
+#
+# Video Capture Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_SAA7134 is not set
+# CONFIG_VIDEO_CX88 is not set
+
+#
+# Encoders and Decoders
+#
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_CX25840 is not set
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+
+#
+# V4L USB devices
+#
+
+#
+# Radio Adapters
+#
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_RTCTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ISA devices
+#
+# CONFIG_SND_ADLIB is not set
+# CONFIG_SND_AD1816A is not set
+# CONFIG_SND_AD1848 is not set
+# CONFIG_SND_ALS100 is not set
+# CONFIG_SND_AZT2320 is not set
+# CONFIG_SND_CMI8330 is not set
+# CONFIG_SND_CS4231 is not set
+# CONFIG_SND_CS4232 is not set
+# CONFIG_SND_CS4236 is not set
+# CONFIG_SND_DT019X is not set
+# CONFIG_SND_ES968 is not set
+# CONFIG_SND_ES1688 is not set
+# CONFIG_SND_ES18XX is not set
+# CONFIG_SND_GUSCLASSIC is not set
+# CONFIG_SND_GUSEXTREME is not set
+# CONFIG_SND_GUSMAX is not set
+# CONFIG_SND_INTERWAVE is not set
+# CONFIG_SND_INTERWAVE_STB is not set
+# CONFIG_SND_OPL3SA2 is not set
+# CONFIG_SND_OPTI92X_AD1848 is not set
+# CONFIG_SND_OPTI92X_CS4231 is not set
+# CONFIG_SND_OPTI93X is not set
+# CONFIG_SND_MIRO is not set
+# CONFIG_SND_SB8 is not set
+# CONFIG_SND_SB16 is not set
+# CONFIG_SND_SBAWE is not set
+# CONFIG_SND_SGALAXY is not set
+# CONFIG_SND_SSCAPE is not set
+# CONFIG_SND_WAVEFRONT is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5535AUDIO is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+
+#
+# USB devices
+#
+CONFIG_SND_USB_AUDIO=m
+# CONFIG_SND_USB_USX2Y is not set
+
+#
+# PCMCIA devices
+#
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_PDAUDIOCF is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_LIBUSUAL 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_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+# CONFIG_USB_SERIAL_ANYDATA is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+CONFIG_USB_SERIAL_BELKIN=m
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+CONFIG_USB_SERIAL_FTDI_SIO=m
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+CONFIG_USB_SERIAL_VISOR=m
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+CONFIG_USB_SERIAL_MCT_U232=m
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=m
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET 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_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+CONFIG_USB_ATM=m
+CONFIG_USB_SPEEDTOUCH=m
+# CONFIG_USB_CXACRU is not set
+CONFIG_USB_UEAGLEATM=m
+# CONFIG_USB_XUSBATM is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+# CONFIG_LEDS_TRIGGER_IDE_DISK is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+# CONFIG_EDAC is not set
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=m
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_SQUASHFS_VMALLOC is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=m
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+# CONFIG_KPROBES is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_UNWIND_INFO is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_STACK_BACKTRACE_COLS=2
+CONFIG_DOUBLEFAULT=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_AES_586=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+# CONFIG_CRYPTO_DEV_PADLOCK is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_X86_BIOS_REBOOT=y
+CONFIG_KTIME_SCALAR=y
diff --git a/target/linux/x86-2.6/patches/100-scx200_hr_timer.patch b/target/linux/x86-2.6/patches/100-scx200_hr_timer.patch
new file mode 100644
index 0000000..38fc16a
--- /dev/null
+++ b/target/linux/x86-2.6/patches/100-scx200_hr_timer.patch
@@ -0,0 +1,320 @@
+SCx200 High Resolution Timer Patch for Linux 2.6
+http://www.gnusto.com/scx200-hr-timer.html
+
+diff -Naurp linux-2.6.12-rc6.orig/arch/i386/Kconfig linux-2.6.12-rc6/arch/i386/Kconfig
+--- linux-2.6.12-rc6.orig/arch/i386/Kconfig 2005-06-07 14:56:02.000000000 +0100
++++ linux-2.6.12-rc6/arch/i386/Kconfig 2005-06-07 16:43:19.000000000 +0100
+@@ -458,6 +458,17 @@ config HPET_EMULATE_RTC
+ bool "Provide RTC interrupt"
+ depends on HPET_TIMER && RTC=y
+
++config SCx200HR_TIMER
++ bool "NatSemi SCx200 27MHz High-Resolution Timer Support"
++ help
++ Some of the AMD (formerly National Semiconductor) Geode
++ processors, notably the SC1100, suffer from a buggy time
++ stamp counter which causes them to lose time when the
++ processor is sleeping. Enable this option to use the
++ on-board 27Mz high-resolution timer to keep time instead.
++ depends on (SCx200)
++ default n
++
+ config SMP
+ bool "Symmetric multi-processing support"
+ ---help---
+diff -Naurp linux-2.6.12-rc6.orig/arch/i386/kernel/scx200.c linux-2.6.12-rc6/arch/i386/kernel/scx200.c
+--- linux-2.6.12-rc6.orig/arch/i386/kernel/scx200.c 2005-06-07 14:56:02.000000000 +0100
++++ linux-2.6.12-rc6/arch/i386/kernel/scx200.c 2005-06-07 16:43:19.000000000 +0100
+@@ -27,6 +27,10 @@ long scx200_gpio_shadow[2];
+
+ unsigned scx200_cb_base = 0;
+
++#ifdef CONFIG_SCx200HR_TIMER
++extern void __devinit scx200hr_timer_enable(void);
++#endif
++
+ static struct pci_device_id scx200_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
+@@ -83,6 +87,9 @@ static int __devinit scx200_probe(struct
+ printk(KERN_INFO NAME ": Configuration Block base 0x%x\n", scx200_cb_base);
+ }
+
++#ifdef CONFIG_SCx200HR_TIMER
++ scx200hr_timer_enable();
++#endif
+ return 0;
+ }
+
+diff -Naurp linux-2.6.12-rc6.orig/arch/i386/kernel/timers/Makefile linux-2.6.12-rc6/arch/i386/kernel/timers/Makefile
+--- linux-2.6.12-rc6.orig/arch/i386/kernel/timers/Makefile 2004-03-11 18:21:13.000000000 +0000
++++ linux-2.6.12-rc6/arch/i386/kernel/timers/Makefile 2005-06-07 16:43:19.000000000 +0100
+@@ -5,5 +5,6 @@
+ obj-y := timer.o timer_none.o timer_tsc.o timer_pit.o common.o
+
+ obj-$(CONFIG_X86_CYCLONE_TIMER) += timer_cyclone.o
++obj-$(CONFIG_SCx200HR_TIMER) += timer_scx200hr.o
+ obj-$(CONFIG_HPET_TIMER) += timer_hpet.o
+ obj-$(CONFIG_X86_PM_TIMER) += timer_pm.o
+diff -Naurp linux-2.6.12-rc6.orig/arch/i386/kernel/timers/timer.c linux-2.6.12-rc6/arch/i386/kernel/timers/timer.c
+--- linux-2.6.12-rc6.orig/arch/i386/kernel/timers/timer.c 2004-12-26 14:07:37.000000000 +0000
++++ linux-2.6.12-rc6/arch/i386/kernel/timers/timer.c 2005-06-07 16:43:19.000000000 +0100
+@@ -13,6 +13,9 @@
+ #endif
+ /* list of timers, ordered by preference, NULL terminated */
+ static struct init_timer_opts* __initdata timers[] = {
++#ifdef CONFIG_SCx200HR_TIMER
++ &timer_scx200hr_init,
++#endif
+ #ifdef CONFIG_X86_CYCLONE_TIMER
+ &timer_cyclone_init,
+ #endif
+diff -Naurp linux-2.6.12-rc6.orig/arch/i386/kernel/timers/timer_scx200hr.c linux-2.6.12-rc6/arch/i386/kernel/timers/timer_scx200hr.c
+--- linux-2.6.12-rc6.orig/arch/i386/kernel/timers/timer_scx200hr.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.12-rc6/arch/i386/kernel/timers/timer_scx200hr.c 2005-06-07 16:43:19.000000000 +0100
+@@ -0,0 +1,220 @@
++/*
++ * Copyright (C) 2005 Ted Phelps
++ *
++ * This is a clock driver for the Geode SCx200's 27MHz high-resolution
++ * timer as the system clock replacing its buggy time stamp counter.
++ *
++ * Based on parts of timer_hpet.c, timer_tsc.c and timer_pit.c.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of the
++ * License, or (at your option) any later version.
++ */
++
++#include <asm/timer.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/seq_file.h>
++#include <linux/scx200.h>
++
++#define NAME "scx200hr"
++
++/* Read the clock */
++#define SCx200HR_CLOCK() inl(scx200_cb_base + SCx200_TIMER_OFFSET)
++
++/* High-resolution timer configuration address */
++#define SCx200_TMCNFG_OFFSET (SCx200_TIMER_OFFSET + 5)
++
++/* Set this bit to disable the 27 MHz input clock */
++#define HR_TM27MPD (1 << 2)
++
++/* Set this bit to update the count-up timer once per cycle of the
++ * 27MHz timer, clear it to update the timer once every 27 cycles
++ * (effectively producing a 1MHz counter) */
++#define HR_TMCLKSEL (1 << 1)
++
++/* Set this bit to enable the high-resolution timer interrupt */
++#define HR_TMEN (1 << 0)
++
++/* The frequency of the timer. Change this to 27000000 and set
++ * HR_TMCLKSEL in scx200hr_enable to run at the faster clock rate. At
++ * this point in time there is no point in doing so since times are
++ * recorded in usec except for the monotonic clock, which is only used
++ * by the hangcheck-timer. */
++#define HR_FREQ 1000000
++
++/* The number of cycles of the high-resolution timer we expect to see
++ * in a single tick. Note that the result is <<8 for greater precision*/
++#define HR_CYCLES_PER_TICK \
++ (SH_DIV(HR_FREQ / 1000000 * TICK_NSEC, 1000, 8))
++
++/* The number of cycles of the high-resolution timer we expect to see
++ * in one microsecond, <<8 */
++#define HR_CYCLES_PER_US ((HR_FREQ / 1000000) << 8)
++
++
++/* The value of the timer at the last interrupt */
++static u32 clock_at_last_interrupt;
++
++/* The number of high-resolution clock cycles beyond what we would
++ have expected that the last tick occurred, <<8 for greater precision */
++static long clock_delay;
++
++/* The total number of timer nanoseconds between the time the timer
++ * went live and the most recent tick. */
++static unsigned long long total_ns;
++
++/* A lock to guard access to the monotonic clock-related variables
++ * (total_ns and clocal_at_last_interrupt). Note that these are also
++ * protected by the xtime lock. */
++static seqlock_t hr_lock = SEQLOCK_UNLOCKED;
++
++/* Nonzero if the timer has been selected */
++static int enable_scx200hr;
++
++static int __init scx200hr_init(char *override)
++{
++ /* Watch for a command-line clock= override */
++ if (override[0] && strncmp(override, NAME, sizeof(NAME) - 1) != 0) {
++ return -ENODEV;
++ }
++
++ /* Note that we should try to enable this timer once the
++ * configuration block address is known */
++ printk(KERN_WARNING NAME ": timer not yet accessible; will probe later.\n");
++ enable_scx200hr = 1;
++ return -EAGAIN;
++}
++
++/* Called by the timer interrupt. The xtime_lock will be held. */
++static void mark_offset_scx200hr(void)
++{
++ u32 now, delta;
++
++ /* Avoid races between the interrupt handler and monotonic_clock */
++ write_seqlock(&hr_lock);
++
++ /* Determine how many cycles have elapsed since the last interrupt */
++ now = SCx200HR_CLOCK();
++ delta = (now - clock_at_last_interrupt) << 8;
++ clock_at_last_interrupt = now;
++
++ /* Update the total us count and remainder */
++ total_ns += (delta * 1000) / HR_CYCLES_PER_US;
++
++ /* The monotonic clock is safe now */
++ write_sequnlock(&hr_lock);
++
++ /* Adjust for interrupt handling delay */
++ delta += clock_delay;
++
++ /* The high-resolution timer is driven by a different crystal
++ * to the main CPU, so there's no guarantee that the 1KHz
++ * interrupt rate will coincide with the timer. This keeps
++ * the jiffies count in line with the high-resolution timer,
++ * which makes it possible for NTP to do its magic */
++ if (delta < HR_CYCLES_PER_TICK) {
++#if 1
++ /* Didn't go over 1000us: decrement jiffies to balance
++ * out increment in do_timer. This will cause some
++ * jitter if the frequency offset is large, as that
++ * adjustment will be applied about 1ms late. */
++ jiffies_64--;
++ clock_delay = delta;
++#else /* !1 */
++ clock_delay = 0;
++#endif /* 1 */
++ } else if (delta < (HR_CYCLES_PER_TICK << 1) + (HR_CYCLES_PER_TICK >> 1)) {
++ clock_delay = delta - HR_CYCLES_PER_TICK;
++ } else {
++ jiffies_64 += delta / HR_CYCLES_PER_TICK - 2;
++ clock_delay = HR_CYCLES_PER_TICK + delta % HR_CYCLES_PER_TICK;
++ }
++}
++
++/* Called by gettimeofday(). Returns the number of microseconds since
++ * the last interrupt. This is called with the xtime_lock held.*/
++static unsigned long get_offset_scx200hr(void)
++{
++ u32 delta;
++
++ /* Get the time now and determine how many cycles have
++ * transpired since the interrupt, adjusting for timer
++ * interrupt jitter. */
++ delta = ((SCx200HR_CLOCK() - clock_at_last_interrupt) << 8) + clock_delay;
++
++ /* Convert from cycles<<8 to microseconds */
++ return delta / HR_CYCLES_PER_US;
++}
++
++/* Returns the number of nanoseconds since the init of the timer. */
++static unsigned long long monotonic_clock_scx200hr(void)
++{
++ u32 delta, seq;
++ unsigned long long ns;
++
++ /* This function is *not* called with xtime_lock held, so we
++ * need to get the hr_lock to ensure we're not competing with
++ * mark_offset_scx200hr. */
++ do {
++ seq = read_seqbegin(&hr_lock);
++ ns = total_ns;
++ delta = SCx200HR_CLOCK() - clock_at_last_interrupt;
++ } while (read_seqretry(&hr_lock, seq));
++
++ /* Convert cycles to microseconds and add. */
++ return ns + delta * 1000 / HR_CYCLES_PER_US;
++}
++
++/* scx200hr timer_opts struct */
++struct timer_opts timer_scx200hr = {
++ .name = NAME,
++ .mark_offset = mark_offset_scx200hr,
++ .get_offset = get_offset_scx200hr,
++ .monotonic_clock = monotonic_clock_scx200hr,
++ .delay = NULL
++};
++
++/* And the init_timer struct */
++struct init_timer_opts __devinitdata timer_scx200hr_init = {
++ .init = scx200hr_init,
++ .opts = &timer_scx200hr
++};
++
++
++/* Switch from the original timer to the high-resolution timer */
++void __devinit scx200hr_timer_enable(void)
++{
++ /* Make sure the timer was requested and that the
++ * configuration block is present */
++ if (!enable_scx200hr || !scx200_cb_present()) {
++ return;
++ }
++
++ /* Reserve the timer region for ourselves */
++ if (!request_region(scx200_cb_base + SCx200_TIMER_OFFSET,
++ SCx200_TIMER_SIZE,
++ "NatSemi SCx200 High-Resolution Timer")) {
++ printk(KERN_WARNING NAME ": unable to lock timer region\n");
++ return;
++ }
++
++ /* Configure the timer */
++ outb(0, scx200_cb_base + SCx200_TMCNFG_OFFSET);
++
++ /* Record the current value of the timer. */
++ clock_at_last_interrupt = SCx200HR_CLOCK();
++
++ /* Get the current value of the monotonic clock */
++ total_ns = cur_timer->monotonic_clock();
++
++ /* Switch from the original timer functions to ours, but keep
++ * the current delay function since loops_per_jiffy will have
++ * been computed using that */
++ timer_scx200hr.delay = cur_timer->delay;
++ cur_timer = &timer_scx200hr;
++
++ printk(KERN_INFO "switching to scx200 high-resolution timer (%lu cpt)\n",
++ HR_CYCLES_PER_TICK);
++}
+diff -Naurp linux-2.6.12-rc6.orig/include/asm-i386/timer.h linux-2.6.12-rc6/include/asm-i386/timer.h
+--- linux-2.6.12-rc6.orig/include/asm-i386/timer.h 2005-06-07 14:56:11.000000000 +0100
++++ linux-2.6.12-rc6/include/asm-i386/timer.h 2005-06-07 16:43:19.000000000 +0100
+@@ -50,6 +50,9 @@ extern struct init_timer_opts timer_tsc_
+ #ifdef CONFIG_X86_CYCLONE_TIMER
+ extern struct init_timer_opts timer_cyclone_init;
+ #endif
++#ifdef CONFIG_SCx200HR_TIMER
++extern struct init_timer_opts timer_scx200hr_init;
++#endif
+
+ extern unsigned long calibrate_tsc(void);
+ extern void init_cpu_khz(void);
+diff -Naurp linux-2.6.12-rc6.orig/include/linux/scx200.h linux-2.6.12-rc6/include/linux/scx200.h
+--- linux-2.6.12-rc6.orig/include/linux/scx200.h 2005-06-07 14:56:11.000000000 +0100
++++ linux-2.6.12-rc6/include/linux/scx200.h 2005-06-07 16:43:19.000000000 +0100
+@@ -32,7 +32,7 @@ extern unsigned scx200_cb_base;
+
+ /* High Resolution Timer */
+ #define SCx200_TIMER_OFFSET 0x08
+-#define SCx200_TIMER_SIZE 0x05
++#define SCx200_TIMER_SIZE 0x06
+
+ /* Clock Generators */
+ #define SCx200_CLOCKGEN_OFFSET 0x10
diff --git a/target/linux/xscale-2.6/Makefile b/target/linux/xscale-2.6/Makefile
new file mode 100644
index 0000000..59f02b3
--- /dev/null
+++ b/target/linux/xscale-2.6/Makefile
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+LINUX_VERSION:=2.6.17
+LINUX_RELEASE:=1
+LINUX_KERNEL_MD5SUM:=37ddefe96625502161f075b9d907f21e
+
+include ./config
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/kernel-build.mk
+
+$(LINUX_DIR)/.patched: $(LINUX_DIR)/.unpacked
+ [ -d ../generic-$(KERNEL)/patches ] && $(PATCH) $(LINUX_DIR) ../generic-$(KERNEL)/patches
+ [ -d ./patches ] && $(PATCH) $(LINUX_DIR) ./patches
+ @$(CP) config $(LINUX_DIR)/.config
+ touch $@
diff --git a/target/linux/xscale-2.6/config b/target/linux/xscale-2.6/config
new file mode 100644
index 0000000..4df1a4c
--- /dev/null
+++ b/target/linux/xscale-2.6/config
@@ -0,0 +1,1384 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.17
+# Sun Aug 6 11:18:40 2006
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_SHMEM is not set
+CONFIG_SLAB=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+CONFIG_OBSOLETE_INTERMODULE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+CONFIG_ARCH_IXP4XX=y
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_AT91RM9200 is not set
+CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
+
+#
+# Intel IXP4xx Implementation Options
+#
+
+#
+# IXP4xx Platforms
+#
+# CONFIG_MACH_NSLU2 is not set
+# CONFIG_ARCH_AVILA is not set
+# CONFIG_ARCH_ADI_COYOTE is not set
+CONFIG_MACH_GATEWAY7001=y
+# CONFIG_ARCH_IXDP425 is not set
+# CONFIG_MACH_IXDPG425 is not set
+# CONFIG_MACH_IXDP465 is not set
+# CONFIG_ARCH_PRPMC1100 is not set
+# CONFIG_MACH_NAS100D is not set
+# CONFIG_MACH_GTWX5715 is not set
+
+#
+# IXP4xx Options
+#
+CONFIG_DMABOUNCE=y
+# CONFIG_IXP4XX_INDIRECT_PCI is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_XSCALE_PMU=y
+
+#
+# Bus support
+#
+CONFIG_PCI=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/mtdblock2 rootfstype=jffs2 noinitrd console=ttyS0,115200"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IPSEC_NAT_TRAVERSAL=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=m
+CONFIG_TCP_CONG_WESTWOOD=y
+CONFIG_TCP_CONG_HTCP=m
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+CONFIG_TCP_CONG_VEGAS=m
+# CONFIG_TCP_CONG_SCALABLE is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_IPV6_TUNNEL is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=y
+CONFIG_IP_NF_IRC=y
+# CONFIG_IP_NF_NETBIOS_NS is not set
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_PPTP is not set
+CONFIG_IP_NF_H323=m
+CONFIG_IP_NF_SIP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_IPP2P=m
+CONFIG_IP_NF_MATCH_TOS=m
+# CONFIG_IP_NF_MATCH_TIME is not set
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_HASHLIMIT is not set
+CONFIG_IP_NF_MATCH_LAYER7=m
+# CONFIG_IP_NF_MATCH_LAYER7_DEBUG is not set
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_IMQ=m
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_ROUTE=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=y
+CONFIG_IP_NF_NAT_FTP=y
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=m
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_NF_SET is not set
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+# CONFIG_IP6_NF_MATCH_OWNER is not set
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+CONFIG_IP6_NF_MATCH_AH=m
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+CONFIG_IP6_NF_FILTER=m
+# CONFIG_IP6_NF_TARGET_LOG is not set
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_ROUTE=m
+# CONFIG_IP6_NF_MANGLE is not set
+# CONFIG_IP6_NF_RAW is not set
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_ESFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+# CONFIG_IEEE80211_SOFTMAC is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_IXP4XX=y
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_IMQ=m
+# CONFIG_IMQ_BEHAVIOR_AA is not set
+# CONFIG_IMQ_BEHAVIOR_AB is not set
+CONFIG_IMQ_BEHAVIOR_BA=y
+# CONFIG_IMQ_BEHAVIOR_BB is not set
+CONFIG_IMQ_NUM_DEVS=2
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 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)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+CONFIG_NET_WIRELESS_RTNETLINK=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_IPW2100=m
+CONFIG_IPW2100_MONITOR=y
+# CONFIG_IPW2100_DEBUG is not set
+CONFIG_IPW2200=m
+CONFIG_IPW2200_MONITOR=y
+# CONFIG_IPW_QOS is not set
+# CONFIG_IPW2200_DEBUG is not set
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+# CONFIG_PRISM54 is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+CONFIG_HOSTAP_FIRMWARE_NVRAM=y
+CONFIG_HOSTAP_PLX=m
+CONFIG_HOSTAP_PCI=m
+CONFIG_HOSTAP_CS=m
+CONFIG_NET_WIRELESS=y
+
+#
+# Wan interfaces
+#
+CONFIG_WAN=y
+# CONFIG_DSCC4 is not set
+# CONFIG_LANMEDIA is not set
+# CONFIG_SYNCLINK_SYNCPPP is not set
+CONFIG_HDLC=m
+CONFIG_HDLC_RAW=y
+# CONFIG_HDLC_RAW_ETH is not set
+CONFIG_HDLC_CISCO=y
+CONFIG_HDLC_FR=y
+CONFIG_HDLC_PPP=y
+
+#
+# X.25/LAPB support is disabled
+#
+# CONFIG_PCI200SYN is not set
+# CONFIG_WANXL is not set
+# CONFIG_PC300 is not set
+# CONFIG_FARSYNC is not set
+CONFIG_DLCI=m
+CONFIG_DLCI_COUNT=24
+CONFIG_DLCI_MAX=8
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+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
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_IXP4XX_WATCHDOG=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_NVRAM 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_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_BANDWIDTH=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# 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=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_MON 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_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=m
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY 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 is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+# CONFIG_NFSD_V3 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_DEBUG_USER is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/target/linux/xscale-2.6/patches/001-gateway_7001.patch b/target/linux/xscale-2.6/patches/001-gateway_7001.patch
new file mode 100644
index 0000000..d144758
--- /dev/null
+++ b/target/linux/xscale-2.6/patches/001-gateway_7001.patch
@@ -0,0 +1,163 @@
+diff -Nur linux-2.6.17/arch/arm/boot/compressed/head-xscale.S linux-2.6.17-owrt/arch/arm/boot/compressed/head-xscale.S
+--- linux-2.6.17/arch/arm/boot/compressed/head-xscale.S 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/arm/boot/compressed/head-xscale.S 2006-08-05 17:02:21.000000000 +0200
+@@ -47,6 +47,11 @@
+ orr r7, r7, #(MACH_TYPE_GTWX5715 & 0xff00)
+ #endif
+
++#ifdef CONFIG_MACH_GATEWAY7001
++ mov r7, #(MACH_TYPE_GATEWAY7001 & 0xff)
++ orr r7, r7, #(MACH_TYPE_GATEWAY7001 & 0xff00)
++#endif
++
+ #ifdef CONFIG_ARCH_IXP2000
+ mov r1, #-1
+ mov r0, #0xd6000000
+diff -Nur linux-2.6.17/arch/arm/mach-ixp4xx/coyote-setup.c linux-2.6.17-owrt/arch/arm/mach-ixp4xx/coyote-setup.c
+--- linux-2.6.17/arch/arm/mach-ixp4xx/coyote-setup.c 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/arm/mach-ixp4xx/coyote-setup.c 2006-08-05 17:02:21.000000000 +0200
+@@ -1,9 +1,10 @@
+ /*
+ * arch/arm/mach-ixp4xx/coyote-setup.c
+ *
+- * Board setup for ADI Engineering and IXDGP425 boards
++ * Board setup for ADI Engineering, IXDGP425 and Gateway 7001 boards
+ *
+ * Copyright (C) 2003-2005 MontaVista Software, Inc.
++ * Copyright (C) 2006 Imre Kaloz <Kaloz@openwrt.org>
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ */
+@@ -111,6 +112,19 @@
+ MACHINE_END
+ #endif
+
++#ifdef CONFIG_MACH_GATEWAY7001
++MACHINE_START(GATEWAY7001, "Gateway 7001")
++ /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
++ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
++ .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
++ .map_io = ixp4xx_map_io,
++ .init_irq = ixp4xx_init_irq,
++ .timer = &ixp4xx_timer,
++ .boot_params = 0x0100,
++ .init_machine = coyote_init,
++MACHINE_END
++#endif
++
+ /*
+ * IXDPG425 is identical to Coyote except for which serial port
+ * is connected.
+diff -Nur linux-2.6.17/arch/arm/mach-ixp4xx/gateway7001-pci.c linux-2.6.17-owrt/arch/arm/mach-ixp4xx/gateway7001-pci.c
+--- linux-2.6.17/arch/arm/mach-ixp4xx/gateway7001-pci.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.17-owrt/arch/arm/mach-ixp4xx/gateway7001-pci.c 2006-08-06 10:37:35.000000000 +0200
+@@ -0,0 +1,67 @@
++/*
++ * arch/arch/mach-ixp4xx/gateway7001-pci.c
++ *
++ * PCI setup routines for Gateway 7001
++ *
++ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
++ *
++ * based on coyote-pci.c:
++ * Copyright (C) 2002 Jungo Software Technologies.
++ * Copyright (C) 2003 MontaVista Softwrae, Inc.
++ *
++ * Maintainer: Imre Kaloz <kaloz@openwrt.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/pci.h>
++
++extern void ixp4xx_pci_preinit(void);
++extern int ixp4xx_setup(int nr, struct pci_sys_data *sys);
++extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
++
++void __init gateway7001_pci_preinit(void)
++{
++ set_irq_type(IRQ_IXP4XX_GPIO10, IRQT_LOW);
++ set_irq_type(IRQ_IXP4XX_GPIO11, IRQT_LOW);
++
++ ixp4xx_pci_preinit();
++}
++
++static int __init gateway7001_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++ if (slot == 0)
++ return IRQ_IXP4XX_GPIO10;
++ else if (slot == 1)
++ return IRQ_IXP4XX_GPIO11;
++ else return -1;
++}
++
++struct hw_pci gateway7001_pci __initdata = {
++ .nr_controllers = 1,
++ .preinit = gateway7001_pci_preinit,
++ .swizzle = pci_std_swizzle,
++ .setup = ixp4xx_setup,
++ .scan = ixp4xx_scan_bus,
++ .map_irq = gateway7001_map_irq,
++};
++
++int __init gateway7001_pci_init(void)
++{
++ if (machine_is_gateway7001())
++ pci_common_init(&gateway7001_pci);
++ return 0;
++}
++
++subsys_initcall(gateway7001_pci_init);
+diff -Nur linux-2.6.17/arch/arm/mach-ixp4xx/Kconfig linux-2.6.17-owrt/arch/arm/mach-ixp4xx/Kconfig
+--- linux-2.6.17/arch/arm/mach-ixp4xx/Kconfig 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/arm/mach-ixp4xx/Kconfig 2006-08-05 17:04:13.000000000 +0200
+@@ -33,6 +33,14 @@
+ Engineering Coyote Gateway Reference Platform. For more
+ information on this platform, see <file:Documentation/arm/IXP4xx>.
+
++config MACH_GATEWAY7001
++ bool "Gateway 7001"
++ select PCI
++ help
++ Say 'Y' here if you want your kernel to support Gateway's
++ 7001 Access Point. For more information on this platform,
++ see http://openwrt.org
++
+ config ARCH_IXDP425
+ bool "IXDP425"
+ select PCI
+diff -Nur linux-2.6.17/arch/arm/mach-ixp4xx/Makefile linux-2.6.17-owrt/arch/arm/mach-ixp4xx/Makefile
+--- linux-2.6.17/arch/arm/mach-ixp4xx/Makefile 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/arch/arm/mach-ixp4xx/Makefile 2006-08-05 17:02:21.000000000 +0200
+@@ -11,4 +11,5 @@
+ obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o gtwx5715-setup.o
+ obj-$(CONFIG_MACH_NSLU2) += nslu2-pci.o nslu2-setup.o nslu2-power.o
+ obj-$(CONFIG_MACH_NAS100D) += nas100d-pci.o nas100d-setup.o nas100d-power.o
++obj-$(CONFIG_MACH_GATEWAY7001) += gateway7001-pci.o coyote-setup.o
+
+diff -Nur linux-2.6.17/include/asm-arm/arch-ixp4xx/uncompress.h linux-2.6.17-owrt/include/asm-arm/arch-ixp4xx/uncompress.h
+--- linux-2.6.17/include/asm-arm/arch-ixp4xx/uncompress.h 2006-06-18 03:49:35.000000000 +0200
++++ linux-2.6.17-owrt/include/asm-arm/arch-ixp4xx/uncompress.h 2006-08-05 17:03:32.000000000 +0200
+@@ -38,9 +38,9 @@
+ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
+ {
+ /*
+- * Coyote and gtwx5715 only have UART2 connected
++ * Some targets only have UART2 connected
+ */
+- if (machine_is_adi_coyote() || machine_is_gtwx5715())
++ if (machine_is_adi_coyote() || machine_is_gtwx5715() || machine_is_gateway7001())
+ uart_base = (volatile u32*) IXP4XX_UART2_BASE_PHYS;
+ else
+ uart_base = (volatile u32*) IXP4XX_UART1_BASE_PHYS;
diff --git a/target/sdk/Config.in b/target/sdk/Config.in
new file mode 100644
index 0000000..3ead296
--- /dev/null
+++ b/target/sdk/Config.in
@@ -0,0 +1,9 @@
+config SDK
+ bool "Build the OpenWrt SDK"
+ default y if ALL
+ help
+ This is essentially a stripped-down version of the buildroot
+ with a precompiled toolchain. It can be used to develop and
+ test packages for OpenWrt before including them in the buildroot
+
+
diff --git a/target/sdk/Makefile b/target/sdk/Makefile
new file mode 100644
index 0000000..a841356
--- /dev/null
+++ b/target/sdk/Makefile
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+# $Id$
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_OS:=$(shell uname -s)
+PKG_CPU:=$(shell uname -m)
+
+SDK_NAME:=OpenWrt-SDK-$(BOARD)-$(KERNEL)-for-$(PKG_OS)-$(PKG_CPU)
+SDK_BUILD_DIR:=$(BUILD_DIR)/$(SDK_NAME)
+
+all: compile
+
+$(BIN_DIR)/$(SDK_NAME).tar.bz2:
+ (cd $(STAGING_DIR); \
+ rm -rf info man share stampfiles; \
+ cd usr; \
+ rm -rf doc info man share; \
+ )
+ rm -rf $(SDK_BUILD_DIR)
+ mkdir -p $(SDK_BUILD_DIR)/dl $(SDK_BUILD_DIR)/package
+ $(CP) $(STAGING_DIR) $(INCLUDE_DIR) $(SCRIPT_DIR) $(TOPDIR)/docs $(SDK_BUILD_DIR)/
+ $(CP) $(TOPDIR)/rules.mk $(TOPDIR)/.config $(SDK_BUILD_DIR)/
+ $(CP) $(TOPDIR)/package/Makefile $(SDK_BUILD_DIR)/package/
+ $(CP) ./files/Makefile $(SDK_BUILD_DIR)/
+ $(CP) ./files/README.SDK $(SDK_BUILD_DIR)/
+ $(CP) ./files/package/rules.mk $(SDK_BUILD_DIR)/package/
+ echo OPENWRTVERSION:=$(OPENWRTVERSION) > $(SDK_BUILD_DIR)/.version.mk
+ find $(SDK_BUILD_DIR) -name .svn | xargs rm -rf
+ find $(SDK_BUILD_DIR) -name CVS | xargs rm -rf
+ (cd $(BUILD_DIR); \
+ tar cfj $@ $(SDK_NAME); \
+ )
+
+download:
+prepare:
+compile: $(BIN_DIR)/$(SDK_NAME).tar.bz2
+install:
+
+clean:
+ rm -rf $(SDK_BUILD_DIR) $(BIN_DIR)/$(SDK_NAME).tar.bz2
diff --git a/target/sdk/files/Makefile b/target/sdk/files/Makefile
new file mode 100644
index 0000000..ba488e3
--- /dev/null
+++ b/target/sdk/files/Makefile
@@ -0,0 +1,69 @@
+# Makefile for OpenWrt
+#
+# Copyright (C) 2006 by Felix Fietkau <openwrt@nbd.name>
+#
+# 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
+#
+
+RELEASE:=Kamikaze
+#VERSION:=2.0 # uncomment for final release
+
+#--------------------------------------------------------------
+# Just run 'make menuconfig', configure stuff, then run 'make'.
+# You shouldn't need to mess with anything beyond this point...
+#--------------------------------------------------------------
+TOPDIR=${shell pwd}
+export TOPDIR
+
+DEVELOPER=1
+export DEVELOPER
+
+all: world
+
+.pkginfo: FORCE
+ifneq ($(shell ./scripts/timestamp.pl -p .pkginfo package Makefile),.pkginfo)
+ @echo Collecting package info...
+ @-for dir in package/*/; do \
+ echo Source-Makefile: $${dir}Makefile; \
+ $(MAKE) --no-print-dir DUMP=1 -C $$dir 2>&- || true; \
+ done > $@
+endif
+
+pkginfo-clean: FORCE
+ -rm -f .pkginfo .config.in
+
+package/%: .pkginfo FORCE
+ $(MAKE) -C package $(patsubst package/%,%,$@) SDK=1
+
+download: FORCE
+ $(MAKE) package/download
+
+world: FORCE
+ $(MAKE) package/compile
+ -( \
+ cd package; \
+ find . -maxdepth 2 -name Config.in | \
+ sed -e 's,/Config.in,,g' | \
+ xargs -r -n1 make compile -C; \
+ )
+
+clean: FORCE
+ rm -rf build_* bin
+
+distclean: clean
+ rm -rf dl .pkg*
+
+.PHONY: FORCE
+FORCE:
diff --git a/target/sdk/files/README.SDK b/target/sdk/files/README.SDK
new file mode 100644
index 0000000..454e32b
--- /dev/null
+++ b/target/sdk/files/README.SDK
@@ -0,0 +1,7 @@
+This is the OpenWrt SDK. It contains a stripped-down version of
+the buildroot. You can use it to test/develop packages without
+having to compile your own toolchain or any of the libraries
+included with OpenWrt.
+
+To use it, just put your buildroot-compatible package directory
+in the subdir 'package/' and run 'make' from this directory.
diff --git a/target/sdk/files/package/depend.mk b/target/sdk/files/package/depend.mk
new file mode 100644
index 0000000..d7b844d
--- /dev/null
+++ b/target/sdk/files/package/depend.mk
@@ -0,0 +1,6 @@
+# You can put your package dependencies in here
+# Example (make openvpn depend on openssl):
+# openvpn-compile: openssl-compile
+#
+# Note: This file is not present in the full buildroot. There you
+# have to put your package dependencies in buildroot/package/Makefile
diff --git a/target/sdk/files/package/rules.mk b/target/sdk/files/package/rules.mk
new file mode 100644
index 0000000..b3f4cdb
--- /dev/null
+++ b/target/sdk/files/package/rules.mk
@@ -0,0 +1,89 @@
+# invoke ipkg with configuration in $(STAGING_DIR)/etc/ipkg.conf
+IPKG := IPKG_INSTROOT=$(TARGET_DIR) IPKG_CONF_DIR=$(IPKG_CONF) $(SCRIPT_DIR)/ipkg -force-defaults -force-depends
+IPKG_STATE_DIR := $(TARGET_DIR)/usr/lib/ipkg
+
+ifneq ($(DUMP),)
+dump:
+.PHONY: dump
+endif
+
+define PKG_template
+IPKG_$(1):=$(PACKAGE_DIR)/$(2)_$(3)_$(4).ipk
+IDIR_$(1):=$(PKG_BUILD_DIR)/ipkg/$(2)
+INFO_$(1):=$(IPKG_STATE_DIR)/info/$(2).list
+
+ifneq ($(BR2_PACKAGE_$(1)),)
+compile-targets: $$(IPKG_$(1))
+endif
+ifneq ($(DEVELOPER),)
+compile-targets: $$(IPKG_$(1))
+endif
+ifeq ($(BR2_PACKAGE_$(1)),y)
+install-targets: $$(INFO_$(1))
+endif
+
+IDEPEND_$(1):=$$(strip $(5))
+
+$$(IDIR_$(1))/CONTROL/control: $(PKG_BUILD_DIR)/.prepared
+ $(SCRIPT_DIR)/make-ipkg-dir.sh $$(IDIR_$(1)) ./ipkg/$(2).control $(3) $(4)
+ if [ "$$(IDEPEND_$(1))" != "" ]; then echo "Depends: $$(IDEPEND_$(1))" >> $$(IDIR_$(1))/CONTROL/control; fi
+ for file in conffiles preinst postinst prerm postrm; do \
+ [ -f ./ipkg/$(2).$$$$file ] && cp ./ipkg/$(2).$$$$file $$(IDIR_$(1))/CONTROL/$$$$file || true; \
+ done
+
+$$(IPKG_$(1)): $$(IDIR_$(1))/CONTROL/control $(PKG_BUILD_DIR)/.built $(PACKAGE_DIR)
+
+$$(INFO_$(1)): $$(IPKG_$(1))
+ $(IPKG) install $$(IPKG_$(1))
+
+$(2)-clean:
+ rm -f $$(IPKG_$(1))
+clean-targets: $(2)-clean
+endef
+
+ifeq ($(DUMP),)
+ifneq ($(strip $(PKG_SOURCE)),)
+$(DL_DIR)/$(PKG_SOURCE):
+ $(SCRIPT_DIR)/download.pl "$(DL_DIR)" "$(PKG_SOURCE)" "$(PKG_MD5SUM)" $(PKG_SOURCE_URL)
+endif
+
+ifneq ($(strip $(PKG_CAT)),)
+$(PKG_BUILD_DIR)/.prepared: $(DL_DIR)/$(PKG_SOURCE)
+ rm -rf $(PKG_BUILD_DIR)
+ mkdir -p $(PKG_BUILD_DIR)
+ $(PKG_CAT) $(DL_DIR)/$(PKG_SOURCE) | tar -C $(PKG_BUILD_DIR)/.. $(TAR_OPTIONS) -
+ if [ -d ./patches ]; then \
+ $(PATCH) $(PKG_BUILD_DIR) ./patches ; \
+ fi
+ touch $(PKG_BUILD_DIR)/.prepared
+endif
+
+all: compile
+
+compile-targets:
+install-targets:
+clean-targets:
+
+source: $(DL_DIR)/$(PKG_SOURCE)
+prepare: $(PKG_BUILD_DIR)/.prepared
+compile: compile-targets
+install: install-targets
+mostlyclean:
+rebuild:
+ -$(MAKE) mostlyclean
+ if [ -f $(PKG_BUILD_DIR)/.built ]; then \
+ $(MAKE) clean; \
+ fi
+ $(MAKE) compile
+
+$(PKG_BUILD_DIR)/.configured: $(PKG_BUILD_DIR)/.prepared
+$(PKG_BUILD_DIR)/.built: $(PKG_BUILD_DIR)/.configured
+
+$(PACKAGE_DIR):
+ mkdir -p $@
+
+clean: clean-targets
+ rm -rf $(PKG_BUILD_DIR)
+
+.PHONY: all source prepare compile install clean
+endif
diff --git a/target/utils/Makefile b/target/utils/Makefile
new file mode 100644
index 0000000..f2a92fe
--- /dev/null
+++ b/target/utils/Makefile
@@ -0,0 +1,32 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+TARGETS := addpattern trx motorola-bin dgfirmware
+
+UTILS_BUILD_DIR:=$(BUILD_DIR)/target-utils
+
+download:
+prepare: $(UTILS_BUILD_DIR)
+compile: prepare $(patsubst %,$(UTILS_BUILD_DIR)/%,$(TARGETS)) FORCE
+ mkdir -p $(STAGING_DIR)/bin
+ $(CP) $(UTILS_BUILD_DIR)/* $(STAGING_DIR)/bin/
+install: compile
+package:
+clean: FORCE
+ rm -rf $(UTILS_BUILD_DIR)
+ for f in $(TARGETS); do \
+ rm -f $(STAGING_DIR)/bin/$$f ; \
+ done
+
+$(UTILS_BUILD_DIR):
+ mkdir -p $(UTILS_BUILD_DIR)
+
+$(UTILS_BUILD_DIR)/%: src/%.c
+ $(CC) -O2 -I $(STAGING_DIR)/include-host -o $@ $(patsubst $(UTILS_BUILD_DIR)/%,src/%.c,$@)
+ chmod 755 $@
+
diff --git a/target/utils/src/addpattern.c b/target/utils/src/addpattern.c
new file mode 100644
index 0000000..5f49b92
--- /dev/null
+++ b/target/utils/src/addpattern.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* July 29, 2004
+ *
+ * This is a hacked replacement for the 'addpattern' utility used to
+ * create wrt54g .bin firmware files. It isn't pretty, but it does
+ * the job for me.
+ *
+ * Extensions:
+ * -v allows setting the version string on the command line.
+ * -{0|1} sets the (currently ignored) hw_ver flag in the header
+ * to 0 or 1 respectively.
+ */
+
+/* January 12, 2005
+ *
+ * Modified by rodent at rodent dot za dot net
+ * Support added for the new WRT54G v2.2 and WRT54GS v1.1 "flags"
+ * Without the flags set to 0x7, the above units will refuse to flash.
+ *
+ * Extensions:
+ * -{0|1|2} sets {0|1} sets hw_ver flag to 0/1. {2} sets hw_ver to 1
+ * and adds the new hardware "flags" for the v2.2/v1.1 units
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+/**********************************************************************/
+
+#define CODE_ID "U2ND" /* from code_pattern.h */
+#define CODE_PATTERN "W54S" /* from code_pattern.h */
+#define PBOT_PATTERN "PBOT"
+
+#define CYBERTAN_VERSION "v3.37.2" /* from cyutils.h */
+
+/* WRT54G v2.2 and WRT54GS v1.1 "flags" (from 3.37.32 firmware cyutils.h) */
+#define SUPPORT_4712_CHIP 0x0001
+#define SUPPORT_INTEL_FLASH 0x0002
+#define SUPPORT_5325E_SWITCH 0x0004
+
+struct code_header { /* from cyutils.h */
+ char magic[4];
+ char res1[4]; /* for extra magic */
+ char fwdate[3];
+ char fwvern[3];
+ char id[4]; /* U2ND */
+ char hw_ver; /* 0: for 4702, 1: for 4712 -- new in 2.04.3 */
+ char unused;
+ unsigned char flags[2]; /* SUPPORT_ flags new for 3.37.2 (WRT54G v2.2 and WRT54GS v1.1) */
+ unsigned char res2[10];
+} ;
+
+/**********************************************************************/
+
+void usage(void) __attribute__ (( __noreturn__ ));
+
+void usage(void)
+{
+ fprintf(stderr, "Usage: addpattern [-i trxfile] [-o binfile] [-p pattern] [-g] [-b] [-v v#.#.#] [-{0|1|2|4}]\n");
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+ char buf[1024]; /* keep this at 1k or adjust garbage calc below */
+ struct code_header *hdr;
+ FILE *in = stdin;
+ FILE *out = stdout;
+ char *ifn = NULL;
+ char *ofn = NULL;
+ char *pattern = CODE_PATTERN;
+ char *pbotpat = PBOT_PATTERN;
+ char *version = CYBERTAN_VERSION;
+ int gflag = 0;
+ int pbotflag = 0;
+ int c;
+ int v0, v1, v2;
+ size_t off, n;
+ time_t t;
+ struct tm *ptm;
+
+ fprintf(stderr, "mjn3's addpattern replacement - v0.81\n");
+
+ hdr = (struct code_header *) buf;
+ memset(hdr, 0, sizeof(struct code_header));
+
+ while ((c = getopt(argc, argv, "i:o:p:gbv:0124")) != -1) {
+ switch (c) {
+ case 'i':
+ ifn = optarg;
+ break;
+ case 'o':
+ ofn = optarg;
+ break;
+ case 'p':
+ pattern = optarg;
+ break;
+ case 'g':
+ gflag = 1;
+ break;
+ case 'b':
+ pbotflag = 1;
+ break;
+ case 'v': /* extension to allow setting version */
+ version = optarg;
+ break;
+ case '0':
+ hdr->hw_ver = 0;
+ break;
+ case '1':
+ hdr->hw_ver = 1;
+ break;
+ case '2': /* new 54G v2.2 and 54GS v1.1 flags */
+ hdr->hw_ver = 1;
+ hdr->flags[0] |= SUPPORT_4712_CHIP;
+ hdr->flags[0] |= SUPPORT_INTEL_FLASH;
+ hdr->flags[0] |= SUPPORT_5325E_SWITCH;
+ break;
+ case '4':
+ /* V4 firmware sets the flags to 0x1f */
+ hdr->hw_ver = 0;
+ hdr->flags[0] = 0x1f;
+ break;
+
+ default:
+ usage();
+ }
+ }
+
+ if (optind != argc) {
+ fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]);
+ usage();
+ }
+
+ if (strlen(pattern) != 4) {
+ fprintf(stderr, "illegal pattern \"%s\": length != 4\n", pattern);
+ usage();
+ }
+
+ if (ifn && !(in = fopen(ifn, "r"))) {
+ fprintf(stderr, "can not open \"%s\" for reading\n", ifn);
+ usage();
+ }
+
+ if (ofn && !(out = fopen(ofn, "w"))) {
+ fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
+ usage();
+ }
+
+ if (time(&t) == (time_t)(-1)) {
+ fprintf(stderr, "time call failed\n");
+ return EXIT_FAILURE;
+ }
+
+ ptm = localtime(&t);
+
+ if (3 != sscanf(version, "v%d.%d.%d", &v0, &v1, &v2)) {
+ fprintf(stderr, "bad version string \"%s\"\n", version);
+ return EXIT_FAILURE;
+ }
+
+ memcpy(&hdr->magic, pattern, 4);
+ if (pbotflag)
+ memcpy(&hdr->res1, pbotpat, 4);
+ hdr->fwdate[0] = ptm->tm_year % 100;
+ hdr->fwdate[1] = ptm->tm_mon + 1;
+ hdr->fwdate[2] = ptm->tm_mday;
+ hdr->fwvern[0] = v0;
+ hdr->fwvern[1] = v1;
+ hdr->fwvern[2] = v2;
+ memcpy(&hdr->id, CODE_ID, strlen(CODE_ID));
+
+ off = sizeof(struct code_header);
+
+ fprintf(stderr, "writing firmware v%d.%d.%d on %d/%d/%d (y/m/d)\n",
+ v0, v1, v2,
+ hdr->fwdate[0], hdr->fwdate[1], hdr->fwdate[2]);
+
+
+ while ((n = fread(buf + off, 1, sizeof(buf)-off, in) + off) > 0) {
+ off = 0;
+ if (n < sizeof(buf)) {
+ if (ferror(in)) {
+ FREAD_ERROR:
+ fprintf(stderr, "fread error\n");
+ return EXIT_FAILURE;
+ }
+ if (gflag) {
+ gflag = sizeof(buf) - n;
+ memset(buf + n, 0xff, gflag);
+ fprintf(stderr, "adding %d bytes of garbage\n", gflag);
+ n = sizeof(buf);
+ }
+ }
+ if (!fwrite(buf, n, 1, out)) {
+ FWRITE_ERROR:
+ fprintf(stderr, "fwrite error\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (ferror(in)) {
+ goto FREAD_ERROR;
+ }
+
+ if (fflush(out)) {
+ goto FWRITE_ERROR;
+ }
+
+ fclose(in);
+ fclose(out);
+
+ return EXIT_SUCCESS;
+}
diff --git a/target/utils/src/dgfirmware.c b/target/utils/src/dgfirmware.c
new file mode 100644
index 0000000..5ff3b69
--- /dev/null
+++ b/target/utils/src/dgfirmware.c
@@ -0,0 +1,376 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+
+#define IMG_SIZE 0x3e0000
+
+#define KERNEL_START 0x020000
+#define KERNEL_SIZE 0x0b0000
+
+#define ROOTFS_START 0x0d0000
+#define ROOTFS_SIZE 0x30ffb2
+
+char* app_name;
+
+
+
+
+void print_usage(void)
+{
+ fprintf(stderr, "usage: dgfirmware [<opts>] <img>\n");
+ fprintf(stderr, " <img> firmware image filename\n");
+ fprintf(stderr, " <opts> -h print this message\n");
+ fprintf(stderr, " -f fix the checksum\n");
+ fprintf(stderr, " -x <file> extract the rootfs file to <file>\n");
+ fprintf(stderr, " -xk <file> extract the kernel to <file>\n");
+ fprintf(stderr, " -m <file> merge in rootfs fil\e from <file>\n");
+ fprintf(stderr, " -k <file> merge in kernel from <file>\n");
+ fprintf(stderr, " -w <file> write back the modified firmware\n");
+}
+
+
+unsigned char* read_img(const char *fname)
+{
+ FILE *fp;
+ int size;
+ unsigned char *img;
+
+ fp = fopen(fname, "rb");
+ if (fp == NULL) {
+ perror(app_name);
+ exit(-1);
+ }
+
+ fseek(fp, 0, SEEK_END);
+ size = ftell(fp);
+
+ if (size != IMG_SIZE) {
+ fprintf(stderr, "%s: image file has wrong size\n", app_name);
+ fclose(fp);
+ exit(-1);
+ }
+
+ rewind(fp);
+
+ img = malloc(IMG_SIZE);
+ if (img == NULL) {
+ perror(app_name);
+ fclose(fp);
+ exit(-1);
+ }
+
+ if (fread(img, 1, IMG_SIZE, fp) != IMG_SIZE) {
+ fprintf(stderr, "%s: can't read image file\n", app_name);
+ fclose(fp);
+ exit(-1);
+ }
+
+ fclose(fp);
+ return img;
+}
+
+
+void write_img(unsigned char* img, const char *fname)
+{
+ FILE *fp;
+
+ fp = fopen(fname, "wb");
+ if (fp == NULL) {
+ perror(app_name);
+ exit(-1);
+ }
+
+ if (fwrite(img, 1, IMG_SIZE, fp) != IMG_SIZE) {
+ fprintf(stderr, "%s: can't write image file\n", app_name);
+ fclose(fp);
+ exit(-1);
+ }
+}
+
+
+void write_rootfs(unsigned char* img, const char *fname)
+{
+ FILE *fp;
+
+ fp = fopen(fname, "wb");
+ if (fp == NULL) {
+ perror(app_name);
+ exit(-1);
+ }
+
+ if (fwrite(img+ROOTFS_START, 1, ROOTFS_SIZE, fp) != ROOTFS_SIZE) {
+ fprintf(stderr, "%s: can't write image file\n", app_name);
+ fclose(fp);
+ exit(-1);
+ }
+}
+
+
+void write_kernel(unsigned char* img, const char *fname)
+{
+ FILE *fp;
+
+ fp = fopen(fname, "wb");
+ if (fp == NULL) {
+ perror(app_name);
+ exit(-1);
+ }
+
+ if (fwrite(img+KERNEL_START, 1, KERNEL_SIZE, fp) != KERNEL_SIZE) {
+ fprintf(stderr, "%s: can't write kernel file\n", app_name);
+ fclose(fp);
+ exit(-1);
+ }
+}
+
+
+unsigned char* read_rootfs(unsigned char* img, const char *fname)
+{
+ FILE *fp;
+ int size;
+ int i;
+
+ for (i=ROOTFS_START; i<ROOTFS_START+ROOTFS_SIZE; i++)
+ img[i] = 0xff;
+
+ fp = fopen(fname, "rb");
+ if (fp == NULL) {
+ perror(app_name);
+ exit(-1);
+ }
+
+ fseek(fp, 0, SEEK_END);
+ size = ftell(fp);
+
+ if (size > ROOTFS_SIZE) {
+ fprintf(stderr, "%s: rootfs image file is too big\n", app_name);
+ fclose(fp);
+ exit(-1);
+ }
+
+ rewind(fp);
+
+ if (fread(img+ROOTFS_START, 1, size, fp) != size) {
+ fprintf(stderr, "%s: can't read rootfs image file\n", app_name);
+ fclose(fp);
+ exit(-1);
+ }
+
+ fclose(fp);
+ return img;
+}
+
+
+unsigned char* read_kernel(unsigned char* img, const char *fname)
+{
+ FILE *fp;
+ int size;
+ int i;
+
+ for (i=KERNEL_START; i<KERNEL_START+KERNEL_SIZE; i++)
+ img[i] = 0xff;
+
+ fp = fopen(fname, "rb");
+ if (fp == NULL) {
+ perror(app_name);
+ exit(-1);
+ }
+
+ fseek(fp, 0, SEEK_END);
+ size = ftell(fp);
+
+ if (size > KERNEL_SIZE) {
+ fprintf(stderr, "%s: kernel binary file is too big\n", app_name);
+ fclose(fp);
+ exit(-1);
+ }
+
+ rewind(fp);
+
+ if (fread(img+KERNEL_START, 1, size, fp) != size) {
+ fprintf(stderr, "%s: can't read kernel file\n", app_name);
+ fclose(fp);
+ exit(-1);
+ }
+
+ fclose(fp);
+ return img;
+}
+
+
+int get_checksum(unsigned char* img)
+{
+ short unsigned s;
+
+ s = img[0x3dfffc] + (img[0x3dfffd]<<8);
+
+ return s;
+}
+
+
+void set_checksum(unsigned char*img, unsigned short sum)
+{
+ img[0x3dfffc] = sum & 0xff;
+ img[0x3dfffd] = (sum>>8) & 0xff;
+}
+
+
+int compute_checksum(unsigned char* img)
+{
+ int i;
+ short s=0;
+
+ for (i=0; i<0x3dfffc; i++)
+ s += img[i];
+
+ return s;
+}
+
+
+int main(int argc, char* argv[])
+{
+ char *img_fname = NULL;
+ char *rootfs_fname = NULL;
+ char *kernel_fname = NULL;
+ char *new_img_fname = NULL;
+
+ int do_fix_checksum = 0;
+ int do_write = 0;
+ int do_write_rootfs = 0;
+ int do_read_rootfs = 0;
+ int do_write_kernel = 0;
+ int do_read_kernel = 0;
+
+ int i;
+ unsigned char *img;
+ unsigned short img_checksum;
+ unsigned short real_checksum;
+
+ app_name = argv[0];
+
+ for (i=1; i<argc; i++) {
+ if (!strcmp(argv[i], "-h")) {
+ print_usage();
+ return 0;
+ }
+ else if (!strcmp(argv[i], "-f")) {
+ do_fix_checksum = 1;
+ }
+ else if (!strcmp(argv[i], "-x")) {
+ if (i+1 >= argc) {
+ fprintf(stderr, "%s: missing argument\n", app_name);
+ return -1;
+ }
+ do_write_rootfs = 1;
+ rootfs_fname = argv[i+1];
+ i++;
+ }
+ else if (!strcmp(argv[i], "-xk")) {
+ if (i+1 >= argc) {
+ fprintf(stderr, "%s: missing argument\n", app_name);
+ return -1;
+ }
+ do_write_kernel = 1;
+ kernel_fname = argv[i+1];
+ i++;
+ }
+ else if (!strcmp(argv[i], "-m")) {
+ if (i+1 >= argc) {
+ fprintf(stderr, "%s: missing argument\n", app_name);
+ return -1;
+ }
+ do_read_rootfs = 1;
+ rootfs_fname = argv[i+1];
+ i++;
+ }
+ else if (!strcmp(argv[i], "-k")) {
+ if (i+1 >= argc) {
+ fprintf(stderr, "%s: missing argument\n", app_name);
+ return -1;
+ }
+ do_read_kernel = 1;
+ kernel_fname = argv[i+1];
+ i++;
+ }
+ else if (!strcmp(argv[i], "-w")) {
+ if (i+1 >= argc) {
+ fprintf(stderr, "%s: missing argument\n", app_name);
+ return -1;
+ }
+ do_write = 1;
+ new_img_fname = argv[i+1];
+ i++;
+ }
+ else if (img_fname != 0) {
+ fprintf(stderr, "%s: too many arguments\n", app_name);
+ return -1;
+ }
+ else {
+ img_fname = argv[i];
+ }
+ }
+
+ if (img_fname == NULL) {
+ fprintf(stderr, "%s: missing argument\n", app_name);
+ return -1;
+ }
+
+ if ((do_read_rootfs && do_write_rootfs) ||
+ (do_read_kernel && do_write_kernel)) {
+ fprintf(stderr, "%s: conflictuous options\n", app_name);
+ return -1;
+ }
+
+ printf ("** Read firmware file\n");
+ img = read_img(img_fname);
+
+ printf ("Firmware product: %s\n", img+0x3dffbd);
+ printf ("Firmware version: 1.%02d.%02d\n", (img[0x3dffeb] & 0x7f), img[0x3dffec]);
+
+ if (do_write_rootfs) {
+ printf ("** Write rootfs file\n");
+ write_rootfs(img, rootfs_fname);
+ }
+
+ if (do_write_kernel) {
+ printf ("** Write kernel file\n");
+ write_kernel(img, kernel_fname);
+ }
+
+ if (do_read_rootfs) {
+ printf ("** Read rootfs file\n");
+ read_rootfs(img, rootfs_fname);
+ do_fix_checksum = 1;
+ }
+
+ if (do_read_kernel) {
+ printf ("** Read kernel file\n");
+ read_kernel(img, kernel_fname);
+ do_fix_checksum = 1;
+ }
+
+ img_checksum = get_checksum(img);
+ real_checksum = compute_checksum(img);
+
+ printf ("image checksum = %04x\n", img_checksum);
+ printf ("real checksum = %04x\n", real_checksum);
+
+ if (do_fix_checksum) {
+ if (img_checksum != real_checksum) {
+ printf ("** Bad Checksum, fix it\n");
+ set_checksum(img, real_checksum);
+ }
+ else {
+ printf ("** Checksum is correct, good\n");
+ }
+ }
+
+ if (do_write) {
+ printf ("** Write image file\n");
+ write_img(img, new_img_fname);
+ }
+
+ free(img);
+ return 0;
+}
+
diff --git a/target/utils/src/motorola-bin.c b/target/utils/src/motorola-bin.c
new file mode 100644
index 0000000..acf856d
--- /dev/null
+++ b/target/utils/src/motorola-bin.c
@@ -0,0 +1,146 @@
+/*
+ * motorola-bin.c
+ *
+ * Copyright (C) 2005-2006 Mike Baker,
+ * Imre Kaloz <kaloz@openwrt.org>
+ * OpenWrt.org
+ *
+ * $Id$
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+/*
+ * February 1, 2006
+ *
+ * Add support for for creating WA840G and WE800G images
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <netinet/in.h>
+
+unsigned long *crc32;
+
+void init_crc32()
+{
+ unsigned long crc;
+ unsigned long poly = ntohl(0x2083b8ed);
+ int n, bit;
+ if ((crc32 = (unsigned long *) malloc(256 * sizeof(unsigned long))) == (void *)-1) {
+ perror("malloc");
+ exit(1);
+ }
+ for (n = 0; n < 256; n++) {
+ crc = (unsigned long) n;
+ for (bit = 0; bit < 8; bit++)
+ crc = (crc & 1) ? (poly ^ (crc >> 1)) : (crc >> 1);
+ crc32[n] = crc;
+ }
+}
+
+unsigned int crc32buf(char *buf, size_t len)
+{
+ unsigned int crc = 0xFFFFFFFF;
+ for (; len; len--, buf++)
+ crc = crc32[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+ return crc;
+}
+
+struct motorola {
+ unsigned int crc; // crc32 of the remainder
+ unsigned int flags; // unknown, 105770*
+ char *trx; // standard trx
+};
+
+void usage(void) __attribute__ (( __noreturn__ ));
+
+void usage(void)
+{
+ printf("Usage: motorola-bin [-device] [trxfile] [binfile]\n\n");
+ printf("Known devices: 1 - WR850G | 2 - WA840G | 3 - WE800G\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ unsigned int len;
+ int fd;
+ int c;
+ void *trx;
+ struct motorola *firmware;
+
+ // verify parameters
+
+ if (argc!=4)
+ {
+ usage();
+ }
+
+ // mmap trx file
+ if (((fd = open(argv[2], O_RDONLY)) < 0)
+ || ((len = lseek(fd, 0, SEEK_END)) < 0)
+ || ((trx = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1))
+ || (close(fd) < 0)) {
+ perror("open/malloc");
+ exit(1);
+ }
+
+ // create a firmware image in memory
+ // and copy the trx to it
+ firmware = malloc(len+8);
+ memcpy(&firmware->trx,trx,len);
+ munmap(trx,len);
+
+ // setup the motorola headers
+ init_crc32();
+
+ // setup the firmware magic
+
+ while ((c = getopt(argc, argv, "123")) !=-1) {
+ switch (c) {
+ case '1':
+ firmware->flags = ntohl(0x10577050); // Motorola WR850G
+ break;
+ case '2':
+ firmware->flags = ntohl(0x10577040); // Motorola WA840G
+ break;
+ case '3':
+ firmware->flags = ntohl(0x10577000); // Motorola WE800G
+ break;
+ default:
+ usage();
+ }
+ }
+
+ firmware->crc = htonl(crc32buf((char *)&firmware->flags,len+4));
+
+ // write the firmware
+ if (((fd = open(argv[3], O_CREAT|O_WRONLY,0644)) < 0)
+ || (write(fd,firmware,len+8) != len+8)
+ || (close(fd) < 0)) {
+ perror("write");
+ exit(-1);
+ }
+
+ free(firmware);
+
+ return 0;
+}
diff --git a/target/utils/src/trx.c b/target/utils/src/trx.c
new file mode 100644
index 0000000..abc9bc9
--- /dev/null
+++ b/target/utils/src/trx.c
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* July 29, 2004
+ *
+ * This is a hacked replacement for the 'trx' utility used to create
+ * wrt54g .trx firmware files. It isn't pretty, but it does the job
+ * for me.
+ *
+ * As an extension, you can specify a larger maximum length for the
+ * .trx file using '-m'. It will be rounded up to be a multiple of 4K.
+ * NOTE: This space will be malloc()'d.
+ *
+ * August 16, 2004
+ *
+ * Sigh... Make it endian-neutral.
+ *
+ * TODO: Support '-b' option to specify offsets for each file.
+ *
+ * February 19, 2005 - mbm
+ *
+ * Add -a (align offset) and -b (absolute offset)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#if defined(__APPLE__)
+#include <machine/endian.h>
+#include <machine/byte_order.h>
+#define __BYTE_ORDER BYTE_ORDER
+#define __BIG_ENDIAN BIG_ENDIAN
+#define bswap_16(x) NXSwapShort(x)
+#define bswap_32(x) NXSwapInt(x)
+#define bswap_64(x) NXSwapLongLong(x)
+#else
+#include <endian.h>
+#include <byteswap.h>
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define STORE32_LE(X) bswap_32(X)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define STORE32_LE(X) (X)
+#else
+#error unkown endianness!
+#endif
+
+uint32_t crc32buf(char *buf, size_t len);
+
+/**********************************************************************/
+/* from trxhdr.h */
+
+#define TRX_MAGIC 0x30524448 /* "HDR0" */
+#define TRX_VERSION 1
+#define TRX_MAX_LEN 0x5A0000
+#define TRX_NO_HEADER 1 /* Do not write TRX header */
+
+struct trx_header {
+ uint32_t magic; /* "HDR0" */
+ uint32_t len; /* Length of file including header */
+ uint32_t crc32; /* 32-bit CRC from flag_version to end of file */
+ uint32_t flag_version; /* 0:15 flags, 16:31 version */
+ uint32_t offsets[3]; /* Offsets of partitions from start of header */
+};
+
+/**********************************************************************/
+
+void usage(void) __attribute__ (( __noreturn__ ));
+
+void usage(void)
+{
+ fprintf(stderr, "Usage: trx [-o outfile] [-m maxlen] [-a align] [-b offset] [-f file] [-f file [-f file]]\n");
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+ FILE *out = stdout;
+ FILE *in;
+ char *ofn = NULL;
+ char *buf;
+ char *e;
+ int c, i;
+ size_t n;
+ uint32_t cur_len;
+ unsigned long maxlen = TRX_MAX_LEN;
+ struct trx_header *p;
+
+ fprintf(stderr, "mjn3's trx replacement - v0.81.1\n");
+
+ if (!(buf = malloc(maxlen))) {
+ fprintf(stderr, "malloc failed\n");
+ return EXIT_FAILURE;
+ }
+
+ p = (struct trx_header *) buf;
+
+ p->magic = STORE32_LE(TRX_MAGIC);
+ cur_len = sizeof(struct trx_header);
+ p->flag_version = STORE32_LE((TRX_VERSION << 16));
+
+ in = NULL;
+ i = 0;
+
+ while ((c = getopt(argc, argv, "-:o:m:a:b:f:")) != -1) {
+ switch (c) {
+ case 'f':
+ case 1:
+ p->offsets[i++] = STORE32_LE(cur_len);
+
+ if (!(in = fopen(optarg, "r"))) {
+ fprintf(stderr, "can not open \"%s\" for reading\n", optarg);
+ usage();
+ }
+ n = fread(buf + cur_len, 1, maxlen - cur_len, in);
+ if (!feof(in)) {
+ fprintf(stderr, "fread failure or file \"%s\" too large\n",optarg);
+ fclose(in);
+ return EXIT_FAILURE;
+ }
+ fclose(in);
+#undef ROUND
+#define ROUND 4
+ if (n & (ROUND-1)) {
+ memset(buf + cur_len + n, 0, ROUND - (n & (ROUND-1)));
+ n += ROUND - (n & (ROUND-1));
+ }
+ cur_len += n;
+
+ break;
+ case 'o':
+ ofn = optarg;
+ if (ofn && !(out = fopen(ofn, "w"))) {
+ fprintf(stderr, "can not open \"%s\" for writing\n", ofn);
+ usage();
+ }
+
+ break;
+ case 'm':
+ errno = 0;
+ maxlen = strtoul(optarg, &e, 0);
+ if (errno || (e == optarg) || *e) {
+ fprintf(stderr, "illegal numeric string\n");
+ usage();
+ }
+#undef ROUND
+#define ROUND 0x1000
+ if (maxlen & (ROUND-1)) {
+ maxlen += (ROUND - (maxlen & (ROUND-1)));
+ }
+ if (maxlen < ROUND) {
+ fprintf(stderr, "maxlen too small (or wrapped)\n");
+ usage();
+ }
+ if (maxlen > TRX_MAX_LEN) {
+ fprintf(stderr, "WARNING: maxlen exceeds default maximum! Beware of overwriting nvram!\n");
+ }
+ if (!(buf = realloc(buf,maxlen))) {
+ fprintf(stderr, "realloc failed");
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'a':
+ errno = 0;
+ n = strtoul(optarg, &e, 0);
+ if (errno || (e == optarg) || *e) {
+ fprintf(stderr, "illegal numeric string\n");
+ usage();
+ }
+ if (cur_len & (n-1)) {
+ n = n - (cur_len & (n-1));
+ memset(buf + cur_len, 0, n);
+ cur_len += n;
+ }
+ break;
+ case 'b':
+ errno = 0;
+ n = strtoul(optarg, &e, 0);
+ if (errno || (e == optarg) || *e) {
+ fprintf(stderr, "illegal numeric string\n");
+ usage();
+ }
+ if (n < cur_len) {
+ fprintf(stderr, "WARNING: current length exceeds -b %d offset\n",n);
+ } else {
+ memset(buf + cur_len, 0, n - cur_len);
+ cur_len = n;
+ }
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (!in) {
+ fprintf(stderr, "we require atleast one filename\n");
+ usage();
+ }
+
+#undef ROUND
+#define ROUND 0x1000
+ n = cur_len & (ROUND-1);
+ if (n) {
+ memset(buf + cur_len, 0, ROUND - n);
+ cur_len += ROUND - n;
+ }
+
+ p->crc32 = crc32buf((char *) &p->flag_version,
+ cur_len - offsetof(struct trx_header, flag_version));
+ p->crc32 = STORE32_LE(p->crc32);
+
+ p->len = STORE32_LE(cur_len);
+
+ if (!fwrite(buf, cur_len, 1, out) || fflush(out)) {
+ fprintf(stderr, "fwrite failed\n");
+ return EXIT_FAILURE;
+ }
+
+ fclose(out);
+
+ return EXIT_SUCCESS;
+}
+
+/**********************************************************************/
+/* The following was grabbed and tweaked from the old snippets collection
+ * of public domain C code. */
+
+/**********************************************************************\
+|* Demonstration program to compute the 32-bit CRC used as the frame *|
+|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *|
+|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *|
+|* protocol). The 32-bit FCS was added via the Federal Register, *|
+|* 1 June 1982, p.23798. I presume but don't know for certain that *|
+|* this polynomial is or will be included in CCITT V.41, which *|
+|* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *|
+|* PUB 78 says that the 32-bit FCS reduces otherwise undetected *|
+|* errors by a factor of 10^-5 over 16-bit FCS. *|
+\**********************************************************************/
+
+/* Copyright (C) 1986 Gary S. Brown. You may use this program, or
+ code or tables extracted from it, as desired without restriction.*/
+
+/* First, the polynomial itself and its table of feedback terms. The */
+/* polynomial is */
+/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
+/* Note that we take it "backwards" and put the highest-order term in */
+/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
+/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
+/* the MSB being 1. */
+
+/* Note that the usual hardware shift register implementation, which */
+/* is what we're using (we're merely optimizing it by doing eight-bit */
+/* chunks at a time) shifts bits into the lowest-order term. In our */
+/* implementation, that means shifting towards the right. Why do we */
+/* do it this way? Because the calculated CRC must be transmitted in */
+/* order from highest-order term to lowest-order term. UARTs transmit */
+/* characters in order from LSB to MSB. By storing the CRC this way, */
+/* we hand it to the UART in the order low-byte to high-byte; the UART */
+/* sends each low-bit to hight-bit; and the result is transmission bit */
+/* by bit from highest- to lowest-order term without requiring any bit */
+/* shuffling on our part. Reception works similarly. */
+
+/* The feedback terms table consists of 256, 32-bit entries. Notes: */
+/* */
+/* 1. The table can be generated at runtime if desired; code to do so */
+/* is shown later. It might not be obvious, but the feedback */
+/* terms simply represent the results of eight shift/xor opera- */
+/* tions for all combinations of data and CRC register values. */
+/* */
+/* 2. The CRC accumulation logic is the same for all CRC polynomials, */
+/* be they sixteen or thirty-two bits wide. You simply choose the */
+/* appropriate table. Alternatively, because the table can be */
+/* generated at runtime, you can start by generating the table for */
+/* the polynomial in question and use exactly the same "updcrc", */
+/* if your application needn't simultaneously handle two CRC */
+/* polynomials. (Note, however, that XMODEM is strange.) */
+/* */
+/* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */
+/* of course, 32-bit entries work OK if the high 16 bits are zero. */
+/* */
+/* 4. The values must be right-shifted by eight bits by the "updcrc" */
+/* logic; the shift must be unsigned (bring in zeroes). On some */
+/* hardware you could probably optimize the shift in assembler by */
+/* using byte-swap instructions. */
+
+static const uint32_t crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
+0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+#define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
+
+uint32_t crc32buf(char *buf, size_t len)
+{
+ uint32_t crc;
+
+ crc = 0xFFFFFFFF;
+
+ for ( ; len; --len, ++buf)
+ {
+ crc = UPDC32(*buf, crc);
+ }
+
+ return crc;
+}